/* ═══════════════════════════════════════════════════════════════════
   STRUCTURAL COLOR — Aaron Sleeper personal-brand primitive library
   LOCAL / staging. The single source of truth for the brand's stable
   primitives (tokens · type · toggle · gradient-ring · panel · chrome).
   Novel/moving bits (raven, flight animation) live in brand.js + page markup.
   Themes: Aurora (dark, default) · Feather (light).
   ═══════════════════════════════════════════════════════════════════ */

@property --sa { syntax: "<angle>"; inherits: false; initial-value: 120deg; }
@property --sb { syntax: "<angle>"; inherits: false; initial-value: 120deg; }

:root {
  /* interference ramp — DARK (Aurora) */
  --c1:#F06BB7; --c2:#8F6CF0; --c3:#5E7CFF; --c4:#3FC6E0; --c5:#3EDBA8;
  /* ground ramp — depth by plane, never shadow: inset < ground < surface < raised */
  --ground:#0F0D13; --surface:#15121B; --raised:#1C1826; --inset:#0A090E;
  /* --ground-lift — CANDIDATE, landed 2026-07-31. The ONE new plane value, a half-step bisecting
     --ground -> --surface in OKLab. Authored because a real job had no plane: the operator shell's
     turn band sat on the same value as chrome while its own ruling forbids that. Measured: one rung
     at this joint is dL .0257 (Aurora) / .0241 (Feather); this half-step is dL .0116 / .0117 —
     agreeing across themes to .0001, which is what makes it a scale position rather than a nudge.
     THE STACK INVARIANT that keeps a half-step from becoming a fifth stratum: it never appears in
     one containment chain with BOTH its integer neighbours (max depth 4; the operator shell's real
     max is 3), so `nothing floats` is under-spent, not strained.
     Aaron ruled bisect-only over re-deriving the existing four (walk E1, 2026-07-31) — so the four
     above are UNTOUCHED and the six surfaces that vendor them see zero change.
     NOT YET SEEN BY EYE: a dL .0116 plane boundary has never been rendered. Derivation of record:
     operator-district/plane-ramp-rederivation.md */
  --ground-lift:#120F17;
  /* field-engine dark albedo floor — deep blue-violet, super-dark: makes magenta/teal pop by contrast
     ("colorless without being colorless"). spike-07 look-insight; Brand to ratify the exact tint + the
     anti-space-purple guard (must stay a super-dark FLOOR, never a purple field = reject #9). */
  --base-tint:#181B40;
  --ink:#EDEBF2; --ink-2:#C3BED0; --muted:#9B96A8; --hairline:#2A2536;
  /* --ink-2: lifted secondary ink for small labels that muted leaves under-legible */
  /* ── INK RAMP, stops 4 + 5 — CANDIDATE, pending Aaron's final hex (his production role, like --pr-*).
     --muted-2: the 4th LEGIBLE rung. Authored per-theme (NOT a color-mix) because its target is a
     CONTRAST RATIO, and a fixed mix % does not hold a ratio across two grounds — the same 86% mix
     lands 5.03:1 on Aurora and 4.51:1 on Feather. See operator-district/ink-ramp-4th-rung.md §3.
     Carries "present but below the reader's current altitude / focus": recessive and still READ.
     AA (>=4.5:1) on every plane it is permitted on — verified 2026-07-29: ground 5.03 / surface 4.82
     / raised 4.53 (Aurora), ground 4.51 / surface 4.84 / raised 5.05 (Feather).
     Hue + chroma held to --muted's family: an ink stop never separates on chroma (hue is spent on data).
     --ink-faint: the 5th stop, DERIVED (brand's own color-mix idiom), SUB-AA BY DESIGN and therefore
     DECORATIVE / DISABLED ONLY — never load-bearing text. The name deliberately BREAKS the -2 grammar:
     it is not another rung of the same kind, and the grammar break is the signal. Derived from --muted
     so it tracks any retune of it. Gate: no element with a semantic role resolves to --ink-faint. */
  --muted-2:#848090;
  --ink-faint:color-mix(in oklab,var(--muted) 55%,var(--ground));
  /* --rule-hover — a boundary the pointer is ON. PROMOTED 2026-08-02 from the operator district's
     --op-rule-hover, whose only consumer in the repo was .op-splitter:hover — and that consumer moved
     to brand core, so the alias would have been left with zero. Retiring it rather than keeping both
     is the --op-stroke-* move (walk E3): a district alias over a brand token of the same value is
     indirection without information. VALUE IS VERBATIM, not re-derived — Aaron's, unchanged.
     theme-derived: both inputs are themed, so parity holds THROUGH the derivation. */
  --rule-hover:color-mix(in oklab,var(--ink) 18%,var(--hairline)); /* theme-derived */
  /* ── SELECTION — RATIFIED 2026-07-31 against a render (walk D1). Aaron's value, his production role.
     TOKENIZED from the rule that had been inline at ::selection since the beginning. The rule was fine;
     the fact that it was ONLY a rule was not. A <link> carries rules; a vendored :root carries VALUES —
     so site/, museum/, field/ and proof-surface/ inherited ::selection for free while obsidian-theme,
     vscode-theme and the operator surface, which hand-carry a token block, inherited NOTHING and
     rendered the browser default. That is I11 one layer deeper than drift: a failure no --check could
     ever catch, because there is nothing to compare. A token can be emitted by a generator; a rule cannot.
     TWO FLOORS, and the old 34% only ever met one of them:
       --select-ink on the fill  >= 4.5:1  (selected text stays readable)   — 34% met this at ~10:1
       the fill vs --ground      >= 3:1    (1.4.11: selection reads as a STATE) — 34% was 1.58:1
     72% clears both in both themes, MEASURED IN A REAL COMPOSITOR (not modelled):
       Aurora  #6B51B2  separation 3.17:1  text 5.16:1
       Feather #907DE1  separation 3.02:1  text 5.37:1
     DERIVED, not authored-per-theme — deliberately, and unlike --muted-2 above. This token's target is
     contrast FROM the ground it mixes with, where fraction and ground move together, so one fraction
     holds the ratio across both themes (measured within 0.02). --muted-2's target moves the other way,
     which is exactly why IT had to be authored twice. Same idiom, opposite reason.
     Probe: operator-district/selection-fill-probe/ — both themes, four fractions, live drag regions. */
  --select-fill:color-mix(in oklab,var(--c2) 72%,transparent);
  /* --select-ink looks like indirection without information and is not, for one reason: the three
     vendoring consumers cannot inherit the RULE, so they must re-author it, and a re-authored rule
     reaching for --ink directly re-spells the pairing instead of referencing it. The token is what makes
     the pair syncable AS A PAIR. If a future topology has every surface link this sheet, retire it. */
  --select-ink:var(--ink);
  /* ── SCROLLBAR — CANDIDATE values, RATIFIED mechanism (walk D6). STANDARD PROPERTIES ONLY, and the
     reason is layout rather than taste: ::-webkit-scrollbar{width} converts a macOS overlay scrollbar
     into a classic one that takes layout space, silently subtracting from measures the operator surface
     asserts as CONTRACTUAL. So the finer instrument is the one with the side effect, and coarse is the
     correct resolution for chrome anyway — the ramp is rationed and never fills chrome (thesis #1).
     Thumb is ink-family, NEVER accent: --c2 already has four consumers. */
  --scrollbar-thumb:color-mix(in oklab,var(--ink) 22%,transparent);
  --scrollbar-thumb-hover:color-mix(in oklab,var(--ink) 38%,transparent);
  --scrollbar-track:transparent;
  /* semantics — flat, never iridescent (Aurora values: brighter, read on dark) */
  --success:#3BC98A; --warn:#E8A93C; --error:#F0616B;
  /* ── PROOF DISTRICT (pr-) token group — CANDIDATE, pending Aaron's final hex (his production role).
     Authored HERE once (source-of-truth invariant); proof.css composes only var(--pr-*), zero hex.
     Method: dataviz palette (sequential=confidence · diverging=for/against · muted marks · WCAG-first).
     BID-Corvus direction: cool single-hue confidence ramp reads "measured/known"; for/against are two
     STRUCTURAL hues in tension (teal↔mauve), never good/bad / green↔red; K grounded-lit, U quiet-hollow. */
  /* sequential — confidence (low→high; low recedes toward paper "not-yet-proven", high earns .ring) */
  --pr-conf-1:#4A5170; --pr-conf-2:#515C87; --pr-conf-3:#586BA4; --pr-conf-4:#6183CE; --pr-conf-5:#7AA0FF;
  /* diverging — for/against margin (neutral midpoint = the paper's own ground = absence) */
  --pr-for:#48A6B4; --pr-against:#C77BAF;
  /* KIU evidence tiers — honesty encoded in weight (K grounded, I reasoned, U hollow/open) */
  --pr-tier-k:#4AC79A; --pr-tier-i:#7AA0FF; --pr-tier-u:#BFA06A;
  /* ── OPERATOR DISTRICT (op-) token group — CANDIDATE, landed 2026-07-31. Authored HERE once
     (source-of-truth invariant); the operator surface composes only var(--op-*) and authors zero hex.
     PURE ALIAS LAYER: every colour token resolves to an existing brand primitive or a color-mix of
     them — ZERO new base hexes here, so Feather comes free through the primitives' own remap. The
     ONLY per-theme override this group needs is the ghost-alpha triple at the bottom of [data-theme].
     BID-Corvus direction: on an instrument the colour budget is spent on DATA, so state (hover/
     active/selected) is ACHROMATIC (plane + rule weight + ink); --c2 is reserved system-wide for
     focus/selection (brand-core's own convention); the ramp fires nowhere on the working canvas.
     THEME-PARITY CLASSIFICATION, and it is why gate 1 accepts this group: an alias is NOT
     theme-invariant (its resolved value differs per theme) and NOT an orphan (it needs no override —
     the referent is already themed, so parity holds THROUGH the derivation). It is `theme-derived`,
     a CLAIM the gate verifies rather than an assertion it takes on trust. Non-colour rows below are
     genuinely theme-invariant and marked as such; the three real per-theme values carry no marker
     and appear in BOTH blocks. Derivations: operator-district/semantic-register.md §2g +
     plane-ramp-rederivation.md */
  /* planes — containment DEPTH (nesting), never zoom altitude. --op-band is the new half-step rung:
     the turn band had no plane of its own and was colliding with chrome. */
  --op-canvas:var(--ground); --op-plane:var(--surface); --op-plane-raised:var(--raised); --op-well:var(--inset); --op-band:var(--ground-lift); /* theme-derived */
  --op-rule:var(--hairline); --op-spine:var(--hairline); /* theme-derived */
  /* --op-edge — the REGION boundary, and deliberately NOT --op-rule's value. Aaron ratified it by
     eye 2026-07-31 against plane-ramp-probe § 2b after the plane alone failed to separate chrome /
     band / read. A THIRD role, not an alias: --op-rule is the in-column divider D15 quieted, and
     --hairline measures 1.21-1.30:1 against the planes it would separate — barely stronger than the
     plane steps that already failed. --ink-faint is ~2x that (2.45-2.63:1) and still under the 3:1
     non-text reference, so "nothing floats" holds. Sub-AA is the POINT: a boundary that reads
     without becoming a drawn rule, which is --ink-faint's own declared decorative/non-text lane.
     NOT a fix for the span problem — a full rung still fails to read; that is lever 2 / E1, deferred
     by Aaron, re-opened in plane-ramp-rederivation.md § 9.2. Role name is provisional pending the
     Brand Identity Director seat (semantic-register.md § 5 reserves role naming). */
  --op-edge:var(--ink-faint); /* theme-derived */
  /* ink — 5 stops. --op-ink-below is the 4th LEGIBLE rung (AA in both themes on canvas/plane/raised;
     NOT permitted on --op-well). --op-ink-faint is sub-AA BY DESIGN: decorative/disabled only. */
  --op-ink:var(--ink); --op-ink-2:var(--ink-2); --op-ink-muted:var(--muted); --op-ink-below:var(--muted-2); --op-ink-faint:var(--ink-faint); /* theme-derived */
  /* source-honesty (operator-surface C2) — confidence rides DASH + WEIGHT + ALPHA, never hue. Dash is
     primary (it survives forced-colors, print and greyscale); alpha only reinforces. EDGE-carried. */
  --op-dash-solid:none; --op-dash-long:6 3; --op-dash-short:2 5; /* theme-invariant */
  --op-src-attested-dash:var(--op-dash-solid); --op-src-derived-dash:var(--op-dash-long); --op-src-inferred-dash:var(--op-dash-short); /* theme-invariant */
  --op-src-attested-w:var(--stroke-bold); --op-src-derived-w:var(--stroke-hair); --op-src-inferred-w:var(--stroke-hair); --op-src-attested-alpha:1; /* theme-invariant */
  /* the ghost alphas — the ONLY genuinely per-theme values in this group. A .45 ghost reads as
     RECEDING on Aurora and as BROKEN/half-loaded on Feather, so both appear in [data-theme] too. */
  --op-src-derived-alpha:.72; --op-src-inferred-alpha:.45;
  /* move-type data channels — six, FLAT, never the gradient. --c2 is ABSENT by design (reserved for
     focus/selection). --op-move-event aliasing --warn is the ONE sanctioned move-type/status rhyme. */
  --op-move-decision:var(--c3); --op-move-branch:var(--c1); --op-move-verdict:var(--c4); --op-move-output:var(--c5); --op-move-event:var(--warn); --op-move-noise:var(--muted); /* theme-derived */
  /* interactive states — ACHROMATIC by district rule. Focus is the one inherited exception. */
  /* --op-rule-hover RETIRED 2026-08-02 into brand core's --rule-hover (same value, same role) when its
     one consumer, .op-splitter:hover, was promoted. --op-rule-active is UNCONSUMED as of that date and
     is left in place deliberately: deleting a district token with a recorded role is a district
     cleanup, not a side effect of a brand-core promotion. Surfaced to Aaron, not decided here. */
  --op-rule-active:color-mix(in oklab,var(--ink) 34%,var(--hairline)); /* theme-derived */
  --op-plane-hover:var(--raised); --op-focus:var(--c2); --op-select-fill:color-mix(in oklab,var(--c2) 14%,transparent); --op-ink-disabled:var(--ink-faint); /* theme-derived */
  /* lifecycle — NODE-carried (border + fill alpha), disjoint from the EDGE-carried axis above.
     Predicted ghosts the CONTAINER, never the label's ink. */
  --op-life-live-w:var(--stroke-bold); --op-life-done-alpha:1; --op-collapsed-alpha:.6; /* theme-invariant */
  --op-life-predicted-alpha:.55;
  /* status / run-state — flat semantics; never a move-type, never a confidence */
  --op-status-ok:var(--success); --op-status-warn:var(--warn); --op-status-error:var(--error); /* theme-derived */
  --ease:cubic-bezier(.3,0,0,1);
  /* ── DURATION tier — I10 dimensional family, landed 2026-07-31. Theme-INVARIANT → :root ONLY
     (a transition is not slower in one theme). PROMOTES EXISTING VALUES AND INVENTS NONE: BRAND.md
     § Depth/Motion already ratifies "120 / 200 / 320ms, cubic-bezier(.3,0,0,1), no bounce" — the
     scale was decided and simply never tokenised, so --ease shipped alone and every consumer wrote
     its own raw ms. Same posture --stroke-* took, and the same reason: a scale nobody can reach is
     a scale that gets re-spelled. Curated-empirical per digest #3 — three values the DS already
     uses, not a ratio, because a ratio here would dress a decided choice as a derivation. */
  --dur-fast:120ms; --dur-base:200ms; --dur-slow:320ms; /* theme-invariant */
  /* ── STROKE tier — I10 dimensional family, landed 2026-07-31. Theme-INVARIANT → :root ONLY.
     Promoted to brand core rather than held at district scope because the promotion condition was
     MET on arrival: the operator district needs these for its source-honesty encoding, and 69 of
     82 border-width declarations on the operator surface are the literal `1px`. Two tiers over one
     value set is the --gap-* shape already rejected as indirection without information, so this is
     ONE tier and the district's --op-stroke-* aliases retire into it (walk E3).
     NAMED --stroke-*, deliberately NOT --rule-width-* (a downstream surface's vocabulary reaching
     upstream) and NOT --hairline-w (binding a WIDTH to a COLOUR token's name).
     THE ACCESSIBILITY CARVE this exists for: a high-contrast theme can now make every hairline
     heavier in ONE declaration under prefers-contrast / forced-colors, instead of selecting 40-odd
     internal class names. That is the whole return on tokenising the weight.
     THE CONSTRAINT, so tokenising is not read as licence: this does NOT permit raising the resting
     weight. D15 quieted the divider deliberately — the ramp separates, the rule stays quiet. */
  --stroke-hair:1px; --stroke-bold:1.5px;
  /* ── SHELL GEOMETRY tier — I10 dimensional family, PROMOTED from the operator district 2026-08-02
     alongside `.splitter` and `.collapsible` (Aaron, /walk D1.3). Theme-INVARIANT → :root ONLY.
     PROMOTES EXISTING VALUES AND INVENTS NONE: these are operator.css's GEOM constants verbatim
     (--op-splitter-w/hit/step, --op-rail-w), moved because their consumers moved. A brand-core rule
     reading a token declared in a district sheet resolves to NOTHING on any surface that does not
     also load that sheet — invalid at computed-value time, silently inheriting — which is precisely
     the surface this promotion exists to serve (field/artisan-01.html links brand.css and nothing
     else). The rules could not travel without them.
     NAMED without the district prefix, on the --stroke-* precedent: a downstream surface's
     vocabulary must not reach upstream, and the district's aliases retire rather than survive
     (the --gap-* shape, rejected as indirection without information).
     --collapsible-rail-w is NOT --rail-w, deliberately: brand core already spends `rail` twice
     (.rail is the fixed top gradient bar, .railed/.rail-col the margin-column layout), and a bare
     --rail-w would read as the width of a bar that has only a height. */
  --splitter-w:5px;          /* theme-invariant */ /* the visible handle */
  --splitter-hit:3px;        /* theme-invariant */ /* grab margin either side — 11px total target */
  --splitter-step:16px;      /* theme-invariant */ /* keyboard resize increment, read by splitter.js */
  --collapsible-rail-w:40px; /* theme-invariant */ /* railed width — a function of glyph + padding, never of the pane */
  /* ── DIMENSIONAL FOUNDATION (--text/space/radius/leading/track) — CANDIDATE, values pending Aaron's
     tuning (his production role, like the --pr-* hexes). Theme-INVARIANT → defined here at ONE altitude,
     never duplicated into [data-theme="feather"] (size/space/radius don't change between themes).
     Derived from the ~237 raw values already in use (ds-foundation-assessment §4): a codify-not-redesign
     rationalization that snaps ad-hoc values to a scale, not a new look. Consume via var(); never re-guess. */
  /* type scale — modular minor-third 1.2, 18px anchor. READING-COMFORT BUMP (2026-07-25, ratified):
     anchor moved 16→18px — Instrument Sans's moderate x-height (~.50 em) reads a step under its set size,
     so 18px reads generous-not-oversized and answers the felt "runs small". Reading core (mono→h3) rides
     full 1.2 grid steps from the 18px body. --text-micro is KEPT as a DELIBERATE FLOORED token at ~11px
     (off the strict −3 step's 10.42px; held legible the way --radius-pill is a deliberate non-ratio
     extreme) — its fine-mono-label tier stays pointed here, NOT retired. --text-mono is the rail/folio
     identity signature at 12.5px. h2/display FLOORS re-floored so the bumped h3 (31.1px) never exceeds h2
     (anti-inversion); caps held (no display balloon — the mono rail stays load-bearing). CANDIDATE — Aaron
     tunes like --pr-*. Derivation of record: proof-surface/scale-function-token-derivation.md +
     proof-surface/type-scale-bump-proposal.md */
  --text-micro:.69rem; --text-mono:.78rem; --text-small:.94rem;
  --text-body:1.125rem; --text-body-lg:1.35rem; --text-lede:1.62rem; --text-h3:1.944rem;
  --text-h2:clamp(2.1rem,4.6vw,3.4rem); --text-display:clamp(3rem,7vw,6rem);
  /* leading (line-height) + tracking (letter-spacing) — paired scales for the type roles */
  --leading-display:1; --leading-tight:1.15; --leading-snug:1.22; --leading-body:1.45; --leading-relaxed:1.6; --leading-loose:1.75;
  --track-display:-.035em; --track-tight:-.02em; --track-normal:0; --track-wide:.02em;
  --track-mono:.06em; --track-caps:.1em; --track-caps-lg:.14em; --track-caps-xl:.2em;
  /* spacing — 4px base (the grid Corvus documents in comments but never tokenized); consumed by name */
  --space-1:4px; --space-2:8px; --space-3:12px; --space-4:16px; --space-5:20px;
  --space-6:24px; --space-8:32px; --space-10:40px; --space-12:48px; --space-16:64px;
  /* the two fluid rhythms, named once (section vertical rhythm · page gutter) — were re-clamped per file */
  --space-section:clamp(72px,12vh,128px); --space-gutter:clamp(22px,5vw,72px);
  /* radius — curated-geometric (ratified): ~1.5× guided low, gently decelerating (1.5·1.5·1.44·1.23),
     envelope-preserving (top=16, no corner-drama); pill UNIFIED (retires the 100px/999px split → one token) */
  --radius-xs:4px; --radius-sm:6px; --radius-md:9px; --radius-lg:13px; --radius-panel:16px; --radius-pill:999px;
  /* measure (line length) — I10 tier, landed 2026-07-28. The reading-comfort axis the 2026-07-25
     foundation pass never enumerated: measure was enforced by EIGHT hand-set `ch` literals scattered
     across brand.css + proof.css + one page's inline <style> (34/44/46/52/56/72/74ch), with no token
     and therefore no coverage guarantee — so a primitive authored without one simply had none, and
     .pr-claim-defeat shipped five lines of narrative prose at 122ch (Space Mono, 12.5px, no cap).
     Theme-INVARIANT → :root only, same one-altitude rule as --text/space/radius/font.
     SCALE FUNCTION IS CURATED-EMPIRICAL, NOT MODULAR — deliberate, and the reason is not aesthetic:
     measure is bounded by an EMPIRICAL reading band (45–75ch), not by perceived proportion, so a
     ratio would generate steps outside the band and dress an arbitrary choice as a system. Three
     curated steps, each pinned to a reading fact, is the honest shape (Typography Craft, `measure`).
     UNIT IS ch, NEVER px — ch scales with the font, so these caps survive any future --text-* bump
     unchanged (the 2026-07-25 bump already proved this: the ch-bound roles held, the uncapped ones
     did not). CANDIDATE — Aaron tunes like --pr-*. Derivation: proof-surface/feedback-ds-obligations.md */
  --measure-tight:34ch; --measure-lede:46ch; --measure-prose:66ch;
  /* NOT a measure axis, deliberately excluded: display BALANCE caps (h1 16ch, .h2 17ch, .catch 26ch)
     are a text-wrap:balance companion for 2–3-word display lines — a different problem from reading
     measure, and folding them in would imply the 45–75ch band governs them. They stay authored raw
     and are named in verify.mjs's gate-5 allowlist so the exclusion is explicit, not an oversight. */
  /* ── FONT-FAMILY FOUNDATION (--font-*) — I10 tier, landed 2026-07-27. Theme-INVARIANT → :root only,
     never duplicated into [data-theme="feather"] (a family doesn't change between themes), same one-altitude
     rule as --text/space/radius. Each token carries its COMPLETE stack INCLUDING fallbacks, declared ONCE;
     selectors reference the token and never re-spell a family name. Repair of record: the four faces load
     from a Google Fonts CDN with font-display:swap, and the display/serif/mono declarations named the brand
     face with NO fallback at all — so a blocked/slow CDN dropped h1/.h2/.brandmark to the browser's DEFAULT
     SERIF (Times), i.e. a different brand rather than a degraded one. Stacks are measured, not guessed:
     fallbacks ordered by advance-width + x-height proximity to the brand face (fontTools over the real CDN
     binaries) and by weight-axis coverage — system-ui leads the sans stacks because .brandmark/h1/.btn ask
     for 600/700 and the variable system faces cover those continuously where Arial/Helvetica would
     synthesize. Derivation + per-face degraded-state bar: proof-surface/font-token-tier.md */
  --font-display:"Bricolage Grotesque",ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
  --font-text:"Instrument Sans",ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
  --font-accent:"Instrument Serif",ui-serif,"Times New Roman",Times,Georgia,serif;
  --font-mono:"Space Mono",ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,"Liberation Mono",monospace;
  /* the one signature gradient, define-once */
  --ramp:linear-gradient(120deg,var(--c1),var(--c2),var(--c3),var(--c4),var(--c5));
  --ramp-loop:linear-gradient(var(--sa),var(--c1),var(--c2),var(--c3),var(--c4),var(--c5),var(--c1));
  /* --ramp-radial: adjacent radial gradients (Argyle heritage) — each hue radiates, so the
     midpoints stay vibrant instead of muddying through a linear interpolation. The DEFAULT for
     substantial color FIELDS; --ramp (linear) stays for hairlines/text-clip/bookmarks. */
  --ramp-radial:
    radial-gradient(ellipse 62% 150% at 2% 46%,  var(--c1), transparent 56%),
    radial-gradient(ellipse 56% 150% at 27% 54%, var(--c2), transparent 56%),
    radial-gradient(ellipse 56% 150% at 50% 44%, var(--c3), transparent 56%),
    radial-gradient(ellipse 56% 150% at 73% 56%, var(--c4), transparent 56%),
    radial-gradient(ellipse 64% 150% at 98% 48%, var(--c5), transparent 58%),
    var(--c3);
}
[data-theme="feather"] {
  /* interference ramp — LIGHT (Feather) */
  --c1:#C93B92; --c2:#6B4FD8; --c3:#3D5FE0; --c4:#0E7F9E; --c5:#0F8A64;
  /* pure white is reserved for raised — surface stays in the paper family (ruling 2026-07-16) */
  --ground:#F1F2F6; --surface:#FAFAFC; --raised:#FFFFFF; --inset:#E8E8EF;
  /* --ground-lift — the Feather half-step. Authored to the MEASURED delta, not copied as a mix
     percentage, for the same reason --muted-2 is: the two ramps are uneven in OPPOSITE directions
     (Aurora's steps rise .0208/.0257/.0303; Feather's fall .0285/.0242/.0143 against the #FFFFFF
     ceiling), so a percentage twin would land somewhere else entirely. dL here is .0117 vs Aurora's
     .0116. Feather has never been rendered on any operator surface — this value is arithmetic. */
  --ground-lift:#F5F6F9;
  --ink:#17141F; --ink-2:#3D3A49; --muted:#5D5A6B; --hairline:#DDDDE6;
  /* INK RAMP stop 4 — CANDIDATE. Feather is NOT a mix-percentage twin of Aurora: the same 86% mix
     lands 5.03:1 on Aurora and 4.51:1 here, so the value is authored to the RATIO, not copied.
     Theme-parity (I10): --muted-2 is defined in both themes; --ink-faint needs no override because
     it derives from --muted and --ground, which are already themed. */
  --muted-2:#6F6D7D;
  /* --ink-faint is re-declared here rather than inherited. ink-ramp-4th-rung.md §2b argued it
     "needs no override because it derives from --muted and --ground, which are already themed" —
     true of how it RESOLVES, false of what theme-parity/light-co-equal checks, which is DECLARATION.
     The gate caught it on first run (2026-07-29). It is not `theme-invariant` either: it resolves to
     a different colour per theme, so marking it so would be a lie to satisfy a check. Same
     expression, declared in both blocks — the mix re-resolves against Feather's --muted/--ground. */
  --ink-faint:color-mix(in oklab,var(--muted) 55%,var(--ground));
  /* SELECTION + SCROLLBAR — same construction as --ink-faint directly above, and re-declared for the
     same reason: the expression is theme-neutral but the RESULT is not, so the parity gate wants both
     blocks and `theme-invariant` would be a lie told to satisfy a check. The mixes re-resolve against
     Feather's --c2 / --ink / --ground. Feather at 72%: fill #907DE1, separation 3.02:1, text 5.37:1 —
     measured in a real compositor, and it is the WORSE of the two themes, which is why 72% is the
     crossing rather than a round number. See :root for the two-floor rationale. */
  --select-fill:color-mix(in oklab,var(--c2) 72%,transparent);
  --select-ink:var(--ink);
  --scrollbar-thumb:color-mix(in oklab,var(--ink) 22%,transparent);
  --scrollbar-thumb-hover:color-mix(in oklab,var(--ink) 38%,transparent);
  --scrollbar-track:transparent;
  /* --warn darkened #C7871A→#8A5A0F for the WCAG AA floor: it is TEXT in .pr-against--empty on paper
     (was 2.49:1, now 4.85:1 vs --inset) and the .pr-claim-defeat border (was 2.92:1 <3, now 5.67:1).
     Feather-only; Aurora --warn stays bright (passes 8.97:1). CANDIDATE amber — Aaron may retune ≥AA. */
  --success:#2E9E6B; --warn:#8A5A0F; --error:#D93843;
  /* PROOF DISTRICT (pr-) — CANDIDATE, pending Aaron's final hex. Feather: marks darken to read on paper;
     low confidence = faint blue-gray near paper, high = deep structural blue.
     Two AA-floor nudges (Feather-only, ≥4.5:1 as text): --pr-tier-u #8A6A30→#7E5F28 (verdict-exceptions
     text was 4.11:1 vs --inset, now 4.84); --pr-tier-k #1E8A64→#16785A (the knockout "K" badge letter
     was 3.85:1, now 4.85). Candidate hues — Aaron retunes, keeping ≥AA. */
  --pr-conf-1:#B9C0D2; --pr-conf-2:#8E9CC0; --pr-conf-3:#5F79AE; --pr-conf-4:#3A5BB8; --pr-conf-5:#22468F;
  --pr-for:#1C7C8C; --pr-against:#A24C8A;
  --pr-tier-k:#16785A; --pr-tier-i:#22468F; --pr-tier-u:#7E5F28;
  /* ── OPERATOR DISTRICT (op-) — the ONLY per-theme override this group needs. Every other --op-*
     token inherits Feather free through the primitive it aliases; that is the whole point of the
     alias layer, and `theme-derived` is what lets gate 1 accept it as parity rather than as ~30
     missing overrides. Ghosting reads differently on paper: at Aurora's alphas a light-mode ghosted
     edge reads "broken / half-loaded" rather than "inferred", so the two ghost alphas lift and the
     predicted-container alpha with them — the co-equal-light guardrail applied to an ENCODING
     rather than to a palette. Never rendered on Feather; these are derived, not seen. */
  --op-src-derived-alpha:.80; --op-src-inferred-alpha:.58; --op-life-predicted-alpha:.62;
}

*{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth}
body{
  background:var(--ground); color:var(--ink);
  font-family:var(--font-text);
  font-size:clamp(15px,1.05vw,17px); line-height:var(--leading-relaxed);
  -webkit-font-smoothing:antialiased; overflow-x:hidden;
  transition:background var(--dur-slow) var(--ease), color var(--dur-slow) var(--ease);
}
/* ── the weight floor (F13 · R3) ──
   The UA default for <b>/<strong> is `bolder`, which computes to 700 from an
   inherited 400/500 — and --font-text (Instrument Sans) loads 400/500/600 upright,
   so an untamed <b> is a 700 request against a 600 master: SYNTHETIC bold, smeared
   letterforms and metrics that do not match the fallback's.
   This was previously neutralized by TWELVE hand-written per-container `b` rules,
   and two containers were missed (.pull at 2.2rem on an italic serif; .ps-spec-note).
   Per-selector discipline requires enumerating every selector correctly, once, and
   again after every addition — a convention, not a mechanism (I11).
   One foundation rule instead: a selector cannot opt out by omission, only by
   declaring. Inline emphasis is 500 plus one ink step; where a container genuinely
   wants 600 it declares it and can say why. Pinned by `weight-floor` (qa/check.mjs). */
b,strong{font-weight:500;color:var(--ink)}
::selection{background:var(--select-fill);color:var(--select-ink)}
/* scrollbars — standard properties, so a treatment cannot move a measure. See the token block above.
   Set on html ONLY: both properties INHERIT, so one declaration reaches every scroll container, and a
   wider selector ([class], body, *) would be blast radius bought for nothing. Deliberately NOT paired
   with scrollbar-gutter here — whether a gutter is RESERVED is a per-surface layout decision (it costs
   ~1.10ch of measure), and inheriting it from brand core would make it a styling side effect, which is
   the exact failure walk D6 ruled against. Surfaces with contractual measures declare it themselves. */
html{scrollbar-color:var(--scrollbar-thumb) var(--scrollbar-track);scrollbar-width:thin}
.wrap{max-width:1500px;margin:0 auto;padding:0 var(--space-gutter)}
.mono{font-family:var(--font-mono)}

/* ── gradient-ring utility: a hairline that FOLLOWS border-radius (no corner clip) ──
   apply to any positioned, radius'd box via a ::before. mask-composite cuts the interior. */
.ring::before{content:"";position:absolute;inset:0;pointer-events:none;border-radius:inherit;padding:1px;
  background:var(--ramp);opacity:.5;transition:opacity var(--dur-slow) var(--ease);
  -webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
  -webkit-mask-composite:xor;
          mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
          mask-composite:exclude}

/* ── top rail: interference hairline that catches the pointer ── */
.rail{position:fixed;top:0;left:0;right:0;height:1.5px;z-index:60;pointer-events:none;
  background:linear-gradient(90deg,var(--c1),var(--c2),var(--c3),var(--c4),var(--c5));opacity:.30}
.rail::after{content:"";position:absolute;inset:0;background:inherit;opacity:1;
  -webkit-mask:radial-gradient(140px 3px at var(--rx,50%) 50%,#000,transparent 70%);
          mask:radial-gradient(140px 3px at var(--rx,50%) 50%,#000,transparent 70%)}

/* ── masthead / folio ── */
.masthead{position:sticky;top:0;z-index:50;
  background:color-mix(in oklab,var(--ground) 80%,transparent);
  backdrop-filter:blur(14px) saturate(120%);
  border-bottom:1px solid var(--hairline)}
.masthead .bar{display:flex;align-items:center;justify-content:space-between;gap:var(--space-6);height:66px}
.brandmark{font-family:var(--font-display);font-weight:700;letter-spacing:var(--track-normal);font-size:var(--text-body);
  display:flex;align-items:center;gap:var(--space-2)}
/* The mark, masked from the canonical file so there is exactly ONE definition of it
   (mark/corvus-mark.svg — digest #7; a copied path string would be a second one).
   background:currentColor makes it theme-reactive and matches the wordmark's ink exactly.
   url() resolves against THIS stylesheet, not the document, so one rule serves every
   surface depth (site/, proof-surface/, alarm-demo/, root) with no per-page path. */
.glyph{height:22px;aspect-ratio:426/396;display:inline-block;flex:none;background:currentColor;
  -webkit-mask:url(mark/corvus-mark.svg) center/contain no-repeat;
          mask:url(mark/corvus-mark.svg) center/contain no-repeat}
.folio{font-family:var(--font-mono);font-size:var(--text-mono);letter-spacing:var(--track-caps-xl);text-transform:uppercase;
  color:var(--muted);display:flex;gap:var(--space-5);align-items:center;flex-wrap:wrap}
.folio .tick{color:var(--ink)}
@media(max-width:640px){.folio span{display:none}}

/* ── theme toggle (single canonical affordance across all surfaces) ── */
.toggle{display:flex;align-items:center;gap:var(--space-2);border:1px solid var(--hairline);
  background:var(--surface);color:var(--muted);
  font-family:var(--font-mono);font-size:var(--text-mono);letter-spacing:var(--track-mono);text-transform:uppercase;
  padding:var(--space-2) var(--space-3);border-radius:var(--radius-pill);cursor:pointer;
  transition:color var(--dur-slow) var(--ease),border-color var(--dur-slow) var(--ease)}
.toggle:hover{color:var(--ink);border-color:color-mix(in oklab,var(--c3) 45%,var(--hairline))}
.toggle .dot{width:9px;height:9px;border-radius:50%;
  background:linear-gradient(var(--sb),var(--c1),var(--c3),var(--c5));animation:spin 9s linear infinite}
@keyframes spin{to{--sb:480deg}}

/* ── hero scaffold: full-bleed canvas + left-anchored copy (balanced, not lop-sided) ── */
.hero{position:relative;min-height:calc(100svh - 66px);overflow:hidden;isolation:isolate}
.hero::before{content:"";position:absolute;inset:-18%;z-index:0;pointer-events:none;
  background:
    radial-gradient(46% 40% at 20% 44%, color-mix(in oklab,var(--c2) 20%,transparent), transparent 72%),
    radial-gradient(58% 44% at 74% 32%, color-mix(in oklab,var(--c2) 28%,transparent), transparent 70%),
    radial-gradient(52% 40% at 88% 62%, color-mix(in oklab,var(--c4) 24%,transparent), transparent 70%),
    radial-gradient(60% 50% at 60% 92%, color-mix(in oklab,var(--c1) 16%,transparent), transparent 72%);
  filter:blur(26px) saturate(115%);opacity:.6;mix-blend-mode:screen;
  animation:drift 36s ease-in-out infinite alternate}
[data-theme="feather"] .hero::before{opacity:.5;mix-blend-mode:multiply;filter:blur(30px)}
@keyframes drift{0%{transform:translate3d(-2%,-1%,0) scale(1.02)}100%{transform:translate3d(3%,2%,0) scale(1.07)}}
#field{position:absolute;inset:0;z-index:1;width:100%;height:100%;display:block}
.catch{position:absolute;inset:-10% -5%;pointer-events:none;z-index:2;opacity:.16;
  background:conic-gradient(from 90deg,var(--c1),var(--c2),var(--c3),var(--c4),var(--c5),var(--c1));
  -webkit-mask:radial-gradient(420px circle at var(--mx,60%) var(--my,42%),#000 0,transparent 62%);
          mask:radial-gradient(420px circle at var(--mx,60%) var(--my,42%),#000 0,transparent 62%);
  transition:opacity var(--dur-slow) var(--ease)}
.catch.lit{opacity:.30}
.hero::after{content:"";position:absolute;inset:0;z-index:3;pointer-events:none;
  background:linear-gradient(100deg,
    color-mix(in oklab,var(--ground) 90%,transparent) 0%,
    color-mix(in oklab,var(--ground) 62%,transparent) 32%,
    transparent 58%)}
[data-theme="feather"] .hero::after{background:linear-gradient(100deg,
    color-mix(in oklab,var(--ground) 84%,transparent) 0%,
    color-mix(in oklab,var(--ground) 46%,transparent) 34%,
    transparent 60%)}
.hero-inner{position:relative;z-index:4;max-width:1500px;margin:0 auto;
  min-height:calc(100svh - 66px);display:flex;align-items:center;
  padding:clamp(40px,8vh,96px) var(--space-gutter)}
.hero-copy{max-width:var(--measure-tight)}

/* ── type primitives ── */
.eyebrow{font-family:var(--font-accent);font-style:italic;font-size:var(--text-lede);color:var(--ink-2);
  display:flex;align-items:center;gap:var(--space-3);margin-bottom:var(--space-6);white-space:nowrap}
/* section bookmark — thick gradient bar, rounded endcaps; punctuates, never overreaches */
.eyebrow::before,.label::before{content:"";width:30px;height:4px;border-radius:var(--radius-pill);background:var(--ramp);flex:none}
h1,.h1{font-family:var(--font-display);font-weight:600;letter-spacing:var(--track-display);line-height:var(--leading-display);
  font-size:var(--text-display);max-width:16ch;text-wrap:balance}
.shimmer{--sa:120deg;background:var(--ramp-loop);background-size:220% 220%;
  -webkit-background-clip:text;background-clip:text;color:transparent;
  animation:sheen 9s linear infinite;font-style:italic;padding-right:.06em}
@keyframes sheen{to{--sa:480deg}}
.lede{margin-top:var(--space-6);max-width:var(--measure-lede);color:var(--muted);font-size:var(--text-lede)}
.chip{font-family:var(--font-mono);font-size:var(--text-mono);letter-spacing:var(--track-wide);color:var(--muted);
  margin-top:var(--space-10);display:inline-flex;align-items:center;gap:var(--space-2);
  border:1px solid var(--hairline);border-radius:var(--radius-pill);padding:var(--space-2) var(--space-4)}
.chip i{width:6px;height:6px;border-radius:50%;background:var(--c5);font-style:normal}
.cap{position:absolute;right:clamp(22px,5vw,64px);bottom:clamp(22px,4vh,44px);z-index:4;
  font-family:var(--font-mono);font-size:var(--text-micro);letter-spacing:var(--track-caps);text-transform:uppercase;
  color:var(--muted);text-align:right;line-height:var(--leading-loose);opacity:.8;max-width:42%}
@media(max-width:900px){.cap{display:none}}

/* ── section frame ── */
section.block{padding:var(--space-section) 0;border-top:1px solid var(--hairline)}
.label{font-family:var(--font-accent);font-style:italic;color:var(--ink-2);font-size:var(--text-lede);margin-bottom:var(--space-4);
  display:flex;align-items:center;gap:var(--space-3)}
.h2{font-family:var(--font-display);font-weight:600;letter-spacing:var(--track-tight);line-height:var(--leading-display);
  font-size:var(--text-h2);max-width:17ch;text-wrap:balance}

/* ── flight paths (hand-crafted novel bit — scaffold only lives here) ── */
.flight{margin-top:clamp(36px,6vw,72px);position:relative}
.flight svg{width:100%;height:auto;display:block;overflow:visible}
.flight-copy{max-width:var(--measure-lede);color:var(--muted);margin-top:var(--space-8);font-size:var(--text-body-lg)}
.pathline{fill:none;stroke-width:2.4;stroke-linecap:round;
  stroke-dasharray:var(--len);stroke-dashoffset:var(--len);
  /* 2.1s is CHOREOGRAPHY, not chrome response, and it is exempted per-declaration in the
     no-raw-duration ledger rather than snapped. Snapped to --dur-slow and rendered
     (2026-08-02): the whole draw completed by t≈150ms — --ease is heavily front-loaded —
     while the companion delays below (1.4s / 1.7s / 1.9s / 2.2s) are out of that gate's
     scope and stayed put, so the sequence drew itself instantly and then sat still for over
     a second. The entrance stopped being a flight. */
  transition:stroke-dashoffset 2.1s var(--ease)}
.drawn .pathline{stroke-dashoffset:0}
.drawn .pathM{transition-delay:1.4s}
.node{r:0;fill:var(--ink);transition:r .5s var(--ease) 1.9s}   /* choreography — beat 3 of the flight; exempted, see .pathline */
.drawn .node{r:5}
.pulse{transform-box:fill-box;transform-origin:center}
.drawn .pulse{animation:pulse 3.4s var(--ease) 2.2s infinite}
@keyframes pulse{0%,100%{r:5;opacity:1}50%{r:8;opacity:.55}}
.comet{opacity:0}.drawn .comet{opacity:1}
.chev{fill:none;stroke:var(--muted);stroke-width:1.4;stroke-linecap:round;stroke-linejoin:round;opacity:0;transition:opacity .6s ease 1.7s}   /* choreography — beat 2 of the flight; exempted, see .pathline */
.drawn .chev{opacity:.7}

/* ── .steps — an ordered sequence where the order is the point ──
   LAYOUT ONLY, in the family of .grid and .railed: it hosts .panel children and supplies no voice
   of its own. The delta against .grid is exactly order + connection — a sequence read out of order
   is a different object from a set read in any order — which is why this is a layout rather than a
   new card.

   TWO CONDITIONS, both places this layout would otherwise quietly acquire a voice it claims not to
   have (Design System Steward, 2026-07-30):

   · THE SPINE IS --hairline, AND A --ramp SPINE IS REFUSED. The ramp is rationed — it fires where
     earned and never fills chrome (digest 1) — and a four-step connector is chrome. .railed already
     takes --hairline for its column border, so converging on it is the precedent rather than a new
     call.
   · THE INDEX IS .panel's EXISTING .n, and .steps authors no second index register. The draft
     contract said the layout supplies "an index per step" while also claiming to supply no voice of
     its own; both cannot be true. `.n` is already the mono index label on .panel, and
     specificity-first applies INSIDE a primitive exactly as it does between them. So there is no
     .steps-index, no counter, no pill: the step number is the panel's own. */
.steps{position:relative;display:flex;flex-direction:column;gap:var(--space-5);
  margin-top:var(--space-10);padding-left:var(--space-8)}
/* The spine reads as a CONNECTOR only if it sits near what it connects; at a wider gutter it reads
   as a page rule and the sequence loses the thing that makes it a sequence. 16px, on the grid. */
.steps::before{content:"";position:absolute;left:var(--space-4);top:var(--space-4);bottom:var(--space-4);
  width:1px;background:var(--hairline)}
@media(max-width:640px){.steps{padding-left:var(--space-5)}.steps::before{left:var(--space-1)}}

/* ── .terms — what is offered, stated as an offer ──
   The transactional register, and the one primitive here whose absence costs money rather than
   polish: a buyer's four questions (what does it cost, what do I get, what is first, how long) were
   answerable only by reading a paragraph. Brand core had no key/value shape of ANY kind — .chip is
   a pill, .rail-note a dated aside, .folio a metadata strip — so this is a genuine gap rather than
   a near-miss.

   A real <dl>: keys and values are definitionally paired, and the element says so. Keys ride the
   mono label voice; values ride the reading face. Scannable without reading, which is the contract. */
.terms{display:flex;flex-direction:column;margin-top:var(--space-8);
  border-top:1px solid var(--hairline);border-bottom:1px solid var(--hairline)}
.terms-row{display:grid;grid-template-columns:minmax(9rem,1fr) 3fr;gap:var(--space-4);
  padding:var(--space-4) 0;align-items:baseline}
.terms-row + .terms-row{border-top:1px solid var(--hairline)}
.terms-key{font-family:var(--font-mono);font-size:var(--text-mono);letter-spacing:var(--track-mono);
  color:var(--muted);line-height:var(--leading-snug)}
.terms-val{font-size:var(--text-body);color:var(--ink-2);line-height:var(--leading-snug);margin:0}
/* .terms--prose — the modifier for values that are READING PARAGRAPHS, not scan lines.
   The base contract ("scannable without reading") sets snug leading and lets the value
   column run the grid's full 3fr (~72ch at the page measure) — right for a one-line
   value, a return-sweep failure once a reading-size value wraps past two lines, and 6ch
   wider than every .page-prose paragraph beside it. Promoted to canon 2026-08-09 when
   the CC front door's values became multi-sentence (Stage-8 R2's staged obligation,
   landed early at brand-canon-home's insistence — the per-surface retune it replaces
   was G2's own defect shape). Base .terms untouched; opt-in per dl. */
.terms--prose .terms-val{line-height:var(--leading-relaxed);max-width:var(--measure-prose)}
@media(max-width:640px){.terms-row{grid-template-columns:1fr;gap:var(--space-1)}}

/* ── .stat — a quantity set as a quantity ──
   The assertive register's smallest primitive, and the one the system most obviously lacked: a
   number that carries an argument was being set as body text inside a paragraph, which is the
   strongest object on a page rendered as its weakest.

   Face first, size second, weight last (§ Type-role assignment): the value rides --font-display,
   which is where a weight ramp actually exists, and reaches --text-display standalone. It is loud
   because it is set differently and set large — not because it is heavy.

   .stat-row PINS THE TIER RATHER THAN ASSUMING IT. The contract's claim is that stats in a row sit
   on ONE baseline, and that is only true if the values share a type tier — a row mixing --text-h2
   and --text-display breaks the alignment silently, and silently is the whole problem. So the row
   SETS the tier for its children instead of documenting a hope. The Steward's condition was "pin
   one tier per row, or drop the baseline claim"; this pins it. */
.stat{display:flex;flex-direction:column;gap:var(--space-2)}
.stat-value{font-family:var(--font-display);font-weight:600;font-size:var(--text-display);
  letter-spacing:var(--track-display);line-height:var(--leading-display);color:var(--ink);
  font-variant-numeric:tabular-nums}
.stat-label{font-family:var(--font-mono);font-size:var(--text-mono);letter-spacing:var(--track-mono);
  color:var(--ink-2);line-height:var(--leading-snug)}
.stat-note{font-size:var(--text-small);color:var(--muted);line-height:var(--leading-body);
  max-width:var(--measure-tight)}
.stat-row{display:flex;flex-wrap:wrap;gap:var(--space-10) var(--space-16);align-items:baseline;
  margin-top:var(--space-8)}
/* One tier for every value in the row — the baseline claim, made structural. */
.stat-row .stat-value{font-size:var(--text-h2)}

/* ── .compare — alternatives read positionally, across shared named dimensions ──
   The assertive register's comparison shape: two or more alternatives set across the SAME named
   dimensions so the difference is seen instead of narrated. Not `pr-diff` — that is before/after
   against an approved snapshot and its poles are TEMPORAL. This is alternatives, and its poles are
   nothing at all.

   IT IS A REAL <table>, and that is a contract decision rather than a convenience. Alternatives ×
   named dimensions IS tabular data: a <table> gives row/column association in the a11y tree for
   free (`scope` on the headers), aligns rows without a single layout knob, and needs no
   `display:contents` wrapper — which would have stripped the very structure a screen reader needs
   to read a comparison as a comparison. A grid of divs would have looked identical and read as a
   flat list of eleven unrelated strings.

   NEUTRALITY IS THE DISTRICT'S RULE, NOT THIS ONE, and it deliberately has no expression here.
   Off a proof surface a preferred column is legitimate — a pricing table SHOULD point at a plan —
   so brand core styles every alternative identically and stops. Forcing sameness by declaration was
   tested and rejected: a declaration is a DEFAULT and a page-local rule overrides a default, which
   would look like enforcement without being it. On proof surfaces the prohibition is held by
   `compare-col-symmetry` (PROOF-INDEX § District constraints).

   The axis column is `.compare-axis`, deliberately NOT a `.compare-cell`: the dimension NAMES are
   not alternatives, so they are free to be styled differently, and keeping them a separate class is
   what lets the symmetry gate constrain only the things that are actually being compared. */
.compare{width:100%;border-collapse:collapse;table-layout:fixed;margin-top:var(--space-8);text-align:left}
/* The AXIS column is narrowed deliberately: it is not an alternative, so it need not share the
   alternatives' width — and at an equal third it pushed the things being compared apart far enough
   that the comparison stopped reading positionally, which is the whole contract. The ALTERNATIVES
   still split the remainder equally; that half of the equal-width claim is what neutrality means. */
.compare-axis{width:22%}
.compare-head{font-family:var(--font-display);font-weight:600;font-size:var(--text-h3);
  letter-spacing:var(--track-tight);line-height:var(--leading-snug);color:var(--ink);
  padding:0 var(--space-4) var(--space-4);vertical-align:bottom;text-wrap:balance}
/* Leading is --leading-snug on both, and that is a design call rather than a gate dodge: a compare
   cell holds a SHORT PHRASE, not running prose, so prose leading would open it up for a reading it
   never does. It also keeps these rules honestly outside gate 6's proxy (reading size + prose
   leading ⇒ a measure cap), which would otherwise have collected its first false positive here —
   and the answer to a false positive is never to manufacture the cap it asks for.
   No max-width: `table-layout:fixed` + `width:100%` divides the columns EQUALLY, which is where the
   real measure control lives, and equal column width is itself part of what neutrality means. */
.compare-axis{font-size:var(--text-small);color:var(--muted);font-weight:400;
  line-height:var(--leading-snug);padding:var(--space-4) var(--space-4) var(--space-4) 0;
  vertical-align:baseline}
.compare-cell{font-size:var(--text-body);color:var(--ink-2);line-height:var(--leading-snug);
  padding:var(--space-4);vertical-align:baseline}
.compare tbody tr{border-top:1px solid var(--hairline)}
/* The corner cell names nothing and must not read as a dimension. */
.compare thead .compare-axis{padding-bottom:var(--space-4)}
.compare-note{font-size:var(--text-small);color:var(--muted);margin-top:var(--space-4);
  line-height:var(--leading-body);max-width:var(--measure-prose)}
@media(max-width:640px){
  .compare-head{font-size:var(--text-body-lg)}
  .compare-axis,.compare-cell{padding-left:var(--space-2);padding-right:var(--space-2)}
}

/* ── principles: inset panels with corner-following gradient ring ── */
.grid{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(12px,1.6vw,20px);margin-top:clamp(36px,5vw,60px)}
@media(max-width:760px){.grid{grid-template-columns:1fr}}
.panel{position:relative;background:var(--surface);border:1px solid var(--hairline);border-radius:var(--radius-panel);
  padding:clamp(22px,2.4vw,30px);overflow:hidden;
  box-shadow:inset 0 1px 0 color-mix(in oklab,var(--ink) 7%,transparent);
  transition:border-color var(--dur-slow) var(--ease),transform var(--dur-slow) var(--ease)}
.panel:hover{border-color:color-mix(in oklab,var(--c3) 40%,var(--hairline))}
.panel:hover.ring::before{opacity:.9}
.panel .n{font-family:var(--font-mono);font-size:var(--text-mono);color:var(--muted);letter-spacing:var(--track-mono)}
.panel h3{font-family:var(--font-display);font-weight:600;letter-spacing:var(--track-tight);font-size:var(--text-h3);margin:var(--space-4) 0 var(--space-2)}
.panel p{color:var(--muted);font-size:var(--text-body)}

/* ── specimen: standalone attribute words that catch the light on hover ── */
.specimen{margin-top:clamp(40px,6vw,68px);display:flex;flex-wrap:wrap;gap:.28em .7em;
  font-family:var(--font-display);font-weight:600;letter-spacing:var(--track-tight);
  font-size:clamp(1.5rem,4vw,2.6rem);line-height:var(--leading-tight)}
.specimen span{color:var(--ink);cursor:default;position:relative;white-space:nowrap;
  transition:color var(--dur-slow) var(--ease)}
.specimen span::after{content:attr(data-w);position:absolute;inset:0;background:var(--ramp);
  -webkit-background-clip:text;background-clip:text;color:transparent;
  opacity:0;transition:opacity var(--dur-slow) var(--ease)}
.specimen span:hover{color:transparent}
.specimen span:hover::after{opacity:1}

/* ── footer ── */
footer{border-top:1px solid var(--hairline);padding:clamp(48px,7vh,80px) 0 clamp(40px,6vh,64px)}
.foot{display:flex;justify-content:space-between;align-items:flex-end;gap:var(--space-8);flex-wrap:wrap}
.pull{font-family:var(--font-accent);font-style:italic;font-size:clamp(1.4rem,3.4vw,2.2rem);
  max-width:26ch;line-height:var(--leading-snug);text-wrap:balance}
/* --font-accent is ONE master — Instrument Serif italic 400, no upright and no bold.
   So .pull's emphasis channel is zero weight steps wide, and the b,strong floor's 500
   would be a phantom step here at best. Emphasis is INK ONLY (F13 · R2): the word reads
   as lit rather than heavy, which is the more Corvus answer — depth is plane value, not
   drama. `inherit` states that intent; it is not a workaround for the floor. */
.pull b{font-weight:inherit;color:var(--ink)}
.foot .chip{margin-top:0}

/* ── annotation rail: a mono margin column (dates, commit-style asides), like a drawing set —
   the identity's structural signature. Collapses to stacked-inline on narrow viewports. ── */
.railed{display:grid;grid-template-columns:1fr;gap:var(--space-5)}
.rail-col{font-family:var(--font-mono);font-size:var(--text-mono);color:var(--muted);line-height:var(--leading-loose)}
/* THE REGISTER TRAVELS WITH THE ATOM (BID-Corvus 2026-07-27, §2a): the note is the atom of the
   identity's structural signature, so it carries its own mono voice — family + size + voice-color —
   and is usable standalone (in a .panel, a card, a pr-figure) without a hand-added .mono.
   line-height is DELIBERATELY NOT here: --leading-loose is tuned to .rail-col's 210px measure, and
   leading answers to measure. Inside .rail-col it inherits loose (unchanged); standalone it inherits
   the host's. Register travels; layout-tuned properties stay with the layout.
   Zero visual regression: equal specificity, later source order, identical values. */
.rail-note{font-family:var(--font-mono);font-size:var(--text-mono);color:var(--muted);margin-bottom:var(--space-6)}
.rail-note .rd{display:flex;align-items:center;gap:var(--space-2);color:var(--ink-2);margin-bottom:var(--space-1);white-space:nowrap}
.rail-note .rd::before{content:"";width:16px;height:3px;border-radius:var(--radius-pill);background:var(--ramp);flex:none}
.rail-note p{color:var(--muted);margin:0}
@media(min-width:1000px){
  .railed{grid-template-columns:210px minmax(0,1fr);gap:0}
  .rail-col{border-right:1px solid var(--hairline);padding-right:var(--space-6);text-align:right}
  /* SCOPED to the column (2026-07-27). Right-alignment is layout, not register: it exists
     because the 210px rail is right-aligned against its border. Unscoped, it also reached
     standalone notes — a note inside a panel/card/figure had its dated head flung to the
     right edge of its host. Same register/layout line as the .rail-note move above, applied
     to the one rule that crossed it. Zero regression inside .rail-col (proven by diff). */
  .rail-col .rail-note .rd{justify-content:flex-end}
  .rail-main{padding-left:var(--space-8)}
}

/* ════════════════════════════════════════════════════════════════════════════
   SHELL LAYOUT — .splitter · .collapsible

   PROMOTED FROM THE OPERATOR DISTRICT 2026-08-02 (Aaron, /walk D1.3, diverging
   from the Steward's "not yet"). These are brand core's first APPLICATION-SHELL
   primitives: brand core was a brand-and-document stratum, and a resizable
   boundary between two regions is neither page furniture nor an epistemic
   object. Both cleared T2 with every rule surviving the transplant.

   THE REASON THE PROMOTION IS RIGHT IS SHARPER THAN THE ONE ON THE RECORD, and
   it was found by looking rather than reasoning: field/artisan-01.html links
   `../brand.css` AND NOTHING ELSE. "Compose from the district" for that surface
   means either linking a ~70KB district sheet to reach two primitives, or joining
   a district it was explicitly admitted to as a CLIENT rather than a member
   (ds-binding §1.3/§4). The Steward's recommendation asserted "nothing about
   composing today gets harder if it happens later"; that claim was false on the
   facts, and this comment records the correction rather than the recommendation.

   NAMES DROP THE DISTRICT PREFIX AND THE DISTRICT NAMES RETIRE — no alias, no
   shim. Brand core was unprefixed at 71 of 71 classes when this was decided (76
   after this promotion), so an `op-` class here
   would be the only one, naming a district the core is not allowed to know
   about. The precedent Aaron cited runs exactly this way: --op-stroke-* did not
   survive promotion as an alias, it retired (walk E3), for the reason brand.css
   states one tier up — "a downstream surface's vocabulary reaching upstream".
   An alias period was priced and refused on a mechanical ground, not a tidy
   one: `op-canon-home` scans operator-district/ only and CANNOT SEE this file,
   so an .op-* selector parked here would be held by no gate for the whole
   alias period, with a removal trigger that is a convention — the shape I11
   says degrades.

   REDUCED MOTION IS RE-DECLARED PER PRIMITIVE, AND THAT IS NOT REDUNDANCY.
   This file ends with a blanket `*{transition:none!important}`, so for anything
   that LINKS brand.css the carves below are already covered — which is why the
   first cut of this block dropped them as a define-once win. That was wrong, and
   the reason is specific to these two primitives: they are brand core's first
   designed to be VENDORED off-repo, and the generator that vendors them
   (vault-extension/operator-surface/sync-corvus-district.mjs) slices brand core
   BY SELECTOR — the way it already slices `.terms` for op-readout. A blanket `*`
   rule is invisible to a selector-scoped slice, so a vendoring consumer would
   receive the primitive and silently lose its reduced-motion honouring. The
   carve travels with the shape it belongs to.
   ════════════════════════════════════════════════════════════════════════════ */

/* ── .splitter — a drag-to-resize handle between two adjacent regions.
   Behaviour is splitter.js: it SETS role/aria-orientation/tabindex/aria-valuenow
   at init, so a consumer who omits them in markup still gets a reachable,
   announced separator. That repair is the primitive — the shape alone ships a
   focusable element with no resize behaviour, which is the Haven defect it was
   pulled over to fix. Composing the class without the script is the half-state.
   ONE MECHANISM, TWO ORIENTATIONS: default is a vertical handle resizing the
   inline axis; --h is a horizontal handle resizing the block axis. ── */
.splitter{position:relative;flex-shrink:0;user-select:none;
  width:var(--splitter-w);align-self:stretch;background:var(--ink-faint);
  cursor:col-resize;border:0;padding:0;
  transition:background-color var(--dur-fast) var(--ease)}
/* The grab target is larger than the paint. A 5px handle is a 5px target
   without this; 11px is the smallest comfortable one. */
.splitter::after{content:"";position:absolute;inset-block:0;
  inset-inline:calc(-1 * var(--splitter-hit))}
.splitter:hover,.splitter.is-dragging{background:var(--rule-hover)}
/* Geometry overridden deliberately: the ring must sit OUTSIDE a 5px handle,
   which is why the shared focus rule is zero-specificity `:where()`. */
.splitter:focus-visible{outline:var(--stroke-bold) solid var(--c2);
  outline-offset:var(--stroke-hair)}
.splitter--h{width:auto;align-self:auto;height:var(--splitter-w);cursor:row-resize}
.splitter--h::after{inset-inline:0;inset-block:calc(-1 * var(--splitter-hit))}

/* ── .collapsible — collapse a pane to a rail, never to zero.
   NEVER TO ZERO IS THE WHOLE PRIMITIVE. A pane that collapses to nothing has not
   been collapsed, it has been closed, and every instrument inside it is gone with
   no affordance to bring it back. The rail is what makes this a collapse rather
   than a dismissal, which is why the state word stays `railed` on promotion:
   `data-collapsed` would name the thing the contract exists to refuse.

   CLAMPED, NOT SET, and this was a real defect caught by rendering. `width:
   var(--collapsible-rail-w)` LOSES to an inline width, and a collapsible pane
   will essentially always carry one — a .splitter resizes by writing style.width.
   The rail would have silently never engaged on the one surface it exists for,
   while passing every check that reads the rule rather than the box. min+max at
   one value clamps any width — inline, author or inherited — without !important.

   `.collapsible-label` IS SCOPED TO ITS OWNER, not named `.rail-label`: brand
   core already spends `rail` on the fixed top bar and on the margin-column
   layout, and a third unrelated meaning in a vocabulary that size is drift. The
   owner-part grammar is brand core's own (.terms-key, .stat-label, .rail-col).

   THE LABEL IS VISUALLY HIDDEN, NOT HIDDEN, and the contract is deliberately
   stronger than "every tab remains focusable". display:none keeps a control
   focusable and strips its accessible NAME — a keyboard user lands on something
   that announces nothing, which is worse than an unreachable control because it
   looks like it works. clip-path + a 1px box, never display:none, visibility:
   hidden (both leave the a11y tree) or opacity:0 (the attenuation channel the
   shell register forbids outright). ── */
.collapsible{flex-shrink:0;transition:width var(--dur-base) var(--ease)}
.collapsible[data-railed="true"]{min-width:var(--collapsible-rail-w);
  max-width:var(--collapsible-rail-w)}
.collapsible[data-railed="true"] .collapsible-label{position:absolute;
  width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}

/* THE A11Y CARVE for .splitter — an accessibility mode, not a theme, which is why
   it may move a value Aurora↔Feather may not. The resting --ink-faint measures
   ~2.5:1 and is ratified at that value by eye; this is the exercise path for
   anyone for whom 2.5:1 does not read at all. Travelled with the primitive from
   the district's region carve, where it was authored as a neighbour. */
@media(prefers-contrast:more){
  .splitter{background:var(--muted-2)}
}

/* Reduced motion — see the block header: carried per-primitive because these two
   are vendored by selector elsewhere, where the file-end blanket cannot reach.
   The colour transition is .splitter's only motion, so this is a complete
   honouring rather than a partial one. */
@media(prefers-reduced-motion:reduce){
  .splitter{transition:none}
  .collapsible{transition:none}
}

/* ── actions: link floor · buttons · link showcase · focus ── */
/* ── the link floor (D1 · Steward ruling 2026-08-09) ──
   The brand rule — underline = link; the cue is STRUCTURAL, never hue — had lived only in
   comments and rulings, never in a rule. So a bare <a> shipped the UA default: blue, visited-
   purple, unthemed — near-illegible on Aurora's ground (no color-scheme is declared, so the
   UA picks its light-mode blue), fine-by-accident on Feather. It shipped exactly that way on
   a client surface (cc-front.html's depth links), because every prior consumer had re-derived
   its own treatment per class (.link, .pr-xref/.pr-source-link, .s-nav-link, .cc-falsifier-
   toggle) and the one surface composing BARE anchors inherited nothing. Per-selector
   discipline is a convention, not a mechanism (I11) — same reasoning as the b,strong weight
   floor above: a selector cannot opt out by omission, only by declaring.
   THE VALUES, with their reasons (compositional choices, tunable like any candidate):
   · color:inherit — a link reads in its sentence's ink; a link inside muted prose must not
     lift itself (the pr-xref/pr-source-link reasoning, adopted as the floor).
   · resting underline --muted, not --hairline — an anchor whose whole job is to be followed
     (a depth map, a body link) needs a READABLE cue; --hairline measures ~1.2–1.3:1 against
     the planes and is the district's deliberately-recessive APPARATUS register. That
     difference has a reason on the record, so pr-xref/pr-source-link keep their quieter
     resting color (converge-drift applies only to unreasoned differences).
   · no :visited differentiation — deliberate: these are working documents, not browsing
     history, and author-origin color:inherit already retires the UA purple.
   · thickness rides --stroke-hair so prefers-contrast can thicken every cue in one move.
   Pinned by `link-floor` (proof-surface/verify.mjs) — absence is the defect it pins. */
a{color:inherit;text-decoration:underline;text-decoration-thickness:var(--stroke-hair);
  text-decoration-color:var(--muted);text-underline-offset:2px;
  transition:text-decoration-color var(--dur-slow) var(--ease)}
a:hover,a:focus-visible{text-decoration-color:currentColor}
.btn{display:inline-flex;align-items:center;gap:var(--space-2);font-family:var(--font-display);font-weight:600;
  font-size:var(--text-body);letter-spacing:var(--track-normal);line-height:var(--leading-display);padding:var(--space-3) var(--space-5);border-radius:var(--radius-md);cursor:pointer;
  border:1px solid var(--hairline);background:var(--surface);color:var(--ink);position:relative;
  /* text-decoration:none — the § 7.2 core fix, landed 2026-08-09 with the link floor above
     (which made it urgent: without this, every <a class="btn"> would inherit the floor's
     underline). Blast radius is exactly one case — <a class="btn"> — which was the defective
     case; a <button> never had a UA underline. Retires the per-consumer resets: cc-front.css
     `.front-action` (retired in the same change) and cc-offer.css `.cc-artifact .btn`
     (frozen sheet; identical value, so it is redundant-not-conflicting — staged to retire at
     the depth re-cut). Recorded in PRIMITIVE-INDEX § `.btn`. */
  text-decoration:none;
  transition:border-color var(--dur-slow) var(--ease),transform var(--dur-base) var(--ease),color var(--dur-slow) var(--ease)}
.btn:hover{transform:translateY(-1px);border-color:color-mix(in oklab,var(--c3) 45%,var(--hairline))}
.btn:active{transform:translateY(0)}
.btn-ghost{background:transparent}
/* primary — the rationed gradient moment: a gradient-ring edge (compose with .ring) */
.btn.ring{border-color:transparent}
.btn.ring::before{opacity:.85}
.btn.ring:hover::before{opacity:1}
/* bold — one loud CTA per view: radial-ramp fill (Argyle heritage), ground-colored text */
.btn-bold{border-color:transparent;background:var(--ramp-radial);color:var(--ground);font-weight:700}
.btn-bold:hover{transform:translateY(-1px);filter:saturate(108%)}
/* inline link, SHOWCASE register — a gradient underline that grows on hover. This is the
   rationed --ramp moment, NOT the default anchor treatment (the floor above is): the ramp
   fires where earned and never fills chrome, and a page of ramp underlines is chrome.
   Re-scoped 2026-08-09 — the index's "every inline text link" claim was the mis-route that
   helped D1 ship (an author querying the catalog was pointed at the showcase, and the floor
   that should catch the un-classed case did not exist). */
.link{color:var(--ink);text-decoration:none;background-image:var(--ramp);
  background-size:100% 1.5px;background-repeat:no-repeat;background-position:0 100%;
  padding-bottom:1.5px;transition:background-size var(--dur-slow) var(--ease)}
.link:hover{background-size:100% 2.5px}
/* focus — a visible ramp-violet ring, never removed */
:where(a,button,.btn,.toggle,input,select,textarea,[tabindex]):focus-visible{
  outline:2px solid var(--c2);outline-offset:2px;border-radius:var(--radius-sm)}

/* ── skip link — the a11y floor, composed into every emitted page by
   render/page-shell.mjs (H9). Chrome, not district canon, so it lives here
   with the other chrome and is available to every surface family.
   HIDDEN BY TRANSFORM, NEVER display:none — the whole point is that it stays
   in the tab order; display:none or visibility:hidden would remove it from
   the only interaction that reaches it. Reveals on :focus (not :focus-visible)
   so it appears for any focus route, and the ring above still draws. ── */
.skip-link{position:absolute;left:var(--space-2);top:var(--space-2);z-index:100;
  transform:translateY(-200%);
  font-family:var(--font-mono);font-size:var(--text-mono);letter-spacing:var(--track-mono);
  color:var(--ink);background:var(--raised);border:1px solid var(--hairline);
  border-radius:var(--radius-sm);padding:var(--space-2) var(--space-3);text-decoration:none;
  transition:transform var(--dur-base) var(--ease)}
.skip-link:focus{transform:none}

/* ── scroll reveal ── */
.reveal{opacity:0;transform:translateY(18px);transition:opacity var(--dur-slow) var(--ease),transform var(--dur-slow) var(--ease)}
.reveal.in{opacity:1;transform:none}
.reveal.d1{transition-delay:.08s}.reveal.d2{transition-delay:.16s}.reveal.d3{transition-delay:.24s}

/* ── reduced motion ── */
@media(prefers-reduced-motion:reduce){
  *{animation:none!important;transition:none!important}
  .shimmer{--sa:120deg}.reveal{opacity:1;transform:none}
  .pathline{stroke-dashoffset:0}.node,.pulse{r:5}.chev{opacity:.7}.catch{opacity:.12}
}
