/* ==========================================================================
   Horizon platform · mockup design system
   Reference implementation of the tokens and components in 03-design.md.

   Everything is scoped under .ab (one artboard = one screen) so screens can
   sit inside the plan hub without touching the hub's own chrome.

   Rules this file enforces:
   - Palette comes only from the site's token contract (src/styles/tokens.css).
   - Orange means one thing: "this is where the action is now" (active nav,
     the single primary action, the current stage, work in progress).
   - Status is green / amber / red + a text label. Status TEXT uses the -ink
     variants (AA on white); dots and bars use the base colours.
   - Surfaces are flat with hairlines. Shadow exists only on overlays.
   ========================================================================== */

@font-face {
  font-family: 'Overpass';
  font-style: normal; font-display: swap; font-weight: 100 900;
  src: url('fonts/overpass-latin.woff2') format('woff2');
}
@font-face {
  font-family: 'Overpass Mono';
  font-style: normal; font-display: swap; font-weight: 300 700;
  src: url('fonts/overpass-mono-latin.woff2') format('woff2');
}

/* ---- tokens --------------------------------------------------------------
   .light keeps the light tokens inside a dark screen, for things whose colours
   are the content: a PDF as it will print, a product shown in a brand's colours.
   An email is a white card in either theme (03-design.md, Email). */
.ab, .ab .light, .ab .mail {
  --paper: #FFFFFF;
  --ink: #141714;
  --ink-70: rgba(20, 23, 20, 0.72);
  --ink-62: rgba(20, 23, 20, 0.64);
  --ink-35: rgba(20, 23, 20, 0.35);
  --ink-18: rgba(20, 23, 20, 0.18);
  --ink-08: rgba(20, 23, 20, 0.07);
  --ink-04: rgba(20, 23, 20, 0.035);
  --brand: #ff7a00;
  --accent: #ff7a00;
  --accent-ink: #141714;
  --accent-soft: rgba(255, 122, 0, 0.10);
  --wordmark: #303030;
  --mail-bg: #f3f3f1;
  --pos: #1f9457;  --pos-ink: #17784a;  --pos-soft: rgba(31, 148, 87, 0.10);
  --warn: #e0a30c; --warn-ink: #8a6100; --warn-soft: rgba(224, 163, 12, 0.14);
  --neg: #d24b42;  --neg-ink: #b53a32;  --neg-soft: rgba(210, 75, 66, 0.09);
  --font: 'Overpass', 'Segoe UI', system-ui, -apple-system, sans-serif;
  --mono: 'Overpass Mono', ui-monospace, 'SF Mono', Consolas, monospace;
  --r-sm: 6px; --r-md: 10px; --r-lg: 16px;
  --shadow-pop: 0 1px 2px rgba(20, 23, 20, 0.06), 0 16px 40px -14px rgba(20, 23, 20, 0.28);
  --scrim: rgba(20, 23, 20, 0.32);
  --plate: transparent; /* dark mode shows a client's brand mark on a light plate */
  --swatch-edge: rgba(20, 23, 20, 0.07);
  --edge: rgba(20, 23, 20, 0.48); /* the edge of a control: 3.2:1 on paper (WCAG 1.4.11) */
  --scroll-thumb: rgba(20, 23, 20, 0.34);
  color-scheme: light;
}
.ab .light, .ab .mail { color: var(--ink); }
.ab {
  position: relative;
  box-sizing: border-box;
  overflow: hidden;
  background: var(--paper);
  color: var(--ink);
  font: 400 14px/1.45 var(--font);
  font-variant-numeric: tabular-nums;
  -webkit-font-smoothing: antialiased;
  text-align: left;
}
.ab *, .ab *::before, .ab *::after { box-sizing: border-box; }

/* ---- scrollbars ------------------------------------------------------------
   Thin, on a transparent track, and the thumb drawn only while an area is
   scrolling: a script marks the area .is-scrolling and takes the mark off 0.8s
   after it stops (the page script in build.mjs, and hub.mjs). Still, nothing is
   drawn. On a touch screen the system's own overlay scrollbar does the same. */
.ab, .ab * { scrollbar-width: thin; scrollbar-color: transparent transparent; }
.ab.is-scrolling, .ab .is-scrolling { scrollbar-color: var(--scroll-thumb) transparent; }
@media (prefers-reduced-motion: no-preference) { .ab, .ab * { transition: scrollbar-color 0.2s ease-out; } }
/* a browser without scrollbar-color (Safari) gets the same through its own scrollbar styling */
@supports not (scrollbar-color: auto) {
  .ab::-webkit-scrollbar, .ab ::-webkit-scrollbar { width: 8px; height: 8px; background: transparent; }
  .ab::-webkit-scrollbar-thumb, .ab ::-webkit-scrollbar-thumb { background: transparent; border-radius: 4px; }
  .ab.is-scrolling::-webkit-scrollbar-thumb, .ab .is-scrolling::-webkit-scrollbar-thumb { background: var(--scroll-thumb); }
}

/* ---- dark theme ------------------------------------------------------------
   The same system on a dark ground: the site's green-tinted ink becomes the
   ground, orange stays the one accent with dark text on it, and status colours
   are re-tuned for dark. Checked: text 15.7:1, --ink-70 9.0:1, --ink-62 6.6:1,
   control borders (--ink-35) 3.5:1, status text 7.4:1 or better on its own fill.
   A screen follows the device unless it, or the viewer, sets data-theme. */
.ab[data-theme="dark"] {
  --paper: #131513;
  --ink: #ECEEE9;
  --ink-70: rgba(236, 238, 233, 0.74);
  --ink-62: rgba(236, 238, 233, 0.62);
  --ink-35: rgba(236, 238, 233, 0.40);
  --ink-18: rgba(236, 238, 233, 0.18);
  --ink-08: rgba(236, 238, 233, 0.08);
  --ink-04: rgba(236, 238, 233, 0.045);
  --accent-soft: rgba(255, 122, 0, 0.16);
  --wordmark: #E6E8E3;
  --mail-bg: #0B0C0B;
  --pos: #2fa866;  --pos-ink: #6fd39a; --pos-soft: rgba(47, 168, 102, 0.16);
  --warn: #e0a30c; --warn-ink: #f2c35a; --warn-soft: rgba(224, 163, 12, 0.16);
  --neg: #e0625a;  --neg-ink: #ff9a90; --neg-soft: rgba(224, 98, 90, 0.16);
  --scrim: rgba(0, 0, 0, 0.6);
  --plate: #FFFFFF;
  --swatch-edge: rgba(236, 238, 233, 0.26);
  --edge: rgba(236, 238, 233, 0.40);
  --scroll-thumb: rgba(236, 238, 233, 0.36);
  --shadow-pop: 0 0 0 1px rgba(236, 238, 233, 0.12), 0 16px 40px -14px rgba(0, 0, 0, 0.8);
  color-scheme: dark;
}
@media (prefers-color-scheme: dark) {
  .ab:not([data-theme="light"]) {
    --paper: #131513;
    --ink: #ECEEE9;
    --ink-70: rgba(236, 238, 233, 0.74);
    --ink-62: rgba(236, 238, 233, 0.62);
    --ink-35: rgba(236, 238, 233, 0.40);
    --ink-18: rgba(236, 238, 233, 0.18);
    --ink-08: rgba(236, 238, 233, 0.08);
    --ink-04: rgba(236, 238, 233, 0.045);
    --accent-soft: rgba(255, 122, 0, 0.16);
    --wordmark: #E6E8E3;
    --mail-bg: #0B0C0B;
    --pos: #2fa866;  --pos-ink: #6fd39a; --pos-soft: rgba(47, 168, 102, 0.16);
    --warn: #e0a30c; --warn-ink: #f2c35a; --warn-soft: rgba(224, 163, 12, 0.16);
    --neg: #e0625a;  --neg-ink: #ff9a90; --neg-soft: rgba(224, 98, 90, 0.16);
    --scrim: rgba(0, 0, 0, 0.6);
    --plate: #FFFFFF;
  --swatch-edge: rgba(236, 238, 233, 0.26);
  --edge: rgba(236, 238, 233, 0.40);
  --scroll-thumb: rgba(236, 238, 233, 0.36);
    --shadow-pop: 0 0 0 1px rgba(236, 238, 233, 0.12), 0 16px 40px -14px rgba(0, 0, 0, 0.8);
    color-scheme: dark;
  }
}
.ab h1, .ab h2, .ab h3, .ab h4, .ab p, .ab ul, .ab ol, .ab dl, .ab dd, .ab figure { margin: 0; padding: 0; }
.ab ul, .ab ol { list-style: none; }
.ab a { color: inherit; text-decoration: none; }
.ab button, .ab input, .ab textarea, .ab select { font: inherit; color: inherit; }
.ab [data-go] { cursor: pointer; }

/* ---- type ---------------------------------------------------------------- */
.ab .h1 { font-size: 26px; line-height: 1.12; font-weight: 800; letter-spacing: -0.015em; }
.ab .h2 { font-size: 20px; line-height: 1.2; font-weight: 800; letter-spacing: -0.01em; }
.ab .h3 { font-size: 16px; line-height: 1.3; font-weight: 700; }
.ab .lead { font-size: 16px; line-height: 1.5; color: var(--ink-70); }
.ab .small { font-size: 13px; }
.ab .muted { color: var(--ink-62); }
.ab .strong { font-weight: 700; }
.ab .label { font: 500 11px/1.2 var(--mono); letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-62); }
.ab .mono { font-family: var(--mono); font-size: 12px; letter-spacing: 0.02em; }
.ab .key { font: 500 12px/1 var(--mono); letter-spacing: 0.04em; color: var(--ink-70); white-space: nowrap; }
.ab .num { font-variant-numeric: tabular-nums; }
.ab .big { font-size: 34px; line-height: 1; font-weight: 800; letter-spacing: -0.02em; }
.ab .right { text-align: right; }
.ab .nowrap { white-space: nowrap; }
.ab .link { text-decoration: underline; text-decoration-color: var(--accent); text-decoration-thickness: 2px; text-underline-offset: 3px; }
.ab .prose { font-size: 15px; line-height: 1.6; color: var(--ink); max-width: 35em; }
/* running text keeps a reading measure of about 73 characters, whatever holds
   it. In em, not ch: Overpass figures are wide, so 68ch sets about 91. */
.ab p, .ab li, .ab .msg .body, .ab .measure { max-width: 35em; }
.ab .prose p + p { margin-top: 12px; }
.ab .prose h4 { font-size: 15px; font-weight: 700; margin: 18px 0 6px; }
.ab .prose ul, .ab ul.prose { list-style: disc; padding-left: 20px; }
.ab .prose li + li { margin-top: 4px; }

/* separator dot: authored as ' · ' in the screens, drawn here (see build.mjs) */
.ab .sdw { white-space: nowrap; }
.ab .sd { display: inline-block; width: 3px; height: 3px; border-radius: 50%; background: currentColor; opacity: 0.6; margin: 0 0.5em; vertical-align: middle; position: relative; top: -0.08em; flex: none; }
/* inside a flex row the container's gap already spaces the dot */
.ab .status > .sd, .ab .check > .sd, .ab .att > .sd, .ab .rowx > .sd, .ab .pill > .sd, .ab .tag > .sd { margin: 0 1px; top: 0; }

/* ---- layout helpers ------------------------------------------------------ */
.ab .stack { display: flex; flex-direction: column; gap: 16px; }
.ab .stack.s4 { gap: 4px; } .ab .stack.s8 { gap: 8px; } .ab .stack.s12 { gap: 12px; }
.ab .stack.s24 { gap: 24px; } .ab .stack.s32 { gap: 32px; }
.ab .rowx { display: flex; align-items: center; gap: 12px; }
.ab .rowx.s4 { gap: 4px; } .ab .rowx.s8 { gap: 8px; } .ab .rowx.s16 { gap: 16px; } .ab .rowx.s24 { gap: 24px; }
.ab .rowx.top { align-items: flex-start; }
.ab .rowx.base { align-items: baseline; }
.ab .rowx.wrap { flex-wrap: wrap; }
.ab .grow { flex: 1 1 auto; min-width: 0; }
.ab .push { margin-left: auto; }
/* read by a screen reader, not drawn: the name of a table column whose cells need no heading on screen */
/* a part drawn twice, once for a phone (.ph-only) and once for everything wider (.ph-hide) */
@container ab (min-width: 760px) { .ab .ph-only { display: none !important; } }
@container ab (max-width: 759px) {
  .ab .ph-hide { display: none !important; }
  .ab .rows > .ph-hide:first-child + .ph-only { border-top: 0; }
}
.ab .vh { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }
/* a hidden heading is held by its own cell, so it scrolls with its table instead of sitting against the artboard */
.ab :is(th, td):has(> .vh) { position: relative; }
/* the controls at the end of a header or toolbar, kept together so they wrap as one */
.ab .tools { display: flex; align-items: inherit; gap: inherit; }
.ab .grid { display: grid; gap: 24px; }
.ab .g2 { grid-template-columns: 1fr 1fr; }
.ab .g3 { grid-template-columns: repeat(3, 1fr); }
.ab .g4 { grid-template-columns: repeat(4, 1fr); }
.ab .g-main { grid-template-columns: minmax(0, 1fr) 360px; }
.ab .g-main.wide { grid-template-columns: minmax(0, 1fr) 420px; }
.ab .rule { height: 1px; width: 100%; margin: 0; background: var(--ink-18); border: 0; flex: none; }
.ab .rule.soft { background: var(--ink-08); }
.ab .clip { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ---- wordmark lockup (same construction as the site: DEVELOPMENT spans
        HORIZON's exact width via space-between) --------------------------- */
.ab .wm { display: inline-flex; align-items: center; gap: 0.46em; font-family: var(--font); color: var(--wordmark); line-height: 1; white-space: nowrap; font-size: 19px; }
.ab .wm-sun { width: 1.4em; height: 1.4em; flex: none; display: block; }
.ab .wm-text { display: flex; flex-direction: column; align-items: stretch; justify-content: center; }
.ab .wm-top { font-weight: 800; font-size: 1em; letter-spacing: -0.02em; line-height: 0.92; }
.ab .wm-sub { display: flex; justify-content: space-between; font-weight: 500; font-size: 0.42em; margin-top: 0.14em; line-height: 1; }
.ab .sun { display: block; flex: none; }

/* ==========================================================================
   WORKSPACE SHELL (staff)
   ========================================================================== */
.ab .shell { display: grid; grid-template-columns: 216px minmax(0, 1fr); height: 100%; }
.ab .side { border-right: 1px solid var(--ink-18); display: flex; flex-direction: column; padding: 22px 0 14px; min-height: 0; }
.ab .side .wm { margin: 0 0 26px 20px; }
.ab .nav { display: flex; flex-direction: column; }
.ab .nv { display: flex; align-items: center; gap: 8px; font: 500 12px/1 var(--mono); letter-spacing: 0.12em; text-transform: uppercase; padding: 11px 20px; color: var(--ink-70); }
.ab .nv:hover { background: var(--ink-04); color: var(--ink); }
.ab .nv.on { background: var(--ink-08); color: var(--ink); box-shadow: inset 2px 0 0 var(--accent); }
.ab .nv .ct { margin-left: auto; font-size: 11px; letter-spacing: 0.04em; color: var(--ink-62); }
.ab .side .foot { margin-top: auto; display: flex; flex-direction: column; }
.ab .side .me { display: flex; align-items: center; gap: 10px; padding: 14px 20px 0; margin-top: 8px; border-top: 1px solid var(--ink-08); }
.ab .side .me .who { font-size: 13px; font-weight: 600; line-height: 1.2; }
.ab .side .me .role { font: 500 11px/1.2 var(--mono); letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-62); }

.ab .main { display: flex; flex-direction: column; min-width: 0; min-height: 0; }
.ab .top { flex: none; height: 56px; display: flex; align-items: center; gap: 16px; padding: 0 32px; border-bottom: 1px solid var(--ink-18); }
.ab .crumbs { display: flex; align-items: center; gap: 8px; font: 500 12px/1 var(--mono); letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-62); min-width: 0; }
.ab .crumbs b { color: var(--ink); font-weight: 600; }
.ab .crumbs .sep { color: var(--ink-35); }
.ab .search { margin-left: auto; display: flex; align-items: center; gap: 8px; width: 300px; height: 34px; padding: 0 10px; border: 1px solid var(--edge); border-radius: var(--r-sm); color: var(--ink-62); font-size: 13px; }
.ab .search kbd { margin-left: auto; font: 500 11px/1 var(--mono); letter-spacing: 0.06em; border: 1px solid var(--ink-18); border-radius: 4px; padding: 3px 5px; color: var(--ink-62); }
.ab .page { flex: 1 1 auto; min-height: 0; overflow: hidden; padding: 28px 32px 32px; display: flex; flex-direction: column; gap: 24px; }
.ab .page-hd { display: flex; align-items: flex-end; gap: 16px; }
.ab .page-hd .sub { margin-top: 6px; color: var(--ink-62); font-size: 14px; }

/* project header: sits between .top and .page on every project screen */
.ab .proj { flex: none; padding: 22px 32px 0; border-bottom: 1px solid var(--ink-18); display: flex; flex-direction: column; gap: 16px; }
.ab .proj-row { display: flex; align-items: center; gap: 16px; }
.ab .proj .client { font: 500 11px/1 var(--mono); letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-62); margin-bottom: 7px; }
.ab .proj .name { font-size: 24px; line-height: 1.1; font-weight: 800; letter-spacing: -0.015em; }
.ab .proj .now { font-size: 13px; color: var(--ink-70); }
.ab .proj .now b { font-weight: 700; color: var(--ink); }

/* tabs */
.ab .tabs { display: flex; gap: 26px; }
.ab .tab { position: relative; padding: 0 0 12px; font: 500 12px/1 var(--mono); letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-62); white-space: nowrap; display: inline-flex; gap: 6px; align-items: center; }
.ab .tab:hover { color: var(--ink); }
.ab .tab.on { color: var(--ink); box-shadow: inset 0 -2px 0 var(--ink); }
.ab .tab .ct { font-size: 11px; letter-spacing: 0.02em; color: var(--ink-62); }
.ab .tabs.sub { gap: 6px; }
.ab .tabs.sub .tab { padding: 7px 10px; border-radius: var(--r-sm); box-shadow: none; }
.ab .tabs.sub .tab.on { background: var(--ink-08); }

/* ==========================================================================
   CLIENT PORTAL SHELL (desktop)
   ========================================================================== */
.ab.portal { font-size: 16px; line-height: 1.5; }
.ab .pshell { display: flex; flex-direction: column; height: 100%; }
.ab .ptop { flex: none; border-bottom: 1px solid var(--ink-18); }
.ab .ptop-in { max-width: 1120px; margin: 0 auto; padding: 0 32px; }
.ab .pbar-row { height: 68px; display: flex; align-items: center; gap: 20px; }
.ab .pproj { display: flex; align-items: baseline; gap: 12px; padding: 22px 0 0; }
.ab .pproj .name { font-size: 28px; font-weight: 800; letter-spacing: -0.015em; line-height: 1.1; }
.ab .ptabs { display: flex; gap: 30px; }
/* the tab takes the 18px above it as target area: same look, 44px tall */
.ab .ptabs .tab { font-size: 12.5px; padding-top: 18px; padding-bottom: 14px; min-width: 44px; }
.ab .pmain { flex: 1 1 auto; min-height: 0; overflow: hidden; }
.ab .pmain-in { max-width: 1120px; margin: 0 auto; padding: 36px 32px 40px; display: flex; flex-direction: column; gap: 32px; }
.ab.portal .h1 { font-size: 32px; }
.ab.portal .h2 { font-size: 22px; }
.ab.portal .h3 { font-size: 17px; }
.ab.portal .small { font-size: 14px; }
.ab.portal .label { font-size: 11.5px; }

/* ==========================================================================
   CLIENT PORTAL SHELL (mobile, 390 wide)
   ========================================================================== */
.ab.mobile { font-size: 16px; line-height: 1.45; }
.ab .mshell { display: flex; flex-direction: column; height: 100%; }
.ab .mtop { flex: none; height: 56px; display: flex; align-items: center; gap: 10px; padding: 0 16px; border-bottom: 1px solid var(--ink-18); }
.ab .mtop .ttl { font-size: 15px; font-weight: 700; line-height: 1.15; }
.ab .mtop .sub { font: 500 11px/1.2 var(--mono); letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-62); }
.ab .mmain { flex: 1 1 auto; min-height: 0; overflow: hidden; padding: 20px 16px; display: flex; flex-direction: column; gap: 20px; }
.ab .mtabs { flex: none; height: 64px; display: grid; grid-template-columns: repeat(5, 1fr); border-top: 1px solid var(--ink-18); padding-bottom: 6px; }
.ab .mtab { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 5px; font: 500 11px/1 var(--mono); letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-62); position: relative; }
.ab .mtab .ic { width: 20px; height: 20px; }
.ab .mtab.on { color: var(--ink); }
.ab .mtab.on::before { content: ""; position: absolute; top: -1px; left: 50%; width: 28px; height: 2px; margin-left: -14px; background: var(--accent); }
.ab .mtab .badge { position: absolute; top: 9px; left: 50%; margin-left: 7px; min-width: 17px; height: 17px; padding: 0 4px; border-radius: 9px; background: var(--ink); color: var(--paper); font: 600 11px/17px var(--mono); letter-spacing: 0; text-align: center; }
.ab.mobile .h1 { font-size: 26px; }
.ab.mobile .h2 { font-size: 20px; }

/* ==========================================================================
   COMPONENTS
   ========================================================================== */

/* buttons: one .primary per view, at most */
.ab .btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px; height: 34px; padding: 0 14px; border: 1px solid var(--edge); border-radius: var(--r-sm); background: var(--paper); font-size: 13px; font-weight: 600; line-height: 1; white-space: nowrap; color: var(--ink); }
.ab .btn:hover { border-color: var(--ink); }
.ab .btn.primary { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.ab .btn.solid { background: var(--ink); border-color: var(--ink); color: var(--paper); }
.ab .btn.ghost { border-color: transparent; color: var(--ink-70); }
.ab .btn.ghost:hover { background: var(--ink-04); color: var(--ink); }
.ab .btn.danger { border-color: var(--neg); color: var(--neg-ink); }
.ab .btn.sm { height: 28px; padding: 0 10px; font-size: 12px; }
.ab .btn.lg { height: 44px; padding: 0 20px; font-size: 15px; }
.ab .btn.xl { height: 52px; padding: 0 24px; font-size: 16px; }
.ab .btn.block { display: flex; width: 100%; }
/* the portal's targets are 44px (03-design.md), so its default button is the .lg size */
.ab.portal .btn:not(.lg):not(.xl), .ab.mobile .btn:not(.lg):not(.xl) { height: 44px; padding: 0 18px; font-size: 15px; }
.ab .btn[disabled], .ab .btn.off { opacity: 0.4; }

/* form fields */
.ab .field { display: flex; flex-direction: column; gap: 7px; }
.ab .field > .label { color: var(--ink-70); }
.ab .input, .ab .textarea, .ab .select { width: 100%; min-height: 38px; padding: 8px 11px; border: 1px solid var(--edge); border-radius: var(--r-sm); background: var(--paper); font-size: 14px; line-height: 1.4; display: flex; align-items: center; }
.ab .textarea { align-items: flex-start; min-height: 96px; white-space: pre-line; }
.ab .select { justify-content: space-between; gap: 8px; }
.ab .rowx > .select { min-height: 34px; padding-top: 0; padding-bottom: 0; }
.ab .input.focus, .ab .textarea.focus { border-color: var(--ink); box-shadow: 0 0 0 3px var(--accent-soft), 0 0 0 1px var(--accent); }
/* keyboard focus is the site's ring (03-design.md). A bordered control turns its
   border ink and gains the orange ring and halo, as .input.focus does. A
   borderless one draws the ink edge itself, so every indicator keeps an 18:1
   edge: the orange ring alone is 2.6:1 and fails WCAG 1.4.11. .focus draws the
   state in a mockup; :focus-visible is the same rule for the build. */
.ab .focus, .ab a:focus-visible, .ab [data-go]:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--paper), 0 0 0 3px var(--ink), 0 0 0 4px var(--accent), 0 0 0 7px var(--accent-soft); }
.ab .btn.focus, .ab .btn:focus-visible { outline: none; border-color: var(--ink); box-shadow: 0 0 0 1px var(--accent), 0 0 0 4px var(--accent-soft); }
.ab .link.focus { border-radius: 2px; }
.ab .nv.focus, .ab .row.focus { box-shadow: inset 0 0 0 1px var(--ink), inset 0 0 0 2px var(--accent), inset 0 0 0 5px var(--accent-soft); }
.ab .nv.on.focus { box-shadow: inset 2px 0 0 var(--accent), inset 0 0 0 1px var(--ink), inset 0 0 0 2px var(--accent), inset 0 0 0 5px var(--accent-soft); }
.ab .tab.on.focus { box-shadow: inset 0 -2px 0 var(--ink), 0 0 0 2px var(--paper), 0 0 0 3px var(--ink), 0 0 0 4px var(--accent), 0 0 0 7px var(--accent-soft); }
.ab .input.lg { min-height: 50px; font-size: 16px; padding: 12px 14px; }
.ab .input.ro { background: var(--ink-04); color: var(--ink-70); }
.ab.portal .input:not(.lg), .ab.mobile .input:not(.lg), .ab.portal .select, .ab.mobile .select { min-height: 44px; }
.ab .ph { color: var(--ink-62); }
.ab .hint { font-size: 12.5px; color: var(--ink-62); }
.ab .err { font-size: 12.5px; color: var(--neg-ink); }
.ab .check { display: inline-flex; align-items: center; gap: 9px; font-size: 14px; }
.ab .box { width: 16px; height: 16px; border: 1px solid var(--edge); border-radius: 4px; flex: none; display: grid; place-items: center; color: var(--paper); }
.ab .box.on { background: var(--ink); border-color: var(--ink); }
.ab .box.on .ic { width: 12px; height: 12px; }
.ab .radio { width: 16px; height: 16px; border: 1px solid var(--edge); border-radius: 50%; flex: none; display: grid; place-items: center; }
.ab .radio.on { border-color: var(--ink); }
.ab .radio.on::after { content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--ink); }
.ab .switch { display: inline-block; vertical-align: middle; width: 32px; height: 18px; border-radius: 9px; background: var(--edge); position: relative; flex: none; }
.ab .switch::after { content: ""; position: absolute; top: 2px; left: 2px; width: 14px; height: 14px; border-radius: 50%; background: var(--paper); }
.ab .switch.on { background: var(--ink); }
.ab .switch.on::after { left: 16px; }
.ab .seg { display: inline-flex; flex: none; max-width: 100%; border: 1px solid var(--edge); border-radius: var(--r-sm); overflow: hidden; }
/* 34px tall, the height of the button beside it; a segment never wraps its words */
.ab .seg span { display: inline-flex; align-items: center; justify-content: center; height: 32px; font: 500 11px/1 var(--mono); letter-spacing: 0.08em; text-transform: uppercase; padding: 0 11px; color: var(--ink-70); white-space: nowrap; }
.ab .seg span + span { border-left: 1px solid var(--ink-18); }
.ab .seg span.on { background: var(--ink); color: var(--paper); }
.ab .seg.tight span { padding: 0 7px; letter-spacing: 0.06em; }
.ab .row .act { font-size: 12.5px; color: var(--ink-62); white-space: nowrap; }
.ab .code6 { display: flex; gap: 8px; }
.ab .code6 span { width: 48px; height: 58px; border: 1px solid var(--edge); border-radius: var(--r-sm); display: grid; place-items: center; font: 600 24px/1 var(--mono); }
.ab .code6 span.focus { border-color: var(--ink); box-shadow: 0 0 0 3px var(--accent-soft), 0 0 0 1px var(--accent); }

/* status: dot + label, and pills */
.ab .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--ink-35); flex: none; display: inline-block; }
.ab .dot.pos { background: var(--pos); } .ab .dot.warn { background: var(--warn); } .ab .dot.neg { background: var(--neg); }
.ab .dot.ink { background: var(--ink); } .ab .dot.accent { background: var(--accent); }
.ab .dot.hollow { background: transparent; box-shadow: inset 0 0 0 1.5px var(--ink-35); }
.ab .status { display: inline-flex; align-items: center; gap: 7px; font-size: 13px; white-space: nowrap; }
.ab .status.big { font-size: 24px; font-weight: 800; letter-spacing: -0.01em; line-height: 1.1; gap: 11px; }
.ab .status.big .dot { width: 13px; height: 13px; }
.ab .pill { display: inline-flex; align-items: center; gap: 6px; height: 20px; padding: 0 7px; border: 1px solid var(--ink-35); border-radius: 3px; font: 500 11px/1 var(--mono); letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-70); white-space: nowrap; }
/* status fills are painted over paper, so a pill keeps its contrast on a grey row */
.ab .pill.pos { color: var(--pos-ink); border-color: var(--pos); background: linear-gradient(var(--pos-soft), var(--pos-soft)), var(--paper); }
.ab .pill.warn { color: var(--warn-ink); border-color: var(--warn); background: linear-gradient(var(--warn-soft), var(--warn-soft)), var(--paper); }
.ab .pill.neg { color: var(--neg-ink); border-color: var(--neg); background: linear-gradient(var(--neg-soft), var(--neg-soft)), var(--paper); }
.ab .pill.ink { color: var(--paper); border-color: var(--ink); background: var(--ink); }
.ab .pill.mute { border-color: var(--ink-18); color: var(--ink-62); }
.ab .pill.lg { height: 24px; padding: 0 9px; font-size: 11px; }
.ab .tag { display: inline-flex; align-items: center; height: 20px; padding: 0 7px; border-radius: 3px; background: var(--ink-08); font: 500 11px/1 var(--mono); letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-70); white-space: nowrap; }

/* 44px hit areas in the portal and on the phone, with the layout unchanged */
.ab .pbar-row > .av[data-go] { box-sizing: content-box; padding: 8px; margin: -8px; background-clip: content-box; }
.ab .mtop > .av[data-go] { box-sizing: content-box; padding: 11px; margin: -11px; background-clip: content-box; }
.ab .mtop > .grow[data-go] { padding: 7px 0; margin: -7px 0; }
.ab .pbar-row > .wm[data-go] { padding: 9px 0; margin: -9px 0; }
.ab.portal a.small, .ab.mobile a.small, .ab.portal .link, .ab.mobile .link, .ab.portal .act, .ab.mobile .act { padding-top: 14px; padding-bottom: 14px; margin-top: -14px; margin-bottom: -14px; }
.ab.portal .check, .ab.mobile .check, .ab.touch .check { padding: 12px 0; margin: -12px 0; }
.ab.portal .status.big[data-go] { padding: 9px 0; margin: -9px 0; }
.ab.portal .switch, .ab.mobile .switch, .ab.touch .switch { box-sizing: content-box; padding: 13px 6px; margin: -13px -6px; background-clip: content-box; border-radius: 15px / 22px; }
.ab.portal .switch::after, .ab.mobile .switch::after, .ab.touch .switch::after { top: 15px; left: 8px; }
.ab.portal .switch.on::after, .ab.mobile .switch.on::after, .ab.touch .switch.on::after { left: 22px; }
/* On a touch screen (.touch) buttons, links, tabs and the search button are
   44px targets without being redrawn: an invisible layer reaches past the
   drawn edge, so the workspace keeps its density and a focus ring still hugs
   what is drawn. A segmented control stays 34px, the height of a native one.
   The drawer's menu items are 44px rows. */
.ab.touch :is(.btn, .link, a.small, .act, .search) { position: relative; }
.ab.touch :is(.btn, .tab, .link, a.small, .act, .search)::after { content: ""; position: absolute; left: 50%; top: 50%; width: max(100%, 44px); height: max(100%, 44px); transform: translate(-50%, -50%); }
.ab.touch .nv { padding-top: 16px; padding-bottom: 16px; }
.ab.portal .canvas-bar { height: 56px; }
.ab.portal .canvas-bar .seg span { height: 45px; padding: 0 11px; }

/* avatars: initials only */
.ab .av { width: 28px; height: 28px; border-radius: 50%; background: var(--ink-08); display: grid; place-items: center; font: 600 11px/1 var(--mono); letter-spacing: 0.02em; color: var(--ink); flex: none; }
.ab .av.sm { width: 22px; height: 22px; font-size: 11px; }
.ab .av.lg { width: 40px; height: 40px; font-size: 13px; }
.ab .av.hz { background: var(--ink); color: var(--paper); }
.ab .av.agent { background: var(--paper); box-shadow: inset 0 0 0 1px var(--ink-35); border-radius: 6px; }

/* panels: a bordered group. Lists inside use hairlines, not more boxes. */
.ab .panel { border: 1px solid var(--ink-18); border-radius: var(--r-md); background: var(--paper); min-width: 0; }
.ab .panel-hd { display: flex; align-items: center; gap: 12px; padding: 14px 18px; border-bottom: 1px solid var(--ink-08); }
.ab .panel-hd .label { color: var(--ink-70); }
.ab .panel-hd .act { margin-left: auto; font-size: 12.5px; color: var(--ink-62); display: inline-flex; align-items: center; gap: 4px; }
.ab .panel-bd { padding: 18px; }
.ab .panel-bd.flush { padding: 0; }
.ab .panel.attn { box-shadow: inset 3px 0 0 var(--accent); }
.ab .panel.subtle { background: var(--ink-04); border-color: transparent; }
.ab .sect-hd { display: flex; align-items: baseline; gap: 12px; padding-bottom: 10px; border-bottom: 1px solid var(--ink-18); }
.ab .sect-hd .ct { font: 500 12px/1 var(--mono); color: var(--ink-62); }
.ab .sect-hd .act { margin-left: auto; font-size: 12.5px; color: var(--ink-62); }

/* list rows */
.ab .rows { display: flex; flex-direction: column; }
.ab .row { display: flex; align-items: center; gap: 14px; padding: 13px 18px; border-top: 1px solid var(--ink-08); min-width: 0; }
.ab .rows > .row:first-child { border-top: 0; }
.ab .rows.bare > .row { padding-left: 0; padding-right: 0; }
.ab .row:hover { background: var(--ink-04); }
.ab .row.sel { background: var(--ink-08); }
.ab .row .ttl { font-weight: 600; line-height: 1.3; }
.ab .row .meta { font-size: 12.5px; color: var(--ink-62); line-height: 1.35; margin-top: 2px; }
.ab .row .when { font: 500 11.5px/1 var(--mono); color: var(--ink-62); white-space: nowrap; }
.ab .row .when.late { color: var(--neg-ink); }

/* tables */
.ab .tbl { width: 100%; border-collapse: collapse; font-size: 13.5px; }
/* --w: a column's drawn width at the design size; below it the table shares out the room */
.ab .tbl th { width: var(--w, auto); text-align: left; font: 500 11px/1 var(--mono); letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-62); padding: 0 14px 10px; border-bottom: 1px solid var(--ink-18); white-space: nowrap; }
.ab .tbl td { padding: 13px 14px; border-bottom: 1px solid var(--ink-08); vertical-align: middle; }
.ab .tbl th:first-child, .ab .tbl td:first-child { padding-left: 0; }
.ab .tbl th:last-child, .ab .tbl td:last-child { padding-right: 0; }
.ab .tbl tr:hover td { background: var(--ink-04); }
.ab .tbl .r { text-align: right; }
.ab .tbl .ttl { font-weight: 600; }
.ab .tbl .meta { font-size: 12.5px; color: var(--ink-62); }
.ab .tbl.in-panel th { padding-top: 14px; }
.ab .tbl.in-panel th:first-child, .ab .tbl.in-panel td:first-child { padding-left: 18px; }
.ab .tbl.in-panel th:last-child, .ab .tbl.in-panel td:last-child { padding-right: 18px; }
.ab .tbl.in-panel tr:last-child td { border-bottom: 0; }

/* key/value */
.ab .kv { display: grid; grid-template-columns: 120px minmax(0, 1fr); row-gap: 11px; column-gap: 16px; font-size: 13.5px; align-items: baseline; }
.ab .kv dt { font: 500 11px/1.3 var(--mono); letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-62); }
.ab .kv.wide { grid-template-columns: 160px minmax(0, 1fr); }
.ab .kv.tight { grid-template-columns: 96px minmax(0, 1fr); }

/* progress */
.ab .pbar { height: 6px; border-radius: 3px; background: var(--ink-08); overflow: hidden; }
.ab .pbar > i { display: block; height: 100%; background: var(--ink); border-radius: 3px; }
.ab .pbar.live > i { background: var(--accent); }
.ab .pbar.pos > i { background: var(--pos); }

/* ---- the stage line: the one signature element ---------------------------
   A project is always at exactly one stage, drawn the same way for staff,
   for clients and (as text) in email. Done = ink, current = orange, next = grey. */
.ab .stage { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); position: relative; }
.ab .stage .st { position: relative; padding-top: 22px; padding-right: 12px; min-width: 0; }
.ab .stage .st::before { content: ""; position: absolute; top: 5px; left: 0; right: 0; height: 2px; background: var(--ink-18); }
.ab .stage .st::after { content: ""; position: absolute; top: 0; left: 0; width: 12px; height: 12px; border-radius: 50%; background: var(--paper); box-shadow: inset 0 0 0 2px var(--ink-35); }
.ab .stage .st.done::before { background: var(--ink); }
.ab .stage .st.done::after { background: var(--ink); box-shadow: none; }
.ab .stage .st.now::after { background: var(--accent); box-shadow: 0 0 0 4px var(--accent-soft); }
.ab .stage .st:last-child::before { display: none; }
.ab .stage .st .n { font: 500 11px/1.2 var(--mono); letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-62); }
.ab .stage .st .t { font-size: 13.5px; font-weight: 600; line-height: 1.25; margin-top: 3px; }
.ab .stage .st .d { font: 500 11px/1.2 var(--mono); color: var(--ink-62); margin-top: 4px; }
.ab .stage .st.next .t { color: var(--ink-62); font-weight: 500; }
.ab .stage.compact { display: flex; }
.ab .stage.compact .st { padding: 0; height: 12px; flex: 1 1 0; }
.ab .stage.compact .st:last-child { flex: 0 0 12px; }
.ab .stage.compact .st .n, .ab .stage.compact .st .t, .ab .stage.compact .st .d { display: none; }

/* vertical timeline (milestones, activity) */
.ab .tl { display: flex; flex-direction: column; }
.ab .tl-item { display: grid; grid-template-columns: 96px 24px minmax(0, 1fr); column-gap: 12px; position: relative; padding-bottom: 26px; }
.ab .tl-item:last-child { padding-bottom: 0; }
.ab .tl-date { font: 500 11.5px/1.3 var(--mono); color: var(--ink-62); text-align: right; padding-top: 2px; }
.ab .tl-date .was { display: block; text-decoration: line-through; color: var(--ink-35); }
.ab .tl-mark { position: relative; display: flex; justify-content: center; }
.ab .tl-mark::before { content: ""; position: absolute; top: 16px; bottom: -26px; left: 50%; width: 2px; margin-left: -1px; background: var(--ink-18); }
.ab .tl-item:last-child .tl-mark::before { display: none; }
/* child combinators: the marker dot is the direct <i>; a tick icon nested inside
   it is also an <i> and must keep its own currentColor fill */
.ab .tl-mark > i { position: relative; z-index: 1; width: 14px; height: 14px; margin-top: 3px; border-radius: 50%; background: var(--paper); box-shadow: inset 0 0 0 2px var(--ink-35); display: grid; place-items: center; color: var(--paper); }
.ab .tl-item.done .tl-mark > i { background: var(--ink); box-shadow: none; }
.ab .tl-mark > i > .ic { width: 10px; height: 10px; background: currentColor; }
.ab .tl-item.done .tl-mark::before { background: var(--ink); }
.ab .tl-item.now .tl-mark > i { background: var(--accent); box-shadow: 0 0 0 4px var(--accent-soft); }
.ab .tl-body .ttl { font-weight: 700; font-size: 15px; line-height: 1.3; }
.ab .tl-body .meta { font-size: 13px; color: var(--ink-62); margin-top: 3px; }
.ab .tl-item.next .tl-body .ttl { color: var(--ink-70); font-weight: 600; }
.ab .tl.tight .tl-item { grid-template-columns: 64px 20px minmax(0, 1fr); padding-bottom: 16px; }
.ab .tl.tight .tl-mark::before { bottom: -16px; }
.ab .tl.tight .tl-body .ttl { font-size: 13.5px; font-weight: 600; }

/* board (tasks, leads) */
.ab .board { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 14px; flex: 1 1 auto; min-height: 0; }
.ab .col { background: var(--ink-04); border-radius: var(--r-md); padding: 0 10px 10px; display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.ab .col-hd { display: flex; align-items: center; gap: 8px; padding: 13px 4px 5px; font: 500 11px/1 var(--mono); letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-70); }
.ab .col-hd .ct { background: var(--ink-08); border-radius: 10px; padding: 3px 7px; font-size: 11px; letter-spacing: 0; }
.ab .col-hd .sum { margin-left: auto; font-size: 11px; letter-spacing: 0.02em; color: var(--ink-62); }
.ab .kcard { background: var(--paper); border: 1px solid var(--ink-18); border-radius: var(--r-sm); padding: 11px 12px; display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.ab .kcard.hot { box-shadow: inset 3px 0 0 var(--accent); }
.ab .kcard .ttl { font-size: 13.5px; font-weight: 600; line-height: 1.3; }
.ab .kcard .meta { font-size: 12px; color: var(--ink-62); line-height: 1.35; }
.ab .kcard .foot { display: flex; align-items: center; gap: 6px; }
.ab .kcard .foot.wrap { flex-wrap: wrap; }
.ab .kcard.done .ttl { color: var(--ink-62); }

/* threads and messages */
.ab .thread { display: flex; flex-direction: column; gap: 18px; }
.ab .msg { display: grid; grid-template-columns: 28px minmax(0, 1fr); column-gap: 12px; }
.ab .msg .hd { display: flex; align-items: baseline; gap: 8px; }
.ab .msg .who { font-weight: 700; font-size: 13.5px; }
.ab .msg .org { font-size: 12.5px; color: var(--ink-62); }
.ab .msg .when { font: 500 11px/1 var(--mono); color: var(--ink-62); margin-left: auto; white-space: nowrap; }
.ab .msg .body { margin-top: 4px; font-size: 14px; line-height: 1.5; }
.ab .msg.internal .body { background: var(--warn-soft); border-radius: var(--r-sm); padding: 8px 10px; }
.ab .msg .att { margin-top: 8px; display: inline-flex; align-items: center; gap: 7px; border: 1px solid var(--ink-18); border-radius: var(--r-sm); padding: 6px 9px; font-size: 12.5px; }
.ab .composer { border: 1px solid var(--edge); border-radius: var(--r-md); padding: 12px 14px; display: flex; flex-direction: column; gap: 12px; }
.ab .composer .ph { font-size: 14px; min-height: 40px; }
.ab.portal .msg .body, .ab.mobile .msg .body { font-size: 15.5px; }
.ab.portal .msg .who, .ab.mobile .msg .who { font-size: 15px; }

/* the approval block: what is being approved, by whom, by when */
.ab .approve { border: 1px solid var(--ink); border-radius: var(--r-md); padding: 20px; display: flex; flex-direction: column; gap: 16px; }
.ab .approve .stmt { font-size: 16px; line-height: 1.45; font-weight: 600; }
.ab .incl { display: flex; flex-direction: column; gap: 8px; font-size: 14px; }
.ab .incl li { display: flex; gap: 9px; align-items: flex-start; }
.ab .incl .ic { margin-top: 3px; color: var(--ink); flex: none; }
.ab .approve .acts { display: flex; gap: 10px; }
.ab .receipt { border: 1px solid var(--pos); background: var(--pos-soft); border-radius: var(--r-md); padding: 16px 18px; }

/* deliverable preview canvas + pinned comments */
.ab .canvas { position: relative; border: 1px solid var(--ink-18); border-radius: var(--r-md); background: var(--ink-04); overflow: hidden; }
.ab .canvas-bar { display: flex; align-items: center; gap: 10px; height: 40px; padding: 0 14px; border-bottom: 1px solid var(--ink-18); background: var(--paper); font-size: 12.5px; color: var(--ink-62); }
.ab .canvas-bar .url { font: 500 11.5px/1 var(--mono); color: var(--ink-70); }
.ab .pin { position: absolute; width: 26px; height: 26px; margin: -13px 0 0 -13px; border-radius: 50% 50% 50% 4px; background: var(--ink); color: var(--paper); display: grid; place-items: center; font: 600 11px/1 var(--mono); box-shadow: 0 2px 6px rgba(20, 23, 20, 0.3); }
.ab .pin.on { background: var(--accent); color: var(--accent-ink); }
.ab .pin.done { background: var(--paper); color: var(--ink-62); box-shadow: inset 0 0 0 1.5px var(--ink-35); }

/* wire blocks: stand-ins for a client's product inside a preview canvas */
.ab .wf { background: var(--paper); border: 1px solid var(--ink-18); border-radius: 5px; }
.ab .wf-bar { height: 8px; border-radius: 4px; background: var(--ink-18); }
.ab .wf-bar.dk { background: var(--ink-35); }
.ab .wf-bar.ac { background: var(--accent); }
.ab .wf-fill { background: var(--ink-08); border-radius: 4px; }

/* log viewer: light, same material as everything else */
.ab .log { background: var(--ink-04); border-radius: var(--r-sm); padding: 14px 16px; font: 400 12px/1.7 var(--mono); color: var(--ink-70); overflow: hidden; white-space: pre; }
.ab .log .t { color: var(--ink-35); }
.ab .log .ok { color: var(--pos-ink); }
.ab .log .bad { color: var(--neg-ink); }
.ab .log .hl { color: var(--ink); font-weight: 600; }
.ab .diff { font: 500 12px/1 var(--mono); white-space: nowrap; }
.ab .diff .a { color: var(--pos-ink); } .ab .diff .d { color: var(--neg-ink); }

/* stepper (wizards, pipelines) */
.ab .steps { display: flex; align-items: center; gap: 10px; font: 500 11px/1 var(--mono); letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-62); }
.ab .steps .s { display: inline-flex; align-items: center; gap: 7px; }
.ab .steps .s.done { color: var(--ink); }
.ab .steps .s.on { color: var(--ink); box-shadow: inset 0 -2px 0 var(--accent); padding-bottom: 5px; margin-bottom: -5px; }
.ab .steps .sep { width: 18px; height: 1px; background: var(--ink-18); }
.ab .pipe { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 2px; }
.ab .pipe .p { padding: 10px 12px; background: var(--ink-04); font-size: 12.5px; display: flex; flex-direction: column; gap: 4px; }
.ab .pipe .p:first-child { border-radius: var(--r-sm) 0 0 var(--r-sm); } .ab .pipe .p:last-child { border-radius: 0 var(--r-sm) var(--r-sm) 0; }
.ab .pipe .p.done { background: var(--pos-soft); } .ab .pipe .p.run { background: var(--accent-soft); } .ab .pipe .p.bad { background: var(--neg-soft); }

/* totals (proposals) */
.ab .totals { margin-left: auto; width: min(300px, 100%); display: grid; grid-template-columns: 1fr auto; row-gap: 8px; font-size: 14px; }
.ab .totals .g { padding-top: 10px; border-top: 1px solid var(--ink); font-weight: 800; font-size: 17px; }

/* AI draft block: a draft is marked as a draft until a person accepts it */
.ab .draft { border: 1px dashed var(--ink-35); border-radius: var(--r-md); }
.ab .draft-hd { display: flex; align-items: center; gap: 10px; padding: 10px 14px; border-bottom: 1px dashed var(--ink-18); font-size: 12.5px; color: var(--ink-70); }
.ab .draft-bd { padding: 16px 18px; }

/* file rows */
.ab .fico { width: 30px; height: 36px; border: 1px solid var(--ink-35); border-radius: 4px; display: grid; place-items: end center; padding-bottom: 5px; font: 600 8px/1 var(--mono); letter-spacing: 0.04em; color: var(--ink-70); flex: none; }
.ab .mark { flex: none; background: var(--plate); box-shadow: 0 0 0 4px var(--plate); }
.ab .swatch { width: 100%; height: 56px; border-radius: var(--r-sm); box-shadow: inset 0 0 0 1px var(--swatch-edge); }

/* overlays */
.ab .scrim { position: absolute; inset: 0; background: var(--scrim); display: grid; place-items: center; z-index: 20; }
/* not ".top": that name belongs to the workspace top bar and would collide */
.ab .scrim.from-top { place-items: start center; padding-top: 120px; }
.ab .dialog { width: 520px; max-width: calc(100% - 32px); background: var(--paper); border-radius: var(--r-lg); box-shadow: var(--shadow-pop); display: flex; flex-direction: column; }
.ab .dialog-hd { padding: 22px 24px 0; }
.ab .dialog-bd { padding: 16px 24px 22px; display: flex; flex-direction: column; gap: 16px; }
.ab .dialog-ft { padding: 16px 24px; border-top: 1px solid var(--ink-08); display: flex; justify-content: flex-end; gap: 10px; }
.ab .menu { background: var(--paper); border: 1px solid var(--ink-18); border-radius: var(--r-md); box-shadow: var(--shadow-pop); padding: 6px; display: flex; flex-direction: column; min-width: 200px; }
.ab .menu .mi { padding: 8px 10px; border-radius: var(--r-sm); font-size: 13.5px; display: flex; align-items: center; gap: 10px; }
.ab .menu .mi.on { background: var(--ink-08); }
.ab .menu .mi kbd, .ab .kbd { margin-left: auto; font: 500 11px/1 var(--mono); border: 1px solid var(--ink-18); border-radius: 4px; padding: 3px 5px; color: var(--ink-62); }
.ab .toast { display: inline-flex; align-items: center; gap: 10px; background: var(--ink); color: var(--paper); border-radius: var(--r-sm); padding: 11px 14px; font-size: 13.5px; box-shadow: var(--shadow-pop); }

/* empty, loading, error */
.ab .empty { padding: 44px 24px; display: flex; flex-direction: column; align-items: flex-start; gap: 10px; max-width: 46ch; }
.ab .empty .ttl { font-size: 16px; font-weight: 700; }
.ab .sk { height: 10px; border-radius: 5px; background: var(--ink-08); }
.ab .banner { display: flex; align-items: center; gap: 12px; padding: 12px 16px; border-radius: var(--r-sm); font-size: 13.5px; }
.ab .banner.neg { background: var(--neg-soft); color: var(--neg-ink); }
.ab .banner.warn { background: var(--warn-soft); color: var(--warn-ink); }
.ab .banner.pos { background: var(--pos-soft); color: var(--pos-ink); }
.ab .banner.ink { background: var(--ink-04); color: var(--ink-70); }

/* auth layout */
.ab .auth { height: 100%; display: grid; grid-template-columns: minmax(0, 1fr); place-items: center; padding: 24px; }
.ab .auth-card { width: 400px; max-width: 100%; display: flex; flex-direction: column; gap: 24px; }

/* email sheet: same construction as the live acknowledgement email */
.ab .mailbg { background: var(--mail-bg); height: 100%; padding: 32px; display: grid; grid-template-columns: repeat(auto-fit, minmax(0, 1fr)); gap: 24px; align-items: start; }
.ab .mail { background: var(--paper); border-top: 4px solid var(--accent); border-radius: 4px; padding: 26px 26px 22px; display: flex; flex-direction: column; gap: 14px; font-size: 14.5px; line-height: 1.55; }
.ab .mail .subj { font: 500 11px/1.4 var(--mono); letter-spacing: 0.04em; color: var(--ink-62); padding-bottom: 12px; border-bottom: 1px solid var(--ink-08); }
.ab .mail .subj b { color: var(--ink); font-weight: 600; }
.ab .mail h3 { font-size: 20px; line-height: 1.2; font-weight: 800; letter-spacing: -0.01em; }
.ab .mail .quote { background: var(--ink-04); border-radius: 4px; padding: 12px 14px; font-size: 14px; }
.ab .mail .ft { font-size: 12px; color: var(--ink-62); padding-top: 12px; border-top: 1px solid var(--ink-08); }

/* state sheets: several small frames on one artboard */
.ab .sheet { height: 100%; padding: 32px; display: grid; gap: 24px; background: var(--ink-04); align-content: start; }
.ab .frame { background: var(--paper); border: 1px solid var(--ink-18); border-radius: var(--r-md); overflow: hidden; display: flex; flex-direction: column; min-width: 0; }
.ab .frame-cap { padding: 10px 14px; border-bottom: 1px solid var(--ink-08); font: 500 11px/1 var(--mono); letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-62); }
.ab .frame-bd { padding: 20px; flex: 1 1 auto; }

/* icons: mask images so they inherit currentColor (see hz-icons.css) */
.ab .ic { display: inline-block; width: 16px; height: 16px; flex: none; background: currentColor; -webkit-mask: var(--i) center / contain no-repeat; mask: var(--i) center / contain no-repeat; vertical-align: -3px; }
.ab .ic.sm { width: 13px; height: 13px; vertical-align: -2px; }
.ab .ic.lg { width: 20px; height: 20px; }

/* ==========================================================================
   RESPONSIVE LAYOUTS
   Each screen reads its own width (the artboard is a size container), so the
   same page works from a folded phone to an ultrawide, and the viewer can show
   any screen at any device size inside one document. Lines on the artboard:
     480   phone and folded phone below, big phone and open fold above
     760   the portal's phone line (design plan): below it the portal is the
           phone design (m-*), above it the desktop design (c-*)
     1024  the workspace sidebar: below it, a menu opens it as a drawer
     1100  main plus a side column: below it the side column goes under
     1920  wide: the side column widens
     2400  ultrawide: content keeps a centred 1760px column
   Nothing here applies at the design sizes (1440 wide, phones 390), so the
   drawn screens do not move.
   ========================================================================== */
.ab { container: ab / inline-size; }

/* a real device size: the page areas scroll instead of being cut at the edge */
.ab.fluid .page, .ab.fluid .pmain, .ab.fluid .mmain { overflow: auto; }
/* and what is on the page keeps its height: a strip or a table that scrolls
   sideways is a scroll container, which a column of flex items would otherwise
   squash to nothing when the page is longer than the screen */
.ab.fluid :is(.page, .pmain-in, .mmain) > * { flex-shrink: 0; }
/* a screen with no shell (a sign in, the emails, the states sheet) scrolls as a whole */
.ab.fluid:not(:has(> .shell, > .pshell, > .mshell)) { overflow: hidden auto; }
.ab.fluid > .auth, .ab.fluid > .mailbg, .ab.fluid > .sheet { height: auto; min-height: 100%; }
/* a bar or write box pinned to the foot of a phone screen (03-design): where
   the page is longer than the screen it stays in reach instead of scrolling away */
.ab.fluid .mmain > .pinned { position: sticky; bottom: 16px; z-index: 2; background: var(--paper); box-shadow: 0 20px 0 16px var(--paper); }

/* ---- a table on a narrow screen ---------------------------------------------
   A table stays a table for as long as it can. Where its box is narrower than
   the width it needs (data-fit on its wrapper), its least important columns
   (data-p="2" on their headings) are left out. Narrower than the width it needs
   without them (data-fit2), which is a phone or a narrow column, each row
   becomes a row of the product's own lists: the title and the value that
   matters on the first line, a quiet line under it, the action under that.
   data-m on a heading places its column: t the title, e the end of the first
   line, s the quiet line, sl the quiet line with the column's name, b a line of
   its own, a the action, x left out. A form or a comparison (data-list="form"
   on the table) becomes labelled lines instead. devices.mjs --fit measures both
   widths and the build writes the container queries; the build copies each
   heading's data-m, data-p and name onto the cells under it. */
.ab .tbl-wrap { container: tblw / inline-size; }
@container style(--list: 1) {
  .ab .tbl thead { display: none; }
  .ab .tbl:not([data-list="form"]) tbody { display: block; }
  .ab .tbl:not([data-list="form"]) tbody > tr { display: flex; flex-wrap: wrap; align-items: baseline; row-gap: 5px; padding: 13px 0; border-bottom: 1px solid var(--ink-08); }
  .ab .tbl.in-panel:not([data-list="form"]) tbody > tr { padding: 13px 18px; }
  .ab .tbl.in-panel:not([data-list="form"]) tbody > tr:last-child { border-bottom: 0; }
  .ab .tbl:not([data-list="form"]) tbody td, .ab .tbl:not([data-list="form"]) tbody td.r, .ab .tbl:not([data-list="form"]) tbody td:first-child, .ab .tbl:not([data-list="form"]) tbody td:last-child,
  .ab .tbl.in-panel:not([data-list="form"]) tbody td:first-child, .ab .tbl.in-panel:not([data-list="form"]) tbody td:last-child { display: block; width: auto; padding: 0; border: 0; text-align: left; background: none; }
  .ab .tbl:not([data-list="form"]) tbody > tr:hover td { background: none; }
  /* the first line: the title, and at its end the value that matters */
  .ab .tbl:not([data-list="form"]) tbody td[data-m="t"] { order: 1; flex: 1 1 0; min-width: 0; margin-right: 12px; font-weight: 600; }
  .ab .tbl:not([data-list="form"]) tbody td[data-m="e"] { order: 2; flex: none; text-align: right; }
  .ab .tbl:not([data-list="form"]) tbody td[data-m="e"] ~ td[data-m="e"] { margin-left: 12px; }
  .ab .tbl:not([data-list="form"]) tbody > tr::before { content: ""; order: 3; flex-basis: 100%; }
  /* the quiet line, each part kept whole, a drawn dot between them */
  .ab .tbl:not([data-list="form"]) tbody td:is([data-m="s"], [data-m="sl"]) { order: 4; max-width: 100%; font-size: 12.5px; color: var(--ink-62); }
  .ab .tbl:not([data-list="form"]) tbody td:is([data-m="s"], [data-m="sl"]) :is(.tv, .ttl) { display: inline; font: inherit; color: inherit; }
  .ab .tbl:not([data-list="form"]) tbody td:is([data-m="s"], [data-m="sl"]) .rowx { display: inline-flex; vertical-align: middle; }
  .ab .tbl:not([data-list="form"]) tbody td:is([data-m="s"], [data-m="sl"]) .meta { display: none; }
  .ab .tbl:not([data-list="form"]) tbody td:is([data-m="s"], [data-m="sl"]):has(~ td:is([data-m="s"], [data-m="sl"]):not([data-p="2"]))::after { content: ""; display: inline-block; width: 3px; height: 3px; border-radius: 50%; background: currentColor; opacity: 0.6; margin: 0 0.5em; vertical-align: middle; position: relative; top: -0.08em; }
  .ab .tbl:not([data-list="form"]) tbody td[data-m="sl"]::before { content: attr(data-label); margin-right: 0.45em; font: 500 11px/1 var(--mono); letter-spacing: 0.08em; text-transform: uppercase; }
  /* a line of its own, then the action */
  .ab .tbl:not([data-list="form"]) tbody td[data-m="b"] { order: 5; flex-basis: 100%; margin-top: 4px; }
  .ab .tbl:not([data-list="form"]) tbody td[data-m="a"] { order: 6; flex-basis: 100%; margin-top: 6px; }
  /* left out: a low priority column, an empty cell, an arrow that only repeats the row's link */
  .ab .tbl:not([data-list="form"]) tbody td:is([data-m="x"], [data-p="2"]), .ab .tbl:not([data-list="form"]) tbody td[data-m="a"]:has(> .tv > .ic:only-child) { display: none; }
  /* a form or a comparison: labelled lines, two to a row where there is room */
  .ab .tbl[data-list="form"] tbody { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 320px), 1fr)); column-gap: 32px; }
  .ab .tbl[data-list="form"] tbody > tr { display: flex; flex-direction: column; gap: 7px; padding: 14px 0; border-bottom: 1px solid var(--ink-08); }
  .ab .tbl.in-panel[data-list="form"] tbody > tr { padding: 14px 18px; }
  .ab .tbl[data-list="form"] tbody > tr:hover td { background: none; }
  .ab .tbl[data-list="form"] tbody td, .ab .tbl[data-list="form"] tbody td:is(.r, :first-child, :last-child) { display: flex; align-items: baseline; gap: 12px; width: auto; padding: 0; border: 0; text-align: left; background: none; }
  .ab .tbl[data-list="form"] tbody td::before { content: attr(data-label); flex: 0 0 34%; font: 500 11px/1.45 var(--mono); letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-62); }
  .ab .tbl[data-list="form"] tbody td > .tv { flex: 1 1 auto; min-width: 0; }
  .ab .tbl[data-list="form"] tbody td > .tv > * { max-width: 100%; }
  .ab .tbl[data-list="form"] tbody td:first-child { font-weight: 600; }
  .ab .tbl[data-list="form"] tbody td:first-child::before, .ab .tbl[data-list="form"] tbody td[data-label=""]::before { display: none; }
  .ab .tbl[data-list="form"] tbody td[data-label=""]:has(> .tv > .ic:only-child), .ab .tbl[data-list="form"] tbody td:has(> .tv:empty) { display: none; }
  .ab .tbl[data-list="form"] tbody td:has(.switch, .pbar, .stage) { align-items: center; }
}

/* ---- a table's phone list --------------------------------------------------
   Where a table no longer fits even without its low priority columns (a phone),
   it is replaced by its phone list, designed with the screen in the pattern of
   the portal's phone screens: rows grouped under a label where grouping helps,
   each row a title and one plain line under it, with one thing at the right (an
   amount, a pill or a status) on the title's line, and an action under the row
   only where the list exists to prompt it. No column labels inside rows. */
.ab .tbl-wrap > .plist { display: none; }
.ab .plist { flex-direction: column; gap: 24px; }
.ab .plist > section { display: flex; flex-direction: column; }
.ab .plist .pl-hd { display: flex; align-items: baseline; gap: 8px; padding-bottom: 6px; border-bottom: 1px solid var(--ink-18); }
.ab .plist .pl-hd .key { color: var(--ink-62); }
.ab .plist .row { align-items: baseline; }
.ab .plist .row > .num { font-weight: 600; }
.ab .plist .row .meta { margin-top: 3px; }
.ab .plist .pl-hd .dot { align-self: center; }
.ab .plist .pl-hd .push { font-size: 11px; }
/* the right of a row: a value, and under it the date or word that goes with it */
.ab .pl-end { flex: none; display: flex; flex-direction: column; align-items: flex-end; text-align: right; }
.ab .pl-end > .num { font-weight: 600; }
.ab .pl-end > .meta { margin-top: 3px; }
.ab .pl-end > .meta.neg { color: var(--neg-ink); }
/* a status on a line of its own under a row's words, and a stage line or bar */
.ab .plist .row .grow > .status { display: flex; margin-top: 6px; font-size: 12.5px; }
.ab .plist .row .grow > .stage, .ab .plist .row .grow > .pbar { margin-top: 10px; }
/* two switches or checks side by side under a row */
.ab .plist .pl-checks { display: flex; flex-wrap: wrap; gap: 6px 20px; margin-top: 10px; font-size: 13px; }
.ab .plist .pl-act { display: flex; flex-wrap: wrap; gap: 8px; padding: 0 0 14px; margin-top: -3px; }
.ab .plist .pl-total { display: flex; align-items: baseline; gap: 12px; padding-top: 12px; border-top: 1px solid var(--ink); font-weight: 700; }
.ab .plist .pl-total > .num { margin-left: auto; }
/* a phone list inside a panel keeps the panel's side padding for its headings */
.ab .plist.in-panel { gap: 0; }
.ab .plist.in-panel .pl-hd { padding: 12px 18px 6px; }
/* a key and value list on a phone: the key over its value */
.ab .plist .pl-kv { row-gap: 9px; padding-top: 12px; }

/* only drawn where they are needed */
.ab .top-menu, .ab .nav-scrim { display: none; }

/* A strip that scrolls sideways (tabs, a segmented control) fades at the edge
   that has more, so a cut label reads as "more this way". Driven by its own
   scroll position; a browser without scroll timelines shows no fade. */
@property --fade-l { syntax: '<length>'; inherits: false; initial-value: 0px; }
@property --fade-r { syntax: '<length>'; inherits: false; initial-value: 0px; }
@keyframes hz-edge-fade { from { --fade-l: 0px; --fade-r: 36px; } to { --fade-l: 36px; --fade-r: 0px; } }

@container ab (max-width: 1439px) {
  /* below the design width a header or toolbar that no longer fits wraps, and
     a table or log wider than its box scrolls sideways inside it */
  .ab .page-hd, .ab .page-hd > .rowx, .ab .page > .rowx { flex-wrap: wrap; row-gap: 12px; }
  .ab .tools { flex-wrap: wrap; max-width: 100%; min-width: 0; }
  .ab .kcard .foot { flex-wrap: wrap; }
  /* a board keeps columns wide enough for a card's longest pill; five fit a laptop */
  .ab .board { grid-auto-columns: minmax(190px, 1fr); overflow-x: auto; }
  @supports (animation-timeline: scroll()) {
    .ab .board { mask-image: linear-gradient(to right, transparent, #000 var(--fade-l), #000 calc(100% - var(--fade-r)), transparent); animation: hz-edge-fade linear both; animation-timeline: scroll(self inline); }
  }
  .ab .tbl-wrap { overflow-x: auto; }
  /* a column's drawn width holds at the design size; below it the table shares out the room */
  .ab .tbl th { width: auto; }
  .ab .log { overflow-x: auto; scrollbar-width: none; }
}

@container ab (max-width: 1099px) {
  .ab .g-main, .ab .g-main.wide { grid-template-columns: minmax(0, 1fr); }
}

@container ab (max-width: 1023px) {
  /* workspace: the sidebar becomes a drawer behind a menu button */
  .ab .shell { grid-template-columns: minmax(0, 1fr); }
  .ab .side { display: none; }
  .ab.nav-open .side { display: flex; position: absolute; z-index: 31; top: 0; bottom: 0; left: 0; width: 264px; max-width: 86%; background: var(--paper); box-shadow: var(--shadow-pop); }
  .ab.nav-open .nav-scrim { display: block; position: absolute; inset: 0; z-index: 30; background: var(--scrim); }
  .ab .top-menu { display: grid; place-items: center; flex: none; width: 44px; height: 44px; margin-left: -12px; }
  .ab .top { padding: 0 20px; gap: 12px; }
  .ab .crumbs > span { display: none; }
  .ab .search { width: 44px; height: 40px; padding: 0; justify-content: center; }
  .ab .search > span, .ab .search kbd { display: none; }
  .ab .page { padding: 20px; }
  .ab .proj { padding: 18px 20px 0; }
  .ab .proj-row { flex-wrap: wrap; row-gap: 10px; }
  .ab .proj .now { order: 3; flex: 1 1 100%; }
  /* long rows of tabs scroll sideways rather than wrap; the strip keeps 10px
     of room around its tabs (taken back with a negative margin, so nothing
     moves) so a tab's focus ring and its touch target are not cut off */
  .ab .tabs, .ab .ptabs { overflow-x: auto; scrollbar-width: none; padding: 10px; margin: -10px; }
  @supports (animation-timeline: scroll()) {
    .ab .tabs, .ab .ptabs { mask-image: linear-gradient(to right, transparent, #000 var(--fade-l), #000 calc(100% - var(--fade-r)), transparent); animation: hz-edge-fade linear both; animation-timeline: scroll(self inline); }
  }
  .ab .g3, .ab .g4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* boards and tables keep a readable width and scroll sideways */
  .ab .board { grid-auto-columns: minmax(248px, 1fr); overflow-x: auto; }
  /* portal on a tablet or an open fold */
  .ab .ptop-in { padding: 0 24px; }
  .ab .pmain-in { padding: 28px 24px 32px; }
  .ab .pproj { flex-wrap: wrap; row-gap: 6px; }
}

@container ab (max-width: 759px) {
  .ab .g2, .ab .g3, .ab .g4 { grid-template-columns: minmax(0, 1fr); }
  .ab .stage:not(.compact) { overflow-x: auto; grid-auto-columns: minmax(112px, 1fr); scrollbar-width: none; }
  .ab .pipe { grid-auto-flow: row; }
  .ab .steps { flex-wrap: wrap; row-gap: 10px; }
  /* a workspace row keeps at least 200px for its title: what does not fit
     beside it (pills, times, buttons) goes to a second line, and an arrow at
     the end stays at the right, centred on the row */
  .ab .page .row { flex-wrap: wrap; row-gap: 8px; }
  .ab .page .row > .grow { flex: 1 1 200px; overflow-wrap: break-word; }
  /* a row with no button is laid out as on the portal's phone screens: its
     words on the left, and at the right, on the title's line, its one value,
     pill or status, which never drops under the words */
  .ab .page .row:not(:has(> .btn)) { flex-wrap: nowrap; align-items: baseline; }
  .ab .page .row:not(:has(> .btn)) > .grow { flex: 1 1 0; }
  .ab .page .row:not(:has(> .btn)) > :not(.grow) { flex: none; }
  .ab .page .row > :is(.av, .fico, .key:first-child, .tag:first-child) { align-self: flex-start; }
  /* a row with a title: the title and its one value, pill or status share the
     first line, and the lines under the title use the row's full width. A
     leading avatar, key or file icon keeps its own column. */
  .ab .page .row:not(:has(> .btn, > .stage, > .pl-end)):has(> .grow > .ttl) { display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 12px; row-gap: 0; align-items: baseline; }
  .ab .page .row:not(:has(> .btn, > .stage, > .pl-end)):has(> .grow > .ttl):has(> :first-child:not(.grow)) { grid-template-columns: auto minmax(0, 1fr) auto; }
  .ab .page .row:not(:has(> .btn, > .stage, > .pl-end)):has(> .grow > .ttl) > .grow { display: contents; }
  .ab .page .row:not(:has(> .btn, > .stage, > .pl-end)):has(> .grow > .ttl) > .grow > * { grid-column: -3 / -2; }
  .ab .page .row:not(:has(> .btn, > .stage, > .pl-end)):has(> .grow > .ttl) > .grow > :not(.ttl) { grid-column: -3 / -1; }
  .ab .page .row:not(:has(> .btn, > .stage, > .pl-end)):has(> .grow > .ttl) > :not(.grow) { grid-column: -2 / -1; grid-row: 1; justify-self: end; }
  .ab .page .row:not(:has(> .btn, > .stage, > .pl-end)):has(> .grow > .ttl) > :first-child:not(.grow) { grid-column: 1; grid-row: 1 / span 2; justify-self: start; align-self: start; }
  .ab .page .row:not(:has(> .btn, > .stage, > .pl-end)):has(> .grow > .ttl) > :not(.grow):not(:first-child) ~ :not(.grow) { grid-row: 2; }
  .ab .page .row:not(:has(> .btn, > .stage, > .pl-end)):has(> .grow > .ttl) > .switch { align-self: center; }
  /* a trailing arrow is placed against the row itself, centred on it */
  .ab .page .row:not(:has(> .btn, > .stage, > .pl-end)):has(> .grow > .ttl) > .ic:last-child:not(.grow):not(:first-child) { grid-column: auto; grid-row: auto; top: 0; bottom: 0; margin: auto 0; transform: none; align-self: auto; }
  .ab .page .row > .switch { align-self: center; }
  /* a row that starts with a tag (Today's cards): the tag and its time on the
     first line, the words under them at full width, the action under those */
  .ab .page .row:has(> .tag:first-child) { flex-wrap: wrap; align-items: center; }
  .ab .page .row:has(> .tag:first-child) > .when { order: 1; margin-left: auto; }
  .ab .page .row:has(> .tag:first-child) > .grow { order: 2; flex: 1 1 100%; }
  .ab .page .row:has(> .tag:first-child) > .btn { order: 3; }
  /* a switch's touch target stays inside the row */
  .ab.touch .page .row > .switch:last-child { margin-right: 0; }
  .ab .page .row:has(> .ic:last-child) { position: relative; padding-right: 46px; }
  .ab .page .row > .ic:last-child { position: absolute; right: 18px; top: 50%; transform: translateY(-50%); }
  .ab .page .rows.bare > .row:has(> .ic:last-child) { padding-right: 28px; }
  .ab .page .rows.bare > .row > .ic:last-child { right: 0; }
  /* a heading row gives its title the width first, the pill goes under it */
  .ab .page > .rowx, .ab .page > .stack > .rowx:first-child { flex-wrap: wrap; row-gap: 8px; }
  /* a segmented control wider than the screen scrolls, like the tabs */
  .ab .seg { overflow-x: auto; scrollbar-width: none; }
  @supports (animation-timeline: scroll()) {
    .ab .seg { mask-image: linear-gradient(to right, transparent, #000 var(--fade-l), #000 calc(100% - var(--fade-r)), transparent); animation: hz-edge-fade linear both; animation-timeline: scroll(self inline); }
  }
  /* a log wraps its lines instead of cutting them */
  .ab .log { white-space: pre-wrap; overflow-wrap: anywhere; }
  /* a row of buttons wraps rather than run off the screen, and a long status
     wraps under its dot */
  .ab .rowx:has(> .btn) { flex-wrap: wrap; row-gap: 8px; }
  .ab .page .status { white-space: normal; }
  /* a status with more to say runs as one line of text after its dot */
  .ab .page .status:has(> .sd) { display: block; }
  .ab .page .status:has(> .sd) > .dot { margin-right: 7px; vertical-align: 1px; }
  .ab .page .status:has(> .sd) > .sd { margin: 0 0.5em; top: -0.08em; }
  /* a canvas's bar wraps its words instead of squeezing them */
  .ab .canvas-bar { flex-wrap: wrap; height: auto; min-height: 40px; padding-top: 8px; padding-bottom: 8px; row-gap: 4px; }
  /* pipeline steps: one line each, the time at the right */
  .ab .pipe .p { flex-direction: row; justify-content: space-between; align-items: baseline; padding: 9px 12px; }
  .ab .mailbg { grid-template-columns: minmax(0, 1fr); padding: 16px; }
  .ab .sheet { padding: 16px; }
  /* a phone draws its scrollbars over the page, so a phone screen shown on a
     desktop takes no room for one; on the phone itself its own overlay shows */
  @media (pointer: fine) { .ab.fluid, .ab.fluid .page, .ab.fluid .pmain, .ab.fluid .mmain { scrollbar-width: none; } }
}

@container ab (max-width: 479px) {
  /* a board shows one column at a time, snapping, the next one's edge in view */
  .ab .board { grid-auto-columns: calc(100% - 28px); gap: 8px; scroll-snap-type: x mandatory; }
  .ab .board > .col { scroll-snap-align: start; }
  /* a message's header: the time stays right, the organisation wraps under the name */
  .ab .msg .hd { flex-wrap: wrap; row-gap: 2px; }
  .ab .top { padding: 0 16px; }
  .ab .page { padding: 16px; }
  .ab .proj { padding: 16px 16px 0; }
  .ab .ptop-in { padding: 0 16px; }
  .ab .pmain-in { padding: 20px 16px 28px; }
}

/* a folded phone (344): the phone's tab labels keep a gap between them */
@container ab (max-width: 359px) {
  .ab .mtab { letter-spacing: 0.03em; }
}

/* the phone design on a big phone or an open fold: one centred reading column */
@container ab (min-width: 480px) and (max-width: 759px) {
  .ab .mtop, .ab .mmain { padding-inline: max(16px, calc((100% - 560px) / 2)); }
}

@container ab (min-width: 1920px) {
  .ab .g-main { grid-template-columns: minmax(0, 1fr) 420px; }
}

@container ab (min-width: 2400px) {
  .ab .top, .ab .proj, .ab .page, .ab .sheet { padding-inline: max(32px, calc((100% - 1760px) / 2)); }
}
