/* ═══════════════════════════════════════════════════════════════════
   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;
  /* ── ICON tier — I10 dimensional family, landed 2026-08-22. Theme-INVARIANT → :root ONLY
     (a glyph is not heavier in one theme). PROMOTED from the operator district on a re-derivation
     that had ALREADY HAPPENED: `.op-icon` (operator.css) and `obsidian-theme/theme.css` each declare
     the same weight for the same icon set — Lucide, ISC, and Obsidian's native set is Lucide too —
     with no token between them. That is CODIFICATION.md § Step 2's named silent failure (a general
     primitive district-sited, every future non-shell surface re-deriving it), with the vendored theme
     as the prediction already come true. Placement verdict + reason:
     operator-district/PRIMITIVE-INDEX.md § `op-icon` + `op-avatar`.

     --icon-stroke IS NOT AN ALIAS OF --stroke-*, AND MUST NOT BECOME ONE. Different KINDS, not
     different values. --stroke-* is a device CSS px length on `border-width`; --icon-stroke is a
     DIMENSIONLESS ratio in the icon's own 24-unit viewBox, so what renders is 1.75 × box ÷ 24 and it
     coincides with a --stroke-* value at exactly ONE box size per value (1px at 13.71px, 1.5px at
     20.57px). Aliasing would make the accessibility carve --stroke-* exists FOR — thicken every
     hairline in one declaration under prefers-contrast — move icon weight by an amount that depends
     on where the icon happens to be rendered. UNITLESS deliberately: inside a viewBox `1.75` and
     `1.75px` render identically, and the bare number is the honest spelling of a ratio. NAMED
     --icon-stroke to match Obsidian's native variable of the same name, so the vendored mapping in
     the theme reads as the identity it is.

     SIZE STEPS ARE CANDIDATE (digest #2 — Aaron's to tune), and one of them is TODAY'S SHIPPED VALUE
     rather than a proposal: --icon-md is `1em`, exactly what `.op-icon` already declares, so
     promoting the tier changes no render anywhere. --icon-sm / --icon-lg have no consumer yet and are
     declared because the tier is the point — a step nobody can reach is a step that gets re-guessed,
     which is the --stroke-* argument verbatim.

     THE FLOOR IS DERIVED, NOT CHOSEN: 14px. Below it the stroke goes sub-pixel — 24 ÷ 1.75 = 13.71px
     is the exact crossing, and 1.75 × 14 ÷ 24 = 1.02 device px is the first integer-clearing box — and
     a sub-pixel stroke renders as a grey smudge rather than a line. RULE: below the floor, DROP the
     icon; never shrink it. THE LIVE DEFECT THIS NAMES, unfixed here on purpose: `.op-icon` at `1em`
     beside a --text-mono label (.78rem = 12.48px) resolves to 0.910 device px, already under the floor
     on shipped chrome. Correcting that instance is a visible render change on a shipped surface and is
     Aaron's call (digest #2); this tier's job is to make the floor sayable, not to spend it. */
  --icon-stroke:1.75;  /* ratio on the 24-unit viewBox — NOT a px length. Do not alias --stroke-*. */
  --icon-sm:16px;      /* CANDIDATE · compact control glyph — no consumer yet */
  --icon-md:1em;       /* the inline step: tracks its label. TODAY'S shipped `.op-icon` value. */
  --icon-lg:24px;      /* CANDIDATE · 1:1 with the source grid — no consumer yet */
  /* ── 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;
}

/* ═══ the UA-palette declaration — `color-scheme`, bound to the theme (2026-08-20, step a04b8e) ═══
   THE DEFECT THIS CLOSES IS AN ABSENCE, WHICH IS WHY NO GATE COULD SEE IT. Until this line the
   design system declared `color-scheme` NOWHERE, so every surface a UA paints for itself — a focus
   ring on an element outside our own focus floor, a caret, in-field selection, a scrollbar inside a
   control, the platform password-reveal affordance, an autofill background — came from the browser's
   LIGHT-mode defaults, on both themes. `brand.css`'s own link-floor header already diagnoses this in
   these words (§ Actions, D1: "no color-scheme is declared, so the UA picks its light-mode blue"),
   and that instance SHIPPED on a client surface. This is the same root cause, declared once.

   BOUND TO THE THEME, NEVER CONSTANT. The repo's other declarations are all hardcoded
   `:root{color-scheme:dark}` in field spikes and prototypes; copying that value here would break the
   co-equal-light guardrail (digest #1) by telling the UA the system is dark-only. Aurora IS `:root`
   and Feather IS `[data-theme="feather"]`, so the polarity is read off the theme attribute rather
   than assumed. `brand.js` also writes `data-theme="aurora"` explicitly; `:root` covers both that and
   the no-attribute default.

   MEASURED, not argued: with `color-scheme:dark` on Aurora the UA focus ring on a bare <summary>
   moves from 3.23:1 to 11.09:1 against `--ground` (Playwright, Chromium + Chrome, 2026-08-20).

   PLACED HERE, AFTER BOTH THEME BLOCKS, DELIBERATELY. Four checkers parse the theme blocks by
   locating the FIRST `:root` / `[data-theme="feather"]` in this file (qa/check.mjs's cssBlock walks
   brace depth from it; proof-surface/verify.mjs matches `[\s\S]*?\n\}`). A one-line `:root` rule
   ABOVE the token block would hand cssBlock a one-declaration block, and theme-parity would then
   compare two empty token sets and PASS OVER NOTHING — the vacuous pass this district has now caught
   three times. Below both blocks, every parser still finds what it is looking for.
   Pinned by `color-scheme-themed` (qa/check.mjs), planted-violation proven both directions. */
:root{color-scheme:dark}
[data-theme="feather"]{color-scheme:light}

*{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth}
/* ── the body size (T13, set 2026-08-20) ──
   `var(--text-body)`. Not a clamp, and deliberately not an `18px` literal.

   WAS `clamp(15px,1.05vw,17px)` — a floor a full 1.2 grid step BELOW this scale's own
   18px anchor, so inherited running prose rendered off-scale at every width up to
   ~1429px and never reached the anchor at all (it ceilings at 17px from ~1619px).
   MEASURED, not argued: the 66ch prose column ran 659.3px against `.lede`'s 794.1px —
   a 134.8px disagreement between two `--measure-*` tokens that are each correct in
   isolation, because `ch` is contingent on the size it is measured against.

   SET BY AARON, on a rendered side-by-side at the real breakpoints in both themes,
   against his own stated prior for something smaller: "18px feels the best both on my
   large screen and my laptop … that surprises me." A CANDIDATE dimensional value is his
   production role (like the --pr-* hexes); this rule records the answer, it does not
   make it. Do not retune it here.

   IT IS `rem`, AND THAT IS THE HALF A px LITERAL WOULD SILENTLY DROP. `html` declares no
   font-size, so --text-body (1.125rem) computes to exactly the 18px he picked AND tracks
   a reader's own root-size preference — "mostly i just like the ability to scale while
   maintaining hierarchy, rhythm, proportion". An `18px` literal renders byte-identical
   today and abandons the property he chose the value for.

   DO NOT RE-CLAMP THIS RULE. Raising only the old floor gives clamp(18px,1.05vw,17px),
   whose minimum EXCEEDS its maximum: CSS returns the MINIMUM, so the preferred and the
   ceiling become dead code that still reads as a live responsive rule. Verified in
   Chromium at eleven widths, 360→2560 — 18px at every one, the 17px ceiling never
   reached. The responsiveness a body clamp was reaching for belongs to the root size,
   which this form already honours. Pinned by `body-size-is-token` (qa/check.mjs); the
   retired string is no longer allowlisted in verify.mjs's CLAMP_OK, so it cannot return
   anywhere in the DS without the raw-dimension gate seeing it. */
body{
  background:var(--ground); color:var(--ink);
  font-family:var(--font-text);
  font-size:var(--text-body); 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}
/* LINK-USABLE BY DECLARATION (T1 · Steward, slot 7b · 2026-08-19) — the .btn § 7.2 shape, one
   axis over. The lockup is a surface's outbound peer edge, so <a class="brandmark"> is a real
   composition; it was not one, because the link floor below would paint a --muted prose underline
   under the WORDMARK HALF ONLY. The glyph is a flex item (blockified, display:block) and takes no
   decoration line — measured, not argued — so the floor SPLITS the lockup at rest, and the whole
   point of masking the mark with background:currentColor is that the two halves are one ink.
   So the resting decoration-color is transparent and NOT text-decoration:none: `none` would also
   kill the floor's own a:hover/a:focus-visible strengthening, which is the cue this needs. At
   (0,1,0) this loses to a:hover (0,1,1) by construction, so hover repaints the line currentColor
   with no rule of its own, and :focus-visible still draws the ring.
   BLAST RADIUS IS EXACTLY ONE CASE — a non-anchor .brandmark has no decoration line to color, and
   renders byte-identical to the shipped form (verified on a real compositor, both themes).
   Refused: bare composition (splits the lockup); a declared variant (the primitive has exactly one
   form, so a variant axis with one member is indirection without information — the --gap-* shape). */
.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);text-decoration-color:transparent}
/* 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}

/* ═══════════════════════════════════════════════════════════════════════════════════════════
   PROMOTED FROM `proof-surface/proof-page.css` 2026-08-20 (step a04b8e, Design System Steward).
   Both registers arrived here from a STAGED promotion, not a fresh placement decision: T1/T2 were
   walked at `steward-ruling-cc-front.md` §3.3+§5, both passed for brand core, and the sheet's own
   header recorded the verdict with a named trigger — "the first non-proof Corvus surface needing a
   sub-display heading, OR a third consumer, whichever comes first." That trigger has FIRED. Siting
   them one tier low with the promotion recorded was the honest interim; leaving them there once a
   non-proof surface needs them is the STRANDING direction CODIFICATION.md names, and the two
   alternatives were both refused with reasons on the record — linking a district sheet from a
   surface whose premise is that the district is refused BY CONSTRUCTION, or a second copy of one
   rule set in two per-surface sheets, which is the defect proof-page.css was created to end.

   THE NAMES DO NOT CHANGE. `page-` reads as page-level composition, which is what these are; it is
   not a namespace claim, and it is not in any gate's PREFIXES list. A rename costs a five-place
   unwind plus an alias trail, and this district has twice chosen an imperfect name over that price
   (`pr-claim-status`, `pr-question`). The `subhead`-not-`heading` reason travels with the primitive
   and is STRONGER here, not weaker: `.page-head` is a real class and a prefix of `page-heading`.

   THE CONVERGENCE OBLIGATION RIDES ALONG, UNCHANGED. `.cc-beat-heading` / `.cc-beat-prose` are
   still a second definition of these shapes and still converge at the cc-offer depth re-cut, with
   the absorption note intact: margins do not collapse inside a flex container, so that layout must
   drop its now-redundant gap at the seam or the beats double-space. The values were chosen to make
   that absorption exact. Trigger unchanged; a promotion does not discharge it.
   Every declaration below is carried across BYTE-FOR-BYTE. Nothing is retuned in a move.
   ═══════════════════════════════════════════════════════════════════════════════════════════ */
/* ── the sub-display heading register ────────────────────────────────
   Brand core's ladder runs h1/.h1 (--text-display, 16ch) → .h2
   (--text-h2, 17ch) → nothing. `.panel h3` is the right tier scoped to
   the wrong place. A section heading of sentence length has no carrier.

   NAMED `subhead`, NOT `heading`, deliberately: `.page-head` is a real
   class in this same file and is a PREFIX of `page-heading`, so a
   truncated typo would land silently on the head band. `subhead` has no
   such truncation path.

   30ch and 40ch are display BALANCE caps, not reading measures — they
   bound the wrap of a short display line, and the empirical 45–75ch
   reading band does not govern them. That is why they are raw `ch` named
   in verify.mjs's gate-5 allowlist rather than folded into --measure-*:
   folding them in would imply the reading band governs them.
     · 30ch is `.cc-beat-heading`'s value, carried across for a 2–6-word
       heading.
     · --wide is the ONE difference that survives, and it survives because
       it has a recorded reason: the CC front page's headings are full
       questions of ~45 characters. At 30ch a 31–40-character question is
       forced to break; 40ch lets it hold one line and breaks the longer
       ones into two balanced lines. 40 sits below the reading band's 45ch
       floor by construction, so the cap cannot be misread as a measure.
   Carried across as-is: the promoted shape sets no `text-wrap:balance`,
   unlike brand core's h1/.h2/.catch caps. Adding it is a Steward call,
   not a promotion's. ── */
.page-subhead{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);max-width:30ch;
  /* The Steward call the promotion note above left open, made 2026-08-09 when a real
     heading fired the trigger: a 41ch heading against the 40ch --wide cap breaks with a
     two-word orphan line. Balance matches brand core's own display caps (h1/.h2/.catch). */
  text-wrap:balance;
  /* THE SPACING HALF (D2, 2026-08-09). The register declared type and no spacing relationship
     to what follows — the half of a heading register that does the visible work — because the
     donor's spacing lived in `.cc-beat`'s flex gap (see the header block). The global reset
     zeroes h2 margins, so the subhead sat FLUSH against the panel/prose it heads.
     --space-5 is the donor's observed heading→content rhythm, carried with its reason; on the
     heading rather than the follower because a heading's followers vary (prose, panel, list)
     and each would otherwise re-derive the gap — the `.label` / `.panel h3` precedent, not
     the `.terms`/.stat-row follower-carries-margin one, which breaks for first-child panels. */
  margin-bottom:var(--space-5)}
.page-subhead--wide{max-width:40ch}

/* ── the reading-prose register ──────────────────────────────────────
   The page's running-prose block: capped, reading leading, --ink-2. It
   exists because brand core caps prose measure on exactly ONE selector
   (`.compare-note`) and a bare <p> in `.page` runs to ~130 characters.

   --ink-2 and the cap are both load-bearing INSIDE a panel: `.panel p`
   is --muted with no leading token and no cap, which the sibling surface
   already ruled a reading-comfort defect for multi-sentence bodies
   (Steward F4) — right for a twenty-word feature card, wrong for a
   multi-paragraph argument. This sheet loads AFTER brand.css and the two
   selectors are equal specificity, so `.page-prose p` wins inside a panel
   by source order. That ordering is the mechanism, not an accident. ── */
.page-prose{max-width:var(--measure-prose);display:flex;flex-direction:column;gap:var(--space-4)}
/* THE PANEL COMPOUND IS THE PROMOTION'S ONE AUTHORED CHANGE, AND IT REPLACES A MECHANISM THE MOVE
   BROKE. In `proof-page.css` the register beat `.panel p` — equal specificity — purely by SOURCE
   ORDER, because that sheet loaded after brand.css; the file's own header called that ordering "the
   mechanism, not an accident". Inside one stylesheet the order inverts: `.panel p` is declared ~300
   lines further down, so it won. MEASURED, not deduced — a paragraph inside a panel came back
   rgb(155,150,168) (--muted) against rgb(195,190,208) (--ink-2) outside one, which is exactly the
   reading-comfort defect this register was promoted to fix, silently reintroduced by moving it.
   Restated as SPECIFICITY instead of position: `.panel .page-prose p` is (0,2,1) and cannot be
   out-ordered. A cross-file ordering guarantee does not survive a move into one file, and it is the
   kind of guarantee that fails without any gate noticing, which is why the fix is the selector
   rather than a rule about where to paste. Pinned by `prose-register-beats-panel` (qa/check.mjs). */
.page-prose p,.panel .page-prose p{font-family:var(--font-text);font-size:var(--text-body);
  line-height:var(--leading-relaxed);color:var(--ink-2);max-width:var(--measure-prose)}
/* List rows are subordinate content and read at the prose register, not above it.
   Unstyled, an <li> inherits --ink and renders BRIGHTER than the paragraph it
   details — the ink inversion the Stage-8 pass named (R3, 2026-08-09). Scoped to
   .page-prose so link lists composed OUTSIDE the prose register (the depth maps,
   where brighter anchor rows are correct) stay untouched. */
.page-prose li,.panel .page-prose li{font-family:var(--font-text);font-size:var(--text-body);
  line-height:var(--leading-relaxed);color:var(--ink-2);max-width:var(--measure-prose)}
/* THE FLOW HALF (D2 sibling, 2026-08-09): a prose block composed after anything must space
   itself from it — on the donor surface `.cc-beat`'s flex gap did this; in bare flow nothing
   did, and `.lede + .page-prose` rendered at 0px. `* + ` scopes the margin to non-first
   position, so prose that OPENS a container (the panel case, where it is the only child)
   stays flush against the panel's own padding. Adjacent block margins collapse, so after a
   `.page-subhead` (margin-bottom --space-5) the seam resolves to --space-5, not the sum. */
* + .page-prose{margin-top:var(--space-4)}


/* ── 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)}
/* .terms--readout — the modifier for COMPACT COMPONENT READOUTS: a terms list inside a
   card, region, or wait card — not an offer block on a page. The base register is
   page-sized (a --space-8 top margin, enclosing rules, --space-4 rows) because an offer
   list is a document section; a readout is a component's dense read, so this modifier
   zeroes the page rhythm and tightens the rows. Promoted from the operator district
   2026-08-17 (D-12 steward ruling): the shape had been authored once as part of
   `.op-readout` and RE-DERIVED byte-for-byte by a second consumer (the permission wait
   card) that could not compose `.op-readout` without claiming provenance semantics it
   does not have — two copies of one register in two repos is the drift this file's
   canon-home rule exists to kill. Placement, not count: a compact key/value list is
   legible on any surface that renders `.terms`, so nothing about it dies outside the
   operator shell. The district's `.op-readout` keeps only what DOES die outside the
   shell: the value-leading inversion and the closed provenance vocabulary.
   NO inter-row rule: a readout's rows are ONE reading of one thing, and a border per
   row makes a four-line glance read as a four-row table. NO enclosing rules: those are
   the offer list's ("what is offered" needs a stated boundary; a component readout has
   its component). Converged 2026-08-17 — the plan readout had kept the enclosing rules
   with no reason on the record; the difference did not survive (case law: only a
   difference with a recorded reason does). Flagged to Aaron: the plan readout drops its
   enclosing hairlines when the surface next re-vendors. */
.terms--readout{margin-top:0;border-top:0;border-bottom:0}
.terms--readout .terms-row{gap:var(--space-2);padding:var(--space-1) 0}
.terms--readout .terms-row + .terms-row{border-top:0}
/* ABSENCE RENDERS AS ABSENCE — on ANY terms list. `no criteria` must not look like
   `0 of 4`: one is a gap in the record and the other is arithmetic. An attribute, not a
   class, so a state does not widen the class surface. Promoted 2026-08-17 with the
   readout register — both prior holders (`.op-readout` in the district, the permission
   card's consumer re-derivation) carried this pair of declarations verbatim, one of them
   with a comment apologising that canon's expression "is not ours to author." Now it is
   nobody's to re-derive.

   SCOPED TO `.terms` ON 2026-08-18 BECAUSE THE PROMOTION HAD NOT ACTUALLY REACHED
   "NOBODY'S TO RE-DERIVE" — IT HAD ONLY MOVED HOUSE. At `.terms-val[data-absent]` this
   rule sits at 0,0,2,0, and brand core is loaded FIRST by construction, so it loses every
   specificity TIE to a consumer. `.op-readout .terms-val{color:var(--op-ink)}` is also
   0,0,2,0 and legitimately raises the readout's value to full ink — a correct district
   rule — so inside `.op-readout` the absent value rendered ITALIC AT FULL INK: half the
   channel, and the half that carries at a glance. Measured on a compositor, not inferred:
   colour rgb(237,235,242) on both the absent and the present value, `colourDiffers:false`
   with `styleDiffers:true`. 100 rows across 10 built pages.

   THE BAND, stated so the next state rule does not have to rediscover it. A consumer
   restyles a brand-core element in one of two forms: a CONSUMER CLASS ON THE SAME ELEMENT
   (`.live-pending-val`, 0,0,1,0 — the form the permission card uses and canon prefers) or
   a DESCENDANT selector (`.op-readout .terms-val`, 0,0,2,0 — the form `brand-canon-home`
   already ledgers as a G2 offence). So base styling occupies 0,0,1,0..0,0,2,0, and a
   brand-core STATE must sit ABOVE that band or it is decided by file order, which is not
   a design decision at all. `.terms` is the qualifier because it costs nothing: a
   `.terms-val` is a `<dd>` inside a `.terms-row` inside a `.terms` by this primitive's own
   contract, so the precondition is already guaranteed and the selector reads as a
   statement rather than a specificity trick.

   WHAT THIS DELIBERATELY CLOSES, named rather than discovered later: a consumer can no
   longer re-tone absence from a same-element compound (`.live-pending-val[data-absent]`,
   0,0,2,0). That is the intent — this channel is canon's — but a consumer with a real
   need for a different absence tone should move `--muted` or raise it with the Steward,
   NOT out-specify canon. THE CEILING IS NOT AN ARMS RACE: 0,0,3,0 clears the observed
   band and the SPECIMEN is what keeps it honest — `runReadouts` asserts colour AND style
   as a conjunction with a planted-violation proof (`--plant=inkwin`), so the next breach
   fails loudly instead of rendering at half strength. Ruled by Aaron 2026-08-18; record:
   workflows/ui-development/engagements/operator-surface/review-steward-absence-channel-2026-08-18.md */
.terms .terms-val[data-absent]{font-style:italic;color:var(--muted)}
@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)}
}

/* ── .warrant — what established the line beside it ──
   A mark naming what established the statement it sits with, at three standings: GATE (a check
   that re-runs) · HAND (checked once, by a person, at a recorded date) · ASSERTED (stated, not
   checked). Placement walk + the refusal that raised it: PRIMITIVE-INDEX.md § .warrant.

   FOUR CONTRACT DECISIONS, each against a real alternative:

   · THE STANDING IS AN ATTRIBUTE, NOT A MODIFIER CLASS. `data-standing` makes the value set
     enumerable — a gate can assert three distinct treatments and an author can be told which
     values exist. Three modifier classes make the set open, and an author who omits one gets
     silence rather than an error.
   · THE BASE RULE IS THE INVALID STATE. A .warrant with no standing, or an unrecognised one,
     renders the --warn dashed hole. Invalid BY CONSTRUCTION rather than by a gate — the
     `pr-figure` unsourced-figure shape, and the reason is that this rule survives transplant: a
     warrant naming no standing is not a warrant on any surface, which is what made it brand core.
   · THE LOWEST STANDING RENDERS VISIBLY, NEVER AS THE ABSENCE OF A MARK. `asserted` takes the
     quietest ink step and keeps its tick and its word. A surface whose weakest line renders
     identically to its strongest is flattering itself, and a reader who finds one flattened line
     discounts all of them. Pinned by `warrant-tier-visible` (proof-surface/verify.mjs).
   · WEIGHT BEFORE WORD, BUT NEVER WEIGHT ALONE. The scan channel is the ink step plus the tick's
     fill, so a reader calibrates a chain without reading five labels (the ITD's constraint). The
     word rides with it at --text-micro in the mono label voice ANYWAY, because an ink-only
     encoding is colour as the sole carrier — which this system already refuses at
     § Type-role assignment and in the district's trace-row rule, and which no legend repairs for
     a screen reader. Recorded as a deliberate correction of the 7a constraint, not a drift.

   THE TREATMENT IS CANDIDATE (digest #2) — the ink steps and the 7px tick are snapped from the
   existing ladder and are Aaron's to tune. The CONTRACT above is not candidate. */
/* The BASE rule is the invalid state — no standing, or one nobody declared: a dashed --warn hole
   that names its own defect, so the failure is legible on the render and not only in a gate's log. */
.warrant{display:inline-flex;align-items:center;gap:var(--space-2);
  font-family:var(--font-mono);font-size:var(--text-micro);letter-spacing:var(--track-mono);
  text-transform:uppercase;line-height:var(--leading-snug);color:var(--warn);
  border-bottom:1px dashed var(--warn);padding-bottom:var(--space-1)}
/* The tick: the scan-layer channel. Fill state is structural, so the ladder does not rest on hue. */
.warrant::before{content:"";width:7px;height:7px;flex:none;border-radius:50%;
  border:1px solid currentColor;background:currentColor}
.warrant::after{content:"no standing declared"}
.warrant[data-standing="gate"],
.warrant[data-standing="hand"],
.warrant[data-standing="asserted"]{border-bottom:0;padding-bottom:0}
.warrant[data-standing="gate"]::after,
.warrant[data-standing="hand"]::after,
.warrant[data-standing="asserted"]::after{content:none}
.warrant[data-standing="gate"]{color:var(--ink)}
.warrant[data-standing="hand"]{color:var(--ink-2)}
.warrant[data-standing="hand"]::before{background:linear-gradient(90deg,currentColor 50%,transparent 50%)}
/* The quietest step still carries a tick and a word — the visible-lowest-standing rule, in CSS. */
.warrant[data-standing="asserted"]{color:var(--muted)}
.warrant[data-standing="asserted"]::before{background:transparent}

/* ── `.transcript` — a machine speaking (2026-08-20, step a04b8e) ─────────────────────────────
   Contract ratified 2026-08-19 and deliberately unformed; the form landed here when the Visual
   Designer's read supplied the one thing the deferral turned on — what makes text read as EMITTED
   rather than TYPED. The answer, and it is counter-intuitive inside this system: **the register is
   carried by what is WITHHELD.** Corvus wants curly quotes, em dashes, ligatures, balanced display
   wrapping. A machine produces none of them, so every one of those refinements appearing inside a
   transcript is the clearest possible tell that a person typed it — which is precisely the failure
   the contract names when it says a transcript that reads as authored is worth nothing.

   THE OPT-OUT IS WRITTEN AGAINST THE FALLBACK STACK, NOT AGAINST SPACE MONO, and that is the
   load-bearing half. `--font-mono` falls back through Menlo, Consolas and Liberation Mono, several
   of which ship contextual alternates that would quietly prettify `!=` or `->`. A degraded font
   stack must degrade to a PLAINER machine, never to a prettier one.

   `--track-normal`, NOT `--track-mono`. The district's mono labels track at .06em because tracking
   opens a LABEL for scanning. A terminal has no tracking, and this deliberate divergence from every
   other mono block in the system is one of the two or three properties doing the register's work.

   ONE INK, ONE WEIGHT, EVERY LINE — the contract's hardest clause answered by refusal. The block
   must render a line that reads as failure WITHOUT a fault register, and it does: it reads as
   failure because it SAYS FAIL. So no per-line or per-token colour, no bold on the failing line, no
   --error / --warn / --success anywhere in the subtree, and no --c1..--c5. The ramp ban is stated
   and gated; this one is MORE likely to be violated, because "just make the FAIL line red" reads as
   helpfulness and is exactly the move that asserts the output is source code — the genre with no
   credibility left. `--ink-2` is the lifted secondary ink for text --muted leaves under-legible;
   --muted would be wrong here because it is the APPARATUS register and a transcript is the
   evidence, not the apparatus around it.

   THE CAP BOUNDS THE CONTAINER; THE CONTENT IS AUTHORED TO FIT; A LONG LINE OVERFLOWS RATHER THAN
   WRAPS. That is the walked-decision lesson applied to itself — a transcript that wraps has HIDDEN
   the violation, one that overflows has REVEALED it, and the surface this primitive was built for
   argues that small text had long lines. `scrollbar-gutter:stable` is declared here and not at the
   foundation for the reason the scrollbar comment above gives: a reserved gutter costs ~1.10ch, so
   surfaces with CONTRACTUAL measures declare it themselves. This block has one.

   LONG WITHOUT DOMINATING IS A BOUNDED SCROLL REGION. A fade was refused (it hides content with no
   affordance saying more exists — a half-state promise, and adjacent to `nothing glows`); a nested
   <details> was refused on contract (the block is already reached through one disclosure, and a
   second makes the artifact cost two interactions). The scrollbar is the affordance, `html` already
   themes it in both themes, and the scrollbar's PRESENCE is itself part of the register — a real
   verification run is longer than its frame, and a block that fits exactly would read as curated.

   THE CONTAINMENT EDGE IS `--hairline`, WHICH IS THE OPPOSITE OF THE CONTROL FLOOR'S ANSWER, AND
   THE DIFFERENCE IS THE POINT. A transcript is not an interactive control, so 1.4.11 does not reach
   it and the recessive apparatus register is correct. A field is a control and must be FOUND in
   order to be acted on. Same two candidate carriers, opposite verdicts, one distinguishing question.
   Pinned by `transcript-no-ramp` and `transcript-opt-out` (qa/check.mjs). ── */
.transcript{font-family:var(--font-mono);font-size:var(--text-mono);
  line-height:var(--leading-snug);letter-spacing:var(--track-normal);
  color:var(--ink-2);background:var(--inset);
  border:var(--stroke-hair) solid var(--hairline);border-radius:var(--radius-sm);
  padding:var(--space-4);max-width:var(--measure-prose);
  white-space:pre;hyphens:none;
  font-variant-ligatures:none;font-feature-settings:"liga" 0,"clig" 0,"calt" 0;
  font-variant-numeric:tabular-nums;
  scrollbar-gutter:stable;max-height:60vh;overflow:auto}

/* ── 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}

/* ── the control floor (2026-08-20, step a04b8e) — the link floor's sibling, one element class over
   ─────────────────────────────────────────────────────────────────────────────────────────────
   WHAT WAS MISSING, STATED AS THE ASYMMETRY THAT MAKES IT DIAGNOSABLE. The focus floor above has
   named `input,select,textarea` since it was written; brand.css declared ZERO resting rules for any
   of them. So the system had a FOCUS contract for form controls and no REGISTER for them — which is
   the exact shape of a floor authored from a rule rather than from a composition. A UA-default
   <input> on Aurora renders a white field with black text in the browser's system font on a
   #0F0D13 ground: not under-designed, a hole punched through the theme.

   IT IS A FLOOR, NOT A CLASS, AND THAT IS THE RULING. The gap analysis proposed `.field`; the name
   is refused and so is the shape. Refused as a NAME because `#field` is already a selector in this
   very file (the constellation-raven canvas) and "the Field" is a whole sibling effort
   (EFFORTS.md · `field/`, the field engine) — one word, two unrelated meanings, in one repo.
   Refused as a SHAPE for the stronger reason: a class must be composed, and an author who forgets
   it gets the UA's answer with no warning. That is precisely how D1 shipped UA-blue links on a
   client artifact, and the repair there was an element floor, not a better-named class. Same
   diagnosis, same altitude. A consumer that wants a different control treatment opts out by
   declaring, exactly as `.btn` opts out of the link floor.

   SCOPE IS TEXT ENTRY, AND `select` IS DELIBERATELY OUT. A select's UA internals — the listbox, the
   arrow, the option list — are not authorable at the level the rest of this floor is, so a
   half-styled select is worse than an honestly-UA one until someone does that pass. The focus floor
   covers select and this one does not; the difference is real (focus IS fully authorable on a
   select) and is written down rather than left to look like an oversight. The excluded input types
   are the ones with their own UA widget — checkbox, radio, range, color, file, and the button-like
   types — each of which wants its own treatment, not a text field's.

   THE BOUNDARY IS `--muted`, NOT `--hairline`, and the reason is already on this file's record.
   MEASURED (WCAG relative luminance, both themes, both plausible parent planes): the `--inset`
   plane step is 1.03:1 / 1.09:1 against --ground — imperceptible, not merely weak; `--hairline` is
   1.30:1 / 1.21:1 and is this system's deliberately-RECESSIVE apparatus register, as the link
   floor's own header says; `--rule-hover` is 4.02:1 on Aurora but 1.44:1 on Feather, so it is a
   boundary that exists in one theme and not the other — the co-equal-light guardrail refuses it.
   `--muted` is 6.73:1 / 5.98:1. A password field is the most followed-through control on any
   surface; it needs identification, and only one candidate supplies it. Hover therefore moves
   toward INK (`--ink-2`, 10.22:1 / 10.60:1), not toward --rule-hover, which would be a downgrade
   in both themes.
   THE PLANE IS STILL DECLARED, and both facts hold at once: the plane carries the THESIS (digest #1
   — depth is plane value, and a field is the canonical recessed thing, exactly as `.panel` pairs a
   plane WITH a border), the rule carries the IDENTIFICATION. The plane step being inert today is a
   CANDIDATE-value observation, proposed with the type-scale family and not corrected here.

   THE FAULT STATE RIDES `[aria-invalid="true"]` — THE ACCESSIBILITY ATTRIBUTE IS THE TRIGGER.
   This is the M2 in this rule: an author cannot render the fault look without also announcing the
   fault to a screen reader, and cannot announce it without the look. A `.is-invalid`-style class
   would have let the two drift apart silently, which is the half-state promise inverted.
   THREE CHANNELS, TWO ACHROMATIC, so the distinction survives a greyscale render: the message
   element's PRESENCE, the rule's WEIGHT going hair → bold, and only then the --error hue.
   `--error` IS A NON-TEXT TOKEN AND THIS FLOOR IS WHAT ASSIGNS IT THAT ROLE. Measured at 6.10:1 on
   Aurora ground and 4.08:1 on Feather — below AA for normal text on paper. `--warn` took exactly
   this repair (§ tokens, "darkened #C7871A→#8A5A0F for the WCAG AA floor: it is TEXT"); --error
   never did, because nothing had rendered it as text. The alternative — retune Feather's --error —
   is a CANDIDATE value and Aaron's, and it stays available. It is not reached for here because
   assigning the token ONE role (a 3:1 non-text boundary) is gateable, while a dual-role token
   carries a 4.5:1 obligation nobody can enforce per use. Error TEXT rides --ink (16.23:1).
   Pinned by `control-floor-fault-achromatic` and `error-token-not-text` (qa/check.mjs).

   AUTOFILL IS THE COMMON CASE ON A PASSWORD FIELD, NOT THE EDGE CASE. Chromium paints
   `:-webkit-autofill` with a hardcoded background that an authored `background` does not override;
   the only reliable suppression is a large zero-offset INSET shadow in the intended plane colour.
   That is a FILL, not a cast — the 2026-08-02 slider-thumb ruling established the distinction in
   this system for this reason: `nothing floats` governs casts, and an inset shadow at zero offset
   and zero blur casts nothing. `color-scheme` (declared above) governs which hardcoded value the
   engine reaches for in the first place, which is why it lands before this rule rather than with it.
   ── */
/* THE EXCLUSION LIST IS WRAPPED IN `:where()`, AND THAT IS A FIX RATHER THAN A STYLE. Written as a
   chain of nine bare `:not()`s the selector weighed (0,9,1) — each :not() contributes its argument's
   weight — so it OUT-SPECIFIED its own `[aria-invalid="true"]` and `:hover` rules and the fault
   state silently never rendered. MEASURED on a compositor, not reasoned: the invalid field came back
   byte-identical to the resting one. `:where()` contributes zero, so this floor now weighs (0,0,1) —
   plain element specificity, the same as the link floor above — and every state rule below it wins
   the way a state rule must. A rule that looks like enforcement and is not is worse than no rule. */
input:where(:not([type=checkbox],[type=radio],[type=range],[type=color],[type=file],[type=submit],[type=button],[type=reset],[type=image])),
textarea{
  background:var(--inset);color:var(--ink);
  border:var(--stroke-hair) solid var(--muted);border-radius:var(--radius-sm);
  font-family:var(--font-text);font-size:var(--text-body);line-height:var(--leading-relaxed);
  padding:var(--space-3) var(--space-4);
  /* THE CAP WAS NOT AUTHORED — `prose-measure-coverage` (I10 gate 6) FAILED this rule on its first
     run and it was right to. Reading size plus prose leading is a reading surface, and an uncapped
     <textarea> is the smallest-text-longest-lines defect with a text cursor in it. It is a MAX, so
     a surface still sets its own width and is bounded by the tier rather than by the viewport.
     Recorded rather than quietly satisfied: a gate this system already owned caught a defect in a
     rule authored the same hour, which is the payoff a tier gate is for. */
  max-width:var(--measure-prose);
  transition:border-color var(--dur-slow) var(--ease)}
input::placeholder,textarea::placeholder{color:var(--muted);opacity:1}
input:hover,textarea:hover{border-color:var(--ink-2)}
/* THE ACHROMATIC CHANNEL IS A DOUBLED EDGE, NOT A HEAVIER ONE, AND THAT IS A MEASURED CORRECTION.
   The specified channel was `border-width: --stroke-hair -> --stroke-bold`. MEASURED in Chromium at
   deviceScaleFactor 1 AND 2: a 1.5px border computes AND renders as 1px — box height delta 0.000,
   identical to the resting field — and the same holds for outline-width. So `--stroke-bold` is
   indistinguishable from `--stroke-hair` at either property, and a fault state carried by that step
   alone would have been an affordance with no contract behind it: exactly the half-state promise
   this system refuses, shipped by the seat that owns the rule.
   The edge is DOUBLED instead: a zero-offset, zero-blur inset ring at --stroke-hair inside the
   border, so the rendered edge goes 1px -> 2px in integer device pixels. It survives a greyscale
   render, which is what makes the no-hue-alone assertion provable rather than hoped-for. The
   `--stroke-bold` declaration is KEPT because it is the correct expression of the intent and it
   costs nothing today; if --stroke-bold is retuned to an integer the two channels reinforce.
   `box-shadow` here is a FILL, not a cast — the 2026-08-02 slider-thumb ruling settled that shape:
   `nothing floats` governs casts, and zero offset with zero blur casts nothing.
   THE TOKEN DEFECT IS PROPOSED, NOT CORRECTED (digest #2): --stroke-bold:1.5px cannot render as a
   stroke, which also makes operator.css's ten prefers-contrast thickenings a no-op. That is a
   CANDIDATE dimensional value and Aaron's — decision row T15. */
input[aria-invalid="true"],textarea[aria-invalid="true"]{
  border-width:var(--stroke-bold);border-color:var(--error);
  box-shadow:inset 0 0 0 var(--stroke-hair) var(--error)}
/* the autofill fill — see the header. -webkit- prefixed because the pseudo-class is, and the
   text-fill-color companion is required or Chromium keeps its own ink over our plane. */
input:-webkit-autofill,input:-webkit-autofill:hover,input:-webkit-autofill:focus{
  box-shadow:inset 0 0 0 40rem var(--inset);-webkit-text-fill-color:var(--ink);caret-color:var(--ink)}

.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}
/* ── `.disclosure` — the evidence announcement (2026-08-20, step a04b8e) ──────────────────────
   ONE CLASS, TWO HOSTS (<summary> | <a>), ZERO VARIANTS — and the zero is the ruling, not an
   economy. The two behaviours it announces are *expand* (the material renders in place) and
   *depart* (the material is an inspectable source elsewhere), and the channel that separates them
   is THE VERB, which is content, not CSS. "One element with a declared variant" was never a live
   option: `expand` is a <summary> inside <details> and `depart` is an <a>, so no single element is
   both. Every rendered property below is identical on both hosts BY CONSTRUCTION, which is what
   makes the contract's clause 4 (distinguishable before use) and clause 5 (one convention, reused
   identically) properties of this stylesheet rather than discipline an author must remember.

   THE LINK FLOOR IS RE-DECLARED HERE RATHER THAN INHERITED, AND THAT IS A DEFECT REPAIR. The floor
   above reaches <a> and does not reach <summary>, so without this the anchor arrived underlined and
   the summary arrived bare — an UNDECLARED SECOND CHANNEL doing the settled channel's job, and one
   that would have separated the two behaviours CORRECTLY BY ACCIDENT (underline reads as "you are
   leaving"). An accidental cue that happens to be right is harder to find than one that is wrong.
   Stripping the anchor's underline instead would re-create D1, the shipped defect the floor exists
   to prevent. `.btn` is the precedent for a declared opt-out and it opts out because it has a
   border and a plane instead; this has neither.

   `--font-mono` at `--text-mono`, NOT `--text-micro`, and refusing the district's own value is the
   deliberate part. --text-micro is the fine-mono-label tier — the register for apparatus a reader
   may IGNORE. This control is the only door to the disclosure layer; an announcement a reader
   ignores has already failed. Sentence case or lower, never uppercase (digest #5: uppercase is a
   label register, never a navigation register — and `depart` literally navigates); a builder
   reaching for "mono label" types text-transform:uppercase by reflex, so it is refused by name.
   Weight 400: Space Mono ships 400/700 and 700 at 12.5px smears for emphasis this has not earned.

   NO RAMP, NO PILL, NO MARKER. `.link` is the rationed showcase register and a chain of five steps
   each carrying an announcement is precisely the "page of ramp underlines is chrome" case the
   thesis rations against. The district's hairline pill measures 1.25–1.30:1 against its plane —
   below 1.4.11's 3:1 for a control boundary, which the district gets away with because its pill is
   decorative and the text carries the affordance; rather than inherit a boundary that would have to
   be argued, the boundary is removed and the verb plus its underline is the affordance (both clear
   4.5:1: --muted is 6.73:1 / 5.98:1, --ink-2 9.88:1 at worst). The UA marker is suppressed on both
   vendor paths because a marker present on expand and absent on depart is a second channel.
   `display:inline`, not inline-flex: there is no marker to seat, and an inline run wraps with its
   container instead of overflowing it at narrow width.
   Pinned by `disclosure-one-channel` (qa/check.mjs) — the two hosts must render identically. ── */
.disclosure{font-family:var(--font-mono);font-size:var(--text-mono);
  letter-spacing:var(--track-mono);line-height:var(--leading-snug);
  color:var(--muted);cursor:pointer;display:inline;
  text-decoration:underline;text-decoration-thickness:var(--stroke-hair);
  text-decoration-color:var(--muted);text-underline-offset:2px;
  transition:color var(--dur-slow) var(--ease),text-decoration-color var(--dur-slow) var(--ease)}
summary.disclosure{list-style:none}
summary.disclosure::-webkit-details-marker{display:none}
.disclosure:hover,.disclosure:focus-visible{color:var(--ink-2);text-decoration-color:currentColor}
/* ── the focus floor — a visible ramp-violet ring, never removed ──
   TWO CORRECTIONS LANDED 2026-08-20 (step a04b8e), both measured on a compositor rather than
   reasoned from the cascade.

   1 · THE SELECTOR IS NO LONGER AN ENUMERATION. It read
   `:where(a,button,.btn,.toggle,input,select,textarea,[tabindex])`, and `summary` was not on it —
   so every native <details> disclosure in this repo (29 of them, across 5 SHIPPED district
   surfaces) fell through to the browser's own ring while every link and button beside it drew the
   violet one. That is the `b,strong` weight floor's lesson arriving a third time, and this file
   already states it in its own words: *a selector cannot opt out by omission, only by declaring.*
   An enumerated floor is a closed set whose miss is SILENT — the omitted element still renders, it
   just renders the UA's answer instead of the system's. Adding `summary` to the list (what both
   reading seats recommended) fixes the instance and leaves the mechanism, so the next natively
   focusable element the system meets — [contenteditable], <dialog>, <iframe>, a media control —
   repeats it. Dropping the list makes the failure IMPOSSIBLE rather than caught: M2 over M3, which
   is this district's stated order.
   SPECIFICITY IS UNCHANGED, which is what makes the widening safe: `:where(…)` contributes 0 and
   `:focus-visible` contributes (0,1,0), so the old rule and the bare pseudo-class weigh the same.
   A consumer that wants a different indicator still opts out by declaring, exactly as before.
   COVERAGE IS THE ONLY THING THAT MOVED, and only in one direction: `:focus-visible` fires when the
   UA judges an indicator warranted, so nothing that was previously un-ringed by design becomes
   ringed by accident. `[tabindex]` already matched `tabindex="-1"`, so programmatic-focus targets
   are no worse off than they were.

   2 · THE RULE NO LONGER SETS `border-radius`, and this was a live defect on every Corvus surface.
   `.toggle` declares `--radius-pill` at (0,1,0); this rule was ALSO (0,1,0) and later in the file,
   so it won — MEASURED: the theme toggle rests at 999px and snapped to 6px the moment a keyboard
   reader reached it. A focus indicator that changes the element's geometry is a shape jump, not an
   indicator. Outlines already follow the element's own border-radius in every current engine, so
   the declaration bought nothing and cost the pill. Pinned by `focus-floor-geometry` (qa/check.mjs).
   ── */
:focus-visible{outline:2px solid var(--c2);outline-offset:2px}

/* ── 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}
}
