/* ============================================================
   JUNO — index.html page styles (layout, nav, story, features)
   Requires css/tokens.css loaded first.
   ============================================================ */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  margin: 0;
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.5;
  color: var(--juno-text-primary);
  background: var(--sky-night-bottom);
  overflow-x: hidden;
}

img { max-width: 100%; height: auto; }
a { color: inherit; }

:focus-visible {
  outline: 3px solid var(--juno-accent);
  outline-offset: 3px;
  border-radius: 6px;
}

.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 300;
  background: var(--juno-surface); color: var(--juno-text-primary);
  padding: 12px 20px; border-radius: 0 0 var(--r-tile) 0;
  font-weight: 600; text-decoration: none;
}
.skip-link:focus { left: 0; }

/* ------------------------------------------------------------
   Fixed backdrop stack: sky → canvas → poster. DOM scrolls above.
   ------------------------------------------------------------ */
.sky-backdrop {
  position: fixed; inset: 0; z-index: 0; pointer-events: none;
  background:
    radial-gradient(1.5px 1.5px at 12% 18%, rgba(255,255,255,.8), transparent 55%),
    radial-gradient(1px 1px at 68% 8%,  rgba(255,255,255,.65), transparent 55%),
    radial-gradient(1.5px 1.5px at 84% 30%, rgba(255,255,255,.5), transparent 55%),
    radial-gradient(1px 1px at 32% 42%, rgba(255,255,255,.55), transparent 55%),
    radial-gradient(1.5px 1.5px at 52% 24%, rgba(255,255,255,.7), transparent 55%),
    radial-gradient(1px 1px at 90% 62%, rgba(255,255,255,.45), transparent 55%),
    radial-gradient(1px 1px at 8% 70%,  rgba(255,255,255,.4), transparent 55%),
    radial-gradient(1.5px 1.5px at 44% 78%, rgba(255,255,255,.5), transparent 55%),
    radial-gradient(1px 1px at 74% 86%, rgba(255,255,255,.5), transparent 55%),
    radial-gradient(1px 1px at 22% 92%, rgba(255,255,255,.45), transparent 55%),
    linear-gradient(180deg, var(--sky-night-top) 0%, var(--sky-night-bottom) 100%);
}

/* ------------------------------------------------------------
   Sky bridges — two fixed 200vh slabs UNDER #hero-canvas, moved
   with translate3d by js/page.js.
   #sky-bridge       night→dawn: at #s-reveal p=0 it sits at y=0 and
                     its visible half is transparent (night backdrop
                     shows); by p=1 it has risen 100vh and dawn fills
                     the lower viewport, handing off to .sky-arc-1.
   #sky-bridge-dusk  dusk→night: hidden until #s-privacy approaches,
                     starts at y=-100vh (dusk half visible, matching
                     --sky-arc-c7) and settles at y=0 (pure night).
   ------------------------------------------------------------ */
.sky-bridge {
  position: fixed; inset: 0;
  z-index: 0; pointer-events: none;
  /* Viewport-sized layer; the 300%-tall gradient is scrubbed through
     it via background-position (page.js), so no giant GPU texture.
     Top third transparent = pure night backdrop at page top; dawn
     rises from the bottom and owns the viewport by #s-reveal's end. */
  background-image: linear-gradient(180deg,
    rgba(23,17,48,0) 0%, rgba(23,17,48,0) 34%,
    rgba(34,26,68,.92) 37%, #3A2E68 41%, #6B57A5 45%,
    #9C87D0 49%, #C4B2E8 53%, #DFD3F2 60%,
    #EAE0F5 70%, #F2EBEE 85%, var(--sky-arc-c0) 100%);
  background-size: 100% 300%;
  background-position: 0 0%;
  background-repeat: no-repeat;
}
.sky-bridge.dusk {
  opacity: 0;
  /* Dusk→night: the gradient's start edge rides #s-privacy's top edge
     (page.js maps its top to background-position). The 66.7% stop
     (#2A2050) is pinned to the founder section's top color so the
     moving seam between them is invisible. */
  background-image: linear-gradient(180deg,
    rgba(23,17,48,0) 0%, rgba(23,17,48,0) 33.32%,
    var(--sky-arc-c6) 33.34%, #A38FD6 43.3%, #7A66B4 52%,
    #4A3A78 60%, #2A2050 66.7%, #221A44 76.7%,
    var(--night-soft) 88%, var(--night-deep) 100%);
}

#hero-canvas {
  position: fixed; inset: 0; z-index: 0;
  width: 100%; height: 100%;
  display: block; pointer-events: none;
  opacity: 0; transition: opacity .9s ease;
}

#hero-poster {
  position: fixed; inset: 0; z-index: 1;
  width: 100%; height: 100%; object-fit: cover;
  pointer-events: none;
  opacity: 1; transition: opacity .9s ease;
}

/* Click-through guarantee: the four full-viewport fixed backdrops sit at
   z-0/z-1 UNDER all content (nav z-100, story z-3, page-body/footer z-5).
   Force pointer-events:none with !important so no inline style from the
   engine can ever let a backdrop intercept taps on the nav, links, or the
   footer. The DOM above them keeps its own stacking context and receives
   every pointer event. */
.sky-backdrop, .sky-bridge, #hero-canvas, #hero-poster {
  pointer-events: none !important;
}

/* Engine tier classes (added to <body> by js/engine/hero.js).
   No class at all behaves exactly like tier 0: poster + plain scroll.
   NOTE: the poster is NOT hidden by tier class anymore — the engine
   crossfades it itself once its uBoot signal passes 0.5 (new contract).
   js/page.js adds body.poster-hold if a tier-2/3 engine never fades
   the poster within 4s, so the hero can never sit black. */
body.hero-tier-0 #hero-canvas { display: none; }
body.hero-tier-1 #hero-canvas,
body.hero-tier-2 #hero-canvas,
body.hero-tier-3 #hero-canvas { opacity: 1; }
body.poster-hold #hero-canvas { opacity: 0 !important; }

/* ------------------------------------------------------------
   Nav
   ------------------------------------------------------------ */
.nav {
  position: fixed; top: 14px; left: 50%; transform: translateX(-50%);
  width: min(1180px, calc(100% - 28px));
  z-index: 100;
  display: flex; align-items: center; gap: 28px;
  padding: 9px 12px 9px 20px;
  color: #fff;
  border-radius: 999px;
  background: rgba(26, 20, 48, .30);
  -webkit-backdrop-filter: blur(20px) saturate(1.35);
  backdrop-filter: blur(20px) saturate(1.35);
  border: 1px solid rgba(255, 255, 255, .14);
  box-shadow: 0 10px 34px rgba(12, 8, 30, .30), inset 0 1px 0 rgba(255, 255, 255, .10);
  transition: background .35s ease, color .35s ease, box-shadow .35s ease,
    border-color .35s ease, width .35s ease, top .35s ease;
}
.nav .nav-logo { display: inline-flex; align-items: center; min-height: 44px; }
.nav .nav-logo img { height: 30px; width: auto; display: block; }
.nav .nav-logo img.logo-blue { display: none; }
.nav-links { display: flex; align-items: center; gap: 26px; margin-left: auto; }
.nav-links a {
  text-decoration: none; font-weight: 500; font-size: 15.5px;
  opacity: .92; padding: 10px 2px; min-height: 44px; display: inline-flex; align-items: center;
}
.nav-links a:hover { opacity: 1; }
.nav-links a.nav-cta, .nav-cta {
  display: inline-flex; align-items: center; gap: 8px;
  background: var(--juno-accent); color: #fff !important;
  border-radius: var(--r-pill); padding: 11px 22px; min-height: 44px;
  font-weight: 600; font-size: 15.5px; text-decoration: none; white-space: nowrap;
  box-shadow: var(--sh-card);
  transition: transform .15s var(--pop), background .2s ease;
}
.nav-cta:hover { background: var(--juno-accent-deep); }
.nav-cta:active { transform: scale(.96); }

body.nav-solid .nav {
  top: 12px;
  width: min(1120px, calc(100% - 28px));
  background: rgba(255, 255, 255, .72);
  -webkit-backdrop-filter: blur(22px) saturate(1.5);
  backdrop-filter: blur(22px) saturate(1.5);
  color: var(--juno-text-primary);
  border-color: rgba(138, 127, 216, .18);
  box-shadow: 0 12px 34px rgba(138, 127, 216, .18), inset 0 1px 0 rgba(255, 255, 255, .6);
}
body.nav-solid .nav-logo img.logo-white { display: none; }
body.nav-solid .nav-logo img.logo-blue { display: block; }

@media (max-width: 719px) {
  .nav-links .nav-secondary { display: none; }
  .nav-links { gap: 12px; }
  .nav { width: calc(100% - 20px); padding: 8px 10px 8px 16px; gap: 12px; }
  body.nav-solid .nav { width: calc(100% - 20px); }
}

/* ------------------------------------------------------------
   Story sections (#s-hero, #s-clues, #s-privacy) — copy floats
   above the fixed 3D canvas. Each .beat is one viewport-tall
   scene, so plain scroll (tier 0) reads perfectly.
   ------------------------------------------------------------ */
.story { position: relative; z-index: 3; color: #fff; }

.beat {
  min-height: 100vh; min-height: 100svh;
  display: grid; place-items: center;
  padding: 96px clamp(20px, 5vw, 48px);
}
.beat-inner { max-width: 720px; text-align: center; }

/* Neutral chip — the closer CTA is the page's ONE gold element. */
.hero-chip {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 12.5px; font-weight: 700; letter-spacing: 1.4px;
  text-transform: uppercase;
  color: rgba(255,255,255,.88);
  background: rgba(255,255,255,.08);
  border: 1px solid rgba(255,255,255,.14);
  border-radius: var(--r-pill); padding: 8px 18px;
  margin-bottom: 26px;
}

.hero-copy { will-change: opacity; }

.hero-h1 {
  font-family: var(--serif); font-weight: 600;
  font-size: clamp(40px, 7vw, 72px);
  line-height: 1.08; letter-spacing: -.015em;
  margin: 0 0 18px;
  text-wrap: balance;
}
.hero-lede {
  font-size: clamp(18px, 2.4vw, 22px);
  color: rgba(255,255,255,.82);
  margin: 0 0 30px;
}

.hero-cta-row {
  display: flex; flex-wrap: wrap; gap: 16px; justify-content: center; align-items: center;
  margin-bottom: 26px;
}
.btn-primary {
  display: inline-flex; align-items: center; gap: 10px;
  background: var(--juno-accent); color: #fff;
  font-weight: 600; font-size: 17px; text-decoration: none;
  padding: 15px 30px; min-height: 52px; border-radius: var(--r-pill);
  box-shadow: var(--sh-elevated);
  transition: transform .15s var(--pop), background .2s ease;
}
.btn-primary:hover { background: var(--juno-accent-deep); }
.btn-primary:active { transform: scale(.96); }
.btn-ghost {
  display: inline-flex; align-items: center; gap: 8px;
  color: rgba(255,255,255,.85); text-decoration: none;
  font-weight: 500; font-size: 16px; padding: 14px 10px; min-height: 44px;
}
.btn-ghost:hover { color: #fff; }

.proof-row {
  display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; align-items: center;
  font-size: 17px; color: rgba(255,255,255,.85);
}
.proof-row .stars { color: rgba(255,255,255,.92); letter-spacing: 2px; font-size: 17px; }
.hero-microquote {
  font-family: var(--serif); font-style: italic;
  color: rgba(255,255,255,.8); font-size: 17px; margin-top: 14px;
}

.hero-fineprint { font-size: 17px; color: rgba(255,255,255,.78); margin-top: 18px; }

/* Legibility over the dimmed brain: a soft violet-black halo (same idea
   as the feel line) so the white headline reads without a scrim hiding
   the brain. Kept subtle at all sizes. */
.hero-h1 { text-shadow: 0 2px 26px rgba(18,12,40,.5); }
.hero-lede { text-shadow: 0 1px 16px rgba(18,12,40,.42); }

/* Mobile hero: keep the H1 in the safe area, right-size the secondary
   lines (17px reads too heavy for "fine print"), and tighten the vertical
   rhythm so the whole block clears the fold on short phones. The CTA row
   already wraps to a clean centered stack at this width. */
@media (max-width: 520px) {
  .beat { padding-top: max(88px, calc(env(safe-area-inset-top) + 72px)); padding-bottom: 40px; }
  .hero-chip { margin-bottom: 18px; }
  .hero-h1 { margin-bottom: 14px; letter-spacing: -.02em; }
  .hero-lede { margin-bottom: 22px; }
  .hero-cta-row { gap: 12px; margin-bottom: 20px; }
  .proof-row, .proof-row .stars { font-size: 15px; }
  .hero-microquote { font-size: 15px; margin-top: 12px; }
  .hero-fineprint { font-size: 13px; margin-top: 14px; }
}

/* ------------------------------------------------------------
   ACT 2 · #s-feel — 120vh, sticky center stage for the engine's
   emoji pass. DOM = serif line + the 8 [data-mood-label] words.
   ------------------------------------------------------------ */
#s-feel { min-height: 120vh; min-height: 120svh; }
.feel-stage {
  position: sticky; top: 0;
  min-height: 100vh; min-height: 100svh;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  padding: 96px clamp(20px, 5vw, 48px) 40px;
}

/* Serif line: fades in as the stage arrives, out by ~70% of the feel
   ACT (scrubbed by js/page.js; visible by default for no-JS /
   reduced motion). */
.feel-line {
  font-family: var(--serif); font-style: italic; font-weight: 500;
  font-size: clamp(30px, 5vw, 52px); line-height: 1.2;
  color: rgba(255,255,255,.96); margin: 0 0 18px;
  text-shadow: 0 0 34px rgba(196,178,246,.55);
  will-change: opacity;
}
body.has-js .feel-line { opacity: 0; }
/* The feel line must hold mid-viewport for the WHOLE feel pass on every
   tier: the belt act spans 120vh of scroll but the sticky stage only
   pins ~20vh, so an in-flow line scrolls off the top a third of the way
   in and reads as "missing". Detach it to fixed on all JS tiers (engine
   tiers 2-3 already relied on this; tiers 0/1 + poster-hold now match).
   page.js owns its opacity window. Reduced motion keeps it in flow and
   fully visible so the static page reads normally. */
@media (prefers-reduced-motion: no-preference) {
  body.has-js .feel-line {
    position: fixed; left: 24px; right: 24px; top: max(96px, 13vh);
    margin: 0; text-align: center; pointer-events: none; z-index: 3;
  }
}

/* Mood-word cloud — [data-mood-label] elements.
   The 3D engine positions/reveals these on tiers 2–3; the CSS
   below is the full fallback presentation for tier 0/1/no-tier. */
.mood-cloud {
  position: relative; width: min(920px, 92vw); height: min(64vh, 620px); flex: none;
}
.mood-word {
  position: absolute;
  opacity: 0;                 /* engine (tiers 2-3) or the .in reveal below owns visibility */
  font-family: var(--serif); font-style: italic; font-weight: 500;
  font-size: 17px;            /* floor; per-word clamps below only go up */
  color: #fff; white-space: nowrap;
  text-shadow: 0 0 18px rgba(196,178,246,.9), 0 0 44px rgba(138,127,216,.6);
}
.mood-word[data-mood-label="anxious"]      { top: 6%;  left: 14%; font-size: clamp(24px,3.4vw,38px); }
.mood-word[data-mood-label="overthinking"] { top: 20%; right: 8%; font-size: clamp(28px,4vw,46px); }
.mood-word[data-mood-label="tired"]        { top: 38%; left: 6%;  font-size: clamp(22px,3vw,34px); }
.mood-word[data-mood-label="hopeful"]      { top: 47%; left: 42%; font-size: clamp(30px,4.6vw,54px); text-shadow: 0 0 22px rgba(236,230,255,.9), 0 0 50px rgba(196,178,246,.55); }
.mood-word[data-mood-label="calm"]         { top: 66%; left: 16%; font-size: clamp(26px,3.6vw,42px); }
.mood-word[data-mood-label="lonely"]       { top: 62%; right: 12%; font-size: clamp(22px,3vw,34px); }
.mood-word[data-mood-label="stress"]       { top: 82%; left: 36%; font-size: clamp(24px,3.2vw,36px); }
.mood-word[data-mood-label="grateful"]     { top: 87%; right: 20%; font-size: clamp(26px,3.6vw,42px); }

/* CSS fallback reveal (tier 0/1, engine absent, or poster-hold —
   i.e. a tier-2/3 engine that wedged before painting; page.js strips
   the engine's inline styles in that case). On healthy tiers 2–3 the
   engine owns opacity/transform via inline styles. */
body.hero-tier-0 .mood-word,
body.hero-tier-1 .mood-word,
body.poster-hold .mood-word,
body:not(.hero-tier-0):not(.hero-tier-1):not(.hero-tier-2):not(.hero-tier-3) .mood-word {
  opacity: 0; transform: translateY(22px) scale(.92);
  transition: opacity .9s var(--settle), transform .9s var(--settle);
}
body.hero-tier-0 .mood-cloud.in .mood-word,
body.hero-tier-1 .mood-cloud.in .mood-word,
body.poster-hold .mood-cloud.in .mood-word,
body:not(.hero-tier-0):not(.hero-tier-1):not(.hero-tier-2):not(.hero-tier-3) .mood-cloud.in .mood-word {
  opacity: 1; transform: none;
}
.mood-cloud .mood-word:nth-child(1) { transition-delay: .05s; }
.mood-cloud .mood-word:nth-child(2) { transition-delay: .22s; }
.mood-cloud .mood-word:nth-child(3) { transition-delay: .4s; }
.mood-cloud .mood-word:nth-child(4) { transition-delay: .58s; }
.mood-cloud .mood-word:nth-child(5) { transition-delay: .76s; }
.mood-cloud .mood-word:nth-child(6) { transition-delay: .94s; }
.mood-cloud .mood-word:nth-child(7) { transition-delay: 1.12s; }
.mood-cloud .mood-word:nth-child(8) { transition-delay: 1.3s; }

/* Non-engine tiers (0/1, poster-hold, or no tier yet): the sticky stage
   only pins ~20vh so the whole cloud would scroll off well before the
   feel act ends, leaving a blank stretch. Hold it fixed + centered for
   the pass; page.js fades it out on the same window as the feel line so
   the beat clears before the reveal (no co-visibility). Engine tiers 2-3
   position the words themselves and are excluded. Reduced motion keeps
   the cloud in flow so the static page reads top-to-bottom. */
@media (prefers-reduced-motion: no-preference) {
  body.hero-tier-0 .mood-cloud,
  body.hero-tier-1 .mood-cloud,
  body.poster-hold .mood-cloud,
  body.has-js:not(.hero-tier-0):not(.hero-tier-1):not(.hero-tier-2):not(.hero-tier-3) .mood-cloud {
    position: fixed; left: 50%; top: 50%;
    transform: translate(-50%, -50%);
    margin: 0; pointer-events: none; z-index: 3;
  }
}

/* Story headlines (reveal / privacy) */
.story-h2 {
  font-family: var(--serif); font-weight: 600;
  font-size: clamp(30px, 4.6vw, 48px); line-height: 1.16;
  letter-spacing: -.01em; margin: 0 0 16px; text-wrap: balance;
}
.story-lede { font-size: clamp(17px, 2vw, 19px); color: rgba(255,255,255,.82); margin: 0 auto; max-width: 560px; }

/* ------------------------------------------------------------
   ACT 3 · #s-reveal — 140vh pinned two-phase. Sky bridges
   night→dawn behind it (#sky-bridge, scrubbed in js/page.js).
   Phase a: serif head, white. Phase b (stage.act2 at ~40%):
   #reveal-phone rises with the printing cascade; sample cards +
   the honest ten-journals line print beside it. At the bridge
   midpoint page.js adds #s-reveal.sky-lit → copy flips to ink.
   ------------------------------------------------------------ */
#s-reveal { min-height: 140vh; min-height: 140svh; }
.reveal-stage {
  position: sticky; top: 0;
  min-height: 100vh; min-height: 100svh;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: clamp(16px, 3vh, 30px);
  padding: 84px clamp(20px, 5vw, 48px) 36px;
}
.reveal-head { max-width: 780px; text-align: center; transition: opacity .7s var(--settle), transform .7s var(--settle); }
/* Beat exclusivity on EVERY JS tier: the reveal head (and the H2 "Your
   journal entries hold the clues.") must not appear until the feel act
   has finished absorbing — otherwise it bleeds in over the brain while
   mood words are still flying. page.js toggles #s-reveal.head-in at
   f≈0.97 for all tiers. This is the matched pair of the fixed feel line
   above; both are applied on tiers 0/1/2/3 so the choreography is
   consistent whatever tier the device resolves to (incl. the tier-1
   fallback and poster-hold). Reduced motion / no-JS: the head is forced
   visible by the reduced-motion block below, so it never locks out. */
body.has-js #s-reveal:not(.head-in) .reveal-head {
  opacity: 0; transform: translateY(28px);
}
.reveal-head .story-h2 { font-size: clamp(28px, 3.6vw, 42px); color: #fff; transition: color .6s ease, text-shadow .6s ease; }
.reveal-head .story-lede { transition: color .6s ease; }
#s-reveal.sky-lit .reveal-head .story-h2 { color: var(--juno-text-primary); }
#s-reveal.sky-lit .reveal-head .story-lede { color: var(--juno-text-secondary); }

.reveal-grid {
  display: grid; grid-template-columns: minmax(0, 1.2fr) auto;
  gap: clamp(28px, 5vw, 76px); align-items: center;
  width: 100%; max-width: 1080px;
}
.reveal-copy { text-align: left; }
.reveal-eyebrow {
  font-size: 12px; font-weight: 700; letter-spacing: 1.4px; text-transform: uppercase;
  color: rgba(255,255,255,.85); margin-bottom: 14px; transition: color .6s ease;
}
#s-reveal.sky-lit .reveal-eyebrow { color: var(--juno-accent-deep); }

.reveal-visual { display: flex; justify-content: center; }
.reveal-visual .phone { width: clamp(200px, 26svh, 300px); }

/* Reveal-phone entrance + printing cascade (class contract:
   .reveal-stage.act2 = phase b; children of #reveal-phone .p-body
   print top-to-bottom; mockup INTERNALS untouched). Gated on
   body.has-js so no-JS never hides content. */
body.has-js .reveal-visual .phone {
  opacity: 0; transform: translateY(56px) scale(.97);
  transition: opacity .9s var(--settle), transform .9s var(--settle);
  will-change: opacity, transform;
}
body.has-js .reveal-stage.act2 .reveal-visual .phone { opacity: 1; transform: none; }
body.has-js #reveal-phone .p-body > * {
  opacity: 0; transform: translateY(16px);
  transition: opacity .6s var(--settle), transform .6s var(--settle);
}
body.has-js .reveal-stage.act2 #reveal-phone .p-body > * { opacity: 1; transform: none; }
.reveal-stage.act2 #reveal-phone .p-body > :nth-child(1) { transition-delay: .30s; }
.reveal-stage.act2 #reveal-phone .p-body > :nth-child(2) { transition-delay: .42s; }
.reveal-stage.act2 #reveal-phone .p-body > :nth-child(3) { transition-delay: .54s; }
.reveal-stage.act2 #reveal-phone .p-body > :nth-child(4) { transition-delay: .66s; }
.reveal-stage.act2 #reveal-phone .p-body > :nth-child(5) { transition-delay: .78s; }
.reveal-stage.act2 #reveal-phone .p-body > :nth-child(6) { transition-delay: .90s; }
body.has-js .reveal-copy .reveal-eyebrow,
body.has-js .reveal-copy .insight-card,
body.has-js .reveal-copy .samples-note,
body.has-js .reveal-copy .engine-note {
  opacity: 0; transform: translateY(22px);
  transition: opacity .7s var(--settle), transform .7s var(--settle);
}
body.has-js .reveal-stage.act2 .reveal-copy .reveal-eyebrow,
body.has-js .reveal-stage.act2 .reveal-copy .insight-card,
body.has-js .reveal-stage.act2 .reveal-copy .samples-note,
body.has-js .reveal-stage.act2 .reveal-copy .engine-note { opacity: 1; transform: none; }
.reveal-stage.act2 .reveal-copy .reveal-eyebrow { transition-delay: .06s; }
.reveal-stage.act2 .reveal-copy .insight-card:nth-of-type(1) { transition-delay: .15s; }
.reveal-stage.act2 .reveal-copy .insight-card:nth-of-type(2) { transition-delay: .30s; }
.reveal-stage.act2 .reveal-copy .insight-card:nth-of-type(3) { transition-delay: .45s; }
.reveal-stage.act2 .reveal-copy .samples-note { transition-delay: .58s; }
.reveal-stage.act2 .reveal-copy .engine-note { transition-delay: .68s; }

@media (max-width: 899px) {
  /* Static stacked layout: head, then phone (order:-1), then copy.
     The stage flows from the section top, so padding-top is the phone's
     ONLY clearance from the fixed nav (pill bottom ≈ 74px). Give the head
     a little air below the nav; the phone that follows then sits fully
     framed below it, its whole top (island + status + "Your Story") clear
     of the nav. ALL tiers share this single value — the phone content is
     printed on entry by page.js (mqStack latch), so no tier needs the old
     oversized run-in that used to shove the phone below the fold. */
  .reveal-stage {
    position: static; min-height: 0;
    padding-top: clamp(90px, 12vh, 118px);
  }
  #s-reveal { min-height: 140svh; }
  .reveal-grid { grid-template-columns: 1fr; gap: 32px; }
  .reveal-visual { order: -1; }
  /* Cap the phone so the WHOLE device (status bar → tab bar) fits under
     the head within one viewport, top clear of the nav. The svh term caps
     device HEIGHT (frame aspect 390/844 → height = width x 2.164) so it
     holds in short landscape too; 224px / 62vw govern in portrait. */
  .reveal-visual .phone { width: min(224px, 62vw, 30svh); }
  .reveal-copy { text-align: center; }
  .reveal-copy .insight-samples { text-align: left; }
}

/* Sample insight cards (reveal phase b) */
.insight-samples {
  display: grid; grid-template-columns: 1fr; gap: 12px;
  margin: 0 0 16px; text-align: left; max-width: 470px;
}
@media (max-width: 899px) { .insight-samples { margin-inline: auto; } }

.insight-card {
  position: relative;
  background: var(--juno-surface); color: var(--juno-text-primary);
  border-radius: var(--r-card); padding: 20px 20px 18px;
  box-shadow: 0 12px 40px rgba(23,17,48,.45);
}
.insight-kind {
  display: flex; align-items: center; gap: 9px; margin-bottom: 12px;
  font-size: 11.5px; font-weight: 700; letter-spacing: 1.2px; text-transform: uppercase;
}
.kind-icon {
  width: 24px; height: 24px; border-radius: 50%; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
}
.kind-icon svg { width: 13px; height: 13px; }
.insight-card.kind-pattern .insight-kind { color: var(--kind-pattern); }
.insight-card.kind-pattern .kind-icon { background: var(--kind-pattern-tint); color: var(--kind-pattern); }
.insight-card.kind-trigger .insight-kind { color: var(--kind-trigger); }
.insight-card.kind-trigger .kind-icon { background: var(--kind-trigger-tint); color: var(--kind-trigger); }
.insight-card.kind-quote .insight-kind { color: var(--kind-quote); }
.insight-card.kind-quote .kind-icon { background: var(--kind-quote-tint); color: var(--kind-quote); }

.insight-headline {
  font-family: var(--serif); font-size: 18px; font-weight: 600; line-height: 1.35; margin: 0 0 8px;
}
.insight-body { font-size: 14px; color: var(--juno-text-secondary); margin: 0; line-height: 1.5; }
.insight-quote {
  font-family: var(--serif); font-style: italic; font-size: 16.5px; line-height: 1.45;
  color: var(--juno-text-primary); margin: 0 0 8px;
}
.insight-date { font-size: 12.5px; color: var(--juno-text-tertiary); }

.sample-badge {
  position: absolute; top: 14px; right: 14px;
  font-size: 10px; font-weight: 700; letter-spacing: 1.2px;
  color: var(--juno-text-tertiary-text);
  background: var(--juno-sample-bg);
  padding: 4px 9px; border-radius: 10px;
}
/* White@.85 while the sky is dark; ink once #s-reveal.sky-lit lands. */
.samples-note { font-size: 17px; color: rgba(255,255,255,.85); text-align: left; margin: 0; transition: color .6s ease; }
.engine-note {
  font-size: 17px; color: rgba(255,255,255,.85); text-align: left; margin: 10px 0 0; transition: color .6s ease;
}
.engine-note strong { color: #fff; font-weight: 600; transition: color .6s ease; }
#s-reveal.sky-lit .samples-note,
#s-reveal.sky-lit .engine-note { color: var(--juno-text-secondary); }
#s-reveal.sky-lit .engine-note strong { color: var(--juno-accent-deep); }
@media (max-width: 899px) { .samples-note, .engine-note { text-align: center; } }

/* ------------------------------------------------------------
   ACT 5 · #s-privacy — 100vh, transparent over the fixed stack;
   #sky-bridge-dusk scrubs dusk→night behind it (js/page.js).
   Card CENTERED; copy is the corrected P1 legal set.
   ------------------------------------------------------------ */
.privacy-act { position: relative; z-index: 3; }
.privacy-beat {
  min-height: 100vh; min-height: 100svh;
  display: grid; place-items: center; align-content: center;
  padding: 96px clamp(20px, 5vw, 48px);
  text-align: center;
}

/* Privacy glass card */
.privacy-card {
  margin: 36px auto 0; max-width: 560px; text-align: left;
  background: rgba(255,255,255,.10);
  border: 1px solid rgba(255,255,255,.20);
  -webkit-backdrop-filter: blur(20px) saturate(1.3);
  backdrop-filter: blur(20px) saturate(1.3);
  border-radius: var(--r-modal); padding: 28px clamp(20px, 4vw, 32px);
  box-shadow: 0 18px 60px rgba(23,17,48,.5);
}
.privacy-point { display: flex; gap: 16px; align-items: flex-start; padding: 13px 0; }
.privacy-point + .privacy-point { border-top: 1px solid rgba(255,255,255,.12); }
.privacy-ico {
  width: 40px; height: 40px; border-radius: 50%; flex: none;
  background: rgba(255,255,255,.12); border: 1px solid rgba(255,255,255,.2);
  display: flex; align-items: center; justify-content: center; color: #fff;
}
.privacy-ico svg { width: 19px; height: 19px; }
.privacy-point h3 { margin: 0 0 3px; font-family: var(--serif); font-size: 18px; font-weight: 600; }
.privacy-point p { margin: 0; font-size: 17px; color: rgba(255,255,255,.82); line-height: 1.5; }
.privacy-link {
  display: inline-flex; align-items: center; margin-top: 18px;
  color: #fff; font-weight: 600; font-size: 17px; text-decoration: none;
  border-bottom: 1px solid rgba(255,255,255,.4); padding-bottom: 2px; min-height: 44px;
}
.privacy-link:hover { border-color: #fff; }

/* ------------------------------------------------------------
   Page body (feature journey onward) — covers the fixed canvas.
   ------------------------------------------------------------ */
.page-body {
  position: relative; z-index: 5;
  /* Contain decorative overhang (the rotated Monthly-Review .float-slide
     is pushed to right:-5% by phone.css and its rotated corner pokes ~2px
     past the viewport at 380-520px, giving scrollWidth 392 at 390). clip
     (not hidden) kills the horizontal scroll without creating a scroll
     container and leaves vertical reveals + sticky untouched. No page-body
     child intentionally overflows the viewport on desktop, so this only
     ever trims that decorative sliver. */
  overflow-x: clip;
}

/* ------------------------------------------------------------
   Sky arc — ONE monotonic dawn→day→dusk pass across the 7 feature
   sections. Section N = linear(cN-1 → cN) + a per-section wash so
   every step is visibly distinct. c0 hands off from the night→dawn
   bridge; c7 hands off to the dusk→night bridge at #s-privacy.
   ------------------------------------------------------------ */
.sky-arc-1 { background: radial-gradient(110% 64% at 50% -6%, rgba(244,208,168,.42), transparent 62%),
             linear-gradient(180deg, var(--sky-arc-c0), var(--sky-arc-c1)); }
.sky-arc-2 { background: radial-gradient(100% 58% at 50% -6%, rgba(247,224,196,.26), transparent 60%),
             linear-gradient(180deg, var(--sky-arc-c1), var(--sky-arc-c2)); }
.sky-arc-3 { background: radial-gradient(120% 66% at 50% -8%, rgba(255,255,255,.5), transparent 58%),
             linear-gradient(180deg, var(--sky-arc-c2), var(--sky-arc-c3)); }
.sky-arc-4 { background: linear-gradient(180deg, var(--sky-arc-c3), var(--sky-arc-c4)); }
.sky-arc-5 { background: radial-gradient(110% 60% at 50% 106%, rgba(138,127,216,.16), transparent 60%),
             linear-gradient(180deg, var(--sky-arc-c4), var(--sky-arc-c5)); }
.sky-arc-6 { background: radial-gradient(110% 60% at 50% 106%, rgba(110,98,194,.22), transparent 58%),
             linear-gradient(180deg, var(--sky-arc-c5), var(--sky-arc-c6)); }
.sky-arc-7 { background: radial-gradient(120% 66% at 50% 108%, rgba(74,60,130,.30), transparent 62%),
             linear-gradient(180deg, var(--sky-arc-c6), var(--sky-arc-c7)); }

.feature {
  min-height: 90vh; min-height: 90svh;
  display: grid; align-items: center;
  padding: clamp(56px, 7vw, 96px) clamp(20px, 5vw, 48px);
}
.feature-grid {
  max-width: 1120px; margin: 0 auto;
  display: grid; grid-template-columns: 1fr 1fr;
  gap: clamp(36px, 6vw, 88px); align-items: center;
}
.feature.flip .feature-copy { order: 2; }
.feature.flip .feature-visual { order: 1; }
@media (max-width: 899px) {
  .feature-grid { grid-template-columns: 1fr; gap: 44px; }
  .feature.flip .feature-copy { order: 1; }
  .feature.flip .feature-visual { order: 2; }
  .feature-copy { text-align: center; }
  .feature-bullets { text-align: left; }
}

.feature-eyebrow {
  font-size: 13px; font-weight: 700; letter-spacing: 1.4px; text-transform: uppercase;
  color: var(--juno-accent-deep); margin-bottom: 14px;
}
.feature-h2 {
  font-family: var(--serif); font-weight: 600;
  font-size: clamp(28px, 3.6vw, 40px); line-height: 1.15; letter-spacing: -.01em;
  margin: 0 0 14px; text-wrap: balance;
}
.feature-lede { font-size: 18px; color: var(--juno-text-secondary); margin: 0 0 22px; }

.feature-bullets { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; }
.feature-bullets li {
  position: relative; padding-left: 26px;
  font-size: 15.5px; color: var(--juno-text-secondary); line-height: 1.5;
}
.feature-bullets li::before {
  content: "✦"; position: absolute; left: 2px; top: 0;
  color: var(--juno-accent); font-size: 13px;
}
.feature-bullets strong { color: var(--juno-text-primary); font-weight: 600; }

.feature-visual {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 14px; position: relative;
}
.phone-caption {
  font-size: 12px; color: var(--juno-text-tertiary-text);
  text-align: center; margin: 0; max-width: 340px;
}

/* Monthly Review chapter grid */
.mr-chapters {
  margin-top: 26px; display: grid; grid-template-columns: 1fr 1fr; gap: 8px 16px;
}
@media (max-width: 480px) { .mr-chapters { grid-template-columns: 1fr; } }
.mr-chapters .ch {
  display: flex; gap: 10px; align-items: baseline; font-size: 13.5px; color: var(--juno-text-secondary);
  line-height: 1.4;
}
.mr-chapters .ch i {
  flex: none; width: 10px; height: 10px; border-radius: 50%;
  transform: translateY(1px);
}
.mr-chapters .ch b { color: var(--juno-text-primary); font-weight: 600; }
.mr-chapters-label {
  margin: 26px 0 12px; font-size: 12px; font-weight: 700; letter-spacing: 1.4px;
  text-transform: uppercase; color: var(--juno-text-tertiary-text);
}

/* Floating secondary slide next to MR phone */
.float-slide {
  position: absolute; right: max(-8px, 2%); bottom: 34px; width: min(200px, 46%);
  border-radius: var(--r-card); padding: 16px;
  background:
    radial-gradient(120% 80% at 20% 0%, rgba(255,255,255,.14), transparent 55%),
    linear-gradient(170deg, var(--mr-mood-a), var(--mr-mood-b) 55%, var(--mr-mood-c));
  color: #fff; box-shadow: var(--sh-modal);
  transform: rotate(3.5deg);
}
.float-slide .fs-eyebrow { font-size: 9.5px; font-weight: 800; letter-spacing: 1.8px; color: rgba(255,255,255,.65); margin-bottom: 10px; }
.float-slide .fs-row { display: flex; align-items: center; gap: 8px; margin-top: 9px; }
.float-slide .fs-row img { width: 22px; height: 22px; }
.float-slide .fs-emoji { width: 22px; font-size: 18px; line-height: 1; text-align: center; flex: none; }
.float-slide .fs-bar { flex: 1; height: 5px; border-radius: 3px; background: rgba(255,255,255,.22); overflow: hidden; }
.float-slide .fs-bar i { display: block; height: 100%; border-radius: 3px; background: #fff; }
.float-slide .fs-pct { font-size: 12px; font-weight: 700; min-width: 32px; text-align: right; }

/* ------------------------------------------------------------
   Night acts (founder + testimonials) — opaque night continuation
   between the dusk→night bridge and the deep-night closer.
   ------------------------------------------------------------ */
.act-night {
  color: #fff;
  background:
    radial-gradient(1.5px 1.5px at 18% 22%, rgba(255,255,255,.5), transparent 55%),
    radial-gradient(1px 1px at 72% 14%, rgba(255,255,255,.4), transparent 55%),
    radial-gradient(1.5px 1.5px at 86% 64%, rgba(255,255,255,.35), transparent 55%),
    radial-gradient(1px 1px at 30% 78%, rgba(255,255,255,.35), transparent 55%),
    radial-gradient(1px 1px at 54% 44%, rgba(255,255,255,.3), transparent 55%),
    var(--night-deep);
}
.act-night .feature-eyebrow { color: #C9BCF4; }
.act-night .feature-h2 { color: #fff; }
.act-night .feature-lede { color: rgba(255,255,255,.8); }
.act-night .testimonial-card { box-shadow: 0 16px 48px rgba(9,6,24,.55); }

/* ------------------------------------------------------------
   Founder card — 60vh
   ------------------------------------------------------------ */
.founder-section {
  min-height: 60vh; min-height: 60svh;
  display: grid; align-items: center;
  padding: clamp(72px, 9vw, 110px) clamp(20px, 5vw, 48px);
}
.founder-section.act-night {
  /* Top color #2A2050 = the dusk slab's 50% stop (seamless handoff). */
  background:
    radial-gradient(1.5px 1.5px at 18% 22%, rgba(255,255,255,.5), transparent 55%),
    radial-gradient(1px 1px at 72% 14%, rgba(255,255,255,.4), transparent 55%),
    radial-gradient(1.5px 1.5px at 86% 64%, rgba(255,255,255,.35), transparent 55%),
    radial-gradient(1px 1px at 30% 78%, rgba(255,255,255,.35), transparent 55%),
    linear-gradient(180deg, #2A2050, var(--night-deep));
}
.founder-card {
  max-width: 780px; margin: 0 auto;
  color: var(--juno-text-primary);
  background: var(--juno-surface-warm);
  border-radius: var(--r-modal); padding: clamp(28px, 5vw, 48px);
  box-shadow: var(--sh-elevated);
  display: grid; grid-template-columns: auto 1fr; gap: clamp(20px, 4vw, 36px);
  align-items: center;
}
@media (max-width: 640px) { .founder-card { grid-template-columns: 1fr; text-align: center; justify-items: center; } }
.founder-portrait {
  width: clamp(96px, 14vw, 132px); height: clamp(96px, 14vw, 132px);
  border-radius: 50%; object-fit: cover;
  border: 4px solid #fff; box-shadow: var(--sh-elevated);
}
.founder-eyebrow { font-size: 13px; font-weight: 700; letter-spacing: 1.3px; text-transform: uppercase; color: var(--juno-accent-deep); margin-bottom: 12px; }
.founder-quote {
  font-family: var(--serif); font-size: clamp(19px, 2.6vw, 24px); line-height: 1.4;
  margin: 0 0 14px; color: var(--juno-text-primary);
}
.founder-quote em { font-style: italic; color: var(--juno-accent-deep); }
.founder-sig { font-size: 14.5px; color: var(--juno-text-secondary); margin: 0 0 14px; }
.founder-link { font-weight: 600; font-size: 15.5px; color: var(--juno-accent-deep); text-decoration: none; display: inline-flex; align-items: center; min-height: 44px; }
.founder-link:hover { text-decoration: underline; }

/* ------------------------------------------------------------
   Testimonials
   ------------------------------------------------------------ */
.testimonials {
  min-height: 70vh; min-height: 70svh;
  display: grid; align-content: center;
  padding: clamp(72px, 9vw, 110px) clamp(20px, 5vw, 48px);
}
.testimonials-head { max-width: 720px; margin: 0 auto 44px; text-align: center; }
.testimonial-grid {
  max-width: 1080px; margin: 0 auto;
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px;
}
@media (max-width: 899px) { .testimonial-grid { grid-template-columns: 1fr; max-width: 480px; } }
.testimonial-card {
  background: var(--juno-surface); color: var(--juno-text-primary);
  border-radius: var(--r-card);
  padding: 26px 24px; box-shadow: var(--sh-card);
  display: flex; flex-direction: column; gap: 18px;
}
.testimonial-quote {
  font-family: var(--serif); font-style: italic; font-size: 17px; line-height: 1.5;
  margin: 0; color: var(--juno-text-primary); flex: 1;
}
.testimonial-who { display: flex; align-items: center; gap: 12px; }
.testimonial-who img { width: 46px; height: 46px; border-radius: 50%; object-fit: cover; }
.testimonial-who .name { font-weight: 600; font-size: 15px; }
.testimonial-who .role { font-size: 13px; color: var(--juno-text-secondary); }

/* ------------------------------------------------------------
   CTA closer — dark bookend, the ONE gold CTA on the page.
   ------------------------------------------------------------ */
.closer {
  position: relative; text-align: center; color: #fff;
  min-height: 100vh; min-height: 100svh;
  display: grid; align-content: center; justify-items: center;
  padding: clamp(88px, 12vw, 150px) clamp(20px, 5vw, 48px);
  background:
    radial-gradient(60% 42% at 50% 24%, rgba(138,127,216,.30), transparent 70%),
    linear-gradient(180deg, var(--night-deep), var(--juno-deep-bottom));
  overflow: hidden;
}
.closer-mascot { width: clamp(120px, 16vw, 150px); height: auto; margin-bottom: 6px; }
/* Neutral chip — gold is reserved for the one .btn-gold below. */
.closer-chip {
  display: inline-flex; font-size: 12.5px; font-weight: 700; letter-spacing: 1.4px; text-transform: uppercase;
  color: rgba(255,255,255,.88); background: rgba(255,255,255,.08);
  border: 1px solid rgba(255,255,255,.14); border-radius: var(--r-pill);
  padding: 8px 18px; margin: 14px 0 22px;
}
.closer h2 {
  font-family: var(--serif); font-weight: 600;
  font-size: clamp(32px, 5.4vw, 56px); line-height: 1.1; letter-spacing: -.015em;
  margin: 0 0 14px; text-wrap: balance;
}
.closer-sub { font-size: 17px; color: rgba(255,255,255,.8); margin: 0 0 26px; }
.closer .proof-row { margin-bottom: 30px; }
.btn-gold {
  display: inline-flex; align-items: center; gap: 10px;
  background: linear-gradient(180deg, var(--juno-gold-cta-top), var(--juno-gold-cta-bottom));
  color: var(--juno-gold-ink); font-weight: 700; font-size: 18px; text-decoration: none;
  padding: 17px 36px; min-height: 56px; border-radius: var(--r-pill);
  box-shadow: 0 10px 32px rgba(240,201,131,.35);
  transition: transform .15s var(--pop), filter .2s ease;
}
.btn-gold:hover { filter: brightness(1.04); }
.btn-gold:active { transform: scale(.96); }
.closer-fineprint { margin-top: 16px; font-size: 17px; color: rgba(255,255,255,.78); }

/* ------------------------------------------------------------
   Footer
   ------------------------------------------------------------ */
.footer {
  position: relative; z-index: 5;
  background: linear-gradient(180deg, var(--juno-bg-top), var(--juno-bg-bottom));
  padding: 56px clamp(20px, 5vw, 48px) 120px;
  color: var(--juno-text-secondary);
}
.footer-inner { max-width: 1080px; margin: 0 auto; }
.footer-row {
  display: flex; flex-wrap: wrap; gap: 28px; align-items: center; justify-content: center;
  padding-bottom: 36px; border-bottom: 1px solid rgba(138,127,216,.18); margin-bottom: 30px;
}
.app-badge {
  display: inline-flex; align-items: center; gap: 12px;
  background: #111; color: #fff; text-decoration: none;
  border-radius: 14px; padding: 10px 20px; min-height: 56px;
}
.app-badge svg { width: 26px; height: 26px; }
.app-badge .small { display: block; font-size: 11px; opacity: .85; }
.app-badge .large { display: block; font-size: 19px; font-weight: 600; line-height: 1.1; }
.qr-block { display: inline-flex; align-items: center; gap: 14px; }
.qr-block img { width: 74px; height: 74px; border-radius: 10px; background: #fff; padding: 5px; box-shadow: var(--sh-card); }
.qr-block .qr-text { font-size: 13px; line-height: 1.4; }
.qr-block .qr-text strong { display: block; color: var(--juno-text-primary); }
.footer-credits { text-align: center; }
.footer-logo { height: 26px; width: auto; margin-bottom: 14px; opacity: .9; }
.footer-built { font-size: 14.5px; margin-bottom: 12px; }
.footer-built a { color: inherit; text-decoration: underline; text-decoration-color: rgba(42,38,64,.2); text-underline-offset: 3px; }
.footer-legal {
  display: flex; flex-wrap: wrap; gap: 6px 10px; justify-content: center;
  font-size: 13.5px;
}
.footer-legal a { color: inherit; text-decoration: none; padding: 4px 2px; }
.footer-legal a:hover { color: var(--juno-text-primary); text-decoration: underline; }
.footer-legal .dot { color: var(--juno-text-tertiary); }

/* ------------------------------------------------------------
   Sticky mobile CTA
   ------------------------------------------------------------ */
.mobile-cta {
  position: fixed; left: 14px; right: 14px; bottom: 14px; z-index: 90;
  display: none; align-items: center; gap: 12px;
  background: var(--juno-accent); color: #fff; text-decoration: none;
  border-radius: var(--r-pill); padding: 12px 20px; min-height: 56px;
  box-shadow: 0 10px 30px rgba(46,38,90,.4);
  transform: translateY(130%); transition: transform .4s var(--settle);
}
.mobile-cta.show { transform: none; }
.mobile-cta .mc-text { flex: 1; line-height: 1.2; }
.mobile-cta .mc-line1 { display: block; font-weight: 700; font-size: 16px; }
.mobile-cta .mc-line2 { display: block; font-size: 12px; opacity: .85; }
.mobile-cta .mc-apple { width: 22px; height: 22px; flex: none; }
.mobile-cta .mc-arrow { font-size: 20px; }
@media (max-width: 759px) { .mobile-cta { display: flex; } }

/* ------------------------------------------------------------
   Scroll reveals (IntersectionObserver adds .in via js/page.js)
   ------------------------------------------------------------ */
.reveal { opacity: 0; transform: translateY(26px); transition: opacity .8s var(--settle), transform .8s var(--settle); }
.reveal.in { opacity: 1; transform: none; }
.reveal.d1 { transition-delay: .08s; }
.reveal.d2 { transition-delay: .16s; }
.reveal.d3 { transition-delay: .24s; }

/* No-JS / reduced-motion: everything visible, no scroll effects.
   (The poster keeps NO !important opacity: page.js still scrubs it
   out across #s-feel at tier 0 so the sky bridges stay visible.) */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .001s !important; animation-iteration-count: 1 !important; transition-duration: .001s !important; }
  /* Hero + feel content is always shown. The REVEAL act is intentionally
     left to the head-in / act2 gates (page.js) even here: transitions are
     ~instant above, so the reveal snaps in as you scroll past the feel
     block instead of bleeding over it. Keeps beats exclusive with zero
     perceptible motion, and it can't lock out (feelDone/act2 both flip
     from ordinary scrolling before you reach the reveal). */
  .reveal, .mood-word, .feel-line, .hero-copy { opacity: 1 !important; transform: none !important; }
  #hero-canvas { display: none !important; }
  /* Drop the scrubbed acts to ONE full-viewport centered block each (the
     extra 120/140vh runway only exists for the animation). Content sits at
     each section's centre, so the next beat's content stays a full viewport
     away — the reveal head never shares the screen with the mood words, and
     there is no tall empty pin to scroll through (no blank stretch). */
  #s-feel, #s-reveal { min-height: 100svh; }
  .feel-stage, .reveal-stage { position: static; min-height: 100svh; justify-content: center; }
}
@media (scripting: none) {
  .reveal, .mood-word, .feel-line { opacity: 1; transform: none; }
}

/* body.poster-hold — added by the page watchdog when a tier-2/3
   engine claimed the stage but never crossfaded the poster (uBoot
   signal missing after 4s): keep the poster, never a black hero. */
body.poster-hold #hero-poster { visibility: visible; }

/* ============================================================
   MOBILE PHONE FIT (<=899px) — feature-section device sizing,
   vertical rhythm, and the phone-rise reveal timing.

   The .phone-frame (phone.css) is aspect-ratio 390/844 and
   font-scales to its own container width (font-size: 100cqw/39),
   so capping the .phone WIDTH caps the whole DEVICE HEIGHT:
       device height = width x (844/390) = width x 2.164.
   We cap width in svh, so status-bar-to-tab-bar always fits the
   viewport height in portrait AND short landscape — never a
   half-cropped phone. These selectors (.feature .phone ...) are
   specific enough to win over phone.css, which loads after this
   file, so no !important is needed.
   Reference caps (device height as a share of the small viewport):
     30svh wide -> 64.9svh tall · 29svh -> 62.8svh · 32svh -> 69.3svh.
   ============================================================ */

/* ---- Phones (<=480px): device ~65svh tall, so the eyebrow + title
        read above it as the section arrives, and the tab bar clears
        the fold. Content flows from the top (align-items:start) so a
        tall stacked section never centre-overflows into its neighbour. */
@media (max-width: 480px) {
  .feature { align-items: start; padding-block: clamp(52px, 11vw, 80px); }
  .feature-grid { gap: clamp(26px, 6vw, 40px); }

  /* Single hero phone: 30svh -> ~65svh device, always whole.
     100% = column width, so it never exceeds its centred track. */
  .feature .feature-visual .phone { width: min(300px, 100%, 30svh); }

  /* Tasks + Goals duo: 82vw per phone forces one-per-row (2 x 82vw >
     100vw wraps), so both stack fully visible. Override phone.css's
     flex-basis:300px + min-width:auto so the svh cap governs the size. */
  .feature.two-phone .phone-duo { gap: clamp(30px, 8vw, 46px); }
  .feature.two-phone .phone-duo .phone {
    flex: 0 1 auto; min-width: 0;
    width: min(270px, 82vw, 29svh);
  }
}

/* ---- Reveal act (<=480px): the FIRST app screen ("Your Story").
        Two mobile fixes over the shared <=899px reveal rules above.

        (1) TOP CLEARANCE. The floating nav is fixed at top:12-14px, ~56px
            tall, so its bottom sits ≈74px down. On engine tiers 2-3 the
            shared block pushes .reveal-stage down clamp(240px,38svh,420px)
            to land the head mid-viewport; on a phone that buries the device
            below the fold, so reaching its tab bar scrolls the "Your Story"
            top (island + status bar + serif header) up under the nav pill.
            Re-pin the reveal content to just BELOW the nav (~96px) on every
            tier so the section headline + the WHOLE device compose in one
            viewport, with the SAMPLE cards flowing below. env(safe-area)
            keeps the notch clear in standalone/PWA.

        (2) DEVICE HEIGHT CAP. .phone-frame is aspect 390/844, so device
            height = phone width x 2.164. The shared rule's 34svh term makes
            the device 34svh x 2.164 ≈ 74svh tall — too tall to also seat
            the headline, so its top hid under the nav on shorter phones.
            26svh wide => ~56svh tall device, leaving ~44svh above for the
            nav + headline. At 390x844: min(224,64vw=250,26svh=219)=219px
            wide -> 474px (56svh) tall; head lands ~96px, device bottom
            ~784px, all inside 844 with the tab bar clear of the fold. */
@media (max-width: 480px) {
  .reveal-stage { padding-top: max(96px, calc(env(safe-area-inset-top) + 80px)); }
  body.hero-tier-2:not(.poster-hold) .reveal-stage,
  body.hero-tier-3:not(.poster-hold) .reveal-stage {
    padding-top: max(96px, calc(env(safe-area-inset-top) + 80px));
  }
  .reveal-visual .phone { width: min(224px, 64vw, 26svh); }
}

/* ---- Tablet / large-phone landscape (481-899px): single column
        (the feature grid flips to 1fr at 899px — this range matches it),
        more width to spend, same svh height guarantee. The duo stays side
        by side and shrinks with vw (2 x 44vw + gap < 100vw) so it never
        overflows; near 899 it wraps cleanly rather than overrunning. */
@media (min-width: 481px) and (max-width: 899px) {
  .feature { align-items: start; }
  .feature .feature-visual .phone { width: min(340px, 100%, 32svh); }
  /* 44vw per phone keeps the pair side by side (2 x 44vw + gap < 100vw)
     without ever overflowing; svh still caps each device's height. */
  .feature.two-phone .phone-duo .phone {
    flex: 0 1 auto; min-width: 0;
    width: min(300px, 44vw, 30svh);
  }
}

/* ---- Phone-rise reveal (<=899px): the IntersectionObserver in
        js/page.js adds .in once .feature-visual actually enters the
        viewport. Tune the motion so the now-whole device lifts in
        cleanly from below (origin at its base) instead of the generic
        26px card nudge. Kept gentle so the early trigger (12% visible)
        reads as a rise that has settled by the time the phone centres.
        Reduced motion falls through to the global block that forces
        every .reveal visible with no transform. */
@media (max-width: 899px) and (prefers-reduced-motion: no-preference) {
  /* body.has-js gate (matches the reveal-phone pattern above): without
     it this higher-specificity opacity:0 would out-rank the
     @media(scripting:none) fallback and hide phones with JS disabled. */
  body.has-js .feature .feature-visual.reveal {
    opacity: 0;
    transform: translateY(46px) scale(.972);
    transform-origin: 50% 100%;
    transition: opacity .85s var(--settle), transform .85s var(--settle);
    will-change: opacity, transform;
  }
  body.has-js .feature .feature-visual.reveal.in { opacity: 1; transform: none; }
}
