/* ==========================================================================
   leoliebenberg.com — "Editorial Ink"
   Design system / CSS foundation. Dark ink base only. No light mode.
   Order: fonts → tokens → reset → base type → utilities → layout → components
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. FONTS  (self-hosted variable, /fonts/)
   -------------------------------------------------------------------------- */

@font-face {
  font-family: 'Clash Display';
  src: url('fonts/clash-display-var.woff2') format('woff2-variations'),
       url('fonts/clash-display-var.woff2') format('woff2');
  font-weight: 200 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2000-206F,
                 U+2074, U+20AC, U+2122, U+2191, U+2193, U+2192, U+2212, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Satoshi';
  src: url('fonts/satoshi-var.woff2') format('woff2-variations'),
       url('fonts/satoshi-var.woff2') format('woff2');
  font-weight: 300 900;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'JetBrains Mono';
  src: url('fonts/jetbrains-mono-var.woff2') format('woff2-variations'),
       url('fonts/jetbrains-mono-var.woff2') format('woff2');
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
}

/* Metric-matched fallbacks — kills the swap reflow (CLS) while the woff2 loads.
   Numbers are eyeballed against each face's real metrics; close enough that the
   line boxes don't jump. */
@font-face {
  font-family: 'Clash Fallback';
  src: local('Helvetica Neue'), local('Arial'), local('Roboto');
  size-adjust: 104%;
  ascent-override: 92%;
  descent-override: 24%;
  line-gap-override: 0%;
}
@font-face {
  font-family: 'Satoshi Fallback';
  src: local('Helvetica Neue'), local('Arial'), local('Roboto');
  size-adjust: 102%;
  ascent-override: 96%;
  descent-override: 24%;
  line-gap-override: 0%;
}
@font-face {
  font-family: 'Mono Fallback';
  src: local('SFMono-Regular'), local('Menlo'), local('Consolas'), local('Courier New');
  size-adjust: 100%;
  ascent-override: 92%;
  descent-override: 24%;
  line-gap-override: 0%;
}

/* --------------------------------------------------------------------------
   2. TOKENS
   Primitives first, semantic aliases second. Author against the SEMANTIC ones.
   -------------------------------------------------------------------------- */

:root {
  /* --- palette primitives (locked) --- */
  --ink:        #0B0B0F;
  --ink-2:      #131319;
  --ink-3:      #1C1C24;
  --bone:       #F5F0E8;
  --bone-dim:   #9A968E;
  --accent:     #3E9BFF;   /* azure — 6.86:1 on ink, AA as text AND as a fill */
  --accent-2:   #38BDF8;   /* sky — the evidence/data tone (9.17:1) */
  --logo:       var(--accent);   /* the mark follows the accent */

  /* channel forms, for alpha compositing without a colour library */
  --ink-rgb:       11 11 15;
  --bone-rgb:      245 240 232;
  --accent-rgb:   62 155 255;
  --accent-2-rgb: 56 189 248;

  /* derived tints — the only sanctioned way to get "in-between" colours */
  --bone-08:      rgb(var(--bone-rgb) / 0.08);
  --bone-14:      rgb(var(--bone-rgb) / 0.14);
  --bone-24:      rgb(var(--bone-rgb) / 0.24);
  --bone-60:      rgb(var(--bone-rgb) / 0.60);
  --accent-12: rgb(var(--accent-rgb) / 0.12);
  --accent-24: rgb(var(--accent-rgb) / 0.24);
  --accent-40: rgb(var(--accent-rgb) / 0.40);
  --accent-2-16:     rgb(var(--accent-2-rgb) / 0.16);
  --accent-2-32:     rgb(var(--accent-2-rgb) / 0.32);

  /* --- semantic colour --- */
  --bg:            var(--ink);
  --bg-raised:     var(--ink-2);
  --bg-sunken:     #08080B;         /* one step below base, for inset wells */
  --surface-hover: #17171F;
  --text:          var(--bone);
  --text-muted:    var(--bone-dim);   /* 6.6:1 on --ink — AA for body */
  --text-accent:   var(--accent);  /* 6.4:1 on --ink — AA, links/large only */
  --text-data:     var(--accent-2);      /* 8.1:1 on --ink */
  --accent-ink:    var(--ink);        /* text ON accent fills: 6.9:1 */
  --line:          var(--ink-3);
  --line-strong:   var(--bone-14);
  --focus:         var(--accent);
  --selection-bg:  var(--accent);
  --selection-fg:  var(--ink);

  /* --- type families --- */
  --font-display: 'Clash Display', 'Clash Fallback', ui-sans-serif, system-ui, sans-serif;
  --font-body:    'Satoshi', 'Satoshi Fallback', ui-sans-serif, system-ui, sans-serif;
  --font-mono:    'JetBrains Mono', 'Mono Fallback', ui-monospace, monospace;

  /* --- type scale (fluid, 320 → 1440 viewport; no media-query steps) --- */
  --step--2:  clamp(0.694rem, 0.68rem + 0.07vw,  0.75rem);
  --step--1:  clamp(0.833rem, 0.80rem + 0.16vw,  0.938rem);
  --step-0:   clamp(1rem,     0.95rem + 0.25vw,  1.125rem);   /* body */
  --step-1:   clamp(1.2rem,   1.12rem + 0.40vw,  1.5rem);
  --step-2:   clamp(1.44rem,  1.31rem + 0.65vw,  2rem);
  --step-3:   clamp(1.728rem, 1.52rem + 1.04vw,  2.625rem);
  --step-4:   clamp(2.074rem, 1.75rem + 1.62vw,  3.5rem);
  --step-5:   clamp(2.488rem, 1.99rem + 2.49vw,  4.625rem);
  --step-6:   clamp(2.986rem, 2.23rem + 3.78vw,  6.125rem);
  --step-7:   clamp(3.583rem, 2.44rem + 5.71vw,  8.125rem);   /* hero only */

  /* --- line-height --- */
  --lh-display: 0.95;   /* big Clash — set TIGHT */
  --lh-tight:   1.06;
  --lh-snug:    1.24;
  --lh-body:    1.6;
  --lh-loose:   1.75;

  /* --- tracking --- */
  --track-display: -0.035em;
  --track-head:    -0.02em;
  --track-body:    -0.005em;
  --track-mono:     0.14em;   /* eyebrows / labels */
  --track-mono-sm:  0.06em;   /* inline data, numbers */

  /* --- weights --- */
  --w-light: 300;
  --w-book:  400;
  --w-med:   500;
  --w-semi:  600;
  --w-bold:  700;

  /* --- measure --- */
  --measure:       65ch;
  --measure-short: 48ch;
  --measure-long:  76ch;

  /* --- spacing scale (fluid; each step grows ~1.15× from 320 → 1440) --- */
  --sp-3xs: clamp(0.25rem, 0.24rem + 0.05vw, 0.3125rem);
  --sp-2xs: clamp(0.5rem,  0.48rem + 0.11vw, 0.625rem);
  --sp-xs:  clamp(0.75rem, 0.71rem + 0.21vw, 0.9375rem);
  --sp-s:   clamp(1rem,    0.95rem + 0.25vw, 1.25rem);
  --sp-m:   clamp(1.5rem,  1.43rem + 0.38vw, 1.875rem);
  --sp-l:   clamp(2rem,    1.86rem + 0.71vw, 2.75rem);
  --sp-xl:  clamp(3rem,    2.71rem + 1.43vw, 4.5rem);
  --sp-2xl: clamp(4rem,    3.43rem + 2.86vw, 7rem);
  --sp-3xl: clamp(6rem,    5.14rem + 4.29vw, 10.5rem);
  --sp-4xl: clamp(8rem,    6.57rem + 7.14vw, 15rem);   /* between acts */

  /* --- radii — restrained. This is print, not a phone OS. --- */
  --r-0:    0px;
  --r-xs:   2px;
  --r-s:    4px;
  --r-m:    8px;
  --r-l:    14px;
  --r-pill: 999px;

  /* --- hairlines --- */
  --hair:        1px;
  --hairline:    var(--hair) solid var(--line);
  --hairline-2:  var(--hair) solid var(--line-strong);
  --hairline-hot: var(--hair) solid var(--accent-40);

  /* --- easing + duration --- */
  --ease-out:   cubic-bezier(0.16, 1, 0.30, 1);     /* the house curve */
  --ease-in:    cubic-bezier(0.55, 0, 1, 0.45);
  --ease-inout: cubic-bezier(0.65, 0, 0.35, 1);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --t-fast: 140ms;
  --t-base: 260ms;
  --t-slow: 520ms;
  --t-vslow: 900ms;

  /* --- elevation (light, warm, never a grey blur blob) --- */
  --shadow-1: 0 1px 0 rgb(var(--bone-rgb) / 0.04) inset,
              0 8px 24px -12px rgb(0 0 0 / 0.8);
  --shadow-2: 0 1px 0 rgb(var(--bone-rgb) / 0.05) inset,
              0 24px 60px -24px rgb(0 0 0 / 0.9);
  --glow-accent: 0 0 0 1px var(--accent-40),
                 0 12px 40px -16px rgb(var(--accent-rgb) / 0.45);

  /* --- layout --- */
  --gutter:        clamp(1.25rem, 1rem + 2vw, 3rem);
  --container:     78rem;   /* 1248px — main reading/content width */
  --container-wide: 96rem;  /* 1536px — full-bleed-ish editorial rows */
  --container-narrow: 44rem;
  --grid-cols: 12;
  --grid-gap:  clamp(1rem, 0.6rem + 1.6vw, 2rem);
  --nav-h:     clamp(3.75rem, 3.4rem + 1.6vw, 5rem);

  /* --- z layers --- */
  --z-bg:       -1;
  --z-base:      0;
  --z-raised:    10;
  --z-sticky:    100;
  --z-nav:       200;
  --z-menu:      300;
  --z-overlay:   400;
  --z-toast:     500;
  --z-cursor:    9999;
}

/* --------------------------------------------------------------------------
   3. RESET
   -------------------------------------------------------------------------- */

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

* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--nav-h) + var(--sp-m));
  /* nothing may push the page sideways */
  overflow-x: clip;
}

body {
  min-height: 100svh;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--step-0);
  font-weight: var(--w-book);
  line-height: var(--lh-body);
  letter-spacing: var(--track-body);
  font-optical-sizing: auto;
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  overflow-x: clip;
}

img, picture, video, canvas, svg { display: block; max-width: 100%; height: auto; }
img { background: var(--ink-2); }   /* no white flash before decode */

input, button, textarea, select { font: inherit; color: inherit; }

p, h1, h2, h3, h4, h5, h6, li, figcaption, blockquote {
  overflow-wrap: break-word;
  hyphens: manual;
}

ul[role='list'], ol[role='list'] { list-style: none; padding: 0; }

hr { border: 0; }

::selection { background: var(--selection-bg); color: var(--selection-fg); }

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: var(--bg); }
::-webkit-scrollbar-thumb { background: var(--ink-3); border: 2px solid var(--bg); border-radius: var(--r-pill); }
::-webkit-scrollbar-thumb:hover { background: var(--bone-24); }

/* The WebGL backdrop from bg.js */
#bg {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: var(--z-bg);
  pointer-events: none;
}

/* --------------------------------------------------------------------------
   4. TYPE
   Clash = display. Satoshi = body. JetBrains = the credibility layer.
   -------------------------------------------------------------------------- */

h1, h2, h3, h4, .display, .h1, .h2, .h3, .h4 {
  font-family: var(--font-display);
  font-weight: var(--w-med);
  line-height: var(--lh-tight);
  letter-spacing: var(--track-head);
  text-wrap: balance;
  /* optical: Clash's left sidebearing is generous — pull big type back to the grid */
  margin-left: -0.015em;
}

.display, .h1, h1 {
  font-size: var(--step-6);
  font-weight: var(--w-med);
  line-height: var(--lh-display);
  letter-spacing: var(--track-display);
  margin-left: -0.03em;
}

/* the one true hero: bigger, tighter, lighter — it should feel drawn, not typed */
.display--hero {
  font-size: var(--step-7);
  font-weight: var(--w-light);
  line-height: 0.92;
  letter-spacing: -0.045em;
  text-wrap: pretty;
}

.h2, h2 { font-size: var(--step-4); line-height: 0.98; letter-spacing: -0.03em; }
.h3, h3 { font-size: var(--step-3); line-height: 1.05; }
.h4, h4 { font-size: var(--step-2); line-height: 1.15; letter-spacing: -0.015em; }
h5, h6  { font-family: var(--font-body); font-size: var(--step-1); font-weight: var(--w-semi); letter-spacing: -0.01em; margin-left: 0; }

/* italic-substitute: Clash has no italic. Emphasis in headlines = the accent tone, not slant. */
h1 em, h2 em, h3 em, .display em {
  font-style: normal;
  color: var(--accent-2);
  font-weight: var(--w-light);
}

p { max-inline-size: var(--measure); }

.lead {
  font-size: var(--step-1);
  line-height: 1.45;
  color: var(--bone);
  font-weight: var(--w-light);
  letter-spacing: -0.012em;
  max-inline-size: var(--measure-short);
  text-wrap: pretty;
}

.prose > * + * { margin-block-start: var(--sp-s); }
.prose > * + h2, .prose > * + h3 { margin-block-start: var(--sp-l); }
.prose p { color: var(--text-muted); }
.prose strong { color: var(--text); font-weight: var(--w-semi); }
.prose a { color: var(--text); text-decoration-color: var(--accent); }

.muted   { color: var(--text-muted); }
.measure { max-inline-size: var(--measure); }
.measure-short { max-inline-size: var(--measure-short); }
.balance { text-wrap: balance; }

/* --- MONO LAYER — eyebrows, labels, data, metadata. Used deliberately. --- */

.eyebrow,
.label,
.meta,
.mono {
  font-family: var(--font-mono);
  font-variant-ligatures: none;
  font-feature-settings: 'tnum' 1, 'zero' 1;
}

/* the section kicker: mono, uppercase, wide, small, with a rule that leads into it */
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2xs);
  font-size: var(--step--2);
  font-weight: var(--w-med);
  letter-spacing: var(--track-mono);
  text-transform: uppercase;
  color: var(--text-muted);
  line-height: 1;
}
.eyebrow::before {
  content: '';
  inline-size: clamp(1.25rem, 3vw, 2.5rem);
  block-size: var(--hair);
  background: var(--accent);
  flex: none;
}
.eyebrow--hot   { color: var(--accent); }
.eyebrow--alt { color: var(--accent-2); }
.eyebrow--alt::before { background: var(--accent-2); }
.eyebrow--bare::before  { display: none; }

/* numbered section marker: "03 / SELECTED WORK" */
.eyebrow[data-index]::after {
  content: attr(data-index);
  color: var(--bone-60);
}

.label {
  font-size: var(--step--2);
  font-weight: var(--w-med);
  letter-spacing: var(--track-mono);
  text-transform: uppercase;
  color: var(--text-muted);
  line-height: 1.2;
}

.meta {
  font-size: var(--step--1);
  letter-spacing: var(--track-mono-sm);
  color: var(--text-muted);
  line-height: 1.4;
}

.mono-num {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  letter-spacing: var(--track-mono-sm);
  color: var(--accent-2);
}

code, kbd, samp, pre {
  font-family: var(--font-mono);
  font-size: 0.9em;
  letter-spacing: 0;
}
:not(pre) > code {
  background: var(--ink-2);
  border: var(--hairline);
  border-radius: var(--r-xs);
  padding: 0.12em 0.4em;
  color: var(--accent-2);
}
pre {
  background: var(--bg-sunken);
  border: var(--hairline);
  border-radius: var(--r-m);
  padding: var(--sp-s);
  overflow-x: auto;
  line-height: 1.6;
}

/* --------------------------------------------------------------------------
   5. A11Y UTILITIES
   -------------------------------------------------------------------------- */

.visually-hidden:not(:focus):not(:active) {
  position: absolute !important;
  inline-size: 1px;
  block-size: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
  border-radius: var(--r-xs);
}
/* mouse users don't get the ring; keyboard users always do */
:focus:not(:focus-visible) { outline: none; }

.skip-link {
  position: fixed;
  top: var(--sp-2xs);
  left: var(--sp-2xs);
  z-index: var(--z-toast);
  transform: translateY(calc(-100% - var(--sp-l)));
  padding: var(--sp-xs) var(--sp-s);
  background: var(--accent);
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: var(--step--2);
  font-weight: var(--w-bold);
  letter-spacing: var(--track-mono);
  text-transform: uppercase;
  text-decoration: none;
  border-radius: var(--r-s);
  transition: transform var(--t-base) var(--ease-out);
}
.skip-link:focus-visible {
  transform: translateY(0);
  outline-offset: 2px;
  outline-color: var(--bone);
}

/* --------------------------------------------------------------------------
   6. LAYOUT
   Container → grid → editorial (asymmetric) rows.
   -------------------------------------------------------------------------- */

.container {
  inline-size: 100%;
  max-inline-size: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.container--wide   { max-inline-size: var(--container-wide); }
.container--narrow { max-inline-size: var(--container-narrow); }
.container--flush  { padding-inline: 0; }   /* only inside an already-padded parent */

.section       { padding-block: var(--sp-3xl); }
.section--tight{ padding-block: var(--sp-2xl); }
.section--act  { padding-block: var(--sp-4xl); }   /* between the big movements */
.section--flush-top { padding-block-start: 0; }

/* raised / inset section — breaks the flat black, cheap and effective */
.section--raised {
  background: var(--bg-raised);
  border-block: var(--hairline);
}
.section--sunken { background: var(--bg-sunken); }

/* --- the grid: 12 cols on desktop, 4 on phone, no media-query cliff --- */
.grid {
  display: grid;
  grid-template-columns: repeat(var(--grid-cols), minmax(0, 1fr));
  gap: var(--grid-gap);
}
@media (max-width: 47.99em) {
  .grid { --grid-cols: 4; }
}

/* span helpers — collapse to full width on small screens automatically */
[class*='col-'] { grid-column: 1 / -1; }
@media (min-width: 48em) {
  .col-1  { grid-column: span 1; }  .col-2  { grid-column: span 2; }
  .col-3  { grid-column: span 3; }  .col-4  { grid-column: span 4; }
  .col-5  { grid-column: span 5; }  .col-6  { grid-column: span 6; }
  .col-7  { grid-column: span 7; }  .col-8  { grid-column: span 8; }
  .col-9  { grid-column: span 9; }  .col-10 { grid-column: span 10; }
  .col-12 { grid-column: 1 / -1; }
  .start-2 { grid-column-start: 2; } .start-3 { grid-column-start: 3; }
  .start-4 { grid-column-start: 4; } .start-5 { grid-column-start: 5; }
  .start-6 { grid-column-start: 6; } .start-7 { grid-column-start: 7; }
  .start-8 { grid-column-start: 8; }
}

/* auto-fit card grid, no breakpoints needed */
.grid-auto {
  display: grid;
  gap: var(--grid-gap);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
}

/* --- EDITORIAL ROWS — the rhythm system. Never the same shape twice. ---
   Use them in sequence, e.g. row--offset → row--stack → row--split → row--ledger.
   Each is a distinct silhouette so no two sections read alike. */

/* (a) offset: narrow label rail + wide body, the body starts INSIDE the grid */
.row--offset {
  display: grid;
  gap: var(--grid-gap);
  grid-template-columns: 1fr;
}
@media (min-width: 48em) {
  .row--offset { grid-template-columns: minmax(0, 3fr) minmax(0, 8fr); column-gap: calc(var(--grid-gap) * 2); }
  .row--offset > :first-child { position: sticky; top: calc(var(--nav-h) + var(--sp-m)); align-self: start; }
}

/* (b) stack: headline hangs LEFT of the content well, text drops below-right.
   This is the deliberate grid-break #1 — the heading escapes the text column. */
.row--stack { display: grid; gap: var(--sp-m); grid-template-columns: 1fr; }
@media (min-width: 62em) {
  .row--stack { grid-template-columns: repeat(12, minmax(0, 1fr)); row-gap: var(--sp-l); }
  .row--stack > .row__head { grid-column: 1 / 9; }
  .row--stack > .row__body { grid-column: 6 / 12; }   /* overlaps the head column */
  .row--stack > .row__aside { grid-column: 1 / 5; align-self: end; }
}

/* (c) split: image bleeds off ONE edge. Deliberate grid-break #2. */
.row--bleed { display: grid; gap: var(--sp-l); grid-template-columns: 1fr; }
@media (min-width: 62em) {
  .row--bleed {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    align-items: center;
    column-gap: var(--sp-2xl);
  }
  /* pull the media past the container edge into the viewport margin */
  .row--bleed > .row__media {
    margin-inline-end: calc(var(--gutter) * -1 - (100vw - min(100vw, var(--container))) / 2);
  }
  .row--bleed.row--bleed-left > .row__media {
    order: -1;
    margin-inline-end: 0;
    margin-inline-start: calc(var(--gutter) * -1 - (100vw - min(100vw, var(--container))) / 2);
  }
}

/* (d) ledger: mono data column pinned right, prose left — reads like a spec sheet */
.row--ledger { display: grid; gap: var(--sp-l); grid-template-columns: 1fr; }
@media (min-width: 48em) {
  .row--ledger {
    grid-template-columns: minmax(0, 7fr) minmax(0, 4fr);
    column-gap: var(--sp-2xl);
    align-items: start;
  }
  .row--ledger > :last-child { border-inline-start: var(--hairline); padding-inline-start: var(--sp-m); }
}

/* full-bleed escape hatches. `.bleed` goes edge-to-edge of the viewport (safe:
   html has overflow-x: clip, so a scrollbar can never make 100vw overflow).
   `.full-bleed` only cancels the container's gutter. */
.bleed {
  margin-inline: calc(50% - 50vw);
  inline-size: 100vw;
  max-inline-size: 100vw;
}
.full-bleed {
  margin-inline: calc(var(--gutter) * -1);
  inline-size: calc(100% + var(--gutter) * 2);
}

.stack > * + * { margin-block-start: var(--flow, var(--sp-s)); }
.stack-l > * + * { margin-block-start: var(--sp-l); }
.cluster { display: flex; flex-wrap: wrap; gap: var(--sp-xs); align-items: center; }

/* --------------------------------------------------------------------------
   7. COMPONENTS
   -------------------------------------------------------------------------- */

/* --- 7.1 Buttons ------------------------------------------------------ */

.btn {
  --btn-bg: transparent;
  --btn-fg: var(--text);
  --btn-bd: var(--line-strong);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2xs);
  min-block-size: 48px;                 /* > 44px tap target */
  padding-inline: var(--sp-m);
  padding-block: var(--sp-2xs);
  background: var(--btn-bg);
  color: var(--btn-fg);
  border: var(--hair) solid var(--btn-bd);
  border-radius: var(--r-pill);
  font-family: var(--font-mono);
  font-size: var(--step--2);
  font-weight: var(--w-med);
  letter-spacing: var(--track-mono);
  text-transform: uppercase;
  text-decoration: none;
  line-height: 1;
  cursor: pointer;
  white-space: nowrap;
  transition:
    background-color var(--t-fast) var(--ease-out),
    border-color var(--t-fast) var(--ease-out),
    color var(--t-fast) var(--ease-out),
    transform var(--t-fast) var(--ease-out),
    box-shadow var(--t-base) var(--ease-out);
}
.btn:hover { transform: translateY(-1px); }
.btn:active { transform: translateY(1px) scale(0.985); transition-duration: 60ms; }
.btn:focus-visible { outline: 2px solid var(--focus); outline-offset: 3px; }
.btn[disabled], .btn[aria-disabled='true'] {
  opacity: 0.45; pointer-events: none; transform: none;
}

/* primary — azure fill, ink text (6.9:1, AA) */
.btn--primary {
  --btn-bg: var(--accent);
  --btn-fg: var(--ink);
  --btn-bd: var(--accent);
  font-weight: var(--w-bold);
}
.btn--primary:hover  { --btn-bg: #5FB0FF; --btn-bd: #5FB0FF; box-shadow: var(--glow-accent); }
.btn--primary:active { --btn-bg: #2B84DB; --btn-bd: #2B84DB; box-shadow: none; }
.btn--primary:focus-visible { outline-offset: 4px; }

/* ghost — hairline outline, fills on hover */
.btn--ghost:hover  { --btn-bg: var(--bone-08); --btn-bd: var(--bone); }
.btn--ghost:active { --btn-bg: var(--bone-14); }

/* text/arrow link — the tertiary action. Underline grows, arrow steps out. */
.btn--text {
  --btn-bd: transparent;
  min-block-size: 44px;
  padding-inline: 0;
  border-radius: var(--r-xs);
  color: var(--text);
  position: relative;
}
.btn--text::after {
  content: '→';
  font-family: var(--font-mono);
  transition: transform var(--t-base) var(--ease-out);
}
.btn--text::before {
  content: '';
  position: absolute;
  inset-block-end: 10px;
  inset-inline: 0 1.4em;
  block-size: var(--hair);
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform var(--t-base) var(--ease-out);
}
.btn--text:hover { color: var(--accent); transform: none; }
.btn--text:hover::before { transform: scaleX(1); }
.btn--text:hover::after  { transform: translateX(4px); }
.btn--text:active { transform: none; opacity: 0.7; }

.btn--sm { min-block-size: 44px; padding-inline: var(--sp-s); font-size: var(--step--2); }
.btn--block { display: flex; inline-size: 100%; }

/* --- 7.2 Inline links (body copy) ------------------------------------- */
/* NOTE: body links stay BONE with an azure underline — accent text at
   16px on ink measures 6.4:1 (passes AA) but vibrates optically at long lengths.
   Colour is the hover state, not the resting state. */
a:not([class]) {
  color: var(--text);
  text-decoration: underline;
  text-decoration-color: var(--accent-40);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.22em;
  transition: color var(--t-fast) var(--ease-out),
              text-decoration-color var(--t-fast) var(--ease-out);
}
a:not([class]):hover { color: var(--accent); text-decoration-color: var(--accent); }

/* --- 7.3 Hairline divider --------------------------------------------- */

.rule {
  block-size: var(--hair);
  background: var(--line);
  border: 0;
  inline-size: 100%;
}
/* a rule with an accent tick at its origin — the house signature */
.rule--tick {
  background: linear-gradient(90deg,
    var(--accent) 0 clamp(1.5rem, 4vw, 3rem),
    var(--line) clamp(1.5rem, 4vw, 3rem));
}
.rule--fade {
  background: linear-gradient(90deg, var(--line-strong), transparent);
}
.rule--vert { inline-size: var(--hair); block-size: 100%; }

/* --- 7.4 Cards --------------------------------------------------------- */

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--sp-xs);
  padding: var(--sp-m);
  background: var(--bg-raised);
  border: var(--hairline);
  border-radius: var(--r-l);
  transition: border-color var(--t-base) var(--ease-out),
              background-color var(--t-base) var(--ease-out),
              transform var(--t-base) var(--ease-out);
}
.card__title { font-family: var(--font-display); font-size: var(--step-2); line-height: 1.1; letter-spacing: -0.02em; }
.card__body  { color: var(--text-muted); font-size: var(--step-0); }
.card__foot  { margin-block-start: auto; padding-block-start: var(--sp-s); border-block-start: var(--hairline); }

/* interactive card — whole surface clickable via a stretched link */
.card--link:hover {
  border-color: var(--bone-24);
  background: var(--surface-hover);
  transform: translateY(-2px);
}
.card--link:has(a:focus-visible) { border-color: var(--accent); }
.card--link .stretch::after { content: ''; position: absolute; inset: 0; border-radius: inherit; }
.card--link .stretch:focus-visible { outline: none; }

/* numbered card — mono index in the corner, editorial */
.card--num::before {
  content: attr(data-num);
  position: absolute;
  inset-block-start: var(--sp-s);
  inset-inline-end: var(--sp-s);
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: var(--track-mono);
  color: var(--bone-60);
}
/* accent card — azure top hairline instead of a coloured background */
.card--hot { border-block-start-color: var(--accent); }

/* --- 7.5 Tags / chips -------------------------------------------------- */

.tag {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3xs);
  padding: 0.4em 0.75em;
  font-family: var(--font-mono);
  font-size: var(--step--2);
  font-weight: var(--w-med);
  letter-spacing: var(--track-mono-sm);
  text-transform: uppercase;
  color: var(--text-muted);
  background: var(--ink-2);
  border: var(--hairline);
  border-radius: var(--r-s);
  line-height: 1.2;
  white-space: nowrap;
}
.tag--hot   { color: var(--accent); border-color: var(--accent-24); background: var(--accent-12); }
.tag--alt { color: var(--accent-2);     border-color: var(--accent-2-32);     background: var(--accent-2-16); }
/* live/status chip */
.tag--live::before {
  content: '';
  inline-size: 6px; block-size: 6px;
  border-radius: 50%;
  background: currentColor;
  box-shadow: 0 0 0 3px rgb(var(--accent-rgb) / 0.18);
}
a.tag { text-decoration: none; transition: color var(--t-fast) var(--ease-out), border-color var(--t-fast) var(--ease-out); }
a.tag:hover { color: var(--text); border-color: var(--bone-24); }

/* --- 7.6 Data row (mono) ----------------------------------------------- */
/* The spec-sheet component. Label left, value right, dotted leader between.
   This is what makes the page read "engineer" instead of "agency". */

.data-list { display: flex; flex-direction: column; }

.data-row {
  display: flex;
  align-items: baseline;
  gap: var(--sp-2xs);
  padding-block: var(--sp-xs);
  border-block-end: var(--hairline);
  font-family: var(--font-mono);
  font-size: var(--step--1);
  letter-spacing: var(--track-mono-sm);
}
.data-row:first-child { border-block-start: var(--hairline); }
.data-row__key {
  flex: none;
  text-transform: uppercase;
  letter-spacing: var(--track-mono);
  font-size: var(--step--2);
  color: var(--text-muted);
}
.data-row__dots {
  flex: 1 1 auto;
  min-inline-size: var(--sp-s);
  align-self: center;
  block-size: var(--hair);
  background-image: linear-gradient(90deg, var(--line-strong) 25%, transparent 25%);
  background-size: 4px var(--hair);
  opacity: 0.6;
}
.data-row__val {
  flex: none;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  text-align: end;
}
.data-row__val--hot   { color: var(--accent); }
.data-row__val--alt { color: var(--accent-2); }

/* below 24rem the key/value pair stacks rather than squeezing */
@media (max-width: 26em) {
  .data-row { flex-wrap: wrap; }
  .data-row__dots { display: none; }
  .data-row__val { flex: 1 0 100%; text-align: start; }
}

/* --- 7.7 Blockquote / pull-quote --------------------------------------- */

blockquote, .quote {
  margin: 0;
  padding-inline-start: var(--sp-m);
  border-inline-start: 2px solid var(--accent);
  font-family: var(--font-body);
  font-size: var(--step-1);
  font-weight: var(--w-light);
  line-height: 1.5;
  letter-spacing: -0.01em;
  color: var(--text);
  max-inline-size: var(--measure-short);
}
blockquote cite, .quote cite {
  display: block;
  margin-block-start: var(--sp-s);
  font-family: var(--font-mono);
  font-size: var(--step--2);
  font-style: normal;
  letter-spacing: var(--track-mono);
  text-transform: uppercase;
  color: var(--text-muted);
}

/* the real editorial move: a display-size pull-quote with a hanging mark.
   It sits OUTSIDE the text measure and breaks the column on purpose. */
.pullquote {
  position: relative;
  border: 0;
  padding: 0;
  margin-block: var(--sp-xl);
  font-family: var(--font-display);
  font-weight: var(--w-light);
  font-size: var(--step-4);
  line-height: 1.05;
  letter-spacing: -0.03em;
  text-wrap: balance;
  max-inline-size: 22ch;
  color: var(--bone);
}
.pullquote::before {
  content: '\201C';
  position: absolute;
  inset-inline-start: -0.5em;
  inset-block-start: -0.12em;
  color: var(--accent);
  font-size: 1.4em;
  line-height: 1;
  pointer-events: none;
}
@media (max-width: 47.99em) {
  /* on phones the hanging mark would overflow — bring it inline */
  .pullquote { padding-inline-start: 0.6em; }
  .pullquote::before { inset-inline-start: -0.05em; }
}
.pullquote cite {
  display: block;
  margin-block-start: var(--sp-m);
  font-family: var(--font-mono);
  font-size: var(--step--2);
  font-style: normal;
  letter-spacing: var(--track-mono);
  text-transform: uppercase;
  color: var(--accent-2);
}

/* --- 7.8 Figure + caption ---------------------------------------------- */

figure { margin: 0; }
.figure { display: flex; flex-direction: column; gap: var(--sp-xs); }
.figure img {
  inline-size: 100%;
  border-radius: var(--r-m);
  border: var(--hairline);
}
.figure figcaption,
.caption {
  display: flex;
  gap: var(--sp-2xs);
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: var(--track-mono-sm);
  line-height: 1.5;
  color: var(--text-muted);
  max-inline-size: 44ch;
}
/* mono index prefix: "FIG. 01 —" */
.figure figcaption::before,
.caption::before {
  content: attr(data-fig);
  flex: none;
  color: var(--accent);
  text-transform: uppercase;
  letter-spacing: var(--track-mono);
}
.figure--frame img { padding: var(--sp-2xs); background: var(--ink-2); }

/* --- 7.9 Nav ----------------------------------------------------------- */

.nav {
  position: fixed;
  inset-block-start: 0;
  inset-inline: 0;
  z-index: var(--z-nav);
  block-size: var(--nav-h);
  display: flex;
  align-items: center;
  border-block-end: var(--hair) solid transparent;
  transition: background-color var(--t-base) var(--ease-out),
              border-color var(--t-base) var(--ease-out),
              backdrop-filter var(--t-base) var(--ease-out);
}
/* .is-stuck is toggled by JS on scroll (or drop it and keep the nav always solid) */
.nav.is-stuck {
  background: rgb(var(--ink-rgb) / 0.72);
  backdrop-filter: blur(14px) saturate(1.2);
  -webkit-backdrop-filter: blur(14px) saturate(1.2);
  border-block-end-color: var(--line);
}

.nav__inner {
  inline-size: 100%;
  max-inline-size: var(--container-wide);
  margin-inline: auto;
  padding-inline: var(--gutter);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-m);
}

.nav__brand {
  display: inline-flex;
  align-items: baseline;
  gap: 0.5ch;
  font-family: var(--font-display);
  font-size: var(--step-0);
  font-weight: var(--w-semi);
  letter-spacing: -0.02em;
  color: var(--text);
  text-decoration: none;
  white-space: nowrap;
}
.nav__brand span { font-family: var(--font-mono); font-size: 0.7em; letter-spacing: var(--track-mono); color: var(--accent); }

.nav__links {
  display: none;                /* mobile-first: hidden until the menu breakpoint */
  align-items: center;
  gap: var(--sp-m);
  list-style: none;
  margin: 0; padding: 0;
}
.nav__link {
  position: relative;
  display: inline-flex;
  align-items: center;
  min-block-size: 44px;
  font-family: var(--font-mono);
  font-size: var(--step--2);
  font-weight: var(--w-med);
  letter-spacing: var(--track-mono);
  text-transform: uppercase;
  color: var(--text-muted);
  text-decoration: none;
  transition: color var(--t-fast) var(--ease-out);
}
.nav__link::after {
  content: '';
  position: absolute;
  inset-block-end: 10px;
  inset-inline: 0;
  block-size: var(--hair);
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform var(--t-base) var(--ease-out);
}
.nav__link:hover,
.nav__link.is-active { color: var(--text); }
.nav__link:hover::after,
.nav__link.is-active::after { transform: scaleX(1); }

/* hamburger — a real 48px target, two lines that become an X */
.nav__toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: 48px;
  block-size: 48px;
  margin-inline-end: -12px;      /* optical: pull the icon flush to the gutter */
  background: none;
  border: 0;
  border-radius: var(--r-s);
  cursor: pointer;
  color: var(--text);
}
.nav__toggle-box { position: relative; inline-size: 22px; block-size: 12px; }
.nav__toggle-box::before,
.nav__toggle-box::after {
  content: '';
  position: absolute;
  inset-inline: 0;
  block-size: 1.5px;
  background: currentColor;
  transition: transform var(--t-base) var(--ease-out), inset-block-start var(--t-fast) var(--ease-out);
}
.nav__toggle-box::before { inset-block-start: 0; }
.nav__toggle-box::after  { inset-block-start: 10px; }
.nav__toggle[aria-expanded='true'] .nav__toggle-box::before { inset-block-start: 5px; transform: rotate(45deg); }
.nav__toggle[aria-expanded='true'] .nav__toggle-box::after  { inset-block-start: 5px; transform: rotate(-45deg); }

/* mobile menu — full-screen ink sheet, staggered items */
.nav__menu {
  position: fixed;
  inset: 0;
  z-index: var(--z-menu);
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--sp-s);
  padding: calc(var(--nav-h) + var(--sp-l)) var(--gutter) var(--sp-xl);
  background: var(--ink);
  overflow-y: auto;
  overscroll-behavior: contain;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-8px);
  transition: opacity var(--t-base) var(--ease-out),
              transform var(--t-base) var(--ease-out),
              visibility 0s linear var(--t-base);
}
.nav__menu[data-open='true'] {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition-delay: 0s;
}
.nav__menu ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.nav__menu li { border-block-end: var(--hairline); }
.nav__menu li:first-child { border-block-start: var(--hairline); }
.nav__menu a {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-s);
  min-block-size: 64px;
  padding-block: var(--sp-xs);
  font-family: var(--font-display);
  font-size: var(--step-3);
  font-weight: var(--w-med);
  letter-spacing: -0.025em;
  color: var(--text);
  text-decoration: none;
  transition: color var(--t-fast) var(--ease-out), padding-inline-start var(--t-base) var(--ease-out);
}
.nav__menu a::after {
  content: attr(data-num);
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: var(--track-mono);
  color: var(--bone-60);
}
.nav__menu a:hover,
.nav__menu a:focus-visible { color: var(--accent); padding-inline-start: var(--sp-2xs); }
.nav__menu-foot { margin-block-start: var(--sp-l); }

/* lock the page while the sheet is open (JS adds .is-locked to <body>) */
body.is-locked { overflow: hidden; }

@media (min-width: 56em) {
  .nav__links  { display: flex; }
  .nav__toggle { display: none; }
  .nav__menu   { display: none; }
}

/* --- 7.10 Footer -------------------------------------------------------- */

.footer {
  border-block-start: var(--hairline);
  padding-block: var(--sp-2xl) var(--sp-l);
  background: var(--bg-sunken);
}
.footer__grid {
  display: grid;
  gap: var(--sp-xl) var(--grid-gap);
  grid-template-columns: 1fr;
}
@media (min-width: 48em) {
  .footer__grid { grid-template-columns: minmax(0, 5fr) minmax(0, 3fr) minmax(0, 3fr); }
}
.footer__cta {
  font-family: var(--font-display);
  font-size: var(--step-4);
  font-weight: var(--w-light);
  line-height: 1;
  letter-spacing: -0.035em;
  text-decoration: none;
  color: var(--text);
  display: inline-block;
  transition: color var(--t-base) var(--ease-out);
}
.footer__cta:hover { color: var(--accent); }
.footer__col { display: flex; flex-direction: column; gap: var(--sp-2xs); align-items: flex-start; }
.footer__col a {
  min-block-size: 44px;
  display: inline-flex;
  align-items: center;
  font-family: var(--font-mono);
  font-size: var(--step--1);
  letter-spacing: var(--track-mono-sm);
  color: var(--text-muted);
  text-decoration: none;
  transition: color var(--t-fast) var(--ease-out);
}
.footer__col a:hover { color: var(--accent); }
.footer__bottom {
  margin-block-start: var(--sp-xl);
  padding-block-start: var(--sp-s);
  border-block-start: var(--hairline);
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-xs) var(--sp-m);
  justify-content: space-between;
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: var(--track-mono-sm);
  color: var(--bone-60);
}

/* --- 7.11 Misc ---------------------------------------------------------- */

/* scroll progress rail (motion.js drives [data-progress]) */
.progress {
  position: fixed;
  inset-block-start: 0;
  inset-inline: 0;
  block-size: 2px;
  z-index: var(--z-toast);
  background: var(--accent);
  pointer-events: none;
}

/* mono marquee/ticker strip — CVE-feed energy without the noise */
.strip {
  display: flex;
  gap: var(--sp-m);
  align-items: center;
  padding-block: var(--sp-xs);
  border-block: var(--hairline);
  font-family: var(--font-mono);
  font-size: var(--step--2);
  letter-spacing: var(--track-mono);
  text-transform: uppercase;
  color: var(--text-muted);
  overflow-x: auto;
  scrollbar-width: none;
}
.strip::-webkit-scrollbar { display: none; }
.strip > * { flex: none; }

/* --------------------------------------------------------------------------
   8. MOTION — reduce
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    transition-delay: 0s !important;
    scroll-behavior: auto !important;
  }
  /* anything motion.js hid pre-reveal must still be visible */
  [data-reveal], [data-split], .nav__menu[data-open='true'] {
    opacity: 1 !important;
    transform: none !important;
    clip-path: none !important;
  }
  .btn:hover, .card--link:hover { transform: none; }
}

/* ==========================================================================
   8. PAGE PARTS — hero, brand mark, nav CTA, footer links
   Added after the system: these are the compositions, not the primitives.
   ========================================================================== */

/* --- 8.1 The hero --------------------------------------------------------
   Mobile: a single honest column.
   >=64em: a deliberate grid break — the name runs wide, the portrait hangs
   into its right shoulder, and the body text sits under the name's left edge.
   The overlap is the whole point; don't "fix" it back into two tidy columns. */

.hero {
  position: relative;
  padding-block-start: calc(var(--nav-h) + var(--sp-2xl));
  padding-block-end: var(--sp-3xl);
}

.hero__eyebrow { margin-block-end: var(--sp-m); }

.hero__title {
  margin-block-end: var(--sp-s);
  /* the name is the loudest thing on the site — let it breathe to the edges */
  max-inline-size: 14ch;
}

.hero__role {
  color: var(--accent);
  margin-block-end: var(--sp-l);
}

.hero__hook {
  font-family: var(--font-display);
  font-weight: var(--w-med);
  font-size: var(--step-2);
  line-height: 1.1;
  letter-spacing: -0.02em;
  color: var(--text);
  margin-block-start: var(--sp-xs);
  text-wrap: balance;
}

.hero__cta { margin-block-start: var(--sp-l); }

.hero__figure {
  margin-block-start: var(--sp-xl);
  margin-inline: 0;
}
.hero__figure img {
  inline-size: 100%;
  block-size: auto;
  border-radius: var(--r-l);
  border: var(--hairline);
  /* the stage photo is very dark; lift it just enough to read on ink */
  filter: contrast(1.04) brightness(1.06);
}

@media (min-width: 64em) {
  .hero .container {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    column-gap: var(--grid-gap);
    align-items: start;
  }
  .hero__eyebrow { grid-column: 1 / -1; }

  .hero__title  { grid-column: 1 / 9;  max-inline-size: none; }
  .hero__role   { grid-column: 1 / 8; }
  .hero__body   { grid-column: 1 / 7; }

  /* the grid break: pull the portrait up into the headline's shoulder */
  .hero__figure {
    grid-column: 8 / -1;
    grid-row: 2 / span 3;
    margin-block-start: calc(var(--sp-xl) * -1);
    z-index: 1;
  }
}

@media (min-width: 80em) {
  .hero__figure { grid-column: 9 / -1; }
}

/* --- 8.2 Brand mark ------------------------------------------------------ */

.brand-mark,
.nav__brand svg {
  flex: none;
  color: var(--logo);
  transition: color var(--t-base) var(--ease-out), transform var(--t-base) var(--ease-out);
}
.nav__brand:hover svg { transform: translateY(-1px); }

/* --- 8.3 Nav CTA ---------------------------------------------------------
   Hidden on mobile: the hamburger sheet already carries the actions, and two
   competing CTAs in a 375px bar is how you get a 40px tap target. */
.nav__cta { display: none; }
@media (min-width: 56em) { .nav__cta { display: inline-flex; } }

/* --- 8.4 Footer links ---------------------------------------------------- */

.footer__links {
  list-style: none;
  margin: var(--sp-xs) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-3xs, 0.375rem);
}
.footer__links a {
  display: inline-flex;
  align-items: center;
  min-block-size: 32px;
  color: var(--text-muted);
  text-decoration: none;
  transition: color var(--t-fast) var(--ease-out);
}
.footer__links a:hover { color: var(--accent); }

.footer__fine {
  margin-block-start: var(--sp-2xl);
  padding-block-start: var(--sp-m);
  border-block-start: var(--hairline);
  color: var(--text-muted);
}

/* --- 8.5 The pinned sequence --------------------------------------------
   [data-pin] is a tall scroll track. Its [data-pin-inner] sticks to the
   viewport while the track passes, and motion.js writes --p (0..1) on the
   track and toggles .is-active on each [data-step].
   No-JS / reduced-motion: every step is .is-active, the track collapses to
   auto height, and it reads as a plain numbered list. That is the point. */

.pin { position: relative; }

.pin__inner {
  position: sticky;
  inset-block-start: var(--nav-h);
  min-block-size: calc(100svh - var(--nav-h));
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding-block: var(--sp-xl);
}

/* the track only needs its extra height when JS is actually scrubbing it */
.motion .pin { block-size: 320svh; }
.motion .pin__inner { block-size: calc(100svh - var(--nav-h)); }
html.reduce .pin,
html:not(.motion) .pin { block-size: auto; }
html.reduce .pin__inner,
html:not(.motion) .pin__inner { position: static; block-size: auto; min-block-size: 0; }

.pin__rail {
  block-size: var(--hair);
  background: var(--line);
  margin-block-end: var(--sp-l);
  position: relative;
  overflow: hidden;
}
.pin__rail::after {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--accent);
  transform: scaleX(var(--p, 0));
  transform-origin: 0 50%;
}
html.reduce .pin__rail::after,
html:not(.motion) .pin__rail::after { transform: scaleX(1); }

.pin__steps {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-m);
}

.step {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--sp-s);
  align-items: baseline;
  opacity: 0.28;
  transform: translate3d(0, 0, 0);
  transition: opacity var(--t-slow) var(--ease-out), transform var(--t-slow) var(--ease-out);
}
.step.is-active { opacity: 1; }
.step__num {
  font-family: var(--font-mono);
  font-size: var(--step--1);
  font-weight: var(--w-bold);
  letter-spacing: var(--track-mono);
  color: var(--bone-60);
  transition: color var(--t-base) var(--ease-out);
}
.step.is-active .step__num { color: var(--accent); }
.step__title {
  font-family: var(--font-display);
  font-size: var(--step-2);
  font-weight: var(--w-med);
  line-height: 1.1;
  letter-spacing: -0.02em;
  margin: 0 0 var(--sp-3xs, 0.375rem);
}
.step__body { color: var(--text-muted); margin: 0; }

/* every step is lit when there's no scrubbing to light them */
html.reduce .step,
html:not(.motion) .step { opacity: 1; }
html.reduce .step__num,
html:not(.motion) .step__num { color: var(--accent); }

@media (min-width: 56em) {
  .pin__steps { gap: var(--sp-l); }
  .step { grid-template-columns: 4rem minmax(0, 1fr); }
}

/* --- 8.6 Story masthead --------------------------------------------------- */
.story__head { padding-block-start: calc(var(--nav-h) + var(--sp-2xl)); }
.story__head .lead { margin-block-start: var(--sp-m); }
.story__head .meta { margin-block-start: var(--sp-s); }

/* ==========================================================================
   9. FIXES — found by driving the real page, not by reading the CSS
   ========================================================================== */

/* 9.1 The mobile sheet covered the nav, which meant it covered its own close
   button: once open, the only ways out were Escape or picking a link. The bar
   has to sit ABOVE the sheet. (The sheet already pads its content down by
   --nav-h, so nothing hides underneath.) */
.nav { z-index: calc(var(--z-menu) + 1); }

/* keep the bar legible against the opaque sheet behind it */
.nav:has(+ .nav__menu[data-open='true']) { background: transparent; backdrop-filter: none; border-block-end-color: transparent; }

/* 9.2 `.nav__menu a` was styling EVERY link in the sheet — including the
   LinkedIn button in the footer, which came out as a 40px display-face word
   in a pill. Scope the big editorial type to the list only. */
.nav__menu-foot a.btn {
  font-family: var(--font-mono);
  font-size: var(--step--2);
  font-weight: var(--w-med);
  letter-spacing: var(--track-mono);
  text-transform: uppercase;
  min-block-size: 48px;
  justify-content: center;
}
.nav__menu-foot a.btn::after { content: none; }

/* 9.3 Four principle cards in an auto-fit grid broke 3 + 1 orphan on desktop.
   Four items want a 2x2. */
@media (min-width: 60em) {
  #principles .grid-auto { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* 9.4 The pinned sequence overflowed the pinned viewport: 5 steps at the global
   type scale come to ~940px of content in an ~820px well, so step 05 was cut
   off — and a pinned section is the one place you cannot scroll to see the rest.
   Size the sequence off viewport HEIGHT (vh) rather than width, so it always
   fits the well it's pinned into, on any screen. */
.pin__steps { gap: clamp(0.75rem, 0.1rem + 1.7vh, 2rem); }

.pin .step__title {
  font-size: clamp(1.05rem, 0.55rem + 1.5vh, 1.7rem);
  margin-block-end: clamp(0.15rem, 0.4vh, 0.5rem);
}
.pin .step__body {
  font-size: clamp(0.85rem, 0.62rem + 0.75vh, 1.05rem);
  line-height: 1.45;
  max-inline-size: 60ch;
}
.pin__rail { margin-block-end: clamp(1rem, 2.5vh, 2.5rem); }
.pin__inner { padding-block: clamp(1rem, 3vh, 3rem); }

/* short landscape screens: drop the bodies of the inactive steps entirely rather
   than clipping the list. The active step always keeps its explanation. */
@media (max-height: 640px) and (min-width: 56em) {
  .pin .step:not(.is-active) .step__body { display: none; }
}

/* 9.5 The inactive pin steps were opacity .28 — which computes to a 1.5:1
   contrast ratio against the ink. That isn't "dimmed", it's unreadable, and it
   fails WCAG AA outright (Lighthouse a11y 96).
   Keep the same read — one step forward, the rest receded — but buy the
   hierarchy with an accent marker and weight instead of near-invisible text.
   .62 measures ~5.6:1 on bone/ink, comfortably AA for body copy. */
.step {
  opacity: 0.62;
  padding-inline-start: var(--sp-s);
  border-inline-start: 2px solid transparent;
  transition: opacity var(--t-slow) var(--ease-out),
              border-color var(--t-slow) var(--ease-out),
              transform var(--t-slow) var(--ease-out);
}
.step.is-active {
  opacity: 1;
  border-inline-start-color: var(--accent);
}
@media (min-width: 56em) {
  .step.is-active { transform: translate3d(var(--sp-2xs), 0, 0); }
}

/* 9.6 ...and the .62 was compounding: the step number and body were ALREADY set
   to muted tones, so the container opacity dimmed a dim colour (3.14:1, still a
   fail). Base them on full bone and let the one opacity do all the dimming —
   .62 of bone on ink measures ~6.9:1. The active step still reads as active via
   the azure number (6.9:1) and the accent rule. */
.step__num,
.step__body { color: var(--text); }
.step.is-active .step__num { color: var(--accent); }

/* 9.7 .row--stack is a 12-column grid that places its children by .row__head /
   .row__body / .row__aside. An untagged child auto-places into a SINGLE column —
   i.e. 1/12 of the width — which shatters the text into one word per line rather
   than failing loudly. (That shipped. It's how the Speaking section broke.)
   Make the degradation safe: anything untagged spans the full row. */
@media (min-width: 62em) {
  .row--stack > *:not([class*='row__']) { grid-column: 1 / -1; }
}
