/* Lamp & Post — landing page styles
   Palette: ink (near-black), paper (cream), white, soft warm gray.
   Type: Alice (serif) throughout, per brand. */

:root {
  --ink: #0d0d0e;
  --ink-soft: #2a2724;
  --paper: #f4ecdc;       /* "Library Paper" cream */
  --paper-deep: #ebe1cd;
  --line: rgba(13,13,14,0.15);
  --line-light: rgba(244,236,220,0.18);
  --accent: #f4ecdc;
  --maxw: 1080px;
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  font-family: "Alice", "Cormorant Garamond", "Source Serif Pro", Georgia, serif;
  color: var(--ink);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  font-size: 18px;
  line-height: 1.55;
}

img, svg { display: block; max-width: 100%; }

a { color: inherit; text-decoration: none; }

.container { width: 100%; max-width: var(--maxw); margin: 0 auto; padding: 0 1.5rem; }
.narrow { max-width: 680px; }

.amp { font-style: italic; font-weight: 400; }

/* -------- Header -------- */
.site-header {
  position: absolute;
  top: 0; left: 0; right: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1.25rem 1.75rem;
  z-index: 10;
  color: var(--paper);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.65rem;
  letter-spacing: 0.04em;
}

.brand-mark {
  width: auto;
  height: 40px;
}

@media (max-width: 560px) {
  .brand-mark { height: 32px; }
}

.site-nav a {
  margin-left: 1.5rem;
  font-size: 0.92rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  opacity: 0.85;
  transition: opacity 160ms ease;
}
.site-nav a:hover { opacity: 1; }

/* -------- Mobile nav toggle (hamburger) -------- */
.nav-toggle {
  display: none; /* shown on mobile via media query */
  background: transparent;
  border: 0;
  padding: 0.5rem;
  margin: -0.5rem;     /* keep visual size while expanding tap target */
  cursor: pointer;
  color: var(--paper);
  width: 44px;
  height: 44px;
  position: relative;
}
/* Three bars built from a single span + its ::before / ::after */
.nav-toggle-bars,
.nav-toggle-bars::before,
.nav-toggle-bars::after {
  display: block;
  width: 24px;
  height: 1.5px;
  background: currentColor;
  border-radius: 1px;
  transition: transform 220ms ease, opacity 180ms ease, top 220ms ease;
}
.nav-toggle-bars {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
}
.nav-toggle-bars::before,
.nav-toggle-bars::after {
  content: "";
  position: absolute;
  left: 0;
}
.nav-toggle-bars::before { top: -7px; }
.nav-toggle-bars::after  { top: 7px; }

/* Bars rearrange into an X when the menu is open */
.nav-toggle[aria-expanded="true"] .nav-toggle-bars {
  background: transparent;
}
.nav-toggle[aria-expanded="true"] .nav-toggle-bars::before {
  top: 0;
  transform: rotate(45deg);
}
.nav-toggle[aria-expanded="true"] .nav-toggle-bars::after {
  top: 0;
  transform: rotate(-45deg);
}

@media (max-width: 720px) {
  .nav-toggle { display: block; }

  /* Mobile: nav becomes a small panel anchored to the right under the header,
     hidden until .is-open is added by the toggle script. */
  .site-nav {
    display: none;
    position: absolute;
    top: 100%; right: 1rem;
    min-width: 180px;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 0.75rem 0;
    background: rgba(12, 11, 10, 0.94);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    border: 1px solid rgba(244, 236, 220, 0.08);
    border-radius: 4px;
    box-shadow: 0 24px 48px -16px rgba(0,0,0,0.55);
  }
  .site-nav.is-open { display: flex; }
  .site-nav a {
    margin: 0;
    padding: 0.7rem 1.25rem;
    text-align: right;
    opacity: 0.9;
  }
  .site-nav a:hover { background: rgba(244, 236, 220, 0.06); opacity: 1; }
}

/* Reduced motion: skip the hamburger ↔ X transition */
@media (prefers-reduced-motion: reduce) {
  .nav-toggle-bars,
  .nav-toggle-bars::before,
  .nav-toggle-bars::after { transition: none; }
}

/* -------- Hero -------- */
.hero {
  position: relative;
  min-height: 100vh;       /* fallback for older browsers */
  min-height: 100dvh;      /* dynamic viewport: fills the visible area even
                              when the mobile URL bar collapses, so the dark
                              gradient stays edge-to-edge with no body color
                              bleeding through at the bottom */
  background: radial-gradient(ellipse at 50% 38%, #1c1a18 0%, #0a0908 70%);
  color: var(--paper);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 6rem 1.5rem 4rem;
  overflow: hidden;
}

/* Hot-spot alphas registered as animatable typed custom properties
   so the radial gradients they feed can smoothly transition between
   target values (background gradients otherwise can't be tweened). */
@property --hs1-a { syntax: "<number>"; initial-value: 0; inherits: false; }
@property --hs2-a { syntax: "<number>"; initial-value: 0; inherits: false; }
@property --hs3-a { syntax: "<number>"; initial-value: 0; inherits: false; }
@property --hs4-a { syntax: "<number>"; initial-value: 0; inherits: false; }
@property --hs5-a { syntax: "<number>"; initial-value: 0; inherits: false; }
@property --hs6-a { syntax: "<number>"; initial-value: 0; inherits: false; }

/* warm glow behind the mark.
   Base radial = uniform halo. Five hot-spot radials at fixed angular
   positions add localized brightness that varies independently — when
   some are bright and others dim, the glow reads as asymmetric, like
   a flame leaning. Opacity / scale / blur affect the whole element. */
.hero::before {
  content: "";
  position: absolute;
  top: 50%; left: 50%;
  width: 520px; height: 520px;
  transform: translate(-50%, -55%) scale(var(--glow-scale, 1));
  background:
    /* upper-left */
    radial-gradient(circle at 32% 32%, rgba(244,236,220, var(--hs1-a)) 0%, transparent 35%),
    /* upper-right */
    radial-gradient(circle at 68% 32%, rgba(244,236,220, var(--hs2-a)) 0%, transparent 35%),
    /* top-center (over the lamp head) */
    radial-gradient(circle at 50% 20%, rgba(244,236,220, var(--hs3-a)) 0%, transparent 40%),
    /* lower-left */
    radial-gradient(circle at 32% 65%, rgba(244,236,220, var(--hs4-a)) 0%, transparent 35%),
    /* lower-right */
    radial-gradient(circle at 68% 65%, rgba(244,236,220, var(--hs5-a)) 0%, transparent 35%),
    /* bottom-center (mirrors top-center, below the lamp) */
    radial-gradient(circle at 50% 80%, rgba(244,236,220, var(--hs6-a)) 0%, transparent 40%),
    /* base uniform halo */
    radial-gradient(circle, rgba(244,236,220,0.32) 0%, rgba(244,236,220,0) 60%);
  filter: blur(var(--glow-blur, 8px));
  pointer-events: none;
  opacity: var(--glow-opacity, 1);
  transition:
    opacity   var(--glow-duration, 2s)    ease-in-out,
    transform var(--glow-duration, 2s)    ease-in-out,
    filter    var(--glow-duration, 2s)    ease-in-out,
    --hs1-a   var(--hs1-duration, 1.5s)   ease-in-out,
    --hs2-a   var(--hs2-duration, 1.5s)   ease-in-out,
    --hs3-a   var(--hs3-duration, 1.5s)   ease-in-out,
    --hs4-a   var(--hs4-duration, 1.5s)   ease-in-out,
    --hs5-a   var(--hs5-duration, 1.5s)   ease-in-out,
    --hs6-a   var(--hs6-duration, 1.5s)   ease-in-out;
}

.hero-lockup {
  position: relative;
  margin: 0 0 1.5rem;
  font-size: 0; /* image-only h1 */
  line-height: 0;
}

.hero-mark {
  width: clamp(280px, 44vw, 460px);
  height: auto;
}

.mission {
  position: relative;
  max-width: 36ch;
  margin: 0 auto;
  font-size: clamp(1rem, 1.6vw, 1.2rem);
  letter-spacing: 0.06em;
  opacity: 0.85;
  font-style: italic;
}

.scroll-cue {
  position: absolute;
  bottom: 1.5rem;
  left: 50%;
  transform: translateX(-50%);
  width: 22px;
  height: 36px;
  border: 1px solid rgba(244,236,220,0.45);
  border-radius: 12px;
  display: block;
}
.scroll-cue span {
  display: block;
  width: 2px; height: 8px;
  background: var(--paper);
  margin: 7px auto 0;
  border-radius: 2px;
  animation: cue 1.8s ease-in-out infinite;
}
@keyframes cue {
  0%, 100% { transform: translateY(0); opacity: 0.4; }
  50%      { transform: translateY(10px); opacity: 1; }
}

/* -------- Story -------- */
.story {
  padding: 6rem 0 5rem;
  text-align: left;
}

.story .lede {
  font-size: clamp(1.6rem, 3vw, 2.1rem);
  letter-spacing: 0.04em;
  margin: 0 0 1.75rem;
}

.story p {
  font-size: 1.1rem;
  margin: 0 0 1.25rem;
  color: var(--ink-soft);
}

.story .kicker {
  margin-top: 1.75rem;
  font-style: italic;
  font-size: 1.15rem;
  color: var(--ink);
}

/* Drop cap (only on viewports wide enough that floating makes sense).
   line-height < 1 tightens the floated box; small negative margin-top
   nudges the glyph top up to meet the first wrap line's cap-height. */
@media (min-width: 760px) {
  .drop-cap::first-letter {
    float: left;
    font-family: "Alice", serif;
    font-style: italic;
    font-size: 4.2em;
    line-height: 0.82;
    margin: 0 1.1rem 0.05rem 0;
    padding: 0;
    color: var(--ink);
  }
}

/* -------- Video banner (placeholder slot for intro video) -------- */
.video-banner {
  background: var(--ink);
  padding: 3rem 0;
}
.video-slot {
  position: relative;
  aspect-ratio: 16 / 9;
  width: 100%;
  background: #000;
  border-radius: 2px;
  overflow: hidden;
}
.video-slot > video,
.video-slot > iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
}
.video-placeholder {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background:
    radial-gradient(ellipse at 50% 50%, #1c1a18 0%, #0a0908 75%);
  color: var(--paper);
}
.video-placeholder span {
  font-size: 0.85rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  opacity: 0.7;
}

/* -------- Gathering (community gathering place — split from Connect) -------- */
.gathering {
  padding: 6rem 0 5rem;
  text-align: center;
}
.gathering h2 {
  font-weight: 400;
  font-size: clamp(1.6rem, 2.6vw, 2rem);
  margin: 0 0 1.5rem;
  letter-spacing: 0.04em;
}
.gathering p {
  font-size: 1.1rem;
  margin: 0;
  color: var(--ink-soft);
  font-style: italic;
}

/* -------- Connect / Socials -------- */
.connect {
  padding: 6rem 0;
  text-align: center;
}

.connect h2 {
  font-weight: 400;
  font-size: clamp(1.6rem, 2.6vw, 2rem);
  margin: 0 0 0.75rem;
  letter-spacing: 0.04em;
}

.connect .sub {
  margin: 0 0 2.5rem;
  color: var(--ink-soft);
  font-style: italic;
}

.socials {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 1.25rem;
}

.socials a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 56px; height: 56px;
  border: 1px solid var(--line);
  border-radius: 50%;
  color: var(--ink);
  transition: background 180ms ease, color 180ms ease, transform 180ms ease;
  position: relative;
}

.socials a:hover {
  background: var(--ink);
  color: var(--paper);
  transform: translateY(-2px);
}

.socials svg { width: 22px; height: 22px; }

.socials span {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
}

/* -------- Footer -------- */
.site-footer {
  background: #050505;
  color: var(--paper);
  text-align: center;
  padding: 3rem 1.5rem 2.25rem;
}

.footer-mark {
  width: auto;
  height: 44px;
  margin: 0 auto 1rem;
  opacity: 0.9;
}

.footer-mission {
  margin: 0 0 0.5rem;
  font-style: italic;
  letter-spacing: 0.06em;
  opacity: 0.85;
}

.footer-meta {
  margin: 0;
  font-size: 0.85rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  opacity: 0.55;
}

/* -------- Small screens -------- */
@media (max-width: 560px) {
  .site-header { padding: 1rem 1.25rem; }
  .hero { padding-top: 5rem; }
  .story, .connect { padding-top: 4rem; padding-bottom: 4rem; }
}

/* ============================================================
   Additions: utilities, paper texture, ignition, marquee,
   photo slots, photo banner, ampersand divider, email signup.
   ============================================================ */

/* -------- Screen-reader-only utility -------- */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0,0,0,0);
  white-space: nowrap;
  border: 0;
}

/* -------- Paper texture overlay (subtle grain on cream sections) -------- */
.paper {
  position: relative;
  background-color: var(--paper);
  isolation: isolate; /* keep blend mode local */
}
.paper::after {
  content: "";
  position: absolute; inset: 0;
  pointer-events: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='260' height='260'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0.55 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
  opacity: 0.055;
  mix-blend-mode: multiply;
  z-index: -1;
}

/* -------- Hero ignition + content fade-in -------- */
.hero-mark    { animation: ignite     1.2s ease-out 0.20s both; }
.mission      { animation: fadeup     0.9s ease-out 1.00s both; }
.scroll-cue   { animation: fadeup     0.7s ease-out 1.40s both; }

/* The glow runs one CSS animation (the ignition pulse) + one JS-driven
   gaslamp loop. After the ignition completes, transitions on the
   --glow-* custom properties take over. */
.hero::before {
  animation: glow-pulse 1.8s ease-out 0.30s;
}

@keyframes ignite {
  0%   { opacity: 0; filter: brightness(0.35) blur(12px); transform: scale(0.985); }
  60%  { opacity: 1; filter: brightness(1.1) blur(0);     transform: scale(1.005); }
  100% { opacity: 1; filter: brightness(1) blur(0);       transform: scale(1); }
}
@keyframes glow-pulse {
  0%   { opacity: 0; }
  55%  { opacity: 1.2; }
  100% { opacity: 1; }
}
@keyframes fadeup {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* -------- Photo slot (aspect-tolerant) -------- */
.photo-slot {
  position: relative;
  overflow: hidden;
  background: var(--ink);
  border-radius: 2px;
}
.photo-slot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  display: block;
  filter: grayscale(100%) contrast(1.05);
}
.photo-slot--portrait { aspect-ratio: 1 / 1; }
.photo-slot--wide     { aspect-ratio: 21 / 9; }

/* Story photo: nudge the cover-crop window leftward in image space so
   the visible content sits ~13px to the right within the slot — adds
   a left-side gap to mirror the existing right-side gap (50% default
   → 44% shifts ~6% of the horizontal overflow). */
.story-photo .photo-slot img { object-position: 44% center; }
@media (max-width: 760px) {
  .photo-slot--wide   { aspect-ratio: 16 / 9; }
}

/* -------- Full-bleed photo banner -------- */
.photo-banner {
  background: var(--ink);
}
.photo-banner .photo-slot { border-radius: 0; }
.photo-banner .photo-slot img { filter: grayscale(100%) brightness(0.82) contrast(1.05); }

/* Parallax: position absolutely with top:-50% / height:200% so the
   image extends 50% above and 50% below the slot. JS only translates
   ±40% of slot height (see MAX in index.html), leaving 10% spare on
   each side to absorb subpixel rounding, browser scroll quirks, and
   mobile URL-bar viewport recalcs without exposing edges. */
.photo-banner.parallax-active .photo-slot img {
  position: absolute;
  top: -50%;
  left: 0;
  width: 100%;
  height: 200%;
  will-change: transform;
}

.banner-caption {
  position: absolute;
  inset: auto 0 0 0;
  padding: 1.5rem 1.5rem 1.75rem;
  text-align: center;
  background: linear-gradient(to top, rgba(0,0,0,0.6), rgba(0,0,0,0));
  color: var(--paper);
}
.banner-caption p {
  margin: 0;
  font-style: italic;
  font-size: clamp(1rem, 1.6vw, 1.25rem);
  letter-spacing: 0.08em;
}

/* -------- Ampersand divider --------
   Real <span> hairlines (not pseudo-elements) so the .paper::after
   noise overlay doesn't collide with the divider's structure. */
.amp-divider {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 1.5rem;
  max-width: 340px;
  margin: 0 auto;
  padding: 2.75rem 1.5rem;
}
.amp-rule {
  display: block;
  height: 1px;
  background: var(--ink);
  opacity: 0.25;
}
.amp-divider .amp {
  font-family: "Alice", serif;
  font-style: italic;
  font-size: clamp(2.4rem, 4.5vw, 3.4rem);
  line-height: 1;
  color: var(--ink);
}

/* -------- Pop-up inquiry contact form -------- */
.popup-inquiry {
  margin-top: 3.5rem;
  padding-top: 2.5rem;
  border-top: 1px solid var(--line);
  display: grid;
  gap: 1.5rem;
  justify-items: center;
}
.popup-lede {
  margin: 0;
  font-style: italic;
  font-size: 1.15rem;
  color: var(--ink);
  letter-spacing: 0.04em;
  text-align: center;
}
.popup-form {
  display: grid;
  gap: 1.25rem;
  width: 100%;
  max-width: 480px;
}
.popup-form label {
  display: grid;
  gap: 0.4rem;
  text-align: left;
}
.popup-form label span {
  font-size: 0.82rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  opacity: 0.7;
  color: var(--ink);
}
.popup-form input,
.popup-form textarea {
  font: inherit;
  color: var(--ink);
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--line);
  padding: 0.55rem 0;
  outline: none;
  transition: border-color 160ms ease;
}
.popup-form input:focus,
.popup-form textarea:focus { border-bottom-color: var(--ink); }
.popup-form textarea { resize: vertical; min-height: 110px; }
.popup-form button {
  justify-self: center;
  margin-top: 0.5rem;
  font: inherit;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  font-size: 0.85rem;
  background: var(--ink);
  color: var(--paper);
  border: 0;
  padding: 0.85rem 2rem;
  border-radius: 999px;
  cursor: pointer;
  transition: transform 160ms ease, background 160ms ease;
}
.popup-form button:hover { transform: translateY(-1px); background: #000; }

/* ============================================================
   Threshold scroll transition — feature-flagged via body[data-threshold].
   Off by default: the markup adds .hero-stage / .threshold-scrim /
   .threshold-overlay but they're inert unless the flag is on.
   ============================================================ */

/* Inert defaults — keep the markup present without effect. */
.hero-stage     { display: contents; }   /* hero behaves as if stage didn't exist */
.threshold-scrim,
.threshold-overlay { display: none; }

body[data-threshold="v1"] .hero-stage {
  display: block;
  position: relative;
  /* hero is 100svh; total 200svh leaves a 100svh runway underneath
     that the sticky hero hangs over until the bottom of the stage
     reaches the top of the viewport. */
  height: 200svh;
  /* Stage's runway space (below the sticky hero) stays the same dark
     as the hero's gradient bottom, so when the mobile URL bar dances
     and the hero briefly resizes, no cream body background bleeds
     through underneath. */
  background: #0a0908;
}

/* Mobile / touch devices: add 100px buffer so the URL-bar dance on
   upward scroll (browser consumes scroll distance when the address
   bar reappears) doesn't shortcut the engagement direction. */
@media (pointer: coarse) {
  body[data-threshold="v1"] .hero-stage {
    height: calc(200svh + 100px);
  }
}

body[data-threshold="v1"] .hero-stage .hero {
  position: sticky;
  top: 0;
}

body[data-threshold="v1"] .threshold-scrim {
  display: block;
  position: fixed;
  inset: 0;
  background: #fff;
  opacity: 0;
  pointer-events: none;
  z-index: 50;
  will-change: opacity;
}

/* Past the stage, scrim + overlay snap to opacity 0 instantly. With the
   overlay holding a clone of the natural page that sits in flow under-
   neath, the snap is visually invisible — the two layers are showing
   identical content at identical positions at the moment of release. */

/* Overlay carries the cloned page content that fades in over the white.
   Cream background ensures the white scrim doesn't show through any
   gaps between cloned sections (and prevents a flash on scroll-back). */
body[data-threshold="v1"] .threshold-overlay {
  display: block;
  position: fixed;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 51;
  opacity: 0;
  background: var(--paper);
  will-change: opacity;
}

/* Cloned sections inside the overlay fill the natural width and
   inherit their own styles (paper grain, banner aspect, etc.). */
body[data-threshold="v1"] .threshold-overlay > * {
  width: 100%;
}

/* ============================================================
   Threshold v2 — sticky hero + CSS scroll-driven bloom.

   Zero JS. The hero is sticky inside a 200dvh stage with a
   split gradient background (dark for the hero area, cream for
   the runway below). A single fixed scrim is a radial gradient
   centered on the lamp; its white area is driven outward by
   scroll, so visually the lamp brightens and blooms to fill the
   viewport before fading.

   Bloom: scroll 0 → 50dvh (white grows from the lamp outward).
   Hold:  scroll 50 → 180dvh (pure white).
   Fade:  scroll 180 → 200dvh (snappy reveal; 20dvh of scroll).

   When the scrim fades, the area behind it is all cream (story
   below + stage's lower gradient) — seamless reveal.
   ============================================================ */

/* Bloom inner/outer radii: @property-registered so the radial
   gradient can be smoothly interpolated by scroll animation.
   Inner = where the solid white core ends.
   Outer = where the soft fade reaches transparent. */
@property --bloom-inner {
  syntax: "<percentage>";
  initial-value: 0%;
  inherits: false;
}
@property --bloom-outer {
  syntax: "<percentage>";
  initial-value: 10%;
  inherits: false;
}

body[data-threshold="v2"] .hero-stage {
  display: block;
  position: relative;
  height: 130dvh;
  /* The dark/cream split is anchored to 100lvh — the *largest*
     viewport possible (all browser UI hidden). That matters because
     mobile Chrome doesn't recompute dvh while a touch is held: the
     URL bar visually collapses but layout stays sized to svh. By
     pinning the boundary to lvh we guarantee the dark portion always
     covers whatever the visible viewport is during the gesture,
     regardless of what dvh reports. The cream portion still runs
     from this boundary to the end of the stage. */
  background: linear-gradient(
    to bottom,
    #0a0908 0,
    #0a0908 100lvh,
    var(--paper) 100lvh,
    var(--paper) 100%
  );
}

body[data-threshold="v2"] .hero-stage .hero {
  position: sticky;
  top: 0;
}

/* Gap-filler: a fixed dark band that lives between viewport y 100svh
   (the stable bottom of the small viewport) and the actual viewport
   bottom. When dvh is in sync with the visible viewport its height is
   zero. When dvh is stale (mobile Chrome during a held gesture: URL
   bar visually collapsed but CSS-side dvh still at svh, so the hero
   stops short of the visible viewport bottom), this band fills the
   gap with dark so cream from below the hero never bleeds through.

   Hidden quickly at the start of the fade-out range so it doesn't
   block the cream reveal of the story coming up underneath. */
body[data-threshold="v2"] .hero-stage::after {
  content: "";
  position: fixed;
  top: 100svh;
  left: 0;
  right: 0;
  bottom: 0;
  background: #0a0908;
  pointer-events: none;
  z-index: 50;
  animation: threshold-gap-fill linear both;
  animation-timeline: scroll(root);
  animation-range: 0 130dvh;
}

@keyframes threshold-gap-fill {
  0%   { opacity: 1; }
  77%  { opacity: 1; }
  82%  { opacity: 0; }
  100% { opacity: 0; }
}

/* Lamp lockup sits above the bloom so the icon stays visible while
   the glow grows behind it — same feel as v1 where the lamp itself
   appeared to be brightening. The drop-shadow keeps the all-white
   lamp icon distinguishable when the bloom behind it is also white;
   it's barely perceptible against the dark hero before the bloom. */
body[data-threshold="v2"] .hero-lockup {
  position: relative;
  z-index: 101;
  filter: drop-shadow(0 0 3px rgba(0, 0, 0, 0.55));
}

body[data-threshold="v2"] .threshold-scrim {
  display: block;
  position: fixed;
  inset: 0;
  /* Radial gradient centered roughly on the lamp icon (~45% from top).
     Wider transition zone between --bloom-inner (solid white core) and
     --bloom-outer (transparent edge) for a softer glow rather than a
     hard-edged spotlight. */
  background: radial-gradient(
    circle at 50% 45%,
    white,
    white var(--bloom-inner),
    transparent var(--bloom-outer)
  );
  --bloom-inner: 0%;
  --bloom-outer: 0%;
  pointer-events: none;
  z-index: 100;
  opacity: 0;
  animation: threshold-bloom-v2 linear both;
  animation-timeline: scroll(root);
  animation-range: 0 130dvh;
}

@keyframes threshold-bloom-v2 {
  /* Hidden at rest */
  0%   { --bloom-inner: 0%;   --bloom-outer: 0%;   opacity: 0; }
  /* First few dvh of scroll: soft glow blooms behind the lamp */
  3%   { --bloom-inner: 0%;   --bloom-outer: 35%;  opacity: 1; }
  /* At peak, bloom-inner pushed well past 100% so solid white extends
     beyond the farthest viewport corner — fully opaque edges to edges,
     no dark bleed-through on wide aspect ratios. */
  23%  { --bloom-inner: 160%; --bloom-outer: 240%; opacity: 1; }
  /* Brief held phase */
  77%  { --bloom-inner: 160%; --bloom-outer: 240%; opacity: 1; }
  /* Snappy ~30dvh fade-out as the story arrives */
  100% { --bloom-inner: 160%; --bloom-outer: 240%; opacity: 0; }
}

/* ============================================================ */

/* Honor users who prefer less motion */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .scroll-cue span { animation: none; }
  .hero-mark,
  .hero::before,
  .mission,
  .scroll-cue { animation: none; }
  .hero::before { transition: none; }

  /* Disable v1 threshold: collapse the stage and hide overlays. */
  body[data-threshold="v1"] .hero-stage     { height: auto; display: contents; }
  body[data-threshold="v1"] .hero-stage .hero { position: relative; }
  body[data-threshold="v1"] .threshold-scrim,
  body[data-threshold="v1"] .threshold-overlay { display: none; }

  /* Disable v2 threshold: collapse the stage, drop the gradient,
     hide the scrim. Hero falls back to normal flow. */
  body[data-threshold="v2"] .hero-stage {
    height: auto;
    display: contents;
    background: none;
  }
  body[data-threshold="v2"] .hero-stage .hero { position: relative; }
  body[data-threshold="v2"] .threshold-scrim { display: none; }
}
