/* ── 00-layers.css ───────────────────────────────────────── */
/* RelevantSec design system — see DESIGN.md at the repo root.
 *
 * Hardware research studio: black canvas, a circuit-board hero, and a
 * searchable publication dashboard. Shared tokens and a stable compact nav.
 *
 * Authored as styles/src/*.css and served as one hashed bundle (lib/assets.js).
 * Filename order is the concatenation order.
 *
 * Layer order is declared once, here, and is the whole cascade contract:
 * anything unlayered beats everything below, so `overrides` stays empty in
 * steady state and is only a break-glass escape hatch.
 */
@layer tokens, reset, base, layout, register, chrome, controls, components, prose, code, utilities, overrides;


/* ── 01-fonts.css ───────────────────────────────────────── */
/* Self-hosted, same-origin. The CSP is `font-src 'self'` — there is no
 * third-party font request on any page, which is also why style-src can stay
 * clean of fonts.googleapis.com.
 *
 * Only the faces a page actually paints get downloaded, so broadcast surfaces
 * never fetch the serif.
 */

/* ── Cabinet Grotesk · UI, chrome, broadcast headings ─────────────────── */
@font-face {
  font-family: "Cabinet Grotesk";
  src: url("/fonts/cabinet-grotesk-400-normal.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Cabinet Grotesk";
  src: url("/fonts/cabinet-grotesk-500-normal.woff2") format("woff2");
  font-weight: 500; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Cabinet Grotesk";
  src: url("/fonts/cabinet-grotesk-800-normal.woff2") format("woff2");
  font-weight: 800; font-style: normal; font-display: swap;
}

/* ── Newsreader · document register reading face ──────────────────────── */
@font-face {
  font-family: "Newsreader";
  src: url("/fonts/newsreader-400-normal-latin.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Newsreader";
  src: url("/fonts/newsreader-400-normal-latin-ext.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Newsreader";
  src: url("/fonts/newsreader-600-normal-latin.woff2") format("woff2");
  font-weight: 600; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Newsreader";
  src: url("/fonts/newsreader-600-normal-latin-ext.woff2") format("woff2");
  font-weight: 600; font-style: normal; font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Newsreader";
  src: url("/fonts/newsreader-400-italic-latin.woff2") format("woff2");
  font-weight: 400; font-style: italic; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Newsreader";
  src: url("/fonts/newsreader-400-italic-latin-ext.woff2") format("woff2");
  font-weight: 400; font-style: italic; font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ── JetBrains Mono · the outlier register: code, metadata, labels ────── */
@font-face {
  font-family: "JetBrains Mono";
  src: url("/fonts/jetbrains-mono-400-normal-latin.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "JetBrains Mono";
  src: url("/fonts/jetbrains-mono-400-normal-latin-ext.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "JetBrains Mono";
  src: url("/fonts/jetbrains-mono-500-normal-latin.woff2") format("woff2");
  font-weight: 500; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "JetBrains Mono";
  src: url("/fonts/jetbrains-mono-700-normal-latin.woff2") format("woff2");
  font-weight: 700; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "JetBrains Mono";
  src: url("/fonts/jetbrains-mono-400-italic-latin.woff2") format("woff2");
  font-weight: 400; font-style: italic; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ── metric-matched fallbacks ─────────────────────────────────────────
 * Derived by measuring each webfont against its fallback in-browser
 * (advance width of a fixed string, plus fontBoundingBox ascent/descent):
 *
 *   size-adjust   = webfont advance / fallback advance
 *   ascent/descent-override = webfont metric / size-adjust
 *
 * Numbers come from the Arial / Liberation metric family, which covers the
 * common Linux and Windows stacks. Re-derive with scripts/verify-visual.mjs's
 * probe if a face is ever swapped — wrong overrides are worse than none.
 *
 * With these in place `font-display: swap` costs almost no visible reflow,
 * which is why it is used everywhere including the hero.
 */
@font-face {
  font-family: "Cabinet Grotesk Fallback";
  src: local("Arial"), local("Liberation Sans"), local("Helvetica Neue"), local("Helvetica");
  size-adjust: 95.11%;
  ascent-override: 91.48%;
  descent-override: 29.44%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Newsreader Fallback";
  src: local("Times New Roman"), local("Liberation Serif"), local("Times");
  size-adjust: 106.71%;
  ascent-override: 69.34%;
  descent-override: 25.30%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "JetBrains Mono Fallback";
  src: local("Liberation Mono"), local("DejaVu Sans Mono"), local("Menlo"), local("Consolas");
  size-adjust: 99.98%;
  ascent-override: 102.02%;
  descent-override: 30.00%;
  line-gap-override: 0%;
}


/* ── 10-tokens.css ───────────────────────────────────────── */
@layer tokens {
  :root {
    --font-ui: "Cabinet Grotesk", "Cabinet Grotesk Fallback", ui-sans-serif, system-ui, sans-serif;
    --font-serif: "Newsreader", "Newsreader Fallback", ui-serif, Georgia, serif;
    --font-mono: "JetBrains Mono", "JetBrains Mono Fallback", ui-monospace, monospace;
    --text-2xs: .6875rem;
    --text-xs: .8125rem;
    --text-sm: .875rem;
    --text-base: 1rem;
    --text-md: 1.125rem;
    --text-lg: 1.25rem;
    --text-xl: 1.5625rem;
    --text-2xl: 1.953rem;
    --text-3xl: clamp(1.953rem, 1.4rem + 1.8vw, 2.75rem);
    --text-4xl: clamp(2.2rem, 1.5rem + 2.6vw, 3.6rem);
    --text-display: clamp(3.2rem, 1.6rem + 4.4vw, 5.5rem);
    --lh-display: 1.06;
    --lh-tight: 1.18;
    --lh-snug: 1.35;
    --lh-normal: 1.6;
    --lh-prose: 1.72;
    --track-display: -.045em;
    --track-tight: -.025em;
    --track-label: .08em;
    --space-3xs: 2px;
    --space-2xs: 4px;
    --space-xs: 8px;
    --space-sm: 12px;
    --space-md: 16px;
    --space-lg: 24px;
    --space-xl: 40px;
    --space-2xl: 64px;
    --space-3xl: 96px;
    --space-4xl: 144px;
    --wrap: 1280px;
    --gutter: clamp(20px, 4vw, 48px);
    --radius-0: 0;
    --radius-1: 4px;
    --radius-2: 6px;
    --radius-3: 12px;
    --radius-pill: 999px;
    --dur-micro: 120ms;
    --dur-short: 220ms;
    --dur-long: 420ms;
    --ease-out: cubic-bezier(.16, 1, .3, 1);
    --ease-in: cubic-bezier(.7, 0, .84, 0);
    --ease-inout: cubic-bezier(.65, 0, .35, 1);
    --z-base: 1;
    --z-raised: 10;
    --z-dropdown: 100;
    --z-sticky: 200;
    --z-modal: 400;
    --z-toast: 500;
    color-scheme: light dark;
    /* The light baseline also serves an explicit system/auto preference. */
    --color-paper: oklch(97% .003 250);
    --color-paper-2: oklch(94% .004 250);
    --color-paper-3: oklch(90% .005 250);
    --color-ink: oklch(18% .008 250);
    --color-ink-2: oklch(34% .012 250);
    --color-muted: oklch(44% .014 250);
    --color-rule: oklch(85% .006 250);
    --color-rule-strong: oklch(77% .009 250);
    --color-edge: oklch(55% .012 250);
    --color-accent: oklch(42% .065 240);
    --color-accent-ink: oklch(98% .003 250);
    --color-focus: oklch(42% .09 240);
    --thumb-filter: grayscale(1) contrast(1.03);
    --grain-opacity: 0;
    --shadow-whisper: 0 1px 2px color-mix(in oklab, var(--color-ink) 8%, transparent);
    --shadow-hairline: 0 0 0 1px var(--color-rule);
    --wash: color-mix(in oklab, var(--color-accent) 3%, var(--color-paper));
  }
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
      color-scheme: dark;
      --color-paper: oklch(0% 0 0);
      --color-paper-2: oklch(17% .005 250);
      --color-paper-3: oklch(22% .007 250);
      --color-ink: oklch(96% .003 250);
      --color-ink-2: oklch(80% .008 250);
      --color-muted: oklch(68% .012 250);
      --color-rule: oklch(28% .008 250);
      --color-rule-strong: oklch(37% .009 250);
      --color-edge: oklch(56% .014 250);
      --color-accent: oklch(85% .045 240);
      --color-accent-ink: oklch(16% .012 250);
      --color-focus: oklch(85% .06 240);
      --thumb-filter: grayscale(1) brightness(.8) contrast(1.05);
    }
  }
  :root[data-theme="dark"] {
    color-scheme: dark;
    --color-paper: oklch(0% 0 0);
    --color-paper-2: oklch(17% .005 250);
    --color-paper-3: oklch(22% .007 250);
    --color-ink: oklch(96% .003 250);
    --color-ink-2: oklch(80% .008 250);
    --color-muted: oklch(68% .012 250);
    --color-rule: oklch(28% .008 250);
    --color-rule-strong: oklch(37% .009 250);
    --color-edge: oklch(56% .014 250);
    --color-accent: oklch(85% .045 240);
    --color-accent-ink: oklch(16% .012 250);
    --color-focus: oklch(85% .06 240);
    --thumb-filter: grayscale(1) brightness(.8) contrast(1.05);
  }
  :root[data-theme="light"] { color-scheme: light; }
}


/* ── 20-reset.css ───────────────────────────────────────── */
@layer reset {
  *, *::before, *::after { box-sizing: border-box; }

  /* clip, not hidden: clip keeps position:sticky and position:fixed working on
   * descendants, where hidden silently creates a scroll container and breaks
   * the sticky masthead and the sticky table of contents. */
  html, body { overflow-x: clip; }

  html {
    -webkit-text-size-adjust: 100%;
    scroll-behavior: smooth;
    scroll-padding-top: calc(var(--masthead-h, 76px) + var(--space-lg));
  }

  body, h1, h2, h3, h4, p, figure, blockquote, dl, dd, ol, ul {
    margin: 0;
  }
  ol[class], ul[class] { list-style: none; padding: 0; }

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

  input, button, textarea, select { font: inherit; color: inherit; }
  button { background: none; border: 0; padding: 0; cursor: pointer; }

  a { color: inherit; }

  /* ── focus ──────────────────────────────────────────────────────────
   * There was not one focus rule in the previous stylesheet. This is the
   * single largest accessibility fix in the redesign.
   *
   * :focus-visible, so it is keyboard-only; instant, never transitioned —
   * a ring that fades in is useless to the person who needs it; and paired
   * with a soft halo so 2px survives on both the near-black and the paper
   * surface, and on top of a hovered row.
   */
  :where(a, button, summary, input, select, textarea, [tabindex]):focus-visible {
    outline: 2px solid var(--color-focus);
    outline-offset: 2px;
    box-shadow: 0 0 0 5px color-mix(in oklab, var(--color-focus) 24%, transparent);
    border-radius: var(--radius-2);
    transition: none;
  }
  :where(a, button):focus:not(:focus-visible) { outline: none; }

  ::selection {
    background: var(--color-accent);
    color: var(--color-accent-ink);
  }

  :target { scroll-margin-top: calc(var(--masthead-h, 76px) + var(--space-lg)); }

  [hidden] { display: none !important; }
  [inert] { pointer-events: none; }
}


/* ── 30-base.css ───────────────────────────────────────── */
@layer base {
  body {
    background: var(--color-paper);
    color: var(--color-ink);
    font-family: var(--font-ui);
    font-size: var(--text-base);
    font-weight: 400;
    line-height: var(--lh-normal);
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
    font-synthesis-weight: none;   /* never fake a weight we did not load */
    min-height: 100vh;
  }

  h1, h2, h3, h4 {
    font-family: var(--font-heading);
    font-weight: var(--heading-weight);
    line-height: var(--lh-tight);
    letter-spacing: var(--track-tight);
    text-wrap: balance;
    overflow-wrap: anywhere;
  }

  p { text-wrap: pretty; }

  /* Machine-adjacent content — dates, counts, tags, code, captions, labels.
   * Once the outlier tags a role it tags every instance of that role. */
  .mono {
    font-family: var(--font-mono);
    font-variant-ligatures: none;
    font-variant-numeric: tabular-nums;
    letter-spacing: 0;
  }

  /* Film grain. Sits at the base level BEHIND content — the old one was at
   * z-index 2000, on top of literally everything including focus rings. It
   * also blends differently per scheme, because a light-on-dark speckle reads
   * as dirt on paper. */
  .grain {
    position: fixed;
    inset: 0;
    z-index: var(--z-base);
    pointer-events: none;
    opacity: var(--grain-opacity);
    mix-blend-mode: var(--grain-blend);
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
  }

  /* The sprite carrying the ribbon mark; present in the DOM, never painted. */
  .sprite { position: absolute; width: 0; height: 0; overflow: hidden; }

  .mark { fill: currentColor; }

  .skip-link {
    position: absolute;
    left: var(--space-md);
    top: var(--space-md);
    z-index: var(--z-toast);
    transform: translateY(-200%);
    background: var(--color-accent);
    color: var(--color-accent-ink);
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    letter-spacing: var(--track-label);
    text-transform: uppercase;
    text-decoration: none;
    padding: var(--space-sm) var(--space-md);
    border-radius: var(--radius-2);
  }
  .skip-link:focus-visible { transform: translateY(0); }

  main:focus { outline: none; }
}


/* ── 35-scrollbars.css ───────────────────────────────────────── */
@layer base {
  /* One native scrollbar treatment for the page and every nested scroller.
   * Firefox uses the standard properties; WebKit/Blink get rounded rails. */
  * {
    --scroll-thumb: var(--color-edge);
    --scroll-thumb-active: var(--color-accent);
    --scroll-track: var(--color-paper-2);
    scrollbar-width: thin;
    scrollbar-color: var(--scroll-thumb) var(--scroll-track);
  }

  html { scrollbar-gutter: stable; }

  @supports selector(::-webkit-scrollbar) {
    * { scrollbar-width: auto; scrollbar-color: auto; }
    *::-webkit-scrollbar { width: 6px; height: 6px; }
    *::-webkit-scrollbar-track { background: var(--scroll-track); border-radius: var(--radius-pill); }
    *::-webkit-scrollbar-thumb { background: var(--scroll-thumb); border-radius: var(--radius-pill); min-width: 32px; min-height: 32px; }
    *::-webkit-scrollbar-thumb:hover,
    *::-webkit-scrollbar-thumb:active { background: var(--scroll-thumb-active); }
    *::-webkit-scrollbar-button { display: none; }
    *::-webkit-scrollbar-corner { background: var(--scroll-track); }
  }

  @media (forced-colors: active) {
    * {
      --scroll-thumb: ButtonText;
      --scroll-thumb-active: Highlight;
      --scroll-track: Canvas;
      scrollbar-color: auto;
    }
  }
}


/* ── 40-layout.css ───────────────────────────────────────── */
@layer layout {
  .wrap {
    width: 100%;
    max-width: var(--wrap);
    margin-inline: auto;
    padding-inline: var(--gutter);
  }

  .section { padding-block: var(--section-gap); }

  /* Rhythm is deliberately uneven — equal padding on every section is the
   * flattest, most templated thing a page can do. */
  .section--alt {
    background: var(--color-paper-2);
    border-block: 1px solid var(--color-rule);
    padding-block: calc(var(--section-gap) * 1.15) var(--section-gap);
  }
  .section--contact {
    padding-block: calc(var(--section-gap) * 0.85) calc(var(--section-gap) * 1.2);
    border-top: 1px solid var(--color-rule);
    background: var(--wash);
  }
  .section--index { padding-block: var(--space-xl) var(--section-gap); }

  .section-head {
    margin-bottom: var(--space-xl);
    padding-bottom: 0;
  }
  .section-head--split {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--space-lg);
    flex-wrap: wrap;
  }

  .kicker {
    font-family: var(--font-ui);
    font-size: var(--text-xs);
    letter-spacing: .01em;
    color: var(--color-muted);
    margin-bottom: var(--space-sm);
  }

  .section-title {
    font-size: var(--text-3xl);
    font-weight: 400;
    letter-spacing: var(--track-display);
  }

  .empty-note {
    color: var(--color-muted);
    font-size: var(--text-sm);
    padding-block: var(--space-xl);
  }
}


/* ── 45-register.css ───────────────────────────────────────── */
@layer register {
  /* The register axis rewrites shape, density, type and rhythm — never colour.
   * The scheme axis rewrites colour — never shape. Keeping them disjoint is
   * what stops a 2x2 combinatorial explosion in every component rule.
   *
   * `--font-reading` and `--font-heading` are the only type knobs a component
   * ever touches; the chrome always uses --font-ui explicitly. */

  :root[data-register="document"] {
    --font-reading: var(--font-serif);
    --font-heading: var(--font-ui);
    --heading-weight: 500;
    --measure: 68ch;
    --section-gap: clamp(3.5rem, 7vw, 5.5rem);
    --reading-size: var(--text-md);
    --reading-lh: var(--lh-prose);
    --card-radius: var(--radius-0);
  }

  :root[data-register="broadcast"] {
    --font-reading: var(--font-ui);
    --font-heading: var(--font-ui);
    --heading-weight: 500;
    --measure: 60ch;
    --section-gap: clamp(4.5rem, 9vw, 7.5rem);
    --reading-size: var(--text-base);
    --reading-lh: var(--lh-normal);
    --card-radius: var(--radius-3);
  }

  /* A section can opt into the other register locally — inheritance handles
   * it, no cascade gymnastics required. */
  [data-register] { }
}


/* ── 50-chrome.css ───────────────────────────────────────── */
@layer chrome {
  .masthead {
    position: sticky;
    top: 0;
    z-index: var(--z-sticky);
    background: color-mix(in oklab, var(--color-paper) 90%, transparent);
    backdrop-filter: blur(18px);
    border-bottom: 1px solid var(--color-rule);
  }
  .masthead-bar-inner {
    display: flex;
    align-items: center;
    gap: var(--space-xl);
    min-height: 88px;
  }
  .masthead-brand { display: inline-flex; align-items: center; gap: 11px; text-decoration: none; flex-shrink: 0; }
  .masthead-mark { width: 29px; height: 24px; }
  .masthead-word { font-family: var(--font-ui); font-size: 1.4rem; font-weight: 800; letter-spacing: -.045em; line-height: 1; }
  .masthead-word-thin { font-weight: 400; color: var(--color-ink-2); }
  .masthead-nav { display: flex; align-items: center; gap: 34px; margin-left: auto; }
  .masthead-link { display: inline-flex; align-items: center; min-height: 44px; color: var(--color-muted); font-size: var(--text-sm); text-decoration: none; position: relative; }
  .masthead-link.is-current { color: var(--color-ink); }
  .masthead-link.is-current::after { content: ""; position: absolute; bottom: 4px; inset-inline: 0; height: 1px; background: var(--color-ink); }
  .masthead-utils { display: flex; align-items: center; gap: var(--space-md); padding-left: var(--space-lg); border-left: 1px solid var(--color-rule); }
  .burger { display: none; position: relative; width: 44px; height: 44px; margin-left: auto; }
  .noscript-nav { display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-lg); padding-block: var(--space-md); }
  .noscript-nav > a { min-height: 44px; display: inline-flex; align-items: center; font-size: var(--text-sm); }
  .burger span { position: absolute; left: 11px; width: 22px; height: 1px; background: var(--color-ink); transition: transform var(--dur-short) var(--ease-out); }
  .burger span:nth-child(1) { top: 18px; }
  .burger span:nth-child(2) { top: 25px; }
  .burger[aria-expanded="true"] span:nth-child(1) { transform: translateY(3.5px) rotate(45deg); }
  .burger[aria-expanded="true"] span:nth-child(2) { transform: translateY(-3.5px) rotate(-45deg); }
  .mobile-menu {
    position: fixed; inset: var(--masthead-h, 72px) 0 0;
    z-index: var(--z-modal); background: var(--color-paper);
    display: flex; flex-direction: column; gap: var(--space-xl);
    padding: var(--space-xl) var(--gutter);
    overflow-y: auto; overscroll-behavior: contain;
    opacity: 0; visibility: hidden; transform: translateY(-8px);
    transition: opacity var(--dur-short) var(--ease-out), transform var(--dur-short) var(--ease-out);
  }
  .mobile-menu.is-open { opacity: 1; visibility: visible; transform: none; }
  .mobile-menu nav { display: grid; }
  .mobile-menu nav a { text-decoration: none; font-size: var(--text-2xl); padding-block: var(--space-md); border-bottom: 1px solid var(--color-rule); }
  .mobile-menu-utils { display: flex; align-items: center; gap: var(--space-lg); }
  .colophon { border-top: 1px solid var(--color-rule); padding-block: var(--space-xl) var(--space-lg); }
  .colophon-inner { display: flex; align-items: center; justify-content: space-between; gap: var(--space-lg); }
  .colophon-wordmark { display: flex; align-items: center; gap: 10px; font-size: 1.2rem; font-weight: 800; letter-spacing: -.035em; text-decoration: none; }
  .colophon-mark { width: 24px; }
  .colophon-tag { margin-top: var(--space-xs); font-size: var(--text-sm); color: var(--color-muted); }
  .colophon-nav { display: flex; flex-wrap: wrap; gap: var(--space-lg); }
  .colophon-nav a { display: inline-flex; align-items: center; min-height: 44px; color: var(--color-muted); font-size: var(--text-sm); text-decoration: none; }
  .cookie-settings { min-height: 44px; color: var(--color-muted); font-size: var(--text-sm); }
  .colophon-bottom { display: flex; justify-content: space-between; gap: var(--space-lg); padding-top: var(--space-xl); font-size: var(--text-xs); color: var(--color-muted); }
  .colophon-bottom > span { font-family: var(--font-mono); font-size: var(--text-2xs); }
  .cookie-banner {
    position: fixed; z-index: var(--z-toast); inset: auto var(--gutter) var(--space-lg);
    display: flex; align-items: end; justify-content: space-between; gap: var(--space-xl);
    max-width: 960px; max-height: calc(100dvh - 2 * var(--space-lg)); overflow-y: auto;
    margin-inline: auto; padding: var(--space-lg);
    border: 1px solid var(--color-rule-strong); border-radius: var(--radius-2);
    background: var(--color-paper-2); box-shadow: 0 16px 48px color-mix(in oklab, black 28%, transparent);
  }
  .cookie-copy { max-width: 580px; }
  .cookie-kicker { margin-bottom: var(--space-xs); font: 500 var(--text-2xs)/1.3 var(--font-mono); letter-spacing: var(--track-label); text-transform: uppercase; color: var(--color-muted); }
  .cookie-copy h2 { margin-bottom: var(--space-xs); font-size: var(--text-lg); letter-spacing: var(--track-tight); }
  .cookie-copy > p:last-child { color: var(--color-ink-2); font-size: var(--text-sm); line-height: var(--lh-normal); }
  .cookie-actions { display: flex; flex-shrink: 0; gap: var(--space-xs); }
  .cookie-choice { min-height: 44px; min-width: 96px; padding: var(--space-xs) var(--space-md); border: 1px solid var(--color-edge); border-radius: var(--radius-2); background: var(--color-paper); color: var(--color-ink); font-size: var(--text-sm); font-weight: 500; }
  @media (hover: hover) { .masthead-link:hover, .colophon-nav a:hover, .cookie-settings:hover { color: var(--color-ink); } .cookie-choice:hover { border-color: var(--color-ink); background: var(--color-paper-3); } }
  @media (max-width: 45rem) {
    .cookie-banner { flex-direction: column; align-items: stretch; gap: var(--space-md); inset-inline: var(--space-sm); bottom: var(--space-sm); padding: var(--space-md); }
    .cookie-actions { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
  }
  @media (max-width: 52rem) {
    .masthead-bar-inner { min-height: 72px; gap: var(--space-md); }
    .masthead-nav, .masthead-utils { display: none; }
    .burger { display: block; }
    .colophon-inner { align-items: flex-start; flex-direction: column; }
    .colophon-bottom { flex-wrap: wrap; gap: var(--space-xs); }
  }
}


/* ── 55-controls.css ───────────────────────────────────────── */
@layer controls {
  .btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 16px;
    min-height: 46px; padding: 12px 21px; font-family: var(--font-ui);
    font-size: var(--text-sm); font-weight: 500; text-decoration: none;
    line-height: 1.25; border: 1px solid transparent; border-radius: var(--radius-2);
    transition: background-color var(--dur-micro), border-color var(--dur-micro), color var(--dur-micro);
  }
  .btn svg { flex-shrink: 0; }
  .btn--solid { background: var(--color-ink); color: var(--color-paper); }
  .btn--ghost { background: transparent; border-color: var(--color-edge); color: var(--color-ink-2); }
  .btn--lg { min-height: 52px; padding-inline: var(--space-lg); font-size: var(--text-base); }
  .btn:active { transform: translateY(1px); }
  .btn[aria-disabled="true"], .btn:disabled { opacity: .55; cursor: not-allowed; }
  .cta-row { display: flex; flex-wrap: wrap; gap: var(--space-sm); align-items: center; }
  .cta-row--center { justify-content: center; }
  .link-more { display: inline-flex; align-items: center; gap: var(--space-sm); min-height: 44px; font-family: var(--font-ui); font-size: var(--text-sm); text-decoration: none; color: var(--color-ink-2); }
  .tags { display: flex; flex-wrap: wrap; gap: var(--space-xs); }
  /* Topic chips: a pad-like dot, pill edge, and a faint fill so they read as
   * objects rather than outlined text. */
  .tag {
    display: inline-flex; align-items: center; gap: 7px;
    font-family: var(--font-mono); font-size: var(--text-2xs); line-height: 1.2; letter-spacing: .01em;
    text-decoration: none; color: var(--color-muted);
    padding: 5px 11px 5px 9px;
    border: 1px solid var(--color-rule); border-radius: var(--radius-pill);
    background: color-mix(in oklab, var(--color-ink) 3%, transparent);
    transition: color var(--dur-micro), border-color var(--dur-micro), background-color var(--dur-micro);
  }
  .tag::before { content: ""; flex-shrink: 0; width: 4px; height: 4px; border-radius: 50%; background: var(--color-edge); transition: background-color var(--dur-micro); }
  a.tag { min-height: 32px; padding-inline: 11px 13px; }
  .tag-filter { display: flex; flex-wrap: wrap; gap: var(--space-xs); margin-top: var(--space-lg); }
  .tag--filter { min-height: 44px; padding-inline: var(--space-sm); }
  .tag--filter.is-active { background: var(--color-ink); color: var(--color-paper); border-color: var(--color-ink); }
  .tag-count { color: inherit; }
  .theme-toggle { display: inline-flex; align-items: center; gap: 7px; min-height: 44px; padding-inline: var(--space-2xs); font-size: .75rem; text-decoration: none; color: var(--color-muted); }
  .theme-dot { width: 12px; height: 12px; border-radius: 50%; border: 1px solid currentColor; background: linear-gradient(to right, currentColor 50%, transparent 50%); }
  .lang-switch { display: inline-flex; align-items: center; }
  .lang-opt { display: inline-flex; align-items: center; justify-content: center; min-height: 44px; min-width: 32px; font-size: .7rem; text-decoration: none; color: var(--color-muted); }
  .lang-opt.is-active { color: var(--color-ink); }
  @media (hover: hover) {
    .btn--solid:hover { background: var(--color-accent); color: var(--color-accent-ink); }
    .btn--ghost:hover { color: var(--color-ink); border-color: var(--color-ink); }
    .link-more:hover, .theme-toggle:hover, .lang-opt:hover { color: var(--color-accent); }
    a.tag:hover { color: var(--color-ink); border-color: var(--color-edge); background: color-mix(in oklab, var(--color-ink) 6%, transparent); }
    a.tag:hover::before { background: var(--color-accent); }
  }
}


/* ── 60-home.css ───────────────────────────────────────── */
@layer components {
  .hero { position: relative; overflow: clip; }
  .hero-grid {
    display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.07fr);
    min-height: calc(100svh - var(--masthead-h, 89px));
    align-items: center; align-content: center; gap: var(--space-lg);
    padding-block: clamp(32px, 6svh, 72px);
  }
  .hero-statement { position: relative; z-index: var(--z-base); }
  .hero-title { font-size: var(--text-display); font-weight: 400; line-height: var(--lh-display); letter-spacing: -.05em; margin-bottom: 28px; }
  .hero-title .line { display: block; }
  :lang(es) .hero-title { font-size: clamp(2.9rem, 4.3vw, 3.75rem); }
  .hero-lede { font-size: var(--text-md); line-height: 1.8; color: var(--color-muted); max-width: 39ch; margin-bottom: 34px; }
  .hero-secondary { display: inline-flex; align-items: center; min-height: 48px; margin-left: var(--space-sm); color: var(--color-ink-2); font-size: var(--text-sm); text-underline-offset: 5px; text-decoration-color: var(--color-rule-strong); }
  .hardware-figure { min-width: 0; margin-inline: -25px -42px; position: relative; }
  .hardware-artwork { position: relative; }
  .hardware-svg { width: 100%; height: auto; font-family: var(--font-mono); }
  .pcb-hotspots { position: absolute; inset: 0; pointer-events: none; }
  .pcb-hotspot {
    position: absolute; transform: translate(-50%, -50%);
    min-width: 44px; min-height: 44px; padding: 0;
    background: transparent; border: 0; border-radius: var(--radius-3);
    pointer-events: auto; cursor: pointer; touch-action: manipulation;
  }
  .pcb-hotspot--uart { left: 30.2%; top: 69%; width: 14%; height: 16%; }
  .pcb-hotspot--flash { left: 57.5%; top: 72.3%; width: 16%; height: 18%; }
  .pcb-hotspot--mcu { left: 50%; top: 41.5%; width: 38%; height: 39%; }
  .pcb-hotspot--signals { left: 79%; top: 56%; width: 18%; height: 16%; }
  .pcb-hotspot:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; box-shadow: none; }
  .pcb-labels { fill: var(--color-muted); }
  .hardware-figure figcaption { text-align: center; padding-inline: var(--space-lg); margin-top: -4px; }
  .hardware-controls { display: inline-flex; gap: var(--space-lg); }
  .hardware-layer { position: relative; min-width: 44px; min-height: 44px; padding-inline: 2px; font-size: var(--text-xs); color: var(--color-muted); touch-action: manipulation; }
  .hardware-layer[aria-pressed="true"] { color: var(--color-ink); }
  .hardware-layer[aria-pressed="true"]::after { content: ""; position: absolute; inset-inline: 2px; bottom: 5px; height: 1px; background: currentColor; }
  .hardware-detail { min-height: 3.2em; max-width: 46ch; margin: 7px auto 0; color: var(--color-muted); font-size: var(--text-xs); line-height: 1.6; text-wrap: balance; }
  .pcb-pulse { stroke-dasharray: 6 200; stroke-dashoffset: 6; }
  .pcb-pulses { filter: drop-shadow(0 0 3px #b9d8ef); transition: opacity var(--dur-long) var(--ease-out); }
  .pcb-ping, .pcb-led-ring { opacity: 0; transform-box: fill-box; transform-origin: center; vector-effect: non-scaling-stroke; }
  [data-layer="firmware"] .pcb-pulses { opacity: .3; }
  .pcb-signal, .pcb-memory, .pcb-chip, .pcb-header { transition: opacity var(--dur-long) var(--ease-out), filter var(--dur-long) var(--ease-out), transform var(--dur-long) var(--ease-out); }
  [data-layer="firmware"] .pcb-memory { filter: drop-shadow(0 0 5px #b9d8ef88) brightness(1.15); }
  [data-layer="firmware"] .pcb-signal { opacity: .35; }
  [data-layer="impact"] .pcb-signal { filter: drop-shadow(0 0 5px #b9d8ef); stroke-width: 2.5; }
  [data-layer="impact"] .pcb-chip { transform: translateY(-5px); filter: drop-shadow(0 0 5px #b9d8ef66); }
  [data-layer="hardware"] .pcb-header { filter: drop-shadow(0 0 5px #b9d8ef44); }
  .hardware-figure:has(.pcb-hotspot--uart:focus-visible) .pcb-header,
  .hardware-figure:has(.pcb-hotspot--flash:focus-visible) .pcb-memory,
  .hardware-figure:has(.pcb-hotspot--mcu:focus-visible) .pcb-chip,
  .hardware-figure:has(.pcb-hotspot--signals:focus-visible) .pcb-signal {
    filter: drop-shadow(0 0 7px #b9d8ef99) brightness(1.35);
  }
  @media (hover: hover) {
    .hardware-figure:has(.pcb-hotspot--uart:hover) .pcb-header,
    .hardware-figure:has(.pcb-hotspot--flash:hover) .pcb-memory,
    .hardware-figure:has(.pcb-hotspot--mcu:hover) .pcb-chip,
    .hardware-figure:has(.pcb-hotspot--signals:hover) .pcb-signal {
      filter: drop-shadow(0 0 7px #b9d8ef99) brightness(1.35);
    }
  }
  .section--research { padding-block: 72px 88px; }
  .research-overview { display: grid; grid-template-columns: minmax(0, 1fr) 270px; gap: var(--space-lg); }
  .research-cards { display: grid; gap: var(--space-lg); min-width: 0; }
  .research-card { display: grid; grid-template-columns: minmax(0, .82fr) minmax(0, 1fr); overflow: hidden; border: 1px solid var(--color-rule); border-radius: var(--radius-3); text-decoration: none; background: var(--color-paper-2); }
  .research-card-media { position: relative; display: flex; min-height: 260px; overflow: hidden; border-right: 1px solid var(--color-rule); background: var(--color-paper-3); }
  .research-card-media .row-thumb { width: 100%; height: 100%; min-height: 260px; border: 0; border-radius: 0; }
  .research-card-media img { object-fit: cover; filter: var(--thumb-filter); transition: filter var(--dur-long) var(--ease-out), transform var(--dur-long) var(--ease-out); }
  .research-card-open { position: absolute; display: grid; place-items: center; right: var(--space-md); bottom: var(--space-md); width: 36px; height: 36px; border: 1px solid #5d6670; border-radius: 50%; background: #101214; color: #f0f1f2; }
  .research-card-body { padding: 28px; display: flex; flex-direction: column; align-items: flex-start; min-width: 0; }
  .meta-row { display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-xs); color: var(--color-muted); font-size: var(--text-2xs); }
  .meta-sep { color: var(--color-muted); }
  .research-card-title { font-family: var(--font-ui); font-size: 1.55rem; font-weight: 500; letter-spacing: -.025em; line-height: 1.3; margin-top: 22px; text-wrap: pretty; }
  .research-card-desc { color: var(--color-muted); font-family: var(--font-ui); font-size: var(--text-sm); line-height: 1.7; margin-block: 14px 22px; }
  .research-card-link { display: inline-flex; align-items: center; gap: var(--space-sm); color: var(--color-ink-2); font-size: var(--text-xs); padding-top: 25px; margin-top: auto; }
  .archive-preview { padding: var(--space-lg); border: 1px solid var(--color-rule); border-radius: var(--radius-3); background: var(--color-paper-2); }
  .archive-heading { display: flex; gap: var(--space-sm); align-items: center; }
  .archive-heading svg { width: 18px; height: 18px; color: var(--color-muted); }
  .archive-heading h3 { font-size: var(--text-sm); font-weight: 500; letter-spacing: 0; }
  .archive-stats { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-sm); padding-block: 22px; border-bottom: 1px solid var(--color-rule); }
  .archive-stats dd { font-size: 2rem; line-height: 1.2; font-weight: 400; font-variant-numeric: tabular-nums; }
  .archive-stats dt { font-size: var(--text-xs); color: var(--color-muted); margin-top: var(--space-2xs); }
  .archive-topics { display: grid; padding-top: var(--space-sm); }
  .archive-topics a { display: flex; align-items: center; justify-content: space-between; gap: var(--space-xs); min-height: 37px; text-decoration: none; color: var(--color-muted); font-family: var(--font-mono); font-size: var(--text-2xs); overflow-wrap: anywhere; }
  .archive-feed { display: flex; align-items: center; gap: var(--space-xs); min-height: 44px; margin-top: var(--space-sm); padding-top: var(--space-sm); border-top: 1px solid var(--color-rule); text-decoration: none; color: var(--color-ink-2); font-size: var(--text-xs); }
  .archive-feed > svg { margin-left: auto; }
  .feed-symbol { font-size: .8rem; }
  .section--focus { border-block: 1px solid var(--color-rule); background: var(--color-paper-2); padding-block: 78px; }
  .focus-layout { display: grid; grid-template-columns: minmax(0, .85fr) minmax(0, 1.5fr); gap: 80px; }
  .focus-intro > p:last-child { font-size: var(--text-base); color: var(--color-muted); max-width: 32ch; margin-top: var(--space-lg); line-height: 1.8; }
  .focus-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 44px 40px; }
  .focus-item { padding-top: var(--space-lg); border-top: 1px solid var(--color-rule); }
  .focus-item > svg { color: var(--color-accent); width: 28px; height: 28px; margin-bottom: 18px; }
  .focus-item h3 { font-size: var(--text-lg); font-weight: 500; margin-bottom: var(--space-sm); }
  .focus-item p { font-size: var(--text-sm); color: var(--color-muted); line-height: 1.8; }
  .about-grid { display: grid; grid-template-columns: minmax(0, .85fr) minmax(0, 1.5fr); gap: 80px; }
  .about-intro .section-title { max-width: 14ch; }
  .about-signature { display: flex; align-items: center; gap: var(--space-sm); margin-top: var(--space-xl); font-size: var(--text-sm); color: var(--color-ink-2); }
  .about-signature-mark { width: 30px; }
  .signature-parent { color: var(--color-muted); }
  .about-body > p { color: var(--color-ink-2); font-size: var(--text-base); line-height: 1.85; max-width: 62ch; }
  .about-body > p + p { margin-top: var(--space-md); color: var(--color-muted); }
  .about-list { display: grid; gap: var(--space-sm); margin-top: var(--space-lg); }
  .about-list li { display: flex; gap: var(--space-sm); color: var(--color-muted); font-size: var(--text-sm); }
  .about-list li span { color: var(--color-accent); }
  .section--contact { border-top: 1px solid var(--color-rule); background: var(--color-paper-2); padding-block: 72px; }
  .contact-inner { display: flex; align-items: center; justify-content: space-between; gap: var(--space-xl); }
  .contact-title { font-size: var(--text-3xl); font-weight: 400; line-height: 1.2; letter-spacing: -.035em; }
  .contact-sub { max-width: 47ch; margin-top: var(--space-md); color: var(--color-muted); font-size: var(--text-sm); }
  .contact-link { display: flex; align-items: center; gap: var(--space-xl); text-decoration: none; padding-block: var(--space-md); border-bottom: 1px solid var(--color-edge); font-size: var(--text-lg); overflow-wrap: anywhere; }
  .contact-link svg { flex-shrink: 0; }
  @media (hover: hover) {
    .hero-secondary:hover, .archive-topics a:hover, .archive-feed:hover, .contact-link:hover { color: var(--color-accent); }
    .research-card:hover { border-color: var(--color-rule-strong); }
    .research-card:hover img { filter: grayscale(.5); transform: scale(1.025); }
    .research-card:hover .research-card-link { color: var(--color-accent); }
    .hardware-layer:hover { color: var(--color-ink); }
  }
  @media (prefers-reduced-motion: no-preference) {
    .hardware-svg { animation: board-enter 1s var(--ease-out) both; }
    @keyframes board-enter { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }

    /* Idle life on the board: the package floats in its exploded view, the
     * pin-1 LED breathes, and data pulses run chip → test pad. One shared
     * 6s float, a 3s heartbeat, and staggered 3.6s pulses so nothing syncs
     * into a visible beat. Paused off-screen by main.js (.is-idle). */
    .pcb-chip-float { animation: pcb-float 6s var(--ease-inout) infinite; }
    .pcb-chip-shadow { animation: pcb-shadow 6s var(--ease-inout) infinite; }
    .pcb-led { animation: pcb-led 3s var(--ease-inout) infinite; }
    .pcb-led-ring { animation: pcb-ring 3s var(--ease-out) infinite; }
    .pcb-ping { animation: pcb-ring 4.2s var(--ease-out) 1s infinite; }
    .pcb-ping--late { animation-delay: 3.1s; }
    .pcb-pulse { animation: pcb-pulse 3.6s cubic-bezier(.45, 0, .55, 1) 1.1s infinite; }
    .pcb-pulse:nth-child(2) { animation-delay: 2.3s; }
    .pcb-pulse:nth-child(3) { animation-delay: 3.5s; }
    [data-layer="impact"] .pcb-pulse { animation-duration: 2s; }
    .hardware-figure.is-idle :is(.pcb-chip-float, .pcb-chip-shadow, .pcb-led, .pcb-led-ring, .pcb-ping, .pcb-pulse) { animation-play-state: paused; }
    @keyframes pcb-float { 50% { transform: translateY(-4px); } }
    @keyframes pcb-shadow { 50% { opacity: .72; } }
    @keyframes pcb-led { 50% { opacity: .45; } }
    @keyframes pcb-ring { 0% { opacity: .9; transform: scale(1); } 70%, 100% { opacity: 0; transform: scale(3.4); } }
    @keyframes pcb-pulse {
      0% { stroke-dashoffset: 6; opacity: 0; }
      8%, 60% { opacity: 1; }
      70%, 100% { stroke-dashoffset: -100; opacity: 0; }
    }
  }
  @media (max-width: 68rem) {
    .hero-title { font-size: clamp(3rem, 5.5vw, 4.5rem); }
    .hardware-figure { margin-inline: -25px; }
    .research-overview { grid-template-columns: minmax(0, 1fr) 235px; }
    .research-card { grid-template-columns: minmax(0, .7fr) minmax(0, 1fr); }
    .research-card-body { padding: 22px; }
    .research-card-title { font-size: 1.35rem; }
    .focus-layout, .about-grid { gap: var(--space-xl); }
  }
  @media (max-width: 52rem) {
    .hero-grid { grid-template-columns: minmax(0, 1fr); min-height: calc(100svh - var(--masthead-h, 73px)); gap: 0; }
    .hero-title { font-size: clamp(3.1rem, 8.5vw, 5rem); }
    .hero-lede { max-width: 43ch; }
    .hardware-figure { width: min(100%, 560px); margin: -12px auto 0; }
    .hardware-figure figcaption { margin-top: -20px; }
    .research-overview { grid-template-columns: minmax(0, 1fr); }
    .archive-preview { display: none; }
    .focus-layout { grid-template-columns: minmax(0, 1fr); gap: var(--space-xl); }
    .focus-intro > p:last-child { max-width: 48ch; margin-top: var(--space-md); }
    .about-grid { grid-template-columns: minmax(0, 1fr); }
    .about-intro .section-title { max-width: 22ch; }
    .about-signature { margin-top: var(--space-lg); }
    .contact-inner { flex-direction: column; align-items: flex-start; gap: var(--space-lg); }
    .section--research { padding-block: 50px 60px; }
    .section--focus, .section--contact { padding-block: 56px; }
  }
  @media (max-width: 34rem) {
    .hero-title { font-size: clamp(2.7rem, 10.4vw, 3.8rem); }
    .hero-lede { font-size: var(--text-base); margin-bottom: 26px; }
    .hero-secondary { margin-left: 0; }
    .hardware-figure { margin-top: 0; }
    .hardware-figure figcaption { margin-top: -5px; padding-inline: 0; }
    .research-card { grid-template-columns: minmax(0, 1fr); }
    .research-card-media { min-height: 180px; max-height: 210px; border-right: 0; border-bottom: 1px solid var(--color-rule); }
    .research-card-media .row-thumb { min-height: 180px; }
    .research-card-body { padding: var(--space-lg); }
    .research-card-title { margin-top: 16px; font-size: 1.5rem; }
    .focus-grid { grid-template-columns: minmax(0, 1fr); gap: 28px; }
    .contact-link { width: 100%; justify-content: space-between; gap: var(--space-md); font-size: var(--text-base); }
    :lang(es) .hero-title { font-size: clamp(2.4rem, 8.9vw, 3.1rem); }
  }
  @media print {
    .hero-grid { min-height: auto; padding-block: var(--space-xl); }
  }
}


/* ── 65-index.css ───────────────────────────────────────── */
@layer components {
  .page-head { padding-block: clamp(3rem, 6vw, 5rem) var(--space-xl); border-bottom: 1px solid var(--color-rule); }
  .page-title { font-size: var(--text-4xl); font-weight: 400; letter-spacing: var(--track-display); }
  .page-sub, .page-lede { margin-top: var(--space-md); font-family: var(--font-reading); color: var(--color-muted); max-width: 58ch; line-height: 1.75; }
  .page-lede { font-size: var(--text-md); }
  .page-sub code { font-family: var(--font-mono); font-size: .9em; background: var(--color-paper-3); padding: .1em .35em; border-radius: var(--radius-1); overflow-wrap: anywhere; }
  .archive-page-heading { display: flex; align-items: center; justify-content: space-between; gap: var(--space-xl); }
  .archive-page-heading > .btn { flex-shrink: 0; }
  .research-dashboard { display: grid; grid-template-columns: 210px minmax(0, 1fr); gap: var(--space-xl); min-height: 430px; }
  .research-sidebar { border-right: 1px solid var(--color-rule); padding-right: var(--space-lg); }
  .sidebar-heading { font-size: var(--text-sm); color: var(--color-ink-2); margin-bottom: var(--space-md); }
  .topic-nav { display: grid; gap: var(--space-2xs); }
  .topic-filter { display: flex; align-items: center; justify-content: space-between; gap: var(--space-sm); min-height: 44px; padding: 10px 12px; border: 1px solid transparent; border-radius: var(--radius-2); text-decoration: none; color: var(--color-muted); font-size: var(--text-sm); }
  .topic-filter > span:first-child { overflow-wrap: anywhere; min-width: 0; }
  .topic-filter > span:last-child { font-family: var(--font-mono); font-size: var(--text-2xs); }
  .topic-filter.is-active { color: var(--color-ink); border-color: var(--color-rule); background: var(--color-paper-2); }
  .sidebar-lab { margin-top: var(--space-xl); padding-top: var(--space-lg); border-top: 1px solid var(--color-rule); }
  .sidebar-lab > svg { color: var(--color-muted); margin-bottom: var(--space-sm); }
  .sidebar-lab p { color: var(--color-muted); font-size: var(--text-sm); }
  .sidebar-lab a { display: inline-flex; align-items: center; gap: var(--space-xs); min-height: 44px; margin-top: var(--space-xs); text-decoration: none; font-size: var(--text-sm); }
  .research-results { min-width: 0; }
  .research-search { display: flex; align-items: center; gap: var(--space-sm); padding: 5px 5px 5px 16px; border: 1px solid var(--color-edge); background: var(--color-paper-2); border-radius: var(--radius-3); }
  .research-search > svg { flex-shrink: 0; color: var(--color-muted); }
  .research-search input[type="search"] { width: 100%; min-width: 0; border: 0; padding-block: var(--space-sm); background: transparent; color: var(--color-ink); font-size: var(--text-sm); }
  .research-search input::placeholder { color: var(--color-muted); opacity: 1; }
  .research-search > button { flex-shrink: 0; min-height: 42px; }
  .results-meta { display: flex; justify-content: space-between; flex-wrap: wrap; gap: var(--space-md); margin-block: 24px 18px; color: var(--color-muted); font-size: var(--text-xs); }
  .results-meta a { color: var(--color-ink-2); text-underline-offset: 3px; }
  .research-empty { display: grid; justify-items: start; gap: var(--space-lg); padding: var(--space-xl); border: 1px solid var(--color-rule); border-radius: var(--radius-3); }
  .research-empty > svg { color: var(--color-muted); }
  .research-empty h2 { max-width: 45ch; font-size: var(--text-lg); font-weight: 400; line-height: 1.6; }
  .row-thumb { display: block; aspect-ratio: 16 / 10; overflow: hidden; background: var(--color-paper-3); }
  .row-thumb img { width: 100%; height: 100%; object-fit: cover; }
  .row-thumb--fallback { display: grid; place-items: center; background-image: repeating-linear-gradient(var(--hatch, 45deg), transparent 0 18px, color-mix(in oklab, var(--color-ink) 5%, transparent) 18px 19px); }
  .row-thumb--fallback[data-hatch="0"] { --hatch: 0deg; }
  .row-thumb--fallback[data-hatch="1"] { --hatch: 30deg; }
  .row-thumb--fallback[data-hatch="2"] { --hatch: 60deg; }
  .row-thumb--fallback[data-hatch="3"] { --hatch: 90deg; }
  .row-thumb--fallback[data-hatch="4"] { --hatch: 120deg; }
  .row-thumb--fallback[data-hatch="5"] { --hatch: 150deg; }
  .row-thumb-mark { width: 64px; color: var(--color-muted); }
  .page-404 { text-align: center; padding-block: clamp(4rem, 12vw, 8rem); border-bottom: 0; }
  .page-404 .page-sub, .page-404 .cta-row { margin-inline: auto; }
  .page-404 .page-sub { max-width: 46ch; }
  .page-404 .cta-row { margin-top: var(--space-2xl); }
  .code-404 { font-size: clamp(4rem, 18vw, 9rem); font-weight: 400; line-height: 1; letter-spacing: -.04em; color: var(--color-ink); margin-block: var(--space-md) var(--space-lg); }
  @media (hover: hover) { .topic-filter:hover { color: var(--color-ink); background: var(--color-paper-2); } }
  @media (max-width: 64rem) {
    .research-dashboard { grid-template-columns: 180px minmax(0, 1fr); gap: var(--space-lg); }
    .research-results .research-card { grid-template-columns: minmax(0, 1fr); }
    .research-results .research-card-media, .research-results .row-thumb { min-height: 200px; max-height: 240px; }
  }
  @media (max-width: 52rem) {
    .archive-page-heading { flex-direction: column; align-items: flex-start; gap: var(--space-lg); }
    .research-dashboard { grid-template-columns: minmax(0, 1fr); }
    .research-sidebar { padding: 0 0 var(--space-lg); border-right: 0; border-bottom: 1px solid var(--color-rule); }
    .topic-nav { display: flex; flex-wrap: wrap; gap: var(--space-xs); }
    .topic-filter { border-color: var(--color-rule); font-size: var(--text-xs); }
    .sidebar-lab { display: none; }
    .research-results .research-card { grid-template-columns: minmax(0, .7fr) minmax(0, 1fr); }
    .research-results .research-card-media, .research-results .row-thumb { min-height: 260px; max-height: none; }
  }
  @media (max-width: 34rem) {
    .research-results .research-card { grid-template-columns: minmax(0, 1fr); }
    .research-results .research-card-media, .research-results .row-thumb { min-height: 180px; max-height: 210px; }
    .research-search { gap: var(--space-xs); padding-left: var(--space-sm); }
    .research-search > svg { display: none; }
    .research-search > .btn { padding-inline: 14px; }
    .research-search input[type="search"] { font-size: 16px; }
  }
}


/* ── 70-post.css ───────────────────────────────────────── */
@layer components {
  /* ── article header ──────────────────────────────────────────────── */
  .post-head {
    padding-block: clamp(2rem, 4vw, 3rem) var(--space-xl);
    border-bottom: 1px solid var(--color-rule-strong);
    background: var(--color-paper);
  }
  /* Same grid as .post-body, so the title sits exactly over the measure column.
   * A narrow auto-centred header floating above left-flush body copy is the
   * classic accidental-mismatch tell. */
  .post-head-inner {
    display: grid;
    grid-template-columns: minmax(0, 1fr) min(var(--measure), 100%) minmax(0, 1fr);
    column-gap: clamp(var(--space-lg), 4vw, var(--space-2xl));
  }
  .post-head-inner > * { grid-column: 2; }

  .back-link {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2xs);
    font-size: var(--text-2xs);
    letter-spacing: var(--track-label);
    text-transform: uppercase;
    text-decoration: none;
    color: var(--color-muted);
    padding-block: var(--space-xs);
    transition: color var(--dur-micro) var(--ease-out);
  }
  .back-link svg { transition: transform var(--dur-short) var(--ease-out); }
  @media (hover: hover) {
    .back-link:hover { color: var(--color-accent); }
    .back-link:hover svg { transform: translateX(-3px); }
  }

  .post-kicker {
    margin-top: var(--space-md);
    font-size: var(--text-2xs);
    letter-spacing: var(--track-label);
    text-transform: uppercase;
    color: var(--color-accent);
  }
  .post-title {
    margin-top: var(--space-sm);
    font-size: var(--text-4xl);
    line-height: var(--lh-display);
    letter-spacing: var(--track-display);
  }
  .post-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-xs);
    margin-top: var(--space-md);
    font-size: var(--text-2xs);
    letter-spacing: 0.06em;
    color: var(--color-muted);
  }
  .post-head-tags { margin-top: var(--space-md); }

  /* ── body: measure + sticky outline gutter ───────────────────────────
   * The outline is server-rendered (lib/posts.js) and positioned with
   * position:sticky in a grid track. The previous build measured and wrote
   * `top`/`maxHeight` from JS on every frame, hard-coupled to the nav height,
   * the header's bounding box and a decorative footer rule — change any one
   * of those and the outline landed in the gutter or collapsed to zero.
   */
  .post-body {
    display: grid;
    grid-template-columns: minmax(0, 1fr) min(var(--measure), 100%) minmax(0, 1fr);
    column-gap: clamp(var(--space-lg), 4vw, var(--space-2xl));
    align-items: start;
    padding-block: var(--space-2xl);
  }
  .post-measure { grid-column: 2; min-width: 0; }

  /* Marginal metadata rail (DESIGN.md: "single measure, marginal metadata").
   * Lives in the left gutter, right-aligned toward the measure like a margin
   * note, sticky beside the reading column. Fills the left symmetrically with
   * the TOC on the right, and it is genuinely useful while scrolling. */
  .post-rail {
    grid-column: 1;
    justify-self: end;
    width: min(13rem, 100%);
    align-self: start;
    position: sticky;
    top: calc(var(--masthead-h, 76px) + var(--space-lg));
    display: grid;
    gap: var(--space-lg);
    padding-right: var(--space-lg);
    border-right: 1px solid var(--color-rule);
    text-align: right;
  }
  .rail-block { display: grid; gap: var(--space-3xs); }
  .rail-label {
    font-size: var(--text-2xs);
    letter-spacing: var(--track-label);
    text-transform: uppercase;
    color: var(--color-muted);
  }
  .rail-value { font-size: var(--text-xs); color: var(--color-ink-2); }
  .rail-value time { font-variant-numeric: tabular-nums; }
  .rail-tags { display: flex; flex-wrap: wrap; gap: var(--space-2xs); justify-content: flex-end; }
  .rail-tags > .tags { justify-content: inherit; gap: 6px; }

  .post-toc {
    grid-column: 3;
    justify-self: start;
    width: min(15rem, 100%);
    position: sticky;
    top: calc(var(--masthead-h, 76px) + var(--space-lg));
    max-height: calc(100vh - var(--masthead-h, 76px) - var(--space-2xl));
    overflow-y: auto;
    border-left: 1px solid var(--color-rule);
    padding-left: var(--space-md);
    padding-right: var(--space-sm);
    overscroll-behavior: contain;
    scrollbar-gutter: stable;
  }
  .post-toc:focus-within { --scroll-thumb: var(--scroll-thumb-active); }
  @media (hover: hover) {
    .post-toc:hover { --scroll-thumb: var(--scroll-thumb-active); }
  }
  .toc-head {
    font-size: var(--text-2xs);
    letter-spacing: var(--track-label);
    text-transform: uppercase;
    color: var(--color-muted);
    margin-bottom: var(--space-sm);
  }
  .toc-item--h3 { padding-left: var(--space-md); }
  .toc-link {
    display: block;
    font-size: var(--text-xs);
    line-height: var(--lh-snug);
    color: var(--color-muted);
    text-decoration: none;
    padding-block: var(--space-2xs);
    border-left: 2px solid transparent;
    margin-left: calc(var(--space-md) * -1 - 1px);
    padding-left: var(--space-md);
    transition: color var(--dur-micro) var(--ease-out), border-color var(--dur-micro) var(--ease-out);
  }
  @media (hover: hover) { .toc-link:hover { color: var(--color-ink); } }
  .toc-link.is-active { color: var(--color-accent); border-left-color: var(--color-accent); }

  .post-langnote {
    font-size: var(--text-xs);
    color: var(--color-muted);
    background: var(--color-paper-2);
    border-left: 2px solid var(--color-accent);
    padding: var(--space-sm) var(--space-md);
    margin-bottom: var(--space-xl);
  }

  /* ── article footer ──────────────────────────────────────────────── */
  .post-foot { padding-bottom: var(--space-3xl); }
  .post-foot-rule {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    color: var(--color-rule-strong);
    margin-bottom: var(--space-xl);
  }
  .post-foot-rule::before, .post-foot-rule::after {
    content: "";
    flex: 1;
    height: 1px;
    background: var(--color-rule);
  }
  .post-foot-mark { width: 26px; }

  .post-nav {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1px;
    background: var(--color-rule);
    border: 1px solid var(--color-rule);
  }
  .post-nav-item {
    display: grid;
    gap: var(--space-2xs);
    background: var(--color-paper);
    padding: var(--space-lg);
    text-decoration: none;
    transition: background-color var(--dur-short) var(--ease-out);
  }
  .post-nav-item--next { text-align: right; }
  @media (hover: hover) {
    a.post-nav-item:hover { background: var(--wash); }
    a.post-nav-item:hover .post-nav-title { color: var(--color-accent); }
  }
  .post-nav-label {
    font-size: var(--text-2xs);
    letter-spacing: var(--track-label);
    text-transform: uppercase;
    color: var(--color-muted);
  }
  .post-nav-title {
    font-family: var(--font-heading);
    font-weight: var(--heading-weight);
    font-size: var(--text-base);
    line-height: var(--lh-snug);
    transition: color var(--dur-micro) var(--ease-out);
  }

  @media (max-width: 78rem) {
    .post-body, .post-head-inner {
      grid-template-columns: minmax(0, var(--measure));
      justify-content: center;
      column-gap: 0;
    }
    .post-head-inner > *, .post-measure, .post-rail { grid-column: 1; }
    .post-toc { display: none; }
    /* rail becomes a plain meta strip above the article on narrow screens */
    .post-rail {
      position: static;
      width: auto;
      text-align: left;
      border-right: 0;
      border-bottom: 1px solid var(--color-rule);
      padding: 0 0 var(--space-lg);
      margin-bottom: var(--space-lg);
      grid-auto-flow: row;
    }
    .rail-tags { justify-content: flex-start; }
  }
  @media (max-width: 40rem) {
    .post-nav { grid-template-columns: minmax(0, 1fr); }
    .post-nav-item--next { text-align: left; }
  }
}

@layer prose {
  /* Document register: serif, 68ch, generous leading. This is the surface the
   * whole site exists to serve, so it gets the most typographic care. */
  .prose {
    font-family: var(--font-reading);
    font-size: var(--reading-size);
    line-height: var(--reading-lh);
    color: var(--color-ink-2);
    font-variant-numeric: oldstyle-nums proportional-nums;
  }

  .prose > * + * { margin-top: var(--space-md); }
  .prose p { max-width: var(--measure); }

  .prose h2, .prose h3, .prose h4 {
    font-family: var(--font-heading);
    color: var(--color-ink);
    letter-spacing: var(--track-tight);
    scroll-margin-top: calc(var(--masthead-h, 76px) + var(--space-lg));
  }
  .prose h2 {
    font-size: var(--text-2xl);
    margin-top: var(--space-2xl);
    padding-top: var(--space-md);
    border-top: 1px solid var(--color-rule);
  }
  .prose h3 { font-size: var(--text-lg); margin-top: var(--space-xl); }
  .prose h4 { font-size: var(--text-md); margin-top: var(--space-lg); }

  .h-anchor {
    margin-left: 0.4em;
    color: var(--color-rule-strong);
    text-decoration: none;
    opacity: 0;
    transition: opacity var(--dur-micro) var(--ease-out);
  }
  .prose :is(h2, h3, h4):hover .h-anchor,
  .h-anchor:focus-visible { opacity: 1; }

  .prose a {
    color: var(--color-accent);
    text-decoration-line: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 2px;
    text-decoration-color: color-mix(in oklab, var(--color-accent) 45%, transparent);
    transition: text-decoration-color var(--dur-micro) var(--ease-out);
  }
  @media (hover: hover) { .prose a:hover { text-decoration-color: currentColor; } }

  .prose strong { color: var(--color-ink); font-weight: 600; }
  .prose em { font-style: italic; }

  .prose ul, .prose ol { padding-left: var(--space-lg); max-width: var(--measure); }
  .prose li + li { margin-top: var(--space-2xs); }
  .prose li::marker { color: var(--color-accent); }

  .prose blockquote {
    border-left: 2px solid var(--color-accent);
    padding-left: var(--space-md);
    color: var(--color-muted);
    max-width: var(--measure);
  }

  /* A markdown blockquote opening with "**Label:** …" is upgraded to a
   * callout by the renderer, so existing posts gain the treatment without a
   * single markdown edit. */
  .callout {
    border: 1px solid var(--color-rule-strong);
    border-left: 3px solid var(--color-accent);
    background: var(--color-paper-2);
    padding: var(--space-md) var(--space-lg);
    max-width: var(--measure);
  }
  .callout--warn { border-left-color: var(--color-accent); }
  .callout-label {
    font-size: var(--text-2xs);
    letter-spacing: var(--track-label);
    text-transform: uppercase;
    color: var(--color-accent);
    margin-bottom: var(--space-xs);
  }
  .callout > p + p { margin-top: var(--space-sm); }

  .prose hr {
    border: 0;
    height: 1px;
    background: var(--color-rule);
    margin-block: var(--space-2xl);
  }

  .prose code:not(.hljs) {
    font-family: var(--font-mono);
    font-variant-ligatures: none;
    font-size: 0.86em;
    background: var(--color-paper-3);
    border: 1px solid var(--color-rule);
    border-radius: var(--radius-1);
    padding: 0.1em 0.35em;
    overflow-wrap: anywhere;
  }

  .prose table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--text-sm);
    font-variant-numeric: tabular-nums;
  }
  .prose :is(th, td) {
    text-align: left;
    padding: var(--space-xs) var(--space-sm);
    border-bottom: 1px solid var(--color-rule);
  }
  .prose th {
    font-family: var(--font-ui);
    font-weight: 500;
    font-size: var(--text-xs);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--color-muted);
    background: var(--color-paper-2);
  }

  /* figures break the measure deliberately — the one grid-break on the page */
  .post-figure {
    margin-block: var(--space-xl);
    width: 100%;
    margin-inline: 0;
  }
  .post-figure :is(img, video) {
    width: 100%;
    border: 1px solid var(--color-rule);
    border-radius: var(--radius-2);
    background: var(--color-paper-2);
  }
  /* .post-video is the class the desmume post writes by hand in raw HTML and
   * which had no rule at all before; it is treated exactly like a rendered
   * video figure. Capped so a tall clip cannot swallow the article. */
  .post-figure--video video, .post-video video {
    max-height: 78vh;
    object-fit: contain;
    background: var(--color-paper-3);
  }
  .post-figure figcaption {
    font-family: var(--font-mono);
    font-size: var(--text-2xs);
    line-height: var(--lh-snug);
    color: var(--color-muted);
    margin-top: var(--space-xs);
    padding-left: var(--space-xs);
    border-left: 2px solid var(--color-rule-strong);
  }

  @media (max-width: 60rem) {
    .post-figure { width: 100%; margin-inline: 0; }
  }
}


/* ── 75-code.css ───────────────────────────────────────── */
@layer code {
  /* Code is a first-class surface on a vulnerability-research site: an article
   * is mostly disassembly, hex and shellcode. Two things the previous build
   * got wrong and this fixes — the block could not be scrolled from the
   * keyboard at all (WCAG 2.1.1) despite being horizontally overflowing, and
   * the syntax theme existed only for dark.
   */
  .code-block {
    margin-block: var(--space-xl);
    width: 100%;
    margin-inline: 0;
    border: 1px solid var(--color-rule-strong);
    border-radius: var(--radius-2);
    background: var(--color-paper-2);
    overflow: hidden;
  }
  .code-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-sm);
    padding: var(--space-2xs) var(--space-sm);
    border-bottom: 1px solid var(--color-rule);
    background: var(--color-paper-3);
  }
  .code-lang {
    font-family: var(--font-mono);
    font-size: var(--text-2xs);
    letter-spacing: var(--track-label);
    text-transform: uppercase;
    color: var(--color-muted);
  }
  .code-copy {
    font-family: var(--font-mono);
    font-size: var(--text-2xs);
    letter-spacing: var(--track-label);
    text-transform: uppercase;
    color: var(--color-muted);
    min-height: 32px;
    padding-inline: var(--space-xs);
    border: 1px solid transparent;
    border-radius: var(--radius-1);
    transition: color var(--dur-micro) var(--ease-out), border-color var(--dur-micro) var(--ease-out);
  }
  @media (hover: hover) {
    .code-copy:hover { color: var(--color-ink); border-color: var(--color-edge); }
  }
  .code-copy.is-copied { color: var(--color-accent); border-color: var(--color-accent); }

  .code-block pre {
    margin: 0;
    padding: var(--space-md);
    overflow-x: auto;
    overscroll-behavior-x: contain;
  }
  .code-block code.hljs {
    font-family: var(--font-mono);
    /* Ligatures OFF. A ligated -> or != is actively hostile in a post whose
     * readers byte-compare the listing against their own output. */
    font-variant-ligatures: none;
    font-size: var(--text-sm);
    line-height: 1.65;
    color: var(--syn-base);
    background: none;
    tab-size: 4;
  }

  /* ── syntax palette ────────────────────────────────────────────────
   * Near-monochrome by design: the accent carries strings, everything else is
   * a low-chroma hue shift off the ink. All values verified ≥4.5:1 on the
   * code surface in both schemes by scripts/check-contrast.mjs.
   */
  :root {
    --syn-base: var(--color-ink-2);
    --syn-comment: oklch(50% 0.02 62);
    --syn-keyword: oklch(43% 0.115 300);
    --syn-string: oklch(43% 0.10 150);
    --syn-number: oklch(46% 0.11 40);
    --syn-title: oklch(43% 0.115 250);
    --syn-type: oklch(44% 0.09 195);
    --syn-attr: oklch(45% 0.10 80);
    --syn-meta: oklch(52% 0.04 62);
    --syn-del: oklch(47% 0.15 25);
    --syn-add: oklch(44% 0.12 150);
  }
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
      --syn-comment: oklch(66% 0.02 62);
      --syn-keyword: oklch(80% 0.12 300);
      --syn-string: oklch(82% 0.14 145);
      --syn-number: oklch(82% 0.13 45);
      --syn-title: oklch(80% 0.11 250);
      --syn-type: oklch(83% 0.11 195);
      --syn-attr: oklch(85% 0.12 95);
      --syn-meta: oklch(70% 0.04 62);
      --syn-del: oklch(75% 0.15 25);
      --syn-add: oklch(82% 0.14 150);
    }
  }
  :root[data-theme="dark"] {
    --syn-comment: oklch(66% 0.02 62);
    --syn-keyword: oklch(80% 0.12 300);
    --syn-string: oklch(82% 0.14 145);
    --syn-number: oklch(82% 0.13 45);
    --syn-title: oklch(80% 0.11 250);
    --syn-type: oklch(83% 0.11 195);
    --syn-attr: oklch(85% 0.12 95);
    --syn-meta: oklch(70% 0.04 62);
    --syn-del: oklch(75% 0.15 25);
    --syn-add: oklch(82% 0.14 150);
  }

  .hljs-comment, .hljs-quote { color: var(--syn-comment); font-style: italic; }
  .hljs-keyword, .hljs-selector-tag, .hljs-literal, .hljs-doctag { color: var(--syn-keyword); font-weight: 500; }
  .hljs-string, .hljs-regexp { color: var(--syn-string); }
  .hljs-number, .hljs-symbol, .hljs-bullet, .hljs-link { color: var(--syn-number); }
  .hljs-title, .hljs-name, .hljs-section, .hljs-title\.function_ { color: var(--syn-title); }
  .hljs-type, .hljs-built_in, .hljs-class .hljs-title { color: var(--syn-type); }
  .hljs-attr, .hljs-attribute, .hljs-variable, .hljs-template-variable, .hljs-selector-attr, .hljs-selector-class, .hljs-selector-id { color: var(--syn-attr); }
  .hljs-meta, .hljs-meta .hljs-keyword { color: var(--syn-meta); }
  .hljs-params { color: var(--syn-base); }
  .hljs-emphasis { font-style: italic; }
  .hljs-strong { font-weight: 700; }
  .hljs-deletion { color: var(--syn-del); background: color-mix(in oklab, var(--syn-del) 12%, transparent); }
  .hljs-addition { color: var(--syn-add); background: color-mix(in oklab, var(--syn-add) 12%, transparent); }

  @media (max-width: 60rem) {
    .code-block { width: 100%; margin-inline: 0; }
  }
}


/* ── 80-broadcast.css ───────────────────────────────────────── */
@layer components {
  /* ── broadcast surfaces: Academy / Courses / Videos ──────────────────
   * These carry placeholder copy and are not linked from the nav. They exist
   * so the second register has real components — media tiles, a curriculum
   * list, state chips — that can be built and reviewed before any course or
   * video actually exists.
   */
  .page-head--broadcast { padding-block: clamp(2.5rem, 5vw, 4rem) var(--space-xl); }
  .page-academy .section, .page-courses .section, .page-videos .section { padding-block: var(--space-2xl); }

  /* Says plainly, on the page, that nothing here is real yet. */
  .placeholder-note {
    display: inline-block;
    margin-top: var(--space-lg);
    font-size: var(--text-2xs);
    letter-spacing: var(--track-label);
    text-transform: uppercase;
    color: var(--color-accent);
    border: 1px dashed var(--color-accent);
    border-radius: var(--radius-2);
    padding: var(--space-xs) var(--space-sm);
  }

  .stub-body {
    font-family: var(--font-reading);
    color: var(--color-ink-2);
    max-width: var(--measure);
    margin-bottom: var(--space-2xl);
  }

  /* curriculum list — asymmetric, ruled, numbered */
  .track-list { border-top: 1px solid var(--color-rule-strong); }
  .track {
    display: grid;
    grid-template-columns: 7rem minmax(0, 1fr) minmax(0, 1.5fr) auto;
    gap: var(--space-lg);
    align-items: baseline;
    padding-block: var(--space-lg);
    border-bottom: 1px solid var(--color-rule);
  }
  .track-label {
    font-size: var(--text-2xs);
    letter-spacing: var(--track-label);
    text-transform: uppercase;
    color: var(--color-accent);
  }
  .track-title { font-size: var(--text-xl); letter-spacing: var(--track-tight); }
  .track-desc { font-family: var(--font-reading); font-size: var(--text-sm); color: var(--color-muted); }
  .track-state, .media-state {
    font-size: var(--text-2xs);
    letter-spacing: var(--track-label);
    text-transform: uppercase;
    color: var(--color-muted);
    border: 1px solid var(--color-rule-strong);
    border-radius: var(--radius-pill);
    padding: var(--space-3xs) var(--space-xs);
    white-space: nowrap;
    justify-self: start;
  }

  /* media grid — 16:9 tiles, the shape YouTube/Udemy content will want */
  .media-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
    gap: var(--space-lg);
  }
  .media-grid--wide { grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr)); }

  .media-card {
    display: grid;
    gap: var(--space-xs);
    align-content: start;
    padding: var(--space-md);
    border: 1px solid var(--color-rule);
    border-radius: var(--card-radius);
    background: var(--color-paper-2);
  }
  /* first tile spans two columns so the grid is not four identical boxes */
  .media-grid > .media-card:first-child { grid-column: span 2; }
  @media (max-width: 60rem) {
    .media-grid > .media-card:first-child { grid-column: auto; }
    .track { grid-template-columns: minmax(0, 1fr); gap: var(--space-xs); }
  }

  .media-thumb {
    display: grid;
    place-items: center;
    aspect-ratio: 4 / 3;
    border-radius: var(--radius-2);
    background:
      repeating-linear-gradient(135deg, transparent 0 9px, color-mix(in oklab, var(--color-ink) 4%, transparent) 9px 10px),
      var(--color-paper-3);
  }
  .media-thumb--wide { aspect-ratio: 16 / 9; }
  .media-thumb-mark { width: 44px; color: var(--color-rule-strong); }
  .media-title { font-size: var(--text-md); letter-spacing: var(--track-tight); }
  .media-desc { font-family: var(--font-reading); font-size: var(--text-sm); color: var(--color-muted); }

  /* Internal dashboard: counts and publication states use real content. */
  .section--admin { padding-block: var(--space-xl) var(--space-3xl); }
  .admin-stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-lg); margin-bottom: var(--space-2xl); }
  .admin-stats > div { padding: var(--space-lg); border: 1px solid var(--color-rule); border-radius: var(--radius-3); background: var(--color-paper-2); }
  .admin-stats dt { font-size: var(--text-sm); color: var(--color-ink-2); }
  .admin-stats dd { font-size: 3rem; font-weight: 400; line-height: 1.2; margin-block: var(--space-sm); font-variant-numeric: tabular-nums; }
  .admin-stats span { font-size: var(--text-xs); color: var(--color-muted); }
  .admin-publications { border: 1px solid var(--color-rule); border-radius: var(--radius-3); background: var(--color-paper-2); overflow: hidden; }
  .admin-publication { display: flex; align-items: center; gap: var(--space-lg); padding: var(--space-lg); text-decoration: none; }
  .admin-publication + .admin-publication { border-top: 1px solid var(--color-rule); }
  .admin-publication-icon { color: var(--color-muted); flex-shrink: 0; }
  .admin-publication-body { display: grid; gap: var(--space-2xs); margin-right: auto; min-width: 0; }
  .admin-publication-title { font-size: var(--text-base); overflow-wrap: anywhere; }
  .admin-publication-date { font-size: var(--text-2xs); color: var(--color-muted); }
  .admin-state { padding: 5px 10px; border: 1px solid var(--color-rule-strong); border-radius: var(--radius-pill); font-size: var(--text-2xs); color: var(--color-accent); white-space: nowrap; }
  .admin-state--draft { color: var(--color-muted); }
  .admin-publication > svg { flex-shrink: 0; color: var(--color-muted); }
  .admin-section-head { margin-top: var(--space-2xl); }
  .admin-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-lg); margin-bottom: var(--space-xl); }
  .admin-card { padding: var(--space-lg); border: 1px solid var(--color-rule); border-radius: var(--radius-3); background: var(--color-paper-2); }
  .admin-card-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-md); margin-bottom: var(--space-lg); }
  .admin-thumb { color: var(--color-accent); }
  .admin-card-title { font-size: var(--text-xl); margin-bottom: var(--space-sm); }
  .admin-card-note { color: var(--color-muted); font-size: var(--text-sm); min-height: 3.2em; }
  .admin-card .link-more { margin-top: var(--space-lg); }
  .admin-note { border-left: 1px solid var(--color-edge); padding: var(--space-xs) var(--space-lg); max-width: 78ch; }
  .admin-note-label { color: var(--color-ink-2); font-size: var(--text-sm); margin-bottom: var(--space-xs); }
  .admin-note p:last-child { color: var(--color-muted); font-size: var(--text-sm); }
  .admin-note code, .page-lede code { font-family: var(--font-mono); font-size: .85em; overflow-wrap: anywhere; }
  @media (hover: hover) { .admin-publication:hover { background: var(--color-paper-3); } }
  @media (max-width: 52rem) {
    .admin-stats { gap: var(--space-sm); }
    .admin-stats > div { padding: var(--space-md); }
    .admin-grid { grid-template-columns: minmax(0, 1fr); }
    .admin-card-note { min-height: 0; }
  }
  @media (max-width: 34rem) {
    .admin-stats { grid-template-columns: minmax(0, 1fr); gap: var(--space-sm); }
    .admin-stats > div { display: grid; grid-template-columns: 1fr auto; align-items: center; }
    .admin-stats dd { grid-column: 2; grid-row: 1 / 3; font-size: 2.2rem; margin: 0 0 0 var(--space-md); }
    .admin-stats span { grid-column: 1; }
    .admin-publication { gap: var(--space-sm); padding: var(--space-md); flex-wrap: wrap; }
    .admin-publication-icon { display: none; }
    .admin-publication-body { flex-basis: 100%; }
  }
}


/* ── 90-utilities.css ───────────────────────────────────────── */
@layer utilities {
  .visually-hidden {
    position: absolute;
    width: 1px; height: 1px;
    margin: -1px; padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  /* ── the page-load reveal ─────────────────────────────────────────────
   * One orchestrated entrance, driven entirely by CSS.
   *
   * Deliberately NOT scroll-triggered. Fading every block in as it enters the
   * viewport is an anti-pattern in its own right, and the previous build tied
   * it to an IntersectionObserver — including on `.prose`, which meant the
   * entire article body was `opacity: 0` until JavaScript ran. Between that
   * and a `body.preload` gate cleared only by JS, there were two independent
   * paths to a blank article if /js/main.js ever failed to load. Primary
   * content is never gated on script now.
   */
  @keyframes reveal {
    from { opacity: 0; transform: translateY(10px); }
    to   { opacity: 1; transform: none; }
  }
  [data-reveal] {
    animation: reveal var(--dur-long) var(--ease-out) both;
  }
  /* Stagger by position, capped at 400ms total — past ~500ms a page reads as
   * slow to settle. */
  [data-reveal]:nth-of-type(2) { animation-delay: 80ms; }
  [data-reveal]:nth-of-type(3) { animation-delay: 160ms; }
  [data-reveal]:nth-of-type(4) { animation-delay: 240ms; }
  [data-reveal]:nth-of-type(5) { animation-delay: 320ms; }
  [data-reveal]:nth-of-type(n + 6) { animation-delay: 400ms; }

  .index-item:nth-child(2) { animation-delay: 70ms; }
  .index-item:nth-child(3) { animation-delay: 140ms; }
  .index-item:nth-child(4) { animation-delay: 210ms; }
  .row-item:nth-child(2) { animation-delay: 60ms; }
  .row-item:nth-child(3) { animation-delay: 120ms; }
  .row-item:nth-child(4) { animation-delay: 180ms; }
  .row-item:nth-child(n + 5) { animation-delay: 240ms; }
}

@layer utilities {
  /* ── reduced motion ──────────────────────────────────────────────────
   * Every animation is switched OFF, not merely shortened. The previous build
   * only crushed durations, which left infinite transform animations parked
   * on their final frame — the marquee ended up permanently translated -50%.
   */
  @media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
      animation-duration: 1ms !important;
      animation-iteration-count: 1 !important;
      transition-duration: 1ms !important;
      scroll-behavior: auto !important;
    }
    [data-reveal] { animation: none; opacity: 1; transform: none; }
    .typed-caret { animation: none; opacity: 1; }
    .masthead-collapse { transition: none; }
    .btn:hover, .row:hover, .card:hover { transform: none; }
  }

  /* ── forced colors ───────────────────────────────────────────────────
   * The old hero relied on -webkit-text-stroke over transparent text, so the
   * emphasised word disappeared entirely wherever the stroke did not paint.
   * Nothing in this system depends on a paint effect to be legible, but the
   * decorative layers are still dropped and the rules made explicit.
   */
  @media (forced-colors: active) {
    .grain { display: none; }
    .hero-em { color: LinkText; box-shadow: none; text-decoration: underline; }
    .btn, .tag, .card, .row, .post-nav-item, .media-card, .hero-proof {
      border: 1px solid ButtonBorder;
    }
    :focus-visible { outline: 3px solid Highlight; }
    .masthead-link.is-current::after { background: Highlight; }
  }

  /* ── print ───────────────────────────────────────────────────────── */
  @media print {
    .masthead, .colophon, .mobile-menu, .grain, .post-toc, .skip-link, .cta-row { display: none !important; }
    body { background: #fff; color: #000; }
    .prose a::after { content: " (" attr(href) ")"; font-size: 0.8em; word-break: break-all; }
    .code-block, .post-figure { break-inside: avoid; width: 100%; margin-inline: 0; }
  }
}
