/* ─────────────────────────────────────────────────────
   VERITAS · ALETHEIA
   Palette: bone · obsidian · gold
   Type: Instrument Serif (display) + IBM Plex Mono (chrome)
   ───────────────────────────────────────────────────── */

:root {
  /* All values sampled / extrapolated from Spline hero — pure cool greyscale, no warm tones */
  --bg:       #131313;   /* hero background */
  --bg-2:     #18181a;   /* very-slightly lifted bg */
  --fg:       #e9e9eb;   /* cool bone (was #f3f3f1 warm) */
  --fg-2:     #a8a8ac;   /* cool mid-grey (was #ddd9d0 warm) */
  --dim:      #8a8a8e;   /* dimmed cool grey — bumped from #5e5e62 for WCAG AA contrast (≥4.5:1 on #131313 bg) */
  --hair:     #222225;   /* hairline / divider (was #1c1c1a warm) */
  /* Accent variables retained but mapped to neutral greys —
     no warm gold anywhere on the site, matching the hero. */
  --gold:     #9a9a9e;
  --gold-2:   #cfcfd2;
  --accent:   #e9e9eb;

  --serif: "Instrument Serif", "Times New Roman", serif;
  --mono:  "IBM Plex Mono", ui-monospace, monospace;

  --pad:   28px;
  --easing: cubic-bezier(.4,0,.2,1);
}

* { box-sizing: border-box; }
[hidden] { display: none !important; }
html, body {
  margin: 0; padding: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--mono);
  font-size: 13px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  letter-spacing: 0.01em;
  overflow-x: hidden;
  /* text-rendering: optimizeLegibility removed from body — known iOS
     Safari bug that causes flicker / jank on large clamp()-sized
     headings during scroll-snap (WebKit Bug 99394). Scope below to
     serif typography that actually benefits from ligature handling. */
}
.serif {
  text-rendering: optimizeLegibility;
}
body.intro-active { overflow: hidden; height: 100vh; height: 100dvh; }
body { background: #131313; }      /* matches Spline hero — manifesto sits on same color */

a { color: inherit; text-decoration: none; }
button, input { font: inherit; color: inherit; background: none; border: 0; }
button { cursor: pointer; }

.serif { font-family: var(--serif); font-weight: 400; }
.mono  { font-family: var(--mono); font-weight: 400; letter-spacing: 0.12em;
         text-transform: uppercase; font-size: 11px; }
.dim   { color: var(--dim); }
.accent{ color: var(--accent); }

/* Pulse dot — used in chrome */
.pulse-dot {
  display: inline-block; width: 6px; height: 6px; border-radius: 50%;
  background: var(--fg); margin-right: 8px; vertical-align: middle;
  box-shadow: 0 0 0 0 rgba(243,243,241,0.7);
  animation: pulse 2.6s ease-out infinite;
}
@keyframes pulse {
  0%   { box-shadow: 0 0 0 0 rgba(243,243,241,0.5); }
  70%  { box-shadow: 0 0 0 9px rgba(243,243,241,0); }
  100% { box-shadow: 0 0 0 0 rgba(243,243,241,0); }
}

/* ─── INTRO GATE ─────────────────────────────────── */

.intro {
  position: fixed; inset: 0; z-index: 1000;
  background: #000;
  display: flex; align-items: center; justify-content: center;
  /* Entry is gated to the .intro__hint pill ONLY (see aletheia.js).
     The pill keeps its own cursor: pointer; everything else on the
     intro should read as non-interactive. */
  cursor: default;
  overflow: hidden;
  opacity: 1;
  transition: opacity 1.2s var(--easing);
}
.intro.is-leaving { opacity: 0; pointer-events: none; }

.intro__chrome {
  position: absolute;
  display: flex; gap: 10px; align-items: center;
  font-family: var(--mono); font-size: 11px;
  letter-spacing: 0.18em; color: var(--fg);
  /* Subtle dark halo around the letters absorbs the void's dotted noise so
     the chrome text reads cleanly without losing its hairline classy feel. */
  text-shadow:
    0 0 6px rgba(0,0,0,0.95),
    0 0 12px rgba(0,0,0,0.75),
    0 1px 2px rgba(0,0,0,0.9);
}
.intro__chrome--tl { top: 24px; left: 24px; }
.intro__chrome--tr { top: 24px; right: 24px; }
.intro__chrome--bl { bottom: 24px; left: 24px; }
.intro__chrome--br { bottom: 24px; right: 24px; }
/* Bump dim chrome from the very-faded var(--dim) (#5e5e62) up to a
   readable mid-grey while keeping it visibly secondary to bright chrome. */
.intro__chrome.dim { color: rgba(207,207,210,0.72); }

.intro__ascii {
  font-family: var(--mono); font-weight: 400;
  color: var(--fg);
  margin: 0; padding: 0;
  letter-spacing: 0; line-height: 1;
  white-space: pre; user-select: none;
  transition: transform 1.1s var(--easing), filter 1.1s var(--easing);
  transform-origin: center center;
  will-change: transform, filter;
}
.intro.is-leaving .intro__ascii {
  transform: scale(1.55);
  filter: blur(6px) brightness(2);
}

/* ═══════════════════════════════════════════════════════════════
   INTRO HINT — Apple-style liquid glass pill (iOS 26 material)
   Refractive backdrop + curved arched sheen + edge halo for the
   actual liquid-glass feel (not just blurred translucency).
   ═══════════════════════════════════════════════════════════════ */
.intro__hint {
  position: absolute; left: 50%; bottom: 64px;
  transform: translateX(-50%);
  display: inline-flex; gap: 14px; align-items: center;
  font-size: 11px; letter-spacing: 0.36em;
  color: rgba(255,255,255,1);
  padding: 16px 36px;
  border-radius: 999px;
  cursor: pointer;
  isolation: isolate;             /* contain pseudo-element stacking */
  overflow: hidden;               /* clip the sheen pseudo to the pill */

  /* NEAR-TRANSPARENT base — you should SEE the ASCII dots through it.
     The glass shape is defined by the rim lights + sheen, not by fill.
     Bottom-edge sheen merged into the base via radial gradient. */
  background:
    radial-gradient(ellipse 80% 60% at 50% 100%,
      rgba(255,255,255,0.10) 0%,
      transparent 70%),
    rgba(0,0,0,0.50);

  /* No backdrop-filter — the intro pre updates ~30Hz so behind-pill
     blur was forcing a GPU re-blur every frame. The rim lights + sheen
     + radial gradient already sell the glass shape. */

  border: 1px solid rgba(255,255,255,0.20);

  /* Rim lights + halo do all the heavy lifting now */
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.50),       /* top rim light */
    inset 0 -1px 1px rgba(255,255,255,0.08),    /* bottom rim */
    0 0 32px rgba(255,255,255,0.08),            /* outer halo (lens bloom) */
    0 12px 28px rgba(0,0,0,0.45),               /* main drop shadow */
    0 2px 4px rgba(0,0,0,0.25);

  text-shadow: 0 1px 2px rgba(0,0,0,0.7);
  /* Smooth fade-in: when JS removes [hidden], opacity transitions 0 → 1
     instead of the pill popping in abruptly. */
  opacity: 1;
  transition:
    opacity 0.8s ease,
    transform 0.4s var(--easing),
    box-shadow 0.4s var(--easing);
}
/* Override the user-agent's [hidden] { display:none } so the pill stays in
   layout and can fade — JS removes the hidden attr to reveal it. */
.intro__hint[hidden] {
  display: inline-flex;
  opacity: 0;
  pointer-events: none;
}

/* Curved arched sheen on the top — this is what makes it read as 3D glass.
   Positioned as a thin elliptical highlight that arcs across the top half
   of the pill, exactly like a specular reflection on a curved surface. */
.intro__hint::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 60%;
  pointer-events: none;
  border-radius: 999px 999px 50% 50% / 999px 999px 100% 100%;
  background:
    radial-gradient(ellipse 90% 100% at 50% 0%,
      rgba(255,255,255,0.45) 0%,
      rgba(255,255,255,0.18) 35%,
      rgba(255,255,255,0.04) 65%,
      transparent 90%);
  z-index: 1;
}

/* Animated border sweep — a soft bright spot rotates slowly around the pill's
   rim, like light reflecting off the edge of curved glass. Uses @property so
   the conic angle is animatable (modern browsers — gracefully no-op on older). */
@property --hint-sweep {
  syntax: '<angle>';
  initial-value: 0deg;
  inherits: false;
}
.intro__hint::after {
  content: '';
  position: absolute;
  inset: -1px;                       /* sit on the border line */
  border-radius: inherit;
  pointer-events: none;
  z-index: 0;
  padding: 1.5px;                    /* ring thickness */
  background: conic-gradient(
    from var(--hint-sweep, 0deg),
    rgba(255,255,255,0.04) 0deg,
    rgba(255,255,255,0.04) 60deg,
    rgba(255,255,255,0.85) 95deg,    /* the bright sweep spot */
    rgba(255,255,255,0.04) 130deg,
    rgba(255,255,255,0.04) 360deg
  );
  /* Mask down to a thin ring (subtract the inner area) */
  -webkit-mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
          mask-composite: exclude;
  animation: hintSweep 5s linear infinite;
}
@keyframes hintSweep {
  to { --hint-sweep: 360deg; }
}

/* Keep the actual text on top of the pseudo elements */
.intro__hint > * { position: relative; z-index: 2; }

.intro__hint:hover {
  transform: translateX(-50%) scale(1.05);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.70),
    inset 0 -1px 1px rgba(255,255,255,0.16),
    inset 0 0 36px rgba(255,255,255,0.10),
    0 0 56px rgba(255,255,255,0.16),            /* halo brightens */
    0 18px 44px rgba(0,0,0,0.60),
    0 2px 6px rgba(0,0,0,0.35);
}
.intro__hint:hover::before {
  background:
    radial-gradient(ellipse 90% 100% at 50% 0%,
      rgba(255,255,255,0.60) 0%,
      rgba(255,255,255,0.24) 35%,
      rgba(255,255,255,0.06) 65%,
      transparent 90%);
}
.intro__hint .dot { color: var(--gold-2); font-size: 14px; }

@keyframes hintPulse {
  0%, 100% { opacity: 0.65; }
  50%      { opacity: 1; }
}

/* ─── TOP CHROME ─────────────────────────────────── */

.chrome {
  position: fixed; top: 0; left: 0; right: 0; z-index: 80;
  display: grid; grid-template-columns: 1fr auto 1fr;
  align-items: center;
  padding: 18px 28px;
  background: linear-gradient(to bottom, rgba(5,5,5,0.85), rgba(5,5,5,0));
  pointer-events: none;
  opacity: 0;
  transform: translateY(-8px);
  transition: opacity 1s var(--easing) 0.4s, transform 1s var(--easing) 0.4s;
}
.chrome.visible { opacity: 1; transform: none; }
.chrome > * { pointer-events: auto; }
.chrome__left { display: flex; gap: 14px; align-items: center; }
.chrome__right { display: flex; gap: 8px; align-items: center; justify-content: flex-end; }
.chrome__nav { display: flex; gap: 32px; }
.chrome__nav a {
  position: relative; opacity: 0.85;
  transition: opacity 0.3s var(--easing);
}
.chrome__nav a:hover { opacity: 1; }
.chrome__nav a.is-active { opacity: 1; }
/* The ::after underline rules live further down in the file (the
   center-out version). Removing the duplicate left-to-right version
   that lived here — it was conflicting on 1px bottom offset and tying
   for specificity. */

/* ─── STAGE (sticky 3D canvas) ───────────────────── */

.stage {
  position: fixed; inset: 0; z-index: 1;    /* BELOW .track (z:20) — Spline is now an ambient backdrop, not an interactive hero */
  pointer-events: none;
}
.stage__canvas, #monolith {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  display: none;          /* DISABLED — Spline iframe is the V now */
  pointer-events: none;
  background: transparent;
  z-index: 1;
}

/* Spline embed — global ambient backdrop. Pointer events disabled so the
   beat content above can be interacted with through it. Always visible. */
.stage__spline {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  z-index: 2;
  pointer-events: none;   /* CRITICAL — scroll/clicks pass through to content above */
  opacity: 1;
}
.stage__spline iframe,
.stage__spline spline-viewer {
  width: 100%; height: 100%;
  border: 0;
  display: block;
  background: transparent; /* let Spline scene's own bg show through (transparent if user set it that way in editor) */
  pointer-events: none;
}
/* Backdrop stays visible across all beats per Pedro. */
/* Toggled by JS — backdrop hidden on Beat 3 so V hero shows clean. */
.stage__spline.is-hidden {
  opacity: 0;
  transition: opacity 0.6s var(--easing);
}
.stage__spline { transition: opacity 0.6s var(--easing); }

/* Spline V hero — sits ABOVE backdrop, BELOW page content.
   Fades out after Beat 3 so it doesn't compete with the manifesto/ledger/apply. */
.stage__v-hero {
  position: fixed; inset: 0;
  width: 100%; height: 100%;
  /* z-index 25 — ABOVE page content (z:20). Wrapper is pointer-events: none
     so wheel/clicks pass through; the inner viewer has pointer-events: auto
     so Spline's hover detection fires. This is the working hover config. */
  z-index: 25;
  pointer-events: none;
  opacity: 1;
  transition: opacity 0.6s var(--easing);
}
.stage__v-hero spline-viewer {
  width: 100%; height: 100%;
  border: 0;
  display: block;
  pointer-events: auto;
}
.stage__v-hero.is-hidden {
  opacity: 0;
  pointer-events: none;       /* wrapper stops catching events */
  visibility: hidden;
  transition: opacity 0.6s var(--easing), visibility 0s linear 0.6s;
}
/* CRITICAL: when V hero is hidden, the inner spline-viewer must ALSO stop
   catching events. Without this, the canvas at z:25 (body root) would
   continue intercepting cursor events across the whole viewport on Beats
   4/5/6, blocking hover on cards/buttons everywhere else on the site. */
.stage__v-hero.is-hidden spline-viewer {
  pointer-events: none !important;
}

/* ─── Cursor-revealed Aletheia layer ──────────────
   Canvas starts transparent — JS paints the chrome Aletheia image into it
   only where the cursor has been (clipped by polygon brush strokes). So the
   particle field behind shows through everywhere Aletheia isn't drawn.
*/
.stage__aletheia {
  position: absolute; inset: 0;
  pointer-events: none;
  z-index: 0;
  opacity: var(--aletheia-fade, 1);
  transition: opacity 0.6s var(--easing);
}
.stage__aletheia__veil {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  display: block;
}

/* ─── HERO TEXT — magazine-cover composition ──────────────
   Wordmark + tagline, centered horizontally, anchored to the
   bottom of the viewport (under the V monolith). Sits ABOVE
   the Spline canvas (z:26 vs 25) so it's readable. Fades out
   together with the V hero. */
.hero-sidetext {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 8vh;
  z-index: 26;
  pointer-events: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  opacity: 1;
  transition: opacity 0.6s var(--easing);
}
.hero-sidetext.is-hidden { opacity: 0; }
.hero-sidetext__wordmark {
  font-family: 'Big Shoulders Display', sans-serif;
  font-weight: 500;
  font-size: clamp(48px, 6.5vw, 110px);
  line-height: 0.95;
  letter-spacing: 0.05em;
  color: var(--fg, #f3f3f1);
  margin-bottom: 14px;
}
.hero-sidetext__tagline {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--dim);
}

@media (max-width: 768px) {
  .hero-sidetext__wordmark { font-size: clamp(36px, 11vw, 72px); }
  .hero-sidetext__tagline  { font-size: 9px; letter-spacing: 0.28em; }
}

/* Stage marks — fade out after beat 3 */
.stage__marks {
  position: fixed; inset: 0; pointer-events: none;
  z-index: 27;          /* ABOVE the V hero canvas (z:25) */
  opacity: 0;
  transition: opacity 0.5s var(--easing);
}
/* Class-driven show/hide. Toggled together with the V hero by JS so
   marks appear when V is visible and disappear when V leaves. */
.stage__marks.visible:not(.is-hidden) { opacity: 1; }
.mark { position: absolute; font-family: var(--mono); font-size: 10px;
        letter-spacing: 0.18em; color: var(--dim); }
.mark--tl { top: 30px; left: 28px; }
.mark--tr { top: 30px; right: 28px; }
.mark--bl { bottom: 30px; left: 28px; }
.mark--br { bottom: 30px; right: 28px; }
.mark--center-hint {
  /* Nudged up to make room for the scroll cue beneath it. */
  bottom: 54px; left: 50%; transform: translateX(-50%);
  opacity: 0.7;
  animation: markPulse 2.4s ease-in-out infinite;
}
@keyframes markPulse {
  0%, 100% { opacity: 0.4; }
  50%      { opacity: 0.85; }
}

/* ── Scroll cue — bouncing chevron telling first-time visitors to scroll.
   Lives in #stageMarks (revealed after intro). JS fades it out as soon
   as the user scrolls into beat 4 so it doesn't linger. */
/* One cue per section (hero, manifesto, ledger — NOT the door). Positioned
   ABSOLUTE at the bottom of each sticky section so it sits at the viewport
   bottom while that section is pinned, then scrolls away with the section
   as you move on (no fixed element trailing the whole page). The hero cue
   lives in #stageMarks and rides its opacity (hidden during intro, fades
   when the hero hides). */
.scroll-cue {
  position: absolute;
  bottom: 22px; left: 50%; transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  font-size: 9px; letter-spacing: 0.34em;
  color: rgba(255,255,255,0.85);
  text-shadow: 0 1px 3px rgba(0,0,0,0.7);
  pointer-events: none;
  z-index: 12;
  opacity: 1;
}
.scroll-cue__chevron {
  font-size: 18px; line-height: 1;
  animation: scrollCueBounce 1.8s ease-in-out infinite;
}
@keyframes scrollCueBounce {
  0%, 100% { transform: translateY(0);    opacity: 0.55; }
  50%      { transform: translateY(5px);  opacity: 1; }
}

/* ─── SCROLL TRACK ───────────────────────────────── */

.track {
  position: relative; z-index: 20;
  padding-top: 0;
}
.beat { position: relative; }
.beat--monolith   { height: 60vh; pointer-events: none; }   /* let cursor pass through to Spline iframe behind */

/* ── Giant VERITAS wordmark on Beat 3 — sits BEHIND the Spline V hero.
   Sized so the leading "V" is clipped at the left viewport edge and the
   trailing "S" is clipped at the right edge — only "ERITA" fully reads.
   The Spline V (body root, z:25) renders on top of this. */
.beat--monolith .beat__pad { pointer-events: none; }
.beat--manifesto  { height: 110vh; height: 110dvh; }   /* Sticky 100vh + 10vh runway out */
.beat--ledger     { height: 130vh; height: 130dvh; }   /* Sticky 100vh + 30vh runway — horizontal scroll is independent */
.beat--door {
  height: 100vh; height: 100dvh;
  /* PERF: content-visibility: auto skips paint + layout when off-screen.
     contain-intrinsic-size gives the layout an estimate so sticky
     positioning doesn't break (which is the failure mode noted earlier
     in this file when content-visibility was tried without intrinsic).
     Door is the last beat and is offscreen most of the user's session. */
  content-visibility: auto;
  contain-intrinsic-size: 100vh;
}

/* (content-visibility removed — was conflicting with sticky positioning
   inside ledger / door, causing layout jank instead of perf wins.) */
.beat__pad { height: 100vh; height: 100dvh; }
/* Total: 430vh — vertical scroll advances page; horizontal scroll pans rail */

/* ─── MANIFESTO (Beat 4) ─────────────────────────── */

.manifesto {
  position: sticky; top: 0;
  height: 100vh;
  height: 100dvh;
  /* Symmetric vertical padding — asymmetric (12vh top / 6vh bottom) was
     visually pushing content down past viewport center. */
  padding: 9vh 8vw;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  text-align: center;
  gap: 28px;
  opacity: 0;            /* JS drives this each frame on scroll */
  will-change: opacity;   /* PERF: was `opacity, transform` but the manifesto
                             container itself never receives a transform — only
                             the per-line .ln children do, and they have their
                             own transforms via class toggle. */
  /* Subtle vignette — softer ramp + lower max alpha so it doesn't create a
     hard color boundary at the bottom edge against the next section. */
  background:
    radial-gradient(ellipse at 50% 50%,
      transparent 0%,
      transparent 50%,
      rgba(0,0,0,0.22) 100%);
}

/* ─── Card-deck panel (right column) ──────────────────
   3D perspective stack of member cards with paper material,
   brass inlays, letterpress typography, choreographed shuffle.
*/
.manifesto__deck-wrap {
  position: relative;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: 38px;
  height: 100%;
  pointer-events: auto;
}
.deck {
  position: relative;
  width: 360px; height: 480px;
  perspective: 1600px;
  perspective-origin: 50% 60%;
  transform-style: preserve-3d;
}

/* Each card uses CSS variables (set by JS) for its position in the stack.
   --depth: 0 (top) → 4 (back). --shuffle: 0 (idle) → 1 (mid-shuffle, exiting). */
.card {
  position: absolute;
  inset: 0;
  border-radius: 4px;
  transform-style: preserve-3d;
  transform-origin: 50% 60%;
  /* Paper material: warm cream with extremely subtle gradient + grain feel */
  background:
    radial-gradient(ellipse at 30% 20%, rgba(255,250,240,0.05), transparent 50%),
    linear-gradient(135deg, #ece4d4 0%, #ddd2bc 60%, #c9bea7 100%);
  border: 1px solid rgba(0,0,0,0.18);
  /* Brass border accent — thin gold inlay around the edge */
  outline: 1px solid rgba(168,168,172,0.30);
  outline-offset: -8px;
  /* Layered shadows: depth + soft cast + crisp contact */
  box-shadow:
    0 1px 0 rgba(255,255,255,0.18) inset,                /* paper top highlight */
    0 -1px 0 rgba(0,0,0,0.20)      inset,                /* paper bottom shadow */
    0 8px 18px rgba(0,0,0,0.55),
    0 28px 48px rgba(0,0,0,0.45);
  transition:
    transform 0.9s cubic-bezier(.22,1,.36,1),
    opacity 0.7s cubic-bezier(.22,1,.36,1),
    box-shadow 0.6s ease;
  /* Each frame's rest pose comes from CSS vars set by JS */
  transform:
    translate3d(
      calc(var(--depth, 0) * 12px),
      calc(var(--depth, 0) * -8px),
      calc(var(--depth, 0) * -22px)
    )
    rotate3d(0, 1, 0.05, calc(var(--depth, 0) * -3.5deg))
    rotateX(calc(var(--wobble-x, 0) * 1deg))
    rotateY(calc(var(--wobble-y, 0) * 1deg));
}
.card--exiting {
  /* Shuffle-out: the top card lifts forward, tilts, slides up-right, fades */
  transform:
    translate3d(280px, -120px, 240px)
    rotate3d(1, 0.5, -0.2, 35deg);
  opacity: 0;
  transition:
    transform 1.1s cubic-bezier(.55,.05,.30,1),
    opacity 0.9s cubic-bezier(.55,.05,.30,1);
}
.card__edge-light {
  /* Specular sheen that sweeps across cards (subtle, slow) */
  position: absolute; inset: 0;
  border-radius: inherit;
  background: linear-gradient(
    115deg,
    transparent 35%,
    rgba(255,255,250,0.18) 50%,
    transparent 65%
  );
  mix-blend-mode: overlay;
  opacity: 0;
  transition: opacity 0.8s ease;
  pointer-events: none;
}
.card:hover .card__edge-light,
.card.is-front:hover .card__edge-light {
  opacity: 1;
}
.card__inner {
  position: absolute;
  inset: 28px 24px;
  display: flex; flex-direction: column;
  justify-content: space-between;
  /* Letterpress text: dark engraved feel via inset shadow trick */
  color: #2b261c;
  font-family: var(--mono);
  text-shadow:
    0 1px 0 rgba(255,255,255,0.45),    /* etch highlight below */
    0 -1px 0 rgba(0,0,0,0.10);         /* etch shadow above */
}
.card__top {
  display: flex; justify-content: space-between; align-items: flex-start;
  font-size: 9px; letter-spacing: 0.32em; opacity: 0.75;
}
.card__top .card__seal {
  font-family: var(--serif);
  font-style: italic;
  font-size: 28px;
  line-height: 1;
  letter-spacing: -0.02em;
  color: #bdbdc0;             /* brass */
  text-shadow:
    0 1px 0 rgba(255,255,255,0.55),
    0 -1px 0 rgba(0,0,0,0.20);
}
.card__handle {
  font-family: var(--mono);
  font-size: 16px;
  letter-spacing: 0.20em;
  font-weight: 500;
  text-transform: uppercase;
  margin-bottom: 4px;
}
.card__craft {
  font-family: var(--serif);
  font-style: italic;
  font-size: 18px;
  letter-spacing: -0.005em;
  opacity: 0.78;
}
.card__bottom {
  display: flex; justify-content: space-between; align-items: flex-end;
  font-size: 10px; letter-spacing: 0.28em;
  text-transform: uppercase;
  opacity: 0.70;
}
.card__bottom .card__num {
  letter-spacing: 0.32em;
}
.card__rule {
  display: block;
  height: 1px;
  background: linear-gradient(to right,
    transparent, rgba(168,168,172,0.40) 30%, rgba(168,168,172,0.40) 70%, transparent);
  margin: 14px 0 12px;
}

/* Anti-CTA below the deck */
.deck__cta {
  display: flex; flex-direction: column; align-items: center;
  gap: 14px;
  text-decoration: none;
  font-size: 11px; letter-spacing: 0.42em;
  color: var(--dim);
  text-transform: uppercase;
  transition: color 0.4s var(--easing);
  cursor: pointer;
}
.deck__cta:hover { color: var(--fg); }
.deck__cta__rule {
  display: block;
  width: 56px; height: 1px;
  background: var(--dim);
  transition: width 0.5s var(--easing), background 0.4s ease;
}
.deck__cta:hover .deck__cta__rule {
  width: 110px;
  background: var(--gold-2);
}
.deck__cta__label {
  white-space: nowrap;
}

@media (max-width: 900px) {
  .manifesto {
    grid-template-columns: 1fr;
    padding: 12vh 6vw 6vh 6vw;
    gap: 6vh;
  }
  .manifesto__deck-wrap { display: none; }   /* mobile: hide deck for now */
}
/* No .is-visible opacity rule — JS owns it. The class only gates the line stagger. */

.manifesto__eyebrow {
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.42em;
  color: var(--dim);
  opacity: 0;
  transition: opacity 1.2s var(--easing) 0.05s;
}
.manifesto.is-visible .manifesto__eyebrow { opacity: 1; }

/* ── MANIFESTO LEDE — editorial monument typography ──────
   "WHAT'S VERITAS?" in massive caps with a slow chrome-shimmer gradient
   flowing through the letterforms via background-clip: text. Per-letter
   spans get cursor magnetism (set by JS). Subtle drop-shadow gives the
   text a luminous lift off the dark background. */
.manifesto__lede {
  /* Big Shoulders Display — refined to match the hero VERITAS wordmark.
     Weight 500 + 0.05em letter-spacing gives the premium / fashion-house feel
     instead of the heavier brutalist blockiness. */
  font-family: 'Big Shoulders Display', 'Instrument Serif', Georgia, 'Times New Roman', serif;
  font-weight: 500;
  font-size: clamp(72px, 12vw, 232px);
  line-height: 0.92;
  letter-spacing: 0.05em;
  margin: 0;
  text-align: center;
  white-space: nowrap;
  color: var(--fg);
  filter: drop-shadow(0 0 28px rgba(207,207,210,0.08));
  opacity: 0;
  transition: opacity 1.4s var(--easing) 0.10s;
  cursor: default;
  user-select: none;
}
.manifesto.is-visible .manifesto__lede { opacity: 1; }

/* Per-letter span — cursor-magnetism transform via JS-written CSS vars */
.manifesto__lede .ch {
  display: inline-block;
  color: inherit;
  --mx: 0px;
  --my: 0px;
  --ms: 1;
  transform: translate(var(--mx), var(--my)) scale(var(--ms));
  /* PERF: dropped transition + will-change — magnetism is disabled, the lede
     never animates per-letter. These vars are inert defaults. */
}
.manifesto__lede .ch--space { width: 0.30em; }
/* Legacy letter-stagger CSS removed — was overriding the new chrome-shimmer
   .ch transform with opacity:0 + filter:blur(10px), making the lede invisible
   and likely causing scroll layout issues. */

.manifesto__body {
  font-family: var(--serif); font-style: italic;
  font-size: clamp(18px, 1.5vw, 22px);
  max-width: 58ch;
  color: var(--fg-2); opacity: 0.85;
  line-height: 1.55;
  text-align: center;
  margin: 12px auto 0;
}
.manifesto__body p { margin: 0 0 14px; }
.manifesto__body .ln {
  opacity: 0; transform: translateY(12px);
  transition: opacity 1.0s var(--easing), transform 1.0s var(--easing);
}
/* Body fades in shortly after the lede appears */
.manifesto.is-visible .ln { opacity: 0.85; transform: none;
  transition-delay: 0.45s; }
.manifesto.is-visible .ln:nth-child(2) { transition-delay: 0.65s; }

.manifesto__meta {
  display: flex; gap: 48px;
  font-size: 10px; letter-spacing: 0.30em;
  margin-top: 16px;
  opacity: 0;
  transition: opacity 1.0s var(--easing) 0.95s;
}
.manifesto.is-visible .manifesto__meta { opacity: 1; }
.manifesto__meta > div { display: flex; flex-direction: column; gap: 4px; align-items: center; }
.manifesto__meta .lbl { color: var(--dim); font-size: 9px; }

/* ─── LEDGER (Beat 5) ────────────────────────────── */

.ledger {
  position: sticky; top: 0;
  height: 100vh;
  height: 100dvh;
  display: flex; flex-direction: column;
  padding: 18vh 0 6vh;
  overflow: hidden;
}
.ledger__head {
  padding: 0 8vw;
  display: flex; flex-direction: column;
  align-items: center;       /* center child items (chip, subtitle, hint) */
  text-align: center;
  gap: 14px;
  margin-bottom: 40px;
}
.ledger__head .mono { display: flex; align-items: center; gap: 14px; font-size: 10px;
                      justify-content: center; }
.hairline { display: inline-block; width: 36px; height: 1px; background: var(--dim); }
.ledger__subtitle {
  font-family: var(--serif); font-style: italic;
  font-size: clamp(22px, 2vw, 30px);
  color: var(--fg-2); opacity: 0.85; margin: 0;
}
.ledger__hint { color: var(--dim); font-size: 10px; opacity: 0.7; }

/* ─── PARALLAX META-RAIL ──────────────────────────────
   A thin strip above the card rail that scrolls at a slower rate as the
   user pans the cards. Adds the feel of a live archive system overhead.
   Content: tx-hash-looking serials, timestamps, classification tags. */
.ledger__metarail {
  position: relative;
  height: 22px;
  margin: 0 0 18px;
  overflow: hidden;
  border-top: 1px solid rgba(207,207,210,0.10);
  border-bottom: 1px solid rgba(207,207,210,0.10);
  background: linear-gradient(180deg, rgba(8,8,10,0.30), rgba(8,8,10,0.55));
  -webkit-mask-image: linear-gradient(90deg,
    transparent 0%, #000 8%, #000 92%, transparent 100%);
          mask-image: linear-gradient(90deg,
    transparent 0%, #000 8%, #000 92%, transparent 100%);
  transition: opacity 0.5s var(--easing);
}
/* Dim the meta-rail when a dossier is open so it doesn't compete */
.ledger.is-frozen .ledger__metarail { opacity: 0.25; }
/* Same for the centered "THE LEDGER" header */
.ledger.is-frozen .ledger__head {
  opacity: 0.30;
  transition: opacity 0.5s var(--easing);
}
.ledger__metarail__strip {
  position: absolute;
  top: 0; left: 0;
  height: 100%;
  display: inline-flex; align-items: center; gap: 28px;
  padding: 0 6vw;
  white-space: nowrap;
  font-family: var(--mono); font-size: 10px;
  letter-spacing: 0.30em;
  color: var(--dim);
  /* Slow continuous scroll left so the strip feels alive even when user is
     idle. Combined with parallax JS that further translates on user pan. */
  animation: metarailDrift 90s linear infinite;
  animation-play-state: paused;        /* PERF: only runs while ledger is in view (see body.ledger-in-view) */
  will-change: transform;
}
body.ledger-in-view .ledger__metarail__strip {
  animation-play-state: running;
}
.ledger__metarail__strip .tag {
  display: inline-flex; align-items: center; gap: 8px;
}
.ledger__metarail__strip .tag .pulse-dot {
  width: 5px; height: 5px;
  background: var(--fg);
  margin: 0;
}
.ledger__metarail__strip .tag .v {
  color: var(--fg);
}
/* Italic editorial quote tag — softer voice, no hard letter-spacing */
.ledger__metarail__strip .tag--quote i {
  font-family: 'Instrument Serif', serif;
  font-style: italic;
  font-weight: 400;
  font-size: 12px;
  letter-spacing: 0.02em;
  color: rgba(243,243,241,0.85);
  text-transform: none;
}
.ledger__metarail__strip .sep {
  display: inline-block;
  width: 22px; height: 1px;
  background: rgba(207,207,210,0.20);
}
@keyframes metarailDrift {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

/* ── Rail area: wraps the scroll container + nav arrows. flex:1 so it fills
   the card region below the head/meta-rail; position:relative anchors the
   absolutely-positioned arrows to THIS box (the actual card area) instead
   of the whole section. */
.ledger__rail-area {
  position: relative;
  flex: 1; min-height: 0;
  display: flex; flex-direction: column;
}

/* ── Rail navigation arrows — pinned to the left/right edges of the card
   area, vertically centered. Self-contained (NOT .glass-btn — that class's
   position:relative would drop these into flow and break the layout).
   The chevron is a CSS-drawn rotated border for exact optical centering;
   text glyphs like ‹ › sit off-center in most fonts. */
.ledger__nav {
  position: absolute;
  top: 50%;
  z-index: 30;
  width: 46px; height: 46px;
  display: flex; align-items: center; justify-content: center;
  padding: 0;
  background: rgba(10,10,12,0.55);
  border: 1px solid rgba(255,255,255,0.18);
  border-radius: 999px;
  cursor: pointer;
  box-shadow: 0 6px 18px rgba(0,0,0,0.45);
  transition: opacity 0.3s var(--easing), background 0.2s var(--easing),
              border-color 0.2s var(--easing), transform 0.2s var(--easing);
}
.ledger__nav::before {
  content: '';
  width: 10px; height: 10px;
  border-top: 2px solid var(--fg);
  border-right: 2px solid var(--fg);
}
.ledger__nav--prev { left: 1.5vw;  transform: translateY(-50%); }
.ledger__nav--next { right: 1.5vw; transform: translateY(-50%); }
/* Rotate the border-square into a chevron; nudge so the V of the chevron
   sits optically centered in the circle. */
.ledger__nav--prev::before { transform: rotate(-135deg); margin-left: 3px; }
.ledger__nav--next::before { transform: rotate(45deg);   margin-right: 3px; }
.ledger__nav:hover {
  background: rgba(20,20,24,0.80);
  border-color: rgba(255,255,255,0.35);
}
.ledger__nav--prev:hover { transform: translateY(-50%) scale(1.08); }
.ledger__nav--next:hover { transform: translateY(-50%) scale(1.08); }
/* Hidden while a dossier is open — the .ledger gets .is-frozen then. */
.ledger.is-frozen .ledger__nav { opacity: 0; pointer-events: none; }
/* Hidden at the rail extremes so arrows never point at empty space.
   JS toggles .at-start / .at-end on the .ledger__rail-area. */
.ledger__rail-area.at-start .ledger__nav--prev,
.ledger__rail-area.at-end   .ledger__nav--next {
  opacity: 0; pointer-events: none;
}
@media (hover: none) {
  .ledger__nav { width: 42px; height: 42px; }
}

.ledger__rail-wrap {
  position: relative;
  flex: 1; min-height: 0;
  overflow-x: auto;
  overflow-y: hidden;
  /* Smooth horizontal scroll on trackpad / drag */
  scroll-behavior: auto;
  scrollbar-width: thin;
  scrollbar-color: rgba(168,168,172,0.30) transparent;
}
.ledger__rail-wrap::-webkit-scrollbar { height: 4px; }
.ledger__rail-wrap::-webkit-scrollbar-track { background: transparent; }
.ledger__rail-wrap::-webkit-scrollbar-thumb { background: rgba(168,168,172,0.30); border-radius: 2px; }
.ledger__rail {
  position: relative;
  display: inline-flex; align-items: center; gap: 28px;
  padding: 0 12vw 0 6vw;        /* tight to the left, generous on the right */
  height: 100%;
  min-width: max-content;        /* let the row size to its full content width */
  transition: opacity 0.4s var(--easing);
}

/* ─── DOSSIER CARD ────────────────────────────────────
   Each card is a museum-grade specimen card: corner registration marks,
   classification stamp, headline stat, animated sparkline, signature handle,
   serial + cycle pips. The card has explicit padding so chrome regions never
   overlap content. */
.ledger__card {
  flex: 0 0 auto;
  width: clamp(280px, 24vw, 360px);
  height: 88%;
  position: relative;
  cursor: pointer;
  display: grid;
  grid-template-rows:
    auto                /* meta-top */
    minmax(0, 1fr)      /* portrait — gets all available space */
    auto                /* id (handle + craft, under portrait) */
    auto                /* social (X + followers + since) */
    auto;               /* meta-bot (serial + cycle) */
  gap: 14px;
  padding: 22px 22px 20px;
  /* PERF: skip paint/layout for cards that are scrolled off the rail.
     Each card has 2 backgrounds + 4 box-shadows + a sparkline + halo.
     With 22 cards in DOM, off-screen ones still rendered every frame
     (compositor re-rasters them on parallax). content-visibility: auto
     defers everything until they enter the viewport. contain-intrinsic
     gives the layout a stable size estimate so the rail doesn't twitch. */
  content-visibility: auto;
  contain-intrinsic-size: 360px 620px;
  background:
    linear-gradient(180deg, rgba(28,28,31,0.65) 0%, rgba(18,18,20,0.85) 100%),
    radial-gradient(ellipse at 50% 0%, rgba(207,207,210,0.06), transparent 60%);
  border: 1px solid rgba(207,207,210,0.10);
  /* Subtle outer "frame" line + inner specular hint */
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.04),
    inset 0 -1px 0 rgba(0,0,0,0.30),
    0 24px 60px rgba(0,0,0,0.55);
  /* These vars are written by JS depth-of-field code. Defaults = neutral.
     PERF: blur is back but QUANTIZED to 4 buckets (0 / 0.4 / 0.8 / 1.2 px)
     so the value only changes when crossing a threshold — no per-frame
     blur recompositing. Max kept tiny so even all-cards-blurred is cheap. */
  --dof-scale: 1;
  --dof-opacity: 1;
  --dof-y: 0px;
  --dof-blur: 0px;
  transform: translateY(var(--dof-y)) scale(var(--dof-scale));
  opacity: var(--dof-opacity);
  /* PERF: filter only applied when card is actually blurred (via .is-blurred
     class set by the DOF loop). Permanent `filter` value forces a GPU layer
     per card even when blur is 0 — 17 always-on layers was a real cost. */
  /* PERF: no will-change + no transform/opacity transition. The DOF loop writes
     these values directly each frame; transitioning them would queue
     interpolations on top of the per-frame writes and stall the GPU. */
  transition:
    border-color 0.4s var(--easing),
    box-shadow 0.4s var(--easing);
}
.ledger__card.is-blurred {
  filter: blur(var(--dof-blur));
}
.ledger__card:hover {
  border-color: rgba(207,207,210,0.28);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.06),
    inset 0 -1px 0 rgba(0,0,0,0.30),
    0 32px 80px rgba(0,0,0,0.65);
}

/* ── Corner registration marks — film-slate detail */
.ledger__card__regmark {
  position: absolute;
  width: 14px; height: 14px;
  pointer-events: none;
}
.ledger__card__regmark::before,
.ledger__card__regmark::after {
  content: ''; position: absolute; background: rgba(207,207,210,0.45);
}
.ledger__card__regmark::before { width: 14px; height: 1px; top: 0; left: 0; }
.ledger__card__regmark::after  { width: 1px; height: 14px; top: 0; left: 0; }
.ledger__card__regmark--tl { top: 6px;    left: 6px; }
.ledger__card__regmark--tr { top: 6px;    right: 6px; transform: scaleX(-1); }
.ledger__card__regmark--bl { bottom: 6px; left: 6px; transform: scaleY(-1); }
.ledger__card__regmark--br { bottom: 6px; right: 6px; transform: scale(-1); }

/* ═══════════════════════════════════════════════════════════════
   GLASS PILL — reusable liquid-glass button utility, distilled from
   the intro__hint pill we built together. Used site-wide on action
   buttons (X pills, close, submit). Has the rim lights + sheen +
   halo + drop shadow but NOT the rotating border sweep — that
   would be visually noisy with multiple instances on screen.
   ═══════════════════════════════════════════════════════════════ */
/* PERF: NO backdrop-filter at rest — 17 cards × backdrop-filter = GPU murder.
   The rim lights + sheen + drop shadow already sell the glass look without it.
   Backdrop-filter only kicks in on hover when at most 1 button is interacting. */
.glass-btn {
  display: inline-flex; align-items: center; gap: 10px;
  font-family: var(--mono);
  font-size: 10px; letter-spacing: 0.30em;
  color: rgba(255,255,255,0.95);
  text-decoration: none;
  padding: 8px 18px;
  border-radius: 999px;
  cursor: pointer;
  isolation: isolate;
  overflow: hidden;
  position: relative;
  background:
    radial-gradient(ellipse 80% 60% at 50% 100%,
      rgba(255,255,255,0.10) 0%,
      transparent 70%),
    rgba(8,8,12,0.50);
  border: 1px solid rgba(255,255,255,0.20);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.40),
    inset 0 -1px 1px rgba(255,255,255,0.06),
    0 0 24px rgba(255,255,255,0.06),
    0 8px 18px rgba(0,0,0,0.40),
    0 2px 4px rgba(0,0,0,0.20);
  text-shadow: 0 1px 2px rgba(0,0,0,0.6);
  /* Set a baseline backdrop-filter so the hover transition interpolates
     from blur(0)/saturate(100%) up to blur(8px)/saturate(140%) instead of
     popping. Visually identity at rest. */
  -webkit-backdrop-filter: blur(0px) saturate(100%);
  backdrop-filter: blur(0px) saturate(100%);
  transition:
    transform 0.3s var(--easing),
    box-shadow 0.3s var(--easing),
    border-color 0.3s var(--easing),
    -webkit-backdrop-filter 0.3s var(--easing),
    backdrop-filter 0.3s var(--easing);
}
/* Sheen across the top — same arched highlight as the intro pill */
.glass-btn::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 60%;
  pointer-events: none;
  border-radius: 999px 999px 50% 50% / 999px 999px 100% 100%;
  background:
    radial-gradient(ellipse 90% 100% at 50% 0%,
      rgba(255,255,255,0.32) 0%,
      rgba(255,255,255,0.12) 35%,
      rgba(255,255,255,0.02) 65%,
      transparent 90%);
  z-index: 1;
}
.glass-btn > * { position: relative; z-index: 2; }
.glass-btn:hover {
  transform: translateY(-1px);
  border-color: rgba(255,255,255,0.40);
  -webkit-backdrop-filter: blur(8px) saturate(140%);
          backdrop-filter: blur(8px) saturate(140%);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.60),
    inset 0 -1px 1px rgba(255,255,255,0.12),
    0 0 36px rgba(255,255,255,0.12),
    0 12px 28px rgba(0,0,0,0.55),
    0 2px 6px rgba(0,0,0,0.30);
}
.glass-btn:hover::before {
  background:
    radial-gradient(ellipse 90% 100% at 50% 0%,
      rgba(255,255,255,0.45) 0%,
      rgba(255,255,255,0.18) 35%,
      rgba(255,255,255,0.03) 65%,
      transparent 90%);
}
.glass-btn svg { display: block; }

/* ── Top strip: now hosts the X handle pill (replaces old classification badge) */
.ledger__card__meta-top {
  display: flex; align-items: center;
  padding-left: 4px;
}
/* Card X pill — uses .glass-btn utility now (handle pill at top of each card) */
.ledger__card__x--top {
  /* sized down to fit on a card */
  font-size: 9px;
  padding: 6px 12px;
  letter-spacing: 0.24em;
  gap: 8px;
}

/* ── Portrait region: the chiaroscuro face/sigil framed in a paper window */
.ledger__card__portrait {
  position: relative;
  background: #0a0a0c;
  border: 1px solid rgba(207,207,210,0.06);
  overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  min-height: 0;            /* critical for grid 1fr to actually shrink */
}
.ledger__card__portrait svg,
.ledger__card__portrait img {
  display: block;
  width: 100%; height: 100%;
  object-fit: cover;
}
/* PFP treatment — clean monochrome base with a cool duotone overlay.
   Crisp, editorial, magazine-cover quality. No more muddy VHS look:
     1. Image: pure B&W, contrast bumped so chiaroscuro pops
     2. Vignette: subtle radial darkening at edges only
     3. Duotone tint applied via the vignette layer using mix-blend-mode
   On hover, the duotone pulls back slightly so the member is even
   sharper / more present. */
.ledger__card__portrait img {
  filter:
    grayscale(100%)
    contrast(1.18)
    brightness(0.95);
  transition: filter 0.4s var(--easing);
}
/* On hover: image returns to its NATURAL color. Grayscale lifts entirely,
   so the member's actual photo (real colors) is revealed. Slight contrast
   bump kept for punch. */
.ledger__card:hover .ledger__card__portrait img {
  filter:
    grayscale(0%)
    contrast(1.05)
    brightness(1);
}
.ledger__card__portrait-fallback {
  width: 100%; height: 100%;
  background: radial-gradient(ellipse at 50% 40%, #1a1a1d 0%, #06060a 80%);
}
/* Duotone tint layer — cool teal/blue in shadows, neutral in highlights.
   mix-blend-mode: color tints the underlying B&W image without changing
   its luminance. Subtle (0.55 alpha) so it reads as "premium editorial
   grade" not "blue filter". Removed the old CRT scanline pattern entirely. */
.ledger__card__vignette {
  position: absolute; inset: 0;
  pointer-events: none;
  background:
    /* cool duotone — deep teal at bottom, lifts toward neutral at top */
    linear-gradient(180deg,
      rgba(180, 195, 210, 0.10) 0%,
      rgba(60, 80, 105, 0.35) 65%,
      rgba(20, 30, 48, 0.55) 100%);
  mix-blend-mode: color;
  transition: opacity 0.4s var(--easing);
  opacity: 0.85;
}
/* Second pseudo for the vignette darkening — kept separate so the duotone
   above stays in 'color' blend without darkening corners */
.ledger__card__vignette::after {
  content: '';
  position: absolute; inset: 0;
  background: radial-gradient(ellipse at 50% 38%,
    transparent 45%,
    rgba(0,0,0,0.50) 100%);
  mix-blend-mode: normal;
}
/* On hover: tint disappears so the original color photo is fully revealed.
   The vignette ::after still applies a faint corner darkening for framing. */
.ledger__card:hover .ledger__card__vignette {
  opacity: 0;
}
/* (.ledger__card__anon removed — anon overlay no longer rendered.) */

/* ── Signature stat: the headline number */
.ledger__card__stat {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px;
  padding: 6px 4px 0;
  border-top: 1px solid rgba(207,207,210,0.10);
}
.ledger__card__stat-val {
  font-family: var(--serif); font-style: italic;
  font-size: clamp(28px, 2.6vw, 38px);
  line-height: 1;
  color: var(--fg);
  letter-spacing: -0.01em;
}
.ledger__card__stat-lbl {
  font-size: 9px; letter-spacing: 0.32em;
  text-align: right; max-width: 50%;
  flex-shrink: 0;
}

/* ── Sparkline */
.ledger__card__spark {
  display: block;
  width: 100%; height: 56px;
  margin: 0 0 4px;
}
.ledger__card__spark .spark__line {
  /* Drawn-in animation — initial state hidden; reveal triggered by .spark-draw */
  transition: stroke-dashoffset 1.6s cubic-bezier(.2,.8,.2,1);
}
.ledger__card__spark .spark__end {
  opacity: 0;
  transition: opacity 0.4s var(--easing) 1.4s;
}
.ledger__card.spark-draw .spark__line { stroke-dashoffset: 0; }
.ledger__card.spark-draw .spark__end  { opacity: 1; }
/* PERF: dropped infinite sparkEndPulse — pulsing the end-cap on every visible
   card was triggering layout/paint each frame. The end-cap is static. */

/* ── Identity block: the human + the role */
.ledger__card__id {
  display: flex; flex-direction: column; gap: 3px;
  padding: 4px 4px 0;
  border-top: 1px solid rgba(207,207,210,0.10);
}
.ledger__card__handle {
  font-family: var(--serif); font-style: italic;
  font-size: clamp(20px, 1.6vw, 24px);
  line-height: 1.05;
  color: var(--fg);
  letter-spacing: -0.005em;
}
.ledger__card__craft {
  font-size: 9px; letter-spacing: 0.30em;
  color: var(--dim);
}

/* ── Social row: just followers · since (X moved to top of card) */
.ledger__card__social {
  display: flex; align-items: center; justify-content: flex-start;
  gap: 10px;
  font-size: 9px; letter-spacing: 0.20em;
  padding: 0 4px;
  text-transform: uppercase;
}
.ledger__card__x {
  display: inline-flex; align-items: center; gap: 6px;
  color: var(--fg);
  text-decoration: none;
  padding: 4px 8px;
  border: 1px solid rgba(207,207,210,0.20);
  background: rgba(8,8,10,0.55);
  letter-spacing: 0.18em;
  transition: color 0.25s var(--easing),
              border-color 0.25s var(--easing),
              background 0.25s var(--easing);
  cursor: pointer;
  flex-shrink: 0;
}
.ledger__card__x:hover {
  color: var(--fg);
  border-color: var(--fg);
  background: rgba(20,20,22,0.85);
}
.ledger__card__x svg { display: block; }
.ledger__card__x-handle {
  font-size: 9px; letter-spacing: 0.18em;
  text-transform: lowercase;
}
.ledger__card__social-meta {
  display: inline-flex; align-items: center; gap: 6px;
  color: var(--dim);
  font-size: 9px; letter-spacing: 0.22em;
  text-align: right;
}
.ledger__card__social-meta .followers { color: var(--fg); }
.ledger__card__social-meta .dot       { color: var(--dim); }

/* ── Bottom metadata: serial + cycle pips */
.ledger__card__meta-bot {
  display: flex; align-items: center; justify-content: space-between;
  gap: 8px;
  font-size: 9px; letter-spacing: 0.28em;
  padding: 0 4px;
}
.ledger__card__meta-bot .serial { color: var(--dim); }

/* ── Achievement (replaces .serial position) ─────────────────────
   The card's biggest latest achievement, in the bottom-left of the
   meta-bot row. The value is the featured element — serif italic,
   medium-large — with the label stacked underneath in small mono
   dim. Stacking (rather than inline) keeps the layout intact even
   when the label is long (e.g. "CYCLE IV · PNL"), avoiding overflow
   into the cycle-pip cluster on narrow cards.
   Per :)'s Discord feedback ("the achievement one ... so put that"). */
/* EXACT match to OPTION A in _card-bottom-options.html — INLINE layout,
   not stacked. The val (italic serif 14px) and lbl (mono dim) sit on the
   SAME LINE separated by a 6px margin. We rebuilt this stacked-and-bigger
   in production by mistake; this restores the original prototype design. */
.ledger__card__meta-bot .ledger__card__achievement {
  color: var(--fg);
  letter-spacing: 0.10em;
  font-size: 10px;
  display: inline-flex;
  align-items: baseline;
}
.ledger__card__meta-bot .achievement-val {
  font-family: var(--serif); font-style: italic;
  font-size: 14px;
  line-height: 1;
  letter-spacing: -0.01em;
  margin-right: 6px;
  color: var(--fg);
}
.ledger__card__meta-bot .achievement-lbl {
  font-family: var(--mono);
  color: var(--dim);
}
.ledger__card__meta-bot .cycle {
  display: flex; align-items: center; gap: 8px;
}
.ledger__card__meta-bot .cycle-lbl { color: var(--dim); }
.ledger__card__meta-bot .cycle-pips {
  display: inline-flex; gap: 3px;
}

/* EXACT match to OPTION B in _card-bottom-options.html — INLINE,
   gold-2 mono 2-digit number + dim 'YR · ACTIVE' label, 6px gap. */
.ledger__card__meta-bot .ledger__card__tenure {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  color: var(--dim);
  font-size: 9px;
  letter-spacing: 0.20em;
}
.ledger__card__meta-bot .tenure-num {
  color: var(--gold-2, #cfcfd2);
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0;
}

/* EXACT match to OPTION C in _card-bottom-options.html — italic V seal
   + 28px hairline + 'VERIFIED · MMXXVI'. 8px gap inline. */
.ledger__card__meta-bot .ledger__card__signature {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: var(--dim);
  font-size: 9px;
  letter-spacing: 0.20em;
}
.ledger__card__meta-bot .sig-mark {
  font-family: var(--serif);
  font-style: italic;
  font-size: 18px;
  line-height: 1;
  color: var(--fg-2, #d8d6d0);
}
.ledger__card__meta-bot .sig-line {
  width: 28px; height: 1px;
  background: rgba(255,255,255,0.18);
  display: inline-block;
}
.ledger__card__meta-bot .pip {
  display: inline-block;
  width: 6px; height: 6px;
  border-radius: 50%;
  background: transparent;
  border: 1px solid rgba(207,207,210,0.40);
}
.ledger__card__meta-bot .pip.on { background: var(--fg); border-color: var(--fg); }

/* ── Examine affordance — pill that fades in on hover, top-right ── */
.ledger__card__examine {
  position: absolute; top: 14px; right: 14px;
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 9px; letter-spacing: 0.34em;
  color: rgba(255,255,255,0.95);
  padding: 6px 14px;
  border-radius: 999px;
  background: rgba(8,8,12,0.65);
  border: 1px solid rgba(255,255,255,0.22);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.18),
    0 6px 14px rgba(0,0,0,0.45);
  text-shadow: 0 1px 2px rgba(0,0,0,0.6);
  opacity: 0;
  transform: translateY(-2px);
  transition: opacity 0.3s var(--easing),
              transform 0.3s var(--easing),
              border-color 0.3s var(--easing),
              box-shadow 0.3s var(--easing);
  pointer-events: none;
  z-index: 4;
}
.ledger__card:hover .ledger__card__examine {
  opacity: 1;
  transform: none;
  border-color: rgba(255,255,255,0.45);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.30),
    0 8px 18px rgba(0,0,0,0.55);
}

/* ── Frozen state (during detail view) ─────────────────
   When the dossier opens, the entire rail must recede:
   - Active card hides completely (its contents would otherwise bleed
     through the dossier layout — handle, stat, sparkline overlapping)
   - Non-active cards become near-invisible with heavy blur so no text
     can leak around the dossier */
.ledger__rail.is-frozen .ledger__card:not(.is-active) {
  opacity: 0.04;
  filter: blur(8px) grayscale(0.7);
  transform: scale(0.92);
  pointer-events: none;
}
.ledger__rail.is-frozen .ledger__card.is-active {
  --dof-scale: 1.0;
  --dof-opacity: 0;     /* hidden — dossier replaces it */
  --dof-y: 0px;
  pointer-events: none;
}
/* Hide hover affordances on the active card too — no examine tag bleeding */
.ledger__rail.is-frozen .ledger__card.is-active .ledger__card__examine {
  opacity: 0 !important;
}
/* Lock horizontal scroll while a member is being examined */
.ledger__rail-wrap.is-frozen { overflow-x: hidden; }

/* ─── DOSSIER DETAIL VIEW (vault-open) ────────────────
   Full-rail-area overlay that takes over when a card is examined. Layout:
   - Top chrome (classification + close)
   - Massive serif handle, top-left
   - Network graph (SVG) — center node + 3 connected nodes + big PnL curve
   - Crafts as inscribed lines, top-right
   - Pull quote, lower-left italic
   - Wax seal footer, bottom-right
*/
/* Body scroll lock while dossier is open — main page can't move while you're
   reading a dossier. Combined with JS that saves/restores scroll position. */
body.is-dossier-open {
  overflow: hidden !important;
  touch-action: none;
}


.ledger__detail {
  /* FIXED to viewport so the rail's horizontal scroll has zero effect on
     where the dossier renders. Each property explicit + !important. NO
     `inset` shorthand — it would expand to `top:auto; left:auto; ...` and
     override the explicit values, putting the element at natural-flow
     position (which IS affected by scroll). */
  position: fixed !important;
  top:    0    !important;
  right:  auto !important;
  bottom: auto !important;
  left:   0    !important;
  width:  100vw !important;
  overflow: hidden !important;          /* clip anything that bleeds past the dossier bounds */
  height: 100vh !important;
  height: 100dvh !important;            /* dynamic vh — handles iOS Safari URL bar collapse */
  z-index: 9999;                         /* intentional top-of-stack — dossier covers nav, hero, chrome */
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.5s var(--easing);
}
.ledger__detail.is-visible { opacity: 1; pointer-events: auto; }

/* Pause every infinite animation inside the dossier while it's CLOSED.
   Dossier stays in the DOM (opacity: 0) so without this gate, dosScanDrift,
   dosCursorBlink, dosGlitch, dosHintPulse, etc. keep burning CPU + battery
   on mobile. Only run them when the user is actually looking at the dossier. */
.ledger__detail:not(.is-visible) * {
  animation-play-state: paused !important;
}

.ledger__detail__veil {
  position: absolute; inset: 0;
  background:
    radial-gradient(ellipse at 50% 40%,
      rgba(8,8,10,0.20) 0%,
      rgba(8,8,10,0.85) 55%,
      rgba(0,0,0,0.96) 95%),
    /* faint vertical scan-line tint */
    repeating-linear-gradient(0deg, rgba(0,0,0,0) 0, rgba(0,0,0,0) 2px,
                                    rgba(0,0,0,0.06) 2px, rgba(0,0,0,0.06) 3px);
  pointer-events: none;
  opacity: 0;
  animation: veilFadeIn 0.45s var(--easing) forwards;
}
@keyframes veilFadeIn { to { opacity: 1; } }

/* Top chrome strip */
.ledger__detail__topchrome {
  position: absolute; top: 22px; left: 28px; right: 28px;
  display: flex; align-items: center; justify-content: space-between;
  z-index: 5;
  opacity: 0;
  transform: translateY(-6px);
  transition: opacity 0.5s var(--easing) 0.2s, transform 0.5s var(--easing) 0.2s;
}
.ledger__detail.reveal .ledger__detail__topchrome { opacity: 1; transform: none; }
.ledger__detail__topchrome .cl {
  display: flex; align-items: center; gap: 10px;
  font-size: 10px; letter-spacing: 0.34em;
  color: var(--fg);
  text-transform: uppercase;
}
.ledger__detail__topchrome .cl .pulse-dot { margin: 0; }

/* Close button — uses .glass-btn for the liquid-glass look. Just sized + spaced here. */
.ledger__detail__close .x { font-size: 16px; line-height: 1; }

/* Network graph SVG */
.ledger__detail__graph {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  pointer-events: none;
}

/* Massive serif handle, top-left */
.ledger__detail__handle {
  position: absolute;
  top: 9vh; left: 4vw;
  max-width: 36vw;
  z-index: 4;
  opacity: 0;
  transform: translate(-12px, 0);
  transition: opacity 0.7s var(--easing) 0.18s, transform 0.7s var(--easing) 0.18s;
}
.ledger__detail.reveal .ledger__detail__handle { opacity: 1; transform: none; }
.ledger__detail__handle-eye {
  font-size: 10px; letter-spacing: 0.40em;
  margin-bottom: 10px;
}

/* Quote rendered INSIDE the handle block (under the name) — not the
   absolute-positioned bottom-left .ledger__detail__quote variant. */
.ledger__detail__handle-quote {
  margin-top: 18px;
  font-family: var(--serif); font-style: italic;
  font-size: clamp(16px, 1.4vw, 20px);
  line-height: 1.4;
  color: var(--fg-2);
  letter-spacing: -0.005em;
  opacity: 0.9;
  max-width: 36vw;
}
/* X button when placed inside the handle block (under the phrase) */
/* X pill in dossier — uses .glass-btn for the liquid-glass look. Just sized here. */
.ledger__detail__x--left {
  margin-top: 18px;
  font-size: 11px; letter-spacing: 0.18em;
}
.ledger__detail__handle-name {
  font-family: var(--serif); font-style: italic;
  font-size: clamp(40px, 5.4vw, 84px);
  font-weight: 400;
  line-height: 1.0;
  margin: 0 0 10px;
  color: var(--fg);
  letter-spacing: -0.015em;
}
.ledger__detail__handle-craft {
  font-size: 10px; letter-spacing: 0.36em;
  color: var(--fg);
  text-transform: uppercase;
}
/* Social block under handle: X button + followers + since */
.ledger__detail__social {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 14px;
  margin-top: 18px;
  font-size: 10px; letter-spacing: 0.24em;
  text-transform: uppercase;
}
.ledger__detail__x {
  display: inline-flex; align-items: center; gap: 8px;
  color: var(--fg);
  text-decoration: none;
  padding: 7px 11px;
  border: 1px solid rgba(207,207,210,0.30);
  background: rgba(8,8,10,0.55);
  letter-spacing: 0.18em;
  text-transform: lowercase;
  font-size: 11px;
  transition: color 0.25s var(--easing),
              border-color 0.25s var(--easing),
              background 0.25s var(--easing),
              transform 0.25s var(--easing);
}
.ledger__detail__x:hover {
  border-color: var(--fg);
  background: rgba(20,20,22,0.85);
  transform: translateY(-1px);
}
.ledger__detail__x svg { display: block; }
.ledger__detail__social-stat {
  display: inline-flex; flex-direction: column; gap: 2px;
  font-size: 9px; letter-spacing: 0.30em;
}
.ledger__detail__social-stat .dim { color: var(--dim); }
.ledger__detail__social-stat .val { color: var(--fg); font-size: 10px; }

/* Crafts as inscribed lines, top-right */
.ledger__detail__crafts {
  position: absolute;
  top: 9vh; right: 4vw;
  text-align: right;
  z-index: 4;
}
.ledger__detail__crafts-eye {
  font-size: 10px; letter-spacing: 0.40em;
  margin-bottom: 14px;
  opacity: 0;
  transition: opacity 0.6s var(--easing) 0.4s;
}
.ledger__detail.reveal .ledger__detail__crafts-eye { opacity: 1; }
.ledger__detail__craft-line {
  font-family: var(--serif); font-style: italic;
  font-size: clamp(20px, 1.8vw, 28px);
  line-height: 1.5;
  color: var(--fg);
  letter-spacing: -0.005em;
}
.ledger__detail__craft-line .ch {
  display: inline-block;
  opacity: 0;
  transform: translateY(10px);
  filter: blur(6px);
  transition:
    opacity 0.45s var(--easing) calc(0.55s + var(--line, 0) * 0.18s + var(--i, 0) * 0.018s),
    transform 0.55s var(--easing) calc(0.55s + var(--line, 0) * 0.18s + var(--i, 0) * 0.018s),
    filter 0.45s var(--easing) calc(0.55s + var(--line, 0) * 0.18s + var(--i, 0) * 0.018s);
}
.ledger__detail__craft-line .ch--space { width: 0.32em; }
.ledger__detail.reveal .ledger__detail__craft-line .ch {
  opacity: 1; transform: none; filter: blur(0);
}

/* Pull quote — lower-left, italic */
.ledger__detail__quote {
  position: absolute;
  left: 4vw; bottom: 14vh;
  max-width: 36vw;
  font-family: var(--serif); font-style: italic;
  font-size: clamp(18px, 1.6vw, 24px);
  line-height: 1.4;
  color: var(--fg-2);
  letter-spacing: -0.005em;
  z-index: 4;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.7s var(--easing) 1.5s, transform 0.7s var(--easing) 1.5s;
}
.ledger__detail.reveal .ledger__detail__quote { opacity: 0.95; transform: none; }
.ledger__detail__quote::before {
  content: '';
  display: block;
  width: 40px; height: 1px;
  background: rgba(207,207,210,0.50);
  margin-bottom: 16px;
}

/* Wax seal footer — bottom-right */
.ledger__detail__seal {
  position: absolute;
  right: 4vw; bottom: 8vh;
  display: flex; align-items: center; gap: 14px;
  z-index: 4;
  opacity: 0;
  transition: opacity 0.7s var(--easing) 1.7s;
}
.ledger__detail.reveal .ledger__detail__seal { opacity: 1; }
.ledger__detail__seal .seal-mark {
  /* ROMAN (not italic) — italic serif V has flat-topped horizontal serifs that
     read as "cut". Roman V has triangular top serifs and reads as a complete
     letter. This matches real wax-seal capitals. */
  font-family: Georgia, Cambria, 'Times New Roman', 'EB Garamond', serif;
  font-style: normal;
  font-weight: 500;
  font-size: 30px;
  width: 44px; height: 44px;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid rgba(207,207,210,0.40);
  border-radius: 50%;
  color: var(--fg);
  line-height: 1;
  padding-bottom: 0;
}
.ledger__detail__seal .seal-meta {
  display: flex; flex-direction: column; gap: 2px;
  font-family: var(--mono); font-size: 9px; letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--fg);
  text-align: right;
}

/* ═══════════════════════════════════════════════════════════════
   DOSSIER · TERMINAL INSTRUMENTATION + TIMELINE FOOTER
   Replaces the old fake PnL chart. Adds bracketed corner labels +
   ▌ AUTHORIZED line + ● REC indicator + drifting CRT scanlines.
   ═══════════════════════════════════════════════════════════════ */

/* CRT scanline overlay — drifts down very slowly */
.ledger__detail__scanlines {
  position: absolute; inset: 0;
  pointer-events: none;
  z-index: 2;
  opacity: 0;
  transition: opacity 0.6s var(--easing) 0.4s;
  background: repeating-linear-gradient(
    to bottom,
    rgba(255,255,255,0.022) 0px,
    rgba(255,255,255,0.022) 1px,
    transparent 1px,
    transparent 3px
  );
  animation: dosScanDrift 6s linear infinite;
}
.ledger__detail.reveal .ledger__detail__scanlines { opacity: 1; }
@keyframes dosScanDrift {
  from { background-position: 0 0; }
  to   { background-position: 0 6px; }
}

/* (REC indicator removed per Pedro — was too distracting) */

/* Terminal instrumentation overlay (inside the SVG, around the V) */
.instrument .i-br {
  stroke-dasharray: 24;
  stroke-dashoffset: 24;
  transition: stroke-dashoffset 0.45s cubic-bezier(.2,.8,.2,1);
}
.instrument .i-lbl,
.instrument .i-auth {
  opacity: 0;
  transition: opacity 0.45s ease;
}
/* Reveal cascade — staggered draw + fade */
.ledger__detail.reveal .instrument .i-br-tl { stroke-dashoffset: 0; transition-delay: 0.70s; }
.ledger__detail.reveal .instrument .i-br-tr { stroke-dashoffset: 0; transition-delay: 0.78s; }
.ledger__detail.reveal .instrument .i-br-bl { stroke-dashoffset: 0; transition-delay: 0.86s; }
.ledger__detail.reveal .instrument .i-br-br { stroke-dashoffset: 0; transition-delay: 0.94s; }
.ledger__detail.reveal .instrument .i-lbl-tl { opacity: 1; transition-delay: 1.05s; }
.ledger__detail.reveal .instrument .i-lbl-tr { opacity: 1; transition-delay: 1.20s; }
.ledger__detail.reveal .instrument .i-lbl-bl { opacity: 1; transition-delay: 1.35s; }
.ledger__detail.reveal .instrument .i-lbl-br { opacity: 1; transition-delay: 1.50s; }
.ledger__detail.reveal .instrument .i-auth   { opacity: 1; transition-delay: 1.75s; }

/* Blinking cursor in AUTHORIZED line */
.instrument .i-cursor {
  fill: #f3f3f1;
  animation: dosCursorBlink 1s steps(1) infinite;
}
@keyframes dosCursorBlink { 50% { opacity: 0; } }

/* V monolith pulse — fired by JS when a timeline event is clicked */
.center-node {
  transition: filter 0.4s ease;
}
.center-node.pulsing {
  animation: dosVPulse 0.95s cubic-bezier(.2,.8,.2,1);
}
@keyframes dosVPulse {
  0%   { filter: drop-shadow(0 0 0 rgba(243,243,241,0)); }
  35%  { filter: drop-shadow(0 0 14px rgba(243,243,241,0.55)); }
  100% { filter: drop-shadow(0 0 0 rgba(243,243,241,0)); }
}

/* Subtle CRT glitch every 14s — soft contrast bump + 1px shake */
.ledger__detail.reveal {
  animation: dosGlitch 14s steps(1, end) infinite 4s;
}
@keyframes dosGlitch {
  0%, 96.5%, 100%      { filter: none; transform: none; }
  97%                  { filter: contrast(1.20) brightness(1.05); transform: translateX(-1px); }
  97.5%                { filter: contrast(0.94); transform: translateX(1px); }
  98%                  { filter: none; transform: none; }
}

/* ── Timeline (replaces fake PnL chart) ──
   Position + width are set inline by JS at openDetail time (computed from
   actual SVG dimensions). CSS only handles z-index, opacity, and transitions. */
.ledger__detail__timeline {
  position: absolute;
  z-index: 4;
  opacity: 0;
  transition: opacity 0.6s var(--easing) 1.85s,
              transform 0.6s var(--easing) 1.85s;
}
.ledger__detail.reveal .ledger__detail__timeline {
  opacity: 1; transform: translateY(0) !important;
}

/* Submitted-record attribution — sits above everything in the timeline so
   it's clear the events are member-reported, not verified by Veritas. */
.ledger__detail__timeline__attr {
  text-align: center;
  font-family: var(--mono);
  font-size: 9px;
  letter-spacing: 0.36em;
  color: rgba(243,243,241,0.45);
  text-transform: uppercase;
  margin: 0 0 10px;
}

/* Click-to-expand affordance — subtle italic hint above the events.
   Fades out once the user clicks any event (they've discovered it). */
.ledger__detail__timeline__hint {
  text-align: center;
  font-family: 'Instrument Serif', serif;
  font-style: italic;
  font-size: 12px;
  color: rgba(243,243,241,0.45);
  margin: 0 0 12px;
  letter-spacing: 0.04em;
  transition: opacity 0.4s ease, transform 0.4s ease;
  /* Subtle breathing pulse so the eye finds it */
  animation: dosHintPulse 3.2s ease-in-out infinite;
}
@keyframes dosHintPulse {
  0%, 100% { opacity: 0.45; }
  50%      { opacity: 0.85; }
}
.ledger__detail__timeline.has-active .ledger__detail__timeline__hint {
  opacity: 0;
  animation: none;
  transform: translateY(-4px);
}

.ledger__detail__timeline__events {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
  gap: 16px;
  /* Bar is ABOVE this row — margin-top to space the labels below the bar. */
  margin-top: 18px;
  margin-bottom: 14px;
}
.ledger__detail__timeline__ev {
  text-align: center;
  min-width: 0;
  padding: 4px 6px;
  background: transparent;
  border: none;
  font: inherit;
  color: inherit;
  cursor: pointer;
  opacity: 0.55;
  transition: opacity 0.45s var(--easing),
              transform 0.45s var(--easing);
  font-family: var(--mono);
}
.ledger__detail__timeline__ev:hover {
  opacity: 0.95;
  transform: translateY(-1px);
}
.ledger__detail__timeline__ev:hover .yr {
  color: rgba(243,243,241,0.95);
}
.ledger__detail__timeline__ev:focus-visible {
  outline: 1px solid rgba(243,243,241,0.4);
  outline-offset: 4px;
}
.ledger__detail__timeline.has-active .ledger__detail__timeline__ev:not(.is-active) {
  opacity: 0.20;
}
.ledger__detail__timeline__ev.is-active {
  opacity: 1;
  transform: translateY(-2px) scale(1.04);
}
.ledger__detail__timeline__ev .yr {
  color: var(--dim);
  font-size: 10px; letter-spacing: 0.30em;
  margin-bottom: 6px;
  transition: color 0.45s ease;
}
.ledger__detail__timeline__ev.is-active .yr { color: var(--fg); }
/* Undated events: render the year as a centered dim middot so the
   slot doesn't look broken/empty. We never invent a year. */
.ledger__detail__timeline__ev.is-undated .yr {
  letter-spacing: 0;
  opacity: 0.4;
}
.ledger__detail__timeline__ev .what {
  color: rgba(243,243,241,0.85);
  font-size: 11px; line-height: 1.35;
  letter-spacing: 0.04em;
}
.ledger__detail__timeline__ev.is-active .what { color: #fff; }

.ledger__detail__timeline__bar {
  position: relative;
  height: 1px;
  background: rgba(243,243,241,0.20);
  margin-bottom: 14px;
}
.ledger__detail__timeline__bar-fill {
  position: absolute;
  top: 0; left: 0; height: 1px;
  background: var(--fg);
  width: 0%;
  transition: width 0.7s cubic-bezier(.2,.8,.2,1);
}
.ledger__detail__timeline__pin {
  position: absolute;
  top: -3px; width: 7px; height: 7px;
  margin-left: -3.5px;
  background: var(--fg);
  border-radius: 50%;
  cursor: pointer;
  transition: width 0.5s cubic-bezier(.2,.8,.2,1),
              height 0.5s cubic-bezier(.2,.8,.2,1),
              top 0.5s cubic-bezier(.2,.8,.2,1),
              margin-left 0.5s cubic-bezier(.2,.8,.2,1);
}
.ledger__detail__timeline__pin.is-active {
  width: 11px; height: 11px;
  top: -5px; margin-left: -5.5px;
}
.ledger__detail__timeline__pin .ring,
.ledger__detail__timeline__pin .ring-outer {
  position: absolute;
  top: 50%; left: 50%;
  width: 7px; height: 7px;
  margin: -3.5px 0 0 -3.5px;
  border-radius: 50%;
  opacity: 0;
  pointer-events: none;
  transition: width 0.65s cubic-bezier(.2,.8,.2,1),
              height 0.65s cubic-bezier(.2,.8,.2,1),
              margin 0.65s cubic-bezier(.2,.8,.2,1),
              opacity 0.65s ease;
}
.ledger__detail__timeline__pin .ring {
  border: 1px solid rgba(243,243,241,0.55);
}
.ledger__detail__timeline__pin .ring-outer {
  border: 1px solid rgba(243,243,241,0.18);
  transition-duration: 0.85s;
}
.ledger__detail__timeline__pin.is-active .ring {
  width: 28px; height: 28px;
  margin: -14px 0 0 -14px;
  opacity: 1;
}
.ledger__detail__timeline__pin.is-active .ring-outer {
  width: 46px; height: 46px;
  margin: -23px 0 0 -23px;
  opacity: 1;
}

.ledger__detail__timeline__axis {
  /* Pinned to the BOTTOM of the dossier panel via absolute positioning so
     the axis labels (T - NY / NOW) are ALWAYS visible regardless of how
     tall the events above wrap. The dossier (.ledger__detail) is the
     positioned ancestor here, so absolute coords are relative to it. */
  position: absolute;
  left: 28px;
  right: 28px;
  bottom: 22px;
  display: flex; justify-content: space-between;
  color: var(--dim);
  font-family: var(--mono);
  font-size: 9px; letter-spacing: 0.30em;
  text-transform: uppercase;
}
.ledger__detail__timeline__context {
  margin: 18px 0 0;
  min-height: 26px;
  text-align: center;
  font-family: 'Instrument Serif', serif;
  font-style: italic;
  font-size: 17px;
  color: rgba(243,243,241,0.85);
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 0.5s ease, transform 0.5s ease;
}
.ledger__detail__timeline.has-active .ledger__detail__timeline__context {
  opacity: 1; transform: none;
}

/* (Claims tier removed — every member now has a field-history timeline.) */

/* ── Manifesto declaration fallback (Concept A) — when no events ──
   Positioned below the V graph + AUTHORIZED line. Width-capped + centered
   so it can't overlap the seal (right) or stretch across the V zone. */
.ledger__detail__declaration {
  position: absolute;
  left: 50%;
  bottom: 5vh;
  transform: translateX(-50%) translateY(8px);
  width: min(560px, 60vw);
  z-index: 4;
  text-align: center;
  border-top: 1px solid rgba(243,243,241,0.14);
  padding-top: 22px;
  opacity: 0;
  transition: opacity 0.6s var(--easing) 1.85s,
              transform 0.6s var(--easing) 1.85s;
}
.ledger__detail.reveal .ledger__detail__declaration {
  opacity: 1; transform: translateX(-50%);
}
.ledger__detail__declaration__quote {
  font-family: 'Bodoni Moda', 'Instrument Serif', serif;
  font-weight: 400; font-style: italic;
  font-size: clamp(20px, 2.4vw, 30px);
  line-height: 1.20;
  color: rgba(243,243,241,0.92);
  margin: 0 auto 12px;
  max-width: 92%;
}
.ledger__detail__declaration__attr {
  color: var(--dim);
  font-family: var(--mono);
  font-size: 10px; letter-spacing: 0.36em;
  text-transform: uppercase;
  margin: 0;
}

/* Mobile: stack the dossier vertically + shrink chrome */
@media (max-width: 900px) {
  .ledger__detail__handle { top: 12vh; left: 6vw; right: 6vw; max-width: 88vw; }
  .ledger__detail__crafts { position: relative; top: auto; right: auto;
                            text-align: left; padding: 4vh 6vw 0; }
  .ledger__detail__quote { left: 6vw; right: 6vw; bottom: 16vh; max-width: 88vw; }
  .ledger__detail__seal  { right: 6vw; bottom: 6vh; }
  .ledger__detail__timeline {
    /* Mobile: stay centered, just narrower so the bar pins don't reach edges */
    left: 50%; right: auto;
    width: 88vw;
    transform: translateX(-50%);
  }
  .ledger__detail__timeline__ev .what { font-size: 10px; }
}


/* ─── REQUEST ACCESS (Beat 6) — proper application form, modern fintech ──
   No wax seal, no Latin chrome, no rotating text rings. Two real fields. */
.beat--door { position: relative; }

.door__bg {
  position: absolute; inset: 0;
  pointer-events: none; overflow: hidden; z-index: 0;
}
.door__bg-veil {
  position: absolute; inset: 0;
  background: radial-gradient(ellipse at 50% 50%,
    rgba(0,0,0,0.18) 0%, rgba(0,0,0,0.72) 60%, rgba(0,0,0,0.94) 100%);
}
.door__bg-grain {
  position: absolute; inset: 0; opacity: 0.45;
  background-image: repeating-linear-gradient(0deg,
    rgba(255,255,255,0) 0, rgba(255,255,255,0) 2px,
    rgba(255,255,255,0.012) 2px, rgba(255,255,255,0.012) 3px);
}

.door {
  position: sticky; top: 0; z-index: 1;
  height: 100vh;
  height: 100dvh;
  display: flex; flex-direction: column;
  align-items: center;
  /* Top-justified, NOT center. Center caused content to ride into the chrome
     bar on shorter viewports because flex centering ignores chrome overlay. */
  justify-content: flex-start;
  gap: 14px;
  /* Top padding generously clears chrome (~64px) + breathing room.
     Min 110px so the seats counter never touches the chrome bar. */
  padding: clamp(110px, 14vh, 160px) 6vw clamp(60px, 8vh, 100px);
  text-align: center;
  opacity: 0;
  transition: opacity 0.6s var(--easing);
}
.door.is-visible { opacity: 1; }

/* ── Staggered reveal cascade — when .door becomes visible, children
       fade + slide in sequence so the page reads top-to-bottom. ── */
.door > * {
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.6s var(--easing),
              transform 0.6s var(--easing);
}
.door.is-visible .door__mark    { opacity: 1; transform: none; transition-delay: 0.05s; }
.door.is-visible .door__eyebrow { opacity: 1; transform: none; transition-delay: 0.20s; }
.door.is-visible .door__lede    { opacity: 1; transform: none; transition-delay: 0.35s; }
.door.is-visible .door__sub     { opacity: 1; transform: none; transition-delay: 0.55s; }
.door.is-visible .door__form    { opacity: 1; transform: none; transition-delay: 0.75s; }
.door.is-visible .door__foot    { opacity: 1; transform: none; transition-delay: 1.10s; }

/* ══════════════════════════════════════════════════════════════
   APPLY · REQUEST ACCESS — polished pass
   Terminal-instrument seats counter, hairline corner-bracketed form,
   refined focus states, staggered reveal cascade tied to .is-visible.
   ══════════════════════════════════════════════════════════════ */

/* Seats counter — uses .glass-btn for the liquid-glass treatment, but
   tones down the rim/sheen brightness because it's a static readout, not
   a button. Less white = quieter, doesn't compete with the headline. */
.door__mark {
  font-size: 10px;
  letter-spacing: 0.36em;
  padding: 14px 28px;
  margin-bottom: 6px;
  cursor: default;
  gap: 12px;
  opacity: 0.55;
  /* Override glass-btn — strip almost all the white. Just a hairline ring
     of the pill shape, no rim glow, no white highlights. */
  background: rgba(8,8,12,0.35) !important;
  border-color: rgba(255,255,255,0.06) !important;
  box-shadow:
    inset 0 0 0 1px rgba(255,255,255,0.02),
    0 4px 10px rgba(0,0,0,0.35) !important;
}
.door__mark::before {
  /* Sheen all but invisible — barely a hint of curvature on top */
  background:
    radial-gradient(ellipse 90% 100% at 50% 0%,
      rgba(255,255,255,0.04) 0%,
      rgba(255,255,255,0.01) 35%,
      transparent 70%) !important;
}
.door__mark:hover { transform: none; }
/* Legacy corner-bracket spans no longer rendered (replaced by glass-btn pill). */
.door__mark-corner { display: none; }
.door__mark-label { color: rgba(243,243,241,0.85); }
.door__mark-num {
  color: var(--fg);
  font-size: 14px;
  font-weight: 500;
  letter-spacing: 0.04em;
  /* PERF: pulse runs only while the door is in view (via .is-visible).
     Otherwise it's a constant repaint cost on offscreen content. */
  animation: doorMarkPulse 2.6s ease-in-out infinite;
  animation-play-state: paused;
}
.door.is-visible .door__mark-num { animation-play-state: running; }
@keyframes doorMarkPulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.75; }
}

.door__eyebrow {
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.42em;
  color: var(--fg); margin-top: 4px;
}

.door__lede {
  font-family: var(--serif); font-weight: 400;
  font-size: clamp(36px, 4.6vw, 64px);
  line-height: 1.05; color: var(--fg);
  margin: 0; max-width: 22ch;
  letter-spacing: -0.015em;
}
/* Brand-mark italic — same treatment as the manifesto lede's italic V */
.door__lede-mark {
  font-style: italic;
  font-family: 'Bodoni Moda', var(--serif), serif;
  font-weight: 500;
  letter-spacing: -0.005em;
}

.door__sub {
  font-family: var(--serif); font-style: italic;
  font-size: clamp(15px, 1.3vw, 19px);
  line-height: 1.45; color: var(--fg-2);
  margin: 0; max-width: 50ch;
  opacity: 0.85;
}

/* Mobile-only context recap. Hidden on desktop because the manifesto
   carries the same pitch a beat earlier. Mobile rules in @media block
   re-show + style this. */
.door__recap {
  display: none;
}

.door__form {
  position: relative;
  display: flex; flex-direction: column;
  gap: 22px;
  width: min(640px, 92vw);
  margin-top: 28px;
  padding: 32px 0;
}

/* Hairline corner registration marks framing the form */
.door__form-regmark {
  position: absolute;
  width: 14px; height: 14px;
  border: 1px solid rgba(243,243,241,0.32);
  pointer-events: none;
}
.door__form-regmark--tl { top: 0; left: -10px;     border-right: none; border-bottom: none; }
.door__form-regmark--tr { top: 0; right: -10px;    border-left: none;  border-bottom: none; }
.door__form-regmark--bl { bottom: 0; left: -10px;  border-right: none; border-top: none; }
.door__form-regmark--br { bottom: 0; right: -10px; border-left: none;  border-top: none; }

.door__row {
  position: relative;
  display: flex; flex-direction: column;
  gap: 10px;
  text-align: left;
}
.door__label {
  display: flex; align-items: baseline; justify-content: space-between;
  font-size: 9px; letter-spacing: 0.42em;
  color: var(--fg); opacity: 0.70;
  text-transform: uppercase;
}
.door__field-counter {
  font-size: 9px; letter-spacing: 0.32em;
  color: var(--dim); opacity: 0.7;
  text-transform: uppercase;
}
/* Form inputs — glass-pill style, matches site button aesthetic. */
.door__field-input {
  position: relative;
  width: 100%;
  padding: 18px 24px;
  border-radius: 999px;
  background:
    radial-gradient(ellipse 80% 60% at 50% 100%,
      rgba(255,255,255,0.08) 0%,
      transparent 70%),
    rgba(8,8,12,0.55);
  border: 1px solid rgba(255,255,255,0.18);
  font-family: var(--serif);
  font-size: clamp(16px, 1.3vw, 18px);
  color: var(--fg);
  outline: none;
  text-shadow: 0 1px 2px rgba(0,0,0,0.6);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.30),
    inset 0 -1px 1px rgba(255,255,255,0.04),
    0 0 18px rgba(255,255,255,0.04),
    0 6px 14px rgba(0,0,0,0.38),
    0 2px 4px rgba(0,0,0,0.20);
  transition: border-color 0.35s var(--easing),
              background 0.35s var(--easing),
              box-shadow 0.35s var(--easing);
}
.door__field-input::placeholder {
  color: var(--dim); opacity: 0.55; font-style: italic;
}
.door__field-input:hover {
  border-color: rgba(255,255,255,0.32);
}
.door__field-input:focus {
  border-color: rgba(255,255,255,0.55);
  background:
    radial-gradient(ellipse 80% 60% at 50% 100%,
      rgba(255,255,255,0.14) 0%,
      transparent 70%),
    rgba(14,14,18,0.78);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.50),
    inset 0 -1px 1px rgba(255,255,255,0.10),
    0 0 32px rgba(255,255,255,0.10),
    0 10px 22px rgba(0,0,0,0.50);
}

.door__action {
  display: flex; align-items: center; justify-content: space-between;
  gap: 18px;
  margin-top: 6px;
}
.door__action-note {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 10px; letter-spacing: 0.30em;
  color: var(--dim);
  text-transform: uppercase;
  text-align: left;
}
.door__action-note .pulse-dot {
  width: 5px; height: 5px;
  background: var(--fg);
  margin: 0;
}

/* Door submit — uses .glass-btn for the liquid-glass look. Just sized + behavior here. */
.door__submit {
  font-size: 11px; letter-spacing: 0.34em;
  text-transform: uppercase;
}
.door__submit-arrow {
  display: inline-flex; align-items: center;
  font-family: var(--serif); font-size: 18px; line-height: 1;
  /* No hover transform — button must stay perfectly still per design pass.
     Matches the seats counter pill above which has zero hover motion. */
}
.door__submit:disabled {
  opacity: 0.35;
  cursor: default;
}
/* Hard-suppress every motion the .glass-btn utility applies on hover.
   The base .glass-btn:hover lifts the element via translateY(-1px) and
   swaps shadows/borders — that's the "wiggle" the user sees. For the
   REQUEST ACCESS CTA we want the seats-counter behavior: rock solid,
   no movement at all. */
.door__submit:not(:disabled):hover,
.door__submit:not(:disabled):active,
.door__submit:not(:disabled):focus {
  transform: none !important;
}
.door__submit:not(:disabled):hover::before {
  background: inherit !important;
}

.door__status {
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.30em;
  color: var(--dim); min-height: 1.2em; text-align: center;
  text-transform: uppercase;
  opacity: 0;
  transition: opacity 0.4s var(--easing), color 0.4s var(--easing);
}
.door__status.is-visible { opacity: 1; }
.door__status.is-error { color: #d8a3a3; }

.door__receipt {
  display: flex; align-items: center; gap: 14px;
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.16em;
  color: var(--fg);
  text-transform: none;
  margin-top: 10px;
  padding: 12px 18px;
  border: 1px solid rgba(207,207,210,0.22);
  background: rgba(8,8,10,0.55);
  max-width: 560px;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.6s var(--easing), transform 0.6s var(--easing);
  text-align: left;
}
.door__receipt.is-visible { opacity: 1; transform: none; }
.door__receipt-tick {
  font-size: 18px; line-height: 1;
  color: var(--fg);
  flex-shrink: 0;
}
.door__receipt-text {
  color: var(--fg-2);
  line-height: 1.5;
}
.door__receipt-num {
  color: var(--fg);
  letter-spacing: 0.20em;
  font-weight: 500;
}

.door__foot {
  position: absolute; bottom: 24px; left: 28px; right: 28px;
  /* 3-column grid guarantees the middle item is truly centered relative
     to the viewport, not just centered between two unequal-width siblings
     (which is what justify-content: space-between would give). */
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  font-family: var(--mono);
  font-size: 10px; letter-spacing: 0.30em;
  color: var(--dim);
  text-transform: uppercase;
}
.door__foot > :first-child  { justify-self: start; }
.door__foot > :nth-child(2) { justify-self: center; }
.door__foot > :last-child   { justify-self: end; }

@media (max-width: 600px) {
  .door__action { flex-direction: column; align-items: stretch; }
  .door__submit { justify-content: center; }
  .door__foot { position: relative; bottom: auto; left: auto; right: auto;
                flex-direction: column; gap: 6px; text-align: center;
                margin-top: 24px; }
}

/* ─── PROGRESS HAIRLINE ──────────────────────────── */

.progress {
  position: fixed; left: 0; right: 0; top: 0; height: 1px;
  background: rgba(255,255,255,0.04); z-index: 90;
  opacity: 0; transition: opacity 0.6s var(--easing);
}
.progress.visible { opacity: 1; }
.progress__bar {
  height: 100%; width: 0%;
  background: linear-gradient(to right, transparent, var(--gold-2));
  transition: width 0.1s linear;
}

/* ─── RESPONSIVE ─────────────────────────────────── */

@media (max-width: 800px) {
  .manifesto { padding: 14vh 6vw 6vh 6vw; }
  .ledger__head { padding: 0 6vw; }
  .ledger__rail { padding: 0 6vw; }
  .ledger__detail .dossier { left: 6vw; right: 6vw; grid-template-columns: 1fr; gap: 16px; }
  .chrome__nav { gap: 18px; }
  .chrome__right { display: none; }
}

/* ─── POLISH PASS ───────────────────────────────────────────────
   Accessibility focus rings, missing micro-interactions, hover
   refinements, reduced-motion safety. Added during audit. */

/* Keyboard focus — hairline outline, only visible on keyboard nav.
   Mouse users see nothing (focus-visible not :focus). */
/* Focus-visible defensive pattern: show a ring on :focus by default
   (so older Safari without :focus-visible support — pre-15.4 — still
   gets a visible ring), then suppress only when :focus-visible exists
   AND the focus is non-keyboard (i.e. mouse). This degrades gracefully:
   modern browsers get the keyboard-only ring; old Safari shows the ring
   on every focus rather than going completely blind. */
:focus {
  outline: 1px solid rgba(207,207,210,0.55);
  outline-offset: 3px;
}
:focus:not(:focus-visible) { outline: none; }
:focus-visible {
  outline: 1px solid rgba(207,207,210,0.55);
  outline-offset: 3px;
}
.door__field-input:focus-visible {
  outline: 1px solid rgba(207,207,210,0.55);
  outline-offset: 0;
}
.ledger__card:focus-visible {
  outline: 1px solid rgba(207,207,210,0.55);
  outline-offset: 4px;
}

/* Make cards keyboard-clickable + show pointer */
.ledger__card { cursor: pointer; }

/* Chrome-left wordmark — clickable to scroll to top */
.chrome__left {
  cursor: pointer;
  transition: opacity 0.3s var(--easing);
}
.chrome__left:hover { opacity: 0.75; }

/* Manifesto eyebrow + meta gain a faint hover sheen — dead pixels otherwise */
.manifesto__eyebrow,
.manifesto__meta {
  transition: opacity 1.2s var(--easing);
}

/* X buttons — subtle icon nudge on hover for delight */
.ledger__card__x svg,
.ledger__detail__x svg {
  transition: transform 0.25s cubic-bezier(.2,.8,.2,1);
}
.ledger__card__x:hover svg,
.ledger__detail__x:hover svg {
  transform: rotate(-6deg) scale(1.08);
}

/* Door SEAL counter — static, no hover state per design pass.
   (FIX: removed the `border-color` + `background` shift on hover; combined
   with the magnetic translate it was causing the pill to wiggle. JS now
   excludes .door__mark from the magnetic targets list as well.) */
.door__mark { transition: none; }

/* Smiley portraits in cards — subtle scale on card hover */
.ledger__card__portrait svg {
  transition: transform 0.6s cubic-bezier(.2,.8,.2,1);
}
.ledger__card:hover .ledger__card__portrait svg {
  transform: scale(1.04);
}

/* Manifesto body italic em — was visually flat, give it a slight color lift */
.manifesto__body em {
  font-style: italic;
  color: var(--fg);
}

/* Selection styling — match site palette instead of browser default */
::selection {
  background: rgba(233,233,235,0.20);
  color: var(--fg);
}

/* Reduced motion — respect user preference. Strip non-essential animations. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  /* Magnetism transforms keep working but the easing settles instantly */
  .manifesto__lede .ch { transition: none; }
  /* Hard-kill flashing animations on the dossier — WCAG 2.3.3 */
  .ledger__detail.reveal,
  .ledger__detail__topchrome,
  .ledger__detail__scanlines,
  .pulse-dot {
    animation: none !important;
  }
  /* Hide the Spline scenes — Spline animations run inside their own
     iframe and ignore CSS animation rules above. Better to remove the
     vestibular hazard entirely than to leave it spinning. */
  .stage__v-hero spline-viewer,
  .stage__spline spline-viewer {
    display: none !important;
  }
}

/* ═════════════════════════════════════════════════════════════
   PREMIUM POLISH PASS — based on 2026 web design trends:
   glassmorphism, magnetic interactions, cursor responsiveness,
   purposeful micro-motion, state-aware feedback. Each addition
   has a comment explaining what premium technique it applies.
   ═════════════════════════════════════════════════════════════ */

/* Chrome bar — semi-transparent dark fill instead of backdrop-filter.
   PERF: backdrop-filter on a full-width sticky bar runs every frame and
   is one of the most expensive CSS properties. The dark gradient fill
   reads as glass-like enough without the constant blur cost. */
.chrome {
  background: linear-gradient(180deg, rgba(5,5,7,0.92), rgba(5,5,7,0.78));
  border-bottom: 1px solid rgba(207,207,210,0.08);
}

/* ── NAV links — animated underline + letter-spacing breath
   Premium sites animate MULTIPLE properties on link hover, not
   just color. Letter-spacing widens slightly so the link reads
   as "expanding toward you". */
.chrome__nav a {
  position: relative;
  transition:
    opacity 0.35s cubic-bezier(.2,.8,.2,1),
    letter-spacing 0.45s cubic-bezier(.2,.8,.2,1);
}
@media (hover: hover) {
  .chrome__nav a:hover {
    letter-spacing: 0.20em;   /* slight widening — only on real cursors */
  }
}

/* ── MAGNETIC BUTTON utility ─────────────────────────────────
   Buttons that subtly translate toward the cursor when nearby.
   JS writes --magnetic-x/y per element on pointermove. */
.is-magnetic {
  transition: transform 0.28s cubic-bezier(.2,.8,.2,1);
  --magnetic-x: 0px;
  --magnetic-y: 0px;
}
.is-magnetic:hover {
  transform: translate(var(--magnetic-x), var(--magnetic-y));
}

/* (Cleanup pass: removed dead `.cursor-dot, .cursor-ring { display:none }`
   rule — those elements never exist in HTML and the JS that referenced them
   was wrapped in `if (false)` and has now been deleted.) */

/* ── SPARKLINE LOADING SHIMMER ───────────────────────────────
   Each card sparkline gets a one-shot sweep when first revealed —
   a thin highlight that travels left-to-right across the line. */
.ledger__card__spark .spark__line {
  filter: drop-shadow(0 0 6px rgba(207,207,210,0.10));
}
/* PERF: dropped infinite sparkPulse — was running drop-shadow keyframe on
   every visible card forever, costing repaints. Static drop-shadow above
   already gives the line glow. */

/* ── CARD HOVER GLOW — focal card gets a soft outer halo ─────
   Layered radial-gradient creates the impression of an ambient
   light source above the card. Premium e-comm sites do this. */
.ledger__card::after {
  content: '';
  position: absolute;
  inset: -1px;
  pointer-events: none;
  border-radius: inherit;
  background: radial-gradient(ellipse at 50% 0%,
    rgba(207,207,210,0.10) 0%,
    transparent 60%);
  opacity: 0;
  transition: opacity 0.45s cubic-bezier(.2,.8,.2,1);
}
.ledger__card:hover::after { opacity: 1; }

/* Press feedback DISABLED — was causing the button to appear to "shift"
   on hover/click. Per design pass: button must stay perfectly still, only
   the arrow slides. (Kept tap-highlight reset below.) */
.door__submit:not(:disabled):active {
  /* no transform, no shadow change — button must NOT move */
}
button, a, .ledger__card { -webkit-tap-highlight-color: transparent; }

/* ── ENHANCED CHROME wordmark hover — wider letter-spacing
   on hover to reinforce the click target */
.chrome__left {
  transition: opacity 0.3s var(--easing), letter-spacing 0.4s var(--easing);
}
.chrome__left:hover { letter-spacing: 0.16em; }

/* Film grain DISABLED for perf — was running an infinite keyframe animation
   and the mix-blend-mode + pseudo-noise patterns added GPU cost. */
.film-grain { display: none; }

/* ── X BUTTON — refined hover with scale + slight rotate */
.ledger__card__x,
.ledger__detail__x {
  position: relative;
  overflow: hidden;
}
.ledger__card__x::before,
.ledger__detail__x::before {
  content: '';
  position: absolute;
  top: 50%; left: 50%;
  width: 0; height: 0;
  background: rgba(255,255,255,0.06);
  border-radius: 50%;
  transform: translate(-50%, -50%);
  transition: width 0.5s cubic-bezier(.2,.8,.2,1),
              height 0.5s cubic-bezier(.2,.8,.2,1);
  pointer-events: none;
}
.ledger__card__x:hover::before,
.ledger__detail__x:hover::before {
  width: 200%; height: 200%;
}

/* DISABLED — was creating a shimmer sweep on hover that read as motion.
   Per design pass: button must stay perfectly still, matching the seats
   counter pill above it. No sweep, no slide, no pulse. */
.door__submit:not(:disabled) {
  position: relative;
}

/* ── INPUT FIELD — premium focus animation with glow ─────────
   Border animates from a corner instead of all-around */
.door__field-input {
  position: relative;
  transition:
    border-color 0.35s cubic-bezier(.2,.8,.2,1),
    background 0.35s cubic-bezier(.2,.8,.2,1),
    box-shadow 0.35s cubic-bezier(.2,.8,.2,1);
}
.door__field-input:focus {
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.04),
    0 0 0 3px rgba(207,207,210,0.06);
}

/* ── DETAILS CLOSE button — refined micro-interaction */
.ledger__detail__close {
  position: relative;
  overflow: hidden;
  transition:
    color 0.3s var(--easing),
    border-color 0.3s var(--easing),
    background 0.3s var(--easing),
    transform 0.25s cubic-bezier(.2,.8,.2,1);
}
.ledger__detail__close:hover { transform: translateY(-1px); }
.ledger__detail__close:active { transform: translateY(0); }

/* ── SCROLL PROGRESS — refine the gold→white gradient + glow */
.progress { height: 2px; }
.progress__bar {
  background: linear-gradient(
    to right,
    transparent,
    rgba(207,207,210,0.55) 30%,
    var(--fg) 60%,
    rgba(207,207,210,0.55) 90%,
    transparent
  );
  filter: drop-shadow(0 0 6px rgba(207,207,210,0.30));
}

/* ── MANIFESTO BODY — refine italic em with subtle highlight */
.manifesto__body em {
  font-style: italic;
  color: var(--fg);
  background: linear-gradient(
    to bottom,
    transparent 0,
    transparent 88%,
    rgba(207,207,210,0.22) 88%,
    rgba(207,207,210,0.22) 96%,
    transparent 96%
  );
  padding: 0 2px;
}

/* ── GLOBAL link/button polish */
a, button, [role="button"] {
  transition-property: color, opacity, border-color, background-color,
                       transform, letter-spacing, box-shadow;
  transition-duration: 0.32s;
  transition-timing-function: cubic-bezier(.2,.8,.2,1);
}

/* Native cursor restored — was hidden for the cursor-follower.
   Use proper cursor types for affordance. */
button, a, [role="button"], .ledger__card { cursor: pointer; }

/* ═════════════════════════════════════════════════════════════
   APPLE LIQUID GLASS BUTTONS (iOS 26 style)
   Thick backdrop-blur + saturation boost, asymmetric inner
   border for refraction feel, layered shadows for depth, and
   shimmer on hover. Applied to all primary CTAs.
   ═════════════════════════════════════════════════════════════ */

/* ═════════════════════════════════════════════════════════════
   LIQUID GLASS BUTTONS — pure CSS, no backdrop-filter.
   The "glass" look comes from layered gradients + asymmetric
   borders + inner highlights. Visible against any background.
   No GPU cost from backdrop blur.
   ═════════════════════════════════════════════════════════════ */

.door__submit,
.ledger__detail__close,
.door__mark {
  /* MUCH stronger glass effect — visible without backdrop. The trick:
     a clear bright reflection band along the TOP HALF, dark bottom,
     hard contrast at the seam. That's what Apple liquid glass does. */
  background:
    /* Top reflection — bright vertical band */
    linear-gradient(180deg,
      rgba(255,255,255,0.32) 0%,
      rgba(255,255,255,0.12) 18%,
      rgba(255,255,255,0.04) 38%,
      rgba(0,0,0,0.10) 50%,
      rgba(0,0,0,0.30) 100%),
    /* Top-center hot-spot for that "light source" feel */
    radial-gradient(ellipse 60% 50% at 50% 0%,
      rgba(255,255,255,0.40) 0%,
      transparent 70%),
    /* Base */
    rgba(28,28,30,0.92);
  border: 1px solid rgba(255,255,255,0.18);
  /* Sharp white line right at the top edge — the "rim light" effect */
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.45),     /* the rim light at top */
    inset 0 0 0 1px rgba(255,255,255,0.04),   /* faint inner glow */
    inset 0 -2px 4px rgba(0,0,0,0.35),        /* bottom inner shadow for depth */
    0 8px 24px rgba(0,0,0,0.55),              /* main drop shadow */
    0 2px 4px rgba(0,0,0,0.40);               /* tight contact shadow */
  position: relative;
}

/* Pseudo-element creates an extra reflective sheen near the top that
   moves on hover, simulating light bouncing off curved glass */
.door__submit::after,
.ledger__detail__close::after,
.door__mark::after {
  content: '';
  position: absolute;
  inset: 1px 1px auto 1px;
  height: 50%;
  pointer-events: none;
  background: linear-gradient(180deg,
    rgba(255,255,255,0.10) 0%,
    rgba(255,255,255,0) 100%);
  border-radius: inherit;
  opacity: 0.8;
  transition: opacity 0.4s var(--easing);
}
/* Hover brightening for the ledger close X only.
   FIX: removed .door__mark from this selector — the seats counter pill
   must stay perfectly static (no glass shift, no movement). The .door__submit
   was already intentionally excluded so the button stays rock solid. */
.ledger__detail__close:hover::after { opacity: 1; }

.ledger__detail__close:hover {
  background:
    linear-gradient(180deg,
      rgba(255,255,255,0.40) 0%,
      rgba(255,255,255,0.18) 18%,
      rgba(255,255,255,0.06) 38%,
      rgba(0,0,0,0.06) 50%,
      rgba(0,0,0,0.25) 100%),
    radial-gradient(ellipse 60% 50% at 50% 0%,
      rgba(255,255,255,0.55) 0%,
      transparent 70%),
    rgba(34,34,38,0.95);
  border-color: rgba(255,255,255,0.32);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.65),
    inset 0 0 0 1px rgba(255,255,255,0.08),
    inset 0 -2px 4px rgba(0,0,0,0.35),
    0 8px 24px rgba(0,0,0,0.55),
    0 2px 4px rgba(0,0,0,0.40);
}

/* Disabled state — flat, no glass */
.door__submit:disabled {
  background: rgba(8,8,10,0.55);
  border-color: rgba(207,207,210,0.10);
  box-shadow: none;
}

/* ── X-buttons: smaller liquid glass */
.ledger__card__x,
.ledger__detail__x {
  background:
    radial-gradient(ellipse 80% 60% at 50% 0%,
      rgba(255,255,255,0.14) 0%,
      transparent 70%),
    linear-gradient(180deg,
      rgba(255,255,255,0.06) 0%,
      rgba(0,0,0,0.20) 100%),
    rgba(18,18,20,0.85);
  border: 1px solid;
  border-color:
    rgba(255,255,255,0.20)
    rgba(255,255,255,0.08)
    rgba(0,0,0,0.35)
    rgba(255,255,255,0.08);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.14),
    inset 0 -1px 0 rgba(0,0,0,0.20),
    0 4px 10px rgba(0,0,0,0.30);
}
.ledger__card__x:hover,
.ledger__detail__x:hover {
  background:
    radial-gradient(ellipse 80% 60% at 50% 0%,
      rgba(255,255,255,0.22) 0%,
      transparent 70%),
    linear-gradient(180deg,
      rgba(255,255,255,0.12) 0%,
      rgba(0,0,0,0.15) 100%),
    rgba(26,26,28,0.92);
  border-top-color: rgba(255,255,255,0.40);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.22),
    inset 0 -1px 0 rgba(0,0,0,0.22),
    0 6px 16px rgba(0,0,0,0.45);
}

/* ── Form input — also gets glass-style focus, no backdrop-filter */
.door__field-input {
  background:
    linear-gradient(180deg,
      rgba(255,255,255,0.03) 0%,
      rgba(0,0,0,0.22) 100%),
    rgba(14,14,16,0.85);
  border-top-color: rgba(255,255,255,0.10);
}
.door__field-input:focus {
  background:
    radial-gradient(ellipse 80% 40% at 50% 0%,
      rgba(255,255,255,0.10) 0%,
      transparent 70%),
    linear-gradient(180deg,
      rgba(255,255,255,0.05) 0%,
      rgba(0,0,0,0.18) 100%),
    rgba(20,20,22,0.92);
  border-top-color: rgba(255,255,255,0.32);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.14),
    0 0 0 3px rgba(207,207,210,0.04),
    0 6px 18px rgba(0,0,0,0.30);
}

/* ═════════════════════════════════════════════════════════════
   ENHANCED HOVER EFFECTS — more pronounced micro-interactions
   ═════════════════════════════════════════════════════════════ */

/* CARDS — 3D tilt on hover (subtle perspective shift) */
.ledger__card {
  transform-origin: center center;
  transition:
    transform 0.45s cubic-bezier(.2,.8,.2,1),
    filter 0.45s cubic-bezier(.2,.8,.2,1),
    opacity 0.45s cubic-bezier(.2,.8,.2,1),
    border-color 0.4s var(--easing),
    box-shadow 0.4s var(--easing);
}
.ledger__card:hover {
  border-color: rgba(207,207,210,0.40);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.08),
    inset 0 -1px 0 rgba(0,0,0,0.30),
    0 24px 60px rgba(0,0,0,0.60),
    0 48px 96px rgba(0,0,0,0.45),
    0 0 60px rgba(207,207,210,0.08);
}

/* Stat number slight scale on card hover */
.ledger__card__stat-val {
  transition: color 0.4s var(--easing), transform 0.45s cubic-bezier(.2,.8,.2,1);
  transform-origin: left center;
}
.ledger__card:hover .ledger__card__stat-val {
  transform: scale(1.04);
}

/* Sparkline brighter on card hover */
.ledger__card .spark__line {
  transition: stroke 0.4s var(--easing), filter 0.4s var(--easing);
}
.ledger__card:hover .spark__line {
  stroke: #fafafa;
  filter: drop-shadow(0 0 12px rgba(207,207,210,0.40));
}

/* Handle gets a subtle letter-spacing on card hover */
.ledger__card__handle {
  transition: letter-spacing 0.45s cubic-bezier(.2,.8,.2,1),
              color 0.4s var(--easing);
}
.ledger__card:hover .ledger__card__handle {
  letter-spacing: 0.005em;
  color: #fafafa;
}

/* Examine pill: refined slide-in instead of fade */
.ledger__card__examine {
  transform: translate(8px, -2px);
  transition: opacity 0.30s cubic-bezier(.2,.8,.2,1),
              transform 0.30s cubic-bezier(.2,.8,.2,1);
}
.ledger__card:hover .ledger__card__examine {
  transform: translate(0, 0);
}

/* NAV LINKS: underline grows from CENTER instead of left */
.chrome__nav a::after {
  content: '';
  position: absolute;
  left: 50%; right: 50%;
  bottom: -6px;
  height: 1px;
  background: var(--fg);
  transition: left 0.35s cubic-bezier(.2,.8,.2,1),
              right 0.35s cubic-bezier(.2,.8,.2,1);
}
.chrome__nav a:hover::after {
  left: 0; right: 0;
}
/* Active state: full underline, ambient glow */
.chrome__nav a.is-active::after {
  left: 0; right: 0;
  box-shadow: 0 0 8px rgba(207,207,210,0.40);
}

/* DOSSIER nodes — subtle pulse on the active member's node */
.ledger__detail__graph .center-node text {
  transition: filter 0.3s var(--easing);
}

/* DISABLED — letter-spacing expansion on hover was widening the label and
   making the whole button appear to wobble. Static label per design pass. */
.door__submit-label {
  /* no transition, no hover state */
}

/* (Cleanup pass: removed `.cursor-dot/.cursor-ring` mix-blend-mode override
   for dossier mode — the cursor follower module is gone.) */

/* ═══════════════════════════════════════════════════════════════
   MOBILE RESPONSIVE — comprehensive pass for phones (≤768px)
   and small phones (≤480px). Goals:
     • Text + tap targets scale to fit narrow viewports
     • Heavy 3D scenes (Spline backdrop + V hero) disabled
       — phones can't render them well, kills battery
     • Ledger horizontal rail still works via touch swipe
     • Dossier opens full-screen on mobile
     • Apply form inputs fill the screen
   ═══════════════════════════════════════════════════════════════ */
@media (max-width: 768px) {

  /* ═══════════════════════════════════════════════════════════════
     MOBILE LOCKDOWN ARCHITECTURE
     ═══════════════════════════════════════════════════════════════
     Free-scroll has leaked through five different snap strategies on
     mobile (passive touch + post-end snap, non-passive touchmove with
     preventDefault, dynamic touchmove attach, CSS scroll-snap with
     mandatory + stop:always, etc.). Pedro's diagnosis is correct:
     anywhere the body CAN scroll, free-scroll WILL leak. The fix is
     to make body scroll structurally impossible.

       1. html, body are position: fixed + overflow: hidden +
          touch-action: none. There is no scroll position. window.scrollY
          is permanently 0. Native scroll cannot happen.
       2. .track (the wrapper containing all four beats) is position:
          fixed + height: 4 × 100dvh, and gets translated via
          transform: translateY(-N * 100dvh). The CSS transition IS the
          snap animation. JS only touches the index + the transform.
       3. Each beat is exactly 100dvh inside .track.
       4. Touch handlers in aletheia.js block all body-level touchmove
          via preventDefault, except for elements with [data-allow-touch]
          or known-scrollable containers (.ledger__rail-wrap,
          .ledger__detail, form inputs, textareas).

     This makes free-scroll architecturally impossible, not just
     "discouraged by heuristics". */
  html, body {
    overflow: hidden !important;
    max-width: 100vw;
    width: 100%;
    height: 100dvh !important;
    position: fixed;
    top: 0;
    left: 0;
    /* touch-action: none disables native page-scroll gestures from
       the OS. Allowed scrollers re-enable their own touch-action. */
    touch-action: none;
    /* (overscroll-behavior is now moot because there's no body scroll,
       but keep it as defensive belt-and-braces against any iOS edge
       case where overflow:hidden + fixed still allows rubber-band.) */
    overscroll-behavior: none;
  }

  /* .track is the transform-wrapper. It contains all four beats and is
     translated up/down by JS as the user advances. */
  .track {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: calc(4 * 100dvh);          /* 4 beats — monolith / manifesto / ledger / door */
    transform: translateY(0);          /* JS overrides this on snap */
    transition: transform 420ms cubic-bezier(0.65, 0, 0.35, 1);
    z-index: 20;
    /* No will-change: transform — it creates a new containing block for
       fixed descendants and we don't want to break the dossier overlay
       or any other position: fixed sibling. The transition is cheap
       enough without it on a phone. */
  }

  /* Each beat fills its slot in the wrapper exactly. */
  .beat--monolith,
  .beat--manifesto,
  .beat--ledger,
  .beat--door {
    height: 100dvh !important;
  }

  /* Inner containers — sticky has no runway when the beat is exactly
     100dvh, so behave like position: relative for clean layout. */
  .manifesto,
  .ledger {
    position: relative !important;
    height: 100dvh !important;
  }

  /* Allow horizontal pan on the ledger rail (its own scroller). */
  .ledger__rail-wrap {
    touch-action: pan-x;
  }

  /* CSS scroll-snap was tried and didn't work reliably on iOS Safari
     with sticky beats + body overflow-x: hidden. Mobile snap is now
     done in JS via touchstart/touchend listeners (see aletheia.js
     activate fn) which call next()/prev() — same path the wheel
     handler uses on desktop. */

  /* ── Spline scenes KEPT on mobile ──
     Earlier we hid both .stage__spline and .stage__v-hero on mobile
     for "perf" — but that gutted the hero and left a huge empty
     space on phones. The Spline V is the centerpiece of the brand;
     hiding it makes the mobile experience feel broken. Letting it
     render: modern phones handle it fine and the experience is
     consistent with desktop. */

  /* ── HERO CHROME — drop the desktop overlays that don't make sense
     on a phone-sized canvas (fake coords, cursor-based OBSERVE hint) */
  .stage__marks .mark--tl,
  .stage__marks .mark--tr,
  .stage__marks .mark--center-hint {
    display: none !important;
  }
  .stage__marks .mark--bl,
  .stage__marks .mark--br {
    font-size: 8px !important;
    letter-spacing: 0.16em !important;
    bottom: 18px !important;
    padding: 0 16px;
    max-width: 50vw;
  }
  .stage__marks .mark--bl { left: 0 !important; }
  .stage__marks .mark--br { right: 0 !important; text-align: right; }

  /* Spline degradation pass.
     Previous mobile pass only turned off pointer-events on the viewer.
     Per Pedro's testing: the WebGL pipeline alone is the dominant lag
     source — even when the viewer is non-interactive, it's still
     burning the GPU every frame. We now (a) skip loading the
     spline-viewer module on mobile entirely (see conditional loader in
     index.html, which sets .is-mobile-no-spline on <html>), and (b)
     display: none the elements at the breakpoint so the unknown-element
     fallbacks don't reserve layout space. The hero on Beat 3 falls back
     to the giant VERITAS wordmark, which was designed to read alone. */
  .stage__v-hero spline-viewer,
  .stage__spline spline-viewer {
    display: none !important;
  }

  /* ── Hero rebalance for the no-Spline mobile experience ──────
     Without the 3D V monogram, the wordmark + tagline IS the hero.
     The desktop rule anchors this block to bottom: 8vh because the
     Spline V occupies the center; on mobile we re-anchor it to the
     vertical center of the viewport and scale the wordmark up so it
     reads as the centerpiece instead of a footer label. */
  .hero-sidetext {
    padding: 0 6vw;
    top: 50%;
    bottom: auto;
    transform: translateY(-50%);
  }
  .hero-sidetext__wordmark {
    /* Hero-scale: 24vw at the center → ~94px on a 390px iPhone,
       ~103px on a 430px Pro Max. Clamped for landscape / tiny /
       extra-wide viewports. Flat fg color — no gradient, no clip-
       path, no animation. */
    font-size: clamp(72px, 24vw, 140px) !important;
    line-height: 0.92;
    letter-spacing: 0.06em;
    margin-bottom: 18px;
    color: var(--fg, #f3f3f1) !important;
  }
  .hero-sidetext__tagline {
    font-size: 10px !important;
    letter-spacing: 0.32em !important;
    line-height: 1.5;
    max-width: 88vw;
    margin: 0 auto;
  }
}

@media (max-width: 768px) {

  /* ── INTRO ────────────────────────────────────────────────── */

  /* Vertical balance on phones.
     The intro flex-centers the ASCII portrait, but the bottom of the
     viewport carries more visual weight than the top — the bottom-left
     and bottom-right corner labels PLUS the "PRESS ANYWHERE TO ENTER"
     pill all stack near the bottom edge, while the top only has two
     small corner labels. Pure geometric centering reads as too-high.
     We bias the centered pre down by giving the intro asymmetric
     vh-based padding: with `align-items: center`, the pre's center
     equals (height + paddingTop − paddingBottom) / 2, so paddingTop >
     paddingBottom shifts it down. Using clamp() so the offset scales
     with phone height without going extreme on very tall or very
     short viewports. (See feedback: never absolute-position content
     with hardcoded px — use viewport-relative layout safeguards.) */
  .intro {
    padding-top: clamp(40px, 14vh, 160px);
    padding-bottom: clamp(48px, 8vh, 100px);
    /* Box-sizing already inherits border-box from the base reset, so
       padding stays inside the fixed 100dvh intro container. */
  }

  .intro__chrome {
    font-size: 9px;
    letter-spacing: 0.20em;
    gap: 6px;
  }
  /* iOS safe-area handling — the page is rendered with viewport-fit=cover
     (see index.html viewport meta), so 100dvh includes the Dynamic Island
     band at the top and the home-indicator band at the bottom. Without
     env(safe-area-inset-*) padding, the corner chrome jams underneath
     those bands and gets visually clipped. We add the inset to the base
     14px gap so non-notched phones see ~14px (inset is 0) and notched
     phones see ~14px + ~50px clearance. */
  .intro__chrome--tl, .intro__chrome--tr,
  .intro__chrome--bl, .intro__chrome--br {
    top: calc(14px + env(safe-area-inset-top, 0px));
    left: calc(14px + env(safe-area-inset-left, 0px));
    right: auto; bottom: auto;
  }
  .intro__chrome--tr {
    top: calc(14px + env(safe-area-inset-top, 0px));
    right: calc(14px + env(safe-area-inset-right, 0px));
    left: auto;
  }
  .intro__chrome--bl {
    bottom: calc(14px + env(safe-area-inset-bottom, 0px));
    left: calc(14px + env(safe-area-inset-left, 0px));
    top: auto;
  }
  .intro__chrome--br {
    bottom: calc(14px + env(safe-area-inset-bottom, 0px));
    right: calc(14px + env(safe-area-inset-right, 0px));
    left: auto; top: auto;
  }

  /* Hint pill — full-width-ish so it's tap-friendly. Bottom uses
     env(safe-area-inset-bottom) so the button clears the iOS Safari
     bottom toolbar / home indicator. Without this, on iPhone the
     URL bar covers the button. Also raise z-index above the ASCII. */
  .intro__hint {
    bottom: calc(48px + env(safe-area-inset-bottom, 0px));
    padding: 14px 22px;
    font-size: 10px;
    letter-spacing: 0.30em;
    z-index: 5;                        /* sit above the .intro__ascii pre */

    /* Keep "PRESS ANYWHERE TO ENTER" on a single line. The pill is
       `position: absolute; left: 50%; transform: translateX(-50%)`, which
       means the shrink-to-fit algorithm sees only 50vw of available width
       (the space to the right of left:50%). On a 390px phone that's
       ~195px — less than the pill's natural single-line width (~222px) —
       so the layout engine wraps the text to fit. `nowrap` opts the
       element out of that wrap and lets it grow to its content width;
       `max-width` then caps it so the centered pill always keeps a
       16px horizontal breathing margin from the viewport edges. */
    white-space: nowrap;
    max-width: calc(100vw - 32px);
    /* Mobile keeps the ORIGINAL near-transparent glass look (the 50%-black
       fill is desktop-only, per Pedro). */
    background:
      radial-gradient(ellipse 80% 60% at 50% 100%,
        rgba(255,255,255,0.12) 0%,
        transparent 70%),
      rgba(255,255,255,0.02);
  }

  /* Scroll cue not needed on mobile — swiping/scrolling is the obvious
     gesture on touch, and the hero is short. */
  .scroll-cue { display: none; }

  /* ── TOP CHROME BAR ───────────────────────────────────────── */
  .chrome {
    /* iOS safe-area on the fixed top bar so VERITAS/clock chrome clears
       the Dynamic Island. Inset values are 0 on non-notched devices. */
    padding:
      calc(12px + env(safe-area-inset-top, 0px))
      calc(16px + env(safe-area-inset-right, 0px))
      12px
      calc(16px + env(safe-area-inset-left, 0px));
    grid-template-columns: 1fr auto;       /* drop nav onto a second row */
    gap: 8px;
  }
  .chrome__left, .chrome__right { font-size: 9px; }
  .chrome__nav { display: none; }          /* primary nav hidden — tap anywhere to scroll */

  /* ── MANIFESTO ────────────────────────────────────────────── */
  .manifesto {
    padding: 14vh 6vw 6vh 6vw;
    gap: 16px;
  }
  .manifesto__lede {
    font-size: clamp(40px, 14vw, 72px);
    white-space: normal;            /* allow wrap on tiny screens */
    line-height: 1.0;
  }
  .manifesto__body {
    font-size: clamp(15px, 4.2vw, 18px);
    max-width: 92vw;
    line-height: 1.5;
  }
  .manifesto__meta {
    gap: 18px;
    font-size: 9px;
    letter-spacing: 0.20em;
  }

  /* ── LEDGER ───────────────────────────────────────────────── */
  .ledger {
    padding: 14vh 0 4vh;
  }
  .ledger__head {
    padding: 0 6vw;
    gap: 10px;
  }
  .ledger__subtitle { font-size: clamp(18px, 5vw, 24px); }
  .ledger__hint    { font-size: 9px; letter-spacing: 0.20em; }

  /* Horizontal rail UX on phones.
     1. touch-action: pan-x — explicitly hand horizontal drags to this
        scroll container. Without it iOS treats a slightly-diagonal swipe
        as ambiguous between the page-snap vertical gesture and the
        rail's horizontal scroll, and often resolves it to vertical.
        With pan-x, horizontal swipes that start in the rail commit to
        the rail immediately.
     2. scroll-snap-type: x mandatory + scroll-snap-align: center on the
        card — each swipe lands cleanly on the next card so users can
        tell there's more by the snap feel + the next card sliding into
        place.
     3. scroll-padding-left so when a card snaps to center it accounts
        for the rail's left padding. */
  .ledger__rail-wrap {
    touch-action: pan-x;
    scroll-snap-type: x mandatory;
    scroll-padding-left: 6vw;
  }
  .ledger__card { scroll-snap-align: center; scroll-snap-stop: always; }

  /* Card nav arrows on mobile — pinned hard to the edges (cards are 78vw
     so the side margins are tight), slightly smaller, and lifted above
     the cards so a tap always hits the arrow. They co-exist with swipe. */
  .ledger__nav {
    width: 38px; height: 38px;
    background: rgba(10,10,12,0.70);
    z-index: 35;
  }
  .ledger__nav--prev { left: 6px; }
  .ledger__nav--next { right: 6px; }
  .ledger__nav::before { width: 8px; height: 8px; }

  /* Cards — narrower so 1-1.5 fit in viewport, AND override the desktop
     grid so the portrait gets a FIXED row height instead of 1fr (which
     was stretching it to fill the whole card on mobile). */
  .ledger__card {
    width: 78vw !important;
    min-width: 78vw !important;
    max-width: 78vw !important;
    height: auto !important;       /* was 88% — collapsing to content */
    max-height: none !important;
    grid-template-rows:
      auto                /* meta-top */
      220px               /* portrait — FIXED height, no longer 1fr */
      auto                /* id */
      auto                /* social */
      auto                /* meta-bot */ !important;
    padding: 18px 18px 16px !important;
    gap: 10px !important;
  }
  .ledger__card__portrait {
    height: 100% !important;
    min-height: 0 !important;
    max-height: 220px !important;
  }
  .ledger__card__handle { font-size: clamp(18px, 5vw, 22px); }
  .ledger__card__craft  { font-size: 9px; letter-spacing: 0.20em; }
  .ledger__card__stat-val { font-size: clamp(22px, 7vw, 32px); }
  /* Card X pill — bump to 44px tap target so users don't accidentally
     trigger card-click instead of opening the X profile. */
  .ledger__card__x--top {
    padding: 10px 14px;
    min-height: 38px;
    font-size: 10px;
  }

  /* Disable depth-of-field on mobile — saves CPU, all cards readable */
  .ledger__card {
    --dof-scale: 1 !important;
    --dof-opacity: 1 !important;
    --dof-y: 0 !important;
  }

  /* ── DOSSIER (member detail overlay) — MOBILE REDESIGN ──────
     The desktop dossier is built around a centered SVG (V monolith
     with orbital nodes + corner labels). That layout uses absolute
     positioning that catastrophically breaks on phone viewports —
     handle pill, disciplines list, stats, and the orbital graph all
     overlap each other in a tiny ~360px width.

     Mobile fix: KILL the orbital graph entirely + STACK the textual
     blocks vertically with natural document flow. The graph is a
     desktop nice-to-have; on mobile, the dossier becomes a clean
     scrollable info card. */
  .ledger__detail {
    /* iOS safe-area pass — the modal is `position: fixed; height: 100dvh`
       so it spans the entire visual viewport including the Dynamic Island
       band and the home indicator band. The earlier 14vh / 6vh paddings
       cleared the bands on non-notched devices but on a 393×852 iPhone
       14 Pro the handle row started ~50px above the safe-area-inset-top,
       cutting "SMILEYDARTH" in half. Adding the env() to the existing
       vh values gives non-notched phones the same 14vh / 6vh and
       notched phones an extra ~50px / ~34px below the system chrome. */
    padding:
      calc(14vh + env(safe-area-inset-top, 0px))
      calc(16px + env(safe-area-inset-right, 0px))
      calc(6vh  + env(safe-area-inset-bottom, 0px))
      calc(16px + env(safe-area-inset-left, 0px))
      !important;
    overflow-y: auto !important;
    overflow-x: hidden !important;
    -webkit-overflow-scrolling: touch;
  }
  .ledger__detail__close {
    /* Close pill sits in the top-right; needs the same inset so it
       isn't tucked behind the Dynamic Island. */
    top: calc(12px + env(safe-area-inset-top, 0px));
    right: calc(12px + env(safe-area-inset-right, 0px));
    padding: 8px 14px;
    font-size: 10px;
    z-index: 100;
  }

  /* (.md__bar mobile override removed — the bar is now position: fixed
     directly in the base rule, so it pins to the viewport without
     needing negative margins to escape the dossier's L/R padding.) */
  /* Hide the orbital-node SVG entirely — V + nodes + corner labels.
     Their geometry needs ≥800px width to fit; below that they collide. */
  .ledger__detail__graph {
    display: none !important;
  }
  /* Hide the AUTHORIZED line + the small dossier eye/topchrome chip
     since they sit on top of the (now gone) graph. */
  .ledger__detail__topchrome {
    display: none !important;
  }
  /* Stack every dossier block vertically using natural flow. Reset
     all the desktop absolute positioning. */
  .ledger__detail__handle,
  .ledger__detail__crafts,
  .ledger__detail__quote,
  .ledger__detail__seal,
  .ledger__detail__timeline,
  .ledger__detail__declaration {
    position: relative !important;
    top: auto !important;
    left: auto !important;
    right: auto !important;
    bottom: auto !important;
    width: 100% !important;
    max-width: 100% !important;
    transform: none !important;
    margin: 0 0 28px 0 !important;
    padding: 0 !important;
    text-align: left !important;
  }
  .ledger__detail__handle {
    margin-top: 0 !important;
  }
  .ledger__detail__handle-name {
    font-size: clamp(34px, 9vw, 52px) !important;
    line-height: 1.0;
  }
  .ledger__detail__handle-quote {
    font-size: clamp(15px, 4.4vw, 18px) !important;
    margin-top: 12px;
  }
  .ledger__detail__handle-craft {
    font-size: 10px !important;
    letter-spacing: 0.20em !important;
    margin-top: 8px;
  }
  /* Disciplines list: smaller font, tighter spacing on mobile */
  .ledger__detail__crafts ul,
  .ledger__detail__crafts {
    font-size: clamp(20px, 6vw, 28px) !important;
    line-height: 1.3;
  }
  .ledger__detail__crafts-eye {
    font-size: 10px !important;
    letter-spacing: 0.20em !important;
    margin-bottom: 10px;
  }
  /* X handle pill + stats: stack as a single block */
  .ledger__detail__social {
    position: relative !important;
    margin: 8px 0 20px !important;
    flex-direction: column !important;
    align-items: flex-start !important;
    gap: 12px !important;
  }
  .ledger__detail__social-handle,
  .ledger__detail__social-stat {
    font-size: 11px !important;
  }
  /* Quote block in normal flow */
  .ledger__detail__quote {
    font-size: clamp(16px, 4.6vw, 20px) !important;
    line-height: 1.4;
    font-style: italic;
  }
  /* Timeline: compress the events grid so it fits 1-col on mobile */
  .ledger__detail__timeline__events {
    display: grid !important;
    grid-template-columns: 1fr 1fr !important;
    gap: 10px !important;
  }
  .ledger__detail__timeline__bar {
    margin: 8px 0 !important;
  }
  .ledger__detail__timeline__ev .yr {
    font-size: 11px !important;
  }
  .ledger__detail__timeline__ev .what {
    font-size: 11px !important;
    line-height: 1.3;
  }
  .ledger__detail__timeline__attr {
    font-size: 10px !important;
    letter-spacing: 0.18em !important;
  }
  .ledger__detail__timeline__hint,
  .ledger__detail__timeline__axis {
    display: none !important;     /* desktop-only nav cues */
  }
  /* Seal: small inline signature at the bottom */
  .ledger__detail__seal {
    margin-top: 12px !important;
    display: flex !important;
    align-items: center;
    gap: 12px;
  }
  .ledger__detail__seal .seal-mark {
    font-size: 32px !important;
  }
  .ledger__detail__seal .seal-meta {
    font-size: 10px !important;
    letter-spacing: 0.16em !important;
  }
  /* Veil — must be FULLY opaque on mobile so the card behind doesn't
     bleed through the stacked dossier content. Was 35% which let the
     pfp + handle + stats from the underlying card show through and made
     everything look broken. */
  .ledger__detail {
    background: #060608 !important;     /* solid backdrop */
  }
  .ledger__detail__veil {
    opacity: 1 !important;
    background: #060608 !important;
  }

  /* ── APPLY FORM (door) ────────────────────────────────────── */
  .door {
    /* Top padding bumped to clear the fixed chrome bar (~50px) so the
       seats counter doesn't sit underneath it on iPhone SE / Pro. */
    padding: clamp(80px, 12vh, 110px) 5vw 10vh;
    gap: 8px;
    /* overflow-y was `auto` to give a fallback scroll surface when the
       iOS keyboard shrunk the visible viewport. The side effect: .door
       became an independent scroll container nested inside beat-door,
       so users could free-scroll the form past the bottom of beat-door
       and feel they'd left the snap rail (Pedro's report). Switching
       back to visible defers keyboard-induced scrolling to the body
       (which iOS Safari handles natively by scrolling the focused
       input into view) and the snap rhythm stays intact. */
    overflow: visible;
  }
  .door__form {
    /* Tighter form gap on mobile — desktop's 22px gap with all the form
       chrome was overflowing the viewport on iPhone SE. */
    gap: 14px !important;
    margin-top: 14px;
  }
  .door__lede {
    font-size: clamp(28px, 8vw, 44px);
    line-height: 1.1;
  }
  .door__sub {
    font-size: clamp(13px, 3.8vw, 16px);
    max-width: 90vw;
  }
  /* Mobile recap — visible only on mobile, gives Veritas context next
     to the form so users don't have to scroll back up. */
  .door__recap {
    display: block !important;
    font-size: 13px;
    line-height: 1.55;
    color: var(--dim, #888);
    max-width: 90vw;
    margin: 4px auto 8px;
    text-align: center;
    font-style: italic;
    opacity: 0.85;
  }
  .door__row {
    width: 100%;
  }
  .door__field-input {
    font-size: 16px;     /* prevent iOS zoom on focus */
    padding: 12px 14px;
  }
  .door__action {
    flex-direction: column;
    gap: 14px;
    align-items: stretch;
  }
  .door__submit {
    width: 100%;
    padding: 16px 20px;
    justify-content: center;
  }
  .door__mark {
    font-size: 9px;
    padding: 6px 12px;
    /* Not interactive — kill pointer-events so users don't tap the
       pulsing seats counter expecting it to do something. */
    pointer-events: none;
  }

  /* ── PROGRESS bar a touch thinner on mobile ───────────────── */
  .progress { height: 1px; }
}

/* ════════════════════════════════════════════════════════════════
   MOBILE DOSSIER — dedicated template (.md__*)
   Built by openDetailMobile in JS. Completely separate from the
   desktop .ledger__detail__* styles. No animations, no overlays,
   no absolute positioning — just a clean scrollable card.
   ════════════════════════════════════════════════════════════════ */
.ledger__detail.is-mobile-dossier {
  /* Cancel ALL desktop dossier styles when in mobile mode. The inline
     style on the element from JS already pins position + opacity. */
  background: #060608 !important;
}
.ledger__detail.is-mobile-dossier .ledger__detail__veil,
.ledger__detail.is-mobile-dossier .ledger__detail__scanlines,
.ledger__detail.is-mobile-dossier .ledger__detail__topchrome,
.ledger__detail.is-mobile-dossier .ledger__detail__graph,
.ledger__detail.is-mobile-dossier .ledger__detail__handle,
.ledger__detail.is-mobile-dossier .ledger__detail__crafts,
.ledger__detail.is-mobile-dossier .ledger__detail__quote,
.ledger__detail.is-mobile-dossier .ledger__detail__seal,
.ledger__detail.is-mobile-dossier .ledger__detail__timeline,
.ledger__detail.is-mobile-dossier .ledger__detail__declaration {
  display: none !important;     /* nothing from desktop dossier renders here */
}

/* Mobile dossier — editorial profile card. References:
   NYT magazine bio cards, Apple People app, Times Style profile pages.
   Compact avatar (88px) inline with identity, then info stacked below
   with hairline dividers between sections — feels like reading a
   magazine spread, not browsing a CRM. */
.md {
  display: flex;
  flex-direction: column;
  padding: 0 0 32px;
  color: var(--fg, #f3f3f1);
  font-family: var(--mono);
}

/* ── Fixed top bar — DOSSIER label + CLOSE pill ───────────────
   IMPORTANT: this rule only ever renders in the mobile dossier
   (.md structure is only injected by openDetailMobile in aletheia.js),
   so we can treat it as mobile-specific.

   Previously this was position: sticky; top: 0. That broke in practice
   on Pedro's iPhone — the bar scrolled with content instead of pinning.
   The sticky anchor is the nearest scroll container, but the dossier
   open-path sets a stack of inline + CSS properties on .ledger__detail
   (position:fixed, height:100svh, overflow-y:auto !important) that
   evidently doesn't establish a sticky-compatible scrollport on iOS
   here. Rather than keep fighting sticky semantics, the bar is now
   anchored directly to the viewport via position: fixed — the same
   way the original .ledger__detail__close did successfully — so the
   bar is GUARANTEED to stay glued to the top regardless of how the
   dossier's scrolling is wired underneath. */
.md__bar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 100;                       /* above all dossier content (was 10) */
  display: flex; align-items: center; justify-content: space-between;
  /* Padding incorporates iOS safe-area insets so:
       - top: clears the Dynamic Island / status bar band
       - left/right: clears the rounded-corner / camera notch zones */
  padding:
    calc(14px + env(safe-area-inset-top,   0px))
    calc(18px + env(safe-area-inset-right, 0px))
    14px
    calc(18px + env(safe-area-inset-left,  0px));
  margin: 0;                          /* reset any inherited negative margins */
  background: var(--bg, #0e0e10);     /* fully opaque — no content ghosts */
  border-bottom: 1px solid rgba(255,255,255,0.07);
}
.md__bar-label {
  font-size: 9px; letter-spacing: 0.32em;
  color: rgba(255,255,255,0.55);
}
.md__close {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 14px 18px;            /* bumped — Apple HIG: 44pt min touch target */
  min-height: 44px;
  background: rgba(255,255,255,0.05);
  border: 1px solid rgba(255,255,255,0.18);
  border-radius: 999px;
  color: #fff;
  font-size: 11px; letter-spacing: 0.22em;
  cursor: pointer;
  -webkit-tap-highlight-color: rgba(0,0,0,0);
}
.md__close-x {
  font-size: 14px; line-height: 1; opacity: 0.8;
}

/* ── HERO: avatar + identity inline ───────────────────
   88px square avatar (NOT full-width). Identity column has
   eyebrow, italic serif name, and X handle stacked vertically. */
.md__hero {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  padding: 28px 20px 22px;
}
.md__avatar {
  flex: 0 0 auto;
  width: 88px; height: 88px;
  border: 1px solid rgba(255,255,255,0.14);
  background: #0a0a0c;
  overflow: hidden;
  border-radius: 2px;     /* sharp corners — editorial, not social */
}
.md__avatar img {
  display: block;
  width: 100%; height: 100%;
  object-fit: cover;
  filter: grayscale(0.1) contrast(1.05);
}
.md__hero-id {
  flex: 1 1 auto;
  min-width: 0;           /* lets long names truncate cleanly */
  display: flex; flex-direction: column; gap: 8px;
  padding-top: 2px;
}
.md__eyebrow {
  font-size: 9px; letter-spacing: 0.40em;
  margin: 0;
  color: rgba(255,255,255,0.55);
}
.md__name {
  margin: 0;
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(26px, 7vw, 36px);
  line-height: 1.0;
  letter-spacing: -0.015em;
  color: #fff;
  word-break: break-word;
}
.md__x {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 12px 16px;            /* bumped — Apple HIG 44pt min */
  min-height: 44px;
  background: rgba(255,255,255,0.04);
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: 999px;
  color: rgba(255,255,255,0.92);
  font-family: var(--mono);
  font-size: 11px; letter-spacing: 0.04em;
  text-decoration: none;
  align-self: flex-start;
  -webkit-tap-highlight-color: rgba(0,0,0,0);
}

/* ── Bio quote — magazine pull-quote feel ── */
.md__bio-wrap {
  padding: 0 20px 22px;
}
.md__bio {
  margin: 0;
  font-family: var(--serif); font-style: italic;
  font-size: 17px; line-height: 1.5;
  color: rgba(255,255,255,0.82);
  position: relative;
  padding-left: 14px;
  border-left: 1px solid rgba(255,255,255,0.18);   /* editorial side-rule */
}

/* ── Stats — compact 3-up with vertical hairline dividers ── */
.md__stats {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  padding: 16px 20px;
  border-top: 1px solid rgba(255,255,255,0.07);
  border-bottom: 1px solid rgba(255,255,255,0.07);
}
.md__stat {
  display: flex; flex-direction: column; gap: 4px;
  padding: 0 10px;
  border-left: 1px solid rgba(255,255,255,0.06);
}
.md__stat:first-child {
  padding-left: 0;
  border-left: 0;
}
.md__stat-label {
  font-size: 8px; letter-spacing: 0.22em;
  color: rgba(255,255,255,0.45);
}
.md__stat-val {
  font-family: var(--serif); font-style: italic;
  font-size: clamp(17px, 5vw, 21px);
  color: #fff;
  line-height: 1.0;
}

/* ── Sections (Disciplines, Milestones) ── */
.md__section {
  padding: 24px 20px 0;
  display: flex; flex-direction: column; gap: 14px;
}
.md__section-title {
  font-size: 9px; letter-spacing: 0.38em;
  margin: 0;
  padding-bottom: 10px;
  border-bottom: 1px solid rgba(255,255,255,0.10);
  color: rgba(255,255,255,0.55);
}

/* Disciplines as inline chips — small caps, hairline border */
.md__chips {
  display: flex; flex-wrap: wrap; gap: 8px;
}
.md__chip {
  display: inline-block;
  padding: 7px 14px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 2px;
  font-family: var(--serif);
  font-style: italic;
  font-size: 15px;
  color: #fff;
  background: rgba(255,255,255,0.02);
}

/* ── Timeline — clean vertical list, no markers, year-aligned ── */
.md__timeline {
  list-style: none;
  margin: 0; padding: 0;
  display: flex; flex-direction: column;
}
.md__tl-item {
  display: grid;
  grid-template-columns: 56px 1fr;
  gap: 14px;
  padding: 14px 0;
  border-bottom: 1px solid rgba(255,255,255,0.05);
}
.md__tl-item:last-child {
  border-bottom: 0;
}
.md__tl-year {
  font-size: 11px; letter-spacing: 0.10em;
  color: rgba(255,255,255,0.55);
  padding-top: 3px;
}
/* Undated event in mobile dossier — show the em-dash placeholder dimmer */
.md__tl-item--undated .md__tl-year {
  opacity: 0.4;
  letter-spacing: 0;
}
.md__tl-what {
  font-family: var(--serif);
  font-size: 16px; line-height: 1.45;
  color: #fff;
}

/* ── Footer stamp ── */
.md__foot {
  display: flex; align-items: center; justify-content: space-between;
  padding: 28px 20px 8px;
  margin-top: 24px;
  font-size: 9px; letter-spacing: 0.24em;
  border-top: 1px solid rgba(255,255,255,0.07);
}
.md__foot-stamp {
  font-family: var(--serif);
  font-size: 22px;
  font-style: italic;
  color: rgba(255,255,255,0.7);
  line-height: 1;
}

/* ── Even narrower (≤480px) — small phones ────────────────── */
@media (max-width: 480px) {
  .intro__chrome { font-size: 8px; letter-spacing: 0.16em; }
  /* letter-spacing also stepped down here (was inheriting 0.30em from the
     ≤768 rule). The pill stays on one line via white-space:nowrap, but
     the wider tracking would push the text past max-width: calc(100vw -
     32px) on the narrowest phones (~320px). 0.18em keeps the pill at
     ~200px on 360px+ phones, well inside the 16px-each-side margin. */
  .intro__hint   {
    font-size: 9px;
    letter-spacing: 0.18em;
    padding: 12px 18px;
    bottom: calc(36px + env(safe-area-inset-bottom, 0px));
  }

  .manifesto__lede { font-size: clamp(34px, 13vw, 56px); }

  /* Card width on the narrowest phones. The original 84vw at this
     breakpoint was wider than the ≤768 baseline (78vw), leaving only
     ~10vw of next-card peek visible — users perceived "one card" and
     didn't realize the rail was horizontally scrollable. Down to 76vw
     leaves ~14-17vw of the next card visibly peeking past the right
     edge, so the rail reads as a swipable strip at a glance. */
  .ledger__card {
    width: 76vw !important;
    min-width: 76vw !important;
    max-width: 76vw !important;
  }
  /* Tighter gap on small phones reclaims a few vw for the peek too. */
  .ledger__rail { gap: 16px; }

  .door__lede { font-size: clamp(24px, 8vw, 36px); }
}

/* Touch devices — kill hover-only treatments that get stuck on tap,
   AND show portraits in their final color/contrast state by default
   (without this, mobile users see only the grayscale "pre-hover" form
   forever, which then becomes a jarring color jump in the dossier). */
@media (hover: none) {
  .ledger__card:hover { transform: none; }
  .door__submit:hover { transform: none; }
  .ledger__card__portrait img {
    filter: grayscale(0%) contrast(1.05) brightness(1) !important;
  }
  .ledger__card__vignette { opacity: 0 !important; }
  /* EXAMINE pill — touch devices have no hover, so the fade-in on hover
     never fires. Make it always visible AND align it visually with the
     X handle pill on the left. The X pill has padding 10px 14px +
     min-height 38px (set in mobile block); match it here so they read
     as a pair on the top row of the card. Top offset 22px = card padding
     so they sit at the exact same y-baseline. */
  .ledger__card__examine {
    opacity: 1 !important;
    transform: none !important;
    pointer-events: none;          /* card itself is the click target */
    top: 22px !important;
    right: 22px !important;
    padding: 10px 14px !important;
    min-height: 38px;
    font-size: 10px;
    letter-spacing: 0.20em;
    box-sizing: border-box;
  }
}

/* ═══════════════════════════════════════════════════════════════
   FINAL OVERRIDE — REQUEST ACCESS button.
   Rules:
     • NO movement (no transform, no letter-spacing widen, no arrow slide)
     • Hover: subtle brighten only (color shift, not size/position)
     • Disabled: clearly dimmed so the user sees when it becomes clickable
     • Pointer events MUST work — the button still needs to be clickable
   ═══════════════════════════════════════════════════════════════ */

/* Base + enabled rest state — bright glass surface */
.door__submit:not(:disabled) {
  transform: none !important;
  transition: background 0.25s ease, border-color 0.25s ease, box-shadow 0.25s ease !important;
  background:
    linear-gradient(180deg,
      rgba(255,255,255,0.32) 0%,
      rgba(255,255,255,0.12) 18%,
      rgba(255,255,255,0.04) 38%,
      rgba(0,0,0,0.10) 50%,
      rgba(0,0,0,0.30) 100%),
    radial-gradient(ellipse 60% 50% at 50% 0%,
      rgba(255,255,255,0.40) 0%,
      transparent 70%),
    rgba(28,28,30,0.92) !important;
  border-color: rgba(255,255,255,0.18) !important;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.45),
    inset 0 0 0 1px rgba(255,255,255,0.04),
    inset 0 -2px 4px rgba(0,0,0,0.35),
    0 8px 24px rgba(0,0,0,0.55),
    0 2px 4px rgba(0,0,0,0.40) !important;
  cursor: pointer !important;
  pointer-events: auto !important;
  opacity: 1 !important;
}

/* Hover: brighter rim + slightly lighter base. NO transform. */
.door__submit:not(:disabled):hover,
.door__submit:not(:disabled):focus {
  transform: none !important;
  background:
    linear-gradient(180deg,
      rgba(255,255,255,0.40) 0%,
      rgba(255,255,255,0.18) 18%,
      rgba(255,255,255,0.06) 38%,
      rgba(0,0,0,0.06) 50%,
      rgba(0,0,0,0.25) 100%),
    radial-gradient(ellipse 60% 50% at 50% 0%,
      rgba(255,255,255,0.55) 0%,
      transparent 70%),
    rgba(34,34,38,0.95) !important;
  border-color: rgba(255,255,255,0.32) !important;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.65),
    inset 0 0 0 1px rgba(255,255,255,0.08),
    inset 0 -2px 4px rgba(0,0,0,0.35),
    0 8px 24px rgba(0,0,0,0.55),
    0 2px 4px rgba(0,0,0,0.40) !important;
}

/* Active (mouse down) — no movement, just a beat darker */
.door__submit:not(:disabled):active {
  transform: none !important;
  background:
    linear-gradient(180deg,
      rgba(255,255,255,0.20) 0%,
      rgba(255,255,255,0.06) 18%,
      rgba(0,0,0,0.10) 50%,
      rgba(0,0,0,0.35) 100%),
    rgba(20,20,22,0.92) !important;
}

/* DISABLED — flat, dim, clearly non-interactive */
.door__submit:disabled,
.door__submit[disabled] {
  background: rgba(8,8,10,0.55) !important;
  border-color: rgba(207,207,210,0.10) !important;
  box-shadow: none !important;
  opacity: 0.35 !important;
  cursor: default !important;
  transform: none !important;
}

/* Kill all the moving pseudo-elements */
.door__submit::before {
  content: none !important;
  display: none !important;
}
.door__submit-label {
  letter-spacing: 0.34em !important;
  transition: none !important;
}
.door__submit:hover .door__submit-label {
  letter-spacing: 0.34em !important;
}
.door__submit-arrow {
  transition: none !important;
  transform: none !important;
}
.door__submit:hover .door__submit-arrow {
  transform: none !important;
}
