/* ============================================================================
   Deep Stack — design system
   One stylesheet, no dependencies, no external fonts. Loaded by every page via
   a RELATIVE path so the site works from file:// as well as from a server.

   Conventions used throughout:
     .prose      long-form reading column, capped at a comfortable measure
     .callout    semantic aside (insight / warning / danger / canon)
     .cmp        two-column theory-vs-practice comparison
     .fig        figure wrapper for inline SVG diagrams
     .code       code block with language tab + copy button
   ========================================================================== */

/* ---------- tokens ---------------------------------------------------- */

:root {
  /* Neutral ramp — cool grey, tuned so 2 steps is always a visible change */
  --n-0:#ffffff; --n-25:#fbfcfd; --n-50:#f6f8fa; --n-100:#eef1f5; --n-150:#e4e9ef;
  /* n-500 darkened from #6b7c90 for WCAG AA. Its only consumer is --ink-3,
     and at the old value every muted-text element failed 4.5:1 on the light
     ground — worst on .tag, which sits on --surface-3 rather than the page
     background and measured 3.17:1. Ramp order is unchanged. */
  --n-200:#d8dfe7; --n-300:#bcc7d3; --n-400:#93a2b3; --n-500:#5c6c80;
  --n-600:#4e5e72; --n-700:#3a4757; --n-800:#28323f; --n-850:#1e2731;
  --n-900:#161d25; --n-950:#0f141a;

  /* Accents. Indigo carries identity; the rest are strictly semantic. */
  --brand:#4f46e5; --brand-l:#6366f1; --brand-d:#3730a3;
  /* ok darkened from #0f9960 for AA. It is a text colour as well as a stroke
     colour — .tag.v, .cmp-head and .t-yes all set type in it — and on the
     light theme's tinted fill it measured 3.17:1. */
  --ok:#0a7448; --ok-l:#16a34a;
  --warn:#b45309; --warn-l:#d97706;
  --bad:#c02626; --bad-l:#dc2626;
  --info:#0369a1; --info-l:#0284c7;
  --canon:#7c3aed;

  /* Semantic surface tokens — every component reads these, never the ramp,
     so dark mode is a single block of overrides at the bottom. */
  --bg:var(--n-25);
  --bg-sunken:var(--n-50);
  --surface:var(--n-0);
  --surface-2:var(--n-50);
  --surface-3:var(--n-100);
  --border:var(--n-200);
  --border-strong:var(--n-300);
  --ink:var(--n-900);
  --ink-2:var(--n-700);
  --ink-3:var(--n-500);
  --ink-inv:var(--n-0);

  --accent:var(--brand);
  --accent-soft:color-mix(in srgb, var(--brand) 8%, transparent);
  /* Text sitting ON the accent fill. The system had no token for this, so
     .skip hard-coded white — which is correct on the light theme's deep
     indigo and fails at 2.98:1 on the dark theme's lighter one. */
  --on-accent:var(--n-0);

  /* Type. System stacks only — no network fetch, no layout shift. */
  --sans:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
  --serif:ui-serif,Georgia,Cambria,"Times New Roman",serif;
  --mono:ui-monospace,"SF Mono","Cascadia Code","JetBrains Mono",Consolas,"Liberation Mono",monospace;

  --step--1:clamp(.82rem,.8rem + .1vw,.875rem);
  --step-0:clamp(1rem,.97rem + .15vw,1.0625rem);
  --step-1:clamp(1.15rem,1.1rem + .25vw,1.25rem);
  --step-2:clamp(1.35rem,1.25rem + .5vw,1.6rem);
  --step-3:clamp(1.6rem,1.4rem + .9vw,2.1rem);
  --step-4:clamp(2rem,1.65rem + 1.6vw,2.9rem);

  --measure:68ch;
  --radius:10px;
  --radius-sm:6px;
  --shadow-1:0 1px 2px rgba(16,24,40,.06),0 1px 3px rgba(16,24,40,.1);
  --shadow-2:0 4px 8px -2px rgba(16,24,40,.1),0 2px 4px -2px rgba(16,24,40,.06);
  --shadow-3:0 12px 20px -6px rgba(16,24,40,.12),0 4px 8px -4px rgba(16,24,40,.08);

  --header-h:58px;
}

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

html{-webkit-text-size-adjust:100%;scroll-behavior:smooth;scroll-padding-top:calc(var(--header-h) + 18px)}
@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto}
  *,*::before,*::after{animation-duration:.01ms!important;transition-duration:.01ms!important}}

body{
  margin:0;background:var(--bg);color:var(--ink);
  font-family:var(--sans);font-size:var(--step-0);line-height:1.65;
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;
}

/* ---------- skip link & a11y ------------------------------------------ */

.skip{position:absolute;left:-9999px;top:0;z-index:200;background:var(--accent);color:var(--on-accent);
  padding:10px 16px;border-radius:0 0 var(--radius-sm) 0;font-weight:600}
.skip:focus{left:0}
:focus-visible{outline:2.5px solid var(--accent);outline-offset:2px;border-radius:3px}
.vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;border:0}

/* ---------- header ----------------------------------------------------- */

.site-header{
  position:sticky;top:0;z-index:100;height:var(--header-h);
  display:flex;align-items:center;gap:18px;
  padding:0 clamp(16px,3vw,32px);
  background:color-mix(in srgb,var(--surface) 88%,transparent);
  backdrop-filter:saturate(180%) blur(12px);
  -webkit-backdrop-filter:saturate(180%) blur(12px);
  border-bottom:1px solid var(--border);
}
.site-header .brand{display:flex;align-items:center;gap:9px;font-weight:700;
  letter-spacing:-.02em;color:var(--ink);text-decoration:none;font-size:var(--step-0);white-space:nowrap}
/* The mark carries its own ground and rounding inside the SVG, so the tile
   that used to sit behind it is gone. That also cuts the logo's dependency on
   --brand, which is the point: the mark is arctic whatever the accent does. */
.site-header .brand .mark{
  width:24px;height:24px;flex:none;display:grid;place-items:center}
.site-header .brand .mark svg{display:block}
.site-header nav{margin-left:auto;display:flex;align-items:center;gap:4px}
.site-header nav a{
  color:var(--ink-2);text-decoration:none;font-size:var(--step--1);font-weight:500;
  padding:6px 11px;border-radius:var(--radius-sm);white-space:nowrap}
/* Secondary nav is a convenience, not the only route home — drop it before it
   wraps and breaks the header's fixed height. */
@media (max-width:760px){.site-header nav a:not(:first-child){display:none}}
.site-header nav a:hover{background:var(--surface-3);color:var(--ink)}
.site-header nav a[aria-current="page"]{color:var(--accent);background:var(--accent-soft)}

.theme-toggle{
  position:relative;
  width:34px;height:34px;flex:none;display:grid;place-items:center;cursor:pointer;
  background:transparent;border:1px solid var(--border);border-radius:var(--radius-sm);
  color:var(--ink-2)}
/* The drawn control stays 34px so the header keeps its density; only the hit
   area grows, to 44x44. Enlarging the element itself would widen the flex row
   and shift the nav, which is a visual change this does not need to make.
   Not gated behind pointer:coarse — Fitts's law applies to a mouse too, and a
   larger target costs a pointer user nothing.
   6px a side, not 5: an absolutely positioned inset resolves against the
   PADDING box, and this control carries a 1px border, so the box being grown
   is 32px. 32 + 2x6 = 44. Measured by hit-testing, not assumed; 5px yields 42. */
.theme-toggle::after{content:"";position:absolute;inset:-6px}
.theme-toggle:hover{background:var(--surface-3);color:var(--ink)}
.theme-toggle svg{width:16px;height:16px}
.theme-toggle .i-sun{display:none}
:root[data-theme="dark"] .theme-toggle .i-sun{display:block}
:root[data-theme="dark"] .theme-toggle .i-moon{display:none}

/* ---------- layout ------------------------------------------------------ */

.shell{max-width:1440px;margin:0 auto;padding:0 clamp(16px,3vw,32px)}

/* Article layout: TOC rail + reading column. Rail collapses under 1100px. */
.doc{
  display:grid;grid-template-columns:minmax(0,1fr) 244px;
  gap:clamp(24px,4vw,64px);align-items:start;
  max-width:1180px;margin:0 auto;padding:0 clamp(16px,3vw,32px)}
@media (max-width:1100px){.doc{grid-template-columns:minmax(0,1fr)}
  .toc{display:none}}

.prose{min-width:0;max-width:var(--measure);padding-block:8px 96px}
.prose.wide{max-width:none}

/* ---------- TOC --------------------------------------------------------- */

.toc{position:sticky;top:calc(var(--header-h) + 24px);max-height:calc(100vh - var(--header-h) - 56px);
  overflow-y:auto;padding:4px 0 24px;font-size:var(--step--1)}
.toc h2{font-size:11px;text-transform:uppercase;letter-spacing:.09em;color:var(--ink-3);
  margin:0 0 10px;font-weight:700}
.toc ol{list-style:none;margin:0;padding:0;border-left:1.5px solid var(--border)}
.toc li{margin:0}
.toc a{display:block;padding:5px 0 5px 14px;margin-left:-1.5px;
  border-left:1.5px solid transparent;color:var(--ink-3);text-decoration:none;line-height:1.4}
.toc a:hover{color:var(--ink)}
.toc a.active{color:var(--accent);border-left-color:var(--accent);font-weight:600}
.toc .lvl-3 a{padding-left:26px;font-size:.94em}

/* ---------- prose typography -------------------------------------------- */

.prose h1{font-size:var(--step-4);line-height:1.1;letter-spacing:-.032em;margin:0 0 14px;font-weight:800}
.prose h2{font-size:var(--step-3);line-height:1.2;letter-spacing:-.024em;
  margin:56px 0 16px;font-weight:700;scroll-margin-top:calc(var(--header-h) + 18px)}
.prose h3{font-size:var(--step-2);line-height:1.3;letter-spacing:-.016em;
  margin:38px 0 12px;font-weight:670;scroll-margin-top:calc(var(--header-h) + 18px)}
.prose h4{font-size:var(--step-1);margin:28px 0 8px;font-weight:650}
.prose h2+h3{margin-top:22px}
.prose p{margin:0 0 18px}
.prose>p:first-of-type{font-size:var(--step-1);line-height:1.6;color:var(--ink-2)}
.prose a{color:var(--accent);text-underline-offset:2.5px;text-decoration-thickness:1.2px}
.prose a:hover{text-decoration-thickness:2px}
.prose strong{font-weight:660;color:var(--ink)}
.prose em{font-style:italic}
.prose ul,.prose ol{margin:0 0 18px;padding-left:24px}
.prose li{margin:0 0 8px}
.prose li::marker{color:var(--ink-3)}
.prose hr{border:0;border-top:1px solid var(--border);margin:44px 0}
.prose code:not(pre code){
  font-family:var(--mono);font-size:.875em;background:var(--surface-3);
  padding:.14em .38em;border-radius:4px;border:1px solid var(--border);
  word-break:break-word}
.prose blockquote{margin:0 0 18px;padding-left:18px;border-left:3px solid var(--border-strong);color:var(--ink-2)}
.prose kbd{font-family:var(--mono);font-size:.8em;background:var(--surface-3);border:1px solid var(--border-strong);
  border-bottom-width:2px;border-radius:4px;padding:.1em .4em}

.lede{font-size:var(--step-1)!important;line-height:1.6;color:var(--ink-2)}

/* ---------- page header (article) --------------------------------------- */

.page-head{padding:44px 0 8px}
.breadcrumb{display:flex;align-items:center;gap:7px;font-size:var(--step--1);color:var(--ink-3);margin-bottom:18px;flex-wrap:wrap}
.breadcrumb a{color:var(--ink-3);text-decoration:none}
.breadcrumb a:hover{color:var(--accent)}
.breadcrumb .sep{opacity:.5}

.eyebrow{display:inline-flex;align-items:center;gap:7px;font-size:11.5px;font-weight:700;
  text-transform:uppercase;letter-spacing:.085em;padding:4px 10px;border-radius:99px;margin-bottom:14px}
.eyebrow.hard{background:color-mix(in srgb,var(--bad) 11%,transparent);color:var(--bad)}
.eyebrow.essential{background:color-mix(in srgb,var(--info) 12%,transparent);color:var(--info)}

.meta-row{display:flex;flex-wrap:wrap;gap:8px;margin:18px 0 0}
.pill{display:inline-flex;align-items:center;gap:6px;font-size:var(--step--1);
  padding:4px 11px;border-radius:99px;border:1px solid var(--border);
  background:var(--surface);color:var(--ink-2)}
.pill b{font-weight:650;color:var(--ink)}

/* ---------- callouts ----------------------------------------------------- */

.callout{
  --c:var(--info);
  position:relative;margin:26px 0;padding:16px 18px 16px 20px;
  border:1px solid var(--border);border-left:3px solid var(--c);
  border-radius:0 var(--radius) var(--radius) 0;background:var(--surface);
  box-shadow:var(--shadow-1)}
/* Block, not flex: as a flex container each run of text and every inline
   <code> became its own flex item, so a title like "A missing <code>implements</code>
   clause ..." broke into three independently-wrapping boxes. Inline layout lets
   the whole title wrap as one sentence. */
.callout>.callout-title{
  display:block;font-weight:670;color:var(--c);
  font-size:var(--step--1);text-transform:uppercase;letter-spacing:.05em;margin-bottom:8px}
.callout>.callout-title svg{width:15px;height:15px;flex:none;
  display:inline-block;vertical-align:-2px;margin-right:8px}
/* A code literal inside an uppercased title must keep its own casing: the
   keyword is "implements", not "IMPLEMENTS". */
.callout>.callout-title code{text-transform:none;letter-spacing:normal;
  white-space:nowrap;font-size:.92em}
.callout>:last-child{margin-bottom:0}
.callout p{margin-bottom:10px}
.callout.insight{--c:var(--brand)}
.callout.warn{--c:var(--warn)}
.callout.danger{--c:var(--bad)}
.callout.ok{--c:var(--ok)}
.callout.canon{--c:var(--canon);background:color-mix(in srgb,var(--canon) 4%,var(--surface))}

/* Canonical-source quote: the authority block. */
.canon-quote{margin:26px 0;padding:20px 22px;border-radius:var(--radius);
  background:color-mix(in srgb,var(--canon) 5%,var(--surface));
  border:1px solid color-mix(in srgb,var(--canon) 22%,var(--border))}
.canon-quote blockquote{margin:0 0 12px;padding:0;border:0;font-family:var(--serif);
  font-size:var(--step-1);line-height:1.55;color:var(--ink)}
.canon-quote blockquote p{margin:0 0 10px}
.canon-quote blockquote :last-child{margin-bottom:0}
.canon-quote .attrib{display:flex;flex-wrap:wrap;align-items:center;gap:8px;font-size:var(--step--1);color:var(--ink-3)}
.canon-quote .attrib .who{font-weight:650;color:var(--ink-2)}
.canon-quote .attrib a{color:var(--canon);font-family:var(--mono);font-size:.92em;text-decoration:none;
  border-bottom:1px solid color-mix(in srgb,var(--canon) 35%,transparent)}
.canon-quote .attrib a:hover{border-bottom-color:var(--canon)}

/* ---------- theory vs practice comparison -------------------------------- */

.cmp{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin:26px 0}
@media (max-width:720px){.cmp{grid-template-columns:1fr}}
.cmp>div{border:1px solid var(--border);border-radius:var(--radius);padding:16px 18px;background:var(--surface)}
.cmp .cmp-head{display:flex;align-items:center;gap:8px;font-weight:670;font-size:var(--step--1);
  text-transform:uppercase;letter-spacing:.05em;margin-bottom:10px}
.cmp .cmp-head svg{width:15px;height:15px;flex:none}
.cmp .bad-side{border-color:color-mix(in srgb,var(--bad) 30%,var(--border))}
.cmp .bad-side .cmp-head{color:var(--bad)}
.cmp .good-side{border-color:color-mix(in srgb,var(--ok) 30%,var(--border))}
.cmp .good-side .cmp-head{color:var(--ok)}
.cmp p{margin-bottom:10px;font-size:.96em}
.cmp>div>:last-child{margin-bottom:0}
.cmp ul{padding-left:20px;margin-bottom:0}
.cmp li{font-size:.96em}

/* ---------- code --------------------------------------------------------- */

.code{margin:24px 0;border:1px solid var(--border);border-radius:var(--radius);
  background:var(--n-950);overflow:hidden;box-shadow:var(--shadow-2)}
.code-bar{display:flex;align-items:center;gap:10px;padding:0 10px 0 14px;height:38px;
  background:#0b1016;border-bottom:1px solid rgba(255,255,255,.07)}
.code-lang{font-family:var(--mono);font-size:11px;font-weight:600;letter-spacing:.06em;
  text-transform:uppercase;color:#7d8da3}
.code-file{font-family:var(--mono);font-size:11.5px;color:#9fb0c5;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.code-bar .spacer{margin-left:auto}
.code-copy{display:inline-flex;align-items:center;gap:5px;background:transparent;border:1px solid rgba(255,255,255,.12);
  color:#9fb0c5;font-size:11.5px;font-family:var(--sans);padding:4px 9px;border-radius:5px;cursor:pointer}
.code-copy:hover{background:rgba(255,255,255,.07);color:#e6edf3}
.code-copy svg{width:12px;height:12px}
.code-copy.done{color:#4ade80;border-color:rgba(74,222,128,.4)}
.code pre{margin:0;padding:15px 16px;overflow-x:auto;font-family:var(--mono);
  font-size:13.2px;line-height:1.62;color:#dbe4ee;tab-size:2}
.code pre code{font-family:inherit;background:none;border:0;padding:0}

/* Annotated-line highlighting: .code pre .hl marks a line of interest. */
.code .hl{display:block;margin:0 -16px;padding:0 16px;
  background:rgba(99,102,241,.15);border-left:2px solid var(--brand-l)}
.code .hl-bad{display:block;margin:0 -16px;padding:0 16px;
  background:rgba(220,38,38,.14);border-left:2px solid var(--bad-l)}
.code .hl-ok{display:block;margin:0 -16px;padding:0 16px;
  background:rgba(22,163,74,.14);border-left:2px solid var(--ok-l)}

/* Token colours — one palette, dark background in both themes so code
   always reads as code and never restyles under the theme toggle. */
.tok-key{color:#c792ea}
.tok-str{color:#c3e88d}
.tok-num{color:#f78c6c}
/* Lifted from #63768a, which measured 3.4–3.95:1 on the code ground and
   failed on every commented line — worst inside .hl blocks, where the tint
   raises the background. Comments carry the explanation a reader most needs.
   Now matches .code-lang's value, so the chrome and the comments agree. */
.tok-com{color:#7d8ea3;font-style:italic}
.tok-fn{color:#82aaff}
.tok-typ{color:#ffcb6b}
.tok-ann{color:#f07178}
.tok-op{color:#89ddff}
.tok-tag{color:#f07178}
.tok-attr{color:#ffcb6b}
.tok-punc{color:#89ddff}

/* code tabs (multi-language examples) */
.code-tabs{margin:24px 0}
.code-tabs .tabs{display:flex;gap:3px;border-bottom:1px solid var(--border);margin-bottom:-1px;flex-wrap:wrap}
.code-tabs .tab{background:transparent;border:1px solid transparent;border-bottom:0;
  padding:7px 14px;font-size:var(--step--1);font-weight:550;color:var(--ink-3);
  cursor:pointer;border-radius:var(--radius-sm) var(--radius-sm) 0 0;font-family:var(--sans)}
.code-tabs .tab:hover{color:var(--ink)}
.code-tabs .tab[aria-selected="true"]{color:var(--accent);background:var(--surface);
  border-color:var(--border);border-bottom-color:var(--surface)}
.code-tabs .panel[hidden]{display:none}
.code-tabs .code{margin-top:0;border-top-left-radius:0}

/* ---------- figures / diagrams -------------------------------------------- */

.fig{margin:30px 0;border:1px solid var(--border);border-radius:var(--radius);
  background:var(--surface);overflow:hidden;box-shadow:var(--shadow-1)}
.fig .fig-body{padding:22px 18px;overflow-x:auto;display:flex;justify-content:center}
.fig svg{max-width:100%;height:auto;display:block}
.fig figcaption{padding:11px 18px;border-top:1px solid var(--border);background:var(--surface-2);
  font-size:var(--step--1);color:var(--ink-3);line-height:1.5}
.fig figcaption b{color:var(--ink-2);font-weight:650}

/* SVG diagram primitives — diagrams use these classes so every diagram in the
   hub is visually consistent and theme-aware without per-page CSS. */
.d-node{fill:var(--surface-2);stroke:var(--border-strong);stroke-width:1.4}
.d-node-accent{fill:color-mix(in srgb,var(--brand) 10%,var(--surface));stroke:var(--brand);stroke-width:1.6}
.d-node-bad{fill:color-mix(in srgb,var(--bad) 9%,var(--surface));stroke:var(--bad);stroke-width:1.5}
.d-node-ok{fill:color-mix(in srgb,var(--ok) 9%,var(--surface));stroke:var(--ok);stroke-width:1.5}
.d-node-store{fill:color-mix(in srgb,var(--warn) 9%,var(--surface));stroke:var(--warn);stroke-width:1.5}
.d-label{fill:var(--ink);font-family:var(--sans);font-size:12.5px;font-weight:600;text-anchor:middle}
.d-sub{fill:var(--ink-3);font-family:var(--sans);font-size:10.5px;text-anchor:middle}
.d-mono{fill:var(--ink-2);font-family:var(--mono);font-size:10.5px;text-anchor:middle}
.d-edge{fill:none;stroke:var(--border-strong);stroke-width:1.6}
.d-edge-accent{fill:none;stroke:var(--brand);stroke-width:1.8}
.d-edge-bad{fill:none;stroke:var(--bad);stroke-width:1.8}
.d-edge-ok{fill:none;stroke:var(--ok);stroke-width:1.8}
.d-edge-dash{stroke-dasharray:5 4}
.d-edge-label{fill:var(--ink-3);font-family:var(--mono);font-size:10px;text-anchor:middle}
.d-zone{fill:color-mix(in srgb,var(--ink-3) 6%,transparent);stroke:var(--border);
  stroke-width:1.2;stroke-dasharray:4 4}
.d-zone-label{fill:var(--ink-3);font-family:var(--sans);font-size:10.5px;font-weight:650;
  text-transform:uppercase;letter-spacing:.06em}
.d-arrow{fill:var(--border-strong)}
.d-arrow-accent{fill:var(--brand)}
.d-arrow-bad{fill:var(--bad)}
.d-arrow-ok{fill:var(--ok)}

/* ---------- tables --------------------------------------------------------- */

.table-wrap{margin:26px 0;overflow-x:auto;border:1px solid var(--border);border-radius:var(--radius);background:var(--surface)}
table{border-collapse:collapse;width:100%;font-size:var(--step--1)}
thead th{text-align:left;padding:11px 14px;background:var(--surface-2);
  border-bottom:1px solid var(--border);font-weight:670;color:var(--ink-2);
  white-space:nowrap;font-size:11.5px;text-transform:uppercase;letter-spacing:.05em}
tbody td{padding:11px 14px;border-bottom:1px solid var(--border);vertical-align:top;line-height:1.55}
tbody tr:last-child td{border-bottom:0}
tbody tr:hover{background:var(--surface-2)}
td code,th code{font-family:var(--mono);font-size:.9em;background:var(--surface-3);
  padding:.1em .34em;border-radius:4px}
.t-yes{color:var(--ok);font-weight:650}
.t-no{color:var(--bad);font-weight:650}
.t-part{color:var(--warn);font-weight:650}

/* ---------- steps ---------------------------------------------------------- */

.steps{counter-reset:s;margin:26px 0;padding:0;list-style:none}
.steps>li{counter-increment:s;position:relative;padding:0 0 22px 44px;border-left:1.5px solid var(--border);margin-left:13px}
.steps>li:last-child{border-left-color:transparent;padding-bottom:0}
.steps>li::before{content:counter(s);position:absolute;left:-14px;top:-2px;
  width:27px;height:27px;border-radius:50%;background:var(--surface);
  border:1.5px solid var(--border-strong);color:var(--ink-2);
  display:grid;place-items:center;font-size:12.5px;font-weight:700;font-variant-numeric:tabular-nums}
.steps>li.is-bad::before{border-color:var(--bad);color:var(--bad)}
.steps>li.is-ok::before{border-color:var(--ok);color:var(--ok)}
/* h3, not h4: these sit under a section h2, and jumping a level broke the
   document outline for anyone navigating by heading. Values unchanged. */
.steps h3{margin:0 0 6px;font-size:var(--step-0);font-weight:660}
.steps p{margin:0 0 8px;font-size:.97em;color:var(--ink-2)}
.steps>li>:last-child{margin-bottom:0}

/* ---------- checklist ------------------------------------------------------ */

.checklist{list-style:none;padding:0;margin:24px 0}
.checklist li{position:relative;padding:11px 14px 11px 42px;border:1px solid var(--border);
  border-radius:var(--radius-sm);margin-bottom:8px;background:var(--surface);font-size:.97em}
.checklist li::before{content:"";position:absolute;left:14px;top:14px;width:16px;height:16px;
  border-radius:4px;border:1.5px solid var(--border-strong)}
.checklist li.done::before{background:var(--ok);border-color:var(--ok)}
.checklist li.done::after{content:"";position:absolute;left:19.5px;top:17.5px;width:4px;height:8px;
  border:solid #fff;border-width:0 2px 2px 0;transform:rotate(45deg)}

/* ---------- evidence block (verified-in-production) ------------------------ */

.evidence{margin:28px 0;border:1px solid color-mix(in srgb,var(--ok) 26%,var(--border));
  border-radius:var(--radius);overflow:hidden;background:var(--surface)}
.evidence-head{display:flex;align-items:center;gap:9px;padding:11px 16px;
  background:color-mix(in srgb,var(--ok) 8%,var(--surface));
  border-bottom:1px solid color-mix(in srgb,var(--ok) 20%,var(--border));
  font-weight:670;font-size:var(--step--1);color:var(--ok)}
.evidence-head svg{width:16px;height:16px;flex:none}
.evidence-body{padding:16px}
.evidence-body>:last-child{margin-bottom:0}
.evidence-body p{margin-bottom:12px;font-size:.97em}
.ev-cite{display:inline-block;font-family:var(--mono);font-size:11.5px;color:var(--ink-3);
  background:var(--surface-3);border:1px solid var(--border);padding:2px 7px;border-radius:4px;margin:2px 4px 2px 0}

/* ---------- prev/next ------------------------------------------------------ */

.pager{display:grid;grid-template-columns:1fr 1fr;gap:14px;margin:56px 0 0;padding-top:28px;border-top:1px solid var(--border)}
@media (max-width:640px){.pager{grid-template-columns:1fr}}
.pager a{display:block;padding:14px 16px;border:1px solid var(--border);border-radius:var(--radius);
  text-decoration:none;background:var(--surface);transition:border-color .15s,box-shadow .15s}
.pager a:hover{border-color:var(--accent);box-shadow:var(--shadow-2)}
.pager .dir{font-size:11px;text-transform:uppercase;letter-spacing:.08em;color:var(--ink-3);font-weight:650}
.pager .ttl{display:block;margin-top:3px;font-weight:650;color:var(--ink);font-size:var(--step-0);line-height:1.35}
.pager .next{text-align:right}

/* ---------- footer --------------------------------------------------------- */

.site-footer{border-top:1px solid var(--border);background:var(--surface-2);margin-top:64px}
.site-footer .inner{max-width:1180px;margin:0 auto;padding:32px clamp(16px,3vw,32px);
  color:var(--ink-3);font-size:var(--step--1);display:grid;gap:12px}
.site-footer a{color:var(--ink-2)}
.site-footer p{margin:0;max-width:80ch}

/* Contact row. Sits under the per-page method note, separated by a rule so the
   editorial content and the personal details stay visually distinct. Middots
   come from CSS rather than markup, so the dots are never read aloud and never
   copied when someone selects the address. */
.site-footer .foot-me{
  display:flex;flex-wrap:wrap;align-items:baseline;gap:4px 0;max-width:none;
  padding-top:14px;border-top:1px solid var(--border)}
.site-footer .foot-me b{color:var(--ink-2);font-weight:650}
.site-footer .foot-me > * + *::before{
  content:"\00B7";margin:0 10px;color:var(--ink-3)}
.site-footer .foot-me a{text-decoration:none;border-bottom:1px solid transparent}
.site-footer .foot-me a:hover{color:var(--accent);border-bottom-color:var(--accent)}

/* ---------- dark theme ------------------------------------------------------ */

@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]){
    --bg:var(--n-950); --bg-sunken:#0a0e13;
    --surface:var(--n-900); --surface-2:var(--n-850); --surface-3:var(--n-800);
    --border:#25303c; --border-strong:#36434f;
    --ink:#e8eef5; --ink-2:#b3c1d1; --ink-3:#8fa2b6;
    --accent:#818cf8; --accent-soft:color-mix(in srgb,#818cf8 13%,transparent);
    --on-accent:var(--n-950);
    --brand:#818cf8; --canon:#a78bfa;
    --ok:#34d399; --warn:#fbbf24; --bad:#f87171; --info:#38bdf8;
    --shadow-1:0 1px 2px rgba(0,0,0,.4);
    --shadow-2:0 4px 10px -2px rgba(0,0,0,.5);
    --shadow-3:0 12px 24px -6px rgba(0,0,0,.55);
  }
}
:root[data-theme="dark"]{
  --bg:var(--n-950); --bg-sunken:#0a0e13;
  --surface:var(--n-900); --surface-2:var(--n-850); --surface-3:var(--n-800);
  --border:#25303c; --border-strong:#36434f;
  --ink:#e8eef5; --ink-2:#b3c1d1; --ink-3:#8fa2b6;
  --accent:#818cf8; --accent-soft:color-mix(in srgb,#818cf8 13%,transparent);
  --on-accent:var(--n-950);
  --brand:#818cf8; --canon:#a78bfa;
  --ok:#34d399; --warn:#fbbf24; --bad:#f87171; --info:#38bdf8;
  --shadow-1:0 1px 2px rgba(0,0,0,.4);
  --shadow-2:0 4px 10px -2px rgba(0,0,0,.5);
  --shadow-3:0 12px 24px -6px rgba(0,0,0,.55);
}

/* ---------- print ------------------------------------------------------------ */

@media print{
  .site-header,.toc,.pager,.theme-toggle,.code-copy{display:none!important}
  .doc{grid-template-columns:1fr}
  body{background:#fff;color:#000}
  .code{break-inside:avoid}
  .fig{break-inside:avoid}
}

/* ---- Property definitions in comparison tables -------------------------
   .table-wrap sets overflow-x, which clips any absolutely positioned
   tooltip, so the definition is a popover: it renders in the top layer and
   cannot be cut off. One interaction on every device — click, tap or Enter —
   because hover does not exist on touch. Esc and outside-click dismiss come
   free with the popover attribute. */
.prop{display:inline-flex;align-items:center;gap:7px}
.prop-btn{
  position:relative;flex:0 0 auto;width:16px;height:16px;border-radius:50%;
  border:1px solid var(--border);background:var(--surface-2);
  color:var(--ink-3);font:600 10.5px/1 ui-sans-serif,system-ui,sans-serif;
  display:inline-flex;align-items:center;justify-content:center;
  cursor:pointer;padding:0;transition:color .12s,border-color .12s,background .12s}
.prop-btn:hover{color:var(--brand);border-color:var(--brand);background:var(--surface)}
.prop-btn::after{content:"i";font-style:italic}
/* The dot stays 16px for the table, but the touch target is 44px so it meets
   the same hit-area rule as the theme toggle. */
.prop-btn::before{content:"";position:absolute;inset:-14px}

.def-pop{
  margin:auto;max-width:34ch;padding:16px 18px;
  border:1px solid var(--border);border-radius:var(--radius);
  background:var(--surface);color:var(--ink-2);
  font-size:var(--step--1);line-height:1.6;
  box-shadow:0 18px 44px rgba(0,0,0,.30)}
.def-pop h4{margin:0 0 6px;font-size:11.5px;letter-spacing:.05em;
  text-transform:uppercase;color:var(--ink-3);font-weight:670}
.def-pop p{margin:0}
.def-pop::backdrop{background:rgba(0,0,0,.42)}

/* A browser without popover support would otherwise render every definition
   inline inside the table. Hide them and let the button's title carry it. */
@supports not selector(:popover-open){
  .def-pop{display:none}
}

/* A table whose columns are set by <colgroup>. The header must be allowed to
   wrap, otherwise a long heading like "Can be present without the others?"
   holds its column open and forces the wrapper to scroll sideways.
   The fixed layout only applies once there is room for it: below that the
   percentages squeeze "Term" until it breaks one letter per line, so the
   table falls back to sizing by content and the wrapper scrolls as usual. */
table.cols thead th{white-space:normal}
table.cols td,table.cols th{overflow-wrap:break-word}
@media (min-width:721px){
  table.cols{table-layout:fixed}
}

/* A citation URL is a single unbreakable word. As a flex item it will not
   shrink below its own content width, so a long one pushes out of the quote
   card. min-width:0 lets it shrink; overflow-wrap lets it break. */
.canon-quote .attrib a{min-width:0;overflow-wrap:anywhere}
