/* ============================================================
   MOMENTUS — v8 · IDENTITY LOCK TOKENS
   Source: clients/momentus/identity-lock.md
   ============================================================ */

:root {
  /* Palette — flipped to black-on-white base + colour blasts
     (letude.group hero blast + 2025.unseen.co per-section rotation) */
  --c-bg:         #f8f6f1;   /* paper — base content sections */
  --c-fg:         #14120e;   /* ink — type on paper + on blast */
  --c-accent:     #ee382b;   /* letude red — signature blast + accent */
  --c-surface:    #ffffff;   /* raised cards on paper */
  --c-mute:       #6e685c;   /* muted captions / metadata on light */
  --c-bone:       #f1ebdd;   /* footer brutalist register (light, on dark slab) */
  --c-line:       rgba(20, 18, 14, 0.12);

  /* Blast hues — per-section floods (the unseen rotation) */
  --blast:        #ee382b;   /* letude red — hero + CTA bookends */
  --ink:          #14120e;   /* black type on blast */
  --slab:         #121110;   /* near-black footer slab */
  --paper:        #f8f6f1;   /* light type on dark/violet sections */

  /* Type families (exactly 3 — locked) */
  --type-display: 'Hanken Grotesk', system-ui, sans-serif;
  --type-body:    'Hanken Grotesk', system-ui, sans-serif;
  --type-em:      'Instrument Serif', 'Georgia', serif;
  --type-mono:    'JetBrains Mono', 'SF Mono', ui-monospace, monospace;

  /* Motion (decisive decel, no bounce) */
  --ease-entrance: cubic-bezier(0.2, 0.9, 0.25, 1);
  --ease-hover:    cubic-bezier(0.2, 0.9, 0.25, 1);
  --t-hover:       220ms;

  /* Layout */
  --wrap:    1320px;
  --gutter:  clamp(1.4rem, 4vw, 4.5rem);

  /* Type scale */
  --fs-mono:    13px;
  --fs-body:    17px;
  --fs-lead:    clamp(18px, 1.4vw, 22px);
  --fs-h2:      clamp(42px, 5.5vw, 84px);
}

/* ============================================================
   RESET + BASE
   ============================================================ */

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

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

body {
  background: var(--c-bg);
  color: var(--c-fg);
  font-family: var(--type-body);
  font-size: var(--fs-body);
  font-weight: 400;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* clip (not hidden) — clips horizontal bleed without making <body> a scroll
     container, which would disable position:sticky for the mobile hero→about cover */
  overflow-x: clip;
}

img { display: block; max-width: 100%; height: auto; }
a   { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }

/* Editorial italic em — the signature inline emphasis */
.em {
  font-family: var(--type-em);
  font-style: italic;
  font-weight: 400;
  font-size: 1.08em;
  letter-spacing: -0.005em;
  color: var(--c-accent);
}

/* Monospace inflection (indexes, timestamps, metadata only) */
.mono {
  font-family: var(--type-mono);
  font-size: var(--fs-mono);
  font-weight: 400;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--c-mute);
}

/* Selection */
::selection { background: var(--c-accent); color: var(--c-bg); }

/* ============================================================
   CONTENT ENTRANCES — TWO standardised grammars, chosen by typeface, so every
   text element on the site enters the same way:
     [data-lines] — SANS-SERIF text rises in LINE BY LINE from below, each visual
                    line masked (the About-paragraph / hero-ghost grammar). JS
                    splits the text into .ln (mask) > .ln-in (riser); per-line delay
                    cascades them. Held hidden via opacity until split so there is no
                    flash of unmasked text, then .is-split releases the parent.
     [data-wipe]  — SERIF text writes on left→right behind a clip sweep (the hero
                    serif wordmark grammar), on the same decisive bezier.
   Two structural helpers share the "enter from below" direction for non-text blocks:
     [data-stagger] — a group's children slide up + fade in a measured cascade.
     [data-rise]    — a single block (media / button / label) slides up + fades.
   All hidden states are gated by .js + no-reduced-motion so nothing hides without JS
   or for motion-sensitive users; JS adds .is-in (and .is-split for lines) to play.
   ============================================================ */
@media (prefers-reduced-motion: no-preference) {
  /* SANS — line-by-line rise. Parent held hidden until JS has wrapped the lines. */
  html.js [data-lines] { opacity: 0; }
  html.js [data-lines].is-split { opacity: 1; }
  html.js [data-lines] .ln { display: block; overflow: hidden; padding-bottom: 0.08em; }
  html.js [data-lines] .ln-in {
    display: block;
    transform: translateY(118%);
    transition: transform 1000ms var(--ease-entrance);
    will-change: transform;
  }
  html.js [data-lines].is-in .ln-in { transform: none; }

  /* SERIF — clip wipe left→right (held-slow start, decisive pickup). */
  html.js [data-wipe] {
    clip-path: inset(-6% 101% -14% -5%);
    transition: clip-path 1300ms cubic-bezier(0.85, 0, 0.2, 1);
    will-change: clip-path;
  }
  html.js [data-wipe].is-in { clip-path: inset(-6% -5% -14% -5%); }

  /* single-block rise + fade (media, buttons, labels) */
  html.js [data-rise] {
    opacity: 0;
    transform: translateY(30px);
    transition: opacity 820ms var(--ease-entrance), transform 820ms var(--ease-entrance);
    will-change: opacity, transform;
  }
  html.js [data-rise].is-in { opacity: 1; transform: none; }

  /* group cascade — children slide up + fade (per-child delay set in JS) */
  html.js [data-stagger] > * {
    opacity: 0;
    transform: translateY(32px);
    transition: opacity 760ms var(--ease-entrance), transform 760ms var(--ease-entrance);
    will-change: opacity, transform;
  }
  html.js [data-stagger].is-in > * { opacity: 1; transform: none; }
}

/* MOBILE — a richer entrance for the featured-work rows: each project wipes in
   left→right while rising, in cascade (the [data-stagger] per-child delay still
   applies). More deliberate than a plain fade-up on the narrow frame. */
@media (max-width: 900px) and (prefers-reduced-motion: no-preference) {
  html.js .work-list[data-stagger] > * {
    transform: translateY(28px);
    clip-path: inset(0 100% 0 0);
    transition: opacity 720ms var(--ease-entrance),
                transform 860ms var(--ease-entrance),
                clip-path 940ms cubic-bezier(0.85, 0, 0.2, 1);
  }
  html.js .work-list[data-stagger].is-in > * { clip-path: inset(0 0 0 0); transform: none; }
}

/* FAIL-OPEN NET — if the reveal engine never boots (stale/blocked script.js, no
   GSAP), the inline <head> watchdog sets .reveals-failopen on <html> after load and
   every held-hidden entrance is forced visible. Content can never be left invisible. */
html.reveals-failopen [data-lines],
html.reveals-failopen [data-wipe],
html.reveals-failopen [data-rise],
html.reveals-failopen .layer-head,
html.reveals-failopen .layer-mark,
html.reveals-failopen .about-h { opacity: 1 !important; }
html.reveals-failopen [data-wipe],
html.reveals-failopen [data-rise],
html.reveals-failopen .layer-head,
html.reveals-failopen .layer-soul,
html.reveals-failopen .hero-wordmark-svg .hwm-front { clip-path: none !important; }
html.reveals-failopen [data-rise],
html.reveals-failopen [data-lines] .ln-in,
html.reveals-failopen .about-line-in,
html.reveals-failopen .layer-ghost,
html.reveals-failopen .hero-wordmark-svg .hwm-back { transform: none !important; translate: 0 0 !important; }
html.reveals-failopen [data-stagger] > *,
html.reveals-failopen .process .pstage,
html.reveals-failopen .hero-poster { opacity: 1 !important; transform: none !important; }
html.reveals-failopen .sitenav { opacity: 1 !important; }
html.reveals-failopen .about-brush { opacity: 1 !important; }
html.reveals-failopen .about-line-in { translate: 0 0 !important; }

/* ============================================================
   CURSOR — a small solid ink circle that trails the pointer with a
   slight lag (JS lerp). No blend mode, no overlay; over interactive
   targets it tightens to a smaller, focused dot. Desktop fine-pointer
   only (touch keeps the native cursor).
   ============================================================ */
.cursor {
  position: fixed;
  top: 0; left: 0;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--ink);
  pointer-events: none;
  z-index: 9999;
  opacity: 0;
  will-change: transform;
  transition: width 320ms var(--ease-hover),
              height 320ms var(--ease-hover),
              border-radius 320ms var(--ease-hover),
              opacity 240ms var(--ease-hover);
}
.cursor.is-on { opacity: 1; }
/* inverts to light over near-black sections (set per-section in JS) so the dot is
   never lost against a dark field */
.cursor.cursor--light { background: var(--paper); }
/* over interactive targets — tighten to a smaller, focused dot */
.cursor.cursor--dot { width: 13px; height: 13px; }
/* inside the featured-works lens the red disc replaces the pointer — hide the dot */
html.lens-on .cursor { opacity: 0; }
@media (pointer: fine) {
  html.has-cursor, html.has-cursor * { cursor: none; }
}

/* ============================================================
   HERO — anchored to fromanother.love — editorial pacing, held-dark, cinematic restraint
   ============================================================ */

.hero {
  /* PAPER — offwhite flood, big magenta→amber gradient-noise auras, giant black
     wordmark, ink accents (anchored to the supplied BG ref) */
  --c-bg: var(--paper);
  --c-fg: var(--ink);
  --c-accent: var(--ink);
  --c-mute: rgba(20, 18, 14, 0.6);
  --c-line: rgba(20, 18, 14, 0.22);
  background: var(--paper);
  color: var(--ink);
  position: relative;
  min-height: 100vh;
  padding: 0 var(--gutter);
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  /* the masthead + poster sit high in the frame as one editorial stack;
     padding-bottom reserves the band for the fixed nav that parks below it */
  padding-top: clamp(40px, 6vh, 76px);
  /* just the capsule pill parks below now (no link bar) — tighter band */
  padding-bottom: clamp(92px, 12vh, 132px);
}
/* Hero aura field — offwhite paper flooded with big, soft gradient-noise circles
   (magenta core → warm amber glow), anchored to the supplied BG reference. Sits
   over the paper base, below the content. The circles hold still; the only motion
   is a few px of relaxed drift toward the cursor — JS writes a normalised offset
   (-1..1 from the hero centre) to --ax/--ay and each blob eases toward it on a
   long cubic-bezier, each at its own depth, so they lean but never reach it. */
.hero-aura {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
}
.aura-blob {
  position: absolute;
  left: 50%; top: 50%;
  translate: -50% -50%;                       /* centring + ambient wander (keyframes) */
  border-radius: 50%;
  filter: blur(36px);
  /* cursor parallax rides transform on a long relaxed bezier; the ambient wander
     rides translate (independent property) so the two compose without fighting. */
  transition: transform 2.2s cubic-bezier(0.22, 1, 0.36, 1);
  will-change: transform, translate;
}
/* magenta core — upper-centre, the densest mass */
.aura-blob--1 {
  width: 60vmin; height: 72vmin;
  top: 40%; left: 50%;
  background: radial-gradient(circle at 50% 46%,
    rgba(231, 44, 138, 0.86) 0%,
    rgba(231, 44, 138, 0.56) 32%,
    rgba(231, 44, 138, 0.18) 54%,
    rgba(231, 44, 138, 0) 70%);
  transform: translate3d(calc(var(--ax, 0) * 46px), calc(var(--ay, 0) * 40px), 0);
  animation: auraDrift1 26s ease-in-out infinite;
}
/* warm amber glow — lower, blooms out from beneath the magenta. the lead mover. */
.aura-blob--2 {
  width: 74vmin; height: 66vmin;
  top: 57%; left: 51%;
  background: radial-gradient(circle at 50% 50%,
    rgba(255, 146, 64, 0.88) 0%,
    rgba(255, 162, 84, 0.50) 36%,
    rgba(255, 188, 116, 0.16) 60%,
    rgba(255, 190, 120, 0) 76%);
  transform: translate3d(calc(var(--ax, 0) * 74px), calc(var(--ay, 0) * 58px), 0);
  animation: auraDrift2 32s ease-in-out infinite;
}
/* rose bridge — softens the magenta→amber seam, a violet lift up top */
.aura-blob--3 {
  width: 50vmin; height: 56vmin;
  top: 34%; left: 47%;
  background: radial-gradient(circle at 50% 50%,
    rgba(214, 60, 156, 0.42) 0%,
    rgba(232, 96, 150, 0.22) 44%,
    rgba(232, 96, 150, 0) 70%);
  transform: translate3d(calc(var(--ax, 0) * 32px), calc(var(--ay, 0) * 28px), 0);
  animation: auraDrift3 22s ease-in-out infinite;
}
/* ambient wander — each blob meanders a few percent of its own box, slow and
   calm, on its own clock + path so the field breathes and never reads as fixed.
   0%/100% return to dead-centre (-50% -50%) so cursor parallax stays symmetric. */
@keyframes auraDrift1 {
  0%   { translate: -50% -50%; }
  25%  { translate: -56% -45%; }
  50%  { translate: -47% -57%; }
  75%  { translate: -44% -48%; }
  100% { translate: -50% -50%; }
}
@keyframes auraDrift2 {
  0%   { translate: -50% -50%; }
  30%  { translate: -43% -55%; }
  60%  { translate: -55% -44%; }
  100% { translate: -50% -50%; }
}
@keyframes auraDrift3 {
  0%   { translate: -50% -50%; }
  33%  { translate: -57% -53%; }
  66%  { translate: -45% -46%; }
  100% { translate: -50% -50%; }
}
/* static paper grain — the site's canonical fractal-noise tooth (the earlier hero
   recipe: coarser 0.8 noise), held still over the auras (no film shimmer). The
   noise is biased toward white so a low-opacity multiply lays a fine organic paper
   tooth — present + tactile — without graying the bright paper. (Overlay reads as
   flat on a near-white field; multiply on white-biased noise is what makes the
   tooth visible.) Sits above the auras, below the content. */
.hero-grain {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  opacity: 0.24;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='hg'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='0.45' intercept='0.55'/%3E%3CfeFuncG type='linear' slope='0.45' intercept='0.55'/%3E%3CfeFuncB type='linear' slope='0.45' intercept='0.55'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23hg)'/%3E%3C/svg%3E");
  background-size: 140px 140px;
}
@media (prefers-reduced-motion: reduce) {
  .aura-blob { transition: none; animation: none; }
}
@media (max-width: 900px) {
  /* touch — auras keep the calm ambient wander but no cursor drift; lighter blur
     for fill-rate. Sized to the tall portrait frame (vw wide × vh tall) so the
     glow fills the poster behind the vertical wordmark, magenta high → amber low. */
  .aura-blob { filter: blur(28px); transition: none; }
  .aura-blob--1 { width: 88vw; height: 46vh; top: 40%; }
  .aura-blob--2 { width: 94vw; height: 44vh; top: 63%; }
  .aura-blob--3 { width: 72vw; height: 38vh; top: 32%; }
}
.hero-stage { position: relative; z-index: 2; }

/* Wordmark hugs the very top; it does not grow, so the free space below it
   becomes the reel band. */
.hero-stage {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: clamp(4px, 0.6vw, 10px);
  width: 100%;
  flex: 0 0 auto;
}

.hero-mark {
  overflow: visible;
  /* full-bleed to the viewport edges so the wordmark fills the top of the
     hero (letude.group scale) */
  width: calc(100% + 2 * var(--gutter));
  margin-left: calc(-1 * var(--gutter));
  margin-right: calc(-1 * var(--gutter));
  /* the SVG box carries ~12vh of empty headroom above the caps; trim it so the
     centred stack reads tight (poster rides just beneath the mark) */
  margin-top: clamp(-44px, -4.5vh, -22px);
  /* fixed mask for the ghost's bottom→top slide-in (itsjay.us hero). Horizontal
     generous so the cursive swash + serif write-on are never side-clipped. */
  clip-path: inset(-35% -2% -1% -2%);
}
.hero-wordmark-svg {
  display: block;
  width: 100%;
  height: auto;
  /* large centred wordmark — fills the viewport width (raised cap lets width win) */
  max-height: 64vh;
  overflow: visible;
}

/* SIGNATURE REVEAL (desktop single wordmark only) — anchored to
   codepen.io/ghepting/pen/vYLqgr (a mark signing itself). The Anton ghost
   "develops" in (machine layer, arrives as a block); the serif soul + cursive
   M "write on" left→right via a clip sweep (human/ink layer). The thesis in
   one gesture. Final state is the locked wordmark — only the arrival changes.
   Scoped to .hero-wordmark-svg so the mobile .hwm-row-svg stack is untouched. */
/* The Anton ghost slides up from below, clipped by .hero-mark's fixed mask
   (itsjay.us "rise-into-mask" reveal) — the machine layer arrives as a block. */
.hero-wordmark-svg .hwm-back {
  translate: 0 112%;
  transition: translate 1300ms var(--ease-entrance) 200ms;
}
.is-hero-ready .hero-wordmark-svg .hwm-back { translate: 0 0; }
/* The serif soul + cursive M write on left→right — a longer held-slow start,
   then a quick decisive pickup (cubic-bezier x1 high / x2 low). */
.hero-wordmark-svg .hwm-front {
  clip-path: inset(-40% 102% -60% -12%);
  transition: clip-path 1500ms cubic-bezier(0.85, 0, 0.2, 1) 440ms;
}
.is-hero-ready .hero-wordmark-svg .hwm-front {
  clip-path: inset(-40% -12% -60% -12%);
}
@media (prefers-reduced-motion: reduce) {
  /* big slides off (vestibular-safe), but keep a gentle opacity fade so the mark
     still *arrives* rather than hard-popping */
  .hero-wordmark-svg .hwm-back { transition: none; translate: 0 0; }
  .hero-wordmark-svg .hwm-front { transition: none; clip-path: none; }
  .hero-wordmark-svg { opacity: 0; transition: opacity 700ms var(--ease-entrance) 120ms; }
  .is-hero-ready .hero-wordmark-svg { opacity: 1; }
}

/* Mobile-only stacked wordmark — MOMENTUS split MO·ME·NT·US, 4 uniform rows
   (shown < 901px; the single rotated mark is desktop-only). */
.hero-mark-stack { display: none; }
/* the stack rises in as one unit once the hero is armed (its rows aren't covered
   by the .hero-wordmark-svg signature reveal, which is scoped to the single mark) */
@media (prefers-reduced-motion: no-preference) {
  html.js .hero-mark-stack {
    opacity: 0;
    transform: translateY(20px);
    transition: opacity 900ms var(--ease-entrance) 140ms, transform 900ms var(--ease-entrance) 140ms;
  }
  html.js.is-hero-ready .hero-mark-stack { opacity: 1; transform: none; }
}
/* JANUARY-format wordmark: tall-sans ghost behind, serif soul in front */
.hwm-back {
  font-family: 'Anton', var(--type-display);
  font-weight: 400;
  letter-spacing: 0;
  fill: rgba(20, 18, 14, 0.17);
}
.hwm-front {
  font-family: var(--type-em);
  font-weight: 400;
  font-style: normal;
  letter-spacing: 0;
  fill: var(--ink);
}
.hwm-initial {
  font-family: 'Pinyon Script', cursive;
  font-style: normal;
  font-size: 1.32em;
}

/* POSTER LINE — fills the hero's lower band so the frame reads as a finished
   poster: tagline lower-left, supporting subtext tucked lower-right. Desktop only;
   the mobile rotated wordmark owns the whole frame (hidden below 900px). */
/* CENTRED EDITORIAL STACK — tagline directly under the masthead, the minimal
   subtext centred beneath it. One quiet column; the poster reads top-to-bottom. */
.hero-poster {
  position: relative;
  z-index: 2;
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: clamp(8px, 0.9vh, 13px);
  width: 100%;
}
.hero-tagline {
  font-family: var(--type-display);
  /* smaller — a poster tagline, not a second headline */
  font-size: clamp(18px, 2vw, 32px);
  font-weight: 500;
  line-height: 1.04;
  letter-spacing: -0.018em;
  color: var(--ink);
}
/* hero accent is ink (matches the wordmark serif), not the red blast. The serif
   italic is optically lighter than the Hanken 500 around it, so size it up a hair
   to balance the two registers across the line. */
.hero-tagline .em { color: var(--ink); font-size: 1.14em; font-weight: 400; }
/* locked subtext — S4 editorial split: two uppercase tracked fragments pushed to
   the poster's edges (justified masthead band), light display weight. */
.hero-subtext {
  display: flex;
  width: 100%;
  justify-content: space-between;
  gap: 2rem;
  font-family: var(--type-display);
  text-transform: uppercase;
  letter-spacing: 0.16em;
  font-weight: 400;
  font-size: clamp(10px, 0.8vw, 12.5px);
  line-height: 1.5;
  color: rgba(20, 18, 14, 0.58);
}
/* the poster rises in after the wordmark has written on (consistent with the
   site's "enter from below" grammar) */
@media (prefers-reduced-motion: no-preference) {
  html.js .hero-poster {
    opacity: 0;
    transform: translateY(22px);
    transition: opacity 820ms var(--ease-entrance) 920ms, transform 820ms var(--ease-entrance) 920ms;
  }
  html.js.is-hero-ready .hero-poster { opacity: 1; transform: none; }
}

/* ------------------------------------------------------------
   HERO UPPER BLOCK (desktop ≥901px) — corner meta + a subtle tumbling wireframe
   object + the purposeful subtext, filling the top while the wordmark anchors the
   base (bymonolog grammar). Hidden < 901px, where the stacked wordmark owns the frame.
   ------------------------------------------------------------ */
.hero-top { display: none; }
@media (min-width: 901px) {
  /* bottom-anchored wordmark layout — tighter top/bottom bands so the whole hero
     (upper block + base wordmark) fits one viewport for the pinned co-stage */
  .hero {
    justify-content: space-between;
    padding-top: clamp(34px, 4.4vh, 56px);
    padding-bottom: clamp(48px, 6.5vh, 78px);
  }
  .hero-top {
    position: relative; z-index: 2;
    display: flex; flex-direction: column; align-items: center;
    width: 100%;
    gap: clamp(16px, 3.2vh, 42px);
    padding-top: clamp(2px, 0.8vh, 12px);
  }
}
.hero-meta {
  width: 100%;
  display: flex; align-items: center; justify-content: space-between;
  color: var(--c-mute);
  font-size: var(--fs-mono); letter-spacing: 0.08em; text-transform: uppercase;
}
.hero-status { display: inline-flex; align-items: center; gap: 0.66em; }
.hero-status-dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--ink);
  animation: heroPulse 2.8s ease-out infinite;
}
@keyframes heroPulse {
  0%   { box-shadow: 0 0 0 0 rgba(20, 18, 14, 0.42); }
  70%  { box-shadow: 0 0 0 7px rgba(20, 18, 14, 0); }
  100% { box-shadow: 0 0 0 0 rgba(20, 18, 14, 0); }
}

/* SUBTLE 3D OBJECT — a thin wireframe cube tumbling slowly (CSS 3D, no dependency).
   Ink edges on the blast; a small ink node marks a vertex. */
.hero-object {
  --cube: clamp(54px, 6vw, 86px);
  width: var(--cube); height: var(--cube);
  perspective: 640px;
  margin-bottom: clamp(10px, 1.6vh, 22px);
}
.hero-cube {
  position: relative; width: 100%; height: 100%;
  transform-style: preserve-3d;
  transform: rotateX(-22deg) rotateY(-28deg);
  animation: heroTumble 24s linear infinite;
}
@keyframes heroTumble {
  from { transform: rotateX(-22deg) rotateY(-28deg) rotateZ(0deg); }
  to   { transform: rotateX(338deg) rotateY(332deg) rotateZ(360deg); }
}
.cube-face {
  position: absolute; inset: 0;
  border: 1.4px solid rgba(20, 18, 14, 0.6);
  background: rgba(20, 18, 14, 0.014);
}
.cube-fr { transform: translateZ(calc(var(--cube) / 2)); }
.cube-bk { transform: rotateY(180deg) translateZ(calc(var(--cube) / 2)); }
.cube-rt { transform: rotateY(90deg) translateZ(calc(var(--cube) / 2)); }
.cube-lt { transform: rotateY(-90deg) translateZ(calc(var(--cube) / 2)); }
.cube-tp { transform: rotateX(90deg) translateZ(calc(var(--cube) / 2)); }
.cube-bm { transform: rotateX(-90deg) translateZ(calc(var(--cube) / 2)); }
.cube-node {
  position: absolute; top: -3.5px; left: -3.5px;
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--ink);
  transform: translateZ(calc(var(--cube) / 2));
}
@media (prefers-reduced-motion: reduce) {
  .hero-status-dot { animation: none; }
  .hero-cube { animation: none; transform: rotateX(-24deg) rotateY(-32deg); }
}

/* ------------------------------------------------------------
   SITE NAV — the ONLY navigation on every page: a single bottom-centre capsule
   (the hamburger pill), always visible, that opens the fullscreen numbered menu.
   ------------------------------------------------------------ */
.sitenav {
  position: fixed;
  left: 0; right: 0;
  bottom: clamp(22px, 3.4vh, 40px);
  z-index: 80;
  display: grid;
  justify-items: center;
  align-items: end;
  pointer-events: none;
  opacity: 0;
  transition: opacity 700ms var(--ease-entrance) 820ms;
}
.is-hero-ready .sitenav { opacity: 1; }

/* one item — the capsule — centred in the grid cell */
.sitenav-capsule { grid-area: 1 / 1; }

/* PILL — a frosted dark capsule reading "Menu" (a tiny two-bar mark + the word), so
   the single nav on every page is unmistakable and never missed. Opens the menu. */
.sitenav-capsule {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 11px;
  height: 52px;
  padding: 0 26px;
  border-radius: 999px;
  background: rgba(20, 18, 14, 0.86);
  border: 1px solid rgba(248, 246, 241, 0.18);
  -webkit-backdrop-filter: blur(14px) saturate(1.2);
  backdrop-filter: blur(14px) saturate(1.2);
  color: var(--paper);
  pointer-events: auto;
  opacity: 1;
  transition: border-color var(--t-hover) var(--ease-hover), background var(--t-hover) var(--ease-hover);
}
.sitenav-capsule:hover { border-color: rgba(248, 246, 241, 0.42); background: rgba(20, 18, 14, 0.94); }
/* the word — the prominent label */
.capsule-label {
  font-family: var(--type-display);
  font-weight: 600;
  font-size: 15px;
  letter-spacing: 0.01em;
  color: var(--paper);
  transition: color var(--t-hover) var(--ease-hover);
}
.sitenav-capsule:hover .capsule-label { color: var(--blast); }
/* tiny two-bar mark, left of the word (affordance only) */
.capsule-bars { position: relative; width: 16px; height: 8px; flex: 0 0 auto; }
.capsule-bars::before,
.capsule-bars::after {
  content: "";
  position: absolute; left: 0; right: 0;
  height: 1.6px;
  background: var(--paper);
  transition: background var(--t-hover) var(--ease-hover);
}
.capsule-bars::before { top: 1px; }
.capsule-bars::after  { bottom: 1px; }
.sitenav-capsule:hover .capsule-bars::before,
.sitenav-capsule:hover .capsule-bars::after { background: var(--blast); }

/* ------------------------------------------------------------
   MENU OVERLAY — fullscreen editorial index. Huge placeholder numbers,
   minimal link text. Items rise in on open (the hero ghost grammar).
   Opened by the capsule; closed by ✕ / backdrop / Esc.
   ------------------------------------------------------------ */
.menu {
  position: fixed;
  inset: 0;
  z-index: 95;
  pointer-events: none;
  visibility: hidden;
  opacity: 0;
  transition: opacity 500ms var(--ease-entrance),
              visibility 0s linear 500ms;
}
.menu[data-open="true"] {
  pointer-events: auto;
  visibility: visible;
  opacity: 1;
  transition: opacity 500ms var(--ease-entrance);
}
.menu-bg { position: absolute; inset: 0; background: #100f0d; }
.menu-bg::before {
  content: "";
  position: absolute; inset: 0;
  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.8' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  opacity: 0.05;
  mix-blend-mode: overlay;
}
.menu-close {
  position: absolute;
  top: 32px; right: var(--gutter);
  width: 56px; height: 56px;
  border-radius: 50%;
  border: 1px solid rgba(248, 246, 241, 0.2);
  display: flex; align-items: center; justify-content: center;
  z-index: 2;
  transition: transform var(--t-hover) var(--ease-hover), border-color var(--t-hover) var(--ease-hover);
}
.menu-close:hover { transform: rotate(90deg); border-color: var(--blast); }
.menu-close-x { position: relative; width: 18px; height: 18px; }
.menu-close-x::before,
.menu-close-x::after {
  content: ""; position: absolute; left: 50%; top: 50%;
  width: 18px; height: 1.5px; background: var(--paper);
}
.menu-close-x::before { transform: translate(-50%, -50%) rotate(45deg); }
.menu-close-x::after  { transform: translate(-50%, -50%) rotate(-45deg); }

.menu-list {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: clamp(4px, 1.4vh, 22px);
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 0 var(--gutter);
  z-index: 1;
}
.menu-item {
  display: flex;
  align-items: baseline;
  gap: clamp(18px, 2.4vw, 48px);
  color: var(--paper);
  width: -moz-max-content;
  width: max-content;
  max-width: 100%;
  transform: translateY(0.5em);
  opacity: 0;
}
.menu[data-open="true"] .menu-item {
  transform: translateY(0);
  opacity: 1;
  transition: transform 760ms var(--ease-entrance), opacity 620ms var(--ease-entrance);
}
.menu[data-open="true"] .menu-item:nth-child(1) { transition-delay: 120ms; }
.menu[data-open="true"] .menu-item:nth-child(2) { transition-delay: 190ms; }
.menu[data-open="true"] .menu-item:nth-child(3) { transition-delay: 260ms; }
.menu[data-open="true"] .menu-item:nth-child(4) { transition-delay: 330ms; }
.menu[data-open="true"] .menu-item:nth-child(5) { transition-delay: 400ms; }
.menu-num {
  font-family: var(--type-em);
  font-style: italic;
  font-size: clamp(60px, 12vw, 168px);
  font-weight: 400;
  letter-spacing: -0.02em;
  line-height: 0.9;
  color: rgba(248, 246, 241, 0.9);
  flex: 0 0 auto;
  transition: color 340ms var(--ease-hover), transform 340ms var(--ease-hover);
}
.menu-label {
  font-family: var(--type-display);
  font-size: clamp(15px, 1.4vw, 20px);
  font-weight: 600;
  letter-spacing: 0.01em;
  opacity: 0.7;
  transition: opacity 340ms var(--ease-hover), transform 340ms var(--ease-hover);
}
.menu-item:hover .menu-num { color: var(--blast); transform: translateX(6px); }
.menu-item:hover .menu-label { opacity: 1; transform: translateX(10px); }

/* the hero wordmark echoed bottom-right — Anton ghost in the hero red, serif soul in white.
   Sized so the serif cap-height tracks the giant menu numerals; width scales naturally.
   Scoped to .menu so it wins the position over the later .layer-mark rule. */
.menu .menu-mark {
  position: absolute;
  right: var(--gutter);
  bottom: clamp(26px, 6vh, 70px);
  z-index: 1;
}
/* serif white, sans ghost in hero red — same offset/appear grammar as the marks */
.menu-mark .layer-soul {
  font-size: clamp(38px, 6.6vw, 92px);    /* a bit smaller than the ghost */
  color: var(--paper);
}
.menu-mark .layer-ghost {
  font-size: clamp(44px, 8.2vw, 112px);   /* dominant, tall + thin (inherits scale) */
  color: var(--blast);
  /* the mark is anchored to the right gutter; right-align the wider ghost to the
     mark (= the serif's right edge) so it extends LEFT into open space rather than
     bleeding off the right edge of the screen */
  left: auto;
  right: 0;
  transform-origin: right bottom;
}

@media (prefers-reduced-motion: reduce) {
  .menu-item { transform: none; opacity: 1; transition: none; }
}

/* ============================================================
   REVEAL STAGE — the red hero holds; then on scroll the black ABOUT panel
   slides UP over it while the hero shrinks into the nav-black field behind
   (GSAP pin + scrub). The statement reveals line-by-line, then a sheet of
   opacity slides down it. On touch / no-motion the two simply stack.
   The pinned LAYOUT is set here by media query (no first-paint flash); JS
   only drives the animation.
   ============================================================ */
.reveal { position: relative; background: var(--paper); }
.reveal-hero {
  position: relative;
  min-height: 100vh;
  transform-origin: 50% 50%;
}
.reveal-hero .hero { min-height: 100vh; }
.reveal-about { position: relative; }

@media (min-width: 901px) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  html.js .reveal { height: 100vh; overflow: clip; }
  html.js .reveal-hero {
    position: absolute; inset: 0; z-index: 1;
    min-height: 0; height: 100%;
    will-change: transform;
  }
  html.js .reveal-about {
    position: absolute; left: 0; right: 0; top: 0; height: 100%; z-index: 4;
    /* emptied on fine-pointer desktop (the about panel is relocated into the
       co-stage); held transparent so only the paper blinds + hero read here. */
    opacity: 0;
    will-change: opacity;
  }
  /* HORIZONTAL-BLIND WIPE — paper strips (built in JS) sweep across the red hero
     left→right, cascaded top→bottom, papering it over before the co-stage's white
     about pins in beneath (paper→paper, seamless). They sit above the hero (z1). */
  html.js .about-blinds { position: absolute; inset: 0; z-index: 2; pointer-events: none; }
  html.js .about-blind {
    position: absolute; left: 0; width: 100%;
    background: var(--paper);
    transform: scaleX(0);
    transform-origin: left center;
    will-change: transform;
  }
}

/* ============================================================
   CO-STAGE — fine-pointer desktop hand-off: ABOUT → PROCESS as one pinned
   horizontal gesture. The shell + panels are built and relocated here by JS
   (bootCoStage) only on fine-pointer desktop, so these rules sit inert on
   mobile / wide-touch where the stage is never created.
   ============================================================ */
.costage { position: relative; background: var(--paper); }
.costage-pin { position: relative; height: 100vh; overflow: clip; }
.costage .cs-hero,
.costage .cs-about,
.costage .cs-process { position: absolute; inset: 0; }
.costage .cs-hero    { z-index: 3; will-change: opacity; }
.costage .cs-about   { z-index: 2; will-change: transform; }
.costage .cs-process { z-index: 1; background: var(--paper); will-change: transform; }
/* the relocated panels fill the stage exactly */
/* the statement sits TRUE-CENTRED (V + H) in the co-stage; the continuous rail
   line frames it from above-left and exits the right edge at the process line's
   start height — it routes AROUND the measured text block, never through it */
.costage .cs-about .about-h {
  min-height: 100%; height: 100%;
  align-items: center;
}
.costage .cs-process .process { height: 100%; }
.costage .cs-process .process-pin { height: 100%; }

/* ABOUT — the locked positioning paragraph; ink type on the paper field */
.about-h {
  background: var(--paper);
  color: var(--ink);
  min-height: 100vh;
  height: 100%;
  display: flex;
  align-items: center;
  padding: clamp(72px, 12vw, 140px) var(--gutter);
  position: relative;
  overflow: hidden;
}
.about-h-inner { max-width: 1100px; margin: 0 auto; position: relative; z-index: 1; }
.about-h-inner .sec-index {
  display: block;
  margin-bottom: clamp(28px, 4vw, 52px);
  color: rgba(20, 18, 14, 0.45);
}
.about-h-statement {
  font-family: var(--type-display);
  font-size: clamp(26px, 3.1vw, 50px);
  font-weight: 400;
  line-height: 1.3;
  letter-spacing: -0.018em;
  color: var(--ink);
}
/* serif emphasis — ink, italic; on the paper field */
.about-h-statement .em { color: var(--ink); font-size: 1.08em; }

/* STRONG ENTRANCE — the statement is split into masked visual lines (JS). Each
   line's text rises from below, then a sheet of opacity slides down them, top to
   bottom. On desktop the reveal-stage pin drives both via GSAP scrub (JS owns the
   transform + opacity). Here we define only the mask structure; the mobile path
   uses a CSS rise on .is-in (so the two never fight over the same property). */
.about-line { display: block; overflow: hidden; padding-bottom: 0.06em; }
.about-line-in { display: block; }

/* statement entrance — the index + masked lines rise on `.is-in` (a self-running
   cascade, per-line delay set in JS). Same on every breakpoint now: desktop fires
   it from the reveal pin's tl.call once the panel settles, mobile/touch from IO. */
.js .about-h .sec-index {
  opacity: 0;
  transform: translateY(0.7em);
  transition: opacity 640ms var(--ease-entrance), transform 640ms var(--ease-entrance);
}
.js .about-h.is-in .sec-index { opacity: 1; transform: none; }
.js .about-line-in { translate: 0 110%; transition: translate 1050ms var(--ease-entrance); }
.js .about-h.is-in .about-line-in { translate: 0 0; }
@media (prefers-reduced-motion: reduce) {
  .about-h .sec-index { opacity: 1; transform: none; transition: none; }
  .about-line-in { translate: 0 0; transition: none; }
}

/* RED CIRCLE — a big signature disc (fine-pointer desktop only; built in JS inside
   bootCoStage). It animates in with the statement, sweeps left→right on scroll
   inverting whatever text it overlaps to white (a moving mask: a red disc + a
   clipped white copy of the statement, layered over the black original — inside the
   circle you read red + white, outside paper + black). At the right edge it shrinks
   into a small dot at the process line's start, then rides the line's drawing head to
   the end. Three CSS vars (--rc-x/--rc-y/--rc-r) set on the pin drive the clip circle
   for BOTH the disc and the white copy, so they stay perfectly in sync. The old
   .about-brush rail host is no longer used. */
.about-brush { display: none; }

.rc-layer {
  position: absolute; inset: 0;
  z-index: 5;
  pointer-events: none;
  opacity: 0;
  will-change: opacity;
}
.rc-disc {
  position: absolute; inset: 0;
  background: var(--blast);
  -webkit-clip-path: circle(var(--rc-r, 0px) at var(--rc-x, 0px) var(--rc-y, 0px));
  clip-path: circle(var(--rc-r, 0px) at var(--rc-x, 0px) var(--rc-y, 0px));
  will-change: clip-path;
}
.rc-white {
  position: absolute; inset: 0;
  -webkit-clip-path: circle(var(--rc-r, 0px) at var(--rc-x, 0px) var(--rc-y, 0px));
  clip-path: circle(var(--rc-r, 0px) at var(--rc-x, 0px) var(--rc-y, 0px));
  will-change: clip-path;
}
.rc-white .about-h { height: 100%; min-height: 100%; align-items: center; background: transparent; }
.rc-white .about-h-statement,
.rc-white .about-h-statement .em { color: #fff; }
.rc-white .about-h-inner .sec-index { color: rgba(255, 255, 255, 0.65); }
@media (prefers-reduced-motion: reduce) {
  .rc-layer { display: none; }
}

/* ============================================================
   MOBILE RED CIRCLE — the vertical echo of the desktop disc. A fixed overlay
   (built in JS by bootMobileCircle): a red disc + white clones of the about
   statement and the process paragraph, all clipped to ONE travelling circle.
   The disc sweeps top→bottom through the about, on into the process, shrinks to a
   dot, settles at the vertical line's start, then rides the drawing head down to
   the end. Whatever the circle covers reads white (the inverted-text mask), the
   rest stays ink — the same gesture as desktop, turned vertical. Mobile-only.
   ============================================================ */
.rcm-layer {
  position: fixed; inset: 0;
  z-index: 40;                 /* above section content, below nav (80) / menu (95) */
  pointer-events: none;
  opacity: 0;
  will-change: opacity;
}
.rcm-disc {
  position: fixed; inset: 0;
  background: var(--blast);
  -webkit-clip-path: circle(var(--rcm-r, 0px) at var(--rcm-x, -200px) var(--rcm-y, -200px));
  clip-path: circle(var(--rcm-r, 0px) at var(--rcm-x, -200px) var(--rcm-y, -200px));
  will-change: clip-path;
}
/* white text clones — JS sets each one's top/left/width + its own clip circle every
   frame so it stays pixel-glued to the (scrolling) source text underneath it */
.rcm-white {
  position: fixed;
  margin: 0;
  pointer-events: none;
  will-change: clip-path, top, left;
}
.rcm-white, .rcm-white * { color: #fff !important; }
@media (min-width: 901px) { .rcm-layer { display: none; } }
@media (prefers-reduced-motion: reduce) { .rcm-layer { display: none; } }

/* ============================================================
   CIRCLE JOURNEY — the same travelling-disc mask, carried past the co-stage into the
   WORK index and on down to the footer (built in JS by bootCircleJourney). A fixed red
   disc + a white clone of the work-list, both clipped to ONE circle that grows in over
   the names, inverts each to white as it passes (left-biased), then condenses to a dot,
   rides the left edge through the proof, and dissolves into the red footer. All viewports.
   ============================================================ */
.cj-layer {
  position: fixed; inset: 0;
  z-index: 6;                  /* above section content, below nav (80) / cursor / menu (95) */
  pointer-events: none;
  opacity: 0;
  will-change: opacity;
}
.cj-disc {
  position: fixed; inset: 0;
  background: var(--blast);
  -webkit-clip-path: circle(var(--cj-r, 0px) at var(--cj-x, -200px) var(--cj-y, -200px));
  clip-path: circle(var(--cj-r, 0px) at var(--cj-x, -200px) var(--cj-y, -200px));
  will-change: clip-path;
}
/* white clone — re-glued over the (scrolling) work-list every frame, clipped to the
   same circle so the covered names read white inside the disc */
.cj-white {
  position: fixed;
  margin: 0;
  pointer-events: none;
  will-change: clip-path, top, left;
}
.cj-white,
.cj-white .wr-1,
.cj-white .wr-2,
.cj-white .work-row-no,
.cj-white .work-row-cat,
.cj-white .work-row-arr { color: #fff !important; }
.cj-white .work-row,
.cj-white.work-list { border-color: rgba(255, 255, 255, 0.22) !important; }
@media (prefers-reduced-motion: reduce) { .cj-layer { display: none; } }

/* ============================================================
   SECTION HEADS — shared rhythm across sections
   ============================================================ */

.sec-head {
  padding: clamp(80px, 12vw, 160px) var(--gutter) clamp(40px, 6vw, 80px);
  max-width: var(--wrap);
  margin: 0 auto;
}
.sec-index {
  display: inline-block;
  margin-bottom: 24px;
  color: var(--c-accent);
}
.sec-title {
  font-family: var(--type-em);
  font-size: var(--fs-h2);
  font-weight: 400;
  font-style: normal;
  line-height: 1.0;
  letter-spacing: -0.01em;
  max-width: 1100px;
  color: var(--c-fg);
}
.sec-lead {
  margin-top: clamp(20px, 2.5vw, 32px);
  font-family: var(--type-body);
  font-size: var(--fs-lead);
  max-width: 640px;
  opacity: 0.78;
}

/* ------------------------------------------------------------
   LAYER-HEAD — the JANUARY-format heading: serif soul in front,
   ghosted heavy-sans echo behind (set per-heading via data-ghost)
   ------------------------------------------------------------ */
.layer-head { position: relative; isolation: isolate; }
.layer-head::before {
  content: attr(data-ghost);
  position: absolute;
  left: 0;
  top: 0;
  white-space: nowrap;
  font-family: var(--type-display);
  font-weight: 500;                        /* thinner ghost */
  font-style: normal;
  letter-spacing: -0.05em;
  line-height: inherit;
  color: var(--c-fg);
  opacity: 0.1;
  /* ghost sits up + left and stretched taller so the serif overhangs it
     bottom-right (the unseen tall-thin grotesk echo) */
  transform: translate(-0.06em, -0.05em) scale(0.97, 1.14);
  transform-origin: left bottom;
  z-index: -1;
  pointer-events: none;
}
/* APPEAR — the layered title writes on left→right (the hero serif's clip-write),
   ghost and serif together. Triggered by .is-in (IO on scroll). The horizontal
   insets are generous (-45%) so the heavy-sans ghost — which is wider than the
   serif soul it sits behind — is never clipped on the right edge. */
.layer-head {
  clip-path: inset(-40% 101% -40% -45%);
  transition: clip-path 1200ms cubic-bezier(0.85, 0, 0.2, 1) 120ms;
}
.layer-head.is-in { clip-path: inset(-40% -45% -40% -45%); }
.cta-line[data-line="1"].is-in { transition-delay: 160ms; }
.cta-line[data-line="2"].is-in { transition-delay: 300ms; }
@media (prefers-reduced-motion: reduce) {
  .layer-head { clip-path: none; transition: none; }
}

/* ============================================================
   WORK — Locomotive-style index: monumental serif names, JANUARY-format head
   ============================================================ */

.work {
  padding-bottom: clamp(80px, 12vw, 160px);
}

/* JANUARY-format section mark — Anton ghost towers behind, Instrument Serif soul
   nests low and in front (the hero-wordmark overlap); first letter of each word cursive. */
.work-head {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: clamp(80px, 12vw, 160px) var(--gutter) clamp(40px, 5.5vw, 78px);
}
.layer-mark {
  position: relative;
  display: inline-block;
  line-height: 0.9;
  /* mask for the ghost's rise — the bottom edge (-9%) masks the rise-from-below;
     the horizontal insets are generous (-45%) so the heavy-sans ghost (wider than
     the serif soul that defines this box's width) is never clipped on the right. */
  clip-path: inset(-48% -45% -9% -45%);
}
/* serif soul — in front, nudged down + right so a small bit overhangs the
   ghost on the bottom-right (the layered drop) */
.layer-soul {
  position: relative;
  display: block;
  font-family: var(--type-em);
  font-style: normal;
  font-weight: 400;
  font-size: clamp(44px, 6.9vw, 96px);     /* a bit smaller than the ghost */
  letter-spacing: -0.012em;
  line-height: 0.9;
  color: var(--c-fg);
  z-index: 1;
  white-space: nowrap;
  /* nudged further down + right so a clear bit overhangs the ghost bottom-right */
  transform: translate(0.12em, 0.18em);
}
/* thinner heavy-sans ghost — taller (vertical stretch + condense), lighter weight,
   the dominant background letterform the serif nests against (the unseen grotesk) */
.layer-ghost {
  position: absolute;
  left: 0;
  top: 0;
  display: block;
  font-family: var(--type-display);
  font-weight: 500;                        /* thinner */
  font-size: clamp(52px, 8.4vw, 116px);    /* larger — dominant layer */
  letter-spacing: -0.045em;                /* tighter → reads taller/condensed */
  line-height: 0.84;
  color: rgba(20, 18, 14, 0.13);
  white-space: nowrap;
  z-index: 0;
  pointer-events: none;
  transform: scale(0.96, 1.16);            /* condense + stretch tall */
  transform-origin: left bottom;
}
/* cursive first letter of each word (the hero wordmark's Pinyon initial) */
.lc {
  font-family: 'Pinyon Script', cursive;
  font-style: normal;
  font-size: 1.34em;
}

/* APPEAR — hero grammar: the ghost rises up from below into the mask; the serif
   writes on left→right. Triggered by .is-in (IO on scroll, or menu-open). */
.layer-ghost {
  translate: 0 120%;
  transition: translate 1150ms var(--ease-entrance) 120ms;
}
.layer-mark.is-in .layer-ghost { translate: 0 0; }
.layer-soul {
  clip-path: inset(-42% 102% -42% -45%);
  transition: clip-path 1300ms cubic-bezier(0.85, 0, 0.2, 1) 360ms;
}
.layer-mark.is-in .layer-soul { clip-path: inset(-42% -45% -42% -45%); }
@media (prefers-reduced-motion: reduce) {
  .layer-ghost { translate: 0 0; transition: none; }
  .layer-soul { clip-path: none; transition: none; }
}

.work-list {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 0 var(--gutter);
  border-top: 1px solid var(--c-line);
}

.work-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: clamp(16px, 3vw, 48px);
  padding: clamp(18px, 2.6vw, 38px) 0;
  border-bottom: 1px solid var(--c-line);
  position: relative;
  overflow: hidden;                 /* masks the cat slide-up + arrow rise */
  transition: opacity var(--t-hover) var(--ease-hover);
}
/* hovered row asserts; siblings recede (Locomotive index behaviour) */
.work-list:hover .work-row { opacity: 0.4; }
.work-list:hover .work-row:hover { opacity: 1; }

/* lead group — a bracketed mono index sits ahead of the name (basement.studio
   case-index register). The index holds still while the name shifts on hover. */
.work-row-lead {
  display: inline-flex;
  align-items: baseline;
  gap: clamp(16px, 2vw, 40px);
  min-width: 0;
}
.work-row-no {
  flex: 0 0 auto;
  color: var(--c-mute);
  font-size: clamp(12px, 1vw, 14px);
  transform: translateY(-0.2em);
}

/* name — serif-italic firm word + thin-sans descriptor */
.work-row-name {
  display: inline-flex;
  align-items: baseline;
  gap: 0.32em;
  line-height: 1.0;
  transition: transform 240ms var(--ease-hover);
}
.work-row:hover .work-row-name {
  transform: translateX(clamp(8px, 1.4vw, 22px));
}
.wr-1 {
  font-family: var(--type-em);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(30px, 5.1vw, 75px);   /* matched to the sans — serif reads optically smaller */
  letter-spacing: -0.01em;
  color: var(--c-fg);
}
.wr-2 {
  font-family: var(--type-display);
  font-weight: 400;                 /* thin — regular sans, never bold */
  font-size: clamp(30px, 5vw, 74px);
  letter-spacing: -0.02em;
  color: var(--c-fg);
}

/* industry — masked single line; rises up and out on hover (about-line grammar) */
.work-row-cat-mask {
  flex: 0 0 auto;
  display: inline-block;
  overflow: hidden;
  line-height: 1.5;
}
.work-row-cat {
  display: inline-block;
  color: var(--c-mute);
  white-space: nowrap;
  transform: translateY(0);
  transition: transform 720ms var(--ease-entrance), opacity 460ms var(--ease-hover);
}
.work-row:hover .work-row-cat {
  transform: translateY(-130%);
  opacity: 0;
}

/* redirect arrow — fills the full row height, rises up from below into the row mask */
.work-row-arr-mask {
  position: absolute;
  right: 0;
  top: 0;
  bottom: 0;
  width: auto;
  aspect-ratio: 1 / 1;
  overflow: hidden;
  pointer-events: none;
}
.work-row-arr {
  display: block;
  width: 100%;
  height: 100%;
  color: var(--c-accent);
  transform: translateY(110%);
  transition: transform 720ms var(--ease-entrance);
}
.work-row:hover .work-row-arr {
  transform: translateY(0);
}

/* The project's cover follows the pointer as the cursor itself (see .cursor--media
   in the cursor block + bootCursor in script.js) — no on-row peek element. */

/* ALL-WORKS — text-only link in the hero-nav register, right-aligned, redirect arrow */
.work-more {
  max-width: var(--wrap);
  margin: clamp(26px, 3.6vw, 52px) auto 0;
  padding: 0 var(--gutter);
  display: flex;
  justify-content: flex-end;
}
.work-more-link {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  font-family: var(--type-em);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(22px, 2.4vw, 36px);
  line-height: 1;
  color: var(--c-fg);
  position: relative;
  transition: gap var(--t-hover) var(--ease-hover);
}
.work-more-link:hover { gap: 0.78em; }
.work-more-arr {
  width: 0.62em;
  height: 0.62em;
  flex: 0 0 auto;
  color: var(--c-accent);
}
/* underline-draw, left→right (hero-nav grammar) */
.work-more-link::after {
  content: "";
  position: absolute;
  left: 0; right: 100%;
  bottom: -0.16em;
  height: 1.5px;
  background: var(--c-accent);
  transition: right var(--t-hover) var(--ease-hover);
}
.work-more-link:hover::after { right: 0; }

/* ============================================================
   PROOF — a monumental client pull-quote on the nav-black field (the About voice
   register, echoed late), then three supporting quotes. Social proof as editorial,
   not a logo wall.
   ============================================================ */

.proof {
  background: var(--ink);
  color: var(--paper);
  --c-accent: #ff6a5e;            /* the blast lifts to a warm coral on the dark field (deck D) */
  --c-mute: rgba(248, 246, 241, 0.5);
  --c-line: rgba(248, 246, 241, 0.16);
  padding: clamp(112px, 19vh, 230px) var(--gutter);
  display: flex;
}
.proof-inner {
  width: 100%; max-width: var(--wrap); margin: 0 auto;
  display: flex; flex-direction: column; align-items: center;
}
.proof .sec-index { display: block; align-self: flex-start; color: var(--c-accent); margin-bottom: clamp(48px, 9vh, 120px); }

/* QUOTE IN CALM — the quotes share one grid cell and crossfade; the wrapper holds
   the tallest so the centred column never jumps as voices change. */
.proof-calm {
  width: 100%; max-width: 60rem; margin: 0 auto;
  display: flex; flex-direction: column; align-items: center; text-align: center;
}
.proof-quotes {
  list-style: none; margin: 0; padding: 0;
  position: relative; width: 100%;
  min-height: clamp(230px, 32vh, 340px);
  display: grid;
}
.proof-q {
  grid-area: 1 / 1;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: clamp(22px, 3vw, 40px);
  opacity: 0; visibility: hidden;
  transition: opacity 680ms var(--ease-entrance);
  pointer-events: none;
}
.proof-q.is-active { opacity: 1; visibility: visible; }
.proof-quote {
  font-family: var(--type-em);
  font-weight: 400;
  font-size: clamp(26px, 3.4vw, 50px);
  line-height: 1.22;
  letter-spacing: -0.012em;
  color: var(--paper);
  margin: 0; max-width: 22ch;
}
.proof-quote .em { font-style: italic; color: var(--c-accent); }
.proof-cite {
  font-family: var(--type-mono); font-style: normal;
  font-size: var(--fs-mono); letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--c-mute);
  display: flex; flex-direction: column; gap: 5px;
}
.proof-cite-role { color: rgba(248, 246, 241, 0.34); }

/* TIMED STATUS DOTS — a dot per testimonial; the active dot widens to a pill and a
   fill sweeps left→right over the dwell (driven per-frame in JS), then hands to the
   next. Hidden without JS (decorative without the timer). */
.proof-dots { display: flex; align-items: center; gap: 12px; margin-top: clamp(46px, 8vh, 100px); }
html:not(.js) .proof-dots { display: none; }
.proof-dot {
  appearance: none; -webkit-appearance: none; border: 0; padding: 0;
  height: 7px; width: 7px; border-radius: 99px;
  background: rgba(248, 246, 241, 0.22);
  position: relative; overflow: hidden;
  transition: width 560ms var(--ease-entrance), background 560ms var(--ease-entrance);
}
.proof-dot.is-active { width: 46px; background: rgba(248, 246, 241, 0.16); }
.proof-dot-fill {
  position: absolute; inset: 0;
  transform: scaleX(0); transform-origin: left center;
  background: var(--c-accent); border-radius: inherit;
}

/* ============================================================
   PROCESS — anchored to 2025.unseen.co — a pinned HORIZONTAL scroll.
   The statement reveals word-by-word (scroll-driven opacity), the five
   gates of the engine scroll past as cards. JS pins + drives the track.
   ============================================================ */

.process {
  /* PAPER — white field, ink type, a black hand-drawn timeline (unseen.co) */
  --c-accent: var(--ink);
  --c-mute: rgba(20, 18, 14, 0.5);
  --c-line: rgba(20, 18, 14, 0.16);
  background: var(--paper);
  color: var(--ink);
  position: relative;
  overflow: hidden;                 /* clips the horizontal track on either edge */
}

.process-pin {
  height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: clamp(22px, 3vh, 42px);
  padding: clamp(34px, 5vh, 72px) 0;
}

.process-head {
  max-width: var(--wrap);
  width: 100%;
  margin: 0 auto;
  padding: 0 var(--gutter);
}
.process-head .sec-index { color: var(--ink); opacity: 0.55; display: inline-block; margin-bottom: clamp(16px, 2.2vw, 28px); }
.process-statement {
  font-family: var(--type-display);
  font-size: clamp(22px, 2.8vw, 46px);
  font-weight: 400;
  line-height: 1.18;
  letter-spacing: -0.02em;
  color: var(--ink);
  max-width: 26ch;
}
.process-statement .em { color: var(--ink); font-family: var(--type-em); font-style: italic; font-size: 1.05em; }
/* per-word opacity reveal — JS wraps each word in .pw and scrubs 0.2 → 1 */
.process-statement .pw { display: inline-block; }

/* TIMELINE TRACK — fixed-width band; the SVG line + the stage nodes ride it. JS
   translates it left across the pin and inks the draw-path in left→right. */
.process-viewport { width: 100%; overflow: hidden; }
.process-track {
  position: relative;
  width: 3240px;
  height: 520px;
  will-change: transform;
}
.process-line {
  position: absolute;
  left: 0; top: 0;
  width: 3240px;
  height: 520px;
  overflow: visible;
  pointer-events: none;
}
.pline-base, .pline-draw { fill: none; stroke-linecap: round; stroke-linejoin: round; }
/* the PATH AHEAD — a faint dotted guide (unseen.co's dashed preview of where the
   line is heading), always visible under the inked trail */
.pline-base { stroke: rgba(20, 18, 14, 0.3); stroke-width: 1.5; stroke-dasharray: 0.5 11; }
/* the TRAIL ALREADY TRAVELLED — thin solid ink, drawn left→right by the scrub */
.pline-draw { stroke: var(--ink); stroke-width: 1.8; }

/* MOBILE timeline — a JS-built vertical flowing line (.process-line-v) with minimal
   dots (.pnode-v) on it. Only exists on mobile (built/removed by the matchMedia in
   bootProcess); reuses the dotted-base / solid-draw pline styling above. */
.process-line-v { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; z-index: 0; }
.pnode-v { fill: var(--ink); }

.pstage {
  position: absolute;
  left: var(--x);
  width: clamp(244px, 20vw, 300px);
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.pstage--top { top: 0; }
.pstage--bot { top: 340px; }
/* the node dot sits on the line; a hair-thin stem links the card to it */
.pnode { position: absolute; left: 50%; width: 10px; height: 10px; border-radius: 50%; background: var(--ink); transform: translateX(-50%); }
.pnode::before { content: ""; position: absolute; left: 50%; width: 1.4px; background: rgba(20, 18, 14, 0.28); transform: translateX(-50%); }
/* node sits on the flowy line at this stage's x (--ny = line-y within the stage
   box); the stem (--stem) bridges node→card. Values are authored per-stage in the
   markup so each dot meets the hand-drawn path. */
.pstage--top .pnode { top: var(--ny, 175px); }
.pstage--top .pnode::before { bottom: 100%; height: var(--stem, 28px); }   /* stem up to the card */
.pstage--bot .pnode { top: var(--ny, -15px); }
.pstage--bot .pnode::before { top: 100%; height: var(--stem, 15px); }      /* stem down to the card */

.pstage-no { color: var(--ink); opacity: 0.55; font-size: 13px; }
.pstage-name {
  font-family: var(--type-display);
  font-size: clamp(22px, 2.1vw, 32px);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1;
  color: var(--ink);
}
.pstage-body {
  font-family: var(--type-body);
  font-size: clamp(14px, 0.95vw, 16px);
  line-height: 1.45;
  color: var(--ink);
  opacity: 0.72;
}

/* ============================================================
   CTA — letude-red blast bookend, layered statement, one action
   ============================================================ */

.cta {
  /* BLAST — letude red flood (bookends the hero), black bold type, ink accents */
  --c-bg: var(--blast);
  --c-fg: var(--ink);
  --c-accent: var(--ink);
  --c-mute: rgba(20, 18, 14, 0.6);
  background: var(--blast);
  color: var(--ink);
  padding: clamp(120px, 16vw, 200px) var(--gutter);
  position: relative;
  overflow: hidden;
}
/* CTA living grain — the same reactive sand-grain canvas as the hero, painted in
   JS over the red blast so the page bookends itself with one consistent texture */
.cta-tex { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 0; pointer-events: none; }

.cta-stage {
  position: relative;
  z-index: 1;
  max-width: var(--wrap);
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 40px;
  align-items: flex-start;
}

.cta-eyebrow { color: var(--c-accent); }

.cta-display {
  font-family: var(--type-em);
  font-size: clamp(64px, 11vw, 168px);
  font-weight: 400;
  font-style: normal;
  line-height: 0.96;
  letter-spacing: -0.02em;
  color: var(--c-fg);
}
.cta-line {
  display: block;
  overflow: visible;
}
.cta-line[data-line="1"] { padding-left: clamp(40px, 8vw, 140px); }
.cta-line[data-line="2"] { padding-left: clamp(80px, 16vw, 280px); }

.cta-actions {
  display: flex;
  flex-direction: column;
  gap: 16px;
  margin-top: clamp(36px, 4.5vw, 64px);
}

.cta-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  align-self: flex-start;
  background: var(--c-accent);
  color: var(--c-bg);
  padding: 22px 40px;
  border-radius: 999px;
  font-family: var(--type-display);
  font-weight: 600;
  font-size: clamp(20px, 1.8vw, 26px);
  letter-spacing: -0.01em;
  transition: transform var(--t-hover) var(--ease-hover);
}
.cta-button:hover { transform: translateY(-2px); }

.cta-anchor { color: var(--c-mute); }

/* On the red blast (.cta) the button is an ink slab; on the black close card it's a
   red pill. Both flip to a cream fill on hover (arrow goes ink) — never colour-on-colour. */
.cta .cta-button {
  background: var(--ink);
  color: var(--paper);
  --btn-fill: var(--paper);
  --btn-arr-color: var(--ink);
}
.close .cta-button {
  background: var(--blast);
  color: var(--paper);
  --btn-fill: var(--paper);
  --btn-arr-color: var(--ink);
}

/* ------------------------------------------------------------
   BUTTON HOVER — shared by every pill button (.btn, .cta-button). One synced
   left→right sweep on the serif-wipe bezier: a contrast colour fills the pill
   (scaleX from the left) while, locked to the same advancing edge, the label
   clip-wipes OUT and a right-arrow clip-wipes IN over the new colour. Because the
   arrow is masked behind the same edge as the fill, it is never visible before the
   sweep reaches it — it rides in WITH the colour, not after. Fill + arrow colours
   are theme vars so red-on-red sections can flip to a cream fill.
   ------------------------------------------------------------ */
.btn, .cta-button { position: relative; overflow: hidden; isolation: isolate; }
/* the colour panel that wipes across the pill (clipped to the pill by overflow) */
.btn::before, .cta-button::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--btn-fill, var(--blast));
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 560ms cubic-bezier(0.85, 0, 0.2, 1);
  z-index: 0;
}
.btn:hover::before, .cta-button:hover::before { transform: scaleX(1); }

/* label + arrow ride above the fill */
.btn-swap { position: relative; z-index: 1; display: inline-flex; align-items: center; justify-content: center; line-height: 1; }
.btn-label {
  display: inline-block;
  clip-path: inset(0 -4% 0 -4%);
  transition: clip-path 560ms cubic-bezier(0.85, 0, 0.2, 1);
}
.btn-arr {
  position: absolute;
  left: 0; right: 0; top: 50%;
  transform: translateY(-50%);
  display: block;
  text-align: center;
  line-height: 1;
  color: var(--btn-arr-color, var(--ink));
  clip-path: inset(0 101% 0 -4%);
  transition: clip-path 560ms cubic-bezier(0.85, 0, 0.2, 1);
}
.btn:hover .btn-label,
.cta-button:hover .btn-label { clip-path: inset(0 0 0 101%); }
.btn:hover .btn-arr,
.cta-button:hover .btn-arr { clip-path: inset(0 -4% 0 -4%); }

@media (prefers-reduced-motion: reduce) {
  .btn::before, .cta-button::before, .btn-label, .btn-arr { transition: none; }
}

/* ============================================================
   FOOTER — anchored to basement.studio — a megafooter: full-bleed wordmark band
   over a hairline, a say-hello / newsletter block beside a big nav index, then
   socials + copyright on the base line. Shared between the home + project pages.
   ============================================================ */

.foot {
  /* DARK slab — the heavy close after the light page (unseen rotates to near-black) */
  --c-bg: var(--slab);
  --c-fg: var(--paper);
  --c-accent: var(--blast);
  --c-mute: rgba(248, 246, 241, 0.5);
  --c-line: rgba(248, 246, 241, 0.12);
  background: var(--slab);
  color: var(--paper);
  position: relative;
  overflow: hidden;
}

/* full-bleed wordmark band — the basement title slab, sat on a hairline */
.foot-mega {
  padding: clamp(48px, 7vw, 104px) var(--gutter) clamp(28px, 3vw, 44px);
  border-bottom: 1px solid var(--c-line);
}
.foot-megaword {
  display: block;
  font-family: var(--type-display);
  font-size: clamp(72px, 17vw, 280px);
  font-weight: 700;
  line-height: 0.82;
  letter-spacing: -0.05em;
  color: var(--c-bone);
  white-space: nowrap;
}
.foot-mega-mark {
  font-size: 0.16em;
  font-weight: 500;
  letter-spacing: 0;
  vertical-align: super;
  color: var(--c-mute);
}

/* body — say-hello/newsletter (left) beside a big nav index (right) */
.foot-body {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: clamp(48px, 7vw, 96px) var(--gutter) clamp(40px, 5vw, 72px);
  display: grid;
  grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr);
  gap: clamp(40px, 6vw, 96px);
  align-items: start;
}

.foot-say { display: flex; flex-direction: column; align-items: flex-start; gap: clamp(18px, 2vw, 28px); max-width: 16ch; }
.foot-say-eyebrow { color: var(--c-mute); }
/* the emotional anchor — a big serif invitation that links to contact (writes on) */
.foot-say-line {
  font-family: var(--type-em);
  font-style: normal;
  font-size: clamp(34px, 4.4vw, 68px);
  font-weight: 400;
  line-height: 1.02;
  letter-spacing: -0.02em;
  color: var(--c-fg);
  position: relative;
}
.foot-say-line .em { color: var(--blast); font-style: italic; }
.foot-say-line::after {
  content: "";
  position: absolute;
  left: 0; right: 100%;
  bottom: -0.04em;
  height: 2px;
  background: var(--blast);
  transition: right 460ms var(--ease-hover);
}
.foot-say-line:hover::after { right: 0; }

.foot-mail {
  font-family: var(--type-em);
  font-style: italic;
  font-size: clamp(20px, 1.8vw, 28px);
  color: var(--c-fg);
  position: relative;
  align-self: flex-start;
}
.foot-mail::after {
  content: "";
  position: absolute;
  left: 0; right: 100%;
  bottom: -0.1em;
  height: 1.5px;
  background: var(--blast);
  transition: right var(--t-hover) var(--ease-hover);
}
.foot-mail:hover::after { right: 0; }

/* big nav index — basement's oversized footer menu */
.foot-nav {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: clamp(2px, 0.4vw, 8px);
  justify-self: end;
}
.foot-nav-link {
  font-family: var(--type-display);
  font-size: clamp(30px, 3.4vw, 52px);
  font-weight: 500;
  line-height: 1.04;
  letter-spacing: -0.025em;
  color: var(--c-fg);
  opacity: 0.82;
  transition: opacity var(--t-hover) var(--ease-hover), transform var(--t-hover) var(--ease-hover);
}
.foot-nav-link:hover { opacity: 1; transform: translateX(8px); color: var(--blast); }

/* studio status — a thin mono row of facts (location · availability · year) */
.foot-meta {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 0 var(--gutter) clamp(30px, 4vw, 48px);
  display: flex;
  flex-wrap: wrap;
  gap: 10px clamp(28px, 4vw, 56px);
}
.foot-meta-item {
  font-family: var(--type-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--c-mute);
  display: inline-flex;
  align-items: baseline;
  gap: 0.7em;
}
.foot-meta-item::before { content: ""; width: 16px; height: 1.5px; background: var(--blast); align-self: center; }

/* base line — socials + copyright */
.foot-base {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: clamp(24px, 3vw, 36px) var(--gutter) clamp(28px, 3.5vw, 44px);
  border-top: 1px solid var(--c-line);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px 40px;
  flex-wrap: wrap;
}
.foot-social { display: inline-flex; align-items: center; gap: clamp(16px, 1.6vw, 28px); flex-wrap: wrap; }
.foot-social-link {
  font-family: var(--type-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--c-fg);
  opacity: 0.7;
  transition: opacity var(--t-hover) var(--ease-hover), color var(--t-hover) var(--ease-hover);
}
.foot-social-link:hover { opacity: 1; color: var(--blast); }

.foot-copy { color: var(--c-mute); opacity: 0.85; font-size: 11px; }

/* ============================================================
   CLOSING PANEL — two thin strips (anchored to inspirux.com). CARD 1 (.close-card) is the
   BLACK strip (foreground): the demoted lead, the EMAIL MEGA-LINK, the conversion button,
   and the studio index (meta / nav / socials) + copy. CARD 2 (.close-reveal) is the thin
   RED MOMENTUS® strip pinned to the viewport bottom (position: sticky) and sitting BEHIND
   the black (z1 < z2): as the black strip scrolls up and off, the pinned red is uncovered
   from beneath it — the parallax reveal (red holds still, black moves). Ink on red.
   NOTE: .close must stay overflow:visible or the sticky would pin to .close, not the
   viewport. The wordmark's side-bleed is clipped by .close-reveal's own overflow instead.
   Reuses .cta-actions / .cta-button / .cta-tex from the CTA block above.
   ============================================================ */
.close { position: relative; background: var(--ink); }

/* CARD 1 — black thin strip (foreground over the red). Paper-on-ink, content height. */
.close-card {
  position: relative;
  z-index: 2;
  background: var(--ink);
  color: var(--paper);
  --c-fg: var(--paper);
  --c-accent: var(--blast);
  --c-mute: rgba(248, 246, 241, 0.5);
  --c-line: rgba(248, 246, 241, 0.16);
}
.close-inner {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: var(--wrap);
  margin: 0 auto;
  padding: clamp(64px, 9vw, 116px) var(--gutter) clamp(52px, 7vw, 92px);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

/* LEAD — one demoted line above the email mega-link (the "moves" motif, kept calm) */
.close-lead {
  font-family: var(--type-display);
  font-weight: 600;
  font-size: clamp(22px, 2.4vw, 36px);
  line-height: 1.06;
  letter-spacing: -0.02em;
  color: var(--c-fg);
  margin-top: clamp(14px, 1.6vw, 22px);
}
.close-lead .em { font-family: var(--type-em); font-style: italic; font-weight: 400; color: var(--blast); }

/* EMAIL MEGA-LINK — the closing line is the address (inspirux.com) */
.close-mega {
  display: flex;
  align-items: baseline;
  gap: clamp(10px, 1.6vw, 28px);
  margin-top: clamp(18px, 2.6vw, 38px);
  max-width: 100%;
  color: var(--c-fg);
  font-family: var(--type-display);
  font-weight: 700;
  font-size: clamp(28px, 5.6vw, 84px);
  line-height: 0.94;
  letter-spacing: -0.035em;
}
.close-mega-text { position: relative; }
.close-mega-text::after {
  content: ""; position: absolute; left: 0; right: 100%; bottom: 0.04em;
  height: clamp(3px, 0.4vw, 7px); background: var(--paper);
  transition: right 380ms var(--ease-hover);
}
.close-mega:hover .close-mega-text::after { right: 0; }
.close-mega-arr { font-size: 0.5em; transition: transform var(--t-hover) var(--ease-hover); }
.close-mega:hover .close-mega-arr { transform: translate(0.12em, -0.12em); }

/* ACTIONS — keep the conversion button + reply anchor */
.close .cta-actions { margin-top: clamp(30px, 4vw, 52px); }

/* INDEX — meta + nav + socials over a hairline */
.close-essentials {
  width: 100%;
  margin-top: clamp(48px, 7vw, 88px);
  padding-top: clamp(32px, 4.4vw, 52px);
  border-top: 1px solid var(--c-line);
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(32px, 5vw, 80px);
  align-items: start;
}
.close-meta { display: flex; flex-direction: column; gap: 10px; }
.close-meta-item {
  font-family: var(--type-mono); font-size: var(--fs-mono); letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--c-mute); display: inline-flex; align-items: baseline; gap: 0.7em;
}
.close-meta-item::before { content: ""; width: 16px; height: 1.5px; background: var(--paper); align-self: center; opacity: 0.5; }

.close-nav { display: flex; flex-direction: column; align-items: flex-start; gap: clamp(2px, 0.4vw, 8px); }
.close-nav-link {
  font-family: var(--type-display); font-size: clamp(20px, 1.9vw, 28px); font-weight: 500;
  line-height: 1.14; letter-spacing: -0.02em; color: var(--c-fg); opacity: 0.82;
  transition: opacity var(--t-hover) var(--ease-hover), transform var(--t-hover) var(--ease-hover);
}
.close-nav-link:hover { opacity: 1; transform: translateX(8px); }

.close-social { display: flex; flex-direction: column; align-items: flex-start; gap: clamp(8px, 1vw, 12px); }
.close-social-link {
  font-family: var(--type-mono); font-size: var(--fs-mono); letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--c-fg); opacity: 0.72; transition: opacity var(--t-hover) var(--ease-hover);
}
.close-social-link:hover { opacity: 1; }

.close-copy { color: var(--c-mute); font-size: 11px; margin-top: clamp(36px, 5vw, 60px); }

/* CARD 2 — thin red strip pinned to the viewport bottom (sticky), BEHIND the black
   (z1 < z2). The black slides up and off, uncovering it from underneath. The full
   MOMENTUS® wordmark bleeds the side edges; overflow:hidden clips the bleed. Hero grain. */
.close-reveal {
  position: sticky;
  bottom: 0;
  z-index: 1;
  height: clamp(200px, 34vh, 400px);
  background: var(--blast);
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
}
.close-reveal .cta-tex { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 1; pointer-events: none; }
.close-megaword {
  position: relative;
  z-index: 1;
  display: block;
  font-family: var(--type-display);
  font-size: clamp(72px, 17vw, 320px);
  font-weight: 700;
  line-height: 0.8;
  letter-spacing: -0.05em;
  color: var(--ink);
  white-space: nowrap;
  text-align: center;
  will-change: transform;
}
.close-mega-mark { font-size: 0.14em; font-weight: 500; letter-spacing: 0; vertical-align: super; color: rgba(20, 18, 14, 0.55); }

/* ============================================================
   PAGE TRANSITION — an espresso curtain wipes UP to cover on internal navigation,
   then lifts away on arrival (JS-driven). Fails open: scaleY(0) default never
   hides content. html.mo-arriving paints an instant cover before first paint so
   the arrival lift has no flash; JS hands that off to the real curtain.
   ============================================================ */
/* The slab + wordmark TRANSLATE as one rigid unit (never scaled — scaling squished
   the mark and, with a markless pre-paint cover, made MOMENTUS vanish then reappear
   at the nav seam). LEAVE: slab rises from below to cover (translateY 100%→0). ARRIVE:
   it keeps rising up and off (0→-100%). The mark travels with it, undistorted, present
   the whole time. The static element + html.mo-arriving covering-state mean the slab
   (with the mark) is already painted on first paint of the arriving page — no flash,
   no gap. */
.page-curtain {
  position: fixed;
  inset: 0;
  z-index: 9990;
  background: #100f0d;
  transform: translateY(100%);   /* parked below — covers nothing (fail-open default) */
  pointer-events: none;
  display: flex;
  align-items: center;
  justify-content: center;
  will-change: transform;
}
.page-curtain.is-cover { pointer-events: auto; }
/* arrival: the inline-head script adds .mo-arriving before first paint, so the slab is
   already covering (with the mark) the instant the new page paints — JS then lifts it */
html.mo-arriving .page-curtain { transform: translateY(0); }
.page-curtain-mark {
  font-family: var(--type-display);
  font-weight: 700;
  font-size: clamp(28px, 5vw, 64px);
  letter-spacing: -0.04em;
  color: var(--c-bone);
  opacity: 0.92;
}
.page-curtain-mark sup { font-size: 0.32em; font-weight: 500; vertical-align: super; opacity: 0.7; }

/* COUNT-UP — the animated numeral keeps tabular rhythm so the digits don't jitter
   the layout as they tick up */
.count-num { font-variant-numeric: tabular-nums; }

/* ============================================================
   RESPONSIVE — tablet + mobile collapses
   ============================================================ */

@media (max-width: 900px) {
  .hero {
    padding-top: clamp(52px, 8vh, 84px);
    padding-bottom: clamp(92px, 14vh, 124px);
    justify-content: flex-start;
    align-items: flex-start;
  }

  /* MOBILE HERO — the single wordmark rotated −90° to run VERTICALLY up the LEFT
     edge, the tops of the letters facing the left of the frame; it fills the height
     and owns the frame. Tagline + subtext drop to the lower-right, clearing the
     column. The container is rotated (origin top-left) so the SVG's own signature
     reveal still plays inside it. (Desktop keeps the upright centred masthead.) */
  .hero-stage { position: static; display: block; width: 100%; }
  .hero-mark-stack { display: none; }      /* the stacked rows are retired on mobile */
  .hero-mark {
    position: absolute;
    top: clamp(24px, 5vh, 60px);           /* sits high in the frame */
    left: clamp(-4px, 0vw, 2px);           /* letter-tops kiss the left edge */
    width: 76vh;                           /* long axis = viewport height → fills the frame */
    margin: 0;
    transform-origin: 0 0;
    transform: rotate(-90deg) translateX(-100%);   /* vertical, letter-tops facing left */
    clip-path: inset(-35% -2% -1% -2%);
    overflow: visible;
    z-index: 2;
    pointer-events: none;
  }
  .hero-mark .hero-wordmark-svg {
    position: static;
    width: 100%;
    height: auto;
    max-height: none;
    transform: none;
  }

  /* tagline + subtext drop to the lower-right, right-aligned and narrowed so the
     block sits clear to the right of the rotated spine and its cursive-M flourish */
  .hero-poster {
    display: flex;
    flex-direction: column;
    position: absolute;
    right: var(--gutter);
    bottom: clamp(132px, 21vh, 184px);
    left: auto;
    width: min(46vw, 192px);
    margin: 0;
    align-items: flex-end;
    text-align: right;
  }
  .hero-tagline { font-size: clamp(19px, 5vw, 28px); text-align: right; }
  .hero-subtext { font-size: clamp(12px, 3.1vw, 14px); max-width: 24ch; text-align: right; }

  /* raise the capsule clear of the phone browser's bottom bar / home indicator
     (a too-low fixed bar gets hidden behind it) — honour the safe-area inset */
  .sitenav { bottom: max(30px, calc(env(safe-area-inset-bottom) + 20px)); }

  /* the fullscreen menu is the primary mobile nav — tighten the type */
  .menu-num { font-size: clamp(48px, 17vw, 96px); }
  .menu-item { gap: clamp(14px, 4vw, 28px); }

  /* MOBILE HERO→ABOUT — reduced-motion / no-JS fallback: plain stacked flow (hero,
     then about, then process). The blind-wipe STAGE (sticky overlap) is layered on
     top of this only under (prefers-reduced-motion: no-preference) below, so motion
     can never trap the about beneath an un-faded hero. */
  .reveal { height: auto; overflow: visible; position: relative; }
  .reveal-hero {
    position: relative;
    inset: auto;
    top: auto;
    height: 100vh;
    min-height: 100vh;
    transform: none;
    z-index: 2;
  }
  .reveal-about {
    position: relative;
    inset: auto;
    top: auto;
    margin-top: 0;
    transform: none;
    z-index: 1;
  }
  .about-h {
    min-height: 100vh;
    padding-top: clamp(72px, 16vw, 120px);
    padding-bottom: clamp(72px, 16vw, 120px);
  }
  .about-h-statement { font-size: clamp(22px, 6vw, 34px); line-height: 1.32; }

  .work-head .layer-soul { font-size: clamp(32px, 10vw, 60px); }
  /* left-anchor the ghost on the narrow frame so the first letter isn't clipped */
  .work-head .layer-ghost { font-size: clamp(38px, 11.6vw, 70px); left: 0; right: auto; transform: none; }
  .work-row { flex-direction: column; align-items: flex-start; gap: 6px; overflow: visible; }
  .work-row-cat-mask { overflow: visible; align-self: flex-start; }
  .work-row-arr-mask { display: none; }   /* arrow reveal is hover-only → desktop */
  .wr-1 { font-size: clamp(26px, 7.1vw, 47px); }
  .wr-2 { font-size: clamp(26px, 7vw, 46px); }
  /* menu wordmark shrinks on the small frame */
  .menu-mark .layer-soul { font-size: clamp(30px, 9vw, 56px); }
  .menu-mark .layer-ghost { font-size: clamp(38px, 11.4vw, 70px); }

  /* proof — sticky stack keeps working; cards go single-column (image over text),
     a short portrait so each card stays under the viewport and still pins */
  .proof-stack { gap: clamp(28px, 9vw, 56px); }
  .proof-card { grid-template-columns: 1fr; gap: clamp(16px, 5vw, 26px); align-items: start; }
  .proof-card:nth-child(1) { top: clamp(74px, 11vh, 100px); }
  .proof-card:nth-child(2) { top: calc(clamp(74px, 11vh, 100px) + 14px); }
  .proof-card:nth-child(3) { top: calc(clamp(74px, 11vh, 100px) + 28px); }
  .proof-card:nth-child(4) { top: calc(clamp(74px, 11vh, 100px) + 42px); }
  .proof-portrait { aspect-ratio: 16 / 10; }
  .proof-quote { max-width: none; }

  /* PROCESS — a VERTICAL timeline: the paragraph sits on top, a centred rail draws
     top→bottom on scroll, and the checkpoints alternate left / right of it, each
     with its node bridging in to the rail. (Desktop is the horizontal scrub.) */
  .process { overflow: visible; }
  .process-pin { height: auto; display: block; padding: clamp(64px, 14vw, 110px) 0; }
  .process-head { margin-bottom: clamp(20px, 5vw, 34px); }
  .process-statement { max-width: none; font-size: clamp(24px, 6.4vw, 38px); }
  .process-statement .pw { opacity: 1 !important; }
  /* the viewport carries the gutter so the track can be full-width (rail at true 50%) */
  .process-viewport { overflow: visible; padding: 0 var(--gutter); }
  .process-line { display: none; }   /* the horizontal SVG is desktop-only */

  .process-track {
    position: relative;
    display: flex;
    flex-direction: column;
    width: auto; height: auto;
    transform: none !important;
    gap: clamp(24px, 6.5vw, 40px);
    padding: clamp(18px, 5vw, 30px) 0 0;
  }

  /* CHECKPOINTS — each card to one side, clearing the centred flowing line; the
     minimal dots (SVG .pnode-v) sit ON the line, no connectors. */
  .pstage {
    position: relative;
    left: auto; top: auto;
    width: calc(50% - 30px);
    transform: none;
    z-index: 1;
    border: 1px solid var(--c-line);
    border-radius: 6px;
    padding: clamp(15px, 4vw, 22px);
    background: var(--c-surface);
  }
  .pstage--top { align-self: flex-start; }   /* left of the line */
  .pstage--bot { align-self: flex-end; }      /* right of the line */
  .pnode { display: none; }                   /* dots are the SVG circles on the line */

  /* the gate cards rise in on scroll (desktop has its own scrubbed draw-reveal) */
  html.js .process .pstage { opacity: 0; transform: translateY(24px); transition: opacity 720ms var(--ease-entrance), transform 720ms var(--ease-entrance); }
  html.js .process .pstage.is-in { opacity: 1; transform: none; }

  .cta-line[data-line="1"] { padding-left: 20px; }
  .cta-line[data-line="2"] { padding-left: 40px; }

  /* footer — wordmark + nav stack; nav left-aligns; base line wraps */
  .foot-body { grid-template-columns: 1fr; gap: clamp(40px, 10vw, 64px); }
  .foot-say { max-width: none; }
  .foot-nav { justify-self: start; gap: 4px; }
  .foot-base { gap: 18px 28px; }

  /* closing panel — strips stay thin; email shrinks to fit; index stacks to one column */
  .close-inner { padding: clamp(72px, 18vw, 110px) var(--gutter) clamp(56px, 14vw, 80px); }
  .close-reveal { height: clamp(130px, 24vh, 220px); }
  .close-mega { font-size: clamp(26px, 7.4vw, 44px); }
  .close-essentials { grid-template-columns: 1fr; gap: clamp(32px, 8vw, 48px); }
  .close-nav { gap: 4px; }
}

/* MOBILE INTRO STAGE — the desktop blind-wipe takeover, vertical-aware. The hero and
   the about are stacked sticky inside ONE 200vh stage (.reveal): the hero on top (z2),
   the about beneath (z1), overlapped via the negative margin so it shares the hero's
   sticky slot. bootMobileIntro wipes paper blinds across the hero top→bottom on scroll,
   fades the hero away behind the closed blinds, and the white ABOUT reads beneath
   (paper→paper) — its statement rising in exactly as on desktop. After the stage the
   whole block scrolls on into the process. Gated to JS + motion so reduced-motion /
   no-JS keep the plain stacked flow above (the about can never be trapped under the
   hero). The red disc (bootMobileCircle) then sweeps top→bottom across the about. */
@media (max-width: 900px) and (prefers-reduced-motion: no-preference) {
  html.js .reveal { height: 460vh; }   /* taller stage = the hero→about sequence breathes over much more scroll */
  html.js .reveal-hero { position: sticky; top: 0; z-index: 2; }
  html.js .reveal-about {
    position: sticky; top: 0;
    height: 100vh; min-height: 100vh;
    margin-top: -100vh;          /* overlap the hero's sticky slot — sits directly beneath it */
    z-index: 1;
  }
  html.js .about-h { height: 100vh; }
  html.js .reveal-hero .about-blinds { position: absolute; inset: 0; z-index: 3; pointer-events: none; }
  html.js .reveal-hero .about-blind {
    position: absolute; left: 0; width: 100%;
    background: var(--paper);
    transform: scaleX(0);
    transform-origin: left center;
    will-change: transform;
  }
}

/* motion-sensitive users — the mobile process cards never hide (placed last so it
   wins the cascade over the mobile rise-in base state above) */
@media (prefers-reduced-motion: reduce) {
  html.js .process .pstage { opacity: 1; transform: none; transition: none; }
}

/* ============================================================
   MHERO — living ink-matrix hero (replaces the former pinned co-stage hero).
   Anchored to "Momentus new BG.mp4". A RED field is the default; the SAME dot
   choreography is rendered into two stacked canvases (#mx-red — black ink on red,
   #mx-dark — warm-white light on night) and cross-dissolved on hover/toggle so the
   hero "changes lighting" without the dots ever jumping. Ported from deck-5; every
   rule is scoped under .mhero so it never touches the rest of the site, and dark is
   keyed on .mhero.dark (not body) so it stays contained to the hero. Placed last to
   win the cascade over the old .hero-stage/.hwm-* rules left inert above.
   ============================================================ */
.mhero {
  --display: 'Hanken Grotesk', system-ui, sans-serif;
  --em: 'Instrument Serif', 'Georgia', serif;
  --mono: 'JetBrains Mono', 'SF Mono', ui-monospace, monospace;
  --x: .6s;                                    /* cross-dissolve duration (red ⇄ dark) */
  position: relative; width: 100%; height: 100vh; overflow: hidden; isolation: isolate;
  display: flex; align-items: center; justify-content: center;
  padding: clamp(20px, 5vh, 60px) var(--gutter);
  background: var(--blast); font-family: var(--display);
  transition: background var(--x) ease;
}
.mhero.dark { background: #060607; }

.mhero #mx-red, .mhero #mx-dark {
  position: absolute; inset: 0; z-index: 0; width: 100%; height: 100%; display: block;
  pointer-events: none; transition: opacity var(--x) ease;
}
.mhero #mx-red  { opacity: 1; }
.mhero #mx-dark { opacity: 0; }
.mhero.dark #mx-red  { opacity: 0; }
.mhero.dark #mx-dark { opacity: 1; }

/* hero wordmark — override the old co-stage hero rules; the mark reads statically
   here (no rise / write-on reveal), as approved in deck-5 */
.mhero .hero-stage {
  position: relative; z-index: 2;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 0; width: 100%; max-width: 1500px; flex: 0 1 auto;
}
.mhero .hero-mark {
  overflow: visible;
  width: calc(100% + 2 * var(--gutter));
  margin: 0 calc(-1 * var(--gutter));
  clip-path: none;
}
.mhero .hero-wordmark-svg { display: block; width: 100%; height: auto; max-height: 52vh; overflow: visible; opacity: 1; }
.mhero .hero-wordmark-svg .hwm-back  { translate: 0 0; transition: fill var(--x) ease; }
.mhero .hero-wordmark-svg .hwm-front { clip-path: none; transition: fill var(--x) ease; }
.mhero .hwm-back    { fill: rgba(0, 0, 0, 0.10); }
.mhero .hwm-front   { fill: #100c08; }
.mhero .hwm-initial { fill: #100c08; }
.mhero.dark .hwm-back    { fill: rgba(255, 255, 255, 0.085); }
.mhero.dark .hwm-front   { fill: #f5f3ee; }
.mhero.dark .hwm-initial { fill: var(--blast); }

/* POSTER — lede (serif spine) → supporting line → the call */
.mhero .poster {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  margin-top: clamp(14px, 2.6vh, 30px); gap: clamp(15px, 2.4vh, 26px);
}
.mhero .lede {
  font-family: var(--em); font-weight: 400; font-size: clamp(16px, 1.7vw, 25px);
  line-height: 1.28; letter-spacing: .004em; color: rgba(16, 12, 8, .86);
  transition: color var(--x) ease;
}
.mhero .lede .em { font-style: italic; font-size: 1em; color: inherit; letter-spacing: 0; }
.mhero .supp {
  font-family: var(--display); font-weight: 400; font-size: clamp(12.5px, 1vw, 15px);
  line-height: 1.55; letter-spacing: .005em; color: rgba(16, 12, 8, .58); max-width: 46ch;
  transition: color var(--x) ease;
}
.mhero.dark .lede { color: rgba(245, 243, 238, .86); }
.mhero.dark .supp { color: rgba(245, 243, 238, .58); }

/* the call — an outlined pill. Hovering it (desktop) dissolves the hero to dark; on
   hover it fills solid (a confident primary action) — since desktop hover also flips
   to dark, the inverted dark-mode fill is what's seen. */
.mhero .hero-cta {
  appearance: none; cursor: pointer; display: inline-flex; align-items: center; gap: .6em;
  margin-top: clamp(2px, .6vh, 8px);
  font-family: var(--display); font-weight: 500; font-size: clamp(11.5px, .92vw, 13.5px);
  letter-spacing: .16em; text-transform: uppercase; color: #100c08;
  padding: .92em 1.8em; border: 1.5px solid rgba(16, 12, 8, .5); border-radius: 999px; background: transparent;
  transition: color var(--x) ease, border-color var(--x) ease, background .32s ease, gap .25s ease;
}
.mhero .hero-cta:hover { background: #100c08; color: #f8f6f1; border-color: #100c08; gap: .85em; }
.mhero .hero-cta-arr { transition: transform .25s ease; }
.mhero .hero-cta:hover .hero-cta-arr { transform: translateX(4px); }
.mhero.dark .hero-cta { color: #f5f3ee; border-color: rgba(245, 243, 238, .55); }
.mhero.dark .hero-cta:hover { background: #f5f3ee; color: #100c08; border-color: #f5f3ee; }

/* POSTER CREDITS — editorial meta pinned to the foot of the frame */
.mhero .credits {
  position: absolute; left: 0; right: 0; bottom: clamp(16px, 3vh, 30px); z-index: 3;
  display: flex; justify-content: space-between; align-items: center;
  padding: 0 var(--gutter); pointer-events: none;
  font-family: var(--mono); font-size: clamp(9px, .74vw, 11px); letter-spacing: .28em; text-transform: uppercase;
}
.mhero .metaL, .mhero .metaR { color: rgba(16, 12, 8, .5); transition: color var(--x) ease; }
.mhero.dark .metaL, .mhero.dark .metaR { color: rgba(245, 243, 238, .42); }

/* TOP NAV — editorial rail framing the poster (same mono caps as the credits, so
   the top + bottom edges read as one frame). Hovering any link dissolves the hero
   to dark (wired in JS, desktop only). */
.mhero .topnav {
  position: absolute; left: 0; right: 0; top: clamp(16px, 3vh, 30px); z-index: 5;
  display: flex; justify-content: space-between; align-items: center; gap: 1.5rem;
  padding: 0 var(--gutter); pointer-events: none;
}
.mhero .nav-tag {
  font-family: var(--mono); font-size: clamp(9px, .74vw, 11px); letter-spacing: .28em;
  text-transform: uppercase; color: rgba(16, 12, 8, .5); white-space: nowrap; transition: color var(--x) ease;
}
.mhero .nav-links { display: flex; align-items: center; gap: clamp(1.4em, 2vw, 2.4em); pointer-events: auto; }
.mhero .nav-links a {
  position: relative; font-family: var(--mono); font-size: clamp(9px, .74vw, 11px);
  letter-spacing: .28em; text-transform: uppercase; text-decoration: none; color: rgba(16, 12, 8, .5);
  transition: color var(--x) ease;
}
.mhero .nav-links a::after {
  content: ""; position: absolute; left: 0; right: 100%; bottom: -.55em; height: 1px;
  background: currentColor; transition: right .3s ease;            /* underline wipes in on hover */
}
.mhero .nav-links a:hover { color: rgba(16, 12, 8, .92); }
.mhero .nav-links a:hover::after { right: 0; }
.mhero.dark .nav-tag { color: rgba(245, 243, 238, .42); }
.mhero.dark .nav-links a { color: rgba(245, 243, 238, .5); }
.mhero.dark .nav-links a:hover { color: rgba(245, 243, 238, .95); }

/* MOBILE DARK TOGGLE — touch only (no hover to trigger the dissolve) */
.mhero .mode-toggle {
  position: absolute; top: max(clamp(16px, 2.4vh, 26px), env(safe-area-inset-top)); right: var(--gutter); z-index: 6;
  display: none; align-items: center; gap: .55em; cursor: pointer;
  font-family: var(--mono); font-size: 10px; letter-spacing: .2em; text-transform: uppercase;
  color: rgba(16, 12, 8, .62); background: transparent; border: 1px solid rgba(16, 12, 8, .26);
  padding: .5em .85em; border-radius: 999px; transition: color var(--x) ease, border-color var(--x) ease;
}
.mhero .mt-dot { width: 7px; height: 7px; border-radius: 50%; background: rgba(16, 12, 8, .5); transition: background var(--x) ease; }
.mhero.dark .mode-toggle { color: rgba(245, 243, 238, .72); border-color: rgba(245, 243, 238, .3); }
.mhero.dark .mt-dot { background: var(--blast); }
@media (hover: none) { .mhero .mode-toggle { display: inline-flex; } }

/* MOBILE — the v8 hero header: the wordmark rotated −90° into a vertical spine up
   the LEFT edge; the poster drops to the lower-right (clear of the spine); the nav
   drops to a centred foot row (clear of the spine, the toggle and the poster). */
@media (max-width: 760px) {
  .mhero { display: block; align-items: initial; justify-content: initial; padding: 0; }
  .mhero .hero-stage { position: static; display: block; width: 100%; height: 100vh; max-width: none; }
  .mhero .hero-mark {
    position: absolute; top: clamp(24px, 5vh, 60px); left: clamp(-4px, 0vw, 2px);
    width: 76vh; margin: 0; transform-origin: 0 0; transform: rotate(-90deg) translateX(-100%);
    clip-path: inset(-35% -2% -1% -2%); overflow: visible; z-index: 2; pointer-events: none;
  }
  .mhero .hero-mark .hero-wordmark-svg { position: static; width: 100%; height: auto; max-height: none; transform: none; }
  .mhero .poster {
    position: absolute; right: var(--gutter); bottom: clamp(120px, 20vh, 180px); left: auto;
    width: min(62vw, 260px); align-items: flex-end; text-align: right; margin: 0; gap: clamp(13px, 2.4vh, 20px); z-index: 4;
  }
  .mhero .lede { font-size: clamp(19px, 5.4vw, 26px); text-align: right; }
  .mhero .supp { font-size: clamp(12px, 3.2vw, 14px); max-width: 30ch; text-align: right; }
  .mhero .credits { display: none; }
  .mhero .topnav { top: auto; bottom: clamp(18px, 4.5vh, 34px); justify-content: center; }
  .mhero .nav-tag { display: none; }
  .mhero .nav-links { gap: 1.6em; }
  .mhero .nav-links a { font-size: 10px; letter-spacing: .2em; }
}

/* ============================================================
   BG REF 2 — editorial poster layer over the red ink-matrix hero.
   Adds: a warm posterised bloom behind the wordmark, paper grain, a
   hand-drawn ✕✕✕ divider, and the studio line split into two justified
   micro-columns flanking the centre. Scoped to .mhero. The desktop poster
   grid lives in @media (min-width:761px); the ≤760 spine keeps the single
   .supp line and hides the new furniture. Placed last to win the cascade.
   ============================================================ */

/* posterised bloom — centrepiece glow behind the wordmark, behind the ink
   dots (DOM-before the canvases, same z-index → painted first). Hard-stop
   bands give the duotone/riso treatment; the grain over it sells paper. */
.mhero .mh-bloom {
  position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background:
    radial-gradient(56% 52% at 50% 47%,
      #ffba98 0%,   #ffba98 13%,
      #ff8d66 13%,  #ff8d66 29%,
      #f5512f 29%,  #f5512f 49%,
      rgba(238,56,43,.5) 65%,
      rgba(238,56,43,0)  82%);
  transition: opacity var(--x) ease, filter var(--x) ease;
}
.mhero.dark .mh-bloom { opacity: .26; filter: saturate(.8) brightness(.55); }

/* paper grain — topmost texture over the whole hero (multiply tooth) */
.mhero .mh-grain {
  position: absolute; inset: 0; z-index: 4; pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 150px 150px; opacity: .12; mix-blend-mode: multiply;
}
.mhero.dark .mh-grain { opacity: .07; }

/* hand-drawn ✕✕✕ divider — two clusters with a centre gap, lightly jittered */
.mhero .hero-rule {
  display: flex; align-items: center; justify-content: center;
  gap: clamp(56px, 15vw, 210px); color: rgba(16, 12, 8, .68);
  transition: color var(--x) ease;
}
.mhero.dark .hero-rule { color: rgba(245, 243, 238, .52); }
.mhero .xrow { display: inline-flex; gap: clamp(9px, 1.3vw, 18px); }
.mhero .xrow i {
  font-style: normal; font-family: var(--mono); line-height: 1;
  font-size: clamp(11px, 1vw, 15px); display: inline-block;
}
.mhero .xrow i:nth-child(1) { transform: rotate(-7deg); }
.mhero .xrow i:nth-child(2) { transform: rotate(5deg); }
.mhero .xrow i:nth-child(3) { transform: rotate(-3deg); }

/* the two flanking micro-columns (studio line, split L/R) — narrow + justified */
.mhero .hero-center { display: flex; flex-direction: column; align-items: center; justify-content: center; min-width: 0; }
.mhero .hero-col {
  font-family: var(--display); font-weight: 400;
  font-size: clamp(10px, .76vw, 12.5px); line-height: 1.62; letter-spacing: .015em;
  color: rgba(16, 12, 8, .6); text-align: justify; hyphens: auto;
  width: clamp(106px, 12vw, 156px); transition: color var(--x) ease;
}
.mhero.dark .hero-col { color: rgba(245, 243, 238, .5); }

/* DESKTOP — the three-column poster grid */
@media (min-width: 761px) {
  .mhero .hero-stage {
    display: grid; width: 100%;
    grid-template-columns: minmax(0, 1fr) minmax(auto, 60%) minmax(0, 1fr);
    grid-template-areas:
      "rule   rule    rule"
      "coll   center  colr";
    align-items: center; column-gap: clamp(18px, 3vw, 56px); row-gap: 0;
  }
  .mhero .hero-rule   { grid-area: rule; margin-bottom: clamp(12px, 2.4vh, 26px); }
  .mhero .hero-col--l { grid-area: coll; justify-self: start; }
  .mhero .hero-col--r { grid-area: colr; justify-self: end; }
  .mhero .hero-center { grid-area: center; }
  .mhero .hero-center .supp { display: none; }   /* split into the two flank columns */
}

/* MOBILE — keep the vertical spine; hide the new poster furniture */
@media (max-width: 760px) {
  .mhero .hero-rule, .mhero .hero-col { display: none; }
  .mhero .mh-grain { opacity: .08; }
}
