/* ===========================================================================
   CLEAN HUB — the second skin. Inert unless js/theme.js stamped
   <html data-theme="clean-hub">; Pink fun is css/style.css, unprefixed, untouched.

   THE RULES OF THIS FILE (scripts/qa/theme-verify.js enforces the first two)
     1. EVERY selector — each one in a comma list, and inside @media — starts with
        html[data-theme="clean-hub"]. Only @keyframes may be bare.
     2. EVERY [style*=...] selector excludes the .report-page subtree. The pack documents
        are dated legal records and look the same under every skin. The exclusion is
        written out in full on each rule rather than implied, so it cannot be lost in an edit.
     3. Colours are TOKENS, defined once in part 1. A hex below part 1 is a bug (one
        exception, marked: the document reset gives the sheets Pink fun's ink back).

   HOW IT WORKS. app.js draws every screen with inline style="" strings, and draws them
   consistently ("border:3px solid #1D3D64", "font:400 15px/1 'Archivo Black',system-ui").
   This sheet matches those strings with attribute-substring selectors and replaces what
   they say with !important, which is the one thing a stylesheet can do that beats an
   inline declaration. So the markup stays Pink fun's markup and Pink fun cannot move.
   Where the COMPOSITION differs (the landing page, the shell header, the bottom nav)
   app.js branches on skinIs('clean-hub') and emits .ch-* classes, styled in part 6.

   THE ONE TRAP. A [style*=] selector matches the attribute's TEXT. The moment a script
   writes el.style.anything, the browser re-serialises the whole attribute —
   "box-shadow:6px 6px 0 #FF2E9A" becomes "box-shadow: rgb(255, 46, 154) 6px 6px 0px" —
   and every substring rule silently stops matching that element. app.js does this to
   .live-ring (the rotating border), #gs-float, .docjob-bar, the pack's GET buttons and
   #docview-download (paintDocButtons), #scan-phase (the hub rewrites its cssText on every
   progress tick), the flying .gs-ghost and the launch ribbon. Those are therefore
   re-dressed BY CLASS OR ID in part 4, never by their style text.

   THE OTHER TRAP. Part 2's rules all end in :not(.report-page):not(.report-page *), which is
   two classes of specificity. A named rule written plainly — #root [data-ui="scorecard"] —
   is therefore OUTRANKED by the generic remap it was meant to override, and loses silently.
   Spell a named rule that competes with part 2 with the element name and both exclusions.

   ORDER IS LOAD-BEARING. Everything is !important, so between two rules that both match,
   specificity decides and then source order. Part 2 is the generic vocabulary; part 3
   the by-context rules that must beat it (they add an element name or a second
   attribute); parts 4-6 named things. Add new generic remaps to part 2, not the end.

   Visual language: the AudioHub design system, "Ocean light". Sora; ui-monospace for
   machine facts and small letter-spaced caps labels; white cards on a warm grey page;
   one accent; 1.8px line icons; no hard shadows, no heavy borders. Light only.
   =========================================================================== */

/* ---------------------------------------------------------------------------
   1. TOKENS
   The -ink / band colours are the design's hues darkened until they pass WCAG AA
   (4.5:1) as TEXT on every surface below; the design's own #1E9BF0 is 3:1 on white and
   is used only as a FILL, under --ch-on-acc. Measured, not guessed: see the contrast
   pass in scripts/qa/theme_leaks.py.
   --------------------------------------------------------------------------- */
html[data-theme="clean-hub"] {
  --ch-bg:   #EFF0E9;   /* page */
  --ch-sur:  #FFFFFF;   /* surface: cards, inputs, pills */
  --ch-rai:  #E7E8E0;   /* raised: chips, tracks, disabled fills */
  --ch-tx:   #1A222C;   /* text */
  --ch-sub:  #5F6771;   /* secondary text — 4.6:1 on --ch-rai, the worst case */
  --ch-fnt:  #9AA0A8;   /* faint: DISABLED text and hairlines only — never content */
  --ch-brd:  #D8DAD0;   /* border */
  --ch-acc:  #1E9BF0;   /* accent, as a fill */
  --ch-on-acc: #0A1826; /* text on the accent */
  --ch-acc-ink: #0A66AD;/* accent, as text and links */
  --ch-soft: #D9EAF7;   /* soft accent: info panels, selected rows */
  --ch-acc-brd: #9CCBF2;/* border of a soft-accent thing */
  --ch-rec:  #E8443C;   /* the design's red — borders and icons */

  /* Score bands keep their MEANING; only the hue is tuned to sit in this palette. */
  --ch-danger:  #B42318;  --ch-danger-soft:  #FDECEA;  --ch-danger-brd:  #F0B4AD;
  --ch-caution: #8A5300;  --ch-caution-soft: #FBF1DC;  --ch-caution-brd: #E5C98E;
  --ch-clear:   #176B37;  --ch-clear-soft:   #E4F3E8;  --ch-clear-brd:   #A9D6B6;
  --ch-ai:      #5B3FB8;  --ch-ai-soft:      #ECE7FA;  --ch-ai-brd:      #C5B8EE;
  /* The risk scale has FIVE steps, not three: Very High is --ch-danger, Moderate is
     --ch-caution, Low is --ch-clear, and these two sit between them. Pink fun paints Moderate
     and Low-Moderate in a yellow and a lime that carry navy text; here every step is an ink
     dark enough to carry white (>= 6:1), so the verdict chip is one treatment in five hues. */
  --ch-high:    #A8410F;  --ch-high-soft:    #FCE9DD;  --ch-high-brd:    #EDBB9C;
  --ch-lowmod:  #4F6B00;  --ch-lowmod-soft:  #EEF4D6;  --ch-lowmod-brd:  #C6D78C;
  --ch-teal:    #0B6B5E;  /* the ACOUSTIC channel's ink: a fifth hue that is a label, not a verdict */
  --ch-on-solid: #FFFFFF; /* text on a solid band fill */
  /* The landing page's surfaces, which sit over a moving backdrop (part 6): --ch-sur and
     --ch-caution-soft, let through just far enough to show it. The alphas are MEASURED, not
     chosen by eye — part 6 has the arithmetic. */
  --ch-sur-veil:     rgba(255, 255, 255, .84);
  --ch-caution-veil: rgba(251, 241, 220, .88);

  --ch-font: 'Sora', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --ch-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --ch-r-card: 20px;
  --ch-r-ctl:  14px;
  --ch-r-pill: 99px;
  --ch-shadow: 0 12px 40px rgba(26, 34, 44, .16);

  /* The live ring (style.css explains it; app.js reads these by name). At rest the frame
     is the accent, so around an accent button it disappears; ringing, a white highlight
     sweeps it. */
  --ring-deep:      #0A66AD;
  --ring-dark:      #1E9BF0;
  --ring-primary:   #1E9BF0;
  --ring-light:     #A9D8FA;
  --ring-highlight: #FFFFFF;
}

html[data-theme="clean-hub"],
html[data-theme="clean-hub"] body { background: var(--ch-bg); }

/* The wrapper render() draws. ONLY font-family and colour are set here, because both are
   inherited into the documents and every .report-page restates both inline. Do not add
   font-size, line-height or letter-spacing to this rule: the certificate sheet inherits those. */
html[data-theme="clean-hub"] #root > div {
  background: var(--ch-bg) !important;
  font-family: var(--ch-font) !important;
  color: var(--ch-tx) !important;
}
/* Belt and braces for a sheet that does NOT restate them (a server-rendered document that
   arrives without inline font/colour): give it back exactly what it inherits in Pink fun.
   Not !important and :where() (zero specificity), so an inline value or any rule at all on
   the sheet still wins; all this beats is inheritance. */
html[data-theme="clean-hub"] :where(#root .report-page) {
  font-family: 'Space Mono', ui-monospace, monospace;
  color: #1D3D64;   /* Pink fun's inherited ink, on purpose: the one non-token hex in this file */
}

html[data-theme="clean-hub"] #root a:not(.report-page):not(.report-page *) { color: var(--ch-acc-ink) !important; }
html[data-theme="clean-hub"] #root :is(input, button, textarea, select):not(.report-page):not(.report-page *) { font-family: var(--ch-font); }
html[data-theme="clean-hub"] #root :is(input, button, textarea, select, a):not(.report-page):not(.report-page *):focus-visible {
  outline: 2px solid var(--ch-acc) !important;
  outline-offset: 2px !important;
}
html[data-theme="clean-hub"] #root input:not(.report-page):not(.report-page *):focus { outline: 2px solid var(--ch-acc); outline-offset: 2px; }

/* ---------------------------------------------------------------------------
   2. THE GENERIC VOCABULARY — every screen at once
   --------------------------------------------------------------------------- */

/* ---- type ---------------------------------------------------------------- */
/* Archivo Black was the display face: headings, prices, big button labels. */
html[data-theme="clean-hub"] #root [style*="Archivo Black"]:not(.report-page):not(.report-page *) {
  font-family: var(--ch-font) !important;
  font-weight: 800 !important;
  text-transform: none !important;
  letter-spacing: -.01em !important;
}
/* A heading set at /.9 or /.95 was tight for a condensed black face; Sora needs air. */
html[data-theme="clean-hub"] #root :is(h1, h2, h3)[style*="Archivo Black"]:not(.report-page):not(.report-page *) { line-height: 1.1 !important; }

/* Space Mono was everything else. Default: it is prose, so it becomes Sora... */
html[data-theme="clean-hub"] #root [style*="Space Mono"]:not(.report-page):not(.report-page *) {
  font-family: var(--ch-font) !important;
  letter-spacing: normal !important;
}
/* ...unless it is a small tracked-out caps LABEL ("STEP 1 OF 3", "MOBILE NUMBER"), which is
   the design's ui-monospace caps label. Bold + letter-spacing is how app.js writes one.
   Not on a BUTTON: mono is for facts and labels, and an action is neither (part 3). */
html[data-theme="clean-hub"] #root [style*="font:700"][style*="Space Mono"][style*="letter-spacing"]:not(button):not(.report-page):not(.report-page *) {
  font-family: var(--ch-mono) !important;
  font-weight: 600 !important;
  letter-spacing: .12em !important;
}
/* ...and unless it is a PASSAGE. app.js writes its warnings the way it writes a label (bold,
   tracked, capitals) but at a reading line-height, /1.5 and up, and three lines of tracked
   monospace capitals is a wall. A passage is prose: Sora, barely tracked. Its capitals stay,
   because they are typed and not transformed (see the note on buttons in part 3). Not at
   9px: what app.js sets that small is a string of machine facts (the score card's RISK 0.62 ·
   6 OF 7 CONFLICTS · cs-2.4 line), and facts stay mono. */
html[data-theme="clean-hub"] #root :is(p, div, li)[style*="font:700"][style*="Space Mono"][style*="letter-spacing"]:is([style*="/1.5 "], [style*="/1.6 "], [style*="/1.7 "], [style*="/1.8 "]):not([style*="font:700 9px"]):not([style*="font:700 9.5px"]):not(.report-page):not(.report-page *) {
  font-family: var(--ch-font) !important;
  font-weight: 600 !important;
  font-size: 11.5px !important;
  letter-spacing: .03em !important;
}
/* Prose set at 10-12px was legible in a wide monospace and is not in Sora. */
html[data-theme="clean-hub"] #root :is([style*="font:400 10px"], [style*="font:400 10.5px"], [style*="font:400 11px"], [style*="font:400 11.5px"]):not(.report-page):not(.report-page *) { font-size: 12.5px !important; }
html[data-theme="clean-hub"] #root :is([style*="font:400 12px"], [style*="font:400 13px"]):not(.report-page):not(.report-page *) { font-size: 13.5px !important; }
html[data-theme="clean-hub"] #root [style*="Lobster Two"]:not(.report-page):not(.report-page *) {
  font-family: var(--ch-font) !important; font-style: normal !important; font-weight: 800 !important;
  -webkit-text-stroke: 0 !important; text-shadow: none !important; color: var(--ch-tx) !important;
}
html[data-theme="clean-hub"] #root [style*="text-align:justify"]:not(.report-page):not(.report-page *) { text-align: left !important; }

/* ---- shadows ------------------------------------------------------------- */
/* "Npx Npx 0 #colour" is the brutalist offset shadow, in every size and colour it comes in. */
html[data-theme="clean-hub"] #root [style*="px 0 #"]:not(.report-page):not(.report-page *) { box-shadow: none !important; }

/* ---- borders ------------------------------------------------------------- */
html[data-theme="clean-hub"] #root :is([style*="border:2px"], [style*="border:3px"], [style*="border:5px"], [style*="border:6px"]):not(.report-page):not(.report-page *) { border-width: 1.5px !important; }
html[data-theme="clean-hub"] #root :is([style*="solid #1D3D64"], [style*="dashed #1D3D64"], [style*="solid #F4F1E6"], [style*="solid #8FA0B5"], [style*="solid #9FB6D4"], [style*="dashed #9FB6D4"], [style*="solid #C8D2DE"], [style*="solid #3A5273"], [style*="solid #E3DED0"], [style*="solid #1F4470"]):not(.report-page):not(.report-page *) { border-color: var(--ch-brd) !important; }
html[data-theme="clean-hub"] #root :is([style*="solid #FF2E9A"], [style*="solid #2F6FB2"]):not(.report-page):not(.report-page *) { border-color: var(--ch-acc) !important; }
html[data-theme="clean-hub"] #root [style*="solid #FF9CCB"]:not(.report-page):not(.report-page *) { border-color: var(--ch-acc-brd) !important; }
html[data-theme="clean-hub"] #root [style*="solid #C0212E"]:not(.report-page):not(.report-page *) { border-color: var(--ch-rec) !important; }
html[data-theme="clean-hub"] #root :is([style*="solid #B96A00"], [style*="solid #8A4E00"], [style*="solid #C9A800"], [style*="dashed #B5762F"]):not(.report-page):not(.report-page *) { border-color: var(--ch-caution-brd) !important; }
html[data-theme="clean-hub"] #root [style*="solid #D6531B"]:not(.report-page):not(.report-page *) { border-color: var(--ch-high-brd) !important; }
html[data-theme="clean-hub"] #root [style*="solid #7C4FD0"]:not(.report-page):not(.report-page *) { border-color: var(--ch-ai-brd) !important; }
html[data-theme="clean-hub"] #root :is([style*="solid #1E7A3C"], [style*="solid #1B7A2E"], [style*="solid #4E7A46"], [style*="solid #2F5A2A"]):not(.report-page):not(.report-page *) { border-color: var(--ch-clear-brd) !important; }
/* Full-bleed rules under a bar were 3px of navy or magenta; here a hairline. */
html[data-theme="clean-hub"] #root :is([style*="border-bottom:3px"], [style*="border-top:3px"], [style*="border-bottom:2px"], [style*="border-top:2px"]):not(.report-page):not(.report-page *) { border-top-width: 1.5px !important; border-bottom-width: 1.5px !important; }

/* ---- corners, by element type ------------------------------------------- */
html[data-theme="clean-hub"] #root button[style]:not([style*="border-radius"]):not(.report-page):not(.report-page *) { border-radius: var(--ch-r-ctl) !important; }
html[data-theme="clean-hub"] #root :is(input, select, textarea)[style]:not([type="checkbox"]):not([type="radio"]):not(.report-page):not(.report-page *) { border-radius: var(--ch-r-ctl) !important; }
html[data-theme="clean-hub"] #root :is(div, a)[style*="border:3px"]:not([style*="border-radius"]):not(.report-page):not(.report-page *) { border-radius: var(--ch-r-card) !important; }
html[data-theme="clean-hub"] #root :is(div, a)[style*="border:2px"]:not([style*="border-radius"]):not(.report-page):not(.report-page *) { border-radius: var(--ch-r-ctl) !important; }
html[data-theme="clean-hub"] #root span:is([style*="border:2px"], [style*="border:3px"]):not([style*="border-radius"]):not(.report-page):not(.report-page *) { border-radius: 8px !important; }
/* A boxed sentence (the bill's TEST PAYMENT line, a REASON: line) and the factor-trail drawer. */
html[data-theme="clean-hub"] #root :is(p, details)[style*="border:"]:not([style*="border-radius"]):not(.report-page):not(.report-page *) { border-radius: 10px !important; }
/* A callout ruled down its left edge keeps the rule — it is how app.js says "a note about the
   thing above" — and gets the corners everything else has. */
html[data-theme="clean-hub"] #root :is([style*="border-left:3px"], [style*="border-left:4px"]):not([style*="border-radius"]):not(.report-page):not(.report-page *) { border-radius: 10px !important; border-left-width: 3px !important; }
html[data-theme="clean-hub"] #root [style*="border-left:3px solid #C0212E"]:not(.report-page):not(.report-page *) { border-left-color: var(--ch-danger) !important; }
html[data-theme="clean-hub"] #root [style*="border-left:3px solid #B96A00"]:not(.report-page):not(.report-page *) { border-left-color: var(--ch-caution) !important; }
html[data-theme="clean-hub"] #root [style*="border-left:3px solid #7C4FD0"]:not(.report-page):not(.report-page *) { border-left-color: var(--ch-ai) !important; }
html[data-theme="clean-hub"] #root [style*="border-left:3px solid #FF2E9A"]:not(.report-page):not(.report-page *) { border-left-color: var(--ch-acc) !important; }

/* ---- fills --------------------------------------------------------------- */
/* Cream was Pink fun's paper. */
html[data-theme="clean-hub"] #root :is([style*="background:#F4F1E6"], [style*="background:#EFE8D3"], [style*="background:#FAF7EA"], [style*="background:#FAFAF4"]):not(.report-page):not(.report-page *) { background: var(--ch-sur) !important; }
html[data-theme="clean-hub"] #root [style*="background:#3778B5"]:not(.report-page):not(.report-page *) { background: var(--ch-bg) !important; }
/* Navy and blue PANELS become the design's soft-accent callout, with ordinary text. */
html[data-theme="clean-hub"] #root :is([style*="background:#2B5C92"], [style*="background:#1F4470"], [style*="background:#16304F"], [style*="background:#2E5EA5"]):not(.report-page):not(.report-page *) {
  background: var(--ch-soft) !important; color: var(--ch-tx) !important;
  border-color: transparent !important; border-radius: var(--ch-r-ctl) !important;
}
html[data-theme="clean-hub"] #root [style*="background:#1D3D64"]:not(.report-page):not(.report-page *) { background: var(--ch-sur) !important; color: var(--ch-tx) !important; }
/* Magenta meant "this one": selected, active, primary. */
html[data-theme="clean-hub"] #root [style*="background:#FF2E9A"]:not(.report-page):not(.report-page *) { background: var(--ch-acc) !important; color: var(--ch-on-acc) !important; border-color: var(--ch-acc) !important; }
html[data-theme="clean-hub"] #root :is([style*="background:#FFF0F7"], [style*="background:#BFE0FF"], [style*="background:#EAF2FA"], [style*="background:#DCEBFA"]):not(.report-page):not(.report-page *) { background: var(--ch-soft) !important; }
html[data-theme="clean-hub"] #root :is([style*="background:#BCD4EA"], [style*="background:#E9EEF5"], [style*="background:#EDEDE7"], [style*="background:#E2E2DA"], [style*="background:#EDF1F6"]):not(.report-page):not(.report-page *) { background: var(--ch-rai) !important; }
/* A busy or un-armed button was a washed-out tint of its own colour (pale red, pale pink,
   pale green). Here "not yet" is one thing whatever it will become: the raised fill. */
html[data-theme="clean-hub"] #root :is([style*="background:#D7BFC2"], [style*="background:#F6A8CE"], [style*="background:#BFD9C4"]):not(.report-page):not(.report-page *) { background: var(--ch-rai) !important; border-color: var(--ch-brd) !important; }
/* Bands. */
html[data-theme="clean-hub"] #root :is([style*="background:#FFD535"], [style*="background:#FFE9CE"], [style*="background:#FFF8E1"], [style*="background:#FFF6D6"], [style*="background:#FFF4E2"], [style*="background:#FBF0DF"]):not(.report-page):not(.report-page *) { background: var(--ch-caution-soft) !important; border-color: var(--ch-caution-brd) !important; color: var(--ch-tx) !important; }
html[data-theme="clean-hub"] #root :is([style*="background:#FDECEC"], [style*="background:#FBE9EA"]):not(.report-page):not(.report-page *) { background: var(--ch-danger-soft) !important; }
html[data-theme="clean-hub"] #root :is([style*="background:#E3D2FC"], [style*="background:#F3EDFB"]):not(.report-page):not(.report-page *) { background: var(--ch-ai-soft) !important; }
html[data-theme="clean-hub"] #root :is([style*="background:#EAF6EC"], [style*="background:#DFF5E1"], [style*="background:#E6F0E4"]):not(.report-page):not(.report-page *) { background: var(--ch-clear-soft) !important; }
html[data-theme="clean-hub"] #root [style*="background:#C0212E"]:not(.report-page):not(.report-page *) { background: var(--ch-danger) !important; }
html[data-theme="clean-hub"] #root :is([style*="background:#B96A00"], [style*="background:#E8B21E"]):not(.report-page):not(.report-page *) { background: var(--ch-caution) !important; }
html[data-theme="clean-hub"] #root [style*="background:#D6531B"]:not(.report-page):not(.report-page *) { background: var(--ch-high) !important; }
html[data-theme="clean-hub"] #root [style*="background:#A8BE33"]:not(.report-page):not(.report-page *) { background: var(--ch-lowmod) !important; }
html[data-theme="clean-hub"] #root :is([style*="background:#1B7A2E"], [style*="background:#4E7A46"], [style*="background:#1E7A3C"]):not(.report-page):not(.report-page *) { background: var(--ch-clear) !important; }
/* The grey "no verdict" chip (FUZZY, NOT SCORED): white on #8FA0B5 was 2.7:1. */
html[data-theme="clean-hub"] #root [style*="background:#8FA0B5"]:not(.report-page):not(.report-page *) { background: var(--ch-sub) !important; }
html[data-theme="clean-hub"] #root [style*="background:#4E2E96"]:not(.report-page):not(.report-page *) { background: var(--ch-ai) !important; }
/* The "desk" the paged documents lie on, and its toolbar. The sheets themselves are untouched. */
html[data-theme="clean-hub"] #root [style*="background:#3F4448"]:not(.report-page):not(.report-page *) { background: var(--ch-rai) !important; }
html[data-theme="clean-hub"] #root [style*="background:#25282B"]:not(.report-page):not(.report-page *) { background: var(--ch-sur) !important; border-radius: var(--ch-r-ctl) !important; }
/* Overlay scrims. */
html[data-theme="clean-hub"] #root [style*="background:rgba(15,25,40"]:not(.report-page):not(.report-page *) { background: rgba(26, 34, 44, .46) !important; }

/* ---- text colours -------------------------------------------------------- */
/* Cream text sat on navy. Whatever that navy became, it is light now. */
html[data-theme="clean-hub"] #root :is([style*="color:#1D3D64"], [style*="color:#F4F1E6"], [style*="color:#CFE0F2"]):not(.report-page):not(.report-page *) { color: var(--ch-tx) !important; }
html[data-theme="clean-hub"] #root :is([style*="color:#5A739E"], [style*="color:#3A5273"], [style*="color:#46608C"], [style*="color:#8FA0B5"], [style*="color:#8FA9C9"], [style*="color:#7C8FA8"], [style*="color:#A9B6C6"], [style*="color:#9FB6D4"], [style*="color:#9FB0C4"]):not(.report-page):not(.report-page *) { color: var(--ch-sub) !important; }
/* #9FB6D4 reads as "disabled" in Pink fun but app.js also sets real sentences in it on navy
   panels, and --ch-fnt is 2.1:1 on the soft accent those panels became. So it is --ch-sub; a
   disabled control still says so with its raised fill, dashed border and not-allowed cursor. */
html[data-theme="clean-hub"] #root :is([style*="color:#FF2E9A"], [style*="color:#14497F"], [style*="color:#2F6FB2"], [style*="color:#2456B8"]):not(.report-page):not(.report-page *) { color: var(--ch-acc-ink) !important; }
html[data-theme="clean-hub"] #root :is([style*="color:#C0212E"], [style*="color:#8E1720"]):not(.report-page):not(.report-page *) { color: var(--ch-danger) !important; }
html[data-theme="clean-hub"] #root :is([style*="color:#8A4E00"], [style*="color:#B96A00"], [style*="color:#FFD535"], [style*="color:#C9A800"], [style*="color:#7A6500"], [style*="color:#8A5410"], [style*="color:#5A4020"]):not(.report-page):not(.report-page *) { color: var(--ch-caution) !important; }
html[data-theme="clean-hub"] #root :is([style*="color:#4E2E96"], [style*="color:#7C4FD0"]):not(.report-page):not(.report-page *) { color: var(--ch-ai) !important; }
html[data-theme="clean-hub"] #root [style*="color:#D6531B"]:not(.report-page):not(.report-page *) { color: var(--ch-high) !important; }
html[data-theme="clean-hub"] #root [style*="color:#E8B21E"]:not(.report-page):not(.report-page *) { color: var(--ch-caution) !important; }
html[data-theme="clean-hub"] #root [style*="color:#A8BE33"]:not(.report-page):not(.report-page *) { color: var(--ch-lowmod) !important; }
html[data-theme="clean-hub"] #root [style*="color:#0E7B6C"]:not(.report-page):not(.report-page *) { color: var(--ch-teal) !important; }
html[data-theme="clean-hub"] #root :is([style*="color:#1B7A2E"], [style*="color:#12572A"], [style*="color:#3BB143"], [style*="color:#1E7A3C"], [style*="color:#2F5A2A"]):not(.report-page):not(.report-page *) { color: var(--ch-clear) !important; }
html[data-theme="clean-hub"] #root [style*="accent-color"]:not(.report-page):not(.report-page *) { accent-color: var(--ch-acc) !important; }

/* ---------------------------------------------------------------------------
   3. BY CONTEXT — the same colour meaning different things on different elements.
   Each adds an element name (or a second attribute) so it outranks part 2.
   --------------------------------------------------------------------------- */

/* A navy BUTTON is the primary action: the accent, with on-accent text. */
html[data-theme="clean-hub"] #root button[style*="background:#1D3D64"]:not(.report-page):not(.report-page *) {
  background: var(--ch-acc) !important; color: var(--ch-on-acc) !important; border-color: var(--ch-acc) !important;
}
/* Anything inside an accent fill reads in the on-accent ink, whatever it said before. */
html[data-theme="clean-hub"] #root :is(button[style*="background:#1D3D64"], button[style*="background:#FF2E9A"]) [style*="color:"]:not(.report-page):not(.report-page *) { color: var(--ch-on-acc) !important; }
/* A cream or white button is the quiet action: a surface with a border. */
html[data-theme="clean-hub"] #root button:is([style*="background:#F4F1E6"], [style*="background:#fff"]):not(.report-page):not(.report-page *) { border: 1.5px solid var(--ch-brd) !important; }
/* A button's label is Sora, not the mono caps label — mono is for facts, not actions.
   Buttons keep their authored CAPS: the labels in app.js are a mix of "Send code" under a
   text-transform and literal "NEXT", and uppercase is the one treatment that makes the two
   agree. Lower-casing them from CSS would also lower-case CIPO and the customer's own mark. */
html[data-theme="clean-hub"] #root button[style*="Space Mono"]:not(.report-page):not(.report-page *) {
  font-family: var(--ch-font) !important; font-weight: 700 !important; letter-spacing: .04em !important;
}
html[data-theme="clean-hub"] #root button[style*="Archivo Black"]:not(.report-page):not(.report-page *) {
  font-weight: 700 !important; text-transform: uppercase !important; letter-spacing: .05em !important;
}
/* ...except the big multi-line choice cards, which are buttons only so they can be pressed. */
html[data-theme="clean-hub"] #root button[data-act="pickPlan"] [style*="Archivo Black"]:not(.report-page):not(.report-page *) { text-transform: none !important; }

/* A SOLID BAND FILL CARRIES WHITE, whatever its text said before. Pink fun put cream on amber
   and navy on yellow; part 2 turns cream and navy into --ch-tx, which on these fills is
   2.5:1. The trailing [style] is there only to outrank part 2's colour rules. */
html[data-theme="clean-hub"] #root :is([style*="background:#C0212E"], [style*="background:#B96A00"], [style*="background:#D6531B"], [style*="background:#E8B21E"], [style*="background:#A8BE33"], [style*="background:#1B7A2E"], [style*="background:#4E7A46"], [style*="background:#1E7A3C"], [style*="background:#4E2E96"], [style*="background:#8FA0B5"])[style]:not(.report-page):not(.report-page *) {
  color: var(--ch-on-solid) !important; border-color: transparent !important;
}
/* ...and a "not yet" tint (part 2) carries secondary text, not the white its solid twin had. */
html[data-theme="clean-hub"] #root :is([style*="background:#D7BFC2"], [style*="background:#F6A8CE"], [style*="background:#BFD9C4"])[style]:not(.report-page):not(.report-page *) { color: var(--ch-sub) !important; }

/* The script headline ("Payment confirmed", "Paid!") was magenta with a navy stroke. Part 2
   takes the face and the stroke off; its colour rule loses to the magenta-means-accent rule
   that follows it, so the ink is settled here: a headline is text, not a link. */
html[data-theme="clean-hub"] #root p[style*="Lobster Two"]:not(.report-page):not(.report-page *) { color: var(--ch-tx) !important; letter-spacing: -.02em !important; line-height: 1.05 !important; }

/* Where Stripe mounts its iframe. The form inside is Stripe's and is white; the hole it sits in
   is a card like any other, so the form does not look pasted onto the page. */
html[data-theme="clean-hub"] #root #stripe-mount { background: var(--ch-sur); border-radius: var(--ch-r-card); overflow: hidden; }

/* The round (i) buttons: Georgia italic on a magenta ring. */
html[data-theme="clean-hub"] #root button[style*="Georgia"]:not(.report-page):not(.report-page *) {
  font-family: var(--ch-font) !important; font-style: normal !important; font-weight: 700 !important;
  border: 1.5px solid var(--ch-brd) !important; background: var(--ch-sur) !important; color: var(--ch-acc-ink) !important;
}

/* Rules drawn as 3px navy bars ("— OR PHONE —"). */
html[data-theme="clean-hub"] #root div[style*="height:3px"][style*="background:#1D3D64"]:not(.report-page):not(.report-page *) { height: 1.5px !important; background: var(--ch-brd) !important; }

/* Inputs. */
html[data-theme="clean-hub"] #root input[style]:not([type="checkbox"]):not([type="radio"]):not(.report-page):not(.report-page *),
html[data-theme="clean-hub"] #root :is(select, textarea)[style]:not(.report-page):not(.report-page *) {
  background: var(--ch-sur) !important; color: var(--ch-tx) !important;
  border: 1.5px solid var(--ch-brd) !important; box-shadow: none !important;
  font-family: var(--ch-font) !important; font-weight: 600 !important;
}
html[data-theme="clean-hub"] #root input[style]:not(.report-page):not(.report-page *)::placeholder { color: var(--ch-fnt); opacity: 1; font-weight: 400; }
/* The one-time code is a machine fact. */
html[data-theme="clean-hub"] #root input#in-code:not(.report-page):not(.report-page *) { font-family: var(--ch-mono) !important; }

/* Example / recent chips: square blue tags become raised pills. */
html[data-theme="clean-hub"] #root button:is([data-act="markExample"], [data-act="gsExample"]):not(.report-page):not(.report-page *) {
  background: var(--ch-rai) !important; border: none !important; border-radius: var(--ch-r-pill) !important;
  padding: 9px 14px !important; font-weight: 600 !important; font-size: 12px !important; letter-spacing: normal !important; color: var(--ch-tx) !important;
}

/* A choice that is ON — a picked statement, the chosen plan — is the soft accent with an
   accent border and ORDINARY text: several lines of prose on solid #1E9BF0 is a poster. */
html[data-theme="clean-hub"] #root :is([data-act="gsToggle"], [data-act="vgsToggle"], [data-act="pickPlan"], [data-act="toggleClass"])[style*="background:#FF2E9A"]:not(.report-page):not(.report-page *) {
  background: var(--ch-soft) !important; color: var(--ch-tx) !important; border-color: var(--ch-acc) !important;
}
html[data-theme="clean-hub"] #root :is([data-act="gsToggle"], [data-act="vgsToggle"], [data-act="pickPlan"], [data-act="toggleClass"])[style*="background:#FF2E9A"] [style*="color:"]:not([style*="border-radius:999px"]):not(.report-page):not(.report-page *) { color: var(--ch-tx) !important; }
html[data-theme="clean-hub"] #root :is([data-act="gsToggle"], [data-act="vgsToggle"]):not(.report-page):not(.report-page *) { border-radius: var(--ch-r-ctl) !important; padding: 12px 14px !important; align-items: center !important; }
html[data-theme="clean-hub"] #root button[data-act="pickPlan"]:not(.report-page):not(.report-page *) { border-radius: var(--ch-r-card) !important; padding: 18px !important; color: var(--ch-tx) !important; }

/* THE PAYWALL CARD over a blurred conflict list was a magenta slab with a blue button in it.
   Magenta-means-accent turns that into three lines of prose on solid #1E9BF0 with a pale
   button — the poster again, and the action is the quietest thing on it. Here the card is the
   overlay card (white, soft shadow) and the button is the one accent on it. */
html[data-theme="clean-hub"] #root [style*="position:absolute"][style*="inset:0"] > div[style*="background:#FF2E9A"]:not(.report-page):not(.report-page *) {
  background: var(--ch-sur) !important; color: var(--ch-tx) !important; border: none !important;
  border-radius: 24px !important; box-shadow: var(--ch-shadow) !important; padding: 24px !important;
}
html[data-theme="clean-hub"] #root button[style*="background:#2B5C92"]:not(.report-page):not(.report-page *) {
  background: var(--ch-acc) !important; color: var(--ch-on-acc) !important; border-color: var(--ch-acc) !important;
}

/* A pack row that can be opened was pale blue with a hard shadow; here it is a white card,
   and the locked one (white already, at .72 opacity) is simply the fainter of the two. */
html[data-theme="clean-hub"] #root div[style*="background:#BCD4EA"][style*="box-shadow:5px 5px 0 #1D3D64"]:not(.report-page):not(.report-page *) { background: var(--ch-sur) !important; border-color: transparent !important; }

/* The wizard's three progress bars. */
html[data-theme="clean-hub"] #root div[style*="height:8px"][style*="border:2px solid #1D3D64"]:not(.report-page):not(.report-page *) { height: 6px !important; border: none !important; border-radius: var(--ch-r-pill) !important; }
html[data-theme="clean-hub"] #root div[style*="height:8px"][style*="background:#F4F1E6"]:not(.report-page):not(.report-page *) { background: var(--ch-rai) !important; }

/* Small square ×. */
html[data-theme="clean-hub"] #root button:is([data-act="gsRemove"], [data-act="vgsRemove"]):not(.report-page):not(.report-page *) { border-radius: var(--ch-r-pill) !important; width: 26px !important; height: 26px !important; color: var(--ch-sub) !important; }

/* The FIND button and its scope caret were one slab split by a hairline. */
html[data-theme="clean-hub"] #root #gs-find-wrap:not(.report-page):not(.report-page *) { gap: 6px; }
html[data-theme="clean-hub"] #root #gs-find-wrap > button[data-act="gsMenuToggle"]:not(.report-page):not(.report-page *) { border: none !important; padding: 14px 11px !important; }

/* Overlays: the card in the middle of a scrim. */
html[data-theme="clean-hub"] #root [style*="position:fixed"][style*="inset:0"] > [data-act="noop"]:not(.report-page):not(.report-page *) {
  background: var(--ch-sur) !important; border: none !important; border-radius: 24px !important; box-shadow: var(--ch-shadow) !important;
}

/* A bottom sheet (the FIND scope menu) is the same card, docked: round only the top, pad it, and
   let its rows be rounded controls instead of full-bleed slabs ruled off in navy. */
html[data-theme="clean-hub"] #root [style*="position:fixed"][style*="align-items:flex-end"] > [data-act="noop"]:not(.report-page):not(.report-page *) {
  border-radius: 24px 24px 0 0 !important; padding: 8px 12px 16px !important;
}
html[data-theme="clean-hub"] #root [style*="align-items:flex-end"] > [data-act="noop"] > p:not(.report-page):not(.report-page *) { background: transparent !important; border: none !important; color: var(--ch-sub) !important; }
html[data-theme="clean-hub"] #root [style*="align-items:flex-end"] > [data-act="noop"] > button:not(.report-page):not(.report-page *) { border: none !important; margin: 4px 0 !important; }
/* "This is the current one" was a 3px magenta outline. */
html[data-theme="clean-hub"] #root [style*="outline:3px solid #FF2E9A"]:not(.report-page):not(.report-page *) { outline: 2px solid var(--ch-acc) !important; outline-offset: -2px !important; }

/* ---------------------------------------------------------------------------
   4. NAMED THINGS — by class or id, because a script rewrites their style attribute
   (see THE ONE TRAP above) or because they live in style.css / index.html.
   --------------------------------------------------------------------------- */
html[data-theme="clean-hub"] #root .live-ring { padding: 2px; border-radius: 16px; box-shadow: none !important; }
html[data-theme="clean-hub"] #root .live-ring > button { border-radius: 14px !important; }
/* The secondary ring-able controls (the drawer toggle, "describe something else") rest on a
   border, not on the accent: only the primary action wears the accent while idle. */
html[data-theme="clean-hub"] #root .live-ring:is([data-ring-key="gspanel"], [data-ring-key="gsmore"]) { --ring-rest: var(--ch-brd) !important; }
html[data-theme="clean-hub"] #root .live-ring[data-ring-key="gsmore"] > button { background: var(--ch-sur) !important; border: none !important; }
/* TRY A NEW NAME was yellow, which part 2 reads as a caution. It is not one: it is the next
   thing to press, and the ring around it already says so. A plain surface inside the ring. */
html[data-theme="clean-hub"] #root .live-ring > button[data-act="variantToggle"] { background: var(--ch-sur) !important; color: var(--ch-tx) !important; }
html[data-theme="clean-hub"] #root #gs-inline-count { background: var(--ch-sur) !important; color: var(--ch-tx) !important; font-family: var(--ch-mono) !important; font-weight: 600 !important; letter-spacing: .1em !important; }
html[data-theme="clean-hub"] #root #gs-inline-count:disabled { background: var(--ch-rai) !important; color: var(--ch-sub) !important; }
html[data-theme="clean-hub"] #root #gs-inline-count > span { color: inherit !important; }
html[data-theme="clean-hub"] #root #gs-inline-count:not(:disabled) > span:last-child { color: var(--ch-acc-ink) !important; }
html[data-theme="clean-hub"] #root #gs-float {
  background: var(--ch-sur) !important; color: var(--ch-tx) !important; border: 1.5px solid var(--ch-brd) !important;
  border-radius: var(--ch-r-pill) !important; box-shadow: var(--ch-shadow) !important;
  font-family: var(--ch-mono) !important; font-weight: 600 !important;
}
/* paintDocButtons() rewrites each GET button's style, so it is dressed by its action (THE ONE TRAP). */
html[data-theme="clean-hub"] #root button[data-act="docOpen"] { background: var(--ch-acc) !important; color: var(--ch-on-acc) !important; border: none !important; border-radius: var(--ch-r-ctl) !important; font-family: var(--ch-font) !important; font-weight: 700 !important; letter-spacing: .04em !important; box-shadow: none !important; }
html[data-theme="clean-hub"] #root button[data-act="docOpen"]:disabled { background: var(--ch-rai) !important; color: var(--ch-sub) !important; }
html[data-theme="clean-hub"] #root .veiled > .veil { background: rgba(239, 240, 233, .62); }
html[data-theme="clean-hub"] #root .docjob-bar { background: var(--ch-acc); border-radius: var(--ch-r-pill); }
/* The viewer's DOWNLOAD button: paintDocButtons() writes its cursor and opacity, so its style
   text is re-serialised and it stayed magenta. By id, like everything else in this part. */
html[data-theme="clean-hub"] #root #docview-download {
  background: var(--ch-acc) !important; color: var(--ch-on-acc) !important; border: none !important;
  border-radius: var(--ch-r-ctl) !important; font-family: var(--ch-font) !important; font-weight: 700 !important; letter-spacing: .04em !important;
}
/* The viewer's toolbar buttons sit on a surface now, not on charcoal. */
html[data-theme="clean-hub"] #root .doc-view button[data-act="docViewBack"] { border: 1.5px solid var(--ch-brd) !important; color: var(--ch-tx) !important; }

/* ---- the scan ---- */
/* Spinners. Part 2 thins every border to 1.5px and greys it, which is right for a card and
   erases a ring whose whole drawing IS its border. Track in the raised grey, head in the accent. */
html[data-theme="clean-hub"] #root [style*="animation:spin"]:not(.report-page):not(.report-page *) {
  border-width: 5px !important; border-color: var(--ch-rai) !important; border-top-color: var(--ch-acc) !important;
}
/* The document job's small spinner has its animation on a class in style.css, not inline. */
html[data-theme="clean-hub"] #root div.docjob-spin:not(.report-page):not(.report-page *) {
  border-width: 4px !important; border-color: var(--ch-rai) !important; border-top-color: var(--ch-acc) !important;
}
/* The simulated scan's ring is dashed so it cannot be mistaken for the real one. It stays dashed. */
html[data-theme="clean-hub"] #root [style*="animation:spin"][style*="dashed"]:not(.report-page):not(.report-page *) { border-color: var(--ch-brd) !important; border-top-color: var(--ch-acc) !important; }
/* THE PHASE LINE IS RE-WRITTEN BY THE HUB (ph.style.cssText on every progress tick), so by
   id. Plain, it is a caps label. LOUD — the model re-read, the one phase with no percentage
   of its own — it is the AI-purple block; "has a background at all" is the only thing the two
   serialisations ("background:#E3D2FC" and "background: rgb(227, 210, 252)") share. */
html[data-theme="clean-hub"] #root #scan-phase {
  font-family: var(--ch-mono) !important; font-weight: 600 !important; font-size: 10.5px !important;
  letter-spacing: .12em !important; color: var(--ch-sub) !important;
}
html[data-theme="clean-hub"] #root #scan-phase[style*="background"]:not(.report-page):not(.report-page *) {
  max-width: 360px; margin-left: auto !important; margin-right: auto !important;
  background: var(--ch-ai-soft) !important; border: 1.5px solid var(--ch-ai-brd) !important;
  border-radius: var(--ch-r-ctl) !important; color: var(--ch-ai) !important; font-size: 11.5px !important;
}
/* The barber-pole under it: same stripes, the skin's purple. */
html[data-theme="clean-hub"] #root #scan-indet > div { border: none !important; border-radius: var(--ch-r-pill) !important; background: var(--ch-ai-soft) !important; height: 8px !important; }
html[data-theme="clean-hub"] #root #scan-indet > div > div { background-image: repeating-linear-gradient(135deg, var(--ch-ai) 0 16px, var(--ch-ai-brd) 16px 32px) !important; }
html[data-theme="clean-hub"] #root #scan-count { font-size: 44px !important; letter-spacing: -.02em !important; }
/* CLOSEST MARKS SO FAR: rows, not boxed slabs. */
html[data-theme="clean-hub"] #root #scan-top > div { border-radius: var(--ch-r-ctl) !important; padding: 10px 14px !important; margin-bottom: 6px !important; }
html[data-theme="clean-hub"] #root #scan-queue { border: none !important; border-radius: var(--ch-r-card) !important; padding: 22px !important; }

/* ---- the score card ----
   Pink fun's is a navy panel with a lit dial. Here it is the screen's one white card: the
   verdict chip and the numeral carry the band's colour, and nothing else on it is coloured.
   data-band / --risk-deg come from scoreHeaderHTML() (hooks; they paint nothing in Pink fun).
   Spelled with the element name and both exclusions ON PURPOSE: part 2's navy-panel rule
   carries them, so a bare [data-ui] selector is outranked by it and loses. */
html[data-theme="clean-hub"] #root div[data-ui="scorecard"]:not(.report-page):not(.report-page *) {
  background: var(--ch-sur) !important; border: none !important; border-radius: var(--ch-r-card) !important; padding: 22px !important;
}
/* --band is set by these and read with a fallback (an unscored search has no band: grey). */
html[data-theme="clean-hub"] #root [data-ui="scorecard"][data-band="very-high"]    { --band: var(--ch-danger); }
html[data-theme="clean-hub"] #root [data-ui="scorecard"][data-band="high"]         { --band: var(--ch-high); }
html[data-theme="clean-hub"] #root [data-ui="scorecard"][data-band="moderate"]     { --band: var(--ch-caution); }
html[data-theme="clean-hub"] #root [data-ui="scorecard"][data-band="low-moderate"] { --band: var(--ch-lowmod); }
html[data-theme="clean-hub"] #root [data-ui="scorecard"][data-band="low"]          { --band: var(--ch-clear); }
/* The dial: the risk arc in the band's ink, the headroom in the raised grey. One colour says
   one thing — the mint "this part is fine" arc was a second verdict on a card that has one. */
html[data-theme="clean-hub"] #root div[data-ui="dial"]:not(.report-page):not(.report-page *) { background: conic-gradient(var(--band, var(--ch-sub)) var(--risk-deg, 0deg), var(--ch-rai) 0) !important; }
html[data-theme="clean-hub"] #root div[data-ui="dial"] > div:not(.report-page):not(.report-page *) { background: var(--ch-sur) !important; width: 82px !important; height: 82px !important; border-radius: 50% !important; }
html[data-theme="clean-hub"] #root div[data-ui="dial"] > div > span:first-child:not(.report-page):not(.report-page *) { color: var(--band, var(--ch-sub)) !important; text-shadow: none !important; font-size: 32px !important; }
html[data-theme="clean-hub"] #root div[data-ui="dial"] > div > span + span:not(.report-page):not(.report-page *) { color: var(--ch-sub) !important; }
/* The verdict chip: a pill, no border, in the band's ink with white on it. */
html[data-theme="clean-hub"] #root [data-ui="scorecard"] span[style*="Archivo Black"][style*="padding:6px 11px"]:not(.report-page):not(.report-page *) {
  background: var(--band, var(--ch-sub)) !important; color: var(--ch-on-solid) !important; border: none !important;
  border-radius: var(--ch-r-pill) !important; padding: 7px 14px !important; font-size: 15px !important; text-transform: none !important;
}
html[data-theme="clean-hub"] #root [data-ui="scorecard"] [style*="border-top:2px solid #1F4470"]:not(.report-page):not(.report-page *) { border-top-color: var(--ch-brd) !important; }

/* ---- the legacy Paid! screen ----
   The celebrating mascot and the pink-and-navy confetti are Pink fun's brand voice. Hidden,
   and the button that was pulled up over her feet is put back where a button goes. */
html[data-theme="clean-hub"] #root img[alt="Celebrating fairy"],
html[data-theme="clean-hub"] #root canvas#confetti { display: none !important; }
html[data-theme="clean-hub"] #root canvas#confetti ~ button[data-act="goDocs"] { margin-top: 18px !important; }
/* THE SHELL KEEPS PINK FUN'S 3px SIDE BORDERS, INVISIBLY. Not nostalgia: they are 6px of the
   column's width, and the pack documents are fluid sheets that re-wrap to whatever column
   they are given. With the borders simply removed, theme_leaks.py --docs measured every
   .report-page 6px wider under this skin (316px -> 322px at a 390px viewport) and therefore
   wrapped differently and 24px shorter — a dated legal record laid out differently depending
   on the skin, which is the one thing contract point 6 forbids. Transparent borders make the
   content box identical by construction, on every screen, instead of per document. */
html[data-theme="clean-hub"] #root .shell {
  background: var(--ch-bg) !important;
  border-left: 3px solid transparent !important;
  border-right: 3px solid transparent !important;
}
@media (prefers-reduced-motion: reduce) {
  html[data-theme="clean-hub"] #root .live-ring { background: var(--ring-rest, var(--ring-dark)); }
}

/* The statement that flies into the drawer when it is picked (flyToBasket). It is appended to
   <body>, so nothing under #root reaches it, and it never appears in a screenshot or in
   theme_leaks.py: it lives for 640ms and only when motion is allowed. Dressed as what it is a
   copy of — a picked statement. */
html[data-theme="clean-hub"] .gs-ghost {
  background: var(--ch-soft) !important; color: var(--ch-tx) !important;
  border: 1.5px solid var(--ch-acc) !important; border-radius: var(--ch-r-ctl) !important;
  font-family: var(--ch-font) !important;
}

/* THE "NEWLY RELEASED" RIBBON, outside #root. Same notice, same words, NOT the same place.
   (A notice and not a link any more: index.html makes it a plain div, so the hover rule that
   used to sit below this one — it stopped the link turning navy on navy — has gone with it.)
   Pink fun pins it obliquely across the top-right corner, over a navy bar whose right end is
   decoration. This skin's header puts a control exactly there — Log in on the landing page,
   the account button and the context strip's NEW in the shell — and the ribbon covered all
   three. So here it is not pinned at all: it is the first thing in the page, a flat strip IN
   THE FLOW, and nothing in the flow can sit on top of anything. The sticky header below it
   still sticks at top:0 once it has scrolled away. index.html folds it shut after a minute
   by animating its height to 0. Pinned, that moved nothing; in the flow it moves the page, so
   the strip's padding sits on the TRACK inside it: padding on the ribbon itself would survive
   height:0 as a 16px stub that then vanishes with a jump when the script sets display:none. */
html[data-theme="clean-hub"] .launch-ribbon {
  position: static; display: block; transform: none; width: auto; top: auto; right: auto;
  padding: 0; background: var(--ch-tx); color: var(--ch-bg) !important; border: none; box-shadow: none;
  font: 600 10.5px/1 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; letter-spacing: .12em;
  /* Pink fun's pinned ribbon takes no pointer (it overlaps a control there). In the flow it is
     on top of nothing, so it may feel one again — which is what pauses the marquee to be read. */
  pointer-events: auto;
}
html[data-theme="clean-hub"] .launch-ribbon .ribbon-track { padding: 8px 0; }

/* ---------------------------------------------------------------------------
   5. THE SHELL — app.js emits these only under skinIs('clean-hub')
   --------------------------------------------------------------------------- */
html[data-theme="clean-hub"] #root .ch-ico { flex: none; display: block; }

/* Header: round back · title pill · round account. The design's top row. */
html[data-theme="clean-hub"] #root .ch-top {
  position: sticky; top: 0; z-index: 40;
  display: flex; align-items: center; gap: 10px;
  padding: 14px 16px 10px;
  background: linear-gradient(var(--ch-bg) 78%, rgba(239, 240, 233, 0));
}
html[data-theme="clean-hub"] #root .ch-round,
html[data-theme="clean-hub"] #root .ch-round-gap { flex: none; width: 44px; height: 44px; }
html[data-theme="clean-hub"] #root .ch-round {
  display: flex; align-items: center; justify-content: center; padding: 0;
  border: none; border-radius: var(--ch-r-pill); background: var(--ch-sur); color: var(--ch-tx); cursor: pointer;
}
html[data-theme="clean-hub"] #root .ch-avatar { font: 700 13px/1 var(--ch-font); letter-spacing: .02em; }
html[data-theme="clean-hub"] #root .ch-top-title {
  flex: 1; min-width: 0; height: 44px; padding: 0 18px;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--ch-r-pill); background: var(--ch-sur);
  font: 800 17px/44px var(--ch-font); color: var(--ch-tx);
  display: block; text-align: center; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* The search-context strip under it. */
html[data-theme="clean-hub"] #root [data-ui="contextbar"] {
  margin: 4px 16px 6px !important; padding: 8px 8px 8px 16px !important;
  background: var(--ch-sur) !important; border: none !important; border-radius: var(--ch-r-pill) !important;
}
html[data-theme="clean-hub"] #root [data-ui="contextbar"] > span { font-family: var(--ch-mono) !important; font-weight: 600 !important; }
/* Tracked less than any other caps label: at 390px the strip has about 250px for "SEARCH:
   <the name> · FULL REPORT · RISK 62/100", and at part 2's .12em the name was the first thing
   to be ellipsised away entirely ("SEARCH:…"). The three attributes are only there to outrank
   part 2's label rule, which would otherwise put the .12em back. */
html[data-theme="clean-hub"] #root [data-ui="contextbar"] > span[style*="font:700"][style*="Space Mono"][style*="letter-spacing"]:not(.report-page):not(.report-page *) { letter-spacing: .04em !important; }
html[data-theme="clean-hub"] #root [data-ui="contextbar"] > button { border-radius: var(--ch-r-pill) !important; padding: 9px 14px !important; }

/* The notice strips under it (a search is already running / search stopped / paid for by your
   credit) were full-bleed bars ruled off underneath. In a column of rounded cards they are
   cards: inset to the same 16px, bordered in their own band, no rule. The context strip above
   is excluded by its hook; nothing else in the shell is a direct child with a bottom rule. */
html[data-theme="clean-hub"] #root [data-ui="shell"] > div[style*="border-bottom:3px solid"]:not([data-ui]):not(.report-page):not(.report-page *) {
  margin: 4px 16px 8px !important; border: 1.5px solid !important; border-radius: var(--ch-r-ctl) !important;
}
html[data-theme="clean-hub"] #root [data-ui="shell"] > div[style*="border-bottom:3px solid #1D3D64"]:not([data-ui]):not(.report-page):not(.report-page *),
html[data-theme="clean-hub"] #root [data-ui="shell"] > div[style*="border-bottom:3px solid #B96A00"]:not([data-ui]):not(.report-page):not(.report-page *) { border-color: var(--ch-caution-brd) !important; }
html[data-theme="clean-hub"] #root [data-ui="shell"] > div[style*="border-bottom:3px solid #1E7A3C"]:not([data-ui]):not(.report-page):not(.report-page *) { border-color: var(--ch-clear-brd) !important; }

/* Bottom nav: a floating pill of icon-over-label tabs; the accent only when active. */
html[data-theme="clean-hub"] #root .ch-nav {
  position: fixed; left: 0; right: 0; bottom: 12px; z-index: 60; margin: 0 auto;
  display: grid; gap: 4px; padding: 6px;
  width: min(calc(100% - 24px), 480px);
  background: var(--ch-sur); border: 1.5px solid var(--ch-brd); border-radius: 26px;
  box-shadow: 0 10px 30px rgba(26, 34, 44, .12);
}
html[data-theme="clean-hub"] #root .ch-tab {
  min-width: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px;
  padding: 8px 2px; border: none; border-radius: 20px; background: transparent; cursor: pointer;
  font: 600 11px/1 var(--ch-font); color: var(--ch-tx) !important; text-decoration: none;
  overflow: hidden; white-space: nowrap;
}
/* ADMIN is a real link, and part 1 paints every link in the accent ink — which made it read
   as the active tab. Spelled with the element and both exclusions so it outranks that rule. */
html[data-theme="clean-hub"] #root a.ch-tab:not(.report-page):not(.report-page *):not(.ch-tab-on) { color: var(--ch-tx) !important; }
html[data-theme="clean-hub"] #root .ch-tab-on { background: var(--ch-soft); color: var(--ch-acc-ink) !important; }
/* ACTIVE with no search behind it still goes somewhere (HISTORY), so it is quieter, not
   disabled: --ch-sub, which still passes AA, where --ch-fnt would not. */
html[data-theme="clean-hub"] #root .ch-tab-dim { color: var(--ch-sub) !important; font-weight: 400; }

/* ---------------------------------------------------------------------------
   6. THE LANDING PAGE — deliberately minimal (landingCleanHTML in app.js)
   --------------------------------------------------------------------------- */
html[data-theme="clean-hub"] #root .ch-land { min-height: 100vh; background: var(--ch-bg); color: var(--ch-tx); font-family: var(--ch-font); }
html[data-theme="clean-hub"] #root .ch-land p,
html[data-theme="clean-hub"] #root .ch-land h1,
html[data-theme="clean-hub"] #root .ch-land h2 { margin: 0; }

/* THE BACKDROP (js/shader-bg.js draws into .ch-shader; landingCleanHTML in app.js explains who
   asks for it). Three declarations on .ch-land do all the placing:
     position + z-index   make the landing its own stacking context, so the canvas at z-index -1
                          paints over the landing's paper and under everything else in it,
                          without one z-index on the content;
     clip-path: inset(0)  clips the canvas — which is position:FIXED, the size of the window and
                          not of the page, because the shader costs by the pixel — to the landing's
                          own box. Without it the canvas would also sit behind the held-code banner
                          above the landing and the ribbon above that.
   NOTHING ON .ch-land MAY CARRY A transform, filter OR will-change: any of them makes it the
   containing block of the fixed canvas, which would then be as tall as the whole page. That is
   why this landing has no screenIn animation.
   100lvh, not 100%: a phone's URL bar sliding away resizes the window, and a canvas that is
   resized is a canvas that is cleared and reallocated. The large viewport height never changes. */
html[data-theme="clean-hub"] #root .ch-land { position: relative; z-index: 0; clip-path: inset(0); }
html[data-theme="clean-hub"] #root .ch-shader { position: fixed; top: 0; left: 0; width: 100%; height: 100vh; height: 100lvh; z-index: -1; pointer-events: none; }
html[data-theme="clean-hub"] #root .ch-shader canvas { display: block; width: 100%; height: 100%; }
/* WHAT SITS OVER IT, AND WHY IT IS STILL AA. The darkest pixel the shader can draw is known:
   its ink saturates at --ch-acc (#1E9BF0, luminance .30) and it has no vignette. The
   hardest text on this page is --ch-sub (#5F6771), which needs a ground of luminance .78 for
   4.5:1. White at .84 over that darkest pixel is luminance .83: 4.8:1 for --ch-sub, 5.0:1 for
   --ch-acc-ink, 13:1 for --ch-tx — and that is a single worst pixel with no blur; the blur
   averages it with the pale paper round it, so the real figure is always better. So: every
   piece of SMALL text on this page stands on a veiled surface, and only --ch-tx at display sizes
   (the h1, the marquee) stands on the backdrop itself, where the same worst pixel gives 5.4:1.
   scripts/qa/shader_check.py measures this from the pixels of real frames. */
html[data-theme="clean-hub"] #root .ch-land :is(.ch-card, .ch-lede, .ch-facts, .ch-foot) { background: var(--ch-sur-veil); -webkit-backdrop-filter: blur(7px); backdrop-filter: blur(7px); }
html[data-theme="clean-hub"] #root .ch-land .ch-notice { background: var(--ch-caution-veil); -webkit-backdrop-filter: blur(7px); backdrop-filter: blur(7px); }
html[data-theme="clean-hub"] #root .ch-land-top { position: sticky; top: 0; z-index: 50; padding: 14px 16px 10px; background: linear-gradient(var(--ch-bg) 78%, rgba(239, 240, 233, 0)); }
html[data-theme="clean-hub"] #root .ch-land-bar { max-width: 1040px; margin: 0 auto; display: flex; align-items: center; justify-content: space-between; gap: 10px; }
html[data-theme="clean-hub"] #root .ch-pill { display: inline-flex; align-items: center; gap: 10px; height: 44px; padding: 0 18px; border-radius: var(--ch-r-pill); background: var(--ch-sur); min-width: 0; }
html[data-theme="clean-hub"] #root .ch-brand-name { font: 800 16px/1 var(--ch-font); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
html[data-theme="clean-hub"] #root .ch-wrap { max-width: 1040px; margin: 0 auto; padding: 0 16px 48px; display: flex; flex-direction: column; gap: 16px; }
html[data-theme="clean-hub"] #root .ch-wrap-hero { padding-bottom: 0; }   /* the marquee runs full-bleed between this wrap and the next */

html[data-theme="clean-hub"] #root .ch-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  height: 44px; padding: 0 20px; border: none; border-radius: var(--ch-r-pill); cursor: pointer;
  font: 700 14px/1 var(--ch-font); white-space: nowrap;
}
html[data-theme="clean-hub"] #root .ch-btn-primary { background: var(--ch-acc); color: var(--ch-on-acc); }
html[data-theme="clean-hub"] #root .ch-btn-quiet { background: var(--ch-sur); color: var(--ch-tx); }
html[data-theme="clean-hub"] #root .ch-btn-lg { height: 56px; padding: 0 30px; border-radius: 16px; font-size: 16px; width: min(100%, 360px); }

html[data-theme="clean-hub"] #root .ch-hero { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 20px; padding: clamp(40px, 9vw, 96px) 0 clamp(28px, 6vw, 64px); }
html[data-theme="clean-hub"] #root .ch-display { font: 800 clamp(34px, 6.4vw, 68px)/1.04 var(--ch-font); letter-spacing: -.025em; max-width: 14ch; }
html[data-theme="clean-hub"] #root .ch-lede { font: 400 clamp(15px, 1.6vw, 18px)/1.6 var(--ch-font); color: var(--ch-sub); max-width: 54ch; padding: 12px 20px; border-radius: 18px; }
html[data-theme="clean-hub"] #root .ch-label { font: 600 10.5px/1.6 var(--ch-mono); letter-spacing: .14em; color: var(--ch-sub); }
html[data-theme="clean-hub"] #root .ch-facts { padding: 6px 14px; border-radius: var(--ch-r-pill); }
html[data-theme="clean-hub"] #root .ch-body { font: 400 14.5px/1.6 var(--ch-font); color: var(--ch-sub); }

html[data-theme="clean-hub"] #root .ch-card { background: var(--ch-sur); border-radius: var(--ch-r-card); padding: 22px; }
/* A NOTE, NOT AN ALERT. The owner's words: "this looks too much like an error … yellow is good
   but make it look less like an error". So the warm paper stays and everything that says
   "something went wrong" goes: no warning triangle (see landingCleanHTML), no amber outline —
   a hairline instead — and a short amber rule down the left, which is how a footnote or a
   pull-quote is marked rather than how a failure is. The rule is a pseudo-element so it can be
   inset from the rounded corners instead of bending round them. */
html[data-theme="clean-hub"] #root .ch-notice { position: relative; display: flex; gap: 14px; align-items: flex-start; padding: 18px 22px 18px 26px; border: 1px solid rgba(229, 201, 142, .5); border-radius: 18px; background: var(--ch-caution-soft); color: var(--ch-tx); }
html[data-theme="clean-hub"] #root .ch-notice::before { content: ''; position: absolute; left: 12px; top: 18px; bottom: 18px; width: 3px; border-radius: 3px; background: #DDB45C; }
html[data-theme="clean-hub"] #root .ch-notice .ch-body { color: var(--ch-tx); margin-top: 4px; }
html[data-theme="clean-hub"] #root .ch-notice-title { font: 700 15px/1.35 var(--ch-font); color: var(--ch-tx); }

html[data-theme="clean-hub"] #root .ch-grid3 { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 12px; }
html[data-theme="clean-hub"] #root .ch-price { display: flex; flex-direction: column; gap: 8px; border: 1.5px solid transparent; }
html[data-theme="clean-hub"] #root .ch-price-on { border-color: var(--ch-acc); }
html[data-theme="clean-hub"] #root .ch-price-n { font: 800 40px/1.1 var(--ch-font); letter-spacing: -.02em; color: var(--ch-tx); }
html[data-theme="clean-hub"] #root .ch-price-fact { font: 600 13px/1.5 var(--ch-font); color: var(--ch-tx); margin-top: auto; padding-top: 6px; }

html[data-theme="clean-hub"] #root .ch-foot { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; justify-content: space-between; margin-top: 12px; padding: 12px 12px 12px 20px; border: 1.5px solid var(--ch-brd); border-radius: var(--ch-r-card); }

/* THE SHARED LANDING BLOCK (landingShared() in app.js), in this skin's dress. The words are
   the ones every landing carries; only the classes are this sheet's.
   The marquee: Pink fun's curve and Pink fun's motion, as one calm line of Sora on the paper and a
   dotted hairline for the path. It is an SVG, so its type is sized in the viewBox's units (1000
   across): 36 of them is 41px on a desktop and 14px on a phone. */
html[data-theme="clean-hub"] #root .ch-mq { overflow: hidden; }
html[data-theme="clean-hub"] #root .ch-mq-svg { display: block; width: 100%; height: clamp(96px, 16vw, 160px); }
html[data-theme="clean-hub"] #root .ch-mq-path { stroke: var(--ch-acc-brd); stroke-width: 1.5; stroke-dasharray: 1 9; stroke-linecap: round; }
html[data-theme="clean-hub"] #root .ch-mq-text { font: 700 36px var(--ch-font); letter-spacing: .01em; fill: var(--ch-tx); }
/* ...and under prefers-reduced-motion app.js writes the same sentence as this still line. */
html[data-theme="clean-hub"] #root .ch-land .ch-mq-still { max-width: 1040px; margin: 0 auto; padding: 8px 16px 28px; text-align: center; font: 700 clamp(13px, 1.5vw, 16px)/1.8 var(--ch-font); letter-spacing: .08em; color: var(--ch-tx); }
html[data-theme="clean-hub"] #root .ch-soon { padding: clamp(22px, 4vw, 40px); }
html[data-theme="clean-hub"] #root .ch-land .ch-h2 { font: 800 clamp(26px, 4.2vw, 44px)/1.08 var(--ch-font); letter-spacing: -.02em; margin: 8px 0 16px; }
html[data-theme="clean-hub"] #root .ch-soon-p { max-width: 74ch; font-size: 15.5px; line-height: 1.7; color: var(--ch-tx); }
html[data-theme="clean-hub"] #root .ch-soon-p + .ch-soon-p { margin-top: 12px; }
html[data-theme="clean-hub"] #root .ch-mark { color: var(--ch-acc-ink); font-weight: 700; }

/* A HELD CREDIT, SAID OUT LOUD (app.js: creditStep3HeadHTML, creditCardBits, the urgency lock in
   wizardHTML, freebieBannerHTML, creditSettingsHTML). The colours already arrive through the
   [style*=] rules above, because the new markup is written in app.js's existing green vocabulary;
   what is here is the shape and the type. Hooked by data-credit, an attribute that paints nothing,
   because these are pieces with a job rather than a colour.
     held      the "You hold N gifted searches: ..." panel at the top of step 3
     use       the label on a covered plan card ("FULL REPORT -- use the freebie code ...")
     covered   "$0.00 -- covered by your code, no card . N left"
     na        "Your gifted code doesn't apply to this one."
     speed     "Your code is for standard speed."      keep / creditUseAfterAll   the two links
   --ch-clear on the selected card's --ch-soft is 5.1:1 and --ch-sub on it is 4.6:1. */
html[data-theme="clean-hub"] #root [data-credit="held"]:not(.report-page):not(.report-page *) { border-width: 1.5px !important; border-radius: var(--ch-r-ctl) !important; box-shadow: none !important; padding: 14px 18px !important; }
html[data-theme="clean-hub"] #root [data-credit="held-line"]:not(.report-page):not(.report-page *) { font: 600 14px/1.55 var(--ch-font) !important; letter-spacing: 0 !important; }
html[data-theme="clean-hub"] #root [data-credit="declined"]:not(.report-page):not(.report-page *) { font: 400 13px/1.6 var(--ch-font) !important; color: var(--ch-tx) !important; }
/* On a plan card, and the card re-inks every coloured descendant -- so these three name the card,
   and the label names its own inline colour, to outrank that rule rather than fight it with order. */
html[data-theme="clean-hub"] #root button[data-act="pickPlan"][style] p[data-credit="use"][style*="color:"][style]:not(.report-page):not(.report-page *) { font: 700 12.5px/1.45 var(--ch-font) !important; letter-spacing: 0 !important; padding: 8px 12px !important; border-width: 1.5px !important; border-radius: 10px !important; background: var(--ch-clear-soft) !important; color: var(--ch-clear) !important; }
html[data-theme="clean-hub"] #root button[data-act="pickPlan"][style] p[data-credit="covered"][style]:not(.report-page):not(.report-page *) { font: 600 13px/1.5 var(--ch-font) !important; color: var(--ch-clear) !important; }
html[data-theme="clean-hub"] #root :is([data-credit="na"], [data-credit="speed"]):not(.report-page):not(.report-page *) { font: 500 12.5px/1.5 var(--ch-font) !important; letter-spacing: 0 !important; color: var(--ch-sub) !important; }
html[data-theme="clean-hub"] #root button:is([data-credit="keep"], [data-act="creditUseAfterAll"])[style]:not(.report-page):not(.report-page *) { font: 600 13px/1.6 var(--ch-font) !important; color: var(--ch-acc-ink) !important; background: none !important; border: 0 !important; box-shadow: none !important; padding: 0 !important; min-height: 0 !important; text-decoration: underline; text-underline-offset: 3px; }
html[data-theme="clean-hub"] #root button[data-credit="urgency-set"][style]:not(.report-page):not(.report-page *) { line-height: 1.35 !important; }
html[data-theme="clean-hub"] #root :is([data-credit="banner-kind"], [data-credit="banner-count"]):not(.report-page):not(.report-page *) { font: 600 13.5px/1.5 var(--ch-font) !important; }
/* ME: one row per kind, the count on the right. */
html[data-theme="clean-hub"] #root [data-credit="me-row"]:not(.report-page):not(.report-page *) { border-bottom: 1px solid var(--ch-brd) !important; padding: 10px 0 !important; }
html[data-theme="clean-hub"] #root [data-credit="me-row"] > span:not(.report-page):not(.report-page *) { font-family: var(--ch-font) !important; }
