/* ═══════════════════════════════════════════════════════════════════════════
   THE SNUG REPORT — TOKEN LAYER

   This file is the site's entire visual identity. A sibling satellite replaces
   it wholesale and gets a different-looking publication out of the same
   components. Rules:

     1. This file contains NO class selectors. Only :root custom properties and
        @font-face-ish declarations. base.css consumes these and nothing else.
        (styles/sheet.mjs rewrites class selectors to add the per-site prefix —
        it does not touch this file, which is why the rule matters.)
     2. No component may state a literal colour, font, radius or space. If one
        does, a sibling site cannot be restyled by swapping this file, and §9.2's
        "same typography / same margins" signal fires across the network.
     3. Every token is named for its ROLE, not its value. `--ink-quiet`, not
        `--grey-600`. A sibling whose quiet ink is warmer still works.

   ── IDENTITY BRIEF ────────────────────────────────────────────────────────
   config/copy-rules.md sets the voice: "a friend who happens to know a great
   deal about sex toys" — warm, plain, unembarrassed, result before spec. The
   design has to read the way that copy reads.

   So: bright warm paper, soft graphite ink (never near-black), and a deep
   petrol blue doing the confident work the old claret was doing badly. Petrol
   is chosen for three reasons, in order:
     · it clears AAA against the paper as body-copy link colour, which claret
       at #7A2E3C did not;
     · it is the complement of the copper-rose satin every product photograph
       is shot on, so the site's own chrome never competes with the plates;
     · it shares no hue family with Coy's cream/blush/rose/clay/berry/plum, and
       §9.2 counts a shared palette as one of the seven "these are one brand"
       signals. The photographs are Coy's and carry Coy's colour — the furniture
       around them must not.

   Amber stays load-bearing and stays amber: it marks a figure that came out of
   the dataset, and nothing else on the site is allowed to use it.

   ── CONTRAST ──────────────────────────────────────────────────────────────
   Verified with a WCAG 2.x relative-luminance check on every foreground /
   background pair base.css actually composes, light and dark. Body text and
   every ink tier clear 7:1 (AAA). Semantic tags, evidence figures and UI clear
   4.5:1 and mostly clear 7:1. The worst pair in the light theme is the evidence
   figure on the evidence wash at 5.67:1 (large display numerals, AAA-large).
   If you change a ground token, re-run the pairs — the faint ink tier is the
   one with the least headroom.
   ═══════════════════════════════════════════════════════════════════════════ */

:root {
  /* ── Colour: ground ───────────────────────────────────────────────────────
     Bright, barely-warm paper. The old #F6F1E8 newsprint was the single biggest
     contributor to "the colours are too dark" — it dropped every foreground on
     the site by about a stop before any of them had done anything wrong. */
  --paper:            #FCFAF6;   /* warm bright paper, not cream */
  --paper-raised:     #FFFFFF;   /* cards, plates, the evidence rail */
  --paper-sunk:       #F5F1E8;   /* inset blocks, spec tables, disabled rows */
  --paper-invert:     #16333C;   /* masthead + footer slab — petrol, not black */

  /* ── Colour: ink ──────────────────────────────────────────────────────────
     Warm graphite rather than near-black. #23211E against this paper is 15.4:1,
     which is more contrast than #1B1512 was delivering on #F6F1E8, and it reads
     softer because the ground is doing the work instead of the ink. */
  --ink:              #23211E;   /* 15.40:1 on paper */
  --ink-quiet:        #4A443C;   /*  9.23:1 — captions, provenance, meta rows */
  --ink-faint:        #555044;   /*  7.63:1 — "Not stated", scaffold hints */
  --ink-invert:       #F7F4EE;   /* 12.16:1 on the slab */
  /* Quiet ink FOR AN INVERTED SURFACE. Its absence was a real bug: the masthead
     strapline, the homepage invert band and the whole footer legal block —
     including the §12 ownership disclosure — were rendering --ink-quiet on
     --paper-invert at about 2:1, i.e. legally present and practically invisible.
     Any surface that flips the ground must flip this too. */
  --ink-invert-quiet: #C3D4D6;   /*  8.72:1 on the slab */

  /* ── Colour: brand ────────────────────────────────────────────────────────
     Deep petrol. --on-brand is the only colour permitted on a brand FILL; it is
     a separate token because in dark mode the brand becomes a light cyan and a
     light label on it is unreadable. --brand-invert is the brand as it appears
     ON the slab, where the deep version would vanish. */
  --brand:            #0E5266;   /*  8.33:1 on paper — AAA as a body link */
  --brand-deep:       #07394A;   /* 11.90:1 — hover, ownership strip text */
  --brand-wash:       #E1EEF2;   /* tinted blocks that must not shout */
  --brand-invert:     #8FD3E6;   /*  8.03:1 on the slab */
  --on-brand:         #FBFAF6;   /*  8.32:1 on --brand */

  /* ── Colour: evidence ─────────────────────────────────────────────────────
     Amber is load-bearing, not decorative. It marks a figure that came out of
     the dataset. Never use it for a call to action or for chrome, or the reader
     stops being able to tell an evidence number from a button. Darkened from
     #B06A22 to clear 4.5:1 as a small label as well as a large numeral. */
  --evidence:         #8F4E10;   /*  6.17:1 on paper */
  --evidence-wash:    #FBEFDF;

  /* ── Colour: semantic states ──────────────────────────────────────────────
     All three clear 7:1 against their own wash. They are not decoration: the
     porous / non-porous / not-stated triple is the site's whole wedge, and a
     tag nobody can read is a tag that is not saying anything. */
  --safe:             #175232;   /*  7.83:1 on --safe-wash */
  --safe-wash:        #E4F0E8;
  --caution:          #8E2A1B;   /*  7.11:1 on --caution-wash */
  --caution-wash:     #FBE8E3;
  --unknown:          #514B40;   /*  7.19:1 — a THIRD state, never absence */
  --unknown-wash:     #EEEAE0;

  /* ── Colour: lines ────────────────────────────────────────────────────── */
  --rule:             #DED7C9;
  --rule-strong:      #B6AC98;
  --rule-hair:        #ECE7DB;

  /* Ground a photograph sits on before it loads and inside its own frame. */
  --plate:            #F0EBE0;

  /* ── Type ─────────────────────────────────────────────────────────────────
     Fraunces is gone. Its soft-serif terminals plus a 900 weight plus its very
     high stroke contrast made every heading on the site work to read, which is
     exactly the complaint. Newsreader replaces it: a variable text serif drawn
     for news, with open apertures, moderate contrast and a real opsz axis, so
     the masthead and a card title get genuinely different cuts of the same face
     rather than one cut scaled. It reads as a publication — which this is — and
     it stays legible at 700, so the display weight comes down from 900 too.

     Archivo stays for body. It is a sturdy, wide-aperture grotesque that holds
     up at 16–18px on a phone, and the heading font was the thing that needed
     replacing, not the reading font. */
  --font-display: 'Newsreader', 'Iowan Old Style', Georgia, 'Times New Roman', serif;
  --font-body:    'Archivo', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
  --font-mono:    ui-monospace, 'SF Mono', 'Cascadia Mono', Menlo, monospace;

  --display-optical:      'opsz' 60;   /* Newsreader axis is 6..72 */
  --display-optical-text: 'opsz' 20;   /* small headings get the text cut */
  --display-weight:       700;
  --display-weight-soft:  600;         /* card titles, slot titles, rail heads */
  --display-tracking:     -0.011em;
  --body-tracking:        0;
  --caps-tracking:        0.1em;       /* uppercase labels */
  --caps-tracking-wide:   0.13em;      /* kickers */
  --caps-tracking-small:  0.06em;      /* tags — tight enough to stay a chip */

  /* Fluid scale. clamp() so a sibling can shift the whole rhythm by editing
     three numbers rather than every breakpoint in base.css. The top of the
     scale came down hard — 5.2rem was a poster, not a page — and the base came
     up, because these are 1,500-word reviews read on a phone. */
  --t-xs:   0.8125rem;
  --t-sm:   0.875rem;
  --t-base: clamp(1.0625rem, 1.02rem + 0.16vw, 1.15rem);
  --t-lg:   clamp(1.1875rem, 1.13rem + 0.24vw, 1.3rem);
  --t-xl:   clamp(1.3rem, 1.14rem + 0.7vw, 1.65rem);
  --t-2xl:  clamp(1.6rem, 1.32rem + 1.2vw, 2.25rem);
  --t-3xl:  clamp(2rem, 1.52rem + 2.1vw, 3.1rem);
  --t-4xl:  clamp(2.4rem, 1.7rem + 3.1vw, 4.1rem);

  --leading-tight: 1.1;
  --leading-head:  1.2;
  --leading-body:  1.7;    /* long-form; was 1.62 */
  --leading-snug:  1.45;   /* meta rows, captions, table cells */

  /* ── Space ────────────────────────────────────────────────────────────── */
  --s-1: 0.25rem;
  --s-2: 0.5rem;
  --s-3: 0.75rem;
  --s-4: 1rem;
  --s-5: 1.5rem;
  --s-6: 2rem;
  --s-7: 3rem;
  --s-8: 4.25rem;
  --s-9: 6rem;

  /* ── Measure and page architecture ────────────────────────────────────────
     62ch of Archivo at this size is ~640px, which is the band long-form actually
     wants. 66ch was pushing 700px+ and costing a line-return on every sweep. */
  --measure:        62ch;
  --measure-narrow: 46ch;   /* standfirsts, captions, pull statements */
  --measure-title:  16ch;   /* the homepage lede head */
  --panel-max:      30rem;  /* the 18+ dialog */
  --strap-basis:    12rem;  /* masthead strapline flex-basis */
  --table-key-w:    34%;    /* spec-table row header column */
  --num-w:          2ch;    /* slot numerals in the margin */
  --page-max:       78rem;
  --rail-width:     19rem;  /* the ledger rail; ignored by 'broadsheet' */
  --gutter:         clamp(1.15rem, 4vw, 3rem);

  /* ── Imagery ──────────────────────────────────────────────────────────────
     Every hero on cdn.coy.co.nz is 1024×1280. The ratio is a token so a sibling
     satellite pointed at a differently-shot catalogue changes one line and no
     component. width/height are still stamped on every <img> — the ratio here
     reserves the box, the attributes stop the reflow if CSS is slow. */
  --img-ratio:      4 / 5;
  --img-fit:        cover;
  --thumb-w:        clamp(4.75rem, 16vw, 7rem);   /* ranked list, index rows */
  --thumb-sm:       3.25rem;                       /* dense link lists */
  --hero-figure-w:  clamp(12.5rem, 30vw, 19rem);   /* review page plate */
  --cover-w:        minmax(0, 1fr);

  /* ── Grid minima. Tokens, not literals, so a sibling's card rhythm differs. */
  --card-min:   15.5rem;
  --figs-min:   8.5rem;
  --split-min:  16rem;
  --cols-min:   14rem;
  --rank-w:     2.25rem;

  /* ── Shape ────────────────────────────────────────────────────────────── */
  --radius-none: 0;
  --radius-sm:   2px;
  --radius-md:   3px;
  --radius-lg:   4px;
  --radius-pill: 999px;
  --border-weight: 1px;
  --border-weight-strong: 2px;
  --border-weight-heavy: 3px;
  --rule-style: solid;

  /* ── Elevation. Deliberately flat — this is print, not an app. ────────── */
  --shadow-none: none;
  --shadow-card: 0 1px 0 var(--rule);
  --shadow-lift: 0 2px 0 var(--rule-strong);

  /* ── Drop cap (broadsheet variant only) ───────────────────────────────── */
  --dropcap-size:    3.4em;
  --dropcap-leading: 0.82;

  /* ── Layers ───────────────────────────────────────────────────────────── */
  --z-gate: 90;
  --z-skip: 100;

  /* ── Motion ───────────────────────────────────────────────────────────── */
  --ease: cubic-bezier(0.2, 0, 0, 1);
  --dur: 140ms;
}

/* Dark is a real reading mode for this category — a lot of the audience reads at
   night on a phone. Only the ground/ink tokens move; roles stay identical, which
   is why no component needs a dark-mode branch. Note --on-brand and
   --ink-invert-quiet flipping independently: in dark mode the brand is a light
   cyan, so the label on a brand fill has to go dark, and the "slab" is the
   darkest surface rather than the lightest. */
@media (prefers-color-scheme: dark) {
  :root {
    --paper:            #14181A;
    --paper-raised:     #1C2225;
    --paper-sunk:       #20262A;
    --paper-invert:     #0B0E0F;

    --ink:              #ECEDE8;
    --ink-quiet:        #C8C9C2;
    --ink-faint:        #B2B5AE;
    --ink-invert:       #ECEDE8;
    --ink-invert-quiet: #A9AFAB;

    --brand:            #79C9DF;
    --brand-deep:       #A9DDEC;
    --brand-wash:       #12303A;
    --brand-invert:     #79C9DF;
    --on-brand:         #08181E;

    --evidence:         #E7A45E;
    --evidence-wash:    #2B2116;

    --safe:             #79C79A;
    --safe-wash:        #16281E;
    --caution:          #F09480;
    --caution-wash:     #2B1815;
    --unknown:          #B4B7B0;
    --unknown-wash:     #242A2C;

    --rule:             #333B3E;
    --rule-strong:      #4C5559;
    --rule-hair:        #262D30;

    --plate:            #232A2D;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   STRUCTURE LAYER — shared across every satellite in the network.

   Two rules hold the §9.2 fingerprint mitigation together:

   1. NO LITERAL VALUES. Every colour, size, space, radius and font in this file
      is a var() from tokens.css. If a hex code or a px size appears here, the
      sibling-site swap stops working and five properties start sharing a face.
      The only literals permitted are structural constants that cannot be
      tokenised: 0, 100%, 1fr/auto in a grid track, counters, and the pixel
      breakpoints in @media — custom properties are not valid in a media query,
      so those four numbers are the one place a sibling has to edit this file.

   2. CLASS NAMES ARE AUTHORED `.x-*`. styles/sheet.mjs rewrites `.x-` to the
      per-site prefix from brand.config.mjs on the way out, so this site ships
      `.snug-card` and satellite #2 ships something else. The `.x-` marker exists
      only so the rewrite can be a precise regex instead of a guess — do not use
      `.x-` for anything that is not a class selector.

   Structural variants live at the bottom under [data-structure]. §9.2's
   mitigation is "vary structure, not just colour"; a palette swap alone leaves
   identical margins and identical DOM rhythm, which is most of what the signal
   actually measures.

   ── ON INVERTED SURFACES ──────────────────────────────────────────────────
   Any block that sets `background: var(--paper-invert)` must also re-point its
   quiet text at `--ink-invert-quiet` and its links at `--brand-invert`. This is
   not stylistic. Before this pass the masthead strapline, the homepage invert
   band and the entire footer legal block — the §12 ownership disclosure among
   them — were painting `--ink-quiet` on `--paper-invert` at roughly 2:1. The
   compliance text was on the page and nobody could read it.
   ═══════════════════════════════════════════════════════════════════════════ */

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--t-base);
  line-height: var(--leading-body);
  letter-spacing: var(--body-tracking);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* The age gate locks the scroll. Applied by the inline script, never by default,
   so a JS-less crawler gets an unlocked, fully readable page. */
html[data-gate="open"] body { overflow: hidden; }

img, svg { max-width: 100%; height: auto; display: block; }

a { color: var(--brand); text-decoration-thickness: var(--border-weight); text-underline-offset: 0.16em; }
a:hover { color: var(--brand-deep); }

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-variation-settings: var(--display-optical);
  font-weight: var(--display-weight);
  line-height: var(--leading-head);
  letter-spacing: var(--display-tracking);
  margin: 0;
  text-wrap: balance;
}
/* Small headings take the TEXT cut of the optical axis, not a shrunk display
   cut. This is most of why the old display face read badly below ~24px: one
   very-high-contrast drawing was being used at every size on the site. */
h3, h4 { font-variation-settings: var(--display-optical-text); font-weight: var(--display-weight-soft); }

p { margin: 0; }

table { border-collapse: collapse; width: 100%; }

.snug-skip {
  position: absolute; left: -9999px; top: 0;
  background: var(--brand); color: var(--on-brand);
  padding: var(--s-3) var(--s-4); z-index: var(--z-skip);
}
.snug-skip:focus { left: 0; }

:where(a, button, summary, input):focus-visible {
  outline: var(--border-weight-strong) solid var(--evidence);
  outline-offset: var(--s-1);
}

/* ── 18+ gate ──────────────────────────────────────────────────────────────
   Content is always in the DOM. The gate is markup that starts [hidden] and is
   revealed by script. An interstitial that gated the HTML itself would hand a
   crawler a single page 267 times, which is the fastest way to make a 267-page
   topical map worth nothing. */
.snug-gate {
  position: fixed; inset: 0; z-index: var(--z-gate);
  display: grid; place-items: center;
  padding: var(--gutter);
  background: color-mix(in srgb, var(--paper-invert) 92%, transparent);
}
.snug-gate[hidden] { display: none; }
.snug-gate__panel {
  background: var(--paper); color: var(--ink);
  max-width: var(--panel-max); width: 100%;
  padding: var(--s-6);
  border-top: var(--border-weight-heavy) var(--rule-style) var(--brand);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lift);
}
.snug-gate__title { font-size: var(--t-xl); margin-bottom: var(--s-3); }
.snug-gate__body { color: var(--ink-quiet); font-size: var(--t-sm); margin: 0 0 var(--s-5); line-height: var(--leading-snug); }
.snug-gate__actions { display: flex; gap: var(--s-3); flex-wrap: wrap; }

.snug-btn {
  font: inherit; font-weight: 600;
  padding: var(--s-3) var(--s-5);
  border: var(--border-weight) var(--rule-style) var(--brand);
  border-radius: var(--radius-sm);
  background: var(--brand); color: var(--on-brand);
  cursor: pointer;
  transition: background var(--dur) var(--ease);
}
.snug-btn:hover { background: var(--brand-deep); border-color: var(--brand-deep); color: var(--on-brand); }
.snug-btn--ghost { background: transparent; color: var(--brand); }
.snug-btn--ghost:hover { background: var(--brand-wash); color: var(--brand-deep); }

/* ── Masthead ──────────────────────────────────────────────────────────────
   A petrol slab rather than a near-black one. It is still the heaviest thing on
   the page — a publication wants a masthead — but it is a colour now, and the
   strapline inside it is actually readable. */
.snug-masthead {
  background: var(--paper-invert);
  color: var(--ink-invert);
  border-bottom: var(--border-weight-heavy) var(--rule-style) var(--brand-invert);
}
.snug-masthead__inner {
  max-width: var(--page-max); margin-inline: auto;
  padding: var(--s-5) var(--gutter);
  display: flex; align-items: baseline; gap: var(--s-5);
  flex-wrap: wrap;
}
.snug-wordmark {
  font-family: var(--font-display);
  font-variation-settings: var(--display-optical);
  font-weight: var(--display-weight);
  font-size: var(--t-xl);
  letter-spacing: var(--display-tracking);
  color: var(--ink-invert); text-decoration: none;
  line-height: var(--leading-tight);
  margin: 0;
}
.snug-wordmark em { font-style: normal; color: var(--brand-invert); }
.snug-wordmark:hover { color: var(--ink-invert); }
.snug-masthead__strap {
  font-size: var(--t-xs); color: var(--ink-invert-quiet);
  text-transform: uppercase; letter-spacing: var(--caps-tracking);
  line-height: var(--leading-snug);
  flex: 1 1 var(--strap-basis);
}
.snug-nav { display: flex; gap: var(--s-5); flex-wrap: wrap; margin-left: auto; }
.snug-nav__link {
  color: var(--ink-invert); text-decoration: none;
  font-size: var(--t-sm); font-weight: 500;
  border-bottom: var(--border-weight-strong) var(--rule-style) transparent;
  padding-bottom: var(--s-1);
}
.snug-nav__link:hover { color: var(--ink-invert); border-bottom-color: var(--brand-invert); }

/* Ownership disclosure strip. §12 requires it on every page; putting it in the
   masthead rather than the footer means it is above the fold on every one of the
   267 pages, which is the difference between disclosed and technically present. */
.snug-ownership {
  background: var(--brand-wash); color: var(--brand-deep);
  font-size: var(--t-xs); line-height: var(--leading-snug);
  border-bottom: var(--border-weight) var(--rule-style) var(--rule);
}
.snug-ownership__inner { max-width: var(--page-max); margin-inline: auto; padding: var(--s-3) var(--gutter); }
.snug-ownership a { color: inherit; }

/* ── Page shell ────────────────────────────────────────────────────────── */
.snug-shell {
  max-width: var(--page-max);
  margin-inline: auto;
  padding: var(--s-7) var(--gutter) var(--s-8);
  display: grid;
  gap: var(--s-7);
}
.snug-main { min-width: 0; }
.snug-main > * + * { margin-top: var(--s-7); }

.snug-crumbs {
  font-size: var(--t-xs); color: var(--ink-quiet);
  margin-bottom: var(--s-5);
  display: flex; gap: var(--s-2); flex-wrap: wrap;
  line-height: var(--leading-snug);
}
.snug-crumbs a { color: var(--ink-quiet); }

/* ── Page head ─────────────────────────────────────────────────────────────
   The kicker carries a short brand rule instead of the hero carrying a heavy
   black underline. Same job — "a new page starts here" — a third of the weight. */
.snug-hero { border-bottom: var(--border-weight) var(--rule-style) var(--rule); padding-bottom: var(--s-6); }
.snug-hero__kicker {
  font-size: var(--t-xs); font-weight: 700;
  text-transform: uppercase; letter-spacing: var(--caps-tracking-wide);
  color: var(--brand); margin-bottom: var(--s-4);
  display: flex; align-items: center; gap: var(--s-3);
  line-height: var(--leading-snug);
}
.snug-hero__kicker::before {
  content: ""; display: block;
  width: var(--s-6); height: var(--border-weight-strong);
  background: var(--brand); flex: none;
}
.snug-hero__title { font-size: var(--t-3xl); }
.snug-hero__standfirst {
  font-size: var(--t-lg); color: var(--ink-quiet);
  max-width: var(--measure); margin-top: var(--s-4);
  text-wrap: pretty;
}

/* Hero with a plate beside it — review pages, brand pages. Stacks on a phone
   with the photograph FIRST, because on a small screen the plate is what tells
   you which of 110 near-identically-named products you are looking at. */
.snug-hero__figure { margin-bottom: var(--s-5); max-width: var(--hero-figure-w); }
.snug-hero__text { min-width: 0; }
@media (min-width: 40rem) {
  .snug-hero--figure { display: grid; grid-template-columns: var(--hero-figure-w) minmax(0, 1fr); gap: var(--s-6); align-items: start; }
  .snug-hero__figure { margin-bottom: 0; max-width: 100%; }
}

/* ── Photographs ───────────────────────────────────────────────────────────
   Every plate is the catalogue's native 4:5, reserved by aspect-ratio here and
   by width/height on the element, so nothing reflows. The mat and the hairline
   frame are load-bearing: the photography is shot on copper-rose satin and
   carries a "coy." wordmark, so without a frame it bleeds into the page and the
   site starts wearing another brand's colour. Framed, it reads as a plate the
   publication has placed — which is exactly what it is. */
.snug-photo { margin: 0; }
.snug-photo__frame {
  display: block; position: relative;
  aspect-ratio: var(--img-ratio);
  background: var(--plate);
  border: var(--border-weight) var(--rule-style) var(--rule);
  border-radius: var(--radius-md);
  overflow: hidden;
}
a.snug-photo__frame { text-decoration: none; transition: border-color var(--dur) var(--ease); }
a.snug-photo__frame:hover { border-color: var(--brand); }
.snug-photo__img {
  width: 100%; height: 100%;
  object-fit: var(--img-fit);
  display: block;
}
/* The 9 products with no photograph. Same box, on purpose. */
.snug-photo__none {
  position: absolute; inset: 0;
  display: grid; align-content: center; justify-items: center; gap: var(--s-2);
  padding: var(--s-3); text-align: center;
  background: var(--paper-sunk);
}
.snug-photo__monogram {
  font-family: var(--font-display);
  font-variation-settings: var(--display-optical);
  font-weight: var(--display-weight);
  font-size: var(--t-2xl); line-height: var(--leading-tight);
  letter-spacing: var(--display-tracking);
  color: var(--ink-faint);
}
.snug-photo__nonelab {
  font-size: var(--t-xs); line-height: var(--leading-snug);
  text-transform: uppercase; letter-spacing: var(--caps-tracking);
  color: var(--ink-faint);
}
.snug-photo--thumb { width: var(--thumb-w); flex: none; }
.snug-photo--row   { width: var(--thumb-sm); flex: none; }
.snug-photo--bare .snug-photo__frame { border: 0; border-radius: 0; }
/* At thumbnail sizes the plate is too small to carry the "no photograph on
   file" line — it clipped rather than wrapped. The monogram alone reads as an
   intentional blank, and the full sentence is still on the element's
   aria-label, so nothing is lost for a screen reader. */
.snug-photo--thumb .snug-photo__nonelab,
.snug-photo--row   .snug-photo__nonelab { display: none; }
.snug-photo--thumb .snug-photo__monogram { font-size: var(--t-lg); }
.snug-photo--row   .snug-photo__monogram { font-size: var(--t-sm); }

/* Contact sheet — homepage cover, brand-page range strip. */
.snug-cover { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s-3); }

/* ── Brief slots ───────────────────────────────────────────────────────────
   One <section> per brief-schema slot, in schema order, id = slot id. The ids
   are the addressable targets §7.5 depends on: moving a question from slot 2 to
   slot 3 across all 110 reviews is a schema edit, not 110 prose edits. Never
   rename one to read better. */
.snug-slot {
  scroll-margin-top: var(--s-6);
  border-top: var(--border-weight) var(--rule-style) var(--rule-hair);
  padding-top: var(--s-6);
}
.snug-slot:first-child { border-top: 0; padding-top: 0; }
/* The page head already draws a rule. Without this the first slot draws a
   second one a few rem below it and every page opens on a double line — the
   `:first-child` above never matched, because the breadcrumbs and the <header>
   are the actual first children of .snug-main. */
.snug-hero + .snug-slot { border-top: 0; padding-top: 0; }
.snug-slot__head {
  display: flex; align-items: baseline; gap: var(--s-3);
  margin-bottom: var(--s-5);
}
.snug-slot__num {
  font-family: var(--font-mono); font-size: var(--t-xs);
  color: var(--ink-faint);
  min-width: var(--num-w);
}
.snug-slot__title { font-size: var(--t-xl); font-variation-settings: var(--display-optical-text); font-weight: var(--display-weight); }
.snug-slot__body { max-width: var(--measure); }
.snug-slot__body > * + * { margin-top: var(--s-5); }

/* Scaffold affordance. An empty slot stays visible and machine-findable so the
   generator has somewhere to write and a reviewer can check slot ORDER before a
   single word exists. SNUG_SLOT_MODE=production drops these per brief-schema's
   dropIfEmpty instead. */
.snug-slot--empty .snug-slot__title { color: var(--ink-faint); }
.snug-slot__hint {
  font-family: var(--font-mono); font-size: var(--t-xs);
  line-height: var(--leading-snug);
  color: var(--ink-faint);
  background: var(--paper-sunk);
  border-left: var(--border-weight-strong) var(--rule-style) var(--rule-strong);
  padding: var(--s-3) var(--s-4);
  white-space: pre-wrap; word-break: break-word;
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}
.snug-slot__hint b { color: var(--ink-quiet); font-weight: 600; }

.snug-prose { max-width: var(--measure); }
.snug-prose p { margin: 0 0 var(--s-5); text-wrap: pretty; }
.snug-prose p:last-child { margin-bottom: 0; }
.snug-placeholder {
  color: var(--ink-faint); font-style: italic;
  border-left: var(--border-weight-strong) var(--rule-style) var(--rule);
  padding-left: var(--s-4);
  line-height: var(--leading-snug);
}

/* ── Evidence figures ──────────────────────────────────────────────────────
   The factual spine. Aggregated star ratings and review counts live HERE, as
   clearly-sourced visible content, and NOWHERE in the JSON-LD — see lib/schema.mjs.

   copy-rules.md demotes evidence to "the flourish, not the subject", so this
   block reads as a quiet plate under a claim rather than as a scoreboard. */
.snug-evidence {
  background: var(--paper-raised);
  border: var(--border-weight) var(--rule-style) var(--rule);
  border-radius: var(--radius-md);
  padding: var(--s-5);
}
.snug-evidence__grid {
  display: grid; gap: var(--s-5);
  grid-template-columns: repeat(auto-fit, minmax(var(--figs-min), 1fr));
}
.snug-evidence__fig {
  font-family: var(--font-display);
  font-variation-settings: var(--display-optical);
  font-weight: var(--display-weight);
  font-size: var(--t-2xl); line-height: var(--leading-tight);
  color: var(--evidence);
  font-variant-numeric: tabular-nums;
  letter-spacing: var(--display-tracking);
  display: block;
}
.snug-evidence__fig--muted { color: var(--ink-faint); font-size: var(--t-lg); }
.snug-evidence__lab {
  display: block; margin-top: var(--s-2);
  font-size: var(--t-xs); color: var(--ink-quiet);
  text-transform: uppercase; letter-spacing: var(--caps-tracking);
  line-height: var(--leading-snug);
}
.snug-evidence__source {
  margin-top: var(--s-5); padding-top: var(--s-4);
  border-top: var(--border-weight) var(--rule-style) var(--rule-hair);
  font-size: var(--t-xs); color: var(--ink-quiet);
  line-height: var(--leading-snug);
}

.snug-score { display: inline-flex; align-items: baseline; gap: var(--s-3); }
.snug-score__num {
  font-family: var(--font-display);
  font-variation-settings: var(--display-optical);
  font-weight: var(--display-weight);
  font-size: var(--t-2xl); line-height: var(--leading-tight);
  color: var(--brand); font-variant-numeric: tabular-nums;
  letter-spacing: var(--display-tracking);
}
.snug-score__grade {
  font-size: var(--t-xs); font-weight: 600;
  text-transform: uppercase; letter-spacing: var(--caps-tracking);
  color: var(--ink-quiet);
}
.snug-score--sm .snug-score__num { font-size: var(--t-lg); }

/* ── Tags ──────────────────────────────────────────────────────────────── */
.snug-tag {
  display: inline-block;
  font-size: var(--t-xs); font-weight: 600;
  text-transform: uppercase; letter-spacing: var(--caps-tracking-small);
  line-height: var(--leading-snug);
  padding: var(--s-1) var(--s-2);
  border-radius: var(--radius-sm);
  background: var(--unknown-wash); color: var(--unknown);
  border: var(--border-weight) var(--rule-style) currentColor;
}
.snug-tag--safe    { background: var(--safe-wash);    color: var(--safe); }
.snug-tag--caution { background: var(--caution-wash); color: var(--caution); }
.snug-tag--unknown { background: var(--unknown-wash); color: var(--unknown); }

/* ── Spec / comparable tables ──────────────────────────────────────────────
   Provenance is rendered, always. A row whose provenance is not-in-supplier-data
   renders "Not stated" — it is NEVER dropped. Dropping it reads as "this product
   has no flared base" instead of "we do not know", and flared base is the one
   attribute in this category where that inversion sends someone to an ED.

   Visually SUBORDINATE, per copy-rules.md ("Result first, specification last —
   they belong near the bottom, small, for the reader who has decided and wants
   to check a number"). Small type, sunk ground, no display face. The page is not
   a spec sheet and must not look like one. */
.snug-spec {
  font-size: var(--t-sm); line-height: var(--leading-snug);
  background: var(--paper-sunk);
  border: var(--border-weight) var(--rule-style) var(--rule);
  border-radius: var(--radius-md);
  overflow: hidden;
}
.snug-spec th, .snug-spec td {
  text-align: left; vertical-align: top;
  padding: var(--s-3) var(--s-4);
  border-bottom: var(--border-weight) var(--rule-style) var(--rule-hair);
}
.snug-spec tr:last-child th, .snug-spec tr:last-child td { border-bottom: 0; }
.snug-spec thead th {
  font-size: var(--t-xs); text-transform: uppercase; letter-spacing: var(--caps-tracking);
  color: var(--ink-quiet); border-bottom-color: var(--rule-strong);
  font-family: var(--font-body); font-weight: 700;
}
.snug-spec tbody th { font-weight: 600; width: var(--table-key-w); color: var(--ink-quiet); }
.snug-spec td { font-variant-numeric: tabular-nums; }
.snug-spec__val--unknown { color: var(--ink-faint); font-style: italic; }
.snug-spec__prov {
  display: block; margin-top: var(--s-1);
  font-size: var(--t-xs); color: var(--ink-faint);
  font-family: var(--font-mono);
}
.snug-spec caption {
  caption-side: bottom; text-align: left;
  padding-top: var(--s-3);
  font-size: var(--t-xs); color: var(--ink-quiet);
  line-height: var(--leading-snug);
}

/* ── Cards and ranked lists ────────────────────────────────────────────── */
.snug-cards {
  display: grid; gap: var(--s-5);
  grid-template-columns: repeat(auto-fill, minmax(var(--card-min), 1fr));
  list-style: none; padding: 0; margin: 0;
}
.snug-card {
  background: var(--paper-raised);
  border: var(--border-weight) var(--rule-style) var(--rule);
  border-radius: var(--radius-md);
  padding: 0; overflow: hidden;
  display: flex; flex-direction: column;
  box-shadow: var(--shadow-card);
}
/* The plate sits flush to the card edge and borrows the card's own frame. */
.snug-card .snug-photo__frame { border: 0; border-radius: 0; border-bottom: var(--border-weight) var(--rule-style) var(--rule); }
.snug-card__body {
  padding: var(--s-4);
  display: flex; flex-direction: column; gap: var(--s-2);
  flex: 1 1 auto; min-width: 0;
}
.snug-card__kicker {
  font-size: var(--t-xs); text-transform: uppercase; letter-spacing: var(--caps-tracking);
  color: var(--ink-quiet); line-height: var(--leading-snug);
}
.snug-card__title { font-size: var(--t-lg); overflow-wrap: break-word; }
.snug-card__title a { text-decoration: none; color: var(--ink); }
.snug-card__title a:hover { color: var(--brand); text-decoration: underline; }
.snug-card__meta {
  font-size: var(--t-xs); color: var(--ink-quiet);
  line-height: var(--leading-snug);
  margin-top: auto; padding-top: var(--s-3);
}

/* Ranked picks. Three regions: the numeral, the plate under it, and the body
   spanning both rows. The numeral stays in the margin — that is the 'ledger'
   structure's signature — but it is brand-coloured now rather than a pale grey
   that failed contrast at the exact moment it was carrying the ranking. */
.snug-ranked { list-style: none; padding: 0; margin: 0; counter-reset: pick; }
.snug-ranked > li {
  counter-increment: pick;
  display: grid;
  grid-template-columns: var(--thumb-w) minmax(0, 1fr);
  column-gap: var(--s-5); row-gap: var(--s-3);
  align-items: start;
  padding: var(--s-6) 0;
  border-bottom: var(--border-weight) var(--rule-style) var(--rule-hair);
}
.snug-ranked > li::before {
  content: counter(pick);
  grid-column: 1; grid-row: 1;
  font-family: var(--font-display);
  font-variation-settings: var(--display-optical);
  font-weight: var(--display-weight);
  font-size: var(--t-xl); line-height: var(--leading-tight);
  color: var(--brand);
  font-variant-numeric: tabular-nums;
  letter-spacing: var(--display-tracking);
}
.snug-pick__media { grid-column: 1; grid-row: 2; }
.snug-pick__body { grid-column: 2; grid-row: 1 / span 2; min-width: 0; }
.snug-pick__body > * + * { margin-top: var(--s-3); }
.snug-pick__title { font-size: var(--t-lg); overflow-wrap: break-word; }
.snug-pick__title a { text-decoration: none; color: var(--ink); }
.snug-pick__title a:hover { color: var(--brand); text-decoration: underline; }
.snug-pick__meta {
  font-size: var(--t-sm); color: var(--ink-quiet);
  display: flex; gap: var(--s-4); flex-wrap: wrap; align-items: baseline;
  line-height: var(--leading-snug);
}

.snug-linklist { list-style: none; padding: 0; margin: 0; }
.snug-linklist li { padding: var(--s-3) 0; border-bottom: var(--border-weight) var(--rule-style) var(--rule-hair); }
.snug-linklist__meta { display: block; font-size: var(--t-xs); color: var(--ink-quiet); line-height: var(--leading-snug); }
/* Index rows carrying a plate — /reviews/ is 110 rows of near-identical names,
   and the thumbnail is the only thing that tells two of them apart at a glance. */
.snug-linklist--media li {
  display: grid; grid-template-columns: var(--thumb-sm) minmax(0, 1fr);
  gap: var(--s-4); align-items: center;
  padding: var(--s-3) 0;
}

/* ── Notes ─────────────────────────────────────────────────────────────────
   The border and the wash carry the semantics; the TEXT is ink. Colouring a
   whole paragraph --caution put body copy at ~6:1 and, worse, made a plain
   statement about cleaning look like a hazard label — which copy-rules.md §2
   explicitly forbids ("safety is a confidence signal, not a warning"). */
.snug-note {
  background: var(--paper-sunk); color: var(--ink);
  border-left: var(--border-weight-heavy) var(--rule-style) var(--rule-strong);
  padding: var(--s-4) var(--s-5);
  font-size: var(--t-sm);
  line-height: var(--leading-snug);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}
.snug-note > * + * { margin-top: var(--s-3); }
.snug-note--caution { background: var(--caution-wash); border-left-color: var(--caution); }
.snug-note--safe { background: var(--safe-wash); border-left-color: var(--safe); }
.snug-note--evidence { background: var(--evidence-wash); border-left-color: var(--evidence); }
.snug-note strong { font-weight: 700; }

/* Marks an internal link target that the topical map references but does not
   contain. Rendered as text, never as an <a> — a link to a page that was never
   planned is a 404 in the crawl budget. */
.snug-todo {
  font-family: var(--font-mono); font-size: var(--t-xs);
  color: var(--ink); background: var(--caution-wash);
  border: var(--border-weight) var(--rule-style) var(--caution);
  padding: 0 var(--s-2); border-radius: var(--radius-sm);
}

/* ── Where to buy — ANOTHER AGENT'S COMPONENT ──────────────────────────── */
.snug-buy {
  border: var(--border-weight) var(--rule-style) var(--rule);
  border-top: var(--border-weight-heavy) var(--rule-style) var(--brand);
  border-radius: var(--radius-md);
  padding: var(--s-5);
  background: var(--paper-raised);
}
.snug-buy > * + * { margin-top: var(--s-3); }
.snug-buy__stub {
  font-family: var(--font-mono); font-size: var(--t-xs);
  color: var(--ink-faint); line-height: var(--leading-snug);
}

/* ── Furniture: byline, disclosure, updated ────────────────────────────── */
.snug-byline {
  border-top: var(--border-weight) var(--rule-style) var(--rule);
  border-bottom: var(--border-weight) var(--rule-style) var(--rule);
  padding: var(--s-5) 0;
  font-size: var(--t-sm);
  line-height: var(--leading-snug);
}
.snug-byline__who { font-weight: 700; }
.snug-byline__bio { color: var(--ink-quiet); margin-top: var(--s-2); max-width: var(--measure); }
.snug-byline__review { color: var(--caution); margin-top: var(--s-3); font-size: var(--t-xs); max-width: var(--measure); }

.snug-updated {
  font-size: var(--t-xs); color: var(--ink-quiet);
  display: flex; gap: var(--s-4); flex-wrap: wrap;
  font-variant-numeric: tabular-nums;
  line-height: var(--leading-snug);
}

.snug-disclosure {
  background: var(--paper-sunk);
  border: var(--border-weight) var(--rule-style) var(--rule);
  border-radius: var(--radius-md);
  padding: var(--s-5);
  font-size: var(--t-sm); color: var(--ink-quiet);
  line-height: var(--leading-snug);
}
.snug-disclosure strong { color: var(--ink); }

/* ── Rail (ledger structure only) ──────────────────────────────────────── */
.snug-rail { min-width: 0; font-size: var(--t-sm); }
.snug-rail > * + * { margin-top: var(--s-5); }
.snug-rail__box {
  border: var(--border-weight) var(--rule-style) var(--rule);
  border-radius: var(--radius-md);
  padding: var(--s-4);
  background: var(--paper-raised);
  line-height: var(--leading-snug);
}
.snug-rail__title {
  font-size: var(--t-xs); text-transform: uppercase; letter-spacing: var(--caps-tracking);
  color: var(--ink-quiet); margin-bottom: var(--s-3);
  font-family: var(--font-body); font-weight: 700;
}
.snug-rail__toc { list-style: none; padding: 0; margin: 0; font-size: var(--t-xs); }
.snug-rail__toc li { padding: var(--s-2) 0; }
.snug-rail__toc a { color: var(--ink-quiet); text-decoration: none; }
.snug-rail__toc a:hover { color: var(--brand); text-decoration: underline; }

/* ── Head-to-head plates ───────────────────────────────────────────────── */
.snug-versus {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  gap: var(--s-4); align-items: center;
  margin-top: var(--s-5);
  max-width: var(--measure);
}
.snug-versus__mark {
  font-family: var(--font-display);
  font-variation-settings: var(--display-optical-text);
  font-weight: var(--display-weight);
  font-size: var(--t-lg); color: var(--ink-faint);
  text-transform: uppercase; letter-spacing: var(--caps-tracking);
}

/* ── Homepage ──────────────────────────────────────────────────────────────
   The lede used to be a wall of text with four numbers under it. It is now text
   against a contact sheet of the catalogue, which is the fastest honest way to
   say "this is a publication about 110 real objects" before a word is read. */
.snug-lede {
  padding: var(--s-8) var(--gutter) var(--s-7);
  max-width: var(--page-max); margin-inline: auto;
}
.snug-lede__inner { display: grid; gap: var(--s-6); align-items: start; }
@media (min-width: 52rem) {
  .snug-lede__inner { grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr); gap: var(--s-8); }
}
.snug-lede__title { font-size: var(--t-4xl); max-width: var(--measure-title); }
.snug-lede__sub { font-size: var(--t-lg); color: var(--ink-quiet); max-width: var(--measure); margin-top: var(--s-5); text-wrap: pretty; }
.snug-lede__figures {
  display: grid; gap: var(--s-5);
  grid-template-columns: repeat(auto-fit, minmax(var(--figs-min), 1fr));
  margin-top: var(--s-6); padding-top: var(--s-5);
  border-top: var(--border-weight-strong) var(--rule-style) var(--rule-strong);
}
.snug-band { border-top: var(--border-weight) var(--rule-style) var(--rule); }
.snug-band__inner { max-width: var(--page-max); margin-inline: auto; padding: var(--s-8) var(--gutter); }
.snug-band--invert { background: var(--paper-invert); color: var(--ink-invert); border-top-color: var(--paper-invert); }
.snug-band--invert .snug-band__title { color: var(--ink-invert); }
.snug-band--invert a { color: var(--brand-invert); }
.snug-band--invert a:hover { color: var(--ink-invert); }
.snug-band--invert .snug-band__standfirst { color: var(--ink-invert-quiet); }
.snug-band--invert .snug-linklist li { border-bottom-color: var(--rule-strong); }
.snug-band__title { font-size: var(--t-2xl); max-width: var(--measure); }
.snug-band__standfirst { color: var(--ink-quiet); max-width: var(--measure); margin-top: var(--s-4); text-wrap: pretty; }
.snug-band__body { margin-top: var(--s-6); }

.snug-splitfigs { display: grid; gap: var(--s-5); grid-template-columns: repeat(auto-fit, minmax(var(--split-min), 1fr)); }

/* ── Footer ────────────────────────────────────────────────────────────── */
.snug-footer {
  background: var(--paper-invert); color: var(--ink-invert);
  border-top: var(--border-weight-heavy) var(--rule-style) var(--brand-invert);
  margin-top: var(--s-8);
}
.snug-footer__inner { max-width: var(--page-max); margin-inline: auto; padding: var(--s-8) var(--gutter); }
.snug-footer__cols { display: grid; gap: var(--s-6); grid-template-columns: repeat(auto-fit, minmax(var(--cols-min), 1fr)); }
.snug-footer a { color: var(--ink-invert); }
.snug-footer a:hover { color: var(--brand-invert); }
.snug-footer .snug-linklist li { border-bottom-color: var(--rule-strong); }
/* Inverted ground — quiet text has to flip with it. The ownership disclosure
   and the byline bio both live in this block. */
.snug-footer .snug-quiet, .snug-footer .snug-faint { color: var(--ink-invert-quiet); }
.snug-footer__legal {
  margin-top: var(--s-7); padding-top: var(--s-5);
  border-top: var(--border-weight) var(--rule-style) var(--rule-strong);
  font-size: var(--t-xs); color: var(--ink-invert-quiet);
  line-height: var(--leading-snug);
  display: grid; gap: var(--s-3);
}
.snug-footer__legal p { margin: 0; max-width: var(--measure); }
.snug-agemark {
  display: inline-block; border: var(--border-weight-strong) var(--rule-style) currentColor;
  border-radius: var(--radius-pill); padding: 0 var(--s-2);
  font-weight: 700; font-size: var(--t-xs);
}

.snug-quiet { color: var(--ink-quiet); }
.snug-faint { color: var(--ink-faint); }
.snug-visually-hidden {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}

/* ═══════════════════════════════════════════════════════════════════════════
   STRUCTURAL VARIANTS — the §9.2 lever.
   brand.config.mjs sets `structure`; BaseLayout stamps it on <html>. Changing
   the one value gives a sibling site different columns, different rhythm and a
   different reading order, not a recoloured clone.
   ═══════════════════════════════════════════════════════════════════════════ */

/* LEDGER — asymmetric measure, sticky evidence rail on the right, numerals in
   the margin of every slot. The evidence count is the point of this site, so it
   sits in the furniture rather than buried in prose. */
[data-structure="ledger"] .snug-shell { grid-template-columns: minmax(0, 1fr); }
@media (min-width: 60rem) {
  [data-structure="ledger"] .snug-shell {
    grid-template-columns: minmax(0, 1fr) var(--rail-width);
    gap: var(--s-8);
  }
  [data-structure="ledger"] .snug-rail { position: sticky; top: var(--s-5); align-self: start; }
}
[data-structure="ledger"] .snug-hero__title { font-size: var(--t-3xl); }

/* BROADSHEET — single centred measure, no rail, drop cap on the opening slot,
   heavier heads. Reserved for a sibling satellite; kept here so the switch is
   real and tested rather than aspirational. */
[data-structure="broadsheet"] .snug-shell {
  grid-template-columns: minmax(0, 1fr);
  max-width: calc(var(--measure) + var(--gutter) * 2);
}
[data-structure="broadsheet"] .snug-rail {
  border-top: var(--border-weight-strong) var(--rule-style) var(--rule-strong);
  padding-top: var(--s-5);
}
[data-structure="broadsheet"] .snug-rail__toc { columns: 2; }
[data-structure="broadsheet"] .snug-slot { border-top: 0; padding-top: var(--s-6); }
[data-structure="broadsheet"] .snug-slot__num { display: none; }
[data-structure="broadsheet"] .snug-slot__title { font-size: var(--t-2xl); }
[data-structure="broadsheet"] .snug-hero { border-bottom-width: var(--border-weight); }
[data-structure="broadsheet"] .snug-hero--figure { grid-template-columns: minmax(0, 1fr); }
[data-structure="broadsheet"] .snug-slot:first-of-type .snug-prose > p:first-child::first-letter {
  float: left; font-family: var(--font-display); font-size: var(--dropcap-size);
  line-height: var(--dropcap-leading); padding-right: var(--s-2); color: var(--brand);
}

/* Generated prose. Deliberately narrow measure and generous leading — these pages
   are read, not scanned, and the evidence figures inside them have to stay
   findable in a wall of text. */
.snug-prose > p { margin: 0 0 var(--s-5); max-width: var(--measure); }
.snug-prose > p:last-child { margin-bottom: 0; }
.snug-prose strong { color: var(--ink); font-weight: 600; }
.snug-prose ul, .snug-prose ol { margin: 0 0 var(--s-5) var(--s-5); max-width: var(--measure); }
.snug-prose li { margin-bottom: var(--s-3); }

/* Video facade. Sized by aspect-ratio so nothing shifts when the iframe swaps in. */
.snug-video { margin: var(--s-5) 0; max-width: var(--measure); }
.snug-video__frame { position: relative; aspect-ratio: 16 / 9; background: var(--paper-sunk);
  border: 1px solid var(--rule); border-radius: var(--radius); overflow: hidden; }
.snug-video__frame img, .snug-video__frame iframe { width: 100%; height: 100%; object-fit: cover; display: block; border: 0; }
.snug-video__play { position: absolute; inset: 0; margin: auto; width: 4rem; height: 4rem;
  border-radius: 999px; border: 0; cursor: pointer; background: var(--brand); color: var(--on-brand);
  font-size: 1.4rem; line-height: 1; display: grid; place-items: center; }
.snug-video__play:hover { background: var(--brand-deep); }
.snug-video__cap { margin-top: var(--s-3); font-size: var(--t-sm); color: var(--ink-quiet); }
.snug-video__kind { display: block; font-weight: 600; color: var(--ink); }
.snug-video__meta { display: block; margin-top: var(--s-1); }

