/* ============================================================
   Standard Frontier — shared styles
   Sections: tokens · reset · aurora · chrome · type · home ·
             essay · join · footer · cursor · motion · responsive
   ============================================================ */

:root {
  --bg:        #060503;   /* near-black, faintly warm */
  --ink:       #f4ede2;   /* warm off-white */
  --ink-dim:   #9b9388;   /* muted text */
  --ink-faint: #5d564d;   /* micro labels */
  --ember:     #6598FF;   /* signature blue (accent) */
  --gold:      #ffc56b;
  --line:      rgba(244, 237, 226, 0.10);

  --gutter: clamp(1.25rem, 4.5vw, 4.5rem);

  --px: 0px;   /* parallax, set by site.js */
  --py: 0px;

  /* Pre-rasterised film-grain tile (150×150, rasterised once then repeated).
     Used by the desktop grain layer AND the mobile stage. This replaces the
     old full-viewport live <feTurbulence> grain, which was a GPU-memory hog. */
  --noise: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='150' height='150'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='1.7' intercept='-0.35'/%3E%3CfeFuncG type='linear' slope='1.7' intercept='-0.35'/%3E%3CfeFuncB type='linear' slope='1.7' intercept='-0.35'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='150' height='150' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* LT Superior Serif — self-hosted, the body typeface (everything but the
   "Standard Frontier" wordmark, which stays in Familjen Grotesk). */
@font-face {
  font-family: "Superior Serif";
  src: url("fonts/LTSuperiorSerif-Regular.otf") format("opentype");
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Superior Serif";
  src: url("fonts/LTSuperiorSerif-Medium.otf") format("opentype");
  font-weight: 500; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Superior Serif";
  src: url("fonts/LTSuperiorSerif-Semibold.otf") format("opentype");
  font-weight: 600; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Superior Serif";
  src: url("fonts/LTSuperiorSerif-Bold.otf") format("opentype");
  font-weight: 700; font-style: normal; font-display: swap;
}

/* PP Mondwest — self-hosted, for small details: micro-labels, coordinates,
   one-line notes, buttons. */
@font-face {
  font-family: "PP Mondwest";
  src: url("fonts/ppmondwest-regular.otf") format("opentype");
  font-weight: 400; font-style: normal; font-display: swap;
}

* { margin: 0; padding: 0; box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  min-height: 100svh;
  background: var(--bg);
  color: var(--ink);
  font-family: "Superior Serif", Georgia, serif;
  font-synthesis: none;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  position: relative;
}
body.hold { overflow: hidden; }          /* single-screen pages (home) */

a { color: inherit; }
::selection { background: rgba(101, 152, 255, 0.28); color: #fff; }

/* ─────────────────────────────  AURORA  ─────────────────────────────
   Injected by site.js. Built from individually-placed, heavily-blurred
   amber lobes so the light merges like lit silk, not a flat gradient.   */

.stage {
  position: fixed;
  inset: -10%;
  z-index: 0;
  transform: translate3d(var(--px), var(--py), 0);
  transition: transform 1.2s cubic-bezier(.16, 1, .3, 1);
  will-change: transform;
}
.lobe, .fold {
  position: absolute;
  border-radius: 50%;
  mix-blend-mode: screen;
  opacity: 0;
  animation: bloom 1.8s cubic-bezier(.22, 1, .36, 1) forwards;
}
.fold { border-radius: 46%; }
@keyframes bloom { to { opacity: 1; } }

/* .drift fills the stage and carries the gentle parallax/drift transform.
   No filter: the old full-viewport feDisplacementMap warp was removed because
   it allocated huge GPU buffers and re-rasterised on every animation frame
   (the browser-crash cause). The blurred lobes alone still read as a soft
   dusty aurora — which is exactly what desktop Safari already showed, since
   the warp was disabled there for an unrelated rendering bug.               */
.drift { position: absolute; inset: 0; }

/* Broad ambient lobes — the wash. Sized in vmax so the field scales with the
   screen and stays dense (no dark gaps) on wide monitors.                    */
/* Sizes/positions are unchanged (vmax) so the composition fills the screen
   exactly as designed. Only the BLUR is capped in px via min(): on normal
   screens the vmax value wins (look unchanged), but on 4K/5K monitors the px
   cap stops the blur radius — and the layer's backing store — from growing
   without bound. Combined with the removed warp filter + static grain, that
   keeps GPU memory in check so the tab no longer crashes on big displays.    */
.lobe.l1 { width: 90vmax; height: 90vmax; right: -19vmax; top: -34vmax;
  background: radial-gradient(closest-side,
    rgba(255,197,107,.82), rgba(101,152,255,.42) 42%, transparent 74%);
  filter: blur(min(6.4vmax, 120px)); animation-delay: .05s; }
.lobe.l2 { width: 98vmax; height: 98vmax; left: -30vmax; top: -14vmax;
  background: radial-gradient(closest-side,
    rgba(101,152,255,.48), rgba(40,80,180,.2) 46%, transparent 76%);
  filter: blur(min(7.6vmax, 132px)); animation-delay: .12s; }
.lobe.l3 { width: 82vmax; height: 82vmax; left: 36%; bottom: -45vmax;
  background: radial-gradient(closest-side,
    rgba(120,165,255,.46), rgba(30,84,190,.18) 48%, transparent 76%);
  filter: blur(min(7.2vmax, 128px)); animation-delay: .18s; }

/* Overlapping elongated ribbons — layered flow lines for depth.              */
.fold.f1 { width: 133vmax; height: 26vmax; left: -9vmax; top: 5.5vmax;
  transform: rotate(-16deg);
  background: radial-gradient(closest-side,
    rgba(150,185,255,.55), rgba(58,118,232,.2) 46%, transparent 76%);
  filter: blur(min(4.4vmax, 80px)); animation-delay: .3s; }
.fold.f2 { width: 125vmax; height: 23vmax; left: -20vmax; top: 23vmax;
  transform: rotate(-23deg);
  background: radial-gradient(closest-side,
    rgba(255,210,140,.42), rgba(120,120,200,.16) 48%, transparent 78%);
  filter: blur(min(4.7vmax, 84px)); animation-delay: .24s; }
.fold.f3 { width: 121vmax; height: 23vmax; left: -5vmax; top: 37vmax;
  transform: rotate(-11deg);
  background: radial-gradient(closest-side,
    rgba(110,160,255,.5), rgba(40,96,210,.18) 47%, transparent 77%);
  filter: blur(min(4.8vmax, 86px)); animation-delay: .36s; }
.fold.f4 { width: 113vmax; height: 22vmax; left: 17vmax; top: -4vmax;
  transform: rotate(-27deg);
  background: radial-gradient(closest-side,
    rgba(150,185,255,.5), rgba(58,118,232,.18) 46%, transparent 76%);
  filter: blur(min(4vmax, 72px)); animation-delay: .42s; }

/* ── Per-page siblings — same family, slightly different light ──────────────
   Home (.pg-home) is the base above; the rest nudge composition + warmth.    */

/* Manifesto — cooler and a touch quieter behind the long read. */
.pg-manifesto .stage { opacity: .82; }
.pg-manifesto .lobe.l1 { right: -27vmax; top: -40vmax;
  background: radial-gradient(closest-side,
    rgba(176,198,255,.5), rgba(101,152,255,.34) 44%, transparent 76%); }
.pg-manifesto .lobe.l3 { left: 26%; bottom: -38vmax; }
.pg-manifesto .fold.f2 {
  background: radial-gradient(closest-side,
    rgba(150,180,255,.4), rgba(90,120,210,.16) 48%, transparent 78%); }

/* Partners — warmer; more gold pushed through the waves. */
.pg-partner .lobe.l1 { right: -12vmax; top: -26vmax;
  background: radial-gradient(closest-side,
    rgba(255,188,96,.9), rgba(255,150,86,.4) 36%, rgba(101,152,255,.26) 62%, transparent 78%); }
.pg-partner .fold.f2 {
  background: radial-gradient(closest-side,
    rgba(255,206,132,.55), rgba(150,128,200,.18) 48%, transparent 78%); }
.pg-partner .lobe.l3 { left: 40%; bottom: -42vmax; }

/* Join — light pooled lower-right on a steeper diagonal. */
.pg-join .lobe.l1 { right: -20vmax; top: -12vmax; }
.pg-join .lobe.l3 { left: 46%; bottom: -50vmax; }
.pg-join .fold.f1 { transform: rotate(-24deg); top: 2vmax; }
.pg-join .fold.f3 { transform: rotate(-19deg); top: 31vmax; }
.pg-join .fold.f4 { transform: rotate(-31deg); }

@media (prefers-reduced-motion: no-preference) {
  .drift { animation: drift 34s ease-in-out infinite alternate; }
}
/* Translate only — NO scale. A scale forces the browser to re-rasterise the
   blurred lobes every frame (expensive + memory-churny); a pure translate just
   slides the already-rendered layer on the compositor (cheap, GPU-only).      */
@keyframes drift {
  0%   { transform: translate3d(0, 0, 0); }
  100% { transform: translate3d(-2.5%, 1.5%, 0); }
}

body.subdue .stage { opacity: 0.55; }   /* dim aurora behind long text */

.vignette {
  position: fixed; inset: 0; z-index: 1; pointer-events: none;
  background:
    radial-gradient(135% 110% at 92% 55%, transparent 42%, rgba(6,5,3,0.4) 82%, var(--bg) 100%),
    linear-gradient(95deg, var(--bg) 19%, rgba(6,5,3,0.82) 35%, rgba(6,5,3,0.2) 56%, transparent 68%);
}

/* One grain layer: a repeating pre-rasterised noise tile (--noise), not a live
   full-viewport <feTurbulence>. mix-blend-mode lets it bite the lit aurora
   beneath it, same as before — but at a fraction of the memory/paint cost. */
.grain {
  position: fixed; inset: 0; z-index: 2; pointer-events: none;
  background-image: var(--noise);
  background-size: 150px 150px;
  background-repeat: repeat;
  opacity: .55; mix-blend-mode: overlay;
}

/* ─────────────────────────────  SHELL + CHROME  ───────────────────── */

.shell {
  position: relative;
  z-index: 3;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  padding: var(--gutter);
}

.micro {
  font-family: "Superior Serif", Georgia, serif;
  font-size: 0.72rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

header {
  display: flex;
  align-items: baseline;   /* align the brand + nav by text baseline so they sit on one line
                              (centering let the nav's underline padding nudge it ~1px off) */
  justify-content: space-between;
  gap: 1.5rem;
}
.mark {
  display: inline-flex; align-items: center; gap: 0.65rem;
  text-decoration: none; color: var(--ink);
  transition: translate .35s cubic-bezier(.16,1,.3,1);
}
.mark .glyph { width: 22px; height: 22px; color: var(--ember); display: block; }
.mark .name { font-family: "Familjen Grotesk", system-ui, sans-serif; font-weight: 500; font-size: 0.98rem; letter-spacing: 0.01em; }

.nav { display: flex; gap: clamp(1.2rem, 2.6vw, 2.4rem); }
.nav a {
  color: #fff; text-decoration: none;
  font-family: "Superior Serif", Georgia, serif;   /* nav in the body serif */
  font-size: 0.98rem; letter-spacing: -0.01em;
  position: relative; padding-bottom: 3px; transition: color .4s;
}
.nav a::after {
  content: ""; position: absolute; left: 0; bottom: 0;
  height: 1px; width: 100%; background: var(--ink);
  transform: scaleX(0); transform-origin: left;
  transition: transform .45s cubic-bezier(.7,0,.2,1);
}
.nav a:hover { color: #fff; }
.nav a:hover::after { transform: scaleX(1); }
.nav a[aria-current="page"] { color: #fff; }
.nav a[aria-current="page"]::after { transform: scaleX(1); background: var(--ember); }

/* ─────────────────────────────  TYPE + ACTIONS  ───────────────────── */

.wordmark {
  font-family: "Familjen Grotesk", system-ui, sans-serif;
  font-weight: 500;
  font-size: clamp(3.1rem, 11.5vw, 10rem);
  line-height: 0.9; letter-spacing: -0.035em;
  color: var(--ink); text-wrap: balance;
}
.wordmark .row { display: block; }
.wordmark .row.two { color: transparent; -webkit-text-stroke: 1px rgba(244,237,226,0.85); }

.lead {
  font-family: "PP Mondwest", "Familjen Grotesk", system-ui, sans-serif;
  font-weight: 500;
  font-size: clamp(1.6rem, 4.16vw, 3.04rem);
  line-height: 1.05; letter-spacing: -0.03em;
  max-width: 20ch; text-wrap: balance;
}
.heading-body { color: #fff; }   /* match the body prose colour */
.kicker { color: var(--ember); margin-bottom: clamp(1.4rem, 3vw, 2.2rem); }

.lede {
  max-width: 34ch;
  font-size: clamp(0.5rem, 0.75vw, 0.61rem);
  line-height: 1.45; color: #fff; font-weight: 400;
}
.sub {
  max-width: 50ch;
  font-size: clamp(1rem, 1.15vw, 1.5rem);
  line-height: 1.5; color: #fff;
}

/* underline-wipe text link (primary CTA) */
.cta {
  display: inline-flex; align-items: baseline; gap: 0.7rem;
  font-family: "Familjen Grotesk", system-ui, sans-serif;
  color: var(--ink); text-decoration: none;
  font-size: 1.02rem; letter-spacing: -0.01em;
  position: relative; padding-bottom: 4px;
  transition: translate .35s cubic-bezier(.16,1,.3,1);
}
.cta::after {
  content: ""; position: absolute; left: 0; bottom: 0;
  width: 100%; height: 1px; background: var(--ink);
  transform: scaleX(1); transform-origin: right;
  transition: transform .55s cubic-bezier(.7,0,.2,1);
}
.cta:hover::after { transform: scaleX(0); transform-origin: left; }
.cta .arrow { color: #6598FF; transition: transform .55s cubic-bezier(.16,1,.3,1); }
.cta:hover .arrow { transform: translate(4px, -4px); }

/* invert-on-hover button (forms) */
.btn {
  display: inline-flex; align-items: center; gap: 0.65rem;
  padding: 0.9rem 1.5rem;
  border: 1px solid rgba(244,237,226,0.25); border-radius: 2px;
  background: transparent; color: var(--ink);
  font: inherit; font-family: "Familjen Grotesk", system-ui, sans-serif;
  font-size: 1rem; letter-spacing: -0.01em;
  cursor: pointer;
  transition: background .4s, color .4s, border-color .4s,
              translate .35s cubic-bezier(.16,1,.3,1);
}
.btn .arrow { color: #6598FF; transition: transform .5s cubic-bezier(.16,1,.3,1); }
.btn:hover { background: var(--ink); color: #0a0805; border-color: var(--ink); }
.btn:hover .arrow { color: #0a0805; transform: translate(3px, -3px); }

/* ─────────────────────────────  HOME LOCKUP  ──────────────────────── */

.hero { flex: 1 1 auto; }

.lockup {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: end;
  gap: 2rem;
}
.lockup .lede { margin-top: clamp(1.4rem, 3vw, 2.3rem); }
.lockup .cta  { margin-top: clamp(1.8rem, 3.4vw, 2.6rem); }

.meta { font-family: "PP Mondwest", "IBM Plex Mono", monospace; text-align: right; line-height: 1.95; }
.meta span { display: block; font-size: 0.864rem; }  /* 20% larger than .micro (0.72rem) */
.meta .accent { color: var(--ink-dim); }

/* ─────────────────────────────  ESSAY (MANIFESTO)  ─────────────────── */
/* Pure type — no rules, no dividers, no decoration. The words carry it.  */

.doc {
  flex: 1 1 auto;
  width: 100%;
  max-width: 820px;
  margin-top: clamp(3.5rem, 12vh, 9rem);
}

.essay { max-width: 800px; }
.essay .lead {
  font-size: clamp(1.76rem, 4.48vw, 3.36rem);
  max-width: 18ch;
  margin-bottom: clamp(2.2rem, 5.5vw, 3.6rem);
}
.prose p {
  font-family: "Superior Serif", Georgia, serif;
  color: #fff;
  font-size: clamp(1rem, 1.15vw, 1.5rem);
  line-height: 1.5;
  letter-spacing: 0.005em;
  max-width: 58ch;
  margin-bottom: clamp(1.5rem, 3vw, 2.2rem);
}
.prose p.end { color: #fff; }
.prose .punch { color: #fff; }
.essay > .cta { margin-top: clamp(2.6rem, 6vh, 4rem); }

/* ─────────────────────────────  JOIN  ─────────────────────────────── */

.form { display: grid; gap: 1.15rem; max-width: 460px; margin-top: clamp(2.5rem, 6vh, 3.5rem); }
.field label { display: block; margin-bottom: 0.55rem; color: var(--ink-faint); }
.field input, .field textarea {
  width: 100%;
  background: rgba(244,237,226,0.03);
  border: 1px solid var(--line); border-radius: 2px;
  color: var(--ink); font: inherit; font-size: 1rem;
  padding: 0.85rem 1rem; resize: vertical;
  transition: border-color .35s, background .35s;
}
.field input::placeholder, .field textarea::placeholder { color: var(--ink-faint); }
.field input:focus, .field textarea:focus {
  outline: none; border-color: rgba(101,152,255,0.7);
  background: rgba(244,237,226,0.05);
}
.form .btn { justify-self: start; margin-top: 0.4rem; }
.form-note { letter-spacing: 0.16em; }
.form-note a { color: var(--ink-dim); text-underline-offset: 3px; }
.form-note a:hover { color: var(--ink); }

.roles { margin-top: clamp(4rem, 10vh, 7rem); }
.roles-title { margin-bottom: 0.5rem; }
.role {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 1.5rem; padding: 1.35rem 0; border-bottom: 1px solid var(--line);
}
.role:first-of-type { border-top: 1px solid var(--line); }
.role-title { font-size: 1.18rem; font-weight: 500; letter-spacing: -0.01em; }
.role-desc { color: #fff; margin-top: 0.3rem; font-size: clamp(0.85rem, 0.95vw, 1.15rem); }
.role-meta { font-family: "PP Mondwest", "IBM Plex Mono", monospace; white-space: nowrap; }

/* ─────────────────────────────  FOOTER  ───────────────────────────── */

.colophon {
  margin-top: clamp(4rem, 11vh, 8rem);
  padding-top: 1.5rem; border-top: 1px solid var(--line);
  display: flex; justify-content: space-between; gap: 1.5rem; flex-wrap: wrap;
}
.colophon-nav { display: flex; gap: 1.6rem; }
.colophon-nav a { color: var(--ink-faint); text-decoration: none; transition: color .35s; }
.colophon-nav a:hover { color: var(--ink); }

/* ─────────────────────────────  CUSTOM CURSOR  ─────────────────────── */
/* A precise ring + dot replace the pointer, and a warm spotlight follows */
/* the cursor and lets the dark areas bloom like a torch over silk.       */

@media (pointer: fine) {
  body.cursor-on,
  body.cursor-on a,
  body.cursor-on button,
  body.cursor-on .mark { cursor: none; }
  body.cursor-on input,
  body.cursor-on textarea { cursor: text; }
}

.cursor-glow {
  position: fixed; top: 0; left: 0;
  width: 540px; height: 540px; margin: -270px 0 0 -270px;
  border-radius: 50%; pointer-events: none; z-index: 2;
  mix-blend-mode: screen; opacity: 0;
  background: radial-gradient(closest-side,
    rgba(0,51,153,0.18), rgba(0,51,153,0.05) 45%, transparent 70%);
  transition: opacity .6s ease;
  will-change: transform;
}
.cursor-ring {
  position: fixed; top: 0; left: 0;
  width: 32px; height: 32px; margin: -16px 0 0 -16px;
  border: 1px solid rgba(244,237,226,0.55); border-radius: 50%;
  pointer-events: none; z-index: 9999; opacity: 0;
  transition: width .3s, height .3s, margin .3s,
              background-color .3s, border-color .3s, opacity .3s;
  will-change: transform;
}
.cursor-dot {
  position: fixed; top: 0; left: 0;
  width: 5px; height: 5px; margin: -2.5px 0 0 -2.5px;
  background: var(--ember); border-radius: 50%;
  pointer-events: none; z-index: 9999; opacity: 0;
  will-change: transform;
}
body.is-hover .cursor-ring {
  width: 56px; height: 56px; margin: -28px 0 0 -28px;
  border-color: rgba(101,152,255,0.8);
  background-color: rgba(101,152,255,0.08);
}
body.is-hover .cursor-dot { opacity: 0; }

/* ─────────────────────────────  MOTION  ───────────────────────────── */

.rise { opacity: 0; transform: translateY(14px); }
@media (prefers-reduced-motion: no-preference) {
  .rise { animation: rise 1s cubic-bezier(.16,1,.3,1) forwards; }
  header.rise { animation-delay: .1s; }
}
@keyframes rise { to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
  .rise { opacity: 1; transform: none; }
  .lobe, .fold { animation: none; opacity: 1; }
}

.lockup .wordmark { animation-delay: .24s; }
.lockup .lede     { animation-delay: .34s; }
.lockup .cta      { animation-delay: .42s; }
.lockup .meta     { animation-delay: .5s; }

/* scroll reveal — only hides content when JS is present (.js on <html>) */
.reveal {
  transition: opacity 1.2s cubic-bezier(.16,1,.3,1),
              transform 1.2s cubic-bezier(.16,1,.3,1);
}
.js .reveal { opacity: 0; transform: translateY(22px); }
.js .reveal.in { opacity: 1; transform: none; }

/* word-by-word body reveal — lights up left to right, line by line */
.w { opacity: 0.2; }
/* Use a keyframe animation, not a transition: animations play the instant the
   class is applied (no committed "before" value / forced reflow needed, which
   is fragile when the words are split and lit in the same tick). Opacity only,
   so safe under Reduce Motion. Per-word stagger via animation-delay (set in JS). */
.w.lit { animation: word-in 0.5s cubic-bezier(.16,1,.3,1) both; }
@keyframes word-in { from { opacity: 0.2; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .js .reveal { opacity: 1; transform: none; transition: none; }
}

/* Mobile body reveal — compositor-driven via a scroll timeline (view()), so it
   is smooth and tied directly to scroll position (a JS scroll handler is choppy
   on iOS). Each word sits dim (0.2) below the reading zone and fills to full as
   its line scrolls up; words on a line fill together, so the body reveals line
   by line, top to bottom. Opacity only, so safe under Reduce Motion. If the
   browser lacks view() timelines, site.js lights the words instead (fallback). */
/* (Mobile reveal is triggered per-line by IntersectionObserver in site.js, with
   a fixed-duration .w.lit fade — see above. A scroll-position-coupled timeline
   was smooth slow but janked on fast iOS momentum, so it was removed.) */

/* Header fade — the page heading dims as you scroll into the body. Driven by a
   scroll timeline where supported (compositor-driven = smooth; iOS throttles
   JS scroll handlers, which makes the JS fallback in site.js choppy). Opacity
   only, so it is fine to keep under Reduce Motion. Fades over the first ~fifth
   of a screen of scroll. */
@supports (animation-timeline: scroll()) {
  .lead {
    animation: lead-dim linear both;
    animation-timeline: scroll(root);
    animation-range: 0 20vh;
  }
}
@keyframes lead-dim { to { opacity: 0; } }

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

@media (max-width: 720px) {
  body:not(.hold) { overflow-x: hidden; }
  .nav a { font-size: 0.92rem; }
  /* CTA sits equidistant between the wordmark above and the coordinates below,
     27px each side. The lockup is bottom-anchored (the .hero spacer pushes it
     down), so the coordinates stay put and only the wordmark/CTA shift up. */
  .lockup { grid-template-columns: 1fr; gap: 27px; }
  .lockup .cta { margin-top: 27px; }
  .meta { text-align: left; }
  .role { flex-direction: column; gap: 0.5rem; }
  .role-meta { white-space: normal; }
  .micro { font-size: 0.66rem; }

  .vignette {
    background:
      linear-gradient(180deg, rgba(6,5,3,0.88), rgba(6,5,3,0.25) 10%, transparent 18%),
      radial-gradient(140% 80% at 78% 32%, transparent 24%, rgba(6,5,3,0.6) 80%, var(--bg) 100%),
      linear-gradient(180deg, transparent 60%, rgba(6,5,3,0.7) 100%);
  }
}

/* Phones — fit the header (brand + the three nav links) on one line.
   The desktop sizes overflow narrow screens and drag the whole page wider
   than the viewport, which then clips the right gutter of the body text.
   Shrinking the wordmark + nav resolves both; flex-wrap is a safety net so
   ultra-narrow screens (<~340px) drop the nav to a tidy second line rather
   than clipping it. */
@media (max-width: 480px) {
  header { gap: 0.9rem; flex-wrap: wrap; row-gap: 0.55rem; }
  .mark { gap: 0.5rem; }
  .mark .glyph { width: 18px; height: 18px; }
  .mark .name { font-size: 0.82rem; }
  .nav { gap: 0.95rem; }
  .nav a { font-size: 0.8rem; letter-spacing: 0; padding-bottom: 2px; }
}

/* Touch devices (incl. iOS Safari): drop the custom cursor, and disable the
   SVG displacement warp on the aurora. WebKit rasterises feDisplacementMap
   over this large region at low fidelity and clips it to the filter box,
   which turns the soft light field into hard angular shapes. Without the warp
   the blurred lobes still read as a soft dusty aurora — and they render cleanly. */
@media (pointer: coarse) {
  .cursor-glow, .cursor-ring, .cursor-dot { display: none; }
  .drift { filter: none; }
  /* iOS Safari mis-composites the fixed, filtered, blended grain over the
     content during momentum scroll — the page appears to "cut" to a grainy
     void. Let the grain scroll with the document (absolute, not fixed) so it
     shares the content's layer and the tearing disappears. inset:0 on the
     relative <body> still covers the full scroll height. */
  .grain { display: none; }
  .shell { transform: none; }
  /* THE CUT FIX. The aurora's lobes are fixed, heavily blurred, screen-blended
     layers; that combination is exactly what makes iOS Safari drop the
     scrolling content layer mid-scroll (text vanishes to the background, then
     janks back). On touch, hide those layers and paint the aurora as a single
     lightweight fixed gradient — no filter, no blend, no transform/will-change
     — which composites cleanly behind scrolling content. */
  .lobe, .fold { display: none; }
  /* The grain is back — but as a STATIC noise tile blended into the gradient at
     PAINT time via background-blend-mode (not a live SVG filter, not a separate
     mix-blend layer). That keeps it inside the one lightweight fixed stage, so
     it composites cleanly (no cut) while still biting the light like the desktop
     grain. --noise holds the pre-rasterised noise; the per-page stages reuse it. */
  .stage {
    /* --noise is defined once at :root and inherited here. */
    transform: none;
    will-change: auto;
    transition: none;
    background-color: var(--bg);   /* dark base: grain blends down to dark, so darks stay dark (not grey) */
    background-image:
      var(--noise),
      radial-gradient(78% 60% at 91% 2%, rgba(255,185,100,0.62), rgba(255,170,90,0.20) 40%, transparent 64%),
      radial-gradient(150% 108% at 66% 20%, rgba(78,134,255,0.52), rgba(56,102,220,0.22) 50%, transparent 82%),
      radial-gradient(120% 95% at 22% 106%, rgba(68,112,234,0.16), transparent 62%);
    background-size: 90px 90px, auto, auto, auto;
    background-repeat: repeat, no-repeat, no-repeat, no-repeat;
    background-blend-mode: overlay, normal, normal, normal;
  }
  /* Per-page tints, mirroring the desktop aurora's mood. */
  .pg-partner .stage {
    background-image:
      var(--noise),
      radial-gradient(118% 82% at 82% 8%, rgba(255,190,110,0.42), rgba(255,150,90,0.16) 40%, transparent 68%),
      radial-gradient(120% 95% at 24% 106%, rgba(101,152,255,0.12), transparent 62%);
    background-size: 90px 90px, auto, auto;
    background-repeat: repeat, no-repeat, no-repeat;
    background-blend-mode: overlay, normal, normal;
  }
  .pg-join .stage {
    background-image:
      var(--noise),
      radial-gradient(120% 85% at 86% 60%, rgba(120,162,255,0.46), rgba(101,152,255,0.16) 44%, transparent 70%),
      radial-gradient(70% 50% at 96% 40%, rgba(255,197,107,0.18), transparent 56%);
    background-size: 90px 90px, auto, auto;
    background-repeat: repeat, no-repeat, no-repeat;
    background-blend-mode: overlay, normal, normal;
  }
  /* Failsafe: if site.js never runs, never leave the body text hidden. The
     script removes .reveal from these the instant it runs (long before 4s), so
     this only takes effect if the script failed entirely. */
  .js .prose p.reveal,
  .js .sub.reveal { animation: sf-failsafe 0.6s ease 4s forwards; }
}
@keyframes sf-failsafe { to { opacity: 1; transform: none; } }
