/* =============================================================================
   cat/web/style.css — CAT Studio's one stylesheet
   The UI redesign of 2026-10-11. The binding spec is docs/UI_REDESIGN.md:
   tokens §2, components §3, pages §4. It supersedes the "studio deck"
   (docs/UI_REBUILD_B.md, docs/DESIGN_B_STUDIO_REFERENCE.html): no mono
   readouts, no tick rail, no amber signal, no panel chassis.

   WHY IT WAS REDONE (the owner, 2026-10-11): "this looks like a vibe coded
   site … we need a little better design thats not confusing … other users
   no chance". Measured on the old file: 169 mono uppercase letter-spaced
   labels, a tick rail under 11 titles, a grey header strip on 166 blocks,
   and a dark deck by default. The answer is removal and hierarchy: a light
   page, white cards, one indigo accent for actions, the system sans,
   sentence case, and status said with a glyph AND a word.

   WHO EDITS WHAT (docs/UI_REDESIGN.md §6.3). This file keeps one order —
   A's tokens and primitives, then B's section, then C's — and later rules
   win, so B and C override A's base without touching it:
     · A owns everything from here down to, not including, the read
       screen's "point at a line" comment (the first rule after §18).
     · B inserts its whole section between `.line-chip .notefield { … }` and
       the episode page's "while it runs" banner.
     · C owns the read-screen rules and everything from that banner down.
   B and C use only tokens (no hex, no px font sizes) and the class names
   below. A new primitive is A's; a page variant is the page owner's,
   prefixed (.home-*, .job-* for B; .ep-* for C).

   =============================================================================
   THE CLASS LIST — the contract (docs/UI_REDESIGN.md §3)

   SHELL (§3.1)
     .chrome .chrome-row       the one sticky header row
       .mark .mark-dot .wordmark
       .nav-toggle             "Menu" — under 940px once html.has-menu is set
       .nav                    the four everyday pages (aria-current marks one)
       .nav-admin-toggle       "Admin ▾" — opens .nav-group as a popover
       .nav-group .nav-group-label   the administrator's four pages
       .chrome-spacer
       .who                    the right-hand side (display: contents)
         .status-strip         #needsyou + #openwork; under 940px a strip
                               under the header
         .whoami .avatar-btn   the avatar and its .menu (#avatar-menu)
         .bell-btn .bell-count the notification bell (#notify-bell) and its
                               .notify-panel (#notify-panel): .notify-head
                               .notify-list .notify-item(.is-unread)
                               .notify-browser (also in Settings)
     .as-strip                 "You're signed in as … by …" under the header
     .stale .banner            compact waiting strips at the top of the page
   PAGE (§3.2, §4.0)
     .page                     the page container
     .page-head .page-head-main .crumb .page-sub .page-actions
   CARDS (§3.3)
     .card .card-head .card-title .card-sub .card-body
   BUTTONS (§3.4)
     .btn-primary .btn-secondary .btn-quiet .link .btn-danger .icon-btn
     modifiers .btn-sm .btn-lg .btn-block
   FORMS (§3.5)
     .input .select .textarea  (bare text inputs, selects and textareas look
                               the same) · .field > label · .field-help
     .field-error · .seg (buttons with aria-pressed) · .choice-chip
     .choice-chip-mark
   STATUS (§3.6)
     .status .status--working|needs|waiting|done|failed|stopped .status--lg
     .status-glyph             (CAT.chip emits this, keeping .chip)
   CALLOUT (§3.7)
     .callout .callout--needs|waiting|failed|stopped|done|info
     .callout--compact .callout-icon .callout-main .callout-title
     .callout-body .callout-actions
   STEPPER (§3.8)
     .steps[role=list] > .step[role=listitem] > .pip, .step-sep
     .step.on (in progress) .step.done .step.is-stopped
     .step.is-needs .step.is-paused .step.is-failed .step.is-partial
     .step.is-turn             waiting its turn (with .on): a clock
     .step-word                the state word under the current step
   PROGRESS (§3.9)
     .progress > i             fill = scaleX(var(--p)); .progress--row (4px)
     .progress.is-counting     pct is null: a static stripe, never 0%
   FOLD (§3.10)
     .fold > summary + .fold-body · .fold--admin
   EMPTY STATE (§3.11)
     .empty-state .empty-state-icon .empty-state-title .empty-state-text
     .empty.loading            the loading line
   TOASTS, MODAL, MENU (§3.12–§3.14)
     .toasts .toast .toast-glyph .toast-text .toast-x
     .modal-back .modal .modal-head .modal-body .modal-foot
     .menu .menu-item .menu-sep .menu-id .menu-note
   VIDEO CARD (§3.15)
     .video-grid .video-card .video-card-media .video-card-ph
     .video-card-dur .video-card-body .video-card-title .video-card-meta
     .video-card-actions
   TABLE (§3.16)   .table .table-wrap · th.is-num/td.is-num (a right-aligned
                   numeric column)
   BADGES, UTILITIES (§3.17)
     .badge .badge--draft .badge--practice .badge--admin
     .muted .meta .code .sr-only .prose

   LEGACY CLASSES are re-skinned in place (§2.8) so every page reads in the
   new system before its owner rebuilds it: .rail is hidden, .screen-tag is
   the page header, .label/.eyebrow are sentence-case labels, .panel is a
   card, .mono is tabular sans, .chip is the status chip, .meter is the
   progress bar, .found/.refusal/.banner are callouts, and the old buttons
   map onto §3.4.
   ============================================================================= */


/* =============================================================================
   1 · FONTS
   The UI is the SYSTEM sans (§2.2): zero bytes, works offline, reads as a
   native product. Newsreader stays for ONE thing — .prose, the long-form
   script — and nothing preloads it. It is self-hosted (cat/web/fonts/), so
   a page load never depends on the network.
   ============================================================================= */

@font-face {
  font-family: "Newsreader";
  font-style: normal;
  font-weight: 400 500;
  font-display: swap;
  src: url("/web/fonts/newsreader-latin.woff2") format("woff2");
}


/* =============================================================================
   2 · TOKENS (§2). No new hex anywhere outside these blocks.
   Every text/surface pair was computed with the WCAG 2.x formula; the
   measured ratio sits beside each token.
   Light is the default: no data-theme attribute means light. Dark applies
   only when the person chose it (data-theme="dark"), or chose System and
   the OS is dark (data-theme="system").
   ============================================================================= */

:root {
  color-scheme: light;

  /* --- fonts --- */
  --font-sans:  -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-mono:  ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
  --font-serif: "Newsreader", Georgia, "Times New Roman", serif;   /* .prose ONLY */

  /* --- type scale: size / line-height (rem on a 16px root) --- */
  --fs-xs:   0.75rem;    --lh-xs:   1rem;       /* 12 — chips, badges */
  --fs-sm:   0.8125rem;  --lh-sm:   1.25rem;    /* 13 — meta, helper text, table heads */
  --fs-md:   0.875rem;   --lh-md:   1.25rem;    /* 14 — buttons, nav, labels */
  --fs-base: 0.9375rem;  --lh-base: 1.5rem;     /* 15 — body */
  --fs-lg:   1rem;       --lh-lg:   1.5rem;     /* 16 — card titles; inputs on a phone */
  --fs-xl:   1.125rem;   --lh-xl:   1.75rem;    /* 18 — section headings, callout titles */
  --fs-2xl:  1.25rem;    --lh-2xl:  1.75rem;    /* 20 — modal titles */
  --fs-3xl:  1.5rem;     --lh-3xl:  2rem;       /* 24 — h1 on a phone */
  --fs-4xl:  1.75rem;    --lh-4xl:  2.25rem;    /* 28 — h1 */
  --fs-5xl:  2.25rem;    --lh-5xl:  2.75rem;    /* 36 — the Spend figure only */

  /* --- spacing, 4px base --- */
  --sp-1: 4px;  --sp-2: 8px;  --sp-3: 12px; --sp-4: 16px; --sp-5: 20px;
  --sp-6: 24px; --sp-8: 32px; --sp-10: 40px; --sp-12: 48px; --sp-16: 64px;

  /* --- radius, by object --- */
  --r-sm: 6px;     /* badge, code, duration badge */
  --r-md: 8px;     /* input, select, textarea, segmented option, menu item */
  --r-lg: 10px;    /* button, segmented track */
  --r-xl: 12px;    /* card, callout, video card, menu, toast */
  --r-2xl: 16px;   /* modal, video hero, empty-state tile */
  --r-full: 999px; /* status chip, avatar, choice chip, progress bar */

  /* --- elevation --- */
  --shadow-xs: 0 1px 2px rgba(16,24,40,.05);
  --shadow-sm: 0 1px 3px rgba(16,24,40,.08), 0 1px 2px rgba(16,24,40,.04);   /* cards */
  --shadow-md: 0 4px 12px rgba(16,24,40,.08), 0 2px 4px rgba(16,24,40,.04);  /* hover lift, sticky bars */
  --shadow-lg: 0 12px 32px rgba(16,24,40,.14), 0 4px 8px rgba(16,24,40,.06); /* menus, toasts, modals */

  /* --- motion: never infinite, never a layout property --- */
  --dur-fast: 120ms;  --dur: 200ms;  --ease: cubic-bezier(.2,0,0,1);

  /* --- layout --- */
  --page-max: 1200px;
  --page-pad: 32px;      /* ≤940px: 24px · ≤560px: 16px */
  --card-pad: 24px;      /* ≤560px: 16px */
  --header-h: 60px;      /* ≤560px: 56px */

  /* --- stacking --- */
  --z-header: 50; --z-menu: 60; --z-toast: 80; --z-modal: 90; --z-skip: 100;

  /* --- surfaces --- */
  --bg:             #F6F7F9;  /* the page */
  --surface:        #FFFFFF;  /* cards, header, menus, inputs, modals — 1.07:1 vs --bg, so cards also carry a border */
  --surface-2:      #F3F4F6;  /* subtle fill: hovered row, segmented track, readout, code */
  --surface-3:      #E9EBEF;  /* pressed/selected, picture placeholder */
  --border:         #E4E6EB;  /* card edge, divider */
  --border-subtle:  #EEF0F3;  /* row separators inside a card */
  --border-strong:  #D3D6DD;  /* table header rule, secondary-button edge */
  --border-control: #8A909B;  /* input/checkbox boundary — 3.21:1 on surface (WCAG 1.4.11) */

  /* --- text --- */
  --text:           #1D2026;  /* 16.32:1 surface · 15.22:1 bg · 14.83:1 surface-2 */
  --text-2:         #4F5563;  /* 7.47:1 surface · 6.97:1 bg · 6.79:1 surface-2 — helper sentences */
  --text-3:         #646A77;  /* 5.43:1 surface · 5.06:1 bg · 4.93:1 surface-2 · 4.55:1 surface-3 — meta, captions */
  --text-disabled:  #9CA3AF;  /* 2.54:1 — disabled controls only */

  /* --- the one accent: primary actions, links, focus, selection --- */
  --accent:         #4F46E5;  /* fill — white on it 6.29:1 */
  --accent-hover:   #4338CA;  /* white on it 7.90:1 */
  --accent-active:  #3730A3;  /* white on it 9.93:1 */
  --accent-text:    #4338CA;  /* links — 7.90:1 surface · 7.37:1 bg · 6.98:1 accent-tint */
  --accent-tint:    #EEF0FF;  /* selected chip/option, current nav — --text on it 14.41:1 */
  --accent-border:  #C7CBFF;
  --on-accent:      #FFFFFF;
  --focus:          #6366F1;  /* focus ring — 4.47:1 surface · 4.17:1 bg (≥3:1) */
  --focus-halo:     rgba(99,102,241,.25);  /* decorative halo around a focused input */

  /* --- status: tint / border / text-on-tint / solid (dot, glyph, bar, left rule) --- */
  --working-bg: #EFF4FF; --working-border: #C7D7FE; --working-text: #1E40AF; /* 7.91:1 */ --working-solid: #2563EB; /* 5.17:1 */
  --needs-bg:   #FFF4E0; --needs-border:   #FBD38D; --needs-text:   #92400E; /* 6.51:1 */ --needs-solid:   #D97706; /* 3.19:1 */
  --waiting-bg: #F2F4F7; --waiting-border: #D0D5DD; --waiting-text: #344054; /* 9.49:1 */ --waiting-solid: #667085; /* 4.97:1 */
  --done-bg:    #E7F6EF; --done-border:    #A6E3C8; --done-text:    #065F46; /* 6.89:1 */ --done-solid:    #059669; /* 3.77:1 */
  --failed-bg:  #FEEFEC; --failed-border:  #FBC4BA; --failed-text:  #912018; /* 7.75:1 */ --failed-solid:  #D92D20; /* 4.83:1 */
  --stopped-bg: #F4F4F5; --stopped-border: #D4D4D8; --stopped-text: #3F3F46; /* 9.50:1 */ --stopped-solid: #71717A; /* 4.83:1 */
  --on-solid:   #FFFFFF;  /* a glyph drawn ON a -solid fill (stepper circles): 3.19:1 needs · 3.77 done · 4.83 failed/stopped · 4.97 waiting · 5.17 working */

  /* --- scrims --- */
  --overlay: rgba(15,17,21,.48);
  --media-scrim: rgba(0,0,0,.72);  /* under text laid on a picture (duration badge) — same in both themes */
  --on-media: #FFFFFF;             /* that text */

  /* --- glyphs drawn by CSS (a mask, coloured by background-color, so
         they take any token). Shapes only — no colour lives in them. --- */
  --glyph-check:   url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3.5 8.5l3 3 6-7' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  --glyph-x:       url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4.5 4.5l7 7M11.5 4.5l-7 7' fill='none' stroke='black' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E");
  --glyph-x-circle: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='6.5' fill='none' stroke='black' stroke-width='1.5'/%3E%3Cpath d='M5.7 5.7l4.6 4.6M10.3 5.7l-4.6 4.6' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E");
  --glyph-info:    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='6.5' fill='none' stroke='black' stroke-width='1.5'/%3E%3Cpath d='M8 7.3v4' fill='none' stroke='black' stroke-width='1.6' stroke-linecap='round'/%3E%3Ccircle cx='8' cy='4.9' r='1' fill='black'/%3E%3C/svg%3E");
  --glyph-alert:   url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 3.5v5.5' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round'/%3E%3Ccircle cx='8' cy='12.2' r='1.3' fill='black'/%3E%3C/svg%3E");
  --glyph-pause:   url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Crect x='4.5' y='4' width='2.4' height='8' rx='.8' fill='black'/%3E%3Crect x='9.1' y='4' width='2.4' height='8' rx='.8' fill='black'/%3E%3C/svg%3E");
  --glyph-clock:   url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='5.6' fill='none' stroke='black' stroke-width='1.7'/%3E%3Cpath d='M8 5v3.3l2.2 1.4' fill='none' stroke='black' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  --glyph-stop:    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Crect x='4.5' y='4.5' width='7' height='7' rx='1.4' fill='black'/%3E%3C/svg%3E");
  --glyph-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M6 3.5l4.5 4.5L6 12.5' fill='none' stroke='black' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  --glyph-film:    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Crect x='3' y='5' width='18' height='14' rx='2.5' fill='none' stroke='black' stroke-width='1.6'/%3E%3Cpath d='M10 9.2v5.6l4.6-2.8z' fill='black'/%3E%3C/svg%3E");

  /* --- LEGACY ALIASES (§2.7). The old names stay defined until no file
         reads them — tests/test_css_tokens_defined.py fails on any var(--x)
         nobody defines, and B's and C's markup keeps the old classes until
         they rebuild it. Delete one only when `grep -r "var(--<name>"
         cat/web` is empty. --- */
  --deck:       var(--bg);
  --panel:      var(--surface);
  --panel-head: var(--surface);          /* the grey header strip is gone */
  --raised:     var(--surface-2);
  --sunk:       var(--surface-2);        /* inputs no longer use it (§3.5) */
  --line:       var(--border);
  --line-soft:  var(--border-subtle);
  --ink:        var(--text);
  --ink-loud:   var(--text);
  --ink-dim:    var(--text-2);
  --ink-faint:  var(--text-3);
  --signal:     var(--accent);
  --signal-bg:  var(--accent-tint);
  --signal-ln:  var(--accent-border);
  --on-signal:  var(--on-accent);
  --good:       var(--done-text);
  --stall:      var(--stopped-text);     /* deliberately NEUTRAL, not red: legacy .is-stall covered paused and stopped runs */
  --shadow:     var(--shadow-sm);
  --t-micro:    var(--fs-xs);            /* the 11px size is gone */
  --t-mini:     var(--fs-sm);
  --t-sm:       var(--fs-md);
  --t-base:     var(--fs-base);
  --t-lg:       var(--fs-xl);
  --t-xl:       var(--fs-2xl);
  --t-2xl:      var(--fs-4xl);
  --t-3xl:      var(--fs-5xl);
  --r:          var(--r-xl);
  --gut:        var(--card-pad);
  --sans:       var(--font-sans);
  --mono:       var(--font-mono);
  --serif:      var(--font-serif);
}

/* DARK — the same names. Two blocks, adjacent, EDIT BOTH OR NEITHER:
   plain CSS cannot alias a declaration block and this file has no build
   step. The first is the person's choice of Dark; the second is System on
   a Mac that is in dark mode. */
:root[data-theme="dark"] {
  color-scheme: dark;
  --bg:             #0F1115;
  --surface:        #171A20;
  --surface-2:      #1E222A;
  --surface-3:      #262B34;
  --border:         #2A2F38;
  --border-subtle:  #22262E;
  --border-strong:  #3A404B;
  --border-control: #6B7380;  /* 3.64:1 on surface */
  --text:           #C9CED6;  /* 11.02:1 surface · 11.95:1 bg · 10.08:1 surface-2 — inside the 7–12:1 band the owner's eye accepted */
  --text-2:         #A2A9B5;  /* 7.37:1 surface · 7.99:1 bg · 6.74:1 surface-2 */
  --text-3:         #858C99;  /* 5.15:1 surface · 5.59:1 bg · 4.71:1 surface-2 — NOT on surface-3 (4.20:1) */
  --text-disabled:  #5D6470;
  --accent:         #5B5BD6;  /* white on it 5.37:1 */
  --accent-hover:   #4E4EC4;  /* 6.54:1 */
  --accent-active:  #4343B0;  /* 7.87:1 */
  --accent-text:    #A5B4FC;  /* 8.74:1 surface · 9.48:1 bg · 7.40:1 accent-tint */
  --accent-tint:    #23244A;  /* --text on it 10.53:1 */
  --accent-border:  #3B3D7A;
  --on-accent:      #FFFFFF;
  --focus:          #818CF8;  /* 5.84:1 on surface */
  --focus-halo:     rgba(129,140,248,.30);
  --working-bg: #14213A; --working-border: #1E3A6B; --working-text: #93C5FD; /* 8.90:1 */ --working-solid: #60A5FA; /* 6.85:1 */
  --needs-bg:   #2E2410; --needs-border:   #5C4314; --needs-text:   #FCD34D; /* 10.58:1 */ --needs-solid:  #F59E0B; /* 8.11:1 */
  --waiting-bg: #1F242C; --waiting-border: #353C47; --waiting-text: #C3CAD5; /* 9.45:1 */ --waiting-solid: #8B93A1; /* 5.63:1 */
  --done-bg:    #0F2A20; --done-border:    #1E5440; --done-text:    #6EE7B7; /* 10.04:1 */ --done-solid:   #34D399; /* 9.06:1 */
  --failed-bg:  #331616; --failed-border:  #6B2424; --failed-text:  #FCA5A5; /* 8.73:1 */ --failed-solid:  #F87171; /* 6.30:1 */
  --stopped-bg: #232328; --stopped-border: #3F3F46; --stopped-text: #C4C4CC; /* 9.02:1 */ --stopped-solid: #A1A1AA; /* 6.80:1 */
  --on-solid:   #0F1115;  /* DARK glyph on the bright dark-theme solids — white would be 2.15:1 on amber. 8.80 needs · 9.83 done · 6.11 waiting · 6.83 failed · 7.43 working · 7.37 stopped */
  --shadow-xs: none;  --shadow-sm: none;   /* dark cards separate by border + surface step */
  --shadow-md: 0 4px 12px rgba(0,0,0,.40);
  --shadow-lg: 0 12px 32px rgba(0,0,0,.55);
  --overlay: rgba(0,0,0,.60);
}

@media (prefers-color-scheme: dark) {
  :root[data-theme="system"] {
    color-scheme: dark;
    --bg:             #0F1115;
    --surface:        #171A20;
    --surface-2:      #1E222A;
    --surface-3:      #262B34;
    --border:         #2A2F38;
    --border-subtle:  #22262E;
    --border-strong:  #3A404B;
    --border-control: #6B7380;  /* 3.64:1 on surface */
    --text:           #C9CED6;  /* 11.02:1 surface · 11.95:1 bg · 10.08:1 surface-2 */
    --text-2:         #A2A9B5;  /* 7.37:1 surface · 7.99:1 bg · 6.74:1 surface-2 */
    --text-3:         #858C99;  /* 5.15:1 surface · 5.59:1 bg · 4.71:1 surface-2 — NOT on surface-3 (4.20:1) */
    --text-disabled:  #5D6470;
    --accent:         #5B5BD6;  /* white on it 5.37:1 */
    --accent-hover:   #4E4EC4;  /* 6.54:1 */
    --accent-active:  #4343B0;  /* 7.87:1 */
    --accent-text:    #A5B4FC;  /* 8.74:1 surface · 9.48:1 bg · 7.40:1 accent-tint */
    --accent-tint:    #23244A;  /* --text on it 10.53:1 */
    --accent-border:  #3B3D7A;
    --on-accent:      #FFFFFF;
    --focus:          #818CF8;  /* 5.84:1 on surface */
    --focus-halo:     rgba(129,140,248,.30);
    --working-bg: #14213A; --working-border: #1E3A6B; --working-text: #93C5FD; /* 8.90:1 */ --working-solid: #60A5FA; /* 6.85:1 */
    --needs-bg:   #2E2410; --needs-border:   #5C4314; --needs-text:   #FCD34D; /* 10.58:1 */ --needs-solid:  #F59E0B; /* 8.11:1 */
    --waiting-bg: #1F242C; --waiting-border: #353C47; --waiting-text: #C3CAD5; /* 9.45:1 */ --waiting-solid: #8B93A1; /* 5.63:1 */
    --done-bg:    #0F2A20; --done-border:    #1E5440; --done-text:    #6EE7B7; /* 10.04:1 */ --done-solid:   #34D399; /* 9.06:1 */
    --failed-bg:  #331616; --failed-border:  #6B2424; --failed-text:  #FCA5A5; /* 8.73:1 */ --failed-solid:  #F87171; /* 6.30:1 */
    --stopped-bg: #232328; --stopped-border: #3F3F46; --stopped-text: #C4C4CC; /* 9.02:1 */ --stopped-solid: #A1A1AA; /* 6.80:1 */
    --on-solid:   #0F1115;  /* see the block above */
    --shadow-xs: none;  --shadow-sm: none;
    --shadow-md: 0 4px 12px rgba(0,0,0,.40);
    --shadow-lg: 0 12px 32px rgba(0,0,0,.55);
    --overlay: rgba(0,0,0,.60);
  }
}

/* the layout tokens step down with the screen (§2.4) */
@media (max-width: 940px) {
  :root { --page-pad: 24px; }
}
@media (max-width: 560px) {
  :root { --page-pad: 16px; --card-pad: 16px; --header-h: 56px; }
}


/* =============================================================================
   3 · BASE + THE ACCESSIBILITY FLOOR (§7.5, non-negotiable)
   ============================================================================= */

* { box-sizing: border-box; }

/* [hidden] MUST WIN. The user-agent's `[hidden]{display:none}` loses to any
   author rule of the same specificity, so `.read-grid{display:grid}` once
   re-showed an element the script had hidden — a stray hairline under the
   composer that no reading of the script explained. `hidden` asserts the
   element is not in the page, and no layout rule may argue with it. */
[hidden] { display: none !important; }

html {
  -webkit-text-size-adjust: 100%;
  /* a grid child with an un-capped min-width slid the page sideways on the
     owner's phone; nothing on the page may do that */
  overflow-x: hidden;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: var(--fs-base);
  line-height: 1.6;
  font-variant-numeric: tabular-nums;   /* counts and costs never jitter */
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

button, input, textarea, select { font: inherit; color: inherit; }
button { cursor: pointer; background: none; border: none; padding: 0; }
a { color: inherit; }
h1, h2, h3, h4 { font-weight: 600; letter-spacing: normal; color: var(--text); }
img, svg, video { max-width: 100%; }
p { margin: 0 0 var(--sp-3); }

/* FOCUS: one visible ring on everything, the primary button included — the
   offset puts the ring on the page, so it never vanishes into a fill.
   No border-radius here: an outline follows the element's own radius. */
:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

/* HIT TARGETS. Every button kind sets its own height (§3.4: 40px, quiet
   36px, small 32px); a bare button or summary gets a 36px floor. On a
   touch screen every button, link-button, summary and choice is 44px. */
button,
[role="button"],
summary,
.adjust,
.chan,
.chan-add,
.choice {
  min-height: 36px;
}
.mark { display: inline-flex; align-items: center; }
/* where forcing a height would stretch a table row or a strip of blocks */
.table button, .readbar button { min-height: 0; }
/* A CONTROL INSIDE A SENTENCE takes the line's height: a ghost button in a
   .hint line forced to a full button height split the paragraph around an
   empty-looking box (audit, 2026-10-02). */
.hint .ghost, .hint button.ghost, .hint .linkish, .hint .link {
  min-height: 0; padding: 0 2px; vertical-align: baseline;
  display: inline; line-height: inherit;
}
/* the touch-screen floor (44px) is at the end of §18, after every rule it
   has to outrank */

/* SKIP TO CONTENT. Off-screen until a keyboard reaches it, then it is the
   first thing on the page; the script at the foot of index.html moves focus
   into #page. */
.skip-link {
  position: absolute; left: 12px; top: -80px; z-index: var(--z-skip);
  padding: 10px 16px; border-radius: var(--r-md);
  background: var(--surface); color: var(--text);
  border: 1px solid var(--border); box-shadow: var(--shadow-lg);
  font-size: var(--fs-md); font-weight: 600; text-decoration: none;
}
.skip-link:focus { top: 12px; }
/* the skip target takes focus to move the keyboard, not to be outlined */
.page:focus, .page:focus-visible { outline: none; }

/* MOTION. Never infinite, never on a layout property; a person who asked
   the OS for less motion gets none. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}
/* menus, toasts and dialogs fade and rise 4px as they open */
@keyframes cat-rise {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: none; }
}
@keyframes cat-drop {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: none; }
}

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


/* =============================================================================
   4 · SHELL — the header (§3.1)
   One row, full width, sticky. Left to right: mark · nav (or Menu) · Admin ▾
   · spacer · status pills · avatar. It is no longer a floating panel.
   ============================================================================= */

.page {
  max-width: var(--page-max);
  margin: 0 auto;
  padding: var(--sp-4) var(--page-pad) 96px;
  min-width: 0;
}

.chrome {
  position: sticky; top: 0; z-index: var(--z-header);
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}
.chrome-row {
  display: flex; align-items: center; gap: var(--sp-3);
  max-width: var(--page-max); margin: 0 auto;
  padding: 0 var(--page-pad);
  min-height: var(--header-h);
  min-width: 0;
}
.chrome-spacer { flex: 1 1 auto; min-width: 0; }
.who { display: contents; }

.mark {
  flex: none; gap: 10px; height: var(--header-h);
  margin-right: var(--sp-3);
  color: var(--text); text-decoration: none;
}
.mark svg { flex: none; color: var(--text-3); }
.mark-dot { fill: var(--accent); }
.mark .wordmark {
  font-size: var(--fs-lg); font-weight: 600; line-height: 1;
  color: var(--text); white-space: nowrap;
}

/* THE NAV — the four everyday pages, then the Admin button. */
.nav {
  display: flex; align-items: center; gap: 2px;
  flex: 0 1 auto; min-width: 0;
  position: relative;      /* the Admin popover hangs from it */
}
.nav a,
.nav-admin-toggle {
  display: inline-flex; align-items: center; gap: 6px; flex: 0 0 auto;
  min-height: 36px; padding: 8px 12px; border-radius: var(--r-lg);
  font-size: var(--fs-md); line-height: var(--lh-md); font-weight: 500;
  color: var(--text-2); text-decoration: none; white-space: nowrap;
  transition: background-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.nav a:hover,
.nav-admin-toggle:hover { color: var(--text); background: var(--surface-2); }
/* the current page: background, colour AND weight — and aria-current, so it
   is said to a screen reader too; never hue alone */
.nav a[aria-current="page"],
.nav a.active,
.nav-admin-toggle.is-current {
  background: var(--accent-tint); color: var(--accent-text); font-weight: 600;
}
.nav-admin-toggle svg { flex: none; transition: transform var(--dur) var(--ease); }
.nav-admin-toggle[aria-expanded="true"] { color: var(--text); background: var(--surface-2); }
.nav-admin-toggle[aria-expanded="true"] svg { transform: rotate(180deg); }

/* THE ADMINISTRATOR'S PAGES. Without the shell's script (no html.has-menu)
   they sit in the row after a divider, as they always did — a page whose
   script did not run still reaches every page. With it, on a wide screen,
   they are a popover under "Admin ▾"; under 940px, a group in the Menu. */
.nav-group {
  display: flex; align-items: center; gap: 2px; flex: 0 0 auto;
  margin-left: var(--sp-2); padding-left: var(--sp-2);
  border-left: 1px solid var(--border);
}
.nav-group-label {
  font-size: var(--fs-sm); font-weight: 600; color: var(--text-3);
  padding: 0 6px 0 2px; white-space: nowrap;
}
.nav-group.is-plain { margin-left: 0; padding-left: 0; border-left: none; }
.nav-group.is-plain .nav-group-label { display: none; }

@media (min-width: 941px) {
  html.has-menu .nav-group {
    display: none;
    position: absolute; top: calc(100% + 10px); right: 0;
    flex-direction: column; align-items: stretch; gap: 2px;
    min-width: 220px; margin: 0; padding: 6px;
    background: var(--surface); border: 1px solid var(--border);
    border-radius: var(--r-xl); box-shadow: var(--shadow-lg);
    z-index: var(--z-menu);
  }
  html.has-menu .nav-group.is-open {
    display: flex;
    animation: cat-drop var(--dur) var(--ease);
  }
  /* somebody who is not an administrator: no toggle, no group — their
     People page is "Your account" in the avatar menu */
  html.has-menu .nav-group.is-plain,
  html.has-menu .nav-group.is-plain.is-open { display: none; }
  /* the button says "Admin", so the label is for a screen reader only */
  html.has-menu .nav-group .nav-group-label {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
  }
  html.has-menu .nav-group a {
    justify-content: flex-start; min-height: 36px; padding: 0 10px;
    border-radius: var(--r-md); color: var(--text);
  }
}

/* THE MENU BUTTON, for screens too narrow for the row. Shown only under
   940px and only once the script that opens it has run (html.has-menu). */
.nav-toggle {
  display: none; align-items: center; gap: 8px; flex: 0 1 auto; min-width: 0;
  min-height: 36px; padding: 6px 12px; border-radius: var(--r-lg);
  border: 1px solid var(--border-strong); background: var(--surface);
  font-size: var(--fs-md); font-weight: 500; color: var(--text);
  white-space: nowrap; overflow: hidden;
}
.nav-toggle:hover, .nav-toggle[aria-expanded="true"] { background: var(--surface-2); }
/* which page you are on, beside the word Menu — the collapsed list cannot */
.nav-here:not(:empty)::before { content: "·"; margin-right: 8px; color: var(--text-3); }
.nav-here { color: var(--text-2); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* UNDER 940px THE ROW BECOMES A MENU: a full-width sheet under the header
   listing the everyday pages, then the "Admin" label and its four links. */
@media (max-width: 940px) {
  /* THE MENU BUTTON GIVES WAY, the avatar never wraps under it: measured at
     375px, "Menu · Settings" pushed the avatar onto a second header line.
     A zero basis keeps the button on the row, it grows back to its own
     width when there is room, and the page's name ellipsises when not. */
  html.has-menu .nav-toggle { display: inline-flex; flex: 1000 1 0; max-width: max-content; }
  html.has-menu .nav-toggle > svg,
  html.has-menu .nav-toggle > span:not(.nav-here) { flex: none; }
  html.has-menu .nav-admin-toggle { display: none; }
  html.has-menu .chrome .nav { display: none; }
  html.has-menu .chrome.nav-open .nav {
    display: flex; flex-direction: column; align-items: stretch; gap: 2px;
    position: absolute; top: 100%; left: 0; right: 0;
    max-height: calc(100vh - var(--header-h)); overflow-y: auto;
    padding: var(--sp-2) var(--page-pad) var(--sp-4);
    background: var(--surface);
    border-bottom: 1px solid var(--border); box-shadow: var(--shadow-lg);
    animation: cat-drop var(--dur) var(--ease);
  }
  html.has-menu .chrome.nav-open .nav a { padding: 10px 12px; }
  html.has-menu .chrome.nav-open .nav-group {
    display: flex; flex-direction: column; align-items: stretch;
    margin: var(--sp-2) 0 0; padding: var(--sp-2) 0 0;
    border-left: none; border-top: 1px solid var(--border-subtle);
  }
  html.has-menu .chrome.nav-open .nav-group.is-plain { border-top: none; margin-top: 0; padding-top: 0; }
  html.has-menu .chrome.nav-open .nav-group-label { padding: 8px 12px 4px; }
}

/* THE STATUS PILLS (#needsyou, #openwork). In the row on a wide screen; a
   strip under the header under 940px, shown only when a pill is. */
.status-strip {
  display: flex; align-items: center; gap: var(--sp-2);
  flex: 0 1 auto; min-width: 0;
}
.status-strip .status {
  min-width: 0; max-width: 100%; overflow: hidden;
  text-decoration: none;
}
.status-strip .chip-word { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
a.status:hover .chip-word { text-decoration: underline; text-underline-offset: 2px; }
@media (max-width: 940px) {
  .chrome-row { flex-wrap: wrap; column-gap: var(--sp-3); row-gap: 0; }
  /* the strip WRAPS rather than cutting a pill's words off: "6 paid items
     in progress on 2 channels" is a count somebody may be acting on */
  .status-strip {
    order: 20; flex: 1 1 100%; flex-wrap: wrap; row-gap: 6px;
    margin: 0 calc(-1 * var(--page-pad)); padding: 6px var(--page-pad);
    min-height: 36px;
    background: var(--surface-2); border-top: 1px solid var(--border-subtle);
    font-size: var(--fs-sm);
  }
}

/* THE AVATAR and its menu (#whoami holds both; users.js paints them, the
   shell opens and closes the menu). */
.whoami { position: relative; flex: none; display: flex; align-items: center; min-width: 0; }
.avatar-btn {
  display: inline-grid; place-items: center; flex: none;
  width: 32px; height: 32px; min-height: 32px; border-radius: var(--r-full);
  background: var(--accent-tint); color: var(--accent-text);
  font-size: var(--fs-sm); font-weight: 600; line-height: 1;
  transition: background-color var(--dur-fast) var(--ease);
}
.avatar-btn:hover, .avatar-btn[aria-expanded="true"] { background: var(--accent-border); }
.menu--avatar {
  top: calc(100% + 10px); right: 0;
  width: min(280px, calc(100vw - 32px));
}

/* THE BELL (common.js, the notification center): beside the avatar on every
   page, with this person's unread count; its panel is fixed under the header
   at the right, never wider than the screen less a 16px gutter each side. */
.bell-btn {
  position: relative; display: inline-grid; place-items: center; flex: none;
  width: 32px; height: 32px; min-height: 32px; border-radius: var(--r-full);
  background: none; border: none; color: var(--text-2);
  transition: background-color var(--dur-fast) var(--ease);
}
.bell-btn[hidden] { display: none; }
.bell-btn:hover, .bell-btn[aria-expanded="true"] { background: var(--surface-2); color: var(--text); }
.bell-glyph { width: 18px; height: 18px; }
.bell-count {
  position: absolute; top: -2px; right: -4px;
  min-width: 18px; height: 18px; padding: 0 5px; border-radius: var(--r-full);
  background: var(--accent); color: var(--on-accent);
  font-size: var(--fs-xs); font-weight: 600; line-height: 18px; text-align: center;
}
.bell-count[hidden] { display: none; }
.notify-panel {
  position: fixed; z-index: var(--z-menu);
  top: calc(var(--header-h) + 8px); right: 16px;
  width: min(380px, calc(100vw - 32px));
  max-height: calc(100vh - var(--header-h) - 24px); overflow-y: auto;
  padding: var(--sp-3);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-xl); box-shadow: var(--shadow-lg);
  animation: cat-drop var(--dur) var(--ease);
}
.notify-panel[hidden] { display: none; }
.notify-head { display: flex; align-items: center; gap: var(--sp-2); margin-bottom: var(--sp-2); }
.notify-title { flex: 1 1 auto; margin: 0; font-size: var(--fs-md); font-weight: 600; }
.notify-close-glyph { width: 14px; height: 14px; }
.notify-list { list-style: none; margin: 0; padding: 0; }
.notify-item {
  display: flex; gap: var(--sp-2); padding: var(--sp-2);
  border-radius: var(--r-md); min-width: 0;
}
.notify-item + .notify-item { border-top: 1px solid var(--border-subtle); }
.notify-item.is-unread { background: var(--accent-tint); }
.notify-icon { flex: none; padding-top: 3px; }
.notify-glyph { width: 14px; height: 14px; }
.notify-item.is-done .notify-glyph { color: var(--done-solid); }
.notify-item.is-needs_you .notify-glyph { color: var(--needs-solid); }
.notify-item.is-failed .notify-glyph { color: var(--failed-solid); }
.notify-main { flex: 1 1 auto; min-width: 0; }
.notify-text, .notify-where, .notify-links { margin: 0; overflow-wrap: anywhere; }
.notify-text { font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--text); }
.notify-links { display: flex; flex-wrap: wrap; gap: 4px var(--sp-3); margin-top: 4px; font-size: var(--fs-sm); }
.notify-empty { margin: var(--sp-2) 0; font-size: var(--fs-sm); color: var(--text-2); }
.notify-foot { margin-top: var(--sp-3); padding-top: var(--sp-3); border-top: 1px solid var(--border-subtle); }
.notify-browser p { margin: 0 0 6px; font-size: var(--fs-sm); line-height: var(--lh-sm); overflow-wrap: anywhere; }
.notify-browser-btn { margin: 2px 0 8px; }
.notify-telegram { margin-bottom: var(--sp-3); padding-bottom: var(--sp-3); border-bottom: 1px solid var(--border-subtle); }
.notify-telegram p { margin: 0 0 6px; font-size: var(--fs-sm); line-height: var(--lh-sm); overflow-wrap: anywhere; }
.notify-telegram .btn-sm { margin: 2px 0 8px; }
.whoami .mono {
  display: block; min-width: 0; max-width: 100%;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  overflow-wrap: normal;
  font-size: var(--fs-md); font-weight: 500; color: var(--text);
}
/* the legacy avatar circle (a page that draws its own) */
.avatar {
  width: 32px; height: 32px; border-radius: var(--r-full);
  display: grid; place-items: center;
  background: var(--accent-tint); color: var(--accent-text);
  font-size: var(--fs-sm); font-weight: 600;
}

/* SIGNED IN AS SOMEBODY ELSE — a full-width strip under the header, never
   only inside the menu: every approval made here is recorded as theirs. */
.as-strip {
  margin: 0; border-radius: 0; border-left: none; border-right: none; border-top: none;
  border-bottom: 1px solid var(--needs-border);
  background: var(--needs-bg); color: var(--text);
  font-size: var(--fs-md); line-height: var(--lh-md);
}
.as-strip-inner {
  max-width: var(--page-max); margin: 0 auto; padding: 10px var(--page-pad);
  display: flex; align-items: center; gap: var(--sp-2); min-width: 0;
  overflow-wrap: anywhere;
}
.as-strip-inner > svg { flex: none; color: var(--needs-solid); }

/* the machine-wide open-paid-work pill: a status chip now (.status), the
   old class kept for whatever still reads it */
.openwork { max-width: 100%; }

/* "CAT can't be reached" and the restart banners: compact waiting strips at
   the top of the page, the width of the page's content. */
.stale,
.banner {
  display: flex; align-items: flex-start; gap: 10px;
  width: calc(100% - 2 * var(--page-pad));
  max-width: calc(var(--page-max) - 2 * var(--page-pad));
  margin: var(--sp-4) auto 0;
  padding: 10px 16px;
  background: var(--surface); color: var(--text);
  border: 1px solid var(--waiting-border); border-left: 4px solid var(--waiting-solid);
  border-radius: var(--r-xl);
  font-size: var(--fs-md); line-height: var(--lh-md);
  overflow-wrap: anywhere;
}
.stale::before,
.banner::before {
  content: ""; flex: none; width: 16px; height: 16px; margin-top: 2px;
  background: var(--waiting-solid);
  -webkit-mask: var(--glyph-info) center / contain no-repeat;
          mask: var(--glyph-info) center / contain no-repeat;
}
/* a .banner a page draws INSIDE itself sits in the page's flow */
.page .banner { width: auto; max-width: none; margin: 0 0 var(--sp-4); }

/* THE PAGES CHANGED UNDER THIS TAB (#webstale): a toast at the bottom left,
   away from the other toasts, with a Reload button. Its base rule lives in
   the episode section below; this restyles it by id. */
#webstale.reload-pill {
  left: 24px; bottom: 24px; z-index: var(--z-toast);
  max-width: min(440px, calc(100vw - 48px));
  padding: 12px 12px 12px 16px; gap: 12px;
  background: var(--surface); color: var(--text);
  border: 1px solid var(--border); border-radius: var(--r-xl);
  box-shadow: var(--shadow-lg);
  font-size: var(--fs-md); line-height: var(--lh-md);
  animation: cat-rise var(--dur) var(--ease);
}
@media (max-width: 560px) {
  #webstale.reload-pill { left: 12px; right: 12px; bottom: 12px; max-width: none; }
}


/* =============================================================================
   5 · THE PAGE HEADER (§3.2) — and the legacy .screen-tag, which is now it
   ============================================================================= */

.page-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  flex-wrap: wrap; gap: var(--sp-4) var(--sp-6);
  margin: var(--sp-4) 0 var(--sp-6);
}
.page-head-main { flex: 1 1 320px; min-width: 0; }
.page-head h1 {
  margin: 0;
  font-size: var(--fs-4xl); line-height: var(--lh-4xl); font-weight: 600;
  letter-spacing: -0.01em; color: var(--text);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; overflow-wrap: anywhere;
}
.page-sub {
  margin: var(--sp-1) 0 0;
  font-size: var(--fs-base); line-height: var(--lh-base); color: var(--text-2);
}
.crumb {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  margin-bottom: var(--sp-1);
  font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--text-3);
}
.crumb > *::after { content: "›"; margin-left: 6px; color: var(--text-3); }
.crumb a { color: var(--text-3); text-decoration: none; }
.crumb a:hover, .crumb a:focus-visible { color: var(--text); text-decoration: underline; }
.page-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
@media (max-width: 560px) {
  .page-head { margin: var(--sp-1) 0 var(--sp-4); }
  .page-head h1 { font-size: var(--fs-3xl); line-height: var(--lh-3xl); }
  .page-actions { width: 100%; }
  .page-actions .btn-primary { width: 100%; }
}

.screen { margin-bottom: var(--sp-12); }
.screen:last-child { margin-bottom: 0; }

/* the legacy screen title IS the page header now: the eyebrow is gone, the
   heading is the h1 size, the note is the page's one-line sub */
.screen-tag {
  display: flex; align-items: baseline; flex-wrap: wrap;
  gap: var(--sp-1) var(--sp-3);
  margin: var(--sp-4) 0 var(--sp-6);
}
.screen-tag .num { display: none; }
.screen-tag h1, .screen-tag h2 {
  flex: 1 1 100%; min-width: 0; margin: 0;
  font-size: var(--fs-4xl); line-height: var(--lh-4xl); font-weight: 600;
  letter-spacing: -0.01em; color: var(--text); overflow-wrap: anywhere;
}
.screen-tag .note {
  flex: 1 1 100%;
  font-size: var(--fs-base); line-height: var(--lh-base); color: var(--text-2);
}
.screen-tag .btn-back { margin-left: -10px; }
@media (max-width: 560px) {
  .screen-tag { margin: var(--sp-1) 0 var(--sp-4); }
  .screen-tag h1, .screen-tag h2 { font-size: var(--fs-3xl); line-height: var(--lh-3xl); }
}

/* THE TICK RAIL IS GONE (§2.8): decoration that carries no meaning. Its
   owners delete the element when they rebuild their header. */
.rail { display: none; }


/* =============================================================================
   6 · CARDS (§3.3) — and the legacy panel, which is now one
   White on the soft grey page, one border, 12px radius, a soft shadow.
   No header strip, no hairline under the title, no card inside a card.
   ============================================================================= */

.panel,
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-sm);
  min-width: 0;    /* a grid child without this is what scrolls the page sideways */
}
/* a legacy .card is a panel and its body in one box */
.card { padding: var(--card-pad); }
.card:has(> .card-head),
.card:has(> .card-body) { padding: 0; }
.card > h2 { margin: 0 0 var(--sp-3); font-size: var(--fs-lg); line-height: var(--lh-lg); }

.card-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  flex-wrap: wrap; gap: var(--sp-3) var(--sp-4);
  padding: 20px var(--card-pad) 0;
}
.card-head > :first-child { min-width: 0; flex: 1 1 auto; }
.card-title {
  margin: 0; font-size: var(--fs-lg); line-height: var(--lh-lg); font-weight: 600;
  color: var(--text); overflow-wrap: anywhere;
}
.card-sub { margin: 2px 0 0; font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--text-2); }
.card-body { padding: var(--sp-4) var(--card-pad) var(--card-pad); min-width: 0; }
.card > .card-body:first-child { padding-top: var(--card-pad); }

.panel-head {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: var(--sp-2) var(--sp-4);
  padding: 20px var(--card-pad) 0;
  background: none; border: none; border-radius: 0;
}
/* the head's first label is the card's title */
.panel-head .label:first-child {
  font-size: var(--fs-lg); line-height: var(--lh-lg); font-weight: 600; color: var(--text);
}
.panel-head .label { white-space: normal; overflow-wrap: break-word; min-width: 0; }
.panel-body { padding: var(--sp-4) var(--card-pad) var(--card-pad); }
.panel > .panel-body:first-child { padding-top: var(--card-pad); }
@media (max-width: 560px) {
  .card-head, .panel-head { padding: var(--sp-4) var(--card-pad) 0; }
  .card-body, .panel-body { padding: var(--sp-3) var(--card-pad) var(--card-pad); }
}

/* the sentence-case label (was the mono uppercase micro-label) */
.label {
  font-family: var(--font-sans); font-size: var(--fs-sm); line-height: var(--lh-sm);
  font-weight: 600; color: var(--text-2);
  letter-spacing: normal; text-transform: none; white-space: normal;
}

.panel-stack { display: flex; flex-direction: column; gap: var(--sp-6); }


/* =============================================================================
   7 · LAYOUT GRIDS (re-skinned; page owners replace them)
   ============================================================================= */

.deck-2    { display: grid; grid-template-columns: 282px minmax(0, 1fr); gap: var(--sp-6); align-items: start; }
.read-grid { display: grid; grid-template-columns: minmax(0, 1fr) 320px; gap: var(--sp-6); align-items: start; }
@media (min-width: 1280px) {
  .read-grid { grid-template-columns: minmax(0, 1fr) 440px; }
}
/* the sticky column clears the sticky header */
.rail-col  {
  display: flex; flex-direction: column; gap: var(--sp-6);
  position: sticky; top: calc(var(--header-h) + 16px); min-width: 0;
}
.wizard    { max-width: 660px; margin: 0 auto; }


/* =============================================================================
   8 · TYPE UTILITIES
   Mono only for real codes inside Admin details (.code); numbers use the
   sans with tabular figures. Newsreader only for .prose.
   ============================================================================= */

.mono {
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  letter-spacing: normal;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}
.num-readout {
  font-family: var(--font-sans);
  font-size: var(--fs-xl); line-height: var(--lh-xl); font-weight: 600;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.eyebrow {
  font-family: var(--font-sans); font-size: var(--fs-sm); line-height: var(--lh-sm);
  font-weight: 600; color: var(--text-2);
  letter-spacing: normal; text-transform: none; white-space: normal;
}
.serif { font-family: var(--font-sans); }   /* the serif is .prose's alone now */
.muted { color: var(--text-2); }
.meta  { font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--text-3); }
.code {
  font-family: var(--font-mono); font-size: var(--fs-sm);
  background: var(--surface-2); border-radius: var(--r-sm);
  padding: 1px 6px; overflow-wrap: anywhere;
}

/* BADGES (§3.17) */
.badge {
  display: inline-flex; align-items: center; flex: none;
  padding: 2px 8px; border-radius: var(--r-sm);
  font-size: var(--fs-xs); line-height: var(--lh-xs); font-weight: 600;
  background: var(--surface-2); color: var(--text-2);
  white-space: nowrap; vertical-align: middle;
}
.badge--draft,
.badge--practice {
  background: var(--waiting-bg); color: var(--waiting-text);
  box-shadow: inset 0 0 0 1px var(--waiting-border);
}
.badge--admin { box-shadow: inset 0 0 0 1px var(--border-strong); }


/* =============================================================================
   9 · READOUTS AND FOLDS
   ============================================================================= */

/* THE FOLD (§3.10): Details, then Admin details, at the foot of a page.
   The legacy folds (.ep-fold, .why-fold, .refusal-raw) wear the same look. */
.fold,
.ep-fold,
.why-fold {
  border-top: 1px solid var(--border-subtle);
}
.fold > summary,
.ep-fold > summary,
.why-fold > summary,
.refusal-raw > summary,
.made-why > summary {
  display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap;
  padding: 12px 0; cursor: pointer; list-style: none;
  font-size: var(--fs-md); line-height: var(--lh-md); font-weight: 500;
  color: var(--text-2);
  transition: color var(--dur-fast) var(--ease);
}
.fold > summary::-webkit-details-marker,
.ep-fold > summary::-webkit-details-marker,
.why-fold > summary::-webkit-details-marker,
.refusal-raw > summary::-webkit-details-marker,
.made-why > summary::-webkit-details-marker { display: none; }
.fold > summary::before,
.ep-fold > summary::before,
.why-fold > summary::before,
.refusal-raw > summary::before,
.made-why > summary::before {
  content: ""; flex: none; width: 16px; height: 16px;
  background: currentColor;
  -webkit-mask: var(--glyph-chevron) center / contain no-repeat;
          mask: var(--glyph-chevron) center / contain no-repeat;
  transition: transform var(--dur) var(--ease);
}
.fold[open] > summary::before,
.ep-fold[open] > summary::before,
.why-fold[open] > summary::before,
.refusal-raw[open] > summary::before,
.made-why[open] > summary::before { transform: rotate(90deg); }
.fold > summary:hover,
.ep-fold > summary:hover,
.why-fold > summary:hover,
.refusal-raw > summary:hover,
.made-why > summary:hover { color: var(--text); }
.fold-body { padding: var(--sp-1) 0 var(--sp-4); min-width: 0; }
.fold--admin > summary::after {
  content: "Admin";
  display: inline-flex; align-items: center;
  padding: 2px 8px; border-radius: var(--r-sm);
  font-size: var(--fs-xs); line-height: var(--lh-xs); font-weight: 600;
  background: var(--surface-2); color: var(--text-2);
  box-shadow: inset 0 0 0 1px var(--border-strong);
}

/* THE EPISODE'S SETTINGS, FOLDED (studio.js foldOpen): one row that reads
   like a sentence, "Change" at the right. */
.ep-fold { margin-top: var(--sp-5); }
.ep-fold > summary { align-items: baseline; column-gap: var(--sp-3); }
.ep-fold > summary::before { align-self: center; }
.ep-fold > summary::after {
  content: "Change"; margin-left: auto;
  font-size: var(--fs-md); font-weight: 500; color: var(--accent-text);
}
.ep-fold[open] > summary::after { content: "Close"; }
.ep-fold[data-verb="show"] > summary::after { content: "Show"; }
.ep-fold[data-verb="show"][open] > summary::after { content: "Hide"; }
.ep-fold > summary:hover::after { text-decoration: underline; }
.ep-fold-k {
  font-size: var(--fs-sm); font-weight: 600; color: var(--text-2);
  letter-spacing: normal; text-transform: none; white-space: normal;
}
.ep-fold-v { font-size: var(--fs-md); color: var(--text); }
.ep-fold[open] { padding-bottom: var(--sp-4); }
.ep-fold .readout { margin-top: var(--sp-1); }

/* a quiet fold that explains a figure; the money itself is never in one */
.why-fold { margin-top: var(--sp-4); }
.why-fold .table-wrap { margin-top: var(--sp-3); }

/* THE READOUT: what is already decided, at a glance, on a soft block with
   no inner hairlines, and one disclosure to change it */
.readout {
  margin-top: var(--sp-6);
  display: flex; flex-wrap: wrap; align-items: stretch;
  gap: var(--sp-3) var(--sp-6);
  padding: 14px 20px;
  background: var(--surface-2); border-radius: var(--r-xl);
}
.readout .cell { flex: 1 1 130px; min-width: 0; padding: 0; border: none; }
.readout .k,
.figure .k {
  font-family: var(--font-sans); font-size: var(--fs-sm); line-height: var(--lh-sm);
  font-weight: 600; color: var(--text-2);
  letter-spacing: normal; text-transform: none; white-space: normal;
}
.readout .v {
  font-size: var(--fs-md); color: var(--text);
  margin-top: 2px; line-height: 1.4; overflow-wrap: anywhere;
}
.readout .adjust {
  display: inline-flex; align-items: center; gap: 6px; align-self: center;
  margin-left: auto; padding: 6px 10px; border-radius: var(--r-lg);
  font-size: var(--fs-md); font-weight: 500; color: var(--accent-text);
  border: none;
}
.readout .adjust:hover { background: var(--surface-3); }
.readout-note { font-size: var(--fs-sm); color: var(--text-2); margin-top: var(--sp-2); }

/* THE READ'S OWN LADDER, on the scan page: the state is a WORD as well as
   a colour */
.step-row { display: flex; align-items: baseline; gap: 10px; margin-top: 6px; }
.step-mark {
  flex: 0 0 auto; min-width: 62px;
  font-size: var(--fs-sm); font-weight: 600; color: var(--text-2);
}
.step-mark.done { color: var(--good); }
.step-mark.now { color: var(--signal); }
.step-mark.stopped { color: var(--stall); }
.step-label { font-size: var(--t-sm); color: var(--text); }

/* ONE HEADLINE FIGURE, in a block of its own (Spend) */
.figure {
  display: flex; flex-direction: column; gap: 6px;
  padding: 16px 20px; border-radius: var(--r-xl);
  background: var(--surface-2);
}
.figure .num-readout { overflow-wrap: anywhere; }
.figure .readout-note { margin-top: 0; }
.figure-more { margin-top: var(--sp-5); }
.figure-more > .label { display: block; margin-bottom: 4px; }
.figure-more .alt-list li > div + div { margin-top: 6px; }
.figure-more .hint { margin-top: 6px; }


/* =============================================================================
   10 · STATUS (§3.6) — glyph + word + colour, in that order of importance.
   Strip the colour out of any state below and it still reads.
   ============================================================================= */

/* THE PROGRESS BAR (§3.9, legacy .meter / .run-meter). pct null renders as
   COUNTING — a static stripe and a word beside it, never 0%, never a loop. */
.progress,
.meter,
.run-meter {
  --p: 0;
  position: relative;
  height: 6px; border-radius: var(--r-full);
  background: var(--surface-3); overflow: hidden;
}
.progress--row, .run-meter { height: 4px; }
.progress > i {
  display: block; height: 100%; width: 100%;
  background: var(--working-solid);
  transform: scaleX(var(--p)); transform-origin: left;
  transition: transform var(--dur) var(--ease);
}
.meter { margin-top: var(--sp-2); }
.meter > i,
.run-meter > i {
  display: block; height: 100%;
  background: var(--working-solid); border-radius: inherit;
}
.run-meter { margin-top: 6px; max-width: 150px; }
.progress.is-counting,
.meter.is-counting {
  background: repeating-linear-gradient(135deg, var(--working-border) 0 6px, var(--surface-3) 6px 12px);
}
.progress.is-counting > i,
.meter.is-counting > i { display: none; }

/* THE STATUS CHIP. CAT.chip(kind, text) emits
     <span class="status status--needs chip"><svg class="status-glyph"/>…</span>
   The word is the kind's text colour, the glyph its solid colour. */
.chip,
.status {
  display: inline-flex; align-items: center; gap: 6px;
  height: 24px; padding: 0 10px 0 8px;
  border-radius: var(--r-full);
  font-family: var(--font-sans); font-size: var(--fs-xs); line-height: 1; font-weight: 600;
  white-space: nowrap; max-width: 100%; vertical-align: middle;
  /* a legacy chip with no kind reads as the neutral one */
  background: var(--stopped-bg); color: var(--stopped-text);
  box-shadow: inset 0 0 0 1px var(--stopped-border);
}
.chip-glyph,
.status-glyph { flex: none; width: 12px; height: 12px; color: var(--stopped-solid); }
.chip-word { overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.status--lg { height: 28px; padding: 0 12px 0 10px; font-size: var(--fs-sm); }
.status--lg .status-glyph { width: 14px; height: 14px; }

.status--working, .chip.is-info, .chip.is-signal {
  background: var(--working-bg); color: var(--working-text); box-shadow: inset 0 0 0 1px var(--working-border);
}
.status--working .status-glyph, .chip.is-info > .chip-glyph, .chip.is-signal > .chip-glyph { color: var(--working-solid); }
.status--needs, .chip.is-wait {
  background: var(--needs-bg); color: var(--needs-text); box-shadow: inset 0 0 0 1px var(--needs-border);
}
.status--needs .status-glyph, .chip.is-wait > .chip-glyph { color: var(--needs-solid); }
.status--waiting {
  background: var(--waiting-bg); color: var(--waiting-text); box-shadow: inset 0 0 0 1px var(--waiting-border);
}
.status--waiting .status-glyph { color: var(--waiting-solid); }
.status--done, .chip.is-good {
  background: var(--done-bg); color: var(--done-text); box-shadow: inset 0 0 0 1px var(--done-border);
}
.status--done .status-glyph, .chip.is-good > .chip-glyph { color: var(--done-solid); }
.status--failed {
  background: var(--failed-bg); color: var(--failed-text); box-shadow: inset 0 0 0 1px var(--failed-border);
}
.status--failed .status-glyph { color: var(--failed-solid); }
.status--stopped, .chip.is-stall, .chip.is-quiet {
  background: var(--stopped-bg); color: var(--stopped-text); box-shadow: inset 0 0 0 1px var(--stopped-border);
}
.status--stopped .status-glyph, .chip.is-stall > .chip-glyph, .chip.is-quiet > .chip-glyph { color: var(--stopped-solid); }

/* the inline state: glyph coloured by kind, the word in body text */
.state {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--text); min-width: 0;
}
.state > svg { flex: none; color: var(--text-3); }
.state.is-good   > svg { color: var(--done-solid); }
.state.is-wait   > svg { color: var(--needs-solid); }
.state.is-stall  > svg { color: var(--stopped-solid); }
.state.is-info   > svg { color: var(--working-solid); }
.state.is-signal > svg { color: var(--working-solid); }
.state.is-quiet  > svg { color: var(--text-3); }
.state.is-down   > svg { color: var(--failed-solid); }

/* An unusable model is SHOWN, greyed, with its real reason and key path —
   never hidden, never silently swapped (§7.4 #12). Greyed by a ground, a
   word and a glyph, never by fading the reason out of legibility. */
.unavailable {
  opacity: 1;
  color: var(--text);
  background: var(--surface-2);
}
.unavailable .reason { color: var(--text); font-size: var(--fs-sm); }
.unavailable .keypath { font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--text-2); overflow-wrap: anywhere; }

/* money. Never a figure that was not measured. */
.unpriced { font-size: var(--fs-sm); color: var(--text-3); }
.bound    { font-size: var(--fs-sm); color: var(--text-2); font-variant-numeric: tabular-nums; }
.exact    { font-size: var(--fs-sm); color: var(--text);   font-variant-numeric: tabular-nums; }


/* =============================================================================
   11 · CALLOUT (§3.7) — the one "something to read before you act" block.
   The legacy .found (neutral), .refusal (waiting, with the x glyph — a
   refused action is not a failed episode) and .banner wear it too.
   ============================================================================= */

.callout {
  display: flex; align-items: flex-start; gap: var(--sp-4);
  padding: 20px var(--card-pad);
  background: var(--surface);
  border: 1px solid var(--waiting-border); border-left: 4px solid var(--waiting-solid);
  border-radius: var(--r-xl);
  min-width: 0;
}
.callout-icon {
  flex: none; width: 36px; height: 36px; border-radius: var(--r-full);
  display: grid; place-items: center;
  background: var(--waiting-bg); color: var(--waiting-solid);
}
.callout-icon svg { width: 18px; height: 18px; }
.callout-main { flex: 1 1 auto; min-width: 0; }
.callout-title {
  margin: 0; font-size: var(--fs-xl); line-height: var(--lh-xl); font-weight: 600;
  color: var(--text); overflow-wrap: anywhere;
}
.callout-body {
  margin: var(--sp-1) 0 0; font-size: var(--fs-base); line-height: var(--lh-base);
  color: var(--text-2);
}
.callout-actions {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-3);
  margin-top: var(--sp-4);
}
.callout--needs   { border-color: var(--needs-border);   border-left-color: var(--needs-solid); }
.callout--needs   .callout-icon { background: var(--needs-bg);   color: var(--needs-solid); }
.callout--waiting { border-color: var(--waiting-border); border-left-color: var(--waiting-solid); }
.callout--waiting .callout-icon { background: var(--waiting-bg); color: var(--waiting-solid); }
.callout--failed  { border-color: var(--failed-border);  border-left-color: var(--failed-solid); }
.callout--failed  .callout-icon { background: var(--failed-bg);  color: var(--failed-solid); }
.callout--stopped { border-color: var(--stopped-border); border-left-color: var(--stopped-solid); }
.callout--stopped .callout-icon { background: var(--stopped-bg); color: var(--stopped-solid); }
.callout--done    { border-color: var(--done-border);    border-left-color: var(--done-solid); }
.callout--done    .callout-icon { background: var(--done-bg);    color: var(--done-solid); }
.callout--info    { border-color: var(--working-border); border-left-color: var(--working-solid); }
.callout--info    .callout-icon { background: var(--working-bg); color: var(--working-solid); }
/* one line, for banners and the composer's "Before you start" */
.callout--compact {
  gap: 10px; padding: 10px 16px; align-items: flex-start;
  font-size: var(--fs-md); line-height: var(--lh-md);
}
.callout--compact .callout-icon { width: auto; height: auto; background: none; margin-top: 2px; }
.callout--compact .callout-icon svg { width: 16px; height: 16px; }
.callout--compact .callout-title { font-size: var(--fs-md); line-height: var(--lh-md); }
.callout--compact .callout-body { margin-top: 0; font-size: var(--fs-md); line-height: var(--lh-md); }
.callout--compact .callout-actions { margin-top: var(--sp-2); }
@media (max-width: 560px) {
  .callout { flex-direction: column; gap: var(--sp-3); }
  .callout--compact { flex-direction: row; }
}

/* the neutral block: what was found (a channel, a reading) */
.found {
  margin-top: var(--sp-6); padding: 20px;
  background: var(--surface-2); border-radius: var(--r-xl); border: none;
}
.found-top { display: flex; gap: var(--sp-4); align-items: center; min-width: 0; }
.sq {
  width: 48px; height: 48px; border-radius: var(--r-lg); flex: none;
  display: grid; place-items: center;
  background: var(--accent-tint); color: var(--accent-text);
  font-size: var(--fs-md); font-weight: 600;
}
.found-name { font-size: var(--fs-lg); line-height: var(--lh-lg); color: var(--text); font-weight: 600; overflow-wrap: anywhere; }
.found-num  { font-size: var(--fs-sm); color: var(--text-3); margin-top: 2px; }

/* a refusal: the sentence leads; the machine token rides data-conflict and
   the title only (UX audit, 2026-10-02) */
.refusal {
  position: relative;
  padding: 12px 16px 12px 44px;
  background: var(--surface); color: var(--text);
  border: 1px solid var(--waiting-border); border-left: 4px solid var(--waiting-solid);
  border-radius: var(--r-xl);
  font-size: var(--fs-md); line-height: 1.55;
  overflow-wrap: anywhere;
}
.refusal::before {
  content: ""; position: absolute; left: 16px; top: 14px; width: 16px; height: 16px;
  background: var(--waiting-solid);
  -webkit-mask: var(--glyph-x-circle) center / contain no-repeat;
          mask: var(--glyph-x-circle) center / contain no-repeat;
}
.refusal > b {
  display: inline-block; font-size: var(--fs-xs); font-weight: 600;
  color: var(--text-3); margin-bottom: 4px;
}
.refusal-text { color: var(--text); }
.refusal ul { margin: 8px 0 0; padding-left: 18px; color: var(--text-2); }
.refusal li { margin: 4px 0; }
.refusal-raw { margin-top: var(--sp-2); font-size: var(--fs-sm); color: var(--text-2); }
.refusal-raw > summary { padding: 6px 0; min-height: 0; font-size: var(--fs-sm); }
.refusal-raw > .mono {
  margin-top: 6px; white-space: pre-wrap; overflow-wrap: anywhere;
  font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--text-2);
}
/* the missing-key sentence and its one link (CAT.keyMissing) */
.key-missing { font-size: var(--fs-md); color: var(--text); line-height: 1.6; }

/* A HASHTAG IS ONE WORD THAT MAY BE VERY LONG — it breaks inside the word
   rather than sliding the page sideways (tests/test_phone_width.py). */
.hashtags { overflow-wrap: anywhere; }


/* =============================================================================
   12 · BUTTONS (§3.4)
   ONE filled primary per view. Everything else is secondary (outlined) or
   quiet (text). Rows in a list never carry a filled primary.
   ============================================================================= */

.btn-primary,
.btn-approve,
.btn-secondary,
.ghost,
.btn-quiet,
.quiet,
.btn-back,
.btn-danger {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 40px; padding: 8px 16px; max-width: 100%;
  border: 1px solid transparent; border-radius: var(--r-lg);
  font-family: var(--font-sans); font-size: var(--fs-md); line-height: var(--lh-md); font-weight: 500;
  text-align: center; text-decoration: none; cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.btn-primary > svg, .btn-approve > svg, .btn-secondary > svg, .ghost > svg,
.btn-quiet > svg, .quiet > svg, .btn-back > svg, .btn-danger > svg { flex: none; }

/* the ONE main action of the view */
.btn-primary,
.btn-approve {
  background: var(--accent); color: var(--on-accent);
  font-weight: 600; box-shadow: var(--shadow-xs);
}
.btn-primary:hover, .btn-approve:hover { background: var(--accent-hover); }
.btn-primary:active, .btn-approve:active { background: var(--accent-active); }
.btn-approve { width: 100%; }

/* the alternatives; every door in a list row */
.btn-secondary,
.ghost {
  background: var(--surface); color: var(--text);
  border-color: var(--border-strong);
}
.btn-secondary:hover, .ghost:hover { background: var(--surface-2); }
.ghost { min-height: 36px; padding: 6px 12px; }
.btn-secondary.block { width: 100%; margin-top: var(--sp-3); }

/* quiet: "Only up to the storyboard", "Back", "Show all" */
.btn-quiet,
.quiet,
.btn-back {
  background: none; color: var(--text-2);
  min-height: 36px; padding: 6px 10px;
}
.btn-quiet:hover, .quiet:hover, .btn-back:hover { color: var(--text); background: var(--surface-2); }
.quiet-links { display: flex; gap: var(--sp-2) var(--sp-4); flex-wrap: wrap; align-items: center; }

/* destructive: the secondary shape, the word in failed text — never a
   solid red slab */
.btn-danger {
  background: var(--surface); color: var(--failed-text);
  border-color: var(--border-strong);
}
.btn-danger > svg { color: var(--failed-solid); }
.btn-danger:hover { background: var(--failed-bg); border-color: var(--failed-border); }

/* a link inside a sentence or a dense row */
.link,
.linkish {
  display: inline; min-height: 0; padding: 0; border: none; background: none;
  font: inherit; color: var(--accent-text); text-align: left;
  text-decoration: none; cursor: pointer;
}
.link:hover, .link:focus-visible,
.linkish:hover, .linkish:focus-visible { text-decoration: underline; text-underline-offset: 2px; }
.prose .link, .prose a { text-decoration: underline; text-underline-offset: 2px; }

/* modifiers */
.btn-sm { min-height: 32px; padding: 4px 12px; font-size: var(--fs-sm); line-height: var(--lh-sm); }
.btn-lg { min-height: 48px; padding: 12px 22px; font-size: var(--fs-lg); line-height: var(--lh-lg); }
.btn-block { width: 100%; }

/* an icon-only control — close, ⋯, copy. It must carry an aria-label. */
.icon-btn {
  display: inline-grid; place-items: center; flex: none;
  width: 36px; height: 36px; min-height: 36px; padding: 0;
  border-radius: var(--r-lg); color: var(--text-2); background: none;
  transition: background-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.icon-btn:hover { background: var(--surface-2); color: var(--text); }

/* A DISABLED CONTROL LOOKS DISABLED — every kind of button (UX audit,
   2026-10-02): dimmed, the not-allowed cursor, and no hover change. Written
   out per class as well as generically so a page's own class can never
   outrank it. */
button:disabled,
button[disabled],
[aria-disabled="true"],
.btn-primary[disabled],
.btn-approve[disabled],
.btn-secondary[disabled],
.btn-back[disabled],
.btn-danger[disabled],
.btn-quiet[disabled],
.ghost[disabled],
.quiet[disabled],
.link[disabled],
.linkish[disabled] { filter: none; opacity: .5; cursor: not-allowed; }
.btn-primary[disabled]:hover,
.btn-approve[disabled]:hover { filter: none; background: var(--accent); }
.btn-secondary[disabled]:hover,
.btn-danger[disabled]:hover,
.ghost[disabled]:hover { background: var(--surface); border-color: var(--border-strong); }
.btn-back[disabled]:hover,
.btn-quiet[disabled]:hover,
.quiet[disabled]:hover { background: none; color: var(--text-2); }
.link[disabled]:hover,
.linkish[disabled]:hover { text-decoration: none; }

.go-row { display: flex; align-items: center; gap: var(--sp-3) var(--sp-4); flex-wrap: wrap; margin-top: var(--sp-6); }

/* the stops promise: a line under the action, not a footnote */
.pledge {
  display: flex; gap: var(--sp-3); align-items: flex-start;
  margin-top: var(--sp-6); padding-top: var(--sp-5);
  border-top: 1px solid var(--border-subtle);
  font-size: var(--fs-md); color: var(--text-2); line-height: 1.6;
}
.pledge svg { flex: none; margin-top: 3px; color: var(--text-3); }

/* the shell's inline asks (CAT.askThen / confirmInline) */
.ask-then, .confirm-inline { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.ask-then .ask-q { margin: 0; color: var(--text); }
.confirm-inline .q { font-size: var(--fs-md); color: var(--text); }


/* =============================================================================
   13 · FORM CONTROLS (§3.5)
   Bare text inputs, selects and textareas look the same as .input/.select/
   .textarea, so a page that never named a class still gets the control.
   ============================================================================= */

.field { margin-top: 6px; }
.field > label {
  display: block; margin-bottom: 6px;
  font-size: var(--fs-md); line-height: var(--lh-md); font-weight: 500; color: var(--text);
}
.field-help { margin-top: 6px; font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--text-2); }
.field-error {
  display: flex; align-items: flex-start; gap: 6px; margin-top: 6px;
  font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--failed-text);
}
.field-error::before {
  content: ""; flex: none; width: 14px; height: 14px; margin-top: 3px;
  background: var(--failed-solid);
  -webkit-mask: var(--glyph-x-circle) center / contain no-repeat;
          mask: var(--glyph-x-circle) center / contain no-repeat;
}

input[type="text"],
input[type="email"],
input[type="password"],
input[type="search"],
input[type="url"],
input[type="number"],
input[type="tel"],
input:not([type]),
.input,
select,
.select,
textarea,
.textarea {
  max-width: 100%;
  background-color: var(--surface); color: var(--text);
  border: 1px solid var(--border-control); border-radius: var(--r-md);
  font-family: var(--font-sans); font-size: var(--fs-base);
  transition: border-color var(--dur-fast) var(--ease);
}
input[type="text"],
input[type="email"],
input[type="password"],
input[type="search"],
input[type="url"],
input[type="number"],
input[type="tel"],
input:not([type]),
.input,
select,
.select {
  min-height: 40px; padding: 0 12px; line-height: 1.5;
}
textarea,
.textarea { padding: 12px; line-height: 1.6; }
select,
.select {
  -webkit-appearance: none; appearance: none;
  padding-right: 32px;
  background-image:
    linear-gradient(45deg, transparent 50%, var(--text-3) 50%),
    linear-gradient(135deg, var(--text-3) 50%, transparent 50%);
  background-position: calc(100% - 17px) 50%, calc(100% - 12px) 50%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}
input::placeholder, textarea::placeholder { color: var(--text-3); opacity: 1; }
input[type="text"]:focus,
input[type="email"]:focus,
input[type="password"]:focus,
input[type="search"]:focus,
input[type="url"]:focus,
input[type="number"]:focus,
input[type="tel"]:focus,
input:not([type]):focus,
.input:focus,
select:focus,
.select:focus,
textarea:focus,
.textarea:focus {
  outline: none;
  border-color: var(--focus);
  box-shadow: 0 0 0 3px var(--focus-halo);
}
input[type="checkbox"],
input[type="radio"] { accent-color: var(--accent); width: 18px; height: 18px; }

/* the legacy shells: the SHELL is the control, the field inside is bare */
.input-shell,
.select-shell {
  display: flex; align-items: center; gap: 10px;
  min-height: 40px; padding: 0 12px;
  background: var(--surface);
  border: 1px solid var(--border-control); border-radius: var(--r-md);
  transition: border-color var(--dur-fast) var(--ease);
}
.input-shell:focus-within,
.select-shell:focus-within {
  border-color: var(--focus);
  box-shadow: 0 0 0 3px var(--focus-halo);
}
.input-shell > svg { flex: none; color: var(--text-3); }
.input-shell input,
.input-shell.is-prose input {
  flex: 1; min-width: 0; min-height: 38px;
  background: none; border: none; outline: none; box-shadow: none;
  padding: 0; border-radius: 0;
  font-family: var(--font-sans); font-size: var(--fs-base); letter-spacing: normal;
}
.input-shell input:focus { box-shadow: none; outline: none; }
.select-shell select {
  flex: 1; min-width: 0; min-height: 38px;
  background-color: transparent; border: none; outline: none; box-shadow: none;
  padding: 0 24px 0 0; border-radius: 0;
  font-size: var(--fs-base); color: var(--text);
  background-position: calc(100% - 9px) 50%, calc(100% - 4px) 50%;
  /* THE CHOSEN WORDS STAY INSIDE THE CONTROL, on every picker: WebKit lays
     a menu's chosen words out past its own edge, and a job's own picker
     holding a long model name pushed Settings to 499px on a 375px phone
     (measured 2026-10-12, review round 2 — the lists to try next had this
     rule; the jobs' own pickers did not) */
  overflow: hidden; text-overflow: ellipsis;
}
.select-shell select:focus { box-shadow: none; outline: none; }

/* A FILE PICKER IS A DROP ZONE WITH A REAL BUTTON IN IT */
input[type="file"] {
  display: block; width: 100%; max-width: 100%; min-height: 40px;
  padding: 16px; border: 1px dashed var(--border-control); border-radius: var(--r-md);
  background: var(--surface-2); color: var(--text);
  font-size: var(--fs-md); cursor: pointer;
}
input[type="file"]:hover { border-color: var(--text-3); }
input[type="file"]::file-selector-button {
  margin-right: 14px; padding: 8px 14px; border-radius: var(--r-lg);
  border: 1px solid var(--border-strong); background: var(--surface); color: var(--text);
  font: inherit; font-weight: 500; cursor: pointer;
}
input[type="file"]::file-selector-button:hover { background: var(--surface-3); }

/* the textareas: the note box, and the idea field (which loses the serif) */
.notefield,
.ask {
  width: 100%; min-height: 96px; resize: vertical;
  background: var(--surface); color: var(--text);
  border: 1px solid var(--border-control); border-radius: var(--r-md);
  padding: 12px; font-family: var(--font-sans); font-size: var(--fs-base); line-height: 1.6;
  letter-spacing: normal;
}
.notefield::placeholder, .ask::placeholder { color: var(--text-3); }
.notefield:focus, .ask:focus, .ask:focus-visible {
  outline: none; border-color: var(--focus); box-shadow: 0 0 0 3px var(--focus-halo);
}
.ask { min-height: 118px; }
/* Auto's steer line: the same field as ONE line */
.ask.is-line { min-height: 40px; resize: none; padding: 8px 12px; }
.ask-eyebrow {
  font-family: var(--font-sans); font-size: var(--fs-sm); line-height: var(--lh-sm);
  font-weight: 600; color: var(--text-2);
  margin-bottom: 6px; letter-spacing: normal; text-transform: none; white-space: normal;
}
.ask-wrap { border: none; padding-bottom: 0; }

/* the line under a field */
.hint { font-size: var(--fs-sm); line-height: 1.55; color: var(--text-2); margin-top: var(--sp-2); overflow-wrap: anywhere; }

.switch-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-4); padding: 14px 0; border-bottom: 1px solid var(--border-subtle);
  min-height: 44px;
}
.switch-row:last-child { border-bottom: none; }
.switch-row .t { font-size: var(--fs-md); color: var(--text); font-weight: 500; }
/* not a caption: it carries the whole consequence of the switch beside it */
.switch-row .d { font-size: var(--fs-sm); color: var(--text-2); margin-top: 4px; line-height: 1.5; }

.alt-ways { display: flex; gap: var(--sp-2); flex-wrap: wrap; align-items: center; margin-top: var(--sp-4); }
/* a blocker's one-click fixes (studio.js fixOptions): a button, and what it
   means under it; wraps at phone width */
.fix-options { display: flex; flex-direction: column; gap: var(--sp-2); margin-top: var(--sp-2); }
.fix-option .hint { white-space: normal; margin-top: 4px; }

/* THE SEGMENTED CONTROL: two to four options, e.g. "Paste a script | Auto".
   role="group" with an aria-label; the options are buttons with
   aria-pressed. */
.seg {
  display: inline-flex; gap: 4px; padding: 4px; max-width: 100%;
  background: var(--surface-2); border-radius: var(--r-lg);
}
.seg > button {
  flex: 1 1 auto; min-height: 36px; padding: 0 14px;
  border-radius: var(--r-md);
  font-size: var(--fs-md); font-weight: 500; color: var(--text-2);
  white-space: nowrap;
  transition: background-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.seg > button:hover { color: var(--text); }
.seg > button[aria-pressed="true"] {
  background: var(--surface); color: var(--text); font-weight: 600;
  box-shadow: var(--shadow-xs), inset 0 0 0 1px var(--border);
}
@media (max-width: 560px) {
  .seg { display: flex; width: 100%; }
}

/* CHOICE CHIPS — the channel picker. Radio semantics: aria-pressed, one
   pressed; pressed is a tint AND a 1.5px ring AND a check, never colour
   alone. They wrap; they never scroll sideways. */
.choice-chip {
  display: inline-flex; align-items: center; gap: 8px;
  max-width: 100%; min-height: 36px; padding: 0 14px 0 6px;
  border-radius: var(--r-full);
  border: 1px solid var(--border-strong); background: var(--surface);
  font-size: var(--fs-md); font-weight: 500; color: var(--text);
  text-align: left;
  transition: background-color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.choice-chip:hover { background: var(--surface-2); }
.choice-chip-mark {
  flex: none; width: 24px; height: 24px; border-radius: var(--r-full);
  display: grid; place-items: center;
  background: var(--surface-3); color: var(--text-2);
  font-size: var(--fs-xs); font-weight: 600; line-height: 1;
}
.choice-chip[aria-pressed="true"] {
  background: var(--accent-tint); color: var(--accent-text);
  border-color: var(--accent); box-shadow: inset 0 0 0 .5px var(--accent);
}
.choice-chip[aria-pressed="true"] .choice-chip-mark { background: var(--accent); color: var(--on-accent); }
.choice-chip[aria-pressed="true"]::after {
  content: ""; flex: none; width: 14px; height: 14px;
  background: var(--accent-text);
  -webkit-mask: var(--glyph-check) center / contain no-repeat;
          mask: var(--glyph-check) center / contain no-repeat;
}


/* =============================================================================
   14 · THE READING SURFACE
   The script is the one place a person reads long-form words: Newsreader,
   18px/1.75, 66 characters a line. Everything around it is the sans.
   ============================================================================= */

.reader { padding: 40px 48px 48px; }

.title {
  font-family: var(--font-sans); font-size: var(--fs-3xl); line-height: var(--lh-3xl);
  font-weight: 600; color: var(--text); margin: var(--sp-3) 0 0;
  letter-spacing: -0.01em; max-width: 24em; overflow-wrap: anywhere;
}
.title-alt { margin-top: var(--sp-3); font-size: var(--fs-sm); color: var(--text-2); }
.title-alt b { font-weight: 600; color: var(--text); }

.readbar {
  display: flex; gap: var(--sp-2) var(--sp-6); flex-wrap: wrap;
  margin: var(--sp-6) 0 0; padding: var(--sp-3) 0;
  border-top: 1px solid var(--border-subtle); border-bottom: 1px solid var(--border-subtle);
  font-size: var(--fs-sm); color: var(--text-3);
  font-variant-numeric: tabular-nums;
}

.prose {
  font-family: var(--font-serif); font-size: 1.125rem; line-height: 1.75;
  max-width: 66ch; color: var(--text);
}
.prose p { margin: 0 0 1.35em; }
.prose p:first-of-type { margin-top: var(--sp-8); }
.scene-break { display: block; width: 40px; height: 1px; background: var(--border-strong); margin: 28px 0 30px; }
.more { font-size: var(--fs-sm); color: var(--text-2); font-family: var(--font-sans); margin-top: var(--sp-8); }

/* on desktop the decision lives in .rail-col; on a phone it becomes this
   slim pinned bar ABOVE the prose. display:none until the phone width. */
.sticky-approve { display: none; }

.decide .panel-body { padding: 20px; }
.changes { margin-top: var(--sp-4); padding-top: var(--sp-4); border-top: 1px solid var(--border-subtle); }
.changes .label { margin-bottom: var(--sp-2); display: block; }
.next-up { font-size: var(--fs-sm); color: var(--text-2); line-height: 1.6; }
.next-up b { font-weight: 600; color: var(--text); }

/* READ 3 — THE STORYBOARD's strip and scene list (studio.js boardArticle) */
.sb-strip {
  display: flex; gap: 2px; margin-top: var(--sp-5); height: 26px;
  padding: 3px; border-radius: var(--r-sm);
  background: var(--surface-2); box-shadow: inset 0 0 0 1px var(--border);
}
/* NEVER WIDER THAN THE PAGE (a 216-scene strip pushed the page to 1156px in
   a 1024px window): the strip's own content never sizes its column, and
   what does not fit is clipped, never scrolled sideways. */
.sb-strip { min-width: 0; max-width: 100%; overflow: hidden; contain: inline-size; }
.sb-block {
  flex: 1 1 0; min-width: 3px; min-height: 0; padding: 0; margin: 0;
  border: none; border-radius: 3px; cursor: pointer;
  background: var(--surface); box-shadow: inset 0 0 0 1px var(--border-strong);
}
.sb-block.is-moving {
  background: repeating-linear-gradient(135deg, var(--accent) 0 2px, var(--accent-tint) 2px 6px);
  box-shadow: inset 0 0 0 1px var(--accent);
}
.sb-block:hover, .sb-block:focus-visible { box-shadow: inset 0 0 0 2px var(--text-2); }
.sb-list { list-style: none; margin: var(--sp-6) 0 0; padding: 0; }
.sb-scene {
  padding: var(--sp-4) 0; border-bottom: 1px solid var(--border-subtle);
  scroll-margin-top: calc(var(--header-h) + 24px);
}
.sb-scene:last-child { border-bottom: none; }
.sb-head { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
.sb-said { margin-top: var(--sp-2); font-size: var(--fs-base); line-height: 1.6; color: var(--text); }
.sb-pic { margin-top: 6px; font-size: var(--fs-md); line-height: 1.55; color: var(--text-2); }
/* a scene's kind of picture, and the words a lettered picture will carry
   (docs/SHOT_KINDS.md §9.2). A kind's name is the model's, so it may wrap */
.sb-kind { white-space: normal; overflow-wrap: anywhere; max-width: 100%; }
.sb-words { margin-top: 4px; font-size: var(--fs-md); line-height: 1.55; color: var(--text); font-weight: 600; overflow-wrap: anywhere; }
.sb-sound { margin-top: 4px; font-size: var(--fs-sm); line-height: 1.5; color: var(--text-2); overflow-wrap: anywhere; }
.sb-scene .linkish { margin-top: 6px; }


/* =============================================================================
   15 · LISTS, ROWS AND TABLES (re-skinned; the page owners replace them)
   ============================================================================= */

/* --- a channel in the old left rail --- */
.chan {
  display: block; width: 100%; text-align: left;
  padding: 14px 16px 14px 13px;
  border-bottom: 1px solid var(--border-subtle);
  border-left: 3px solid transparent;
}
.chan:last-of-type { border-bottom: none; }
.chan:hover { background: var(--surface-2); }
.chan[aria-pressed="true"] { background: var(--accent-tint); border-left-color: var(--accent); }
.chan .cname { font-size: var(--fs-base); font-weight: 600; color: var(--text); }
.chan .cnum  { font-size: var(--fs-sm); color: var(--text-3); margin-top: 2px; }
.chan .cstyle { font-size: var(--fs-sm); color: var(--text-2); margin-top: var(--sp-2); line-height: 1.45; }

.chan-add {
  display: flex; align-items: center; gap: var(--sp-2); width: 100%;
  padding: 12px 16px; border-top: 1px solid var(--border-subtle);
  font-size: var(--fs-md); font-weight: 500; color: var(--accent-text);
}
.chan-add:hover { background: var(--surface-2); }

.chan-chip { display: inline-flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-sm); color: var(--text-2); }
a.chan-chip { text-decoration: none; }
a.chan-chip:hover, a.chan-chip:focus-visible { color: var(--text); text-decoration: underline; text-underline-offset: 3px; }
.dot { width: 8px; height: 8px; border-radius: 50%; background: var(--accent); flex: none; }

/* --- a piece of recent work --- */
.work { margin-top: var(--sp-4); }
.row {
  display: grid; grid-template-columns: 76px minmax(0, 1fr) 190px 120px;
  gap: var(--sp-4); align-items: center;
  padding: 14px 20px; border-bottom: 1px solid var(--border-subtle);
}
.row:last-child { border-bottom: none; }
.row .rt { font-size: var(--fs-md); font-weight: 600; color: var(--text); line-height: 1.4; overflow-wrap: anywhere; }
/* the title IS the way to the episode's page */
.rt-link { color: inherit; text-decoration: none; }
.rt-link:hover, .rt-link:focus-visible { text-decoration: underline; text-underline-offset: 3px; }
.table .rt-link { color: var(--accent-text); text-decoration: none; }
.table .rt-link:hover, .table .rt-link:focus-visible { text-decoration: underline; }
.row .rm { font-size: var(--fs-sm); color: var(--text-3); margin-top: 4px; }
.row .act { text-align: right; font-size: var(--fs-sm); color: var(--text-2); white-space: nowrap; }

/* --- EPISODES BY CHANNEL (owner, 2026-10-04): one group per channel on
       the Studio, one section per group on a channel's page --- */
.work-group + .work-group { border-top: 1px solid var(--border); }
.work-group-head {
  display: flex; flex-wrap: wrap; align-items: center; gap: 2px var(--sp-4);
  padding: 14px 20px; border-bottom: 1px solid var(--border-subtle);
  background: none;
}
.work-group-name { margin: 0; font-size: var(--fs-base); font-weight: 600; line-height: 1.3; }
.work-group-toggle {
  display: inline-flex; align-items: center; gap: var(--sp-2); padding: 0;
  font: inherit; color: var(--text); background: none; text-align: left;
}
.work-group-toggle:hover { color: var(--accent-text); }
.work-group-counts { flex: 1 1 200px; font-size: var(--fs-sm); color: var(--text-2); }
.work-group-more { padding: 6px 20px 16px; }
.work-sec + .work-sec { border-top: 1px solid var(--border); }
.work-sec-head { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 14px; padding: 18px 20px 4px; }
.work-sec-head h3 { margin: 0; font-size: var(--fs-base); font-weight: 600; color: var(--text); }
.work-sec-empty { padding: 4px 20px 18px; margin-top: 0; }
.row.work-row { grid-template-columns: 76px minmax(0, 1fr) minmax(0, 230px) minmax(0, auto); }
.work-row .act {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end;
  gap: var(--sp-2) var(--sp-4); white-space: normal;
}
.work-fix { display: block; margin-top: 6px; }
.work-play { padding: 0 20px 20px; }
/* max-height: an upright (9:16) film at 640px wide stood 1138px tall on an
   800px screen (measured 2026-10-11); 80vh keeps the whole film and its
   controls in view */
.work-play video { display: block; width: 100%; max-width: 640px; max-height: 80vh; border-radius: var(--r-md); background: var(--surface-3); }
.chan-counts { margin-top: 10px; }
.chan-counts .ghost { max-width: 100%; text-align: left; }
.chan-face { display: flex; gap: var(--sp-4); align-items: flex-start; }
.chan-face-words { flex: 1 1 auto; min-width: 0; }
.chan-tile {
  flex: none; width: 76px; height: 43px; border-radius: var(--r-sm);
  display: grid; place-items: center; object-fit: cover;
  background: var(--surface-3);
  font-size: var(--fs-md); font-weight: 600; color: var(--text-2);
}

/* object-fit: an upright (9:16) episode's poster was squashed sideways in
   this 16:9 box (measured 2026-10-11); `cover` shows its middle */
.thumb {
  width: 76px; height: 43px; border-radius: var(--r-sm); overflow: hidden;
  background: var(--surface-3); display: block;
  object-fit: cover;
}
.thumb-empty { display: grid; place-items: center; color: var(--text-3); }

.alt-list { list-style: none; margin: 0; padding: 0; }
.alt-list li {
  padding: 12px 0; border-bottom: 1px solid var(--border-subtle);
  font-size: var(--fs-md); line-height: 1.5; color: var(--text);
}
.alt-list li:last-child { border-bottom: none; padding-bottom: 0; }

/* THE TABLE (§3.16): horizontal rules only, sentence-case heads, numbers
   right-aligned with tabular figures */
.table { width: 100%; border-collapse: collapse; font-size: var(--fs-md); }
.table th {
  text-align: left; padding: 12px 16px;
  background: none; border-bottom: 1px solid var(--border-strong);
  font-family: var(--font-sans); font-size: var(--fs-sm); line-height: var(--lh-sm);
  font-weight: 600; color: var(--text-2);
  letter-spacing: normal; text-transform: none; white-space: normal;
}
.table td {
  padding: 12px 16px; border-bottom: 1px solid var(--border-subtle);
  color: var(--text); vertical-align: top;
}
.table tr:last-child td { border-bottom: none; }
.table tbody tr:hover td { background: var(--surface-2); }
/* a numeric COLUMN is right-aligned when its head and its cells both say
   so (.is-num); a legacy td.num whose head does not stays left, or the
   number would sit under nothing */
.table .is-num { text-align: right; }
.table td.num, .table td.mono {
  font-family: var(--font-sans); font-size: var(--fs-md);
  color: var(--text); font-variant-numeric: tabular-nums; white-space: nowrap;
}
.table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }

/* --- nothing here / loading --- */
.empty {
  padding: var(--sp-6) 0; font-size: var(--fs-md); color: var(--text-2);
  line-height: 1.6;
}
.empty.loading { color: var(--text-3); }

/* THE EMPTY STATE (§3.11): what will be here, and one action */
.empty-state {
  display: flex; flex-direction: column; align-items: center; gap: var(--sp-2);
  padding: 40px 24px; text-align: center;
}
.empty-state-icon {
  width: 48px; height: 48px; border-radius: var(--r-2xl);
  display: grid; place-items: center; margin-bottom: var(--sp-2);
  background: var(--surface-2); color: var(--text-3);
}
.empty-state-icon svg { width: 24px; height: 24px; }
.empty-state-title,
.empty-state > h2,
.empty-state > h3 {
  margin: 0; font-size: var(--fs-lg); line-height: var(--lh-lg); font-weight: 600; color: var(--text);
}
.empty-state-text,
.empty-state > p {
  margin: 0; max-width: 44ch;
  font-size: var(--fs-base); line-height: var(--lh-base); color: var(--text-2);
}
.empty-state > .btn-primary,
.empty-state > .btn-secondary,
.empty-state > .btn-quiet { margin-top: var(--sp-3); }

/* THE VIDEO CARD (§3.15): Library, a channel's Finished section */
.video-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: var(--sp-6);
}
.video-card { display: flex; flex-direction: column; gap: var(--sp-3); min-width: 0; }
.video-card-media {
  position: relative; display: block; overflow: hidden;
  aspect-ratio: 16 / 9; border-radius: var(--r-xl);
  background: var(--surface-3);
}
.video-card-media img {
  display: block; width: 100%; height: 100%; object-fit: cover;
  transition: transform var(--dur) var(--ease);
}
/* a 9:16 poster is shown whole on the placeholder ground, never cropped */
.video-card-media.is-upright img { object-fit: contain; }
.video-card:hover .video-card-media { box-shadow: var(--shadow-md); }
.video-card:hover .video-card-media img { transform: scale(1.02); }
/* no poster: the placeholder ground with a film glyph — never black */
.video-card-ph::before {
  content: ""; position: absolute; left: 50%; top: 50%;
  width: 32px; height: 32px; margin: -16px 0 0 -16px;
  background: var(--text-3);
  -webkit-mask: var(--glyph-film) center / contain no-repeat;
          mask: var(--glyph-film) center / contain no-repeat;
}
.video-card-dur {
  position: absolute; right: 8px; bottom: 8px;
  padding: 2px 6px; border-radius: var(--r-sm);
  background: var(--media-scrim); color: var(--on-media);
  font-size: var(--fs-xs); line-height: var(--lh-xs); font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.video-card-media .badge { position: absolute; left: 8px; top: 8px; }
.video-card-body { min-width: 0; }
.video-card-title {
  font-size: var(--fs-base); line-height: var(--lh-base); font-weight: 600;
  color: var(--text); text-decoration: none;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; overflow-wrap: anywhere;
}
.video-card-title:hover, .video-card-title:focus-visible { text-decoration: underline; text-underline-offset: 2px; }
.video-card-meta {
  margin-top: 2px; font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--text-3);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.video-card-actions { display: flex; align-items: center; gap: var(--sp-2); margin-top: var(--sp-2); }
@media (max-width: 560px) {
  .video-grid { gap: var(--sp-4); }
}
@media (max-width: 400px) {
  .video-grid { grid-template-columns: minmax(0, 1fr); }
}


/* =============================================================================
   16 · THE STEPPER (§3.8) — the base the wizard (B) and the episode (C) use
   Markup the phone test measures: .steps[role=list] > .step[role=listitem]
   with .pip and .step-sep. The current stage carries .on; a stopped, paused
   or failed one .is-stopped (plus .is-needs/.is-paused/.is-failed/
   .is-partial to say which); a finished one .done.
   ============================================================================= */

.steps { display: flex; align-items: center; gap: 0; flex-wrap: wrap; }
.step {
  display: flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-md); font-weight: 500; color: var(--text-3);
}
.step .pip {
  position: relative; flex: none;
  width: 24px; height: 24px; border-radius: var(--r-full);
  display: grid; place-items: center;
  background: var(--surface); box-shadow: inset 0 0 0 1.5px var(--border-strong);
  font-size: var(--fs-xs); font-weight: 600; color: var(--text-3);
}
.step .pip::after {
  content: none; position: absolute; inset: 5px;
  -webkit-mask: var(--glyph-check) center / contain no-repeat;
          mask: var(--glyph-check) center / contain no-repeat;
}
/* in progress (the wizard's current step, the episode's current stage) */
.step.on { color: var(--text); font-weight: 600; }
.step.on .pip { box-shadow: inset 0 0 0 2px var(--working-solid); color: var(--working-text); }
/* done: a filled circle with a check; the number stays for a screen reader */
.step.done { color: var(--text-2); }
.step.done .pip { background: var(--done-solid); box-shadow: none; color: transparent; }
.step.done .pip::after { content: ""; background: var(--on-solid); }
/* where a run stopped: neutral unless it says which kind */
.step.is-stopped { color: var(--text); font-weight: 600; }
.step.is-stopped .pip { background: var(--stopped-solid); box-shadow: none; color: transparent; }
.step.is-stopped .pip::after { content: ""; background: var(--on-solid); -webkit-mask-image: var(--glyph-stop); mask-image: var(--glyph-stop); }
.step.is-needs .pip { background: var(--needs-solid); box-shadow: none; color: transparent; }
.step.is-needs .pip::after { content: ""; background: var(--on-solid); -webkit-mask-image: var(--glyph-alert); mask-image: var(--glyph-alert); }
.step.is-paused .pip { background: var(--waiting-solid); box-shadow: none; color: transparent; }
.step.is-paused .pip::after { content: ""; background: var(--on-solid); -webkit-mask-image: var(--glyph-pause); mask-image: var(--glyph-pause); }
/* WAITING ITS TURN for the channel's pictures (studio.js EP_STAGE_CLASS
   `turn`, with .on so a narrow rail still names it): the waiting colour and a
   CLOCK, never the pause glyph — it goes on by itself (review of
   episodes-in-parallel, 2026-10-12) */
.step.is-turn .pip { background: var(--waiting-solid); box-shadow: none; color: transparent; }
.step.is-turn .pip::after { content: ""; background: var(--on-solid); -webkit-mask-image: var(--glyph-clock); mask-image: var(--glyph-clock); }
.step.is-failed .pip { background: var(--failed-solid); box-shadow: none; color: transparent; }
.step.is-failed .pip::after { content: ""; background: var(--on-solid); -webkit-mask-image: var(--glyph-x); mask-image: var(--glyph-x); }
.step.is-partial .pip { background: var(--surface); box-shadow: inset 0 0 0 2px var(--done-solid); color: transparent; }
.step.is-partial .pip::after { content: ""; background: var(--done-solid); -webkit-mask-image: var(--glyph-stop); mask-image: var(--glyph-stop); }
/* the state word under the current step */
.step-word { display: block; font-size: var(--fs-sm); font-weight: 400; color: var(--text-2); }
/* the connector: 2px, green once the step before it is done. It gives way
   before a step's name does. */
.step-sep {
  width: 32px; flex: 0 1 32px; min-width: 10px; height: 2px;
  border-radius: 1px; background: var(--border); margin: 0 var(--sp-2);
}
.step.done + .step-sep { background: var(--done-solid); }

/* THE EPISODE'S RAIL STAYS ON ONE LINE at every width that is not a phone:
   the circles, the current stage (and where a run stopped) named. */
@media (min-width: 561px) {
  .read-grid .steps { flex-wrap: nowrap; }
  .read-grid .step-sep { margin: 0 6px; }
  .read-grid .step:not(.on):not(.is-stopped) { font-size: 0; gap: 0; }
  .read-grid .step:not(.on):not(.is-stopped) .pip { font-size: var(--fs-xs); }
  .read-grid .step.done:last-child { font-size: var(--fs-md); gap: var(--sp-2); }
}
/* A NARROW RAIL KEEPS EVERY CIRCLE AND NAMES ONLY THE CURRENT STEP — plus
   the one a run stopped at, and the last step of a finished rail (UX review,
   2026-10-02). The other words stay in the page for a screen reader. */
@media (max-width: 940px) {
  .steps { flex-wrap: nowrap; }
  .step-sep { margin: 0 6px; }
  .step:not(.on):not(.is-stopped) { font-size: 0; gap: 0; }
  .step:not(.on):not(.is-stopped) .pip { font-size: var(--fs-xs); }
  .step.done:last-child { font-size: var(--fs-md); gap: var(--sp-2); }
}
/* …AND ON A PHONE THE RAIL WRAPS, WITH NO SEPARATORS: a separator is its
   own flex item, so a wrapped rail started its second row with one. */
@media (max-width: 560px) {
  .steps { flex-wrap: wrap; row-gap: var(--sp-2); column-gap: 10px; }
  .step-sep { display: none; }
}

/* --- the add-a-channel wizard (re-skinned; B rebuilds it) --- */
.learn { margin-top: var(--sp-5); padding-top: var(--sp-4); border-top: 1px solid var(--border-subtle); }
.learn-row { display: flex; justify-content: space-between; gap: 14px; align-items: baseline; flex-wrap: wrap; }
.learn-row .t { font-size: var(--fs-md); color: var(--text); }
.learn-row .c { font-size: var(--fs-sm); color: var(--text-3); font-variant-numeric: tabular-nums; }
.learn .meter { margin-top: var(--sp-3); }
.learn .calm { font-size: var(--fs-sm); color: var(--text-2); margin-top: 10px; line-height: 1.55; }

.choice-head { margin-top: var(--sp-8); font-size: var(--fs-base); color: var(--text); font-weight: 600; }
.choices { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3); margin-top: var(--sp-3); }
.choices.is-three { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.choice {
  text-align: left; padding: var(--sp-4); border-radius: var(--r-lg);
  background: var(--surface); border: 1px solid var(--border-strong);
  transition: background-color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.choice:hover { background: var(--surface-2); }
/* selected = a tint AND a ring AND a filled tick AND aria-pressed */
.choice[aria-pressed="true"] {
  background: var(--accent-tint); border-color: var(--accent);
  box-shadow: inset 0 0 0 .5px var(--accent);
}
.choice .ct { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-md); font-weight: 600; color: var(--text); }
.choice .cd { display: block; font-size: var(--fs-sm); color: var(--text-2); margin-top: 6px; line-height: 1.55; }
.choice[aria-pressed="true"] .cd { color: var(--text); }
.tick {
  width: 16px; height: 16px; border-radius: 50%; flex: none;
  display: grid; place-items: center;
  box-shadow: inset 0 0 0 1.5px var(--border-strong);
}
.choice[aria-pressed="true"] .tick { background: var(--accent); box-shadow: none; color: var(--on-accent); }
/* THE NEW-DIRECTION DIALOG'S OPTIONS (CAT.directionModal, 2026-10-11): the
   same option card, chosen by aria-checked in a radiogroup; one column, the
   reasons read top to bottom */
.choice[aria-checked="true"] {
  background: var(--accent-tint); border-color: var(--accent);
  box-shadow: inset 0 0 0 .5px var(--accent);
}
.choice[aria-checked="true"] .cd { color: var(--text); }
.choice[aria-checked="true"] .tick { background: var(--accent); box-shadow: none; color: var(--on-accent); }
/* WORDS ON SCREEN (captionPicker, channels.js): the five looks as option
   cards with their real picture on top, the colours as chips with a
   swatch, then where / how big, then the picture of the pick. The cards
   wrap to two a row on a phone; nothing scrolls sideways. */
.cap-picker .choice-head { margin-top: var(--sp-5); }
.cap-looks .cap-look { padding: var(--sp-2); min-width: 0; }
.cap-thumb, .cap-media {
  display: block; width: 100%; height: auto; border-radius: var(--r-md);
  background: var(--surface-3); margin-bottom: var(--sp-2);
}
.cap-look .ct { font-size: var(--fs-sm); }
.cap-colours { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-3); }
.cap-picker .seg { margin-top: var(--sp-3); }
.cap-swatch { box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .3); }
.choice-chip[aria-pressed="true"] .cap-swatch { box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .3); }
.cap-big { margin-top: var(--sp-4); max-width: 560px; }
@media (max-width: 560px) {
  .cap-looks { grid-template-columns: 1fr; }
}
.choices.dir-options { grid-template-columns: 1fr; }
.dir-option { width: 100%; }
.dir-option .cd + .cd { margin-top: 4px; }
.dir-option .dir-kind { font-weight: 600; }
.dir-intro { margin: 0; font-size: var(--fs-base); line-height: var(--lh-base); color: var(--text); }
/* PICK MORE THAN ONE (common.js directionModal): the toggle under the
   intro, the tick-box count, the confirmation's list of new channels and
   its "which one does this channel keep" group; a ticked card past the cap
   is drawn dimmed by .choice:disabled. Long niche names wrap (375px). */
.dir-many { margin-top: var(--sp-3); max-width: 100%; white-space: normal; text-align: left; }
.dir-count { margin: var(--sp-2) 0 0; }
.dir-option[role="checkbox"]:disabled { opacity: .55; cursor: not-allowed; }
.dir-option .dir-made { font-weight: 600; }
.dir-new-list { margin: var(--sp-2) 0 var(--sp-3); padding-left: 1.2em; overflow-wrap: anywhere; }
.dir-new-list li + li { margin-top: 4px; }
.dir-keeps-head { margin: var(--sp-4) 0 var(--sp-2); font-weight: 600; }
.dir-failed { color: var(--text); font-weight: 600; }
/* THE READING'S ONE PRICE CARD (CAT.readingCard): the import card's
   spacing, one line per part */
.reading-card { margin-top: var(--sp-4); }
.reading-card .callout-main > * + * { margin-top: var(--sp-2); }
.reading-card .alt-list li { padding: 6px 0; font-size: var(--fs-sm); overflow-wrap: anywhere; }
.reading-parts .alt-list li,
.alt-list.reading-parts-list li { padding: 6px 0; font-size: var(--fs-sm); overflow-wrap: anywhere; }

.wiz-foot {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4);
  padding: var(--sp-4) var(--card-pad) var(--card-pad);
  border-top: 1px solid var(--border-subtle);
  background: none; border-radius: 0 0 var(--r-xl) var(--r-xl);
}


/* =============================================================================
   17 · OVERLAYS — toasts (§3.12), the modal (§3.13), menus (§3.14)
   ============================================================================= */

.toasts {
  position: fixed; right: 24px; bottom: 24px; z-index: var(--z-toast);
  display: flex; flex-direction: column; gap: var(--sp-2);
  max-width: min(420px, calc(100vw - 48px));
}
/* A TOAST CAN BE CLOSED AND CANNOT COVER THE SCREEN (UX audit, 2026-10-02):
   capped at 40% of the viewport, its text scrolls, and it has a close
   button. A leading glyph says its kind; there is no coloured left rule. */
.toast {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 12px 8px 12px 16px; border-radius: var(--r-xl);
  background: var(--surface); border: 1px solid var(--border);
  box-shadow: var(--shadow-lg);
  font-size: var(--fs-md); color: var(--text); line-height: var(--lh-md);
  overflow-wrap: anywhere;
  max-height: 40vh;
  animation: cat-rise var(--dur) var(--ease);
}
.toast-glyph { flex: none; width: 16px; height: 16px; margin-top: 2px; color: var(--working-solid); }
.toast.ok    .toast-glyph { color: var(--done-solid); }
.toast.warn  .toast-glyph { color: var(--needs-solid); }
.toast.error .toast-glyph { color: var(--failed-solid); }
.toast-text { flex: 1 1 auto; min-width: 0; max-height: calc(40vh - 24px); overflow-y: auto; }
.toast-x {
  flex: 0 0 auto; display: inline-grid; place-items: center;
  width: 32px; height: 32px; min-height: 32px; margin: -6px 0 -6px 0;
  border-radius: var(--r-lg); color: var(--text-2);
}
.toast-x:hover { color: var(--text); background: var(--surface-2); }
.toast.out { opacity: 0; transition: opacity var(--dur) var(--ease); }

.modal-back {
  position: fixed; inset: 0; z-index: var(--z-modal);
  background: var(--overlay);
  display: grid; place-items: center; padding: var(--sp-4);
}
.modal {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-2xl); box-shadow: var(--shadow-lg);
  width: min(560px, calc(100vw - 32px)); max-height: calc(100vh - 64px); overflow: auto;
  animation: cat-rise var(--dur) var(--ease);
}
.modal.wide { width: min(880px, calc(100vw - 32px)); }
.modal-head {
  display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-4);
  padding: 20px var(--card-pad) 0;
  background: none; border: none; border-radius: 0;
}
.modal-head h2 {
  margin: 0; font-size: var(--fs-2xl); line-height: var(--lh-2xl); font-weight: 600;
  color: var(--text); overflow-wrap: anywhere;
}
.modal-head .icon-btn { margin: -6px -10px 0 0; }
.modal-body { padding: var(--sp-4) var(--card-pad); }
.modal-body:last-child { padding-bottom: var(--card-pad); }
/* actions right-aligned: primary rightmost, a destructive one far left */
.modal-foot {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end;
  gap: var(--sp-2); padding: var(--sp-4) var(--card-pad) var(--card-pad);
}
.modal-foot .btn-danger { margin-right: auto; }
/* AN EPISODE DONE, OR WAITING, WHILE YOU WERE ON ANOTHER PAGE (common.js
   newsShow): several are listed, each with its own "Open it", which wraps
   under its sentence on a phone */
.news-list li {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: var(--sp-2); overflow-wrap: anywhere;
}
.news-list li > span { flex: 1 1 12rem; min-width: 0; }
@media (max-width: 560px) {
  /* a bottom sheet */
  .modal-back { place-items: end center; padding: 0; }
  .modal, .modal.wide {
    width: 100%; max-height: 90vh;
    border-radius: var(--r-2xl) var(--r-2xl) 0 0;
    border-bottom: none;
  }
}

/* THE MENU (popover): the Admin menu, the avatar menu, Library's "⋯".
   Trigger has aria-expanded; Escape or a click outside closes it and
   returns focus to the trigger; the arrow keys move between items. */
.menu {
  position: absolute; z-index: var(--z-menu);
  display: flex; flex-direction: column; gap: 2px;
  min-width: 220px; padding: 6px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-xl); box-shadow: var(--shadow-lg);
  text-align: left;
  animation: cat-drop var(--dur) var(--ease);
}
.menu-item {
  display: flex; align-items: center; gap: var(--sp-2); width: 100%;
  min-height: 36px; padding: 0 10px; border-radius: var(--r-md);
  font-size: var(--fs-md); line-height: var(--lh-md); font-weight: 500;
  color: var(--text); text-decoration: none; text-align: left; white-space: nowrap;
  background: none; border: none;
}
.menu-item:hover, .menu-item:focus-visible { background: var(--surface-2); }
.menu-item > svg { flex: none; color: var(--text-3); }
.menu-sep { height: 1px; margin: 4px 0; background: var(--border-subtle); border: none; }
/* a menu built in groups (the avatar menu): a hairline between groups that
   hold something, none around an empty one */
.menu-group { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.menu-group:empty { display: none; }
.menu-group:not(:empty) ~ .menu-group:not(:empty) {
  margin-top: 4px; padding-top: 4px; border-top: 1px solid var(--border-subtle);
}
.menu-slot { display: contents; }
.menu-id {
  gap: 4px; padding: 8px 10px;
  font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--text-2);
  white-space: normal;
}
.menu-id .badge { align-self: flex-start; }
.menu-note { padding: 4px 10px 8px; font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--text-2); white-space: normal; }


/* =============================================================================
   17a · A's PAGES (docs/UI_REDESIGN.md §4.4–§4.7) — the Library, Spend,
   Settings, People and the sign-in card. Page variants only, built from the
   tokens and the primitives above; every page's own class is prefixed
   (.lib-*, .spend-*, .set-*, .people-*, .signin-*).
   ============================================================================= */

/* --- THE LIBRARY (§4.4): one filter row, then the video-card grid --- */
.lib-filters {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--sp-3); margin-bottom: var(--sp-6); min-width: 0;
}
.lib-search { position: relative; flex: 1 1 260px; min-width: 0; }
.lib-search > svg {
  position: absolute; left: 12px; top: 50%; transform: translateY(-50%);
  color: var(--text-3); pointer-events: none;
}
.lib-search input { width: 100%; padding-left: 36px; }
.lib-filters > select { flex: 0 1 220px; min-width: 0; }
.lib-count { margin-left: auto; white-space: nowrap; }
.lib-count:empty { display: none; }
.lib-stale { margin-bottom: var(--sp-6); }

/* a script or a storyboard: no video, so its glyph on the placeholder
   ground and the badge's words say so */
.lib-ph { display: grid; place-items: center; color: var(--text-3); }
.lib-badge { max-width: calc(100% - 16px); white-space: normal; text-align: left; }
.video-card-title { display: block; }
.video-card-title:hover, .video-card-title:focus-visible { color: var(--text); }
/* the meta line: the channel's name gives way first, the date and the cost
   never do */
.lib-meta { display: flex; align-items: baseline; min-width: 0; }
.lib-meta > * { flex: none; white-space: pre; }
.lib-meta > .lib-chan { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lib-chan { color: inherit; text-decoration: none; }
.lib-chan:hover, .lib-chan:focus-visible { color: var(--text); text-decoration: underline; text-underline-offset: 2px; }
.video-card-actions .btn-secondary { gap: 6px; }

/* the "⋯" menu, anchored under its trigger at the card's right */
.lib-more { position: relative; margin-left: auto; }
.lib-menu { right: 0; top: calc(100% + 4px); }
.lib-trash { color: var(--failed-text); }
.lib-trash > svg { color: var(--failed-solid); }
.lib-ask {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2);
  margin: 0; padding: 6px 10px; white-space: normal;
  /* a set width, so the menu holding the ask widens to it rather than
     wrapping the question and the Trash sentence into a tall column; never
     wider than a phone leaves room for */
  width: min(300px, calc(100vw - 64px)); max-width: 300px;
}
.lib-ask .hint { flex: 1 1 100%; margin: 0; color: var(--text); }
/* what the Trash is and how to undo it, under the question, before the Yes */
.lib-ask .lib-ask-note { color: var(--text-2); font-size: var(--fs-sm); line-height: var(--lh-sm); }

/* "Other files…" */
.lib-dialog .lib-sec + .lib-sec,
.lib-dialog .lib-sec + .hint,
.lib-dialog .hint + .lib-sec { margin-top: var(--sp-5); }
.lib-sec-title { margin: 0 0 var(--sp-2); font-size: var(--fs-md); line-height: var(--lh-md); font-weight: 600; color: var(--text); }
.lib-sec p { margin: 0; }
.lib-sec p + p, .lib-sec p.hint { margin-top: var(--sp-2); }
.lib-files { list-style: none; margin: 0 -10px; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.lib-file {
  display: flex; align-items: center; gap: var(--sp-2);
  min-height: 36px; padding: 0 10px; border-radius: var(--r-md);
  color: var(--text); text-decoration: none; font-size: var(--fs-md);
  transition: background-color var(--dur-fast) var(--ease);
}
.lib-file:hover, .lib-file:focus-visible { background: var(--surface-2); }
.lib-file > svg { flex: none; color: var(--text-3); }
.lib-facts { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 4px var(--sp-4); margin: 0; }
.lib-facts > div { display: contents; }
.lib-facts dt { font-size: var(--fs-sm); color: var(--text-2); }
.lib-facts dd { margin: 0; font-size: var(--fs-md); color: var(--text); overflow-wrap: anywhere; }
.lib-sec .code { display: inline-block; margin: 0 4px 4px 0; }

/* --- SPEND (§4.5): three tiles, the episodes, then the folds --- */
.spend-tiles {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--sp-6); align-items: stretch;
}
.spend-tile { padding: 20px var(--card-pad); display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.spend-tile-k { font-size: var(--fs-sm); line-height: var(--lh-sm); font-weight: 600; color: var(--text-2); }
.spend-figure {
  font-size: var(--fs-5xl); line-height: var(--lh-5xl); font-weight: 700;
  color: var(--text); letter-spacing: -0.01em; overflow-wrap: anywhere;
  font-variant-numeric: tabular-nums;
}
.spend-tile-words {
  font-size: var(--fs-xl); line-height: var(--lh-xl); font-weight: 600;
  color: var(--text); overflow-wrap: anywhere;
}
.spend-tile-note { font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--text-2); }
.spend-ep-meta { margin-top: 2px; }
.card-table { padding: var(--sp-3) 0 var(--sp-2); }
.card-table .table th:first-child, .card-table .table td:first-child { padding-left: var(--card-pad); }
.card-table .table th:last-child, .card-table .table td:last-child { padding-right: var(--card-pad); }
.spend-folds { padding: 4px var(--card-pad) 8px; }
.spend-folds > .fold:first-child { border-top: none; }
.spend-sec-title { margin: var(--sp-4) 0 var(--sp-2); font-size: var(--fs-md); line-height: var(--lh-md); font-weight: 600; color: var(--text); }
.spend-breakdown:first-child .spend-sec-title,
.spend-why .spend-sec-title { margin-top: var(--sp-3); }
.spend-breakdown .table-wrap { margin: 0 calc(var(--sp-4) * -1); }
/* a fold that is also a panel (#spend-time: the tests read it by id) wears
   the fold, not the card */
.fold.panel {
  background: none; border: 0; border-top: 1px solid var(--border-subtle);
  border-radius: 0; box-shadow: none;
}
@media (max-width: 560px) {
  .lib-filters { gap: var(--sp-2) var(--sp-3); }
  .lib-search { flex-basis: 100%; }
  .lib-filters > select { flex: 1 1 0; }
  .lib-count { flex-basis: 100%; margin-left: 0; }
}

@media (max-width: 940px) {
  .spend-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .spend-tiles > :first-child { grid-column: 1 / -1; }
}
@media (max-width: 560px) {
  .spend-tiles { grid-template-columns: minmax(0, 1fr); gap: var(--sp-4); }
  .spend-figure { font-size: var(--fs-4xl); line-height: var(--lh-4xl); }
}

/* --- SETTINGS (§4.6): a section nav beside the content --- */
.set-layout {
  display: grid; grid-template-columns: 200px minmax(0, 1fr);
  gap: var(--sp-8); align-items: start;
}
.set-nav {
  position: sticky; top: calc(var(--header-h) + 24px);
  display: flex; flex-direction: column; gap: 2px; min-width: 0;
}
.set-nav a {
  display: flex; align-items: center; min-height: 36px; padding: 0 12px;
  border-radius: var(--r-lg);
  font-size: var(--fs-md); line-height: var(--lh-md); font-weight: 500;
  color: var(--text-2); text-decoration: none;
  transition: background-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.set-nav a:hover { color: var(--text); background: var(--surface-2); }
.set-nav a[aria-current="true"] { background: var(--accent-tint); color: var(--accent-text); font-weight: 600; }
.set-main { display: flex; flex-direction: column; gap: var(--sp-10); min-width: 0; }
.set-sec { display: flex; flex-direction: column; gap: var(--sp-6); min-width: 0; }
.set-sec-title { margin: 0; font-size: var(--fs-xl); line-height: var(--lh-xl); font-weight: 600; color: var(--text); }
.set-main [id^="set-"], .set-main [id^="key-"] { scroll-margin-top: calc(var(--header-h) + 16px); }
.set-card .panel-head .label:first-child { flex: 1 1 auto; }
.set-count { font-weight: 500; color: var(--text-3); }
.set-purpose { margin: 0; font-size: var(--fs-base); line-height: var(--lh-base); color: var(--text-2); }
.set-warn { color: var(--text); }
.set-how, .set-why { margin-top: var(--sp-5); }
.set-how p, .set-why p { margin: 0; font-size: var(--fs-md); line-height: 1.6; color: var(--text-2); max-width: 72ch; }
.set-how p + p, .set-why p + p { margin-top: var(--sp-3); }
.set-all > .fold-body { padding-top: var(--sp-2); }
/* "IF THE MODEL FOR “…” FAILS, TRY NEXT" under each writing job's picker (docs/SELF_REPAIR.md
   §11.2): the models in the order CAT tries them, each picker with Move up /
   Move down / Remove beside it, wrapping under it on a phone */
/* A JOB'S OWN LIST, SET IN UNDER IT: a rule down its left, never the
   divider the jobs themselves are drawn between — the same line made
   it read as a fourth job (review, 2026-10-12) */
.set-chain { margin-top: var(--sp-2); padding: var(--sp-1) 0 var(--sp-1) var(--sp-4);
             border-left: 2px solid var(--border-subtle); }
.set-chain:focus { outline: none; }
.set-chain:focus-visible { box-shadow: 0 0 0 3px var(--focus-halo); }
.set-chain > .t { font-size: var(--fs-md); line-height: var(--lh-md); font-weight: 500; color: var(--text); }
.set-chain-list { margin: var(--sp-2) 0 0; padding-left: 20px; display: flex; flex-direction: column; gap: var(--sp-3); }
.set-chain-list > li { min-width: 0; }
/* THE PICKER'S WORDS STAY INSIDE IT: WebKit lays a menu's chosen words out
   past the menu's own edge, and a model with a long name ("Practice writer
   for the script and the review") pushed Settings to 379px on a 375px
   phone (measured, tests/test_self_repair_screens.py). The menu clips them;
   the row never moves. */
.set-chain-list .select-shell, .set-chain-add .select-shell { max-width: 420px; min-width: 0; }
.set-chain .select-shell select { overflow: hidden; text-overflow: ellipsis; }
.set-chain-moves, .set-chain-add { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1) var(--sp-2); margin-top: var(--sp-1); }
.set-chain-add { margin-top: var(--sp-2); }
.set-chain-add > .select-shell { flex: 1 1 220px; min-width: 0; }
/* A LISTED MODEL CAT CANNOT USE IS GREYED ON THE CONTROL ITSELF (§7.4 rule
   12) — a ground and a dashed edge, never colour alone; its reason is the
   line under it. `.select-shell` sets its own ground after `.unavailable`
   at the same weight and won: both pickers read rgb(255,255,255) (measured
   by review 2026-10-12, round 2). */
.select-shell.unavailable { background: var(--surface-2); border-style: dashed; }
@media (max-width: 940px) {
  .set-layout { grid-template-columns: minmax(0, 1fr); gap: var(--sp-6); }
  /* the tabs wrap; they never scroll out of sight */
  .set-nav {
    position: static; flex-direction: row; flex-wrap: wrap; gap: var(--sp-2);
    padding-bottom: var(--sp-3); border-bottom: 1px solid var(--border);
  }
}


/* --- PEOPLE, WRITING INSTRUCTIONS, CHANNEL STYLE (§4.7): the folds sit
       under what they explain; the month picker or "Add a person" is the
       page's one action --- */
.doc-fold, .set-details { margin-top: var(--sp-4); }
.people-fields { display: flex; flex-direction: column; gap: 18px; max-width: 560px; }
.people-rest { margin: 0; }
/* a chip in a table cell keeps its word: the column grows to it, never
   cuts "admin" to "a…" */
.table .chip-word { min-width: auto; overflow: visible; white-space: nowrap; }
.page-actions > select { flex: 0 1 220px; min-width: 0; }
@media (max-width: 560px) {
  .page-actions > select { flex: 1 1 100%; }
}

/* --- SIGN IN (§4.7): one centred card --- */
.signin { display: flex; justify-content: center; padding-top: 15vh; }
.signin-card {
  width: 100%; max-width: 400px; padding: var(--sp-8) var(--card-pad);
  display: flex; flex-direction: column; gap: var(--sp-4);
}
.signin-card h1 {
  margin: 0 0 var(--sp-2);
  font-size: var(--fs-2xl); line-height: var(--lh-2xl); font-weight: 600; color: var(--text);
}
.signin-mark { color: var(--text); }
.signin-mark .mark-dot { fill: var(--accent); }
.signin-card .field { margin-top: 0; }
.signin-card input { width: 100%; }
.signin-card .btn-primary { margin-top: var(--sp-2); }
.signin-error:empty { display: none; }
@media (max-width: 560px) {
  .signin { padding-top: var(--sp-8); }
  .signin-card { padding: var(--sp-6) var(--card-pad); }
}

/* =============================================================================
   18 · RESPONSIVE
   Breakpoints: 560px (phone, checked at 375), 940px (tablet: the nav is the
   Menu, two columns become one), 1280px (wide). No horizontal scroll at 375.
   ============================================================================= */

@media (max-width: 940px) {
  .deck-2, .read-grid { grid-template-columns: minmax(0, 1fr); }
  .rail-col { position: static; }

  /* the decision comes back ABOVE the prose on a phone — as a SLIM bar, so
     the person still scrolls through the script. Never the panel above
     unread text. */
  .sticky-approve {
    display: flex; gap: 10px; align-items: center;
    position: sticky; top: calc(var(--header-h) + 8px); z-index: 5;
    margin: var(--sp-5) 0 -10px; padding: 10px;
    border: 1px solid var(--border); border-radius: var(--r-xl);
    background: var(--surface); box-shadow: var(--shadow-md);
  }
  .sticky-approve .btn-approve { flex: 1; }
  .sticky-approve .btn-secondary { width: auto; margin: 0; white-space: nowrap; }

  /* ONE FILLED ACTION ON SCREEN: on a phone the PINNED BAR is the decision;
     the panel below repeats it for somebody who has scrolled past, so the
     repeat wears the secondary treatment. */
  .rail-col .btn-approve {
    background: var(--surface); color: var(--text);
    border-color: var(--border-strong); box-shadow: none;
  }
  .rail-col .btn-approve:hover { background: var(--surface-2); }

  .reader { padding: 32px 24px 40px; }
  .row { grid-template-columns: 76px minmax(0, 1fr); gap: var(--sp-3) var(--sp-4); }
  .row .state { grid-column: 2; }
  .row .act { grid-column: 2; text-align: left; }
  .row.work-row { grid-template-columns: 76px minmax(0, 1fr); }
  .work-row .act { justify-content: flex-start; }
}

@media (max-width: 560px) {
  .reader { padding: 24px 16px 32px; }
  .prose { font-size: 1.0625rem; line-height: 1.75; }
  .title { font-size: var(--fs-2xl); line-height: var(--lh-2xl); }
  .choices, .choices.is-three { grid-template-columns: 1fr; }
  .readout { padding: 12px 16px; }
  .readout .cell { flex: 1 1 100%; }
  .readout .adjust { margin-left: 0; }
  .go-row { gap: var(--sp-3); }
  /* primary buttons at a phone's width are full-width (§3.4) */
  .btn-primary { width: 100%; }
  .quiet-links { width: 100%; justify-content: space-between; }
  .row { grid-template-columns: 60px minmax(0, 1fr); padding: 12px 16px; }
  .row.work-row { grid-template-columns: 60px minmax(0, 1fr); }
  .thumb { width: 60px; height: 34px; }
  .work-group-head, .work-sec-head { padding-left: 16px; padding-right: 16px; }
  .work-sec-empty, .work-group-more, .work-play { padding-left: 16px; padding-right: 16px; }
  .chan-tile { width: 60px; height: 34px; }
  .toasts { right: 12px; left: 12px; bottom: 12px; max-width: none; }
  /* inputs at 16px stop iOS zooming the page on focus */
  input[type="text"], input[type="email"], input[type="password"], input[type="search"],
  input[type="url"], input[type="number"], input[type="tel"], input:not([type]),
  .input, select, .select, textarea, .textarea, .notefield, .ask,
  .input-shell input, .select-shell select { font-size: var(--fs-lg); }
}

/* 390px is the owner's phone. Everything that can outgrow its column is
   capped here: a long channel URL and an un-wrapped run id were the two
   things that slid the page sideways. */
@media (max-width: 400px) {
  .readbar { gap: var(--sp-2) var(--sp-4); }
  .screen-tag { gap: var(--sp-2); }
  .mono, .row .rm, .chan .cnum, .found-num { overflow-wrap: anywhere; }
  .quiet-links { gap: var(--sp-3); }
  .mark .wordmark { font-size: var(--fs-md); }
}

/* The export dialog's destination field grows to fill its row and drops
   the button underneath when there is no room. */
.export-row { align-items: stretch; margin-top: var(--sp-2); gap: var(--sp-3); }
.export-row .export-dest { flex: 1 1 240px; min-width: 0; }

/* ON A TOUCH SCREEN every button, link-button, summary and choice is a 44px
   target (§3.4, §7.5) — written last, so it outranks each control's own
   desktop height. A link inside a sentence keeps the line's height. */
@media (pointer: coarse) {
  button,
  [role="button"],
  summary,
  select,
  .nav a,
  .nav-admin-toggle,
  .nav-toggle,
  .mark,
  .linkish,
  .link,
  .quiet,
  .ghost,
  .btn-primary,
  .btn-approve,
  .btn-secondary,
  .btn-quiet,
  .btn-back,
  .btn-danger,
  .btn-sm,
  .seg > button,
  .choice-chip,
  .menu-item,
  .adjust,
  .chan,
  .chan-add,
  .choice {
    min-height: 44px;
  }
  .icon-btn, .toast-x, .avatar-btn { min-width: 44px; min-height: 44px; }
  .avatar-btn { width: 44px; height: 44px; }
  .bell-btn { width: 44px; height: 44px; }
  .linkish, .link { display: inline-flex; align-items: center; }
  .hint .ghost, .hint button.ghost, .hint .linkish, .hint .link,
  .table button, .readbar button, .sb-block { min-height: 0; }
  .hint .linkish, .hint .link { display: inline; }
}

/* Print: the script is a thing people print and read on paper. */
@media print {
  .chrome, .nav, .rail-col, .sticky-approve, .toasts, .openwork, .stale, .as-strip { display: none !important; }
  body { background: white; color: black; }
  .panel, .card { border: none; box-shadow: none; }
  .prose { max-width: none; font-size: 12pt; }
}

/* A SCRIPT LINE A PERSON CAN POINT AT (studio.js prose, both reads), only
   while the rail's "Point at a line" is pressed; otherwise the script is
   plain, selectable text. Each line is then an <a role="button"> — it wraps
   with the text, where a <button> is always one box — so a keyboard reaches
   it, drawn as the text it is, same serif, same measure, until it is
   hovered or focused (the focus ring is the global :focus-visible one). A
   line that already carries a note keeps a dotted underline in either
   state, always beside its "Line n" chip in the rail, never colour alone. */
.prose .line-pick {
  font: inherit; color: inherit; line-height: inherit; letter-spacing: inherit;
  text-decoration: none; background: none; cursor: pointer;
  border-radius: 2px;
}
.prose .line-pick:hover { background: var(--surface-2); box-shadow: 0 0 0 2px var(--surface-2); }
.prose .line-pick.picked, .prose .line-picked {
  text-decoration: underline dotted var(--accent);
  text-underline-offset: 3px;
}
.line-pick-bar { margin: 0 0 12px; }
.line-pick-bar .hint { margin-top: 4px; }
.line-notes { list-style: none; margin: 6px 0 12px; padding: 0; }
.line-chip {
  margin: 0 0 10px; padding: 8px 10px;
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--surface-2);
}
.line-chip-head { font-size: var(--fs-md); line-height: 1.45; margin-bottom: 6px; overflow-wrap: anywhere; }
.line-chip .notefield { width: 100%; min-height: 0; }

/* ===== B · STUDIO HOME, COMPOSER, CHANNELS (redesign 2026-10-11) ===== */
/* docs/UI_REDESIGN.md §4.1 (the Studio home) and §4.3 (Channels, a
   channel's page, the wizard, the scan page). Tokens and §3 class names
   only; page variants are prefixed .home-* and .job-*. Later rules win, so
   this section overrides A's base for these pages without touching it. */

/* ---- THE STUDIO, CHANNEL FIRST (docs/STUDIO_CHANNEL_FIRST.md) --------- */
/* Two rooms, one column each — there is no side column on the home (owner,
   2026-10-20: "right box is so confusing"). / is the CHOOSER: a grid of
   channel cards (.chooser-*), then Tonight. /?channel=<slug> is that
   channel's WORKSPACE (.ws-*): its header, the New episode form when
   opened, then Needs you, Being made, Finished, Ideas. Tokens only. */

/* the chooser: one card per channel, the whole card one link */
.chooser { margin-bottom: var(--sp-6); }
.chooser-grid {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: var(--sp-4); align-items: stretch;
}
.chooser-card {
  position: relative; display: flex; flex-direction: column; gap: var(--sp-3);
  padding: var(--sp-5); min-width: 0; margin: 0;
  transition: box-shadow var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.chooser-card:hover { border-color: var(--border-strong); box-shadow: var(--shadow-md); }
/* the keyboard's ring goes round the card the link stands for (the
   link keeps its own ring too, for an engine without :has) */
.chooser-card:has(.chooser-link:focus-visible) { outline: 2px solid var(--focus); outline-offset: 2px; }
.chooser-top { display: grid; grid-template-columns: 96px minmax(0, 1fr); gap: var(--sp-4); align-items: center; }
.chooser-face.chan-row-face { width: 96px; height: 54px; border-radius: var(--r-md); }
.chooser-face .chan-row-face-tile { font-size: var(--fs-lg); }
.chooser-id { min-width: 0; }
.chooser-name { margin: 0; font-size: var(--fs-lg); line-height: var(--lh-lg); font-weight: 600; overflow-wrap: anywhere; }
.chooser-link { color: var(--text); text-decoration: none; }
/* STRETCHED: the name's link covers the card, so a click anywhere opens it */
.chooser-link::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }
.chooser-last { margin-top: 2px; }
.chooser-what { margin: 2px 0 0; font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--text-2); overflow-wrap: anywhere; }
.chooser-eps { margin: 2px 0 0; font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--text-3); }
.chooser-say { border-top: 1px solid var(--border-subtle); padding-top: var(--sp-3); margin-top: auto; }
.chooser-add {
  justify-content: center; align-items: flex-start;
  border: 1px dashed var(--border); border-radius: var(--r-xl); background: transparent;
}
.chooser-add-link {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-base); font-weight: 600; color: var(--accent-text);
}
.chooser-add:hover { background: var(--accent-tint); }

/* one chip-and-sentence line (a channel's state), read-only */
.ws-say { display: flex; align-items: flex-start; gap: var(--sp-2); min-width: 0; }
.ws-say > .status { flex: none; }
.ws-say-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.ws-say-main { font-size: var(--fs-md); line-height: var(--lh-md); font-weight: 500; color: var(--text); overflow-wrap: anywhere; }
.ws-say-sub { font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--text-2); overflow-wrap: anywhere; }

/* the workspace header: the way back, then face · name · the one primary */
.ws-head { margin: var(--sp-2) 0 var(--sp-6); display: flex; flex-direction: column; gap: var(--sp-3); }
.ws-back {
  display: inline-flex; align-items: center; gap: 6px; align-self: flex-start;
  font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--text-2); text-decoration: none;
}
.ws-back:hover, .ws-back:focus-visible { color: var(--text); text-decoration: underline; }
.ws-head-row { display: grid; grid-template-columns: 128px minmax(0, 1fr) auto; gap: var(--sp-5); align-items: center; }
.ws-face.chan-row-face { width: 128px; height: 72px; }
.ws-id { min-width: 0; display: flex; flex-direction: column; gap: var(--sp-1); }
.ws-name {
  margin: 0; font-size: var(--fs-3xl); line-height: var(--lh-3xl); font-weight: 600;
  letter-spacing: -0.01em; color: var(--text); overflow-wrap: anywhere;
}
.ws-what { margin: 0; font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--text-2); overflow-wrap: anywhere; }
.ws-head-say { margin-top: var(--sp-1); }
.ws-who { margin: 0; }
.ws-actions { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: var(--sp-2); }
.ws-switch-wrap { display: inline-flex; min-width: 0; }
.ws-switch { max-width: 220px; }
.ws-chan-link { text-decoration: none; gap: 4px; }

/* the form, under the header, when New episode opened it */
.ws-new { margin-bottom: var(--sp-6); }
.ws-new[hidden] { display: none; }
.home-new-head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); }

/* the four sections: a heading with its count, then rows or cards */
.ws-sections { display: flex; flex-direction: column; gap: var(--sp-8); min-width: 0; }
.ws-sec { min-width: 0; }
.ws-sec-head { display: flex; align-items: baseline; gap: var(--sp-2); margin: 0 0 var(--sp-3); }
.ws-sec-title { margin: 0; font-size: var(--fs-xl); line-height: var(--lh-xl); font-weight: 600; color: var(--text); }
.ws-sec-count {
  min-width: 22px; padding: 0 7px; border-radius: var(--r-full);
  background: var(--surface-2); color: var(--text-2); text-align: center;
  font-size: var(--fs-sm); line-height: var(--lh-sm); font-weight: 600; font-variant-numeric: tabular-nums;
}
.ws-sec-count:empty { display: none; }
.ws-needs .ws-sec-count { background: var(--needs-bg); color: var(--needs-text); }
.ws-sec-body {
  border: 1px solid var(--border); border-radius: var(--r-xl); background: var(--surface);
  overflow: hidden; min-width: 0;
}
.ws-sec-body > .row.job-row:first-child,
.ws-sec-body > .ws-making-item:first-child > .row.job-row { border-top: none; }
/* Finished holds cards, not rows: no box round the grid */
.ws-finished .ws-sec-body { border: none; background: transparent; overflow: visible; }
.ws-empty { margin: 0; padding: var(--sp-4); font-size: var(--fs-md); line-height: var(--lh-md); color: var(--text-3); }
.ws-finished .ws-empty { padding: var(--sp-4) 0; }
.ws-also { margin: 0; padding: var(--sp-3) var(--sp-4); border-top: 1px solid var(--border-subtle);
  font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--text-2); }
.ws-making-item + .ws-making-item { border-top: 1px solid var(--border-subtle); }
.ws-making-item > .row.job-row { border-top: none; }
.ws-stages { margin: 0; padding: 0 var(--sp-4) var(--sp-3) calc(var(--sp-4) + 40px + var(--sp-3)); }
.ws-stages > summary { font-size: var(--fs-sm); }
.ws-stages .timeline-list { margin: var(--sp-2) 0 0; padding-left: var(--sp-5); }
.ws-grid { gap: var(--sp-5); }
.ws-done .video-card-actions { flex-wrap: wrap; }
.ws-done-more { display: flex; flex-wrap: wrap; gap: 2px var(--sp-3); margin-top: var(--sp-2); }
.ws-door { font-size: var(--fs-sm); line-height: var(--lh-sm); }
.ws-foot { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--sp-2) var(--sp-4); margin-top: var(--sp-4); }
.ws-foot .work-group-more { padding: 0; }
.ws-lib { display: inline-flex; align-items: center; gap: 4px; font-size: var(--fs-sm); }
.ws-ended { margin-top: var(--sp-6); border: 1px solid var(--border); border-radius: var(--r-xl); background: var(--surface); overflow: hidden; }
.ws-ended > .work-sub-title { padding-top: var(--sp-3); }
.ws-ideas-find {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: var(--sp-2) var(--sp-4); padding: var(--sp-4);
}
.ws-ideas-find .home-help { flex: 1 1 260px; }
.ws-ideas-find + .row.job-row { border-top: 1px solid var(--border-subtle); }

@media (max-width: 940px) {
  .ws-head-row { grid-template-columns: 96px minmax(0, 1fr); }
  .ws-head .ws-face.chan-row-face { width: 96px; height: 54px; }
  .ws-actions { grid-column: 1 / -1; justify-content: flex-start; }
}
@media (max-width: 560px) {
  /* the Channels card names its face's grid area on a phone; these grids
     have no such area, so the face takes its own place in order */
  .ws-face.chan-row-face, .chooser-face.chan-row-face { grid-area: auto; }
  .chooser-grid { grid-template-columns: minmax(0, 1fr); gap: var(--sp-3); }
  .chooser-card { padding: var(--sp-4); }
  .chooser-top { grid-template-columns: 64px minmax(0, 1fr); gap: var(--sp-3); }
  .chooser-face.chan-row-face { width: 64px; height: 64px; }
  .ws-head-row { grid-template-columns: 56px minmax(0, 1fr); gap: var(--sp-3); }
  /* .ws-head in front: the Channels card's phone rule (.chan-row-face.has-poster,
     64px, later in this file) won over this one and pushed a channel with a
     poster 8px into its name (polish round, 2026-10-22) */
  .ws-head .ws-face.chan-row-face { width: 56px; height: 56px; align-self: start; margin-top: 4px; }
  .ws-name { font-size: var(--fs-2xl); line-height: var(--lh-2xl); }
  .ws-actions > .btn-primary { flex: 1 1 100%; justify-content: center; }
  .ws-switch-wrap, .ws-switch { flex: 1 1 auto; max-width: 100%; }
  .ws-sections { gap: var(--sp-6); }
  .ws-stages { padding-left: var(--sp-3); }
}

/* the composer card: one column of fields, 20px between groups */
.home-form { display: flex; flex-direction: column; gap: var(--sp-5); min-width: 0; }
.home-form > * { margin-top: 0; }
.home-form .field { margin-top: 0; }
.home-field { display: flex; flex-direction: column; gap: var(--sp-2); min-width: 0; }
.home-field > label,
.home-label {
  font-size: var(--fs-md); line-height: var(--lh-md); font-weight: 500; color: var(--text);
  margin: 0;
}
.home-help {
  margin: 0; font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--text-2);
}
.home-sub {
  display: flex; align-items: center; gap: var(--sp-2);
  margin: var(--sp-5) 0 0; font-size: var(--fs-md); line-height: var(--lh-md);
  font-weight: 600; color: var(--text);
}

/* the chosen channel's one line: a chip, then the words */
.home-chan-line {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1) var(--sp-2);
  font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--text-2);
}
.home-chan-words { min-width: 0; overflow-wrap: anywhere; }
.home-chan-bar { flex: 1 1 100%; max-width: 240px; }

/* the start choice: the segmented control and its one line */
.home-starts { align-self: flex-start; }
/* four starts (Auto, Paste a script, Short film - no voice, ...) are wider
   than a phone: they wrap onto a second row rather than push the card out */
@media (max-width: 560px) {
  .home-starts { flex-wrap: wrap; }
  .home-starts > button { flex: 1 1 auto; padding: 0 10px; }
}

/* the script box: big, but never taller than the screen */
.home-script {
  display: block; width: 100%; min-height: 280px; max-height: 60vh; resize: vertical;
}
.home-form #studio-steer { width: 100%; }
.home-count { margin-top: calc(-1 * var(--sp-3)); }
.home-count:empty { display: none; }
.home-count .hint { display: flex; align-items: flex-start; gap: 6px; }
.home-count .hint > svg { flex: none; margin-top: 3px; color: var(--needs-solid); }
.home-keys { margin-top: calc(-1 * var(--sp-3)); color: var(--text-3); }
.home-form > .field-error { margin-top: calc(-1 * var(--sp-2)); }
.home-form-err:empty { display: none; }

/* "Episode settings": one row that reads like a sentence */
.home-settings { margin-top: 0; border-bottom: 1px solid var(--border-subtle); }
.home-settings > summary { padding: 14px 0; }
.home-settings .ep-fold-k {
  font-size: var(--fs-md); font-weight: 500; color: var(--text);
}
.home-settings .ep-fold-v { color: var(--text-2); }
.home-settings .ep-fold-v:not(:empty)::before { content: "· "; color: var(--text-3); }
.home-settings[open] { padding-bottom: var(--sp-4); }
.home-settings .fold-body > .readout:first-child { margin-top: 0; }
.home-settings .readout + .readout-note { margin-top: var(--sp-2); }
.home-settings .found { margin-top: var(--sp-4); }

/* "Before you start": one compact callout, a sentence and its fix a line */
.home-before .callout-icon { color: var(--waiting-solid); }
.home-before .callout-icon svg { width: 16px; height: 16px; }
.home-before-list {
  list-style: none; margin: var(--sp-1) 0 0; padding: 0;
  display: flex; flex-direction: column; gap: var(--sp-2);
}
.home-before-item {
  position: relative; padding-left: 14px;
  font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--text);
  overflow-wrap: anywhere;
}
.home-before-item::before {
  content: ""; position: absolute; left: 2px; top: 8px;
  width: 5px; height: 5px; border-radius: var(--r-full); background: var(--text-3);
}
.home-before-item.is-blocking::before { background: var(--waiting-solid); }
.home-before-more { margin-top: var(--sp-1); }
.home-before-more > summary { font-size: var(--fs-sm); }

/* the one primary, and the quiet ways beside it */
.home-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-3); }
.home-actions .quiet-links { width: auto; }
@media (max-width: 560px) {
  .home-actions > .btn-primary { width: 100%; }
}

/* the stops, short, under the button — and the whole sentence one fold down */
.home-stops {
  display: flex; align-items: flex-start; gap: var(--sp-2);
  margin: calc(-1 * var(--sp-2)) 0 0;
  font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--text-2);
}
.home-stops > svg { flex: none; margin-top: 3px; color: var(--text-3); }
.home-how { margin-top: calc(-1 * var(--sp-2)); }
.home-how .fold-body p { margin: 0 0 var(--sp-2); font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--text-2); }

/* "Already made on this channel", folded under the steer line */
.home-made { margin-top: 0; }
.home-made > .hint, .home-made > .alt-list, .home-made > .refusal { margin: 0 0 var(--sp-3); }

/* Auto's own panel: find, its price, its topics, make these */
.home-auto { display: flex; flex-direction: column; gap: var(--sp-3); min-width: 0; }
.home-auto:focus { outline: none; }
.home-auto > .home-actions + .hint { margin-top: 0; }
.home-topics {
  display: flex; flex-direction: column; gap: var(--sp-3);
  padding: var(--sp-5); border-radius: var(--r-xl); background: var(--surface-2);
}
.home-topics > .home-sub { margin-top: 0; }
.home-topics .hint { margin-top: 0; }
.home-topics .go-row, .home-topics .home-actions { margin-top: var(--sp-1); }
.home-topics .choice { background: var(--surface); }
.home-topics .choice[aria-pressed="true"] { background: var(--accent-tint); }

/* several episodes imported together: one callout above the paste box */
.home-import .callout-main > * + * { margin-top: var(--sp-2); }
.home-import .alt-list li { padding: 6px 0; font-size: var(--fs-sm); }
.home-import .readout { margin-top: var(--sp-2); }
.home-import-yes { margin-top: var(--sp-3); }
.home-file { display: block; }
[data-files="chosen"] { margin-top: 0; }

/* ---- TONIGHT: the overnight list (cat/web/studio.js renderNight) ------- */
.home-night { display: flex; flex-direction: column; gap: var(--sp-3); margin-bottom: var(--sp-4); min-width: 0; }
.night-title { margin: 0; font-size: var(--fs-xl); line-height: var(--lh-xl); font-weight: 600; color: var(--text); }
.night-headline { margin: 0; font-size: var(--fs-lg); line-height: var(--lh-lg); color: var(--text); }
.night-eps, .night-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-2); }
.night-ep { border-top: 1px solid var(--border-subtle); padding-top: var(--sp-2); }
.night-ep-head { display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--sp-1) var(--sp-3); }
.night-ep-title { font-weight: 600; color: var(--text); min-width: 0; overflow-wrap: anywhere; }
.night-ep-acts, .night-ctl, .night-window { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-3); }
.night-card { border: 1px solid var(--border); border-radius: var(--r-md); padding: var(--sp-3); background: var(--surface-2); }
.night-card p { margin: 0 0 var(--sp-1) 0; }
.night-window label { display: flex; align-items: center; gap: var(--sp-2); color: var(--text-2); font-size: var(--fs-sm); }

/* ---- AN EPISODE'S ROW (the workspace's sections, a channel's page) ---- */
/* "Show N more" under a list, and a list's small heading */
.work-group-more { padding: var(--sp-1) var(--sp-4) var(--sp-3); }
.job-older { display: block; }
/* a channel's topic searches, after its episodes, under their own heading */
.work-searches { border-top: 1px solid var(--border); }
.work-sub-title {
  margin: 0; padding: var(--sp-3) var(--sp-4) var(--sp-1);
  font-size: var(--fs-sm); line-height: var(--lh-sm); font-weight: 600;
  color: var(--text-2); text-transform: none;
}

/* ONE ROW: a tinted tile with the kind's glyph, the title and its one line,
   the door at the right — 64px at least, rows divided by a quiet rule */
.row.job-row {
  display: grid; grid-template-columns: 40px minmax(0, 1fr) auto;
  gap: var(--sp-1) var(--sp-3); align-items: center;
  min-height: 64px; padding: var(--sp-3) var(--sp-4);
  border-top: 1px solid var(--border-subtle); border-bottom: none;
}
.job-tile {
  width: 40px; height: 40px; border-radius: var(--r-md);
  display: grid; place-items: center; align-self: start;
  background: var(--stopped-bg); color: var(--stopped-solid);
}
.job-tile .job-glyph { width: 18px; height: 18px; }
.job-tile.is-working { background: var(--working-bg); color: var(--working-solid); }
.job-tile.is-needs   { background: var(--needs-bg);   color: var(--needs-solid); }
.job-tile.is-waiting { background: var(--waiting-bg); color: var(--waiting-solid); }
.job-tile.is-done    { background: var(--done-bg);    color: var(--done-solid); }
.job-tile.is-failed  { background: var(--failed-bg);  color: var(--failed-solid); }
.job-main { min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.job-row .rt {
  font-size: var(--fs-md); line-height: var(--lh-md); font-weight: 600; color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.job-line {
  display: flex; flex-wrap: wrap; align-items: center; gap: 2px 6px;
  font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--text);
  min-width: 0;
}
.job-line > .status { flex: none; }
.job-said { min-width: 0; overflow-wrap: anywhere; }
.job-row .rm.job-meta { margin: 0; font-size: var(--fs-sm); color: var(--text-3); }
.job-row .work-fix { display: inline; margin: 0; }
.job-bar { max-width: 240px; margin-top: 2px; }
.job-row .act {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end;
  gap: var(--sp-1) var(--sp-3); text-align: right; white-space: normal;
}
.job-row .act .linkish { font-size: var(--fs-sm); }
.job-door { white-space: nowrap; }

@media (max-width: 940px) {
  .row.job-row { grid-template-columns: 40px minmax(0, 1fr); }
  .job-row .act { grid-column: 2; justify-content: flex-start; text-align: left; }
}
@media (max-width: 560px) {
  .row.job-row { padding: var(--sp-3); }
  .work-group-more { padding-left: var(--sp-3); padding-right: var(--sp-3); }
}

/* ---- CHANNELS: a grid of cards (§4.3) --------------------------------- */
/* "FIX PROBLEMS BY ITSELF" on a channel (docs/SELF_REPAIR.md §11.3): its
   label, the three choices (.seg), and one line under them */
.chan-repair { margin-top: var(--sp-4); display: flex; flex-direction: column; align-items: flex-start; gap: var(--sp-2); min-width: 0; }
.chan-repair > .k { font-size: var(--fs-sm); line-height: var(--lh-sm); font-weight: 600; color: var(--text-2); }
.chan-repair > .hint { margin-top: 0; }
/* the stops a person asked for (channels.js readsChoiceEl): a box and its
   words, wrapping at 375px with no sideways scroll */
.chan-read-switch { display: flex; align-items: flex-start; gap: var(--sp-2); min-width: 0; max-width: 100%; cursor: pointer; }
.chan-read-switch > input { flex: 0 0 auto; margin-top: 3px; }
.chan-read-switch > span { display: flex; flex-direction: column; min-width: 0; overflow-wrap: anywhere; }
.chan-read-switch > span > .hint { margin-top: 2px; }
.chan-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: var(--sp-6); align-items: start;
}
@media (max-width: 560px) {
  .chan-grid { grid-template-columns: minmax(0, 1fr); gap: var(--sp-4); }
}
/* the card: .chan stays on it (tests find a card by it), and the old left
   rail's look is undone */
.chan.chan-card {
  display: flex; flex-direction: column; gap: var(--sp-3);
  padding: var(--card-pad); text-align: left;
  background: var(--surface); border: 1px solid var(--border);
  border-left: 1px solid var(--border); border-radius: var(--r-xl);
  box-shadow: var(--shadow-sm); min-width: 0;
}
.chan.chan-card:hover { background: var(--surface); }
.chan.chan-card > * { margin-top: 0; }
.chan-card-head { display: flex; align-items: center; gap: var(--sp-3); min-width: 0; }
.chan-card-tile {
  flex: none; width: 48px; height: 48px; border-radius: var(--r-lg);
  display: grid; place-items: center;
  background: var(--accent-tint); color: var(--accent-text);
  font-size: var(--fs-md); font-weight: 600;
}
.chan-card-id { min-width: 0; flex: 1 1 auto; }
.chan.chan-card .cname {
  margin: 0; font-size: var(--fs-lg); line-height: var(--lh-lg); font-weight: 600;
  color: var(--text); overflow-wrap: anywhere;
}
.chan.chan-card .cname .rt-link { color: var(--text); }
.chan.chan-card .cnum { margin-top: 2px; font-size: var(--fs-sm); color: var(--text-3); overflow-wrap: anywhere; }
.chan.chan-card .cnum a { color: var(--text-3); }
.chan.chan-card .cnum a:hover { color: var(--text); }
.chan.chan-card .cstyle { margin-top: 0; }
.chan.chan-card .readiness { margin-top: 0 !important; }
.chan.chan-card .readiness .alt-list li { padding: 6px 0; font-size: var(--fs-sm); }
.chan.chan-card .chan-counts { margin-top: 0; }
.chan.chan-card .chan-counts .ghost {
  min-height: 0; padding: 0; border: none; background: none;
  color: var(--accent-text); font-size: var(--fs-sm); font-weight: 500;
}
.chan.chan-card .chan-counts .ghost:hover { text-decoration: underline; background: none; }
.chan-card-foot {
  display: flex; flex-wrap: wrap; align-items: flex-start; gap: var(--sp-2);
  margin-top: var(--sp-1); padding-top: var(--sp-3);
  border-top: 1px solid var(--border-subtle);
}
.chan-card-foot > .btn-secondary, .chan-card-foot > .btn-quiet { text-decoration: none; }
.chan-more { flex: 1 1 100%; border-top: none; }
.chan-more > summary { padding: 6px 0; font-size: var(--fs-sm); }
.chan-more-doors { display: flex; flex-wrap: wrap; gap: var(--sp-2); padding-top: 0; }
.chan-more-doors .ghost, .chan-more-doors .btn-danger { min-height: 32px; padding: 4px 12px; font-size: var(--fs-sm); }
@media (min-width: 561px) {
  .chan-more { flex: 0 1 auto; margin-left: auto; }
  .chan-more[open] { flex-basis: 100%; margin-left: 0; }
}
.chan-banked-note { margin-top: var(--sp-6); }
.chan-banked-intro { margin: calc(-1 * var(--sp-2)) 0 var(--sp-6); max-width: 72ch; }
/* a card opened inside a channel's own page is flat: it sits in a card */
.chan-home-settings .chan.chan-card { padding: 0; border: none; box-shadow: none; }

/* ---- CHANNELS, STREAMLINED (docs/CHANNELS_STREAMLINED.md, 2026-10-13) ----
   One full-width card per channel, one column at every width: the top says
   who it is and what it makes, with "New episode" at the same place on every
   card and ⋯ beside it; the band under it holds AT MOST TWO rows — the
   verdict, then what an episode is doing — each a chip in a fixed 112px
   column, a sentence and one door, so the chips line up down the page.
   Role tokens only; it reads in either skin. */
.chan-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-4); }
.chan.chan-row {
  display: block; padding: 0; text-align: left; min-width: 0;
  border: 1px solid var(--border); border-radius: var(--r-xl);
  background: var(--surface); overflow: visible;
}
.chan.chan-row:hover { background: var(--surface); }
.chan-top {
  display: grid; grid-template-columns: 144px minmax(0, 1fr) auto;
  gap: var(--sp-5); align-items: center; padding: var(--sp-5) var(--card-pad);
}
.chan-row-face {
  position: relative; display: grid; place-items: center; overflow: hidden;
  width: 144px; height: 81px; border-radius: var(--r-lg);
  background: var(--accent-tint); color: var(--accent-text); text-decoration: none;
}
.chan-row-face.has-poster { background: var(--surface-3); }
.chan-row-face-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.chan-row-face-tile { font-size: var(--fs-xl); line-height: 1; font-weight: 600; letter-spacing: .02em; }
.chan-row-face-dur {
  position: absolute; right: 6px; bottom: 6px; padding: 1px 6px; border-radius: var(--r-sm);
  background: var(--media-scrim); color: var(--on-media);
  font-size: var(--fs-xs); line-height: var(--lh-xs); font-weight: 600; font-variant-numeric: tabular-nums;
}
.chan-id { min-width: 0; }
.chan-name { margin: 0; font-size: var(--fs-xl); line-height: var(--lh-xl); font-weight: 600; overflow-wrap: anywhere; }
.chan-name .rt-link { color: var(--text); }
.chan-what { margin: 2px 0 0; font-size: var(--fs-md); line-height: var(--lh-md); color: var(--text-2); overflow-wrap: anywhere; }
.chan-eps { margin: 2px 0 0; font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--text-3); }
.chan-eps .link { font-size: inherit; }
.chan-actions { display: flex; align-items: center; gap: var(--sp-2); }
.chan-new { min-height: 40px; white-space: nowrap; text-decoration: none; }
.chan-menu-wrap { position: relative; }
.chan-menu { right: 0; top: calc(100% + 6px); min-width: 280px; }
.chan-menu[hidden] { display: none; }
.chan-menu .menu-item {
  flex-direction: column; align-items: flex-start; gap: 0;
  min-height: 0; padding: 7px 10px; white-space: normal;
}
.chan-menu .menu-label { font-size: var(--fs-md); line-height: var(--lh-md); font-weight: 500; color: var(--text); }
.chan-menu .menu-help { font-size: var(--fs-sm); line-height: var(--lh-sm); font-weight: 400; color: var(--text-3); }
.chan-menu .menu-danger .menu-label { color: var(--failed-text); }
.chan-menu .alt-ways { flex-direction: column; align-items: stretch; gap: var(--sp-2); padding: var(--sp-2) 10px; margin: 0; }
.chan-menu .alt-ways .hint { white-space: normal; }

.chan-band { border-top: 1px solid var(--border-subtle); padding: var(--sp-1) var(--card-pad) var(--sp-2); }
.band-row {
  display: grid; grid-template-columns: 112px minmax(0, 1fr) auto;
  gap: var(--sp-4); align-items: center; padding: 10px 0;
}
.band-row[hidden] { display: none; }
.band-row + .band-row { border-top: 1px dashed var(--border-subtle); }
.band-chip { min-width: 0; }
.band-text { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.band-say { font-size: var(--fs-base); line-height: var(--lh-base); font-weight: 500; color: var(--text); overflow-wrap: anywhere; }
.band-say .hint, .band-say .band-who { margin: 0; font-size: inherit; line-height: inherit; color: inherit; }
.band-sub { font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--text-2); overflow-wrap: anywhere; }
.band-more { font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--text-3); }
.band-more .link { font-size: inherit; }
.band-doors { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: var(--sp-2); }
.band-door { white-space: nowrap; text-decoration: none; }
.band-bar { max-width: 420px; margin-top: 6px; }
.chan-kept-needs { margin-left: var(--sp-1); text-decoration: none; }
.chan-kept-needs .status { vertical-align: baseline; }
.chan-skel { height: 172px; background: var(--surface-2); border-color: var(--border-subtle); box-shadow: none; }

/* the empty state */
.chan-empty { padding: var(--sp-2) var(--sp-8) var(--sp-6); }
.chan-empty .empty-state { padding: var(--sp-8) 0 var(--sp-5); }
.chan-empty-foot { max-width: 720px; margin: var(--sp-2) auto 0; font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--text-3); text-align: center; }

/* the read dialog: the price, said before the paid click */
.read-cost {
  margin: var(--sp-3) 0 0; padding: 10px var(--sp-3); border-radius: var(--r-md);
  background: var(--surface-2); color: var(--text); font-size: var(--fs-md); line-height: var(--lh-md);
}

/* the channel's own page receives what the list let go */
.chan-home-what { margin: 0 0 var(--sp-2); font-size: var(--fs-md); line-height: var(--lh-md); color: var(--text-2); }
.chan-home-source .t { font-weight: 600; color: var(--text); margin-top: 2px; }
.chan-home-admin { margin-top: var(--sp-4); }

/* a finger gets 44px everywhere (UI_REDESIGN §3.4): these rules come after
   A's coarse-pointer block, so they say it again for the card's own sizes */
@media (pointer: coarse) {
  .chan-new, .chan-menu .menu-item, .band-door { min-height: 44px; }
}

@media (max-width: 560px) {
  .chan-row-face, .chan-row-face.has-poster { width: 64px; height: 64px; }
  .chan-row-face-dur { display: none; }
  .chan.chan-row {
    display: grid; grid-template-columns: 64px minmax(0, 1fr) auto;
    grid-template-areas: "face id menu" "band band band" "new new new";
    column-gap: var(--sp-3); padding: var(--sp-4) var(--card-pad);
  }
  .chan-top, .chan-actions { display: contents; }
  .chan-row-face { grid-area: face; }
  .chan-id { grid-area: id; align-self: center; }
  .chan-menu-wrap { grid-area: menu; margin: -6px -8px 0 0; align-self: start; }
  .chan-band { grid-area: band; padding: var(--sp-1) 0 var(--sp-2); margin-top: var(--sp-3); }
  .chan-new { grid-area: new; width: 100%; justify-content: center; margin-top: var(--sp-2); }
  .chan-name { font-size: var(--fs-lg); line-height: var(--lh-lg); }
  .chan-what { font-size: var(--fs-sm); line-height: var(--lh-sm); }
  .band-row { grid-template-columns: minmax(0, 1fr); gap: 6px; padding: var(--sp-3) 0; }
  .band-doors { justify-content: flex-start; }
  .band-doors .btn-quiet { margin-left: -12px; }
  .chan-menu { right: -8px; min-width: min(300px, calc(100vw - 32px)); }
  .chan-empty { padding: var(--sp-1) var(--sp-4) var(--sp-5); }
}

/* ---- A CHANNEL'S OWN PAGE (§4.3) ---------------------------------------- */
.chan-home-face { margin-bottom: var(--sp-6); }
.chan-home-face .chan-face { align-items: flex-start; }
.chan-home-tile {
  width: 96px; height: 54px; border-radius: var(--r-lg); object-fit: cover;
  display: grid; place-items: center;
  background: var(--accent-tint); color: var(--accent-text);
  font-size: var(--fs-lg); font-weight: 600;
}
.chan-home-face .readiness { margin-top: var(--sp-3) !important; }
.chan-home-episodes { display: flex; flex-direction: column; gap: var(--sp-6); }
.card.work-sec { padding: 0; }
.work-sec + .work-sec { border-top: 1px solid var(--border); }
.card.work-sec .work-sec-head {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-1) var(--sp-3);
  padding: var(--sp-5) var(--card-pad) var(--sp-3);
}
.work-sec-title { margin: 0; font-size: var(--fs-lg); line-height: var(--lh-lg); font-weight: 600; color: var(--text); }
.work-sec-count { font-size: var(--fs-sm); color: var(--text-3); font-variant-numeric: tabular-nums; }
.work-sec-more { margin-left: auto; font-size: var(--fs-sm); }
.card.work-sec .work-sec-empty { padding: 0 var(--card-pad) var(--sp-5); margin: 0; }
.card.work-sec > .job-row:last-child { padding-bottom: var(--sp-4); }
.work-sec-grid { padding: var(--sp-1) var(--card-pad) var(--card-pad); }
.work-sec-fold { margin: 0 var(--card-pad); border-top: 1px solid var(--border-subtle); }
.work-sec-fold > .job-row { padding-left: 0; padding-right: 0; }
.chan-home-settings { margin-top: var(--sp-6); }
.chan-home-settings .readout { margin-top: 0; }
.chan-home-details { margin-top: var(--sp-6); }
.chan-home-details .alt-ways { margin-top: var(--sp-2); }
/* a finished episode's title link sits inside .rt (the row's own class) */
.video-card .rt { min-width: 0; }
.video-card-actions .link { font-size: var(--fs-sm); }
.video-card-media.work-play { padding: 0; background: var(--media-scrim); }
.video-card-media.work-play video {
  display: block; width: 100%; height: 100%; max-width: none; max-height: none;
  object-fit: contain; border-radius: 0; background: none;
}
@media (max-width: 560px) {
  .card.work-sec .work-sec-head { padding: var(--sp-4) var(--card-pad) var(--sp-2); }
  .work-sec-grid { padding: var(--sp-1) var(--card-pad) var(--card-pad); }
}

/* ---- THE ADD-A-CHANNEL WIZARD (§4.3): a centred card, the stepper at its
   top, the step's one question large, Back and Next in its foot ---------- */
.wizard { max-width: 640px; margin: 0 auto; }
.wizard > .panel > .panel-head { padding: var(--sp-5) var(--card-pad); border-bottom: 1px solid var(--border-subtle); }
.wizard .panel-body { padding: var(--card-pad) !important; }
.wizard .field > label,
.wizard .choice-head {
  font-size: var(--fs-xl); line-height: var(--lh-xl); font-weight: 600; color: var(--text);
}
.wizard .field > label { margin-bottom: var(--sp-3); }
.wizard .input-shell { min-height: 48px; }
.wizard .input-shell input { min-height: 46px; font-size: var(--fs-lg); }
.wizard .found { margin-top: 0; }
.wizard .wiz-foot { padding: var(--sp-4) var(--card-pad); }
.wizard .wiz-foot + .quiet-links { justify-content: flex-start; }
.wizard .steps { gap: 0; }

/* ---- THE SCAN PAGE (/scan/<channel>): its reading ladder as the stepper's
   vertical form — a mark and a word a line ------------------------------ */
.step-row {
  display: flex; align-items: baseline; gap: var(--sp-3);
  padding: 6px 0; border-bottom: 1px solid var(--border-subtle);
}
.step-row:last-child { border-bottom: none; }
.step-mark { min-width: 72px; font-weight: 600; }
.step-mark.done { color: var(--done-text); }
.step-mark.now { color: var(--working-text); }
.step-mark.stopped { color: var(--stopped-text); }

/* ---- THE VISUAL GUIDE'S KINDS OF PICTURE (docs/SHOT_KINDS.md §9.1): one
   block per kind — its name and how often, its key frame, its look, its
   words, when it is used, how it comes in and goes out. A frame is a small
   picture; the key frame among them carries the accent ring, and its
   pressed state says so to a screen reader (scan.js frameGrid) --------- */
.kind-list { display: grid; gap: var(--sp-4); margin-top: var(--sp-3); min-width: 0; }
.kind-block {
  min-width: 0; padding: var(--sp-4);
  border: 1px solid var(--border); border-radius: var(--r-xl);
  background: var(--surface);
}
.kind-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 10px; min-width: 0; }
.kind-cols { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--sp-3) var(--sp-6); min-width: 0; }
.kind-pics, .kind-says { min-width: 0; }
.kind-says { overflow-wrap: anywhere; }
.kind-says > .label, .kind-pics > .label:first-child { margin-top: var(--sp-3); }
@media (min-width: 900px) {
  .kind-cols { grid-template-columns: minmax(0, 420px) minmax(0, 1fr); }
}
.kind-name {
  font-size: var(--fs-lg); line-height: var(--lh-lg); font-weight: 600;
  color: var(--text); overflow-wrap: anywhere;
}
.kind-main { font-size: var(--fs-sm); color: var(--text-3); }
/* a white card on a white block needs an edge, or the frame has none */
.kind-key {
  display: block; width: 480px; max-width: 100%; margin-top: var(--sp-2);
  border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--surface-3);
}
.kind-frames { display: flex; flex-wrap: wrap; gap: 6px; margin-top: var(--sp-2); min-width: 0; }
.kind-frame {
  position: relative; display: block; padding: 0; line-height: 0; flex: none;
  border: 1px solid var(--border-strong); border-radius: var(--r-sm);
  background: var(--surface-3); overflow: hidden;
}
.kind-frame img { display: block; width: 96px; max-width: 100%; }
button.kind-frame:hover:not(:disabled) { border-color: var(--text-2); }
button.kind-frame:disabled { cursor: not-allowed; opacity: .55; }
.kind-frame.is-key { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent); }
.kind-others { margin-top: var(--sp-3); min-width: 0; }
.kind-others > summary { display: inline-flex; align-items: center; }
.kind-other { margin: 0; width: 98px; min-width: 0; }
.kind-other > .hint { margin-top: 2px; overflow-wrap: anywhere; }
/* a phone (after the rules it narrows): three frames to a row inside the panel and the block */
@media (max-width: 560px) {
  .kind-block { padding: var(--sp-3); }
  .kind-frame img { width: 84px; }
  .kind-other { width: 86px; }
}

/* ===== END B ===== */

/* =============================================================================
   THE EPISODE PAGE WHILE IT RUNS (wave B, B1) — the live picture grid, the
   picture viewer, the administrator's event log, the composer's video
   preview, the "You asked" line, the theme switch and the reload pill. Built
   from this file's own tokens; nothing here is a second visual system.
   ============================================================================= */

/* "You asked" under the episode's title: the person's own request, quiet */
.asked { margin-top: 6px; font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--text-2); overflow-wrap: anywhere; }
.asked .label { margin-right: 6px; }

/* PICTURES SO FAR — a grid of buttons, each a picture and its scene. The
   cell is a real <button>, so the focus ring and the 44px floor hold. */
.made-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: var(--sp-3); margin-top: var(--sp-2);
}
.made-cell {
  display: flex; flex-direction: column; gap: 4px; min-height: 44px;
  padding: 0; border: none; background: none; color: inherit;
  text-align: left; cursor: pointer; font: inherit;
}
.made-cell.is-pending { cursor: default; }
/* a landed picture with its Redo under it: one grid slot, the picture's
   button first, then the Redo link (studio.js, "REDO THIS PICTURE") */
.made-slot { display: flex; flex-direction: column; min-width: 0; }
.made-slot > .linkish { align-self: flex-start; }
/* EARLIER VERSIONS (cat/stages/takes.py): the takes side by side; a strip
   scrolls sideways inside its own box, never the page */
.takes-unit { margin-top: 12px; min-width: 0; }
.takes-strip { display: flex; gap: 12px; overflow-x: auto; padding-bottom: 4px; }
.takes-fig { flex: 0 0 160px; margin: 0; display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.takes-fig .made-img { width: 100%; height: auto; display: block; }
.takes-audio { width: 100%; }
.takes-titles { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.takes-days { width: 5em; }
/* SHORTS (cat/media/shorts.py): one block per stretch CAT picked, the tall
   player beside nothing - it is narrow on purpose, 9:16, and never wider
   than the card */
.ep-shorts-looks { border: 1px solid var(--border-subtle); border-radius: var(--r-md); padding: var(--sp-3); margin: 0 0 var(--sp-3); display: flex; flex-direction: column; gap: var(--sp-2); min-width: 0; }
.ep-shorts-look { display: flex; gap: var(--sp-2); align-items: flex-start; font-size: var(--fs-sm); color: var(--text-2); }
.ep-short { border-top: 1px solid var(--border-subtle); padding: var(--sp-3) 0; min-width: 0; }
.ep-short-open { margin: 0 0 var(--sp-1); overflow-wrap: anywhere; }
.ep-short-facts { margin: 0 0 var(--sp-2); padding-left: var(--sp-4); font-size: var(--fs-sm); color: var(--text-2); }
.ep-short-text > p { font-size: var(--fs-sm); color: var(--text-2); overflow-wrap: anywhere; }
.ep-short-video { display: block; width: min(100%, 240px); aspect-ratio: 9 / 16; background: var(--surface-3); border-radius: var(--r-md); margin: var(--sp-2) 0; }
.ep-short-title { display: flex; flex-direction: column; gap: var(--sp-1); margin: var(--sp-2) 0; font-size: var(--fs-sm); color: var(--text-2); min-width: 0; }
.ep-short-title-input { width: 100%; max-width: 100%; box-sizing: border-box; min-width: 0; }
/* THE FIX-IT PANEL (cat/stages/fixit.py, studio.js fixitCard): the scene
   grid is the pictures' own grid; each slot adds two small rows of links
   under the caption, a bar for what is waiting, and the preview clip */
.fixit-row { display: flex; flex-wrap: wrap; gap: var(--sp-3); }
.fixit-slot.is-changed .made-img { outline: 2px solid var(--accent, currentColor); outline-offset: 2px; }
.fixit-bar { margin-top: var(--sp-3); display: flex; flex-direction: column; gap: var(--sp-2); min-width: 0; }
.fixit-waiting { margin: 0; font-weight: 600; }
.fixit-video { width: 100%; max-width: 640px; border-radius: var(--r-md); background: var(--surface-3); }
.fixit-history { margin-top: var(--sp-3); }
.made-img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; border-radius: var(--r-md); display: block; background: var(--surface-3); }
.made-wait {
  width: 100%; aspect-ratio: 16 / 9; border-radius: var(--r-md); display: grid; place-items: center;
  background: var(--surface-2); color: var(--text-3);
}
.made-cap { font-size: var(--fs-sm); color: var(--text-2); line-height: var(--lh-sm); overflow-wrap: anywhere; }
.made-cap b { color: var(--text); font-weight: 600; }
.made-redo { margin-top: var(--sp-1); font-size: var(--fs-sm); }
a.made-cell { text-decoration: none; }
/* a picture not made yet that CAT reworded: why, and the words, folded
   under its cell (studio.js makingPanel) */
.made-why { margin-top: var(--sp-1); font-size: var(--fs-sm); min-width: 0; }
/* THE HOUSE CHEVRON, as every other fold on the page wears it (the fold
   rules above) — it showed the browser's own ▶ (review 2026-10-12, round
   3); compact, like .refusal-raw, under a scene's cell */
.made-why > summary { padding: 6px 0; font-size: var(--fs-sm); }
.made-why > p { margin: var(--sp-1) 0 0; overflow-wrap: anywhere; }

/* THE PICTURE VIEWER (CAT.lightbox): the picture as large as the dialog
   allows, its line under it, and Previous / n of N / Next */
.lightbox-stage { display: grid; place-items: center; background: var(--sunk); border-radius: 6px; }
/* the picture fills the dialog's width (a small one is scaled up, not left
   as a stamp in the middle) and never runs below the screen */
.lightbox-stage img, .lightbox-stage video {
  width: 100%; height: auto; max-height: calc(100vh - 260px);
  object-fit: contain; display: block; border-radius: 6px;
}
.lightbox-sub { margin-top: 12px; font-size: var(--t-base); line-height: 1.55; color: var(--ink); }
.lightbox-nav { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 14px; }

/* THE ADMINISTRATOR'S EVENT LOG */
.event-tools { display: flex; flex-wrap: wrap; gap: 10px; margin: 10px 0; }
.event-tools .select-shell, .event-tools .input-shell { flex: 1 1 180px; min-width: 0; }
.event-scroll { overflow-x: auto; max-height: 520px; overflow-y: auto; margin-top: 8px; }
.event-table { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); }
.event-table th { text-align: left; font-weight: 600; color: var(--text-2); padding: 6px 8px; border-bottom: 1px solid var(--border-strong); }
.event-table td { padding: 5px 8px; border-bottom: 1px solid var(--border-subtle); vertical-align: top; overflow-wrap: anywhere; }
.event-table td.mono { font-family: var(--font-mono); font-size: var(--fs-xs); }
.event-table tr.lvl-warn td, .event-table tr.lvl-error td { color: var(--stopped-text); }

/* THE VIDEO A PASTED ADDRESS NAMES */
.peek-row { display: flex; gap: 12px; align-items: center; margin-top: 10px; }
.peek-img { width: 128px; aspect-ratio: 4 / 3; object-fit: cover; border-radius: 4px; flex: none; }

/* THE THEME SWITCH in the top bar: a glyph AND a word */
.theme-switch {
  display: inline-flex; align-items: center; gap: 6px; min-height: 36px;
  white-space: nowrap; flex: none;
  padding: 5px 10px; border-radius: 6px; border: none; cursor: pointer;
  background: none; color: var(--ink-dim); font: inherit; font-size: var(--t-mini);
  box-shadow: inset 0 0 0 1px var(--line);
}
.theme-switch:hover { color: var(--ink-loud); }

/* THE PAGES CHANGED UNDER THIS TAB — bottom left, away from the toasts */
.reload-pill {
  position: fixed; left: 16px; bottom: 16px; z-index: 60;
  max-width: min(460px, calc(100vw - 32px));
  display: flex; align-items: center; gap: 12px;
  padding: 10px 12px 10px 16px; border-radius: var(--r);
  background: var(--signal-bg); color: var(--ink);
  box-shadow: inset 0 0 0 1px var(--signal-ln), var(--shadow);
  font-size: var(--t-mini); line-height: 1.45;
}
.reload-pill .btn-secondary { flex: none; }

@media (max-width: 560px) {
  .made-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-2); }
  .peek-row { align-items: flex-start; }
  .peek-img { width: 96px; }
}

/* "Use this hook": the opening is read above the buttons, on its own line
   of the button row (owner, 2026-10-04) */
.go-row .best-hook { flex-basis: 100%; margin: 0 0 12px; }
.go-row .best-hook blockquote { margin: 6px 0 0; padding: 10px 14px;
  border-left: 3px solid var(--border-strong); white-space: pre-wrap;
  font-size: var(--fs-base); line-height: 1.5; }

/* ===== C · EPISODE PAGE (redesign 2026-10-11) =====
   docs/UI_REDESIGN.md §4.2 — the episode page in every state, the price
   check and the read screens. Built from A's primitives (§3: .page-head,
   .card, .callout, .status, .steps, .progress, .fold, .empty-state); the
   page's own variants are .ep-*. Tokens only: no hex, no px font sizes.
   Top to bottom: the way back, the header, the five stages, the one thing
   to do (or what it is doing now), the work, then Details and Admin
   details. */

.ep-back { margin-top: var(--sp-4); }
.ep-back .btn-back { margin-left: -10px; }

/* THE HEADER: the title as the page's one h1, the meta line, the chip */
.ep-head { align-items: flex-start; margin: var(--sp-2) 0 var(--sp-4); }
.ep-head .page-sub.ep-meta {
  margin-top: var(--sp-2);
  font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--text-3);
}
.ep-meta a { color: var(--text-2); text-decoration: none; }
.ep-meta a:hover, .ep-meta a:focus-visible { color: var(--text); text-decoration: underline; text-underline-offset: 3px; }
.ep-status { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.ep-head-status { padding-top: 6px; }
.ep-head-wrap > .asked { margin: calc(-1 * var(--sp-2)) 0 var(--sp-4); }
.ep-draft-why { margin: 0 0 var(--sp-4); font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--text-2); }

/* THE FIVE STAGES, in a card of their own (§3.8). On a wide screen every
   stage is named; under 940px only the circles and the current stage (and
   where a run stopped) — A's rule, which the phone test measures. */
.ep-steps-card { padding: 20px var(--card-pad); margin-bottom: var(--sp-6); }
.ep-steps { flex-wrap: nowrap; }
.ep-steps .step { align-items: center; }
.ep-steps .step-text { display: inline-flex; flex-direction: column; line-height: 1.25; }
.ep-steps .step-word { font-size: var(--fs-sm); font-weight: 400; color: var(--text-2); }
.ep-steps .step-sep { flex: 1 1 32px; max-width: 72px; }
.ep-steps-note {
  margin: var(--sp-4) 0 0; padding-top: var(--sp-3);
  border-top: 1px solid var(--border-subtle);
  font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--text-2);
}
.ep-steps-note:empty { display: none; }

/* THE STAGE TIMELINE (cat/kernel/progress.py): the word AND the order carry a
   stage's state; the weight and colour only echo it. */
.ep-timeline-card { padding: var(--sp-1) var(--card-pad); margin-bottom: var(--sp-6); }
.timeline-list { list-style: none; margin: 0; padding: 0; }
/* state | step, with the step's time in the step's own column (polish round,
   2026-10-22: as a wrapping flex row the time fell under the state word on
   a phone, "stopped / — 0s") */
.timeline-row {
  display: grid; grid-template-columns: 5.5em minmax(0, 1fr); gap: 0 var(--sp-2);
  align-items: baseline;
  padding: var(--sp-2) 0; border-top: 1px solid var(--border-subtle);
  font-size: var(--fs-md); line-height: var(--lh-md); color: var(--text-2);
}
.timeline-row:first-child { border-top: 0; }
.timeline-state { font-size: var(--fs-xs); color: var(--text-3); text-transform: none; }
.timeline-label { min-width: 0; overflow-wrap: anywhere; }
.timeline-bits { grid-column: 2; font-size: var(--fs-sm); line-height: var(--lh-sm); }
.ep-timeline-fold { border-top: 0; }
.ep-timeline-fold > summary { font-weight: 600; color: var(--text); }
.ep-timeline-fold > .ep-timeline { padding-bottom: var(--sp-3); }
.timeline-row.is-making .timeline-label,
.timeline-row.is-needs_you .timeline-label { color: var(--text); font-weight: 600; }
.timeline-row.is-later { color: var(--text-3); }
.timeline-cost { margin: var(--sp-3) 0 0; }
.job-progress { color: var(--text-2); }
@media (max-width: 560px) { .ep-timeline-card { padding: var(--sp-1) var(--sp-4); } }
@media (max-width: 560px) {
  .ep-steps-card { padding: var(--sp-4); }
  .ep-steps { flex-wrap: wrap; }
}

/* THE STATE BODY: one callout across the page, the only filled button on
   it. The hold's own help (CAT.holdHelp) and the money line sit inside. */
.ep-state:empty { display: none; }
.ep-callout .callout-body + .callout-body { margin-top: var(--sp-2); }
.ep-callout .callout-main > .hint { margin-top: var(--sp-2); }
.ep-callout .go-row { margin-top: var(--sp-4); }
.ep-callout .callout-actions .hint { flex-basis: 100%; margin-top: 0; }
.ep-unanswered { display: flex; align-items: flex-start; gap: 6px; }
.ep-unanswered > svg { flex: none; margin-top: 4px; color: var(--needs-solid); }
.ep-warn-list { list-style: none; margin: var(--sp-3) 0 0; padding: 0; }
.ep-warn-list li {
  display: flex; align-items: flex-start; gap: 6px; margin-top: var(--sp-1);
  font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--text);
}
.ep-warn-list li > svg { flex: none; margin-top: 3px; color: var(--needs-solid); }

/* THE PAGE'S BLOCKS stack with one rhythm; two columns below the stepper
   on a wide screen (main | side), one under 940px in the order listed */
.ep-body { display: flex; flex-direction: column; gap: var(--sp-6); }
.ep-grid {
  display: grid; grid-template-columns: minmax(0, 1fr) 360px;
  gap: var(--sp-6); align-items: start;
}
@media (min-width: 1280px) { .ep-grid { grid-template-columns: minmax(0, 1fr) 400px; } }
@media (max-width: 940px) { .ep-grid { grid-template-columns: minmax(0, 1fr); } }
.ep-main, .ep-side, .ep-stack { display: flex; flex-direction: column; gap: var(--sp-6); min-width: 0; }
.ep-slot { min-width: 0; }
.ep-slot:empty, .ep-stack:empty, .ep-main:empty, .ep-side:empty { display: none; }
.ep-grid:has(> .ep-main:empty):has(> .ep-side:empty) { display: none; }
/* nothing in the main column (a callout above it, no pictures, no script):
   the side column's cards sit under the callout, at the side column's width */
.ep-grid:not(:has(> .ep-main > :not(:empty))) { grid-template-columns: minmax(0, 400px); }
.ep-grid:not(:has(> .ep-main > :not(:empty))) > .ep-main { display: none; }
.ep-callout .ep-glyph, .ep-gone .ep-glyph { color: inherit; }

/* A CARD'S TITLE AND ITS COUNT ("Pictures so far · 12 of 40 pictures") */
.ep-count { font-weight: 400; color: var(--text-2); }
.ep-card-actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-3); }
.ep-sub,
.ep-detail-title {
  margin: var(--sp-5) 0 var(--sp-2);
  font-size: var(--fs-md); line-height: var(--lh-md); font-weight: 600; color: var(--text);
}
.card-body > .ep-sub:first-child,
.fold-body > .ep-sub:first-child,
.ep-detail > .ep-detail-title:first-child { margin-top: 0; }

/* THE NOW CARD: what it is doing, how far, the bar, the Stop */
.ep-now .card-body { display: flex; flex-direction: column; gap: var(--sp-2); }
.ep-now-title { margin: 0; font-size: var(--fs-xl); line-height: var(--lh-xl); font-weight: 600; color: var(--text); }
.ep-now-line { margin: 0; font-size: var(--fs-base); line-height: var(--lh-base); color: var(--text-2); font-variant-numeric: tabular-nums; }
.ep-now-bar { margin: var(--sp-2) 0 var(--sp-1); }
.ep-now-sent:empty { display: none; }
.ep-now-sent .hint { display: flex; align-items: flex-start; gap: 6px; margin-top: 0; color: var(--text-3); }
.ep-now-sent .hint > svg { flex: none; margin-top: 3px; }
.ep-now-stop { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-3); margin-top: var(--sp-3); }
.ep-now .hint { margin-top: 0; }

/* THE SUMMARY: the cost in one line, then what was made */
.ep-cost-line { margin: 0; font-size: var(--fs-base); line-height: var(--lh-base); color: var(--text); }
.ep-cost-k { color: var(--text-2); }
.ep-cost-line b { font-weight: 600; font-variant-numeric: tabular-nums; }
.ep-cost .meta { margin: 2px 0 0; }
.ep-cost .empty.loading { padding: 0; font-size: var(--fs-sm); }
.ep-facts { display: flex; flex-direction: column; margin: var(--sp-4) 0 0; }
.ep-fact {
  display: flex; justify-content: space-between; gap: var(--sp-4);
  padding: var(--sp-2) 0; border-top: 1px solid var(--border-subtle);
  font-size: var(--fs-md); line-height: var(--lh-md);
}
.ep-fact dt { color: var(--text-2); }
.ep-fact dd { margin: 0; color: var(--text); font-weight: 600; font-variant-numeric: tabular-nums; text-align: right; }

/* THE HERO: the finished video, first and largest. An upright (9:16)
   film stands at most 72% of the screen tall, centred. */
.ep-hero {
  position: relative; overflow: hidden; width: 100%;
  aspect-ratio: 16 / 9; border-radius: var(--r-2xl);
  background: var(--media-scrim);
}
.ep-hero video { display: block; width: 100%; height: 100%; object-fit: contain; }
.ep-hero.is-upright { aspect-ratio: auto; display: flex; justify-content: center; }
.ep-hero.is-upright video { width: auto; max-width: 100%; height: 72vh; max-height: 72vh; }
.ep-hero--empty {
  display: grid; place-items: center; padding: var(--sp-6);
  background: var(--surface-2); box-shadow: inset 0 0 0 1px var(--border);
  text-align: center;
}
.ep-hero-said { margin: 0; max-width: 44ch; font-size: var(--fs-base); line-height: var(--lh-base); color: var(--text-2); }
.ep-hero-note { margin: 0; }
.ep-actionbar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-3); margin-top: var(--sp-4); }
/* why a Copy beside the video is disabled, said under the bar */
.ep-actionbar-why { margin: var(--sp-2) 0 0; }
@media (max-width: 560px) {
  .ep-hero { border-radius: var(--r-xl); }
  .ep-actionbar .btn-primary { width: 100%; }
}

/* THE PICTURES (making, or every scene once it is done) */
.ep-pics .made-grid { margin-top: 0; }
.ep-pics .card-body > .hint:last-child { margin-top: var(--sp-3); }

/* THE SCRIPT, as the reading surface at the body size */
.ep-script-text { font-size: var(--fs-base); line-height: 1.7; max-width: none; }
.ep-script-text p:first-of-type { margin-top: 0; }
.ep-script-text p:last-child { margin-bottom: 0; }
.ep-script--wide .ep-script-text { font-size: 1.125rem; line-height: 1.75; max-width: 66ch; }
.ep-script-more { margin-top: var(--sp-3); margin-left: -10px; }

/* THE THUMBNAIL */
.ep-thumb-img {
  display: block; width: 100%; aspect-ratio: 16 / 9; object-fit: cover;
  border-radius: var(--r-lg); background: var(--surface-3);
}
/* the three for YouTube's Test & Compare (2026-10-28) */
.ep-thumb-variants {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: var(--sp-3); margin-top: var(--sp-3);
}
.ep-thumb-variant { margin: 0; display: flex; flex-direction: column; gap: var(--sp-1); min-width: 0; }
.ep-thumb-variant figcaption { display: flex; flex-direction: column; gap: 2px; font-size: var(--fs-sm); overflow-wrap: anywhere; }
.ep-thumb-variant .btn-sm { align-self: flex-start; }

/* FOR YOUTUBE: each option with its Copy at the right */
.ep-youtube .alt-list li { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1) var(--sp-2); }
.ep-youtube .alt-list li > span:first-child { flex: 1 1 220px; min-width: 0; overflow-wrap: anywhere; }
.ep-youtube .alt-list li > .ghost { margin-left: auto; }
.ep-youtube .ghost { min-height: 32px; padding: 4px 10px; font-size: var(--fs-sm); }
.ep-youtube-paid { margin-top: 0; }
.ep-desc { font-size: var(--fs-base); line-height: 1.65; max-width: none; margin-top: var(--sp-3); }
.ep-desc p { margin: 0 0 var(--sp-2); color: var(--text); }
.ep-credit { margin: 0; font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--text); overflow-wrap: anywhere; }
/* the YouTube tags, as one line that breaks inside a long phrase rather
   than sliding the page sideways (tests/test_phone_width.py) */
.ep-tags { margin: var(--sp-2) 0; font-size: var(--fs-base); line-height: var(--lh-base); color: var(--text); overflow-wrap: anywhere; }
.ep-found { margin-top: var(--sp-3); }
.ep-notes .alt-list li { font-size: var(--fs-md); }

/* MARK AS PUBLISHED and the topics a search offers, inside their cards */
.ep-publish .card-body > .label:first-child { display: block; margin-bottom: var(--sp-1); }
.ep-publish .go-row { margin-top: var(--sp-4); }
.ep-topics .card-body > :first-child { margin-top: 0; }

/* A FOLD'S WORDS keep to the chevron's line and wrap there, rather than
   dropping under it on a narrow screen */
details > summary:has(> .ep-sum) { flex-wrap: nowrap; }
details > summary > .ep-sum { flex: 0 1 auto; min-width: 0; }

/* DETAILS, THEN ADMIN DETAILS, at the foot of the page */
.ep-folds { margin-top: var(--sp-6); }
.ep-folds > .fold:last-child { border-bottom: 1px solid var(--border-subtle); }
.ep-detail:empty { display: none; }
.ep-detail + .ep-detail { margin-top: var(--sp-5); }
.ep-detail .ep-fold { margin-top: var(--sp-3); }
.ep-detail .num-readout { margin: 0; font-size: var(--fs-lg); line-height: var(--lh-lg); }
.ep-cost-said { overflow-wrap: anywhere; }
.ep-hide { margin-top: var(--sp-5); }
.ep-report { margin-top: var(--sp-3); overflow-x: auto; }
.ep-verdict.is-compact { margin-top: var(--sp-3); }
.ep-sound .readout { margin-top: var(--sp-2); }

/* AN EPISODE THAT IS NOT HERE */
.ep-gone { margin-top: var(--sp-2); }
.ep-gone-ways { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--sp-2); margin-top: var(--sp-3); }

/* THE PRICE CHECK (CAT.modal): the bounds first; what exactly the yes signs
   folded; the footer's stop far left, the Yes rightmost */
.ep-modal-lead { margin: 0; font-size: var(--fs-base); line-height: var(--lh-base); color: var(--text); }
/* what asks after the yes, under the lead (studio.js cardStopsLines) */
.ep-card-stops { margin: var(--sp-3) 0 0; }
.ep-approving { margin-top: var(--sp-5); }
.ep-card-text { display: block; margin: var(--sp-2) 0 0; padding: var(--sp-3); white-space: pre-wrap; overflow-wrap: anywhere; }
.modal .found { margin-top: var(--sp-4); }
.modal .ep-warn-list { margin-top: var(--sp-4); }
/* the price card's actions stay in view while the card scrolls — and the
   new-direction dialog's (common.js directionModal), whose "Use this
   direction" sat under every option card, below the fold */
.ep-price .modal-foot,
.dir-modal .modal-foot {
  position: sticky; bottom: 0; z-index: 1;
  background: var(--surface); box-shadow: 0 -1px 0 var(--border-subtle);
}

/* WHY THESE DIRECTIONS (common.js directionReportEl): the measured report
   in its own order, every tag a small chip; long quotes and titles wrap, so
   nothing scrolls sideways at 375px */
.why-report { overflow-wrap: anywhere; }
.why-sec { margin: 0 0 var(--sp-4); }
/* "Channels like this one": the pasted links fill the row, never wider */
.similar-urls { display: block; width: 100%; max-width: 100%; box-sizing: border-box;
  margin: 0 0 var(--sp-2); }
.why-head { margin: 0 0 var(--sp-2); font-size: var(--fs-base); }
.why-verdict { margin: 0 0 var(--sp-2); font-weight: 600; }
.why-sub { margin: var(--sp-3) 0 var(--sp-1); font-weight: 600; }
.why-list { margin: 0; padding-left: var(--sp-4); }
.why-line, .why-list > li { margin: 0 0 var(--sp-1); }
.why-quote { color: var(--text-2); }
blockquote.why-quote { margin: var(--sp-2) 0; padding-left: var(--sp-3); border-left: 2px solid var(--line); }
.why-warn { color: var(--text); font-weight: 600; }
.why-tag {
  display: inline-block; padding: 0 6px; border-radius: 999px; white-space: nowrap;
  font-size: var(--fs-xs); line-height: var(--lh-xs); font-weight: 600;
  background: var(--surface-2); color: var(--text-2); vertical-align: baseline;
}
.why-md { white-space: pre-wrap; overflow-wrap: anywhere; font-size: var(--fs-sm); }
.dir-why { margin: var(--sp-3) 0; }
.dir-why > summary { cursor: pointer; font-weight: 600; }
.dir-measured { font-weight: 600; }
.dir-measured > .dir-m-line { display: block; overflow-wrap: anywhere; }
.dir-measured > .dir-m-line.hint { font-weight: 400; }
.dir-why-link { display: inline-block; margin-top: var(--sp-1); font-weight: 400;
  color: var(--accent-text); text-decoration: underline; cursor: pointer; }

/* THE READ SCREENS: restyled, with the extras folded under their labels */
.ep-next-fold { margin: 0 0 var(--sp-6); }
.ep-read-fold { margin-top: var(--sp-4); }
.ep-read-fold .found-name { font-size: var(--fs-base); }
.ep-titles-fold { padding: 0 var(--card-pad); }
.ep-titles-fold > summary { border-top: none; padding: var(--sp-4) 0; }
.ep-titles-fold[open] { padding-bottom: var(--sp-4); }
.reader .title-alt .linkish { font-weight: 600; }

/* FIXING PROBLEMS BY ITSELF (docs/SELF_REPAIR.md §11.1 — the owner,
   2026-10-11). The "Reworded" badge on a picture CAT gave new words by
   itself: the house's neutral .badge with its pencil glyph beside the word,
   so the fact is never colour alone. On the pause's card, the line saying
   when CAT will carry on by itself wears a clock in the wait's own ink. In
   the picture viewer, a reworded picture's line goes under its narration on
   a line of its own (studio.js joins the two with a newline). */
.ep-reworded { gap: 4px; }
.ep-reworded svg { flex: none; }
.ep-auto svg { vertical-align: -2px; margin-right: 2px; color: var(--waiting-text); }
.lightbox-sub { white-space: pre-line; }
.ep-fixed li { overflow-wrap: anywhere; }
.ep-reworded-why { overflow-wrap: anywhere; }


/* WHAT WORKS (cat/web/works.js) and the episode's "How it did" card
   (cat/web/studio.js howItDidCard): the feedback loop. Small plain bars with
   their numbers written beside them; nothing is colour alone. */
.perf-line.is-measured { color: var(--text); font-weight: 600; }
.works-bars, .works-list, .works-ab { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-3); }
.works-bar-row { display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, 2fr) auto; gap: var(--sp-3); align-items: center; }
.works-bar-name { overflow-wrap: anywhere; font-size: var(--fs-sm); }
.works-bar { position: relative; display: block; height: 10px; background: var(--surface-3); border-radius: var(--r-sm); }
.works-bar-fill { position: absolute; left: 0; top: 0; bottom: 0; background: var(--accent); border-radius: var(--r-sm); }
.works-bar-med { position: absolute; top: -3px; bottom: -3px; width: 2px; background: var(--text); }
.works-bar-num { font-size: var(--fs-sm); color: var(--text-2); white-space: nowrap; font-variant-numeric: tabular-nums; }
.works-two { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-6); }
.works-ep a { font-weight: 600; overflow-wrap: anywhere; }
.works-spark { width: 100%; max-width: 280px; height: 56px; color: var(--accent-text); display: block; }
.works-trend, .works-note, .works-verdict, .ep-feedback-verdict { font-size: var(--fs-base); line-height: 1.55; overflow-wrap: anywhere; }
.works-verdict, .ep-feedback-verdict { font-weight: 600; margin-top: var(--sp-2); }
.works-switch { display: flex; flex-wrap: wrap; gap: var(--sp-4); align-items: center; }
.ep-feedback-form { display: flex; flex-direction: column; gap: var(--sp-2); align-items: flex-start; max-width: 420px; }
.ep-feedback-form .input { width: 100%; }
.ep-verdict { display: flex; flex-direction: column; gap: var(--sp-2); align-items: flex-start; max-width: 420px; margin-bottom: var(--sp-3); }
.ep-verdict .input { width: 100%; }
.ep-verdict-row { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.ep-verdict-row .btn[aria-pressed="true"] { border-color: var(--accent, currentColor); font-weight: 600; }
.taste-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-2); }
.taste-item { display: flex; gap: var(--sp-2); align-items: flex-start; justify-content: space-between; flex-wrap: wrap; padding: var(--sp-2) 0; border-bottom: 1px solid var(--line, rgba(127,127,127,.25)); }
.taste-item-text { flex: 1 1 220px; min-width: 0; overflow-wrap: anywhere; }
.taste-item-text p { margin: 2px 0; }
.ep-feedback-ab { list-style: none; padding: 0; margin: 0 0 var(--sp-2); font-size: var(--fs-sm); }
@media (max-width: 560px) {
  .works-two { grid-template-columns: minmax(0, 1fr); }
  .works-bar-row { grid-template-columns: minmax(0, 1fr) auto; }
  .works-bar-row .works-bar { grid-column: 1 / -1; grid-row: 2; }
}

/* THE FILM READ — a scene board (cat/web/studio.js filmBoardArticle).
   Cards in order; "what we see" leads, "what we hear" is small. Every width
   is a share of its column, so a 375px phone never scrolls sideways. */
.film-board { min-width: 0; }
.film-runtime { display: flex; gap: 2px; width: 100%; height: 14px; margin: 14px 0 6px;
  border-radius: 4px; overflow: hidden; }
.film-runtime-block { display: block; min-width: 2px; height: 100%; background: var(--border); }
.film-runtime-chapter { background: var(--accent); }
.film-review { margin: 10px 0 0; }
.film-cards { list-style: none; margin: 16px 0 0; padding: 0; display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr)); }
.film-card { border: 1px solid var(--border); border-radius: 10px; padding: 12px 14px;
  min-width: 0; overflow-wrap: anywhere; }
.film-card-head { display: flex; flex-wrap: wrap; gap: 6px 10px; align-items: baseline;
  margin-bottom: 8px; font-size: 13px; }
.film-card-no { font-weight: 700; }
.film-card-secs { color: var(--text-3); font-variant-numeric: tabular-nums; }
.film-card-chapter { padding: 1px 8px; border-radius: 999px; background: var(--surface-2);
  font-size: 12px; }
.film-card-still { display: block; width: 100%; height: auto; border-radius: 6px; margin-bottom: 8px; }
.film-card-pair { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; margin-bottom: 4px; }
.film-card-pair figure { margin: 0; min-width: 0; }
.film-card-pair figcaption { font-size: 11.5px; margin: -4px 0 4px; }
.film-card-style { font-size: 12.5px; margin: 0 0 6px; color: var(--text-3); }
.film-card-style-off { color: var(--failed-text); font-weight: 600; }
.film-unmatched { margin: 10px 0 0; font-weight: 600; }
.film-text-door { margin: 10px 0 0; }
.film-card-see { font-size: 16px; line-height: 1.45; margin: 2px 0 6px; }
.film-card-moves { font-size: 13px; margin: 0 0 6px; }
.film-card-onscreen { font-size: 14px; margin: 0 0 6px; }
.film-card-hear { font-size: 12.5px; color: var(--text-3); margin: 0 0 4px; }
.film-card-who { font-size: 12.5px; margin: 0; }

/* A DIALOGUE MICRO-DRAMA's read and cast stop (docs/CAS_PORT_PLAN.md Phase 1).
   Laid out for 375 px: nothing wider than its column, long words broken. */
.drama-read .drama-logline { font-style: italic; margin: 8px 0; }
.drama-scene { border-top: 1px solid var(--line, #ddd); margin-top: 14px; padding-top: 10px; }
.drama-heading { font-family: ui-monospace, Menlo, monospace; font-size: 13px; letter-spacing: .02em; margin: 0 0 6px; }
.drama-card { display: grid; grid-template-columns: 1fr; gap: 2px; margin: 0 0 8px; font-size: 13px; }
.drama-card div { display: flex; gap: 6px; flex-wrap: wrap; }
.drama-card dt { font-weight: 600; min-width: 70px; }
.drama-card dd { margin: 0; flex: 1 1 160px; min-width: 0; overflow-wrap: anywhere; }
.drama-line { margin: 8px 0; }
.drama-said { margin: 0; overflow-wrap: anywhere; }
.drama-who { text-transform: uppercase; font-size: 12px; letter-spacing: .04em; }
.drama-shots { margin: 4px 0 0 12px; padding: 0; list-style: none; font-size: 13px; }
.drama-shots li { overflow-wrap: anywhere; }
.drama-shot-kind { font-weight: 600; }
.drama-cast-list { margin: 4px 0 8px; padding-left: 18px; }
.drama-fountain { white-space: pre-wrap; overflow-wrap: anywhere; max-width: 100%; font-size: 12px; }
.cast-grid { list-style: none; padding: 0; margin: 8px 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 12px; }
.cast-card { min-width: 0; overflow-wrap: anywhere; }
.cast-passport { width: 100%; height: auto; border-radius: 8px; display: block; margin-bottom: 6px; }
.cast-identity, .cast-voice { font-size: 13px; margin: 4px 0; }

/* THE SHOT DIRECTOR (studio.js shotDirectorCard, owner 2026-10-26): a
   shot's words read as written, wrapped, never scrolled sideways */
.shot-clip { margin: 0 0 12px; }
.shot-clip > summary { cursor: pointer; }
.shot-body { margin-top: 8px; }
.shot-parts { margin: 0; }
.shot-parts dt { font-weight: 600; margin-top: 8px; }
.shot-parts dd { margin: 2px 0 0; }
.shot-text { white-space: pre-wrap; overflow-wrap: anywhere; margin: 0; font-size: 13px; line-height: 1.45; }
.shot-actions, .shot-direct { margin-top: 10px; }
.shot-note { width: 100%; box-sizing: border-box; margin-bottom: 6px; }
.shot-diff { margin-top: 8px; }
