/* ============================================================================
   GRAIN → SOLLEVA — the compat / swap layer  (NOT imported by the barrel)
   ----------------------------------------------------------------------------
   THIS FILE IS NOT INERT AND IS NOT SUPPOSED TO BE. It is the swap: it
   re-points grain's shipping token names onto Solleva values, revives the
   style-dictionary token surface, and re-states body/selection/focus/motion
   in the Solleva register. Importing it CHANGES HOW EVERY CONSUMER RENDERS.

   Who turns it on:
     - T-GRAIN-SWAP (grain step 3) — adds one @import to src/styles.css.
     - a consumer that wants to preview early:
         import '@goforgeit/grain/themes/grain-solleva-compat.css'
       AFTER '@goforgeit/grain/styles.css' (it must win the cascade).

   What must be settled BEFORE it is turned on:
     - §2b revives custom properties that no grain file declares today. Some
       were live `var()` call sites in consumers that resolved to NOTHING —
       foundry (--font-size-display), lore and anvil (--tracking-widest).
       Turning them on is a visible change in those repos and it is
       T-GRAIN-DANGLE's (step 2) call, not step 1's. The forge pair that used
       to head this list (forge-ink, forge-soft) is gone: 0.4.7 deletes the
       retired names rather than reviving them.
     - §5's 14 unnamespaced utility classes (.section-label, .mono, .tabular,
       .text-muted, .bg-atmospheric, …) collide by name with cream.css and
       typography.css and with consumer markup.
     - §6's `*, *::before, *::after { … !important }` reduced-motion block.

   This file @imports the spine, so it is self-contained: linking it alone
   resolves every value. That is also how T-GRAIN-ALIAS's read-back evidence
   is specified — "the layer loaded in isolation" means this file, alone.
   ============================================================================ */

@import "./grain-solleva.css";

/* FONTS: the hearth source's remote Google-Fonts @import is deleted here too.
   See the note in grain-solleva.css; T-GRAIN-FONTS self-hosts the faces. */

/* ============================================================================
   §2 GRAIN-COMPAT ALIAS LAYER — every shipping grain token name → Solleva.
   DEPRECATED on arrival. Consumers migrate to --sol-* names; see
   migration.md for the disposition of each. Role-split tokens (forge-blue)
   alias to their MOST COMMON role; the other roles need code changes.
   ============================================================================ */

:root {
  /* Surfaces — the parchment field becomes the daylight field */
  --background:        var(--sol-ground);
  --background-sunken: var(--sol-ground-sunken);
  --background-deep:   var(--sol-ground-deep);
  --surface:           var(--sol-surface);
  --surface-sunken:    var(--sol-ground-sunken);  /* inputs are sunken wells now */
  --surface-elevated:  var(--sol-surface);
  --surface-overlay:   color-mix(in oklab, var(--sol-surface) 55%, transparent);
  /* the atmospheric gradient dies: the daylight ground is flat */
  --bg-gradient:       linear-gradient(var(--sol-ground), var(--sol-ground));

  /* Ink. NOTE: grain --text-faint was READABLE text; it maps to tertiary
     (5.68:1), NOT to --sol-ink-faint (graphic-only, 3.05:1). */
  --ink:            var(--sol-ink);
  --ink-secondary:  var(--sol-ink-secondary);
  --ink-tertiary:   var(--sol-ink-tertiary);
  --ink-emphasis:   var(--sol-ink);
  --text-main:      var(--sol-ink);
  --text-muted:     var(--sol-ink-secondary);
  --text-faint:     var(--sol-ink-tertiary);  /* TEXT. body-faint ink; IS --sol-ink-tertiary,
                                                 whose own declaration is text-licensed. The
                                                 ratio is not restated here because it differs
                                                 by register and GATE 2 measures both. */

  /* Borders — alpha ink */
  --border:          var(--sol-line);
  --border-light:    var(--sol-line-faint);
  --border-hairline: var(--sol-line);
  --border-faint:    var(--sol-line-faint);

  /* Forge Blue — ROLE SPLIT, now DELETED (0.4.7; see migration.md §3.1).
     The four names shipped one release as pure aliases so consumers could
     migrate off the role split; they are gone now, and the roles they carried
     answer to their own names: fill/ink is --ink, the selected wash is
     --background-sunken, the boundary is --border, the graphic accent is
     --sol-accent, and links are --sol-accent-ink.

     DF-1 is why this is a deletion and not another alias. The old comment
     claimed the ink alias "keeps white-text-on-fill readable at 15.9:1" — true
     in daylight, silently assumed in the night block below, where forge-blue
     resolved to a near-white and white-on-near-white measured 1.23:1 in every
     consumer shipping a filled Button. An alias carries a role's NAME without
     carrying its licence. The ink that rides a filled control is --on-accent,
     the controls consume that token, and check-contrast-pairs.mjs measures the
     PAIR in both registers, so the assumption cannot go unstated again. */

  /* Sage → lifted */
  --sage:        var(--sol-lifted);
  --sage-bg:     var(--sol-lifted-tint);
  --sage-border: color-mix(in oklab, var(--sol-lifted) 25%, transparent);
  --sage-vivid:  var(--sol-lifted);

  /* Amber → holding */
  --amber:        var(--sol-holding);
  --amber-bg:     var(--sol-holding-tint);
  --amber-border: color-mix(in oklab, var(--sol-holding) 25%, transparent);
  --amber-vivid:  var(--sol-holding);

  /* Danger → fault */
  --danger-red:        var(--sol-fault);
  --danger-red-bg:     var(--sol-fault-tint);
  --danger-red-border: color-mix(in oklab, var(--sol-fault) 25%, transparent);

  /* Forge Warmth family — RETIRED, and now DELETED. Delight is the daylight
     line. The six neutralizing aliases bought consumers a migration window;
     it closed with 0 reads, so the names go. Glow moments re-point to
     --sol-daylight-line / --sol-accent (graphic) in code. */

  /* Shadows / elevation — warm shadow stack → light-from-below lifts.
     Sunken inset dies: sunken is a lightness step, not a shadow. */
  --shadow-sunken:   none;
  --shadow-elevated: var(--sol-lift-1);
  --shadow-float:    var(--sol-lift-2);
  --shadow-subtle:   var(--sol-lift-1);
  --elevation-0: var(--sol-lift-0);
  --elevation-1: var(--sol-lift-1);
  --elevation-2: var(--sol-lift-1);   /* cards at rest */
  --elevation-3: var(--sol-lift-2);   /* hover / dropdowns */
  --elevation-4: var(--sol-lift-2);

  /* Radii — 4px floor rises to 6px; 12px cards settle to 10px */
  --radius-sm:    var(--sol-radius-1);
  --radius-input: var(--sol-radius-1);
  /* --radius-md was 8px. NOTE: buttons never consumed it — button.tsx:23-26
     hardcodes Tailwind `rounded-md` (6px) on purpose, so buttons are already
     at the Solleva value. What actually moves 8px → 6px is every OTHER
     --radius-md consumer: dropdown-menu (×2), context-menu (×2), select
     popover, rich-tooltip, stream-box, sidebar-rail item. */
  --radius-md:    var(--sol-radius-1);
  --radius-lg:    var(--sol-radius-2);
  --radius-panel: var(--sol-radius-2);
  --radius-card:  var(--sol-radius-2);
  --radius-pill:  var(--sol-radius-pill);

  /* Typography — three voices become two (+ code-only mono) */
  --font-sans:  var(--sol-font-sans);    /* Inter Tight → Archivo */
  --font-serif: var(--sol-font-serif);   /* Newsreader → Source Serif 4 */
  --font-mono:  var(--sol-font-code);    /* JetBrains Mono → code-only; metric
                                            values must move to Archivo tabular-nums */
  --font-size-base:      var(--sol-text-2);
  --line-height-base:    var(--sol-leading-ui);
  --letter-spacing-base: 0;              /* Archivo runs untracked at text sizes */

  --tracking-tight:  var(--sol-tracking-display);
  --tracking-normal: 0;
  --tracking-wide:   var(--sol-tracking-label);
  --tracking-caps:   var(--sol-tracking-label);  /* 0.12em → 0.08em */

  --weight-body:    var(--sol-weight-body);
  --weight-label:   var(--sol-weight-medium);
  --weight-heading: var(--sol-weight-title);

  /* Spacing — same 4px scale, grain names */
  --space-1: var(--sol-space-1);  --space-2: var(--sol-space-2);
  --space-3: var(--sol-space-3);  --space-4: var(--sol-space-4);
  --space-6: var(--sol-space-5);  --space-8: var(--sol-space-6);
  --space-12: var(--sol-space-7); --space-16: var(--sol-space-8);
  --space-24: var(--sol-space-9);

  /* Motion — role split: grain's one "normal" becomes quick (state) vs
     rise (entrance). The alias favors entrances; state transitions should
     migrate to --sol-t-quick in code. */
  --duration-fast:   var(--sol-t-quick);
  --duration-normal: var(--sol-t-rise);
  --duration-slow:   var(--sol-t-settle);
  --ease-default:    var(--sol-ease);
  --ease-out:        var(--sol-ease);
  --ease-spring:     var(--sol-ease);    /* nothing bounces */
  --ease-decelerate: var(--sol-ease);

  /* Layout */
  --sidebar-w: var(--sol-rail-w);
  --topbar-h:  var(--sol-topbar-h);
  --activity-h: 120px;
}

/* ----------------------------------------------------------------------------
   §2b THE STYLE-DICTIONARY SURFACE — grain publishes a SECOND token set at
   tokens/build/css/grain-tokens.css that does NOT ship in dist/grain.css and
   is imported by nobody in grain's own src. Consumers still reach for it
   (foundry: --font-size-caption ×3; kiln: forge-ink ×3, forge-soft ×1) —
   and those uses resolve to NOTHING today, because the file is never loaded.
   Aliased here so the migration doesn't silently inherit a live bug.
   Two of these are BELOW THE 12px FLOOR and are therefore NOT aliased to a
   working value — they are deliberately left to fail, loudly. See migration.md §2.4.
   ---------------------------------------------------------------------------- */
:root {
  /* The SD build spells the atmospheric gradient --background-gradient; cream.css
     spells the same thing --bg-gradient. Both die into the flat daylight ground. */
  --background-gradient: linear-gradient(var(--sol-ground), var(--sol-ground));
  /* forge-ink and forge-soft are DELETED (0.4.7). §2b aliased them because
     kiln read them (×3 and ×1) against a stylesheet that was never loaded, so
     the reads resolved to nothing. kiln's origin/main now reads neither — the
     only surviving mentions in any consumer are prose — so the alias has no
     reader left and the name goes. --ink and --background-sunken are the roles. */
  --on-accent:      var(--sol-surface);          /* text riding a filled control */
  --hairline:       var(--sol-line);             /* was #DCD4C7 — a parchment hairline */
  --surface-muted:  var(--sol-ground-sunken);
  --sage-soft:      var(--sol-lifted-tint);
  --amber-soft:     var(--sol-holding-tint);
  --radius-control: var(--sol-radius-1);         /* 11px → 6px */
  --radius-card-lg: var(--sol-radius-2);         /* 14px → 10px */
  --space-cardPad:      var(--sol-space-4);      /* 14px → 16px (onto the 4px grid) */
  --space-mobileGutter: var(--sol-space-4);      /* 18px → 16px (onto the 4px grid) */
  --tracking-smallcaps: var(--sol-tracking-label); /* 0.06em → 0.08em */
  --tracking-widest:    var(--sol-tracking-label); /* 0.14em → 0.08em; one label tracking */

  /* The named size ramp collapses onto the six steps. */
  --font-size-narrative:  var(--sol-text-3);     /* 13px sans → 15.5px serif */
  --font-size-title:      var(--sol-text-4);     /* 18px  → 18px */
  --font-size-heading:    var(--sol-text-5);     /* 20px  → 22px */
  --font-size-display-sm: var(--sol-text-6);     /* 25px  → 28px */
  --font-size-display:    var(--sol-text-6);     /* 28px  → 28px (product ceiling) */
  /* --font-size-caption (11px) and --font-size-eyebrow (9px) are NOT aliased.
     Both sit under the 12px floor; there is no legal Solleva value for them.
     Call sites must move to --sol-text-1 (12px) explicitly. Leaving them
     undefined makes the migration visible instead of silently rounding it up. */
}

/* ============================================================================
   §3 STATUS / AGENT SEMANTICS — verbs, not moods.
   Status color always travels with a word; color is never the only signifier.
   ============================================================================ */

:root {
  /* Agent status — grain names, Solleva verbs */
  --status-running:  var(--sol-lifted);        /* alive and carrying */
  --status-idle:     var(--sol-ink-faint);     /* graphic use only */
  --status-thinking: var(--sol-holding);
  --status-stopped:  var(--sol-ink-faint);
  --status-tripped:  var(--sol-fault);

  --eval-pass: var(--sol-lifted);
  --eval-warn: var(--sol-holding);
  --eval-fail: var(--sol-fault);

  /* Agent types — the four-hue family collapses into the slate/status
     system. Who an agent IS is carried by name + icon; color carries only
     what it is DOING. Distinct hues retained solely for dense multi-agent
     visualizations (Forge), derived from the ink/status ramps: */
  --agent-orchestrator: var(--sol-ink-secondary);
  --agent-worker:       var(--sol-lifted);
  --agent-human:        var(--sol-accent-ink);   /* the human is the accent */
  --agent-specialist:   var(--sol-holding);
  --agent-orchestrator-bg: var(--sol-ground-sunken);
  --agent-orchestrator-border: var(--sol-line-strong);
  --agent-worker-bg: var(--sol-lifted-tint);
  --agent-worker-border: color-mix(in oklab, var(--sol-lifted) 25%, transparent);
  --agent-human-bg: var(--sol-accent-tint);
  --agent-human-border: color-mix(in oklab, var(--sol-accent-ink) 25%, transparent);
  --agent-specialist-bg: var(--sol-holding-tint);
  --agent-specialist-border: color-mix(in oklab, var(--sol-holding) 25%, transparent);
}

[data-theme="dark"] {
  /* SPINE RE-POINTS — the night register's other half.
     §5 below paints unnamespaced surfaces (body, ::selection, .text-*,
     .bg-textured, :focus-visible) directly from the SPINE's daylight names,
     not from the grain names re-pointed underneath. Re-pointing only the grain
     names left every one of those rules painting daylight under
     data-theme="dark": a measured body background of oklch(0.98 0.006 250)
     (--sol-ground) on a document whose --background had correctly resolved to
     oklch(0.230 0.025 255). That is the "silent fallback to cream" this track
     exists to remove, surviving inside the fix for it.
     check-dark-theme.mjs now enumerates the colour-bearing --sol-* tokens the
     painted rules reference and requires every one to appear here; the 12
     non-colour ones (fonts, sizes, leading, tracking, weight) are excluded by
     name in that check's EXCLUDED block. Count required here: 6.

     0.4.6 — THE SIX WERE THE PAINTED RULES' NAMES, NOT THE CONSUMED ONES.
     check-dark-theme's population is "--sol-* names referenced by a colour-
     bearing property inside a compat RULE". grain's COMPONENTS are not compat
     rules — they ship as Tailwind class strings in dist/index.js and are
     compiled in the consumer's build against this barrel — so every spine name
     a component consumed was outside that population and no check required a
     night value for it. Measured downstream: a surface painting
     --sol-ground-sunken rendered oklch(0.958 …), daylight, under
     data-theme="dark" (kiln: 1.09:1 foreground/background). That is the same
     "silent fallback to cream" this block exists to remove, one namespace over.
     The RAMPS are therefore completed rather than the individual names patched
     — a hole in a ramp is how this recurred twice. Each value below is the one
     the GRAIN-name role directly beneath it already carries in this same block,
     so the two namespaces cannot drift; the one derived value says so. */
  --sol-ground:        var(--sol-night);
  /* Ground ramp — mirrors --surface / --background-sunken / --background-deep
     below. Surfaces get lighter as they rise in daylight; at night they get
     lighter as they rise too, so the ramp keeps its direction. */
  --sol-surface:       var(--sol-night-raised);
  --sol-ground-sunken: color-mix(in oklab, var(--sol-night) 88%, var(--sol-night-raised));
  --sol-ground-deep:   color-mix(in oklab, var(--sol-night) 94%, var(--sol-daylight-on-night));
  /* Graphic-only ink. Mirrors --status-idle / --status-stopped below, which is
     where this token's night value is already ruled. GRAPHIC/DISABLED ONLY in
     both registers — its daylight declaration refuses glyphs and so does this. */
  --sol-ink-faint:     color-mix(in oklab, var(--sol-daylight-on-night) 42%, transparent);
  /* Accent, graphic half. --sol-accent-on-night is the spine's own night twin
     of --sol-accent and carries the same GRAPHIC-ONLY licence (never text);
     --amber-vivid below already points at it. (forge-blue-vivid and
     forge-gold used to be named here too; 0.4.7 deleted them.) The text half
     (--sol-accent-ink) and the ring half (--sol-accent-deep) are re-pointed
     further down, by threshold, and are NOT this name. */
  --sol-accent:        var(--sol-accent-on-night);
  --sol-accent-tint:   color-mix(in oklab, var(--sol-accent-on-night) 12%, var(--sol-night));
  /* Lines. Mirrors --border / --border-light below: the night register carries
     its lines as the night INK at alpha, not as the daylight ink.
     --sol-line-strong is the one DERIVED value in this block — the daylight
     ramp is ink at 6/12/22% and the night ramp only ever declared its 14% and
     22% steps, so there is no ruled night figure for "strong". It takes 34%,
     which was the step this block used for its strong boundary (the deleted
     forge-blue-border) applied to the night ink instead of the night accent.
     That alias is gone as of 0.4.7, so this line is now the sole carrier of the
     34% figure rather than a second copy of it. Measured on --sol-night:
     3.31:1, clearing WCAG 1.4.11's 3:1 — the only threshold a line must meet. */
  --sol-line:          color-mix(in oklab, var(--sol-daylight-on-night) 22%, transparent);
  --sol-line-faint:    color-mix(in oklab, var(--sol-daylight-on-night) 14%, transparent);
  --sol-line-strong:   color-mix(in oklab, var(--sol-daylight-on-night) 34%, transparent);
  --sol-ink:           var(--sol-daylight-on-night);
  --sol-ink-secondary: color-mix(in oklab, var(--sol-daylight-on-night) 76%, transparent);
  --sol-ink-tertiary:  color-mix(in oklab, var(--sol-daylight-on-night) 62%, transparent);
  --sol-selection:     color-mix(in oklab, var(--sol-accent-on-night) 28%, var(--sol-night-raised));

  /* THE ACCENT INKS MUST FLIP TOO — T-GRAIN-REPOINT.
     --sol-accent-ink (#AB3415) and --sol-accent-deep (#892312) are
     DAYLIGHT-PRESSED values: they are dark oranges chosen to sit on a near-white
     ground, where they measure 6.14:1 and 8.58:1. On the night ground they are
     near-black, and measured by the contrast sweep they collapse to
        --sol-accent-ink  -> 2.59:1   (links: BELOW AA 4.5:1)
        --sol-accent-deep -> 1.85:1   (focus rings: BELOW 3:1, WCAG 1.4.11)
     Step 5 re-points links and focus rings ONTO these two names, so without
     this block that re-point silently makes every link unreadable and every
     focus ring invisible in dark mode — the exact "silent fallback to cream"
     class T-GRAIN-SWAP's own night block was written to remove, reappearing
     one token further down.

     THE TWO NAMES DO NOT TAKE THE SAME VALUE, and an earlier revision of this
     block gave them one. --sol-accent-on-night is 5.46:1 ON --sol-night — the
     ground, and the only surface it was ever measured against. It clears the
     3:1 of WCAG 1.4.11 everywhere a ring lands, so it is right for
     --sol-accent-deep. It does NOT clear the 4.5:1 of 1.4.3 once text rides a
     RAISED surface: on --surface-elevated it is 3.92:1, which
     grain-solleva.css:121 states in the token's own declaration ("GRAPHIC
     ONLY"). Pointing the TEXT name at it therefore reintroduces, for
     Button/elevated and Button/text, the very defect this block exists to
     remove — measured, 16 rendered pairs below AA in dark.
     --sol-accent-ink-on-night is the TEXT twin (grain-solleva.css:128) and
     clears AA on every night surface a text run can land on: 7.19:1 on the
     ground, 6.21:1 raised, 5.00:1 on --surface-elevated, 6.22:1 on the tint.
     It arrived with DF-1 (52ecef0), after this track's base 9edadf7.

     Threshold decides the name: 1.4.11 (3:1, rings/boundaries) ->
     --sol-accent-on-night; 1.4.3 (4.5:1, text) -> --sol-accent-ink-on-night. */
  --sol-accent-ink:    var(--sol-accent-ink-on-night);  /* TEXT  — 1.4.3, 4.5:1 */
  --sol-accent-deep:   var(--sol-accent-on-night);      /* RINGS — 1.4.11, 3:1 */
  /* The ring's inner halo separates the control from whatever it sits on, so it
     tracks the page, not a fixed cream; the outer ring moves to the on-night
     accent (5.46:1 on night) because --sol-accent-deep is a daylight-pressed
     value and reads as near-black against the night ground. */
  --sol-focus-ring:    0 0 0 2px var(--sol-night), 0 0 0 4px var(--sol-accent-on-night);

  /* Surfaces */
  --background:        var(--sol-night);
  --background-sunken: color-mix(in oklab, var(--sol-night) 88%, var(--sol-night-raised));
  --background-deep:   color-mix(in oklab, var(--sol-night) 94%, var(--sol-daylight-on-night));
  --surface:           var(--sol-night-raised);
  --surface-sunken:    var(--sol-night);
  --surface-elevated:  color-mix(in oklab, var(--sol-night-raised) 92%, var(--sol-daylight-on-night));
  --surface-overlay:   color-mix(in oklab, var(--sol-night-raised) 88%, transparent);
  --surface-muted:     color-mix(in oklab, var(--sol-night) 72%, var(--sol-night-raised));
  --bg-gradient:       linear-gradient(var(--sol-night), var(--sol-night));
  --background-gradient: linear-gradient(var(--sol-night), var(--sol-night));

  /* Ink and borders */
  --ink:            var(--sol-daylight-on-night);
  --ink-secondary:  color-mix(in oklab, var(--sol-daylight-on-night) 76%, transparent);
  --ink-tertiary:   color-mix(in oklab, var(--sol-daylight-on-night) 62%, transparent);
  --ink-emphasis:   var(--sol-daylight-on-night);
  --text-main:      var(--sol-daylight-on-night);
  --text-muted:     color-mix(in oklab, var(--sol-daylight-on-night) 76%, transparent);
  /* Follows --sol-ink-tertiary BY CONSTRUCTION rather than repeating its
     night value. Taken from lane A. The literal that used to sit here was a
     hand-copied duplicate of the --sol-ink-tertiary line 4 rows above, so the
     two could drift and the by-ROLE mapping this track exists to guarantee
     would quietly stop holding in the night register only. */
  --text-faint:     var(--sol-ink-tertiary);  /* TEXT. body-faint ink; IS --sol-ink-tertiary,
                                                 whose own declaration is text-licensed. The
                                                 ratio is not restated here because it differs
                                                 by register and GATE 2 measures both. */
  --border:          color-mix(in oklab, var(--sol-daylight-on-night) 22%, transparent);
  --border-light:    color-mix(in oklab, var(--sol-daylight-on-night) 14%, transparent);
  --border-hairline: color-mix(in oklab, var(--sol-daylight-on-night) 22%, transparent);
  --border-faint:    color-mix(in oklab, var(--sol-daylight-on-night) 14%, transparent);
  --hairline:        color-mix(in oklab, var(--sol-daylight-on-night) 22%, transparent);
  --on-accent:       var(--sol-night);

  /* Legacy accent families, reduced to the night register.
     ------------------------------------------------------------------------
     THE `*-bg` TINTS MIX INTO --sol-night, NOT INTO `transparent`. They used to
     mix into transparent, which meant the tint's RENDERED lightness was a
     function of whatever surface it happened to sit on — so the contrast
     between the accent ink and its own tint was not knowable at the point the
     token is defined. Measured: --danger-red on --danger-red-bg came out
     4.72:1 over the ground, 4.12:1 over --surface, 3.43:1 over
     --surface-elevated. Same token pair, three answers, one of them failing.
     That is DF-1's shape exactly: a value that only works if you already know
     what is underneath it. Opaque tints make the pair deterministic and
     surface-independent (4.72:1 everywhere), and they match the daylight
     register, where the tints are solid tokens (--sol-fault-tint,
     --sol-accent-tint) rather than washes. The accent hue is untouched.
     Borders stay translucent: a border is not a text background. */
  /* The twelve forge-* names are DELETED in the night register too (0.4.7).
     A name retired in one register and kept in the other is still a shipped
     name: the done-gate measures the TRANSITIVE CLOSURE, so every night colour
     these aliases reached was reachable as forge pigment and counted as such. */

  --sage:        var(--sol-daylight-on-night);
  --sage-bg:     color-mix(in oklab, var(--sol-daylight-on-night) 10%, var(--sol-night));
  --sage-soft:   color-mix(in oklab, var(--sol-daylight-on-night) 10%, transparent);
  --sage-border: color-mix(in oklab, var(--sol-daylight-on-night) 25%, transparent);
  --sage-vivid:  var(--sol-daylight-on-night);
  --amber:        var(--sol-accent-ink-on-night);   /* TEXT role (Badge/warning, Chip/amber) */
  --amber-bg:     color-mix(in oklab, var(--sol-accent-on-night) 12%, var(--sol-night));
  --amber-soft:   color-mix(in oklab, var(--sol-accent-on-night) 12%, transparent);
  --amber-border: color-mix(in oklab, var(--sol-accent-on-night) 25%, transparent);
  --amber-vivid:  var(--sol-accent-on-night);
  --danger-red:        var(--sol-accent-ink-on-night);  /* TEXT role (Badge/destructive, Chip/danger, MiniCard delta) */
  --danger-red-bg:     color-mix(in oklab, var(--sol-accent-on-night) 12%, var(--sol-night));
  --danger-red-border: color-mix(in oklab, var(--sol-accent-on-night) 25%, transparent);

  /* Status and agent semantics */
  --status-running:  var(--sol-daylight-on-night);
  --status-idle:     color-mix(in oklab, var(--sol-daylight-on-night) 42%, transparent);
  --status-thinking: var(--sol-accent-on-night);
  --status-stopped:  color-mix(in oklab, var(--sol-daylight-on-night) 42%, transparent);
  --status-tripped:  var(--sol-accent-on-night);
  --eval-pass: var(--sol-daylight-on-night);
  --eval-warn: var(--sol-accent-on-night);
  --eval-fail: var(--sol-accent-on-night);
  --agent-orchestrator: color-mix(in oklab, var(--sol-daylight-on-night) 76%, transparent);
  --agent-worker:       var(--sol-daylight-on-night);
  --agent-human:        var(--sol-accent-ink-on-night);  /* TEXT role (agent labels) */
  --agent-specialist:   var(--sol-accent-on-night);
  --agent-orchestrator-bg:     var(--sol-night);
  --agent-orchestrator-border: color-mix(in oklab, var(--sol-daylight-on-night) 28%, transparent);
  --agent-worker-bg:           color-mix(in oklab, var(--sol-daylight-on-night) 10%, var(--sol-night));
  --agent-worker-border:       color-mix(in oklab, var(--sol-daylight-on-night) 25%, transparent);
  --agent-human-bg:            color-mix(in oklab, var(--sol-accent-on-night) 12%, var(--sol-night));
  --agent-human-border:        color-mix(in oklab, var(--sol-accent-on-night) 25%, transparent);
  --agent-specialist-bg:       color-mix(in oklab, var(--sol-accent-on-night) 12%, var(--sol-night));
  --agent-specialist-border:   color-mix(in oklab, var(--sol-accent-on-night) 25%, transparent);
}

/* ============================================================================
   §5 UTILITIES — the unnamespaced ones. Every class below already exists by
   name in cream.css / typography.css or in consumer markup; that is the point
   (they are re-points), and it is why they cannot ship in the inert spine.
   ============================================================================ */

body {
  font-family: var(--sol-font-sans);
  font-size: var(--sol-text-2);
  line-height: var(--sol-leading-ui);
  letter-spacing: 0;
  color: var(--sol-ink);
  background: var(--sol-ground);   /* flat — no gradient, no noise. --sol-ground
                                      is daylight at :root and night under
                                      [data-theme="dark"], so this one
                                      declaration serves both registers. */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Section label — WAS 11px in grain (below the floor). Now step 1: 12px. */
.section-label {
  font-family: var(--sol-font-sans);
  font-size: var(--sol-text-1);
  font-weight: var(--sol-weight-medium);
  text-transform: uppercase;
  letter-spacing: var(--sol-tracking-label);
  color: var(--sol-ink-tertiary);
  line-height: var(--sol-leading-solid);
}

/* Voice utilities (grain names kept; faces re-pointed) */
.display-serif { font-family: var(--sol-font-serif); font-weight: 400; letter-spacing: var(--sol-tracking-display); }
.narrative-voice  { font-family: var(--sol-font-serif); font-weight: 400; font-size: var(--sol-text-3); line-height: var(--sol-leading-prose); }
.narrative-emphasis { font-family: var(--sol-font-serif); font-style: italic; font-weight: 400; }
/* .mono is code-only now; numbers use .tabular */
.mono    { font-family: var(--sol-font-code); font-size: var(--sol-text-2); }
.tabular { font-family: var(--sol-font-sans); font-variant-numeric: tabular-nums; }

.text-secondary { color: var(--sol-ink-secondary); }
.text-tertiary  { color: var(--sol-ink-tertiary); }
.text-muted     { color: var(--sol-ink-secondary); }
.text-faint     { color: var(--sol-ink-tertiary); }  /* NOT ink-faint: that is graphic-only */

/* Atmospheric classes retired: the daylight ground is flat and quiet */
.bg-textured, .bg-atmospheric { background: var(--sol-ground); position: relative; }
.bg-textured::after, .bg-atmospheric::after { content: none; }

/* ============================================================================
   §6 ACCESSIBILITY
   ============================================================================ */

::selection { background: var(--sol-selection); color: var(--sol-ink); }

/* ONE ring, and the selector is UNIVERSAL on purpose.
   This rule used to enumerate:
     button, [role="button"], a, input, select, textarea, [role="switch"],
     [role="tab"], [tabindex]
   An enumeration cannot satisfy "one consistent focus ring", because the set of
   things a browser will draw a focus indicator on is not the set somebody
   remembered to type. MEASURED: G-M6 walked 214 KEYBOARD tab stops across
   7 Foundry screens x 2 registers and found 2 of them — the <summary> of Home's
   process-table disclosure — presenting Chromium's own `rgb(0,95,204) auto 1px`
   instead of this ring. <summary> is natively focusable and is in none of the
   groups above; neither are iframe, area[href], [contenteditable], or
   audio/video[controls]. Extending the list would only move the next miss.
   :focus-visible ALREADY means "an element the browser wants to indicate", so
   :where(*) is the exact population, and :where() keeps the specificity at 0 so
   a component composing the ring with its own shadow still wins.
   scripts/check-focus-ring.mjs REACH asserts this selector stays universal. */
:where(*):focus-visible {
  outline: none;
  box-shadow: var(--sol-focus-ring);
}

/* Touch-aware targets (kept from grain) */
@media (pointer: coarse) {
  button, [role="button"], a, input, select, textarea, [role="switch"], [role="tab"] {
    min-height: 44px;
    min-width: 44px;
  }
}

/* grain's name for the rail metric. */
@media (max-width: 1279px) { :root { --sidebar-w: 48px; } }
@media (max-width: 767px)  { :root { --sidebar-w: 0px;  } }

/* Reduced motion — the re-point half (the sol- half is in the spine). */
@media (prefers-reduced-motion: reduce) {
  :root {
    --duration-fast: 0ms; --duration-normal: 0ms; --duration-slow: 0ms;
  }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}
