/* ==========================================================================
   BeCozU — Root Page Sections (home.css)
   Loaded only by the root index.html. Everything shared across pages lives
   in core.css, which this file assumes is already loaded (tokens, .reveal,
   .section/.eyebrow/.headline-*, header/nav/footer, .card/.tile/.chip,
   the Neuro Flow diagram, and the Journey background).
   ========================================================================== */

/* --------------------------------------------------------------------------
   Hero Section — Upper Amber Cradle Stage + Lower Pure Black Narrative
   -------------------------------------------------------------------------- */
.hero-section {
  position: relative;
  background: var(--bg-primary);
}

/* Two full-screen beats, stacked: the cradle glows and the promise is
   stated first, then the name and the way forward get a screen of their
   own instead of sharing the first one. */
.hero-sector {
  position: relative;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.hero-sector-open {
  min-height: 100vh;
  justify-content: flex-start;
  padding-top: calc(var(--nav-height) + 10px);
  padding-bottom: 40px;
  overflow: hidden;
}

.hero-sector-brand {
  min-height: 100vh;
  justify-content: center;
  padding: 60px 24px;
  text-align: center;
}

/* 1. Upper Stage: Pristine Amber Cradle (Full-scale Cinematic Immersive View) */
.hero-cradle-viewport {
  position: relative;
  width: 100%;
  max-width: 100%;
  height: clamp(380px, 52vh, 620px);
  margin: 0 0 16px 0;
  display: flex;
  justify-content: center;
  align-items: center;
  overflow: hidden;
}

.hero-cradle-viewport .hero-video-bg {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 36%;
  opacity: 0.88;
  filter: contrast(1.1) brightness(0.96);
  z-index: 1;
}

.hero-cradle-fade {
  position: absolute;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 48%;
  background: linear-gradient(180deg, transparent 0%, rgba(0, 0, 0, 0.75) 60%, var(--bg-primary) 100%);
  z-index: 2;
  pointer-events: none;
}

/* 2. Lower Stage: Pure Black Area Below the Cradle for Narrative & Buttons (Zero Overlap) */
.hero-content {
  position: relative;
  z-index: 3;
  max-width: 880px;
  width: 100%;
  padding: 0 24px;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  background: var(--bg-primary);
}

.hero-quote-intro {
  font-size: clamp(0.85rem, 1.3vw, 1.05rem);
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--accent-cyan);
  margin-bottom: 18px;
  text-shadow: 0 0 20px rgba(0, 210, 255, 0.6);
}

.hero-title {
  margin-bottom: 22px;
  text-shadow: 0 10px 40px rgba(0, 0, 0, 0.9);
}

.hero-tagline {
  max-width: 720px;
  margin: 0 auto 30px auto;
}

.hero-tagline-lead {
  font-size: clamp(1.15rem, 2.2vw, 1.625rem);
  font-weight: 400;
  color: var(--text-primary);
  line-height: 1.45;
  margin-bottom: 18px;
  word-break: keep-all;
  overflow-wrap: break-word;
  text-wrap: balance;
}

/* Vertical rhythm for the brand sector: the gap *inside* this group has to
   stay clearly smaller than the gaps *between* groups below, or the mark, the
   line, the buttons and the scroll cue all read as one undifferentiated block.
   Viewport-relative so a full-height sector doesn't leave the cluster stranded
   in the middle of it — but clamped, so a short window can't collapse it. */
.hero-brand-statement {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  /* Centered precisely in the upper region of the viewport,
     with expansive cinematic breathing room above 'A Dark Light.' */
  margin-top: clamp(-220px, -16vh, -65px);
  gap: clamp(100px, 18vh, 220px);
  margin-bottom: clamp(40px, 7vh, 80px);
}

/* Resting state is the mark already lit — so with scripting off it is simply
   there, rather than stranded at opacity 0 waiting for an observer that will
   never run. */
.hero-brand-glow-logo {
  height: clamp(36px, 4.8vw, 52px);
  width: auto;
  display: block;
  /* Every keyframe declares the same filter functions in the same order —
     brightness, invert, then exactly two drop-shadows. A list that changes
     length between stops cannot be interpolated at all, which is what made
     the outer glow snap into existence partway through instead of growing. */
  filter: brightness(0) invert(1) drop-shadow(0 0 24px rgba(0, 210, 255, 0.45)) drop-shadow(0 0 42px var(--veil-4));
}

/* Armed only when JS is present to light it: dark, scaled back, no glow —
   waiting for initBrandBloom to bring it out of the black. */
:where(.has-js) .hero-brand-glow-logo {
  opacity: 0;
  transform: scale(0.88);
  filter: brightness(0) invert(1) drop-shadow(0 0 0 rgba(0, 210, 255, 0)) drop-shadow(0 0 0 rgba(255, 255, 255, 0));
}

/* Toggled by initBrandBloom on entering the sector, and removed on leaving so
   the whole bloom plays again the next time the reader comes back. */
.hero-brand-glow-logo.is-blooming {
  animation: logo-dawn-bloom 10s cubic-bezier(0.33, 0, 0.25, 1) 0.5s forwards,
    logo-dawn-breathe 16s ease-in-out 10.5s infinite alternate;
}

.hero-dark-light-sub {
  font-size: clamp(1.25rem, 2.4vw, 1.875rem);
  letter-spacing: 0.05em;
  display: block;
}

.hero-cta-group {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-4);
  flex-wrap: wrap;
  margin-bottom: clamp(28px, 4.6vh, 50px);
}

/* Scroll indicator placed right below CTA buttons */
.hero-scroll-indicator {
  position: relative;
  margin: 0 auto;
  width: fit-content;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  color: var(--text-secondary);
  font-size: 0.75rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  z-index: 3;
  pointer-events: none;
}

/* .hero-enter already played this element in once, on load, before the
   reader ever scrolled down to it — so by the time they arrived here it was
   sitting there fully formed. Toggled instead by the same initBrandBloom
   observer that blooms the logo above it, so it arrives out of the dark on
   every visit to this screen, not just the first. No glow keyframes needed
   here — a label and a line only need the fade, not the cinematic ramp. */
:where(.has-js) .hero-scroll-indicator {
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 1.1s var(--ease-apple), transform 1.1s var(--ease-apple);
}

.hero-scroll-indicator.is-visible {
  opacity: 1;
  transform: none;
}

/* One unbroken ramp out of the dark. Intermediate stops each got their own
   pass of the easing curve, so the light arrived in four visible landings
   rather than one continuous rise — the curve belongs on the whole animation,
   not on every segment of it. */
@keyframes logo-dawn-bloom {
  from {
    opacity: 0;
    transform: scale(0.88);
    filter: brightness(0) invert(1) drop-shadow(0 0 0 rgba(0, 210, 255, 0)) drop-shadow(0 0 0 rgba(255, 255, 255, 0));
  }

  to {
    opacity: 0.92;
    transform: scale(1.04);
    filter: brightness(0) invert(1) drop-shadow(0 0 24px rgba(0, 210, 255, 0.45)) drop-shadow(0 0 42px var(--veil-4));
  }
}

/* Opens on exactly the state the bloom closed on, so the handoff between the
   two animations passes without a dip. */
@keyframes logo-dawn-breathe {
  from {
    opacity: 0.92;
    transform: scale(1.04);
    filter: brightness(0) invert(1) drop-shadow(0 0 24px rgba(0, 210, 255, 0.45)) drop-shadow(0 0 42px var(--veil-4));
  }

  to {
    opacity: 1;
    transform: scale(1.085);
    filter: brightness(0) invert(1) drop-shadow(0 0 34px rgba(0, 210, 255, 0.62)) drop-shadow(0 0 58px rgba(255, 255, 255, 0.5));
  }
}

.hero-scroll-text {
  display: inline-block;
  animation: pulse-down 2.4s infinite ease-in-out;
}

.scroll-line {
  width: 1px;
  height: 32px;
  background: linear-gradient(180deg, var(--accent-cyan) 0%, transparent 100%);
  animation: pulse-down 2.4s infinite ease-in-out;
}

@keyframes pulse-down {

  0%,
  100% {
    opacity: 0.35;
    transform: translateY(0);
  }

  50% {
    opacity: 0.95;
    transform: translateY(5px);
  }
}

/* Hero entrance — the dark resolves into a voice, then a promise, then a way
   forward. Staggered rather than simultaneous so it reads as an opening shot. */
:where(.has-js) .hero-enter {
  opacity: 0;
  transform: translateY(28px);
  transition:
    opacity 1s var(--ease-apple),
    transform 1s var(--ease-apple);
  transition-delay: calc(var(--i, 0) * 160ms);
}

.is-ready .hero-enter {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  .hero-enter {
    opacity: 1;
    transform: none;
  }
}

/* --------------------------------------------------------------------------
   Section: Dark Knight Story Showcase (Apple 2-Column Split Architecture)
   -------------------------------------------------------------------------- */
/* Scroll track: a tall section the reader walks through. The stage inside is
   pinned, so scrolling advances the chapters instead of moving the product. */
.story-scroll-track {
  position: relative;
  height: 140vh;
}

.story-pin {
  position: sticky;
  top: 100px;
  height: calc(100vh - 100px);
  display: flex;
  align-items: center;
  overflow-x: clip;
}

/* Fallback when JS is unavailable or the reader asked for reduced motion:
   unpin, and let all five chapters stack and read as plain content. */
.no-pin .story-scroll-track {
  height: auto;
  padding: var(--space-12) 0;
}

.no-pin .story-pin {
  position: static;
  height: auto;
}

/* Fullscreen stage: every chapter is one centered moment over an ambient
   glow, no tabs or boxed product shot. Absolutely fills .story-pin (already
   position:sticky, so it's a valid containing block). */
.story-stage {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 0 24px;
}

/* Cinematic bars, chapter 05 only — the reveal (below) already toggles
   #story.finale-active, so these just fade in on the same hook. */
.story-letterbox {
  position: absolute;
  left: 0;
  right: 0;
  height: clamp(40px, 8vh, 96px);
  background: #000000;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.6s var(--ease-apple);
  z-index: 1;
}

.story-letterbox-top {
  top: 0;
}

.story-letterbox-bottom {
  bottom: 0;
}

#story.finale-active .story-letterbox {
  opacity: 1;
}

.story-stage-backdrop {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  /* Solid black rather than the page's night sky: the film's last five seconds
     are literally black frames, and anything showing through them would leave
     the title card sitting on faint navy instead of nothing. It also makes the
     earlier shots composite toward black as their opacity ramps. */
  background: #000000;
}

/* The section is a real running shot now, not a CSS glow alone. Opacity
   tracks --chapter-light so the footage itself "emerges" as the chapters
   advance, same device the glow underneath it already used. */
.story-video-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  /* contain, not cover. The film is a composed 16:9 frame, and the pinned
     stage is wider than that on a short window — cover was cutting up to 31%
     off the height, which took the gold contacts out of the macro shot
     entirely. The pillarbox this leaves is black on a black page, so nothing
     is visible except the whole frame, as cut. */
  /* Narrow and portrait windows: fill the stage. The stage is taller than
     16:9 there, so letterboxing would strand the film as a thin band with a
     large empty gap above the subtitle. */
  object-fit: cover;
  opacity: calc(0.32 + var(--chapter-light, 0) * 0.48);
  transition: opacity 0.9s var(--ease-apple);
}

/* Wide windows: show the frame whole. Past roughly this aspect the pinned
   stage is wider than the film, and `cover` was cutting up to 31% off the
   height — enough to take the gold contacts out of the macro shot entirely.
   The pillarbox this leaves is black on a black page. */
@media (min-aspect-ratio: 3/2) {
  .story-video-bg {
    object-fit: contain;
  }
}

/* The section's copy of record. Hidden once JS is driving the single-line
   playback below — .no-pin and reduced-motion both restore it (further
   down) so the full narration is always available as plain stacked text
   whenever the animated version can't run. */
.lyric-stack {
  display: none;
}

.lyric-line {
  font-size: clamp(1.125rem, 1.6vw, 1.375rem);
  font-weight: 400;
  line-height: 1.6;
  color: var(--text-secondary);
  letter-spacing: -0.01em;
  word-break: keep-all;
  text-wrap: balance;
}

.lyric-line-climax {
  margin-top: 10px;
  font-size: clamp(1.8rem, 3.4vw, 2.9rem);
  font-weight: 700;
  line-height: 1.28;
  letter-spacing: -0.025em;
  /* Matches .story-finale-line.is-climax, so the stacked fallback closes on
     the same white the played version does. */
  color: #ffffff;
}

/* Finale line: chapter 05 only. A subtitle over the running video, not a
   poster headline — positioned in the lower third, just above the bottom
   letterbox bar, the way a caption sits under a film frame rather than
   dead-centre in it. Crossfades between lines the same way setEyebrow()
   crossfades text, driven by scroll progress in main.js. */
.story-finale-line {
  display: none;
  position: absolute;
  left: 50%;
  bottom: calc(clamp(40px, 8vh, 96px) + 28px);
  transform: translateX(-50%);
  z-index: 2;
  max-width: 720px;
  width: 100%;
  padding: 0 24px;
  font-size: clamp(1.1rem, 2.2vw, 1.5rem);
  font-weight: 600;
  line-height: 1.5;
  letter-spacing: -0.01em;
  word-break: keep-all;
  text-wrap: balance;
  background: var(--text-gradient);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  padding-bottom: 0.1em;
  opacity: 1;
  transition: opacity 0.3s var(--ease-apple);
}

.story-finale-line.is-swapping {
  opacity: 0;
}

/* The closing lines land in flat white rather than the dawn gradient — amber
   belongs to the arrival at the final CTA, and against black it read as a
   yellow cast rather than as light. Ordinary lines keep the white-to-grey
   gradient, so pure white still marks these two as the climax. */
.story-finale-line.is-climax {
  background: none;
  -webkit-text-fill-color: #ffffff;
  color: #ffffff;
}

/* The title card. Not a subtitle: it leaves the lower third, drops the
   gradient for flat white, and takes the centre of an empty black frame —
   the treatment the reference ending uses for its own title. */
.story-finale-line.is-titlecard {
  top: 50%;
  bottom: auto;
  transform: translate(-50%, -50%);
  max-width: 90%;
  font-size: clamp(0.95rem, 2.1vw, 1.5rem);
  font-weight: 300;
  line-height: 1.4;
  text-transform: uppercase;
  letter-spacing: 0.46em;
  /* Letter-spacing also trails the final glyph, which drags the whole line
     off-centre; re-indenting by the same amount puts it back. */
  text-indent: 0.46em;
  background: none;
  -webkit-text-fill-color: #ffffff;
  color: #ffffff;
}

/* JS adds #story.finale-active once the pinned moment engages and the
   playback sequence begins (see initStoryScroll): the letterbox bars and
   the single finale line appear together. */
#story.finale-active .story-finale-line {
  display: block;
}

@media (max-width: 1024px) {
  .story-scroll-track {
    height: 130vh;
  }
}

.no-pin .story-scroll-track {
  height: auto;
}

.no-pin .story-stage {
  position: static;
  display: block;
  padding: 0;
}

.no-pin .story-stage-backdrop {
  display: none;
}

.no-pin .story-letterbox {
  display: none;
}

/* Stacked fallback: the full narration, read in order, whenever the
   animated single-line playback can't run (no JS, no sticky support, or
   reduced motion — see the media query below). */
.no-pin .lyric-stack {
  display: flex;
  flex-direction: column;
  gap: 14px;
  max-width: 640px;
  margin: 0 auto;
  text-align: left;
}

@media (prefers-reduced-motion: reduce) {
  .story-finale-line {
    transition: none;
  }

  /* The dawn is stated, not performed: skip the timed playback and the
     forced scroll-away, and just show the whole narration as plain text. */
  .story-scroll-track {
    height: auto;
  }

  .story-pin {
    position: static;
    height: auto;
  }

  .story-stage {
    position: static;
    display: block;
    padding: 40px 24px;
  }

  .story-stage-backdrop,
  .story-letterbox,
  .story-finale-line {
    display: none;
  }

  .lyric-stack {
    display: flex;
    flex-direction: column;
    gap: 14px;
    max-width: 640px;
    margin: 0 auto;
    text-align: left;
  }
}

/* --------------------------------------------------------------------------
   Section: 360 Product Showcase (Rotating Hero Device)
   -------------------------------------------------------------------------- */
/* Two of these carried inline margin-bottom, 48px on one and 60px on the
   other, for the same "block then the next block" relationship. */
.product-showcase-grid {
  margin-bottom: var(--space-9);
}

.product-showcase-grid .headline-medium {
  margin-bottom: var(--space-4);
}

/* Same frame as .product-video-card but holding a landscape still instead of
   a portrait clip. Written as a compound selector on purpose: .product-video-card
   sets aspect-ratio 4/5 further down the file, and a bare .product-video-still
   would lose to it on source order. This used to be an inline style, which won
   by being inline — the class has to earn that specificity honestly. */
.product-video-card.product-video-still {
  margin: var(--space-8) auto;
  max-width: 640px;
  aspect-ratio: 16 / 9;
}

.product-video-still img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Same override as .product-video-still, for a video instead of an img:
   this one clip's value is entirely in its on-screen labels, and the
   default 4/5 cover-crop cuts off the left/right edges where they sit. */
.product-video-card.product-video-diagram {
  aspect-ratio: 16 / 9;
}

.product-showcase-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-10);
  align-items: center;
}

/* The glow has to live OUTSIDE the card: the card is opaque and clips its
   overflow, so a glow inside it was painted behind an opaque fill and never
   rendered at all. */
.product-video-frame {
  position: relative;
  isolation: isolate;
}

/* Every source clip is 720x1280 portrait. Without an explicit ratio the card
   inherits 9:16, which made these render up to 1700px tall. 4/5 keeps ~70% of
   the frame while matching the height of the text column beside it, and it
   stays correct if landscape masters replace the sources later. */
.product-video-card {
  position: relative;
  z-index: 1;
  aspect-ratio: 4 / 5;
  border-radius: var(--radius-xl);
  overflow: hidden;
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  box-shadow: var(--shadow-float);
}

.product-video-card video {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
  object-position: center 45%;
  filter: brightness(0.88) contrast(1.04);
}

/* Same reason as the story stage: white studio footage needs its edges eased
   into the page instead of ending on a hard bright rectangle. */
.product-video-card::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(circle at 50% 50%, transparent 48%, rgba(0, 0, 0, 0.42) 82%, rgba(0, 0, 0, 0.72) 100%);
}


/* --------------------------------------------------------------------------
   Section: taVNS Deep Tech
   -------------------------------------------------------------------------- */

/* Still used by the story stage's live badge. */
@keyframes live-blink {

  0%,
  100% {
    opacity: 1;
    transform: scale(1);
  }

  50% {
    opacity: 0.3;
    transform: scale(0.8);
  }
}


/* Shared with the Overview section's 13g / 93g / 5.3 LE row — not simulator-only. */
.intensity-stats-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-4);
}

.intensity-stats-row {
  margin-top: var(--space-7);
}

.stat-pill {
  background: var(--veil-1);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  padding: var(--space-4);
  text-align: center;
}

.stat-pill-label {
  font-size: 0.75rem;
  color: var(--text-secondary);
  margin-bottom: 4px;
}

.stat-pill-value {
  font-size: 1.125rem;
  font-weight: 700;
  color: var(--text-highlight);
}


/* --------------------------------------------------------------------------
   Section: Dual Architecture (Left Ear vs Right Ear)
   -------------------------------------------------------------------------- */
.dual-ear-container {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-7);
  margin-top: var(--space-9);
}

.dual-ear-card {
  background: linear-gradient(180deg, var(--bg-surface-elevated) 0%, var(--bg-surface) 100%);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-xl);
  padding: var(--space-8);
  position: relative;
  overflow: hidden;
  transition: var(--transition-default);
}

.dual-ear-card .headline-medium {
  margin-bottom: var(--space-3);
}

.dual-ear-card:hover {
  border-color: var(--border-active);
  transform: translateY(-4px);
}

.ear-side-tag {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.8125rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-pill);
  margin-bottom: 20px;
}

.ear-side-left {
  background: rgba(0, 210, 255, 0.15);
  color: var(--accent-cyan);
  border: 1px solid var(--border-active);
}

/* Cyan acts, blue watches. This tag was on Tailwind's default blue, a colour
   from a system this page doesn't use; --accent-blue says the same thing in
   our own palette and makes "One acts. One keeps watch." legible as colour. */
.ear-side-right {
  background: var(--accent-blue-soft);
  color: var(--accent-blue);
  border: 1px solid rgba(41, 151, 255, 0.4);
}

/* --------------------------------------------------------------------------
   Section: Interactive App Showcase & Bio-Feedback Tabs
   -------------------------------------------------------------------------- */
.app-showcase-wrap {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-10);
  align-items: center;
  margin-top: var(--space-9);
}

.app-tab-nav {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.app-tab-btn {
  text-align: left;
  padding: var(--space-7);
  border-radius: var(--radius-lg);
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  transition: var(--transition-default);
  position: relative;
  overflow: hidden;
}

.app-tab-btn .headline-small {
  color: var(--text-highlight);
  margin-bottom: var(--space-2);
}

.app-tab-btn::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 4px;
  background: var(--accent-cyan);
  opacity: 0;
  transition: opacity 0.3s ease;
}

.app-tab-btn.active {
  background: var(--bg-surface-elevated);
  border-color: var(--border-active);
  box-shadow: var(--shadow-lift);
}

.app-tab-btn.active::before {
  opacity: 1;
}

.app-mockup-frame {
  position: relative;
  width: 100%;
  max-width: 360px;
  margin: 0 auto;
  aspect-ratio: 9 / 19.5;
  background: var(--bg-primary);
  border-radius: 44px;
  border: 8px solid var(--bg-surface-elevated);
  box-shadow: var(--shadow-cinema), 0 0 0 1px var(--veil-3);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.mockup-screen {
  flex: 1;
  padding: 0;
  position: relative;
  width: 100%;
  height: 100%;
  background: var(--bg-primary);
  overflow: hidden;
}

.mockup-panel {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  visibility: hidden;
  transform: scale(0.98);
  transition: opacity 0.4s var(--ease-apple), transform 0.4s var(--ease-apple), visibility 0.4s;
}

.mockup-panel.active {
  opacity: 1;
  visibility: visible;
  transform: scale(1);
}

.mockup-screen-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* --------------------------------------------------------------------------
   Section: Apple-grade Bento Grid
   -------------------------------------------------------------------------- */
.bento-grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: var(--space-6);
  margin-top: var(--space-9);
}

.bento-card {
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-xl);
  padding: var(--space-8);
  position: relative;
  overflow: hidden;
  transition: var(--transition-default);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}

.bento-card:hover {
  border-color: var(--border-glass);
  transform: translateY(-4px);
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.7);
}

.bento-col-4 {
  grid-column: span 4;
}

.bento-col-6 {
  grid-column: span 6;
}

.bento-col-6 .body-medium {
  margin-top: var(--space-3);
}

.bento-icon-circle {
  width: 56px;
  height: 56px;
  border-radius: var(--radius-lg);
  background: var(--veil-1);
  border: 1px solid var(--border-subtle);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--accent-cyan);
  margin-bottom: 24px;
}

.bento-card p {
  word-break: keep-all;
  overflow-wrap: break-word;
  text-wrap: balance;
  line-height: 1.6;
}

.bento-media-img {
  width: 100%;
  height: 170px;
  object-fit: cover;
  border-radius: var(--radius-md);
  margin: 14px 0 16px 0;
  display: block;
  border: 1px solid var(--border-subtle);
  transition: transform 0.4s ease, border-color 0.4s ease;
}

.bento-card:hover .bento-media-img {
  transform: scale(1.02);
  border-color: var(--border-glass);
}


/* --------------------------------------------------------------------------
   Section 10: Final Cinematic Closing CTA
   Deep pure darkness with focused, ultra-smooth 10-second dawn sunrise awakening
   -------------------------------------------------------------------------- */
.final-cta-section {
  position: relative;
  padding: 200px 0 220px 0;
  text-align: center;
  overflow: hidden;
  background: var(--bg-primary);
}

/* Subtle, concentrated horizon dawn — NOT washing out the whole screen */
.cta-dawn-sky {
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse at 50% 100%, rgba(255, 120, 30, 0.08) 0%, transparent 60%);
  opacity: 0;
  pointer-events: none;
  z-index: 0;
  transition: none;
}

.final-cta-section.dawn-active .cta-dawn-sky {
  opacity: 1;
  transition: opacity 10s cubic-bezier(0.22, 1, 0.36, 1);
}

.cta-sunrise {
  position: absolute;
  left: 50%;
  bottom: -180px;
  width: min(640px, 90vw);
  height: 400px;
  transform: translateX(-50%) translateY(80px) scale(0.7);
  border-radius: 50%;
  background: radial-gradient(circle at 50% 50%, rgba(255, 190, 110, 0.35) 0%, rgba(255, 120, 35, 0.16) 35%, rgba(180, 50, 10, 0.04) 58%, transparent 75%);
  filter: blur(48px);
  pointer-events: none;
  z-index: 0;
  opacity: 0;
  transition: none;
}

.final-cta-section.dawn-active .cta-sunrise {
  opacity: 0.85;
  transform: translateX(-50%) translateY(0) scale(1);
  transition: transform 10s cubic-bezier(0.22, 1, 0.36, 1), opacity 9.8s cubic-bezier(0.22, 1, 0.36, 1);
  animation: sunrise-breathe 16s ease-in-out infinite alternate 10s;
}

@keyframes sunrise-breathe {
  0% {
    transform: translateX(-50%) translateY(0) scale(1);
    opacity: 0.8;
    filter: blur(48px);
  }

  50% {
    transform: translateX(-50%) translateY(-10px) scale(1.03);
    opacity: 0.92;
    filter: blur(44px) drop-shadow(0 0 24px rgba(255, 140, 50, 0.2));
  }

  100% {
    transform: translateX(-50%) translateY(-4px) scale(1.01);
    opacity: 0.82;
    filter: blur(46px);
  }
}

.final-cta-section>* {
  position: relative;
  z-index: 1;
}

/* "Step into the dark." stays in deep grey. "Wake up to the light." starts in complete
   darkness and slowly awakens to glowing golden dawn over 10 full seconds. */
.cta-line-dark {
  background: var(--text-gradient);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  display: inline-block;
  padding-bottom: 0.12em;
}

/* .headline-huge paints itself with a gradient clipped to the text. This
   headline can't use it — its two lines carry two different colours, so the
   gradient is switched off and each line is coloured directly. */
.final-cta-section .headline-huge {
  margin-bottom: var(--space-6);
  background: none;
  -webkit-text-fill-color: currentColor;
}

.cta-lead {
  margin: 0 auto var(--space-8) auto;
  max-width: 600px;
}

.cta-actions {
  display: flex;
  justify-content: center;
  gap: var(--space-4);
  flex-wrap: wrap;
}

.cta-line-light {
  background: var(--dawn-text-gradient);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  display: inline-block;
  padding-bottom: 0.12em;
  filter: brightness(0.18) grayscale(1) drop-shadow(0 0 0 rgba(255, 178, 107, 0));
  opacity: 0.2;
  transition: none;
}

.final-cta-section.dawn-active .cta-line-light {
  filter: brightness(1.08) grayscale(0) drop-shadow(0 0 26px rgba(255, 178, 107, 0.45)) drop-shadow(0 0 45px rgba(255, 120, 40, 0.2));
  opacity: 1;
  transition: filter 10s cubic-bezier(0.22, 1, 0.36, 1) 0.2s, opacity 9.5s cubic-bezier(0.22, 1, 0.36, 1) 0.2s;
}

/* The closing CTA's arrival choreography for .btn-dawn (base look lives in
   core.css, next to the other .btn-* rules, since app/'s store-download
   button uses .btn-dawn without this section). .final-cta-section .btn-dawn
   matches core's .btn-dawn:hover at (0,2,0) specificity, and this file loads
   after core.css, so the hover below is re-stated at (0,3,0) on purpose:
   without it, source order alone would hand the tie to the entrance rule and
   hovering the amber button mid-sunrise would silently stop lifting it. */
.final-cta-section .btn-dawn {
  transform: translateY(10px);
  opacity: 0.85;
  transition: transform 3.5s cubic-bezier(0.2, 0.8, 0.2, 1) 1.2s, opacity 3.5s ease 1.2s, box-shadow 0.3s ease;
}

.final-cta-section.dawn-active .btn-dawn {
  transform: translateY(0);
  opacity: 1;
}

.final-cta-section .btn-dawn:hover {
  transform: translateY(-2px) scale(1.02);
  box-shadow: var(--glow-dawn);
}

/* Settle back into the dark, so the dawn reads as the climax rather than
   the new baseline. */

@media (max-width: 1024px) {
  .product-showcase-grid,
  .dual-ear-container,
  .app-showcase-wrap {
    grid-template-columns: 1fr;
    gap: 40px;
  }

  .bento-col-4,
  .bento-col-6,
  .bento-col-8 {
    grid-column: span 12;
  }

}

@media (max-width: 768px) {
  .intensity-stats-row {
    grid-template-columns: 1fr;
  }

  .final-cta-section {
    padding: 120px 0 140px 0;
  }

  .cta-sunrise {
    height: 420px;
    bottom: -160px;
  }
}

/* --------------------------------------------------------------------------
   Reduced Motion (root-page-specific)
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .sky-horizon {
    opacity: 0.9;
  }

  .cta-sunrise {
    animation: none;
  }

  .story-light-burst {
    display: none;
  }
}

/* setChapter() normally supplies these. Without it the stage would sit at
   its chapter-01 exposure (30% brightness) forever. */
:where(html:not(.has-js)) .story-scroll-track {
  --chapter-light: 1;
}
