/*§RUN§[70,"\n",3505,"\n",49953,"\n",820]§*/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); }


  /* CONTRACT-AbilityPages-17SEP.md criterion 2 — Ryan's ruling: "B's page, card at the top" —
     the item page's own head band (SPLICED below by this file's own script, verbatim, from
     `CC- Item.dc.html` at this round's base mirror), `CC AbilityCard` embedded unchanged
     directly under it, then this drawing's own four sections. A DRAFT: never pushed to design by
     Build — Plan pushes after a fresh Verify. */
  :root { --gutter:clamp(16px, 3.5443cqw + 2.18px, 44px); --section:clamp(44px, 5.5696cqw + 22.28px, 88px); }
  body { margin:0; background:var(--ground); color:var(--ink); font-family:'Geist', system-ui, sans-serif; -webkit-font-smoothing:antialiased; }
  * { box-sizing:border-box; }
  a { color:var(--accent-base); text-decoration:none; }
  a:hover { color:var(--accent-lift); }

  [data-cc-figjoint] input[data-cc-native] { position:absolute; width:1px; height:1px; opacity:0; margin:0; pointer-events:none; }
  [data-cc-figjoint] [data-cc-tier] { background:#12161a; color:var(--quiet); }
  [data-cc-figjoint] [data-cc-tier]:hover { background:#2b3138; color:var(--loud); }
  [data-cc-figjoint] [data-cc-tier]:has(input:checked) { background:#2b3138; color:var(--loud); pointer-events:none; }
  [data-cc-figjoint] [data-cc-tier]:has(input:focus-visible) { outline:2px solid var(--stroke, #696E74); outline-offset:2px; }
  [data-cc-figjoint] [data-cc-figpane] { display:none; }
  [data-cc-figjoint]:has([data-cc-tier="starting"] input:checked) [data-cc-figpane="starting"] { display:block; }
  [data-cc-figjoint]:has([data-cc-tier="t1"] input:checked) [data-cc-figpane="t1"] { display:block; }
  [data-cc-figjoint]:has([data-cc-tier="t2"] input:checked) [data-cc-figpane="t2"] { display:block; }

  /* ⭐ 22 Sep · MOBILE PAIR 10 — PHONE ONLY, below 900cqw. Nothing on this page is broken at 390
     except its two controls, and both are a few pixels under the floor. The tier strip goes
     38 → 44 and stops being max-content: the three split the measure and reach both edges, which
     makes them equal-weight choices rather than three words of different lengths. The back link
     — the page's only way out — takes a 44 min-height further down, on the element itself.
     ⭐ !important because the strip and its labels state width and height inline. */
  /* ⛔ 23 Sep · CONTRACT-MobileApply-22SEP.md criterion 16, Addendum 5 — THE BACK LINK'S
     `display` IS SCOPED THE WAY ITS `min-height` ALREADY WAS. Pair 10 clamped the link's
     min-height below 900 but wrote `display:inline-flex` unconditionally, which contradicts this
     drawing's own sentence two lines above the element: "above it, nothing here resolves and the
     link is what it was". It did not: at 1280 and 1440 the link went inline → inline-flex and
     205.9 → 198.0 wide, the only desktop change reading the Ability Page from the mirror would
     have made. Scoping it here is not an override of design's intent — it is the file doing what
     its own comment claims. `align-items` moves with it, being inert on an inline box anyway.
     ⭐ The tier-strip rules below were checked for the same defect and do NOT have it: both have
     always sat inside this query, which is why 38 → 44 never reached a pointer width. */
  @container (max-width: 900px) {
    [data-cc-backlink] { display:inline-flex; align-items:center; }
    [data-cc-figjoint] [data-cc-tierstrip] { width:auto !important; }
    [data-cc-figjoint] [data-cc-tier] { flex:1 1 0; height:44px !important; justify-content:center; padding:0 var(--space-bound) !important; }
  }


  :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 { --hollow:#101317; --seam:#4b5259; --stroke:#696E74;
    --meta:#A4AAB1; --lede:#C7CCD1;
    --gold:oklch(0.750 0.125 90); --gold-lift:oklch(0.860 0.055 90);
    --realm-arthurian:oklch(0.750 0.125 25); --realm-tuatha:oklch(0.750 0.125 160); --realm-viking:oklch(0.750 0.125 250);
    --absent-ink:var(--quiet); --absent-line:var(--edge);
    --absent-hatch:repeating-linear-gradient(135deg, transparent 0 3px, color-mix(in oklab, var(--absent-line) 40%, transparent) 3px 4px);
    --shadow-modal:0 24px 60px rgba(0,0,0,0.6);
  }
  body { margin:0; background:var(--ground); color:var(--ink); font-family:'Geist', system-ui, sans-serif; -webkit-font-smoothing:antialiased; }
  * { box-sizing:border-box; }
  a { color:var(--gold); text-decoration:none; }
  a:hover { color:var(--gold-lift); }

  /* ══ brief 100 §2.4 / §2.6 · THE CARD OPENS IN CSS ═══════════════════════════════════════
     What this block replaces: a matchMedia listener, a resize listener, a capture-phase scroll
     listener, a document keydown listener, a getBoundingClientRect per open, and six state keys
     (open, pinned, rect, box, canHover, vw, vh). The card is a child of its own trigger now, so
     :hover and :focus-within are the whole mechanism.

     ⭐ TWO PRESENTATIONS, PICKED BY THE POINTER, in a media query rather than in JS. A fine
     pointer gets the flyout under the name; a coarse pointer gets the bottom sheet. That was
     `canHover` read from matchMedia and pushed into state on every change.
     ⭐ THE FLYOUT NO LONGER CLOSES ON SCROLL, because it no longer has to: it is positioned
     against its trigger instead of against the window, so it travels with the page.
     ⛔ NO DISPLAY, WIDTH OR POSITION MAY BE INLINE ON THE CARD. Every one of those takes part in
     an open/closed or either/or state, and an inline value outranks this block. */
  [data-cc-scrim] { display:none; position:fixed; inset:0; background:rgba(0,0,0,0.5); z-index:60; pointer-events:none; }
  [data-cc-sheet-hint] { display:none; }
  @media (hover: none) { [data-cc-card] [data-cc-sheet-hint] { display:block; } }
  [data-cc-card]  { display:none; flex-direction:column; width:380px; max-width:min(380px, calc(100vw - 24px)); }
  /* A specimen mount has no trigger: the hit is display:contents and the card is just in flow. */
  [data-cc-hit="static"] > [data-cc-card] { display:flex; }

  /* ⭐ brief 105 §1 · THE MOUNT'S OWN WRAPPER TAKES NO POINTER EVENTS EITHER — the same fix as
     CC ItemCard, band for band. dc-import wraps every mount in its own div (.sc-host), and an
     overlay mount's `style="position:absolute; inset:0"` lands on THAT div, not on the hit span
     the 11 Sep note made click-through. Scoped to a wrapper that holds an overlay hit only. */
  .sc-host:has(> [data-cc-hit="overlay"]) { pointer-events:none; }

  @media (hover: hover) and (pointer: fine) {
  /* ⭐ 11 Sep · AN OVERLAY MOUNT'S TRIGGER IS THE CELL IT COVERS, NOT THE COVER. The hit is a
     transparent box over a row or a table cell, and while it took pointer events it also
     swallowed the press that belongs to the thing underneath — which used to be fine only
     because the card forwarded that press in script. It takes no pointer events now, so the
     row's own label or link gets the click, and the card opens on the PARENT's hover and
     focus-within instead. One selector change, and the hit stays a box so anchor positioning
     still has something to measure against. */
    :hover > * > [data-cc-hit="overlay"] > [data-cc-card],
    :focus-within > [data-cc-hit="overlay"] > [data-cc-card],
    [data-cc-hit="inline"]:hover  > [data-cc-card],
    [data-cc-hit="inline"]:focus-within  > [data-cc-card] {
      display:flex; position:absolute; top:100%; left:0; margin-top:10px; z-index:70;
      max-height:min(560px, 68dvh); overflow-y:auto; overflow-x:hidden;
      box-shadow:var(--shadow-modal); pointer-events:none;
    }
    /* ⭐ WHERE THE BROWSER CAN FLIP A PANEL ITSELF, IT DOES. This is the exact computation the
       deleted script ran — below if it fits, else above, else pinned to the window — expressed
       as anchor positioning with try-fallbacks. It also restores fixed positioning, so a host
       cell that clips cannot clip the card. Behind @supports, because the fallback above is the
       honest floor: start-aligned under the trigger, clamped by max-width. */
    @supports (anchor-name: --cc-card) and (position-try-fallbacks: flip-block) {
      [data-cc-hit="overlay"], [data-cc-hit="inline"] { anchor-name:--cc-card; anchor-scope:--cc-card; }
      :hover > * > [data-cc-hit="overlay"] > [data-cc-card],
      :focus-within > [data-cc-hit="overlay"] > [data-cc-card],
      [data-cc-hit="inline"]:hover  > [data-cc-card],
      [data-cc-hit="inline"]:focus-within  > [data-cc-card] {
        position:fixed; position-anchor:--cc-card; position-area:block-end span-inline-end;
        top:auto; left:auto; margin:10px 0 0;
        position-try-fallbacks: flip-block, flip-inline, flip-block flip-inline;
      }
    }
  }

  /* ⚠️ COARSE POINTER · a tap focuses the trigger and the sheet comes up; a tap anywhere off it
     takes the focus away and the sheet goes. That is the whole interaction, and it is why the
     sheet's "Close" button is retired: a control inside the card's own focus subtree cannot
     take focus out of that subtree, so a Close there could only ever be script. The scrim takes
     no pointer events for the same reason — the tap has to reach the page to land the dismiss. */
  @media (hover: none) {
    :focus-within > [data-cc-hit="overlay"] > [data-cc-card],
    [data-cc-hit="inline"]:focus-within  > [data-cc-card] {
      display:flex; position:fixed; left:0; right:0; bottom:0; width:auto; max-width:none;
      z-index:70; max-height:82dvh; overflow-y:auto;
      border-left:0; border-right:0; border-bottom:0; box-shadow:var(--shadow-modal);
    }
    :focus-within > [data-cc-hit="overlay"] > [data-cc-scrim],
    [data-cc-hit="inline"]:focus-within  > [data-cc-scrim] { display:block; }

    /* ⛔ 23 Sep · CONTRACT-MobileApply-22SEP.md criterion 12 — THE SHEET HAD NO WAY TO BE OPENED.
       Everything above this line was right: the rules are correct, and focusing the overlay in
       script does raise the sheet. But `.sc-host:has(> [data-cc-hit="overlay"])` is
       `pointer-events:none` for the fine-pointer reason above (the row's own label or link must
       get the click), the overlay inherits it, and on a coarse pointer there IS no hover — so a
       tap went straight through to the name span and nothing ever took focus. Four tap points
       across a Loadout ability row opened 0 cards (REVIEW-MobileApply-22SEP, finding 3). The
       `tabindex` this round added was meant to reach the sheet and could not.
       ⛔ RESTORING IT EVERYWHERE WOULD BREAK THE THING IT WAS TURNED OFF FOR. The Class ladder
       mounts this same overlay on top of a `<label for="cc-abil-…">`, whose tap must still select
       the row; CC: Ability Path's ability row has nothing under the overlay but its own name. So
       the restore is an OPT-IN a host declares: `data-cc-tapcard` on the element the overlay
       covers. ⚠️ The obvious shorthand — condition it on the host's parent holding no link or
       label — was written first and MEASURED WRONG: `:has()` reaches the whole subtree, and the
       card mounted inside that parent carries its own links, so the guard never matched and all
       four taps still opened nothing. An opt-in cannot fail that way.
       ⛔ 23 Sep · criterion 23 — a comment terminator that stood at the end of the line above closed this
       comment one paragraph early. The paragraph below it was then bare text, CSS error recovery
       swallowed it TOGETHER WITH the first restore rule's block, and only the `!important` rule
       survived to carry criterion 12. One terminator removed; both rules now parse.
       ⭐ `!important` on the hit itself: an overlay mount states `pointerEvents:'none'` INLINE
       (see `hitStyle` below), and an inline declaration outranks a helmet rule. Measured, not
       assumed — without it the host went to `auto` and the overlay stayed `none`, and all four
       taps still opened nothing. */
    [data-cc-tapcard] > .sc-host:has(> [data-cc-hit="overlay"]) { pointer-events:auto; }
    [data-cc-tapcard] > .sc-host > [data-cc-hit="overlay"] { pointer-events:auto !important; }
  }


  :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; }
  }


  /* ⭐ 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)); }
[data-cc-hover-css="color:var(--loud);"]:hover{color:var(--loud) !important}
[data-cc-hover-css="background:var(--surface);"]:hover{background:var(--surface) !important}
[data-cc-hover-css="color:var(--ink);"]:hover{color:var(--ink) !important}
[data-cc-hover-css="background:var(--ground); color:var(--loud);"]:hover{background:var(--ground) !important; color:var(--loud) !important}
[data-cc-hover-css="background:var(--ground);"]:hover{background:var(--ground) !important}
[data-cc-hover-css="background:var(--panel);"]:hover{background:var(--panel) !important}
[data-cc-hover-css="color:oklch(0.860 0.055 90);"]:hover{color:oklch(0.860 0.055 90) !important}
[data-cc-hover-css="background:#232b34;"]:hover{background:#232b34 !important}
[data-cc-hover-css="color:var(--quiet);"]:hover{color:var(--quiet) !important}
