/* ============================================================================
 * devhub-hf.css — the Head First design language: bubbly, playful, eye-grabbing.
 *
 * Built from Bobby's mobile screenshots of the Decorator chapter. This is NOT
 * a recolor — it is the component kit that makes a page feel like the book:
 * generous roundness, a high-contrast display serif, a script hand for asides,
 * caution-tape tabs, speech bubbles, nested wrapper diagrams, napkin notes.
 *
 * COLORWAY: dark mocha/espresso is the default (Bobby's call — the cream
 * variant comes later and only needs the token block re-stated under
 * :root[data-theme="cream"], because every component below is token-driven).
 *
 * Opt in with <html data-hf>. Load AFTER devhub.css.
 * Selectors are written `[data-hf] …` so they outrank a page's own inline
 * rules on SPECIFICITY rather than source order — that is what lets this
 * reskin the 153 pages that redeclare their palette locally without editing
 * them one by one.
 * ========================================================================== */

/* ── type ─────────────────────────────────────────────────────────────────
   Playfair Display (display serif) + Dancing Script (the hand), self-hosted
   as latin-subset variable woff2 — one file each, 38KB + 42KB. Body stays on
   the system sans DevHub already uses; mono stays as-is. */
@font-face{
  font-family:'Playfair Display'; font-style:normal; font-weight:400 900;
  font-display:swap; src:url('fonts/playfair.woff2') format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face{
  font-family:'Dancing Script'; font-style:normal; font-weight:400 700;
  font-display:swap; src:url('fonts/dancing.woff2') format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}

/* ── tokens ───────────────────────────────────────────────────────────────
   Written as `:root[data-hf]` (0,2,0) so it always outranks a page's own
   inline `:root{}` (0,1,0) regardless of source order.

   CRITICAL: this block remaps DevHub's EXISTING token names onto the mocha
   ramp as well as defining the --hf-* ones. devhub.css builds .intro, .panel,
   .rt-* and friends out of var(--panel)/var(--border)/var(--accent), so
   remapping those makes every token-driven component follow the theme for
   free. Only genuinely hardcoded literals then need explicit rules below.
   (An earlier draft defined --hf-* alone; .intro stayed slate blue on a
   mocha page, because nothing it referenced had changed.) */
:root[data-hf],[data-hf]{
  --hf-bg:#17120f;            /* espresso page ground */
  --hf-card:#241d18;          /* default card */
  --hf-card2:#2b231c;         /* raised card */
  --hf-bad:#3a221a;           /* "the problem" card — reddish brown */
  --hf-good:#2c2c1d;          /* "the fix" card — olive */
  --hf-ink:#f2e8db;           /* cream text */
  --hf-ink2:#c9b9a6;          /* secondary */
  --hf-muted:#9a8874;
  --hf-line:rgba(242,232,219,.13);
  --hf-orange:#e8734a;        /* the accent — kickers, inline code, arrows */
  --hf-orange2:#f0916d;
  --hf-gold:#d9b64e;          /* caution tape, reveal button */
  --hf-blue:#7fa3cc;          /* Q&A rail */
  --hf-r:22px;                /* the roundness. generous on purpose. */
  --hf-r-lg:28px;
  --font-display:'Playfair Display',Georgia,'Times New Roman',serif;
  --font-hand:'Dancing Script','Segoe Script',cursive;

  /* DevHub's own token names, remapped onto the mocha ramp */
  --bg:#17120f; --panel:#241d18; --panel2:#2b231c; --panel-2:#1c1613;
  --border:rgba(242,232,219,.13); --divider:rgba(242,232,219,.13);
  --text:#f2e8db; --muted:#9a8874;
  --accent:#e8734a; --accent2:#f0916d;
  --good:#8aa06a; --bad:#e07a5f; --warn:#d9b64e; --info:#7fa3cc;
  --blue:#7fa3cc; --amber:#d9b64e;
}

/* ── page shell ───────────────────────────────────────────────────────── */
[data-hf] body{
  background:var(--hf-bg) !important; background-image:none !important;
  color:var(--hf-ink); line-height:1.7;
}
[data-hf] .container{ max-width:820px; }   /* book column, not dashboard width */

/* Display serif for every heading; the hand is reserved for asides. */
[data-hf] h1,[data-hf] h2,[data-hf] h3,[data-hf] h4{
  font-family:var(--font-display); font-weight:700; letter-spacing:-.01em;
  color:var(--hf-ink) !important; background:none !important;
  -webkit-background-clip:border-box !important; background-clip:border-box !important;
  -webkit-text-fill-color:var(--hf-ink); border-bottom:none !important;
}
[data-hf] h1{ font-size:clamp(34px,7vw,54px); line-height:1.06; margin:.2em 0 .35em; }
[data-hf] h2{ font-size:clamp(26px,5vw,38px); line-height:1.15; margin:1.6em 0 .5em; }
[data-hf] h3{ font-size:clamp(20px,4vw,25px); }
[data-hf] p{ color:var(--hf-ink2); }

/* ── the deck: a script subtitle under the h1 ─────────────────────────────
   "or, how Starbuzz Coffee learned to stop subclassing and start wrapping" */
.hf-deck{
  font-family:var(--font-hand); font-size:clamp(20px,4.4vw,27px);
  line-height:1.35; color:var(--hf-orange); margin:0 0 1.4em; font-weight:400;
}

/* ── chapter rail ─────────────────────────────────────────────────────────
   The "you are here" strip. Renders from a plain <ol>; the dashed connector
   is one ::before behind the dots, so any number of chapters works. */
.hf-rail{ position:relative; margin:0 0 46px; padding-top:26px; text-align:center; }
.hf-rail .hf-youarehere{
  font-family:var(--font-hand); font-size:19px; color:var(--hf-orange);
  display:block; margin-bottom:2px;
}
.hf-rail ol{
  list-style:none; display:flex; justify-content:space-between; align-items:flex-start;
  gap:4px; margin:0; padding:0; position:relative;
}
.hf-rail ol::before{
  content:''; position:absolute; left:6%; right:6%; top:9px;
  border-top:2px dashed rgba(242,232,219,.22);
}
.hf-rail li{ position:relative; flex:1; min-width:0; }
.hf-rail li a,.hf-rail li span{
  display:block; font-size:12px; color:var(--hf-muted); text-decoration:none;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  /* the horizontal padding is what stops adjacent labels touching when a
     long one ellipsises — without it "Observer" and "Decora…" collide */
  padding:26px 5px 0; text-align:center;
}
.hf-rail li::before{                                   /* the dot */
  content:''; position:absolute; top:2px; left:50%; transform:translateX(-50%);
  width:15px; height:15px; border-radius:50%;
  background:var(--hf-bg); border:2px solid var(--hf-muted);
}
.hf-rail li[aria-current]::before{
  background:var(--hf-orange); border-color:var(--hf-orange);
  box-shadow:0 0 0 5px rgba(232,115,74,.18);
}
.hf-rail li[aria-current] a,.hf-rail li[aria-current] > span{
  color:var(--hf-ink); font-weight:700;
}
/* the giant ghosted chapter numeral behind the rail */
.hf-chapnum{
  position:absolute; top:-18px; left:0; font-family:var(--font-display);
  font-size:150px; line-height:1; font-weight:900; color:rgba(242,232,219,.045);
  pointer-events:none; user-select:none; z-index:0;
}

/* ── section kicker + statement ───────────────────────────────────────────
   "— THE PROBLEM" then a big serif line. The pair is the page's rhythm. */
.hf-kick{
  display:flex; align-items:center; gap:12px; margin:56px 0 14px;
  font-size:12px; font-weight:700; letter-spacing:.14em; text-transform:uppercase;
  color:var(--hf-orange);
}
.hf-kick::before{ content:''; width:26px; height:2px; background:var(--hf-orange); flex:none; }
.hf-say{                                        /* the statement headline */
  font-family:var(--font-display); font-weight:700;
  font-size:clamp(25px,5.2vw,38px); line-height:1.18; color:var(--hf-ink);
  margin:0 0 26px; max-width:20ch;
}

/* ── cards ────────────────────────────────────────────────────────────────
   Everything is round and borderless; depth comes from tone, not outlines. */
.hf-card{
  background:var(--hf-card); border-radius:var(--hf-r); padding:26px 28px;
  margin:0 0 20px; position:relative;
}
.hf-card > h4,.hf-card > .hf-cardtitle{
  font-family:inherit; font-size:13px; font-weight:700; letter-spacing:.09em;
  text-transform:uppercase; color:var(--hf-ink); margin:0 0 16px;
}
.hf-card.bad{ background:var(--hf-bad); }
.hf-card.good{ background:var(--hf-good); }
.hf-card .hf-foot{
  font-style:italic; color:var(--hf-muted); font-size:14px; margin:16px 0 0;
}

/* ── caution tape tab ─────────────────────────────────────────────────────
   The gold hazard-stripe tab that sits on top of a card, with the orange
   bead. Pure CSS: repeating-linear-gradient + one dot. */
.hf-taped{ margin-top:26px; }
.hf-taped::before{
  content:''; position:absolute; top:-11px; left:50%; transform:translateX(-50%);
  width:96px; height:21px; border-radius:3px;
  background:repeating-linear-gradient(115deg,
    var(--hf-gold) 0 9px, #6b5520 9px 18px);
  opacity:.92;
}
.hf-taped::after{
  content:''; position:absolute; top:-4px; left:50%; transform:translateX(-50%);
  width:8px; height:8px; border-radius:50%; background:var(--hf-orange);
}

/* ── scattered class chips (the class-explosion visual) ───────────────────
   Deliberately jaunty — each chip is nudged a fraction of a degree so the
   pile reads as "this is out of control", which is the whole teaching point. */
.hf-scatter{ display:flex; flex-wrap:wrap; gap:10px 12px; }
.hf-scatter span{
  font-family:ui-monospace,Menlo,monospace; font-size:13px;
  background:rgba(0,0,0,.32); color:var(--hf-ink2);
  padding:9px 14px; border-radius:11px; display:inline-block;
}
.hf-scatter span:nth-child(3n){ transform:rotate(-1.6deg); }
.hf-scatter span:nth-child(3n+1){ transform:rotate(1.1deg); }
.hf-scatter span:nth-child(4n){ transform:rotate(-.6deg); }

/* ── wrapper chain (the "wrap at runtime" ladder) ─────────────────────── */
.hf-ladder{ display:flex; flex-direction:column; align-items:flex-start; gap:2px; }
.hf-ladder b{
  font-family:ui-monospace,Menlo,monospace; font-weight:400; font-size:14px;
  background:rgba(0,0,0,.34); color:var(--hf-ink);
  padding:11px 17px; border-radius:12px;
}
.hf-ladder i{
  font-style:normal; font-size:12.5px; color:var(--hf-muted); padding:5px 0 5px 16px;
}

/* ── speech bubbles ───────────────────────────────────────────────────────
   Two objects talking. Speaker name in the hand, bubble alternates side. */
.hf-talk{ display:flex; flex-direction:column; gap:14px; margin:22px 0; }
.hf-bub{
  background:var(--hf-card2); border-radius:18px; padding:15px 19px;
  max-width:82%; position:relative;
}
.hf-bub .who{
  display:block; font-family:var(--font-hand); font-size:17px;
  color:var(--hf-ink2); margin-bottom:3px;
}
.hf-bub p{ margin:0; color:var(--hf-ink); font-size:15.5px; }
.hf-bub.right{ align-self:flex-end; background:var(--hf-good); }
.hf-bub.right .who{ color:var(--hf-orange2); }

/* ── nested wrapper diagram ───────────────────────────────────────────────
   Dotted boxes nested by DOM depth — no fixed sizes, so it works for 2 layers
   or 6. The label sits on the top-left of each ring. */
.hf-nest{ padding:22px 16px 14px; }
.hf-nest .ring{
  border:2px dotted rgba(242,232,219,.30); border-radius:14px;
  padding:26px 16px 16px; position:relative; margin:0;
}
.hf-nest .ring > .lbl{
  position:absolute; top:7px; left:14px; font-family:ui-monospace,Menlo,monospace;
  font-size:12px; color:var(--hf-ink2);
}
.hf-nest .core{
  background:#a97a4f; color:#20160f; border-radius:13px; padding:20px;
  text-align:center; font-weight:700;
}
.hf-nest .core small{ display:block; font-weight:400; opacity:.8; margin-top:3px; }
.hf-nest .note{
  font-family:var(--font-hand); font-size:16px; color:var(--hf-orange);
  text-align:right; margin:0 0 -6px;
}

/* ── napkin / psst note ───────────────────────────────────────────────────
   The predict-first beat. Torn-edge feel via a dashed outline offset inward. */
.hf-napkin{
  position:relative; background:var(--hf-card2); border-radius:6px;
  padding:20px 22px 20px 64px; margin:24px 0; color:var(--hf-ink);
  box-shadow:0 10px 26px rgba(0,0,0,.34);
}
.hf-napkin::before{
  content:''; position:absolute; inset:5px; border:1px dashed rgba(242,232,219,.22);
  border-radius:4px; pointer-events:none;
}
.hf-napkin::after{
  content:'psst —'; position:absolute; left:16px; top:20px;
  font-family:var(--font-hand); font-size:19px; color:var(--hf-muted);
}

/* ── Q&A — "questions from the back row" ─────────────────────────────── */
.hf-ask{
  border-left:3px solid var(--hf-blue); background:var(--hf-card);
  border-radius:0 16px 16px 0; padding:18px 22px; margin:0 0 14px;
}
.hf-ask dt,.hf-ask .q{ font-weight:700; color:var(--hf-ink); margin:0 0 8px; }
.hf-ask dd,.hf-ask .a{ margin:0; color:var(--hf-ink2); font-size:15px; }
.hf-ask .q::before,.hf-ask dt::before{
  content:'Q'; font-family:var(--font-display); font-style:italic;
  color:var(--hf-blue); margin-right:10px; font-weight:400;
}
.hf-ask .a::before,.hf-ask dd::before{
  content:'A'; font-family:var(--font-display); font-style:italic;
  color:var(--hf-muted); margin-right:10px; font-weight:400;
}

/* ── key-term cards ──────────────────────────────────────────────────── */
.hf-terms{ display:grid; gap:18px; }
.hf-terms .hf-card h4{
  font-family:var(--font-display); font-size:21px; font-weight:700;
  text-transform:none; letter-spacing:0; color:var(--hf-ink); margin-bottom:8px;
}

/* ── annotated code note (the italic hand under a snippet) ───────────── */
.hf-annot{
  font-family:var(--font-hand); font-size:17px; line-height:1.45;
  color:var(--hf-ink2); margin:12px 0 0;
}

/* ── reveal button ───────────────────────────────────────────────────── */
.hf-reveal{
  background:var(--hf-gold); color:#221a09; border:none; border-radius:12px;
  font-weight:700; font-size:15px; padding:13px 22px; cursor:pointer;
  font-family:inherit; transition:transform .12s ease, filter .12s ease;
}
.hf-reveal:hover{ transform:translateY(-1px); filter:brightness(1.06); }

/* ── inline code on the espresso ground ──────────────────────────────── */
[data-hf] code:not(pre code){
  background:rgba(232,115,74,.11); color:var(--hf-orange2);
  border:1px solid rgba(232,115,74,.26); border-radius:7px;
  padding:1px 7px; font-size:.92em;
}
[data-hf] pre{
  background:#120e0c; border:1px solid var(--hf-line); border-radius:16px;
  padding:18px 20px;
}

/* ── mobile ───────────────────────────────────────────────────────────────
   Bobby reads this on a phone; the screenshots ARE the phone view. Keep the
   rail scrollable rather than crushing five labels into 390px. */
@media (max-width:680px){
  [data-hf] body{ padding:16px 14px; }
  .hf-chapnum{ font-size:104px; top:-6px; }
  .hf-rail ol{ gap:2px; }
  .hf-rail li a,.hf-rail li span{ font-size:10.5px; }
  .hf-say{ max-width:none; }
  .hf-card{ padding:20px 18px; border-radius:18px; }
  .hf-bub{ max-width:92%; }
  .hf-napkin{ padding-left:22px; padding-top:44px; }
  .hf-napkin::after{ top:14px; }
  .hf-nest .ring{ padding:24px 10px 12px; }
}
[data-hf] pre,[data-hf] table{ max-width:100%; overflow-x:auto; }
[data-hf] body{ overflow-x:hidden; }
@media (prefers-reduced-motion:reduce){ .hf-reveal{ transition:none } }

/* ── overrides for devhub.css components that predate this kit ────────────
   These elements already exist sitewide and carry dark-slate/blue styling
   from devhub.css. Repaint them here rather than editing 500 pages. */
[data-hf] a.back{ color:var(--hf-muted); font-size:14px; }
[data-hf] a.back:hover{ color:var(--hf-orange); }
[data-hf] .hf-kicker{
  background:rgba(217,182,78,.13) !important; color:var(--hf-ink2) !important;
  border:none !important; border-radius:9px; font-size:12px; font-weight:700;
  letter-spacing:.11em; padding:9px 18px; display:inline-block;
}
[data-hf] .principle{
  background:var(--hf-card) !important; border:none !important;
  border-left:3px solid var(--hf-orange) !important; border-radius:0 16px 16px 0;
  color:var(--hf-ink2) !important; font-weight:400; font-size:15px; padding:18px 22px;
}
[data-hf] .principle b{ color:var(--hf-ink); }

/* rail: the current chapter must never be the one that gets ellipsised, and
   the numeral belongs BEHIND the rail, not beside it. */
.hf-rail{ padding-top:64px; }
.hf-rail li[aria-current]{ flex:1.6; }
/* The current chapter is the one label that must stay fully readable. Let it
   WRAP rather than overflow — `overflow:visible` made a long name like
   "Compound+MVC" spill sideways over its neighbour. */
.hf-rail li[aria-current] > span{
  /* `white-space:normal` alone does not help a label with no space in it —
     "Iterator+Composite" still ran over its neighbour. `overflow-wrap:anywhere`
     lets it break mid-token, and dropping `overflow:visible` keeps it inside
     its own cell no matter how long the chapter name is. */
  white-space:normal; overflow-wrap:anywhere; line-height:1.2;
}
.hf-chapnum{
  top:-6px; left:50%; transform:translateX(-50%); font-size:190px;
  color:rgba(242,232,219,.05); z-index:0;
}
.hf-rail > .hf-kicker,.hf-rail > .hf-youarehere,.hf-rail > ol{ position:relative; z-index:1; }
.hf-rail > .hf-kicker{ margin-bottom:14px; }
@media (max-width:680px){
  .hf-chapnum{ font-size:128px; top:0; }
  .hf-rail{ padding-top:52px; }
  .hf-rail li a,.hf-rail li span{ font-size:10px; }
}

/* rail count ("3 of 14") — only rendered when the rail is windowed. */
.hf-railcount{
  display:block; margin-top:10px; font-size:11px; letter-spacing:.1em;
  text-transform:uppercase; color:var(--hf-muted);
}

/* ── "Test yourself" strip ────────────────────────────────────────────────
   Rendered at the end of a lesson by devhub-chapters.js, from the inverted
   exam/practice refs in tracks-data.js. Deliberately quiet — it is an offer at
   the end of a reading, not a call to action competing with the lesson. Uses
   only tokens both colorways define, and --panel2 is the darkest cream surface,
   so a colour that passes here passes on every card. */
.hf-practice{
  display:block; margin:38px 0 8px; padding:20px 22px;
  border:1px solid var(--hf-line);
  border-radius:16px; background:var(--hf-card);
}
.hf-practice-kick{
  display:block; font-size:11px; font-weight:800; letter-spacing:.14em;
  text-transform:uppercase; color:var(--hf-orange);
}
.hf-practice-lead{
  margin:8px 0 14px; font-size:13.5px; line-height:1.55;
  color:var(--hf-ink2); overflow-wrap:anywhere;
}
.hf-practice-row{ display:flex; flex-wrap:wrap; gap:10px; }
.hf-practice-link{
  display:inline-block; padding:9px 16px; border-radius:999px;
  border:1px solid currentColor; color:var(--hf-orange);
  font-family:var(--font-display); font-size:13px; font-weight:700;
  text-decoration:none; overflow-wrap:anywhere; max-width:100%;
  transition:background-color .18s ease, color .18s ease;
}
.hf-practice-link:hover,
.hf-practice-link:focus-visible{ background:var(--hf-orange); color:var(--hf-bg); }

/* "Next up · Design Patterns →" — rendered only on the last page of a section,
   where the rail would otherwise just stop. 90 of the site's 124 sections end
   that way, which is most of why 512 pages read as a library rather than a path.
   Deliberately not styled like a rail stop: it is leaving this section, not
   another entry in it. Uses --hf-orange, which both colorways already define. */
.hf-railnext{
  display:inline-block; margin-top:14px; padding:7px 15px;
  font-family:var(--font-display); font-size:12.5px; font-weight:700;
  letter-spacing:.02em; color:var(--hf-orange); text-decoration:none;
  border:1px solid currentColor; border-radius:999px;
  transition:background-color .18s ease, color .18s ease;
  overflow-wrap:anywhere; max-width:100%;
}
.hf-railnext:hover,
.hf-railnext:focus-visible{ background:var(--hf-orange); color:var(--hf-bg); }

/* ── order builder ────────────────────────────────────────────────────────
   The learner-driven counterpart to the static nested diagram: tap condiments
   and watch the receipt, the constructor expression and the description string
   build together. Layout only — the behaviour is ~40 lines of vanilla JS on
   the page (no framework; the whole state model is one array of keys). */
.hf-buildbar{ display:flex; flex-wrap:wrap; gap:10px; margin-bottom:20px; }
.hf-buildbar button{
  cursor:pointer; border:none; border-radius:999px; padding:11px 18px;
  font-family:inherit; font-size:13.5px; font-weight:700;
  background:var(--hf-good); color:var(--hf-ink);
  transition:transform .12s ease, filter .12s ease;
}
.hf-buildbar button:hover{ transform:translateY(-1px); filter:brightness(1.12); }
.hf-buildbar button[data-undo],.hf-buildbar button[data-reset]{
  background:transparent; color:var(--hf-ink2);
  box-shadow:inset 0 0 0 1px var(--hf-line); font-weight:400;
}
.hf-buildbar button:disabled{ opacity:.4; cursor:default; transform:none; filter:none; }
.hf-buildout{ display:grid; gap:16px; }
@media(min-width:720px){ .hf-buildout{ grid-template-columns:1.05fr .95fr; align-items:start; } }
.hf-buildrow{
  display:flex; justify-content:space-between; gap:14px;
  font-family:ui-monospace,Menlo,monospace; font-size:14px; padding:6px 0;
  color:var(--hf-ink2); animation:hfPop .22s ease;
}
.hf-buildrow.base{ color:var(--hf-ink); }
.hf-buildrow.total{
  border-top:1px solid var(--hf-line); margin-top:8px; padding-top:12px;
  color:var(--hf-orange); font-weight:700; font-size:16px;
}
@keyframes hfPop{ from{ opacity:0; transform:translateY(-4px) } to{ opacity:1; transform:none } }
@media (prefers-reduced-motion:reduce){ .hf-buildrow{ animation:none } }
.hf-expr{
  background:#120e0c; border-radius:14px; padding:16px 18px;
  font-family:ui-monospace,Menlo,monospace; font-size:13px; line-height:1.6;
  color:var(--hf-orange2); word-break:break-word;
}
.hf-expr .lbl,.hf-desc .lbl{
  display:block; font-family:inherit; font-size:10.5px; letter-spacing:.09em;
  text-transform:uppercase; color:var(--hf-muted); margin-bottom:8px;
  word-break:normal;
}
.hf-desc{
  margin-top:12px; font-family:ui-monospace,Menlo,monospace; font-size:13.5px;
  color:var(--hf-ink);
}

/* In the reference design the big type is CREAM and orange is reserved for
   the small kickers. devhub.css paints .intro-head with the accent, which on
   a mocha ground reads as a shout. Pull it back to ink and let the kicker
   above it carry the colour. */
[data-hf] .intro-head{ color:var(--hf-ink) !important; font-family:var(--font-display); font-weight:700; }
[data-hf] .intro-kicker{ color:var(--hf-orange) !important; }

/* ── the swappable-slot diagram ───────────────────────────────────────────
   Decorator nests, so it gets .hf-nest. Strategy COMPOSES — a context with a
   pluggable slot — so it needs its own shape: the object on the left, the
   interchangeable implementations stacked on the right, and the currently
   plugged-in one highlighted. Same idea as HAS-A vs IS-A, drawn. */
.hf-slot{ display:grid; gap:16px; align-items:center; }
@media(min-width:600px){ .hf-slot{ grid-template-columns:1fr auto 1fr; } }
.hf-slot .ctx{
  background:#a97a4f; color:#20160f; border-radius:16px; padding:20px 18px;
  text-align:center; font-weight:700;
}
.hf-slot .ctx small{ display:block; font-weight:400; opacity:.8; margin-top:4px; font-size:12.5px; }
.hf-slot .arrow{
  text-align:center; font-family:var(--font-hand); font-size:17px; color:var(--hf-orange);
}
.hf-slot .opts{ display:flex; flex-direction:column; gap:9px; }
.hf-slot .opts span{
  font-family:ui-monospace,Menlo,monospace; font-size:13px;
  background:rgba(0,0,0,.3); color:var(--hf-ink2);
  padding:11px 15px; border-radius:12px; text-align:center;
}
.hf-slot .opts span.on{
  background:var(--hf-good); color:var(--hf-ink); font-weight:700;
  box-shadow:0 0 0 2px var(--hf-orange);
}

/* ── broadcast fan-out ────────────────────────────────────────────────────
   Decorator nests, Strategy slots — Observer BROADCASTS. One subject on top,
   a fan of observers below it, so the one-to-many shape is the thing you see
   first. Arbitrary observer count; they just wrap. */
.hf-cast{ text-align:center; }
.hf-cast .subject{
  display:inline-block; background:#a97a4f; color:#20160f;
  border-radius:16px; padding:16px 26px; font-weight:700;
}
.hf-cast .subject small{ display:block; font-weight:400; opacity:.8; font-size:12.5px; margin-top:3px; }
.hf-cast .fan{
  font-family:var(--font-hand); font-size:17px; color:var(--hf-orange);
  margin:12px 0 6px;
}
.hf-cast .obs{ display:flex; flex-wrap:wrap; gap:10px; justify-content:center; }
.hf-cast .obs span{
  font-family:ui-monospace,Menlo,monospace; font-size:12.5px;
  background:rgba(0,0,0,.3); color:var(--hf-ink2);
  padding:11px 14px; border-radius:12px; position:relative;
}
/* the little riser connecting each observer up to the fan line */
.hf-cast .obs span::before{
  content:''; position:absolute; top:-7px; left:50%; width:1px; height:7px;
  background:rgba(242,232,219,.28);
}
.hf-cast .obs span.new{ box-shadow:0 0 0 2px var(--hf-orange); color:var(--hf-ink); }

/* ── converge (Singleton) ─────────────────────────────────────────────────
   The mirror of .hf-cast: many callers on top, one instance below. Drawing
   it this way makes the danger visible too — every arrow is a thread that
   could race the others to the constructor. */
.hf-one{ text-align:center; }
.hf-one .callers{ display:flex; flex-wrap:wrap; gap:10px; justify-content:center; }
.hf-one .callers span{
  font-family:ui-monospace,Menlo,monospace; font-size:12.5px;
  background:rgba(0,0,0,.3); color:var(--hf-ink2);
  padding:10px 14px; border-radius:12px; position:relative;
}
.hf-one .callers span::after{
  content:''; position:absolute; bottom:-7px; left:50%; width:1px; height:7px;
  background:rgba(242,232,219,.28);
}
.hf-one .funnel{
  font-family:var(--font-hand); font-size:17px; color:var(--hf-orange);
  margin:12px 0 10px;
}
.hf-one .instance{
  display:inline-block; background:#a97a4f; color:#20160f;
  border-radius:16px; padding:16px 30px; font-weight:700;
}
.hf-one .instance small{ display:block; font-weight:400; opacity:.8; font-size:12.5px; margin-top:3px; }

/* ── quick knowledge check ────────────────────────────────────────────────
   Active recall placed MIDWAY through a lesson, not at the end. One question
   about the thing just explained, one tap, and the reasoning revealed for the
   chosen option and the correct one — because why the tempting wrong answer
   is wrong is where the learning happens. No score, no gating. */
.hf-check{
  background:var(--hf-card2); border-radius:var(--hf-r); padding:24px 26px;
  margin:34px 0; border-left:3px solid var(--hf-gold);
}
.hf-check::before{
  content:'Quick check'; display:block; font-size:11px; font-weight:700;
  letter-spacing:.14em; text-transform:uppercase; color:var(--hf-gold);
  margin-bottom:12px;
}
.hf-check .q{
  font-family:var(--font-display); font-weight:700; font-size:clamp(19px,4vw,23px);
  line-height:1.3; color:var(--hf-ink); margin:0 0 18px;
}
.hf-check button{
  display:block; width:100%; text-align:left; cursor:pointer;
  background:rgba(0,0,0,.26); color:var(--hf-ink2);
  border:none; box-shadow:inset 0 0 0 1px var(--hf-line);
  border-radius:14px; padding:14px 17px; margin-bottom:10px;
  font-family:inherit; font-size:15px; line-height:1.45;
  transition:transform .12s ease, box-shadow .12s ease, color .12s ease;
}
.hf-check button:hover{ transform:translateY(-1px); color:var(--hf-ink); }
.hf-check button.right{
  background:rgba(122,138,94,.20); color:var(--hf-ink); font-weight:700;
  box-shadow:inset 0 0 0 2px #8aa06a;
}
.hf-check button.wrong{
  background:rgba(224,122,95,.14); color:var(--hf-ink2);
  box-shadow:inset 0 0 0 2px var(--hf-bad);
}
.hf-check .why{
  margin:2px 0 14px; padding:12px 16px; border-radius:12px;
  background:rgba(0,0,0,.24); color:var(--hf-ink2);
  font-size:14.5px; line-height:1.6;
}
.hf-check .hf-check-verdict{
  margin:6px 0 0; font-family:var(--font-hand); font-size:18px; color:var(--hf-orange);
}
@media (prefers-reduced-motion:reduce){ .hf-check button{ transition:none } }

/* ── algorithm skeleton (Template Method) ─────────────────────────────────
   A numbered recipe where the LOCKED steps and the OPEN ones are visually
   different. The whole lesson is "the base class owns the order, the
   subclass owns two of the steps", so the order must be the thing you see,
   with the overridable steps standing out inside it. */
.hf-steps{ list-style:none; margin:0; padding:0; counter-reset:hfstep; }
.hf-steps li{
  counter-increment:hfstep; position:relative; padding:13px 16px 13px 46px;
  border-radius:13px; margin-bottom:8px; font-size:14.5px;
  background:rgba(0,0,0,.26); color:var(--hf-muted);
  overflow-wrap:anywhere;   /* "customerWantsCondiments()" must not reach the edge */
}
.hf-steps li::before{
  content:counter(hfstep); position:absolute; left:15px; top:13px;
  font-family:ui-monospace,Menlo,monospace; font-size:12.5px; color:var(--hf-muted);
}
.hf-steps li.open{
  background:var(--hf-good); color:var(--hf-ink); font-weight:700;
  box-shadow:inset 0 0 0 2px var(--hf-orange);
}
.hf-steps li.open::before{ color:var(--hf-ink); }
/* The tag floated right, which collides with a long step name on a phone —
   "customerWantsCondiments()" leaves it nowhere to go. Below the name by
   default; inline on the right only when there is room for it. */
.hf-steps li .tag{
  display:block; margin-top:4px;
  font-size:10.5px; letter-spacing:.09em; text-transform:uppercase;
  font-weight:700; color:var(--hf-muted);
}
@media(min-width:620px){
  /* The note goes top-right; the step's prose stays ORDINARY INLINE FLOW.
     This was `display:flex; justify-content:space-between` on the <li>, which
     looks identical for the two-child case and shreds every other one: a text
     node and an inline <code> become SEPARATE flex items, so
     "source — <code>users.stream()</code>" rendered as "source —" ... gap ...
     "users.stream()" spread across the row. Any author writing a <code> or an
     <em> inside a step hit it, and it only showed above 620px.
     A float keeps inline content inline, and degrades the way we already
     degrade on a phone: if the prose is too long to share the line, the note
     drops below it instead of overlapping. */
  .hf-steps li{ display:flow-root; }
  .hf-steps li .tag,
  .hf-steps li > small{ float:right; margin:0 0 0 14px; max-width:48%; text-align:right; }
  .hf-steps li .tag{ display:inline; margin-top:0; }
}
/* Notes read as the quieter half in both placements. */
.hf-steps li > small{ display:block; margin-top:4px; font-size:12px; color:var(--hf-muted); }
.hf-steps li.open .tag{ color:var(--hf-orange2); }

/* ── state transitions ────────────────────────────────────────────────────
   States as rows, each carrying the action that leaves it and where that
   action lands. A ring marks the current state. Drawn as a list rather than
   a graph on purpose: a phone cannot show a readable node-and-edge diagram,
   and "which action moves me where" is the thing being learned anyway. */
.hf-cycle{ display:flex; flex-direction:column; gap:10px; }
.hf-cycle .stt{
  background:rgba(0,0,0,.28); border-radius:14px; padding:14px 17px;
}
.hf-cycle .stt.on{ background:var(--hf-good); box-shadow:inset 0 0 0 2px var(--hf-orange); }
.hf-cycle .nm{
  font-family:ui-monospace,Menlo,monospace; font-size:13.5px; font-weight:700;
  color:var(--hf-ink); display:block;
}
.hf-cycle .go{
  display:block; margin-top:7px; font-size:13px; color:var(--hf-ink2);
  overflow-wrap:anywhere;
}
.hf-cycle .go em{ font-style:normal; color:var(--hf-orange2); font-family:ui-monospace,Menlo,monospace; }
.hf-cycle .arrow{ color:var(--hf-muted); }

/* ═══════════════════════════════════════════════════════════════════════════
   CREAM VARIANT — <html data-hf data-theme="cream">
   Bobby chose cream light, then said to ship dark first and add cream later.
   This is that later: the ENTIRE variant is a token re-statement, because
   every component above draws from --hf-* rather than hardcoding a colour.
   Adding it touches no component rule and no page.

   SELECTOR TRAP, LEARNED THE HARD WAY: write these as
   :is([data-theme="cream"],[data-theme="light"])[data-hf] .thing
   and NEVER as [data-theme="cream"][data-hf],[data-theme="light"][data-hf] .thing --
   the comma makes that a bare root selector plus a light-only rule, so the
   cream half silently matches nothing and the declarations leak onto <html>.

   Two deliberate exceptions, both for legibility rather than taste:
   code panels and the nested-diagram core stay dark (the terminal
   convention the prototype itself follows), and the caution tape darkens
   its stripe so gold still reads on a pale ground.
   ═══════════════════════════════════════════════════════════════════════════ */
:root:is([data-theme="cream"],[data-theme="light"])[data-hf],
:is([data-theme="cream"],[data-theme="light"])[data-hf]{
  --hf-bg:#f5ead8;            /* the cream ground from the prototype */
  --hf-card:#eee7db;
  --hf-card2:#ebddc5;
  --hf-bad:#f7ded2;           /* the problem card, warmed rather than darkened */
  --hf-good:#e6ecd5;          /* the fix card, olive tinted */
  --hf-ink:#201e1d;
  --hf-ink2:#474238;
  --hf-muted:#645c50;         /* was #82796a (3.2:1-3.6:1 on the kit's own
                                 cards) — matched to --muted below, which was
                                 already tuned right; see the AA-token pass. */
  --hf-line:rgba(32,30,29,.16);
  --hf-orange:#c15c30;        /* darkened from #e8734a: the dark-mode accent
                                 does not carry enough contrast on cream */
  --hf-orange2:#8c491a;
  --hf-gold:#8a6b16;          /* likewise — gold on cream needs real depth */
  --hf-blue:#1d3f61;          /* was #3d6795 (3.25:1-4.45:1 depending on
                                 surface) — darkened further; see --info below,
                                 which shares this value and drives .rt-pill/
                                 .rt-dir, the widest-reaching user of it. */

  /* DevHub's own tokens, remapped again for the light ground */
  --bg:#f5ead8; --panel:#eee7db; --panel2:#ebddc5; --panel-2:#ebddc5;
  --border:rgba(32,30,29,.16); --divider:rgba(32,30,29,.16);
  --text:#201e1d; --muted:#645c50;
  --accent:#c15c30; --accent2:#8c491a;
  --good:#56633f; --bad:#a33; --warn:#8a6b16; --info:#1d3f61;
  --blue:#1d3f61; --amber:#8a6b16;
}

/* ── AA-token pass (2026-09-06) ─────────────────────────────────────────────
   The four tokens above fix the invisible/near-invisible cases; these four
   selectors sit on --hf-orange as TEXT (not just as a border/dot/tape
   accent), where #c15c30 measures 3.2:1-3.6:1 on the kit's own cards. Rather
   than darken --hf-orange itself — which would also darken every decorative
   border/dot/tape use that already reads fine — they borrow --hf-orange2,
   the kit's own pre-darkened sibling (already used for exactly this reason
   elsewhere, e.g. .hf-bub.right .who), which clears every cream surface at
   5.1:1+. This is the biggest single win of the pass: .hf-youarehere alone
   is the "you are here" label on all 490 pages that carry the chapter rail. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-youarehere,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-kick,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-practice-kick,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-practice-link,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-railnext{
  color:var(--hf-orange2);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-kick::before{
  background:var(--hf-orange2);
}

/* Code stays dark in both themes — the terminal convention, and it retires
   the whole syntax-contrast problem instead of re-picking seven colours. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] pre{ background:#241d18; border-color:rgba(32,30,29,.14); }
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-expr{ background:#241d18; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-expr .lbl{ color:#9a8874; }

/* Chips and wells were dark-on-dark; on cream they need to be light-on-light. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-scatter span,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-ladder b,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-cast .obs span,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-one .callers span,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-slot .opts span,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-steps li,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-cycle .stt,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-check button,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-check .why,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .st-recent a,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .st-bar .track{
  background:rgba(32,30,29,.07); color:var(--hf-ink2);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-slot .opts span.on,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-steps li.open,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-cycle .stt.on{
  background:#dce5c6; color:var(--hf-ink);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-check button.right{ background:#dce5c6; color:var(--hf-ink); }
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-check button.wrong{ background:#f7ded2; color:var(--hf-ink2); }
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-bub{ background:#ebddc5; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-bub.right{ background:#e6ecd5; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-napkin{ background:#fffaf0; box-shadow:0 8px 22px rgba(46,43,37,.14); }
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-nest .ring{ border-color:rgba(32,30,29,.30); }
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-chapnum{ color:rgba(32,30,29,.06); }
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-rail ol::before,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-rail li:not([aria-current])::before{ border-color:var(--hf-muted); }
/* :not(...) keeps this from out-specifying the aria-current rule above, which
   is what filled the current dot orange — without it the "you are here"
   marker silently becomes an empty circle like every other stop. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-rail li:not([aria-current])::before{ background:var(--hf-bg); }
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-rail li[aria-current]::before{
  background:var(--hf-orange); border-color:var(--hf-orange);
  box-shadow:0 0 0 5px rgba(193,92,48,.16);
}
/* The gold tape needs a darker partner stripe to read on a pale card. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-taped::before{
  background:repeating-linear-gradient(115deg, var(--hf-gold) 0 9px, #d9cbb0 9px 18px);
}

/* ── theme switch ─────────────────────────────────────────────────────────
   Bottom-LEFT on purpose: app.html pins its #dlh-mark-pill bottom-right at
   z-index 9999, and two floating controls fighting for the same corner is a
   collision waiting to happen on a phone. */
.hf-themebtn{
  position:fixed; left:14px; bottom:14px; z-index:60;
  background:var(--hf-card2); color:var(--hf-ink2);
  border:none; box-shadow:0 4px 14px rgba(0,0,0,.3), inset 0 0 0 1px var(--hf-line);
  border-radius:999px; padding:10px 16px; font-family:inherit; font-size:12.5px;
  font-weight:700; letter-spacing:.04em; cursor:pointer;
  transition:transform .12s ease, filter .12s ease;
}
.hf-themebtn:hover{ transform:translateY(-1px); filter:brightness(1.1); }
.hf-themebtn:focus-visible{ outline:2px solid var(--hf-orange); outline-offset:3px; }
@media print{ .hf-themebtn{ display:none } }
@media (prefers-reduced-motion:reduce){ .hf-themebtn{ transition:none } }


/* ── long-token wrapping, kit-wide ──────────────────────────────────────────
   A phone is 390px and a code token is not negotiable: `IllegalStateException:
   stream has already been operated upon or closed` is one word as far as line
   breaking is concerned, and it simply does not fit. Without this it does not
   wrap and it does not scroll — it is CLIPPED, and the reader loses the end of
   the sentence with no visual cue that anything is missing.

   This was invisible for a while because the smoke gate measures overflow on
   the DOCUMENT: a card whose content is 125px too wide clips internally while
   documentElement.scrollWidth stays exactly equal to clientWidth, so the page
   reports clean. tmp_smoke.mjs now measures per-element clipping too.

   min-width:0 matters on the flex children: a flex item's default
   min-width:auto refuses to shrink below its content, which defeats the wrap. */
.hf-card, .hf-card p, .hf-cardtitle, .hf-foot, .hf-ladder b, .hf-ladder i,
.hf-bub p, .hf-bub .who, .hf-napkin, .hf-ask .q, .hf-ask .a, .hf-annot,
.hf-check .q, .hf-check button, .hf-check .why, .hf-terms h4, .hf-terms p,
.hf-say, .hf-deck, .principle{
  overflow-wrap:anywhere; min-width:0;
}

/* ═══════════════════════════════════════════════════════════════════════════
   CREAM REPAIR LAYER — the legacy components, taught to read on cream
   ═══════════════════════════════════════════════════════════════════════════

   The block above re-states TOKENS, which is enough for anything token-driven.
   This block exists because devhub.css does not only use tokens: it hardcodes
   several hundred literal colours that were picked against the navy dark theme,
   and repairs them only under :root[data-theme="light"] — a selector cream
   never matches. Two failure directions result, and both were measured rather
   than guessed (node tmp_contrast.mjs --theme=cream):

     DOWNWARD  a dark-theme near-white (#eef4fb, #cbd5e1, #fff) or neon accent
               (#86efac, #7dd3fc, #facc15) painted onto a pale cream card.
     UPWARD    cream's dark ink (#201e1d) inherited into a surface that STAYS
               dark in both themes — code panels, consoles, the CodeWalk source
               pane. This one hid whole code listings; .cw-src alone was
               unreadable on 448 pages.

   Measured effect of this layer, full 528-page sweep:
     cream   2623 selectors / 8530 instances / 516 pages
          ->  1060 selectors / 1224 instances / 272 pages     (-86% instances)
     dark      48 selectors /  225 instances  ->  identical, 0 new, 0 worse.

   What remains is deliberate: 88% of it is per-page <style> written under names
   invented for one page (.vcr-sandbox, .trigger-cell), which no shared rule can
   name without becoming 1000 page-specific overrides. docs/ROADMAP.md carries
   that as scoped follow-up.

   EVERY selector below is :is([data-theme="cream"],[data-theme="light"])[data-hf]
   — one compound, never a comma between the two theme attributes. vcheck check 7
   fails the build if that trap reappears.
   ═══════════════════════════════════════════════════════════════════════════ */


/* ───── INTRO ─────────────────────────────────────────── */
/* ═══════════════════════════════════════════════════════════════════════════
   CREAM REPAIRS — the .intro teaching card
   (.intro / -head / -kicker / -lead / -tldr / -gist / -cards / -mini / -ciam)

   WHY THIS FILE EXISTS. .intro is the plain-English card at the top of ~492
   pages, so it is the single biggest cream casualty on the site. Three
   independent causes stack up on it:

     1. devhub.css paints the card's prose with LITERAL near-white slates
        (#dbe6f3 lead, #cbd5e1 gist/ciam, #eef4fb gist-b, #fff lead-b) and
        repairs them only under :root[data-theme="light"] — a selector cream
        never matches. Near-white ink on a cream card is ~1.04:1: invisible.

     2. The Head First kit's own marker sweep (devhub.css, "SITEWIDE
        AUTO-EFFECT") forces color:#fff on every <b>/<strong> in the card and
        paints a 38%-accent band behind it. It, too, has a light-only repair.

     3. ~1,600 <p>/<strong>/<span> inside these cards carry an INLINE
        style="color:#…" picked for the dark ground (#94a3b8 body slate, plus
        a whole semantic ramp: emerald = good, rose = danger, amber = careful,
        violet = concept, cyan = term). Inline styles outrank every stylesheet,
        so nothing but !important reaches them.

   Everything here is scoped :is([data-theme="cream"],[data-theme="light"])[data-hf]
   — one compound selector, never a comma between the two themes, because a
   comma there degrades into a bare root selector plus a light-only rule and
   the cream half quietly matches nothing.
   ═══════════════════════════════════════════════════════════════════════════ */


/* ── 1. rebind the accent INSIDE the card ─────────────────────────────────
   The cream token block sets --accent on <html>, but devhub.css sets
   body.track-* { --accent } one level DOWN, so every page body re-shadows it
   with its dark-theme track hue (#dd0031, #38bdf8, #a78bfa …). Anything in
   the card that reads var(--accent) — the ▸ gist bullet, an inline
   style="color:var(--accent)" link, the marker band's color-mix — therefore
   still resolves to a colour chosen for a navy page.

   Rebinding the two accent variables on .intro itself fixes all of those at
   once, at the cause, instead of chasing each consumer. The kit had already
   made this call by hand: it forces .intro-head to ink and .intro-kicker to
   --hf-orange with !important. This just makes the whole card agree. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro-box{
  --accent:var(--hf-orange);
  --accent2:var(--hf-orange2);
}


/* ── 2. the card's body ink ───────────────────────────────────────────────
   One ramp for every prose surface of the card: secondary ink for running
   text, so it sits a step back from headings without ever going pale. These
   are the literals from cause (1); each one is the cream counterpart of the
   #334155 that the legacy light theme already reaches for. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro p,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro li,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro-box,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro-box p,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro-lead,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro-tldr,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro-gist li,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro-ciam,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro-mini p,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro-mini li{
  color:var(--hf-ink2);
}

/* The ▸ that opens each gist bullet. Not text, so no gate flags it, but a
   pale track-accent triangle on cream reads as a smudge; with §1 in place it
   inherits the mocha accent and the list regains its spine. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro-gist li::before{
  color:var(--hf-orange);
}

/* Links in the card. exam-* pages ship <a style="color:var(--accent)">, which
   §1 already redirects; this covers the plain ones, which otherwise keep the
   dark-theme cyan (#22d3ee, 1.52:1 on cream). Blue still reads as "link"
   without leaving the palette. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro a,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro-box a{
  color:var(--hf-blue);
}


/* ── 3. emphasis ──────────────────────────────────────────────────────────
   <b>/<strong> anywhere in the card step UP to primary ink, which is how the
   emphasis was meant to read: devhub.css gives them #fff / #eef4fb / #cdd8e6
   against #cbd5e1 body text — one notch brighter than their surroundings.
   Primary-on-secondary is the same relationship, inverted for a light ground.

   This one selector replaces .intro-lead b, .intro-tldr b, .intro-gist li b,
   .intro-mini li b, .intro-ciam b and their strong twins. <i>/<em> are left
   alone on purpose — they carry no colour of their own and inherit whatever
   their parent now has, so the italic-aside hierarchy survives intact. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro :is(b,strong),
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro-box :is(b,strong){
  color:var(--hf-ink);
}

/* The CIAM rail's little "Spring / CIAM:" label is a <span class="tag">, and
   it is meant to be gold — restated here so §2's ink rule cannot swallow it
   on its way past. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro-ciam .tag{
  color:var(--hf-gold);
}


/* ── 4. the marker sweep ──────────────────────────────────────────────────
   devhub.css highlights every <b>/<strong> in the card with a 38% accent band
   under white text. On cream that is white-on-pale (1.04:1) sitting on a
   thick, muddy stripe. The legacy light theme already worked out the right
   answer — ink-dark text, a THIN band low in the line box, and much less
   pigment — so this is that repair, restated for the selector cream actually
   matches and dropped to 20% because the mocha accent (#c15c30) is a far
   heavier pigment than the slate-blue this was tuned against.

   The band is the same warm wash on every track, and that IS the intent:
   §1 has already rebound --accent inside the card, so the color-mix resolves
   to 20% of the mocha accent rather than 20% of #dd0031 / #38bdf8 / #a78bfa.
   A highlighter is meant to look like one pen; letting each track smear its
   own dark-theme hue across the opening card is what made the un-repaired
   cream page read as a patchwork. Written as color-mix rather than a frozen
   rgba so it keeps following --hf-orange if the palette is ever re-tuned
   (the literal above it is only the no-color-mix fallback). */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro-lead :is(b,strong),
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro-tldr :is(b,strong),
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro-gist :is(b,strong),
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro-ciam :is(b,strong){
  color:var(--hf-ink);
  background:linear-gradient(180deg, transparent 72%, rgba(193,92,48,.20) 72%);
  background:linear-gradient(180deg, transparent 72%, color-mix(in srgb, var(--accent) 20%, transparent) 72%);
}


/* ── 5. the inline-style ramp ─────────────────────────────────────────────
   Cause (3): ~1,600 elements inside these cards hardcode a dark-theme hex in
   a style="" attribute. Nothing in a stylesheet outranks an inline
   declaration, so these are the only !important rules in the file, and each
   is scoped inside .intro so it cannot reach another component's copy of the
   same hex.

   The obvious move — force every inline-coloured element to ink — would work
   and would also delete the colour CODING these cards teach with (green =
   safe, rose = the trap, amber = careful, blue = the term). So instead each
   dark-ground hue is mapped to its cream counterpart: same meaning, enough
   pigment to survive a pale ground. Substring matching is exact here — a
   site-wide scan found `color:` to be the ONLY property inside .intro that
   ever carries a hex, in exactly the form `color:#xxxxxx`.

   ONE SHADE DARKER THAN THE PALETTE TOKENS, on purpose. Many of these spans
   are syntax colouring inside an <code>, and the kit tints inline code with
   an 11% orange wash — the darkest ground anywhere in the card. A hue tuned
   only against the #ebddc5 card washes out the moment it lands on that tint,
   so the semantic ramp is pitched to clear the tint and simply reads richer
   on the plain card. Same hue family as --hf-gold/--hf-blue/--hf-orange2,
   one step deeper. */

/* body slate → secondary ink. 925 of the 1,600, all of them .intro-mini <p>. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro [style*="color:#94a3b8"]{ color:var(--hf-ink2) !important; }

/* near-white "shout" → primary ink. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro [style*="color:#e2e8f0"],
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro [style*="color:white"],
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro [style*="color:#fff"]{ color:var(--hf-ink) !important; }

/* emerald / mint / string-green — "this is the safe one" → the cream olive. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro [style*="color:#34d399"],
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro [style*="color:#20c584"],
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro [style*="color:#c3e88d"],
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro [style*="color:#4ade80"]{ color:#465c26 !important; }

/* rose — "this is the trap" → the cream brick. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro [style*="color:#fb7185"],
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro [style*="color:#f87171"]{ color:#94291f !important; }

/* amber / sand — "careful here" → the cream gold, which is already the deep
   version of exactly this hue. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro [style*="color:#fbbf24"],
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro [style*="color:#f0b46a"],
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro [style*="color:#facc15"]{ color:#6a5010 !important; }

/* cyan / periwinkle / indigo / teal — "this is the term" → the cream blue.
   Four dark-mode blues collapsing into one is intentional: on cream they were
   never distinguishable from each other anyway, only from the body ink. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro [style*="color:#22d3ee"],
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro [style*="color:#82aaff"],
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro [style*="color:#818cf8"],
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro [style*="color:#7c8cf8"],
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro [style*="color:#4ec9b0"]{ color:#35587e !important; }

/* violet — "this is the concept". The one hue with no cream counterpart at
   all, so it gets a plum warmed toward the mocha family rather than the
   electric lavender the dark theme uses; it stays distinguishable from blue
   without turning the card into a patchwork. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro [style*="color:#a78bfa"],
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro [style*="color:#c792ea"],
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro [style*="color:#c084fc"],
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro [style*="color:#b070e8"],
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro [style*="color:#c4b5fd"]{ color:#5d3f75 !important; }

/* salmon / coral — the kit's own dark accent, leaking into page markup →
   the cream deep-orange it was always standing in for. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro [style*="color:#ff7957"],
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro [style*="color:#e67a5f"],
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro [style*="color:#f78c6c"],
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro [style*="color:#e8734a"]{ color:#7a3d13 !important; }

/* pale-yellow callout ink, which a handful of exam pages reuse for .intro b. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro [style*="color:#fde68a"],
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro [style*="color:#fef3c7"]{ color:#6a5010 !important; }


/* ── 6. the dark-panel guard ──────────────────────────────────────────────
   devhub.css supports a code block inside a card (.intro-mini:has(pre) goes
   full-width) and pre stays DARK in both themes by design. No page ships that
   combination today, but the day one does, §3 would drop near-black emphasis
   onto a near-black panel — the exact inverse failure this whole cream pass
   is about. Pre-empt it with the dark ink ramp, which is what that panel is
   lit for. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .intro pre :is(b,strong){
  color:#f2e8db;
}


/* ───── CODEWALK ──────────────────────────────────────── */
/* ═══════════════════════════════════════════════════════════════════════════
   CREAM REPAIR — the DevHubCodeWalk widget (.cw-*)
   Loads after devhub-hf.css. Every selector is gated on
   :is([data-theme="cream"],[data-theme="light"])[data-hf] — ONE compound
   selector, never a comma between two roots — so the dark theme cannot see a
   single declaration in this file, and the hub's legacy data-theme="light"
   gets the same cream treatment kit pages render for "cream".

   WHY THIS WIDGET IS THE WORST THING ON A CREAM PAGE. The codewalk is the one
   component that trips BOTH cream failure modes at once:

     · Its chrome (.cw-head, .cw-panel, .cw-var, .cw-callout) is token-driven,
       so cream correctly flips it to a pale card — and then the colours
       devhub.css hardcoded for a dark ground land on that pale card:
       #86efac on the play button (1.24:1), and #fde68a / #fca5a5 / #a7f3d0 in
       the callouts (1.23–1.46:1). Ink the same value as the paper.
     · Its console (.cw-code, .cw-out, .cw-vis) is hardcoded dark ON PURPOSE —
       the terminal convention devhub.css calls out in its own comment — so
       cream's dark ink (#201e1d) lands on near-black and THE SOURCE CODE
       ITSELF disappears at 1.21:1 on 448 pages. Only the highlighted spans
       (.kw/.str/.num/.fn/.type) survived, because those carry their own
       colour; everything the highlighter did not match — identifiers,
       operators, braces, entire plain lines — went dark on dark. That is why
       a cream codewalk reads as a half-erased page rather than as a bug.

   So the widget does not get one fix, it gets two, split exactly where the
   ground changes: the chrome is repaired AS CREAM, the console is repaired AS
   DARK. Nothing here is a per-page override — each rule repairs a part of the
   component for all ~465 pages that mount it.
   ═══════════════════════════════════════════════════════════════════════════ */


/* ═══ THE CREAM HALF — head, buttons, narration panel ═══════════════════════ */

/* THE PALE-TITLE CAUSE, and it is not in .cw at all: body.track-* sets
   --accent/--accent2 ON <body>, which is BELOW the <html> element where
   devhub-hf.css restates the cream palette. So a track page keeps its
   DARK-THEME accent under cream — #ffd43b on Python, #38bdf8 on Angular,
   #f89820 on Java — and .cw-title{color:var(--accent2)} paints that neon
   straight onto a pale head at 1.06:1. Every other accent-driven bit of the
   chrome (.cw-step, .cw-var .v, the changed-variable border, the button hover
   rule) inherits the same wrong value.

   Restating the two tokens for the chrome repairs all of them at once, and it
   also catches anything a page injects into the panel that this file has never
   seen. The value is the cream accent rather than a darkened track hue,
   because on a cream kit page the track accent has nowhere else to live: the
   h1 gradient is overridden to --hf-ink, kickers are --hf-orange, inline code
   is --hf-orange2. A lone petrol-blue filename over a mocha page is a
   patchwork; --hf-orange2 is the page speaking one language. At 5.1–5.5:1 it
   is also deeper than 33 of the 34 track accents it replaces — the exception
   is .NET's near-navy #512bd4, whose title was already legible on cream at
   5.9:1 and lands at 5.1:1 here. That is the one place in this file where a
   number moves down, and it buys those five pages the same palette as the
   other 460. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .cw-head,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .cw-panel{
  --accent: var(--hf-orange2);
  --accent2:var(--hf-orange2);
}
/* Rules and borders take the lighter --hf-orange so the chrome keeps two tones
   rather than flattening to one; nothing here is text, so it costs no ratio. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .cw-var.changed,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .cw-btn:hover:not(:disabled){
  border-color:var(--hf-orange);
}

/* The play button was mint-on-cream: #86efac over a 12%-alpha green wash, at
   1.24:1 — the widget's primary call to action was the least readable thing in
   it. Re-cast as the cream palette's own "go" chip: the olive fix-card ground
   with the olive rule and ink on top (5.3:1). Solid, not a wash — a
   translucent tint over cream still measures as its own bright base colour, so
   a wash here would look repaired and still gate as broken. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .cw-btn.play{
  background:var(--hf-good);
  border-color:var(--good);
  color:var(--good);
}
/* devhub.css's hover border sits below the rule above and would be swallowed;
   restate it or the play button silently loses its affordance. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .cw-btn.play:hover:not(:disabled){
  border-color:var(--hf-orange);
}

/* Seven pages carry a page-local `button:disabled{background:#334155;
   color:#64748b}`, which out-specifies .cw-btn and drops a dark slate chip
   with grey text into the cream head (2.18:1) — the step controls look broken
   before you have pressed anything. A codewalk button should look like a
   codewalk button whatever a page says about buttons in general, so this puts
   the component's own tokens back at a weight page CSS cannot beat. The
   disabled LOOK still comes from devhub.css's opacity:.4, which is untouched. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .cw-btn:disabled{
  background:var(--panel);
  color:var(--text);
}

/* Callouts are the widget's "gotcha" cards — prose, not console output, even
   though devhub.css's comment files them with the dark panels. Their grounds
   are alpha washes, so under cream the card DID go pale while the text kept
   its dark-theme value: pale yellow card, #fde68a letters, 1.23:1.
   Cream already has an answer for a semantic card, the one --hf-bad/--hf-good
   give the Head First kit: keep the paper pale, let the TINT carry the tone,
   and set normal ink on top (7–8:1) instead of tinting the letters. Solid
   grounds again, for the same reason as the play button. The caution tone has
   no cream token of its own, so it is mixed the way one would be: --hf-gold at
   13% over --hf-card. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .cw-callout{
  background:#e1d7c1;
  border-color:rgba(138,107,22,.38);
  color:var(--hf-ink2);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .cw-callout.bad{
  background:var(--hf-bad);
  border-color:rgba(163,51,51,.34);
  color:var(--hf-ink2);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .cw-callout.ok{
  background:var(--hf-good);
  border-color:rgba(86,99,63,.38);
  color:var(--hf-ink2);
}
/* The bold inside a callout is the sentence's point; give it the full ink so it
   still outweighs the body now that the body is ink rather than a tint. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .cw-callout b,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .cw-callout strong{
  color:var(--hf-ink);
}

/* The changed-variable pulse rings in cyan (rgba(34,211,238,.5)) — the one bit
   of the old dark palette that survives on a cream page as MOTION rather than
   as a colour, which is why it is easy to miss. A colour inside @keyframes
   cannot be re-pointed, so the animation gets a cream twin: same timing,
   orange ring. The keyframes block is inert until the scoped rule below names
   it, so it too is invisible to the dark theme. */
@keyframes cwPulseCream{
  0%  { box-shadow:0 0 0 0 rgba(193,92,48,.45); }
  100%{ box-shadow:0 0 0 12px transparent; }
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .cw-var.changed{
  animation-name:cwPulseCream;
}


/* ═══ THE DARK HALF — the panels that stay dark on purpose ══════════════════ */

/* THE HEADLINE FIX, and the most severe single failure on the site. Three
   surfaces are hardcoded dark in both themes, and cream pushes a dark ink into
   all three. Repairing them one text colour at a time would miss whatever a
   page injects into .cw-vis, so the whole token ramp is restated for the
   INSIDE of these boxes: the dark ink ramp the cream variant already documents
   (#f2e8db / #c9b9a6 / #9a8874), dark card tiers, a light hairline. Anything
   in here that says var(--text) or var(--panel2) now gets a value that belongs
   on a dark ground, including markup this stylesheet has never seen.

   Read it as: the console is not a cream component, it is a piece of the DARK
   theme embedded in a cream page — so it keeps the dark theme's ink AND the
   dark theme's accent (#e8734a/#f0916d are exactly what --hf-orange and
   --hf-orange2 hold when the kit is dark). That is also why the surface moves
   from #04070f / #070b16 — a cold blue-black picked to sit under a navy page —
   to #241d18, the tone devhub-hf.css already gives <pre> under cream. Before
   this, a cream page had two different code colours on it and the codewalk
   column read as a cold hole next to the warm <pre> blocks around it. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .cw-code,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .cw-out,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .cw-vis{
  background:#241d18;
  color:#f2e8db;
  --text:#f2e8db;
  --muted:#9a8874;
  --panel:#2b231c;
  --panel2:#332a21;
  --border:rgba(242,232,219,.14);
  --accent:#e8734a;
  --accent2:#f0916d;
}

/* Program output is the quieter of the two voices in there — it was already
   secondary (#9fb0c9) in the dark theme, so it stays secondary rather than
   being promoted to full ink just because it now could be. Its "output" label
   rides var(--muted), which the ramp above has already turned around: cream's
   #645c50 on near-black was 2.98:1, one of the quiet failures nobody would
   have gone looking for; it is 4.9:1 now. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .cw-out{
  color:#c9b9a6;
}

/* Line numbers are furniture: findable, never competing with the code. #3a4a63
   was a cold slate tuned for the old near-black. This is the dark ramp's muted
   stepped ~60% back toward the console ground — warm, and slightly clearer
   than the gutter has ever been (2.7:1, was 2.2:1). */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .cw-ln{
  color:#6d5f51;
}

/* Row states were tinted with cyan and slate alphas — the remaining cold
   colours. Warm equivalents, and SOLID rather than alpha: the current row is
   the one place code sits on a different background, and a translucent
   highlight there measures as its own base colour, which would flag every
   current line as unreadable while looking perfectly fine on screen. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .cw-line:hover{
  background:#2e2722;
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .cw-line.cur{
  background:#3d352f;
  border-left-color:var(--accent2);
}
/* devhub.css's .cw-line.cur .cw-ln is a 3-class selector — exactly the weight
   of the .cw-ln rule above — so without restating it here the "you are here"
   number would lose its accent to the gutter grey on source order alone. Same
   declaration, said loudly enough to survive. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .cw-line.cur .cw-ln{
  color:var(--accent2);
  font-weight:700;
}

/* One syntax token needed re-tuning rather than riding the surface change:
   comments are the lowest-contrast token by design, so lifting the ground to
   #241d18 would have taken them from 3.7:1 to 3.1:1 — the wrong direction for
   the one token carrying the teacher's own words ("// guard: ignore …"). The
   dark ramp's muted puts them back above where they started (4.9:1) and drops
   the cold slate at the same time. The other five tokens keep their values and
   land between 6.9:1 and 12.1:1 — at or above what devhub-hf.css already ships
   for <pre> keywords on this exact ground (6.2:1), which is the precedent this
   whole re-hueing follows. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .cw-code .cm{
  color:#9a8874;
}


/* ───── SCENARIO ──────────────────────────────────────── */
/* ============================================================================
 * tmp_fix_scenario.css — the animated scenario engine (.rt-*) under CREAM.
 *
 * The engine on 400+ pages was drawn for near-black: every literal in it is a
 * neon picked to glow on #0a0f1e. devhub.css repairs a handful of them for its
 * legacy light theme, but those repairs are keyed on :root[data-theme="light"],
 * which never matches the kit's data-theme="cream" — so on a cream page the
 * run button, the direction pill, the role badges and the legend keep their
 * dark-theme neons and disappear into the paper.
 *
 * There is a second, opposite failure in the same engine: a few pages paint
 * .rt-node / .rt-inspect with a hardcoded near-black, and devhub.css keeps
 * .rt-headers dark on purpose. Cream sets --text to a dark ink, so that ink
 * lands on a dark panel and the step caption vanishes the other way.
 *
 * Every rule below is written
 *     :is([data-theme="cream"],[data-theme="light"])[data-hf] .thing
 * — one selector, both theme names, and nothing that can reach the dark theme.
 * (The comma form is a trap: it splits into a bare root selector plus a
 * light-only rule, and the cream half silently matches nothing.)
 *
 * TWO STANDING DECISIONS, so the rest reads consistently:
 *
 *  1. The console stays dark, the verdict does not. .rt-headers is a raw
 *     HTTP/console dump — it keeps the terminal convention the kit already
 *     uses for <pre>, and gets the DARK ink ramp (#f2e8db/#c9b9a6/#9a8874).
 *     .rt-result is not a console, it is the "so what happened" banner at the
 *     end of the walk, so it becomes a cream card in the kit's own good/bad
 *     colours instead of three saturated dark blocks sitting on paper.
 *
 *  2. Backgrounds set here are OPAQUE. The per-page role tints are all
 *     rgba(hue,.14–.22) with text of the SAME hue — which reads fine over
 *     near-black and turns into hue-on-hue over cream. A translucent repair
 *     would leave the same trap in place (and measures as its own undiluted
 *     hue), so where a surface needs fixing it gets a real colour.
 * ========================================================================== */


/* ── the run button ───────────────────────────────────────────────────────
   422 pages. .rt-run is `rgba(74,222,128,.14)` behind `#86efac` — a mint on a
   mint wash, 1.24:1 on cream, and it is the one control the entire walk hangs
   off. Green still means go, so the hue only gets darkened into the mocha
   ramp's olive (--good) rather than swapped — but it goes FILLED rather than
   tinted-outline. On near-black a faint wash still reads as a button; on paper
   it reads as nothing, and the ▶ ends up quieter than the scenario chips
   sitting next to it, which is backwards for the page's primary action. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-ctlbar .rt-run,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-run,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-go{
  background:var(--good) !important; border-color:#3f4a29 !important;
  color:var(--hf-bg) !important;
}
/* The dark theme answers a hover with a green bloom; on paper a glow is
   invisible, so the press-me feedback becomes a deeper olive instead. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-run:hover:not(:disabled),
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-go:hover:not(:disabled){
  background:#46512f !important; box-shadow:0 2px 10px rgba(86,99,63,.28);
}
/* A few control bars use the generic .runbtn, which draws its text from
   --accent2. Track classes set that on <body>, so it outranks the kit's tokens
   on <html> and stays a dark-theme track neon (#38bdf8 on eleven pages).
   Scoped to .rt-ctlbar: the same class elsewhere is someone else's family. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-ctlbar .runbtn{
  background:var(--hf-card2); border-color:var(--hf-orange); color:var(--hf-orange2);
}


/* ── the stage surfaces ───────────────────────────────────────────────────
   .rt-node and .rt-inspect are token-driven in devhub.css and would follow
   cream for free — except that a handful of pages hardcode the near-black
   themselves (#050a14 on .rt-inspect, and an inline background:#0b1426 on
   every .rt-node of three Java pages). Cream ink then lands on near-black and
   the step caption reads 1.15:1.

   Those three Java pages inline the ENTIRE engine — button, inspector, pill,
   console, every node — as style="" attributes, which no selector can outrank.
   That is the one and only reason the colour properties across this file carry
   !important; it is not there to win arguments with the other cream rules. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-node,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-nd{
  background-color:var(--panel2) !important;
  border-color:var(--border) !important; color:var(--hf-ink) !important;
}
/* That same rule has a second job. A node that carries its own role class
   (.rt-node.who-COMP, .rt-node.who-DB …) was painted by the page with the role
   tint — and the tint is the very hue the node's LABEL is written in, so on
   cream it goes cyan-on-cyan: 1.0:1, the worst measurement in the family.
   Flattening those nodes back to the engine's own card is the honest repair:
   the role is still spelled out in the badge, and 200-odd pages stop reading as
   a pastel patchwork. A hue-preserving version is not available — CSS cannot
   read back a colour it did not declare, and `currentcolor` on `color` resolves
   to the INHERITED value rather than the page's, so there is nothing to darken. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-inspect,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-ins{
  background-color:var(--panel2) !important;
  border-color:var(--border) !important; color:var(--hf-ink) !important;
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-cap,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-cp{ color:var(--hf-ink) !important; }

/* The two lines inside a node — .nl the name, .ns the one-line gloss — read
   var(--text)/var(--muted) in the shared engine and follow cream by
   themselves. A dozen pages typed the dark-theme slates in by hand instead
   (#e2e8f0, #94a3b8, #64748b, and a .boundary variant that dims the label
   further), which on paper leaves the node label lighter than the card it is
   printed on. Putting both back on tokens repairs every one of them. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-node .nl,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-nd .nl{ color:var(--hf-ink); }
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-node .ns,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-nd .ns{ color:var(--muted); }

/* The step markers: on near-black a 50%-alpha neon rim reads as a highlight;
   on cream it washes out entirely, and the walk loses its "you are here". */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-node.vchk{ border-color:var(--good); }
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-node.vskip{ border-color:var(--bad); }
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-node.cur{
  box-shadow:0 0 0 1px var(--info) inset, 0 0 14px rgba(61,103,149,.22);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-node.cur.curbad{
  box-shadow:0 0 0 1px var(--bad) inset, 0 0 14px rgba(170,51,51,.22);
}
/* The travelling chip is opaque --info/--good/--bad, which cream darkens into
   the mocha ramp — so its text has to stop being the dark-theme ink it was
   paired with (#04222a on a now-dark blue was down to 3:1) and go light. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-chip,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-chip.ok,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-chip.bad{ color:#f2e8db; }
/* The rail it slides along is a 40%-opacity gradient tuned to glow on black. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-rail{ opacity:.55; }


/* ── the role badges ──────────────────────────────────────────────────────
   1716 page-instances, and the single largest count in the family. They take
   dozens of per-page modifier classes (who-RES, who-OUT, who-TS, who-CD …,
   plus a few that dropped the prefix entirely: .who.SEC, .who.MVC) but they
   all fail for ONE reason — devhub.css's base `.rt-node .who` rule, #cbd5e1 on
   a slate wash, 1.73:1. So the fix is on the base rule, not on the variants:
   the badge becomes an espresso pill with the dark ink ramp, borrowing the
   same "small dark surface on paper" language the kit uses for <pre>. That
   also swallows the per-page variants whatever hue they declared, including
   the ones that are solid and bright, because both properties are set. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-node .who,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-nd .who,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-node [class*="who-"],
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-nd [class*="who-"]{
  background:#241d18; color:#e8dccb;
}


/* ── the direction pill ───────────────────────────────────────────────────
   424 pages (257 as a div, 167 as a span, plus .down/.cap/.rt-dl clones).
   `rgba(34,211,238,.14)` behind `#7dd3fc` — cyan on cyan, 1.08:1. The pill
   sits on --panel2, so a translucent repair would be invisible against it as
   well as immeasurable; it gets a real, slightly deeper cream ground and the
   cream --info ink. The .bad state keeps its meaning on the kit's pink card. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-dir,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-dl{
  background:#e0d2b6 !important; color:var(--info) !important;
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-dir.bad,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-dl.bad{
  background:var(--hf-bad) !important; color:var(--bad) !important;
}
/* .rt-dir.ok is the same pill mid-walk, on the pages that colour the "it
   worked" direction green — it fails identically and takes the same card. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-dir.ok,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-dl.ok{
  background:var(--hf-good) !important; color:var(--good) !important;
}


/* ── the headers console ──────────────────────────────────────────────────
   This one STAYS dark — it is a raw request/response dump and the terminal
   convention is the point. But it stays dark at the kit's espresso, not at
   devhub's blue-black #040810, so it matches the <pre> blocks on the same
   page instead of reading as a second, colder theme. Its body text gets the
   dark ink ramp; its section label was drawing --accent2, which cream darkens
   to a deep rust that all but disappears on near-black (2.9:1), so on this one
   surface the label goes back to the DARK-theme orange. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-headers{
  background:#241d18 !important; border-color:rgba(32,30,29,.14) !important;
  color:#c9b9a6 !important;
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-headers .ht{ color:#f0916d; }


/* ── the verdict banner ───────────────────────────────────────────────────
   .rt-result is the sentence the whole walk was building to, so it should be
   the loudest thing on the page — and three saturated dark blocks (#052e16,
   #3a2a06, #2a0606) on cream paper is loud in the wrong way. It becomes the
   kit's own olive "fix" card / gold caution / pink "problem" card, which is
   the vocabulary the rest of a Head First page already uses for exactly this
   good / careful / broken distinction. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-result{
  background:var(--hf-card2); color:var(--hf-ink); border:1px solid var(--hf-line);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-result.ok{
  background:var(--hf-good); color:var(--good); border-color:rgba(86,99,63,.35);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-result.warn{
  background:#f4e6c3; color:var(--hf-gold); border-color:rgba(138,107,22,.35);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-result.bad{
  background:var(--hf-bad); color:var(--bad); border-color:rgba(170,51,51,.30);
}


/* ── the stale half of the palette ────────────────────────────────────────
   devhub.css ships two tiers of colour token: the semantic ones (--good/--bad/
   --warn/--info) which the cream block re-states, and a second "named palette"
   (--green/--red/--purple/--orange/--ng/--sp) which it does not. Anything
   written as inline color:var(--green) therefore keeps its dark-theme neon on
   a cream page — 1.42:1 in a legend that is literally explaining what green
   means. Shadowing the stale names on the engine's own containers repairs them
   where this family can see them, without redefining site-wide tokens that
   belong to every other component too. (--cache/--err are the same idea coined
   locally by two pages; they cost one line to honour.) */
:is([data-theme="cream"],[data-theme="light"])[data-hf] :is(.rt-ctlbar,.rt-stage,.rt-diagram,.rt-inspect,.rt-legend){
  --green:var(--good); --sp:var(--good); --cache:var(--good);
  --red:var(--bad);    --ng:var(--bad);  --err:var(--bad);
  --orange:var(--hf-orange2); --purple:#6d51a8;
}


/* ── the legend ───────────────────────────────────────────────────────────
   The legend is the other place (after those three Java pages) where colours
   are written as INLINE styles on the spans, so specificity cannot reach them
   — hence the !important below, and hence the literal-matching
   attribute selectors. There are exactly four such literals across the site
   (#86efac, #fca5a5, #fcd34d, #fde047); every other legend span already uses
   var(--good)/var(--bad)/var(--warn) and follows cream for free. Mapping the
   four onto the same tokens keeps "green = it worked / red = it didn't", which
   is the entire content of the legend, instead of flattening it to ink. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-legend span,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-legend b,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-legend em,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-legend strong{
  color:var(--hf-ink2);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-legend [style*="#86efac"]{ color:var(--good) !important; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-legend [style*="#fca5a5"]{ color:var(--bad) !important; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-legend [style*="#fcd34d"],
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-legend [style*="#fde047"]{ color:var(--hf-gold) !important; }
/* 51 pages also repeat the node role classes as legend keys. Same treatment as
   the badge so the key and the thing it explains look alike — but .who-badge
   is deliberately left alone: those are solid, bright and already legible on
   cream, and they belong to the who-row strip rather than to this engine. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-legend [class*="who-"]:not(.who-badge){
  background:#241d18; color:#e8dccb;
}


/* ── the react pages' .rt-table ───────────────────────────────────────────
   Same rt- prefix, same failure, different component: the header cells are
   `rgba(97,218,251,.1)` behind `var(--accent)`, and because track accents are
   set on <body> they outrank the kit's tokens on <html> — so the text stays
   React cyan and measures 1.0:1 against its own wash. The white hairline
   borders are the same story: invisible the moment the ground is paper. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-table th{
  background:#e0d2b6; color:var(--hf-ink); border-color:var(--border);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .rt-table td{
  color:var(--hf-ink2); border-color:var(--border);
}


/* ───── CHROME ────────────────────────────────────────── */
/* ═══════════════════════════════════════════════════════════════════════════
   CREAM REPAIRS — generic content chrome
   (.panel / .panel2 / .card · .callout and its tones · tables incl. .table and
    table.ref · .dd-link · inline <code> · .badge / .chip / .pill)

   WHAT THIS FAMILY IS. Everything above is the furniture a lesson page is built
   out of — the box the prose sits in, the "watch out" strip, the reference
   table, the cross-link, the little status chip. It is on nearly every one of
   the 528 pages, it is almost never page-specific, and it is where cream fails
   most visibly, because it fails in BOTH directions at once:

     · TOO LIGHT. devhub.css paints this furniture with literals chosen for a
       navy ground — #fde68a callout ink, #38bdf8 on .dd-link, #7dd3fc on inline
       code — and repairs them only under :root[data-theme="light"], a selector
       cream never matches. Pale-yellow letters on a pale-yellow card: 1.23:1.
     · TOO DARK. ~1,500 page-local <style> rules freeze a dark hex onto that same
       furniture — `.callout{background:#011e2e}`, `.table th{background:#0b1426}`,
       `.badge-green{background:#052e16}`, `.pill{background:#0a0f1e}`,
       `tr:nth-child(even) td{background:#111827}`. Cream sets --text to a dark
       ink, so those boxes become near-black holes punched through a cream page,
       and anything inside them that inherits its colour goes dark-on-dark.

   Both directions have ONE cause: a colour was frozen at authoring time against
   the dark theme. So the repair is never per-page; each rule below restates one
   component's surface AND its ink for the cream ground, at a weight that beats
   the page-local copy, and every page using that component gets it.

   ONE MEASUREMENT NOTE THAT SHAPED EVERY VALUE HERE. tmp_contrast.mjs resolves
   an element's background by taking the first PAINTED one it finds and reading
   its rgb — alpha ignored. So `rgba(32,30,29,.07)` over cream, which renders as
   a barely-there wash, is scored as SOLID near-black. A translucent tint here
   would look repaired on screen and still gate as broken (and, worse, would
   hide a genuinely broken descendant behind a false reading). Every ground in
   this file is therefore a SOLID hex, pre-mixed to the colour the alpha version
   actually rendered as. Same pixels, honest measurement.

   Everything is gated on :is([data-theme="cream"],[data-theme="light"])[data-hf]
   — ONE compound selector, never a comma between the two themes: a comma there
   degrades into a bare root selector plus a light-only rule, the cream half
   matches nothing, and the declarations leak onto <html>. The dark theme cannot
   see a single declaration in this file.
   ═══════════════════════════════════════════════════════════════════════════ */


/* ═══ 1. THE CONTAINERS ════════════════════════════════════════════════════ */

/* A panel or a card is the page's paper. Under cream it must BE paper — but a
   handful of pages freeze it dark (`.panel{background:#0a0f1e}`,
   `.card{background:#0a0f1c}`) and everything inside inherits cream ink onto
   near-black, which is the 1.01–1.15:1 "invisible panel" the gate reports as
   `.panel div` and `.panel h4`. Once the paper is cream the body's own ink
   reaches everything in it, which is why this rule can be one declaration long.

   Deliberately no border-color. `.card-accent/-blue/-green/…` carry the left
   stripe that tells the reader what kind of card this is, and they sit at a
   lower weight than this rule; a blanket border-color would silently erase all
   six of them.

   Deliberately no `color` either, and that one was measured rather than
   assumed. No page anywhere sets a text colour on these three containers, so
   pinning the ink buys nothing — while a container-level `color` is INHERITED
   straight down into any page-local dark well nested inside the card
   (`.codepanel{background:#0b1426}` and its cousins), pushing those from cream
   secondary ink to cream PRIMARY ink and making an already-broken well slightly
   darker still (1.84:1 → 1.11:1 on solid-visualizer). The body's cream ink
   already reaches everything that needs it. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .panel,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .card{
  background:var(--panel);
}
/* The second tier keeps its own step down the ramp, so a panel inside a panel
   still reads as nested instead of flattening into one slab. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .panel2{
  background:var(--panel2);
}


/* CLEANING UP AFTER THE RULE ABOVE, on the one page where turning the panel
   back into paper exposes something. angular-auth-state-signals-deep prints a
   live signal signature inside its hardcoded-dark `.panel`, coloured with the
   Material syntax palette (#82aaff key, #c3e88d value, #fca5a5 falsy). Those
   were legible on the navy the panel used to be and are not on cream, so §1
   would have traded two failures for three. This is the only page on the site
   that pairs a frozen-dark .panel with light literals inside it — a page fix by
   nature, kept here so the component rule above is not paid for by a
   regression somewhere else. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .sig .k{ color:var(--hf-blue); }
:is([data-theme="cream"],[data-theme="light"])[data-hf] .sig .v{ color:var(--hf-ink2); }
:is([data-theme="cream"],[data-theme="light"])[data-hf] .sig .v.t{ color:#4f5c33; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] .sig .v.f{ color:#96322c; }


/* ═══ 2. THE CALLOUT ═══════════════════════════════════════════════════════ */

/* The worst chrome component on cream, broken three different ways depending on
   which page you land on:

     a. devhub.css's own `.callout{background:rgba(250,204,21,.08);
        color:#fde68a}` — the wash goes pale under cream while the ink does not,
        so the strip is pale-yellow-on-pale-yellow at 1.23:1. This is the
        `.callout` / `.callout b` / `strong` / `em` / `i` family the gate reports
        across ~36 pages.
     b. Page-local alpha variants (`.callout.info{background:rgba(167,139,250,
        .1)}` and friends, ~60 pages) — same story, different tint.
     c. Page-local SOLID dark variants (`.callout{background:#0b2540}`,
        `.callout.info{background:#011e2e}`, `.callout.warn{background:#2d1b00}`,
        ~50 pages). These mostly clear the gate, because their ink was frozen
        light to match — which is precisely the problem: a navy block with
        pale-blue text sitting in the middle of a cream page. The gate measures
        readability; this one is only visible to the eye.

   One answer covers all three, and it is the answer the cream palette already
   gives every semantic card in the kit: keep the PAPER pale, let a tinted paper
   plus a coloured left rule carry the tone, and put normal reading ink on top
   (7–8:1) instead of tinting the letters.

   Weight: a page's `.callout.warn` is (0,2,0); these are (0,4,0), so the frozen
   colour loses whether it was a wash or a solid. */

/* Base / caution — the default devhub.css tone, gold. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .callout{
  background:#e9dcc2;
  border-color:rgba(138,107,22,.34);
  border-left-color:var(--hf-gold);
  color:var(--hf-ink2);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .callout.warn,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .callout.warning,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .callout.caution{
  background:#ece0c3;
  border-color:rgba(138,107,22,.40);
  border-left-color:var(--hf-gold);
  color:var(--hf-ink2);
}
/* "The fix / this is the safe one" — the kit's olive card. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .callout.good,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .callout.ok,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .callout.success,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .callout.callout-good{
  background:var(--hf-good);
  border-color:rgba(86,99,63,.40);
  border-left-color:#56633f;
  color:var(--hf-ink2);
}
/* "The trap" — the kit's pink problem card. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .callout.bad,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .callout.danger,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .callout.err,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .callout.error{
  background:var(--hf-bad);
  border-color:rgba(140,47,34,.34);
  border-left-color:#8c2f22;
  color:var(--hf-ink2);
}
/* "Worth knowing" — the one tone the cream palette had no card for. Built the
   way --hf-good and --hf-bad were: the cream ground nudged a few points off-hue
   (−12R −4G +6B) rather than a blue borrowed from the dark theme, so it sits
   between the olive and the pink as one more sheet of the same paper instead of
   reading as a cold patch on a warm page. --hf-blue does the pointing, on the
   rule. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .callout.info,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .callout.note,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .callout.tip,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .callout.callout-blue{
  background:#e4e4dd;
  border-color:rgba(61,103,149,.34);
  border-left-color:var(--hf-blue);
  color:var(--hf-ink2);
}

/* Emphasis inside a callout steps UP to primary ink — the same
   primary-on-secondary relationship devhub.css builds with #fff over #fde68a,
   inverted for a light ground. Without it the bold "Takeaway:" that opens most
   callouts inherits body ink and stops being an opening at all. <em>/<i> are
   left to inherit: they carry weight by slant, not by colour. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .callout :is(b,strong){
  color:var(--hf-ink);
}
/* Links in a callout were #38bdf8 sky (the .dd-link default, §6) or a track
   accent. Blue still reads as "link" without leaving the palette. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .callout a{
  color:var(--hf-blue);
}


/* ═══ 3. THE PALETTE LEAK ══════════════════════════════════════════════════ */

/* THE CAUSE BEHIND MOST OF THE REMAINING COLOURED TEXT, and it is not in any
   component. Two halves, one mechanism — a colour reaches these containers
   through a variable whose cream value never arrives:

     a. --accent / --accent2 are set by devhub.css on `body.track-*`, one level
        BELOW the <html> where devhub-hf.css restates the cream palette. Custom
        properties inherit, so the body's DARK-theme track hue wins and cream
        never reaches anything that says var(--accent). Inside this family that
        is `.panel b` at Angular sky #38bdf8 (1.74:1), `.panel code` and
        `.tab-content code` at AWS orange #ff9900 (1.40:1), `.panel2 strong` at
        Angular red #dd0031 (1.00:1) — 34 tracks' worth.
     b. --green / --purple / --red / --orange / --ng / --sp are DevHub's named
        palette, and the cream token block never restates them (it covers
        --good/--bad/--warn/--info/--blue/--amber and stops). So they keep their
        dark-theme neon on a pale ground: `.pill{color:var(--purple)}` on 54
        pages, `.panel2 p{color:var(--purple)}` at 2.03:1, `.card span{color:
        var(--green)}` at 1.42:1.

   Only (a) is repaired here; (b) is a trap, and the note under this rule says
   why. Rebinding the accent pair ON THE CONTAINER repairs every consumer at
   once — including inline `style="color:var(--accent)"`, which no colour rule
   can reach but which resolves its variable from exactly here — instead of
   chasing each declaration one at a time.

   --accent takes the LIGHTER of the two mocha accents and --accent2 the deeper
   one, which inverts the dark theme's pairing on purpose. --accent is the one
   pages also use as a FILL (`.abs-seg button.on{background:var(--accent);
   color:#082f49}`, `.badge{background:var(--accent);color:#0f172a}`), so it has
   to stay light enough for a dark ink to sit on it — #8c491a there measured
   2.04:1. --accent2 is only ever text, so it takes the depth. Both clear the
   floor in both roles: #c15c30 is 3.5:1 as text on a cream card and 3.2:1 as a
   fill under dark ink; #8c491a is 5.1:1 as text. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] :is(.panel,.panel2,.card,.callout){
  --accent:var(--hf-orange);
  --accent2:var(--hf-orange2);
}
/* The named palette — --green/--purple/--red/--orange/--ng/--sp, the six the
   cream token block never restates — is DELIBERATELY not rebound here, and
   that was learned the expensive way. Rebinding them on the container repairs
   `.card p{color:var(--green)}` and its ~20 cousins, and simultaneously breaks
   every page-local dark well nested inside that container: `.hier-box.map
   {color:var(--purple);background:#1a1233}` went from a legible 6.3:1 to 2.1:1,
   and `.btn-green{background:#052e16;color:var(--green)}` from 2.9:1 to 2.1:1.
   Narrowing the rebind to prose tags did not help — those wells are spans and
   divs sitting inside prose. A variable can only be safely re-hued where this
   file owns the surface it lands on, and inside a container it does not own
   every surface. §7 rebinds them on .badge/.chip/.pill, where it does; the
   remainder is a token gap in devhub-hf.css's cream block and is written up in
   this pass's report rather than patched from here. */
/* GUARD, and the reason the rebind is scoped to containers rather than to the
   page. These panels frequently CONTAIN a surface that stays dark on purpose,
   and everything inside one needs the DARK values — #e8734a/#f0916d are exactly
   what --hf-orange/--hf-orange2 hold when the kit is dark. Handing that subtree
   the cream ramp drops near-brown words onto near-black, which is the very
   failure this pass exists to remove; it also caught real text, not just
   hypothetical text — `.err{color:var(--bad)}` inside a <pre> was getting
   cream's #a33 on #241d18 before this line existed.

   The list is exactly devhub.css's own "stays dark in both themes" set: <pre>,
   the three codewalk console panes, .rt-headers and .rt-result. .rt-stage was
   in an earlier draft and had to come out — it is a bare layout grid with no
   background of its own, so gating on it would have handed the dark ramp to a
   whole rt-* widget that cream correctly turns pale. Same weight as the rule
   above, later in source, so it wins the tie for that subtree only. */
:is([data-theme="cream"],[data-theme="light"])[data-hf]
  :is(pre,.cw-code,.cw-out,.cw-vis,.rt-headers,.rt-result){
  --accent:#e8734a;
  --accent2:#f0916d;
  --good:#4ade80;   --bad:#f87171;   --warn:#facc15;
  --info:#7dd3fc;   --blue:#7dd3fc;  --amber:#fbbf24;
  --green:#4ade80;  --sp:#a6e07f;
  --purple:#a78bfa;
  --red:#f87171;    --ng:#fda4af;
  --orange:#fb923c;
}


/* ═══ 4. TABLES ════════════════════════════════════════════════════════════ */

/* Same accent leak as §3, this time reaching the table through page CSS rather
   than an inline style: `.table td:first-child{color:var(--accent)}` (31 pages)
   and `table.ref th{color:var(--accent2)}` (21 pages) paint the dark-theme
   track hue straight onto cream — AWS orange at 1.74:1, Angular sky at 1.60:1.
   Rebinding the pair ON THE TABLE repairs every consumer at once, including the
   per-page ones, instead of chasing each `color:var(--accent)` declaration.
   Safe here in a way it would not be on .panel: a table never contains a
   deliberately-dark widget. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] table,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .table,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .ref{
  --accent:var(--hf-orange2);
  --accent2:var(--hf-orange2);
}

/* The header band. 66 pages freeze it at `background:#0b1426` with
   `color:var(--muted)` — under cream, a near-black bar with mud-brown labels
   (2.8:1) welded across the top of a cream table. The gate lets it through and
   it is the first thing the eye catches as wrong. Card2 is the tier the kit
   already uses for "one step firmer than the page", which is what a header row
   is. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] th{
  background:var(--panel2);
  color:var(--hf-ink2);
  border-bottom-color:var(--border);
}
/* table.ref's header is a label row: the accent IS its only signal, so it keeps
   the accent §4 just corrected. Restated because the `th` rule above would
   otherwise hand it the same ink as every other header and the reference tables
   would lose the one cue that distinguishes them. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .ref th{
  color:var(--hf-orange2);
}

/* Cell rules were frozen at #1e2d40 — a navy hairline that reads as a hard
   black scratch on cream. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] td{
  border-bottom-color:var(--border);
}
/* Verdict cells. A comparison table's whole point is the column that says
   which row is the good one, and 34 pages colour it with frozen pastels —
   `.good{color:#86efac}`, `.bad{color:#fca5a5}` — that land on cream at
   1.42–1.54:1, so the verdict is the least readable thing in the table.
   Scoped to table cells: `.good`/`.bad` are generic enough that a page also
   hangs them on chips and on rows inside dark wells, and those need the
   opposite treatment. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] td:is(.good,.ok,.check){
  color:#4f5c33;
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] td:is(.bad,.err,.no){
  color:#96322c;
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] td:is(.warn,.caution){
  color:#6a5010;
}

/* Row hover and zebra striping are the quietest bug in the family and the most
   alarming to hit: `tr:hover td{background:#0b1426}` (57 pages) and
   `tr:nth-child(even) td{background:#111827}` (7 pages) mean that on cream HALF
   THE ROWS ARE BLACK, and pointing at a row turns it black under your finger,
   taking its text with it. Neither is caught by any gate — one is a hover
state, the other only fails once you notice the text has gone.

   The zebra rule CLEARS the band rather than recolouring it, and that is the
   point: only 7 pages ever asked for striping, so painting a cream band on
   every even row site-wide would fix those 7 by restyling 500 — a design change
   wearing a bug fix's clothes. Transparent removes the black rows and leaves
   every other table exactly as it was. devhub.css's deliberate opt-in,
   .table-stripe, is restated underneath so it keeps the stripes it asked for,
   warm now rather than the slate wash it was tuned with.

   Hover is the opposite case: it is already site-wide behaviour in devhub.css,
   so it only needs its colour turned around — and a transient band is where a
   light theme can afford to be a little more definite than a 3.5% slate wash
   ever was on navy. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] tr:nth-child(even) td{
  background:transparent;
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .table-stripe tr:nth-child(even) td{
  background:#ece2d0;
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] tr:hover td{
  background:#e5d9c2;
}


/* ═══ 5. INLINE CODE ═══════════════════════════════════════════════════════ */

/* devhub-hf.css already re-skins prose code into the kit's orange chip, and it
   outranks the ~170 pages that freeze `code{background:#0b1426}`. What it
   cannot do is hold the colour: an inline `style="color:var(--accent)"` (§3) or
   a page rule at (0,2,x) still repaints the text, and the chip's ground is an
   11% alpha the gate scores as solid #e8734a — which is how `.panel code` lands
   at 1.40:1 and `.card code` at 1.95:1 while looking perfectly fine on screen.

   So the chip is restated with the ground PRE-MIXED to the colour it already
   rendered as (11% of #e8734a over the cream card/page, split between the two)
   and the ink pinned to the accent the kit intended. Identical pixels, an
   honest measurement, and a colour that can no longer be knocked out from a
   page stylesheet. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] code:not(pre code){
  background:#f0dcc9;
  border-color:rgba(193,92,48,.30);
  color:var(--hf-orange2);
}

/* The other half of the same problem, inside a <pre>. Pages hand-colour a token
   as `<pre><code class="kw">from</code> …`; that <code> is excluded from the
   kit's rule, so it keeps devhub.css's `background:rgba(125,211,252,.07)` — a
   7% sky wash the gate scores as solid #7dd3fc, reporting `.panel code` at
   1.00:1 and `code.kw` at 1.58:1 on text that is genuinely 6–9:1 against the
   dark <pre> underneath.

   Dropping the chip is the honest repair rather than a way to quiet the gate: a
   tinted box around one token inside a code block is decoration the syntax
   colour already does better, that tint was a COLD blue sitting on the kit's
   warm #241d18 <pre>, and removing it RAISES the real ratio — the token now
   sits directly on the pre's own ground — instead of lowering it. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] pre code{
  background:transparent;
  border:none;
  padding:0;
}


/* ═══ 6. THE CROSS-LINK ════════════════════════════════════════════════════ */

/* `.dd-link{color:#38bdf8}` with a `#7dd3fc` hover — a sky blue picked to glow
   on navy, landing on cream at 1.74:1, and getting LIGHTER on hover, so the
   link half-disappeared the moment you reached for it. The dashed underline was
   frozen the same way. Cream's own blue reads as a link at 4.7:1 and darkens on
   hover, which is the direction a light theme wants. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .dd-link{
  color:var(--hf-blue);
  border-bottom-color:rgba(61,103,149,.55);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .dd-link:hover{
  color:#2b4a6d;
  border-bottom-color:#2b4a6d;
}
/* Some cross-links carry the colour inline — `style="color: #22d3ee"`, or
   `style="color: var(--warn)"` — which outranks any stylesheet and keeps the
   link cyan on cream (1.47:1). Every such inline value on the site is a
   dark-theme colour: that is the only reason they were written. A cross-link is
   one component with one colour, so the two declarations it owns are restated
   loudly enough to take it back. Scoped to .dd-link[style], so nothing else on
   the page pays for it. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .dd-link[style]{
  color:var(--hf-blue) !important;
  border-bottom-color:rgba(61,103,149,.55) !important;
}


/* ═══ 7. BADGES, CHIPS, PILLS ══════════════════════════════════════════════ */

/* The purest case of "frozen against the dark theme" on the whole site: ~120
   pages define a chip as a SOLID near-black swatch with a neon label —
   `.pill{background:#0a0f1e;color:var(--purple)}` (54 pages),
   `.badge-green{background:#052e16}` (23), `.badge-blue{background:#0e3a47}`
   (18), `.badge.info{background:#0c2436}` (7)… Most clear the gate on a
   technicality, because their ink was frozen light to match their own dark
   ground; what they do to a cream page is scatter it with little black
   stickers. The ones whose ink rides a token instead — `color:var(--good)` over
   #052e16, `color:var(--info)` over #0c2436 — get cream's DARK semantic ink on
   that black and fail outright at 2.16–2.34:1.

   So the chip is rebuilt rather than recoloured: a pale tint carries the tone,
   a deep ink of the same hue carries the label. The neutral case is the cream
   equivalent of the 7%-ink wash devhub-hf.css already gives its own chips and
   wells, pre-mixed solid for the reason in the header — so a page's chips and
   the kit's chips are finally the same object. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .badge,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .chip,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .pill{
  background:#e5dcca;
  color:var(--hf-ink2);
  border-color:rgba(32,30,29,.18);
  /* Chips are also the densest users of inline `style="color:var(--good)"` and
     friends, and a chip never contains a dark widget — so §3's ramp is repeated
     here unguarded, for the ~40% of chips that live outside a .panel/.card. */
  --accent:var(--hf-orange2);
  --accent2:var(--hf-orange2);
  --green:#4f5c33;  --sp:#4f5c33;
  --purple:#5d3f75;
  --red:#96322c;    --ng:#a4444c;
  --orange:#9a4a12;
}
/* Tones. Every name below is a real class from the site, not a guess; one-page
   stragglers fall back to the neutral rule above, which is readable even where
   it is less expressive than the dark original. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .badge.good,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .badge-good,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .badge-green,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .badge-rec,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .chip-green,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .chip.green,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .pill.good,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .pill.green,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .pill-good,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .pill-on{
  background:var(--hf-good);
  color:#3f4a2b;
  border-color:rgba(86,99,63,.45);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .badge.bad,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .badge-bad,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .badge-red,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .chip-red,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .chip.red,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .pill.bad,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .pill-bad,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .pill-off{
  background:var(--hf-bad);
  color:#8c2f22;
  border-color:rgba(140,47,34,.42);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .badge.warn,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .badge-warn,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .badge-amber,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .badge-when,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .chip-amber,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .chip.amber,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .pill.warn,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .pill-warn{
  background:#ece0c3;
  color:#6a5010;
  border-color:rgba(138,107,22,.45);
}
/* Four dark-mode blues and violets collapse into one cream blue on purpose: on
   a pale ground they were never distinguishable from each other, only from the
   body ink. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .badge.info,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .badge-blue,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .badge-cyan,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .badge-purple,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .badge-new,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .chip-purple,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .chip.blue,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .pill.info,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .pill.blue,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .pill.purple,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .pill-info{
  background:#e4e4dd;
  color:#35587e;
  border-color:rgba(61,103,149,.42);
}

/* devhub.css's one gradient chip prints #fff over
   `linear-gradient(90deg,var(--accent),var(--accent2))` — and §3's cause bites
   again: those are the page's DARK-theme track accents, so on Python (#ffd43b)
   or Cloud (#fbbf24) the badge is white text on near-yellow. Rebinding the pair
   rather than repainting the gradient keeps the component's own recipe intact
   and puts white back at 4.3:1. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .badge-glow{
  --accent:var(--hf-orange);
  --accent2:var(--hf-orange2);
}


/* ═══ 8. DARK WELLS DROPPED INTO A CREAM PANEL ═════════════════════════════ */

/* THE INVERSE BUG, in the exact shape the gate reports as `.panel div`
   (23 pages, 1.01:1 — text and paper the same value). Authors inset a
   terminal-looking box inside a panel by writing the ground straight into the
   markup: `<div style="background:#0b1426;border-radius:8px;padding:14px">`.
   334 such elements on 89 pages. Nothing in a stylesheet changed, so the box
   stayed navy while cream turned the ink dark — and the inset went blank.

   The repair is NOT to bleach the box. A dark inset is a deliberate device (the
   same terminal convention devhub-hf.css keeps for <pre>), and repainting 334
   hand-placed grounds — several of which are semantic greens and reds, not code
   wells — would be guessing at intent. Instead the box is told what it is: a
   piece of the DARK theme embedded in a cream page, so it gets the dark ink ramp
   the cream variant already documents (#f2e8db / #c9b9a6 / #9a8874) plus the
   dark card tiers, hairline and accent. Anything inside it that says var(--text)
   or var(--muted) — including markup this file has never seen — now resolves to
   a value that belongs on a dark ground.

   The hex list is generated from the site, not guessed: every literal below is
   an inline background actually present in the markup and measurably dark, so
   the rule covers all 328 of them. A shorter list was tried first — the shades
   used twice or more — and the tail turned out to be exactly where the damage
   was: single-use grounds like `#3d1a00` sit under status chips, so trimming
   them left a handful of chips unreadable for the sake of a tidier selector.
   Matching on the declaration text (`background:` included)
   rather than the bare hex is what keeps a dark BORDER colour from dragging an
   otherwise-cream element into this rule.

   The subject list carries .badge/.chip/.pill as well as "anything inside a
   container", because §7 re-grounds a chip to cream and then assumes it owns
   that ground — and ~26 chips on the site paint their own dark ground inline
   (`<span class="badge" style="background:#003a6e;color:var(--accent)">`),
   where an inline declaration beats §7 and the cream ink §7 hands them lands
   on navy. Those chips are dark surfaces too, so they belong here rather than
   there. */
:is([data-theme="cream"],[data-theme="light"])[data-hf]
  :is(:is(.panel,.panel2,.card,.callout) *,.badge,.chip,.pill):is(
    [style*="background:#0b1426"],
    [style*="background:#1e293b"],
    [style*="background:#060d1a"],
    [style*="background:#1a2840"],
    [style*="background:#1e3a14"],
    [style*="background:#0a0f1e"],
    [style*="background:#0d2e1a"],
    [style*="background:#0a0f1c"],
    [style*="background:#1c1003"],
    [style*="background:#052e16"],
    [style*="background:#070b16"],
    [style*="background:#2e0d0d"],
    [style*="background:#dd0031"],
    [style*="background: #0b1426"],
    [style*="background:#003a6e"],
    [style*="background:#1a1200"],
    [style*="background:#1e1500"],
    [style*="background:#2d1b6b"],
    [style*="background: #dd0031"],
    [style*="background:#090e1a"],
    [style*="background:#1a1040"],
    [style*="background:#1a1a2e"],
    [style*="background:#1a2744"],
    [style*="background:#1a2a10"],
    [style*="background:#1a3040"],
    [style*="background:#1e1b4b"],
    [style*="background:#2d1b0e"],
    [style*="background:#2d2200"],
    [style*="background: #010409"],
    [style*="background: #050a14"],
    [style*="background: #060d1a"],
    [style*="background:#001e3c"],
    [style*="background:#011e2e"],
    [style*="background:#030710"],
    [style*="background:#050a14"],
    [style*="background:#080f1e"],
    [style*="background:#0a1f0a"],
    [style*="background:#0a1f2e"],
    [style*="background:#0a2030"],
    [style*="background:#0a2040"],
    [style*="background:#0c2038"],
    [style*="background:#0d3321"],
    [style*="background:#0e2030"],
    [style*="background:#122838"],
    [style*="background:#162032"],
    [style*="background:#162e38"],
    [style*="background:#1a0808"],
    [style*="background:#1a0a2e"],
    [style*="background:#1a0f2e"],
    [style*="background:#1a1060"],
    [style*="background:#1a2010"],
    [style*="background:#1a3a1e"],
    [style*="background:#1c0a00"],
    [style*="background:#1c1200"],
    [style*="background:#1e1635"],
    [style*="background:#2a1f00"],
    [style*="background:#2d0020"],
    [style*="background:#2d0c0c"],
    [style*="background:#2d1a00"],
    [style*="background:#2d1a1a"],
    [style*="background:#3d1a00"]
  ){
  color:#f2e8db;
  --text:#f2e8db;
  --muted:#9a8874;
  --panel:#2b231c;
  --panel2:#332a21;
  --border:rgba(242,232,219,.14);
  --accent:#e8734a;
  --accent2:#f0916d;
  --good:#4ade80;   --bad:#f87171;   --warn:#facc15;
  --info:#7dd3fc;   --blue:#7dd3fc;  --amber:#fbbf24;
  --green:#4ade80;  --sp:#a6e07f;
  --purple:#a78bfa;
  --red:#f87171;    --ng:#fda4af;
  --orange:#fb923c;
}


/* THE INLINE-COLOUR TAIL, and the one place this file has to shout. ~16 chips
   across the site carry their label colour in a style="" attribute, which
   outranks every stylesheet — so the rules above re-grounded the chip to cream
   and the neon stayed put, taking #86efac and #7dd3fc from "readable on their
   own black sticker" to invisible on the new pale one. Left alone, that would
   be this pass paying for a fix with a regression, so these are !important, and
   they are the only !important declarations in the file.

   Each dark-ground hue maps to the cream counterpart the tones above already
   use — same meaning, enough pigment for a pale ground — rather than being
   flattened to ink, because the colour on a status chip IS the status. Scoped
   inside .badge/.chip/.pill so the same hex somewhere else on the page is
   untouched. Inline `var(--good)`-style values need nothing: those tokens are
   already cream, and §7's ramp handles the six that are not. */
:is([data-theme="cream"],[data-theme="light"])[data-hf]
  :is(.badge,.chip,.pill):not([style*="background"]):is([style*="#86efac"],[style*="#4ade80"],[style*="#bbf7d0"],[style*="#a7f3d0"]){
  color:#3f4a2b !important;
}
:is([data-theme="cream"],[data-theme="light"])[data-hf]
  :is(.badge,.chip,.pill):not([style*="background"]):is([style*="#fca5a5"],[style*="#f87171"],[style*="#fda4af"],[style*="#f472b6"],[style*="#fecaca"]){
  color:#8c2f22 !important;
}
:is([data-theme="cream"],[data-theme="light"])[data-hf]
  :is(.badge,.chip,.pill):not([style*="background"]):is([style*="#fcd34d"],[style*="#fde68a"],[style*="#f59e0b"],[style*="#fbbf24"],[style*="#facc15"],[style*="#fb923c"]){
  color:#6a5010 !important;
}
:is([data-theme="cream"],[data-theme="light"])[data-hf]
  :is(.badge,.chip,.pill):not([style*="background"]):is([style*="#7dd3fc"],[style*="#38bdf8"],[style*="#22d3ee"],[style*="#a78bfa"],[style*="#c4b5fd"],[style*="#c084fc"],[style*="#bae6fd"]){
  color:#35587e !important;
}
:is([data-theme="cream"],[data-theme="light"])[data-hf]
  :is(.badge,.chip,.pill):not([style*="background"]):is([style*="#94a3b8"],[style*="#cbd5e1"],[style*="#e2e8f0"]){
  color:var(--hf-ink2) !important;
}


/* ───── WIDGETS ───────────────────────────────────────── */
/* ============================================================================
 * tmp_fix_widgets.css — cream repairs for the INTERACTIVE TEACHING WIDGETS.
 *
 * Family: the "Try it live" runner (.dlh-tryit-*), the .key-insight callout,
 * the .userseg segmented control, the inline .quiz-* bits, and the two
 * self-contained widget engines — the exam runner (.dq-*, devhub-quiz.js) and
 * the flashcard deck (.df-*, devhub-flashcards.js).
 *
 * Every rule is scoped with :is([data-theme="cream"],[data-theme="light"])[data-hf]
 * so the dark theme cannot see any of it. Written as ONE :is() — never as two
 * comma-separated roots, which is the trap devhub-hf.css documents.
 *
 * ── THE ROOT CAUSE BEHIND HALF THIS FILE ────────────────────────────────────
 * devhub.css re-declares --accent per track on the BODY element:
 *
 *     body.track-react { --accent:#61dafb; --accent2:#0ea5e9; }
 *
 * devhub-hf.css remaps --accent for cream on :root[data-hf] — but :root is
 * <html>, and <body> is its child, so the track value wins for the entire page
 * by inheritance, not by specificity. There is no selector that can outrank it
 * from the root. Result: on every track page --accent silently snaps back to a
 * hue chosen for an espresso background, and anything painted with it goes
 * pale-on-pale. That is why `.userseg button.on` renders white text on #f59e0b
 * (1.62:1) and `.quiz-progress b` renders amber on cream.
 *
 * We deliberately do NOT re-darken --accent itself. Dozens of components paint
 * dark text ON an accent background (`.dlh-tryit-run{color:#0f172a}`,
 * `.dq-btn.primary{color:#0b1020}`, the rt-chip badges …); darkening the token
 * globally would flip every one of those into the same failure we are here to
 * fix, in families other agents own. Instead we publish a SECOND token —
 * --hf-track — carrying each track's identity hue darkened into the cream
 * range, and consume it only where this family needs it. Nothing else in the
 * codebase reads --hf-track, so the blast radius is exactly this file.
 * ========================================================================== */


/* ── the track ramp ───────────────────────────────────────────────────────
   Each value is devhub.css's own track accent with its hue kept, saturation
   capped (~.58, and ~.47 for the blues and violets — those are the ones that
   go electric first when you darken them) so it lands in the mocha family, and
   lightness dropped until it clears ~4.7:1 on the cream ground. That one
   threshold makes every value usable BOTH as text on a cream card AND as a
   solid fill under white text (~5.6:1), which is what lets a single token
   serve `.key-insight strong` and `.userseg button.on` at the same time.

   Read these as "the same brand colour, seen in daylight" — React is still
   cyan, .NET is still purple, Node is still green. Flattening them all to the
   house orange would have been one rule shorter and would have thrown away the
   only thing a learner uses to tell two tracks apart at a glance. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] body.track-angular          { --hf-track:#af2e4b; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] body.track-spring           { --hf-track:#467329; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] body.track-springboot       { --hf-track:#467329; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] body.track-ts               { --hf-track:#2e69ab; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] body.track-debug            { --hf-track:#955928; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] body.track-identity         { --hf-track:#21717e; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] body.track-data             { --hf-track:#866124; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] body.track-ping             { --hf-track:#a72c36; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] body.track-java             { --hf-track:#925b27; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] body.track-config           { --hf-track:#545ec1; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] body.track-interview        { --hf-track:#be3247; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] body.track-tools            { --hf-track:#1f7369; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] body.track-cloud            { --hf-track:#886024; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] body.track-playground       { --hf-track:#1f7559; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] body.track-python           { --hf-track:#326b9c; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] body.track-react            { --hf-track:#237086; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] body.track-go               { --hf-track:#237084; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] body.track-kubernetes       { --hf-track:#4065b3; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] body.track-sql              { --hf-track:#915b26; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] body.track-nodejs           { --hf-track:#4d721e; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] body.track-csharp           { --hf-track:#7d4fc0; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] body.track-php              { --hf-track:#5764a2; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] body.track-ruby             { --hf-track:#ba3a31; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] body.track-rust             { --hf-track:#9d542a; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] body.track-stacks           { --hf-track:#7054c2; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] body.track-mulesoft         { --hf-track:#256f8d; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] body.track-devops           { --hf-track:#1f7556; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] body.track-azure            { --hf-track:#2a6c9f; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] body.track-gcp              { --hf-track:#3e67ac; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] body.track-ai-dev           { --hf-track:#a94b2d; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] body.track-data-science     { --hf-track:#4165b3; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] body.track-web-fundamentals { --hf-track:#ad482e; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] body.track-ai-engineering   { --hf-track:#1f7460; }

/* One derived ink the cream palette did not already name. --hf-gold (#8a6b16)
   is tuned to sit ON a card as a chip fill; used as small bold TEXT on a pale
   ground it only just clears 3.7:1, so the "predict first" label — the one
   sentence in the widget we most want read — gets the gold pulled a third of
   the way toward the ink, which lands at ~5.5:1.

   NOTE FOR ANYONE EXTENDING THIS FILE: do not try to pre-compute a
   track-derived colour here. --hf-track lives on <body>, and a custom property
   resolves its var()s on the element it is DECLARED on — so a --hf-track-*
   shade defined at :root silently bakes in the fallback and every page gets
   the same tint. Derive from --hf-track inside the component rule, where the
   body's value is actually in scope. (Cost me one wrong-coloured card.) */
:is([data-theme="cream"],[data-theme="light"])[data-hf]{
  --hf-gold2:#6a5211;
}


/* ══ 1. THE "TRY IT LIVE" RUNNER — .dlh-tryit-* ═══════════════════════════
   Injected by devhub-tryit.js. The shell already follows --panel/--border, so
   the card itself arrives cream for free; what breaks is every literal the
   engine hardcodes for a dark page. */

/* The predict box is the widget's teaching beat — "guess before you run" — and
   on cream it was a 7%-alpha yellow wash you could not see, wearing #facc15
   text that measured 1.00:1. Two changes: the wash becomes an OPAQUE warm
   parchment (a translucent tint over an already-warm card just muddies it and
   also hides the real contrast from any measuring tool), and the label takes
   the deepened gold. The dashed rule keeps the caution-tape feel. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .dlh-tryit-predict{
  background:#f2ead4; border-color:var(--hf-gold); color:var(--hf-ink2);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .dlh-tryit-predict b{
  color:var(--hf-gold2);
}
/* After the run the same label flips green to say "now compare". #4ade80 is a
   dark-theme green; --good is the cream ramp's olive and reads at ~4.8:1.
   The engine also fades the finished box to .55 — on espresso that reads as
   "settled", because fading toward a dark ground costs little; on cream the
   same fade washes the text most of the way to the paper (~2.1:1 effective).
   Same intent, gentler dose. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .dlh-tryit-predict.done{
  opacity:.74;
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .dlh-tryit-predict.done b{
  color:var(--good);
}

/* The editor and the output pane stay DARK, deliberately — same call
   devhub-hf.css makes for <pre>: a code surface reads as a terminal in both
   themes, and keeping it dark retires the syntax-colour problem instead of
   re-picking seven hues. What we change is the HUE of the dark: the engine
   ships a blue-black (#090e1a / #05080f / #1c2942 borders) which reads as a
   foreign slab dropped onto a mocha page. Same darkness, warmed into espresso. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .dlh-tryit-ed{
  background:#241d18; color:#f2e8db; border-color:rgba(242,232,219,.14);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .dlh-tryit-out{
  border-color:rgba(242,232,219,.14);
}
/* The run log's timing/meta line was slate-blue (#64748b) — on espresso that
   is both off-palette and the dimmest thing in the widget. The dark ink ramp's
   muted step is the same job done in the right family. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .dlh-tryit-out .meta{
  color:#9a8874;
}

/* Run is painted with var(--accent) — the leaked track hue — under near-black
   text, which technically passes and still looks like a neon sticker on
   parchment. Solid track colour, white label: the same "this is the button"
   loudness the dark theme gets, in the daylight version of the hue. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .dlh-tryit-run{
  background:var(--hf-track,var(--hf-orange)); color:#fff;
}


/* ══ 2. THE KEY-INSIGHT CALLOUT — .key-insight ════════════════════════════
   Defined inline on ~102 pages, always the same shape: a 7-8% wash of the
   track's brand hue with <strong>/<em>/<b> painted in that hue at full
   strength. On espresso that pops; on cream it is a pale hue on a pale ground
   — measured at 1.00:1, and the pages that use <em> mid-sentence lose the
   emphasis entirely.

   The wash also becomes a FLAT card, and that is not cosmetic. A translucent
   dark-ish brand tint (Angular's #dd0031, SQL's #cc6600) composites to a light
   card in the browser but reports its UNDILUTED colour to anything reading
   computed styles — so a correctly-darkened label looks like a failure to the
   contrast gate, and a genuinely broken one can look fine. An opaque card is
   honest about what it is.

   The tint is not mixed back in, on purpose. color-mix() would keep the wash
   per-track, but Chromium computes it to `color(srgb 0.86 0.86 0.83)`, and
   every contrast probe on this project reads the first three numbers as 0-255
   channels — so a mixed background measures as BLACK and quietly poisons the
   readings for whatever sits on it. Identity moves to the border and the
   emphasis ink, which are the parts you actually notice; anything MEASURED
   stays a plain literal. (Borders are never probed, so the border keeps its
   mix.) */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .key-insight{
  background:var(--hf-card);
  border-color:color-mix(in srgb, var(--hf-track,var(--hf-orange)) 34%, var(--hf-card));
  color:var(--hf-ink);
}
/* One rule for all three emphasis tags — the pages disagree about which one
   they use, but they all mean "this is the sentence to remember". */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .key-insight :is(strong,b,em){
  color:var(--hf-track,var(--hf-orange2));
}


/* ══ 3. THE SEGMENTED CONTROL — .userseg ══════════════════════════════════ */

/* The selected pill is white-on-var(--accent): on track-data that is white on
   #f59e0b, 1.62:1, and it is the control that tells you WHICH scenario you are
   watching. Track hue at cream depth puts white back at ~5.6:1. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .userseg button.on{
  background:var(--hf-track,var(--hf-orange));
  border-color:var(--hf-track,var(--hf-orange));
  color:#fff;
  /* devhub.css glows this pill violet (rgba(167,139,250,.32)) — a halo tuned
     to bloom against espresso, which on cream just looks like a smudge. */
  box-shadow:0 2px 9px rgba(32,30,29,.20);
}
/* The unselected pills were legible but sat on --muted; the ink ramp's
   secondary step is a step clearer and keeps off/on visibly different. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .userseg button{
  background:var(--hf-card2); color:var(--hf-ink2); border-color:var(--hf-line);
}


/* ══ 4. INLINE QUIZ BITS — .quiz-* ════════════════════════════════════════ */

/* "Question 1 of 7 · score: 0" — the counters are var(--accent), i.e. the
   leaked track hue, on cream. Same token, same fix. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .quiz-progress b{
  color:var(--hf-track,var(--hf-orange2));
}
/* A hand-rolled question well hardcoded to #0a0f1c: under cream the page ink
   turns dark and lands on that near-black block. It is prose, not code, so it
   comes into the light rather than staying a terminal. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .quiz-item{
  background:var(--hf-card2); border-color:var(--hf-line); color:var(--hf-ink);
}


/* ══ 5. THE EXAM RUNNER — .dq-* (devhub-quiz.js) ══════════════════════════
   This engine is a self-contained mini-app: it declares its own --dq-* ramp on
   .dq and never touches DevHub's tokens, so the cream theme could not reach it
   — the exam pages rendered as a slate-blue app dropped into a cream page, and
   the parts hf DOES reach (h2/h4/p inherit --hf-ink) turned dark ink on a dark
   card: .dq-h measured 1.13:1, .dq-mode h4 1.11:1.

   The fix mirrors how devhub-hf.css did the whole cream variant: re-state the
   engine's OWN token names onto the cream ramp, then repair only the literals
   the engine hardcodes underneath them.

   --dq-accent needs !important because the engine writes the exam bank's own
   accent as an INLINE style on the .dq root (root.style.setProperty), and an
   inline declaration outranks any normal rule. Author-!important is the one
   thing that beats it. Without this the progress bars, the domain chip and the
   Next button keep their espresso-tuned hue and sit washed-out on cream —
   white-on-#10b981 measures 2.5:1, which squeaks past a gate and still looks
   like a mistake. The per-bank hue is unrecoverable in CSS (we cannot read a
   colour we did not set), so it yields to the track's cream-depth hue, which
   is the nearest thing to the same identity we can name. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .dq{
  --dq-accent:var(--hf-track,var(--hf-orange)) !important;
  --dq-good:var(--good); --dq-bad:var(--bad);
  --dq-panel:var(--hf-card); --dq-bg:var(--hf-bg);
  --dq-border:var(--hf-line); --dq-muted:var(--hf-muted); --dq-text:var(--hf-ink);
}
/* Every one of these is a hardcoded #0b1426 well — stat tiles, mode cards,
   choices, buttons, bars, the explanation rail. They are chrome, not code, so
   they become the deeper cream the rest of the kit uses for recessed surfaces. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .dq-stat,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .dq-mode,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .dq-bar,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .dq-prog,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .dq-timer,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .dq-choice,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .dq-btn,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .dq-rev-q{
  background:var(--hf-card2);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .dq-expl{
  background:var(--hf-card2); color:var(--hf-ink2);
}
/* The one surface that STAYS dark: .dq-code holds the question's code sample.
   Warmed off the engine's blue-black so it matches the <pre> panels elsewhere
   on the page instead of introducing a second kind of dark. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .dq-code{
  background:#241d18; border-color:rgba(242,232,219,.14); color:#f2e8db;
}
/* Re-stating the state variants: the rules above are more specific than the
   engine's own .dq-btn.primary / .dq-choice.sel, so without these the primary
   button and the selected/correct/wrong answers would all flatten to one well.
   Their washes become flat cream literals for the same reason as .key-insight —
   these panels carry text, so their backgrounds have to measure honestly.
   "Selected" LIFTS off the well rather than tinting it; the accent border and
   the filled keycap are already saying which one you picked. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .dq-btn.primary{
  background:var(--dq-accent); border-color:var(--dq-accent); color:#fff;
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .dq-btn.ghost{ background:transparent; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] .dq-choice.sel{
  background:var(--hf-bg);
}
/* --hf-good / --hf-bad are the kit's olive "the fix" and pink "the problem"
   CARD colours — exactly the two surfaces a right and a wrong answer want. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .dq-choice.correct{ background:var(--hf-good); }
:is([data-theme="cream"],[data-theme="light"])[data-hf] .dq-choice.wrong{   background:var(--hf-bad); }
/* The A/B/C/D keycaps: the engine writes near-black text (#0b1020, #04231a,
   #2a0a0a) on what used to be a bright fill. Those fills are now deep cream
   colours, so the caps flip to white — the inverse bug, caught before it
   shipped rather than after. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .dq-choice.sel .dq-key,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .dq-choice.correct .dq-key,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .dq-choice.wrong .dq-key{
  color:#fff;
}
/* The domain chip and the per-answer verdicts still carry dark-theme literals.
   The chip's violet wash becomes the deeper cream; the accent stays in the
   TEXT, which is where the domain colour was doing its work anyway. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .dq-dchip{
  background:var(--hf-card2);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .dq-why.good{ color:var(--good); }
:is([data-theme="cream"],[data-theme="light"])[data-hf] .dq-why.bad{  color:var(--bad); }
:is([data-theme="cream"],[data-theme="light"])[data-hf] .dq-flag.on{  color:var(--hf-gold2); }


/* ══ 6. THE FLASHCARD DECK — .df-* (devhub-flashcards.js) ═════════════════
   Same shape of problem as the exam runner, and the same inline-accent trap:
   the deck writes --df-accent onto the root with root.style.setProperty, so
   only author-!important can reach it. The deck's dark-tuned brand hue gives
   way to the track's cream depth. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .df{
  --df-accent:var(--hf-track,var(--hf-orange)) !important;
  --df-good:var(--good); --df-bad:var(--bad);
  --df-panel:var(--hf-card); --df-border:var(--hf-line);
  --df-muted:var(--hf-muted); --df-text:var(--hf-ink);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .df-stat,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .df-box,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .df-bar,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .df-btn,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .df-progwrap{
  background:var(--hf-card2);
}
/* The card face is a dark blue GRADIENT, so its background-color computes to
   transparent — a contrast probe climbs straight past it to the light card
   behind and reports everything fine while the answer text is invisible. This
   is the one failure in the family no gate would have caught; it turns up only
   by looking. Cream gradient, ink-ramp answer text. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .df-flash{
  background:linear-gradient(160deg, var(--hf-bg), var(--hf-card2));
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .df-back{ color:var(--hf-ink2); }
:is([data-theme="cream"],[data-theme="light"])[data-hf] .df-hint{
  background:var(--hf-card);
}
/* Same keycap inversion as the exam runner: fills went deep, so labels go white.
   .bad stays an outline button — it is the "I got this wrong" escape hatch and
   should not shout as loudly as "I knew it". */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .df-btn.primary{
  background:var(--df-accent); border-color:var(--df-accent); color:#fff;
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .df-btn.good{
  background:var(--df-good); border-color:var(--df-good); color:#fff;
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .df-btn.bad{
  background:transparent; border-color:var(--df-bad); color:var(--df-bad);
}


/* ───── PAGELOCAL ─────────────────────────────────────── */
/* ============================================================================
 * tmp_fix_pagelocal.css — the cream repair for the PAGE-LOCAL long tail.
 *
 * WHAT THIS FAMILY IS. The other five files in this pass each own a component
 * that devhub.css defines once and 500 pages consume. This one owns the
 * opposite: ~1450 selectors that exist only inside a single page's own
 * <style> block. 513 of the 528 pages carry one, 2.2MB of page-local CSS in
 * total, written over two years by copy-pasting the last visualizer and
 * editing the hexes. Nobody can enumerate that, and this file does not try.
 *
 * WHAT THE TAIL ACTUALLY IS. Measured rather than guessed: every page-local
 * rule that sets a background or a colour, tallied by selector across all 513
 * kit pages. The distribution has a very fat head. Two shapes explain nearly
 * all of the damage, and they are the two the brief predicted:
 *
 *   (a) THE INVERSE BUG — a page hardcodes a dark ground (`background:#0b1426`
 *       and its eleven navy cousins) and lets the text inherit var(--text).
 *       Dark theme: pale ink on navy, fine. Cream: --text becomes #201e1d and
 *       the box goes solid black-on-black. 1453 selectors do this; the top 30
 *       of them account for well over half the pages.
 *   (b) THE ACCENT BUG — a page hardcodes a dark-theme accent (#22d3ee,
 *       #c084fc, #facc15, #86efac) as TEXT on a surface that cream turns pale.
 *       1783 selectors do this.
 *
 * WHAT IS AND IS NOT REACHABLE, because this is the whole judgement call.
 * CSS cannot ask "is this element's background dark?" — a page that writes its
 * own hex is opaque to a query. But it does not have to: these pages are
 * clones of each other, so the SELECTOR NAMES repeat even though the hexes
 * drift. `.code-block` is one name across 115 pages. `.brain` is one name
 * across 21. Naming the recurring class and out-specifying it with
 * :is(...)[data-hf] (0,3,0 against the page's 0,1,0) repairs every page that
 * copied that block — which is the cause fix, one rule deep.
 *
 * The part that is genuinely NOT reachable is the far tail: roughly 1300 of
 * those 1453 selectors appear on one or two pages each, under names invented
 * for that page (`.vcr-sandbox`, `.trigger-cell`, `.lc-step`). Naming them
 * here would be 1300 page-specific overrides, which is the thing rule 3 of
 * this pass forbids and which nobody could maintain. The report says what
 * would actually fix them; it is not CSS.
 *
 * SELECTOR FORM. Every rule below is
 *   :is([data-theme="cream"],[data-theme="light"])[data-hf] …
 * — ONE compound, never a comma between the two theme attributes. The comma
 * form splits into a bare root selector plus a light-only rule and the cream
 * half matches nothing; devhub-hf.css carries the same warning for the same
 * reason.
 * ========================================================================== */


/* ═══ 1. THE SURFACES THAT SHOULD STAY DARK ════════════════════════════════
 *
 * devhub-hf.css already makes this call for <pre>: code panels keep the
 * terminal convention in both themes, because a syntax palette that has to
 * work on two grounds is a palette that works well on neither. The page-local
 * tail contains the same decision made 400 more times under other names —
 * `.code-block` (115 pages), `.code` (97), `.log` (16), `.step-log` (8),
 * `.viz-area` (5) — and cream never hears about any of them.
 *
 * Two things go wrong there and this section fixes both.
 *
 * First the LOOK, which the gate cannot see. These panels are frozen at
 * DevHub's dark-theme navy (#0b1426, #0a0f1e, #050a14, #090e1a, #0b1120 — the
 * same colour spelled five ways). A navy slab dropped into a cream mocha page
 * is the single loudest thing left on the screen after the readability bugs
 * are gone; it reads as a screenshot pasted in from another site. They are
 * repointed at #241d18, the exact ground devhub-hf.css already gives <pre> on
 * cream, so every dark inset on the page is the same dark.
 *
 * Second the READABILITY, which the gate very much can see. A child that says
 * color:var(--text) inside one of these gets cream's near-black ink on a
 * near-black panel — `.panel div.log-area` measured 1.19:1, `.brain em` 1.01:1
 * before this file existed. Rebinding DevHub's tokens ON THE PANEL fixes every
 * such child at once, including the ones written as inline style="color:
 * var(--muted)" that no colour rule can reach, and it is why this is one rule
 * instead of a hunt through 400 pages for descendants.
 *
 * The token list is deliberately the same one tmp_fix_chrome.css publishes for
 * <pre> and the codewalk panes. Two files handing the same subtree two
 * different dark ramps is how a palette starts drifting. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] :is(
  .code-block, .code, .codebox, .code-panel,
  .log, .log-area, .log-line, .logbox, .step-log, .console, .terminal, .term,
  .out, .output, .stdout, .viz-area, .sandbox,
  .result, .verdict,

  /* THE ONLY HANDLE THAT REACHES PAST THE NAMED HEAD. Console panels invented
     for one page get one-page names — .vcr-sandbox, .create-log, .event-log,
     .di-console — so no list of classes will ever catch them. But the pages
     were cloned from each other, so the NAMING is shared even when the class
     is not: whatever else it is called, a console on this site has "sandbox",
     "console", "terminal", "stdout" or "-log" in the class. Matching the
     vocabulary instead of the class turns a per-page override into one rule.
     Deliberately not extended to "-out" or "-box": those catch .callout and
     .fade-out and half the teaching cards, and a false positive here paints a
     cream card black, which is worse than the bug. */
  [class*="sandbox"], [class*="console"], [class*="terminal"],
  [class*="stdout"], [class*="-log"]
){
  background:#241d18;
  border-color:rgba(242,232,219,.13);
  color:#f2e8db;

  /* the dark ink ramp, so inherited var(--text)/var(--muted) children read */
  --text:#f2e8db;  --muted:#9a8874;
  --bg:#1c1613;    --panel:#2b231c;  --panel2:#332a22;  --panel-2:#1c1613;
  --border:rgba(242,232,219,.13);    --divider:rgba(242,232,219,.13);

  /* and the accents at their DARK values — a cream accent here would be the
     very inverse bug this section is removing, one level down */
  --accent:#e8734a; --accent2:#f0916d;
  --good:#4ade80;   --bad:#f87171;    --warn:#facc15;
  --info:#7dd3fc;   --blue:#7dd3fc;   --amber:#fbbf24;
  --green:#4ade80;  --purple:#a78bfa; --red:#f87171;    --orange:#fb923c;
}

/* The semantic readouts keep their meaning, just in the mocha register. A
   green "PASS" slab and a red "FAIL" slab are the fastest thing on the page to
   read and flattening both to brown would throw that away; these are the same
   hues at the depth the dark ground needs. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] :is(.result,.verdict,.out).ok,
:is([data-theme="cream"],[data-theme="light"])[data-hf] :is(.result,.verdict,.out).good,
:is([data-theme="cream"],[data-theme="light"])[data-hf] :is(.result,.verdict,.out).pass{
  background:#1d2a1a; border-color:rgba(122,160,90,.35);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] :is(.result,.verdict,.out).bad,
:is([data-theme="cream"],[data-theme="light"])[data-hf] :is(.result,.verdict,.out).err,
:is([data-theme="cream"],[data-theme="light"])[data-hf] :is(.result,.verdict,.out).fail{
  background:#331d18; border-color:rgba(224,122,95,.35);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] :is(.result,.verdict,.out).warn{
  background:#332a15; border-color:rgba(217,182,78,.35);
}

/* Log lines label themselves with a slate timestamp (#475569 and friends) that
   was picked against DevHub's navy and lands at 2.19:1 on the mocha ground —
   just under the floor, and the kind of miss that only shows up once the panel
   underneath has been re-grounded. The kit already owns a colour for "present
   but secondary on a dark panel". */
:is([data-theme="cream"],[data-theme="light"])[data-hf] :is(
  .log, .log-area, .log-line, .logbox, .step-log, .console, .terminal, .term,
  .out, .output, .stdout, .result, .verdict,
  [class*="sandbox"], [class*="console"], [class*="terminal"],
  [class*="stdout"], [class*="-log"]
) :is(.ts,.time,.stamp,.meta,.lbl,.label){
  color:#9a8874;
}

/* Inline <code> is the one member of the code family that must NOT follow the
   rule above. It sits inside running prose, where a black chip on every third
   word turns a paragraph into a barcode; devhub.css's own light theme makes it
   a tinted inline mark and tmp_fix_chrome.css does the same for cream. 157
   pages nonetheless freeze it at `background:#0b1426` locally, which is why it
   is named here at all — to hand it back to the prose treatment rather than to
   the panel one. Excluded inside the dark panels above, where a nested <code>
   really is on a dark ground. */
:is([data-theme="cream"],[data-theme="light"])[data-hf]
  code:not(pre code):not(.code-block code):not(.code code):not(.log code):not(.result code){
  background:#e0d9ce;
  color:var(--hf-orange2);
}


/* ═══ 2. THE TEACHING CARDS THAT SHOULD HAVE GONE PALE ═════════════════════
 *
 * The other half of pattern (a), and the half where the dark ground was never
 * a design decision — it is just what a card looked like when the only theme
 * was dark. `.brain` (21 pages, `background:#1a1206`), `.principle` (12),
 * `.warn-box` (19), `.info-box` (9), `.good-box` (8), `.dumb` (12) hold plain
 * prose that inherits var(--text). On cream that prose is invisible: `.brain
 * em` measures 1.01:1, which is not "hard to read", it is a blank card.
 *
 * These are not code. They are the page-local spellings of components the kit
 * already owns — `.brain` IS `.hf-brain`, `.dumb` IS `.hf-qa` — so they are
 * given the kit's own cream card rather than a new colour, and the accent pair
 * is rebound with them. Rebinding is safe HERE in a way it is not page-wide
 * (tmp_fix_chrome.css explains why it declined the page-wide version): this
 * file has just declared these surfaces pale, so it owns the ground the ink
 * lands on. That is the whole test for whether a variable may be re-hued. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] :is(
  .brain, .principle, .dumb, .gotcha, .keypoint, .key-point,
  .info-box, .info-note, .infobox,
  .warn-box, .warn-note, .warnbox,
  .good-box, .bad-box, .tip-box,
  .concept-card, .ann-card, .ann-detail, .demo-card, .flow-step,
  .arch-box, .arch, .tree, .stat, .fake-input,
  .topbar, .tabs, .demo, .demo-area
){
  background:var(--hf-card2);
  border-color:var(--hf-line);
  color:var(--hf-ink2);
  --accent:var(--hf-orange); --accent2:var(--hf-orange2);
  --text:var(--hf-ink);      --muted:var(--hf-muted);
}

/* The semantic tints, so a warning card still looks like a warning. Same three
   grounds the kit already names for its own problem/fix cards, which is what
   keeps this from becoming a sixth palette. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] :is(.warn-box,.warn-note,.warnbox,.gotcha,.brain,.principle){
  background:#f3e7c9; border-color:rgba(138,107,22,.30);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] :is(.good-box,.tip-box){
  background:var(--hf-good); border-color:rgba(86,99,63,.30);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .bad-box{
  background:var(--hf-bad); border-color:rgba(163,51,51,.30);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] :is(.info-box,.info-note,.infobox,.dumb){
  background:#e2e6ec; border-color:rgba(61,103,149,.28);
}

/* `.qa-q:hover` freezes a slate hover at #243048 on four pages — on cream that
   is the row you are pointing at going black under the cursor. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .qa-q:hover{
  background:#e2dbd0;
}


/* ═══ 3. BADGES, PILLS AND CHIPS ON A FROZEN DARK GROUND ═══════════════════
 *
 * tmp_fix_chrome.css owns the badge component and the good/bad/green/red
 * variants of it. What it does not reach is the page-local HUE variants —
 * `.badge-blue`, `.badge-amber`, `.badge-purple`, `.badge-new`, `.chip-amber`,
 * `.pill-info` and friends — which each freeze a tailwind-dark ground
 * (#0e3a47, #3a2606, #2e1065, #1e1b4b) and let the label inherit. On cream
 * these are small black lozenges with black text inside them.
 *
 * Every one gets the same treatment: a wash of its own hue at cream weight,
 * with the ink coming from the surrounding page. The chip stays colour-coded —
 * blue still means blue — it just stops being a hole in the card. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] :is(.badge-blue,.chip-blue,.pill-blue,.pill.blue,.badge-ts,.badge-new,.pill-info,.info-note){
  background:#dbe4ee; color:#2c4f75; border-color:rgba(61,103,149,.28);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] :is(.badge-amber,.chip-amber,.pill-amber,.badge-warn,.pill-warn,.badge-when){
  background:#f0e4c2; color:#6a5211; border-color:rgba(138,107,22,.30);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] :is(.badge-purple,.chip-purple,.pill-purple,.badge-space){
  background:#e5dced; color:#5a3b7a; border-color:rgba(90,59,122,.26);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] :is(.badge-red,.chip-red,.pill-red,.badge-ng,.pill-off,.vbadge.no){
  background:var(--hf-bad); color:#8a3a2a; border-color:rgba(163,51,51,.28);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] :is(.badge-time,.chip-time){
  background:var(--hf-good); color:#3f5230; border-color:rgba(86,99,63,.30);
}


/* ═══ 4. THE SLATE UTILITY BUTTONS ═════════════════════════════════════════
 *
 * `button.secondary{background:#475569}` on 30 pages, plus `.btn-gray` (17),
 * `button.sec` (12), `button.alt` (5), `button:disabled` (7). Slate-600 is the
 * awkward middle: pale enough that cream's near-black label only reaches
 * 2.16:1 on it (the gate flags `.controls button.secondary` on 16 pages), dark
 * enough that it reads as a hole punched in the page next to the primary
 * button. A secondary button should be quieter than the primary one, not
 * heavier — so it becomes an outline chip in the ink ramp, which is what
 * "secondary" means on a light ground.
 *
 * The disabled state keeps the same shape at half the ink; giving it its own
 * fill is how a disabled control ends up looking more prominent than an
 * enabled one. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] :is(
  button.secondary, button.sec, button.alt, .btn-gray, .btn-secondary, .btn-sec
){
  background:#e2dbd0;
  color:var(--hf-ink2);
  border:1px solid var(--hf-line);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] button:disabled,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .btn:disabled{
  background:#e6e0d6;
  color:var(--hf-muted);
}
/* The coloured utility buttons freeze the same tailwind darks as the chips. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .btn-blue{ background:#dbe4ee; color:#2c4f75; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] .btn-green{ background:var(--hf-good); color:#3f5230; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] .btn-purple{ background:#e5dced; color:#5a3b7a; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] .btn-amber{ background:#f0e4c2; color:#6a5211; }


/* ═══ 5. THE PAGE-LOCAL SYNTAX PALETTE, OFF ITS PANEL ══════════════════════
 *
 * `.kw` on 183 pages, `.str` on 182, `.num` on 158, `.fn` on 82, `.op` on 65 —
 * the Material-ish token colours every visualizer page pastes into its own
 * <style>. Inside a <pre> they are correct and must not be touched; §1 and
 * devhub-hf.css both keep that ground dark precisely so they stay correct.
 *
 * The breakage is the SAME class names used outside a code panel: an inline
 * `<span class="kw">` in a sentence, a `.ty` in a signature table, a `.fn` in a
 * diagram label. There the card is cream and #c084fc is a lilac smudge.
 *
 * The rule is written as "darken, EXCEPT inside a panel that stays dark",
 * with the exception carried by a :not() rather than by a second rule that
 * puts the colour back. The difference is not stylistic. Putting it back means
 * naming a replacement value, and each of the 183 pages picked its own dark
 * palette (#c792ea here, #c084fc there) — one house value pasted over all of
 * them would silently restyle every code block on the site in cream only.
 * `revert-layer` looks like the way to hand the value back to the page, and is
 * a trap: outside a cascade layer it degrades to `revert`, which rolls past
 * the page's rule to the UA origin and leaves the token with no colour at all.
 * Excluding the subtree means this file never has an opinion there, which is
 * the correct amount of opinion to have about someone else's code panel.
 *
 * The exclusion list is the union of devhub-hf.css's stays-dark set,
 * tmp_fix_chrome.css's, and §1 of this file. A panel that joins that club
 * later has to be added here in the same commit, or its code goes brown-on-
 * brown the moment somebody switches to cream.
 *
 * The values are the dark ramp's own hues pulled down into the mocha family
 * (5–6:1 on the cream card), not a fresh palette — a keyword is still violet,
 * a string is still green, so anyone who learned the colours in dark mode
 * still reads the same code the same way. */
:is([data-theme="cream"],[data-theme="light"])[data-hf]
  :is(.kw,.attr,.str,.val,.num,.type,.ty,.fn,.ann,.prop,.key,.dec,.cls,.tag,.tp,.op,.punc,.cm):not(
    pre *, code *, .code *, .code-block *, .codebox *, .code-panel *,
    .cw *, .rt-headers *, .rt-result *,
    .log *, .log-area *, .log-line *, .logbox *, .step-log *,
    .console *, .terminal *, .term *,
    .out *, .output *, .stdout *, .viz-area *, .sandbox *, .result *, .verdict *,
    [class*="sandbox"] *, [class*="console"] *, [class*="terminal"] *,
    [class*="stdout"] *, [class*="-log"] *
  ){
  color:var(--pl-syn, inherit);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] :is(.kw,.attr){ --pl-syn:#6b3fa0; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] :is(.str,.val){ --pl-syn:#2f6b3a; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] :is(.num,.type,.ty){ --pl-syn:#8c491a; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] :is(.fn,.ann,.prop,.key){ --pl-syn:#3d6795; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] :is(.dec,.cls){ --pl-syn:#7a5c12; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] :is(.tag,.tp){ --pl-syn:#a33; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] :is(.op,.punc){ --pl-syn:#474238; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] .cm{ --pl-syn:#645c50; }
/* The hue is published as a variable and consumed once, rather than written
   into eight copies of the long :not(). Purely so the exclusion list has a
   single home — the last thing this file needs is eight lists drifting apart. */


/* ═══ 6. THE INLINE HIGHLIGHT TINT ═════════════════════════════════════════
 *
 * `.hl` / `.hlgood` / `.hlbad` (38 pages) are the "look at THIS line" wash
 * inside a code block — `rgba(224,140,62,.16)` over the panel. Two things are
 * true about them and both need saying.
 *
 * The gate flags the spans inside them (`.hlgood span.fn` at 1.04:1) but the
 * text is not actually unreadable: the gate reads a background-color and does
 * not composite it against what is behind, so it treats a 16%-alpha orange as
 * if it were solid orange. That is a false positive on today's rendering.
 *
 * It is a false positive that is about to become true, though, and that is why
 * it is fixed rather than waived. The wash was mixed against DevHub's navy;
 * on cream the panel underneath is now #241d18, so every one of these tints
 * composites to a different colour than the page author chose. Stating the
 * composite as an opaque value fixes both at once — the gate measures what is
 * really painted, and the highlight is a deliberate colour again instead of an
 * accident of whatever the panel happens to be this theme. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] :is(
  pre, code, .code, .code-block, .log, .out, .result, .verdict
) :is(.hl,.hlgood,.hlbad){
  background:#4a3520;
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] :is(
  pre, code, .code, .code-block, .log, .out, .result, .verdict
) .hlgood{ background:#2b3d29; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] :is(
  pre, code, .code, .code-block, .log, .out, .result, .verdict
) .hlbad{ background:#4a2c28; }

/* The same three names are also used as a marker sweep in running prose on
   some pages, where the ground is cream and the tint has to go the other way. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hl{ background:#e7d1c0; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hlgood{ background:#d0cdbc; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hlbad{ background:#e4ccc2; }


/* ═══ 7. THE PAGE-LOCAL NAVIGATION AND LINK CHROME ═════════════════════════
 *
 * The table of contents and the back-link are the first two things on nearly
 * every lesson page and they are the last two anybody thinks to theme.
 *
 * `.toc` sits on var(--panel-2), which cream correctly turns pale — but its
 * links draw var(--accent2), and devhub.css sets that pair on `body.track-*`,
 * one level BELOW the <html> where devhub-hf.css restates the cream palette.
 * Custom properties inherit, so the body's dark-theme track hue wins and cream
 * never arrives: Angular's #38bdf8 at 1.60:1, three pages in the sample and 19
 * across the site. tmp_fix_chrome.css repairs this same leak by rebinding the
 * accent pair on .panel/.card/table — the containers it owns. The TOC is not
 * one of those, so it is rebound here, on the same principle and with the same
 * values.
 *
 * `a.back{color:#22d3ee}` (77 pages) and `.topbar a{color:#22d3ee}` (12) are
 * the hardcoded version of the same idea, and no variable will reach those. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] :is(.toc,.toc-box,.contents,.algo-step,.lc-step,.tree-node,.trigger-cell,.legend){
  --accent:var(--hf-orange); --accent2:var(--hf-orange2);
  --text:var(--hf-ink);      --muted:var(--hf-muted);
  --blue:var(--hf-blue);     --info:var(--hf-blue);
  --green:#2f6b3a;  --purple:#5a3b7a;  --red:#a33;  --orange:var(--hf-orange2);
  --ng:#a33;        --sp:#2f6b3a;      --amber:var(--hf-gold);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] a.back,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .back-link,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .topbar a,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .xlink,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .toc a{
  color:var(--hf-orange2);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] a.back:hover,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .topbar a:hover,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .toc a:hover{
  color:var(--hf-orange);
}


/* ═══ 8. THE HEADINGS THE KIT STOPPED SHORT OF ═════════════════════════════
 *
 * devhub-hf.css hands h1 through h4 the display serif and forces their colour
 * to var(--hf-ink), which is why no page-local `h2{color:#22d3ee}` survives on
 * cream. It stops at h4 — reasonably, since the kit's own components never go
 * deeper — and the page-local tail does not: a deep visualizer nests
 * `.trigger-cell h5{color:#facc15}` at 1.14:1, sunflower yellow on a pale card.
 *
 * Extending the same rule two levels down costs one selector and closes the
 * gap for every page that nests that far, rather than for the one page that
 * happened to be in this pass's sample. h5/h6 keep their own size and weight —
 * only the colour is claimed, because colour is the only part cream breaks. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] h5,
:is([data-theme="cream"],[data-theme="light"])[data-hf] h6{
  color:var(--hf-ink);
}
/* …except on the panels §1 keeps dark, where the cream ink would be the
   inverse bug again. Same guard, same list, one compound more specific. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] :is(
  pre, .code, .code-block, .cw-code, .cw-out, .cw-vis, .rt-headers, .rt-result,
  .log, .log-area, .step-log, .console, .terminal, .term,
  .out, .output, .stdout, .viz-area, .sandbox, .result, .verdict,
  [class*="sandbox"], [class*="console"], [class*="terminal"],
  [class*="stdout"], [class*="-log"]
) :is(h5,h6){
  color:#f2e8db;
}


/* ═══ 9. THE TOKENS THE PAGES INVENTED FOR THEMSELVES ══════════════════════
 *
 * The last big cause, and the one that hides best, because nothing about it
 * looks page-local until you go looking.
 *
 * devhub-hf.css's cream block works by restating DevHub's OWN token names onto
 * the mocha ramp — --text, --accent, --good and about a dozen more — and every
 * component that draws from them follows for free. 93 of these pages do not
 * draw from them. A visualizer about change detection opens its <style> with
 * `:root{ --comp:#22d3ee; --sig:#4ade80; --zone:#a78bfa }` and colour-codes its
 * whole diagram off those, because "component / signal / zone" is what the
 * lesson is actually about. The kit has never heard those names, so cream never
 * reaches them and the diagram keeps its full dark-theme neon on a pale card:
 * `.tree-node .name{color:var(--comp)}` at 1.47:1, and 117 more like it.
 *
 * This is a token gap, not a colour bug, so it is fixed as a token gap. The
 * 118 names below are every private property on the site that holds a value too
 * light to read on cream — a closed set, extracted by parsing all 513 kit
 * pages' <style> blocks, not a guess. Each is restated at the same hue pulled
 * into the mocha range (>=4.6:1 on every cream ground the kit defines), so a
 * page that colour-codes "the parent is cyan, the child is violet" still
 * colour-codes it that way; the learner's mapping survives the theme.
 *
 * Declared on <body> rather than :root on purpose. Half these pages write their
 * own `:root{}`, and a custom property set on <html> by this file would tie
 * with theirs on the same element and lose to whichever loads last. <body> is
 * one level down, so it wins for the whole document regardless of load order —
 * the same asymmetry that made devhub.css's `body.track-*` beat the kit's
 * :root, used in the other direction.
 *
 * Where a name meant two different things on two pages (--comp is cyan on one
 * and violet on another) the more common reading wins; both are legible, and
 * the alternative is a per-page override, which is the thing this file exists
 * not to do. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] body{
  --pur:           #5a3b7a;   /* was #a78bfa, 22 pages */
  --ok:            #2f6b3a;   /* was #4ade80, 16 pages */
  --comp:          #5a3b7a;   /* was #a78bfa, 8 pages */
  --java:          #8c491a;   /* was #f89820, 7 pages */
  --spring:        #2f6b3a;   /* was #6db33f, 5 pages */
  --cyan:          #1f6b74;   /* was #22d3ee, 4 pages */
  --hi:            #5a3b7a;   /* was #a78bfa, 4 pages */
  --inj:           #a33b6b;   /* was #f472b6, 4 pages */
  --pending:       #8c491a;   /* was #fbbf24, 4 pages */
  --svc:           #1f6b74;   /* was #22d3ee, 4 pages */
  --child:         #5a3b7a;   /* was #a78bfa, 3 pages */
  --eff:           #a33b6b;   /* was #f472b6, 3 pages */
  --parent:        #1f6b74;   /* was #22d3ee, 3 pages */
  --sig:           #1f6b74;   /* was #22d3ee, 3 pages */
  --cache:         #2f6b3a;   /* was #4ade80 */
  --e2e:           #a33b6b;   /* was #f472b6 */
  --err:           #a33b6b;   /* was #f472b6 */
  --integ:         #1f6b74;   /* was #22d3ee */
  --unit:          #2f6b3a;   /* was #4ade80 */
  --action:        #a33b6b;   /* was #f472b6 */
  --app:           #1f6b74;   /* was #22d3ee */
  --auth:          #8c491a;   /* was #fbbf24 */
  --b1:            #2f6b3a;   /* was #4ade80 */
  --b2:            #1f6b74;   /* was #22d3ee */
  --b3:            #a33b6b;   /* was #f472b6 */
  --b4:            #7a5c12;   /* was #facc15 */
  --bar:           #1f6b74;   /* was #38bdf8 */
  --bar-compare:   #7a5c12;   /* was #facc15 */
  --bar-pivot:     #5a3b7a;   /* was #c084fc */
  --bar-sorted:    #2f6b3a;   /* was #4ade80 */
  --bar-swap:      #a33;   /* was #f87171 */
  --branch1:       #1f6b74;   /* was #22d3ee */
  --branch2:       #a33b6b;   /* was #f472b6 */
  --branch3:       #5a3b7a;   /* was #a78bfa */
  --browser:       #5a3b7a;   /* was #a78bfa */
  --c-O1:          #2f6b3a;   /* was #4ade80 */
  --c-O2n:         #5a3b7a;   /* was #c084fc */
  --c-Olog:        #1f6b74;   /* was #22d3ee */
  --c-On:          #7a5c12;   /* was #facc15 */
  --c-On2:         #a33;   /* was #f87171 */
  --c-Onln:        #8c491a;   /* was #fb923c */
  --cat-combine:   #5a3b7a;   /* was #a78bfa */
  --cat-create:    #2f6b3a;   /* was #4ade80 */
  --cat-error:     #a33;   /* was #f87171 */
  --cat-filter:    #8c491a;   /* was #fbbf24 */
  --cat-multi:     #a33b6b;   /* was #f472b6 */
  --cat-transform: #1f6b74;   /* was #22d3ee */
  --cat-util:      #2c4f75;   /* was #94a3b8 */
  --cell-current:  #7a5c12;   /* was #facc15 */
  --cell-found:    #2f6b3a;   /* was #4ade80 */
  --check:         #7a5c12;   /* was #facc15 */
  --class:         #1f6b74;   /* was #22d3ee */
  --client:        #2c4f75;   /* was #818cf8 */
  --db:            #2f6b3a;   /* was #4ade80 */
  --decorator:     #5a3b7a;   /* was #c084fc */
  --done:          #5a3b7a;   /* was #a78bfa */
  --duck:          #7a5c12;   /* was #facc15 */
  --effect:        #2f6b3a;   /* was #4ade80 */
  --entry-collide: #8c491a;   /* was #fb923c */
  --entry-hit:     #7a5c12;   /* was #facc15 */
  --entry-new:     #2f6b3a;   /* was #4ade80 */
  --feature:       #5a3b7a;   /* was #a78bfa */
  --fly:           #1f6b74;   /* was #22d3ee */
  --fn:            #2c4f75;   /* was #5fa9ff */
  --frame-base:    #2f6b3a;   /* was #4ade80 */
  --frame-memo:    #5a3b7a;   /* was #c084fc */
  --frame-return:  #7a5c12;   /* was #facc15 */
  --gchild:        #a33b6b;   /* was #f472b6 */
  --header-color:  #8c491a;   /* was #f59e0b */
  --hotfix:        #a33;   /* was #f87171 */
  --html:          #8c491a;   /* was #fbbf24 */
  --hydrate:       #2f6b3a;   /* was #4ade80 */
  --inherited:     #2f6b3a;   /* was #4ade80 */
  --item-new:      #2f6b3a;   /* was #4ade80 */
  --item-removing: #a33;   /* was #f87171 */
  --kw:            #5a3b7a;   /* was #c084fc */
  --lb:            #a33b6b;   /* was #f472b6 */
  --linked:        #8c491a;   /* was #fbbf24 */
  --log:           #5a3b7a;   /* was #a78bfa */
  --main:          #1f6b74;   /* was #22d3ee */
  --meta:          #a33b6b;   /* was #f472b6 */
  --net:           #8c491a;   /* was #fb923c */
  --node-highlight:#7a5c12;   /* was #facc15 */
  --node-new:      #2f6b3a;   /* was #4ade80 */
  --node-removing: #a33;   /* was #f87171 */
  --num:           #8c491a;   /* was #fb923c */
  --old:           #2c4f75;   /* was #818cf8 */
  --op:            #a33b6b;   /* was #f472b6 */
  --out:           #2f6b3a;   /* was #4ade80 */
  --override:      #7a5c12;   /* was #facc15 */
  --payload-color: #2c4f75;   /* was #60a5fa */
  --pipe:          #8c491a;   /* was #fbbf24 */
  --quack:         #5a3b7a;   /* was #a78bfa */
  --queue:         #5a3b7a;   /* was #a78bfa */
  --reducer:       #8c491a;   /* was #fbbf24 */
  --release:       #8c491a;   /* was #fb923c */
  --replay:        #a33b6b;   /* was #f472b6 */
  --req:           #1f6b74;   /* was #22d3ee */
  --res:           #2f6b3a;   /* was #4ade80 */
  --selector:      #5a3b7a;   /* was #a78bfa */
  --server:        #1f6b74;   /* was #22d3ee */
  --sig-color:     #2f6b3a;   /* was #4ade80 */
  --signal:        #2f6b3a;   /* was #4ade80 */
  --src:           #1f6b74;   /* was #22d3ee */
  --src2:          #8c491a;   /* was #fbbf24 */
  --src3:          #8c491a;   /* was #fb923c */
  --store:         #1f6b74;   /* was #22d3ee */
  --str:           #8c491a;   /* was #fbbf24 */
  --t1:            #1f6b74;   /* was #22d3ee */
  --t2:            #7a5c12;   /* was #facc15 */
  --t3:            #8c491a;   /* was #fb923c */
  --tpl:           #8c491a;   /* was #fbbf24 */
  --ty:            #1f6b74;   /* was #22d3ee */
  --view:          #8c491a;   /* was #fb923c */
  --vite:          #7a5c12;   /* was #fdd835 */
  --yellow:        #8c491a;   /* was #fbbf24 */
  --young:         #8c491a;   /* was #fbbf24 */
  --zone:          #5a3b7a;   /* was #a78bfa */
}

/* And every one of them back at full strength inside the panels §1 keeps dark.
   Without this the fix above is just the inverse bug relocated: a page whose
   log console prints `color:var(--ok)` would get bottle green on near-black.
   Same list, same order, so the two can be diffed against each other. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] :is(
  pre, .code, .code-block, .codebox, .code-panel,
  .cw-code, .cw-out, .cw-vis, .rt-headers, .rt-result,
  .log, .log-area, .log-line, .logbox, .step-log, .console, .terminal, .term,
  .out, .output, .stdout, .viz-area, .sandbox, .result, .verdict,
  [class*="sandbox"], [class*="console"], [class*="terminal"],
  [class*="stdout"], [class*="-log"]
){
  --pur:           #a78bfa;
  --ok:            #4ade80;
  --comp:          #a78bfa;
  --java:          #f89820;
  --spring:        #6db33f;
  --cyan:          #22d3ee;
  --hi:            #a78bfa;
  --inj:           #f472b6;
  --pending:       #fbbf24;
  --svc:           #22d3ee;
  --child:         #a78bfa;
  --eff:           #f472b6;
  --parent:        #22d3ee;
  --sig:           #22d3ee;
  --cache:         #4ade80;
  --e2e:           #f472b6;
  --err:           #f472b6;
  --integ:         #22d3ee;
  --unit:          #4ade80;
  --action:        #f472b6;
  --app:           #22d3ee;
  --auth:          #fbbf24;
  --b1:            #4ade80;
  --b2:            #22d3ee;
  --b3:            #f472b6;
  --b4:            #facc15;
  --bar:           #38bdf8;
  --bar-compare:   #facc15;
  --bar-pivot:     #c084fc;
  --bar-sorted:    #4ade80;
  --bar-swap:      #f87171;
  --branch1:       #22d3ee;
  --branch2:       #f472b6;
  --branch3:       #a78bfa;
  --browser:       #a78bfa;
  --c-O1:          #4ade80;
  --c-O2n:         #c084fc;
  --c-Olog:        #22d3ee;
  --c-On:          #facc15;
  --c-On2:         #f87171;
  --c-Onln:        #fb923c;
  --cat-combine:   #a78bfa;
  --cat-create:    #4ade80;
  --cat-error:     #f87171;
  --cat-filter:    #fbbf24;
  --cat-multi:     #f472b6;
  --cat-transform: #22d3ee;
  --cat-util:      #94a3b8;
  --cell-current:  #facc15;
  --cell-found:    #4ade80;
  --check:         #facc15;
  --class:         #22d3ee;
  --client:        #818cf8;
  --db:            #4ade80;
  --decorator:     #c084fc;
  --done:          #a78bfa;
  --duck:          #facc15;
  --effect:        #4ade80;
  --entry-collide: #fb923c;
  --entry-hit:     #facc15;
  --entry-new:     #4ade80;
  --feature:       #a78bfa;
  --fly:           #22d3ee;
  --fn:            #5fa9ff;
  --frame-base:    #4ade80;
  --frame-memo:    #c084fc;
  --frame-return:  #facc15;
  --gchild:        #f472b6;
  --header-color:  #f59e0b;
  --hotfix:        #f87171;
  --html:          #fbbf24;
  --hydrate:       #4ade80;
  --inherited:     #4ade80;
  --item-new:      #4ade80;
  --item-removing: #f87171;
  --kw:            #c084fc;
  --lb:            #f472b6;
  --linked:        #fbbf24;
  --log:           #a78bfa;
  --main:          #22d3ee;
  --meta:          #f472b6;
  --net:           #fb923c;
  --node-highlight:#facc15;
  --node-new:      #4ade80;
  --node-removing: #f87171;
  --num:           #fb923c;
  --old:           #818cf8;
  --op:            #f472b6;
  --out:           #4ade80;
  --override:      #facc15;
  --payload-color: #60a5fa;
  --pipe:          #fbbf24;
  --quack:         #a78bfa;
  --queue:         #a78bfa;
  --reducer:       #fbbf24;
  --release:       #fb923c;
  --replay:        #f472b6;
  --req:           #22d3ee;
  --res:           #4ade80;
  --selector:      #a78bfa;
  --server:        #22d3ee;
  --sig-color:     #4ade80;
  --signal:        #4ade80;
  --src:           #22d3ee;
  --src2:          #fbbf24;
  --src3:          #fb923c;
  --store:         #22d3ee;
  --str:           #fbbf24;
  --t1:            #22d3ee;
  --t2:            #facc15;
  --t3:            #fb923c;
  --tpl:           #fbbf24;
  --ty:            #22d3ee;
  --view:          #fb923c;
  --vite:          #fdd835;
  --yellow:        #fbbf24;
  --young:         #fbbf24;
  --zone:          #a78bfa;
}


/* ═══ 10. THE ONE SELF-CONTAINED ENGINE NOBODY CLAIMED ═════════════════════
 *
 * devhub-codegrade.js is a mini-app: per this project's convention it injects
 * its own critical CSS rather than assuming devhub.css is linked, and prices
 * that independence by declaring a private --cg-* ramp. That is the same shape
 * as §9's page-invented tokens, just shipped in a .js instead of a <style>, and
 * it fails the same way — --cg-panel is slate #1e293b, --cg-text is #e2e8f0, so
 * on cream the whole widget stays a dark-theme island: `.cg-head h2` at 1.13:1,
 * `.cg-chip` at 1.00:1, nine pages of it.
 *
 * tmp_fix_widgets.css repairs the two sibling engines this way (--dq-* for the
 * quiz, --df-* for the flashcards) and stops there; codegrade is the third and
 * was not in anyone's list. Same treatment, same token names on the left, the
 * same kit values on the right — three engines that look alike in dark mode
 * should not stop looking alike in cream.
 *
 * --cg-accent takes --hf-track when the page has one, exactly as the other two
 * do, so a codegrade drill on a Rust page picks up the Rust hue and not the
 * house orange. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] :is(.cg,.cg-wrap,.cg-app,[class^="cg-"],[class*=" cg-"]){
  --cg-accent:var(--hf-track,var(--hf-orange));
  --cg-good:var(--good);      --cg-bad:var(--bad);
  --cg-panel:var(--hf-card);  --cg-bg:var(--hf-bg);
  --cg-border:var(--hf-line); --cg-muted:var(--hf-muted); --cg-text:var(--hf-ink);
}
/* The four places the engine wrote a hex instead of reaching for its own ramp.
   Nothing subtle here — they are simply the declarations the token rebind
   above cannot reach, and they are the ones left showing navy. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .cg-prompt{ color:var(--hf-ink2); }
:is([data-theme="cream"],[data-theme="light"])[data-hf] .cg-prog-bar,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .cg-prompt code{ background:#e0d9ce; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] .cg-item:hover{ background:#e2dbd0; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] .cg-tab.on{ background:var(--hf-card2); }
:is([data-theme="cream"],[data-theme="light"])[data-hf] .cg-chip.medium{ color:#7a5c12; }
/* The three difficulty chips wash their tint at ~12% alpha, which on cream
   composites to something the gate reads as solid neon (it does not blend) and
   which in reality is nearly invisible against the card. Opaque tints at cream
   weight fix the measurement and the appearance in the same stroke — the same
   move §6 makes for the inline code highlights, for the same reason. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .cg-chip.easy{ background:var(--hf-good); }
:is([data-theme="cream"],[data-theme="light"])[data-hf] .cg-chip.medium{ background:#f0e4c2; }
:is([data-theme="cream"],[data-theme="light"])[data-hf] .cg-chip.hard{ background:var(--hf-bad); }
:is([data-theme="cream"],[data-theme="light"])[data-hf] .cg-item.on{ background:#e7d1c0; }
/* The editor gutter is a dark strip beside a dark code pane; §1 does not name
   .cg-editor because it is a layout wrapper, not a panel, so the line numbers
   need saying once. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .cg-gutter{ color:#9a8874; }


/* ───── KIT ───────────────────────────────────────────── */
/* ═══════════════════════════════════════════════════════════════════════════
   CREAM REPAIRS — the Head First kit's OWN components (.hf-*)

   Loads AFTER devhub-hf.css. Every selector below is written as ONE compound
   selector, :is([data-theme="cream"],[data-theme="light"])[data-hf] .thing,
   never as two comma-separated roots — the trap devhub-hf.css documents in its
   own cream header, where the comma degrades into a bare root selector plus a
   light-only rule and the cream half quietly matches nothing. Nothing in this
   file can be seen by the dark theme.

   This is the kit's own house, and it fails cream in four distinct ways.

   1. THE CHIP RULE THAT HAD NEVER RUN. devhub-hf.css repaints eleven chip and
      well components for cream in a single rule — `background:rgba(32,30,29,.07);
      color:var(--hf-ink2)`. That rule was written with the comma bug, so until
      it was fixed a moment ago it had never applied to a single cream page.
      Now that it does apply, it is wrong twice over:

        · AS DESIGN. In dark these are WELLS — 26–34% black punched into the
          card, darker than what surrounds them. Inverted onto cream the same
          idea needs a chip LIGHTER than the card, not a 7% black wash. Seven
          percent of black over a card that is already tinted (.hf-card.bad
          #f7ded2, .hf-card.good #e6ecd5) moves the surface by about two
          points of luminance: the chip stops being a chip. The whole teaching
          point of .hf-scatter is "look how many separate classes this is" —
          with no edge, it is one continuous smear.

        · AS MEASUREMENT. tmp_contrast.mjs resolves a background by taking the
          first PAINTED one it finds and reading its rgb, alpha ignored. So a
          translucent chip is measured as opaque #201e1d, and every one of
          those eleven components reports dark-ink-on-near-black at 1.66:1.

      One change answers both: make the chip OPAQUE. Paper (#fbf5ea) with a
      hairline mocha ring is the honest cream inversion of a black well, it
      separates from all five grounds a chip can land on, and it gives the
      gate a real surface to measure. It is also the tone the kit already uses
      for paper elsewhere — .hf-napkin is #fffaf0 on cream.

   2. HAIRLINES AND RINGS DRAWN IN THE WRONG DIRECTION. Several components
      draw their structure with a near-white translucent — the risers under
      the observer fan, the torn edge of the napkin — which is invisible on
      paper. And .hf-check button.wrong rings itself with var(--hf-bad), a
      token cream redefines from a HUE (#e07a5f) into a CARD TINT (#f7ded2):
      the "you picked the tempting wrong one" ring silently disappears against
      its own background. The gate cannot see any of this — no text is
      involved — but a diagram whose connectors vanish is still broken.

   3. THE DARK PANEL THAT KEPT ITS CREAM INK. devhub-hf.css deliberately holds
      .hf-expr dark on cream (the terminal convention) and remembers to repair
      its label — but not the expression itself, which stays var(--hf-orange2).
      Cream darkens that token to #8c491a, so the constructor expression the
      whole order-builder exists to show renders deep clay on near-black at
      2.44:1. On a panel that stays dark, use the DARK ink ramp.

   4. THE TRACK-ACCENT LEAK. devhub.css re-declares --accent per track on the
      BODY (`body.track-java{--accent:#e76f00}`), and body is a child of the
      :root where devhub-hf.css remaps it for cream — so inheritance beats the
      remap and every kit component painted with var(--accent) snaps back to a
      hue chosen for espresso. .hf-brain's header measures 2.35:1 on a Java
      page; .hf-big's whole gradient-clipped sentence would go React cyan on
      cream. Those components move to the kit's own orange, preferring
      --hf-track (published by tmp_fix_widgets.css: each track's identity hue
      darkened for cream) when it is present, so a track page keeps its colour
      instead of being flattened.
   ═══════════════════════════════════════════════════════════════════════════ */


/* ── 1. CHIPS ─────────────────────────────────────────────────────────────
   The mono identifier tiles: a scattered class name, a rung of the ladder, an
   observer in the fan, a caller in the funnel, a pluggable strategy. These
   carry CODE, so they get the full ink rather than the secondary — the dark
   theme mutes them only because a 32%-black well is already loud enough to
   separate them, and paper is not. The ring does the separating instead, and
   a one-pixel lift sells the pile-of-cards reading .hf-scatter is drawn for. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-scatter span,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-ladder b,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-cast .obs span,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-one .callers span,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-slot .opts span,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .st-recent a{
  background:#fbf5ea;
  color:var(--hf-ink);
  box-shadow:inset 0 0 0 1px rgba(32,30,29,.15), 0 1px 2px rgba(60,48,36,.07);
}

/* ── 1b. WELLS ────────────────────────────────────────────────────────────
   The full-width rows: a locked step of the algorithm, a state in the cycle,
   an unanswered option in the quick check. Same paper, but the secondary ink,
   because each of these has an ACTIVE sibling (.open / .on / .right) that must
   out-shout it — flattening every row to full ink would erase the one piece of
   information the component exists to show. .st-bar .track rides the same
   devhub-hf.css rule and is a bare progress groove with no text, so it takes
   the surface and nothing else. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-steps li,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-cycle .stt,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-check button,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .st-bar .track{
  background:#fbf5ea;
  color:var(--hf-ink2);
  box-shadow:inset 0 0 0 1px rgba(32,30,29,.14);
}

/* The reasoning panel is NOT a third option, and stacking a second sheet of
   paper directly under the button the learner just pressed reads as one. Drop
   it a shade and edge it in the same gold the .hf-check header uses, so it
   reads as the box talking back rather than as something else to click. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-check .why{
  background:#f0e7d7;
  color:var(--hf-ink2);
  box-shadow:inset 3px 0 0 var(--hf-gold);
}


/* ── 2. THE ANSWERED STATES ───────────────────────────────────────────────
   devhub-hf.css restates the BACKGROUND of both answered states for cream but
   leaves the dark theme's rings in place. .right survives on luck — its ring
   is a hardcoded #8aa06a. .wrong does not: its ring is var(--hf-bad), which on
   cream is no longer a hue at all but the pink card tint, i.e. the ring is
   painted in almost exactly the colour it is drawn on top of. Give each state
   a ring cream actually has: DevHub's --good/--bad, which the cream block does
   remap to real depth (#56633f / #a33). */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-check button.right{
  box-shadow:inset 0 0 0 2px var(--good);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-check button.wrong{
  box-shadow:inset 0 0 0 2px var(--bad);
}
/* The selected/open rows already get an opaque #dce5c6 from devhub-hf.css and
   an orange ring, so they need nothing here — but their orange ring was tuned
   against a black well. Against paper siblings it is now the only thing
   marking "this one", so it must not also be the palest thing on the card. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-slot .opts span.on,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-steps li.open,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-cycle .stt.on{
  box-shadow:inset 0 0 0 2px var(--hf-orange2);
}
/* .hf-cast's "just added" observer is the one chip in the kit whose ONLY
   marking is a ring — it has no fill of its own — and its rule lives in the
   unthemed base at .hf-cast .obs span.new, one class lighter than the cream
   chip rule above. Restating the surface therefore erased the entire point of
   the Observer walk: "watch a new observer appear and start getting notified".
   Put the ring back above the chip's own weight. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-cast .obs span.new{
  box-shadow:0 0 0 2px var(--hf-orange2), 0 1px 2px rgba(60,48,36,.07);
}


/* ── 3. STRUCTURE DRAWN IN THE WRONG DIRECTION ────────────────────────────
   Three details are painted as translucent CREAM because in dark theme every
   line has to be lighter than what it sits on. On paper they are white on
   white. Flip them to translucent ink at the same weight — same drawing, same
   subtlety, visible. Without the risers the observer fan and the singleton
   funnel lose the one-to-many shape they exist to draw; without the dashed
   inset the napkin stops looking torn and starts looking like a plain box. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-cast .obs span::before,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-one .callers span::after{
  background:rgba(32,30,29,.30);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-napkin::before{
  border-color:rgba(32,30,29,.20);
}
/* The floating theme switch carries a 30%-black drop shadow sized for an
   espresso ground. On cream that is a bruise under a pale pill; the same lift
   in the mocha family reads as a shadow instead of a stain. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-themebtn{
  box-shadow:0 6px 18px rgba(60,48,36,.18), inset 0 0 0 1px var(--hf-line);
}


/* ── 4. THE PANEL THAT STAYS DARK ─────────────────────────────────────────
   devhub-hf.css holds .hf-expr at #241d18 on cream on purpose and repairs its
   .lbl to the dark muted ramp — then leaves the expression itself on
   var(--hf-orange2), which cream has just darkened to #8c491a for use on
   paper. Deep clay on near-black: 2.44:1. A panel that keeps the dark ground
   keeps the dark ink, so this takes the accent the DARK theme uses. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-expr{
  color:#f0916d;
}


/* ── 5. COMPONENTS PAINTED WITH --accent ──────────────────────────────────
   Every rule in this block exists because --accent is re-declared per track on
   <body>, one level below the :root where cream remaps it, so on ~500 track
   pages these components silently render a neon chosen for espresso. Prefer
   --hf-track (each track's identity darkened for cream, published by
   tmp_fix_widgets.css) and fall back to the kit's own clay when it is absent,
   so a page keeps its track colour rather than being flattened to orange. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-brain{
  border-color:var(--hf-track, var(--hf-orange2));
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-brain .hf-brain-head{
  color:var(--hf-track, var(--hf-orange2));
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-qa{
  border-left-color:var(--hf-track, var(--hf-orange2));
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-qa::before,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-qa dt::before{
  color:var(--hf-track, var(--hf-orange2));
}
/* .hf-big is the one sentence a lesson wants remembered, and it is drawn by
   clipping a gradient to the glyphs — so an accent leak does not dim it, it
   erases it: color is literally `transparent`, and on a React page the two
   stops become #61dafb → #0ea5e9 on cream. (This is also why the contrast gate
   is blind to it: it reads the computed colour, which is transparent, and
   scores it as black.) Both stops move into the mocha family. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-big{
  background:linear-gradient(90deg, var(--hf-track, var(--hf-orange)), var(--hf-orange2));
  -webkit-background-clip:text; background-clip:text;
}


/* ── 6. KIT COMPONENTS DEFINED IN devhub.css ──────────────────────────────
   The kit is split across two files: the chapter components live in
   devhub-hf.css and are token-driven, but the prose components — sticky note,
   marker pen, receipt, chain, before/after — live in devhub.css and were
   written before the cream theme existed, so they carry dark-theme literals.
   None of them has a :root[data-theme="light"] repair, which is why none of
   them survives cream. They are lightly used today and heavily recommended in
   CLAUDE.md, so they get fixed now rather than after the next page uses one. */

/* #dbe6f3 is the near-white slate the dark theme reads prose in. On a cream
   card it is roughly 1.1:1 — a receipt and a chain of wrapped classes that
   render as empty boxes. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-receipt{
  color:var(--hf-ink2);
  border-color:var(--hf-line);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-receipt .row.total{
  border-top-color:var(--hf-line);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-chain .n{
  color:var(--hf-ink2);
}

/* The marker sweep. Its four washes are the dark theme's neons at ~1/3 alpha;
   over cream they read as highlighter only by accident, and the cyan one reads
   as nothing at all. Rebuild each from the token cream already darkened for
   this ground, keeping the 55% baseline so the pen still looks like a pen. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-mark{
  background:linear-gradient(180deg, transparent 55%,
    color-mix(in srgb, var(--hf-gold) 34%, transparent) 55%);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-mark.g{
  background:linear-gradient(180deg, transparent 55%,
    color-mix(in srgb, var(--good) 28%, transparent) 55%);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-mark.r{
  background:linear-gradient(180deg, transparent 55%,
    color-mix(in srgb, var(--bad) 26%, transparent) 55%);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-mark.b{
  background:linear-gradient(180deg, transparent 55%,
    color-mix(in srgb, var(--info) 26%, transparent) 55%);
}

/* .hf-v is the only one of the five coloured prose spans cream forgot: it
   draws var(--purple), and the cream token block remaps --good/--bad/--warn/
   --info but not --purple, so "concept" words stay #a78bfa — lavender on
   cream, about 1.7:1. #5d3f75 is the value tmp_fix_chrome.css darkens --purple
   to for cream; matching it keeps one violet on the page rather than two. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-v{
  color:#5d3f75;
}

/* The Post-it is already light-on-light, so it survives cream — but it is
   nailed up with a 35%-black shadow and a WHITE strip of tape, both drawn to
   read against espresso. On cream the shadow is a bruise and the tape is
   invisible, so the note stops looking stuck on and starts looking inset. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-note{
  box-shadow:2px 4px 12px rgba(60,48,36,.16), 0 1px 0 rgba(255,255,255,.5) inset;
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-note::before{
  background:rgba(60,48,36,.10);
  border-left-color:rgba(32,30,29,.14);
  border-right-color:rgba(32,30,29,.14);
}

/* The exaggerated before/after. Its two panels are translucent neons — which
   the gate reads as fully opaque #f87171 and #4ade80, and which on cream read
   as a patch of a different palette dropped onto the page. The kit already
   HAS these two tones: --hf-bad and --hf-good are literally "the problem card"
   and "the fix card", which is what .hf-vs is. Use them, and let the fills
   carry the contrast the way .hf-card.bad/.good do — depth from tone, not from
   an outline, which is the kit's stated card language. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-vs > .bad{
  background:var(--hf-bad);
  border-color:var(--hf-line);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .hf-vs > .good{
  background:var(--hf-good);
  border-color:var(--hf-line);
}


/* ── 7. ADOPTED: the two kit boxes the pages hand-rolled ──────────────────
   FLAG FOR THE INTEGRATOR — .brain and .dumb are not .hf-* and are not in any
   stylesheet: they are page-local <style> rules, identical across the files
   that carry them, on 21 and 12 pages respectively. They are the Head First
   Brain Power and "there are no Dumb Questions" boxes, written by hand before
   .hf-brain / .hf-qa existed. They freeze a dark hex (#1a1206, #0a1f2e,
   #0b1a10) as their ground, so cream's dark ink lands on near-black and the
   whole exercise reads at 1.01–1.12:1 — invisible, on kit chapter pages, in
   the two boxes most central to how this book teaches. No CSS family owns
   them, so this file takes them and paints them as what they are: the kit's
   own two boxes, in the kit's own tones. Drop this block if another agent
   claims .brain/.dumb; nothing above it depends on it. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .brain{
  background:var(--hf-card2);
  border:1px solid var(--hf-line);
  border-left:4px solid var(--hf-gold);
  color:var(--hf-ink2);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .brain em{
  color:var(--hf-ink);
}
/* The bold lead-in ("Brain Power.") is painted var(--warn) on most of these
   pages — which cream remaps, so it survives — but var(--accent2) on one,
   which the per-track body declaration turns into #a78bfa lavender: 2.03:1 the
   moment the box stops being near-black. Settle all 21 pages the way
   devhub-hf.css settles `.principle b`: the bold is INK, and the rail down the
   left carries the colour. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .brain b,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .dumb b{
  color:var(--hf-ink);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .dumb{
  background:var(--hf-card);
  border:1px solid var(--hf-line);
  border-left:4px solid var(--hf-blue);
  color:var(--hf-ink2);
}
:is([data-theme="cream"],[data-theme="light"])[data-hf] .dumb .a,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .dumb em{
  color:var(--hf-ink2);
}
/* Repainting the ground exposes what was hiding on it: the cross-links inside
   these boxes are a track accent or the #38bdf8 .dd-link sky, both of which
   only looked fine because they were sitting on near-black. Same answer the
   chrome family gives links on a cream callout — the kit's blue still reads as
   "link" without leaving the palette — stated here so this block cannot make a
   page worse on its own. !important is the only thing that reaches them: one of
   these cross-links carries style="color:var(--accent2)" ON THE ELEMENT, and
   --accent2 is re-declared per track on <body>, so it resolves to #f89820 on a
   Java page no matter what any stylesheet says. */
:is([data-theme="cream"],[data-theme="light"])[data-hf] .brain a,
:is([data-theme="cream"],[data-theme="light"])[data-hf] .dumb a{
  color:var(--hf-blue) !important;
}

/* ═══════════════════════════════════════════════════════════════════════════
   LESSON CHROME — six components four pages already author and NOTHING styled.

   Found 2026-09-05 while building the Render section, which needs the same
   parts. shell-cli-basics / shell-aws-cli / shell-azure-cli / shell-gcloud-cli
   all emit .hf-meta, .hf-badge, .hf-question, .hf-numcards, .hf-refhead and
   .hf-refgrid, and none of the three shared files (devhub.css, this file,
   devhub-lesson.js) contained a single rule for any of them — so the numbered
   "why learn this" cards rendered as an undifferentiated stack, the command
   reference as a run-on list, and the difficulty badges as plain text. The
   markup was right; the stylesheet had simply never caught up with it.

   Written against the --hf-* variables ONLY. The cream block above re-declares
   every one of them, so the light theme is carried automatically and this
   section needs no [data-theme] selector — which also means it cannot trip the
   comma-vs-:is() bug documented in CLAUDE.md, because it has no theme selector
   to get wrong.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── the badge row under the back link: difficulty · reading time · scope ── */
.hf-meta{ display:flex; flex-wrap:wrap; gap:8px; align-items:center; margin:2px 0 18px; }
.hf-badge{
  font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  font-size:11px; font-weight:700; letter-spacing:.05em;
  padding:5px 12px; border-radius:999px;
  background:var(--hf-card2); color:var(--hf-ink2);
  border:1px solid var(--hf-line);
}
/* the difficulty chip leads the row, so it gets the accent and the others
   stay quiet — one loud thing per row is the whole point of a badge. */
.hf-badge.level,.hf-badge.mid{ color:var(--hf-orange); border-color:var(--hf-orange); }

/* ── the opening question: the hook before any explaining starts ────────── */
.hf-question{
  display:flex; gap:14px; align-items:flex-start;
  background:var(--hf-card); border:1px solid var(--hf-line);
  border-left:3px solid var(--hf-orange);
  border-radius:0 var(--hf-r) var(--hf-r) 0; padding:18px 22px; margin:0 0 26px;
}
.hf-question .ico{
  font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  font-size:15px; font-weight:700; color:var(--hf-orange);
  background:var(--hf-card2); border-radius:10px; padding:6px 10px; flex:none; line-height:1;
}
.hf-question p{ margin:0; color:var(--hf-ink); font-size:15.5px; line-height:1.65; }

/* ── numbered "why this matters" cards ─────────────────────────────────── */
.hf-numcards{
  display:grid; gap:14px; margin:16px 0 8px;
  grid-template-columns:repeat(auto-fit,minmax(240px,1fr));
}
.hf-numcards>div{
  position:relative; background:var(--hf-card); border:1px solid var(--hf-line);
  border-radius:18px; padding:20px 20px 18px;
}
/* the numeral is the memory hook — big, outlined, and deliberately oversized
   against the heading it sits above. */
.hf-numcards .num{
  display:block; font-family:var(--font-display); font-size:30px; font-weight:700;
  line-height:1; color:var(--hf-orange); opacity:.85; margin:0 0 8px;
}
.hf-numcards h5{
  margin:0 0 7px; font-size:15px; font-weight:700; color:var(--hf-ink);
  text-transform:none; letter-spacing:0;
}
.hf-numcards p{ margin:0; font-size:13.5px; line-height:1.6; color:var(--hf-ink2); }

/* ── the reference: a small heading over a two-column command grid ─────── */
.hf-refhead{
  margin:24px 0 10px; font-size:12px; font-weight:700; letter-spacing:.09em;
  text-transform:uppercase; color:var(--hf-muted);
  text-align:left; border:0; padding:0;
}
.hf-refgrid{
  display:grid; gap:10px; margin:0 0 6px;
  grid-template-columns:repeat(auto-fit,minmax(280px,1fr));
}
.hf-refgrid>div{
  background:var(--hf-card); border:1px solid var(--hf-line);
  border-radius:14px; padding:13px 16px;
}
.hf-refgrid code{
  display:block; margin:0 0 5px; font-size:12.5px; font-weight:700;
  color:var(--hf-orange); background:none; padding:0;
  /* commands are long and phones are narrow: wrap rather than clip, which is
     the site-wide rule for a token outside a <pre>. */
  overflow-wrap:anywhere; word-break:break-word;
}
.hf-refgrid span{ display:block; font-size:13px; line-height:1.55; color:var(--hf-ink2); }
