/*§RUN§[70,"\n",3505,"\n",46843]§*/html,body{height:100%;margin:0}#dc-root,#dc-root>.sc-host{height:100%}/**
 * faces.css — the two type families `tokens.css` names, actually delivered.
 * `CONTRACT-Webfont-16AUG.md`. Self-hosted, `public/fonts/PROVENANCE.md` records the source.
 *
 * ⛔ §0's defect, measured three ways before this file existed: zero `@font-face` anywhere in
 * `src/`, zero font integration in `astro.config`/`package.json`, zero `.woff2` hits in `dist/`
 * — the built output, which is the check that would have caught it. `tokens.css` has named
 * `"Geist"` and `"Geist Mono"` since it was written; every page has rendered in the `system-ui` /
 * `ui-monospace` fallback the whole time.
 *
 * ⛔⛔ SCOPE, deliberately narrow — §1. Three Geist weights, two Geist Mono weights: exactly
 * what `--type-*-weight` publishes today. NOT Geist 700 (loaded by the drawing, used by no rule
 * this project has). Shipping a weight nothing uses is the font-file version of the 51 inert
 * `60ch` declarations design struck the same day this contract was written.
 *
 * ⛔ `font-display: swap`, never `optional` — `optional` can drop the face entirely on a slow
 * connection, which reintroduces the exact fallback this file exists to remove.
 *
 * ⭐ `CONTRACT-Serif-16AUG.md` adds "Newsreader" below, ROMAN and ITALIC, both the `opsz` variable
 * file (NOT the smaller `wght`-only file — the optical axis is the entire reason this face is
 * variable at all) clamped to `font-weight: 400`, the one weight design's corpus draws.
 *
 * ⭐⭐ `CONTRACT-Optimize-14SEP.md` addendum 2 criterion 3, 17 Sep 2026: the two files at
 * `/fonts/Newsreader-{Roman,Italic}.woff2` are now `fontTools.varLib.instancer wght=400` output
 * — the `wght` axis (200-800, never set by any rule) is pinned OUT of the font itself rather than
 * only clamped by this `@font-face` block, and `opsz` (6-72, the axis this face exists for) is
 * kept, at the same served address (no manifest tracks `public/fonts`, so no new address is
 * owed) and the same 224-character set. Roman 132,000 → 57,608 B, Italic 146,872 → 63,544 B. A
 * computed-style scan of the built site (FINDING-Speed-16SEP.md, confirmed again by this round)
 * found 0 elements setting Newsreader to a weight or `font-variation-settings` other than what
 * this file already declares, so pinning the axis in the file changes no rendered page.
 */

@font-face {
  font-family: "Geist";
  src: url("/fonts/Geist-Regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Geist";
  src: url("/fonts/Geist-Medium.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Geist";
  src: url("/fonts/Geist-SemiBold.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Geist Mono";
  src: url("/fonts/GeistMono-Regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Geist Mono";
  src: url("/fonts/GeistMono-Medium.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Newsreader";
  src: url("/fonts/Newsreader-Roman.woff2") format("woff2-variations");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Newsreader";
  src: url("/fonts/Newsreader-Italic.woff2") format("woff2-variations");
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}

    .sc-placeholder{background:color-mix(in srgb,currentColor 8%,transparent);
      border:1px solid color-mix(in srgb,currentColor 50%,transparent);
      border-radius:2px;box-sizing:border-box;overflow:hidden}
    @keyframes sc-shine{0%{background-position:100% 50%}100%{background-position:0% 50%}}
    html.sc-dc-streaming .sc-placeholder,
    html.sc-dc-streaming .sc-interp.sc-missing{position:relative;
      background:color-mix(in srgb,currentColor 5%,transparent);
      border-color:transparent}
    html.sc-dc-streaming .sc-placeholder::before,
    html.sc-dc-streaming .sc-interp.sc-missing::before{content:'';
      position:absolute;inset:0;pointer-events:none;
      background:linear-gradient(90deg,rgba(217,119,87,0) 25%,rgba(247,225,211,.95) 37%,rgba(217,119,87,0) 63%);
      background-size:400% 100%;animation:sc-shine 1.4s ease infinite}
    html.sc-dc-streaming .sc-placeholder:nth-child(n+9 of .sc-placeholder)::before,
    html.sc-dc-streaming .sc-interp.sc-missing:nth-child(n+9 of .sc-interp.sc-missing)::before{animation:none;
      background:color-mix(in srgb,currentColor 8%,transparent)}
    .sc-placeholder-error{padding:4px 8px;font:11px/1.4 ui-monospace,monospace;
      color:color-mix(in srgb,currentColor 70%,transparent);word-break:break-word}
    .sc-interp.sc-missing{display:inline-block;width:2em;height:1em;overflow:hidden;
      vertical-align:text-bottom;background:rgba(255,255,255,.3);border:1px solid rgba(0,0,0,.5);
      border-radius:2px;box-sizing:border-box;color:transparent;
      user-select:none}
    .sc-interp.sc-unresolved{font-family:ui-monospace,monospace;font-size:.85em;
      color:color-mix(in srgb,currentColor 50%,transparent);
      background:color-mix(in srgb,currentColor 10%,transparent);border-radius:3px;
      padding:0 3px}
    .sc-host.sc-has-error{position:relative}
    .sc-logic-error{position:absolute;top:8px;left:8px;z-index:2147483647;max-width:60ch;
      padding:6px 10px;background:#b00020;color:#fff;font:12px/1.4 ui-monospace,monospace;
      border-radius:4px;white-space:pre-wrap;pointer-events:none}
    /* Mirrors PRINT_BASELINE_CSS in apps/web deck-stage-export.ts — keep both
       in sync until dc-runtime regains a build step. */
    @media print {
      @page { margin: 0.5cm; }
      figure, table { break-inside: avoid; }
      #dc-root, #dc-root > .sc-host { height: auto; }
      *, *::before, *::after {
        print-color-adjust: exact; -webkit-print-color-adjust: exact;
        backdrop-filter: none !important; -webkit-backdrop-filter: none !important;
        animation-delay: -99s !important; animation-duration: .001s !important;
        animation-iteration-count: 1 !important; animation-fill-mode: both !important;
        animation-play-state: running !important; transition-duration: 0s !important;
      }
    }
  
x-dc{display:none!important}

/**
 * cc-tokens.css — the shared token layer, one copy for every drawing (brief 119, drafted by Claude Code, 15 Sep 2026).
 *
 * Step 1 of Ryan's trial (D1 A, then his "A" on 15 Sep): these are CC Shell Header's own token lines, moved here
 * verbatim, byte for byte, and the header now links this file instead of declaring them. Nothing else links it yet.
 * Once Ryan has reviewed the header in the editor, the other drawings link it too and their own copies go.
 * ⚠️ 16 names carry two or three values across the drawings today (--ground, --surface, --rule, --edge, --stroke,
 * --caption, --quiet, --meta, --lede, --ink, --loud, --gutter and four --accent-* steps); those are settled with
 * design before a second drawing links this file, never picked silently here.
 */

:root { --gutter-window:clamp(16px, 3.5443cqw + 2.18px, 44px); --gutter:var(--gutter-window); --space-apart:24px; --space-inset:16px; --space-bound:8px; --space-block:44px; --space-tight:4px; } /* ⭐ DECLARED brief 84 §2 — this drawing's own line, no longer an injection (was brief 48 A1). Transcribed from FOUNDATION: spacing and measure. ⭐ brief 86 §1 — --gutter's published value now lives in --gutter-window and --gutter reads it; same computed value, no second copy of the clamp, and the measure override on the chrome root has a name to reference. */
:root { --type-close-esc:10.5px; } /* ⭐ brief 62 §2 — published: off both --type-label (9.504px/400/.14em) and --type-micro (9.5px/400/.06em), a real third mono-caps size, not a rounding of either. */
:root { --ground:#0C0F12; --surface:#14171B; --panel:#1C2028; --rule:#272A2F; --caption:#7B8187; --quiet:#8E949C; --ink:#D6D9DE; --loud:#F5F7F9; } /* ⭐ DECLARED brief 84 §1 — this drawing's own line, no longer an injection (was brief 47 A1). Transcribed from FOUNDATION's neutral ramp. */
:root { --edge:#3F4348; } /* ⭐ brief 120 Part 3 (row 1977; Claude Code, 15 Sep, Ryan's A): CC Shell Header's search-overlay close button paints var(--edge) and nothing declared it. #3F4348 is the value the site has shipped since 11 Sep, and CC: Loadout's own ramp carries it. One of the 16 two-valued names brief 119 settles before a second drawing links this file. */
:root { --meta:#A4AAB1; } /* Declared once here (Ryan's yes, 17 Sep 2026). Every other drawing that paints var(--meta) declares this same #A4AAB1, so none of them changes. CC: Gathering declared none after linking this file, so its meta text lost its colour; this restores the value the site ships. */


/* ⛔ REALM IS INHERITED, NEVER A PROP — tokens.css §48.11, ruled 15 Aug. What follows is a
   TRANSCRIPT of the token layer so this component draws standalone, keyed to `data-realm` on
   an ANCESTOR, which is the only thing that may set a realm. ⭐ SiteHeader declares no accent
   value of its own and takes no realm: the second ladder, and REALMS[].hue with it, is gone. */
:root, [data-realm] {
  --accent-hue-oklch: 90;
  --accent-wash:  oklch(0.222 0.028 var(--accent-hue-oklch));
  --accent-ring:  oklch(0.300 0.060 var(--accent-hue-oklch));
  --accent-rule:  oklch(0.450 0.090 var(--accent-hue-oklch));
  --accent-base:  oklch(0.750 0.125 var(--accent-hue-oklch));
  --accent-press: oklch(0.660 0.125 var(--accent-hue-oklch));
  --accent-lift:  oklch(0.860 0.055 var(--accent-hue-oklch));
  --chrome-gold:  oklch(0.750 0.125 90);
  /* Facts ABOUT a realm, never the page's cast — the class matrix and the result chip.
     ⭐ brief 88 §1 — and, from today, the realm SELECTOR's matched set: it names the realm the
     reader chose, which need not be the realm the page is cast in. */
  --realm-arthurian: oklch(0.750 0.125  25);
  --realm-tuatha:    oklch(0.750 0.125 160);
  --realm-viking:    oklch(0.750 0.125 250);
  /* ⚠️ brief 88 §1, MY ONE DEVIATION FROM THE WORDING, declared. The amendment says the divider
     hairline takes --realm-*, but that is the ladder's BASE step (L 0.750 / C 0.125) and the
     seam was drawn at its RING step (--accent-ring, L 0.300 / C 0.060) — a 1px full-chroma line
     across the whole window is not a hairline, it is a rule. These three are the ring step at
     each realm's hue, transcribed off the same ladder --accent-ring comes from, so the seam
     takes the CHOSEN realm as ruled and keeps the weight it was drawn at. ⏳ To take the
     wording literally instead, point the seam at --realm-* and delete these three. */
  --realm-ring-arthurian: oklch(0.300 0.060  25);
  --realm-ring-tuatha:    oklch(0.300 0.060 160);
  --realm-ring-viking:    oklch(0.300 0.060 250);
}
[data-realm="arthurian"]        { --accent-hue-oklch:  25; }
[data-realm="tuatha-de-danann"] { --accent-hue-oklch: 160; }
[data-realm="viking"]           { --accent-hue-oklch: 250; }

/* Failure: the failed-link underline and the notice edge. Every drawing already paints
   var(--danger, oklch(0.660 0.170 22)); declared once here (Ryan, 15 Sep 2026). */
:root { --danger: oklch(0.660 0.170 22); }


  :root { --gutter:clamp(16px, 3.5443cqw + 2.18px, 44px); --section:clamp(44px, 5.5696cqw + 22.28px, 88px); } /* ⭐ DECLARED brief 84 §2 — this drawing's own line, no longer an injection (was brief 48 A1). Transcribed from FOUNDATION: spacing and measure. */
  body { margin:0; background:var(--ground); color:var(--ink); font-family:'Geist', system-ui, sans-serif; -webkit-font-smoothing:antialiased; }
  * { box-sizing:border-box; }
  /* The accent ladder, declared once. ⭐ This page is realm-NEUTRAL, so its gold IS the
     accent at the default cast (hue 90); chrome that must never cast is the shell's
     --chrome-gold and lives in the two chrome components, not here. */
  /* ⛔ brief 95 §2 · THIS RULE CANNOT REACH A LINK THAT STATES ITS OWN COLOUR. An inline
     `color:` beats a stylesheet `a:hover`, so every anchor drawn with an inline rest ink needs
     its own style-hover — which is why the breadcrumb's Codex read as inert while the anchors
     that inherit this rule did not. Both crumbs carry their hover on the element now. */
  a { color:var(--accent-base); text-decoration:none; }
  a:hover { color:var(--accent-lift); }

  /* ⭐ 22 Sep · MOBILE PAIR 14 — PHONE ONLY, below 900cqw. The eight other benches wrapped as
     chips on 8px gaps, none of them 44 tall and each a different height depending on whether it
     carried a mark — a ragged block where taps land between chips. Below 900 they are one
     full-width 44-tall row each, on the site's own 1px hairline rather than 8px of loose air.
     ⛔ Ruled 22 Sep (Q10): the names stay WHOLE. One column costs 174px more page than a two-up
     grid, which is the price of not having one surface call a bench by a shorter name than every
     other surface does. ⭐ !important because the chips state their gap and padding inline. */
  @container (max-width: 900px) {
    [data-cc-benches] { flex-direction:column; gap:1px !important; background:var(--rule); }
    [data-cc-benches] > a { min-height:44px; padding:0 var(--space-inset) !important; }
  }

  /* ══ brief 100 §2.3 · THE TWO CHIP GROUPS, AND WHAT THEY SHOW ═════════════════════════════
     Mode and realm are radio groups; both panes and every realm group are in the drawn page.
     The keys here are this file's own constants (craft/refine, and RL's four ids), not data, so
     enumerating them is a rule and not a copy of a record. ⛔ No inline display on a pane or a
     ladder group — an inline value outranks these rules. */
  input[data-cc-native] { position:absolute; width:1px; height:1px; opacity:0; margin:0; pointer-events:none; }
  [data-cc-tab] { background:transparent; color:#A4AAB1; }
  [data-cc-tab] [data-cc-tab-count] { color:#6f767d; }
  [data-cc-tab]:hover { background:var(--surface); }
  [data-cc-tab]:has(input:checked) { background:var(--surface); color:var(--loud); }
  [data-cc-tab]:has(input:checked) [data-cc-tab-count] { color:var(--accent-base); }
  [data-cc-tab]:has(input:focus-visible) { outline:2px solid var(--quiet); outline-offset:2px; }

  /* A pane shows when its mode is checked AND the station has that mode at all. */
  [data-cc-pane] { display:none; }
  :root:has(#cc-cs-mode-craft:checked)  [data-cc-pane="craft"][data-cc-has="yes"],
  :root:has(#cc-cs-mode-refine:checked) [data-cc-pane="refine"][data-cc-has="yes"] { display:block; }

  /* A ladder group shows under its own realm's chip and under All; a cross-realm group shows
     under every chip, which is the rule the deleted .filter() held. */
  [data-cc-lrealm] { display:none; }
  :root:has(#cc-cs-realm-all:checked) [data-cc-lrealm],
  :root:has(#cc-cs-realm-arthurian:checked) [data-cc-lrealm="arthurian"],
  :root:has(#cc-cs-realm-tdd:checked)       [data-cc-lrealm="tdd"],
  :root:has(#cc-cs-realm-viking:checked)    [data-cc-lrealm="viking"],
  :root:has(#cc-cs-realm-arthurian:checked) [data-cc-lrealm="cross-realm"],
  :root:has(#cc-cs-realm-tdd:checked)       [data-cc-lrealm="cross-realm"],
  :root:has(#cc-cs-realm-viking:checked)    [data-cc-lrealm="cross-realm"] { display:block; }

  /* ⭐ brief 101 §1.27 · THE EMPTY RESULT IS A TYPED LINE, NOT A VANISHED SECTION. A realm the
     bench holds no recipes for — no band of its own AND no cross-realm band to fall back on —
     draws one line under the chip instead of an empty pane. ⛔ Only the realms that are
     genuinely empty are drawn (the logic computes them), so this rule only has to decide which
     chip is checked. */
  /* ══ brief 103 §1d · WHERE THE RECIPE ROW STOPS BEING COLUMNS ═══════════════════════════════
     Five columns do not fit a phone. At 390 the Item track was 70px, so "Recruit's Warhammer"
     printed straight over the 1.1 beside it, and the Inputs chips ran off the right edge of a
     page that clips. Below 760 of container the row is three lines instead of five columns —
     the name, then the row's own figures, then the inputs — and the column head goes, because a
     head names columns and there are none. ⛔ Nothing is dropped: every field a reader had at
     1440 is still on the row at 390. ⭐ !important because the row states its template inline,
     and an inline value outranks a rule; this is the same spelling CC Shell Header's matrix
     fold uses. */
  @container (max-width: 760px) {
    [data-cc-head="craft"], [data-cc-head="refine"] { display:none !important; }
    [data-cc-row="craft"] {
      grid-template-columns:auto auto minmax(0,1fr) !important;
      row-gap:var(--space-bound) !important;
      align-items:baseline !important;
    }
    [data-cc-row="craft"] [data-cc-cell="item"]   { grid-column:1 / -1; grid-row:1; }
    [data-cc-row="craft"] [data-cc-cell="ts"]     { grid-column:1; grid-row:2; }
    [data-cc-row="craft"] [data-cc-cell="slot"]   { grid-column:2; grid-row:2; }
    [data-cc-row="craft"] [data-cc-cell="level"]  { grid-column:3; grid-row:2; }
    [data-cc-row="craft"] [data-cc-cell="inputs"] { grid-column:1 / -1; grid-row:3; }
    /* The refining row is the same object one column shorter, so it folds the same way. */
    [data-cc-row="refine"] {
      grid-template-columns:minmax(0,1fr) auto !important;
      row-gap:var(--space-bound) !important;
      align-items:baseline !important;
    }
    [data-cc-row="refine"] [data-cc-cell="item"]   { grid-column:1; grid-row:1; }
    [data-cc-row="refine"] [data-cc-cell="level"]  { grid-column:2; grid-row:1; }
    [data-cc-row="refine"] [data-cc-cell="inputs"] { grid-column:1 / -1; grid-row:2; }
    [data-cc-row="refine"] [data-cc-cell="feeds"]  { grid-column:1 / -1; grid-row:3; }
  }

  /* ⛔ 23 Sep · CONTRACT-MobileApply-22SEP.md criterion 14 — THIS PAGE'S TWO PROSE LINKS, which
     the 22 Sep pass did not touch at all: "the Forge →" (86.6 × 21, the last words of the paired-
     bench sentence) and "← Crafting" (71.5 × 19, the way back up, alone in its own paragraph).
     Both are text inside prose, so what they owe is 44 of HEIGHT — a sentence's own width is the
     measure's, not a control's (Plan's call, Addendum 3). Vertical padding on an INLINE box is
     the way to buy that: it is hit-tested and painted, and it does not enter the line box, so the
     paragraph's rhythm is untouched and nothing moves at any width. `display:inline-block` would
     have bought the same target and dropped "the Forge →" out of its own sentence's baseline.
     ⭐ Scoped to the phone container like every other pair in this drawing, so a pointer width is
     provably untouched rather than argued to be. */
  @container (max-width: 900px) {
    /* 13, not 12: "← Crafting" sets on a 19px line and 19 + 24 lands at 43. Measured, not
       assumed — the first pass here used 12 and the sweep caught it one pixel short. */
    [data-screen-label="Mode lead"] p a,
    [data-screen-label="Other benches"] p a { padding-block:13px; }

    /* ⛔ 23 Sep · CONTRACT-MobileApply-22SEP.md criterion 25 — THE STATION THE MEASURE FILES NEVER
       SAMPLED. They measured /crafting/blacksmithing, which has no Refine mode, so /crafting/forge
       carried 31 targets under 44 that no file named: the Mode lead's "Feeds" chips, 7 at 138–211 ×
       30, and the Refine mode's station links, 24 at 106–164 × 18 — each a standalone link to
       another station, in a chip row or a list cell, never in a sentence. All nine station pages
       carry both bands in markup; only forge renders them, so this is one page's worth of targets
       and every page's worth of rule. The chips and links are already inline-flex, so height is all
       they need. */
    [data-cc-feedchips] a,
    [data-cc-cell="feeds"] a { min-height:44px; }
  }

  [data-cc-lempty] { display:none; }
  :root:has(#cc-cs-realm-arthurian:checked) [data-cc-lempty="arthurian"],
  :root:has(#cc-cs-realm-tdd:checked)       [data-cc-lempty="tdd"],
  :root:has(#cc-cs-realm-viking:checked)    [data-cc-lempty="viking"] { display:flex; }


  /* ⭐ brief 119, 15 Sep 2026 — the token lines that stood here (spacing, --type-close-esc, the neutral ramp, and the realm-keyed accent ladder with its three realm selectors) moved verbatim to ./cc-tokens.css, linked above. Values unchanged. */
  /* ⛔ NOT a bare `a` selector. A helmet stylesheet is global and this component is
     IMPORTED, so a bare rule here outranks the host page's own by mount order and decides
     link colour for every link on the page. Scoped to this component's own root instead. */
  [data-cc-chrome="header"] a { color:var(--ink); text-decoration:none; }
  [data-cc-chrome="header"] a:hover { color:var(--loud); }

  /* ⛔ caret-color was --chrome, which is the focus ring and only the focus ring. Removed:
     the field's caret is currentColor, which is --loud, the ink already in the box. */
  input.cc-q { all:unset; flex:1 1 auto; min-width:0; font-family:'Geist', system-ui, sans-serif; color:var(--loud); }
  input.cc-q::placeholder { color:#A4AAB1; }
  /* ⛔ The search field carries NO ring and NO border in any state — ground and ink only.
     ⭐ AND THE SEARCH BAR IS THE WHOLE ROW: everything above the divider is one object, so
     the ground change belongs to the row, not to a box inside it. A 564-wide well sitting in
     a wider row drew exactly the edge the no-border rule exists to avoid — it just drew it
     in ground instead of in stroke. The measure governs the RESULTS below the divider; the
     bar itself is full-bleed, and its close affordance is part of it.
     `all:unset` does not remove the UA focus outline, so focus was also drawing a bright box
     around the flex area. Now: focus deepens the row and lifts the placeholder to --lede. */
  input.cc-q:focus, input.cc-q:focus-visible { outline:none; box-shadow:none; }
  /* ⭐ brief 61 §5 — was raw #080A0D. Now the published --state-recess relation: a flat
     30% black veil over whatever ground sits beneath, same shape as the hover lift. */
  [data-searchrow]:focus-within { background:color-mix(in srgb, black 30%, var(--ground)) !important; }
  [data-searchrow]:focus-within input.cc-q::placeholder { color:#C7CCD1; }

  /* ── the chrome's own four rules · sweep, 16 Aug ─────────────────────────────────
     ⭐ ONE rule each for the button reset, the tint, the ring and the guard. Written
     here rather than inline because the alternative is 16 decisions in this file and 161
     across the corpus, and because a per-element hover is 16 places for the next one to
     drift. ⛔ This is the only thing in the file that could not be an inline style. */
  [data-cc-chrome="header"] {
    --chrome:#CFD6DE; --focus-ring-width:2px; --focus-ring-offset:2px;
    --motion-tint:160ms; --motion-settle:260ms; --motion-drift:420ms;
  }
  /* ⛔⛔ The two layout groups are collapsed to 0 by a clamp and clipped, which hides them
     from the EYE and not from the TAB ORDER — harmless while they were spans, a defect the
     moment they became real controls. A phone reader would tab seven invisible desktop
     controls, Sign in and the search trigger among them, before reaching anything drawn.
     ⭐ visibility:hidden takes them out of the tab order and the a11y tree; the clamp still
     owns the layout, so no dimension moves. Two queries, not fourteen attributes. */
  @container (max-width: 899.98px) { [data-cc-chrome="header"] [data-cc-group="desktop"] { visibility:hidden; } }
  @container (min-width: 900px)    { [data-cc-chrome="header"] [data-cc-group="mobile"]  { visibility:hidden; } }

  /* ⛔ 23 Sep · CONTRACT-MobileApply-22SEP.md criterion 21 — ONE SHAPE, SWEPT, NOT ONE INSTANCE.
     Pair 01 made the mark's anchor a 44-tall flex box below 900 with every size term clamped to 0
     above it — and left `display:flex; align-items:center` unconditional. Above 900 the box stays
     39.08 × 24 either way, which is why pass 2 could only declare it an exception rather than call it
     a defect; but it is the same shape as criterion 16's back link and criterion 20's name links,
     and the sweep scopes every instance of the shape rather than excusing the ones that happen to
     paint nothing. The anchor keeps main's `display:block`, and flex moves in here — both
     declared in this sheet and neither inline, because an inline `display` would outrank the query. */
  [data-cc-chrome="header"] [data-cc-logolink] { display:block; }
  @container (max-width: 899.98px) { [data-cc-chrome="header"] [data-cc-logolink] { display:flex; align-items:center; } }

  [data-cc-chrome="header"] button {
    appearance:none; -webkit-appearance:none; background:none; border:0; margin:0;
    padding:0; font:inherit; color:inherit; text-align:left;
  }
  /* tint · 160ms ease. ⛔ Colour only — the chrome draws no settle, drift or ambient. */
  [data-cc-chrome="header"] a,
  [data-cc-chrome="header"] button {
    transition: color var(--motion-tint) ease, background-color var(--motion-tint) ease;
  }
  /* ⭐ Focus DRAWN as a state rather than left to the standard.
     ⛔ `input:focus-visible` WAS in this list, on the reasoning that `all:unset` had removed
     the field's ring and the ring had to come back. Removed 15 Aug: the search bar's states
     are ground and ink only, so the ring is not missing from it — it is refused by it. Links
     and buttons keep the ring; they have no ground of their own to deepen. */
  [data-cc-chrome="header"] a:focus-visible,
  [data-cc-chrome="header"] button:focus-visible {
    outline: var(--focus-ring-width) solid var(--chrome);
    outline-offset: var(--focus-ring-offset);
  }
  /* ⛔ The guard, keyed to the same three names. tint KEEPS — a colour change is not
     motion, and dropping it takes feedback away and gives nothing back. settle and drift
     lose their geometry, ambient stops. Declared although the chrome draws none of those
     three, so the next thing added here inherits the contract instead of inventing one. */
  @media (prefers-reduced-motion: reduce) {
    [data-cc-chrome="header"] [data-motion="settle"],
    [data-cc-chrome="header"] [data-motion="drift"] { transform:none; transition-property:color, background-color; }
    [data-cc-chrome="header"] [data-motion="ambient"] { animation:none; }
  }

  /* ══ brief 100 §2 · THE BROWSER RUNS THIS CHROME NOW ═══════════════════════════════════
     Five controls used to be five pieces of component state (menu, drawer, search, scope) and
     a document keydown listener. They are now the platform's: `popover` for the four menus,
     the drawer and the search overlay; `<details>` for the drawer's two expanding sections;
     a radio group for the search scope; `:placeholder-shown` for typed-vs-resting. Escape,
     outside-click dismiss, one-open-at-a-time and the invoker's aria-expanded all arrive from
     the standard. ⛔ This block is the only thing in the file that could not be inline: every
     rule here is either a pseudo-state or a state read off a DIFFERENT element with :has().

     ⚠️ ONE DECLARED DIFFERENCE. A popover is painted in the TOP LAYER, so its containing block
     is the window and not this component's query container. Its edge is therefore drawn off
     --cc-edge (the same clamp in vw) rather than --gutter (cqw). In the build the bar spans the
     window and the two are the same number; in a narrow preview harness the panels take the
     window's edge while the bar takes the harness's. Named rather than hidden. */
  [data-cc-chrome="header"] {
    --cc-edge: max(clamp(16px, 3.5443vw + 2.18px, 44px), (100vw - 1180px) / 2);
    --cc-bar-bottom: 60px;               /* ribbon 3 + bar 56 + seam 1 */
  }
  /* The ribbon is a prop, so the drop is read off the ribbon's PRESENCE, not off a hole. */
  [data-cc-chrome="header"]:not(:has([data-cc-ribbon])) { --cc-bar-bottom: 57px; }

  [data-cc-chrome="header"] [popover] { margin:0; border:0; padding:0; color:var(--ink); }
  /* ⛔ No scrim. The chrome never drew one, and a popover brings a default backdrop. */
  [data-cc-chrome="header"] [popover]::backdrop { background:transparent; }
  [data-cc-chrome="header"] [data-cc-pop] {
    /* inset:auto first — the UA sheet sets inset:0 on every popover, and an over-constrained
       left+right+width resolves to the left edge whatever `right` says. */
    position:fixed; inset:auto; top:var(--cc-bar-bottom); z-index:50;
    background:var(--surface); max-height:calc(100dvh - var(--cc-bar-bottom)); overflow-y:auto;
  }
  /* ⚠️ Each side names BOTH horizontal offsets. A popover with left AND right set is
     over-constrained and the browser keeps the start edge, which is how a right-hung menu
     first drew itself against the left gutter — the UA sheet's inset:0 is on the element too
     and one `inset:auto` earlier in the block was not enough to clear it. */
  [data-cc-chrome="header"] [data-cc-pop="left"]  { left:calc(var(--cc-edge) - 16px); right:auto; }
  [data-cc-chrome="header"] [data-cc-pop="right"] { right:calc(var(--cc-edge) - 16px); left:auto; }
  [data-cc-chrome="header"] [data-cc-pop="wide"]  { left:0; right:auto; width:100vw; }
  /* One declaration rather than fifty edits: inside a top-layer panel --gutter IS --cc-edge, so
     every edge the panels already drew off --gutter keeps its name and changes its measure. */
  [data-cc-chrome="header"] [popover] { --gutter: var(--cc-edge); }

  /* ══ 11 Sep, Ryan · THE TWO BAR MENUS OPEN ON HOVER, AND CLASSES IS A LINK ════════════════
     Classes and the realm chooser are not press-to-open menus: the pointer arrives and they
     come down. That rules out `popover`, which only opens on invocation — so these two panels
     are plain fixed panels shown by :hover and :focus-within, read off the chrome root with
     :has(). The panel stays open while the pointer is inside it because it is a DESCENDANT of
     nothing it needs to be: the rule tests the panel's own hover as a second condition.
     ⭐ A press on Classes now GOES TO /classes — it is an <a>, and the menu is what hover adds.
     ⚠️ position:fixed, not absolute: the desktop nav group clips (overflow:hidden), and the
     chrome root's container-type makes it the containing block for fixed children, so the panel
     hangs off the root and the group cannot cut it. Its top edge is the bar's bottom edge with
     no gap, which is what lets the pointer travel from the opener into the panel.
     ⛔ The search overlay, the account menu and the mobile drawer stay popovers: those are
     press-to-open, and Escape plus light dismiss is exactly what they want. */
  /* ⚠️ 11 Sep, Ryan · THE BRIDGE, and it is the whole reason the panel is two elements. The
     opener is a 44px box centred in a 56px bar, so its bottom edge sits ~7px above the bar's —
     and the panel began at the bar's bottom. Between the two was a dead band where neither was
     hovered, so the menu closed on the way down to it. The PANEL is now a transparent box that
     starts 10px higher and pads that 10px back; its inner box is the surface the reader sees.
     The hover regions therefore overlap and the drawn edge does not move. ⛔ The bridge cannot
     be a ::before or a negative-top child: the scrolling box would clip it, which is why the
     scroll and the ground moved to the inner element. */
  [data-cc-chrome="header"] [data-cc-panel] {
    display:none; position:fixed; inset:auto; z-index:50;
    top:calc(var(--cc-bar-bottom) - 10px); padding-top:10px;
    background:transparent; --gutter: var(--cc-edge);
  }
  [data-cc-chrome="header"] [data-cc-panel-inner] {
    background:var(--surface); max-height:calc(100dvh - var(--cc-bar-bottom)); overflow-y:auto;
  }
  [data-cc-chrome="header"] [data-cc-panel="classes"] { left:calc(var(--cc-edge) - 16px); right:auto; }
  [data-cc-chrome="header"] [data-cc-panel="realm"]   { right:calc(var(--cc-edge) - 16px); left:auto; }
  /* ⭐ brief 101 §1.8 · the account menu joins them, right-aligned to the same edge. */
  [data-cc-chrome="header"] [data-cc-panel="account"] { right:calc(var(--cc-edge) - 16px); left:auto; }
  [data-cc-chrome="header"]:has([data-cc-opener="account"]:hover)        [data-cc-panel="account"],
  [data-cc-chrome="header"]:has([data-cc-opener="account"]:focus-visible) [data-cc-panel="account"],
  [data-cc-chrome="header"]:has([data-cc-panel="account"]:hover)         [data-cc-panel="account"],
  [data-cc-chrome="header"]:has([data-cc-panel="account"]:focus-within)  [data-cc-panel="account"],
  [data-cc-chrome="header"]:has([data-cc-opener="classes"]:hover)        [data-cc-panel="classes"],
  [data-cc-chrome="header"]:has([data-cc-opener="classes"]:focus-visible) [data-cc-panel="classes"],
  [data-cc-chrome="header"]:has([data-cc-panel="classes"]:hover)         [data-cc-panel="classes"],
  [data-cc-chrome="header"]:has([data-cc-panel="classes"]:focus-within)  [data-cc-panel="classes"],
  [data-cc-chrome="header"]:has([data-cc-opener="realm"]:hover)          [data-cc-panel="realm"],
  [data-cc-chrome="header"]:has([data-cc-opener="realm"]:focus-visible)  [data-cc-panel="realm"],
  [data-cc-chrome="header"]:has([data-cc-panel="realm"]:hover)           [data-cc-panel="realm"],
  [data-cc-chrome="header"]:has([data-cc-panel="realm"]:focus-within)    [data-cc-panel="realm"] { display:block; }

  /* The two caret states of the Classes opener, and the drawer opener's two words. Both used to
     be a pair of sc-ifs on component state; both are drawn once now and chosen by CSS.
     ⛔ AND NEITHER CARET MAY CARRY AN INLINE `display`. One did, and an inline display outranks
     the rule that hides it — which is why the open menu drew both arrows at once. */
  [data-cc-chrome="header"] [data-cc-caret="down"] { display:block; }
  [data-cc-chrome="header"] [data-cc-caret="up"]   { display:none; }
  [data-cc-chrome="header"]:has([data-cc-opener="classes"]:hover)       [data-cc-opener="classes"] [data-cc-caret="down"],
  [data-cc-chrome="header"]:has([data-cc-panel="classes"]:hover)        [data-cc-opener="classes"] [data-cc-caret="down"],
  [data-cc-chrome="header"]:has([data-cc-panel="classes"]:focus-within) [data-cc-opener="classes"] [data-cc-caret="down"] { display:none; }
  [data-cc-chrome="header"]:has([data-cc-opener="classes"]:hover)       [data-cc-opener="classes"] [data-cc-caret="up"],
  [data-cc-chrome="header"]:has([data-cc-panel="classes"]:hover)        [data-cc-opener="classes"] [data-cc-caret="up"],
  [data-cc-chrome="header"]:has([data-cc-panel="classes"]:focus-within) [data-cc-opener="classes"] [data-cc-caret="up"]   { display:block; }
  [data-cc-chrome="header"] [data-cc-drawer-word="close"] { display:none; }
  [data-cc-chrome="header"]:has(#cc-drawer:popover-open) [data-cc-drawer-word="menu"]  { display:none; }
  [data-cc-chrome="header"]:has(#cc-drawer:popover-open) [data-cc-drawer-word="close"] { display:inline; color:var(--loud); }

  /* THE SEARCH OVERLAY'S TWO HALVES. Resting is an empty field, which the browser already
     knows: :placeholder-shown. So both halves are in the drawn page and CSS picks, with no
     render pass and no state — and a reader who types with no engine running still crosses
     from one to the other. ⛔ The RESULTS inside the typed half are a fetch, so they stay the
     build's (§7); this rule only decides which half is on screen.

     ⛔ AND NOT ONE OF THESE DISPLAY VALUES MAY BE INLINE. An inline `display` outranks the UA
     stylesheet's `[popover]:not(:popover-open) { display:none }`, so a popover carrying its own
     inline display is a panel that is permanently open — which is exactly how the first cut of
     this pass drew the search overlay. Every display that participates in an open/closed or
     either/or state therefore lives in this block, and the inline styles keep the rest. */
  #cc-search:popover-open { display:flex; flex-direction:column; }
  #cc-search [data-cc-when="typed"]   { display:contents; }
  #cc-search [data-cc-when="resting"] { display:block; }
  #cc-search:has(input.cc-q:placeholder-shown)      [data-cc-when="typed"]   { display:none; }
  #cc-search:not(:has(input.cc-q:placeholder-shown)) [data-cc-when="resting"] { display:none; }

  /* THE SCOPE CHIPS ARE A RADIO GROUP. The pressed chip is :checked, so the ground and the ink
     are a rule rather than two holes, and the "Search All Realms Instead" escape is a <label>
     pointing at the first radio — a control that changes state with no handler at all. */
  [data-cc-chrome="header"] input[data-cc-native] {
    position:absolute; width:1px; height:1px; opacity:0; margin:0; pointer-events:none;
  }
  #cc-search [data-cc-scope] { background:transparent; color:var(--quiet); }
  #cc-search [data-cc-scope]:hover { color:var(--loud); }
  #cc-search [data-cc-scope]:has(input:checked) { background:var(--ground); color:var(--loud); }
  #cc-search [data-cc-scope="realm"]:has(input:checked) { color:var(--accent-base); }
  #cc-search [data-cc-scope]:has(input:focus-visible) {
    outline: var(--focus-ring-width) solid var(--chrome); outline-offset: var(--focus-ring-offset);
  }
  /* The widen escape is pointless once the scope is already all realms — it was a `display`
     hole read off state, and it is now the same fact read off the radio. */
  #cc-search:has(#cc-scope-all:checked) [data-cc-widen] { display:none; }

  /* ⭐ brief 115 §2 · THE RESULT CHIP TAKES ITS OWN REALM'S HUE. The pattern used to pin every
     chip to var(--chrome-gold) and let the BUILD print only the word — so a Viking result's
     chip read the right word in the wrong colour. data-cc-result-realm is the marked part the
     build sets per row ("arthurian" | "tuatha" | "viking" | "" for no realm), and this is the
     only place the colour is decided. */
  #cc-search [data-cc-result-chip] { color:var(--chrome-gold); }
  #cc-search [data-cc-result-chip][data-cc-result-realm="arthurian"] { color:var(--realm-arthurian); }
  #cc-search [data-cc-result-chip][data-cc-result-realm="tuatha"] { color:var(--realm-tuatha); }
  #cc-search [data-cc-result-chip][data-cc-result-realm="viking"] { color:var(--realm-viking); }

  /* THE DRAWER'S TWO EXPANDING SECTIONS are <details>. The marker goes; the caret the drawing
     already drew stays, and turns on [open]. */
  #cc-drawer details > summary { list-style:none; cursor:pointer; }
  #cc-drawer details > summary::-webkit-details-marker { display:none; }
  #cc-drawer details > summary:hover { background:var(--ground); }
  #cc-drawer details[open] > summary [data-cc-caret="down"] { transform:rotate(180deg); }

  /* ══ brief 102 · SIGNED IN/OUT AND THE READER'S REALM ARE ROOT ATTRIBUTES, NOT PROPS ═══════
     Both are decided when the page is READ, so both versions of everything they touch are drawn
     and one attribute on :root (the document, not this component) picks. Other reading pages —
     the class ladder's offer, the crafting index CTA, Home — read the SAME two attributes, which
     is why they live above this component rather than on its own root.
     ⛔ data-cc-reader-realm is never data-realm: that attribute is the page's own cast (brief 87)
     and a page never reads its own cast as the reader's choice.
     ⭐ Every element that carries an inline `display` already (the sign-in control and the
     avatar are inline-flex by default) needs !important to win here — that is the one place
     this stylesheet uses it outside the published --state-recess exception, and for the same
     reason: an inline value always outranks an external rule otherwise. */
  :root[data-cc-account="in"] [data-cc-chrome="header"] [data-cc-signed="out"] { display:none !important; }
  :root:not([data-cc-account="in"]) [data-cc-chrome="header"] [data-cc-signed="in"] { display:none !important; }
  :root:not([data-cc-account="in"]) [data-cc-chrome="header"] [data-cc-panel="account"] { display:none !important; }

  /* THE REALM WORD, EVERYWHERE IT APPEARS. `data-cc-rw` marks a run of text that depends on the
     reader's realm — the bar's opener, the drawer's Realm summary, the drawer's Classes hint —
     so one rule serves every site the word is drawn, and none of them computes a string. */
  [data-cc-chrome="header"] [data-cc-rw] { display:none; }
  :root:not([data-cc-reader-realm]) [data-cc-chrome="header"] [data-cc-rw=""] { display:inline; }
  :root[data-cc-reader-realm="arthurian"] [data-cc-chrome="header"] [data-cc-rw="arthurian"],
  :root[data-cc-reader-realm="tuatha-de-danann"] [data-cc-chrome="header"] [data-cc-rw="tuatha-de-danann"],
  :root[data-cc-reader-realm="viking"] [data-cc-chrome="header"] [data-cc-rw="viking"] { display:inline; }
  /* The opener's ink and the seam under the bar take the SAME attribute as a colour rather than
     a second copy of a word — there is no text to duplicate, so this is the one site the switch
     stays a value instead of a set of spans. */
  [data-cc-chrome="header"] [data-cc-realm-ink] { color:var(--quiet); }
  [data-cc-chrome="header"] [data-cc-seam] { height:1px; background:var(--rule); }
  :root[data-cc-reader-realm="arthurian"] [data-cc-chrome="header"] [data-cc-realm-ink] { color:var(--realm-arthurian); }
  :root[data-cc-reader-realm="tuatha-de-danann"] [data-cc-chrome="header"] [data-cc-realm-ink] { color:var(--realm-tuatha); }
  :root[data-cc-reader-realm="viking"] [data-cc-chrome="header"] [data-cc-realm-ink] { color:var(--realm-viking); }
  :root[data-cc-reader-realm="arthurian"] [data-cc-chrome="header"] [data-cc-seam] { background:var(--realm-ring-arthurian); }
  :root[data-cc-reader-realm="tuatha-de-danann"] [data-cc-chrome="header"] [data-cc-seam] { background:var(--realm-ring-tuatha); }
  :root[data-cc-reader-realm="viking"] [data-cc-chrome="header"] [data-cc-seam] { background:var(--realm-ring-viking); }

  /* THE CLASS MENU IS ONE MATRIX, ALWAYS — three columns, all 21 names, never a second copy of
     the data keyed to a realm. A chosen realm narrows it to one column and adds the way back to
     /classes; nothing here is content, only which cells and which width. */
  [data-cc-chrome="header"] [data-cc-panel-inner="classes"] { width:560px; }
  :root[data-cc-reader-realm] [data-cc-chrome="header"] [data-cc-panel-inner="classes"] { width:360px; }
  :root[data-cc-reader-realm] [data-cc-chrome="header"] [data-cc-mrow] { grid-template-columns:96px minmax(0,1fr) !important; }
  :root[data-cc-reader-realm="arthurian"] [data-cc-chrome="header"] [data-cc-mcol="tuatha-de-danann"],
  :root[data-cc-reader-realm="arthurian"] [data-cc-chrome="header"] [data-cc-mcol="viking"],
  :root[data-cc-reader-realm="tuatha-de-danann"] [data-cc-chrome="header"] [data-cc-mcol="arthurian"],
  :root[data-cc-reader-realm="tuatha-de-danann"] [data-cc-chrome="header"] [data-cc-mcol="viking"],
  :root[data-cc-reader-realm="viking"] [data-cc-chrome="header"] [data-cc-mcol="arthurian"],
  :root[data-cc-reader-realm="viking"] [data-cc-chrome="header"] [data-cc-mcol="tuatha-de-danann"] { display:none; }
  [data-cc-chrome="header"] [data-cc-classes-exit] { display:none; }
  :root[data-cc-reader-realm] [data-cc-chrome="header"] [data-cc-classes-exit] { display:block; }

  /* THE DRAWER'S CLASS LIST IS THE SAME TRIO, ALWAYS, narrowed to one link the same way, so
     /classes' full 21 and a realm's 7 are one piece of markup rather than two. */
  :root[data-cc-reader-realm="arthurian"] [data-cc-chrome="header"] [data-cc-drawer-cell]:not([data-cc-drawer-cell="arthurian"]),
  :root[data-cc-reader-realm="tuatha-de-danann"] [data-cc-chrome="header"] [data-cc-drawer-cell]:not([data-cc-drawer-cell="tuatha-de-danann"]),
  :root[data-cc-reader-realm="viking"] [data-cc-chrome="header"] [data-cc-drawer-cell]:not([data-cc-drawer-cell="viking"]) { display:none; }

  /* THE REALM PICKER'S OWN CURRENT MARK reads the live attribute, not the value baked at save,
     so picking a realm from this exact menu moves the mark with no reload. "" is All Realms. */
  [data-cc-chrome="header"] [data-cc-realm-row] { background:transparent; }
  :root:not([data-cc-reader-realm]) [data-cc-chrome="header"] [data-cc-realm-row=""],
  :root[data-cc-reader-realm="arthurian"] [data-cc-chrome="header"] [data-cc-realm-row="arthurian"],
  :root[data-cc-reader-realm="tuatha-de-danann"] [data-cc-chrome="header"] [data-cc-realm-row="tuatha-de-danann"],
  :root[data-cc-reader-realm="viking"] [data-cc-chrome="header"] [data-cc-realm-row="viking"] { background:var(--ground); }

  /* PENDING AND FAILED, AS ATTRIBUTES ON THE CONTROL ITSELF. Pending dims the control, takes it
     out of the tab order's effect (pointer-events, not tabindex) and swaps its word to the -ing
     form drawn beside it — no JS style hole, so the look survives a save. Failed leaves the
     control alone and tints its lower edge, the same edge the header's own failure line uses. */
  [data-cc-chrome="header"] [data-cc-pending] { opacity:0.45; pointer-events:none; }
  [data-cc-chrome="header"] [data-cc-word="pending"] { display:none; }
  [data-cc-chrome="header"] [data-cc-pending] [data-cc-word="rest"] { display:none; }
  [data-cc-chrome="header"] [data-cc-pending] [data-cc-word="pending"] { display:inline; }
  [data-cc-chrome="header"] [data-cc-failed] { box-shadow:inset 0 -2px 0 0 var(--danger, oklch(0.660 0.170 22)); }


  :root { --meta:#A4AAB1; --gold:oklch(0.750 0.125 90); --gold-lift:oklch(0.860 0.055 90); }
  body { margin:0; background:#0C0F12; color:#D6D9DE; font-family:'Geist', system-ui, sans-serif; -webkit-font-smoothing:antialiased; }
  * { box-sizing:border-box; }
  a { color:oklch(0.750 0.125 90); text-decoration:none; }
  a:hover { color:oklch(0.860 0.055 90); }
  /* ⛔ 23 Sep · criterion 24 — a STANDALONE link is a control, and a control is 44 × 44 at 390 (Plan's rule, now in spec/RULINGS.md; inline links inside running prose are exempt). "Items" measured 40.2 wide, CLASSIFIED on the built item page: its parent is
     this <nav>, and its only siblings are the "/" separator and the current page's name — a
     breadcrumb row, not prose, so the parent link is a standalone control. This drawing declares
     no container of its own, so the query resolves against the page that mounts it, which is the
     measure the rest of that page's phone rules read. */
  @container (max-width: 899.98px) { [data-cc-crumbparent] { min-width:44px; } }


  :root { --gutter:clamp(16px, 3.5443cqw + 2.18px, 44px); --section:clamp(44px, 5.5696cqw + 22.28px, 88px); } /* ⭐ DECLARED brief 84 §2 — this drawing's own line, no longer an injection (was brief 48 A1). Transcribed from FOUNDATION: spacing and measure. */
  /* ⛔ Scoped for the same reason as the header — see that file. A bare `a` rule in an
     imported component's helmet decides link colour for the whole host page. */
  [data-cc-chrome="footer"] a { color:var(--ink); text-decoration:none; }
  [data-cc-chrome="footer"] a:hover { color:var(--loud); }

  /* ── the same four chrome rules as the header · sweep, 16 Aug ────────────────────
     ⭐ The footer has no controls, so it needs three of them: the tint, the ring, and
     the guard that says the tint keeps. ⛔ There is no button reset because there is
     no button — every interactive thing in this file is a destination and is an <a>. */
  [data-cc-chrome="footer"] {
    --chrome:#CFD6DE; --focus-ring-width:2px; --focus-ring-offset:2px;
    --motion-tint:160ms; --motion-settle:260ms; --motion-drift:420ms;
  }
  [data-cc-chrome="footer"] a { transition: color var(--motion-tint) ease; }
  [data-cc-chrome="footer"] a:focus-visible {
    outline: var(--focus-ring-width) solid var(--chrome);
    outline-offset: var(--focus-ring-offset);
  }
  @media (prefers-reduced-motion: reduce) {
    /* tint KEEPS — nothing here moves, and the colour change is the whole of the state. */
  }

  /* ⭐ ink → lede on the SIZE axis, not the importance one. The column links are 14px on
     the desktop layout and 16px below 900, which is the size class where ink glares — so
     the fold happens in the same query that changes the size, and nowhere else. */
  [data-cc-chrome="footer"] a.cc-col { color:var(--ink); }
  @container (max-width: 900px) {
    [data-cc-chrome="footer"] a.cc-col { color:#C7CCD1; }
  }

  /* ⭐ 22 Sep · MOBILE PAIR 02 — the last three links on every page of the site were 13px
     tall at 9.5px mono, baseline-aligned on one wrapping line. Below 900 they take the same
     treatment the Columns band one hairline above already takes: a column of 44-tall rows at
     gap 0 (three padded controls that touch, per the spacing round), and 12.5px — this band's
     own copyright size, not a new ramp step (Q3, 22 Sep). The copyright takes the full measure
     above them. Nothing here applies at pointer widths. */
  @container (max-width: 900px) {
    [data-cc-chrome="footer"] [data-cc-legal] {
      flex-basis:100%; flex-direction:column; align-items:stretch; gap:0; font-size:12.5px;
    }
    [data-cc-chrome="footer"] [data-cc-legal] > a,
    [data-cc-chrome="footer"] [data-cc-legal] > span {
      display:flex; align-items:center; min-height:44px;
    }
    /* ⛔ 23 Sep · criterion 24 — a STANDALONE link is a control, and a control is 44 × 44 at 390 (Plan's rule, now in spec/RULINGS.md; inline links inside running prose are exempt). Pair 02 gave these three 44 of height and nothing about width, so Terms
       stood at 31.4 and Privacy at 43.9. They are the legal row's own links, one per row below 900
       — standalone, not words in a sentence. Width only; the height is Pair 02's. */
    [data-cc-chrome="footer"] [data-cc-legal] > a { min-width:44px; }
  }
