/* ═══════════════════════════════════════════════════════════════════
   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).
   ═══════════════════════════════════════════════════════════════════ */

/* Self-hosted faces (e6f4a0): the brand's own + the --font-mono coverage faces. Relative to this sheet — a
   consumer that serves brand.css without its fonts/ directory degrades to the stacks' named fallbacks. */
@import url("fonts/faces.css");

@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.
     IT WAS SEEN BY EYE, 2026-09-19/20, and read as near-invisible: the turn-band render
     (turn-footer.md § Not reconciled) measured this half-step against --ground at reading distance
     and found it doing almost no work in Aurora — "the boundary is carried by the rule + the gap
     alone; it still counts, but the plane channel is doing almost nothing there." Aaron's redirect
     (batch-3 look 2, S2): "the stripe between turns one step stronger, dark theme only." Read here
     as ONE HALF-STEP MORE (the increment already in this token's own name, not a leap to --surface —
     merging the two would erase the band/plane distinction the token exists to carry): Aurora's dL
     .0116 doubles to dL .0231 (t .450 -> .902 on the ground->surface OKLab interpolation), landing
     one hex step below --surface at every channel — distinct, never equal. FEATHER IS HELD (Aaron's
     own word) — its dL stays .0117, UNTOUCHED below. CANDIDATE — the doubling is this seat's reading
     of "one step stronger", not a measured target; Aaron's eye on the re-render is what actually
     tests it (turns-are-countable-at-a-glance, wireframes/turn-footer.md). Derivation of record:
     operator-district/plane-ramp-rederivation.md; this retune: operator-district/PRIMITIVE-INDEX.md
     § THE TURN BAND. */
  --ground-lift:#14111A; /* CANDIDATE — Aurora only, S2 2026-09-20, dL .0231 from --ground (was .0116) */
  /* 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 — Aurora re-measured 2026-09-22 against the CURRENT
     ramp: ground 5.03 / band 4.86 / surface 4.82 / raised 4.53; Feather re-measured 2026-09-15 after
     its widen (see the Feather block): ground 4.86 / band 5.03 / surface 5.21 / raised 5.43.
     ⚠ THE AURORA ROW WAS ONE PLANE SHORT FOR EIGHT WEEKS, and the gap is the shape to watch rather
     than the number: this certification was verified 2026-07-29, --ground-lift landed 2026-07-31, and
     its Aurora value doubled again on 2026-09-20 (S2) — so a rung entered the ramp twice and the
     enumeration that certifies ink against planes trailed it both times, silently, because an
     enumeration says nothing about what it does not list. The band clears (4.86, +0.36), so nothing
     moves here; what changed is that the claim now covers the plane READ actually renders on. ADDING
     A PLANE RUNG OBLIGES A RE-MEASURE OF THIS LINE. Found by the 2026-09-22 plane-contrast sweep:
     workflows/ui-development/surfaces/operator-surface/steward-plane-contrast-2026-09-22.md.
     (Scope unchanged and still load-bearing: PLANES ONLY — the guarantee does not survive a TINT;
     operator-district/selection-scrollbar-and-tint-contrast.md § 4c/4d.)
     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 */
  /* --ink-tint — a neutral tint of the CURRENT ink: the host's own ink at a low mix of itself over whatever
     ground it sits on, so it steps away from the ground in both themes with one rule and carries no hue in
     either (rebuild 7b round 5, 2026-10-16, with `mark.found`). Brand core's name for the value the operator
     district already spends as --op-chip-tint; snapped VERBATIM from it, so nothing that adopts it moves.
     THEME-INVARIANT by construction: it names no themed input, and currentColor resolves per element at the
     use site. CANDIDATE 8%, Aaron's (digest #2). */
  --ink-tint:color-mix(in oklab,currentColor 8%,transparent); /* theme-invariant */
  /* ── 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
     RETUNED TO 40% — 2026-09-15, Aaron's, asked twice on the installed operator surface (09-14:
     "the selected text should have better contrast. suggest lighter purple? … make sure aurora is
     updated too"; 09-15: "still medium purple background with black text. insufficient contrast").
     The 3:1 separation floor was the wrong instrument for THIS fill: a luminance ratio counts a
     saturated violet on a neutral ground as barely-there while the eye reads the hue shift
     unmistakably — and the 72% that satisfied the ratio put --ink on a mid-lightness field, the one
     place no ink reads well. Text is what a selection exists to keep legible, so the text floor
     governs and the fill is as light as the hue still carries. Re-measured, same compositor probe
     (Lab/vault-extension/scratchpad/probe-select-fraction.mjs):
       Aurora  #42336B  separation 1.77:1  text 9.25:1
       Feather #BBB1EA  separation 1.77:1  text 9.15: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) 40%,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 */

  /* ── DATA-VIZ DISTRICT (dv-) token group — CANDIDATE, landed 2026-09-02 (Aaron approved
     at 30e9c4, no retune). Authored HERE once (source-of-truth invariant); dv.css composes
     only var(--dv-*) and authors zero hex, the --op-* discipline one district over.

     PURE ALIAS + DERIVATION LAYER: ZERO new base hexes. The categorical tier aliases ramp
     stops outright; the sequential tier is a color-mix of two already-themed primitives. So
     Feather comes free through the primitives' own remap and this group needs NO per-theme
     override at all — one fewer than --op-*, which still owes its ghost-alpha triple.

     CATEGORICAL — three stops, and the count is a measurement rather than a preference.
     All ten C(5,3) selections were scored in both themes against four floors (normal
     separation, deuteranopia, protanopia, chroma); exactly one clears all four. --c2/--c3
     collapse to 1.3 deltaE under deuteranopia, so every pair holding both is out first:
     five stops, three separable categorical slots. Reuse of a stop that already carries a
     chrome meaning is LEGAL by Aaron's D4 ruling (class-scoped, not global), which is what
     makes aliasing correct rather than merely convenient. Measurements + the acceptance
     test: dataviz-district/categorical-hue-candidates.md.

     TWO TIGHT MARGINS, APPROVED AS MEASURED — c1/c4 under deuteranopia at 6.3 (Aurora) /
     6.7 (Feather) against a 6.0 floor, and c4's Feather chroma at 0.101 against 0.10. A
     retune of --c1 or --c4 for reasons having nothing to do with data-viz can break a floor
     Aaron has approved, which is why dv-cat-separation is owed as a gate, not a note.

     SEQUENTIAL — magnitude, one hue's lightness steps. NOT the Interference Ramp: those are
     different objects sharing a word, and reading "the ramp is rationed" onto a 300-cell
     waffle would be correct-by-the-letter and wrong (DV-ESTABLISHMENT §3, encoding-contract
     §7.2). Derived toward --ground at the low end and --ink at the high end, so LOW VALUE
     SITS NEAR THE PAPER and high value sits far from it. The inversion between themes is
     therefore STRUCTURAL, not authored: Aurora runs dark->pale (OKLab L .225 -> .847),
     Feather runs pale->dark (.920 -> .396), because ground and ink swap. A copy-paste
     leaving both themes running the same direction is not expressible here. That is
     Contrast-Follows-The-Paper held by construction rather than by a gate.

     ABSENCE — an edge and no fill, deliberately. Absence-Is-Not-Zero requires the no-value
     mark to differ from a zero mark by a property OTHER than the magnitude channel; a fill
     token would supply exactly the affordance the principle refuses, so none exists.
     Derivations + the falsifiers: dataviz-district/DV-ESTABLISHMENT.md §3. */
  --dv-cat-1:var(--c1); --dv-cat-2:var(--c2); --dv-cat-3:var(--c4); /* theme-derived */
  --dv-seq-lo:color-mix(in oklab,var(--c4) 10%,var(--ground)); /* theme-derived */
  --dv-seq-hi:color-mix(in oklab,var(--c4) 55%,var(--ink)); /* theme-derived */
  /* e8cc52 (2026-09-29; PMO 2e9b9e94 + ab94c9d3, Aaron's direction e9250ba6) — CANDIDATE, in review.
     Absence's edge is the one mark of a no-value cell, so it takes the non-text floor (>= 3:1 vs the
     ground; WCAG 1.4.11): --muted-2 (the ramp's 4th legible rung, neutral) at 80%, measured 3.51:1
     Aurora / 3.31:1 Feather. A data cell's edge is a different job and keeps the old hairline value
     unchanged as --dv-cell-edge, so only absence moves. The track rises from --inset (1.03 / 1.09:1)
     to --muted-2 at 32%: 1.53:1 both themes, and the fill still reads >= 5.5:1 on it. */
  --dv-absent-edge:color-mix(in oklab,var(--muted-2) 80%,transparent); /* theme-derived */
  --dv-cell-edge:color-mix(in oklab,var(--ink) 16%,transparent); /* theme-derived */
  --dv-track:color-mix(in oklab,var(--muted-2) 32%,transparent); /* theme-derived */
  --op-rule:var(--hairline); --op-spine:var(--hairline); /* theme-derived */
  /* RECONCILED (S2, 2026-09-20): wireframes/turn-footer.md § Not mine, routed names "the rule's
     ink (D15's --ink-faint / --op-rule — the two names for one ruled ink are the Steward's to
     reconcile)". They are not two names for one ink — this line already says which: --op-rule IS
     D15's realized form ("the in-column divider D15 quieted", two sentences down), and --ink-faint
     is a DIFFERENT, sub-AA decorative role (--op-edge's, immediately below). The turn boundary's
     rule reads --op-rule; no new value, no rename — the ambiguity was in the wireframe's citation,
     not in canon. */
  /* --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).
     RETUNED 2026-09-29 (Aaron: "the border color to contrast less with its surface color so they
     stand out less"; his Figma pass, Corvus DS from-code 177:2166, set it to --hairline at 42%
     opacity), then dialled back up the same day ("the panes are barely visible … maybe not as
     contrasty as it was but not quite this flat"): --muted at 25% over the ground, ~1.25-1.6:1
     against the planes — about half of --ink-faint's 2.3-2.7:1, and one step above --op-rule's
     hairline, so the seam order edge > rule holds by value again (BAND 2/5 gates it; the full
     --hairline was tried first and collapsed the two). CANDIDATE — Aaron's value. */
  --op-edge:color-mix(in oklab,var(--muted) 25%,var(--ground)); /* 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-regular); --op-src-inferred-w:var(--stroke-regular); --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 */
  /* --op-on-focus — INK for a label set ON the --op-focus fill (e55ad7, 2026-09-29; PMO 1164d64e + 199a372a).
     The armed Send used --op-well, a GROUND token, as its label ink: the pair cleared AA by 0.11 in
     Feather (4.61:1, mark-contrast measured), but no pair table could see it, because nobody enumerates
     "a ground used as ink on one state". A role token names the relation instead. NO NEW VALUE: it
     aliases a plane per theme — the darkest in Aurora (--inset, 5.26:1 on --c2, unchanged) and the
     lightest in Feather (--raised #FFF, 5.62:1 on --c2) — so it is a real per-theme value and appears
     in BOTH blocks, no marker. Gate: op-no-ground-as-ink (qa/check.mjs) + the armed state in
     operator-district/mark-contrast.json. */
  --op-on-focus:var(--inset);
  /* --op-hover-tint — the ONE written exception to "hover is achromatic" (semantic-register § 2e,
     amended 2026-09-16): where the plane rung has no headroom — a hover inside an object that already
     rests on the ramp's ceiling, Feather's #FFF on #FFF — a hover may wear the focus hue at a fixed
     low mix. The rail tab is its first and only consumer. CANDIDATE 8%, Aaron's to tune (digest #2);
     --op-select-fill is the same idiom at 14%, so hover < selection in the one hue they share. */
  --op-hover-tint:color-mix(in oklab,var(--c2) 8%,transparent); /* theme-derived */
  /* --op-chip-tint / --op-chip-tint-hover — op-link-chip's plane, look B "tint pill" (Aaron 2026-10-07, call C1;
     Steward re-entry 10 § 4, PMO 4839cbec). A mix of the chip's OWN ink over whatever ground it sits on, so it
     steps away from the ground in both themes with one rule: the plane rungs run in opposite directions per theme,
     so no single plane token can (D1 — Aurora's --op-plane-hover sat closer to READ's ground than --op-plane,
     1.07 < 1.14 : 1; D2 — Feather's --op-plane WAS READ's ground, 1.00 : 1; both measured on vault-extension).
     ACHROMATIC — the ink is the host's — so this is not a second consumer of --op-hover-tint's hue exception.
     THEME-INVARIANT by construction: the declaration names no themed input; currentColor resolves at the chip,
     per element, in either theme. CANDIDATE 8% / 13%, Aaron's (digest #2). */
  /* round 5: one value, two names — the district reads its own name, brand core's --ink-tint is the value's home */
  --op-chip-tint:var(--ink-tint); /* theme-invariant */
  --op-chip-tint-hover:color-mix(in oklab,currentColor 13%,transparent); /* theme-invariant */
  /* --op-speaker-mark — fire ① of the district's colour ration (steward-theme-contrast-2026-09-15 § 4,
     walked by Aaron 2026-09-15; semantic-register § 2d amended 2026-09-16): the surface's OWN speaker
     mark — ◆, the face tile — wears --c2 as IDENTITY. Ink only, on READ's ground (5.12:1 Aurora ·
     5.03:1 Feather, computed), the one hue in a turn head. A ROLE token, not a second reach at
     --op-focus: "where you are" (focus, selection) and "who is speaking" share a VALUE today and are
     not one binding — the --node-branch finding (a move-type hue that happened to be c2, so "Vault
     speaking" and "a dispatch card" rhymed by coincidence) in canon's own costume. Retune one and the
     other must not move. NEVER a fill behind a speaker's words, never the operator's monogram (the two
     speakers differ by MARK, not by colour — or the pair becomes the bubble pair), never any seat's
     head beyond the mark itself. CANDIDATE, Aaron's (digest #2). */
  --op-speaker-mark:var(--c2); /* 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. SPENT ON LABELS in
     this district (op-state-token · op-trace-row · op-btn--danger · the consumer's liveness word), so
     the three referents carry a TEXT obligation on every plane the district composes them on — met by
     value, both themes, since the Feather retune of --error/--success (2026-09-13, [data-theme] block). */
  --op-status-ok:var(--success); --op-status-warn:var(--warn); --op-status-error:var(--error); /* theme-derived */
  /* ── THE CONTEXT-FILL STEPS (--op-ctx-fill-1..7) — landed 2026-10-04, Aaron's design (Figma
     HIXJ2kc8 110:1101, `context-fill-icon-keyframes`; approved 2026-10-04). Fire ⑥ of the colour
     ration (semantic-register § 3): the ramp WALKED, one flat stop per step, on op-ctx-fill's segments
     and nowhere else (gate ctx-fill-reach-enumerated). Pure derivation, ZERO new hexes: steps 1 · 4 · 7
     are --c5 · --c3 · --c1 verbatim; 2 · 3 · 5 · 6 are oklab mixes of the adjacent stops, the share
     fitted to his Figma hexes (ΔE_ok 0.27 · 0.38 · 0.00 · 0.88 against #3FCFC7 · #49B0E9 · #8271F4 ·
     #BB6CD5). The walk skips --c4 and --c2 as pure stops — his, recorded, not corrected. CANDIDATE. */
  --op-ctx-fill-1:var(--c5); --op-ctx-fill-2:color-mix(in oklab,var(--c4) 55%,var(--c5)); --op-ctx-fill-3:color-mix(in oklab,var(--c3) 32%,var(--c4)); /* theme-derived */
  --op-ctx-fill-4:var(--c3); --op-ctx-fill-5:color-mix(in oklab,var(--c2) 70%,var(--c3)); --op-ctx-fill-6:color-mix(in oklab,var(--c1) 45%,var(--c2)); --op-ctx-fill-7:var(--c1); /* theme-derived */
  /* ── THE SYNTAX GROUP (--op-syn-*) — landed 2026-09-23, arm B (Aaron's pick, U10 · 7a4d20).
     The code well's ink, one role set painted identically in the editor and in READ's fences.
     Canon's rationale + the arms rendered + the reject reasons: operator-district/syntax-colour.md.
     THE CONTEXT EXCEPTION, and why the ramp hues are legal here at all (semantic-register § 2i):
     "within a code-editing view syntax highlighting is contextually different than seeing that
     particular color value elsewhere" (Aaron). A hue in a fence answers "what kind of token" and
     carries none of its chrome meaning — it never reaches prose or chrome (the .tok-* rules in
     operator.css are scoped to the three code wells, and a gate refuses a bare one).
     SHAPE — pure alias + derivation, ZERO new hexes:
       · --op-syn-lift — THE ONE NUMBER, and the one per-theme value in the group (no marker; it
         appears in BOTH blocks). Aurora 100% (the hue verbatim — its lowest hue, --c2, is already
         5.26:1 on the well). Feather 84% — CANDIDATE, Aaron's. Feather's ramp hues are boundary /
         mark colours and fail AA as TEXT on the well: raw on --inset c1 3.81 · c2 4.61 · c3 4.40 ·
         c4 3.79 · c5 3.56. 84% is the first whole step at which the worst (c5) clears 4.5 (4.61);
         86% falls under. Authored per theme for --muted-2's reason: the target is a RATIO, and a mix
         twin does not hold a ratio across two grounds. DO NOT TIDY THIS AWAY — the four raw ratios
         above are why it exists, and PRIMITIVE-INDEX § Tokens carries them too.
       · --op-syn-hue-1..5 — the five rungs a role reaches. A role NEVER reaches --cN directly
         (gate syn-rung-only), so the lift is applied in ONE place and a retune moves every hue.
       · sixteen role tokens — each carries an ASSIGNMENT decision (which hue this role wears),
         which is what separates this from the rejected --gap-* rename-alias shape.
     Arm B's map is One Dark's, hue-for-hue: keyword violet · string green · regex/escape cyan ·
     function blue · property magenta · type cyan · literal AMBER (--op-status-warn — the one
     status-hue-on-data line; the swap put to Aaron stood by silence, 2026-09-20). Contrast floor
     (syn-role-floor): 16 roles × {--op-well, --op-canvas} × both themes ≥ 4.5:1; the tightest cell
     is Feather string on the well, 4.61. */
  --op-syn-lift:100%;
  --op-syn-hue-1:color-mix(in oklab,var(--c1) var(--op-syn-lift),var(--ink)); --op-syn-hue-2:color-mix(in oklab,var(--c2) var(--op-syn-lift),var(--ink)); --op-syn-hue-3:color-mix(in oklab,var(--c3) var(--op-syn-lift),var(--ink)); /* theme-derived */
  --op-syn-hue-4:color-mix(in oklab,var(--c4) var(--op-syn-lift),var(--ink)); --op-syn-hue-5:color-mix(in oklab,var(--c5) var(--op-syn-lift),var(--ink)); /* theme-derived */
  --op-syn-name:var(--op-ink-2); --op-syn-definition:var(--op-ink); --op-syn-function:var(--op-syn-hue-3); --op-syn-keyword:var(--op-syn-hue-2); /* theme-derived */
  --op-syn-string:var(--op-syn-hue-5); --op-syn-string2:var(--op-syn-hue-4); --op-syn-literal:var(--op-status-warn); --op-syn-property:var(--op-syn-hue-1); /* theme-derived */
  --op-syn-type:var(--op-syn-hue-4); --op-syn-operator:var(--op-ink-2); --op-syn-punctuation:var(--op-ink-muted); --op-syn-comment:var(--op-ink-muted); /* theme-derived */
  --op-syn-meta:var(--op-ink-muted); --op-syn-invalid:var(--op-status-error); --op-syn-inserted:var(--op-status-ok); --op-syn-deleted:var(--op-status-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.

     ── T15, RULED 2026-10-07 15:26 (Aaron, on specimens/stroke-scale-2026-10-07.html @314a111):
     A STROKE'S WEIGHT IS A POSITION ON AN AXIS, THE WAY A FACE'S IS. Thin → black on the font
     convention (100 · 400 · 700 · 900), one continuous curve: stroke(w) = regular × 1.2^((w−400)/100)
     — the type scale's own minor third, one step per 100 of weight. Regular is today's hairline.
     His words: "i could actually feel the curve of values vs the snapped … exact always feels better."
     So the values are EXACT and never snapped: thin 1/1.2³ · regular 1 · bold 1.2³ · black 1.2⁵.
       THE CURVE IS RULED; THE ANCHOR IS CANDIDATE (digest #2). Each stop is written as a self-contained
     expression rather than var(--stroke-regular) × n because the operator surface's vendoring bridge
     derives these values verbatim and cannot follow a var() into a name it does not carry. So a
     retune of regular is four edits, and gate `stroke-on-the-curve` (qa/check.mjs) FAILs any stop
     left off the curve — the curve, not the authoring form, is what is pinned.
       ONLY THE FOUR STOPS THE REGISTER NAMES. Light/medium/semibold/extrabold sit on the same curve and
     are NOT declared: a token with no consumer is a guess about a shape nobody has built. A fifth
     stop is named by its font-weight word and the curve gate already knows its value.
       NAMED BY WEIGHT, and --stroke-hair RETIRED WITHOUT AN ALIAS. "hair" is not a position on the
     axis, it collided with the COLOUR token --hairline (a width wearing a colour's name, the shape
     the 07-31 note above refused for --hairline-w), and an alias over --stroke-regular would be
     indirection without information — the --gap-* case law. Tripwire `stroke-hair-retired` pins it.
       HOW AN EDGE DRAWS ITS WEIGHT (option b′). border-width and outline-width FLOOR to whole CSS px
     in Chromium at DPR 1 and 2 (measured: 1.5 and 1.728 both compute 1px), and a box drawn as a line
     paint-snaps (a 1.728px-wide box paints 2px). So a stroke that is not a whole px is NEVER fed to
     a snapping property: a box edge keeps its regular border (it reserves the layout every box was
     built around) and carries the weight ABOVE regular as a zero-blur inset edge —
     `box-shadow: inset 0 0 0 calc(var(--stroke-bold) - var(--stroke-regular)) <edge>` — which paints
     exactly what b′ painted (the regular pixel full ink, the remainder as coverage). A line drawn as
     a box carries its remainder as a zero-offset spread. Gate `stroke-never-snaps`. Neither is a
     cast: zero offset, zero blur, nothing floats (the 2026-08-02 slider-thumb ruling).
       FORCED COLOURS drops box-shadow, so every edge drawn ONLY as an inset edge owes a real
     border or outline under @media (forced-colors: active) — gate `inset-edge-forced-colors`.
     A remainder edge needs none: its regular border is real and survives; the weight above it goes.
       --stroke-bold's 1.5px RETIRES here: it was a hope that a half pixel would render, and it never
     did at a border. --stroke-focus below stays OFF this axis on purpose. */
  --stroke-thin:calc(1px / 1.728); --stroke-regular:1px; --stroke-bold:1.728px; --stroke-black:2.48832px;
  /* ── DISPLAY STROKES — T15's second register, RATIFIED 2026-10-30 (Aaron, ticket VAULT-12, /walk D10.3
     "Ratify the axis", on specimens/display-strokes-2026-10-07.html). A decorative line takes its weight
     from the TYPE BESIDE IT: the same axis as the UI stops above, anchored at the adjacent style's stem
     instead of at 1px —  display(w, style) = stem(style) × 1.2^((w − 400) / 100).
     TWO FAMILIES, because the anchor is per style and the step is per weight:
       --stroke-display-stem-<style>  the face's regular vertical stem, in EM (measured with fontTools,
         vertical stem of `n` at 40% x-height, italic read perpendicular to the slant — the method that
         reproduced stroke-scale § 5's Sans .080 / Mono .078). Instrument Serif italic .0797 · Instrument
         Sans .080 · Space Mono .078 · head = Bricolage Grotesque 600 ≈ .126 (interpolated between opsz-14
         400 .091 and 700 .144; display opsz not measured). MEASURED values, not CANDIDATE: a retune is a
         re-measure, and gate `display-stroke-on-the-curve` pins each to its measurement.
       --stroke-display-<weight>  the axis step, UNITLESS — 1.2^((w−400)/100) — because a display stroke
         has no length until it meets a style. Same four stops the UI register names; a fifth is named by
         its font-weight word (the curve gate knows its value), never declared without a consumer.
     AUTHORING FORM: calc(var(--stroke-display-stem-<style>) * var(--stroke-display-<weight>)), written on
     the element whose type the line accompanies (or its pseudo-element). The stem is an em token, so the
     length resolves against THAT element's font size at the use site — never at :root — and the line
     cannot drift from its type. Never pre-multiply stem × step into one :root token: a custom property
     substitutes its var()s where it is DECLARED, so a descendant's stem override would never reach it.
     DRAWING: never a border and never a bare box height (gate `stroke-never-snaps` treats every display
     token as fractional by construction). A gradient line paints through background-size in a box rounded
     up to the next whole px, the band anchored to the box's TOP edge; a flat line may use a zero-offset
     spread; an SVG line uses stroke-width. All three render the exact value.
     THE EDGE LOOK, RULED (Aaron delegated, 2026-10-30, /walk follow-through — BRAND.md § Display strokes):
     (1) each line takes the stem of the style beside it, headings their own heavier stem; (2) an underline
     MIRRORS its text's weight (--type-weight-step, declared where bold is set) and hover adds × bold; an
     ornament PICKS its step, written at its rule; (3) the rail's type is the folio; (4) no floor — exact
     at every density. medium · semibold · extrabold are declared with their first consumers (b/strong's
     mirror, the rail, the eyebrow bar). Theme-invariant → :root only. */
  --stroke-display-stem-serif:.0797em; --stroke-display-stem-sans:.08em; --stroke-display-stem-mono:.078em; --stroke-display-stem-head:.126em;
  --stroke-display-thin:calc(1 / 1.728); --stroke-display-regular:1; --stroke-display-medium:1.2; --stroke-display-semibold:1.44;
  --stroke-display-bold:1.728; --stroke-display-extrabold:2.0736; --stroke-display-black:2.48832;
  /* --stroke-focus —the FOCUS RING's width, 2px, an integer on purpose (6ad2c5, 2026-09-29; PMO
     ade9fa6b + 9a04a141). The ring read --stroke-bold, and 1.5px floors to 1px at 1x DPR, so
     OP-ESTABLISHMENT § 3.1's promised 2px rendered as 1 and a page carried two ring weights (brand
     core's blanket rule was a 2px literal). T15 (2026-10-07) did NOT bring it back onto the stroke
     axis: a ring is an indicator with an a11y floor (WCAG 2.4.13's 2px), a stroke is a weight — a
     retune of one must not move the other, so it is never an alias of a --stroke-<weight> stop.
     Theme-invariant → :root only. Gates: focus-width-integer (qa/check.mjs) · ro-p7's computed ≥ 2px lines. */
  --stroke-focus:2px;
  /* --stroke-device — ONE DEVICE PIXEL, at any scale (rebuild 7b round 7, c7d8e9; plan op-surface-rebuild
     § Decisions made, 2026-10-18: Aaron likes how hairlines look at native density, and "canon should draw
     hairlines at one device pixel at any scale"). OFF THE WEIGHT AXIS, as --stroke-focus is, and for a
     different reason: a weight is a CSS length the eye reads as heavier or lighter; this is a RESOLUTION
     fact — the thinnest line the screen can draw — and its CSS length changes with the screen while what it
     draws never does. 1px at 1×, 1/1.5px at 1.5×, 0.5px at 2×: the ladder of `resolution` queries below sets
     1px / dppx at each stop, so between two stops the line is at most one stop's ratio over one device pixel.
     MEASURED (round 7's probe, Chromium, 2026-10-18): a 1px BORDER at 1.5× paints two device rows (255 + 128
     ink, a smear); a 0.5px border still COMPUTES 1px (border-width never goes under one CSS px), so a border
     can never draw this token. An INSET EDGE (`box-shadow: inset 0 var(--stroke-device) 0 0 <edge>`) or a
     background strip of this height paints exactly one device row at full ink at 1×, 1.5×, 2× and 3×. So:
     NEVER feed it to border-width or outline-width (gate `stroke-device-never-a-border`); draw it as an inset
     edge or a strip, and give it a real border under forced colours (`inset-edge-forced-colors`). Theme-
     invariant → :root only. The render proof is `qa/hairline-check.mjs` (1×, 1.5×, 2×). */
  --stroke-device:1px;
  /* ── ICON tier — I10 dimensional family, landed 2026-08-22; RE-DERIVED 2026-09-16 for a FILL set.
     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` and `obsidian-theme/theme.css`
     each declared the same weight for the same icon set with no token between them — CODIFICATION.md
     § Step 2's named silent failure, with the vendored theme as the prediction come true. Placement
     verdict + reason: operator-district/PRIMITIVE-INDEX.md § `op-icon` + `op-avatar`.

     THE SET LEFT AND TOOK ITS PROPERTY WITH IT. The tier landed with `--icon-stroke: 1.75`, a ratio on
     Lucide's 24-unit stroke grid. On 2026-09-16 the district's set became Phosphor Light — FILLED
     geometry on a 256-unit grid, no stroke to tune — and the token had no consumer left. It is
     RETIRED, not zeroed and not kept "for the theme": the Obsidian theme rides Obsidian's own Lucide
     and now declares its weight theme-locally (`--cv-icon-stroke`), an accepted divergence recorded
     at that declaration and under P10. A tripwire (`no-icon-stroke-after-phosphor`) pins the
     declaration and every `var()` of it absent from brand.css and the district. Lesson, recorded in
     the Steward's case law: the 08-22 tier was right as TOKENS and wrong in ONE — `--icon-stroke` was
     the SET's property wearing the TIER's name. What survives the set is the BOX.
     Record: operator-district/icon-set-change-record.md § 2.

     SIZE STEPS — CANDIDATE, RETUNED 2026-09-30 (f0a107 · PMO b6dc62f3), PENDING AARON'S LOOK.
     The 09-15 boxes measured SMALL beside their own label in real chrome (Steward seat read
     2026-09-30, op-surface at 1512×950, chrome label --text-small = 15.04px): head/toolbar icon
     buttons 1.00×, menu item marks, act carets, op-kind and rail pane tabs 0.93× — and Phosphor
     Light's ink inside a 14px box is 9.4–11.2px tall, i.e. the glyph read at the cap height of
     15px text. The retune puts the box ONE minor-third step (1.2, the type axis' ratio, ruling #3)
     above its label:
       --icon-md  1em → 1.2em — the inline step: still tracks its label, now at 1.2× it.
       --icon-sm  14px → 18px — the CONTROL step: 18 / 15.04 = 1.197× the chrome label.
     The smaller arm, 16px (1.06×), stands beside it on the look specimen; it sits UNDER the
     1.15× band this retune gates, so choosing it is a deliberate gate change, not a value swap.
     Gate: icon-to-label-ratio (qa/check.mjs) — every box 1.15–1.25× its label, a 1em plant FAILs.
     --icon-lg is 24px — the large step (no longer "1:1 with the source grid": the grid is 256).
     Consumers that sized a glyph by literal (`.shell-collapse .icon` and kin) say `var(--icon-sm)`
     and move with it; the working mark's DRAW does not (operator.css, pinned — its window clips).

     THE FLOOR IS OBSERVED, NOT DERIVED — reclassified 2026-09-16. The 08-22 floor was arithmetic:
     24 ÷ 1.75 = 13.71px, the box where a Lucide stroke clears one device pixel. Phosphor Light's
     12-unit ribbon is 0.66 device px at 14px — under that crossing — and it is the column he read as
     CLEAR. Counter-space decided, not stroke arithmetic, so the derived floor picked the wrong winner.
     RULE, unchanged: below the floor, DROP the icon; never shrink it.
     THE FLOOR IS MOVING, AND THIS SAYS SO. Until 2026-09-30 the floor was 14px, the smallest box a
     specimen approved (2026-09-15, "phosphor light at 14px looks the best"), and this comment said
     growing the box "ships something he did not look at". This retune DOES grow it, and that is the
     open condition, not a contradiction to hide: 18px is a CANDIDATE that has NOT been approved —
     Aaron judges 14 · 16 · 18 on a specimen of real chrome, both themes, before anything re-vendors
     (f0a109 waits on that look). What the 09-15 read approved was the SET's clarity at 14px; what it
     did not test was the box against its label, which is the axis this retune moves. */
  --icon-sm:18px;      /* CANDIDATE (was 14px) — the CONTROL step and the floor; 1.197× the chrome label */
  --icon-md:1.2em;     /* CANDIDATE (was 1em) — the inline step: 1.2× its label (one minor-third step) */
  --icon-lg:24px;      /* the large step */
  /* ── GLYPH tier — the slot every non-text mark beside text sits in (b8e2d5, 2026-10-11).
     The vault base's glyph-label contract (Lab/design-system-base/primitives/glyph-label.md,
     GLY-1–18) fixes relations; these are Corvus's values. Theme-INVARIANT → :root ONLY.
       --glyph-slot  16px CANDIDATE — the square slot a bullet, ordinal, checkbox, chevron or type
                     icon occupies (GLY-1). Its own token, not an --icon-* step and not a --space-*
                     rung: the slot is the COLUMN, and the --icon-* box is what an icon draws at
                     (with a dropped-never-shrunk floor, mid-retune 14 → 18). Coupling the column to
                     the icon look would move every list indent on an icon decision. 16 matches the
                     Obsidian binding (--cv-glyph, 06884d) so the brand's two surfaces nest alike.
       --glyph-unit  slot + --space-2 = 24px — one nesting step (GLY-4). A relation, not an alias:
                     a slot retune moves the step with it. The GAP is --space-2 spelled directly —
                     a --glyph-gap token would be the rejected --gap-* alias shape, and gate 2b
                     admits only var(--space-*) in a gap.
     THE OPEN CONDITION, said rather than hidden: a type icon drawn in a 16px slot sits under the
     --icon-sm CANDIDATE (18) and over the approved 14 floor. The reference page (glyph-label.html)
     wires --icon-sm and --icon-lg as slot alternates so the look can decide; 18 puts the unit at
     26, off the 4px grid. */
  --glyph-slot:16px;   /* CANDIDATE — the glyph slot (GLY-1) */
  --glyph-unit:calc(var(--glyph-slot) + var(--space-2)); /* the nesting step (GLY-4) */
  /* ── 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 */
  /* RAISED 2026-09-04, --space-10 → --space-12, at the operator's request:
     *"the OS ui overall feels very tight to me in the left icon rail as well as
     the navigator pane."* The token's own comment is what licenses it — this is
     "a function of GLYPH + PADDING," so more room around the glyph is the value
     moving for the reason it exists, not a layout number being nudged.

     IT IS ONE KNOB FOR TWO AXES, and that coupling was the whole decision. The
     collapsible primitive reads it as the railed pane's WIDTH; the operator
     district reads it as each rail tab's HEIGHT. So one step buys air in both
     and keeps the icon box square. The alternative — decoupling, so the district
     declared its own tab-height rung — was measured, put to Aaron with its cost
     (cc-offer never moves; icon boxes stop being square; the district carries a
     divergence needing a recorded reason) and NOT chosen.

     BLAST RADIUS, ENUMERATED RATHER THAN EXPECTED: operator-district/operator.css
     (rail tab height) · the collapsible primitive (railed min/max width) ·
     dist-cc/index.html + dist-cc/cc-offer.html (inlined at build, so the shipped
     Change Craft offer moves on its NEXT rebuild, not today) ·
     field/artisan-02-layout.html. Aaron was shown that list, including the
     client-facing member, and took the trade.

     WHY THE LITERAL BECAME A var(). 40px was already exactly --space-10 — on the
     scale, but written as a number, so nothing said so and nothing would have
     caught it drifting off. The neighbours in this GEOM group are still literals
     and are a separate cleanup; this one converts because it was being touched
     anyway. --space-12 is declared below this line and resolves fine: custom
     properties are computed-value-time, not parse-order. */
  --collapsible-rail-w:var(--space-12); /* 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);
  /* masthead geometry (G3, 2026-11-03, Steward slot 7b for aaron-portfolio). --masthead-bar-h is the sticky
     bar's row; --masthead-h is the whole offset the masthead occupies, the bar PLUS its 1px bottom rule, which
     is what an anchor must clear and what a full-height block subtracts. A relation, not an alias (the
     --gap-* refusal does not apply: no other token names this quantity). It retires the two hand-typed
     `calc(100svh - 66px)` (one pixel short of the measured 67) and the portfolio's interim --ap-masthead-h.
     Theme-invariant → :root only (`--masthead-` in tools/theme-invariant.mjs). */
  --masthead-bar-h:66px; --masthead-h:calc(var(--masthead-bar-h) + 1px);
  /* 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 em, NEVER px — RECALIBRATED 2026-10-17 (r3c5e7, panel-v2 TC-1; walk D1.1). The tier was
     authored in `ch` on the belief that ch counts characters. It does not: ch is the advance of the
     "0", and Instrument Sans draws a wide, tabular-looking zero — 0.666em — against a running average
     of 0.445em (measured over every Corvus surface's body text, 0.440–0.468). So 66ch held ~99
     characters, and every prose surface set 92–101 a line while BRAND.md said 45–75. Each step is now
     "N characters at the consumer's own size", N × 0.445em, so the face shows in the derivation
     instead of hiding in one glyph. em keeps what ch was chosen for (the cap scales with its own text
     and survives any --text-* bump), does not jump when the web font swaps in over its fallback (ch
     is re-read from the loaded face's 0), and treats the faces evenly: at these values Instrument
     Sans and Bricolage both hold ~66 at prose, where a ch tier sized to the same result (44ch) would
     hold Space Mono at 44, under the band. Not the
     layout-scale em dimensional-unit-policy.md refuses — a measure tracks its own text, as --track-*
     does. Derivation + measurements: BRAND.md § Type. Held by `measure-check` (qa/measure-check.mjs):
     every consumer, rendered at its declared size, counted line by line.
       tight 22.5em ≈ 51 characters — the stub column; its shipped WIDTH was right (34ch = 22.6em),
                   only its description was wrong, and the hero column holds a display headline
       lede  26em   ≈ 58 characters — larger type, fewer characters (full lines 50–61 measured)
       prose 29.5em ≈ 66 characters — the number this tier always named (full lines 57–68)
     CANDIDATE — Aaron tunes like --pr-*, on a render. Original tier: proof-surface/feedback-ds-obligations.md */
  --measure-tight:22.5em; --measure-lede:26em; --measure-prose:29.5em;
  /* 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's coverage faces (e6f4a0, ruled 2026-10-03): kaomoji are a primary use of non-ASCII glyphs, so the
     mono voice carries them in-face. Each family after Space Mono is a self-hosted subset (fonts/faces.css, imported
     above) whose unicode-range is exactly what it adds — it never draws a glyph Space Mono has. Iosevka Charon Mono
     and Noto Sans JP/KR are size-adjusted onto Space Mono's cell; the single-script faces are proportional. Order is
     generated, not chosen here: tools/fonts/build-faces.py; gate tools/fonts/glyph-gate.mjs checks this stack
     against fonts/coverage.json. Derivation: proof-surface/font-token-tier.md §3.5. */
  --font-mono:"Space Mono","Iosevka Charon Mono","Noto Sans JP","Noto Sans KR","Noto Sans Thai","Noto Sans Kannada","Noto Sans Arabic","Noto Sans Canadian Aboriginal","Noto Sans Sinhala","Noto Sans Georgian","Noto Sans Math","Noto Sans Symbols 2",ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,"Liberation Mono",monospace;
  /* --font-display-italic — the .shimmer word's real italic (09c15c; face picked by Aaron 2026-09-29 at 8fe880,
     Typography + Brand Identity reviews PASS-WITH-CONDITIONS, 8fe880-review.md). Bricolage ships no italic, so
     the display voice borrows ONE drawn italic from a second family: Schibsted Grotesk italic, requested as a
     single master at 650 (its stems measured against Bricolage 600 across opsz 36-96: -0.6%…-2.3%; 600 was
     -9.5%…-11%). Zero weight steps, like --font-accent. Bricolage is the SECOND family on purpose: if Schibsted
     fails to load, .shimmer (font-synthesis:none) paints upright Bricolage — the 67899b interim's face, at 650
     rather than its 600 — and never a synthesized oblique. The system tail then carries it as --font-display's does. */
  --font-display-italic:"Schibsted Grotesk","Bricolage Grotesque",ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
  /* 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);
  /* --btn-bold-deepen — the ink step laid over the ramp under .btn-bold's label (3e834c, Q4). Aurora
     needs none (its --ground label on the ramp clears AA, 5.03:1 worst); Feather's value is CANDIDATE. */
  --btn-bold-deepen:0%;
}
/* --stroke-device's ladder (round 7, c7d8e9): 1px / dppx at each stop, ascending, so the last query that
   matches is the screen's own stop. Stops: the postures Aaron reads on (1×, the 38GN950's ~1.5×, the
   laptop's 2×), Chromium's page-zoom products in between, and 3× / 4×. Gate `stroke-device-ladder`
   (qa/check.mjs) holds every value to 1px / its stop; `qa/hairline-check.mjs` reads the paint. */
@media (resolution >= 1.1dppx)  { :root { --stroke-device:calc(1px / 1.1); } }
@media (resolution >= 1.25dppx) { :root { --stroke-device:calc(1px / 1.25); } }
@media (resolution >= 1.5dppx)  { :root { --stroke-device:calc(1px / 1.5); } }
@media (resolution >= 1.75dppx) { :root { --stroke-device:calc(1px / 1.75); } }
@media (resolution >= 2dppx)    { :root { --stroke-device:calc(1px / 2); } }
@media (resolution >= 2.2dppx)  { :root { --stroke-device:calc(1px / 2.2); } }
@media (resolution >= 2.5dppx)  { :root { --stroke-device:calc(1px / 2.5); } }
@media (resolution >= 3dppx)    { :root { --stroke-device:calc(1px / 3); } }
@media (resolution >= 4dppx)    { :root { --stroke-device:calc(1px / 4); } }
[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.
     WIDENED 2026-09-15 (Aaron, walked D1.6.5): #6F6D7D sat at 4.51:1 on --ground — AA by 0.01 — and
     the operator surface's first Feather render put that margin in front of him. One L step darker
     in OKLab with hue and chroma held (L 0.5421 → 0.5248, ΔL −0.0173; C 0.0248 → 0.0250; h 291.3° →
     291.2°, the residue of 8-bit quantisation). Measured (WCAG relative luminance, off the hex):
     --ground 4.86 · --ground-lift 5.03 · --surface 5.21 · --raised 5.43 · --inset 4.46 (inset was
     never a permitted plane for this rung — ink-ramp-4th-rung.md § 3.3). The --muted → --muted-2
     joint widens 0.066 → 0.082 (still a half-step of the house cadence; § 4.3 stands). Aurora is
     untouched: it was never at the margin. */
  --muted-2:#6A6878;
  /* --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) 40%,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.
     --error and --success TOOK THE SAME REPAIR 2026-09-13 (Steward, e7a3f1 second pass), for the same
     reason and by the same method. The operator district spends --op-status-{ok,error} on LABELS —
     op-state-token, op-trace-row, op-btn--danger, the consumer's liveness word — so on this district
     the aliases ARE text, and the unprimed critic measured the liveness word at 4.38:1 on --surface
     (P3, CRITICAL). --success had never been measured as text on paper: 3.02:1 on --ground. Each
     was moved in OKLab on L ALONE (hue and chroma held — #D93843 L.589→.528, #2E9E6B L.624→.489)
     until it clears AA on --inset, the hardest paper plane, so the 4.5:1 obligation a dual-role token
     carries is discharged by the VALUE on every plane rather than policed per use. Both land on
     --warn's own Feather rung to the hundredth (ground 5.28 / 5.31 · surface 5.67 / 5.70 · raised
     5.91 / 5.94 · inset 4.85 / 4.87) — three status tokens, one rung on paper. Aurora untouched
     (error 6.10 · success 9.11 on ground). The brand-core control-floor ruling below (--error is a
     boundary token in DS sheets; error TEXT rides --ink) is unchanged — this is the alternative it
     names as "a CANDIDATE value and Aaron's", reached for because the district's status register
     is ratified as label-carried. CANDIDATE hues — Aaron may retune ≥AA. */
  --success:#007343; --warn:#8A5A0F; --error:#C31E32;
  /* 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 SYNTAX GROUP's one per-theme value — CANDIDATE 84%, Aaron's (see :root). The first whole
     step at which Feather's least-luminous hue (--c5) clears AA as text on --inset: 4.61:1. */
  --op-syn-lift:84%;
  /* --op-on-focus — the lightest plane on paper; see :root (e55ad7). */
  --op-on-focus:var(--raised);
  /* --btn-bold-deepen — CANDIDATE, Aaron's (3e834c, Q4). Measured (mark-contrast gradient-text, worst
     pixel, system.html): 0% 4.13 · 6% 4.43 · 8% 4.60 · 10% 4.79 · 12% 4.87 · 14% 5.06. 8% is the first to
     clear and clears by 0.10 — the armed send's thin margin again — so 10% is the proposal. See :root. */
  --btn-bold-deepen:10%;
}

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

/* >>> token-role binding — the vault base's role tier (2026-10-10) <<<
   Corvus's answer to Lab/design-system-base/tokens/roles.css: one alias per base role, pointing at
   Corvus's OWN semantic token, and nothing else — no value is written here, and nothing is renamed.
   Base-tier tooling (the design-feedback widget) reads only these keys, so on a Corvus page it wears
   Corvus. Ruling: design-system-base/reports/2026-10-10-steward-color-roles-ruling.md.
   Declaration: ./role-binding.json. Gate: design-system-base/gates/role-binding.py (R1–R5).

   FOCUS IS --c2, NOT --c1. Brand core's focus hue is --c2 (`:focus-visible` and `.splitter:focus-visible`
   below; the district's --op-focus aliases it). The widget used to read --c1 for focus — a palette
   slot standing in for a role — and this binding is where that mis-binding is corrected.

   THE SELECTOR LIST IS LOAD-BEARING (R3). var() inside a custom property substitutes on the element
   that DECLARES it and descendants inherit the substituted value, so a binding on :root alone would
   freeze Aurora's values for any subtree that sets its own data-theme (a side-by-side theme
   specimen). [data-theme] re-binds at every theme position.
   KNOWN GAP, BEHIND THE COLOUR-RULES SWITCH: the colour-rules planes re-declare --hairline below
   :root, so with the switch on, --role-border inside a plane carries the root's hairline, not the
   plane's. Re-binding per plane belongs inside the colour-rules region, which is generated and
   scope-gated (verify:families SCOPE), so it lands with the region when the switch is ruled in.
   PLACED AFTER BOTH THEME BLOCKS for the same reason as color-scheme above: the theme-block parsers
   find the FIRST :root / [data-theme="feather"] in this file. */
:root, [data-theme] {
  --role-canvas: var(--ground);
  --role-surface: var(--surface);
  --role-field: var(--inset);
  --role-text: var(--ink);
  --role-text-muted: var(--muted);
  --role-border: var(--hairline);
  --role-focus: var(--c2);
  --role-success: var(--success);
  --role-font-text: var(--font-text);
  --role-font-mono: var(--font-mono);
}
/* <<< token-role binding >>> */

*{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). */
/* --type-weight-step: the axis step of THIS weight (500 = medium), so a line that mirrors its text — the
   .link underline (ruled 2026-10-30, call 2) — follows the word. Moves with font-weight, never alone (gate
   display-stroke-consumers). */
b,strong{font-weight:500;color:var(--ink);--type-weight-step:var(--stroke-display-medium)}
::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)}
/* .wrap--measure — the same centred column, capped at the reading measure instead of the page width
   (rebuild 7b round 5, 2026-10-16; Aaron on the emit's harness index: "left and right side text are so far
   apart on my screen"). content-box so the CONTENT is the measure: under the global border-box the prose cap
   would include the fluid gutter and the text column would shrink as the viewport grows. ch resolves on the
   element's own font. */
.wrap--measure{max-width:var(--measure-prose);box-sizing:content-box}
.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 ──
   A DISPLAY stroke beside the folio (ruled 2026-10-30, call 3): Space Mono's stem at --text-mono,
   semibold. font-size is set here only so the em resolves against the folio's size; the box is the
   next whole px and the band paints at the exact weight, top-anchored (::after inherits the size). */
.rail{position:fixed;top:0;left:0;right:0;z-index:60;pointer-events:none;font-size:var(--text-mono);
  height:round(up,calc(var(--stroke-display-stem-mono) * var(--stroke-display-semibold)),1px);
  background:linear-gradient(90deg,var(--c1),var(--c2),var(--c3),var(--c4),var(--c5)) left top / 100% calc(var(--stroke-display-stem-mono) * var(--stroke-display-semibold)) no-repeat;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:var(--masthead-bar-h)}
/* THE ANCHOR CLEARS THE MASTHEAD (G3). Without this every Corvus page with a sticky .masthead lands a
   fragment's heading UNDER the bar. Keyed to the masthead's presence by the sibling combinator rather than
   by :has() (the stack posture has not ruled on :has, see .folio below) and rather than on `html` (a page
   with no masthead would inherit an offset it has no bar for). scroll-margin on the target, so focus
   arrival and scrollIntoView clear it too. Gated: `masthead-offset-derived` (qa/check.mjs). */
.masthead ~ [id],.masthead ~ * [id]{scroll-margin-top:var(--masthead-h)}
/* 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)}
/* ≤640 the folio drops its METADATA ITEMS — never the control it hosts.
   THE DEFECT THIS REPLACES (measured, 2026-08-30): the rule read `.folio span`, and the theme
   toggle's two children are both <span>, so on every viewport ≤640 the ONLY control on the bar
   rendered at 26×18 with `display:none` on .dot and #toggle-label and an empty accessible name
   in view — a half-state promise, live in production on 13 surfaces. `span` was never the
   concept: PRIMITIVE-INDEX §.folio already declares BOTH roles in one entry — "Items collapse
   ≤640px" AND "the theme toggle host" — and a tag selector cannot tell an item from a host.
   The folio is display:flex, so its roles ARE its direct children: text items are spans, the
   hosted control is a button. The child combinator says exactly that, and a button's internals
   are unreachable from `.folio >` by construction. Verified against the immune case: portfolio's
   two surfaces already compose the toggle OUTSIDE the folio and measured 93.3×37 at every
   viewport before this fix — the composition this selector generalizes.
   REFUSED: `.folio span:not(.toggle span)` (enumerates one exception; the next control re-breaks,
   and its miss direction is SILENT DESTRUCTION); `:has()`-guarded wrappers (cryptic, and adds a
   selector-support dependency the stack posture has not ruled on); a `.folio-item` class on ~13
   surfaces + 3 emitters (names the concept, but the concept is already carried structurally by
   flex-item position, so the class would be a second vocabulary to keep in sync — the --gap-*
   shape). RESIDUAL EDGE, closed by gate not selector: a control authored as a direct-child
   <span> would still be hidden. `folio-hosts-no-span-control` in qa/check.mjs pins its absence. */
@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 - var(--masthead-h));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 - var(--masthead-h));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.
   A DISPLAY stroke that PICKS its step (ruled 2026-10-30, call 2): the serif lede's stem at extrabold. */
.eyebrow::before,.label::before{content:"";width:30px;border-radius:var(--radius-pill);flex:none;
  height:round(up,calc(var(--stroke-display-stem-serif) * var(--stroke-display-extrabold)),1px);
  background:var(--ramp) center top / 100% calc(var(--stroke-display-stem-serif) * var(--stroke-display-extrabold)) no-repeat}
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 carries a REAL italic (09c15c, face picked at 8fe880). Bricolage ships no italic, so
   `font-style:italic` once painted a SYNTHESIZED oblique on the brand's one rationed word (842157fd), and
   67899b Q1 set it upright meanwhile. It now reads --font-display-italic (Schibsted Grotesk italic, one
   master at 650 — the weight that matches Bricolage 600's stems). font-synthesis:none is the degraded-state
   contract: if the italic never loads, the word paints upright Bricolage, never a faked slant. The .06em
   pad returns with the slant: under background-clip:text the leaning terminal would otherwise fall
   outside the painted box. line-height:0 keeps the line box the h1's: Schibsted's ascent/descent would
   otherwise grow the last line 3px when the face swaps in (measured, site/index.html @1280, both themes);
   the background still paints the glyphs' content area, so the ramp is unchanged. */
.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-family:var(--font-display-italic);font-style:italic;font-weight:650;
  font-synthesis:none;padding-inline-end:.06em;line-height:0}
@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}
/* mark.found — the span a find landed on (rebuild 7b round 5, 2026-10-16; T3 split from the operator
   district's mark.op-found, values snapped from it so nothing moves). ACHROMATIC: the matched text at full
   ink on --ink-tint, so it carries no hue in either theme — never the selection's c2 fill (a hit on that
   fill reads as a live selection where the reader selects text), never a status hue. A hairline ring in
   --muted tells it from a tinted chip in prose: a kind, not a brighter tint. Values CANDIDATE, Aaron's. */
mark.found{background:var(--ink-tint);color:var(--ink);border-radius:var(--radius-xs);
  box-shadow:0 0 0 var(--stroke-regular) var(--muted)}
.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);max-width:42%}
/* dd99bb (2026-09-29; PMO 8a34cfae): the .8 opacity was an unnamed ink step under --muted, and it put an
   11px caps caption at 3.84:1 on the Feather ground. --muted alone is the ramp's AA text rung (5.98:1). */
@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);overflow-wrap:break-word}
/* PROSE NEVER PAINTS PAST ITS MEASURE (e11a06, 2026-10-09; PMO 923605f2 / bfd5aae0, Steward re-entry 11 § 4).
   A token with no break opportunity — a URL, a path — ran 44–82px past its block (a bold Slides URL, measured on
   the operator surface). `break-word`, NOT `anywhere`: it breaks only when the token would otherwise overflow and
   is not counted in min-content, so a table cell or a flex parent keeps its width. Inherited by every element of
   the register. Gate: `prose-breaks-long-token` (qa/brand-specimen-check.mjs); plant `prosenobreak`. */
/* 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)}
/* ── THE DOCUMENT ELEMENTS OF THE PROSE REGISTER (e5b1d2, Steward 2026-09-15) ──
   Two Corvus surfaces — the operator district and the Obsidian theme — each authored a
   table, a fence, a quote, a rule, lists and headings for running prose, and converged
   independently on every plane-and-hierarchy call (operator-district/markdown-element-
   inventory.md § 3). A second consumer promotes, never copies (CODIFICATION T2: every
   rule below transplants to a landing page or a museum label and still means something).
   What did NOT transplant stays in the districts: the ramp tick on a rule (rationed —
   a `---` in agent prose is paragraph-frequency), the bordered chip on inline code
   (29 per 1k words on the instrument), the theme's nesting wash and language flair.
   CANDIDATE values — Aaron's to tune (digest #2); the two Steward rulings of 2026-09-15
   are baked in: the 1.2/18 ladder stands, capped at two rungs above body for a heading
   inside prose; the table header is the label voice, and `--muted` is what makes it light.
   Consumers compose `.page-prose`: the operator's `.prose-block` re-vendors these; the
   Obsidian theme realizes the same calls through its L2 native vars, L3 naming the rule
   each mirrors (theme parity holds the tokens; the calls are held by this comment and the
   inventory, which is the honest limit forcing-mechanism-parity names). */
/* HEADINGS INSIDE PROSE — three rungs, and the top one is the CEILING. `--text-lede` is two
   rungs above body; `--text-h3` and up are display sizes for page chrome and never appear
   inside a running column (the operator parser demotes `#`→h4 for exactly this reason; a
   document emitter composing this register demotes the same way). Margins pull a heading
   toward what it heads: above > the paragraph gap, below < it. */
.page-prose h4,.page-prose h5,.page-prose h6{max-width:var(--measure-prose);color:var(--ink);margin:0}
.page-prose h4{font-family:var(--font-display);font-weight:600;font-size:var(--text-lede);line-height:var(--leading-snug);letter-spacing:var(--track-tight);margin-top:var(--space-4)}
.page-prose h5{font-family:var(--font-display);font-weight:600;font-size:var(--text-body-lg);line-height:var(--leading-snug);letter-spacing:var(--track-tight);margin-top:var(--space-2)}
.page-prose h6{font-family:var(--font-text);font-weight:600;font-size:var(--text-body);line-height:var(--leading-tight)}
/* Inside the register's flex column the gap is the paragraph gap (--space-4); a heading's
   margin-top ADDS to it (flex gaps do not collapse), so h4 sits at 32 above / 16 below. */
/* LISTS — ONE MARKER COLUMN for every kind (2026-10-04, c0d103; was per type, 16 for `ul` and 24
   for `ol`). A bullet, an ordinal and a checkbox at one depth sit in one --space-6 cell and END at
   one x — the native `::marker` is end-aligned, one space before the words — so `•`, `3.` and a
   task box share an edge and the words after them start at one x. Right-aligned, never centred:
   ordinals vary in width (`9.` against `10.`) and centring would make the periods wander. The
   nesting step IS the cell (a nested list's own inset), so a renderer that draws depth × step +
   cell lands where this does. Overhang, stated: an ordinal wider than the cell less one space
   (`10.` and up at the body rung) hangs left into the parent's indent or the column's padding —
   the right-aligned convention; a container must not clip it. Cost: bullets gain 8px a level.
   Nested items step by one rung less than the block gap because the indent carries the level. */
.page-prose ul,.page-prose ol{margin:0;padding-inline-start:var(--space-6);display:flex;flex-direction:column;gap:var(--space-2)}
.page-prose li>ul,.page-prose li>ol{margin-top:var(--space-1);gap:var(--space-1)}
.page-prose li::marker{color:var(--muted)}
/* THE BULLET IS A CHARACTER, NOT THE UA's SHAPE (c0d103). `disc` is painted as a symbol with
   its own fixed gap — measured, its ink ends ~12px before the words where an ordinal's period
   ends one space before them — so a bullet and `3.` could never share an edge. A string marker
   is text with the ordinal's own suffix (one space), so the dot ends where the period does, and
   a renderer that draws `•` in a cell (the composer) draws the same glyph. */
.page-prose ul{list-style-type:"\2022\a0"}
/* NESTED ORDERED NUMBERING cycles 1 → a → i by DEPTH (2026-10-04, c0d109; Aaron: "standards-grade
   patterns always appreciated") — the Word / Google Docs default. Depth counts every list level
   above the item, bulleted or ordered (tabs in) — counted as `li` ancestors, since every nested
   list sits in an item — so an ordered list under a bullet is `a.`. Each
   depth reads differently from its neighbours and every label stays short enough for the one
   marker column (`viii.` overhangs the way `10.` does). The source keeps its digits; `<ol start>`
   keeps its start in every scheme. Written to nine levels — a ladder CSS cannot express as a
   modulus; past it the deepest rung holds. */
.page-prose ol{list-style-type:decimal}
.page-prose li ol{list-style-type:lower-alpha}
.page-prose li li ol{list-style-type:lower-roman}
.page-prose li li li ol{list-style-type:decimal}
.page-prose li li li li ol{list-style-type:lower-alpha}
.page-prose li li li li li ol{list-style-type:lower-roman}
.page-prose li li li li li li ol{list-style-type:decimal}
.page-prose li li li li li li li ol{list-style-type:lower-alpha}
.page-prose li li li li li li li li ol{list-style-type:lower-roman}
/* INLINE CODE — spends face, never mass, and never ink. No chip, no border, no step down, no
   colour step: at prose frequency (29 per 1k words on the instrument, census C1) a bordered
   chip is a texture and a brighter ink makes every identifier shout over the sentence it sits
   in — the face alone is the mark. The width correction mono actually needs is the
   operator's `font-size-adjust`, applied on the consumer where the prose x-height is known. */
.page-prose code{font-family:var(--font-mono);font-size:1em;color:inherit;padding:0 .12em}
/* FENCE — the MASS species: an inset plane one rung down, a hairline, the small radius, and
   the run's gap. `overflow` and `white-space` are deliberately NOT declared — the consumer's
   overflow primitive owns the inline axis (the operator's `op-scroll-x`); core declares only the
   FLOOR — `overflow-x:auto`, so a long line never escapes the plane on a surface with no primitive
   (it did, on the first specimen shot) — and never `white-space`, which is the UA's `pre`.
   `background-color`, the LONGHAND, on purpose: the shorthand resets `background-image`, and at
   (0,1,1) it would erase the fold gradients a consumer's overflow primitive paints on the same
   element (the operator's `op-scroll-x`, at (0,1,0)) — the plane would win and the "there is
   more" cue would vanish, which is critic C1's finding reproduced from the other side. */
.page-prose pre{margin:0;overflow-x:auto;padding:var(--space-3);background-color:var(--inset);border:var(--stroke-regular) solid var(--hairline);border-radius:var(--radius-sm);
  font-family:var(--font-mono);font-size:var(--text-small);line-height:var(--leading-body);letter-spacing:var(--track-mono);color:var(--ink);tab-size:2;max-width:var(--measure-prose)}
.page-prose pre code{padding:0;font-size:inherit;letter-spacing:inherit;background:none}
/* QUOTE — a left rule in the secondary ink; the interior is the register itself (a quote holds
   paragraphs, lists, even a fence). No wash, no italic: the rule is the whole mark. */
.page-prose blockquote{margin:0;padding-inline-start:var(--space-3);border-inline-start:var(--stroke-regular) solid var(--muted);box-shadow:inset calc(var(--stroke-bold) - var(--stroke-regular)) 0 0 0 var(--muted);max-width:var(--measure-prose);display:flex;flex-direction:column;gap:var(--space-4)}
/* THEMATIC BREAK — a hairline at a section gap, one rung over the paragraph gap. The ramp does
   not fire here in core; a district that has earned a tick composes it on top. */
.page-prose hr{border:0;height:0;border-top:var(--stroke-regular) solid var(--hairline);margin:var(--space-2) 0;max-width:var(--measure-prose)}
/* TABLE — no grid, hairline rows, one rung down, no zebra. The head row is the label voice
   under the EDGE (the hairline at bold stroke); cells are the secondary ink with tabular
   figures under the interior RULE. First and last cells drop their inline padding so the
   table's ink aligns to the prose column's own edge. The consumer owns overflow (a wrapper
   that scrolls); core sizes the table to its container and nothing wider. */
.page-prose table{border-collapse:collapse;width:100%;max-width:var(--measure-prose);font-size:var(--text-small);line-height:var(--leading-snug);color:var(--ink-2)}
.page-prose th{text-align:start;padding:var(--space-2) var(--space-3);border-bottom:var(--stroke-regular) solid var(--hairline);box-shadow:inset 0 calc(var(--stroke-regular) - var(--stroke-bold)) 0 0 var(--hairline);
  font-family:var(--font-mono);font-size:var(--text-mono);font-weight:400;letter-spacing:var(--track-mono);text-transform:uppercase;color:var(--muted);white-space:nowrap}
.page-prose td{padding:var(--space-2) var(--space-3);border-bottom:var(--stroke-regular) solid var(--hairline);vertical-align:top;font-variant-numeric:tabular-nums}
.page-prose th:first-child,.page-prose td:first-child{padding-inline-start:0}
.page-prose th:last-child,.page-prose td:last-child{padding-inline-end:0}


/* ── 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}
/* .terms--inline — the modifier for A FEW SHORT PAIRS READ IN ONE LINE (rebuild 7b round 7, c7d8e9; DS3 — Aaron:
   "when we print multiple key value pairs in a line that looks like prose it feels dense … it is more effortful to
   spot the one value i'm scanning for"). The field's name for the shape is a DESCRIPTION LIST; its horizontal form
   (PatternFly, SKY UX up to six pairs, ServiceNow's label-value) is for a few short pairs where a stack would cost
   the line. Each pair is one inline unit — the key in the label voice, its value at reading weight beside it — and
   the pairs are separated by SPACE (--space-4), never by a ` · ` inside a sentence, so the eye lands on a key and
   reads its value. No rules, no page rhythm (the readout modifier's reasoning). Wraps between pairs, never inside
   one. Placement: brand core (T2 — an inline description list holds on any Corvus surface; nothing in it is a
   district's). Consumers: the operator district's effort readout (the trail's tip, the drawer's head, the Briefing's
   effort lines), the handoff callout and the navigator's bound line. Gate `terms-inline-is-one-line`
   (operator-district/specimen.html ro-r7read); plant `termsstacked`. */
.terms--inline{flex-direction:row;flex-wrap:wrap;align-items:baseline;column-gap:var(--space-4);row-gap:var(--space-1);
  margin-top:0;border-top:0;border-bottom:0}
.terms--inline .terms-row{display:inline-flex;align-items:baseline;gap:var(--space-1);padding:0;flex:none;min-width:0}
.terms--inline .terms-row + .terms-row{border-top:0}
.terms--inline .terms-val{margin: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)}
/* `.absent` — THE ABSENCE CHANNEL'S STANDALONE ENTRY POINT (2026-09-13, Steward, operator
   visual direction § 2.7). The channel above is scoped to `.terms` by contract; a stated
   absence also lands in slots that are not a terms value — an empty anchor, an instrument
   with no spine to read — and the operator surface had grown THREE faces for it (mono
   italic · sans italic · sans regular, the last reading as ghost text, which a stated fact
   must never wear). One face, composed: italic, --muted, and the LABEL VOICE — mono is the
   system voice and a stated absence is a system fact ("no criteria" is a note about the
   record, not prose). Size inherits from the slot, so an absence that IS the subject
   takes the subject's rung; only face and ink are the channel's. Same declarations as the
   terms channel (one rule of thought, two entry paths — the `--rail` precedent), kept as a
   separate selector so the terms channel's 0,0,3,0 band argument stays exactly as written.
   A consumer composing `.absent` MUST NOT set colour or font-style on the same element —
   the terms channel's ceiling clause, restated here because a bare class cannot out-
   specify a consumer class the way `.terms .terms-val[data-absent]` does; the operator
   surface pins it with a verify-page row instead (`absence-has-one-face`).
   The ink is --muted, not --muted-2: the channel's value was walked 2026-08-18 and a later
   direction paragraph does not overturn a walked ruling; the delta is Aaron's to tune. */
.absent{font-family:var(--font-mono);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-regular) 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}

/* ── `.figure` — a picture of real work, in a reserved box (G1, 2026-11-03, Steward slot 7b) ──────────
   PLACEMENT: brand core, a T2/T3 split. `pr-figure`'s own Placement line named this residue as a live
   split candidate "the moment a non-proof surface needs one"; aaron-portfolio is that moment, and apex's
   page-local `figure.ax-field` was a second consumer re-deriving the shape. The shape transplants intact;
   the claim-class rule (and its unsourced hole) stays the district's.
   THE BOX EXISTS BEFORE THE BYTES. An image carries intrinsic width/height attributes, so `height:auto`
   resolves its ratio before load; while loading, the `--inset` plane is what the reader sees. If the
   image fails, its alt text renders in that box at the small rung in `--muted` — the failure is content,
   never a spinner, never a placeholder graphic.
   NOTHING FLOATS, NOTHING GLOWS: no shadow, no filter, no transform on the figure, its media or its image.
   A screenshot is shown as captured; a darkening filter in Aurora would misrepresent the work. The edge is a
   regular hairline, which is also what separates a light capture from Feather's light ground. Gated:
   `figure-nothing-floats` (qa/check.mjs; plants a filter and a shadow).
   GROUP MODE is a role, not a layout: several assets inside one `.figure[role=group]` share one caption;
   how they are arranged belongs to the consuming surface's sheet. */
.figure{display:flex;flex-direction:column;margin:0;min-width:0}
.figure-media{display:block;background:var(--inset);border:var(--stroke-regular) solid var(--hairline);
  border-radius:var(--radius-xs);overflow:hidden}
.figure-media img,img.figure-media{display:block;width:100%;height:auto;
  font-family:var(--font-text);font-size:var(--text-small);line-height:var(--leading-snug);color:var(--muted)}
.figure-media + .figure-media{margin-top:var(--space-3)}

/* ── `.caption` — a one-line mono caption naming the block beneath it (G2; graduated 2026-11-03) ──────
   Ratified 2026-09-16 in the awaiting-form ledger; graduated in aaron-portfolio's emitter window, and the
   ledger entry left in the same change. The label voice (digest #5: mono is a label voice), sentence case
   and NEVER caps (a caption, not a band; gated `caption-never-caps`), the mono rung, `--muted` ink, one
   grid step above the block it names, never louder than the body it captions. Not the hero `.cap` (an
   absolute uppercase footnote) and not `.eyebrow`/`.label` (display-voice kickers). Inside a `.figure` it
   is the `figcaption`, first child. */
.caption{display:block;font-family:var(--font-mono);font-size:var(--text-mono);letter-spacing:var(--track-mono);
  line-height:var(--leading-snug);color:var(--muted);margin:0 0 var(--space-1)}

/* ── 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)}
/* HOVER IS AN AFFORDANCE, SO ONLY A PANEL YOU CAN ACT ON HAS ONE (3470db, 2026-09-29; PMO 2426863c).
   The tint fired on every panel — a static principle card, a proof claim, a swatch — and a hover
   that changes nothing on click is a false affordance (PROOF-INDEX already refused it for pr-diff).
   Steward's call: scoped to a panel that IS the control (an <a> or <button> wearing .panel),
   not dropped — the treatment survives for the case it describes, and .btn's hover (67899b Q2)
   still has its model. A panel that merely CONTAINS a link is not the control. */
:is(a,button).panel:hover{border-color:color-mix(in oklab,var(--c3) 40%,var(--hairline))}
:is(a,button).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)}
/* --leading-snug (3470db; PMO 26f3387c): the h3 had no line-height and inherited the body's 1.6,
   a 49.8px pitch at the h3 rung. A heading takes the ladder's heading leading, as .h2 does. */
.panel h3{font-family:var(--font-display);font-weight:600;letter-spacing:var(--track-tight);font-size:var(--text-h3);line-height:var(--leading-snug);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}

/* ── .swatch — the labelled colour specimen ─────────────────────────────────
   PROMOTED to brand core 2026-09-02 (D3, T3 split). The shape lived page-local
   in system.html as `.s-sw`/`.s-band`/`.s-meta`, and site-chrome had ALREADY
   registered `.s-swatch` as a deferred formalization of it — two independent
   readings that this is a general shape, before the dv- district needed a third.
   Composes .panel (surface + hairline + radius + overflow) and zeroes its
   padding so the band runs edge-to-edge; adds nothing .panel already carries. */
.swatch{padding:0}
.swatch-band{display:block;width:100%;height:78px}
.swatch-meta{display:flex;flex-direction:column;gap:var(--space-1);
  padding:var(--space-3) var(--space-4)}
.swatch-name{font-family:var(--font-display);font-weight:600;font-size:var(--text-small)}
.swatch-value{font-size:var(--text-mono);color:var(--muted);
  text-transform:uppercase;letter-spacing:var(--track-mono)}

/* ── 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;color:var(--ink-2)}
/* THE RESTING INK (dd99bb, 2026-09-29; PMO 7b30334c) — CANDIDATE, in review. .pull inherited --ink, and
   .pull b is --ink, so the one emphasis channel below was zero steps wide: the lit word read exactly
   as its line. The line now rests one rung down (--ink-2) and the lit word keeps --ink. */
/* --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;border-radius:var(--radius-pill);flex:none;
  height:round(up,calc(var(--stroke-display-stem-mono) * var(--stroke-display-black)),1px);
  background:var(--ramp) center top / 100% calc(var(--stroke-display-stem-mono) * var(--stroke-display-black)) no-repeat}
/* `.panel .rail-note p` is written out (3470db, 2026-09-29; PMO 101fd504): inside a panel, `.panel p`
   (0,1,1) out-specified `.rail-note p` (0,1,1, earlier in the file) and set the note's body at
   --text-body in Space Mono under a --text-mono head. The compound (0,2,1) keeps the register in the
   note's own named use case, the .panel/.page-prose precedent (specificity, never position). */
.rail-note p,.panel .rail-note p{color:var(--muted);margin:0;font-size:var(--text-mono)}
@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-focus) solid var(--c2);
  outline-offset:var(--stroke-regular)}
.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}
}

/* ── .glyph-list — a non-text mark beside text (b8e2d5, 2026-10-11).
   Realizes the vault base's glyph-label role (Lab/design-system-base/primitives/glyph-label.md,
   GLY-1–18): a bullet, an ordinal, a checkbox, a switch, a menu icon and a tree's chevron + type
   icon all sit in ONE square slot, so every kind of label starts on one column and nesting steps
   by one unit whatever the marker. The geometry reads two tokens and one space rung and nothing
   else — --glyph-slot, --glyph-unit, --space-2 — so a retune of the slot moves every column and
   step together, and the render probe (qa/glyph-label-probe.json) measures that it did.
     GLY-1  the slot is --glyph-slot square; the label starts one --space-2 after it.
     GLY-2  the slot is one line of its label tall (1lh) and the glyph centres in it — UNSAFE centre,
            so a glyph taller than its label's line overflows both edges equally and stays on the
            line's centre. A FLEX slot, not a grid: a grid's implicit auto row grows to the glyph, so
            the glyph centred in a 24px row hung from the slot's top — the probe read a 24px glyph on a
            21.8px chrome line 1.1px low (slot icon-lg, 2026-10-11). A single-line flex container
            takes its line from the slot's definite 1lh.
     GLY-4  a nested list sits in its parent's body, so its slot starts on the parent's label column;
            a tree, whose rows hold a glyph PAIR, steps by --glyph-unit explicitly.
     GLY-6/7 an ordinal is text: tabular lining figures, end-aligned, baseline-shared with its label,
            overflowing toward the start. A switch is wider than the slot and overflows the same way.
            The container owes that room (the reference page's column gives it; a clip would not).
     GLY-9  the native input stays, visually hidden by clip (never display:none, which strips the
            name), under a drawn glyph that carries no semantics (aria-hidden on the drawing).
     GLY-13 a trailing cluster sits at the end edge of the line; no column is reserved for it.
     GLY-14/15 a tree's disclosure + type glyphs touch (no gap inside the pair) and the disclosure
            column is reserved inside the row, so a leaf keeps its empty disclosure slot.
   The glyph ART is the consumer's (Phosphor Light on the reference page); this block draws boxes,
   never marks. Glyphs paint from currentColor, so forced colours remap them (GLY-10). */
.glyph-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:var(--space-1)}
.glyph-list>li{position:relative;display:grid;grid-template-columns:var(--glyph-slot) minmax(0,1fr);
  column-gap:var(--space-2);align-items:start}
.glyph-body{display:flex;flex-direction:column;gap:var(--space-1);min-width:0}
.glyph-slot{inline-size:var(--glyph-slot);block-size:1lh;display:flex;align-items:unsafe center;justify-content:unsafe center;color:var(--muted);border-radius:var(--radius-xs)}
.glyph-slot>svg{inline-size:var(--glyph-slot);block-size:var(--glyph-slot);fill:currentColor}
.glyph-slot--ordinal{display:flex;justify-content:flex-end;white-space:nowrap;font-variant-numeric:tabular-nums lining-nums}
.glyph-slot--ordinal,.glyph-slot--ordinal+.glyph-body{align-self:baseline}
.glyph-slot--wide{display:flex;justify-content:flex-end;align-items:unsafe center}
.glyph-slot--wide>svg{inline-size:auto;flex:none}
.glyph-control{position:absolute;inline-size:1px;block-size:1px;margin:0;overflow:hidden;clip-path:inset(50%)}
.glyph-control:focus-visible+.glyph-slot{outline:var(--stroke-focus) solid var(--c2);outline-offset:var(--stroke-regular)}
.glyph-control:not(:checked)+.glyph-slot>[data-state="on"],.glyph-control:checked+.glyph-slot>[data-state="off"]{display:none}
.glyph-control:checked+.glyph-slot{color:var(--ink)}
.glyph-line{display:flex;align-items:flex-start;gap:var(--space-2)}
.glyph-trail{margin-inline-start:auto;display:flex;align-items:center;gap:var(--space-2);block-size:1lh;flex:none;color:var(--muted)}
.glyph-list--tree>li{display:block}
.glyph-list--tree .glyph-list--tree{margin-top:var(--space-1);padding-inline-start:var(--glyph-unit)}
.glyph-row{display:grid;grid-template-columns:calc(2 * var(--glyph-slot)) minmax(0,1fr);column-gap:var(--space-2);
  align-items:start;list-style:none;cursor:pointer;color:inherit;text-decoration:none}
.glyph-row::-webkit-details-marker{display:none}
.glyph-pair{display:flex}
details[open]>.glyph-row .glyph-slot--disclosure>svg{rotate:90deg}

/* ── .foldout (+ .foldout-body) — a disclosure head with sibling acts (rebuild 7b round 5, 2026-10-16;
   T3 split from the operator district's op-tree-topic, geometry snapped from it so nothing moves).
   A wrapper holding a native <details> whose <summary> is the head's ONE toggle, then the head's acts
   (a link, a press) AFTER the details — never inside the summary: interactive content in a disclosure
   trigger is not legal HTML — then the folded content, .foldout-body, across the line beneath. DOM order
   is summary · acts · body, so reading order is focus order (WCAG 2.4.3 · 1.3.2). The toggle stays the
   platform's: the expanded state is the details element's own. Three columns — the head shrinks to its
   words, the first act takes the room, a last act keeps its width. The closed rule sits inside :where() so
   it adds nothing above (0,1,0) per part: the operator district's HIDDEN MEANS HIDDEN ceiling for display
   selectors is (0,3,0), and a brand-core rule must never out-specify a consumer's hidden state.
   Not `.disclosure` — that is the evidence control's announcement convention (a register on a summary or
   an anchor); this is a head's geometry, and a .disclosure summary may sit inside it. `fold` was refused as
   the name: field/spike-13-ladder.html links this sheet and authors details.fold. */
.foldout{display:grid;grid-template-columns:minmax(0,max-content) minmax(0,1fr) auto;
  align-items:center;column-gap:var(--space-2)}
.foldout>details{grid-column:1;grid-row:1;min-width:0}
.foldout>.foldout-body{grid-column:1 / -1;grid-row:2}
:where(.foldout:has(> details:not([open])))>.foldout-body{display: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-regular 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-regular);
  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 (Feather's value has since
   moved to the floor, 5.28:1 — § tokens, 2026-09-13 — because the OPERATOR district spends the alias
   as a label; the brand-core role assignment here is unchanged). `--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-regular) 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-regular -> --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-regular` 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-regular 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.
   `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.
   T15 (2026-10-07) RULED THE AXIS, and this rule followed it two ways. (1) The inert
   `border-width:var(--stroke-bold)` is GONE: a fractional stroke never feeds a snapping property
   (gate stroke-never-snaps), and it had only ever computed 1px. (2) The doubled edge is KEPT AS IT
   RENDERS — 1px border + 1px inset = 2px — rather than moved onto bold (1.728) or black (2.488):
   which stop a fault edge wears is a look, not a migration, and a fault channel is not the place to
   change one silently. The two-regular form is what ships until Aaron picks a stop. */
input[aria-invalid="true"],textarea[aria-invalid="true"]{
  border-color:var(--error);
  box-shadow:inset 0 0 0 var(--stroke-regular) 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),background-color var(--dur-base) var(--ease),color var(--dur-slow) var(--ease)}
/* HOVER IS A PLANE AND AN EDGE, NEVER A LIFT (3e834c, Aaron 2026-09-29, Q2 on 67899b; PMO b7c147cc).
   `translateY(-1px)` read as a float against "nothing floats"; the control now answers the pointer the
   way .panel does — its edge takes the c3 mix — and steps one plane up (surface → raised). :active
   returns the plane. No transform anywhere in the control. */
.btn:hover{background-color:var(--raised);border-color:color-mix(in oklab,var(--c3) 45%,var(--hairline))}
.btn:active{background-color:var(--surface)}
.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 */
/* THE FEATHER STOP UNDER THE LABEL (3e834c, Aaron 2026-09-29, Q4 on 67899b; PMO f583404f). Feather's
   paper-toned label (--ground) over the radial ramp measured 4.13:1 at its worst pixel (mark-contrast,
   gradient-text) — under AA at 18px bold. Ruled: a shallower Feather ramp stop under the label, the type
   scale untouched. Realized as ONE layer over the ramp — --ink at --btn-bold-deepen, which moves every
   stop the same step toward ink so the ramp's order and hues hold — keyed by a token that is 0% in
   Aurora (its label already clears) and CANDIDATE in Feather, Aaron's to tune at the step's check. */
.btn-bold{border-color:transparent;
  background:linear-gradient(color-mix(in oklab,var(--ink) var(--btn-bold-deepen),transparent),color-mix(in oklab,var(--ink) var(--btn-bold-deepen),transparent)),var(--ramp-radial);
  color:var(--ground);font-weight:700}
/* the bold fill has no plane to step to, so its answer is the edge alone (Q2): the ink hairline */
.btn-bold:hover{border-color:var(--ink);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). */
/* The underline is a DISPLAY stroke that MIRRORS its text (ruled 2026-10-30, call 2): the sans stem × the
   text's own step (--type-weight-step, regular unless bold sets it), and hover adds three steps (× bold). */
.link{color:var(--ink);text-decoration:none;background-image:var(--ramp);
  background-size:100% calc(var(--stroke-display-stem-sans) * var(--type-weight-step,var(--stroke-display-regular)));
  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% calc(var(--stroke-display-stem-sans) * var(--type-weight-step,var(--stroke-display-regular)) * var(--stroke-display-bold))}
/* .trail-mark — a mark that trails a reference's words (rebuild 7b round 5, 2026-10-16; T3 split from the
   operator district's op-out, which composes this and re-sockets its icon tier; values snapped from it). An aria-hidden glyph AFTER a
   link's or a button's words, never leading them, in the reference's own ink, at the control icon step, one
   --space-1 after the words (the mark's own interior inset: an inline mark beside inline text). The
   destination it signals is in the reference's name or description, never in the mark.
   THE GLYPH IS SIZED HERE, ON THE SVG, AND THE TIER IS NOT RE-SOCKETED: --icon-md is declared exactly once in
   this sheet (icon-to-label-ratio counts it), so the mark draws its direct svg child at --icon-sm. At (0,1,1)
   that out-specifies a district icon class's own box. */
.trail-mark{display:inline-flex;flex:none;margin-inline-start:var(--space-1);color:currentColor}
.trail-mark>svg{inline-size:var(--icon-sm);block-size:var(--icon-sm);fill:currentColor}
/* ── `.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-regular);
  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:var(--stroke-focus) 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}

/* ── the print floor (G4, 2026-11-03, Steward slot 7b) ──────────────────────────────────────────────
   PAPER IS FEATHER. The light theme's planes and inks are the brand's paper reading; brand.js swaps
   data-theme to feather on `beforeprint` and restores it on `afterprint`, so Feather's tokens are reached
   through their one home rather than copied into this block (define-once). A headless render asks for
   `?theme=feather` itself. `print-color-adjust:economy` is DELIBERATE: the sheet of paper is the ground, so
   plane fills drop and only ink and images print.
   ON PAPER: the interactive chrome goes (rail, theme toggle, skip link); the masthead stops being sticky
   and translucent; no ramp fills (`.link` and `.shimmer` fall back to plain ink with a real underline);
   motion-gated content is shown, never left at its pre-reveal opacity; a figure, a terms row and a panel
   never split across a page; a heading never ends a page. One surface's own print choices (what IT hides)
   stay in its own sheet under @media print. Gated: `print-floor` (qa/check.mjs) + the portfolio's
   computed print row. */
@media print{
  html{print-color-adjust:economy;-webkit-print-color-adjust:economy}
  .rail,.toggle,.skip-link{display:none}
  .masthead{position:static;backdrop-filter:none;background:none}
  .link{background-image:none;text-decoration:underline;text-decoration-thickness:var(--stroke-regular)}
  .shimmer{background:none;-webkit-text-fill-color:currentColor;color:var(--ink)}
  .reveal{opacity:1;transform:none}
  .figure,.terms-row,.panel{break-inside:avoid}
  h1,h2,h3,.h2,.page-subhead{break-after:avoid}
}

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

/* @generated color-families:rules — do not hand-edit; source: color-families/rules.json via emit.mjs. OFF BY DEFAULT: every rule is scoped to :root[data-color-rules="on"] (RULES-CODIFICATION § 9). */
:root[data-color-rules="on"]{--c1:#ED68B5;--c2:#916EF2;--c3:#5C7EFF;--c4:#43C7E3;--c5:#33D29E;--success:#4BD18F;--warn:#E9A63D;--error:#FA6A6F;--ink:#F1F2F6;--ink-2:#C3BED0;--muted:#9B96A8;--muted-2:#848090;--hairline:#231F2F;--rule-hover:#413E4D;--op-rule-active:#5F5A6B;--btn-c2-hover:#AB94FB;--btn-c2-press:#C6BAFF;--success-text:#00A365;--warn-text:#B57C1F;--error-text:#EE3D4F;--success-icon:#4BD18F;--warn-icon:#E9A63D;--error-icon:#FA6A6F;--success-fill:#4BD18F;--on-success-fill:#1C1826;--warn-fill:#E9A63D;--on-warn-fill:#1C1826;--error-fill:#FA6A6F;--on-error-fill:#1C1826;--ramp:linear-gradient(120deg in oklch decreasing hue,var(--c1),var(--c2),var(--c3),var(--c4),var(--c5));--op-status-ok:var(--success-text);--op-status-warn:var(--warn-text);--op-status-error:var(--error-text)}
:root[data-color-rules="on"] [data-cr-plane="inset"]{--plane:#0A090E;--hairline:#1E1A29;--rule-hover:#3C3847;--op-rule-active:#595565;--btn-c2-hover:#AC96FB;--btn-c2-press:#C9BDFF;--success-text:#009B61;--warn-text:#AC771E;--error-text:#E4374A;--op-rule:var(--hairline);--op-spine:var(--hairline);--op-status-ok:var(--success-text);--op-status-warn:var(--warn-text);--op-status-error:var(--error-text);--op-syn-literal:var(--op-status-warn);--op-syn-invalid:var(--op-status-error);--op-syn-inserted:var(--op-status-ok);--op-syn-deleted:var(--op-status-error)}
:root[data-color-rules="on"] [data-cr-plane="ground"]{--plane:#0F0D13;--hairline:#231F2F;--rule-hover:#413E4D;--op-rule-active:#5F5A6B;--btn-c2-hover:#AB94FB;--btn-c2-press:#C6BAFF;--success-text:#00A365;--warn-text:#B57C1F;--error-text:#EE3D4F;--op-rule:var(--hairline);--op-spine:var(--hairline);--op-status-ok:var(--success-text);--op-status-warn:var(--warn-text);--op-status-error:var(--error-text);--op-syn-literal:var(--op-status-warn);--op-syn-invalid:var(--op-status-error);--op-syn-inserted:var(--op-status-ok);--op-syn-deleted:var(--op-status-error)}
:root[data-color-rules="on"] [data-cr-plane="surface"]{--plane:#15121B;--hairline:#2A2536;--rule-hover:#484454;--op-rule-active:#666272;--btn-c2-hover:#A992FA;--btn-c2-press:#C3B6FF;--success-text:#00AC6B;--warn-text:#BE8323;--error-text:#F34D59;--op-rule:var(--hairline);--op-spine:var(--hairline);--op-status-ok:var(--success-text);--op-status-warn:var(--warn-text);--op-status-error:var(--error-text);--op-syn-literal:var(--op-status-warn);--op-syn-invalid:var(--op-status-error);--op-syn-inserted:var(--op-status-ok);--op-syn-deleted:var(--op-status-error)}
:root[data-color-rules="on"] [data-cr-plane="raised"]{--plane:#1C1826;--hairline:#312D3D;--rule-hover:#504C5C;--op-rule-active:#6F6B7A;--btn-c2-hover:#A790FA;--btn-c2-press:#C0B1FF;--success-text:#00B772;--warn-text:#C98C2A;--error-text:#F76067;--op-rule:var(--hairline);--op-spine:var(--hairline);--op-status-ok:var(--success-text);--op-status-warn:var(--warn-text);--op-status-error:var(--error-text);--op-syn-literal:var(--op-status-warn);--op-syn-invalid:var(--op-status-error);--op-syn-inserted:var(--op-status-ok);--op-syn-deleted:var(--op-status-error)}
:root[data-color-rules="on"][data-theme="feather"]{--c1:#BB2B85;--c2:#784ED8;--c3:#4360E2;--c4:#057C9B;--c5:#008460;--success:#007346;--warn:#855C1B;--error:#C9263B;--ink:#0F0D13;--ink-2:#3E3A49;--muted:#5E5A6B;--muted-2:#6A6776;--hairline:#D6D4DF;--rule-hover:#B1ACBE;--op-rule-active:#8F8B9C;--btn-c2-hover:#622FBF;--btn-c2-press:#4D00A5;--success-text:#007548;--warn-text:#81591B;--error-text:#B51730;--success-icon:#007346;--warn-icon:#855C1B;--error-icon:#C9263B;--success-fill:#007346;--on-success-fill:#FFFFFF;--warn-fill:#855C1B;--on-warn-fill:#FFFFFF;--error-fill:#C9263B;--on-error-fill:#FFFFFF;--ramp:linear-gradient(120deg in oklch decreasing hue,var(--c1),var(--c2),var(--c3),var(--c4),var(--c5));--op-status-ok:var(--success-text);--op-status-warn:var(--warn-text);--op-status-error:var(--error-text)}
:root[data-color-rules="on"][data-theme="feather"] [data-cr-plane="inset"]{--plane:#E8E8EF;--hairline:#CDCAD8;--rule-hover:#A8A3B5;--op-rule-active:#878393;--btn-c2-hover:#6331C1;--btn-c2-press:#5002AB;--success-text:#006C42;--warn-text:#77521A;--error-text:#A90C2A;--op-rule:var(--hairline);--op-spine:var(--hairline);--op-status-ok:var(--success-text);--op-status-warn:var(--warn-text);--op-status-error:var(--error-text);--op-syn-literal:var(--op-status-warn);--op-syn-invalid:var(--op-status-error);--op-syn-inserted:var(--op-status-ok);--op-syn-deleted:var(--op-status-error)}
:root[data-color-rules="on"][data-theme="feather"] [data-cr-plane="ground"]{--plane:#F1F2F6;--hairline:#D6D4DF;--rule-hover:#B1ACBE;--op-rule-active:#8F8B9C;--btn-c2-hover:#622FBF;--btn-c2-press:#4D00A5;--success-text:#007548;--warn-text:#81591B;--error-text:#B51730;--op-rule:var(--hairline);--op-spine:var(--hairline);--op-status-ok:var(--success-text);--op-status-warn:var(--warn-text);--op-status-error:var(--error-text);--op-syn-literal:var(--op-status-warn);--op-syn-invalid:var(--op-status-error);--op-syn-inserted:var(--op-status-ok);--op-syn-deleted:var(--op-status-error)}
:root[data-color-rules="on"][data-theme="feather"] [data-cr-plane="surface"]{--plane:#FAFAFC;--hairline:#DEDCE5;--rule-hover:#B8B4C6;--op-rule-active:#9792A4;--btn-c2-hover:#612CBE;--btn-c2-press:#4A009F;--success-text:#007D4D;--warn-text:#8A601C;--error-text:#BF1F36;--op-rule:var(--hairline);--op-spine:var(--hairline);--op-status-ok:var(--success-text);--op-status-warn:var(--warn-text);--op-status-error:var(--error-text);--op-syn-literal:var(--op-status-warn);--op-syn-invalid:var(--op-status-error);--op-syn-inserted:var(--op-status-ok);--op-syn-deleted:var(--op-status-error)}
:root[data-color-rules="on"][data-theme="feather"] [data-cr-plane="raised"]{--plane:#FFFFFF;--hairline:#E3E1E9;--rule-hover:#BDB8CA;--op-rule-active:#9B97A9;--btn-c2-hover:#602BBD;--btn-c2-press:#48009C;--success-text:#008250;--warn-text:#90631C;--error-text:#C52339;--op-rule:var(--hairline);--op-spine:var(--hairline);--op-status-ok:var(--success-text);--op-status-warn:var(--warn-text);--op-status-error:var(--error-text);--op-syn-literal:var(--op-status-warn);--op-syn-invalid:var(--op-status-error);--op-syn-inserted:var(--op-status-ok);--op-syn-deleted:var(--op-status-error)}
:root[data-color-rules="on"][data-color-live="on"]{--plane:#0F0D13;--fam-magenta-L-max:0.975;--fam-magenta-L-root:0.635;--fam-magenta-L-min:0.185;--fam-magenta-C-max:0.03;--fam-magenta-C-root:0.2211;--fam-magenta-C-min:0.1005;--fam-magenta-h-max:347.3;--fam-magenta-h-root:347.3;--fam-magenta-h-min:347.3;--fam-magenta-C-of-l:calc(var(--fam-magenta-C-root) + clamp(0, (l - var(--fam-magenta-L-root)) / (var(--fam-magenta-L-max) - var(--fam-magenta-L-root)), 1) * (var(--fam-magenta-C-max) - var(--fam-magenta-C-root)) + clamp(0, (l - var(--fam-magenta-L-root)) / (var(--fam-magenta-L-min) - var(--fam-magenta-L-root)), 1) * (var(--fam-magenta-C-min) - var(--fam-magenta-C-root)));--fam-magenta-h-of-l:calc(var(--fam-magenta-h-root) + clamp(0, (l - var(--fam-magenta-L-root)) / (var(--fam-magenta-L-max) - var(--fam-magenta-L-root)), 1) * (var(--fam-magenta-h-max) - var(--fam-magenta-h-root)) + clamp(0, (l - var(--fam-magenta-L-root)) / (var(--fam-magenta-L-min) - var(--fam-magenta-L-root)), 1) * (var(--fam-magenta-h-min) - var(--fam-magenta-h-root)));--fam-violet-L-max:0.975;--fam-violet-L-root:0.635;--fam-violet-L-min:0.185;--fam-violet-C-max:0.03;--fam-violet-C-root:0.1904;--fam-violet-C-min:0.2371;--fam-violet-h-max:292.3;--fam-violet-h-root:292.3;--fam-violet-h-min:292.3;--fam-violet-C-of-l:calc(var(--fam-violet-C-root) + clamp(0, (l - var(--fam-violet-L-root)) / (var(--fam-violet-L-max) - var(--fam-violet-L-root)), 1) * (var(--fam-violet-C-max) - var(--fam-violet-C-root)) + clamp(0, (l - var(--fam-violet-L-root)) / (var(--fam-violet-L-min) - var(--fam-violet-L-root)), 1) * (var(--fam-violet-C-min) - var(--fam-violet-C-root)));--fam-violet-h-of-l:calc(var(--fam-violet-h-root) + clamp(0, (l - var(--fam-violet-L-root)) / (var(--fam-violet-L-max) - var(--fam-violet-L-root)), 1) * (var(--fam-violet-h-max) - var(--fam-violet-h-root)) + clamp(0, (l - var(--fam-violet-L-root)) / (var(--fam-violet-L-min) - var(--fam-violet-L-root)), 1) * (var(--fam-violet-h-min) - var(--fam-violet-h-root)));--fam-blue-L-max:0.975;--fam-blue-L-root:0.635;--fam-blue-L-min:0.185;--fam-blue-C-max:0.03;--fam-blue-C-root:0.1967;--fam-blue-C-min:0.2132;--fam-blue-h-max:269;--fam-blue-h-root:269;--fam-blue-h-min:269;--fam-blue-C-of-l:calc(var(--fam-blue-C-root) + clamp(0, (l - var(--fam-blue-L-root)) / (var(--fam-blue-L-max) - var(--fam-blue-L-root)), 1) * (var(--fam-blue-C-max) - var(--fam-blue-C-root)) + clamp(0, (l - var(--fam-blue-L-root)) / (var(--fam-blue-L-min) - var(--fam-blue-L-root)), 1) * (var(--fam-blue-C-min) - var(--fam-blue-C-root)));--fam-blue-h-of-l:calc(var(--fam-blue-h-root) + clamp(0, (l - var(--fam-blue-L-root)) / (var(--fam-blue-L-max) - var(--fam-blue-L-root)), 1) * (var(--fam-blue-h-max) - var(--fam-blue-h-root)) + clamp(0, (l - var(--fam-blue-L-root)) / (var(--fam-blue-L-min) - var(--fam-blue-L-root)), 1) * (var(--fam-blue-h-min) - var(--fam-blue-h-root)));--fam-cyan-L-max:0.975;--fam-cyan-L-root:0.635;--fam-cyan-L-min:0.185;--fam-cyan-C-max:0.1141;--fam-cyan-C-root:0.121;--fam-cyan-C-min:0.02;--fam-cyan-h-max:205;--fam-cyan-h-root:221;--fam-cyan-h-min:233.5;--fam-cyan-C-of-l:calc(var(--fam-cyan-C-root) + clamp(0, (l - var(--fam-cyan-L-root)) / (var(--fam-cyan-L-max) - var(--fam-cyan-L-root)), 1) * (var(--fam-cyan-C-max) - var(--fam-cyan-C-root)) + clamp(0, (l - var(--fam-cyan-L-root)) / (var(--fam-cyan-L-min) - var(--fam-cyan-L-root)), 1) * (var(--fam-cyan-C-min) - var(--fam-cyan-C-root)));--fam-cyan-h-of-l:calc(var(--fam-cyan-h-root) + clamp(0, (l - var(--fam-cyan-L-root)) / (var(--fam-cyan-L-max) - var(--fam-cyan-L-root)), 1) * (var(--fam-cyan-h-max) - var(--fam-cyan-h-root)) + clamp(0, (l - var(--fam-cyan-L-root)) / (var(--fam-cyan-L-min) - var(--fam-cyan-L-root)), 1) * (var(--fam-cyan-h-min) - var(--fam-cyan-h-root)));--fam-oil-L-max:0.975;--fam-oil-L-root:0.635;--fam-oil-L-min:0.185;--fam-oil-C-max:0.1626;--fam-oil-C-root:0.1388;--fam-oil-C-min:0.02;--fam-oil-h-max:165.7;--fam-oil-h-root:165.7;--fam-oil-h-min:165.7;--fam-oil-C-of-l:calc(var(--fam-oil-C-root) + clamp(0, (l - var(--fam-oil-L-root)) / (var(--fam-oil-L-max) - var(--fam-oil-L-root)), 1) * (var(--fam-oil-C-max) - var(--fam-oil-C-root)) + clamp(0, (l - var(--fam-oil-L-root)) / (var(--fam-oil-L-min) - var(--fam-oil-L-root)), 1) * (var(--fam-oil-C-min) - var(--fam-oil-C-root)));--fam-oil-h-of-l:calc(var(--fam-oil-h-root) + clamp(0, (l - var(--fam-oil-L-root)) / (var(--fam-oil-L-max) - var(--fam-oil-L-root)), 1) * (var(--fam-oil-h-max) - var(--fam-oil-h-root)) + clamp(0, (l - var(--fam-oil-L-root)) / (var(--fam-oil-L-min) - var(--fam-oil-L-root)), 1) * (var(--fam-oil-h-min) - var(--fam-oil-h-root)));--fam-success-L-max:0.975;--fam-success-L-root:0.635;--fam-success-L-min:0.185;--fam-success-C-max:0.1037;--fam-success-C-root:0.1828;--fam-success-C-min:0.02;--fam-success-h-max:158;--fam-success-h-root:158;--fam-success-h-min:158;--fam-success-C-of-l:calc(var(--fam-success-C-root) + clamp(0, (l - var(--fam-success-L-root)) / (var(--fam-success-L-max) - var(--fam-success-L-root)), 1) * (var(--fam-success-C-max) - var(--fam-success-C-root)) + clamp(0, (l - var(--fam-success-L-root)) / (var(--fam-success-L-min) - var(--fam-success-L-root)), 1) * (var(--fam-success-C-min) - var(--fam-success-C-root)));--fam-success-h-of-l:calc(var(--fam-success-h-root) + clamp(0, (l - var(--fam-success-L-root)) / (var(--fam-success-L-max) - var(--fam-success-L-root)), 1) * (var(--fam-success-h-max) - var(--fam-success-h-root)) + clamp(0, (l - var(--fam-success-L-root)) / (var(--fam-success-L-min) - var(--fam-success-L-root)), 1) * (var(--fam-success-h-min) - var(--fam-success-h-root)));--fam-warn-L-max:0.975;--fam-warn-L-root:0.635;--fam-warn-L-min:0.185;--fam-warn-C-max:0.1656;--fam-warn-C-root:0.1246;--fam-warn-C-min:0.02;--fam-warn-h-max:74.2;--fam-warn-h-root:74.2;--fam-warn-h-min:74.2;--fam-warn-C-of-l:calc(var(--fam-warn-C-root) + clamp(0, (l - var(--fam-warn-L-root)) / (var(--fam-warn-L-max) - var(--fam-warn-L-root)), 1) * (var(--fam-warn-C-max) - var(--fam-warn-C-root)) + clamp(0, (l - var(--fam-warn-L-root)) / (var(--fam-warn-L-min) - var(--fam-warn-L-root)), 1) * (var(--fam-warn-C-min) - var(--fam-warn-C-root)));--fam-warn-h-of-l:calc(var(--fam-warn-h-root) + clamp(0, (l - var(--fam-warn-L-root)) / (var(--fam-warn-L-max) - var(--fam-warn-L-root)), 1) * (var(--fam-warn-h-max) - var(--fam-warn-h-root)) + clamp(0, (l - var(--fam-warn-L-root)) / (var(--fam-warn-L-min) - var(--fam-warn-L-root)), 1) * (var(--fam-warn-h-min) - var(--fam-warn-h-root)));--fam-error-L-max:0.975;--fam-error-L-root:0.635;--fam-error-L-min:0.185;--fam-error-C-max:0.03;--fam-error-C-root:0.2128;--fam-error-C-min:0.1307;--fam-error-h-max:20.6;--fam-error-h-root:20.6;--fam-error-h-min:20.6;--fam-error-C-of-l:calc(var(--fam-error-C-root) + clamp(0, (l - var(--fam-error-L-root)) / (var(--fam-error-L-max) - var(--fam-error-L-root)), 1) * (var(--fam-error-C-max) - var(--fam-error-C-root)) + clamp(0, (l - var(--fam-error-L-root)) / (var(--fam-error-L-min) - var(--fam-error-L-root)), 1) * (var(--fam-error-C-min) - var(--fam-error-C-root)));--fam-error-h-of-l:calc(var(--fam-error-h-root) + clamp(0, (l - var(--fam-error-L-root)) / (var(--fam-error-L-max) - var(--fam-error-L-root)), 1) * (var(--fam-error-h-max) - var(--fam-error-h-root)) + clamp(0, (l - var(--fam-error-L-root)) / (var(--fam-error-L-min) - var(--fam-error-L-root)), 1) * (var(--fam-error-h-min) - var(--fam-error-h-root)));--cr-knob-hover-lift:1.2;--cr-knob-status-text:0.465;--cr-L-c2:0.635;--cr-L-warn:0.771;--cr-L-error:0.703;--btn-c2-hover:oklch(from oklch(from var(--plane) calc((l + var(--cr-knob-hover-lift) * (var(--cr-L-c2) - l))) 0 0) l var(--fam-violet-C-of-l) var(--fam-violet-h-of-l));--warn-text:oklch(from oklch(from var(--plane) calc((l + clamp(-1, (0.5 - l) * 1000000, 1) * var(--cr-knob-status-text))) 0 0) l var(--fam-warn-C-of-l) var(--fam-warn-h-of-l));--error-text:oklch(from oklch(from var(--plane) calc((l + clamp(-1, (0.5 - l) * 1000000, 1) * var(--cr-knob-status-text))) 0 0) l var(--fam-error-C-of-l) var(--fam-error-h-of-l));--warn-fill:oklch(from oklch(from var(--plane) calc(var(--cr-L-warn)) 0 0) l var(--fam-warn-C-of-l) var(--fam-warn-h-of-l));--error-fill:oklch(from oklch(from var(--plane) calc(var(--cr-L-error)) 0 0) l var(--fam-error-C-of-l) var(--fam-error-h-of-l))}
:root[data-color-rules="on"][data-color-live="on"][data-theme="feather"]{--plane:#F1F2F6;--cr-L-c2:0.545;--cr-L-warn:0.508;--cr-L-error:0.545;--btn-c2-hover:oklch(from oklch(from var(--plane) calc((l + var(--cr-knob-hover-lift) * (var(--cr-L-c2) - l))) 0 0) l var(--fam-violet-C-of-l) var(--fam-violet-h-of-l));--warn-text:oklch(from oklch(from var(--plane) calc((l + clamp(-1, (0.5 - l) * 1000000, 1) * var(--cr-knob-status-text))) 0 0) l var(--fam-warn-C-of-l) var(--fam-warn-h-of-l));--error-text:oklch(from oklch(from var(--plane) calc((l + clamp(-1, (0.5 - l) * 1000000, 1) * var(--cr-knob-status-text))) 0 0) l var(--fam-error-C-of-l) var(--fam-error-h-of-l));--warn-fill:oklch(from oklch(from var(--plane) calc(var(--cr-L-warn)) 0 0) l var(--fam-warn-C-of-l) var(--fam-warn-h-of-l));--error-fill:oklch(from oklch(from var(--plane) calc(var(--cr-L-error)) 0 0) l var(--fam-error-C-of-l) var(--fam-error-h-of-l))}
:root[data-color-rules="on"][data-color-live="on"] [data-cr-plane]{--btn-c2-hover:oklch(from oklch(from var(--plane) calc((l + var(--cr-knob-hover-lift) * (var(--cr-L-c2) - l))) 0 0) l var(--fam-violet-C-of-l) var(--fam-violet-h-of-l));--warn-text:oklch(from oklch(from var(--plane) calc((l + clamp(-1, (0.5 - l) * 1000000, 1) * var(--cr-knob-status-text))) 0 0) l var(--fam-warn-C-of-l) var(--fam-warn-h-of-l));--error-text:oklch(from oklch(from var(--plane) calc((l + clamp(-1, (0.5 - l) * 1000000, 1) * var(--cr-knob-status-text))) 0 0) l var(--fam-error-C-of-l) var(--fam-error-h-of-l));--warn-fill:oklch(from oklch(from var(--plane) calc(var(--cr-L-warn)) 0 0) l var(--fam-warn-C-of-l) var(--fam-warn-h-of-l));--error-fill:oklch(from oklch(from var(--plane) calc(var(--cr-L-error)) 0 0) l var(--fam-error-C-of-l) var(--fam-error-h-of-l))}
:root[data-color-rules="on"][data-color-live="on"] [data-fam-t]{--fam-magenta-at:oklch(from oklch(calc(var(--fam-magenta-L-root) + clamp(0, (5 - var(--fam-t)) / 5, 1) * (var(--fam-magenta-L-max) - var(--fam-magenta-L-root)) + clamp(0, (var(--fam-t) - 5) / 5, 1) * (var(--fam-magenta-L-min) - var(--fam-magenta-L-root))) 0 0) l var(--fam-magenta-C-of-l) var(--fam-magenta-h-of-l));--fam-violet-at:oklch(from oklch(calc(var(--fam-violet-L-root) + clamp(0, (5 - var(--fam-t)) / 5, 1) * (var(--fam-violet-L-max) - var(--fam-violet-L-root)) + clamp(0, (var(--fam-t) - 5) / 5, 1) * (var(--fam-violet-L-min) - var(--fam-violet-L-root))) 0 0) l var(--fam-violet-C-of-l) var(--fam-violet-h-of-l));--fam-blue-at:oklch(from oklch(calc(var(--fam-blue-L-root) + clamp(0, (5 - var(--fam-t)) / 5, 1) * (var(--fam-blue-L-max) - var(--fam-blue-L-root)) + clamp(0, (var(--fam-t) - 5) / 5, 1) * (var(--fam-blue-L-min) - var(--fam-blue-L-root))) 0 0) l var(--fam-blue-C-of-l) var(--fam-blue-h-of-l));--fam-cyan-at:oklch(from oklch(calc(var(--fam-cyan-L-root) + clamp(0, (5 - var(--fam-t)) / 5, 1) * (var(--fam-cyan-L-max) - var(--fam-cyan-L-root)) + clamp(0, (var(--fam-t) - 5) / 5, 1) * (var(--fam-cyan-L-min) - var(--fam-cyan-L-root))) 0 0) l var(--fam-cyan-C-of-l) var(--fam-cyan-h-of-l));--fam-oil-at:oklch(from oklch(calc(var(--fam-oil-L-root) + clamp(0, (5 - var(--fam-t)) / 5, 1) * (var(--fam-oil-L-max) - var(--fam-oil-L-root)) + clamp(0, (var(--fam-t) - 5) / 5, 1) * (var(--fam-oil-L-min) - var(--fam-oil-L-root))) 0 0) l var(--fam-oil-C-of-l) var(--fam-oil-h-of-l));--fam-success-at:oklch(from oklch(calc(var(--fam-success-L-root) + clamp(0, (5 - var(--fam-t)) / 5, 1) * (var(--fam-success-L-max) - var(--fam-success-L-root)) + clamp(0, (var(--fam-t) - 5) / 5, 1) * (var(--fam-success-L-min) - var(--fam-success-L-root))) 0 0) l var(--fam-success-C-of-l) var(--fam-success-h-of-l));--fam-warn-at:oklch(from oklch(calc(var(--fam-warn-L-root) + clamp(0, (5 - var(--fam-t)) / 5, 1) * (var(--fam-warn-L-max) - var(--fam-warn-L-root)) + clamp(0, (var(--fam-t) - 5) / 5, 1) * (var(--fam-warn-L-min) - var(--fam-warn-L-root))) 0 0) l var(--fam-warn-C-of-l) var(--fam-warn-h-of-l));--fam-error-at:oklch(from oklch(calc(var(--fam-error-L-root) + clamp(0, (5 - var(--fam-t)) / 5, 1) * (var(--fam-error-L-max) - var(--fam-error-L-root)) + clamp(0, (var(--fam-t) - 5) / 5, 1) * (var(--fam-error-L-min) - var(--fam-error-L-root))) 0 0) l var(--fam-error-C-of-l) var(--fam-error-h-of-l))}
/* @end color-families:rules */
