/* GENERATED by tools/build_ink.py from: tokens.css, components.css, game.css, parts/controls.css, parts/gallery.css, parts/game-overlay.css, parts/game-identity.css, parts/forms.css, parts/game-density.css, parts/data-hud.css. Do not hand-edit.
   Wrapped in @layer ink so host #id / high-specificity rules win by default (POKER 1);
   see docs/adoption.md to let the kit win back specific legacy rules. */
@layer ink {
/* A-Ink tokens v1 — Buddy Design System foundations (DS-2b). Plain CSS custom properties.
   Two first-class themes from one token set (Steve ruling 2026-11-01, option a): neither is secondary.
   Product default: lab site, docs, dashboards = LIGHT (no attribute needed); games = DARK (body.ink-game).
   Every surface can switch: <html data-theme="light|dark"> overrides the product default, and data-theme on any element
   scopes a theme to that subtree (e.g. a dark Perform panel inside a light app; add .ink-theme-scope to paint it).
   Rules baked in (see docs/role-models.md R1–R12):
   - one warm accent, used on one thing per screen;
   - other hues are state only;
   - two radii;
   - no gradients behind text, no blur;
   - motion only on state changes, 200ms or less. */
/* fonts.css is intentionally not bundled here — fonts are optional (POKER 10).
   Add a-ink/fonts.css or a-ink/fonts-plex.css yourself; see docs/adoption.md. */

:root {

  /* ---- type ---- */
  --ink-font-display: "Newsreader", ink-display-fallback, "Iowan Old Style", Georgia, serif;
  --ink-font-ui:      "IBM Plex Sans", ink-ui-fallback, system-ui, -apple-system, sans-serif;
  --ink-font-mono:    "IBM Plex Mono", ink-mono-fallback, ui-monospace, "SF Mono", monospace;
  /* scale: named by role */
  --ink-fs-display: clamp(2.5rem, 5.2vw, 4.25rem);
  --ink-fs-h1:      clamp(1.875rem, 3.7vw, 3.5rem);
  --ink-fs-h2:      1.375rem;
  --ink-fs-h3:      1rem;
  --ink-fs-lede:    1.25rem;
  --ink-fs-prose:   1.125rem;
  --ink-fs-body:    1rem;       /* 16px: role-model median (docs/benchmarks.md) */
  --ink-fs-sm:      0.9375rem;  /* 15px below desktop; panel round 4 measured 14px as too small beside 16px role-model body */
  --ink-fs-xs:      0.8125rem;  /* 13px: phone meta labels (folios, timestamps) measured too small at 12px */
  --ink-lh:         1.5;
  --ink-lh-tight:   1.15;

  /* ---- tracking: letter-spacing tiers (GECKO 18) ---- */
  --ink-track-tight:  -0.02em;  /* dense tabular mono figures (.ink-stat__value, .ink-hud__big, .ink-data-dense) */
  --ink-track-normal: 0em;      /* explicit reset, e.g. a mono suffix sitting next to tracked caps text */
  --ink-track-wide:   0.02em;   /* opened slightly — small mono readouts that need a little more air than tight */
  --ink-track-caps:   0.06em;   /* uppercase eyebrow/label convention (the majority value already in the kit) */

  /* ---- space (4px base) ---- */
  --ink-1: 4px;  --ink-2: 8px;  --ink-3: 12px; --ink-4: 16px;
  --ink-5: 24px; --ink-6: 32px; --ink-7: 48px; --ink-8: 72px;

  /* ---- layout ---- */
  --ink-max: 1240px;
  --ink-margin-col: 88px;   /* ledger margin (signature) */
  --ink-gutter: 24px;
  --ink-sidenav: 232px;
  --ink-control-h: 36px;
  --ink-target-phone: 44px;  /* minimum tap target below the tablet breakpoint */
  --ink-control-h-sm: 28px;
  /* breakpoints (for reference; media queries can't read vars): phone < 760px · tablet 760–1099 · desktop >= 1100 */
  --ink-bp-tablet: 760px;
  --ink-bp-desktop: 1100px;

  /* ---- shape: exactly two radii (+ round for avatars and dots) ---- */
  --ink-r-sm: 4px;
  --ink-r-md: 8px;
  --ink-r-round: 50%;

  /* ---- elevation: borders and lightness first; shadows are short (R10: blur <= 8px) ---- */
  --ink-elev-0: none;

  /* ---- motion: state changes only ---- */
  --ink-dur-fast: 100ms;
  --ink-dur:      140ms;
  --ink-dur-slow: 200ms;    /* ceiling (R7) */
  --ink-delay-tip: 300ms;   /* tooltip show-delay: a wait before appearing, not an animation length */
  --ink-ease: cubic-bezier(.2, 0, 0, 1);

  /* ---- z-index ---- */
  --ink-z-base: 0;
  --ink-z-sticky: 10;
  --ink-z-menu: 20;
  --ink-z-sheet: 30;
  --ink-z-modal: 40;
  --ink-z-toast: 50;
  --ink-z-tooltip: 60;
}

/* touch screens: every control clears a 44px target without per-page work (DS-S gap: kit buttons failed tap counts) */
@media (pointer: coarse) { :root { --ink-control-h: 44px; --ink-control-h-sm: 44px; } }

/* desktop: --ink-fs-sm is the dominant UI text size (not a secondary one) at this width, so it rounds up to 16px */
@media (min-width: 1024px) { :root { --ink-fs-sm: 1rem; --ink-fs-xs: 0.875rem; } }  /* desktop meta/labels 14px (panel round 22 lens 1); phone stays 13px */

/* @theme light — default for the lab site, docs and dashboards. Accent darkened to keep AA on paper. */
:root, [data-theme="light"] {
  color-scheme: light;
  color-scheme: light;
  --ink-sunk:        #ECE6DC;
  --ink-bg:          #F6F3EE;
  --ink-surface:     #FFFFFF;
  --ink-raised:      #EFEBE4;
  --ink-overlay:     #FFFFFF;
  /* semantic card steps: in light, --ink-raised is a hover/selected TINT (darker than paper), so cards sit on white */
  --ink-card:        var(--ink-surface);
  --ink-skel:        var(--ink-raised);   /* loading bars: a tint on white cards */
  --ink-panel:       var(--ink-raised);   /* secondary panels (metrics strip, receipt, empty state): a tint between paper and the white card */
  --ink-card-sub:    var(--ink-bg);
  --ink-line:        #DDD7CD;
  --ink-line-strong: #8B7F72;  /* control borders: >= 3:1 on every light surface (WCAG 1.4.11; tools/check_tokens.py) */
  --ink-scrim:       rgba(30, 27, 23, .45);
  --ink-text:   #1D1B18;
  --ink-muted:  #5C564D;
  --ink-faint:  #6B6458;
  --ink-accent:       #B0441E;   /* >= 4.5:1 on every light surface incl. --ink-sunk (was #B4461F, 4.41 on sunk; R19) */
  --ink-accent-hover: #9E3B18;
  --ink-on-accent:    #FFFFFF;
  --ink-accent-wash:  rgba(180, 70, 31, .10);
  --ink-ok:    #2E6B3F;
  --ink-hold:  #855C0B;
  --ink-fault: #A8382A;
  --ink-fault-line: #A8382A;
  --ink-heat-1: #E2DBCF; --ink-heat-2: #C4B9A7; --ink-heat-3: #8F8370;
  --ink-elev-1: 0 1px 0 rgba(60, 40, 20, .07);
  --ink-elev-2: 0 2px 8px rgba(0, 0, 0, .12);
  /* data hues: series and team/faction marks ONLY (chart lines, faction chips, legend dots) — never UI, never state.
     Kept off the accent (17°) and the state hues; each is >= 4.5:1 on every surface. DS-S kit gap (3DDEPT, GECKO). */
  --ink-data-1: #2F5F9E; --ink-data-2: #22706B; --ink-data-3: #7D4A80; --ink-data-4: #4F5966;
  --ink-lamp-off: #8F8370;     /* an unlit lamp: clears 3:1 against bg and surface (DS-S GECKO gap 4) */
}

/* @theme dark — default for games; any page opts in with data-theme="dark". Five warm surface steps. */
[data-theme="dark"], :root:not([data-theme="light"]) .ink-game {
  color-scheme: dark;
  /* ---- color: surfaces — five warm steps, ~5% lightness apart (Steve fb-1: dark read bland next to light) ---- */
  --ink-sunk:        #0B0A08;  /* wells: empty heat cells, code, track grooves */
  --ink-bg:          #13110E;  /* page: warm near-black, not neutral grey */
  --ink-surface:     #1E1B17;  /* panels, cards, table body: lifts off the page like light's white on paper */
  --ink-raised:      #29251F;  /* hover/selected row, inputs, menus */
  --ink-overlay:     #322D27;  /* modal, sheet, toast, tooltip */
  --ink-card:        var(--ink-raised);   /* cards lift one step above panels in dark */
  --ink-skel:        var(--ink-overlay);  /* loading bars: one step above the raised card, or they vanish into it (panel r16 lenses 5-6) */
  --ink-panel:       var(--ink-surface);  /* secondary panels sit between the page and the raised card (panel lens 5, rounds 20/22/23) */
  --ink-card-sub:    var(--ink-bg);       /* sub-pane one step below the raised card, as light does (panel r14/r16/r17 lens 5: dark detail pane read flat) */
  --ink-line:        #433C33;  /* hairlines: visible but quiet */
  --ink-line-strong: #857A6B;  /* ledger rule, control borders: >= 3:1 on every dark surface (WCAG 1.4.11; tools/check_tokens.py) */
  --ink-scrim:       rgba(8, 7, 6, .72);

  /* ---- color: text (warm ink, not neutral grey) ---- */
  --ink-text:   #F0E8DB;
  --ink-muted:  #B3A898;
  --ink-faint:  #A69A89;       /* timestamps, folios, disabled text: still >= 4.5:1 on every surface */

  /* ---- color: the one accent (vermilion ink) ---- */
  --ink-accent:       #F0784A;
  --ink-accent-hover: #F68A5E;
  --ink-on-accent:    #13110E;
  --ink-accent-wash:  rgba(240, 120, 74, .15);   /* selected background behind --ink-text only */

  /* ---- color: state hues (meaning only) ---- */
  --ink-ok:    #8BC49A;
  --ink-hold:  #DDB25A;
  --ink-fault: #EE8A78;
  --ink-fault-line: #B85A4A;   /* error border on inputs */
  /* activity heat (day strip): levels 1–3; level 4 = --ink-text. Near-neutral warm greys (C* < 3) so
     amber/ochre stays reserved for hold/gate states — heat no longer competes with --ink-hold. */
  --ink-heat-1: #353331; --ink-heat-2: #5F5C59; --ink-heat-3: #908D89;

  --ink-elev-1: inset 0 1px 0 rgba(255, 236, 210, .045), 0 1px 0 rgba(0, 0, 0, .45);  /* top-edge light + floor line */
  --ink-elev-2: inset 0 1px 0 rgba(255, 236, 210, .06), 0 2px 8px rgba(0, 0, 0, .5);
  --ink-data-1: #8AB0E6; --ink-data-2: #74C4BC; --ink-data-3: #CDA2D2; --ink-data-4: #AEB8C4;
  --ink-lamp-off: #7A7064;
}

/* A-Ink components v1 — plain CSS, needs tokens.css first. Class prefix: ink-. Minimal JS lives in ink.js.
   State hooks: every interactive component styles its real pseudo-class AND a mirror class, so the playbook
   can show a state at rest:
     :hover = .is-hover   ·   :focus-visible = .is-focus   ·   :active = .is-active
     :disabled / [aria-disabled="true"] = .is-disabled   ·   .is-loading   ·   [aria-invalid="true"] = .is-error
   SIGNATURE — the ledger margin: each section opens on a full-width rule. Its serial (§ 01) and date sit in a mono
   margin column, like a numbered lab notebook. On phones the folio becomes a running head with a rule drawn
   through it. The warm accent marks ONE thing per screen. */

.ink, .ink *, .ink::before, .ink::after, .ink *::before, .ink *::after { box-sizing: border-box; }
.ink { color: var(--ink-text); font: 400 var(--ink-fs-body)/var(--ink-lh) var(--ink-font-ui); -webkit-font-smoothing: antialiased; }
body.ink { margin: 0; background: var(--ink-bg); }
html:has(body.ink) { background: var(--ink-bg); }
:where(.ink) a { color: inherit; text-decoration: underline; text-decoration-color: var(--ink-line-strong); text-underline-offset: 3px; }
:where(.ink) a:hover { text-decoration-color: var(--ink-text); }
.ink :focus-visible, .ink .is-focus { outline: 2px solid var(--ink-text); outline-offset: 2px; }
:where(.ink) :is(h1, h2, h3, h4) { margin: 0; font-weight: 500; }
:where(.ink) h1 { font: 500 var(--ink-fs-h1)/1.1 var(--ink-font-display); letter-spacing: -0.01em; font-variation-settings: "opsz" 72; }
:where(.ink) h2 { font: 500 var(--ink-fs-h2)/1.2 var(--ink-font-display); font-variation-settings: "opsz" 36; }
:where(.ink) h3 { font: 600 var(--ink-fs-h3)/1.3 var(--ink-font-ui); }
:where(.ink) h4 { font: 600 var(--ink-fs-sm)/1.3 var(--ink-font-ui); }
:where(.ink) p { margin: 0 0 var(--ink-3); }
:where(.ink) p:last-child { margin-bottom: 0; }
.ink code { overflow-wrap: anywhere; font: 400 0.92em var(--ink-font-mono); background: var(--ink-raised); padding: 1px 4px; border-radius: var(--ink-r-sm); }
.ink .ink-btn kbd { color: inherit; border-color: currentColor; background: transparent; }
.ink pre { font: 400 var(--ink-fs-sm)/1.55 var(--ink-font-mono); background: var(--ink-bg); border: 1px solid var(--ink-line);
  border-radius: var(--ink-r-md); padding: var(--ink-3) var(--ink-4); overflow-x: auto; margin: 0 0 var(--ink-4); }
.ink pre code { background: none; padding: 0; }
.ink-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* ---- text roles ---- */
.ink-display { font: 400 var(--ink-fs-display)/1.02 var(--ink-font-display); letter-spacing: var(--ink-track-tight); font-variation-settings: "opsz" 72; margin: 0; }
.ink-display em { font-style: italic; }
.ink-lede { font: 400 var(--ink-fs-lede)/1.45 var(--ink-font-display); font-variation-settings: "opsz" 24; color: var(--ink-muted); max-width: 46ch; }
.ink-lede strong { color: var(--ink-text); font-weight: 500; }
.ink-prose { font: 400 var(--ink-fs-prose)/1.6 var(--ink-font-display); font-variation-settings: "opsz" 16; max-width: 62ch; }
.ink-prose p, .ink-prose ul, .ink-prose ol { margin: 0 0 var(--ink-4); }
.ink-prose h2 { margin: var(--ink-6) 0 var(--ink-3); }
.ink-prose h3 { margin: var(--ink-5) 0 var(--ink-2); }
.ink-prose blockquote { margin: 0 0 var(--ink-4); padding-left: var(--ink-4); border-left: 2px solid var(--ink-line-strong); color: var(--ink-muted); font-style: italic; }
.ink-muted { color: var(--ink-muted); }
.ink-faint { color: var(--ink-faint); }
.ink-label { font: 500 var(--ink-fs-xs)/1.3 var(--ink-font-ui); letter-spacing: var(--ink-track-caps); text-transform: uppercase; color: var(--ink-muted); }
.ink-mono, .ink-hash { font-family: var(--ink-font-mono); font-size: var(--ink-fs-sm); font-feature-settings: "tnum" 1; }
.ink-hash { color: var(--ink-muted); }
.ink-num { font-family: var(--ink-font-mono); font-feature-settings: "tnum" 1; }
.ink-sm { font-size: var(--ink-fs-sm); }
.ink-ok { color: var(--ink-ok); } .ink-hold { color: var(--ink-hold); } .ink-fault { color: var(--ink-fault); }

/* ---- icon ---- */
.ink-icon { width: 16px; height: 16px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; vertical-align: -3px; }
.ink-icon--lg { width: 20px; height: 20px; }
.ink-icon--xl { width: 32px; height: 32px; stroke-width: 1.5; }

/* ---- layout primitives (so pages need no CSS of their own) ---- */
.ink-shell { max-width: var(--ink-max); margin: 0 auto; padding: 0 var(--ink-gutter) var(--ink-8); }
.ink-shell--narrow { max-width: 760px; }
.ink-stack { display: flex; flex-direction: column; gap: var(--ink-4); }
.ink-stack--sm { gap: var(--ink-2); } .ink-stack--lg { gap: var(--ink-6); }
.ink-row { display: flex; align-items: center; gap: var(--ink-2); flex-wrap: wrap; }
.ink-row--between { justify-content: space-between; }
.ink-row--end { justify-content: flex-end; }
.ink-grid { display: grid; gap: var(--ink-5); grid-template-columns: repeat(var(--cols, 2), minmax(0, 1fr)); }
.ink-grid--2 { --cols: 2; } .ink-grid--3 { --cols: 3; } .ink-grid--4 { --cols: 4; }
.ink-grid--main-aside { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }
.ink-grid--aside-main { grid-template-columns: minmax(200px, 1fr) minmax(0, 3fr); }
.ink-grid--hero { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: var(--ink-7); align-items: end; }
.ink-gap-0 { gap: 0; }
.ink-mt-2 { margin-top: var(--ink-2); } .ink-mt-3 { margin-top: var(--ink-3); } .ink-mt-4 { margin-top: var(--ink-4); } .ink-mt-5 { margin-top: var(--ink-5); } .ink-mt-6 { margin-top: var(--ink-6); }
.ink-mb-0 { margin-bottom: 0; } .ink-mb-2 { margin-bottom: var(--ink-2); } .ink-mb-4 { margin-bottom: var(--ink-4); } .ink-mt-7 { margin-top: var(--ink-7); }
.ink kbd { font: 400 var(--ink-fs-xs)/1 var(--ink-font-mono); color: var(--ink-muted); padding: 2px 4px; border: 1px solid var(--ink-line-strong); border-radius: var(--ink-r-sm); }
@media (max-width: 759px) {
  .ink-grid, .ink-grid--main-aside, .ink-grid--aside-main, .ink-grid--hero { grid-template-columns: minmax(0, 1fr); gap: var(--ink-6); }  /* stacked columns read as sections: 32px, never 16 */
  .ink-grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ---- nav bar ---- */
.ink-topbar { display: flex; align-items: center; gap: var(--ink-5); height: 56px; border-bottom: 1px solid var(--ink-line);
  max-width: var(--ink-max); margin: 0 auto; padding: 0 var(--ink-gutter); }
.ink-wordmark { font: 500 1.125rem/1 var(--ink-font-display); letter-spacing: -0.01em; text-decoration: none !important; white-space: nowrap; }
.ink-wordmark b { font-weight: 500; font-style: italic; }
.ink-nav { display: flex; gap: var(--ink-1); margin: 0; padding: 0; list-style: none; overflow-x: auto; scrollbar-width: none; min-width: 0; }
.ink-nav a { display: block; padding: var(--ink-2) var(--ink-3); font-size: var(--ink-fs-sm); color: var(--ink-muted); text-decoration: none; border-radius: var(--ink-r-sm); white-space: nowrap; }
.ink-nav a:hover, .ink-nav a.is-hover { color: var(--ink-text); background: var(--ink-surface); }
.ink-nav a[aria-current="page"] { color: var(--ink-text); box-shadow: inset 0 -2px 0 var(--ink-text); border-radius: 0; }
.ink-topbar__end { margin-left: auto; display: flex; align-items: center; gap: var(--ink-3); }
@media (max-width: 759px) { .ink-topbar { gap: var(--ink-3); padding: 0 var(--ink-4); } .ink-topbar__end .ink-hide-phone { display: none; } }

/* ---- side nav + app layout ---- */
.ink-app { display: grid; grid-template-columns: var(--ink-sidenav) minmax(0, 1fr); min-height: 100vh; }
.ink-app__main { min-width: 0; padding: 0 var(--ink-6) var(--ink-8); }
.ink-sidenav { border-right: 1px solid var(--ink-line); padding: var(--ink-4) var(--ink-3); background: var(--ink-bg); }
.ink-sidenav .ink-wordmark { display: block; padding: var(--ink-2) var(--ink-3) var(--ink-5); }
.ink-sidenav__group { margin: 0 0 var(--ink-5); padding: 0; list-style: none; }
.ink-sidenav__title { padding: 0 var(--ink-3) var(--ink-2); }
.ink-sidenav a { display: flex; align-items: center; gap: var(--ink-3); padding: 6px var(--ink-3); border-radius: var(--ink-r-sm);
  color: var(--ink-muted); text-decoration: none; font-size: var(--ink-fs-sm); }
.ink-sidenav a:hover, .ink-sidenav a.is-hover { color: var(--ink-text); background: var(--ink-surface); }
.ink-sidenav a[aria-current="page"] { color: var(--ink-text); background: var(--ink-raised); }
.ink-sidenav a .ink-count { margin-left: auto; font: 400 var(--ink-fs-xs) var(--ink-font-mono); color: var(--ink-faint); }
@media (max-width: 759px) {
  .ink-app { grid-template-columns: minmax(0, 1fr); }
  .ink-sidenav { border-right: 0; border-bottom: 1px solid var(--ink-line); padding: var(--ink-2) var(--ink-4); display: flex; align-items: center; gap: var(--ink-2); overflow-x: auto; }
  .ink-sidenav .ink-wordmark { padding: 0 var(--ink-3) 0 0; }
  .ink-sidenav__group { display: flex; margin: 0; } .ink-sidenav__title { display: none; }
  .ink-sidenav a { white-space: nowrap; }
  .ink-app__main { padding: 0 var(--ink-4) var(--ink-7); }
}

/* ---- breadcrumb ---- */
.ink-crumbs { display: flex; flex-wrap: wrap; align-items: center; gap: var(--ink-2); margin: 0 0 var(--ink-3); padding: 0; list-style: none; font-size: var(--ink-fs-sm); color: var(--ink-muted); }
.ink-crumbs li + li::before { content: "/"; margin-right: var(--ink-2); color: var(--ink-faint); }
.ink-crumbs a { color: var(--ink-muted); text-decoration: none; }
.ink-crumbs a:hover { color: var(--ink-text); text-decoration: underline; }
.ink-crumbs [aria-current="page"] { color: var(--ink-text); }

/* ---- SIGNATURE: ledger margin ---- */
.ink-ledger { display: grid; grid-template-columns: var(--ink-margin-col) minmax(0, 1fr); column-gap: var(--ink-gutter);
  border-top: 1px solid var(--ink-line-strong); padding-top: var(--ink-4); margin-top: var(--ink-7); }
.ink-ledger:first-child, .ink-ledger--first { margin-top: var(--ink-6); }
.ink-folio { font: 400 var(--ink-fs-xs)/1.5 var(--ink-font-mono); color: var(--ink-faint); font-feature-settings: "tnum" 1; }
.ink-folio b { display: block; color: var(--ink-text); font-weight: 500; }
.ink-ledger__head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--ink-4); flex-wrap: wrap; margin-bottom: var(--ink-4); }
.ink-ledger__body { min-width: 0; }
@media (max-width: 759px) {
  /* phone: the folio is a running head — serial, a rule drawn through, then the date */
  .ink-ledger { grid-template-columns: minmax(0, 1fr); border-top: 0; padding-top: 0; margin-top: var(--ink-6); }
  .ink-folio { display: flex; align-items: center; gap: var(--ink-3); margin-bottom: var(--ink-3); white-space: nowrap; }
  .ink-folio b { display: inline; font-size: var(--ink-fs-sm); }
  .ink-folio::after { content: ""; order: 1; flex: 1; height: 1px; background: var(--ink-line-strong); }
  .ink-folio b { order: 0; } .ink-folio > span { order: 2; min-width: 0; max-width: 70%; white-space: normal; text-align: right; } /* wrap, never ellipsise (R17) */
  .ink-folio::after { min-width: 24px; }
  .ink-folio br { display: none; }
}

/* the one-accent marker */
.ink-stamp { display: inline-block; width: 8px; height: 8px; background: var(--ink-accent); vertical-align: 0.08em; margin-right: var(--ink-2); }

/* ---- button + icon button ---- */
.ink-btn { position: relative; display: inline-flex; align-items: center; justify-content: center; gap: var(--ink-2); min-height: var(--ink-control-h); padding: 0 var(--ink-4);
  font: 500 var(--ink-fs-sm)/1 var(--ink-font-ui); color: var(--ink-text); background: transparent; white-space: nowrap;
  border: 1px solid var(--ink-line-strong); border-radius: var(--ink-r-sm); cursor: pointer; text-decoration: none !important;
  transition: background var(--ink-dur) var(--ink-ease), border-color var(--ink-dur) var(--ink-ease), transform var(--ink-dur-fast) var(--ink-ease); }
.ink-btn:hover, .ink-btn.is-hover { background: var(--ink-raised); border-color: var(--ink-muted); }
.ink-btn:active, .ink-btn.is-active { transform: translateY(1px); background: var(--ink-overlay); }
.ink-btn--primary { background: var(--ink-accent); border-color: var(--ink-accent); color: var(--ink-on-accent); }
.ink-btn--primary:hover, .ink-btn--primary.is-hover { background: var(--ink-accent-hover); border-color: var(--ink-accent-hover); }
.ink-btn--primary:active, .ink-btn--primary.is-active { background: var(--ink-accent-hover); }
.ink-btn--quiet { border-color: transparent; color: var(--ink-muted); }
.ink-btn--quiet:hover, .ink-btn--quiet.is-hover { color: var(--ink-text); background: var(--ink-surface); border-color: transparent; }
.ink-btn--danger { color: var(--ink-fault); border-color: var(--ink-fault-line); }
.ink-btn--danger:hover, .ink-btn--danger.is-hover { background: var(--ink-raised); border-color: var(--ink-fault); }
.ink-btn--sm { min-height: var(--ink-control-h-sm); padding: 0 var(--ink-3); font-size: var(--ink-fs-xs); }
.ink-btn--block { display: flex; width: 100%; }
.ink-btn:disabled, .ink-btn[aria-disabled="true"], .ink-btn.is-disabled {
  cursor: not-allowed; transform: none; color: var(--ink-faint); background: transparent; border-color: var(--ink-line); border-style: dashed; }
/* loading: the label stays readable ("Saving…") and a spinner leads it; with reduced motion the spinner becomes three
   static dots, so a frozen ring never reads as a letter (panel round 5) */
.ink-btn.is-loading { pointer-events: none; }
.ink-btn.is-loading::before { content: ""; flex: none; width: 12px; height: 12px; border-radius: var(--ink-r-round);
  border: 2px solid currentColor; border-right-color: transparent; animation: ink-spin 800ms linear infinite; }
.ink-btn.is-loading::after { content: "…"; margin-left: calc(-1 * var(--ink-2)); }
@media (prefers-reduced-motion: reduce) {
  .ink-btn.is-loading::before { animation: none; border: 0; width: auto; height: auto; content: "···"; letter-spacing: 1px; }
}
.ink-iconbtn { display: inline-grid; place-items: center; width: var(--ink-control-h); height: var(--ink-control-h); padding: 0; flex: none;
  color: var(--ink-muted); background: transparent; border: 1px solid transparent; border-radius: var(--ink-r-sm); cursor: pointer;
  transition: background var(--ink-dur) var(--ink-ease), color var(--ink-dur) var(--ink-ease); }
.ink-iconbtn:hover, .ink-iconbtn.is-hover { color: var(--ink-text); background: var(--ink-raised); }
.ink-iconbtn:active, .ink-iconbtn.is-active { background: var(--ink-overlay); }
.ink-iconbtn[aria-pressed="true"] { color: var(--ink-text); border-color: var(--ink-line-strong); }
.ink-iconbtn:disabled, .ink-iconbtn.is-disabled { color: var(--ink-faint); cursor: not-allowed; background: transparent; }
.ink-iconbtn--sm { width: var(--ink-control-h-sm); height: var(--ink-control-h-sm); }
@keyframes ink-spin { to { transform: rotate(360deg); } }

/* ---- link ---- */
.ink-link { color: var(--ink-text); text-decoration: underline; text-decoration-color: var(--ink-line-strong); text-underline-offset: 3px; display: inline-flex; align-items: center; gap: 4px; }
.ink-link:hover, .ink-link.is-hover { text-decoration-color: var(--ink-text); }
.ink-link--quiet { color: var(--ink-muted); text-decoration: none; }
.ink-link--quiet:hover, .ink-link--quiet.is-hover { color: var(--ink-text); }

/* ---- form fields: input, textarea, select ---- */
.ink-field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.ink-field > label, .ink-field__label { font-size: var(--ink-fs-sm); font-weight: 500; }
.ink-field__help { font-size: var(--ink-fs-xs); color: var(--ink-muted); }
.ink-field__error { font-size: var(--ink-fs-xs); color: var(--ink-fault); display: flex; gap: 6px; align-items: center; }
.ink-input, .ink-textarea, .ink-select { width: 100%; min-width: 0; min-height: var(--ink-control-h); padding: 0 var(--ink-3);
  background: var(--ink-bg); color: var(--ink-text); border: 1px solid var(--ink-line-strong); border-radius: var(--ink-r-sm);
  font: 400 var(--ink-fs-sm)/1.4 var(--ink-font-ui); transition: border-color var(--ink-dur) var(--ink-ease); }
.ink-input--inline { width: auto; min-width: 220px; }
.ink-textarea { padding: var(--ink-2) var(--ink-3); min-height: 96px; resize: vertical; display: block; }
.ink-select { appearance: none; padding-right: 32px; cursor: pointer;
  background-image: linear-gradient(45deg, transparent 50%, var(--ink-muted) 50%), linear-gradient(135deg, var(--ink-muted) 50%, transparent 50%);
  background-position: calc(100% - 17px) 50%, calc(100% - 12px) 50%; background-size: 5px 5px; background-repeat: no-repeat; }
.ink-input::placeholder, .ink-textarea::placeholder { color: var(--ink-faint); }
.ink-input:hover, .ink-textarea:hover, .ink-select:hover, .ink-input.is-hover { border-color: var(--ink-muted); }
.ink-input:focus-visible, .ink-textarea:focus-visible, .ink-select:focus-visible, .ink-input.is-focus, .ink-textarea.is-focus {
  outline: 2px solid var(--ink-text); outline-offset: 0; border-color: var(--ink-text); }
.ink-input[aria-invalid="true"], .ink-textarea[aria-invalid="true"], .ink-select[aria-invalid="true"], .ink-input.is-error { border-color: var(--ink-fault-line); }
.ink-input:disabled, .ink-textarea:disabled, .ink-select:disabled, .ink-input.is-disabled {
  color: var(--ink-faint); background: var(--ink-surface); border-style: dashed; border-color: var(--ink-line); cursor: not-allowed; }
.ink-input-group { position: relative; display: flex; align-items: center; }
.ink-input-group > .ink-icon { position: absolute; left: 10px; color: var(--ink-faint); pointer-events: none; }
.ink-input-group > .ink-input { padding-left: 32px; }
@media (max-width: 759px) { .ink-input { font-size: 16px; } }  /* 16px stops iOS auto-zoom on focus */

/* ---- checkbox + radio ---- */
.ink-check { display: inline-flex; align-items: flex-start; gap: var(--ink-2); font-size: var(--ink-fs-sm); cursor: pointer; line-height: 1.4; }
.ink-check input { appearance: none; margin: 1px 0 0; width: 16px; height: 16px; flex: none; display: grid; place-content: center;
  background: var(--ink-bg); border: 1px solid var(--ink-line-strong); border-radius: var(--ink-r-sm); cursor: pointer;
  transition: background var(--ink-dur) var(--ink-ease), border-color var(--ink-dur) var(--ink-ease); }
.ink-check input[type="radio"] { border-radius: var(--ink-r-round); }
.ink-check:hover input, .ink-check.is-hover input { border-color: var(--ink-text); }
.ink-check input:checked { background: var(--ink-text); border-color: var(--ink-text); }
.ink-check input[type="checkbox"]:checked::before { content: ""; width: 9px; height: 5px; border: solid var(--ink-bg); border-width: 0 0 2px 2px; transform: translateY(-1px) rotate(-45deg); }
.ink-check input[type="radio"]:checked::before { content: ""; width: 6px; height: 6px; border-radius: var(--ink-r-round); background: var(--ink-bg); }
.ink-check input:focus-visible, .ink-check.is-focus input { outline: 2px solid var(--ink-text); outline-offset: 2px; }
.ink-check input[aria-invalid="true"] { border-color: var(--ink-fault); }
.ink-check:has(input:disabled), .ink-check.is-disabled { color: var(--ink-faint); cursor: not-allowed; }
.ink-check input:disabled { border-style: dashed; border-color: var(--ink-line-strong); background: var(--ink-surface); cursor: not-allowed; }
.ink-fieldset { border: 0; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--ink-2); }
.ink-fieldset legend { font-size: var(--ink-fs-sm); font-weight: 500; margin-bottom: var(--ink-2); padding: 0; }

/* ---- switch ---- */
.ink-switch { position: relative; display: inline-flex; align-items: center; gap: var(--ink-3); font-size: var(--ink-fs-sm); cursor: pointer; }
.ink-switch::before { content: ""; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 32px; height: 24px; } /* invisible hit area; track stays 32x18 */
.ink-switch input { appearance: none; margin: 0; flex: none; position: relative; width: 32px; height: 18px; border-radius: var(--ink-r-sm);
  background: var(--ink-raised); border: 1px solid var(--ink-line-strong); cursor: pointer; transition: background var(--ink-dur) var(--ink-ease); }
.ink-switch input::before { content: ""; position: absolute; top: 2px; left: 2px; width: 12px; height: 12px; border-radius: var(--ink-r-sm);
  background: var(--ink-muted); transition: transform var(--ink-dur) var(--ink-ease), background var(--ink-dur) var(--ink-ease); }
.ink-switch:hover input, .ink-switch.is-hover input { border-color: var(--ink-text); }
.ink-switch input:checked { background: var(--ink-text); border-color: var(--ink-text); }
.ink-switch input:checked::before { transform: translateX(14px); background: var(--ink-bg); }
.ink-switch input:focus-visible, .ink-switch.is-focus input { outline: 2px solid var(--ink-text); outline-offset: 2px; }
.ink-switch:has(input:disabled), .ink-switch.is-disabled { color: var(--ink-faint); cursor: not-allowed; }
.ink-switch input:disabled { border-style: dashed; cursor: not-allowed; }

/* ---- slider ---- */
.ink-slider { width: 100%; appearance: none; height: 20px; background: transparent; margin: 0; cursor: pointer; }
.ink-slider::-webkit-slider-runnable-track { height: 2px; background: var(--ink-line-strong); }
.ink-slider::-moz-range-track { height: 2px; background: var(--ink-line-strong); }
.ink-slider::-webkit-slider-thumb { appearance: none; width: 14px; height: 14px; margin-top: -6px; border-radius: var(--ink-r-round); background: var(--ink-text); border: 2px solid var(--ink-bg); }
.ink-slider::-moz-range-thumb { width: 14px; height: 14px; border-radius: var(--ink-r-round); background: var(--ink-text); border: 2px solid var(--ink-bg); }
.ink-slider:focus-visible, .ink-slider.is-focus { outline: 2px solid var(--ink-text); outline-offset: 4px; }
.ink-slider:disabled { cursor: not-allowed; opacity: .5; }

/* ---- tabs + segmented control ---- */
.ink-tabs { display: flex; gap: var(--ink-4); border-bottom: 1px solid var(--ink-line); margin-bottom: var(--ink-4); overflow-x: auto; scrollbar-width: none; }
.ink-tabs a, .ink-tabs button { padding: var(--ink-2) 0; font: 400 var(--ink-fs-sm) var(--ink-font-ui); color: var(--ink-muted); text-decoration: none; white-space: nowrap;
  background: none; border: 0; cursor: pointer; }
.ink-tabs a:hover, .ink-tabs button:hover, .ink-tabs .is-hover { color: var(--ink-text); }
.ink-tabs [aria-current="true"], .ink-tabs [aria-selected="true"] { color: var(--ink-text); box-shadow: inset 0 -2px 0 var(--ink-text); }
.ink-tabs [aria-disabled="true"], .ink-tabs button:disabled { color: var(--ink-faint); cursor: not-allowed; }
.ink-tabs .ink-count, .ink-seg .ink-count { font: 400 var(--ink-fs-xs) var(--ink-font-mono); color: var(--ink-faint); margin-left: 4px; }
.ink-seg { display: inline-flex; padding: 2px; gap: 2px; background: var(--ink-surface); border: 1px solid var(--ink-line-strong); border-radius: var(--ink-r-md); }
.ink-seg button { display: inline-flex; align-items: center; gap: 6px; min-height: var(--ink-control-h-sm); padding: 0 var(--ink-3); font: 500 var(--ink-fs-xs) var(--ink-font-ui); color: var(--ink-muted);
  background: transparent; border: 0; border-radius: var(--ink-r-sm); cursor: pointer; transition: background var(--ink-dur) var(--ink-ease); }
.ink-seg button:hover, .ink-seg button.is-hover { color: var(--ink-text); }
.ink-seg button[aria-pressed="true"] { color: var(--ink-text); background: var(--ink-overlay); box-shadow: var(--ink-elev-1); }
.ink-seg button:disabled { color: var(--ink-faint); cursor: not-allowed; }

/* ---- badge / status (dot + word; never a filled pill) ---- */
.ink-state { display: inline-flex; align-items: center; gap: 6px; font-size: var(--ink-fs-sm); white-space: nowrap; color: var(--ink-muted); }
.ink-state::before { content: ""; width: 7px; height: 7px; border-radius: var(--ink-r-round); background: var(--ink-faint); flex: none; }
.ink-state--ok { color: var(--ink-ok); }       .ink-state--ok::before { background: var(--ink-ok); }
.ink-state--hold { color: var(--ink-hold); }   .ink-state--hold::before { background: var(--ink-hold); }
.ink-state--fault { color: var(--ink-fault); } .ink-state--fault::before { background: var(--ink-fault); }
.ink-state--idle { color: var(--ink-muted); }
.ink-state--live::before { background: var(--ink-text); box-shadow: 0 0 0 2px var(--ink-line-strong); }  /* live = activity, not a fault: neutral ink, not red */
.ink-tag { display: inline-flex; align-items: center; gap: 4px; padding: 1px 6px; font: 500 var(--ink-fs-xs)/1.5 var(--ink-font-mono);
  color: var(--ink-muted); border: 1px solid var(--ink-line-strong); border-radius: var(--ink-r-sm); white-space: nowrap; }

/* ---- card (bordered panel; never a floating soft-shadow card) ---- */
.ink-card { background: var(--ink-card); border: 1px solid var(--ink-line); border-radius: var(--ink-r-md); box-shadow: var(--ink-elev-1); padding: var(--ink-4); min-width: 0; }
.ink-card--flush { padding: 0; overflow: hidden; }
.ink-card__head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--ink-3); margin-bottom: var(--ink-3); }
.ink-card__foot { margin-top: var(--ink-4); padding-top: var(--ink-3); border-top: 1px solid var(--ink-line); }
a.ink-card { display: block; text-decoration: none; transition: border-color var(--ink-dur) var(--ink-ease); }
a.ink-card:hover, .ink-card.is-hover { border-color: var(--ink-line-strong); }

/* ---- stats strip + sparkline + day strip (real-dashboard parts) ---- */
.ink-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); border: 1px solid var(--ink-line); border-radius: var(--ink-r-md); box-shadow: var(--ink-elev-1); background: var(--ink-panel); }
.ink-stat { padding: var(--ink-4); border-right: 1px solid var(--ink-line); min-width: 0; }
.ink-stat:last-child { border-right: 0; }
.ink-stat__value { display: flex; align-items: baseline; gap: var(--ink-2); font: 500 1.75rem/1.1 var(--ink-font-mono); font-feature-settings: "tnum" 1; margin: var(--ink-1) 0; letter-spacing: var(--ink-track-tight); }
.ink-stat__value small { font-size: var(--ink-fs-sm); color: var(--ink-muted); letter-spacing: var(--ink-track-normal); }
.ink-stat__delta { font-size: var(--ink-fs-sm); color: var(--ink-muted); }
.ink-spark { display: block; width: 100%; height: 28px; margin-top: var(--ink-2); overflow: visible; }
.ink-spark polyline { fill: none; stroke: var(--ink-muted); stroke-width: 1.5; vector-effect: non-scaling-stroke; }
.ink-spark circle { fill: var(--ink-text); }
.ink-spark--live polyline { stroke: var(--ink-accent); }
@media (max-width: 759px) {
  .ink-stats { grid-template-columns: 1fr 1fr; }
  .ink-stat:nth-child(2n) { border-right: 0; }
  .ink-stat:nth-child(n+3) { border-top: 1px solid var(--ink-line); }
}
/* day strip: one cell per day, data-n 0–4 = activity level; a commit calendar without a chart library */
.ink-days { display: grid; grid-template-columns: repeat(14, minmax(0, 1fr)); align-items: end; height: 30px; gap: 3px; margin: 0; padding: 0; list-style: none; }
.ink-days li { height: 22px; align-self: end; border-radius: var(--ink-r-sm); background: var(--ink-sunk); border: 1px solid var(--ink-line); }
.ink-days li[data-n="1"] { background: var(--ink-heat-1); } .ink-days li[data-n="2"] { background: var(--ink-heat-2); }
.ink-days li[data-n="3"] { background: var(--ink-heat-3); } .ink-days li[data-n="4"] { background: var(--ink-text); }
.ink-days li.is-today { outline: 2px solid var(--ink-text); outline-offset: 1px; }
.ink-days-axis { display: flex; justify-content: space-between; font: 400 var(--ink-fs-xs) var(--ink-font-mono); color: var(--ink-faint); margin-top: var(--ink-1); }
/* meter: labelled horizontal bar, value via the native <meter>/<progress> element (no inline styles) */
.ink-bars { display: grid; grid-template-columns: max-content minmax(0, 1fr) max-content; gap: 6px var(--ink-3); align-items: center; font-size: var(--ink-fs-sm); }
.ink-bars .ink-num { color: var(--ink-muted); text-align: right; }

/* ---- table ---- */
.ink-table-wrap { border: 1px solid var(--ink-line); border-radius: var(--ink-r-md); box-shadow: var(--ink-elev-1); overflow-x: auto; background: var(--ink-surface); }
.ink-table { width: 100%; border-collapse: collapse; font-size: var(--ink-fs-body); }
.ink-table th { text-align: left; font: 500 var(--ink-fs-xs)/1.3 var(--ink-font-ui); letter-spacing: var(--ink-track-caps); text-transform: uppercase; color: var(--ink-muted);
  padding: var(--ink-2) var(--ink-3); border-bottom: 1px solid var(--ink-line); white-space: nowrap; background: var(--ink-raised); }  /* head row = third surface step */
.ink-table th[aria-sort] { cursor: pointer; } .ink-table th[aria-sort="descending"]::after { content: " ↓"; } .ink-table th[aria-sort="ascending"]::after { content: " ↑"; }
.ink-table td { padding: var(--ink-2) var(--ink-3); border-bottom: 1px solid var(--ink-line); vertical-align: top; }
.ink-table tr:last-child td { border-bottom: 0; }
.ink-table tbody tr:hover td, .ink-table tbody tr.is-hover td { background: var(--ink-raised); }
.ink-table tbody tr[aria-selected="true"] td { background: var(--ink-raised); }
.ink-table tbody tr[aria-selected="true"] td:first-child { box-shadow: inset 2px 0 0 var(--ink-text); }
.ink-table .r { text-align: right; } .ink-table .nowrap { white-space: nowrap; }
.ink-table--compact td, .ink-table--compact th { padding: var(--ink-1) var(--ink-3); }
@media (max-width: 759px) { .ink-table--compact td { padding-block: var(--ink-2); } }  /* phone rows read cramped at 4px (panel r16 lens 1); type size unchanged */
.ink-table td.ink-table__empty { padding: var(--ink-6) var(--ink-3); text-align: center; color: var(--ink-muted); }

/* ---- list row + list/detail split ---- */
.ink-list { list-style: none; margin: 0; padding: 0; }
.ink-list__item { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 2px var(--ink-3); padding: var(--ink-3) var(--ink-4);
  border-bottom: 1px solid var(--ink-line); cursor: pointer; text-decoration: none; color: inherit; }
.ink-list__item:hover, .ink-list__item.is-hover { background: var(--ink-raised); }
.ink-list__item[aria-selected="true"], .ink-list__item[aria-current="page"] { background: var(--ink-raised); box-shadow: inset 2px 0 0 var(--ink-text); }
.ink-list__item:focus-visible { outline-offset: -2px; }
.ink-list__item[aria-disabled="true"] { cursor: not-allowed; color: var(--ink-faint); }
.ink-list__title { font-weight: 500; min-width: 0; }
.ink-list__meta { grid-column: 1 / -1; font-size: var(--ink-fs-sm); color: var(--ink-muted); }
.ink-list__lead { display: flex; align-items: center; gap: var(--ink-3); min-width: 0; }
.ink-split { display: grid; grid-template-columns: minmax(280px, 380px) minmax(0, 1fr); border: 1px solid var(--ink-line); border-radius: var(--ink-r-md); box-shadow: var(--ink-elev-1); background: var(--ink-card); min-height: 520px; overflow: hidden; }
.ink-split > .ink-list { border-right: 1px solid var(--ink-line); background: var(--ink-card-sub); }  /* list sits one step below the detail */
.ink-detail { padding: var(--ink-5) var(--ink-6); min-width: 0; }
.ink-detail__title { margin: var(--ink-2) 0 var(--ink-4); }
@media (max-width: 759px) {
  .ink-split { grid-template-columns: minmax(0, 1fr); min-height: 0; }
  .ink-split > .ink-list { border-right: 0; }
  .ink-split > :not(.ink-list) { display: none; }   /* phone: the list is the screen; a row opens its detail as its own screen */
  .ink-split.is-detail > .ink-list { display: none; } .ink-split.is-detail > :not(.ink-list) { display: block; }
  .ink-detail { padding: var(--ink-4); }
}

/* key/value + log */
.ink-kv { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: var(--ink-2) var(--ink-5); margin: 0 0 var(--ink-5); font-size: var(--ink-fs-sm); }
.ink-kv dt { color: var(--ink-muted); }
.ink-kv dd { margin: 0; min-width: 0; }
.ink-log { list-style: none; margin: 0; padding: 0; font-size: var(--ink-fs-sm); }
.ink-log li { display: grid; grid-template-columns: 72px minmax(0, 1fr); gap: var(--ink-3); padding: var(--ink-2) 0; border-bottom: 1px solid var(--ink-line); }
.ink-log time, .ink-log .ink-log__key { font-family: var(--ink-font-mono); color: var(--ink-faint); font-feature-settings: "tnum" 1; }
.ink-log--wide li { grid-template-columns: 72px 80px minmax(0, 1fr); }

/* ---- avatar ---- */
.ink-avatar { display: inline-grid; place-items: center; width: 28px; height: 28px; flex: none; border-radius: var(--ink-r-round);
  background: var(--ink-raised); border: 1px solid var(--ink-line-strong); font: 500 var(--ink-fs-xs) var(--ink-font-mono); color: var(--ink-text); overflow: hidden; }
.ink-avatar img { width: 100%; height: 100%; object-fit: cover; }
.ink-avatar--lg { width: 40px; height: 40px; font-size: var(--ink-fs-sm); }
.ink-avatar--bot { border-style: dashed; color: var(--ink-muted); }
.ink-avatars { display: inline-flex; } .ink-avatars .ink-avatar + .ink-avatar { margin-left: -6px; box-shadow: 0 0 0 2px var(--ink-bg); }

/* ---- progress + skeleton + spinner ---- */
.ink-progress { width: 100%; height: 4px; appearance: none; border: 0; border-radius: var(--ink-r-sm); background: var(--ink-raised); overflow: hidden; display: block; }
.ink-progress::-webkit-progress-bar { background: var(--ink-raised); }
.ink-progress::-webkit-progress-value { background: var(--ink-text); transition: width var(--ink-dur-slow) var(--ink-ease); }
.ink-progress::-moz-progress-bar { background: var(--ink-text); }
.ink-progress--live::-webkit-progress-value { background: var(--ink-accent); }
.ink-progress--live::-moz-progress-bar { background: var(--ink-accent); }
.ink-progress:indeterminate { background: linear-gradient(90deg, var(--ink-raised) 0 35%, var(--ink-muted) 35% 55%, var(--ink-raised) 55%) 0 0 / 300% 100%; animation: ink-slide 1.2s linear infinite; }
.ink-progress:indeterminate::-webkit-progress-bar { background: transparent; }
@keyframes ink-slide { from { background-position: 100% 0; } to { background-position: 0 0; } }
.ink-skel { display: block; height: 12px; border-radius: var(--ink-r-sm); background: var(--ink-skel); margin: 0 0 var(--ink-2); }
.ink-skel--title { height: 22px; width: 40%; margin-bottom: var(--ink-4); }
.ink-skel--line { width: 100%; } .ink-skel--short { width: 60%; } .ink-skel--num { height: 28px; width: 50%; }
.ink-skel--block { height: 120px; }
.ink-spinner { display: inline-block; width: 16px; height: 16px; border-radius: var(--ink-r-round); border: 2px solid var(--ink-line-strong); border-right-color: var(--ink-text); animation: ink-spin 800ms linear infinite; vertical-align: -3px; }

/* ---- alert (inline) ---- */
.ink-alert { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: var(--ink-3); align-items: start; padding: var(--ink-3) var(--ink-4);
  background: var(--ink-surface); border: 1px solid var(--ink-line); border-left-width: 3px; border-radius: var(--ink-r-sm); font-size: var(--ink-fs-sm); }
.ink-alert--ok { border-left-color: var(--ink-ok); } .ink-alert--ok > .ink-icon { color: var(--ink-ok); }
.ink-alert--hold { border-left-color: var(--ink-hold); } .ink-alert--hold > .ink-icon { color: var(--ink-hold); }
.ink-alert--fault { border-left-color: var(--ink-fault); } .ink-alert--fault > .ink-icon { color: var(--ink-fault); }
.ink-alert__title { font-weight: 600; display: block; margin-bottom: 2px; }

/* ---- empty / error / loading state block ---- */
.ink-empty { display: grid; justify-items: start; gap: var(--ink-3); padding: var(--ink-7) var(--ink-6); border: 1px dashed var(--ink-line-strong); border-radius: var(--ink-r-md); max-width: 620px; background: var(--ink-panel); }
.ink-empty > .ink-icon { color: var(--ink-muted); }
.ink-empty h2, .ink-empty h3 { margin: 0; }
.ink-empty p { color: var(--ink-muted); margin: 0; max-width: 52ch; }
.ink-empty--fault { border-color: var(--ink-fault-line); border-style: solid; } .ink-empty--fault > .ink-icon { color: var(--ink-fault); }
.ink-empty--flush { border: 0; padding: var(--ink-6) 0; }
.ink-errcode { font: 400 var(--ink-fs-display)/1 var(--ink-font-display); font-variation-settings: "opsz" 72; color: var(--ink-faint); }

/* ---- menu (popover list) ---- */
.ink-menu-wrap { position: relative; display: inline-block; }
.ink-menu { position: absolute; z-index: var(--ink-z-menu); top: calc(100% + 4px); left: 0; min-width: 200px; margin: 0; padding: var(--ink-1); list-style: none;
  background: var(--ink-overlay); border: 1px solid var(--ink-line-strong); border-radius: var(--ink-r-md); box-shadow: var(--ink-elev-2); }
.ink-menu--end { left: auto; right: 0; }
.ink-menu[hidden] { display: none; }
.ink-menu--static { position: static; display: block; }
.ink-menu [role="menuitem"] { display: flex; align-items: center; gap: var(--ink-3); width: 100%; padding: 6px var(--ink-3); font: 400 var(--ink-fs-sm) var(--ink-font-ui);
  color: var(--ink-text); background: none; border: 0; border-radius: var(--ink-r-sm); cursor: pointer; text-align: left; text-decoration: none; }
.ink-menu [role="menuitem"]:hover, .ink-menu [role="menuitem"]:focus-visible, .ink-menu [role="menuitem"].is-hover { background: var(--ink-raised); outline: none; }
.ink-menu [role="menuitem"][aria-disabled="true"] { color: var(--ink-faint); cursor: not-allowed; background: none; }
.ink-menu [role="menuitem"].ink-menu__danger { color: var(--ink-fault); }
.ink-menu kbd { margin-left: auto; font: 400 var(--ink-fs-xs) var(--ink-font-mono); color: var(--ink-faint); }
.ink-menu hr { border: 0; border-top: 1px solid var(--ink-line); margin: var(--ink-1) 0; }

/* ---- tooltip ---- */
.ink-tip { position: relative; display: inline-flex; }
.ink-tip__body { position: absolute; z-index: var(--ink-z-tooltip); bottom: calc(100% + 6px); left: 50%; transform: translateX(-50%); padding: 4px 8px; white-space: nowrap;
  font: 400 var(--ink-fs-xs)/1.4 var(--ink-font-ui); color: var(--ink-text); background: var(--ink-overlay); border: 1px solid var(--ink-line-strong); border-radius: var(--ink-r-sm);
  opacity: 0; pointer-events: none; transition: opacity var(--ink-dur-fast) var(--ink-ease) var(--ink-delay-tip); }
.ink-tip:hover .ink-tip__body, .ink-tip:focus-within .ink-tip__body, .ink-tip.is-open .ink-tip__body { opacity: 1; }

/* ---- modal (native <dialog>) + sheet ---- */
.ink-modal { width: min(520px, calc(100vw - 32px)); padding: 0; color: var(--ink-text); background: var(--ink-overlay); border: 1px solid var(--ink-line-strong);
  border-radius: var(--ink-r-md); box-shadow: var(--ink-elev-2); }
.ink-modal::backdrop { background: var(--ink-scrim); }
.ink-modal__head { display: flex; align-items: center; justify-content: space-between; gap: var(--ink-3); padding: var(--ink-4) var(--ink-5); border-bottom: 1px solid var(--ink-line); }
.ink-modal__body { padding: var(--ink-5); font-size: var(--ink-fs-sm); }
.ink-modal__foot { display: flex; justify-content: flex-end; gap: var(--ink-2); padding: var(--ink-3) var(--ink-5); border-top: 1px solid var(--ink-line); }
.ink-modal--static { position: static; display: block; margin: 0; width: 100%; max-width: 520px; }
.ink-sheet { position: fixed; inset: 0 0 0 auto; margin: 0 0 0 auto; height: 100%; max-height: none; width: min(440px, 100vw); padding: 0; color: var(--ink-text);
  background: var(--ink-overlay); border: 0; border-left: 1px solid var(--ink-line-strong); }
.ink-sheet::backdrop { background: var(--ink-scrim); }
.ink-sheet--static { position: static; display: block; height: auto; width: 100%; border: 1px solid var(--ink-line-strong); border-radius: var(--ink-r-md); }
@media (max-width: 759px) { .ink-sheet:not(.ink-sheet--static) { inset: auto 0 0 0; width: 100%; height: auto; max-height: 85vh; border-left: 0; border-top: 1px solid var(--ink-line-strong); border-radius: var(--ink-r-md) var(--ink-r-md) 0 0; } }

/* ---- toast ---- */
.ink-toasts { position: fixed; z-index: var(--ink-z-toast); right: var(--ink-4); bottom: var(--ink-4); display: flex; flex-direction: column; gap: var(--ink-2); width: min(380px, calc(100vw - 32px)); }
.ink-toasts--static { position: static; width: 100%; max-width: 380px; }
.ink-toast { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: var(--ink-3); align-items: start; padding: var(--ink-3);
  background: var(--ink-overlay); border: 1px solid var(--ink-line-strong); border-radius: var(--ink-r-md); box-shadow: var(--ink-elev-2); font-size: var(--ink-fs-sm); }
.ink-toast > .ink-icon { margin-top: 2px; }
.ink-toast--ok > .ink-icon { color: var(--ink-ok); } .ink-toast--fault > .ink-icon { color: var(--ink-fault); } .ink-toast--hold > .ink-icon { color: var(--ink-hold); }

/* ---- page-pattern parts ---- */
.ink-shelf { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); background: var(--ink-surface); border: 1px solid var(--ink-line);
  border-radius: var(--ink-r-md); box-shadow: var(--ink-elev-1); }   /* a surfaced strip with ruled cells, like the stats strip */
.ink-shelf > * { padding: var(--ink-4); border-right: 1px solid var(--ink-line); min-width: 0; }
.ink-shelf > *:last-child { border-right: 0; }
.ink-shelf p { margin-top: var(--ink-2); }
@media (max-width: 759px) { .ink-shelf { grid-template-columns: 1fr 1fr; }
  .ink-shelf > * { border-bottom: 1px solid var(--ink-line); } .ink-shelf > *:nth-child(2n) { border-right: 0; } .ink-shelf > *:nth-last-child(-n+2) { border-bottom: 0; } }
.ink-toc { list-style: none; margin: 0; padding: 0; font-size: var(--ink-fs-sm); position: sticky; top: var(--ink-4); }
.ink-toc a { display: block; padding: 4px 0 4px var(--ink-3); color: var(--ink-muted); text-decoration: none; border-left: 1px solid var(--ink-line); }
.ink-toc a:hover { color: var(--ink-text); }
.ink-toc a[aria-current="true"] { color: var(--ink-text); border-left-color: var(--ink-text); }
.ink-settings-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--ink-4); align-items: center; padding: var(--ink-4) 0; border-bottom: 1px solid var(--ink-line); }
.ink-settings-row p { margin: 2px 0 0; font-size: var(--ink-fs-sm); color: var(--ink-muted); }
.ink-form-actions { display: flex; gap: var(--ink-2); justify-content: flex-end; padding-top: var(--ink-4); border-top: 1px solid var(--ink-line); margin-top: var(--ink-5); }
@media (max-width: 759px) { .ink-form-actions { flex-direction: column-reverse; } .ink-form-actions .ink-btn { width: 100%; } }
.ink-footer { max-width: var(--ink-max); margin: 0 auto; padding: var(--ink-5) var(--ink-gutter); border-top: 1px solid var(--ink-line);
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--ink-3); font-size: var(--ink-fs-sm); color: var(--ink-muted); }

@media (prefers-reduced-motion: reduce) {
  .ink *, .ink *::before, .ink *::after { transition: none !important; animation: none !important; }
}

/* ---- tool workspace parts (instrument / practice / producer tools) ---- */
.ink-toolbar { display: flex; align-items: center; gap: var(--ink-2); flex-wrap: wrap; padding: var(--ink-2) 0; border-bottom: 1px solid var(--ink-line); margin-bottom: var(--ink-5); }
.ink-toolbar__spacer { flex: 1; }
.ink-readout { font: 400 clamp(3.5rem, 10vw, 7rem)/1 var(--ink-font-display); font-variation-settings: "opsz" 72; letter-spacing: -0.03em; }
.ink-readout small { font: 400 var(--ink-fs-body) var(--ink-font-mono); color: var(--ink-muted); letter-spacing: var(--ink-track-normal); margin-left: var(--ink-2); }
.ink-scale { display: grid; grid-template-columns: repeat(var(--steps, 11), minmax(0, 1fr)); align-items: end; height: 48px; border-bottom: 1px solid var(--ink-line-strong); }
.ink-scale i { display: block; height: 30%; width: 1px; justify-self: center; background: var(--ink-line-strong); }
.ink-scale i:nth-child(odd) { height: 50%; }
.ink-scale i.is-center { height: 100%; background: var(--ink-muted); }
.ink-scale i.is-at { height: 100%; width: 3px; background: var(--ink-text); }
/* results placard (games) */
.ink-placard { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--ink-2) var(--ink-6); align-items: end; }
.ink-placard__pos { font: 400 clamp(4rem, 12vw, 8rem)/0.85 var(--ink-font-display); font-variation-settings: "opsz" 72; letter-spacing: -0.04em; }
.ink-placard__pos sup { font-size: 0.35em; vertical-align: top; margin-left: 2px; }
@media (max-width: 759px) { .ink-placard { grid-template-columns: minmax(0, 1fr); } }
.ink-table .ink-spark { width: 96px; height: 18px; margin: 0; }

/* ---- panel round 1 fixes ---- */
/* phone: nav gets its own scrolling row, every control clears a 44px target (accessibility lens) */
@media (max-width: 759px) {
  .ink-topbar { flex-wrap: wrap; height: auto; row-gap: 0; padding-top: var(--ink-1); }
  .ink-topbar .ink-nav { order: 3; flex: 1 0 100%; margin: 0 calc(-1 * var(--ink-4)); padding: 0 var(--ink-2); border-top: 1px solid var(--ink-line); }
  /* A2 wrapped .ink-nav in <nav aria-label="Primary">: the flex child is now the <nav>, so the row-break must apply to it too,
     and the theme/status end slot sits beside the brand on row 1 instead of on a row of its own (panel round 21 lens 2). */
  .ink-topbar > nav { order: 3; flex: 1 0 100%; }
  .ink-topbar > nav > .ink-nav { margin: 0 calc(-1 * var(--ink-4)); }
  .ink-topbar__end { order: 2; margin-left: auto; }
}
@media (max-width: 759px), (pointer: coarse) {
  .ink-nav a, .ink-tabs a, .ink-tabs button, .ink-seg button { min-height: var(--ink-target-phone); display: inline-flex; align-items: center; }
  .ink-btn, .ink-input, .ink-select { min-height: var(--ink-target-phone); }
  .ink-iconbtn { width: var(--ink-target-phone); height: var(--ink-target-phone); }
  .ink-list__item { min-height: var(--ink-target-phone); }
  .ink-wordmark { display: inline-flex; align-items: center; min-height: var(--ink-target-phone); }
  .ink-switch::before { width: var(--ink-target-phone); height: var(--ink-target-phone); }
}
@media (min-width: 760px) { .ink-show-phone { display: none !important; } }
/* phone first-viewport budget (density lens, round 2): secondary content steps back */
@media (max-width: 759px) {
  .ink-hide-phone { display: none !important; }
  .ink-show-phone { display: table-row; }
  .ink-stat__delta { display: none; }
}
/* receipt: one claim + commit + re-runnable check — the lab's product object, used as the landing visual */
.ink-receipt { display: grid; gap: var(--ink-3); margin: 0; background: var(--ink-panel); }
.ink-receipt__claim { font: 400 var(--ink-fs-h2)/1.3 var(--ink-font-display); margin: 0; }
.ink-receipt .ink-kv { margin: 0; }
.ink-receipt pre { margin: 0; }
/* one section rhythm (spacing lens, round 6): nothing inside a ledger body adds its own top margin before the first item */
.ink-ledger__body > :first-child, .ink-ledger__body > * > :first-child, .ink-prose > :first-child { margin-top: 0; }
/* theme-matched media: show the image made for the active theme */
.ink-only-dark { display: none; }
:root[data-theme="dark"] .ink-only-dark, :root:not([data-theme="light"]) .ink-game .ink-only-dark { display: block; }
:root[data-theme="dark"] .ink-only-light, :root:not([data-theme="light"]) .ink-game .ink-only-light { display: none; }
.ink-shot { margin: 0; border: 1px solid var(--ink-line); border-radius: var(--ink-r-md); overflow: hidden; box-shadow: var(--ink-elev-1); background: var(--ink-surface); }
.ink-shot img { display: block; width: 100%; height: auto; }
.ink-shot figcaption { padding: var(--ink-2) var(--ink-3); border-top: 1px solid var(--ink-line); font-size: var(--ink-fs-sm); color: var(--ink-muted); }

/* day strip: volume is encoded by height AND shade, never colour alone (accessibility lens, round 7) */
.ink-days li[data-n="0"] { height: 4px; } .ink-days li[data-n="1"] { height: 10px; } .ink-days li[data-n="2"] { height: 16px; }
.ink-days li[data-n="3"] { height: 22px; } .ink-days li[data-n="4"] { height: 30px; }
/* phone: tab and nav hit areas are visible, not just measured */
@media (max-width: 759px) {
  .ink-nav a[aria-current="page"] { background: var(--ink-raised); box-shadow: inset 0 -2px 0 var(--ink-text); }
  .ink-tabs a, .ink-tabs button { padding-inline: var(--ink-3); border-radius: var(--ink-r-sm); }
  .ink-tabs [aria-current="true"], .ink-tabs [aria-selected="true"] { background: var(--ink-raised); }
}

/* ===== DS-S kit gaps (seat reports burn3-*-2026-11-02) ===== */
.ink-theme-scope { background: var(--ink-bg); color: var(--ink-text); }
/* data chip / legend dot: a series or faction, coloured by --ink-data-N, always with a text label (never colour alone) */
.ink-datum { display: inline-flex; align-items: center; gap: var(--ink-2); font-size: var(--ink-fs-sm); }
.ink-datum::before { content: ""; width: 10px; height: 10px; border-radius: var(--ink-r-round); background: var(--c, var(--ink-data-1)); flex: none; }
.ink-datum--1 { --c: var(--ink-data-1); } .ink-datum--2 { --c: var(--ink-data-2); } .ink-datum--3 { --c: var(--ink-data-3); } .ink-datum--4 { --c: var(--ink-data-4); }
/* lamp: a status light with an OFF tier; the label carries the meaning, the lamp repeats it */
.ink-lamp { display: inline-flex; align-items: center; gap: var(--ink-2); font: 500 var(--ink-fs-xs)/1 var(--ink-font-mono); letter-spacing: .04em; text-transform: uppercase; color: var(--ink-muted); }
.ink-lamp::before { content: ""; width: 10px; height: 10px; border-radius: var(--ink-r-round); border: 2px solid var(--ink-lamp-off); background: transparent; }
.ink-lamp--on::before { background: var(--ink-text); border-color: var(--ink-text); }
.ink-lamp--ok::before { background: var(--ink-ok); border-color: var(--ink-ok); } .ink-lamp--hold::before { background: var(--ink-hold); border-color: var(--ink-hold); }
.ink-lamp--fault::before { background: var(--ink-fault); border-color: var(--ink-fault); }
/* meter / gauge: a value on a scale with a target band (tuner, budget, progress-to-target) */
.ink-meter { display: grid; gap: var(--ink-1); }
.ink-meter__track { position: relative; height: 8px; background: var(--ink-sunk); border: 1px solid var(--ink-line); border-radius: var(--ink-r-sm); }
.ink-meter__band { position: absolute; top: -1px; bottom: -1px; left: var(--lo, 45%); right: calc(100% - var(--hi, 55%)); background: var(--ink-raised); border-inline: 1px solid var(--ink-line-strong); }
.ink-meter__needle { position: absolute; top: -6px; bottom: -6px; left: var(--v, 50%); width: 2px; margin-left: -1px; background: var(--ink-text); }
.ink-meter__scale { display: flex; justify-content: space-between; font: 400 var(--ink-fs-xs) var(--ink-font-mono); color: var(--ink-faint); }
/* step dots: position in a short sequence (setlist, tutorial, wizard) */
.ink-steps { display: inline-flex; gap: var(--ink-2); margin: 0; padding: 0; list-style: none; }
.ink-steps li { width: 8px; height: 8px; border-radius: var(--ink-r-round); border: 1px solid var(--ink-line-strong); }
.ink-steps li[aria-current="step"] { background: var(--ink-text); border-color: var(--ink-text); width: 20px; border-radius: var(--ink-r-sm); }
.ink-steps li.is-done { background: var(--ink-line-strong); }
/* transport bar: play / tempo / key, 44px floor on every control */
.ink-transport { display: flex; align-items: center; gap: var(--ink-3); padding: var(--ink-2) var(--ink-3); background: var(--ink-surface); border: 1px solid var(--ink-line); border-radius: var(--ink-r-md); box-shadow: var(--ink-elev-1); flex-wrap: wrap; }
.ink-transport .ink-btn, .ink-transport .ink-iconbtn { min-height: 44px; min-width: 44px; }
.ink-stepper { display: inline-flex; align-items: center; border: 1px solid var(--ink-line-strong); border-radius: var(--ink-r-sm); }
.ink-stepper button { min-width: 44px; min-height: 44px; background: none; border: 0; color: var(--ink-text); font: 500 var(--ink-fs-body) var(--ink-font-ui); cursor: pointer; }
.ink-stepper output { min-width: 64px; text-align: center; font: 500 var(--ink-fs-body) var(--ink-font-mono); border-inline: 1px solid var(--ink-line); padding: 0 var(--ink-2); }
/* timeline / event strip: compact chronological marks with times */
.ink-timeline { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(96px, 1fr); gap: 0; margin: 0; padding: 0; list-style: none; overflow-x: auto; border-top: 1px solid var(--ink-line-strong); }
.ink-timeline li { position: relative; padding: var(--ink-3) var(--ink-2) 0 0; font-size: var(--ink-fs-sm); }
.ink-timeline li::before { content: ""; position: absolute; top: -5px; left: 0; width: 9px; height: 9px; border-radius: var(--ink-r-round); background: var(--ink-bg); border: 2px solid var(--ink-line-strong); }
.ink-timeline li.is-key::before { background: var(--ink-text); border-color: var(--ink-text); }
.ink-timeline time { display: block; font: 400 var(--ink-fs-xs) var(--ink-font-mono); color: var(--ink-faint); }
/* peek sheet: a bottom sheet with a grab bar and a one-line summary for canvas-first phone pages */
.ink-peek { background: var(--ink-overlay); border: 1px solid var(--ink-line-strong); border-bottom: 0; border-radius: var(--ink-r-md) var(--ink-r-md) 0 0; box-shadow: var(--ink-elev-2); }
.ink-peek > summary { list-style: none; display: grid; justify-items: center; gap: var(--ink-2); padding: var(--ink-2) var(--ink-4) var(--ink-3); min-height: 44px; cursor: pointer; }
.ink-peek > summary::-webkit-details-marker { display: none; }
.ink-peek > summary::before { content: ""; width: 36px; height: 4px; border-radius: var(--ink-r-sm); background: var(--ink-line-strong); }
.ink-peek__summary { display: flex; justify-content: space-between; width: 100%; gap: var(--ink-3); font-size: var(--ink-fs-sm); }
.ink-peek__body { padding: 0 var(--ink-4) var(--ink-4); border-top: 1px solid var(--ink-line); }
/* disclosure row: a quiet expandable row for secondary detail */
.ink-disclose { border-bottom: 1px solid var(--ink-line); }
.ink-disclose > summary { display: flex; align-items: center; justify-content: space-between; min-height: 44px; cursor: pointer; list-style: none; color: var(--ink-muted); font-size: var(--ink-fs-sm); }
.ink-disclose > summary::-webkit-details-marker { display: none; }
.ink-disclose > summary::after { content: "+"; font-family: var(--ink-font-mono); }
.ink-disclose[open] > summary::after { content: "−"; }
.ink-disclose[open] > summary { color: var(--ink-text); }
.ink-disclose > :not(summary) { padding-bottom: var(--ink-3); }
/* media card: art/canvas slot + title + status + mono meta (3D thumbnails, songs, tracks) */
.ink-media { display: grid; grid-template-rows: auto 1fr; background: var(--ink-card); border: 1px solid var(--ink-line); border-radius: var(--ink-r-md); overflow: hidden; box-shadow: var(--ink-elev-1); min-width: 0; }
.ink-media__art { aspect-ratio: 4 / 3; background: var(--ink-sunk); border-bottom: 1px solid var(--ink-line); display: grid; place-items: center; color: var(--ink-faint); overflow: hidden; }
.ink-media__art > img, .ink-media__art > canvas { width: 100%; height: 100%; object-fit: cover; }
.ink-media__body { display: grid; gap: var(--ink-1); padding: var(--ink-3); }
.ink-media__meta { font: 400 var(--ink-fs-xs) var(--ink-font-mono); color: var(--ink-faint); }

.ink-card--raised { background: var(--ink-overlay); box-shadow: var(--ink-elev-2); }   /* the one card that needs a reader first (e.g. Waiting on Steve) — one step above the default raised card */
@media (max-width: 759px) { .ink-lede { font-size: var(--ink-fs-prose); } }
/* phone: tabs never clip a label; they wrap to a second row (panel round 9) */
@media (max-width: 759px) { .ink-tabs { flex-wrap: wrap; column-gap: var(--ink-2); overflow: visible; } }

/* List preview (job B2): on phones a long list shows its first rows and folds the rest behind a disclosure;
   from 760px up the fold is always open and its toggle is hidden, so the desktop list-detail is unchanged. */
.ink-list__more { list-style: none; padding: 0; }
.ink-list__more > .ink-list__disclose > summary { min-height: 44px; display: flex; align-items: center; gap: var(--ink-2); padding: 0 var(--ink-4); }
.ink-list__more .ink-list { border: 0; }
@media (min-width: 760px) {
  .ink-list__disclose > summary { display: none; }
  .ink-list__disclose:not([open]) > :not(summary) { display: block; }
  .ink-list__disclose::details-content { content-visibility: visible; height: auto; overflow: visible; }
}

/* A long state label inside a value cell wraps instead of being clipped (fit check, R17). */
.ink dd .ink-state, .ink td .ink-state--wrap { white-space: normal; align-items: baseline; }
.ink dd .ink-state::before { flex: none; }

/* Skip link (job A2, docs/qa/a11y-2026-11-02.md fix 3): the first focusable element on every ink
   page, so a keyboard user can jump straight to #main instead of tabbing through the nav every load.
   Hidden the .ink-sr way until keyboard focus reaches it, then pinned top-left on --ink-overlay. */
.ink-skip {
  position: absolute; top: var(--ink-2); left: var(--ink-2); z-index: var(--ink-z-toast);
  width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
  background: var(--ink-overlay); color: var(--ink-text); border-radius: var(--ink-r-sm);
  text-decoration: none; font-size: var(--ink-fs-sm);
}
.ink-skip:focus-visible {
  width: auto; height: auto; overflow: visible; clip: auto; white-space: normal;
  display: inline-flex; align-items: center; padding: var(--ink-2) var(--ink-4);
}
@media (max-width: 759px), (pointer: coarse) { .ink-skip:focus-visible { min-height: var(--ink-target-phone); } }
/* Focus inside scroll strips: the phone nav and tabs scroll horizontally, so their overflow clipped the 2px ring drawn 2px OUTSIDE
   the link (panel round 25 lenses 6 and 10: no visible ring on the phone focus captures). Draw it inside the box there instead. */
.ink-nav a:focus-visible, .ink-nav a.is-focus, .ink-tabs a:focus-visible, .ink-tabs button:focus-visible, .ink-tabs .is-focus { outline-offset: -2px; }

/* A-Ink game skin — load after components.css, on games only: <body class="ink ink-game">.
   It is a skin layer over the shared foundations: the same tokens and components with bigger touch targets, a display
   type voice for menus, and a HUD frame. In-world art (the canvas, sprites, 3D) is out of the kit's scope;
   the HUD frame only gives the four corners and the centre a consistent chrome around it. */

.ink-game { --ink-control-h: 48px; --ink-control-h-sm: 36px; }
.ink-game .ink-btn { font-size: var(--ink-fs-body); padding: 0 var(--ink-5); letter-spacing: var(--ink-track-wide); }
/* touch: the game's own 36px small-control size is below the 44px floor; coarse pointers win over the game scale */
@media (pointer: coarse) { .ink-game { --ink-control-h: 48px; --ink-control-h-sm: 44px; } }

/* ---- game menu: a title page, not a web page ---- */
.ink-gamemenu { min-height: 100vh; display: grid; grid-template-columns: minmax(0, 1fr) minmax(300px, 400px); }
.ink-gamemenu__art { position: relative; background: var(--ink-surface); border-right: 1px solid var(--ink-line); overflow: hidden; display: grid; place-items: end start; padding: var(--ink-6); }
.ink-gamemenu__art canvas, .ink-gamemenu__art img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.ink-gamemenu__title { position: relative; font: 400 clamp(3rem, 8vw, 6.5rem)/0.95 var(--ink-font-display); letter-spacing: -0.03em; font-variation-settings: "opsz" 72; margin: 0; }
.ink-gamemenu__title em { font-style: italic; }
.ink-gamemenu__panel { display: flex; flex-direction: column; justify-content: center; gap: var(--ink-5); padding: var(--ink-6); }
.ink-gamemenu__list { display: flex; flex-direction: column; gap: var(--ink-2); margin: 0; padding: 0; list-style: none; }
.ink-gamemenu__list .ink-btn { width: 100%; justify-content: space-between; }
.ink-gamemenu__list .ink-btn kbd { color: inherit; }
@media (max-width: 759px) {
  .ink-gamemenu { grid-template-columns: minmax(0, 1fr); grid-template-rows: 42vh auto; }
  .ink-gamemenu__art { border-right: 0; border-bottom: 1px solid var(--ink-line); padding: var(--ink-5); }
  .ink-gamemenu__panel { padding: var(--ink-5) var(--ink-4); justify-content: flex-start; }
}

/* ---- lobby: seats as a numbered roster ---- */
.ink-seats { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 var(--ink-5); counter-reset: seat; }
.ink-seats li { counter-increment: seat; display: grid; grid-template-columns: 32px auto minmax(0, 1fr) auto; gap: var(--ink-3); align-items: center;
  padding: var(--ink-2) 0; border-bottom: 1px solid var(--ink-line); font-size: var(--ink-fs-sm); min-height: 48px; }
.ink-seats li::before { content: counter(seat, decimal-leading-zero); font: 400 var(--ink-fs-xs) var(--ink-font-mono); color: var(--ink-faint); }
.ink-seats li.is-empty { color: var(--ink-faint); }
.ink-seats li.is-you { box-shadow: inset 2px 0 0 var(--ink-accent); padding-left: var(--ink-2); }
@media (max-width: 759px) { .ink-seats { grid-template-columns: minmax(0, 1fr); } }
.ink-code-big { font: 500 2rem/1 var(--ink-font-mono); letter-spacing: .12em; }

/* ---- HUD frame: chrome around the canvas, never over the action ---- */
.ink-hud { position: relative; min-height: 100vh; background: var(--ink-bg); overflow: hidden; }
.ink-hud__stage { position: absolute; inset: 0; display: grid; place-items: center; background: var(--ink-surface); }
.ink-hud__stage:empty, .ink-hud__stage > div:empty { background: repeating-linear-gradient(135deg, var(--ink-surface) 0 14px, var(--ink-raised) 14px 28px); }
.ink-hud__stage canvas, .ink-hud__stage img { width: 100%; height: 100%; object-fit: cover; }
/* HUD chrome sits over the game canvas, so it stays dark ink in both themes: this scopes a fixed dark
   token set on the slot (QA fix 3, light-theme-2026-11-02), built from the kit's own dark-theme values
   (tokens.css [data-theme="dark"]) rather than literal hex on the properties below. */
.ink-hud__slot { --ink-bg: #13110E; --ink-text: #F0E8DB; --ink-muted: #B3A898; --ink-faint: #A69A89; --ink-accent: #F0784A; --ink-line: #433C33;
  --ink-raised: #23211E; color-scheme: dark; position: absolute; z-index: var(--ink-z-sticky); display: flex; flex-direction: column; gap: var(--ink-1);
  padding: var(--ink-2) var(--ink-3); background: var(--ink-bg); border: 1px solid var(--ink-line); border-radius: var(--ink-r-sm);
  font: 500 var(--ink-fs-sm)/1.3 var(--ink-font-mono); font-feature-settings: "tnum" 1; color: var(--ink-text); }
.ink-hud__slot--tl { top: var(--ink-4); left: var(--ink-4); }
.ink-hud__slot--tr { top: var(--ink-4); right: var(--ink-4); text-align: right; align-items: flex-end; }
.ink-hud__slot--bl { bottom: var(--ink-4); left: var(--ink-4); }
.ink-hud__slot--br { bottom: var(--ink-4); right: var(--ink-4); text-align: right; align-items: flex-end; }
.ink-hud__slot--tc { top: var(--ink-4); left: 50%; transform: translateX(-50%); align-items: center; }
.ink-hud__big { font: 500 1.75rem/1 var(--ink-font-mono); letter-spacing: var(--ink-track-tight); }
.ink-hud__label { font: 500 var(--ink-fs-xs)/1 var(--ink-font-ui); letter-spacing: .08em; text-transform: uppercase; color: var(--ink-muted); }
.ink-hud__slot .ink-progress { width: 140px; }
.ink-hud__slot--live .ink-hud__big { color: var(--ink-accent); }
@media (max-width: 759px) {
  .ink-hud__slot { padding: 6px var(--ink-2); font-size: var(--ink-fs-xs); }
  .ink-hud__big { font-size: 1.25rem; }
  .ink-hud__slot .ink-progress { width: 96px; }
}

/* title scene: line art drawn in ink tokens, so it follows the theme (panel round 1: the art panel read as empty) */
.ink-gamemenu__art { place-items: stretch; grid-template-rows: minmax(0, 1fr) auto; gap: var(--ink-5); }
.ink-gamemenu__scene { position: relative; width: 100%; height: 100%; max-height: 62vh; align-self: center; }
.ink-gamemenu__scene .rail { fill: var(--ink-raised); stroke: var(--ink-line-strong); stroke-width: 1.5; }
.ink-gamemenu__scene .felt { fill: var(--ink-bg); stroke: var(--ink-line); }
.ink-gamemenu__scene .cards rect { fill: var(--ink-surface); stroke: var(--ink-line-strong); }
.ink-gamemenu__scene .pot { font: 400 15px var(--ink-font-mono); fill: var(--ink-muted); text-anchor: middle; }
.ink-gamemenu__scene .seat circle { fill: var(--ink-sunk); stroke: var(--ink-line); stroke-dasharray: 3 3; }
.ink-gamemenu__scene .seat.is-taken circle { fill: var(--ink-overlay); stroke: var(--ink-line-strong); stroke-dasharray: none; }
.ink-gamemenu__scene .seat text { font: 500 13px var(--ink-font-mono); fill: var(--ink-faint); text-anchor: middle; }
.ink-gamemenu__scene .seat.is-taken text { fill: var(--ink-text); }
.ink-gamemenu__caption { position: relative; display: grid; gap: var(--ink-2); }

/* ===== DS-S game kit gaps (poker, racer, gecko-fps, constellation) ===== */
/* playing card: face, back, empty slot. Suit colour follows the two-colour deck in ink, not the state hues */
.ink-pcard { display: inline-grid; grid-template-rows: auto 1fr; width: 48px; height: 68px; padding: 4px 6px; border-radius: var(--ink-r-sm);
  background: #FBF8F2; color: #1D1B18; border: 1px solid #A39B8E; font: 600 18px/1 var(--ink-font-display); box-shadow: var(--ink-elev-1); }
.ink-pcard small { font: 500 12px/1 var(--ink-font-ui); }
.ink-pcard--red { color: #A8382A; }
.ink-pcard--back { background: var(--ink-raised); border-color: var(--ink-line-strong);
  background-image: repeating-linear-gradient(45deg, transparent 0 5px, var(--ink-line) 5px 6px); color: transparent; }
.ink-pcard--empty { background: transparent; border: 1px dashed var(--ink-line-strong); box-shadow: none; }
.ink-pcard--lg { width: 72px; height: 102px; font-size: 26px; }
/* pills: pot, dealer button, chip stack, turn clock */
.ink-pill { display: inline-flex; align-items: center; gap: var(--ink-1); padding: 2px var(--ink-2); border-radius: var(--ink-r-sm);
  font: 500 var(--ink-fs-xs)/1.5 var(--ink-font-mono); color: var(--ink-text); background: var(--ink-raised); border: 1px solid var(--ink-line-strong); }
.ink-pill--dealer { width: 24px; height: 24px; padding: 0; justify-content: center; border-radius: var(--ink-r-round); background: var(--ink-text); color: var(--ink-bg); border-color: var(--ink-text); }
.ink-pill--pot { font-size: var(--ink-fs-sm); }
.ink-clock { display: inline-grid; grid-template-columns: auto 64px; align-items: center; gap: var(--ink-2); font: 500 var(--ink-fs-sm) var(--ink-font-mono); }
.ink-clock__bar { height: 4px; background: var(--ink-sunk); border-radius: var(--ink-r-sm); overflow: hidden; }
.ink-clock__bar i { display: block; height: 100%; width: var(--left, 60%); background: var(--ink-text); }
.ink-clock--low .ink-clock__bar i { background: var(--ink-hold); }
/* bet slider: labelled min / value / all-in */
.ink-bet { display: grid; gap: var(--ink-2); }
.ink-bet__ends { display: flex; justify-content: space-between; font: 400 var(--ink-fs-xs) var(--ink-font-mono); color: var(--ink-faint); }
.ink-bet output { font: 500 var(--ink-fs-h2) var(--ink-font-mono); }
/* seat ring (SVG): seats around a table; taken seats show initials, empty seats are dashed */
.ink-seatring { width: 100%; height: auto; }
.ink-seatring .rail { fill: var(--ink-raised); stroke: var(--ink-line-strong); stroke-width: 1.5; }
.ink-seatring .felt { fill: var(--ink-bg); stroke: var(--ink-line); }
.ink-seatring .seat circle { fill: var(--ink-sunk); stroke: var(--ink-line); stroke-dasharray: 3 3; }
.ink-seatring .seat.is-taken circle { fill: var(--ink-overlay); stroke: var(--ink-line-strong); stroke-dasharray: none; }
.ink-seatring .seat.is-turn circle { stroke: var(--ink-text); stroke-width: 2; }
.ink-seatring text { font: 500 13px var(--ink-font-mono); fill: var(--ink-text); text-anchor: middle; }
.ink-seatring .seat:not(.is-taken) text { fill: var(--ink-faint); }
/* kill feed / event toasts: a short stack in a HUD corner, newest on top, mono. Theme-aware (QA fix 3):
   a light host gets a light chip, a dark one keeps today's dark chip — color-mix keeps the same alpha look
   literal rgba() gave, just on top of the theme's own --ink-bg/--ink-text instead of their dark-theme hex. */
.ink-feed { display: grid; gap: 2px; margin: 0; padding: 0; list-style: none; justify-items: end; }
.ink-feed li { padding: 2px var(--ink-2); background: color-mix(in srgb, var(--ink-bg) 82%, transparent); color: var(--ink-text); border-radius: var(--ink-r-sm); font: 400 var(--ink-fs-xs)/1.6 var(--ink-font-mono); }
.ink-feed li b { font-weight: 600; }
/* touch controls: round action buttons and a thumb-stick base (game HUD, phone). Theme-aware (QA fix 3),
   same reasoning as .ink-feed above. */
.ink-actionbtn { width: 64px; height: 64px; border-radius: var(--ink-r-round); display: inline-grid; place-items: center;
  background: color-mix(in srgb, var(--ink-bg) 70%, transparent); color: var(--ink-text); border: 2px solid var(--ink-line-strong); font: 600 var(--ink-fs-xs) var(--ink-font-mono); text-transform: uppercase; }
.ink-actionbtn:active, .ink-actionbtn.is-active { background: var(--ink-text); color: var(--ink-bg); border-color: var(--ink-text); }
.ink-stick { width: 112px; height: 112px; border-radius: var(--ink-r-round); border: 2px dashed var(--ink-line-strong); display: grid; place-items: center; }
.ink-stick::after { content: ""; width: 48px; height: 48px; border-radius: var(--ink-r-round); background: color-mix(in srgb, var(--ink-text) 85%, transparent); }
/* game menu over a live canvas: the scene stays visible, the menu sits on a solid veil panel (no blur, R10) */
.ink-gamemenu--veil { position: relative; grid-template-columns: minmax(0, 1fr); place-items: center end; padding: var(--ink-6); }
.ink-gamemenu--veil > canvas, .ink-gamemenu--veil > .ink-gamemenu__live { position: absolute; inset: 0; width: 100%; height: 100%; }
.ink-gamemenu--veil .ink-gamemenu__panel { position: relative; width: min(400px, 100%); background: var(--ink-overlay); border: 1px solid var(--ink-line-strong); border-radius: var(--ink-r-md); box-shadow: var(--ink-elev-2); }
/* teach overlay: a one-time touch tutorial card pointing at a control */
.ink-teach { position: relative; max-width: 280px; padding: var(--ink-3) var(--ink-4); background: var(--ink-text); color: var(--ink-bg); border-radius: var(--ink-r-md); font-size: var(--ink-fs-sm); }
.ink-teach::after { content: ""; position: absolute; bottom: -6px; left: 24px; width: 12px; height: 12px; background: inherit; transform: rotate(45deg); }
.ink-teach .ink-btn { color: var(--ink-bg); border-color: var(--ink-bg); margin-top: var(--ink-2); }
/* game wordmark slot: a game's own title art may replace the serif display (R9 exemption is scoped to this slot) */
.ink-wordmark-slot { display: block; max-width: 520px; }
.ink-wordmark-slot > img, .ink-wordmark-slot > svg { display: block; width: 100%; height: auto; }
/* light theme: card slots must clear 3:1 against the table (WCAG 1.4.11; panel round 9) */
.ink-gamemenu__scene .cards rect { stroke: var(--ink-muted); stroke-width: 1.5; }

/* A-Ink controls kit — plain CSS, needs tokens.css + components.css first. Class prefix: ink-.
   New controls only (components.css/game.css already cover .ink-stepper, .ink-transport, .ink-disclose —
   reuse those, don't redefine them here). Same state-hook convention as components.css: every interactive
   control styles its real pseudo-class/attribute AND a mirror class, so a static page can show a state at rest:
     :hover = .is-hover   ·   :focus-visible = .is-focus   ·   :active = .is-active   ·   :disabled = .is-disabled
   (DS-S kit gaps, job K2 — game-seat pilot reports burn3-*-2026-11-02: 3DDEPT 3/9, GUITAR 1/2/3/4/7,
   POKER 2/3/4/8/11, GECKO 7/13, RACER 1/chips.) */

/* ---- rating picker: equal-width radio cells, native radio semantics (3DDEPT 3) ---- */
.ink-rating { display: flex; margin: 0; padding: 0; border: 1px solid var(--ink-line-strong); border-radius: var(--ink-r-sm); overflow: hidden; }
.ink-rating label { position: relative; flex: 1; display: flex; align-items: center; justify-content: center; min-height: 44px; min-width: 44px;
  font: 500 var(--ink-fs-sm) var(--ink-font-ui); color: var(--ink-muted); cursor: pointer; border-right: 1px solid var(--ink-line);
  transition: background var(--ink-dur) var(--ink-ease), color var(--ink-dur) var(--ink-ease); }
.ink-rating label:last-child { border-right: 0; }
.ink-rating input { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
.ink-rating label:hover, .ink-rating label.is-hover { background: var(--ink-raised); color: var(--ink-text); }
.ink-rating label:has(input:focus-visible), .ink-rating label.is-focus { outline: 2px solid var(--ink-text); outline-offset: -2px; z-index: 1; }
.ink-rating label:active, .ink-rating label.is-active { background: var(--ink-overlay); }
.ink-rating label:has(input:checked) { background: var(--ink-text); color: var(--ink-bg); }
.ink-rating label:has(input:disabled) { color: var(--ink-faint); cursor: not-allowed; }

/* ---- toggle button: .ink-btn pressed state (GECKO 7, GUITAR 3) ---- */
.ink-btn[aria-pressed="true"] { background: var(--ink-accent-wash); border-color: var(--ink-accent); color: var(--ink-text); }
.ink-btn[aria-pressed="true"]:hover, .ink-btn[aria-pressed="true"].is-hover { background: var(--ink-accent-wash); border-color: var(--ink-accent-hover); }

/* ---- chip: a toggle chip, compact on desktop, 44px floor on a coarse phone pointer (GUITAR 7, RACER chips) ---- */
.ink-chip { display: inline-flex; align-items: center; gap: 6px; min-height: 28px; padding: 0 var(--ink-3);
  font: 500 var(--ink-fs-xs) var(--ink-font-ui); color: var(--ink-muted); background: var(--ink-surface);
  border: 1px solid var(--ink-line-strong); border-radius: var(--ink-r-sm); cursor: pointer;
  transition: background var(--ink-dur) var(--ink-ease), border-color var(--ink-dur) var(--ink-ease), color var(--ink-dur) var(--ink-ease); }
.ink-chip:hover, .ink-chip.is-hover { color: var(--ink-text); border-color: var(--ink-muted); }
.ink-chip:focus-visible, .ink-chip.is-focus { outline: 2px solid var(--ink-text); outline-offset: 2px; }
.ink-chip:active, .ink-chip.is-active { background: var(--ink-overlay); }
.ink-chip[aria-pressed="true"] { color: var(--ink-text); background: var(--ink-raised); border-color: var(--ink-text); }
.ink-chip:disabled, .ink-chip.is-disabled { color: var(--ink-faint); cursor: not-allowed; border-style: dashed; background: transparent; }
@media (max-width: 759px) and (pointer: coarse) { .ink-chip { min-height: 44px; padding: 0 var(--ink-4); } }

/* ---- touch slider: .ink-slider modifier — 44px box, 24px thumb, filled track, min/now/max labels (GUITAR 4, POKER 3) ---- */
.ink-slider-field { display: grid; gap: var(--ink-2); }
.ink-slider--touch { height: 44px; }
.ink-slider--touch::-webkit-slider-runnable-track { height: 6px; border-radius: var(--ink-r-sm);
  background: linear-gradient(to right, var(--ink-text) 0 var(--p, 50%), var(--ink-line-strong) var(--p, 50%) 100%); }
.ink-slider--touch::-moz-range-track { height: 6px; border-radius: var(--ink-r-sm); background: var(--ink-line-strong); }
.ink-slider--touch::-moz-range-progress { height: 6px; border-radius: var(--ink-r-sm); background: var(--ink-text); }
.ink-slider--touch::-webkit-slider-thumb { width: 24px; height: 24px; margin-top: -9px; border-radius: var(--ink-r-round); border: 2px solid var(--ink-bg); background: var(--ink-text); }
.ink-slider--touch::-moz-range-thumb { width: 24px; height: 24px; border-radius: var(--ink-r-round); border: 2px solid var(--ink-bg); background: var(--ink-text); }
.ink-slider-field__scale { display: flex; justify-content: space-between; font: 400 var(--ink-fs-xs) var(--ink-font-mono); color: var(--ink-faint); }
.ink-slider-field__scale output { color: var(--ink-text); font-weight: 500; }

/* ---- tall link: an inline text link whose hit area clears 44px without inflating the line box (GECKO 13, RACER 1) ---- */
.ink-link--tall { position: relative; display: inline-block; color: var(--ink-text); text-decoration: underline;
  text-decoration-color: var(--ink-line-strong); text-underline-offset: 3px; }
.ink-link--tall::after { content: ""; position: absolute; left: -4px; right: -4px; top: 50%; height: 44px; transform: translateY(-50%); }
.ink-link--tall:hover, .ink-link--tall.is-hover { text-decoration-color: var(--ink-text); }
.ink-link--tall:focus-visible, .ink-link--tall.is-focus { outline: 2px solid var(--ink-text); outline-offset: 3px; }

/* ---- turn timer: a countdown pill; low uses --ink-fault, never a pulse animation (POKER 2) ---- */
.ink-timer { display: inline-flex; align-items: center; gap: var(--ink-2); padding: 2px var(--ink-3); border-radius: var(--ink-r-sm);
  font: 500 var(--ink-fs-sm)/1.4 var(--ink-font-mono); font-feature-settings: "tnum" 1; color: var(--ink-text);
  background: var(--ink-raised); border: 1px solid var(--ink-line-strong); }
.ink-timer__bar { width: 48px; height: 4px; border-radius: var(--ink-r-sm); background: var(--ink-sunk); overflow: hidden; }
.ink-timer__bar i { display: block; height: 100%; width: var(--left, 60%); background: var(--ink-text); }
.ink-timer--low { color: var(--ink-fault); border-color: var(--ink-fault-line); }
.ink-timer--low .ink-timer__bar i { background: var(--ink-fault); }

/* ---- flash: a short inline confirmation, role=status (3DDEPT 9) ---- */
.ink-flash { display: inline-flex; align-items: center; gap: 6px; padding: 2px var(--ink-2); border-radius: var(--ink-r-sm);
  font: 500 var(--ink-fs-xs) var(--ink-font-ui); color: var(--ink-ok); background: var(--ink-raised); }
.ink-flash > .ink-icon { color: var(--ink-ok); }

/* ---- disclosure chip: a compact <details> summary chip, distinct from the full-width .ink-disclose row (POKER 8) ---- */
.ink-disclose-chip { display: inline-block; }
.ink-disclose-chip > summary { display: inline-flex; align-items: center; gap: 4px; min-height: 28px; padding: 0 var(--ink-3);
  font: 500 var(--ink-fs-xs) var(--ink-font-ui); color: var(--ink-muted); background: var(--ink-surface);
  border: 1px solid var(--ink-line-strong); border-radius: var(--ink-r-sm); cursor: pointer; list-style: none; }
.ink-disclose-chip > summary::-webkit-details-marker { display: none; }
.ink-disclose-chip > summary::after { content: "+"; font-family: var(--ink-font-mono); }
.ink-disclose-chip[open] > summary::after { content: "\2212"; }
.ink-disclose-chip > summary:hover, .ink-disclose-chip > summary.is-hover { color: var(--ink-text); border-color: var(--ink-muted); }
.ink-disclose-chip > summary:focus-visible, .ink-disclose-chip > summary.is-focus { outline: 2px solid var(--ink-text); outline-offset: 2px; }
.ink-disclose-chip > :not(summary) { margin-top: var(--ink-2); padding: var(--ink-3); background: var(--ink-surface);
  border: 1px solid var(--ink-line); border-radius: var(--ink-r-sm); font-size: var(--ink-fs-sm); }
@media (max-width: 759px) and (pointer: coarse) { .ink-disclose-chip > summary { min-height: 44px; } }

/* ---- text fields: 16px on phones stops iOS auto-zoom; components.css already covers .ink-input (POKER 11) ---- */
@media (max-width: 759px) { .ink-textarea, .ink-select { font-size: 16px; } }

/* A-Ink gallery / showroom parts — load after components.css. Site default (light); both themes supported.
   Class prefix: ink-. Needs: tokens.css, components.css. (DS-S kit gap, GECKO + RACER seat reports burn3-2026-11-02) */

/* ---- page head: sticky display head (h1 + lede + .ink-toolbar) over a scrolling gallery (GECKO 1)
   self-contained like .ink-topbar: centers its own max-width, so it drops straight into <header>, no shell wrapper */
.ink-pagehead { position: sticky; top: 0; z-index: var(--ink-z-sticky); background: var(--ink-bg);
  max-width: var(--ink-max); margin: 0 auto; padding: var(--ink-5) var(--ink-gutter) var(--ink-3); border-bottom: 1px solid var(--ink-line); }
.ink-pagehead .ink-lede { margin-top: var(--ink-2); }
.ink-pagehead .ink-toolbar { margin: var(--ink-3) 0 0; border-bottom: 0; padding-bottom: 0; }
@media (max-width: 759px) { .ink-pagehead { padding: var(--ink-4) var(--ink-4) var(--ink-2); } }

/* ---- section head: heading with a right-aligned mono count (GECKO 2) ---- */
.ink-section-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--ink-3); margin-bottom: var(--ink-3); }
.ink-section-head .ink-count { font: 400 var(--ink-fs-xs) var(--ink-font-mono); color: var(--ink-faint); }

/* ---- autogrid: a self-sizing card grid, no per-page column math (GECKO 3) ---- */
.ink-autogrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(var(--ink-autogrid-min, 220px), 1fr)); gap: var(--ink-3); }

/* ---- clickable media card: pairs with .ink-media, works on <a> and <button> (GECKO 4) ---- */
.ink-media--action { display: grid; grid-template-rows: auto 1fr; width: 100%; min-width: 0; margin: 0; padding: 0;
  font: inherit; text-align: left; text-decoration: none !important; color: inherit; cursor: pointer; appearance: none;
  background: var(--ink-surface); border: 1px solid var(--ink-line); border-radius: var(--ink-r-md); overflow: hidden;
  box-shadow: var(--ink-elev-1); transition: border-color var(--ink-dur) var(--ink-ease), transform var(--ink-dur-fast) var(--ink-ease); }
.ink-media--action:hover, .ink-media--action.is-hover { border-color: var(--ink-line-strong); }
.ink-media--action:focus-visible, .ink-media--action.is-focus { outline: 2px solid var(--ink-text); outline-offset: 2px; }
.ink-media--action:active, .ink-media--action.is-active { transform: translateY(1px); background: var(--ink-raised); }

/* ---- experimental card tone: dashed line + a notch label, both themes (RACER 5) ---- */
.ink-card--experimental { position: relative; border-style: dashed; border-color: var(--ink-line-strong); }
.ink-card--experimental::before { content: "experimental"; position: absolute; top: -8px; left: var(--ink-4); padding: 0 6px;
  background: var(--ink-bg); font: 500 var(--ink-fs-xs)/1 var(--ink-font-mono); letter-spacing: var(--ink-track-caps); text-transform: uppercase; color: var(--ink-faint); }

/* A-Ink game overlays — parts/game-overlay.css. Load after game.css: <body class="ink ink-game">.
   New kit parts for chrome that sits on top of a live canvas — a menu veil, a bottom action dock, a hold
   control, and HUD corner fixes (job K3, seat-pilot gaps 3DDEPT/GECKO/POKER, burn3 2026-11-02).
   In-world art (the canvas, sprites, 3D) stays out of the kit's scope; .ink-canvas-demo below is a
   stand-in gradient for these pages only, never real in-game art. */

/* fake canvas: a warm gradient stand-in so overlay pages don't need a real <canvas> or WebGL context */
.ink-canvas-demo { position: absolute; inset: 0;
  background: radial-gradient(circle at 50% 36%, var(--ink-accent-wash), transparent 60%),
    linear-gradient(180deg, var(--ink-raised) 0%, var(--ink-bg) 46%, var(--ink-sunk) 100%); }

/* ---- veil: a menu card over a live canvas, no <dialog> needed (3DDEPT 5, DS-S gap 2) ---- */
/* fixed, not absolute: it covers the viewport on its own rather than being clipped by a HUD stage's overflow */
.ink-veil { position: fixed; inset: 0; z-index: var(--ink-z-modal); display: grid; place-items: center;
  padding: var(--ink-4); background: var(--ink-scrim); }
.ink-veil__card { width: min(560px, 100vw - 32px); max-height: 88vh; overflow-y: auto; min-width: 0;
  background: var(--ink-overlay); color: var(--ink-text); border: 1px solid var(--ink-line-strong);
  border-radius: var(--ink-r-md); box-shadow: var(--ink-elev-2); padding: var(--ink-5); }

/* ---- scene panel: a standalone panel surface for UI docked over a live canvas/3D scene — an inventory,
   objectives or settings panel anchored to a corner — without adopting .ink-gamemenu's own two-column
   layout the way .ink-gamemenu--veil's panel does (GECKO 3, DS-S gap "panel token for UI over a live
   3D scene"). Non-blocking (no scrim, not fixed to the viewport): several can sit over the scene at once,
   unlike .ink-veil which is a single blocking decision point. ---- */
.ink-scene-panel { position: absolute; z-index: var(--ink-z-sticky); width: min(320px, calc(100% - 2 * var(--ink-4)));
  background: var(--ink-overlay); color: var(--ink-text); border: 1px solid var(--ink-line-strong);
  border-radius: var(--ink-r-md); box-shadow: var(--ink-elev-2); padding: var(--ink-4); }
.ink-scene-panel--tl { top: var(--ink-4); left: var(--ink-4); }
.ink-scene-panel--tr { top: var(--ink-4); right: var(--ink-4); }
.ink-scene-panel--bl { bottom: var(--ink-4); left: var(--ink-4); }
.ink-scene-panel--br { bottom: var(--ink-4); right: var(--ink-4); }
/* demo-only stand-in stage for the panel pattern page — a small boxed scene instead of the full viewport
   .ink-hud, same spirit as .ink-canvas-demo above */
.ink-scene-panel-demo { position: relative; min-height: 220px; border-radius: var(--ink-r-md); overflow: hidden; }

/* ---- HUD action bar: docked to the bottom edge of the canvas (GECKO 6, 11) ---- */
/* the ground stays translucent, never solid: an opaque bar over WebGL blanks a band in Chromium */
.ink-hud-bar { position: absolute; inset: auto 0 0 0; z-index: var(--ink-z-sticky); display: flex; flex-wrap: wrap;
  align-items: center; justify-content: center; gap: var(--ink-3); padding: var(--ink-3) var(--ink-4);
  background: color-mix(in srgb, var(--ink-bg) 96%, transparent); border-top: 1px solid var(--ink-line); }

/* ---- hold pad: 72px round press-and-hold control (GECKO 8). Theme-aware (QA fix 3, light-theme-2026-11-02):
   a light host gets a light pad, dark keeps today's look — color-mix on --ink-bg/--ink-text instead of
   their dark-theme hex literals. ---- */
.ink-holdpad { position: relative; width: 72px; height: 72px; flex: none; border-radius: var(--ink-r-round);
  display: inline-grid; place-items: center; background: color-mix(in srgb, var(--ink-bg) 70%, transparent); color: var(--ink-text);
  border: 2px solid var(--ink-line-strong); font: 600 var(--ink-fs-xs) var(--ink-font-mono); text-transform: uppercase;
  cursor: pointer; transition: border-color var(--ink-dur) var(--ink-ease); }
.ink-holdpad:hover, .ink-holdpad.is-hover { border-color: var(--ink-text); }
.ink-holdpad:active, .ink-holdpad.is-holding { border-color: var(--ink-accent); }
/* ring: fill driven by --hold (0–1), set from JS while the press is held; no transition, it tracks the hold live */
.ink-holdpad__ring { position: absolute; inset: -2px; border-radius: var(--ink-r-round); pointer-events: none;
  background: conic-gradient(var(--ink-accent) calc(var(--hold, 0) * 360deg), transparent 0); }
.ink-holdpad__label { position: relative; }
/* a hold control floating free of the bottom dock (demo placement only — a real page positions it per layout) */
.ink-holdpad--float { position: absolute; right: var(--ink-4); bottom: var(--ink-7); z-index: var(--ink-z-sticky); }

/* ---- HUD title slot: wraps instead of running past the canvas edge (GECKO 5) ---- */
.ink-hud__slot--tc { max-width: calc(100% - 2 * var(--ink-4)); white-space: normal; text-align: center; }

/* ---- bottom corner slots clear the action dock instead of sitting under it (GECKO 6 follow-up):
   .ink-hud__slot--bl/--br anchor to the viewport edge in game.css with no notion of the bar docked
   on top of them; lift them when both share a page, as on this overlay. ---- */
.ink-hud:has(.ink-hud-bar) .ink-hud__slot--bl,
.ink-hud:has(.ink-hud-bar) .ink-hud__slot--br { bottom: calc(var(--ink-4) + 76px); }

/* ---- HUD slots carry a data hue: the corner keeps the label, the hue is a repeated cue, not the only one (GECKO 14) ---- */
.ink-hud__slot--data-1 { box-shadow: inset 0 2px 0 var(--ink-data-1); }
.ink-hud__slot--data-2 { box-shadow: inset 0 2px 0 var(--ink-data-2); }
.ink-hud__slot--data-3 { box-shadow: inset 0 2px 0 var(--ink-data-3); }
.ink-hud__slot--data-4 { box-shadow: inset 0 2px 0 var(--ink-data-4); }

/* ---- event strip: compact chronological rows, mono time + icon-free marker + text (3DDEPT 8) ---- */
.ink-events { display: grid; gap: 1px; margin: 0; padding: 0; list-style: none; max-height: 100%; overflow-y: auto; }
.ink-events li { display: grid; grid-template-columns: 52px 8px minmax(0, 1fr); align-items: center; gap: var(--ink-2);
  padding: 3px 0; border-bottom: 1px solid var(--ink-line); font-size: var(--ink-fs-xs); }
.ink-events li:last-child { border-bottom: 0; }
.ink-events time { font: 400 var(--ink-fs-xs) var(--ink-font-mono); color: var(--ink-faint); font-feature-settings: "tnum" 1; }
.ink-events__mark { width: 6px; height: 6px; border-radius: var(--ink-r-round); background: var(--ink-line-strong); }
.ink-events li.is-key .ink-events__mark { background: var(--ink-text); }

/* ---- short-landscape density: a phone turned sideways has little height to spare (POKER 5, 6, 13) ---- */
@media (max-height: 560px) and (orientation: landscape) {
  .ink-game { --ink-control-h: 44px; --ink-control-h-sm: 44px; }
  .ink-game .ink-card, .ink-veil__card { padding: var(--ink-4); }
  /* 3 actions + a stepper share one dock: 2 columns, ~600px wide, instead of a single cramped row */
  .ink-hud-bar { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); max-width: 600px; margin: 0 auto; gap: var(--ink-2); }
}

/* A-Ink game identity — parts/game-identity.css. Load after game.css: <body class="ink ink-game">.
   Closes three seat-pilot gaps (burn3-POKER-2026-11-02, items 17/18/20/24):
     - POKER 24: a per-game accent token, so one game's felt-green doesn't need a doubled-class
       override repeated on every component that currently paints --ink-accent;
     - POKER 17/18: the .ink-seats roster — a real 2-up breakpoint (not 2-up from tablet), a 44px
       phone row floor, a per-row action slot, and host/you tags;
     - POKER 20: a wider-tracking .ink-code-big variant for a room code read off a phone held up
       across the table.
   Not bundled into dist/ink.css (same as parts/game-table.css — see tools/build_ink.py: only
   parts an adopter should get unconditionally go in KIT_PARTS). Link it directly next to game.css;
   see a-ink/patterns/game-identity.html. Every rule here targets .ink-game and/or adds new classes
   — game.css, components.css and tokens.css are untouched. */

/* ---- POKER 24: per-game accent (v1.1 G9: split into a light/dark pair — see below) ----
   Set --ink-game-accent-light and/or --ink-game-accent-dark on .ink-game — inline style, or the
   game's own single class — and every primary button / selected state in the game skin follows
   whichever one matches the theme actually in effect. Nothing below needs a doubled
   .ink-game.my-game-theme selector to repeat the override per component:
     <body class="ink ink-game" style="--ink-game-accent-dark: #4F9E6B; --ink-game-accent-light: #358554">
   Defaults to the kit accent, so a game that never sets either renders exactly as it does today.
   A game that only ever renders dark (the .ink-game default — most do) only needs -dark.

   Why a pair, not one value (G3's original shape): --ink-on-accent flips per theme — white in
   light, near-black (#13110E) in dark (tokens.css) — so the text drawn on this accent (primary
   buttons, the host/you pill) needs >= 4.5:1 against TWO different colors, and almost no single
   hex clears both at once; >= 3:1 where the accent is only a boundary (the is-you seat edge, the
   is-turn seat-ring stroke) has the same problem against each theme's own surfaces. Check a
   light/dark pair before using it:
     python3 tools/check_tokens.py style #358554 #4F9E6B
   (a single hex still works there too, checked against both themes at once — for a plain
   --ink-game-accent override that only has to pass one theme because the game stays dark/light).
   If a value fails, lighten/darken it — don't widen what --ink-on-accent is allowed to be, that's
   shared by every other accent use.

   --ink-game-accent itself stays the token every rule below reads — this just resolves it to the
   right half of the pair for the theme in effect. A page that still sets only the old single
   --ink-game-accent (G3) is unaffected: that declaration sits directly on the element, so it
   outranks these theme-scoped rules by specificity and renders exactly as before. */
.ink-game { --ink-game-accent: var(--ink-accent); }
[data-theme="light"] .ink-game             { --ink-game-accent: var(--ink-game-accent-light, var(--ink-accent)); }
:root:not([data-theme="light"]) .ink-game  { --ink-game-accent: var(--ink-game-accent-dark, var(--ink-accent)); }
.ink-game .ink-btn--primary { background: var(--ink-game-accent); border-color: var(--ink-game-accent); }
.ink-game .ink-btn--primary:hover, .ink-game .ink-btn--primary.is-hover,
.ink-game .ink-btn--primary:active, .ink-game .ink-btn--primary.is-active {
  background: color-mix(in srgb, var(--ink-game-accent) 85%, var(--ink-text) 15%);
  border-color: color-mix(in srgb, var(--ink-game-accent) 85%, var(--ink-text) 15%);
}
.ink-game ol.ink-seats li.is-you { box-shadow: inset 2px 0 0 var(--ink-game-accent); }
.ink-game .ink-seatring .seat.is-turn circle { stroke: var(--ink-game-accent); }

/* ---- POKER 17/18: seat roster ----
   game.css ships .ink-seats 2-up unconditionally (1-up only below 760px) with a 3-column row
   (avatar, name, state) and no per-row action. The seat pilots asked for three things: 2-up
   starting at 1024px, not 760px (a tablet-width row was too tight for name + state + an action);
   a 5th row column for a per-row action; and host/you identity carried as a tag, not just the
   existing is-you edge. All three land as later/higher-specificity rules over game.css, not a
   hand-edit of it. */
@media (max-width: 1023px) { ol.ink-seats { grid-template-columns: minmax(0, 1fr); } }
@media (max-width: 759px) { ol.ink-seats li { min-height: var(--ink-target-phone); } }
.ink-game ol.ink-seats li { grid-template-columns: 32px auto minmax(0, 1fr) auto auto; }

/* name cell gets its own flex row so a host/you tag wraps next to the name instead of stealing
   a grid column every row would need to leave empty for a seat with no tag */
.ink-seat-name { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--ink-1); min-width: 0; }
.ink-seat-name > span:first-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ink-pill--host { background: var(--ink-text); color: var(--ink-bg); border-color: var(--ink-text); }
.ink-game .ink-pill--you { background: var(--ink-game-accent); color: var(--ink-on-accent); border-color: var(--ink-game-accent); }
/* the action slot only exists on rows that have one (occupied, not-you seats); an is-you or
   is-empty row leaves the 5th grid track empty rather than carrying a placeholder */
.ink-game ol.ink-seats li > .ink-btn--sm { flex: none; justify-self: end; }

/* ---- POKER 20: room code read at a distance ---- */
.ink-code-big--wide { letter-spacing: .3em; }

/* A-Ink forms kit — plain CSS, needs tokens.css + components.css first. Class prefix: ink-.
   New form patterns only (components.css already covers .ink-input/.ink-textarea/.ink-select/.ink-check/
   .ink-switch/.ink-btn — reuse those, don't redefine them here). Same state-hook convention as
   components.css: every interactive control styles its real pseudo-class/attribute AND a mirror class,
   so a static page can show a state at rest:
     :hover = .is-hover   ·   :focus-visible = .is-focus   ·   :active = .is-active   ·   :disabled = .is-disabled
   (DS-S kit gaps, job G1 — game-seat pilot reports burn3-POKER-2026-11-02: POKER 14/15/16/19/21.) */

/* ---- checkbox/radio hit area: the 16px box in components.css IS the input, so it fails the 44px
   tap count on a coarse phone pointer. An invisible 44x44 box on the input itself (not the label,
   which may wrap a multi-line row) fixes the count without touching the 16px visual box (POKER 14). */
@media (max-width: 759px) and (pointer: coarse) {
  .ink-check input { position: relative; }
  .ink-check input::after { content: ""; position: absolute; top: 50%; left: 50%; width: 44px; height: 44px; transform: translate(-50%, -50%); }
}

/* ---- check row: one-line checkbox label + a muted help line tied to it with aria-describedby,
   not nested inside the <label> (POKER 15). Reuses components.css .ink-check and .ink-field__help. */
.ink-check-row { display: flex; flex-direction: column; gap: var(--ink-1); }
.ink-check-row > .ink-check { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ink-check-row > .ink-field__help { margin: 0 0 0 24px; } /* 16px box + --ink-2 gap, so the help text lines up under the label, not the box */

/* ---- select: 16px on phones stops iOS auto-zoom, the same fix components.css already gives
   .ink-input (POKER 16). */
@media (max-width: 759px) { .ink-select { font-size: 16px; } }

/* ---- chat: a scrolling message log with an empty state, and the field+send group (POKER 19). ---- */
.ink-chat { display: flex; flex-direction: column; height: 360px; min-width: 0; background: var(--ink-surface);
  border: 1px solid var(--ink-line); border-radius: var(--ink-r-md); overflow: hidden; }
.ink-chat__log { flex: 1; min-height: 0; margin: 0; padding: var(--ink-3); display: flex; flex-direction: column;
  gap: var(--ink-2); overflow-y: auto; list-style: none; }
.ink-chat__msg { align-self: flex-start; max-width: 80%; padding: var(--ink-2) var(--ink-3); border-radius: var(--ink-r-md);
  background: var(--ink-raised); font: 400 var(--ink-fs-sm)/1.4 var(--ink-font-ui); color: var(--ink-text); }
.ink-chat__msg b { display: block; font: 500 var(--ink-fs-xs) var(--ink-font-ui); color: var(--ink-muted); margin-bottom: 2px; }
.ink-chat__msg--me { align-self: flex-end; background: var(--ink-accent-wash); }
.ink-chat__empty { flex: 1; display: grid; place-content: center; gap: var(--ink-2); padding: var(--ink-6);
  color: var(--ink-muted); font-size: var(--ink-fs-sm); text-align: center; }
.ink-chat__empty .ink-icon { color: var(--ink-faint); margin: 0 auto; }

/* text field + send button as one visual group, 44px floor at phone/coarse via --ink-control-h like
   .ink-input/.ink-btn already carry; works standalone or as a .ink-chat footer. */
.ink-input-send { display: flex; align-items: stretch; min-width: 0; background: var(--ink-bg);
  border: 1px solid var(--ink-line-strong); border-radius: var(--ink-r-sm); overflow: hidden; }
.ink-input-send > .ink-input { flex: 1; min-width: 0; border: 0; border-radius: 0; background: transparent; }
.ink-input-send > .ink-input:focus-visible, .ink-input-send > .ink-input.is-focus { outline-offset: -2px; z-index: 1; }
.ink-input-send > .ink-btn { flex: none; border: 0; border-left: 1px solid var(--ink-line-strong); border-radius: 0; }
.ink-chat > .ink-input-send { border: 0; border-top: 1px solid var(--ink-line); border-radius: 0; }

/* ---- file input: style the native ::file-selector-button as a secondary .ink-btn, 44px floor at
   phone/coarse via the same --ink-control-h token .ink-btn already escalates (POKER 21). ---- */
.ink-file { display: inline-flex; align-items: center; width: 100%; min-width: 0; min-height: var(--ink-control-h);
  font: 400 var(--ink-fs-sm) var(--ink-font-ui); color: var(--ink-muted); cursor: pointer; }
.ink-file::file-selector-button { margin-right: var(--ink-3); min-height: var(--ink-control-h); padding: 0 var(--ink-4);
  font: 500 var(--ink-fs-sm) var(--ink-font-ui); color: var(--ink-text); background: var(--ink-surface);
  border: 1px solid var(--ink-line-strong); border-radius: var(--ink-r-sm); cursor: pointer;
  transition: background var(--ink-dur) var(--ink-ease), border-color var(--ink-dur) var(--ink-ease); }
.ink-file:hover::file-selector-button, .ink-file.is-hover::file-selector-button { background: var(--ink-raised); border-color: var(--ink-muted); }
.ink-file:focus-visible::file-selector-button, .ink-file.is-focus::file-selector-button { outline: 2px solid var(--ink-text); outline-offset: 2px; }
.ink-file:active::file-selector-button, .ink-file.is-active::file-selector-button { background: var(--ink-overlay); }
.ink-file:disabled, .ink-file.is-disabled { color: var(--ink-faint); cursor: not-allowed; }
.ink-file:disabled::file-selector-button, .ink-file.is-disabled::file-selector-button {
  color: var(--ink-faint); cursor: not-allowed; border-style: dashed; background: transparent; }

/* A-Ink game density — a-ink/parts/game-density.css. Load after game.css (and parts/game-overlay.css
   if the page also carries the HUD action bar): <body class="ink ink-game">. Job G2 (seat-pilot gaps
   POKER 6, 13, 22, 23; GECKO 17): a lobby or table card had no documented way to ask for a tighter
   rhythm than game.css's own default, so a full seat list plus its buy-in field and action row runs
   past the fold — on a phone turned sideways (POKER 6, 13; GECKO 17: ~390px of height to work with,
   not game.css's portrait-tuned 844) and on a dense, fully-expanded lobby read at 1440x900 (POKER 22:
   the last seat row misses the fold; POKER 23: the join action below it goes with it).

   One compact density step, reached two ways. Both set the same three things, so a page never shows
   two different "compact" looks depending on which way it got there:

     1. .ink-game--compact — opt in by hand, on `.ink-game` itself or any element inside it. For a
        lobby/table that's dense by nature (a full table of seats) at any viewport, desktop included
        (POKER 22, 23).
     2. @media (max-height: 560px) and (orientation: landscape) — the same step, automatic, no class
        needed. Covers a phone rotated to landscape on *any* .ink-game page, compact or not
        (POKER 6, 13; GECKO 17).

   What each sets, and why:
     --ink-control-h                      -> 44px, the phone tap-target floor. The (pointer: coarse)
                                              guard below pins it there even if a later edit tries to
                                              set it lower for a roomier desktop compact look — compact
                                              never ships a sub-44px control on a touch surface.
     .ink-card / .ink-veil__card padding  -> var(--ink-4)   (16px — down from the card's own 24px/
                                              var(--ink-5) default; see components.css .ink-card and
                                              parts/game-overlay.css .ink-veil__card)
     .ink-stack / .ink-fieldset gap,
     .ink-seats gap                       -> var(--ink-3)  (12px — the rhythm between a lobby card's
                                              fields and between the rows in its seat list)

   A third rule, desktop-only and gated to .ink-game--compact only (not automatic — a wide short
   viewport is a design choice about the lobby, not a device constraint the way short-landscape is),
   tightens the seat list's own row height and padding so a full table's last row clears the 1440x900
   fold (POKER 22, 23) without shrinking any control below its own floor. */

.ink-game--compact { --ink-control-h: 44px; }
.ink-game--compact .ink-card,
.ink-game--compact .ink-veil__card { padding: var(--ink-4); }
.ink-game--compact .ink-stack,
.ink-game--compact .ink-fieldset { gap: var(--ink-3); }
.ink-game--compact .ink-seats { gap: var(--ink-1) var(--ink-3); }
.ink-game--compact .ink-seats li { padding: var(--ink-1) 0; }

/* touch: 44px is a floor, not a target — this is the same guard game.css's own (pointer: coarse)
   override gives the non-compact skin, repeated here so compact can never slip under it either. */
@media (pointer: coarse) { .ink-game--compact { --ink-control-h: 44px; } }

/* short-landscape: automatic, no class needed — mirrors .ink-game--compact's three rules above
   exactly (control height, card padding, field/seat gaps), so a page that only hits this breakpoint
   by rotation reads the same as one that opted into compact by hand. Scoped to .ink-game, not
   .ink-game--compact, because every game page — not just ones that chose compact — gets squeezed by
   a phone turned sideways. */
@media (max-height: 560px) and (orientation: landscape) {
  .ink-game { --ink-control-h: 44px; }
  .ink-game .ink-card,
  .ink-game .ink-veil__card { padding: var(--ink-4); }
  .ink-game .ink-stack,
  .ink-game .ink-fieldset { gap: var(--ink-3); }
  .ink-game .ink-seats { gap: var(--ink-1) var(--ink-3); }
  .ink-game .ink-seats li { padding: var(--ink-1) 0; }
  /* components.css's own .ink-list__disclose forces its fold open from 760px of *width* up, with
     no notion of a landscape phone's short height — re-fold it here (summary back, content back out
     of flow) so a dense roster doesn't re-open into the ~390px this breakpoint actually has to work
     with. .ink-game adds the specificity needed to win over that unconditioned rule. */
  .ink-game .ink-list__disclose > summary { display: flex; }
  .ink-game .ink-list__disclose:not([open]) > :not(summary) { display: none; }
}

/* desktop compact: a dense, fully-expanded lobby (every seat row shown, none folded behind a
   disclosure) read at 1440x900 pushes its last row below the fold (POKER 22) and the join action
   under it with it (POKER 23). Tighten the seat rows themselves — min-height and padding — only
   under .ink-game--compact and only from the kit's own desktop breakpoint (--ink-bp-desktop, 1100px)
   up: a touch surface narrower than that never reaches this rule, so the 40px row here doesn't need
   --ink-control-h's 44px floor — pointer, not viewport width, decides the tap-target floor, and the
   (pointer: coarse) guard above still wins over this rule if it ever applies at this width. */
@media (min-width: 1100px) {
  .ink-game--compact .ink-seats li { min-height: 40px; }
}

/* A-Ink Data HUD — parts/data-hud.css. A dense, mono readout grid for ops/telemetry boards: a generalized
   companion to game.css's .ink-hud__slot (which is anchored to a live canvas) for boards and dashboards that
   are not a game overlay (job G4, seat gaps GECKO 14, 15, 16, 18).

   GECKO 18: letter-spacing tokens. The kit's uppercase/mono labels (gallery.css, components.css .ink-label,
   game.css .ink-hud__label) each hand-picked a tracking value (.04em/.06em/.08em); --ink-track-tight/-normal/
   -wide/-caps name the same four roles so a new part picks one instead of inventing a fifth. Promoted into
   a-ink/tokens.css (job G8) — this file just consumes them below. */

/* ---- dense data type tier (GECKO 14): mono, tabular figures, tighter line-height — within the kit's
   general 1.3-1.7 line-height rule (R18), at its tight end. A utility, not a component: pair it with any
   numeric readout (a HUD value below, a dense table cell) to get the same tabular mono treatment. ---- */
.ink-data-dense { font-family: var(--ink-font-mono); font-feature-settings: "tnum" 1;
  line-height: 1.3; letter-spacing: var(--ink-track-tight); }

/* ---- Data HUD: a grid of dense readouts for a board (not a canvas overlay). Each cell hues by
   --ink-data-1..4 — the kit's data palette — never a literal colour (GECKO 14). ---- */
.ink-datahud { display: grid; grid-template-columns: repeat(auto-fit, minmax(128px, 1fr)); gap: 1px;
  background: var(--ink-line); border: 1px solid var(--ink-line); border-radius: var(--ink-r-md); overflow: hidden; }
.ink-datahud__cell { position: relative; min-width: 0; display: flex; flex-direction: column; gap: 2px;
  padding: var(--ink-3) var(--ink-4); background: var(--ink-surface); border-left: 3px solid var(--ink-line-strong); }
.ink-datahud__cell--data-1 { border-left-color: var(--ink-data-1); }
.ink-datahud__cell--data-2 { border-left-color: var(--ink-data-2); }
.ink-datahud__cell--data-3 { border-left-color: var(--ink-data-3); }
.ink-datahud__cell--data-4 { border-left-color: var(--ink-data-4); }
.ink-datahud__label { font: 500 var(--ink-fs-xs)/1.3 var(--ink-font-ui); letter-spacing: var(--ink-track-caps);
  text-transform: uppercase; color: var(--ink-muted); }
.ink-datahud__value { font-size: 1.375rem; color: var(--ink-text); }   /* pair with .ink-data-dense for the mono/tabular tier */
.ink-datahud__value small { font: 400 var(--ink-fs-xs) var(--ink-font-mono); letter-spacing: var(--ink-track-normal);
  color: var(--ink-faint); margin-left: var(--ink-1); }
/* delta/trend readout: a touch more open than the dense value above it, not caps, not tight */
.ink-datahud__delta { font: 500 var(--ink-fs-xs) var(--ink-font-mono); letter-spacing: var(--ink-track-wide); }
.ink-datahud__delta--up { color: var(--ink-ok); } .ink-datahud__delta--down { color: var(--ink-fault); }

/* inert cell: the reading behind it isn't live right now (sensor offline, feed paused). Uses the OFF tier's
   real colour token below, never opacity, so effective contrast can't drift under a dimmed ancestor
   (tools/check_dim.mjs, GECKO 16). */
.ink-datahud__cell--off { border-left-color: var(--ink-lamp-off); }
.ink-datahud__cell--off .ink-datahud__value { color: var(--ink-faint); }

@media (max-width: 759px) {
  .ink-datahud { grid-template-columns: repeat(auto-fit, minmax(108px, 1fr)); }
}

/* ---- OFF tier for inert indicators (GECKO 15): .ink-state and .ink-lamp (components.css) each default
   their "nothing to report" look to --ink-muted, which reads closer to "quiet" than "off". This modifier
   dims further to --ink-faint — still >= 4.5:1 on every surface in both themes (tools/check_tokens.py) — by
   swapping the token, not by lowering opacity, so the dim is real everywhere it's read, not just where it
   was authored. ---- */
.ink-state--off { color: var(--ink-faint); }
.ink-state--off::before { background: var(--ink-faint); }
.ink-lamp--off { color: var(--ink-faint); }

}
