
:root {
  color-scheme: light;
  --font-family: "Noto Sans", "Noto Sans SC", "Noto Sans Arabic", system-ui, sans-serif;
  --font-voice: "Noto Serif", "Noto Serif SC", "Noto Naskh Arabic", Georgia, serif;
  --font-size-caption: 13px;
  --font-size-small: 15px;
  --font-size-base: 17px;
  --font-size-title: 20px;
  --font-size-display: 26px;
  --font-size-hero: 34px;
  --font-size-overview-title: 44px;
  --font-size-overview-phone: 36px;
  --font-size-overview-money: 40px;
  --line-height: 1.6;
  --line-height-tight: 1.2;
  --tracking-tight: -0.02em;
  --color-ok: #3F6B5C;
  --color-brand: #9A0F5E;
  --color-needs: #9A0F5E;
  --color-needs-wash: #F9EAF2;
  --color-warn: #171717;
  --color-assistant: #171717;
  --color-assistant-wash: #F9EAF2;
  --color-ink: #171717;
  --color-ink-secondary: #625D57;
  --color-surface: #FFFDFA;
  --color-paper: #F7F3EE;
  --color-sand: #EDE7DF;
  --color-border: #DED7CF;
  --color-ok-wash: #FFFDFA;
  --color-ok-line: #DED7CF;
  --color-warn-wash: #FFFDFA;
  --color-warn-line: #DED7CF;
  --color-orb-glow: #9A0F5E;
  --color-coin: #5A0A2E;
  --color-coin-ground: #F5F1EA;
  --color-nav-active: var(--color-needs);
  --color-accent: var(--color-needs);
  --space-4: 4px;
  --space-8: 8px;
  --space-12: 12px;
  --space-16: 16px;
  --space-20: 20px;
  --space-24: 24px;
  --space-32: 32px;
  --space-40: 40px;
  --space-48: 48px;
  --radius-control: 12px;
  --radius-card: 16px;
  --radius-panel: 20px;
  --radius-chip: 999px;
  --measure-column: 1040px;
  --measure-prose: 62ch;
  --measure-form: 40ch;
  --shadow-lift1: none;
  --shadow-lift2: none;
  --motion-fast: 160ms;
  --motion-normal: 220ms;
  --motion-max: 250ms;
  --motion-step: 40ms;
  --motion-ease: cubic-bezier(0.25, 0.46, 0.45, 0.94);
  --motion-ease-in: cubic-bezier(0.55, 0.085, 0.68, 0.53);
  --motion-spring: cubic-bezier(0.34, 1.3, 0.64, 1);
  --travel-nudge: 2px;
  --travel-fold: 8px;
  --travel-page: 12px;
  --travel-rise: 16px;
  --travel-toast: 24px;
  --travel-sheet: 48px;
  --motion-scale-press: 0.97;
  --motion-scale-enter: 0.96;
  --face-1-bg: #3366A8;
  --face-1-fg: #FFFFFF;
  --face-2-bg: #187A70;
  --face-2-fg: #FFFFFF;
  --face-3-bg: #6B7320;
  --face-3-fg: #FFFFFF;
  --face-4-bg: #8C6B0A;
  --face-4-fg: #FFFFFF;
  --face-5-bg: #AD5C14;
  --face-5-fg: #FFFFFF;
  --face-6-bg: #6450B0;
  --face-6-fg: #FFFFFF;
  --face-7-bg: #0F7085;
  --face-7-fg: #FFFFFF;
  --face-8-bg: #8A5A3C;
  --face-8-fg: #FFFFFF;
}
html[lang="zh"] { --line-height: 1.7; --font-family: "Noto Sans SC", "Noto Sans", "Noto Sans Arabic", system-ui, sans-serif; --font-voice: "Noto Serif SC", "Noto Serif", "Noto Naskh Arabic", serif; --line-height-tight: 1.35; --tracking-tight: 0; }
html[lang="ar"] { --line-height: 1.75; --font-family: "Noto Sans Arabic", "Noto Sans", "Noto Sans SC", system-ui, sans-serif; --font-voice: "Noto Naskh Arabic", "Noto Serif", "Noto Serif SC", serif; --line-height-tight: 1.45; --tracking-tight: 0; }
  * { box-sizing: border-box; }
  body { margin: 0; background: var(--color-paper); color: var(--color-ink);
    font: var(--font-size-base)/var(--line-height) var(--font-family); }
  a { color: inherit; text-decoration: none; }
  /* The identity system (2026-10-04) — what the owner selects is lifted out in the brand. */
  ::selection { background:var(--color-brand); color:var(--color-surface); }
  /* Anything a PERSON says — her draft, a buyer's quoted words. Never a label. */
  .voice { font-family: var(--font-voice); }
  /* THE WARMTH RUN (2026-10-03) — a customer's face (faces.ts): their photo laid
     on their coloured initial, round. The initial is always there under it, so a
     photo that does not arrive leaves the initial, never a hole. */
  .face { position:relative; display:inline-grid; place-items:center; flex:none; overflow:hidden;
    border-radius:var(--radius-chip); inline-size:40px; block-size:40px; font-size:var(--font-size-base);
    font-weight:600; line-height:1; user-select:none; }
  .face-xs { inline-size:24px; block-size:24px; font-size:var(--font-size-caption); }
  .face-s { inline-size:32px; block-size:32px; font-size:var(--font-size-small); }
  .face-l { inline-size:56px; block-size:56px; font-size:var(--font-size-title); }
  .face-xl { inline-size:96px; block-size:96px; font-size:var(--font-size-hero); }
  .face-i { display:grid; place-items:center; inline-size:100%; block-size:100%; }
  /* The Solar run — the person drawn for a customer with no name yet is Solar's, at 1.4em of the face's size; its
     line is the one for the size it is drawn at (18 px on the smallest face, 24 on the usual one). */
  .face-i svg { inline-size:1.4em; block-size:1.4em; }
  .face-p { position:absolute; inset:0; inline-size:100%; block-size:100%; object-fit:cover; }
  .face.t1 { background:var(--face-1-bg); color:var(--face-1-fg); }
  .face.t2 { background:var(--face-2-bg); color:var(--face-2-fg); }
  .face.t3 { background:var(--face-3-bg); color:var(--face-3-fg); }
  .face.t4 { background:var(--face-4-bg); color:var(--face-4-fg); }
  .face.t5 { background:var(--face-5-bg); color:var(--face-5-fg); }
  .face.t6 { background:var(--face-6-bg); color:var(--face-6-fg); }
  .face.t7 { background:var(--face-7-bg); color:var(--face-7-fg); }
  .face.t8 { background:var(--face-8-bg); color:var(--face-8-fg); }
  .face-link { display:inline-flex; align-items:center; gap:var(--space-8); color:inherit; min-width:0; }
  .face-link:focus-visible { outline:none; }
  .face-link:focus-visible .face { outline:2px solid var(--color-brand); outline-offset:2px; }
  /* w4-whole-22 — a pressed face is opening its card: it dims until the card is there. */
  .face-link[aria-busy="true"] .face { opacity:0.6; }
  .layout { display: grid; grid-template-columns: 208px 1fr; min-height: 100vh; }
  /* A grid child does not shrink below its own content unless told to: its
     default min-width is auto, so one unbreakable string — a long sku, a URL a
     buyer pasted — widens the content track and scrolls the whole page
     sideways. Nothing in the product does that today; this is the guard, not a
     repair. */
  .layout > * { min-width: 0; }
  /* The rail (the design pass): its groups down the side, Setup and Log out
     at its foot, and the whole of it in view while the page scrolls. */
  nav.side { background: var(--color-paper); border-inline-end: 1px solid var(--color-border);
    padding: var(--space-16) var(--space-12); display:flex; flex-direction:column;
    position:sticky; top:0; height:100vh; overflow-y:auto; }
  .navgroup + .navgroup { margin-top: var(--space-12); }
  .navfoot { margin-top:auto; padding-top: var(--space-16); }
  .brand { display:flex; align-items:center; gap:var(--space-8); font-weight: 700;
    font-size: var(--font-size-base); padding: 6px 12px 18px; letter-spacing: var(--tracking-tight); }
  .brand .mark { flex:none; }
  /* Two cuts of one mark (brand.ts): the detail cut beside the word on a desktop,
     the small reversed cut alone in the phone nav — below 40px the pale disc
     would not read. One is drawn at a time. */
  .brand .mark-detail { display:flex; }
  .brand .mark-small { display:none; }
  .brand small { display:block; color:var(--color-ink-secondary); font-weight:500;
    font-size:var(--font-size-caption); letter-spacing:0; margin-top:var(--space-4); }
  /* CC-14 — the business's own name leads the block, and a long one wraps
     inside the rail rather than widening it. */
  /* Phase 9 (V1-014, V1-099) — a Chinese name is one word: it breaks only at
     its spaces. One too long to sit beside the mark goes under it, where the
     rail's whole width is its own; a word longer than the rail still breaks. */
  .brand { flex-wrap:wrap; }
  .brand .brandname { flex:1 1 0; max-width:100%; overflow-wrap:break-word; }
  .brand .brandname bdi { word-break:keep-all; }
  /* On a phone the rail is one row with no room for a name, so the name heads
     Today instead: one line that scrolls away with the page. Drawn on the
     phone only; the rail carries it everywhere else. */
  .business-name { display:none; margin:0 0 var(--space-4); font-size:var(--font-size-caption);
    font-weight:600; color:var(--color-ink-secondary); overflow-wrap:anywhere; }
  /* CC-20 — the way past the nav for a keyboard: out of sight until it has
     focus, then the first thing on the page, over the rail. */
  .skip { position:absolute; top:calc(-2 * var(--space-48)); inset-inline-start:var(--space-8); z-index:3;
    padding:var(--space-8) var(--space-16); border-radius:var(--radius-card);
    background:var(--color-surface); color:var(--color-ink); box-shadow:var(--shadow-lift2);
    font-size:var(--font-size-small); font-weight:600; }
  .skip:focus, .skip:focus-visible { top:var(--space-8); }
  /* THE WARMTH RUN, phase 1 — each entry is its shape and its word. */
  /* The icons run (2026-10-04) — the icon is level with the word's FIRST line, not with the word and its count
     together: the row starts at the top, its padding centres one line in the row's height, and the icon
     sits in that line (the Solar nav: a 28 px icon in a 24 to 26 px line). It used to drop 10.5 px under its word. */
  /* The Solar nav (2026-10-05) — airier, as the owner asked: each entry 52 px tall (it was 44), 16 px between
     the icon and its word (12), and 8 px between entries (4). */
  nav.side a.navlink { display: flex; align-items: flex-start; gap: var(--space-16); padding: var(--space-8) var(--space-12);
    padding-block: calc((52px - 1lh) / 2);
    min-height: 52px; border-radius: var(--radius-control); color: var(--color-ink-secondary);
    font-size: var(--font-size-small); font-weight:500; margin-bottom: var(--space-8); }
  /* The Solar nav (2026-10-05) — Solar's Linear drawings at 28 px (the Icons run's 24, sized up 15 per cent):
     a 1.5-unit line on a 24-unit square, so 1.75 px, between the stems of the 15 px words beside it at 500
     (1.5 to 1.6 px) and at 600 (1.9). Every icon in the ink, the wordmark's near-black, whatever the
     colour of its word. */
  nav.side .ni { flex:none; inline-size:28px; block-size:28px; margin-block:calc((1lh - 28px) / 2); color: var(--color-ink); }
  /* The fix wave (the guide's frames, 1024 px) — the word and its count wrap TOGETHER: the word keeps
     itself whole (never a letter a line), and where the two do not fit side by side the count goes
     under the word, aligned with it. On a phone the pair dissolves into the tile (display:contents). */
  nav.side .nl-body { display:flex; flex:1 1 auto; flex-wrap:wrap; align-items:center; column-gap:var(--space-8); row-gap:0; min-width:0; }
  nav.side .nl-text { flex:0 1 auto; max-inline-size:100%; overflow-wrap:break-word; }
  html[lang="zh"] nav.side .nl-text { word-break:keep-all; }
  /* An icon that points (Log out's arrow, a reply's) is mirrored on a right-to-left page, wherever it is drawn. */
  [dir="rtl"] svg.flips { transform:scaleX(-1); }
  nav.side a.navlink:hover { background: var(--color-surface); color: var(--color-ink); }
  /* The entry you are on is unmistakable without a colour: a raised white
     tile on the rail's grey, its word in weight, its icon in the deep magenta
     (the colour one job's variable). The Solar nav: the same line drawing as
     at rest — never a filled icon; the owner's "white pill with a deep-magenta
     icon". The needs dot means something waits, and it never sits on the icon
     of the entry you are on. */
  nav.side a.navlink.active { background: var(--color-surface); color: var(--color-ink); font-weight:600;
    box-shadow: var(--shadow-lift1); }
  nav.side a.navlink.active .ni { color: var(--color-nav-active); }
  /* The rail's one number: customers waiting for the owner. Wine under a white figure, the owner's choice; the row's dot is
     the same wine. Hidden at nothing; on a phone it rides the icon's corner. */
  nav.side .navcount { display:inline-flex; align-items:center; justify-content:center; flex:none; white-space:nowrap; min-inline-size:1.6em; padding:0 var(--space-4);
    font-size:var(--font-size-caption); font-weight:700; color:var(--color-surface); background:var(--color-coin);
    border-radius:var(--radius-chip); font-variant-numeric:tabular-nums; line-height:1.6; }
  /* V1 · option A (2026-09-24) — there is no header band. The nav row is the
     chrome; the language switch and log out are the first rows of Setup, and
     the login page keeps its own switcher. */
  .langsw { display:inline-flex; gap:var(--space-4); background:var(--color-sand);
    border:1px solid var(--color-border); border-radius:var(--radius-chip); padding:3px; }
  /* Phase 9 (public-missed-09) — the same pill on the site, the door and the shell:
     names, not underlined links. */
  .langsw a { display:inline-flex; align-items:center; min-height:44px; padding:0 var(--space-8);
    border-radius:var(--radius-chip); font-size:var(--font-size-caption);
    color:var(--color-ink-secondary); white-space:nowrap; text-decoration:none; }
  /* Five names fit a 360 px phone with the narrow padding; a wider screen gets the roomier one. */
  @media (min-width: 25rem) { .langsw a { padding:0 var(--space-12); } }
  /* The switcher is chrome. A solid jade fill made it the loudest object
     on a page whose subject was somebody's business. */
  .langsw a.on { background:var(--color-surface); color:var(--color-brand); font-weight:600; }

  /* M49 — THE COLUMN. One measure for the whole product, centred in the space
     beside the nav rather than stuck against it. At 2000px the old page put a
     1040px block hard left and left 700px of nothing to its right, which reads
     as a window that failed to fill rather than a sheet placed on a desk.
     Centred is a decision; the accidental middle was not. */
  main { padding: var(--space-32); max-width: var(--measure-column); margin-inline: auto; width: 100%; }
  /* Prose is allowed to be narrower INSIDE the column. It may not be a
     different number: these two classes are the only prose measures there are. */
  .measure-prose { max-width: var(--measure-prose); }
  .measure-form { max-width: var(--measure-form); }
  /* Phase 9 (settings-a-new-19, settings-a-missed-17) — a heading that wraps breaks into even lines, never one word alone. */
  /* The type pass (2026-10-04) — the page title is the top of the hierarchy: the largest size, bold, closed up. */
  h1.page { font-size:var(--font-size-hero); font-weight:700; line-height:var(--line-height-tight); letter-spacing:var(--tracking-tight);
    margin: 0 0 var(--space-24); text-wrap:balance; }
  @media (max-width: 560px) { h1.page { font-size:var(--font-size-display); } }
  /* The hairline in --shadow-lift1 does what a 1px border used to; two would
     read as a double rule at the same edge. */
  .card { background:var(--color-surface); border:0; border-radius:var(--radius-card);
    box-shadow:var(--shadow-lift1); padding:var(--space-24); margin:var(--space-16) 0; }
  /* Phase F: section headings speak to the owner in her own sentence case.
     The 13px tracked-uppercase eyebrow was the one SaaS tell the product had. */
  .card h2, .block h2, main h2 { font-size:var(--font-size-title); font-weight:600; line-height:var(--line-height-tight);
    color:var(--color-ink); margin:0 0 var(--space-12); text-transform:none; letter-spacing:var(--tracking-tight); text-wrap:balance; }
  /* Phase 9 (missed-19, missed-21) — a heading that wraps leaves no word alone on its last line; nor does a paragraph. */
  h1.page, main h2, main h3 { text-wrap:balance; }
  main p, main li { text-wrap:pretty; }

  /* Counts. Never a KPI tile — a plain line, the way Today has always drawn it. */
  .stats { display:flex; flex-direction:column; }
  .stat { display:flex; align-items:baseline; gap:var(--space-8); padding:8px 0;
    border-bottom:1px solid var(--color-border); }
  .stat:last-child { border-bottom:0; }
  .stat .v { font-size:var(--font-size-base); font-weight:600; color:var(--color-ink);
    font-variant-numeric:tabular-nums; min-width:2.5em; }
  .stat .l { font-size:var(--font-size-small); color:var(--color-ink-secondary); }

  /* One pill. It marks STATE — never decoration, never a label wearing a costume. */
  .pill { display:inline-block; padding:4px 10px; border-radius:var(--radius-chip);
    font-size:var(--font-size-caption); font-weight:600;
    margin-inline-end:var(--space-8); margin-block-end:var(--space-8); white-space:nowrap; }
  .pill.ok { background:var(--color-ok-wash); color:var(--color-ok); }
  /* B20 — a pill that holds a sentence (what a file goes without, a journal's gaps) wraps inside the page's measure:
     on a phone it ran 820 px wide and the whole page scrolled sideways. */
  .pill.long { white-space:normal; max-width:100%; overflow-wrap:anywhere; }
  .pill.bad { background:var(--color-warn-wash); color:var(--color-warn); }
  .pill.warn { background:var(--color-needs-wash); color:var(--color-needs); }
  .pill.owner { background:var(--color-sand); color:var(--color-ink); font-weight:600; }
  /* Phase 4 — the four signals: a colour and a shape. */
  .shape { display:inline-block; flex:none; align-self:center; inline-size:0.75em; block-size:0.75em; vertical-align:-0.04em; background-color:currentColor; -webkit-mask-position:center; mask-position:center; -webkit-mask-size:contain; mask-size:contain; -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat; forced-color-adjust:none; }
  .s-ok { -webkit-mask-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M3.2 8.6l3.1 3.1 6.5-7' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/></svg>"); mask-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M3.2 8.6l3.1 3.1 6.5-7' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/></svg>"); }
  .s-waiting { -webkit-mask-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><circle cx='8' cy='8' r='6' fill='black'/></svg>"); mask-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><circle cx='8' cy='8' r='6' fill='black'/></svg>"); }
  .s-chore { -webkit-mask-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><circle cx='8' cy='8' r='5.4' fill='none' stroke='black' stroke-width='2'/></svg>"); mask-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><circle cx='8' cy='8' r='5.4' fill='none' stroke='black' stroke-width='2'/></svg>"); }
  .s-failed { -webkit-mask-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M4.3 4.3l7.4 7.4M11.7 4.3l-7.4 7.4' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round'/></svg>"); mask-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M4.3 4.3l7.4 7.4M11.7 4.3l-7.4 7.4' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round'/></svg>"); }
  .s-you { -webkit-mask-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><rect x='4' y='4' width='8' height='8' rx='1' fill='black'/></svg>"); mask-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><rect x='4' y='4' width='8' height='8' rx='1' fill='black'/></svg>"); }
  .dot.todo { color:var(--color-ink-secondary); }
  .fwarn::before, .imp-warn::before, .sr-value.warn::before, .prob:not(.bad)::before { content:""; display:inline-block; flex:none; align-self:center; inline-size:0.75em; block-size:0.75em; vertical-align:-0.04em; background-color:currentColor; -webkit-mask-position:center; mask-position:center; -webkit-mask-size:contain; mask-size:contain; -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat; forced-color-adjust:none; -webkit-mask-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><circle cx='8' cy='8' r='5.4' fill='none' stroke='black' stroke-width='2'/></svg>"); mask-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><circle cx='8' cy='8' r='5.4' fill='none' stroke='black' stroke-width='2'/></svg>"); margin-inline-end:var(--space-4); }
  .dot.ok { color:var(--color-ok); }
  /* The needs dot as an element (signalMark): the disc is its own box, the glyph it carries for a page read
     without the sheet is pushed out of it. */
  .dot.warn { color:var(--color-needs); display:inline-block; inline-size:0.55em; block-size:0.55em; border-radius:var(--radius-chip);
    background:currentColor; overflow:hidden; text-indent:1em; white-space:nowrap; vertical-align:baseline; }
  .dot.bad { color:var(--color-warn); }
  /* THE IDENTITY SYSTEM (2026-10-04) — THE ASSISTANT'S NAME TAG, its shape now that the four-point mark is gone:
     its wash as the ground, its light words, a chip, beside what it wrote. Draw it with .as-tag; the
     selectors after it are where its label is drawn today. The takeover pill is one: no mark before it. */
  .as-tag, .msg-by .as, #approve .top > .as, .card > p > .as { display:inline-flex; align-items:center; gap:var(--space-4);
    padding:2px var(--space-8); border-radius:var(--radius-chip); background:var(--color-assistant-wash); color:var(--color-assistant); font-weight:600; }
  .card > p > .as { font-size:var(--font-size-caption); }
  .pill.as { background:var(--color-assistant-wash); color:var(--color-assistant); }
  /* THE SOLAR RUN (2026-10-05) — every icon is Solar's Linear drawing (icons.ts). Its line is drawn at a fixed
     width on screen whatever the icon's size, and a little lighter as the icon gets smaller, so every icon
     reads at the nav's weight (measured side by side with the nav's 28 px): 1.75 px from 23 px up, 1.65 at 20
     to 22, 1.6 at 18 to 19.5, 1.5 at 17 and under. Each place below names its own; the assistant's mark grows
     with its words, so the larger words it stands in name theirs. */
  svg.sl * { vector-effect:non-scaling-stroke; }
  svg.sl > * { stroke-width:1.75px; }
  .sheet-x > .xi.sl > *, .dl-get > .ni.sl > *, .dl-who.dl-only .kind-icon.sl > *,
  .face-s .face-i svg.sl > * { stroke-width:1.65px; }
  .mo-e .kind-icon.sl > *, .face-xs .face-i svg.sl > *, .dl-say .am.sl > * { stroke-width:1.6px; }
  .am.sl > *, .mi.sl > *, .go > .gi.sl > *, .ir-reg .ni.sl > *, .dl-who .kind-icon.sl > * { stroke-width:1.5px; }
  .td-head .am.sl > * { stroke-width:1.75px; }
  /* The icons run (2026-10-04) — the assistant's slot drawn inline, as a MARK beside words (agentMark.ts): a little
     larger than the line's capitals and centred on them, in the colour its place gives it (the light shade, with .as). */
  .am { display:inline-block; flex:none; inline-size:1.15em; block-size:1.15em; vertical-align:-0.22em; }
  /* What a customer sent that is not words — a file, a voice note, a photo — before the words that say it, in the ink. */
  .mi { display:inline-block; flex:none; inline-size:1.15em; block-size:1.15em; vertical-align:-0.22em; margin-inline-end:var(--space-4); color:var(--color-ink); }
  .pill.ok::before, .pill.taught::before, .sbx-trust.pass .verdict::before, .chip.auto::before, .sr-value.ok::before, .p-tag.big::before { content:""; display:inline-block; flex:none; align-self:center; inline-size:0.75em; block-size:0.75em; vertical-align:-0.04em; background-color:currentColor; -webkit-mask-position:center; mask-position:center; -webkit-mask-size:contain; mask-size:contain; -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat; forced-color-adjust:none; -webkit-mask-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M3.2 8.6l3.1 3.1 6.5-7' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/></svg>"); mask-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M3.2 8.6l3.1 3.1 6.5-7' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/></svg>"); margin-inline-end:var(--space-4); }
  .pill.warn::before, .pill.reason::before, .draft .held-why::before, .chip.draft::before, .pc-wait::before { content:""; display:inline-block; inline-size:0.55em; block-size:0.55em; border-radius:var(--radius-chip); background:currentColor; vertical-align:baseline; margin-inline-end:0.4em; }
  .pill.bad::before, .flash.bad::before, .perr::before, .fielderr::before, .ev-d::before, .sbx-trust.fail .verdict::before, .chip.warn::before, .sr-value.bad::before, .prob.bad::before { content:""; display:inline-block; flex:none; align-self:center; inline-size:0.75em; block-size:0.75em; vertical-align:-0.04em; background-color:currentColor; -webkit-mask-position:center; mask-position:center; -webkit-mask-size:contain; mask-size:contain; -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat; forced-color-adjust:none; -webkit-mask-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M4.3 4.3l7.4 7.4M11.7 4.3l-7.4 7.4' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round'/></svg>"); mask-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M4.3 4.3l7.4 7.4M11.7 4.3l-7.4 7.4' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round'/></svg>"); margin-inline-end:var(--space-4); }
  @media (forced-colors: active) {
    .dot.warn { inline-size:auto; block-size:auto; text-indent:0; background:none; }
    .pill.warn::before, .pill.reason::before, .draft .held-why::before, .chip.draft::before, .pc-wait::before, .btn.send.needs::before { forced-color-adjust:none; }
  }
  @media (prefers-reduced-motion: no-preference) {
    .btn, .srow, a.navlink, .tab, .deeper, summary, nav.side .ni {
      transition: background-color var(--motion-fast) var(--motion-ease), border-color var(--motion-fast) var(--motion-ease),
        box-shadow var(--motion-fast) var(--motion-ease), color var(--motion-fast) var(--motion-ease),
        transform var(--motion-fast) var(--motion-ease); }
    .btn:active, a.srow:active, button.srow:active, .tab:active, nav.side a.navlink:active { transform:scale(var(--motion-scale-press)); }
    nav.side a.navlink:hover .ni { transform:translateY(calc(-1 * var(--travel-nudge))); }
    nav.side a.navlink:active .ni { transform:none; }
    nav.side a.navlink.active .ni { animation:nomi-settle var(--motion-normal) var(--motion-ease); }
    details[open] > :not(summary) { animation:nomi-arrive var(--motion-normal) var(--motion-ease) both; }
    /* Delay hiding only when closing: opening must expose its fields to the very next Tab. */
    details:not([open])::details-content { opacity:0; transition:opacity var(--motion-fast) var(--motion-ease-in), content-visibility var(--motion-fast) allow-discrete; }
    details > summary::before { transition:transform var(--motion-fast) var(--motion-ease); }
    .flash, #approve, .working, .home-card, .td, .sgroup { animation:nomi-rise var(--motion-normal) var(--motion-ease) both; }
    #approve, .td { animation-delay:var(--motion-fast); }
    .home-schedule { animation:nomi-rise var(--motion-normal) var(--motion-ease) both; animation-delay:var(--motion-fast); }
    .sgroup + .sgroup { animation-delay:var(--motion-step); }
    .sgroup + .sgroup + .sgroup { animation-delay:calc(2 * var(--motion-step)); }
    /* The warmth run — drawn again in place for a newcomer, Today does not rise in again (w4-whole-21). */
    main[data-drawn-again] .home-card, main[data-drawn-again] .home-schedule, main[data-drawn-again] .td, main[data-drawn-again] .td-row > li { animation:none; }
    .td-row > li { animation:nomi-rise var(--motion-normal) var(--motion-ease) both; animation-delay:var(--motion-fast); }
    .td-row > li:nth-child(2) { animation-delay:calc(var(--motion-fast) + 1 * var(--motion-step)); }
    .td-row > li:nth-child(3) { animation-delay:calc(var(--motion-fast) + 2 * var(--motion-step)); }
    .td-row > li:nth-child(4) { animation-delay:calc(var(--motion-fast) + 3 * var(--motion-step)); }
    .td-row > li:nth-child(5) { animation-delay:calc(var(--motion-fast) + 4 * var(--motion-step)); }
    .td-row > li:nth-child(6) { animation-delay:calc(var(--motion-fast) + 5 * var(--motion-step)); }
    .td-row > li:nth-child(7) { animation-delay:calc(var(--motion-fast) + 6 * var(--motion-step)); }
    .td-row > li:nth-child(8) { animation-delay:calc(var(--motion-fast) + 7 * var(--motion-step)); }
    .td-row { scroll-behavior:smooth; }
    .working .dots i { animation:nomi-breathe var(--motion-max) var(--motion-ease) infinite alternate; }
    .working .dots i + i { animation-delay:var(--motion-fast); }
    .working .dots i + i + i { animation-delay:var(--motion-normal); }
    .btn[aria-busy="true"]::after { animation:nomi-breathe var(--motion-max) var(--motion-ease) infinite alternate; }
    .face-link[aria-busy="true"] .face { animation:nomi-breathe var(--motion-max) var(--motion-ease) infinite alternate; }
    dialog.ask, dialog.sheet, dialog.ask::backdrop, dialog.sheet::backdrop {
      transition: opacity var(--motion-fast) var(--motion-ease-in), transform var(--motion-fast) var(--motion-ease-in),
        overlay var(--motion-fast) allow-discrete, display var(--motion-fast) allow-discrete; }
    dialog.ask:not([open]), dialog.sheet:not([open]) { opacity:0; transform:translateY(var(--travel-rise)) scale(var(--motion-scale-enter)); }
    dialog.ask:not([open])::backdrop, dialog.sheet:not([open])::backdrop { opacity:0; }
    dialog.ask[open] { transition-duration:var(--motion-normal); transition-timing-function:var(--motion-ease); }
    dialog.sheet[open] { transition-duration:var(--motion-max); transition-timing-function:var(--motion-spring); }
    dialog.ask[open]::backdrop, dialog.sheet[open]::backdrop { transition-duration:var(--motion-normal); transition-timing-function:var(--motion-ease); }
    @starting-style {
      dialog.ask[open] { opacity:0; transform:translateY(var(--travel-rise)) scale(var(--motion-scale-enter)); }
      dialog.sheet[open] { opacity:0; transform:translateY(var(--travel-sheet)) scale(var(--motion-scale-enter)); }
      dialog.ask[open]::backdrop, dialog.sheet[open]::backdrop { opacity:0; }
    }
    .toast { animation:nomi-toast-in var(--motion-normal) var(--motion-ease) both; }
    [dir="rtl"] .toast { animation-name:nomi-toast-in-rtl; }
    .toast.out { animation:nomi-toast-out var(--motion-fast) var(--motion-ease-in) both; }
    [dir="rtl"] .toast.out { animation-name:nomi-toast-out-rtl; }
    main { view-transition-name:page; }
    nav.side a.navlink.active { view-transition-name:rail-on; }
    .si-order .si-fil.on { view-transition-name:lens-on; }
    .mo td.sel .mo-d { view-transition-name:day-on; }
    ::view-transition-group(*) { animation-duration:var(--motion-max); animation-timing-function:var(--motion-ease); }
    ::view-transition-group(page) { animation:none; }
    ::view-transition-old(page) { animation:nomi-fade-out var(--motion-fast) var(--motion-ease-in) both; }
    ::view-transition-new(page) { animation:nomi-page-in var(--motion-max) var(--motion-ease) both; }
  }
  @media (prefers-reduced-motion: reduce) {
    *, *::before, *::after { animation-duration:1ms !important; animation-iteration-count:1 !important;
      animation-delay:0s !important; transition-duration:1ms !important; scroll-behavior:auto !important; }
  }
  @keyframes nomi-arrive { from { opacity:0; transform:translateY(calc(-1 * var(--travel-fold))); } }
  @keyframes nomi-settle { from { opacity:0.5; transform:translateY(calc(-1 * var(--travel-nudge))); } }
  @keyframes nomi-rise { from { opacity:0; transform:translateY(var(--travel-rise)); } }
  @keyframes nomi-breathe { from { opacity:0.25; } to { opacity:1; } }
  @keyframes nomi-toast-in { from { opacity:0; transform:translateX(var(--travel-toast)); } }
  @keyframes nomi-toast-out { to { opacity:0; transform:translateX(var(--travel-toast)); } }
  @keyframes nomi-toast-in-rtl { from { opacity:0; transform:translateX(calc(-1 * var(--travel-toast))); } }
  @keyframes nomi-toast-out-rtl { to { opacity:0; transform:translateX(calc(-1 * var(--travel-toast))); } }
  @keyframes nomi-toast-up { from { opacity:0; transform:translateY(var(--travel-toast)); } }
  @keyframes nomi-toast-down { to { opacity:0; transform:translateY(var(--travel-toast)); } }
  @keyframes nomi-page-in { from { opacity:0; transform:translateY(var(--travel-page)); } }
  @keyframes nomi-fade-out { to { opacity:0; } }
  /* The assistant at work: its mark, what it is doing, three dots. One run of text, so the dots follow
     the last word when the words wrap (w4-conversation-25), not the far edge of the line. */
  .working { display:block; font-size:var(--font-size-small); color:var(--color-ink-secondary); }
  .working .dots { display:inline-flex; gap:var(--space-4); margin-inline-start:var(--space-8); vertical-align:middle; }
  .working .dots i { width:6px; height:6px; border-radius:var(--radius-chip); background:var(--color-ink-secondary); }
  /* Asking first: the product's own dialog over a dimmed page. */
  dialog.ask { border:0; border-radius:var(--radius-panel); padding:var(--space-24); max-width:var(--measure-form);
    inline-size:min(var(--measure-form), calc(100vw - var(--space-32))); box-shadow:var(--shadow-lift2);
    background:var(--color-surface); color:var(--color-ink); }
  dialog.ask::backdrop { background:var(--color-ink); opacity:0.35; }
  /* THE WARMTH RUN, phase 3 — THE PROFILE CARD (customerCard.ts): a rounded
     panel, the face large at its head, two figures, what they bought, and one
     action at its foot. As a page it sits in the column; lifted by the script
     into its sheet, it springs up over the page — from the bottom edge on a
     phone, where it is a bottom sheet. */
  .pcard { display:flex; flex-direction:column; gap:var(--space-16); max-width:var(--measure-form); margin-inline:auto;
    padding:var(--space-24); background:var(--color-surface); border-radius:var(--radius-panel); box-shadow:var(--shadow-lift1); }
  .pc-top { display:flex; flex-direction:column; align-items:center; gap:var(--space-4); text-align:center; }
  .pc-top .face { margin-block-end:var(--space-8); }
  .pc-name { margin:0; font-size:var(--font-size-display); font-weight:700; line-height:var(--line-height-tight); letter-spacing:var(--tracking-tight); overflow-wrap:anywhere; }
  .pc-meta { margin:0; display:flex; flex-wrap:wrap; justify-content:center; gap:var(--space-4) var(--space-12);
    color:var(--color-ink-secondary); font-size:var(--font-size-small); }
  .pc-wait { margin:0; color:var(--color-needs); font-weight:600; font-size:var(--font-size-small); }
  .pc-regular { margin:0; color:var(--color-ink-secondary); font-weight:600; font-size:var(--font-size-caption); }
  .pc-facts { display:grid; grid-template-columns:1fr 1fr; gap:var(--space-8); margin:0; }
  .pc-facts > div { padding:var(--space-12) var(--space-16); background:var(--color-sand); border-radius:var(--radius-card); }
  .pc-facts dt { font-size:var(--font-size-caption); color:var(--color-ink-secondary); }
  .pc-facts dd { margin:0; font-size:var(--font-size-display); font-weight:300; line-height:var(--line-height-tight); letter-spacing:var(--tracking-tight); font-variant-numeric:tabular-nums; overflow-wrap:anywhere; }
  .pc-h { margin:0 0 var(--space-4); font-size:var(--font-size-caption); font-weight:500; color:var(--color-ink-secondary); }
  .pc-list { list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:var(--space-4); }
  .pc-qty, .pc-none { color:var(--color-ink-secondary); font-size:var(--font-size-small); }
  .pc-none { margin:0; }
  .pc-top + .pc-facts, .pc-things + .pc-open { margin-block-start:var(--space-4); }
  /* Phase 9 (w4-customers-26) — the card's one action is the primary one: the brand fill (the identity system), its words inside their own padding
     (scoped to the card, so it is not the plain door's colour and inset, which the shell draws later). */
  .pcard .pc-open { align-self:stretch; width:auto; justify-content:center; min-height:48px; padding:var(--space-12) var(--space-16);
    border-radius:var(--radius-control); background:var(--color-brand); color:var(--color-surface); font-weight:600; }
  .pcard .pc-open .go { color:var(--color-surface); }
  .pcard .pc-open:hover, .pcard .pc-open:focus-visible { box-shadow:var(--shadow-lift2); }
  dialog.sheet { border:0; padding:0; background:transparent; color:var(--color-ink); overflow:visible;
    inline-size:min(var(--measure-form), calc(100vw - var(--space-32))); max-width:var(--measure-form); }
  dialog.sheet::backdrop { background:var(--color-ink); opacity:0.35; }
  dialog.sheet .pcard { box-shadow:var(--shadow-lift2); max-block-size:calc(100vh - 2 * var(--space-48)); overflow-y:auto; }
  .sheet-bar { display:flex; justify-content:flex-end; margin:0 0 var(--space-8); }
  .sheet-x { display:inline-grid; place-items:center; inline-size:44px; block-size:44px; border:0; border-radius:var(--radius-chip); background:var(--color-surface);
    color:var(--color-ink); cursor:pointer; box-shadow:var(--shadow-lift1); }
  .sheet-x > .xi { inline-size:20px; block-size:20px; }
  @media (max-width: 720px) {
    dialog.sheet { inline-size:100%; max-width:100%; margin:auto 0 0; }
    dialog.sheet .pcard { border-end-start-radius:0; border-end-end-radius:0; max-block-size:calc(100vh - 2 * var(--space-48)); }
    .sheet-bar { padding-inline:var(--space-8); }
  }
  .ask-q { margin:0 0 var(--space-16); }
  /* Phase 9 (cross-new-04) — the two buttons share one row on a phone: a long word wraps inside its own button. */
  .ask-acts { display:flex; gap:var(--space-8); flex-wrap:nowrap; align-items:stretch; }
  .ask-acts .btn { min-width:0; }
  .ask-acts [data-ask-yes] { flex:1 1 auto; }
  .ask-acts [data-ask-no] { flex:none; }
  /* Phase 6 — a form on its way: its button says so, and does not take a second press. */
  .btn[aria-busy="true"] { cursor:progress; }
  .btn[aria-busy="true"]::after { content:"…"; margin-inline-start:var(--space-4); }
  /* Undo, inside the notice that says what was done. */
  .flash.has-undo { display:flex; align-items:center; justify-content:space-between; gap:var(--space-8) var(--space-16); flex-wrap:wrap; }
  .flash .undo { margin:0; }

  /* One button (the design pass, 2026-09-29). The primary act is the one
     FILL on a screen; every other button is outlined in Stone on white, its
     words ink; a quiet one is words; red takes something away.
     The identity system (2026-10-04) — the ordinary primary act (Save, Add,
     Connect, Next) is filled in the BRAND magenta. The act that answers
     something WAITING for the owner (.btn.send.needs, NEEDS_ACT: Send on a
     reply waiting for review, Confirm on an order waiting for the tap, Reply
     in a conversation handed to you) is the DEEP fill, and its word is led
     by the white needs dot — so it is told from Save by its shape, not by
     its shade alone. The light magenta is never a button. A fill's edge is
     the fill itself (a transparent border), so no magenta draws a frame. */
  .btn { display:inline-flex; align-items:center; justify-content:center; min-height:44px;
    padding:10px 18px; border-radius:var(--radius-control);
    border:1.5px solid var(--color-ink-secondary);
    background:var(--color-surface); color:var(--color-ink);
    font:inherit; font-size:var(--font-size-small); font-weight:500; cursor:pointer; }
  .btn.send { background:var(--color-brand); border-color:transparent; color:var(--color-surface); font-weight:600; }
  .btn.send:hover { box-shadow:var(--shadow-lift2); }
  .btn.send.needs { background:var(--color-needs); border-color:transparent; color:var(--color-surface); }
  .btn.send.needs::before { content:""; display:inline-block; inline-size:0.55em; block-size:0.55em; border-radius:var(--radius-chip); background:currentColor; vertical-align:baseline; margin-inline-end:0.5em; flex:none; }
  .btn.danger { border-color:var(--color-warn); color:var(--color-warn); }
  .btn.ghost { background:transparent; border-color:transparent; color:var(--color-ink-secondary); font-weight:400; }
  .btn.ghost:hover { color:var(--color-ink); text-decoration:underline; text-decoration-color:var(--color-brand); }
  .inline { display:inline; }
  .doors { display:flex; flex-direction:column; gap:var(--space-8); margin-top:var(--space-12); }
  /* M49 — a button in a column form stretched to the width of the input above
     it, which made "Save" a 455px slab. A button is as wide as its word. */
  form .btn, form button:not(.full) { align-self:start; }

  /* ── The form. ONE definition, in the shell, because five pages use it.
     Three of them (the rate, the closures, the samples) referenced these
     classes while emitting no rule for them, so their fields rendered as
     inline labels strung across the page — the same failure as a renderer
     reaching for a variable nobody emits, and invisible to every test that reads
     strings rather than boxes. Caught by a screenshot. */
  .pform { display:flex; flex-direction:column; gap:var(--space-16);
           max-width:var(--measure-form); margin-top:var(--space-12); }
  .fld { display:flex; flex-direction:column; gap:var(--space-4);
         font-size:var(--font-size-small); color:var(--color-ink); }
  /* Phase 9 — a text field's box, for text-like fields only: a tick or a
     radio given its padding, border and height drew a stretched, padded box
     and pushed the last choice of a row onto a line of its own. A choice is
     reached through its label, which is the 44px target. */
  .pform input:not([type="checkbox"]):not([type="radio"]), .pform textarea, .pform select {
    background:var(--color-surface); border:1px solid var(--color-ink-secondary);
    border-radius:var(--radius-control); color:var(--color-ink); padding:11px 14px; font:inherit;
    min-height:44px; resize:vertical; }
  .pform label.check { display:flex; align-items:center; gap:var(--space-8); min-height:44px; }
  /* Phase 9 (cross-new-03) — a field sent back is marked by its edge on every form, the calendar's too, not only a settings row. */
  main input[aria-invalid="true"], main textarea[aria-invalid="true"], main select[aria-invalid="true"] { border-color:var(--color-warn); }
  .chkbox { display:inline-flex; align-items:center; gap:var(--space-8);
            font-size:var(--font-size-small); color:var(--color-ink); min-height:44px; }
  .chkbox input { min-height:0; }
  /* Phase 9 (V1-416) — a chosen radio or tick in the product's own colour (the brand, since the identity system), not the browser's blue. */
  input[type="radio"], input[type="checkbox"] { accent-color:var(--color-brand); }
  /* One figure, stated large: the rate she set, the sample price, the state an
     order is in. It is a READING, not a KPI tile. */
  .stated-now { font-size:var(--font-size-display); font-weight:300; line-height:var(--line-height-tight); letter-spacing:var(--tracking-tight); margin:var(--space-12) 0; }

  /* One notice — in two tones, because one of them is a refusal.
     D5: every notice was painted in the jade of a success, so "Only the owner
     may do that" and "Sent" looked alike at a glance. The bad tone carries
     a line as well as a wash, since the two washes are close enough in
     value that colour alone would be the whole signal. */
  .flash { background:var(--color-surface); color:var(--color-ink);
    border:1px solid transparent; box-shadow:var(--shadow-lift1);
    border-radius:var(--radius-card); padding:var(--space-12) var(--space-16);
    margin-bottom:var(--space-16); font-size:var(--font-size-small); }
  .flash.bad { background:var(--color-warn-wash); color:var(--color-warn);
    border-color:var(--color-warn-line); }
  /* CC-26 · the line a page shows when something new arrives while it is
     open: the notice's own tone, and the whole line one door to the newest.
     The design pass (UI-PASS 6): it sits in the page's header, in the flow —
     the list's, the conversation's — never over a control; empty, it takes
     no room. */
  .live { max-width:var(--measure-prose); }
  .dhead .live { margin-inline-start:auto; }
  .dhead.listhead { margin-bottom:var(--space-16); }
  .listhead h1.page { margin:0; }
  .live-line { padding:0; margin:0; }
  .live-line .deeper { gap:var(--space-8); padding:0 var(--space-12); color:inherit; font-weight:600; }

  /* One tab row. */
  .tabs { display:flex; gap:var(--space-8); margin-bottom:var(--space-16); }
  .tab { display:inline-flex; align-items:center; min-height:44px; padding:8px 16px;
    border-radius:var(--radius-chip); background:var(--color-surface);
    border:1px solid var(--color-border); color:var(--color-ink-secondary);
    font-size:var(--font-size-small); font-weight:500; }
  /* Phase 9 (V1-171) — the chosen tab is the one that stands out: an edge twice as heavy and weight, not a paler grey than its
     neighbours. The identity system — the edge and the words in the brand: the edge of what you are on is one of the three edges
     the brand may draw (a focus ring and an underline are the others). */
  .tab.on { background:var(--color-surface); border-color:var(--color-accent); box-shadow:inset 0 0 0 1px var(--color-accent); color:var(--color-accent); font-weight:600; }

  .list { display:flex; flex-direction:column; gap:var(--space-12); }
  .back { display:inline-flex; align-items:center; gap:var(--space-4); min-height:44px;
    color:var(--color-brand); font-size:var(--font-size-small); }
  pre { background:var(--color-paper); border:1px solid var(--color-border);
    border-radius:var(--radius-card); padding:18px; overflow-x:auto;
    font:var(--font-size-small)/1.55 "SF Mono", ui-monospace, Menlo, monospace;
    color:var(--color-ink); white-space:pre; margin:0; }
  /* Phase 9 (V1-193) — at the prose measure, as wide as the form above it reads, not the whole column. */
  pre.doc { white-space:pre-wrap; overflow-wrap:anywhere; text-align:start; max-width:var(--measure-prose); }
  /* One "go deeper" link for the whole product; the chevron mirrors in RTL. */
  /* Each "go deeper" is its own ROW. Inline-flex put three of them on one
     line on the settings page, where they read as one run-on sentence with
     chevrons in it rather than three separate doors. fit-content keeps the
     target the width of its words, not the width of the column. */
  /* The identity system (2026-10-04) — a door is the brand: its words, its chevron, its underline. */
  .deeper { display:flex; width:fit-content; align-items:center; gap:var(--space-4); min-height:44px;
    padding:var(--space-8) 0; font-size:var(--font-size-small); color:var(--color-brand); }
  .deeper:hover, .deeper:focus-visible { text-decoration:underline; text-underline-offset:3px; }
  /* The chevron carries the affordance now that the label does not shout — in the brand, on every door and row. */
  /* The caret is Solar's chevron at 16 px (the Solar run; Phosphor's before), in the brand like the door's words;
     it was the font's character once, a third of the row's icon. */
  .go { display:inline-flex; align-items:center; flex:none; color:var(--color-brand); }
  .go > .gi { inline-size:16px; block-size:16px; }
  [dir="rtl"] .go { transform:scaleX(-1); }
  .tlines { list-style:none; margin:var(--space-8) 0 0; padding:0; display:flex; flex-direction:column; }
  .tline { display:flex; align-items:baseline; flex-wrap:wrap; gap:var(--space-4) var(--space-8); min-height:44px; padding:var(--space-8) 0;
    border-bottom:1px solid var(--color-paper); color:var(--color-ink); text-decoration:none; }
  .tline:hover, .tline:focus-visible { text-decoration:underline; text-decoration-color:var(--color-brand); text-underline-offset:3px; }
  .tline .go { margin-inline-start:auto; }
  .tl-who { font-weight:600; }
  /* Settings in labelled groups (phase 3 of the UI rebuild): one card of rows
     per group; a row names the setting, says it in one line, shows what it is
     set to now at the line's end, and opens it. */
  .sgroup { margin:0 0 var(--space-32); }
  .sgroup-h { font-size:var(--font-size-caption); font-weight:500; color:var(--color-ink-secondary); margin:0 0 var(--space-8); }
  /* The warmth pass — a menu card rests on the page: a warm shadow, its own hairline inside it, no drawn border. */
  .scard { list-style:none; margin:0; padding:0; background:var(--color-surface); border:0;
    border-radius:var(--radius-card); box-shadow:var(--shadow-lift1); overflow:hidden; }
  .scard > li + li, .scard > .srow + .srow { border-top:1px solid var(--color-border); }
  .srow { display:flex; align-items:center; gap:var(--space-12); min-height:56px; padding:var(--space-8) var(--space-16); color:var(--color-ink); }
  a.srow:hover, a.srow:focus-visible { background:var(--color-paper); }
  /* Phase 9 (w4-whole-16) — the card clips its rows to its corners, so a row's focus ring is drawn inside the row, rounded like the card. */
  .scard .srow:focus-visible { outline-offset:-2px; border-radius:calc(var(--radius-card) - 1px); }
  .sr-main { display:flex; flex-direction:column; flex:1 1 auto; min-width:0; }
  .sr-label { font-weight:500; font-size:var(--font-size-small); }
  .sr-desc { font-size:var(--font-size-caption); color:var(--color-ink-secondary); }
  .sr-value { flex:0 1 auto; max-width:45%; font-size:var(--font-size-small); color:var(--color-ink-secondary); text-align:end; overflow-wrap:anywhere; }
  /* A value that is a state says which, with its shape (the four signals); any other value stays quiet. */
  .sr-value.ok { color:var(--color-ok); font-weight:600; }
  .sr-value.warn { color:var(--color-ink-secondary); font-weight:600; }
  .sr-value.bad { color:var(--color-warn); font-weight:600; }
  .srow .go { flex:none; }
  /* Phase 9 (w4-today-setup-23, w4-whole-08) — a menu row is a grid of four: the shape, the name, the value, the door.
     The name and the value share the room equally until the shorter of the two is whole, then the longer one wraps
     between words; nothing is cut, and the columns follow the page's direction. */
  .srow.sr-menu { display:grid; grid-template-columns:min-content minmax(0, auto) minmax(0, max-content) min-content; column-gap:0; }
  .srow.sr-menu > .ni { grid-column:1; margin-inline-end:var(--space-12); }
  .srow.sr-menu > .sr-main { grid-column:2; }
  /* The icons run (2026-10-04) — the icon is level with its row's NAME, not centred on the name and the line under it
     (it fell 11.5 px under the name of a two-line row): the grid's row is centred in the row's height, the icon and
     the name start at its top, and the icon sits in the name's first line (a 24 px icon in a 24 to 26 px line). */
  .srow.sr-menu { align-content:center; }
  .srow.sr-menu > .ni, .srow.sr-menu > .sr-main { align-self:start; }
  .srow.sr-menu > .ni { font-size:var(--font-size-small); margin-block:calc((1lh - 24px) / 2); }
  .srow.sr-menu > .sr-value { grid-column:3; margin-inline-start:var(--space-12); max-width:100%; min-width:0; overflow-wrap:break-word; }
  .srow.sr-menu > .go { grid-column:4; margin-inline-start:var(--space-12); }
  .sr-ctl { flex:0 1 auto; min-width:0; }
  /* THE WARMTH RUN — a menu row (Settings, and the menus phase 7 makes of My
     business, the assistant and Setup): its shape, its name, where it stands,
     and the door. The value stays beside the name on a phone, and wraps under
     itself rather than being cut. A row that does something (Log out) is a button drawn
     as a row, in its own card at the foot. */
  /* The Solar run — Solar's drawing at 24 px in the ink, the nav's 1.75 px line, beside the name's 15 px. */
  .sr-menu > .ni { flex:none; inline-size:24px; block-size:24px; color:var(--color-ink); }
  /* The owner's decision (2026-10-03): 56 for a row, 64 for a row that carries a line under its name. */
  a.srow.sr-menu:has(.sr-desc), div.srow.sr-menu:has(.sr-desc) { min-height:64px; }
  button.srow { inline-size:100%; border:0; background:none; font:inherit; color:var(--color-ink); text-align:start; cursor:pointer; }
  button.srow:hover, button.srow:focus-visible { background:var(--color-paper); }
  .sr-foot { margin-block-start:var(--space-24); }
  /* A setting as a row inside its card: what it is on the start side, its
     control on the end side; stacked on a phone. One save per form, at the
     form's end. Phase 9 (settings-b-outreach-new-04): the bar no longer
     sticks to the foot of the screen, where it lay across the form's first
     screen and read as the save of whichever card it covered. */
  .scard > .setrow + .setrow, .scard > .setrow + .fr-acts { border-top:1px solid var(--color-border); }
  .setrow { display:grid; grid-template-columns:minmax(0, 2fr) minmax(0, 3fr); gap:var(--space-8) var(--space-16);
    align-items:start; padding:var(--space-12) var(--space-16); }
  .fr-l { display:flex; flex-direction:column; gap:var(--space-4); min-width:0; padding-top:var(--space-8); }
  .fr-name { font-weight:500; font-size:var(--font-size-small); }
  .fr-desc { font-size:var(--font-size-caption); color:var(--color-ink-secondary); }
  .fr-c { display:flex; flex-direction:column; gap:var(--space-4); min-width:0; }
  .fr-c > input:not([type="checkbox"]):not([type="radio"]), .fr-c > select, .fr-c > textarea { width:100%; }
  .fr-c > .fr-value { padding-top:var(--space-8); }
  /* A tick in the control column sits at its start, beside the line that names it, never centred in the column. */
  .fr-c > input[type="checkbox"], .fr-c > input[type="radio"], .fr-c > .chkbox { align-self:flex-start; }
  .setrow.bad .fr-c > input, .setrow.bad .fr-c > textarea, .setrow.bad .fr-c > select { border-color:var(--color-warn); }
  .fr-acts { display:flex; flex-wrap:wrap; justify-content:flex-end; gap:var(--space-8); padding:var(--space-12) var(--space-16); }
  .savebar { display:flex; justify-content:flex-end; gap:var(--space-8);
    margin:var(--space-8) 0 0; padding:var(--space-12) 0; border-top:1px solid var(--color-border); }
  @media (max-width: 720px) {
    .setrow { grid-template-columns:minmax(0, 1fr); }
    .fr-l { padding-top:0; }
    .savebar .btn, .fr-acts .btn { flex:1 1 auto; }
  }
  /* On a phone the value goes under the line that says what the setting is, the door staying at the end. */
  @media (max-width: 560px) {
    a.srow { flex-wrap:wrap; row-gap:0; }
    a.srow .sr-main { flex-basis:0; }
    .sr-value { order:3; flex-basis:100%; max-width:100%; text-align:start; }
    .srow.sr-menu > .sr-value { order:0; max-width:100%; text-align:end; }
  }
  .tl-why, .tl-when { color:var(--color-ink-secondary); font-size:var(--font-size-small); }
  .today-date { font-weight:400; }
  .today-worth { margin-top:var(--space-12); }
  /* Phase 9 (w4-today-setup-05) — a line worth the owner's attention is said at the size of the band's own lines,
     and one about a customer leads with their face. */
  .today-worth .grow { text-wrap:pretty; font-size:var(--font-size-small); }
  .today-worth .row.has-face { display:grid; grid-template-columns:min-content minmax(0, 1fr) auto; column-gap:var(--space-12); }
  .today-foot { font-size:var(--font-size-small); margin:var(--space-16) 0 0; }
  .block.home-start { background:var(--color-surface); border-radius:var(--radius-card); box-shadow:var(--shadow-lift1);
    padding:var(--space-24); margin:0 0 var(--space-24); }
  .home-start h2 { font-size:var(--font-size-display); line-height:var(--line-height-tight); margin:0; text-wrap:balance; }
  .home-start > p { margin:var(--space-8) 0 0; max-width:var(--measure-prose); }
  .home-start-go { display:flex; flex-wrap:wrap; align-items:center; gap:var(--space-12) var(--space-24); margin-top:var(--space-16); }
  .home-steps { list-style:none; margin:var(--space-24) 0 0; padding:var(--space-16) 0 0; border-top:1px solid var(--color-border);
    display:grid; gap:var(--space-8); counter-reset:home-step; font-size:var(--font-size-small); }
  .home-steps li { counter-increment:home-step; display:flex; gap:var(--space-8); align-items:baseline; color:var(--color-ink-secondary); }
  .home-steps li::before { content:counter(home-step); flex:none; display:inline-grid; place-items:center; inline-size:1.7em; block-size:1.7em;
    border-radius:var(--radius-chip); border:1px solid var(--color-border); font-size:var(--font-size-caption); font-weight:600; }
  .home-steps li.next { color:var(--color-ink); font-weight:600; }
  .home-steps li.next::before { border-color:var(--color-ink); color:var(--color-ink); }
  .home-steps li.ok::before { background:var(--color-ok-wash); border-color:var(--color-ok-line); }
  .setup-strip { display:flex; flex-wrap:wrap; align-items:baseline; gap:var(--space-4) var(--space-12); margin:0 0 var(--space-16);
    padding:var(--space-8) var(--space-16); border-radius:var(--radius-card); background:var(--color-surface); border:1px solid var(--color-border); }
  .setup-strip .deeper { margin:0; }
  .today-foot p { margin:0; }
  /* Phase 9 (w4-today-setup-07) — setting up is its own small block under the band, never inside the calm panel. */
  .today-foot.setup { margin:0 0 var(--space-24); }
  /* Phase 9 (V1-102) — the next step and its video, side by side where they fit. */
  .today-next { display:flex; flex-wrap:wrap; column-gap:var(--space-24); }
  /* THE WARMTH RUN, phase 2 — Today in three zones. 1 · who waits for you: a
     thin band whose one colour is the waiting signal's, a face and a name and
     one line of why per person, in a card of rows; nobody waiting is a calm,
     warm line on white, never a dashed box. */
  main h2.tw-head { margin:0 0 var(--space-12); }
  .tw-need { color:var(--color-needs); font-weight:600; }
  .tw-calm-line { margin:var(--space-4) 0 0; font-size:var(--font-size-small); color:var(--color-ink-secondary); }
  /* THE HOME RUN (2026-10-05) — Home, composed from the shell's own parts and nothing new: the greeting
     open on the page in the page title's size; the rule between it and the card is the section's own
     hairline (.block); what needs you is the caught-up box's card (the surface, lift1, the card's radius),
     compact when it is one calm line; the schedule and the wins are LIGHTER — the same warm white and
     radius resting flat on the rule's hairline instead of a lift. Two up on a wide screen, stacked on a
     phone; the wins' headline at the section size, the greeting being the page's title. */
  .home-hello h1.page { margin:0; }
  .home-date { margin:var(--space-4) 0 0; color:var(--color-ink-secondary); }
  .home-ready { margin:var(--space-12) 0 0; color:var(--color-ink-secondary); }
  .home-card { background:var(--color-surface); border-radius:var(--radius-card); box-shadow:var(--shadow-lift1); padding:var(--space-24); }
  .home-card.is-calm { padding:var(--space-16) var(--space-24); }
  .home-card .tw-list { background:transparent; box-shadow:none; }
  main h2.home-calm { margin:0; font-size:var(--font-size-base); font-weight:600; }
  .home-care { font-weight:400; color:var(--color-ink-secondary); }
  .home-grid { display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:var(--space-24); align-items:start; }
  .home-tile { min-width:0; background:var(--color-surface); border:1px solid var(--color-border); border-radius:var(--radius-card); padding:var(--space-24); }
  main .home-tile h2.td-head { font-size:var(--font-size-title); }
  .home-how { margin:var(--space-4) 0 var(--space-12); font-size:var(--font-size-small); color:var(--color-ink-secondary); }
  .home-schedule .dl.home-dates { margin:0 0 var(--space-8); background:transparent; box-shadow:none; }
  .home-schedule .home-dates .dl-row { padding-inline:0; }
  .home-wins .tt { margin-top:var(--space-16); }
  .tw-note { margin:0 0 var(--space-12); }
  .tw-note-t { margin:0; font-weight:600; }
  .tw-note .muted { margin:var(--space-4) 0 0; }
  .tw-list { list-style:none; margin:0; padding:0; background:var(--color-surface); border-radius:var(--radius-card);
    box-shadow:var(--shadow-lift1); overflow:hidden; }
  .tw-list > li + li { border-top:1px solid var(--color-border); }
  .tw-item { display:flex; align-items:center; gap:var(--space-12); padding-inline-start:var(--space-12); }
  .tw-go { display:flex; align-items:center; gap:var(--space-8); flex:1 1 auto; min-width:0; min-height:56px;
    padding-block:var(--space-8); padding-inline-end:var(--space-12); color:var(--color-ink); }
  .tw-go:hover .tw-name, .tw-go:focus-visible .tw-name { text-decoration:underline; text-decoration-color:var(--color-brand); text-underline-offset:3px; }
  .tw-who { display:flex; flex-direction:column; flex:1 1 auto; min-width:0; }
  .tw-name, .tw-why { min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; text-align:match-parent; }
  .tw-name { font-weight:600; font-size:var(--font-size-small); }
  /* A Latin name on an Arabic page keeps the page's side, as the Inbox's row does. */
  [dir="rtl"] .tw-name:dir(ltr), [dir="ltr"] .tw-name:dir(rtl) { text-align:end; }
  .tw-why { font-size:var(--font-size-caption); color:var(--color-ink-secondary); }
  .tw-go .go { flex:none; }
  /* 2 · what the assistant handled: the headline in its name, then the faces,
     a word under each, in one row that scrolls sideways (from the right in
     Arabic), snaps to a face, and fades at its end to say there is more. The
     padding at the end leaves the last face clear of the fade. */
  main h2.td-head { font-size:var(--font-size-display); font-weight:600; margin:0 0 var(--space-16); }
  /* Nothing connected yet: a heading for the way forward, not the day's news. */
  main h2.td-head.is-plain { font-size:var(--font-size-title); margin-block-end:var(--space-8); }
  .td-ready { margin:0; font-size:var(--font-size-small); color:var(--color-ink-secondary); }
  .td-row { list-style:none; margin:0 0 var(--space-8); padding:var(--space-4) 0; padding-inline-end:var(--space-48);
    display:flex; gap:var(--space-8); overflow-x:auto; overscroll-behavior-inline:contain;
    scroll-snap-type:inline proximity; scrollbar-width:thin; scrollbar-color:var(--color-ink-secondary) transparent;
    -webkit-mask-image:linear-gradient(to right, var(--color-ink) calc(100% - var(--space-48)), transparent);
    mask-image:linear-gradient(to right, var(--color-ink) calc(100% - var(--space-48)), transparent); }
  [dir="rtl"] .td-row {
    -webkit-mask-image:linear-gradient(to left, var(--color-ink) calc(100% - var(--space-48)), transparent);
    mask-image:linear-gradient(to left, var(--color-ink) calc(100% - var(--space-48)), transparent); }
  .td-row > li { flex:none; scroll-snap-align:start; }
  .td-face, .td-more { display:flex; flex-direction:column; align-items:center; gap:var(--space-4);
    inline-size:calc(56px + var(--space-16)); padding-block:var(--space-4); color:var(--color-ink); text-align:center; }
  /* Phase 9 (w4-today-setup-02, -03) — under a face, the customer's name, then one word of what happened; neither
     breaks inside itself, and a name too long for the column ends in an ellipsis on its own side. */
  .td-name, .td-word { max-inline-size:100%; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
  .td-name { font-size:var(--font-size-caption); font-weight:600; }
  .td-word { font-size:var(--font-size-caption); color:var(--color-ink-secondary); }
  .td-face:hover .td-word { color:var(--color-ink); }
  .td-plus { display:grid; place-items:center; inline-size:56px; block-size:56px; border-radius:var(--radius-chip);
    background:var(--color-surface); box-shadow:var(--shadow-lift1); font-size:var(--font-size-small); font-weight:600; }
  /* 3 · the day's three figures: a figure over its word, in ink, side by side. */
  main h2.tt-head { font-size:var(--font-size-small); color:var(--color-ink-secondary); }
  .tt-row { list-style:none; margin:0; padding:0; display:grid; grid-template-columns:repeat(3, minmax(0, 1fr)); gap:var(--space-12); }
  .tt-row > li { display:flex; flex-direction:column; min-width:0; }
  .tt-n { font-size:var(--font-size-display); font-weight:300; line-height:var(--line-height-tight); letter-spacing:var(--tracking-tight); font-variant-numeric:tabular-nums; }
  .tt-l { font-size:var(--font-size-caption); color:var(--color-ink-secondary); }
  @media (max-width: 560px) {
    main h2.td-head { font-size:var(--font-size-title); }
    .home-card, .home-card.is-calm, .home-tile { padding:var(--space-16); }
  }
  @media (max-width: 720px) {
    .home-grid { grid-template-columns:minmax(0, 1fr); gap:var(--space-16); }
  }
  /* Phase 9 (V1-094) — on a phone a line's door goes under its sentence, so the sentence keeps the width. */
  @media (max-width: 560px) {
    .today-worth .row { flex-direction:column; align-items:flex-start; gap:0; }
    .today-worth .row.has-face { grid-template-columns:min-content minmax(0, 1fr); align-items:center; }
    .today-worth .row.has-face > .tw-face { grid-row:1 / 3; align-self:start; }
    .today-worth .row.has-face > .deeper { grid-column:2; }
  }
  /* The chevron above mirrors because it POINTS — "onward" is to the left in
     Arabic. The mark does NOT, and its absence here is deliberate rather than an
     oversight: a brand mark is a constant, the same object in every language,
     and flipping it would make Nomi a different mark for Arabic readers. Only
     directional glyphs mirror. Do not add .mark to this rule. */
  a:focus-visible, button:focus-visible, input:focus-visible,
  textarea:focus-visible, select:focus-visible { outline:2px solid var(--color-brand); outline-offset:2px; }
  .muted { color:var(--color-ink-secondary); font-size:var(--font-size-caption); }
  /* M49 — one empty state, aligned like everything else. It was centred while
     the page around it was left-aligned, which is the single clearest way to
     make a considered page look like an accident. It mirrors in RTL on its own.
     Phase 6 — and a panel of its own, so it never reads as the caption of the
     button above it: what will be here, why it is not yet, and where there is
     one, the door to the next step. */
  /* The warmth pass — no dashed box: on the page it is a soft card of its own, resting on the paper;
     inside a card it is a recess of paper, so it never reads as a card in a card. */
  .empty { text-align:start; color:var(--color-ink); font-size:var(--font-size-small);
    padding:var(--space-16); margin:var(--space-12) 0 0; max-width:var(--measure-prose);
    background:var(--color-surface); border:0; border-radius:var(--radius-card); box-shadow:var(--shadow-lift1); }
  .card .empty, .scard .empty, .pcard .empty, .tw-list .empty { background:var(--color-paper); box-shadow:none; }
  .empty .muted { color:var(--color-ink-secondary); }
  .empty .deeper, .empty .doors { margin-top:var(--space-8); }

  /* ── Speech: the two voices. ─────────────────────────────────────────────
     Anything a PERSON says — the buyer's words, her drafts, her sent replies —
     is set in the voice serif. Everything around the speech (labels,
     timestamps, buttons, counts) is the product speaking, and stays sans.
     One family per speaker, everywhere: these components are declared HERE and
     owned by the shell, because inbox and sandbox each carrying a copy is how
     the two drifted apart last time. */
  .timeline { display:flex; flex-direction:column; gap:var(--space-12); }
  .msg { max-width:82%; }
  .msg.inbound { align-self:flex-start; } .msg.outbound { align-self:flex-end; }
  .bubble { font-family:var(--font-voice); padding:10px 14px; border-radius:var(--radius-card);
    white-space:pre-wrap; word-break:break-word; }
  /* The buyer's words are FULL SIZE; every reply is one step down. The page
     belongs to the buyer's business — she works inside it. */
  .msg.inbound .bubble { font-size:var(--font-size-base);
    background:var(--color-sand); border:1px solid var(--color-border); border-start-start-radius:4px; }
  /* Phase 9 (V1-236, V1-261, V1-292) — the hairline every bubble has: on a phone, and in Practice,
     the page is paper too, and the customer's words floated as indented text with no bubble. */
  /* Phase 9 (V1-267) — the day once, where it changes; each caption then gives its time. */
  .tday { align-self:center; margin:var(--space-8) 0 0; font-size:var(--font-size-caption); color:var(--color-ink-secondary); }
  /* Her sent replies: neutral. These carried an amber fill — colour on every
     message she ever sent, marking no state at all. */
  .msg.outbound .bubble { font-size:var(--font-size-small);
    background:var(--color-surface); border:1px solid var(--color-border);
    border-start-end-radius:4px; }
  /* THE WARMTH RUN, phase 5 — what the ASSISTANT said sits on its wash, and the caption under it
     says its name in magenta; a person's reply keeps the plain bubble. A newcomer to the
     conversation tells the two apart at a glance. A wash, never a frame: the hairline goes. */
  .msg.outbound .bubble.by-as { background:var(--color-assistant-wash); border-color:transparent; }
  .ts { font-size:var(--font-size-caption); margin-top:var(--space-4); }
  /* The fix wave (w4-conversation-17) — its name tag over the assistant's words, so it is read first. */
  .msg-by { font-size:var(--font-size-caption); margin-bottom:var(--space-4); }
  .as { color:var(--color-assistant); }
  /* CC-25 — a link into a transcript lands on its newest message: clear of the
     sticky phone nav, with the message before it still in view. After an
     action it lands on the notice the action left, drawn under that message.
     The practice box is a landing of the same kind. */
  #latest, #compose, #main { scroll-margin-top:25vh; }
  /* Phase 9 (V1-239) — on a laptop the newest message lands lower: a short conversation does not
     move at all, so the header is never cut through; a long one keeps the reply under it in view. */
  @media (min-width: 1100px) { #latest { scroll-margin-top:40vh; } }
  /* The fix wave (V1-239) — a conversation that fits the first screen does not move to reach its newest
     message: the strip above it made the old 40vh scroll the page and cut through the way back. */
  @media (min-width: 1100px) { .timeline.few #latest { scroll-margin-top:100vh; } }
  /* Her PROPOSAL — visually subordinate to the buyer's words above it. Not a
     boxed rival: a quiet serif paragraph behind a jade hairline that means
     "hers, awaiting your decision". border-inline-start keeps the hairline on
     the reading edge in RTL with no override. */
  .proposed { font-family:var(--font-voice); font-size:var(--font-size-small);
    border-inline-start:2px solid var(--color-ink); padding:2px 14px;
    margin-bottom:var(--space-12); white-space:pre-wrap; word-break:break-word; }

  /* ── A plain section: air and a hairline. The DEFAULT grouping. ──────────
     A card is reserved for a boundary that MEANS something — one buyer's
     business, one verdict. A page of prose and counts is sections, not boxes. */
  /* M49 — one gap between sections, from the scale. It was 22px here and
     anything from 40 to 180 once each page had added its own margins. */
  .block { padding:var(--space-32) 0; border-top:1px solid var(--color-border); }
  .block:first-of-type { border-top:0; padding-top:var(--space-4); }
  /* RTL needs NO override here: a grid's first track already sits on the
     inline-start edge, so the sidebar mirrors to the right on its own. The
     three rules that used to live here re-flipped it — putting the sidebar
     back on the LEFT in Arabic, and, because two explicitly-placed columns ran
     against DOM order, pushing the whole content column into grid row 2 behind
     a screen-height gap. Every page was affected at desktop width. */

  /* ── V1 step two — the shared families, defined ONCE (Symow, decision 4:
     "define what already exists, once, in one stylesheet"). Each rule below
     was declared in two or more pages with small differences; this is the one
     body, and tests/parity/v1-one-stylesheet.test.ts refuses a second. Names
     that meant two things (.acts, .certs, .tag, .prow…) were renamed on the
     page that used them differently, so a name has one meaning again. */
  .editform { display:flex; flex-direction:column; gap:var(--space-8); }
  .replyform { display:flex; flex-direction:column; gap:var(--space-8); }
  /* Phase 9 (V1-238, V1-263) — the hand-over card reads down: whose it is, why, then what to do.
     In a row its state floated mid-card beside a stray label, with an empty band above. */
  .takeover { display:flex; flex-direction:column; align-items:flex-start; gap:var(--space-8); }
  .takeover > .pill { white-space:normal; margin:0; }
  .takeover-note { margin:0; font-size:var(--font-size-small); }
  .acts { display:flex; gap:var(--space-8); flex-wrap:wrap; margin-bottom:var(--space-16); }
  .perr { color:var(--color-warn); font-size:var(--font-size-caption); margin:0; }
  /* Phase 6 — a form's refusal under the field it concerns: why, the rule it follows, the way on. */
  .perr-block { margin:var(--space-8) 0; display:flex; flex-direction:column; gap:var(--space-4); }
  .perr-block p { margin:0; }
  .pq { display:flex; flex-direction:column; gap:var(--space-4); font-size:var(--font-size-small); color:var(--color-ink); }
  .subline { font-size:var(--font-size-caption); margin-bottom:var(--space-12); }
  .dhead { display:flex; align-items:center; gap:var(--space-12); flex-wrap:wrap; margin-bottom:var(--space-8); }
  .chips { display:flex; flex-wrap:wrap; gap:var(--space-8); }
  .chip { background:var(--color-sand); border:1px solid var(--color-border); border-radius:var(--radius-chip); padding:5px 12px; font-size:var(--font-size-caption); }
  .as-box { display:inline-flex; align-items:center; gap:var(--space-4); font-size:var(--font-size-small); min-height:44px; }
  .facts { margin-top:var(--space-16); display:flex; flex-direction:column; gap:var(--space-8); }
  .sub { margin:var(--space-16) 0 var(--space-12); font-size:var(--font-size-caption); color:var(--color-ink-secondary); }
  .note { font-size:var(--font-size-small); margin-top:var(--space-8); margin-bottom:var(--space-12); }
  .ok-line { color:var(--color-ok); font-weight:600; margin-bottom:var(--space-12); }
  .frow { display:flex; gap:var(--space-12); font-size:var(--font-size-small); }
  .flabel { color:var(--color-ink-secondary); min-width:8.5em; }
  .dhead.spread { justify-content:space-between; }
  /* ── V1 · what ten pages each drew for themselves, named once (step four).
     A list of hairline rows — dense, as decision 2 says of lists — and the
     column that names someone; two text sizes; a fieldset of choices; the
     one-time access code; the stopped pill. */
  .rows { list-style:none; margin:var(--space-12) 0 0; padding:0; }
  /* A list of counts or rows is read, not scanned: it keeps the prose measure,
     so a figure, its word and its chevron stay together at 1280 px. */
  .stats, .rows { max-width:var(--measure-prose); }
  .row { display:flex; align-items:center; justify-content:space-between; gap:var(--space-12); flex-wrap:wrap;
    padding:var(--space-8) 0; border-bottom:1px solid var(--color-border); }
  .row:last-child { border-bottom:0; }
  /* One column the width of the row, each line at its own width, so a line
     that spreads (a name and its state) reaches the row's far edge. Left to
     the row's space-between, the column shrank to its content, and on the
     channels page each state sat a different distance from its name. */
  .row.lines { display:grid; grid-template-columns:minmax(0, 1fr); justify-items:start; gap:var(--space-4); }
  .row.lines > .spread { justify-self:stretch; }
  .row.top { align-items:flex-start; }
  .row p { margin:0; }
  .row .btn { flex:none; }
  .grow { flex:1; min-width:0; }
  /* .who is the inbox's inline line (flag · name · country) and must stay
     inline; the column that names someone on People is .person. */
  .person { display:flex; flex-direction:column; gap:var(--space-4); min-width:0; }
  .caption { font-size:var(--font-size-caption); }
  .stripe-payments article h3, .stripe-payments article .caption { overflow-wrap:anywhere; }
  .small { font-size:var(--font-size-small); }
  ul.chips { list-style:none; margin:var(--space-12) 0 0; padding:0; }
  /* The plain pill: a state that waits on nothing. Its hairline keeps it a pill on the page's own paper, not bare grey words. */
  .pill.stop { background:var(--color-sand); color:var(--color-ink-secondary); border:1px solid var(--color-border); }
  /* The one-time access code on the People page; tests read it by this class. */
  .issued .code { font-size:var(--font-size-display); font-weight:600; letter-spacing:.08em; margin:var(--space-8) 0; }
  .choices { border:0; margin:0; padding:0; display:flex; flex-wrap:wrap; gap:var(--space-8) var(--space-16); }
  .choices legend { padding:0; margin-bottom:var(--space-4); font-size:var(--font-size-caption); }
  /* V1 · decision 5 (2026-09-28): the row's one tag. Caption size, never
     wrapped; state colour only when it names a state — now (waiting for the
     owner), you (a person here holds it). Any other label, the calendar's
     kinds among them, is the neutral tag. */
  .tag { display:inline-flex; align-items:center; padding:5px 11px; border-radius:var(--radius-chip);
    font-size:var(--font-size-caption); font-weight:600; white-space:nowrap;
    background:var(--color-sand); color:var(--color-ink-secondary); }
  .tag.you { background:transparent; color:var(--color-ink); font-weight:600; }
  /* The doors either side of one page of a list, and where it sits in the whole. */
  .pager { display:flex; flex-wrap:wrap; align-items:center; gap:var(--space-4) var(--space-24); margin-top:var(--space-24); }
  /* Today (step four). The calm state IS the page: a short rule and one
     sentence in the product's voice — quiet, not jade, while messaging is off.
     And a count you can tap: the stat row as a link, its figure one step up. */
  .calm-page { padding:var(--space-32) 0 var(--space-48); }
  .calm-rule { height:2px; width:3.5rem; background:var(--color-ink); border-radius:2px; margin-bottom:var(--space-24); }
  .calm-page.off .calm-rule { background:var(--color-border); }
  .calm-say { font-size:var(--font-size-title); font-weight:300; line-height:1.45; color:var(--color-ink); margin:0; max-width:var(--measure-prose); }
  a.stat { color:inherit; }
  .stat.need .v { font-size:var(--font-size-title); }
  /* The controls the browser used to draw — the hand-to select, a details
     disclosure, a textarea outside a form — get the same recess as an input. */
  main select, main textarea, main input:not([type=checkbox]):not([type=radio]) {
    background:var(--color-surface); border:1px solid var(--color-ink-secondary);
    border-radius:var(--radius-control); color:var(--color-ink); padding:11px 14px; font:inherit; min-height:44px; }
  main textarea { resize:vertical; }
  details > summary { display:flex; align-items:center; gap:var(--space-8); min-height:44px; cursor:pointer;
    color:var(--color-ink); font-size:var(--font-size-small); list-style:none; }
  details > summary::-webkit-details-marker { display:none; }
  /* The fold's caret is the doors' (Solar's chevron at 16 px, its 1.5 px line; the Solar run), drawn by the stylesheet:
     a box in the brand cut to the caret, so no face draws it. Open, it turns down. */
  details > summary::before { content:""; display:inline-block; flex:none; inline-size:16px; block-size:16px;
    color:var(--color-brand); background-color:currentColor; -webkit-mask-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none'><path fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2.25' d='M9 5L15 12L9 19'/></svg>"); mask-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none'><path fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2.25' d='M9 5L15 12L9 19'/></svg>"); -webkit-mask-size:contain; mask-size:contain; -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat; -webkit-mask-position:center; mask-position:center; forced-color-adjust:none; }
  details[open] > summary::before { transform:rotate(90deg); }
  [dir="rtl"] details:not([open]) > summary::before { transform:scaleX(-1); }
  /* The twins of :hover and :focus-visible, so a page can SHOW a state without a
     pointer. Only the components page under Setup wears them. */
  .btn:hover:not(.send):not(.ghost), .btn.is-hover:not(.send):not(.ghost) { background:var(--color-paper); }
  .btn.send.is-hover { box-shadow:var(--shadow-lift2); }
  .is-focus { outline:2px solid var(--color-brand); outline-offset:2px; }
  .btn:disabled, .btn.is-disabled { background:var(--color-paper); border-color:var(--color-border);
    color:var(--color-ink-secondary); box-shadow:none; cursor:default; }
  /* The identity system — the needs act goes quiet too when it cannot be pressed (its fill outranked the
     rule above and stayed deep). It keeps its dot, in the quiet ink. */
  .btn.send.needs:disabled, .btn.send.needs.is-disabled { background:var(--color-paper); border-color:var(--color-border);
    color:var(--color-ink-secondary); box-shadow:none; cursor:default; }

  @media (max-width: 720px) {
    /* Rows matter here. .layout carries min-height:100vh, and with one column
       and no declared rows the nav and the content shared that height evenly:
       the nav row grew to half the viewport and, because a flex row stretches
       its children by default, the ACTIVE tab's background filled all of it —
       a jade slab down the page, on every surface, at phone width. */
    .layout { grid-template-columns: 1fr; grid-template-rows: auto 1fr; }
    /* Four destinations fit one row on a phone: an equal-width bottom-style bar
       at the top, each a full-height target, no wrapping to three ragged rows. */
    /* V1 step three — the nav STAYS (sticky) and compacts as the page scrolls.
       No script: the state is
       a pure function of scroll position, so nothing can be stuck collapsed and
       nothing changes when scripting is off. Where scroll-driven animation is
       unsupported the nav is simply sticky at full size. */
    nav.side { position:sticky; top:0; z-index:2; display:flex; flex-direction:row; align-items:center; gap:var(--space-4);
      height:auto; overflow:visible; padding:10px 12px; border-inline-end:none; border-bottom:1px solid var(--color-border); }
    /* The groups dissolve into the one row of five: Today, Inbox, Calendar,
       the assistant, Settings — each its icon over its word. "Customers", the
       wide rail's heading, is not an entry. */
    .navgroup, .navfoot { display:contents; }
    /* The mark belongs to the product, so it sits with the product's nav — small,
       and without the word beside it. */
    nav.side .brand { display:flex; padding:0; margin-inline-end:var(--space-4); }
    nav.side .brand .mark-detail { display:none; }
    nav.side .brand .mark-small { display:flex; }
    nav.side .brand .brandname { display:none; }
    .business-name { display:block; }
    nav.side a.navlink { position:relative; flex:1 1 auto; flex-direction:column; flex-wrap:nowrap; white-space:nowrap;
      gap:var(--space-8); margin:0; padding:var(--space-4) 2px; min-height:64px; min-width:0; align-items:center; justify-content:center;
      font-size:var(--font-size-caption); text-align:center; box-shadow:none; }
    nav.side a.navlink.active { background: var(--color-surface); box-shadow: var(--shadow-lift1); }
    nav.side .nl-body { display:contents; }
    nav.side .nl-text { max-inline-size:100%; overflow:hidden; text-overflow:ellipsis; }
    nav.side .ni { margin-block:0; }
    /* The count rides the icon's corner on a phone: the word keeps its room. Cut out of the tile by a
       ring of the tile's own white, so on the filled entry it stays a count, not part of the shape. */
    nav.side .navcount { position:absolute; inset-block-start:2px; inset-inline-start:calc(50% + 4px); margin:0; padding:0 var(--space-4);
      box-shadow:0 0 0 2px var(--color-surface); }
    /* Phase 7 — one line: the shorter phone label where there is one, and a sideways scroll as the last resort. */
    nav.side { overflow-x:auto; scrollbar-width:none; padding-inline:var(--space-8); }
    /* Phase 9 (V1-014) — the entries sit edge to edge (each keeps its own padding), so "Customers" can carry its count on the one line. */
    nav.side { gap:0; }
    nav.side .navcount { margin-inline-start:var(--space-4); }
    @supports (animation-timeline: scroll()) {
      @media (prefers-reduced-motion: no-preference) {
        nav.side { animation: nav-compact linear both; animation-timeline: scroll(root); animation-range: 0 160px; }
        nav.side a.navlink { animation: navlink-compact linear both; animation-timeline: scroll(root); animation-range: 0 160px; }
      }
    }
    main { padding:var(--space-16); }
    .card { padding:var(--space-16); }
    .msg { max-width:92%; }
    .stats { grid-template-columns: repeat(2,1fr); }
    .frow { flex-direction:column; align-items:flex-start; gap:var(--space-4); }
    .flabel { min-width:0; font-size:var(--font-size-caption); }
    /* The motion pass — on a phone the toast comes up from the foot, and the profile card's sheet from the screen's edge, settling with no spring. */
    @media (prefers-reduced-motion: no-preference) {
      .toast, [dir="rtl"] .toast { animation-name:nomi-toast-up; }
      .toast.out, [dir="rtl"] .toast.out { animation-name:nomi-toast-down; }
      dialog.sheet[open] { transition-timing-function:var(--motion-ease); }
      dialog.sheet:not([open]) { transform:translateY(100%); }
      @starting-style { dialog.sheet[open] { transform:translateY(100%); } }
    }
  }
  /* Phase 7 — the narrowest phones: the five entries before the small mark.
     Phase 9 (V1-014, cross-new-02) — up to 440 px, now that "Customers" carries
     its count and each entry has one name at every width (measured at 360–430
     in five languages); below 400 px the entries sit edge to edge. */
  @media (max-width: 379px) {
    nav.side .brand { display:none; }
  }
  @media (max-width: 440px) {
    nav.side .brand { display:none; }
  }
  @media (max-width: 400px) {
    nav.side a.navlink { padding-inline:0; }
  }
  /* V1 step three — the compaction the sticky phone nav plays over the first
     160px of scroll (see the phone block). Spacing from the scale only. */
  @keyframes nav-compact { to { padding-top:var(--space-4); padding-bottom:var(--space-4); } }
  @keyframes navlink-compact { to { min-height:44px; padding-top:var(--space-4); padding-bottom:var(--space-4); } }

  .login { max-width: var(--measure-form); margin: 6vh auto var(--space-48); padding: 0 var(--space-16); }
  .login .top-sw { display:flex; justify-content:center; margin-bottom:var(--space-16); }
  .login .card { padding:var(--space-24) 0 0; border:0; background:transparent; box-shadow:none; }
  .login .brand { flex-direction:column; justify-content:center; gap:var(--space-12); text-align:center;
    font-weight:700; font-size:var(--font-size-title); margin-bottom:var(--space-24); padding:0; }
  /* Phase 9 (V1-040 and public-missed-10) — above: the site's mark and name, centred like
     the pill above them and the links below. */
  .login .brand small { margin-top:0; }
  .login h1 { font-size:var(--font-size-display); font-weight:700; line-height:var(--line-height-tight); letter-spacing:var(--tracking-tight); margin:0 0 var(--space-8); }
  .login h1 { text-wrap:balance; text-align:center; margin-bottom:var(--space-24); }
  .login .lead { color:var(--color-ink-secondary); font-size:var(--font-size-caption); margin:0 0 var(--space-16); }
  /* No word or character left alone on a line (V1-056): a short lead in even lines, the rest pretty. */
  .login .lead { text-wrap:balance; font-size:var(--font-size-base); }
  .login .hint, .login .err, .login .fld-err { text-wrap:pretty; }
  /* V1-031, V1-045, V1-049 — a field, a list and a button are drawn in the page's face,
     not the browser's own. */
  input, select, button, textarea { font-family:inherit; }
  /* V1-034, V1-050 — a link on the door looks like one. */
  .login .card a, .login .other a, .login .foot a { color:var(--color-ink); text-decoration:underline;
    text-decoration-color:var(--color-brand); text-underline-offset:0.2em; }
  /* w4-public-04 — a field, a list and a button are controls: a control's corner, as inside the app. */
  input { width:100%; padding:12px 14px; border-radius:var(--radius-control);
    border:1px solid var(--color-ink-secondary); background:var(--color-surface);
    color:var(--color-ink); font-size:var(--font-size-base); margin:var(--space-8) 0 var(--space-16); }
  /* M49 — as wide as its word, like every other button in the product. */
  button { min-height:44px; padding:12px var(--space-24); border:0; border-radius:var(--radius-control);
    background:var(--color-ink); color:var(--color-surface); font-weight:600;
    font-size:var(--font-size-small); cursor:pointer; }
  button:hover { background:var(--color-ink); box-shadow:none; }
  select { width:100%; min-height:44px; padding:10px 14px; border-radius:var(--radius-control);
    border:1px solid var(--color-ink-secondary); background:var(--color-surface);
    color:var(--color-ink); font-size:var(--font-size-base); margin:var(--space-8) 0 var(--space-16); }
  .login h2 { font-size:var(--font-size-small); color:var(--color-ink-secondary); margin:var(--space-24) 0 var(--space-8); font-weight:600; }
  .login form > h2:first-child { margin-top:0; }
  fieldset.checks { border:0; padding:0; margin:0 0 var(--space-16); }
  fieldset.checks legend { color:var(--color-ink-secondary); font-size:var(--font-size-caption); padding:0; margin-bottom:var(--space-8); }
  label.check { display:inline-flex; align-items:center; gap:var(--space-8); min-height:44px; margin-inline-end:var(--space-16); color:var(--color-ink); }
  label.check input { width:auto; margin:0; }
  /* V1-053 — the terms box keeps the form's own gap above the button. */
  label.check.terms { display:flex; margin-bottom:var(--space-16); }
  .err { color:var(--color-warn); font-size:var(--font-size-caption); margin-bottom:var(--space-8); }
  .err ul { margin:var(--space-4) 0 0; padding-inline-start:var(--space-24); }
  .err li { margin:0; }
  .fld-err { color:var(--color-warn); font-size:var(--font-size-caption); margin:calc(-1 * var(--space-8)) 0 var(--space-16); }
  /* public-missed-13 — the field refused is marked at its own edge (the terms box's
     refusal keeps the gap its margin leaves). */
  .err-field { border-color:var(--color-warn); }
  label.check .err-field { outline:2px solid var(--color-warn); outline-offset:2px; }
  .err::before, .fld-err::before { content:""; display:inline-block; flex:none; align-self:center; inline-size:0.75em; block-size:0.75em; vertical-align:-0.04em; background-color:currentColor; -webkit-mask-position:center; mask-position:center; -webkit-mask-size:contain; mask-size:contain; -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat; forced-color-adjust:none; -webkit-mask-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M4.3 4.3l7.4 7.4M11.7 4.3l-7.4 7.4' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round'/></svg>"); mask-image:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M4.3 4.3l7.4 7.4M11.7 4.3l-7.4 7.4' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round'/></svg>"); margin-inline-end:var(--space-4); }
  .hint { color:var(--color-ink-secondary); font-size:var(--font-size-caption); margin:calc(-1 * var(--space-8)) 0 var(--space-16); }
  label { color:var(--color-ink); font-size:var(--font-size-base); display:block; }
  details { margin-top:var(--space-24); border-top:1px solid var(--color-border); padding-top:var(--space-16); }
  summary { cursor:pointer; color:var(--color-ink-secondary); font-size:var(--font-size-caption); min-height:44px; display:flex; align-items:center; }
  details form { margin-top:var(--space-8); }
  .login button[type=submit] { width:100%; }
  .login .hint,.login .err { background:transparent; border:0; padding-inline:0; }
  .login .other { text-align:center; margin:var(--space-16) 0 0; font-size:var(--font-size-caption); }
  .login .other.small { margin-top:var(--space-8); }
  /* V1-038, V1-039 — the door's foot is where to read more, not a slogan. */
  .login .foot { display:flex; justify-content:center; flex-wrap:wrap; gap:0 var(--space-16);
    margin-top:var(--space-24); font-size:var(--font-size-caption); }
  .login .foot a { display:inline-flex; align-items:center; min-height:44px; color:var(--color-ink-secondary); }
  .forgot { margin:var(--space-8) 0 0; font-size:var(--font-size-caption); }
