/* ==========================================================================
   chriswilkie.com — v2
   Sun-bleached Venice Beach / Malibu Sunset with a singular classic-car
   pinstripe. Static HTML5 · semantic vanilla CSS3 · no frameworks.

   Colour discipline:
     · Neon pink NEVER appears as text or a UI line — only as a background
       blend stop inside --gradient-horizon.
     · --accent-pinstripe (aqua) is invoked at exactly 1px, in exactly three
       places: the nav bezel top border, the active filter underline, and the
       single razor-thin rule dividing the layout sections.
     · Everything else structural is --border-mute. Muted line divisions,
       never chunky container boxes.

   Layout constraints:
     · no bento boxes          · no 3-column feature cards
     · no centred sections     · no pill badges (tracked text only)
   ========================================================================== */

/* ── 1. THE MALIBU SUNSET DUAL-MODE ───────────────────────────────────── */
/* Dark is the default for everyone. The OS preference deliberately does NOT
   decide it — :root carries the dark tokens, so the basement is what loads
   even with JS disabled. Light is opt-in via the toggle, which writes
   data-theme="light" and persists it. */

/* --- DARK MODE TOKENS (Dive Bar Basement) — THE DEFAULT --- */
/* The room reverts to smoky aubergine and muted violet. Two things stay from
   the stage-lights pass: the neon aqua pinstripe, and the full-saturation
   sweep in --gradient-horizon (its stops are hardcoded so the muted UI tokens
   can't drag the line art back down with them). */
:root,
[data-theme="dark"] {
  color-scheme: dark;

  --bg-canvas:   #130F1A;   /* Aubergine Black — basement dark */
  --bg-surface:  #1D1626;   /* Raised Panel */
  --text-main:   #E9E2E4;   /* warm off-white, softened by the room */
  --border-mute: #332B40;   /* Smoked Violet — soft but present */

  /* Haze tones follow the room; the cool one keeps the neon aqua. */
  --haze-a: #9A7FB8;   /* violet haze */
  --haze-b: #7E6A9B;   /* deep dusk */
  --haze-c: #2FE8D5;   /* neon aqua */

  /* Violet carries the copy, pulled back from neon. The razor line does not
     pull back — aqua stays at full voltage. */
  --accent-pinstripe: #2FE8D5;   /* Neon Aqua — 1.5px lines */
  --accent-warm:      #BFA6DE;   /* Electric Violet, desaturated */
  --accent-ink:       #BFA6DE;   /* 8.8:1 on the canvas */
  --glow-shadow: rgba(47, 232, 213, 0.15);
  --glow-spec:   0 0 44px 10px var(--glow-shadow);

  /* Full-saturation stage sweep — decorative line art only, so it can shout
     where the interface doesn't. Stops are literal on purpose. */
  --gradient-horizon: linear-gradient(90deg,
    #00F0DC 0%, #2FE8D5 16%, #4A6BE8 40%,
    #A64BFF 66%, #F03FB0 90%, #FF5CC0 100%);

  --text-body:  #BDB4C2;
  --text-muted: #918798;

  /* Heavier caps and a denser grille — the room is louder than the beach. */
  --display-weight: 800;
  --grille-size:    3px;

  /* Knob machining */
  --knob-lip:  rgba(255, 255, 255, 0.06);
  --knob-well: rgba(0, 0, 0, 0.35);

  /* Mode-independent */
  --font-display: 'Cinzel', 'Playfair Display', serif;
  --font-sans:    'Plus Jakarta Sans', 'Inter', -apple-system, sans-serif;

  --track: 0.15em;
  --ease-mech: cubic-bezier(0.16, 1, 0.3, 1);
  --measure: 1160px;
  --gutter:  2.5rem;

  /* Interactive rows inset their text by this much and bleed their tint back
     out by the same amount — so copy stays aligned to the layout grid while
     the hover fill keeps breathing room around it. Must stay < --gutter. */
  --row-bleed: 1.75rem;
}

/* --- LIGHT MODE TOKENS (Hazy California Postcard) — OPT-IN --- */
/* Venice Beach at midday: sun-bleached paper, aqua pinstripe, sunset orange. */
[data-theme="light"] {
  color-scheme: light;

  --bg-canvas:   #FDFBF7;   /* Vintage Sand — matte warm cream paper */
  --bg-surface:  #F5EFE4;   /* Boardwalk Tan — deeper hue for layout fields */
  --text-main:   #3C4A42;   /* Sun-Bleached Slate — muted off-black */
  --border-mute: #E6DFD3;   /* Faded Sidewalk — soft structural dividers */

  /* Hazy Sunset Core Tones — pushed a touch further into pink and aqua */
  --haze-a: #F2A48A;   /* Dusty Peach */
  --haze-b: #E39FBE;   /* Sunset Dusk Twilight — pinker */
  --haze-c: #8FC4CE;   /* Faded Coastal Marine — more aqua */

  /* THE SINGULAR CAR PINSTRIPE POP */
  --accent-pinstripe: #00B5A2;   /* Electric Malibu Aqua */
  --accent-warm:      #E04D1D;   /* Boulevard Sunset Orange */
  --glow-shadow: rgba(0, 181, 162, 0.15);
  --glow-spec:   0 0 30px 6px var(--glow-shadow);

  /* Smooth Horizon Haze Gradient — more saturated Venice blend. */
  --gradient-horizon: linear-gradient(90deg,
    var(--haze-c) 0%, #4FC3C7 18%, #FF9E00 42%,
    var(--accent-warm) 66%, #F0559B 86%, #E01A75 100%);

  --text-body:  #4E5A53;
  --text-muted: #66726B;

  /* Boulevard Orange is 3.9:1 on Vintage Sand — under par at 10px. Small
     tracked text uses this deeper cut (4.8:1); every graphic invocation of
     the warm accent keeps --accent-warm exactly as specified. */
  --accent-ink: #C94014;

  --display-weight: 700;
  --grille-size:    4px;

  --knob-lip:  rgba(255, 255, 255, 0.45);
  --knob-well: rgba(0, 0, 0, 0.07);
}

/* ── 2. RESET & BASE ──────────────────────────────────────────────────── */

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

html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }

body {
  background: var(--bg-canvas);
  color: var(--text-main);
  font-family: var(--font-sans);
  font-size: 15px;
  line-height: 1.75;
  letter-spacing: 0.015em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
  /* Smooth day → twilight transition. */
  transition: background-color 0.55s var(--ease-mech), color 0.55s var(--ease-mech);
}

::selection { background: var(--haze-a); color: var(--text-main); }

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

:focus-visible { outline: 1.5px solid var(--accent-pinstripe); outline-offset: 3px; }

@view-transition { navigation: auto; }

::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 0.6s;
  animation-timing-function: var(--ease-mech);
}

@keyframes page-fade { from { opacity: 0; } to { opacity: 1; } }
body { animation: page-fade 0.7s var(--ease-mech) both; }

/* ── 3. LAYOUT ────────────────────────────────────────────────────────── */

.container {
  max-width: var(--measure);
  margin: 0 auto;
  padding: 0 var(--gutter);
}

/* Deliberately uneven vertical rhythm — uniform padding is avoided. */
.band       { padding: 5rem 0; }
.band-airy  { padding: 8rem 0; }
.band-dense { padding: 3.25rem 0; }
.band-ruled { border-top: 1px solid var(--border-mute); }

/* PINSTRIPE #3 — the single razor-thin rule dividing the layout sections.
   One per page. Exactly 1.5px. */
.pinstripe-rule {
  height: 0;
  border: none;
  border-top: 1.5px solid var(--accent-pinstripe);
  opacity: 0.9;
}

.reveal {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 0.7s var(--ease-mech), transform 0.7s var(--ease-mech);
}

.reveal.visible { opacity: 1; transform: translateY(0); }

/* ── 4. TYPOGRAPHY ────────────────────────────────────────────────────── */

.display {
  font-family: var(--font-display);
  font-weight: 400;
  letter-spacing: -0.015em;
  line-height: 1;
  color: var(--text-main);
}

/* METALLIC VINYL TYPOGRAPHY
   Chiselled Roman capitals, canted right — half automotive emblem, half
   heavy-metal record sleeve. --metal-slant is baked into any animated
   transform too, so it survives the hero keyframes. */
:root { --metal-slant: -5deg; }

.metal,
h2.emblem {
  font-family: var(--font-display);
  font-weight: var(--display-weight);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  transform: skewX(var(--metal-slant));
  transform-origin: left bottom;
}

h2.emblem {
  font-size: clamp(0.95rem, 1.8vw, 1.2rem);
  line-height: 1.25;
  color: var(--text-main);
}

/* Micro metadata — uppercase tracked text. Never a capsule. */
.meta {
  font-family: var(--font-sans);
  font-size: 10px;
  font-weight: 600;
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--text-muted);
}

.meta-accent { color: var(--accent-ink); }

/* Cinzel ships no italic, so display emphasis is chromatic, not typographic. */
.accent-em { color: var(--accent-ink); }

.meta-sep { color: var(--border-mute); padding: 0 0.35rem; user-select: none; }

/* Band header — left-set index, emblem, muted rule out to the edge. */
.band-head {
  display: flex;
  align-items: baseline;
  gap: 1.5rem;
  margin-bottom: 2.5rem;
}

.band-head .index {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: var(--track);
  color: var(--accent-ink);
  flex-shrink: 0;
}

.band-head .rule {
  flex: 1;
  height: 1px;
  background: linear-gradient(to right, var(--border-mute), transparent);
  transform: translateY(-0.32rem);
}

.band-intro {
  font-size: 14.5px;
  color: var(--text-body);
  line-height: 1.85;
  max-width: 58ch;
  margin-bottom: 3rem;
}

a { color: var(--accent-ink); }

/* Raw tracked specification text — replaces tag pills entirely. */
.specs {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 0.55rem;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--text-muted);
}

.specs .spec { white-space: nowrap; }

.specs .spec + .spec::before {
  content: '/';
  color: var(--border-mute);
  padding-right: 0.55rem;
}

/* ── 5. SOFT BACKLIT DUSK GLOW ────────────────────────────────────────── */
/* Interactive targets bloom rather than shift — a hazy dusk lamp behind
   the text, never a hard shadow. */

.analog-interactive {
  font-family: var(--font-sans);
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: var(--track);
  border: 1px solid var(--border-mute);
  padding: 0.8rem 1.5rem;
  background-color: transparent;
  color: var(--text-main);
  cursor: pointer;
  text-decoration: none;
  display: inline-block;
  transition: background-color 0.3s var(--ease-mech),
              box-shadow 0.35s var(--ease-mech),
              border-color 0.3s ease,
              color 0.3s ease;
}

.analog-interactive:hover,
.analog-interactive:focus-visible {
  background-color: var(--bg-surface);
  border-color: var(--haze-a);
  color: var(--accent-ink);
  box-shadow: var(--glow-spec);
}

.btn { color: var(--accent-ink); border-color: var(--haze-a); }
.btn-ghost { font-weight: 600; color: var(--text-muted); }

/* ── 6. THE NAVIGATION BEZEL ──────────────────────────────────────────── */

.site-nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 100;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1.25rem;
  padding: 0.6rem var(--gutter);
  background-color: color-mix(in srgb, var(--bg-canvas) 90%, transparent);
  backdrop-filter: blur(16px) saturate(1.2);
  -webkit-backdrop-filter: blur(16px) saturate(1.2);
  /* PINSTRIPE #1 — the nav bezel top border. Exactly 1.5px. */
  border-top: 1.5px solid var(--accent-pinstripe);
  border-bottom: 1px solid var(--border-mute);
  transition: background-color 0.55s var(--ease-mech);
}

@supports not (background-color: color-mix(in srgb, red 50%, transparent)) {
  .site-nav { background-color: var(--bg-canvas); }
}

/* Vintage amplifier grille cloth on the panel wings — a fine dot mesh that
   dissolves inward so it never sits behind the copy. */
.site-nav::before,
.site-nav::after {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  width: 33%;
  background-image: radial-gradient(var(--border-mute) 1px, transparent 0);
  background-size: var(--grille-size) var(--grille-size);
  pointer-events: none;
  opacity: 0.9;
}

.site-nav::before {
  left: 0;
  -webkit-mask-image: linear-gradient(to right, #000 0%, transparent 100%);
          mask-image: linear-gradient(to right, #000 0%, transparent 100%);
}

.site-nav::after {
  right: 0;
  -webkit-mask-image: linear-gradient(to left, #000 0%, transparent 100%);
          mask-image: linear-gradient(to left, #000 0%, transparent 100%);
}

/* Panel furniture rides above the grille. */
.nav-logo, .nav-right { position: relative; z-index: 1; }

.nav-logo {
  font-family: var(--font-display);
  font-size: 1.3rem;
  letter-spacing: 0.01em;
  color: var(--text-main);
  text-decoration: none;
  white-space: nowrap;
  transition: color 0.3s ease, text-shadow 0.35s var(--ease-mech);
}

.nav-logo span { color: var(--accent-ink); }

.nav-logo:hover {
  color: var(--accent-ink);
  text-shadow: 0 0 24px var(--glow-shadow);
}

.nav-right { display: flex; align-items: center; gap: 0.6rem; min-width: 0; }

/* Key bank — divided by muted hairlines, not boxes. Never hidden: the rack
   scrolls sideways when the viewport is narrow. */
.nav-array {
  display: flex;
  list-style: none;
  border: 1px solid var(--border-mute);
  /* Opaque — the grille mesh must not read through the key faces. */
  background-color: var(--bg-canvas);
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}

.nav-array::-webkit-scrollbar { display: none; }

.nav-array a {
  display: block;
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
  text-decoration: none;
  padding: 0.6rem 0.9rem;
  white-space: nowrap;
  border-left: 1px solid var(--border-mute);
  transition: background-color 0.3s var(--ease-mech),
              box-shadow 0.35s var(--ease-mech),
              color 0.3s ease;
}

.nav-array li:first-child a { border-left: none; }

.nav-array a:hover,
.nav-array a:focus-visible {
  color: var(--accent-ink);
  background-color: var(--bg-surface);
  box-shadow: var(--glow-spec);
}

.nav-array a.current {
  color: var(--accent-ink);
  background-color: var(--bg-surface);
}

/* ── The knurled volume knob ──
   Machined metal edge, milled face, and a single razor-thin pinstripe
   indicator that swings between the two positions. */
.theme-toggle {
  position: relative;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: 1px solid var(--border-mute);
  color: var(--text-muted);
  cursor: pointer;
  padding: 0;
  display: grid;
  place-items: center;
  flex-shrink: 0;
  /* knurled rim over a milled face */
  background:
    radial-gradient(circle at 50% 38%, var(--bg-canvas) 0 44%, transparent 45%),
    repeating-conic-gradient(from 0deg,
      var(--bg-surface) 0deg 3deg,
      var(--bg-canvas)  3deg 6deg);
  box-shadow: inset 0 1px 0 var(--knob-lip),
              inset 0 -1px 2px var(--knob-well);
  transition: box-shadow 0.35s var(--ease-mech),
              border-color 0.3s ease,
              color 0.3s ease;
}

.theme-toggle:hover,
.theme-toggle:focus-visible {
  color: var(--accent-ink);
  border-color: var(--haze-a);
  box-shadow: var(--glow-spec),
              inset 0 1px 0 var(--knob-lip);
}

.theme-toggle:active { transform: translateY(1px); }

/* The indicator — PINSTRIPE, exactly 1.5px. Rotates with the setting. */
.knob-tick {
  position: absolute;
  inset: 0;
  transform: rotate(32deg);          /* dark is the default position */
  transition: transform 0.45s var(--ease-mech);
  pointer-events: none;
}

.knob-tick::before {
  content: '';
  position: absolute;
  left: 50%;
  top: 2.5px;
  width: 1.5px;
  height: 8px;
  margin-left: -0.75px;
  background: var(--accent-pinstripe);
}

[data-theme="light"] .knob-tick { transform: rotate(-32deg); }

.theme-toggle svg {
  position: relative;
  width: 12px; height: 12px;
  stroke: currentColor;
  fill: none;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Icon shows the mode you would switch TO. No override → follow the OS. */
/* The icon shows the mode you would switch TO. Dark is the default, so the
   sun is the default face. */
.icon-sun  { display: block; }
.icon-moon { display: none; }

[data-theme="light"] .icon-sun  { display: none; }
[data-theme="light"] .icon-moon { display: block; }

/* ── 7. LEDGER — the operations matrix ────────────────────────────────── */
/* Muted line divisions over chunky container boxes. */

.ledger {
  width: calc(100% + 2 * var(--row-bleed));
  margin: 0 calc(-1 * var(--row-bleed));
  border-collapse: collapse;
  text-align: left;
}

/* Inset the outer cells so hovered rows keep breathing room while the copy
   stays aligned to the layout grid. */
.ledger th:first-child,
.ledger td:first-child { padding-left: var(--row-bleed); }

.ledger th:last-child,
.ledger td:last-child { padding-right: var(--row-bleed); }

.ledger caption { display: none; }

.ledger thead th {
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--text-muted);
  padding: 0 1.25rem 0.7rem 0;
  border-bottom: 1px solid var(--border-mute);
  vertical-align: bottom;
}

.ledger tbody tr {
  border-bottom: 1px solid var(--border-mute);
  transition: background-color 0.3s var(--ease-mech),
              box-shadow 0.35s var(--ease-mech);
}

.ledger tbody tr:hover {
  background-color: var(--bg-surface);
  box-shadow: var(--glow-spec);
}

.ledger td { padding: 0.85rem 1.25rem 0.85rem 0; vertical-align: baseline; }
.ledger th:last-child, .ledger td:last-child { padding-right: 0; }

.ledger .cell-index {
  width: 5rem;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: var(--track);
  color: var(--accent-ink);
  white-space: nowrap;
}

.ledger .cell-name {
  font-size: 14px;
  font-weight: 700;
  color: var(--text-main);
  width: 15rem;
}

.ledger .cell-detail { font-size: 13.5px; color: var(--text-body); line-height: 1.7; }

.ledger .cell-note {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--text-muted);
  text-align: right;
  white-space: nowrap;
  width: 8rem;
}

/* ── 8. THE SMOOTH HORIZON GRID ENGINE ────────────────────────────────── */

.horizon-container {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  width: 100%;
  margin: 6rem 0;
}

.horizon-line {
  background: var(--gradient-horizon);
  border: none;
  height: 1px;
}

/* Linear scaling array — a clean 1.0 → 0.05 analog-synth grid fade. */
.horizon-line:nth-child(1) { width: 100%; margin-bottom:  2px; opacity: 1; }
.horizon-line:nth-child(2) { width:  92%; margin-bottom:  3px; opacity: 0.9; }
.horizon-line:nth-child(3) { width:  84%; margin-bottom:  4px; opacity: 0.8; }
.horizon-line:nth-child(4) { width:  76%; margin-bottom:  5px; opacity: 0.7; }
.horizon-line:nth-child(5) { width:  68%; margin-bottom:  6px; opacity: 0.6; }
.horizon-line:nth-child(6) { width:  60%; margin-bottom:  7px; opacity: 0.5; }
.horizon-line:nth-child(7) { width:  52%; margin-bottom:  8px; opacity: 0.4; }
.horizon-line:nth-child(8) { width:  44%; margin-bottom:  9px; opacity: 0.3; }
.horizon-line:nth-child(9) { width:  36%; margin-bottom: 10px; opacity: 0.2; }
.horizon-line:nth-child(10) { width:  28%; margin-bottom: 11px; opacity: 0.15; }
.horizon-line:nth-child(11) { width:  20%; margin-bottom: 12px; opacity: 0.1; }
.horizon-line:nth-child(12) { width:  10%; margin-bottom: 13px; opacity: 0.05; }

/* ── 8b. THE MINI HORIZON GLYPH ───────────────────────────────────────── */
/* The footer horizon reduced to an icon: the same scaling array of gradient
   rules, shrunk to mark eyebrows, list items and section rails. Replaces the
   lone single-line dashes so the motif recurs at every scale. */

.horizon-glyph {
  display: flex;
  flex-direction: column;
  gap: 2px;
  width: var(--glyph-w, 40px);
  flex-shrink: 0;
  transition: width 0.35s var(--ease-mech);
}

/* Children may be <hr> or <i> — the latter is phrasing content, so a glyph is
   valid inside a <p> eyebrow where an <hr> would break the paragraph. */
.horizon-glyph > * {
  display: block;
  border: none;
  height: 1px;
  margin: 0;
  background: var(--gradient-horizon);
}

.horizon-glyph > *:nth-child(1) { width: 100%; opacity: 1;    }
.horizon-glyph > *:nth-child(2) { width: 82%;  opacity: 0.8;  }
.horizon-glyph > *:nth-child(3) { width: 64%;  opacity: 0.6;  }
.horizon-glyph > *:nth-child(4) { width: 44%;  opacity: 0.4;  }
.horizon-glyph > *:nth-child(5) { width: 24%;  opacity: 0.22; }

.horizon-glyph-sm { --glyph-w: 26px; gap: 1.5px; }
.horizon-glyph-lg { --glyph-w: 62px; }

/* ── 8c. THE COLLISION HEADLINE ───────────────────────────────────────── */
/* The name states itself, dissolves into the two halves of the job, they
   collide, and the impact scatters the disciplines that live between them
   before the name reassembles.

   One shared 10s cycle drives every element, so the loop can never drift.
   The collision starts at 1.6s so the idea lands before anyone scrolls past:
     0.0–1.0s   "Chris Wilkie" holds        3.2–5.2s   terms coast outward
     1.0–1.7s   name dissolves              5.2–7.1s   terms halt (readable)
     1.6–3.1s   words converge, impact      7.1–8.4s   terms fade in place
     3.1–3.8s   words dissolve              8.7–10.0s  name reassembles

   The cycle both opens and closes on the name, so the loop seam is invisible.

   Progressive enhancement: the <h1> is real text, fully visible with no JS
   and under reduced-motion. .js-anim (set in <head>, pre-paint) opts in. */

.hero-stage {
  position: relative;
  font-size: clamp(2.4rem, 6.2vw, 5.3rem);   /* Roman caps run ~50% wider */
  min-height: 1.9em;           /* two lines at 0.95 leading — no layout shift */
  margin-bottom: 2.5rem;
}

/* Overlays the headline rather than sitting in flow beside it. */
.hero-collide {
  display: none;
  position: absolute;
  inset: 0;
}

.hero-collide,
.hero-collide * { pointer-events: none; }

.collide-stack { display: flex; flex-direction: column; align-items: flex-start; }

.collide-word {
  font-family: var(--font-display);
  font-size: inherit;
  font-weight: var(--display-weight);
  line-height: 0.95;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  transform-origin: left center;
  color: var(--text-main);
  white-space: nowrap;
  will-change: transform, opacity;
}

/* A tight cluster — the terms stay close to the headline rather than flying
   to the section edges, so they read as one group. */
.burst {
  position: absolute;
  left: 0;
  top: 50%;
  width: var(--burst-spread, min(166%, 46rem));
}

.burst-term {
  --burst-unit: clamp(0.40px, 0.064vw, 0.88px);  /* tracks the fluid stage */
  --burst-squeeze: 1;     /* narrows the horizontal spread on small screens */
  --burst-inset: 0%;
  position: absolute;
  left: calc(var(--x) * var(--burst-squeeze) + var(--burst-inset));
  top: calc(var(--y) * var(--burst-unit));
  font-family: var(--font-sans);
  font-size: 14px;
  font-weight: 600;
  letter-spacing: var(--track);
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--text-muted);
  opacity: 0;
  transform: translate(-50%, -50%);
  will-change: transform, opacity;
}

.burst-term-hot  { color: var(--accent-ink); }
.burst-term-cool { color: var(--haze-c); }

/* ── The sequence ── */

@keyframes hero-fade-up {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Opens visible, holds 4s, dissolves — then reassembles to close the loop. */
@keyframes hero-name {
  0%,
  10%     { opacity: 1; transform: translateY(0) skewX(var(--metal-slant)); }
  17%     { opacity: 0; transform: translateY(-10px) skewX(var(--metal-slant)); }
  87%     { opacity: 0; transform: translateY(12px) skewX(var(--metal-slant));
            animation-timing-function: cubic-bezier(0.25, 1, 0.5, 1); }
  100%    { opacity: 1; transform: translateY(0) skewX(var(--metal-slant)); }
}

/* Drops from above, overshoots into the collision, recoils, then dissolves. */
@keyframes collide-down {
  0%,
  16%     { opacity: 0; transform: translateY(-175%) skewX(var(--metal-slant)); }
  19%     { opacity: 1; }
  29%     { transform: translateY(9%) skewX(var(--metal-slant)); }    /* impact — past its rest line */
  30.5%   { transform: translateY(-5%) skewX(var(--metal-slant)); }   /* recoil */
  31.5%   { opacity: 1; transform: translateY(0) skewX(var(--metal-slant)); }
  38%,
  100%    { opacity: 0; transform: translateY(0) scale(0.94) skewX(var(--metal-slant)); }
}

/* Rises from below into the same impact. */
@keyframes collide-up {
  0%,
  16%     { opacity: 0; transform: translateY(175%) skewX(var(--metal-slant)); }
  19%     { opacity: 1; }
  29%     { transform: translateY(-9%) skewX(var(--metal-slant)); }
  30.5%   { transform: translateY(5%) skewX(var(--metal-slant)); }
  31.5%   { opacity: 1; transform: translateY(0) skewX(var(--metal-slant)); }
  38%,
  100%    { opacity: 0; transform: translateY(0) scale(0.94) skewX(var(--metal-slant)); }
}

/* Launches from the point of impact, coasts out over ~2s, halts at its
   resting coordinate for ~1.9s, then fades in place without moving. */
@keyframes burst-fly {
  0%,
  32% {
    opacity: 0;
    transform: translate(calc(-50% + var(--fx) * var(--burst-unit)),
                         calc(-50% + var(--fy) * var(--burst-unit))) scale(0.62);
    animation-timing-function: cubic-bezier(0.17, 0.75, 0.25, 1);
  }
  36%    { opacity: 1; }
  52%    {                                            /* arrived — full stop */
    opacity: 1;
    transform: translate(-50%, -50%) scale(1);
    animation-timing-function: linear;
  }
  71%    { opacity: 1; transform: translate(-50%, -50%) scale(1); }  /* HALT */
  84%,
  100%   { opacity: 0; transform: translate(-50%, -50%) scale(1); }  /* fade */
}

.js-anim .hero-collide { display: block; }

/* Looping — one shared duration keeps the cycle locked together. */
.js-anim .hero-title     { animation: hero-name 10s linear infinite; }
.js-anim .collide-word-a { animation: collide-down 10s var(--ease-mech) infinite; }
.js-anim .collide-word-b { animation: collide-up   10s var(--ease-mech) infinite; }
.js-anim .burst-term     { animation: burst-fly 10s linear var(--d) infinite; }

/* One-shot — the rest of the hero arrives immediately and stays put. */
.js-anim .hero-eyebrow { animation: hero-fade-up 0.5s var(--ease-mech) 0.10s both; }
.js-anim .hero-tagline { animation: hero-fade-up 0.6s var(--ease-mech) 0.30s both; }
.js-anim .hero-cta     { animation: hero-fade-up 0.6s var(--ease-mech) 0.45s both; }
.js-anim .hero-readout { animation: hero-fade-up 0.6s var(--ease-mech) 0.60s both; }

@media (max-width: 1000px) {
  /* Column widens to 80% here, so the multiplier drops but the absolute cap
     holds the cluster at the same physical size. */
  .burst { --burst-spread: min(125%, 46rem); }
  .burst-term { font-size: 13px; }
}

@media (max-width: 720px) {
  /* The column is full-width here, so squeeze the cluster inward instead. */
  .burst { --burst-spread: 100%; }
  .burst-term {
    --burst-unit: 0.40px;
    --burst-squeeze: 0.8;
    --burst-inset: 6%;
    font-size: 10px;
  }
}

@media (max-width: 560px) {
  /* A phone can't hold twelve terms without collisions, so the long ones
     drop out and the six survivors take the full width. */
  .burst-term-wide { display: none; }
  .burst-term {
    --burst-unit: 0.40px;
    --burst-squeeze: 1;
    --burst-inset: 3%;
    font-size: 9.5px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .js-anim .hero-collide { display: none; }
  .js-anim .hero-title,
  .js-anim .hero-eyebrow,
  .js-anim .hero-tagline,
  .js-anim .hero-cta,
  .js-anim .hero-readout { opacity: 1; animation: none; }
}

/* ── 9. FOOTER ────────────────────────────────────────────────────────── */

.site-footer {
  border-top: 1px solid var(--border-mute);
  padding: 2rem 0 3rem;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 1rem;
}

.footer-copy {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--text-muted);
}

.footer-copy span { color: var(--accent-ink); }

.footer-link {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--text-muted);
  text-decoration: none;
  transition: color 0.3s ease, text-shadow 0.35s var(--ease-mech);
}

.footer-link:hover {
  color: var(--accent-ink);
  text-shadow: 0 0 24px var(--glow-shadow);
}

/* ── 10. STATE MESSAGES ───────────────────────────────────────────────── */

.state-msg { padding: 2.5rem 0; color: var(--text-muted); font-size: 14px; }

/* ── 11. RESPONSIVE ───────────────────────────────────────────────────── */

@media (max-width: 900px) {
  /* The bezel wraps: logo on top, full-width scrolling key rack beneath.
     The navigation is never hidden. */
  .site-nav { flex-wrap: wrap; row-gap: 0.45rem; padding: 0.5rem 1.35rem 0.55rem; }
  .nav-right { width: 100%; gap: 0.5rem; }
  .nav-array { flex: 1; min-width: 0; }
  .nav-array a { padding: 0.55rem 0.8rem; }
}

@media (max-width: 720px) {
  /* Bleed must stay under the gutter or rows overflow the viewport. */
  :root { --gutter: 1.35rem; --row-bleed: 0.85rem; }

  .band       { padding: 3.5rem 0; }
  .band-airy  { padding: 4.5rem 0; }
  .band-dense { padding: 2.5rem 0; }

  .band-head { gap: 0.9rem; margin-bottom: 1.85rem; }
  .band-head .rule { display: none; }
  .band-intro { margin-bottom: 2rem; }

  .horizon-container { margin: 3.5rem 0; }

  /* The matrix becomes a stacked, text-first technical list. */
  .ledger thead { display: none; }
  .ledger, .ledger tbody, .ledger tr, .ledger td { display: block; width: auto; }
  .ledger tbody tr { padding: 1.1rem var(--row-bleed); }
  .ledger td { padding: 0; }
  .ledger td:first-child, .ledger td:last-child { padding: 0; }
  .ledger .cell-index { margin-bottom: 0.4rem; width: auto; }
  .ledger .cell-name { margin-bottom: 0.3rem; width: auto; }
  .ledger .cell-note { text-align: left; margin-top: 0.45rem; width: auto; }

  .site-footer { flex-direction: column; align-items: flex-start; gap: 0.75rem; }
}

/* ── 12. MOTION PREFERENCES ───────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  @view-transition { navigation: none; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  .reveal { opacity: 1; transform: none; }
}
