/* ==========================================================================
   FLAGSHIP — styles for the converged single-scroll experience: header act
   nav + progress bar, act-transition interludes, and the embedded-act
   frames (shared .act-embed rules for every act). Everything else (hero,
   how, pricing, footer) reuses style.css/base.css untouched.
   ========================================================================== */

/* ---------------------------------------------------------------------- */
/* Header: act navigation + scroll progress                              */
/* ---------------------------------------------------------------------- */
.flagship-header .wrap { flex-wrap: nowrap; }

/* Unlike overflow:hidden, clip does not create a non-scrolling ancestor
   that prevents the sticky header from following the document viewport. */
body { overflow-x: clip; }

.act-nav {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  flex-wrap: nowrap;
}

.act-dot {
  display: flex;
  align-items: center;
  gap: 0.45em;
  font-family: var(--font-body);
  font-size: var(--text-xs);
  /* Was --color-text-muted (a muted gray-green) -- read as too low-contrast
     against the header's near-black background to comfortably scan six
     labels at a glance. --color-warning (#ffb020) is the same warm orange
     already used for the whale-sized-payment glow in Whale Reef/Coin Flow
     and the live-badge alert state, so this reuses an established accent
     rather than introducing a new color, and clears well over 7:1 contrast
     here for easy reading. */
  color: var(--color-warning);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-full);
  white-space: nowrap;
  transition: color 180ms ease, background 180ms ease;
}
.act-dot:hover { color: var(--color-warning-hover); }
.act-dot .act-num {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--color-warning);
  border: 1px solid color-mix(in oklab, var(--color-warning) 45%, transparent);
  border-radius: var(--radius-full);
  width: 1.5em;
  height: 1.5em;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: color 180ms ease, border-color 180ms ease;
}
.act-dot.is-active {
  /* Was --color-text (near-white): correct before the nav labels were
     switched to the warm orange accent, but now it made the current act
     (e.g. Aurora, active by default at the top of the page) look like it
     had been missed by that change while every other label read orange.
     Keep the same orange as the resting state -- the tinted pill
     background plus the teal-highlighted numeral badge below already
     carry the "this one is active" signal without needing a color break. */
  color: var(--color-warning);
  background: color-mix(in oklab, var(--color-primary) 12%, transparent);
}
.act-dot.is-active .act-num {
  color: var(--color-primary);
  border-color: color-mix(in oklab, var(--color-primary) 55%, transparent);
}

.scroll-progress {
  height: 2px;
  background: var(--color-divider);
  overflow: hidden;
}
.scroll-progress span {
  display: block;
  height: 100%;
  width: 0%;
  background: var(--color-primary);
  transition: width 120ms linear;
}

/* Measured: brand + full-label act-nav + header-actions genuinely don't
   fit in the 901-980px band (confirmed via direct element measurement --
   they overflow the header's flex row by up to ~40px there even though
   neither adjacent breakpoint's condition is true), and Safari's font
   metrics for this typeface can plausibly push that a bit wider still.
   That overflow silently widens the whole document (nowrap flex children
   don't shrink below content width by default), turning the entire
   single-scroll page horizontally scrollable -- which is what let the
   embedded acts' right-anchored stat panels end up scrolled mostly out
   of view. Raised from 900 to 1080 with real margin on both sides of the
   old danger band so no viewport width between the two breakpoints can
   ever force that overflow again. */
@media (max-width: 1080px) {
  .act-dot span:not(.act-num) { display: none; }
  .act-dot { padding: var(--space-2); }
}
@media (max-width: 720px) {
  /* Full pill labels don't fit next to the logo and header actions on a
     phone, but dropping act navigation entirely would leave mobile
     visitors with no way to see which act they're in or jump to another
     one — only a generic scroll-position bar. Move the same jump buttons
     to their own compact row, centered below the main header row; at this
     width all five labels still fit on one line. */
  .flagship-header .wrap { flex-wrap: wrap; row-gap: var(--space-2); }
  .act-nav {
    display: flex;
    order: 10;
    flex-basis: 100%;
    justify-content: center;
    gap: var(--space-1);
    padding-top: var(--space-1);
    border-top: 1px solid var(--color-divider);
  }
  .act-nav .act-dot {
    padding: var(--space-1) 0.4em;
    min-height: 44px;
    justify-content: center;
    font-size: 11px;
    gap: 0.3em;
  }
  /* The 900px rule above hides the text label, leaving only the roman
     numeral — right when the nav still shared a row with the logo and
     header actions. Down here it has its own dedicated centered row with
     room to spare, so bring the label back per this block's own comment. */
  .act-nav .act-dot span:not(.act-num) { display: inline; }
}
@media (max-width: 400px) {
  .act-nav .act-dot { min-width: 44px; }
  /* All five full labels only fit on the dedicated row down to ~385px
     (measured); narrower phones (375, 360, 320) overflow the viewport by
     a few px once every pill carries its full word. Fall back to
     numeral-only pills again below this width — same look as the
     721-900px range, just for a different reason (nav width, not shared
     row space). */
  .act-nav .act-dot span:not(.act-num) { display: none; }
}

/* ---------------------------------------------------------------------- */
/* Header brand lockup -- same teal-to-purple gradient text used for the
   hero's "breathe" emphasis and its "...portrayed as art." tagline below,
   applied here to "Ledger Vitals" and "portrayed as art" in the header so
   the two touches of color in the page read as one deliberate treatment
   rather than two different accent colors. Scoped to .flagship-header so
   the standalone concept pages keep their plain muted wordmark. */
.flagship-header .brand-sub,
.flagship-header .brand-tagline {
  background: linear-gradient(100deg, var(--color-primary), var(--color-blue) 65%, var(--color-purple));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
/* The middot separator is generated content, not part of the gradient
   text node above -- give it back an explicit solid color rather than
   letting it inherit "transparent" from its parent and vanish. */
.flagship-header .brand-tagline::before {
  color: var(--color-text-faint);
}

/* ---------------------------------------------------------------------- */
/* Hero scroll cue                                                        */
/* ---------------------------------------------------------------------- */
.scroll-cue {
  margin-top: var(--space-8);
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  color: var(--color-text-faint);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.scroll-cue svg { width: 18px; height: 18px; animation: scroll-cue-bob 1.8s ease-in-out infinite; }
@keyframes scroll-cue-bob {
  0%, 100% { transform: translateY(0); opacity: 0.55; }
  50% { transform: translateY(6px); opacity: 1; }
}

/* ---------------------------------------------------------------------- */
/* Act transitions — short interludes between embedded acts               */
/* ---------------------------------------------------------------------- */
.act-transition {
  background: var(--color-bg);
  border-top: 1px solid var(--color-divider);
  border-bottom: 1px solid var(--color-divider);
  padding-block: var(--space-16);
  scroll-snap-align: start;
}
.act-transition-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--space-6);
  max-width: 640px;
  margin-inline: auto;
}
.act-transition-line {
  font-family: var(--font-display);
  font-size: var(--text-lg);
  color: var(--color-text-muted);
  line-height: 1.5;
}
.act-transition-next {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  font-family: var(--font-body);
  font-weight: 600;
  font-size: var(--text-sm);
  color: var(--color-text);
  padding: var(--space-3) var(--space-5);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
  transition: border-color 180ms ease, transform 180ms ease, background 180ms ease;
}
.act-transition-next:hover {
  border-color: var(--color-primary);
  background: color-mix(in oklab, var(--color-primary) 8%, transparent);
  transform: translateY(-1px);
}
.act-transition-next .act-num {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--color-primary);
  border: 1px solid color-mix(in oklab, var(--color-primary) 45%, transparent);
  border-radius: var(--radius-full);
  width: 1.7em;
  height: 1.7em;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.act-transition-next svg { width: 16px; height: 16px; animation: scroll-cue-bob 1.8s ease-in-out infinite; }

/* Secondary cross-link, Payments -> Coin Flow. Placed in the static
   II->III transition interstitial rather than floated over the live
   Whale Reef embed — an overlay pill there ended up covering the reef's
   own "live" status line on short mobile viewports, and any absolutely-
   positioned overlay is fragile against that panel's real-time content
   changing height. A plain link in the transition flow has none of that
   risk and reads as a natural aside between acts, not a UI collision. */
.act-transition-bridge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--color-text-faint);
  border-bottom: 1px solid transparent;
  margin-top: calc(var(--space-6) * -1 + var(--space-3));
  transition: color 180ms ease, border-color 180ms ease;
}
.act-transition-bridge:hover {
  color: var(--color-primary);
  border-color: color-mix(in oklab, var(--color-primary) 50%, transparent);
}
@media (max-width: 640px) {
  .act-transition-bridge { text-align: center; max-width: 320px; line-height: 1.5; }
}

/* ---------------------------------------------------------------------- */
/* Embedded acts — Payments / Atmosphere / Topology, each a full-bleed    */
/* iframe hosting an already-real, already-tested concept page.           */
/* ---------------------------------------------------------------------- */
.act-embed {
  position: relative;
  /* Shrunk by the sticky header's real height (flagship.js measures it into
     --scroll-pad) so that, combined with base.css's matching scroll-padding-top,
     the section fits entirely below the header on scroll-snap arrival instead
     of overflowing the viewport bottom by the header's height. */
  height: calc(100vh - var(--scroll-pad, var(--space-16)));
  min-height: 560px;
  scroll-snap-align: start;
  background: #05070a;
  overflow: hidden;
}
.act-embed-frame-wrap {
  position: absolute;
  inset: 0;
}
.act-iframe {
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
}
.act-embed-caption {
  position: absolute;
  top: var(--space-5);
  left: var(--space-5);
  z-index: 5;
  /* This pill sits directly on top of the embedded act's iframe (a sibling
     in this parent document, so it always renders above the iframe's own
     internal content no matter what z-index that content uses). On mobile,
     a caption long enough to reach the right edge visually buries the
     act's own .lv-panel-toggle button, which lives at top-right inside the
     iframe -- exactly what happened on Coin Flow, whose caption is the
     longest of the four. Reserve that corner unconditionally so no caption
     can grow into it; the text wraps to a second line instead. */
  max-width: calc(100% - var(--space-5) - 64px);
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-body);
  font-size: var(--text-xs);
  color: var(--color-text-muted);
  background: color-mix(in oklab, #05070a 68%, transparent);
  backdrop-filter: blur(8px);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: var(--radius-full);
  padding: var(--space-2) var(--space-4);
  /* Tappable so a visitor can shrink this pill down to its numeral badge
     when it sits over content they want an unobstructed view of — see
     the [data-caption-toggle] handler in flagship.js. Only this small
     pill intercepts the tap; the rest of the act's video surface (and
     every one of its own internal tap handlers) is untouched. */
  pointer-events: auto;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: padding 220ms ease, gap 220ms ease, background 220ms ease;
}
.act-caption-controls {
  position: absolute;
  top: var(--space-5);
  left: var(--space-5);
  right: 108px; /* Keep the labeled Hide info control accessible. */
  z-index: 5;
  display: flex;
  align-items: flex-start;
  gap: 6px;
  pointer-events: none;
}
.act-caption-controls .act-embed-caption {
  position: static;
  min-width: 0;
  max-width: none;
  min-height: 44px;
}
.act-refresh {
  flex: 0 0 auto;
  min-height: 44px;
  padding: 8px 11px;
  border: 1px solid rgba(255, 255, 255, 0.22);
  border-radius: var(--radius-full);
  background: rgba(5, 7, 10, 0.9);
  color: #d7e5e3;
  font: 500 11px/1.2 var(--font-body);
  cursor: pointer;
  pointer-events: auto;
  touch-action: manipulation;
}
.act-refresh:hover { background: #17332f; border-color: #74c9b8; }
.act-refresh:focus-visible { outline: 2px solid #74c9b8; outline-offset: 3px; }
.act-refresh:disabled { opacity: 0.7; cursor: wait; }
#act-proof .act-refresh { margin-top: 16px; }
@media (max-width: 400px) {
  .act-caption-controls { left: 8px; right: 108px; }
  .act-caption-controls .act-embed-caption { padding: 8px; }
  .act-refresh { padding-inline: 8px; }
}
.act-embed-caption:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}
.act-embed-caption.is-collapsed {
  padding: var(--space-2);
  gap: 0;
  min-width: 44px;
  align-items: center;
  justify-content: center;
}
.act-embed-caption.is-collapsed .act-embed-caption-body {
  display: none;
}
.act-embed-caption .act-num {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--color-primary);
  border: 1px solid color-mix(in oklab, var(--color-primary) 45%, transparent);
  border-radius: var(--radius-full);
  width: 1.5em;
  height: 1.5em;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.act-embed-caption.is-collapsed .act-num {
  border-color: color-mix(in oklab, var(--color-primary) 75%, transparent);
}
/* Whale Reef's caption gets a second line inviting visitors to click an
   orb -- the reef's whale calls only ever play on click, so this act is
   the one place a silent, uninteracted visitor is missing the payoff. */
.act-embed-caption-payments {
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-1);
}
.act-embed-caption-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}
.act-embed-caption-hint {
  color: var(--color-warning);
  font-weight: 600;
  flex-shrink: 0;
}
.act-embed-caption.is-collapsed .act-embed-caption-hint {
  display: none;
}
.pulse-redesign-note {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  margin-top: var(--space-6);
  padding: var(--space-3) var(--space-5);
  border: 1px solid color-mix(in oklab, var(--color-primary) 40%, transparent);
  border-radius: var(--radius-full);
  background: color-mix(in oklab, var(--color-primary) 10%, var(--color-surface));
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  text-decoration: none;
  max-width: 640px;
  transition: border-color 180ms ease, background 180ms ease;
}
.pulse-redesign-note:hover {
  border-color: var(--color-primary);
  background: color-mix(in oklab, var(--color-primary) 16%, var(--color-surface));
}
.pulse-redesign-note strong {
  color: var(--color-primary);
  font-weight: 600;
}
.pulse-redesign-dot {
  flex-shrink: 0;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--color-primary);
  box-shadow: 0 0 0 4px color-mix(in oklab, var(--color-primary) 25%, transparent);
  animation: pulse-redesign-blink 2.2s ease-in-out infinite;
}
@keyframes pulse-redesign-blink {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.45; }
}
@media (max-width: 640px) {
  .pulse-redesign-note { font-size: var(--text-xs); padding: var(--space-2) var(--space-4); }
}

.act-embed-standalone {
  position: absolute;
  bottom: var(--space-5);
  right: var(--space-5);
  z-index: 5;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--color-text-faint);
  background: color-mix(in oklab, #05070a 68%, transparent);
  backdrop-filter: blur(8px);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: var(--radius-full);
  padding: var(--space-2) var(--space-4);
  transition: color 180ms ease, border-color 180ms ease;
}
.act-embed-standalone:hover {
  color: var(--color-text);
  border-color: color-mix(in oklab, var(--color-primary) 45%, transparent);
}
.act-mobile-next { display: none; }

@media (max-width: 760px) {
  .act-embed .act-embed-standalone { display: none; }
  .act-mobile-next {
    position: absolute;
    bottom: max(12px, env(safe-area-inset-bottom, 0px));
    width: 148px;
    min-height: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 8px;
    border-radius: var(--radius-full);
    z-index: 8;
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
  }
  .act-mobile-next {
    left: calc(50% - 74px);
    border: 1px solid #74c9b8;
    color: #dcfff5;
    background: rgba(9, 38, 35, .96);
    font: 600 14px/1.2 var(--font-body);
    cursor: pointer;
  }
  .act-mobile-next:focus-visible { outline: 2px solid #dcfff5; outline-offset: 3px; }
  .act-embed { height: calc(var(--lv-mobile-height, 100dvh) - var(--scroll-pad, var(--space-16))); min-height: 0; }
}

@media (max-width: 720px) {
  .act-embed-caption { font-size: 10px; padding: var(--space-1) var(--space-3); left: var(--space-3); top: var(--space-3); }
}

/* Gentle resting points at act boundaries; never mandatory so the two    */
/* multi-section acts (Atmosphere's hero+embed, Proof) scroll freely —    */
/* their own nested sections still snap individually via .act-embed.     */
html { scroll-snap-type: y proximity; }
@media (max-width: 760px) {
  html { scroll-snap-type: none; scroll-behavior: auto; }
  main { overflow-anchor: none; }
}
.act[id="act-atmosphere"], .act[id="act-proof"] { scroll-snap-align: none; }

/* Immersive toggle: recedes the header/nav chrome so the act currently  */
/* in view reads closer to full-bleed. See flagship.js for why this is a */
/* CSS class rather than the real Fullscreen API. Chrome dims rather     */
/* than vanishes, and stays clickable throughout (opacity only, never    */
/* pointer-events:none) — the toggle itself must always stay reachable   */
/* to turn immersive mode back off. Hovering or focusing the header      */
/* brings it back to full strength.                                     */
.flagship-header {
  transition: opacity 0.35s ease;
}
body.lv-immersive .flagship-header {
  opacity: 0.16;
}
body.lv-immersive .flagship-header:hover,
body.lv-immersive .flagship-header:focus-within {
  opacity: 1;
}
/* Forces the dim through for a beat right after toggling on, even while
   the cursor is still over the header from the click itself — see
   flagship.js setImmersive() for why the plain :hover rule above can
   otherwise make the toggle look like it did nothing. */
body.lv-immersive.lv-immersive-confirm .flagship-header,
body.lv-immersive.lv-immersive-confirm .flagship-header:hover,
body.lv-immersive.lv-immersive-confirm .flagship-header:focus-within {
  opacity: 0.16;
}
body.lv-immersive .scroll-cue { opacity: 0; pointer-events: none; }

/* Global mute — a real, working toggle. Two icons live in the DOM (a
   speaker with sound waves, a speaker with an X); only one shows at a
   time, swapped by the .is-muted class rather than by redrawing a single
   path, so the two states are unmistakably different shapes, not just a
   color change. */
[data-mute-toggle] .icon-sound-off { display: none; }
[data-mute-toggle].is-muted .icon-sound-on { display: none; }
[data-mute-toggle].is-muted .icon-sound-off { display: block; }
[data-mute-toggle].is-muted { color: var(--color-primary); }
