
  /* ---------------------------------------------------------------------
     Design tokens. See DESIGN.md at the repo root — it is the authority, this
     block is its implementation. Canopy is a measuring instrument: numbers are
     the hero, status is a reading rather than decoration, and the chrome gets
     out of the way. Scales here are deliberately short; if a new value feels
     necessary, the layout is usually wrong.
     --------------------------------------------------------------------- */
  :root {
    color-scheme: light dark;
    /* Swiss world (2026-08-09). The leaf green stopped being the brand colour
       and became one status among three. What carries the surface now is the
       grid, the scale contrast, and a single signal red used as a field rather
       than a sprinkled accent. The leaf tokens survive because the sprout mark
       and a hundred call sites still reference them; they are no longer the
       product's voice. */
    --line: #1111112e;
    --rule: #111;
    --signal: #e2231a;        /* fill only — 4.68:1 with white on it */
    --signal-ink: #cc1b10;    /* text — #e2231a measured 4.25:1 and failed */
    --leaf: #3f8049; --leaf-deep: #2f6b3c; --leaf-ink: #2f6b3c;

    /* Status splits three ways, because one hex cannot be both a legible text
       colour and a saturated fill. --x is the fill (strips, bars, dots, solid
       shapes with no text on them); --x-ink is the text colour, tuned to clear
       4.5:1 on both surface and page; --on-x is what sits ON the fill. Amber
       takes near-black ink — white on #c79a33 measured 2.59:1, which fails the
       bar Canopy's own a11y layer grades other sites against. */
    /* --pass deepened from #4c9a5a: white on the old green measured 3.46:1, so
       every "PASS" pill and ✓ badge failed the same bar. #3f8049 clears 4.78:1
       with white and still reads as the same leaf family. */
    --pass: #3f8049; --warn: #c79a33; --fail: #c0563e;
    --pass-ink: #2f6b3c; --warn-ink: #7a5a12; --fail-ink: #a8412a;
    --on-pass: #fff; --on-warn: #241a02; --on-fail: #fff;

    /* #797f77 measured 3.85:1 on --page: secondary copy is most of the words
       in a report and does not get to be decorative. */
    --muted: #5f665e;

    /* Near-white ground, near-black ink. Elevation is a rule, not a shadow:
       Swiss separates by line and space, so the shadow tokens flatten to
       nothing rather than being deleted out from under 40 call sites. */
    --surface: #fff; --page: #f4f4f2; --ink: #111;
    --shadow: none;
    --shadow-lift: none;
    --ring: 0 0 0 3px #e2231a55;

    /* Type scale on a 16px body floor. Replaces 133 declarations across 29
       ad-hoc sizes (14 of them crammed between 0.66 and 0.98rem, which is
       drift, not hierarchy). Body is 1rem because a report's check details are
       the substance of the product and get read, not glanced at; the old
       0.95rem body sat against a 1.15rem h2, two steps too close to carry
       different jobs, which is why reports read as one undifferentiated wall. */
    --t-micro: 0.75rem; --t-small: 0.875rem; --t-body: 1rem; --t-lead: 1.125rem;
    --t-h3: 1.25rem; --t-h2: 1.5rem; --t-h1: 2rem;
    --t-display: 4.5rem; --t-display-md: 3rem; --t-display-sm: 2.4rem;
    /* The grade letter is a component ramp, not a type step: it renders at four
       container-dependent sizes that already form a coherent ~1.26 ratio, so
       they are tokenised as they stand rather than bent into the text scale. */
    --g-sm: 1.9rem; --g-md: 2.8rem; --g-lg: 5rem; --g-xl: 8rem;

    /* Space, 4px base. Replaces 19 margin values incl. 1/1.05/1.1/1.2 coexisting. */
    --s1: 0.25rem; --s2: 0.5rem; --s3: 0.75rem; --s4: 1rem; --s5: 1.5rem; --s6: 2rem; --s7: 3rem;

    --r-sm: 0px; --r-md: 0px; --r-full: 999px;
    --radius: var(--r-md);

    --m-fast: 120ms; --m-base: 350ms; --m-slow: 700ms;
    --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  }
  /* The dark palette is needed by two selectors that CSS cannot merge — an
     attribute rule (visitor forced dark) and a media rule (OS asked, visitor
     hasn't overridden). With no build step the *assignments* must appear
     twice, so the VALUES are defined once here and both rules reference them.
     A palette change is now one edit; previously the whole block was
     duplicated verbatim and one copy was always an edit behind. */
  :root {
    --d-surface: #171717; --d-page: #0f0f0f; --d-ink: #f2f2f0; --d-muted: #a3a3a0;
    --d-shadow: 0 1px 2px #00000060, 0 4px 16px #00000050;
    --d-shadow-lift: 0 2px 6px #00000070, 0 12px 28px #00000060;
    --d-leaf-ink: #7fc48c; --d-line: #ffffff2b; --d-rule: #f2f2f0; --d-signal-ink: #ff6b5e;
    --d-pass-ink: #7fc48c; --d-warn-ink: #d9ae4a; --d-fail-ink: #e08d75;
  }
  :root[data-theme="dark"] {
    --surface: var(--d-surface); --page: var(--d-page); --ink: var(--d-ink); --muted: var(--d-muted);
    --shadow: none; --shadow-lift: none; --leaf-ink: var(--d-leaf-ink);
    --line: var(--d-line); --rule: var(--d-rule); --signal-ink: var(--d-signal-ink);
    --pass-ink: var(--d-pass-ink); --warn-ink: var(--d-warn-ink); --fail-ink: var(--d-fail-ink);
  }
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
      --surface: var(--d-surface); --page: var(--d-page); --ink: var(--d-ink); --muted: var(--d-muted);
      --shadow: none; --shadow-lift: none; --leaf-ink: var(--d-leaf-ink);
    --line: var(--d-line); --rule: var(--d-rule); --signal-ink: var(--d-signal-ink);
      --pass-ink: var(--d-pass-ink); --warn-ink: var(--d-warn-ink); --fail-ink: var(--d-fail-ink);
    }
  }
  /* Numbers are the hero: anything that can change or be compared gets tabular
     figures, so a score doesn't shift width as it counts. */
  .num, .tally, .hist-score, .grade small, .grade span, td.score, .date {
    font-variant-numeric: tabular-nums;
  }
  * { box-sizing: border-box; }
  html { background: var(--page); }
  body {
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", ui-sans-serif, sans-serif;
    /* The measure widened from 680px because a grid needs columns to be a
       grid. Prose still sits on a readable measure via .col spans rather than
       by starving the whole page of width. */
    max-width: 1120px; margin: var(--s6) auto var(--s7); padding: 0 var(--s5); line-height: 1.55;
    background: var(--page); color: var(--ink);
    -webkit-font-smoothing: antialiased;
  }
  /* ---------------------------------------------------------------------
     The grid. One 12-column module disciplines every surface, present and
     future — that is the whole reason this world was chosen over the louder
     candidates: it answers layouts nobody has designed yet. Anything that
     needs a new arrangement asks the grid for columns, never for a one-off.
     --------------------------------------------------------------------- */
  .grid { display: grid; grid-template-columns: repeat(12, 1fr); gap: var(--s5); }
  .c1{grid-column:span 1}.c2{grid-column:span 2}.c3{grid-column:span 3}
  .c4{grid-column:span 4}.c5{grid-column:span 5}.c6{grid-column:span 6}
  .c7{grid-column:span 7}.c8{grid-column:span 8}.c9{grid-column:span 9}
  .c12{grid-column:1/-1}
  @media (max-width: 860px) {
    .grid { gap: var(--s4); }
    .c3,.c4,.c5 { grid-column: span 6; }
    .c6,.c7,.c8,.c9 { grid-column: 1/-1; }
  }
  @media (max-width: 560px) { .grid > * { grid-column: 1/-1; } }
  /* Display type: hierarchy is scale contrast and weight, not decoration.
     Tight tracking is what stops a system grotesk reading as a default. */
  .display { font-size: var(--t-display); line-height: .94; letter-spacing: -.04em;
    font-weight: 700; margin: 0; }
  .display em { font-style: normal; color: var(--signal-ink); }
  @media (max-width: 860px) { .display { font-size: var(--t-display-md); } }
  @media (max-width: 560px) { .display { font-size: var(--t-display-sm); } }
  /* Rules carry structure in place of cards and shadows. */
  .rule-top { border-top: 2px solid var(--rule); padding-top: var(--s3); }
  .rule-hair { border-top: 1px solid var(--line); }
  /* Homepage hero. The headline owns columns 1-8 at display scale, the lede
     sits on a readable measure beside it, and the facts stack under a rule in
     the right columns. Hierarchy is scale and position, not colour or boxes. */
  .hero { margin: var(--s6) 0 var(--s5); align-items: start; }
  .hero-lede { font-size: var(--t-lead); line-height: 1.45; color: var(--ink); margin: 0; }
  ul.hero-facts { list-style: none; margin: 0; padding: 0; font-size: var(--t-small);
    color: var(--muted); line-height: 1.9; }
  .brand { margin-bottom: var(--s2); }
  .brand h1 { font-size: var(--t-h2); letter-spacing: -.02em; }
  /* The scan form is the page's primary instrument: full measure, on a rule. */
  form.scan { margin-top: var(--s5); align-items: stretch; }
  .tagline { font-size: var(--t-body); }
  @media (prefers-reduced-motion: no-preference) {
    .report, .feats, .tiers, .cmp-grades, .layer-grid, table.dash, table.up {
      animation: rise 0.35s ease-out both; }
    @keyframes rise { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
  }
  /* Skip link: 27 nav links is a real tab gauntlet on every page. Off-screen
     until focused, then it lands as a proper control. */
  .skip { position: absolute; left: -9999px; top: 0; z-index: 10;
    background: var(--surface); color: var(--leaf-ink); font-weight: 600;
    font-size: var(--t-small); padding: var(--s2) var(--s4);
    border: 1px solid var(--rule); border-radius: var(--r-sm); box-shadow: none; }
  .skip:focus { left: var(--s4); top: var(--s2); }
  #main:focus { outline: none; }
  nav.nav { display: flex; align-items: flex-start; gap: var(--s4);
    font-size: var(--t-small); margin: 0 0 var(--s6); padding-bottom: var(--s3);
    border-bottom: 2px solid var(--rule); }
  /* With five grouped rows the brand sits at the top-left, aligned with the
     first (SCAN) row, rather than floating at the vertical centre of the block. */
  nav.nav > a.nav-brand { padding-top: var(--s1); }
  /* The brand lockup is the nav's home anchor and the one identity the nav
     bar carries — the mark and wordmark used to live only in the page header
     below it (DESIGN §9). Its own aria-label overrides the sprout's, so the
     link announces "Canopy — home", not "Canopy sprout Canopy". */
  a.nav-brand { flex: 0 0 auto; display: inline-flex; align-items: center; gap: var(--s2);
    color: var(--ink); text-decoration: none; font-weight: 700; }
  a.nav-brand .sprout { width: 26px; height: 26px; }
  a.nav-brand .nav-wordmark { font-size: var(--t-lead); letter-spacing: -0.02em; }
  a.nav-brand:hover .nav-wordmark { text-decoration: underline; text-underline-offset: 5px;
    text-decoration-thickness: 2px; text-decoration-color: var(--signal); }
  a.nav-brand:focus-visible { outline: none; box-shadow: var(--ring); }
  nav.nav .nav-rows { flex: 1 1 auto; min-width: 0;
    display: flex; flex-direction: column; gap: var(--s1); }
  nav.nav .nav-row { position: relative; display: flex; flex-wrap: wrap; align-items: baseline;
    /* The left inset is clearance for the absolutely-positioned row label
       (SCAN/LAYERS/CHECKS/MONITOR/TOOLKIT), so it tracks the widest label's
       width — not the space scale. Snapping it to --s7 (3rem) overlapped the
       label with the first link; 4rem was sized for the old six-letter labels
       and the seven-letter MONITOR/TOOLKIT need the extra room. */
    gap: var(--s1) var(--s3); padding: var(--s1) 0 var(--s1) 4.75rem; }
  /* On a phone the wrapped nav was ~450px of a 812px screen — the product
     started below a wall of links. Each row becomes one scrollable strip. */
  @media (max-width: 700px) {
    /* Brand sits on its own line above the two scroll strips, so a phone
       leads with the identity, not a cramped logo fighting the links. */
    nav.nav { flex-direction: column; align-items: stretch; gap: var(--s2); }
    a.nav-brand { align-self: flex-start; }
    nav.nav .nav-row { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none;
      padding-left: 4.1rem; padding-bottom: var(--s1); }
    nav.nav .nav-row::-webkit-scrollbar { display: none; }
    nav.nav .nav-row a { white-space: nowrap; }
    nav.nav .nav-label { top: 0.3rem; }
  }
  nav.nav .nav-label { position: absolute; left: 0; top: 0.35rem; font-size: var(--t-micro);
    text-transform: uppercase; letter-spacing: 0.08em; color: var(--muted); opacity: 0.75; }
  nav.nav .nav-spacer { flex: 1; }
  nav.nav a { color: var(--muted); text-decoration: none; padding: 0.15rem 0.1rem; }
  nav.nav a:hover { color: var(--ink); }
  /* Current page: colour alone would be the one signal a colour-blind or
     low-vision visitor misses, so it also carries weight and an underline. */
  nav.nav a[aria-current="page"] {
    color: var(--ink); font-weight: 700;
    text-decoration: underline; text-underline-offset: 6px;
    text-decoration-thickness: 3px; text-decoration-color: var(--signal);
  }
  nav.nav .nav-sep { width: 1px; height: 0.9rem; background: var(--line); }
  nav.nav .nav-pro { color: var(--leaf-ink); font-weight: 600; }
  button.theme-toggle { margin-left: auto; font: inherit; font-size: var(--t-micro); white-space: nowrap;
    color: var(--muted); background: var(--surface); border: 1px solid var(--line);
    border-radius: 999px; padding: 0.14rem var(--s2); cursor: pointer; line-height: 1.4;
    transition: color 0.15s, border-color 0.15s, transform 0.12s; }
  button.theme-toggle:hover { color: var(--ink); border-color: var(--rule); }
  button.theme-toggle:active { transform: none; }
  button.theme-toggle:focus-visible { outline: none; box-shadow: var(--ring); }
  .brand { display: flex; align-items: center; gap: var(--s2); }
  .brand h1 { font-size: var(--t-h1); margin: 0; letter-spacing: -0.02em; font-weight: 700; }
  .tagline { color: var(--muted); margin: var(--s1) 0 var(--s5); font-weight: 400; }
  a { color: var(--leaf-ink); }
  form.scan { display: flex; gap: var(--s2); flex-wrap: wrap; }
  form.scan input[type=url], form.scan input[type=text] {
    flex: 1 1 260px; padding: var(--s3) var(--s2); font-size: var(--t-lead);
    border: 0; border-bottom: 2.5px solid var(--rule); border-radius: 0;
    background: transparent; color: inherit;
    transition: border-color var(--m-fast);
  }
  form.scan input:focus-visible { outline: none; box-shadow: var(--ring); }
  form.scan button {
    padding: var(--s3) var(--s5); font-size: var(--t-small); font-weight: 700; cursor: pointer;
    letter-spacing: .08em; text-transform: uppercase;
    border: 0; border-radius: 0; color: #fff; background: var(--signal);
    box-shadow: none; transition: filter var(--m-fast);
  }
  form.scan button:hover { filter: brightness(1.06); transform: translateY(-1px); }
  form.scan button:active { transform: none; }
  form.scan button:focus-visible { outline: none; box-shadow: var(--ring); }
  button.busy { opacity: 0.75; cursor: progress; filter: saturate(0.7); }
  /* Scan progress. Every scan is a full-page GET the server answers
     synchronously — a whole-site sweep costs ~43 subrequests and several
     seconds, during which the browser sits on the current page with nothing
     but the dimmed button to show for it, which reads as frozen. A 2px signal
     bar pinned to the top edge (the --rule weight, the field colour) draws
     toward the right edge on submit and holds near the end — the standard
     "request in flight" affordance in Canopy's own vocabulary. The page
     navigation is the completion, so it never animates to 100%. Motion only:
     under reduced-motion it stays width 0 (invisible) and the button's
     "Scanning…" label carries the state. */
  .scanbar { position: fixed; top: 0; left: 0; height: 2px; width: 0;
    background: var(--signal); z-index: 50; pointer-events: none; }
  @media (prefers-reduced-motion: no-preference) {
    .scanbar.go { animation: scanning 8s var(--ease) forwards; }
    @keyframes scanning { from { width: 0; } to { width: 92%; } }
  }
  /* Scope control. The hero form promised twelve layers and ran one; the
     choice is now explicit and "Everything" is the default, so the front door
     delivers what the tagline sells. Native radios, visually replaced by their
     labels — no inline styles, and keyboard/screen-reader behaviour is the
     browser's rather than something reimplemented badly. */
  .sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
  fieldset.scope { flex: 1 0 100%; display: flex; gap: var(--s2); border: 0; padding: 0;
    margin: var(--s2) 0 0; }
  .scope-opt { cursor: pointer; }
  .scope-opt input { position: absolute; opacity: 0; width: 0; height: 0; }
  .scope-opt span { display: inline-flex; align-items: baseline; gap: var(--s2);
    padding: var(--s2) var(--s3); border: 1px solid var(--rule); border-radius: 0;
    font-size: var(--t-small); color: var(--muted); background: transparent;
    transition: background var(--m-fast), color var(--m-fast); }
  .scope-opt small { font-size: var(--t-micro); opacity: 0.8; white-space: nowrap; }
  /* On a narrow screen the sub-labels wrapped under their own pill and made the
     control look broken. The pill label alone carries the meaning; the
     descriptor is a nicety, so it goes rather than wraps. */
  @media (max-width: 560px) { .scope-opt small { display: none; } }
  .scope-opt:hover span { color: var(--ink); }
  .scope-opt input:checked + span { background: var(--ink); color: var(--page);
    border-color: var(--ink); font-weight: 700; }
  .scope-opt input:focus-visible + span { outline: none; box-shadow: var(--ring); }
  /* Folded feature groups: the homepage was 65+ clickable choices before the
     fold. The twelve layers stay open (they are the promise made concrete);
     everything else is one line until asked for. */
  details.feat-fold { margin-top: var(--s6); border-top: 1px solid var(--line); padding-top: var(--s3); }
  details.feat-fold summary { cursor: pointer; display: flex; align-items: baseline;
    gap: var(--s2); list-style: none; }
  details.feat-fold summary::-webkit-details-marker { display: none; }
  details.feat-fold summary::after { content: "▸"; color: var(--muted); font-size: var(--t-small); }
  details.feat-fold[open] summary::after { content: "▾"; }
  details.feat-fold summary .feat-label { margin: 0; }
  details.feat-fold .feat-count { font-size: var(--t-small); color: var(--muted); }
  details.feat-fold summary:focus-visible { outline: none; box-shadow: var(--ring); border-radius: var(--r-sm); }
  .after-result { margin: var(--s5) 0 0; font-size: var(--t-body); }
  .after-result a { color: var(--leaf-ink); text-decoration: none; }
  .after-result a:hover { text-decoration: underline; }
  .examples { font-size: var(--t-small); color: var(--muted); margin: var(--s2) 0 0; }
  .examples a { color: inherit; }
  h2 { font-size: var(--t-h2); margin-top: var(--s6); }
  ul { padding-left: 0; list-style: none; }

  /* A report is a ruled region of the page, not a card floating on it. */
  .report { margin-top: var(--s6); border: 0; border-top: 2px solid var(--rule);
    border-radius: 0; padding: var(--s5) 0 0; background: transparent; box-shadow: none; }
  .report.error { border-top-color: var(--signal); }
  /* Failure card (see failureCard()). A dead end is the screen a first visit is
     likeliest to land on, so it is laid out like a small report rather than a
     stack of paragraphs: diagnosis on top, then the routes out. */
  .report.fail { border-color: #c0563e88; }
  .fail-head { display: flex; align-items: flex-start; gap: var(--s3); }
  .fail-icon { flex: none; width: 1.55rem; height: 1.55rem; margin-top: var(--s1); border-radius: 50%;
    background: var(--fail); color: #fff; font-weight: 700; font-size: var(--t-body); line-height: 1;
    display: flex; align-items: center; justify-content: center; }
  .fail-lead { min-width: 0; }
  .fail-title { font-weight: 700; margin: 0; word-break: break-word; }
  .fail-msg { margin: var(--s1) 0 0; color: var(--muted); font-size: var(--t-body); }
  .fail-tag { display: inline-block; vertical-align: 0.1em; margin-left: var(--s1); white-space: nowrap;
    font-size: var(--t-micro); font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em;
    color: var(--fail); background: #c0563e1a; border: 1px solid #c0563e40;
    border-radius: 999px; padding: 0.14rem var(--s2); }
  .fail-why { margin: var(--s4) 0 0; font-size: var(--t-body); }
  .fail-acts { display: flex; flex-wrap: wrap; gap: var(--s2); margin-top: var(--s4); }
  a.fail-act { font-size: var(--t-small); font-weight: 600; text-decoration: none; color: var(--ink);
    background: var(--surface); border: 1px solid var(--line); border-radius: 999px;
    padding: var(--s2) var(--s4); transition: border-color 0.12s, color 0.12s, transform 0.12s; }
  a.fail-act:hover { border-color: var(--signal); color: var(--signal-ink); }
  a.fail-act:active { transform: none; }
  a.fail-act:focus-visible { outline: none; box-shadow: var(--ring); }
  a.fail-act.primary { color: #fff; border-color: transparent; box-shadow: var(--shadow);
    background: var(--signal); }
  a.fail-act.primary:hover { color: #fff; filter: brightness(1.06); }
  .fail-alt { margin: var(--s4) 0 0; padding: var(--s3) 0 0; font-size: var(--t-small);
    background: transparent; border: 0; border-top: 1px solid var(--line); border-radius: 0; }
  .fail-alt a { font-weight: 600; }
  .report-head { display: flex; align-items: flex-start; gap: var(--s5); }
  /* The grade stopped being a rounded gradient chip with a radial gauge — that
     was the old world's signature and it read as a widget. Here the letter is
     the largest object on the page, set in a hard field, with the score as a
     rule beneath it. Scale contrast is the hierarchy; nothing glows. */
  .grade { display: block; flex: none; border-radius: 0; padding: var(--s3) var(--s4) var(--s3);
    color: #fff; min-width: 132px; }
  .grade span { display: block; font-size: var(--g-lg); font-weight: 700; line-height: .84;
    letter-spacing: -.05em; }
  .grade small { display: block; font-size: var(--t-micro); letter-spacing: .1em;
    margin-top: var(--s2); border-top: 1px solid #ffffff59; padding-top: var(--s1); }
  .g-good { background: var(--pass); }
  .g-mid { background: var(--warn); color: var(--on-warn); }
  .g-mid small { border-top-color: #241a0259; }
  .g-bad { background: var(--fail); }
  .g-none { background: #767676; }
  /* The score bar replaces the radial sweep: same information, in the grid's
     own language. Width comes from a class, never an inline style. */
  .gbar-wrap { margin-top: var(--s2); height: 4px; background: #ffffff40; }
  .gbar-fill { display: block; height: 100%; background: #fff; }
  .g-mid .gbar-wrap { background: #241a0233; } .g-mid .gbar-fill { background: var(--on-warn); }
  /* The tile's own delta since the last recorded scan. Inherits the tile's
     on-fill colour, so direction reads by arrow and word rather than by hue —
     the background is already a status colour. */
  .grade .gdelta { display: block; font-size: var(--t-micro); letter-spacing: .08em;
    margin-top: var(--s1); font-variant-numeric: tabular-nums; opacity: .92; }
  @media (prefers-reduced-motion: no-preference) {
    .gbar-fill { animation: gbarIn var(--m-slow) var(--ease) both; transform-origin: left; }
    @keyframes gbarIn { from { transform: scaleX(0); } to { transform: scaleX(1); } }
  }
  /* Percentage widths as classes — style-src 'self' forbids inline widths,
     and every progress-style bar in the product shares this one ladder. */
  .w-0 { width: 0%; } .w-5 { width: 5%; } .w-10 { width: 10%; } .w-15 { width: 15%; } .w-20 { width: 20%; } .w-25 { width: 25%; } .w-30 { width: 30%; } .w-35 { width: 35%; } .w-40 { width: 40%; } .w-45 { width: 45%; } .w-50 { width: 50%; } .w-55 { width: 55%; } .w-60 { width: 60%; } .w-65 { width: 65%; } .w-70 { width: 70%; } .w-75 { width: 75%; } .w-80 { width: 80%; } .w-85 { width: 85%; } .w-90 { width: 90%; } .w-95 { width: 95%; } .w-100 { width: 100%; }

  .report-meta { min-width: 0; }
  /* The scanned target is now an <h2>, so heading navigation lands on the
     result instead of skipping past it to the marketing sections below. It
     must not take the section-heading size: it is an identifier, not a title. */
  .target { font-weight: 600; word-break: break-all; margin: 0 0 var(--s1);
    font-size: var(--t-lead); line-height: 1.3; }
  .tally { color: var(--muted); font-size: var(--t-body); margin: 0; }
  .t-pass { color: var(--pass-ink); } .t-warn { color: var(--warn-ink); } .t-fail { color: var(--fail-ink); }

  /* Per-check health strip: one cell per check, class-colored (no inline
     widths, so it survives style-src 'self'). Reads as the report's shape.
     Cells are links now rather than <i> decorations — the detail used to live
     only in a title attribute, which meant hover-only: invisible to keyboards,
     screen readers and every touch device. The bar still reads at 8px, but each
     link carries a 20px hit area so it is reachable by thumb as well as cursor. */
  .health-strip { display: flex; gap: 3px; margin: var(--s4) 0 var(--s1); }
  .health-strip a { flex: 1 1 0; min-width: 3px; display: flex; align-items: center;
    height: 20px; border-radius: 0; text-decoration: none; }
  .health-strip a span { display: block; width: 100%; height: 8px; border-radius: 0;
    background: var(--line); transition: transform var(--m-fast), opacity var(--m-fast); }
  .health-strip a.s-pass span { background: var(--pass); }
  .health-strip a.s-warn span { background: var(--warn); }
  .health-strip a.s-fail span { background: var(--fail); }
  .health-strip:hover a span { opacity: 0.55; }
  .health-strip a:hover span, .health-strip a:focus-visible span { opacity: 1; transform: scaleY(1.5); }
  .health-strip a:focus-visible { outline: none; box-shadow: var(--ring); }
  /* Jumping from the strip lands on the check itself, and the row takes focus
     so a screen reader reads the check you asked for rather than the list top. */
  li.check:target { background: #1111110a; border-radius: var(--r-sm); }
  li.check:focus { outline: none; }
  li.check:focus-visible { outline: 2px solid var(--signal); outline-offset: 2px; border-radius: 0; }

  /* The verdict — the report reading itself to you. It sits between the tile
     and the evidence, so the eye gets grade → sentence → shape → detail. The
     left rule carries the status colour; the text stays --ink so it is read as
     a statement, not as another coloured chip. */
  .verdict { margin: var(--s4) 0 0; padding: var(--s3) var(--s4);
    font-size: var(--t-body); background: var(--page);
    border: 1px solid var(--line); border-left: 3px solid var(--muted);
    border-radius: var(--r-sm); }
  .verdict strong { font-weight: 700; }
  .verdict.v-pass { border-left-color: var(--pass); }
  .verdict.v-warn { border-left-color: var(--warn); }
  .verdict.v-fail { border-left-color: var(--fail); }
  .tier-note { margin: var(--s1) 0 var(--s2); font-size: var(--t-small); color: var(--muted); }
  .tally-more { color: inherit; }
  /* A green tile under a red regression banner told the visitor two things at
     once and let them contradict: the letter said "fine", the banner said
     "you just got worse". The banner now reads as part of the head rather than
     a detached alert, so they are taken in together. */
  .report .change { margin-bottom: var(--s4); }
  ul.checks { list-style: none; margin: var(--s2) 0 0; }
  .tier-label { font-size: var(--t-micro); text-transform: uppercase; letter-spacing: 0.05em;
    color: var(--muted); font-weight: 600; margin: var(--s5) 0 0; }
  .check { display: flex; gap: var(--s3); padding: var(--s3) 0; border-top: 1px solid var(--line); }
  .check .badge { flex: none; width: 1.5rem; height: 1.5rem; border-radius: 50%; color: #fff;
    display: flex; align-items: center; justify-content: center; font-size: var(--t-body); font-weight: 700; }
  .check.pass .badge { background: var(--pass); color: var(--on-pass); }
  .check.warn .badge { background: var(--warn); color: var(--on-warn); }
  .check.fail .badge { background: var(--fail); color: var(--on-fail); }
  .check-label { font-weight: 600; margin: var(--s1) 0 var(--s1); }
  .check-detail { margin: 0; color: var(--muted); font-size: var(--t-body); }
  .rec { margin: var(--s2) 0 0; font-size: var(--t-small); }
  .rec span { display: inline-block; font-weight: 700; color: var(--leaf-ink); margin-right: var(--s1); }
  .rec code, .raw code { font-size: var(--t-small); }
  /* A cure link — the finding's fix as a one-click CTA to a Canopy tool. */
  .cure { margin: var(--s1) 0 0; font-size: var(--t-small); }
  .cure a { font-weight: 600; color: var(--signal-ink); }
  .cure a:hover { text-decoration: underline; }
  code { background: #8881; padding: 0.1rem var(--s1); border-radius: 0; word-break: break-word; }
  pre { position: relative; }
  .copy-btn { position: absolute; top: 0.45rem; right: 0.45rem; font-size: var(--t-micro); font-weight: 600;
    padding: var(--s1) var(--s2); border: 1px solid var(--line); border-radius: 0; cursor: pointer;
    background: var(--surface); color: var(--muted); opacity: 0; transition: opacity 0.12s, color 0.12s; }
  pre:hover .copy-btn, .copy-btn:focus-visible { opacity: 1; }
  .copy-btn:hover { color: var(--signal-ink); border-color: var(--signal); }
  .copy-btn.did { color: var(--signal-ink); border-color: var(--signal); opacity: 1; }
  @media (pointer: coarse) { .copy-btn { opacity: 1; } }
  /* Thumb targets. Measured on a phone, the nav links were 26px tall and the
     footer/example links similar — comfortably past WCAG 2.2's 24px floor, well
     under the 44px that a thumb actually wants. On coarse pointers only, so the
     desktop nav keeps its density. */
  @media (pointer: coarse) {
    nav.nav a, footer a, .examples a, .after-result a {
      display: inline-flex; align-items: center; min-height: 44px; }
    .scope-opt span { min-height: 44px; }
    .health-strip a { height: 44px; }
  }
  details.raw { margin-top: var(--s4); }
  details.raw summary { cursor: pointer; color: var(--muted); font-size: var(--t-body); }
  details.raw table { width: 100%; border-collapse: collapse; margin-top: var(--s2); font-size: var(--t-small); }
  details.raw td { border-top: 1px solid var(--line); padding: var(--s1) var(--s2); vertical-align: top; word-break: break-all; }
  details.raw td:first-child { color: var(--muted); white-space: nowrap; }
  details.embed { margin-top: var(--s4); }
  details.embed summary { cursor: pointer; color: var(--muted); font-size: var(--t-body); display: flex; align-items: center; gap: var(--s2); }
  details.embed summary img { vertical-align: middle; }
  .embed-label { font-size: var(--t-small); text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); margin: var(--s3) 0 var(--s1); }
  details.embed code { display: block; font-size: var(--t-small); padding: var(--s2) var(--s2); white-space: pre-wrap; word-break: break-all; }
  textarea.md-export { display: block; width: 100%; box-sizing: border-box; margin-top: var(--s2);
    font: 0.78rem/1.5 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; color: var(--ink);
    background: var(--page); border: 1px solid var(--line); border-radius: 0;
    padding: var(--s2) var(--s3); resize: vertical; white-space: pre; overflow-x: auto; }
  textarea.md-export:focus { outline: 2px solid var(--signal); outline-offset: 1px; }
  .pill { display: inline-block; min-width: 2.7rem; padding: 0.1rem var(--s2); border-radius: 999px;
    font-size: var(--t-micro); font-weight: 700; text-transform: uppercase; letter-spacing: 0.02em; color: #fff; text-align: center; }
  .pill.pass { background: var(--pass); color: var(--on-pass); }
  .pill.warn { background: var(--warn); color: var(--on-warn); }
  .pill.fail { background: var(--fail); color: var(--on-fail); }
  .pill.na { background: #767676; color: #fff; }
  details.hist { margin-top: var(--s4); }
  details.hist summary { cursor: pointer; color: var(--muted); font-size: var(--t-body); }
  details.hist table { width: 100%; border-collapse: collapse; margin-top: var(--s2); font-size: var(--t-small); }
  details.hist td { border-top: 1px solid var(--line); padding: var(--s1) var(--s2); vertical-align: middle; }
  details.hist td a { color: inherit; }
  .hist-date { color: var(--muted); white-space: nowrap; }
  .hist-auto { color: var(--muted); font-size: var(--t-small); }
  .d-up { color: var(--pass-ink); font-weight: 700; } .d-down { color: var(--fail-ink); font-weight: 700; }
  .change { border-radius: 0; padding: var(--s2) var(--s3); font-size: var(--t-body); margin: 0 0 var(--s4); }
  .change.up { background: transparent; border: 0; border-left: 3px solid var(--pass); padding-left: var(--s3); }
  .change.down { background: transparent; border: 0; border-left: 3px solid var(--fail); padding-left: var(--s3); }
  .hist-score { font-variant-numeric: tabular-nums; }
  .snap-banner { background: transparent; border: 0; border-left: 3px solid var(--ink); border-radius: 0;
    padding: var(--s2) var(--s3); font-size: var(--t-small); margin: 0 0 var(--s4); }
  .snap-banner a { color: inherit; font-weight: 600; }
  .next-steps { font-size: var(--t-small); margin: var(--s4) 0 0; padding: var(--s2) var(--s4);
    background: transparent; border: 0; border-top: 1px solid var(--line); border-radius: 0; }
  .next-steps span { color: var(--muted); margin-right: var(--s1); }
  .next-steps a { color: var(--leaf-ink); text-decoration: none; font-weight: 600; }
  .next-steps a:hover { text-decoration: underline; }
  .api-hint { font-size: var(--t-small); color: var(--muted); margin: var(--s4) 0 0; }
  .api-hint a { color: inherit; }

  .feats { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s3); margin-top: var(--s3); }
  .feat-label { font-size: var(--t-small); text-transform: uppercase; letter-spacing: 0.08em;
    color: var(--muted); margin: var(--s6) 0 0; font-weight: 600; }
  .examples-strip { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--s3); margin-top: var(--s3); }
  @media (max-width: 700px) { .examples-strip { grid-template-columns: 1fr 1fr; } }
  a.example-card { display: flex; flex-direction: column; align-items: flex-start; gap: var(--s2);
    border: 0; border-top: 2px solid var(--rule); border-radius: 0; padding: var(--s3) 0 var(--s4);
    text-decoration: none; color: inherit; background: transparent; box-shadow: none;
    transition: color var(--m-fast); }
  a.example-card:hover { border-top-color: var(--signal); color: var(--signal-ink); }
  .example-domain { font-weight: 600; font-size: var(--t-body); }
  .example-cta { font-size: var(--t-small); color: var(--muted); }
  @media (max-width: 560px) { .feats { grid-template-columns: 1fr; } }
  a.feat { display: block; border: 0; border-top: 1px solid var(--line); border-radius: 0;
    padding: var(--s3) 0 var(--s4); text-decoration: none; color: inherit;
    background: transparent; box-shadow: none; transition: color var(--m-fast); }
  a.feat:hover { border-top-color: var(--signal); color: var(--signal-ink); }
  a.feat h3 { margin: 0 0 var(--s1); font-size: var(--t-body); color: inherit; font-weight: 700; }
  a.feat p { margin: 0; font-size: var(--t-small); color: var(--muted); }

  @media (max-width: 700px) {
    table.dash, table.cmp, table.up, details.raw table, details.hist table {
      display: block; overflow-x: auto; -webkit-overflow-scrolling: touch; }
  }
  .date { color: var(--muted); font-variant-numeric: tabular-nums; }
  .kind { font-size: var(--t-micro); text-transform: uppercase; letter-spacing: 0.03em; color: var(--muted); }
  .changelog li { list-style: none; padding: var(--s1) 0; border-top: 1px solid var(--line); font-size: var(--t-body); }
  footer { margin-top: var(--s7); font-size: var(--t-small); color: var(--muted); }
  footer a { color: inherit; }


  .compare-form { display: grid; gap: var(--s2); }
  .compare-form .row { display: flex; gap: var(--s2); align-items: center; }
  .compare-form .row span { width: 1.1rem; font-weight: 700; color: var(--muted); flex: none; }
  .compare-form input[type=url] {
    flex: 1 1 auto; padding: var(--s3) var(--s3); font-size: var(--t-body);
    border: 0; border-bottom: 2px solid var(--rule); border-radius: 0; background: transparent; color: inherit; min-width: 0;
  }
  .compare-form button {
    justify-self: start; padding: var(--s3) var(--s4); font-size: var(--t-body); font-weight: 600; cursor: pointer;
    border: 0; border-radius: 0; background: var(--signal); color: #fff; margin-top: var(--s1);
  }
  .compare-form button:hover { background: var(--signal-ink); }
  .cmp-grades { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s4); margin-top: var(--s6); }
  .cmp-card { border: 0; border-top: 2px solid var(--rule); border-radius: 0; padding: var(--s4); min-width: 0; background: transparent; box-shadow: none; }
  .cmp-card.error { border-color: #c0563e; }
  .cmp-card .grade { min-width: 84px; padding: var(--s2) var(--s3); }
  .cmp-card .grade span { font-size: var(--g-md); }
  .cmp-head { display: flex; align-items: center; gap: var(--s3); }
  .cmp-url { font-weight: 600; word-break: break-all; margin: 0; font-size: var(--t-body); }
  .cmp-sub { color: var(--muted); font-size: var(--t-small); margin: var(--s1) 0 0; }
  .cmp-sub a { color: inherit; }
  table.cmp { width: 100%; border-collapse: collapse; margin-top: var(--s5); font-size: var(--t-body); }
  table.cmp th { text-align: left; font-size: var(--t-small); text-transform: uppercase; letter-spacing: 0.03em;
    color: var(--muted); font-weight: 600; padding: var(--s2) var(--s2); border-bottom: 1px solid var(--line); }
  table.cmp th.col { text-align: center; width: 4.5rem; }
  table.cmp td { padding: var(--s2); border-top: 1px solid var(--line); vertical-align: middle; }
  table.cmp td.st { text-align: center; }
  table.cmp tr.diff { background: #c79a3318; }
  .compare-form select { padding: var(--s2) var(--s3); font-size: var(--t-body); border: 1px solid var(--line);
    border-radius: 0; background: var(--surface); color: inherit; }
  .cmp-legend { color: var(--muted); font-size: var(--t-small); margin: var(--s3) 0 0; }
  /* The "vs" between the two hosts of an example comparison card. A quiet
     micro-label, not a third domain — the two .example-domain lines carry the weight. */
  .cmp-ex-vs { font-size: var(--t-micro); text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); }


  .pv-plat { font-size: var(--t-micro); text-transform: uppercase; letter-spacing: 0.06em;
    color: var(--muted); font-weight: 700; margin: var(--s5) 0 var(--s2); }
  .pv-card { border: 0; border-top: 2px solid var(--rule); border-radius: 0; overflow: hidden;
    background: transparent; box-shadow: none; max-width: 520px; }
  .pv-img { display: block; width: 100%; background: #8881; object-fit: cover; }
  .pv-img-lg { aspect-ratio: 1.91 / 1; }
  .pv-noimg { display: flex; align-items: center; justify-content: center;
    color: var(--muted); font-size: var(--t-small); text-align: center; }
  .pv-noimg span { padding: var(--s2); }
  .pv-broken { background: #c0563e18; color: #c0563e; }
  .pv-body { padding: var(--s3) var(--s4); min-width: 0; }
  .pv-host { color: var(--muted); font-size: var(--t-small); margin: 0 0 var(--s1);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .pv-title { font-weight: 600; margin: 0 0 var(--s1); line-height: 1.3;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
  .pv-desc { color: var(--muted); font-size: var(--t-small); margin: 0; line-height: 1.4;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
  /* X small (summary) card: square thumb left, text right. */
  .pv-x-sm { display: flex; align-items: stretch; }
  .pv-x-sm .pv-img-sq { width: 120px; flex: none; aspect-ratio: 1 / 1; border-right: 1px solid var(--line); }
  .pv-x-sm .pv-body { display: flex; flex-direction: column; justify-content: center; }
  .pv-x-lg .pv-body { padding: var(--s2) var(--s4); }
  /* Slack/Discord attachment: colored rail, text, small thumb. */
  .pv-slack { position: relative; display: flex; gap: var(--s3); padding: var(--s3) var(--s4) var(--s3) var(--s4);
    max-width: 520px; align-items: flex-start; }
  .pv-slack-rail { position: absolute; left: 0; top: 0; width: 4px; height: 100%; }
  .pv-slack-main { min-width: 0; flex: 1; }
  .pv-slack-site { display: flex; align-items: center; gap: var(--s1); font-size: var(--t-small);
    font-weight: 600; margin: 0 0 var(--s1); color: var(--ink); }
  .pv-fav { width: 16px; height: 16px; border-radius: 0; flex: none; }
  .pv-slack-title { color: #1a6fc4; }
  :root[data-theme="dark"] .pv-slack-title { color: #6ab0f3; }
  @media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .pv-slack-title { color: #6ab0f3; } }
  .pv-img-thumb { width: 72px; height: 72px; flex: none; border-radius: 0; aspect-ratio: 1 / 1; }


  pre.secfile { position: relative; background: var(--surface); border: 0; border-left: 3px solid var(--rule);
    border-radius: var(--radius); padding: var(--s4) var(--s4); overflow-x: auto; font-size: var(--t-small);
    line-height: 1.5; box-shadow: var(--shadow); }
  .secfile-note { color: var(--muted); font-size: var(--t-small); margin: var(--s2) 0 var(--s2); }
  .secfile-note code { font-size: var(--t-small); }
  details.sec-gen { margin-top: var(--s6); border-top: 1px solid var(--line); padding-top: var(--s4); }
  details.sec-gen > summary { cursor: pointer; font-weight: 600; color: var(--leaf-ink); font-size: var(--t-body); }
  form.sec-genform { display: grid; gap: var(--s4); margin-top: var(--s4); max-width: 32rem; }
  form.sec-genform label { display: grid; gap: var(--s1); font-size: var(--t-body); font-weight: 600; }
  form.sec-genform label small { font-weight: 400; color: var(--muted); font-size: var(--t-small); }
  form.sec-genform input, form.sec-genform textarea, form.sec-genform select {
    padding: var(--s2) var(--s3); font-size: var(--t-body); border: 1px solid var(--line);
    border-radius: 0; background: var(--surface); color: inherit; min-width: 0; font-family: inherit; }
  form.sec-genform textarea { resize: vertical; line-height: 1.5; }
  form.sec-genform button { justify-self: start; padding: var(--s2) var(--s4); font-size: var(--t-body); font-weight: 600;
    cursor: pointer; border: 0; border-radius: 0; background: var(--signal); color: #fff; }
  form.sec-genform button:hover { background: var(--signal-ink); }
  /* /schema — grouped subfields (address, offer) share a row on wide screens. */
  .schema-group { display: grid; gap: var(--s3); grid-template-columns: 1fr 1fr; margin: 0; padding: 0; border: 0; }
  .schema-group legend { font-weight: 700; font-size: var(--t-small); padding: 0; margin-bottom: var(--s1);
    grid-column: 1 / -1; color: var(--muted); }
  .schema-group label { grid-column: auto; }
  @media (max-width: 560px) { .schema-group { grid-template-columns: 1fr; } }
  .schema-types { display: flex; flex-wrap: wrap; gap: var(--s2); margin: var(--s3) 0 var(--s5); }
  .schema-types a, .schema-types strong { font-size: var(--t-small); padding: var(--s1) var(--s3);
    border: 1px solid var(--line); border-radius: var(--r-full); }
  .schema-types strong { background: var(--ink); color: var(--page); border-color: var(--ink); }
  /* /csp-builder — checkbox groups for content toggles and third-party services.
     A vertical list of plain-weight rows, checkbox left of a label + hint, no box
     (the fieldset is invisible, the legend is the .schema-group rail). */
  .csp-fieldset { border: 0; margin: 0 0 var(--s5); padding: 0; }
  .csp-fieldset legend { font-weight: 700; font-size: var(--t-small); text-transform: uppercase;
    letter-spacing: 0.08em; padding: 0; margin-bottom: var(--s2); color: var(--muted); }
  .csp-opts { display: grid; gap: var(--s2); }
  @media (min-width: 561px) { .csp-opts.csp-two { grid-template-columns: 1fr 1fr; gap: var(--s2) var(--s5); } }
  .csp-check { display: flex; gap: var(--s2); align-items: flex-start; font-weight: 400;
    font-size: var(--t-body); }
  .csp-check input { margin-top: var(--s1); flex: none; }
  .csp-check small { display: block; color: var(--muted); font-size: var(--t-small); }


  .ref-section { margin-top: var(--s6); }
  .ref-section h3 { font-size: var(--t-lead); margin: 0 0 var(--s1); }
  .ref-note { color: var(--muted); font-size: var(--t-body); margin: 0 0 var(--s2); }
  pre.ref-code { background: var(--surface); border: 0; border-left: 3px solid var(--rule); border-radius: 0;
    padding: var(--s4) var(--s4); overflow-x: auto; font-size: var(--t-small); line-height: 1.45; margin: 0; }
  pre.ref-code code { background: none; padding: 0; }
  table.targets { width: 100%; border-collapse: collapse; margin-top: var(--s3); font-size: var(--t-small); }
  table.targets td { border-top: 1px solid var(--line); padding: var(--s1) var(--s2); vertical-align: top; }
  table.targets td:first-child { white-space: nowrap; font-weight: 600; }
  table.targets td:last-child { word-break: break-word; }
  .ref-toc { color: var(--muted); font-size: var(--t-body); }
  .ref-toc a { color: inherit; }


  .tiers { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s4); margin-top: var(--s6); }
  @media (max-width: 560px) { .tiers { grid-template-columns: 1fr; } }
  .tally-more { color: var(--leaf-ink); }
  .tier { border: 0; border-top: 2px solid var(--rule); border-radius: 0; padding: var(--s4); background: transparent; box-shadow: none; }
  .tier.pro { border-top-color: var(--signal); border-top-width: 3px; box-shadow: none; }
  .tier h3 { margin: 0; font-size: var(--t-lead); }
  .tier .price { font-size: var(--t-h1); font-weight: 700; margin: var(--s1) 0 var(--s3); }
  .tier .price small { font-size: var(--t-small); font-weight: 400; color: var(--muted); }
  .tier ul { list-style: none; margin: 0; }
  .tier-for { font-size: var(--t-small); color: var(--muted); margin: 0 0 var(--s3); }
  .tier li { padding: var(--s1) 0; font-size: var(--t-body); border-top: 1px solid var(--line); }
  .tier li::before { content: "✓ "; color: var(--pass-ink); font-weight: 700; }
  .soon { display: inline-block; font-size: var(--t-micro); text-transform: uppercase; letter-spacing: 0.04em;
    background: var(--signal); color: #fff; border-radius: 999px; padding: 0.1rem var(--s2); margin-left: var(--s2); vertical-align: middle; }
  form.waitlist { display: flex; gap: var(--s2); flex-wrap: wrap; margin-top: var(--s4); }
  form.waitlist input[type=email] { flex: 1 1 200px; padding: var(--s2) var(--s3); font-size: var(--t-body);
    border: 0; border-bottom: 2px solid var(--rule); border-radius: 0; background: transparent; color: inherit; }
  form.waitlist button { padding: var(--s2) var(--s4); font-size: var(--t-body); font-weight: 600; cursor: pointer;
    border: 0; border-radius: 0; background: var(--signal); color: #fff; }
  .wl-note { font-size: var(--t-small); color: var(--muted); margin: var(--s2) 0 0; }
  .wl-msg { border: 0; border-left: 3px solid var(--ink); background: transparent; border-radius: 0;
    padding: var(--s2) var(--s4); font-size: var(--t-body); margin-top: var(--s4); }
  .wl-msg.err { border-left-color: var(--fail); }


  .site-hero { display: flex; align-items: center; gap: var(--s4); margin-top: var(--s6); }
  .site-hero .grade { min-width: 200px; padding: var(--s4) var(--s5); }
  .site-hero .grade span { font-size: var(--g-xl); }
  .layer-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s3); margin-top: var(--s4); }
  @media (max-width: 560px) { .layer-grid { grid-template-columns: 1fr; } }
  a.layer-card { display: flex; align-items: center; gap: var(--s3); border: 0;
    border-top: 1px solid var(--line); border-radius: 0; padding: var(--s3) 0;
    text-decoration: none; color: inherit; background: transparent; box-shadow: none;
    transition: color var(--m-fast), border-color var(--m-fast); }
  a.layer-card:hover { border-top-color: var(--signal); color: var(--signal-ink); }
  .layer-card .grade { min-width: 62px; padding: var(--s2); flex: none; }
  .layer-card .grade span { font-size: var(--g-sm); }
  .layer-card .grade .gbar-wrap, .cmp-card .grade .gbar-wrap { display: none; }
  .layer-card h3 { margin: 0 0 var(--s1); font-size: var(--t-body); }
  .layer-card p { margin: 0; font-size: var(--t-small); color: var(--muted); }
  .layer-card.err { border-color: #c0563e55; }
  .priorities { margin-top: var(--s6); border-top: 1px solid var(--line); padding-top: var(--s5); }
  .priorities h2 { margin: 0 0 var(--s1); font-size: var(--t-lead); }
  .priorities.clear h2 { color: var(--pass); }
  .prio-intro { margin: 0 0 var(--s4); color: var(--muted); font-size: var(--t-small); }
  ol.prio-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--s2); }
  .prio-item { display: flex; gap: var(--s3); align-items: flex-start; }
  .prio-tag { flex: none; font-size: var(--t-micro); font-weight: 700; text-transform: uppercase; letter-spacing: 0.03em;
    padding: 0.15rem var(--s2); border-radius: var(--r-sm); margin-top: var(--s1); }
  .prio-tag.fail { background: var(--fail); color: var(--on-fail); }
  .prio-tag.warn { background: var(--warn); color: var(--on-warn); }
  .prio-body { min-width: 0; }
  .prio-head { margin: 0; font-size: var(--t-body); font-weight: 600; }
  .prio-layer { font-weight: 500; font-size: var(--t-small); color: var(--muted); text-decoration: none; white-space: nowrap; }
  .prio-layer:hover { color: var(--signal-ink); }
  .prio-rec { margin: var(--s1) 0 0; font-size: var(--t-small); color: var(--muted); }
  .prio-more { margin: var(--s4) 0 0; font-size: var(--t-small); color: var(--muted); }


  table.dash { width: 100%; border-collapse: collapse; margin-top: var(--s6); }
  table.dash th { text-align: left; font-size: var(--t-micro); text-transform: uppercase; letter-spacing: 0.04em;
    color: var(--muted); font-weight: 600; padding: var(--s2) var(--s2); border-bottom: 1px solid var(--line); }
  /* Data tables are a dense role: DESIGN.md §3 allows below the 16px body
     floor here, because a grade wall must fit its measure. At 1rem the
     dashboard's twelve columns ran past the container edge. */
  table.dash td, table.up td, table.cmp td { font-size: var(--t-small); }
  table.dash { display: block; overflow-x: auto; }
  table.dash td { padding: var(--s2) var(--s2); border-top: 1px solid var(--line); vertical-align: middle; }
  table.dash td.dom { font-weight: 600; white-space: nowrap; }
  table.dash td.dom a { color: inherit; text-decoration: none; }
  table.dash td.dom a:hover { color: var(--leaf-ink); }
  table.dash img { display: block; height: 20px; }
  table.dash td.rm a { color: var(--muted); text-decoration: none; font-size: var(--t-small); }
  .dash-note { color: var(--muted); font-size: var(--t-small); margin-top: var(--s3); }
  table.dash td.trend { white-space: nowrap; font-size: var(--t-small); }
  table.dash td.trend a { text-decoration: none; font-weight: 600; }
  table.dash td.trend a.tr-up { color: var(--pass-ink); }
  table.dash td.trend a.tr-down { color: #c0563e; }
  table.dash td.trend a.tr-flat { color: var(--muted); }
  table.dash td.trend a.tr-none { color: var(--muted); font-weight: 400; text-decoration: underline dotted; }


  table.up { width: 100%; border-collapse: collapse; margin-top: var(--s6); }
  table.up th { text-align: left; font-size: var(--t-micro); text-transform: uppercase; letter-spacing: 0.04em;
    color: var(--muted); font-weight: 600; padding: var(--s2) var(--s2); border-bottom: 1px solid var(--line); }
  table.up td { padding: var(--s2) var(--s2); border-top: 1px solid var(--line); vertical-align: middle; font-size: var(--t-body); }
  table.up td.u-url { font-weight: 600; word-break: break-all; }
  .dot { display: inline-block; width: 0.7rem; height: 0.7rem; border-radius: 50%; margin-right: var(--s2); vertical-align: baseline; }
  .dot.ok { background: var(--pass); } .dot.down { background: var(--fail); } .dot.unknown { background: #9f9f9f; }
  td.u-num { font-variant-numeric: tabular-nums; }
  table.up td.rm a { color: var(--muted); text-decoration: none; }
  .up-note { color: var(--muted); font-size: var(--t-small); margin-top: var(--s3); }
  .status-head { display: flex; align-items: center; gap: var(--s3); margin-top: var(--s6); }
  .status-head .dot { width: 1rem; height: 1rem; }
  .status-head h2 { margin: 0; font-size: var(--t-h3); }
  .stat-row { display: flex; gap: var(--s4); flex-wrap: wrap; margin-top: var(--s4); }
  .stat { border: 0; border-top: 2px solid var(--rule); border-radius: 0; background: transparent;
    box-shadow: none; padding: var(--s3) var(--s4); min-width: 8rem; }
  .stat b { display: block; font-size: var(--t-h3); font-variant-numeric: tabular-nums; }
  .stat span { font-size: var(--t-micro); text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); }
  svg.spark { display: block; width: 100%; height: 80px; margin-top: var(--s5); border: 1px solid var(--line);
    border-radius: var(--radius); background: var(--surface); box-shadow: var(--shadow); }
  .spark-label { color: var(--muted); font-size: var(--t-small); margin: var(--s2) 0 0; }
  .mt-2 { margin-top: var(--s6); }
  .mt-3 { margin-top: var(--s7); }
  .muted-note { color: var(--muted); font-size: var(--t-body); margin-top: var(--s1); }
  .tagline-gap { margin-top: var(--s5); }
  .tagline-gap-lg { margin-top: var(--s5); }
  .grade.g-none { background: #9f9f9f; }
  .break-all { word-break: break-all; }


  .ep { margin-top: var(--s5); }
  .ep h3 { font-size: var(--t-body); margin: 0 0 var(--s1); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
  .ep p { margin: 0 0 var(--s2); color: var(--muted); font-size: var(--t-body); }
  pre.doc-code { background: var(--surface); border: 0; border-left: 3px solid var(--rule); border-radius: 0;
    padding: var(--s3) var(--s4); overflow-x: auto; font-size: var(--t-small); line-height: 1.45; margin: var(--s2) 0 0; }
  pre.doc-code code { background: none; padding: 0; }


  .rpt-brand { display: flex; align-items: center; gap: var(--s3); margin-top: var(--s5);
    padding-bottom: var(--s4); border-bottom: 2px solid var(--rule); }
  .rpt-brand-mark { width: 40px; height: 40px; border-radius: 0; flex: none; color: #fff;
    background: var(--ink);
    display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: var(--t-h3); }
  .rpt-brand-name { font-weight: 700; font-size: var(--t-lead); margin: 0; }
  .pro-pill { margin-left: auto; font-size: var(--t-micro); text-transform: uppercase; letter-spacing: 0.06em;
    font-weight: 700; color: #fff; background: var(--ink); border-radius: 999px; padding: 0.15rem var(--s2); }
  .pro-note { font-size: var(--t-small); border: 0; border-left: 3px dashed var(--rule); border-radius: 0;
    padding: var(--s2) 0; margin-top: var(--s4); border-top: 1px solid var(--line); }
  .set-nav { font-size: var(--t-small); color: var(--muted); margin: var(--s4) 0 0; padding: var(--s2) var(--s3);
    border: 1px solid var(--line); border-radius: 0; background: var(--surface); }
  .set-nav span { text-transform: uppercase; letter-spacing: 0.05em; font-size: var(--t-micro); margin-right: var(--s1); }
  .set-nav a { color: var(--leaf-ink); text-decoration: none; font-weight: 600; }
  .set-nav a:hover { text-decoration: underline; }
  .set-nav em { font-style: normal; opacity: 0.75; font-size: var(--t-small); }
  .set-nav strong { color: var(--ink); }
  @media print { .set-nav { display: none; } }
  .rpt-head { margin-top: var(--s5); }
  .rpt-meta { color: var(--muted); font-size: var(--t-small); margin: var(--s1) 0 0; }
  .rpt-summary { border: 0; border-top: 2px solid var(--rule); border-radius: 0; background: transparent;
    box-shadow: none; padding: var(--s4) var(--s4); margin-top: var(--s4); font-size: var(--t-body); }
  .rpt-site { border: 0; border-top: 2px solid var(--rule); border-radius: 0; background: transparent;
    box-shadow: none; padding: var(--s4) 0 var(--s5); margin-top: var(--s5); break-inside: avoid; }
  .rpt-site-head { display: flex; align-items: center; gap: var(--s4); }
  .rpt-site-head .grade { min-width: 84px; padding: var(--s2) var(--s3); }
  .rpt-site-head .grade span { font-size: var(--g-md); }
  .rpt-domain { font-weight: 600; margin: 0; word-break: break-all; }
  .rpt-sub { color: var(--muted); font-size: var(--t-small); margin: var(--s1) 0 0; }
  table.rpt { width: 100%; border-collapse: collapse; margin-top: var(--s4); font-size: var(--t-body); }
  table.rpt th { text-align: left; font-size: var(--t-micro); text-transform: uppercase; letter-spacing: 0.05em;
    color: var(--muted); font-weight: 600; padding: var(--s1) var(--s2); border-bottom: 1px solid var(--line); }
  table.rpt td { padding: var(--s2); border-top: 1px solid var(--line); vertical-align: middle; }
  table.rpt td.rpt-num { font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap; }
  .rpt-none { color: var(--muted); font-size: var(--t-body); margin: var(--s3) 0 0; }
  .rpt-uptime { font-size: var(--t-body); margin: var(--s4) 0 0; padding: var(--s2) var(--s3); border-radius: 0;
    background: transparent; border-top: 1px solid var(--line); }
  .rpt-uptime a { color: var(--signal-ink); }
  .rpt-unwatched { background: none; border-style: dashed; color: var(--muted); }
  .print-credit { display: none; }
  @media print {
    nav.nav, form.scan, .rpt-actions, footer a { display: none !important; }
    /* App chrome is for the operator, not the client: on a printed report the
       first thing on the page should be the report, not our tool header. */
    body.doc .brand, body.doc .tagline, body.doc footer { display: none !important; }
    body.doc .rpt-brand { margin-top: 0; }
    body { max-width: none; margin: 0; padding: 0; background: #fff; color: #000; }
    .rpt-site, .rpt-summary { box-shadow: none; break-inside: avoid; }
    a { text-decoration: none; color: #000; }
    /* The document says who made it and when, once, at the end. */
    .print-credit { display: block; margin-top: var(--s5); padding-top: var(--s2);
      border-top: 1px solid #ccc; font-size: var(--t-micro); color: #555; }
    table.rpt th, table.rpt td { padding: var(--s1) var(--s2); }
    table.rpt td.rpt-num { width: 5.5rem; }
    .rpt-uptime { background: none; border: 1px solid #ddd; }
  }


  .ob-list { list-style: none; margin: var(--s4) 0 0; }
  .ob-list li { display: flex; align-items: center; gap: var(--s2); padding: var(--s2) 0;
    border-top: 1px solid var(--line); font-size: var(--t-body); }
  .ob-list li.done { color: var(--ink); }
  .ob-list li.todo { color: var(--muted); }
  .ob-mark { width: 1.4rem; height: 1.4rem; border-radius: 50%; flex: none; display: flex;
    align-items: center; justify-content: center; font-size: var(--t-small); font-weight: 700; color: #fff; }
  .ob-mark.ok { background: var(--pass); } .ob-mark.err { background: var(--fail); }
  .ob-mark.now { background: var(--signal); }
  .ob-mark.wait { background: var(--line); color: var(--muted); }
  .ob-bar { height: 6px; border-radius: 999px; background: var(--line); overflow: hidden; margin-top: var(--s4); }
  .ob-bar span { display: block; height: 100%; background: var(--signal);
    transition: width 0.3s; }


  .trend-card { border: 0; border-top: 2px solid var(--rule); border-radius: 0; background: transparent;
    box-shadow: none; padding: var(--s4) var(--s4) var(--s4); margin-top: var(--s4); }
  .trend-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s3); flex-wrap: wrap; }
  .trend-head h3 { margin: 0; font-size: var(--t-body); }
  .trend-head h3 a { color: inherit; }
  .trend-meta { font-size: var(--t-small); color: var(--muted); }
  .trend-chart { width: 100%; height: auto; display: block; margin-top: var(--s2); }
  .trend-empty { margin-top: var(--s4); font-size: var(--t-small); color: var(--muted); }
  .trend-empty a { white-space: nowrap; }


  .digest-sum { margin-top: var(--s6); font-size: var(--t-lead); }
  .digest-card { border: 0; border-top: 2px solid var(--rule); border-radius: 0; background: transparent;
    box-shadow: none; padding: var(--s4) var(--s4) var(--s4); margin-top: var(--s4); }
  .digest-card h3 { margin: 0 0 var(--s1); font-size: var(--t-lead); }
  .digest-card h3 a { color: inherit; text-decoration: none; }
  .digest-card h3 a:hover { color: var(--signal-ink); }
  table.digest { width: 100%; border-collapse: collapse; margin-top: var(--s2); }
  table.digest td { padding: var(--s2) var(--s2); border-top: 1px solid var(--line); font-size: var(--t-body); }
  table.digest td.dg-layer a { color: inherit; }
  table.digest td.dg-move { white-space: nowrap; font-weight: 600; font-variant-numeric: tabular-nums; }
  td.dg-move.up { color: var(--pass-ink); } td.dg-move.down { color: var(--fail-ink); }
  .digest-steady { color: var(--muted); font-size: var(--t-small); margin: var(--s2) 0 var(--s1); }


  @media print {
    /* Nobody prints a near-black page, and the status colours need a light
       field to read against, so force the light neutrals regardless of the
       visitor's theme. !important clears the dark selectors' higher specificity
       (:root:not([data-theme=light]) beats a bare :root). The status FILLS
       (--pass/--warn/--fail) are theme-independent and left untouched, so the
       verdict still prints in colour. */
    :root {
      --page: #fff !important; --surface: #fff !important; --ink: #111 !important;
      --muted: #4a4f48 !important; --line: #1111112e !important; --rule: #111 !important;
      --leaf-ink: #2f6b3c !important; --signal-ink: #cc1b10 !important;
      --pass-ink: #2f6b3c !important; --warn-ink: #7a5a12 !important; --fail-ink: #a8412a !important;
    }
    html, body { background: #fff; color: #111; }
    /* App chrome belongs to the operator at the screen, not the client holding
       the PDF. The brand header, the report, its history and any regression
       banner stay; the tagline and every operator-facing tail come off. */
    .tagline, .examples, .next-steps, .embed, .api-hint,
    .snap-banner, .set-nav { display: none !important; }
    /* The grade letter and every status fill carry the verdict — print them in
       colour instead of letting the printer economise them to grey. */
    .grade, .health-strip, .health-strip a, .pill, .badge,
    .g-good, .g-mid, .g-bad {
      -webkit-print-color-adjust: exact; print-color-adjust: exact;
    }
    /* Don't guillotine a check, a site block or a verdict across a page break. */
    .report, .check, .rpt-site, .verdict, .change { break-inside: avoid; }
    a { color: inherit; text-decoration: none; }
    @page { margin: 1.6cm; }
  }
