/* ============================================================
   Cam Carroll Studio — Design System
   Achromatic. Editorial. Hand-tuned.
   ============================================================ */

/* ─────────────────────────────────────────────────────────────
   1. Tokens
   ───────────────────────────────────────────────────────────── */
:root {
  /* Palette — ink/paper only. No accent color. Sierra's gold is reserved
     for moments where Sierra is shown, never for studio chrome. */
  --ink:        #0A0A0C;
  --ink-2:      #101013;
  --ink-3:      #15151A;
  --ink-4:      #1C1C22;

  --paper:      #F1ECE3;
  --paper-2:    #E6E0D3;
  --paper-3:    #C9C3B8;
  --ash:        #8A8479;
  --ash-2:      #6B665C;

  /* Hairlines — paper at low alpha. Keep these dim. */
  --rule:       rgba(241, 236, 227, 0.06);
  --rule-2:     rgba(241, 236, 227, 0.12);
  --rule-3:     rgba(241, 236, 227, 0.22);

  /* Reserved-color zone (Sierra only) */
  --sierra-gold:  #CBB26A;

  /* Easing — the three house curves */
  --ease-house:  cubic-bezier(0.16, 1, 0.3, 1);
  --ease-cinema: cubic-bezier(0.65, 0.05, 0.36, 1);
  --ease-micro:  cubic-bezier(0.32, 0.72, 0, 1);

  /* Durations */
  --dur-tap:    160ms;
  --dur-fast:   220ms;
  --dur-base:   480ms;
  --dur-slow:   880ms;
  --dur-cinema: 1400ms;

  /* Tracking */
  --track-display: -0.018em;
  --track-wordmark: 0.02em;
  --track-body:    -0.005em;
  --track-eyebrow: 0.22em;

  /* Spacing rhythm (fluid) */
  --space-1:  clamp(0.5rem,  0.5vw,  0.75rem);
  --space-2:  clamp(0.75rem, 0.75vw, 1rem);
  --space-3:  clamp(1rem,    1.2vw,  1.5rem);
  --space-4:  clamp(1.5rem,  1.8vw,  2.25rem);
  --space-5:  clamp(2rem,    3vw,    3.5rem);
  --space-6:  clamp(3rem,    5vw,    6rem);
  --space-7:  clamp(4.5rem,  8vw,    9rem);
  --space-8:  clamp(6rem,    12vw,   14rem);

  --gutter:   clamp(1.25rem, 4vw, 3rem);

  /* Scroll-tied parallax — set by JS on the headline */
  --scroll-y: 0px;
}

/* ─────────────────────────────────────────────────────────────
   2. Base reset & document
   ───────────────────────────────────────────────────────────── */
* {
  -webkit-tap-highlight-color: transparent;
}

html {
  background: var(--ink);
  color: var(--paper);
  scroll-behavior: smooth;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  font-feature-settings: "kern" 1, "liga" 0;
}

body {
  background: var(--ink);
  color: var(--paper);
  font-family: 'Inter', system-ui, -apple-system, sans-serif;
  font-size: 16px;
  line-height: 1.55;
  letter-spacing: var(--track-body);
  font-weight: 400;
  margin: 0;
  /* Critical: must be `clip` not `hidden`. `overflow-x: hidden` would
     implicitly make overflow-y: auto, turning body into a scroll container
     and breaking position: sticky throughout the page (sticky elements
     would stick to body, not the viewport, but body never scrolls).
     `clip` clips horizontally without creating a scroll container.
     The `hidden` rule is a fallback for browsers without `clip` support. */
  overflow-x: hidden;
  overflow-x: clip;
  min-height: 100svh;
  position: relative;
  /* Hide native cursor when the custom cursor is active (desktop only). */
}
body.has-custom-cursor,
body.has-custom-cursor * {
  cursor: none;
}

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

:focus { outline: none; }
:focus-visible {
  outline: 1px solid var(--paper);
  outline-offset: 4px;
  border-radius: 2px;
}

/* ─────────────────────────────────────────────────────────────
   3. ATMOSPHERE LAYER
   The single biggest leap from "big text on black" to "cinematic canvas."
   Order of stacking, from back to front:
     body bg → vignette (::before) → editorial grid → page content → grain (::after)
   ───────────────────────────────────────────────────────────── */

/* Vignette — a soft radial darkening at the corners. Apple's iPhone pages
   use a similar treatment to give flat dark canvases dimension. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 1;
  background:
    radial-gradient(ellipse 120% 80% at 50% 50%,
      transparent 0%,
      transparent 55%,
      rgba(0, 0, 0, 0.35) 100%);
}

/* Film grain — fixed SVG turbulence noise.
   The data URL is a single SVG with feTurbulence + feColorMatrix that
   produces neutral monochrome grain. Tiled at 220px so it never looks
   like a pattern, only like film. Opacity is the dial — keep it low. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 200;
  opacity: 0.07;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='220' height='220'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch' seed='3'/><feColorMatrix values='0 0 0 0 1   0 0 0 0 1   0 0 0 0 1   0 0 0 0.6 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
  background-size: 220px 220px;
}
@media (prefers-reduced-motion: reduce) {
  body::after { opacity: 0.04; }
}

/* Editorial hairline grid — two faint vertical rules at 25% / 75%.
   Architectural scaffolding the visitor never consciously names but always
   feels. Hidden under 720px (mobile sees only the type). */
.grid-overlay {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 2;
  display: none;
}
.grid-overlay::before,
.grid-overlay::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  width: 1px;
  background: var(--rule);
}
.grid-overlay::before { left: 25%; }
.grid-overlay::after  { left: 75%; }
@media (min-width: 720px) {
  .grid-overlay { display: block; }
}

/* Peripheral chapter mark — rotated 90° on left edge.
   Pentagram + Linear move: tiny editorial mark in the margin that says
   "this is part of an ordered sequence." Desktop only. */
.chapter-mark {
  position: fixed;
  left: clamp(0.75rem, 1.5vw, 1.25rem);
  top: 50%;
  z-index: 3;
  transform: translateY(-50%) rotate(-90deg);
  transform-origin: center center;
  display: none;
  align-items: center;
  gap: 0.75rem;
  color: var(--ash);
  font-family: 'Inter', sans-serif;
  font-size: 10px;
  font-weight: 500;
  letter-spacing: var(--track-eyebrow);
  text-transform: uppercase;
  line-height: 1;
  white-space: nowrap;
  pointer-events: none;
}
.chapter-mark::before {
  content: "";
  width: 28px;
  height: 1px;
  background: var(--rule-3);
}
@media (min-width: 900px) {
  .chapter-mark { display: inline-flex; }
}

/* ─────────────────────────────────────────────────────────────
   4. Typography — display & UI
   ───────────────────────────────────────────────────────────── */

.font-display,
h1, h2, h3, .h1, .h2, .h3 {
  font-family: 'Cormorant Garamond', 'Iowan Old Style', Georgia, serif;
  font-weight: 400;
  letter-spacing: var(--track-display);
  line-height: 1.04;
  font-feature-settings: "kern" 1, "liga" 1, "dlig" 1;
}

.h-hero {
  /* Floor lowered from 3.5rem so 320–430px viewports don't overflow.
     Preferred 10vw scales linearly; ceiling holds the hero readable on 4K. */
  font-size: clamp(2.5rem, 10vw, 12rem);
  line-height: 0.98;
  letter-spacing: -0.022em;
  font-weight: 400;
}
.h-display {
  font-size: clamp(2.75rem, 7vw, 6rem);
  line-height: 1.02;
  letter-spacing: -0.02em;
}
.h-section {
  font-size: clamp(2rem, 4.5vw, 3.75rem);
  line-height: 1.06;
  letter-spacing: -0.018em;
}
.h-sub {
  font-size: clamp(1.5rem, 2.6vw, 2.25rem);
  line-height: 1.18;
  letter-spacing: -0.012em;
}

.eyebrow {
  font-family: 'Inter', system-ui, sans-serif;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: var(--track-eyebrow);
  text-transform: uppercase;
  color: var(--ash);
  line-height: 1;
}

.wordmark {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 500;
  letter-spacing: var(--track-wordmark);
  line-height: 1;
  color: var(--paper);
  text-decoration: none;
}
.wordmark em {
  font-style: italic;
  font-weight: 400;
  color: var(--paper);
}
/* Inner span — magnetic target for the wordmark. Inline-block so transforms
   apply, with no impact on the natural text layout. */
.wordmark__inner,
.site-header__brand-inner {
  display: inline-block;
}

.prose {
  font-family: 'Inter', system-ui, sans-serif;
  font-size: clamp(1rem, 1.05vw, 1.1875rem);
  line-height: 1.62;
  color: var(--paper-3);
  max-width: 36rem;
  letter-spacing: -0.005em;
}
.prose strong { color: var(--paper); font-weight: 500; }
.prose em     { font-family: 'Cormorant Garamond', Georgia, serif; font-style: italic; color: var(--paper); }

/* ─────────────────────────────────────────────────────────────
   5. Layout primitives
   ───────────────────────────────────────────────────────────── */
.frame {
  padding-left: var(--gutter);
  padding-right: var(--gutter);
}
.rule {
  border: 0;
  height: 1px;
  background: var(--rule-2);
  margin: 0;
}

/* Ensure page content sits ABOVE vignette and grid, BELOW grain.
   Note: .chapter-mark is INTENTIONALLY excluded — it needs position: fixed
   to live in the margin, and has its own z-index in section 3. */
.cold-open,
main, section, header, footer {
  position: relative;
  z-index: 4;
}

/* ─────────────────────────────────────────────────────────────
   6. Motion primitives
   ───────────────────────────────────────────────────────────── */

.reveal {
  opacity: 0;
  transform: translate3d(0, 14px, 0);
  transition:
    opacity    var(--dur-base)  var(--ease-house),
    transform  var(--dur-base)  var(--ease-house);
  will-change: opacity, transform;
}
.reveal.in {
  opacity: 1;
  transform: translate3d(0, 0, 0);
}

.stagger > * {
  opacity: 0;
  transform: translate3d(0, 14px, 0);
  transition:
    opacity    var(--dur-base)  var(--ease-house),
    transform  var(--dur-base)  var(--ease-house);
  transition-delay: calc(var(--i, 0) * 90ms);
  will-change: opacity, transform;
}
.stagger.in > * {
  opacity: 1;
  transform: translate3d(0, 0, 0);
}
.stagger.in > *:nth-child(1)  { transition-delay:   0ms; }
.stagger.in > *:nth-child(2)  { transition-delay:  90ms; }
.stagger.in > *:nth-child(3)  { transition-delay: 180ms; }
.stagger.in > *:nth-child(4)  { transition-delay: 270ms; }
.stagger.in > *:nth-child(5)  { transition-delay: 360ms; }
.stagger.in > *:nth-child(6)  { transition-delay: 450ms; }
.stagger.in > *:nth-child(7)  { transition-delay: 540ms; }
.stagger.in > *:nth-child(8)  { transition-delay: 630ms; }

/* Per-word reveal — splitWords() in scripts.js builds these spans
   inside .headline. Each word rises from below its own baseline.
   The default rule uses --i for auto-staggering future headlines;
   the Cold Open hero overrides with hand-tuned optical delays below. */
.headline .word {
  display: inline-block;
  opacity: 0;
  transform: translate3d(0, 1.05em, 0);
  transition:
    opacity   var(--dur-slow)   var(--ease-cinema),
    transform var(--dur-cinema) var(--ease-cinema);
  transition-delay: calc(var(--i, 0) * 90ms);
  will-change: opacity, transform;
}
/* Italic words — DOM-walking splitter tags words inside <em> with this class
   so the headline's "seriously." preserves its italic styling. */
.headline .word--italic { font-style: italic; }

/* Activation: body.is-loaded triggers the reveal. Also keeps the legacy
   `.in` class working for non-headline use cases. Simple translate3d
   end state — no CSS variable composition (which caused matrix-interp
   glitches during the reveal animation in the previous iteration). */
body.is-loaded .headline .word,
.headline .word.in {
  opacity: 1;
  transform: translate3d(0, 0, 0);
}

/* Headline interactivity — per-CHARACTER hover, not per-word.
   splitWords() in scripts.js wraps every letter of every word in a
   <span class="char">. CSS :hover on each char drives an individual
   lift+scale animation. Like keys on a keyboard responding to a fingertip.

   1. data-cursor still on the word → cursor ring expands when hovering
      any letter in the word (Index/Brief button style — unchanged)
   2. Each .char lifts independently on hover. Translate Y -7px + scale
      1.08 + slight color brighten. Pure CSS state, no JS per-frame work.
   3. Reveal animation stays on the .word level (unchanged). Per-letter
      hover composes WITH the reveal because they're on different elements
      (parent word handles reveal Y/opacity, child char handles hover lift). */
.cold-open .headline .word {
  /* No special positioning — chars are display:inline-block within. */
}

/* AUDIO-REACTIVE headline glow.
   Subtle paper-color drop-shadow filter on the headline pulses with the
   ambient pad's mid-frequency energy. drop-shadow is GPU-accelerated and
   propagates through child elements (so every char glows in sync).

   When audio is off (--audio-mid = 0), filter resolves to drop-shadow(0 0
   0 transparent) — zero visual impact. As mid energy rises with the chord
   sustain, the headline acquires a soft paper bloom that breathes at the
   chord-progression rate. Almost imperceptible until you notice it.

   MOBILE: filter: drop-shadow() updated at 60fps is GPU-expensive on
   mobile DPR 3 phones, costing ~9× more pixels to re-blur. Disabled
   entirely on mobile — the constellation pulse + spotlight (which is
   already hidden on touch) carry the audio-reactive feel. */
.cold-open .headline {
  filter: drop-shadow(0 0
    calc(var(--audio-mid, 0) * 14px)
    rgba(241, 236, 227, calc(var(--audio-mid, 0) * 0.35))
  );
  will-change: filter;
}
@media (max-width: 767px), (pointer: coarse) {
  .cold-open .headline { filter: none !important; will-change: auto; }
}
.cold-open .headline .char {
  display: inline-block;
  /* Default identity transform — explicit so the hover transition
     interpolates between matching structures (no matrix decomposition
     glitch when going from "none" to "translate + scale"). */
  transform: translateY(0) scale(1);
  transition:
    transform 360ms cubic-bezier(0.32, 0.72, 0, 1),
    color     360ms cubic-bezier(0.32, 0.72, 0, 1),
    text-shadow 360ms cubic-bezier(0.32, 0.72, 0, 1);
  will-change: transform;
}
.cold-open .headline .char:hover {
  transform: translateY(-7px) scale(1.08);
  /* Subtle paper-color brighten — keeps the editorial palette but adds
     a "the letter you're touching glows" signal. */
  text-shadow: 0 1px 16px rgba(241, 236, 227, 0.35);
}
@media (hover: none), (pointer: coarse), (prefers-reduced-motion: reduce) {
  .cold-open .headline .char {
    transform: none !important;
    text-shadow: none !important;
    transition: none;
  }
}

/* Cold Open hero headline — hand-tuned optical timing.
   Short connecting words ("for", "that", "take") get less weight;
   content words breathe; the italic "seriously." holds back ~260ms longer
   so it lands as a closing kick rather than a sequence step.
   Total animation tail: ~2.6s (last word delay 1230 + 1400 cinema duration). */
.cold-open .headline .word:nth-child(1) { transition-delay:  380ms; } /* Hand-coded */
.cold-open .headline .word:nth-child(2) { transition-delay:  490ms; } /* websites */
.cold-open .headline .word:nth-child(3) { transition-delay:  570ms; } /* for */
.cold-open .headline .word:nth-child(4) { transition-delay:  680ms; } /* businesses */
.cold-open .headline .word:nth-child(5) { transition-delay:  770ms; } /* that */
.cold-open .headline .word:nth-child(6) { transition-delay:  860ms; } /* take */
.cold-open .headline .word:nth-child(7) { transition-delay:  970ms; } /* themselves */
.cold-open .headline .word:nth-child(8) { transition-delay: 1230ms; } /* seriously. — punchline hold */

.link-hairline {
  position: relative;
  display: inline-flex;
  align-items: baseline;
  gap: 0.6em;
  color: var(--paper);
  text-decoration: none;
  padding-bottom: 4px;
}
.link-hairline::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: currentColor;
  transform-origin: left center;
  transform: scaleX(0.18);
  opacity: 0.5;
  transition:
    transform var(--dur-base) var(--ease-house),
    opacity   var(--dur-base) var(--ease-house);
}
.link-hairline:hover::after,
.link-hairline:focus-visible::after {
  transform: scaleX(1);
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  .reveal,
  .stagger > *,
  .headline .word {
    opacity: 1;
    transform: none;
  }
}

/* ─────────────────────────────────────────────────────────────
   7. Scrollbar (v=80 — refined obsidian/bone)

   Replaces the system default scrollbar with the studio's color
   language. Quiet and luxurious — the thumb is a low-alpha paper
   tint that brightens on hover and on active grab. Thin enough
   (6px) to read as editorial, not chunky.

   Three states:
     default — paper at 18% alpha (a whisper)
     hover   — paper at 34% alpha (acknowledged)
     active  — paper at 55% alpha (held)

   Track is fully transparent so the scrollbar floats over the
   obsidian background without a "channel" outline. Firefox gets
   the equivalent treatment via scrollbar-width + scrollbar-color.
   ───────────────────────────────────────────────────────────── */
::-webkit-scrollbar         { width: 6px; height: 6px; }
::-webkit-scrollbar-track   { background: transparent; }
::-webkit-scrollbar-thumb {
  background: rgba(241, 236, 227, 0.18);
  border-radius: 3px;
}
::-webkit-scrollbar-thumb:hover  { background: rgba(241, 236, 227, 0.34); }
::-webkit-scrollbar-thumb:active { background: rgba(241, 236, 227, 0.55); }

/* Firefox — equivalent treatment */
html {
  scrollbar-width: thin;
  scrollbar-color: rgba(241, 236, 227, 0.18) transparent;
}

/* ─────────────────────────────────────────────────────────────
   8. Cold Open
   ───────────────────────────────────────────────────────────── */
.cold-open {
  min-height: 100svh;
  display: grid;
  grid-template-rows: auto 1fr auto auto;
  padding-block: clamp(1.25rem, 3vh, 2.5rem);
  position: relative;
}
.cold-open__top,
.cold-open__bottom {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}
.cold-open__top {
  gap: var(--space-4);
}
.cold-open__top-left,
.cold-open__top-right {
  display: inline-flex;
  align-items: center;
  gap: clamp(0.75rem, 2vw, 1.5rem);
}

/* v=83 — keep the right cluster pinned to the right edge now that the
   cold-open wordmark on the left has been removed. With only one flex
   child remaining in .cold-open__top, justify-content: space-between
   has nothing to "between" and would otherwise drift the cluster left.
   margin-left: auto restores the right-edge alignment cleanly. */
.cold-open__top-right {
  margin-left: auto;
}
.cold-open__center {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding-block: var(--space-5);
  /* Scroll-tied parallax hook — JS updates --scroll-y on this element. */
  transform: translate3d(0, calc(var(--scroll-y) * 0.15), 0);
  will-change: transform;
}
.cold-open .headline {
  margin: 0;
  max-width: 18ch;
}

/* Scroll cue — small, persistent. A subtle pulse. */
.scroll-cue {
  display: inline-flex;
  align-items: center;
  gap: 0.75rem;
  color: var(--ash);
  font-family: 'Inter', sans-serif;
  font-size: 11px;
  letter-spacing: var(--track-eyebrow);
  text-transform: uppercase;
}
.scroll-cue::before {
  content: "";
  width: 1px;
  height: 28px;
  background: linear-gradient(to bottom, transparent, var(--paper-3), transparent);
  animation: scroll-cue-pulse 2.6s var(--ease-house) infinite;
}
@keyframes scroll-cue-pulse {
  0%   { transform: translateY(-12px); opacity: 0; }
  35%  { opacity: 1; }
  100% { transform: translateY(12px);  opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .scroll-cue::before { animation: none; opacity: 0.6; transform: none; }
}

/* ─────────────────────────────────────────────────────────────
   9. Status pill — capsule with pulsing dot
   ───────────────────────────────────────────────────────────── */
.status-pill {
  display: none;       /* Desktop-only signal — see media query below. */
  align-items: center;
  gap: 0.55rem;
  padding: 0.45rem 0.85rem 0.45rem 0.65rem;
  border: 1px solid var(--rule-2);
  border-radius: 999px;
  font-family: 'Inter', sans-serif;
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--paper-3);
  background: linear-gradient(180deg, rgba(241,236,227,0.02), rgba(241,236,227,0));
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  white-space: nowrap;
  line-height: 1;
}
@media (min-width: 720px) {
  .status-pill { display: inline-flex; }
}
.status-pill__dot {
  position: relative;
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 999px;
  background: var(--paper);
  flex: 0 0 auto;
}
.status-pill__dot::after {
  content: "";
  position: absolute;
  inset: -3px;
  border-radius: 999px;
  background: var(--paper);
  opacity: 0;
  animation: status-pulse 2.6s var(--ease-house) infinite;
}
@keyframes status-pulse {
  0%   { transform: scale(0.6); opacity: 0.55; }
  100% { transform: scale(2.4); opacity: 0;    }
}
@media (prefers-reduced-motion: reduce) {
  .status-pill__dot::after { animation: none; }
}

/* ─────────────────────────────────────────────────────────────
   10. Marquee — slow ambient ticker at the foot of the Cold Open
   ───────────────────────────────────────────────────────────── */
.marquee {
  position: relative;
  margin-top: var(--space-4);
  overflow: hidden;
  height: 24px;
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  /* Edge fade — Lusion/Locomotive signature touch. */
  -webkit-mask-image: linear-gradient(to right, transparent 0%, black 8%, black 92%, transparent 100%);
          mask-image: linear-gradient(to right, transparent 0%, black 8%, black 92%, transparent 100%);
}
.marquee__track {
  display: flex;
  align-items: center;
  height: 100%;
  width: max-content;
  gap: clamp(1.5rem, 4vw, 3rem);
  animation: marquee-scroll 64s linear infinite;
  will-change: transform;
}
.marquee__group {
  display: inline-flex;
  align-items: center;
  gap: clamp(1.5rem, 4vw, 3rem);
  flex: 0 0 auto;
  font-family: 'Inter', sans-serif;
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--ash);
  line-height: 1;
  white-space: nowrap;
}
.marquee__group span::after {
  content: "·";
  display: inline-block;
  margin-left: clamp(1.5rem, 4vw, 3rem);
  color: var(--rule-3);
}
/* Every span gets a dot — including the last of a group — so the loop seam
   between group A's final word and group B's first word reads continuously. */
@keyframes marquee-scroll {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .marquee__track { animation: none; }
}

/* ─────────────────────────────────────────────────────────────
   11. Custom cursor — paper dot + outline ring on interactive elements
   ───────────────────────────────────────────────────────────── */
.cursor {
  position: fixed;
  top: 0;
  left: 0;
  /* Above preloader (99998), preloader curtain, and everything else.
     Visitor must always be able to see and find their cursor — including
     while the preloader is showing the Begin gateway. */
  z-index: 100000;
  pointer-events: none;
  border-radius: 999px;
  /* Hidden by default; JS adds .is-active on first mousemove */
  opacity: 0;
  transform: translate3d(-50%, -50%, 0);
}
.cursor.is-active { opacity: 1; }
.cursor--dot {
  width: 6px;
  height: 6px;
  background: var(--paper);
  mix-blend-mode: difference;
  transition:
    width        var(--dur-fast) var(--ease-micro),
    height       var(--dur-fast) var(--ease-micro),
    background   var(--dur-fast) var(--ease-micro),
    opacity      var(--dur-fast) var(--ease-micro);
}
.cursor--ring {
  width: 36px;
  height: 36px;
  border: 1px solid var(--paper);
  opacity: 0;
  transform: translate3d(-50%, -50%, 0) scale(0.6);
  transition:
    opacity   var(--dur-base) var(--ease-house),
    transform var(--dur-base) var(--ease-house);
  mix-blend-mode: difference;
}
.cursor.is-active.cursor--ring { opacity: 0; } /* ring stays hidden until hover */
body.cursor-hover .cursor--ring {
  opacity: 0.9;
  transform: translate3d(-50%, -50%, 0) scale(1);
}
body.cursor-hover .cursor--dot {
  width: 2px;
  height: 2px;
}
/* Touch / coarse pointer / reduced-motion: hide custom cursor entirely. */
@media (hover: none), (pointer: coarse), (prefers-reduced-motion: reduce) {
  .cursor { display: none !important; }
}

/* ─────────────────────────────────────────────────────────────
   12. Cold Open entry choreography
   Activated when JS adds `.is-loaded` to <body>.
   Each chrome element fades + lifts on its own delay; total ~1.6s.
   ───────────────────────────────────────────────────────────── */
.intro-fade {
  opacity: 0;
  transform: translate3d(0, 6px, 0);
  filter: blur(2px);
}
body.is-loaded .intro-fade {
  opacity: 1;
  transform: translate3d(0, 0, 0);
  filter: blur(0);
  transition:
    opacity   var(--dur-slow) var(--ease-cinema),
    transform var(--dur-slow) var(--ease-cinema),
    filter    var(--dur-slow) var(--ease-cinema);
}
/* Per-element staggered delays. Hand-tuned, not equal intervals — optical timing. */
body.is-loaded .intro-fade.d-1 { transition-delay:   0ms; }
body.is-loaded .intro-fade.d-2 { transition-delay: 140ms; }
body.is-loaded .intro-fade.d-3 { transition-delay: 240ms; }
body.is-loaded .intro-fade.d-4 { transition-delay: 380ms; }
body.is-loaded .intro-fade.d-5 { transition-delay: 520ms; }
body.is-loaded .intro-fade.d-6 { transition-delay: 720ms; }
body.is-loaded .intro-fade.d-7 { transition-delay: 980ms; }

/* MMXXVI — glyph-by-glyph type-in. Wrap each char in a <span>. */
.glyph-in span {
  display: inline-block;
  opacity: 0;
  transform: translate3d(0, 4px, 0);
}
body.is-loaded .glyph-in span {
  opacity: 1;
  transform: translate3d(0, 0, 0);
  transition:
    opacity   480ms var(--ease-cinema),
    transform 480ms var(--ease-cinema);
}
body.is-loaded .glyph-in span:nth-child(1) { transition-delay: 320ms; }
body.is-loaded .glyph-in span:nth-child(2) { transition-delay: 400ms; }
body.is-loaded .glyph-in span:nth-child(3) { transition-delay: 470ms; }
body.is-loaded .glyph-in span:nth-child(4) { transition-delay: 530ms; }
body.is-loaded .glyph-in span:nth-child(5) { transition-delay: 580ms; }
body.is-loaded .glyph-in span:nth-child(6) { transition-delay: 620ms; }

/* Hairline-draw — the corner anchor under-rules expand from text baseline. */
.draw-rule {
  position: relative;
}
.draw-rule::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -6px;
  height: 1px;
  background: var(--rule-2);
  transform-origin: left center;
  transform: scaleX(0);
  transition: transform var(--dur-slow) var(--ease-cinema);
}
body.is-loaded .draw-rule.d-4::before { transition-delay: 480ms; transform: scaleX(1); }
body.is-loaded .draw-rule.d-5::before { transition-delay: 620ms; transform: scaleX(1); }

/* Headline no longer uses intro-fade — replaced by per-word reveal (Section 6).
   This rule kept as a safety: if .headline ever gets .intro-fade applied
   elsewhere (e.g. in a future case-study page), it won't get blurred. */
.headline.intro-fade { filter: none; }

/* Chapter mark needs its own rotate transform preserved through intro-fade.
   Without this override the intro-fade's 6px translate would wipe out the rotation. */
.chapter-mark.intro-fade,
body.is-loaded .chapter-mark.intro-fade {
  transform: translateY(-50%) rotate(-90deg);
}

@media (prefers-reduced-motion: reduce) {
  .intro-fade,
  .glyph-in span,
  .draw-rule::before {
    opacity: 1;
    transform: none;
    filter: none;
  }
  .draw-rule::before { transform: scaleX(1); }
}

/* ─────────────────────────────────────────────────────────────
   13. Magnetic interactive elements
   The cursor pulls the element toward it within ~100px.
   JS updates --mx / --my CSS variables on the element; the transition
   smooths every change including the return-to-zero when the cursor
   exits the attraction zone. Mobile / coarse-pointer: no-op (transition
   on transform still fires but JS never sets the vars).
   ───────────────────────────────────────────────────────────── */
.magnetic,
[data-magnetic] {
  transform: translate3d(var(--mx, 0px), var(--my, 0px), 0);
  transition: transform 240ms var(--ease-house);
  will-change: transform;
}
/* Magnetic items inside a transform context (rotated chapter mark, etc.)
   should opt out — they need their own transform space. Add .no-magnetic
   to suppress, or simply omit data-magnetic. */
@media (hover: none), (pointer: coarse), (prefers-reduced-motion: reduce) {
  .magnetic,
  [data-magnetic] {
    transition: none;
    transform: none;
  }
}

/* ─────────────────────────────────────────────────────────────
   14. Sticky header
   Hidden during Cold Open (scroll < 80vh).
   After threshold: reveals on scroll-up, hides on scroll-down.
   Backdrop blur + saturate (Apple product-page treatment).
   ───────────────────────────────────────────────────────────── */
.site-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  height: 60px;
  padding: 0 var(--gutter);
  /* Translucent obsidian + heavy blur — same recipe as apple.com/iphone */
  background: rgba(10, 10, 12, 0.66);
  backdrop-filter: blur(20px) saturate(180%);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
  border-bottom: 1px solid var(--rule);
  transform: translate3d(0, -100%, 0);
  transition: transform var(--dur-base) var(--ease-house);
  pointer-events: none; /* hidden state: no interaction even if mid-transition */
}
.site-header[data-state="visible"] {
  transform: translate3d(0, 0, 0);
  pointer-events: auto;
}
.site-header__brand {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 500;
  font-size: 1rem;
  letter-spacing: var(--track-wordmark);
  line-height: 1;
  color: var(--paper);
  text-decoration: none;
}
.site-header__brand em {
  font-style: italic;
  font-weight: 400;
}
.site-header__nav {
  display: flex;
  align-items: center;
  gap: clamp(1.25rem, 2.5vw, 2.5rem);
  list-style: none;
  margin: 0;
  padding: 0;
}
.site-header__link {
  font-family: 'Inter', sans-serif;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--paper-3);
  text-decoration: none;
  padding-bottom: 4px;
  position: relative;
  transition: color var(--dur-fast) var(--ease-micro);
}
.site-header__link::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: currentColor;
  transform-origin: left center;
  transform: scaleX(0);
  opacity: 0.6;
  transition:
    transform var(--dur-base) var(--ease-house),
    opacity   var(--dur-base) var(--ease-house);
}
.site-header__link:hover,
.site-header__link:focus-visible { color: var(--paper); }
.site-header__link:hover::after,
.site-header__link:focus-visible::after {
  transform: scaleX(1);
  opacity: 1;
}
/* Phone layout: shrink to wordmark + condensed nav.
   At <520px we drop nav labels to single letters or just hide them. */
@media (max-width: 520px) {
  .site-header { height: 52px; }
  .site-header__nav { gap: 1rem; }
  .site-header__link { font-size: 11px; letter-spacing: 0.12em; }
}

/* ─────────────────────────────────────────────────────────────
   15. Scroll progress hairline
   1px line at the top edge of the viewport. Scales horizontally
   based on --progress (0 → 1) set by JS. Engineering polish — the
   kind of detail Linear and Stripe ship as a signature. Hidden until
   the user has started scrolling so the Cold Open stays uncluttered.
   ───────────────────────────────────────────────────────────── */
.scroll-progress {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 1px;
  z-index: 9998;
  pointer-events: none;
  transform-origin: left center;
  transform: scaleX(var(--progress, 0));
  background: var(--paper);
  opacity: 0.45;
  transition: opacity var(--dur-base) var(--ease-house);
  will-change: transform;
}
.scroll-progress[data-state="idle"] { opacity: 0; }
@media (prefers-reduced-motion: reduce) {
  .scroll-progress { transition: none; }
}


/* ═════════════════════════════════════════════════════════════════
   SESSION 3 — THE EDITORIAL PIVOT
   Studio statement extension, full-bleed Pivot transition,
   Sierra case study spread, motion moments, dynamic chapter marks,
   live local time, image-enter-with-blur.
   ═════════════════════════════════════════════════════════════════ */

/* ─────────────────────────────────────────────────────────────
   16. Studio statement — extended editorial intro
   ───────────────────────────────────────────────────────────── */
.studio-statement {
  padding-block: clamp(6rem, 14vw, 14rem);
  position: relative;
}
.studio-statement__inner {
  max-width: 56rem;
  margin: 0 auto;
}
.studio-statement__eyebrow {
  margin-bottom: var(--space-4);
}
.studio-statement__line {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-size: clamp(1.5rem, 2.6vw, 2.5rem);
  line-height: 1.22;
  letter-spacing: -0.014em;
  color: var(--paper);
  margin: 0 0 var(--space-4) 0;
  max-width: 32ch;
}
.studio-statement__line + .studio-statement__line {
  color: var(--paper-3);
}
.studio-statement__line em {
  font-style: italic;
  color: var(--paper);
}

/* ─────────────────────────────────────────────────────────────
   17. The Pivot — full-bleed cinematic transition into the work
   The outer .pivot is tall (250vh). Inside, .pivot__viewport is
   position: sticky so it pins at 100vh as the visitor scrolls
   through. JS sets --pivot-progress (0→1) based on how far
   we've scrolled through the section. CSS reads that to drive
   the video scale, overlay darkness, and content fade.
   ───────────────────────────────────────────────────────────── */
.pivot {
  position: relative;
  height: 250vh;
  z-index: 4;
}
.pivot__viewport {
  position: sticky;
  top: 0;
  height: 100vh;
  width: 100%;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Subtle bottom fade keeps the seam between Pivot and case study soft. */
  -webkit-mask-image: linear-gradient(180deg, black 0%, black 85%, transparent 100%);
          mask-image: linear-gradient(180deg, black 0%, black 85%, transparent 100%);
}
.pivot__media {
  position: absolute;
  inset: 0;
  z-index: 1;
  overflow: hidden;
}
.pivot__media video,
.pivot__media .pivot__placeholder {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  /* Scale 1.2 → 1.0 across the scroll. JS-set --pivot-progress drives it. */
  transform: scale(calc(1.16 - var(--pivot-progress, 0) * 0.16));
  will-change: transform;
}
.pivot__media video {
  object-fit: cover;
  opacity: 0;
  transition: opacity 600ms var(--ease-cinema);
}
.pivot__media[data-video-state="loaded"] video { opacity: 1; }
.pivot__media[data-video-state="loaded"] .pivot__placeholder { opacity: 0; }

/* Cinematic CSS placeholder — multiple radial gradients drifting over 28s.
   Loaded as a fallback when no real Sierra footage is in brand_assets/sierra/.
   Looks like a film still, not a "broken video" box. */
.pivot__placeholder {
  background:
    radial-gradient(ellipse 60% 80% at 25% 50%, rgba(160, 110, 60, 0.18), transparent 60%),
    radial-gradient(ellipse 80% 60% at 80% 60%, rgba(90, 80, 100, 0.14), transparent 70%),
    radial-gradient(ellipse 100% 100% at 50% 100%, rgba(0,0,0, 0.55), transparent 60%),
    linear-gradient(160deg, #16161B 0%, #0A0A0C 70%);
  background-size: 100% 100%, 100% 100%, 100% 100%, 100% 100%;
  animation: pivot-cinema 28s ease-in-out infinite alternate;
  opacity: 1;
  transition: opacity 600ms var(--ease-cinema);
}
@keyframes pivot-cinema {
  0% {
    background-position: 0% 0%, 100% 100%, 50% 100%, 0% 0%;
    background-size: 100% 100%, 100% 100%, 100% 100%, 100% 100%;
  }
  100% {
    background-position: 30% 30%, 70% 70%, 50% 100%, 0% 0%;
    background-size: 120% 120%, 130% 110%, 100% 100%, 100% 100%;
  }
}

/* Dark overlay — gets lighter as user scrolls through Pivot. */
.pivot__overlay {
  position: absolute;
  inset: 0;
  z-index: 2;
  background:
    linear-gradient(180deg,
      rgba(10,10,12, calc(0.55 - var(--pivot-progress, 0) * 0.28)) 0%,
      rgba(10,10,12, calc(0.30 - var(--pivot-progress, 0) * 0.15)) 50%,
      rgba(10,10,12, calc(0.65 - var(--pivot-progress, 0) * 0.15)) 100%);
}
/* Film grain over the Pivot — same SVG noise as body, but stronger. */
.pivot__overlay::after {
  content: "";
  position: absolute;
  inset: 0;
  opacity: 0.09;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='220' height='220'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch' seed='5'/><feColorMatrix values='0 0 0 0 1   0 0 0 0 1   0 0 0 0 1   0 0 0 0.6 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
  background-size: 220px 220px;
}

/* Editorial content overlaid at center of the Pivot. Fades + lifts as
   we scroll past, handing off to the case study below. */
.pivot__content {
  position: relative;
  z-index: 3;
  text-align: center;
  padding: 0 var(--gutter);
  max-width: 56rem;
  /* Opacity 1 → 0.2, plus a -40px lift, scrubbed by --pivot-progress */
  opacity: calc(1 - var(--pivot-progress, 0) * 0.8);
  transform: translateY(calc(var(--pivot-progress, 0) * -56px));
}
.pivot__eyebrow {
  margin-bottom: var(--space-4);
  color: var(--paper-3);
}
.pivot__title {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 400;
  font-size: clamp(3rem, 9vw, 8.5rem);
  line-height: 0.98;
  letter-spacing: -0.022em;
  color: var(--paper);
  margin: 0;
}
.pivot__title em { font-style: italic; }
.pivot__sub {
  margin-top: var(--space-3);
  color: var(--paper-3);
  font-family: 'Inter', sans-serif;
  font-size: clamp(0.8125rem, 0.9vw, 0.9375rem);
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

@media (prefers-reduced-motion: reduce) {
  .pivot { height: 100vh; }
  .pivot__media video,
  .pivot__media .pivot__placeholder { transform: none; animation: none; }
  .pivot__content { opacity: 1; transform: none; }
}

/* ─────────────────────────────────────────────────────────────
   18. Case study spread — editorial magazine layout
   ───────────────────────────────────────────────────────────── */
.case-study {
  position: relative;
  z-index: 4;
  padding-block: clamp(5rem, 10vw, 11rem);
  background: var(--ink);
}
.case-study__header {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-4);
  margin-bottom: clamp(3rem, 6vw, 6rem);
  max-width: 64rem;
}
@media (min-width: 900px) {
  .case-study__header {
    grid-template-columns: 4rem 1fr;
    gap: clamp(2rem, 4vw, 4rem);
    align-items: baseline;
  }
}
.case-study__chapter {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 400;
  font-size: clamp(3rem, 5vw, 5rem);
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--paper);
}
.case-study__title-block {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.case-study__eyebrow {
  color: var(--ash);
}
.case-study__title {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 400;
  font-size: clamp(2.5rem, 6vw, 5.5rem);
  line-height: 1.02;
  letter-spacing: -0.022em;
  color: var(--paper);
  margin: 0;
}
.case-study__title em { font-style: italic; }
.case-study__sub {
  color: var(--ash);
}

.case-study__essay {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-4);
  margin-bottom: clamp(4rem, 8vw, 8rem);
  max-width: 60rem;
}
/* Spacer column hidden by default (mobile); visible on >=900px so the
   essay aligns to the title block. Order matters: this rule MUST come
   BEFORE the @media block, or the media block's display:block is
   overridden by source order. */
.case-study__essay-spacer { display: none; }
@media (min-width: 900px) {
  .case-study__essay {
    grid-template-columns: 4rem 1fr 1fr;
    gap: clamp(2rem, 4vw, 4rem);
  }
  .case-study__essay-spacer { display: block; }
}
.case-study__essay p {
  font-family: 'Inter', sans-serif;
  font-size: clamp(0.9375rem, 1vw, 1.0625rem);
  line-height: 1.7;
  color: var(--paper-3);
  letter-spacing: -0.003em;
  margin: 0;
}
.case-study__essay strong { color: var(--paper); font-weight: 500; }
.case-study__essay em {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  color: var(--paper);
}

/* ─────────────────────────────────────────────────────────────
   19. Motion moments — the four-up grid showing Sierra in motion
   ───────────────────────────────────────────────────────────── */
.moments {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(3rem, 5vw, 5rem);
  margin-bottom: clamp(4rem, 8vw, 8rem);
}
@media (min-width: 900px) {
  .moments {
    grid-template-columns: 1fr 1fr;
    gap: clamp(3rem, 4vw, 4.5rem) clamp(2rem, 3vw, 3rem);
  }
  /* Stagger the right column down by 8rem for editorial rhythm — like a magazine spread */
  .moments .moment:nth-child(even) { margin-top: clamp(0rem, 6vw, 6rem); }
}
.moment {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.moment__header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  padding-bottom: var(--space-2);
  border-bottom: 1px solid var(--rule-2);
}
.moment__numeral {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-weight: 400;
  font-size: clamp(1.5rem, 1.8vw, 1.875rem);
  line-height: 1;
  color: var(--paper);
  letter-spacing: -0.01em;
}
.moment__title {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 400;
  font-size: clamp(1.375rem, 1.7vw, 1.75rem);
  line-height: 1.1;
  letter-spacing: -0.012em;
  color: var(--paper);
  margin: 0;
  flex: 1;
  text-align: right;
}

.moment__media {
  position: relative;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  background: var(--ink-2);
  border: 1px solid var(--rule);
  /* Layered with media-reveal blur enter — added via class on the element */
}
.moment__media video,
.moment__placeholder {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
/* Foreground video — the actual content. Object-fit defaults to cover
   for landscape; switches to contain when JS detects portrait orientation. */
.moment__media-fg {
  object-fit: cover;
  z-index: 3;
  opacity: 0;
  transition: opacity 600ms var(--ease-cinema);
}
.moment__media[data-video-state="loaded"] .moment__media-fg { opacity: 1; }
.moment__media[data-video-state="loaded"] .moment__placeholder { opacity: 0; }

/* Portrait videos — Apple App Store treatment.
   Foreground at natural aspect (object-fit: contain), background is a
   blurred + saturated clone of the same video filling the container.
   The video appears to float above its own ambient halo. */
.moment__media[data-orientation="portrait"] .moment__media-fg {
  object-fit: contain;
}
.moment__media-bg {
  z-index: 1;
  object-fit: cover;
  /* The blur + saturate + brightness combo is the exact recipe Apple uses
     on App Store video previews. The transform: scale hides the blur halo
     edges that would otherwise show against the container border. */
  filter: blur(36px) saturate(160%) brightness(1.12);
  transform: scale(1.18);
  opacity: 0;
  transition: opacity 1100ms var(--ease-cinema);
  pointer-events: none;
}
.moment__media[data-orientation="portrait"][data-video-state="loaded"] .moment__media-bg {
  opacity: 0.85;
}
@media (prefers-reduced-motion: reduce) {
  .moment__media-bg { transition: none; }
}

/* Static-image moment (e.g., the Fleet screenshot when no video exists).
   Slow CSS Ken-Burns animation: subtle scale + slow vertical drift.
   Apple App Store uses this same technique on static product screenshots
   between video clips — the page itself appears to drift and breathe. */
.moment__media--image {
  background: var(--ink);
}
.moment__image {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 0% 0%;
  transform: scale(1.06);
  animation: moment-kenburns 26s ease-in-out infinite alternate;
  will-change: transform, object-position;
}
@keyframes moment-kenburns {
  0%   { transform: scale(1.04); object-position: 0% 0%;   }
  50%  { transform: scale(1.10); object-position: 0% 50%;  }
  100% { transform: scale(1.04); object-position: 0% 100%; }
}
@media (prefers-reduced-motion: reduce) {
  .moment__image {
    animation: none;
    transform: scale(1);
    object-position: 0% 0%;
  }
}

/* Cinematic placeholder — drifting radial gradients, varied seed per moment
   via the --seed CSS variable for visual variety across the grid. */
.moment__placeholder {
  z-index: 1;
  background:
    radial-gradient(ellipse 60% 80% at 30% 40%, rgba(241, 236, 227, 0.06), transparent 60%),
    radial-gradient(ellipse 80% 60% at 70% 70%, rgba(241, 236, 227, 0.03), transparent 65%),
    linear-gradient(135deg, var(--ink-3) 0%, var(--ink) 70%);
  background-size: 100% 100%;
  animation: moment-drift 18s ease-in-out infinite alternate;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  padding: clamp(0.875rem, 1.5vw, 1.25rem);
  transition: opacity 600ms var(--ease-cinema);
}
.moment__placeholder span {
  font-family: 'Inter', sans-serif;
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ash);
  line-height: 1;
}
.moment:nth-child(2) .moment__placeholder { animation-delay: -4s; }
.moment:nth-child(3) .moment__placeholder { animation-delay: -9s; }
.moment:nth-child(4) .moment__placeholder { animation-delay: -13s; }
@keyframes moment-drift {
  0%   { background-position: 0% 0%, 100% 100%, 0% 0%; }
  100% { background-position: 50% 50%, 50% 0%, 0% 0%; }
}

.moment__caption {
  font-family: 'Inter', sans-serif;
  font-size: clamp(0.8125rem, 0.9vw, 0.9375rem);
  line-height: 1.55;
  color: var(--paper-3);
  letter-spacing: -0.003em;
  margin: 0;
  max-width: 38ch;
}

/* ─────────────────────────────────────────────────────────────
   20. CTA links — magnetic, hairline-draw, animated chevron
   ───────────────────────────────────────────────────────────── */
.case-study__cta {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(1.5rem, 3vw, 3rem);
  align-items: center;
  padding-top: clamp(2rem, 4vw, 4rem);
  border-top: 1px solid var(--rule);
}
.cta-link {
  position: relative;
  display: inline-flex;
  align-items: baseline;
  gap: 0.85rem;
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 400;
  font-size: clamp(1.5rem, 2.4vw, 2.25rem);
  line-height: 1;
  letter-spacing: -0.014em;
  color: var(--paper);
  text-decoration: none;
  padding-bottom: 8px;
}
.cta-link::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: currentColor;
  transform-origin: left center;
  transform: scaleX(0.12);
  opacity: 0.5;
  transition:
    transform var(--dur-base) var(--ease-house),
    opacity   var(--dur-base) var(--ease-house);
}
.cta-link:hover::after,
.cta-link:focus-visible::after {
  transform: scaleX(1);
  opacity: 1;
}
.cta-link__arrow {
  font-style: italic;
  display: inline-block;
  transition: transform var(--dur-base) var(--ease-house);
}
.cta-link:hover .cta-link__arrow {
  transform: translateX(6px);
}
.cta-link--external .cta-link__arrow {
  transition: transform var(--dur-base) var(--ease-house);
}
.cta-link--external:hover .cta-link__arrow {
  transform: translate(4px, -4px);
}

/* ─────────────────────────────────────────────────────────────
   21. Live local time chip
   Sits inside the sticky header. Pulses softly.
   JS updates the time string every 30 seconds (America/New_York).
   ───────────────────────────────────────────────────────────── */
.live-time {
  display: none;
  align-items: center;
  gap: 0.55rem;
  font-family: 'Inter', sans-serif;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--paper-3);
  line-height: 1;
  white-space: nowrap;
}
.live-time__dot {
  width: 5px;
  height: 5px;
  border-radius: 999px;
  background: var(--paper);
  animation: live-time-pulse 2.4s ease-in-out infinite;
}
.live-time__separator {
  color: var(--rule-3);
  margin: 0 0.1rem;
}
.live-time__clock {
  color: var(--paper);
  font-variant-numeric: tabular-nums;
}
@keyframes live-time-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.35; }
}
@media (prefers-reduced-motion: reduce) {
  .live-time__dot { animation: none; }
}
@media (min-width: 720px) {
  .live-time { display: inline-flex; }
}
@media (max-width: 900px) {
  /* Smaller live-time in compressed sticky header */
  .live-time { font-size: 10px; letter-spacing: 0.12em; }
}

/* Site header layout adjustment — make room for live time in the middle */
.site-header__center {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 1;
}
@media (max-width: 720px) {
  .site-header__center { display: none; }
}

/* ─────────────────────────────────────────────────────────────
   22. Media reveal — image / video enter-with-blur
   Apple's signature image reveal. Any element with .media-reveal
   starts blurred + slightly scaled, settles in on intersection.
   Reusable across the entire site — every future image inherits this.
   ───────────────────────────────────────────────────────────── */
.media-reveal {
  opacity: 0;
  filter: blur(10px);
  transform: scale(1.04);
  transition:
    opacity   1000ms var(--ease-cinema),
    filter    1400ms var(--ease-cinema),
    transform 1400ms var(--ease-cinema);
  will-change: opacity, filter, transform;
}
.media-reveal.in {
  opacity: 1;
  filter: blur(0);
  transform: scale(1);
}
@media (prefers-reduced-motion: reduce) {
  .media-reveal {
    opacity: 1; filter: none; transform: none; transition: none;
  }
}

/* ─────────────────────────────────────────────────────────────
   23. Dynamic chapter mark — crossfade on section change
   The base .chapter-mark already has its rotation and fixed-position
   styling (Section 3). This adds the crossfade behavior used when
   the dynamic chapter mark text changes (I → II → III).
   ───────────────────────────────────────────────────────────── */
.chapter-mark {
  transition:
    opacity var(--dur-fast) var(--ease-micro);
}
.chapter-mark--changing {
  opacity: 0 !important;
}
@media (prefers-reduced-motion: reduce) {
  .chapter-mark { transition: none; }
}


/* ═════════════════════════════════════════════════════════════════
   SESSION 4 — THE CONVERSION ARC
   Process · Pricing · Founder + Guarantee · Contact
   Removes the four reasons a $5K–$25K client doesn't pull the trigger:
     "How would we work together?" "Can I afford this?" "Who is he?"
     "How do I actually start?"
   ═════════════════════════════════════════════════════════════════ */

/* ─────────────────────────────────────────────────────────────
   24. Chapter III — The Process
   Three editorial steps. Each row: numeral · title · body.
   Hairline rules between steps create magazine-spread rhythm.
   ───────────────────────────────────────────────────────────── */
.process {
  position: relative;
  z-index: 4;
  padding-block: clamp(6rem, 12vw, 14rem);
  background: var(--ink);
}
.process__header {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-4);
  margin-bottom: clamp(4rem, 7vw, 7rem);
  max-width: 64rem;
}
@media (min-width: 900px) {
  .process__header {
    grid-template-columns: 5rem 1fr;
    gap: clamp(2rem, 4vw, 4rem);
    align-items: baseline;
  }
}
.process__chapter {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 400;
  font-size: clamp(3rem, 5vw, 5rem);
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--paper);
}
.process__title-block {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.process__title {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 400;
  font-size: clamp(2.5rem, 6vw, 5.5rem);
  line-height: 1.02;
  letter-spacing: -0.022em;
  color: var(--paper);
  margin: 0;
}
.process__title em { font-style: italic; }
.process__sub {
  color: var(--ash);
}

.process__steps {
  display: grid;
  gap: 0;
}
.process__step {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-3);
  padding-block: clamp(3rem, 5vw, 5rem);
  border-top: 1px solid var(--rule-2);
}
.process__step:last-child {
  border-bottom: 1px solid var(--rule-2);
}
@media (min-width: 900px) {
  .process__step {
    grid-template-columns: 5rem 1fr 1.5fr;
    gap: clamp(2rem, 4vw, 4rem);
    align-items: baseline;
  }
}
.process__numeral {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-weight: 400;
  font-size: clamp(2.5rem, 5vw, 4.5rem);
  line-height: 1;
  letter-spacing: -0.012em;
  color: var(--paper);
}
.process__step-title {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 400;
  font-size: clamp(2rem, 3.5vw, 3rem);
  line-height: 1.06;
  letter-spacing: -0.018em;
  color: var(--paper);
  margin: 0 0 var(--space-2) 0;
}
.process__step-sub {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-size: clamp(1.0625rem, 1.2vw, 1.25rem);
  line-height: 1.3;
  color: var(--paper-3);
  margin: 0;
}
.process__step-body {
  font-family: 'Inter', sans-serif;
  font-size: clamp(0.9375rem, 1vw, 1.0625rem);
  line-height: 1.7;
  color: var(--paper-3);
  letter-spacing: -0.003em;
  margin: 0;
  max-width: 38rem;
}
.process__step-body strong { color: var(--paper); font-weight: 500; }
.process__step-body em {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  color: var(--paper);
}

/* ─────────────────────────────────────────────────────────────
   25. Chapter IV — Pricing signal + selectivity filter
   The single highest-leverage line for conversion. Filters
   wrong-fit clients before they waste your time, pre-qualifies
   serious ones. Centered, generous whitespace, confident.
   ───────────────────────────────────────────────────────────── */
.pricing {
  position: relative;
  z-index: 4;
  padding-block: clamp(6rem, 10vw, 12rem);
  text-align: center;
  background: var(--ink);
}
.pricing__inner {
  max-width: 64rem;
  margin: 0 auto;
  padding: 0 var(--gutter);
}
.pricing__eyebrow {
  margin-bottom: var(--space-4);
}
.pricing__statement {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 400;
  font-size: clamp(1.625rem, 2.6vw, 2.5rem);
  line-height: 1.3;
  letter-spacing: -0.014em;
  color: var(--paper);
  margin: 0 0 var(--space-5) 0;
  max-width: 36ch;
  margin-left: auto;
  margin-right: auto;
}
.pricing__statement em { font-style: italic; }
.pricing__statement strong {
  font-weight: 400;
  color: var(--paper);
  font-feature-settings: "lnum" 1, "tnum" 1;
}
.pricing__rule {
  display: block;
  width: 4rem;
  height: 1px;
  background: var(--rule-3);
  margin: var(--space-5) auto;
  border: 0;
}
.pricing__filter {
  font-family: 'Inter', sans-serif;
  font-size: clamp(0.8125rem, 0.9vw, 0.9375rem);
  line-height: 1.6;
  color: var(--ash);
  letter-spacing: -0.003em;
  margin: 0 auto;
  max-width: 42rem;
}
.pricing__filter em {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  color: var(--paper-3);
}

/* ─────────────────────────────────────────────────────────────
   26. Chapter V — Founder preview
   Oversized italic pull-quote, monogram portrait placeholder,
   link to the full About page. The portrait swaps in seamlessly
   when brand_assets/portrait.jpg drops in — currently uses a
   CSS-generated italic "C" monogram on an ink gradient.
   ───────────────────────────────────────────────────────────── */
.founder {
  position: relative;
  z-index: 4;
  padding-block: clamp(7rem, 14vw, 16rem);
  text-align: center;
  background: var(--ink);
  border-top: 1px solid var(--rule);
}
.founder__inner {
  max-width: 68rem;
  margin: 0 auto;
  padding: 0 var(--gutter);
}
.founder__eyebrow {
  margin-bottom: var(--space-5);
}
.founder__quote {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-weight: 400;
  font-size: clamp(2rem, 4.5vw, 4.25rem);
  line-height: 1.15;
  letter-spacing: -0.02em;
  color: var(--paper);
  margin: 0 0 clamp(3rem, 5vw, 5rem) 0;
  /* Slight quotation-style hanging indent on the lead character */
  text-indent: -0.1em;
}
.founder__attribution {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: clamp(2.5rem, 4vw, 4rem);
}
.founder__portrait {
  position: relative;
  width: 64px;
  height: 64px;
  border-radius: 999px;
  background:
    radial-gradient(ellipse at 30% 30%, var(--ink-4), var(--ink-2) 80%);
  border: 1px solid var(--rule-3);
  overflow: hidden;
  flex-shrink: 0;
}
/* Monogram placeholder — swapped out automatically when a real
   <img> is added inside .founder__portrait. */
.founder__portrait::after {
  content: "C";
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-weight: 400;
  font-size: 30px;
  color: var(--paper);
  line-height: 1;
  padding-top: 1px;
}
.founder__portrait img {
  position: relative;
  z-index: 2;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.founder__byline {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.25rem;
  text-align: left;
}
.founder__name {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 500;
  font-size: 1.125rem;
  letter-spacing: 0.01em;
  color: var(--paper);
  line-height: 1;
}
.founder__name em { font-style: italic; font-weight: 400; }
.founder__role {
  font-family: 'Inter', sans-serif;
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ash);
  line-height: 1;
}

/* Guarantee — Cam's commitment, placed inside the founder chapter
   as his voice rather than a marketing line. Italic, centered,
   weighted like a signed statement. */
.founder__guarantee {
  display: block;
  max-width: 52rem;
  margin: clamp(3rem, 5vw, 5rem) auto 0;
  padding-top: clamp(3rem, 5vw, 5rem);
  border-top: 1px solid var(--rule-2);
}
.founder__guarantee-eyebrow {
  margin-bottom: var(--space-3);
}
.founder__guarantee-text {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-weight: 400;
  font-size: clamp(1.5rem, 2.6vw, 2.25rem);
  line-height: 1.28;
  letter-spacing: -0.014em;
  color: var(--paper);
  margin: 0;
  max-width: 42ch;
  margin-left: auto;
  margin-right: auto;
}

/* ─────────────────────────────────────────────────────────────
   27. Chapter VI — Contact
   Two-column on desktop: editorial intro left, form right.
   The intro is sticky so it holds in view while the form scrolls.
   Form uses hairline-underline inputs — editorial print form, not
   card-style. Routes via Netlify Forms to desk@camcarrollstudio.com.
   ───────────────────────────────────────────────────────────── */
.contact {
  position: relative;
  z-index: 4;
  padding-block: clamp(6rem, 12vw, 14rem);
  background: var(--ink);
  border-top: 1px solid var(--rule);
}
.contact__inner {
  max-width: 88rem;
  margin: 0 auto;
  padding: 0 var(--gutter);
}
.contact__layout {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(3rem, 6vw, 6rem);
}
@media (min-width: 900px) {
  .contact__layout {
    grid-template-columns: 1fr 1fr;
    gap: clamp(4rem, 8vw, 8rem);
    align-items: start;
  }
}
.contact__intro {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}
@media (min-width: 900px) {
  .contact__intro {
    position: sticky;
    top: 100px;
  }
}
.contact__eyebrow {
  margin-bottom: var(--space-3);
}
.contact__title {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 400;
  font-size: clamp(2.5rem, 5vw, 5rem);
  line-height: 1.02;
  letter-spacing: -0.022em;
  color: var(--paper);
  margin: 0;
}
.contact__title em { font-style: italic; }
.contact__lead {
  font-family: 'Inter', sans-serif;
  font-size: clamp(1rem, 1.05vw, 1.125rem);
  line-height: 1.62;
  color: var(--paper-3);
  letter-spacing: -0.003em;
  margin: 0;
  max-width: 32rem;
}
.contact__direct {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--rule);
}
.contact__direct-label {
  font-family: 'Inter', sans-serif;
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ash);
  line-height: 1;
}
.contact__direct-link {
  position: relative;
  display: inline-block;
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-size: clamp(1.25rem, 1.6vw, 1.5rem);
  line-height: 1.2;
  letter-spacing: -0.01em;
  color: var(--paper);
  text-decoration: none;
  padding-bottom: 4px;
  width: fit-content;
}
.contact__direct-link::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: currentColor;
  transform-origin: left center;
  transform: scaleX(0.18);
  opacity: 0.5;
  transition:
    transform var(--dur-base) var(--ease-house),
    opacity   var(--dur-base) var(--ease-house);
}
.contact__direct-link:hover::after,
.contact__direct-link:focus-visible::after {
  transform: scaleX(1);
  opacity: 1;
}

/* ─── 28. Contact form — editorial hairline inputs ─── */
.contact-form {
  display: grid;
  gap: var(--space-4);
}
.contact-form__row {
  display: grid;
  gap: var(--space-4);
}
.contact-form__row--two {
  grid-template-columns: 1fr;
}
@media (min-width: 640px) {
  .contact-form__row--two { grid-template-columns: 1fr 1fr; }
}
.contact-form__field {
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
  position: relative;
}
.contact-form__label {
  font-family: 'Inter', sans-serif;
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ash);
  line-height: 1;
  transition: color var(--dur-fast) var(--ease-micro);
}
.contact-form__field:focus-within .contact-form__label {
  color: var(--paper-3);
}
.contact-form__input,
.contact-form__textarea,
.contact-form__select {
  appearance: none;
  -webkit-appearance: none;
  width: 100%;
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--rule-2);
  padding: 0.75rem 0;
  color: var(--paper);
  font-family: 'Inter', sans-serif;
  font-size: 16px;        /* 16px prevents iOS from zooming on focus */
  line-height: 1.4;
  letter-spacing: -0.005em;
  border-radius: 0;
  outline: none;
  transition: border-color var(--dur-base) var(--ease-house);
}
.contact-form__input:focus,
.contact-form__textarea:focus,
.contact-form__select:focus {
  border-bottom-color: var(--paper);
}
.contact-form__input::placeholder,
.contact-form__textarea::placeholder {
  color: var(--ash-2);
}
.contact-form__textarea {
  resize: vertical;
  min-height: 7rem;
}
.contact-form__select {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14' fill='none'><path d='M2 5l5 5 5-5' stroke='%238A8479' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-position: right 2px center;
  background-repeat: no-repeat;
  background-size: 14px;
  padding-right: 1.5rem;
  cursor: pointer;
}
.contact-form__select option {
  background: var(--ink-2);
  color: var(--paper);
  font-size: 14px;
}
/* Honeypot — visually hidden, accessibility-hidden, off-screen.
   Bots that fill all fields trip this and Netlify discards the submission. */
.contact-form__honeypot {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}
.contact-form__submit {
  position: relative;
  display: inline-flex;
  align-items: baseline;
  gap: 0.85rem;
  margin-top: var(--space-3);
  padding: 0.5rem 0;
  background: transparent;
  border: 0;
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 400;
  font-size: clamp(1.75rem, 2.6vw, 2.25rem);
  line-height: 1;
  letter-spacing: -0.014em;
  color: var(--paper);
  cursor: pointer;
  width: fit-content;
}
.contact-form__submit::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: currentColor;
  transform-origin: left center;
  transform: scaleX(0.12);
  opacity: 0.5;
  transition:
    transform var(--dur-base) var(--ease-house),
    opacity   var(--dur-base) var(--ease-house);
}
.contact-form__submit:hover::after,
.contact-form__submit:focus-visible::after {
  transform: scaleX(1);
  opacity: 1;
}
.contact-form__submit-arrow {
  font-style: italic;
  display: inline-block;
  transition: transform var(--dur-base) var(--ease-house);
}
.contact-form__submit:hover .contact-form__submit-arrow {
  transform: translateX(8px);
}
.contact-form__note {
  font-family: 'Inter', sans-serif;
  font-size: 11.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ash);
  margin: var(--space-3) 0 0 0;
}


/* ═════════════════════════════════════════════════════════════════
   SESSION 5 — THE STANDALONE PAGES
   /work · /about · /thank-you · OG share card · footer
   Plus the home-page recognition + selected-clients moves.
   Every page shares the same chrome (atmosphere, sticky header,
   custom cursor, footer) so navigating between them is continuous.
   ═════════════════════════════════════════════════════════════════ */

/* ─────────────────────────────────────────────────────────────
   29. /work — Sierra Auto Group standalone case study
   Hero · meta grid · essay · V-to-H scrubber · specs · next-step
   ───────────────────────────────────────────────────────────── */

/* 29a. Hero — Sierra title + subtitle + meta grid */
.work-hero {
  position: relative;
  z-index: 4;
  min-height: 100vh;
  display: grid;
  grid-template-rows: auto 1fr auto;
  padding: clamp(7rem, 12vw, 12rem) var(--gutter) clamp(3rem, 5vw, 5rem);
}
.work-hero__top {
  margin-bottom: var(--space-5);
}
.work-hero__center {
  display: flex;
  flex-direction: column;
  justify-content: center;
  max-width: 64rem;
}
.work-hero__eyebrow { color: var(--ash); }
.work-hero__title {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 400;
  font-size: clamp(3rem, 9vw, 10rem);
  line-height: 0.98;
  letter-spacing: -0.024em;
  color: var(--paper);
  margin: var(--space-3) 0 0 0;
}
.work-hero__title em { font-style: italic; }
.work-hero__sub {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-size: clamp(1.25rem, 2vw, 1.875rem);
  line-height: 1.3;
  color: var(--paper-3);
  margin: var(--space-4) 0 0 0;
  max-width: 42ch;
}

.work-hero__meta {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-4) clamp(1.5rem, 3vw, 3rem);
  padding-top: clamp(2.5rem, 4vw, 4rem);
  margin-top: clamp(3rem, 5vw, 5rem);
  border-top: 1px solid var(--rule-2);
}
@media (min-width: 720px) {
  .work-hero__meta { grid-template-columns: repeat(4, 1fr); }
}
.work-hero__meta-item {
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
}
.work-hero__meta-label {
  font-family: 'Inter', sans-serif;
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ash);
  line-height: 1;
}
.work-hero__meta-value {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 400;
  font-size: clamp(1rem, 1.2vw, 1.25rem);
  line-height: 1.3;
  color: var(--paper);
}
.work-hero__meta-value em { font-style: italic; }
.work-hero__meta-link {
  color: var(--paper);
  text-decoration: none;
  border-bottom: 1px solid var(--rule-3);
  transition: border-color var(--dur-fast) var(--ease-micro);
}
.work-hero__meta-link:hover { border-bottom-color: var(--paper); }

/* 29b. Essay — the story of what was built */
.work-essay {
  position: relative;
  z-index: 4;
  padding-block: clamp(5rem, 10vw, 12rem);
  background: var(--ink);
}
.work-essay__inner {
  max-width: 56rem;
  margin: 0 auto;
  padding: 0 var(--gutter);
  display: flex;
  flex-direction: column;
  gap: clamp(2rem, 4vw, 4rem);
}
.work-essay__lead {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 400;
  font-size: clamp(1.75rem, 3.2vw, 2.875rem);
  line-height: 1.2;
  letter-spacing: -0.016em;
  color: var(--paper);
  margin: 0;
}
.work-essay__lead em { font-style: italic; }
.work-essay__body {
  font-family: 'Inter', sans-serif;
  font-size: clamp(1rem, 1.05vw, 1.125rem);
  line-height: 1.72;
  color: var(--paper-3);
  letter-spacing: -0.003em;
  margin: 0;
}
.work-essay__body strong { color: var(--paper); font-weight: 500; }
.work-essay__body em {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  color: var(--paper);
}

/* 29c. V-to-H scrubber — vertical scroll drives horizontal pan
   through a row of panels. Locomotive's signature trick.
   The outer .scrubber is tall (600vh by default). Inside, .scrubber__viewport
   is position: sticky and holds the horizontal track. JS sets two CSS vars:
   --scrub-progress (0→1 over the tall section's scroll) and
   --scrub-distance (the pixel travel needed = trackWidth - viewportWidth).
   CSS does: transform: translateX(progress * -distance). */
.scrubber {
  position: relative;
  height: 600vh;
  background: var(--ink);
  z-index: 4;
  border-top: 1px solid var(--rule);
  /* iOS Safari fix: explicit pan-y so the browser knows vertical scroll
     should be captured by the page, never a horizontal swipe gesture.
     Without this, iOS can sometimes "eat" the scroll and the sticky
     viewport doesn't update, freezing the horizontal pan. */
  touch-action: pan-y;
}
.scrubber__viewport {
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
.scrubber__title {
  flex: 0 0 auto;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  padding: clamp(1.5rem, 3vh, 2.5rem) var(--gutter) var(--space-4);
}
.scrubber__title-label {
  color: var(--ash);
}
.scrubber__title-count {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-size: clamp(1rem, 1.4vw, 1.25rem);
  color: var(--paper);
  font-feature-settings: "lnum" 1;
}
.scrubber__stage {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  overflow: hidden;
  padding-bottom: var(--space-4);
}
.scrubber__track {
  display: flex;
  gap: clamp(1.5rem, 3vw, 3rem);
  padding: 0 var(--gutter);
  height: 100%;
  align-items: stretch;
  will-change: transform;
  transform: translate3d(calc(var(--scrub-progress, 0) * var(--scrub-distance, 0px) * -1), 0, 0);
}
.scrubber__panel {
  flex: 0 0 auto;
  width: clamp(280px, 60vw, 1100px);
  height: 100%;
  background: var(--ink-2);
  border: 1px solid var(--rule-2);
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
.scrubber__panel-media {
  position: relative;
  flex: 1 1 auto;
  overflow: hidden;
  background:
    radial-gradient(ellipse at 30% 40%, rgba(241,236,227,0.05), transparent 60%),
    radial-gradient(ellipse at 70% 70%, rgba(241,236,227,0.03), transparent 65%),
    linear-gradient(135deg, var(--ink-3) 0%, var(--ink) 80%);
}
.scrubber__panel-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Scrolling-window effect: as the panel pans through viewport center,
     JS sets --panel-active (0 → 1 → 0). object-position-y traces from 0%
     (top of full-page screenshot visible) to 100% (bottom visible), so
     each panel reveals the ENTIRE page content as it passes the center.
     Apple's iPhone product gallery + Stripe Press case-studies both
     use a version of this. */
  object-position: 0% calc(var(--panel-active, 0) * 100%);
  display: block;
  transition: object-position 120ms linear;
  will-change: object-position;
}
@media (prefers-reduced-motion: reduce) {
  .scrubber__panel-media img {
    object-position: 0% 0%;
    transition: none;
  }
}
.scrubber__panel-meta {
  flex: 0 0 auto;
  padding: clamp(1rem, 1.5vw, 1.5rem);
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--space-3);
  border-top: 1px solid var(--rule);
  background: rgba(10, 10, 12, 0.6);
  backdrop-filter: blur(20px);
}
.scrubber__panel-title {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-size: clamp(1rem, 1.3vw, 1.25rem);
  color: var(--paper);
  margin: 0;
}
.scrubber__panel-label {
  font-family: 'Inter', sans-serif;
  font-size: 10px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ash);
}
.scrubber__hint {
  position: absolute;
  left: 0;
  right: 0;
  bottom: clamp(0.75rem, 1.5vh, 1.5rem);
  text-align: center;
  font-family: 'Inter', sans-serif;
  font-size: 10px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ash);
  opacity: calc(1 - var(--scrub-progress, 0) * 2);
  pointer-events: none;
  transition: opacity 200ms linear;
}
@media (prefers-reduced-motion: reduce) {
  /* Reduced motion: collapse the scrubber to a normal-height section
     and stack panels vertically. No scroll-tied transform. */
  .scrubber { height: auto; }
  .scrubber__viewport { position: relative; height: auto; }
  .scrubber__stage { padding: var(--space-4); }
  .scrubber__track {
    transform: none;
    flex-direction: column;
    height: auto;
    gap: var(--space-3);
  }
  .scrubber__panel { width: 100%; height: 70vh; }
  .scrubber__hint { display: none; }
}

/* 29d. Specs — results / numbers row */
.work-specs {
  position: relative;
  z-index: 4;
  padding-block: clamp(5rem, 10vw, 12rem);
  background: var(--ink);
  border-top: 1px solid var(--rule);
}
.work-specs__inner {
  max-width: 88rem;
  margin: 0 auto;
  padding: 0 var(--gutter);
}
.work-specs__header {
  margin-bottom: clamp(3rem, 5vw, 5rem);
}
.work-specs__title {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 400;
  font-size: clamp(2rem, 4vw, 3.5rem);
  line-height: 1.05;
  letter-spacing: -0.018em;
  color: var(--paper);
  margin: var(--space-3) 0 0 0;
}
.work-specs__title em { font-style: italic; }
.work-specs__grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0;
}
@media (min-width: 900px) {
  .work-specs__grid { grid-template-columns: repeat(4, 1fr); }
}
.work-specs__item {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: clamp(2rem, 3vw, 3rem) clamp(1rem, 2vw, 2rem);
  border-top: 1px solid var(--rule-2);
}
@media (min-width: 900px) {
  .work-specs__item + .work-specs__item {
    border-left: 1px solid var(--rule-2);
  }
}
.work-specs__number {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 400;
  font-size: clamp(3rem, 6vw, 5.5rem);
  line-height: 1;
  letter-spacing: -0.022em;
  color: var(--paper);
  font-feature-settings: "lnum" 1, "tnum" 1;
}
.work-specs__number em { font-style: italic; }
.work-specs__label {
  font-family: 'Inter', sans-serif;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ash);
  line-height: 1.4;
  margin-top: var(--space-1);
}

/* 29e. Next step — bottom of /work */
.work-next {
  position: relative;
  z-index: 4;
  padding-block: clamp(5rem, 10vw, 12rem);
  text-align: center;
  border-top: 1px solid var(--rule);
}
.work-next__eyebrow { margin-bottom: var(--space-4); }
.work-next__title {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 400;
  font-size: clamp(2rem, 4vw, 3.5rem);
  line-height: 1.06;
  letter-spacing: -0.018em;
  color: var(--paper);
  margin: 0 0 var(--space-5) 0;
}
.work-next__title em { font-style: italic; }


/* ─────────────────────────────────────────────────────────────
   30. /about — founder destination
   Hero with portrait · three-act essay · what I work on/don't · signature
   ───────────────────────────────────────────────────────────── */
.about-hero {
  position: relative;
  z-index: 4;
  padding: clamp(8rem, 14vw, 14rem) var(--gutter) clamp(4rem, 8vw, 8rem);
  background: var(--ink);
}
.about-hero__inner {
  max-width: 88rem;
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(3rem, 6vw, 6rem);
  align-items: end;
}
@media (min-width: 900px) {
  .about-hero__inner {
    grid-template-columns: 1fr 1.3fr;
    gap: clamp(4rem, 7vw, 7rem);
  }
}

/* Portrait container — currently shows a Cormorant "C" monogram.
   Swaps to real photo when an <img> child is added. */
.about-portrait {
  position: relative;
  aspect-ratio: 4 / 5;
  width: 100%;
  max-width: 32rem;
  background:
    radial-gradient(ellipse at 30% 30%, var(--ink-4), var(--ink-2) 80%);
  border: 1px solid var(--rule-3);
  overflow: hidden;
}
.about-portrait::after {
  content: "C";
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-weight: 400;
  font-size: clamp(8rem, 16vw, 16rem);
  color: var(--paper);
  opacity: 0.32;
  line-height: 1;
  padding-bottom: 1rem;
}
.about-portrait img {
  position: relative;
  z-index: 2;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.about-portrait__caption {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 3;
  padding: var(--space-3);
  display: flex;
  justify-content: space-between;
  gap: var(--space-2);
  background: linear-gradient(180deg, transparent, rgba(10,10,12, 0.7));
}
.about-portrait__caption span {
  font-family: 'Inter', sans-serif;
  font-size: 10px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--paper-3);
}

.about-hero__title-block {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.about-hero__eyebrow { margin-bottom: var(--space-2); }
.about-hero__title {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 400;
  font-size: clamp(3rem, 8vw, 8rem);
  line-height: 0.98;
  letter-spacing: -0.024em;
  color: var(--paper);
  margin: 0;
}
.about-hero__title em { font-style: italic; }
.about-hero__lead {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-weight: 400;
  font-size: clamp(1.25rem, 2vw, 1.75rem);
  line-height: 1.35;
  color: var(--paper-3);
  margin: var(--space-3) 0 0 0;
  max-width: 42ch;
}

.about-essay {
  padding-block: clamp(5rem, 10vw, 12rem);
  background: var(--ink);
}
.about-essay__inner {
  max-width: 64rem;
  margin: 0 auto;
  padding: 0 var(--gutter);
}
.about-essay__act {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-3);
  padding-block: clamp(3rem, 5vw, 5rem);
  border-top: 1px solid var(--rule-2);
}
@media (min-width: 900px) {
  .about-essay__act {
    grid-template-columns: 5rem 1fr;
    gap: clamp(2rem, 4vw, 4rem);
    align-items: baseline;
  }
}
.about-essay__act:last-child { border-bottom: 1px solid var(--rule-2); }
.about-essay__numeral {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-weight: 400;
  font-size: clamp(2.5rem, 4.5vw, 4rem);
  line-height: 1;
  color: var(--paper);
}
.about-essay__act-body {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.about-essay__act-eyebrow { color: var(--ash); }
.about-essay__act-title {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 400;
  font-size: clamp(1.875rem, 3.5vw, 3rem);
  line-height: 1.08;
  letter-spacing: -0.018em;
  color: var(--paper);
  margin: 0;
}
.about-essay__act-title em { font-style: italic; }
.about-essay__act-prose {
  font-family: 'Inter', sans-serif;
  font-size: clamp(1rem, 1.05vw, 1.125rem);
  line-height: 1.72;
  color: var(--paper-3);
  margin: 0;
  max-width: 38rem;
}
.about-essay__act-prose strong { color: var(--paper); font-weight: 500; }
.about-essay__act-prose em {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  color: var(--paper);
}

.about-lists {
  padding-block: clamp(5rem, 10vw, 12rem);
  background: var(--ink);
}
.about-lists__inner {
  max-width: 88rem;
  margin: 0 auto;
  padding: 0 var(--gutter);
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(3rem, 5vw, 5rem);
}
@media (min-width: 900px) {
  .about-lists__inner {
    grid-template-columns: 1fr 1fr;
    gap: clamp(4rem, 8vw, 8rem);
  }
}
.about-lists__col { display: flex; flex-direction: column; gap: var(--space-3); }
.about-lists__title {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 400;
  font-size: clamp(1.875rem, 3vw, 2.5rem);
  line-height: 1.1;
  letter-spacing: -0.014em;
  color: var(--paper);
  margin: 0 0 var(--space-2) 0;
}
.about-lists__title em { font-style: italic; }
.about-lists__items {
  list-style: none;
  margin: 0;
  padding: 0;
}
.about-lists__item {
  font-family: 'Inter', sans-serif;
  font-size: clamp(0.9375rem, 1vw, 1.0625rem);
  line-height: 1.5;
  color: var(--paper-3);
  padding: var(--space-2) 0;
  border-top: 1px solid var(--rule);
}
.about-lists__item:last-child { border-bottom: 1px solid var(--rule); }
.about-lists__item em {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  color: var(--paper);
}

/* About signature — italic "Cam Carroll" mark at the end of /about.
   When a real handwritten signature SVG drops in, swap the text for
   the SVG and keep the caption below. */
.about-signature {
  padding-block: clamp(5rem, 10vw, 12rem);
  text-align: center;
}
.about-signature__inner { max-width: 56rem; margin: 0 auto; }
.about-signature__mark {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-weight: 400;
  font-size: clamp(3rem, 6vw, 5rem);
  line-height: 1;
  letter-spacing: -0.024em;
  color: var(--paper);
  margin: 0;
}
.about-signature__caption {
  font-family: 'Inter', sans-serif;
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ash);
  margin: var(--space-4) 0 0 0;
}


/* ─────────────────────────────────────────────────────────────
   31. /thank-you — quiet confirmation moment
   ───────────────────────────────────────────────────────────── */
.thank-you {
  position: relative;
  z-index: 4;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(8rem, 14vw, 12rem) var(--gutter) clamp(4rem, 8vw, 8rem);
  text-align: center;
}
.thank-you__inner { max-width: 56rem; }
.thank-you__eyebrow { margin-bottom: var(--space-4); }
.thank-you__title {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-weight: 400;
  font-size: clamp(3.5rem, 10vw, 10rem);
  line-height: 0.98;
  letter-spacing: -0.024em;
  color: var(--paper);
  margin: 0 0 var(--space-5) 0;
}
.thank-you__body {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 400;
  font-size: clamp(1.25rem, 2vw, 1.75rem);
  line-height: 1.42;
  color: var(--paper-3);
  margin: 0 auto var(--space-5);
  max-width: 36ch;
}
.thank-you__body em {
  font-style: italic;
  color: var(--paper);
}
.thank-you__signature {
  display: inline-block;
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-size: clamp(1.25rem, 1.6vw, 1.5rem);
  color: var(--paper);
  margin: var(--space-5) 0 var(--space-6);
}
.thank-you__detail {
  font-family: 'Inter', sans-serif;
  font-size: 10.5px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ash);
  margin: var(--space-3) 0 var(--space-6);
}
.thank-you__back {
  display: inline-flex;
  align-items: baseline;
  gap: 0.6rem;
  font-family: 'Inter', sans-serif;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--paper-3);
  text-decoration: none;
  padding-bottom: 4px;
  position: relative;
}
.thank-you__back::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: currentColor;
  transform-origin: left center;
  transform: scaleX(0.2);
  opacity: 0.5;
  transition: transform var(--dur-base) var(--ease-house), opacity var(--dur-base) var(--ease-house);
}
.thank-you__back:hover::after { transform: scaleX(1); opacity: 1; }


/* ─────────────────────────────────────────────────────────────
   32. Editorial site footer (every page except /og-card)
   ───────────────────────────────────────────────────────────── */
.site-footer {
  position: relative;
  z-index: 4;
  padding: clamp(4rem, 7vw, 6rem) var(--gutter) clamp(2.5rem, 4vw, 3.5rem);
  border-top: 1px solid var(--rule);
  background: var(--ink);
}
.site-footer__inner {
  max-width: 88rem;
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(3rem, 5vw, 4rem);
}
@media (min-width: 720px) {
  .site-footer__inner {
    grid-template-columns: 2fr 1fr 1fr 1fr;
    gap: clamp(2rem, 4vw, 4rem);
    align-items: start;
  }
}
.site-footer__brand { display: flex; flex-direction: column; gap: var(--space-2); }
.site-footer__wordmark {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 500;
  font-size: clamp(1.5rem, 2vw, 1.875rem);
  letter-spacing: 0.02em;
  color: var(--paper);
  line-height: 1.1;
  text-decoration: none;
}
.site-footer__wordmark em { font-style: italic; font-weight: 400; }
.site-footer__tagline {
  font-family: 'Inter', sans-serif;
  font-size: 11px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ash);
  line-height: 1.4;
  max-width: 28rem;
}
.site-footer__col { display: flex; flex-direction: column; gap: var(--space-2); }
.site-footer__label {
  font-family: 'Inter', sans-serif;
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ash);
  line-height: 1;
  margin-bottom: 0.4rem;
}
.site-footer__link {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 400;
  font-size: clamp(1rem, 1.2vw, 1.125rem);
  line-height: 1.5;
  color: var(--paper);
  text-decoration: none;
  position: relative;
  width: fit-content;
}
.site-footer__link::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -2px;
  height: 1px;
  background: currentColor;
  transform-origin: left center;
  transform: scaleX(0);
  opacity: 0.5;
  transition: transform var(--dur-base) var(--ease-house), opacity var(--dur-base) var(--ease-house);
}
.site-footer__link:hover::after { transform: scaleX(1); opacity: 1; }
.site-footer__link em {
  font-style: italic;
}
.site-footer__bottom {
  max-width: 88rem;
  margin: clamp(3rem, 5vw, 4rem) auto 0;
  padding-top: clamp(1.5rem, 2.5vw, 2rem);
  border-top: 1px solid var(--rule);
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--space-2);
  font-family: 'Inter', sans-serif;
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ash);
}


/* ─────────────────────────────────────────────────────────────
   33. Home additions — Recognition chip + Selected Clients lineup
   ───────────────────────────────────────────────────────────── */
.recognition {
  position: relative;
  z-index: 4;
  padding-block: clamp(4rem, 7vw, 6rem);
  text-align: center;
  background: var(--ink);
  border-top: 1px solid var(--rule);
}
.recognition__inner {
  max-width: 64rem;
  margin: 0 auto;
  padding: 0 var(--gutter);
}
.recognition__eyebrow { margin-bottom: var(--space-3); }
.recognition__statement {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-weight: 400;
  font-size: clamp(1.25rem, 1.9vw, 1.625rem);
  line-height: 1.4;
  letter-spacing: -0.01em;
  color: var(--paper-3);
  margin: 0;
}
.recognition__statement strong { color: var(--paper); font-weight: 400; font-style: normal; }

.clients {
  position: relative;
  z-index: 4;
  padding-block: clamp(4rem, 7vw, 6rem);
  background: var(--ink);
  border-top: 1px solid var(--rule);
}
.clients__inner {
  max-width: 88rem;
  margin: 0 auto;
  padding: 0 var(--gutter);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-4);
  text-align: center;
}
.clients__label { color: var(--ash); }
.clients__list {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: baseline;
  gap: clamp(1.5rem, 4vw, 4rem);
  list-style: none;
  margin: 0;
  padding: 0;
}
.clients__item {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 400;
  font-size: clamp(1.5rem, 2.4vw, 2rem);
  line-height: 1.2;
  letter-spacing: -0.014em;
  color: var(--paper);
}
.clients__item em {
  font-style: italic;
  color: var(--paper-3);
}


/* ─────────────────────────────────────────────────────────────
   34. OG card — never rendered on the live site, only by render-og.mjs.
   Sized exactly to 1200×630, the platform standard. The Playwright
   script loads /og-card.html at this viewport and screenshots.
   ───────────────────────────────────────────────────────────── */
.og-card {
  box-sizing: border-box;  /* explicit — padding must NOT add to 1200×630 */
  width: 1200px;
  height: 630px;
  position: relative;
  overflow: hidden;
  background:
    radial-gradient(ellipse 100% 80% at 50% 50%, transparent 0%, transparent 50%, rgba(0,0,0, 0.5) 100%),
    linear-gradient(180deg, var(--ink-2) 0%, var(--ink) 80%);
  padding: 64px 80px;
  display: grid;
  grid-template-rows: auto 1fr auto;
}
.og-card::before {
  content: "";
  position: absolute;
  inset: 0;
  opacity: 0.06;
  pointer-events: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='220' height='220'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch' seed='5'/><feColorMatrix values='0 0 0 0 1   0 0 0 0 1   0 0 0 0 1   0 0 0 0.6 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
  background-size: 220px 220px;
}
.og-card__top {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  position: relative;
  z-index: 2;
}
.og-card__wordmark {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 500;
  font-size: 22px;
  letter-spacing: 0.02em;
  color: var(--paper);
}
.og-card__wordmark em { font-style: italic; font-weight: 400; }
.og-card__mark {
  font-family: 'Inter', sans-serif;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ash);
}
.og-card__center {
  display: flex;
  align-items: center;
  position: relative;
  z-index: 2;
}
.og-card__headline {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 400;
  font-size: 90px;
  line-height: 0.98;
  letter-spacing: -0.022em;
  color: var(--paper);
  margin: 0;
  max-width: 18ch;
}
.og-card__headline em { font-style: italic; }
.og-card__bottom {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  position: relative;
  z-index: 2;
}
.og-card__location,
.og-card__url {
  font-family: 'Inter', sans-serif;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ash);
}


/* ─────────────────────────────────────────────────────────────
   35. Index button — circular magnetic CTA on the home.
   Sits between the Cold Open and the studio statement. The signature
   shape of luxury motion studios (Lusion, Active Theory, Resn) —
   a hairline-bordered circle with an italic Cormorant label inside.
   Magnetic attraction makes it lean toward the cursor as you approach.
   ───────────────────────────────────────────────────────────── */
.index-cta {
  position: relative;
  z-index: 4;
  padding: clamp(4rem, 8vw, 7rem) var(--gutter);
  display: flex;
  flex-wrap: wrap;             /* lets the two buttons stack on narrow viewports */
  justify-content: center;
  align-items: center;
  gap: clamp(1.5rem, 3vw, 2.5rem);
  background: var(--ink);
}
.index-button {
  display: inline-flex;
  text-decoration: none;
  color: var(--paper);
  /* The outer <a> is the click target; the inner span is the magnetic
     element that visually leans toward the cursor without moving the
     click target. */
}
.index-button__inner {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  width:  clamp(150px, 14vw, 180px);
  height: clamp(150px, 14vw, 180px);
  border-radius: 999px;
  border: 1px solid var(--rule-3);
  background: linear-gradient(180deg, rgba(241,236,227,0.025), rgba(241,236,227,0));
  text-align: center;
  position: relative;
  transition:
    border-color 480ms var(--ease-house),
    background   480ms var(--ease-house);
}
/* A second invisible ring expands outward on hover — a subtle "halo" that
   makes the button feel alive without being noisy. */
.index-button__inner::after {
  content: "";
  position: absolute;
  inset: -6px;
  border-radius: 999px;
  border: 1px solid var(--paper);
  opacity: 0;
  transform: scale(0.94);
  transition:
    opacity   var(--dur-base) var(--ease-house),
    transform var(--dur-base) var(--ease-house);
  pointer-events: none;
}
.index-button:hover .index-button__inner,
.index-button:focus-visible .index-button__inner {
  border-color: var(--paper);
  background: linear-gradient(180deg, rgba(241,236,227,0.05), rgba(241,236,227,0.01));
}
.index-button:hover .index-button__inner::after,
.index-button:focus-visible .index-button__inner::after {
  opacity: 0.25;
  transform: scale(1);
}
.index-button__eyebrow {
  font-family: 'Inter', sans-serif;
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--ash);
  line-height: 1;
  transition: color var(--dur-base) var(--ease-house);
}
.index-button:hover .index-button__eyebrow,
.index-button:focus-visible .index-button__eyebrow {
  color: var(--paper-3);
}
.index-button__title {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-weight: 400;
  font-size: clamp(1.5rem, 2vw, 1.75rem);
  line-height: 1;
  letter-spacing: -0.014em;
  color: var(--paper);
}
.index-button__arrow {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-size: 1.125rem;
  line-height: 1;
  color: var(--paper);
  display: inline-block;
  transition: transform var(--dur-base) var(--ease-house);
}
.index-button:hover .index-button__arrow,
.index-button:focus-visible .index-button__arrow {
  transform: translateX(6px);
}
@media (prefers-reduced-motion: reduce) {
  .index-button__inner,
  .index-button__inner::after,
  .index-button__eyebrow,
  .index-button__arrow {
    transition: none;
  }
}


/* ═════════════════════════════════════════════════════════════════
   SESSION 6 — THE MAJESTIC PASS
   Page transitions · Preloader · Animated grain · Custom 404 · C.C. mark
   ═════════════════════════════════════════════════════════════════ */

/* ─────────────────────────────────────────────────────────────
   36. Page transitions — cinematic curtain on every nav click
   The page-curtain is a fixed-position overlay that JS animates
   in and out around navigation. Z-index 99999 keeps it above
   everything including the custom cursor.

   On outgoing navigation: curtain dynamically created in JS,
   fades in over 380ms, then window.location is set.
   On incoming page (after navigation): a sessionStorage flag
   triggers an inline <head> script that adds .has-incoming-curtain
   to <html> BEFORE first paint. Critical CSS makes the curtain
   opaque, hiding the page until JS runs and starts the fade-out.
   ───────────────────────────────────────────────────────────── */
/* CINEMATIC PAGE TRANSITIONS (v=80) — vertical curtain sweep

   The curtain is a fixed-position obsidian sheet that animates
   VERTICALLY through the viewport — like a single film frame
   sweeping past. Replaces the previous opacity fade with a
   directional motion that reads as a deliberate cut, not a
   browser navigation.

   Three states drive the choreography:

     default                          (off-screen below)
       transform: translateY(100%)

     .is-sweeping-in / has-incoming-  (covering viewport)
       transform: translateY(0)

     .curtain-rising                  (off-screen above)
       transform: translateY(-100%)

   Outgoing nav (JS-created curtain):
     • Append .page-curtain to body — starts off-screen below
     • Force layout, then add .is-sweeping-in → curtain sweeps UP
     • At 420ms (80% through the 540ms transition), navigate.
       The remaining 120ms of cover happens during the brief
       browser load gap — visitor never sees a flash.

   Incoming nav (after navigation):
     • Critical CSS keeps curtain at translateY(0) on first paint
       because html has .has-incoming-curtain
     • JS adds .curtain-rising → curtain sweeps UP off the top
     • Cleanup at 720ms removes the classes

   The result is a single vertical wipe of obsidian — visually
   continuous from before-click to after-load. Apple/Locomotive
   tier film cut. */
.page-curtain {
  position: fixed;
  inset: 0;
  z-index: 99999;
  background: var(--ink);
  pointer-events: none;
  transform: translate3d(0, 100%, 0);
  transition: transform 540ms cubic-bezier(0.65, 0.05, 0.36, 1);
  will-change: transform;
}

/* Outgoing OR incoming — covering the viewport */
.page-curtain.is-sweeping-in,
html.has-incoming-curtain .page-curtain {
  transform: translate3d(0, 0, 0);
}

/* Risen — sweeps off the top to reveal the new page */
html.has-incoming-curtain.curtain-rising .page-curtain {
  transform: translate3d(0, -100%, 0);
}

@media (prefers-reduced-motion: reduce) {
  /* Reduced motion — fall back to instant opacity transitions,
     no vertical sweep. pageTransitions() also early-exits for
     reduced motion so this path is rarely exercised. */
  .page-curtain {
    transition: opacity 1ms;
    transform: none;
    opacity: 0;
  }
  .page-curtain.is-sweeping-in,
  html.has-incoming-curtain .page-curtain {
    opacity: 1;
    transform: none;
  }
  html.has-incoming-curtain.curtain-rising .page-curtain {
    opacity: 0;
  }
}

/* ─────────────────────────────────────────────────────────────
   37. Preloader — Netflix-tier cinematic intro
   Fires once per session (sessionStorage check). Four phases:
     0   – 1.6s  ENTRY  — hairline grows, glow rises, MMXXVI fades in,
                          wordmark composed letter-by-letter via three
                          word spans that arrive with blur-clear + lift
     1.6 – 2.2s HOLD    — everything composed, glow pulses, stillness
     2.2 – 3.4s ZOOM    — wordmark scales 1 → 80x with progressive blur
                          and opacity fade. Background dissolves to
                          transparent revealing the Cold Open animating
                          in underneath. Visitor "flies through" the type.
     3.6s       CLEANUP — DOM removed, Cold Open continues its reveal
   ───────────────────────────────────────────────────────────── */
.preloader {
  position: fixed;
  /* iOS viewport coverage fix: position:fixed + inset:0 anchors to the
     LAYOUT viewport on iOS, not the visual viewport. When Safari's URL
     bar collapses during the preloader, the bottom of the page becomes
     visible because the fixed element doesn't extend that far.
     Explicit top/left/width/height with 100dvh tracks the dynamic
     viewport — preloader always covers exactly what the visitor sees. */
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;        /* fallback for older browsers */
  height: 100svh;       /* small viewport (URL bar visible) */
  height: 100dvh;       /* dynamic — follows URL bar transitions */
  z-index: 99998;
  background: var(--ink);
  display: grid;
  place-items: center;
  /* Was `pointer-events: none` — that combined with parent gestures was
     causing iOS Safari to drop button taps. The preloader now accepts
     all events directly, and JS attaches a tap-anywhere handler to fire
     enterSite() the moment ANY part of the preloader is tapped after
     the gateway appears. Decorative children (glow, tunnel, portal)
     still have pointer-events: none individually so they don't shadow
     taps from elements above them. */
  pointer-events: auto;
  overflow: hidden;          /* zoom scale(80) extends way beyond viewport */
}

/* ── Lock body scroll while preloader is active ──
   Prevents iOS rubber-band overscroll from exposing the page beneath.
   Modern browsers use :has(), older fall back to the body.preloader-active
   class which JS adds/removes in preloaderRun().

   v=82 BUG FIX: gated the :has() selector by html:not(.preloaded). The
   .preloader element stays in the DOM after dismissal (it's just
   display: none'd via html.preloaded .preloader). Without this gate,
   :has(.preloader) kept matching forever, so body stayed at
   overflow: hidden — which silently broke position: sticky across
   the ENTIRE site. The Sierra scrubber on /work and any future
   sticky element relied on body's overflow being normal post-load.

   CRITICAL: do NOT add `touch-action: none` here. On iOS Safari that
   property at the body level intercepts and blocks ALL child touch
   events — including the Begin button. overflow + overscroll alone
   are sufficient to lock scroll without blocking taps. */
html:not(.preloaded) body:has(.preloader),
body.preloader-active {
  overflow: hidden;
  overscroll-behavior: none;
}
html.preloaded .preloader { display: none; }

/* ──────────────────────────────────────────────────────────────
   63. CINEMATIC SINGLE-PAGE CONTACT FORM (v=84)

   Replaces the previous five-step contact form with a single
   editorial form built on three primitives:

     1. FLOATING LABELS — labels start as large Cormorant italic
        inside each field. On focus or when filled, they translate
        UP and SHRINK into a small-caps Montserrat eyebrow above
        the field. The font transition is delayed by 190ms so
        the typeface swap happens mid-translation, not at start.

     2. HAIRLINE UNDERLINES THAT DRAW OPEN — each field's bottom
        border is a 1px rule-2 line. A pseudo-element draws a
        paper-color line from left to right over the bottom edge
        on focus-within (520ms, ease-cinema). Same "rule drawing
        open" language used by the chapter plate header rules.

     3. CUSTOM CHEVRONS ON SELECTS — native dropdown arrow is
        suppressed; an editorial Cormorant chevron sits at the
        right of each select. Rotates 180° on focus.

   Floating-label detection uses :placeholder-shown for inputs/
   textareas (every visible input gets placeholder=" "), and
   :valid for selects (every required select has an empty
   `disabled selected hidden` default option, so the select is
   :invalid until the user picks something real).

   prefers-reduced-motion: transitions disabled. Form remains
   fully functional, just instant.
   ────────────────────────────────────────────────────────────── */

.contact-form--cinematic {
  display: flex;
  flex-direction: column;
  gap: clamp(2.25rem, 3.6vw, 3rem);
  max-width: 36rem;
  width: 100%;
}

/* Honeypot — visually hidden, accessible to bots */
.contact-form--cinematic .contact-form__honeypot {
  position: absolute !important;
  left: -9999px !important;
  width: 1px;
  height: 1px;
  overflow: hidden;
  visibility: hidden;
  margin: 0;
}

/* ── Field container ────────────────────────────────────────── */
.contact-field {
  position: relative;
  padding-top: 1.6rem;
}

/* The bottom hairline that DRAWS open on focus — sits on top of
   the static border-bottom on the input. */
.contact-field::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  width: 0;
  height: 1px;
  background: var(--paper);
  transition: width 520ms var(--ease-cinema);
  pointer-events: none;
}
.contact-field:focus-within::after {
  width: 100%;
}

/* ── Inputs / select / textarea — transparent, hairline bottom ── */
.contact-field__input,
.contact-field__select,
.contact-field__textarea {
  width: 100%;
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--rule-2);
  outline: none;
  color: var(--paper);
  font-family: 'Inter', sans-serif;
  font-weight: 400;
  font-size: clamp(1rem, 1.1vw, 1.1rem);
  line-height: 1.6;
  padding: 0.6rem 0;
  caret-color: var(--paper);
  border-radius: 0;
  -webkit-font-smoothing: antialiased;
}

.contact-field__textarea {
  resize: vertical;
  min-height: 6rem;
  font-family: 'Inter', sans-serif;
}

/* Remove autofill background-color flash in WebKit / Chrome */
.contact-field__input:-webkit-autofill,
.contact-field__textarea:-webkit-autofill {
  -webkit-text-fill-color: var(--paper);
  -webkit-box-shadow: 0 0 0 1000px var(--ink) inset;
  caret-color: var(--paper);
  transition: background-color 9999s ease-out;
}

/* ── Floating label ─────────────────────────────────────────── */
.contact-field__label {
  position: absolute;
  left: 0;
  top: 2.2rem;
  pointer-events: none;
  font-family: 'Cormorant Garamond', serif;
  font-weight: 500;
  font-style: italic;
  font-size: clamp(1.15rem, 1.3vw, 1.3rem);
  line-height: 1.4;
  color: var(--ash);
  letter-spacing: 0;
  transform-origin: left top;
  transition:
    transform     420ms var(--ease-house),
    font-size     420ms var(--ease-house),
    color         320ms var(--ease-cinema),
    letter-spacing 420ms var(--ease-house);
}

.contact-field__optional {
  font-family: 'Inter', sans-serif;
  font-style: normal;
  font-size: 0.78em;
  font-weight: 400;
  color: var(--ash);
  margin-left: 0.4em;
  letter-spacing: 0;
  text-transform: none;
}

/* FLOATING STATE — triggered when input is focused OR has content
   (i.e. placeholder is not shown). For selects: focused OR :valid. */
.contact-field__input:focus + .contact-field__label,
.contact-field__input:not(:placeholder-shown) + .contact-field__label,
.contact-field__textarea:focus + .contact-field__label,
.contact-field__textarea:not(:placeholder-shown) + .contact-field__label,
.contact-field__select:focus + .contact-field__label,
.contact-field__select:valid + .contact-field__label {
  transform: translateY(-2.1rem);
  font-family: 'Montserrat', sans-serif;
  font-weight: 500;
  font-style: normal;
  font-size: 0.68rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--paper);
}

/* When the label floats, its optional indicator shrinks alongside it */
.contact-field__input:focus + .contact-field__label .contact-field__optional,
.contact-field__input:not(:placeholder-shown) + .contact-field__label .contact-field__optional,
.contact-field__select:focus + .contact-field__label .contact-field__optional,
.contact-field__select:valid + .contact-field__label .contact-field__optional {
  font-family: 'Montserrat', sans-serif;
  font-size: 0.85em;
  letter-spacing: 0.22em;
  text-transform: uppercase;
}

/* ── Select styling ─────────────────────────────────────────── */
.contact-field--select {
  position: relative;
}
.contact-field__select {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  cursor: pointer;
  padding-right: 1.8rem;
}

/* Native option styling — limited to background + color in most
   browsers, but enough to match the brand. */
.contact-field__select option {
  background: var(--ink);
  color: var(--paper);
  font-family: 'Inter', sans-serif;
  padding: 0.5rem;
}
.contact-field__select option:disabled {
  color: var(--ash);
}

/* Editorial chevron — Cormorant italic glyph, rotates on focus */
.contact-field__chevron {
  position: absolute;
  right: 0;
  top: 2.2rem;
  pointer-events: none;
  font-family: 'Cormorant Garamond', serif;
  color: var(--paper);
  font-size: 0.95rem;
  line-height: 1.6;
  transition: transform 320ms var(--ease-house);
}
.contact-field--select:focus-within .contact-field__chevron {
  transform: rotate(180deg);
}

/* ── Footer (submit + reply note) ───────────────────────────── */
.contact-form--cinematic .contact-form__footer {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: clamp(1rem, 1.5vw, 1.5rem);
  margin-top: clamp(0.5rem, 1.5vw, 1.5rem);
}

@media (prefers-reduced-motion: reduce) {
  .contact-field::after,
  .contact-field__label,
  .contact-field__chevron {
    transition: none !important;
  }
}

/* Separate background layer — fades to transparent during zoom phase.
   Solid black on top of .preloader's own background so first paint is
   guaranteed opaque, but JS-controlled fade can dissolve only this layer.
   backdrop-filter creates the cinematic FOCUS PULL during zoom: as the bg
   fades and the page behind becomes visible, the page is initially blurred
   (we're "arriving from a distance"), then comes razor-sharp as the
   filter strength animates to 0. Same effect a film camera does at the
   end of a long zoom. */
.preloader__bg {
  position: absolute;
  inset: 0;
  z-index: 1;
  background: var(--ink);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
}
/* MOBILE: backdrop-filter on a full-screen layer murders iOS GPU and
   makes the preloader glitch/stutter during the zoom phase. The solid
   background already covers the screen — the focus pull is a desktop-
   only flourish. Killing it here is a net visual gain on phones. */
@media (max-width: 767px), (pointer: coarse) {
  .preloader__bg {
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
  }
}

/* Tunnel walls — radial vignette suggesting the curving walls of a vault
   corridor we're flying through. Fades in during the first half of zoom,
   peaks at the midpoint, recedes as we "exit the tunnel" into the page. */
.preloader__tunnel-walls {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  opacity: 0;
  transform: scale(1);
  background: radial-gradient(circle at center,
    transparent 8%,
    rgba(0, 0, 0, 0.20) 40%,
    rgba(0, 0, 0, 0.60) 75%,
    rgba(0, 0, 0, 0.92) 100%);
}

/* Portal — the radial light at the end of the tunnel. Grows from the
   wordmark's center, blooms bright at the midpoint, then expands beyond
   the viewport as we burst through into the page. mix-blend-mode: screen
   makes it visibly "lift" everything underneath without recoloring it. */
.preloader__portal {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 100px;
  height: 100px;
  z-index: 3;
  pointer-events: none;
  opacity: 0;
  transform: translate(-50%, -50%) scale(0);
  border-radius: 50%;
  background: radial-gradient(circle,
    rgba(241, 236, 227, 0.55) 0%,
    rgba(241, 236, 227, 0.22) 28%,
    rgba(241, 236, 227, 0.06) 56%,
    transparent 78%);
  mix-blend-mode: screen;
  filter: blur(14px);
}

/* Ambient glow — radial paper-glow behind the type. Emerges in phase 1,
   pulses slowly during hold, fades out during zoom. */
.preloader__glow {
  position: absolute;
  left: 50%;
  top: 50%;
  width: clamp(600px, 75vw, 1200px);
  height: clamp(400px, 50vh, 800px);
  z-index: 2;
  transform: translate(-50%, -50%) scale(0.9);
  background: radial-gradient(ellipse at center,
    rgba(241, 236, 227, 0.12) 0%,
    rgba(241, 236, 227, 0.04) 35%,
    transparent 65%);
  opacity: 0;
  pointer-events: none;
  animation:
    preloader-glow-in    1.4s cubic-bezier(0.16, 1, 0.3, 1) 300ms forwards,
    preloader-glow-pulse 3.6s ease-in-out 1700ms infinite;
}

.preloader__inner {
  position: relative;
  z-index: 3;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(1rem, 2vh, 1.75rem);
}

/* Hairline — grows from center, horizontal sweep */
.preloader__rule {
  height: 1px;
  width: 0;
  background: var(--paper);
  opacity: 0.4;
  animation: preloader-rule 1000ms cubic-bezier(0.16, 1, 0.3, 1) 100ms forwards;
}

/* MMXXVI — small editorial mark below the rule */
.preloader__mark {
  font-family: 'Inter', sans-serif;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.42em;
  text-transform: uppercase;
  color: var(--ash);
  margin: 0;
  opacity: 0;
  transform: translateY(10px);
  animation: preloader-text-arrive 800ms cubic-bezier(0.16, 1, 0.3, 1) 600ms forwards;
}

/* Wordmark — composed of three .preloader__word spans that arrive
   independently with stagger. The composition IS the moment. */
.preloader__wordmark {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 500;
  font-size: clamp(1.25rem, 1.6vw, 1.5rem);
  letter-spacing: 0.02em;
  color: var(--paper);
  margin: 0;
  display: inline-flex;
  align-items: baseline;
  gap: 0.4em;
  transform-origin: center center;
  /* No `filter` in will-change — the zoom keyframes are blur-free
     (Netflix-style razor-sharp fly-through, not speed-warp blur). */
  will-change: transform, opacity;
}
.preloader__word {
  display: inline-block;
  opacity: 0;
  transform: translateY(14px) scale(0.94);
  filter: blur(8px);
  animation: preloader-word-arrive 700ms cubic-bezier(0.16, 1, 0.3, 1) forwards;
  animation-delay: calc(500ms + var(--i, 0) * 200ms);
}
.preloader__word--italic {
  font-style: italic;
  font-weight: 400;
}

/* ── Entry keyframes ── */
@keyframes preloader-rule {
  to { width: clamp(180px, 22vw, 320px); }
}
@keyframes preloader-text-arrive {
  to { opacity: 1; transform: translateY(0); }
}
@keyframes preloader-word-arrive {
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
    filter: blur(0);
  }
}
@keyframes preloader-glow-in {
  0%   { opacity: 0; transform: translate(-50%, -50%) scale(0.9); }
  100% { opacity: 1; transform: translate(-50%, -50%) scale(1);   }
}
@keyframes preloader-glow-pulse {
  0%, 100% { opacity: 0.75; transform: translate(-50%, -50%) scale(1);    }
  50%      { opacity: 1;    transform: translate(-50%, -50%) scale(1.08); }
}

/* ── ZOOM PHASE — triggered by .is-zooming class added at 2.2s ── */
.preloader.is-zooming .preloader__bg {
  animation: preloader-bg-dissolve 1.4s ease-in forwards;
}
.preloader.is-zooming .preloader__tunnel-walls {
  animation: preloader-tunnel-walls 1.4s ease-in-out forwards;
}
.preloader.is-zooming .preloader__portal {
  animation: preloader-portal 1.4s cubic-bezier(0.6, 0, 0.84, 0.4) forwards;
}
.preloader.is-zooming .preloader__glow {
  animation: preloader-glow-out 800ms ease-out forwards;
}
.preloader.is-zooming .preloader__rule,
.preloader.is-zooming .preloader__mark {
  animation: preloader-secondary-fade 500ms ease-out forwards;
}
.preloader.is-zooming .preloader__wordmark {
  /* Slightly more aggressive ease-in than the old (0.7, 0, 0.84, 0.4)
     so the early scale grows more slowly, then accelerates hard — the
     camera-pulled-into-the-letter feeling. */
  animation: preloader-zoom-into 1.4s cubic-bezier(0.6, 0, 0.84, 0.4) forwards;
}
/* Lock per-word entry — they should hold at fully-arrived state through
   the zoom (the parent wordmark is what scales, not the individual words). */
.preloader.is-zooming .preloader__word {
  animation: none;
  opacity: 1;
  transform: none;
  filter: none;
}

@keyframes preloader-bg-dissolve {
  /* Opacity AND backdrop blur both go to zero — the page behind comes
     into view AND into focus simultaneously. Pure focus pull. */
  0%   {
    opacity: 1;
    backdrop-filter: blur(20px);
    -webkit-backdrop-filter: blur(20px);
  }
  60%  {
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
  }
  100% {
    opacity: 0;
    backdrop-filter: blur(0);
    -webkit-backdrop-filter: blur(0);
  }
}

@keyframes preloader-tunnel-walls {
  /* Vignette fades in during first half (we're entering the tunnel),
     peaks at midpoint (deep inside), recedes during second half (exiting). */
  0%   { opacity: 0;   transform: scale(1);   }
  20%  { opacity: 0.7; transform: scale(1.15); }
  45%  { opacity: 1;   transform: scale(1.6); }
  75%  { opacity: 0.5; transform: scale(2.6); }
  100% { opacity: 0;   transform: scale(4);   }
}

@keyframes preloader-portal {
  /* Light at the end of the tunnel. Starts as a tiny pinpoint behind
     the wordmark, blooms outward, then expands past the viewport edges
     as we burst through into the page. */
  0%   { opacity: 0;   transform: translate(-50%, -50%) scale(0);  }
  18%  { opacity: 0.5; transform: translate(-50%, -50%) scale(2);  }
  45%  { opacity: 1;   transform: translate(-50%, -50%) scale(10); }
  72%  { opacity: 0.7; transform: translate(-50%, -50%) scale(28); }
  100% { opacity: 0;   transform: translate(-50%, -50%) scale(65); }
}
@keyframes preloader-glow-out {
  to { opacity: 0; }
}
@keyframes preloader-secondary-fade {
  to { opacity: 0; }
}
@keyframes preloader-zoom-into {
  /* The signature move — Netflix-style. The wordmark stays razor-sharp
     and fully opaque through 88% of the animation as it accelerates
     into the camera. Only the final 12% fades it out. No blur ever:
     real cinematic zooms (Netflix, Apple Pro launch) don't blur the
     focal element — they keep it solid until it leaves frame.
     The ease-in curve on the parent (cubic-bezier 0.6, 0, 0.84, 0.4)
     handles the visual acceleration; we just plot scale linearly here
     and let easing shape the motion. */
  0%   { transform: scale(1);   opacity: 1; }
  88%  { transform: scale(55);  opacity: 1; }
  100% { transform: scale(100); opacity: 0; }
}

/* ─────────────────────────────────────────────────────────────
   MOBILE PRELOADER — surgical overrides for iOS Safari.

   Why this exists: the desktop preloader uses `filter: blur()` on
   the word entry (.preloader__word) and on the portal disk
   (.preloader__portal). On iOS Safari at DPR 3, animating filter:blur
   on text causes per-frame raster glitches — the words "ghost" or
   "jitter" instead of fading cleanly. The portal's blur(14px) on a
   100px disc growing to scale(65) is an enormous GPU paint that
   stutters the entire compositor.

   Fix: mobile uses zero filter:blur anywhere in the preloader.
   The visual identity is preserved via softer gradient stops on the
   portal/glow and a more elegant opacity+translate word arrival
   (cleaner anyway — blur fade-in on serif text was always slightly
   off on Cormorant's thin strokes).

   The Netflix zoom keyframe is also rescaled for mobile: scale(45)
   instead of scale(100). At 20px base font × 45 = 900px tall text,
   which fills the iPhone viewport (390×844) cleanly. scale(100) on
   mobile DPR 3 means rasterizing 6000px text — iOS quietly drops
   the animation rather than crash. Capping at 45 keeps it cinematic
   AND lets iOS actually paint it.

   DESKTOP RULES STAY EXACTLY AS THEY ARE. Mobile overrides are
   gated to (max-width: 767px) or (pointer: coarse).
   ───────────────────────────────────────────────────────────── */
@keyframes preloader-word-arrive-mobile {
  /* Same visual story as desktop (translate up + fade in), minus
     the filter:blur stage that iOS Safari can't render smoothly. */
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}
@keyframes preloader-zoom-into-mobile {
  /* Mobile Netflix zoom — scale 1 → 28 → 45, opacity holds, then fades.
     translate3d in every keyframe forces GPU compositing on iOS.
     The 82% hold at scale(28) gives the camera-pulled-into-the-letter
     acceleration; final 18% explodes outward + fades. */
  0%   { transform: translate3d(0, 0, 0) scale(1);  opacity: 1; }
  82%  { transform: translate3d(0, 0, 0) scale(28); opacity: 1; }
  100% { transform: translate3d(0, 0, 0) scale(45); opacity: 0; }
}
@media (max-width: 767px), (pointer: coarse) {
  /* Word entry — opacity + translate only (no filter:blur). */
  .preloader__word {
    filter: none;
    transform: translateY(18px) scale(0.96);
    animation: preloader-word-arrive-mobile 720ms cubic-bezier(0.16, 1, 0.3, 1) forwards;
    animation-delay: calc(540ms + var(--i, 0) * 220ms);
    -webkit-backface-visibility: hidden;
    backface-visibility: hidden;
  }
  /* Portal — no filter:blur. Softer gradient stops simulate the
     glow falloff that blur(14px) provided on desktop. Visually
     near-identical, GPU-cheap. */
  .preloader__portal {
    filter: none;
    background: radial-gradient(circle,
      rgba(241, 236, 227, 0.48) 0%,
      rgba(241, 236, 227, 0.20) 22%,
      rgba(241, 236, 227, 0.06) 48%,
      transparent 72%);
  }
  /* Wordmark — force GPU compositing so the Netflix zoom paints
     on the compositor thread instead of the main thread. */
  .preloader__wordmark {
    -webkit-transform: translate3d(0, 0, 0);
    transform: translate3d(0, 0, 0);
    -webkit-backface-visibility: hidden;
    backface-visibility: hidden;
  }
  /* Mobile Netflix zoom — uses the mobile-tuned keyframe above. */
  .preloader.is-zooming .preloader__wordmark {
    animation: preloader-zoom-into-mobile 1.4s cubic-bezier(0.6, 0, 0.84, 0.4) forwards;
  }
  /* Tunnel walls — keep them on mobile (they add depth) but reduce
     the final scale so iOS doesn't have to rasterize an 8x-scaled
     radial gradient that's mostly off-screen anyway. */
  .preloader.is-zooming .preloader__tunnel-walls {
    animation: preloader-tunnel-walls-mobile 1.4s ease-in-out forwards;
  }
}
@keyframes preloader-tunnel-walls-mobile {
  0%   { opacity: 0;   transform: scale(1);   }
  20%  { opacity: 0.6; transform: scale(1.12); }
  45%  { opacity: 0.85; transform: scale(1.5); }
  75%  { opacity: 0.4; transform: scale(2.2); }
  100% { opacity: 0;   transform: scale(3);   }
}

/* Preloader runs its gentle entry animations on ALL devices, even when
   prefers-reduced-motion is set. Reason: iOS Low Power Mode triggers
   reduced-motion automatically, and we don't want users in Low Power
   Mode to see a static preloader — that breaks the brand entirely.
   The entry animations (rule grow, MMXXVI fade, word fade-in stagger,
   glow fade) are gentle fades + slow translates — zero motion-sickness
   risk. Tunnel walls + portal stay disabled on reduced-motion since
   they have dramatic scale + transform.
   Removed entry-animation overrides intentionally. */
@media (prefers-reduced-motion: reduce) {
  .preloader__bg { backdrop-filter: none; -webkit-backdrop-filter: none; }
  .preloader__tunnel-walls,
  .preloader__portal { display: none; }
}

/* ─────────────────────────────────────────────────────────────
   38. Animated film grain — 16fps cadence
   Overrides the body::after grain animation so the texture
   shifts between random positions at film frame rate.
   Static grain reads as texture; animated reads as FILM.
   ───────────────────────────────────────────────────────────── */
body::after {
  animation: ccs-grain-drift 0.5s steps(8) infinite;
}
@keyframes ccs-grain-drift {
  0%   { background-position:   0px   0px; }
  12%  { background-position: -42px  18px; }
  25%  { background-position:  31px -25px; }
  37%  { background-position: -18px  39px; }
  50%  { background-position:  47px  11px; }
  62%  { background-position: -29px -33px; }
  75%  { background-position:  16px  44px; }
  87%  { background-position: -36px  -7px; }
  100% { background-position:   0px   0px; }
}
@media (prefers-reduced-motion: reduce) {
  body::after { animation: none; }
}

/* ─────────────────────────────────────────────────────────────
   39. C.C. typographic mark — the studio's visual signature
   Two italic Cormorant capital C's separated by italic periods.
   The brand voice IS the mark. Used in favicon, founder
   portrait, About signature, OG card.
   ───────────────────────────────────────────────────────────── */
.cc-mark {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-weight: 400;
  line-height: 1;
  letter-spacing: -0.01em;
  color: var(--paper);
  display: inline-block;
}
.cc-mark em {
  /* The "." between Cs renders slightly raised + tracked tight */
  font-style: italic;
  margin: 0 -0.05em 0 -0.02em;
  position: relative;
  top: -0.05em;
  color: var(--paper);
}

/* Founder portrait monogram — replace the lone "C" with "C.C." mark. */
.founder__portrait::after,
.about-portrait::after {
  content: "C" "\2024" "C" "\2024";
  letter-spacing: -0.03em;
}

/* About signature — bigger C.C. paired with full name below. */
.about-signature__mark {
  /* Increase the type variant — see Session 5 §30 for base styles. */
  display: inline-flex;
  align-items: baseline;
  gap: 0.7em;
}
.about-signature__cc {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-weight: 400;
  font-size: 1.4em;
  line-height: 1;
  color: var(--paper);
  letter-spacing: -0.02em;
}


/* ─────────────────────────────────────────────────────────────
   40. Custom 404 page — editorial "Not in the catalogue" moment
   Same chrome (sticky header, footer, atmosphere). The 404 itself
   is a centered editorial moment, like the thank-you page but
   with "lost" rather than "received" framing.
   ───────────────────────────────────────────────────────────── */
.err-404 {
  position: relative;
  z-index: 4;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(8rem, 14vw, 12rem) var(--gutter) clamp(4rem, 8vw, 8rem);
  text-align: center;
}
.err-404__inner { max-width: 56rem; }
.err-404__eyebrow {
  display: inline-flex;
  align-items: baseline;
  gap: 0.8rem;
  margin-bottom: var(--space-4);
}
.err-404__code {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-weight: 400;
  font-size: clamp(1.25rem, 1.6vw, 1.5rem);
  letter-spacing: -0.012em;
  color: var(--paper);
  line-height: 1;
}
.err-404__title {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-weight: 400;
  font-size: clamp(3rem, 8vw, 8rem);
  line-height: 1;
  letter-spacing: -0.024em;
  color: var(--paper);
  margin: 0 0 var(--space-5) 0;
}
.err-404__body {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-size: clamp(1.25rem, 1.8vw, 1.625rem);
  line-height: 1.4;
  color: var(--paper-3);
  margin: 0 auto var(--space-6);
  max-width: 38ch;
}
.err-404__body em { font-style: italic; color: var(--paper); }
.err-404__detail {
  font-family: 'Inter', sans-serif;
  font-size: 10.5px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ash);
  margin: var(--space-3) 0 var(--space-6);
}
.err-404__back {
  display: inline-flex;
  align-items: baseline;
  gap: 0.6rem;
  font-family: 'Inter', sans-serif;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--paper-3);
  text-decoration: none;
  padding-bottom: 4px;
  position: relative;
}
.err-404__back::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: currentColor;
  transform-origin: left center;
  transform: scaleX(0.2);
  opacity: 0.5;
  transition: transform var(--dur-base) var(--ease-house), opacity var(--dur-base) var(--ease-house);
}
.err-404__back:hover::after { transform: scaleX(1); opacity: 1; }


/* ═════════════════════════════════════════════════════════════════
   SESSION 7 — THE LIVING SITE
   Cursor-driven parallax · Scroll velocity skew · Ambient breathing
   Cold Open depth gradient · Currently-designing chip · Back-to-top
   Hover-prefetch (JS-only, no CSS counterpart)
   Inspired by Lusion (godly.website curated tier) + Unseen Studio
   ═════════════════════════════════════════════════════════════════ */

/* ─────────────────────────────────────────────────────────────
   41. Ambient breathing — the page is alive
   Body opacity oscillates 1.000 → 0.985 over 8s. Below conscious
   detection threshold. Apple iPad Pro, Vision Pro launch, and Lusion
   homepages all do this. The single highest-value-per-line-of-code
   move on the entire site.
   ───────────────────────────────────────────────────────────── */
@keyframes ccs-ambient-breath {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.985; }
}
@media (prefers-reduced-motion: no-preference) {
  body { animation: ccs-ambient-breath 8s ease-in-out infinite; }
}

/* ─────────────────────────────────────────────────────────────
   42. Cursor-driven micro-parallax on the Cold Open
   JS sets --cursor-x / --cursor-y as the cursor moves across the
   viewport (range: -50px to +50px on each axis). CSS reads these
   and applies translation with a depth multiplier per layer.

   The composition is critical: the .cold-open__center already
   uses --scroll-y for scroll-tied parallax. Cursor parallax
   composes via calc() so both effects coexist without conflict.

   Slow transition (1.4s + 1.6s) on the cursor offsets makes the
   page feel like it has weight and momentum — Apple iPhone hero
   trick. Wordmark and other static elements stay anchored.
   ───────────────────────────────────────────────────────────── */
:root {
  --cursor-x: 0px;
  --cursor-y: 0px;
}
@media (hover: hover) and (pointer: fine) {
  .cold-open__center {
    transform: translate3d(
      calc(var(--cursor-x, 0px) * 0.020),
      calc(var(--scroll-y, 0px) * 0.15 + var(--cursor-y, 0px) * 0.015),
      0
    );
    transition: transform 1.4s cubic-bezier(0.32, 0.72, 0, 1);
  }
  .marquee {
    transform: translate3d(
      calc(var(--cursor-x, 0px) * 0.050),
      calc(var(--cursor-y, 0px) * 0.030),
      0
    );
    transition: transform 1.6s cubic-bezier(0.32, 0.72, 0, 1);
  }
}
@media (prefers-reduced-motion: reduce) {
  .cold-open__center,
  .marquee {
    transform: translate3d(0, var(--scroll-y, 0), 0);
    transition: none;
  }
}

/* ─────────────────────────────────────────────────────────────
   43. Scroll velocity skew
   JS measures scroll velocity each frame, exponentially decays
   toward 0 when scrolling stops. CSS applies the resulting skew
   via custom property to opted-in elements (data-scroll-skew).

   Restricted to specific elements so layout integrity (especially
   sticky positioning inside .pivot, .scrubber) is preserved.
   Active Theory's signature scroll-physics polish.
   ───────────────────────────────────────────────────────────── */
:root { --scroll-skew: 0deg; }
[data-scroll-skew] {
  transform: skewY(var(--scroll-skew, 0deg));
  transform-origin: 50% 0%;
  will-change: transform;
}
[data-scroll-skew].scrub-active {
  /* When other transforms are present (e.g., parallax-driven scroll-y),
     elements opt out of the skew composition via this class. Reserved
     for future use; not currently active anywhere. */
  transform: none;
}
@media (prefers-reduced-motion: reduce) {
  [data-scroll-skew] { transform: none; }
}

/* ─────────────────────────────────────────────────────────────
   44. Cold Open depth gradient
   Subtle layered radial gradients drift over 30s to suggest a
   3D-rendered scene without WebGL. Inspired by Unseen Studio's
   ethereal pink architectural hero, translated into our editorial
   ink/paper palette with a single warm Sierra-gold accent at very
   low alpha. Sits BEHIND content (z-index 0), above the body
   vignette/grain.
   ───────────────────────────────────────────────────────────── */
.cold-open::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(ellipse 50% 70% at 22% 28%, rgba(241, 236, 227, 0.022), transparent 55%),
    radial-gradient(ellipse 40% 55% at 78% 72%, rgba(203, 178, 106, 0.014), transparent 60%);
  background-size: 130% 130%, 140% 140%;
  animation: ccs-cold-open-depth 32s ease-in-out infinite alternate;
}
@keyframes ccs-cold-open-depth {
  0%   { background-position:   0%   0%,  100% 100%; }
  100% { background-position:  35%  35%,   65%  65%; }
}
@media (prefers-reduced-motion: reduce) {
  .cold-open::before { animation: none; }
}

/* ─────────────────────────────────────────────────────────────
   45. "Currently designing" status chip
   Sits below the status pill on the Cold Open top row.
   Editorial humanity signal — proves the studio is active.
   Two-line stack on desktop; hidden under 720px to avoid crowding.
   ───────────────────────────────────────────────────────────── */
.cold-open__top-right {
  flex-direction: column;
  align-items: flex-end;
  gap: clamp(0.5rem, 1vw, 0.75rem) !important;
}
@media (max-width: 720px) {
  .cold-open__top-right {
    flex-direction: row;
    align-items: center;
  }
}
.currently-designing {
  display: none;
  align-items: center;
  gap: 0.55rem;
  font-family: 'Inter', sans-serif;
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ash);
  line-height: 1;
  white-space: nowrap;
}
.currently-designing__dot {
  display: inline-block;
  width: 5px;
  height: 5px;
  border-radius: 999px;
  background: var(--paper-3);
  animation: currently-pulse 3s ease-in-out infinite;
}
.currently-designing__sep {
  color: var(--rule-3);
}
.currently-designing__project {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-weight: 400;
  font-size: 11.5px;
  letter-spacing: -0.005em;
  text-transform: none;
  color: var(--paper-3);
}
@keyframes currently-pulse {
  0%, 100% { opacity: 0.45; }
  50%      { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .currently-designing__dot { animation: none; opacity: 0.7; }
}
@media (min-width: 720px) {
  .currently-designing { display: inline-flex; }
}

/* ─────────────────────────────────────────────────────────────
   46. Back-to-top button — Sierra-style polish
   Fixed bottom-right. Appears after 1000px scroll. Magnetic.
   Hairline circle with italic ↑ inside, slow rotation halo on hover.
   Backdrop blur lets content show through faintly underneath.
   ───────────────────────────────────────────────────────────── */
.back-to-top {
  position: fixed;
  /* iOS Safari bottom URL bar safe-area, same pattern as audio toggle. */
  bottom: max(clamp(1.25rem, 3vh, 2rem), calc(env(safe-area-inset-bottom, 0px) + 0.75rem));
  right: max(clamp(1.25rem, 3vw, 2rem), calc(env(safe-area-inset-right, 0px) + 0.5rem));
  z-index: 60;
  background: transparent;
  border: 0;
  padding: 0;
  cursor: pointer;
  opacity: 0;
  transform: translate3d(0, 14px, 0);
  pointer-events: none;
  transition: opacity 520ms var(--ease-house), transform 520ms var(--ease-house);
}
.back-to-top[data-state="visible"] {
  opacity: 1;
  transform: translate3d(0, 0, 0);
  pointer-events: auto;
}
.back-to-top__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 58px;
  height: 58px;
  border-radius: 999px;
  border: 1px solid var(--rule-3);
  background: rgba(10, 10, 12, 0.55);
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  transition:
    border-color 480ms var(--ease-house),
    background   480ms var(--ease-house);
  position: relative;
}
.back-to-top__inner::after {
  /* Halo ring — same recipe as .index-button. */
  content: "";
  position: absolute;
  inset: -5px;
  border-radius: 999px;
  border: 1px solid var(--paper);
  opacity: 0;
  transform: scale(0.92);
  transition:
    opacity   var(--dur-base) var(--ease-house),
    transform var(--dur-base) var(--ease-house);
  pointer-events: none;
}
.back-to-top:hover .back-to-top__inner,
.back-to-top:focus-visible .back-to-top__inner {
  border-color: var(--paper);
  background: rgba(241, 236, 227, 0.04);
}
.back-to-top:hover .back-to-top__inner::after,
.back-to-top:focus-visible .back-to-top__inner::after {
  opacity: 0.28;
  transform: scale(1);
}
.back-to-top__arrow {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-weight: 500;
  font-size: 1.125rem;
  line-height: 1;
  color: var(--paper);
  display: inline-block;
  transition: transform 480ms var(--ease-house);
}
.back-to-top:hover .back-to-top__arrow {
  transform: translateY(-3px);
}
.back-to-top__label {
  font-family: 'Inter', sans-serif;
  font-size: 8.5px;
  font-weight: 500;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--ash);
  line-height: 1;
  margin-top: 3px;
}
@media (prefers-reduced-motion: reduce) {
  .back-to-top__arrow { transition: none; }
}


/* ═════════════════════════════════════════════════════════════════
   SESSION 8 — THE CINEMA PASS
   Cursor spotlight · Scroll-pinned chapter acts · 3D card tilt
   Canvas particle field on Cold Open
   ═════════════════════════════════════════════════════════════════ */

/* ─────────────────────────────────────────────────────────────
   47. Cursor spotlight — Vercel/Linear-tier ambient light
   Large radial gradient follows the cursor across the viewport.
   mix-blend-mode: screen brightens content underneath without
   recoloring it. Fades in on first mousemove, follows via rAF
   in scripts.js with a soft lerp so the light feels weighted.
   Hidden on touch / coarse-pointer / reduced-motion.
   ───────────────────────────────────────────────────────────── */
.spotlight {
  position: fixed;
  top: 0;
  left: 0;
  width: 820px;
  height: 820px;
  border-radius: 999px;
  /* Above the preloader (99998) so it brightens the preloader's pure
     black bg around the visitor's cursor — guiding the eye to the
     Begin button. Still below the cursor dot/ring (100000) so the
     cursor itself stays crisp on top of the glow. */
  z-index: 99999;
  pointer-events: none;
  background: radial-gradient(
    circle at center,
    rgba(241, 236, 227, 0.20) 0%,
    rgba(241, 236, 227, 0.10) 18%,
    rgba(241, 236, 227, 0.035) 40%,
    rgba(241, 236, 227, 0.012) 60%,
    transparent 75%
  );
  mix-blend-mode: screen;
  /* Position via the modern `translate` property; JS sets this on mousemove.
     Compose with scale + filter below — these can react to audio without
     touching the JS-controlled position. */
  translate: -9999px -9999px;
  /* AUDIO-REACTIVE: scale up subtly on each kick, intensify on bass.
     Falls back to scale(1) when audio is off (vars are 0). */
  scale: calc(1 + var(--audio-kick, 0) * 0.12 + var(--audio-bass, 0) * 0.04);
  /* AUDIO-REACTIVE: brightness GAINS on each kick — spotlight literally
     flashes brighter every 4 seconds with the heartbeat. Cheap GPU op. */
  filter: brightness(calc(1 + var(--audio-kick, 0) * 0.55 + var(--audio-bass, 0) * 0.20));
  opacity: 0;
  transition: opacity 700ms var(--ease-cinema);
  will-change: translate, scale, filter;
}
.spotlight.is-active { opacity: 1; }
@media (hover: none), (pointer: coarse), (prefers-reduced-motion: reduce) {
  .spotlight { display: none !important; }
}

/* ─────────────────────────────────────────────────────────────
   48. Chapter act cards — Apple iPhone Pro signature
   A scroll-pinned moment between chapters. Outer .chapter-act is
   tall (160vh). Inside, .chapter-act__viewport is sticky at top:0
   and holds a massive Cormorant numeral that scales with the
   visitor's scroll position through the section.

   JS sets --act-progress (0 → 1) on .chapter-act based on scroll
   through the section. CSS reads it: numeral grows from scale(0.6)
   → scale(1.0) → scale(0.6), opacity follows a bell curve.

   These cards are EDITORIAL ACT BREAKS — they don't carry content,
   they punctuate the transition between major chapters. Wes Anderson
   "Chapter II" film cards translated to scroll.
   ───────────────────────────────────────────────────────────── */
.chapter-act {
  position: relative;
  z-index: 4;
  /* Increased to 240vh so the cinematic zoom-through has room to breathe.
     Inner sticky viewport covers 100vh; the remaining 140vh is the scroll
     runway during which JS sets --act-opacity and --act-scale. */
  height: 240vh;
  --act-progress: 0;
  --act-opacity: 0;
  --act-scale: 1.4;
  /* Subtle ambient warmth — same recipe as cold-open depth gradient. */
  background:
    radial-gradient(ellipse 60% 80% at 50% 50%, rgba(241, 236, 227, 0.018), transparent 55%),
    var(--ink);
}
.chapter-act__viewport {
  position: sticky;
  top: 0;
  height: 100vh;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.chapter-act__inner {
  position: relative;
  text-align: center;
  /* Opacity + scale set by JS via piecewise zoom-through curve.
     Phase 1: zoom IN  (scale 1.4 → 1.0, opacity 0 → 1) — 0% – 15%
     Phase 2: HOLD     (scale 1.0 → 1.05, opacity 1)    — 15% – 55%
     Phase 3: zoom OUT (scale 1.05 → 2.6, opacity 1→0)  — 55% – 92%
     Phase 4: empty hold                                 — 92% – 100% */
  opacity: var(--act-opacity, 1);
  transform: scale(var(--act-scale, 1));
  will-change: opacity, transform;
}
.chapter-act__numeral {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-weight: 400;
  font-size: clamp(8rem, 28vw, 28rem);
  line-height: 0.85;
  letter-spacing: -0.04em;
  color: var(--paper);
  margin: 0;
  display: block;
}
.chapter-act__title {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-weight: 400;
  font-size: clamp(1.25rem, 2.4vw, 2rem);
  line-height: 1.2;
  letter-spacing: -0.012em;
  color: var(--paper-3);
  margin: clamp(1.25rem, 2vw, 2rem) 0 0 0;
}
.chapter-act__eyebrow {
  font-family: 'Inter', sans-serif;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--ash);
  line-height: 1;
  margin: 0 0 var(--space-3) 0;
}
@media (prefers-reduced-motion: reduce) {
  .chapter-act { height: 70vh; --act-opacity: 1; --act-scale: 1; }
  .chapter-act__viewport { position: relative; height: 70vh; }
  .chapter-act__inner { opacity: 1; transform: none; }
  .chapter-act__numeral { font-size: clamp(6rem, 16vw, 14rem); }
}

/* ─────────────────────────────────────────────────────────────
   49. 3D card tilt on hover — Resn/Active Theory signature
   Each card with .tilt-card establishes a perspective context.
   JS reads cursor position relative to the card, computes rotateX
   + rotateY, applies via CSS variables. Pure transform — no
   position/layout impact. Returns to flat on mouseleave.
   ───────────────────────────────────────────────────────────── */
.tilt-card {
  --tilt-x: 0deg;
  --tilt-y: 0deg;
  transform: perspective(1100px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg));
  transform-style: preserve-3d;
  transition: transform 480ms var(--ease-house);
  will-change: transform;
}
/* While the cursor is INSIDE the card, JS removes the transition for
   immediate response (no lag); when the cursor leaves, the transition
   smoothly returns the card to flat. */
.tilt-card.is-tilting {
  transition: none;
}
@media (hover: none), (pointer: coarse), (prefers-reduced-motion: reduce) {
  .tilt-card {
    transform: none;
    transition: none;
  }
}

/* The .moment cards have other transforms inside them (media-reveal,
   blur enter, Ken-Burns). Those live on CHILD elements, so the
   .tilt-card transform on the parent composes cleanly. */
.moment.tilt-card,
.scrubber__panel.tilt-card {
  /* The transform-origin matters: center-center makes the tilt feel
     like the card is balanced on its center. */
  transform-origin: center center;
}

/* ─────────────────────────────────────────────────────────────
   50. Canvas particle field — the WebGL-without-WebGL wildcard
   A <canvas> element sits inside the Cold Open behind all content.
   JS draws ~70 paper-colored particles drifting with depth-based
   size and opacity, with subtle cursor avoidance. Lusion/Active
   Theory ambient particle feel without any external dependency.
   ───────────────────────────────────────────────────────────── */
/* ── Constellation band — wrapper around cold-open + index-cta + studio-statement.
   Provides the positioning ancestor for the single shared <canvas
   class="particle-field">, letting one canvas + one rAF loop + one
   particle pool span all three sections as a seamless starfield.
   The band ends where the Pivot section begins, creating a natural
   visual stop at Chapter II without any JS-driven scroll gating. */
.constellation-band {
  position: relative;
}
.particle-field {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 5;        /* above sections at z:4 — particles drawn on top of
                        text/buttons exactly as in the original cold-open
                        composition (z:1 above static cold-open children).
                        Canvas pixels are transparent except for particle
                        dots + connection lines, so text reads cleanly. */
  pointer-events: none;
  opacity: 0;
  transition: opacity 1.4s var(--ease-cinema);
}
body.is-loaded .particle-field { opacity: 1; }
/* Note: particles intentionally show in prefers-reduced-motion. iOS Low
   Power Mode triggers reduced-motion automatically; we don't want phones
   in Low Power Mode to lose the constellation atmosphere. The drift is
   gentle (DRIFT_SPEED 0.05) — zero motion-sickness risk. */


/* §51 Vault Hero CSS — REMOVED. The vault hero (Three.js obsidian
   corridor) was deactivated; CSS rules deleted to keep stylesheet lean.
   The vault-hero.js file remains on disk as a dormant module for future
   revival but no markup references it. */


/* ─────────────────────────────────────────────────────────────
   52. Phase 2 — Gateway (Begin button inside preloader)
   The preloader's existing entry phase plays as before; this
   gateway fades in 1.8s after page load, just below the wordmark.
   Visitor clicks Begin → user gesture unlocks audio + triggers
   the Netflix zoom. The hairline divider above the button is a
   subtle nod to a vault door's seam. The ◐ icon rotates on hover.
   ───────────────────────────────────────────────────────────── */
.preloader__gateway {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(0.9rem, 1.6vh, 1.4rem);
  margin-top: clamp(1.5rem, 3vh, 2.5rem);
  opacity: 0;
  transform: translateY(8px);
  /* Delay matches the last word arrival (0.9s + 0.7s entry = 1.6s) */
  animation: preloader-gateway-arrive 900ms cubic-bezier(0.16, 1, 0.3, 1) 1700ms forwards;
}
@keyframes preloader-gateway-arrive {
  to { opacity: 1; transform: translateY(0); }
}

.preloader__divider {
  width: 1px;
  height: clamp(1.25rem, 2.4vh, 2rem);
  background: var(--paper);
  opacity: 0.28;
}

.preloader__begin {
  position: relative;
  background: transparent;
  border: 0;
  cursor: pointer;
  /* .preloader itself has pointer-events: none so visitors can't click
     through-page elements during the intro. The Begin button needs to
     opt BACK IN so the gateway click registers. */
  pointer-events: auto;
  /* iOS tap optimization:
       touch-action: manipulation — kills the 300ms double-tap delay and
         tells Safari "this is a tap target, no panning gestures here"
       -webkit-tap-highlight-color: transparent — no gray flash on tap
       Large minimum tap target — 44×44px Apple HIG minimum. Our padding
       expands the visible button without changing its visual layout. */
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  -webkit-user-select: none;
  user-select: none;
  min-height: 44px;
  min-width: 132px;
  justify-content: center;
  display: inline-flex;
  align-items: baseline;
  gap: 0.55em;
  padding: 0.4em 0.25em;
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-weight: 400;
  font-size: clamp(1.4rem, 2vw, 1.85rem);
  letter-spacing: -0.012em;
  color: var(--paper);
  /* Magnetic CSS variables (set by [data-magnetic] handler) compose
     into the transform — same mechanism as Index/Brief buttons. */
  transform: translate3d(var(--mx, 0), var(--my, 0), 0);
  transition:
    transform 480ms cubic-bezier(0.16, 1, 0.3, 1),
    color     360ms cubic-bezier(0.16, 1, 0.3, 1);
}
.preloader__begin::after {
  /* Hairline underline that animates from short to full on hover */
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0.18em;
  height: 1px;
  background: var(--paper);
  opacity: 0.45;
  transform: scaleX(0.32);
  transform-origin: left center;
  transition:
    transform 620ms cubic-bezier(0.16, 1, 0.3, 1),
    opacity   420ms cubic-bezier(0.16, 1, 0.3, 1);
}
.preloader__begin:hover::after,
.preloader__begin:focus-visible::after {
  transform: scaleX(1);
  opacity: 0.85;
}
.preloader__begin-icon {
  /* The ◐ glyph — half-filled circle suggests a door at the moment of opening */
  display: inline-block;
  font-size: 0.62em;
  opacity: 0.55;
  transform: rotate(0deg);
  transition:
    transform 800ms cubic-bezier(0.16, 1, 0.3, 1),
    opacity   400ms cubic-bezier(0.16, 1, 0.3, 1);
}
.preloader__begin:hover .preloader__begin-icon,
.preloader__begin:focus-visible .preloader__begin-icon {
  transform: rotate(180deg);
  opacity: 1;
}

.preloader__hint {
  font-family: 'Inter', sans-serif;
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--ash);
  margin: 0;
  opacity: 0.85;
}

/* During zoom: the gateway fades out fast (faster than wordmark)
   so visitor sees the button "leaving frame" before the wordmark zoom */
.preloader.is-zooming .preloader__gateway {
  animation: preloader-gateway-leave 380ms ease-out forwards;
}
@keyframes preloader-gateway-leave {
  to { opacity: 0; transform: translateY(-4px); }
}

@media (prefers-reduced-motion: reduce) {
  .preloader__gateway {
    animation: none;
    opacity: 1;
    transform: none;
  }
}


/* ─────────────────────────────────────────────────────────────
   53. Phase 2 — Persistent audio toggle (bottom-left pill)
   Glassmorphic ink pill. Three animated waves when audio is on,
   static dots when off. Visible across every page. Fades in on
   body.is-loaded so the toggle doesn't compete with the preloader.
   ───────────────────────────────────────────────────────────── */
.audio-toggle {
  position: fixed;
  /* iOS Safari renders a bottom URL bar that overlaps the viewport.
     env(safe-area-inset-bottom) accounts for it. Max with the design
     gutter ensures we never undershoot the visual baseline. */
  bottom: max(clamp(1rem, 2.6vh, 1.85rem), calc(env(safe-area-inset-bottom, 0px) + 0.5rem));
  left: max(clamp(1rem, 2.6vw, 1.85rem), calc(env(safe-area-inset-left, 0px) + 0.5rem));
  z-index: 200;
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
  padding: 0.5em 0.95em 0.5em 0.85em;
  background: rgba(241, 236, 227, 0.06);
  backdrop-filter: blur(14px) saturate(120%);
  -webkit-backdrop-filter: blur(14px) saturate(120%);
  border: 1px solid rgba(241, 236, 227, 0.12);
  border-radius: 999px;
  cursor: pointer;
  color: var(--paper);
  opacity: 0;
  transform: translateY(6px);
  transition:
    opacity 700ms cubic-bezier(0.16, 1, 0.3, 1) 400ms,
    transform 700ms cubic-bezier(0.16, 1, 0.3, 1) 400ms,
    background 240ms,
    border-color 240ms;
  /* Always keep an OS cursor hidden so the custom dot is the only cursor */
}
body.is-loaded .audio-toggle {
  opacity: 1;
  transform: translateY(0);
}
.audio-toggle:hover {
  background: rgba(241, 236, 227, 0.11);
  border-color: rgba(241, 236, 227, 0.24);
}

.audio-toggle__waves {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 2px;
  height: 14px;
}
.audio-toggle__wave {
  display: inline-block;
  width: 2px;
  height: 4px;
  background: currentColor;
  border-radius: 2px;
  opacity: 0.55;
  transform-origin: center bottom;
  transition: height 240ms ease, opacity 240ms ease;
}

/* OFF state — three static dim dots */
.audio-toggle[data-state="off"] .audio-toggle__wave {
  height: 4px;
  opacity: 0.4;
  animation: none;
}

/* ON state — three desynced bouncing waves */
.audio-toggle[data-state="on"] .audio-toggle__wave:nth-child(1) {
  animation: audio-toggle-wave 1.4s ease-in-out infinite;
}
.audio-toggle[data-state="on"] .audio-toggle__wave:nth-child(2) {
  animation: audio-toggle-wave 1.7s ease-in-out infinite 0.18s;
}
.audio-toggle[data-state="on"] .audio-toggle__wave:nth-child(3) {
  animation: audio-toggle-wave 1.3s ease-in-out infinite 0.36s;
}
@keyframes audio-toggle-wave {
  0%, 100% { height: 4px;  opacity: 0.55; }
  50%      { height: 12px; opacity: 1; }
}

.audio-toggle__label {
  font-family: 'Inter', sans-serif;
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: currentColor;
  opacity: 0.78;
  line-height: 1;
  transition: opacity 240ms;
}
.audio-toggle:hover .audio-toggle__label { opacity: 1; }

/* Reduced motion: kill the wave animation, keep the toggle itself usable */
@media (prefers-reduced-motion: reduce) {
  .audio-toggle__wave { animation: none !important; }
  .audio-toggle { transition: none; }
}

/* Mobile: shrink the pill but keep it accessible.
   ALSO disable backdrop-filter (expensive on mobile) — replace with
   a slightly more opaque solid ink so the pill still reads visually
   without the GPU cost of blurring the page behind it every frame. */
@media (max-width: 767px), (pointer: coarse) {
  .audio-toggle {
    padding: 0.45em 0.7em;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    background: rgba(10, 10, 12, 0.78);
    border-color: rgba(241, 236, 227, 0.18);
  }
  .audio-toggle__label { display: none; }
}


/* ─────────────────────────────────────────────────────────────
   54. Phase 3 — Studio Archive (3D draggable sphere of cards)
   The /archive page. WebGL canvas fills the viewport behind the
   persistent UI. Top-left eyebrow, bottom-center readout that
   updates with the hovered project, drag hint that fades on first
   interaction, mobile fallback grid for sub-768px viewports.
   ───────────────────────────────────────────────────────────── */
.archive {
  position: relative;
  width: 100%;
  min-height: 100svh;
  overflow: hidden;
  background: var(--ink);
}

/* The WebGL canvas — fills the section behind all overlay UI */
.archive__canvas {
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100svh;
  z-index: 1;
  cursor: grab;
  display: block;
  background: transparent;
}
.archive__canvas.is-grabbing { cursor: grabbing; }
.archive__canvas.is-hovering { cursor: pointer; }
.archive__canvas.is-flying   { cursor: progress; }

/* Hide the canvas-derived cursor when our custom dot cursor is active.
   The grab/grabbing OS cursor would compete with the paper dot. */
body.has-custom-cursor .archive__canvas,
body.has-custom-cursor .archive__canvas.is-grabbing,
body.has-custom-cursor .archive__canvas.is-hovering {
  cursor: none;
}

/* Top-left eyebrow — "A · Studio Archive" */
.archive__eyebrow {
  position: fixed;
  top: clamp(5.5rem, 9vh, 7rem);
  left: clamp(1.5rem, 4vw, 3rem);
  z-index: 6;
  display: inline-flex;
  align-items: baseline;
  gap: 0.6em;
  font-family: 'Inter', sans-serif;
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--ash);
  pointer-events: none;
}
.archive__eyebrow-mark {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-size: 14px;
  letter-spacing: 0;
  color: var(--paper);
  text-transform: none;
}

/* Bottom-center live readout — updates with hovered card */
.archive__readout {
  position: fixed;
  bottom: clamp(3.75rem, 7vh, 5.25rem);
  left: 50%;
  transform: translateX(-50%);
  z-index: 6;
  display: inline-flex;
  align-items: center;
  gap: clamp(0.6rem, 1.2vw, 1rem);
  padding: 0.65rem 1.1rem;
  background: rgba(241, 236, 227, 0.04);
  backdrop-filter: blur(14px) saturate(120%);
  -webkit-backdrop-filter: blur(14px) saturate(120%);
  border: 1px solid rgba(241, 236, 227, 0.10);
  border-radius: 999px;
  font-family: 'Inter', sans-serif;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--paper);
  white-space: nowrap;
  pointer-events: none;
  transition: opacity 360ms var(--ease-cinema);
}
.archive__readout-number,
.archive__readout-industry,
.archive__readout-year {
  opacity: 0.62;
}
.archive__readout-name {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-size: 15px;
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  color: var(--paper);
  opacity: 1;
}
.archive__readout-divider {
  opacity: 0.32;
  color: var(--paper);
}

/* Drag-to-explore hint — visible first time only */
.archive__hint {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 5;
  display: inline-flex;
  align-items: center;
  gap: 0.8em;
  padding: 0.55rem 1.15rem;
  font-family: 'Inter', sans-serif;
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--ash);
  pointer-events: none;
  opacity: 0;
  animation: archive-hint-arrive 800ms cubic-bezier(0.16, 1, 0.3, 1) 2500ms forwards;
}
.archive__hint.is-hidden {
  animation: archive-hint-leave 500ms cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
@keyframes archive-hint-arrive {
  from { opacity: 0; transform: translate(-50%, calc(-50% + 6px)); }
  to   { opacity: 1; transform: translate(-50%, -50%); }
}
@keyframes archive-hint-leave {
  to { opacity: 0; transform: translate(-50%, calc(-50% - 8px)); }
}
.archive__hint-arrow {
  display: inline-block;
  color: var(--paper);
  font-size: 14px;
  letter-spacing: 0;
  opacity: 0.7;
  animation: archive-hint-arrow 2.2s ease-in-out infinite;
}
.archive__hint-arrow--right { animation-direction: reverse; }
@keyframes archive-hint-arrow {
  0%, 100% { transform: translateX(0); }
  50%      { transform: translateX(-4px); }
}

/* Coming-soon pill — appears at clicked card position */
.archive__coming-soon {
  position: fixed;
  z-index: 12;
  padding: 0.45rem 0.95rem;
  background: rgba(10, 10, 12, 0.92);
  backdrop-filter: blur(14px);
  border: 1px solid rgba(203, 178, 106, 0.4);
  border-radius: 999px;
  font-family: 'Inter', sans-serif;
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--gold);
  pointer-events: none;
  opacity: 0;
  transform: translate(-50%, -100%) translateY(8px);
  transition:
    opacity   320ms cubic-bezier(0.16, 1, 0.3, 1),
    transform 360ms cubic-bezier(0.16, 1, 0.3, 1);
}
.archive__coming-soon.is-visible {
  opacity: 1;
  transform: translate(-50%, -100%) translateY(0);
}

/* ── Mobile fallback grid (< 768px or reduced-motion) ── */
.archive__grid {
  display: none;
  margin: 0;
  padding: 0;
}
/* Mobile portrait polish: 3D scene renders fine but UI overlays
   need tighter sizing so they don't crowd the canvas. */
@media (max-width: 767px) {
  .archive__eyebrow {
    top: clamp(4.25rem, 7vh, 5.5rem);
    left: clamp(1rem, 4vw, 1.5rem);
    font-size: 9.5px;
    letter-spacing: 0.28em;
  }
  .archive__readout {
    bottom: clamp(5.5rem, 9vh, 6.5rem);
    padding: 0.5rem 0.85rem;
    font-size: 9.5px;
    letter-spacing: 0.12em;
    gap: 0.4rem;
    flex-wrap: wrap;
    justify-content: center;
    max-width: calc(100vw - 2rem);
  }
  .archive__readout-name { font-size: 13px; }
  /* On very narrow viewports, drop the year + industry tags to keep the
     name + number readable */
  @media (max-width: 480px) {
    .archive__readout-year,
    .archive__readout-divider:nth-of-type(3) { display: none; }
  }
  .archive__hint {
    font-size: 9.5px;
    letter-spacing: 0.28em;
    padding: 0.45rem 0.85rem;
  }
}

/* The static grid only appears as a fallback now if archive.js never
   initialized the 3D scene (no WebGL). Otherwise the 3D scene runs on
   every device including iOS Low Power Mode. */
/* Static-grid fallback ONLY when archive.js could not start the WebGL
   scene (no GL context). JS adds .archive-mobile class on the body in
   that case — same drives the grid-only layout. Most visitors never
   see this; their phones have WebGL. */
body.archive-mobile .archive__canvas,
body.archive-mobile .archive__hint,
body.archive-mobile .archive__readout { display: none; }
body.archive-mobile .archive__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(1rem, 3vw, 1.75rem);
  padding: clamp(7rem, 14vh, 10rem) clamp(1rem, 4vw, 2rem) clamp(5rem, 10vh, 8rem);
  position: relative;
  z-index: 4;
}
@media (min-width: 480px) {
  body.archive-mobile .archive__grid { grid-template-columns: 1fr 1fr; }
}

/* Mobile editorial card — semantic <a> with frame, hero, title, year */
.archive-card {
  display: flex;
  flex-direction: column;
  position: relative;
  padding: clamp(0.85rem, 2.5vw, 1.15rem);
  background: var(--card-bg, #16161B);
  color: var(--card-fg, var(--paper));
  border: 1px solid rgba(241, 236, 227, 0.10);
  border-radius: 2px;
  text-decoration: none;
  overflow: hidden;
  transition:
    transform 540ms cubic-bezier(0.16, 1, 0.3, 1),
    border-color 320ms;
}
.archive-card:hover {
  transform: translateY(-4px);
  border-color: rgba(241, 236, 227, 0.22);
}
.archive-card[aria-disabled="true"] {
  cursor: default;
  pointer-events: none;
}
.archive-card__top {
  display: flex;
  justify-content: space-between;
  font-family: 'Inter', sans-serif;
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  opacity: 0.7;
  margin-bottom: 0.85rem;
}
.archive-card__hero {
  aspect-ratio: 4 / 3;
  background-size: cover;
  background-position: center;
  background-color: var(--card-accent, #2A2A30);
  border-radius: 1px;
  margin-bottom: 0.9rem;
  position: relative;
}
.archive-card__hero::after {
  /* Subtle paper hairline border on the hero */
  content: "";
  position: absolute;
  inset: 0;
  border: 1px solid rgba(241, 236, 227, 0.12);
  border-radius: 1px;
}
.archive-card__title {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-weight: 500;
  font-size: clamp(1.1rem, 4vw, 1.4rem);
  line-height: 1.1;
  margin-bottom: 0.4rem;
}
.archive-card__tagline {
  font-family: 'Inter', sans-serif;
  font-size: 12px;
  line-height: 1.5;
  opacity: 0.72;
  margin-bottom: 1rem;
}
.archive-card__bottom {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: auto;
}
.archive-card__rule {
  display: inline-block;
  width: 36px;
  height: 1px;
  background: var(--card-accent, var(--paper));
  opacity: 0.7;
}
.archive-card__year {
  font-family: 'Inter', sans-serif;
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--card-accent, var(--paper));
}
.archive-card__pill {
  position: absolute;
  top: 1rem;
  right: 1rem;
  padding: 0.32em 0.7em;
  font-family: 'Inter', sans-serif;
  font-size: 9px;
  font-weight: 500;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--card-accent, var(--gold));
  border: 1px solid var(--card-accent, var(--gold));
  border-radius: 999px;
  opacity: 0.85;
}


/* ─────────────────────────────────────────────────────────────
   55. Phase 4 — RGB Chromatic Split Type Transitions
   When a major chapter title scrolls into view, two pseudo-elements
   appear: a red channel shifted right (+10px) and a cyan channel
   shifted left (-10px). Both use mix-blend-mode: screen so they
   add additively over the paper text underneath. Over 380ms they
   converge back to (0,0) and fade to opacity 0 — leaving only
   the clean paper headline visible.

   Why screen blend: red + cyan + paper at same position → bright
   white-ish, which doesn't hurt because the cyan/red opacity drops
   to 0 by the time they converge. The intermediate frames carry the
   "fractured RGB" glitch energy — like a CRT signal stabilizing.

   Trigger: rgbSplit() in scripts.js adds .is-glitched via
   IntersectionObserver when the target enters the viewport.

   Requires: data-text attribute on the element (auto-populated by
   JS from textContent for any element missing it).

   Subtle but pure majestic. Editorial luxury with a hint of glitch
   futurism. Like a Berghain poster — restrained, but uncompromising.
   ───────────────────────────────────────────────────────────── */

.rgb-headline {
  position: relative;
  display: inline-block;
  /* Pseudo-elements are positioned absolute relative to this.
     inline-block keeps the natural text flow but creates a
     bounding box for the pseudos to align to. */
}

.rgb-headline::before,
.rgb-headline::after {
  content: attr(data-text);
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  /* Inherit ALL font properties so the channels match the parent type
     exactly — same family, weight, italic, letter-spacing, line-height. */
  font-family: inherit;
  font-size: inherit;
  font-weight: inherit;
  font-style: inherit;
  letter-spacing: inherit;
  line-height: inherit;
  /* Hidden by default until JS adds .is-glitched */
  opacity: 0;
  /* Screen blend mode so red + cyan + paper layer additively */
  mix-blend-mode: screen;
}

/* Red channel — slightly warm coral red, not pure 100% red */
.rgb-headline::before {
  color: #FF3856;
}

/* Cyan channel — slightly muted teal, not pure 100% cyan */
.rgb-headline::after {
  color: #4AE0DD;
}

/* The chromatic resolve animation — fires when .is-glitched is added.
   Red channel slides from +10px to 0; cyan slides from -10px to 0.
   Both fade opacity from 0.85 to 0. By the end, the parent text
   stands alone — clean, paper-colored, readable. */
.rgb-headline.is-glitched::before {
  animation: rgb-resolve-red 460ms cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
.rgb-headline.is-glitched::after {
  animation: rgb-resolve-cyan 460ms cubic-bezier(0.16, 1, 0.3, 1) forwards;
}

@keyframes rgb-resolve-red {
  0%   { opacity: 0.85; transform: translate3d(11px, 0, 0); }
  30%  { opacity: 0.82; transform: translate3d(8px, 0, 0); }
  60%  { opacity: 0.55; transform: translate3d(3px, 0, 0); }
  85%  { opacity: 0.22; transform: translate3d(1px, 0, 0); }
  100% { opacity: 0;    transform: translate3d(0, 0, 0); }
}
@keyframes rgb-resolve-cyan {
  0%   { opacity: 0.85; transform: translate3d(-11px, 0, 0); }
  30%  { opacity: 0.82; transform: translate3d(-8px, 0, 0); }
  60%  { opacity: 0.55; transform: translate3d(-3px, 0, 0); }
  85%  { opacity: 0.22; transform: translate3d(-1px, 0, 0); }
  100% { opacity: 0;    transform: translate3d(0, 0, 0); }
}

/* Reduced motion: kill the chromatic effect entirely. The clean
   paper headline still reveals via its existing entrance animation. */
@media (prefers-reduced-motion: reduce) {
  .rgb-headline::before,
  .rgb-headline::after { display: none; }
}


/* ─────────────────────────────────────────────────────────────
   56. Mobile performance overrides — disable all GPU-expensive
   filters that run at 60fps on mobile DPR 3 phones. Each blur
   filter (backdrop or drop-shadow) on mobile costs ~9× more
   pixel work than desktop. Replacing with solid translucent
   fills + 1px borders preserves the visual hierarchy without
   the framerate hit. Visitors don't see the "glass" — but they
   feel the silky 60fps. That's the better trade.
   ───────────────────────────────────────────────────────────── */
@media (max-width: 767px), (pointer: coarse) {
  /* Archive readout pill — bottom-center on /archive */
  .archive__readout {
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    background: rgba(10, 10, 12, 0.78);
    border-color: rgba(241, 236, 227, 0.20);
  }
  /* Coming-soon pill — appears at clicked card on /archive */
  .archive__coming-soon {
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    background: rgba(10, 10, 12, 0.95);
  }
  /* Other backdrop-filter consumers that might still be active */
  .preloader__bg {
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
  /* Animated film grain — pure decoration, hide on mobile */
  .grain { display: none; }
}

/* ═════════════════════════════════════════════════════════════════
   58. CINEMATIC STEPPED CONTACT FORM
   ═════════════════════════════════════════════════════════════════
   Five-step intake — each step is one focused moment.

   Visual model: each step takes the full form area; only the active
   step is visible. Transitions are pure transform+opacity (60fps on
   mobile, no layout work). Selected choice cards animate to a paper-
   color border + gold dot. Progress hairline fills from left to right
   as the visitor advances.

   All rules scoped to .contact-form--stepped so the original single-
   screen .contact-form layout would still work if data-stepped-form
   were removed. Doesn't touch anything outside the contact section.
   ═════════════════════════════════════════════════════════════════ */

/* The stepped form gets its own layout container — wider, more cinematic,
   centered. Overrides the original two-column layout for this variant. */
.contact-form--stepped {
  display: block;
  width: 100%;
}

/* ── Progress eyebrow + hairline ── */
.contact-form__progress {
  display: flex;
  flex-direction: column;
  gap: clamp(0.5rem, 1vw, 0.75rem);
  margin-bottom: clamp(2.5rem, 4vw, 4rem);
}
.contact-form__progress-eyebrow {
  font-family: 'Inter', sans-serif;
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--ash);
  margin: 0;
  display: flex;
  align-items: center;
  gap: 0.5em;
}
.contact-form__progress-eyebrow [data-step-current] {
  color: var(--paper);
  font-variant-numeric: tabular-nums;
  display: inline-block;
  min-width: 1ch;
}
.contact-form__progress-sep {
  opacity: 0.45;
}
.contact-form__progress-bar {
  position: relative;
  height: 1px;
  background: var(--rule-2);
  overflow: hidden;
}
.contact-form__progress-fill {
  position: absolute;
  inset: 0;
  background: var(--paper);
  opacity: 0.5;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 600ms var(--ease-cinema);
}

/* ── Steps container — relative positioning anchor for the absolutely
   positioned step panels. min-height keeps the layout stable across
   different step heights so the page doesn't reflow on advance. ── */
.contact-form__steps {
  position: relative;
  min-height: clamp(28rem, 50vh, 36rem);
}

/* Each step is positioned absolutely and faded in/out by translate +
   opacity. Inactive steps stay in the DOM (so all form fields are
   submitted to Netlify) but are visually hidden + non-interactive. */
.contact-form__step {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  gap: clamp(1.25rem, 2vw, 1.75rem);
  margin: 0;
  padding: 0;
  border: 0;
  opacity: 0;
  transform: translate3d(40px, 0, 0);
  pointer-events: none;
  visibility: hidden;
  transition:
    opacity   480ms var(--ease-cinema),
    transform 480ms var(--ease-cinema),
    visibility 0s linear 480ms;
}
.contact-form__step.is-active {
  opacity: 1;
  transform: translate3d(0, 0, 0);
  pointer-events: auto;
  visibility: visible;
  transition:
    opacity   520ms var(--ease-cinema) 80ms,
    transform 520ms var(--ease-cinema) 80ms,
    visibility 0s linear 0ms;
}
/* Reverse direction: when going BACK, slide in from the LEFT. */
.contact-form__step.is-leaving-backward {
  transform: translate3d(-40px, 0, 0);
}
.contact-form__step.is-entering-backward {
  transform: translate3d(-40px, 0, 0);
}

/* ── Step typography ── */
.contact-form__step-eyebrow {
  font-family: 'Inter', sans-serif;
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--gold);
  margin: 0;
  padding: 0;
  /* fieldset legend reset */
  display: block;
  width: 100%;
}
.contact-form__step-question {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 400;
  font-size: clamp(1.875rem, 3.5vw, 3rem);
  line-height: 1.1;
  letter-spacing: -0.018em;
  color: var(--paper);
  margin: 0;
  max-width: 22ch;
}
.contact-form__step-question em { font-style: italic; }
.contact-form__step-sub {
  font-family: 'Inter', sans-serif;
  font-size: clamp(0.875rem, 1vw, 0.9375rem);
  line-height: 1.6;
  color: var(--paper-3);
  margin: 0;
  max-width: 38rem;
}

/* ── Choice cards ──
   Radio-input-driven cards. Each card has a label + detail line.
   Selected state: paper-color border, slight lift, gold dot appears.
   Hover state: subtle paper-tint background.
   The native radio input is visually hidden but kept accessible. */
.contact-form__choices {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(0.5rem, 1vw, 0.75rem);
  margin-top: clamp(1rem, 2vw, 1.5rem);
}
@media (min-width: 720px) {
  .contact-form__choices { grid-template-columns: 1fr 1fr; }
}
.contact-choice {
  position: relative;
  display: block;
  cursor: pointer;
  /* Hide native radio but keep it accessible (off-screen, not display:none) */
}
.contact-choice input[type="radio"] {
  position: absolute;
  opacity: 0;
  pointer-events: none;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
.contact-choice__inner {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  padding: clamp(1rem, 1.6vw, 1.25rem) clamp(1.1rem, 2vw, 1.5rem);
  border: 1px solid var(--rule-2);
  background: rgba(241, 236, 227, 0.012);
  transition:
    border-color 320ms var(--ease-cinema),
    background   320ms var(--ease-cinema),
    transform    320ms var(--ease-cinema);
  position: relative;
}
.contact-choice__label {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 500;
  font-size: clamp(1.1rem, 1.4vw, 1.3125rem);
  line-height: 1.15;
  letter-spacing: -0.01em;
  color: var(--paper);
}
.contact-choice__detail {
  font-family: 'Inter', sans-serif;
  font-size: 11.5px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ash);
  line-height: 1.45;
}
/* Hover: lift + tint */
.contact-choice:hover .contact-choice__inner {
  border-color: var(--rule);
  background: rgba(241, 236, 227, 0.028);
  transform: translateY(-1px);
}
/* Focus-visible: same as hover (keyboard accessibility) */
.contact-choice input[type="radio"]:focus-visible + .contact-choice__inner {
  border-color: var(--paper);
  outline: 1px solid var(--gold);
  outline-offset: 2px;
}
/* Selected state: paper border + gold dot + subtle lift hold */
.contact-choice input[type="radio"]:checked + .contact-choice__inner {
  border-color: var(--paper);
  background: rgba(241, 236, 227, 0.04);
  transform: translateY(-1px);
}
.contact-choice input[type="radio"]:checked + .contact-choice__inner::after {
  content: "";
  position: absolute;
  top: clamp(1rem, 1.6vw, 1.25rem);
  right: clamp(1rem, 1.6vw, 1.25rem);
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--gold);
  box-shadow: 0 0 8px rgba(203, 178, 106, 0.6);
}

/* ── Inputs container (steps IV + V) ── */
.contact-form__inputs {
  display: flex;
  flex-direction: column;
  gap: clamp(1.25rem, 2vw, 1.5rem);
  margin-top: clamp(1rem, 2vw, 1.5rem);
}
.contact-form__optional {
  font-size: 10px;
  letter-spacing: 0.2em;
  color: var(--ash);
  text-transform: uppercase;
  margin-left: 0.4em;
}

/* ── Step navigation buttons ── */
.contact-form__nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: clamp(1rem, 2vw, 1.5rem);
  margin-top: auto;
  padding-top: clamp(1.5rem, 3vw, 2rem);
}
.contact-form__nav--first {
  justify-content: flex-end; /* no Back button on step 1 */
}

.contact-form__next,
.contact-form__back {
  font-family: 'Inter', sans-serif;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--paper);
  background: transparent;
  border: none;
  cursor: pointer;
  padding: 0.85rem 0;
  display: inline-flex;
  align-items: center;
  gap: 0.65em;
  transition: color 280ms var(--ease-cinema), opacity 280ms var(--ease-cinema);
  position: relative;
}
.contact-form__back {
  color: var(--ash);
}
.contact-form__back:hover { color: var(--paper); }
.contact-form__next:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}
.contact-form__next:not(:disabled)::after {
  content: "";
  position: absolute;
  bottom: 0.55rem;
  left: 0;
  right: 0;
  height: 1px;
  background: var(--paper);
  opacity: 0.5;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 320ms var(--ease-cinema);
}
.contact-form__next:not(:disabled):hover::after {
  transform: scaleX(1);
}
.contact-form__next-arrow,
.contact-form__back-arrow {
  display: inline-block;
  transition: transform 280ms var(--ease-cinema);
}
.contact-form__next:not(:disabled):hover .contact-form__next-arrow {
  transform: translateX(4px);
}
.contact-form__back:hover .contact-form__back-arrow {
  transform: translateX(-4px);
}

/* ── Final submit button — bigger, gold-tinted, the close ── */
.contact-form--stepped .contact-form__submit {
  margin-left: auto;
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-weight: 500;
  font-size: clamp(1.125rem, 1.5vw, 1.375rem);
  letter-spacing: 0.02em;
  text-transform: none;
  color: var(--paper);
  background: transparent;
  border: 1px solid var(--paper);
  padding: clamp(0.8rem, 1.4vw, 1.05rem) clamp(1.5rem, 2.8vw, 2.25rem);
  display: inline-flex;
  align-items: center;
  gap: 0.8em;
  cursor: pointer;
  transition:
    background 360ms var(--ease-cinema),
    color      360ms var(--ease-cinema),
    transform  360ms var(--ease-cinema);
}
.contact-form--stepped .contact-form__submit:hover {
  background: var(--paper);
  color: var(--ink);
  transform: translateY(-2px);
}
.contact-form--stepped .contact-form__submit-arrow {
  transition: transform 280ms var(--ease-cinema);
}
.contact-form--stepped .contact-form__submit:hover .contact-form__submit-arrow {
  transform: translateX(6px);
}
.contact-form--stepped .contact-form__submit.is-submitting {
  pointer-events: none;
  opacity: 0.7;
}
.contact-form--stepped .contact-form__submit.is-submitting .contact-form__submit-arrow {
  /* Spinning arrow on submit — discrete motion confirms work in flight */
  animation: ccs-submit-pulse 0.9s ease-in-out infinite;
}
@keyframes ccs-submit-pulse {
  0%, 100% { opacity: 1;   transform: translateX(0);     }
  50%      { opacity: 0.4; transform: translateX(8px);   }
}

/* ── Note line (last step) ── */
.contact-form--stepped .contact-form__note {
  margin-top: clamp(1rem, 2vw, 1.5rem);
  text-align: right;
}

/* ── No-JS fallback: render all steps stacked vertically so the
   form remains usable if scripts.js fails entirely. The hidden
   class is added by JS once it boots; without JS, steps stay
   visible. ── */
.contact-form--stepped:not([data-js-ready]) .contact-form__step {
  position: relative;
  inset: auto;
  opacity: 1;
  transform: none;
  pointer-events: auto;
  visibility: visible;
  margin-bottom: clamp(2rem, 4vw, 3rem);
}
.contact-form--stepped:not([data-js-ready]) .contact-form__progress {
  display: none;
}
.contact-form--stepped:not([data-js-ready]) .contact-form__nav {
  display: none;
}

/* ── Cinematic top back button ──
   Lives at the top of every step except step 1. Replaces the
   bottom Back button on mobile (where the bottom of the form is
   often past the fold). Editorial styling: tracked uppercase
   "Back to" + italic Cormorant chapter name + chevron that
   nudges left on hover. Hairline underline grows on hover for
   the "turning the page" feel.
   Hidden on desktop by default (display: none); shown on mobile
   via the @media block below. ── */
.contact-form__step-back {
  display: none;
  align-items: baseline;
  gap: 0.55em;
  background: transparent;
  border: 0;
  padding: 0.45rem 0;
  margin: 0;
  cursor: pointer;
  color: var(--ash);
  text-align: left;
  align-self: flex-start;   /* don't stretch in the flex column */
  position: relative;
  transition: color 320ms var(--ease-cinema);
  font-family: inherit;
  -webkit-tap-highlight-color: transparent;
}
.contact-form__step-back-arrow {
  font-size: 1.25em;
  line-height: 1;
  color: inherit;
  transition: transform 320ms var(--ease-cinema);
}
.contact-form__step-back-label {
  font-family: 'Inter', sans-serif;
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: inherit;
  line-height: 1;
}
.contact-form__step-back-context {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-weight: 500;
  font-size: 1.0625rem;
  letter-spacing: -0.005em;
  color: var(--paper-3);
  line-height: 1;
  transition: color 320ms var(--ease-cinema);
}
/* Hairline underline — grows from left on hover/active. Editorial detail. */
.contact-form__step-back::after {
  content: "";
  position: absolute;
  bottom: 0.1rem;
  left: 0;
  right: 0;
  height: 1px;
  background: var(--paper);
  opacity: 0.4;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 380ms var(--ease-cinema);
}
.contact-form__step-back:hover,
.contact-form__step-back:focus-visible {
  color: var(--paper);
  outline: none;
}
.contact-form__step-back:hover .contact-form__step-back-arrow,
.contact-form__step-back:focus-visible .contact-form__step-back-arrow {
  transform: translateX(-4px);
}
.contact-form__step-back:hover .contact-form__step-back-context,
.contact-form__step-back:focus-visible .contact-form__step-back-context {
  color: var(--paper);
}
.contact-form__step-back:hover::after,
.contact-form__step-back:focus-visible::after {
  transform: scaleX(1);
}
.contact-form__step-back:active .contact-form__step-back-arrow {
  transform: translateX(-6px);
}

/* ── Mobile refinements ── */
@media (max-width: 720px) {
  /* ── FIX: cards no longer cut off ──
     Desktop kept the container at min-height 26-34rem with steps
     absolutely positioned inside. On mobile that was clipping any
     step taller than 34rem (the Industry step with 7 cards + nav
     overflows by ~250px, pushing the bottom Back button off-screen
     under the footer). Solution: let the active step flow naturally
     so the container grows to its content; inactive steps stay
     absolute so they don't add to the container height. Container
     reflows instantly on step change — the cross-fade transition
     masks any height pop. */
  .contact-form__steps {
    min-height: 0;
    position: relative;
  }
  .contact-form__step.is-active {
    position: relative;
    inset: auto;
  }
  .contact-form__step:not(.is-active) {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
  }

  /* Show top back button (hidden on desktop) */
  .contact-form__step-back {
    display: inline-flex;
  }

  /* Hide bottom Back button on mobile — top back button replaces it.
     The Continue/Submit button on the right stays where it is. */
  .contact-form__nav .contact-form__back {
    display: none;
  }
  /* With Back gone, right-align Continue alone on its row. */
  .contact-form__nav {
    justify-content: flex-end;
    gap: 1rem;
  }

  .contact-form__step-question {
    font-size: clamp(1.5rem, 7vw, 2rem);
  }
  .contact-form--stepped .contact-form__submit {
    padding: 0.85rem 1.4rem;
  }
}

/* ═════════════════════════════════════════════════════════════════
   57. ABOUT PAGE — CINEMATIC EXTENSIONS
   ═════════════════════════════════════════════════════════════════
   New elements added in v=56 for the cinematic About overhaul:

     • .about-numeral      — oversized italic "V" chapter mark
                             (body-set, anchors the hero block visually
                             without competing with the floating
                             .chapter-mark in the margin)
     • .about-meta         — coordinates + currently-designing line
     • .about-quote        — pull-quote interludes between essay acts
                             (large-display italic, hairline divider,
                             editorial caption — print-magazine pacing)
     • .about-influences   — selected lineage section (Apple, Pentagram,
                             Stripe, Lusion, Linear, Locomotive)
     • .about-signature__plate — editorial frame around the signature
                                 (hairlines top + bottom, italic mark
                                 centered, like the colophon page of
                                 a hand-bound book)

   Everything here is SCOPED to .about-* selectors so nothing else
   on the site can be affected. The shared <canvas class="particle-field">
   reuses the existing constellation system from index.html — same
   physics, same density logic, same audio reactivity. Zero new JS.
   ═════════════════════════════════════════════════════════════════ */

/* ── Hero: oversized "V" chapter numeral.
   Body-set Cormorant italic V that lives ABOVE the eyebrow inside
   the title block. Reads as "Chapter V" the moment the page loads.
   Sized to be the second-loudest element in the hero after the title
   itself. Animates in via the standard .reveal hook. */
.about-numeral {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-weight: 400;
  font-size: clamp(4rem, 9vw, 8rem);
  line-height: 0.9;
  letter-spacing: -0.04em;
  color: var(--paper);
  opacity: 0.78;
  margin: 0 0 var(--space-2) 0;
}

/* ── Hero meta: coordinates + currently-designing line.
   Sits below the hero lead. Two-line block: editorial coordinates
   (real lat/lng of Boston), then a "Currently" status that reads
   like the colophon line in a magazine masthead. Both stay small,
   uppercase tracked, quiet — they're proof of life, not announcements. */
.about-meta {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin: var(--space-4) 0 0 0;
  padding-top: var(--space-3);
  border-top: 1px solid var(--rule-2);
}
.about-meta__coords {
  font-family: 'Inter', sans-serif;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--ash);
  margin: 0;
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
}
.about-meta__dot {
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--gold);
  /* Slow pulse — proof of life, but never aggressive. Matches the
     "live time" dot in the header. */
  animation: ccs-about-pulse 3.4s ease-in-out infinite;
}
@keyframes ccs-about-pulse {
  0%, 100% { opacity: 1;   transform: scale(1);   }
  50%      { opacity: 0.45; transform: scale(0.85); }
}
.about-meta__currently {
  font-family: 'Inter', sans-serif;
  font-size: clamp(0.875rem, 1vw, 1rem);
  line-height: 1.55;
  color: var(--paper-3);
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.6em;
}
.about-meta__currently-label {
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--gold);
}
.about-meta__currently-text em {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  color: var(--paper);
}

/* ── Pull-quote interlude.
   Sits between essay acts. Oversized italic display Cormorant on a
   centered block, with a decorative open-quote glyph above and a
   small caption below. Hairlines top + bottom give it the "lifted
   plate" feel of a print-magazine pull-quote. The opening quote
   mark uses real typographic punctuation; positioned to feel
   editorial, not decorative. */
.about-quote {
  margin: clamp(3rem, 6vw, 6rem) auto;
  max-width: 38rem;
  padding: clamp(2rem, 4vw, 3.5rem) clamp(1rem, 3vw, 2.5rem);
  text-align: center;
  border-top: 1px solid var(--rule-2);
  border-bottom: 1px solid var(--rule-2);
  position: relative;
}
.about-quote__mark {
  display: block;
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-weight: 400;
  font-size: clamp(3rem, 5vw, 4.5rem);
  line-height: 0.5;
  color: var(--gold);
  opacity: 0.65;
  margin: 0 0 var(--space-2) 0;
}
.about-quote__text {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 400;
  font-size: clamp(1.5rem, 3vw, 2.5rem);
  line-height: 1.22;
  letter-spacing: -0.014em;
  color: var(--paper);
  margin: 0;
  /* The quote itself is plain weight; the *meaning-carrying* word
     inside is italicized via inline <em> for emphasis. Reads like
     New Yorker / Wallpaper editorial pull-quotes. */
}
.about-quote__text em {
  font-style: italic;
}
.about-quote__caption {
  font-family: 'Inter', sans-serif;
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--ash);
  margin: var(--space-3) 0 0 0;
}

/* ── Selected influences section.
   Subtle homage to the studios + brands whose work raises the bar.
   Editorial grid of cells, each with a name (display Cormorant) and
   a detail line (small Inter tracked). No links, no logos — just
   typography. Like the colophon of a film or a magazine masthead. */
.about-influences {
  padding-block: clamp(5rem, 10vw, 12rem);
  background: var(--ink);
}
.about-influences__inner {
  max-width: 76rem;
  margin: 0 auto;
  padding: 0 var(--gutter);
}
.about-influences__eyebrow {
  margin-bottom: var(--space-3);
  color: var(--ash);
}
.about-influences__title {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 400;
  font-size: clamp(1.875rem, 3vw, 2.5rem);
  line-height: 1.1;
  letter-spacing: -0.014em;
  color: var(--paper);
  margin: 0 0 clamp(2.5rem, 5vw, 4rem) 0;
  max-width: 28ch;
}
.about-influences__title em { font-style: italic; }
.about-influences__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: 0;
  border-top: 1px solid var(--rule-2);
}
@media (min-width: 640px) {
  .about-influences__list { grid-template-columns: 1fr 1fr; }
}
@media (min-width: 960px) {
  .about-influences__list { grid-template-columns: 1fr 1fr 1fr; }
}
.about-influences__item {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: clamp(1.5rem, 2.5vw, 2.25rem) clamp(1rem, 2vw, 1.75rem);
  border-bottom: 1px solid var(--rule-2);
  /* Cell-borders on the right give the grid its print feel; the
     last-of-row drops its right border so the outer edge stays clean. */
  border-right: 1px solid var(--rule-2);
  transition: background 460ms var(--ease-cinema), transform 460ms var(--ease-cinema);
}
@media (min-width: 640px) {
  .about-influences__item:nth-child(2n) { border-right: none; }
}
@media (min-width: 960px) {
  .about-influences__item:nth-child(2n) { border-right: 1px solid var(--rule-2); }
  .about-influences__item:nth-child(3n) { border-right: none; }
}
.about-influences__item:hover {
  background: rgba(241, 236, 227, 0.025);
  transform: translateY(-2px);
}
.about-influences__name {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 500;
  font-size: clamp(1.375rem, 2vw, 1.625rem);
  line-height: 1;
  letter-spacing: -0.012em;
  color: var(--paper);
}
.about-influences__detail {
  font-family: 'Inter', sans-serif;
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ash);
  line-height: 1.4;
}

/* ── Signature plate — editorial frame around the closing mark.
   Hairlines top + bottom, italic preface above, italic mark inside,
   tracked caption below. Each rule is a centered 60-wide hairline
   that grows from a single point to its full width when the plate
   scrolls into view (CSS scale-x on the rule). */
.about-signature__preface {
  color: var(--ash);
  margin: 0 0 clamp(2rem, 4vw, 3rem) 0;
}
.about-signature__plate {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(1rem, 2vw, 1.75rem);
  margin: 0 auto;
  max-width: 36rem;
  padding-block: clamp(2rem, 3vw, 3rem);
}
.about-signature__rule {
  display: block;
  height: 1px;
  width: clamp(120px, 16vw, 220px);
  background: var(--paper);
  opacity: 0.32;
  transform: scaleX(0);
  transform-origin: center;
  transition: transform 1.1s var(--ease-cinema), opacity 1.1s var(--ease-cinema);
}
/* Hairlines grow from center as the page settles. Single trigger on
   is-loaded matches the existing intro-fade choreography pattern. */
body.is-loaded .about-signature__rule {
  transform: scaleX(1);
}
body.is-loaded .about-signature__rule--top    { transition-delay: 220ms; }
body.is-loaded .about-signature__rule--bottom { transition-delay: 320ms; }

/* ═════════════════════════════════════════════════════════════════
   60. MOBILE POLISH PASS — v=60
   ═════════════════════════════════════════════════════════════════
   Surgical mobile-only refinement after a full audit of all four
   main pages across iPhone SE (320), Mini (375), 14 Pro (390), and
   Pro Max (430). Desktop is NOT touched. Each fix is scoped to the
   tightest media query that resolves the bug.

   Findings:
     1. <fieldset> contact-form steps overflowing ~20px past viewport
        on every phone width. Cause: <fieldset>'s browser default
        min-inline-size: min-content ignores the parent column.
     2. Sticky header clipping "CONTACT" to "CONT" on iPhone SE.
        Cause: 4-link nav + wordmark exceeds 320px at the existing
        @media(max-width: 520px) sizing.
     3. Chapter-act blocks 240vh tall on mobile (~2026px each, ×2 on
        home = ~4000px of mostly-empty scroll). Cause: vertical
        runway tuned for the desktop cinematic zoom-through.
     4. Process steps + About-essay acts at clamp(3rem, 5vw, 5rem)
        padding-block — 96px each side compounding across many
        chapters into ~1700px of extra scroll on home + about.
   ═════════════════════════════════════════════════════════════════ */

/* ── Contact form <fieldset> overflow fix — every viewport ──── */
.contact-form__step {
  min-inline-size: 0;
  max-width: 100%;
}

/* ── Sticky header: make 4-link nav fit iPhone SE (320 - 380px) ── */
@media (max-width: 380px) {
  .site-header {
    padding-inline: 0.75rem;
    gap: 0.5rem;
  }
  .site-header__brand {
    font-size: 0.8125rem;
    letter-spacing: 0;
    white-space: nowrap;
  }
  .site-header__nav { gap: 0.5rem; }
  .site-header__link {
    font-size: 9.5px;
    letter-spacing: 0.06em;
  }
}
/* iPhone SE specifically (320px) needs an even tighter pass — the
   wordmark + 4 nav links cannot all fit comfortably otherwise. */
@media (max-width: 340px) {
  .site-header { padding-inline: 0.5rem; gap: 0.375rem; }
  .site-header__brand { font-size: 0.75rem; }
  .site-header__nav { gap: 0.4375rem; }
  .site-header__link { font-size: 9px; letter-spacing: 0.04em; }
}

/* ── Chapter-act compression: kill the dead air on mobile ──── */
@media (max-width: 720px) {
  .chapter-act { height: 120vh; }
  .chapter-act__viewport { height: 100vh; }
}

/* ── Chapter padding compression: process + about-essay ──── */
@media (max-width: 720px) {
  .process__step       { padding-block: clamp(1.75rem, 4vw, 2.5rem); }
  .about-essay__act    { padding-block: clamp(1.75rem, 4vw, 2.5rem); }
}

/* ═════════════════════════════════════════════════════════════════
   61. ARCHIVE — EDITORIAL INDEX (mobile dual-layout)
   ═════════════════════════════════════════════════════════════════
   Desktop visitors get only the draggable 3D sphere. Mobile visitors
   get the same sphere as a 100svh hero, then scroll down to an
   editorial 2-column table of the same projects — magazine pacing.

   The .archive__index <section> in archive.html is hidden by default
   (display: none) and only revealed when body.archive-with-index
   is set by archive.js for phone viewports with WebGL. No-WebGL
   visitors hit the existing body.archive-mobile fallback path.
   ═════════════════════════════════════════════════════════════════ */

/* Default: editorial index is hidden — sphere alone is the experience. */
.archive__index { display: none; }

/* Mobile dual-layout: sphere becomes a 100svh hero, index flows below. */
@media (max-width: 767px) {
  body.archive-with-index .archive {
    min-height: auto;
    overflow: visible;
    /* display: flow-root creates a new Block Formatting Context, blocking
       the .archive__index's margin-top: 100svh from collapsing UP into
       .archive's top margin (which would shove the whole section + its
       absolutely-positioned children down by 100svh in body coords). */
    display: flow-root;
  }
  /* Canvas absolute-positioned within .archive (was fixed). This lets
     the canvas anchor to the top 100svh and the editorial section
     flow naturally beneath it. */
  body.archive-with-index .archive__canvas {
    position: absolute;
    inset: 0 0 auto 0;
    width: 100%;
    height: 100svh;
    z-index: 1;
  }
  /* Eyebrow + readout + hint: absolute within .archive so they scroll
     UP with the sphere as visitor reaches the index section. */
  body.archive-with-index .archive__eyebrow,
  body.archive-with-index .archive__readout,
  body.archive-with-index .archive__hint {
    position: absolute;
  }
  body.archive-with-index .archive__eyebrow {
    top: clamp(4.25rem, 7vh, 5.5rem);
  }
  /* On mobile we hide the readout entirely. Its purpose is to surface
     which card is hovered/focused on the sphere — meaningless on touch
     where every card is already labeled in the editorial grid below.
     Removing it also eliminates the awkward transition zone where the
     readout pill was overlapping the editorial INDEX header. */
  body.archive-with-index .archive__readout { display: none; }
  body.archive-with-index .archive__eyebrow { z-index: 2; }
  body.archive-with-index .archive__hint {
    /* Sphere zone is 100svh tall; center the hint within it (not within
       the full .archive container which now also holds the index). */
    top: 50svh;
  }

  /* The index section starts after the 100svh sphere viewport. */
  body.archive-with-index .archive__index {
    display: block;
    position: relative;
    z-index: 5;
    margin-top: 100svh;
    padding:
      clamp(3rem, 8vw, 5rem)
      clamp(1.25rem, 4vw, 2rem)
      clamp(4rem, 10vw, 7rem);
    background: var(--ink);
    /* Soft fade-in from the sphere zone so the seam feels intentional */
    box-shadow: 0 -40px 80px -40px rgba(10, 10, 12, 0.95);
  }
}

/* ── Editorial section header (Index · Ten projects, hand-set.) ── */
.archive__index-header {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(0.85rem, 2vw, 1.2rem);
  text-align: center;
  margin-bottom: clamp(2.5rem, 7vw, 4rem);
}
.archive__index-eyebrow {
  font-family: 'Inter', sans-serif;
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.42em;
  text-transform: uppercase;
  color: var(--gold);
  opacity: 0.9;
}
.archive__index-title {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 400;
  font-size: clamp(2rem, 8vw, 3.25rem);
  line-height: 1.04;
  letter-spacing: -0.018em;
  color: var(--paper);
  margin: 0;
  max-width: 16ch;
}
.archive__index-title em {
  font-style: italic;
  color: var(--paper);
}
.archive__index-sub {
  font-family: 'Inter', sans-serif;
  font-size: 13px;
  line-height: 1.55;
  color: var(--paper-3);
  opacity: 0.78;
  margin: 0;
  max-width: 32ch;
}
.archive__index-sub em {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  color: var(--paper);
  font-size: 14.5px;
}
.archive__index-rule {
  display: block;
  width: 40px;
  height: 1px;
  background: var(--paper);
  opacity: 0.35;
  margin-top: 0.25rem;
}
.archive__index-rule--end {
  width: 64px;
  opacity: 0.28;
}

/* ── Grid sizing in the dual-layout path ────────────────────────
   Mirror the existing body.archive-mobile grid columns so both
   paths produce identical layout. */
body.archive-with-index .archive__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(1rem, 3vw, 1.5rem);
  margin: 0;
  padding: 0;
}
@media (min-width: 480px) {
  body.archive-with-index .archive__grid {
    grid-template-columns: 1fr 1fr;
  }
}

/* ── Index footer (More, forthcoming.) ────────────────────────── */
.archive__index-footer {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(1rem, 3vw, 1.5rem);
  margin-top: clamp(2.5rem, 7vw, 4rem);
}
.archive__index-closing {
  font-family: 'Inter', sans-serif;
  font-size: 10.5px;
  letter-spacing: 0.36em;
  text-transform: uppercase;
  color: var(--ash);
  margin: 0;
  display: flex;
  align-items: baseline;
  gap: 0.65em;
}
.archive__index-closing em {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-size: 15px;
  letter-spacing: 0;
  text-transform: none;
  color: var(--paper);
}

/* ── Card improvements — scroll reveal, editorial status, hero glow ── */

/* Pre-reveal state: hidden + lifted, staggered by --card-stagger. */
.archive-card {
  opacity: 0;
  transform: translateY(24px);
  transition:
    opacity 720ms cubic-bezier(0.16, 1, 0.3, 1) var(--card-stagger, 0ms),
    transform 720ms cubic-bezier(0.16, 1, 0.3, 1) var(--card-stagger, 0ms),
    border-color 320ms ease;
  will-change: opacity, transform;
}
.archive-card.is-revealed {
  opacity: 1;
  transform: translateY(0);
}
/* Touch tap-active: subtle press feedback */
.archive-card.is-revealed:active {
  transform: translateY(-1px) scale(0.985);
  transition: transform 200ms cubic-bezier(0.16, 1, 0.3, 1);
}

/* Live card (Sierra) — golden accent border + diagonal accent wash */
.archive-card--live {
  border-color: rgba(203, 178, 106, 0.20);
}
.archive-card--live .archive-card__hero::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(135deg, transparent 55%, var(--card-accent, transparent) 100%);
  opacity: 0.20;
  mix-blend-mode: screen;
  pointer-events: none;
  z-index: 1;
}

/* Editorial "Forthcoming" status — italic, no pill, no border. */
.archive-card__status {
  position: absolute;
  /* Position BELOW the industry label which is at the top of the card.
     The status sits on the hero image's lower-right corner instead. */
  bottom: calc(clamp(1.1rem, 3vw, 1.5rem) + 50px);
  right: clamp(1rem, 3vw, 1.4rem);
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-weight: 500;
  font-size: 13px;
  letter-spacing: 0.01em;
  color: var(--card-accent, var(--paper));
  opacity: 0.88;
  z-index: 3;
  text-shadow: 0 1px 8px rgba(10, 10, 12, 0.7);
}

/* Hero accent glow — soft palette wash in the upper-right corner. */
.archive-card__hero-glow {
  position: absolute;
  inset: 0;
  background: radial-gradient(
    circle at 80% 20%,
    var(--card-accent, transparent) 0%,
    transparent 55%
  );
  opacity: 0.16;
  mix-blend-mode: screen;
  pointer-events: none;
  z-index: 0;
}

/* Hero gets relative positioning context for the glow + diagonal wash. */
.archive-card__hero { position: relative; }

/* Reduced motion: skip the scroll reveal — cards render visible. */
@media (prefers-reduced-motion: reduce) {
  .archive-card {
    opacity: 1;
    transform: none;
    transition: border-color 320ms ease;
  }
}

/* ═════════════════════════════════════════════════════════════════
   68. ARCHIVE — DESKTOP INDEX + PREVIEWS + FILTERS + LIVE PULSE
   ═════════════════════════════════════════════════════════════════
   Cinematic upgrade to the archive page (v=68):
     • Editorial INDEX section now shows on EVERY device (was mobile only)
     • Live cards (Sierra / Auberge / Verde) get custom brand previews
       in their hero area instead of plain abstract gradient
     • Filter pills above the grid let visitors slice by vertical
     • "Live" pulsing dot indicator replaces "Coming soon" pill
     • Tighter card grid spacing on every viewport
     • Atmospheric radial backdrop around the sphere zone on desktop
   ═════════════════════════════════════════════════════════════════ */

/* ── Show the editorial index on DESKTOP too ─────────────────── */
@media (min-width: 768px) {
  body.archive-with-index .archive {
    min-height: auto;
    overflow: visible;
    display: flow-root;
  }
  body.archive-with-index .archive__canvas {
    position: absolute;
    inset: 0 0 auto 0;
    width: 100%;
    height: 100svh;
    z-index: 1;
  }
  /* Desktop keeps the eyebrow + hint + readout, but they get pinned
     to the sphere zone (absolute within .archive) so they scroll
     away as visitor reaches the editorial index below. */
  body.archive-with-index .archive__eyebrow,
  body.archive-with-index .archive__readout,
  body.archive-with-index .archive__hint {
    position: absolute;
  }
  body.archive-with-index .archive__eyebrow {
    top: clamp(5.5rem, 9vh, 7rem);
    z-index: 3;
  }
  body.archive-with-index .archive__readout {
    top: auto;
    bottom: auto;
    top: calc(100svh - clamp(4rem, 7vh, 5rem));
    z-index: 3;
  }
  body.archive-with-index .archive__hint {
    top: 50svh;
  }

  body.archive-with-index .archive__index {
    display: block;
    position: relative;
    z-index: 5;
    margin-top: 100svh;
    padding:
      clamp(5rem, 9vw, 8rem)
      clamp(2rem, 5vw, 4rem)
      clamp(5rem, 9vw, 7rem);
    background: var(--ink);
    box-shadow: 0 -60px 120px -40px rgba(10, 10, 12, 0.92);
  }

  /* "Scroll for index" cue between sphere and section — appears as a
     subtle eyebrow at the top of the editorial section, signalling
     visitors they can keep scrolling past the sphere. */
  body.archive-with-index .archive__index::before {
    content: "↓ Editorial index";
    display: block;
    text-align: center;
    font-family: 'Inter', sans-serif;
    font-size: 10px;
    font-weight: 500;
    letter-spacing: 0.42em;
    text-transform: uppercase;
    color: var(--gold);
    opacity: 0.7;
    margin-bottom: clamp(2.5rem, 5vw, 4rem);
  }

  /* Wider grid on desktop — 3 columns mid-size, 4 columns large */
  body.archive-with-index .archive__grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: clamp(1rem, 2vw, 1.5rem);
    max-width: 1280px;
    margin: 0 auto;
  }
  @media (min-width: 1280px) {
    body.archive-with-index .archive__grid {
      grid-template-columns: repeat(4, 1fr);
    }
  }
}

/* ── Atmospheric backdrop around the sphere zone ─────────────── */
.archive::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(ellipse 80% 60% at 50% 45%, rgba(203, 178, 106, 0.05), transparent 70%),
    radial-gradient(ellipse 50% 80% at 20% 80%, rgba(241, 236, 227, 0.025), transparent 75%),
    radial-gradient(ellipse 40% 60% at 85% 25%, rgba(241, 236, 227, 0.03), transparent 70%);
  opacity: 0.85;
  transition: opacity 800ms var(--ease-house, cubic-bezier(0.16, 1, 0.3, 1));
}

/* ── Filter pills ────────────────────────────────────────────── */
.archive__filters {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.45rem;
  max-width: 980px;
  margin: 0 auto clamp(2rem, 4vw, 3rem);
  padding-inline: 0.5rem;
}
.archive-filter {
  font-family: 'Inter', sans-serif;
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--paper-3);
  padding: 0.55rem 0.95rem;
  background: transparent;
  border: 1px solid rgba(241, 236, 227, 0.14);
  border-radius: 999px;
  cursor: pointer;
  transition:
    border-color 380ms var(--ease-house, cubic-bezier(0.16, 1, 0.3, 1)),
    color 380ms var(--ease-house, cubic-bezier(0.16, 1, 0.3, 1)),
    background 380ms var(--ease-house, cubic-bezier(0.16, 1, 0.3, 1)),
    transform 380ms var(--ease-house, cubic-bezier(0.16, 1, 0.3, 1));
}
.archive-filter:hover {
  border-color: var(--paper);
  color: var(--paper);
  transform: translateY(-1px);
}
.archive-filter.is-active {
  border-color: var(--gold);
  color: var(--gold);
  background: rgba(203, 178, 106, 0.08);
}

/* ── Filtered-out cards collapse smoothly ────────────────────── */
.archive-card.is-filtered-out {
  opacity: 0;
  transform: translateY(8px) scale(0.96);
  pointer-events: none;
  max-height: 0;
  margin: 0 !important;
  padding: 0 !important;
  overflow: hidden;
  border: 0;
  transition:
    opacity 320ms var(--ease-house, cubic-bezier(0.16, 1, 0.3, 1)),
    transform 320ms var(--ease-house, cubic-bezier(0.16, 1, 0.3, 1)),
    max-height 480ms var(--ease-house, cubic-bezier(0.16, 1, 0.3, 1));
}

/* ── "Live" pulsing dot indicator (replaces "Coming soon" for live cards) ── */
.archive-card__live {
  position: absolute;
  top: clamp(0.85rem, 2.5vw, 1.15rem);
  right: clamp(0.85rem, 2.5vw, 1.15rem);
  display: inline-flex;
  align-items: center;
  gap: 0.45em;
  font-family: 'Inter', sans-serif;
  font-size: 9px;
  font-weight: 500;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--gold);
  padding: 0.3em 0.7em;
  background: rgba(10, 10, 12, 0.5);
  border: 1px solid rgba(203, 178, 106, 0.4);
  border-radius: 999px;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  z-index: 3;
}
.archive-card__live-dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--gold);
  box-shadow: 0 0 0 0 rgba(203, 178, 106, 0.7);
  animation: ccs-archive-live-pulse 1.8s cubic-bezier(0.16, 1, 0.3, 1) infinite;
}
@keyframes ccs-archive-live-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(203, 178, 106, 0.55); transform: scale(1); }
  70%  { box-shadow: 0 0 0 10px rgba(203, 178, 106, 0);  transform: scale(1.15); }
  100% { box-shadow: 0 0 0 0 rgba(203, 178, 106, 0);    transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .archive-card__live-dot { animation: none; }
}

/* ── AUBERGE preview frame ───────────────────────────────────── */
.archive-card__hero--auberge {
  background:
    radial-gradient(ellipse at 70% 20%, rgba(226, 195, 154, 0.20), transparent 60%),
    linear-gradient(150deg, #2A1B0E 0%, #14110A 60%, #3D2A18 100%);
}
.archive-card__preview-frame {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: stretch;
  padding: clamp(0.75rem, 2vw, 1rem);
  z-index: 1;
}
.archive-card__preview-eye {
  font-family: 'Inter', sans-serif;
  font-size: 7.5px;
  font-weight: 500;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--card-fg, #F5EBDD);
  opacity: 0.55;
  align-self: flex-start;
}
.archive-card__preview-mark {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: normal;
  font-weight: 400;
  font-size: clamp(1.5rem, 4.5vw, 2.25rem);
  letter-spacing: 0.34em;
  color: var(--card-fg, #F5EBDD);
  align-self: center;
  margin-block: auto;
  text-align: center;
}
.archive-card__preview-mark em {
  font-style: italic;
  color: var(--card-accent, #E2C39A);
  padding-inline: 0.1em;
}
.archive-card__preview-rule {
  display: block;
  width: 36px;
  height: 1px;
  background: var(--card-accent, #E2C39A);
  opacity: 0.6;
  align-self: center;
  margin-block: 0.5rem;
}
.archive-card__preview-sub {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-weight: 400;
  font-size: 10.5px;
  line-height: 1.3;
  color: var(--card-fg, #F5EBDD);
  opacity: 0.75;
  text-align: center;
  align-self: stretch;
}
.archive-card__preview-sub em {
  font-style: italic;
  color: var(--card-accent);
}

/* ── VERDE COAST preview frame ────────────────────────────────── */
.archive-card__hero--verde {
  background:
    radial-gradient(ellipse at 75% 25%, rgba(184, 201, 176, 0.18), transparent 60%),
    linear-gradient(150deg, #1A2624 0%, #0E1614 60%, #243532 100%);
}
.archive-card__preview-frame--verde .archive-card__preview-mark {
  letter-spacing: 0.38em;
}
.archive-card__preview-topo {
  width: 90%;
  align-self: center;
  color: var(--card-accent, #B8C9B0);
  margin-block: 0.4rem;
}

/* ── SIERRA preview frame (uses the real fleet.jpg) ───────────── */
.archive-card__hero--sierra {
  /* Existing background-image from heroImage prop is kept.
     We add a soft golden corner glow + a darker bottom gradient
     for legibility against the photo. */
  position: relative;
}
.archive-card__hero--sierra::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg, transparent 50%, rgba(10, 10, 12, 0.55) 100%),
    radial-gradient(circle at 80% 15%, rgba(203, 178, 106, 0.25), transparent 55%);
  pointer-events: none;
}

/* ── Tighten the card grid spacing (mobile) ──────────────────── */
@media (max-width: 767px) {
  body.archive-with-index .archive__grid {
    gap: clamp(0.85rem, 2.5vw, 1.25rem);
  }
}
@media (min-width: 480px) and (max-width: 767px) {
  body.archive-with-index .archive__grid {
    grid-template-columns: 1fr 1fr;
  }
}

/* ── Slightly tighter card padding so cards feel more dense ──── */
.archive-card {
  padding: clamp(0.7rem, 2vw, 1rem);
}
.archive-card__hero { margin-bottom: 0.75rem; }
.archive-card__top { margin-bottom: 0.65rem; }
.archive-card__title { font-size: clamp(1rem, 3.6vw, 1.25rem); margin-bottom: 0.3rem; }
.archive-card__tagline { font-size: 11.5px; margin-bottom: 0.85rem; }

/* ── Card hover lift more pronounced ─────────────────────────── */
.archive-card.is-revealed:hover {
  transform: translateY(-4px);
  border-color: rgba(241, 236, 227, 0.28);
}
.archive-card--live.is-revealed:hover {
  border-color: rgba(203, 178, 106, 0.55);
}

/* ═════════════════════════════════════════════════════════════════
   69. BACK-TO-HOME BUTTON
   ═════════════════════════════════════════════════════════════════
   Sleek glassmorphic pill that lives bottom-left, stacked above the
   audio toggle (the two form a vertical pair, balancing the
   back-to-top button bottom-right).

   Behaviour comes for free from existing systems:
     - Hover/click sounds   →  body-delegated UI sound layer in
                               scripts.js (any <a>/<button>/[data-cursor]
                               element auto-triggers the synthesized
                               whispers).
     - Page-curtain exit    →  pageTransitions() in scripts.js
                               intercepts internal <a href="/">
                               clicks, fades the black curtain in,
                               then navigates — same cinematic
                               transition as every other nav click.
     - Magnetic cursor      →  data-magnetic on inner span; the
                               existing magnetic system in scripts.js
                               pulls the inner toward the cursor
                               on desktop.
   ═════════════════════════════════════════════════════════════════ */
.back-to-home {
  position: fixed;
  /* iOS safe-area aware. Sits ABOVE the audio toggle (audio is at
     bottom 1-1.85rem; this is offset further up to stack vertically). */
  bottom: max(clamp(4.5rem, 8vh, 5.5rem), calc(env(safe-area-inset-bottom, 0px) + 4rem));
  left:   max(clamp(1rem, 2.6vw, 1.85rem), calc(env(safe-area-inset-left, 0px) + 0.5rem));
  z-index: 200;
  text-decoration: none;
  color: var(--paper);
  opacity: 0;
  transform: translateY(8px);
  transition:
    opacity 700ms cubic-bezier(0.16, 1, 0.3, 1) 600ms,
    transform 700ms cubic-bezier(0.16, 1, 0.3, 1) 600ms;
}
body.is-loaded .back-to-home {
  opacity: 1;
  transform: translateY(0);
}

.back-to-home__inner {
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
  padding: 0.5em 1em 0.5em 0.85em;
  background: rgba(241, 236, 227, 0.06);
  backdrop-filter: blur(14px) saturate(120%);
  -webkit-backdrop-filter: blur(14px) saturate(120%);
  border: 1px solid rgba(241, 236, 227, 0.12);
  border-radius: 999px;
  transition:
    background 320ms cubic-bezier(0.16, 1, 0.3, 1),
    border-color 320ms cubic-bezier(0.16, 1, 0.3, 1),
    transform 320ms cubic-bezier(0.16, 1, 0.3, 1);
  white-space: nowrap;
}

.back-to-home:hover .back-to-home__inner,
.back-to-home:focus-visible .back-to-home__inner {
  background: rgba(241, 236, 227, 0.11);
  border-color: rgba(203, 178, 106, 0.45);
  transform: translateY(-1px);
}

.back-to-home__arrow {
  font-family: 'Inter', sans-serif;
  font-size: 13px;
  font-weight: 500;
  color: var(--gold);
  line-height: 1;
  display: inline-block;
  transition: transform 380ms cubic-bezier(0.16, 1, 0.3, 1);
}

.back-to-home:hover .back-to-home__arrow {
  transform: translateX(-4px);
}

.back-to-home__label {
  font-family: 'Inter', sans-serif;
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--paper-3);
  line-height: 1;
  transition: color 320ms cubic-bezier(0.16, 1, 0.3, 1);
}

.back-to-home:hover .back-to-home__label,
.back-to-home:focus-visible .back-to-home__label {
  color: var(--paper);
}

@media (max-width: 720px) {
  /* On phones the audio toggle is slightly smaller — tighten the
     home button's vertical offset so the pair stays balanced. */
  .back-to-home {
    bottom: max(clamp(4rem, 8vh, 5rem), calc(env(safe-area-inset-bottom, 0px) + 3.6rem));
  }
  .back-to-home__inner { padding: 0.45em 0.85em 0.45em 0.75em; }
  .back-to-home__label { font-size: 10px; letter-spacing: 0.28em; }
}

@media (prefers-reduced-motion: reduce) {
  .back-to-home,
  .back-to-home__inner,
  .back-to-home__arrow,
  .back-to-home__label { transition: none !important; }
  body.is-loaded .back-to-home { opacity: 1; transform: none; }
  .back-to-home:hover .back-to-home__arrow { transform: none; }
}

/* ──────────────────────────────────────────────────────────────
   57. CINEMATIC CHAPTER PLATES (v=71)

   Full-bleed obsidian flash that introduces each chapter of the
   home page — modeled on Locomotive's chapter cuts, Apple's
   220/480/380ms title-card cadence, and Studio Mesh's editorial
   restraint. The plate covers the page in obsidian for ~1.66s
   with a Cormorant italic Roman numeral + Montserrat small-caps
   label, then DISMISSES with a chromatic split (red/cyan offsets,
   reusing the rgbSplit DNA from §55).

   Timing budget — strict, no fluff:
     0ms     plate fades in              (220ms ease-cinema)
     120ms   hairline rules draw open    (480ms)
     220ms   numeral rises into place    (520ms)
     460ms   label fades up              (480ms)
     900ms   STATE → hold (the beat)
     1280ms  STATE → exit — chromatic split, plate fades to 0
     1660ms  STATE → idle, back to invisible

   z-index sits at 99500: above all content (4), header (50), and
   sticky chrome (9998) — below cursor (100000) so the cursor still
   tracks across the plate (a small detail visitors love), and below
   the preloader (99998) which is gone by the time plates fire.

   pointer-events: none ALWAYS so scroll continues underneath.
   ────────────────────────────────────────────────────────────── */
.chapter-plate {
  position: fixed;
  inset: 0;
  z-index: 99500;
  display: grid;
  place-items: center;
  pointer-events: none;
  opacity: 0;
  background: var(--ink);
  will-change: opacity;
  contain: layout style paint;
  transition: opacity 380ms var(--ease-cinema);
}

.chapter-plate[data-state="arming"] {
  opacity: 1;
  transition: opacity 220ms var(--ease-cinema);
}
.chapter-plate[data-state="hold"] {
  opacity: 1;
  transition: opacity 0ms linear;
}
.chapter-plate[data-state="exit"] {
  opacity: 0;
  transition: opacity 380ms var(--ease-cinema);
}

/* Film-grain overlay — pure SVG fractalNoise, 4% screen-blended.
   The grain only commits during arming/hold so it doesn't render
   when the plate is idle (which would be a per-pixel cost for nothing). */
.chapter-plate::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
  mix-blend-mode: screen;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240' viewBox='0 0 240 240'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0.94  0 0 0 0 0.93  0 0 0 0 0.89  0 0 0 0.18 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
  transition: opacity 240ms var(--ease-cinema);
}
.chapter-plate[data-state="arming"]::before,
.chapter-plate[data-state="hold"]::before { opacity: 0.05; }

/* The inner stage holds the four typographic elements: top rule,
   numeral (with chromatic pseudo-elements), label, bottom rule. */
.chapter-plate__inner {
  display: grid;
  justify-items: center;
  row-gap: clamp(1.2rem, 2vw, 2rem);
  text-align: center;
  width: min(72ch, 88vw);
}

/* Hairline rules — the editorial-frame around the numeral. They
   draw open from a width of 0 to a fluid target width on entry. */
.chapter-plate__rule {
  height: 1px;
  width: 0;
  background: var(--rule-3);
  transition: width 480ms var(--ease-cinema) 120ms;
}
.chapter-plate[data-state="arming"] .chapter-plate__rule,
.chapter-plate[data-state="hold"]   .chapter-plate__rule {
  width: clamp(120px, 28vw, 320px);
}
.chapter-plate[data-state="exit"] .chapter-plate__rule {
  transition: width 320ms var(--ease-cinema);
  width: 0;
}

/* The numeral — Cormorant italic, large, paper-color. Carries the
   chromatic-split pseudo-elements for the exit dismissal. */
.chapter-plate__numeral {
  position: relative;
  display: inline-block;
  font-family: 'Cormorant Garamond', serif;
  font-style: italic;
  font-weight: 500;
  font-size: clamp(7.5rem, 18vw, 18rem);
  line-height: 0.9;
  letter-spacing: -0.02em;
  color: var(--paper);
  opacity: 0;
  transform: translate3d(0, 18px, 0);
  transition:
    opacity   420ms var(--ease-cinema) 220ms,
    transform 520ms var(--ease-house)  220ms;
  will-change: transform, opacity;
}
.chapter-plate[data-state="arming"] .chapter-plate__numeral,
.chapter-plate[data-state="hold"]   .chapter-plate__numeral {
  opacity: 1;
  transform: translate3d(0, 0, 0);
}

/* v=74 — Removed the entire chromatic-split pseudo-element
   exit decoration. Plates now dismiss with a pure obsidian
   opacity fade (handled by the parent `.chapter-plate`
   opacity transition on data-state=exit). The earlier
   red/cyan offset language was Resn/Active Theory DNA that
   doesn't fit the quiet-luxury voice. Apple-style title
   cards fade clean; we now match that cadence. */

/* The label — Montserrat, small caps, ash. Sits below the numeral. */
.chapter-plate__label {
  font-family: 'Montserrat', sans-serif;
  font-weight: 500;
  font-size: clamp(0.72rem, 1vw, 0.88rem);
  letter-spacing: var(--track-eyebrow);
  text-transform: uppercase;
  color: var(--ash);
  opacity: 0;
  transform: translate3d(0, 8px, 0);
  transition:
    opacity   360ms var(--ease-cinema) 460ms,
    transform 480ms var(--ease-house)  460ms;
  will-change: transform, opacity;
}
.chapter-plate[data-state="arming"] .chapter-plate__label,
.chapter-plate[data-state="hold"]   .chapter-plate__label {
  opacity: 1;
  transform: translate3d(0, 0, 0);
}

/* Anchor markers — invisible scroll triggers. Zero size, zero
   visual presence, IntersectionObserver fodder only. */
.chapter-plate-anchor {
  position: relative;
  height: 1px;
  width: 100%;
  margin: 0;
  pointer-events: none;
  visibility: hidden;
}

/* Mobile — pull the numeral down slightly so it fits a portrait viewport. */
@media (max-width: 768px) {
  .chapter-plate__numeral { font-size: clamp(6rem, 28vw, 11rem); }
  .chapter-plate__label   { font-size: 0.7rem; letter-spacing: 0.26em; }
}

/* Reduced motion — plates do not fire. Visitor sees only the in-flow
   chapter-acts and section reveals (which themselves honor reduced motion). */
@media (prefers-reduced-motion: reduce) {
  .chapter-plate { display: none !important; }
}

/* ──────────────────────────────────────────────────────────────
   58. Chapter III sub-section rhythm (v=72)

   In the four-chapter framework, three sub-sections — process,
   pricing, founder — all live under Chapter III ("The Method").
   Their original padding budgets were chosen for top-level chapter
   boundaries; the same numbers between sibling sub-sections create
   ~280px of dead space at every join.

   These rules cut the colliding paddings by ~60% so the transitions
   between process → pricing → founder feel like a single chapter's
   internal rhythm — not three separate chapters bumping into each
   other. The IV·Begin plate still gets a full breath of space
   below the founder section.
   ────────────────────────────────────────────────────────────── */
.process + .pricing,
.pricing + .founder {
  padding-top: clamp(3rem, 5vw, 6rem);
}
.process:has(+ .pricing) {
  padding-bottom: clamp(3.5rem, 6vw, 7rem);
}
.pricing:has(+ .founder) {
  padding-bottom: clamp(3.5rem, 6vw, 7rem);
}

/* ──────────────────────────────────────────────────────────────
   59. TEXT SCRAMBLE / DECODE (v=74)

   Quiet-luxury character decoding for the chapter plate title
   cards. Inspired by Pentagram, Wallpaper magazine motion graphics,
   and the Apollo Magazine title-card cadence — NOT by glitch /
   chromatic-aberration aesthetics (Resn, Active Theory). The
   cycling motion itself is the cinematic moment; the lock is
   simply settling.

   v=74 cleanup notes (from v=73):
     • Removed the per-character chromatic text-shadow lock-flash.
       At the label's small font size, the 0.04em red/cyan offsets
       read as "broken text," not editorial decoration.
     • Removed the fixed `width: 0.9ch` on every span. At the
       label scale, locking ten uppercase characters into 0.9ch
       slots forced them to overlap and look squeezed. Now: no
       width on label chars (natural Montserrat kerning); just
       a soft `min-width` on numeral chars so narrow Roman glyphs
       (I, L) don't look lonely during the cycle.
     • Removed the plate-exit chromatic split entirely. The plate
       now dismisses with a clean obsidian fade, which feels far
       more like Apple's title-card cadence than Resn's glitch
       vocabulary.
     • Lock animation is opacity-only (0.6 → 1 over 240ms with
       house easing). Smooth, almost invisible — just enough to
       avoid a hard cut from random glyph to final character.
   ────────────────────────────────────────────────────────────── */
.scramble-char {
  display: inline-block;
  text-align: center;
  position: relative;
  font-variant-numeric: tabular-nums;
}

/* Numerals get a small min-width so narrow Roman glyphs (I, L)
   don't look orphaned during the cycle. Labels stay at natural
   width so uppercase kerning reads cleanly. */
.chapter-plate__numeral .scramble-char {
  min-width: 0.55ch;
}
.scramble-char--space {
  min-width: 0.3em;
}

.scramble-char--lock {
  animation: scramble-lock-soft 240ms var(--ease-house);
}

/* Quiet luxury lock animation — opacity only, no chromatic,
   no scale. The visitor feels the character SETTLE without
   noticing the transition. Inverse of glitch decoration. */
@keyframes scramble-lock-soft {
  0%   { opacity: 0.6; }
  100% { opacity: 1;   }
}

/* Defensive — when scramble has replaced numeral innerHTML with
   spans, hide the unused pseudo-element chromatic so it can't
   accidentally fire. v=74 also removed the [data-state="exit"]
   pseudo opacity rules (was the old chromatic split exit) so
   plates now dismiss with a pure obsidian fade. */
.chapter-plate__numeral[data-scrambling="0"]::before,
.chapter-plate__numeral[data-scrambling="0"]::after {
  display: none !important;
}

@media (prefers-reduced-motion: reduce) {
  .scramble-char,
  .scramble-char--lock {
    animation: none !important;
    opacity: 1 !important;
  }
}

/* ──────────────────────────────────────────────────────────────
   60. CHAPTER I — STUDIO META + FOUNDER INTRO + SERVICES (v=75)

   Three sections that restructure the home page to lead with the
   FOUNDER instead of the case study. Visitors used to scroll
   past two minutes of Sierra video before learning who Cam is or
   what he sells. After v=75:

     1. Cold open (existing hero)
     2. Studio statement (existing positioning manifesto)
     3. NEW — Studio meta grid (4 editorial cells: Based · Practice ·
        Availability · Founded). Visitor scans the facts in 3 sec.
     4. NEW — Founder intro (portrait + first-person bio).
     5. NEW — What I do (4-cell services grid).
     6. Chapter II plate flashes → Sierra pivot.

   All three new sections live INSIDE .constellation-band so the
   starfield continues to subtly hum behind them — visual continuity
   across the whole Chapter I act, exactly like the reference site
   (ulrychkristian.cz) keeps a single ambient backdrop under all of
   its cover-page material.

   Reveal animations: every internal element carries the existing
   .reveal class so it integrates with the IntersectionObserver
   reveal pass in scripts.js — no new JS needed.
   ────────────────────────────────────────────────────────────── */

/* ── Studio metadata grid ───────────────────────────────────── */
.studio-meta {
  position: relative;
  z-index: 4;
  padding-block: clamp(3.5rem, 7vw, 7rem);
  padding-inline: var(--gutter);
}
.studio-meta__grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  max-width: 96rem;
  margin: 0 auto;
  border-top: 1px solid var(--rule-2);
  border-bottom: 1px solid var(--rule-2);
}
.studio-meta__cell {
  padding: clamp(1.5rem, 2vw, 2rem) clamp(1.25rem, 2vw, 2rem);
  border-left: 1px solid var(--rule);
}
.studio-meta__cell:first-child { border-left: none; }
.studio-meta__label {
  font-family: 'Montserrat', sans-serif;
  font-weight: 500;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: var(--track-eyebrow);
  color: var(--ash);
  margin: 0 0 clamp(0.6rem, 1vw, 1rem);
}
.studio-meta__value {
  font-family: 'Cormorant Garamond', serif;
  font-weight: 500;
  font-size: clamp(1rem, 1.3vw, 1.35rem);
  line-height: 1.35;
  letter-spacing: -0.008em;
  color: var(--paper);
  margin: 0;
}
.studio-meta__value em {
  font-style: italic;
  font-weight: 400;
}

@media (max-width: 880px) {
  .studio-meta__grid { grid-template-columns: repeat(2, 1fr); }
  .studio-meta__cell:nth-child(3) { border-left: none; }
  .studio-meta__cell:nth-child(3),
  .studio-meta__cell:nth-child(4) { border-top: 1px solid var(--rule); }
}
@media (max-width: 520px) {
  .studio-meta__grid { grid-template-columns: 1fr; }
  .studio-meta__cell {
    border-left: none !important;
    border-top: 1px solid var(--rule);
    padding: clamp(1.25rem, 4vw, 1.75rem) clamp(0.25rem, 1vw, 1rem);
  }
  .studio-meta__cell:first-child { border-top: none; }
}

/* ── Founder intro (portrait + bio) ──────────────────────────── */
.founder-intro {
  position: relative;
  z-index: 4;
  padding-block: clamp(5rem, 10vw, 11rem);
  padding-inline: var(--gutter);
}
.founder-intro__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.85fr);
  gap: clamp(3rem, 6vw, 6rem);
  max-width: 92rem;
  margin: 0 auto;
  align-items: center;
}
.founder-intro__copy {
  max-width: 52ch;
}
.founder-intro__eyebrow {
  margin: 0 0 clamp(1.25rem, 2vw, 2rem);
}
.founder-intro__title {
  font-family: 'Cormorant Garamond', serif;
  font-weight: 500;
  font-size: clamp(2.5rem, 5.5vw, 5rem);
  line-height: 1.0;
  letter-spacing: -0.022em;
  color: var(--paper);
  margin: 0 0 clamp(1.75rem, 2.5vw, 2.5rem);
}
.founder-intro__title em {
  font-style: italic;
  font-weight: 400;
}
.founder-intro__body {
  font-family: 'Inter', sans-serif;
  font-size: clamp(0.98rem, 1.05vw, 1.1rem);
  line-height: 1.7;
  color: var(--paper);
  opacity: 0.88;
  margin: 0 0 clamp(1rem, 1.5vw, 1.5rem);
  max-width: 52ch;
}
.founder-intro__body em {
  font-style: italic;
  color: var(--paper);
  opacity: 1;
}
.founder-intro__body:last-of-type { margin-bottom: 0; }

/* Portrait placeholder — dark editorial frame with a faint CC
   monogram and a hairline grid texture. Looks intentional, not
   broken. When the real image drops in, the inner -frame contents
   are replaced; outer layout doesn't shift (aspect-ratio holds). */
.founder-intro__portrait {
  position: relative;
  aspect-ratio: 4 / 5;
  border: 1px solid var(--rule-3);
  background:
    radial-gradient(ellipse 85% 60% at 50% 32%,
      rgba(241, 236, 227, 0.07), transparent 65%),
    linear-gradient(155deg, #16161c 0%, #0c0c10 55%, #0a0a0c 100%);
  overflow: hidden;
}
.founder-intro__portrait-frame {
  position: absolute;
  inset: 1px;
  display: grid;
  place-items: center;
  background-image:
    linear-gradient(0deg,  transparent 49.6%, rgba(241,236,227,0.035) 50%, transparent 50.4%),
    linear-gradient(90deg, transparent 49.6%, rgba(241,236,227,0.035) 50%, transparent 50.4%);
  background-size: 32px 32px;
}
.founder-intro__portrait-monogram {
  font-family: 'Cormorant Garamond', serif;
  font-style: italic;
  font-weight: 500;
  font-size: clamp(5rem, 11vw, 8.5rem);
  line-height: 1;
  color: var(--paper);
  opacity: 0.16;
  letter-spacing: -0.06em;
}
.founder-intro__portrait-caption {
  position: absolute;
  bottom: clamp(1.25rem, 2.4vw, 1.85rem);
  left: 50%;
  transform: translateX(-50%);
  font-family: 'Cormorant Garamond', serif;
  font-style: italic;
  font-size: clamp(0.78rem, 0.9vw, 0.9rem);
  color: var(--ash);
  letter-spacing: 0.04em;
  white-space: nowrap;
}

@media (max-width: 820px) {
  .founder-intro__grid {
    grid-template-columns: 1fr;
    gap: clamp(2.5rem, 5vw, 4rem);
  }
  .founder-intro__portrait {
    max-width: 22rem;
    margin: 0 auto;
    width: 100%;
  }
}

/* ── Services grid — "What I do" ────────────────────────────── */
.services {
  position: relative;
  z-index: 4;
  padding-block: clamp(4rem, 8vw, 9rem);
  padding-inline: var(--gutter);
}
.services__header {
  text-align: center;
  max-width: 60rem;
  margin: 0 auto clamp(3rem, 5vw, 5rem);
}
.services__eyebrow {
  margin: 0 0 clamp(1rem, 1.5vw, 1.5rem);
}
.services__title {
  font-family: 'Cormorant Garamond', serif;
  font-weight: 500;
  font-size: clamp(2.5rem, 5.5vw, 5rem);
  line-height: 1.05;
  letter-spacing: -0.022em;
  color: var(--paper);
  margin: 0;
}
.services__title em {
  font-style: italic;
  font-weight: 400;
}
.services__grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  max-width: 92rem;
  margin: 0 auto;
  border-top: 1px solid var(--rule-2);
  border-left: 1px solid var(--rule-2);
}
.services__cell {
  padding: clamp(2rem, 3.5vw, 3.5rem);
  border-right: 1px solid var(--rule-2);
  border-bottom: 1px solid var(--rule-2);
  position: relative;
}
.services__cell-num {
  display: block;
  font-family: 'Montserrat', sans-serif;
  font-weight: 500;
  font-size: 0.7rem;
  letter-spacing: var(--track-eyebrow);
  color: var(--ash);
  margin: 0 0 clamp(2rem, 3.5vw, 4rem);
}
.services__cell-title {
  font-family: 'Cormorant Garamond', serif;
  font-weight: 500;
  font-size: clamp(1.5rem, 2.4vw, 2.25rem);
  line-height: 1.15;
  letter-spacing: -0.015em;
  color: var(--paper);
  margin: 0 0 clamp(1rem, 1.5vw, 1.5rem);
}
.services__cell-body {
  font-family: 'Inter', sans-serif;
  font-size: clamp(0.92rem, 1vw, 1rem);
  line-height: 1.65;
  color: var(--paper);
  opacity: 0.78;
  margin: 0;
  max-width: 38ch;
}
.services__cell-body em {
  font-style: italic;
  color: var(--paper);
  opacity: 1;
}

@media (max-width: 720px) {
  .services__grid { grid-template-columns: 1fr; }
}

/* ──────────────────────────────────────────────────────────────
   61. CINEMATIC IRIS-WIPE IMAGE REVEAL (v=78)

   Editorial film-aperture reveal. Any element with the attribute
   `data-image-reveal` starts CLIPPED FROM THE RIGHT (invisible),
   slightly zoomed (1.06×), and opacity 0. When IntersectionObserver
   detects it crossing the viewport, the JS adds `.is-revealed` and
   the element ANIMATES OPEN:

       0ms       opacity fade-in (320ms ease-cinema)
       0ms       clip-path sweeps L→R, revealing the image
                 (1100ms — cubic-bezier(0.65, 0.05, 0.36, 1))
       0ms       scale settles 1.06 → 1.0 (1400ms ease-house)
       1400ms    fully resolved, will-change released

   Inspired by the cinema "iris wipe" — the camera aperture opening
   at the start of a scene. Pairs with the chapter-plate language:
   both speak the editorial-film-cut grammar. No glitch, no
   chromatic, no decoration — pure clean cinema.

   OPT-IN ONLY — applied via `data-image-reveal` attribute. Doesn't
   conflict with the existing `.media-reveal` blur system; the two
   can coexist on different elements (or the same one, though
   stacking is discouraged).

   Future Sierra images: just add `data-image-reveal` to the <img>
   (or <picture>, or any wrapper) and it inherits the same reveal.
   No JS change needed — the boot pass picks up new elements via
   the existing IntersectionObserver query.

   prefers-reduced-motion is honored — element shows immediately
   with no animation.
   ────────────────────────────────────────────────────────────── */
[data-image-reveal] {
  opacity: 0;
  transform: scale(1.06);
  clip-path: inset(0 100% 0 0);
  transition:
    opacity   320ms  var(--ease-cinema),
    transform 1400ms var(--ease-house),
    clip-path 1100ms cubic-bezier(0.65, 0.05, 0.36, 1);
  will-change: transform, opacity, clip-path;
}
[data-image-reveal].is-revealed {
  opacity: 1;
  transform: scale(1);
  clip-path: inset(0 0 0 0);
}

@media (max-width: 720px) {
  /* Slightly less dramatic scale settle on mobile so the entry
     doesn't push surrounding content during the animation. */
  [data-image-reveal] {
    transform: scale(1.03);
  }
}

@media (prefers-reduced-motion: reduce) {
  [data-image-reveal] {
    opacity: 1 !important;
    transform: none !important;
    clip-path: none !important;
    transition: none !important;
  }
}

/* ──────────────────────────────────────────────────────────────
   62. END CREDITS PLATE (v=79)

   The most cinematic closing card on the site. Lives at the
   bottom of every public-facing page. When it scrolls into view,
   a SEVEN-BEAT CASCADE fires over ~1.5 seconds:

     0ms      top rule draws open (560ms ease-cinema)
     180ms    "Directed by" eyebrow fades + rises (360ms)
     320ms    "Cam Carroll." italic rises (460ms)
     500ms    signature line settles (380ms)
     680ms    MMXXVI year crystallizes (420ms)
     840ms    bottom rule draws open (560ms)
     1080ms   "Fin." closes the act (420ms)
     1500ms   cascade complete

   Speaks the same editorial-film grammar as the chapter plates
   and the iris-wipe image reveal — same Cormorant italic, same
   hairline rules, same ease-cinema curves. The visitor reads
   it as the language the site speaks, not decoration tacked on.

   Distinctive: almost no studios end their site with a credits
   card. The ones that do (Pentagram, Wallpaper-tier publications)
   are the ones visitors remember. We're betting that's worth
   the 80 lines of CSS.

   prefers-reduced-motion: cascade is disabled, plate appears
   immediately in its final state.
   ────────────────────────────────────────────────────────────── */
.credits {
  position: relative;
  z-index: 4;
  padding-block: clamp(5rem, 10vw, 11rem);
  background: var(--ink);
  text-align: center;
  border-top: 1px solid var(--rule);
}

.credits__inner {
  max-width: 56rem;
  margin: 0 auto;
  padding-inline: var(--gutter);
  display: flex;
  flex-direction: column;
  align-items: center;
}

/* Hairline rules — animate width 0 → target. The top draws
   FIRST, the bottom draws near the end of the cascade so the
   whole composition feels like it's bracketed open and closed. */
.credits__rule {
  display: block;
  height: 1px;
  width: 0;
  background: var(--rule-3);
  transition: width 560ms var(--ease-cinema);
}

.credits__rule--top {
  margin-bottom: clamp(2rem, 3vw, 3rem);
}

.credits__rule--bottom {
  margin: clamp(2.5rem, 3.5vw, 3.5rem) 0 clamp(1.5rem, 2vw, 2rem);
  transition-delay: 840ms;
}

.credits.is-revealed .credits__rule {
  width: clamp(140px, 24vw, 320px);
}

/* "Directed by" eyebrow */
.credits__eyebrow {
  font-family: 'Montserrat', sans-serif;
  font-weight: 500;
  font-size: clamp(0.7rem, 0.85vw, 0.85rem);
  text-transform: uppercase;
  letter-spacing: 0.28em;
  color: var(--ash);
  margin: 0 0 clamp(1.25rem, 2vw, 1.75rem);
  opacity: 0;
  transform: translate3d(0, 8px, 0);
  transition:
    opacity   360ms var(--ease-cinema) 180ms,
    transform 480ms var(--ease-house)  180ms;
}
.credits.is-revealed .credits__eyebrow {
  opacity: 1;
  transform: translate3d(0, 0, 0);
}

/* "Cam Carroll." — the marquee. Cormorant 500 with italic surname. */
.credits__name {
  font-family: 'Cormorant Garamond', serif;
  font-weight: 500;
  font-size: clamp(2.5rem, 5vw, 4.5rem);
  letter-spacing: -0.022em;
  color: var(--paper);
  margin: 0 0 clamp(1.75rem, 2.5vw, 2.5rem);
  line-height: 1.0;
  opacity: 0;
  transform: translate3d(0, 14px, 0);
  transition:
    opacity   460ms var(--ease-cinema) 320ms,
    transform 560ms var(--ease-house)  320ms;
}
.credits__name em {
  font-style: italic;
  font-weight: 400;
}
.credits.is-revealed .credits__name {
  opacity: 1;
  transform: translate3d(0, 0, 0);
}

/* Signature line — Inter 400, max 38ch so the linebreak is tight. */
.credits__signature {
  font-family: 'Inter', sans-serif;
  font-weight: 400;
  font-size: clamp(0.95rem, 1.05vw, 1.08rem);
  line-height: 1.7;
  color: var(--paper);
  opacity: 0.92;
  margin: 0;
  max-width: 38ch;
  opacity: 0;
  transform: translate3d(0, 8px, 0);
  transition:
    opacity   380ms var(--ease-cinema) 500ms,
    transform 480ms var(--ease-house)  500ms;
}
.credits__signature em {
  font-style: italic;
  color: var(--paper);
  opacity: 1;
}
.credits.is-revealed .credits__signature {
  opacity: 1;
  transform: translate3d(0, 0, 0);
}

/* The year — italic Cormorant, ash, generous tracking. Reads
   like the credit-roll year stamp at the end of an A24 film. */
.credits__year {
  font-family: 'Cormorant Garamond', serif;
  font-weight: 500;
  font-style: italic;
  font-size: clamp(1.1rem, 1.5vw, 1.5rem);
  letter-spacing: 0.18em;
  color: var(--ash);
  margin: clamp(1.5rem, 2.5vw, 2.5rem) 0 0;
  opacity: 0;
  transform: translate3d(0, 10px, 0);
  transition:
    opacity   420ms var(--ease-cinema) 680ms,
    transform 520ms var(--ease-house)  680ms;
}
.credits.is-revealed .credits__year {
  opacity: 1;
  transform: translate3d(0, 0, 0);
}

/* "Fin." — the final beat. Italic Cormorant, paper color.
   The site's last word. */
.credits__fin {
  font-family: 'Cormorant Garamond', serif;
  font-weight: 500;
  font-style: italic;
  font-size: clamp(1.4rem, 2vw, 2rem);
  color: var(--paper);
  margin: 0;
  letter-spacing: 0.04em;
  opacity: 0;
  transform: translate3d(0, 6px, 0);
  transition:
    opacity   420ms var(--ease-cinema) 1080ms,
    transform 520ms var(--ease-house)  1080ms;
}
.credits.is-revealed .credits__fin {
  opacity: 1;
  transform: translate3d(0, 0, 0);
}

@media (prefers-reduced-motion: reduce) {
  .credits .credits__eyebrow,
  .credits .credits__name,
  .credits .credits__signature,
  .credits .credits__year,
  .credits .credits__fin {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
  .credits .credits__rule {
    width: clamp(140px, 24vw, 320px) !important;
    transition: none !important;
  }
}

/* ═════════════════════════════════════════════════════════════════
   70. ARCHIVE — TWO-ACT RESTRUCTURE (v=85)
   ═════════════════════════════════════════════════════════════════
   The archive page is reframed as a two-act editorial spread:

     ACT I · THE INDEX
       Filter pills + 10 project cards on top. The concrete browsable
       lineup — visitor lands, scans, filters.
       [ cinematic chapter plate transition — II · In Orbit ]
     ACT II · IN ORBIT
       The draggable 3D globe below. Editorial header above,
       full-bleed 100svh stage. Reveals cinematically as visitor
       scrolls into view: canvas fades in over 1200ms while camera
       lerps distance/yaw/pitch from a far-tilted starting position
       into home. Drag hint arrives 1000ms after canvas.

   Inverts the v=68 "sphere-first, grid-below" pattern that made
   the sphere feel like friction. The old §61 + §68 rules are
   OVERRIDDEN below via more specific selectors + later source
   order (rather than deleted) so the sphere-first pattern can be
   reverted in one commit if we ever need it.
   ═════════════════════════════════════════════════════════════════ */

/* ── Neutralize the old sphere-first positioning ────────────── */
body.archive-with-index .archive {
  min-height: auto;
  overflow: visible;
  display: block;   /* was flow-root — no BFC needed anymore */
}
/* Old rule positioned canvas at top of .archive — now scoped
   inside the stage, so this default is reset. The stage-scoped
   rules below take precedence via specificity. */
body.archive-with-index .archive__canvas {
  position: static;
  width: auto;
  height: auto;
}
/* Old rule pushed .archive__index below the 100svh sphere zone.
   No longer needed — index sits at natural top of flow now. */
body.archive-with-index .archive__index {
  margin-top: 0;
}
/* Retire the old "↓ Editorial index" desktop cue that pointed
   at the section (the section IS the top of the page now). */
body.archive-with-index .archive__index::before {
  content: none !important;
}

/* ── Act I · The Index — subtle atmospheric refinement ─────── */
.archive__index {
  /* Override §61's v=68 default that hid the section until archive.js
     added body.archive-with-index. In v=85 Act I is the LANDING —
     visible on first paint regardless of body class. */
  display: block;
  /* Guarantee Act I is always at least viewport-tall so the chapter
     plate anchor (which sits between the two acts) is always below
     the fold at page load — even before archive.js has populated
     the grid. Without this, the plate would fire immediately at
     boot when scripts.js registers its IntersectionObserver on a
     grid that's still empty (race between scripts.js DOMContentLoaded
     boot and archive.js window.load start). */
  min-height: 100svh;
  padding:
    clamp(6rem, 12vw, 10rem)
    clamp(1.25rem, 4vw, 2rem)
    clamp(5rem, 10vw, 7rem);
  background:
    radial-gradient(ellipse 100% 40% at 50% 0%, rgba(241, 236, 227, 0.028), transparent 55%),
    var(--ink);
}
/* Body-scoped padding override — some earlier rules may set
   different padding under body.archive-with-index. Repeat here
   to guarantee we win specificity. */
body.archive-with-index .archive__index {
  padding:
    clamp(6rem, 12vw, 10rem)
    clamp(1.25rem, 4vw, 2rem)
    clamp(5rem, 10vw, 7rem);
}

/* ── The "Or scroll for a view in orbit ↓" anchor cue ───────
   Sits below the index header rule. Italic Cormorant, ash color,
   hairline underline draws open on hover, gold arrow bobs at
   3.2s cycle to draw the eye downward. Click smooth-scrolls to
   #orbit (see archive.js initJumpLink).
   ────────────────────────────────────────────────────────────── */
.archive__jump {
  display: inline-flex;
  align-items: baseline;
  gap: 0.65em;
  margin-top: clamp(1.5rem, 2.5vw, 2.25rem);
  padding: 0.35rem 0.15rem 0.5rem;
  position: relative;
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-weight: 500;
  font-size: clamp(0.95rem, 1.15vw, 1.15rem);
  letter-spacing: -0.005em;
  color: var(--paper-3);
  text-decoration: none;
  cursor: pointer;
  transition: color var(--dur-base) var(--ease-house);
}
.archive__jump-label {
  display: inline;
}
.archive__jump-label em {
  font-style: italic;
  color: var(--paper);
}
.archive__jump-arrow {
  display: inline-block;
  color: var(--gold);
  font-style: normal;
  font-size: 1.05em;
  line-height: 1;
  transition: transform 480ms var(--ease-house);
  animation: archive-jump-bob 3.2s ease-in-out infinite;
}
@keyframes archive-jump-bob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(4px); }
}
.archive__jump::after {
  content: "";
  position: absolute;
  left: 0.15rem;
  right: 0.15rem;
  bottom: 0.2rem;
  height: 1px;
  background: currentColor;
  transform-origin: left center;
  transform: scaleX(0.18);
  opacity: 0.5;
  transition:
    transform var(--dur-base) var(--ease-house),
    opacity   var(--dur-base) var(--ease-house);
}
.archive__jump:hover,
.archive__jump:focus-visible {
  color: var(--paper);
  outline: none;
}
.archive__jump:hover::after,
.archive__jump:focus-visible::after {
  transform: scaleX(1);
  opacity: 1;
}
.archive__jump:hover .archive__jump-arrow,
.archive__jump:focus-visible .archive__jump-arrow {
  transform: translateY(8px);
  animation: none;
}
@media (prefers-reduced-motion: reduce) {
  .archive__jump-arrow { animation: none !important; }
}

/* ── Act II · In Orbit — the draggable globe below ─────────── */
.archive__orbit {
  position: relative;
  z-index: 4;
  padding-block: clamp(4rem, 8vw, 7rem) 0;
  background:
    radial-gradient(ellipse 100% 50% at 50% 0%, rgba(203, 178, 106, 0.055), transparent 65%),
    radial-gradient(ellipse 80% 60% at 50% 100%, rgba(241, 236, 227, 0.022), transparent 65%),
    var(--ink);
  border-top: 1px solid var(--rule);
}

/* Editorial header ABOVE the sphere. Sits above stage in z-index
   so it never gets occluded by canvas. Reveal via .reveal + IO. */
.archive__orbit-header {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(0.85rem, 2vw, 1.25rem);
  text-align: center;
  padding: 0 clamp(1.25rem, 4vw, 2rem);
  margin: 0 auto clamp(2rem, 4vw, 3rem);
  max-width: 76rem;
  position: relative;
  z-index: 6;
}
.archive__orbit-eyebrow {
  font-family: 'Inter', sans-serif;
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.42em;
  text-transform: uppercase;
  color: var(--gold);
  opacity: 0.92;
}
.archive__orbit-title {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-weight: 400;
  font-size: clamp(2rem, 5vw, 3.75rem);
  line-height: 1.02;
  letter-spacing: -0.022em;
  color: var(--paper);
  margin: 0;
  max-width: 20ch;
}
.archive__orbit-title em { font-style: italic; }
.archive__orbit-sub {
  font-family: 'Inter', sans-serif;
  font-size: clamp(0.72rem, 0.92vw, 0.88rem);
  font-weight: 500;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--ash);
  margin: 0;
  line-height: 1.6;
}
.archive__orbit-sub-sep {
  color: var(--rule-3);
  margin: 0 0.25em;
}

/* ── The 100svh stage that holds the sphere + overlays ─────── */
.archive__orbit-stage {
  position: relative;
  width: 100%;
  height: 100svh;
  min-height: 500px;
  overflow: hidden;
}

/* Canvas — absolutely positioned inside the stage now, fading in
   from opacity 0 when stage.is-in-view. This selector is more
   specific than the old §54 rules so it wins by specificity. */
body.archive-with-index .archive__orbit-stage > .archive__canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 1;
  cursor: grab;
  display: block;
  background: transparent;
  opacity: 0;
  transition: opacity 1200ms var(--ease-cinema);
}
body.archive-with-index .archive__orbit-stage.is-in-view > .archive__canvas {
  opacity: 1;
}
body.archive-with-index .archive__orbit-stage > .archive__canvas.is-grabbing { cursor: grabbing; }
body.archive-with-index .archive__orbit-stage > .archive__canvas.is-hovering { cursor: pointer; }
body.archive-with-index .archive__orbit-stage > .archive__canvas.is-flying   { cursor: progress; }
body.has-custom-cursor .archive__orbit-stage > .archive__canvas,
body.has-custom-cursor .archive__orbit-stage > .archive__canvas.is-grabbing,
body.has-custom-cursor .archive__orbit-stage > .archive__canvas.is-hovering {
  cursor: none;
}

/* Live readout pill — positioned at bottom-center of the stage.
   Fades in 500ms AFTER canvas begins revealing so the sphere
   arrives on screen before the metadata pill does. Hidden on
   mobile (touch has no hover — the grid already labels every card). */
body.archive-with-index .archive__orbit-stage > .archive__readout {
  position: absolute;
  bottom: clamp(1.75rem, 4vh, 3rem);
  left: 50%;
  transform: translateX(-50%);
  top: auto;
  z-index: 6;
  opacity: 0;
  transition: opacity 900ms var(--ease-cinema) 500ms;
}
body.archive-with-index .archive__orbit-stage.is-in-view > .archive__readout {
  opacity: 1;
}
@media (max-width: 767px) {
  body.archive-with-index .archive__orbit-stage > .archive__readout {
    display: none !important;
  }
}

/* Drag hint — center of stage. Reveals 1000ms AFTER canvas begins
   fading in, giving the visitor a beat to see the sphere before
   being prompted to interact. Uses existing archive-hint-arrive
   keyframe from §54 (arrive from center + slight fade). */
body.archive-with-index .archive__orbit-stage > .archive__hint {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 5;
  opacity: 0;
  animation: none;
}
body.archive-with-index .archive__orbit-stage.is-in-view > .archive__hint {
  animation: archive-hint-arrive 900ms cubic-bezier(0.16, 1, 0.3, 1) 1000ms forwards;
}

/* Footer below the stage — closing "More, forthcoming." beat. */
.archive__orbit-footer {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(1rem, 3vw, 1.5rem);
  padding: clamp(3rem, 6vw, 5rem) clamp(1.25rem, 4vw, 2rem);
  max-width: 76rem;
  margin: 0 auto;
}

/* Mobile refinements */
@media (max-width: 720px) {
  .archive__orbit {
    padding-block: clamp(3rem, 6vw, 5rem) 0;
  }
  .archive__orbit-header {
    margin-bottom: clamp(1.5rem, 3vw, 2rem);
  }
  .archive__orbit-title {
    font-size: clamp(1.75rem, 7vw, 2.5rem);
  }
  .archive__orbit-sub {
    font-size: clamp(0.68rem, 2.4vw, 0.78rem);
    letter-spacing: 0.28em;
  }
  .archive__jump {
    font-size: clamp(0.95rem, 3.6vw, 1.05rem);
  }
}
@media (prefers-reduced-motion: reduce) {
  /* Reveal instantly — no cinematic camera-in wait */
  body.archive-with-index .archive__orbit-stage > .archive__canvas,
  body.archive-with-index .archive__orbit-stage > .archive__readout {
    opacity: 1 !important;
    transition: none !important;
  }
}
