/* ============================================================================
 * The Bench Platform — Design Tokens
 * ============================================================================
 * Single source of truth for all visual values in the app. Organized in 3
 * strict tiers. Components reference ONLY Tier 2 (core roles) or Tier 3
 * (scoped/derived) tokens — never Tier 1 primitives, never inline color-mix().
 *
 *   Tier 1 — Primitives: raw scale-based color values (`--color-green-100`,
 *                        `--color-orange-burnt-500`). Never role-named.
 *                        Referenced only by Tier 2 and Tier 3 — never by
 *                        components. A handful of legacy non-scale names
 *                        remain (`--color-navy-deep/-mid/-light`,
 *                        `--color-text-dark`) — future cleanup ticket.
 *   Tier 2 — Core roles: the canonical semantic tokens. 15 brand/status/main
 *                        tokens — --primary (the accent TEXT: links, headers,
 *                        row actions, icons; a FILL reads --accent, the brand
 *                        pair — TBL2-1923), --surface, --surface-raised,
 *                        --surface-overlay, --text, --text-muted,
 *                        --text-inverse, --border, --success, --warning,
 *                        --danger, --info, --main-bg, --main-accent-1,
 *                        --main-accent-2. **Dark mode rewires Tier 2**, and
 *                        MIRRORS every Tier 3 / legacy token composed off
 *                        it — nothing adapts on its own (see the dark block).
 *   Tier 3 — Scoped:     specific-purpose tokens that compose off Tier 2.
 *                        --primary-hover, --highlight* (fill/shadow/border/
 *                        glow + solid), --status-{name}-bg/-text,
 *                        --hero-bg/-raised/-border, field-state aliases,
 *                        etc. NONE auto-adapts: declared here, each resolves
 *                        on <html>, so the ones composed off Tier 2 are
 *                        mirrored in the dark block (TBL2-1573). The
 *                        --status-*-bg / -text pairs reference brand
 *                        primitives directly, so they get dark-block
 *                        overrides with their own d-* values instead.
 *   Legacy aliases:      ~80 older token names (--bg-card, --text-primary,
 *                        etc.) retained as Tier 3 aliases to avoid breaking
 *                        untouched components. Do NOT introduce new uses;
 *                        prefer Tier 2/Tier 3 canonical names.
 *
 * Light is the default (`:root`). Dark is opt-in via either class
 * `body.dark-mode` (ContextService, PM profile) or attribute
 * `[data-theme="dark"]` on <html> (proto ThemeService). Both trigger the
 * same dark tokens. The dark block overrides the 12 theme-adaptive Tier 2
 * tokens + --main-bg (navy in dark, cream in light per Joey) + the 5
 * black-shadow depths + a handful of Tier 3 exceptions that reference Tier 1
 * directly. --main-accent-1 and --main-accent-2 stay static (rose/peach).
 *
 * Full system: docs/development/design-tokens.md
 * Migration progress: docs/development/design-tokens-migration.md
 * ============================================================================ */

/* K-BRAND-2.1 (2026-07-31) — GROUNDS ARE PER-SURFACE-ROLE. `[data-ground]`
 * scopes a SUBTREE onto a ground (custom properties resolve at the nearest
 * defining ancestor): stamp `data-ground="espresso"` on a shell/section for
 * the espresso ground (talent-facing surfaces), `data-ground="light"` to
 * re-pin a light island inside an espresso subtree. The legacy theme
 * triggers (body.dark-mode / [data-theme]) share the same blocks until the
 * toggle retires. */
:root,
[data-theme="light"],
[data-ground="light"] {
  /* ═══════════════════════════════════════════════════════════════════════
   * TIER 1 — Primitives (raw hex — never referenced directly by components)
   * Grouped by palette. Dark primitives live here too so the dark block
   * below only has to rewire Tier 2 pointers, not redeclare hex.
   *
   * The [data-theme="light"] selector lets any subtree opt out of dark
   * mode by setting data-theme="light" on a wrapper element. Used for
   * brand-static surfaces like the public/auth flow (login, apply,
   * forgot, etc.) where the design intent is "always light regardless
   * of the user's global theme toggle".
   * ═══════════════════════════════════════════════════════════════════════ */

  /* Navy family (nav / brand — static on both themes) */

  /* Orange family */
  --color-orange-500:       #FC6804;   /* dark --primary */
  --color-orange-600:       #E55D00;
  --color-orange-burnt-50:  #FEF0EA;   /* light --highlight-fill (Joey accent-light) */
  --color-orange-burnt-500: #E85D26;   /* light --primary (Joey burnt orange) */
  --color-orange-burnt-600: #D04D1A;   /* light --primary-hover (Joey accent-hover) */

  /* Cream / warm grays (light surfaces & borders) */
  --color-cream-50:       #F7F4EF;
  --color-white:          #FFFFFF;
  --color-warm-100:       #EDE7DC;
  --color-warm-200:       #EAE4DA;

  /* Warm grays (light text — warm stack, replaces cool grays) */
  --color-gray-900:       #1A1714;
  --color-gray-600:       #78716C;
  --color-gray-400:       #A8A29E;

  /* Cool grays (dark text) */
  --color-text-dark:        #F0F2F8;
  --color-text-muted-dark:  #A0AECF;

  /* Status — light palette (Joey values on a Tailwind-like scale)
   * Backgrounds (-100) + text (-600/-700/-800/-900). The old --color-*-500
   * names were renamed to match the scale accurately. */
  --color-green-100:      #DCFCE7;
  --color-green-900:      #14532D;
  --color-amber-100:      #FEF3C7;
  --color-amber-700:      #B45309;
  --color-red-100:        #FEE2E2;
  --color-red-600:        #DC2626;
  --color-blue-100:       #DBEAFE;
  --color-blue-700:       #026A8E;   /* brand teal (banner gradient stop) */
  --color-blue-800:       #1E40AF;

  /* Purple scale — new family (neutral status pair) */
  --color-purple-100:     #F3E8FF;
  --color-purple-400:     #C084FC;   /* dark-mode neutral text */
  --color-purple-700:     #7E22CE;   /* light-mode neutral text */

  /* Status — dark palette (lighter / more saturated for contrast on navy) */
  --color-green-400:      #4ADE80;
  --color-amber-400:      #FBBF24;
  --color-red-400:        #F87171;
  --color-blue-400:       #60A5FA;

  /* Brown scale — dark warm surface (hero, opt-in) */
  --color-brown-800:      #241F18;
  --color-brown-900:      #1C1814;

  /* Hero accent family (rose + peach — used by prominent dark headers) */
  --color-rose-400:       #E88CA5;
  --color-peach-400:      #F4A261;

  /* ═══════════════════════════════════════════════════════════════════════
   * TIER 2 — Semantic (components use ONLY these)
   * Light defaults. Dark block below rewires the pointers to the dark
   * palette; nothing else changes.
   * ═══════════════════════════════════════════════════════════════════════ */

  /* Brand (9) — K-BRAND-1.1 (2026-07-31): THE WASH. Tier 2 re-points onto the
   * vendored brand palette (block A at the bottom of this file). Light ground =
   * the brand light set; the dark block below carries the espresso-ground set.
   * --surface keeps its exact value (#F7F4EF = the brand's audited Paper — the
   * old cream-50 and the brand paper are the same hex); cards go white → the
   * audited Card-light. Page GRADIENTS + the lens material arrive in Phase 2 —
   * these are the brand's flat fallbacks. */

  /* THE ACCENT PAIR — set ONCE per ground, read everywhere (brand CLAUDE.md
   * § Color). Light ground: Deep Orange + white ink. The dark block below
   * flips the pair to Light Orange + espresso ink (must stay ABOVE it in the
   * file so the override cascades — do not move to the bottom brand block). */
  --accent:               var(--deeporange);
  --accent-ink:           #FFFFFF;

  /* TBL2-1923 (K-1028-10, Carlos 2026-10-28, DS-1 = A) — --primary is the accent
   * TEXT role: links, headers, row actions, icons. The FILL is --accent, the
   * brand's own pair above, and every fill in the app reads it (TBL2-1923 moved
   * 196 background sites and 84 fill-paired borders off --primary; the fills'
   * values are untouched, K-1028-4). Deep Orange reads 4.72:1 on paper and
   * 4.38:1 on --surface-raised, under AA either way once a row is opaque; this
   * value reads 6.25 and 5.79 (the register's DS-1 table). A literal, not a
   * ramp step: the vendored ramp has no step between --orange-600 (#C63B26) and
   * --orange-700 (#9B291F), and the value is Carlos's. Fixed at the token, never
   * per site (TBL2-1313). */
  --primary:              #A6301F;
  --surface:              var(--surface-paper);
  --surface-raised:       var(--surface-card-light);
  --surface-overlay:      var(--almond-400);
  --text:                 var(--espresso);
  /* K-v195-Ink (2026-08-03) — Carlos. Was --espresso-300 (#776A62), which lands
   * at 4.41:1 on --surface-card-light and misses AA by 0.09. Measured with the
   * conformance runner's pixel sampler across all 15 audited routes, this pair
   * ALONE accounted for 348 of 459 contrast violations (459 -> 111). Every other
   * candidate cause was a long tail of genuine per-surface work.
   *
   * --espresso-400 is the next step down the SAME package ramp (5.71:1) — no
   * value invented, nothing vendored touched. tokens.json ships the ramp but
   * does not prescribe which step is muted text, so the STEP is our mapping to
   * choose. The espresso blocks below keep --almond-600: this is a light-ground
   * fix and dark grounds carry their own ink. */
  --text-muted:           var(--espresso-400);
  /* TBL2-1931 (K-1029-1 BUILD 5, DS-1 = A: "text on the hero ground reads a hero-ink
   * token or sits on an opaque island") — the muted ink for text whose ground is the
   * hero gradient, through a lens panel or bare. --text-muted reads 3.46 to 4.43 there
   * (the key-players island, the team tracker, the client hero, the portal disclaimer,
   * measured on dev); --espresso-600 is the first step of the vendored ramp that reads
   * 4.5 on every one of those grounds (5.27 on the darkest, (234,173,125)). The hero's
   * bare lower right (--hero-3) is under 4.5 for every ink but --text: that is a panel
   * to add, not an ink. Espresso keeps its own muted ink (the dark block). */
  --text-muted-on-hero:   var(--espresso-600);
  /* TBL2-1931 (Copilot, PR #3253) — a toned word on the light hero (the IC answers' YES / NO):
   * --basil-ink and --cherry-ink read 3.70 / 3.73 on the darkest hero ground, so each is
   * mixed toward espresso just until it reads 4.5 on every hero ground measured (basil 74%,
   * #14553A; cherry 78%, #941328). Espresso keeps the ground's own status inks (dark block). */
  --status-success-text-on-hero: color-mix(in srgb, var(--basil-ink) 74%, var(--espresso));
  --status-error-text-on-hero:   color-mix(in srgb, var(--cherry-ink) 78%, var(--espresso));
  /* TBL2-1931 (BUILD 5) — the greeting's name accent: blush-700 on the light ground,
   * the brand welcome lockup (K-BRAND-2.4). Espresso has its own step (dark block). */
  --greeting-name-ink:    var(--blush-700);
  --text-light:           var(--espresso-200);
  --text-inverse:         var(--accent-ink);
  --border:               var(--almond-500);

  /* Status (4) — brand statuses (K-BRAND-1.1). Tier 2 carries the TEXT-SAFE
   * face of each status (honey's raw #FFAA00 fails on light grounds, so its
   * solved ink is the Tier-2 value); the Tier-3 pairs below carry the chip
   * construction (solved ink on the 18% soft wash). --info lands on teal per
   * ruling R-1 (brand has no blue; teal carries Sage-sync identity +
   * informational accents; in-flight statuses migrate to honey per-surface in
   * Phase 4). */
  --success:              var(--basil);
  --warning:              var(--honey-ink);
  --danger:               var(--cherry);
  /* K-v193-InfoHoney (2026-08-03) — Carlos: --info FOLDS INTO HONEY.
     The brand package defines exactly four statuses — basil (success),
     honey (in progress / coming due soon), cherry (overdue / negative),
     sage (completed / no action) — and says "do not invent a fifth".
     --info was that fifth, and it spent the TEAL ACCENT on status duty.
     An audit of its 79 consumer files showed it marking "Good Match",
     "Interview requested", "Syncing to Ramp…" — in-progress states, which
     is honey's definition exactly. Kept as an alias rather than deleted so
     the 105 call sites keep compiling; they now render honey. */
  --info:                 var(--honey-ink);

  /* Main (3) — prominent surfaces shared by chat-widget, PM/internal profile
   * hero, tbl-tags/segmented. K-BRAND-1.1: navy exits the system — dark
   * --main-bg is espresso now; accents re-point rose/peach → blush/hero-peach
   * (nearest brand equivalents, same warm role). */
  --main-bg:              var(--surface);
  --main-accent-1:        var(--blush-500);
  --main-accent-2:        var(--hero-2);

  /* STATIC INK OVER ESPRESSO (TBL2-1334 item 1).
   * Two proto shells use hero ramp stops as FOREGROUND INK on espresso/ember
   * grounds, chosen for measured contrast under K-v208 (G6-15) — --primary had
   * failed there at 3.52:1 / 3.38:1. Those are accessibility values, not ground
   * values, and they must NOT follow the dark ground ramp: with the espresso
   * ramp applied they would resolve #4C3E33 and #422F21, measuring 1.34:1 and
   * 1.08:1 on espresso-800 — invisible text.
   * Declared as their own static tokens so the linkage is explicit and cannot be
   * broken by a future ramp change. (Copilot, PR #1771.) */
  --hero-ink-cream:       #FCE8D1;  /* 11.50:1 on espresso-800 */
  --hero-ink-peach:       #F5C08E;  /*  8.37:1 on espresso-800 */

  /* THE STATIC HERO PLATE (TBL2-1334 item 1).
   * The public/PM profile avatar plate (`_public-profile-hero.scss`) paints
   * ground-hero, but it is NOT a page ground: the initials sit on it in static
   * var(--espresso) ink precisely because "the plate's gradient does not flip
   * with the theme". The dark ramp would have made that premise false and the
   * initials dark-on-dark, with no light lock on the PM profile to save them.
   * These four are the brand Hero stops held static so that plate can re-pin
   * from tokens rather than raw hex. (Copilot, PR #1771.) */
  --hero-plate-0:         #E5CBBC;
  --hero-plate-1:         #FCE8D1;
  --hero-plate-2:         #F5C08E;
  --hero-plate-3:         #CB7C50;

  /* ═══════════════════════════════════════════════════════════════════════
   * TIER 3 — Scoped / derived tokens
   * ═══════════════════════════════════════════════════════════════════════
   * Specific-purpose tokens that compose off Tier 2 (mostly) or Tier 1 (for
   * the status bg pairs that must match exact cream shades). All consumed
   * only by components that need them — never the primary dependency.
   *
   * None of them adapts in dark on its own. Those composed off a token the
   * dark block redefines are MIRRORED there with identical text (the dark
   * block's header says why); the status bg/text pairs, which reference
   * brand primitives directly, are overridden there with their d-* values.
   * ═══════════════════════════════════════════════════════════════════════ */

  /* Primary variant — CTA hover (K-BRAND-1.1: one ramp step down from Deep Orange) */
  --primary-hover:        var(--orange-700);

  /* Highlight family — 4 role-based buckets + bare solid. Role names
   * describe USE (fill / shadow / border / glow), not hue intensity.
   * --highlight-fill uses Joey's hand-picked tint (#FEF0EA); dark block
   * overrides to a color-mix derived from the accent.
   * TBL2-1923: the family is FILL-side, so it composes off --accent, the fill
   * pair, and not off --primary, which is now the accent TEXT. Text that read
   * the bare --highlight reads --primary (51 sites moved). */
  --highlight:            var(--accent);
  --highlight-fill:       var(--orange-100);
  --highlight-shadow:     color-mix(in srgb, var(--accent) 20%, transparent);
  --highlight-border:     color-mix(in srgb, var(--accent) 30%, transparent);
  --highlight-glow:       color-mix(in srgb, var(--accent) 40%, transparent);

  /* Status bg/text pairs — K-BRAND-1.1: the brand chip construction (SOLVED
   * ink on the 18% soft wash of the base; the *-soft tokens ARE that wash,
   * the *-ink tokens are computed upstream — never hand-derive). Info rides
   * teal (R-1); neutral rides sage (brand "completed / no action"); the
   * basil-vs-sage SEMANTIC split (completed→sage) lands Phase 2 behind the
   * chip primitive. Dark block overrides to the d-* espresso family. */
  --status-success-bg:    var(--basil-soft);
  --status-success-text:  var(--basil-ink);
  --status-warning-bg:    var(--honey-soft);
  --status-warning-text:  var(--honey-ink);
  --status-error-bg:      var(--cherry-soft);
  --status-error-text:    var(--cherry-ink);
  /* K-v193-InfoHoney — info chips take honey's solved ink + 18% wash. */

  /* K-v193-Avatar (2026-08-03) — Carlos: an avatar with no photograph falls back
     to ONE colour + initials, palette-compliant: the Espresso / Paper pair.
     Set here once per ground and read everywhere — pd-avatar previously defaulted
     to a GRADIENT (--highlight → --bg-elevated, a prohibited legacy alias) and
     cp-avatar hashed each name across a 7-colour palette, so the same person
     could be a different colour on two surfaces.
     Circle takes ESPRESSO and the initials take PAPER: the page grounds are all
     paper-family now, so a paper circle would dissolve into them. */
  --avatar-fallback-bg:   var(--espresso);
  --avatar-fallback-ink:  var(--surface-paper);

  /* TBL2-1923 (K-1028-10, DS-8 = A; kind sheet plate = A) — the ink an initials
   * plate takes from its OWN luminance: espresso on a light plate, almond on a
   * dark one (the crossover is 0.21 relative luminance; above it espresso reads
   * better, below it almond). The plate is the ground, not the page, so both are
   * STATIC by role and not mirrored. The client-logo component picks one from the
   * plate colour it is given (shared/utils/plate-ink.ts); a plate it cannot read
   * keeps the fallback pair above. A white ring (the client page, the portal)
   * reads the light one. */
  --ink-on-light-plate:   var(--espresso);
  --ink-on-dark-plate:    var(--almond);

  --status-info-bg:       var(--honey-soft);
  --status-info-text:     var(--honey-ink);
  --status-neutral-bg:    var(--sage-soft);
  --status-neutral-text:  var(--sage-ink);

  /* TBL2-1950 — each soft wash composited on the row surface, opaque. The solved inks above are
   * solved on the wash over --surface-raised; a data-grid row's hover step is --surface-overlay, on
   * which they read 3.92 to 4.26:1. The hovered row swaps the translucent washes for these, so the
   * pill reads as at rest (4.51 to 5.06) and axe and the pixel sampler read one colour. The base is
   * the hue the wash is 18% of, per ground, as the bg pairs are; the composite is mirrored. */
  --status-success-base:      var(--basil);
  --status-warning-base:      var(--honey);
  --status-error-base:        var(--cherry);
  --status-info-base:         var(--honey);
  --status-neutral-base:      var(--sage);
  --status-success-bg-on-row: color-mix(in srgb, var(--status-success-base) 18%, var(--surface-raised));
  --status-warning-bg-on-row: color-mix(in srgb, var(--status-warning-base) 18%, var(--surface-raised));
  --status-error-bg-on-row:   color-mix(in srgb, var(--status-error-base) 18%, var(--surface-raised));
  --status-info-bg-on-row:    color-mix(in srgb, var(--status-info-base) 18%, var(--surface-raised));
  --status-neutral-bg-on-row: color-mix(in srgb, var(--status-neutral-base) 18%, var(--surface-raised));

  /* K-v197-SolidStatus (2026-08-04) — Carlos: "solid does not mean only using
   * white, each status type has its options", and the exact hexes are already in
   * the brand file, so these are TOKENISED rather than hand-picked.
   *
   * WHY SOLID EXISTS ALONGSIDE SOFT. The soft pair is an 18% wash, so the chip
   * inherits whatever is beneath it. On the hero gradient that ground moves:
   * measured on client-invoice, the SAME "Draft" chip runs 4.98 at the top of
   * the page and 4.48 at the bottom — the package solves its soft inks for a
   * PAPER ground ("Solved for 4.5:1 on an 18 percent wash of the base. Do not
   * hand pick."), which our gradient surfaces do not provide. A solid chip is
   * OPAQUE, so it is position-independent by construction and the drift cannot
   * occur. That is the whole reason to have it.
   *
   * The ink is NOT one rule — it is per status, and every pairing below is a
   * package value measured to clear AA with margin:
   *   basil  #006C48 + white           6.48
   *   cherry #D2042D + white           5.53
   *   honey  #FFAA00 + espresso        7.19   (white on honey is 1.91 — fails)
   *   sage   #A7B8A5 + espresso        6.56   (white on sage light is 3.57)
   * ⚠️ Sage is the one pairing that reaches for the ESPRESSO-mode base (--d-sage)
   * on a light ground: no combination of sage's light base clears AA, and this
   * one does. Deliberate, and the only mixed-variant pair here. */
  --status-solid-success-bg:   var(--basil);
  --status-solid-success-text: var(--color-white);
  --status-solid-error-bg:     var(--cherry);
  --status-solid-error-text:   var(--color-white);
  --status-solid-warning-bg:   var(--honey);
  --status-solid-warning-text: var(--espresso);
  --status-solid-info-bg:      var(--honey);
  --status-solid-info-text:    var(--espresso);
  --status-solid-neutral-bg:   var(--d-sage);
  --status-solid-neutral-text: var(--espresso);
  /* K-v199-S4 (D7 + D7b, Carlos 2026-08-05) — THE MONEY-PIPELINE TONE.
   * A fifth SOLID pair, and deliberately not a fifth STATUS: the four-status
   * canon (basil / honey / cherry / sage) is untouched. This is the R-1
   * Sage-sync IDENTITY colour — the same teal that carries "this record talks
   * to Sage" everywhere else — worn by the terminal money states so the whole
   * pipeline reads as one thing: Approved-Synced, Synced to Sage, Sent in
   * Portal, and (D7b) PAID.
   *
   * Paid joining this family is the point of D7b. It was sage tint in billing
   * and honey tint on project-detail-active — the same status, two tones, on
   * two surfaces a PM sees in the same session. Carlos: "one money-pipeline
   * colour".
   *
   * Ink is WHITE, measured, not chosen: white on #38715E is 5.69:1; espresso
   * on it is 2.41 and fails. (The audit estimated ~4.9 — the real figure is
   * higher, and either way it clears AA with margin.)
   *
   * NOT --sage / --d-sage (those are "completed, no action", the NEUTRAL tone)
   * and NOT --basil (that is success). A synced invoice is not "done", it is
   * "in the ledger", which is why it gets the sync identity rather than a
   * lifecycle tone. */
  --status-solid-synced-bg:    var(--teal-700);
  --status-solid-synced-text:  var(--color-white);

  /* K-v199-S6 (R-B, Carlos 2026-08-05) — THE SCROLLBAR PAIR.
   * Every vertical scroll surface in the proto was riding the UA-DEFAULT grey
   * bar — main.hub__content (the main scroller on 20 routes), every drawer
   * body, the profile and admin rails. The three sites that WERE styled
   * disagreed with each other: 5px on $border-default, 4px on --border, and a
   * global .custom-scrollbar at 5px on --text-muted.
   * One pair, consumed through the `brand-scrollbar` mixin
   * (shared/_scrollbar.scss). The espresso ground re-points the thumb
   * with the rest of the glass family, so one mixin serves both grounds.
   * Track is transparent by design: the bar is a thumb on the surface, not a
   * channel cut into it. */
  --scrollbar-thumb:           var(--border);
  --scrollbar-track:           transparent;
  /* K-TalSweep-4 (2026-06-11) — status BORDER shades. Components were
   * inlining color-mix(status 30%, transparent) for badge/island
   * borders (banned in component SCSS); the shade now lives here. */
  --status-success-border: color-mix(in srgb, var(--success) 30%, transparent);
  --status-warning-border: color-mix(in srgb, var(--warning) 30%, transparent);
  --status-error-border:   color-mix(in srgb, var(--danger) 30%, transparent);
  --status-info-border:    color-mix(in srgb, var(--info) 30%, transparent);

  /* Slice K67 (2026-05-06): chip-tint family — 50%-transparent variants
   * of the status-*-bg tokens. Used by the client-list CBU chips so the
   * pills don't pop out as much as full status-bg fills. Composes off
   * the status-*-bg tokens the dark block overrides, so the dark block
   * mirrors these too (TBL2-1573). */
  --chip-tint-success:    color-mix(in srgb, var(--status-success-bg), transparent 50%);
  --chip-tint-info:       color-mix(in srgb, var(--status-info-bg),    transparent 50%);
  --chip-tint-warning:    color-mix(in srgb, var(--status-warning-bg), transparent 50%);

  /* Hero scoped (dark warm surface embedded in light mode — static, opt-in).
   * K-BRAND-1.1: the deep-brown hero stack re-points to brand ESPRESSO
   * (#3A2A1F/#422F21 — a step warmer/lighter than the old #1C1814/#241F18).
   * Supersedes the K-Brown-1 value lock per the brand-supersedes-canon ruling. */
  --hero-bg:              var(--espresso-800);
  --hero-bg-raised:       var(--espresso-700);
  --hero-border:          #FFFFFF14;

  /* Menu chrome — composes off the hero family, so the nav reads espresso in
   * BOTH grounds (brand espresso ground rule). Active item = the espresso-
   * ground accent (Light Orange) per the brand accent-pair rule. */
  --menu-bg:              var(--hero-bg);          /* espresso-800 */
  --menu-bg-raised:       var(--hero-bg-raised);   /* espresso-700 */
  --menu-border:          var(--hero-border);      /* #FFFFFF14 */
  --menu-text:            var(--almond);           /* almond copy on espresso */
  --menu-text-muted:      var(--almond-600);
  --menu-text-active:     var(--lightorange);      /* espresso-ground accent */
  --menu-item-hover:      color-mix(in srgb, var(--color-white) 10%, transparent);

  /* Status-pill family — K-BRAND-1.1: re-cut onto the brand chip construction
   * (solved ink + soft wash). The hardcoded #22AF47/#B8860B/#7C3AED die here;
   * purple → HONEY per ruling R-2 ("processing and in-progress are similar").
   * Info rides teal (R-1). Dark block overrides to the d-* family. */
  --pill-info-text:       var(--teal-700);
  --pill-info-bg:         color-mix(in srgb, var(--teal-700) 12%, transparent);
  --pill-success-text:    var(--basil-ink);
  --pill-success-bg:      var(--basil-soft);
  --pill-warning-text:    var(--honey-ink);
  --pill-warning-bg:      var(--honey-soft);
  --pill-danger-text:     var(--cherry-ink);
  --pill-danger-bg:       var(--cherry-soft);
  --pill-purple-text:     var(--honey-ink);
  --pill-purple-bg:       var(--honey-soft);
  --pill-muted-text:      var(--text-muted);
  --pill-muted-bg:        color-mix(in srgb, var(--text-muted) 12%, transparent);

  /* Banner — K-BRAND-1.1: the navy→teal gradient dies; the brand banner is
   * SOLID Deep Orange with white ink, never glass, one per screen. Kept as a
   * (solid) token so the existing background: var(--banner-gradient) consumers
   * re-point without markup changes. */
  --banner-gradient:      var(--deeporange);

  /* Lance banner scoped — K-BRAND-1.1: peach tint → brand GOLD tint (the Lance
   * identity color). The full gold-carrier field component lands in Phase 3;
   * this keeps the existing Lance banner surfaces on-brand meanwhile. */
  --bg-lance-banner:        color-mix(in srgb, var(--gold-400) 22%, var(--surface));
  --bg-lance-banner-raised: color-mix(in srgb, var(--gold-400) 32%, var(--surface));
  --text-lance-banner:      var(--gold-800);
  --border-lance-banner:    color-mix(in srgb, var(--gold-500) 45%, transparent);

  /* Canonical Lance marker — K-BRAND-1.1: gold IS the Lance identity now
   * (brand rule; supersedes K-v141-Marker's orange lock per the
   * brand-supersedes-canon ruling). The flat currentColor MARK + motion
   * states replace the pulse in Phase 3; this recolors the ~70 existing
   * marker instances meanwhile.
   * K-v214c (Carlos, 2026-08-13) — ESPRESSO, per the icon spec ("espresso —
   * default, any light ground"; gold only where Lance himself is the
   * subject). Was gold-600, which read muddy at mark sizes — espresso also
   * clears contrast with margin. The espresso-ground override below stays
   * bright so marks never vanish on dark artifacts. */
  --lance-marker-color:     var(--espresso);

  /* ═══════════════════════════════════════════════════════════════════════
   * Non-color tokens (theme-agnostic)
   * ═══════════════════════════════════════════════════════════════════════ */

  /* Typography */
  /* K81d (2026-05-12) — Carlos: legacy `--font-sans` (Montserrat) +
   * `--font-serif` (Cormorant Garamond) repointed at the canonical
   * tokens. After the K79o Montserrat CDN sweep, Montserrat was never
   * actually loaded — consumers of `--font-sans` got a system fallback
   * which looked off vs the canonical Outfit body. Aliasing both to
   * the canonical tokens lets any straggler consumer render correctly
   * without a per-file sweep. */
  --font-sans:          'Outfit', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  /* K-BRAND-1.4 (2026-07-31): the brand type flip — Literata carries display
   * (supersedes the v7 §A3 Playfair canon per the brand-supersedes-canon
   * ruling); Lance speaks Ibarra Real Nova (ROMAN — the italic pairings at
   * existing consumers unwind per-surface in Phases 3/4; brand reserves
   * italic for Lance quoting the user). Outfit body unchanged. Weight
   * normalization (brand headings are 500, the app's title rules say 700)
   * is deliberately NOT part of the wash — it rides the Phase-2 flagships +
   * Phase-4 waves where each surface is verified. */
  --font-serif:         'Literata', Georgia, serif;
  /* K-BRAND-5.6 (2026-08-02) BACKSTOP: --font-mono re-pointed at the body face.
   * JetBrains Mono / Fira Code were never loaded anywhere (no @font-face, no
   * index link) so this token only ever resolved to a local system mono. All
   * first-class consumers were retired in the brand waves; any straggler now
   * renders Outfit. Paper surfaces are unaffected — the paper fence
   * (shared/_paper-fence.scss) redefines --font-mono in its own scope. */
  --font-mono:          var(--font-body);
  --font-body:          'Outfit', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-title:         'Literata', Georgia, serif;
  --font-lance:         'Ibarra Real Nova', Georgia, serif;

  --font-2xs:           0.5rem;
  --font-xs:            0.625rem;
  --font-sm:            0.6875rem;
  --font-md:            0.75rem;
  --font-base:          0.8125rem;
  --font-lg:            1rem;
  --font-xl:            1.25rem;
  --font-2xl:           1.5rem;
  --font-metric:        1.75rem;

  --weight-regular:     400;
  --weight-medium:      500;
  --weight-semibold:    600;
  --weight-bold:        700;
  --weight-extrabold:   800;

  --tracking-tight:     0.2px;
  --tracking-normal:    0.4px;
  --tracking-wide:      0.5px;
  --tracking-caps:      0.63px;

  --leading-tight:      1.2;
  --leading-normal:     1.5;
  --leading-relaxed:    1.6;

  /* Spacing */
  --space-0:            0;
  --space-0-5:          2px;
  --space-1:            4px;
  --space-1-5:          6px;
  --space-2:            8px;
  --space-3:            12px;
  --space-4:            16px;
  --space-5:            20px;
  --space-6:            24px;
  --space-8:            32px;
  --space-10:           40px;
  --space-12:           48px;

  /* Border radius — K-BRAND-1.5 (R-11): the legacy scale re-points onto the
   * brand radius scale. sm/md both land on control (10px — buttons, inputs,
   * selects; the Bootstrap bridge follows), lg = card (14, exact match),
   * full = chip (999). Per-case card-vs-control judgment on the ~800
   * hardcoded px radii rides the Phase-4 waves. New code uses the named
   * brand tokens (--radius-chip/control/card/table/panel/screen) directly. */
  --radius-sm:          var(--radius-control);
  --radius-md:          var(--radius-control);
  --radius-lg:          var(--radius-card);
  --radius-full:        var(--radius-chip);

  /* Legacy radius aliases — do not use in new code */
  --radius-xs:          var(--radius-sm);
  --radius-xl:          var(--radius-lg);

  /* Shadows — light-mode defaults use a warm rgba scale (Joey). The dark
   * block below overrides the 5 black-shadow depths (stronger black opacity
   * on navy surfaces). --shadow-focus derives from --primary via color-mix,
   * so it auto-adapts. */
  --shadow-none:        none;
  --shadow-sm:          0 1px 3px rgba(28, 25, 23, 0.05), 0 2px 6px rgba(28, 25, 23, 0.04);
  --shadow-md:          0 3px 18px rgba(28, 25, 23, 0.08), 0 1px 4px rgba(28, 25, 23, 0.04);
  --shadow-card:        0 3px 18px rgba(28, 25, 23, 0.08), 0 1px 4px rgba(28, 25, 23, 0.04);
  --shadow-lg:          0 8px 40px rgba(28, 25, 23, 0.13), 0 2px 8px rgba(28, 25, 23, 0.06);
  --shadow-elevated:    0 8px 40px rgba(28, 25, 23, 0.13), 0 2px 8px rgba(28, 25, 23, 0.06);
  --shadow-focus:       0 0 0 2px color-mix(in srgb, var(--primary) 22%, transparent);

  /* Control heights */
  --h-xs:               24px;
  --h-sm:               32px;
  --h-md:               40px;
  --h-lg:               48px;

  /* Icon sizes */
  --ic-sm:              14px;
  --ic-md:              16px;
  --ic-lg:              20px;
  --ic-xl:              24px;

  /* Containers */
  --container-narrow:   720px;
  --container-default:  1200px;
  --container-wide:     1440px;

  /* Transitions — K-BRAND-1.5: legacy names re-point onto the brand motion
   * scale (instant 90 / quick 160 / base 240; slow-420 exists as
   * --motion-slow for new code). Standard easing replaces ease-out. */
  --duration-fast:      var(--motion-instant);
  --duration-normal:    var(--motion-quick);
  --duration-slow:      var(--motion-base);
  --ease-default:       var(--ease-standard);

  /* Z-Index scale */
  --z-base:             0;
  --z-card:             1;
  --z-sticky:           10;
  --z-dropdown:         10;
  --z-overlay:          50;
  /* TBL2-1927 (DS-9): both were read with a fallback and declared nowhere,
   * so the fallback painted; declared here at the value that rendered. */
  --z-nav:              50;
  --z-popover:          60;
  --z-drawer:           100;
  --z-modal:            100;
  --z-toast:            200;
  --z-tooltip:          300;

  /* Nav (STATIC — always deep brown in both themes per Carlos R2
   * lock 2026-05-14. The main navbar is the one consistent brand
   * chrome users see everywhere; brown matches the editorial
   * vocabulary the rest of the proto is moving toward (hero, public
   * profile, Lance banner dark). Previously navy `--color-navy-500`;
   * flipped to point at the new `--menu-*` Tier 3 family so any
   * future menu/dark-mode polish flows from one source. */
  --nav-bg:             var(--menu-bg);
  --nav-text:           var(--menu-text);
  --nav-blur:           0;
  --nav-border:         var(--menu-border);
  --nav-item-hover:     var(--menu-item-hover);

  /* Lance brand button — intentionally matches the nav chrome (static deep
   * brown, same in both themes) so the Lance CTA reads as distinct from the
   * orange --primary onboarding CTA. See TBL2-981 item 5. */
  --brand-lance:        var(--nav-bg);

  /* Lance gold logo family (TBL2-1064 Phase C — gold-triangle icon). STATIC:
   * brand gold reads the same in light + dark. K-BRAND-1.1: the old yellower
   * #E4BE47 ramp re-points onto the BRAND gold ramp (#CEA05D core) so the
   * two-golds problem dies; the triangle icon itself is replaced by the flat
   * currentColor mark in Phase 3. */
  --lance-gold:           var(--gold-500);
  --lance-gold-bright:    var(--gold-200);
  --lance-gold-light:     var(--gold-300);
  --lance-gold-mid:       var(--gold-600);
  --lance-gold-deep:      var(--gold-700);
  --lance-gold-dark:      var(--gold-800);
  --lance-gold-frame-hi:  var(--gold-300);
  --lance-gold-frame-lo:  var(--gold-700);
  --lance-gold-back-hi:   var(--gold-400);
  --lance-gold-back-lo:   var(--gold-700);

  /* TBL2-1931 (K-1029-5, L-1 = B, Carlos 2026-10-29) — the Lance drawer keeps its gold
   * ground and its text is espresso. Gold Gradient B runs #CEA05D to #82561C, and
   * espresso reads 5.76:1 on the first stop and 2.15 on the last, so the darker end is
   * lifted just until espresso reads 4.5 on every band: --gold-600 (#B98D4C), 4.56, the
   * next step up the vendored ramp. STATIC: the drawer is the same gold on both grounds. */
  --lance-drawer-ground-lo: var(--gold-600);
  --lance-drawer-ink:       var(--espresso);
  --lance-gold-panel:     var(--espresso-900);
  --lance-gold-ring:      color-mix(in srgb, var(--lance-gold) 50%, transparent);
  --lance-gold-glint:     color-mix(in srgb, var(--color-white) 90%, transparent);
  /* K-v196-S8 — the focus GLEAM's travelling band. A softer sibling of the
   * glint (55 vs 90): the glint is a highlight that sits, this sweeps across
   * the gold carrier once on focus and is gone. Minted here because color-mix()
   * is banned in component scss — the brand lint caught it in the gleam's first
   * form and it belongs at Tier 3 anyway. */
  --lance-gleam-band:     color-mix(in srgb, var(--color-white) 55%, transparent);

  /* K-BRAND-3.1/3.2 — the ONE s12 gold-carrier recipe (Lance field wrapper +
   * framed app-icon ground) + its support inks. Minted here because
   * color-mix() is banned in component scss. STATIC like the logo — the
   * carrier never flips with the ground; ink on it is always espresso.
   * K-v206-S1 (2026-08-10, Carlos) — softening RETIRED: the color-mix blends
   * (60/90/45) muted the metallic band; the client's s9 `.lancefield` uses
   * the RAW goldc scale at 26/52/76% and Carlos ruled the surfaces equalize
   * to it exactly. The sheen + drop values below are the s9 literals, minted
   * as Tier-3 aliases because raw rgba is banned in component scss. */
  --lance-gold-carrier: linear-gradient(
    112deg,
    var(--goldc-0),
    var(--goldc-1) 26%,
    var(--goldc-2) 52%,
    var(--goldc-3) 76%,
    var(--goldc-4)
  );
  --lance-field-sheen:        inset 0 1px 0 rgba(255, 255, 255, 0.34);
  --lance-field-shadow:       0 10px 24px -14px rgba(58, 42, 31, 0.5);
  /* K-v206-S4 — the s9 welcome lockup's NAME line (greet-2): blush emphasis.
   * Role-named Tier 3 so components never reach the blush primitives. */
  --greeting-name-ink:        var(--blush-700);
  --lance-gold-ring-soft:     color-mix(in srgb, var(--gold-500) 35%, transparent);
  /* TBL2-1410 (Carlos, live session 2026-10-28) — the chip rule in gold: the fill of a
   * Lance BUTTON that sits beside a primary. The gold carrier is the field recipe and
   * runs dark at both ends, so on a short button it swallows the espresso ink; the
   * button takes this wash with a --lance-gold hairline and --lance-ink instead.
   * Mixed over ALMOND, not transparent, so it is opaque and static like the carrier
   * (a translucent wash would go dark over the espresso ground and take the ink with
   * it). Minted here because color-mix() is banned in component scss. */
  --lance-gold-wash:          color-mix(in srgb, var(--gold-500) 22%, var(--almond));
  --lance-gold-wash-hover:    color-mix(in srgb, var(--gold-500) 35%, var(--almond));
  --lance-ink:                var(--espresso);
  --lance-field-placeholder:  color-mix(in srgb, var(--espresso) 72%, transparent);

  /* K-BRAND-4.W3 — soft accent fill for espresso-ground cards (talent cards'
   * tinted chips/CTAs). Minted here because color-mix() is banned in
   * component scss. */
  --accent-fill-espresso:     color-mix(in srgb, var(--lightorange) 16%, transparent);

  /* Avatar identity palette (STATIC — same hues in light + dark). Identity
   * colors stay visually distinct from theme colors so a user's avatar reads
   * as that user, not as a primary/accent surface. Indexed by hash of user
   * identity (today: userId % palette length). See DISCOVERED_ISSUES.md —
   * "Avatar identity palette as static Tier-3 tokens (should be hash-derived)"
   * for the proper long-term replacement. */
  --avatar-fill-1:      #6366f1;
  --avatar-fill-2:      #8b5cf6;
  --avatar-fill-3:      #ec4899;
  --avatar-fill-4:      #f59e0b;
  --avatar-fill-5:      #10b981;
  --avatar-fill-6:      #3b82f6;
  --avatar-fill-7:      #ef4444;
  --avatar-fill-8:      #14b8a6;
  --avatar-fill-9:      #f97316;
  --avatar-fill-10:     #06b6d4;

  /* CBU (Reference Client) identity palette — STATIC, same hues both themes.
   * Selected by rc-image-color pipe via cbu.cbuId. Color names match the
   * legacy `.cbu-image.{color}` CSS modifiers. See DISCOVERED_ISSUES.md —
   * same hash-derived-utility concern as --avatar-fill-N. */
  --cbu-fill-light-red:   #FF5757;
  --cbu-fill-violet:      #8C52FF;
  --cbu-fill-blue:        #5271FF;
  --cbu-fill-orange:      #F78D45;
  --cbu-fill-yellow:      #F7CF1D;
  --cbu-fill-green:       #8DAAA0;
  --cbu-fill-light-blue:  #1AAEE7;
  --cbu-fill-pink:        #C499B8;
  --cbu-fill-brown:       #DAB894;
  /* Foreground for letters laid over the static CBU palette. Must stay
   * static-light: --text-inverse flips dark in dark mode and would yield
   * dark-on-bright (illegible) over the saturated CBU bg hues. */
  --cbu-fg:               #ffffff;

  /* ═══════════════════════════════════════════════════════════════════════
   * LEGACY ALIASES — do NOT use in new code
   * ═══════════════════════════════════════════════════════════════════════
   * Declared here, and therefore RESOLVED here: var() is substituted on the
   * element that declares the property, and descendants inherit the literal.
   * This block's :root arm is <html>. Production's dark trigger
   * (body.dark-mode) and every [data-ground="espresso"] band are OTHER
   * elements, so an alias composed off a token the dark block redefines stays
   * LIGHT under them unless the dark block re-declares it. Adding an alias
   * here means adding its mirror to the dark block's "TBL2-1573 mirrors"
   * section — dark-alias-mirrors.spec.ts computes the rule and fails without.
   * ══════════════════════════════════════════════════════════════════════ */

  /* Brand button / focus aliases → follow --primary (role-based, kept).
   * The old --accent / --accent-orange-* family was removed in TBL2-905 —
   * consumers migrated to the Tier 3 --highlight-* family defined above. */
  --main-button-color:         var(--accent);
  --secondary-button-color:    var(--text-muted);
  --border-focus:              color-mix(in srgb, var(--primary) 40%, transparent);

  /* Brand "navy" aliases — K-BRAND-1.1: NAVY EXITS THE SYSTEM. Every navy
   * alias re-points to brand espresso (the dark brand chrome). --brand-red
   * sat one hex off Bench Orange #FF3300 (logo-artwork-only under the brand)
   * — it re-points to Deep Orange; its consumers get audited in Phase 4/5. */
  --brand-navy:         var(--espresso-800);
  --brand-red:          var(--deeporange);
  --navy:               var(--espresso-800);
  --bg-navy:            var(--espresso-800);
  /* --proto-navy / --proto-danger / --proto-muted were deleted with the prototype (TBL2-1841 PR 2);
   * nothing outside its folders used them. */

  /* Surface aliases → --surface / --surface-raised / --surface-overlay */
  --bg-base:            var(--surface);
  --bg-card:            var(--surface-raised);
  --bg-card-alt:        var(--surface-overlay);
  --bg-card-50:         color-mix(in srgb, var(--surface-raised) 50%, transparent);
  --bg-elevated:        var(--surface-raised);
  --bg-elevated-50:     color-mix(in srgb, var(--surface-overlay) 50%, transparent);
  --bg-elevated-alt:    var(--surface-overlay);
  --bg-elevated-light:  var(--surface-overlay);
  --bg-inset:           var(--surface-overlay);
  --bg-interactive:     var(--surface-overlay);
  --surface-muted:      var(--surface-overlay);
  --color-background-1: var(--surface);
  --color-background-3: var(--surface-overlay);
  --color-background-6: var(--surface-raised);
  --color-background-input: var(--surface-raised);
  --color-card-header:  var(--surface-overlay);
  --subtle-bg-overlay:  color-mix(in srgb, var(--surface) 40%, transparent);
  --slate-subtle:       color-mix(in srgb, var(--text) 5%, transparent);
  --sys-icon-bg:        color-mix(in srgb, var(--text) 8%, transparent);

  /* Text aliases */
  --text-primary:       var(--text);
  --text-secondary:     var(--text-muted);
  --text-heading:       var(--text);
  --color-font-2:       var(--text);
  --color-font-6:       var(--text-muted);
  --color-font-7:       var(--text-muted);
  --color-font-9:       var(--text-muted);
  --color-font-12:      var(--text-muted);
  --color-font-15:      var(--text-muted);
  --co2or-font-2:       var(--text); /* legacy typo, keep alias to not break */
  --color-input-text:   var(--text);
  --color-input-label:  var(--text-muted);

  /* Border aliases */
  --border-default:     var(--border);
  --border-default-30:  color-mix(in srgb, var(--border) 30%, transparent);
  --border-default-40:  color-mix(in srgb, var(--border) 40%, transparent);
  --border-default-50:  color-mix(in srgb, var(--border) 50%, transparent);
  --border-subtle:      var(--surface-overlay);
  --border-row:         color-mix(in srgb, var(--border) 50%, transparent);

  /* Status aliases → tints of --success / --warning / --danger / --info */
  --status-green:           var(--success);
  --status-green-tint:      color-mix(in srgb, var(--success) 10%, transparent);
  --status-green-subtle:    color-mix(in srgb, var(--success) 5%, transparent);
  --status-green-border:    color-mix(in srgb, var(--success) 20%, transparent);
  --status-green-bg:        color-mix(in srgb, var(--success) 10%, transparent);
  --status-green-15:        color-mix(in srgb, var(--success) 13%, transparent);
  --status-green-highlight: color-mix(in srgb, var(--success) 7%, transparent);
  /* NAMING TRAP (K-BRAND-1.1): --sage-green was emerald = SUCCESS semantics,
   * NOT the brand's Sage (#758E75 = completed/no-action). It re-points to
   * basil accordingly — never to var(--sage). */
  --sage-green:             var(--basil);
  --sage-green-tint:        color-mix(in srgb, var(--basil) 10%, transparent);

  --status-amber:        var(--warning);
  --status-amber-tint:   color-mix(in srgb, var(--warning) 10%, transparent);
  --status-amber-subtle: color-mix(in srgb, var(--warning) 5%, transparent);
  --status-amber-border: color-mix(in srgb, var(--warning) 20%, transparent);
  --status-amber-bg:     color-mix(in srgb, var(--warning) 10%, transparent);

  --status-red:          var(--danger);
  --status-red-tint:     color-mix(in srgb, var(--danger) 10%, transparent);
  --status-red-subtle:   color-mix(in srgb, var(--danger) 5%, transparent);
  --status-red-border:   color-mix(in srgb, var(--danger) 20%, transparent);
  --status-red-bg:       color-mix(in srgb, var(--danger) 10%, transparent);

  --status-blue:         var(--info);
  --status-blue-tint:    color-mix(in srgb, var(--info) 10%, transparent);
  --status-blue-border:  color-mix(in srgb, var(--info) 20%, transparent);

  /* K-BRAND-1.1 / R-2: purple has no brand home — Carlos: "processing and
   * in-progress are similar" → honey. */
  --status-purple:       var(--honey-ink);
  --status-purple-tint:  color-mix(in srgb, var(--honey) 10%, transparent);

  --text-success:        var(--success);
  --text-warning:        var(--warning);

  /* Overlay / hover aliases — theme-adaptive tints of --text (black in
   * light, white in dark since --text is near-white in dark) */
  --white-05:               color-mix(in srgb, var(--text) 4%, transparent);
  --hover-overlay-subtle:   color-mix(in srgb, var(--text) 4%, transparent);
  --hover-overlay-light:    color-mix(in srgb, var(--text) 6%, transparent);

  /* Modal scrim — the darkening layer behind a centered dialog. Stays
   * black in BOTH themes (a scrim darkens content; it is NOT a tint of a
   * theme-adaptive role), so it is intentionally not overridden in dark
   * mode. Defined here with a literal rgba (allowed in tokens.css, like
   * the --shadow-* tokens) so components reference a named token instead
   * of inlining rgba. */
  --modal-scrim:            rgba(0, 0, 0, 0.5);

  /* ── K-DEBT-1 (2026-08-02) — burn-down mints ────────────────────────────
   * Role-named Tier-3 aliases that retire the lint:brand TODO backlog. Each
   * absorbed several hand-written literals that were doing ONE job at
   * several accidental values (the percentages below are the chosen value,
   * not an average). The MIRRORED ones are re-declared in the espresso
   * block because they compose off tokens that block re-points; the STATIC
   * ones deliberately do not flip (a veil over a photograph, a knob on its
   * own track, ink on always-dark chrome).
   *
   * WHY MIRRORS ARE REQUIRED (verified in-browser, not inferred): a custom
   * property containing var() is substituted when THAT PROPERTY is computed —
   * i.e. in the scope where it is declared — and the already-resolved value is
   * what inherits. Re-pointing only the BASE in a nested scope does NOT
   * re-derive the alias. Probe: given `#a{--base:#000;--derived:color-mix(in
   * srgb,var(--base) 50%,transparent)}` and `#b{--base:#fff}` nested inside,
   * #b's --derived still computes with #000; a #c that ALSO re-declares
   * --derived computes with #fff. Hence every alias composed off a
   * ground-dependent role is re-declared in the espresso block below. */

  /* MIRRORED — compose off ground-dependent roles. */
  --border-table-row:       color-mix(in srgb, var(--border) 60%, transparent);
  --surface-inset-quiet:    color-mix(in srgb, var(--text-muted) 5%, transparent);
  --border-accent-hover:    color-mix(in srgb, var(--primary) 50%, var(--border));
  --danger-hover:           color-mix(in srgb, var(--danger) 80%, black);
  --danger-ghost-hover:     color-mix(in srgb, var(--danger) 8%, transparent);
  /* The lens material's own derivations (shared/_lens.scss consumes
   * these; custom-property substitution happens where a property is
   * DECLARED, so a lens inside [data-ground=espresso] needs the mirror). */
  /* TBL2-1923 (K-1028-10, DS-1 = A): rows and inset cards paint
   * --surface-raised at FULL opacity, so the text inside them never sits on the
   * hero gradient (the same accent link read 4.06:1 on the first row of Clients
   * and 3.09:1 on the tenth through the 40% fill). The glass PANEL keeps its
   * material; this is the row and the card cut from it. Composed off a token
   * the dark block redefines, so the dark block mirrors it verbatim. */
  --lens-fill-fallback:     var(--surface-raised);
  --lens-row-fill:          var(--surface-raised);
  --lens-row-separator:     color-mix(in srgb, var(--glass-edge) 55%, transparent);

  /* STATIC — same value in both grounds, by role. */
  --toggle-knob:            var(--color-white);
  /* A veil is a CONTROL's own ground over unpredictable image content —
   * distinct from --modal-scrim, which darkens a page behind a dialog. */
  --veil-photo:             rgba(0, 0, 0, 0.5);
  --veil-photo-strong:      rgba(0, 0, 0, 0.65);
  /* Always-dark chrome (portal nav sheets, hero bands, espresso cards). */
  --ink-on-espresso-muted:  color-mix(in srgb, var(--almond) 72%, transparent);
  --fill-on-espresso:       color-mix(in srgb, var(--color-white) 8%, transparent);
  --accent-border-espresso: color-mix(in srgb, var(--lightorange) 40%, transparent);

  /* Directional + knob depths — every other --shadow-* casts straight down. */
  --shadow-edge-right:      8px 0 32px rgba(0, 0, 0, 0.18);
  --shadow-edge-left:       -8px 0 32px rgba(0, 0, 0, 0.18);
  --shadow-edge-top:        0 -4px 14px rgba(0, 0, 0, 0.07);
  --shadow-knob:            0 1px 3px rgba(0, 0, 0, 0.2);

  /* K-DEBT-5 — the two composite gradients the burn-down held for a visual
   * call. Both are STATIC (they live on always-dark hero chrome) and both are
   * brand-tinted onto the --scrim-copy family (45,32,23) rather than the
   * pre-brand cool 28,24,20. Full-gradient tokens are precedented here by
   * --scrim-copy above. */

  /* The hero band darkener: dark at the crown, lifting through the portrait's
   * midtones, dark again at the base so the lockup reads at both ends. */
  --scrim-hero-band: linear-gradient(
    180deg,
    rgba(45, 32, 23, 0.82) 0%,
    rgba(45, 32, 23, 0.55) 40%,
    rgba(45, 32, 23, 0.78) 100%
  );

  /* Ambient hero texture: three low-alpha ellipses that keep a flat espresso
   * band from reading dead. Brand hues (blush / gold / teal) replace the
   * retired rose-peach-slate trio at the same weights. */
  --hero-ambient-wash:
    radial-gradient(ellipse at 25% 35%, color-mix(in srgb, var(--blush-500) 10%, transparent) 0%, transparent 50%),
    radial-gradient(ellipse at 75% 55%, color-mix(in srgb, var(--gold-500) 8%, transparent) 0%, transparent 50%),
    radial-gradient(ellipse at 50% 80%, color-mix(in srgb, var(--teal-700) 6%, transparent) 0%, transparent 50%);

  /* Field state aliases */
  --field-confirmed-bg:         transparent;
  --field-confirmed-border:     var(--border);
  --field-lance-bg:             var(--highlight-fill);
  --field-lance-border:         var(--primary);
  --field-lance-border-width:   3px;
  --field-gap-required-bg:      var(--status-red-tint);
  --field-gap-required-border:  var(--danger);
  --field-gap-optional-bg:      var(--status-amber-tint);
  --field-gap-optional-border:  var(--warning);
  --field-empty-bg:             transparent;
  --field-empty-border:         var(--border);

  /* Semantic border shortcuts */
  --border-hairline:    1px solid color-mix(in srgb, var(--primary) 8%, transparent);
  --border-warm:        1px solid var(--border);
  --border-strong:      1px solid var(--primary);
}

/* ══════════════════════════════════════════════════════════════════════════
 * DARK theme
 * Triggered by ContextService (body.dark-mode) or proto ThemeService
 * ([data-theme="dark"] on <html>) — both apply the same dark tokens.
 *
 * Rewires the Tier 2 pointers + the black-shadow depths + --text-heading, and
 * MIRRORS every token whose light declaration references one of them. Nothing
 * adapts automatically: var() resolves where a property is declared, and
 * body.dark-mode or an espresso band is not the element the light block's
 * :root arm declares on (<html>), so an un-mirrored alias inherits its LIGHT
 * literal. The proto's <html data-theme> path hid it — that IS the :root
 * element — which is how --bg-card shipped cream-on-cream filter pills to
 * production dark mode (TBL2-1573).
 * ═════════════════════════════════════════════════════════════════════════ */
body.dark-mode,
[data-theme="dark"],
[data-ground="espresso"] {
  /* K-BRAND-1.2 (2026-07-31) — THE ESPRESSO GROUND. Dark mode becomes the
   * brand espresso ground (supersedes the K-Brown-1 deep-brown value lock per
   * the brand-supersedes-canon ruling): espresso surfaces, almond copy, the
   * espresso-ground accent pair (Light Orange + espresso ink), d-* status
   * family. When the theme toggle retires (Phase 2 grounds model), this block
   * becomes the [data-ground="espresso"] scope. */

  /* THE GROUND SWITCH — the accent pair flips here.
   * Package rule, verbatim from the client's guideline: "Which orange — The
   * background decides. Deep Orange on light, Light Orange on espresso." */
  --accent:               var(--lightorange);
  --accent-ink:           var(--espresso);

  /* K-v198-Orange (2026-08-05) — ⚠️ THE LINE ABOVE USED TO CLAIM "--primary and
   * --text-inverse follow automatically via their :root pointers". THEY DO NOT,
   * and every espresso surface in the app was painting the LIGHT-ground orange
   * because of it.
   *
   * Why: the computed value of a custom property is its specified value with
   * var() ALREADY substituted. `--primary: var(--accent)` therefore resolves at
   * :root — where --accent is Deep Orange — and what inherits down into this
   * scope is the frozen literal #C63B26, not a live pointer. Re-declaring
   * --accent here changes --accent and nothing downstream of it.
   *
   * MEASURED on billing-proto: stamping data-ground="espresso" moved --accent
   * #C63B26 -> #FB7301 while --primary stayed #C63B26 and the Lance CTA's ink
   * never changed. 11 accent-derived tokens were frozen this way.
   *
   * Each declaration below is IDENTICAL to its :root counterpart; repeating it
   * here is what forces it to recompute against this scope's --accent. Order
   * matters: --primary first, then the tokens derived from --primary. */
  /* TBL2-1923 (K-1028-10, Carlos 2026-10-28, DS-2 = A) — the espresso ground's
   * accent TEXT token. Light Orange, the fill, reads 2.98:1 on the page ground
   * (the lens glass over espresso, (93,75,61)) and 3.75 in a card; the ruled
   * value is #FFB366 "or the nearest value that reads 4.5:1 or better". This is
   * that value, composed off Tier 2 as the header law asks: 55% of the accent
   * over white is #FDB273, 4.64 on the page ground, 5.86 in a card, 5.77 on
   * --espresso-600 (the lightest dark hero stop). The FILL stays Light Orange.
   * TBL2-1931: the Lance suggestion island's glass is a lighter page ground,
   * (97,78,65), where 55% read 4.41; 53% (#FDB578) is the nearest that reads 4.5
   * on it (4.51) and on every ground above (4.75, 5.9). */
  --primary:              color-mix(in srgb, var(--accent) 53%, var(--color-white));
  --highlight:            var(--accent);
  --highlight-border:     color-mix(in srgb, var(--accent) 30%, transparent);
  --highlight-glow:       color-mix(in srgb, var(--accent) 40%, transparent);
  --highlight-shadow:     color-mix(in srgb, var(--accent) 20%, transparent);
  --border-focus:         color-mix(in srgb, var(--primary) 40%, transparent);
  --border-strong:        1px solid var(--primary);
  --border-hairline:      1px solid color-mix(in srgb, var(--primary) 8%, transparent);
  --shadow-focus:         0 0 0 2px color-mix(in srgb, var(--primary) 22%, transparent);
  --field-lance-border:   var(--primary);
  --main-button-color:    var(--accent);

  /* Tier 2 overrides */
  --surface:              var(--espresso-800);
  --surface-raised:       var(--espresso-700);
  --surface-overlay:      var(--espresso-600);
  --text:                 var(--almond);
  /* TBL2-1923 (K-1028-10, Carlos 2026-10-28, DS-2 = A): --almond-600 (#BDAD96)
   * reads 3.77:1 on the page ground and 4.76 in a card; #D9CBB6 reads 5.19 and
   * 6.54. A literal, as --accent-ink is: it sits between --almond-500 and
   * --almond-400 on the vendored ramp and the value is Carlos's. The light
   * ground keeps --espresso-400 (K-v195-Ink). */
  --text-muted:           #D9CBB6;
  --text-muted-on-hero:   var(--text-muted); /* TBL2-1931 — the espresso hero takes the ground's own muted ink */
  --status-success-text-on-hero: var(--status-success-text);
  --status-error-text-on-hero:   var(--status-error-text);
  /* TBL2-1931 — blush-700 read 1.77:1 on espresso; --blush-300 is the darkest step
   * of the ramp that reads 4.5 on the espresso page ground (4.53; 5.78 measured). */
  --greeting-name-ink:    var(--blush-300);
  /* --text-inverse stays WHITE here (not the espresso accent-ink): the token
   * is consumed broadly as "text on dark surfaces" (hero copy etc.), not only
   * on accent fills. Espresso-ink-on-lightorange button discipline arrives
   * with per-surface --accent-ink adoption in Phase 2. */
  --text-inverse:         var(--color-white);
  --border:               color-mix(in srgb, var(--color-white) 10%, transparent);

  --success:              var(--d-basil);
  --warning:              var(--d-honey);
  --danger:               var(--d-cherry);
  /* K-v193-InfoHoney — mirrored onto espresso. */
  --info:                 var(--d-honey);

  /* Black-shadow depths — stronger opacities on dark surfaces.
   * --shadow-focus auto-adapts via color-mix on --primary, no override needed. */
  --shadow-sm:          0 1px 3px rgba(0, 0, 0, 0.30), 0 2px 8px rgba(0, 0, 0, 0.20);
  --shadow-md:          0 4px 24px rgba(0, 0, 0, 0.35), 0 1px 4px rgba(0, 0, 0, 0.25);
  --shadow-card:        0 4px 24px rgba(0, 0, 0, 0.35), 0 1px 4px rgba(0, 0, 0, 0.25);
  --shadow-lg:          0 10px 48px rgba(0, 0, 0, 0.45), 0 2px 8px rgba(0, 0, 0, 0.30);
  --shadow-elevated:    0 10px 48px rgba(0, 0, 0, 0.45), 0 2px 8px rgba(0, 0, 0, 0.30);

  /* K-DEBT-1 mirrors — identical declaration text; each recomputes against
   * THIS block's --border/--text-muted/--primary/--danger/--surface-raised/
   * --glass-edge. The STATIC mints (toggle-knob, veils, on-espresso inks)
   * are deliberately absent: they must not flip. */
  --border-table-row:       color-mix(in srgb, var(--border) 60%, transparent);
  --surface-inset-quiet:    color-mix(in srgb, var(--text-muted) 5%, transparent);
  --border-accent-hover:    color-mix(in srgb, var(--primary) 50%, var(--border));
  --danger-hover:           color-mix(in srgb, var(--danger) 80%, black);
  --danger-ghost-hover:     color-mix(in srgb, var(--danger) 8%, transparent);
  --lens-fill-fallback:     var(--surface-raised);
  --lens-row-fill:          var(--surface-raised);
  --lens-row-separator:     color-mix(in srgb, var(--glass-edge) 55%, transparent);

  /* TBL2-1573 mirrors (ruled by Sergio, 2026-09-07) — the sweep K-DEBT-1
   * started. THE RULE IS MECHANICAL: a token in the light block is mirrored
   * here if and only if this block redefines a token its value references,
   * directly or through another mirrored token. Each line is copied verbatim
   * from the light block; repeating it is what makes it recompute on THIS
   * element. styles-contracts/dark-alias-mirrors.spec.ts computes the rule
   * from the live stylesheets, so a token added to the light block without
   * its mirror here fails that spec.
   *
   * Out by construction, not by omission:
   *  - the STATIC tokens (toggle knob, veils, on-espresso inks, --cbu-fg, the
   *    brand/navy aliases, the hero plate and inks) reference nothing this
   *    block redefines, so the rule never selects them;
   *  - --main-button-color and --border-focus are already mirrored above;
   *  - the 14 aliases main.css re-declares on `body {}` (--color-background-1
   *    /-3/-6, --color-background-input, --color-card-header, --color-font-2
   *    /-6/-7/-9/-12/-15, --color-input-label/-text, --secondary-button-color).
   *    Below <body> the :root declaration of those is dead, and main.css's own
   *    `body.dark-mode, [data-theme='dark']` twin already flips them — a mirror
   *    here would lose to that twin in dark mode and only restyle espresso
   *    bands with values main.css never uses. */

  /* Tier 3 — status borders, chip tints, the muted pill. */
  --status-success-border: color-mix(in srgb, var(--success) 30%, transparent);
  --status-warning-border: color-mix(in srgb, var(--warning) 30%, transparent);
  --status-error-border:   color-mix(in srgb, var(--danger) 30%, transparent);
  --status-info-border:    color-mix(in srgb, var(--info) 30%, transparent);
  --chip-tint-success:    color-mix(in srgb, var(--status-success-bg), transparent 50%);
  --chip-tint-info:       color-mix(in srgb, var(--status-info-bg),    transparent 50%);
  --chip-tint-warning:    color-mix(in srgb, var(--status-warning-bg), transparent 50%);
  --pill-muted-text:      var(--text-muted);
  --pill-muted-bg:        color-mix(in srgb, var(--text-muted) 12%, transparent);

  /* Legacy — surface aliases. --bg-card is the one that painted the pills. */
  --bg-base:            var(--surface);
  --bg-card:            var(--surface-raised);
  --bg-card-alt:        var(--surface-overlay);
  --bg-card-50:         color-mix(in srgb, var(--surface-raised) 50%, transparent);
  --bg-elevated:        var(--surface-raised);
  --bg-elevated-50:     color-mix(in srgb, var(--surface-overlay) 50%, transparent);
  --bg-elevated-alt:    var(--surface-overlay);
  --bg-elevated-light:  var(--surface-overlay);
  --bg-inset:           var(--surface-overlay);
  --bg-interactive:     var(--surface-overlay);
  --surface-muted:      var(--surface-overlay);
  --subtle-bg-overlay:  color-mix(in srgb, var(--surface) 40%, transparent);
  --slate-subtle:       color-mix(in srgb, var(--text) 5%, transparent);
  --sys-icon-bg:        color-mix(in srgb, var(--text) 8%, transparent);

  /* Legacy — text aliases. */
  --text-primary:       var(--text);
  --text-secondary:     var(--text-muted);
  --co2or-font-2:       var(--text);

  /* Legacy — border aliases. */
  --border-default:     var(--border);
  --border-default-30:  color-mix(in srgb, var(--border) 30%, transparent);
  --border-default-40:  color-mix(in srgb, var(--border) 40%, transparent);
  --border-default-50:  color-mix(in srgb, var(--border) 50%, transparent);
  --border-subtle:      var(--surface-overlay);
  --border-row:         color-mix(in srgb, var(--border) 50%, transparent);
  --border-warm:        1px solid var(--border);

  /* Legacy — status aliases. --sage-green and --status-purple are absent on
   * purpose: they reference brand primitives, which this block never redefines. */
  --status-green:           var(--success);
  --status-green-tint:      color-mix(in srgb, var(--success) 10%, transparent);
  --status-green-subtle:    color-mix(in srgb, var(--success) 5%, transparent);
  --status-green-border:    color-mix(in srgb, var(--success) 20%, transparent);
  --status-green-bg:        color-mix(in srgb, var(--success) 10%, transparent);
  --status-green-15:        color-mix(in srgb, var(--success) 13%, transparent);
  --status-green-highlight: color-mix(in srgb, var(--success) 7%, transparent);
  --status-amber:        var(--warning);
  --status-amber-tint:   color-mix(in srgb, var(--warning) 10%, transparent);
  --status-amber-subtle: color-mix(in srgb, var(--warning) 5%, transparent);
  --status-amber-border: color-mix(in srgb, var(--warning) 20%, transparent);
  --status-amber-bg:     color-mix(in srgb, var(--warning) 10%, transparent);
  --status-red:          var(--danger);
  --status-red-tint:     color-mix(in srgb, var(--danger) 10%, transparent);
  --status-red-subtle:   color-mix(in srgb, var(--danger) 5%, transparent);
  --status-red-border:   color-mix(in srgb, var(--danger) 20%, transparent);
  --status-red-bg:       color-mix(in srgb, var(--danger) 10%, transparent);
  --status-blue:         var(--info);
  --status-blue-tint:    color-mix(in srgb, var(--info) 10%, transparent);
  --status-blue-border:  color-mix(in srgb, var(--info) 20%, transparent);
  --text-success:        var(--success);
  --text-warning:        var(--warning);

  /* Legacy — overlay / hover tints of --text. */
  --white-05:               color-mix(in srgb, var(--text) 4%, transparent);
  --hover-overlay-subtle:   color-mix(in srgb, var(--text) 4%, transparent);
  --hover-overlay-light:    color-mix(in srgb, var(--text) 6%, transparent);

  /* Legacy — field state aliases. The two -bg tints chain through the status
   * aliases above, which is why "through another mirrored token" is in the rule. */
  --field-confirmed-border:     var(--border);
  --field-lance-bg:             var(--highlight-fill);
  --field-gap-required-bg:      var(--status-red-tint);
  --field-gap-required-border:  var(--danger);
  --field-gap-optional-bg:      var(--status-amber-tint);
  --field-gap-optional-border:  var(--warning);
  --field-empty-border:         var(--border);

  /* Directional/knob depths go stronger on dark, like the family above. */
  --shadow-edge-right:      8px 0 32px rgba(0, 0, 0, 0.45);
  --shadow-edge-left:       -8px 0 32px rgba(0, 0, 0, 0.45);
  --shadow-edge-top:        0 -4px 14px rgba(0, 0, 0, 0.30);
  --shadow-knob:            0 1px 3px rgba(0, 0, 0, 0.45);

  /* Heading signature: almond copy on espresso (brand ink-follows-ground) */
  --text-heading:       var(--almond);

  /* Status chip pairs — the d-* espresso family: solved dark inks on 18%
   * washes of the dark bases (brand construction). Neutral rides d-sage.
   *
   * TBL2-1931 (K-1029-1 BUILD 5, DS-2 = A: one status-ink pair per ground) — the
   * vendored d-*-ink values are solved for the wash over --espresso-700, the card.
   * On the espresso PAGE ground (the lens glass over espresso, (93,75,61), the
   * ground TBL2-1923 solved the accent text on) they read 3.44 to 3.65, and a pill
   * on a hero panel read 3.56 on dev. Each -text is the vendored ink lifted toward
   * white just until it reads 4.5:1 on its own wash over that ground: basil 66%
   * (#BAD6C5), honey 58% (#EED7A0), cherry 68% (#F1C2C5), sage 57% (#D7DDD3).
   * Composed off Tier 2, as the dark --primary is; the vendored inks and every
   * wash (a FILL, TBL2-1410's) are untouched. */
  --status-success-bg:   color-mix(in srgb, var(--d-basil) 18%, transparent);
  --status-success-text: color-mix(in srgb, var(--d-basil-ink) 66%, var(--color-white));
  --status-warning-bg:   color-mix(in srgb, var(--d-honey) 18%, transparent);
  --status-warning-text: color-mix(in srgb, var(--d-honey-ink) 58%, var(--color-white));
  --status-error-bg:     color-mix(in srgb, var(--d-cherry) 18%, transparent);
  --status-error-text:   color-mix(in srgb, var(--d-cherry-ink) 68%, var(--color-white));

  /* K-v193-Avatar — MIRRORED. On an espresso ground the pair inverts, or the
     circle would vanish into the page exactly as a paper circle would on paper. */
  --avatar-fallback-bg:   var(--surface-paper);
  --avatar-fallback-ink:  var(--espresso);

  --status-info-bg:      color-mix(in srgb, var(--d-honey) 18%, transparent);
  --status-info-text:    color-mix(in srgb, var(--d-honey-ink) 58%, var(--color-white));
  --status-neutral-bg:   color-mix(in srgb, var(--d-sage) 18%, transparent);
  --status-neutral-text: color-mix(in srgb, var(--d-sage-ink) 57%, var(--color-white));

  /* TBL2-1950 — the soft washes' bases on espresso (the d-* family, as the bg pairs above), and the
   * light block's on-row composites, mirrored. */
  --status-success-base:      var(--d-basil);
  --status-warning-base:      var(--d-honey);
  --status-error-base:        var(--d-cherry);
  --status-info-base:         var(--d-honey);
  --status-neutral-base:      var(--d-sage);
  --status-success-bg-on-row: color-mix(in srgb, var(--status-success-base) 18%, var(--surface-raised));
  --status-warning-bg-on-row: color-mix(in srgb, var(--status-warning-base) 18%, var(--surface-raised));
  --status-error-bg-on-row:   color-mix(in srgb, var(--status-error-base) 18%, var(--surface-raised));
  --status-info-bg-on-row:    color-mix(in srgb, var(--status-info-base) 18%, var(--surface-raised));
  --status-neutral-bg-on-row: color-mix(in srgb, var(--status-neutral-base) 18%, var(--surface-raised));

  /* --text-light: softer transparent version of --text-muted so
   * placeholders/disabled stay legible on espresso. */
  --text-light:         color-mix(in srgb, var(--text-muted) 70%, transparent);

  /* --main-bg: navy EXITS — espresso owns the dark prominent chrome. */
  --main-bg:            var(--espresso-800);

  /* Hover/fill derive from the live accent (Light Orange on espresso) — the
   * FILL pair, not --primary, which is the accent text here (TBL2-1923). */
  --primary-hover:      color-mix(in srgb, var(--accent) 85%, black);
  --highlight-fill:     color-mix(in srgb, var(--accent) 10%, transparent);

  /* Lance banner on espresso — espresso surfaces, gold identity ink. */
  --bg-lance-banner:        var(--espresso-800);
  --bg-lance-banner-raised: var(--espresso-700);
  --text-lance-banner:      var(--gold-400);
  --border-lance-banner:    color-mix(in srgb, var(--color-white) 8%, transparent);

  /* Canonical Lance marker — brighter gold against espresso. */
  --lance-marker-color:     var(--gold-500);

  /* K-BRAND-2.1 — glass material follows the ground: the bare --glass-*
   * names re-point to the espresso tints here, so the lens mixin
   * (shared/_lens.scss) adapts per ground with zero caller logic. */
  --glass-hi:               var(--glass-hi-espresso);
  --glass-mid:              var(--glass-mid-espresso);
  --glass-lo:               var(--glass-lo-espresso);
  --glass-edge:             var(--glass-edge-espresso);
  --glass-sheen:            var(--glass-sheen-espresso);
  --glass-shadow:           var(--glass-shadow-espresso);
  --glass-shadow-raised:    var(--glass-shadow-raised-espresso);
  /* K-v199-S6 (R-B) — the scrollbar follows the ground with the glass. An
   * almond thumb is invisible on espresso; the glass edge is the line this
   * ground already uses for hairlines, so the bar reads as part of the frame
   * rather than as a browser artifact sitting on top of it. */
  --scrollbar-thumb:        var(--glass-edge-espresso);

  /* Status-pill family on espresso — d-* inks + 18% washes (K-BRAND-1.2;
   * purple → honey per R-2; info → teal per R-1). TBL2-1931: the inks read the
   * --status-*-text pair above (one status-ink pair per ground, DS-2 = A). */
  --pill-info-text:       var(--teal-400);
  --pill-info-bg:         color-mix(in srgb, var(--teal-500) 18%, transparent);
  --pill-success-text:    var(--status-success-text);
  --pill-success-bg:      color-mix(in srgb, var(--d-basil) 18%, transparent);
  --pill-warning-text:    var(--status-warning-text);
  --pill-warning-bg:      color-mix(in srgb, var(--d-honey) 18%, transparent);
  --pill-danger-text:     var(--status-error-text);
  --pill-danger-bg:       color-mix(in srgb, var(--d-cherry) 18%, transparent);
  --pill-purple-text:     var(--status-warning-text);
  --pill-purple-bg:       color-mix(in srgb, var(--d-honey) 18%, transparent);
}

/* ══════════════════════════════════════════════════════════════════════════
 * Talent theme (warm off-white, used by the talent portal)
 * Rewires Tier 2 to a warmer palette; legacy aliases follow automatically.
 * ═════════════════════════════════════════════════════════════════════════ */
.theme-talent {
  /* K-TalSweep-1 (2026-06-11) — Carlos: the legacy cool palette
   * (#F8F6F2 / navy #1A1A2E text / gray-blue muted) made the talent
   * Billing + Project Detail surfaces read as a different product
   * from the rest of the talent lane (navy page titles vs the warm
   * brown canon). Tier 2 rewiring retired — the canonical warm
   * palette flows through. Only the two shadow aliases remain (8
   * consumers in project-detail/invoicing). */
  --shadow-card:        var(--shadow-sm);
  --shadow-elevated:    var(--shadow-md);
}

/* K-Brown-3 (2026-05-14) — Carlos: `.theme-talent` was authored as a
 * light-only warm-cream override (talent-invoicing-shell host class).
 * In dark mode those literals (#F8F6F2 cream + #1A1A2E dark navy
 * text) override the Tier 2 dark block, so the Talent Billing
 * surface renders as cream-on-cream chrome with dark navy text on
 * brown body → ~3:1 fail / invisible title + KPI values. Reset the
 * overrides to the canonical brown dark palette so the warm-dark
 * lock applies cleanly. */
body.dark-mode .theme-talent,
[data-theme="dark"] .theme-talent,
body.dark-mode.theme-talent,
[data-theme="dark"].theme-talent {
  /* K-BRAND-1.2: follows the espresso ground (was the brown-900/800 stack). */
  --surface:            var(--espresso-800);
  --surface-raised:     var(--espresso-700);
  --surface-overlay:    var(--espresso-600);
  --text:               var(--almond);
  --text-muted:         #D9CBB6; /* TBL2-1923 — the espresso ground's muted ink, as in the dark block above */
  --border:             color-mix(in srgb, var(--color-white) 10%, transparent);
}

/* ══════════════════════════════════════════════════════════════════════════
 * Heading / nav signature rules
 * ═════════════════════════════════════════════════════════════════════════ */
[data-theme] h1,
[data-theme] h2,
[data-theme] h3,
[data-theme] .section-header,
[data-theme] .section-divider__title,
[data-theme] .sidebar-title,
[data-theme] .ins-heading,
[data-theme] .ins-section-title {
  color: var(--text-heading);
}

[data-theme] .ins-nav__title,
[data-theme] .pd-nav__item,
[data-theme] .ah-nav__item,
[data-theme] .billing-nav__item,
[data-theme] .pl-nav__item,
[data-theme] .td__nav-btn,
[data-theme] .tp-nav__item,
[data-theme] .find-work__nav-link {
  color: var(--nav-text, #F7F4EF);
}

/* Smooth transitions on theme toggle (AG Grid excluded) — K-BRAND-1.5: theme
 * swap rides the brand base tier (240ms, standard easing). */
[data-theme] * {
  transition:
    background-color var(--motion-base) var(--ease-standard),
    color var(--motion-base) var(--ease-standard),
    border-color var(--motion-base) var(--ease-standard),
    box-shadow var(--motion-base) var(--ease-standard);
}
[data-theme] .ag-root *,
[data-theme] .ag-body-viewport *,
[data-theme] .ag-center-cols-viewport * {
  transition: none;
}

/* ══════════════════════════════════════════════════════════════════════════
 * Lance Progressive Animation
 * ═════════════════════════════════════════════════════════════════════════ */
@keyframes lanceFadeIn {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: translateY(0); }
}

.lance-progressive > * {
  opacity: 0;
  animation: lanceFadeIn 300ms ease forwards;
}

.lance-progressive > *:nth-child(1) { animation-delay: 0ms; }
.lance-progressive > *:nth-child(2) { animation-delay: 80ms; }
.lance-progressive > *:nth-child(3) { animation-delay: 160ms; }
.lance-progressive > *:nth-child(4) { animation-delay: 240ms; }
.lance-progressive > *:nth-child(5) { animation-delay: 320ms; }
.lance-progressive > *:nth-child(6) { animation-delay: 400ms; }
.lance-progressive > *:nth-child(7) { animation-delay: 480ms; }
.lance-progressive > *:nth-child(8) { animation-delay: 560ms; }

@media (prefers-reduced-motion: reduce) {
  .lance-progressive > * {
    opacity: 1;
    animation: none;
  }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

/* ══════════════════════════════════════════════════════════════════════════
 * Focus treatment (global) — uses tier 2 primary
 * ═════════════════════════════════════════════════════════════════════════ */
*:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

body.dark-mode *:focus-visible,
[data-theme="dark"] *:focus-visible {
  /* K-BRAND-1.1 / R-1: brand has no blue — the espresso-ground focus ring is
   * the ground's accent (Light Orange), not the old info blue. */
  outline-color: var(--lightorange);
}

/* ══════════════════════════════════════════════════════════════════════════
 * Form controls — transparent by default
 * Text-like inputs, selects, and textareas inherit the surface they sit
 * on; only explicit :disabled / [readonly] states paint a solid
 * background. Don't reintroduce backgrounds on :focus or :hover in
 * component styles.
 *
 * Non-text input types (submit / reset / button / image / file / checkbox
 * / radio / range / color / hidden) keep their native / framework
 * rendering — the rule does not target them. If a new text-like HTML
 * input type ships, add it to the :is() list.
 * ═════════════════════════════════════════════════════════════════════════ */
input:is(
  [type="text"], [type="email"], [type="password"], [type="search"],
  [type="tel"], [type="url"], [type="number"], [type="date"],
  [type="time"], [type="datetime-local"], [type="month"], [type="week"]
):not(:disabled):not([readonly]),
input:not([type]):not(:disabled):not([readonly]),
select:not(:disabled):not([readonly]),
textarea:not(:disabled):not([readonly]) {
  background: transparent;
}

/* Native <option> elements are rendered by the OS/browser and ignore the
 * transparent bg on their parent <select>, so we paint them explicitly
 * with Tier 2 tokens to avoid white-on-white in dark mode. */
option {
  background: var(--surface-raised);
  color: var(--text);
}

/* ══════════════════════════════════════════════════════════════════════════
 * Bootstrap bridge — re-route Bootstrap 5's CSS variables to our Tier 2
 * tokens so every `.btn` / `.btn-primary` / `.btn-outline-*` automatically
 * follows the current theme. Component code stays plain Bootstrap classes;
 * nothing to override per-feature.
 * ═════════════════════════════════════════════════════════════════════════ */

/* Body / form-control bridge — Bootstrap reads --bs-body-bg,
 * --bs-body-color and --bs-border-color from :root when painting
 * .form-control, .form-select, and any other default control. Wiring
 * them to our Tier 2 tokens makes those controls flip with the theme
 * without every feature needing to override Bootstrap vars locally.
 * --bs-body-bg points at --surface-raised so controls read as raised
 * chrome on the page (cream/navy-deep); when the text-like input rule
 * above fires it wins on specificity and the field becomes transparent. */
:root {
  --bs-body-bg:           var(--surface-raised);
  --bs-body-color:        var(--text);
  --bs-border-color:      var(--border);
  --bs-secondary-color:   var(--text-muted);
}

body.dark-mode,
[data-theme="dark"] {
  --bs-body-bg:           var(--surface-raised);
  --bs-body-color:        var(--text);
  --bs-border-color:      var(--border);
  --bs-secondary-color:   var(--text-muted);
}

/* Radii on buttons — use our scale */
.btn        { --bs-btn-border-radius:    var(--radius-sm); }
.btn-sm     { --bs-btn-border-radius:    var(--radius-sm); }
.btn-lg     { --bs-btn-border-radius:    var(--radius-md); }

/* Primary → --accent, the FILL pair (auto-adapts light↔dark↔talent).
 * TBL2-1923: --primary is the accent TEXT since K-1028-10; a button is a fill.
 * The ink on the fill is the pair's own, --accent-ink (white on Deep Orange,
 * espresso on Light Orange, 4.93:1): --text-inverse stays white on espresso and
 * read 2.78:1 there, the pairing the dark block left "for per-surface
 * --accent-ink adoption". The DISABLED state is the ghost of
 * modules/main/shared/_buttons.scss (DS-7 = A; kind sheet button = A):
 * transparent, the hairline, muted ink, full opacity — the 55% wash read
 * 1.5 to 1.9:1. */
.btn-primary {
  --bs-btn-color:                var(--accent-ink);
  --bs-btn-bg:                   var(--accent);
  --bs-btn-border-color:         var(--accent);
  --bs-btn-hover-color:          var(--accent-ink);
  --bs-btn-hover-bg:             color-mix(in srgb, var(--accent) 85%, black);
  --bs-btn-hover-border-color:   color-mix(in srgb, var(--accent) 85%, black);
  --bs-btn-active-color:         var(--accent-ink);
  --bs-btn-active-bg:            color-mix(in srgb, var(--accent) 75%, black);
  --bs-btn-active-border-color:  color-mix(in srgb, var(--accent) 75%, black);
  --bs-btn-disabled-color:       var(--text-muted);
  --bs-btn-disabled-bg:          transparent;
  --bs-btn-disabled-border-color: var(--border);
  --bs-btn-disabled-opacity:     1;
}

/* Secondary → neutral outline */
.btn-secondary {
  --bs-btn-color:                var(--text-muted);
  --bs-btn-bg:                   transparent;
  --bs-btn-border-color:         var(--border);
  --bs-btn-hover-color:          var(--text);
  --bs-btn-hover-bg:             var(--surface-overlay);
  --bs-btn-hover-border-color:   var(--border);
  --bs-btn-active-color:         var(--text);
  --bs-btn-active-bg:            var(--surface-overlay);
  --bs-btn-active-border-color:  var(--border);
}

/* Outline-danger */
.btn-outline-danger {
  --bs-btn-color:                var(--danger);
  --bs-btn-border-color:         var(--danger);
  --bs-btn-hover-color:          var(--text-inverse);
  --bs-btn-hover-bg:             var(--danger);
  --bs-btn-hover-border-color:   var(--danger);
  --bs-btn-active-color:         var(--text-inverse);
  --bs-btn-active-bg:            var(--danger);
  --bs-btn-active-border-color:  var(--danger);
}

/* ══════════════════════════════════════════════════════════════════════════
 * ng-bootstrap datepicker — global theme.
 * Applies to every ngb-datepicker in the app (onboarding "Available From",
 * anywhere). Originally scoped to the TBL2-820 work-item modals under
 * TBL2-820; promoted to global so popover-style datepickers attached to a
 * plain <input ngbDatepicker> also pick up the theme.
 * ═════════════════════════════════════════════════════════════════════════ */
ngb-datepicker {
  background: var(--surface-overlay);
  color: var(--text);
  border: 1px solid var(--border);
}
ngb-datepicker .ngb-dp-header,
ngb-datepicker .ngb-dp-weekdays,
ngb-datepicker .ngb-dp-month-name {
  background: var(--surface-raised);
  color: var(--text);
}
ngb-datepicker .ngb-dp-weekday {
  color: var(--text-muted);
}
ngb-datepicker .btn-link {
  color: var(--text);
}
ngb-datepicker .btn-link:hover,
ngb-datepicker .btn-link:focus {
  color: var(--primary);
}
ngb-datepicker .ngb-dp-arrow-btn:disabled {
  color: var(--text-muted);
  opacity: 0.5;
}
ngb-datepicker .ngb-dp-day .btn-light {
  background: transparent;
  color: var(--text);
}
ngb-datepicker .ngb-dp-day .btn-light:hover {
  background: var(--surface-overlay);
}
ngb-datepicker .ngb-dp-day.disabled .btn-light,
ngb-datepicker .ngb-dp-day.hidden .btn-light {
  color: var(--text-muted);
  opacity: 0.4;
}
ngb-datepicker .ngb-dp-day .bg-primary {
  background-color: var(--accent);
  color: var(--text-inverse);
}

/* ═══════════════════════════════════════════════════════════════════════════
 * K-BRAND-0.3 (2026-07-31) — THE BENCH BRAND TOKENS (Phase 0: additive, ZERO
 * consumers). Two blocks:
 *
 *   A. VENDORED — the client's brand palette, copied VERBATIM from
 *      docs/design/brand/tokens.css (generated upstream from the brand source;
 *      DO NOT EDIT here — changes go through the client and are re-vendored).
 *   B. MINTED — token families the brand package specifies in prose
 *      (docs/design/brand/CLAUDE.md tables + reference/brand-standards.html
 *      material values) but ships no tokens for (CR-6/CR-7 pending upstream
 *      homes). Authored here; reconcile when the client regenerates.
 *
 * Nothing below is referenced by any component yet. The Phase-1 wash re-points
 * the Tier 2/3 tokens above onto block A; Phase 2 consumes block B (lens
 * material, grounds, type scale). Program rules + rulings: the "Brand Package
 * (VISUAL AUTHORITY)" section of src/the-bench-web/CLAUDE.md and the K-BRAND-0
 * PR (#1310) description; the package itself lives at docs/design/brand/.
 * ═══════════════════════════════════════════════════════════════════════════ */

/* ── A. VENDORED brand palette (docs/design/brand/tokens.css, verbatim) ───── */
:root {
  --orange: #FF3300;
  --deeporange: #C63B26;
  --lightorange: #FB7301;
  --almond: #F0E8D9;
  --blush: #C99276;
  --espresso: #3A2A1F;
  --teal: #A9CFC5;
  --gold: #CEA05D;
  --orange-100: #FBF0EC;
  --orange-200: #F7C7BB;
  --orange-300: #F3997E;
  --orange-400: #FB7301;
  --orange-500: #FF3300;
  --orange-600: #C63B26;
  --orange-700: #9B291F;
  --orange-800: #761E14;
  --orange-900: #3C1B0C;
  --almond-100: #FAF5F1;
  --almond-200: #F9F2EA;
  --almond-300: #F0E8D9;
  --almond-400: #E7DAC7;
  --almond-500: #D1C4B1;
  --almond-600: #BDAD96;
  --almond-700: #A8927A;
  --almond-800: #876F55;
  --almond-900: #473728;
  --blush-100: #FDF0EA;
  --blush-200: #ECC7B7;
  --blush-300: #DEB8A5;
  --blush-400: #D6A793;
  --blush-500: #C99276;
  --blush-600: #B6795C;
  --blush-700: #915437;
  --blush-800: #824121;
  --blush-900: #2D160E;
  --espresso-100: #C7BCB6;
  --espresso-200: #938C86;
  --espresso-300: #776A62;
  --espresso-400: #665950;
  --espresso-500: #584A3F;
  --espresso-600: #4C3E33;
  --espresso-700: #422F21;
  /* K-v193-NoBlue (2026-08-03) — Carlos: the five raw --color-navy-*
     primitives are DELETED. They were the last true blue VALUES in the
     system and had zero consumers; the brand palette has no blue at all
     (its only cool colour is teal #A9CFC5). --navy/--brand-navy/--bg-navy
     survive as aliases that already resolve to espresso. */
  --espresso-800: #3A2A1F;
  --espresso-900: #090909;
  --teal-100: #EEF7F4;
  --teal-200: #DFEEE7;
  --teal-300: #D4E3E0;
  --teal-400: #C7DED6;
  --teal-500: #A9CFC5;
  --teal-600: #80AEA3;
  --teal-700: #38715E;
  --teal-800: #285F4A;
  --teal-900: #014129;
  --gold-100: #EEE5D6;
  --gold-200: #EFDEC4;
  --gold-300: #E7CAA2;
  --gold-400: #E0BB84;
  --gold-500: #CEA05D;
  --gold-600: #B98D4C;
  --gold-700: #8D6025;
  --gold-800: #6A4519;
  --gold-900: #342112;
  --hero-0: #E5CBBC;
  --hero-1: #FCE8D1;
  --hero-2: #F5C08E;
  --hero-3: #CB7C50;
  --ambient-0: #F5EFE7;
  --ambient-1: #FFB27D;
  --ambient-2: #F45F22;
  --affogato-0: #3A2A1F;
  --affogato-1: #4A3527;
  --affogato-2: #E5CBBC;
  --ember-0: #3A2A1F;
  --ember-1: #915437;
  --ember-2: #F45F22;
  --goldb-0: #CEA05D;
  --goldb-1: #82561C;
  --goldc-0: #82561C;
  --goldc-1: #CEA05D;
  --goldc-2: #EFE3D3;
  --goldc-3: #B28242;
  --goldc-4: #433118;
  --basil: #006C48;
  --d-basil: #459D78;
  --basil-ink: #076443;
  --d-basil-ink: #97C1A7;
  --honey: #FFAA00;
  --d-honey: #DAA520;
  --honey-ink: #815814;
  --d-honey-ink: #E1BA5B;
  --cherry: #D2042D;
  --d-cherry: #E45D74;
  --cherry-ink: #AE0D2A;
  --d-cherry-ink: #EAA5A9;
  --sage: #758E75;
  --d-sage: #A7B8A5;
  --sage-ink: #5B624F;
  --d-sage-ink: #B9C4B1;
  --lc-bench-orange: #FF3300;
  --lc-light-orange: #FB7301;
  --lc-stage-black: #090909;
  --lc-light-almond: #F9F2E8;
  --lc-teal: #A9CFC5;
  --lc-dark-blush: #AF6E51;
  --basil-soft: #006C482E;
  --honey-soft: #FFAA002E;
  --cherry-soft: #D2042D2E;
  --sage-soft: #758E752E;
}

/* ── B. MINTED brand token families (authored from CLAUDE.md + reference) ── */
:root {
  /* NOTE (K-BRAND-1.2): the --accent/--accent-ink pair moved UP into the
   * Tier-2 section — this bottom block loads AFTER the dark block, so a
   * default here would out-cascade the dark block's espresso-ground override
   * at equal :root/[data-theme] specificity. Only never-overridden constants
   * belong down here. */

  /* Type scale — 10 levels from the brand CLAUDE.md table (CR-7: no upstream
   * type tokens exist; this is the bridging source until the client emits them).
   * Faces re-point at Phase 1: display = Literata, UI/body = Outfit, Lance =
   * Ibarra Real Nova roman (italic ONLY when quoting the user). */
  --type-brand-title-size: 72px;   --type-brand-title-line: 1.02; --type-brand-title-track: -0.012em; --type-brand-title-weight: 400;
  --type-brand-emph-size: 56px;    --type-brand-emph-line: 1.06;  --type-brand-emph-track: -0.006em;  --type-brand-emph-weight: 800;
  --type-h1-size: 64px;            --type-h1-line: 1.05;          --type-h1-track: -0.03em;           --type-h1-weight: 500;
  --type-h2-size: 44px;            --type-h2-line: 1.10;          --type-h2-track: -0.02em;           --type-h2-weight: 500;
  --type-h3-size: 32px;            --type-h3-line: 1.18;          --type-h3-track: -0.02em;           --type-h3-weight: 500;
  --type-h4-size: 20px;            --type-h4-line: 1.30;          --type-h4-track: 0.06em;            --type-h4-weight: 500;
  --type-body1-size: 16px;         --type-body1-line: 1.55;       --type-body1-track: 0;              --type-body1-weight: 300;
  --type-body2-size: 14px;         --type-body2-line: 1.60;       --type-body2-track: 0.06em;         --type-body2-weight: 300;
  --type-body3-size: 12px;         --type-body3-line: 1.60;       --type-body3-track: 0.06em;         --type-body3-weight: 300;
  --type-lance-size: 20px;         --type-lance-line: 1.45;       --type-lance-track: -0.02em;        --type-lance-weight: 400;

  /* Radius scale (brand CLAUDE.md § Radius). Existing --radius-sm/md/full
   * re-point onto these at Phase 1; table rows stay square INSIDE a panel-
   * radius table; text inputs take control, never chip. */
  --radius-chip: 999px;
  --radius-control: 10px;
  --radius-card: 14px;
  --radius-table: 0;
  --radius-panel: 20px;
  --radius-screen: 26px; /* CR-14 pending: web-app applicability unconfirmed */

  /* Spacing — brand named step 72 (4pt scale; completes the existing --space-N
   * family; the off-scale 2/20/40px steps are deprecated at Phase 1). */
  --space-18: 72px;

  /* Motion (brand CLAUDE.md § Motion). Existing --duration-* re-point at
   * Phase 1 (fast→90, normal→160, slow→240); slow-420 is NEW so it gets its
   * own family rather than colliding with the current --duration-slow. */
  --motion-instant: 90ms;
  --motion-quick: 160ms;
  --motion-base: 240ms;
  --motion-slow: 420ms;
  --ease-standard: cubic-bezier(0.2, 0, 0, 1);
  --ease-exit: cubic-bezier(0.4, 0, 1, 1);
  --ease-entrance: cubic-bezier(0, 0, 0, 1);

  /* Grid / chrome (brand: 1440 frame, content cap 1120 centered, nav 52). */
  --nav-height: 52px;
  --content-cap: 1120px;
  /* K-BRAND-3.4 — the Lance drawer: 460 on a 1440 frame, min 380, max 520
   * (full width below 900 via the drawer's own media query). Read by
   * .chat-window and the .app-shell--lance-open push plumbing in main.css. */
  --lance-drawer-width: clamp(380px, 32vw, 520px);

  /* Glass-lens material — values from reference/brand-standards.html s6 (the
   * ONLY source; CR-6 asks the client for upstream token homes). The page
   * gradient runs at --surface-angle; the lens fill runs exactly reversed at
   * --glass-angle — the reversal is what makes the edge read as glass.
   * Light-ground set at :root; espresso variants suffixed until the Phase-2
   * ground scope re-points the bare names. */
  --surface-angle: 150deg;
  --glass-angle: 330deg;
  --glass-blur: 14px;
  --glass-saturate: 1.3;
  /* K-v195-Waist (2026-08-04) — Carlos: "it is not transparency but they seem to
   * carry their own gradient." The s6 fill is a V — 0.66 down to 0.24 at 48%,
   * back up to 0.46 — so every lens carried a WAIST of extra warmth across its
   * middle. On a chip that is a sheen; on a 692px reading card it reads as a
   * gradient belonging to the card, which is the opposite of what a lens is for.
   *
   * Deviation from s6, deliberate and ours (Carlos: fix it, no client CR). Each
   * stop's deviation from --glass-lo is compressed to 35%, so the reversal
   * survives and the waist does not. Measured on the blue channel across a card
   * (where the warm shift lives — LUMINANCE IS NEARLY BLIND TO IT, 0.0722
   * weight, and measuring luminance first said this change was a no-op):
   *   0.66/0.24/0.46 → 217 215 216 212 212 210 209 213 223   (dip = the waist)
   *   0.53/0.38/0.46 → 217 217 218 218 218 218 217 220 226   (monotonic)
   * The residual rise is the page gradient through the blur — a lens SHOULD
   * transmit that. Espresso variants are untouched: at 0.15/0.035/0.10 the same
   * V is a quarter the amplitude over a dark ground and does not read as a waist. */
  --glass-hi: rgba(255, 255, 255, 0.53);
  --glass-mid: rgba(255, 255, 255, 0.38);
  --glass-lo: rgba(255, 255, 255, 0.46);
  --glass-edge: rgba(255, 255, 255, 0.58);
  --glass-sheen: rgba(255, 255, 255, 0.70);
  --glass-shadow: 0 10px 26px -14px rgba(58, 42, 31, 0.42);
  --glass-shadow-raised: 0 18px 44px -20px rgba(58, 42, 31, 0.5);
  --glass-hi-espresso: rgba(255, 255, 255, 0.15);
  --glass-mid-espresso: rgba(255, 255, 255, 0.035);
  --glass-lo-espresso: rgba(255, 255, 255, 0.10);
  --glass-edge-espresso: rgba(255, 255, 255, 0.17);
  --glass-sheen-espresso: rgba(255, 255, 255, 0.22);
  --glass-shadow-espresso: 0 12px 30px -16px rgba(0, 0, 0, 0.66);
  --glass-shadow-raised-espresso: 0 20px 50px -22px rgba(0, 0, 0, 0.75);

  /* Legibility scrim (reference s5b): type over a gradient always gets one —
   * a soft dark wash across the copy end of the panel. */
  --scrim-copy: linear-gradient(158deg, rgba(45, 32, 23, 0.74), rgba(45, 32, 23, 0.56) 48%, rgba(45, 32, 23, 0.22) 74%, transparent 92%);

  /* Surface constants (reference s11 / contrast.mjs — CR-6 pending upstream
   * token homes; these are the audited ink grounds). */
  --surface-paper: #F7F4EF;
  --surface-card-light: #F6EADF;
  --surface-card-espresso: #4A3527;

  /* ── The centred espresso PHOTO GROUND (TBL2-1435) ────────────────────────
   * Carlos, 2026-08-26 (relayed by Esteban): a photo frame sits on the brand
   * package's centred espresso ground. This supersedes TBL2-1427's Affogato
   * ruling FOR PHOTO FRAMES ONLY — Affogato stands everywhere else.
   *
   * CR-6 class of gap, and the sharpest one yet: the brand rules name "the
   * espresso ground" in PROSE and ship no token for it, and all six gradients
   * the package does ship (§A hero, ambient, affogato, ember, goldb, goldc)
   * are LINEAR. Nothing upstream matched what the
   * package's own talent frames actually show. Measured off the four sample
   * frames that carry it — method, accuracy and reproduction in
   * docs/analysis/talent-frame-espresso-ground.md. Reconcile if the client
   * ever emits it.
   *
   * DERIVED, NOT TRANSCRIBED. The ramp is a Gaussian falloff between two §A
   * primitives, sampled out to 3 sigma, where the tail has decayed to 1.111%
   * of espresso-700 and the ramp is espresso-900 for the eye:
   *
   *     stop(t) = color-mix(in srgb, --espresso-700 P%, --espresso-900)
   *     P       = exp(-(3t)^2 / 2)
   *
   * Written as color-mix rather than nine hexes so a §A re-vendor of either
   * endpoint propagates instead of drifting silently — the whole reason this
   * file is the only sanctioned home for color-mix. The percentages are exact
   * to 3dp: each rounds to the measured stop byte-for-byte.
   *
   * THEME-INVARIANT BY CONSTRUCTION, which is why it belongs in this bottom
   * block per the K-BRAND-1.2 note above: --espresso-700 and --espresso-900
   * are each declared exactly once in §A with no dark override, so nothing
   * here can be out-cascaded. (Contrast --hero-*, which has three definitions
   * and swaps ramps — TBL2-1334.)
   *
   * Composed by `ground-photo` in shared/_ground.scss. Never inline the
   * stops at a call site; the mixin is the single definition. */
  --photoground-0: var(--espresso-700);
  --photoground-1: color-mix(in srgb, var(--espresso-700) 95.600%, var(--espresso-900));
  --photoground-2: color-mix(in srgb, var(--espresso-700) 83.527%, var(--espresso-900));
  --photoground-3: color-mix(in srgb, var(--espresso-700) 66.698%, var(--espresso-900));
  --photoground-4: color-mix(in srgb, var(--espresso-700) 48.675%, var(--espresso-900));
  --photoground-5: color-mix(in srgb, var(--espresso-700) 32.465%, var(--espresso-900));
  --photoground-6: color-mix(in srgb, var(--espresso-700) 17.732%, var(--espresso-900));
  --photoground-7: color-mix(in srgb, var(--espresso-700) 6.471%, var(--espresso-900));
  --photoground-8: color-mix(in srgb, var(--espresso-700) 1.111%, var(--espresso-900));

  /* TBL2-1770 — THE TWO OTHER PHOTO GROUNDS (Carlos + Sarah, 2026-10-02).
   *
   * A person now picks the ground behind their photo: Espresso (above), Teal,
   * Deep orange or Light orange, "all of them with that gradient / sunburst /
   * halo". Each one is the SAME Gaussian as the espresso ramp, with the same
   * nine P values, between its own pair of §A primitives — so the halo has the
   * same shape on every colour and only the colours change.
   *
   * The pairs are the centre colour and the edge colour. The two oranges are
   * Carlos's options 4 and 5 from the TBL2-1770 comparison sheet, endpoint for
   * endpoint (TBL2-1781, 2026-10-05). The brand --orange ramp was option 3: the
   * picker no longer offers it, but a photo saved with it before he picked
   * keeps its ground, so the ramp stays.
   *
   * THEME-INVARIANT for the same reason as the espresso ramp: every endpoint
   * is declared once in §A with no dark override.
   *
   * Selected by `.brand-ground-photo--teal` / `--deeporange` / `--lightorange`
   * / `--orange` in material-utilities.scss, which reassign the nine
   * --photoground-N the mixin reads. Never inline these stops at a call site. */
  --photoground-teal-0: var(--teal);
  --photoground-teal-1: color-mix(in srgb, var(--teal) 95.600%, var(--teal-800));
  --photoground-teal-2: color-mix(in srgb, var(--teal) 83.527%, var(--teal-800));
  --photoground-teal-3: color-mix(in srgb, var(--teal) 66.698%, var(--teal-800));
  --photoground-teal-4: color-mix(in srgb, var(--teal) 48.675%, var(--teal-800));
  --photoground-teal-5: color-mix(in srgb, var(--teal) 32.465%, var(--teal-800));
  --photoground-teal-6: color-mix(in srgb, var(--teal) 17.732%, var(--teal-800));
  --photoground-teal-7: color-mix(in srgb, var(--teal) 6.471%, var(--teal-800));
  --photoground-teal-8: color-mix(in srgb, var(--teal) 1.111%, var(--teal-800));

  --photoground-deeporange-0: var(--deeporange);
  --photoground-deeporange-1: color-mix(in srgb, var(--deeporange) 95.600%, var(--orange-900));
  --photoground-deeporange-2: color-mix(in srgb, var(--deeporange) 83.527%, var(--orange-900));
  --photoground-deeporange-3: color-mix(in srgb, var(--deeporange) 66.698%, var(--orange-900));
  --photoground-deeporange-4: color-mix(in srgb, var(--deeporange) 48.675%, var(--orange-900));
  --photoground-deeporange-5: color-mix(in srgb, var(--deeporange) 32.465%, var(--orange-900));
  --photoground-deeporange-6: color-mix(in srgb, var(--deeporange) 17.732%, var(--orange-900));
  --photoground-deeporange-7: color-mix(in srgb, var(--deeporange) 6.471%, var(--orange-900));
  --photoground-deeporange-8: color-mix(in srgb, var(--deeporange) 1.111%, var(--orange-900));

  --photoground-lightorange-0: var(--lightorange);
  --photoground-lightorange-1: color-mix(in srgb, var(--lightorange) 95.600%, var(--orange-700));
  --photoground-lightorange-2: color-mix(in srgb, var(--lightorange) 83.527%, var(--orange-700));
  --photoground-lightorange-3: color-mix(in srgb, var(--lightorange) 66.698%, var(--orange-700));
  --photoground-lightorange-4: color-mix(in srgb, var(--lightorange) 48.675%, var(--orange-700));
  --photoground-lightorange-5: color-mix(in srgb, var(--lightorange) 32.465%, var(--orange-700));
  --photoground-lightorange-6: color-mix(in srgb, var(--lightorange) 17.732%, var(--orange-700));
  --photoground-lightorange-7: color-mix(in srgb, var(--lightorange) 6.471%, var(--orange-700));
  --photoground-lightorange-8: color-mix(in srgb, var(--lightorange) 1.111%, var(--orange-700));

  --photoground-orange-0: var(--orange);
  --photoground-orange-1: color-mix(in srgb, var(--orange) 95.600%, var(--orange-800));
  --photoground-orange-2: color-mix(in srgb, var(--orange) 83.527%, var(--orange-800));
  --photoground-orange-3: color-mix(in srgb, var(--orange) 66.698%, var(--orange-800));
  --photoground-orange-4: color-mix(in srgb, var(--orange) 48.675%, var(--orange-800));
  --photoground-orange-5: color-mix(in srgb, var(--orange) 32.465%, var(--orange-800));
  --photoground-orange-6: color-mix(in srgb, var(--orange) 17.732%, var(--orange-800));
  --photoground-orange-7: color-mix(in srgb, var(--orange) 6.471%, var(--orange-800));
  --photoground-orange-8: color-mix(in srgb, var(--orange) 1.111%, var(--orange-800));
}

/* ═══════════════════════════════════════════════════════════════════════════
 * TBL2-1334 item 1 — THE ESPRESSO HERO RAMP (dark ground).
 *
 * RULED: Carlos, 2026-08-22, judged LIVE on the running stack via the K-v195
 * dev-toggle overlay against three candidates — "A looks the best". R-1 and
 * TBL2-1301 §VERIFICATION MECHANICS ¶3 require this call be made on a
 * rendering, never on a screenshot pair; it was.
 *
 * Candidate A, "Espresso mirror": it keeps the LIGHT ramp's shape — a lift at
 * the 33% stop, then a warm descent — rebuilt entirely from existing brand
 * palette values. Nothing new is minted; only the ramp assignment is new.
 *
 * WHY THIS BLOCK EXISTS AT ALL. --hero-0..3 are declared once, inside the
 * VENDORED brand block (§A, headed "A. VENDORED brand palette"), a named
 * TBL2-1301 fence, and is
 * not edited. `styles/shell-ground.scss` paints them unconditionally on the
 * authenticated layout, so before this block dark mode rendered a LIGHT hero
 * ground under espresso panels, with page-header ink washed out over it
 * (measured on the proto and on the local stack; docs/evidence/TBL2-1334/).
 *
 * SCOPE IS DELIBERATELY NARROW — the two THEME selectors only, NOT the
 * [data-ground="espresso"] arm that the main dark block
 * (body.dark-mode, [data-theme="dark"], [data-ground="espresso"]) also carries.
 * That arm scopes espresso BANDS inside light surfaces; they are not page
 * grounds and do not paint ground-hero, so folding a ground ramp into them
 * would widen the blast radius for no demonstrated need.
 *
 * THE SELECTOR IS BODY-SCOPED ON PURPOSE, AND THAT IS LOAD-BEARING.
 * ThemeService sets data-theme="dark" on <html> (theme.service.ts), so a bare
 * [data-theme="dark"] arm would match :root — the SAME element where
 * --main-accent-2: var(--hero-2) is declared. --main-accent-2 would
 * then recompute against the dark --hero-2 and every avatar colour and
 * profile-hero gradient would go muddy brown. MEASURED: with a bare arm,
 * html[data-theme="dark"] gave --main-accent-2 #422F21 instead of #F5C08E.
 * Excluding :root — while still matching `body` under it, and still matching a
 * scoped [data-theme="dark"] subtree — keeps the ramp off :root, so
 * --main-accent-2 stays frozen against the LIGHT --hero-2 as this file's
 * Tier-2 header rule requires
 * ("--main-accent-1 and --main-accent-2 stay static (rose/peach)"). Caught by
 * Copilot on PR #1771; pinned by hero-dark-ramp.spec.ts, which now exercises
 * the <html> attribute path and not only body.dark-mode.
 * ═══════════════════════════════════════════════════════════════════════════ */
body.dark-mode,
[data-theme="dark"]:not(:root),
[data-theme="dark"] body {
  --hero-0: #3A2A1F;  /* espresso-800 */
  --hero-1: #4C3E33;  /* espresso-600 — the lift at 33%, mirroring the light ramp */
  --hero-2: #422F21;  /* espresso-700 */
  --hero-3: #2D160E;  /* blush-900   — the deep warm anchor */
}

/* ── TBL2-1334 item 1 — THE LIGHT RE-PIN FOR THE HERO RAMP ──────────────────
 * The dark ramp above inherits into EVERY descendant of body, including the
 * pre-auth light lock (`<div data-theme="light">`, public.component.html:1).
 * --hero-0..3 are declared only on :root in the vendored §A block, so the lock
 * had nothing to re-pin them with, and `.main-background` — which consumes them
 * with !important — painted the ESPRESSO ground on /login and /apply after a
 * dark-mode -> logout SPA transition.
 *
 * MEASURED before this block: inside the lock under a dark body, --hero-0..3
 * resolved #3A2A1F #4C3E33 #422F21 #2D160E and .main-background painted
 * linear-gradient(150deg in oklab, rgb(58,42,31) ...). The light lock held for
 * the alias family and leaked the ground.
 *
 * :root is deliberately NOT in this selector — §A stays the sole :root
 * declaration of the ramp. Caught by Copilot on PR #1771.
 * ─────────────────────────────────────────────────────────────────────────── */
[data-theme="light"],
[data-ground="light"] {
  --hero-0: #E5CBBC;
  --hero-1: #FCE8D1;
  --hero-2: #F5C08E;
  --hero-3: #CB7C50;
}
