/* Gym Product Review — ember on graphite.
   Palette and motion per docs/superpowers/specs/2026-08-20-gym-product-review-design.md §15. */

/* ---- self-hosted type — latin-subset variable fonts, no CDN, no FOIT ----
   Files live in /fonts (site/fonts/, adjacent to site/brand/), fetched once
   from Google Fonts' own SIL-licensed files and served from this origin.
   Each is a single variable-weight woff2, so three requests cover every
   weight the site uses. font-display: swap avoids invisible text; the
   system-font fallback stack after each family is tuned to sit close in
   x-height and width so swap-in doesn't jump the layout. */

:root {
  --font-sans: 'Archivo', 'Segoe UI', system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
  --font-serif: 'Iowan Old Style', Georgia, 'Times New Roman', serif; /* webfont retired 2026-09-22 */
  --font-mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  --bg-page: #ffffff;
  --bg-alt: #fbfaf9;
  --bg-inset: #faf8f6;
  --bg-deep: #16130f;

  --text: #16130f;
  --text-2: #2c2621;
  --text-dim: #57504a;
  /* Darkened from the original #9a938c: that value read at ~3.05:1 on
     --bg-page, under the 4.5:1 AA floor for the normal-size text it's
     actually used on (chips, captions, empty-state labels). This holds
     ~4.9:1 while staying visibly the lightest step in the text ramp. */
  --text-mute: #767068;

  --border: #e9e5e0;
  --border-strong: #d2ccc4;

  --ember: #d9482a;
  --ember-bright: #f2643f;
  --ember-deep: #a03318;
  --ember-tint: rgba(217, 72, 42, 0.08);

  --verified: #0f6e6a;
  --verified-bg: #eafaf8;

  --link: #1b4f8f;
  --link-hover: #123a6d;

  --wrap: 1340px;
  --measure: 68ch;

  /* ---- spacing scale — an 8px rhythm, used for new/refined components ---- */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 28px;
  --space-7: 40px;
  --space-8: 56px;
  --space-9: 80px;

  --radius-sm: 4px;
  --radius-md: 6px;
  --radius-lg: 10px;

  --border-soft: #f1eee9;
}

* { box-sizing: border-box; }
html, body { overflow-x: clip; }

body {
  margin: 0;
  background: var(--bg-page);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 17px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

.wrap { max-width: var(--wrap); margin: 0 auto; padding: 0 24px; }
.prose { max-width: var(--measure); }

a { color: var(--link); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: var(--link-hover); }
a:active { color: var(--ember-deep); }

/* ---- interaction states: baseline for every focusable element ----
   :focus-visible only (never plain :focus) so mouse clicks stay clean and
   keyboard/AT users get a ring that reads as designed, not defaulted.
   Anything with a bespoke ring (sort buttons, etc.) simply overrides this. */
/* Skip to content. Every page's masthead carries the brand, a nav, a theme
   toggle, a search and a rankings menu, which is a lot of tabbing before a
   keyboard or switch user reaches the thing they came for — WCAG 2.4.1.
   Off-screen rather than display:none, so it stays focusable, and it lands on
   <main id="main" tabindex="-1"> so focus actually moves rather than only the
   scroll position. */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  padding: 10px 16px;
  /* Fixed colours, not theme tokens. Two attempts with tokens both failed:
     --bg-deep on --bg-page read 1.11:1, because the :root block at the top of
     this file sets --bg-page to #ffffff and a later one redefines the palette
     to navy; --ember-deep with #fff read 1.39:1, because .btn declares that
     pair but a theme override repaints the button. A skip link is a chip
     overlaid on an unknown corner of the page, and an invisible one is worse
     than none, so it does not take part in theming at all. 16.1:1. */
  background: #10151c;
  color: #ffffff;
  font: 600 0.9rem/1 var(--font-sans);
  letter-spacing: 0.02em;
  border-radius: 0 0 var(--radius-sm) 0;
}
.skip-link:focus {
  left: 0;
}
main:focus {
  outline: none;
}

a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--ember);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}
button:disabled,
input:disabled,
select:disabled,
textarea:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
select:not(:disabled):hover,
input:not(:disabled):hover {
  border-color: var(--text-mute);
}

/* ---- masthead ---- */
.masthead {
  border-bottom: 1px solid var(--border);
  padding: 18px 0;
  position: sticky;
  top: 0;
  background: rgba(255, 255, 255, 0.94);
  backdrop-filter: saturate(140%) blur(8px);
  z-index: 10;
}
.masthead .wrap { display: flex; align-items: center; justify-content: space-between; gap: 16px; }
.brand { font-weight: 700; letter-spacing: -0.02em; font-size: 1.05rem; color: var(--text); text-decoration: none; }
.brand .mark { color: var(--ember); }
.nav { display: flex; gap: 22px; font-size: 0.94rem; }
.nav a { color: var(--text-dim); text-decoration: none; transition: color 0.15s ease; }
.nav a:hover { color: var(--ember); }

/* ---- hero ---- */
.hero { padding: 72px 0 56px; border-bottom: 1px solid var(--border); }
.eyebrow {
  font-family: var(--font-mono);
  font-size: 0.74rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  /* ember-deep, not ember: at this size/weight plain ember reads ~4.3:1 on
     white, just under AA. Same hue family, still unmistakably the brand
     mark's color, and it now clears 4.5:1. */
  color: var(--ember-deep);
  margin: 0 0 18px;
}
h1 {
  font-weight: 700;
  font-size: clamp(2rem, 5vw, 3.15rem);
  line-height: 1.08;
  letter-spacing: -0.03em;
  margin: 0 0 22px;
  max-width: 20ch;
  text-wrap: balance;
}
.lede { font-family: var(--font-serif); font-size: clamp(1.08rem, 2vw, 1.28rem); line-height: 1.55; color: var(--text-2); max-width: var(--measure); margin: 0; text-wrap: pretty; }

/* ---- sections ---- */
section { padding: var(--space-8) 0; border-bottom: 1px solid var(--border); }
section:last-of-type { border-bottom: 0; }
h2 { font-weight: 700; font-size: clamp(1.35rem, 3vw, 1.75rem); letter-spacing: -0.02em; margin: 0 0 10px; text-wrap: balance; }
h3 { font-weight: 600; font-size: 1.06rem; margin: 30px 0 8px; letter-spacing: -0.01em; }
p { margin: 0 0 16px; }
.prose p, .prose li { font-family: var(--font-serif); color: var(--text-2); }
.prose { line-height: 1.68; }

.pillars { display: grid; grid-template-columns: repeat(auto-fit, minmax(270px, 1fr)); gap: 22px; margin-top: 30px; }
.pillar { border: 1px solid var(--border); border-left: 3px solid var(--ember); border-radius: 3px; padding: 22px; background: var(--bg-alt); }
.pillar h3 { margin: 0 0 8px; font-size: 1.02rem; }
.pillar p { margin: 0; font-size: 0.95rem; color: var(--text-dim); }

.num { font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-feature-settings: 'tnum' 1, 'lnum' 1; }

/* ---- tables: a reference work, not a blog list ----
   Numeric columns right-align so a consistent decimal-place count (the
   generators always call .toFixed()) lines digits up on the decimal point,
   the way a financial table does. Header labels stay left/ragged — mixing
   ragged labels with right-set values is the standard dense-table pattern
   (FT, Bloomberg) and reads more considered than forcing both to match. */
table { border-collapse: collapse; width: 100%; font-size: 0.93rem; }
.scroll { overflow-x: auto; margin: var(--space-5) 0; border: 1px solid var(--border); border-radius: var(--radius-md); }
.scroll table { margin: 0; }
/* A .scroll wrapping a long, client-sorted table gets a bounded, internally
   scrolling frame so its header can be genuinely sticky -- overflow-x:auto
   forces overflow-y:auto per spec regardless, so this embraces it on
   purpose instead of fighting it. Short tables never reach the max-height,
   so nothing visibly changes for them. Progressive enhancement: browsers
   without :has() just keep ordinary page scrolling. */
.scroll:has(> table[data-sortable]),
.scroll.tall { max-height: 74vh; overflow-y: auto; }
th, td { text-align: left; padding: 12px 14px; border-bottom: 1px solid var(--border); vertical-align: top; }
thead th {
  position: sticky; top: 0; z-index: 3;
  background: var(--bg-page);
  box-shadow: inset 0 -1px 0 var(--border-strong);
  border-bottom: 0;
}
td.n, th.n { text-align: right; font-variant-numeric: tabular-nums; }
td.n { font-family: var(--font-mono); font-feature-settings: 'tnum' 1; white-space: nowrap; }
tbody tr:hover td { background: var(--bg-inset); }
cite { display: block; font-size: 0.82rem; color: var(--text-mute); font-style: normal; }

.note {
  border: 1px solid var(--border-strong);
  border-left: 3px solid var(--verified);
  background: var(--verified-bg);
  border-radius: 3px;
  padding: 18px 20px;
  margin: 26px 0;
}
.note strong { color: var(--verified); }
.note p { margin: 0; font-size: 0.95rem; }

footer { background: var(--bg-deep); color: #b8b0a8; padding: 42px 0; font-size: 0.9rem; }
footer a { color: #e8e2db; }
footer .wrap > * + * { margin-top: 10px; }

/* ---- motion, matching PSR behaviour ---- */
.reveal { opacity: 0; transform: translateY(10px); transition: opacity 420ms ease, transform 420ms cubic-bezier(0.22, 1, 0.36, 1); }
.reveal.in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; transition: none; }
  .masthead { backdrop-filter: none; }
}

@media (max-width: 640px) {
  body { font-size: 16px; }
  .hero { padding: 48px 0 38px; }
  section { padding: 40px 0; }
  .nav { gap: 15px; font-size: 0.88rem; }
}

/* =========================================================================
   Product / category / tool templates
   ========================================================================= */

/* ---- masthead: nav, condense-on-scroll, mobile drawer ---- */
.masthead { transition: padding 200ms ease; }
.masthead.is-condensed { padding: 11px 0; }
.masthead.is-condensed .brand { font-size: 0.98rem; }
@media (prefers-reduced-motion: reduce) { .masthead { transition: none; } }

.nav { align-items: center; }
/* ember-deep, not ember: "current page" is a persistent state (unlike the
   :hover rules below), so it has to clear 4.5:1 on its own -- ember alone
   reads ~4.3:1 at this size. */
.nav a.current { color: var(--ember-deep); font-weight: 600; }
.nav-toggle {
  display: none;
  background: none; border: 1px solid var(--border-strong); border-radius: 4px;
  width: 38px; height: 34px; padding: 0; cursor: pointer;
  align-items: center; justify-content: center; gap: 3px; flex-direction: column;
}
.nav-toggle:hover { border-color: var(--ember); }
.nav-toggle:active span { background: var(--ember); }
.nav-toggle span { display: block; width: 18px; height: 2px; background: var(--text); transition: background 150ms ease; }
@media (prefers-reduced-motion: reduce) { .nav-toggle span { transition: none; } }

.nav-drawer { display: none; }
.nav-scrim { display: none; }

@media (max-width: 760px) {
  .nav-toggle { display: inline-flex; }
  .nav-links { display: none; }
  .nav-drawer {
    display: block;
    visibility: hidden;
    transition: transform 260ms cubic-bezier(0.22, 1, 0.36, 1), visibility 0s linear 260ms;
    position: fixed; inset: 0 0 0 auto; width: min(78vw, 320px);
    background: var(--bg-page); border-left: 1px solid var(--border);
    padding: 84px 26px 26px; transform: translateX(100%);
    transition: transform 260ms cubic-bezier(0.22, 1, 0.36, 1);
    z-index: 20; box-shadow: -12px 0 32px rgba(22,19,15,0.12);
  }
  .nav-drawer.open { transform: translateX(0); visibility: visible; transition-delay: 0s; }
  .nav-drawer .nav-links { display: flex; flex-direction: column; gap: 4px; font-size: 1.05rem; }
  .nav-drawer .nav-links a { padding: 11px 4px; border-bottom: 1px solid var(--border-soft, var(--border)); }
  .nav-scrim {
    display: none; position: fixed; inset: 0; background: rgba(22,19,15,0.35); z-index: 19;
  }
  .nav-drawer.open ~ .nav-scrim,
  .nav-drawer.open + .nav-scrim { display: block; }
  @media (prefers-reduced-motion: reduce) { .nav-drawer { transition: none; } }
}

/* ---- breadcrumb / eyebrow line ---- */
.crumb { font-family: var(--font-mono); font-size: 0.74rem; letter-spacing: 0.06em; color: var(--text-mute); margin: 0 0 14px; }
.crumb a { color: var(--text-mute); }
.crumb a:hover { color: var(--ember); }

/* ---- badges / chips ---- */
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: 0.04em;
  padding: 4px 9px; border-radius: 20px; border: 1px solid var(--border-strong);
  color: var(--text-dim); background: var(--bg-alt);
}
.chip.verified { color: var(--verified); background: var(--verified-bg); border-color: rgba(15,110,106,0.28); }
.chip.stale { color: var(--ember-deep); background: var(--ember-tint); border-color: rgba(217,72,42,0.28); }
.favicon-chip {
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; border-radius: 50%; flex: none;
  background: var(--bg-deep); color: #fff; font-size: 0.68rem; font-weight: 700;
  font-family: var(--font-sans);
}
.brand-row { display: flex; align-items: center; gap: 8px; }

/* ---- score bars ----
   Five-bucket logic: 8+ ember gradient, 6-8 teal, 4-6 amber, 3-4 orange, <3 red.
   Bucket colors are declared once as --b5..--b1 and reused by both the
   component bars and the composite ring below, so the two never drift. */
:root {
  --b5: var(--ember);
  --b4: #0f6e6a;
  --b3: #c68a1f;
  --b2: #c9682f;
  --b1: #b8402f;
}
.score-block { margin: var(--space-5) 0; }
.score-block-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin-bottom: 7px; }
.score-block-head .label { font-size: 0.93rem; font-weight: 500; color: var(--text-2); }
.score-block-head .weight { font-family: var(--font-mono); font-size: 0.76rem; color: var(--text-mute); }
.score-block-head .value { font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: 1.05rem; font-weight: 700; }
.bar-track { height: 10px; border-radius: 6px; background: var(--bg-inset); border: 1px solid var(--border); overflow: hidden; }
.bar-fill {
  height: 100%; width: 0; border-radius: 6px;
  transition: width 900ms cubic-bezier(0.22, 1, 0.36, 1);
}
@media (prefers-reduced-motion: reduce) { .bar-fill { transition: none; } }
.bar-fill.b5 { background: linear-gradient(90deg, var(--ember), var(--ember-bright)); }
.bar-fill.b4 { background: var(--b4); }
.bar-fill.b3 { background: var(--b3); }
.bar-fill.b2 { background: var(--b2); }
.bar-fill.b1 { background: var(--b1); }

/* ---- composite score — the single most important object on the page ----
   A ring rather than a bar: it reads at a glance from across the layout,
   scales down cleanly to a thumbnail on a ranking row, and its fill is set
   once at render time via a CSS custom property (--pct), so it is correct
   on first paint with zero script and zero layout shift. */
.score-anchor {
  display: flex; align-items: center; gap: var(--space-5);
  padding: var(--space-5); border: 1px solid var(--border); border-radius: var(--radius-lg);
  background: var(--bg-alt);
}
.score-anchor.is-empty { background: var(--bg-inset); }
.score-ring {
  --pct: 0;
  --ring-color: var(--text-mute);
  position: relative; flex: none;
  width: 104px; height: 104px; border-radius: 50%;
  background: conic-gradient(var(--ring-color) calc(var(--pct) * 1%), var(--border) 0);
  display: grid; place-items: center;
}
.score-ring::before {
  content: ''; position: absolute; inset: 9px; border-radius: 50%;
  background: var(--bg-page); box-shadow: inset 0 0 0 1px var(--border);
}
.score-ring .score-num {
  position: relative; font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-weight: 700; font-size: 1.7rem; line-height: 1; color: var(--text);
}
.score-ring .score-of {
  position: relative; display: block; margin-top: 2px;
  font-family: var(--font-mono); font-size: 0.68rem; color: var(--text-mute); text-align: center;
}
.score-anchor-meta { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.score-anchor-label { font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-mute); }
.score-anchor-tier { font-size: 1.05rem; font-weight: 700; color: var(--text); }
.score-anchor.b5 .score-ring { --ring-color: var(--b5); }
.score-anchor.b5 .score-anchor-tier { color: var(--ember-deep); }
.score-anchor.b4 .score-ring { --ring-color: var(--b4); }
.score-anchor.b4 .score-anchor-tier { color: var(--verified); }
.score-anchor.b3 .score-ring { --ring-color: var(--b3); }
.score-anchor.b3 .score-anchor-tier { color: #a06a15; }
.score-anchor.b2 .score-ring { --ring-color: var(--b2); }
.score-anchor.b2 .score-anchor-tier { color: #a5502a; }
.score-anchor.b1 .score-ring { --ring-color: var(--b1); }
.score-anchor.b1 .score-anchor-tier { color: #8f2f21; }
.score-anchor.is-empty .score-anchor-tier { color: var(--text-mute); }

@media (max-width: 640px) {
  .score-ring { width: 88px; height: 88px; }
  .score-ring .score-num { font-size: 1.4rem; }
}

/* ---- "not enough data" — a deliberate honest state, not a broken cell ----
   A dash glyph in the numeral register (mono, same as the numbers it stands
   in for) reads as "this cell was considered and withheld", not as an
   error. Kept quiet: no icon, no color alarm -- absence of data is routine
   here, not exceptional. */
.nd {
  display: inline-flex; align-items: baseline; gap: 6px;
  color: var(--text-mute); font-style: normal;
  font-family: var(--font-mono); font-size: 0.86em; letter-spacing: 0.01em;
}
.nd::before { content: '\2014'; color: var(--border-strong); font-weight: 600; }
.nd-reason { display: block; font-family: var(--font-sans); font-size: 0.78rem; color: var(--text-mute); font-style: italic; margin-top: 3px; }

/* ---- product page layout ---- */
.product-head {
  display: grid; grid-template-columns: 1.5fr 1fr; gap: 40px; align-items: start;
}
@media (max-width: 860px) { .product-head { grid-template-columns: 1fr; } }
.product-title { font-size: clamp(1.6rem, 3.4vw, 2.3rem); margin: 6px 0 10px; }
.product-sub { color: var(--text-dim); font-size: 0.98rem; margin: 0 0 20px; }

.side-card {
  border: 1px solid var(--border); border-radius: 6px; background: var(--bg-alt);
  padding: 22px; position: sticky; top: 84px;
}
.side-card + .side-card { margin-top: 18px; }
.side-card h3 { margin-top: 0; font-size: 0.92rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-mute); }
.offer-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 10px 0; border-bottom: 1px solid var(--border); }
.offer-row:last-child { border-bottom: 0; }
.offer-price { font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: 1.15rem; font-weight: 700; }
.offer-meta { font-size: 0.82rem; color: var(--text-mute); }
/* White text on plain --ember reads ~4.3:1 -- just under the 4.5:1 AA floor
   at this size. --ember-deep is the same hue family at ~7:1, so filled
   buttons use it as the resting fill; the bright ember stays for accents,
   bars, and text-free surfaces where it's already well clear of the bar. */
.btn {
  display: inline-block; padding: 9px 16px; border-radius: 4px; font-size: 0.9rem;
  background: var(--ember-deep); color: #fff; text-decoration: none; font-weight: 600;
  transition: filter 150ms ease;
}
.btn:hover { filter: brightness(1.1); color: #fff; }
.btn:active { filter: brightness(0.9); box-shadow: inset 0 1px 3px rgba(0,0,0,0.25); }
@media (prefers-reduced-motion: reduce) { .btn { transition: none; } }
.btn.ghost { background: none; border: 1px solid var(--border-strong); color: var(--text); }
.btn.ghost:hover { border-color: var(--ember); color: var(--ember); }
.btn.ghost:active { background: var(--ember-tint); }
.copy-btn {
  font-family: var(--font-mono); font-size: 0.82rem; padding: 6px 10px; border-radius: 4px;
  border: 1px dashed var(--border-strong); background: var(--bg-page); color: var(--text-2); cursor: pointer;
  transition: border-color 150ms ease, color 150ms ease;
}
.copy-btn:hover { border-color: var(--ember); color: var(--ember-deep); }
.copy-btn:active { background: var(--bg-inset); }
.copy-btn.copied { border-color: var(--verified); color: var(--verified); }
@media (prefers-reduced-motion: reduce) { .copy-btn { transition: none; } }

.signal-list { list-style: none; margin: 10px 0 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.signal {
  border: 1px solid var(--border-strong); border-left: 3px solid var(--ember-deep);
  border-radius: 3px; padding: 12px 14px; background: var(--ember-tint); font-size: 0.9rem;
}
.signal.info { border-left-color: var(--text-mute); background: var(--bg-inset); }
.signal .tag { font-family: var(--font-mono); font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ember-deep); display: block; margin-bottom: 4px; }
.signal.info .tag { color: var(--text-mute); }

.provenance { font-size: 0.88rem; color: var(--text-dim); }
.provenance dl { display: grid; grid-template-columns: auto 1fr; gap: 6px 14px; margin: 0; }
.provenance dt { color: var(--text-mute); }
.provenance dd { margin: 0; font-family: var(--font-mono); font-size: 0.86rem; word-break: break-word; }

/* ---- dose audit / met-not-met rows ---- */
tr.dose-met td.status { color: var(--verified); }
tr.dose-under td.status { color: var(--ember-deep); }
td.status { font-family: var(--font-mono); font-size: 0.82rem; font-weight: 600; white-space: nowrap; }

/* ---- sortable tables (site/js/sortable-table.js contract) ---- */
th button[data-sort-key] {
  font: inherit; cursor: pointer; user-select: none; white-space: nowrap;
  background: none; border: 0; padding: 0; color: inherit;
  font-size: 0.76rem; letter-spacing: 0.08em; text-transform: uppercase; font-weight: 600;
}
th button[data-sort-key]::after { content: '\2195'; color: var(--text-mute); margin-left: 5px; font-size: 0.9em; }
th[aria-sort="ascending"] button[data-sort-key]::after { content: '\2191'; color: var(--ember); }
th[aria-sort="descending"] button[data-sort-key]::after { content: '\2193'; color: var(--ember); }
th button[data-sort-key]:focus-visible { outline: 2px solid var(--ember); outline-offset: 2px; }
.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;
}

/* ---- filter forms (site/js/filters.js contract) ---- */
.filter-form { display: flex; flex-wrap: wrap; gap: 18px 26px; align-items: flex-end; margin: 22px 0; padding: 18px 20px; border: 1px solid var(--border); border-radius: 6px; background: var(--bg-alt); }
.filter-group { display: flex; flex-direction: column; gap: 6px; font-size: 0.86rem; }
.filter-group > span.filter-label { font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-mute); }
.filter-group label { display: flex; align-items: center; gap: 6px; font-weight: 400; color: var(--text-2); }
.filter-form select { font: inherit; padding: 7px 10px; border: 1px solid var(--border-strong); border-radius: 4px; background: var(--bg-page); color: var(--text); }
.filter-form button[type="reset"] { align-self: center; background: none; border: 1px solid var(--border-strong); border-radius: 4px; padding: 8px 12px; cursor: pointer; color: var(--text-dim); font-size: 0.86rem; transition: border-color 150ms ease, color 150ms ease; }
.filter-form button[type="reset"]:hover { border-color: var(--ember); color: var(--ember); }
.filter-form button[type="reset"]:active { background: var(--ember-tint); }
@media (prefers-reduced-motion: reduce) { .filter-form button[type="reset"] { transition: none; } }
[data-filter-count] { font-family: var(--font-mono); font-size: 0.82rem; color: var(--text-mute); align-self: center; }
[data-filter-empty] { color: var(--text-mute); font-style: italic; }
tr[hidden] { display: none; }

/* ---- protein calculator (site/js/protein-calculator.js contract) ---- */
.calc-form { display: grid; gap: 14px; max-width: 420px; }
.calc-form label { display: flex; flex-direction: column; gap: 6px; font-size: 0.88rem; color: var(--text-2); }
.calc-form input { font: inherit; padding: 9px 12px; border: 1px solid var(--border-strong); border-radius: 4px; background: var(--bg-page); color: var(--text); font-family: var(--font-mono); }
.calc-form .calc-actions { display: flex; gap: 10px; align-items: center; }
[data-calc-output] { margin-top: 6px; padding: 14px 16px; border-radius: 4px; background: var(--bg-inset); border: 1px solid var(--border); font-size: 0.94rem; }
[data-calc-output] p { margin: 0 0 6px; }
[data-calc-output] p:last-child { margin-bottom: 0; }
[data-calc-result] strong { font-family: var(--font-mono); color: var(--ember-deep); }
[data-calc-compare] { color: var(--text-dim); font-size: 0.88rem; }
[data-calc-empty] { color: var(--text-mute); font-style: italic; }

/* ---- ranking / cost-per-gram tables ---- */
tr.rank-row td.rank { font-family: var(--font-mono); color: var(--text-mute); }
.mini-bar-track { width: 70px; height: 6px; border-radius: 4px; background: var(--border); display: inline-block; vertical-align: middle; overflow: hidden; }
.mini-bar-fill { height: 100%; display: block; }

.tool-controls { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin: 22px 0; }
.tool-controls input[type="search"] {
  font: inherit; padding: 9px 12px; border: 1px solid var(--border-strong); border-radius: 4px;
  min-width: 220px; background: var(--bg-page); color: var(--text);
}
.tool-controls select {
  font: inherit; padding: 9px 12px; border: 1px solid var(--border-strong); border-radius: 4px;
  background: var(--bg-page); color: var(--text);
}
.tool-count { font-family: var(--font-mono); font-size: 0.82rem; color: var(--text-mute); }

/* ---- method callout on category / tool pages ---- */
.method-box {
  border: 1px solid var(--border-strong); border-left: 3px solid var(--ember);
  border-radius: 3px; padding: 18px 20px; background: var(--bg-alt); margin: 22px 0;
  font-size: 0.93rem; color: var(--text-dim);
}
.method-box h3 { margin: 0 0 6px; font-size: 0.95rem; color: var(--text); }

.card-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 18px; margin: 24px 0; }
.cat-card {
  border: 1px solid var(--border); border-radius: 5px; padding: 18px; background: var(--bg-page);
  text-decoration: none; color: var(--text); transition: border-color 150ms ease, transform 150ms ease;
}
.cat-card:hover { border-color: var(--ember); transform: translateY(-2px); }
.cat-card:active { transform: translateY(0); border-color: var(--ember-deep); }
@media (prefers-reduced-motion: reduce) { .cat-card { transition: none; } }
.cat-card h3 { margin: 0 0 6px; color: var(--text); }
.cat-card p { margin: 0; font-size: 0.86rem; color: var(--text-mute); }

@media (max-width: 640px) {
  .side-card { position: static; }
  .tool-controls input[type="search"] { min-width: 0; flex: 1 1 100%; }
}

/* ---- hero calls to action ---- */
.hero-actions { display: flex; flex-wrap: wrap; gap: 12px; margin: 28px 0 0; }
.btn-primary, .btn-secondary {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 12px 20px; border-radius: 4px; font-size: 0.95rem; font-weight: 600;
  text-decoration: none; border: 1px solid transparent;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
/* Same AA fix as .btn above: filled buttons rest on --ember-deep, not
   --ember, so white-on-fill clears 4.5:1 (~7:1) instead of falling short
   at ~4.3:1. */
.btn-primary { background: var(--ember-deep); color: #fff; }
.btn-primary:hover { filter: brightness(1.1); color: #fff; }
.btn-primary:active { filter: brightness(0.9); }
.btn-secondary { border-color: var(--border-strong); color: var(--text); background: var(--bg-alt); }
.btn-secondary:hover { border-color: var(--ember); color: var(--ember-deep); }
.btn-secondary:active { background: var(--ember-tint); }
.btn-primary:focus-visible, .btn-secondary:focus-visible { outline: 2px solid var(--ember); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { .btn-primary, .btn-secondary { transition: none; } }

/* =========================================================================
   Creative direction v2 — "the lab ledger"
   One motif: the verified number. Restraint everywhere else.
   ========================================================================= */

/* ---- display typography ---- */
.display {
  font-size: clamp(2.6rem, 6vw, 4.3rem);
  line-height: 1.02;
  letter-spacing: -0.042em;
  font-weight: 700;
  max-width: 13ch;
  margin: 0 0 26px;
}
.eyebrow { display: flex; align-items: center; gap: 10px; }
.eyebrow-rule { display: inline-block; width: 34px; height: 2px; background: var(--ember); }

/* ---- hero: asymmetric ledger composition ---- */
.hero-ledger {
  position: relative;
  padding: 88px 0 72px;
  background:
    repeating-linear-gradient(to bottom, transparent 0 31px, rgba(22,19,15,0.035) 31px 32px),
    var(--bg-alt, #fbfaf9);
  border-bottom: 1px solid var(--border);
  overflow: hidden;
}
.hero-grid {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(300px, 4fr);
  gap: clamp(32px, 6vw, 96px);
  align-items: center;
}
.hero-copy .lede { margin-bottom: 4px; }

/* ---- the specimen card ---- */
.specimen {
  background: var(--bg-page);
  border: 1px solid var(--border-strong);
  border-radius: 3px;
  padding: 26px 28px 20px;
  box-shadow:
    0 1px 0 rgba(22,19,15,0.04),
    0 18px 44px -18px rgba(22,19,15,0.18);
  position: relative;
  transform: rotate(0.4deg);
}
@media (prefers-reduced-motion: no-preference) {
  .specimen { transition: transform 320ms cubic-bezier(0.22, 1, 0.36, 1), box-shadow 320ms ease; }
  .specimen:hover { transform: rotate(0deg) translateY(-3px); box-shadow: 0 1px 0 rgba(22,19,15,0.04), 0 26px 56px -20px rgba(22,19,15,0.24); }
}
.specimen-head {
  display: flex; justify-content: space-between; align-items: center;
  padding-bottom: 14px; margin-bottom: 16px;
  border-bottom: 1px solid var(--border);
}
.specimen-no {
  font-family: var(--font-mono); font-size: 0.68rem; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--text-mute);
}
.stamp {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--font-mono); font-size: 0.66rem; font-weight: 600;
  letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--verified); background: var(--verified-bg);
  border: 1px solid rgba(15,110,106,0.3); border-radius: 2px;
  padding: 4px 8px;
}
.specimen-brand {
  font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--text-dim); margin: 0 0 2px;
}
.specimen-name {
  font-size: 1.5rem; font-weight: 700; letter-spacing: -0.02em;
  margin: 0 0 18px; color: var(--text);
}
.specimen-score {
  display: flex; align-items: baseline; gap: 12px;
  padding: 14px 0; margin-bottom: 6px;
  border-top: 1px solid var(--border); border-bottom: 1px solid var(--border);
}
.specimen-score-n {
  font-family: var(--font-mono); font-size: 3.4rem; font-weight: 600;
  line-height: 1; letter-spacing: -0.03em; color: var(--ember-deep);
  font-variant-numeric: tabular-nums;
}
.specimen-score-l {
  font-family: var(--font-mono); font-size: 0.64rem; line-height: 1.45;
  letter-spacing: 0.12em; text-transform: uppercase; color: var(--text-mute);
}
.specimen-rows { margin: 10px 0 14px; }
.specimen-rows > div {
  display: flex; align-items: baseline; gap: 8px;
  padding: 7px 0; font-size: 0.92rem;
}
.specimen-rows dt { color: var(--text-dim); flex-shrink: 0; }
.specimen-rows > div::before {
  content: ""; order: 2; flex: 1;
  border-bottom: 1px dotted var(--border-strong);
  transform: translateY(-4px);
}
.specimen-rows dt { order: 1; }
.specimen-rows dd {
  order: 3; margin: 0;
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-weight: 600; color: var(--text);
}
.specimen-foot {
  font-size: 0.78rem; color: var(--text-mute); margin: 0;
  padding-top: 12px; border-top: 1px solid var(--border); line-height: 1.55;
}

/* ---- stat line ---- */
.statline { border-bottom: 1px solid var(--border); background: var(--bg-page); }
.statline-wrap {
  display: grid; grid-template-columns: repeat(4, 1fr);
}
.statline-wrap > div {
  padding: 26px 8px 22px;
  border-left: 1px solid var(--border);
  display: flex; flex-direction: column; gap: 3px;
}
.statline-wrap > div:first-child { border-left: 0; padding-left: 0; }
.statline-wrap > div:not(:first-child) { padding-left: 26px; }
.stat-n {
  font-family: var(--font-mono); font-size: 2rem; font-weight: 600;
  letter-spacing: -0.02em; color: var(--text); line-height: 1;
  font-variant-numeric: tabular-nums;
}
.stat-l {
  font-family: var(--font-mono); font-size: 0.68rem; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--text-mute);
}

/* ---- ledger rows (replaces card grid) ---- */
.ledger { list-style: none; margin: 34px 0 0; padding: 0; border-top: 1px solid var(--border-strong); }
.ledger-row {
  display: grid;
  grid-template-columns: 72px minmax(0, 58ch) 1fr;
  gap: 28px; align-items: start;
  padding: 30px 0;
  border-bottom: 1px solid var(--border);
}
.ledger-no {
  font-family: var(--font-mono); font-size: 0.8rem; font-weight: 600;
  letter-spacing: 0.08em; color: var(--ember-deep); padding-top: 5px;
}
.ledger-body h3 { margin: 0 0 8px; font-size: 1.14rem; letter-spacing: -0.015em; }
.ledger-body p { margin: 0; font-family: var(--font-serif); color: var(--text-2); font-size: 0.99rem; }
.ledger-figure {
  justify-self: end; align-self: center;
  font-family: var(--font-mono); font-size: clamp(1.2rem, 2.6vw, 2rem);
  font-weight: 600; letter-spacing: -0.02em;
  color: var(--border-strong); user-select: none;
}

/* ---- buttons: instrument tactility ---- */
.btn-primary, .btn-secondary {
  border-radius: 2px;
  font-family: var(--font-mono); font-size: 0.78rem; font-weight: 600;
  letter-spacing: 0.09em; text-transform: uppercase;
  padding: 14px 22px;
}
.btn-primary { background: var(--ember-deep); }
.btn-primary:hover { background: var(--ember); }
.btn-primary:active { transform: translateY(1px); }
.btn-secondary:active { transform: translateY(1px); }

/* ---- responsive recomposition ---- */
@media (max-width: 980px) {
  .hero-grid { grid-template-columns: 1fr; gap: 40px; }
  .specimen { max-width: 440px; transform: none; }
  .statline-wrap { grid-template-columns: repeat(2, 1fr); }
  .statline-wrap > div { border-left: 0; padding-left: 0 !important; border-top: 1px solid var(--border); }
  .statline-wrap > div:nth-child(-n+2) { border-top: 0; }
  .ledger-figure { display: none; }
  .ledger-row { grid-template-columns: 52px 1fr; }
}
@media (max-width: 640px) {
  .hero-ledger { padding: 52px 0 44px; }
  .display { max-width: none; }
  .specimen { padding: 20px 20px 16px; }
  .specimen-score-n { font-size: 2.7rem; }
  .stat-n { font-size: 1.55rem; }
  .hero-actions { flex-direction: column; }
  .btn-primary, .btn-secondary { width: 100%; }
}

/* ---- brand tag: replaces the initial-circle chip ---- */
.brand-tag {
  font-family: var(--font-mono); font-size: 0.62rem; font-weight: 600;
  letter-spacing: 0.12em; color: var(--text-dim);
  border: 1px solid var(--border-strong); border-radius: 2px;
  padding: 2px 6px; flex-shrink: 0;
}
.favicon-chip { display: none; }

/* =========================================================================
   v3 — "field journal" reskin.
   Warm paper, ink, Fraunces display with real personality, Space Mono
   labels, print-weight rules, offset shadows. Overrides the layers above.
   ========================================================================= */


:root {
  --ink: #211a10;
  --paper: #f3ecdd;
  --paper-deep: #ebe2cf;
  --paper-card: #faf6ec;

  --bg-page: var(--paper);
  --bg-alt: var(--paper-deep);
  --bg-inset: var(--paper-deep);
  --bg-deep: var(--ink);

  --text: var(--ink);
  --text-2: #37301f;
  --text-dim: #57503c;
  --text-mute: #6e6650;

  --border: #cfc4a9;
  --border-strong: var(--ink);
  --border-soft: #ddd3bc;

  --font-display: 'Iowan Old Style', Georgia, serif; /* Fraunces retired 2026-09-22 */
  --font-serif: 'Iowan Old Style', Georgia, serif;
  --font-mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  --shadow-offset: 6px 6px 0 var(--ink);
  --shadow-offset-sm: 3px 3px 0 var(--ink);
}

body { background: var(--bg-page); }

/* ---- display voice: Fraunces everywhere it counts ---- */
h1, h2, .display, .specimen-name, .stat-n {
  font-family: var(--font-display);
  font-optical-sizing: auto;
}
h1, .display { font-weight: 620; letter-spacing: -0.015em; }
.display { line-height: 1.0; }
.display em, h1 em {
  font-style: italic; font-weight: 560; color: var(--ember-deep);
}
h2 { font-weight: 600; letter-spacing: -0.01em; font-size: clamp(1.5rem, 3.2vw, 2.1rem); }
h3 { font-family: var(--font-sans); }

/* ---- masthead: print rule + Fraunces wordmark ---- */
.masthead {
  background: var(--paper);
  border-bottom: 2px solid var(--ink);
  backdrop-filter: none;
}
.brand {
  font-family: var(--font-display); font-weight: 700;
  font-size: 1.22rem; letter-spacing: -0.01em;
}
.brand .mark { color: var(--ember-deep); font-style: italic; }
.nav a, .nav-links a {
  font-family: var(--font-mono); font-size: 0.72rem;
  letter-spacing: 0.13em; text-transform: uppercase;
  color: var(--text-dim);
}
.nav a.current, .nav-links a.current { color: var(--ember-deep); }
.nav-toggle { border: 2px solid var(--ink); border-radius: 0; }
.nav-toggle span { background: var(--ink); }

/* ---- hero ---- */
.hero, .hero-ledger {
  background: var(--paper);
  border-bottom: 2px solid var(--ink);
}
.hero-ledger { padding: 72px 0 64px; }
.eyebrow { color: var(--ember-deep); }
.eyebrow-rule { background: var(--ink); height: 3px; }

/* ---- specimen: index card with a hard shadow and a crooked stamp ---- */
.specimen {
  background: var(--paper-card);
  border: 2px solid var(--ink);
  border-radius: 0;
  box-shadow: var(--shadow-offset);
  transform: rotate(-0.5deg);
}
@media (prefers-reduced-motion: no-preference) {
  .specimen:hover { transform: rotate(0deg) translate(-2px, -2px); box-shadow: 8px 8px 0 var(--ink); }
}
.specimen-head { border-bottom: 1px solid var(--ink); }
.stamp {
  border: 1.5px solid var(--verified); border-radius: 0;
  transform: rotate(-2.5deg); background: transparent;
}
.specimen-name { font-size: 1.75rem; font-weight: 640; }
.specimen-score { border-color: var(--ink); }
.specimen-score-n { font-family: var(--font-display); font-weight: 700; color: var(--ember-deep); }
.specimen-rows > div::before { border-bottom: 1px dotted var(--text-mute); }
.specimen-foot { border-top: 1px solid var(--border); }

/* ---- buttons: print-poster tactility ---- */
.btn-primary, .btn-secondary {
  border-radius: 0; border: 2px solid var(--ink);
  box-shadow: var(--shadow-offset-sm);
  transition: transform 120ms ease, box-shadow 120ms ease, background 120ms ease;
}
.btn-primary { background: var(--ink); color: var(--paper); }
.btn-primary:hover { background: var(--ember-deep); color: var(--paper); }
.btn-secondary { background: var(--paper-card); color: var(--ink); }
.btn-secondary:hover { background: var(--paper-deep); color: var(--ink); border-color: var(--ink); }
.btn-primary:active, .btn-secondary:active {
  transform: translate(3px, 3px); box-shadow: 0 0 0 var(--ink);
}
@media (prefers-reduced-motion: reduce) {
  .btn-primary, .btn-secondary, .specimen { transition: none; }
}

/* ---- statline: heavy print rules, Fraunces numerals ---- */
.statline { background: var(--paper); border-bottom: 2px solid var(--ink); }
.statline-wrap > div { border-left: 1px solid var(--ink); }
.stat-n { font-size: 2.6rem; font-weight: 640; }
.stat-l { color: var(--text-dim); }

/* ---- ledger rows ---- */
.ledger { border-top: 2px solid var(--ink); }
.ledger-row { border-bottom: 1px solid var(--border); }
.ledger-no {
  font-family: var(--font-display); font-style: italic;
  font-size: 1.7rem; font-weight: 560; color: var(--ember-deep);
  padding-top: 0;
}
.ledger-figure { color: var(--border); }

/* ---- tables: journal ruling ---- */
.scroll { border: 2px solid var(--ink); border-radius: 0; background: var(--paper-card); }
th { color: var(--text-dim); border-bottom: 2px solid var(--ink); }
tbody tr:hover { background: var(--paper-deep); }
.brand-tag { border: 1.5px solid var(--ink); border-radius: 0; color: var(--ink); }

/* ---- notes / cards ---- */
.note {
  border: 2px solid var(--ink); border-left-width: 8px; border-radius: 0;
  background: var(--paper-card);
}
.note strong { color: var(--ink); }
.pillar, .method-box { border-radius: 0; background: var(--paper-card); }
.awaiting-note { border-left: 3px solid var(--ink); }

/* ---- footer: ink block, oversized sign-off ---- */
footer { background: var(--ink); color: #cfc4a9; border-top: 2px solid var(--ink); }
footer a { color: var(--paper); }
footer .wrap > p:first-child strong {
  font-family: var(--font-display); font-size: 1.6rem; font-weight: 640;
  letter-spacing: -0.01em;
}

/* ---- links: chunkier underline ---- */
a { text-decoration-thickness: 1.5px; text-underline-offset: 3px; }

/* ---- focus ring in ink ---- */
a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible {
  outline: 2px solid var(--ember-deep); border-radius: 0;
}

/* v3 nits */
.nav { gap: 30px; }
:root { --link: #8a4a1f; --link-hover: var(--ember-deep); }
a { color: var(--link); }
a:hover { color: var(--ember-deep); }
.specimen-foot a, .offer-meta a { color: var(--link); }
tbody a { color: var(--ink); text-decoration-color: var(--ember-deep); }
tbody a:hover { color: var(--ember-deep); }
.nav-links { display: inline-flex; gap: 26px; }
@media (max-width: 760px) {
  .masthead .nav .nav-links { display: none; }
}

/* =========================================================================
   v4 — texture and hand. Bricolage Grotesque for workhorse headings,
   printed-paper grain, crop marks, marquee, ghost numerals.
   ========================================================================= */


:root { --font-grotesque: 'Archivo', system-ui, sans-serif; }

/* Fraunces keeps the hero + biggest editorial moments; Bricolage takes the
   working headings so the two voices argue productively. */
h2 { font-family: var(--font-grotesque); font-weight: 700; letter-spacing: -0.025em; }
h3, .ledger-body h3 { font-family: var(--font-grotesque); font-weight: 650; letter-spacing: -0.015em; }
.specimen-name { font-family: var(--font-grotesque); font-weight: 720; letter-spacing: -0.02em; }
.btn-primary, .btn-secondary { font-family: var(--font-grotesque); font-weight: 650; letter-spacing: 0.05em; }

/* ---- printed-paper grain: one inline SVG, fixed overlay, no request ---- */
body::after {
  content: "";
  position: fixed; inset: 0; z-index: 999; pointer-events: none;
  opacity: 0.05; mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ---- crop marks: the specimen card as a print proof ---- */
.specimen { overflow: visible; }
.crop { position: absolute; width: 14px; height: 14px; pointer-events: none; }
.crop::before, .crop::after { content: ""; position: absolute; background: var(--ink); }
.crop::before { width: 14px; height: 1.5px; }
.crop::after { width: 1.5px; height: 14px; }
.crop.tl { top: -22px; left: -22px; } .crop.tl::before { bottom: 0; } .crop.tl::after { right: 0; }
.crop.tr { top: -22px; right: -22px; } .crop.tr::before { bottom: 0; } .crop.tr::after { left: 0; }
.crop.bl { bottom: -22px; left: -22px; } .crop.bl::before { top: 0; } .crop.bl::after { right: 0; }
.crop.br { bottom: -22px; right: -22px; } .crop.br::before { top: 0; } .crop.br::after { left: 0; }

/* ---- hand-drawn stroke under the hero's italic word ---- */
.uln { position: relative; white-space: nowrap; }
.uln svg {
  position: absolute; left: -2%; bottom: -0.12em; width: 104%; height: 0.28em;
  overflow: visible; pointer-events: none;
}
.uln svg path {
  fill: none; stroke: var(--ember-deep); stroke-width: 3.2; stroke-linecap: round;
  opacity: 0.85;
}

/* ---- marquee: slow mono ticker between sections ---- */
.marquee {
  border-bottom: 2px solid var(--ink);
  background: var(--ink); color: var(--paper);
  overflow: hidden; padding: 10px 0; user-select: none;
}
.marquee-track {
  display: flex; gap: 0; width: max-content;
  animation: marquee 38s linear infinite;
}
.marquee span {
  font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: 0.22em;
  text-transform: uppercase; white-space: nowrap; padding-right: 3.2em;
}
.marquee span b { color: var(--ember-bright); font-weight: 400; }
@keyframes marquee { to { transform: translateX(-50%); } }
@media (prefers-reduced-motion: reduce) {
  .marquee-track { animation: none; }
}

/* ---- ghost numerals on ledger rows ---- */
.ledger-row { position: relative; }
.ledger-no {
  font-size: 3rem; line-height: 0.9;
  opacity: 0.92;
}

/* ---- footer sign-off: oversized italic ---- */
.footer-sign {
  font-family: var(--font-display); font-style: italic; font-weight: 560;
  font-size: clamp(1.9rem, 5vw, 3.4rem); letter-spacing: -0.02em;
  color: var(--paper); margin: 0 0 18px; line-height: 1.05;
}
.footer-sign em { color: var(--ember-bright); font-style: italic; }

/* ---- illustration system ---- */
.riso {
  filter: grayscale(1) sepia(0.28) contrast(1.1) brightness(1.03);
  mix-blend-mode: multiply;
}
.spot-fig {
  justify-self: end; align-self: center;
  width: clamp(96px, 11vw, 158px); height: auto;
}
.plate-band { background: var(--paper); }
.plate {
  margin: 0; border: 2px solid var(--ink);
  background: var(--paper-card); box-shadow: var(--shadow-offset);
  padding: 14px;
}
.plate img { display: block; width: 100%; height: auto; }
.plate figcaption {
  font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: 0.08em;
  color: var(--text-dim); padding: 12px 4px 0; text-transform: uppercase;
}
@media (max-width: 980px) {
  .spot-fig { display: none; }
}
.blend { mix-blend-mode: multiply; }

/* =========================================================================
   v5 — information architecture: cards, section heads, CTA band, footer org
   ========================================================================= */

.section-head { display: flex; align-items: baseline; justify-content: space-between; gap: 20px; margin-bottom: 6px; }
.view-all {
  font-family: var(--font-mono); font-size: 0.74rem; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--ember-deep); text-decoration: none;
  border-bottom: 1.5px solid var(--ember-deep); padding-bottom: 2px; white-space: nowrap;
}
.view-all:hover { color: var(--ink); border-color: var(--ink); }

/* ---- product cards ---- */
.product-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 22px; margin-top: 26px; }
.product-card {
  display: flex; flex-direction: column; gap: 6px;
  background: var(--paper-card); border: 2px solid var(--ink);
  padding: 20px 22px 18px; text-decoration: none; color: var(--ink);
  box-shadow: var(--shadow-offset-sm);
  transition: transform 140ms ease, box-shadow 140ms ease;
}
.product-card:hover { transform: translate(-2px,-2px); box-shadow: 5px 5px 0 var(--ink); color: var(--ink); }
.product-card:active { transform: translate(2px,2px); box-shadow: 0 0 0 var(--ink); }
.pc-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; }
.pc-rank { font-size: 0.72rem; color: var(--text-mute); }
.pc-name { font-family: var(--font-grotesque); font-weight: 720; font-size: 1.35rem; letter-spacing: -0.02em; line-height: 1.1; }
.pc-cat { font-family: var(--font-mono); font-size: 0.68rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--text-dim); }
.pc-score { display: flex; align-items: baseline; gap: 10px; margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--border); }
.pc-score-n { font-family: var(--font-display); font-weight: 700; font-size: 2.3rem; line-height: 1; color: var(--ember-deep); }
.pc-score-l { font-family: var(--font-mono); font-size: 0.62rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-mute); }
.pc-link { font-family: var(--font-mono); font-size: 0.7rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ember-deep); margin-top: 10px; }

/* ---- guide cards ---- */
.guide-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 18px; margin-top: 26px; }
.guide-card {
  display: flex; flex-direction: column; gap: 8px;
  border: 1px solid var(--ink); background: var(--paper-card);
  padding: 18px 20px; text-decoration: none; color: var(--ink);
  transition: background 140ms ease;
}
.guide-card:hover { background: var(--paper-deep); color: var(--ink); }
.guide-kicker { font-family: var(--font-mono); font-size: 0.62rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--ember-deep); }
.guide-title { font-family: var(--font-grotesque); font-weight: 680; font-size: 1.05rem; letter-spacing: -0.015em; line-height: 1.25; }
.guide-desc { font-family: var(--font-serif); font-size: 0.9rem; color: var(--text-dim); line-height: 1.5; }
.guide-meta { font-size: 0.68rem; color: var(--text-mute); margin-top: auto; padding-top: 8px; }
.byline { font-family: var(--font-mono); font-size: 0.74rem; letter-spacing: 0.05em; color: var(--text-dim); margin: 10px 0 0; }
.guide-body h2 { margin-top: 40px; }
.guide-body h3 { margin-top: 28px; }
.guide-body ul { font-family: var(--font-serif); color: var(--text-2); padding-left: 22px; }
.guide-body li { margin-bottom: 8px; }
.guide-body code { font-family: var(--font-mono); font-size: 0.88em; background: var(--paper-deep); padding: 1px 5px; }

/* ---- CTA band ---- */
.cta-band { background: var(--ember-deep); border-top: 2px solid var(--ink); border-bottom: 0; padding: 64px 0; text-align: center; }
.cta-line {
  font-family: var(--font-display); font-style: italic; font-weight: 560;
  font-size: clamp(1.5rem, 3.4vw, 2.5rem); color: var(--paper);
  letter-spacing: -0.02em; margin: 0 0 26px; line-height: 1.2;
}
.btn-cream { composes: none; }
.btn-cream, .btn-ghost {
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--font-grotesque); font-weight: 650; font-size: 0.78rem;
  letter-spacing: 0.05em; text-transform: uppercase; text-decoration: none;
  padding: 14px 22px; border: 2px solid var(--ink);
}
.btn-cream { background: var(--paper); color: var(--ink); box-shadow: var(--shadow-offset-sm); }
.btn-cream:hover { background: #fff; color: var(--ink); }
.btn-ghost { background: transparent; color: var(--paper); border-color: var(--paper); }
.btn-ghost:hover { background: rgba(243,236,221,0.12); color: var(--paper); }

/* ---- footer org chart ---- */
footer { padding: 56px 0 30px; }
.footer-grid {
  display: grid; grid-template-columns: minmax(260px, 1.6fr) repeat(3, 1fr);
  gap: 40px; padding-bottom: 36px; border-bottom: 1px solid rgba(243,236,221,0.25);
}
.footer-note { font-family: var(--font-serif); font-size: 0.88rem; line-height: 1.6; color: #b3a88f; max-width: 40ch; }
.footer-col { display: flex; flex-direction: column; gap: 9px; }
.footer-head {
  font-family: var(--font-mono); font-size: 0.66rem; letter-spacing: 0.16em;
  text-transform: uppercase; color: #8f846b; margin: 0 0 4px;
}
.footer-col a { color: var(--paper); text-decoration: none; font-size: 0.92rem; }
.footer-col a:hover { color: var(--ember-bright); }
.footer-legal {
  display: flex; flex-wrap: wrap; gap: 8px 28px; padding-top: 22px;
  font-family: var(--font-mono); font-size: 0.68rem; letter-spacing: 0.04em; color: #8f846b;
}
@media (max-width: 900px) {
  .footer-grid { grid-template-columns: 1fr 1fr; }
  .footer-brand { grid-column: 1 / -1; }
  .product-row, .guide-grid { grid-template-columns: 1fr; }
}

/* =========================================================================
   v6 — product photography + alignment pass
   ========================================================================= */

/* Product images: transparent PNGs sit directly on the paper */
.pc-img {
  display: flex; align-items: center; justify-content: center;
  height: 168px; margin: -6px 0 10px;
}
.pc-img img { max-height: 100%; width: auto; max-width: 82%; object-fit: contain; filter: drop-shadow(4px 6px 0 rgba(33,26,16,0.18)); }

.row-thumb {
  width: 44px; height: 44px; object-fit: contain; flex-shrink: 0;
  background: transparent;
}
.brand-row { display: flex; align-items: center; gap: 10px; }

.product-hero { display: flex; align-items: center; gap: 40px; }
.product-photo {
  width: clamp(150px, 18vw, 240px); height: auto; object-fit: contain;
  filter: drop-shadow(6px 8px 0 rgba(33,26,16,0.18));
  flex-shrink: 0;
}
.product-hero-copy { min-width: 0; }
@media (max-width: 760px) {
  .product-hero { flex-direction: column; align-items: flex-start; gap: 18px; }
  .product-photo { width: 150px; }
}

/* ---- alignment corrections ---- */
/* Prose sections previously centered as a narrow column while every other
   section ran from the left rail — the drift read as a mistake. Constrain
   the text, not the container, so every section shares one left edge. */
.wrap.prose { max-width: var(--wrap); }
.wrap.prose > * { max-width: var(--measure); }

/* Specimen score: center the two-line mono label against the numeral */
.specimen-score { align-items: center; }

/* Card internals: keep rank chip and brand tag on one baseline */
.pc-head { align-items: baseline; }

/* Statline: uniform top alignment */
.statline-wrap > div { justify-content: flex-start; }

/* CTA band buttons share exact height */
.btn-cream, .btn-ghost { min-height: 48px; }
.btn-primary, .btn-secondary { min-height: 48px; }

/* ---- coverage: how much of the category weighting a score rests on ---- */
.cov { color: var(--text-dim); }
.cov-low { color: var(--ember-deep); }
.pc-score-l { line-height: 1.4; }

/* ---- ranking product cell on small screens: stack, give the name the row ---- */
@media (max-width: 760px) {
  .rank-row .brand-row { flex-wrap: wrap; gap: 6px 10px; }
  .rank-row .brand-row a { flex-basis: 100%; order: 3; }
  .rank-row .brand-row .row-thumb { width: 36px; height: 36px; order: 1; }
  .rank-row .brand-row .brand-tag { order: 2; }
  .rank-row td:first-child { padding-right: 6px; }
}
@media (max-width: 760px) {
  .rank-row td:nth-child(2) { min-width: 200px; }
  .rank-row .brand-row a { line-height: 1.3; }
}

/* v7 — filters as wrapped chips: 31 brands no longer stack into a column that
   pushes the ranking table below the fold. */
.filter-form { display: flex; flex-direction: column; gap: 18px; }
.filter-group { flex-direction: row; flex-wrap: wrap; gap: 8px 8px; align-items: center; }
.filter-group > span.filter-label { flex-basis: 100%; margin-bottom: 2px; }
.filter-group label { gap: 6px; padding: 5px 10px 5px 8px; border: 1.5px solid var(--ink, #211a10); background: var(--paper-2, #faf6ec); font-family: var(--font-mono); font-size: 0.74rem; letter-spacing: 0.02em; line-height: 1; cursor: pointer; box-shadow: 2px 2px 0 var(--ink, #211a10); }
.filter-group label:has(input:checked) { background: var(--ink, #211a10); color: var(--paper, #f3ecdd); }
.filter-group label input { margin: 0; accent-color: var(--ember, #a03318); }
.filter-actions { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
@media (max-width: 760px) { .filter-group label { padding: 6px 9px; font-size: 0.72rem; } }
.filter-form { align-items: flex-start; }
.filter-group { width: 100%; }
/* True-duotone spot art prints straight onto the paper: multiply removes the
   generated file's own near-white ground so the page's grain shows through.
   brightness lifts that ground to pure white first, so no box edge remains. */
.spot-fig { mix-blend-mode: multiply; filter: brightness(1.06); }

/* =========================================================================
   v8 — wayfinding: category folder tabs + ranking tiles.
   The masthead grows a second tier of literal file-folder tabs — one per
   "Best X" ranking — so the catalog's structure is visible from every page.
   ========================================================================= */

/* The 2px ink rule moves down to the tabstrip so the tabs can sit ON it. */
.masthead { border-bottom: 0; padding-bottom: 0; }
.masthead .wrap { padding-bottom: 14px; border-bottom: 1px solid var(--border); }
.masthead.is-condensed .wrap { padding-bottom: 9px; }

.tabstrip { background: var(--paper); border-bottom: 2px solid var(--ink); }
/* .masthead .wrap sets space-between + a bottom rule for the brand row;
   neither belongs on the tab tier, so this selector must outrank it. */
.masthead .tabstrip-wrap {
  display: flex; align-items: flex-end; justify-content: flex-start; gap: 6px;
  padding-top: 12px; padding-bottom: 0; border-bottom: 0;
  overflow-x: auto; scrollbar-width: none;
}
.masthead .tabstrip-wrap::-webkit-scrollbar { display: none; }
.tabstrip-label {
  font-family: var(--font-display); font-style: italic; font-weight: 560;
  font-size: 0.95rem; color: var(--ember-deep);
  padding: 0 10px 7px 0; white-space: nowrap; flex-shrink: 0;
  user-select: none;
}
.tab {
  font-family: var(--font-mono); font-size: 0.7rem; letter-spacing: 0.1em;
  text-transform: uppercase; text-decoration: none; white-space: nowrap;
  color: var(--text-dim);
  background: var(--paper-deep);
  border: 2px solid var(--ink); border-bottom: 0;
  border-radius: 4px 4px 0 0;
  padding: 8px 14px 7px;
  position: relative; flex-shrink: 0;
  transition: background 120ms ease, color 120ms ease, padding 120ms ease;
}
.tab:hover { background: var(--ink); color: var(--paper); }
/* The current tab is "open": page-colored, and it punches a hole in the
   2px rule below it so tab and page read as one sheet of paper. */
.tab.current {
  background: var(--paper); color: var(--ember-deep);
  padding-top: 11px;
}
.tab.current::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -2px;
  height: 2px; background: var(--paper);
}
.tab.current:hover { background: var(--paper); color: var(--ink); }
@media (prefers-reduced-motion: reduce) { .tab { transition: none; } }
@media (max-width: 640px) {
  .tabstrip-label { display: none; }
  .tab { font-size: 0.66rem; padding: 7px 11px 6px; }
}

/* Drawer section head, above the ranking links on mobile */
.drawer-head {
  font-family: var(--font-mono); font-size: 0.64rem; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--text-mute);
  margin: 22px 0 6px;
}

/* ---- category ranking tiles (homepage + /best/ hub) ---- */
.cat-tile-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(236px, 1fr));
  gap: 22px; margin-top: 26px;
}
.cat-tile {
  display: flex; flex-direction: column; gap: 8px;
  background: var(--paper-card); border: 2px solid var(--ink);
  box-shadow: var(--shadow-offset-sm);
  padding: 18px 20px 16px; text-decoration: none; color: var(--ink);
  transition: transform 140ms ease, box-shadow 140ms ease;
}
.cat-tile:hover { transform: translate(-2px, -2px); box-shadow: 5px 5px 0 var(--ink); color: var(--ink); }
.cat-tile:active { transform: translate(2px, 2px); box-shadow: 0 0 0 var(--ink); }
@media (prefers-reduced-motion: reduce) { .cat-tile { transition: none; } }
.ct-head { display: flex; align-items: flex-start; gap: 10px; min-height: 74px; }
.ct-count {
  font-family: var(--font-display); font-weight: 640; font-size: 2.5rem;
  line-height: 1; color: var(--ember-deep);
}
.ct-count-l {
  font-family: var(--font-mono); font-size: 0.62rem; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--text-mute); padding-top: 6px;
}
.ct-img {
  margin-left: auto; height: 74px; width: auto; max-width: 74px;
  object-fit: contain; filter: drop-shadow(3px 4px 0 rgba(33,26,16,0.18));
}
.ct-title {
  font-family: var(--font-grotesque); font-weight: 720; font-size: 1.4rem;
  letter-spacing: -0.02em; line-height: 1.1;
}
.ct-rows {
  display: flex; flex-direction: column;
  margin-top: 4px; border-top: 1px solid var(--border);
}
.ct-row {
  display: flex; align-items: baseline; gap: 8px;
  padding: 7px 0; border-bottom: 1px dotted var(--border);
  font-size: 0.85rem;
}
.ct-rank { font-size: 0.68rem; color: var(--text-mute); flex-shrink: 0; }
.ct-name {
  min-width: 0; flex: 1; overflow: hidden;
  white-space: nowrap; text-overflow: ellipsis;
  color: var(--text-2);
}
.ct-score { font-weight: 700; font-size: 0.82rem; color: var(--ember-deep); flex-shrink: 0; }
.ct-link {
  font-family: var(--font-mono); font-size: 0.68rem; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--ember-deep); margin-top: 10px;
}
@media (max-width: 900px) {
  .cat-tile-grid { grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
}

/* =========================================================================
   v9 — quiet luxury. The field-journal voice keeps its paper, Fraunces and
   ember; the hardware changes: hard 2px ink borders and offset print-block
   shadows give way to hairlines, layered ambient depth, generous radii,
   pill tabs, atmospheric gradients and compositor-thread scroll reveals.
   Deliberate, calm, expensive.
   ========================================================================= */

:root {
  /* Softened structure tokens: every component that referenced these
     inherits the new depth language without being touched. */
  --border-strong: #b5a887;
  --shadow-offset:
    0 1px 2px rgba(33, 26, 16, 0.06),
    0 10px 24px -12px rgba(33, 26, 16, 0.18),
    0 32px 64px -32px rgba(33, 26, 16, 0.22);
  --shadow-offset-sm:
    0 1px 2px rgba(33, 26, 16, 0.05),
    0 6px 16px -8px rgba(33, 26, 16, 0.14),
    0 18px 40px -24px rgba(33, 26, 16, 0.16);
  --shadow-lift:
    0 2px 4px rgba(33, 26, 16, 0.06),
    0 16px 32px -14px rgba(33, 26, 16, 0.22),
    0 44px 80px -36px rgba(33, 26, 16, 0.28);
  --radius-md: 10px;
  --radius-lg: 16px;
  --radius-xl: 22px;
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
}

html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }
::selection { background: rgba(217, 72, 42, 0.16); }

/* Paper grain stays, at a whisper. */
body::after { opacity: 0.028; }

/* ---- masthead: floating glass, hairline seams ---- */
.masthead {
  /* 0.96, not 0.88: at 0.88 product photos scrolling beneath ghosted
     through the glass strongly enough to read as a rendering bug. */
  background: rgba(243, 236, 221, 0.96);
  backdrop-filter: blur(12px) saturate(150%);
  -webkit-backdrop-filter: blur(12px) saturate(150%);
  box-shadow: 0 1px 0 rgba(33, 26, 16, 0.05);
  transition: padding 200ms ease, box-shadow 300ms ease;
}
.masthead.is-condensed { box-shadow: 0 12px 32px -20px rgba(33, 26, 16, 0.35); }
.masthead .wrap { border-bottom: 1px solid rgba(33, 26, 16, 0.08); }
.nav a, .nav-links a { letter-spacing: 0.09em; }
.nav-toggle { border: 1px solid var(--border); border-radius: 10px; }
.nav-toggle span { height: 1.5px; }

/* ---- tabs: from folder tabs to a refined pill rail ---- */
.tabstrip { background: transparent; border-bottom: 1px solid rgba(33, 26, 16, 0.08); }
.masthead .tabstrip-wrap { padding: 10px 24px 12px; align-items: center; gap: 8px; }
.tab {
  border: 1px solid transparent; border-radius: 999px;
  background: transparent; color: var(--text-dim);
  padding: 8px 16px; letter-spacing: 0.07em;
  transition: background 180ms ease, color 180ms ease, border-color 180ms ease, box-shadow 180ms ease;
}
.tab:hover { background: rgba(33, 26, 16, 0.06); color: var(--ink); }
.tab.current {
  background: var(--ink); color: var(--paper);
  padding: 8px 16px; border-color: var(--ink);
  box-shadow: 0 6px 16px -8px rgba(33, 26, 16, 0.45);
}
.tab.current::after { display: none; }
.tab.current:hover { background: var(--ink); color: var(--paper); }
.tabstrip-label { font-size: 1rem; padding-bottom: 2px; }

/* ---- hero: ruled ledger lines give way to warm atmosphere ---- */
.hero, .hero-ledger {
  background:
    radial-gradient(90rem 42rem at 88% -12%, rgba(250, 244, 230, 0.9) 0%, rgba(250, 244, 230, 0) 62%),
    radial-gradient(70rem 36rem at -10% 110%, rgba(235, 226, 207, 0.55) 0%, rgba(235, 226, 207, 0) 55%),
    var(--paper);
  border-bottom: 1px solid rgba(33, 26, 16, 0.08);
}

/* ---- the specimen card: index card becomes gallery object ---- */
.specimen {
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-offset);
  transform: none;
  padding: 30px 32px 24px;
  background: linear-gradient(175deg, #fbf7ed 0%, var(--paper-card) 100%);
}
@media (prefers-reduced-motion: no-preference) {
  .specimen:hover { transform: translateY(-4px); box-shadow: var(--shadow-lift); }
}
.crop { display: none; }
.specimen-head { border-bottom: 1px solid var(--border-soft); }
.stamp { border-radius: 999px; transform: none; border-width: 1px; padding: 5px 11px; }
.specimen-score { border-color: var(--border-soft); }

/* ---- buttons: poster blocks become tailored pills ---- */
.btn-primary, .btn-secondary, .btn-cream, .btn-ghost {
  font-family: var(--font-grotesque); font-size: 0.92rem; font-weight: 600;
  letter-spacing: 0.015em; text-transform: none;
  border-radius: 999px; padding: 13px 28px;
  border: 0; box-shadow: none;
  transition: background 180ms ease, color 180ms ease, transform 180ms var(--ease-out), box-shadow 250ms ease;
}
.btn-primary {
  background: linear-gradient(180deg, #2b2213 0%, var(--ink) 100%);
  color: var(--paper);
  box-shadow: 0 1px 2px rgba(33,26,16,0.2), 0 12px 28px -14px rgba(33, 26, 16, 0.55);
}
.btn-primary:hover {
  background: linear-gradient(180deg, #b03a1c 0%, var(--ember-deep) 100%);
  color: var(--paper); transform: translateY(-2px);
  box-shadow: 0 2px 4px rgba(33,26,16,0.18), 0 18px 36px -16px rgba(160, 51, 24, 0.55);
}
.btn-secondary {
  background: transparent; color: var(--ink);
  box-shadow: inset 0 0 0 1px var(--border-strong);
}
.btn-secondary:hover { background: var(--paper-card); color: var(--ink); transform: translateY(-2px); box-shadow: inset 0 0 0 1px var(--border-strong), var(--shadow-offset-sm); }
.btn-primary:active, .btn-secondary:active { transform: translateY(0); box-shadow: 0 1px 2px rgba(33,26,16,0.2); }
.btn-cream { background: var(--paper); color: var(--ink); box-shadow: 0 1px 2px rgba(0,0,0,0.15), 0 12px 28px -14px rgba(0, 0, 0, 0.4); }
.btn-cream:hover { background: #fffdf6; transform: translateY(-2px); }
.btn-ghost { box-shadow: inset 0 0 0 1px rgba(243, 236, 221, 0.55); border: 0; color: var(--paper); }
.btn-ghost:hover { background: rgba(243, 236, 221, 0.12); box-shadow: inset 0 0 0 1px rgba(243, 236, 221, 0.85); }
.btn {
  border-radius: 999px; padding: 11px 22px;
  font-family: var(--font-grotesque); font-weight: 600;
  box-shadow: 0 10px 24px -12px rgba(160, 51, 24, 0.5);
}

/* ---- statline: engraved hairlines ---- */
.statline { border-bottom: 1px solid rgba(33, 26, 16, 0.08); }
.statline-wrap > div { border-left: 1px solid rgba(33, 26, 16, 0.12); }
.stat-n { color: var(--ink); }

/* ---- ledger rows ---- */
.ledger { border-top: 1px solid rgba(33, 26, 16, 0.16); }
.ledger-row { border-bottom: 1px solid var(--border-soft); }

/* ---- cards: one elevated card language everywhere ---- */
.product-card, .cat-tile, .guide-card {
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-lg);
  background: linear-gradient(175deg, #fcf8ee 0%, var(--paper-card) 100%);
  box-shadow: var(--shadow-offset-sm);
  transition: transform 240ms var(--ease-out), box-shadow 300ms ease, border-color 240ms ease;
}
.product-card { padding: 24px 26px 22px; }
.cat-tile { padding: 22px 24px 20px; }
.guide-card { padding: 22px 24px; }
.product-card:hover, .cat-tile:hover, .guide-card:hover {
  transform: translateY(-5px);
  box-shadow: var(--shadow-lift);
  border-color: var(--border);
  background: linear-gradient(175deg, #fdfaf2 0%, #fbf7ec 100%);
}
.product-card:active, .cat-tile:active { transform: translateY(-1px); box-shadow: var(--shadow-offset-sm); }
/* Cut-outs carry their own silhouette, so the only treatment they need is
   the shadow that sets them off the ground. */
.pc-img img, .ct-img { filter: drop-shadow(0 10px 14px rgba(0, 0, 0, 0.35)); }
.product-photo { filter: drop-shadow(0 16px 22px rgba(0, 0, 0, 0.4)); }
.row-thumb { filter: drop-shadow(0 3px 5px rgba(0, 0, 0, 0.3)); }
.brand-tag { border: 1px solid var(--border); border-radius: 999px; padding: 3px 9px; color: var(--text-dim); }

/* ---- tables: framed like a plate, not a cage ---- */
.scroll {
  border: 1px solid var(--border-soft); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-offset-sm);
}
th { border-bottom: 1px solid var(--border); }
thead th { background: #f8f3e6; }
tbody tr:hover { background: rgba(33, 26, 16, 0.035); }

/* ---- notes, method boxes, pillars, plates ---- */
.note {
  border: 1px solid var(--border-soft); border-left: 3px solid var(--verified);
  border-radius: var(--radius-md); box-shadow: var(--shadow-offset-sm);
}
.method-box, .pillar {
  border: 1px solid var(--border-soft); border-left: 3px solid var(--ember-deep);
  border-radius: var(--radius-md);
}
.side-card { border: 1px solid var(--border-soft); border-radius: var(--radius-lg); box-shadow: var(--shadow-offset-sm); }
.plate {
  border: 1px solid var(--border-soft); border-radius: var(--radius-xl);
  box-shadow: var(--shadow-offset); padding: 18px; overflow: hidden;
}
.plate img { border-radius: calc(var(--radius-xl) - 10px); }
.signal { border-radius: var(--radius-md); border-width: 1px; border-left-width: 3px; }
.awaiting-note { border-left: 3px solid var(--border-strong); }

/* ---- filters: soft chips ---- */
.filter-form { border: 1px solid var(--border-soft); border-radius: var(--radius-lg); background: rgba(250, 246, 236, 0.6); }
.filter-group label {
  border: 1px solid var(--border); border-radius: 999px;
  background: var(--paper-card); box-shadow: none;
  padding: 6px 13px; transition: background 160ms ease, border-color 160ms ease, color 160ms ease;
}
.filter-group label:hover { border-color: var(--border-strong); }
.filter-group label:has(input:checked) { background: var(--ink); border-color: var(--ink); color: var(--paper); }
.filter-form button[type="reset"] { border-radius: 999px; }
.copy-btn { border-radius: 999px; }
.calc-form input, .filter-form select, .tool-controls input[type="search"], .tool-controls select { border-radius: 10px; border-color: var(--border); }

/* ---- CTA band: deep ember gradient with inner glow ---- */
.cta-band {
  background:
    radial-gradient(60rem 24rem at 50% -30%, rgba(242, 100, 63, 0.35) 0%, rgba(242, 100, 63, 0) 60%),
    linear-gradient(150deg, #93290f 0%, #5f1b09 100%);
  border-top: 0;
}
footer { border-top: 0; }

/* ---- score anchors ---- */
.score-anchor { border: 1px solid var(--border-soft); border-radius: var(--radius-lg); box-shadow: var(--shadow-offset-sm); background: var(--paper-card); }
.score-ring::before { background: var(--paper-card); }

/* ---- focus: same ember ring, rounded to match the new geometry ---- */
a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible {
  outline: 2px solid var(--ember-deep); outline-offset: 2px; border-radius: 8px;
}
.tab:focus-visible, .btn-primary:focus-visible, .btn-secondary:focus-visible,
.btn-cream:focus-visible, .btn-ghost:focus-visible, .filter-group label:focus-within {
  border-radius: 999px;
}

/* ---- motion: transition-based reveals only ----
   Scroll-driven view() animations were tried here and REMOVED on purpose:
   a scroll-linked animation stays applied forever, and an animated
   transform/opacity creates a persistent stacking context on the card —
   which isolates every mix-blend-mode child, so product photos stopped
   blending into the paper and rendered as white boxes. The JS reveal
   (site/assets/site.js + .reveal/.in) uses transitions instead: once a
   transition finishes it releases its stacking context and the blends
   composite against the page again. Do not reintroduce animation-timeline
   on anything that contains a blended image. */
.reveal { transition: opacity 640ms ease, transform 640ms var(--ease-out); }
/* Grid entrances stagger left-to-right */
.cat-tile-grid > .reveal:nth-child(2), .product-row > .reveal:nth-child(2), .guide-grid > .reveal:nth-child(2) { transition-delay: 70ms; }
.cat-tile-grid > .reveal:nth-child(3), .product-row > .reveal:nth-child(3), .guide-grid > .reveal:nth-child(3) { transition-delay: 140ms; }
.cat-tile-grid > .reveal:nth-child(4), .product-row > .reveal:nth-child(4), .guide-grid > .reveal:nth-child(4) { transition-delay: 210ms; }
.cat-tile-grid > .reveal:nth-child(5), .product-row > .reveal:nth-child(5), .guide-grid > .reveal:nth-child(5) { transition-delay: 280ms; }
@media print { .reveal { opacity: 1; transform: none; } }

/* ---- mobile refinements ---- */
@media (max-width: 640px) {
  .tab { padding: 7px 13px; }
  .masthead .tabstrip-wrap { padding-left: 16px; padding-right: 16px; }
}

/* ---- guide articles: a centered reading column ----
   Article pages pinned a 68ch column to the left rail and left the right
   half of a wide screen empty. The measure now centers, title block and
   body together, the way a printed essay sits on its page. */
.wrap.guide-measure { max-width: calc(70ch + 2 * var(--gutter)); }
.guide-body p, .guide-body li { font-size: 1.04rem; }

/* ---- product-card without a photo: a monogram medallion keeps the card's
   proportions instead of collapsing the image zone ---- */
.pc-img--mono span {
  width: 112px; height: 112px; border-radius: 50%;
  background: var(--paper-deep); border: 1px solid var(--border);
  display: grid; place-items: center;
  font-family: var(--font-grotesque); font-weight: 700; font-size: 2.6rem;
  color: var(--text-mute); user-select: none;
}
/* Score row pins to the card floor so a row of cards shares one baseline */
.product-card .pc-score { margin-top: auto; }

/* ---- consensus provenance: the count and source beside the score ---- */
.consensus-source {
  font-size: 0.82rem; color: var(--text-dim); line-height: 1.6;
  border-left: 3px solid var(--border-strong);
  padding: 6px 0 6px 14px; margin: 14px 0 0;
}

/* ---- composite ring: center the number and "/10" as one group ----
   The ring's grid has two auto rows; default align-content:stretch spread
   them across the full 104px circle, pinning the numeral to the top half
   and "/10" to the bottom. Pack the rows and center the pair. */
.score-ring { align-content: center; }
.score-ring .score-of { margin-top: 1px; }


/* =========================================================================
   v10 — wayfinding color + page-to-page flow.
   Each category gets one restrained accent, used only as a wayfinding mark
   (tab dot, tile numeral, tile seam) so the palette stays calm. Cross-
   document view transitions make navigation read as one continuous surface.
   ========================================================================= */

:root {
  --cat-protein-powder: #a03318;
  --cat-protein-bar: #7a4a21;
  --cat-protein-snack: #a06a15;
  --cat-pre-workout: #0f6e6a;
  --cat-energy-drink: #1b4f8f;
}

/* Tab dots: a 6px wayfinding mark per category */
.tab[class*="tab--"] { display: inline-flex; align-items: center; gap: 8px; }
.tab[class*="tab--"]::before {
  content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: var(--cat, var(--ember-deep)); flex: none;
  opacity: 0.85; transition: opacity 180ms ease;
}
.tab.current[class*="tab--"]::before { opacity: 1; box-shadow: 0 0 0 3px rgba(243, 236, 221, 0.22); }
.tab--protein-powder { --cat: var(--cat-protein-powder); }
.tab--protein-bar { --cat: var(--cat-protein-bar); }
.tab--protein-snack { --cat: var(--cat-protein-snack); }
.tab--pre-workout { --cat: var(--cat-pre-workout); }
.tab--energy-drink { --cat: var(--cat-energy-drink); }

/* Category tiles: the count numeral, top seam and link pick up the accent */
.cat-tile { position: relative; overflow: hidden; }
.cat-tile::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 3px;
  background: linear-gradient(90deg, var(--cat, var(--ember-deep)), transparent 82%);
  opacity: 0.85;
}
.cat-tile--protein-powder { --cat: var(--cat-protein-powder); }
.cat-tile--protein-bar { --cat: var(--cat-protein-bar); }
.cat-tile--protein-snack { --cat: var(--cat-protein-snack); }
.cat-tile--pre-workout { --cat: var(--cat-pre-workout); }
.cat-tile--energy-drink { --cat: var(--cat-energy-drink); }
.cat-tile .ct-count, .cat-tile .ct-link { color: var(--cat, var(--ember-deep)); }
.cat-tile .ct-score { color: var(--text-2); }
/* Pin the link to the tile's floor so a five-up row reads as one baseline */
.cat-tile .ct-link { margin-top: auto; padding-top: 12px; }

/* ---- cross-document view transitions ----
   Same-origin navigations crossfade instead of flashing white; the masthead
   is named so it holds still while the page changes under it. Browsers
   without support fall back to ordinary navigation.
   Chrome's crossfade also captures fixed overlays per-document, which makes
   the paper grain double-expose for a beat — acceptable at 0.028 opacity. */
@media (prefers-reduced-motion: no-preference) {
  @view-transition { navigation: auto; }
  .masthead { view-transition-name: masthead; }
  ::view-transition-old(root), ::view-transition-new(root) { animation-duration: 220ms; }
  ::view-transition-old(masthead), ::view-transition-new(masthead) { animation-duration: 120ms; }
}

/* ---- typography flow ---- */
p, li { text-wrap: pretty; }
.ct-name { text-wrap: initial; }



/* ---- v10.1: room to breathe ----
   The 1340px measure with 24px gutters ran wall-to-wall on a laptop.
   A narrower column inside wide, viewport-scaled gutters is the single
   cheapest signal of an expensive page: the content becomes an object
   sitting on the paper instead of filling it. */
:root { --wrap: 1680px; --gutter: clamp(24px, 3vw, 48px); }
.wrap { padding-left: var(--gutter); padding-right: var(--gutter); }
.masthead .tabstrip-wrap { padding-left: var(--gutter); padding-right: var(--gutter); }
@media (max-width: 640px) { :root { --gutter: 20px; } }
/* The narrower measure squeezed the ranking tables: slimmer cell padding
   keeps all seven columns fitting without a phantom horizontal scrollbar,
   and the product-name column stops wrapping to a word per line. */
th, td { padding: 12px 12px; }
.rank-row td:nth-child(2) { min-width: 240px; }
.rank-row .brand-row a { line-height: 1.4; }

/* ---- facet chips: "Narrow it down" on category and facet pages ---- */
.facet-chips {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  margin: 24px 0 0;
}
.facet-chips-label {
  font-family: var(--font-display); font-style: italic; font-weight: 560;
  font-size: 0.95rem; color: var(--ember-deep);
  margin-right: 6px; white-space: nowrap;
}
.facet-chip {
  font-family: var(--font-mono); font-size: 0.7rem; letter-spacing: 0.07em;
  text-transform: uppercase; text-decoration: none; white-space: nowrap;
  color: var(--text-dim); background: var(--paper-card);
  border: 1px solid var(--border); border-radius: 999px;
  padding: 7px 14px;
  transition: background 160ms ease, color 160ms ease, border-color 160ms ease;
}
.facet-chip .num { color: var(--ember-deep); margin-left: 2px; }
.facet-chip:hover { background: rgba(33, 26, 16, 0.06); border-color: var(--border-strong); color: var(--ink); }
.facet-chip.current { background: var(--ink); border-color: var(--ink); color: var(--paper); }
.facet-chip.current .num { color: var(--paper-deep); }
@media (prefers-reduced-motion: reduce) { .facet-chip { transition: none; } }

/* =========================================================================
   v11 — the command palette. Site-wide instant search (masthead button,
   "/" or Ctrl/Cmd+K) over every product, ranking, guide and tool.
   ========================================================================= */

.search-btn {
  display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--font-mono); font-size: 0.7rem; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--text-dim);
  background: var(--paper-card); border: 1px solid var(--border);
  border-radius: 999px; padding: 7px 12px 7px 14px; cursor: pointer;
  transition: border-color 160ms ease, color 160ms ease, box-shadow 200ms ease;
}
.search-btn:hover { border-color: var(--border-strong); color: var(--ink); box-shadow: var(--shadow-offset-sm); }
.search-btn kbd, .sp-foot kbd, .sp-close kbd {
  font-family: var(--font-mono); font-size: 0.62rem; line-height: 1;
  color: var(--text-mute); background: var(--paper-deep);
  border: 1px solid var(--border); border-radius: 5px; padding: 3px 5px 2px;
}
@media (max-width: 760px) {
  .search-btn { padding: 8px 10px; }
  .search-btn-label, .search-btn kbd { display: none; }
}

.search-modal { position: fixed; inset: 0; z-index: 60; display: none; }
.search-modal.open { display: block; }
html.search-open { overflow: hidden; }
.search-scrim {
  position: absolute; inset: 0;
  background: rgba(33, 26, 16, 0.42);
  backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
}
.search-panel {
  position: relative; margin: 11vh auto 0; width: min(620px, calc(100vw - 32px));
  background: var(--paper-card); border: 1px solid var(--border-soft);
  border-radius: var(--radius-xl); overflow: hidden;
  box-shadow: 0 2px 6px rgba(33,26,16,0.12), 0 40px 90px -30px rgba(33, 26, 16, 0.55);
}
@media (prefers-reduced-motion: no-preference) {
  .search-modal.open .search-panel { animation: sp-in 240ms var(--ease-out); }
  @keyframes sp-in { from { opacity: 0; transform: translateY(14px) scale(0.985); } }
}
.sp-inputrow {
  display: flex; align-items: center; gap: 12px;
  padding: 16px 18px; border-bottom: 1px solid var(--border-soft);
  color: var(--text-mute);
}
.sp-input {
  flex: 1; font: inherit; font-family: var(--font-grotesque); font-size: 1.05rem;
  color: var(--ink); background: none; border: 0; outline: none; padding: 0;
}
.sp-input::placeholder { color: var(--text-mute); }
.sp-input::-webkit-search-cancel-button { display: none; }
.sp-close { background: none; border: 0; padding: 2px; cursor: pointer; }
.sp-list {
  list-style: none; margin: 0; padding: 8px;
  max-height: min(52vh, 480px); overflow-y: auto;
}
.sp-row {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 12px; border-radius: 12px; cursor: pointer;
}
.sp-main { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
.sp-title {
  font-family: var(--font-grotesque); font-weight: 600; font-size: 0.98rem;
  color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sp-meta {
  font-family: var(--font-mono); font-size: 0.64rem; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--text-mute);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sp-score {
  font-weight: 700; font-size: 0.9rem; color: var(--ember-deep); flex: none;
}
.sp-go { color: var(--text-mute); flex: none; }
.sp-row.selected { background: var(--ink); }
.sp-row.selected .sp-title { color: var(--paper); }
.sp-row.selected .sp-meta { color: var(--border); }
.sp-row.selected .sp-score { color: var(--ember-bright); }
.sp-row.selected .sp-go { color: var(--paper); }
.sp-empty {
  padding: 22px 14px; font-family: var(--font-serif); font-style: italic;
  color: var(--text-mute); text-align: center;
}
.sp-foot {
  display: flex; align-items: center; gap: 18px;
  padding: 10px 18px; border-top: 1px solid var(--border-soft);
  font-family: var(--font-mono); font-size: 0.62rem; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--text-mute);
}
.sp-foot span { display: inline-flex; align-items: center; gap: 5px; }
.sp-foot span:last-child { margin-left: auto; letter-spacing: 0.04em; }
@media (max-width: 640px) {
  .search-panel { margin-top: 6vh; }
  .sp-foot span:last-child { display: none; }
}

/* =========================================================================
   v12 — color, turned up. The paper-and-ink identity stays; the near-
   monochrome beige does not. Sunnier paper, a vivid coral-vermilion ember,
   a saturated jade counterweight, gold for mid scores, category color on
   real surfaces instead of 6px dots only, and warm atmospheric light in
   the hero. Saturation lives in accents and washes; text contrast is
   untouched or improved.
   ========================================================================= */

:root {
  /* Paper: one step sunnier and cleaner */
  --paper: #f7efdf;
  --paper-deep: #efe4cd;
  --paper-card: #fdf8ec;
  --bg-page: var(--paper);
  --bg-alt: var(--paper-deep);
  --bg-inset: var(--paper-deep);

  /* Ember family: from muted brick to vivid coral-vermilion */
  --ember: #e2491f;
  --ember-bright: #ff6b3d;
  --ember-deep: #b23310;

  /* Jade replaces the grey teal as the cool counterweight */
  --verified: #0c7f6b;
  --verified-bg: #e4f6ef;
  --gold: #c8860a;

  /* Score buckets: same logic, richer pigments */
  --b5: var(--ember);
  --b4: #0f8b74;
  --b3: #d99a10;
  --b2: #d06a28;
  --b1: #bd3b25;

  /* Category accents: full-strength wayfinding colors */
  --cat-protein-powder: #c03a10;
  --cat-protein-bar: #8a5220;
  --cat-protein-snack: #c8860a;
  --cat-pre-workout: #0c7f6b;
  --cat-energy-drink: #2456b8;
}

/* ---- hero: warm light instead of plain cream ---- */
.hero, .hero-ledger {
  background:
    radial-gradient(80rem 38rem at 85% -10%, rgba(255, 138, 76, 0.14) 0%, rgba(255, 138, 76, 0) 58%),
    radial-gradient(60rem 32rem at -8% 108%, rgba(12, 127, 107, 0.08) 0%, rgba(12, 127, 107, 0) 55%),
    var(--paper);
}

/* ---- statline: the numbers carry the brand color ---- */
.stat-n { color: var(--ember-deep); }

/* ---- category tiles: a tinted wash of their own color ---- */
@supports (background: color-mix(in oklab, red 10%, white)) {
  .cat-tile { background: linear-gradient(175deg, color-mix(in oklab, var(--cat, var(--ember-deep)) 5%, #fdf8ec) 0%, var(--paper-card) 70%); }
  .cat-tile:hover { background: linear-gradient(175deg, color-mix(in oklab, var(--cat, var(--ember-deep)) 9%, #fdf8ec) 0%, color-mix(in oklab, var(--cat, var(--ember-deep)) 3%, #fdf8ec) 100%); }
  .cat-tile .ct-rank { color: color-mix(in oklab, var(--cat, var(--ember-deep)) 60%, var(--text-mute)); }
}
.cat-tile::before { opacity: 1; height: 4px; }

/* ---- tabs: hover takes the category's tint; the dot glows on current ---- */
@supports (background: color-mix(in oklab, red 10%, white)) {
  .tab[class*="tab--"]:hover { background: color-mix(in oklab, var(--cat, var(--ink)) 12%, transparent); color: var(--ink); }
}

/* ---- score anchors: tier color reaches the tier word and ring more boldly ---- */
.score-anchor.b5 .score-anchor-tier { color: var(--ember); }
.score-anchor.b4 .score-anchor-tier { color: var(--b4); }
.bar-fill.b5 { background: linear-gradient(90deg, var(--ember-deep), var(--ember-bright)); }
.bar-fill.b4 { background: linear-gradient(90deg, #0c7f6b, #15a98c); }
.bar-fill.b3 { background: linear-gradient(90deg, #c8860a, #eab308); }

/* ---- verified stamp and chips: jade, not grey ---- */
.chip.verified, .stamp { color: var(--verified); border-color: rgba(12, 127, 107, 0.45); background: var(--verified-bg); }

/* ---- footer: a category-color filament across the top ---- */
footer { position: relative; }
footer::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 4px;
  background: linear-gradient(90deg,
    var(--cat-protein-powder) 0 20%, var(--cat-protein-bar) 20% 40%,
    var(--cat-protein-snack) 40% 60%, var(--cat-pre-workout) 60% 80%,
    var(--cat-energy-drink) 80% 100%);
}
.footer-sign em { color: var(--ember-bright); }

/* ---- CTA band: hotter ember light ---- */
.cta-band {
  background:
    radial-gradient(64rem 26rem at 50% -32%, rgba(255, 107, 61, 0.5) 0%, rgba(255, 107, 61, 0) 62%),
    linear-gradient(150deg, #a12c0c 0%, #641b06 100%);
}

/* ---- guide cards: kicker color family + tinted hover ---- */
.guide-card:hover { background: #fbf4e3; }
.guide-kicker { color: var(--ember); }

/* ---- links inside tables & prose warm up ---- */
:root { --link: #a2481c; }

/* ---- hand-drawn underline + eyebrow rules take the vivid ember ---- */
.uln svg path { stroke: var(--ember); }
.display em, h1 em { color: var(--ember); }
.ledger-no { color: var(--ember); }
.specimen-score-n { color: var(--ember); }
.pc-score-n { color: var(--ember-deep); }

/* =========================================================================
   v13 — BOLD BLACK + RED. The warm-paper era ends here: pure white ground,
   near-black grotesque typography, one aggressive performance red. This
   layer re-tokens the whole system and overrides every literal warm value
   left in earlier layers. Commercial energy, lab-grade contrast.
   ========================================================================= */

:root {
  /* Ground: white, with cool greys for structure */
  --paper: #ffffff;
  --paper-deep: #f4f4f2;
  --paper-card: #ffffff;
  --bg-page: #ffffff;
  --bg-alt: #f7f7f5;
  --bg-inset: #f4f4f2;

  /* Ink: true near-black */
  --ink: #0b0b0c;
  --bg-deep: #0b0b0c;
  --text: #0b0b0c;
  --text-2: #1f1f21;
  --text-dim: #47474b;
  --text-mute: #6b6b70;

  --border: #e4e4e1;
  --border-soft: #ececea;
  --border-strong: #b9b9b4;

  /* Performance red */
  --ember: #e4002b;
  --ember-bright: #ff2445;
  --ember-deep: #b00022;
  --ember-tint: rgba(228, 0, 43, 0.07);

  --verified: #0a8752;
  --verified-bg: #e7f6ee;
  --link: #b00022;
  --link-hover: #7d0018;

  /* Score buckets: brand red = exceptional, green = strong, amber = middling,
     rust = weak, cold grey = poor. Worst scores read drained, not branded. */
  --b5: var(--ember);
  --b4: #0a8752;
  --b3: #d78a06;
  --b2: #a1470f;
  --b1: #77777c;

  --cat-protein-powder: #e4002b;
  --cat-protein-bar: #a16207;
  --cat-protein-snack: #ea7d00;
  --cat-pre-workout: #0a8752;
  --cat-energy-drink: #1d4fd7;

  /* Neutral, crisper elevation */
  --shadow-offset:
    0 1px 2px rgba(10, 10, 12, 0.05),
    0 10px 24px -12px rgba(10, 10, 12, 0.14),
    0 32px 64px -32px rgba(10, 10, 12, 0.18);
  --shadow-offset-sm:
    0 1px 2px rgba(10, 10, 12, 0.04),
    0 6px 16px -8px rgba(10, 10, 12, 0.10),
    0 18px 40px -24px rgba(10, 10, 12, 0.12);
  --shadow-lift:
    0 2px 4px rgba(10, 10, 12, 0.05),
    0 16px 32px -14px rgba(10, 10, 12, 0.16),
    0 44px 80px -36px rgba(10, 10, 12, 0.22);
}

/* Paper grain is over. */
body::after { display: none; }
::selection { background: rgba(228, 0, 43, 0.14); }

/* ---- type: the grotesque takes over; the serif era ends ---- */
h1, .display, h2, .brand, .stat-n, .specimen-name, .footer-sign, .cta-line,
.ledger-no, .ct-count, .tabstrip-label, .facet-chips-label {
  font-family: var(--font-grotesque);
  font-style: normal;
}
h1, .display { font-weight: 800; letter-spacing: -0.035em; }
h2 { font-weight: 750; }
.display em, h1 em { font-style: normal; font-weight: 800; color: var(--ember); }
.brand { font-weight: 800; letter-spacing: -0.03em; }
.brand .mark { color: var(--ember); font-style: normal; }
.stat-n { font-weight: 780; }
.ledger-no { font-weight: 800; font-style: normal; }
.ct-count { font-weight: 800; }
.tabstrip-label, .facet-chips-label { font-weight: 700; font-size: 0.82rem; text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-mute); }
.footer-sign, .cta-line { font-weight: 800; font-style: normal; letter-spacing: -0.02em; }
.footer-sign em, .cta-line em { font-style: normal; }
.lede, .prose p, .prose li, .ledger-body p, .guide-desc, .guide-body p, .guide-body li, .footer-note {
  font-family: var(--font-sans);
}
.specimen-score-n, .pc-score-n { font-family: var(--font-grotesque); font-weight: 800; }
.score-ring .score-num { font-family: var(--font-grotesque); font-weight: 800; }

/* ---- masthead: white glass, black rule energy ---- */
.masthead {
  background: rgba(255, 255, 255, 0.94);
  box-shadow: 0 1px 0 rgba(10, 10, 12, 0.07);
}
.masthead .wrap { border-bottom: 1px solid rgba(10, 10, 12, 0.07); }
.tabstrip { border-bottom: 1px solid rgba(10, 10, 12, 0.08); }
.nav a.current, .nav-links a.current { color: var(--ember); }
.nav a:hover { color: var(--ember); }

/* ---- hero: white with a hard red signal, not a warm wash ---- */
.hero, .hero-ledger {
  background:
    radial-gradient(70rem 34rem at 88% -12%, rgba(228, 0, 43, 0.06) 0%, rgba(228, 0, 43, 0) 55%),
    #ffffff;
  border-bottom: 1px solid var(--border);
}
.eyebrow { color: var(--ember-deep); }
.eyebrow-rule { background: var(--ember); }

/* ---- statline ---- */
.statline { border-bottom: 1px solid var(--border); }
.statline-wrap > div { border-left: 1px solid var(--border); }
.stat-n { color: var(--ink); }
.stat-l { color: var(--text-mute); }

/* ---- buttons: red is the action color ---- */
.btn-primary {
  background: linear-gradient(180deg, #ff1a3e 0%, var(--ember) 55%, #c40025 100%);
  color: #fff;
  box-shadow: 0 1px 2px rgba(10,10,12,0.18), 0 12px 28px -12px rgba(228, 0, 43, 0.55);
}
.btn-primary:hover {
  background: linear-gradient(180deg, var(--ember) 0%, #c40025 100%);
  color: #fff;
  box-shadow: 0 2px 4px rgba(10,10,12,0.16), 0 18px 36px -14px rgba(228, 0, 43, 0.6);
}
.btn-secondary { color: var(--ink); box-shadow: inset 0 0 0 1.5px var(--ink); background: #fff; }
.btn-secondary:hover { background: var(--ink); color: #fff; box-shadow: inset 0 0 0 1.5px var(--ink), var(--shadow-offset-sm); }
.btn { background: var(--ember); box-shadow: 0 10px 24px -12px rgba(228, 0, 43, 0.55); }
.btn:hover { background: var(--ember-deep); }

/* ---- tables, cards, chrome: neutral greys ---- */
thead th { background: #f6f6f4; }
tbody tr:hover { background: rgba(10, 10, 12, 0.03); }
.product-card, .cat-tile, .guide-card {
  background: #ffffff;
  border-color: var(--border);
}
.product-card:hover, .guide-card:hover { background: #fcfcfb; border-color: var(--border-strong); }
.guide-card:hover { background: #fafaf8; }
.tab:hover { background: rgba(10, 10, 12, 0.05); }
.search-scrim { background: rgba(10, 10, 12, 0.5); }
.consensus-source { border-left-color: var(--ember); }

/* Category tiles keep their tinted wash, over white */
@supports (background: color-mix(in oklab, red 10%, white)) {
  .cat-tile { background: linear-gradient(175deg, color-mix(in oklab, var(--cat, var(--ember)) 6%, #ffffff) 0%, #ffffff 70%); }
  .cat-tile:hover { background: linear-gradient(175deg, color-mix(in oklab, var(--cat, var(--ember)) 10%, #ffffff) 0%, color-mix(in oklab, var(--cat, var(--ember)) 3%, #ffffff) 100%); }
}

/* ---- illustrations: strip the sepia warmth, print black on white ---- */
.riso { filter: grayscale(1) contrast(1.12) brightness(1.04); }
.spot-fig { filter: brightness(1.06) saturate(1.15); }
.plate { background: #fff; }
.plate figcaption { color: var(--text-mute); }

/* ---- CTA band: full-bleed performance red ---- */
.cta-band {
  background:
    radial-gradient(64rem 26rem at 50% -32%, rgba(255, 60, 90, 0.55) 0%, rgba(255, 60, 90, 0) 60%),
    linear-gradient(150deg, #d40028 0%, #8a0019 100%);
}
.btn-cream { background: #fff; color: var(--ink); }
.btn-cream:hover { background: var(--ink); color: #fff; }
.btn-ghost { color: #fff; box-shadow: inset 0 0 0 1.5px rgba(255,255,255,0.7); }
.btn-ghost:hover { background: rgba(255,255,255,0.14); box-shadow: inset 0 0 0 1.5px #fff; }

/* ---- footer: black block, neutral text, red signature ---- */
footer { background: var(--ink); color: #b9b9bd; }
footer::before { height: 4px; }
.footer-sign { color: #fff; }
.footer-sign em { color: var(--ember-bright); }
.footer-note { color: #9a9aa0; }
.footer-head { color: #7c7c82; }
.footer-col a { color: #f0f0f2; }
.footer-col a:hover { color: var(--ember-bright); }
.footer-legal { color: #7c7c82; }
footer a { color: #f0f0f2; }

/* ---- specimen card: clean white instrument ---- */
.specimen { background: #ffffff; border-color: var(--border); }
.specimen-head, .specimen-score, .specimen-foot { border-color: var(--border); }
.specimen-brand { color: var(--text-mute); }

/* ---- score ring inner disc on white ---- */
.score-ring::before { background: #fff; box-shadow: inset 0 0 0 1px var(--border); }
.score-anchor { background: #fff; }
.score-anchor.b3 .score-anchor-tier { color: #b57205; }

/* ---- focus ring ---- */
a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible {
  outline-color: var(--ember);
}

/* ---- filter chips / facet chips on white ---- */
.filter-group label { background: #fff; }
.filter-group label:has(input:checked) { background: var(--ink); border-color: var(--ink); }
.facet-chip { background: #fff; }
.facet-chip .num { color: var(--ember); }
.facet-chip.current { background: var(--ink); border-color: var(--ink); }
.search-btn { background: #fff; }
.search-btn kbd, .sp-foot kbd, .sp-close kbd { background: #f4f4f2; border-color: var(--border); }
.sp-row.selected { background: var(--ink); }
.sp-row.selected .sp-score { color: var(--ember-bright); }
.sp-score { color: var(--ember); }
.filter-form { background: #fafaf9; }
[data-calc-output] { background: #f7f7f5; }
.method-box, .pillar { background: #fff; border-left-color: var(--ember); }
.note { background: #fff; }
.signal { background: var(--ember-tint); border-left-color: var(--ember); }
.signal .tag { color: var(--ember-deep); }
.side-card { background: #fff; }
.guide-body code { background: #f1f1ef; }
.awaiting-note { border-left-color: var(--border-strong); }

/* =========================================================================
   v14 — professional discipline. The templated tells go: tracked-uppercase
   monospace on every navigational element, novelty conceits, bouncy hovers.
   Mono stays where it earns its keep — data, numerals, tables. Navigation
   and actions read in sentence case like every serious product does.
   ========================================================================= */

/* ---- navigation: sentence case, real weight, no tracking ---- */
.nav a, .nav-links a {
  font-family: var(--font-grotesque);
  font-size: 0.92rem; font-weight: 600;
  letter-spacing: 0; text-transform: none;
}
.tab {
  font-family: var(--font-grotesque);
  font-size: 0.85rem; font-weight: 600;
  letter-spacing: 0; text-transform: none;
  padding: 7px 14px;
}
.tab.current { padding: 7px 14px; }
.facet-chip {
  font-family: var(--font-grotesque);
  font-size: 0.8rem; font-weight: 600;
  letter-spacing: 0; text-transform: none;
}
.search-btn {
  font-family: var(--font-grotesque);
  font-size: 0.82rem; font-weight: 600;
  letter-spacing: 0; text-transform: none;
}
.drawer-head { letter-spacing: 0.08em; }

/* ---- action links: sentence case semibold, not shouted ---- */
.pc-link, .ct-link, .view-all, .sp-foot span {
  font-family: var(--font-grotesque);
  font-weight: 600; letter-spacing: 0; text-transform: none;
}
.pc-link, .ct-link { font-size: 0.85rem; }
.view-all { font-size: 0.88rem; border-bottom-width: 2px; }
.sp-foot span { font-size: 0.72rem; color: var(--text-mute); }
.crumb { font-family: var(--font-sans); font-size: 0.8rem; letter-spacing: 0; }

/* ---- labels that stay small-caps lose the extreme tracking ---- */
.eyebrow { letter-spacing: 0.09em; }
.specimen-brand, .specimen-no { letter-spacing: 0.09em; }
.footer-head { letter-spacing: 0.1em; }
.pc-cat, .guide-kicker, .ct-count-l { letter-spacing: 0.08em; }
.stat-l { letter-spacing: 0.07em; }
.filter-group > span.filter-label { letter-spacing: 0.05em; }

/* ---- filter chips and form controls in sentence-case sans ---- */
.filter-group label { font-family: var(--font-sans); font-size: 0.85rem; letter-spacing: 0; }
.copy-btn { font-family: var(--font-grotesque); font-size: 0.82rem; }
.filter-form button[type="reset"] { font-family: var(--font-grotesque); }
[data-filter-count] { font-family: var(--font-sans); }
.tool-count { font-family: var(--font-sans); }

/* ---- restrained motion: cards settle, they don't leap ---- */
.product-card:hover, .cat-tile:hover, .guide-card:hover { transform: translateY(-2px); }
.specimen:hover { transform: translateY(-2px); }
.btn-primary:hover, .btn-secondary:hover { transform: translateY(-1px); }

/* ---- the last novelty conceits ---- */
.uln svg { display: none; }
.uln { white-space: normal; }
.ledger-figure { display: none; }

/* ---- table headers: quieter, still structured ---- */
th button[data-sort-key] { font-size: 0.74rem; letter-spacing: 0.05em; }

/* ---- awaiting note reads as body text ---- */
.awaiting-note { font-size: 0.9rem; color: var(--text-dim); }

/* =========================================================================
   v15 — the product-team look. What still read as generated: everything
   floating in rounded, shadowed cards; landing-page display sizes; glow
   gradients; a marketing band; decorative dots and filaments. Experienced
   teams ship flat, dense, hairline-divided interfaces. Radii come down to
   6-10px, shadows nearly vanish (floating UI keeps its), tabs become real
   product tabs (text + active underline), sections tighten, and the data
   moves up the page.
   ========================================================================= */

:root {
  --radius-md: 6px;
  --radius-lg: 8px;
  --radius-xl: 10px;
  --shadow-offset: 0 1px 2px rgba(10, 10, 12, 0.06);
  --shadow-offset-sm: 0 1px 2px rgba(10, 10, 12, 0.05);
  --shadow-lift: 0 4px 14px -4px rgba(10, 10, 12, 0.12);
}

/* ---- scale: down from landing page to product ---- */
.display { font-size: clamp(1.9rem, 3.6vw, 2.75rem); line-height: 1.08; letter-spacing: -0.025em; max-width: 21ch; margin-bottom: 18px; }
h1 { font-size: clamp(1.7rem, 3vw, 2.3rem); letter-spacing: -0.02em; }
h2 { font-size: clamp(1.15rem, 2vw, 1.4rem); letter-spacing: -0.015em; margin-bottom: 8px; }
.lede { font-size: 1.02rem; line-height: 1.6; }
section { padding: 44px 0; }
.hero, .hero-ledger { padding: 40px 0 36px; background: #fff; }
.hero-grid { align-items: start; gap: clamp(28px, 4vw, 64px); }
.eyebrow { font-size: 0.7rem; margin-bottom: 12px; }
.hero-actions { margin-top: 20px; }

/* ---- masthead + tabs: a real product's two-tier nav ---- */
.masthead { backdrop-filter: none; -webkit-backdrop-filter: none; background: #fff; }
.masthead .wrap { padding-top: 0; padding-bottom: 10px; }
.masthead { padding-top: 12px; }
.masthead.is-condensed { padding-top: 8px; }
.tabstrip { border-bottom: 1px solid var(--border); }
.masthead .tabstrip-wrap { padding-top: 0; padding-bottom: 0; gap: 4px; align-items: stretch; }
.tab, .tab.current {
  border: 0; border-radius: 0; background: none; box-shadow: none;
  padding: 10px 10px 9px; margin: 0;
  border-bottom: 2px solid transparent;
  color: var(--text-dim);
}
.tab:hover { background: none; color: var(--ink); border-bottom-color: var(--border-strong); }
.tab.current { color: var(--ink); border-bottom-color: var(--ember); font-weight: 700; }
.tab.current:hover { background: none; color: var(--ink); }
.tab[class*="tab--"]::before { display: none; }
.tab.current::after { display: none; }

/* ---- buttons: compact, solid, 8px — tools, not billboards ---- */
.btn-primary, .btn-secondary, .btn-cream, .btn-ghost, .btn {
  border-radius: 8px; padding: 10px 18px; font-size: 0.92rem; min-height: 0;
  transform: none !important; box-shadow: none;
}
.btn-primary { background: var(--ember); }
.btn-primary:hover { background: var(--ember-deep); box-shadow: none; }
.btn-secondary { box-shadow: inset 0 0 0 1px var(--border-strong); background: #fff; }
.btn-secondary:hover { background: #f6f6f4; color: var(--ink); box-shadow: inset 0 0 0 1px var(--ink); }
.btn { padding: 8px 14px; font-size: 0.88rem; }
.search-btn { border-radius: 8px; padding: 7px 10px 7px 12px; }
.search-btn:hover { box-shadow: none; border-color: var(--ink); }

/* ---- cards flatten: hairline borders, no float ---- */
.product-card, .cat-tile, .guide-card, .side-card, .score-anchor, .specimen,
.note, .method-box, .pillar, .filter-form, .scroll, .plate {
  border-radius: var(--radius-lg);
  box-shadow: none;
}
.product-card, .cat-tile, .guide-card { border: 1px solid var(--border); }
.product-card:hover, .cat-tile:hover, .guide-card:hover {
  transform: none; box-shadow: none;
  border-color: #c9c9c4; background: #fbfbfa;
}
.specimen { border: 1px solid var(--border); padding: 20px 22px 16px; }
@media (prefers-reduced-motion: no-preference) { .specimen:hover { transform: none; box-shadow: none; } }
.scroll { border: 1px solid var(--border); }
.side-card { border: 1px solid var(--border); }
.score-anchor { border: 1px solid var(--border); }
.filter-form { border: 1px solid var(--border); background: #fbfbfa; }
.cat-tile::before { height: 3px; }

/* ---- tiles + cards: tighter internals ---- */
.ct-count { font-size: 1.9rem; }
.ct-head { min-height: 56px; }
.ct-img { height: 56px; max-width: 56px; }
.ct-title { font-size: 1.12rem; }
.cat-tile { padding: 16px 18px 14px; gap: 6px; }
.pc-img { height: 132px; margin-bottom: 6px; }
.pc-img--mono span { width: 84px; height: 84px; font-size: 2.1rem; }
.product-card { padding: 18px 20px 16px; }
.pc-name { font-size: 1.08rem; }
.pc-score-n { font-size: 1.7rem; }
.guide-card { padding: 16px 18px; }

/* ---- statline: a metrics strip, not a billboard ---- */
.statline-wrap > div { padding: 14px 8px 12px; }
.statline-wrap > div:not(:first-child) { padding-left: 20px; }
.stat-n { font-size: 1.45rem; font-weight: 750; }
.stat-l { font-size: 0.66rem; }

/* ---- glow gradients off; flat surfaces on ---- */
.hero, .hero-ledger { background: #fff; }
.cta-band {
  background: var(--ink);
  padding: 36px 0;
}
.cta-line { font-size: clamp(1.05rem, 2vw, 1.35rem); font-weight: 700; margin-bottom: 16px; letter-spacing: -0.01em; }
.btn-cream { border-radius: 8px; padding: 9px 16px; font-size: 0.88rem; }
.btn-ghost { border-radius: 8px; padding: 9px 16px; font-size: 0.88rem; box-shadow: inset 0 0 0 1px rgba(255,255,255,0.5); }
footer::before { display: none; }
footer { padding: 36px 0 22px; }
.footer-sign { font-size: 1.3rem; margin-bottom: 10px; }
.footer-grid { padding-bottom: 22px; gap: 28px; }
.footer-col a { font-size: 0.88rem; }
.footer-note { font-size: 0.82rem; }

/* ---- chips: rectangles with a little air, not bubbles ---- */
.facet-chip { border-radius: 6px; padding: 5px 10px; }
.facet-chips { margin-top: 16px; gap: 6px; }
.filter-group label { border-radius: 6px; padding: 5px 10px; }
.filter-form button[type="reset"] { border-radius: 6px; }
.copy-btn { border-radius: 6px; }
.brand-tag { border-radius: 4px; padding: 2px 6px; }
.chip { border-radius: 5px; }
.stamp { border-radius: 5px; }
.search-btn kbd, .sp-foot kbd, .sp-close kbd { border-radius: 4px; }

/* ---- ledger rows: numbered list, quietly ---- */
.ledger-no { font-size: 1rem; font-weight: 700; color: var(--text-mute); padding-top: 3px; }
.ledger-row { padding: 20px 0; grid-template-columns: 44px minmax(0, 60ch) 1fr; gap: 18px; }
.ledger-body h3 { font-size: 1.02rem; }
.ledger-body p { font-size: 0.95rem; }
.spot-fig { width: clamp(72px, 8vw, 110px); }

/* ---- search modal keeps elevation (it floats), radius tightens ---- */
.search-panel { border-radius: 12px; box-shadow: 0 2px 6px rgba(10,10,12,0.1), 0 24px 60px -20px rgba(10, 10, 12, 0.35); }
.sp-row { border-radius: 8px; }

/* ---- product page ---- */
.product-title { font-size: clamp(1.5rem, 2.6vw, 2rem); }
.product-photo { width: clamp(120px, 13vw, 170px); }
.composite-badge .score-ring { width: 92px; height: 92px; }
.score-ring .score-num { font-size: 1.45rem; }
.consensus-source { font-size: 0.8rem; }

/* ---- section heads sit closer to their content ---- */
.section-head { margin-bottom: 2px; }
.product-row, .guide-grid, .cat-tile-grid { margin-top: 18px; gap: 16px; }
.card-grid { gap: 14px; }
/* Actions are one color; the tile's identity lives in its count and seam. */
.cat-tile .ct-link { color: var(--ember-deep); }

/* ---- masthead spans the viewport: brand hard left, nav hard right ----
   The header rows escape the content column's max-width so the logo and
   the utility nav sit at the screen edges like an application chrome;
   page content below keeps its measured column. */
.masthead > .wrap,
.masthead .tabstrip-wrap {
  max-width: none;
  padding-left: 24px;
  padding-right: 24px;
}
.masthead .nav { gap: 26px; }

/* ---- data tables: zebra scan lines, tighter rows ---- */
tbody tr:nth-child(even) td { background: #fafaf9; }
tbody tr:hover td { background: #f4f4f2; }
th, td { padding: 10px 12px; }

/* ---- v16: phone order on product pages ----
   Stacked on a phone, the headline composite has to lead; the component
   bars are its breakdown and read as noise without the total above them. */
@media (max-width: 860px) {
  .score-head { gap: 24px; }
  .score-head > .score-head-total { order: -1; }
}

/* Refine chips: one sideways-scrolling row on phones. Wrapped, a category
   with 19 facets filled the whole first screen and pushed the ranking
   itself below the fold. The label stays pinned at the row's left edge. */
@media (max-width: 640px) {
  .facet-chips {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    margin-left: -20px; margin-right: -20px;
    padding: 2px 20px 6px;
    -webkit-mask-image: linear-gradient(90deg, #000 88%, transparent);
            mask-image: linear-gradient(90deg, #000 88%, transparent);
  }
  .facet-chips::-webkit-scrollbar { display: none; }
  .facet-chip { flex: 0 0 auto; white-space: nowrap; }
  .facet-chips-label { flex: 0 0 auto; }
}

/* Filter panel: a disclosure. Open on desktop, closed on phones (site.js). */
.filter-panel > summary {
  display: flex; align-items: baseline; gap: 10px;
  cursor: pointer; list-style: none;
  font-weight: 700; font-size: 0.95rem; color: var(--ink);
  padding: 10px 0;
}
.filter-panel > summary::-webkit-details-marker { display: none; }
.filter-panel > summary::after {
  content: ""; width: 7px; height: 7px; margin-left: auto; align-self: center;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: rotate(45deg) translateY(-2px); transition: transform .15s ease;
}
.filter-panel[open] > summary::after { transform: rotate(-135deg) translateY(-2px); }
.filter-summary-meta { font-weight: 400; font-size: 0.85rem; color: var(--text-mute); }
.filter-panel > summary:focus-visible { outline: 2px solid var(--ember); outline-offset: 2px; }
@media (max-width: 640px) {
  .filter-panel { border: 1px solid var(--border, #e5e5e3); border-radius: 8px; padding: 2px 14px; }
  .filter-panel[open] { padding-bottom: 12px; }
}

/* Ranking table on phones: rank, product, composite and the category's cost
   metric stay; coverage and per-component columns (all on the product page)
   drop so the score is on screen without a sideways scroll. */
@media (max-width: 640px) {
  .rank-table th:nth-child(n+4):nth-last-child(n+2),
  .rank-table td:nth-child(n+4):nth-last-child(n+2) { display: none; }
  .rank-table th, .rank-table td { padding: 10px 8px; }
  .rank-table .rank { width: 28px; padding-left: 10px; }
  .rank-table .row-thumb { width: 40px; height: 40px; }
  .rank-table .brand-tag { font-size: 0.62rem; }
  .rank-table th { font-size: 0.66rem; letter-spacing: 0.04em; white-space: normal; line-height: 1.25; vertical-align: bottom; }
  .rank-table .rank-row td:nth-child(2) { min-width: 0; width: auto; }
  .rank-table td.n { white-space: normal; }
  .rank-table td.n .num { white-space: nowrap; }
  .rank-table .brand-row { flex-wrap: wrap; gap: 6px; }
  .rank-table th *, .rank-table th { white-space: normal !important; text-align: inherit; }
  .rank-table th.n, .rank-table td.n { text-align: right; }
  .rank-table td.n .num { font-size: 0.9rem; }
}
@media (max-width: 640px) {
  .rank-table .nd { white-space: normal; display: inline-block; font-size: 0.72rem; line-height: 1.25; max-width: 72px; text-align: right; }
}
@media (max-width: 640px) {
  .rank-table { table-layout: fixed; }
  .rank-table th:nth-child(1) { width: 34px; }
  .rank-table th:nth-child(3) { width: 90px; }
  .rank-table th:last-child { width: 74px; }
  .rank-table .brand-tag { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .rank-table td:nth-child(2) a { overflow-wrap: anywhere; }
  .rank-table th:first-child, .rank-table td.rank { padding-left: 8px; padding-right: 4px; }
  .rank-table th.n, .rank-table thead th:nth-child(n+3) { text-align: right; }
}

/* Tile rows name the brand: "Fudge Brownie" alone could be anyone's bar. */
.ct-brand { font-weight: 700; color: var(--ink); }

/* ---- v17: the hero photo and title are the buying link ----
   Both are paid links (rel="sponsored"), so each shows what it is: the photo
   reveals a label on hover/focus, the title carries an external-link mark,
   and a disclosure line sits under the heading. The title keeps its display
   type — a headline that happens to be clickable, not a body-text link. */
.product-photo-link {
  position: relative; display: inline-flex; flex-shrink: 0;
  text-decoration: none; border-radius: 4px;
  transition: transform .18s ease;
}
.product-photo-link:hover { transform: translateY(-2px); }
.product-photo-link:focus-visible { outline: 2px solid var(--ember); outline-offset: 6px; }
.photo-buy-cue {
  position: absolute; left: 50%; bottom: -6px; transform: translate(-50%, 6px);
  white-space: nowrap; padding: 5px 10px; border-radius: 3px;
  background: var(--ink); color: var(--paper);
  font-family: var(--font-mono, monospace); font-size: 0.68rem;
  letter-spacing: 0.06em; text-transform: uppercase;
  opacity: 0; pointer-events: none; transition: opacity .18s ease, transform .18s ease;
}
.product-photo-link:hover .photo-buy-cue,
.product-photo-link:focus-visible .photo-buy-cue { opacity: 1; transform: translate(-50%, 0); }
.product-title-link {
  color: inherit; text-decoration: none;
  background-image: linear-gradient(var(--ember), var(--ember));
  background-size: 0% 2px; background-repeat: no-repeat; background-position: 0 100%;
  transition: background-size .2s ease, color .2s ease;
}
.product-title-link:hover, .product-title-link:focus-visible { color: var(--ember-deep); background-size: 100% 2px; }
.product-title-link:focus-visible { outline: 2px solid var(--ember); outline-offset: 3px; }
.ext-mark { font-size: 0.6em; margin-left: 0.28em; color: var(--ember); vertical-align: super; }
.buy-note {
  margin: 8px 0 0; font-size: 0.78rem; line-height: 1.5; color: var(--text-mute);
}
@media (prefers-reduced-motion: reduce) {
  .product-photo-link, .photo-buy-cue, .product-title-link { transition: none; }
  .product-photo-link:hover { transform: none; }
}


/* ---- v18: three deviations the design audit measured ----
   1. A table that illustrates an argument sits in the argument's column.
      On /how-we-rate the .scroll wrapper is a direct child of <section>,
      so it ran to the viewport edge (left: 0) while the prose beside it
      started at the 24px gutter. */
section > .scroll {
  max-width: var(--wrap);
  margin-left: auto;
  margin-right: auto;
  padding-left: var(--gutter);
  padding-right: var(--gutter);
}
/* 2. Form controls inherit the type system — the filter panel's inputs were
      rendering in the UA default (Arial), a fourth family in a 3-family system. */
input, select, textarea { font-family: inherit; font-size: inherit; }

/* ---- v19: the surfaces the browser draws for us ----
   Selection, caret and scrollbars ship with defaults that belong to no
   design system. Selection was already themed; these are the rest. */
input, textarea, select, [contenteditable] { caret-color: var(--ember); }

/* Firefox: a thin ink thumb on the paper track. */
html { scrollbar-color: rgba(11, 11, 12, 0.32) transparent; }
.scroll { scrollbar-width: thin; scrollbar-color: rgba(11, 11, 12, 0.28) transparent; }

/* WebKit: the table scroller is the one people actually grab. */
.scroll::-webkit-scrollbar { height: 10px; }
.scroll::-webkit-scrollbar-track { background: transparent; }
.scroll::-webkit-scrollbar-thumb {
  background: rgba(11, 11, 12, 0.22);
  border: 3px solid var(--paper);
  border-radius: 999px;
}
.scroll:hover::-webkit-scrollbar-thumb { background: rgba(11, 11, 12, 0.38); }

/* Selection on the ink footer and the ember CTA band: a 14% red tint over
   near-black is invisible, so those surfaces carry their own pair. */
footer ::selection, footer::selection { background: rgba(228, 0, 43, 0.55); color: #fff; }
.cta-band ::selection, .cta-band::selection { background: rgba(255, 255, 255, 0.28); color: #fff; }

/* ---- v20: touch targets on phones ----
   The search button (30px), menu toggle (34px) and facet chips (33px) are
   correctly sized for the eye and too small for a thumb. The hit area is
   expanded to 44px with a pseudo-element so the drawn control is untouched;
   pointer: coarse keeps mouse users out of it entirely. */
@media (max-width: 860px) and (pointer: coarse) {
  /* Chips live in a horizontal scroller, which clips any overflow — they
     get real height instead of a phantom hit area. */
  .facet-chip { min-height: 40px; display: inline-flex; align-items: center; gap: 4px; }
  .search-btn, .nav-toggle, .tab { position: relative; }
  .search-btn::after, .nav-toggle::after, .tab::after {
    content: "";
    position: absolute;
    left: 0; right: 0; top: 50%;
    height: 44px;
    transform: translateY(-50%);
  }
  /* The tabstrip's active underline is drawn with ::after — keep it. */
  .tab::after { height: 44px; background: none; }
}

/* The menu toggle was the last element rendering in a UA default face. */
button { font-family: inherit; }

/* ---- v21: value context strip ----
   Where this product's cost sits among everything scored in its category.
   The SVG is geometry only — x stretches to the column, non-scaling strokes
   hold every hairline at its authored width, and all type is real HTML at a
   real font size. Population marks are recessive ink; the focal mark is the
   only ember in the figure and carries a direct label. */
.value-strip { margin: 26px 0 0; padding: 0; }
.vs-head {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  margin-bottom: 20px;
}
.vs-title {
  font-family: var(--font-mono); font-size: 0.68rem; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--text-mute);
}
.vs-basis { font-family: var(--font-mono); font-size: 0.68rem; color: var(--text-mute); }
.vs-plot { position: relative; }
.value-strip svg {
  display: block; width: 100%; height: 44px; overflow: visible;
}
.value-strip svg line { vector-effect: non-scaling-stroke; }
.vs-axis { stroke: var(--border); stroke-width: 1; }
.vs-tick { stroke: var(--ink); stroke-width: 1.5; opacity: 0.2; transition: opacity .12s ease; }
.vs-tick:hover { opacity: 0.65; }
.vs-median { stroke: var(--ink); stroke-width: 1.5; opacity: 0.4; stroke-dasharray: 3 3; }
.vs-focal { stroke: var(--ember); stroke-width: 3; }
/* Direct label, pinned to the focal mark and kept inside the plot at both ends. */
.vs-flag {
  position: absolute; top: -17px;
  left: clamp(2.2rem, var(--focal), calc(100% - 2.2rem));
  transform: translateX(-50%);
  font-family: var(--font-mono); font-size: 0.82rem; font-weight: 700;
  color: var(--ember-deep); font-variant-numeric: tabular-nums; white-space: nowrap;
}
.vs-median-label {
  position: absolute; bottom: -16px;
  left: clamp(1.6rem, var(--median), calc(100% - 1.6rem));
  transform: translateX(-50%);
  font-family: var(--font-mono); font-size: 0.62rem; letter-spacing: 0.06em;
  color: var(--text-mute); white-space: nowrap;
}
.vs-foot {
  display: flex; align-items: baseline; justify-content: space-between; gap: 16px;
  margin-top: 24px;
  font-family: var(--font-mono); font-size: 0.7rem; color: var(--text-mute);
  font-variant-numeric: tabular-nums;
}
.vs-read {
  font-family: var(--font-sans); font-size: 0.85rem; color: var(--text-dim);
  text-align: center; flex: 1 1 auto; min-width: 0;
}
.vs-read strong { color: var(--ink); font-weight: 700; }
.vs-end { flex: 0 0 auto; }
@media (max-width: 640px) {
  .vs-foot { flex-wrap: wrap; row-gap: 6px; }
  .vs-read { order: 2; flex: 1 0 100%; text-align: left; }
}

/* ---- v22: product buy bar ----
   Slides up once the hero has left the screen. Paper on ink hairline, the
   score in mono, one ember button — the same destination as the hero links,
   never a second offer. */
.buybar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
  background: var(--paper);
  border-top: 1px solid var(--border-strong);
  box-shadow: 0 -6px 24px -18px rgba(11, 11, 12, 0.5);
  transform: translateY(101%);
  transition: transform .26s cubic-bezier(0.22, 1, 0.36, 1);
}
.buybar.is-on { transform: translateY(0); }
.buybar-in {
  display: flex; align-items: center; gap: 16px;
  padding-top: 10px; padding-bottom: 10px;
}
.buybar-id { display: flex; flex-direction: column; min-width: 0; flex: 1 1 auto; }
.buybar-brand {
  font-family: var(--font-mono); font-size: 0.62rem; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--text-mute);
}
.buybar-name {
  font-weight: 700; font-size: 0.95rem; color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.buybar-score { display: flex; align-items: baseline; gap: 4px; flex: 0 0 auto; }
.buybar-score .num { font-size: 1.15rem; font-weight: 700; color: var(--ink); }
.buybar-score-l { font-family: var(--font-mono); font-size: 0.62rem; color: var(--text-mute); }
.buybar-cta { flex: 0 0 auto; white-space: nowrap; }
@media (max-width: 520px) {
  .buybar-score { display: none; }
  .buybar-name { font-size: 0.88rem; }
}
@media (prefers-reduced-motion: reduce) { .buybar { transition: none; } }

/* ---- v23: compare tray + side-by-side panel ----
   Opt-in selection on a ranking, a tray of picks, and a panel that puts the
   published numbers in columns. Same ledger language: hairlines, mono
   figures, one ember action. */
.compare-bar {
  display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap;
  margin: 0 0 14px;
}
.btn-ghost {
  background: var(--paper); color: var(--ink);
  border: 1px solid var(--border-strong); border-radius: 8px;
  padding: 7px 14px; font-weight: 600; font-size: 0.88rem; cursor: pointer;
  transition: background .16s ease, border-color .16s ease, color .16s ease;
}
.btn-ghost:hover { border-color: var(--ink); }
.btn-ghost[aria-pressed="true"] { background: var(--ink); color: var(--paper); border-color: var(--ink); }
.compare-hint { font-size: 0.82rem; color: var(--text-mute); }
.rank-table.is-selecting td.rank { white-space: nowrap; }
.row-pick { margin-right: 8px; vertical-align: middle; accent-color: var(--ember); }
.rank-table.is-selecting tbody tr:hover td { background: var(--ember-tint); }

.compare-tray {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 45;
  background: var(--ink); color: var(--paper);
  transform: translateY(101%);
  transition: transform .26s cubic-bezier(0.22, 1, 0.36, 1);
}
.compare-tray.is-on { transform: translateY(0); }
.compare-tray.is-full { animation: ct-nudge .36s ease; }
@keyframes ct-nudge { 50% { transform: translateY(-6px); } }
.ct-in { display: flex; align-items: center; gap: 14px; padding-top: 12px; padding-bottom: 12px; }
.ct-count {
  font-family: var(--font-mono); font-size: 0.7rem; letter-spacing: 0.06em;
  color: rgba(255, 255, 255, 0.62); flex: 0 0 auto;
}
.ct-count .num { color: var(--paper); font-size: 0.95rem; }
.ct-chips { display: flex; gap: 8px; flex: 1 1 auto; min-width: 0; overflow-x: auto; scrollbar-width: none; }
.ct-chips::-webkit-scrollbar { display: none; }
.ct-chip {
  display: inline-flex; align-items: center; gap: 8px; flex: 0 0 auto;
  border: 1px solid rgba(255, 255, 255, 0.22); border-radius: 6px;
  padding: 5px 6px 5px 10px; font-size: 0.85rem; white-space: nowrap;
}
.ct-chip-brand {
  font-family: var(--font-mono); font-size: 0.58rem; letter-spacing: 0.08em;
  text-transform: uppercase; color: rgba(255, 255, 255, 0.55);
}
.ct-x {
  background: none; border: 0; color: rgba(255, 255, 255, 0.65);
  font-size: 1.05rem; line-height: 1; cursor: pointer; padding: 0 4px;
}
.ct-x:hover { color: var(--ember-bright); }
.ct-go { flex: 0 0 auto; }
.ct-go[disabled] { opacity: 0.45; cursor: not-allowed; }

.compare-panel { position: fixed; inset: 0; z-index: 60; display: grid; place-items: center; }
.cp-scrim { position: absolute; inset: 0; background: rgba(11, 11, 12, 0.55); }
.cp-card {
  position: relative; background: var(--paper); border: 1px solid var(--border-strong);
  border-radius: 10px; width: min(1100px, calc(100vw - 32px)); max-height: calc(100vh - 64px);
  display: flex; flex-direction: column; box-shadow: 0 24px 60px -30px rgba(11, 11, 12, 0.6);
  animation: cp-rise .22s cubic-bezier(0.22, 1, 0.36, 1);
}
@keyframes cp-rise { from { opacity: 0; transform: translateY(10px); } }
.cp-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 16px 20px; border-bottom: 1px solid var(--border);
}
.cp-head h2 { margin: 0; font-size: 1.15rem; }
.cp-close {
  background: none; border: 0; font-size: 1.6rem; line-height: 1;
  color: var(--text-dim); cursor: pointer; padding: 0 4px;
}
.cp-close:hover { color: var(--ink); }
.cp-body { overflow: auto; padding: 8px 20px 20px; }
.cp-table { width: 100%; }
.cp-table th[scope="col"] { vertical-align: bottom; text-align: left; }
.cp-table th[scope="row"] { text-align: left; font-weight: 600; color: var(--text-dim); white-space: nowrap; }
.cp-brand {
  display: block; font-family: var(--font-mono); font-size: 0.58rem;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-mute);
}
.cp-table td { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.cp-best { position: relative; }
.cp-best .num, .cp-best { color: var(--ink); font-weight: 700; }
.cp-flag {
  display: inline-block; margin-left: 6px; font-family: var(--font-mono);
  font-size: 0.55rem; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--ember-deep);
}
.cp-note { font-size: 0.8rem; color: var(--text-mute); margin: 14px 0 0; }
body.has-modal { overflow: hidden; }
@media (prefers-reduced-motion: reduce) {
  .compare-tray, .cp-card { transition: none; animation: none; }
}

/* Ranking header sticks under the masthead so the column you are reading
   keeps its name through 71 rows. sticky resolves against the nearest scroll
   container, so this table deliberately has none: instead of a horizontal
   scroller it sheds its most secondary column (Coverage) at the widths where
   seven columns will not fit. Nothing is ever clipped out of reach. */
.rank-wrap { width: 100%; }
.rank-table thead th {
  position: sticky; top: 84px; z-index: 2;
  background: var(--paper);
  box-shadow: inset 0 -1px 0 var(--border-strong);
}
@media (max-width: 1099px) {
  .rank-table thead th:nth-child(4), .rank-table tbody td:nth-child(4) { display: none; }
}
@media (max-width: 860px) { .rank-table thead th { top: 100px; } }
@media (max-width: 640px) { .rank-table thead th { top: 96px; } }
@media (max-width: 1099px) {
  /* Long metric headers ("$ / dosed serving") were forcing the table past
     its column; let them wrap and give the product cell less floor. */
  .rank-table th, .rank-table th * { white-space: normal; }
  .rank-table th { vertical-align: bottom; line-height: 1.25; }
  .rank-table .rank-row td:nth-child(2) { min-width: 170px; }
}
@media (max-width: 1099px) {
  /* Same two space hogs as on phones: the "not enough data" phrase setting a
     numeric column's floor, and a brand tag that refuses to wrap. */
  .rank-table .nd {
    display: inline-block; max-width: 84px; white-space: normal;
    font-size: 0.72rem; line-height: 1.25; text-align: right;
  }
  .rank-table .brand-row { flex-wrap: wrap; gap: 6px; }
  .rank-table .brand-tag { max-width: 100%; }
}

/* ============================================================
   v24 — the front page carries its weight
   The hero showed one sample record and a modest headline. It now opens
   with display type at magazine scale and the whole catalog drawn as a
   distribution, and the coverage numbers sit in a full-bleed ink band.
   ============================================================ */

/* ---- hero: bigger type, more air, a heavier opening rule ---- */
.hero-ledger { padding-top: 52px; padding-bottom: 44px; }
.hero-ledger .display {
  font-size: clamp(2.6rem, 5.4vw, 4.4rem);
  line-height: 1.02;
  letter-spacing: -0.04em;
  margin-bottom: 20px;
}
.hero-ledger .lede { font-size: clamp(1.02rem, 1.35vw, 1.18rem); line-height: 1.62; max-width: 46ch; }
.hero-ledger .hero-actions { margin-top: 28px; }
.hero-grid { align-items: center; }

/* ---- catalog spectrum: every published score, in one picture ---- */
.catalog-spectrum {
  margin: 0; padding: 22px 24px 18px;
  border: 1px solid var(--border-strong); border-radius: 10px;
  background: var(--paper);
}
.cs-head, .cs-foot { display: flex; align-items: baseline; justify-content: space-between; gap: 14px; }
.cs-title {
  font-family: var(--font-mono); font-size: 0.68rem; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--text-mute);
}
.cs-n { font-family: var(--font-mono); font-size: 0.72rem; color: var(--text-mute); }
.cs-n .num { color: var(--ink); font-size: 0.95rem; font-weight: 700; }
.cs-plot {
  display: flex; align-items: flex-end; gap: 3px;
  height: 148px; margin: 18px 0 8px;
}
.cs-bar {
  position: relative; flex: 1 1 0; min-width: 0;
  height: var(--h); min-height: 2px;
  background: var(--ink); opacity: 0.16;
  border-radius: 2px 2px 0 0;
  transition: opacity .16s ease, transform .16s ease;
}
.cs-bar:hover { opacity: 0.4; }
.cs-bar.is-top { background: var(--ember); opacity: 1; }
.cs-bar.is-top:hover { opacity: 0.85; }
/* A generous hit area so a 6px bar is still pointable. */
.cs-hit { position: absolute; inset: -8px -2px -8px -2px; }
.cs-axis {
  display: flex; justify-content: space-between;
  font-family: var(--font-mono); font-size: 0.62rem; color: var(--text-mute);
  border-top: 1px solid var(--border); padding-top: 6px;
}
.cs-foot { margin-top: 14px; font-size: 0.78rem; }
.cs-median { font-family: var(--font-mono); color: var(--text-mute); }
.cs-median .num { color: var(--ink); font-weight: 700; }
.cs-top {
  color: var(--ink); text-decoration: none; font-weight: 600; text-align: right;
  border-bottom: 1px solid transparent;
}
.cs-top:hover { border-bottom-color: var(--ember); }
.cs-top-l {
  font-family: var(--font-mono); font-size: 0.6rem; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--text-mute); display: block;
}
.cs-top .num { color: var(--ember-deep); font-weight: 700; margin-left: 4px; }

/* ---- coverage band: ink, full bleed, numerals at scale ---- */
.statline { background: var(--ink); border-bottom: 0; border-top: 1px solid var(--ink); }
.statline .statline-wrap > div { border-left: 1px solid rgba(255, 255, 255, 0.14); padding-top: 22px; padding-bottom: 20px; }
.statline .statline-wrap > div:first-child { border-left: 0; }
.statline .stat-n { color: var(--paper); font-size: clamp(1.6rem, 2.6vw, 2.3rem); }
.statline .stat-l { color: rgba(255, 255, 255, 0.55); }

@media (max-width: 860px) {
  .hero-ledger { padding-top: 34px; }
  .catalog-spectrum { margin-top: 28px; }
  .cs-plot { height: 108px; }
}

/* ---- v25: the leaders, before the table ----
   A ranking page used to open on a header row. The top three now sit above
   it as cards: rank numeral, product, composite, and the category's cost
   metric. #1 carries the only ember. */
.podium {
  list-style: none; margin: 0 0 26px; padding: 0;
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px;
}
.podium-card {
  border: 1px solid var(--border); border-radius: 10px; background: var(--paper);
  transition: border-color .16s ease, transform .16s ease;
}
.podium-card:hover { border-color: var(--border-strong); transform: translateY(-2px); }
.podium-card.is-first { border-color: var(--ink); }
.podium-card > a {
  display: grid; grid-template-columns: auto 1fr; align-items: center; gap: 14px;
  padding: 16px; text-decoration: none; color: inherit; height: 100%;
}
.pod-rank {
  font-size: 1.5rem; font-weight: 700; color: var(--border-strong);
  line-height: 1; align-self: start;
}
.is-first .pod-rank { color: var(--ember); }
.pod-img { grid-row: span 1; display: block; width: 62px; }
.pod-img img { width: 62px; height: 62px; object-fit: contain; display: block; }
.pod-body { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.pod-name {
  font-weight: 700; font-size: 0.98rem; line-height: 1.25; color: var(--ink);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.pod-figs { display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap; margin-top: 4px; }
.pod-score { font-size: 1.32rem; font-weight: 700; color: var(--ink); }
.pod-score-l, .pod-metric-l {
  font-family: var(--font-mono); font-size: 0.58rem; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--text-mute);
}
.pod-metric { font-size: 0.92rem; color: var(--text-dim); margin-left: 8px; }
/* A row you are pointing at gets an ember edge — the table's only hover mark. */
.rank-table tbody tr { box-shadow: inset 3px 0 0 transparent; transition: box-shadow .12s ease; }
.rank-table tbody tr:hover { box-shadow: inset 3px 0 0 var(--ember); }
@media (max-width: 900px) {
  .podium { grid-template-columns: 1fr; gap: 10px; }
  .podium-card > a { padding: 12px 14px; }
  .pod-img, .pod-img img { width: 48px; height: 48px; }
}

/* ============================================================
   v26 — a voice of its own
   The old trio (Bricolage / DM Sans / Space Mono) is the default Google
   pairing that lands on every generated site. This is a broadsheet setup
   instead: a high-contrast serif for display, a grotesque with grit for
   text, and an engineering mono for anything measured. The palette cools
   and deepens with it — blue-black ink, cool greys, the ember kept as the
   single action colour and a deeper green reserved for verification.
   ============================================================ */
@font-face {
  font-family: 'Instrument Serif';
  font-style: normal; font-weight: 400; font-display: swap;
  src: url('/fonts/instrument-serif.woff2') format('woff2');
}
@font-face {
  font-family: 'Instrument Serif';
  font-style: italic; font-weight: 400; font-display: swap;
  src: url('/fonts/instrument-serif-italic.woff2') format('woff2');
}
@font-face {
  font-family: 'Archivo';
  font-style: normal; font-weight: 400 800; font-display: swap;
  src: url('/fonts/archivo-var.woff2') format('woff2-variations'), url('/fonts/archivo-var.woff2') format('woff2');
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal; font-weight: 400; font-display: swap;
  src: url('/fonts/plex-mono.woff2') format('woff2');
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal; font-weight: 600; font-display: swap;
  src: url('/fonts/plex-mono-600.woff2') format('woff2');
}

:root {
  --font-display: 'Instrument Serif', 'Iowan Old Style', Georgia, serif;
  --font-grotesque: 'Archivo', 'Segoe UI', system-ui, sans-serif;
  --font-sans: 'Archivo', 'Segoe UI', system-ui, sans-serif;
  --font-mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  /* Ink carries a blue cast — reads colder and more instrument-like than a
     neutral black, and separates the page from warm-grey AI defaults. */
  --ink: #0a0d14;
  --bg-deep: #0a0d14;
  --text: #0a0d14;
  --text-2: #1c212b;
  --text-dim: #444c5c;
  --text-mute: #656d7c;

  /* Cool surfaces, not warm. */
  --paper: #ffffff;
  --paper-card: #ffffff;
  --bg-page: #ffffff;
  --bg-alt: #f6f7f9;
  --bg-inset: #f1f3f7;
  --paper-deep: #f1f3f7;
  --border: #e3e6ec;
  --border-soft: #eceff4;
  --border-strong: #b2b9c6;

  /* The action colour stays; the deep step gains a touch more blue so it
     sits with the new ink instead of against it. */
  --ember: #e4002b;
  --ember-bright: #ff2445;
  --ember-deep: #b00024;
  --ember-tint: rgba(228, 0, 43, 0.06);
  --link: #b00024;
  --link-hover: #7d0019;

  --verified: #0e7c66;
  --verified-bg: #e6f5f1;
}

/* ---- display: the serif takes the headlines and the masthead ---- */
h1, .display, .brand, .hero-ledger .display, .cta-line, .footer-sign {
  font-family: var(--font-display);
  font-weight: 400;
  letter-spacing: -0.015em;
}
h1, .display, .hero-ledger .display { line-height: 1.02; }
.hero-ledger .display { font-size: clamp(2.9rem, 6vw, 5rem); }
h1 { font-size: clamp(2.2rem, 4vw, 3.1rem); }
.display em, h1 em { font-style: italic; color: var(--ember); font-weight: 400; }
.brand { font-size: 1.32rem; letter-spacing: -0.01em; font-weight: 400; }
.brand .mark { color: var(--ember); }

/* Subheads stay grotesque: the serif leads, Archivo organises. */
h2, h3, h4, .pod-name, .pc-name, .ct-name {
  font-family: var(--font-grotesque);
  font-weight: 700;
  letter-spacing: -0.012em;
}
h2 { font-size: clamp(1.25rem, 1.9vw, 1.5rem); }

/* Body copy gains a touch more size and a tighter measure than DM Sans had. */
body { font-family: var(--font-sans); }
.prose > p, .prose > ul, .prose > ol { font-size: 1.02rem; line-height: 1.66; }

/* Every measured figure is Plex Mono with tabular figures. */
.num, td.n, th.n, .vs-flag, .cs-n .num, .stat-n {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1, 'zero' 1;
}
.stat-n { font-weight: 600; letter-spacing: -0.02em; }
.eyebrow, .vs-title, .cs-title, .brand-tag, .pod-score-l, .pod-metric-l,
.buybar-brand, .ct-chip-brand, .cp-brand, .filter-label, .tabstrip-label {
  font-family: var(--font-mono); font-weight: 400;
}

/* ============================================================
   v27 — ledger composition: rules, not boxes
   Every block on this site had become a rounded rectangle with a hairline
   border — the card grid is the most machine-designed pattern there is.
   Structure now comes from rules and columns the way a printed ledger or a
   broadsheet does: a heavy rule opens a section, hairlines divide columns,
   and the only remaining boxes are the ones that are genuinely a unit you
   act on (offers, the compare panel).
   ============================================================ */

/* ---- hero: headline runs the full measure, the row beneath is asymmetric ---- */
.hero-ledger { padding-top: 40px; padding-bottom: 0; }
.hero-grid {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  grid-template-areas: "eyebrow eyebrow" "head head" "copy visual";
  column-gap: clamp(32px, 5vw, 72px);
  row-gap: 0;
  align-items: start;
}
.hero-eyebrow { grid-area: eyebrow; margin-bottom: 18px; }
.hero-head {
  grid-area: head;
  font-size: clamp(3rem, 7.6vw, 6.4rem);
  line-height: 0.96;
  letter-spacing: -0.022em;
  margin: 0 0 34px;
  max-width: 18ch;
}
.hero-copy { grid-area: copy; padding-top: 26px; border-top: 1px solid var(--border); }
.hero-ledger .lede { font-size: 1.06rem; line-height: 1.6; max-width: 42ch; color: var(--text-dim); }
.hero-ledger .hero-actions { margin-top: 24px; }
.catalog-spectrum { grid-area: visual; }

/* The spectrum loses its box: a 2px ink rule opens it, like a figure in a
   report, and the plot sits directly on the paper. */
.catalog-spectrum {
  border: 0; border-radius: 0; background: none;
  padding: 26px 0 0; margin: 0;
  border-top: 2px solid var(--ink);
}
.cs-plot { height: 168px; gap: 4px; }
.cs-bar { border-radius: 0; }
.cs-foot { border-top: 1px solid var(--border); padding-top: 12px; }

/* ---- sections open with a rule and a mono label ---- */
.section-rule {
  border-top: 2px solid var(--ink);
  padding-top: 14px; margin-bottom: 26px;
  display: flex; align-items: baseline; justify-content: space-between; gap: 16px;
}
.section-rule h2 { margin: 0; }
.section-rule .sr-meta {
  font-family: var(--font-mono); font-size: 0.7rem; letter-spacing: 0.06em;
  color: var(--text-mute); text-transform: uppercase;
}

/* ---- podium: three ruled columns, not three cards ---- */
.podium { gap: 0; border-top: 2px solid var(--ink); }
.podium-card {
  border: 0; border-radius: 0; background: none;
  border-left: 1px solid var(--border);
  padding: 0;
}
.podium-card:first-child { border-left: 0; }
.podium-card:hover { transform: none; border-color: var(--border); }
.podium-card > a {
  grid-template-columns: auto 1fr;
  align-items: start; gap: 12px;
  padding: 20px clamp(14px, 1.6vw, 22px);
}
.podium-card:first-child > a { padding-left: 0; }
.podium-card.is-first { border-color: var(--border); }
/* The rank is a display numeral, set in the serif at a size that reads as
   composition rather than a badge. */
.pod-rank {
  font-family: var(--font-display); font-weight: 400;
  font-size: clamp(2.2rem, 3.4vw, 3.2rem); line-height: 0.8;
  color: var(--border-strong);
}
.is-first .pod-rank { color: var(--ember); }
.podium-card > a:hover .pod-name { color: var(--ember-deep); }
.pod-name { transition: color .14s ease; }

/* ---- category tiles: an index, ruled, not a row of boxes ---- */
.cat-tile {
  border: 0; border-radius: 0; background: none;
  border-top: 1px solid var(--border);
  padding: 18px 0 16px;
}
.cat-tile:hover { background: none; transform: none; }
.cat-tile:hover .ct-name { color: var(--ember-deep); }

/* ---- notes and method boxes: a rule on the left, nothing else ---- */
.note, .method-box {
  border-radius: 0; background: none;
  border-top: 0; border-right: 0; border-bottom: 0;
  border-left: 2px solid var(--border-strong);
  padding: 4px 0 4px 18px;
}
.note { border-left-color: var(--verified); }

/* ---- the ranking table reads as a ledger: column rules, heavy bounds ---- */
.rank-table { border-top: 2px solid var(--ink); }
.rank-table thead th { box-shadow: inset 0 -1px 0 var(--ink); }
.rank-table tbody td + td { border-left: 1px solid var(--border-soft); }
.rank-table tbody tr:last-child td { border-bottom: 1px solid var(--border-strong); }

/* ---- home product cards keep an edge only where they are a unit ---- */
.product-card { border-radius: 0; border-color: var(--border); }
.product-card:hover { border-color: var(--ink); }
.guide-card { border-radius: 0; }

@media (max-width: 900px) {
  .hero-grid {
    grid-template-columns: 1fr;
    grid-template-areas: "eyebrow" "head" "copy" "visual";
  }
  .catalog-spectrum { margin-top: 30px; }
  .hero-head { max-width: none; margin-bottom: 24px; }
  .podium { grid-template-columns: 1fr; }
  .podium-card { border-left: 0; border-top: 1px solid var(--border); }
  .podium-card:first-child { border-top: 0; }
  .podium-card > a, .podium-card:first-child > a { padding-left: 0; padding-right: 0; }
}

/* ---- v27b: the rest of the surfaces ---- */

/* Corners tighten everywhere. 8px rounding is the default of every template;
   3px reads as a printed rule meeting a printed rule. */
.btn, .btn-primary, .btn-secondary, .btn-ghost, .facet-chip, .tab,
.note, .method-box, .side-card, .product-card, .guide-card, .cat-tile,
.search-btn, .filter-panel, .cp-card, .ct-chip, .chip {
  border-radius: 3px;
}
.brand-tag, .row-thumb, .chip.verified { border-radius: 2px; }

/* Side cards become ruled blocks: a heavy rule, a mono label, content. */
.side-card {
  border: 0; border-radius: 0; background: none;
  border-top: 2px solid var(--ink);
  padding: 14px 0 0; position: static;
}
.side-card + .side-card { margin-top: 30px; }
.side-card h3 { margin: 0 0 10px; }

/* A section heading opens on a rule, the way a column does in print. */
section > .wrap > h2:first-child,
section > .wrap > h2.section-open {
  border-top: 2px solid var(--ink);
  padding-top: 14px;
  margin-top: 0;
}

/* The closing band: ink, left-aligned, the line set in the serif. Centred
   text over a coloured panel with two buttons underneath is the layout every
   template ships with. */
.cta-band {
  background: var(--ink); border-top: 0; border-bottom: 0;
  padding: clamp(48px, 7vw, 86px) 0;
  text-align: left;
}
.cta-band .wrap { display: grid; gap: 22px; }
.cta-line {
  font-family: var(--font-display); font-weight: 400;
  font-size: clamp(1.9rem, 4vw, 3.1rem); line-height: 1.04;
  letter-spacing: -0.015em; color: var(--paper);
  max-width: 20ch; margin: 0;
}
.cta-band .btn-primary { background: var(--ember); border-color: var(--ember); }
.cta-band .btn-secondary { background: none; color: var(--paper); border: 1px solid rgba(255,255,255,0.35); }
.cta-band .btn-secondary:hover { border-color: var(--paper); background: rgba(255,255,255,0.08); }

/* Offers stay a real container — it is the one block on a product page that
   is a unit you act on — but it loses the soft look. */
.offers-card, .side-card.offers { border-radius: 3px; }

/* ============================================================
   v28 — night ledger
   The sister site (peptidesourcereview.info) is a dark navy publication
   with a metal accent. This is the same room at night: PSR's ground,
   this site's ember instead of its gold. Light stays the default; dark
   follows the system unless the reader has chosen, and the choice sticks.
   ============================================================ */
:root[data-theme="dark"] {
  --paper: #0a0e16;
  --paper-card: #10151f;
  --paper-deep: #161d2c;
  --bg-page: #0a0e16;
  --bg-alt: #121826;
  --bg-inset: #161d2c;

  /* --ink is this system's "text" token, so in the dark it is light. The
     places that used it as a *surface* are re-pointed below. */
  --ink: #eef1f6;
  --text: #eef1f6;
  --text-2: #dbe0ea;
  --text-dim: #a8b0c2;
  --text-mute: #828b9e;

  --border: rgba(255, 255, 255, 0.11);
  --border-soft: rgba(255, 255, 255, 0.06);
  --border-strong: rgba(255, 255, 255, 0.24);

  /* Ember lifts on a dark ground: the light-mode red goes muddy at 4.5:1. */
  --ember: #ff2b4d;
  --ember-bright: #ff5c73;
  --ember-deep: #ff7286;
  --ember-tint: rgba(255, 43, 77, 0.13);
  --link: #ff7286;
  --link-hover: #ff9dab;

  --verified: #35c49b;
  --verified-bg: rgba(53, 196, 155, 0.12);
  --bg-deep: #070a12;

  color-scheme: dark;
}

/* ---- surfaces that were hardcoded light ---- */
:root[data-theme="dark"] body,
:root[data-theme="dark"] .hero,
:root[data-theme="dark"] .hero-ledger,
:root[data-theme="dark"] .masthead { background: var(--paper); }
:root[data-theme="dark"] .method-box,
:root[data-theme="dark"] .pillar,
:root[data-theme="dark"] .note,
:root[data-theme="dark"] .side-card { background: none; }
:root[data-theme="dark"] .btn-secondary { background: none; color: var(--ink); }
:root[data-theme="dark"] .btn-secondary:hover { background: rgba(255, 255, 255, 0.06); }
:root[data-theme="dark"] .filter-form,
:root[data-theme="dark"] [data-calc-output],
:root[data-theme="dark"] .guide-body code { background: var(--paper-card); }
:root[data-theme="dark"] tbody tr:nth-child(even) td { background: var(--bg-alt); }
:root[data-theme="dark"] tbody tr:hover td { background: var(--bg-inset); }
:root[data-theme="dark"] .rank-table tbody tr:hover { box-shadow: inset 3px 0 0 var(--ember); }

/* ---- the inverted bands invert back: on a dark page they are panels ---- */
:root[data-theme="dark"] .statline { background: var(--paper-card); border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); }
:root[data-theme="dark"] .statline .stat-n { color: var(--ink); }
:root[data-theme="dark"] .statline .stat-l { color: var(--text-mute); }
:root[data-theme="dark"] .statline .statline-wrap > div { border-left-color: var(--border); }
:root[data-theme="dark"] .cta-band { background: var(--paper-card); border-top: 1px solid var(--border); }
:root[data-theme="dark"] .cta-line { color: var(--ink); }
:root[data-theme="dark"] footer { background: #070a12; border-top: 1px solid var(--border); color: var(--text-dim); }
:root[data-theme="dark"] footer a { color: var(--ink); }
:root[data-theme="dark"] .facet-chip.current,
:root[data-theme="dark"] .btn-ghost[aria-pressed="true"] { background: var(--ember); border-color: var(--ember); color: #fff; }
:root[data-theme="dark"] .compare-tray { background: var(--paper-card); border-top: 1px solid var(--border-strong); color: var(--ink); }
:root[data-theme="dark"] .ct-count { color: var(--text-mute); }
:root[data-theme="dark"] .ct-chip { border-color: var(--border-strong); }
:root[data-theme="dark"] .cp-card { background: var(--paper-card); }
:root[data-theme="dark"] .buybar { background: var(--paper-card); box-shadow: 0 -8px 28px -20px #000; }

/* ---- data marks: ink hairlines become light hairlines ---- */
:root[data-theme="dark"] .cs-bar { background: #fff; opacity: 0.22; }
:root[data-theme="dark"] .cs-bar:hover { opacity: 0.45; }
:root[data-theme="dark"] .cs-bar.is-top { background: var(--ember); opacity: 1; }
:root[data-theme="dark"] .vs-tick { stroke: #fff; opacity: 0.26; }
:root[data-theme="dark"] .vs-median { stroke: #fff; opacity: 0.45; }
:root[data-theme="dark"] .vs-focal { stroke: var(--ember); }
:root[data-theme="dark"] .rank-table thead th { box-shadow: inset 0 -1px 0 var(--border-strong); background: var(--paper); }
:root[data-theme="dark"] .rank-table { border-top-color: var(--border-strong); }
:root[data-theme="dark"] .podium,
:root[data-theme="dark"] .catalog-spectrum,
:root[data-theme="dark"] section > .wrap > h2:first-child { border-top-color: var(--border-strong); }


/* ---- the switch itself ---- */
.theme-toggle {
  display: inline-flex; align-items: center; gap: 6px;
  background: none; border: 1px solid var(--border); border-radius: 3px;
  color: var(--text-dim); cursor: pointer;
  font-family: var(--font-mono); font-size: 0.62rem; letter-spacing: 0.08em;
  text-transform: uppercase; padding: 6px 9px;
  transition: border-color .16s ease, color .16s ease;
}
.theme-toggle:hover { border-color: var(--border-strong); color: var(--ink); }
.theme-toggle svg { display: block; }
.theme-toggle .tt-sun { display: none; }
:root[data-theme="dark"] .theme-toggle .tt-sun { display: block; }
:root[data-theme="dark"] .theme-toggle .tt-moon { display: none; }
@media (max-width: 860px) { .theme-toggle .tt-label { display: none; } }

/* Controls that hardcode a white ground in light mode need their own dark
   ground; found by sweeping computed contrast on a dark page, not by eye. */
:root[data-theme="dark"] .facet-chip,
:root[data-theme="dark"] .search-btn,
:root[data-theme="dark"] .filter-group label,
:root[data-theme="dark"] .filter-form button[type="reset"],
:root[data-theme="dark"] .copy-btn {
  background: var(--paper-card);
  border-color: var(--border);
  color: var(--text-dim);
}
:root[data-theme="dark"] .facet-chip:hover,
:root[data-theme="dark"] .search-btn:hover { border-color: var(--border-strong); color: var(--ink); }
:root[data-theme="dark"] thead th { background: var(--paper-card); color: var(--text-dim); }
:root[data-theme="dark"] .search-btn kbd,
:root[data-theme="dark"] .sp-foot kbd,
:root[data-theme="dark"] .sp-close kbd { background: var(--bg-inset); border-color: var(--border); color: var(--text-dim); }
:root[data-theme="dark"] .filter-group label:has(input:checked) { background: var(--ember); border-color: var(--ember); color: #fff; }
/* White on the bright dark-mode ember is 3.68:1 — the fill keeps the
   light-mode red, which clears 4.5:1 under white text. */
:root[data-theme="dark"] .facet-chip.current,
:root[data-theme="dark"] .btn-ghost[aria-pressed="true"],
:root[data-theme="dark"] .filter-group label:has(input:checked) { background: #e4002b; border-color: #e4002b; }
:root[data-theme="dark"] .facet-chip.current .num { color: #fff; }

/* ============================================================
   v29 — blue paper, yellow signal
   Tinted paper is an editorial move with a long history (the FT's salmon);
   a pale blue ground reads cooler and more instrument-like than white and
   is instantly distinguishable from every white-page review site.
   Yellow cannot carry text on a light ground, so it is a FILL colour with
   dark type on top, and a deep amber carries anything that must read as
   text. In the dark theme the same yellow goes the other way: it is bright
   enough to be the text accent, which also nods at the sister site's gold.
   ============================================================ */
:root {
  --paper: #eaf1f9;
  --paper-card: #f5f9fd;
  --paper-deep: #dfe9f5;
  --bg-page: #eaf1f9;
  --bg-alt: #e1ebf6;
  --bg-inset: #d9e5f2;

  --ink: #0b1622;
  --text: #0b1622;
  --text-2: #1b2a3a;
  --text-dim: #3f5368;
  --text-mute: #566a80;
  --bg-deep: #0b1622;

  --border: #ccdaea;
  --border-soft: #dce7f3;
  --border-strong: #93aac4;

  /* Accent: a fill, plus a text-safe amber. */
  --ember: #f2c94c;
  --ember-bright: #ffdf7a;
  --ember-deep: #6f4d00;
  --ember-tint: rgba(242, 201, 76, 0.22);
  --link: #6f4d00;
  --link-hover: #4f3700;
  --on-accent: #0b1622;

  --verified: #0b6b57;
  --verified-bg: #ddefe9;
}

:root[data-theme="dark"] {
  --ember: #f5d97a;
  --ember-bright: #ffe9a8;
  --ember-deep: #f5d97a;
  --ember-tint: rgba(245, 217, 122, 0.14);
  --link: #f5d97a;
  --link-hover: #ffe9a8;
  --on-accent: #0a0e16;
  --verified: #35c49b;
}

/* Anything filled with the accent carries dark type — white on yellow is
   unreadable in either theme. */
.btn, .btn-primary, .btn-primary:hover,
.facet-chip.current, .filter-group label:has(input:checked),
.btn-ghost[aria-pressed="true"], .cta-band .btn-primary,
:root[data-theme="dark"] .facet-chip.current,
:root[data-theme="dark"] .filter-group label:has(input:checked),
:root[data-theme="dark"] .btn-ghost[aria-pressed="true"] {
  background: var(--ember);
  border-color: var(--ember);
  color: var(--on-accent);
}
.btn:hover, .btn-primary:hover, .cta-band .btn-primary:hover {
  background: var(--ember-bright); border-color: var(--ember-bright); color: var(--on-accent);
}
.facet-chip.current .num,
:root[data-theme="dark"] .facet-chip.current .num { color: var(--on-accent); }
/* The old red glow under a button was tuned for red. */
.btn { box-shadow: none; }

/* Marks that were ember-as-ink become the readable amber. */
.brand .mark, .display em, h1 em, .cs-top .num, .vs-flag,
.pod-metric-l, .is-first .pod-rank, .facet-chip .num { color: var(--ember-deep); }
:root[data-theme="dark"] .brand .mark,
:root[data-theme="dark"] .display em,
:root[data-theme="dark"] h1 em { color: var(--ember); }

/* Data marks keep the fill colour — they sit on the ground, not under text. */
.cs-bar.is-top, :root[data-theme="dark"] .cs-bar.is-top { background: var(--ember); }
.vs-focal, :root[data-theme="dark"] .vs-focal { stroke: var(--ember-deep); }
:root[data-theme="dark"] .vs-focal { stroke: var(--ember); }
.tab.current { border-bottom-color: var(--ember); }
.rank-table tbody tr:hover { box-shadow: inset 3px 0 0 var(--ember); }
.eyebrow-rule { background: var(--ember-deep); }
:root[data-theme="dark"] .eyebrow-rule { background: var(--ember); }

/* Light theme surfaces that assumed white paper. */
:root:not([data-theme="dark"]) .hero,
:root:not([data-theme="dark"]) .hero-ledger,
:root:not([data-theme="dark"]) .masthead,
:root:not([data-theme="dark"]) body { background: var(--paper); }
:root:not([data-theme="dark"]) .note,
:root:not([data-theme="dark"]) .method-box,
:root:not([data-theme="dark"]) .side-card { background: none; }
:root:not([data-theme="dark"]) .facet-chip,
:root:not([data-theme="dark"]) .search-btn,
:root:not([data-theme="dark"]) .filter-group label,
:root:not([data-theme="dark"]) .filter-form,
:root:not([data-theme="dark"]) thead th,
:root:not([data-theme="dark"]) .btn-secondary,
:root:not([data-theme="dark"]) [data-calc-output],
:root:not([data-theme="dark"]) .guide-body code { background: var(--paper-card); }
:root:not([data-theme="dark"]) tbody tr:nth-child(even) td { background: var(--bg-alt); }
:root:not([data-theme="dark"]) tbody tr:hover td { background: var(--bg-inset); }
:root:not([data-theme="dark"]) .search-btn kbd { background: var(--bg-inset); }
:root:not([data-theme="dark"]) .statline { background: var(--ink); }
:root:not([data-theme="dark"]) .cta-band { background: var(--ink); }

/* Three tones the blue ground pushed under AA, measured not eyeballed:
   the 2nd/3rd rank numerals (2.10:1), the keyboard hint (4.36:1) and the
   footer's muted text (4.39:1). */
.pod-rank { color: var(--text-mute); }              /* 4.89:1 on blue paper */
.is-first .pod-rank { color: var(--ember-deep); }
.search-btn kbd, .sp-foot kbd, .sp-close kbd { color: #4c5f74; }   /* 5.14:1 */
footer .footer-head, footer .footer-legal, footer .footer-note, footer small,
footer .footer-legal span { color: #9aa7b5; }                       /* 7.44:1 */
:root[data-theme="dark"] .pod-rank { color: var(--text-mute); }
:root[data-theme="dark"] .is-first .pod-rank { color: var(--ember); }
:root[data-theme="dark"] .search-btn kbd { color: var(--text-dim); }

/* The homepage cards carried a cream gradient from an older era — invisible
   in light mode against blue paper, and a white slab in the dark. */
.product-card, .guide-card { background: var(--paper-card); }
.product-card:hover, .guide-card:hover { background: var(--bg-alt); border-color: var(--border-strong); }
:root[data-theme="dark"] .product-card,
:root[data-theme="dark"] .guide-card { background: var(--paper-card); border-color: var(--border); }
:root[data-theme="dark"] .product-card:hover,
:root[data-theme="dark"] .guide-card:hover { background: var(--bg-inset); border-color: var(--border-strong); }

/* Category accents are tuned for a light ground; on navy they need their
   own steps or the tile numerals disappear (measured at 1.09:1). */
:root[data-theme="dark"] {
  --cat-protein-powder: #ff6b81;
  --cat-protein-bar: #e3b341;
  --cat-protein-snack: #ff9f4a;
  --cat-pre-workout: #35c49b;
  --cat-energy-drink: #6c9cff;
}
:root[data-theme="dark"] .cat-tile .ct-rank { color: var(--cat, var(--ember)); }

/* Two legacy blocks that still assumed a white page. */
.plate { background: var(--paper-card); }
:root[data-theme="dark"] .plate { background: var(--paper-card); border-color: var(--border); }
.btn-cream { background: var(--paper-card); color: var(--ink); box-shadow: none; border: 1px solid var(--border-strong); }
.btn-cream:hover { background: var(--bg-alt); }
:root[data-theme="dark"] .btn-cream { background: var(--paper-card); color: var(--ink); border-color: var(--border-strong); }
:root[data-theme="dark"] .btn-cream:hover { background: var(--bg-inset); }

/* ============================================================
   v30 — deep blue ground
   The brief was "darker blue so the lighter yellow reads". Measured, a
   slightly darker blue makes it worse: #eaf1f9 gives yellow 1.22:1 and
   #c3d4e8 gives 1.09:1, because the ground climbs toward the yellow's own
   lightness. Yellow only clears 4.5:1 once the ground is #3d566f or below.
   So the paper becomes a deep blueprint blue: light yellow reads at 11:1
   and can finally be the text accent as well as the fill. The near-black
   theme stays as the alternate for anyone who wants maximum contrast.
   ============================================================ */
:root {
  --paper: #16263a;
  --paper-card: #1c3145;
  --paper-deep: #22384f;
  --bg-page: #16263a;
  --bg-alt: #1b2d42;
  --bg-inset: #22384f;
  --bg-deep: #0f1d2e;

  --ink: #eaf1f9;
  --text: #eaf1f9;
  --text-2: #d3e0ee;
  --text-dim: #aec1d6;
  --text-mute: #8fa6c0;

  --border: rgba(255, 255, 255, 0.12);
  --border-soft: rgba(255, 255, 255, 0.07);
  --border-strong: rgba(255, 255, 255, 0.26);

  --ember: #f5d97a;
  --ember-bright: #ffe9a8;
  --ember-deep: #f5d97a;
  --ember-tint: rgba(245, 217, 122, 0.14);
  --link: #f5d97a;
  --link-hover: #ffe9a8;
  --on-accent: #0b1622;

  --verified: #35c49b;
  --verified-bg: rgba(53, 196, 155, 0.14);

  --cat-protein-powder: #ff8fa1;
  --cat-protein-bar: #e3b341;
  --cat-protein-snack: #ff9f4a;
  --cat-pre-workout: #35c49b;
  --cat-energy-drink: #7fa8ff;

  color-scheme: dark;
}

/* The blue theme is a dark ground, so it takes the dark treatments. */
:root:not([data-theme="dark"]) body,
:root:not([data-theme="dark"]) .hero,
:root:not([data-theme="dark"]) .hero-ledger,
:root:not([data-theme="dark"]) .masthead { background: var(--paper); }
:root:not([data-theme="dark"]) .note,
:root:not([data-theme="dark"]) .method-box,
:root:not([data-theme="dark"]) .side-card { background: none; }
:root:not([data-theme="dark"]) .facet-chip,
:root:not([data-theme="dark"]) .search-btn,
:root:not([data-theme="dark"]) .filter-group label,
:root:not([data-theme="dark"]) .filter-form,
:root:not([data-theme="dark"]) thead th,
:root:not([data-theme="dark"]) .btn-secondary,
:root:not([data-theme="dark"]) .btn-cream,
:root:not([data-theme="dark"]) .plate,
:root:not([data-theme="dark"]) .product-card,
:root:not([data-theme="dark"]) .guide-card,
:root:not([data-theme="dark"]) [data-calc-output],
:root:not([data-theme="dark"]) .guide-body code { background: var(--paper-card); border-color: var(--border); color: var(--text-dim); }
:root:not([data-theme="dark"]) .product-card .pc-name,
:root:not([data-theme="dark"]) .guide-card h3,
:root:not([data-theme="dark"]) .btn-secondary,
:root:not([data-theme="dark"]) .btn-cream { color: var(--ink); }
:root:not([data-theme="dark"]) .search-btn kbd { background: var(--bg-inset); border-color: var(--border); color: var(--text-dim); }
:root:not([data-theme="dark"]) tbody tr:nth-child(even) td { background: var(--bg-alt); }
:root:not([data-theme="dark"]) tbody tr:hover td { background: var(--bg-inset); }
:root:not([data-theme="dark"]) .statline,
:root:not([data-theme="dark"]) .cta-band { background: var(--paper-card); border-top: 1px solid var(--border); border-bottom: 0; }
:root:not([data-theme="dark"]) .statline .stat-n,
:root:not([data-theme="dark"]) .cta-line { color: var(--ink); }
:root:not([data-theme="dark"]) .statline .stat-l { color: var(--text-mute); }
:root:not([data-theme="dark"]) .statline .statline-wrap > div { border-left-color: var(--border); }
:root:not([data-theme="dark"]) footer { background: var(--bg-deep); border-top: 1px solid var(--border); color: var(--text-dim); }
:root:not([data-theme="dark"]) footer a { color: var(--ink); }
:root:not([data-theme="dark"]) footer .footer-head,
:root:not([data-theme="dark"]) footer .footer-legal,
:root:not([data-theme="dark"]) footer .footer-note { color: var(--text-mute); }
:root:not([data-theme="dark"]) .compare-tray { background: var(--paper-card); color: var(--ink); }
:root:not([data-theme="dark"]) .cp-card,
:root:not([data-theme="dark"]) .buybar { background: var(--paper-card); }
/* Data marks: ink hairlines become light on a dark ground. */
:root:not([data-theme="dark"]) .cs-bar { background: #fff; opacity: 0.24; }
:root:not([data-theme="dark"]) .cs-bar:hover { opacity: 0.45; }
:root:not([data-theme="dark"]) .cs-bar.is-top { background: var(--ember); opacity: 1; }
:root:not([data-theme="dark"]) .vs-tick { stroke: #fff; opacity: 0.28; }
:root:not([data-theme="dark"]) .vs-median { stroke: #fff; opacity: 0.45; }
:root:not([data-theme="dark"]) .vs-focal { stroke: var(--ember); }
:root:not([data-theme="dark"]) .rank-table thead th { background: var(--paper); box-shadow: inset 0 -1px 0 var(--border-strong); }
:root:not([data-theme="dark"]) .rank-table,
:root:not([data-theme="dark"]) .podium,
:root:not([data-theme="dark"]) .catalog-spectrum,
:root:not([data-theme="dark"]) section > .wrap > h2:first-child { border-top-color: var(--border-strong); }
:root:not([data-theme="dark"]) .cat-tile .ct-rank { color: var(--cat, var(--ember)); }

/* ============================================================
   v31 — product shots turn toward you
   A slow tilt on the Y axis with a slight lift, so a product reads as an
   object rather than a sticker. Eased out of the same exponential curve the
   rest of the site uses; honours prefers-reduced-motion.
   ============================================================ */
.pod-img img, .pc-img img, .ct-img, .row-thumb, .product-photo {
  transition: transform .42s cubic-bezier(0.22, 1, 0.36, 1),
              filter .42s cubic-bezier(0.22, 1, 0.36, 1);
  will-change: auto;
}
.podium-card > a:hover .pod-img img,
.product-card:hover .pc-img img,
.cat-tile:hover .ct-img,
.rank-row:hover .row-thumb {
  transform: perspective(620px) rotateY(-14deg) rotateX(5deg) scale(1.07);
}
.product-photo-link:hover .product-photo {
  transform: perspective(900px) rotateY(-12deg) rotateX(4deg) scale(1.04);
}
/* The shadow has to follow the silhouette, not the image box: box-shadow
   would draw a rectangle around a cut-out. drop-shadow traces the alpha. */
.product-photo-link:hover .product-photo {
  filter: drop-shadow(14px 20px 26px rgba(0, 0, 0, 0.55));
}
.podium-card > a:hover .pod-img img,
.rank-row:hover .row-thumb {
  filter: drop-shadow(5px 7px 9px rgba(0, 0, 0, 0.45));
}
.product-card:hover .pc-img img,
.cat-tile:hover .ct-img {
  filter: drop-shadow(9px 13px 18px rgba(0, 0, 0, 0.5));
}
@media (prefers-reduced-motion: reduce) {
  .pod-img img, .pc-img img, .ct-img, .row-thumb, .product-photo { transition: none; }
  .podium-card > a:hover .pod-img img,
  .product-card:hover .pc-img img,
  .cat-tile:hover .ct-img,
  .rank-row:hover .row-thumb,
  .product-photo-link:hover .product-photo { transform: none; }
}

/* ============================================================
   v32 — every product shot is a cut-out
   The catalogue used to be a mix: transparent PNGs, white-background JPGs
   and dark studio banners, each needing its own treatment (a multiply blend
   on light paper, a white plate on dark, a square crop for the banners).
   All 235 shots are now background-removed PNGs trimmed to the product, so
   the treatment is one rule for all of them: no plate, no blend, no crop —
   just the silhouette and the shadow it casts. See data/product-images.json
   for how a new shot is prepared.
   ============================================================ */
.pod-img img, .pc-img img, .ct-img, .row-thumb, .product-photo {
  background: none;
  mix-blend-mode: normal;
  object-fit: contain;
}

/* ============================================================
   v33 — PSR's hand, GPR's palette
   peptidesourcereview.info and this site are siblings, and from here they
   share a hand: the same three typefaces, the same pill buttons with a
   travelling sheen, the same way depth is built. What they do not share is
   colour — PSR is gold on near-black navy, this is light yellow on deep
   blue — or layout, because the substance differs.

   Measured off the live PSR page rather than eyeballed. The numbers below
   are its numbers.
   ============================================================ */

@font-face {
  font-family: 'Source Serif 4';
  font-style: normal; font-weight: 200 900; font-display: swap;
  src: url('/fonts/source-serif.woff2') format('woff2');
}
@font-face {
  font-family: 'Source Serif 4';
  font-style: italic; font-weight: 200 900; font-display: swap;
  src: url('/fonts/source-serif-italic.woff2') format('woff2');
}
@font-face {
  font-family: 'DM Sans';
  font-style: normal; font-weight: 100 1000; font-display: swap;
  src: url('/fonts/dm-sans.woff2') format('woff2');
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal; font-weight: 100 800; font-display: swap;
  src: url('/fonts/jetbrains-mono.woff2') format('woff2');
}

:root {
  --font-sans: 'DM Sans', 'Segoe UI', system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
  --font-serif: 'Source Serif 4', 'Iowan Old Style', Georgia, 'Times New Roman', serif;
  --font-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  /* v26 routes every display element through --font-display and every UI
     element through --font-grotesque, and it does so from selectors like
     `.hero-ledger .display` that outrank anything written here. Retargeting
     the variables moves the whole type system in one move instead of
     fighting specificity element by element. */
  --font-display: 'Source Serif 4', 'Iowan Old Style', Georgia, serif;
  --font-grotesque: 'DM Sans', 'Segoe UI', system-ui, sans-serif;

  /* PSR's motion curve and duration, used for every state change. */
  --psr-ease: cubic-bezier(0.4, 0, 0.2, 1);
  --psr-dur: 0.3s;
  /* Its hairline: 0.8px, not 1px. Thinner than a browser default border and
     that is the point — an outline you read as an edge, not as a frame. */
  --hair: 0.8px;
  --r-card: 18px;
  --r-card-sm: 14px;
  --r-pill: 999px;

  /* The sheen needs two stops that actually differ. --ember-deep is currently
     the same value as --ember, so reusing it would paint a flat gradient and
     the animation would run invisibly. PSR's own stops are #B8862E against
     #E8C878 — about a 1.3x lift. These are that relationship applied to this
     site's yellow. */
  --sheen-base: #dcbf5c;
  --sheen-lift: #fff3c4;
}

/* ---- display type ----
   PSR sets its h1 at 72px / 600 / -1.8px tracking. That tracking is the
   detail people miss: a serif this large needs negative tracking or it
   reads as a book, not a masthead. -0.025em reproduces it at any size. */
h1, h2, h3, .display, .hero-head, .pod-name, .prose h2, .prose h3 {
  font-family: var(--font-serif);
  letter-spacing: -0.025em;
}
/* PSR sets its masthead at weight 600 and -1.8px of tracking on a 72px
   serif, which is -0.025em. v26's own hero rule sets 400/-0.04em from a
   two-class selector, so it is named here rather than out-specified. */
h1, .display, .hero-head,
.hero-ledger .display, .hero-ledger .hero-head { font-weight: 600; letter-spacing: -0.025em; }
body, .lede, .prose p, .prose li { font-family: var(--font-sans); }
.lede { font-family: var(--font-sans); }

/* ---- the pill button, and the sheen that travels across it ----
   The gradient is 220% of the button's width with its highlight at the 45/50/55
   stops, so at any moment only a narrow band is bright. Animating
   background-position drags that band across. Nothing moves in layout, so it
   costs one composited paint and never reflows. */
@keyframes gpr-sheen { to { background-position: -220% 0; } }

.btn-primary,
.buybar .btn-primary,
a.btn-primary {
  border-radius: var(--r-pill);
  border: 0;
  padding: 12px 28px;
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: 0.875rem;
  letter-spacing: 0;
  color: var(--on-accent);
  background-image: linear-gradient(110deg,
    var(--sheen-base) 45%,
    var(--sheen-lift) 50%,
    var(--sheen-base) 55%);
  background-size: 220% 100%;
  box-shadow: 0 0 24px -6px rgba(245, 217, 122, 0.7);
  animation: gpr-sheen 3.2s linear infinite;
  transition: transform .2s var(--psr-ease), box-shadow .2s var(--psr-ease);
}
.btn-primary:hover {
  transform: translateY(-1px);
  box-shadow: 0 0 30px -4px rgba(245, 217, 122, 0.85);
}

/* The quiet twin: same pill, no fill, a hairline at 15% and text at 80%.
   PSR pairs every sheened button with one of these so the sheen means
   something — if both glowed, neither would. */
.btn-secondary, a.btn-secondary {
  border-radius: var(--r-pill);
  border: var(--hair) solid rgba(255, 255, 255, 0.15);
  background: transparent;
  box-shadow: none;
  padding: 12px 28px;
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: 0.875rem;
  color: rgba(255, 255, 255, 0.8);
  transition: color .15s var(--psr-ease), background-color .15s var(--psr-ease), border-color .15s var(--psr-ease);
}
.btn-secondary:hover {
  border-color: rgba(255, 255, 255, 0.3);
  background: rgba(255, 255, 255, 0.04);
  color: #fff;
}

/* Small pills: nav chips, brand tags, facet links. Mono, 12px, hairline. */
.brand-tag, .facet-chip, .refine a, .cat-tile .ct-rank {
  border-radius: var(--r-pill);
}

/* ---- depth without drop shadows ----
   PSR's cards carry no box-shadow at all. Depth comes from a two-stop
   gradient between translucent grounds plus a hairline border — the card
   looks lit from above rather than lifted off the page, which is what keeps
   a dark interface from turning muddy. */
.podium-card, .product-card, .cat-tile, .score-card, .composite-badge,
.statline, .compare-tray, .search-panel {
  border-radius: var(--r-card);
  border: var(--hair) solid rgba(255, 255, 255, 0.10);
  background-image: linear-gradient(180deg,
    rgba(255, 255, 255, 0.045) 0%,
    rgba(255, 255, 255, 0.012) 100%);
  transition: border-color var(--psr-dur) var(--psr-ease),
              background-color var(--psr-dur) var(--psr-ease),
              transform var(--psr-dur) var(--psr-ease);
}
.podium-card:hover, .product-card:hover, .cat-tile:hover {
  border-color: rgba(245, 217, 122, 0.28);
}
.rank-row, .guide-card { border-radius: var(--r-card-sm); }

/* ---- the glow pulse PSR uses to mark its sister link ----
   Reused here for the same job, pointing the other way. */
@keyframes gpr-sister-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(245, 217, 122, 0.30); }
  50%      { box-shadow: 0 0 16px 2px rgba(245, 217, 122, 0.42); }
}
.sister-link {
  border-radius: var(--r-pill);
  border: var(--hair) solid rgba(245, 217, 122, 0.4);
  padding: 4px 12px;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--ember);
  animation: gpr-sister-pulse 2.8s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
  .btn-primary, .sister-link { animation: none; }
  .btn-primary:hover { transform: none; }
}

/* A full-page computed-contrast sweep after the v33 type change found seven
   dark-theme failures, all the same token: --text-mute (#828b9e) on the
   panel ground (#1c3145) measures 3.90:1 against the 4.5 small text needs.
   The failing strings are the statline labels and the ranking numerals, and
   they are small enough (10.5-11.5px) that they get no large-text allowance.
   #9aa3b6 is the nearest value that clears it. */
:root[data-theme="dark"] { --text-mute: #9aa3b6; }

/* ============================================================
   v34 — the depth layers, which is where PSR's "modern" actually lives
   Measured off the live page once its gate was down. Three mechanisms, all
   cheap, none of which move layout.
   ============================================================ */

/* 1. The graph-paper grid. PSR calls it .lab-grid and it is the whole reason
   its hero reads as a bench rather than a poster: two 1px gradients crossed
   at 42px, white at 4.3%. Faint enough that you register texture without
   ever resolving lines. */
/* The theme layers set `background: var(--paper)` on the hero from a
   `:root:not([data-theme="dark"])` selector, and that shorthand resets
   background-image. So the grid is declared at the same specificity, as
   background-image only, leaving each theme's ground colour underneath it
   exactly as it was. */
.hero-ledger { position: relative; overflow: hidden; }
:root:not([data-theme="dark"]) .hero-ledger,
:root[data-theme="dark"] .hero-ledger {
  background-image:
    linear-gradient(rgba(255, 255, 255, 0.043) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, 0.043) 1px, transparent 1px);
  background-size: 42px 42px;
  background-color: var(--paper);
}

/* 2. The cursor spotlight: a soft accent glow that tracks the pointer and is
   invisible until the pointer moves. It is what makes the surface feel lit
   rather than printed. Pointer-events none so it never intercepts a click,
   and it only fades in once site.js has a real position to place it at. */
.hero-ledger::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
  transition: opacity .45s var(--psr-ease);
  background: radial-gradient(360px 360px at var(--mx, 50%) var(--my, 40%),
              rgba(245, 217, 122, 0.14), transparent 70%);
}
.hero-ledger.is-lit::after { opacity: 1; }
.hero-ledger > * { position: relative; z-index: 1; }

/* 3. The border sweep. A 1px gradient hairline pinned to a card's top edge,
   scaled to nothing at rest and run out to full width on hover — a light
   passing over the edge. PSR puts one on every card in its grid. */
.podium-card, .product-card, .cat-tile, .guide-card { position: relative; }
.podium-card::before, .product-card::before, .cat-tile::before, .guide-card::before {
  content: '';
  position: absolute;
  inset-inline: 0;
  top: 0;
  height: 1px;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform .5s var(--psr-ease);
  background: linear-gradient(to right, transparent, rgba(245, 217, 122, 0.6) 50%, transparent);
  pointer-events: none;
  z-index: 2;
}
.podium-card:hover::before, .product-card:hover::before,
.cat-tile:hover::before, .guide-card:hover::before { transform: scaleX(1); }

/* 4. The eyebrow becomes a pill. PSR sets 11px DM Sans at 0.22em tracking,
   uppercase, 600, accent on a near-opaque ink ground, with no border at all
   — the fill alone carries it. */
.eyebrow, .hero-eyebrow {
  /* A grid item blockifies inline-flex and then stretches to fill its area,
     which turned the pill into a full-width bar. justify-self keeps it the
     width of its own text, which is what a chip is. */
  display: inline-flex;
  justify-self: start;
  width: fit-content;
  align-items: center;
  gap: 8px;
  border-radius: var(--r-pill);
  background: var(--bg-deep, #0f1d2e);
  padding: 6px 16px;
  font-family: var(--font-sans);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ember);
}
/* The rule that used to sit beside the eyebrow is redundant inside a pill. */
.eyebrow .eyebrow-rule, .hero-eyebrow .eyebrow-rule { display: none; }

@media (prefers-reduced-motion: reduce) {
  .hero-ledger::after { transition: none; }
  .podium-card::before, .product-card::before,
  .cat-tile::before, .guide-card::before { transition: none; }
}

/* The PSR-shaped headline is ~51 characters, where the old question was 33.
   At the inherited 80px cap in an 18ch measure it broke to four lines and
   pushed the hero visual under the fold. PSR sets its own 51-character
   headline at 72px over three lines, so this matches that: 4.5rem cap, and a
   measure wide enough for the line to actually fill. */
.hero-ledger .display, .hero-head {
  font-size: clamp(2.6rem, 5.4vw, 4.5rem);
  max-width: 21ch;
}

/* ============================================================
   v35 — PSR's page architecture
   v33 took its hand, v34 its depth. This takes the structure: the type
   scale, the section rhythm, the way an accent lands inside a heading, and
   the small mono furniture that frames the whole thing. Measured off the
   live page section by section.
   ============================================================ */

:root { --wrap: 1340px; }

/* ---- the accent inside a heading ----
   PSR does not colour a title word flat. It clips a four-stop gold gradient
   to the glyphs and walks it across at 200% width over 6 seconds — slower
   than the button sheen, because a headline should shimmer rather than
   flash. Falls back to a solid accent wherever background-clip:text is
   unsupported, so the words never vanish. */
@keyframes gpr-title-sheen { to { background-position: 200% center; } }

.title-accent {
  color: var(--ember);
  font-style: normal;
}
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .title-accent {
    color: transparent;
    background-image: linear-gradient(100deg,
      var(--ember) 20%, var(--sheen-lift) 40%, var(--sheen-base) 60%, var(--ember) 80%);
    background-size: 200% auto;
    -webkit-background-clip: text;
            background-clip: text;
    animation: gpr-title-sheen 6s linear infinite;
  }
}

/* ---- the type scale ----
   Source Serif 4 at 600 throughout, with -0.025em of tracking on anything
   36px and over and none below it. PSR's own numbers: 72 / 48 / 36 / 24 / 18. */
h2, .display-2 {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(2rem, 3.4vw, 3rem);      /* 48px cap */
  letter-spacing: -0.025em;
  line-height: 1.08;
}
h2.section-sub, .h2-minor {
  font-size: clamp(1.6rem, 2.6vw, 2.25rem); /* 36px cap */
}
h3, .pod-name, .pc-name {
  font-family: var(--font-display);
  font-weight: 600;
  letter-spacing: normal;
}
h3 { font-size: 1.5rem; }                    /* 24px section-level */
.pod-name, .pc-name, .rank-row h3 { font-size: 1.125rem; }  /* 18px card-level */

/* ---- section rhythm ----
   112px top and bottom, 160px above the hero, and a 40px band for the
   statline fenced by hairlines. The grounds alternate so a long page reads
   as chapters rather than one scroll. */
main > section, main > .section { padding-block: clamp(56px, 7vw, 112px); }
.hero-ledger { padding-top: clamp(80px, 10vw, 160px); padding-bottom: clamp(56px, 7vw, 112px); }
.statline {
  padding-block: 40px;
  border-top: var(--hair) solid rgba(255, 255, 255, 0.08);
  border-bottom: var(--hair) solid rgba(255, 255, 255, 0.08);
  background: var(--bg-alt);
}
main > section:nth-of-type(even) { background: var(--bg-alt); }

/* ---- the mono furniture ----
   The line under the hero stats: 11px JetBrains Mono, 0.18em tracking,
   uppercase, white at 55%, with the date alone carrying the accent. It is
   what makes the page feel maintained rather than published once. White at
   35% was 2.99:1 on the navy statline (#1c3145) and failed WCAG AA for 11px
   text; 55% is 5.15:1 and still sits behind the gold date (6.68:1). */
.audit-line {
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.55);
  margin-top: 18px;
}
.audit-line .audit-date { color: rgba(245, 217, 122, 0.8); }

/* ---- footer ----
   One hairline across the top, 64px of air, and a single middot-separated
   legal line rather than a stack. */
footer { border-top: var(--hair) solid rgba(255, 255, 255, 0.08); padding-block: 64px; }
.footer-legal { font-family: var(--font-mono); font-size: 0.6875rem; letter-spacing: 0.06em; }

/* ---- scroll reveal ----
   PSR fades and lifts each block as it arrives. This site already had the
   pattern; these are PSR's numbers for it. */
.reveal {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity .55s var(--psr-ease), transform .55s var(--psr-ease);
}
.reveal.in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .title-accent { animation: none; }
  .reveal { opacity: 1; transform: none; transition: none; }
}

/* v26 styles display accents as `.display em` — one class plus one element,
   which outranks a lone `.title-accent` class and was forcing the headline
   accent back to flat italic ember with the gradient never clipping. Named
   at matching weight here, and the brand's second word takes PSR's italic. */
.display .title-accent,
h1 .title-accent,
.hero-head .title-accent {
  font-style: normal;
  font-weight: inherit;
  color: var(--ember);
}
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .display .title-accent,
  h1 .title-accent,
  .hero-head .title-accent {
    color: transparent;
    background-image: linear-gradient(100deg,
      var(--ember) 20%, var(--sheen-lift) 40%, var(--sheen-base) 60%, var(--ember) 80%);
    background-size: 200% auto;
    -webkit-background-clip: text;
            background-clip: text;
    animation: gpr-title-sheen 6s linear infinite;
  }
}
/* PSR sets the second word of its wordmark in italic accent serif. */
.brand .mark { font-style: italic; color: var(--ember); font-weight: 600; }

@media (prefers-reduced-motion: reduce) {
  .display .title-accent, h1 .title-accent, .hero-head .title-accent { animation: none; }
}

/* The reveal pattern hides its content until script adds `.in`, which means
   a reader with JavaScript off saw nothing at all — the blocks stayed at
   opacity 0 permanently. The hidden state is now gated on a `js` class that
   the pre-paint head script sets, so no-script renders everything visible
   and the animation is simply skipped. */
.reveal { opacity: 1; transform: none; }
.js .reveal {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity .55s var(--psr-ease), transform .55s var(--psr-ease);
}
.js .reveal.in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .js .reveal { opacity: 1; transform: none; transition: none; }
}

/* ============================================================
   v36 — the masthead behaves like PSR's, read from its source
   PSR's navbar is `fixed`, sits at py-5 (20px), and past 24px of scroll
   swaps to py-3 (12px) with backdrop-blur-xl, an 80% ink ground and a
   white/10 bottom border, over a 300ms transition. It never changes the
   size of its wordmark.
   ============================================================ */

/* The wordmark stayed put on PSR and jumps here: condensing re-set .brand to
   0.98rem, so the top-left text shrank and sprang back on every crossing of
   the threshold. Only the bar's padding should move. */
/* `inherit` was wrong: it takes the masthead's own font-size (17px), so the
   wordmark still changed size on scroll, just less visibly. Restate the
   brand's size so condensing cannot touch it. */
.masthead.is-condensed .brand { font-size: 1.125rem; }
.brand { font-size: 1.125rem; letter-spacing: -0.025em; }

.masthead {
  padding: 20px 0;
  transition: padding .3s var(--psr-ease), background-color .3s var(--psr-ease),
              border-color .3s var(--psr-ease), backdrop-filter .3s var(--psr-ease);
  border-bottom: var(--hair) solid transparent;
  background: transparent;
}
.masthead.is-condensed {
  padding: 12px 0;
  background: color-mix(in srgb, var(--paper) 80%, transparent);
  -webkit-backdrop-filter: blur(20px);
          backdrop-filter: blur(20px);
  border-bottom-color: rgba(255, 255, 255, 0.10);
}
/* The inner rule that drew its own divider fought the header's own border. */
.masthead .wrap { border-bottom: 0; padding-bottom: 0; }
.masthead.is-condensed .wrap { padding-bottom: 0; }

@media (prefers-reduced-motion: reduce) { .masthead { transition: none; } }

/* ============================================================
   v37 — hero geometry, taken from PSR's own component source
   Reverse-engineering the DOM got the tokens right and the measures wrong.
   The Tailwind classes give exact values, so these are its numbers rather
   than my approximations of them.
   ============================================================ */

/* h1: `max-w-4xl font-serif text-5xl leading-[1.04] font-semibold
   tracking-tight md:text-7xl` — 48px rising to 72px, 1.04 leading, and a
   896px measure. I had guessed 21ch, which is roughly 738px, and that is
   why the headline wrapped differently and sat narrower than PSR's. */
.hero-ledger .display, .hero-head {
  font-size: clamp(3rem, 5.4vw, 4.5rem);
  line-height: 1.04;
  max-width: 56rem;
  margin-top: 28px;
}

/* lede: `mt-6 max-w-2xl text-lg leading-relaxed text-white/65` */
.hero-ledger .lede {
  font-size: 1.125rem;
  line-height: 1.625;
  max-width: 42rem;
  margin-top: 24px;
  color: rgba(255, 255, 255, 0.65);
}

/* actions: `mt-9 flex flex-wrap items-center gap-4`, buttons at
   `rounded-full px-7 py-3 text-sm`, the primary bold and the ghost
   semibold. */
.hero-ledger .hero-actions { margin-top: 36px; gap: 16px; display: flex; flex-wrap: wrap; align-items: center; }
.btn-primary { padding: 12px 28px; font-weight: 700; }
.btn-secondary { padding: 12px 28px; font-weight: 600; }
.btn-primary:hover { transform: scale(1.02) translateY(-1px); }

/* The statline is PSR's stat grid: one rounded panel, hairline gaps showing
   the ground through, an accent-tinted border and a deep soft shadow —
   rounded-2xl, border-gold/15, gap-px, shadow-[0_24px_60px_-30px]. */
.statline {
  border-radius: 16px;
  border: var(--hair) solid rgba(245, 217, 122, 0.15);
  box-shadow: 0 24px 60px -30px rgba(0, 0, 0, 0.9);
  overflow: hidden;
  margin-top: 64px;
}

/* Entrance: PSR staggers each hero block in from 26px below over 0.7s on a
   [0.2,0.65,0.3,1] curve. This site's reveal used 14px over 0.55s. */
.js .reveal {
  transform: translateY(26px);
  transition: opacity .7s cubic-bezier(0.2, 0.65, 0.3, 1),
              transform .7s cubic-bezier(0.2, 0.65, 0.3, 1);
}

/* An earlier layer sets the weight from `a.btn-primary`, one class plus one
   element, which outranks a bare `.btn-primary`. PSR's primary is bold and
   its ghost semibold, so both are named at matching weight. */
a.btn-primary, .buybar a.btn-primary { font-weight: 700; }
a.btn-secondary { font-weight: 600; }

/* ============================================================
   v38 — alignment and the double rule
   Four faults, all introduced by carding and re-spacing elements that were
   built for a different treatment.
   ============================================================ */

/* 1. The double line. The tabstrip drew its own bottom border AND the
   masthead gained one in v36, so scrolling produced two rules a pixel
   apart. PSR has exactly one, on the header, and none at all at the top of
   the page. The masthead's is now the only divider. */
.masthead .tabstrip { border-bottom: 0; }

/* 2. The gutter. PSR's container is `max-w-[1340px] px-6` — a flat 24px at
   every width. This site had grown a fluid `clamp(24px, 3vw, 48px)`, which
   is 43.2px at 1440 and pushed every page 19px further right than PSR's. */
:root { --gutter: 24px; }
.wrap { padding-inline: 24px; }

/* 3. The hero sat too low. PSR's navbar is `fixed`, so it costs no vertical
   space and its 160px of hero padding contains the 72px bar — 88px of real
   gap. This masthead is sticky and in flow at 118px (it carries a second
   row of category tabs PSR does not have), so its 144px of padding was
   stacking on top of the bar rather than absorbing it. Padding now targets
   the same 88px gap; the hero still starts lower than PSR's by the height
   of that extra nav row, which is structural rather than stylistic. */
.hero-ledger { padding-top: clamp(48px, 5vw, 88px); }

/* 4. Category tiles had no horizontal padding: they were bare columns
   before v33 gave them a border, a background and an 18px radius, so their
   text and thumbnails ran flush to the edge and were clipped by the corner.
   Matching the product card's 20px. */
.cat-tile { padding-inline: 20px; }

/* 5. The statline is PSR's full-bleed `border-y` band, not the rounded stat
   grid that sits inside its hero — v37 confused the two and gave the band a
   16px radius and a drop shadow it should not have, on an element whose
   border was also incomplete. Back to a band. */
.statline {
  border-radius: 0;
  box-shadow: none;
  border: 0;
  border-top: var(--hair) solid rgba(255, 255, 255, 0.08);
  border-bottom: var(--hair) solid rgba(255, 255, 255, 0.08);
  margin-top: 0;
  overflow: visible;
}

/* The theme layers zero the statline's bottom border from a
   `:root:not([data-theme="dark"])` selector, which outranks a bare
   `.statline`, so the band was drawing its top rule and nothing underneath.
   Declared at matching weight for both themes. */
:root:not([data-theme="dark"]) .statline,
:root[data-theme="dark"] .statline {
  border-bottom: var(--hair) solid rgba(255, 255, 255, 0.08);
  border-radius: 0;
  box-shadow: none;
}

/* The brand mark beside the wordmark, as PSR sets it: 28px, softly rounded,
   with the two sitting on a shared baseline. */
.brand { display: inline-flex; align-items: center; gap: 10px; }
.brand-icon { width: 28px; height: 28px; border-radius: 7px; display: block; flex-shrink: 0; }
.brand-words { display: inline-flex; align-items: baseline; gap: 6px; }
@media (max-width: 480px) { .brand-icon { width: 24px; height: 24px; } }

/* ============================================================
   v40 — the rankings control replaces the second masthead row.

   The masthead carried two rows: brand + nav, then a full-width strip of
   six category tabs. That strip cost every page ~45px above the fold and
   pushed the hero well below where PSR's sits, to show links most readers
   reach through the page itself. It is now one pill — straight to /best/ —
   with a caret that opens the categories.

   The caret is a native <details>/<summary>. The menu therefore opens with
   scripting disabled; site.js only adds Escape and click-outside, which a
   bare <details> does not do.
   ============================================================ */
.rankings-cta {
  display: inline-flex;
  align-items: stretch;
  position: relative;
  border-radius: var(--r-pill);
  /* One pill with a seam, not two buttons: the sheen runs across the whole
     shape and the divider is drawn inside it. */
  box-shadow: 0 0 24px -6px rgba(220, 191, 92, 0.55);
}
.rankings-go,
.rankings-drop > summary {
  background: linear-gradient(110deg, var(--sheen-base) 45%, var(--sheen-lift) 50%, var(--sheen-base) 55%);
  background-size: 220% 100%;
  animation: gpr-sheen 3.2s linear infinite;
  color: #16263a;
  border: 0;
  font-family: var(--font-sans);
  font-weight: 700;
  font-size: 0.86rem;
  letter-spacing: -0.01em;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  cursor: pointer;
}
.rankings-go {
  padding: 10px 14px 10px 16px;
  border-radius: var(--r-pill) 0 0 var(--r-pill);
  text-decoration: none;
  white-space: nowrap;
}
.rankings-drop { position: static; }
.rankings-drop > summary {
  padding: 10px 12px 10px 10px;
  border-radius: 0 var(--r-pill) var(--r-pill) 0;
  /* The seam. A 1px rule in the ink colour reads as one moulded pill; a
     gap would read as two buttons that happen to touch. */
  box-shadow: inset 1px 0 0 rgba(22, 38, 58, 0.28);
  list-style: none;
}
/* Safari draws its own triangle unless both are cleared. */
.rankings-drop > summary::-webkit-details-marker { display: none; }
.rankings-drop > summary::marker { content: ''; }
.rankings-go:hover,
.rankings-drop > summary:hover { filter: brightness(1.06); }
.rankings-go:focus-visible,
.rankings-drop > summary:focus-visible { outline: 2px solid var(--ember); outline-offset: 2px; }

.rankings-drop .caret {
  width: 0; height: 0;
  border-left: 4.5px solid transparent;
  border-right: 4.5px solid transparent;
  border-top: 5px solid currentColor;
  transition: transform var(--psr-dur) var(--psr-ease);
}
.rankings-drop[open] .caret { transform: rotate(180deg); }

.rankings-menu {
  position: absolute;
  top: calc(100% + 10px);
  right: 0;
  z-index: 60;
  min-width: 15rem;
  display: flex;
  flex-direction: column;
  padding: 6px;
  border-radius: var(--r-card-sm);
  /* Surface and ink both come from the palette rather than being written
     out per theme. `data-theme="light"` is on <html> by default while the
     resolved palette is dark, so a `:root:not([data-theme="dark"])` rule --
     the pattern used elsewhere in this file -- paints light-theme styling
     onto a dark page. This component cannot use that selector. */
  background: var(--bg-page);
  color: var(--text);
  border: var(--hair) solid currentColor;
  box-shadow: 0 18px 44px -12px rgba(0, 0, 0, 0.55);
}
/* currentColor on the border would be full-strength ink; fade it to a
   hairline without needing to know which palette is live. */
.rankings-menu { border-color: color-mix(in srgb, var(--text) 18%, transparent); }

.rankings-menu a {
  padding: 9px 12px;
  border-radius: 9px;
  font-family: var(--font-sans);
  font-size: 0.88rem;
  color: var(--text);
  text-decoration: none;
  white-space: nowrap;
  transition: background var(--psr-dur) var(--psr-ease);
}
.rankings-menu a:hover { background: rgba(245, 217, 122, 0.12); }
.rankings-menu a.current { color: var(--ember); font-weight: 600; }
.rankings-menu-all {
  font-weight: 600;
  margin-bottom: 4px;
  padding-bottom: 11px;
  border-bottom: var(--hair) solid color-mix(in srgb, var(--text) 14%, transparent);
  border-radius: 9px 9px 0 0;
}


@media (prefers-reduced-motion: reduce) {
  .rankings-go, .rankings-drop > summary { animation: none; }
  .rankings-drop .caret { transition: none; }
}

/* The drawer already lists every ranking, so below the nav breakpoint the
   pill would be a third route to the same six links in a masthead that is
   short of room. */
@media (max-width: 860px) { .rankings-cta { display: none; } }

/* `.nav a` (0,1,1) and `.nav a, .nav-links a` (0,1,1) both beat
   `.rankings-go` (0,1,0), so the pill inherited the nav's dim link colour
   and weight 600 and rendered gold-on-gold. Named through .masthead .nav to
   outrank them rather than reaching for !important.

   The caret also needs .rankings-drop to be a flex box of its own: the
   <details> is the flex child that stretches, and without this its
   <summary> keeps its own content height and the seam stops halfway down
   the pill. */
.masthead .nav a.rankings-go {
  color: #16263a;
  font-family: var(--font-sans);
  font-size: 0.86rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  text-transform: none;
  text-decoration: none;
}
.masthead .nav a.rankings-go:hover { color: #16263a; }
.rankings-drop { display: flex; }
.rankings-drop > summary { align-items: center; }

/* The composite is a weighted mean of what could be scored, so a product
   measured on one axis can read 10.0 while ranking last. The caveat sits
   with the number rather than only in the score blocks further down. */
.buybar-score-cov {
  display: block;
  font-family: var(--font-sans);
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--text-mute, var(--text-dim));
  opacity: 0.85;
  white-space: nowrap;
}

/* ============================================================
   v41 — the ledger spot art stops being black
   The spot illustrations were drawn as dark line art on a near-white sheet,
   and v8 knocked that sheet out with `mix-blend-mode: multiply` so the paper
   grain showed through. v30 then made the ground deep blue, and multiply
   against #16263a crushes every channel: the drawings composited to about
   rgb(4,2,3). They were still there, and they were black on navy.
   The reveal transition made one bug look like two. An ancestor at
   opacity < 1 forms a stacking context, which isolates the blend group, so
   for the length of the transition each image painted its raw self — a white
   sheet with dark red ink — and then went black the instant opacity hit 1
   and the context released. That is the flash, and the comment at the v9
   .reveal rule already warned that anything containing a blended image
   behaves this way.
   Blending was only ever standing in for transparency the files did not
   have. scripts/brand/ink-spot-art.py gives them real alpha — darkness
   becomes opacity, the sheet becomes clear, and the ink becomes one light
   colour — so nothing here depends on the backdrop any more. No blend, no
   filter, no flash, and it reads on both grounds the site ships (#16263a,
   and #0a0e16 when the theme is toggled).
   ============================================================ */
.spot-fig,
.riso {
  mix-blend-mode: normal;
  filter: none;
}

/* The hero still-life is the same fix with one difference worth recording.
   It is a four-ink riso print — cream sheet, red table, cyan panelling,
   black line — so the darkness ramp that suits the spot art is wrong for
   it: red is dark by luminance without being shadow, so the table turned
   into a pale mass while the white tub standing on it fell away to
   nothing, which reads as a negative of the picture. Only the black plate
   is line, so only the black plate is inked and the flat colour fills drop
   out. What is left is a white line drawing on the navy, in the same hand
   as the three spots above it. */
