/* Gainmo website — Task 1: pure-white page + centered 9:16 scroll-scrubbed video */

/* Length of the scroll section that maps to the full video timeline.
   Larger = more scrolling per frame (slower/finer scrub). Tune to taste. */
:root {
  --scroll-length: 500vh;

  /* Century Gothic across the board. It's installed locally (and ships with
     MS Office), so most desktops render it directly; the fallbacks are
     geometric sans-serifs (Futura ships on macOS) so visitors without it stay
     close to the intended look. See note about self-hosting a web clone. */
  --font-sans: "Century Gothic", "CenturyGothic", "ITC Avant Garde Gothic",
    "Avant Garde", "Futura", "Trebuchet MS", "Segoe UI", system-ui, sans-serif;

  --ink: #18181b; /* primary text/logo — matches the app's Ink */
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
  background: #ffffff; /* pure white — the only surface color for this task */
}

body {
  /* The 9:16 box never exceeds the viewport width, so nothing should push a
     horizontal scrollbar; this is a belt-and-suspenders guard. */
  overflow-x: hidden;
  font-family: var(--font-sans);
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* ---------------------------------------------------------------------------
   Navbar — fixed, transparent (no bar/blur/divider) so it floats on the white
   hero. Logo + links grouped left; App Store badge pushed to the far right.
--------------------------------------------------------------------------- */
.navbar {
  position: fixed;
  inset: 0 0 auto 0; /* top: 0; left/right: 0 */
  z-index: 100;
  background: transparent;
}

.nav-inner {
  display: flex;
  align-items: center;
  gap: clamp(24px, 3.5vw, 48px); /* space between logo and the links */
  height: clamp(76px, 9vw, 96px);
  padding: 0 clamp(18px, 4vw, 44px);
  max-width: 1440px;
  margin: 0 auto;
}

.brand {
  display: inline-flex;
  align-items: center;
  transition: opacity 0.2s ease;
}
.brand:hover {
  opacity: 0.7;
}
.brand-logo {
  display: block;
  height: clamp(46px, 5.5vw, 62px); /* wordmark ~3.37:1 */
  width: auto;
  /* The kettlebell "g" makes the artwork's box symmetric, but its long
     descender sits below the baseline while the visible word rides ~4.7% high.
     Nudge the logo down by that offset so the word optically centers with the
     links and the App Store badge (which sit at the bar's true center). */
  transform: translateY(4.7%);
}

.nav-links {
  display: flex;
  align-items: center;
  gap: clamp(20px, 2.6vw, 38px);
}
.nav-links a {
  font-family: var(--font-sans);
  font-size: 17px;
  letter-spacing: 0.02em;
  color: var(--ink);
  text-decoration: none;
  opacity: 0.85;
  transition: opacity 0.2s ease;
}
.nav-links a:hover {
  opacity: 1;
}

.app-store {
  margin-left: auto; /* push to the far right */
  display: inline-flex;
  align-items: center;
  transition: opacity 0.2s ease;
}
.app-store:hover {
  opacity: 0.85;
}
.app-store img {
  display: block;
  height: clamp(48px, 5.5vw, 58px);
  width: auto;
}

/* ---------------------------------------------------------------------------
   Mobile menu — hamburger button + dropdown. Hidden on desktop; the media
   query below reveals them and collapses the inline nav links into the menu
   (the App Store badge stays in the bar, to the left of the hamburger).
--------------------------------------------------------------------------- */
.nav-toggle {
  display: none; /* desktop: hidden (shown in the mobile media query) */
  margin-left: auto; /* push to the far right of the bar */
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

/* Three ink bars (center bar is the element; ::before/::after are the outer two)
   that morph into an X when the menu is open. */
.nav-toggle-bars,
.nav-toggle-bars::before,
.nav-toggle-bars::after {
  display: block;
  width: 26px;
  height: 2px;
  background: var(--ink);
  border-radius: 2px;
  transition: transform 0.3s ease, opacity 0.2s ease, background 0.2s ease;
}
.nav-toggle-bars {
  position: relative;
}
.nav-toggle-bars::before,
.nav-toggle-bars::after {
  content: "";
  position: absolute;
  left: 0;
}
.nav-toggle-bars::before { top: -8px; }
.nav-toggle-bars::after { top: 8px; }

.nav-toggle[aria-expanded="true"] .nav-toggle-bars {
  background: transparent; /* hide the middle bar */
}
.nav-toggle[aria-expanded="true"] .nav-toggle-bars::before {
  transform: translateY(8px) rotate(45deg);
}
.nav-toggle[aria-expanded="true"] .nav-toggle-bars::after {
  transform: translateY(-8px) rotate(-45deg);
}

/* Frosted dropdown anchored under the bar, top-right. Kept in flow (display is
   flipped to flex on mobile) but visually gated by opacity/pointer-events so it
   can animate; `.is-open` reveals it. */
.mobile-menu {
  display: none; /* desktop: not rendered at all */
  position: fixed;
  top: 64px;
  right: 12px;
  left: auto;
  z-index: 90;
  flex-direction: column;
  align-items: stretch;
  min-width: 210px;
  padding: 10px;
  background: rgba(255, 255, 255, 0.82);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  backdrop-filter: blur(18px) saturate(140%);
  border: 1px solid rgba(24, 24, 27, 0.08);
  border-radius: 16px;
  box-shadow: 0 12px 40px rgba(24, 24, 27, 0.16);
  opacity: 0;
  transform: translateY(-8px) scale(0.98);
  transform-origin: top right;
  pointer-events: none;
  transition: opacity 0.2s ease, transform 0.2s ease;
}
.mobile-menu.is-open {
  opacity: 1;
  transform: translateY(0) scale(1);
  pointer-events: auto;
}
.mobile-menu a {
  font-family: var(--font-sans);
  font-size: 18px;
  letter-spacing: 0.02em;
  color: var(--ink);
  text-decoration: none;
  padding: 12px 14px;
  border-radius: 10px;
  transition: background 0.15s ease;
}
.mobile-menu a:active {
  background: rgba(24, 24, 27, 0.06);
}

@media (prefers-reduced-motion: reduce) {
  .mobile-menu {
    transition: opacity 0.2s ease;
    transform: none;
  }
  .mobile-menu.is-open {
    transform: none;
  }
}

/* Compact the bar on small screens: logo left; the App Store badge + hamburger
   group on the right (only the nav links collapse into the menu). */
@media (max-width: 640px) {
  .nav-inner {
    height: 72px;
    gap: 12px;
  }
  .nav-links {
    display: none;
  }
  /* Badge keeps its margin-left:auto (base rule) so it + the hamburger are
     pushed to the right; the hamburger then sits just to the badge's right. */
  .app-store img {
    height: 34px;
  }
  .nav-toggle {
    display: inline-flex;
    margin-left: 0;
  }
  .mobile-menu {
    display: flex; /* now in flow; opacity/pointer-events gate visibility */
  }
  .brand-logo {
    height: 44px;
  }
}

/* The tall scroll track. ScrollyVideo computes progress from this element's
   position, so it must be the direct parent of the sticky mount. */
.scroll-track {
  position: relative;
  width: 100%;
  height: var(--scroll-length);
  background: #ffffff;
}

/*
  The ScrollyVideo mount. Sized to the largest 9:16 box that fits the viewport
  (contain), so the vertical video is never stretched or cropped:
    • Wide desktop  -> height = 100vh, width = 100vh * 9/16  (white to left/right)
    • Tall phone    -> width  = 100vw, height = 100vw * 16/9 (near-full canvas)

  ScrollyVideo sets `position: sticky` and `top: 0` inline (sticky:true). We
  override `top` with !important to keep the box vertically centered when it is
  width-constrained; on desktop the calc is <= 0 so it clamps to a flush top.

  Because this box is exactly 9:16 and the video is 9:16, ScrollyVideo's
  cover-fit resolves to a perfect fit either way (canvas path fits exactly; the
  video-element path adds a ~1% overscan, clipped by overflow:hidden).
*/
#scrolly {
  position: sticky; /* ScrollyVideo also sets this; declaring it here lets the
                       poster overlay position to this box from the first paint */
  width: min(100vw, calc(100vh * 9 / 16));
  height: min(100vh, calc(100vw * 16 / 9));
  margin: 0 auto; /* horizontal centering */
  top: max(0px, calc((100vh - 100vw * 16 / 9) / 2)) !important; /* vertical centering */
  overflow: hidden;
  background: #ffffff;

  /* On load the hero slides up from below the viewport into place over 1.5s.
     The poster (frame 0) is showing the whole time, so the rise masks the video
     download/decode. fill:backwards reverts to base after, so the JS exit
     transform can take over at the end. */
  animation: heroRise 1.5s cubic-bezier(0.16, 1, 0.3, 1) backwards;
  /* Promote to its own compositor layer up front so heroRise runs on the
     compositor thread. Without this the transform can be driven on the main
     thread, which — at load — is busy downloading/decoding the clip, so the
     rise drops frames and stutters on slower/cold loads. This also smooths the
     JS-driven exit transform, which reuses this same layer. */
  will-change: transform;
}

@keyframes heroRise {
  from {
    transform: translateY(100vh); /* completely below the viewport */
  }
  to {
    transform: translateY(0);
  }
}

@media (prefers-reduced-motion: reduce) {
  #scrolly {
    animation: none;
  }
}

/* Phones are taller than 9:16, so a contained 9:16 box leaves white bands above
   and below. On mobile, fill the whole viewport instead and let ScrollyVideo's
   cover-fit crop the sides slightly. The video fills the box's height 1:1, so
   the vertical plate-wipe math in main.js stays correct. */
@media (max-width: 640px) {
  #scrolly {
    width: 100vw;
    height: 100vh; /* fallback for browsers without dvh */
    height: 100dvh; /* true visible viewport, accounting for mobile chrome */
    top: 0 !important;
  }
}

/* ScrollyVideo's inner element should own the whole box. */
#scrolly > video,
#scrolly > canvas {
  display: block;
}

/* First-frame poster: a 21KB image that paints instantly while the ~19MB video
   downloads and WebCodecs decodes (~1s). It sits ABOVE the still-empty
   video/canvas; main.js fades it out on ready, revealing the identical frame 0
   the canvas has by then painted — so the hero is visible immediately, no flash. */
.hero-poster {
  position: absolute;
  inset: 0;
  z-index: 2;
  background: #ffffff url("assets/hero-poster.png") center / cover no-repeat;
  transition: opacity 0.3s ease;
  /* ScrollyVideo's cover-fit gives the canvas a 1% center overscan (min-*: 101%
     in setCoverStyle). Match it here so the barbell doesn't shift/grow when the
     poster fades out to reveal frame 0 — the load-in stays seamless. */
  transform: scale(1.01);
}
.hero-poster.is-hidden {
  opacity: 0;
}

/* ---------------------------------------------------------------------------
   Story panels — text shown during each hold. Fixed overlay above the video,
   below the navbar. Positioned in the white space above the barbell. main.js
   drives opacity + a small rise per panel.
--------------------------------------------------------------------------- */
.story {
  position: fixed;
  inset: 0;
  z-index: 50;
  pointer-events: none;
}

.story-panel {
  position: absolute;
  top: 19%;
  left: 0;
  right: 0;
  margin-inline: auto;
  width: min(680px, 86vw);
  text-align: center;
  opacity: 0;
  will-change: opacity, transform, clip-path;
}

/* The first headline animates in on page load (not scroll), then main.js
   erases it with a top-down clip as the first plate descends through it. */
.story-panel--first {
  animation: firstHeadlineIn 0.85s 0.2s cubic-bezier(0.22, 1, 0.36, 1) both;
}

@keyframes firstHeadlineIn {
  from {
    opacity: 0;
    transform: translateY(18px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@media (prefers-reduced-motion: reduce) {
  .story-panel--first {
    animation-duration: 0.01ms;
    animation-delay: 0ms;
  }
}

.story-panel h2 {
  margin: 0 0 12px;
  font-family: var(--font-sans);
  font-weight: 700;
  font-size: clamp(30px, 4.4vw, 52px);
  line-height: 1.05;
  letter-spacing: -0.035em; /* Century Gothic runs wide — tighten the tracking */
  color: var(--ink);
}

/* When a panel stacks two <h2> lines, tighten the gap so they read as one
   two-line headline (the second h2 keeps its normal space before the <p>). */
.story-panel h2:has(+ h2) {
  margin-bottom: -6px;
}

/* Mobile: at small sizes the two headline lines read a touch cramped, so give
   them a smidge more room between them. */
@media (max-width: 640px) {
  .story-panel h2:has(+ h2) {
    margin-bottom: -2px;
  }
}

.story-panel p {
  margin: 0;
  font-family: var(--font-sans);
  font-size: clamp(15px, 1.5vw, 18px);
  line-height: 1.5;
  color: #8e9399; /* app's TextSecondary */
}

/* First headline: single, predictable knob for the gap between the headline
   and its subtext. We zero the last headline line's bottom margin so this
   margin-top fully controls the space (no margin-collapse surprises). */
.story-panel--first h2:last-of-type {
  margin-bottom: 0;
}
.story-panel--first p {
  margin-top: 0px;
}
