/* ============================================================================
   GRAIN → SOLLEVA — §1 the additive token spine  (grain step 1, T-GRAIN-ALIAS)
   ----------------------------------------------------------------------------
   THE CONTRACT OF THIS FILE: it is inert BY NAMESPACE, not by import order.

   Every declaration here is either
     (a) a custom property whose name begins  --sol-  , or
     (b) an @keyframes whose name begins      sol-    , or
     (c) a rule whose every selector is  :root  or a  .sol-  prefixed class.
   Nothing in grain, and nothing in any consumer, declares or matches those
   names today. Measured 2026-08-06 over 9 canonical consumer repos — kiln,
   foundry, lore, temper, anvil, forge, foundry-engagement-kit, grain-kit,
   accumulate — across *.tsx/jsx/ts/js/html/css, EXCLUDING node_modules/,
   dist/, build/, target/, .git/ and .claude/worktrees/:
       .sol- class usages 0 · --sol-* references 0 · @keyframes sol- 0
   grain's own four barrel files declare 108 custom properties and share
   0 names with this file. So this file changes no resolved value and paints
   no pixel wherever it sits in the cascade — first, last, or inside
   dist/grain.css. That is a property a machine can check:
   `node scripts/check-alias-inert.mjs` enforces (a)(b)(c) and
   `node scripts/check-alias-render.mjs` measures 0 deltas in a real browser
   over 770 comparisons.

   The earlier shape of this file claimed inertness from being imported FIRST.
   That claim was false and was measured false twice: a rule imported first
   still wins every property its later namesake does not also declare, so a
   bare `body {}` and 14 unnamespaced utility classes leaked through, and 19
   custom properties that no later file re-declares (§2b) went live in four
   consumers. Everything that re-points a grain name, or paints, now lives in
   the sibling  grain-solleva-compat.css , which the barrel does NOT import.

   §1  the canonical --sol-* tokens (verbatim from foundation/tokens.css,
       which remains the LAW — any drift here is a bug; regenerate from it)
   §4  motion — one principle: EVERYTHING ARRIVES BY RISING. The full
       keyframe library, including the scatter-and-form dot motif
       (scatter → gather → form → lift), Solleva's storytelling device.
       All keyframe and class names are sol- prefixed.

   §2 (the grain-compat alias layer), §2b (the style-dictionary surface),
   §3 (status/agent re-points), §5 (unnamespaced utilities) and §6
   (body/::selection/:focus-visible/coarse-pointer/reduced-motion `!important`)
   are NOT here — they are the swap, and they live in grain-solleva-compat.css.
   T-GRAIN-SWAP turns that file on with one @import; T-GRAIN-DANGLE rules on
   its §2b before that happens.

   Register: support under load — "the ground rises under you."
   Ground: cold daylight white · Ink: deep slate-blue · Accent: solar
   vermilion (never a fill; the daylight line under a lifted mass).

   Standing constraints (non-negotiable): light mode primary · nothing
   customer-facing below 12px · WCAG AA 4.5:1 on every text pair (full
   computed table: foundation/design-system.md §2.8) · OFL fonts self-hosted
   & PROVED loaded · flat rows for left-side messages · composer is a bubble ·
   no customer-facing monospace.

   THE FORGE FLOOR IS RETIRED. No parchment, no ember, no gold, no heat.
   Elevation is daylight, not shadow; completion is a lift, not a glow.
   ============================================================================ */

/* ---- FONTS ----------------------------------------------------------------
   Production: Source Serif 4 + Archivo, OFL, SELF-HOSTED as base64 woff2
   variable fonts with font-display: block (design-system.md §3.1), with the
   two-step load proof:
     1. await Promise.all(fontFaces.map(f => f.load()))
     2. document.fonts.check('16px "Source Serif 4"') && …'16px "Archivo"'
   document.fonts.check() alone is NOT proof (cross-engine finding).

   NO @import OF A REMOTE STYLESHEET LIVES HERE. The hearth source carried
     @import url("https://fonts.googleapis.com/css2?family=Archivo…")
   as a development convenience, by its own words. Shipping it would have put
   a third-party network fetch into every consumer of @goforgeit/grain (grain
   ships 0 remote @imports today) and it broke any consumer whose CSS pipeline
   resolves @import — measured: grain's own lightningcss raises ResolverError
   on it. It is deleted. Until T-GRAIN-FONTS self-hosts the two faces,
   --sol-font-sans / --sol-font-serif fall back to their stack tails
   (system-ui / Georgia). No consumer reads them yet, so nothing regresses.
   ---------------------------------------------------------------------------- */

/* ============================================================================
   §1 CANONICAL TOKENS — verbatim from foundation/tokens.css (the law)
   ============================================================================ */

:root {
  /* ---- GROUND RAMP — cold daylight; surfaces get LIGHTER as they rise
     (surface > ground > sunken > deep). Elevation is daylight, not shadow. */
  --sol-surface:        oklch(0.993 0.003 250);  /* #FBFDFF — raised: cards, composer, panels */
  --sol-ground:         oklch(0.980 0.006 250);  /* #F5F9FC — the page */
  --sol-ground-sunken:  oklch(0.958 0.009 250);  /* #EDF2F7 — rails, wells, input fields */
  --sol-ground-deep:    oklch(0.930 0.012 250);  /* #E2E9F0 — furthest-back fields */

  /* ---- WEBSITE AUDIENCE TEMPERATURES — marketing section washes ONLY */
  --sol-web-dawn:   oklch(0.975 0.010 220);  /* #F0F9FB — maker register */
  --sol-web-noon:   var(--sol-ground);       /* #F5F9FC — working register */
  --sol-web-steel:  oklch(0.972 0.008 265);  /* #F3F6FB — enterprise register */

  /* ---- INK RAMP — deep slate-blue, never warm brown-black */
  --sol-ink:            oklch(0.245 0.030 255);  /* #17212F — 15.32:1 on ground */
  --sol-ink-secondary:  oklch(0.410 0.035 255);  /* #3E4C5D —  8.28:1 */
  --sol-ink-tertiary:   oklch(0.500 0.030 255);  /* #586474 —  5.68:1; placeholders live here */
  --sol-ink-faint:      oklch(0.650 0.020 255);  /* #87909C — GRAPHIC/DISABLED ONLY (3.05:1) */

  /* ---- ACCENT RAMP — solar vermilion: heat-as-light. Never fills a large
     field; it is the thin line of daylight beneath a lifted mass. */
  --sol-accent:         oklch(0.620 0.185 35);   /* #DF502C — graphic only, never text */
  --sol-accent-ink:     oklch(0.500 0.160 35);   /* #AB3415 — links, named next steps. 6.14:1 */
  --sol-accent-deep:    oklch(0.420 0.140 32);   /* #892312 — pressed / focus. 8.58:1 */
  --sol-accent-tint:    oklch(0.945 0.030 35);   /* #FFE6E0 — SMALL chips/badges only */

  /* ---- SEMANTIC / STATUS — verbs, not moods */
  --sol-lifted:         oklch(0.480 0.100 155);  /* #236E44 — done / raised.     5.86:1 */
  --sol-holding:        oklch(0.520 0.110 75);   /* #8D5E00 — waiting on you.    5.31:1 */
  --sol-fault:          oklch(0.480 0.150 25);   /* #A12F2F — failed, fail loud. 6.70:1 */
  --sol-lifted-tint:    oklch(0.950 0.025 155);  /* #E2F4E7 */
  --sol-holding-tint:   oklch(0.955 0.030 85);   /* #F9EFDA */
  --sol-fault-tint:     oklch(0.950 0.020 25);   /* #FCEAE8 */

  /* ---- NIGHT — footers, logo-on-dark. NOT a dark mode; the brand is daylight. */
  --sol-night:          oklch(0.230 0.025 255);  /* #151E29 */
  --sol-night-raised:   oklch(0.280 0.028 255);  /* #202A37 */
  --sol-daylight-on-night: oklch(0.930 0.010 250); /* #E3E8EE — 13.64:1 on night */
  --sol-accent-on-night:   oklch(0.680 0.170 40);  /* #EC6D3D — GRAPHIC ONLY.
       5.46:1 against --sol-night, which is the only surface it was measured
       against. It is NOT a text colour: on --sol-night-raised it is 4.70:1 and
       on --surface-elevated 3.92:1, so any text painted with it fails AA the
       moment it sits on a raised card. The daylight register already draws
       this distinction (--sol-accent graphic-only vs --sol-accent-ink for
       text); the night register did not, and had one token doing both jobs. */
  --sol-accent-ink-on-night: oklch(0.750 0.150 42); /* #FC8B5D — TEXT. The night
       twin of --sol-accent-ink. Clears AA on every night surface it can land
       on, not just the ground: 7.19:1 on --sol-night, 6.21:1 on
       --sol-night-raised, 5.00:1 on --surface-elevated, 6.22:1 on the accent
       tint. In sRGB gamut with no channel clipping (unlike anything above
       L=0.75 at this chroma). See DF-1. */

  /* ---- LINES & SELECTION */
  --sol-line:        color-mix(in oklab, var(--sol-ink) 12%, transparent);
  --sol-line-strong: color-mix(in oklab, var(--sol-ink) 22%, transparent);
  --sol-line-faint:  color-mix(in oklab, var(--sol-ink) 6%, transparent); /* compat: grain --border-light/faint */
  --sol-selection:   oklch(0.930 0.022 250);     /* #DDE9F6 */

  /* ---- TYPE — Source Serif 4 (body) + Archivo (UI + wordmark).
     NO customer-facing monospace: counts, IDs, timestamps, money are
     Archivo + font-variant-numeric: tabular-nums. --sol-font-code exists
     ONLY for literal source code on developer surfaces. */
  --sol-font-serif: "Source Serif 4", Georgia, serif;
  --sol-font-sans:  "Archivo", system-ui, sans-serif;
  --sol-font-code:  ui-monospace, "SF Mono", Menlo, monospace; /* literal code only */

  /* Six-step ramp. Floor 12px — nothing customer-facing below it. */
  --sol-text-1: 12px;    /* Archivo 500, +0.08em, uppercase — meta, labels, counts */
  --sol-text-2: 13px;    /* Archivo 400/500 — chrome, rows, buttons */
  --sol-text-3: 15.5px;  /* Source Serif 4 400 — body, transcript, composer */
  --sol-text-4: 18px;    /* Archivo 600 — pane & card titles */
  --sol-text-5: 22px;    /* Archivo 600 — section heads (product) */
  --sol-text-6: 28px;    /* Archivo 650 — display (product ceiling) */

  --sol-weight-body:    400;
  --sol-weight-medium:  500;
  --sol-weight-title:   600;
  --sol-weight-display: 650;

  /* Exactly three line-height ratios (H4). */
  --sol-leading-prose: 1.72;  /* serif body only */
  --sol-leading-ui:    1.5;   /* multi-line UI text */
  --sol-leading-solid: 1.25;  /* single-line; height comes from the box */

  --sol-tracking-label:   0.08em;   /* step 1 uppercase labels only */
  --sol-tracking-display: -0.01em;  /* steps 5–6 only */
  --sol-measure: 72ch;

  /* ---- SPACE — 4px base */
  --sol-space-1: 4px;  --sol-space-2: 8px;  --sol-space-3: 12px;
  --sol-space-4: 16px; --sol-space-5: 24px; --sol-space-6: 32px;
  --sol-space-7: 48px; --sol-space-8: 64px; --sol-space-9: 96px;

  /* ---- RADII — nothing sharper than 6px, nothing rounder than 16px except pills */
  --sol-radius-1: 6px;      /* controls: buttons, inputs, chips */
  --sol-radius-2: 10px;     /* cards, panels, next-step surfaces */
  --sol-radius-3: 16px;     /* floating panels, sheets, the composer bubble */
  --sol-radius-pill: 999px;

  /* ---- ELEVATION — light from below-forward: bright top edge + soft
     under-shadow (the proof of the gap). Resting plane changes are
     lightness steps, never shadows. */
  --sol-lift-0: none;
  --sol-lift-1: 0 1px 0 0 rgba(255,255,255,0.9) inset,
                0 1px 2px rgba(23,33,47,0.06),
                0 4px 12px -6px rgba(23,33,47,0.10);
  --sol-lift-2: 0 1px 0 0 rgba(255,255,255,0.9) inset,
                0 2px 4px rgba(23,33,47,0.06),
                0 12px 28px -12px rgba(23,33,47,0.16);
  --sol-panel-edge: -1px 0 0 0 rgba(23,33,47,0.10),
                    -16px 0 32px -12px rgba(23,33,47,0.14);
  /* the daylight line: the accent as under-glow, never as fill.
     Reserved for THE named next step and the mark — at most one per screen. */
  --sol-daylight-line: 0 2px 0 0 var(--sol-accent);

  /* ---- MOTION — everything arrives by rising; exits fade in place. */
  --sol-ease: cubic-bezier(0.19, 1, 0.22, 1);
  --sol-t-quick: 180ms;    /* state changes: hover, press, toggle */
  --sol-t-rise:  420ms;    /* entrances */
  --sol-t-settle: 700ms;   /* hero-scale resolution beats only */
  --sol-rise-distance: 10px;

  /* Per-instance stagger API for .sol-motif-dot: a composition sets --sol-d (delay) and
     --sol-dx/--sol-dy (scatter origin) per dot, inline. Declared here at their identity
     values so an unset dot resolves instead of dangling — the animation is unchanged
     (an undeclared var() with a 0 fallback and a declared 0 compute the same), but the
     contract is now readable and the scanner can tell "no delay" from "typo". */
  --sol-d: 0ms;
  --sol-dx: 0px;
  --sol-dy: 0px;

  /* ---- FOCUS — 2px ring, 2px offset, every affordance */
  --sol-focus-ring: 0 0 0 2px var(--sol-ground), 0 0 0 4px var(--sol-accent-deep);

  /* ---- LAYOUT METRICS (tier contract H6) */
  --sol-rail-w: 60px;        /* icon rail — no captions, no right border */
  --sol-rail-w-tablet: 48px;
  --sol-panel-w: 280px;      /* contextual panel — one shared component */
  --sol-topbar-h: 56px;      /* gradient-fade header (H7) — zero border edges */
}

/* Hex fallbacks for engines without oklch() */
@supports not (color: oklch(0.5 0.1 30)) {
  :root {
    --sol-surface: #FBFDFF; --sol-ground: #F5F9FC;
    --sol-ground-sunken: #EDF2F7; --sol-ground-deep: #E2E9F0;
    --sol-web-dawn: #F0F9FB; --sol-web-noon: #F5F9FC; --sol-web-steel: #F3F6FB;
    --sol-ink: #17212F; --sol-ink-secondary: #3E4C5D;
    --sol-ink-tertiary: #586474; --sol-ink-faint: #87909C;
    --sol-accent: #DF502C; --sol-accent-ink: #AB3415;
    --sol-accent-deep: #892312; --sol-accent-tint: #FFE6E0;
    --sol-lifted: #236E44; --sol-holding: #8D5E00; --sol-fault: #A12F2F;
    --sol-lifted-tint: #E2F4E7; --sol-holding-tint: #F9EFDA; --sol-fault-tint: #FCEAE8;
    --sol-night: #151E29; --sol-night-raised: #202A37;
    --sol-daylight-on-night: #E3E8EE; --sol-accent-on-night: #EC6D3D;
    --sol-accent-ink-on-night: #FC8B5D;
    --sol-selection: #DDE9F6;
    --sol-line: rgba(23,33,47,0.12); --sol-line-strong: rgba(23,33,47,0.22);
    --sol-line-faint: rgba(23,33,47,0.06);
  }
}

/* ============================================================================
   §4 MOTION — everything arrives by rising; exits fade in place.
   Entrances translate UP 8–12px and settle. Nothing drops in, nothing
   slides sideways, nothing bounces. Pressing is the one sanctioned
   downward motion (you feel the ground take the load).
   ============================================================================ */

/* -- Core entrance: replaces forge-rise AND fade-in-up ---------------------- */
@keyframes sol-rise {
  from { opacity: 0; transform: translateY(var(--sol-rise-distance)); }
  to   { opacity: 1; transform: translateY(0); }
}

/* -- Exit: what leaves does not fall — it fades in place -------------------- */
@keyframes sol-fade-out {
  from { opacity: 1; }
  to   { opacity: 0; }
}

/* -- Completion: replaces forge-temper / molten-seal. The finished thing
      rises 4px and the daylight appears beneath it, then settles. ----------- */
@keyframes sol-lift-settle {
  0%   { transform: translateY(0); box-shadow: var(--sol-lift-0); }
  45%  { transform: translateY(-4px); box-shadow: var(--sol-lift-1), var(--sol-daylight-line); }
  100% { transform: translateY(-2px); box-shadow: var(--sol-lift-1), var(--sol-daylight-line); }
}

/* -- The daylight line arriving under a lifted mass ------------------------- */
@keyframes sol-daylight-in {
  from { opacity: 0; transform: scaleX(0.2); }
  to   { opacity: 1; transform: scaleX(1); }
}

/* -- Live indicators (opacity only — glow is reserved for the accent) ------- */
@keyframes sol-pulse {          /* replaces dot-pulse: thinking, listening */
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.45; }
}
@keyframes sol-idle {           /* replaces idle-breathe */
  0%, 100% { opacity: 0.6; }
  50%      { opacity: 1; }
}
@keyframes sol-live-ring {      /* replaces pulse-ring: live/recording echo */
  0%   { transform: scale(1); opacity: 0.6; }
  100% { transform: scale(2.5); opacity: 0; }
}
@keyframes sol-fault-ring {     /* replaces pulse-alert: fail loud, then hold */
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in oklab, var(--sol-fault) 35%, transparent); }
  50%      { box-shadow: 0 0 0 6px color-mix(in oklab, var(--sol-fault) 0%, transparent); }
}

/* -- Loading: neutral shimmer (kept — daylight moving across a surface) ----- */
@keyframes sol-shimmer {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(100%); }
}

/* -- Progress: the fill IS a daylight line; its leading edge breathes.
      Replaces molten-edge / molten-shimmer / heat-flow. -------------------- */
@keyframes sol-progress-edge {
  0%, 100% { opacity: 0.6; }
  50%      { opacity: 1; }
}

/* ----------------------------------------------------------------------------
   THE SCATTER-AND-FORM DOT MOTIF — the storytelling device.
   Four beats: SCATTER → GATHER → FORM → LIFT. The system never adds dots;
   it arranges what is yours. Dots gather UNDER a mass as a supporting bed
   and raise it; the last frame always shows daylight under the lifted mass.

   Usage contract:
     .sol-motif                  — container (position: relative)
     .sol-motif-dot              — a dot; set per-dot --sol-dx/--sol-dy
                                   (scatter offsets) and --sol-d (stagger delay)
     .sol-motif-mass             — the thing being lifted
     .sol-motif-daylight         — the vermilion line in the gap
   Beat timing: gather runs --sol-t-rise per dot (staggered ≤60ms, ≤5
   staggered items); form+lift resolve on --sol-t-settle.
   Colors: dots are ink on daylight (slate), warm dots (--sol-accent) are
   YOURS — at most one warm dot per composition. Never legacy blue-on-cream.
   ---------------------------------------------------------------------------- */

@keyframes sol-dot-gather {     /* beat 1→2: from scattered rest to the bed */
  0%   { transform: translate(var(--sol-dx), var(--sol-dy)); opacity: 0.35; }
  60%  { opacity: 0.8; }
  100% { transform: translate(0, 0); opacity: 1; }
}

@keyframes sol-dot-form {       /* beat 3: the bed tightens — dots take the load */
  0%   { transform: scale(1); }
  50%  { transform: scale(0.82); }
  100% { transform: scale(1); }
}

@keyframes sol-mass-lift {      /* beat 4: the mass rises off the bed */
  0%   { transform: translateY(0); box-shadow: var(--sol-lift-0); }
  100% { transform: translateY(calc(-1 * var(--sol-rise-distance)));
         box-shadow: var(--sol-lift-2); }
}

@keyframes sol-dot-carry {      /* ambient loop for a formed bed at work:
                                   a slow vertical breath — the bed holds */
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-2px); }
}

.sol-motif { position: relative; }
.sol-motif-dot {
  width: 6px; height: 6px; border-radius: var(--sol-radius-pill);
  background: var(--sol-ink-secondary);
  animation: sol-dot-gather var(--sol-t-rise) var(--sol-ease) both;
  animation-delay: var(--sol-d);
}
.sol-motif-dot--warm { background: var(--sol-accent); } /* yours; max one */
.sol-motif-mass {
  animation: sol-mass-lift var(--sol-t-settle) var(--sol-ease) both;
}
.sol-motif-daylight {
  height: 2px; border-radius: 1px; background: var(--sol-accent);
  transform-origin: center;
  animation: sol-daylight-in var(--sol-t-settle) var(--sol-ease) both;
}

/* -- Scroll-driven rise (replaces forge-scroll-reveal) ---------------------- */
@supports (animation-timeline: view()) {
  .sol-scroll-rise {
    animation: sol-rise linear both;
    animation-timeline: view();
    animation-range: entry 0% entry 30%;
  }
  .sol-scroll-stagger > * {
    animation: sol-rise linear both;
    animation-timeline: view();
  }
  .sol-scroll-stagger > :nth-child(1) { animation-range: entry 0% entry 25%; }
  .sol-scroll-stagger > :nth-child(2) { animation-range: entry 5% entry 30%; }
  .sol-scroll-stagger > :nth-child(3) { animation-range: entry 10% entry 35%; }
  .sol-scroll-stagger > :nth-child(4) { animation-range: entry 15% entry 40%; }
}

/* RETIRED KEYFRAMES (no replacement — off-system):
   breathe (ambient shadow oscillation: no up),
   ember-breathe — the KEYFRAME was deleted from cream.css in 0.4.6. It was the
   last hardcoded forge pigment grain painted: an amber literal inside the
   keyframe body, which no token could reach and no palette repoint could move.
   The class name survives there as a deprecated alias onto sol-pulse; grain's
   own StatusDot uses .sol-live-pulse below,
   forge-temper (scale celebration → sol-lift-settle), molten-seal,
   molten-edge, molten-shimmer, heat-flow, switch-bounce (nothing bounces),
   shimmer-sweep → sol-shimmer, forge-rise / fade-in-up → sol-rise,
   pulse-ring → sol-live-ring, pulse-alert → sol-fault-ring,
   dot-pulse → sol-pulse, idle-breathe → sol-idle, forge-scroll-reveal →
   sol-scroll-rise. Legacy names are compiled into grain component source;
   see migration.md §4 for the per-component rewire. */

/* ============================================================================
   §5 UTILITIES — the sol- prefixed ones only. The unnamespaced utilities
   (.section-label, .display-serif, .narrative-voice, .narrative-emphasis, .mono,
   .tabular, .text-secondary, .text-tertiary, .text-muted, .text-faint,
   .bg-textured, .bg-atmospheric) are in grain-solleva-compat.css — they
   collide by name with cream.css / typography.css and with consumer markup.
   ============================================================================ */

/* Entrance utilities (replace .forge-rise / .fade-in-up + delays) */
.sol-rise { animation: sol-rise var(--sol-t-rise) var(--sol-ease) both; }
.sol-rise.delay-1 { animation-delay: 60ms; }
.sol-rise.delay-2 { animation-delay: 120ms; }
.sol-rise.delay-3 { animation-delay: 180ms; }
.sol-rise.delay-4 { animation-delay: 240ms; }
/* stagger law: ≤5 staggered items, ≤60ms apart; later items appear settled */

/* Live-indicator utility — the sanctioned replacement for the retired warm
   status halo named in §4's RETIRED list above. A running/live dot breathes in
   OPACITY only, per §4's rule ("Live indicators (opacity only — glow is
   reserved for the accent)"), and takes its pigment from whatever token painted
   it, so it is register-correct by construction rather than by a hardcoded
   literal. 3s is the retired class's own cadence, kept so its deprecated alias
   is a like-for-like swap. Shipped as a plain class, not a Tailwind arbitrary
   value, so it paints for consumers whose Tailwind @source does not follow
   grain. */
.sol-live-pulse { animation: sol-pulse 3s var(--sol-ease) infinite; }

.sol-shimmer { position: relative; overflow: hidden; }
.sol-shimmer::after {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent,
              color-mix(in oklab, var(--sol-surface) 60%, transparent), transparent);
  animation: sol-shimmer 2s ease-in-out infinite;
}

/* Prose measure — capped on the prose element, never on a row */
.sol-prose { max-width: var(--sol-measure); }

/* Rail metric responds; --sidebar-w (grain's name for it) is a re-point and
   lives in the compat layer. */
@media (max-width: 1279px) { :root { --sol-rail-w: 48px; } }
@media (max-width: 767px)  { :root { --sol-rail-w: 0px;  } }

/* Reduced motion: zero the sol- durations and distances; the motif serves its
   final lifted frame, static (design-system.md §7 — three stills, last frame
   always shows daylight under the lifted mass). The universal
   `*, *::before, *::after { … !important }` sweep and the --duration-* resets
   are re-points, not additions, and live in the compat layer. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --sol-t-quick: 0ms; --sol-t-rise: 0ms; --sol-t-settle: 0ms;
    --sol-rise-distance: 0px;
  }
  .sol-motif-dot  { animation: none; transform: translate(0,0); opacity: 1; }
  .sol-motif-mass { animation: none;
                    transform: translateY(calc(-1 * 10px));
                    box-shadow: var(--sol-lift-2); }
  .sol-motif-daylight { animation: none; opacity: 1; transform: scaleX(1); }
}
