/* ==================================================================
   Peptide Corpus — document pages (evidence, rubric, glossary, policy)

   Pairs with scripts/lib/layout.mjs, which is the only place the head,
   nav and footer are defined. This file styles the shared chrome plus
   the document body. Every colour is a semantic alias from
   /assets/tokens/colors.css — no raw ramp values, no hex.
   ================================================================== */

* { box-sizing: border-box; }
[hidden] { display: none !important; }

/* Paint in the system stack immediately rather than waiting on a webfont. --font-sans names Inter
   first and falls through to the same stack, so the page is correct either way. */
html { font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; scroll-behavior: smooth; }
body { margin: 0; font-family: var(--font-sans); background: var(--bg); color: var(--text); overflow-x: hidden; line-height: 1.6; }
svg { display: block; }
h1, h2, h3, h4, p, ul, ol, figure, dl, dd, table { margin: 0; }
ul, ol { padding: 0; list-style: none; }
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
code, .mono { font-family: var(--font-mono); font-size: .9em; font-variant-numeric: tabular-nums; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

.wrap { width: 100%; max-width: 1160px; margin: 0 auto; padding: 0 clamp(18px, 4vw, 36px); }
.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; }
.skip { position: absolute; left: var(--space-3, 12px); top: -60px; z-index: 100; padding: 12px 16px;
  background: var(--surface); color: var(--text); border: 1px solid var(--border); border-radius: var(--radius-sm, 8px); }
.skip:focus { top: 12px; }

/* ── Header ───────────────────────────────────────────────────────── */
.site-head { position: sticky; top: 0; z-index: 40; background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(10px); border-bottom: 1px solid var(--border-subtle); }
.head-in { display: flex; align-items: center; gap: clamp(14px, 3vw, 30px); height: 62px; }
.brand { display: inline-flex; align-items: center; gap: 9px; color: var(--text); flex: none; }
.brand:hover { text-decoration: none; }
.brand-mark { width: 25px; height: 25px; }
.mark-bg { fill: var(--accent); }
.mark-tri { fill: none; stroke: var(--on-accent); stroke-width: 8; stroke-linejoin: round; stroke-linecap: round; }
.brand-word { font-size: 13px; font-weight: 800; letter-spacing: .085em; }
.brand-word b { color: var(--accent); font-weight: 800; }
.nav-links { display: flex; gap: clamp(10px, 2vw, 22px); flex: 1; }
.nav-links a { font-size: 14.5px; font-weight: 600; color: var(--text-muted); white-space: nowrap; }
.nav-links a:hover { color: var(--text); text-decoration: none; }
.nav-links a[aria-current="page"] { color: var(--accent); }
.nav-actions { display: flex; align-items: center; gap: 10px; flex: none; }
.icon-btn { display: grid; place-items: center; width: 34px; height: 34px; padding: 0; border: 1px solid var(--border);
  border-radius: var(--radius-sm, 8px); background: var(--surface); color: var(--text-muted); cursor: pointer; font-family: inherit; }
.icon-btn:hover { color: var(--text); border-color: var(--border-strong); }
.icon-btn svg { width: 16px; height: 16px; }
.ico-sun { display: none; }
[data-theme="dark"] .ico-moon { display: none; }
[data-theme="dark"] .ico-sun { display: block; }
.btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px; padding: 9px 16px; border-radius: var(--radius-sm, 8px);
  font-family: inherit; font-size: 14px; font-weight: 700; border: 1px solid transparent; cursor: pointer; white-space: nowrap; }
.btn:hover { text-decoration: none; }
.btn-primary { background: var(--accent); color: var(--on-accent); }
.btn-primary:hover { background: var(--accent-hover); }
.btn-sm { padding: 7px 13px; font-size: 13.5px; }
@media (max-width: 860px) {
  .nav-links { display: none; }
  .head-in { justify-content: space-between; }
}

/* ── Document body ────────────────────────────────────────────────── */
.doc { max-width: 860px; padding-top: clamp(26px, 5vw, 48px); padding-bottom: clamp(52px, 8vw, 96px); }
.doc h1 { font-size: clamp(28px, 4.6vw, 42px); line-height: 1.1; font-weight: 800; letter-spacing: -.025em; text-wrap: balance; margin-bottom: 14px; }
.doc h2 { font-size: clamp(20px, 2.6vw, 25px); font-weight: 800; letter-spacing: -.015em; margin: 46px 0 12px; text-wrap: balance; scroll-margin-top: 78px; }
.doc h3 { font-size: 19px; font-weight: 750; margin: 4px 0 8px; letter-spacing: -.01em; }
.doc h4 { font-size: 12px; font-weight: 800; text-transform: uppercase; letter-spacing: .07em; color: var(--text-muted); margin-bottom: 8px; }
.doc p { margin-bottom: 14px; max-width: 72ch; }
.doc p:last-child { margin-bottom: 0; }
.doc strong { font-weight: 700; }
.doc em { font-style: italic; }

.eyebrow { margin-bottom: 8px !important; }
.lede { font-size: clamp(16.5px, 2vw, 19px); color: var(--text-muted); line-height: 1.55; max-width: 66ch; }
.reviewed { font-size: 13px; color: var(--text-muted); margin-top: 16px !important; padding-top: 14px; border-top: 1px solid var(--border-subtle); }
.rv-label { font-weight: 700; color: var(--text); }

.crumbs { margin-bottom: 18px; font-size: 13px; }
.crumbs ol { display: flex; flex-wrap: wrap; gap: 7px; }
.crumbs li + li::before { content: "/"; color: var(--text-subtle); margin-right: 7px; }
.crumbs a { color: var(--text-muted); }
.crumbs li[aria-current] { color: var(--text-subtle); }

/* ── Table of contents ────────────────────────────────────────────── */
.toc { margin: 26px 0 6px; padding: 18px 20px; background: var(--surface-subtle); border: 1px solid var(--border-subtle); border-radius: var(--radius-md, 12px); }
.toc h2 { margin: 0 0 10px; font-size: 12px; text-transform: uppercase; letter-spacing: .07em; color: var(--text-muted); font-weight: 800; }
.toc ol { counter-reset: toc; display: grid; gap: 6px; }
.toc li { counter-increment: toc; font-size: 14.5px; }
.toc li::before { content: counter(toc) "."; color: var(--text-subtle); font-family: var(--font-mono); font-size: 12px; margin-right: 8px; }

/* ── The ladder ───────────────────────────────────────────────────── */
.ladder { display: grid; gap: 8px; margin: 26px 0; counter-reset: none; }
.step-link { display: grid; grid-template-columns: 42px 1fr auto; align-items: center; gap: 14px; padding: 14px 16px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-md, 12px); color: var(--text); }
.step-link:hover { text-decoration: none; border-color: var(--accent); background: var(--selected-tint); }
.step-n { display: grid; place-items: center; width: 30px; height: 30px; border-radius: 50%; background: var(--accent-soft);
  color: var(--accent); font-family: var(--font-mono); font-weight: 700; font-size: 14px; }
.step-body { display: grid; gap: 2px; min-width: 0; }
.step-name { font-weight: 700; font-size: 16px; }
.step-short { font-size: 13.5px; color: var(--text-muted); }
.step-code { font-family: var(--font-mono); font-size: 11.5px; color: var(--text-subtle); white-space: nowrap; }
/* Rung strength renders as WEIGHT, not hue — colour stays free to mean category elsewhere, and a
   colour-blind reader loses nothing. Rung 1 is solid; rung 7 is nearly transparent. */
.ladder-step:nth-child(1) .step-n { background: var(--accent); color: var(--on-accent); }
.ladder-step:nth-child(2) .step-n { background: color-mix(in srgb, var(--accent) 72%, var(--surface)); color: var(--on-accent); }
.ladder-step:nth-child(3) .step-n { background: color-mix(in srgb, var(--accent) 52%, var(--surface)); color: var(--on-accent); }
.ladder-step:nth-child(4) .step-n { background: color-mix(in srgb, var(--accent) 34%, var(--surface)); }
.ladder-step:nth-child(5) .step-n { background: color-mix(in srgb, var(--accent) 22%, var(--surface)); }
.ladder-step:nth-child(6) .step-n { background: color-mix(in srgb, var(--accent) 14%, var(--surface)); }
.ladder-step:nth-child(7) .step-n { background: color-mix(in srgb, var(--accent) 8%, var(--surface)); }
@media (max-width: 560px) { .step-code { display: none; } .step-link { grid-template-columns: 34px 1fr; } }

/* ── Tier badge — always a link to the rubric ─────────────────────── */
.tier-badge { display: inline-flex; align-items: center; padding: 3px 10px; border-radius: var(--radius-pill, 999px);
  background: var(--accent-soft); color: var(--text-on-soft); border: 1px solid var(--accent-soft-border);
  font-size: 12px; font-weight: 700; white-space: nowrap; }
.tier-badge:hover { text-decoration: none; border-color: var(--accent); }

/* THE RUNG, VISIBLE AT A GLANCE.
   Every badge used to be the same violet: a human RCT and a computational prediction were
   indistinguishable until you read them. On an index of 196 rows that makes the ladder — the whole
   product — invisible while scanning.

   ONE HUE, VARYING WEIGHT, deliberately. The obvious move is green/amber/red, and it is wrong here:
   that ramp reads as safe/caution/danger, and a computational rung is not DANGEROUS, it is weakly
   evidenced. Those are different claims and only one of them is ours to make. Filled → outlined →
   dashed encodes position on the ladder and nothing else, and dashed at the bottom borrows the same
   grammar the gap chips use for "barely there".

   Colour is never the only signal: the label text is always present, so this degrades to plain
   badges under forced-colours or for anyone who cannot separate the steps. */
.tier-badge.tier-human_rct { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.tier-badge.tier-human_rct:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
.tier-badge.tier-human_observational { background: var(--accent-soft); color: var(--text-on-soft); border-color: var(--accent); }
.tier-badge.tier-human_case_series { background: var(--accent-soft); color: var(--text-on-soft); border-color: var(--accent-soft-border); }
.tier-badge.tier-animal_in_vivo { background: var(--surface); color: var(--text-muted); border-color: var(--border-strong); }
.tier-badge.tier-in_vitro { background: var(--surface); color: var(--text-muted); border-color: var(--border); }
.tier-badge.tier-theoretical,
.tier-badge.tier-computational { background: transparent; color: var(--text-muted);
  border-style: dashed; border-color: var(--border-strong); font-weight: 600; }

/* "Not graded" is an absence, and reads as one: dashed and italic, the same grammar as a declared
   gap rather than a quieter version of a value. */
.tier-none { display: inline-flex; align-items: center; padding: 3px 10px;
  border-radius: var(--radius-pill, 999px); border: 1px dashed var(--border-strong);
  font-size: 12px; font-style: italic; color: var(--text-muted); white-space: nowrap; }

/* ── Rung sections ────────────────────────────────────────────────── */
.rung { margin: 34px 0; padding: 22px 24px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-md, 12px); scroll-margin-top: 78px; }
.rung-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 10px; }
.rung-n { font-size: 11.5px; font-weight: 800; text-transform: uppercase; letter-spacing: .07em; color: var(--text-muted); }
.rung-code { color: var(--text-subtle); font-size: 11.5px; }
.rung-def { font-size: 16px; color: var(--text-muted); }
.rung-eg { font-size: 14px; color: var(--text-muted); padding-top: 12px; border-top: 1px solid var(--border-subtle); margin-top: 16px !important; }
.eg-label { font-size: 11px; font-weight: 800; text-transform: uppercase; letter-spacing: .06em; color: var(--text-subtle); margin-right: 7px; }

.crit { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin: 18px 0; }
@media (max-width: 700px) { .crit { grid-template-columns: 1fr; } }
.crit-col { padding: 15px 17px; border-radius: var(--radius-sm, 8px); border: 1px solid var(--border-subtle); }
.crit-yes { background: var(--success-soft); border-color: color-mix(in srgb, var(--success) 26%, transparent); }
.crit-no  { background: var(--danger-soft);  border-color: color-mix(in srgb, var(--danger) 26%, transparent); }
.crit-yes h4, .crit-yes h2 { color: var(--success); }
.crit-no h4,  .crit-no h2  { color: var(--danger); }
.crit-col h2 { margin: 0 0 10px; font-size: 12px; text-transform: uppercase; letter-spacing: .07em; font-weight: 800; }
.crit-col ul { display: grid; gap: 8px; }
.crit-col li { font-size: 14.5px; line-height: 1.5; padding-left: 18px; position: relative; }
/* Text markers, not icons and never emoji — they survive copy-paste and screen readers read them. */
.crit-yes li::before { content: "+"; position: absolute; left: 0; color: var(--success); font-weight: 800; }
.crit-no li::before  { content: "\2212"; position: absolute; left: 0; color: var(--danger); font-weight: 800; }

.not-licensed { margin: 18px 0; padding: 16px 18px; border-radius: var(--radius-sm, 8px);
  background: var(--warning-soft); border-left: 3px solid var(--warning); }
.not-licensed h2, .not-licensed h4 { color: var(--warning); margin: 0 0 8px; font-size: 12px; text-transform: uppercase; letter-spacing: .07em; font-weight: 800; }
.not-licensed p { font-size: 14.5px; margin: 0; }

/* ── Policy sections ──────────────────────────────────────────────── */
.policy { scroll-margin-top: 78px; }
.policy ul { display: grid; gap: 9px; margin: 12px 0 16px; max-width: 72ch; }
.policy li { padding-left: 20px; position: relative; font-size: 15px; line-height: 1.55; }
.policy li::before { content: ""; position: absolute; left: 4px; top: .62em; width: 5px; height: 5px; border-radius: 50%; background: var(--accent); }

.callout { margin: 26px 0; padding: 20px 22px; background: var(--accent-soft); border-left: 3px solid var(--accent); border-radius: var(--radius-md, 12px); }
.callout h2 { margin: 0 0 8px; font-size: 17px; }
.callout p { font-size: 15px; margin: 0; }

.link-list { display: grid; gap: 8px; margin: 14px 0; }
.link-list a { display: block; padding: 13px 16px; background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-sm, 8px); color: var(--text); font-size: 14.5px; }
.link-list a:hover { text-decoration: none; border-color: var(--accent); background: var(--selected-tint); }
.link-list b { color: var(--accent); }

.pending { font-size: 14.5px; color: var(--text-muted); padding: 15px 17px; background: var(--surface-sunken);
  border: 1px dashed var(--border-strong); border-radius: var(--radius-sm, 8px); }

/* ── Rung prev/next ───────────────────────────────────────────────── */
.rung-nav { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin: 34px 0 22px; }
@media (max-width: 560px) { .rung-nav { grid-template-columns: 1fr; } }
.rung-nav a { display: grid; gap: 3px; padding: 14px 16px; background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-sm, 8px); color: var(--text); }
.rung-nav a:hover { text-decoration: none; border-color: var(--accent); }
.rung-nav span { font-size: 11.5px; text-transform: uppercase; letter-spacing: .06em; color: var(--text-muted); font-weight: 700; }
.rung-nav b { font-size: 15.5px; }
.rn-next { text-align: right; }
.rn-none { display: grid; place-items: center; padding: 14px 16px; font-size: 13.5px; color: var(--text-muted);
  border: 1px dashed var(--border); border-radius: var(--radius-sm, 8px); }
.back-rubric { font-size: 14.5px; }

/* ── Tables ───────────────────────────────────────────────────────── */
.doc table { width: 100%; border-collapse: collapse; font-size: 14.5px; }
.doc th, .doc td { text-align: left; padding: 11px 13px; border-bottom: 1px solid var(--border-subtle); vertical-align: top; }
.doc th { background: var(--surface-subtle); font-size: 11.5px; text-transform: uppercase; letter-spacing: .05em; color: var(--text-muted); font-weight: 800; white-space: nowrap; }
.rev { margin-top: 14px; border: 1px solid var(--border); border-radius: var(--radius-md, 12px); overflow: hidden; }

/* ── Footer ───────────────────────────────────────────────────────── */
.site-foot { border-top: 1px solid var(--border); padding: 34px 0 44px; background: var(--surface-subtle); }
.foot-disc { max-width: 68ch; font-size: 13.5px; color: var(--text-muted); margin-bottom: 18px; }
.foot-links { display: flex; flex-wrap: wrap; gap: 8px 20px; }
.foot-links a { font-size: 13.5px; color: var(--text-muted); }
.foot-links a:hover { color: var(--text); }

/* ==================================================================
   Glossary
   ================================================================== */

/* A–Z jump bar. Only letters that HAVE terms are rendered — the competitor
   prints dead unlinked J/K/Q/U/W/X/Y/Z, which reads as an unfinished list. */
.azbar { display: flex; flex-wrap: wrap; gap: 6px; margin: 22px 0 8px; padding: 12px 14px;
  background: var(--surface-subtle); border: 1px solid var(--border-subtle); border-radius: var(--radius-md, 12px); }
.azbar a { display: grid; place-items: center; min-width: 30px; height: 30px; padding: 0 7px;
  border-radius: var(--radius-sm, 8px); font-family: var(--font-mono); font-size: 13px; font-weight: 700;
  color: var(--text-muted); background: var(--surface); border: 1px solid var(--border); }
.azbar a:hover { text-decoration: none; color: var(--on-accent); background: var(--accent); border-color: var(--accent); }

.az { margin-top: 30px; scroll-margin-top: 78px; }
.az h2 { margin: 0 0 10px; font-family: var(--font-mono); font-size: 20px; color: var(--accent);
  border-bottom: 1px solid var(--border); padding-bottom: 6px; }
.term-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 7px; }
.term-grid a { display: grid; gap: 1px; padding: 10px 12px; border: 1px solid var(--border);
  border-radius: var(--radius-sm, 8px); background: var(--surface); color: var(--text); }
.term-grid a:hover { text-decoration: none; border-color: var(--accent); background: var(--selected-tint); }
.term-grid b { font-size: 14.5px; font-weight: 650; }
.term-grid span { font-size: 11.5px; color: var(--text-subtle); }

/* Domain tree — the parent/child structure rendered AS a tree, not flattened. */
.tree { display: grid; gap: 8px; margin: 18px 0; }
.tree > li > a { display: inline-block; padding: 9px 13px; border: 1px solid var(--border);
  border-radius: var(--radius-sm, 8px); background: var(--surface); color: var(--text); }
.tree > li > a:hover { text-decoration: none; border-color: var(--accent); }
.tree ul { display: flex; flex-wrap: wrap; gap: 6px; margin: 7px 0 0 20px; padding-left: 14px;
  border-left: 2px solid var(--border); }
.tree ul a { display: inline-block; padding: 5px 10px; font-size: 13.5px; color: var(--text-muted);
  background: var(--surface-subtle); border-radius: var(--radius-pill, 999px); }
.tree ul a:hover { text-decoration: none; color: var(--text); }

/* The definition is the first thing on the page and is sized to be read, not skimmed. */
.definition { font-size: clamp(17px, 2.1vw, 19.5px); line-height: 1.6; color: var(--text);
  padding: 18px 20px; background: var(--surface); border-left: 3px solid var(--accent);
  border-radius: var(--radius-md, 12px); max-width: none !important; }

/* "What it is not" — the field that carries the product. Given the warning treatment on purpose:
   it is the most useful thing on the page and should not read as a footnote. */
.not-this { margin: 24px 0; padding: 18px 20px; border-radius: var(--radius-md, 12px);
  background: var(--warning-soft); border-left: 3px solid var(--warning); }
.not-this h2 { margin: 0 0 8px !important; font-size: 12px; text-transform: uppercase;
  letter-spacing: .07em; color: var(--warning); font-weight: 800; }
.not-this p { font-size: 15.5px; margin: 0; }

.alias-list { display: flex; flex-wrap: wrap; gap: 6px; margin: 12px 0; }
.alias-list li { padding: 5px 11px; background: var(--surface-sunken); border: 1px solid var(--border-subtle);
  border-radius: var(--radius-pill, 999px); font-family: var(--font-mono); font-size: 12.5px; color: var(--text-muted); }
.alias-note { font-size: 13.5px; color: var(--text-muted); }

.rels { display: grid; gap: 10px; margin: 14px 0; }
.rel { display: grid; grid-template-columns: 150px 1fr; gap: 12px; padding: 11px 14px;
  background: var(--surface-subtle); border-radius: var(--radius-sm, 8px); }
.rel dt { font-size: 12px; text-transform: uppercase; letter-spacing: .06em; color: var(--text-muted); font-weight: 800; }
.rel dd { margin: 0; font-size: 14.5px; }
@media (max-width: 560px) { .rel { grid-template-columns: 1fr; gap: 4px; } }

/* An indexed compound with no record. Rendered as plain text, never as a dead link — a link that
   goes nowhere is worse than an honest statement that there is nowhere to go. */
.no-page { display: block; padding: 13px 16px; background: var(--surface-sunken);
  border: 1px dashed var(--border-strong); border-radius: var(--radius-sm, 8px);
  font-size: 14.5px; color: var(--text-muted); }
.no-page b { color: var(--text); }

/* ==================================================================
   Peptide records
   ================================================================== */
.statbar { display: grid; grid-template-columns: repeat(auto-fit, minmax(112px, 1fr)); gap: 8px; margin: 16px 0; }
.statbar div { padding: 11px 14px; background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-md, 12px); text-align: center; }
.statbar b { display: block; font-size: 22px; font-weight: 800; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.statbar span { display: block; margin-top: 2px; font-size: 12px; color: var(--text-muted); }

.tbl-scroll { overflow-x: auto; margin: 16px 0; border: 1px solid var(--border); border-radius: var(--radius-md, 12px); }
.tbl-scroll:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.ptable { min-width: 720px; }
.ptable th[scope="row"] { font-weight: 650; }
.ptable th[scope="row"] a { color: var(--text); }
.ptable th[scope="row"] a:hover { color: var(--accent); }
.fda-yes { color: var(--success); font-weight: 700; font-size: 13px; }

/* Record header: the four numbers a reader wants before reading prose. */
.rec-head { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; margin: 22px 0 8px; }
.rh-item { padding: 13px 15px; background: var(--surface-subtle); border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sm, 8px); }
.rh-item span:first-child { display: block; font-size: 11.5px; text-transform: uppercase;
  letter-spacing: .06em; color: var(--text-muted); font-weight: 800; margin-bottom: 6px; }
.rh-item b { font-size: 17px; font-weight: 700; }
.tier-why { font-size: 14px; color: var(--text-muted); }

.fda { margin: 14px 0; padding: 16px 18px; background: var(--success-soft);
  border-left: 3px solid var(--success); border-radius: var(--radius-md, 12px); }
.fda p { font-size: 15px; }
.fda-note, .uv-note { font-size: 13.5px; color: var(--text-muted); margin-bottom: 0 !important; }

/* Anything carried from a source that labels itself unverified keeps the label attached. */
.unverified { margin: 14px 0; padding: 15px 17px; background: var(--warning-soft);
  border-left: 3px solid var(--warning); border-radius: var(--radius-md, 12px); }
.uv-label { font-size: 11.5px; text-transform: uppercase; letter-spacing: .07em; font-weight: 800;
  color: var(--warning); margin-bottom: 6px !important; }
.muted-note { font-size: 13.5px; color: var(--text-muted); }

.chip-list { display: flex; flex-wrap: wrap; gap: 6px; margin: 12px 0; }
.chip-list li { padding: 5px 12px; background: var(--surface-sunken); border: 1px solid var(--border-subtle);
  border-radius: var(--radius-pill, 999px); font-size: 13px; color: var(--text-muted); }
.chip-list li a { color: var(--text-muted); }
.chip-list li a:hover { color: var(--accent); text-decoration: none; }

/* Citations render as real anchors to PubMed and DOI. The competitor's profile carries 14 JSON-LD
   blocks and zero <a> tags pointing at either — machine-facing citations only. */
.cites { display: grid; gap: 8px; margin: 14px 0; }
.cites li { display: grid; grid-template-columns: auto 1fr; gap: 12px; align-items: start;
  padding: 12px 14px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-sm, 8px); }
.cite-body { min-width: 0; }
.cite-body a { font-size: 14.5px; overflow-wrap: anywhere; }
.cite-basis { display: block; margin-top: 4px; font-size: 12px; color: var(--text-muted); font-family: var(--font-mono); }
@media (max-width: 560px) { .cites li { grid-template-columns: 1fr; gap: 7px; } }

/* The gap ledger. Given real weight on the page — it is the most distinctive thing we publish. */
.gaps { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 7px; margin: 14px 0; }
.gaps li { display: grid; gap: 2px; padding: 11px 14px; background: var(--surface-sunken);
  border: 1px dashed var(--border-strong); border-radius: var(--radius-sm, 8px); }
.gaps b { font-size: 14px; font-weight: 650; }
.gaps span { font-size: 12.5px; color: var(--text-muted); }

/* ==================================================================
   Record layout — a DATA surface, not a document

   doc.css began as a document stylesheet: one 860px reading column,
   headings, paragraphs. Correct for the rubric and the glossary, which
   genuinely are documents. Wrong for a peptide record, which a reader
   scans for a fact rather than reading top to bottom. This block ports
   the composition from the product mockup: content plus a sticky rail,
   with each section as a card that can be found at a glance.
   ================================================================== */
.rec { max-width: 1160px; padding-top: clamp(22px, 4vw, 40px); padding-bottom: clamp(52px, 8vw, 96px);
  display: grid; grid-template-columns: minmax(0, 1fr) 296px; grid-template-rows: auto 1fr;
  gap: 0 34px; align-items: start; }
.rec-top { grid-column: 1 / -1; margin-bottom: 22px; }
.rec-top h1 { font-size: clamp(30px, 4.4vw, 44px); line-height: 1.06; font-weight: 800;
  letter-spacing: -.03em; text-wrap: balance; margin-bottom: 10px; }
.rec-top .lede { font-size: clamp(16px, 1.9vw, 18.5px); }
.rec-top .reviewed { margin-top: 14px !important; }
.rec-main { display: grid; gap: 14px; min-width: 0; }
.rec-rail { position: sticky; top: 78px; display: grid; gap: 12px; }
@media (max-width: 1000px) {
  .rec { grid-template-columns: minmax(0, 1fr); }
  /* Natural order on a narrow screen: title and crumbs first, then the record, then the rail
     facts. order:-1 used to hoist the rail ABOVE the h1, so a phone visitor met two stat cards
     before learning what page they were on — the operator called it out from a live phone. */
  .rec-rail { position: static; margin-top: 6px; }
  .rail-nav { display: none; }
}

/* ── Cards ─────────────────────────────────────────────────────────── */
.card { padding: 20px 22px; background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-md, 12px); scroll-margin-top: 78px; }
.card > h2 { margin: 0 0 12px; font-size: 17px; font-weight: 750; letter-spacing: -.01em;
  display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.card > h3 { margin: 18px 0 8px; font-size: 14px; font-weight: 700; }
.card p:last-child { margin-bottom: 0; }
.card-good { border-left: 3px solid var(--success); }
.card-warn { border-left: 3px solid var(--warning); }
.card-gap  { border-left: 3px solid var(--accent-2); }
.lead-fact { font-size: 16.5px; line-height: 1.5; }

.tag-warn { font-size: 10.5px; font-weight: 800; text-transform: uppercase; letter-spacing: .07em;
  padding: 3px 8px; border-radius: var(--radius-pill, 999px); background: var(--warning-soft); color: var(--warning); }
.tag-count { font-family: var(--font-mono); font-size: 11.5px; font-weight: 700; padding: 2px 8px;
  border-radius: var(--radius-pill, 999px); background: var(--surface-sunken); color: var(--text-muted); }

/* ── Rail ──────────────────────────────────────────────────────────── */
.rail-card { padding: 16px 18px; background: var(--surface-subtle); border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md, 12px); }
.rail-card h2 { margin: 0 0 11px; font-size: 11.5px; text-transform: uppercase; letter-spacing: .07em;
  color: var(--text-muted); font-weight: 800; }
.rail-facts { display: grid; gap: 9px; }
.rail-facts > div { display: grid; grid-template-columns: 1fr auto; gap: 10px; align-items: baseline;
  padding-bottom: 9px; border-bottom: 1px solid var(--border-subtle); }
.rail-facts > div:last-child { border-bottom: 0; padding-bottom: 0; }
.rail-facts dt { font-size: 12.5px; color: var(--text-muted); }
.rail-facts dd { margin: 0; font-size: 13.5px; font-weight: 650; text-align: right; }
.rail-nav ol { counter-reset: rn; display: grid; gap: 3px; }
.rail-nav li { counter-increment: rn; }
.rail-nav a { display: block; padding: 5px 8px; border-radius: var(--radius-sm, 8px);
  font-size: 13.5px; color: var(--text-muted); }
.rail-nav a:hover { text-decoration: none; color: var(--text); background: var(--surface); }
.rail-nav a::before { content: counter(rn) "."; font-family: var(--font-mono); font-size: 11px;
  color: var(--text-subtle); margin-right: 7px; }
.rail-note { margin: 9px 0 0 !important; font-size: 11.5px; color: var(--text-subtle); }

/* Citations by rung. A bar chart, because "4 RCTs and 1 animal study" is a shape, not a list —
   and the shape is the honest summary a single badge cannot give. */
.rung-bars { display: grid; gap: 7px; }
.rung-bars li { display: grid; grid-template-columns: 1fr 56px 18px; gap: 8px; align-items: center; }
.rung-bars a { font-size: 12px; color: var(--text-muted); }
.rung-bars a:hover { color: var(--accent); text-decoration: none; }
.rung-bars .bar { height: 6px; border-radius: 3px; background: var(--surface-sunken); overflow: hidden; }
.rung-bars .bar i { display: block; height: 100%; background: var(--accent); border-radius: 3px; }
.rung-bars b { font-family: var(--font-mono); font-size: 12px; text-align: right; }

/* Inside a card the shared blocks need to sit flush rather than re-introducing their own margins. */
.card .tbl-scroll { margin: 0 0 10px; }
.card .chip-list, .card .alias-list { margin: 0; }
.card .gaps { margin: 12px 0 0; }
.card .rels { margin: 0; }
.card .cites { margin: 0; }
.card .not-licensed { margin: 16px 0 0; }
.tier-why { font-size: 13.5px; color: var(--text-muted); margin-bottom: 14px; }

/* ==================================================================
   Calculators
   The server renders a real answer into .calc-result; the JS replaces
   it as you type. If the JS never runs the page still answers.
   ================================================================== */
.calc { margin: 22px 0; padding: 20px 22px; background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-md, 12px); }
.modes { margin: 0 0 16px; padding: 0; border: 0; display: grid; gap: 6px; }
.modes legend { padding: 0; font-size: 11.5px; text-transform: uppercase; letter-spacing: .07em;
  color: var(--text-muted); font-weight: 800; margin-bottom: 8px; }
.modes label { display: flex; align-items: center; gap: 9px; font-size: 14.5px; cursor: pointer;
  padding: 8px 11px; border-radius: var(--radius-sm, 8px); border: 1px solid var(--border-subtle);
  background: var(--surface-subtle); }
.modes label:hover { border-color: var(--border-strong); }
.modes input { accent-color: var(--accent); flex: none; }

.calc-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 12px; }
/* Every column shares one skeleton — caption row, control row, quick-pick row — pinned to the same
   heights, so three fields with different furniture ("optional", a unit select, five picks against
   six) still sit level. The "optional" tag is lifted out of flow to the caption's right edge, where
   it stops minting a row of its own and pushing that column's control down. */
.calc-grid label { display: grid; gap: 5px; grid-template-rows: 18px minmax(46px, auto) auto;
  align-content: start; position: relative; font-size: 12.5px; font-weight: 700; color: var(--text-muted); }
.calc-grid .opt { position: absolute; top: 1px; right: 0; font-weight: 500;
  color: var(--text-muted); text-transform: none; font-size: 11.5px; }
.in { display: flex; align-items: stretch; min-height: 46px; border: 1px solid var(--border); border-radius: var(--radius-sm, 8px);
  background: var(--bg); overflow: hidden; }
.in:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--focus-ring); }
.in input, .in select { flex: 1; min-width: 0; padding: 10px 12px; border: 0; background: transparent;
  color: var(--text); font-family: var(--font-mono); font-size: 15px; font-variant-numeric: tabular-nums; }
.in input:focus, .in select:focus { outline: none; }
.in select { font-family: var(--font-sans); font-size: 14px; }
.unit { display: grid; place-items: center; padding: 0 12px; background: var(--surface-sunken);
  border-left: 1px solid var(--border); font-family: var(--font-mono); font-size: 12.5px; color: var(--text-muted); }

.calc-result { margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--border-subtle); }
.calc-out { width: 100%; border-collapse: collapse; }
.calc-out th { background: transparent; text-transform: none; letter-spacing: 0; font-size: 13.5px;
  font-weight: 600; color: var(--text-muted); padding: 7px 0; border: 0; white-space: normal; }
.calc-out td { padding: 7px 0 7px 14px; border: 0; font-size: 16px; font-weight: 700; }
.calc-out td.muted { font-size: 13px; font-weight: 500; color: var(--text-subtle); }
.calc-warn { margin: 10px 0 0; padding: 10px 13px; background: var(--warning-soft); color: var(--warning);
  border-radius: var(--radius-sm, 8px); font-size: 13.5px; font-weight: 600; }

/* The formula, with the numbers substituted. A result you cannot check is an assertion. */
.working { margin: 12px 0; padding: 15px 17px; background: var(--surface-sunken); border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sm, 8px); font-family: var(--font-mono); font-size: 13.5px; line-height: 1.75;
  white-space: pre-wrap; overflow-x: auto; color: var(--text); }

/* The number the reader acts on, given the weight it deserves. Competitors lead with "draw to
   15.0 units" and demote concentration; ours led with concentration, which nobody acts on. */
.hero-num { display: flex; align-items: baseline; gap: 9px; flex-wrap: wrap; margin: 0 0 14px !important;
  padding-bottom: 14px; border-bottom: 1px solid var(--border-subtle); }
.hero-num b { font-family: var(--font-mono); font-size: clamp(34px, 6vw, 46px); font-weight: 700;
  line-height: 1; letter-spacing: -.03em; color: var(--accent); font-variant-numeric: tabular-nums; }
.hero-num span { font-size: 17px; font-weight: 650; color: var(--text); }
.hero-num em { font-style: normal; font-size: 13px; color: var(--text-muted); margin-left: auto; }

.steps { counter-reset: st; display: grid; gap: 10px; margin: 14px 0 16px; padding: 0; max-width: 70ch; }
.steps li { counter-increment: st; position: relative; padding: 12px 15px 12px 46px; font-size: 15px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-sm, 8px); }
.steps li::before { content: counter(st); position: absolute; left: 14px; top: 12px;
  display: grid; place-items: center; width: 22px; height: 22px; border-radius: 50%;
  background: var(--accent-soft); color: var(--accent); font-family: var(--font-mono);
  font-size: 12px; font-weight: 700; }

/* Policy links sit under the section links, one step quieter — present and findable without
   competing with the nav they follow. */
.foot-legal { margin-top: 10px; }
/* --text-muted, NOT --text-subtle. design/tokens/colors.css measures subtle at 3.44:1 and says in
   the file that it is decoration only: "Nothing a reader needs may use it. Meaningful small print
   goes on --text-muted." These are the disclaimer, privacy and terms links on a health site, which
   is the definition of small print a reader needs. The one-step-quieter hierarchy comes from size. */
.foot-legal a { font-size: 12.5px; color: var(--text-muted); }
.foot-legal a:hover { color: var(--text); }

/* The reported dose translated to the syringe. Full width and left-aligned: it is read as three
   parallel facts about one dose, not as a centred data grid. Numbers are tabular so the low and
   high rows line up digit-for-digit — the comparison between them is the point of the table. */
.dose-draw { width: 100%; border-collapse: collapse; margin: 14px 0 10px; }
.dose-draw th, .dose-draw td { text-align: left; padding: 7px 10px 7px 0; font-size: 13.5px;
  border-bottom: 1px solid var(--border-subtle); }
.dose-draw thead th { font-size: 11px; letter-spacing: .05em; text-transform: uppercase;
  color: var(--text-subtle); font-weight: 700; padding-bottom: 5px; }
.dose-draw tbody th { font-weight: 600; color: var(--text); white-space: nowrap; }
.dose-draw td { font-variant-numeric: tabular-nums; color: var(--text-muted); }
.dose-draw tbody tr:last-child th, .dose-draw tbody tr:last-child td { border-bottom: 0; }

/* Category chips in the record index. The source is semicolon-delimited and 28 of 196 records carry
   two or three; as one string the longest ran 87 characters and wrapped to four lines, which set the
   height of every row around it. Chips wrap within the cell instead. */
.cat-chips { display: flex; flex-wrap: wrap; gap: 4px; margin: 0; padding: 0; list-style: none; }
.cat-chips li { padding: 2px 8px; border-radius: var(--radius-pill, 999px);
  background: var(--surface-sunken); border: 1px solid var(--border-subtle);
  font-size: 11.5px; line-height: 1.5; color: var(--text-muted); white-space: nowrap; }

/* Column proportions for the record index. Left to the browser, Compound took 413px for a word
   while Regulatory got 110px for a 50-character phrase and wrapped to five lines, setting the
   height of every row near it. table-layout:fixed makes the widths mean something. */
.ptable { table-layout: fixed; }
.ptable .col-name { width: 22%; }
.ptable .col-cat  { width: 30%; }
.ptable .col-rung { width: 17%; }
.ptable .col-cite { width: 9%; }
.ptable .col-reg  { width: 22%; }
.reg-note { display: block; margin-top: 1px; font-size: 11px; line-height: 1.4; color: var(--text-subtle); }

/* Wide tables break out of the prose column. .doc caps at 860px so paragraphs stay near 72ch,
   which is right for reading and wrong for a five-column table of 196 rows — it was squeezing
   Regulatory into 173px and wrapping every long status. The table now widens to the .wrap content
   box (1160px less 36px padding each side) and no further, so it stays aligned with the header
   above it. The calc collapses to 0 below ~1080px, so narrow screens are untouched. */
@media (min-width: 1080px) {
  .doc > .tbl-scroll { margin-inline: calc(-1 * min(114px, (100vw - 72px - 860px) / 2)); }
}

/* ── Record index: list view and card view, from ONE set of markup ─────────────────────────────
   The same <table> renders both. Cards are the table with rows turned into blocks and each cell
   labelled from its data-label. No second copy of 196 records to keep in sync with the filter
   chips, and nothing duplicated for a crawler to see twice.

   WHY BOTH. The table is right for comparison — scan 196 rungs in one pass. The card is right for
   understanding one record without opening it. And the card view surfaces something the table
   hides: 46 of 196 records carry a summary and 150 do not, so the difference between a curated
   record and a thin one becomes visible rather than buried. That is honest signal, not a defect,
   and the thin cards say what the record does hold rather than rendering blank. */

/* Summary is the card body. It has no place in the table, where it would blow the row height. */
.ptable .col-summary, .ptable .col-summary-h, .ptable .cell-summary { display: none; }

.viewtoggle { margin-top: 12px; }
.ptable .thin { color: var(--text-subtle); font-style: italic; }

.as-cards .ptable, .as-cards .ptable tbody { display: block; }
/* The list view's 720px min-width keeps seven columns legible inside the scroll container. A card
   grid brings its own widths, and inheriting that minimum pushed the whole page sideways on a
   phone once .as-cards removed the scroll container. */
.tbl-scroll.as-cards .ptable { min-width: 0; }
.as-cards .ptable thead, .as-cards .ptable colgroup { display: none; }
.tbl-scroll.as-cards { overflow: visible; border: 0; border-radius: 0; }
.as-cards .ptable tbody {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(272px, 1fr)); gap: 12px; }
.as-cards .ptable tr {
  display: flex; flex-direction: column; gap: 7px; padding: 15px 16px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-md, 12px); }
.as-cards .ptable tr:hover { border-color: var(--border-strong); }
.as-cards .ptable th[scope="row"] { font-size: 16px; font-weight: 700; padding: 0; border: 0; }
.as-cards .ptable td { padding: 0; border: 0; font-size: 13px; }
/* Label above value, so a card reads as a set of named facts rather than a wrapped table row. */
.as-cards .ptable td::before {
  content: attr(data-label); display: block; margin-bottom: 2px;
  font-size: 10px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
  color: var(--text-subtle); }
.as-cards .ptable .cell-summary { display: block; order: -1; font-size: 13.5px; color: var(--text-muted); }
.as-cards .ptable .cell-summary::before { content: none; }
.as-cards .ptable .col-summary-h { display: none; }
@media (max-width: 560px) { .as-cards .ptable tbody { grid-template-columns: 1fr; } }
/* A cell holding an em-dash is fine in a table, where the column gives it meaning. On a card it
   becomes "CATEGORY —", which is a label introducing nothing. Drop those in card view only. */
.as-cards .ptable td.is-empty { display: none; }

/* ── Calculator result panels ──────────────────────────────────────────────────────────────────
   Setup, the draw, then what it means for the vial. Three panels rather than one stacked column,
   so the number you act on is not buried under the arithmetic that produced it. Collapses to one
   column below 760px, where stacking is the right answer anyway. */
.cpanels { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 12px; margin-top: 4px; }
.cpanel { padding: 15px 16px; background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-md, 12px); }
.cpanel h3 { margin: 0 0 9px; font-size: 10.5px; font-weight: 800; letter-spacing: .07em;
  text-transform: uppercase; color: var(--text-subtle); }
/* The draw is the answer, so it spans wider when there is room and carries the barrel. */
.cpanel-hero { grid-column: span 2; }
@media (max-width: 760px) { .cpanel-hero { grid-column: auto; } }
.cpanel-num { display: flex; align-items: baseline; gap: 6px; }
.cpanel-num b { font-size: 30px; font-weight: 800; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.cpanel-num span { font-size: 14px; color: var(--text-muted); }
.cpanel-sub { margin-top: 1px; font-size: 12.5px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.cpanel-note { margin-top: 9px; font-size: 11.5px; color: var(--text-subtle); }
/* Per-graduation potency: what one mark on the barrel actually holds. */
.perunit { display: grid; gap: 5px; margin-top: 11px; padding-top: 10px; border-top: 1px solid var(--border-subtle); }
.perunit div { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; }
.perunit dt { font-size: 12px; color: var(--text-muted); }
.perunit dd { margin: 0; font-size: 13px; font-weight: 650; font-variant-numeric: tabular-nums; }
.cpanel .calc-out th { font-size: 12.5px; }
.cpanel .syr { margin: 10px 0 0; }

/* "Classified as" on a compound record. Was a bare chip list of term names; the glossary carries a
   whyItMatters sentence on all 128 terms and none of it reached the compound pages, which are the
   ones people actually land on. One sentence per term, so a taxonomy label explains itself where
   it is used rather than only where it is defined. */
.cls-terms { display: grid; gap: 13px; margin: 10px 0 4px; }
.cls-terms div { display: grid; gap: 3px; }
.cls-terms dt { display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px;
  font-size: 14.5px; font-weight: 650; }
.cls-domain { font-size: 10.5px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
  color: var(--text-muted); padding: 1px 7px; border: 1px solid var(--border-subtle);
  border-radius: var(--radius-pill, 999px); }
.cls-terms dd { margin: 0; font-size: 13.5px; line-height: 1.5; color: var(--text-muted); max-width: 68ch; }
/* "No sources yet" is a thinner claim than "not graded" and reads quieter, but it is still a
   reader-facing string, so it stays on --text-muted like everything else that is not decoration. */
.tier-nosource { border-style: dotted; }

/* The glossary's front door. 193 terms A-to-Z is a reference for someone who already knows the
   vocabulary; this block is for the reader who does not, and it is deliberately the first thing
   on the page rather than a footnote under the alphabet. */
.starthere { margin: 20px 0 30px; padding: 20px 22px; background: var(--accent-soft);
  border: 1px solid var(--accent-soft-border); border-radius: var(--radius-md, 12px); }
.starthere h2 { margin-top: 0; }
.starthere > p { max-width: 70ch; }
.starthere .link-list li { background: var(--surface); }
.starthere .muted-note a { font-weight: 600; }

/* The grade, as a strip rather than a paragraph. This was four lines of small grey prose sitting
   between the lede and the first card — the one thing a visitor came to check, styled like a
   disclaimer. Badge first, derivation beside it, the rubric link at the end. */
.tier-strip { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px;
  margin: 0 0 18px; padding: 11px 14px; background: var(--surface);
  border: 1px solid var(--border); border-left: 3px solid var(--accent);
  border-radius: var(--radius-md, 12px); font-size: 13.5px; }
.tier-strip-label { font-size: 10.5px; font-weight: 800; letter-spacing: .07em;
  text-transform: uppercase; color: var(--text-subtle); }
.tier-strip-basis { color: var(--text-muted); }
.tier-strip-why { margin-left: auto; font-size: 12.5px; white-space: nowrap; }
@media (max-width: 640px) { .tier-strip-why { margin-left: 0; } }

/* The ladder, actually shaped like one. The step number carries the same ramp as the tier badges
   on the index — filled at the top, dashed at the bottom — so the two surfaces read as one system.
   The right column is the live count of records grading at each rung, which turns the diagram from
   a legend into a statement about the corpus. "none yet" is rendered, not hidden: four empty rungs
   is information. */
.step-count { font-family: var(--font-mono, ui-monospace, monospace); font-size: 12px;
  color: var(--text-muted); white-space: nowrap; font-variant-numeric: tabular-nums; }
.ladder-step .step-n { border: 1px solid transparent; }
.step-human_rct .step-n { background: var(--accent); color: var(--on-accent); }
.step-human_observational .step-n { background: var(--accent-soft); color: var(--text-on-soft); border-color: var(--accent); }
.step-human_case_series .step-n { background: var(--accent-soft); color: var(--text-on-soft); }
.step-animal_in_vivo .step-n { background: var(--surface); color: var(--text-muted); border-color: var(--border-strong); }
.step-in_vitro .step-n { background: var(--surface); color: var(--text-muted); border-color: var(--border); }
.step-theoretical .step-n, .step-computational .step-n { background: transparent; color: var(--text-muted);
  border-style: dashed; border-color: var(--border-strong); }

/* Tool cards: the worked answer is the headline. */
.toolgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 12px; margin: 18px 0; }
.toolcard { display: flex; flex-direction: column; gap: 8px; padding: 17px 18px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-md, 12px);
  color: inherit; text-decoration: none; transition: border-color .12s, box-shadow .12s; }
.toolcard:hover { border-color: var(--accent); box-shadow: var(--shadow-sm); text-decoration: none; }
.toolcard h2 { margin: 0; font-size: 16px; }
.toolcard > p:last-child { margin: 0; font-size: 13px; color: var(--text-muted); }
.toolcard-eg { display: grid; gap: 1px; margin: 0; padding: 9px 12px; background: var(--surface-sunken);
  border-radius: var(--radius-sm, 8px); }
.toolcard-eg span { font-size: 11px; color: var(--text-muted); }
.toolcard-eg b { font-size: 14px; font-variant-numeric: tabular-nums; color: var(--accent-press, var(--accent)); }

/* ── Record cards, restructured ────────────────────────────────────────────────────────────────
   Order: category (colour-coded) on top, name, summary if the record has one, then the facts as
   an icon badge row. The "No summary on file" filler is dropped in card view — the category chips
   now own that top slot, and thinness is already legible from how little else the card carries. */

/* Search + toggle share the top row of the bar. */
.fb-top { display: flex; align-items: center; gap: 10px; flex-basis: 100%; }
.fb-search { flex: 1 1 auto; min-width: 0; padding: 9px 13px; font: inherit; font-size: 14px;
  color: var(--text); background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-pill, 999px); }
.fb-search:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 1px; border-color: var(--accent); }
.viewtoggle { margin-left: auto; }

/* Category hues. One per family; both chip tint and card edge derive from the same custom
   property, so the two can never disagree. Tokens only, so both themes hold. */
.cg-repair    { --cg: var(--success); }
.cg-metabolic { --cg: var(--warning); }
.cg-cognitive { --cg: var(--accent); }
.cg-immune    { --cg: var(--info); }
.cg-cardio    { --cg: var(--danger); }
.cg-longevity { --cg: var(--accent-2); }
.cg-hormonal  { --cg: color-mix(in srgb, var(--danger) 55%, var(--accent)); }
.cg-sleep     { --cg: color-mix(in srgb, var(--info) 55%, var(--accent)); }
.cg-growth    { --cg: color-mix(in srgb, var(--success) 55%, var(--info)); }
.cg-gut       { --cg: color-mix(in srgb, var(--warning) 55%, var(--success)); }
.cat-chips li.cg-none { border-style: dashed; font-style: italic; color: var(--text-muted); background: transparent; }
.cat-chips li[class*="cg-"]:not(.cg-none) {
  background: color-mix(in srgb, var(--cg) 12%, var(--surface));
  border-color: color-mix(in srgb, var(--cg) 32%, transparent);
  color: color-mix(in srgb, var(--cg) 58%, var(--text)); font-weight: 600; }

tr[data-catgroup="repair"]    { --cg: var(--success); }
tr[data-catgroup="metabolic"] { --cg: var(--warning); }
tr[data-catgroup="cognitive"] { --cg: var(--accent); }
tr[data-catgroup="immune"]    { --cg: var(--info); }
tr[data-catgroup="cardio"]    { --cg: var(--danger); }
tr[data-catgroup="longevity"] { --cg: var(--accent-2); }
tr[data-catgroup="hormonal"]  { --cg: color-mix(in srgb, var(--danger) 55%, var(--accent)); }
tr[data-catgroup="sleep"]     { --cg: color-mix(in srgb, var(--info) 55%, var(--accent)); }
tr[data-catgroup="growth"]    { --cg: color-mix(in srgb, var(--success) 55%, var(--info)); }
tr[data-catgroup="gut"]       { --cg: color-mix(in srgb, var(--warning) 55%, var(--success)); }
tr[data-catgroup="other"]     { --cg: var(--border-strong); }

.as-cards .ptable tr { border-top: 3px solid var(--cg, var(--border-strong)); position: relative; }

/* Order inside a card: category, name, summary, facts. */
.as-cards .ptable td[data-label="Category"] { order: -3; }
.as-cards .ptable td[data-label="Category"]::before { content: none; }
.as-cards .ptable th[scope="row"] { order: -2; font-size: 16.5px; letter-spacing: -.01em; }
.as-cards .ptable .cell-summary { order: -1; }
.as-cards .ptable .cell-summary .thin { display: none; }
.as-cards .ptable .cell-summary:not(:has(*)) { display: block; }

/* The facts, as one badge row with icons. The text labels drop (the badge shapes carry the
   meaning); each cell gains a small masked icon in currentColor, so it recolours with the theme
   and with the value it sits beside. */
.as-cards .ptable td[data-label="Strongest rung"],
.as-cards .ptable td[data-label="Citations"],
.as-cards .ptable td[data-label="Regulatory"] {
  display: inline-flex; align-items: center; gap: 6px; margin-top: auto; }
.as-cards .ptable td[data-label="Strongest rung"] { padding-top: 6px; }
.as-cards .ptable td[data-label="Strongest rung"]::before,
.as-cards .ptable td[data-label="Citations"]::before,
.as-cards .ptable td[data-label="Regulatory"]::before {
  content: ""; display: inline-block; width: 13px; height: 13px; flex: none;
  background: currentColor; opacity: .55;
  -webkit-mask: var(--ico) center / contain no-repeat; mask: var(--ico) center / contain no-repeat; }
.as-cards .ptable td[data-label="Strongest rung"]::before {
  --ico: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2.4" stroke-linecap="round"><path d="M8 3v18M16 3v18M8 7h8M8 12h8M8 17h8"/></svg>'); }
.as-cards .ptable td[data-label="Citations"]::before {
  --ico: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/></svg>'); }
.as-cards .ptable td[data-label="Regulatory"]::before {
  --ico: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>'); }
/* Citations count reads as "N citations", not a bare digit. */
.as-cards .ptable td[data-label="Citations"]::after { content: " citation(s)"; font-size: 12px; color: var(--text-muted); }
/* Re-asserted below the fact-row rules, which otherwise out-cascade it: an empty cell stays
   hidden in card view even now that the fact cells are inline-flex. */
.as-cards .ptable td.is-empty[data-label] { display: none; }
/* The filter group: three labelled dropdowns in one row under the search. */
.fb-selects { display: flex; flex-wrap: wrap; gap: 12px 10px; flex-basis: 100%; padding-top: 5px; }
/* A grid item's min-width is its content unless told otherwise, so one long nowrap category chip
   ("Hormonal & Sexual Health / Cardiovascular") silently widened its card past the wrapper and
   brought the horizontal scrollbar back. Cards may shrink; chips may wrap their text. */
.as-cards .ptable tr { min-width: 0; }
.as-cards .cat-chips li { white-space: normal; }

/* Molecular structure. The image stays on a white plate in BOTH themes — a skeletal formula is
   black lines on white, and inverting or dark-tinting it would redraw the chemistry. */
.mol { margin: 4px 0 16px; }
/* The plate is the brand: the old viewer's violet panel, black pill chips and the triangle mark,
   carried over. The molecule itself stays on a white card inside it in BOTH themes — a skeletal
   formula is black lines on white, and CPK element colours mean something; tinting the chemistry
   to match a theme would redraw it. The frame is ours, the drawing is PubChem's. */
.mol-plate { position: relative; padding: 46px 18px 18px; max-width: 540px;
  background: linear-gradient(135deg, var(--accent) 0%, var(--accent-press, var(--accent)) 100%);
  border-radius: var(--radius-lg, 16px); box-shadow: var(--shadow-md); }
.mol-plate img { display: block; width: 100%; height: auto; background: #fff;
  border-radius: var(--radius-md, 12px); padding: 10px; }
.mol-chip { position: absolute; top: 12px; left: 14px; padding: 4px 11px;
  background: rgba(7, 10, 16, .82); color: #fff; border-radius: var(--radius-pill, 999px);
  font-family: var(--font-mono, ui-monospace, monospace); font-size: 10.5px; font-weight: 700;
  letter-spacing: .07em; text-transform: uppercase; white-space: nowrap; }
.mol-chip-dim { left: auto; right: 54px; background: rgba(7, 10, 16, .5); }
.mol-mark { position: absolute; top: 9px; right: 14px; width: 26px; height: 26px;
  color: rgba(255, 255, 255, .85); }
.mol figcaption { margin-top: 8px; font-size: 12.5px; color: var(--text-muted); max-width: 60ch; }
@media (max-width: 560px) { .mol-chip-dim { display: none; } }

/* At-a-glance strip: why it is studied and what the studies are, as counts of real rows.
   Icons come from components.css mask vars; the label column keeps the three rows scannable. */
.glance { display: grid; gap: 8px; margin: 4px 0 18px; padding: 14px 16px;
  border: 1px solid var(--border); border-radius: var(--radius-md, 12px);
  background: var(--surface); }
.glance-row { display: flex; flex-wrap: wrap; gap: 4px 9px; align-items: baseline;
  font-size: 13.5px; line-height: 1.55; }
.glance-row .ico { align-self: center; color: var(--accent); }
.glance-row b { flex: none; min-width: 122px; font-size: 10.5px; font-weight: 800;
  letter-spacing: .05em; text-transform: uppercase; color: var(--text-muted); }
.glance-row > span:last-child { min-width: 0; flex: 1 1 240px; }
.glance-row a { color: inherit; }
.glance-row a strong { color: var(--success-strong, var(--success)); }

/* Row-heading fixes: .doc th's nowrap/background/uppercase are for COLUMN headers; on the name
   cell they made long names shoot under the next column and painted a grey band across every
   card. Names wrap, keep their case, and sit on the card background. */
.ptable th[scope="row"] { white-space: normal; overflow-wrap: anywhere; background: transparent;
  text-transform: none; letter-spacing: 0; font-size: 13.5px; }
.as-cards .ptable th[scope="row"] { font-size: 16px; }

/* The index table scrolls inside its own region so the column titles stay put. */
.tbl-scroll:has(.ptable) { max-height: min(80dvh, 940px); overflow: auto; }
.ptable thead th { position: sticky; top: 0; z-index: 3; box-shadow: 0 1px 0 var(--border); }
.tbl-scroll.as-cards { max-height: none; overflow: visible; }

/* Tool icons on the hub cards, and structured adverse-effect rows */
.toolcard h2 { display: flex; align-items: center; gap: 9px; }
.tc-ico { width: 17px; height: 17px; color: var(--accent); }
.ae-list { list-style: none; margin: 6px 0 0; padding: 0; display: grid; gap: 10px; }
.ae { border: 1px solid var(--border); border-radius: var(--radius-md, 12px); padding: 12px 14px;
  background: var(--surface-subtle, var(--surface)); }
.ae-text { margin: 0 0 8px; font-size: 14px; }
.ae-tags { margin: 0; display: flex; flex-wrap: wrap; gap: 6px; }
.ae-chip { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; font-weight: 600;
  padding: 3px 10px; border-radius: 999px; border: 1px solid var(--border);
  color: var(--text-muted); background: var(--surface); }
.ae-chip .ico { width: 12px; height: 12px; }
.ae-chip.ae-good { color: var(--success-strong, var(--success));
  border-color: color-mix(in srgb, var(--success) 45%, var(--border));
  background: color-mix(in srgb, var(--success) 9%, var(--surface)); }
.ae-chip.ae-none { border-style: dashed; font-style: italic; font-weight: 500; }

/* Long machine-readable identifiers (SMILES, InChI, sequence). Without overflow-wrap a single
   400-character InChI sets the grid column width and shoves the card off the page. Capped in
   height with its own scroll so a huge string cannot dominate the card either. */
.rel dd.mono.wrap { overflow-wrap: anywhere; word-break: break-all; font-size: 11.5px;
  line-height: 1.6; max-height: 8.5em; overflow-y: auto; }

/* The 3D plate. The model ships as transparent atoms with its shadow already composited into the
   PNG's own alpha, so it sits directly on the violet — no white card, which is what made the
   skeletal formula glare in dark mode. The plate is the same violet in both themes, so one image
   serves both. */
.mol-plate-3d { padding: 46px 14px 14px; }
.mol-plate-3d img { background: none; padding: 0; border-radius: 0;
  filter: drop-shadow(0 12px 22px rgba(7, 10, 16, .34)); }

/* The skeletal formula, one click below the model. It stays the canonical depiction — it claims
   connectivity and nothing else — but it is the second thing most readers want to look at. */
.mol-2d { margin-top: 10px; }
/* The WHITE belongs to the image, not to the panel. Painting the whole disclosure white put the
   caption — var(--text-muted), a light grey in dark mode — on white and made it unreadable. A
   skeletal formula genuinely does need a white ground (black lines, and CPK colours mean
   something), so the image keeps its white card and the panel keeps the theme. */
.mol-2d .acc-body { background: var(--surface); border-radius: 0 0 var(--radius-md, 12px) var(--radius-md, 12px); }
.mol-2d .acc-body img { display: block; width: 100%; height: auto; max-width: 460px; margin: 0 auto;
  background: #fff; border-radius: var(--radius-md, 12px); padding: 10px; }
.mol-2d .acc-body .muted-note { margin: 8px 0 0; }

/* Index thumbnails. The row heading becomes a small flex: molecule, then name. In card view the
   thumbnail grows and moves above the name, because a card has room for a picture and a table row
   does not. */
.ptable th[scope="row"] a { display: flex; align-items: center; gap: 10px; }
.row-thumb { width: 38px; height: 38px; flex: none; object-fit: contain; }
.as-cards .ptable th[scope="row"] a { display: block; }
.as-cards .row-thumb { width: 84px; height: 84px; display: block; margin: 0 0 6px; }
@media (max-width: 560px) { .row-thumb { width: 30px; height: 30px; } }

/* The share card, in whichever theme is active. Both images ship; CSS picks. data-theme is always
   present because layout.mjs resolves the stored choice (or the OS preference) before first paint,
   so this follows the site's own toggle rather than only the OS. */
.sharecard { margin: 10px 0 0; }
.sharecard img { display: block; width: 100%; height: auto; border: 1px solid var(--border);
  border-radius: var(--radius-md, 12px); }
.sharecard figcaption { margin-top: 8px; font-size: 12.5px; color: var(--text-muted); }


/* Title and molecule side by side. The heading stays real text — it is the record's strongest
   claim on its own name — and the picture sits beside it rather than replacing it. The hero uses
   the 10 KB thumbnail, not the 226 KB model: above the fold every byte is measured, and this is
   displayed at 150px. */
/* THE MOLECULE SITS DIRECTLY AFTER THE H1 IN THE DOM, which is the order a phone reads and the
   order a screen reader announces: name, then picture of it. Desktop lifts it out into a second
   column beside the whole block — a purely visual move, so the document order stays honest.
   It used to be a separate wrapper hoisted above the title with order:-1, which meant a phone
   showed the picture before the page said what it was. */
.rec-top.has-hero { display: grid; grid-template-columns: minmax(0, 1fr) auto;
  column-gap: clamp(16px, 4vw, 40px); align-items: start; }
.rec-top.has-hero > *:not(.rec-hero) { grid-column: 1; }
.rec-hero { grid-column: 2; grid-row: 1 / -1; align-self: center; margin: 0; }
.rec-hero img { display: block; width: 150px; height: 150px; object-fit: contain; }
@media (max-width: 720px) {
  /* One column, and the molecule keeps its document position: straight after the title. A 150px
     square beside a wrapping compound name squeezes the name into a column two words wide. */
  .rec-top.has-hero { grid-template-columns: minmax(0, 1fr); }
  .rec-top.has-hero > * { grid-column: 1 !important; }
  .rec-hero { grid-row: auto; margin: 4px 0 2px; }
  .rec-hero img { width: 96px; height: 96px; }
}
/* ── The shop: vendor + lab directory ─────────────────────────────────────────────────────────
   The score system mirrors the tier system on purpose — badge geometry, strip, bars — so the two
   read as one grading language. The one deliberate divergence: score badges link the SHOP
   methodology, never the evidence rubric, because a vendor score and an evidence rung must never
   be mistaken for each other. check-build enforces the link the same way it does tier badges. */
.score-badge { display: inline-flex; align-items: center; padding: 3px 10px; border-radius: var(--radius-pill, 999px);
  font-family: var(--font-mono, ui-monospace, monospace); font-size: 12px; font-weight: 700;
  font-variant-numeric: tabular-nums; border: 1px solid transparent; }
.score-badge:hover { text-decoration: none; border-color: var(--accent); }
.score-badge.sb-high { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.score-badge.sb-high:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
.score-badge.sb-mid { background: var(--accent-soft); color: var(--text-on-soft); border-color: var(--accent-soft-border); }
.score-badge.sb-low { background: var(--surface); color: var(--text-muted); border-color: var(--border-strong); }

.score-strip { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px;
  margin: 0 0 18px; padding: 11px 14px; background: var(--surface);
  border: 1px solid var(--border); border-left: 3px solid var(--accent);
  border-radius: var(--radius-md, 12px); font-size: 13.5px; }

/* Dimension bars: the rung-bars grid with a wider value column — "10.0" is four mono digits. */
.score-bars { display: grid; gap: 7px; margin: 6px 0 10px; padding: 0; list-style: none; }
.score-bars li { display: grid; grid-template-columns: minmax(130px, 1fr) minmax(90px, 2fr) 34px; gap: 8px; align-items: center; }
.score-bars a { font-size: 12px; color: var(--text-muted); }
.score-bars a:hover { color: var(--accent); text-decoration: none; }
.score-bars .bar { height: 6px; border-radius: 3px; background: var(--surface-sunken); overflow: hidden; }
.score-bars .bar i { display: block; height: 100%; background: var(--accent); border-radius: 3px; }
.score-bars b { font-family: var(--font-mono, ui-monospace, monospace); font-size: 12px; text-align: right; }
.score-bars .sb-none { grid-column: 2 / 4; font-size: 12px; color: var(--text-subtle); }

/* Placement strips. Sponsored carries the warning accent and its disclosure INLINE — the
   disclosure is part of the strip, never a footnote elsewhere (check-build: sponsor/undisclosed).
   The editorial "highest scored" variant keeps the accent border so paid and derived cannot be
   confused at a glance. */
.sponsor-strip { margin: 18px 0; padding: 14px 16px; border: 1px solid var(--border);
  border-left: 3px solid var(--warning); border-radius: var(--radius-md, 12px); }
.sponsor-strip.is-editorial { border-left-color: var(--accent); }
.sponsor-note { margin: 0 0 10px; font-size: 13px; color: var(--text-muted); }
.sponsor-tag { display: inline-block; margin-right: 6px; padding: 1px 8px; font-size: 10.5px;
  font-weight: 800; letter-spacing: .07em; text-transform: uppercase; color: var(--warning);
  border: 1px solid currentColor; border-radius: var(--radius-pill, 999px); }
.sponsor-tag.st-editorial { color: var(--text-muted); }
.sponsor-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 12px; }
.sponsor-card { padding: 13px 14px; background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-md, 12px); font-size: 13.5px; }
.sponsor-card p { margin: 0 0 6px; }
.sponsor-card p:last-child { margin-bottom: 0; }
.sponsor-card-head { display: flex; align-items: center; gap: 8px; font-size: 15px; }

/* Every price, shipping and verification fact carries the date we saw it. Quiet, but present. */
.obs-date { font-size: 11.5px; color: var(--text-subtle); font-variant-numeric: tabular-nums; white-space: nowrap; }

/* Vendor + lab comparison columns. */
.vtable .col-vendor { width: 24%; }
.vtable .col-vtype { width: 13%; }
.vtable .col-vscore { width: 8%; }
.vtable .col-vcoa { width: 14%; }
.vtable .col-vship { width: 13%; }
.vtable .col-vprice { width: 9%; }
.vtable .col-vdate { width: 12%; }
.vtable .col-lmethods { width: 24%; }
.vtable .col-lprice { width: 16%; }
.ptable td.is-empty { color: var(--text-subtle); }

/* Vendor logos: downloaded at probe time, served same-origin, sized to stay furniture rather than
   advertising. A vendor without one gets a typographic monogram — never a broken image. */
.v-logo { display: inline-block; width: 20px; height: 20px; border-radius: 5px; object-fit: contain;
  vertical-align: -4px; margin-right: 8px; background: var(--surface-sunken);
  border: 1px solid var(--border-subtle); }
.v-mono { display: inline-flex; align-items: center; justify-content: center;
  font: 700 11px var(--font-mono, ui-monospace, monospace); color: var(--text-muted); }
.rail-store { display: flex; align-items: center; gap: 4px; }
.rail-store .v-logo { width: 24px; height: 24px; }
/* Card views carry the logo in the corner, clear of the name. */
.sponsor-card { position: relative; }
.sponsor-card > .v-logo { position: absolute; top: 12px; right: 12px; width: 30px; height: 30px; margin: 0; }
.as-cards .ptable tr { position: relative; }
.as-cards .ptable .v-logo { position: absolute; top: 15px; right: 15px; width: 32px; height: 32px; margin: 0; }

/* The storefront carousel: the store's own top-8, server-rendered, scroll-snap, no script. */
/* A grid item's min-width is its content unless told otherwise (same trap .rec-main already
   guards one level up): eight 190px cards gave the #products section a ~1600px intrinsic width,
   which widened the whole record column and pushed the score bars off-screen. Every direct child
   of the record column defers to the track, and the carousel scrolls inside it. */
.rec-main > * { min-width: 0; }
.pcarousel { display: flex; gap: 10px; margin: 10px 0 6px; padding: 2px 2px 10px; list-style: none;
  overflow-x: auto; scroll-snap-type: x mandatory; -webkit-overflow-scrolling: touch; }
.pcarousel li { flex: 0 0 190px; scroll-snap-align: start; display: grid; gap: 6px;
  align-content: start; padding: 12px 13px; background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--radius-md, 12px); }
.pcarousel li a { font-size: 13.5px; font-weight: 650; line-height: 1.35; }
.p-price { font-size: 12.5px; color: var(--text-muted); }

/* The browse cards carry a three-product taste of the storefront feed; the full carousel lives on
   the record. Hidden in list view — the comparison table is for comparing, not shopping. */
.ptable .cell-products { display: none; }
.as-cards .ptable .cell-products { display: block; font-size: 12.5px; color: var(--text-muted); }

/* Vendor strengths/weaknesses. The rubric's crit component read as heavy colour washes here and
   its +/− markers hung outside the panels. Neutral surfaces, a coloured edge, markers set inside
   the text block where they belong. */
.vcrit { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 12px; margin: 12px 0 4px; }
.vc { padding: 14px 16px; background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-md, 12px); }
.vc h3 { margin: 0 0 9px; font-size: 10.5px; font-weight: 800; letter-spacing: .07em;
  text-transform: uppercase; color: var(--text-subtle); }
.vc ul { margin: 0; padding: 0; list-style: none; display: grid; gap: 7px; }
.vc li { position: relative; padding-left: 21px; font-size: 13.5px; line-height: 1.5; }
.vc li::before { position: absolute; left: 2px; top: 0;
  font-family: var(--font-mono, ui-monospace, monospace); font-weight: 700; }
.vc-good { border-left: 3px solid var(--success); }
.vc-good li::before { content: "+"; color: var(--success); }
.vc-bad { border-left: 3px solid var(--warning); }
.vc-bad li::before { content: "\2212"; color: var(--warning); }

/* Product thumbnails in the carousel: downloaded platform thumbnail variants served same-origin,
   square-cropped so eight mismatched aspect ratios read as one row. Cards without one stay text-first. */
.p-thumb { width: 100%; aspect-ratio: 1 / 1; height: auto; object-fit: cover;
  border-radius: var(--radius-sm, 8px); background: var(--surface-sunken);
  border: 1px solid var(--border-subtle); }

/* A struck-through "was" price beside the live one — the store's own sale claim, quoted. */
.p-price s { color: var(--text-subtle); margin-right: 5px; }

/* An unscored record's badge: same slot, quieter weight, dashed edge — a declared absence. */
.score-badge.sb-none { background: transparent; color: var(--text-muted);
  border: 1px dashed var(--border-strong); font-family: inherit; font-weight: 600; }
/* ── Forum ──────────────────────────────────────────────────────────────────────────────────────
   Member content gets its own visual family (.card-ugc), deliberately unlike every graded-claim
   component: no tier colour, no badge, a plain "member post" label where a graded card carries a
   rung. §7 of the architecture decisions is a rendering rule too — a thread must never look like
   evidence. Precedents for "present but not a graded fact" are .unverified and .no-page. */

.thread-list { list-style: none; margin: 6px 0 22px; padding: 0; display: grid; gap: 10px; }
.thread-row { padding: 13px 16px; background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-md, 12px); }
.thread-row.is-pinned { border-color: var(--border-strong); }
.thread-title { font-weight: 650; font-size: 15.5px; text-decoration: none; color: var(--text); }
.thread-title:hover { text-decoration: underline; }
.thread-meta { margin: 5px 0 0; font-size: 12.5px; color: var(--text-muted); }
.thread-pin { font-weight: 700; text-transform: uppercase; letter-spacing: .04em; font-size: 11px;
  color: var(--text-subtle); }
.thread-tag { display: inline-block; padding: 1px 9px; border: 1px solid var(--border);
  border-radius: 999px; font-size: 12px; font-weight: 600; text-decoration: none;
  color: var(--text-muted); background: var(--surface-subtle, var(--surface)); }
a.thread-tag:hover { border-color: var(--accent); color: var(--accent); }
.thread-tag.is-unresolved { border-style: dashed; font-style: italic; font-weight: 500; }
.cat-count { display: block; margin-top: 3px; font-size: 12.5px; color: var(--text-muted); }

/* The post card. Left border is the neutral structural grey — never a tier colour. */
.card-ugc { margin: 14px 0; padding: 16px 18px; background: var(--surface-subtle, var(--surface));
  border: 1px solid var(--border); border-left: 3px solid var(--border-strong);
  border-radius: var(--radius-md, 12px); }
.card-ugc.is-op { background: var(--surface); }
.post-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 10px; margin: 0 0 10px; }
.post-handle { font-weight: 700; font-size: 14px; }
.post-label { font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .05em;
  color: var(--text-subtle); }
.post-head time { margin-left: auto; font-size: 12.5px; color: var(--text-muted); }
.post-edited { font-size: 12px; font-style: italic; color: var(--text-subtle); }
.post-body { font-size: 15px; }
.post-body p { margin: 0 0 10px; }
.post-body p:last-child { margin-bottom: 0; }
.post-body blockquote { margin: 10px 0; padding: 8px 14px; border-left: 3px solid var(--border);
  color: var(--text-muted); background: var(--surface-sunken); border-radius: 0 var(--radius-sm, 8px) var(--radius-sm, 8px) 0; }
.post-body blockquote p { margin: 0; }
.post-body code { font-family: var(--font-mono); font-size: .92em; padding: 1px 5px;
  background: var(--surface-sunken); border-radius: 5px; }
.post-foot { margin-top: 10px; font-size: 12px; }
.post-foot a { color: var(--text-subtle); text-decoration: none; }
.post-foot a:hover { color: var(--text-muted); text-decoration: underline; }

.thread-about { font-size: 13.5px; color: var(--text-muted); margin: 2px 0 16px; }
.thread-continues { font-size: 13.5px; color: var(--text-muted); margin: 2px 0 14px; }

/* The composer block: always present, honest about what it is, never a fake disabled input. */
.composer { margin: 26px 0 14px; padding: 20px 22px; background: var(--surface);
  border: 1px solid var(--border-strong); border-radius: var(--radius-md, 12px); }
.composer h2 { margin: 0 0 8px; font-size: 17px; }
.composer p { font-size: 14px; color: var(--text-muted); margin: 0 0 14px; }
.composer.is-locked { border-style: dashed; }
.composer.is-locked p { margin-bottom: 0; }

.built-note { margin: 14px 0 0; font-size: 12.5px; color: var(--text-subtle); }

.pager { display: flex; align-items: center; gap: 14px; margin: 18px 0; font-size: 14px; }
.pager-where { color: var(--text-muted); font-size: 13px; }
.pager-end { color: var(--text-subtle); }

/* ── Vendor price catalogue (vp-) ─────────────────────────────────────────────────────────────
   The "Catalogue, as their API returns it" section on /shop/vendors/{slug}, rendered by
   build-shop.mjs from content/vendor-prices.json — a file that may not exist, in which case
   none of these classes reach a page. Everything else the section uses is existing furniture
   (.card, .card-gap, .tbl-scroll, .ptable, .muted-note, .obs-date, .tag-count, .is-empty);
   these rules only size the four columns, seat the observed-date line under the heading, and
   quiet the struck-through regular price so a sale reads as two figures, not an alarm. */
.vp-observed { margin: -6px 0 12px; }
.vp-cat { min-width: 560px; }
.vp-cat .col-vpname { width: 55%; }
.vp-cat .col-vpprice, .vp-cat .col-vpreg, .vp-cat .col-vpcur { width: 15%; }
.vp-cat s { color: var(--text-subtle); text-decoration-color: var(--text-subtle); }
