/* ---- ui/tokens.css ---- */
/* Kindling — src/ui/tokens.css  (v1.1, matches DESIGN.md v1.1 + review fixes)
   Canonical code token file. The only file allowed to contain hex/rgb colors, font families, or px type sizes.
   Layers: primitive → semantic (--color-*, --font-*, --space-*) → component (--button-*, --input-*, --pill-*, --table-*).
   Components reference semantic or component tokens only.
   Parent brand: Campfire Brand Guidelines v1.0 (May 2025), Figma FrVgaQ74gOz6Tn5Pwj44O5. */

:root {
  /* ============ PRIMITIVES ============ */
  /* Campfire parent palette (inherited, verbatim) */
  --primitive-orange: #FF3F01;      --primitive-off-white: #F2ECE7;   --primitive-white: #FFFFFF;
  --primitive-light-brown: #C49B86; --primitive-black: #000000;       --primitive-light-gray: #F5F5F5;
  --primitive-tan: #D29A54;         --primitive-light-yellow: #FFFAA2; --primitive-brown: #531F10;
  --primitive-red-rock: #C06E4A;    --primitive-sand: #EBD5BB;        --primitive-cacti-green: #75751F;
  --primitive-yellow: #FDFD02;
  /* Parent gradients — functional CSS bands; use approved background assets for high-expression moments */
  --primitive-gradient-flame-tri: linear-gradient(180deg, #FF3F01 0%, #FF7700 55%, #FFFAA2 100%);
  --primitive-gradient-flame-duo: linear-gradient(180deg, #FF3F01 0%, #FF7700 100%);
  --primitive-gradient-leather:   linear-gradient(180deg, #D9A15C 0%, #C58A42 100%);

  /* Kindling product primitives (functional extensions, DESIGN.md §5.2) */
  --primitive-ink-900: #1C1512; --primitive-ink-700: #4A3B34; --primitive-ink-500: #6F5D54; --primitive-ink-300: #B8A99F;
  --primitive-warm-050: #FAF8F5; --primitive-warm-100: #F2ECE7; --primitive-warm-200: #E9E0D8;
  --primitive-warm-300: #DCCFC4; --primitive-warm-500: #8F7A6E;
  --primitive-ember-900: #A32600; --primitive-ember-800: #B52B00; --primitive-ember-700: #C93000; --primitive-ember-600: #E23600; --primitive-ember-550: #F53B00;
  --primitive-ember-500: #FF3F01; --primitive-ember-100: #FFE8DD; --primitive-ember-050: #FFF3EE;
  --primitive-ok-600: #5B6318;   --primitive-ok-100: #ECEBD3;
  --primitive-warn-600: #805417; --primitive-warn-100: #F7ECD7;
  --primitive-bad-600: #A3391F;  --primitive-bad-100: #F7DED4;
  --primitive-info-600: #6B5045; --primitive-info-100: #EFE4DC;
  --primitive-dark-ground: #16110F; --primitive-dark-panel: #1F1917; --primitive-dark-raised: #2A2320;
  --primitive-dark-line: #3A312C;   --primitive-dark-line-interactive: #9A897D;
  --primitive-dark-ink: #F2ECE7;    --primitive-dark-ink-2: #C9BBB0;  --primitive-dark-ink-3: #9E8C80; --primitive-dark-ink-disabled: #5E524A;
  /* dark-ink-3 was #8F7F74 (4.51:1 on panel, but 4.01:1 on raised where table headers sit). #9A897D: 5.17 panel · 4.6 raised · 5.9 ground. Decision 0003. */
  --primitive-ember-dark: #FF5A24;  --primitive-ember-dark-hover: #FF6A3A; --primitive-ember-dark-action: #D43300; --primitive-ember-dark-tint: #4A2114; --primitive-ember-dark-wash: #2E1A13;
  --primitive-ok-dark: #A7B24A;   --primitive-ok-dark-tint: #2A2E15;
  --primitive-warn-dark: #E0A54F; --primitive-warn-dark-tint: #332612;
  --primitive-bad-dark: #E8735A;  --primitive-bad-dark-tint: #3A1C15;
  --primitive-info-dark: #C9A38E; --primitive-info-dark-tint: #2E2521;

  /* ============ SEMANTIC — LIGHT (default) ============ */
  --color-surface-ground: var(--primitive-warm-100);
  --color-surface-panel: var(--primitive-white);
  --color-surface-well: var(--primitive-warm-050);
  --color-surface-overlay: var(--primitive-white);
  --color-line-subtle: var(--primitive-warm-200);        /* nonessential grouping only */
  --color-line-default: var(--primitive-warm-300);       /* quiet card boundaries */
  --color-line-interactive: var(--primitive-warm-500);   /* inputs, controls — ≥3:1 on ground and panel */

  --color-ink: var(--primitive-ink-900);
  --color-ink-secondary: var(--primitive-ink-700);
  --color-ink-tertiary: var(--primitive-ink-500);
  --color-ink-disabled: var(--primitive-ink-300);        /* decoration only; never meaningful text */
  --color-ink-inverse: var(--primitive-white);

  --color-brand: var(--primitive-ember-500);             /* mark, marker, focus, selection accent, bands */
  --color-brand-strong: var(--primitive-ember-700);      /* orange as small text; strong action variant */
  --color-brand-tint: var(--primitive-ember-100);
  --color-brand-wash: var(--primitive-ember-050);

  --color-action-primary: var(--primitive-ember-700);          /* deep ember + white label = 5.38:1 (DESIGN 1.4 §3.2) */
  --color-action-primary-hover: var(--primitive-ember-800);    /* + white = 6.34:1 */
  --color-action-primary-edge: var(--primitive-ember-900);     /* the one-pixel rim inside the button */
  --color-on-action-primary: var(--primitive-white);
  /* Retired in 1.4: the "strong" variant is the primary now. Aliases stay so nothing old breaks. */
  --color-action-primary-strong: var(--color-action-primary);
  --color-action-primary-strong-hover: var(--color-action-primary-hover);
  --color-on-action-primary-strong: var(--color-on-action-primary);

  --color-ok: var(--primitive-ok-600);     --color-ok-tint: var(--primitive-ok-100);
  --color-warn: var(--primitive-warn-600); --color-warn-tint: var(--primitive-warn-100);
  --color-bad: var(--primitive-bad-600);   --color-bad-tint: var(--primitive-bad-100);
  --color-info: var(--primitive-info-600); --color-info-tint: var(--primitive-info-100);
  --color-neutral: var(--primitive-ink-700); --color-neutral-tint: var(--primitive-warm-050);

  --color-focus: var(--primitive-ember-500);             /* 3.01:1 on off-white, 3.52:1 on white */
  --color-selection: var(--primitive-ember-100);

  --shadow-1: 0 1px 2px rgb(83 31 16 / .06), 0 1px 1px rgb(83 31 16 / .04);
  --shadow-2: 0 8px 24px rgb(83 31 16 / .12), 0 2px 6px rgb(83 31 16 / .06);

  --color-chart-1: var(--primitive-ember-500); --color-chart-2: var(--color-ink-tertiary); /* second series: neutral, ≥3:1 on the well in both themes */
  --color-chart-3: var(--primitive-cacti-green); --color-chart-4: var(--primitive-red-rock);
  --color-chart-5: var(--primitive-brown); --color-chart-6: var(--primitive-light-brown);
  --color-chart-grid: var(--primitive-warm-200);

  /* Expressive bands (Present / Guide modes only). Text on a band is --color-ink (6.8:1 at the weakest stop);
     white on a band is reserved for the Campfire mark. */
  --gradient-band: var(--primitive-gradient-flame-duo);
  --gradient-band-open: var(--primitive-gradient-flame-tri);   /* nothing sits on it */
  --color-on-band: var(--primitive-ink-900);

  /* ============ TYPE ============ */
  --font-display: "Migra", "Fraunces", Georgia, serif;
  --font-title: "neue-haas-grotesk-display", "Neue Haas Grotesk Display", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --font-ui: "neue-haas-grotesk-text", "Neue Haas Grotesk Text", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --font-code: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;   /* identifiers/code only */

  --text-2xs: 11px; --leading-2xs: 16px;
  --text-xs: 12px;  --leading-xs: 16px;
  --text-sm: 13px;  --leading-sm: 18px;
  --text-base: 14px; --leading-base: 20px;
  --text-md: 16px;  --leading-md: 24px;
  --text-lg: 18px;  --leading-lg: 26px;
  --text-xl: 22px;  --leading-xl: 28px;
  --text-2xl: 28px; --leading-2xl: 34px;
  --text-3xl: 40px; --leading-3xl: 44px;
  --text-4xl: 56px; --leading-4xl: 58px;
  --tracking-label: .06em;
  --weight-regular: 400; --weight-medium: 500; --weight-strong: 600; --weight-title: 700;

  /* ============ SPACE · SHAPE · MOTION ============ */
  --space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px; --space-5: 20px; --space-6: 24px;
  --space-8: 32px; --space-10: 40px; --space-12: 48px; --space-16: 64px;
  --radius-control: 8px; --radius-card: 12px; --radius-band: 16px; --radius-pill: 999px;
  --duration-fast: 120ms; --duration-standard: 160ms; --duration-deliberate: 240ms;
  --easing-standard: cubic-bezier(.2, .8, .2, 1);

  /* ============ LAYOUT ============ */
  --layout-rail: 56px; --layout-rail-expanded: 220px; --layout-topbar: 52px; --layout-drawer: 560px; --layout-dialog: 480px;
  --layout-portal-column: 480px; --layout-prose: 720px; --layout-evidence: 1120px;
  --measure-prose: 68ch; --measure-drawer: 60ch;
  --target-min: 44px;

  /* ============ COMPONENT TOKENS ============ */
  /* Control anatomy (DESIGN 1.4 §7): height 36 (28 sm, 44 lg/touch), padding 0 14,
     `inset 0 0 0 1px` rim + `inset 0 1px 0` highlight, translateY(.5px) on press. */
  --button-height: 36px; --button-height-small: 28px; --button-height-touch: 44px;
  --button-radius: var(--radius-control); --button-radius-small: 6px; --button-radius-touch: 10px;
  --button-padding-x: 14px; --button-padding-x-small: 10px; --button-padding-x-touch: 18px;
  --button-press: .5px;
  --button-primary-bg: var(--color-action-primary); --button-primary-bg-hover: var(--color-action-primary-hover);
  --button-primary-fg: var(--color-on-action-primary); --button-primary-edge: var(--color-action-primary-edge);
  /* Object anatomy (DESIGN 1.4 §3.3): a one-pixel darker rim, a one-pixel top highlight, a half-pixel press. */
  --button-highlight: rgb(255 255 255 / .28); --shadow-button: 0 1px 1px rgb(83 31 16 / .06);
  --button-press-shadow: inset 0 1px 2px rgb(83 31 16 / .18);
  --button-primary-strong-bg: var(--color-action-primary-strong); --button-primary-strong-bg-hover: var(--color-action-primary-strong-hover);
  --button-primary-strong-fg: var(--color-on-action-primary-strong);
  /* Secondary is a sheet with a quiet rim; its label carries the contrast, so the rim is
     `line-default` and only firms up to `line-interactive` on hover (DESIGN 1.4 §9 Buttons). */
  --button-secondary-bg: var(--color-surface-panel); --button-secondary-border: var(--color-line-default);
  --button-secondary-border-hover: var(--color-line-interactive); --button-secondary-fg: var(--color-ink);
  --button-ghost-fg: var(--color-ink-secondary); --button-ghost-bg-hover: var(--color-brand-wash);
  --button-destructive-fg: var(--color-bad); --button-destructive-border: var(--color-bad);
  --segmented-height: 32px; --segmented-item-height: 28px; --segmented-radius: var(--radius-control); --segmented-item-radius: 6px;

  --input-height: 36px; --input-height-touch: 44px; --input-height-small: 28px; --input-radius: var(--radius-control);
  --input-bg: var(--color-surface-panel); --input-border: var(--color-line-interactive); --input-fg: var(--color-ink);
  --input-placeholder: var(--color-ink-tertiary); --input-border-error: var(--color-bad);
  --input-padding-x: 12px;
  /* Input focus is its own thing (DESIGN 1.4 §9 Inputs / §9d): an ink border with a 3px
     brand-wash halo, not the §7 outline ring. Both are documented in base.css. */
  --input-focus-border: var(--color-ink); --input-focus-halo: 3px; --input-focus-halo-color: var(--color-brand-wash);
  --input-error-halo-color: var(--color-bad-tint);
  /* Checkbox / radio 16 with an ink fill; switch 34×20 with `ok` on (DESIGN 1.4 §9 Inputs). */
  --control-box: 16px; --control-box-touch: 20px;
  --control-fill: var(--color-ink); --control-mark: var(--color-ink-inverse);
  --switch-width: 34px; --switch-height: 20px; --switch-thumb: 14px;
  --switch-width-touch: 40px; --switch-height-touch: 24px; --switch-thumb-touch: 18px;
  --switch-on-bg: var(--color-ok); --switch-off-bg: var(--color-surface-well);

  /* Overlays (DESIGN 1.4 §9 Overlays): menus radius 10 / 4px padding / 32px items,
     dialogs behind a 35% ink backdrop, drawers a second sheet inset 8 with shadow-2. */
  --menu-radius: 10px; --menu-padding: 4px; --menu-item-height: 32px; --menu-item-padding-x: 10px;
  --overlay-scrim: color-mix(in srgb, var(--color-ink) 35%, transparent);
  --sheet-inset: 8px;
  /* Breakpoints (docs/decisions/0014-responsive.md). Custom properties cannot drive @media, so the
     numbers are literal in every stylesheet: phone ≤ 720, narrow 721–1024, desktop above. */
  /* Phone shell (0014): the rail becomes a 56px bottom bar. Anything fixed to the bottom of the
     sheet — the bulk strip, toasts, a bottom sheet — sits above it via `--shell-bottom-bar`, which
     the shell sets to this on a phone and leaves 0 elsewhere (the portal and client pages have no bar). */
  --layout-rail-bar: 56px;
  --shell-bottom-bar: 0px;
  /* A button under a coarse pointer (0014 pattern 8): 40 in the team app. `--button-height-touch`
     (44) is the portal's own floor (DESIGN §8) and stays where it is. */
  --button-height-coarse: 40px;

  /* Sign-in photograph (DESIGN §7). The one screen with an image. The ground beneath it is a dark
     blue that passes every text pair on its own, so a failed load is still a legible page; the
     scrims are the dark ground's rgb triplet at measured alphas; the button is the dark-theme
     ember because the light one reads 2.98:1 against the teal. Measured to this picture. */
  --signin-column: 400px;
  --signin-ground: #0B212D;
  --signin-scrim-rgb: 22 17 15;
  --signin-scrim-radial: radial-gradient(78% 72% at 50% 48%, rgb(22 17 15 / 0.62) 0%, rgb(22 17 15 / 0.46) 46%, rgb(22 17 15 / 0.18) 74%, rgb(22 17 15 / 0) 100%);
  --signin-scrim-band: linear-gradient(180deg, rgb(22 17 15 / 0) 82%, rgb(22 17 15 / 0.88) 100%);
  --signin-scrim-radial-narrow: radial-gradient(120% 62% at 50% 46%, rgb(22 17 15 / 0.72) 0%, rgb(22 17 15 / 0.54) 52%, rgb(22 17 15 / 0.24) 80%, rgb(22 17 15 / 0) 100%);
  --signin-scrim-band-narrow: linear-gradient(180deg, rgb(22 17 15 / 0) 78%, rgb(22 17 15 / 0.9) 100%);
  --signin-ink: var(--primitive-off-white);
  --signin-line: #DCD1C7;
  --signin-hint: #BFB0A5;
  --signin-hint-strong: #E4DAD1;
  --signin-foot: #A8988C;
  --signin-button: var(--primitive-ember-dark-action);
  --signin-button-hover: var(--primitive-ember-700);
  --signin-button-edge: var(--primitive-ember-800);
  --signin-button-highlight: rgb(255 255 255 / 0.22);
  --signin-button-shadow: 0 6px 20px rgb(0 0 0 / 0.35);
  --signin-note-info-bg: rgb(242 236 231 / 0.12); --signin-note-info: #E4DAD1;
  --signin-note-warn-bg: rgb(214 160 60 / 0.16);  --signin-note-warn: #F0D9A8;
  --signin-note-bad-bg: rgb(214 90 60 / 0.18);    --signin-note-bad: #F5C3B4;

  --pill-height: 22px; --pill-radius: var(--radius-pill); --pill-text: var(--text-xs); --pill-padding-x: var(--space-2);

  --table-row-comfortable: 40px; --table-row-compact: 32px;
  --table-header-bg: var(--color-surface-well); --table-header-fg: var(--color-ink-tertiary);
  --table-row-hover-bg: var(--color-surface-well); --table-row-selected-bg: var(--color-selection);
  --table-row-selected-marker: var(--color-brand); --table-rule: var(--color-line-subtle);
  --table-cell-padding-x: var(--space-3); --table-cell-padding-y: var(--space-1);

  --nav-active-marker: var(--color-brand); --nav-active-bg: var(--color-brand-wash);
  --avatar-sm: 24px; --avatar-md: 40px; --avatar-lg: 56px;

  color-scheme: light;
}

/* ============ SEMANTIC — DARK (team app) ============
   Explicit choice wins; a guarded system preference may set the team-app default.
   Portal and client pages are light in v1: they set data-theme="light" on <html>. */
@media (prefers-color-scheme: dark) {
  :root[data-surface="app"]:not([data-theme="light"]) {
    --color-surface-ground: var(--primitive-dark-ground); --color-surface-panel: var(--primitive-dark-panel);
    --color-surface-well: var(--primitive-dark-raised); --color-surface-overlay: var(--primitive-dark-raised);
    --color-line-subtle: var(--primitive-dark-line); --color-line-default: var(--primitive-dark-line);
    --color-line-interactive: var(--primitive-dark-line-interactive);   /* 5.17:1 on panel, 4.6:1 on raised */
    --color-ink: var(--primitive-dark-ink); --color-ink-secondary: var(--primitive-dark-ink-2);
    --color-ink-tertiary: var(--primitive-dark-ink-3); --color-ink-disabled: var(--primitive-dark-ink-disabled);
    --color-ink-inverse: var(--primitive-dark-ground);
    --color-brand: var(--primitive-ember-dark); --color-brand-strong: #FF7A50;
    --color-brand-tint: var(--primitive-ember-dark-tint); --color-brand-wash: var(--primitive-ember-dark-wash);
    --color-action-primary: var(--primitive-ember-dark-action); --color-action-primary-hover: var(--primitive-ember-700);
    --color-action-primary-edge: var(--primitive-ember-800);
    --color-on-action-primary: var(--primitive-white);                  /* 4.91:1 on #D43300 */
    --color-action-primary-strong: var(--color-action-primary); --color-action-primary-strong-hover: var(--color-action-primary-hover);
    --color-on-action-primary-strong: var(--color-on-action-primary);
    --color-ok: var(--primitive-ok-dark); --color-ok-tint: var(--primitive-ok-dark-tint);
    --color-warn: var(--primitive-warn-dark); --color-warn-tint: var(--primitive-warn-dark-tint);
    --color-bad: var(--primitive-bad-dark); --color-bad-tint: var(--primitive-bad-dark-tint);
    --color-info: var(--primitive-info-dark); --color-info-tint: var(--primitive-info-dark-tint);
    --color-neutral: var(--primitive-dark-ink-2); --color-neutral-tint: var(--primitive-dark-raised);
    --color-focus: var(--primitive-ember-dark); --color-selection: var(--primitive-ember-dark-tint);
    --button-highlight: rgb(255 255 255 / .12); --shadow-button: 0 1px 1px rgb(0 0 0 / .4);
    --shadow-1: 0 1px 2px rgb(0 0 0 / .5), 0 1px 1px rgb(0 0 0 / .3);
    --shadow-2: 0 8px 24px rgb(0 0 0 / .6), 0 2px 6px rgb(0 0 0 / .4);
    --color-chart-5: var(--primitive-info-dark); --color-chart-grid: var(--primitive-dark-line);
    color-scheme: dark;
  }
}
:root[data-theme="dark"] {
  --color-surface-ground: var(--primitive-dark-ground); --color-surface-panel: var(--primitive-dark-panel);
  --color-surface-well: var(--primitive-dark-raised); --color-surface-overlay: var(--primitive-dark-raised);
  --color-line-subtle: var(--primitive-dark-line); --color-line-default: var(--primitive-dark-line);
  --color-line-interactive: var(--primitive-dark-line-interactive);
  --color-ink: var(--primitive-dark-ink); --color-ink-secondary: var(--primitive-dark-ink-2);
  --color-ink-tertiary: var(--primitive-dark-ink-3); --color-ink-disabled: var(--primitive-dark-ink-disabled);
  --color-ink-inverse: var(--primitive-dark-ground);
  --color-brand: var(--primitive-ember-dark); --color-brand-strong: #FF7A50;
  --color-brand-tint: var(--primitive-ember-dark-tint); --color-brand-wash: var(--primitive-ember-dark-wash);
  --color-action-primary: var(--primitive-ember-dark-action); --color-action-primary-hover: var(--primitive-ember-700);
  --color-action-primary-edge: var(--primitive-ember-800);
  --color-on-action-primary: var(--primitive-white);
  --color-action-primary-strong: var(--color-action-primary); --color-action-primary-strong-hover: var(--color-action-primary-hover);
  --color-on-action-primary-strong: var(--color-on-action-primary);
  --color-ok: var(--primitive-ok-dark); --color-ok-tint: var(--primitive-ok-dark-tint);
  --color-warn: var(--primitive-warn-dark); --color-warn-tint: var(--primitive-warn-dark-tint);
  --color-bad: var(--primitive-bad-dark); --color-bad-tint: var(--primitive-bad-dark-tint);
  --color-info: var(--primitive-info-dark); --color-info-tint: var(--primitive-info-dark-tint);
  --color-neutral: var(--primitive-dark-ink-2); --color-neutral-tint: var(--primitive-dark-raised);
  --color-focus: var(--primitive-ember-dark); --color-selection: var(--primitive-ember-dark-tint);
  --shadow-1: 0 1px 2px rgb(0 0 0 / .5), 0 1px 1px rgb(0 0 0 / .3);
  --shadow-2: 0 8px 24px rgb(0 0 0 / .6), 0 2px 6px rgb(0 0 0 / .4);
  --color-chart-5: var(--primitive-info-dark); --color-chart-grid: var(--primitive-dark-line);
  color-scheme: dark;
}

/* ============ WHITE-LABEL (approved themes only; values come from the tenant record) ============ */
:root[data-tenant] { --gradient-band: var(--primitive-gradient-leather); }

/* ============ BASE ============ */
/* Focus and motion live in base.css (DESIGN 1.4 §7 focus, §9a motion) — this file is values only. */
html { background: var(--color-surface-ground); color: var(--color-ink); font-family: var(--font-ui);
       font-size: var(--text-base); line-height: var(--leading-base); -webkit-font-smoothing: antialiased; }

/* ============ GALLERY TEST MODES (M0 addition — see docs/BUILD_LOG.md) ============ */
/* Fonts blocked: what renders when the licensed webfonts fail to load. Toggle on /design. */
:root[data-fonts="blocked"] {
  --font-display: "Fraunces", Georgia, serif;
  --font-title: "Helvetica Neue", Helvetica, Arial, sans-serif;
  --font-ui: "Helvetica Neue", Helvetica, Arial, sans-serif;
}
/* Forced-colors approximation for the /design toggle (system color keywords only).
   Real forced-colors mode is exercised by gallery:check via Playwright emulation. */
:root[data-forced-colors="active"] {
  --color-surface-ground: Canvas; --color-surface-panel: Canvas; --color-surface-well: Canvas; --color-surface-overlay: Canvas;
  --color-line-subtle: CanvasText; --color-line-default: CanvasText; --color-line-interactive: CanvasText;
  --color-ink: CanvasText; --color-ink-secondary: CanvasText; --color-ink-tertiary: CanvasText; --color-ink-disabled: GrayText; --color-ink-inverse: Canvas;
  --color-brand: Highlight; --color-brand-strong: Highlight; --color-brand-tint: Canvas; --color-brand-wash: Canvas;
  --color-action-primary: ButtonFace; --color-action-primary-hover: ButtonFace; --color-on-action-primary: ButtonText;
  --color-action-primary-strong: ButtonFace; --color-action-primary-strong-hover: ButtonFace; --color-on-action-primary-strong: ButtonText;
  --color-ok: CanvasText; --color-ok-tint: Canvas; --color-warn: CanvasText; --color-warn-tint: Canvas;
  --color-bad: CanvasText; --color-bad-tint: Canvas; --color-info: CanvasText; --color-info-tint: Canvas;
  --color-neutral: CanvasText; --color-neutral-tint: Canvas;
  --color-focus: Highlight; --color-selection: Highlight;
  --shadow-1: none; --shadow-2: none;
  --gradient-band: Canvas; --gradient-band-open: Canvas; --color-on-band: CanvasText;
  --color-chart-1: CanvasText; --color-chart-2: CanvasText; --color-chart-3: CanvasText;
  --color-chart-4: CanvasText; --color-chart-5: CanvasText; --color-chart-6: CanvasText; --color-chart-grid: GrayText;
}


/* ---- ui/base.css ---- */
/* Kindling — base.css: reset, base typography, focus, motion, forced-colors. Tokens only. */

*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html { text-size-adjust: 100%; -moz-text-size-adjust: 100%; -webkit-text-size-adjust: 100%; }
body { min-height: 100dvh; background: var(--color-surface-ground); color: var(--color-ink); }
img, svg, video, canvas { display: block; max-width: 100%; }
button, input, select, textarea { font: inherit; color: inherit; letter-spacing: inherit; }
button { background: none; border: 0; padding: 0; cursor: pointer; text-align: inherit; }
button:disabled { cursor: not-allowed; }
a { color: inherit; text-decoration-thickness: 1px; text-underline-offset: 2px; text-decoration-color: var(--color-line-interactive); }
a:hover { text-decoration-color: currentColor; }
ul, ol { padding-inline-start: 0; list-style: none; }
table { border-collapse: collapse; border-spacing: 0; }
hr { border: 0; border-top: 1px solid var(--color-line-subtle); }
:focus:not(:focus-visible) { outline: none; }
::placeholder { color: var(--input-placeholder); opacity: 1; }
::selection { background: var(--color-selection); }

/* ============ FOCUS ============
   Kindling has two focus treatments and they are not interchangeable.

   1. The ring (DESIGN §7, §9d "a visible focus ring"): 2px `--color-focus`, 2px offset. This is
      the floor for everything you can focus — buttons, links, tabs, menu items, rows, the rail.
      It sits *outside* the control, so it never changes the control's size.
   2. The field (DESIGN §9 Inputs, §9d "2px ink + 3px brand wash"): a text field trades the ring
      for an ink border plus a 3px `--color-brand-wash` halo, because a bordered box already has
      an edge and an outline around it reads as a second box. Inputs, textareas, selects and the
      adorned `.input-group` use it; nothing else does.

   Forced colors falls back to `CanvasText`, which both treatments respect. */
:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }
@media (forced-colors: active) { :focus-visible { outline: 2px solid CanvasText; } }

/* ============ MOTION (DESIGN §9a) ============
   Three durations, one curve; exits at 0.75×. `prefers-reduced-motion` collapses every duration
   to 1ms — not "less", none — while leaving static transforms (a rotated pin icon, a switch thumb
   at its end position) alone, because those carry state rather than motion. */
/* Overlays enter from where they came from and travel at most 8px: a menu or popover fades in
   with a 2% scale (DESIGN §9a). Shared so the rail menus, the Popover component and the command
   palette all use the same one. */
@keyframes overlay-pop { from { opacity: 0; transform: translateY(-4px) scale(.98); } }
@keyframes overlay-fade { from { opacity: 0; } }
@keyframes overlay-rise { from { opacity: 0; transform: translateY(8px); } }
@keyframes overlay-slide-end { from { opacity: 0; transform: translateX(8px); } }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: 1ms !important;
    transition-delay: 0ms !important;
    animation-duration: 1ms !important;
    animation-delay: 0ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
  }
}

/* Base typography (DESIGN.md §6) */
h1, h2, h3, h4 { font-weight: var(--weight-medium); text-wrap: balance; }
h1 { font-family: var(--font-title); font-size: var(--text-xl); line-height: var(--leading-xl); }
h2 { font-family: var(--font-title); font-size: var(--text-lg); line-height: var(--leading-lg); }
h3 { font-size: var(--text-base); line-height: var(--leading-base); }
h4 { font-size: var(--text-sm); line-height: var(--leading-sm); }
p { text-wrap: pretty; }
small { font-size: var(--text-xs); line-height: var(--leading-xs); }
strong, b { font-weight: var(--weight-medium); }
code, kbd, samp { font-family: var(--font-code); font-size: var(--text-xs); }
kbd { display: inline-block; padding: 0 var(--space-1); border: 1px solid var(--color-line-default); border-radius: var(--radius-control); line-height: var(--leading-xs); background: var(--color-surface-well); }

/* Type utilities — one per scale step, one per face */
.t-display { font-family: var(--font-display); font-weight: var(--weight-regular); }
.t-title { font-family: var(--font-title); font-weight: var(--weight-medium); }
.t-ui { font-family: var(--font-ui); }
.t-2xs { font-size: var(--text-2xs); line-height: var(--leading-2xs); }
.t-xs { font-size: var(--text-xs); line-height: var(--leading-xs); }
.t-sm { font-size: var(--text-sm); line-height: var(--leading-sm); }
.t-base { font-size: var(--text-base); line-height: var(--leading-base); }
.t-md { font-size: var(--text-md); line-height: var(--leading-md); }
.t-lg { font-size: var(--text-lg); line-height: var(--leading-lg); }
.t-xl { font-size: var(--text-xl); line-height: var(--leading-xl); }
.t-2xl { font-size: var(--text-2xl); line-height: var(--leading-2xl); }
.t-3xl { font-size: var(--text-3xl); line-height: var(--leading-3xl); }
.t-4xl { font-size: var(--text-4xl); line-height: var(--leading-4xl); }
.t-label { font-size: var(--text-2xs); line-height: var(--leading-2xs); font-weight: var(--weight-medium); text-transform: uppercase; letter-spacing: var(--tracking-label); color: var(--color-ink-tertiary); }
.t-medium { font-weight: var(--weight-medium); }
.t-strong { font-weight: var(--weight-strong); }
.tnum, [data-tnum] { font-variant-numeric: tabular-nums; }
.ink-2 { color: var(--color-ink-secondary); }
.ink-3 { color: var(--color-ink-tertiary); }
.measure-prose { max-width: var(--measure-prose); }
.measure-drawer { max-width: var(--measure-drawer); }
.truncate { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
/* Long unbroken strings — emails, URLs, handles — break rather than widen the page (0014 pattern 1). */
.wrap-anywhere { overflow-wrap: anywhere; }

/* Accessibility helpers */
.visually-hidden { position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0; }
.skip-link { position: absolute; left: var(--space-4); top: -100px; z-index: 100; padding: var(--space-2) var(--space-3); background: var(--color-surface-panel); border: 1px solid var(--color-line-interactive); border-radius: var(--radius-control); }
.skip-link:focus { top: var(--space-4); }

/* Layout primitives */
.stack { display: flex; flex-direction: column; gap: var(--space-4); }
.stack-2 { display: flex; flex-direction: column; gap: var(--space-2); }
.stack-6 { display: flex; flex-direction: column; gap: var(--space-6); }
.row { display: flex; align-items: center; gap: var(--space-2); }
.row-3 { display: flex; align-items: center; gap: var(--space-3); }
.row-4 { display: flex; align-items: center; gap: var(--space-4); }
.wrap { flex-wrap: wrap; }
.grow { flex: 1 1 auto; min-width: 0; }
.right { margin-inline-start: auto; }
.center { text-align: center; }

/* Forced colors: keep meaning without color */
@media (forced-colors: active) {
  a { text-decoration: underline; }
  .skip-link { forced-color-adjust: none; }
}


/* ---- ui/components/_icons.css ---- */
.icon { flex: 0 0 auto; vertical-align: middle; }


/* ---- ui/components/avatar.css ---- */
/* Avatar — 24 / 40 / 56 */
.avatar { display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto; border-radius: var(--radius-pill); object-fit: cover; background: var(--color-surface-well); box-shadow: inset 0 0 0 1px var(--color-line-subtle); }
.avatar-sm { width: var(--avatar-sm); height: var(--avatar-sm); font-size: var(--text-2xs); }
.avatar-md { width: var(--avatar-md); height: var(--avatar-md); font-size: var(--text-sm); }
.avatar-lg { width: var(--avatar-lg); height: var(--avatar-lg); font-size: var(--text-lg); }
.avatar-initials { color: var(--color-ink-secondary); font-weight: var(--weight-medium); letter-spacing: 0.02em; user-select: none; }
@media (forced-colors: active) { .avatar { border: 1px solid CanvasText; } }


/* ---- ui/components/band.css ---- */
/* Band — DESIGN.md §5.6 and decision 0002. The one expressive surface on Present and
   Guide pages: at most one per page or message (brand guide §7.4). Text on a band is
   --color-on-band (ink, 6.8:1 at the weakest gradient stop); white belongs to the Campfire
   mark alone. The team app never uses this. Tokens only. */

.band {
  display: flex; flex-direction: column; gap: var(--space-3);
  padding: var(--space-10);
  background: var(--gradient-band); color: var(--color-on-band);
  border-radius: var(--radius-band);
}
.band-cover { padding: var(--space-16) var(--space-10); }

/* The open band is the gradient at rest. Nothing sits on it, so nothing has to clear it. */
.band-open { min-height: var(--space-16); padding: 0; background: var(--gradient-band-open); }

.band-closing { align-items: center; text-align: center; }

.band-eyebrow { color: var(--color-on-band); }
.band-title { font-size: var(--text-3xl); line-height: var(--leading-3xl); max-width: var(--measure-prose); text-wrap: balance; }
.band-cover .band-title { font-size: var(--text-4xl); line-height: var(--leading-4xl); }
.band-closing .band-title { font-size: var(--text-2xl); line-height: var(--leading-2xl); }
.band-lede { font-size: var(--text-md); line-height: var(--leading-md); max-width: var(--measure-prose); text-wrap: pretty; }

/* The mark row: whoever leads on the left, the client's logo tile on the right (§5.7). */
.band-marks { display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); flex-wrap: wrap; margin-bottom: var(--space-3); }
.band-closing .band-marks { justify-content: center; }

.band-mark { height: 32px; width: auto; align-self: flex-start; }
.band-closing .band-mark { align-self: center; }
.band-mark-print { display: none; }

/* A client logo always sits on its own white tile over a colored band — in both presets, no
   exception: a red-on-white logo disappears on its own red band (DESIGN 1.4 §5.7, decision 0013).
   The 160×40 box is the one the brand-kit preview shows, and the logo keeps its own clear space. */
.band-logo-tile {
  display: inline-flex; align-items: center; justify-content: center;
  padding: var(--space-2) var(--space-3);
  background: var(--color-surface-panel); border-radius: var(--radius-control); box-shadow: var(--shadow-1);
}
.band-logo-tile img { display: block; block-size: auto; max-block-size: 40px; max-inline-size: 160px; width: auto; object-fit: contain; }
.band-mark-text { font-family: var(--font-title); font-weight: var(--weight-medium); font-size: var(--text-lg); line-height: var(--leading-lg); margin-bottom: var(--space-2); }

/* Tenant band (DESIGN 1.4 §5.7). The gradient comes from `--tenant-band`, written onto the page
   root by src/domain/theme.ts, and the label is always white: the client's primary is darkened
   until white clears 4.5:1 at every stop, so there is no ink/white branch to get wrong. */
.band-tenant { background: var(--tenant-band, var(--gradient-band)); color: var(--color-ink-inverse); }
.band-tenant .band-eyebrow { color: inherit; }

.band-summary { display: flex; flex-wrap: wrap; gap: var(--space-8); margin-top: var(--space-4); }
.band-summary .band-figure { display: flex; flex-direction: column; gap: var(--space-1); }
.band-summary .band-figure-value { font-size: var(--text-xl); line-height: var(--leading-xl); font-weight: var(--weight-medium); font-variant-numeric: tabular-nums; }

@media (max-width: 720px) {
  .band { padding: var(--space-6); }
  .band-cover { padding: var(--space-10) var(--space-6); }
}

/* Print and export keep the hierarchy without the gradient (§9.9, brand guide §9). */
@media print {
  .band, .band-tenant { background: none; color: var(--color-ink); border: 1px solid var(--color-line-default); box-shadow: none; }
  .band-tenant .band-eyebrow { color: var(--color-ink); }
  .band-open { display: none; }
  .band-mark-screen { display: none; }
  .band-mark-print { display: block; }
  /* On paper the tile has no colour to stand out from, so it takes a hairline instead. */
  .band-logo-tile { box-shadow: none; border: 1px solid var(--color-line-subtle); padding: var(--space-1) var(--space-2); }
}

@media (forced-colors: active) {
  .band { border: 1px solid CanvasText; }
}


/* ---- ui/components/bar-chart.css ---- */
/* BarChart — DESIGN.md §9c. Horizontal bars, one accent, values printed, bars from zero,
   no pie, every series labelled in place. Under four data points the bars drop away and the
   same markup reads as a table. Tokens only. */

.chart {
  margin: 0; min-inline-size: 0;
  padding: var(--space-4) var(--space-5);
  border: 1px solid var(--color-line-default); border-radius: var(--radius-card);
  background: var(--color-surface-panel);
}
.chart-head { display: flex; flex-direction: column; gap: 2px; margin-block-end: var(--space-3); }
.chart-title { font-size: var(--text-sm); line-height: var(--leading-sm); font-weight: var(--weight-medium); }
.chart-sub { font-size: var(--text-xs); line-height: var(--leading-xs); }

/* A second series has to earn a legend (§9c), so the legend only renders when one exists. */
.chart-legend { display: flex; gap: var(--space-3); margin-block-start: var(--space-2); font-size: var(--text-xs); line-height: var(--leading-xs); color: var(--color-ink-secondary); }
.chart-key { display: inline-flex; align-items: center; gap: var(--space-1); }
.chart-key::before { content: ""; inline-size: 10px; block-size: 10px; border-radius: 3px; }
.chart-key-primary::before { background: var(--color-chart-1); }
.chart-key-secondary::before { background: var(--color-chart-2); }

.chart-grid { inline-size: 100%; border-collapse: collapse; }
.chart-row + .chart-row .chart-label, .chart-row + .chart-row .chart-cell { padding-block-start: var(--space-2); }
.chart-label {
  inline-size: 96px; padding-inline-end: var(--space-3);
  text-align: start; vertical-align: middle;
  font-size: var(--text-xs); line-height: var(--leading-xs); font-weight: var(--weight-regular);
  color: var(--color-ink-secondary);
  overflow: hidden; text-overflow: ellipsis;
}
.chart-cell { display: flex; align-items: center; gap: var(--space-3); }
.chart-track {
  flex: 1 1 auto; min-inline-size: 0;
  block-size: var(--space-2); border-radius: var(--radius-pill);
  background: var(--color-surface-well); overflow: hidden;
}
/* Bars start at zero: the width is the value over the maximum, never over a range. */
.chart-fill { display: block; block-size: 100%; inline-size: var(--chart-pct, 0%); background: var(--color-chart-1); border-radius: var(--radius-pill); }
.chart-row[data-series="secondary"] .chart-fill { background: var(--color-chart-2); }
/* Values are printed, never inferred from an axis (§9c). */
.chart-value { flex: 0 0 auto; min-inline-size: 6ch; text-align: end; font-size: var(--text-xs); line-height: var(--leading-xs); color: var(--color-ink); }

/* Fewer than four points: the bars are gone, the numbers stay. */
.chart-table .chart-cell { justify-content: flex-start; }
.chart-table .chart-value { text-align: start; }

@media (forced-colors: active) {
  .chart { border-color: CanvasText; }
  .chart-track { border: 1px solid CanvasText; }
  .chart-fill, .chart-row[data-series="secondary"] .chart-fill { forced-color-adjust: none; background: CanvasText; }
  .chart-key::before { forced-color-adjust: none; background: CanvasText; }
}
@media print {
  .chart { break-inside: avoid; }
}


/* ---- ui/components/brand-chip.css ---- */
/* Brand chip — DESIGN 1.4 §8 (topbar) and §5.7 (client theming). The one place a client's colour
   appears inside the team app, and it appears as a mark: a dot or a logo, never a coloured label,
   never a coloured ground behind text. Tokens only; `--tenant-brand` is written inline by the
   server from the brand's kit, and a brand without one falls back to a neutral dot. */

.bchip {
  display: inline-flex; align-items: center; gap: var(--space-2);
  min-block-size: 28px; padding: 0 var(--space-3);
  border: 1px solid var(--color-line-default); border-radius: var(--radius-pill);
  background: var(--color-surface-panel); color: var(--color-ink);
  font-size: var(--text-xs); line-height: var(--leading-xs); font-weight: var(--weight-medium);
  max-inline-size: 100%; text-decoration: none; vertical-align: middle;
  transition: border-color var(--duration-fast) var(--easing-standard);
}
a.bchip:hover { border-color: var(--color-line-interactive); }

.bchip-dot {
  inline-size: 10px; block-size: 10px; flex: 0 0 auto; border-radius: var(--radius-pill);
  background: var(--tenant-brand, var(--color-ink-tertiary));
}

/* A client logo sits on its own white tile here for the same reason it does on a band: the mark
   is drawn for one ground, and the chip has to hold in both themes (DESIGN §5.7). */
.bchip-tile {
  display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto;
  block-size: 20px; padding: 0 var(--space-1);
  background: var(--color-surface-panel); border-radius: var(--radius-control);
}
.bchip-tile img { display: block; block-size: auto; max-block-size: 16px; max-inline-size: 56px; object-fit: contain; }

.bchip-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-inline-size: 24ch; }

/* In dark mode the tile keeps its own light ground, so a dark-drawn logo still reads. */
:root[data-theme="dark"] .bchip-tile { background: var(--color-ink-inverse); }

@media (forced-colors: active) {
  .bchip { border-color: CanvasText; }
  .bchip-dot { background: CanvasText; }
}


/* ---- ui/components/brand-lockup.css ---- */
/* The approved lockup: icon, hairline, wordmark — one color, the text's own. */
.lockup { display: inline-flex; align-items: center; gap: var(--space-3); color: inherit; }
.lockup-rule { align-self: stretch; width: 1px; background: var(--color-line-default); }
.lockup-stacked { flex-direction: column; gap: var(--space-2); }
.lockup-stacked .lockup-rule { width: 40px; height: 1px; align-self: center; }
.mark { display: inline-block; vertical-align: middle; flex: none; }

/* The endorsement: quiet, tertiary, the logo doing the naming. */
.fueled-by { display: inline-flex; align-items: center; gap: var(--space-2); color: var(--color-ink-tertiary); font-size: var(--text-xs); line-height: var(--leading-xs); white-space: nowrap; }
.fueled-by .mark { color: var(--color-ink-secondary); }


/* ---- ui/components/button.css ---- */
/* Button — DESIGN.md §3.3 (objects, not decals), §7 (control anatomy), §9 Buttons. Tokens only.
   Every button is built the same way: a fill, a one-pixel darker rim, a one-pixel top highlight,
   and a half-pixel press. No gradients, no drop shadow at rest beyond the hairline lift. */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
  height: var(--button-height); padding: 0 var(--button-padding-x);
  border: 0; border-radius: var(--button-radius);
  font-size: var(--text-base); line-height: 1; font-weight: var(--weight-medium);
  white-space: nowrap; text-decoration: none; vertical-align: middle; user-select: none;
  transition: background-color var(--duration-fast) var(--easing-standard),
    box-shadow var(--duration-fast) var(--easing-standard),
    color var(--duration-fast) var(--easing-standard),
    transform var(--duration-fast) var(--easing-standard);
}
.btn:active:not(:disabled):not([aria-disabled="true"]), .btn[data-state="active"] { transform: translateY(var(--button-press)); }
.btn-small { height: var(--button-height-small); padding: 0 var(--button-padding-x-small); border-radius: var(--button-radius-small); font-size: var(--text-sm); }
.btn-touch { height: var(--button-height-touch); padding: 0 var(--button-padding-x-touch); border-radius: var(--button-radius-touch); font-size: var(--text-md); }
.btn-icon { width: var(--button-height); padding: 0; }
.btn-icon.btn-small { width: var(--button-height-small); }
.btn-icon.btn-touch { width: var(--button-height-touch); }
.btn-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.btn > svg { flex: 0 0 auto; }

/* Primary: deep ember with a white label. One per view (§9). Bright Campfire Orange is never a fill. */
.btn-primary { background: var(--button-primary-bg); color: var(--button-primary-fg);
  box-shadow: inset 0 0 0 1px var(--button-primary-edge), inset 0 1px 0 var(--button-highlight), var(--shadow-button); }
.btn-primary:hover, .btn-primary[data-state="hover"] { background: var(--button-primary-bg-hover); }
.btn-primary:active, .btn-primary[data-state="active"] { background: var(--button-primary-bg-hover);
  box-shadow: inset 0 0 0 1px var(--button-primary-edge), var(--button-press-shadow); }

/* `primary-strong` retired in DESIGN 1.4: it is the primary now (kept as a class alias for old markup). */
.btn-primary-strong { background: var(--button-primary-bg); color: var(--button-primary-fg);
  box-shadow: inset 0 0 0 1px var(--button-primary-edge), inset 0 1px 0 var(--button-highlight), var(--shadow-button); }
.btn-primary-strong:hover, .btn-primary-strong[data-state="hover"] { background: var(--button-primary-bg-hover); }
.btn-primary-strong:active, .btn-primary-strong[data-state="active"] { background: var(--button-primary-bg-hover);
  box-shadow: inset 0 0 0 1px var(--button-primary-edge), var(--button-press-shadow); }

/* Secondary: a sheet with a quiet rim that firms up on hover. */
.btn-secondary { background: var(--button-secondary-bg); color: var(--button-secondary-fg);
  box-shadow: inset 0 0 0 1px var(--button-secondary-border), inset 0 1px 0 var(--button-highlight), var(--shadow-button); }
.btn-secondary:hover, .btn-secondary[data-state="hover"] { background: var(--color-surface-well);
  box-shadow: inset 0 0 0 1px var(--button-secondary-border-hover), inset 0 1px 0 var(--button-highlight), var(--shadow-button); }
.btn-secondary:active, .btn-secondary[data-state="active"] { background: var(--color-surface-well);
  box-shadow: inset 0 0 0 1px var(--button-secondary-border-hover), var(--button-press-shadow); }

/* Ghost: text until you point at it. `tertiary` is the old name for the same thing. */
.btn-ghost, .btn-tertiary { background: transparent; color: var(--button-ghost-fg); box-shadow: none; }
.btn-ghost:hover, .btn-ghost[data-state="hover"],
.btn-tertiary:hover, .btn-tertiary[data-state="hover"] { background: var(--button-ghost-bg-hover); color: var(--color-ink); }
.btn-ghost:active, .btn-ghost[data-state="active"],
.btn-tertiary:active, .btn-tertiary[data-state="active"] { background: var(--button-ghost-bg-hover); color: var(--color-ink); box-shadow: var(--button-press-shadow); }

/* Destructive is text (§9). The filled form exists only inside a confirmation — see dialog.css. */
.btn-destructive { background: transparent; color: var(--button-destructive-fg); box-shadow: none; }
.btn-destructive:hover, .btn-destructive[data-state="hover"] { background: var(--color-bad-tint);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--color-bad) 30%, transparent); }
.btn-destructive:active, .btn-destructive[data-state="active"] { background: var(--color-bad-tint);
  box-shadow: inset 0 0 0 1px var(--color-bad); }

.btn[data-state="focus"] { outline: 2px solid var(--color-focus); outline-offset: 2px; }

.btn:disabled, .btn[aria-disabled="true"] {
  background: var(--color-surface-well); color: var(--color-ink-disabled);
  box-shadow: inset 0 0 0 1px var(--color-line-default); cursor: not-allowed; transform: none;
}
/* A disabled text button stays a text button: a filled grey box would read as a new control. */
.btn-ghost:disabled, .btn-tertiary:disabled, .btn-destructive:disabled,
.btn-ghost[aria-disabled="true"], .btn-tertiary[aria-disabled="true"], .btn-destructive[aria-disabled="true"] {
  background: transparent; box-shadow: none;
}
/* Loading keeps the button's width and its label, so a screen reader still hears the outcome (§9). */
.btn[aria-busy="true"] { cursor: progress; }
.btn-primary[aria-busy="true"], .btn-primary-strong[aria-busy="true"] {
  background: var(--button-primary-bg); color: var(--button-primary-fg);
  box-shadow: inset 0 0 0 1px var(--button-primary-edge), inset 0 1px 0 var(--button-highlight), var(--shadow-button);
}
.btn-secondary[aria-busy="true"] { background: var(--button-secondary-bg); color: var(--button-secondary-fg);
  box-shadow: inset 0 0 0 1px var(--button-secondary-border), inset 0 1px 0 var(--button-highlight), var(--shadow-button); }
.btn-ghost[aria-busy="true"], .btn-tertiary[aria-busy="true"] { background: transparent; color: var(--button-ghost-fg); box-shadow: none; }
.btn-destructive[aria-busy="true"] { background: transparent; color: var(--button-destructive-fg); box-shadow: none; }

/* Spinner: a ring that goes still under reduced motion (base.css collapses the duration to 1ms). */
.spinner {
  --spinner-size: 16px;
  display: inline-block; width: var(--spinner-size); height: var(--spinner-size); flex: 0 0 auto;
  border: 2px solid currentColor; border-right-color: transparent; border-radius: var(--radius-pill);
  animation: spin 800ms linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* Split button: two halves that share one rim (§9). */
.btn-split { display: inline-flex; }
.btn-split > .btn:first-child { border-start-end-radius: 0; border-end-end-radius: 0; }
.btn-split > .btn:last-child { border-start-start-radius: 0; border-end-start-radius: 0; margin-inline-start: -1px; }
/* The focused half rises above the shared seam. */
.btn-split > .btn:focus-visible { z-index: 1; position: relative; }

/* Under a coarse pointer a default button stands 40 (0014 pattern 8); small buttons keep 28 — still
   over the 24 floor — and the portal's 44 `.btn-touch` is its own floor. */
@media (pointer: coarse) {
  .btn:not(.btn-small):not(.btn-touch) { height: var(--button-height-coarse); }
  .btn-icon:not(.btn-small):not(.btn-touch) { width: var(--button-height-coarse); }
}

@media (forced-colors: active) {
  .btn { border: 1px solid ButtonText; forced-color-adjust: none; background: ButtonFace; color: ButtonText; box-shadow: none; }
  .btn-primary, .btn-primary-strong { background: Highlight; color: HighlightText; }
  .btn-ghost, .btn-tertiary, .btn-destructive { background: ButtonFace; color: ButtonText; }
  .btn:disabled, .btn[aria-disabled="true"] { color: GrayText; border-color: GrayText; }
}


/* ---- ui/components/card.css ---- */
/* Card — DESIGN.md §7.7 and brand guide §7.7. A border or an elevation, never both.
   Tokens only. */

.card {
  position: relative; display: block;
  background: var(--color-surface-panel); color: var(--color-ink);
  border-radius: var(--radius-card);
}
.card-border { border: 1px solid var(--color-line-default); }
.card-shadow-1 { box-shadow: var(--shadow-1); }
.card-shadow-2 { box-shadow: var(--shadow-2); }

.card-head { display: flex; align-items: flex-start; gap: var(--space-3); padding: var(--space-5) var(--space-5) 0; }
.card-title { font-family: var(--font-title); font-weight: var(--weight-medium); font-size: var(--text-lg); line-height: var(--leading-lg); }
.card-head-actions { flex: 0 0 auto; display: flex; align-items: center; gap: var(--space-2); }
.card-body { padding: var(--space-5); }
.card-head + .card-body { padding-top: var(--space-3); }
.card-foot {
  display: flex; align-items: center; gap: var(--space-3);
  padding: var(--space-3) var(--space-5);
  border-top: 1px solid var(--color-line-subtle);
}

.card-pad-compact .card-head { padding: var(--space-3) var(--space-3) 0; }
.card-pad-compact .card-body { padding: var(--space-3); }
.card-pad-compact .card-head + .card-body { padding-top: var(--space-2); }
.card-pad-compact .card-foot { padding: var(--space-2) var(--space-3); }
.card-pad-none .card-head, .card-pad-none .card-body, .card-pad-none .card-foot { padding: 0; }
.card-pad-none .card-foot { border-top: 0; }

.card-interactive {
  text-decoration: none;
  transition: background-color var(--duration-fast) var(--easing-standard), border-color var(--duration-fast) var(--easing-standard);
}
.card-interactive:hover, .card-interactive[data-state="hover"] { background: var(--color-surface-well); text-decoration: none; }
.card-interactive.card-border:hover, .card-interactive.card-border[data-state="hover"] { border-color: var(--color-line-interactive); }
.card-interactive:active, .card-interactive[data-state="active"] { background: var(--color-brand-wash); }
.card-interactive[data-state="focus"] { outline: 2px solid var(--color-focus); outline-offset: 2px; }

/* Selected: tint plus a 2px marker plus the word "Selected" in the markup (§9.2, §11). */
.card-selected { background: var(--color-selection); }
.card-selected.card-border { border-color: var(--color-brand); }
.card-selected::before {
  content: ""; position: absolute; inset-block: 0; inset-inline-start: 0; width: 2px;
  background: var(--color-brand);
  border-start-start-radius: var(--radius-card); border-end-start-radius: var(--radius-card);
}
/* The selection tint is a hotter, darker ground than a panel: tertiary ink drops to 4.1:1 on
   it in dark theme, so quiet text steps up to secondary inside a selected card (§5.4). */
.card-selected .ink-3, .card-selected .t-label { color: var(--color-ink-secondary); }

/* Card padding 20 → 16 on a phone (0014 pattern 10). Type and density do not change. */
@media (max-width: 720px) {
  .card-head { padding: var(--space-4) var(--space-4) 0; }
  .card-body { padding: var(--space-4); }
  .card-foot { padding: var(--space-3) var(--space-4); }
}

@media (forced-colors: active) {
  .card { border: 1px solid CanvasText; }
  .card-selected::before { background: Highlight; }
  .card-interactive:hover { background: Canvas; }
}

@media print {
  .card { box-shadow: none; border: 1px solid var(--color-line-default); break-inside: avoid; }
}


/* ---- ui/components/checkbox.css ---- */
/* Checkbox — DESIGN.md §9.5. Native input, appearance stripped, mark in currentColor. Tokens only. */

.checkbox {
  display: grid; grid-template-columns: auto 1fr; column-gap: var(--space-2); align-items: start;
  min-inline-size: 0;
}
.checkbox-touch { min-height: var(--target-min); align-content: center; }

/* Box and both marks share the same grid cell so the mark sits inside the box. */
.checkbox-input, .checkbox-mark, .checkbox-dash { grid-area: 1 / 1; }

.checkbox-input {
  appearance: none;
  inline-size: var(--control-box); block-size: var(--control-box); margin: 0; margin-block-start: 2px;
  border: 1px solid var(--input-border); border-radius: 4px;
  background: var(--input-bg); cursor: pointer;
  transition: background-color var(--duration-fast) var(--easing-standard), border-color var(--duration-fast) var(--easing-standard);
}
.checkbox-touch .checkbox-input { inline-size: var(--control-box-touch); block-size: var(--control-box-touch); }
.checkbox-input:hover, .checkbox-input[data-state="hover"] { border-color: var(--color-ink-secondary); }
.checkbox-input[data-state="focus"] { outline: 2px solid var(--color-focus); outline-offset: 2px; }
/* Ink fill, not orange: bright Campfire Orange marks a place, it never fills a control (§3.2, §9). */
.checkbox-input:checked,
.checkbox-input:indeterminate,
.checkbox-input[data-indeterminate="true"] { background: var(--control-fill); border-color: var(--control-fill); }
.checkbox-input[aria-invalid="true"] { border-color: var(--input-border-error); }
.checkbox-input:disabled { background: var(--color-surface-well); border-color: var(--color-line-default); cursor: not-allowed; }
.checkbox-input:disabled:checked,
.checkbox-input:disabled[data-indeterminate="true"] { background: var(--color-line-default); border-color: var(--color-line-default); }

.checkbox-mark, .checkbox-dash {
  inline-size: var(--control-box); block-size: var(--control-box); margin-block-start: 2px;
  color: var(--control-mark); pointer-events: none; visibility: hidden;
}
.checkbox-touch .checkbox-mark, .checkbox-touch .checkbox-dash { inline-size: var(--control-box-touch); block-size: var(--control-box-touch); }
.checkbox-input:checked ~ .checkbox-mark { visibility: visible; }
.checkbox-input:indeterminate ~ .checkbox-mark,
.checkbox-input[data-indeterminate="true"] ~ .checkbox-mark { visibility: hidden; }
.checkbox-input:indeterminate ~ .checkbox-dash,
.checkbox-input[data-indeterminate="true"] ~ .checkbox-dash { visibility: visible; }
.checkbox-input:disabled ~ .checkbox-mark, .checkbox-input:disabled ~ .checkbox-dash { color: var(--color-surface-panel); }

.checkbox-text { grid-area: 1 / 2; display: flex; flex-direction: column; gap: 2px; min-inline-size: 0; }
.checkbox-label { font-size: var(--text-base); line-height: var(--leading-base); cursor: pointer; }
.checkbox-desc { font-size: var(--text-xs); line-height: var(--leading-xs); color: var(--color-ink-secondary); }
.checkbox[data-disabled="true"] .checkbox-label { color: var(--color-ink-tertiary); cursor: not-allowed; }
.checkbox[data-disabled="true"] .checkbox-desc { color: var(--color-ink-tertiary); }

@media (forced-colors: active) {
  .checkbox-input { border-color: CanvasText; }
  .checkbox-input:checked, .checkbox-input:indeterminate, .checkbox-input[data-indeterminate="true"] { background: Highlight; border-color: Highlight; }
  .checkbox-mark, .checkbox-dash { color: HighlightText; forced-color-adjust: none; }
  .checkbox-input:disabled { border-color: GrayText; }
  .checkbox[data-disabled="true"] .checkbox-label, .checkbox[data-disabled="true"] .checkbox-desc { color: GrayText; }
}


/* ---- ui/components/chip.css ---- */
/* Chip — DESIGN.md §9.2 (filter chips, tags). Neutral by default: a chip is not a status. Tokens only. */

.chip {
  display: inline-flex; align-items: center; gap: var(--space-1);
  min-block-size: 24px; padding: 0 var(--space-2);
  border: 1px solid var(--color-line-default); border-radius: var(--radius-pill);
  background: var(--color-surface-panel); color: var(--color-ink);
  font-size: var(--text-xs); line-height: var(--leading-xs);
  max-inline-size: 100%; text-decoration: none; vertical-align: middle;
  transition: background-color var(--duration-fast) var(--easing-standard), border-color var(--duration-fast) var(--easing-standard);
}
.chip-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-inline-size: 28ch; }

/* Filter bar: field + operator + value, then a removal control.
   The chip is 28px tall so the removal control can meet the 24px minimum target (WCAG 2.2). */
.chip-filter { min-block-size: 28px; padding-inline-end: 2px; border-color: var(--color-line-interactive); }
.chip-filter-field { color: var(--color-ink-secondary); }
.chip-filter-value { font-weight: var(--weight-medium); }
.chip-filter-remove {
  display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto;
  inline-size: 24px; block-size: 24px; border-radius: var(--radius-pill);
  color: var(--color-ink-secondary); text-decoration: none;
}
.chip-filter-remove:hover, .chip-filter-remove[data-state="hover"] { background: var(--color-surface-well); color: var(--color-ink); }
.chip-filter-remove:active, .chip-filter-remove[data-state="active"] { background: var(--color-bad-tint); color: var(--color-bad); }
.chip-filter-remove[data-state="focus"] { outline: 2px solid var(--color-focus); outline-offset: 2px; }
.chip-filter[data-disabled="true"] { color: var(--color-ink-tertiary); border-color: var(--color-line-default); background: var(--color-surface-well); }
.chip-filter[data-disabled="true"] .chip-filter-field { color: var(--color-ink-tertiary); }
.chip-filter-remove:disabled { color: var(--color-ink-disabled); }

/* Choice: selection is tint + check + aria-pressed, never colour alone. */
.chip-choice { min-block-size: 28px; padding: 0 var(--space-3); cursor: pointer; }
.chip-choice:hover, .chip-choice[data-state="hover"] { background: var(--color-surface-well); border-color: var(--color-line-interactive); }
.chip-choice:active, .chip-choice[data-state="active"] { background: var(--color-brand-wash); }
.chip-choice[data-state="focus"] { outline: 2px solid var(--color-focus); outline-offset: 2px; }
.chip-choice[data-selected="true"] { background: var(--color-brand-tint); border-color: var(--color-brand); color: var(--color-ink); font-weight: var(--weight-medium); }
.chip-choice[data-selected="true"]:hover, .chip-choice[data-selected="true"][data-state="hover"] { background: var(--color-brand-tint); border-color: var(--color-brand); }
.chip-choice-check { color: var(--color-brand-strong); }
.chip-choice:disabled { background: var(--color-surface-well); color: var(--color-ink-disabled); border-color: var(--color-line-default); cursor: not-allowed; }

@media (forced-colors: active) {
  .chip { border-color: CanvasText; }
  .chip-choice[data-selected="true"] { border-color: Highlight; }
  .chip-choice-check { color: Highlight; }
  .chip-choice:disabled, .chip-filter[data-disabled="true"] { color: GrayText; border-color: GrayText; }
}


/* ---- ui/components/creator-result-card.css ---- */
/* CreatorResultCard — a discovery result as a card (DESIGN.md §7.7, §9.2). Tokens only.
   A border, never a border plus a shadow; the selected state is a tint plus a 2px marker plus
   the word "Selected" in the markup, the same rule the table rows follow. */

.crc {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  min-width: 0;
  padding: var(--space-4);
  background: var(--color-surface-panel);
  color: var(--color-ink);
  border: 1px solid var(--color-line-default);
  border-radius: var(--radius-card);
}

.crc-selected {
  background: var(--color-selection);
  border-color: var(--color-line-interactive);
}
/* The selection tint is darker than the panel, so the quietest text steps up a level and keeps
   its 4.5:1 in both themes. */
.crc-selected .crc-matched, .crc-selected .crc-stat dt { color: var(--color-ink-secondary); }
.crc-selected::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  inset-block: 0;
  width: 2px;
  border-start-start-radius: var(--radius-card);
  border-end-start-radius: var(--radius-card);
  background: var(--color-brand);
}

.crc-head { display: flex; align-items: flex-start; gap: var(--space-3); min-width: 0; }
.crc-identity { display: flex; flex-direction: column; gap: var(--space-1); min-width: 0; }
.crc-name { overflow-wrap: anywhere; }
.crc-handle { display: inline-flex; align-items: center; gap: var(--space-1); overflow-wrap: anywhere; }

/* The checkbox keeps its label for assistive technology but the card already says the name,
   so the visible text collapses to the box itself. */
.crc-select .checkbox-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

.crc-stats { display: flex; flex-wrap: wrap; gap: var(--space-4); margin: 0; }
.crc-stat { display: flex; flex-direction: column; gap: var(--space-1); min-width: 0; }
.crc-stat dt { margin: 0; }
.crc-stat-value { margin: 0; font-size: var(--text-md); line-height: var(--leading-md); font-weight: var(--weight-medium); }

.crc-segment, .crc-matched { margin: 0; }

.crc-flags { display: flex; flex-wrap: wrap; gap: var(--space-2); margin: 0; padding: 0; list-style: none; }
/* A flag is a fact, not a status, so it borrows the Chip's neutral treatment. Links are
   underlined rather than coloured: colour alone never carries meaning (§11). */
.crc-flag {
  display: inline-flex; align-items: center;
  min-height: var(--pill-height);
  padding: 0 var(--space-2);
  border: 1px solid var(--color-line-default);
  border-radius: var(--radius-pill);
  background: var(--color-surface-well);
  color: var(--color-ink);
  font-size: var(--text-xs); line-height: var(--leading-xs);
  text-decoration: none;
}
a.crc-flag { text-decoration: underline; text-underline-offset: 2px; }
a.crc-flag:hover { background: var(--color-brand-wash); border-color: var(--color-line-interactive); }
a.crc-flag:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }

.crc-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin-top: auto; padding-top: var(--space-1); }
.crc-actions form { display: contents; }

.crc-loading { gap: var(--space-4); }

@media (forced-colors: active) {
  .crc { border: 1px solid CanvasText; }
  .crc-selected::before { background: Highlight; }
}


/* ---- ui/components/data-table.css ---- */
/* DataTable — DESIGN.md §9.2. Tokens only. The toolbar above it is toolbar.css. */
.dt { display: flex; flex-direction: column; gap: var(--space-3); min-width: 0; }
.dt-clear { color: var(--color-ink-secondary); }
.dt-density { display: inline-flex; gap: 2px; padding: 2px; border-radius: var(--radius-control); background: var(--color-surface-well); }
.dt-density .btn[aria-pressed="true"] { background: var(--color-surface-panel); color: var(--color-ink); box-shadow: var(--shadow-1); }

/* §9: "the bulk bar is an ink-colored floating strip". It sticks to the bottom of the
   table's own section rather than the viewport, so it belongs to this table and not to the
   page, and it sits after the rows in DOM order — you select, then you act. */
.dt-bulk {
  position: sticky; z-index: 4;
  inset-block-end: var(--space-4);
  display: flex; align-items: center; gap: var(--space-2);
  inline-size: max-content; max-inline-size: 100%; margin-inline: auto;
  padding: var(--space-2) var(--space-2) var(--space-2) var(--space-4);
  background: var(--color-ink); color: var(--color-ink-inverse);
  border-radius: var(--radius-card); box-shadow: var(--shadow-2);
  font-size: var(--text-sm); line-height: var(--leading-sm);
  flex-wrap: wrap;
}
.dt-bulk[hidden] { display: none; }
.dt-bulk-count { margin-inline-end: var(--space-2); white-space: nowrap; }
/* The strip is an inverse surface, so its buttons carry the inverse ink rather than the
   sheet's. Fills stay out: one ink ground, quiet labels on it. */
.dt-bulk .btn { color: var(--color-ink-inverse); background: none; border-color: transparent; box-shadow: none; }
.dt-bulk .btn:hover { background: var(--color-ink-secondary); color: var(--color-ink-inverse); }
.dt-bulk .btn-destructive { color: var(--color-bad-tint); }
.dt-bulk .btn:focus-visible { outline-color: var(--color-ink-inverse); }

.dt-scroll {
  /* Positioned so absolutely-placed descendants (every `.visually-hidden` span) stay inside this
     box: unpositioned, a scroll container does not contain them and a 1px box parks at its static
     x far to the right, widening the document without ever showing up in a bounding-box scan. */
  position: relative;
  overflow: auto; max-height: var(--dt-max-height, calc(100dvh - 200px));
  border: 1px solid var(--color-line-default); border-radius: var(--radius-card); background: var(--color-surface-panel);
}
/* The region is in the tab order (0014 pattern 2); the ring stays inside the clipped box. */
.dt-scroll:focus-visible { outline: 2px solid var(--color-focus); outline-offset: -2px; }
.dt-table { width: 100%; min-width: max-content; font-size: var(--text-sm); line-height: var(--leading-sm); }

.dt-th { position: sticky; top: 0; z-index: 2; height: 34px; padding: 0 var(--table-cell-padding-x); text-align: left; vertical-align: middle; white-space: nowrap;
  background: var(--table-header-bg); color: var(--table-header-fg); font-size: var(--text-2xs); line-height: var(--leading-2xs); font-weight: var(--weight-medium);
  text-transform: uppercase; letter-spacing: var(--tracking-label); border-bottom: 1px solid var(--color-line-default); }
.dt-th-sorted { color: var(--color-ink); }
/* The sort link fills the header cell (0014 pattern 8): the cell's own padding moves onto the
   link, so the whole 34px cell is the target and the ring draws inside it. */
.dt-sort { display: flex; align-items: center; gap: var(--space-1); height: 34px; margin-inline: calc(var(--table-cell-padding-x) * -1); padding-inline: var(--table-cell-padding-x);
  color: inherit; text-decoration: none; }
.dt-sort:hover { color: var(--color-ink); }
.dt-sort:focus-visible { outline-offset: -2px; }
.dt-sort-icon { display: inline-flex; color: var(--color-ink-tertiary); }
.dt-th-sorted .dt-sort-icon { color: var(--color-ink); }
.dt-td-right { text-align: right; }
.dt-td-right .dt-sort { flex-direction: row-reverse; }
/* Opt-in wrapping for a column of sentences; long unbroken strings break anywhere (0014 pattern 1). */
.dt-td-wrap { white-space: normal; overflow-wrap: anywhere; min-width: 16ch; max-width: 40ch; }
/* Summary row: medium weight, a firmer rule above, stuck to the bottom of the region. */
.dt-summary .dt-td { position: sticky; bottom: 0; z-index: 2; font-weight: var(--weight-medium); border-top: 1px solid var(--color-line-default); border-bottom: 0; background: var(--table-header-bg); }
.dt-summary .dt-td.dt-sticky { z-index: 3; }

/* §9: rows are 40 comfortable. A creator cell is two 16px lines, so the vertical padding
   has to be 4 for the row to land on 40 — `--table-cell-padding-y` (8) would make it 48. */
.dt-td { height: var(--table-row-comfortable); padding: var(--space-1) var(--table-cell-padding-x); vertical-align: middle; border-bottom: 1px solid var(--table-rule); background: var(--color-surface-panel); white-space: nowrap; }
.dt-td-text, .dt-td-creator { max-width: 320px; }
.dt-td-creator { min-width: 220px; }
.dt-td-metric { font-variant-numeric: tabular-nums; }
.dt-td-empty { padding: var(--space-8) var(--space-4); white-space: normal; }
.dt-row:last-child .dt-td { border-bottom: 0; }
.dt-row:hover .dt-td { background: var(--table-row-hover-bg); }
.dt-row:focus-visible { outline: 2px solid var(--color-focus); outline-offset: -2px; }
.dt-row-selected .dt-td { background: var(--table-row-selected-bg); }
.dt-row-selected:hover .dt-td { background: var(--table-row-selected-bg); }
/* §9: selected = brand-wash + a 3px marker. */
.dt-row-selected .dt-td:first-child { box-shadow: inset 3px 0 0 var(--table-row-selected-marker); }
/* Decision 0003: tertiary ink never sits on the selection tint. */
.dt-row-selected .ink-3, .dt-row-selected .dt-creator-handle { color: var(--color-ink-secondary); }

.dt-sticky { position: sticky; left: 0; z-index: 1; }
.dt-th.dt-sticky { z-index: 3; }
.dt-sticky-after-select { left: 40px; }
.dt-sticky-first { box-shadow: inset -1px 0 0 var(--color-line-subtle); }
.dt-th-select, .dt-td-select { width: 40px; padding: 0; text-align: center; }

.dt-check { appearance: none; width: 16px; height: 16px; margin: 0; border: 1px solid var(--color-line-interactive); border-radius: 3px; background: var(--color-surface-panel); vertical-align: middle; display: inline-grid; place-content: center; cursor: pointer; }
.dt-check:checked { background: var(--color-brand-strong); border-color: var(--color-brand-strong); }
.dt-check:checked::after { content: ""; width: 9px; height: 5px; border: 2px solid var(--color-ink-inverse); border-top: 0; border-right: 0; transform: translateY(-1px) rotate(-45deg); }
.dt-check:disabled { opacity: .5; cursor: not-allowed; }
@media (prefers-reduced-motion: reduce) { .dt-check:checked::after { transform: rotate(-45deg) !important; } }

/* §9: rows 40 comfortable / 32 compact. The header stays 34 in both — it is a fixed
   landmark, and shrinking it just makes the caps label harder to hit. */
[data-density="compact"] .dt-td { height: var(--table-row-compact); padding-block: 0; }
[data-density="compact"] .avatar-sm { width: 20px; height: 20px; }

.dt-footer { display: flex; gap: var(--space-2); font-size: var(--text-xs); line-height: var(--leading-xs); color: var(--color-ink-secondary); padding: 0 var(--space-1); }

/* Cells */
.dt-creator { display: inline-flex; align-items: center; gap: var(--space-2); min-width: 0; max-width: 100%; }
.dt-creator-text { display: flex; flex-direction: column; min-width: 0; line-height: var(--leading-xs); }
.dt-creator-name { font-weight: var(--weight-medium); color: var(--color-ink); text-decoration: none; max-width: 28ch; }
.dt-creator-name:hover { text-decoration: underline; }
.dt-creator-handle { font-size: var(--text-xs); max-width: 28ch; }
[data-density="compact"] .dt-creator-handle { display: none; }
.dt-metric { display: inline-block; }
.dt-date-exact { display: none; color: var(--color-ink-secondary); }
.dt-row:hover .dt-date-exact, .dt-row:focus-within .dt-date-exact, .dt-row:focus .dt-date-exact { display: inline; }
.dt-row:hover .dt-date-relative, .dt-row:focus-within .dt-date-relative, .dt-row:focus .dt-date-relative { display: none; }
/* §9: row actions appear on hover/focus. Opacity, not display — the button stays in the
   tab order, so the keyboard never loses it, and it shows itself the moment it takes focus
   or its menu opens. */
.dt-actions { display: inline-flex; justify-content: flex-end; width: 100%; }
.dt-actions > .btn { opacity: 0; transition: opacity var(--duration-fast) var(--easing-standard); }
.dt-row:hover .dt-actions > .btn,
.dt-row:focus-within .dt-actions > .btn,
.dt-row:focus .dt-actions > .btn,
.dt-actions > .btn:focus-visible,
.dt-actions:has(> [popover]:popover-open) > .btn { opacity: 1; }
/* Touch has no hover, and a print-out has no pointer at all. */
@media (hover: none) { .dt-actions > .btn { opacity: 1; } }

/* §9b: a real 0 is a zero; "—" is the absence of a measurement and says so on focus. */
.dt-nodata { border-radius: var(--radius-control); color: var(--color-ink-tertiary); }
.dt-nodata:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }
.dt-th-label { display: inline-flex; align-items: center; gap: var(--space-1); }
.dt-th-source { flex: 0 0 auto; }

/* Native popover menus used by the toolbar and actions (no JS needed). Anchored to the trigger
   where the browser can (`anchorStyle()` names the pair) and flipped to stay in the viewport
   (0014 pattern 6); elsewhere they open under the top bar, inset from both edges. */
.dt-menu {
  position: fixed; margin: 0; border: 0;
  inset-block-start: var(--space-16); inset-inline: var(--space-4); inset-block-end: auto; margin-inline: auto;
  padding: var(--space-1); width: max-content; min-width: 200px; max-width: min(360px, calc(100vw - var(--space-8)));
  max-height: 60dvh; overflow-y: auto; overscroll-behavior: contain;
  background: var(--color-surface-overlay); border-radius: var(--menu-radius); box-shadow: var(--shadow-2); color: var(--color-ink);
}
.dt-menu:popover-open { display: flex; flex-direction: column; gap: 2px; animation: overlay-pop var(--duration-standard) var(--easing-standard); }
@supports (anchor-name: --a) {
  .dt-menu { inset: auto; margin-inline: 0; margin-block-start: var(--space-1); position-area: bottom span-inline-end; position-try-fallbacks: flip-block, flip-inline; }
  .dt-menu-end { position-area: bottom span-inline-start; }
}
.dt-menu-item { display: flex; align-items: center; gap: var(--space-2); height: 32px; padding: 0 var(--space-3); border-radius: var(--radius-control); text-decoration: none; font-size: var(--text-sm); white-space: nowrap; }
.dt-menu-item:hover, .dt-menu-item:focus-visible { background: var(--color-surface-well); }
.dt-menu-item-destructive { color: var(--color-bad); }
.dt-menu-check { width: 14px; display: inline-flex; }
.dt-menu-groups { min-width: 240px; }
.dt-menu-group + .dt-menu-group { border-top: 1px solid var(--color-line-subtle); margin-top: var(--space-1); padding-top: var(--space-1); }
.dt-menu-group-label { padding: var(--space-2) var(--space-3) var(--space-1); }
.dt-columns-panel { min-width: 280px; padding: var(--space-3); gap: var(--space-2); }
.dt-columns-list { display: flex; flex-direction: column; gap: 2px; margin: var(--space-2) 0; }
.dt-columns-item { display: flex; align-items: center; gap: var(--space-1); }

/* §9: skeleton rows on load, preserving the real column widths. §9a: pulse opacity only. */
.dt-skel {
  display: block; height: 12px; border-radius: var(--radius-control);
  background: var(--color-surface-well); box-shadow: inset 0 0 0 1px var(--color-line-subtle);
  animation: skeleton-pulse 1400ms var(--easing-standard) infinite;
}

/* ---- Phone (≤ 720, decision 0014 pattern 2) ----
   The page scrolls, not the region — a table inside a scrolling page never scrolls vertically on
   its own. The first column stays sticky; the toolbar's desktop-only controls go (toolbar.css);
   the bulk strip becomes a full-width sheet above the bottom bar. */
@media (max-width: 720px) {
  .dt-scroll { max-height: none; }
  .dt-td-text, .dt-td-creator { max-width: 240px; }
  .dt-td-creator { min-width: 180px; }
  .dt-bulk {
    position: fixed; z-index: 25; inset-inline: 0; inset-block-end: var(--shell-bottom-bar);
    inline-size: auto; max-inline-size: none; margin: 0;
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-card) var(--radius-card) 0 0;
  }
  .dt-bulk .btn { height: var(--button-height-coarse); }
  .dt-bulk-count { flex: 1 1 100%; }
  .dt-bulk .right { margin-inline-start: 0; }
}

@media (forced-colors: active) {
  .dt-row-selected .dt-td:first-child { box-shadow: inset 3px 0 0 Highlight; }
  .dt-bulk { forced-color-adjust: none; background: Canvas; color: CanvasText; border: 1px solid CanvasText; }
  .dt-bulk .btn { color: CanvasText; }
  .dt-check { border-color: CanvasText; }
  .dt-check:checked { background: Highlight; }
  .dt-menu { border: 1px solid CanvasText; }
}
@media print {
  .toolbar, .dt-bulk, .dt-footer-hint { display: none; }
  .dt-actions > .btn { display: none; }
  .dt-scroll { max-height: none; overflow: visible; border: 0; }
  .dt-th { position: static; }
}


/* ---- ui/components/dialog.css ---- */
/* Dialog — DESIGN.md §9 Overlays. Focused decisions and short forms: a native <dialog>, 480 wide,
   centered behind a 35% ink backdrop. Tokens only. */

.dialog {
  position: static;                       /* the gallery's static `open` state sits in flow */
  width: var(--layout-dialog); max-width: 100%;
  padding: 0; margin: 0;
  border: 1px solid var(--color-line-default); border-radius: var(--radius-card);
  background: var(--color-surface-overlay); color: var(--color-ink);
}
.dialog[open] { display: flex; flex-direction: column; }

.dialog:modal {
  position: fixed; inset: 0; margin: auto;
  max-height: calc(100dvh - var(--space-12));
  border: 0; box-shadow: var(--shadow-2);
  overflow: hidden;
  animation: overlay-rise var(--duration-deliberate) var(--easing-standard);
}
.dialog::backdrop { background: var(--overlay-scrim); }

.dialog-body { flex: 1 1 auto; overflow-y: auto; padding: var(--space-6); }
/* The body carries tabindex="0" so a long, control-free dialog can still be scrolled from
   the keyboard; keep the ring inside the clipped panel. */
.dialog-body:focus-visible { outline: 2px solid var(--color-focus); outline-offset: -2px; }
.dialog-title { font-size: var(--text-lg); line-height: var(--leading-lg); }
.dialog-desc { margin-top: var(--space-2); max-width: var(--measure-drawer); font-size: var(--text-base); line-height: var(--leading-base); }
.dialog-body > .stack, .dialog-body > .stack-2 { margin-top: var(--space-4); }

.dialog-actions {
  display: flex; align-items: center; justify-content: flex-end; gap: var(--space-3); flex-wrap: wrap;
  flex: 0 0 auto;
  padding: var(--space-4) var(--space-6);
  border-top: 1px solid var(--color-line-subtle);
  background: var(--color-surface-overlay);
}

/* Filled critical confirmation (§9 Buttons: "a filled critical action is allowed only inside a
   confirmation"). --color-ink-inverse on --color-bad is 6.6:1 light, 6.5:1 dark. */
.dialog-critical .btn-destructive {
  background: var(--color-bad); color: var(--color-ink-inverse);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--color-bad) 80%, var(--color-ink)), inset 0 1px 0 var(--button-highlight), var(--shadow-button);
}
.dialog-critical .btn-destructive:hover, .dialog-critical .btn-destructive[data-state="hover"] {
  background: color-mix(in srgb, var(--color-bad) 85%, var(--color-ink));
}
.dialog-critical .btn-destructive:active, .dialog-critical .btn-destructive[data-state="active"] {
  background: color-mix(in srgb, var(--color-bad) 85%, var(--color-ink));
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--color-bad) 80%, var(--color-ink)), var(--button-press-shadow);
}

/* A full-screen sheet under 720 (0014 pattern 6). The body scrolls; the actions stay at the foot,
   full width, 40 tall (pattern 5). */
@media (max-width: 720px) {
  .dialog:modal { inset: 0; margin: 0; width: 100%; max-width: none; height: 100dvh; max-height: none; border-radius: 0; }
  .dialog-body { padding: var(--space-5) var(--space-4); }
  .dialog-actions { justify-content: stretch; padding: var(--space-3) var(--space-4) calc(var(--space-3) + env(safe-area-inset-bottom, 0px)); }
  .dialog-actions .btn { flex: 1 1 auto; height: var(--button-height-coarse); }
}

/* Escape never discards unsaved work silently (§9d). The overlay island stops the first Escape
   over a dirty form and reveals this line; the second Escape closes. Shared with the drawer. */
.overlay-discard {
  display: none; margin-block-start: var(--space-4);
  padding: var(--space-2) var(--space-3); border-radius: var(--radius-control);
  background: var(--color-warn-tint); color: var(--color-warn);
  font-size: var(--text-xs); line-height: var(--leading-xs);
}
[data-unsaved="true"] .overlay-discard { display: block; }
/* In a footer it takes its own row above the buttons, so nothing has to shuffle to fit it. */
.dialog-actions .overlay-discard, .drawer-foot .overlay-discard { flex: 1 1 100%; margin-block-start: 0; }
@media (forced-colors: active) { .overlay-discard { border: 1px solid CanvasText; color: CanvasText; } }

@media (forced-colors: active) {
  .dialog { border: 1px solid CanvasText; }
  .dialog:modal { border: 1px solid CanvasText; }
  .dialog-critical .btn-destructive { background: ButtonFace; color: ButtonText; border: 1px solid ButtonText; }
}


/* ---- ui/components/drawer.css ---- */
/* Drawer — DESIGN.md §3.1, §9 Overlays. A second sheet: 560 wide, inset 8 from the edges of the
   viewport, radius-card, shadow-2, floating over the table context it came from. Under 720px it
   becomes a full-screen sheet. Native <dialog>: Escape closes and focus returns. Tokens only. */

.drawer {
  position: static;                       /* the gallery's static `open` state sits in flow */
  width: var(--layout-drawer); max-width: 100%;
  max-height: 560px;
  padding: 0; margin: 0;
  border: 1px solid var(--color-line-default); border-radius: var(--radius-card);
  background: var(--color-surface-overlay); color: var(--color-ink);
  overflow: hidden;
}
.drawer[open] { display: flex; flex-direction: column; }

/* Opened with showModal(): a second sheet inset 8 from the inline-end edge, elevated (§3.1). */
.drawer:modal {
  position: fixed;
  inset: var(--sheet-inset) var(--sheet-inset) var(--sheet-inset) auto;
  height: auto; max-height: none;
  border: 0; border-radius: var(--radius-card);
  box-shadow: var(--shadow-2);
  animation: overlay-slide-end var(--duration-deliberate) var(--easing-standard);
}

/* ::backdrop inherits custom properties from the dialog in current browsers; where it
   does not, the scrim simply does not paint and the dialog is still modal. */
.drawer::backdrop { background: var(--overlay-scrim); }

.drawer-head {
  display: flex; align-items: flex-start; gap: var(--space-4); flex: 0 0 auto;
  padding: var(--space-5) var(--space-6);
  border-bottom: 1px solid var(--color-line-subtle);
}
.drawer-title { font-size: var(--text-2xl); line-height: var(--leading-2xl); }
.drawer-desc { margin-top: var(--space-1); max-width: var(--measure-drawer); font-size: var(--text-base); line-height: var(--leading-base); }

.drawer-body { flex: 1 1 auto; overflow-y: auto; padding: var(--space-6); }
/* The body carries tabindex="0" so it can be scrolled from the keyboard; keep the ring inside
   the clipped panel. */
.drawer-body:focus-visible { outline: 2px solid var(--color-focus); outline-offset: -2px; }
.drawer-body > p, .drawer-body > .stack > p { max-width: var(--measure-drawer); }

.drawer-foot {
  display: flex; align-items: center; justify-content: flex-end; gap: var(--space-3); flex: 0 0 auto; flex-wrap: wrap;
  padding: var(--space-4) var(--space-6);
  border-top: 1px solid var(--color-line-subtle);
  background: var(--color-surface-overlay);
}
.drawer-foot .drawer-foot-note { margin-inline-end: auto; }

@media (max-width: 720px) {
  .drawer:modal { inset: 0; width: 100%; max-width: none; border-radius: 0; }
  .drawer-head, .drawer-body { padding-inline: var(--space-4); }
  /* Actions full width at the foot, 40 tall under a thumb (0014 pattern 5). */
  .drawer-foot { justify-content: stretch; padding: var(--space-3) var(--space-4) calc(var(--space-3) + env(safe-area-inset-bottom, 0px)); }
  .drawer-foot .btn { flex: 1 1 auto; height: var(--button-height-coarse); }
  .drawer-foot .overlay-discard, .drawer-foot .drawer-foot-note { flex: 1 1 100%; }
}

@media (forced-colors: active) {
  .drawer { border: 1px solid CanvasText; }
  .drawer:modal { border: 1px solid CanvasText; }
}


/* ---- ui/components/empty-state.css ---- */
/* EmptyState — DESIGN.md §9.2, §6.3 and brand guide §6. Migra only at 28px and only for
   the display moment; the compact variant inside a table drops to NHG Display. Tokens only. */

.empty {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: var(--space-3);
  padding: var(--space-12) var(--space-6);
}
/* §10a: no illustration. The words are the whole shape — statement, one line, one button.
   An error empty state carries its tone on the statement, and still says it in words. */
.empty-error .empty-title { color: var(--color-bad); }

/* Migra floor: text-2xl is 28px. Never set this smaller. */
.empty-title { font-size: var(--text-2xl); line-height: var(--leading-2xl); text-wrap: balance; }
.empty-body { max-width: var(--measure-drawer); font-size: var(--text-md); line-height: var(--leading-md); text-wrap: pretty; }
.empty-action { margin-top: var(--space-2); }

.empty-compact { padding: var(--space-8) var(--space-4); gap: var(--space-2); }
.empty-compact .empty-title {
  font-family: var(--font-title); font-weight: var(--weight-medium);
  font-size: var(--text-lg); line-height: var(--leading-lg);
}
.empty-compact .empty-body { font-size: var(--text-base); line-height: var(--leading-base); }
.empty-compact .empty-action { margin-top: var(--space-1); }

@media (forced-colors: active) {
  .empty-error .empty-title { color: CanvasText; }
}


/* ---- ui/components/feedback-tally.css ---- */
/* FeedbackTally — client feedback counts in a list row (DESIGN.md §9.2). Tokens only. */

.tally { display: inline-flex; align-items: center; gap: var(--space-3); white-space: nowrap; }
.tally-part { display: inline-flex; align-items: center; gap: var(--space-1); color: var(--color-ink-secondary); }
.tally-up { color: var(--color-ok); }
.tally-down { color: var(--color-bad); }
.tally-quiet { color: var(--color-ink-tertiary); }

@media (forced-colors: active) {
  .tally-part, .tally-up, .tally-down { color: CanvasText; }
}


/* ---- ui/components/field-set.css ---- */
/* FieldSet — DESIGN.md §9 Inputs. Label above at 13/500, help 12 tertiary, error 12 `bad` naming
   the fix, below and associated. Tokens only. */

.field { display: flex; flex-direction: column; gap: var(--space-1); min-inline-size: 0; }
.field-label {
  font-size: var(--text-sm); line-height: var(--leading-sm); font-weight: var(--weight-medium);
  color: var(--color-ink); display: inline-flex; align-items: baseline; gap: var(--space-1);
}
.field-help { font-size: var(--text-xs); line-height: var(--leading-xs); color: var(--color-ink-tertiary); }
.field-error {
  display: flex; align-items: flex-start; gap: var(--space-1);
  font-size: var(--text-xs); line-height: var(--leading-xs); color: var(--color-bad);
}
.field-required { color: var(--color-bad); }
.field-disabled .field-label, .field-disabled .field-help { color: var(--color-ink-tertiary); }

/* Native group for radios and checkboxes. */
.field-group { border: 0; padding: 0; margin: 0; min-inline-size: 0; gap: var(--space-2); }
.field-legend { padding: 0; margin-block-end: var(--space-1); }

/* Help sits above the control, so restore the control's own gap under it. */
.field .field-help + * { margin-block-start: var(--space-1); }

@media (forced-colors: active) {
  .field-error { color: CanvasText; }
  .field-required { color: CanvasText; }
}


/* ---- ui/components/input.css ---- */
/* Input — DESIGN.md §9 Inputs, §7 (shape, motion). Tokens only.
   Label above (field-set.css), 36 tall, a real `line-interactive` border, radius 8. Hover firms the
   border to `ink-secondary`; focus is an ink border with a 3px brand-wash halo (see the focus note
   in base.css); `:user-invalid` is a `bad` border with a tint halo.
   `.input` is the bordered field and stands alone; `.input-group` takes the border over when an
   icon or a text adornment sits inside the field. */

.input {
  display: block; inline-size: 100%; min-inline-size: 0;
  height: var(--input-height); padding: 0 var(--input-padding-x);
  border: 1px solid var(--input-border); border-radius: var(--input-radius);
  background: var(--input-bg); color: var(--input-fg);
  font-size: var(--text-base); line-height: var(--leading-base);
  transition: border-color var(--duration-fast) var(--easing-standard), box-shadow var(--duration-fast) var(--easing-standard);
}
.input-touch { height: var(--input-height-touch); font-size: var(--text-md); line-height: var(--leading-md); }
/* Compact field for dense toolbars (the /design mode bar uses it). */
.input-small { height: var(--input-height-small); padding: 0 var(--space-2); font-size: var(--text-sm); line-height: var(--leading-sm); }

.input:hover, .input[data-state="hover"] { border-color: var(--color-ink-secondary); }
.input:focus-visible, .input[data-state="focus"] {
  outline: none;
  border-color: var(--input-focus-border);
  /* Halo first, then a second ink pixel: the border reads as 2px without the box changing size. */
  box-shadow: 0 0 0 var(--input-focus-halo) var(--input-focus-halo-color), 0 0 0 1px var(--input-focus-border);
}
.input:user-invalid, .input[aria-invalid="true"] { border-color: var(--input-border-error); }
.input:user-invalid:focus-visible, .input[aria-invalid="true"]:focus-visible,
.input[aria-invalid="true"][data-state="focus"] {
  border-color: var(--input-border-error);
  box-shadow: 0 0 0 var(--input-focus-halo) var(--input-error-halo-color), 0 0 0 1px var(--input-border-error);
}
.input:disabled { background: var(--color-surface-well); color: var(--color-ink-disabled); border-color: var(--color-line-default); cursor: not-allowed; }
.input:read-only:not(:disabled) { background: var(--color-surface-well); border-color: var(--color-line-default); }

/* Date and number spinners inherit the field's ink rather than the UA's blue. */
.input::-webkit-calendar-picker-indicator { opacity: .6; cursor: pointer; }
.input[type="search"]::-webkit-search-cancel-button { appearance: none; }

/* Adorned field: icon / "$" / "%" sit inside one bordered box. */
.input-group {
  display: flex; align-items: center; gap: var(--space-2);
  inline-size: 100%; height: var(--input-height); padding: 0 var(--input-padding-x);
  border: 1px solid var(--input-border); border-radius: var(--input-radius);
  background: var(--input-bg); color: var(--input-fg);
  transition: border-color var(--duration-fast) var(--easing-standard), box-shadow var(--duration-fast) var(--easing-standard);
}
.input-group-touch { height: var(--input-height-touch); }
.input-group .input {
  flex: 1 1 auto; height: 100%; padding: 0; border: 0; border-radius: 0; background: none;
}
.input-group .input:focus-visible, .input-group .input:user-invalid { outline: none; box-shadow: none; border: 0; }
.input-group:hover { border-color: var(--color-ink-secondary); }
.input-group:focus-within, .input-group[data-state="focus"] {
  border-color: var(--input-focus-border);
  box-shadow: 0 0 0 var(--input-focus-halo) var(--input-focus-halo-color), 0 0 0 1px var(--input-focus-border);
}
.input-group[data-invalid="true"] { border-color: var(--input-border-error); }
.input-group[data-invalid="true"]:focus-within { box-shadow: 0 0 0 var(--input-focus-halo) var(--input-error-halo-color), 0 0 0 1px var(--input-border-error); }
.input-group[data-disabled="true"] { background: var(--color-surface-well); color: var(--color-ink-disabled); border-color: var(--color-line-default); }
.input-group[data-disabled="true"] .input:disabled { background: none; border: 0; }
.input-group-touch .input { font-size: var(--text-md); line-height: var(--leading-md); }

.input-icon { color: var(--color-ink-tertiary); }
.input-affix { flex: 0 0 auto; color: var(--color-ink-secondary); font-variant-numeric: tabular-nums; user-select: none; }

@media (forced-colors: active) {
  .input, .input-group { border-color: CanvasText; }
  /* The halo does not paint in forced colors, so focus falls back to the system ring. */
  .input:focus-visible, .input-group:focus-within { outline: 2px solid CanvasText; outline-offset: 1px; }
  .input:disabled, .input-group[data-disabled="true"] { border-color: GrayText; color: GrayText; }
  .input:user-invalid, .input[aria-invalid="true"], .input-group[data-invalid="true"] { border-style: dashed; }
}


/* ---- ui/components/metric-tile.css ---- */
/* MetricTile — DESIGN.md §9.7 (creator record) / §9.9 (source and freshness). Tokens only.
   The only routine team-app component that elevates one number to display scale. */

/* §9 Cards & tiles: a card is sheet + hairline, radius 12, padding 18–20 — a border OR a
   shadow, never both. The tile is 11 caps label / 28-500 value / 12 delta. */
.metric {
  display: flex; flex-direction: column; gap: var(--space-1); align-items: flex-start;
  min-inline-size: 0; padding: var(--space-4) var(--space-5);
  border: 1px solid var(--color-line-default); border-radius: var(--radius-card);
  background: var(--color-surface-panel);
}
.metric-label { color: var(--color-ink-tertiary); }
/* The only routine place a number stands alone at display size (§9). */
.metric-value {
  font-family: var(--font-title); font-size: var(--text-2xl); line-height: var(--leading-2xl);
  font-weight: var(--weight-medium); color: var(--color-ink); letter-spacing: -0.01em;
}
.metric-display { padding: var(--space-5); }
.metric-display .metric-value { font-size: var(--text-3xl); line-height: var(--leading-3xl); }
.metric-note { font-size: var(--text-xs); line-height: var(--leading-xs); color: var(--color-ink-secondary); }

.metric-delta {
  display: inline-flex; align-items: center; gap: var(--space-1);
  font-size: var(--text-xs); line-height: var(--leading-xs);
}
/* §9b: the colour follows what the movement *means* for this metric, never the arrow's
   direction — a rising cost-per-post points up and is still bad news. */
.metric-delta-good { color: var(--color-ok); }
.metric-delta-bad { color: var(--color-bad); }
.metric-delta-neutral { color: var(--color-ink-secondary); }
.metric-delta-word { color: var(--color-ink-secondary); }

/* Source and "last updated" are a SourceChip disclosure (§9b), reachable by keyboard. */
.metric-source { margin-block-start: var(--space-1); }

/* Loading: a bar the width of a real number, not a spinner. §9a — pulse opacity only. */
.metric-skeleton {
  inline-size: 5ch; block-size: var(--leading-2xl); border-radius: var(--radius-control);
  background: var(--color-surface-well);
  animation: skeleton-pulse 1400ms var(--easing-standard) infinite;
}
.metric-display .metric-skeleton { block-size: var(--leading-3xl); }

@media (forced-colors: active) {
  .metric { border-color: CanvasText; }
  .metric-delta-good, .metric-delta-bad, .metric-delta-neutral { color: CanvasText; }
}


/* ---- ui/components/platform-icon.css ---- */
/* PlatformIcon — DESIGN.md §9.2 (platform cell). Monochrome, currentColor, one 24 grid. Tokens only. */

.platform-icon { flex: 0 0 auto; vertical-align: middle; }

.platform-list { display: inline-flex; align-items: center; gap: var(--space-2); color: var(--color-ink-secondary); }
.platform-list-empty { color: var(--color-ink-tertiary); }

/* Connected: a small check badge over the mark. The word ", connected" is in the label too. */
.platform-connected {
  --platform-size: 20px;
  position: relative; display: inline-flex; flex: 0 0 auto;
  inline-size: var(--platform-size); block-size: var(--platform-size);
}
.platform-badge {
  position: absolute; inset-block-end: -2px; inset-inline-end: -3px;
  inline-size: 10px; block-size: 10px; color: var(--color-ok);
}
.platform-badge-disc { fill: currentColor; stroke: var(--color-surface-panel); stroke-width: 2; }
.platform-badge-check { fill: none; stroke: var(--color-surface-panel); }

@media (forced-colors: active) {
  .platform-badge { forced-color-adjust: none; }
  .platform-badge-disc { fill: CanvasText; stroke: Canvas; }
  .platform-badge-check { stroke: Canvas; }
}


/* ---- ui/components/popover.css ---- */
/* Popover + Menu — DESIGN.md §9 Overlays. Native Popover API: the trigger, Escape and
   click-outside all work with no JS. Radius 10, 4px padding, 32px items, shadow-2; elevation
   only, never elevation plus a border (§7). Enter is a fade plus a 2% scale (§9a). Tokens only. */

.pop-wrap { position: relative; display: inline-block; }

.pop {
  /* Reset the UA popover box, then rebuild it from tokens. */
  position: fixed; margin: 0; border: 0;
  inset-block-start: var(--space-16); inset-inline: var(--space-4); inset-block-end: auto;
  margin-inline: auto;                    /* fallback when anchor positioning is unavailable */
  padding: var(--menu-padding);
  width: max-content; min-width: 200px; max-width: min(320px, calc(100vw - var(--space-8)));
  max-height: min(60dvh, calc(100dvh - var(--shell-bottom-bar) - var(--space-16))); overflow-y: auto; overscroll-behavior: contain;
  background: var(--color-surface-overlay); color: var(--color-ink);
  border-radius: var(--menu-radius); box-shadow: var(--shadow-2);
}
.pop:popover-open { animation: overlay-pop var(--duration-standard) var(--easing-standard); }

@supports (anchor-name: --a) {
  .pop {
    inset: auto; margin-inline: 0;
    position-area: bottom span-inline-end;
    position-try-fallbacks: flip-block, flip-inline;
    margin-block-start: var(--space-1);
  }
  .pop-bottom-end { position-area: bottom span-inline-start; }
}

/* Gallery-only: the panel is not a popover, so it lays out inside the relative wrapper. */
.pop-static {
  position: absolute; position-area: none;
  inset-block-start: calc(100% + var(--space-1)); inset-inline-start: 0; inset-inline-end: auto;
  margin: 0; z-index: 2;
}
.pop-static.pop-bottom-end { inset-inline-start: auto; inset-inline-end: 0; }

.menu { min-width: 220px; }
.menu-item {
  display: flex; align-items: center; gap: var(--space-2); width: 100%; min-height: var(--menu-item-height);
  padding: 0 var(--menu-item-padding-x); border-radius: 6px;
  color: var(--color-ink); text-decoration: none;
  font-size: var(--text-sm); line-height: var(--leading-sm);
  transition: background-color var(--duration-fast) var(--easing-standard);
}
.menu-item:hover, .menu-item[data-state="hover"], .menu-item:focus-visible { background: var(--color-brand-wash); text-decoration: none; }
.menu-item-destructive { color: var(--color-bad); }
.menu-item-destructive:hover, .menu-item-destructive[data-state="hover"] { background: var(--color-bad-tint); }
.menu-item:disabled { color: var(--color-ink-disabled); background: none; cursor: not-allowed; }
.menu-item-label { flex: 1 1 auto; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.menu-item-shortcut { font-size: var(--text-xs); line-height: var(--leading-xs); color: var(--color-ink-tertiary); font-variant-numeric: tabular-nums; }
.menu-item:disabled .menu-item-shortcut { color: var(--color-ink-disabled); }
.menu-item-gutter { width: 16px; height: 16px; flex: 0 0 auto; }

.menu-sep { margin: var(--space-1) 0; border-top: 1px solid var(--color-line-subtle); }
.menu-group + .menu-group { margin-top: var(--space-2); }
.menu-group-label { padding: var(--space-2) var(--menu-item-padding-x) var(--space-1); }

/* Generic panel content: a small form or a block of facts. */
.pop-body { padding: var(--space-3); display: flex; flex-direction: column; gap: var(--space-3); }
.pop-body p { font-size: var(--text-sm); line-height: var(--leading-sm); }

@media (forced-colors: active) {
  .pop { border: 1px solid CanvasText; }
  .menu-item:hover { background: Highlight; color: HighlightText; forced-color-adjust: none; }
  .menu-item:disabled { color: GrayText; }
}


/* ---- ui/components/progress-segments.css ---- */
/* ProgressSegments — DESIGN.md §9.2 (progress cell). Segments plus the count in words. Tokens only. */

.progress { display: inline-flex; flex-direction: column; gap: var(--space-1); align-items: flex-start; min-inline-size: 0; }
.progress-label { color: var(--color-ink-tertiary); }
.progress-track { display: inline-flex; align-items: center; gap: 3px; }
.progress-seg {
  inline-size: 18px; block-size: 6px; border-radius: var(--radius-pill);
  background: var(--color-line-default);
}
.progress-seg-done { background: var(--color-ok); }
/* Bonus deliverables sit past the requirement, so they read as extra, not as more of the same. */
.progress-seg-bonus { background: none; box-shadow: inset 0 0 0 1.5px var(--color-ok); }
.progress-text { font-size: var(--text-xs); line-height: var(--leading-xs); color: var(--color-ink-secondary); white-space: nowrap; }

/* Table cell: one line, 4px bar. The label stays in the accessible name but is not
   repeated on screen — the column header already says "Requirements". */
/* Nothing required: an em dash that explains itself on focus rather than a 0/0 bar. */
.progress-none { flex-direction: row; align-items: center; border-radius: var(--radius-control); }
.progress-none:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }

.progress-small { flex-direction: row; align-items: center; gap: var(--space-2); }
.progress-small .progress-label { display: none; }
.progress-small .progress-seg { inline-size: 12px; block-size: 4px; }
.progress-small .progress-text { font-size: var(--text-sm); line-height: var(--leading-sm); }

@media (forced-colors: active) {
  .progress-seg { forced-color-adjust: none; background: Canvas; box-shadow: inset 0 0 0 1px CanvasText; }
  .progress-seg-done { background: CanvasText; }
  .progress-seg-bonus { background: Canvas; box-shadow: inset 0 0 0 1px CanvasText; }
}


/* ---- ui/components/provenance-chip.css ---- */
/* ProvenanceChip — DESIGN.md §9b, extended for D5. Every enriched field group says where it came
   from, how old it is, and whether anyone confirmed it. Built from the SourceChip's own shapes so
   the two read as one family; `estimated` is the one that carries colour, because an estimate
   sitting beside a measured number has to survive a screenshot. Tokens only. */

.prov {
  display: inline-flex; align-items: center; gap: 3px;
  min-height: 16px; padding-inline: var(--space-1);
  max-width: 100%; min-width: 0;
  border-radius: var(--radius-control);
  background: var(--color-surface-well); color: var(--color-ink-tertiary);
  box-shadow: inset 0 0 0 1px var(--color-line-subtle);
  font-size: var(--text-2xs); line-height: 16px; font-weight: var(--weight-medium);
  white-space: nowrap; vertical-align: middle;
}
.prov-src { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.prov-age { flex: 0 0 auto; }
.prov-check { flex: 0 0 auto; color: var(--color-ok); }

/* Estimated is a claim about certainty, so it is the one group that carries colour. */
.prov-est { background: var(--color-warn-tint); color: var(--color-warn); box-shadow: none; }
.prov-est .prov-check { color: inherit; }

/* The disclosure: the chip is the summary, the sentence is the body. */
.prov-wrap { font-size: var(--text-xs); line-height: var(--leading-xs); min-width: 0; max-width: 100%; }
.prov-wrap > summary {
  display: inline-flex; align-items: center; max-width: 100%; min-width: 0;
  cursor: pointer; border-radius: var(--radius-control); list-style: none;
}
.prov-wrap > summary::marker { content: ""; }
.prov-wrap > summary::-webkit-details-marker { display: none; }
.prov-wrap > summary:hover .prov { color: var(--color-ink-secondary); }
.prov-wrap > summary:hover .prov-est { color: var(--color-warn); }
.prov-detail { margin-block-start: var(--space-1); color: var(--color-ink-secondary); text-wrap: pretty; }

.prov-mark { display: inline-flex; min-width: 0; max-width: 100%; }

.prov-row { display: flex; flex-wrap: wrap; gap: var(--space-1); margin: 0; padding: 0; list-style: none; }
.prov-row > li { display: flex; min-width: 0; }

@media (forced-colors: active) {
  .prov { forced-color-adjust: none; background: Canvas; color: CanvasText; box-shadow: inset 0 0 0 1px CanvasText; }
  .prov-est { background: Canvas; color: CanvasText; box-shadow: inset 0 0 0 2px CanvasText; }
  .prov-check { color: CanvasText; }
}


/* ---- ui/components/radio.css ---- */
/* Radio — DESIGN.md §9.5. Native input, appearance stripped, dot in a contrast-checked pair. Tokens only. */

.radio {
  display: grid; grid-template-columns: auto 1fr; column-gap: var(--space-2); align-items: start;
  min-inline-size: 0;
}
.radio-touch { min-height: var(--target-min); align-content: center; }

.radio-input, .radio-dot { grid-area: 1 / 1; }

.radio-input {
  appearance: none;
  inline-size: var(--control-box); block-size: var(--control-box); margin: 0; margin-block-start: 2px;
  border: 1px solid var(--input-border); border-radius: var(--radius-pill);
  background: var(--input-bg); cursor: pointer;
  transition: background-color var(--duration-fast) var(--easing-standard), border-color var(--duration-fast) var(--easing-standard);
}
.radio-touch .radio-input { inline-size: var(--control-box-touch); block-size: var(--control-box-touch); }
.radio-input:hover, .radio-input[data-state="hover"] { border-color: var(--color-ink-secondary); }
.radio-input[data-state="focus"] { outline: 2px solid var(--color-focus); outline-offset: 2px; }
/* Ink fill, not orange (§3.2, §9 Inputs). */
.radio-input:checked { background: var(--control-fill); border-color: var(--control-fill); }
.radio-input[aria-invalid="true"] { border-color: var(--input-border-error); }
.radio-input:disabled { background: var(--color-surface-well); border-color: var(--color-line-default); cursor: not-allowed; }
.radio-input:disabled:checked { background: var(--color-line-default); border-color: var(--color-line-default); }

.radio-dot {
  inline-size: var(--control-box); block-size: var(--control-box); margin-block-start: 2px;
  display: grid; place-items: center; pointer-events: none; visibility: hidden;
}
.radio-touch .radio-dot { inline-size: var(--control-box-touch); block-size: var(--control-box-touch); }
.radio-dot::after {
  content: ""; inline-size: 6px; block-size: 6px; border-radius: var(--radius-pill);
  background: var(--control-mark);
}
.radio-input:checked ~ .radio-dot { visibility: visible; }
.radio-input:disabled ~ .radio-dot::after { background: var(--color-surface-panel); }

.radio-text { grid-area: 1 / 2; display: flex; flex-direction: column; gap: 2px; min-inline-size: 0; }
.radio-label { font-size: var(--text-base); line-height: var(--leading-base); cursor: pointer; }
.radio-desc { font-size: var(--text-xs); line-height: var(--leading-xs); color: var(--color-ink-secondary); }
.radio[data-disabled="true"] .radio-label { color: var(--color-ink-tertiary); cursor: not-allowed; }
.radio[data-disabled="true"] .radio-desc { color: var(--color-ink-tertiary); }

@media (forced-colors: active) {
  .radio-input { border-color: CanvasText; }
  .radio-input:checked { background: Highlight; border-color: Highlight; }
  .radio-dot::after { background: HighlightText; forced-color-adjust: none; }
  .radio-input:disabled { border-color: GrayText; }
  .radio[data-disabled="true"] .radio-label, .radio[data-disabled="true"] .radio-desc { color: GrayText; }
}


/* ---- ui/components/segmented.css ---- */
/* Segmented control — DESIGN.md §9 Buttons. A well holding raised segments; the selected one
   is the sheet lifted out of the well. Tokens only. */

.segmented {
  display: inline-flex; align-items: center; gap: 2px;
  height: var(--segmented-height); padding: 2px;
  background: var(--color-surface-well);
  border-radius: var(--segmented-radius);
  box-shadow: inset 0 0 0 1px var(--color-line-default);
  position: relative; max-width: 100%; overflow-x: auto; scrollbar-width: none;
}
.segmented-item {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
  height: var(--segmented-item-height); padding: 0 var(--space-3);
  border: 0; border-radius: var(--segmented-item-radius);
  background: transparent; color: var(--color-ink-secondary);
  font-size: var(--text-sm); line-height: 1; font-weight: var(--weight-medium);
  white-space: nowrap; text-decoration: none;
  transition: background-color var(--duration-fast) var(--easing-standard), color var(--duration-fast) var(--easing-standard), box-shadow var(--duration-fast) var(--easing-standard);
}
.segmented-item:hover, .segmented-item[data-state="hover"] { color: var(--color-ink); background: var(--color-brand-wash); text-decoration: none; }
.segmented-item[data-state="focus"] { outline: 2px solid var(--color-focus); outline-offset: 2px; }
.segmented-item[aria-pressed="true"], .segmented-item[aria-current="true"] {
  background: var(--color-surface-panel); color: var(--color-ink);
  box-shadow: inset 0 0 0 1px var(--color-line-default), inset 0 1px 0 var(--button-highlight), var(--shadow-button);
}
.segmented-item[disabled], .segmented-item[aria-disabled="true"] { color: var(--color-ink-disabled); cursor: not-allowed; background: transparent; box-shadow: none; }

.segmented-small { height: var(--button-height-small); }
.segmented-small .segmented-item { height: 24px; padding: 0 var(--space-2); font-size: var(--text-xs); }

@media (forced-colors: active) {
  .segmented { box-shadow: none; border: 1px solid CanvasText; }
  .segmented-item[aria-pressed="true"], .segmented-item[aria-current="true"] { forced-color-adjust: none; background: Highlight; color: HighlightText; box-shadow: none; }
  .segmented-item[disabled] { color: GrayText; }
}


/* ---- ui/components/select.css ---- */
/* Select — DESIGN.md §9.5. Native control, one chevron drawn over it. Tokens only. */

.select-wrap { position: relative; display: block; inline-size: 100%; min-inline-size: 0; }
.select {
  appearance: none;
  inline-size: 100%;
  padding-inline-end: var(--space-8);
  cursor: pointer;
}
.select:disabled { cursor: not-allowed; }
/* The prompt reads as placeholder text until a real option is chosen. */
.select[data-placeholder="true"] { color: var(--input-placeholder); }
.select option { color: var(--color-ink); background: var(--color-surface-panel); }

.select-chevron {
  position: absolute; inset-block-start: 50%; inset-inline-end: var(--space-3);
  translate: 0 -50%; pointer-events: none; color: var(--color-ink-secondary);
}
.select-wrap[data-disabled="true"] .select-chevron { color: var(--color-ink-disabled); }

@media (forced-colors: active) {
  .select-chevron { color: CanvasText; }
  .select-wrap[data-disabled="true"] .select-chevron { color: GrayText; }
}


/* ---- ui/components/shelfworthy-mark.css ---- */
/* The Shelfworthy mark sits on the text baseline of whatever names it. */
.sw-mark { display: inline-block; vertical-align: -0.15em; flex: none; }
.sw-mark-wordmark { vertical-align: middle; }


/* ---- ui/components/skeleton.css ---- */
/* Skeleton — DESIGN.md §9 (Feedback: skeletons preserve real widths) and §9a (Motion:
   "Skeletons pulse opacity, never position"). One shared `skeleton-pulse` keyframe, used
   here and by any component that draws its own loading bar. tokens.css sets
   `animation: none` under prefers-reduced-motion, leaving a flat well. Tokens only. */

/* §9a: opacity only. Nothing travels; nothing shimmers across the block. */
@keyframes skeleton-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.45; }
}

.skeleton {
  display: block; flex: 0 0 auto;
  border-radius: var(--radius-control);
  background-color: var(--color-surface-well);
  box-shadow: inset 0 0 0 1px var(--color-line-subtle);
  animation: skeleton-pulse 1400ms var(--easing-standard) infinite;
}

.skeleton-text { block-size: var(--leading-base); inline-size: 100%; }
.skeleton-title { block-size: var(--leading-xl); inline-size: 18ch; border-radius: var(--radius-control); }
.skeleton-row { block-size: var(--table-row-comfortable); inline-size: 100%; border-radius: var(--radius-control); }
.skeleton-tile { block-size: 72px; inline-size: 100%; border-radius: var(--radius-card); }
/* Square from the width, so one `width` gives a 24 / 40 / 56 circle. */
.skeleton-avatar { inline-size: var(--avatar-md); block-size: auto; aspect-ratio: 1; border-radius: var(--radius-pill); }
.skeleton-block { block-size: 120px; inline-size: 100%; border-radius: var(--radius-card); }

.skeleton-lines { display: flex; flex-direction: column; gap: var(--space-2); inline-size: 100%; }
.skeleton-group { min-inline-size: 0; }
/* Print, export, and the gallery's reduced-motion demonstration. */
.skeleton-still, .skeleton-still .skeleton { animation: none; }

@media (forced-colors: active) {
  .skeleton { forced-color-adjust: none; background: Canvas; border: 1px solid GrayText; }
}


/* ---- ui/components/source-chip.css ---- */
/* SourceChip — DESIGN.md §9b. A metric declares where it came from, in one word.
   Quiet for the three sources you can stand behind; tinted for `estimated`, which is the
   one that has to survive a screenshot. Tokens only. */

.src {
  display: inline-flex; align-items: center;
  block-size: 16px; padding-inline: var(--space-1);
  border-radius: var(--radius-control);
  background: var(--color-surface-well); color: var(--color-ink-tertiary);
  box-shadow: inset 0 0 0 1px var(--color-line-subtle);
  font-size: var(--text-2xs); line-height: 1; font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-label); text-transform: uppercase;
  white-space: nowrap; vertical-align: middle;
}
/* Estimated is a claim about certainty, so it is the one source that carries colour. */
.src-estimated { background: var(--color-warn-tint); color: var(--color-warn); box-shadow: none; }

/* The disclosure: the chip is the summary, the sentence and the date are the body. */
.src-wrap { font-size: var(--text-xs); line-height: var(--leading-xs); }
.src-wrap > summary {
  display: inline-flex; align-items: center; gap: var(--space-1);
  cursor: pointer; border-radius: var(--radius-control); list-style: none;
}
.src-wrap > summary::marker { content: ""; }
.src-wrap > summary::-webkit-details-marker { display: none; }
.src-wrap > summary:hover .src { color: var(--color-ink); }
.src-wrap > summary:hover .src-estimated { color: var(--color-warn); }
.src-detail { margin-block-start: var(--space-1); color: var(--color-ink-secondary); text-wrap: pretty; }

@media (forced-colors: active) {
  .src { forced-color-adjust: none; background: Canvas; color: CanvasText; box-shadow: inset 0 0 0 1px CanvasText; }
  .src-estimated { background: Canvas; color: CanvasText; box-shadow: inset 0 0 0 2px CanvasText; }
}


/* ---- ui/components/status-pill.css ---- */
/* StatusPill — DESIGN.md §9 (Status): pill 22 tall, tint + 6px dot + 12/500 text,
   semantic colour by meaning. The word carries the state; the dot and the tint reinforce it,
   so the pill survives greyscale, forced colours and a colourblind reader. Tokens only. */
.pill {
  display: inline-flex; align-items: center; gap: var(--space-1);
  height: var(--pill-height); padding-inline: 7px 9px;
  border-radius: var(--pill-radius);
  /* §9 asks for 12/500 here. `--pill-text` still says 11px in tokens.css — see the report. */
  font-size: var(--text-xs); line-height: 1; font-weight: var(--weight-medium);
  white-space: nowrap; vertical-align: middle; letter-spacing: 0.01em;
}
/* The 6px dot. `currentColor` keeps it locked to the tone's own text colour, which is the
   colour already contrast-checked against the tint. */
.pill::before {
  content: ""; flex: 0 0 auto;
  inline-size: 6px; block-size: 6px; border-radius: var(--radius-pill);
  background: currentColor;
}
.pill-large { height: 24px; padding-inline: var(--space-2) var(--space-3); font-size: var(--text-xs); }
.pill-ok { background: var(--color-ok-tint); color: var(--color-ok); }
.pill-warn { background: var(--color-warn-tint); color: var(--color-warn); }
.pill-bad { background: var(--color-bad-tint); color: var(--color-bad); }
.pill-info { background: var(--color-info-tint); color: var(--color-info); }
.pill-neutral { background: var(--color-neutral-tint); color: var(--color-neutral); box-shadow: inset 0 0 0 1px var(--color-line-default); }
/* A neutral state is the absence of heat, so its dot is a ring rather than a filled mark. */
.pill-neutral::before { background: none; box-shadow: inset 0 0 0 1.5px currentColor; }

@media (forced-colors: active) {
  .pill { border: 1px solid CanvasText; }
  .pill::before { forced-color-adjust: none; background: CanvasText; }
  .pill-neutral::before { background: Canvas; box-shadow: inset 0 0 0 1px CanvasText; }
}


/* ---- ui/components/switch.css ---- */
/* Switch — DESIGN.md §9 Inputs / §11. 34×20 track plus a visible word; state never rides on
   colour alone. Position uses the `translate` property, not `transform`, so a reduced-motion
   setting collapses the duration (base.css) without stranding the thumb. Tokens only. */

.switch { display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); min-inline-size: 0; }
.switch-text { display: flex; flex-direction: column; gap: 2px; min-inline-size: 0; }
.switch-label { font-size: var(--text-base); line-height: var(--leading-base); }
.switch-desc { font-size: var(--text-xs); line-height: var(--leading-xs); color: var(--color-ink-secondary); }

.switch-control {
  display: inline-flex; align-items: center; gap: var(--space-2); flex: 0 0 auto;
  padding: var(--space-1); margin: calc(var(--space-1) * -1); border-radius: var(--radius-control);
}
.switch-touch .switch-control { min-block-size: var(--target-min); padding-inline: var(--space-2); }

.switch-track {
  position: relative; display: inline-block; flex: 0 0 auto;
  inline-size: var(--switch-width); block-size: var(--switch-height);
  border: 1px solid var(--color-line-interactive); border-radius: var(--radius-pill);
  background: var(--switch-off-bg);
  transition: background-color var(--duration-fast) var(--easing-standard), border-color var(--duration-fast) var(--easing-standard);
}
.switch-touch .switch-track { inline-size: var(--switch-width-touch); block-size: var(--switch-height-touch); }

.switch-thumb {
  position: absolute; inset-block-start: 2px; inset-inline-start: 2px;
  inline-size: var(--switch-thumb); block-size: var(--switch-thumb); border-radius: var(--radius-pill);
  background: var(--color-ink-secondary);
  transition: translate var(--duration-fast) var(--easing-standard), background-color var(--duration-fast) var(--easing-standard);
}
.switch-touch .switch-thumb { inline-size: var(--switch-thumb-touch); block-size: var(--switch-thumb-touch); }

/* On is `ok`, not orange (§9 Inputs): the switch reports a state, and orange marks a place. */
.switch-control[aria-checked="true"] .switch-track { background: var(--switch-on-bg); border-color: var(--switch-on-bg); }
.switch-control[aria-checked="true"] .switch-thumb { background: var(--color-ink-inverse); translate: calc(var(--switch-width) - var(--switch-thumb) - 6px) 0; }
.switch-touch .switch-control[aria-checked="true"] .switch-thumb { translate: calc(var(--switch-width-touch) - var(--switch-thumb-touch) - 6px) 0; }

.switch-word {
  min-inline-size: 3ch; font-size: var(--text-sm); line-height: var(--leading-sm);
  font-weight: var(--weight-medium); color: var(--color-ink-secondary);
}
.switch-control[aria-checked="true"] .switch-word { color: var(--color-ink); }

.switch-control:hover .switch-track, .switch-control[data-state="hover"] .switch-track { border-color: var(--color-ink-secondary); }
.switch-control[data-state="focus"] { outline: 2px solid var(--color-focus); outline-offset: 2px; }

.switch-control:disabled { cursor: not-allowed; }
.switch-control:disabled .switch-track { background: var(--color-surface-well); border-color: var(--color-line-default); }
.switch-control:disabled .switch-thumb { background: var(--color-ink-disabled); }
.switch-control:disabled[aria-checked="true"] .switch-track { background: var(--color-line-default); border-color: var(--color-line-default); }
.switch-control:disabled[aria-checked="true"] .switch-thumb { background: var(--color-surface-panel); }
.switch-control:disabled .switch-word { color: var(--color-ink-tertiary); }
.switch[data-disabled="true"] .switch-label { color: var(--color-ink-tertiary); }
.switch[data-disabled="true"] .switch-desc { color: var(--color-ink-tertiary); }

@media (forced-colors: active) {
  .switch-track { border-color: CanvasText; }
  .switch-thumb { background: CanvasText; forced-color-adjust: none; }
  .switch-control[aria-checked="true"] .switch-track { background: Highlight; border-color: Highlight; }
  .switch-control[aria-checked="true"] .switch-thumb { background: HighlightText; }
  .switch-control:disabled .switch-track { border-color: GrayText; }
  .switch-control:disabled .switch-thumb { background: GrayText; }
}


/* ---- ui/components/tabs.css ---- */
/* Tabs — DESIGN.md §9.6 (navigation) and §9.7 (creator record). Text tabs with a 2px
   active underline; never pills. Tokens only. */

.tabs { position: relative; border-bottom: 1px solid var(--color-line-subtle); min-width: 0; }
/* One line, scrolling sideways (0014 pattern 4). Positioned so the visually-hidden text inside a
   tab cannot escape the scroll box and widen the page. */
.tabs-list { position: relative; display: flex; align-items: stretch; flex-wrap: nowrap; gap: var(--space-5); overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: thin; }
/* A fade on the edge that hides more tabs. `tabs.js` sets data-scroll="start end" as the strip
   moves; without it there is no fade and the strip still scrolls. The fade takes the surface
   the strip sits on — `--tabs-fade` for a strip on a well or a band. */
.tabs::before, .tabs::after {
  content: ""; position: absolute; top: 0; bottom: 1px; width: var(--space-8); pointer-events: none;
  opacity: 0; transition: opacity var(--duration-fast) var(--easing-standard);
}
.tabs::after { right: 0; background: linear-gradient(to right, transparent, var(--tabs-fade, var(--color-surface-panel))); }
.tabs::before { left: 0; background: linear-gradient(to left, transparent, var(--tabs-fade, var(--color-surface-panel))); }
.tabs[data-scroll~="end"]::after, .tabs[data-scroll~="start"]::before { opacity: 1; }

.tab {
  display: inline-flex; align-items: center; gap: var(--space-2);
  padding: var(--space-3) 0; margin-bottom: -1px;
  border-bottom: 2px solid transparent;
  color: var(--color-ink-secondary); text-decoration: none; white-space: nowrap;
  font-size: var(--text-base); line-height: var(--leading-base);
  transition: color var(--duration-fast) var(--easing-standard), border-color var(--duration-fast) var(--easing-standard);
}
.tab:hover, .tab[data-state="hover"] { color: var(--color-ink); border-bottom-color: var(--color-line-interactive); text-decoration: none; }
.tab:active, .tab[data-state="active"] { color: var(--color-ink); border-bottom-color: var(--color-brand-strong); }
.tab[data-state="focus"] { outline: 2px solid var(--color-focus); outline-offset: 2px; }

/* Active: underline + full-contrast ink + weight. Never colour alone (§11). */
.tab[aria-current], .tab[aria-selected="true"] {
  color: var(--color-ink); border-bottom-color: var(--color-brand); font-weight: var(--weight-medium);
}
.tab[aria-disabled="true"] { color: var(--color-ink-disabled); cursor: not-allowed; }
.tab[aria-disabled="true"]:hover { border-bottom-color: transparent; }

.tab-count { font-size: var(--text-xs); line-height: var(--leading-xs); color: var(--color-ink-tertiary); }
.tab[aria-current] .tab-count, .tab[aria-selected="true"] .tab-count { color: var(--color-ink-secondary); }

/* Panel mode. Without JS every panel is stacked under its heading; tabs.js hides the
   headings and the inactive panels once the tab pattern is live. */
.tabs-panel { padding-top: var(--space-5); }
.tabs-panel + .tabs-panel { border-top: 1px solid var(--color-line-subtle); margin-top: var(--space-5); }
.tabs-panelset[data-tabs-enhanced] .tabs-panel + .tabs-panel { border-top: 0; margin-top: 0; }
.tabs-panel-heading { font-family: var(--font-title); font-size: var(--text-lg); line-height: var(--leading-lg); font-weight: var(--weight-medium); margin-bottom: var(--space-3); }
.tabs-panel:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }

@media (max-width: 720px) {
  .tabs-list { gap: var(--space-4); scrollbar-width: none; }
  /* A little room at the trailing edge so the last tab clears the fade when scrolled to the end. */
  .tabs-list::after { content: ""; flex: 0 0 var(--space-4); }
}

@media (forced-colors: active) {
  .tabs::before, .tabs::after { display: none; }
  .tab[aria-current], .tab[aria-selected="true"] { border-bottom-color: Highlight; }
  .tab[aria-disabled="true"] { color: GrayText; }
}


/* ---- ui/components/textarea.css ---- */
/* Textarea — DESIGN.md §9.5. Inherits the .input box; grows from a floor, never shrinks below it. */

.textarea-wrap { display: flex; flex-direction: column; gap: var(--space-1); min-inline-size: 0; }
.textarea {
  height: auto;
  min-height: calc(var(--input-height) * 2);
  padding: var(--space-2) var(--space-3);
  resize: vertical;
  field-sizing: content;
}
.textarea-count {
  align-self: flex-end;
  font-size: var(--text-xs); line-height: var(--leading-xs); color: var(--color-ink-secondary);
}


/* ---- ui/components/timeline.css ---- */
/* Timeline — DESIGN.md §9.7 (Activity tab) and §10 (dates: `Jul 18, 2026` in records).
   Every actor kind has its own icon shape and a word for assistive technology, so the
   marker never depends on colour. Tokens only. */

.timeline { display: flex; flex-direction: column; }

.timeline-day {
  position: sticky; inset-block-start: 0; z-index: 1;
  padding: var(--space-2) 0;
  background: var(--color-surface-panel);
  border-bottom: 1px solid var(--color-line-subtle);
}
.timeline-group + .timeline-group { margin-top: var(--space-4); }

.timeline-items { display: flex; flex-direction: column; }
.timeline-item {
  display: grid; grid-template-columns: 24px 72px 1fr; gap: var(--space-3);
  align-items: start;
  padding: var(--space-3) 0;
}
.timeline-item + .timeline-item { border-top: 1px solid var(--color-line-subtle); }

.timeline-marker {
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; border-radius: var(--radius-pill);
  background: var(--color-surface-well); color: var(--color-ink-secondary);
  box-shadow: inset 0 0 0 1px var(--color-line-subtle);
}
/* §9e: the dot takes semantic colour only for money and outcomes. Actor kind is carried by
   the icon's shape and by a visually-hidden word, never by colour. */
.timeline-marker[data-tone="money"] { background: var(--color-ok-tint); color: var(--color-ok); box-shadow: none; }
.timeline-marker[data-tone="good"] { background: var(--color-ok-tint); color: var(--color-ok); box-shadow: none; }
.timeline-marker[data-tone="bad"] { background: var(--color-bad-tint); color: var(--color-bad); box-shadow: none; }
.timeline-marker[data-tone="attention"] { background: var(--color-warn-tint); color: var(--color-warn); box-shadow: none; }

.timeline-time {
  font-size: var(--text-sm); line-height: var(--leading-lg);
  color: var(--color-ink-tertiary); white-space: nowrap;
}
.timeline-text { font-size: var(--text-base); line-height: var(--leading-lg); color: var(--color-ink-secondary); }
.timeline-actor { color: var(--color-ink); font-weight: var(--weight-medium); }
.timeline-type { font-size: var(--text-xs); }

.timeline-empty { padding: var(--space-6) 0; font-size: var(--text-base); line-height: var(--leading-base); }

/* Loading: three bars that keep the block's height and pulse opacity only (§9a). */
.timeline-loading { gap: var(--space-4); padding: var(--space-4) 0; }
.timeline-bar {
  display: block; height: 12px; border-radius: var(--radius-control);
  background: var(--color-surface-well); box-shadow: inset 0 0 0 1px var(--color-line-subtle);
  animation: skeleton-pulse 1400ms var(--easing-standard) infinite;
}
.timeline-bar:nth-child(2) { width: 72%; }
.timeline-bar:nth-child(3) { width: 56%; }
.timeline-bar:nth-child(4) { width: 64%; }

@media (max-width: 560px) {
  .timeline-item { grid-template-columns: 24px 1fr; }
  .timeline-time { grid-column: 2; }
  .timeline-text { grid-column: 2; }
}

@media (forced-colors: active) {
  .timeline-marker, .timeline-marker[data-tone] { border: 1px solid CanvasText; color: CanvasText; background: Canvas; }
  .timeline-bar { border: 1px solid GrayText; }
}


/* ---- ui/components/toast.css ---- */
/* Toast — DESIGN.md §9 (feedback) and §5.4. Inverse surface: the approved tooltip/toast
   pair. Ink ground, ink-inverse text and icon, a 4px tone bar as an accent. Tokens only. */

.toast-region {
  position: fixed; z-index: 60;
  /* Clear of the phone's bottom bar: the shell sets `--shell-bottom-bar` (0 where there is none). */
  inset-block-end: calc(var(--shell-bottom-bar) + var(--space-4)); inset-inline-end: var(--space-4);
  display: flex; flex-direction: column; align-items: flex-end; gap: var(--space-2);
  max-width: calc(100% - var(--space-8));
  pointer-events: none;
}
.toast-region > * { pointer-events: auto; }
.toast-region-inline { position: static; align-items: flex-start; max-width: 100%; }

.toast {
  position: relative; display: flex; align-items: flex-start; gap: var(--space-3);
  min-width: 280px; max-width: 420px;
  padding: var(--space-3) var(--space-3) var(--space-3) var(--space-4);
  background: var(--color-ink); color: var(--color-ink-inverse);
  border-radius: var(--radius-control); box-shadow: var(--shadow-2);
  overflow: hidden;
  /* §9a: a toast is a 160ms thing. It enters from the corner it lives in and travels 8px. */
  transition: opacity calc(var(--duration-standard) * 0.75) var(--easing-standard);
  animation: toast-in var(--duration-standard) var(--easing-standard);
}
@keyframes toast-in {
  from { opacity: 0; transform: translateY(8px); }
}
.toast[data-dismissing] { opacity: 0; }

.toast-bar { position: absolute; inset-block: 0; inset-inline-start: 0; width: 4px; }
.toast-ok .toast-bar { background: var(--color-ok-tint); }
.toast-info .toast-bar { background: var(--color-info-tint); }
.toast-warn .toast-bar { background: var(--color-warn-tint); }
.toast-bad .toast-bar { background: var(--color-bad-tint); }

.toast-icon { flex: 0 0 auto; margin-block-start: 2px; color: var(--color-ink-inverse); }
.toast-message { flex: 1 1 auto; min-width: 0; font-size: var(--text-base); line-height: var(--leading-base); }
.toast-action {
  flex: 0 0 auto; align-self: center;
  color: var(--color-ink-inverse); font-weight: var(--weight-medium);
  text-decoration-color: currentColor;
}
.toast-dismiss {
  flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; border-radius: var(--radius-control);
  color: var(--color-ink-inverse);
}
.toast-dismiss:hover { background: color-mix(in srgb, var(--color-ink-inverse) 20%, transparent); }

@media (max-width: 480px) {
  .toast-region { inset-inline: var(--space-4); align-items: stretch; }
  .toast { min-width: 0; max-width: none; }
}

@media (forced-colors: active) {
  .toast { forced-color-adjust: none; background: Canvas; color: CanvasText; border: 1px solid CanvasText; }
  .toast-icon, .toast-action, .toast-dismiss { color: CanvasText; }
  .toast-bar { background: CanvasText; }
}


/* ---- ui/components/toolbar.css ---- */
/* Toolbar — DESIGN.md §9.2, decision 0014 pattern 3. Tokens only.
   Desktop: views · chips · Add filter · Clear all ……… search · actions · density · columns.
   Phone: one row of search · Filters · More, then the chips scrolling sideways. Same markup;
   the stylesheet decides which controls have a box at which width. */

.toolbar { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; min-width: 0; }
.toolbar-right { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; margin-inline-start: auto; }
.toolbar-filters { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
/* The chips have no box of their own on a desktop, so the row reads chips, Add filter, Clear all. */
.toolbar-chips { display: contents; }
.toolbar-chips .dt-clear { order: 1; }
.toolbar-filter-add { display: inline-flex; }
.toolbar-search, .toolbar-desktop { display: flex; align-items: center; gap: var(--space-2); }
/* The More menu has no box on a desktop: its contents sit in the row where the actions always were. */
.toolbar-more { display: contents; }
.toolbar-more-trigger, .toolbar-more-views,
.toolbar-filter-icon-phone, .toolbar-filter-label-phone { display: none; }
.toolbar-more-label { padding: var(--space-2) var(--space-3) var(--space-1); }

/* ---- Narrow and phone (≤ 1024, decision 0014 pattern 3): collapse, never more than two rows.
   Row one: search · Filters · More. Row two: the active chips, one line, scrolling sideways.
   Views and the actions live in More; density and the column manager are desktop-only. ---- */
@media (max-width: 1024px) {
  .toolbar { gap: var(--space-2); }
  .toolbar-filters, .toolbar-right { display: contents; }
  .toolbar-views, .toolbar-desktop, .toolbar-filter-icon-desktop, .toolbar-filter-label-desktop { display: none; }
  .toolbar-filter-icon-phone { display: block; }
  .toolbar-filter-label-phone { display: inline; }
  /* Row one: search grows, then Filters, then More. All three stand 36 tall like the field. */
  .toolbar-search { order: 0; flex: 1 1 160px; min-width: 0; }
  .toolbar-search > * { flex: 1 1 auto; min-width: 0; }
  .toolbar-filter-add { order: 1; }
  .toolbar-more-trigger { order: 2; display: inline-flex; }
  .toolbar-filter-add .btn, .toolbar-more-trigger {
    height: var(--button-height); padding-inline: var(--button-padding-x-small); border-radius: var(--button-radius);
    background: var(--button-secondary-bg); color: var(--button-secondary-fg);
    box-shadow: inset 0 0 0 1px var(--button-secondary-border), inset 0 1px 0 var(--button-highlight), var(--shadow-button);
  }
  /* Row two: the active chips, one line, scrolling sideways; Clear all rides at the end. */
  .toolbar-chips { order: 3; display: flex; align-items: center; gap: var(--space-2); flex: 1 1 100%; min-width: 0;
    overflow-x: auto; position: relative; padding-block: 2px; scrollbar-width: none; overscroll-behavior-x: contain; }
  .toolbar-chips:empty { display: none; }
  .toolbar-chips > * { flex: 0 0 auto; }
  .toolbar-chips .dt-clear { order: 0; white-space: nowrap; }
  /* More is a real menu now: anchored under its trigger like every other menu (pattern 6). */
  .toolbar-more:not(:popover-open) { display: none; }
  .toolbar-more:popover-open {
    position: fixed; margin: 0; border: 0;
    inset-block-start: var(--space-16); inset-inline: var(--space-4); inset-block-end: auto; margin-inline: auto;
    display: flex; flex-direction: column; gap: 2px;
    padding: var(--menu-padding); width: max-content; min-width: 220px; max-width: min(360px, calc(100vw - var(--space-8)));
    max-height: 60dvh; overflow-y: auto; overscroll-behavior: contain;
    background: var(--color-surface-overlay); color: var(--color-ink); border-radius: var(--menu-radius); box-shadow: var(--shadow-2);
    animation: overlay-pop var(--duration-standard) var(--easing-standard);
  }
  .toolbar-more:popover-open .btn { width: 100%; justify-content: flex-start; height: var(--menu-item-height); box-shadow: none; background: transparent; color: var(--color-ink); border-radius: 6px; padding-inline: var(--menu-item-padding-x); }
  .toolbar-more:popover-open .btn:hover { background: var(--color-brand-wash); }
  .toolbar-more:popover-open .pop-wrap { display: block; }
  .toolbar-more:popover-open .pop-wrap > .btn .btn-label { display: inline; }
  .toolbar-more-views { display: flex; flex-direction: column; gap: 2px; padding-block-end: var(--space-1); margin-block-end: var(--space-1); border-bottom: 1px solid var(--color-line-subtle); }
  .toolbar-more-views .dt-menu-item[aria-current] { font-weight: var(--weight-medium); }
}
@supports (anchor-name: --a) {
  @media (max-width: 1024px) {
    .toolbar-more:popover-open { inset: auto; margin-inline: 0; margin-block-start: var(--space-1); position-area: bottom span-inline-start; position-try-fallbacks: flip-block, flip-inline; }
  }
}

/* ---- Phone (≤ 720): the filter set and More open as a sheet from the bottom, above the bar,
   with 40-tall rows under a thumb (patterns 3, 6, 8). ---- */
@media (max-width: 720px) {
  .toolbar-sheet, .toolbar-sheet:popover-open {
    position: fixed; inset: auto 0 var(--shell-bottom-bar) 0; margin: 0;
    width: auto; min-width: 0; max-width: none; max-height: 70dvh; overflow-y: auto; overscroll-behavior: contain;
    padding: var(--space-3) var(--space-3) calc(var(--space-4) + env(safe-area-inset-bottom, 0px));
    border-radius: var(--radius-card) var(--radius-card) 0 0;
    position-area: none; position-try-fallbacks: none;
    animation: overlay-rise var(--duration-deliberate) var(--easing-standard);
  }
  .toolbar-more:popover-open { gap: var(--space-1); }
  .toolbar-more:popover-open .btn { height: var(--button-height-coarse); }
  .toolbar-more:popover-open .dt-menu-item { min-height: var(--button-height-coarse); }
}

@media (forced-colors: active) {
  .toolbar-sheet { border: 1px solid CanvasText; }
}


/* ---- ui/components/verdict-dot.css ---- */
/* VerdictDot — DESIGN.md §9.2 (verdict cell) / §9.3. Dot + word; the word does the work. Tokens only. */

.verdict { display: inline-flex; align-items: baseline; gap: var(--space-2); white-space: nowrap; vertical-align: middle; }
.verdict-dot {
  flex: 0 0 auto; inline-size: 8px; block-size: 8px; border-radius: var(--radius-pill);
  background: currentColor; translate: 0 -1px;
}
.verdict-word { font-size: var(--text-sm); line-height: var(--leading-sm); color: var(--color-ink); min-inline-size: 0; }

.verdict-cleared { color: var(--color-ok); }
.verdict-review { color: var(--color-warn); }
.verdict-blocked { color: var(--color-bad); }
/* Not run has never been asked, so the dot is a hollow ring rather than a filled state. */
.verdict-not_run { color: var(--color-ink-secondary); }
.verdict-not_run .verdict-dot { background: none; box-shadow: inset 0 0 0 1.5px currentColor; }

/* Word-only (proposal cards) still carries the tone, so it stays legible in print. */
.verdict-word-only .verdict-word { color: currentColor; font-weight: var(--weight-medium); }

@media (forced-colors: active) {
  .verdict-dot { border: 1px solid CanvasText; forced-color-adjust: none; background: CanvasText; }
  .verdict-not_run .verdict-dot { background: Canvas; }
}


/* ---- ui/layout/app-shell.css ---- */
/* AppShell — DESIGN.md §3.1 (sheet on ground), §8 (layout), §9 (shell pattern). Tokens only.
   The rail lives on the off-white ground: no white sidebar, no dividing border. The workspace is
   a white sheet inset 8px with a hairline edge and radius-card, and it is the thing that scrolls,
   so the sheet keeps its rounded corners and its inset at every scroll position. */

.shell { display: grid; grid-template-columns: var(--layout-rail) minmax(0, 1fr);
  height: var(--shell-height, 100dvh); overflow: hidden;
  background: var(--color-surface-ground); position: relative; }
.shell[data-rail="pinned"] { grid-template-columns: var(--layout-rail-expanded) minmax(0, 1fr); }

/* ---- Rail: on the ground ---- */
.rail { position: relative; z-index: 20; height: 100%; width: var(--layout-rail);
  display: flex; flex-direction: column; padding: var(--space-2); gap: var(--space-1);
  background: transparent; border: 0; overflow: hidden;
  transition: width var(--duration-standard) var(--easing-standard), box-shadow var(--duration-standard) var(--easing-standard); }
/* Unpinned, the expanded rail floats over the sheet, so it takes an overlay ground and shadow-2.
   Pinned, the grid column is already 220 wide and the rail stays flat on the ground. */
.shell:not([data-rail="pinned"]) .rail:hover,
.shell:not([data-rail="pinned"]) .rail:focus-within {
  width: var(--layout-rail-expanded);
  background: var(--color-surface-overlay);
  border-start-end-radius: var(--radius-card); border-end-end-radius: var(--radius-card);
  box-shadow: var(--shadow-2);
}
.shell[data-rail="pinned"] .rail { width: var(--layout-rail-expanded); }

.rail-home { display: flex; align-items: center; gap: var(--space-3); height: 40px; padding: 0 6px; border-radius: var(--radius-control); text-decoration: none; margin-bottom: var(--space-2); }
.rail-home-tile { border-radius: 7px; flex: none; }
.rail-home-name { font-family: var(--font-title); font-weight: var(--weight-medium); font-size: var(--text-md); }
.rail-list { display: flex; flex-direction: column; gap: 2px; }
.rail-bottom { margin-top: auto; display: flex; flex-direction: column; gap: 2px; }
.rail-item { position: relative; display: flex; align-items: center; gap: var(--space-3); width: 100%; height: 40px; padding: 0 var(--space-2); border-radius: var(--radius-control); color: var(--color-ink-secondary); text-decoration: none; white-space: nowrap;
  transition: background-color var(--duration-fast) var(--easing-standard), color var(--duration-fast) var(--easing-standard); }
.rail-item:hover { background: var(--color-brand-wash); color: var(--color-ink); }
.rail-icon { flex: 0 0 auto; margin: 0 2px; }
.rail-item .avatar { margin: 0 0; }
/* Active place: 3px Campfire Orange marker plus the wash (DESIGN §3.2 — bright orange marks, never fills). */
.rail-item-active { background: var(--nav-active-bg); color: var(--color-ink); }
.rail-item-active::before { content: ""; position: absolute; left: calc(var(--space-2) * -1); top: 8px; bottom: 8px; width: 3px; border-radius: 0 2px 2px 0; background: var(--nav-active-marker); }
.rail-item-active .rail-icon { stroke-width: 2.25; }
.rail-item-active .rail-label { font-weight: var(--weight-medium); }
.rail-label { display: flex; flex-direction: column; opacity: 0; transition: opacity var(--duration-fast) var(--easing-standard); font-size: var(--text-sm); line-height: var(--leading-sm); min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.rail:hover .rail-label, .rail:focus-within .rail-label, .shell[data-rail="pinned"] .rail-label { opacity: 1; }
.rail-label-eyebrow { font-size: var(--text-2xs); line-height: var(--leading-2xs); color: var(--color-ink-tertiary); text-transform: uppercase; letter-spacing: var(--tracking-label); }
.rail-kbd { margin-inline-start: var(--space-2); }
.rail-pin[aria-pressed="true"] { color: var(--color-ink); }
.rail-pin[aria-pressed="true"] .rail-icon { transform: rotate(45deg); }
/* Rail menus follow the overlay rule: radius 10, 4px padding, 32px items, shadow-2 (§9 Overlays). */
.rail-menu { margin: 0 0 0 var(--layout-rail); padding: var(--menu-padding); min-width: 200px; background: var(--color-surface-overlay); border: 0; border-radius: var(--menu-radius); box-shadow: var(--shadow-2); color: var(--color-ink); }
.rail-menu:popover-open { display: flex; flex-direction: column; gap: 2px; animation: overlay-pop var(--duration-standard) var(--easing-standard); }
.rail-menu-item { display: flex; align-items: center; gap: var(--space-2); height: var(--menu-item-height); padding: 0 var(--menu-item-padding-x); border-radius: 6px; text-decoration: none; font-size: var(--text-sm); }
.rail-menu-item:hover, .rail-menu-item:focus-visible { background: var(--color-brand-wash); }
.rail-menu-check { width: 14px; display: inline-flex; }
/* Anchor the menus beside their rail item where the browser supports it; otherwise they open at the top-left of the viewport. */
@supports (anchor-name: --a) {
  .rail-anchor-brand { anchor-name: --rail-brand; }
  .rail-anchor-account { anchor-name: --rail-account; }
  .rail-menu-brand { position-anchor: --rail-brand; }
  .rail-menu-account { position-anchor: --rail-account; }
  .rail-menu-brand, .rail-menu-account { inset: auto; margin: 0 0 0 var(--space-2); left: anchor(right); bottom: anchor(bottom); position-try-fallbacks: flip-block; }
}
.rail-menu-head { display: flex; flex-direction: column; padding: var(--space-2) var(--menu-item-padding-x) var(--space-3); border-bottom: 1px solid var(--color-line-subtle); margin-bottom: var(--space-1); }
.rail-menu-item-button { width: 100%; }

/* ---- The sheet ---- */
.shell-main { display: flex; flex-direction: column; min-width: 0;
  margin: var(--sheet-inset) var(--sheet-inset) var(--sheet-inset) 0;
  background: var(--color-surface-panel);
  border: 1px solid var(--color-line-default); border-radius: var(--radius-card);
  overflow-y: auto; overflow-x: hidden; overscroll-behavior-y: contain; }
.topbar { position: sticky; top: 0; z-index: 10; background: var(--color-surface-panel); border-bottom: 1px solid var(--color-line-subtle); }
.topbar-row { display: flex; align-items: center; gap: var(--space-3); height: var(--layout-topbar); padding: 0 var(--space-5); }
.topbar-title { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.topbar-actions { margin-inline-start: auto; display: flex; align-items: center; gap: var(--space-2); }
.topbar-search .kbd-hint { margin-inline-start: var(--space-1); color: var(--color-ink-tertiary); font-family: var(--font-code); font-size: var(--text-xs); }
/* Under 900 the ⌘K button loses its label and keeps its accessible name. */
@media (max-width: 900px) { .topbar-search .btn-label, .topbar-search .kbd-hint { display: none; } }
/* Endorsement (§9): quiet, right-aligned, tertiary ink, never a link, once per surface.
   The logo is artwork in currentColor — the word "Campfire" is never set as text. */
.topbar-endorsement {
  display: inline-flex; align-items: center; gap: 6px; flex: 0 0 auto;
  margin-inline-start: var(--space-4); padding-inline-start: var(--space-4);
  border-inline-start: 1px solid var(--color-line-subtle);
  color: var(--color-ink-tertiary);
  font-size: var(--text-xs); line-height: var(--leading-xs); white-space: nowrap;
}
.topbar-sub { padding: 0 var(--space-5); }
.shell-content { padding: var(--space-5); min-width: 0; }

/* Global search dialog (§9d — one palette). The result list inside it is styled with the rest of
   the search face, in src/faces/app/search/search.css — the two share one stylesheet bundle. */
.search-dialog { width: min(640px, calc(100vw - var(--space-8))); margin: 12vh auto 0; padding: 0; border: 0; border-radius: var(--radius-card); background: var(--color-surface-overlay); color: var(--color-ink); box-shadow: var(--shadow-2); }
.search-dialog::backdrop { background: var(--overlay-scrim); }
.search-field { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3) var(--space-4); border-bottom: 1px solid var(--color-line-subtle); }
.search-field input { flex: 1 1 auto; min-width: 0; height: 32px; border: 0; background: transparent; font-size: var(--text-md); outline: none; box-shadow: none; }
/* Empty until the island fetches; it never collapses to a scrollbar-less jump. */
.search-results { max-height: min(50dvh, 420px); overflow-y: auto; overscroll-behavior: contain; }
.search-results:empty { display: none; }
.search-hint { padding: var(--space-3) var(--space-4); border-top: 1px solid var(--color-line-subtle); }
.search-results:empty + .search-hint { border-top: 0; }

/* ---- The foot of the sheet (0014 pattern 7) ----
   Only a phone shows this: the endorsement leaves the top bar and sits here, once. */
.shell-foot { display: none; }
.shell-foot-endorsement {
  display: inline-flex; align-items: center; gap: 6px;
  color: var(--color-ink-tertiary); font-size: var(--text-xs); line-height: var(--leading-xs); white-space: nowrap;
}

/* ---- Narrow (721–1024, decision 0014): the rail is icon-only and never pinned; the sheet keeps
   its inset; the title keeps a few characters before the actions can squeeze it. ---- */
@media (max-width: 1024px) {
  .shell[data-rail="pinned"] { grid-template-columns: var(--layout-rail) minmax(0, 1fr); }
  .shell[data-rail="pinned"] .rail { width: var(--layout-rail); }
  .shell[data-rail="pinned"] .rail:hover, .shell[data-rail="pinned"] .rail:focus-within {
    width: var(--layout-rail-expanded);
    background: var(--color-surface-overlay);
    border-start-end-radius: var(--radius-card); border-end-end-radius: var(--radius-card);
    box-shadow: var(--shadow-2);
  }
  .shell[data-rail="pinned"] .rail-label { opacity: 0; }
  .shell[data-rail="pinned"] .rail:hover .rail-label, .shell[data-rail="pinned"] .rail:focus-within .rail-label { opacity: 1; }
  .rail-pin { display: none; }
  .topbar-title { flex: 1 1 auto; min-width: 8ch; }
}

/* ---- Phone (≤ 720, decision 0014) ----
   The rail becomes a 56px bottom bar fixed with `inset-inline: 0` (pattern 1 — never a width), the
   sheet goes full-bleed and the document scrolls. The bar carries every place the rail did — the
   six sections, Admin for admins, the brand switch, Settings and the account menu — as icons;
   only the pin goes, because there is nothing to pin. Menus open as a sheet above the bar. */
@media (max-width: 720px) {
  .shell { --shell-bottom-bar: calc(var(--layout-rail-bar) + env(safe-area-inset-bottom, 0px));
    grid-template-columns: minmax(0, 1fr); height: auto; min-height: 100dvh; overflow: visible; }
  .rail { position: fixed; inset-inline: 0; inset-block-end: 0; inset-block-start: auto; z-index: 30;
    width: auto; height: var(--shell-bottom-bar);
    flex-direction: row; align-items: center; gap: 0;
    padding: var(--space-2) var(--space-2) calc(var(--space-2) + env(safe-area-inset-bottom, 0px));
    background: var(--color-surface-panel); border-top: 1px solid var(--color-line-default);
    overflow: visible; transition: none; }
  .shell:not([data-rail="pinned"]) .rail:hover, .shell:not([data-rail="pinned"]) .rail:focus-within,
  .shell[data-rail="pinned"] .rail, .shell[data-rail="pinned"] .rail:hover, .shell[data-rail="pinned"] .rail:focus-within {
    width: auto; box-shadow: none; border-radius: 0; background: var(--color-surface-panel); }
  .rail-home, .rail-label, .rail-pin { display: none; }
  .rail-list { flex: 1 1 auto; flex-direction: row; gap: 0; min-width: 0; }
  .rail-list > li { flex: 1 1 0; min-width: 0; display: flex; }
  .rail-bottom { flex: 0 1 auto; flex-direction: row; gap: 0; margin: 0; }
  .rail-item { flex: 1 1 0; width: auto; min-width: 32px; justify-content: center; padding: 0; gap: 0; }
  .rail-icon { margin: 0; }
  .rail-item-active::before { left: 6px; right: 6px; top: -8px; bottom: auto; width: auto; height: 3px; border-radius: 0 0 2px 2px; }
  /* Menus: a sheet above the bar, inset 8, never anchored off the edge (pattern 6). */
  .rail-menu, .rail-menu-brand, .rail-menu-account {
    position: fixed; inset: auto var(--space-2) calc(var(--shell-bottom-bar) + var(--space-2)) var(--space-2);
    margin: 0; min-width: 0; max-height: 60dvh; overflow-y: auto; overscroll-behavior: contain;
    position-try-fallbacks: none; }
  .shell-main { margin: 0; border: 0; border-radius: 0; overflow: visible; min-height: 100dvh; }
  /* The title row may take two lines: the title keeps its first characters; the actions follow. */
  .topbar-row { flex-wrap: wrap; height: auto; min-height: var(--layout-topbar); padding: var(--space-2) var(--space-4); row-gap: var(--space-2); }
  .topbar-title { flex: 1 1 auto; min-width: min(100%, 12ch); }
  .topbar-endorsement { display: none; }
  .topbar-sub { padding-inline: var(--space-4); }
  .shell-content { padding: var(--space-4); }
  .shell-foot { display: flex; justify-content: center; margin-top: auto;
    padding: var(--space-4) var(--space-4) calc(var(--space-4) + var(--shell-bottom-bar));
    border-top: 1px solid var(--color-line-subtle); }
  /* The command palette is a full-screen sheet on a phone (pattern 6). */
  .search-dialog:modal { inset: 0; margin: 0; width: 100%; max-width: none; height: 100dvh; max-height: none; border-radius: 0; }
  .search-results { max-height: calc(100dvh - 160px); }
}
@media (forced-colors: active) {
  .shell-main { border-color: CanvasText; }
  .rail-item-active { outline: 2px solid Highlight; outline-offset: -2px; }
  .rail-item-active::before { background: Highlight; }
  .rail-menu, .search-dialog { border: 1px solid CanvasText; }
}
@media print {
  .rail, .topbar-actions { display: none; }
  .shell { grid-template-columns: 1fr; height: auto; overflow: visible; }
  .shell-main { margin: 0; border: 0; overflow: visible; }
}


/* ---- ui/layout/error-page.css ---- */
/* Error pages — the 404 sheet. Tokens only. */
.error-page { display: flex; flex-direction: column; justify-content: center; min-height: 50dvh; }
.error-page-bare { min-height: 100dvh; padding: var(--space-8) var(--space-5); background: var(--color-surface-panel); }


/* ---- faces/app/admin/admin.css ---- */
/* Admin dashboard — DESIGN.md §9.2 (tables), §9.5 (forms). Tokens only, no new colours. */
.adm-page { padding-block-end: var(--space-12); }
.adm-intro { max-width: var(--measure-prose); }
.adm-note { max-width: var(--measure-prose); }
.adm-section { scroll-margin-block-start: var(--space-8); }

/* Overview: one tile per thing that could need an admin today. */
.adm-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--space-4); align-items: start; }
.adm-tile .card-body { display: flex; flex-direction: column; gap: var(--space-2); align-items: start; }
.adm-tile .metric-note { max-width: 34ch; }

/* The tables are DataTables (src/ui/components/data-table.css): 34 header, 40/32 rows, one
   line per cell. Admin's diagnostic cells carry sentences — blockers, reasons, errors — so
   the one cell that wraps is allowed to, top-aligned, and only that row grows past the floor. */
.adm-td-wrap { display: block; white-space: normal; max-width: 44ch; padding-block: var(--space-1); }
.adm-table .dt-td:has(> .adm-td-wrap) { vertical-align: top; }
/* The ledger's totals: one line under the table, in column order, since DataTable has no
   footer-row slot and its footer counts rows. */
.adm-totals { display: flex; flex-wrap: wrap; gap: var(--space-4) var(--space-8); margin: 0; padding: 0 var(--space-1); }
.adm-totals-item { display: flex; align-items: baseline; gap: var(--space-2); }
.adm-totals-item dd { margin: 0; font-weight: var(--weight-medium); }

/* A row's blockers read as a list, one refusal per line. */
.adm-blockers { margin: 0; padding-inline-start: var(--space-4); display: flex; flex-direction: column; gap: var(--space-1); }

/* Release: the checkbox column is 40px, so its label is for screen readers only. */
.adm-check .checkbox-text { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }
.adm-bulk { gap: var(--space-3); }
.adm-bulk p { max-width: var(--measure-prose); }

/* Forms whose only job is to carry a hidden field; their submit lives in the table via `form`. */
.adm-forms { display: none; }

.adm-role-form { gap: var(--space-2); }
.adm-role-form .select { min-width: 14ch; }
.adm-hint { margin-block-start: var(--space-1); max-width: 32ch; white-space: normal; }

.adm-invite { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--space-4); align-items: end; }
.adm-invite-action { display: flex; align-items: end; }

.adm-details { border: 1px solid var(--color-line-default); border-radius: var(--radius-card); padding: var(--space-4); background: var(--color-surface-panel); }
.adm-details > summary { cursor: pointer; }
.adm-details > summary:focus-visible { outline: 2px solid var(--color-focus); outline-offset: var(--space-1); border-radius: var(--radius-control); }
.adm-details[open] > summary { margin-block-end: var(--space-4); }

@media (max-width: 900px) {
  .adm-invite { grid-template-columns: 1fr; }
  .adm-invite-action { justify-content: start; }
}

/* Phone (decision 0014): the worksheets keep their tables (they scroll in their own region); the
   forms go one column with a full-width primary; the ledger totals read one pair per line. */
@media (max-width: 720px) {
  .adm-tiles { grid-template-columns: minmax(0, 1fr); }
  .adm-td-wrap { max-width: 60vw; }
  .adm-totals { flex-direction: column; gap: var(--space-2); }
  .adm-totals-item { justify-content: space-between; }
  .adm-bulk { flex-direction: column; align-items: stretch; }
  .adm-bulk .btn { width: 100%; min-height: var(--button-height-coarse); }
  .adm-invite-action .btn { width: 100%; min-height: var(--button-height-coarse); }
  .adm-role-form { flex-wrap: wrap; }
  .adm-hint { max-width: none; }
  .adm-details { padding: var(--space-3); }
  .adm-page form > .row:has(> .btn-primary) { flex-direction: column; align-items: stretch; }
  .adm-page form > .row > .btn-primary { width: 100%; min-height: var(--button-height-coarse); }
}


/* ---- faces/app/brands/roster.css ---- */
/* Brand rosters (/app/brands, D6) — the index with the lookup box, and one brand's twelve months
   grouped by collaboration type. A roster row is a row, not a card grid: the same four facts in
   the same place all the way down. Every value is a token. */

.ros { display: flex; flex-direction: column; gap: var(--space-5); padding: var(--space-4) var(--space-5) var(--space-6); max-inline-size: 76rem; min-width: 0; }
.ros-index { max-inline-size: 56rem; }
.ros-lede { margin: 0; max-inline-size: 70ch; }
.ros-crumb { margin: 0; }
.ros-crumb a { color: inherit; }
.ros-card { max-inline-size: 44rem; }
.ros-aside { margin: 0; }

/* ---------- The lookup ---------- */
.ros-lookup { display: flex; align-items: flex-end; gap: var(--space-3); }
.ros-lookup > :first-child { flex: 1 1 auto; min-width: 0; }
.ros-none { margin: var(--space-3) 0 0; }
.ros-cands { list-style: none; margin: var(--space-3) 0 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); }
.ros-cand {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-line-subtle); border-radius: 10px; background: var(--color-surface-well);
}
.ros-cand-t { min-width: 0; display: flex; flex-direction: column; gap: 2px; }

/* ---------- The index rows ---------- */
.ros-rows { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); }
.ros-row-link {
  display: block; padding: var(--space-3); text-decoration: none; color: inherit;
  border: 1px solid var(--color-line-subtle); border-radius: 10px; background: var(--color-surface-panel);
  transition: border-color var(--duration-fast) var(--easing-standard);
}
.ros-row-link:hover { border-color: var(--color-line-default); background: var(--color-surface-well); }
.ros-row-link:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }
.ros-row-t { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.ros-row-name { font-size: var(--text-base); line-height: var(--leading-base); font-weight: var(--weight-strong); }

/* ---------- The roster head ---------- */
.ros-head { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: var(--space-3); }
.ros-head-t { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.ros-head-t p { margin: 0; }
.ros-head-counts { font-size: var(--text-md); line-height: var(--leading-md); }
.ros-head-acts { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }

.ros-addall {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin: 0;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-line-subtle); border-radius: 10px; background: var(--color-surface-well);
}
.ros-addall .select-wrap, .ros-addall .input-wrap { inline-size: auto; min-inline-size: 12rem; }

/* ---------- One group ---------- */
.ros-group { display: flex; flex-direction: column; gap: var(--space-2); }
.ros-group-h { display: flex; align-items: center; gap: var(--space-2); margin: 0; color: var(--color-ink-tertiary); }
.ros-group-n { font-weight: var(--weight-regular); letter-spacing: 0; text-transform: none; }

/* ---------- One row ---------- */
.ros-row {
  display: grid; gap: var(--space-3); align-items: center;
  grid-template-columns: 40px minmax(10rem, 1.4fr) auto auto minmax(0, auto);
  padding: var(--space-3);
  border: 1px solid var(--color-line-subtle); border-radius: 10px; background: var(--color-surface-panel);
}
.ros-row-who { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.ros-row-who a { color: inherit; }
.ros-row-name { font-size: var(--text-base); line-height: var(--leading-base); font-weight: var(--weight-strong); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ros-row-handle { display: flex; align-items: center; gap: var(--space-1); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ros-row-stats { display: flex; align-items: center; gap: var(--space-4); }
.ros-stat { display: flex; flex-direction: column; align-items: flex-end; gap: 1px; }
.ros-stat-v { font-size: var(--text-base); line-height: var(--leading-base); font-weight: var(--weight-medium); }
.ros-stat-l { text-transform: lowercase; }
.ros-frames { list-style: none; margin: 0; padding: 0; display: flex; gap: var(--space-1); }
.ros-frame { inline-size: 40px; block-size: 40px; border-radius: 6px; overflow: hidden; background: var(--color-surface-well); }
.ros-frame img { inline-size: 100%; block-size: 100%; object-fit: cover; display: block; }
.ros-row-flags { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: var(--space-2); }

@media (max-width: 900px) {
  .ros-row { grid-template-columns: 40px minmax(0, 1fr); }
  .ros-row-stats, .ros-frames, .ros-row-flags { grid-column: 2 / -1; justify-content: flex-start; }
  .ros-row-stats { gap: var(--space-3); }
  .ros-stat { align-items: flex-start; }
}

@media (max-width: 640px) {
  .ros { padding: var(--space-3) var(--space-4) var(--space-5); gap: var(--space-4); }
  .ros-lookup { flex-direction: column; align-items: stretch; }
  .ros-cand { flex-wrap: wrap; }
}


/* ---- faces/app/campaigns/campaigns.css ---- */
/* Campaign workspace (M4): settings sections, messages, payments and activity.
   DESIGN.md §8 (layout), §9.2 (tables), §9.5 (forms). Tokens only. */

.cs-settings { padding-block-end: var(--space-12); }
.cs-intro { max-width: var(--measure-prose); }

/* Two and three fields on a row once there is room; one column on a narrow viewport (§11 reflow). */
.cs-fields-2,
.cs-fields-3 { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--space-4); }
@media (min-width: 720px) {
  .cs-fields-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .cs-fields-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

.cs-checks { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: var(--space-2); }

.cs-toggle { display: block; padding-block: var(--space-2); }
.cs-toggle + .cs-toggle { border-block-start: 1px solid var(--color-line-subtle); }

/* The requirements table: the row inputs belong to forms that cannot live inside a <tr>. */
.cs-table { margin-block: var(--space-2); }
.cs-table .dt-td { vertical-align: top; }
.cs-forms { display: contents; }

.cs-overrides { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); }
.cs-override {
  display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap;
  padding-block: var(--space-2);
  border-block-end: 1px solid var(--color-line-subtle);
}
.cs-override:last-child { border-block-end: 0; }

/* A drawer the server rendered open — a deep link to ?create=1 or ?filter=, or the round trip
   behind "Use this brand's terms" — with no island to promote it to a modal. Pin it like the
   modal so it reads as a panel over the table rather than a card beneath it. Once something
   calls showModal() the :modal rules take over and this stops applying. */
.cs-panel[open]:not(:modal) {
  /* a drawer is a second sheet (DESIGN 1.4 §9e): inset on every side, card radius */
  position: fixed; inset: var(--sheet-inset) var(--sheet-inset) var(--sheet-inset) auto; z-index: 20;
  height: auto; max-height: none;
  border: 0; border-radius: var(--radius-card);
  box-shadow: var(--shadow-2);
}
@media (max-width: 720px) {
  .cs-panel[open]:not(:modal) { inset: 0; width: 100%; max-width: none; border-radius: 0; }
}

/* Messages */
.cs-messages { padding-block-end: var(--space-12); }
.cs-recipients { gap: var(--space-4); align-items: end; flex-wrap: wrap; }
.cs-recipients .field { min-width: 16rem; }

.cs-threads { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-4); }
.cs-thread { min-width: 0; }
.cs-thread-head { gap: var(--space-2); padding-block-end: var(--space-3); }

.cs-message-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); }
.cs-message {
  display: flex; align-items: baseline; gap: var(--space-3); flex-wrap: wrap;
  padding-block: var(--space-2);
  border-block-start: 1px solid var(--color-line-subtle);
}
.cs-message-meta { display: flex; align-items: center; gap: var(--space-2); flex: 0 0 auto; }
.cs-message-subject { color: var(--color-ink); min-width: 0; overflow-wrap: anywhere; }

/* Portal events (M6): what a creator did in the portal, newest first. */
.cs-portal-events { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.cs-portal-event {
  display: flex; align-items: baseline; gap: var(--space-3); flex-wrap: wrap;
  padding-block: var(--space-2);
  border-block-start: 1px solid var(--color-line-subtle);
}
.cs-portal-event:first-child { border-block-start: 0; }
.cs-portal-who { color: var(--color-ink); flex: 0 0 auto; }
.cs-portal-what { min-width: 0; flex: 1 1 24ch; overflow-wrap: anywhere; }
.cs-portal-when { flex: 0 0 auto; margin-inline-start: auto; }

/* Activity */
.cs-load-more { justify-content: center; padding-block-start: var(--space-4); }

/* Phone (decision 0014, pattern 5): one column, every field full width, the primary full width at
   the foot of its form. The campaign facts row and every side-by-side strip stack. */
@media (max-width: 720px) {
  .cp-facts { row-gap: var(--space-2); }
  .cs-recipients { align-items: stretch; }
  .cs-recipients .field { min-width: 0; flex: 1 1 100%; }
  .cs-recipients .btn { width: 100%; min-height: var(--button-height-coarse); }
  .cs-checks { grid-template-columns: minmax(0, 1fr); }
  .cs-settings form > .row:has(> .btn-primary),
  .cs-messages form > .row:has(> .btn-primary) { flex-direction: column; align-items: stretch; }
  .cs-settings form > .row > .btn-primary,
  .cs-messages form > .row > .btn-primary { width: 100%; min-height: var(--button-height-coarse); }
  .cs-message-meta { flex-wrap: wrap; }
  .cs-portal-when { margin-inline-start: 0; flex-basis: 100%; }
}


/* ---- faces/app/campaigns/chrome.css ---- */
/* Campaign page chrome (M4) */
.cp-facts { margin-bottom: var(--space-4); }


/* ---- faces/app/campaigns/contracts/contracts.css ---- */
/* The Agreement block in the pipeline's expanded creator panel (M7). Tokens only (invariant 1). */

.ct-block { min-width: 0; }
.ct-actions { gap: var(--space-2); }

/* The one action that contradicts Docusign sits behind a disclosure, quiet until it is opened. */
.ct-manual > summary {
  cursor: pointer;
  color: var(--color-ink-tertiary);
  width: fit-content;
  border-radius: var(--radius-control);
  padding: var(--space-1) 0;
}
.ct-manual > summary:hover { color: var(--color-ink-secondary); }
.ct-manual > summary:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }
.ct-manual-form {
  margin-top: var(--space-2);
  padding: var(--space-3);
  border: 1px solid var(--color-line-subtle);
  border-radius: var(--radius-control);
  background: var(--color-surface-well);
  max-width: var(--measure-drawer);
}

/* The paperwork strip: Agreement and Ad permission side by side under the requirements. */
.pl-paperwork {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-6);
  padding-top: var(--space-3);
  border-top: 1px solid var(--color-line-subtle);
}
.pl-paperwork > * { flex: 1 1 320px; min-width: 0; }


/* ---- faces/app/campaigns/creators/pipeline.css ---- */
/* Campaign Creators tab (M4). The table itself is styled by src/ui/components/data-table.css;
   this file adds the count strip, the board, the deliverables panel and the recommended list.
   Tokens only (invariant 1). */

.pipeline { display: flex; flex-direction: column; gap: var(--space-4); min-width: 0; }

/* ---- status counts: the filter, and the shape of the roster at a glance ---- */
.pl-counts { padding: 0 var(--space-1); }
.pl-count { border-radius: var(--radius-pill); text-decoration: none; display: inline-flex; }
.pl-count:hover .pill { box-shadow: var(--shadow-1); }
.pl-count-active .pill { outline: 2px solid var(--color-brand); outline-offset: 1px; }
.pl-req-count { margin-inline-start: auto; }

/* ---- table cells ---- */
.pl-creator { display: inline-flex; align-items: center; gap: var(--space-1); min-width: 0; }
.pl-chevron { flex: none; }
.pl-chevron svg { transition: transform var(--duration-fast) var(--easing-standard); }
.pl-chevron[aria-expanded='true'] svg { transform: rotate(90deg); }
@media (prefers-reduced-motion: reduce) {
  .pl-chevron svg { transition: none; }
}
.pl-uploaded { flex-wrap: wrap; }
.pl-uploaded-item { gap: var(--space-1); }
.pl-view-toggle { display: inline-flex; align-items: center; gap: var(--space-1); }

/* ---- board ---- */
.pl-board {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(240px, 1fr);
  gap: var(--space-3);
  overflow-x: auto;
  padding-bottom: var(--space-2);
}
.pl-col {
  display: flex; flex-direction: column; gap: var(--space-2); min-width: 0;
  background: var(--color-surface-well);
  border: 1px solid var(--color-line-subtle);
  border-radius: var(--radius-card);
  padding: var(--space-3);
}
.pl-col-head { display: flex; align-items: center; gap: var(--space-2); }
.pl-col-head .tnum { margin-inline-start: auto; }
.pl-col-list {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: var(--space-2);
  min-height: var(--space-16);
  border-radius: var(--radius-control);
  transition: background-color var(--duration-fast) var(--easing-standard);
}
.pl-col-list[data-drop-active='true'] {
  background: var(--color-brand-wash);
  outline: 2px dashed var(--color-brand);
  outline-offset: 2px;
}
.pl-col-empty { padding: var(--space-3) var(--space-2); }

.pl-card {
  background: var(--color-surface-panel);
  border: 1px solid var(--color-line-default);
  border-radius: var(--radius-control);
  padding: var(--space-3);
  display: flex; flex-direction: column; gap: var(--space-2);
  min-width: 0;
}
.pl-card[data-dragging='true'] { opacity: 0.5; }
.pl-card-top { display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
.pl-card-name { display: flex; flex-direction: column; min-width: 0; flex: 1 1 auto; }
.pl-card-name a { font-weight: var(--weight-medium); overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.pl-card-pills { row-gap: var(--space-1); }

/* ---- deliverables panel ---- */
.pl-panel {
  background: var(--color-surface-panel);
  border: 1px solid var(--color-line-default);
  border-radius: var(--radius-card);
  padding: var(--space-4);
  display: flex; flex-direction: column; gap: var(--space-4);
}
.pl-panel:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }
.pl-panel-head { display: flex; align-items: center; gap: var(--space-4); flex-wrap: wrap; }
.pl-panel-title { margin: 0; }

/* Inside a table the panel is one full-width row, so it keeps the table's own padding. */
.pl-expand-cell { padding: var(--space-2) var(--table-cell-padding-x) var(--space-4); }
.pl-expand-cell .pl-panel { margin: 0; }

.pl-reqs { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-3); }
.pl-req {
  border: 1px solid var(--color-line-subtle);
  border-radius: var(--radius-control);
  padding: var(--space-3);
  display: flex; flex-direction: column; gap: var(--space-3);
}
.pl-req-head { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
.pl-req-title { font-weight: var(--weight-medium); }
.pl-req-body { display: flex; flex-direction: column; gap: var(--space-3); }
.pl-req-post { margin: 0; }
.pl-link { display: grid; grid-template-columns: minmax(200px, 2fr) minmax(200px, 2fr) auto; gap: var(--space-3); align-items: end; }
.pl-review { display: flex; flex-direction: column; gap: var(--space-2); min-width: 260px; }

.pl-bonus { display: flex; flex-direction: column; gap: var(--space-2); }
.pl-bonus-list { list-style: none; margin: 0; padding: 0; row-gap: var(--space-2); }
.pl-bonus-item { flex-wrap: wrap; }

/* ---- recommended creators ---- */
.pl-rec-list { list-style: none; margin: var(--space-3) 0 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); }
/* Avatar · name and one wrapped meta line · the action. The text column takes whatever is left,
   so the meta line wraps as prose instead of one word per line. */
.pl-rec {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: var(--space-3); min-width: 0;
  padding: var(--space-2) 0;
  border-top: 1px solid var(--color-line-subtle);
}
.pl-rec:first-child { border-top: 0; }
.pl-rec-text { display: flex; flex-direction: column; min-width: 0; }
.pl-rec-meta { overflow-wrap: anywhere; }
.pl-rec-followers { white-space: nowrap; }
.pl-rec-action { min-width: 0; }

/* ---- add creators ---- */
.pl-add-dialog { max-width: var(--layout-portal-column); }
.pl-add-modes { display: flex; gap: var(--space-1); margin-bottom: var(--space-3); }
.pl-add-search { display: flex; align-items: end; gap: var(--space-2); margin-bottom: var(--space-3); }
.pl-add-search .field { flex: 1 1 auto; }
.pl-add-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); max-height: 320px; overflow-y: auto; }
.pl-add-row { padding: var(--space-1); }

@media (width < 900px) {
  .pl-link { grid-template-columns: 1fr; }
  .pl-board { grid-auto-flow: row; grid-auto-columns: auto; }
}

/* Phone (decision 0014): the counts strip is one scrolling row, the recommended action goes full
   width under the name, and nothing inside the panel keeps a fixed minimum. */
@media (width <= 720px) {
  .pl-counts { flex-wrap: nowrap; overflow-x: auto; padding-block: var(--space-1); scrollbar-width: none; }
  .pl-counts .pl-count { flex: none; }
  .pl-req-count { flex: none; margin-inline-start: var(--space-2); white-space: nowrap; }
  .pl-rec { grid-template-columns: auto minmax(0, 1fr); }
  .pl-rec-action { grid-column: 1 / -1; }
  .pl-rec-action .btn { width: 100%; min-height: var(--button-height-coarse); }
  .pl-review { min-width: 0; }
  .pl-panel { padding: var(--space-3); }
  .pl-add-search { flex-wrap: wrap; }
  .pl-add-search .btn { width: 100%; }
}


/* ---- faces/app/campaigns/payments/payments.css ---- */
/* Campaign Payments tab (M7). Tokens only — see CLAUDE.md invariant 1. */

.cpay { display: flex; flex-direction: column; }

.cpay-h2 { font-size: var(--text-lg); font-weight: var(--weight-medium); margin: 0; }

/* ---- Review queue (invariant 7): the rows a person should look at first ---- */
.cpay-review {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  background: var(--color-warn-tint);
  border: 1px solid var(--color-warn);
  border-radius: var(--radius-card);
}

.cpay-review-title {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
  color: var(--color-warn);
}

.cpay-review-list { display: flex; flex-direction: column; gap: var(--space-1); margin: 0; padding: 0; list-style: none; }

.cpay-review-item { display: flex; flex-wrap: wrap; gap: var(--space-2); }

.cpay-review-who { font-weight: var(--weight-medium); }

.cpay-review-help { margin: 0; }

/* ---- Table cells ---- */
.cpay-mask { color: var(--color-ink-secondary); white-space: nowrap; }

.cpay-actions { align-items: flex-start; gap: var(--space-1); }

/* What a member sees where an admin gets the Release button. */
.cpay-awaiting { color: var(--color-ink-secondary); }

/* The gate's own sentence, on the row rather than in a tooltip: a disabled control has to say
   why in words somebody can read without a mouse. */
.cpay-why { display: block; max-width: 22rem; text-wrap: pretty; }

/* ---- Cost sheet ---- */
.cpay-tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
  gap: var(--space-3);
}

/* ---- Ledger ---- */
.cpay-ledger-head { align-items: baseline; }

.cpay-balance { font-size: var(--text-lg); font-variant-numeric: tabular-nums; }

.cpay-ledger-note { margin: 0; }

.cpay-kind { color: var(--color-ink-secondary); }

.cpay-amount { white-space: nowrap; }
.cpay-amount-credit { color: var(--color-ok); }
.cpay-amount-debit { color: var(--color-ink); }

/* ---- Dialogs ---- */
.cpay-blocked {
  margin: 0;
  padding: var(--space-2) var(--space-3) var(--space-2) var(--space-5);
  color: var(--color-bad);
  background: var(--color-bad-tint);
  border-radius: var(--radius-control);
}

.cpay-blocked li + li { margin-top: var(--space-1); }

/* The source chips on this tab sit in header cells beside sort links and under tile values: the
   disclosure keeps a 24px hit area (0014 pattern 8) while the chip itself stays 20 tall. */
.cpay .src-wrap > summary { min-block-size: var(--space-6); }

@media (width <= 720px) {
  .cpay-why { max-width: none; }
  .cpay-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .cpay-ledger-head { flex-wrap: wrap; row-gap: var(--space-2); }
  .cpay-review { padding: var(--space-3); }
  .cpay dialog form > .row:has(> .btn-primary) { flex-direction: column-reverse; align-items: stretch; }
  .cpay dialog form > .row > .btn { width: 100%; min-height: var(--button-height-coarse); }
}


/* ---- faces/app/campaigns/posts/posts.css ---- */
/* Campaign Posts tab (M4 step 6). Tokens only — see CLAUDE.md invariant 1. */

.cpp { display: flex; flex-direction: column; gap: var(--space-5); }

/* ---- KPI strip ---- */
.cpp-kpis {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: var(--space-3);
}

/* ---- View switch, filters, controls ---- */
.cpp-views { gap: var(--space-2); }
.cpp-filters { gap: var(--space-2); }
.cpp-creator-filter { gap: var(--space-2); }
.cpp-clear { color: var(--color-ink-secondary); }
.cpp-controls { gap: var(--space-3); }

/* ---- Published: grid ---- */
.cpp-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
  gap: var(--space-4);
  margin: 0;
  padding: 0;
  list-style: none;
}

.cpp-card {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--color-surface-panel);
  border: 1px solid var(--color-line-default);
  border-radius: var(--radius-card);
}

.cpp-card-media {
  position: relative;
  aspect-ratio: 4 / 5;
  background: var(--color-surface-well);
}

.cpp-card-media img { display: block; width: 100%; height: 100%; object-fit: cover; }

.cpp-card-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  color: var(--color-ink-tertiary);
}

.cpp-card-body { padding: var(--space-3); }
.cpp-card-meta { gap: var(--space-1); }
.cpp-card-chips { gap: var(--space-1); }

.cpp-figures {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-2);
  margin: 0;
  padding-top: var(--space-2);
  border-top: 1px solid var(--color-line-subtle);
}

.cpp-figure dt { margin: 0; }
.cpp-figure dd { margin: 0; font-size: var(--text-sm); line-height: var(--leading-sm); }

.cpp-cell-creator { display: flex; flex-direction: column; min-width: 0; }

/* ---- Calendar ---- */
.cpp-calendar { display: flex; flex-direction: column; gap: var(--space-3); }
.cpp-calendar-head { gap: var(--space-3); }

.cpp-calendar-grid {
  width: 100%;
  border-collapse: collapse;
  table-layout: fixed;
}

.cpp-calendar-weekday {
  padding: var(--space-2);
  text-align: start;
  background: var(--table-header-bg);
  border: 1px solid var(--color-line-subtle);
}

.cpp-calendar-day {
  height: var(--space-16);
  padding: var(--space-1);
  vertical-align: top;
  background: var(--color-surface-panel);
  border: 1px solid var(--color-line-subtle);
}

.cpp-calendar-day-out { background: var(--color-surface-well); }
.cpp-calendar-date { display: block; margin-bottom: var(--space-1); color: var(--color-ink-tertiary); }

.cpp-calendar-item {
  display: flex;
  gap: var(--space-1);
  align-items: center;
  margin-bottom: var(--space-1);
  padding: var(--space-1);
  overflow: hidden;
  font-size: var(--text-2xs);
  line-height: var(--leading-2xs);
  color: var(--color-ink);
  text-decoration: none;
  border-radius: var(--radius-control);
}

.cpp-calendar-item-published { background: var(--color-brand-tint); }
.cpp-calendar-item-planned { border: 1px dashed var(--color-line-interactive); }
.cpp-calendar-item:hover { text-decoration: underline; }

/* ---- Dialogs ---- */
.cpp-metric-fields {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(7rem, 1fr));
  gap: var(--space-3);
}

.cpp-paid-fields {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(7rem, 1fr));
  gap: var(--space-3);
}

/* ---- Bulk import ---- */
.cpp-import-file { padding: var(--space-2); height: auto; }
.cpp-table-scroll { overflow-x: auto; }

.cpp-import-table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
.cpp-import-table th,
.cpp-import-table td {
  padding: var(--table-cell-padding-y) var(--table-cell-padding-x);
  text-align: start;
  border-bottom: 1px solid var(--table-rule);
}

.cpp-import-table th {
  font-size: var(--text-2xs);
  line-height: var(--leading-2xs);
  font-weight: var(--weight-medium);
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  color: var(--table-header-fg);
  background: var(--table-header-bg);
}

.cpp-import-table td { max-width: 20rem; }

@media (width <= 720px) {
  .cpp-calendar-grid { font-size: var(--text-2xs); }
  .cpp-calendar-day { height: var(--space-12); }
  .cpp-calendar-head { flex-wrap: wrap; }

  /* Controls collapse rather than stack four deep (0014 pattern 3): the view strip scrolls
     sideways with Import at its end; the creator filter takes the row with its select growing;
     layout and sort share one row. */
  .cpp-views { flex-wrap: nowrap; overflow-x: auto; padding-block: var(--space-1); scrollbar-width: none; }
  .cpp-views > * { flex: none; }
  .cpp-views .right { margin-inline-start: var(--space-2); }
  .cpp-creator-filter { flex: 1 1 100%; }
  .cpp-creator-filter .select { flex: 1 1 auto; min-width: 0; }
  .cpp-controls { row-gap: var(--space-2); }
  .cpp-controls .t-label { display: none; }
  .cpp-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .cpp-figures { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .cpp-metric-fields, .cpp-paid-fields { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .cpp-import-table td { max-width: 14rem; }
}

/* ---- Review queue (M6): one row per post waiting on a person ---- */
.cpp-review-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.cpp-review-item {
  display: flex;
  gap: var(--space-3);
  padding: var(--space-3);
  background: var(--color-surface-panel);
  border: 1px solid var(--color-line-default);
  border-radius: var(--radius-card);
}

.cpp-review-media {
  flex: 0 0 auto;
  width: var(--space-16);
  aspect-ratio: 4 / 5;
  overflow: hidden;
  background: var(--color-surface-well);
  border-radius: var(--radius-control);
}

.cpp-review-media img { display: block; width: 100%; height: 100%; object-fit: cover; }

.cpp-review-body { min-width: 0; flex: 1 1 auto; }
.cpp-review-evidence { gap: var(--space-1); }
.cpp-review-actions { gap: var(--space-2); }

@media (width <= 720px) {
  .cpp-review-item { flex-direction: column; }
  .cpp-review-media { width: 100%; aspect-ratio: 16 / 9; }
}


/* ---- faces/app/campaigns/report-editor.css ---- */
/* Report editor — DESIGN.md §8 (layout), §9.2 (tables), §9.5 (forms), §9.9 (client report). Tokens only. */

.rep-index { display: flex; flex-direction: column; gap: var(--space-4); padding-block-end: var(--space-12); }
.rep-campaign-name { color: var(--color-ink); font-weight: 500; }
.rep-campaign-name:hover { color: var(--color-brand-strong); }

.rep-editor { padding-block-end: var(--space-12); }
.rep-intro { max-width: var(--measure-prose); }
.rep-hint { max-width: 40ch; }

/* One column until there is room for the draft and its preview side by side. */
.rep-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--space-6); align-items: start; }
@media (min-width: 1100px) {
  .rep-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 26rem); }
  .rep-side { position: sticky; top: var(--space-4); }
}

.rep-blocks { min-width: 0; }
.rep-side { min-width: 0; display: flex; flex-direction: column; gap: var(--space-4); }

.rep-block-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-4); }
.rep-block-item { min-width: 0; }
.rep-block { min-width: 0; }
.rep-block-actions { gap: var(--space-1); }
.rep-block-form { margin-block-start: var(--space-4); }
.rep-toggle { display: block; padding-block-end: var(--space-3); border-block-end: 1px solid var(--color-line-subtle); }
.rep-inline { display: contents; }
.rep-hidden-form { display: none; }

.rep-add { gap: var(--space-3); align-items: end; flex-wrap: wrap; }
.rep-add-field { min-width: 16rem; }

/* Hero picker: the approved sources, shown as pictures so the choice is the picture. */
.rep-hero-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); gap: var(--space-3); }
.rep-hero-option { display: flex; flex-direction: column; gap: var(--space-1); cursor: pointer; min-width: 0; }
.rep-hero-input { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.rep-hero-frame {
  display: flex; align-items: center; justify-content: center;
  aspect-ratio: 1 / 1; overflow: hidden;
  border: 1px solid var(--color-line-interactive); border-radius: var(--radius-control);
  background: var(--color-surface-well); color: var(--color-ink-tertiary);
  font-size: var(--text-2xs);
}
.rep-hero-frame img { width: 100%; height: 100%; object-fit: cover; }
.rep-hero-input:checked + .rep-hero-frame {
  border-color: var(--color-brand); box-shadow: 0 0 0 2px var(--color-brand);
}
.rep-hero-input:focus-visible + .rep-hero-frame { outline: 2px solid var(--color-focus); outline-offset: 2px; }
.rep-hero-name { font-size: var(--text-2xs); color: var(--color-ink-secondary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Selection carries a word as well as the ring (§11). */
.rep-hero-input:checked ~ .rep-hero-name::after { content: " · chosen"; color: var(--color-brand-strong); }

.rep-checklist { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: var(--space-2); }

/* Preview: the client page itself, in its own document. */
.rep-preview { display: flex; flex-direction: column; gap: var(--space-2); }
.rep-preview-head { display: flex; align-items: center; gap: var(--space-2); }
/* The client page in its own document: its landmarks and styles stay its own. */
.rep-preview-frame {
  display: block; width: 100%; height: 34rem;
  border: 1px solid var(--color-line-default); border-radius: var(--radius-card);
  background: var(--color-surface-panel);
}
.rep-preview-empty { display: grid; place-items: center; overflow: auto; padding: var(--space-4); }
.rep-preview-frame:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }

/* Versions */
.rep-versions { max-width: var(--layout-evidence); }
.rep-version-actions { gap: var(--space-1); flex-wrap: wrap; }
.rep-link-cell { min-width: 18rem; max-width: 36rem; white-space: normal; }
.rep-copy code, .rep-copy [data-copy-text] { white-space: normal; overflow-wrap: anywhere; word-break: break-all; }
.rep-link-status { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
.rep-copy { display: flex; flex-direction: column; gap: var(--space-2); align-items: start; }
.rep-copy-value {
  font-family: var(--font-code); font-size: var(--text-2xs);
  padding: var(--space-1) var(--space-2);
  border: 1px solid var(--color-line-default); border-radius: var(--radius-control);
  background: var(--color-surface-well); color: var(--color-ink-secondary);
  overflow-wrap: anywhere; max-width: 34ch;
}

/* The bios checkbox wraps its own label (0014 pattern 8): the whole row is the target, never a
   bare 16px box between an input and a button. Drawn with the Checkbox component's classes. */
.rep-check { display: grid; grid-template-columns: auto minmax(0, 1fr); column-gap: var(--space-2); align-items: start; min-height: var(--space-6); cursor: pointer; }
.rep-check .checkbox-input, .rep-check .checkbox-mark { grid-area: 1 / 1; }
.rep-check .checkbox-text { grid-area: 1 / 2; }

/* Phone (decision 0014): the add-section field and the block actions take the full width; the
   hero picker keeps two pictures per row; the version links wrap instead of holding a minimum. */
@media (max-width: 720px) {
  .rep-add { align-items: stretch; }
  .rep-add-field { min-width: 0; flex: 1 1 100%; }
  .rep-add .btn { width: 100%; min-height: var(--button-height-coarse); }
  .rep-block-form > .row:has(> .btn), .rep-side form > .row:has(> .btn) { flex-direction: column; align-items: stretch; }
  .rep-block-form > .row > .btn, .rep-side form > .row > .btn { width: 100%; min-height: var(--button-height-coarse); }
  .rep-hero-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .rep-checklist { grid-template-columns: minmax(0, 1fr); }
  .rep-preview-frame { height: 28rem; }
  .rep-link-cell { min-width: 0; }
  .rep-copy-value { max-width: 100%; }
  .rep-versions { max-width: none; }
}


/* ---- faces/app/campaigns/shelfworthy/shelfworthy.css ---- */
/* Campaign Shelfworthy screen (M9). Tokens only — see CLAUDE.md invariant 1. */

.sw { display: flex; flex-direction: column; }

.sw-h3 { font-size: var(--text-lg); font-weight: var(--weight-medium); margin: 0; }

.sw-intro { max-width: 60ch; text-wrap: pretty; }

/* ---- The offer picker ---- */
.sw-offers { display: flex; flex-direction: column; gap: var(--space-3); }

.sw-offer { display: block; }

/* ---- The numbers from the last pull ---- */
.sw-tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
  gap: var(--space-3);
}

/* ---- Roster cells ---- */
.sw-creator { font-weight: var(--weight-medium); }

/* The copy control and the value it copies sit on one line; the value stays selectable so the
   page works with the island's clipboard call refused (insecure context, denied permission). */
.sw-copy {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  max-width: 100%;
  min-width: 0;
  white-space: normal;
}

.sw-url { overflow-wrap: anywhere; }

/* The sticker sentence is long by design; it is clamped here and copied whole. */
.sw-sticker {
  display: block;
  min-width: 0;
  max-width: 20rem;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  color: var(--color-ink-secondary);
  font-size: var(--text-sm);
}

/* ---- A mint that Shelfworthy refused ---- */
.sw-error { display: inline-flex; flex-direction: column; gap: var(--space-1); align-items: flex-start; }

.sw-why { display: block; max-width: 22rem; text-wrap: pretty; }


/* ---- faces/app/community/community.css ---- */
/* Community (/app/community) — the table screen. Tokens only; the table itself is styled by
   src/ui/components/data-table.css and this file only adds what the page wraps around it. */

.community { display: flex; flex-direction: column; gap: var(--space-4); min-width: 0; }

/* The search sits in the DataTable toolbar's search slot and the view actions in its actions
   slot; the Toolbar (src/ui/components/toolbar.css) collapses them on a phone (0014 pattern 3). */
.community-search { display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
.community-search-input { width: 220px; }

/* Top channel: platform, followers, engagement rate — right aligned like every metric cell. */
.community-top { display: inline-flex; align-items: center; gap: var(--space-2); justify-content: flex-end; }

.community-pagination {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); flex-wrap: wrap;
  padding: 0 var(--space-1);
}
.community-range { font-size: var(--text-sm); line-height: var(--leading-sm); color: var(--color-ink-secondary); }
.community-pagination-controls { display: flex; align-items: center; gap: var(--space-2); }

/* Filter drawers: a long option list scrolls inside the drawer body rather than pushing
   "Apply filter" out of reach. */
.community-choices {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: var(--space-2);
  max-height: 320px; overflow-y: auto;
  padding: var(--space-1);
}
.community-range-fields { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-4); }

/* Phone (docs/decisions/0014-responsive.md pattern 3): the search fills what the Toolbar's
   Filters and More leave of the row; the field submits on Enter (and the keyboard's Go), so the
   Search button would only cost width. */
@media (max-width: 720px) {
  .community-search { flex: 1 1 auto; }
  .community-search-input { flex: 1 1 auto; width: auto; min-width: 7rem; }
  .community-search > .btn { display: none; }
  .community-range-fields { grid-template-columns: 1fr; }
  .community-pagination-controls { width: 100%; }
  .community-pagination-controls > .btn { flex: 1 1 0; }
}

/* D5: the merge review queue. Two people side by side, the rule, the score, one verb. */
.mq-page { padding-block-end: var(--space-6); }
.mq-person { display: inline-flex; align-items: center; gap: var(--space-2); min-width: 0; }
.mq-person-text { display: flex; flex-direction: column; min-width: 0; }
.mq-detail { display: block; text-wrap: pretty; }
.mq-wins { color: var(--color-ink-secondary); }
.mq-acts { display: flex; flex-wrap: wrap; gap: var(--space-2); }


/* ---- faces/app/creators/creator-record.css ---- */
/* Creator record — DESIGN.md §9.7 (header, 320px facts + fluid main), §9.2, §9.5. Tokens only. */

.cr-content { display: flex; flex-direction: column; gap: var(--space-6); padding-block-end: var(--space-12); }

/* ---- Header: 56px avatar, name, handle, platforms, verdict, status ---- */
.cr-header { display: flex; align-items: center; gap: var(--space-4); flex-wrap: wrap; }
.cr-header-text { display: flex; flex-direction: column; gap: var(--space-1); min-width: 0; }
.cr-name { margin: 0; }
.cr-meta { display: flex; align-items: baseline; gap: var(--space-2); margin: 0; flex-wrap: wrap; }
.cr-handle { overflow-wrap: anywhere; }
.cr-header-marks { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; margin-inline-start: auto; }

/* ---- "Add to" split button: one control, two halves, one shared edge ---- */
.cr-split { display: inline-flex; align-items: stretch; }
.cr-split .cr-split-main { border-start-end-radius: 0; border-end-end-radius: 0; }
.cr-split .cr-split-menu { margin-inline-start: 1px; }
.cr-split .cr-split-menu .btn { border-start-start-radius: 0; border-end-start-radius: 0; }

/* ---- Body: 320px profile facts plus a fluid main column ---- */
.cr-body { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--space-6); align-items: start; }
/* Desktop only (0014: > 1024): the facts column beside the main column. Narrow and phone stack. */
@media (min-width: 1025px) {
  .cr-body { grid-template-columns: 320px minmax(0, 1fr); }
}
.cr-facts { display: flex; flex-direction: column; gap: var(--space-4); }
.cr-main { display: flex; flex-direction: column; gap: var(--space-6); min-width: 0; }
.cr-single { display: flex; flex-direction: column; gap: var(--space-6); min-width: 0; }

.cr-facts-list { display: flex; flex-direction: column; gap: var(--space-3); margin: 0; }
.cr-fact { display: flex; flex-direction: column; gap: var(--space-1); }
.cr-fact-value { margin: 0; color: var(--color-ink); }

.cr-chips { display: flex; flex-wrap: wrap; gap: var(--space-1); margin: 0; padding: 0; list-style: none; }
.cr-fresh { white-space: nowrap; }

/* ---- Tables: real controls live in the rows, so they wrap rather than clip ---- */
/* The scroller is the containing block for the visually hidden labels inside it (0014 pattern 1):
   an absolutely positioned label in a cell otherwise lands past the viewport and widens the page. */
.cr-table { position: relative; }
.cr-table:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }
.cr-table .dt-td { height: auto; white-space: normal; vertical-align: top; padding-block: var(--space-2); }
.cr-table .dt-td-right { white-space: nowrap; }
.cr-account-cell { display: flex; align-items: center; gap: var(--space-2); }
.cr-account-handle { overflow-wrap: anywhere; }
.cr-source-cell { display: flex; flex-direction: column; gap: var(--space-1); }

.cr-post-cell { display: flex; align-items: flex-start; gap: var(--space-2); }
.cr-post-text { display: flex; flex-direction: column; gap: var(--space-1); min-width: 0; max-width: 32ch; }
.cr-thumb {
  display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto;
  width: var(--space-10); height: var(--space-10);
  border-radius: var(--radius-control); background: var(--color-surface-well);
  color: var(--color-ink-tertiary); overflow: hidden;
}
.cr-thumb img { width: 100%; height: 100%; object-fit: cover; }

/* ---- Followers panel ---- */
.cr-audience-head { display: flex; align-items: baseline; gap: var(--space-2); flex-wrap: wrap; margin: 0; }
.cr-audience-number { font-family: var(--font-display); }
/* Each breakdown is a BarChart (src/ui/components/bar-chart.css); the grid only places them. */
.cr-audience-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--space-5); }
.cr-source { margin: 0; }

/* ---- Brands and hashtags ---- */
.cr-mentions { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: var(--space-5); }
.cr-mention-list { display: flex; flex-direction: column; gap: var(--space-2); margin: 0; padding: 0; list-style: none; }

/* ---- Vetting placeholders ---- */
.cr-vetting-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: var(--space-4); }

/* ---- Manage forms ---- */
.cr-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--space-4); align-items: start; }
.cr-grid-full { grid-column: 1 / -1; }
.cr-add-contact { padding-block-start: var(--space-4); border-block-start: 1px solid var(--color-line-subtle); }
.cr-tag-types { display: flex; flex-direction: column; gap: var(--space-1); }
.cr-tag-row { display: inline-flex; align-items: center; gap: var(--space-1); }
.cr-add-tag { align-items: flex-end; gap: var(--space-2); flex-wrap: wrap; }
.cr-rule { width: 100%; height: 1px; border: 0; margin-block: var(--space-2); background: var(--color-line-subtle); }
.cr-paypal { margin: 0; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }

/* ---- Content filters ---- */
.cr-filters { display: flex; align-items: flex-end; gap: var(--space-3); flex-wrap: wrap; }
.cr-filter-actions { display: flex; align-items: center; gap: var(--space-2); }

.cr-load-more { justify-content: center; padding-block-start: var(--space-3); }

/* ---- Merge ---- */
.cr-merge-search { align-items: flex-end; gap: var(--space-3); flex-wrap: wrap; }
.cr-move-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--space-5); }
.cr-move { display: flex; flex-direction: column; gap: var(--space-2); }
.cr-move-list { display: flex; flex-direction: column; gap: var(--space-1); margin: 0; padding: 0; list-style: none; }

/* Phone (0014 pattern 5): forms are one column, every field full width, the submit full width at
   the bottom of its form and touch height. Buttons inside table cells keep their size. */
@media (max-width: 720px) {
  .cr-header-marks { margin-inline-start: 0; }
  .cr-grid { grid-template-columns: 1fr; }
  .cr-content form > .row.right { flex-wrap: wrap; }
  .cr-content form > .row.right > .btn,
  .cr-add-contact > .cr-grid-full > .btn.right,
  .cr-add-tag > .btn,
  .cr-merge-search > .btn,
  .cr-filter-actions > .btn { flex: 1 1 100%; min-height: var(--button-height-touch); margin-inline-start: 0; }
  .cr-add-tag > .field,
  .cr-merge-search > .field,
  .cr-filters > .field { flex: 1 1 100%; }
  .cr-filter-actions { flex-wrap: wrap; width: 100%; }
  .cr-add-contact > .cr-grid-full { flex-wrap: wrap; }
  .cr-split { width: 100%; }
  .cr-split .cr-split-main { flex: 1 1 auto; }
}


/* ---- faces/app/creators/vetting.css ---- */
/* Creator record → Vetting (M5). DESIGN.md §9.3 and §9.7. Tokens only — invariant 1. */
.cr-vetting-list { display: flex; flex-direction: column; gap: var(--space-6); }

.cr-vet-head { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: flex-start; justify-content: space-between; }
.cr-vet-head > .stack-2 { min-width: 0; }

/* Where the judgement came from: relative time, rubric version, model. */
.cr-vet-provenance { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-1); }

.cr-vet-override { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-2); padding: var(--space-3); border: 1px solid var(--color-line-default); border-radius: var(--radius-card); background: var(--color-surface-well); }

.cr-vet-reasons { margin: 0; padding-inline-start: var(--space-5); color: var(--color-ink-secondary); display: flex; flex-direction: column; gap: var(--space-1); }

.cr-vet-grade { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); margin: 0; }

.cr-vet-signals { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: var(--space-4); }

/* Examples stay folded away: a post id is evidence, not something to read past. */
.cr-vet-examples > summary { cursor: pointer; color: var(--color-ink-secondary); font-size: var(--text-sm); line-height: var(--leading-sm); }
.cr-vet-examples > summary:focus-visible { outline: 2px solid var(--color-focus); outline-offset: var(--space-1); border-radius: var(--radius-control); }
.cr-vet-example-list { margin: var(--space-2) 0 0; padding: 0; list-style: none; display: flex; flex-wrap: wrap; gap: var(--space-2); font-size: var(--text-sm); line-height: var(--leading-sm); }

.cr-vet-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); }


/* ---- faces/app/discover/customers.css ---- */
/* Creators among your customers (/app/discover/customers, D6). The card grid is Discover's own
   (.dsc-grid); this file adds the upload, the confirm counts and the file rows. Every value is a
   token. */

.cus { display: flex; flex-direction: column; gap: var(--space-5); padding: var(--space-4) var(--space-5) var(--space-6); max-inline-size: 72rem; min-width: 0; }
.cus-narrow { max-inline-size: 44rem; }
.cus-lede { margin: 0; max-inline-size: 70ch; }
.cus-aside { margin: calc(var(--space-4) * -1) 0 0; }
.cus-crumb { margin: 0; }
.cus-crumb a { color: inherit; }
.cus-group-h { margin: 0 0 var(--space-2); color: var(--color-ink-tertiary); }

/* ---------- The upload ---------- */
.cus-card { max-inline-size: 44rem; }
.cus-form { display: flex; flex-direction: column; gap: var(--space-4); }
.cus-privacy { margin: 0; max-inline-size: 66ch; }
.cus-actions { display: flex; align-items: center; justify-content: flex-end; gap: var(--space-2); margin: 0; }
.cus-file { font-size: var(--text-sm); line-height: var(--leading-sm); color: var(--color-ink-secondary); max-inline-size: 100%; }
.cus-file::file-selector-button {
  margin-inline-end: var(--space-2); block-size: 28px; padding: 0 var(--space-3);
  border: 1px solid var(--color-line-interactive); border-radius: var(--radius-control);
  background: var(--color-surface-panel); color: var(--color-ink); font: inherit; cursor: pointer;
}

/* ---------- The confirm step ---------- */
.cus-counts { display: grid; grid-template-columns: repeat(auto-fit, minmax(7rem, 1fr)); gap: var(--space-3); margin: var(--space-3) 0; }
.cus-count { display: flex; flex-direction: column; gap: 2px; }
.cus-count dt { margin: 0; }
.cus-count dd { margin: 0; font-size: var(--text-lg); line-height: var(--leading-lg); font-weight: var(--weight-title); }
.cus-cost { margin: 0 0 var(--space-3); color: var(--color-ink-secondary); }

/* ---------- The file rows ---------- */
.cus-rows { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); }
.cus-row {
  display: grid; grid-template-columns: minmax(0, 1fr) auto auto; gap: var(--space-3);
  align-items: center; padding: var(--space-3); text-decoration: none; color: inherit;
  border: 1px solid var(--color-line-subtle); border-radius: 10px; background: var(--color-surface-panel);
  transition: border-color var(--duration-fast) var(--easing-standard);
}
.cus-row:hover { border-color: var(--color-line-default); background: var(--color-surface-well); }
.cus-row:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }
.cus-row-t { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.cus-row-name { font-size: var(--text-base); line-height: var(--leading-base); font-weight: var(--weight-strong); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cus-row-meta { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cus-row-counts { text-align: end; color: var(--color-ink-secondary); }

/* ---------- One import ---------- */
.cus-head { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: var(--space-3); }
.cus-head-t { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.cus-head-t p { margin: 0; }
.cus-head-counts { font-size: var(--text-md); line-height: var(--leading-md); }
.cus-head-acts { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.cus-failed { margin: 0; color: var(--color-ink-secondary); }
.cus-addall {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin: 0;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-line-subtle); border-radius: 10px; background: var(--color-surface-well);
}
.cus-addall .select-wrap { inline-size: auto; min-inline-size: 14rem; }

@media (max-width: 640px) {
  .cus { padding: var(--space-3) var(--space-4) var(--space-5); gap: var(--space-4); }
  .cus-row { grid-template-columns: minmax(0, 1fr) auto; }
  .cus-row-counts { grid-column: 1 / -1; text-align: start; }
  .cus-counts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}


/* ---- faces/app/discover/discover.css ---- */
/* Discover (/app/discover, D2) — the search surface. Layout, states and motion follow
   docs/prototype/discover.html; every value is a token. Cards are styled here because they are the
   face's own component (src/faces/app/discover/CreatorCard.tsx). */

.dsc-content { padding: 0; display: flex; flex-direction: column; min-height: 100%; }
.dsc { display: flex; flex-direction: column; min-width: 0; flex: 1 1 auto; }

/* ---------- The bar ---------- */
.dsc-searchwrap { padding: var(--space-4) var(--space-5) 0; }
.dsc-searchbar {
  display: flex; align-items: center; gap: var(--space-2);
  min-height: 44px; padding: 0 var(--space-1) 0 var(--space-3);
  border: 1px solid var(--color-line-interactive); border-radius: 10px;
  background: var(--color-surface-panel);
  transition: border-color var(--duration-fast) var(--easing-standard), box-shadow var(--duration-fast) var(--easing-standard);
}
.dsc-searchbar:focus-within { border-color: var(--color-ink); box-shadow: 0 0 0 3px var(--color-brand-wash); }
.dsc-searchbar-brief { align-items: flex-start; padding-top: var(--space-2); padding-bottom: var(--space-2); }
.dsc-search-lead { color: var(--color-ink-tertiary); flex: 0 0 auto; }
.dsc-searchbar-brief .dsc-search-lead { margin-top: var(--space-1); }
.dsc-q {
  flex: 1 1 auto; min-width: 0; border: 0; background: none; outline: 0;
  font: inherit; font-size: var(--text-md); line-height: var(--leading-md); color: var(--color-ink);
  min-height: 42px;
}
.dsc-q::placeholder { color: var(--color-ink-tertiary); }
.dsc-q-brief { resize: vertical; min-height: 120px; font-size: var(--text-base); line-height: var(--leading-base); padding-top: var(--space-2); }
.dsc-listpick, .dsc-lenspick { display: none; }
.dsc-searchbar[data-mode="list"] .dsc-listpick { display: block; }
/* A handle seed is answered under a lens; the bar offers it before the search runs. */
.dsc-searchbar[data-mode="handle"] .dsc-lenspick { display: block; }
.dsc-list-select { height: 32px; }
/* Mode: four radios styled as a segmented control; the well is the same as every other segmented (§9). */
.dsc-modes {
  display: inline-flex; gap: 2px; padding: 2px; margin: 0; border: 0;
  background: var(--color-surface-well); border-radius: var(--radius-control);
  box-shadow: inset 0 0 0 1px var(--color-line-subtle);
  flex: 0 0 auto;
}
.dsc-mode { position: relative; }
.dsc-mode span {
  display: inline-flex; align-items: center; height: 26px; padding: 0 var(--space-2);
  border-radius: 6px; font-size: var(--text-xs); font-weight: var(--weight-medium); color: var(--color-ink-tertiary);
  cursor: pointer;
}
.dsc-mode input:checked + span { background: var(--color-surface-panel); color: var(--color-ink); box-shadow: inset 0 0 0 1px var(--color-line-default); }
.dsc-mode input:focus-visible + span { outline: 2px solid var(--color-focus); outline-offset: 2px; }
.dsc-search-go { flex: 0 0 auto; }

/* ---------- Chips ---------- */
.dsc-chips { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin: 0; padding: var(--space-3) var(--space-5) 0; list-style: none; }
.dsc-chip { position: relative; gap: 0; }
.dsc-chip-edit {
  display: inline-flex; align-items: center; gap: 0.3em; height: 26px; padding: 0 var(--space-1);
  border: 0; background: none; font: inherit; color: inherit; cursor: pointer; border-radius: var(--radius-control);
  white-space: nowrap;
}
.dsc-chip-edit:hover { background: var(--color-surface-well); }
.dsc-chip-resolved { border-color: var(--color-brand-tint); background: var(--color-brand-wash); }
.dsc-chip-add { border-style: dashed; color: var(--color-ink-tertiary); cursor: pointer; }
.dsc-chip-add:hover { color: var(--color-ink); border-color: var(--color-line-interactive); }
/* A refinement highlights what it changed, then settles: one region, 1.6 s, no travel (§9a). */
@keyframes dsc-chip-flash { 0%, 40% { background: var(--color-brand-tint); border-color: var(--color-brand); } 100% { background: var(--color-surface-panel); } }
.dsc-chip-changed { animation: dsc-chip-flash 1600ms var(--easing-standard) both; }
.dsc-chip-pop { padding: var(--space-3); min-width: 260px; }
.dsc-chip-pop .row { margin-top: var(--space-2); justify-content: flex-end; }

/* ---------- Results head ---------- */
.dsc-rhead { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; padding: var(--space-4) var(--space-5) var(--space-3); }
.dsc-count strong { color: var(--color-ink); }

/* The first pass (D3): four links, a dot and a word each — never colour alone (§11). */
.dsc-labelfilter { display: inline-flex; gap: var(--space-1); flex-wrap: wrap; }
.dsc-labelbtn {
  display: inline-flex; align-items: center; gap: var(--space-2); height: 26px; padding: 0 9px;
  border: 1px solid var(--color-line-default); border-radius: var(--radius-pill);
  background: var(--color-surface-panel); color: var(--color-ink-secondary);
  font-size: var(--text-xs); font-weight: var(--weight-medium); text-decoration: none; white-space: nowrap;
}
.dsc-labelbtn:hover { border-color: var(--color-line-interactive); color: var(--color-ink); text-decoration: none; }
.dsc-labelbtn[aria-current="true"] { background: var(--color-surface-well); border-color: var(--color-line-interactive); color: var(--color-ink); }
.dsc-labeldot { width: 8px; height: 8px; border-radius: var(--radius-pill); flex: 0 0 auto; }
.dsc-labeldot-ok { background: var(--color-ok); }
.dsc-labeldot-warn { background: var(--color-warn); }
.dsc-labeldot-bad { background: var(--color-bad); }

/* ---------- Body: results + panel ---------- */
/* Searching: the flame in the white space under the bar, everything else below the bar gone until the next page. */
.dsc-searching { display: none; }
.dsc[data-searching] > :not(.dsc-searchwrap):not(.dsc-searching):not(script) { display: none; }
.dsc[data-searching] .dsc-searching {
  display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center;
  flex: 1 1 auto; gap: var(--space-2); padding: var(--space-12) var(--space-6);
}
.dsc-searching-flame, .dsc-searching-still { display: block; inline-size: 87px; block-size: 115px; margin-block-end: var(--space-3); }
.dsc-searching-still { display: none; }
.dsc-searching-title { font-size: var(--text-lg); line-height: var(--leading-lg); font-family: var(--font-title); font-weight: var(--weight-medium); }
.dsc-searching-body { font-size: var(--text-sm); line-height: var(--leading-sm); }
@media (prefers-reduced-motion: reduce) {
  .dsc-searching-flame { display: none; }
  .dsc[data-searching] .dsc-searching-still { display: block; }
}

.dsc-body { display: grid; grid-template-columns: minmax(0, 1fr) 320px; flex: 1 1 auto; min-height: 0; }
.dsc[data-panel="collapsed"] .dsc-body { grid-template-columns: minmax(0, 1fr) 40px; }
.dsc-results { padding: 0 var(--space-5) var(--space-6); min-width: 0; }
.dsc-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: var(--space-3); }
.dsc-grid-compact { grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: var(--space-2); }

/* ---------- Card ---------- */
.dsc-card {
  position: relative; display: flex; flex-direction: column; gap: var(--space-2);
  padding: var(--space-3) var(--space-3) var(--space-2);
  background: var(--color-surface-panel);
  border: 1px solid var(--color-line-subtle); border-radius: var(--radius-card);
  transition: border-color var(--duration-fast) var(--easing-standard), background-color var(--duration-fast) var(--easing-standard);
}
.dsc-card:hover { border-color: var(--color-line-default); }
.dsc-card:focus-visible, .dsc-card[data-focused="true"] { outline: 0; border-color: var(--color-ink); box-shadow: 0 0 0 3px var(--color-brand-wash); }
.dsc-card:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }
.dsc-card[data-selected="true"] { background: var(--color-brand-wash); }
.dsc-card[data-selected="true"]::before { content: ""; position: absolute; left: -1px; top: var(--space-3); bottom: var(--space-3); width: 3px; border-radius: 2px; background: var(--color-brand); }
.dsc-card[data-decision="keep"] { border-color: var(--color-ok); }
/* A passed card is settled, not hidden: the frames dim, the words stay at full strength. Fading
   the whole card drops tertiary text to 2.6:1, which invariant 9 catches the moment a passed card
   is above the fold. The verdict is carried by the footer's word and dot, not by opacity. */
.dsc-card[data-decision="pass"] { border-color: var(--color-line-subtle); }
.dsc-card[data-decision="pass"] .dsc-thumb img,
.dsc-card[data-decision="pass"] .dsc-thumb-blank,
.dsc-card[data-decision="pass"] .dsc-thumb-empty { opacity: 0.5; }
.dsc-card[data-decision="hold"] { border-style: dashed; }
.dsc-grid-compact .dsc-card { gap: var(--space-1); padding: var(--space-2); }

.dsc-thumbs { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-1); border-radius: var(--radius-control); overflow: hidden; }
.dsc-thumbs-8 { grid-template-columns: repeat(4, 1fr); gap: var(--space-2); }
.dsc-thumb { position: relative; display: block; aspect-ratio: 4 / 5; background: var(--color-surface-well); overflow: hidden; }
.dsc-thumb img, .dsc-thumb-blank { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; background: var(--color-surface-well); }
.dsc-thumb-empty { background: linear-gradient(160deg, var(--color-surface-well), var(--color-line-subtle)); }
.dsc-thumb-tag {
  position: absolute; left: var(--space-1); bottom: var(--space-1);
  height: 16px; padding: 0 5px; border-radius: 4px;
  font-size: var(--text-2xs); line-height: 16px; font-weight: var(--weight-medium); letter-spacing: 0.02em;
  background: var(--color-ink); color: var(--color-ink-inverse);
}
.dsc-thumb-tag-kw { background: var(--color-action-primary); color: var(--color-on-action-primary); }
/* The caption is a preview on hover; the same posts, with captions, are in the peek's Content tab. */
.dsc-thumb-cap {
  position: absolute; inset: 0; padding: var(--space-1);
  display: flex; align-items: flex-end;
  background: var(--color-ink); color: var(--color-ink-inverse);
  font-size: var(--text-2xs); line-height: 13px;
  opacity: 0; transition: opacity var(--duration-fast) var(--easing-standard);
  overflow: hidden;
}
.dsc-thumb:hover .dsc-thumb-cap { opacity: 0.92; }

.dsc-card-head { display: flex; gap: var(--space-2); align-items: flex-start; }
.dsc-who { flex: 1 1 auto; min-width: 0; }
.dsc-name { margin: 0; font-size: var(--text-base); line-height: var(--leading-sm); font-weight: var(--weight-medium); color: var(--color-ink); }
.dsc-handle { margin: 0; display: flex; align-items: center; gap: var(--space-1); font-size: var(--text-xs); line-height: var(--leading-xs); color: var(--color-ink-tertiary); }
.dsc-where { position: relative; margin: 2px 0 0; display: flex; align-items: center; gap: var(--space-1); font-size: var(--text-xs); line-height: var(--leading-xs); color: var(--color-ink-secondary); min-width: 0; }
.dsc-where-btn {
  display: inline-flex; align-items: center; gap: 5px; min-width: 0; max-width: 100%;
  border: 0; background: none; padding: 0; font: inherit; color: inherit; cursor: default; border-radius: var(--radius-control);
}
/* Confidence dot: high is ok, mid is warn, low is a ring, none is nothing. Evidence appears on hover and focus. */
.dsc-conf { display: inline-block; width: 7px; height: 7px; border-radius: var(--radius-pill); background: var(--color-ok); flex: 0 0 auto; }
[data-confidence="mid"] .dsc-conf, .dsc-conf[data-confidence="mid"] { background: var(--color-warn); }
[data-confidence="low"] .dsc-conf, .dsc-conf[data-confidence="low"] { background: transparent; box-shadow: inset 0 0 0 1.5px var(--color-ink-tertiary); }
[data-confidence="none"] .dsc-conf, .dsc-conf[data-confidence="none"] { background: transparent; box-shadow: inset 0 0 0 1.5px var(--color-line-default); }
.dsc-where-dot { position: relative; display: inline-flex; align-items: center; min-width: 0; max-width: 100%; }
/* D5: the dot opens to the resolver's own line, which names the votes — so it wraps and is capped
   rather than running off the card. */
.dsc-where-evidence {
  position: absolute; left: 0; top: 100%; z-index: 2; margin-top: var(--space-1);
  padding: var(--space-1) var(--space-2); border-radius: var(--radius-control);
  background: var(--color-ink); color: var(--color-ink-inverse);
  inline-size: max-content; max-inline-size: min(280px, 60vw); text-wrap: pretty;
  opacity: 0; pointer-events: none; transition: opacity var(--duration-fast) var(--easing-standard);
}
.dsc-where-btn:hover + .dsc-where-evidence, .dsc-where-btn:focus-visible + .dsc-where-evidence { opacity: 1; }

/* D5 provenance: a chip per enriched group, beside the fact it explains. It stays in the tab order
   — opacity, never visibility — so tabbing to it is what brings it up for a keyboard. */
.dsc-provwrap { position: relative; }
.dsc-provwrap .prov-wrap { opacity: 0; transition: opacity var(--duration-fast) var(--easing-standard); }
.dsc-provwrap:hover .prov-wrap,
.dsc-provwrap:focus-within .prov-wrap,
.dsc-card:focus-within .dsc-provwrap .prov-wrap,
.dsc-provwrap .prov-wrap[open] { opacity: 1; }
.dsc-statrow { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; min-width: 0; }
.dsc-statrow .dsc-stats { flex: 0 1 auto; }
.dsc-fit { text-align: right; flex: 0 0 auto; display: flex; flex-direction: column; align-items: flex-end; gap: 2px; }
.dsc-fit-value { font-family: var(--font-title); font-size: var(--text-lg); line-height: var(--leading-lg); font-weight: var(--weight-medium); letter-spacing: -0.01em; }
.dsc-fit-none { color: var(--color-ink-disabled); font-weight: var(--weight-regular); }
.dsc-fit-pill { margin-top: 2px; }
.dsc-fit-cell { display: inline-flex; flex-direction: column; align-items: flex-end; gap: 2px; }
.dsc-why-cell { display: block; max-width: 280px; color: var(--color-ink-secondary); }

/* The exploration pick, named where the prototype names it. Ink on ink-inverse, not a status. */
.dsc-stretch {
  position: absolute; inset-inline-end: var(--space-3); inset-block-start: var(--space-3); z-index: 1;
  height: 20px; padding: 0 7px; border-radius: 5px;
  background: var(--color-ink); color: var(--color-ink-inverse);
  font-size: var(--text-2xs); line-height: 20px; font-weight: var(--weight-medium); letter-spacing: 0.03em;
}

/* The reason a score was given. A score is never rendered without it. */
.dsc-why { display: flex; gap: var(--space-2); align-items: flex-start; margin: 0; font-size: var(--text-xs); line-height: var(--leading-xs); color: var(--color-ink-secondary); }
.dsc-why-icon { color: var(--color-ink-tertiary); flex: 0 0 auto; margin-top: 2px; }

/* Evidence chips: one fact, its source, and the warn tint when the fact is estimated (§9b). */
.dsc-evidence { display: flex; flex-wrap: wrap; gap: var(--space-1); margin: 0; padding: 0; list-style: none; }
.dsc-ev {
  display: inline-flex; align-items: center; gap: var(--space-1); min-height: 20px; padding: 0 7px;
  max-width: 100%; min-width: 0;
  border: 1px solid var(--color-line-subtle); border-radius: 5px; background: var(--color-surface-well);
  font-size: var(--text-2xs); line-height: 18px; color: var(--color-ink-secondary); white-space: nowrap;
}
/* A chip never leaves the card: the fact truncates, the source stays whole; focus shows the full fact (§6). */
.dsc-ev-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dsc-ev-src { flex: 0 0 auto; }
.dsc-ev:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }
.dsc-ev:focus-visible .dsc-ev-text { white-space: normal; overflow: visible; }
.dsc-ev-est { background: var(--color-warn-tint); border-color: transparent; color: var(--color-warn); }
.dsc-ev-src { color: var(--color-ink-tertiary); }
.dsc-ev-est .dsc-ev-src { color: inherit; }

.dsc-stats { display: flex; gap: var(--space-4); margin: 0; font-size: var(--text-xs); line-height: var(--leading-xs); color: var(--color-ink-secondary); flex-wrap: wrap; }
.dsc-stats dd { margin: 0; }
.dsc-stats strong { color: var(--color-ink); font-weight: var(--weight-medium); }

.dsc-flags { display: flex; gap: var(--space-2); flex-wrap: wrap; align-items: center; min-height: 22px; }
.dsc-flags .verdict-word { font-size: var(--text-xs); }

/* The pass-reason row. Dashed = a hard rule for the brand. */
.dsc-reasons-form[hidden] { display: none; }
.dsc-reasons { display: flex; flex-wrap: wrap; gap: var(--space-1); margin: 0; padding: var(--space-2); border: 1px solid var(--color-line-default); border-radius: var(--radius-control); background: var(--color-surface-well); min-width: 0; }
.dsc-reasons-title { float: left; width: 100%; padding: 0; margin-bottom: 2px; }
.dsc-reason {
  height: 24px; padding: 0 var(--space-2); border-radius: var(--radius-pill);
  border: 1px solid var(--color-line-default); background: var(--color-surface-panel);
  font: inherit; font-size: var(--text-xs); font-weight: var(--weight-medium); color: var(--color-ink-secondary); cursor: pointer;
}
.dsc-reason:hover { border-color: var(--color-line-interactive); color: var(--color-ink); }
.dsc-reason-hard { border-style: dashed; }

.dsc-card-foot { display: flex; align-items: center; justify-content: space-between; gap: var(--space-1); border-top: 1px solid var(--color-line-subtle); padding-top: var(--space-2); margin-top: auto; min-width: 0; }
/* Actions appear on hover and focus; they are in the tab order the whole time (nothing hover-only). */
.dsc-acts { display: flex; gap: 0; flex-wrap: wrap; min-width: 0; opacity: 0; transition: opacity var(--duration-fast) var(--easing-standard); }
.dsc-card:hover .dsc-acts, .dsc-card[data-focused="true"] .dsc-acts, .dsc-card:focus-within .dsc-acts, .dsc-acts:focus-within { opacity: 1; }
@media (hover: none) { .dsc-acts { opacity: 1; } }
.dsc-act-form { display: contents; }
.dsc-act {
  display: inline-flex; align-items: center; gap: var(--space-1); height: 26px; padding: 0 7px;
  border: 0; border-radius: 6px; background: none; font: inherit; font-size: var(--text-xs); font-weight: var(--weight-medium);
  color: var(--color-ink-secondary); cursor: pointer; text-decoration: none; white-space: nowrap;
}
.dsc-act:hover { background: var(--color-brand-wash); color: var(--color-ink); text-decoration: none; }
.dsc-act-keep:hover { background: var(--color-ok-tint); color: var(--color-ok); }
.dsc-act-pass:hover { background: var(--color-bad-tint); color: var(--color-bad); }
.dsc-act kbd, .dsc-key kbd, .dsc-more kbd { font-size: var(--text-2xs); line-height: 14px; min-width: 16px; padding: 0 4px; text-align: center; }
.dsc-act kbd { color: var(--color-ink-tertiary); }
.dsc-act-pop .btn { height: 26px; padding: 0 7px; font-size: var(--text-xs); color: var(--color-ink-secondary); }
.dsc-list-form { padding: var(--space-3); min-width: 240px; }
.dsc-card-tools { display: flex; align-items: center; gap: 0; flex: 0 0 auto; }
.dsc-more { padding: var(--space-1); min-width: 220px; }
.dsc-more .menu-item { width: 100%; border: 0; background: none; font: inherit; text-align: left; cursor: pointer; }
.dsc-more kbd { margin-inline-start: auto; }
.dsc-decided { display: inline-flex; align-items: center; gap: var(--space-2); font-size: var(--text-xs); font-weight: var(--weight-medium); }
.dsc-decided-dot { width: 8px; height: 8px; border-radius: var(--radius-pill); background: currentColor; flex: 0 0 auto; }
.dsc-decided-keep { color: var(--color-ok); }
.dsc-decided-pass { color: var(--color-bad); }
.dsc-decided-hold { color: var(--color-info); }
.dsc-undo-form { display: contents; }
.dsc-undo {
  border: 0; background: none; padding: 0 0 0 var(--space-1); font: inherit; font-size: var(--text-2xs);
  color: var(--color-ink-tertiary); text-decoration: underline; cursor: pointer;
}
.dsc-undo:hover { color: var(--color-ink); }

/* Similar-to: the three lenses as a menu, opened by the button or by S. */
.dsc-act-lens { display: inline-flex; }
.dsc-lens-pop { padding: var(--space-1); min-width: 220px; }
.dsc-lens-title { padding: var(--space-1) var(--space-2); margin: 0; }
.dsc-lens-list { margin: 0; padding: 0; list-style: none; }
.dsc-lens-list .menu-item { display: flex; align-items: baseline; gap: var(--space-2); width: 100%; }
.dsc-lens-list .menu-item span { margin-inline-start: auto; }
.dsc-row-acts form { display: contents; }

/* Skeletons keep the real card's widths (§9). */
.dsc-card-skeleton .dsc-thumb { animation: skeleton-pulse 1400ms var(--easing-standard) infinite; }
.dsc-card-skeleton .dsc-who { gap: var(--space-1); }

/* ---------- Archetype plan ---------- */
.dsc-plan { margin-bottom: var(--space-4); border: 1px solid var(--color-line-subtle); border-radius: 10px; overflow: hidden; }
.dsc-plan-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); padding: var(--space-2) var(--space-4); background: var(--color-surface-well); border-bottom: 1px solid var(--color-line-subtle); }
.dsc-plan-head p { margin: 0; }
.dsc-plan-rows { margin: 0; padding: 0; list-style: none; }
.dsc-arow { display: flex; gap: var(--space-4); align-items: center; padding: var(--space-2) var(--space-4); border-bottom: 1px solid var(--color-line-subtle); }
.dsc-arow:last-child { border-bottom: 0; }
.dsc-arow[aria-current="true"] { background: var(--color-brand-wash); }
.dsc-arow p { margin: 0; }
.dsc-arow form { display: contents; }

/* ---------- Side panel ---------- */
.dsc-panel { display: flex; flex-direction: column; min-height: 0; border-left: 1px solid var(--color-line-subtle); background: var(--color-surface-well); border-radius: 0 0 var(--radius-card) 0; }
.dsc-panel-head { display: flex; align-items: center; justify-content: space-between; padding: var(--space-3) var(--space-4) var(--space-2); }
.dsc-panel-open { display: none; }
.dsc[data-panel="collapsed"] .dsc-panel-head { flex-direction: column; padding: var(--space-2) 0; }
.dsc[data-panel="collapsed"] .dsc-panel-head .t-label, .dsc[data-panel="collapsed"] .dsc-panel-close, .dsc[data-panel="collapsed"] .dsc-panel-body, .dsc[data-panel="collapsed"] .dsc-refine { display: none; }
.dsc[data-panel="collapsed"] .dsc-panel-open { display: block; }
.dsc-panel-body { flex: 1 1 auto; min-height: 0; }
.dsc-sec { padding: var(--space-3) var(--space-4); border-top: 1px solid var(--color-line-subtle); }
.dsc-sec h3 { margin: 0 0 var(--space-2); }
.dsc-sec p { margin: 0; }
.dsc-assume, .dsc-sugg { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: var(--space-2); }
.dsc-assume { padding-left: var(--space-3); margin-left: 2px; margin-bottom: var(--space-2); border-left: 2px solid var(--color-line-default); }
.dsc-sugg li { display: flex; gap: var(--space-2); align-items: flex-start; justify-content: space-between; }
.dsc-link { flex: 0 0 auto; color: var(--color-brand-strong); font-weight: var(--weight-medium); font-size: var(--text-xs); text-decoration: none; }
.dsc-link:hover { text-decoration: underline; }
.dsc-save .input { flex: 1 1 auto; min-width: 0; }
.dsc-sec-of { font-weight: var(--weight-regular); letter-spacing: normal; text-transform: none; }
/* Kept against passed, as one bar: the keeps fill it, the passes are what is left. */
.dsc-mem { display: flex; gap: var(--space-2); align-items: center; margin: 2px 0 var(--space-2); }
.dsc-mem-bar { flex: 1 1 auto; height: 6px; border-radius: 3px; background: var(--color-bad-tint); overflow: hidden; }
.dsc-mem-fill { display: block; height: 100%; background: var(--color-ok); border-radius: 3px; }
.dsc-mem-act { margin-top: var(--space-2); }
.dsc-reverse { display: flex; align-items: center; gap: var(--space-2); }
.dsc-refine { margin-top: auto; padding: var(--space-3) var(--space-4) var(--space-4); border-top: 1px solid var(--color-line-subtle); }
.dsc-refine-in { display: flex; align-items: center; gap: var(--space-2); height: 36px; padding: 0 var(--space-1) 0 var(--space-3); border: 1px solid var(--color-line-interactive); border-radius: var(--radius-control); background: var(--color-surface-panel); }
.dsc-refine-in:focus-within { border-color: var(--color-ink); box-shadow: 0 0 0 3px var(--color-brand-wash); }
.dsc-refine-input { flex: 1 1 auto; min-width: 0; border: 0; background: none; outline: 0; font: inherit; font-size: var(--text-sm); color: var(--color-ink); }
.dsc-refine-input::placeholder { color: var(--color-ink-tertiary); }

/* ---------- Filters drawer ---------- */
.dsc-filters { display: flex; flex-direction: column; gap: var(--space-5); }
.dsc-fgroup { margin: 0; padding: 0; border: 0; display: flex; flex-direction: column; gap: var(--space-3); }
.dsc-fgroup legend { padding: 0; margin-bottom: var(--space-1); }
.dsc-fgroup > p { margin: -var(--space-2) 0 0; }
.dsc-frow { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-3); align-items: start; }
.dsc-checks { margin: 0; padding: 0; border: 0; display: flex; flex-direction: column; gap: var(--space-1); }
.dsc-filters-foot { display: flex; gap: var(--space-2); }

/* ---------- Keys ---------- */
.dsc-keys { display: grid; grid-template-columns: 1fr auto; gap: var(--space-2) var(--space-4); margin: var(--space-4) 0 0; }
.dsc-key { display: contents; }
.dsc-key dt { font-size: var(--text-sm); color: var(--color-ink-secondary); }
.dsc-key dd { margin: 0; display: flex; gap: var(--space-1); justify-content: flex-end; }

/* ---------- Peek ---------- */
.dsc-peek-drawer .drawer-body { padding-top: var(--space-4); }
.dsc-peek { display: flex; flex-direction: column; gap: var(--space-4); }
.dsc-peek-head { display: flex; gap: var(--space-4); align-items: flex-start; }
.dsc-peek-head h3, .dsc-peek-head p { margin: 0; }
.dsc-peek-foot { display: flex; align-items: center; gap: var(--space-3); padding-top: var(--space-3); border-top: 1px solid var(--color-line-subtle); }
.dsc-peek-page { max-width: 720px; }
.dsc-table-wrap { position: relative; overflow-x: auto; border: 1px solid var(--color-line-subtle); border-radius: var(--radius-control); }
.dsc-table-wrap:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }
.dsc-minitable { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
.dsc-minitable th { height: 34px; padding: 0 var(--space-3); text-align: left; background: var(--color-surface-well); font-size: var(--text-2xs); letter-spacing: var(--tracking-label); text-transform: uppercase; font-weight: var(--weight-medium); color: var(--color-ink-tertiary); white-space: nowrap; border-bottom: 1px solid var(--color-line-subtle); }
.dsc-minitable td { height: 40px; padding: 0 var(--space-3); border-bottom: 1px solid var(--color-line-subtle); white-space: nowrap; }
.dsc-minitable .right { text-align: right; }
.dsc-bars { display: flex; flex-direction: column; gap: var(--space-2); }
.dsc-bar { display: grid; grid-template-columns: 90px 1fr 44px; gap: var(--space-2); align-items: center; font-size: var(--text-xs); }
.dsc-bar-track { display: block; height: 8px; border-radius: 4px; background: var(--color-surface-well); box-shadow: inset 0 0 0 1px var(--color-line-subtle); overflow: hidden; }
.dsc-bar-fill { display: block; height: 100%; background: var(--color-brand-strong); border-radius: 4px; }
.dsc-bar-value { text-align: right; color: var(--color-ink-secondary); }
.dsc-vcard { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-2) var(--space-3); border: 1px solid var(--color-line-subtle); border-radius: var(--radius-control); }
.dsc-vcard p { margin: 0; }
/* The peek's Fit tab: the one place the fit stands at display size. */
.dsc-fitbig { display: flex; gap: var(--space-4); align-items: flex-start; padding: var(--space-3); border: 1px solid var(--color-line-subtle); border-radius: 10px; background: var(--color-surface-well); }
.dsc-fitbig-n { margin: 0; flex: 0 0 auto; font-family: var(--font-title); font-size: var(--text-3xl); line-height: var(--leading-3xl); font-weight: var(--weight-medium); letter-spacing: -0.01em; }
.dsc-fitbig-n small { display: block; color: var(--color-ink-tertiary); }
.dsc-fitbig p { margin: 0; }

/* ---------- Responsive (decision 0014) ---------- */
@media (max-width: 1024px) {
  .dsc-body, .dsc[data-panel="collapsed"] .dsc-body { grid-template-columns: minmax(0, 1fr); }
  .dsc-panel { border-left: 0; border-top: 1px solid var(--color-line-subtle); border-radius: 0; }
  .dsc-panel-close, .dsc-panel-open { display: none; }
  .dsc[data-panel="collapsed"] .dsc-panel-body, .dsc[data-panel="collapsed"] .dsc-refine, .dsc[data-panel="collapsed"] .dsc-panel-head .t-label { display: block; }
}
@media (max-width: 720px) {
  .dsc-searchwrap, .dsc-chips, .dsc-rhead, .dsc-results { padding-inline: var(--space-4); }
  .dsc-searchbar { flex-wrap: wrap; padding: var(--space-2); }
  .dsc-q { flex-basis: 100%; }
  .dsc-modes { order: 2; }
  .dsc-search-go { order: 3; margin-inline-start: auto; }
  .dsc-frow { grid-template-columns: 1fr; }
  .dsc-arow { flex-wrap: wrap; }
  .dsc-acts { opacity: 1; }
  .dsc-act, .dsc-reason, .dsc-labelbtn { min-height: 32px; }
  .dsc-fitbig { flex-direction: column; gap: var(--space-3); }
}
@media (forced-colors: active) {
  .dsc-card, .dsc-panel, .dsc-reasons, .dsc-vcard { border-color: CanvasText; }
  .dsc-conf, .dsc-decided-dot, .dsc-bar-fill, .dsc-labeldot, .dsc-mem-fill { background: CanvasText; }
  .dsc-ev, .dsc-labelbtn, .dsc-fitbig { border: 1px solid CanvasText; }
  .dsc-stretch { background: Canvas; color: CanvasText; border: 1px solid CanvasText; }
  .dsc-thumb-tag, .dsc-thumb-cap, .dsc-where-evidence { background: Canvas; color: CanvasText; border: 1px solid CanvasText; }
}

/* D5: the peek's Where block — the metro, the confidence and every vote that placed them. */
.dsc-where-block { display: flex; flex-direction: column; gap: var(--space-1); }
.dsc-where-line { margin: 0; display: flex; align-items: center; gap: 5px; flex-wrap: wrap; }
.dsc-where-ev { margin: 0; padding-inline-start: var(--space-4); display: flex; flex-direction: column; gap: 2px; font-size: var(--text-xs); line-height: var(--leading-xs); color: var(--color-ink-secondary); }
.dsc-where-ev > li { text-wrap: pretty; }
.dsc-peek-field { display: flex; flex-direction: column; gap: var(--space-1); min-width: 0; }

/* The /design reference for provenance holds the chips open, so a screenshot shows them. */
.dsc-prov-open .dsc-provwrap .prov-wrap { opacity: 1; }

/* ============================================================ D6: picking, the bulk bar, the survey */

/* The select box sits in the card's top-left corner, opposite the Stretch tag. Its label is for
   assistive technology only — the card beside it is the visible name. */
.dsc-pick { position: absolute; inset-block-start: var(--space-3); inset-inline-start: var(--space-3); z-index: 2; display: block; }
.dsc-pick .checkbox-text {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}
/* Unpicked, the box is quiet until the card is hovered, focused or already picked — the grid is
   read before it is ticked. It stays in the tab order the whole time (nothing hover-only). */
.dsc-pick .checkbox-input { background: var(--color-surface-panel); opacity: 0; transition: opacity var(--duration-fast) var(--easing-standard); }
.dsc-card:hover .dsc-pick .checkbox-input,
.dsc-card:focus-within .dsc-pick .checkbox-input,
.dsc-card[data-focused="true"] .dsc-pick .checkbox-input,
.dsc-pick .checkbox-input:focus-visible,
.dsc-pick .checkbox-input:checked { opacity: 1; }
@media (hover: none) { .dsc-pick .checkbox-input { opacity: 1; } }

/* The bulk form owns no layout: it carries hidden fields and the cards' boxes join it by `form=`. */
.dsc-bulk-form { display: contents; }
.dsc-bulk { margin-block-start: var(--space-4); }
.dsc-bulk-act { display: inline-flex; }
.dsc-bulk-pop { max-width: min(340px, calc(100vw - var(--space-8))); }

/* ---------- Pickers ---------- */
.dsc-picker { display: flex; flex-direction: column; gap: var(--space-2); min-width: 240px; padding: var(--space-2); }
.dsc-picker-title { margin: 0; padding: 0 var(--space-1); }
.dsc-picker-find { width: 100%; }
.dsc-picker-rows { margin: 0; padding: 0; list-style: none; max-height: 220px; overflow-y: auto; overscroll-behavior: contain; }
.dsc-picker-row { width: 100%; border: 0; background: none; font: inherit; text-align: left; cursor: pointer; gap: var(--space-2); }
.dsc-picker-row .t-xs { flex: 0 0 auto; }
.dsc-picker-none { padding: 0 var(--space-1); }
.dsc-picker-new { display: flex; flex-direction: column; gap: var(--space-1); padding: var(--space-2) var(--space-1) var(--space-1); border-top: 1px solid var(--color-line-subtle); }
.dsc-picker-newrow { display: flex; align-items: center; gap: var(--space-2); }
.dsc-picker-newrow .input { flex: 1 1 auto; min-width: 0; }
.dsc-picker-hint { margin: 0; }
.dsc-picker-confirm { min-width: 260px; }
.dsc-picker-confirm p { margin: 0; padding: 0 var(--space-1); }
.dsc-picker-confirm .dsc-picker-newrow { justify-content: flex-end; padding-top: var(--space-1); }

/* ---------- The Blocked gate (invariant 5) ---------- */
.dsc-blocked { margin: var(--space-3) var(--space-5) 0; border-color: var(--color-bad); }
.dsc-blocked-list { margin: var(--space-4) 0 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: var(--space-2); }
.dsc-blocked-row { display: flex; flex-direction: column; gap: 2px; padding: var(--space-2); border: 1px solid var(--color-line-subtle); border-radius: var(--radius-control); background: var(--color-bad-tint); }
.dsc-blocked-form { margin-top: var(--space-4); }

/* ---------- Survey ---------- */
.dsc-survey { display: flex; flex-direction: column; gap: var(--space-3); }
.dsc-survey-head { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; }
.dsc-survey-head h2 { margin: 0; }
.dsc-survey-note { margin: 0; }
.dsc-survey-scroll { overflow-x: auto; overscroll-behavior-x: contain; border: 1px solid var(--color-line-subtle); border-radius: var(--radius-card); background: var(--color-surface-panel); }
.dsc-survey-scroll:focus-visible { outline: 2px solid var(--color-focus); outline-offset: -2px; }
.dsc-survey-table { width: 100%; min-width: max-content; border-collapse: collapse; }
.dsc-survey-corner { width: 128px; min-width: 128px; background: var(--color-surface-well); border-bottom: 1px solid var(--color-line-subtle); }
.dsc-survey-col {
  vertical-align: top; text-align: left; width: 220px; min-width: 200px;
  padding: var(--space-3); border-bottom: 1px solid var(--color-line-default); border-left: 1px solid var(--color-line-subtle);
  font-weight: var(--weight-regular);
}
.dsc-survey-col:focus-visible { outline: 2px solid var(--color-focus); outline-offset: -2px; }
.dsc-survey-who { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.dsc-survey-name { font-size: var(--text-base); line-height: var(--leading-sm); font-weight: var(--weight-medium); color: var(--color-ink); }
.dsc-survey-handle { display: flex; align-items: center; gap: var(--space-1); font-size: var(--text-xs); line-height: var(--leading-xs); color: var(--color-ink-tertiary); }
.dsc-survey-tools { display: flex; align-items: center; gap: var(--space-1); margin-top: var(--space-2); }
.dsc-survey-move, .dsc-survey-remove {
  display: inline-flex; align-items: center; gap: var(--space-1); min-height: 24px; padding: 0 var(--space-1);
  border-radius: 6px; color: var(--color-ink-tertiary); font-size: var(--text-2xs); text-decoration: none;
}
.dsc-survey-move:hover, .dsc-survey-remove:hover { background: var(--color-brand-wash); color: var(--color-ink); text-decoration: none; }
.dsc-survey-remove { margin-inline-start: auto; }
.dsc-survey-rowhead {
  width: 128px; min-width: 128px; text-align: left; vertical-align: top;
  padding: var(--space-3); background: var(--color-surface-well);
  border-bottom: 1px solid var(--color-line-subtle);
  font-size: var(--text-2xs); line-height: var(--leading-2xs); font-weight: var(--weight-medium);
  letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--color-ink-tertiary);
}
.dsc-survey-cell {
  vertical-align: top; padding: var(--space-3); border-bottom: 1px solid var(--color-line-subtle); border-left: 1px solid var(--color-line-subtle);
  font-size: var(--text-sm); line-height: var(--leading-sm); color: var(--color-ink-secondary);
}
.dsc-survey-cell > * { display: block; }
.dsc-survey-stat { display: block; }
.dsc-survey-stat strong { color: var(--color-ink); font-weight: var(--weight-medium); }
.dsc-survey-fit { display: flex; align-items: center; gap: var(--space-2); margin-bottom: 2px; }
.dsc-survey-fit strong { font-family: var(--font-title); font-size: var(--text-lg); line-height: var(--leading-lg); font-weight: var(--weight-medium); }
.dsc-survey-thumbs { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--space-1); }
.dsc-survey-row-links .dsc-survey-cell { display: table-cell; }
.dsc-survey-row-links .btn { margin-inline-end: var(--space-1); }

@media (max-width: 720px) {
  /* The survey keeps its columns; the region scrolls sideways inside itself so the page never does. */
  .dsc-survey-col, .dsc-survey-corner, .dsc-survey-rowhead { width: 160px; min-width: 160px; }
  .dsc-blocked { margin-inline: var(--space-4); }
  .dsc-bulk-pop { max-width: calc(100vw - var(--space-6)); }
}

@media (forced-colors: active) {
  .dsc-survey-scroll, .dsc-survey-col, .dsc-survey-cell, .dsc-survey-rowhead, .dsc-blocked-row { border-color: CanvasText; }
}

/* ---------- Print: the survey is the page (§8 — print flattens bands and drops shadows) ---------- */
@media print {
  .rail, .topbar, .shell-foot, .dsc-panel, .dsc-searchwrap, .dsc-chips, .dsc-rhead, .dt-bulk, .dsc-bulk,
  .toast-region, .dsc-survey-head .pop-wrap, .dsc-survey-tools, .dsc-survey-row-links, .skip-link { display: none !important; }
  .dsc-body, .dsc[data-panel="collapsed"] .dsc-body { grid-template-columns: minmax(0, 1fr); }
  .dsc-results { padding: 0; }
  .dsc-survey-scroll { overflow: visible; border: 0; }
  .dsc-survey-table { width: 100%; min-width: 0; }
  .dsc-survey-row, .dsc-survey-col { break-inside: avoid; page-break-inside: avoid; }
  .dsc-survey-cell, .dsc-survey-rowhead, .dsc-survey-col { border-color: var(--color-line-default); }
}


/* ---- faces/app/discover/scouts.css ---- */
/* Scouts (/app/discover/scouts, D4) — the inbox and the scout page. Layout follows
   docs/prototype/discover.html (.tabs, .sgroup, .srow, .shead, .promise, .progress, .plan/.arow,
   .runlog); the card grid, the label filter and the side panel are Discover's own, so this file
   only adds what the prototype draws beside them. Every value is a token. */

.sct { display: grid; grid-template-columns: minmax(0, 1fr) 320px; align-items: start; flex: 1 1 auto; min-width: 0; }
.sct-narrow { grid-template-columns: minmax(0, 1fr); }
.sct-list { min-width: 0; padding: var(--space-4) var(--space-5) var(--space-6); display: flex; flex-direction: column; gap: var(--space-4); }
.sct-lede { margin: 0; }
.sct-h { margin: 0; }
.sct-sub { margin: 0; max-inline-size: 60ch; }
.sct-crumb { margin: 0; }
/* The inbox has no side panel, so it keeps its own measure rather than running the sheet's width. */
.sct-inbox { max-inline-size: 72rem; }

/* ---------- The brand square ----------
   The client's colour is a mark, never a text background: a kit mark rides its own white tile, and
   a brand with no mark gets its initial in ink inside a ring in the brand colour (§5.7). That keeps
   every text pair one the contrast check already measures. */
.sct-square {
  display: grid; place-items: center; flex: 0 0 auto; overflow: hidden;
  background: var(--color-surface-well);
  box-shadow: inset 0 0 0 2px var(--tenant-brand, var(--color-line-subtle));
}
.sct-square-20 { inline-size: 20px; block-size: 20px; border-radius: 5px; }
.sct-square-40 { inline-size: 40px; block-size: 40px; border-radius: 9px; }
.sct-square img { inline-size: 100%; block-size: 100%; object-fit: contain; background: var(--color-surface-panel); }
.sct-square-initial { font-size: var(--text-xs); font-weight: var(--weight-title); color: var(--color-ink-secondary); }
.sct-square-40 .sct-square-initial { font-size: var(--text-md); }

/* ---------- The inbox ---------- */
.sct-group { display: flex; flex-direction: column; gap: var(--space-2); }
.sct-group-h { display: flex; align-items: center; gap: var(--space-2); margin: 0; color: var(--color-ink-tertiary); }
.sct-group-n { font-weight: var(--weight-regular); letter-spacing: 0; text-transform: none; }
.sct-rows { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); }
.sct-row {
  display: grid; grid-template-columns: 20px minmax(0, 1fr) auto auto; gap: var(--space-3);
  align-items: center; padding: var(--space-3); text-decoration: none; color: inherit;
  border: 1px solid var(--color-line-subtle); border-radius: 10px; background: var(--color-surface-panel);
  transition: border-color var(--duration-fast) var(--easing-standard);
}
.sct-row:hover { border-color: var(--color-line-default); background: var(--color-surface-well); }
.sct-row:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }
.sct-row-t { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.sct-row-name { font-size: var(--text-base); line-height: var(--leading-base); font-weight: var(--weight-strong); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sct-row-meta { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sct-row-batch { text-align: end; color: var(--color-ink-secondary); white-space: nowrap; }

/* ---------- The create form ---------- */
.sct-form { display: flex; flex-direction: column; gap: var(--space-4); max-inline-size: 64ch; }
.sct-frow { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-3); }

/* ---------- The scout head ---------- */
.sct-head { display: flex; align-items: flex-start; gap: var(--space-3); }
.sct-head-name { margin: 0; }
.sct-head-meta { margin: 2px 0 0; }
.sct-head-acts { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }

/* The calibration pill: n segments and the count in words (§9 Status). */
.sct-progress {
  display: inline-flex; align-items: center; gap: var(--space-2);
  block-size: 22px; padding: 0 var(--space-2); border-radius: 11px;
  background: var(--color-info-tint); color: var(--color-info);
  font-size: var(--text-xs); font-weight: var(--weight-medium);
}
.sct-progress-segs { display: inline-flex; gap: 2px; }
.sct-progress-segs i { inline-size: 10px; block-size: 6px; border-radius: 2px; background: var(--color-line-default); }
.sct-progress-segs i.on { background: var(--color-info); }

/* ---------- Notes, promises, calibration ---------- */
.sct-note, .sct-calnote, .sct-start, .sct-attention {
  display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap;
  padding: var(--space-3); border: 1px solid var(--color-line-subtle); border-radius: 10px; background: var(--color-surface-well);
}
.sct-note p, .sct-calnote p, .sct-start p { margin: 0; }
/* Attention is a marker beside the well, not a tinted ground under text: every text pair on this
   screen stays one src/ui/token-pairs.ts already measures (invariant 9). */
.sct-attention { display: block; border-color: var(--color-line-default); border-inline-start: 3px solid var(--color-warn); padding-inline-start: calc(var(--space-3) - 2px); }
.sct-attention h3 { margin: 0 0 var(--space-1); color: var(--color-warn); }
.sct-attention p { margin: 0 0 var(--space-2); }

.sct-promises { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-2); }
.sct-promise {
  display: flex; flex-direction: column; gap: 2px;
  padding: var(--space-3); border: 1px solid var(--color-line-subtle); border-radius: 8px;
  background: var(--color-surface-well); font-size: var(--text-xs); line-height: var(--leading-xs);
}
.sct-promise strong { font-weight: var(--weight-strong); color: var(--color-ink); }

/* ---------- Questions ---------- */
.sct-questions, .sct-exclusions { display: flex; flex-direction: column; gap: var(--space-2); }
.sct-qlist { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-3); }
.sct-q p { margin: 0 0 var(--space-1); }
.sct-answer { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
.sct-answer .input { flex: 1 1 22ch; min-inline-size: 0; }

/* ---------- The plan ---------- */
.sct-plan { border: 1px solid var(--color-line-subtle); border-radius: 10px; overflow: hidden; }
.sct-plan-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); flex-wrap: wrap; padding: var(--space-2) var(--space-3); background: var(--color-surface-well); border-bottom: 1px solid var(--color-line-subtle); }
.sct-plan-head p { margin: 0; }
.sct-arows { list-style: none; margin: 0; padding: 0; }
.sct-arow { border-bottom: 1px solid var(--color-line-subtle); }
.sct-arow:last-child { border-bottom: 0; }
.sct-arow-form { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-2) var(--space-3); flex-wrap: wrap; }
.sct-arow-form p { margin: 0; }
.sct-arow-name { font-weight: var(--weight-strong); }
.sct-arow-counts { white-space: nowrap; }
.sct-exclusions { padding: var(--space-3); border-top: 1px solid var(--color-line-subtle); }
.sct-exclusions h3 { margin: 0; }
.sct-exlist { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-1); }
.sct-ex { display: flex; align-items: center; gap: var(--space-2); }

/* ---------- The batch head ---------- */
.sct-bhead { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; }
.sct-bhead p { margin: 0; }

/* ---------- The run log ---------- */
.sct-runlog { border: 1px solid var(--color-line-subtle); border-radius: 10px; background: var(--color-surface-panel); }
.sct-runlog summary { display: flex; justify-content: space-between; gap: var(--space-3); padding: var(--space-2) var(--space-3); cursor: pointer; font-size: var(--text-base); font-weight: var(--weight-medium); list-style: none; }
.sct-runlog summary::-webkit-details-marker { display: none; }
.sct-runlog summary:focus-visible { outline: 2px solid var(--color-focus); outline-offset: -2px; border-radius: 10px; }
.sct-rl { list-style: none; margin: 0; padding: 0 var(--space-3) var(--space-3); display: flex; flex-direction: column; gap: var(--space-2); }
.sct-rl-row { display: grid; grid-template-columns: 10ch minmax(0, 1fr) auto auto; gap: var(--space-1) var(--space-3); align-items: baseline; }
.sct-rl-empty { margin: 0; padding: 0 var(--space-3) var(--space-3); }

/* ---------- Activity ---------- */
.sct-activity { display: flex; flex-direction: column; gap: var(--space-2); }
.sct-activity-head { display: flex; align-items: center; gap: var(--space-2); }
.sct-activity-head h3 { margin: 0; }

/* ---------- The side panel ---------- */
.sct-panel { position: sticky; top: 0; }
.sct-notify { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; margin-top: var(--space-2); }

/* ---------- Responsive (decision 0014) ---------- */
@media (max-width: 1024px) {
  .sct { grid-template-columns: minmax(0, 1fr); }
  .sct-panel { position: static; border-left: 0; border-top: 1px solid var(--color-line-subtle); border-radius: 0; }
}
@media (max-width: 720px) {
  .sct-list { padding-inline: var(--space-4); }
  .sct-promises { grid-template-columns: minmax(0, 1fr); }
  .sct-frow { grid-template-columns: minmax(0, 1fr); }
  .sct-row { grid-template-columns: 20px minmax(0, 1fr); row-gap: var(--space-2); }
  .sct-row-batch { text-align: start; grid-column: 2; }
  .sct-rl-row { grid-template-columns: minmax(0, 1fr); }
  .sct-arow-form { align-items: flex-start; }
}
@media (forced-colors: active) {
  .sct-row, .sct-plan, .sct-runlog, .sct-promise, .sct-note, .sct-calnote, .sct-start, .sct-attention { border: 1px solid CanvasText; }
  .sct-progress { border: 1px solid CanvasText; }
  .sct-progress-segs i { background: Canvas; border: 1px solid CanvasText; }
  .sct-progress-segs i.on { background: CanvasText; }
  .sct-square { border: 1px solid CanvasText; }
}


/* ---- faces/app/discover/seed-actions.css ---- */
/* "Search similar" and "Start scout from …" (D6). The lens chooser is a <details> whose summary
   wears the secondary button's own classes, so there is one button shape in the product and no
   script behind the menu. Every value is a token. */

.seed-menu { position: relative; display: inline-block; }
.seed-menu > summary { list-style: none; cursor: pointer; }
.seed-menu > summary::-webkit-details-marker { display: none; }
.seed-menu > summary:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }
.seed-menu[open] > summary > svg:last-child { transform: rotate(180deg); }

/* The panel is absolutely positioned, so a closed <details> does not take it out of layout on its
   own — it is taken out here, or an invisible menu would still crowd what is under it. */
.seed-menu:not([open]) > .seed-menu-panel { display: none; }
.seed-menu-panel {
  position: absolute; z-index: 20; inset-inline-end: 0; margin-block-start: var(--space-1);
  min-inline-size: 15rem; padding: var(--space-2);
  background: var(--color-surface-panel);
  border: 1px solid var(--color-line-subtle); border-radius: 10px;
  box-shadow: var(--shadow-2);
}
.seed-menu-lede { margin: 0 0 var(--space-1); padding-inline: var(--space-2); }
.seed-menu-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.seed-menu-item {
  display: flex; flex-direction: column; gap: 1px;
  padding: var(--space-2); border-radius: 8px;
  text-decoration: none; color: inherit;
}
.seed-menu-item:hover { background: var(--color-surface-well); }
.seed-menu-item:focus-visible { outline: 2px solid var(--color-focus); outline-offset: -2px; }
.seed-menu-name { font-size: var(--text-sm); font-weight: var(--weight-medium); }
.seed-menu-hint { line-height: var(--leading-xs); }

.seed-scout { display: inline-flex; margin: 0; }

@media (max-width: 640px) {
  .seed-menu-panel { position: static; min-inline-size: 0; inline-size: 100%; }
}


/* ---- faces/app/import/import.css ---- */
/* Bulk import — DESIGN.md §9.2 (tables), §9.5 (forms), §9.6. Tokens only. */
.imp-page { padding-block-end: var(--space-12); }
.imp-form { margin: 0; }

/* Step indicator: the subheader row of the shell. Never colour alone — the current step
   carries aria-current and a heavier label, the finished ones a rule and a check-weight number. */
.imp-steps { display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-4); padding-block: var(--space-3); margin: 0; }
.imp-step { display: inline-flex; align-items: center; gap: var(--space-2); color: var(--color-ink-tertiary); }
.imp-step + .imp-step::before { content: ""; width: var(--space-6); height: 1px; background: var(--color-line-default); margin-inline-end: var(--space-2); }
.imp-step-number { display: inline-flex; align-items: center; justify-content: center; width: 20px; height: 20px; border-radius: var(--radius-pill); border: 1px solid var(--color-line-default); font-variant-numeric: tabular-nums; }
.imp-step-done { color: var(--color-ink-secondary); }
.imp-step-done .imp-step-number { border-color: var(--color-line-interactive); }
.imp-step-current { color: var(--color-ink); }
.imp-step-current .imp-step-label { font-weight: var(--weight-medium); }
.imp-step-current .imp-step-number { border-color: var(--nav-active-marker); background: var(--color-brand-wash); color: var(--color-ink); }

/* Upload */
.imp-file { height: auto; padding: var(--space-2) var(--space-3); cursor: pointer; }
.imp-file::file-selector-button { margin-inline-end: var(--space-3); padding: var(--space-1) var(--space-3); border: 1px solid var(--color-line-interactive); border-radius: var(--radius-control); background: var(--color-surface-well); color: var(--color-ink); cursor: pointer; }
.imp-file::file-selector-button:hover { background: var(--color-surface-panel); }
.imp-or { color: var(--color-ink-tertiary); text-transform: uppercase; letter-spacing: var(--tracking-label); }
.imp-problem { max-width: var(--measure-prose); }

/* Column matching */
.imp-fieldset { border: 0; padding: 0; margin: 0; display: flex; flex-direction: column; gap: var(--space-3); }
.imp-fieldset + .imp-fieldset { padding-block-start: var(--space-4); border-block-start: 1px solid var(--color-line-subtle); }
.imp-fieldset legend { padding: 0; margin-block-end: var(--space-2); }
.imp-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: var(--space-4); align-items: start; }
.imp-grid .field-help { max-width: 40ch; }

.imp-unused { margin: 0; padding: 0; }
.imp-unused-row { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-2); }
.imp-unused-header { min-width: 16ch; }
.imp-unused-reason::before { content: "— "; }
.imp-note { margin-block-start: var(--space-3); }

/* Preview and result */
.imp-counts { display: flex; flex-wrap: wrap; gap: var(--space-6); margin: 0; }
.imp-count { display: flex; flex-direction: column; gap: var(--space-1); }
.imp-count dd { margin: 0; font-variant-numeric: tabular-nums; }
/* The preview scrolls in its own region (0014 pattern 2): a keyboard can reach it, and it is the
   containing block for any visually hidden label inside it, so nothing widens the page. */
.imp-table { --dt-max-height: 60dvh; border: 0; border-radius: 0; position: relative; }
.imp-table:focus-visible { outline: 2px solid var(--color-focus); outline-offset: -2px; }
.imp-outcome { display: flex; align-items: center; gap: var(--space-2); white-space: normal; max-width: 44ch; }
.imp-note-link { color: var(--color-ink-secondary); }
.imp-detail { white-space: normal; max-width: 48ch; }
.imp-more { padding: var(--space-3) var(--space-4); border-block-start: 1px solid var(--color-line-subtle); }

.imp-handles { display: inline-flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; }
.imp-handle { display: inline-flex; align-items: center; gap: var(--space-1); }
/* Brand guide: a handle is NHG Text in tertiary ink, never a mono face. */
.imp-handle-text { font-family: var(--font-ui); }

/* Phone (0014 pattern 5): one column, the step's action full width at the foot of its form. */
@media (max-width: 720px) {
  .imp-steps { gap: var(--space-2); }
  .imp-step + .imp-step::before { width: var(--space-3); }
  .imp-counts { gap: var(--space-4); }
  .imp-grid { grid-template-columns: minmax(0, 1fr); }
  .imp-page form > .row, .imp-page form.row { flex-wrap: wrap; }
  .imp-page form > .row > .btn, .imp-page form.row > .btn { flex: 1 1 100%; min-height: var(--button-height-touch); }
  .imp-unused-header { min-width: 0; }
}


/* ---- faces/app/lists/lists.css ---- */
/* Lists and the list page (M8) — Operate mode: calm shell, no brand imagery, the data is the
   design (DESIGN.md §9.2, §9.6; brand guide §9). Tokens only. */

.lists, .list-page { display: flex; flex-direction: column; gap: var(--space-6); }

.lists-search { display: flex; align-items: center; gap: var(--space-2); }
.lists-name { display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
/* §9: table rows are 40 comfortable. A two-line first cell has to use the DataTable's own
   two-line metrics — two 16px lines, the second at 12px — or the row grows past 40. */
.lists-name-text { display: flex; flex-direction: column; min-width: 0; line-height: var(--leading-2xs); }
/* The cell inherits the table's nowrap; a long name wraps inside its column (0014 pattern 1)
   rather than running into the next one. Only a long name costs the row a second line. */
.lists-name-link { font-weight: var(--weight-medium); white-space: normal; overflow-wrap: anywhere; line-height: var(--leading-2xs); }
.lists-name-text > .ink-3 { font-size: var(--text-xs); line-height: var(--leading-2xs); }
.lists-desc { display: block; max-width: 280px; }
.lists-tags { display: flex; align-items: center; gap: var(--space-1); flex-wrap: wrap; }
.lists-published { display: flex; align-items: center; gap: var(--space-2); }

/* ---- one list ---- */
.list-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-6); flex-wrap: wrap; }
.list-head-text { display: flex; flex-direction: column; gap: var(--space-2); max-width: var(--measure-prose); }
.list-head-desc { max-width: var(--measure-prose); }
.list-head-actions { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }

.list-member-name { display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
.list-top { display: flex; align-items: center; gap: var(--space-2); justify-content: flex-end; }
.list-comment { display: block; max-width: 240px; }
.list-row-actions { display: flex; align-items: center; gap: var(--space-1); justify-content: flex-end; }
.list-row-actions form { display: flex; }

.list-panels { display: grid; grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); gap: var(--space-4); align-items: start; }
.list-panels > * { min-width: 0; }

.list-versions { display: flex; flex-direction: column; gap: var(--space-4); }
.list-version { display: flex; flex-direction: column; gap: var(--space-2); padding-bottom: var(--space-4); border-bottom: 1px solid var(--color-line-subtle); align-items: flex-start; }
.list-version:last-child { border-bottom: 0; padding-bottom: 0; }
.list-version-head { display: flex; align-items: center; gap: var(--space-2); }

.list-copy { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
.list-copy-value { font-family: var(--font-code); font-size: var(--text-xs); line-height: var(--leading-xs); color: var(--color-ink-secondary); overflow-wrap: anywhere; word-break: break-all; }

.list-unmatched-items { display: flex; flex-wrap: wrap; gap: var(--space-2); margin: var(--space-3) 0; }
.list-unmatched-items code { font-family: var(--font-code); font-size: var(--text-xs); line-height: var(--leading-xs); padding: 2px var(--space-2); background: var(--color-surface-well); border-radius: var(--radius-control); }

/* ---- dialogs ---- */
.list-picker-search { display: flex; align-items: center; gap: var(--space-2); margin-bottom: var(--space-3); }
.list-picks { display: flex; flex-direction: column; gap: var(--space-2); max-height: 320px; overflow-y: auto; }
.list-pick { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); padding: var(--space-2); border-radius: var(--radius-control); }
.list-pick:hover { background: var(--color-surface-well); }

.list-publish-members { max-height: 260px; overflow-y: auto; }

/* Narrow and phone (0014): the two panels stack. */
@media (max-width: 1024px) {
  .list-panels { grid-template-columns: minmax(0, 1fr); }
}

/* Phone (0014): the header text and its actions stack; the actions share the row width; the
   picker's search is one field with its button beside it, then the picks one per line. */
@media (max-width: 720px) {
  .list-head { flex-direction: column; gap: var(--space-4); }
  .list-head-text, .list-head-desc { max-width: none; }
  .list-head-actions { width: 100%; }
  .list-head-actions > .btn { flex: 1 1 calc(50% - var(--space-2)); }
  .lists-search { flex-wrap: nowrap; }
  .lists-search > .input-group { flex: 1 1 auto; min-width: 7rem; }
  .lists-search > .btn[type="submit"] { display: none; }
  .list-picker-search > .input-group { flex: 1 1 auto; min-width: 0; }
  .list-pick { flex-wrap: wrap; }
  .list-copy { align-items: flex-start; }
  .list-copy-value { min-width: 0; }
}

@media (forced-colors: active) {
  .list-version { border-bottom-color: CanvasText; }
}

/* The star is a one-button form, so it works with no JavaScript. Filled means starred; the
   button's accessible name says which way pressing it goes. */
.lists-star { display: flex; }
.lists-star-on { color: var(--color-brand); }


/* ---- faces/app/messages/messages.css ---- */
/* Messaging screens — DESIGN.md §9.5 (forms), §9.7 (creator record). Tokens only. */

.msg-page { padding-block-end: var(--space-12); max-width: var(--layout-evidence); }
.msg-stack-3 { display: flex; flex-direction: column; gap: var(--space-3); }

/* ---- Creator record header (minimal: the full one lives with the creator record) */
.msg-subheader { display: flex; flex-direction: column; gap: var(--space-3); }
.msg-record-head { display: flex; align-items: center; gap: var(--space-3); }
.msg-record-id { display: flex; flex-direction: column; gap: var(--space-1); min-width: 0; }

/* ---- Composer */
.msg-composer-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--space-4); align-items: start; }
.msg-composer-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); }
.msg-blocked { color: var(--color-bad); margin: 0; }

.msg-preview { padding: var(--space-4); border: 1px solid var(--color-line-default); border-radius: var(--radius-card); background: var(--color-surface-well); }
.msg-preview-subject { color: var(--color-ink); margin: 0; }
.msg-preview-body { white-space: pre-wrap; margin: 0; }
.msg-preview-note { margin: 0; }

/* ---- Threads */
.msg-thread-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-2) var(--space-3); }
.msg-thread-head h3 { margin: 0; }
.msg-thread-head p { margin: 0; }

.msg-card-head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); margin-block-end: var(--space-2); }
.msg-direction { color: var(--color-ink-tertiary); text-transform: uppercase; letter-spacing: var(--tracking-label); }
.msg-who { min-width: 0; overflow-wrap: anywhere; }
.msg-when { margin-inline-start: auto; }
.msg-subject { margin: 0 0 var(--space-1); color: var(--color-ink); }
.msg-body { margin: 0; white-space: pre-wrap; overflow-wrap: anywhere; }
.msg-error { margin: var(--space-2) 0 0; color: var(--color-bad); }

/* An inbound message is the one that needs an answer, so it carries the brand marker. */
.msg-card-in { border-inline-start: 2px solid var(--color-brand); }
.msg-card-out { border-inline-start: 2px solid var(--color-line-default); }

/* ---- Inbox */
.msg-inbox { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-1); }
.msg-inbox-row {
  display: grid;
  grid-template-columns: auto minmax(8rem, 12rem) minmax(0, 1fr) auto auto;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3);
  border: 1px solid var(--color-line-default);
  border-radius: var(--radius-card);
  background: var(--color-surface-panel);
  color: var(--color-ink);
  text-decoration: none;
}
.msg-inbox-row:hover { background: var(--color-surface-well); }
.msg-inbox-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.msg-inbox-subject { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.msg-inbox-when { white-space: nowrap; }

/* ---- Bulk composer and results */
.msg-recipients { list-style: none; margin: var(--space-3) 0 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); }
.msg-recipient { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); }
/* An address or handle has no break opportunity of its own (0014 pattern 1). */
.msg-recipient > *, .msg-result > *, .msg-record-id > * { min-width: 0; overflow-wrap: anywhere; }

.msg-results { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); }
.msg-result { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); padding-block: var(--space-2); border-block-end: 1px solid var(--color-line-subtle); }

/* Phone (0014): the composer is one column with its submit full width; an inbox row is the
   avatar beside a stack of name, subject, status and time — every text cell in the fluid column,
   never in the avatar's auto column where a long subject would widen the page. */
@media (max-width: 720px) {
  .msg-composer-grid { grid-template-columns: 1fr; }
  .msg-composer-actions > .btn { flex: 1 1 100%; min-height: var(--button-height-touch); }
  .msg-inbox-row { grid-template-columns: auto minmax(0, 1fr); grid-auto-rows: auto; row-gap: var(--space-1); align-items: start; }
  .msg-inbox-row > :first-child { grid-column: 1; grid-row: 1 / span 4; }
  .msg-inbox-row > :not(:first-child) { grid-column: 2; min-width: 0; }
  .msg-inbox-when { justify-self: start; }
  .msg-when { margin-inline-start: 0; }
}


/* ---- faces/app/reports/reports.css ---- */
/* /app/reports — the campaign report index, the ops catalogue and one ops report.
   DESIGN.md §9.2 (tables). Tokens only (invariant 1): no colour, font or type size is named here. */

.rep { padding-block-end: var(--space-12); }
.rep-section { scroll-margin-block-start: var(--space-8); }
.rep-section > .row { align-items: baseline; gap: var(--space-3); }
.rep-note { max-width: var(--measure-prose); }
.rep-strong { font-weight: var(--weight-medium); }

/* These tables carry sentences (a note, an enrichment error), so rows grow instead of truncating. */
.rep-table { border: 1px solid var(--color-line-default); border-radius: var(--radius-card); }
.rep-table .dt-td { height: auto; vertical-align: top; padding-block: var(--space-3); }
.rep-td-wrap { white-space: normal; max-width: 52ch; }

/* The eight ops reports as cards on the index, so the names are readable before the counts load. */
.rep-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: var(--space-4); margin: 0; padding: 0; list-style: none; }
.rep-card { height: 100%; }
.rep-card .card-body { display: flex; flex-direction: column; gap: var(--space-1); }

/* The picker: which ops report is open, as a row of chips that are links. */
.rep-picker { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.rep-picker-on { background: var(--color-brand-wash); border-color: var(--color-brand); font-weight: var(--weight-medium); }

/* Filters. Every choice is a link, so the whole state of a report is its URL — <details> keeps
   that true with JavaScript off, and the menu closes on navigation because the page reloads. */
.rep-filters { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin-block-end: var(--space-3); }
.rep-filter { position: relative; }
.rep-filter-summary { cursor: pointer; list-style: none; }
.rep-filter-summary::-webkit-details-marker { display: none; }
.rep-filter-summary:focus-visible { outline: 2px solid var(--color-focus); outline-offset: var(--space-1); }
.rep-filter[open] > .rep-filter-summary { border-color: var(--color-brand); }
.rep-filter-menu {
  position: absolute; z-index: 30; inset-inline-start: 0; min-width: 14rem; max-height: 20rem; overflow-y: auto;
  margin: var(--space-1) 0 0; padding: var(--space-1); list-style: none;
  background: var(--color-surface-overlay); border: 1px solid var(--color-line-default); border-radius: var(--radius-card); box-shadow: var(--shadow-2);
}
.rep-filter-menu a { display: block; padding: var(--space-1) var(--space-2); border-radius: var(--radius-control); color: var(--color-ink); text-decoration: none; }
.rep-filter-menu a:hover { background: var(--color-surface-well); }
.rep-filter-menu a[aria-current='true'] { background: var(--color-brand-wash); font-weight: var(--weight-medium); }
.rep-clear { color: var(--color-ink-secondary); }

/* Cells. */
.rep-platform { display: inline-flex; align-items: center; gap: var(--space-1); }
.rep-handle { color: var(--color-ink-tertiary); }

/* Phone (0014): one card per row; a filter menu never leaves a 320 viewport. */
@media (max-width: 720px) {
  .rep-cards { grid-template-columns: minmax(0, 1fr); }
  .rep-filter-menu { max-inline-size: calc(100vw - var(--space-8)); }
  .rep-section > .row > .right { margin-inline-start: 0; }
}


/* ---- faces/app/search/search.css ---- */
/* Global search results — DESIGN.md §9.1, §9.6. Tokens only.
   These rules dress both renderings: the fragment inside the ⌘K dialog (whose chrome lives in
   src/ui/layout/app-shell.css) and the "see all results" page. */

.search-results-inner { padding-block: var(--space-2); }
/* Divs, not a list: ARIA forbids role="group" on an li, and an anchor cannot sit inside a ul.
   The listbox/group/option roles carry the structure instead. */
.search-group + .search-group { margin-block-start: var(--space-2); padding-block-start: var(--space-2); border-block-start: 1px solid var(--color-line-subtle); }
.search-group-title { padding: var(--space-1) var(--space-4); margin: 0; }

.search-option { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-2) var(--space-4); min-height: 40px; text-decoration: none; color: var(--color-ink); cursor: pointer; }
.search-option:hover { background: var(--color-surface-well); }
/* aria-activedescendant moves this, not focus — so it has to read as strongly as a focus ring. */
.search-option[aria-selected="true"] { background: var(--color-brand-wash); box-shadow: inset 2px 0 0 var(--nav-active-marker); }
.search-option:focus-visible { outline: 2px solid var(--color-focus); outline-offset: -2px; }
.search-option-text { display: flex; flex-direction: column; min-width: 0; line-height: var(--leading-xs); gap: 2px; }
.search-option-title { font-weight: var(--weight-medium); }
/* Brand guide §6: a handle is NHG Text in tertiary ink. Kindling has no mono face. */
.search-option-meta { display: inline-flex; align-items: center; gap: var(--space-1); font-family: var(--font-ui); }

.search-note, .search-empty { padding: var(--space-3) var(--space-4); margin: 0; }
.search-empty { color: var(--color-ink-secondary); }
.search-more { padding: var(--space-2) var(--space-4) var(--space-1); margin: 0; }

/* The full page */
.search-page { padding-block-end: var(--space-12); max-width: var(--measure-drawer); }
.search-page-form { display: flex; align-items: flex-end; gap: var(--space-3); flex-wrap: wrap; }
.search-page-form .field { flex: 1 1 320px; min-width: 0; }
.search-page-list { margin: 0; padding: 0; border: 1px solid var(--color-line-default); border-radius: var(--radius-card); background: var(--color-surface-panel); overflow: hidden; }
.search-page-list li + li .search-option-page { border-block-start: 1px solid var(--color-line-subtle); }
.search-option-page { min-height: 48px; }

@media (forced-colors: active) {
  .search-option[aria-selected="true"] { outline: 2px solid Highlight; outline-offset: -2px; }
}


/* ---- faces/app/settings/brands.css ---- */
/* Settings → Brands (DESIGN 1.4 §5.7). Operate mode: the screen itself is Campfire's, quiet and
   dense. The only colour on it belongs to the client, and it appears where a client would see it
   — inside the preview. Tokens only; the `--tenant-*` properties come from the server. */

.bk-list { display: flex; flex-direction: column; border: 1px solid var(--color-line-default); border-radius: var(--radius-card); background: var(--color-surface-panel); }
.bk-row { display: flex; align-items: center; gap: var(--space-4); padding: var(--space-3) var(--space-4); border-bottom: 1px solid var(--color-line-subtle); }
.bk-row:last-child { border-bottom: 0; }
.bk-row-facts { flex: 1 1 auto; min-inline-size: 0; }
.bk-row-edit { flex: 0 0 auto; }

.bk-columns { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--space-5); align-items: start; }
.bk-actions { display: flex; align-items: center; gap: var(--space-4); margin-top: var(--space-5); flex-wrap: wrap; }

/* Colour: the picker and the hex sit on one row, because they are one value. */
.bk-color { display: flex; align-items: center; gap: var(--space-2); }
.bk-swatch-input {
  inline-size: 36px; block-size: 36px; flex: 0 0 auto; padding: 2px;
  border: 1px solid var(--color-line-interactive); border-radius: var(--radius-control);
  background: var(--color-surface-panel); cursor: pointer;
}
.bk-hex { max-inline-size: 12ch; font-variant-numeric: tabular-nums; text-transform: uppercase; }

.bk-uploads { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--space-4); }
.bk-file { font-size: var(--text-sm); line-height: var(--leading-sm); color: var(--color-ink-secondary); max-inline-size: 100%; }
.bk-file::file-selector-button {
  margin-inline-end: var(--space-2); block-size: 28px; padding: 0 var(--space-3);
  border: 1px solid var(--color-line-interactive); border-radius: var(--radius-control);
  background: var(--color-surface-panel); color: var(--color-ink); font: inherit; cursor: pointer;
}
.bk-remove { display: inline-flex; align-items: center; gap: var(--space-2); color: var(--color-ink-secondary); }

/* The preview is the only part of the screen that carries the client's colour. */
.bk-preview .band { padding: var(--space-5); }
.bk-preview .band-title { font-size: var(--text-2xl); line-height: var(--leading-2xl); }
.bk-accent { color: var(--tenant-ink, var(--color-brand-strong)); font-weight: var(--weight-strong); letter-spacing: var(--tracking-label); }
.bk-tint { background: var(--tenant-tint, var(--color-brand-tint)); border-radius: var(--radius-control); padding: var(--space-2) var(--space-3); }

.bk-grounds { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-3); }
.bk-ground { display: flex; flex-direction: column; gap: var(--space-2); }
.bk-ground-label { color: var(--color-ink-tertiary); }
/* The 160×40 box from §5.7, on each of the two grounds a logo will ever sit on. The dark one is
   the app's own dark ground, which is why it is the one primitive this file names. */
.bk-ground-box {
  display: flex; align-items: center; justify-content: center;
  block-size: 56px; padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-line-default); border-radius: var(--radius-control);
  background: var(--color-surface-panel); color: var(--color-ink-tertiary);
  font-size: var(--text-xs); line-height: var(--leading-xs);
}
.bk-ground[data-tone="dark"] .bk-ground-box { background: var(--primitive-dark-ground); border-color: var(--primitive-dark-line); color: var(--primitive-dark-ink-3); }
.bk-ground-box img { display: block; max-block-size: 40px; max-inline-size: 160px; block-size: auto; inline-size: auto; object-fit: contain; }

.bk-derived { display: flex; flex-direction: column; gap: var(--space-3); }
.bk-derived-row { display: grid; grid-template-columns: 140px minmax(0, 1fr); gap: var(--space-3); align-items: baseline; }
.bk-derived-value { display: inline-flex; align-items: center; gap: var(--space-2); font-weight: var(--weight-medium); }
.bk-derived-note { display: block; margin-top: var(--space-1); }
.bk-swatch { inline-size: 14px; block-size: 14px; border-radius: var(--radius-control); border: 1px solid var(--color-line-default); }

@media (max-width: 1100px) {
  .bk-columns { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 720px) {
  .bk-row { flex-wrap: wrap; }
  .bk-row-edit { flex: 1 1 100%; }
  .bk-row-edit .btn { width: 100%; min-height: var(--button-height-coarse); }
  .bk-grounds { grid-template-columns: 1fr; }
  .bk-uploads { grid-template-columns: minmax(0, 1fr); }
  .bk-derived-row { grid-template-columns: minmax(0, 1fr); }
  .bk-actions { flex-direction: column; align-items: stretch; }
  .bk-actions .btn { width: 100%; min-height: var(--button-height-coarse); }
  .bk-hex { max-inline-size: none; flex: 1 1 auto; }
}

@media (forced-colors: active) {
  .bk-list, .bk-ground-box, .bk-swatch { border-color: CanvasText; }
}

/* Reference photos (D3): what the brand looks like in the world, as thumbnails with a remove box. */
.bk-refs { display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: var(--space-3); margin: 0; padding: 0; list-style: none; }
.bk-ref { display: flex; flex-direction: column; gap: var(--space-1); min-width: 0; }
.bk-ref-box {
  display: block; aspect-ratio: 4 / 3; overflow: hidden;
  border: 1px solid var(--color-line-subtle); border-radius: var(--radius-control);
  background: var(--color-surface-well);
}
.bk-ref-box img { width: 100%; height: 100%; object-fit: cover; display: block; }
@media (forced-colors: active) {
  .bk-ref-box { border-color: CanvasText; }
}

/* Details (name, short name, client, Slack) — the create card on the list and the edit card on the brand. */
.bk-details-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--space-4); }


/* ---- faces/app/settings/contracts.css ---- */
/* Settings → Contracts (M7). Tokens only (invariant 1). */

.sc-brands,
.sc-fields,
.sc-preview {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.sc-brands { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); }
.sc-brand { min-width: 0; }

/* Each field: its label and help on the left, the key Kindling sends it under on the right. */
.sc-field {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: start;
  gap: var(--space-3);
  padding-bottom: var(--space-3);
  border-bottom: 1px solid var(--color-line-subtle);
}
.sc-field:last-child { border-bottom: 0; padding-bottom: 0; }
.sc-field-key { white-space: nowrap; padding-top: var(--space-6); }

/* The preview reads as three columns on a wide screen and stacks below it. */
.sc-preview-row {
  display: grid;
  grid-template-columns: minmax(0, 12rem) minmax(0, 12rem) minmax(0, 1fr);
  gap: var(--space-3);
  align-items: baseline;
  padding-bottom: var(--space-2);
  border-bottom: 1px solid var(--color-line-subtle);
}
.sc-preview-row:last-child { border-bottom: 0; padding-bottom: 0; }
.sc-preview-label { align-self: start; }
.sc-preview-tab { overflow-wrap: anywhere; }
/* Deliverables arrive as one line per requirement; the agreement keeps them that way. */
.sc-preview-value { white-space: pre-line; overflow-wrap: anywhere; }

@media (max-width: 720px) {
  .sc-brands { grid-template-columns: minmax(0, 1fr); }
  .sc-field { grid-template-columns: minmax(0, 1fr); }
  .sc-field-key { padding-top: 0; white-space: normal; overflow-wrap: anywhere; }
  .sc-preview-row { grid-template-columns: minmax(0, 1fr); gap: var(--space-1); }
}


/* ---- faces/app/settings/discovery-settings.css ---- */
/* Settings → Discovery (D5): the credit ledger's budget line, the six-month table, the per-source
   kill switch row. Tokens only; the bar takes no colour from being over budget — the number says
   that, and a red bar would make a routine month look like an incident. */

.set-budget { display: flex; flex-direction: column; gap: var(--space-1); }
.set-budget-track {
  block-size: 8px; inline-size: 100%; border-radius: var(--radius-pill);
  background: var(--color-surface-well); box-shadow: inset 0 0 0 1px var(--color-line-subtle);
  overflow: hidden;
}
.set-budget-fill { display: block; block-size: 100%; background: var(--color-chart-1); }
.set-budget-save { display: flex; align-items: flex-end; }

/* Months across, vendors down. It scrolls in its own region rather than widening the page. */
.set-ledger th[scope="row"] { white-space: nowrap; }
.set-ledger td, .set-ledger th { white-space: nowrap; }

/* The kill switch is its own one-click form, so it saves without the rest of the row. */
.set-source-switch { display: flex; }
.set-source-switch .switch { inline-size: 100%; }

@media (forced-colors: active) {
  .set-budget-track { forced-color-adjust: none; background: Canvas; box-shadow: inset 0 0 0 1px CanvasText; }
  .set-budget-fill { background: CanvasText; }
}

/* The third cut of the same money, folded away until someone asks for it. */
.set-ledger-more > summary { cursor: pointer; color: var(--color-ink-secondary); padding-block: var(--space-1); border-radius: var(--radius-control); }
.set-ledger-more > summary:hover { color: var(--color-ink); }
.set-ledger-more[open] > summary { margin-block-end: var(--space-2); }


/* ---- faces/app/settings/integrations.css ---- */
/*
 * Settings → Integrations (M7), and the public connect page it sends clients to.
 *
 * One stylesheet for both because the bundle is global (src/ui/css.ts) and the two screens are
 * one feature: the team generates a link here, the client opens it there. Tokens only.
 */

.int-brands { gap: var(--space-5); }

.int-brand {
  padding-block-end: var(--space-5);
  border-block-end: 1px solid var(--color-line-subtle);
}

.int-brands > .int-brand:last-child {
  padding-block-end: 0;
  border-block-end: 0;
}

/* A generated link is long: let it scroll inside the field rather than stretch the card. */
.int-link { width: 100%; min-width: 0; }

@media (max-width: 720px) {
  .int-brand > .row, .int-brand .row.wrap { row-gap: var(--space-2); }
  .int-brand form > .row:has(> .btn-primary) { flex-direction: column; align-items: stretch; }
  .int-brand form > .row > .btn-primary { width: 100%; min-height: var(--button-height-coarse); }
}

/* Discovery credits (M8): one row per vendor and call kind, the numbers right-aligned. */
.int-usage { margin: 0; padding: 0; list-style: none; }
.int-usage > li { padding-block: var(--space-1); }

/* ---- the public connect page (/connect/meta/:token) ---- */

.mc-page {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-8) var(--space-4);
  background: var(--color-surface-ground);
}

.mc-inner {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  width: 100%;
  max-width: var(--layout-prose);
  padding: var(--space-8);
  border-radius: var(--radius-card);
  background: var(--color-surface-panel);
}

.mc-mark { display: block; height: 36px; width: auto; }
.mc-title { margin: 0; color: var(--color-ink); }
.mc-list { display: flex; flex-direction: column; gap: var(--space-2); }

.mc-list li {
  padding-inline-start: var(--space-4);
  border-inline-start: 2px solid var(--color-line-subtle);
}

.mc-actions { margin-block-start: var(--space-2); display: flex; flex-wrap: wrap; gap: var(--space-3); }


/* ---- faces/app/settings/policies.css ---- */
/* Settings → Policies (M5). Tokens only — invariant 1. */
.pol-head { display: flex; flex-wrap: wrap; gap: var(--space-4); align-items: flex-start; justify-content: space-between; }
.pol-head > .stack-2 { min-width: 0; flex: 1 1 32ch; }

/* The threshold grid: two narrow number columns beside a readable category name. */
.pol-head + form .set-table .dt-td .input { min-width: 8ch; max-width: 10ch; }

/* The table is its own scroll region (0014 pattern 2): the first column stays put while the rest scroll. */
.pol-table { max-height: none; }
.pol-table .dt-table { min-width: max-content; }
@media (max-width: 720px) {
  .pol-head { flex-direction: column; align-items: stretch; }
  .pol-head > .stack-2 { flex: 0 0 auto; }
  .pol-head > .btn { width: 100%; min-height: var(--button-height-coarse); }
  .pol-table .dt-th:first-child, .pol-table .dt-td:first-child { position: sticky; inset-inline-start: 0; z-index: 1; background: var(--color-surface-panel); }
  .pol-table .dt-th:first-child { background: var(--table-header-bg); }
  .pol-head + form .set-table .dt-td .input { max-width: none; }
}


/* ---- faces/app/settings/portal-settings.css ---- */
/* Settings → Portal (M6). Tokens only — invariant 1. */
.sp-version { align-items: center; gap: var(--space-2); }

/* Radio and checkbox groups read as a column on narrow screens, a row when there is room. */
.sp-checks { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4); }

.sp-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--space-4); align-items: start; }
.sp-grid .input { max-width: 12ch; }

.sp-templates { display: flex; flex-direction: column; gap: var(--space-3); margin: var(--space-4) 0 0; padding: 0; list-style: none; }
.sp-template { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: flex-start; justify-content: space-between; padding: var(--space-3) var(--space-4); border: 1px solid var(--color-line-default); border-radius: var(--radius-card); background: var(--color-surface-well); }
.sp-template-text { min-width: 0; flex: 1 1 32ch; }
.sp-template-name { color: var(--color-ink); font-weight: var(--weight-medium); }
.sp-template-subject { overflow-wrap: anywhere; }

@media (max-width: 900px) {
  .sp-grid { grid-template-columns: 1fr; }
}
@media (max-width: 720px) {
  .sp-grid .input { max-width: none; }
  .sp-checks { flex-direction: column; }
  .sp-template { padding: var(--space-3); }
}


/* ---- faces/app/settings/settings.css ---- */
/* Settings — DESIGN.md §9.2 (tables), §9.5 (forms). Tokens only. */
.set-page { padding-block-end: var(--space-12); }
.set-section { display: flex; flex-direction: column; gap: var(--space-4); }
.set-intro { max-width: var(--measure-prose); }

/* Rows hold real form controls, so they grow past the standard row height and wrap
   rather than scroll: these tables have few columns, and every one has to stay reachable. */
.set-table .dt-table { min-width: 0; }
.set-table .dt-td { height: auto; white-space: normal; vertical-align: top; padding-block: var(--space-3); }
.set-table .dt-td .input { min-width: 12ch; }
.set-table .dt-td .field-error { margin-block-start: var(--space-1); max-width: 32ch; }
.set-table .dt-td-right { white-space: nowrap; }
.set-td-wide { max-width: 44ch; }
.set-td-chips { max-width: 36ch; }
.set-row-actions { gap: var(--space-1); }

/* Row forms carry only hidden inputs; their controls live in the table via `form`. */
.set-forms { display: none; }

.set-add { gap: var(--space-4); }
.set-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--space-4); align-items: start; }
.set-grid-full { grid-column: 1 / -1; }

.set-chips { display: flex; flex-wrap: wrap; gap: var(--space-1); margin: 0; padding: 0; list-style: none; }

/* Wide enough to read the body beside its preview; one column when there is no room. */
.set-template { max-width: var(--layout-evidence); }
.set-template-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--space-4); align-items: start; }
.set-template-grid:focus-visible { outline: 2px solid var(--color-focus); outline-offset: var(--space-2); }
@media (min-width: 1100px) {
  .set-template-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
}
.set-preview { display: flex; flex-direction: column; gap: var(--space-2); padding: var(--space-4); border: 1px solid var(--color-line-default); border-radius: var(--radius-card); background: var(--color-surface-well); }
.set-preview-subject { color: var(--color-ink); }
.set-preview-body { white-space: pre-wrap; color: var(--color-ink-secondary); }
.set-preview-note { margin-block-start: var(--space-1); }

@media (max-width: 900px) {
  .set-grid { grid-template-columns: 1fr; }
}

/* Phone (decision 0014, pattern 5): one column, labels above, every field and the primary full
   width; the primary sits at the foot of its form. */
@media (max-width: 720px) {
  .set-page form > .row:has(> .btn-primary),
  .set-page .set-add > .row { flex-direction: column; align-items: stretch; }
  .set-page form > .row > .btn-primary,
  .set-page .set-add > .row > .btn-primary { width: 100%; min-height: var(--button-height-coarse); }
  .set-grid { grid-template-columns: minmax(0, 1fr); }
  .set-td-wide, .set-td-chips { max-width: none; }
  .set-template { max-width: none; }
  .set-preview { padding: var(--space-3); }
}

/* Settings → Discovery (D1): one fieldset per waterfall step, fields in a row that wraps on a phone. */
.set-rows { display: grid; gap: var(--space-3); }
.set-row { border: 1px solid var(--color-line-default); border-radius: var(--radius-control); padding: var(--space-3); margin: 0; }
.set-row > legend { padding: 0 var(--space-1); }
.set-row-fields { display: flex; flex-wrap: wrap; gap: var(--space-4); align-items: end; }
.set-row-fields > * { min-width: 0; flex: 1 1 12rem; }


/* ---- faces/app/vetting/vetting.css ---- */
/* Vetting review queue (/app/vetting). The table is src/ui/components/data-table.css; this file
   shapes the three cells that carry two lines or a sentence. Tokens only (invariant 1). */

.vq { min-width: 0; padding-block-end: var(--space-12); }
.vq-intro { max-width: var(--measure-prose); }

/* Client over policy, two lines in one cell. */
.vq-policy { display: flex; flex-direction: column; min-width: 0; line-height: var(--leading-xs); }
.vq-client { color: var(--color-ink); }

.vq-verdict { display: inline-flex; align-items: center; gap: var(--space-2); }

/* The reason is a sentence: it wraps, top-aligned, and only its row grows past the floor. */
.vq-reason { display: block; white-space: normal; max-width: 36ch; text-wrap: pretty; }
#vetting-queue .dt-td:has(> .vq-reason) { vertical-align: top; padding-block: var(--space-2); }

.vq-campaigns { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-1); }
.vq-campaigns a { white-space: nowrap; }

@media (max-width: 720px) {
  .vq-reason { max-width: 60vw; }
}


/* ---- faces/auth/auth.css ---- */
/* Sign-in (design/signin.html). The team sign-in carries the one photograph in the system (DESIGN
   §7): the night sky from beside a fire, the wordmark in the aperture, two measured scrims on top
   and a dark ground beneath so a failed load is still a legible page. The other auth surfaces
   (admin needed, the offline chooser) keep the plain card on the ground. */

.auth {
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: var(--space-8) var(--space-4);
  background: var(--color-surface-ground);
  position: relative;
}

.auth::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(120% 80% at 50% -10%, var(--color-brand-wash) 0%, transparent 60%);
  pointer-events: none;
}

.auth-card { position: relative; }

.auth-card {
  width: 100%;
  max-width: var(--layout-portal-column);
}

.auth-card .card-body {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.auth-wordmark {
  margin: 0;
  line-height: 1;
  color: var(--color-ink);
}

/* The one product line: quiet, under the mark, never rotating. */
.auth-line {
  margin: calc(var(--space-2) * -1) 0 var(--space-2);
  font-size: var(--text-md);
  line-height: var(--leading-md);
  color: var(--color-ink-secondary);
}

.auth-foot {
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-line-subtle);
}

.auth-last {
  font-size: var(--text-xs);
  line-height: var(--leading-xs);
}

.auth-title {
  font-family: var(--font-title);
  font-weight: var(--weight-medium);
  font-size: var(--text-xl);
  line-height: var(--leading-xl);
  margin: var(--space-2) 0 0;
  max-width: var(--measure-prose);
}

.auth-subtitle {
  font-family: var(--font-title);
  font-weight: var(--weight-medium);
  font-size: var(--text-md);
  line-height: var(--leading-md);
}

.auth-body {
  max-width: var(--measure-prose);
}

.auth-fineprint {
  font-size: var(--text-sm);
  line-height: var(--leading-sm);
}

/* A named problem, not an alarm: a tinted sentence that says what happened and what to press. */
.auth-note {
  padding: var(--space-3);
  border-radius: var(--radius-control);
  font-size: var(--text-sm);
  line-height: var(--leading-sm);
  text-align: left;
}

.auth-note-warn { background: var(--color-warn-tint); color: var(--color-warn); }
.auth-note-info { background: var(--color-info-tint); color: var(--color-info); }

.auth-actions {
  display: flex;
  gap: var(--space-2);
  flex-wrap: wrap;
  margin-top: var(--space-2);
}

/* Offline chooser (dev only — the route 404s once Google is configured). */
.auth-accounts {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: 0;
  margin: 0;
}

.auth-account {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3);
  border: 1px solid var(--color-line-default);
  border-radius: var(--radius-control);
  background: var(--color-surface-well);
}

.auth-account-id {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-width: 0;
}

.auth-account-email {
  font-size: var(--text-sm);
  line-height: var(--leading-sm);
  overflow-wrap: anywhere;
}

.auth-freeform {
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-line-subtle);
}

@media (max-width: 560px) {
  .auth {
    align-items: start;
    padding: var(--space-6) var(--space-4);
  }

  .auth-account {
    flex-direction: column;
    align-items: stretch;
  }
}

/* ---------- the night sign-in (design/signin.html `.signin.night`) ---------- */

.auth-night {
  background: var(--signin-ground);
  isolation: isolate;
  color: var(--signin-ink);
}

.auth-night::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -2;
  background-image: var(--auth-sky); /* set inline by the page: the content-hashed image URL */
  background-size: cover;
  background-position: 50% 46%;
}

/* Two scrims: a radial at 62 % centre easing to 31 % at the tree line, and a bottom band under
   the footer, which sits over lit trunks rather than sky. Tuned to this picture (DESIGN §7). */
.auth-night::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: var(--signin-scrim-radial), var(--signin-scrim-band);
}

@media (max-width: 720px) {
  /* The plain card starts at the top on a phone (the chooser is a long form); the photograph keeps
     its column centred, as on the desktop, and the 560 rule above must not win here. */
  .auth-night { align-items: center; padding: var(--space-10) var(--space-5) var(--space-16); }
  /* The 42-high wordmark is wider than a 320 column less its padding: let it scale to fit. */
  .auth-night .auth-wordmark .mark { max-width: 100%; height: auto; }
  .auth-night::before { background-position: 50% 42%; }
  .auth-night::after {
    background: var(--signin-scrim-radial-narrow), var(--signin-scrim-band-narrow);
  }
}

/* No card on the photograph: a bare column, 400 wide, the wordmark in the aperture. */
.auth-night .auth-col {
  position: relative;
  width: 100%;
  max-width: var(--signin-column);
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.auth-night .auth-wordmark { color: var(--signin-ink); }
.auth-night .auth-line { color: var(--signin-line); }
.auth-night .auth-fineprint,
.auth-night .auth-last { color: var(--signin-hint); }
.auth-night .auth-fineprint b { color: var(--signin-hint-strong); font-weight: var(--weight-medium); }

.auth-night .auth-note-info { background: var(--signin-note-info-bg); color: var(--signin-note-info); }
.auth-night .auth-note-warn { background: var(--signin-note-warn-bg); color: var(--signin-note-warn); }
.auth-night .auth-note-bad { background: var(--signin-note-bad-bg); color: var(--signin-note-bad); }

/* The dark-theme ember on the photograph: the light one reads 2.98:1 against the teal. */
.auth-night .btn-primary {
  background: var(--signin-button);
  box-shadow: inset 0 0 0 1px var(--signin-button-edge), inset 0 1px 0 var(--signin-button-highlight), var(--signin-button-shadow);
}
.auth-night .btn-primary:hover { background: var(--signin-button-hover); }
.auth-night .btn-primary:focus-visible { outline: 2px solid var(--signin-ink); outline-offset: 3px; }

/* The endorsement alone, centred, pinned over the bottom band. */
.auth-night .auth-foot {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  margin: 0;
  padding: var(--space-5) var(--space-6);
  border-top: 0;
  display: flex;
  justify-content: center;
  color: var(--signin-foot);
}
.auth-night .auth-foot .fueled-by-label { color: var(--signin-foot); }
.auth-night .auth-foot .mark { color: var(--signin-ink); }



/* ---- faces/design/gallery.css ---- */
/* /design gallery chrome. Tokens only. */
.dg-shell { display: flex; flex-direction: column; height: 100dvh; }
.dg-bar { display: flex; align-items: center; gap: var(--space-6); height: var(--layout-topbar); padding: 0 var(--space-4); background: var(--color-surface-panel); border-bottom: 1px solid var(--color-line-default); flex: 0 0 auto; }
.dg-jumps { display: flex; gap: var(--space-3); overflow-x: auto; flex: 1 1 auto; min-width: 0; }
.dg-jumps a { white-space: nowrap; text-decoration: none; color: var(--color-ink-secondary); font-size: var(--text-sm); }
.dg-jumps a:hover { color: var(--color-ink); text-decoration: underline; }
.dg-modes { display: flex; align-items: center; gap: var(--space-3); font-size: var(--text-sm); flex: 0 0 auto; }
.dg-frames { display: grid; flex: 1 1 auto; min-height: 0; }
.dg-frames-2 { grid-template-columns: 1fr 1fr; }
.dg-frames-1 { grid-template-columns: 1fr; }
.dg-frame { width: 100%; height: 100%; border: 0; border-right: 1px solid var(--color-line-default); background: var(--color-surface-ground); }
.dg-frame:last-child { border-right: 0; }

.dg { padding: var(--space-8) var(--space-8) var(--space-16); max-width: 1400px; }
.dg-head { margin-bottom: var(--space-10); }
.dg-head h1 { margin: var(--space-1) 0 var(--space-3); }
.dg-toc { display: flex; flex-wrap: wrap; gap: var(--space-3); margin-top: var(--space-4); }
.dg-toc a { font-size: var(--text-sm); }
.dg-section { margin-bottom: var(--space-16); scroll-margin-top: var(--space-6); }
.dg-section > h2 { margin-bottom: var(--space-2); }
.dg-section > p { margin-bottom: var(--space-6); }
.dg-group { margin-top: var(--space-8); }
.dg-group-label { margin-bottom: var(--space-4); padding-bottom: var(--space-2); border-bottom: 1px solid var(--color-line-subtle); }

.dg-story { margin-bottom: var(--space-10); scroll-margin-top: var(--space-6); }
.dg-story-head { margin-bottom: var(--space-4); }
.dg-story-head h4 a { text-decoration: none; }
.dg-story-head h4 a:hover { text-decoration: underline; }
.dg-story-head p { margin-top: var(--space-1); }
.dg-states { display: grid; grid-template-columns: repeat(auto-fill, minmax(360px, 1fr)); gap: var(--space-4); }
.dg-state-wide { grid-column: 1 / -1; }
.dg-state-head { margin-bottom: var(--space-2); }
.dg-canvas { padding: var(--space-4); background: var(--color-surface-panel); border: 1px solid var(--color-line-default); border-radius: var(--radius-card); min-height: 72px; overflow: auto; }
.dg-canvas-ground { background: var(--color-surface-ground); }

.dg-table { width: 100%; font-size: var(--text-sm); line-height: var(--leading-sm); }
.dg-table th { text-align: left; font-size: var(--text-2xs); text-transform: uppercase; letter-spacing: var(--tracking-label); color: var(--color-ink-tertiary); font-weight: var(--weight-medium); padding: var(--space-2) var(--space-3); border-bottom: 1px solid var(--color-line-default); }
.dg-table td { padding: var(--space-2) var(--space-3); border-bottom: 1px solid var(--color-line-subtle); vertical-align: middle; }
.dg-table .num { text-align: right; }
.dg-swatch { display: inline-block; width: 40px; height: 24px; border-radius: var(--radius-control); box-shadow: inset 0 0 0 1px var(--color-line-default); }
.dg-sample { display: inline-flex; align-items: center; justify-content: center; width: 48px; height: 32px; border-radius: var(--radius-control); font-weight: var(--weight-medium); box-shadow: inset 0 0 0 1px var(--color-line-subtle); }
.dg-sample-boundary { border: 2px solid; box-shadow: none; }
.dg-pass { color: var(--color-ok); font-weight: var(--weight-medium); }
.dg-fail { color: var(--color-bad); font-weight: var(--weight-medium); }
.dg-contrast { margin-bottom: var(--space-8); }
.dg-contrast h3 { margin-bottom: var(--space-3); }

.dg-type-row { display: grid; grid-template-columns: 200px 1fr; gap: var(--space-6); padding: var(--space-4) 0; border-bottom: 1px solid var(--color-line-subtle); }
.dg-type-meta { display: flex; flex-direction: column; gap: var(--space-1); }
.dg-type-samples { display: flex; flex-direction: column; gap: var(--space-2); min-width: 0; }
.dg-type-samples p { overflow-wrap: anywhere; }

.dg-space { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: var(--space-8); }
.dg-space h3 { margin-bottom: var(--space-3); }
.dg-space-list { display: flex; flex-direction: column; gap: var(--space-2); }
.dg-space-bar { display: inline-block; height: 12px; background: var(--color-brand); border-radius: 2px; }
.dg-radius { display: block; width: 56px; height: 56px; background: var(--color-surface-well); border: 1px solid var(--color-line-interactive); }
.dg-shadow { display: block; width: 96px; height: 64px; background: var(--color-surface-panel); border-radius: var(--radius-card); }

.dg-marks { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: var(--space-4); }
.dg-mark { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--space-3); padding: var(--space-6); border-radius: var(--radius-card); min-height: 140px; border: 1px solid var(--color-line-subtle); }
.dg-mark img { height: 40px; width: auto; }
.dg-mark-white { background: var(--primitive-white); color: var(--primitive-ink-900); }
.dg-mark-offwhite { background: var(--primitive-off-white); color: var(--primitive-ink-900); }
.dg-mark-orange { background: var(--primitive-orange); color: var(--primitive-ink-900); }
.dg-mark-dark { background: var(--primitive-dark-ground); color: var(--primitive-dark-ink); }

.dg-icons { display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: var(--space-2); }
.dg-icons li { display: flex; align-items: center; gap: var(--space-2); padding: var(--space-2); border-radius: var(--radius-control); background: var(--color-surface-panel); }
.dg-refs { display: flex; flex-direction: column; gap: var(--space-2); }

.dg-state-open { margin-inline-start: var(--space-2); }
.dg-frame-state { width: 100%; border: 1px solid var(--color-line-default); border-radius: var(--radius-card); background: var(--color-surface-ground); }
.dg-state-page { min-height: 100dvh; }


/* ---- faces/portal/portal.css ---- */
/* Creator portal (M6). Guide mode: one column at 480px, one task per screen, 44px targets,
   Campfire at the top and Kindling only in the footer (DESIGN.md §8, §9.10; brand guide §3, §8).
   Light only — the portal has no dark theme in v1 (DESIGN.md §5.5). Tokens only. */

/* The <body> element. Named apart from `.portal-body` (a paragraph) on purpose: one class
   doing both jobs gave every paragraph a full viewport of height. */
.portal-ground {
  min-height: 100dvh;
  background: var(--color-surface-ground);
}

.portal {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
  width: 100%;
  max-width: var(--layout-portal-column);
  min-height: 100dvh;
  margin: 0 auto;
  padding: var(--space-5) var(--space-4) var(--space-10);
}

/* ---------------------------------------------------------------- chrome */

.portal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  min-height: var(--target-min);
}

.portal-mark {
  display: inline-flex;
  align-items: center;
  min-height: var(--target-min);
}

.portal-mark-img {
  width: 120px;
  height: auto;
}

.portal-signout {
  margin-inline-start: auto;
}

.portal-main {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  flex: 1 1 auto;
}

.portal-foot {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding-top: var(--space-6);
  border-top: 1px solid var(--color-line-subtle);
}

.portal-foot-line {
  margin: 0;
  font-size: var(--text-sm);
  line-height: var(--leading-sm);
}

/* ---------------------------------------------------------------- type */

.portal-title {
  margin: 0;
  font-size: var(--text-2xl);
  line-height: var(--leading-2xl);
}

.portal-subtitle {
  margin: 0;
  font-family: var(--font-title);
  font-weight: var(--weight-medium);
  font-size: var(--text-lg);
  line-height: var(--leading-lg);
}

.portal-h3 {
  margin: 0;
  font-family: var(--font-title);
  font-weight: var(--weight-medium);
  font-size: var(--text-md);
  line-height: var(--leading-md);
}

.portal-lede {
  margin: 0;
  font-size: var(--text-md);
  line-height: var(--leading-md);
  color: var(--color-ink-secondary);
}

.portal-body {
  font-size: var(--text-base);
  line-height: var(--leading-base);
}

.portal-main p {
  margin: 0;
}

.portal-note {
  margin: 0;
  padding: var(--space-3);
  border: 1px solid var(--color-line-default);
  border-radius: var(--radius-control);
  background: var(--color-surface-well);
  font-size: var(--text-sm);
  line-height: var(--leading-sm);
}

.portal-note-problem {
  border-color: var(--color-warn);
  background: var(--color-warn-tint);
  color: var(--color-ink);
}

.portal-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-line-subtle);
}

.portal-links a {
  display: inline-flex;
  align-items: center;
  min-height: var(--target-min);
}

/* ---------------------------------------------------------------- cards and lists */

.portal-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  margin: 0;
  padding: 0;
  list-style: none;
}

.portal-card-title {
  margin: 0;
  font-family: var(--font-title);
  font-weight: var(--weight-medium);
  font-size: var(--text-lg);
  line-height: var(--leading-lg);
}

.portal-card .card-body {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  align-items: flex-start;
}

.portal-card-state {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2);
  font-size: var(--text-sm);
  line-height: var(--leading-sm);
}

.portal-card-meta {
  font-size: var(--text-sm);
  line-height: var(--leading-sm);
}

.portal-card-action {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  width: 100%;
}

/* The primary action fills the column, like every other primary in the portal. */
.portal-card-action .btn {
  flex: 1 1 auto;
  justify-content: center;
}

.portal-summary {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin: 0;
  width: 100%;
}

.portal-summary-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
}

.portal-summary-label {
  font-size: var(--text-sm);
  line-height: var(--leading-sm);
  color: var(--color-ink-secondary);
}

.portal-summary-value {
  margin: 0;
  font-weight: var(--weight-medium);
  text-align: end;
}

.portal-progress {
  align-self: flex-start;
}

/* ---------------------------------------------------------------- the stepper */

.portal-steps {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: portal-step;
}

.step {
  padding: var(--space-4);
  border: 1px solid var(--color-line-subtle);
  border-radius: var(--radius-card);
  background: var(--color-surface-panel);
}

.step[data-status='current'] {
  border-color: var(--color-line-interactive);
  box-shadow: var(--shadow-1);
}

.step[data-status='upcoming'] {
  background: var(--color-surface-well);
}

.step-head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.step-marker {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  flex: 0 0 auto;
  border: 1px solid var(--color-line-default);
  border-radius: var(--radius-pill);
  background: var(--color-surface-ground);
  color: var(--color-ink-secondary);
}

.step[data-status='complete'] .step-marker {
  border-color: var(--color-ok);
  color: var(--color-ok);
}

.step[data-status='current'] .step-marker {
  border-color: var(--color-brand);
  background: var(--color-brand-tint);
  color: var(--color-ink);
}

.step-number {
  font-size: var(--text-sm);
  line-height: var(--leading-sm);
  font-weight: var(--weight-medium);
}

.step-title {
  margin: 0;
  flex: 1 1 auto;
  min-width: 0;
  font-family: var(--font-title);
  font-weight: var(--weight-medium);
  font-size: var(--text-md);
  line-height: var(--leading-md);
}

.step-word {
  font-size: var(--text-sm);
  line-height: var(--leading-sm);
  text-align: end;
}

.step-word-done {
  color: var(--color-ok);
}

.step-note {
  margin: var(--space-2) 0 0;
  padding-inline-start: calc(28px + var(--space-3));
  font-size: var(--text-sm);
  line-height: var(--leading-sm);
}

.step-body {
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-line-subtle);
}

/* ---------------------------------------------------------------- forms */

.portal-form {
  width: 100%;
}

.portal-form .btn {
  width: 100%;
}

.portal-form .input,
.portal-form .input-group {
  width: 100%;
}

.portal-decline {
  padding-top: var(--space-2);
  border-top: 1px solid var(--color-line-subtle);
}

.portal-decline-summary {
  display: flex;
  align-items: center;
  min-height: var(--target-min);
  font-size: var(--text-sm);
  line-height: var(--leading-sm);
  color: var(--color-ink-secondary);
  cursor: pointer;
}

.portal-decline[open] .portal-decline-summary {
  margin-bottom: var(--space-3);
}

.portal-terms-hint {
  font-size: var(--text-xs);
  line-height: var(--leading-xs);
}

.portal-terms {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  max-height: 260px;
  overflow-y: auto;
  padding: var(--space-3);
  border: 1px solid var(--color-line-subtle);
  border-radius: var(--radius-control);
  background: var(--color-surface-well);
  font-size: var(--text-sm);
  line-height: var(--leading-sm);
}

/* ---------------------------------------------------------------- accounts and requirements */

.portal-accounts,
.portal-requirements {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.portal-account {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
  min-height: var(--target-min);
  padding: var(--space-3);
  border: 1px solid var(--color-line-default);
  border-radius: var(--radius-control);
  background: var(--color-surface-panel);
}

.portal-account-text,
.portal-requirement-text {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-width: 0;
  font-size: var(--text-sm);
  line-height: var(--leading-sm);
}

.portal-account form {
  margin-inline-start: auto;
}

.portal-requirement {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
}

.portal-requirement-head {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  width: 100%;
}

/* A post URL is one long unbreakable token; let it wrap rather than push the card wide. */
.portal-linked {
  overflow-wrap: anywhere;
}

.portal-bonus {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-line-subtle);
}

.portal-bonus-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: var(--target-min);
  font-size: var(--text-sm);
  line-height: var(--leading-sm);
}

/* ---------------------------------------------------------------- Shelfworthy link (M9) */

.portal-shelfworthy-url {
  overflow-wrap: anywhere;
  font-variant-numeric: tabular-nums;
}

/* The whole sticker sentence, exactly as it will be pasted — nothing is clipped away here,
   because a creator has to be able to read what they are about to publish. */
.portal-shelfworthy-sticker {
  margin: 0;
  font-size: var(--text-sm);
  line-height: var(--leading-sm);
  color: var(--color-ink-secondary);
  text-wrap: pretty;
}

/* The value and the control stack on a phone, which is where the portal actually lives. */
.portal-copy {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-2);
  width: 100%;
}

/* ---------------------------------------------------------------- ad-permission guide */

.portal-guide {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  margin: 0;
  padding: 0;
  list-style: none;
}

.portal-guide-step {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.portal-guide-shot {
  width: 100%;
  max-width: 240px;
  height: auto;
  border: 1px solid var(--color-line-subtle);
  border-radius: var(--radius-control);
  background: var(--color-surface-well);
}

.portal-guide-text {
  font-size: var(--text-sm);
  line-height: var(--leading-sm);
}

/* The creator's own payment state (M7). Their amount, never anybody else's. */
.portal-payment {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.portal-payment-line {
  margin: 0;
  font-size: var(--text-sm);
  line-height: var(--leading-sm);
  color: var(--color-ink-secondary);
}

/* Numbered on purpose: these happen in order. A flex container would drop the markers. */
.portal-next {
  margin: 0;
  padding-inline-start: var(--space-5);
  font-size: var(--text-sm);
  line-height: var(--leading-sm);
}

.portal-next li + li {
  margin-top: var(--space-2);
}

.portal-brief-section {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.portal-polling {
  padding: var(--space-4);
  border: 1px dashed var(--color-line-default);
  border-radius: var(--radius-control);
  background: var(--color-surface-well);
}

/* The band is allowed here and nowhere else in the portal (DESIGN.md §5.6). */
.portal .band {
  width: 100%;
}

@media (max-width: 420px) {
  .portal {
    padding: var(--space-4) var(--space-4) var(--space-8);
  }

  .portal-account form {
    width: 100%;
    margin-inline-start: 0;
  }

  .portal-account .btn {
    width: 100%;
  }
}


/* ---- faces/public/proposal.css ---- */
/* Published Talent Proposal — Present mode (DESIGN.md §8 client pages, §9.9; brand guide §3, §8).
   Light in v1 (§5.5). Tokens only. Reading column 720, evidence 1120.

   Print is a first-class layout, not an afterthought: the same rules run under `@media print`
   and under `[data-print="1"]`, which `?print=1` sets so the team can see the paper version on
   screen before sending the link. The two blocks at the bottom are deliberate duplicates and
   must be edited together. Controls disappear on paper — nothing there can be clicked — and the
   answer each card already carries stays, so a printed proposal still reads correctly. */

.proposal { background: var(--color-surface-ground); color: var(--color-ink); min-height: 100dvh; }
.proposal .band { border-radius: 0; }
.proposal-main { max-width: var(--layout-evidence); margin: 0 auto; padding: var(--space-12) var(--space-6); }

.proposal-notice { display: flex; align-items: center; gap: var(--space-2); padding: var(--space-3) var(--space-4); margin-bottom: var(--space-6); border: 1px solid var(--color-ok); border-radius: var(--radius-card); background: var(--color-surface-panel); color: var(--color-ink); max-width: var(--layout-prose); }

/* Client theming (DESIGN 1.4 §5.7). The `--tenant-*` properties are written onto `.proposal` by
   the server from the snapshot's kit. Under Client-led the client owns the band and the accents;
   Campfire keeps the frame — and the status colours, because Approved and Passed mean the same
   thing on every proposal and a client's palette does not get to move them. */
.proposal[data-preset="client-led"] .pcard-comment { background: var(--tenant-wash); }
.proposal[data-preset="client-led"] .proposal-notice { border-color: var(--tenant-ink); }

.proposal-intro { max-width: var(--layout-prose); margin-bottom: var(--space-4); }
.proposal-lede { font-size: var(--text-lg); line-height: var(--leading-lg); margin-bottom: var(--space-4); }
.proposal-how { max-width: var(--layout-prose); margin-bottom: var(--space-10); }
.proposal-empty { max-width: var(--layout-prose); color: var(--color-ink-secondary); }

.proposal-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); gap: var(--space-6); }

.pcard { background: var(--color-surface-panel); border: 1px solid var(--color-line-default); border-radius: var(--radius-card); overflow: hidden; display: flex; flex-direction: column; scroll-margin-top: var(--space-8); }
.pcard[data-status="approved"] { border-color: var(--color-ok); }
.pcard[data-status="passed"] { border-color: var(--color-line-subtle); }

/* Evidence, not decoration: up to four recent posts, each a link to the real thing. A flex row
   rather than four fixed columns, so a creator with two recent posts shows two full-width
   thumbnails instead of two and a pair of empty cells. The strip has a fixed height rather than
   each thumbnail an aspect ratio, so a card with two posts is the same shape as one with four. */
.pcard-thumbs { display: flex; gap: 1px; height: 132px; background: var(--color-line-subtle); }
.pcard-thumb { flex: 1 1 0; min-width: 0; height: 100%; background: var(--color-surface-well); }
.pcard-thumb a, .pcard-thumb img { display: block; width: 100%; height: 100%; }
.pcard-thumb img { object-fit: cover; }

.pcard-body { display: flex; flex-direction: column; gap: var(--space-4); padding: var(--space-5); }
.pcard-id { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: var(--space-3); }
.pcard-names { min-width: 0; }
.pcard-name { font-size: var(--text-xl); line-height: var(--leading-xl); overflow-wrap: anywhere; }
.pcard-handle { display: flex; align-items: center; gap: var(--space-1); min-width: 0; overflow-wrap: anywhere; }

.pcard-metrics { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--space-3); }

.pcard-facts { display: flex; flex-direction: column; gap: var(--space-2); }
.pcard-fact { display: grid; grid-template-columns: 92px 1fr; gap: var(--space-3); align-items: baseline; }
.pcard-fact dd { font-size: var(--text-sm); line-height: var(--leading-sm); }
/* The verdict is a word (DESIGN.md §9.9). Tone is carried by a label as well as by colour. */
.pcard-verdict { font-weight: var(--weight-medium); }
.pcard-verdict-ok { color: var(--color-ok); }
.pcard-verdict-warn { color: var(--color-warn); }
.pcard-verdict-bad { color: var(--color-bad); }
.pcard-verdict-neutral { color: var(--color-ink-secondary); }

.pcard-bio { font-size: var(--text-sm); line-height: var(--leading-sm); color: var(--color-ink-secondary); max-width: var(--measure-prose); }
.pcard-comment { display: flex; flex-direction: column; gap: var(--space-1); padding: var(--space-3); background: var(--color-surface-well); border-radius: var(--radius-control); font-size: var(--text-sm); line-height: var(--leading-sm); }

.pcard-actions { display: flex; flex-direction: column; gap: var(--space-3); margin-top: auto; padding-top: var(--space-3); border-top: 1px solid var(--color-line-subtle); }
.pcard-decide { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.pcard-comment-form { display: flex; flex-direction: column; gap: var(--space-2); align-items: flex-start; }
.pcard-comment-form textarea { width: 100%; }

.proposal-footer { border-top: 1px solid var(--color-line-default); background: var(--color-surface-panel); }
.proposal-footer-inner { max-width: var(--layout-evidence); margin: 0 auto; padding: var(--space-8) var(--space-6); display: flex; flex-direction: column; gap: var(--space-2); }
.proposal-footer-mark { height: 24px; width: auto; }
/* The endorsement (brand guide §3): "Fueled by" and the CAMPFIRE logo as artwork, once, here. */
.proposal-endorse { display: inline-flex; align-items: center; gap: var(--space-2); }
.proposal-endorse .mark { display: block; }

/* The client gate: the client's band when there is a kit, one heading, one paragraph, no button. */
.proposal-notice-page { display: flex; flex-direction: column; }
.proposal-notice-band { min-block-size: 120px; }
.proposal-notice-inner { max-width: var(--layout-prose); margin: 0 auto; padding: var(--space-16) var(--space-6); display: flex; flex-direction: column; gap: var(--space-4); align-items: flex-start; }
.proposal-notice-mark { height: 36px; width: auto; }
.proposal-notice-title { font-size: var(--text-2xl); line-height: var(--leading-2xl); }
.proposal-notice-body { max-width: var(--measure-prose); }

@media (max-width: 720px) {
  .proposal-main { padding: var(--space-8) var(--space-4); }
  .proposal-cards { grid-template-columns: 1fr; }
  .proposal-notice-inner { padding: var(--space-10) var(--space-4); }
}

/* Under 400 the name cell between the avatar and the status pill is too narrow for a two-word name,
   so the pill drops under the name and the name keeps its column. */
@media (max-width: 400px) {
  .pcard-id { grid-template-columns: auto minmax(0, 1fr); }
  .pcard-id > .pill { grid-column: 2; justify-self: start; }
}

/* ---------------------------------------------------------------------------
   Paper. Flat band, no shadows, two cards to a row, no controls, and the answer
   already on record kept in words. Keep the two blocks in sync.
   --------------------------------------------------------------------------- */
@media print {
  .proposal { background: none; }
  .proposal .band, .proposal .band-tenant { background: none; color: var(--color-ink); border: 1px solid var(--color-line-default); box-shadow: none; }
  .proposal .band-mark-screen { display: none; }
  .proposal .band-mark-print { display: block; }
  .proposal-main { max-width: none; padding: var(--space-8) 0; }
  .proposal-cards { grid-template-columns: repeat(2, 1fr); gap: var(--space-4); }
  .pcard { break-inside: avoid; box-shadow: none; }
  .proposal-how, .pcard-actions, .skip-link, .proposal .metric-source { display: none; }
  .proposal a { text-decoration: none; }
  .proposal a::after { content: none; }
  .proposal-footer { background: none; }
  .proposal-footer-inner { padding: var(--space-6) 0; }
}

.proposal[data-print="1"] { background: var(--color-surface-panel); }
.proposal[data-print="1"] :is(.band, .band-tenant) { background: none; color: var(--color-ink); border: 1px solid var(--color-line-default); box-shadow: none; }
.proposal[data-print="1"] .band-mark-screen { display: none; }
.proposal[data-print="1"] .band-mark-print { display: block; }
.proposal[data-print="1"] .proposal-main { max-width: none; padding: var(--space-8) 0; }
.proposal[data-print="1"] .proposal-cards { grid-template-columns: repeat(2, 1fr); gap: var(--space-4); }
.proposal[data-print="1"] .pcard { break-inside: avoid; box-shadow: none; }
.proposal[data-print="1"] :is(.proposal-how, .pcard-actions, .skip-link, .metric-source) { display: none; }
.proposal[data-print="1"] a { text-decoration: none; }
.proposal[data-print="1"] a::after { content: none; }
.proposal[data-print="1"] .proposal-footer { background: none; }
.proposal[data-print="1"] .proposal-footer-inner { padding: var(--space-6) 0; }

@media (forced-colors: active) {
  .pcard, .pcard-comment { border: 1px solid CanvasText; }
}


/* ---- faces/public/report.css ---- */
/* Client report — Present mode (DESIGN.md §8 client pages, §9.9; brand guide §8, §9).
   Light in v1 (§5.5). Tokens only. Reading column 720, evidence 1120, sections 64/40.

   Print is a first-class layout here, not an afterthought: the same rules run under
   `@media print` and under `[data-print="1"]`, which `?print=1` sets so a reviewer can
   see the paper version on screen before sending the link. The two blocks at the bottom
   of this file are deliberate duplicates and must be edited together. */

@page { margin: 16mm; }

.report { background: var(--color-surface-ground); color: var(--color-ink); min-height: 100dvh; }
.report .band { border-radius: 0; }
.report-main { max-width: var(--layout-evidence); margin: 0 auto; padding: var(--space-16) var(--space-6); }
.report-section { margin-bottom: var(--space-16); }
.report-section:last-child { margin-bottom: 0; }
.report-h { display: flex; align-items: baseline; gap: var(--space-3); font-family: var(--font-display); font-weight: var(--weight-regular); font-size: var(--text-2xl); line-height: var(--leading-2xl); margin-bottom: var(--space-6); }

/* The three stages (DESIGN 1.4 §10a): 01 · Spark → 02 · Kindling → 03 · Fire. The eyebrow opens
   a stage; the sections inside it carry only their own heading. The number is the one place a
   client page spends brand colour on text — ember, or the client's derived ink under their kit. */
.report-stage { color: var(--color-ink-secondary); margin-bottom: var(--space-2); }
.report-num { font-family: var(--font-ui); font-size: var(--text-2xs); color: var(--color-brand-strong); letter-spacing: var(--tracking-label); font-weight: var(--weight-strong); }
.report-reading { max-width: var(--layout-prose); }
.report-lede { font-size: var(--text-lg); line-height: var(--leading-lg); margin-bottom: var(--space-4); }
.report-note { margin-bottom: var(--space-4); }
.report-quiet { max-width: var(--layout-prose); }

/* Client theming (DESIGN 1.4 §5.7). The `--tenant-*` properties are written onto `.report` by
   the server from the snapshot's kit; nothing here invents a colour, and a page with no kit falls
   back to Campfire's own tokens. Under Client-led the client owns the accents — section numbers,
   links, the selected scope — and Campfire keeps the frame: type, grid, spacing, status colours. */
.report[data-preset="client-led"] .report-num { color: var(--tenant-ink); }
.report[data-preset="client-led"] .report-post-link,
.report[data-preset="client-led"] .report-embed-open { color: var(--tenant-ink); }
.report[data-preset="client-led"] .segmented-item:hover { background: var(--tenant-wash); }
.report[data-preset="client-led"] .report-vp-source { background: var(--tenant-wash); border-radius: var(--radius-control); padding: var(--space-2) var(--space-3); }

/* The scope control is three links, so the page re-renders server-side with no script. */
.report-scope { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; margin-bottom: var(--space-10); }
.report-scope-chips { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
.report-scope-note { max-width: var(--layout-prose); }

/* Shown only on paper (and in the ?print=1 preview): what a closed disclosure cannot say. */
.report-print-only { display: none; }

.report-hero { margin-bottom: var(--space-6); }
.report-hero img { width: 100%; max-height: 420px; object-fit: cover; border-radius: var(--radius-card); }

.report-kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: var(--space-4); }
.report-kpis-wide { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
/* Seven KPIs read best as 4 + 3; auto-fit would leave one number stranded on its own row. */
@media (min-width: 900px) {
  .report-kpis:not(.report-kpis-wide) { grid-template-columns: repeat(4, 1fr); }
}
.report-kpi { display: flex; flex-direction: column; min-inline-size: 0; }
.report-kpi > .metric { height: 100%; }

/* Positioned on purpose: the visually-hidden source notes inside the cells are absolutely placed,
   and without a positioned scroll container they escape it and widen the document on a phone. */
.report-table-wrap { position: relative; overflow-x: auto; background: var(--color-surface-panel); border: 1px solid var(--color-line-default); border-radius: var(--radius-card); }
.report-table { width: 100%; font-size: var(--text-md); line-height: var(--leading-md); }
.report-table th, .report-table td { padding: var(--space-3) var(--space-4); border-bottom: 1px solid var(--color-line-subtle); text-align: left; }
.report-table thead th { font-size: var(--text-2xs); line-height: var(--leading-2xs); text-transform: uppercase; letter-spacing: var(--tracking-label); color: var(--color-ink-tertiary); font-weight: var(--weight-medium); background: var(--color-surface-well); }
.report-table tbody tr:last-child th, .report-table tbody tr:last-child td { border-bottom: 0; }
.report-table .num { text-align: right; }
.report-platform { display: flex; align-items: center; gap: var(--space-2); font-weight: var(--weight-medium); }

/* Verified purchases (M9): one row per creator, then the totals band the client reads first. */
.report-vp tbody tr:last-child th, .report-vp tbody tr:last-child td { border-bottom: 1px solid var(--color-line-subtle); }
.report-vp tfoot th, .report-vp tfoot td { background: var(--color-surface-well); font-weight: var(--weight-medium); border-bottom: 0; }
.report-vp-source { margin-top: var(--space-3); }

.report-creators { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(300px, 100%), 1fr)); gap: var(--space-4); }
.report-creator { background: var(--color-surface-panel); border: 1px solid var(--color-line-default); border-radius: var(--radius-card); padding: var(--space-5); display: flex; flex-direction: column; gap: var(--space-3); }
.report-creator-head { display: flex; gap: var(--space-3); align-items: center; }
.report-creator-id { min-width: 0; }
.report-creator-id h3 { overflow-wrap: anywhere; }
.report-creator-id p { display: flex; align-items: center; gap: var(--space-1); flex-wrap: wrap; }
.report-creator-bio { max-width: var(--measure-prose); }
.report-creator-stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-2); margin-top: auto; }
.report-creator-stats dt { font-size: var(--text-2xs); line-height: var(--leading-2xs); text-transform: uppercase; letter-spacing: var(--tracking-label); color: var(--color-ink-tertiary); }
.report-creator-stats dd { font-family: var(--font-title); font-weight: var(--weight-medium); font-size: var(--text-lg); line-height: var(--leading-lg); }

.report-posts { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: var(--space-4); }
.report-post { background: var(--color-surface-panel); border: 1px solid var(--color-line-default); border-radius: var(--radius-card); overflow: hidden; display: flex; flex-direction: column; }
.report-post-media { position: relative; display: block; aspect-ratio: 4 / 5; background: var(--color-surface-well); }
.report-post-media img { width: 100%; height: 100%; object-fit: cover; }
.report-post-placeholder { display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; color: var(--color-ink-tertiary); }
.report-post-boosted { position: absolute; top: var(--space-2); left: var(--space-2); }
.report-post-body { padding: var(--space-3); display: flex; flex-direction: column; gap: var(--space-2); }
.report-post-head { gap: var(--space-1); }
.report-post-caption { display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.report-post-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-2); }
.report-post-stats dt { font-size: var(--text-2xs); line-height: var(--leading-2xs); text-transform: uppercase; letter-spacing: var(--tracking-label); color: var(--color-ink-tertiary); }
.report-post-stats dd { font-weight: var(--weight-medium); }
.report-post-link { color: var(--color-ink-secondary); display: inline-flex; align-items: center; gap: var(--space-1); margin-top: auto; }

.report-gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: var(--space-3); }
.report-gallery-item { border-radius: var(--radius-card); overflow: hidden; background: var(--color-surface-well); aspect-ratio: 4 / 5; }
.report-gallery-item a, .report-gallery-item img { display: block; width: 100%; height: 100%; }
.report-gallery-item img { object-fit: cover; }

/* An embed is a link card. A client page never frames a document it does not control. */
.report-embed { display: flex; flex-direction: column; gap: var(--space-1); padding: var(--space-4); background: var(--color-surface-panel); border: 1px solid var(--color-line-default); border-radius: var(--radius-card); text-decoration: none; }
.report-embed:hover { border-color: var(--color-line-interactive); }
.report-embed-host { font-family: var(--font-title); }
.report-embed-open { display: inline-flex; align-items: center; gap: var(--space-1); color: var(--color-ink-secondary); }

.report-footer { border-top: 1px solid var(--color-line-default); background: var(--color-surface-panel); }
.report-footer-inner { max-width: var(--layout-evidence); margin: 0 auto; padding: var(--space-8) var(--space-6); display: flex; flex-direction: column; gap: var(--space-2); }
.report-footer-mark { height: 24px; width: auto; }
/* The endorsement (brand guide §3, DESIGN 1.5 §10a): the words, then the CAMPFIRE logo as
   artwork. Once per surface. The mark is inline and takes the colour of the line it sits on. */
.report-endorse { display: inline-flex; align-items: center; gap: var(--space-2); }
.report-endorse .mark { display: block; }

/* The client gate: the client's band when there is a kit, one heading, one paragraph, no button —
   the next step is a reply to a person. It never suggests the reader did anything wrong. */
.report-notice { display: flex; flex-direction: column; }
.report-notice-band { min-block-size: 120px; }
.report-notice-inner { max-width: var(--layout-prose); margin: 0 auto; padding: var(--space-16) var(--space-6); display: flex; flex-direction: column; gap: var(--space-4); align-items: flex-start; }
.report-notice-mark { height: 36px; width: auto; }
.report-notice-title { font-size: var(--text-2xl); line-height: var(--leading-2xl); }
.report-notice-body { max-width: var(--measure-prose); }

@media (max-width: 720px) {
  .report-main { padding: var(--space-10) var(--space-4); }
  .report-section { margin-bottom: var(--space-10); }
  .report-creator-stats { grid-template-columns: repeat(2, 1fr); }
  .report-notice-inner { padding: var(--space-10) var(--space-4); }
}

/* ---------------------------------------------------------------------------
   Paper. Flat bands, no shadows, one section per page, repeated table headers,
   provenance in text rather than in a disclosure. Keep the two blocks in sync.
   --------------------------------------------------------------------------- */
@media print {
  .report { background: none; }
  .report .band, .report .band-tenant { background: none; color: var(--color-ink); border: 1px solid var(--color-line-default); box-shadow: none; }
  .report[data-preset="client-led"] .report-num { color: var(--color-ink); }
  .report .band-mark-screen { display: none; }
  .report .band-mark-print { display: block; }
  .report-main { max-width: none; padding: var(--space-8) 0; }
  .report-section { break-before: page; margin-bottom: var(--space-8); }
  .report-section:first-of-type { break-before: auto; }
  .report-creator, .report-post, .report-gallery-item, .report-table-wrap, .report-kpi, .report-embed, .card { break-inside: avoid; box-shadow: none; }
  .report-table thead { display: table-header-group; }
  .report-vp tfoot th, .report-vp tfoot td { background: none; border-top: 1px solid var(--color-line-default); }
  /* Seven columns have to fit the printable width, so the evidence table tightens on paper. */
  .report-table-wrap { overflow: visible; }
  .report-table { font-size: var(--text-sm); line-height: var(--leading-sm); }
  .report-table th, .report-table td { padding: var(--space-2); overflow-wrap: anywhere; }
  .report-scope-chips, .report-scope-note, .skip-link, .report-post-link, .report .metric-source { display: none; }
  .report-print-only { display: block; }
  .report a { text-decoration: none; }
  .report a::after { content: none; }
  .report-footer { background: none; }
  .report-footer-inner { padding: var(--space-6) 0; }
}

.report[data-print="1"] { background: var(--color-surface-panel); }
.report[data-print="1"] :is(.band, .band-tenant) { background: none; color: var(--color-ink); border: 1px solid var(--color-line-default); box-shadow: none; }
.report[data-print="1"][data-preset="client-led"] .report-num { color: var(--color-ink); }
.report[data-print="1"] .band-mark-screen { display: none; }
.report[data-print="1"] .band-mark-print { display: block; }
.report[data-print="1"] .report-main { max-width: none; padding: var(--space-8) 0; }
.report[data-print="1"] .report-section { break-before: page; margin-bottom: var(--space-8); }
.report[data-print="1"] .report-section:first-of-type { break-before: auto; }
.report[data-print="1"] :is(.report-creator, .report-post, .report-gallery-item, .report-table-wrap, .report-kpi, .report-embed, .card) { break-inside: avoid; box-shadow: none; }
.report[data-print="1"] .report-table thead { display: table-header-group; }
.report[data-print="1"] :is(.report-vp tfoot th, .report-vp tfoot td) { background: none; border-top: 1px solid var(--color-line-default); }
.report[data-print="1"] .report-table-wrap { overflow: visible; }
.report[data-print="1"] .report-table { font-size: var(--text-sm); line-height: var(--leading-sm); }
.report[data-print="1"] :is(.report-table th, .report-table td) { padding: var(--space-2); overflow-wrap: anywhere; }
.report[data-print="1"] :is(.report-scope-chips, .report-scope-note, .skip-link, .report-post-link, .metric-source) { display: none; }
.report[data-print="1"] .report-print-only { display: block; }
.report[data-print="1"] a { text-decoration: none; }
.report[data-print="1"] a::after { content: none; }
.report[data-print="1"] .report-footer { background: none; }
.report[data-print="1"] .report-footer-inner { padding: var(--space-6) 0; }

@media (forced-colors: active) {
  .report-creator, .report-post, .report-table-wrap, .report-embed { border-color: CanvasText; }
}


/* ---- faces/public/unsubscribe.css ---- */
/* The public unsubscribe page (/u). Light only, one column, nothing to decide but one button. */

.unsub {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-8) var(--space-4);
  background: var(--color-surface-ground);
}

.unsub-inner {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  max-width: var(--layout-prose);
  padding: var(--space-8);
  border-radius: var(--radius-card);
  background: var(--color-surface-panel);
  text-align: start;
}

.unsub-mark { display: block; height: 36px; width: auto; }
.unsub-title { margin: 0; color: var(--color-ink); }
.unsub-inner p { margin: 0; }
.unsub-form { margin-block-start: var(--space-2); }
