/* ============================================================
   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
   ───────────────────────────────────────────────────────────── */
::-webkit-scrollbar         { width: 10px; height: 10px; }
::-webkit-scrollbar-track   { background: var(--ink); }
::-webkit-scrollbar-thumb   { background: var(--ink-4); border-radius: 8px; border: 2px solid var(--ink); }
::-webkit-scrollbar-thumb:hover { background: var(--ash-2); }

/* ─────────────────────────────────────────────────────────────
   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);
}
.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 hello@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.
   ───────────────────────────────────────────────────────────── */
.page-curtain {
  position: fixed;
  inset: 0;
  z-index: 99999;
  background: var(--ink);
  pointer-events: none;
  opacity: 0;
  transition: opacity 480ms var(--ease-cinema);
}
/* Incoming page — curtain starts opaque, fades to transparent.
   The html.has-incoming-curtain class is set in the inline head
   script (before first paint) so there's no flash of unstyled page. */
html.has-incoming-curtain .page-curtain {
  opacity: 1;
}
html.has-incoming-curtain.curtain-rising .page-curtain {
  opacity: 0;
}
@media (prefers-reduced-motion: reduce) {
  .page-curtain { transition: opacity 1ms; }
}

/* ─────────────────────────────────────────────────────────────
   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().

   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. */
body:has(.preloader),
body.preloader-active {
  overflow: hidden;
  overscroll-behavior: none;
}
html.preloaded .preloader { display: none; }

/* 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 Uxbridge), 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; }
