@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url(/fonts/fraunces-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url(/fonts/fraunces-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Fraunces';
  font-style: italic;
  font-weight: 300 700;
  font-display: swap;
  src: url(/fonts/fraunces-italic-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Fraunces';
  font-style: italic;
  font-weight: 300 700;
  font-display: swap;
  src: url(/fonts/fraunces-italic-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Instrument Sans';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(/fonts/instrumentsans-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Instrument Sans';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(/fonts/instrumentsans-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Instrument Sans';
  font-style: italic;
  font-weight: 400 700;
  font-display: swap;
  src: url(/fonts/instrumentsans-italic-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Instrument Sans';
  font-style: italic;
  font-weight: 400 700;
  font-display: swap;
  src: url(/fonts/instrumentsans-italic-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 100 800;
  font-display: swap;
  src: url(/fonts/jetbrainsmono-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 100 800;
  font-display: swap;
  src: url(/fonts/jetbrainsmono-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  --s1: 2px;
  --s2: 4px;
  --s3: 6px;
  --s4: 8px;
  --s5: 10px;
  --s6: 12px;
  --s7: 14px;
  --s8: 16px;
  --s9: 20px;
  --s10: 24px;
  --s11: 32px;
  --s12: 40px;
  --s13: 48px;

  --t1: 9px;
  --t2: 10px;
  --t3: 11px;
  --t4: 12.5px;
  --t5: 13.5px;
  --t6: 15px;
  --t7: 17px;
  --t8: 20px;
  --t9: 24px;
  --t10: 30px;
  --t11: 40px;

  /* Small text is read in bulk and wants air; a heading is one line and a
     loose one reads as two. */
  --lh1: 1.4;
  --lh2: 1.4;
  --lh3: 1.45;
  --lh4: 1.5;
  --lh5: 1.55;
  --lh6: 1.6;
  --lh7: 1.5;
  --lh8: 1.35;
  --lh9: 1.25;
  --lh10: 1.2;
  --lh11: 1.1;
  /* The interface's running text (UIC-42): `--t5` on this, every door. */
  --lh-body: 1.5;
  /* The least a field's type is on a phone, or iOS zooms into it (PBOX-13). */
  --t-field: 16px;
  /* A field's type: the running text's, and `--t-field` on a phone (`controls.css`), whoever draws the box. */
  --t-input: var(--t5);

  --r1: 2px;
  --r2: 4px;
  --r3: 6px;
  --r4: 8px;
  --r5: 10px;
  --r6: 12px;
  --r7: 16px;
  --r-pill: 999px;

  /* How long a state takes to arrive. Fifty-three rules across the sheets
     spelled twenty-two different durations for the one thing a hover does,
     and a screen where two neighbours settle at different moments reads as
     two screens. Long enough to be seen, short enough not to be waited for. */
  --quick: .15s ease;
  /* What unfolds — a label, a fold, a list closing to its row — and a mark that lands (UIC-42). */
  --unfold: .35s cubic-bezier(.4, 0, .2, 1);
  --spring: .18s cubic-bezier(.34, 1.56, .64, 1);
  /* A notice coming up from the foot, and going (UIC-42). */
  --arrive: .22s ease-out;
  --leave: .2s ease-in;
  /* A drawer sliding in from the right, and out again — the script waits out the second (UI-8). */
  --enter: .22s cubic-bezier(.4, 0, .2, 1);
  --exit: .18s cubic-bezier(.4, 0, .2, 1);
  /* The pulse of something at work — the assistant's three dots (UIC-42). */
  --beat: 1.2s;

  /* The three measures every product has and each had named for itself —
     `--k-page`/`--k-prose`/`--k-gutter` in the portal, a literal 1240 in nine
     of the portal's rules and in the front page's wrapper, `container` and
     `container-narrow` in the console's. They are *measures* and not steps
     (UI-42), which is why they are lengths here and not rungs; what they are
     not is one product's, so they are named once and a product that wants a
     different page retunes the name rather than inventing one.

     `--measure` and not `--page`: `--page` is the ground a page is painted
     on, and a width called the same thing as a colour is an hour lost the
     first time somebody reaches for the wrong one.

     `--read` is the fourth (UIC-41): the one centred column a page that is
     read or filled in stands in — a manual, the account, the settings — its
     title and its body on the same two edges. */
  --measure: 1240px;
  --read: 880px;
  --prose: 62ch;
  --gutter: clamp(16px, 2.4vw, 44px);

  /* The way back's ring, and the least a finger can press (UIC-43). */
  --back: 34px;
  --finger: 44px;

  /* The card a question or a small job is asked in (UIC-44): the mailbox's
     delete-task card, and its wide twin for a form that needs the room. */
  --dialog: 430px;
  --dialog-wide: 640px;
  /* The column a sheet's job stands in, its head on the same edges (UIC-43). */
  --sheet-col: 660px;
  /* And a writing surface's: the composer, its head, its message and its foot on one wide column. */
  --sheet-wide: 1420px;
  /* One turn of a conversation: a message, a tool's call, the cards it points at (UIC-42). */
  --bubble: 720px;
  /* A phone's width, for a page drawn as a phone would draw it (the console's canvas). */
  --phone: 402px;
  /* The least a field in a table's cell is drawn at: a few words (`Field.cell`). */
  --cell-least: 128px;
  /* A numbered part's name, down the left of its controls where the column holds both (KODU-110). */
  --part-label: 180px;

  /* The heights a press stands at, the mailbox's (UIC-42, P8); a field's box is the tall one. */
  --press: 30px;
  --press-small: 27px;
  --press-tall: 38px;

  /* The controls' own measures (UIC-42): the switch's track, a paint, a menu, a card, a scrolling list. */
  --switch-w: 44px;
  --switch-h: 26px;
  --swatch-size: 28px;
  --menu: 210px;
  --tile: 104px;
  --list-max: 272px;
  /* A list's search pill at its widest, on a board with the room to stretch it (UIC-43). */
  --find: 420px;
  /* The strip a notice is said in, a run of a form's controls, the report box (UIC-42). */
  --notice: 560px;
  --group: 560px;
  --report: 340px;
  /* A drawer's panel: a detail beside what is open, or a record's form (UI-8, UIC-43). */
  --drawer: 544px;

  /* A working surface's columns, the mailbox's, on every door (UIC-42, UIC-38): the rail, the list beside it, the list of what its chosen row holds (the mailbox's threads), and a side column for a part of the thing open (the console's properties, a record's facts). */
  --rail-col: 84px;
  --list-col: clamp(264px, 22vw, 296px);
  --sublist-col: 420px;
  /* The sublist in the list's place below the wide desk: its head holds the way back, a face, a name and two rounds. */
  --sublist-narrow: 300px;
  --side-col: 300px;
  /* How far in from a column's edges, and a pane's, what they hold stands: a phone's, the frame widening both on a desk (`layouts.css`). */
  --list-inset: var(--s7);
  --pane-inset: var(--s7);
  /* The least the thing keeps beside its side column before the side stands under it (`layouts::sided`). */
  --main-least: 420px;
  /* How far a sheet from the foot rises over the screen: the part chosen inside a pane below the wide desk. */
  --sheet-rise: 62dvh;
  /* How far what hangs on a face's edge stands in: nothing on a phone, where the face stands down; a face and its gap on a desk (`lists.css`, UIC-51). */
  --hang: 0px;
  /* The room left after a page's last thing on a phone, so it is never read against the foot (`layouts.css`, UIC-51). */
  --page-end: calc(var(--s13) * 2.5);
}
/* A phone's field at the size iOS will not zoom into (PBOX-13), so the device's width asks. In the
   scale and not in `controls.css`: every sheet starts with this, and a page's second sheet put the
   desk's `--t-input` back after the tier's phone had set it — the front page's form and Miiu's
   prompt zoomed on every tap. */
@media (max-width: 640px) {
  :root { --t-input: var(--t-field); }
}

:root {
  color-scheme: light dark;

  --page:    oklch(0.95 0.008 85);
  --surface: oklch(0.99 0.004 85);
  --mid:     oklch(0.975 0.005 85);
  --rail:    oklch(0.965 0.006 85);
  --field:   oklch(0.96 0.006 85);
  --hover:   oklch(0.955 0.006 85);
  --chip:    oklch(0.93 0.006 85);
  --line:    oklch(0.91 0.006 85);
  --line2:   oklch(0.88 0.006 85);
  --hair:    oklch(0.93 0.006 85);
  --edge:    oklch(0.82 0.006 85);
  --ring:    oklch(0.78 0.01 85);

  --ink:   oklch(0.22 0.01 85);
  --ink2:  oklch(0.28 0.01 85);
  --ink3:  oklch(0.46 0.01 85);
  --mute:  oklch(0.58 0.01 85);
  --faint: oklch(0.62 0.01 85);
  --idle:  oklch(0.72 0.01 85);
  --rail-ink: oklch(0.55 0.012 85);

  --accent:      oklch(0.52 0.14 265);
  --accent-down: oklch(0.46 0.14 265);
  --accent-idle: oklch(0.82 0.03 265);
  --accent-ink:  oklch(0.99 0.004 265);
  --accent-text: oklch(0.38 0.1 265);
  --chip-ink:    oklch(0.33 0.09 265);
  --wash:        oklch(0.52 0.14 265 / 0.09);
  --wash-faint:  oklch(0.52 0.14 265 / 0.05);
  --accent-soft: oklch(0.52 0.14 265 / 0.12);
  --accent-line: oklch(0.52 0.14 265 / 0.4);

  /* The two colours in here that are not the design's, and must not be. A QR
     is read by a camera, not by a person, and the standard it is read against
     assumes black modules on white paper — a near-white page and a near-black
     ink are close enough to look right and far enough to cost somebody a scan
     on a dim phone. They do not swap with the scheme, and nothing but a QR may
     use them. */
  --qr-paper: oklch(1 0 0);
  --qr-ink:   oklch(0 0 0);

  --star:      oklch(0.58 0.14 145);
  --star-soft: oklch(0.94 0.05 145);
  --star-ink:  oklch(0.4 0.09 145);
  --ok-bg:     oklch(0.55 0.12 145 / 0.12);
  --ok-ink:    oklch(0.42 0.1 145);

  /* The one red. It is spent on deleting and on a deadline that has actually
     passed, and nowhere else — which is what makes it mean anything. */
  --danger:      oklch(0.5 0.16 25);
  --danger-fill: oklch(0.52 0.17 25);
  --danger-down: oklch(0.45 0.17 25);
  --danger-line: oklch(0.88 0.02 25);
  --danger-soft: oklch(0.96 0.03 25);
  --danger-wash: oklch(0.95 0.05 25);
  --danger-deep: oklch(0.45 0.13 25);
  --bad-bg:      oklch(0.55 0.18 25 / 0.1);
  --flag-line:   oklch(0.55 0.18 25 / 0.35);
  --flag-bg:     oklch(0.55 0.18 25 / 0.06);
  --flag-ink:    oklch(0.42 0.14 25);

  /* Neither the accent nor a warning: the tone a note about the product wears
     when it is neither good news nor bad. */
  --alert:     oklch(0.58 0.16 35);
  --info:      oklch(0.5 0.13 285);
  --info-soft: oklch(0.96 0.025 285);

  /* An answer written and not sent is amber: asking to be finished, neither
     the accent nor the attention sand. */
  --draft-line:     oklch(0.88 0.03 60);
  --draft-bg:       oklch(0.985 0.008 60);
  --draft-edge:     oklch(0.7 0.08 60);
  --draft-ink:      oklch(0.58 0.03 60);
  --draft-tag:      oklch(0.55 0.09 60);
  --draft-tag-line: oklch(0.82 0.06 60);

  /* The accent-tinted machine text of the manual's tables and code. */
  --doc-key:  oklch(0.3 0.06 265);
  --doc-code: oklch(0.32 0.03 265);

  /* The attention tone: sand at hue 75, one lightness tinted at five
     strengths. Waiting, Block all, an overdue count and every warning wear it,
     because none of them is an error — they are things asking to be looked at,
     and colouring them red would spend the delete colour on a first-time
     sender. They are not re-answered in the dark: a translucent tint of one
     mid lightness holds under either ground. */
  --attn-h: 75;
  --attn-c: 0.06;
  --attn-fill: oklch(0.68 var(--attn-c) var(--attn-h) / 0.168);
  --warn-bg:   oklch(0.68 var(--attn-c) var(--attn-h) / 0.224);
  --warn-line: oklch(0.68 var(--attn-c) var(--attn-h) / 0.448);
  --badge-bg:   oklch(0.68 var(--attn-c) var(--attn-h) / 0.56);
  --attn-line:  oklch(0.68 var(--attn-c) var(--attn-h) / 0.7);
  --badge-line: oklch(0.68 var(--attn-c) var(--attn-h) / 0.84);
  --warn-ink:  oklch(0.44 0.066 75);
  --warn-dot:  oklch(0.66 0.096 75);

  --solid:     oklch(0.22 0.006 85);
  --solid-ink: oklch(0.95 0.004 85);

  /* An avatar's hue comes from the address, so one person is one colour
     everywhere, for everyone. Only the lightness and chroma change with the
     scheme — the hue is the identity and must not move. */
  --av-bg: 0.87 0.05;
  --av-fg: 0.38 0.075;

  --radius: 10px;

  --serif: 'Fraunces', 'Iowan Old Style', 'Palatino Linotype', Palatino, Georgia, serif;
  --sans:  'Instrument Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --mono:  'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  /* Shadows are for what floats. Nothing in a column has one. */
  --desk:   0 1px 2px oklch(0.2 0.01 85 / 0.06), 0 24px 60px oklch(0.2 0.01 85 / 0.10);
  --lift:   0 1px 3px oklch(0.2 0.01 85 / 0.12);
  --card:   0 10px 32px oklch(0.2 0.01 85 / 0.08);
  --tip:    0 12px 30px oklch(0.2 0.01 85 / 0.24);
  --tip-sm: 0 8px 20px oklch(0.2 0.01 85 / 0.25);
  --float:  0 10px 28px oklch(0.2 0.01 85 / 0.12);
  --knob:   0 1px 3px oklch(0.2 0.01 85 / 0.25);
  --pop:   0 14px 36px oklch(0.2 0.01 85 / 0.18);
  --sheet: 0 24px 60px oklch(0.2 0.01 85 / 0.3);
  --slide: -18px 0 44px oklch(0.2 0.01 85 / 0.14);
  --rise: 0 -10px 34px oklch(0.15 0.01 85 / 0.18);
  --shadow: 0 1px 2px oklch(0.2 0.01 85 / 0.06), 0 20px 50px oklch(0.2 0.01 85 / 0.09);
  --scrim: oklch(0.25 0.01 85 / 0.45);
  --veil:  oklch(0.2 0.01 85 / 0.16);

  /* The stage a picture fills the screen on (UIC-20): a warm near-black in
     both schemes — the picture is the light there, so the dark scheme has
     nothing to invert — its controls a veil of the ground over the picture,
     their hairline a veil of the ink. And the paper a drawing is contained
     on: white in both schemes, because white is what it was drawn on. */
  --stage: oklch(0.13 0.01 85);
  --stage-ink: oklch(0.98 0.005 85);
  --stage-veil: oklch(0.1 0.01 85 / 0.5);
  --stage-line: oklch(0.98 0.005 85 / 0.28);
  --paper: oklch(0.99 0.003 85);
}


@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --page:    oklch(0.155 0.006 85);
    --surface: oklch(0.195 0.006 85);
    --mid:     oklch(0.185 0.006 85);
    --rail:    oklch(0.17 0.006 85);
    --field:   oklch(0.22 0.006 85);
    --hover:   oklch(0.235 0.006 85);
    --chip:    oklch(0.25 0.006 85);
    --line:    oklch(0.27 0.006 85);
    --line2:   oklch(0.31 0.006 85);
    --hair:    oklch(0.25 0.006 85);
    --edge:    oklch(0.38 0.006 85);
    --ring:    oklch(0.44 0.01 85);

    --ink:   oklch(0.94 0.004 85);
    --ink2:  oklch(0.88 0.004 85);
    --ink3:  oklch(0.72 0.008 85);
    --mute:  oklch(0.58 0.008 85);
    --faint: oklch(0.55 0.008 85);
    --idle:  oklch(0.45 0.008 85);
    --rail-ink: oklch(0.62 0.01 85);

    --accent:      oklch(0.72 0.08 265);
    --accent-down: oklch(0.78 0.09 265);
    --accent-idle: oklch(0.38 0.04 265);
    --accent-ink:  oklch(0.18 0.01 265);
    --accent-text: oklch(0.8 0.09 265);
    --chip-ink:    oklch(0.82 0.08 265);
    --wash:        oklch(0.72 0.08 265 / 0.17);
    --wash-faint:  oklch(0.72 0.08 265 / 0.1);
    --accent-soft: oklch(0.72 0.08 265 / 0.24);
    --accent-line: oklch(0.72 0.08 265 / 0.45);

    --star:      oklch(0.76 0.13 145);
    --star-soft: oklch(0.27 0.04 145);
    --star-ink:  oklch(0.84 0.1 145);
    --ok-bg:     oklch(0.7 0.12 145 / 0.16);
    --ok-ink:    oklch(0.8 0.1 145);

    --danger:      oklch(0.72 0.14 25);
    --danger-fill: oklch(0.68 0.16 25);
    --danger-down: oklch(0.74 0.16 25);
    --danger-line: oklch(0.4 0.08 25);
    --danger-soft: oklch(0.28 0.05 25);
    --danger-wash: oklch(0.3 0.07 25);
    --danger-deep: oklch(0.78 0.12 25);
    --bad-bg:      oklch(0.65 0.18 25 / 0.16);
    --flag-line:   oklch(0.65 0.16 25 / 0.45);
    --flag-bg:     oklch(0.65 0.16 25 / 0.12);
    --flag-ink:    oklch(0.8 0.12 25);

    --alert:     oklch(0.62 0.16 35);
    --info:      oklch(0.76 0.11 285);
    --info-soft: oklch(0.28 0.05 285);

    --draft-line:     oklch(0.35 0.05 60);
    --draft-bg:       oklch(0.22 0.02 60);
    --draft-edge:     oklch(0.55 0.08 60);
    --draft-ink:      oklch(0.7 0.05 60);
    --draft-tag:      oklch(0.75 0.09 60);
    --draft-tag-line: oklch(0.45 0.07 60);

    --doc-key:  oklch(0.82 0.07 265);
    --doc-code: oklch(0.8 0.04 265);

    --warn-ink: oklch(0.85 0.07 75);
    --warn-dot: oklch(0.74 0.1 75);

    --solid:     oklch(0.94 0.004 85);
    --solid-ink: oklch(0.2 0.006 85);

    --av-bg: 0.36 0.06;
    --av-fg: 0.85 0.06;

    --desk:   0 1px 2px oklch(0.05 0.01 85 / 0.3), 0 24px 60px oklch(0.05 0.01 85 / 0.4);
    --lift:   0 1px 3px oklch(0.05 0.01 85 / 0.4);
    --card:   0 10px 32px oklch(0.05 0.01 85 / 0.3);
    --tip:    0 12px 30px oklch(0.05 0.01 85 / 0.5);
    --tip-sm: 0 8px 20px oklch(0.05 0.01 85 / 0.5);
    --float:  0 10px 28px oklch(0.05 0.01 85 / 0.4);
    --knob:   0 1px 3px oklch(0.05 0.01 85 / 0.5);
    --pop:   0 14px 36px oklch(0.05 0.01 85 / 0.5);
    --sheet: 0 24px 60px oklch(0.05 0.01 85 / 0.6);
    --slide: -18px 0 44px oklch(0.05 0.01 85 / 0.45);
    --rise: 0 -10px 34px oklch(0.05 0.01 85 / 0.45);
    --shadow: 0 1px 2px oklch(0.05 0.01 85 / 0.3), 0 20px 50px oklch(0.05 0.01 85 / 0.3);
    --scrim: oklch(0.05 0.01 85 / 0.6);
    --veil:  oklch(0.05 0.01 85 / 0.35);
    --stage: oklch(0.13 0.01 85);
    --stage-ink: oklch(0.98 0.005 85);
    --stage-veil: oklch(0.1 0.01 85 / 0.5);
    --stage-line: oklch(0.98 0.005 85 / 0.28);
    --paper: oklch(0.99 0.003 85);
  }
}
:root[data-theme="dark"] {
    --page:    oklch(0.155 0.006 85);
    --surface: oklch(0.195 0.006 85);
    --mid:     oklch(0.185 0.006 85);
    --rail:    oklch(0.17 0.006 85);
    --field:   oklch(0.22 0.006 85);
    --hover:   oklch(0.235 0.006 85);
    --chip:    oklch(0.25 0.006 85);
    --line:    oklch(0.27 0.006 85);
    --line2:   oklch(0.31 0.006 85);
    --hair:    oklch(0.25 0.006 85);
    --edge:    oklch(0.38 0.006 85);
    --ring:    oklch(0.44 0.01 85);

    --ink:   oklch(0.94 0.004 85);
    --ink2:  oklch(0.88 0.004 85);
    --ink3:  oklch(0.72 0.008 85);
    --mute:  oklch(0.58 0.008 85);
    --faint: oklch(0.55 0.008 85);
    --idle:  oklch(0.45 0.008 85);
    --rail-ink: oklch(0.62 0.01 85);

    --accent:      oklch(0.72 0.08 265);
    --accent-down: oklch(0.78 0.09 265);
    --accent-idle: oklch(0.38 0.04 265);
    --accent-ink:  oklch(0.18 0.01 265);
    --accent-text: oklch(0.8 0.09 265);
    --chip-ink:    oklch(0.82 0.08 265);
    --wash:        oklch(0.72 0.08 265 / 0.17);
    --wash-faint:  oklch(0.72 0.08 265 / 0.1);
    --accent-soft: oklch(0.72 0.08 265 / 0.24);
    --accent-line: oklch(0.72 0.08 265 / 0.45);

    --star:      oklch(0.76 0.13 145);
    --star-soft: oklch(0.27 0.04 145);
    --star-ink:  oklch(0.84 0.1 145);
    --ok-bg:     oklch(0.7 0.12 145 / 0.16);
    --ok-ink:    oklch(0.8 0.1 145);

    --danger:      oklch(0.72 0.14 25);
    --danger-fill: oklch(0.68 0.16 25);
    --danger-down: oklch(0.74 0.16 25);
    --danger-line: oklch(0.4 0.08 25);
    --danger-soft: oklch(0.28 0.05 25);
    --danger-wash: oklch(0.3 0.07 25);
    --danger-deep: oklch(0.78 0.12 25);
    --bad-bg:      oklch(0.65 0.18 25 / 0.16);
    --flag-line:   oklch(0.65 0.16 25 / 0.45);
    --flag-bg:     oklch(0.65 0.16 25 / 0.12);
    --flag-ink:    oklch(0.8 0.12 25);

    --alert:     oklch(0.62 0.16 35);
    --info:      oklch(0.76 0.11 285);
    --info-soft: oklch(0.28 0.05 285);

    --draft-line:     oklch(0.35 0.05 60);
    --draft-bg:       oklch(0.22 0.02 60);
    --draft-edge:     oklch(0.55 0.08 60);
    --draft-ink:      oklch(0.7 0.05 60);
    --draft-tag:      oklch(0.75 0.09 60);
    --draft-tag-line: oklch(0.45 0.07 60);

    --doc-key:  oklch(0.82 0.07 265);
    --doc-code: oklch(0.8 0.04 265);

    --warn-ink: oklch(0.85 0.07 75);
    --warn-dot: oklch(0.74 0.1 75);

    --solid:     oklch(0.94 0.004 85);
    --solid-ink: oklch(0.2 0.006 85);

    --av-bg: 0.36 0.06;
    --av-fg: 0.85 0.06;

    --desk:   0 1px 2px oklch(0.05 0.01 85 / 0.3), 0 24px 60px oklch(0.05 0.01 85 / 0.4);
    --lift:   0 1px 3px oklch(0.05 0.01 85 / 0.4);
    --card:   0 10px 32px oklch(0.05 0.01 85 / 0.3);
    --tip:    0 12px 30px oklch(0.05 0.01 85 / 0.5);
    --tip-sm: 0 8px 20px oklch(0.05 0.01 85 / 0.5);
    --float:  0 10px 28px oklch(0.05 0.01 85 / 0.4);
    --knob:   0 1px 3px oklch(0.05 0.01 85 / 0.5);
    --pop:   0 14px 36px oklch(0.05 0.01 85 / 0.5);
    --sheet: 0 24px 60px oklch(0.05 0.01 85 / 0.6);
    --slide: -18px 0 44px oklch(0.05 0.01 85 / 0.45);
    --rise: 0 -10px 34px oklch(0.05 0.01 85 / 0.45);
    --shadow: 0 1px 2px oklch(0.05 0.01 85 / 0.3), 0 20px 50px oklch(0.05 0.01 85 / 0.3);
    --scrim: oklch(0.05 0.01 85 / 0.6);
    --veil:  oklch(0.05 0.01 85 / 0.35);
    --stage: oklch(0.13 0.01 85);
    --stage-ink: oklch(0.98 0.005 85);
    --stage-veil: oklch(0.1 0.01 85 / 0.5);
    --stage-line: oklch(0.98 0.005 85 / 0.28);
    --paper: oklch(0.99 0.003 85);
}
:root[data-theme="light"] {
  color-scheme: light;
}
:root[data-theme="dark"] {
  color-scheme: dark;
}
@media (prefers-color-scheme: dark) and (max-width: 640px) {
  :root:not([data-theme="light"]) {
    --page:    oklch(0.1 0.004 85);
    --surface: oklch(0.125 0.005 85);
    --mid:     oklch(0.115 0.005 85);
    --rail:    oklch(0.11 0.004 85);
    --field:   oklch(0.16 0.005 85);
    --hover:   oklch(0.175 0.005 85);
    --chip:    oklch(0.19 0.005 85);
    --line:    oklch(0.3 0.006 85);
    --line2:   oklch(0.34 0.006 85);
    --hair:    oklch(0.28 0.006 85);

    --ink:   oklch(0.985 0.002 85);
    --ink2:  oklch(0.94 0.003 85);
    --ink3:  oklch(0.82 0.006 85);
    --mute:  oklch(0.7 0.008 85);
    --faint: oklch(0.64 0.008 85);
  }
}
@media (max-width: 640px) {
  :root[data-theme="dark"] {
    --page:    oklch(0.1 0.004 85);
    --surface: oklch(0.125 0.005 85);
    --mid:     oklch(0.115 0.005 85);
    --rail:    oklch(0.11 0.004 85);
    --field:   oklch(0.16 0.005 85);
    --hover:   oklch(0.175 0.005 85);
    --chip:    oklch(0.19 0.005 85);
    --line:    oklch(0.3 0.006 85);
    --line2:   oklch(0.34 0.006 85);
    --hair:    oklch(0.28 0.006 85);

    --ink:   oklch(0.985 0.002 85);
    --ink2:  oklch(0.94 0.003 85);
    --ink3:  oklch(0.82 0.006 85);
    --mute:  oklch(0.7 0.008 85);
    --faint: oklch(0.64 0.008 85);
  }
}
.ui-paper {
  color-scheme: light;
  color: var(--ink);

  --page:    oklch(0.95 0.008 85);
  --surface: oklch(0.99 0.004 85);
  --mid:     oklch(0.975 0.005 85);
  --rail:    oklch(0.965 0.006 85);
  --field:   oklch(0.96 0.006 85);
  --hover:   oklch(0.955 0.006 85);
  --chip:    oklch(0.93 0.006 85);
  --line:    oklch(0.91 0.006 85);
  --line2:   oklch(0.88 0.006 85);
  --hair:    oklch(0.93 0.006 85);
  --edge:    oklch(0.82 0.006 85);
  --ring:    oklch(0.78 0.01 85);

  --ink:   oklch(0.22 0.01 85);
  --ink2:  oklch(0.28 0.01 85);
  --ink3:  oklch(0.46 0.01 85);
  --mute:  oklch(0.58 0.01 85);
  --faint: oklch(0.62 0.01 85);
  --idle:  oklch(0.72 0.01 85);
  --rail-ink: oklch(0.55 0.012 85);

  --accent:      oklch(0.52 0.14 265);
  --accent-down: oklch(0.46 0.14 265);
  --accent-idle: oklch(0.82 0.03 265);
  --accent-ink:  oklch(0.99 0.004 265);
  --accent-text: oklch(0.38 0.1 265);
  --chip-ink:    oklch(0.33 0.09 265);
  --wash:        oklch(0.52 0.14 265 / 0.09);
  --wash-faint:  oklch(0.52 0.14 265 / 0.05);
  --accent-soft: oklch(0.52 0.14 265 / 0.12);
  --accent-line: oklch(0.52 0.14 265 / 0.4);

  /* The two colours in here that are not the design's, and must not be. A QR
     is read by a camera, not by a person, and the standard it is read against
     assumes black modules on white paper — a near-white page and a near-black
     ink are close enough to look right and far enough to cost somebody a scan
     on a dim phone. They do not swap with the scheme, and nothing but a QR may
     use them. */
  --qr-paper: oklch(1 0 0);
  --qr-ink:   oklch(0 0 0);

  --star:      oklch(0.58 0.14 145);
  --star-soft: oklch(0.94 0.05 145);
  --star-ink:  oklch(0.4 0.09 145);
  --ok-bg:     oklch(0.55 0.12 145 / 0.12);
  --ok-ink:    oklch(0.42 0.1 145);

  /* The one red. It is spent on deleting and on a deadline that has actually
     passed, and nowhere else — which is what makes it mean anything. */
  --danger:      oklch(0.5 0.16 25);
  --danger-fill: oklch(0.52 0.17 25);
  --danger-down: oklch(0.45 0.17 25);
  --danger-line: oklch(0.88 0.02 25);
  --danger-soft: oklch(0.96 0.03 25);
  --danger-wash: oklch(0.95 0.05 25);
  --danger-deep: oklch(0.45 0.13 25);
  --bad-bg:      oklch(0.55 0.18 25 / 0.1);
  --flag-line:   oklch(0.55 0.18 25 / 0.35);
  --flag-bg:     oklch(0.55 0.18 25 / 0.06);
  --flag-ink:    oklch(0.42 0.14 25);

  /* Neither the accent nor a warning: the tone a note about the product wears
     when it is neither good news nor bad. */
  --alert:     oklch(0.58 0.16 35);
  --info:      oklch(0.5 0.13 285);
  --info-soft: oklch(0.96 0.025 285);

  /* An answer written and not sent is amber: asking to be finished, neither
     the accent nor the attention sand. */
  --draft-line:     oklch(0.88 0.03 60);
  --draft-bg:       oklch(0.985 0.008 60);
  --draft-edge:     oklch(0.7 0.08 60);
  --draft-ink:      oklch(0.58 0.03 60);
  --draft-tag:      oklch(0.55 0.09 60);
  --draft-tag-line: oklch(0.82 0.06 60);

  /* The accent-tinted machine text of the manual's tables and code. */
  --doc-key:  oklch(0.3 0.06 265);
  --doc-code: oklch(0.32 0.03 265);

  /* The attention tone: sand at hue 75, one lightness tinted at five
     strengths. Waiting, Block all, an overdue count and every warning wear it,
     because none of them is an error — they are things asking to be looked at,
     and colouring them red would spend the delete colour on a first-time
     sender. They are not re-answered in the dark: a translucent tint of one
     mid lightness holds under either ground. */
  --attn-h: 75;
  --attn-c: 0.06;
  --attn-fill: oklch(0.68 var(--attn-c) var(--attn-h) / 0.168);
  --warn-bg:   oklch(0.68 var(--attn-c) var(--attn-h) / 0.224);
  --warn-line: oklch(0.68 var(--attn-c) var(--attn-h) / 0.448);
  --badge-bg:   oklch(0.68 var(--attn-c) var(--attn-h) / 0.56);
  --attn-line:  oklch(0.68 var(--attn-c) var(--attn-h) / 0.7);
  --badge-line: oklch(0.68 var(--attn-c) var(--attn-h) / 0.84);
  --warn-ink:  oklch(0.44 0.066 75);
  --warn-dot:  oklch(0.66 0.096 75);

  --solid:     oklch(0.22 0.006 85);
  --solid-ink: oklch(0.95 0.004 85);

  /* An avatar's hue comes from the address, so one person is one colour
     everywhere, for everyone. Only the lightness and chroma change with the
     scheme — the hue is the identity and must not move. */
  --av-bg: 0.87 0.05;
  --av-fg: 0.38 0.075;

  --radius: 10px;

  --serif: 'Fraunces', 'Iowan Old Style', 'Palatino Linotype', Palatino, Georgia, serif;
  --sans:  'Instrument Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --mono:  'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  /* Shadows are for what floats. Nothing in a column has one. */
  --desk:   0 1px 2px oklch(0.2 0.01 85 / 0.06), 0 24px 60px oklch(0.2 0.01 85 / 0.10);
  --lift:   0 1px 3px oklch(0.2 0.01 85 / 0.12);
  --card:   0 10px 32px oklch(0.2 0.01 85 / 0.08);
  --tip:    0 12px 30px oklch(0.2 0.01 85 / 0.24);
  --tip-sm: 0 8px 20px oklch(0.2 0.01 85 / 0.25);
  --float:  0 10px 28px oklch(0.2 0.01 85 / 0.12);
  --knob:   0 1px 3px oklch(0.2 0.01 85 / 0.25);
  --pop:   0 14px 36px oklch(0.2 0.01 85 / 0.18);
  --sheet: 0 24px 60px oklch(0.2 0.01 85 / 0.3);
  --slide: -18px 0 44px oklch(0.2 0.01 85 / 0.14);
  --rise: 0 -10px 34px oklch(0.15 0.01 85 / 0.18);
  --shadow: 0 1px 2px oklch(0.2 0.01 85 / 0.06), 0 20px 50px oklch(0.2 0.01 85 / 0.09);
  --scrim: oklch(0.25 0.01 85 / 0.45);
  --veil:  oklch(0.2 0.01 85 / 0.16);

  /* The stage a picture fills the screen on (UIC-20): a warm near-black in
     both schemes — the picture is the light there, so the dark scheme has
     nothing to invert — its controls a veil of the ground over the picture,
     their hairline a veil of the ink. And the paper a drawing is contained
     on: white in both schemes, because white is what it was drawn on. */
  --stage: oklch(0.13 0.01 85);
  --stage-ink: oklch(0.98 0.005 85);
  --stage-veil: oklch(0.1 0.01 85 / 0.5);
  --stage-line: oklch(0.98 0.005 85 / 0.28);
  --paper: oklch(0.99 0.003 85);
}

/* The ground every surface stands on, first in the tier's sheet (UIC-42). */

*, *::before, *::after { box-sizing: border-box; }

/* A phone turned on its side keeps the type it was drawn in: Safari's own enlarging reads as the page zooming itself. */
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }

/* One body for every application door (UIC-42); a storefront's theme sets its own (THEME-7). The
   body is a container (UIC-23), and a contained body's ground stops at its own foot, so it is at
   least the window. */
body {
  min-height: 100dvh;
  margin: 0;
  background: var(--page);
  color: var(--ink);
  font-family: var(--sans);
  font-size: var(--t5);
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* A tap acts at once; pinch still zooms. */
  touch-action: manipulation;
}

/* A link, a press and a field start bare; the tier's controls draw what they are. */
a { color: inherit; text-decoration: none; }
button, input, textarea, select { font: inherit; color: inherit; }
button { margin: 0; padding: 0; border: 0; background: none; cursor: pointer; }
::placeholder { color: var(--faint); }
/* A machine's words are the house's mono, never the browser's. */
:where(code, kbd, samp, pre) { font-family: var(--mono); }
/* A tick, a dot, a slider and a bar the browser draws, in the accent. */
:where(input, progress) { accent-color: var(--accent); }
img { max-width: 100%; }

/* `hidden` hides, whatever display a class gave the element. */
[hidden] { display: none !important; }

/* One focus ring for whatever a keyboard lands on (UIC-42), at a pseudo-class's weight. */
:where(a, button, summary, [tabindex], input, select, textarea):focus-visible {
  outline: var(--s1) solid var(--accent);
  outline-offset: var(--s1);
}

/* One look for every control on every surface (UIC-8), on the house tokens.
   Nothing here defines a colour or a length of its own: the tokens come first
   (`tokens::preamble`) and the application's own sheet comes after, and may
   add to a control but never redraws one.

   The shape is the mailbox's, which is the one in this product worth copying:
   the label above the box and quiet, the box a clean rounded rectangle on the
   surface, and the accent spent on focus rather than on decoration.

   **One name per thing** (UIC-10). The `.field`/`.input`/`.k-field`/`.k-input`
   aliases this file carried are gone: there is one control in the tier now, it
   spells one class, and an application's sheet that wants to add to it spells
   the same one. */

/* ── a glyph, and words only a screen reader hears (UIC-36) ──────────────── */

/* `ui::icon` draws every glyph in the product, so its size is the tier's:
   a letter tall, in the colour of the words it sits in. These two rules were
   Platform's (`theme.css`), and the portal and the sites link no such sheet —
   so a glyph there with no rule of its own drew at the SVG's natural size
   (the arrow under the visitor's sign-in, the arrow on the chat's own press)
   and a label meant for a screen reader was printed on the page. */
.icon {
  width: 1em;
  height: 1em;
  display: inline-block;
  vertical-align: -0.125em;
  fill: currentColor;
  flex-shrink: 0;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ── a field: a label, a box, a hint ─────────────────────────────────────── */

.ui-field {
  display: flex;
  flex-direction: column;
  gap: var(--s3);
  margin: 0;
  position: static;
}
/* A cell of a table of fields keeps room for a few words however many columns share its row. */
.ui-field.is-cell { min-width: var(--cell-least); }

.ui-label {
  display: block;
  position: static;
  margin: 0;
  font-family: inherit;
  font-size: var(--t4);
  line-height: var(--lh4);
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink3);
  pointer-events: auto;
}

/* A label for a screen reader alone (`Field.label_hidden`): out of the column, and the glyph centres in the box. */
.ui-label.sr-only { position: absolute; }
.ui-label.sr-only ~ .ui-field-icon { top: calc((var(--press-tall) - 1em) / 2); }

.ui-hint {
  margin: 0;
  font-size: var(--t4);
  color: var(--mute);
  text-wrap: pretty;
}

.ui-input {
  width: 100%;
  box-sizing: border-box;
  height: var(--press-tall);
  padding: 0 var(--s6);
  border: 1px solid var(--line);
  border-radius: var(--r3);
  /* On the surface, not on `--field` (UIC-8). */
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: var(--t-input);
  outline: none;
  transition: border-color var(--quick);
}

/* A price or a size reads in the figures' face: a column of them lines up. */
.ui-input.mono {
  font-family: var(--mono);
}

/* At least a box tall; its `rows` say the rest, so a note of two lines is not drawn as a page of four. */
textarea.ui-input {
  height: auto;
  min-height: var(--press-tall);
  padding: var(--s5) var(--s6);
  line-height: var(--lh-body);
  resize: vertical;
}

/* A line that grows with what is typed is not a box to drag. */
textarea.ui-input:is([rows="1"], [data-grow]) { resize: none; }

select.ui-input {
  height: var(--press-tall);
  padding: 0 var(--s5);
}

.ui-input:focus {
  border-color: var(--accent-line, var(--accent));
}

/* On a phone `--t-input` is `--t-field`, the size iOS will not zoom into: the scale says so (PBOX-13). */

.ui-input:disabled {
  background: var(--chip);
  color: var(--mute);
}

/* A search is the list's pill (`ui::find`, UIC-43): the field's box on the hover ground, the lens at its left end. */
.ui-input[type="search"] {
  appearance: none;
  border-color: transparent;
  border-radius: var(--r-pill);
  background: var(--hover);
}
.ui-input[type="search"]:focus { border-color: var(--accent-line, var(--accent)); }
.ui-find { margin: 0; min-width: 0; }

/* A leading glyph, and the room the box makes for it. Measured from the top
   because a field with a hint is taller, and from the bottom the glyph lands
   in the hint instead of in the box. */
.ui-field-icon {
  position: absolute;
  left: var(--s6);
  /* The label's line, its gap, then the middle of the box. */
  top: calc(var(--t4) * var(--lh4) + var(--s3) + (var(--press-tall) - 1em) / 2);
  color: var(--mute);
  pointer-events: none;
  line-height: 1;
}
.ui-field.has-icon {
  position: relative;
}
.ui-field.has-icon .ui-input {
  padding-left: calc(var(--s10) + var(--s2));
}

/* A refused field, marked where it is (UI-29): the problem script hangs its
   sentence off the field itself. */
.is-invalid .ui-input,
.is-invalid .sel {
  border-color: var(--danger);
}
.ui-field-error {
  margin: 0;
  font-size: var(--t4);
  font-weight: 600;
  color: var(--danger);
  text-wrap: pretty;
}

/* A box you tick reads along its label, its hint under the two. */
.ui-field-check {
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s5);
}
.ui-field-check > .ui-hint {
  flex-basis: 100%;
  order: 3;
}
.ui-field-check > .ui-label {
  order: 2;
  color: var(--ink2);
}
.ui-field-check .ui-checkbox {
  order: 1;
  width: auto;
  height: auto;
  flex: none;
}

/* UI-37: a price is one box — the amount stretches, the currency sits at its
   right edge. */
.ui-field.money {
  flex-direction: row;
  flex-wrap: wrap;
  gap: var(--s5);
}
.ui-field.money > .ui-label {
  flex-basis: 100%;
}
.ui-field.money .money-amount {
  flex: 1 1 calc(4 * var(--s11));
}
.ui-field.money .money-cur {
  flex: 0 0 auto;
  width: auto;
  min-width: calc(2 * var(--s12));
}
.ui-field.money .money-cur:disabled {
  color: var(--mute);
}
.ui-field.money > .ui-hint {
  flex-basis: 100%;
}

/* The media library's field is a strip of pictures, not a box (GAP-216). */
.ui-field.media-field > .ui-label {
  font-size: var(--t4);
}

/* ── a rectangular press: a form's, or a page's ──────────────────────────── */

/* A storefront's press, its `--btn-*` and `--radius-btn` the site's knobs (THEME-7); an application door's is the pill (UIC-43). */
.ui-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s3);
  height: var(--press-tall);
  padding: 0 var(--s8);
  border: 1px solid var(--line2);
  border-radius: var(--radius-btn, var(--r4));
  background: none;
  color: var(--ink2);
  font-size: var(--t5);
  font-weight: 500;
  line-height: 1;
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  transition: opacity var(--quick), background-color var(--quick), border-color var(--quick), color var(--quick);
}
.ui-btn:hover { border-color: var(--ink); color: var(--ink); }
.ui-btn.is-primary {
  background: var(--btn-fill, var(--accent));
  color: var(--btn-ink, var(--accent-ink));
  border-color: var(--btn-line, var(--accent));
}
.ui-btn.is-primary:hover { opacity: .88; }
.ui-btn.is-danger { color: var(--danger); }
.ui-btn.is-danger:hover { background: var(--danger-soft); border-color: var(--danger); color: var(--danger); }
.ui-btn.is-block { width: 100%; }
/* `Size::Small` is one height in every look (P8): the pill's and the round's `--press-small`. */
.ui-btn.is-small { height: var(--press-small); padding: 0 var(--s6); font-size: var(--t4); }
.ui-btn.is-tall { height: var(--press-tall); }
.ui-btn:disabled, .ui-btn:disabled:hover { opacity: .5; cursor: default; }
.ui-btn .ui-btn-icon { font-size: var(--t6); }

/* A press of two lines, its sub-line under the words, stands as a rectangle (UIC-42). */
:is(.ui-btn, .ui-pill, .ui-submit).has-sub {
  flex-direction: column;
  align-items: flex-start;
  gap: var(--s1);
  height: auto;
  min-height: var(--press-tall);
  padding: var(--s4) var(--s7);
  border-radius: var(--r4);
  line-height: var(--lh3);
  white-space: normal;
  text-align: left;
}
.ui-btn-sub { font-size: var(--t3); font-weight: 400; color: var(--mute); }
.is-primary > .ui-btn-sub { color: inherit; }

/* ── a round press whose label unfurls (UI-25) ───────────────────────────── */

/* At rest it is a *circle*, not an oval: `--ui-round-size` is both the height
   and the minimum width, and the horizontal padding is set so that a single
   1em icon lands exactly on that width. Padding alone cannot do it — the old
   `.55rem .7rem` made the box 2.4rem wide and 2.1rem tall, so every icon
   button in the product was subtly egg-shaped. */
.ui-round {
  /* Read off the press heights (P8): its `Size` picks the step. */
  --ui-round-size: var(--press);
  /* Less its two hairlines, or the circle comes out wider than it is tall. */
  --ui-round-pad: calc((var(--ui-round-size) - var(--t6)) / 2 - 1px);

  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0;
  height: var(--ui-round-size);
  min-width: var(--ui-round-size);
  padding-inline: var(--ui-round-pad);
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--ink3);
  cursor: pointer;
  font-size: var(--t4);
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  transition: border-color var(--quick), background var(--quick), color var(--quick);
}
/* The mailbox's hover: the accent outline, never a shadow (P8). */
.ui-round:hover { border-color: var(--accent); color: var(--accent); }
.ui-round .ui-btn-icon { font-size: var(--t6); }
/* A door's own drawing in the `icon` slot stands at the glyph's size. */
.ui-round > svg:not(.icon) { flex: none; width: var(--s7); height: var(--s7); }
.ui-round.is-small { --ui-round-size: var(--press-small); }
.ui-round.is-tall { --ui-round-size: var(--press-tall); }

/* A file input keeps the browser's own words for what was chosen, beside a
   press drawn as the round pill above (UIC-7) — never the system's grey
   button, which is the one control no sheet had dressed. */
input[type="file"] { max-width: 100%; font: inherit; font-size: var(--t4); color: var(--ink2); }
input[type="file"]::file-selector-button {
  height: var(--press);
  margin-right: var(--s5);
  padding-inline: var(--s7);
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: none;
  color: var(--ink3);
  font: inherit;
  font-size: var(--t4);
  cursor: pointer;
  transition: border-color var(--quick), color var(--quick);
}
input[type="file"]::file-selector-button:hover { border-color: var(--accent); color: var(--accent); }

/* A press that must be a label holds its file input (UI-15): out of sight even when `hidden`, still where Tab lands, its ring on the press. */
label:is(.ui-btn, .ui-pill, .ui-round, .ui-submit):has(> input[type="file"]) { position: relative; }
label:is(.ui-btn, .ui-pill, .ui-round, .ui-submit) > input[type="file"] {
  display: block !important;
  position: absolute;
  inset: 0;
  width: 1px;
  height: 1px;
  margin: auto;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  border: 0;
  opacity: 0;
}

/* The scheme press (UIC-18). A ring with a glyph in it, the same object
   whether it is a link the server answers or a button a script does — which
   is the only difference between the two surfaces that wear it, and not a
   difference anybody looking at it can see.

   Its own size and not `.ui-round`'s: this one sits in a masthead beside
   words rather than in a row of controls, and it is drawn at the height of
   the text it stands next to. */
.ui-theme {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: var(--s11);
  height: var(--s11);
  border: 1px solid var(--line2);
  border-radius: var(--r-pill);
  background: none;
  color: var(--ink);
  font-size: var(--t5);
  line-height: 1;
  cursor: pointer;
}
.ui-theme:hover { border-color: var(--ink); }

/* The label unfurls rather than appearing: `max-width` is what a transition
   can actually animate, and the margin keeps it off the icon as it opens. */
.ui-round .ui-btn-label {
  max-width: 0;
  overflow: hidden;
  white-space: nowrap;
  transition: max-width var(--unfold), margin-left var(--unfold);
  margin-left: 0;
}
.ui-round:hover .ui-btn-label,
.ui-round:focus-visible .ui-btn-label,
.ui-round:has(> input[type="file"]:focus-visible) .ui-btn-label,
.ui-round.is-open .ui-btn-label { max-width: var(--menu); margin-left: var(--s3); }
.ui-round.is-closed .ui-btn-label { max-width: 0; margin-left: 0; }

/* One that always shows its label is a pill, not a circle, so it gets the
   breathing room a circle does not need. */
.ui-round.is-open { padding-inline: calc(var(--ui-round-pad) + var(--s1)); }
/* An icon-only round stays a circle whatever state class a script gives it. */
.ui-round.is-closed { padding-inline: var(--ui-round-pad); }

/* A filled press is the accent, never the ink: one primary per screen (P7). */
.ui-round.is-primary {
  background: var(--accent);
  color: var(--accent-ink);
  border-color: var(--accent);
}
.ui-round.is-primary:hover { background: var(--accent-down); border-color: var(--accent-down); color: var(--accent-ink); }
/* The red outline opens the question; only its answer is filled (PBOX-18, UIC-44). */
.ui-round.is-danger { color: var(--danger); border-color: var(--danger-line); }
.ui-round.is-danger:hover { background: var(--danger-soft); border-color: var(--danger); color: var(--danger); }

/* A press in a dense row draws nothing until the pointer is on it (P20). */
.ui-round.is-quiet { border-color: transparent; background: none; }
.ui-round.is-quiet:hover { border-color: transparent; background: var(--hover); color: var(--ink); }

/* One that cannot be pressed has to look it. A primary that is off keeps the
   ink of a live button otherwise, which is a button lying about itself — and
   the lie is loudest exactly where it matters, on a Save with nothing to save. */
.ui-round:disabled { opacity: .4; cursor: default; }
.ui-round:disabled:hover { border-color: var(--line); color: var(--ink3); }
.ui-round.is-primary:disabled:hover { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.ui-round.is-danger:disabled:hover { background: none; border-color: var(--danger-line); color: var(--danger); }
.ui-round.is-quiet:disabled:hover { background: none; border-color: transparent; }

@media (prefers-reduced-motion: reduce) {
  .ui-round, .ui-round .ui-btn-label { transition: none; }
}

/* ── a pill: small, outlined, inline ─────────────────────────────────────── */

/* The mailbox's pill, everybody's (P8, UIC-42): a hairline on no fill, the accent under the pointer. */
.ui-pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s3);
  height: var(--press);
  padding: 0 var(--s7);
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: none;
  color: var(--ink3);
  font-size: var(--t4);
  font-weight: 400;
  line-height: 1;
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  transition: border-color var(--quick), background var(--quick), color var(--quick);
}
.ui-pill:hover {
  border-color: var(--accent);
  color: var(--accent);
}
.ui-pill svg {
  width: var(--s6);
  height: var(--s6);
  flex: none;
}
.ui-pill-n {
  font-family: var(--mono);
  font-size: var(--t3);
  font-weight: 500;
  color: var(--mute);
}
.ui-pill:hover .ui-pill-n {
  color: inherit;
}
.ui-pill.is-primary {
  border-color: var(--accent);
  background: var(--accent);
  color: var(--accent-ink);
  font-weight: 500;
}
.ui-pill.is-primary:hover {
  border-color: var(--accent-down);
  background: var(--accent-down);
  color: var(--accent-ink);
}
.ui-pill.is-primary .ui-pill-n {
  color: inherit;
}
.ui-pill.is-small {
  height: var(--press-small);
  padding: 0 var(--s6);
}
.ui-pill.is-tall {
  height: var(--press-tall);
  padding: 0 var(--s8);
  font-size: var(--t5);
}
/* The red outline opens the question; only its answer is filled (PBOX-18). */
.ui-pill.is-danger { border-color: var(--danger-line); color: var(--danger); }
.ui-pill.is-danger:hover { border-color: var(--danger); background: var(--danger-soft); color: var(--danger); }
/* Asking to be looked at is the sand, never the red (PBOX-6). */
.ui-pill.is-attn {
  border-color: var(--attn-line);
  background: var(--attn-fill);
  color: var(--warn-ink);
  font-weight: 500;
}
.ui-pill.is-attn:hover { border-color: var(--attn-line); background: var(--warn-bg); color: var(--warn-ink); }
/* On — the filter a list is under, the choice a pill's radio holds — is the accent's wash, never its fill (P7, UIC-43). */
.ui-pill.is-on,
.ui-pill.is-on:hover,
label.ui-pill:has(> input:is([type="radio"], [type="checkbox"]):checked) {
  border-color: transparent;
  background: var(--accent-soft);
  color: var(--accent-text);
  font-weight: 500;
}
.ui-pill.is-on svg { fill: currentColor; }
/* A choice drawn as pills (`ui::pill_choice`): each a label round its radio or its box, which a keyboard still reaches. */
label.ui-pill:has(> input:is([type="radio"], [type="checkbox"])) { position: relative; }
label.ui-pill > input:is([type="radio"], [type="checkbox"]) { position: absolute; inset: 0; margin: 0; opacity: 0; pointer-events: none; }
label.ui-pill:has(> input:is([type="radio"], [type="checkbox"]):focus-visible) { outline: var(--s1) solid var(--accent); outline-offset: var(--s1); }
/* Words in a row that act, with no ring until the pointer is on them. */
.ui-pill.is-quiet { border-color: transparent; }
.ui-pill.is-quiet:hover { border-color: transparent; background: var(--hover); color: var(--ink); }
/* One that cannot be pressed is solid grey whatever its tone: after the tones, and outweighing their hover. */
.ui-pill:disabled,
.ui-pill:is(.is-plain, .is-danger, .is-attn, .is-on, .is-quiet):disabled,
.ui-pill:is(.is-plain, .is-danger, .is-attn, .is-on, .is-quiet):disabled:hover {
  border-color: var(--line);
  background: none;
  color: var(--idle);
  font-weight: 400;
  cursor: default;
}
.ui-pill.is-quiet:disabled,
.ui-pill.is-quiet:disabled:hover { border-color: transparent; }
.ui-pill.is-primary:disabled,
.ui-pill.is-primary:disabled:hover {
  border-color: var(--accent-idle);
  background: var(--accent-idle);
  color: var(--accent-ink);
  cursor: default;
}

/* ── the press that finishes a form ──────────────────────────────────────── */

/* The mailbox's *Add task* (P7, P12): its height a floor, so long words take a second line. */
.ui-submit {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--s4);
  min-height: var(--press-tall);
  margin-left: auto;
  padding: var(--s2) var(--s9);
  border: 1px solid var(--accent);
  border-radius: var(--r-pill);
  background: var(--accent);
  color: var(--accent-ink);
  font-size: var(--t5);
  font-weight: 500;
  line-height: var(--lh3);
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: border-color var(--quick), background var(--quick), color var(--quick);
}
.ui-submit:hover {
  border-color: var(--accent-down);
  background: var(--accent-down);
}
/* The second way of doing the same thing, offered beside the first: the same
   button, not filled. Two filled buttons on one card is two primary actions,
   which is none. */
.ui-submit.is-plain {
  border-color: var(--line);
  background: none;
  color: var(--ink3);
  font-weight: 400;
}
.ui-submit.is-plain:hover {
  border-color: var(--accent);
  background: none;
  color: var(--accent);
}
/* A form whose press deletes asks first; only the answer is filled red (PBOX-18). */
.ui-submit.is-danger {
  border-color: var(--danger-line);
  background: none;
  color: var(--danger);
}
.ui-submit.is-danger:hover {
  border-color: var(--danger);
  background: var(--danger-soft);
}
.ui-submit:disabled,
.ui-submit:disabled:hover {
  border-color: var(--accent-idle);
  background: var(--accent-idle);
  color: var(--accent-ink);
  cursor: default;
}
.ui-submit:is(.is-plain, .is-danger):disabled,
.ui-submit:is(.is-plain, .is-danger):disabled:hover {
  border-color: var(--line);
  background: none;
  color: var(--idle);
}
.ui-submit.is-small { min-height: var(--press); padding: var(--s1) var(--s7); font-size: var(--t4); }
.ui-submit svg {
  width: var(--s7);
  height: var(--s7);
  flex: none;
}
.ui-submit.is-block {
  margin-left: 0;
  width: 100%;
}

/* ── a modal's committing action (KODU-25) ───────────────────────────────── */

/* The question's answer, the tall pill (P8, UIC-44): a long name takes a second line, never off the card. */
.ui-modal {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s4);
  min-height: var(--press-tall);
  padding: var(--s3) var(--s8);
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: none;
  color: var(--ink2);
  font-family: inherit;
  font-size: var(--t5);
  font-weight: 400;
  line-height: var(--lh-body);
  text-align: center;
  overflow-wrap: anywhere;
  cursor: pointer;
  transition: border-color var(--quick), background var(--quick), color var(--quick);
}
.ui-modal:hover {
  border-color: var(--accent);
  color: var(--accent);
}
.ui-modal.is-primary {
  border-color: var(--accent);
  background: var(--accent);
  color: var(--accent-ink);
  font-weight: 500;
}
.ui-modal.is-primary:hover {
  background: var(--accent-down);
  border-color: var(--accent-down);
  color: var(--accent-ink);
}
/* The one red fill (UIC-44): the press that answers a question by deleting.
   The press that *opens* the question is the outline `is-danger` of a round
   or a button; this is the yes. */
.ui-modal.is-danger {
  border-color: var(--danger-fill);
  background: var(--danger-fill);
  color: var(--accent-ink);
  font-weight: 500;
}
.ui-modal.is-danger:hover {
  background: var(--danger-down);
  border-color: var(--danger-down);
  color: var(--accent-ink);
}
.ui-modal:disabled { opacity: .5; cursor: default; }

/* ── words alone ─────────────────────────────────────────────────────────── */

.ui-text-btn {
  color: var(--accent);
  font-size: var(--t5);
  cursor: pointer;
}
.ui-text-btn:hover {
  text-decoration: underline;
  text-underline-offset: var(--s1);
}

/* ── one focus ring on every press (UIC-42) ──────────────────────────────── */

/* The base's ring with a class's weight, so no door's outline replaces it; a field rings its border. */
:is(.ui-btn, .ui-pill, .ui-round, .ui-submit, .ui-modal, .ui-text-btn, .ui-theme):focus-visible {
  outline: var(--s1) solid var(--accent);
  outline-offset: var(--s1);
}
/* A label press wears it while the file input inside has the keyboard. */
label:is(.ui-btn, .ui-pill, .ui-round, .ui-submit):has(> input[type="file"]:focus-visible) {
  outline: var(--s1) solid var(--accent);
  outline-offset: var(--s1);
}

/* ── a thing's acts: a card's answers, a walker's steps (UIC-43, PBOX-13) ── */

/* On a phone each is a finger's target; from 641px it stands at its `Size` again. */
.ui-acts :is(.ui-pill, .ui-btn) { min-height: var(--finger); min-width: var(--finger); }
.ui-acts .ui-round { min-height: var(--finger); min-width: var(--finger); }
@container (min-width: 641px) {
  .ui-acts :is(.ui-pill, .ui-btn) { min-height: auto; min-width: auto; }
  .ui-acts .ui-round { min-height: auto; min-width: var(--ui-round-size); }
}

/* ── a question and its answer, one press apart (UIC-34) ─────────────────── */

/* Folds stacked are one list: a hairline over each, and one under the last; a frame that folds is another `ui-fold`. */
details.ui-fold { display: block; border-top: 1px solid var(--hair); }
details.ui-fold:last-child { border-bottom: 1px solid var(--hair); }
/* The question is the whole row and the press, the mark at its far end. */
.ui-fold-q {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s8);
  padding: var(--s8) 0;
  font-size: var(--t6);
  line-height: var(--lh6);
  font-weight: 500;
  color: var(--ink);
}
.ui-fold-q::-webkit-details-marker { display: none; }
.ui-fold-q:hover { color: var(--accent); }
.ui-fold-q:focus-visible { outline: var(--s1) solid var(--accent); outline-offset: var(--s2); border-radius: var(--r2); }
/* A plus that turns to a cross when the answer is out. */
.ui-fold-mark { flex: none; display: inline-flex; color: var(--mute); transition: transform var(--quick); }
.ui-fold-mark .icon { width: var(--s7); height: var(--s7); }
.ui-fold[open] .ui-fold-mark { transform: rotate(45deg); }
/* The answer in the quiet voice, clear of the mark's column. */
.ui-fold-a {
  margin: 0;
  max-width: var(--prose);
  padding: 0 var(--s12) var(--s8) 0;
  font-size: var(--t5);
  line-height: var(--lh5);
  color: var(--mute);
}

/* ── a group of fields held shut (UI-13) ─────────────────────────────────── */

/* The border is what makes a folded group read as a lid rather than as the
   end of the form: closed, the summary is the only thing on that line. */
.ui-advanced {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--field);
  padding: var(--s4) var(--s5);
}
.ui-advanced > summary {
  display: flex;
  align-items: center;
  gap: var(--s3);
  list-style: none;
  cursor: pointer;
  font-size: var(--t3);
  font-weight: 600;
  color: var(--ink3);
}
.ui-advanced > summary::-webkit-details-marker { display: none; }
.ui-advanced > summary:hover { color: var(--ink); }
.ui-advanced > summary:focus-visible { outline: var(--s1) solid var(--accent); outline-offset: var(--s1); }
/* The arrow points along the fold: right when shut, down when open. */
.ui-advanced-caret { flex: none; width: var(--s4); height: var(--s4); transition: transform var(--unfold); }
.ui-advanced[open] > summary .ui-advanced-caret { transform: rotate(90deg); }
.ui-advanced-body { margin-top: var(--s7); }
.ui-advanced-body > * + * { margin-top: var(--s8); }

@media (prefers-reduced-motion: reduce) {
  .ui-advanced-caret { transition: none; }
}

/* The ⋯ menu is `lists.css` (`ui::more`, UIC-43). */

/* ── one press that hands a page on (UIC-32) ─────────────────────────────── */

/* A fold, so the whole control works with nothing running: shut it is a
   pill, open it is a sheet of ordinary links. Where the browser has a sheet
   of its own the script takes the press and none of this is ever seen. */
.ui-share { position: relative; display: inline-flex; }
/* The pill is the whole press, so the browser's own triangle goes. */
.ui-share > summary { list-style: none; cursor: pointer; }
.ui-share > summary::-webkit-details-marker { display: none; }
/* A disclosure that wears a control is that control: no triangle beside
   it, in any engine. */
summary:is(.ui-pill, .ui-round) { list-style: none; cursor: pointer; }
summary:is(.ui-pill, .ui-round)::-webkit-details-marker { display: none; }
.ui-share-menu {
  position: absolute;
  top: calc(100% + var(--s3));
  right: 0;
  z-index: 40;
  display: flex;
  flex-direction: column;
  min-width: var(--menu);
  max-width: 80vw;
  padding: var(--s2);
  border: 1px solid var(--line);
  border-radius: var(--r5);
  background: var(--surface);
  box-shadow: var(--float);
}
.ui-share-row {
  display: flex;
  align-items: center;
  gap: var(--s5);
  padding: var(--s4) var(--s5);
  border: 0;
  border-radius: var(--r4);
  background: none;
  color: var(--ink2);
  font: inherit;
  font-size: var(--t5);
  text-align: left;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}
.ui-share-row:hover { background: var(--hover); color: var(--ink); }
.ui-share-row[hidden] { display: none; }
.ui-share-ico { flex: none; width: var(--s8); height: var(--s8); color: var(--mute); }
/* Hung from the press's left corner where the press itself is near the left
   edge: a sheet 200 wide hanging from the right corner of a control at the
   start of its own line opens off the screen. */
@media (max-width: 560px) {
  .ui-share-menu { right: auto; left: 0; }
}

/* The controls an answer is chosen with, drawn here for every door (UI-15, UI-36, UIC-42). */

/* ── a switch, and a run of cards answering one question (UI-36) ─────────── */

/* The mailbox's settings card (UIC-42): the words, how it stands, the track. */
.sw {
  /* The hidden box stands inside its card, or focusing it scrolls the frame to where it would be. */
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: var(--s8);
  padding: var(--s8);
  border: 1px solid var(--line);
  border-radius: var(--r4);
  background: var(--surface);
  cursor: pointer;
}
.sw + .sw { margin-top: var(--s4); }
.sw:hover { border-color: var(--accent-line); }
.sw:has(.sw-in:focus-visible) { outline: var(--s1) solid var(--accent); outline-offset: var(--s1); }
.sw.is-locked { cursor: default; opacity: .72; }
.sw.is-locked:hover { border-color: var(--line); }
/* A line of a form or a card's head: the same switch with no box of its own. */
.sw.is-bare { padding: 0; border: 0; background: none; }

/* The box carries the state and the keyboard, hidden but still in the tab order. */
.sw-in {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  clip-path: inset(50%);
  overflow: hidden;
  white-space: nowrap;
}

.sw-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--s3); }
.sw-label { font-size: var(--t5); font-weight: 600; color: var(--ink); }
.sw-note { font-size: var(--t4); line-height: var(--lh-body); color: var(--ink3); }
/* How the answer stands now, a fact the machine keeps (SET-19). */
.sw-stands {
  padding-top: var(--s1);
  font-family: var(--mono);
  font-size: var(--t2);
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--mute);
}

.sw-track {
  flex: none;
  display: flex;
  align-items: center;
  width: var(--switch-w);
  height: var(--switch-h);
  padding: calc((var(--switch-h) - var(--s9)) / 2);
  border-radius: var(--r-pill);
  background: var(--line2);
  transition: background var(--quick);
}
.sw-knob {
  width: var(--s9);
  height: var(--s9);
  border-radius: 50%;
  background: var(--surface);
  box-shadow: var(--knob);
  transition: transform var(--quick);
}
.sw:has(.sw-in:checked) .sw-track { background: var(--accent); }
.sw:has(.sw-in:checked) .sw-knob { transform: translateX(calc(var(--switch-w) - var(--switch-h))); }

/* One of a run, so a tick rather than a track, and the chosen card washed. */
.sw-pick:has(.sw-in:checked) { border-color: var(--accent); background: var(--accent-soft); }
.sw-mark {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--s9);
  height: var(--s9);
  margin-top: var(--s1);
  border: 1px solid var(--line);
  border-radius: 50%;
  background: var(--surface);
  color: var(--accent-ink);
}
.sw-mark svg { width: var(--s5); height: var(--s5); display: none; }
.sw-pick:has(.sw-in:checked) .sw-mark { background: var(--accent); border-color: var(--accent); }
.sw-pick:has(.sw-in:checked) .sw-mark svg { display: block; }

@media (prefers-reduced-motion: reduce) {
  .sw-track, .sw-knob { transition: none; }
}

/* ── the same answer as a segmented row (UI-15, `seg_of`) ────────────────── */

/* The mailbox's pill track (P18, UIC-43): one row, never a silent scroll — cut segments show their ellipsis. */
.seg {
  display: inline-flex;
  flex: 0 1 auto;
  gap: var(--s1);
  min-width: 0;
  max-width: 100%;
  padding: var(--s1);
  overflow: hidden;
  border-radius: var(--r-pill);
  background: var(--hover);
}
.seg-item {
  flex: 0 1 auto;
  display: block;
  min-width: 0;
  height: var(--press-small);
  padding: 0 var(--s4);
  border: 0;
  border-radius: var(--r-pill);
  background: transparent;
  color: var(--ink3);
  font-size: var(--t4);
  line-height: var(--press-small);
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-decoration: none;
  cursor: pointer;
  transition: background var(--quick), color var(--quick);
}
.seg-item:hover { color: var(--ink); }
/* A view named by its drawing (cards, lines): the glyph centred in its segment, the words its name. */
.seg-item:has(> svg) { display: inline-flex; align-items: center; justify-content: center; padding: 0 var(--s5); }
.seg-item > svg { width: var(--s8); height: var(--s8); }
.seg-item:focus-visible { outline-offset: calc(-1 * var(--s1)); }
.seg-item[aria-pressed="true"],
.seg-item[aria-current="page"],
.segf input:checked + .seg-item { background: var(--surface); color: var(--ink); font-weight: 600; box-shadow: var(--lift); }

/* The chips answering a form's question: a label wearing the chip, its radio inside. */
.segf { display: inline-flex; }
.segf-item { flex: 0 1 auto; min-width: 0; display: flex; position: relative; cursor: pointer; }
.segf-item .seg-item { flex: 1 1 auto; }
.segf-item:has(.sw-in:focus-visible) .seg-item { outline: var(--s1) solid var(--accent); outline-offset: calc(-1 * var(--s1)); }

@container (min-width: 641px) {
  .seg-item { padding: 0 var(--s7); }
}

/* ── a list that folds to the chosen row (`ui::select`, P11) ─────────────── */

.choice-field { position: relative; }
.choice-field.has-icon .sel { padding-left: calc(var(--s10) + var(--s4)); }

.sel {
  display: grid;
  gap: 0;
  padding: var(--s3) var(--s5);
  border: 1px solid var(--line);
  border-radius: var(--r3);
  background: var(--surface);
  transition: border-color var(--quick);
}
.sel:hover { border-color: var(--mute); }
.sel:focus-within { border-color: var(--accent-line); }

.sel-multi { max-height: var(--list-max); overflow-y: auto; }

.sel-node {
  visibility: visible;
  transition: max-height var(--unfold), opacity var(--quick), visibility 0s;
}

/* Closed with a choice: every branch without it folds, and `hidden` takes it out of the tab order. */
.sel[data-open="false"]:has(input:checked) .sel-node:not(:has(input:checked)) {
  max-height: 0;
  opacity: 0;
  visibility: hidden;
  transition: max-height var(--unfold), opacity var(--quick), visibility var(--unfold);
}

.sel-opt {
  display: flex;
  align-items: flex-start;
  gap: var(--s4);
  padding: var(--s2) 0;
  font-size: var(--t5);
  line-height: var(--lh3);
  cursor: pointer;
}
.sel-opt:hover .opt-mark { border-color: var(--ink3); }
.sel-opt input { position: absolute; opacity: 0; width: 0; height: 0; }

.opt-mark {
  display: grid;
  place-items: center;
  flex-shrink: 0;
  width: var(--s8);
  height: var(--s8);
  margin-top: var(--s1);
  border: 1px solid var(--mute);
  background: var(--surface);
  transition: background var(--quick), border-color var(--quick);
}
.opt-dot { border-radius: 50%; }
.opt-box { border-radius: var(--r2); }

.opt-mark::after {
  content: "";
  opacity: 0;
  transform: scale(.4);
  transition: opacity var(--quick), transform var(--spring);
}
.opt-dot::after { width: var(--s3); height: var(--s3); border-radius: 50%; background: var(--surface); }
.opt-box::after {
  width: var(--s3);
  height: var(--s5);
  margin-top: calc(-1 * var(--s1));
  border: solid var(--surface);
  border-width: 0 var(--s1) var(--s1) 0;
  transform: rotate(45deg) scale(.4);
}

input:checked + .opt-mark { background: var(--ink); border-color: var(--ink); }
input:checked + .opt-mark::after { opacity: 1; transform: scale(1); }
input:checked + .opt-box::after { transform: rotate(45deg) scale(1); }
input:focus-visible + .opt-mark { outline: var(--s1) solid var(--accent); outline-offset: var(--s1); }

.sel-text { min-width: 0; }
.sel-value { margin-left: var(--s3); font-size: var(--t3); opacity: .35; }

/* Nesting, marked by the line it hangs from. */
.sel-kids {
  margin-left: var(--s4);
  padding-left: var(--s6);
  border-left: 1px dotted var(--line);
}

@media (prefers-reduced-motion: reduce) {
  .sel-node, .opt-mark, .opt-mark::after { transition: none; }
}

/* ── a colour answered by pointing at it (UI-15, `ui::swatches`) ─────────── */

/* The paint is the chip's own `--swatch`; a chip with none is the surface. */
.swatches { display: flex; flex-wrap: wrap; gap: var(--s4); }
.swatch {
  position: relative;
  width: var(--swatch-size);
  height: var(--swatch-size);
  border: var(--s1) solid transparent;
  border-radius: var(--r3);
  outline: 1px solid var(--line2);
  outline-offset: -1px;
  background: var(--swatch, var(--surface));
  cursor: pointer;
}
.swatch-round { border-radius: 50%; }
.swatch:has(input:checked) { border-color: var(--accent); }
.swatch:focus-within { border-color: var(--accent); }
.swatch > input {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  clip-path: inset(50%);
  overflow: hidden;
  white-space: nowrap;
}

/* ── a starting point chosen by its picture (`ui::picker`) ───────────────── */

.picker { display: grid; grid-template-columns: repeat(auto-fit, minmax(var(--tile), 1fr)); gap: var(--s5); }
.pick {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--s3);
  padding: var(--s4);
  border: 1px solid var(--line);
  border-radius: var(--r6);
  background: var(--surface);
  cursor: pointer;
  transition: border-color var(--quick), background var(--quick);
}
/* Out of sight, still in the tab order and still announced. */
.pick-radio {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip-path: inset(50%);
}
.pick:hover { border-color: var(--mute); }
.pick:has(input:checked) { border-color: var(--accent); background: var(--accent-soft); }
.pick:has(input:focus-visible) { outline: var(--s1) solid var(--accent-line); outline-offset: var(--s1); }
.pick-name { font-size: var(--t4); font-weight: 600; }
.pick-meta { margin-top: var(--s4); }

/* The card draws the page it makes: a bar, a hero, a row of cards. */
.pick-plan { display: flex; flex-direction: column; gap: var(--s1); padding: var(--s2); border-radius: var(--r3); background: var(--field); }
.pick-bar { display: flex; align-items: center; gap: var(--s1); }
.pick-dot { width: var(--s2); height: var(--s2); border-radius: 50%; background: var(--ink3); flex: none; }
.pick-nav { height: var(--s1); flex: 1; border-radius: var(--r1); background: var(--line); }
.pick-hero { display: flex; flex-direction: column; align-items: center; gap: var(--s1); padding-block: var(--s2); }
.pick-line { width: 60%; height: var(--s1); border-radius: var(--r1); background: var(--ink3); }
.pick-cta { width: 22%; height: var(--s2); border-radius: var(--r1); background: var(--accent); }
.pick-row { display: flex; gap: var(--s1); }
.pick-card { flex: 1; height: var(--s5); border-radius: var(--r1); background: var(--line); }

/* A prepared look paints its own plan from the card's `--pk-*`, the house's without them. */
.pick-plan.tinted { background: var(--pk-bg, var(--field)); }
.pick-plan.tinted .pick-dot { background: var(--pk-accent, var(--accent)); }
.pick-plan.tinted .pick-nav { background: color-mix(in srgb, var(--pk-ink, var(--ink)) 22%, var(--pk-bg, var(--field))); }
.pick-plan.tinted .pick-line { background: color-mix(in srgb, var(--pk-ink, var(--ink)) 85%, var(--pk-bg, var(--field))); }
.pick-plan.tinted .pick-cta { background: var(--pk-accent, var(--accent)); }
.pick-plan.tinted .pick-card { background: color-mix(in srgb, var(--pk-ink, var(--ink)) 16%, var(--pk-bg, var(--field))); }

/* The surfaces a screen is made of (UIC-11), on the house tokens and defining
   nothing of its own.

   These are the shapes all three applications drew for themselves and each
   named separately — `k-quiet`/`pb-note`/`cn-note`, `k-group`/`cn-set`,
   `k-card`, `k-panel`/`pb-modal` — which is why a screen was still a
   `format!` template: there was nothing here to call. Each rule below is the
   union of the three, taking the mailbox's measure where they disagreed. */

/* ── what the screen says for itself ─────────────────────────────────────── */

.ui-note {
  margin: 0;
  font-size: var(--t4);
  line-height: var(--lh4);
  color: var(--mute);
  text-wrap: pretty;
}

/* News, in a box, in one of three weathers. Amber is the commonest and the
   one worth spelling out: nothing was lost, the form came back with what was
   typed still in it, and red would say otherwise. */
.ui-say {
  margin: 0;
  padding: var(--s5) var(--s7);
  border: 1px solid transparent;
  border-radius: var(--r5);
  font-size: var(--t5);
  line-height: var(--lh5);
  text-wrap: pretty;
}
.ui-say.is-warn {
  border-color: var(--warn-line);
  background: var(--warn-bg);
  color: var(--warn-ink);
}
.ui-say.is-wrong {
  border-color: var(--danger-line);
  background: var(--danger-soft);
  color: var(--danger);
}
.ui-say.is-done {
  border-color: var(--star-soft);
  background: var(--ok-bg);
  color: var(--ok-ink);
}

/* ── what the screen says at its foot (UIC-24) ───────────────────────────── */

/* Report a problem (ISS-8): the box stands at the page's bottom-left corner,
   over every surface and under the confirm dialog; beside a rail standing
   down the left, where the face that opened it is. Shut until it is asked for. */
.ui-report { position: fixed; left: var(--s8); bottom: var(--s8); z-index: 120; }
@container (min-width: 641px) {
  body:has(.ui-rail-nav) .ui-report { left: calc(var(--rail-col) + var(--s6)); }
}
.ui-report-box {
  display: flex; flex-direction: column; gap: var(--s5);
  width: min(var(--report), calc(100vw - 2 * var(--s8))); padding: var(--s7);
  border: 1px solid var(--line); border-radius: var(--r7); background: var(--surface); box-shadow: var(--shadow);
}
.ui-report-box[hidden] { display: none; }

/* The page's own right-click menu (UIC-35): at the pointer, over the page and
   under the report box it opens. */
.ui-context {
  position: fixed; z-index: 115; min-width: var(--menu); padding: var(--s3);
  display: flex; flex-direction: column;
  border: 1px solid var(--line); border-radius: var(--r6); background: var(--surface); box-shadow: var(--shadow);
}
.ui-context[hidden] { display: none; }
.ui-context-item {
  padding: var(--s4) var(--s5); border: 0; border-radius: var(--r4); background: none;
  font: inherit; font-size: var(--t5); color: var(--ink); text-align: left; cursor: pointer;
}
.ui-context-item:hover, .ui-context-item:focus-visible { background: var(--chip); outline: none; }
.ui-context-hint {
  margin: var(--s2) 0 0; padding: var(--s3) var(--s5) var(--s2); border-top: 1px solid var(--hair);
  font-size: var(--t3); color: var(--mute);
}

/* Where the notices stand: fixed at the foot wherever the page drew them,
   clear of a phone's safe area, over every surface (the overlay is 110, the
   drawer 130). The strip takes the pointer; the space around it does not. */
.ui-notices {
  position: fixed; left: 0; right: 0; z-index: 140;
  bottom: max(var(--s9), calc(env(safe-area-inset-bottom) + var(--s9)));
  display: flex; flex-direction: column; align-items: center; gap: var(--s4);
  padding: 0 var(--gutter);
  pointer-events: none;
}

/* The mailbox's strip (PBOX-25), now everybody's: the dark solid rather than
   the red, because it is a thing that happened and not a thing to fix here —
   the thing to fix is marked where it is. The dot says which weather. */
.ui-notice {
  pointer-events: auto;
  display: flex; align-items: flex-start; gap: var(--s6);
  width: min(var(--notice), 100%);
  padding: var(--s6) var(--s6) var(--s6) var(--s8);
  border-radius: var(--r5);
  background: var(--solid);
  color: var(--solid-ink);
  box-shadow: var(--sheet);
  animation: ui-notice-in var(--arrive);
}
.ui-notice.is-leaving { animation: ui-notice-out var(--leave) forwards; }
.ui-notice-dot {
  flex: none; width: var(--s5); height: var(--s5); border-radius: 50%;
  transform: translateY(var(--s3));
  background: var(--solid-ink); opacity: .45;
}
.ui-notice.is-wrong .ui-notice-dot { background: var(--danger-fill); opacity: 1; }
.ui-notice.is-warn .ui-notice-dot { background: var(--warn-dot); opacity: 1; }
.ui-notice.is-done .ui-notice-dot { background: var(--star); opacity: 1; }
.ui-notice-body { flex: 1; min-width: 0; }
.ui-notice-said, .ui-notice-more {
  margin: 0;
  font-size: var(--t5);
  line-height: var(--lh5);
  text-wrap: pretty;
}
.ui-notice-said { font-weight: 600; }
.ui-notice-more { opacity: .78; }
.ui-notice-close {
  flex: none; width: var(--s10); height: var(--s10); padding: 0; margin: 0;
  display: inline-flex; align-items: center; justify-content: center;
  border: 0; border-radius: 50%; background: none;
  color: inherit; font: inherit; font-size: var(--t7); line-height: 1;
  opacity: .7; cursor: pointer;
  transform: translateY(calc(var(--s1) * -1));
}
.ui-notice-close:hover { opacity: 1; }
.ui-notice-close:focus-visible { outline: var(--s1) solid var(--accent); outline-offset: var(--s1); }
@keyframes ui-notice-in {
  from { opacity: 0; transform: translateY(var(--s4)); }
  to { opacity: 1; transform: none; }
}
@keyframes ui-notice-out {
  to { opacity: 0; transform: translateY(var(--s3)); }
}
@media (prefers-reduced-motion: reduce) {
  .ui-notice, .ui-notice.is-leaving { animation: none; }
}

/* ── who somebody is (UI-19) ─────────────────────────────────────────────── */

/* Initials on the address's hue (`--hue` from `ui::face`), lit by the scheme, a press tall. */
.ui-face {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: var(--press);
  height: var(--press);
  border-radius: 50%;
  background: oklch(var(--av-bg) var(--hue));
  color: oklch(var(--av-fg) var(--hue));
  font-size: var(--t3);
  font-weight: 600;
  line-height: 1;
  user-select: none;
  position: relative;
  overflow: hidden;
  box-sizing: border-box;
  text-transform: uppercase;
}
/* One step per place a person stands; the letters a step under the disc. */
.ui-face.is-tiny { width: var(--s9); height: var(--s9); font-size: var(--t1); }
.ui-face.is-small { width: var(--s10); height: var(--s10); font-size: var(--t1); }
.ui-face.is-mid { width: var(--back); height: var(--back); font-size: var(--t4); }
.ui-face.is-big { width: var(--s11); height: var(--s11); font-size: var(--t4); }
.ui-face.is-row { width: var(--s12); height: var(--s12); font-size: var(--t5); }
.ui-face.is-portrait { width: calc(var(--s13) * 2); height: calc(var(--s13) * 2); font-size: var(--t9); }
/* Overlapping faces keep a ring of the ground they stand on between them (`--face-ring`, the surface unless a column says). */
.ui-face.is-ring { border: var(--s1) solid var(--face-ring, var(--surface)); }
.ui-faces.is-crowd { display: inline-flex; flex: none; align-items: center; }
.ui-faces.is-crowd > .ui-face + .ui-face { margin-left: calc(-1 * var(--s4)); }
/* A photograph covers the letters, which stay under it for when it does not load. */
/* A third of the way down, not the middle: a portrait taller than the circle keeps the face and loses the chest (KODU-126). */
.ui-face-photo { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: 50% 33%; border-radius: 50%; }
/* A group on a row: two small faces at opposite corners of one row face's room. */
.ui-faces.is-pair { position: relative; flex: none; width: var(--s12); height: var(--s12); }
.ui-faces.is-pair > .ui-face:first-child { position: absolute; top: 0; left: 0; }
.ui-faces.is-pair > .ui-face:last-child { position: absolute; right: 0; bottom: 0; }

/* ── one word about the thing beside it ──────────────────────────────────── */

.ui-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--s3);
  padding: var(--s1) var(--s4);
  border-radius: var(--r4);
  background: var(--chip);
  color: var(--ink3);
  font-size: var(--t3);
  font-weight: 600;
  white-space: nowrap;
}
.ui-chip.is-live { background: var(--ok-bg); color: var(--ok-ink); }
.ui-chip.is-held { background: var(--chip); color: var(--mute); }
.ui-chip.is-owed { background: var(--warn-bg); color: var(--warn-ink); }
/* Late, refused, not answering: the red's wash, never its fill (the mailbox's `is-late`). */
.ui-chip.is-late { background: var(--danger-wash); color: var(--danger-deep); }
/* Set for a day and not past it: the mailbox's due date, in the accent's wash. */
.ui-chip.is-due { background: var(--accent-soft); color: var(--accent-text); }
/* How much is not yet seen: a count in the accent's fill, as round as its one figure allows. */
.ui-chip.is-new { justify-content: center; min-width: var(--s9); padding: var(--s1) var(--s3); background: var(--accent); color: var(--accent-ink); font-variant-numeric: tabular-nums; }
/* A word somebody chose rather than a state the machine printed: the mono, on the hover's grey (P14). */
.ui-chip.is-tag { font-family: var(--mono); font-size: var(--t2); font-weight: 400; background: var(--hover); color: var(--ink3); }
/* Who somebody is: their face before the words, in the reading weight (a recipient). */
.ui-chip.is-who { padding-left: var(--s1); font-size: var(--t4); font-weight: 400; color: var(--ink2); background: var(--field); }
/* A chip that fills its line, its words ending in an ellipsis where the line is shorter (a task in a calendar's cell). */
.ui-chip.is-line { display: block; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
a.ui-chip { text-decoration: none; }
a.ui-chip:hover { color: var(--accent-down); }
/* A filter's chip is never wider than its row: its words end in an ellipsis and the × stays on the screen (UIC-51). */
.ui-chip:has(> .ui-chip-off) { max-width: 100%; }
.ui-chip-said { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
/* The × that takes a filter off, a round inside the chip. */
.ui-chip-off {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--s8);
  height: var(--s8);
  margin-right: calc(-1 * var(--s2));
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  color: inherit;
  font-size: var(--t5);
  line-height: 1;
  text-decoration: none;
  cursor: pointer;
}
.ui-chip-off:hover { background: var(--accent-soft); }
/* A status on a press is pressed where it is read; one that discloses what it counts waits until it is live. */
button.ui-chip:hover { text-decoration: underline; text-underline-offset: var(--s1); }
button.ui-chip[aria-expanded]:not(.is-live) { cursor: default; text-decoration: none; }

/* ── a run of controls under one label ───────────────────────────────────── */

/* A column, because a form is filled in in order, and a measure rather than
   the full width, because a line of text nobody can follow to the end is not
   a form anybody finishes. */
.ui-group {
  display: flex;
  flex-direction: column;
  gap: var(--s8);
  max-width: var(--group);
}
.ui-group > .ui-label {
  margin: 0;
}

/* ── a surface ───────────────────────────────────────────────────────────── */

.ui-card {
  padding: clamp(var(--s8), 1.4vw, var(--s9));
  border: 1px solid var(--line);
  border-radius: var(--r7);
  background: var(--surface);
}

/* ── a detail beside what is open, or a record's form (UI-8, UIC-43) ───────── */

/* `ui::drawer` and `ui::panel`, in the mailbox's look: what it is about stays
   in sight behind it under a light veil, and it slides in from the right. Here
   and not in Platform's sheet, so a door that loads only the tier has it. */
.drawer {
  position: fixed; inset: 0; z-index: 120;
  display: flex; justify-content: flex-end;
  background: var(--veil);
  animation: drawer-backdrop-in var(--exit);
}
.drawer-panel {
  width: min(var(--drawer), 100%); height: 100%;
  display: flex; flex-direction: column;
  background: var(--surface); border-left: 1px solid var(--line); box-shadow: var(--slide);
  animation: drawer-in var(--enter);
}
@keyframes drawer-backdrop-in { from { opacity: 0; } }
@keyframes drawer-backdrop-out { to { opacity: 0; } }
@keyframes drawer-in { from { transform: translateX(var(--s10)); opacity: 0; } }
@keyframes drawer-out { to { transform: translateX(var(--s10)); opacity: 0; } }
.drawer.is-closing { animation: drawer-backdrop-out var(--exit) forwards; pointer-events: none; }
.drawer.is-closing .drawer-panel { animation: drawer-out var(--exit) forwards; }
@media (prefers-reduced-motion: reduce) {
  .drawer, .drawer-panel, .drawer.is-closing, .drawer.is-closing .drawer-panel { animation: none; }
}
.drawer-head {
  flex: none;
  display: flex; align-items: center; gap: var(--s6);
  padding: var(--s9) var(--s10) var(--s8);
  border-bottom: 1px solid var(--line);
}
.drawer-head strong {
  font-family: var(--serif); font-size: var(--t8); font-weight: 500; line-height: var(--lh8);
  letter-spacing: -0.015em; color: var(--ink); overflow-wrap: anywhere;
}
.drawer-body { flex: 1; min-height: 0; overflow-y: auto; padding: var(--s9) var(--s10); }
/* A drawer's or a record's form stands its parts one under the other, a step apart (UI-20). */
:is(.drawer-body, .rec) { display: flex; flex-direction: column; gap: var(--s8); }
/* What a refused save says, at the form's head (UIC-24). */
.drawer-alert {
  padding: var(--s5) var(--s7);
  border-radius: var(--r4);
  background: var(--danger-soft);
  color: var(--danger);
  font-size: var(--t4);
}
.drawer-alert a { color: inherit; font-weight: 600; text-decoration: underline; text-underline-offset: .2em; }
/* A record's staged pictures (UI-20): the strip, a picture with its red ×, the first one's cover tag. */
.ui-media-strip { display: flex; flex-wrap: wrap; gap: var(--s5); margin-block: var(--s5); }
.ui-thumb { position: relative; flex: none; width: calc(var(--s13) + var(--s10)); height: calc(var(--s13) + var(--s10)); }
.ui-thumb img { display: block; width: 100%; height: 100%; object-fit: cover; border-radius: var(--r4); background: var(--field); }
.ui-thumb > .ui-round { position: absolute; top: var(--s2); right: var(--s2); }
.ui-thumb-cover {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: var(--s1) 0;
  border-radius: 0 0 var(--r4) var(--r4);
  background: var(--stage-veil);
  color: var(--stage-ink);
  font-size: var(--t1);
  letter-spacing: .06em;
  text-align: center;
  text-transform: uppercase;
}
.drawer-foot {
  flex: none;
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--s5);
  padding: var(--s8) var(--s10) var(--s9);
  border-top: 1px solid var(--hair);
}
/* Its acts stand as a record's head's do (UI-20): Delete, then the commit last, at the right; a finger tall on a phone (`ui-acts`). */
.drawer-actions { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: var(--s4); }
.drawer-status { font-size: var(--t3); color: var(--mute); }
.drawer-status.is-saved { color: var(--star); }
/* Settings with an endpoint of their own, below the form rather than in it. */
.drawer-extra { border-top: 1px solid var(--line); padding: var(--s9) var(--s10); background: var(--field); }
/* The panel is the page's one live surface while it is open: the page behind it does not scroll. */
body.drawer-open { overflow: hidden; }

/* ── the surface a whole job sits on ─────────────────────────────────────── */

/* UI-14: `ui::overlay`. The lightbox is one of these too — it adds a stage
   and a zoom, not a way of covering the page. Here in the tier and not in
   any one application's sheet, because the components that wear it are the
   tier's: until 2026-09-08 these rules lived in Platform's theme sheet,
   which only the console loads, and the question `ui::confirm` asks stood
   unstyled at the foot of the mailbox's document, off the screen — a press
   that did nothing anybody could see (LLM-32). */
.overlay {
  position: fixed; inset: 0; z-index: 110;
  background: var(--surface);
  overflow-y: auto;
  overscroll-behavior: contain;
}
.overlay-head {
  position: sticky; top: 0; z-index: 1;
  display: flex; align-items: center; gap: var(--s8);
  padding: var(--s8) var(--s10);
  background: var(--surface); border-bottom: 1px solid var(--line);
}
.overlay-body { padding: var(--s10); }
/* One scrollbar, one wheel: the page behind stays where it was. */
body.overlay-open { overflow: hidden; }

/* UI-22, UIC-44: `ui::dialog` — the question a press asks, and a job small
   enough for one card. The mailbox's delete-task card: a card over a dimmed
   page rather than the whole surface, because the page behind is the thing
   being decided about. Over the drawer's 120 and the dock's 60 — one of the
   things it asks about is a drawer being closed — and under the strip. */
.ui-dialog {
  position: fixed; inset: 0; z-index: 130;
  display: flex; align-items: safe center; justify-content: center;
  padding: var(--s8);
  background: var(--scrim);
  overflow-y: auto;
  overscroll-behavior: contain;
}
/* The whole glass, whatever column it is drawn in: a page that is the
   question stands in a pane whose `> *` caps and centres its children, and
   that must not make the veil a column too. */
.ui-dialog[role="dialog"] { width: auto; max-width: none; margin: 0; }
.ui-dialog-card {
  display: flex; flex-direction: column; gap: var(--s7);
  width: min(var(--dialog), 100%);
  padding: var(--s10);
  border-radius: var(--r6);
  background: var(--surface);
  box-shadow: var(--sheet);
}
.ui-dialog-card.is-wide { width: min(var(--dialog-wide), 100%); }
/* A card with a way out on every step wears it beside its title. */
.ui-dialog-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--s5); }
/* A long address or a file's name breaks inside the card (UIC-44). */
.ui-dialog-title {
  margin: 0;
  font-family: var(--serif); font-size: var(--t8); line-height: var(--lh8); font-weight: 500;
  color: var(--ink);
  overflow-wrap: anywhere;
}
.ui-dialog-says { margin: 0; font-size: var(--t5); line-height: var(--lh6); color: var(--ink3); overflow-wrap: anywhere; }
/* The answers, the safe one first. A phone stacks them across the card, so
   neither is ever pushed off it; a desk sets them side by side at the right.
   Each is the tier's tall pill (`.ui-modal`), focus ring and all. */
.ui-dialog-acts {
  display: flex;
  flex-direction: column;
  gap: var(--s4);
}
/* Two that do not fit one row take two, each whole (UIC-44). */
@container (min-width: 641px) {
  .ui-dialog-acts { flex-direction: row; flex-wrap: wrap; justify-content: flex-end; }
  /* An action that is not one of the answers — adding a tag — stands apart. */
  .ui-dialog-acts > .is-away { margin-right: auto; }
}
/* Docked (UIC-43): at the foot of what it is about, no veil, the thing live beside it. */
.ui-dialog.is-docked[role="dialog"] {
  position: absolute; inset: auto var(--s4) var(--s4) var(--s4); z-index: 60;
  display: block; max-height: 60%; padding: 0;
  border-radius: var(--r6); background: none; overflow: auto;
}
/* Its paint is its own: a pinned row over a live canvas is otherwise painted again where it is not. */
.ui-dialog.is-docked .ui-dialog-card { width: auto; gap: var(--s5); padding: var(--s7) var(--s8); contain: paint; }
/* Three fifths of the thing on any width, so its own head stays in reach; the title stays in view while the rest scrolls,
   and on a desk, where the answers are one row, they do too. */
.ui-dialog.is-docked .ui-dialog-head { position: sticky; top: 0; z-index: 1; background: var(--surface); }
@container (min-width: 641px) {
  .ui-dialog.is-docked[role="dialog"] {
    right: auto; left: var(--s6); bottom: var(--s6);
    width: min(var(--dialog-wide), calc(100% - var(--s12)));
  }
  .ui-dialog.is-docked .ui-dialog-acts {
    position: sticky; bottom: 0; z-index: 1;
    margin-bottom: calc(-1 * var(--s7)); padding: var(--s4) 0 var(--s7); background: var(--surface);
  }
}

/* ── the card a whole screen is filled in on ─────────────────────────────── */

/* `nowrap` is load-bearing: the moment a sheet gives this a height, a
   wrapping column folds its tail off the right-hand edge. */
.ui-form {
  display: flex;
  flex-direction: column;
  flex-wrap: nowrap;
  align-items: stretch;
  gap: var(--s9);
  margin: 0 auto;
  padding: clamp(var(--s8), 1.4vw, var(--s9));
  border: 1px solid var(--line);
  border-radius: var(--r7);
  background: var(--surface);
}

.ui-form-head {
  display: flex;
  align-items: center;
  gap: var(--s6);
}
/* The heading takes the room and the way out is pushed to the far edge. */
.ui-form-head > .ui-h2 { flex: 1; min-width: 0; }

/* The press stands on a line of its own under a rule, with whatever the form
   has to say about itself opposite it. */
.ui-form-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--s6);
  padding-top: var(--s8);
  border-top: 1px solid var(--hair);
}
.ui-form-aside {
  font-size: var(--t4);
  color: var(--mute);
  text-wrap: pretty;
}

/* Two or three fields that belong to one fact, sharing a line and going back
   under each other where there is no room. */
.ui-field-row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: var(--s5);
}
/* `min-width: 0` is not decoration: without it one long unbreakable value —
   a pasted URL, an IBAN — sets the field's floor and pushes its neighbour off
   the row. Kodu's `.k-row` learned this the hard way and the tier inherits
   the lesson. */
.ui-field-row > .ui-field { flex: 1 1 calc(6 * var(--s11)); min-width: 0; }

/* ── headings, at the house sizes ────────────────────────────────────────── */

.ui-h1 {
  margin: 0;
  font-family: var(--serif);
  font-size: var(--t8);
  line-height: var(--lh8);
  font-weight: 500;
  color: var(--ink);
}
.ui-h2 {
  margin: 0;
  font-family: var(--serif);
  font-size: var(--t7);
  line-height: var(--lh7);
  font-weight: 500;
  color: var(--ink);
}

/* The arrangements (UIC-6, UI-18), on the house tokens and defining no colour
   and no length of its own.

   The frame fills the browser and does not scroll: `html` and `body` stay put
   and each column scrolls itself. That is the one thing the mailbox, the
   console and the portal already agreed on and each had written out
   separately.

   **Which columns a screen has is the application's; how wide each is, the
   tier's.** A column is as wide as what it is (UIC-38): the rail
   `--rail-col`, the list `--list-col`, the list of what its chosen row holds
   `--sublist-col`, the part of the thing beside it `--side-col`, and the thing
   itself takes the rest. An application sheet writes no track and no step. */

/* The page is the container (UIC-23): every question about width — an
   application's own queries, the layer's `d-` twins — is asked of the
   body's own width and not the window's, so a page narrowed by the dock
   (UIC-13) is a phone to everything on it. */
body { container-type: inline-size; }

.ui-frame {
  display: flex;
  width: 100%;
  height: 100dvh;
  min-height: 0;
  overflow: hidden;
  position: relative;
  background: var(--surface);
}
.ui-frame > .ui-rail { flex: none; width: var(--rail-col); }
.ui-frame > .ui-list { flex: none; width: var(--list-col); }
.ui-frame > .ui-sublist { flex: none; width: var(--sublist-col); }
.ui-frame > .ui-pane { flex: 1 1 0; }
.ui-frame > .ui-props { flex: none; width: var(--side-col); }
/* What a column and a pane hold stands in from their edges a thumb's width on a phone, the heads' own inset on a desk. */
@container (min-width: 641px) {
  .ui-frame { --list-inset: var(--s9); --pane-inset: var(--s10); }
}

/* Every column is a flex column that can shrink: without the two `min-*`
   zeroes a long word in one of them widens the track and pushes the others
   off the screen, which is the bug every one of these three surfaces has had
   at least once. */
.ui-col {
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.ui-rail {
  background: var(--rail);
  border-right: 1px solid var(--line);
  /* Visible, not hidden: a rail holds popovers that must be allowed out of
     it, and it is narrow enough never to need to scroll sideways. */
  overflow: visible;
}

/* The list, and the list of what its chosen row holds — the mailbox's threads of a conversation. */
.ui-list, .ui-sublist {
  background: var(--surface);
  border-right: 1px solid var(--line);
  overflow-y: auto;
}

/* A list column's head and rows are `lists.css` (UIC-43). */

.ui-pane {
  background: var(--surface);
  overflow-y: auto;
}

/* The fourth column: what is chosen inside the pane, when that is a different
   thing from what the pane is about. On the far side, so the reading goes
   rail → list → the thing → the part of it. */
.ui-props {
  background: var(--surface);
  border-left: 1px solid var(--line);
  overflow-y: auto;
}

/* Below the wide desk a frame holds the rail and two columns (UIC-38). One with three names the
   column that steps out (`data-narrow`): the list once something it holds is open, the thing while
   nothing is, the part of the thing while the list is chosen from; a sublist takes the list's place
   or the thing's room. The way to a list stepped out (`is-to-list`) stands there and on a phone. */
@container (min-width: 641px) {
  .ui-fold .is-to-list { display: none; }
}
@container (min-width: 641px) and (max-width: 1080px) {
  .ui-fold[data-narrow="list"] > .ui-list,
  .ui-fold[data-narrow="pane"] > .ui-pane,
  .ui-fold[data-narrow="props"] > .ui-props { display: none; }
  .ui-fold[data-narrow="list"] > .ui-sublist { width: var(--sublist-narrow); }
  .ui-fold[data-narrow="pane"] > .ui-sublist { flex: 1 1 0; }
  .ui-fold[data-narrow="list"] .is-to-list { display: inline-flex; }
  /* A thing beside its list is narrow here: its head's words take their own row under the title, as on a phone. */
  .ui-fold > .ui-list ~ .ui-pane .ui-pane-acts:has(> :is(.ui-pill, .ui-btn, .ui-submit)) {
    grid-row: auto;
    grid-column: 1 / -1;
    flex-wrap: wrap;
    margin-left: 0;
  }
}

/* A frame that folds (`ui-fold`, UIC-42): on a phone the column its `data-phone` names fills the screen and the rail lies down under it, reversed so the reading order keeps the rail first. Where two things stand side by side, the later — opened from the first — is the screen; the part chosen inside the thing rises from the foot as a sheet. */
@container (max-width: 640px) {
  .ui-fold[data-phone] { display: flex; flex-direction: column-reverse; }
  .ui-fold > .ui-col { width: auto; }
  .ui-fold > .ui-col:not(.ui-rail) { flex: 1; border-right: 0; }
  .ui-fold[data-phone="list"] > .ui-col:not(.ui-rail, .ui-list),
  .ui-fold[data-phone="sublist"] > .ui-col:not(.ui-rail, .ui-sublist) { display: none; }
  .ui-fold[data-phone="pane"] > .ui-list { display: none; }
  .ui-fold[data-phone="pane"] > .ui-sublist,
  .ui-fold[data-phone="pane"] > .ui-pane:has(~ .ui-pane) { display: none; }
  .ui-fold > .ui-props {
    position: fixed;
    inset: auto 0 0 0;
    z-index: 30;
    max-height: var(--sheet-rise);
    border-left: 0;
    border-top: 1px solid var(--line);
    border-radius: var(--r6) var(--r6) 0 0;
    box-shadow: var(--rise);
  }
  /* A thing that is read (`data-reading`: a letter open in the mailbox) is the whole screen; the rail waits on the list it came from, and the pane's ring is the way back. */
  .ui-fold[data-reading] > .ui-rail { display: none; }
  /* A column scrolls as one: a list's head and its search leave with its rows and are there again at the top. */
  .ui-fold > .ui-col > .ui-list-rows { flex: none; min-height: auto; overflow-y: visible; }
  /* While a column scrolls down the bar steps under the foot, and comes back the moment it scrolls up (`TUCK_SCRIPT`). */
  .ui-fold > .ui-rail { transition: margin-bottom var(--unfold); }
  .ui-fold > .ui-rail.is-tucked { margin-bottom: calc(-1 * var(--rail-h, 0px)); }
  /* A page ends with room after its last thing, so the last row is read clear of the foot and of the bar (UIC-51). */
  .ui-fold[data-phone]:not([data-still]) > .ui-col:not(.ui-rail)::after { content: ""; flex: none; height: var(--page-end); }
}

/* A phone's page scrolls as the document (UIC-51): a browser takes its own bars away only while the document scrolls, and a frame of the window whose columns scroll themselves kept Safari's toolbar on the screen for good. So a folded frame is as tall as what it shows; the bar rides the foot and the pane's head the top, and both step aside as the browser's do (`TUCK_SCRIPT`). A screen that is the screen — a map, a picture, a chat over its composer — says `data-still` and keeps the window's frame. The device's width asks: a desk the dock narrows keeps its columns. */
@media (max-width: 640px) {
  html:has(.ui-fold[data-phone]:not([data-still])),
  html:has(.ui-fold[data-phone]:not([data-still])) > body { height: auto; overflow: visible; }
  .ui-fold[data-phone]:not([data-still]) { height: auto; min-height: 100dvh; min-width: 0; overflow: visible; }
  .ui-fold[data-phone]:not([data-still]) > .ui-col:not(.ui-rail) { overflow: visible; overflow-x: clip; }
  .ui-fold[data-phone]:not([data-still]) > .ui-rail { position: sticky; bottom: 0; z-index: 20; transition: transform var(--unfold); }
  .ui-fold[data-phone]:not([data-still]) > .ui-rail.is-tucked { margin-bottom: 0; transform: translateY(100%); }
  /* A sheet the frame lays over itself (`ui-over`, the mailbox's composer) is the window's, its head and its press on the screen however far down the page is. */
  .ui-fold[data-phone]:not([data-still]) > .ui-over { position: fixed; }
}

/* The part of a pane that scrolls under its head on a desk. On a phone the pane scrolls as one, so what stands over the words — the head, a search — leaves with them and the words have the screen. */
.ui-pane-scroll { flex: 1; min-height: 0; overflow-y: auto; }
@container (max-width: 640px) {
  .ui-pane-scroll { flex: none; min-height: auto; overflow-y: visible; }
}

/* ── a thing and a part of it beside it (`layouts::sided`, UIC-38) ── */

/* The side keeps `--side-col` while the thing keeps `--main-least`; once the pane holds less the side
   stands under the thing, a hairline over it, and the two scroll as one. */
.ui-sided { flex: 1; min-height: 0; display: flex; flex-wrap: wrap; overflow-y: auto; }
.ui-sided-main {
  flex: 999 1 var(--main-least);
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--s10);
  padding: var(--s8) var(--s7) var(--s10);
}
.ui-sided-main > * { max-width: var(--sheet-col); }
.ui-sided-side {
  flex: 1 1 var(--side-col);
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--s9);
  margin: -1px 0 0 -1px;
  padding: var(--s10) var(--s9);
  border-top: 1px solid var(--hair);
  border-left: 1px solid var(--hair);
  background: var(--mid);
}
@container (min-width: 641px) {
  .ui-sided-main { padding: var(--s10) var(--s10) var(--s13); }
}

/* ── a page that is read or filled in (UIC-41): its band over one centred column ── */

.ui-reading { display: flex; flex-direction: column; min-width: 0; }
.ui-reading[data-measure="prose"] { --read: var(--prose); }
.ui-reading[data-measure="wide"] { --read: var(--measure); }
.ui-reading-body { padding: clamp(var(--s8), 3vw, var(--s10)) var(--gutter) var(--s13); }
/* The column the band's title stands over, whatever its children say about their own margins. */
.ui-reading-col {
  display: flex;
  flex-direction: column;
  gap: var(--s10);
  width: 100%;
  min-width: 0;
  max-width: var(--read);
  margin-inline: auto;
}
/* A card filled in on a reading page is the column: its edges are the title's, not its content's. */
.ui-reading-col > .ui-form { margin-inline: 0; }

/* A working surface's list and the thing open beside it (UIC-43), phone first: the list's head,
   its rows, its caption, the ⋯, what an empty one says, and the pane's head — the mailbox's,
   every door's. The desk is the container rules at the foot of each part. */

/* ── the list column's head ──────────────────────────────────────────────── */

.ui-list-head {
  flex: none;
  display: flex;
  flex-direction: column;
  gap: var(--s6);
  padding: var(--s7) var(--s7) var(--s5);
}
/* The title asks no room of its own before it wraps, and grows to its words: the + stays beside it, the ⋯ at the end. */
.ui-list-head-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s5) var(--s3); min-width: 0; }
.ui-list-title {
  flex: 1 1 0;
  min-width: 0;
  max-width: max-content;
  margin: 0;
  font-family: var(--serif);
  font-size: var(--t9);
  font-weight: 500;
  line-height: var(--lh9);
  letter-spacing: -0.015em;
  color: var(--ink);
  overflow-wrap: anywhere;
}
.ui-list-acts { position: relative; flex: none; display: flex; align-items: center; gap: var(--s2); margin-left: auto; }
/* Words take a row of their own under the title on a phone, a finger tall, as a page head's do. */
.ui-list-acts:has(> :is(.ui-pill, .ui-btn, .ui-text-btn)) { order: 1; flex: 1 1 100%; flex-wrap: wrap; gap: var(--s4); margin-left: 0; }
.ui-list-acts :is(.ui-pill, .ui-btn) { min-height: var(--finger); }
/* The chip the list is narrowed by is as wide as its words. */
.ui-list-head > .ui-chip { align-self: flex-start; }
/* What the list is of is a desk's: a phone gives its rows the room (UIC-51). */
.ui-list-lede { display: none; }
/* The search takes its row, up to a search's measure. */
.ui-list-tools { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s4); min-width: 0; }
.ui-list-tools > .ui-find { flex: 1 1 var(--list-max); min-width: 0; max-width: var(--find); }
/* The views keep the title's row, at its end, whether or not a search stands under it: they never move under the pointer. */
.ui-list-head-row > .seg { margin-left: auto; }
.ui-list-head-row > .seg + .ui-list-acts { margin-left: 0; }
/* A board's head stands on the board's own gutter; a hairline closes it, over its caption where it has one. */
.ui-list-head.is-board { padding: 0 0 var(--s4); gap: var(--s8); }
.ui-list-head.is-board > .ui-caption-row { padding-top: var(--s8); border-top: 1px solid var(--line); }
.ui-list-head.is-board:not(:has(> .ui-caption-row)) { padding-bottom: var(--s8); border-bottom: 1px solid var(--line); margin-bottom: var(--s8); }

/* What the one + makes, under it while the pointer or the keyboard is on it. */
.ui-tipped { position: relative; display: inline-flex; flex: none; }
.ui-tip {
  display: none;
  position: absolute;
  top: calc(100% + var(--s3));
  right: calc(-1 * var(--s3));
  z-index: 30;
  width: max-content;
  max-width: var(--list-max);
  padding: var(--s5) var(--s6);
  border-radius: var(--r3);
  background: var(--solid);
  color: var(--solid-ink);
  font-size: var(--t3);
  font-weight: 400;
  line-height: var(--lh6);
  box-shadow: var(--tip);
  pointer-events: none;
}
.ui-tipped:hover > .ui-tip, .ui-tipped:focus-within > .ui-tip { display: block; }
/* It opens leftward, into the room, from the row's end where a + stands; beside a list's title, rightward. */
.ui-list-head-row > .ui-tipped > .ui-tip { right: auto; left: calc(-1 * var(--s3)); }
/* A tip a press opens and shuts, a phone having no hover (the address a name wrote from): rightward from the line's start. */
.ui-tipped.is-press > .ui-tip { right: auto; left: 0; overflow-wrap: anywhere; }
.ui-tipped.is-press:is(:hover, :focus-within) > .ui-tip { display: none; }
.ui-tipped.is-press.is-open > .ui-tip { display: block; }

/* ── a caption: a group, a key, a machine fact (P22) ─────────────────────── */

.ui-caption {
  min-width: 0;
  font-family: var(--mono);
  font-size: var(--t2);
  line-height: var(--lh2);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--mute);
  overflow-wrap: anywhere;
}
/* An address or a path is printed as it is spelled: one put through text-transform is one nobody can type. */
.ui-caption.is-spelled { text-transform: none; letter-spacing: 0.02em; }
a.ui-caption { text-decoration: none; }
a.ui-caption:hover { color: var(--accent-down); text-decoration: underline; }
.ui-caption-row { display: flex; justify-content: space-between; align-items: baseline; gap: var(--s9); min-width: 0; }
/* The order a list is in and its ⋯ (`flex center none gap-4`), after what the caption says at its end. */
.ui-caption-row:has(> .ui-caption-acts) { align-items: center; }
/* What it says keeps its words on one line; what stands at its end gives way first, cut short, and the order and the ⋯ never leave the row (UIC-51). */
.ui-caption-row > .ui-caption:first-child { flex: none; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ui-caption-row > .ui-caption-acts { flex: 1 1 auto; min-width: 0; justify-content: flex-end; }
.ui-caption-row > .ui-caption:last-child:not(:first-child),
.ui-caption-acts > .ui-caption { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ui-caption-acts > :not(.ui-caption) { flex: none; }

/* A record's facts: each key a caption over its value on a phone, beside it on a desk; a hairline between them. */
.ui-fact { display: flex; flex-direction: column; gap: var(--s1); padding: var(--s5) 0; border-bottom: 1px solid var(--hair); }
.ui-fact:last-child { border-bottom: 0; }
.ui-fact > dd { margin: 0; min-width: 0; font-size: var(--t5); line-height: var(--lh5); color: var(--ink2); overflow-wrap: anywhere; }
.ui-facts.is-mono .ui-fact > dd { font-family: var(--mono); font-size: var(--t3); line-height: var(--lh3); }

/* ── the rows ────────────────────────────────────────────────────────────── */

.ui-list-rows { flex: 1; min-height: 0; overflow-y: auto; display: flex; flex-direction: column; gap: var(--s1); padding: 0 var(--s4) var(--s6); }
.ui-list-rows > * { flex: none; }
/* A run of rows that belong together — a category, a day — under its caption, on the rows' own edge. */
.ui-list-rows > .ui-caption-row { padding: var(--s9) var(--s6) var(--s3); }
.ui-list-rows > .ui-caption-row:first-child { padding-top: var(--s3); }
/* A board's rows stand on its head's edge, their wash out in the board's gutter; the board scrolls, not they. */
.ui-list-rows.is-board { flex: none; overflow: visible; padding: 0; margin-inline: calc(-1 * var(--s6)); }
/* Its rows' presses end on the head's edge too, as their faces start on it. */
.ui-list-rows.is-board .ui-list-row.is-box:has(> .ui-list-row-acts),
.ui-list-rows.is-board .ui-list-row.has-acts > .ui-list-row-acts { padding-right: var(--s6); }

.ui-list-row {
  display: flex;
  align-items: center;
  gap: var(--s6);
  min-width: 0;
  padding: var(--s6);
  border-radius: var(--r4);
  color: inherit;
  text-decoration: none;
}
.ui-list-row:hover { background: var(--hover); }
/* The open one, and the one a fragment lands on (the listing you came back from): washed. */
.ui-list-row:is(.is-on, :target) { background: var(--wash); }
/* A row with presses of its own is a box around its link and them. */
.ui-list-row.has-acts { padding: 0; gap: 0; }
.ui-list-row-open {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: var(--s6);
  padding: var(--s6);
  border-radius: inherit;
  color: inherit;
  text-decoration: none;
}
.ui-list-row-acts { flex: none; display: flex; align-items: center; gap: var(--s1); padding-right: var(--s4); }
/* Words among a row's presses are a finger tall on a phone, as a thing's acts are (PBOX-13); so is a round beside them. */
.ui-list-row-acts :is(.ui-pill, .ui-btn) { min-height: var(--finger); }
.ui-list-row-acts .ui-round { min-width: var(--finger); min-height: var(--finger); }
/* Rounds keep the row's line; words take a line of their own under it on a phone, at its right, as a pane's acts do. */
.ui-list-row.has-acts:has(> .ui-list-row-acts :is(.ui-pill, .ui-btn, .ui-submit)) { flex-wrap: wrap; }
.ui-list-row.has-acts:has(> .ui-list-row-acts :is(.ui-pill, .ui-btn, .ui-submit)) > .ui-list-row-open { flex-basis: 100%; }
.ui-list-row.has-acts:has(> .ui-list-row-acts :is(.ui-pill, .ui-btn, .ui-submit)) > .ui-list-row-acts {
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--s3);
  margin: calc(-1 * var(--s3)) 0 0 auto;
  padding-bottom: var(--s6);
}
/* A row that opens nothing, or holds what a link cannot (a tag's link, a form): a box, its link stretched over it and what hangs under its lines above the link. */
.ui-list-row.is-box { position: relative; flex-wrap: wrap; align-items: flex-start; }
/* Its words keep a reading width beside the face; the presses step under them, at the right, where both do not fit. */
.ui-list-row.is-box > .ui-list-row-text { flex: 1 1 min(var(--list-max), 60%); }
.ui-list-row.is-box:not(:has(.ui-list-row-link)):not(summary > *):hover { background: none; }
.ui-list-row.is-box:has(> .ui-list-row-acts) { padding-right: var(--s4); }
.ui-list-row.is-box > .ui-list-row-acts { position: relative; flex-wrap: wrap; justify-content: flex-end; gap: var(--s3); margin-left: auto; padding-right: 0; }
.ui-list-row-link { display: flex; flex-direction: column; gap: var(--s1); min-width: 0; color: inherit; text-decoration: none; }
.ui-list-row-link::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }
.ui-list-row-subject.is-none { font-style: italic; color: var(--mute); }
/* A thing that can be finished, ticked at its row's left; done is green, the accent being yours, unread, chosen. */
.ui-tick {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--s9);
  height: var(--s9);
  padding: 0;
  border: var(--s1) solid var(--ring);
  border-radius: 50%;
  background: none;
  color: var(--accent-ink);
  cursor: pointer;
}
.ui-tick:hover { border-color: var(--star); }
.ui-tick.is-done { background: var(--star); border-color: var(--star); }
.ui-tick > svg { width: var(--s6); height: var(--s6); }
/* Finished: its words struck through and faint. */
.ui-list-row.is-done .ui-list-row-subject { text-decoration: line-through; color: var(--faint); }
/* The sub-list's open row is ruled in the accent, not washed: two washed rows in two columns read as one choice. */
.ui-sublist .ui-list-row.is-on { background: none; border-radius: 0; box-shadow: inset var(--s1) 0 var(--accent); }
.ui-sublist .ui-list-row.is-on:hover { background: var(--hover); }
.ui-list-row-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: var(--s1); }
.ui-list-row-top { display: flex; justify-content: space-between; align-items: baseline; gap: var(--s4); }
.ui-list-row-line { display: flex; align-items: center; gap: var(--s3); min-width: 0; }
.ui-list-row-line > :not(.ui-list-row-subject, .ui-list-row-under) { flex: none; }
/* A record's facts: one line of captions (`grow flex center clip gap-3 nobr`) that gives way before the chips after it do. */
.ui-list-row-under > * { min-width: 0; flex: 0 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ui-list-row-who, .ui-list-row-subject { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ui-list-row-who { font-size: var(--t5); font-weight: 500; color: var(--ink2); }
.ui-list-row-when { flex: none; font-size: var(--t3); color: var(--mute); font-variant-numeric: tabular-nums; }
.ui-list-row-subject { flex: 1 1 auto; font-family: var(--serif); font-size: var(--t5); color: var(--ink3); }
.ui-list-row:is(.is-unseen, .is-on) .ui-list-row-who { font-weight: 600; color: var(--ink); }
.ui-list-row.is-unseen .ui-list-row-when { font-weight: 600; color: var(--accent-down); }
.ui-list-row.is-unseen .ui-list-row-subject { color: var(--ink2); }
/* A row whose words are its subject (a report): two lines of them before the cut, the chips on a line under. */
.ui-list-row.is-wrap, .ui-list-row.is-wrap > .ui-list-row-open { align-items: flex-start; }
.ui-list-row.is-wrap .ui-list-row-line { flex-wrap: wrap; row-gap: var(--s3); }
.ui-list-row.is-wrap .ui-list-row-subject {
  flex: 1 1 100%;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-height: var(--lh5);
  white-space: normal;
  overflow-wrap: anywhere;
}
.ui-list-row-line > .ui-caption { flex: 0 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* A thing's picture at the left, where a person's face would stand; the hatch holds its place until it has one. */
.ui-list-row-thumb { flex: none; width: var(--s12); height: var(--s12); border-radius: var(--r3); object-fit: cover; background: var(--field); }
.ui-list-row-thumb.is-empty { background: repeating-linear-gradient(135deg, var(--chip) 0 var(--s3), var(--line) var(--s3) var(--s6)); }
/* A door's own picture of a thing (a listing's photograph over its tint), framed as the thumbnail. */
.ui-list-row-thumb.is-framed { overflow: hidden; }
.ui-list-row-thumb.is-framed > * { width: 100%; height: 100%; aspect-ratio: auto; }
.ui-list-row-thumb.is-framed svg { width: var(--s9); height: var(--s9); }
/* A document's tile: its kind spelt at its foot, where a picture would be. */
.ui-list-row-thumb.is-kind {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding-bottom: var(--s2);
  border: 1px solid var(--line);
  font-family: var(--mono);
  font-size: var(--t1);
  letter-spacing: 0.04em;
  color: var(--ink3);
}

/* ── nothing to show (P6) ────────────────────────────────────────────────── */

.ui-empty {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--s12) var(--s8);
  text-align: center;
}
.ui-empty-in { max-width: var(--list-max); display: flex; flex-direction: column; align-items: center; gap: var(--s4); }
.ui-empty-glyph { width: var(--s10); height: var(--s10); color: var(--faint); }
.ui-empty-title { font-family: var(--serif); font-size: var(--t7); font-weight: 500; line-height: var(--lh7); color: var(--ink3); }
.ui-empty-says { margin: 0; font-size: var(--t4); line-height: var(--lh5); color: var(--mute); }
/* A board's: where its first row would stand, not in the middle of the room the rows would fill. */
.ui-empty.is-left { flex: none; justify-content: flex-start; text-align: left; padding: var(--s11) var(--s1); }
.ui-empty.is-left .ui-empty-in { align-items: flex-start; max-width: var(--group); }

/* ── the ⋯ (P20) ─────────────────────────────────────────────────────────── */

.ui-more { position: relative; display: inline-flex; flex: none; }
.ui-more-menu {
  position: absolute;
  top: calc(100% + var(--s3));
  right: 0;
  z-index: 60;
  min-width: var(--menu);
  display: flex;
  flex-direction: column;
  padding: var(--s2);
  border: 1px solid var(--line);
  border-radius: var(--r4);
  background: var(--surface);
  box-shadow: var(--pop);
}
.ui-more-menu > .ui-caption { display: block; padding: var(--s3) var(--s5) var(--s2); }
.ui-more-item {
  display: flex;
  align-items: center;
  gap: var(--s5);
  width: 100%;
  padding: var(--s4) var(--s5);
  border: 0;
  border-radius: var(--r3);
  background: none;
  color: var(--ink2);
  font-size: var(--t5);
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}
.ui-more-item:hover { background: var(--hover); color: var(--ink); }
.ui-more-item.is-on { color: var(--accent-down); font-weight: 600; }
.ui-more-item.is-danger { color: var(--danger); }
.ui-more-item.is-danger:hover { background: var(--danger-soft); color: var(--danger); }
.ui-more-form { display: contents; }
.ui-more-rule { height: 1px; margin: var(--s2) 0; background: var(--hair); }

/* ── a face beside running text (`ui-hang`): a letter's sender, a comment's writer ── */

/* On a desk the face hangs to the left of the name and of everything under it; on a phone it joins the name's line and the words take the width. */
.ui-hang {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  grid-template-areas: "face head" "face body";
  column-gap: var(--s6);
  row-gap: var(--s2);
  align-items: start;
}
.ui-hang-face { grid-area: face; display: flex; }
.ui-hang-head { grid-area: head; min-width: 0; }
.ui-hang-body { grid-area: body; min-width: 0; }
/* A face beside words no name heads (`is-lone`, the assistant's reply): on a phone it stands down and the words take the width, and so does what hangs on its edge (`--hang`, UIC-51). */
.ui-hang.is-lone { grid-template-areas: "face body"; }
@container (max-width: 640px) {
  .ui-hang { grid-template-areas: "face head" "body body"; column-gap: var(--s5); row-gap: var(--s4); align-items: center; }
  .ui-hang-body { align-self: start; }
  .ui-hang.is-lone { grid-template-areas: "body"; }
  .ui-hang.is-lone > .ui-hang-face { display: none; }
}

/* ── the thing itself: the pane's head ───────────────────────────────────── */

/* Ring, face, title and acts on one row; the chips on their own under it (the whole width on a phone). */
.ui-pane-head {
  flex: none;
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr) auto;
  align-items: start;
  row-gap: var(--s4);
  padding: var(--s7);
  border-bottom: 1px solid var(--line);
  background: var(--surface);
}
.ui-pane-head > .ui-back { grid-area: 1 / 1; margin-block: calc((var(--t8) * var(--lh10) - var(--back)) / 2); margin-right: var(--s6); }
.ui-pane-face { grid-area: 1 / 2; align-self: center; display: flex; margin-right: var(--s6); }
.ui-pane-titled { grid-area: 1 / 3; min-width: 0; display: flex; flex-direction: column; gap: var(--s2); }
.ui-pane-title {
  margin: 0;
  min-width: 0;
  font-family: var(--serif);
  font-size: var(--t8);
  font-weight: 500;
  line-height: var(--lh10);
  letter-spacing: -0.015em;
  color: var(--ink);
  /* Wraps between words; a word wider than the column ends in an ellipsis, never split. */
  overflow-x: clip;
  text-overflow: ellipsis;
}
.ui-pane-title.is-none { font-style: italic; font-weight: 400; color: var(--ink3); }
.ui-pane-meta { margin: 0; min-width: 0; font-size: var(--t3); line-height: var(--lh3); color: var(--mute); overflow-wrap: anywhere; }
/* A pane that reads one thing stands its head and its words on the reading column (UIC-41): the same two edges. */
.ui-pane-head.is-read { padding-inline: max(var(--gutter), (100% - var(--read)) / 2); }
.ui-pane-body { padding: var(--s9) var(--gutter) var(--s13); }
.ui-pane-chips { grid-row: 2; grid-column: 1 / -1; min-width: 0; display: flex; flex-wrap: wrap; align-items: center; gap: var(--s3); }
.ui-pane-chips > * { min-width: 0; max-width: 100%; }
/* Rounds and the ⋯ keep the title's row; words take a row of their own on a phone, a finger tall. */
.ui-pane-acts { grid-area: 1 / 4; display: flex; align-items: center; gap: var(--s3); min-height: calc(var(--t8) * var(--lh10)); margin-left: var(--s6); }
.ui-pane-acts:has(> :is(.ui-pill, .ui-btn, .ui-submit)) { grid-row: auto; grid-column: 1 / -1; flex-wrap: wrap; margin-left: 0; }
.ui-pane-acts :is(.ui-pill, .ui-btn) { min-height: var(--finger); }
/* On a phone the head rides the top of a pane that scrolls as one, steps up out of the way while the words scroll down and comes back the moment they scroll up (`TUCK_SCRIPT`). */
@container (max-width: 640px) {
  .ui-pane-head { position: sticky; top: 0; z-index: 2; transition: transform var(--unfold); }
  .ui-pane-head.is-tucked { transform: translateY(-100%); }
}

@container (min-width: 641px) {
  .ui-list-head { padding: var(--s10) var(--s9) var(--s8); }
  .ui-list-head.is-board { padding: 0 0 var(--s4); }
  .ui-list-head.is-board:not(:has(> .ui-caption-row)) { padding-bottom: var(--s8); }
  .ui-list-lede { display: block; }
  .ui-frame, .ui-dock { --hang: calc(var(--s10) + var(--s4)); }
  .ui-list-acts:has(> :is(.ui-pill, .ui-btn, .ui-text-btn)) { order: 0; flex: none; flex-wrap: nowrap; margin-left: auto; }
  .ui-list-acts :is(.ui-pill, .ui-btn) { min-height: 0; }
  .ui-list-rows { padding: 0 var(--s6) var(--s6); }
  .ui-fact { flex-direction: row; align-items: baseline; gap: var(--s7); }
  .ui-fact > dt { flex: none; width: var(--part-label); }
  .ui-list-row-acts :is(.ui-pill, .ui-btn) { min-height: 0; }
  .ui-list-row-acts .ui-round { min-width: var(--ui-round-size); min-height: 0; }
  .ui-list-row.has-acts:has(> .ui-list-row-acts :is(.ui-pill, .ui-btn, .ui-submit)) { flex-wrap: nowrap; }
  .ui-list-row.has-acts:has(> .ui-list-row-acts :is(.ui-pill, .ui-btn, .ui-submit)) > .ui-list-row-open { flex-basis: auto; }
  .ui-list-row.has-acts:has(> .ui-list-row-acts :is(.ui-pill, .ui-btn, .ui-submit)) > .ui-list-row-acts { margin: 0; padding-bottom: 0; }
  .ui-pane-head { row-gap: var(--s3); padding: var(--s9) var(--s10) var(--s8); }
  .ui-pane-head > .ui-back { margin-right: var(--s7); }
  .ui-pane-chips { grid-column: 3 / -1; }
  .ui-pane-acts { margin-left: var(--s7); }
  .ui-pane-acts:has(> :is(.ui-pill, .ui-btn, .ui-submit)) { grid-area: 1 / 4; flex-wrap: nowrap; margin-left: var(--s7); }
  .ui-pane-face { margin-right: var(--s7); }
  .ui-pane-acts :is(.ui-pill, .ui-btn) { min-height: 0; }
}

/* The head of a page or a sheet (UIC-43), phone first: the desk is the container rule at the foot. */

/* ── the way back: one ring before the title ─────────────────────────────── */

.ui-back {
  position: relative;
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--back);
  height: var(--back);
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--ink3);
  text-decoration: none;
  transition: border-color var(--quick), color var(--quick);
}
.ui-back .icon { width: var(--s8); height: var(--s8); }
.ui-back:hover, .ui-back:focus-visible { border-color: var(--accent); color: var(--accent); }
/* A finger's target around a ring the eye reads smaller. */
.ui-back::before { content: ""; position: absolute; inset: calc((var(--back) - var(--finger)) / 2); }

/* ── the band ─────────────────────────────────────────────────────────────── */

/* Its hairline reaches whatever edge clips it: the pane, the sheet, the glass. */
.ui-head {
  --ui-head-line: calc(clamp(var(--t9), 3vw, var(--t10)) * var(--lh10));
  flex: none;
  display: flex;
  flex-direction: column;
  gap: var(--s6);
  padding: var(--s8) var(--gutter) 0;
  border-bottom: 1px solid var(--line);
  border-image: linear-gradient(var(--line), var(--line)) 0 0 1 / 0 0 1px / 0 100vw;
}
/* The band stands at the column's measure, its title over what it heads (UIC-41). */
.ui-head-row, .ui-head > .ui-doc-tabs { width: 100%; max-width: var(--read); margin-inline: auto; }
.ui-head:not(:has(> .ui-doc-tabs)) { padding-bottom: var(--s8); }
/* A sheet's head stands on the sheet's column, the one its job is done in (UIC-43). */
.ui-head.is-sheet { --read: var(--sheet-col); }
.ui-head.is-sheet.is-wide { --read: var(--sheet-wide); }
/* A job over the page keeps its band, and its way out, in view while its column scrolls under it. */
.overlay > .ui-reading > .ui-head { position: sticky; top: 0; z-index: 1; background: var(--surface); }

.ui-head-row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: var(--s6);
}
.ui-head-row > .ui-back { margin-block: calc((var(--ui-head-line) - var(--back)) / 2); }
/* Where the band's gutter holds the ring, the row reaches out by it and the title stands on the column's edge;
   a ring the desk does not draw (`d-hidden`, the parent beside it) asks for no room. */
.ui-head-row:has(> .ui-back:not(.d-hidden, .hidden)) {
  --ui-head-hang: clamp(0px, ((100% - var(--read)) / 2 - var(--back) - var(--s6)) * 1000, var(--back) + var(--s6));
  max-width: calc(var(--read) + var(--ui-head-hang));
  margin-left: calc((100% - min(100%, var(--read))) / 2 - var(--ui-head-hang));
  margin-right: auto;
}

/* The path wraps under the title before the acts leave the row. */
.ui-head-titled {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s1) var(--s7);
}
.ui-head-title {
  margin: 0;
  min-width: 0;
  font-family: var(--serif);
  font-size: clamp(var(--t9), 3vw, var(--t10));
  font-weight: 500;
  line-height: var(--lh10);
  letter-spacing: -0.02em;
  color: var(--ink);
  overflow-wrap: anywhere;
}
/* A path printed as it is spelled: one put through text-transform is one nobody can type. */
.ui-head-meta {
  min-width: 0;
  font-family: var(--mono);
  font-size: var(--t2);
  line-height: var(--lh2);
  letter-spacing: 0.05em;
  color: var(--mute);
  overflow-wrap: anywhere;
}

/* On a phone the acts take a row of their own under the title, at the left, a finger tall. */
.ui-head-acts {
  order: 1;
  flex: 1 1 100%;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s4);
  min-width: 0;
}
.ui-head-acts [hidden] { display: none; }
/* Acts with nothing to show yet — a press a script reveals, a line it fills — take no row. */
.ui-head-acts:not(:has(> :not(.hidden, [hidden], span:empty))) { display: none; }
.ui-head-acts :is(.ui-pill, .ui-btn) { min-height: var(--finger); }

/* A sheet's way out keeps the title's row at every width, its acts before it on a desk. */
.ui-head-close {
  flex: none;
  display: flex;
  align-items: center;
  min-height: var(--ui-head-line);
}

@container (min-width: 641px) {
  .ui-head-row { flex-wrap: nowrap; }
  .ui-head-acts { order: 0; flex: none; min-height: var(--ui-head-line); margin-left: auto; }
  .ui-head-acts :is(.ui-pill, .ui-btn) { min-height: 0; }
}

/* The manual (UIC-12), phone first: the band is head.css, the column is the reading layout's. */

/* ── the books: words with a line under the one being read ───────────────── */

/* One row a thumb swipes on a phone, never a second line under the first. */
.ui-doc-tabs {
  display: flex;
  gap: clamp(var(--s7), 2vw, var(--s10));
  flex-wrap: nowrap;
  overflow-x: auto;
  scrollbar-width: none;
}
.ui-doc-tabs::-webkit-scrollbar { display: none; }
/* A finger's target on a phone; a word longer than one starts on the column's edge. */
.ui-doc-tab {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--finger);
  min-width: var(--finger);
  padding: var(--s6) 0;
  font-size: var(--t5);
  color: var(--ink3);
  white-space: nowrap;
  box-shadow: inset 0 -2px 0 transparent;
}
.ui-doc-tab:hover { color: var(--ink); }
.ui-doc-tab.is-on { color: var(--ink); font-weight: 600; box-shadow: inset 0 -2px 0 var(--accent); }

/* ── the pages of a book: the same words a step smaller, over the document ── */

.ui-doc-pills {
  display: flex;
  gap: clamp(var(--s6), 2vw, var(--s9));
  flex-wrap: nowrap;
  overflow-x: auto;
  scrollbar-width: none;
  margin-bottom: var(--s9);
  border-bottom: 1px solid var(--hair);
}
.ui-doc-pills::-webkit-scrollbar { display: none; }
.ui-doc-pill {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--finger);
  min-width: var(--finger);
  padding: var(--s4) 0;
  font-size: var(--t4);
  color: var(--ink3);
  white-space: nowrap;
  box-shadow: inset 0 -2px 0 transparent;
}
.ui-doc-pill:hover { color: var(--ink); }
.ui-doc-pill.is-on { color: var(--ink); font-weight: 600; box-shadow: inset 0 -2px 0 var(--accent); }

/* ── the document, read two ways ─────────────────────────────────────────── */

.ui-doc-body { display: flex; flex-direction: column; min-width: 0; }
/* A class that sets display outranks the browser's own rule for hidden. */
.ui-doc-raw[hidden], .ui-doc-md[hidden] { display: none; }

.ui-doc-raw {
  margin: 0;
  padding: var(--s8);
  border: 1px solid var(--hair);
  border-radius: var(--r4);
  background: var(--mid);
  font-family: var(--mono);
  font-size: var(--t4);
  line-height: 1.7;
  color: var(--ink2);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.ui-doc-md h1 {
  margin: 0 0 var(--s7);
  font-family: var(--serif);
  font-size: var(--t9);
  font-weight: 500;
  letter-spacing: -0.015em;
  color: var(--ink);
}
.ui-doc-md h2 {
  margin: var(--s11) 0 var(--s6);
  font-family: var(--serif);
  font-size: var(--t8);
  font-weight: 500;
  letter-spacing: -0.015em;
  color: var(--ink);
}
.ui-doc-md h3 {
  margin: var(--s9) 0 var(--s5);
  font-family: var(--serif);
  font-size: var(--t6);
  font-weight: 500;
  color: var(--ink);
}
.ui-doc-md p { margin: 0 0 var(--s6); font-size: var(--t5); line-height: 1.65; color: var(--ink3); }
.ui-doc-md ul, .ui-doc-md ol { margin: 0 0 var(--s7); padding-left: var(--s9); }
.ui-doc-md li { margin-bottom: var(--s3); font-size: var(--t5); line-height: 1.65; color: var(--ink3); }
.ui-doc-md strong { color: var(--ink2); font-weight: 600; }
.ui-doc-md a { color: var(--accent); }
.ui-doc-md a:hover { text-decoration: underline; }
.ui-doc-md hr { margin: var(--s9) 0; border: 0; border-top: 1px solid var(--hair); }
.ui-doc-md > :first-child { margin-top: 0; }
.ui-doc-md > :last-child { margin-bottom: 0; }
/* A letter's picture (INBOX-75), held as a place with its words until asked for. */
.ui-doc-md img { max-width: 100%; height: auto; vertical-align: middle; border-radius: var(--r2); }
.ui-doc-held {
  display: inline-flex; align-items: center; flex-wrap: wrap; gap: var(--s3); max-width: 100%;
  padding: var(--s1) var(--s4);
  border: 1px dashed var(--line); border-radius: var(--r2);
  font-size: var(--t3); color: var(--faint); overflow-wrap: anywhere;
}
.ui-doc-md blockquote {
  margin: 0 0 var(--s7);
  padding: var(--s6) var(--s8);
  border-left: 2px solid var(--accent-line);
  background: var(--wash);
  font-size: var(--t5);
  line-height: 1.65;
  color: var(--ink2);
}
.ui-doc-md .code, .ui-doc-md code {
  padding: var(--s1) var(--s2);
  border: 0;
  border-radius: var(--r2);
  background: var(--hover);
  font-family: var(--mono);
  font-size: var(--t3);
  color: var(--ink2);
}
.ui-doc-md .md-code {
  margin: 0 0 var(--s8);
  padding: var(--s6) var(--s8);
  border: 1px solid var(--hair);
  border-radius: var(--r4);
  background: var(--mid);
  font-family: var(--mono);
  font-size: var(--t3);
  line-height: 1.75;
  color: var(--doc-code);
  overflow-x: auto;
}
.ui-doc-md .md-code code { padding: 0; background: none; font-size: inherit; }

/* A wider table cannot reflow, so on a phone it scrolls inside itself. */
.ui-doc-md .md-table {
  display: block;
  width: 100%;
  margin: 0 0 var(--s8);
  border: 1px solid var(--hair);
  border-radius: var(--r4);
  border-collapse: collapse;
  overflow-x: auto;
  text-align: left;
}
.ui-doc-md .md-table th, .ui-doc-md .md-table td {
  padding: var(--s5) var(--s7);
  border-bottom: 1px solid var(--hair);
  vertical-align: baseline;
  font-size: var(--t4);
  line-height: 1.5;
  color: var(--ink3);
}
.ui-doc-md .md-table th {
  font-family: var(--mono);
  font-size: var(--t1);
  font-weight: 400;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--mute);
}
.ui-doc-md .md-table tr:last-child td { border-bottom: 0; }

/* A reference table is rows of a key and what it does: on a phone the key over its sentence. */
.ui-doc-md .md-table[data-cols="2"],
.ui-doc-md .md-table[data-cols="2"] tbody,
.ui-doc-md .md-table[data-cols="2"] tr,
.ui-doc-md .md-table[data-cols="2"] th,
.ui-doc-md .md-table[data-cols="2"] td { display: block; }
.ui-doc-md .md-table[data-cols="2"] thead { display: none; }
.ui-doc-md .md-table[data-cols="2"] tr {
  padding: var(--s5) var(--s7);
  border-bottom: 1px solid var(--hair);
}
.ui-doc-md .md-table[data-cols="2"] tr:last-child { border-bottom: 0; }
.ui-doc-md .md-table[data-cols="2"] th,
.ui-doc-md .md-table[data-cols="2"] td { padding: 0; border-bottom: 0; }
.ui-doc-md .md-table[data-cols="2"] td:first-child {
  padding-bottom: var(--s2);
  font-family: var(--mono);
  font-size: var(--t3);
  color: var(--doc-key);
  overflow-wrap: anywhere;
}

/* ── the Test panel ──────────────────────────────────────────────────────── */

.ui-doc-test { margin-bottom: var(--s10); }
.ui-doc-strip {
  height: 36px;
  padding: 0 var(--s8);
  border: 1px dashed var(--line2);
  border-radius: var(--r-pill);
  background: var(--surface);
  display: inline-flex;
  align-items: center;
  gap: var(--s4);
  align-self: flex-start;
  cursor: pointer;
  color: var(--ink3);
  font-family: var(--sans);
  font-size: var(--t4);
}
.ui-doc-strip:hover { border-color: var(--accent); color: var(--accent); }
.ui-doc-strip[hidden], .ui-doc-card[hidden], .ui-doc-x-body[hidden] { display: none; }

.ui-doc-card {
  border: 1px solid var(--line);
  border-radius: var(--r6);
  background: var(--surface);
  box-shadow: var(--card);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.ui-doc-card-head {
  flex: none;
  padding: var(--s5) var(--s6) var(--s5) var(--s8);
  border-bottom: 1px solid var(--hair);
  display: flex;
  align-items: center;
  gap: var(--s6);
  flex-wrap: wrap;
}
.ui-doc-card-head p {
  margin: 0;
  flex: 1;
  min-width: 0;
  font-size: var(--t4);
  line-height: 1.45;
  color: var(--ink3);
}
.ui-doc-card-body { display: flex; gap: var(--s9); padding: var(--s8); flex-wrap: wrap; }
.ui-doc-ask {
  flex: none;
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: var(--s7);
}
.ui-doc-card-head .ui-pill, .ui-doc-ask .ui-pill { min-height: var(--finger); }
.ui-doc-said { flex: 1; min-width: 240px; display: flex; flex-direction: column; gap: var(--s3); }
.ui-doc-field { display: flex; flex-direction: column; gap: var(--s3); }

/* The label a reference wears over a box: a word, in the mono face, quiet. */
.ui-doc-label {
  font-family: var(--mono);
  font-size: var(--t2);
  letter-spacing: 0.08em;
  color: var(--mute);
  text-transform: uppercase;
}
.ui-doc-empty { margin: 0; padding: var(--s3) 0; font-size: var(--t4); color: var(--mute); }

/* ── one exchange: what was asked, and what came back ────────────────────── */

.ui-doc-xs { display: flex; flex-direction: column; gap: var(--s4); }
.ui-doc-x { border: 1px solid var(--hair); border-radius: var(--r4); overflow: hidden; }
.ui-doc-x-head {
  width: 100%;
  display: flex;
  align-items: center;
  gap: var(--s4);
  padding: var(--s4) var(--s5);
  border: 0;
  background: var(--rail);
  cursor: pointer;
  text-align: left;
  font-family: var(--sans);
}
.ui-doc-x-head:hover { background: var(--hover); }
.ui-doc-x-chev { font-family: var(--mono); font-size: var(--t2); color: var(--mute); }
.ui-doc-x-title {
  font-family: var(--mono);
  font-size: var(--t3);
  color: var(--doc-key);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ui-doc-x-part { padding: var(--s4) var(--s5); border-top: 1px solid var(--hair); }
.ui-doc-x-part.is-in { background: var(--mid); }
.ui-doc-x-tag { font-family: var(--mono); font-size: var(--t1); letter-spacing: 0.1em; padding-bottom: var(--s2); }
.ui-doc-x-tag.is-out { color: var(--accent-down); }
.ui-doc-x-tag.is-in { color: var(--ok-ink); }
.ui-doc-x-text {
  margin: 0;
  font-family: var(--mono);
  font-size: var(--t3);
  line-height: 1.6;
  color: var(--doc-code);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  max-height: 320px;
  overflow: auto;
}
/* After a written-down write: the way to its form, offered rather than opened. */
.ui-doc-x-part .ui-doc-x-open { margin-top: var(--s1); }

/* ── the desk ────────────────────────────────────────────────────────────── */

@container (min-width: 641px) {
  .ui-doc-tabs { flex-wrap: wrap; overflow-x: visible; }
  .ui-doc-tab { min-height: 0; min-width: 0; padding: 0 0 var(--s6); }
  .ui-doc-pills { flex-wrap: wrap; overflow-x: visible; }
  .ui-doc-pill { min-height: 0; min-width: 0; padding: 0 0 var(--s5); }
  .ui-doc-raw { padding: var(--s9) var(--s10); }

  .ui-doc-md .md-table { display: table; overflow: hidden; }
  .ui-doc-md .md-table[data-cols="2"],
  .ui-doc-md .md-table[data-cols="2"] thead,
  .ui-doc-md .md-table[data-cols="2"] tbody { display: block; }
  .ui-doc-md .md-table[data-cols="2"] tr { display: flex; align-items: baseline; gap: var(--s8); }
  .ui-doc-md .md-table[data-cols="2"] th:first-child,
  .ui-doc-md .md-table[data-cols="2"] td:first-child { flex: none; min-width: 246px; padding-bottom: 0; }
  .ui-doc-md .md-table[data-cols="2"] th:last-child,
  .ui-doc-md .md-table[data-cols="2"] td:last-child { flex: 1; min-width: 0; }

  .ui-doc-ask { width: 320px; max-width: 100%; }
  .ui-doc-card-head .ui-pill, .ui-doc-ask .ui-pill { min-height: 0; }
}

/* The dock (UIC-13, UIC-14): a surface that opens beside the page rather than
   over it, on the house tokens and defining nothing of its own but its width.

   On a desk the page moves aside and both are readable at once — which is the
   point of asking something while looking at the thing you are asking about.
   On a phone there is no beside, so it takes the screen.

   Three shares, not open and shut (UIC-14): the page, half each, and the
   whole screen. The whole contract with the page is one attribute on `<html>`,
   which carries which share it is. A surface's own sheet can join in —
   narrowing a map, moving a sticky bar — by matching `[data-dock="half"]`
   without knowing the dock's script exists. */

:root {
  /* A knob, not a token: how wide the dock is at the share it is on, which a
     surface may turn down. The script writes this one as pixels when the
     reader has dragged the boundary (UIC-15). */
  --ui-dock-w: 0px;
  /* Neither side goes below this. A column narrower than this is one nobody
     reads — the drag stops here rather than squeezing a half out of use, and
     a window with no room for two of them is not draggable at all. */
  --ui-dock-min: 420px;
  /* How tall the panel is (UIC-31). `100dvh` is the screen and stays the
     screen while a software keyboard is up: iOS shrinks the *visual*
     viewport and leaves the layout one — and every `dvh` and every
     `@media (max-height:)` with it — alone, so a panel fixed at the full
     height keeps its composer under the keys and its head above the top of
     what can be seen. The script writes what `visualViewport` says; with no
     script, and with no keyboard, the two are the same number. */
  --ui-dock-vh: 100dvh;
  /* And how far down the visible band starts (UIC-31). A fixed panel is
     anchored to the layout viewport, which does not move when the keys come
     up; the browser scrolls the *visual* viewport inside it to show what is
     focused, and this is that scroll. Zero everywhere else. */
  --ui-dock-top: 0px;
  /* How far the tab on the rim reaches in from the right edge, on a phone's finger as on a desk. */
  --ui-dock-reach: var(--s13);
}

/* Beside the page the dock opens at the floor — a column, not half the
   window — and the reader drags it wider from there (UIC-15); a dragged
   width is written over this one as pixels. Full is the screen. */
[data-dock="half"] { --ui-dock-w: var(--ui-dock-min); }
[data-dock="full"] { --ui-dock-w: 100%; }

/* ── the handle on the rim the panel comes out of ────────────────────────── */

/* A tab against the right edge, not a button floating in the corner: an arrow
   pointing the way the panel will travel and the two letters saying what is
   behind it. Small and quiet — everything it covers is something somebody
   came for. It sits below the header band every surface keeps its own face
   in, which is the knob a surface turns if its own is taller. */
.ui-dock-handle {
  position: fixed;
  top: var(--ui-dock-handle-top, 76px);
  right: 0;
  z-index: 61;
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  padding: var(--s3) var(--s4) var(--s3) var(--s3);
  border: 1px solid var(--line);
  border-right: 0;
  border-radius: var(--r4) 0 0 var(--r4);
  background: var(--surface);
  color: var(--mute);
  font-family: var(--mono);
  font-size: var(--t2);
  font-weight: 600;
  letter-spacing: .06em;
  cursor: pointer;
  box-shadow: var(--float);
  transition: color .2s, background .2s, padding-right .2s;
}
.ui-dock-handle:hover {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
  padding-right: var(--s6);
}
.ui-dock-handle:focus-visible { outline: var(--s1) solid var(--accent); outline-offset: var(--s1); }
.ui-dock-handle[hidden] { display: none; }
.ui-dock-handle-arrow { flex: none; }
.ui-dock-handle-word { line-height: 1; }
/* A page's band under the tab keeps clear of it: the title wraps and the acts end before it (UIC-43). */
body:has(.ui-dock-handle:not([hidden])) .ui-head-row {
  padding-inline-end: max(0px, var(--ui-dock-reach) - var(--gutter) - (100% - min(100%, var(--read))) / 2);
}

/* ── and the same again as a row in the surface's own menu ───────────────── */

/* Nothing floats over the page. The dock is reached from wherever that
   surface already keeps "Assistant", so the control sits among the menu's
   other rows and inherits their shape: the class the surface passes does the
   dressing, and these rules only lay the row out and place the share on the
   right of it, where a value belongs in a list of settings. */
.ui-dock-toggle {
  display: flex;
  align-items: center;
  gap: var(--s5);
  width: 100%;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
}
.ui-dock-toggle-word { flex: 1; min-width: 0; }

/* ── the panel ───────────────────────────────────────────────────────────── */

.ui-dock {
  position: fixed;
  top: var(--ui-dock-top);
  right: 0;
  z-index: 60;
  width: var(--ui-dock-w);
  height: var(--ui-dock-vh);
  /* Three rows and not three flex items (UIC-31): the head, the conversation
     and the composer each have a row of their own, so nothing the fold or a
     keyboard does can push one of them off the panel. It is the arrangement
     the dock already wears where it *is* the page (UIC-22), lifted to the
     panel itself. */
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto minmax(0, 1fr) auto;
  grid-template-areas: "head" "body" "foot";
  min-height: 0;
  background: var(--surface);
  /* The hairline is the edge; no shadow (2026-09-07: *"dont use drop shadow
     for the assistant"*) — the dock is a column beside the page, not a
     sheet lying on it. */
  border-left: 1px solid var(--line);
}
/* Only once the share has settled, and never under a hand (UIC-15): a page
   that draws itself already open would otherwise slide out on every
   navigation, and an animated width chases a dragging pointer rather than
   following it. */
[data-dock-ready]:not([data-dock-drag]) .ui-dock {
  transition: width .28s cubic-bezier(.4, 0, .2, 1);
}

/* ── the boundary, dragged ──────────────────────────────────────────────── */

/* The line itself, on the panel's own edge: a hit area wide enough for a
   hand, drawn as nothing until it is reached for. The two arrows in the head
   move the same boundary in steps; this is it dragged. */
.ui-dock-grip {
  position: absolute;
  top: 0;
  /* Twelve pixels, half of them over the page: a boundary somebody has to
     aim at is one they miss, and a hand is not a pixel. */
  left: -6px;
  width: 12px;
  height: 100%;
  z-index: 1;
  cursor: col-resize;
  touch-action: none;
  background: none;
}
.ui-dock-grip:hover, .ui-dock-grip:focus-visible {
  background: var(--accent);
  outline: none;
}
/* Nothing to drag when the panel is the screen, or when the screen has no
   room for two readable halves. */
[data-dock="full"] .ui-dock-grip { display: none; }
@media (max-width: 839px) {
  .ui-dock-grip { display: none; }
}

/* A shut dock is shut. `display: flex` above is an author rule and the
   browser's own `[hidden] { display: none }` is not, so without this line the
   panel stays on the screen with the attribute set — covering the page it is
   supposed to sit beside. */
.ui-dock[hidden] { display: none; }

.ui-dock > .ui-dock-head { grid-area: head; }
.ui-dock > .ui-dock-body { grid-area: body; }
.ui-dock > .ui-dock-foot { grid-area: foot; }

.ui-dock-head {
  display: flex;
  align-items: flex-start;
  gap: var(--s5);
  padding: var(--s8) var(--s8) var(--s6);
  border-bottom: 1px solid var(--hair);
}
/* Whose panel this is, beside its name: a portrait is who a reader is
   talking to, which the name alone only says once you have read it. */
.ui-dock-face {
  flex: none;
  width: var(--s11);
  height: var(--s11);
  border-radius: 50%;
  object-fit: cover;
  /* A third of the way down: a tall portrait keeps the face in the circle. */
  object-position: 50% 33%;
  background: var(--page);
}
.ui-dock-titled { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--s2); }
/* The name, and whatever small thing the filling keeps beside it. A row, so
   the two sit on one line; the name may shrink and the small thing may not,
   because a picker that has lost its own width is one nobody can read. */
.ui-dock-name { display: flex; align-items: baseline; gap: var(--s3); min-width: 0; }
.ui-dock-title { margin: 0; font-size: var(--t6); font-weight: 600; color: var(--ink); }
.ui-dock-said { margin: 0; font-size: var(--t4); line-height: var(--lh4); color: var(--mute); }

/* The boundary, with a hand on each side of it. Two small arrows, together,
   so the pair reads as one control with two directions rather than as two
   unrelated buttons that happen to sit next to each other. */
.ui-dock-edge { flex: none; display: flex; align-items: center; gap: var(--s1); }
/* The two presses in the corner (UIC-21): the whole screen, and shut. The
   first is a switch and shows it — pressed, it is the way back beside the
   page. */
.ui-dock-full,
.ui-dock-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--s11);
  height: var(--s11);
  border: 0;
  border-radius: var(--r3);
  background: none;
  color: var(--mute);
  cursor: pointer;
}
.ui-dock-full svg, .ui-dock-close svg { width: 16px; height: 16px; }
.ui-dock-full:hover,
.ui-dock-close:hover { background: var(--hover); color: var(--ink); }
.ui-dock-full[aria-pressed="true"] { background: var(--hover); color: var(--ink); }
/* A press the filling keeps beside its own name wears the head's manner,
   like the two in the corner (2026-09-09): their size, no ring and no ground
   until the hand is on it, and centred on the name rather than hung from
   its baseline — a ringed circle beside a title read as a badge, not as a
   press. */
.ui-dock-name .ui-round {
  --ui-round-size: var(--s11);
  align-self: center;
  border-color: transparent;
  background: none;
  color: var(--mute);
  box-shadow: none;
}
.ui-dock-name .ui-round:hover,
.ui-dock-name .ui-round:focus-visible {
  border-color: transparent;
  background: var(--hover);
  color: var(--ink);
  box-shadow: none;
}

/* ── what was said before ────────────────────────────────────────────────── */

/* Top left, where a list of what there is belongs — the same corner the
   console, the mailbox and the portal all keep their rail in. */
.ui-dock-past-open {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--s11);
  height: var(--s11);
  margin-top: calc(var(--s1) * -1);
  border: 0;
  border-radius: var(--r3);
  background: none;
  color: var(--mute);
  cursor: pointer;
}
.ui-dock-past-open:hover { background: var(--hover); color: var(--ink); }
.ui-dock-past-open[aria-expanded="true"] { background: var(--hover); color: var(--ink); }
/* The filling's own press beside it (UIC-21): the same quiet square, so the
   corner reads as one row of two — the list, and a fresh one. */
.ui-dock-fresh {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--s11);
  height: var(--s11);
  margin-top: calc(var(--s1) * -1);
  border: 0;
  border-radius: var(--r3);
  background: none;
  color: var(--mute);
  cursor: pointer;
}
.ui-dock-fresh:hover { background: var(--hover); color: var(--ink); }
.ui-dock-fresh .icon { width: var(--s5); height: var(--s5); }

/* A cover over the conversation, not a box above it (UIC-31): the reader is
   choosing between conversations, so the one underneath is not what they are
   reading — and a fold that pushed the composer off the bottom is one nobody
   opens twice. `100%` is the conversation's own row, so the head stays over
   it and the composer under it whatever the list is; `50dvh` was half of the
   *screen*, which with a keyboard up is more than the whole panel. */
.ui-dock-past {
  grid-area: body;
  z-index: 2;
  align-self: start;
  max-height: 100%;
  overflow-y: auto;
  padding: var(--s5) var(--s8) var(--s6);
  background: var(--page);
  border-bottom: 1px solid var(--line);
}
.ui-dock-past[hidden] { display: none; }
.ui-dock-past-head {
  margin: 0 0 var(--s4);
  font-size: var(--t3);
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--faint);
}
.ui-dock-past-body { display: flex; flex-direction: column; gap: var(--s1); }

.ui-dock-body { min-height: 0; overflow-y: auto; padding: var(--s8); }
.ui-dock-foot { padding: var(--s6) var(--s8) var(--s8); border-top: 1px solid var(--hair); }
/* A body that is a pane scrolling itself — the assistant's conversation — stands flush and does not scroll twice. */
.ui-dock.is-flush > .ui-dock-body { padding: 0; overflow: hidden; }


/* ── the page moves aside ────────────────────────────────────────────────── */

/* On the padding rather than on a transform: a transform would move the page
   without resizing it, so a column that scrolls would keep the width it had
   and hide its right-hand edge under the dock. The frame is `width: 100%`, so
   padding on the body is what narrows it.

   Nothing is done to the body while the dock is shut, and that is deliberate:
   a `scrollbar-gutter` here would have been a quiet fifteen pixels off the
   width of every page of every surface, dock or no dock, which is the sort of
   thing a shared sheet must not do. */
[data-dock="half"] body { padding-right: var(--ui-dock-w); }

/* At full there is nothing to narrow: padding the body by its own width would
   collapse the page rather than move it, so the panel simply covers it and
   the page underneath stops scrolling. */
[data-dock="full"] body { overflow: hidden; }

/* Armed one frame after the dock settles, and dropped while the boundary is
   under a hand: a page that arrives already narrowed has not *moved*, and
   animating it on arrival is the twitch on every navigation and every redraw
   (UIC-15). */
@media (prefers-reduced-motion: no-preference) {
  [data-dock-ready]:not([data-dock-drag]) body {
    transition: padding-right .28s cubic-bezier(.4, 0, .2, 1);
  }
}

/* ── a phone has no beside ───────────────────────────────────────────────── */

@media (max-width: 640px) {
  /* Both open shares are the screen: half of a phone is not a column anybody
     can read. */
  [data-dock="half"] { --ui-dock-w: 100%; }
  .ui-dock { border-left: 0; }
  /* Nothing moves: the dock is the screen, and padding the body would leave
     the page scrolled sideways underneath it. */
  [data-dock="half"] body { padding-right: 0; overflow: hidden; }
  /* A 24px tab is a pointer's target and not a finger's (docs.css says the
     same of its own) — and here it is the only way back in (UIC-16, UIC-26):
     Marie and a Kodu visitor have no menu row to reach the dock from. */
  .ui-dock-handle { min-height: 44px; padding-left: var(--s5); padding-right: var(--s5); }
  /* The panel is the screen already: a press to make it the screen is one that does nothing (UIC-51). */
  .ui-dock-full { display: none; }
}

/* ── the smallest screens there are (UIC-26) ─────────────────────────────── */

/* A watch is 184 wide and 224 tall, and on it the head was more than half the
   screen: a title, a line of subtitle under it, and a row of three presses,
   over a conversation reduced to a sliver. The head is chrome — it says what
   this is, which you know, because you opened it. So below this width the
   subtitle goes, the padding comes in, and the title steps down a size; the
   presses stay, because closing the thing must not become the hard part. */
@media (max-width: 400px) {
  .ui-dock-head { gap: var(--s3); padding: var(--s5) var(--s5) var(--s4); }
  .ui-dock-said { display: none; }
  .ui-dock-title { font-size: var(--t5); }
}

/* Shorter than a phone lying down: the head gives up its border and its
   bottom padding too, so what is left of the screen is the conversation. */
@media (max-height: 420px) {
  .ui-dock-head { padding-block: var(--s4) var(--s3); border-bottom-color: transparent; }
  .ui-dock-said { display: none; }
}

/* ── the dock as the page (UIC-22) ───────────────────────────────────────── */

/* Where the dock *is* the page (`ai.<base>`) it stands in the flow instead of
   fixed beside it: nothing to move aside, no share to walk. The head, the
   fold, the body and the foot are the same four things, laid out as columns
   where the window has room — the fold on the left as the list of what there
   is, the foot on the right as what the assistant can reach — and stacked on
   a phone, the fold covering the conversation when it is asked for, as it
   does in the panel. The page hands it the height it has to fill. */
[data-dock="page"] body { padding-right: 0; }
/* The rows are the panel's own now (UIC-31) and so is the fold's cover; what
   is left here is standing in the flow instead of fixed beside the page —
   and the height the pane hands it, which must beat the panel's own knob or
   this dock is a whole visible viewport tall inside a pane. */
.ui-dock.is-page {
  position: relative;
  top: auto;
  right: auto;
  z-index: auto;
  width: 100%;
  height: 100%;
  min-height: 0;
  border-left: 0;
}
/* The fold and the foot stand as columns on a page, so they breathe as columns. */
.ui-dock.is-page > :is(.ui-dock-past, .ui-dock-foot) { padding: var(--s7) var(--s6); }
/* A page's foot stands only as the third column: under the composer it took a third of a phone, and the head's gear opens the same list. */
.ui-dock.is-page > .ui-dock-foot { display: none; }
/* Its columns are the frame's (UIC-38): the fold is a list (`--list-col`), the
   foot the part beside the thing (`--side-col`), and they step where the
   frame steps — the page's own width, never the window's. */
@container (min-width: 641px) {
  /* Two columns: the fold stands as the list on the left, always, and the
     press that opened it as a cover is put away. A dock with nothing behind
     it keeps the one column. */
  .ui-dock.is-page:has(> .ui-dock-past) {
    grid-template-columns: var(--list-col) minmax(0, 1fr);
    grid-template-areas: "past head" "past body" "past foot";
  }
  /* `!important` answers the tier's own `[hidden]` (UIC-42): on the page the
     fold is a column that stands whatever the cover's press last said. */
  .ui-dock.is-page > .ui-dock-past,
  .ui-dock.is-page > .ui-dock-past[hidden] {
    display: block !important;
    grid-area: past;
    z-index: auto;
    align-self: stretch;
    max-height: none;
    overflow-y: auto;
    border-bottom: 0;
    border-right: 1px solid var(--line);
  }
  .ui-dock.is-page > .ui-dock-head > .ui-dock-past-open { display: none; }
}
@container (min-width: 1081px) {
  /* Three: and the foot — what the assistant can reach — as a column on the
     right, beside the conversation rather than under it. */
  .ui-dock.is-page {
    grid-template-columns: minmax(0, 1fr) var(--side-col);
    grid-template-rows: auto minmax(0, 1fr);
    grid-template-areas: "head foot" "body foot";
  }
  .ui-dock.is-page:has(> .ui-dock-past) {
    grid-template-columns: var(--list-col) minmax(0, 1fr) var(--side-col);
    grid-template-areas: "past head foot" "past body foot";
  }
  .ui-dock.is-page > .ui-dock-foot {
    display: block;
    border-top: 0;
    border-left: 1px solid var(--line);
    overflow-y: auto;
  }
}

/* The gallery (UIC-20, out of KODU-69): one strip that snaps a picture at a
   time, the arrows and the count over it, the thumbnails and the captions
   under it, and the same strip filling the screen in a <dialog>. Scroll-snap
   does the leafing, so a finger, a wheel and the keyboard all work before any
   script does; the script adds the arrows, the jump from a thumbnail, the
   count and the full-screen view. */

/* Never wider than the column it stands in: a caption that cannot break —
   an address, say — would otherwise widen the album to its own length and
   push the picture past the screen's edge, and a strip turning to a longer
   caption jumped wider on every turn (2026-09-07, on a phone). */
.ui-gallery { min-width: 0; max-width: 100%; }
.ui-gal-main {
  width: 100%;
  aspect-ratio: 3 / 2;
  max-height: 480px;
  background: var(--chip);
}
.ui-gal-track, .ui-light-track {
  display: flex;
  width: 100%;
  height: 100%;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  scrollbar-width: none;
  overscroll-behavior-x: contain;
}
.ui-gal-track::-webkit-scrollbar, .ui-light-track::-webkit-scrollbar, .ui-gal-thumbs::-webkit-scrollbar { display: none; }
.ui-gal-track:focus-visible { outline: var(--s1) solid var(--accent); outline-offset: calc(-1 * var(--s1)); }
.ui-gal-shot {
  flex: 0 0 100%;
  width: 100%;
  height: 100%;
  scroll-snap-align: start;
  scroll-snap-stop: always;
  cursor: zoom-in;
}
.ui-gal-shot img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* The arrows over the picture: shown when the pointer is over it, always on a
   screen with no pointer. */
.ui-gal-arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: color-mix(in oklab, var(--surface) 88%, transparent);
  color: var(--ink);
  cursor: pointer;
  opacity: 0;
  transition: opacity .15s ease, border-color .15s ease, color .15s ease;
}
.ui-gal-arrow.is-prev { left: var(--s3); }
.ui-gal-arrow.is-next { right: var(--s3); }
.ui-gal-arrow svg { width: 18px; height: 18px; }
.ui-gal-arrow:hover { border-color: var(--accent); color: var(--accent); }
.ui-gal-main:hover .ui-gal-arrow, .ui-gal-arrow:focus-visible { opacity: 1; }
@media (hover: none) { .ui-gal-arrow { opacity: 1; } }

/* Full screen, with the count on it: one press for "see it big" and "which
   one am I on", in the corner a thumb reaches. */
.ui-gal-full {
  position: absolute;
  right: var(--s3);
  bottom: var(--s3);
  display: flex;
  align-items: center;
  gap: var(--s2);
  height: 32px;
  padding: 0 var(--s3);
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: color-mix(in oklab, var(--surface) 88%, transparent);
  color: var(--ink);
  font: inherit;
  cursor: pointer;
}
.ui-gal-full svg { width: 16px; height: 16px; }
.ui-gal-full:hover { border-color: var(--accent); color: var(--accent); }
.ui-gal-count, .ui-light-count {
  font-family: var(--mono);
  font-size: var(--t3);
  font-variant-numeric: tabular-nums;
}

/* One caption under the strip, the one for the picture in view; the rest
   are there for a reader with no script, who sees the first alone. */
/* `contain: inline-size`: the row's own width is the album's, never its
   words' — a caption's minimum width is otherwise its longest unbreakable
   run, and that is what an address is. */
.ui-gal-captions { margin: 0; min-height: 1.5em; min-width: 0; contain: inline-size; overflow-wrap: anywhere; }
.ui-gal-caption { display: none; margin: 0; color: var(--ink2); font-size: var(--t4); line-height: 1.5; text-wrap: pretty; }
.ui-gal-caption.is-on { display: block; }

.ui-gal-thumbs {
  display: flex;
  gap: var(--s2);
  overflow-x: auto;
  scrollbar-width: none;
}
/* The ring is an inset outline rather than a shadow around the box: the row
   clips nothing that way, and it needs no room kept for it. */
.ui-gal-thumb {
  flex: none;
  width: 84px;
  aspect-ratio: 3 / 2;
  border-radius: var(--r4);
  overflow: hidden;
  opacity: .7;
  outline: var(--s1) solid transparent;
  outline-offset: calc(-1 * var(--s1));
  transition: opacity .15s ease, outline-color .15s ease;
}
.ui-gal-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.ui-gal-thumb:hover { opacity: 1; }
.ui-gal-thumb.is-on { opacity: 1; outline-color: var(--accent); }

/* The dots, for a strip that turns by itself: one a picture, the one in view
   filled and a touch larger, each a press to its picture. */
.ui-gal-dots { display: flex; justify-content: center; gap: var(--s3); padding: var(--s2) 0; }
.ui-gal-dot {
  width: 8px;
  height: 8px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--line);
  cursor: pointer;
  transition: background .15s ease, transform .15s ease;
}
.ui-gal-dot:hover { background: var(--ink3); }
.ui-gal-dot.is-on { background: var(--accent); transform: scale(1.25); }

/* Until the script is there, the controls it serves are not either: the
   strip scrolls on its own and every picture is a link to its file, and a
   dot that leads nowhere is not drawn. */
.ui-gallery:not(.is-live) .ui-gal-arrow, .ui-gallery:not(.is-live) .ui-gal-full, .ui-gallery:not(.is-live) .ui-gal-dots { display: none; }

/* Drawings rather than photographs: contained on paper, not cropped to the
   frame — in the strip, in the thumbnails and on the dark full screen alike,
   since white paper is what they were drawn on whichever scheme the page is
   in. */
.ui-gallery.is-paper .ui-gal-shot img, .ui-gallery.is-paper .ui-gal-thumb img { object-fit: contain; background: var(--paper); }
.ui-gallery.is-paper .ui-gal-shot img { padding: var(--s4); }
.ui-gallery.is-paper .ui-light-shot { background: var(--paper); padding: var(--s6); }

/* The full-screen view: the whole viewport, the picture contained in it, the
   same arrows in the stage's ink, the count at the foot. The stage is a warm
   near-black in both schemes — the picture is the light there. */
.ui-light {
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100vh;
  max-width: none;
  max-height: none;
  margin: 0;
  padding: 0;
  border: 0;
  background: var(--stage);
  color: var(--stage-ink);
}
.ui-light::backdrop { background: var(--stage); }
.ui-light-shot {
  flex: 0 0 100%;
  width: 100%;
  height: 100%;
  object-fit: contain;
  scroll-snap-align: start;
  scroll-snap-stop: always;
  /* A press closes it, the way a press opened it. */
  cursor: zoom-out;
}
.ui-light .ui-gal-arrow, .ui-light-close {
  opacity: 1;
  border-color: var(--stage-line);
  background: var(--stage-veil);
  color: var(--stage-ink);
}
.ui-light .ui-gal-arrow:hover, .ui-light-close:hover { border-color: var(--stage-ink); color: var(--stage-ink); }
.ui-light-close {
  position: absolute;
  top: var(--s3);
  right: var(--s3);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border: 1px solid;
  border-radius: 50%;
  cursor: pointer;
}
.ui-light-close svg { width: 20px; height: 20px; }
.ui-light-count {
  position: absolute;
  left: 50%;
  bottom: var(--s4);
  transform: translateX(-50%);
  padding: var(--s1) var(--s3);
  border-radius: var(--r-pill);
  background: var(--stage-veil);
}
html:has(.ui-light[open]) { overflow: hidden; }
@media (prefers-reduced-motion: reduce) { .ui-gal-track, .ui-light-track { scroll-behavior: auto; } }

/* ── the editor's manner (KODU-110, the tier's since 2026-09-09) ─────────── */

/* A section: a rule over it, its number and name down the left in the
   serif, its controls to the right. The same drawing Kodu's *Lisa kuulutus*
   makes, so a settings surface on any door reads as one of that family.
   No box and no ground: the rule is what separates one from the next.
   Phone first: the name stands over its controls, and beside them only
   where the part itself holds both — a phone, a form's `--prose` column. */
.ui-part {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s5) clamp(var(--s10), 3vw, var(--s13));
  padding-block: clamp(var(--s9), 2.4vw, var(--s11));
  border-top: 1px solid var(--line2);
}
.ui-part:first-child { padding-top: var(--s4); border-top: 0; }
.ui-part > .ui-part-body { flex: 999 1 calc(2 * var(--part-label)); min-width: 0; }
.ui-part-no {
  flex: 1 1 var(--part-label);
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--s3);
  margin: 0;
  font-family: var(--serif);
  font-size: var(--t7);
  font-weight: 500;
  line-height: 1.2;
  color: var(--ink);
}
.ui-part-n {
  font-family: var(--mono);
  font-size: var(--t3);
  font-weight: 500;
  letter-spacing: 0.1em;
  color: var(--mute);
}
/* The foot of the column: what one press will do, and the press. */
.ui-sheet-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s6);
  flex-wrap: wrap;
  padding-top: clamp(var(--s9), 2.4vw, var(--s11));
  border-top: 1px solid var(--line2);
}

/* The rail's contents and your own menu (UIC-38), on the house tokens.

   A phone is the ground (UIC-23): the rail lies down as a bar along the foot
   of the screen, the frame putting it there with `column-reverse`. From 641px
   of the page's own width it stands down the left as a column. The column's
   width is the application's grid track; nothing here decides it. */

.ui-rail-nav {
  flex: none;
  flex-direction: row;
  align-items: center;
  justify-content: space-around;
  gap: 0;
  border-right: 0;
  border-top: 1px solid var(--line);
  /* Installed to a Home Screen the page runs full screen, and the home
     indicator is inside it: the bar steps over, not under. */
  padding: var(--s3) var(--s2) calc(var(--s4) + env(safe-area-inset-bottom));
  position: relative;
}

.ui-rail-brand { display: none; flex: none; }
.ui-rail-mark { display: block; width: calc(var(--s11) - var(--s1)); height: calc(var(--s11) - var(--s1)); }
.ui-rail-mark svg { display: block; width: 100%; height: 100%; }
/* Letters in place of a drawing: a site's initials on the accent. */
.ui-rail-mark.is-letters {
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--r4);
  background: var(--accent);
  color: var(--accent-ink);
  font-family: var(--serif);
  font-size: var(--t5);
  font-weight: 600;
}

.ui-rail-list {
  display: flex;
  flex: 1;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-around;
  gap: var(--s1);
  min-width: 0;
}
.ui-rail-rule, .ui-rail-space { display: none; }

/* An entry is an icon over its word, the tint on the icon's box and never on
   the row: a band behind a centred icon is what makes a column read as a list. */
.ui-rail-item {
  display: flex;
  flex: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--s2);
  min-width: calc(var(--s12) + var(--s2));
  min-height: calc(var(--s12) + var(--s2));
  max-width: 100%;
  color: var(--mute);
  font-size: var(--t2);
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
}
.ui-rail-box {
  position: relative;
  display: flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: var(--s12);
  height: calc(var(--s11) - var(--s1));
  border-radius: var(--r5);
  color: var(--rail-ink);
  transition: background var(--quick), color var(--quick);
}
.ui-rail-box svg { width: var(--s9); height: var(--s9); stroke-width: 1.7; }
.ui-rail-label { max-width: 100%; overflow-wrap: break-word; text-wrap: balance; }
.ui-rail-item:hover .ui-rail-box { background: var(--hover); color: var(--ink); }
.ui-rail-item.is-open { color: var(--ink); font-weight: 600; }
.ui-rail-item.is-open .ui-rail-box { color: var(--ink); }
.ui-rail-item.is-here { color: var(--accent-down); font-weight: 600; }
.ui-rail-item.is-here .ui-rail-box { background: var(--accent-soft); color: var(--accent-down); }
/* The lit tile tints a stroke drawing's first, closed shape under its strokes: the mailbox's duotone, every door's (UIC-42). */
.ui-rail-item.is-here .ui-rail-box svg[fill="none"] > :first-child { fill: currentColor; fill-opacity: .16; }
.ui-rail-item.is-primary { color: var(--accent-down); font-weight: 600; }
.ui-rail-item.is-primary .ui-rail-box,
.ui-rail-item.is-primary:hover .ui-rail-box { background: var(--accent); color: var(--accent-ink); }
/* A plus fills its box edge to edge where the other drawings keep a margin. */
.ui-rail-item.is-primary .ui-rail-box svg { width: var(--s8); height: var(--s8); }

.ui-rail-badge {
  position: absolute;
  top: var(--s1);
  right: var(--s1);
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: var(--s8);
  height: var(--s8);
  padding: 0 var(--s2);
  border-radius: var(--r4);
  background: var(--accent);
  color: var(--accent-ink);
  font-size: var(--t1);
  font-weight: 600;
  line-height: 1;
}
/* A queue of exceptions is the attention tone, not the accent of unread mail. */
.ui-rail-badge.is-attn { background: var(--badge-bg); color: var(--warn-ink); border: 1px solid var(--badge-line); }
.ui-rail-badge.is-quiet { background: var(--line); color: var(--mute); }

/* An entry's sections sit in a tray right under it. Every tray is drawn and
   the shut ones fold to nothing, so opening one is an easing; a shut tray is
   hidden too, which takes its links out of the tab order once it has folded.
   On a phone the open one is a row of its own over the entries. */
.ui-rail-tray {
  display: grid;
  grid-template-rows: 0fr;
  visibility: hidden;
  order: -1;
  flex-basis: 100%;
  border-bottom: 1px solid transparent;
  transition: grid-template-rows .24s ease, margin .24s ease, padding .24s ease,
              border-color .24s ease, background-color .24s ease, visibility 0s linear .24s;
}
.ui-rail-tray.is-open {
  grid-template-rows: 1fr;
  visibility: visible;
  border-bottom-color: var(--hair);
  padding-bottom: var(--s2);
  margin-bottom: var(--s2);
  transition-delay: 0s;
}
.ui-rail-tray-in {
  display: flex;
  align-items: center;
  justify-content: space-around;
  gap: var(--s1);
  min-height: 0;
  overflow: hidden;
}
.ui-rail-tray .ui-rail-box svg { width: calc(var(--s9) - var(--s1)); height: calc(var(--s9) - var(--s1)); }
@media (prefers-reduced-motion: reduce) {
  .ui-rail-tray, .ui-rail-tray.is-open { transition: none; }
}

.ui-rail-foot {
  display: flex;
  flex: none;
  align-items: center;
  justify-content: center;
  gap: var(--s1);
  padding: 0 var(--s2);
  align-self: flex-end;
}

/* ── the phone's menu (KODU-65) ──────────────────────────────────────────── */

/* A rail with more than a bar holds: the bar is the mark, the menu and your
   face, and everything else waits in the menu — the scheme included. */
.ui-rail-menu { display: none; }
@container (max-width: 640px) {
  /* Three even thirds — the mark, the menu, the face — each centred in its
     own, so the bar is level and nothing hugs an edge. */
  .ui-rail-nav[data-phone="menu"] { justify-content: space-between; }
  .ui-rail-nav[data-phone="menu"] .ui-rail-brand { display: flex; flex: 1; justify-content: center; }
  .ui-rail-nav[data-phone="menu"] .ui-rail-list { display: none; }
  .ui-rail-nav[data-phone="menu"] .ui-rail-foot { flex: 2; align-self: center; justify-content: space-around; padding: 0; }
  .ui-rail-nav[data-phone="menu"] .ui-rail-foot > :not(.ui-rail-menu, .ui-you) { display: none; }
  .ui-rail-nav[data-phone="menu"] .ui-rail-menu { display: block; }
  /* The scheme's ring stands in the open menu's head, left of its ✕: a phone reaches it on every door. */
  .ui-rail-nav[data-phone="menu"]:has(> .ui-rail-foot > .ui-rail-menu[open]) .ui-rail-foot > .ui-theme {
    display: flex;
    position: fixed;
    z-index: 71;
    top: calc((var(--s13) + var(--s4) - var(--s11)) / 2);
    right: calc(var(--s7) + var(--s9) + var(--s6));
  }
}
.ui-rail-menu > summary { list-style: none; }
.ui-rail-menu > summary::-webkit-details-marker { display: none; }
.ui-rail-menu-shut { display: none; }
/* Open, the summary is the sheet's head and the list is the screen under it. */
.ui-rail-menu[open] > .ui-rail-menu-open {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 70;
  flex-direction: row;
  justify-content: space-between;
  min-height: calc(var(--s13) + var(--s4));
  max-width: none;
  padding: 0 var(--s7);
  background: var(--surface);
  border-bottom: 1px solid var(--line);
}
.ui-rail-menu[open] > .ui-rail-menu-open .ui-rail-box { display: none; }
.ui-rail-menu[open] > .ui-rail-menu-open .ui-rail-label { font-size: var(--t7); font-weight: 600; color: var(--ink); text-align: left; }
.ui-rail-menu[open] > .ui-rail-menu-open .ui-rail-menu-shut { display: block; font-size: var(--t8); color: var(--ink3); }
.ui-rail-menu-pop {
  position: fixed;
  inset: calc(var(--s13) + var(--s4)) 0 0;
  z-index: 70;
  display: flex;
  flex-direction: column;
  gap: var(--s1);
  overflow-y: auto;
  padding: var(--s5) var(--s5) calc(var(--s7) + env(safe-area-inset-bottom));
  background: var(--surface);
}
.ui-rail-menu-row {
  display: flex;
  align-items: center;
  gap: var(--s5);
  min-height: var(--s13);
  padding: 0 var(--s5);
  border-radius: var(--r5);
  color: var(--ink2);
  font-size: var(--t6);
  font-weight: 500;
  text-decoration: none;
}
.ui-rail-menu-row.is-here { color: var(--accent); background: var(--accent-soft); }
.ui-rail-menu-icon { display: flex; flex: none; color: var(--mute); }
.ui-rail-menu-icon svg { width: var(--s9); height: var(--s9); }
.ui-rail-menu-rule { height: 1px; margin: var(--s2) var(--s3); background: var(--hair); }

/* ── your face and its menu ──────────────────────────────────────────────── */

/* The menu is placed against the rail and not against the face: on a phone a
   menu hung off a 44px target near the edge lands half inside the screen, and
   the bar is the full width, so its top edge is the offset nobody has to keep. */
.ui-you { position: static; }
.ui-you > summary { list-style: none; }
.ui-you > summary::-webkit-details-marker { display: none; }
.ui-you-open {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: calc(var(--s12) + var(--s2));
  min-height: calc(var(--s12) + var(--s2));
  border-radius: var(--r4);
  color: var(--ink3);
  cursor: pointer;
}
.ui-you-open:hover, .ui-you[open] > .ui-you-open { background: var(--chip); color: var(--ink); }
.ui-you-glyph { display: flex; }
.ui-you-glyph svg { width: var(--s9); height: var(--s9); }
/* Your colour, off your address and the same on every door (UI-19): only the
   hue rides on the element, and how light it is drawn is the scheme's. */
.ui-you-face {
  --ui-hue: 265;
  position: relative;
  display: flex;
  flex: none;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  width: calc(var(--s11) - var(--s1));
  height: calc(var(--s11) - var(--s1));
  border-radius: var(--r-pill);
  background: oklch(var(--av-bg) var(--ui-hue));
  color: oklch(var(--av-fg) var(--ui-hue));
  font-size: var(--t3);
  font-weight: 700;
  letter-spacing: .02em;
  line-height: 1;
}
.ui-you-photo { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.ui-you-pop {
  position: absolute;
  z-index: 60;
  right: var(--s4);
  bottom: calc(100% + var(--s4));
  display: flex;
  flex-direction: column;
  width: max-content;
  min-width: calc(var(--s13) * 4.5);
  max-width: calc(100vw - var(--s8));
  padding: var(--s2);
  border: 1px solid var(--line);
  border-radius: var(--r6);
  background: var(--surface);
  box-shadow: var(--pop);
}
.ui-you-who { display: flex; flex-direction: column; gap: var(--s1); padding: var(--s3) var(--s5) var(--s4); overflow: hidden; }
.ui-you-name, .ui-you-address { overflow: hidden; text-overflow: ellipsis; }
.ui-you-name { color: var(--ink); font-size: var(--t5); font-weight: 600; }
.ui-you-address { color: var(--mute); font-family: var(--mono); font-size: var(--t3); }
.ui-you-rule { height: 1px; margin: var(--s2) var(--s3); background: var(--hair); }
.ui-you-form { display: contents; }
.ui-you-row {
  display: flex;
  align-items: center;
  gap: var(--s5);
  width: 100%;
  min-height: calc(var(--s11) + var(--s2));
  padding: 0 var(--s5);
  border: 0;
  border-radius: var(--r3);
  background: none;
  color: var(--ink2);
  font: inherit;
  font-size: var(--t5);
  text-align: left;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}
.ui-you-row:hover { background: var(--hover); color: var(--ink); }
.ui-you-row.is-here { color: var(--accent-down); font-weight: 600; }
.ui-you-icon { display: flex; flex: none; color: var(--mute); }
.ui-you-icon svg { width: calc(var(--s8) + var(--s1)); height: calc(var(--s8) + var(--s1)); }
.ui-you-row:hover .ui-you-icon, .ui-you-row.is-here .ui-you-icon { color: currentColor; }

/* ── a desk: the column down the left ────────────────────────────────────── */

@container (min-width: 641px) {
  .ui-rail-nav {
    flex-direction: column;
    justify-content: flex-start;
    gap: var(--s8);
    padding: var(--s9) 0 var(--s8);
    border-top: 0;
    border-right: 1px solid var(--line);
  }
  .ui-rail-brand { display: flex; }
  .ui-rail-list {
    flex: none;
    flex-direction: column;
    flex-wrap: nowrap;
    justify-content: flex-start;
    align-self: stretch;
    --ui-rail-gap: var(--s7);
    gap: var(--ui-rail-gap);
  }
  /* The first list is what gives way on a short window, and it scrolls
     inside itself: the others and the foot must not go off the bottom. */
  .ui-rail-brand + .ui-rail-list { flex: 0 1 auto; min-height: 0; overflow-y: auto; scrollbar-width: none; }
  .ui-rail-brand + .ui-rail-list::-webkit-scrollbar { display: none; }
  .ui-rail-rule { display: block; flex: none; width: calc(var(--s11) + var(--s2)); height: 1px; background: var(--line); }
  .ui-rail-space { display: block; flex: 1 1 auto; min-height: var(--s6); }
  .ui-rail-item { min-width: 0; min-height: 0; }
  /* A word longer than the column breaks rather than crossing into the pane.
     Only in the list, which is the column's width: a tray is its contents'. */
  .ui-rail-list > .ui-rail-item { max-width: calc(100% - var(--s4)); }
  .ui-rail-box { width: calc(var(--s12) + var(--s2)); height: calc(var(--s11) + var(--s3)); }
  /* The sections stand on a soft panel as wide as the column, never as wide
     as what is in it: a box sized by its words is centred differently by
     every engine, and a border around it is what read as crooked. */
  .ui-rail-tray {
    order: 0;
    flex-basis: auto;
    align-self: stretch;
    margin: calc(var(--ui-rail-gap) * -1) var(--s4) 0;
    padding: 0;
    border: 0;
    border-radius: var(--r6);
  }
  .ui-rail-tray.is-open {
    margin: calc(var(--s3) - var(--ui-rail-gap)) var(--s4) 0;
    padding: var(--s4) 0;
    background: var(--hover);
  }
  .ui-rail-tray .ui-rail-item:not(.is-here):hover .ui-rail-box { background: var(--chip); }
  .ui-rail-tray-in { flex-direction: column; justify-content: flex-start; gap: var(--s4); }
  .ui-rail-foot { flex-direction: column; gap: var(--s5); padding: 0; align-self: center; }
  /* The column is too narrow to hold a menu, so it stands clear of the
     column on the right, level with the foot — why the rail may not clip. */
  .ui-you-open { min-width: 0; min-height: 0; width: calc(var(--s12) + var(--s2)); height: calc(var(--s11) + var(--s3)); }
  .ui-you-pop { right: auto; bottom: var(--s8); left: calc(100% + var(--s3)); }
  /* A laptop's window once its browser has drawn a bar: the gaps close up
     before the first list has to scroll. */
  @media (max-height: 820px) {
    .ui-rail-nav { gap: var(--s4); }
    .ui-rail-list { --ui-rail-gap: var(--s5); }
  }
}

/* The foot of every public screen (UIC-39), on the house tokens.

   Three bands, each quieter than the one above it: the columns a reader might
   want, a hairline, then the machine facts nobody reads until they need them.
   Not a card — a rule and space. The box spans what holds it; the bands stop
   at the page's measure. Where a frame stands the foot is the application's
   class, never a redrawing of it. */

.ui-foot {
  display: flex;
  flex-direction: column;
  gap: clamp(var(--s8), 2vw, var(--s10));
  width: 100%;
}
.ui-foot-cols, .ui-foot-rule, .ui-foot-line {
  width: 100%;
  max-width: var(--measure);
  margin-inline: auto;
}

/* `auto-fit` with a floor rather than a breakpoint: one column on a phone,
   more as the room allows, the heads lined up on their left edges. */
.ui-foot-cols {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(calc(var(--s12) * 5), 1fr));
  gap: var(--s9) var(--s12);
}
.ui-foot-col { display: flex; flex-direction: column; gap: var(--s4); min-width: 0; }
/* The smallest tracked-out type on the page, so a head reads as a label. */
.ui-foot-head {
  margin: 0;
  color: var(--ink3);
  font-size: var(--t3);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.ui-foot-list { display: flex; flex-direction: column; gap: var(--s3); margin: 0; padding: 0; list-style: none; }

/* Close together, so tighter than the ladder's leading; underlined on hover
   only, under the text, or the column would be a fence. */
.ui-foot-link {
  color: var(--ink3);
  font-size: var(--t5);
  line-height: 1.3;
  text-decoration: none;
  text-underline-offset: 3px;
}
.ui-foot-link:hover { color: var(--accent); text-decoration: underline; }
.ui-foot-link.is-on { color: var(--ink); font-weight: 600; }
/* A press in a link's dress: it loses the button's box and keeps the word. */
button.ui-foot-link { width: auto; padding: 0; border: 0; background: none; font: inherit; font-size: var(--t5); cursor: pointer; }

/* A company's facts keep the register machine facts wear: mono, small,
   quiet — the name itself a step darker, being what the numbers check. */
.ui-foot-fact { color: var(--mute); font-family: var(--mono); font-size: var(--t3); line-height: 1.35; }
.ui-foot-fact:first-child { color: var(--ink3); }

.ui-foot-rule { height: 1px; margin-block: 0; border: 0; background: var(--hair); }

.ui-foot-line {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s4) var(--s10);
  color: var(--mute);
  font-family: var(--mono);
  font-size: var(--t3);
}
.ui-foot-door { min-width: 0; overflow-wrap: anywhere; }
.ui-foot-by { display: flex; align-items: baseline; gap: var(--s3); margin: 0; }
/* The platform's name a step darker than the words before it: it is the link. */
.ui-foot-platform {
  display: inline-flex;
  align-items: center;
  gap: .4em;
  color: var(--ink3);
  font-weight: 500;
  text-decoration: none;
  text-underline-offset: 3px;
}
.ui-foot-platform:hover { color: var(--accent); text-decoration: underline; }
.ui-foot-mark { display: inline-flex; width: 1.1em; height: 1.1em; }
.ui-foot-mark svg { width: 100%; height: 100%; }

/* The storefront's sheet at /theme.css, the console's and Platform's pages' too, on the tier's tokens and controls (UI-17, UIC-42). */

/* ── the ground (the elements' reset is the tier's, `base.css`) ────────── */

html, body { height: 100%; }
/* A site's own type (THEME-7), the tier's where no site stands behind the page (UIC-42). */
body {
  background: var(--surface);
  font-size: var(--body-size, var(--t5));
  line-height: var(--body-lh, var(--lh-body));
}
img { display: block; }
h1, h2, h3, p { margin: 0; }
code, .mono-num, .code { font-family: var(--mono); }

/* ── layout ─────────────────────────────────────────────────────────────── */

.container { width: 100%; max-width: var(--container, 1360px); margin-inline: auto; padding-inline: 1.75rem; }
.container-narrow { width: 100%; max-width: 720px; margin-inline: auto; padding-inline: 1.75rem; }
.container-tight { width: 100%; max-width: 420px; margin-inline: auto; padding-inline: 1.75rem; }
/* A phone's sign-in is mostly card: the desktop's 4rem of vertical air and
   1.75rem gutters ate a third of an iPhone mini's screen (2026-09-01). */
@media (max-width: 480px) {
  .container-tight { padding-inline: 1rem; }
  .center-page, .center-page-start { padding-block: 1.25rem; }
  .container-tight .panel { padding: 1rem; }
}
.center-page { min-height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; padding-block: 3rem; }
.center-page-start { min-height: 100%; display: flex; flex-direction: column; justify-content: center; padding-block: 4rem; }

.header {
  position: sticky; top: 0; z-index: 10;
  background: color-mix(in oklab, var(--surface) var(--nav-alpha, 85%), transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line);
  max-width: var(--nav-max, none); margin-inline: auto;
}
.header-inner { display: flex; align-items: center; justify-content: space-between; gap: 1.5rem; padding-block: 1.25rem; }
.brand-group { display: flex; align-items: center; gap: .75rem; min-width: 0; }
.brand { font-weight: 600; letter-spacing: -0.01em; font-size: 1rem; }
/* The company's mark beside its name, pressed as one thing wherever comm.ee
   is written. */
.brand-home { display: inline-flex; align-items: center; gap: .45em; color: inherit; text-decoration: none; }
.brand-mark { display: inline-flex; width: 1.15em; height: 1.15em; }
.brand-mark svg { width: 100%; height: 100%; }
.brand-logo { display: block; height: 1.6rem; width: auto; max-width: 12rem; object-fit: contain; }
/* Only the owner sees it, so it is quiet until reached for. */
.console-link { --ui-round-size: 2rem; opacity: .55; transition: opacity .2s; }
.console-link:hover, .console-link:focus-visible { opacity: 1; }
.nav { display: flex; align-items: center; gap: 1.5rem; flex-wrap: wrap; }
.nav a { color: var(--ink3); font-size: 0.875rem; transition: color .15s; }
.nav a:hover { color: var(--ink); }
.nav-links, .nav-extras { display: flex; align-items: center; gap: 1.5rem; flex-wrap: wrap; }

/* Past a handful of pages the rest wait under "More" — a sheet, not a wall. */
.nav-more { position: relative; }
.nav-more summary {
  list-style: none; cursor: pointer; color: var(--ink3); font-size: 0.875rem;
  transition: color .15s; user-select: none;
}
.nav-more summary::-webkit-details-marker { display: none; }
.nav-more summary::after { content: " ▾"; font-size: 0.7em; }
.nav-more summary:hover, .nav-more[open] summary { color: var(--ink); }
.nav-more-sheet {
  position: absolute; left: 0; top: calc(100% + 0.75rem); z-index: 30;
  display: flex; flex-direction: column; gap: 0.15rem;
  min-width: 13rem; max-height: 60vh; overflow-y: auto;
  padding: 0.6rem; background: var(--surface);
  border: 1px solid var(--line); border-radius: 0.6rem;
  box-shadow: 0 12px 34px rgb(0 0 0 / 0.12);
}
.nav-more-sheet a { padding: 0.35rem 0.6rem; border-radius: 0.4rem; }
.nav-more-sheet a:hover { background: var(--field); }

/* ── the header's theme answers (THEME-9). The defaults wear no class, so an
   unthemed header is exactly the block above. ─────────────────────────────── */

.header.nav-static { position: static; }
.header.nav-noline { border-bottom-color: transparent; }
.header.navpad-snug .header-inner { padding-block: .55rem; }
.header.navpad-tall .header-inner { padding-block: 2rem; }

.header.navlinks-left .nav, .header.navlinks-center .nav { flex: 1; }
.header.navlinks-left .nav .nav-links { flex: 1; justify-content: flex-start; }
.header.navlinks-center .nav .nav-links { flex: 1; justify-content: center; }

.header.nav-beside .header-inner { justify-content: flex-start; gap: 2rem; }
.header.nav-beside .nav { flex: 1; }
.header.nav-beside .nav .nav-extras { margin-left: auto; }
.header.nav-centre .header-inner,
.header.nav-stack .header-inner { flex-direction: column; gap: .6rem; }
.header.nav-centre .header-inner { align-items: center; text-align: center; }
.header.nav-stack .header-inner { align-items: flex-start; }
.header.nav-centre .nav, .header.nav-stack .nav { width: 100%; }
.header.nav-centre .nav .nav-links { flex: 1; justify-content: center; }
.header.nav-stack .nav .nav-links { flex: 1; justify-content: flex-start; }
.header.nav-centre .nav .nav-extras, .header.nav-stack .nav .nav-extras { margin-left: auto; }

.header.navbg-ink { background: color-mix(in oklab, var(--solid) var(--nav-alpha, 85%), transparent); color: var(--solid-ink); }
/* A telephone's masthead is one row (GAP-308): the name does not break in
   two and the links and the account press do not drop under it — at 375 px
   the storefront was a masthead of three rows for two links. The links are
   allowed to be small before they are allowed to wrap. */
@media (max-width: 480px) {
  .header-inner { gap: .75rem; }
  .brand { white-space: nowrap; font-size: .95rem; }
  .nav, .nav-links, .nav-extras { flex-wrap: nowrap; gap: .85rem; }
  .nav a { font-size: .8rem; white-space: nowrap; }
  .header.nav-centre .header-inner, .header.nav-stack .header-inner { gap: .4rem; }
}
.header.navbg-ink .nav a { color: color-mix(in oklab, var(--solid-ink) 72%, transparent); }
.header.navbg-ink .nav a:hover, .header.navbg-ink .nav a.active { color: var(--solid-ink); }
.header.navbg-accent { background: color-mix(in oklab, var(--accent) var(--nav-alpha, 85%), transparent); color: var(--accent-ink); }
.header.navbg-accent .nav a { color: color-mix(in oklab, var(--accent-ink) 75%, transparent); }
.header.navbg-accent .nav a:hover, .header.navbg-accent .nav a.active { color: var(--accent-ink); }
.header.navbg-clear { background: transparent; backdrop-filter: none; border-bottom-color: transparent; }

.footer { margin-top: 5rem; border-top: 1px solid var(--line); padding-block: 2rem; color: var(--mute); font-size: 0.75rem; max-width: var(--footer-max, none); margin-inline: auto; }

.sb-root { max-width: var(--sections-max, none); margin-inline: auto; }

.section { margin-top: calc(3.5rem * var(--space, 1)); }
.section-tight { margin-top: calc(2.5rem * var(--space, 1)); }

/* ── type ───────────────────────────────────────────────────────────────── */

/* An eyebrow is a label on a machine reading, so it is set in the mono face
   at the size the design gives it, not in small caps of the running text. */
.eyebrow { font-family: var(--mono); text-transform: uppercase; letter-spacing: .08em; font-size: .65rem; color: var(--mute); }
/* Headings are the serif, running text is the sans. The pairing is the whole
   look — a page set entirely in one of them reads as a form. */
.h1 { font-family: var(--serif); font-size: clamp(1.75rem, 3.5vw, var(--h1-max, 2.5rem)); font-weight: 500; letter-spacing: -0.02em; line-height: 1.15; }
.h2 { font-family: var(--serif); font-size: calc(var(--h1-max, 2.5rem) / 2); font-weight: 500; letter-spacing: -0.015em; }
.h3 { font-size: .95rem; font-weight: 600; letter-spacing: -0.01em; }
.lede { margin-top: .75rem; color: var(--ink3); max-width: 42rem; }
.muted { color: var(--ink3); }
.faint { color: var(--mute); font-size: .8rem; }
.tiny { font-size: .7rem; }
.mono-num { font-variant-numeric: tabular-nums; }
.link { color: var(--accent); text-decoration: underline; text-underline-offset: .2em; }
.link:hover { opacity: .8; }
.code { background: var(--field); border-radius: var(--r2); padding: .1rem .4rem; font-size: .85em; }

/* ── spacing helpers ────────────────────────────────────────────────────── */

.mt-1 { margin-top: .25rem; } .mt-2 { margin-top: .5rem; } .mt-3 { margin-top: .75rem; }
.mt-4 { margin-top: 1rem; } .mt-5 { margin-top: 1.25rem; } .mt-6 { margin-top: 1.5rem; }
.mt-8 { margin-top: 2rem; } .mt-10 { margin-top: 2.5rem; }
.mb-4 { margin-bottom: 1rem; } .mb-6 { margin-bottom: 1.5rem; }

/* ── grid / cards ───────────────────────────────────────────────────────── */

.grid-products { display: grid; gap: 1.5rem; grid-template-columns: 1fr; }
@media (min-width: 640px) { .grid-products { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .grid-products { grid-template-columns: repeat(3, 1fr); } }

.card {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.25rem;
  background: var(--surface);
  transition: border-color .15s;
}
.card:hover { border-color: var(--mute); }
.card-raised { background: var(--field); box-shadow: var(--shadow); }

.card-media { aspect-ratio: 4 / 3; width: 100%; border-radius: var(--radius-img, calc(var(--radius) - 3px)); background: var(--field); object-fit: cover; }
.card-media-empty { aspect-ratio: 4 / 3; width: 100%; border-radius: var(--radius-img, calc(var(--radius) - 3px)); background: var(--field); display: flex; align-items: center; justify-content: center; color: var(--mute); font-size: .75rem; }

.price { margin-top: .75rem; font-weight: 600; }

.empty { padding: 4rem 0; text-align: center; color: var(--mute); font-size: .875rem; }
.empty-box { border: 1px dashed var(--line); border-radius: var(--radius); padding: 3.5rem 1.5rem; text-align: center; }

.cards-stack > * + * { margin-top: var(--gap, 1.25rem); }

/* ── forms ──────────────────────────────────────────────────────────────── */

.panel { border: 1px solid var(--line); border-radius: var(--radius); padding: 1.5rem; background: var(--field); box-shadow: var(--shadow); }
.form > * + * { margin-top: 1rem; }
/* ── pills / alerts (a status is `ui::chip`, the tier's) ────────────────── */

.pill { display: inline-flex; align-items: center; gap: .4rem; border: 1px solid var(--line); border-radius: var(--r-pill); padding: .3rem .7rem; font-size: .75rem; }

.alert { padding: .65rem .9rem; border-radius: calc(var(--radius) - 3px); font-size: .85rem; }
.alert-warning { background: var(--warn-bg); color: var(--warn-ink); }
.alert-danger { background: var(--danger-soft); color: var(--danger); }
/* UI-33: the one way on out of a refusal, in the banner that states it. */
.alert a { color: inherit; font-weight: 600; text-decoration: underline; text-underline-offset: .2em; }

/* ── misc components ───────────────────────────────────────────────────── */
/* A separator between two ways of signing in. It only means anything with
   something on both sides, so it lives inside the block that holds them. */
.signin-or { margin: 1rem 0; color: var(--mute); }
.link-button { border: 0; background: none; padding: 0; font: inherit; color: var(--accent); cursor: pointer; text-decoration: underline; }

.stats-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: .75rem; }
@media (min-width: 640px) { .stats-grid { grid-template-columns: repeat(5, 1fr); } }
.stat { border: 1px solid var(--line); border-radius: var(--radius); padding: .875rem 1rem; }
.stat-value { font-size: 1.5rem; font-weight: 600; }
.stat-label { font-size: .68rem; text-transform: uppercase; letter-spacing: .05em; color: var(--ink3); }

details > summary { cursor: pointer; list-style: none; }
details > summary::-webkit-details-marker { display: none; }

/* The staged picture strip a record's form shows is the tier's (`.ui-media-strip`, `.ui-thumb`, UIC-42). */

/* ── storefront: lightbox extras (thumbs, zoom) ────────────────────────── */

.lightbox-thumbs { display: flex; gap: .6rem; padding-top: .75rem; flex-wrap: wrap; }
.lightbox-thumb {
  width: 4rem; height: 4rem; object-fit: cover; border-radius: var(--r3);
  opacity: .5; cursor: pointer; border: 2px solid transparent;
  transition: opacity .15s, border-color .15s;
}
.lightbox-thumb:hover { opacity: .85; }
.lightbox-thumb.active { opacity: 1; border-color: var(--ink); }

/* ── storefront: chat widget ────────────────────────────────────────────── */

.chat-widget-toggle {
  position: fixed; right: 1.5rem; bottom: 1.5rem; z-index: 90;
  width: 3.25rem; height: 3.25rem; border-radius: var(--r-pill); border: none;
  background: var(--solid); color: var(--solid-ink);
  font-size: 1.3rem; cursor: pointer; box-shadow: var(--shadow);
  display: flex; align-items: center; justify-content: center;
}
.chat-widget-dot { position: absolute; top: .1rem; right: .1rem; width: .6rem; height: .6rem; border-radius: var(--r-pill); background: var(--danger); }

.chat-widget-panel {
  position: fixed; right: 1.5rem; bottom: 5.25rem; z-index: 90;
  width: min(22rem, calc(100vw - 3rem)); max-height: min(30rem, calc(100vh - 8rem));
  display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow); overflow: hidden;
}
.chat-widget-header { padding: .75rem 1rem; border-bottom: 1px solid var(--line); font-weight: 600; font-size: .85rem; display: flex; justify-content: space-between; align-items: center; }
.chat-widget-body { flex: 1; overflow-y: auto; padding: .75rem 1rem; display: flex; flex-direction: column; gap: .5rem; min-height: 8rem; }
.chat-widget-bubble { max-width: 80%; padding: .5rem .7rem; border-radius: var(--radius); font-size: .82rem; }
.chat-widget-bubble-me { align-self: flex-end; background: var(--solid); color: var(--solid-ink); }
.chat-widget-bubble-them { align-self: flex-start; background: var(--field); }
.chat-widget-footer { border-top: 1px solid var(--line); padding: .6rem; }
.chat-widget-footer form { display: flex; gap: .4rem; }

/* ── layout slots ───────────────────────────────────────────────────────── */

/* A slot holds sections, so it needs no styling of its own beyond saying
   where it ends and the page begins. The sections inside carry their own
   arrangement and placement, exactly as a page's do (LAYOUT-2). */
.layout-slot { display: flex; flex-direction: column; }
.layout-header { margin-bottom: 1.5rem; padding-bottom: 1rem; border-bottom: 1px solid var(--line); }
.layout-footer { margin-top: 1.5rem; padding-top: 1rem; border-top: 1px solid var(--line); }

/* LAYOUT-7: where the page goes, on a layout drawn on its own. It is an
   outline rather than a box with a fill, because it is the one thing on the
   page that is not there — a solid tile reads as content. */
.sb-placeholder {
  display: flex; align-items: center; justify-content: center; gap: .6rem;
  margin: 1.25rem 0; padding: 2.5rem 1rem;
  border: 2px dashed var(--line); border-radius: var(--radius);
  color: var(--mute); font-size: .85rem; letter-spacing: .01em;
}
.sb-placeholder-icon { width: 1.1rem; height: 1.1rem; }

/* Current page in the site nav. */
.nav a.active { color: var(--ink); font-weight: 600; }
.brand.active { text-decoration: none; }

/* ── gallery (masonry) ──────────────────────────────────────────────────── */

/* A grid rather than CSS columns.
   `columns` balances: with four products across three tracks it fills two and
   leaves the third empty, so a small shop rendered as a lopsided half-page.
   `auto-fill` uses every track there is room for, and `align-items: start`
   keeps each tile at its picture's own height rather than stretching it to
   the tallest in the row — which is the part of masonry worth having. */
.gallery {
  display: grid; gap: 2.5rem; align-items: start;
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
}
/* A tile is an `<a>` to the product's own page (COMM-20) and behaves like one
   for anybody who asks the browser for a link — so it wears no link colour and
   no underline of its own. */
.gallery-item {
  display: block; width: 100%; position: relative;
  border: none; padding: 0; background: none; cursor: pointer;
  color: inherit; text-align: left; text-decoration: none;
}
/* A minimum height and a background so an image that has not loaded, or a
   product that has none, still occupies the space it will take — otherwise
   the masonry columns collapse and the page jumps as pictures arrive. */
.gallery-item img {
  width: 100%; height: auto; display: block; border-radius: var(--radius-img, 2px);
  min-height: 8rem; background: var(--field);
}
.gallery-empty {
  aspect-ratio: 4 / 5; border-radius: var(--r1); background: var(--field);
  display: flex; align-items: center; justify-content: center;
  color: var(--mute); font-size: .75rem;
}
/* The name and the price share a line while the tile has room for both, and
   the price drops under the name when it has not — a six-column grid on a
   phone is a tile a word wide, and a price that stays on the line is drawn
   over the name (2026-09-12). */
.gallery-item .gallery-caption {
  display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between;
  gap: .15rem .75rem; margin-top: .6rem; font-size: .8rem; text-align: left;
}
.gallery-item .gallery-caption .name { font-weight: 600; min-width: 0; overflow-wrap: anywhere; }
.gallery-item .gallery-caption .name p { display: inline; margin: 0; }
.gallery-item .gallery-caption .price { margin-top: 0; color: var(--ink3); font-weight: 400; white-space: nowrap; }

/* ── properties: the badge on a card, and the bar over a wall (COMM-22) ─── */

/* Over the picture, not under the name: what a card says about a product is
   read while the eye is still on the picture. */
.gallery-badges {
  position: absolute; top: .5rem; left: .5rem; z-index: 1;
  display: flex; flex-wrap: wrap; gap: .25rem; max-width: calc(100% - 1rem);
}
.badge-soft {
  padding: .1rem .4rem; border-radius: var(--r-pill);
  background: color-mix(in oklab, var(--surface) 88%, transparent);
  color: var(--ink2); font-size: .65rem; font-weight: 600; line-height: 1.5;
  backdrop-filter: blur(4px);
}

/* Every control is a link, so a narrowed shop is an address (COMM-22). */
.facets {
  display: flex; flex-wrap: wrap; align-items: center; gap: .75rem 1.25rem;
  margin-top: 1.25rem; padding-block: .75rem;
  border-block: 1px solid var(--line);
}
.facet { display: flex; flex-wrap: wrap; align-items: center; gap: .35rem; }
.facet-name {
  font-family: var(--mono); font-size: .62rem; text-transform: uppercase;
  letter-spacing: .08em; color: var(--mute); margin-right: .15rem;
}
.facet-option {
  padding: .2rem .6rem; border-radius: var(--r-pill);
  border: 1px solid var(--line); color: var(--ink3);
  font-size: .78rem; transition: border-color .15s, color .15s, background .15s;
}
.facet-option:hover { border-color: var(--mute); color: var(--ink); }
.facet-option.is-on { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.facet-count { margin-left: auto; color: var(--mute); font-size: .75rem; }
.facet-clear { margin-left: .6rem; color: var(--accent); text-decoration: underline; text-underline-offset: .2em; }
.gallery-item:hover .gallery-caption .name { text-decoration: underline; text-underline-offset: .2em; }

/* ── a wall's other pages (COMM-21) ─────────────────────────────────────── */

.sb-pager { display: flex; align-items: baseline; gap: 1.25rem; margin-top: 2.5rem; }
.sb-pager-count { color: var(--mute); font-size: .8rem; }

/* ── a product's own page (COMM-20) ─────────────────────────────────────── */

.product { display: grid; gap: 2.5rem; padding-block: 3rem; }
@media (min-width: 900px) {
  .product { grid-template-columns: 1fr 1fr; gap: 3.5rem; align-items: start; }
}
.product-shot img {
  width: 100%; height: auto; display: block;
  border-radius: var(--radius-img, 2px); background: var(--field);
}
.product-thumbs { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: .75rem; }
.product-thumb {
  width: 4rem; padding: 0; background: none; cursor: pointer;
  border: 1px solid transparent; border-radius: var(--r1);
}
.product-thumb.active { border-color: var(--ink); }
.product-thumb img { width: 100%; height: auto; display: block; border-radius: var(--r1); }
.product-name p { display: inline; margin: 0; }
.product-price { font-size: 1.25rem; font-weight: 600; margin-top: 1rem; }
#product-cart-slot { margin-top: 1.5rem; }
.product-desc { margin-top: 1.5rem; color: var(--ink3); }
.product-desc p + p { margin-top: .75rem; }
.product-comments {
  max-width: 44rem; margin: 0 auto 4rem;
  padding-top: 2rem; border-top: 1px solid var(--line);
}

/* ── the blog (BLOG-2, BLOG-4) ──────────────────────────────────────────── */

.post { padding-block: 3rem; }
.post-cover { width: 100%; height: auto; display: block; border-radius: var(--r1); margin-bottom: 2rem; }
.post-date { margin-top: .5rem; }
.post-body { margin-top: 2rem; color: var(--ink3); }
.post-body p + p { margin-top: .75rem; }
.post-comments { padding-top: 2rem; border-top: 1px solid var(--line); margin-bottom: 4rem; }

.post-list { display: grid; gap: 2.5rem; }
@media (min-width: 700px) { .post-list { grid-template-columns: 1fr 1fr; } }
.post-card { display: grid; gap: .35rem; color: inherit; text-decoration: none; }
.post-card-cover {
  width: 100%; height: auto; display: block;
  border-radius: var(--r1); background: var(--field); margin-bottom: .5rem;
}
.post-card-title { font-size: 1.25rem; font-weight: 600; }
.post-card-excerpt { color: var(--ink3); }

/* ── lightbox ───────────────────────────────────────────────────────────── */

/*
   The picture first, edge to edge, and everything you decide with underneath
   it in one centred column.

   This replaced a two-column layout that put the picture in a rounded card
   beside a details panel. That is a good shape for a spec sheet and the wrong
   one for a thing that is looked at: the picture was the smaller half of the
   screen, boxed, on a page background. A band the full width of the window on
   black is the picture being the subject.

   The band is 70vh so that what is below it is *visible* — a hair of the name
   and price shows under the fold, which is what says "there is more here"
   without a scroll hint that has to be drawn.
*/
/* Specificity rather than source order, so the two z-indexes cannot be
   reordered into each other by an edit above. */
.overlay.lightbox { z-index: 100; }

.lightbox-stage {
  position: relative;
  display: flex; align-items: center;
  width: 100%; height: 70vh;
  background: #000;
  /* Horizontal, not hidden: a picture wider than the window at this height is
     scrolled to rather than cropped. Vertical stays hidden so the band cannot
     grow its own scrollbar inside the page's. */
  overflow-x: auto; overflow-y: hidden;
}
.lightbox-stage img#lightbox-image {
  height: 100%; width: auto; max-width: none; margin: auto;
  flex-shrink: 0; cursor: zoom-in;
}

/* Zoomed is the whole window — the page enters browser fullscreen at the same
   moment, so this is the height of the screen rather than of the viewport
   inside the browser's chrome. `dvh` because a phone's toolbar retracts. */
.lightbox.zoomed { overflow: hidden; }
.lightbox.zoomed .lightbox-stage { height: 100dvh; }
.lightbox.zoomed .lightbox-details,
.lightbox.zoomed .lightbox-thumbs { display: none; }
.lightbox.zoomed img#lightbox-image { cursor: zoom-out; }

.lightbox-close { position: fixed; top: 1.25rem; right: 1.25rem; z-index: 2; }
/* Faint until wanted: they sit over the picture, which is the thing being
   looked at, and a control at full strength over an image is a control in
   front of it. */
.lightbox-nav {
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 1;
  opacity: .3; transition: opacity .2s ease-in-out;
}
.lightbox-nav:hover, .lightbox-nav:focus-visible { opacity: 1; }
.lightbox-prev { left: .9rem; }
.lightbox-next { right: .9rem; }

.lightbox-thumbs { justify-content: center; padding-inline: 1.75rem; }

.lightbox-details {
  display: grid; gap: 1rem; justify-items: center; text-align: center;
  max-width: 44rem; margin-inline: auto;
  padding: 2rem 1.75rem 4rem;
}
.lightbox-details > * { max-width: 100%; }
/* A picture has no price and nothing to buy, and an empty grid item still
   holds its gap open — which read as a hole where the price should be. */
.lightbox-details > :empty { display: none; }
.lightbox-details .name { font-weight: 600; font-size: 1.35rem; letter-spacing: -0.01em; }
.lightbox-details .name p { margin: 0; }
.lightbox-details .price { font-size: 1.1rem; font-weight: 600; }
.lightbox-details .desc { color: var(--ink3); font-size: .9rem; }
.lightbox-details .desc p + p { margin-top: .75rem; }

/* ── comments ───────────────────────────────────────────────────────────── */
/*
   A thread reads as a conversation or it reads as a log. What made this a log
   was that every line looked the same: no faces, no thread rail, a date
   instead of "an hour ago", and a form of three bare boxes that belonged to
   some other application. The rules below are the difference.
*/

.lightbox-comments {
  margin-top: 2.5rem; padding-top: 2rem;
  border-top: 1px solid var(--line);
  /* The product view centres its column; a conversation is read from the
     left edge like any other prose. */
  text-align: left;
}
.comment-title {
  display: flex; align-items: center; gap: .5rem;
  font-size: .95rem; font-weight: 600;
}
.comment-title-icon { display: inline-flex; color: var(--mute); }
.comment-empty { margin-top: .75rem; font-size: .85rem; color: var(--mute); }

.comment { display: flex; gap: .75rem; padding-block: 1.1rem; }
.comment + .comment { border-top: 1px solid var(--line); }
.comment-main { flex: 1; min-width: 0; }

/* Nobody has a face — there are no accounts — so it is the initial, on a hue
   derived from the name. Two people down a thread are then two colours,
   which is what makes a thread skimmable at all. */
.comment-avatar {
  flex-shrink: 0; width: 2.25rem; height: 2.25rem; border-radius: var(--r-pill);
  display: grid; place-items: center;
  font-size: .85rem; font-weight: 600; line-height: 1;
  color: hsl(var(--avatar-hue, 0) 45% 30%);
  background: hsl(var(--avatar-hue, 0) 60% 90%);
}
/* The shop is not one of the visitors, so it is not one of the colours. */
.comment-avatar.is-shop {
  background: var(--ink); color: var(--surface);
}
@media (prefers-color-scheme: dark) {
  .comment-avatar { color: hsl(var(--avatar-hue, 0) 70% 85%); background: hsl(var(--avatar-hue, 0) 35% 25%); }
}

.comment-head { display: flex; align-items: baseline; gap: .5rem; flex-wrap: wrap; }
.comment-author { font-weight: 600; font-size: .875rem; }
.comment-when { color: var(--mute); font-size: .72rem; }
.comment-badge {
  font-size: .62rem; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
  padding: .1rem .4rem; border-radius: var(--r-pill);
  background: var(--ink); color: var(--surface);
}
.comment-body {
  margin-top: .3rem; font-size: .9rem; line-height: 1.55;
  color: var(--ink3); white-space: pre-wrap; overflow-wrap: anywhere;
}

/* One level of indentation, because there is only one level to show
   (CMNT-1). The rail is what says these answer the comment above them. */
.comment-thread {
  margin-top: .9rem; padding-left: 1rem;
  border-left: 2px solid var(--line);
}
.comment-thread .comment { padding-block: .8rem; }
.comment-thread .comment:first-child { padding-top: 0; }
.comment-thread .comment-avatar { width: 1.75rem; height: 1.75rem; font-size: .72rem; }

.comment-reply-toggle {
  margin-top: .5rem; padding: 0; border: none; background: none; cursor: pointer;
  color: var(--mute); font-size: .75rem; font-weight: 600;
}
.comment-reply-toggle:hover { color: var(--ink); text-decoration: underline; }

.comment-form { display: grid; gap: .75rem; margin-top: 1.25rem; }
.comment-thread .comment-form, .comment .comment-form { margin-top: .75rem; }
/* Name and email side by side: they are one line of who-you-are, and stacked
   they made a three-box tower taller than the comment being answered. */
.comment-form-row { display: grid; gap: .75rem; }
@media (min-width: 560px) {
  .comment-form-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.comment-form .ui-btn { justify-self: start; }
.comment-error { color: var(--danger); font-size: .78rem; }

/* CMNT-11: what replaces the form when a comment is waiting. Not an error and
   not a success — a receipt, saying what has to happen next. */
.comment-pending {
  margin-top: 1.25rem; padding: 1rem 1.1rem;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--field); font-size: .85rem;
}
.comment-pending p { margin-top: .35rem; color: var(--ink3); line-height: 1.5; }

/* ── pictures (SECT-13) ─────────────────────────────────────────────────── */

/* A picture section is one photograph at the width it was given. It is a
   `.gallery` of one, so the tile, the hover and the lightbox are the ones
   every other picture on the site uses — but not its columns: `.gallery`
   fills a row with 15rem tracks, which turned one photograph into a thumbnail
   with the rest of the row empty beside it. */
.sb-picture { margin: 0; display: block; }
.sb-picture .gallery-item > img { width: 100%; height: auto; }
/* A picture tile has no price under it, so its caption is one line and only
   worth showing when the picture has a name of its own. */
.gallery-item.is-picture .gallery-caption { justify-content: flex-start; }
.gallery-item.is-picture .gallery-caption:empty { display: none; }

/* ── cart ───────────────────────────────────────────────────────────────── */

.cart-toggle {
  display: inline-flex; align-items: center; gap: .4rem;
  border: 1px solid var(--line); border-radius: var(--r-pill);
  padding: .4rem .8rem; font-size: .8rem; background: none; cursor: pointer; color: var(--ink);
}
.cart-toggle:hover { background: var(--field); }
.cart-count { font-variant-numeric: tabular-nums; font-weight: 600; }

/* UI-14's overlay and UI-22's question are the tier's (`libs/ui/assets/surfaces.css`,
   2026-09-08): every application serves them with `commee_ui::STYLE`, this
   sheet included. Only the lightbox's own z-index stays here, above. */

/* COMM-17: the order, as two halves that fit on one screen — what is being
   bought, and where it is going. They stack on a phone, basket first, because
   that is the half you check before you start typing. */
.checkout {
  display: grid; gap: 2rem;
  max-width: 68rem; margin: 0 auto;
}
@media (min-width: 900px) {
  .checkout { grid-template-columns: minmax(0, 22rem) minmax(0, 1fr); align-items: start; }
}
.checkout-basket {
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--field); padding: 1.25rem;
}
.checkout-line {
  display: flex; gap: .75rem; align-items: flex-start;
  padding-block: .9rem; border-bottom: 1px solid var(--line);
}
.checkout-line img, .checkout-line-blank {
  width: 3.5rem; height: 3.5rem; object-fit: cover; border-radius: var(--r2); flex-shrink: 0;
}
.checkout-line-blank { background: var(--line); }
.checkout-line .info { flex: 1; min-width: 0; font-size: .82rem; }
.checkout-line .info .name { font-weight: 600; }
.checkout-line .line-total { font-size: .82rem; font-weight: 600; white-space: nowrap; }
.checkout-total {
  display: flex; justify-content: space-between;
  margin-top: 1.25rem; padding-top: 1rem;
  border-top: 1px solid var(--line); font-weight: 600;
}

/* Two column-fuls of form: who to reach, and where to go. One question per
   column-heading, so neither is a wall of eight identical boxes. */
.checkout-columns { display: grid; gap: 1.5rem; }
@media (min-width: 640px) {
  .checkout-columns { grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: start; }
}
.checkout-column { display: grid; gap: 1rem; align-content: start; }

/* The decision, in the corner a decision belongs in. It used to sit under the
   left-hand column, level with nothing and a screen away from the total on a
   short form. Fixed to the overlay rather than the page, because the overlay
   is what is being read. */
.checkout-actions {
  position: fixed; right: 1.5rem; bottom: 1.5rem; z-index: 2;
  display: flex; justify-content: flex-end;
}
.checkout-actions .ui-btn { box-shadow: var(--shadow); }

/* CUST-2 */
.account-doors { display: grid; gap: 1.5rem; margin-top: calc(2rem * var(--space, 1)); }
@media (min-width: 640px) {
  .account-doors { grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: start; }
}
.account-doors > section {
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--field); box-shadow: var(--shadow);
  padding: 1.5rem;
}
.account-doors .eyebrow { display: block; margin-bottom: 1.25rem; }
.account-doors .form .ui-btn { margin-top: 1.5rem; }
.h1 + .alert { margin-top: 1rem; }

.qty-stepper { display: inline-flex; align-items: center; gap: .6rem; }
.qty-stepper button {
  width: 1.75rem; height: 1.75rem; border-radius: var(--r-pill); border: 1px solid var(--line);
  background: none; color: var(--ink); cursor: pointer; font-size: .9rem; line-height: 1;
}
.qty-stepper button:hover { background: var(--field); }
.qty-stepper .n { min-width: 1.25rem; text-align: center; font-variant-numeric: tabular-nums; }

/* ── icons ──────────────────────────────────────────────────────────────── */
/* `.icon` and `.sr-only` are the tier's (`libs/ui/assets/controls.css`, UIC-36):
   every surface draws glyphs, and not every surface links this sheet. */

/* The rounded button moved to the tier with the rest of them (UIC-10):
   `.ui-round`, its `--ui-round-size` and the label that unfurls are one
   definition in `libs/ui/assets/controls.css`, served in front of this sheet. */

/* The floating label is gone (UIC-8, 2026-09-04). It put the label inside the
   control's border and gave every box 3.4rem of height to clear it, which was
   this product's fourth way of drawing a field. The label stands above the box
   now, the mailbox's way, and the one definition is the UI tier's. UI-5 is
   overridden; the id is kept.

   `.field.money` and the picture strip moved there with it — both were rules
   about beating the floating label, and there is nothing left to beat. */

/* ── the choosing controls ───────────────────────────────────────────────── */
/* ── sections ───────────────────────────────────────────────────────────── */
/*
   Arrangements are a closed set in the schema, so this is the whole list —
   a section cannot ask for a class that is not written here.
*/

.sb-stack { display: grid; gap: 2rem; }
/* One rule for every grid. The column counts arrive as custom properties on
   the element (SECT-7), so "three across on a phone, six on a desktop" is two
   integers rather than a class per combination — there are thirty-two, and a
   stylesheet with thirty-two near-identical rules is one nobody keeps right.
   One breakpoint, because two numbers is what an author was asked for. */
.sb-grid {
  display: grid; gap: .5rem;
  grid-template-columns: repeat(var(--cols-m, 1), minmax(0, 1fr));
}
@media (min-width: 640px) {
  .sb-grid { gap: 1rem; grid-template-columns: repeat(var(--cols-d, 3), minmax(0, 1fr)); }
}
/* A grid item is `min-width: auto` by default, so it refuses to shrink below
   its content — which pushes the last column out past its own container's
   border the moment anything inside it is wider than its track. */
.sb-children > * { min-width: 0; }

/* A gallery sizes its own tracks; inside an arranged section the section's
   count wins, so this comes after `.gallery` rather than before it. Without
   that the two grids fight and the arrangement does nothing. */
.gallery.sb-stack { grid-template-columns: 1fr; }

/* A tile in a grid is a square crop, so a wall of them is a wall rather than a
   ragged edge — the picture decides what is interesting, the grid decides the
   shape. The caption sits under it and does not enter the square. */
.gallery.sb-grid .gallery-item > img,
.gallery.sb-grid .gallery-empty {
  aspect-ratio: 1; width: 100%; height: auto; object-fit: cover;
}
.sb-heading { margin-top: 1rem; }

/* SECT-7's control: a mode, and — only when it is `grid` — two counts. */
.arrangement-field { display: grid; gap: .75rem; }
.arrangement-cols { display: flex; gap: .75rem; }
.arrangement-cols > * { flex: 1; min-width: 0; }

/* SECT-12's: two axes side by side, because vertical and horizontal are one
   question asked twice and reading them on one line says so. */
.placement-pair { display: flex; gap: .75rem; }
.placement-pair > * { flex: 1; min-width: 0; }

.tab-icon { margin-right: .4rem; color: var(--mute); }
.active-tab .tab-icon { color: inherit; }

/* BUILD-8: a root section is as wide as the window and carries its own reading
   column. The page used to be one 720px column with everything inside it,
   which left no way to express a full-bleed band, a wide gallery, or a
   two-column container that actually reads as two columns. Nesting is
   untouched — a child is as wide as the parent arranging it. */
.page-main { width: 100%; }
/* The title and a page-level layout slot are full-bleed bands too, so they
   line up with the reading column the sections carry instead of sitting in a
   narrower one of their own — which read as a centred heading over
   left-aligned content. */
.page-title { padding-block: 2.5rem 0.5rem; }

/* SECT-12: a section's content fills the section, and a section fills the
   cell it was given. A root section is therefore as wide as the window, and a
   container split two ways gives two halves that really are halves.
   
   The 72rem reading column that used to sit here made that untrue: two columns
   were two halves of 1152px floating in a wider page, and there was no way to
   ask for anything else. Width is now a consequence of the tree — how many
   columns the parent has — and the space around it is `padded`/`spaced`,
   which an author sets per section rather than inheriting from a rule. */
/* UIC-41, where it is obvious: a root section that is not one of the
   landing's own bands — which carry their tint to the glass and their words
   in a column of their own — stands in the header's column and on its edges,
   so the shop reads down the middle of a wide window and not along its left
   side. A container's two halves are halves of that column. */
.page-band,
.sb-root > .sb-node:not([data-kind="hero"], [data-kind="band"], [data-kind="cards"], [data-kind="stats"], [data-kind="who"], [data-kind="contact"]) {
  width: 100%;
  max-width: var(--container, 1360px);
  margin-inline: auto;
  padding-inline: calc(1.75rem - 8px);
}
/* The title has no padded body of its own to add the 8px, so it takes the
   header's whole gutter and lands on the same edge. */
.page-band { padding-inline: 1.75rem; }
.sb-node { display: grid; grid-template-columns: minmax(0, 1fr); }
.sb-body { min-width: 0; }
.sb-padded > .sb-body { padding: var(--s4); }
.sb-spaced > .sb-body { margin: var(--s4); }
/* A section of words stands at the reading measure on the band's left edge (UIC-41). */
.sb-node[data-kind="markdown"] > .sb-body { max-width: var(--prose); }

/* LAND-4: the language switch in the header — the codes, the one in use
   underlined. */
.nav-langs { display: inline-flex; gap: .5rem; margin-right: .5rem; }
.nav-lang { font-size: .72rem; font-weight: 600; letter-spacing: .06em; color: var(--mute); }
.nav-lang:hover { color: var(--ink); }
.nav-lang.is-on { color: var(--ink); text-decoration: underline; text-underline-offset: .3em; }

/* ── landing sections (LAND-2) ──────────────────────────────────────────── */
/*
   comm.ee's own idiom (SITE-2, SITE-3) in the site's own colours: flat, edge
   to edge, the serif light and large, pills, a screen's worth of air around
   a hero, and a band the whole width of the window in a tint of its tone.
   Every colour is the theme row's (THEME-7); a tone is one of five names.
*/
.sb-kicker { font-family: var(--sans); font-size: .8rem; font-weight: 500; letter-spacing: .06em; text-transform: uppercase; color: var(--mute); margin: 0 0 .75rem; }
.sb-head, .sb-band-head {
  font-family: var(--serif); font-weight: 300; letter-spacing: -0.02em;
  font-size: clamp(2rem, 4vw, 3.5rem); line-height: 1.05; margin: 0; text-wrap: balance;
}
.sb-lede { margin-top: 1rem; color: var(--ink3); font-size: clamp(1.05rem, 1.4vw, 1.3rem); max-width: 40rem; text-wrap: pretty; }
.sb-prose { margin-top: 1rem; color: var(--ink3); max-width: 36rem; }
.sb-prose p + p { margin-top: .75rem; }
.sb-actions { display: flex; flex-wrap: wrap; gap: .75rem; align-items: center; margin-top: 1.5rem; }
.sb-actions.jcenter { justify-content: center; }
/* A landing's pill at the site's own measure (LAND-2, GAP-329). */
.sb-pill { height: auto; padding: .7rem 1.4rem; font-size: .95rem; font-weight: 500; }
.sb-pill-plain { font-weight: 500; }
.sb-ticks { list-style: none; margin: 1rem 0 0; padding: 0; display: grid; gap: .4rem; color: var(--ink3); }
.sb-tick { color: var(--tone, var(--accent)); font-weight: 600; }
.sb-facts {
  list-style: none; margin: 1.5rem 0 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: 1.25rem; justify-content: center;
  font-size: .85rem; font-weight: 500; letter-spacing: .04em; color: var(--mute);
}
.sb-facts li + li::before { content: "·"; margin-right: 1.25rem; }
.sb-facts a { color: var(--accent); }

/* The five tones (LAND-2): the same on either ground. */
.sb-band[data-tone="indigo"], .sb-card[data-tone="indigo"] { --tone: oklch(0.55 0.2 275); }
.sb-band[data-tone="teal"], .sb-card[data-tone="teal"] { --tone: oklch(0.72 0.13 185); }
.sb-band[data-tone="coral"], .sb-card[data-tone="coral"] { --tone: oklch(0.68 0.19 30); }
.sb-band[data-tone="amber"], .sb-card[data-tone="amber"] { --tone: oklch(0.8 0.16 80); }
.sb-band[data-tone="gold"], .sb-card[data-tone="gold"] { --tone: oklch(0.62 0.12 80); }

/* Each landing kind but the band carries its own reading column and a
   screen's worth of air above and below; the band paints its own. */
.sb-node[data-kind="cards"] > .sb-body, .sb-node[data-kind="stats"] > .sb-body,
.sb-node[data-kind="who"] > .sb-body, .sb-node[data-kind="contact"] > .sb-body {
  max-width: var(--container); margin-inline: auto; padding: clamp(3rem, 8vw, 6rem) 1.5rem;
}
.sb-node[data-kind="cards"], .sb-node[data-kind="stats"], .sb-node[data-kind="who"], .sb-node[data-kind="contact"], .sb-node[data-kind="hero"] { margin-top: 0; }

/* The hero: centred, the sentence is the picture. */
.sb-node[data-kind="hero"] > .sb-body { max-width: 64rem; margin-inline: auto; padding-inline: 1.5rem; }
.sb-hero {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  padding-block: clamp(4rem, 12vh, 9rem) clamp(3rem, 8vh, 6rem);
}
.sb-hero-head {
  font-family: var(--serif); font-weight: 300; letter-spacing: -0.025em;
  font-size: clamp(2.75rem, 7vw, 6.5rem); line-height: 1; margin: 0; text-wrap: balance;
}
.sb-hero .sb-lede { margin-top: 1.5rem; }

/* A band: the whole width in a tint of its tone, two columns from 900px,
   the picture on the wider track whichever side it stands. */
.sb-node[data-kind="band"] { margin-top: 0; }
.sb-node[data-kind="band"] > .sb-body { background: color-mix(in oklab, var(--tone, var(--accent)) 8%, var(--surface)); }
.sb-band {
  --tone: var(--accent);
  display: grid; gap: 2.5rem; align-items: center;
  max-width: var(--container); margin-inline: auto;
  padding: clamp(3rem, 8vw, 7rem) 1.5rem;
}
.sb-node[data-kind="band"] > .sb-body { --tone: var(--accent); }
.sb-node[data-kind="band"] > .sb-body:has(.sb-band[data-tone="indigo"]) { --tone: oklch(0.55 0.2 275); }
.sb-node[data-kind="band"] > .sb-body:has(.sb-band[data-tone="teal"]) { --tone: oklch(0.72 0.13 185); }
.sb-node[data-kind="band"] > .sb-body:has(.sb-band[data-tone="coral"]) { --tone: oklch(0.68 0.19 30); }
.sb-node[data-kind="band"] > .sb-body:has(.sb-band[data-tone="amber"]) { --tone: oklch(0.8 0.16 80); }
.sb-node[data-kind="band"] > .sb-body:has(.sb-band[data-tone="gold"]) { --tone: oklch(0.62 0.12 80); }
.sb-band .sb-kicker { color: color-mix(in oklab, var(--tone) 70%, var(--ink)); }
@media (min-width: 900px) {
  .sb-band { grid-template-columns: 5fr 7fr; gap: clamp(2rem, 5vw, 5rem); }
  .sb-band.is-flip { grid-template-columns: 7fr 5fr; }
  .sb-band.is-flip .sb-band-say { order: 2; }
  .sb-band.is-flip .sb-frame { order: 1; }
}
.sb-frame { margin: 0; min-width: 0; border-radius: var(--r1); overflow: hidden; background: var(--surface); border: 1px solid var(--line); }
.sb-frame-bar {
  display: flex; align-items: center; gap: .3rem; padding: .5rem .75rem;
  border-bottom: 1px solid var(--hair); font-family: var(--mono); font-size: .75rem; color: var(--mute);
}
.sb-frame-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--line); flex: none; }
.sb-frame-at { margin-left: .4rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sb-frame img { width: 100%; height: auto; display: block; }

/* Cards: the arrangement's columns, a rule over each in its tone, no boxes. */
.sb-cards-head { max-width: 52rem; margin-bottom: clamp(2rem, 4vw, 3.5rem); }
.sb-cards.sb-grid, .sb-stats.sb-grid { gap: clamp(1.5rem, 3vw, 3rem); }
.sb-card { --tone: var(--accent); border-top: 2px solid var(--tone); padding-top: 1.25rem; display: flex; flex-direction: column; gap: .75rem; }
.sb-badge { align-self: flex-start; font-size: .7rem; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; color: var(--tone); }
.sb-card-head { font-family: var(--serif); font-weight: 400; font-size: 1.5rem; line-height: 1.2; margin: 0; }
.sb-card .sb-prose, .sb-card .sb-ticks { margin-top: 0; }
.sb-card .sb-pill-plain { margin-top: auto; align-self: flex-start; }

/* Stats: the figure large in the serif, its label and sentence under it;
   the panels framed like a band's picture. */
.sb-stat-num { font-family: var(--serif); font-weight: 300; font-size: clamp(2.5rem, 5vw, 4.5rem); line-height: 1; margin: 0; letter-spacing: -0.02em; }
.sb-stat-head { font-size: 1rem; font-weight: 600; margin: .5rem 0 0; }
.sb-stat-say { margin-top: .35rem; color: var(--ink3); font-size: .95rem; }
.sb-panels { display: grid; gap: 1.5rem; margin-top: clamp(2rem, 4vw, 3.5rem); }
@media (min-width: 900px) { .sb-panels { grid-template-columns: 1fr 1fr; } }
.sb-panel { margin: 0; border: 1px solid var(--line); border-radius: var(--r1); overflow: hidden; background: var(--surface); }
.sb-panel img { width: 100%; height: auto; display: block; border-bottom: 1px solid var(--hair); }
.sb-panel figcaption { padding: .9rem 1rem; font-size: .95rem; color: var(--ink3); }
.sb-panel figcaption strong { color: var(--ink); }
.sb-panel-say, .sb-panel-say p { display: inline; margin: 0; }

/* Who: the portrait beside the words. */
.sb-who { display: grid; gap: 2rem; align-items: center; }
@media (min-width: 900px) {
  .sb-who:has(.sb-portrait) { grid-template-columns: 4fr 8fr; gap: clamp(2rem, 5vw, 5rem); }
}
.sb-who-say { max-width: 52rem; }
.sb-portrait { width: min(100%, 340px); aspect-ratio: 1; object-fit: cover; border-radius: var(--r1); display: block; }
.sb-promise { margin: 1.5rem 0 0; font-family: var(--serif); font-weight: 300; font-size: clamp(1.4rem, 2vw, 1.9rem); line-height: 1.25; }
.sb-who .sb-facts { justify-content: flex-start; }

/* Contact: one column down the middle, the form at a reading width. */
.sb-contact { display: flex; flex-direction: column; align-items: center; gap: 2rem; max-width: 46rem; margin-inline: auto; }
.sb-contact-say { display: flex; flex-direction: column; align-items: center; text-align: center; }
.sb-note { text-align: center; max-width: 36rem; }
.sb-note-head { font-family: var(--serif); font-weight: 400; font-size: 1.4rem; margin: 0; }
.sb-contact-form { width: 100%; }
.sb-form-fields { display: grid; gap: 1rem; }
@media (min-width: 640px) {
  .sb-form-fields { grid-template-columns: 1fr 1fr; }
  .sb-form-fields .ui-field:has(textarea) { grid-column: 1 / -1; }
}
.sb-contact-form .ui-btn { margin-top: 1.25rem; }
.sb-fine { margin-top: 1rem; font-size: .85rem; color: var(--mute); text-align: center; }
.sb-sent { text-align: center; }
.nav .ui-round { --ui-round-size: 1.6rem; }

/* ── claiming an address ────────────────────────────────────────────────── */

.brand-tail { color: var(--accent); }

.claim-main { padding-block: clamp(1.5rem, 4vh, 2.75rem) 4rem; }
.claim-cols { display: grid; grid-template-columns: minmax(0, 1fr); gap: 2.25rem; align-items: start; }
@media (min-width: 62rem) {
  .claim-cols { grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr); gap: 2.75rem; }
  /* The preview follows the form down: what is being typed and what it makes
     have to be on screen at the same time or neither is answering the other. */
  .claim-see { position: sticky; top: 6rem; }
}
.claim-say { min-width: 0; }
.claim-see { min-width: 0; }
.claim-see-head { display: flex; align-items: center; justify-content: space-between; gap: .75rem; margin-bottom: .5rem; }

/* The address the title is about to take, under the field that decides it. */
.claim-host { font-family: var(--mono); font-size: .8rem; color: var(--ink3); min-height: 1.4em; margin-top: -.4rem; }
.claim-host-taken { color: var(--danger); }

.claim-go { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; margin-top: 1.5rem; }

/* Two fields that are one answer — a first name and a last name sit on one
   line at any width that has room for two. */
.pair { display: grid; grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); gap: 0 .75rem; }

/* ── the preview ────────────────────────────────────────────────────────── */

.prev { --prev-width: 100%; }
.prev[data-segmented="phone"] { --prev-width: 20rem; }
.prev-frame {
  width: var(--prev-width); margin-inline: auto;
  border: 1px solid var(--line); border-radius: var(--radius);
  overflow: hidden; background: var(--surface); box-shadow: var(--shadow);
  transition: width .2s;
}
.prev-chrome { display: flex; align-items: center; gap: .35rem; padding: .45rem .6rem; background: var(--field); border-bottom: 1px solid var(--line); }
.prev-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--line); flex: none; }
.prev-url { flex: 1; margin-left: .35rem; font-family: var(--mono); font-size: .62rem; color: var(--mute); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.prev-page { display: flex; flex-direction: column; min-height: 19rem; }
.prev-bar { display: flex; align-items: center; gap: .5rem; padding: .7rem .9rem; border-bottom: 1px solid var(--hair); }
.prev-mark {
  width: 1.35rem; height: 1.35rem; flex: none; border-radius: var(--r2);
  background: var(--solid); color: var(--solid-ink);
  display: flex; align-items: center; justify-content: center;
  font-size: .55rem; font-weight: 600; letter-spacing: .02em;
}
.prev-brand { font-family: var(--serif); font-size: .85rem; font-weight: 600; letter-spacing: -0.01em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.prev-body { flex: 1; display: flex; flex-direction: column; }
.prev-sec { padding: 1.25rem .9rem; text-align: center; }
.prev-sec + .prev-sec { border-top: 1px solid var(--hair); }
.prev-h { font-family: var(--serif); font-size: 1rem; font-weight: 500; letter-spacing: -0.01em; }
.prev-p { margin-top: .25rem; font-size: .72rem; color: var(--ink3); line-height: 1.5; }
.prev-foot { padding: .6rem .9rem; border-top: 1px solid var(--hair); background: var(--field); font-size: .62rem; color: var(--mute); text-align: center; }

/* The chosen look tints the page being previewed (REG-11): the tint rides on
   three custom properties the script can move when the pick changes. */
.prev-page.tinted { background: var(--pv-bg); color: var(--pv-ink); }
.prev-page.tinted .prev-bar { border-bottom-color: color-mix(in srgb, var(--pv-ink) 14%, transparent); }
.prev-page.tinted .prev-mark { background: var(--pv-accent); color: var(--pv-bg); }
.prev-page.tinted .prev-h { color: var(--pv-ink); }
.prev-page.tinted .prev-p { color: color-mix(in srgb, var(--pv-ink) 72%, var(--pv-bg)); }
.prev-page.tinted .prev-sec + .prev-sec { border-top-color: color-mix(in srgb, var(--pv-ink) 12%, transparent); }
.prev-page.tinted .prev-foot {
  background: color-mix(in srgb, var(--pv-ink) 6%, var(--pv-bg));
  color: color-mix(in srgb, var(--pv-ink) 62%, var(--pv-bg));
  border-top-color: color-mix(in srgb, var(--pv-ink) 12%, transparent);
}

/* An example picture, before it exists: a placeholder in the offer's own
   colours, one wide or a grid — the shape the real section takes. */
.prev-art {
  height: 5.2rem; border-radius: var(--r3);
  background: linear-gradient(
    135deg,
    color-mix(in srgb, var(--pv-accent, var(--accent)) 42%, var(--pv-bg, var(--surface))),
    color-mix(in srgb, var(--pv-ink, var(--ink)) 34%, var(--pv-bg, var(--surface)))
  );
}
.prev-sec > .prev-art, .prev-sec > .prev-grid { margin-bottom: .6rem; }
.prev-grid { display: grid; grid-template-columns: repeat(var(--n, 3), 1fr); gap: var(--s2); }
.prev-grid .prev-art { height: 2.6rem; }

/* ── a phone ────────────────────────────────────────────────────────────── */
/* Read at arm's length: everything set in rem grows together off the root,
   and the smallest print — ten-pixel capitals nobody could read — takes a
   step more on top. The owner's own --body-size keeps ruling the prose and
   gains the point everything else gained; a page with no site behind it
   keeps the tier's. A field's type on a phone is the tier's (`--t-field`),
   and so are its label, hint and refusal (P11). */
@media (max-width: 640px) {
  html { font-size: 112.5%; }
  body { font-size: calc(var(--body-size, calc(var(--t5) - 1px)) + 1px); }
  .eyebrow { font-size: .72rem; }
  .tiny { font-size: .75rem; }
  .stat-label { font-size: .72rem; }
  .nav a, .nav-more summary { font-size: .95rem; }
  .claim-host { font-size: .9rem; }
}

/* The utility layer (UI-42). Served after every application's own sheet, so a
   class here wins the tie against a component class setting the same property.

   Every value is a step on `theme/scale.rs` or a token on `theme/tokens.rs`.
   Nothing in this file names a number or a colour of its own. */

/* ── layout ──────────────────────────────────────────────────────────────── */

.flex { display: flex; }
.stack { display: flex; flex-direction: column; }
.row { display: flex; flex-direction: row; align-items: center; }
.grid { display: grid; }
.grid-2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid-3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid-4 { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); }
/* Two columns in a ratio: the shares a document's `:grid-2-1` asks for
   (PAPER-11), and a sidebar beside its page anywhere else. */
.grid-1-2 { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); }
.grid-2-1 { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }
.grid-1-3 { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 3fr); }
.grid-3-1 { display: grid; grid-template-columns: minmax(0, 3fr) minmax(0, 1fr); }
.wrap { flex-wrap: wrap; }
.nowrap { flex-wrap: nowrap; }

.start { align-items: flex-start; }
.center { align-items: center; }
.end { align-items: flex-end; }
.baseline { align-items: baseline; }
.stretch { align-items: stretch; }
.between { justify-content: space-between; }
.around { justify-content: space-around; }
.jstart { justify-content: flex-start; }
.jcenter { justify-content: center; }
.jend { justify-content: flex-end; }

/* What one child says about itself, against what its container said about
   all of them. A chip in a column is the usual case: the column stretches
   its children and the chip is as wide as its own word. */
.self-start { align-self: flex-start; }
.self-center { align-self: center; }
.self-end { align-self: flex-end; }

.grow { flex: 1 1 auto; min-width: 0; }
.none { flex: none; }
.shrink { min-width: 0; }

.block { display: block; }
.inline { display: inline; }
.iblock { display: inline-block; }
.iflex { display: inline-flex; align-items: center; }
.relative { position: relative; }
.absolute { position: absolute; }
.fixed { position: fixed; }
.sticky { position: sticky; }
.inset-0 { inset: 0; }
.clip { overflow: hidden; }
.scroll-y { overflow-y: auto; }
.scroll-x { overflow-x: auto; }

/* What a script puts an element behind. The three sheets each carried their
   own copy of this one declaration, so which one a screen got depended on
   which application was serving it. `!important` because it answers a
   `display` the element already has, and it is the only one in the layer. */
.hidden { display: none !important; }

/* A box that fills what holds it is not a measure — it is the absence of one,
   and the same three declarations were written 157 times between the sheets. */
.w-full { width: 100%; }
.h-full { height: 100%; }
.min-h-full { min-height: 100%; }
.cover { object-fit: cover; }


/* ── space ───────────────────────────────────────────────────────────────── */

.gap-0 { gap: 0; }
.gap-1 { gap: var(--s1); }
.gap-2 { gap: var(--s2); }
.gap-3 { gap: var(--s3); }
.gap-4 { gap: var(--s4); }
.gap-5 { gap: var(--s5); }
.gap-6 { gap: var(--s6); }
.gap-7 { gap: var(--s7); }
.gap-8 { gap: var(--s8); }
.gap-9 { gap: var(--s9); }
.gap-10 { gap: var(--s10); }
.gap-11 { gap: var(--s11); }
.gap-12 { gap: var(--s12); }
.gap-13 { gap: var(--s13); }

.gx-0 { column-gap: 0; }
.gx-1 { column-gap: var(--s1); }
.gx-2 { column-gap: var(--s2); }
.gx-3 { column-gap: var(--s3); }
.gx-4 { column-gap: var(--s4); }
.gx-5 { column-gap: var(--s5); }
.gx-6 { column-gap: var(--s6); }
.gx-7 { column-gap: var(--s7); }
.gx-8 { column-gap: var(--s8); }
.gx-9 { column-gap: var(--s9); }
.gx-10 { column-gap: var(--s10); }
.gx-11 { column-gap: var(--s11); }
.gx-12 { column-gap: var(--s12); }
.gx-13 { column-gap: var(--s13); }

.gy-0 { row-gap: 0; }
.gy-1 { row-gap: var(--s1); }
.gy-2 { row-gap: var(--s2); }
.gy-3 { row-gap: var(--s3); }
.gy-4 { row-gap: var(--s4); }
.gy-5 { row-gap: var(--s5); }
.gy-6 { row-gap: var(--s6); }
.gy-7 { row-gap: var(--s7); }
.gy-8 { row-gap: var(--s8); }
.gy-9 { row-gap: var(--s9); }
.gy-10 { row-gap: var(--s10); }
.gy-11 { row-gap: var(--s11); }
.gy-12 { row-gap: var(--s12); }
.gy-13 { row-gap: var(--s13); }

.p-0 { padding: 0; }
.p-1 { padding: var(--s1); }
.p-2 { padding: var(--s2); }
.p-3 { padding: var(--s3); }
.p-4 { padding: var(--s4); }
.p-5 { padding: var(--s5); }
.p-6 { padding: var(--s6); }
.p-7 { padding: var(--s7); }
.p-8 { padding: var(--s8); }
.p-9 { padding: var(--s9); }
.p-10 { padding: var(--s10); }
.p-11 { padding: var(--s11); }
.p-12 { padding: var(--s12); }
.p-13 { padding: var(--s13); }

.px-0 { padding-inline: 0; }
.px-1 { padding-inline: var(--s1); }
.px-2 { padding-inline: var(--s2); }
.px-3 { padding-inline: var(--s3); }
.px-4 { padding-inline: var(--s4); }
.px-5 { padding-inline: var(--s5); }
.px-6 { padding-inline: var(--s6); }
.px-7 { padding-inline: var(--s7); }
.px-8 { padding-inline: var(--s8); }
.px-9 { padding-inline: var(--s9); }
.px-10 { padding-inline: var(--s10); }
.px-11 { padding-inline: var(--s11); }
.px-12 { padding-inline: var(--s12); }
.px-13 { padding-inline: var(--s13); }

.py-0 { padding-block: 0; }
.py-1 { padding-block: var(--s1); }
.py-2 { padding-block: var(--s2); }
.py-3 { padding-block: var(--s3); }
.py-4 { padding-block: var(--s4); }
.py-5 { padding-block: var(--s5); }
.py-6 { padding-block: var(--s6); }
.py-7 { padding-block: var(--s7); }
.py-8 { padding-block: var(--s8); }
.py-9 { padding-block: var(--s9); }
.py-10 { padding-block: var(--s10); }
.py-11 { padding-block: var(--s11); }
.py-12 { padding-block: var(--s12); }
.py-13 { padding-block: var(--s13); }

.pt-0 { padding-top: 0; }
.pt-1 { padding-top: var(--s1); }
.pt-2 { padding-top: var(--s2); }
.pt-3 { padding-top: var(--s3); }
.pt-4 { padding-top: var(--s4); }
.pt-5 { padding-top: var(--s5); }
.pt-6 { padding-top: var(--s6); }
.pt-7 { padding-top: var(--s7); }
.pt-8 { padding-top: var(--s8); }
.pt-9 { padding-top: var(--s9); }
.pt-10 { padding-top: var(--s10); }
.pt-11 { padding-top: var(--s11); }
.pt-12 { padding-top: var(--s12); }
.pt-13 { padding-top: var(--s13); }

.pb-0 { padding-bottom: 0; }
.pb-1 { padding-bottom: var(--s1); }
.pb-2 { padding-bottom: var(--s2); }
.pb-3 { padding-bottom: var(--s3); }
.pb-4 { padding-bottom: var(--s4); }
.pb-5 { padding-bottom: var(--s5); }
.pb-6 { padding-bottom: var(--s6); }
.pb-7 { padding-bottom: var(--s7); }
.pb-8 { padding-bottom: var(--s8); }
.pb-9 { padding-bottom: var(--s9); }
.pb-10 { padding-bottom: var(--s10); }
.pb-11 { padding-bottom: var(--s11); }
.pb-12 { padding-bottom: var(--s12); }
.pb-13 { padding-bottom: var(--s13); }

/* The only margins there are, and all four are `auto` or nothing. Spacing
   between siblings belongs to the container's gap: a margin that suited one
   parent overlapped the next, which is what this layer exists to stop
   (UI-42). An `auto` is not a length — it is which edge the box is pushed to,
   the one thing a gap cannot say. */
.m-0 { margin: 0; }
.mx-auto { margin-inline: auto; }
.my-auto { margin-block: auto; }
.ml-auto { margin-left: auto; }

/* Where a page stops, and where a reading inside it stops. Every product had
   both and each had named them for itself; the names are the scale's now, so
   a block that lines up with the page says so in the markup.
   **After the margins on purpose**: `m-0 measure` has to mean "no margin of
   its own, and centred", which is what an element wearing both is asking
   for. Written above them it lost the `auto` to the reset, and the foot's
   own hairline was capped at the measure and then left-aligned under bands
   that were centred. */
.measure { width: 100%; max-width: var(--measure); margin-inline: auto; }
.prose { max-width: var(--prose); }
.gutter { padding-inline: var(--gutter); }

/* ── type ────────────────────────────────────────────────────────────────── */

.t-1 { font-size: var(--t1); line-height: var(--lh1); }
.t-2 { font-size: var(--t2); line-height: var(--lh2); }
.t-3 { font-size: var(--t3); line-height: var(--lh3); }
.t-4 { font-size: var(--t4); line-height: var(--lh4); }
.t-5 { font-size: var(--t5); line-height: var(--lh5); }
.t-6 { font-size: var(--t6); line-height: var(--lh6); }
.t-7 { font-size: var(--t7); line-height: var(--lh7); }
.t-8 { font-size: var(--t8); line-height: var(--lh8); }
.t-9 { font-size: var(--t9); line-height: var(--lh9); }
.t-10 { font-size: var(--t10); line-height: var(--lh10); }
.t-11 { font-size: var(--t11); line-height: var(--lh11); }

.serif { font-family: var(--serif); }
.sans { font-family: var(--sans); }
.mono { font-family: var(--mono); }

.fw-4 { font-weight: 400; }
.fw-5 { font-weight: 500; }
.fw-6 { font-weight: 600; }
.fw-7 { font-weight: 700; }

.upper { text-transform: uppercase; }
.track { letter-spacing: 0.08em; }
.tabular { font-variant-numeric: tabular-nums; }
.tleft { text-align: left; }
.tcenter { text-align: center; }
.tright { text-align: right; }
.pretty { text-wrap: pretty; }
.balance { text-wrap: balance; }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* `.nowrap` above is the flex one. These two are the text's: a line that may
   not break, and a word — a key, an address, a token — that may break
   anywhere rather than push its column wider. */
.nobr { white-space: nowrap; }
.anywhere { overflow-wrap: anywhere; }

/* ── ink ─────────────────────────────────────────────────────────────────── */

.text-ink { color: var(--ink); }
.text-ink2 { color: var(--ink2); }
.text-ink3 { color: var(--ink3); }
.text-mute { color: var(--mute); }
.text-faint { color: var(--faint); }
.text-accent { color: var(--accent); }
.text-accent-ink { color: var(--accent-ink); }
.text-solid-ink { color: var(--solid-ink); }
.text-danger { color: var(--danger); }
.text-ok { color: var(--ok-ink); }
.text-warn { color: var(--warn-ink); }
.text-info { color: var(--info); }
.text-star { color: var(--star); }

/* ── ground ──────────────────────────────────────────────────────────────── */

.bg-none { background: none; }
.bg-page { background: var(--page); }
.bg-surface { background: var(--surface); }
.bg-rail { background: var(--rail); }
.bg-mid { background: var(--mid); }
.bg-chip { background: var(--chip); }
.bg-field { background: var(--field); }
.bg-accent { background: var(--accent); }
.bg-accent-soft { background: var(--accent-soft); }
.bg-solid { background: var(--solid); }
.bg-danger-soft { background: var(--danger-soft); }
.bg-ok { background: var(--ok-bg); }
.bg-warn { background: var(--warn-bg); }
.bg-info-soft { background: var(--info-soft); }
.bg-star-soft { background: var(--star-soft); }

/* ── edges ───────────────────────────────────────────────────────────────── */

.line { border: 1px solid var(--line); }
.line-t { border-top: 1px solid var(--line); }
.line-b { border-bottom: 1px solid var(--line); }
.line-l { border-left: 1px solid var(--line); }
.line-r { border-right: 1px solid var(--line); }
.line2 { border: 1px solid var(--line2); }
.hair { border: 1px solid var(--hair); }
.hair-t { border-top: 1px solid var(--hair); }
.hair-b { border-bottom: 1px solid var(--hair); }
.line-accent { border: 1px solid var(--accent-line); }
.line-danger { border: 1px solid var(--danger-line); }
.line-warn { border: 1px solid var(--warn-line); }
.line-none { border: 0; }

.r-0 { border-radius: 0; }
.r-1 { border-radius: var(--r1); }
.r-2 { border-radius: var(--r2); }
.r-3 { border-radius: var(--r3); }
.r-4 { border-radius: var(--r4); }
.r-5 { border-radius: var(--r5); }
.r-6 { border-radius: var(--r6); }
.r-7 { border-radius: var(--r7); }
.r-pill { border-radius: var(--r-pill); }

.shadow { box-shadow: var(--shadow); }
.shadow-pop { box-shadow: var(--pop); }
.shadow-none { box-shadow: none; }

/* ── what answers a pointer ──────────────────────────────────────────────── */

/* The sheets spelled twenty-two different transitions between them, and
   fifty-three rules wanted the same one: the colours move, nothing else, and
   the eye reads the change as a state rather than as an animation. */
.transition-colors { transition: background var(--quick), border-color var(--quick), color var(--quick); }
.transition-transform { transition: transform var(--quick); }

.cursor-pointer { cursor: pointer; }
.cursor-default { cursor: default; }
.pointer-none { pointer-events: none; }
.pointer-auto { pointer-events: auto; }

.hover-text-ink:hover { color: var(--ink); }
.hover-text-accent:hover { color: var(--accent); }
.hover-text-danger:hover { color: var(--danger); }
.hover-underline:hover { text-decoration: underline; text-underline-offset: 2px; }

.hover-bg-hover:hover { background: var(--hover); }
.hover-bg-chip:hover { background: var(--chip); }
.hover-bg-surface:hover { background: var(--surface); }
.hover-bg-accent-soft:hover { background: var(--accent-soft); }

.hover-line-accent:hover { border-color: var(--accent); }
.hover-line-ink:hover { border-color: var(--ink); }
.hover-line-danger:hover { border-color: var(--danger); }

.active-bg-down:active { background: var(--accent-down); }

/* A ring the keyboard draws and the mouse does not, taking the corner of
   whatever it is put on rather than deciding one of its own. */
.focus-ring:focus-visible { outline: var(--s1) solid var(--accent); outline-offset: var(--s1); border-radius: inherit; }
.focus-none:focus { outline: none; }

/* Not `[disabled]`: a link and a label can be past answering too, and neither
   takes the attribute. */
.disabled { opacity: 0.5; cursor: default; pointer-events: none; }

/* ── the desk (UIC-23) ───────────────────────────────────────────────────── */

/* Mobile is the ground. A utility above is every width, and its `d-` twin
   is the desk — 641px and up, measured on the page's own width (the body is
   the container, `layouts.css`), so a page narrowed by the dock is a phone
   to it. `row d-stack` is a row on a phone and a column on a desk; the twin
   comes after the base in this file, which is what lets it win the tie.
   Only the arrangement has twins: what changes between a phone and a desk
   is where things stand, not what colour they are. */
@container (min-width: 641px) {
  .d-flex { display: flex; }
  .d-stack { display: flex; flex-direction: column; }
  .d-row { display: flex; flex-direction: row; align-items: center; }
  .d-grid { display: grid; }
  .d-grid-2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .d-grid-3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .d-grid-4 { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .d-grid-7 { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); }
  .d-grid-1-2 { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); }
  .d-grid-2-1 { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }
  .d-grid-1-3 { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 3fr); }
  .d-grid-3-1 { display: grid; grid-template-columns: minmax(0, 3fr) minmax(0, 1fr); }
  .d-block { display: block; }
  .d-iflex { display: inline-flex; align-items: center; }
  .d-hidden { display: none; }
  .d-wrap { flex-wrap: wrap; }
  .d-nowrap { flex-wrap: nowrap; }

  .d-start { align-items: flex-start; }
  .d-center { align-items: center; }
  .d-end { align-items: flex-end; }
  .d-stretch { align-items: stretch; }
  .d-between { justify-content: space-between; }
  .d-jstart { justify-content: flex-start; }
  .d-jcenter { justify-content: center; }
  .d-jend { justify-content: flex-end; }

  .d-grow { flex: 1 1 auto; min-width: 0; }
  .d-none { flex: none; }
  .d-w-full { width: 100%; }

  .d-gap-0 { gap: 0; }
  .d-gap-1 { gap: var(--s1); }
  .d-gap-2 { gap: var(--s2); }
  .d-gap-3 { gap: var(--s3); }
  .d-gap-4 { gap: var(--s4); }
  .d-gap-5 { gap: var(--s5); }
  .d-gap-6 { gap: var(--s6); }
  .d-gap-7 { gap: var(--s7); }
  .d-gap-8 { gap: var(--s8); }
  .d-gap-9 { gap: var(--s9); }
  .d-gap-10 { gap: var(--s10); }
  .d-gap-11 { gap: var(--s11); }
  .d-gap-12 { gap: var(--s12); }
  .d-gap-13 { gap: var(--s13); }
}
