/* ===================================================================
   Coverd — Homepage
   Breakpoints:  Desktop (default) · Tablet (<=1024px) · Mobile (<=640px)

   Fluid scaling: the root font-size stays 16px at/below 1440px, then
   grows to 24px by 2880px. All scalable sizes use rem, so the whole
   page scales up proportionally on large screens while remaining
   identical at <=1440px.
   =================================================================== */

/* -------------------------------------------------------------------
   Cera Round — variable font (single file covers weights 100–900).
   ------------------------------------------------------------------- */
@font-face {
  font-family: "Cera Round";
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
  src: url("assets/fonts/CeraRound-Variable.woff2") format("woff2-variations"),
       url("assets/fonts/Cera-Round-Variable.ttf") format("truetype-variations");
}
@font-face {
  font-family: "Cera Round";
  font-weight: 100 900;
  font-style: italic;
  font-display: swap;
  src: url("assets/fonts/CeraRound-Variable-Italic.woff2") format("woff2-variations"),
       url("assets/fonts/Cera-Round-Variable-Italic.ttf") format("truetype-variations");
}

:root {
  --yellow: #fff401;
  --yellow-card: #fff400;
  --black: #000000;
  --white: #ffffff;

  --ink-50: rgba(0, 0, 0, 0.5);
  --ink-40: rgba(0, 0, 0, 0.4);
  --ink-20: rgba(0, 0, 0, 0.2);
  --ink-10: rgba(0, 0, 0, 0.1);
  --ink-08: rgba(0, 0, 0, 0.08);

  --font: "Cera Round", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;

  --container-max: 2880px;
  /* Fluid tokens: interpolate continuously from mobile up to 1440px, then
     the rem max keeps scaling with the root font above 1440px. This avoids
     hard snaps at the 1024/640 breakpoints when resizing. */
  --gutter: clamp(28px, 4.5vw - 0.8px, 4rem);

  --section-gap: clamp(96px, 10vw + 26px, 10.625rem);

  /* Nav height + the frame around the hero (fixed px so the margin
     stays constant while the hero itself grows/shrinks). --hero-top is
     the nav-to-hero gap; --hero-gap is the left/right/bottom frame. */
  --header-h: 6.125rem;
  --hero-top: 0px;
  --hero-gap: 64px;
}

* { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  /* Always reserve the vertical scrollbar's space so the (absolutely-centred)
     nav logo + the centred hero sit in the exact same place on every page —
     whether or not that page scrolls — instead of jumping by the scrollbar width. */
  scrollbar-gutter: stable;
  /* 16px up to a 1440px viewport, scaling to 24px at 2880px */
  font-size: clamp(16px, 0.556vw + 8px, 24px);
  /* iOS Safari tints the status bar, the bottom toolbar and the elastic
     overscroll from the root background colour. It can only be one value at a
     time, so JS swaps it by scroll position (see refreshThemeColor): yellow over
     the top + content, white once the white footer fills the lower viewport.
     The top and bottom rubber-bands happen at opposite ends of the scroll, so
     that single value lands correct at each end — the top stays yellow while the
     footer (and any pull-up past it) reads white. Body/content sit opaque on
     top, so this only shows through in the safe areas + overscroll. */
  background-color: var(--yellow);
}

body {
  margin: 0;
  font-family: var(--font);
  font-size: 1rem;
  /* Transparent so the html gradient governs the top status bar (yellow) and
     the footer/overscroll (white). A solid white body made iOS sample white
     behind the status bar at the top of the page. */
  background: transparent;
  color: var(--black);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
  /* iOS Safari ignores user-scalable=no, so kill the double-tap zoom here. */
  touch-action: manipulation;
  -webkit-text-size-adjust: 100%;
}

/* Yellow covers everything above the footer. Because the bottom toolbar
   tints to the background behind it, it reads yellow over content and
   white once you reach the white footer. */
.site-header,
main {
  background: var(--yellow);
}

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

/* Mobile-only line break inside headings (toggled on in the 640px query). */
.brk { display: none; }

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

ul { margin: 0; padding: 0; list-style: none; }

.container {
  width: 100%;
  max-width: var(--container-max);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  border-radius: 10rem;
  font-weight: 700;
  font-size: 1rem;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  border: 1px solid transparent;
  padding: 1.25rem 2rem;
  transition: opacity 0.15s ease, background 0.15s ease;
}
.btn__icon { width: 1.0625rem; height: 1.25rem; }

/* Hover: the content climbs vertically — the label (or an icon button's icon)
   rises and exits the top while an identical copy climbs in right behind it,
   landing seamlessly on the duplicate. The window hugs the line tightly so the
   two copies stay close: it reads as one continuous strip ticking upward, never
   a label that vanishes into a gap. Any leading icon stays fixed. The button
   itself never moves and casts no shadow. Markup injected by JS (buttonRoll). */
/* The label is a row of per-letter rolls; the wave staggers their delays. */
.btn__wave {
  display: inline-flex;
  align-items: stretch;
  flex: none;
}
.btn__space { display: inline-block; }
.btn__roll {
  display: inline-flex;
  overflow: hidden;
  flex: none;
}
.btn__roll-inner {
  display: flex;
  flex-direction: column;
  flex: none;
  /* Sit at the top of the (overflow-hidden) window and keep the natural
     two-line height — otherwise the parent inline-flex stretches this strip to
     a single line and translateY(-50%) only travels half a line. */
  align-self: flex-start;
  /* Single, smooth roll on hover. The per-letter --i index staggers the start
     so the glyphs fire in sequence and the word ripples as a wave. */
  transition: transform 0.42s cubic-bezier(0.34, 0.85, 0.36, 1);
  transition-delay: calc(var(--i, 0) * 32ms);
}
.btn__roll-item {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
}
/* Window hugs the line (just enough to clear descenders); the negative margins
   pull that height back so the button stays exactly the size it was. Keeping it
   tight is what makes the climb read as continuous rather than a blank flip. */
.btn .btn__roll { height: 1.22em; margin-block: -0.11em; }
.btn .btn__roll-item { height: 1.22em; line-height: 1.22; white-space: nowrap; }
.icon-btn .btn__roll,
.icon-btn .btn__roll-item { height: 1.125rem; }
/* The two stacked copies are identical, so rolling up exactly one copy
   (-50% of the inner) lands seamlessly on the duplicate. */
.btn:hover .btn__roll-inner,
.btn:focus-visible .btn__roll-inner,
.icon-btn:hover .btn__roll-inner,
.icon-btn:focus-visible .btn__roll-inner {
  transform: translateY(-50%);
}

.btn--white  { background: var(--white); color: var(--black); padding: 1.25rem 2.25rem; font-size: 1.125rem; }
.btn--black  { background: var(--black); color: var(--white); }
.btn--outline { background: var(--yellow); color: var(--black); border-color: var(--ink-10); }
.btn--black:hover { background: #1a1a1a; }

/* ---------- Icon buttons ---------- */
.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.625rem;
  height: 2.625rem;
  border-radius: 10rem;
  border: 1px solid var(--ink-10);
  background: var(--yellow);
}
.icon-btn img { width: auto; height: 1.125rem; }

/* ===================================================================
   HEADER / NAV
   =================================================================== */
.site-header { position: relative; z-index: 50; }

.nav {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: var(--header-h);
  /* Inset the nav items further than the 64px hero frame so the links and
     store buttons sit pulled-in, matching the design (reset to the plain
     gutter on tablet/mobile below). */
  padding-inline: calc(var(--gutter) + 2.5rem);
}

.nav__links {
  display: flex;
  align-items: center;
  gap: 1.5rem;
  font-size: 1rem;
}
.nav__link { font-weight: 500; opacity: 0.5; transition: opacity 0.15s ease; }
.nav__link:hover { opacity: 0.8; }
.nav__link.is-active { font-weight: 700; opacity: 1; }

.nav__logo {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}
.nav__logo img { width: 7.75rem; height: auto; }

.nav__actions { display: flex; align-items: center; gap: 0.75rem; }
/* App Store / Google Play render as pills (24px left/right padding). */
.nav__actions .icon-btn { width: auto; padding-inline: 1.5rem; }

.nav__menu-btn {
  display: none;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  padding: 0;
  background: none;
  border: none;
  cursor: pointer;
}
.nav__menu-btn img { width: 1.75rem; height: auto; }

/* ---------- Slide-down menu overlay ---------- */
.menu-overlay {
  position: fixed;
  inset: 0;
  z-index: 100;
  /* Dark scrim: instant on open, but on close it fades out (see .is-closing) in
     step with the panel sliding up. Without the fade, the panel leaving exposed
     the full scrim, which was then removed in a single frame — the close
     "flash". The fade finishes just before the panel does, so the page is
     revealed cleanly with nothing to pop. */
  background-color: rgba(0, 0, 0, 0.4);
  transition: background-color 0.38s ease;
}
.menu-overlay.is-closing { background-color: rgba(0, 0, 0, 0); }
/* White fill behind the status-bar / notch so the very top reads white
   (matching the panel) instead of the dark scrim. */
.menu-overlay::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: env(safe-area-inset-top);
  background: var(--white);
}
.menu-overlay__panel {
  background: var(--white);
  border-radius: 0 0 2rem 2rem;
  /* Fill the status-bar / notch area with the panel's white so the bar
     reads white (instead of the dark scrim over the yellow page). */
  padding-top: env(safe-area-inset-top);
  padding-bottom: 2.25rem;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15);
  will-change: transform;
  /* Slides straight down from the top and settles (decelerating ease-out).
     Pure translate — no opacity — so it never fades, only slides. */
  animation: slideDown 0.4s cubic-bezier(0.22, 1, 0.36, 1) both;
}
/* Reverse on close: glide straight back up and off the top of the screen. */
.menu-overlay.is-closing .menu-overlay__panel {
  animation: slideUp 0.42s cubic-bezier(0.4, 0, 0.6, 0.45) both;
}
@keyframes slideDown { from { transform: translateY(-100%); } to { transform: translateY(0); } }
@keyframes slideUp { from { transform: translateY(0); } to { transform: translateY(-100%); } }

.menu-overlay__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 6.125rem;
  position: relative;
}
.menu-overlay__top .nav__logo { position: absolute; }
.menu-overlay__close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem; height: 1.75rem;
  background: none; border: none; cursor: pointer; color: var(--black);
}
.menu-overlay__links {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 1.75rem;
  padding-top: 0.5rem;
  font-size: 1.5rem;
  font-weight: 700;
}
.menu-overlay__links a { color: var(--ink-40); transition: color 0.15s ease; }
.menu-overlay__links a.is-active { color: var(--black); }
.menu-overlay__divider {
  height: 1px;
  background: var(--ink-10);
  margin: 2rem var(--gutter) 0;
}
.menu-overlay__stores {
  display: flex;
  justify-content: center;
  gap: 0.75rem;
  margin-top: 2rem;
}
.menu-overlay__stores .icon-btn {
  width: auto;
  padding-inline: 1.5rem;
  background: var(--white);
}

/* ===================================================================
   HERO
   =================================================================== */
/* Uniform frame around the hero: same gap on every side, fixed in px so
   it "stays" put while the card grows/shrinks with the window. */
.hero {
  margin-top: var(--hero-top);
  padding-inline: var(--hero-gap);
}

.hero__card {
  position: relative;
  width: 100%;
  /* Fill the viewport height: full height minus the nav and the
     top + bottom gaps, so the hero always sits within the viewport. */
  aspect-ratio: auto;
  height: calc(100vh - var(--header-h) - var(--hero-top) - var(--hero-gap));
  /* dvh tracks Safari's collapsing toolbar so the image fills down to the
     visible bottom (leaving only the 8px frame), instead of svh which left
     a yellow gap when the address bar collapsed. */
  height: calc(100dvh - var(--header-h) - var(--hero-top) - var(--hero-gap));
  min-height: 360px;
  border-radius: clamp(28px, 3.8cqw, 72px);
  overflow: hidden;
  container-type: inline-size;
  /* Transparent so the page's yellow shows around the growing intro square
     (matching the splash); the image covers the card once fully grown. */
  background: transparent;
}
.hero__bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 30%;
  /* No clip-path by default: the card's own border-radius + overflow:hidden
     round the image, so the corners always match and track window resizing.
     The clip-path below is added ONLY for the intro grow, then removed. */
}
/* Intro only: clip the image so it can grow from the logo square out to a
   full-bleed cover. This is the animation's end state (radius set by JS to the
   card's live radius); JS removes the class once grown so there's no stale,
   mismatched corner left behind. */
.hero__card.is-hero-clip .hero__bg {
  clip-path: inset(0px round var(--hero-radius, 40px));
}
/* Intro start state (applied at load): a rounded square matching the intro
   logo's on-screen size + position. The four insets are set by JS. */
.hero__card.is-hero-primed .hero__bg {
  clip-path: inset(
    var(--hero-clip-top, 30%) var(--hero-clip-right, 35%)
    var(--hero-clip-bottom, 30%) var(--hero-clip-left, 35%)
    round var(--hero-clip-r, 22px)
  );
}
/* Intro motion: enabled just before the square is released, so it eases open
   from the logo square to the full cover. */
.hero__card.is-hero-animate .hero__bg {
  transition: clip-path 0.85s cubic-bezier(0.62, 0.02, 0.2, 1);
  will-change: clip-path;
}
.hero__overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(0, 0, 0, 0.25) 0%, rgba(0, 0, 0, 0.1) 35%, rgba(0, 0, 0, 0.45) 100%);
}
/* Overlay gradient + heading/CTA fade in last — only after the image has
   filled the card (the hold class is removed by JS once the grow finishes). */
.hero__overlay,
.hero__content {
  transition: opacity 0.55s ease;
}
.hero__card.is-hero-hold-content .hero__overlay,
.hero__card.is-hero-hold-content .hero__content {
  opacity: 0;
}
.hero__content {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  color: var(--white);
  padding: 1.5rem;
}
.hero__title {
  margin: 0;
  font-size: clamp(2.25rem, 4.9cqw, 7rem);
  font-weight: 900;
  letter-spacing: -0.019em;
  line-height: 1;
}
.hero__subtitle {
  margin: clamp(0.625rem, 1.4cqw, 1.75rem) 0 0;
  font-size: clamp(1.125rem, 2.13cqw, 3rem);
  font-weight: 500;
  line-height: 1.5;
}
.hero__cta {
  margin-top: clamp(1.25rem, 2.3cqw, 2.75rem);
  font-size: clamp(1rem, 1.37cqw, 1.75rem);
  padding: clamp(0.875rem, 1.5cqw, 1.75rem) clamp(1.5rem, 2.75cqw, 3.25rem);
}

/* ===================================================================
   SHARED SECTION TITLE
   =================================================================== */
.section-title {
  margin: 0;
  text-align: center;
  font-size: clamp(36px, 2.5vw + 20px, 3.5rem);
  font-weight: 700;
  letter-spacing: -0.019em;
  line-height: 1.2;
}

/* ===================================================================
   CASH BACK
   =================================================================== */
.cashback {
  margin-top: var(--section-gap);
  display: flex;
  flex-direction: column;
  align-items: center;
}
.pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 3.75rem;
  height: 2.25rem;
  padding: 0 1rem;
  border: 1px solid var(--black);
  border-radius: 6.25rem;
  font-size: 1rem;
  font-weight: 500;
}
.cashback .section-title { margin-top: 2.75rem; }
.cashback__card-img {
  width: 32.75rem;
  max-width: 100%;
  margin-top: 0.5rem;
}
.cashback__card-img img,
.cashback__card-img video { display: block; width: 100%; height: auto; }
.cashback__desc {
  max-width: 28.6875rem;
  margin: 0;
  text-align: center;
  font-size: 1.25rem;
  font-weight: 500;
  line-height: 1.4;
}
.cashback__buttons {
  display: flex;
  gap: 1.125rem;
  width: 24.25rem;
  max-width: 100%;
  margin-top: 1.5rem;
}
.cashback__buttons .btn { flex: 1; height: 4rem; }
.rating {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 1.625rem;
  color: var(--ink-40);
}
.rating__star { width: 1.125rem; height: 1.125rem; }
.rating__text { font-size: 1.125rem; letter-spacing: -0.04em; }
.rating__dot { margin: 0 0.5rem; }

/* ===================================================================
   EXPLORE CARDS
   =================================================================== */
.explore { margin-top: var(--section-gap); }
.explore .section-title { margin-bottom: 4rem; }

.explore__cards {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 2.75rem;
  max-width: 68.125rem;
  margin-inline: auto;
}
.feature-card {
  position: relative;
  aspect-ratio: 334 / 468;
  border-radius: 2.5rem;
  overflow: hidden;
  background: var(--yellow-card);
}
.feature-card__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.feature-card::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(0, 0, 0, 0) 45%, rgba(0, 0, 0, 0.55) 100%);
}
.feature-card__body {
  position: absolute;
  left: 2.375rem;
  right: 2.375rem;
  bottom: 2.5rem;
  z-index: 2;
}
.feature-card__icon { width: 1.875rem; height: auto; margin-bottom: 1.125rem; }
.feature-card__title {
  margin: 0;
  color: var(--white);
  /* Fixed 40px (not rem) so it doesn't scale up to ~44px on wide screens. */
  font-size: 40px;
  font-weight: 700;
  line-height: 1;
}

/* Mouse grab-and-pull affordance (only when the row is scrollable). */
.explore__cards.is-grabbable { cursor: grab; }
.explore__cards.is-dragging { cursor: grabbing; user-select: none; }
.explore__cards.is-dragging .feature-card { pointer-events: none; }

.explore__dots { display: none; justify-content: center; align-items: center; gap: 0.5rem; margin-top: 1.5rem; }
.explore__dots .dot {
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 0.5rem;
  background: var(--ink-20);
  border: none;
  padding: 0;
  cursor: pointer;
  transition: width 0.25s ease, background 0.25s ease;
}
.explore__dots .dot.is-active { width: 1rem; background: var(--black); }

.explore__caption {
  margin: 4rem auto 0;
  max-width: 33.25rem;
  text-align: center;
  font-size: 1.25rem;
  font-weight: 500;
}
.explore__cta { display: flex; width: 13.125rem; height: 4rem; margin: 1.5rem auto 0; }

/* ===================================================================
   INVESTORS & PRESS
   =================================================================== */
.investors { margin-top: var(--section-gap); }
.investors .section-title { margin-bottom: 6.5rem; }

.investors__list {
  max-width: 54.125rem;
  margin-inline: auto;
}
.investors__list li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1.75rem 0;
  border-bottom: 1px solid var(--ink-08);
  font-size: 1.25rem;
  font-weight: 500;
}
.investors__list li:first-child { padding-top: 0; }
/* The whole row is a link to the firm's site. */
.investors__list li a {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  color: inherit;
  text-decoration: none;
  transition: opacity 0.15s ease;
}
.investors__list li a:hover { opacity: 0.6; }
.investors__list li img { height: 1.5rem; width: auto; }

/* ---------- Press card ---------- */
.press-card {
  position: relative;
  max-width: 54.125rem;
  /* ~90px gap from the bottom of the investors list to the founders image. */
  margin: 5.625rem auto 0;
  height: 33rem;
  border-radius: 2.5rem;
  overflow: hidden;
  background: #ffffff;
}
.press-card__media {
  position: absolute;
  inset: 0;
}
.press-card__bg {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center top;
}

.press-card__footer {
  position: absolute;
  left: 2.5rem;
  right: 2.5rem;
  bottom: 2.25rem;
  z-index: 3;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1.5rem;
}
.press-card__headline {
  margin: 0;
  max-width: 27rem;
  font-size: 1.25rem;
  font-weight: 700;
  line-height: 1.3;
}
.press-card__more { height: 4rem; flex-shrink: 0; }

/* ===================================================================
   FEATURED ON
   =================================================================== */
/* ~170px of breathing room above the label (section margin) and below the
   logos (inner padding) — matches the page's section rhythm. */
.featured { margin-top: var(--section-gap); }
.featured__inner {
  max-width: 54.25rem;
  margin-inline: auto;
  padding: 0 0 var(--section-gap);
  text-align: center;
}
.featured__label {
  margin: 0 0 2.5rem;
  font-size: 0.875rem;
  font-weight: 500;
  letter-spacing: 0.07em;
}
.featured__logos {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7rem;
}
.featured__logos img { width: auto; opacity: 0.9; }
.featured__logos img:nth-child(1) { height: 1.625rem; }
.featured__logos img:nth-child(2) { height: 2.375rem; }
.featured__logos img:nth-child(3) { height: 2.75rem; }

/* ===================================================================
   FOOTER
   =================================================================== */

/* ===================================================================
   LEGAL PAGES  (Privacy, Terms, Sweepstakes, Responsible Play)
   A centered title on yellow, then a single readable text column.
   =================================================================== */
.legal-hero {
  text-align: center;
  /* Sits below the nav with the same rhythm the other heroes use. */
  padding: clamp(40px, 7vw, 84px) var(--gutter) clamp(36px, 5vw, 64px);
}
.legal-hero__title {
  margin: 0;
  font-size: clamp(36px, 4vw + 12px, 4rem);
  font-weight: 900;
  letter-spacing: -0.019em;
  line-height: 1.05;
}
.legal-body {
  width: 100%;
  /* ~1090px reading column (centered), matching the design. */
  max-width: 68.125rem;
  margin-inline: auto;
  padding: 0 var(--gutter) clamp(80px, 9vw, 140px);
}
.legal-doc {
  font-size: 1rem;
  font-weight: 500;
  line-height: 1.6;
  color: var(--black);
}
.legal-doc p { margin: 0 0 1.25rem; }
.legal-doc p:last-child { margin-bottom: 0; }
.legal-doc__meta { font-weight: 900; }
.legal-doc h2 {
  font-size: 1.375rem;
  font-weight: 900;
  letter-spacing: -0.01em;
  margin: 2.75rem 0 1rem;
  line-height: 1.2;
}
.legal-doc h2:first-child { margin-top: 0; }
.legal-doc h3 { font-size: 1.0625rem; font-weight: 900; margin: 2rem 0 0.75rem; }
.legal-doc ul { margin: 0 0 1.25rem; padding-left: 1.25rem; }
.legal-doc li { margin-bottom: 0.625rem; }
.legal-doc a { color: var(--black); text-decoration: underline; text-underline-offset: 2px; }
.legal-doc a:hover { opacity: 0.6; }
.legal-doc strong { font-weight: 900; }
/* A small lead/disclaimer block above the body copy. */
.legal-doc__note { color: var(--ink-50); }

/* Credit card account-opening disclosure box ("Schumer box"):
   a bordered two-column table with full-width section bands. */
.legal-doc .disclosure {
  width: 100%;
  border-collapse: collapse;
  margin: 0 0 1.5rem;
  border: 2px solid var(--black);
  font-size: 0.9375rem;
  line-height: 1.5;
}
.legal-doc .disclosure th,
.legal-doc .disclosure td {
  border: 1px solid var(--black);
  padding: 0.875rem 1.125rem;
  text-align: left;
  vertical-align: top;
}
.legal-doc .disclosure tbody th[scope="row"] {
  width: 42%;
  font-weight: 900;
}
.legal-doc .disclosure td { font-weight: 500; }
/* Full-width yellow section bands. */
.legal-doc .disclosure__section th {
  background: var(--yellow);
  font-size: 0.8125rem;
  font-weight: 900;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}
/* Sub-fee rows are indented and use the regular body weight. */
.legal-doc .disclosure__sub th[scope="row"] {
  font-weight: 500;
  padding-left: 2.25rem;
}
/* The oversized headline APR figure. */
.legal-doc .disclosure__apr { font-size: 1.375rem; }

@media (max-width: 640px) {
  .legal-hero { padding-top: clamp(24px, 8vw, 48px); }
  .legal-doc h2 { font-size: 1.25rem; }
  .legal-doc .disclosure { font-size: 0.875rem; }
  .legal-doc .disclosure th,
  .legal-doc .disclosure td { padding: 0.625rem 0.75rem; }
  .legal-doc .disclosure tbody th[scope="row"] { width: 45%; }
  .legal-doc .disclosure__sub th[scope="row"] { padding-left: 1.5rem; }
}

   /* =================================================================
   FOOTER
   ================================================================= */
.site-footer {
  background: var(--white);
  /* The gap above the footer is a solid yellow BORDER, not a transparent
     margin. A margin would show the root background through it, and the root
     flips yellow→white by scroll position (refreshThemeColor) to tint the
     bottom overscroll — so the gap used to flip to white as you reached the
     footer, making the footer look like it suddenly grew its top padding (the
     "jump"). A border is painted by the footer itself, so it stays yellow and
     the footer's top padding never changes. */
  border-top: 4rem solid var(--yellow);
  /* Extend the white into the home-indicator / bottom safe area. */
  padding: 7.125rem 0 calc(3.75rem + env(safe-area-inset-bottom));
}
.footer__top {
  display: flex;
  align-items: stretch;
  justify-content: space-between;
}
.footer__brand { display: flex; gap: 8.75rem; }
.footer__logo img { width: 5rem; height: 5rem; }
.footer__links { display: flex; flex-direction: column; gap: 0.875rem; font-size: 1rem; font-weight: 500; }
.footer__links a:hover { opacity: 0.6; }

/* Stores pinned to the top, legal links to the bottom (level with the last
   nav item, "Responsible Play"). */
.footer__right { display: flex; flex-direction: column; align-items: flex-end; justify-content: space-between; gap: 1.75rem; }
/* White pills (icon centred, 24px left/right padding) like the header stores. */
.footer__right .icon-btn { background: var(--white); width: auto; padding-inline: 1.5rem; }
.footer__stores { display: flex; gap: 0.75rem; }
.footer__legal { display: flex; gap: 3.125rem; font-size: 1rem; font-weight: 500; }
.footer__legal a:hover { opacity: 0.6; }

.footer__divider {
  height: 1px;
  background: var(--ink-08);
  /* ~88px of breathing room above and below the divider. */
  margin: 5.5rem 0 0;
}
.footer__wordmark { margin-top: 5.5rem; }
.footer__wordmark img { width: 100%; height: auto; }
.footer__copy {
  /* 124px gap between the wordmark and the ©2026 line. */
  margin: 7.75rem 0 0;
  text-align: center;
  font-size: 1rem;
  font-weight: 500;
  color: var(--ink-20);
}

/* ===================================================================
   SUPPORT PAGE
   Hero banner · Contact · categorized FAQ accordion. Two-column rows
   (label left / content right) collapse to a single column on mobile.
   =================================================================== */
.support-hero {
  width: 100%;
  max-width: var(--container-max);
  margin-inline: auto;
  /* Match the home page hero's frame exactly (64px desktop / 16 tablet / 8
     mobile) so both heroes have identical left/right margins. */
  padding: 0 var(--hero-gap);
}
.support-hero__card {
  position: relative;
  display: grid;
  place-items: center;
  aspect-ratio: 1312 / 396;
  /* Same rounded corners as the home page hero (the photos are opaque, so a
     CSS clip is clean). container-type lets the cqw-based radius track this
     card's width just like the home hero. */
  border-radius: clamp(28px, 3.8cqw, 72px);
  overflow: hidden;
  container-type: inline-size;
}
.support-hero__bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Top-align so the heads + draped arm/shoulders show in the banner crop. */
  object-position: center top;
}
.support-hero__title {
  /* Fill the hero and center the text with flex (NOT a translate), because the
     overscroll-inertia script drives this title's `transform`. A centering
     transform would get overwritten and yank it off-center; filling + flex
     keeps it dead-center while the inertia only nudges the whole box. */
  position: absolute;
  inset: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0;
  color: var(--white);
  font-size: 4rem;
  font-weight: 900;
  letter-spacing: -0.019em;
  line-height: 1;
  text-align: center;
}

.support-section { margin-top: clamp(64px, 8vw, 116px); }
.support-faq { margin-top: clamp(80px, 10vw, 140px); }
.support-inner { max-width: 68.125rem; margin-inline: auto; }
/* Gap from the full-width "FAQ’s" divider down to the first category. */
.support-faq .support-inner { margin-top: clamp(80px, 10vw, 144px); }

/* Label (left) / content (right) two-column row. */
.support-row {
  display: grid;
  /* fr (not %) so the 32px column gutter is subtracted from the row instead of
     overflowing it; the narrower label column also lets long titles wrap. */
  grid-template-columns: 39fr 61fr;
  column-gap: 2rem;
  align-items: start;
  row-gap: 1.5rem;
}
.support-faq .support-row + .support-row { margin-top: clamp(72px, 9vw, 120px); }

.support-row__label {
  margin: 0;
  font-size: 2.5rem;
  font-weight: 700;
  letter-spacing: -0.019em;
  line-height: 1.2;
}
.support-row__label--lg { font-size: 2.875rem; }

.support-list { min-width: 0; }

/* ---- Contact items ---- */
.support-item { padding-bottom: 2.375rem; }
.support-item + .support-item {
  border-top: 1px solid var(--ink-08);
  padding-top: 2.375rem;
}
.support-item__q {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 0;
  font-size: 1.25rem;
  font-weight: 700;
  line-height: 1.3;
}
.support-item__icon { width: 1.5rem; height: 1.5rem; flex-shrink: 0; }
.support-item__a {
  /* Indent to line up under the title text, past the icon (1.5rem) + gap. */
  margin: 1.125rem 0 0 2.25rem;
  font-size: 1.25rem;
  font-weight: 500;
  line-height: 1.4;
}
.support-item__a a { text-decoration: underline; }

/* ---- FAQ pill divider ---- */
.support-faq__head {
  display: flex;
  align-items: center;
  gap: 1.5rem;
}
.support-faq__head::before,
.support-faq__head::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--ink-08);
}
.support-faq__pill {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 2.25rem;
  padding: 0 1.25rem;
  border: 1px solid var(--black);
  border-radius: 6.25rem;
  font-size: 1rem;
  font-weight: 500;
}

/* ---- FAQ accordion ---- */
.faq { border-bottom: 1px solid var(--ink-08); }
/* Drop the trailing rule under the bottom item of each category — a divider
   hanging before the gap to the next group reads clunky. */
.support-list .faq:last-child { border-bottom: 0; }
.faq__q {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin: 0;
  padding: 1.5rem 0;
  list-style: none;
  cursor: pointer;
  font-size: 1.25rem;
  font-weight: 700;
  line-height: 1.3;
}
.faq__q::-webkit-details-marker { display: none; }
.faq__q::marker { content: ""; }
.faq__chevron {
  flex-shrink: 0;
  width: 1.5rem;
  height: 1.5rem;
  color: var(--black);
  transition: transform 0.36s cubic-bezier(0.4, 0, 0.2, 1);
}
.faq.is-open .faq__chevron { transform: rotate(180deg); }
.faq__a {
  max-width: 38.5rem;
  /* Slide open/closed by transitioning the grid row between 0fr and 1fr — the
     smoothest, glitch-free collapse: it interpolates the content's own height
     and reverses cleanly mid-flight. The inner child clips the copy as it
     slides; opacity fades it in/out. JS just toggles `.is-open`. */
  display: grid;
  grid-template-rows: 0fr;
  opacity: 0;
  transition: grid-template-rows 0.36s cubic-bezier(0.4, 0, 0.2, 1),
              opacity 0.26s ease;
}
.faq__a > * {
  overflow: hidden;
  min-height: 0;
}
.faq.is-open .faq__a {
  grid-template-rows: 1fr;
  opacity: 1;
}
.faq__a p {
  margin: 0;
  padding-bottom: 1.5rem;
  font-size: 1.25rem;
  font-weight: 500;
  line-height: 1.4;
}
.faq__a a { text-decoration: underline; }
.faq__a ul {
  margin: 0 0 1.5rem;
  padding-left: 1.25rem;
  font-size: 1.25rem;
  font-weight: 500;
  line-height: 1.4;
}
.faq__a li + li { margin-top: 0.35rem; }
.faq__a strong { font-weight: 700; }

/* Support page: yellow breathing room below the last FAQ before the white
   footer begins (88–160px). Padding on main — not the footer — so the gap
   reads clearly on the yellow background. */
.support {
  padding-bottom: clamp(88px, 10vw, 160px);
}

.support + .site-footer {
  border-top: 0;
  padding-top: clamp(3rem, 5vw, 4.5rem);
}

/* Explore already has yellow lead-in sections (WGYB + reviews), so the global
   yellow footer border reads like an extra "container" stripe on Safari. Drop
   it just for explore and use normal top padding like support.
   Use a direct body class (not :has) for maximum Safari compatibility. */
body.page-explore .site-footer {
  border-top: 0;
  padding-top: clamp(3rem, 5vw, 4.5rem);
}
/* ~40px of yellow breathing room between the reviews rating/pagination and the
   white footer. */
body.page-explore .reviews { padding-bottom: 40px; }

/* ===================================================================
   TABLET   (<= 1024px)
   =================================================================== */
@media (max-width: 1024px) {
  :root { --hero-gap: 16px; }

  /* Back to the plain gutter so the menu button + logo align with content. */
  .nav { padding-inline: var(--gutter); }
  .nav__links { display: none; }
  .nav__menu-btn { display: flex; }
  /* Store buttons live in the dropdown menu on tablet/mobile, not the nav. */
  .nav__actions { display: none; }

  .featured__logos { gap: 4rem; }

  /* Explore cards: swipeable carousel on tablet (trackpad / drag paginate). */
  .explore .section-title { margin-bottom: 2.25rem; }
  .explore__cards {
    display: flex;
    gap: var(--gutter);
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    -webkit-overflow-scrolling: touch;
    margin-inline: calc(-1 * var(--gutter));
    padding-inline: var(--gutter);
    scrollbar-width: none;
    max-width: none;
  }
  .explore__cards::-webkit-scrollbar { display: none; }
  .feature-card {
    flex: 0 0 100%;
    scroll-snap-align: center;
    scroll-snap-stop: normal;
    aspect-ratio: 346 / 448;
  }
  .explore__dots { display: flex; }
  .explore__caption { margin-top: 3rem; font-size: 1.25rem; max-width: 17.625rem; }

  /* Support: taller banner ratio + tighter columns. Hero title stays 64px. */
  .support-hero__card { aspect-ratio: 928 / 420; }
  /* Tablet hero margin is 48px in the design (not the 16px home-hero frame). */
  .support-hero { padding-inline: 48px; }
  .support-row { grid-template-columns: 34fr 66fr; }
}

/* ===================================================================
   MOBILE   (<= 640px)
   =================================================================== */
@media (max-width: 640px) {
  :root { --hero-gap: 8px; --header-h: 4.5rem; }

  .nav__logo img { width: 5.75rem; }
  .menu-overlay__top { height: 4.5rem; }

  /* Hero is a rounded card in a uniform yellow frame (the page yellow shows
     through the transparent corners + the gap below). Radius matches the iPhone's
     screen-corner curve so the card reads as concentric with the phone. Two
     viewport models, because Safari's toolbar floats OVER the page while every
     other browser's bar is solid (.is-ios-safari is set by JS — CSS can't tell
     iOS Safari from iOS Chrome, both being WebKit):
       • Default / mobile Chrome → svh: the card ends just above the bottom bar so
         the image sits above it (never behind). svh is a *fixed* height (unlike
         dvh), so the hero does NOT resize as the toolbar hides/shows on scroll —
         that live resize was shoving the footer up/down mid-scroll.
       • iOS Safari → lvh + overshoot: the image bleeds down behind the floating
         toolbar, hugging the phone's bottom corners. */
  .hero { padding-bottom: var(--hero-gap); }
  .hero__card {
    border-radius: 52px;
    height: calc(100svh - var(--header-h) - var(--hero-top) - var(--hero-gap));
  }
  .is-ios-safari .hero__card {
    height: calc(100lvh - var(--header-h) - var(--hero-top) - var(--hero-gap) + 57px);
  }
  /* Text block vertically centered, CTA pinned near the bottom. Default sits the
     CTA a normal pad above the bar; Safari lifts it back above the floating
     toolbar (band = lvh − svh) plus the image overshoot, so only the image runs
     behind the bar. */
  .hero__content {
    display: grid;
    grid-template-rows: 1fr auto;
    align-items: center;
    justify-items: center;
    padding: 1.75rem 1.5rem 2.5rem;
  }
  .is-ios-safari .hero__content {
    padding-bottom: calc(4rem + 100lvh - 100svh + 20px);
  }
  /* Mobile line breaks (lock-ups) in headings — match the Figma frame. */
  .brk { display: inline; }

  /* Hero: 48px Black, two lines, -0.912px tracking. */
  .hero__text { align-self: center; }
  .hero__title { font-size: clamp(2.5rem, 12.4cqw, 3rem); letter-spacing: -0.019em; line-height: 1; }
  .hero__subtitle { font-size: 1.25rem; line-height: 1.5; margin-top: 0.75rem; }
  .hero__cta { margin-top: 0; align-self: end; font-size: 1rem; padding: 1.125rem 2.5rem; }

  /* Section titles: 42px Bold, line-height 1.2, -0.798px tracking. */
  .section-title { font-size: 2.625rem; line-height: 1.2; letter-spacing: -0.019em; }

  /* NEW pill: 12px, 46×25. */
  .pill { height: 1.5625rem; min-width: 2.875rem; padding: 0 0.75rem; font-size: 0.75rem; }

  .cashback .section-title { margin-top: 1.75rem; }
  .cashback__card-img { width: 27.75rem; max-width: 100%; }
  .cashback__desc { font-size: 1.25rem; line-height: 1.4; max-width: 19.4375rem; }
  /* Stack with the black "Apply for Card" on top, "Get the App" below. */
  .cashback__buttons { flex-direction: column-reverse; width: 13.125rem; gap: 0.75rem; }
  .cashback__buttons .btn { width: 100%; }
  .rating__text { font-size: 0.8125rem; }

  /* Card titles on small phones: 50px Bold. */
  .feature-card__title { font-size: 3.125rem; line-height: 1; }

  .investors .section-title { margin-bottom: 2.25rem; }
  /* Investor rows: 20px Medium. */
  .investors__list li { font-size: 1.25rem; font-weight: 500; }

  /* Mobile: the founders photo is its own rounded card; the headline and
     Read More button sit below it on the yellow page (not inside the card). */
  .press-card {
    height: auto;
    aspect-ratio: auto;
    background: transparent;
    overflow: visible;
    border-radius: 0;
    margin-top: 2.25rem;
  }
  .press-card__media {
    position: relative;
    height: 16.25rem;
    border-radius: 2rem;
    overflow: hidden;
  }
  .press-card__footer {
    position: static;
    flex-direction: column;
    align-items: flex-start;
    gap: 1.125rem;
    padding: 1.25rem 0 0;
    left: auto; right: auto; bottom: auto;
  }
  /* Press headline: 20px Medium, line-height 26px (not bold on mobile). */
  .press-card__headline { font-size: 1.25rem; font-weight: 500; line-height: 1.3; max-width: none; }
  .press-card__more { width: 10.25rem; }

  /* Match the design's ~70px gap from the founder area to "Also featured on". */
  .featured { margin-top: 2rem; }
  .featured__inner { padding: 2.5rem 0; }
  .featured__logos { gap: 2.25rem; flex-wrap: wrap; }
  .featured__logos img:nth-child(1) { height: 1.25rem; }
  .featured__logos img:nth-child(2) { height: 1.75rem; }
  .featured__logos img:nth-child(3) { height: 2rem; }

  .site-footer { padding: 3.5rem 0 calc(2.5rem + env(safe-area-inset-bottom)); }

  .support {
    padding-bottom: clamp(88px, 14vw, 160px);
  }
  .support + .site-footer {
    padding-top: 3.5rem;
  }

  /* Two-column footer: logo on its own row, main links (left) and legal
     links + store glyphs (right). `display: contents` flattens the brand /
     right wrappers so their children become grid items. */
  .footer__top {
    display: grid;
    grid-template-columns: 1fr 1fr;
    column-gap: 1.5rem;
    row-gap: 1.5rem;
    grid-template-areas:
      "logo  logo"
      "main  legal"
      "main  stores";
    align-items: start;
  }
  .footer__brand,
  .footer__right { display: contents; }

  .footer__logo { grid-area: logo; margin: 0 0 0.75rem; }
  .footer__logo img { width: 4rem; height: 4rem; }

  .footer__links { grid-area: main; gap: 1.375rem; font-size: 1.125rem; font-weight: 600; }
  .footer__legal {
    grid-area: legal;
    flex-direction: column;
    gap: 1.375rem;
    font-size: 1.125rem;
    font-weight: 600;
  }

  /* Bare Play/Apple glyphs (no circle), pinned to the bottom-right and
     ordered Play then Apple to match the design. */
  .footer__stores {
    grid-area: stores;
    flex-direction: row-reverse;
    justify-self: end;
    align-self: end;
    gap: 1.25rem;
  }
  .footer__stores .icon-btn {
    width: auto;
    height: auto;
    border: none;
    background: transparent;
    padding: 0;
  }
  .footer__stores .icon-btn img { height: 1.5rem; }

  .footer__wordmark { margin-top: 2.5rem; }
  .footer__copy { text-align: center; }

  /* ---- Support page (mobile) ---- */
  /* Near-square hero; frame matches the home hero via --hero-gap (8px here). */
  .support-hero { padding: 0 var(--hero-gap); }
  .support-hero__card { aspect-ratio: 385 / 390; border-radius: 32px; }
  .support-hero__title { font-size: 3rem; }

  .support-section { margin-top: clamp(56px, 18vw, 88px); }
  .support-faq { margin-top: clamp(72px, 22vw, 100px); }
  .support-faq .support-inner { margin-top: clamp(64px, 20vw, 96px); }

  /* Stack each row: label on top, items below (~56px label→content gap). */
  .support-row { grid-template-columns: 1fr; row-gap: 3.5rem; }
  .support-faq .support-row + .support-row { margin-top: clamp(72px, 22vw, 100px); }
  .support-row__label,
  .support-row__label--lg { font-size: 2rem; }

  .support-item__a { font-size: 1rem; }

  .faq__a p { font-size: 1rem; }
  .faq__a ul { font-size: 1rem; }
}

/* ============ Intro logo splash ============ */
.splash {
  position: fixed;
  inset: 0;
  z-index: 2000;
  display: grid;
  place-items: center;
  /* Exact yellow baked into Logo_Animation.mp4 so the video edges blend
     invisibly into the full-screen overlay. */
  background: #fcf500;
  opacity: 1;
  /* Crossfades out (over the still-visible logo) as the hero square grows in,
     so the logo hands straight off to the image with no empty-yellow gap. */
  transition: opacity 0.3s ease;
}

.splash__video {
  /* Centered (via the splash grid) and a lot smaller than full-screen:
     ~90vw on phones (10% in from the edges), capped on larger screens so
     the logo stays compact. The video is square, so height follows. */
  width: min(90vw, 460px);
  height: auto;
  object-fit: contain;
}

/* Faded out by JS once the clip ends (or after a fallback timeout). */
.splash.is-hidden {
  opacity: 0;
  pointer-events: none;
}

/* Hold the page until the intro plays, then ease it in as the splash fades. */
body.is-loading {
  overflow: hidden;
}
/* Splash intro: the page is made solid underneath the (opaque) splash, so this
   only keeps the scroll locked while the logo animation plays. */
body.is-intro {
  overflow: hidden;
}
/* Hold the nav items hidden until the hero image has finished growing, then
   ease them in. The yellow header bar itself stays put, so there's no flash —
   only the items (menu, links, logo, store buttons) animate in. */
.nav {
  transition: opacity 0.55s ease;
}
body.is-nav-hidden .nav {
  opacity: 0;
}
/* Cross-page crossfade via the View Transitions API. Same-origin navigations
   snapshot the outgoing page and crossfade it into the incoming one natively —
   no blank gap. The JS keeps both pages' content fully visible at snapshot time
   (it never fades the outgoing page and reveals the incoming one instantly on
   in-site nav), so this crossfades real content to real content. Browsers
   without view transitions just navigate normally and use the is-loading fade
   below as the entrance. */
@view-transition {
  navigation: auto;
}
/* The incoming page eases in slowly (from 98.5%) with a soft slide up while the
   outgoing one fades out — every navigation lands with the same gentle intro
   motion as a fresh load. The splash loader is untouched: it only runs on fresh
   loads, where there is no outgoing page and therefore no view transition. */
::view-transition-old(root) {
  /* Hold the OUTGOING page fully opaque underneath, with NORMAL blending (not the
     UA-default additive `plus-lighter`). Because the incoming page also zooms +
     slides in, an additive crossfade blended the two misaligned pages into a
     ghosted / washed-out flash mid-transition. Holding the old page opaque lets
     the new one fade + zoom cleanly ON TOP of it — no ghosting, no brightness dip. */
  animation: pageHold 0.9s both;
  mix-blend-mode: normal;
}
::view-transition-new(root) {
  animation: pageFadeIn 0.9s cubic-bezier(0.33, 1, 0.68, 1) both;
  mix-blend-mode: normal;
  transform-origin: center center;
}
@keyframes pageHold {
  from, to { opacity: 1; }
}
@keyframes pageFadeIn {
  from { opacity: 0; transform: scale(0.985) translateY(8px); }
  to   { opacity: 1; transform: scale(1) translateY(0); }
}

main,
.site-footer {
  opacity: 1;
  transform: scale(1) translateY(0);
  transform-origin: center top;
  /* Fresh-load entrance (cross-page navigations use the view transition above,
     tuned to match): a slow, soft fade up with a barely-there zoom (from 98.5%). */
  transition: opacity 0.8s ease-out, transform 0.9s cubic-bezier(0.33, 1, 0.68, 1);
}
body.is-loading main,
body.is-loading .site-footer {
  opacity: 0;
  transform: scale(0.985) translateY(8px);
}
/* The header is a FIXED anchor across every page: it only fades in (never zooms
   or slides), and it's lifted into its own view-transition group so a page-to-page
   navigation leaves the nav exactly in place while the content animates beneath
   it. Combined with the reserved scrollbar gutter, the nav never jumps. */
.site-header {
  opacity: 1;
  transition: opacity 0.7s ease-out;
  view-transition-name: site-header;
}
body.is-loading .site-header { opacity: 0; }

/* Keep the body transparent while loading so the (yellow) root background shows
   through instead of a white flash before the content fades in. */
body.is-loading {
  background: transparent;
}

/* Failsafe: the JS strips .is-loading to reveal the page. If scripting is
   unavailable it never runs, so reveal everything (and drop the splash) rather
   than leaving a blank page stuck on the loading state. */
@media (scripting: none) {
  .splash { display: none !important; }
  body.is-loading .site-header,
  body.is-loading main,
  body.is-loading .site-footer {
    opacity: 1;
    transform: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .splash { transition: none; }
  .site-header,
  main,
  .site-footer { transition: none; transform: none; }
  /* Fold the header back into the root snapshot so it swaps instantly with the
     page (no stray crossfade) for reduced-motion users. */
  .site-header { view-transition-name: none; }
  .hero__bg,
  .hero__overlay,
  .hero__content,
  .nav { transition: none; }
  .menu-overlay,
  .menu-overlay.is-closing,
  .menu-overlay__panel,
  .menu-overlay.is-closing .menu-overlay__panel { animation: none; transition: none; }
  .faq__a { transition: none; }
  /* Skip the cross-page crossfade — navigate with an instant swap instead. */
  ::view-transition-old(root),
  ::view-transition-new(root) { animation: none; }
  /* No button content-roll. */
  .btn__roll-inner { transition: none; }
  .btn:hover .btn__roll-inner,
  .btn:focus-visible .btn__roll-inner,
  .icon-btn:hover .btn__roll-inner,
  .icon-btn:focus-visible .btn__roll-inner { transform: none; }
}

/* ===================================================================
   EXPLORE APP PAGE — single pinned phone, scroll-scrubbed.
   One device stays pinned in the viewport while a tall .xtrack scrolls
   past it; the JS scrubber reads that progress and crossfades the phone
   through three app states. The hero icon ring trails the phone down and
   then scatters outward to reveal each section's copy + props.
   Progressive enhancement: WITHOUT the .is-scrub class (no-JS or
   reduced-motion) the stage collapses to a normal, fully-readable
   stacked layout. The JS adds .is-scrub to switch on the experience.
   =================================================================== */
.x-explore {
  position: relative;
  /* The floating icons (.xring/.xic) deliberately splash past the phone — on
     narrow viewports their spread pushes them beyond the screen edge, which on
     its own makes the whole page scroll sideways (body{overflow-x:hidden} is
     unreliable because it turns the body into a scroll container). Clip the
     spill HERE instead. `clip` (not hidden/auto) clips without establishing a
     scroll container, so the sticky phone keeps pinning; overflow-y stays
     visible so the desktop WGYB tuck and vertical icon splash are untouched. */
  overflow-x: clip;
  /* One knob controls phone size everywhere; the ring scales off it.
     Height-capped (vh) so the device + hero copy both fit the pinned view. */
  --phw: min(clamp(210px, 23vw, 320px), 26vh);
  --gutter: clamp(20px, 6vw, 104px);
  /* How far the floating icons sit from the phone. Pushes every icon
     radially out from centre WITHOUT changing its size, so a higher value
     reads as "further from the phone + more spaced apart". JS scrubs this
     from SPREAD_TIGHT -> SPREAD_WIDE on desktop as the hero splashes open. */
  --ring-spread: 2.3;
  /* Per-section props frame the phone CLOSELY (so they read as sitting beside
     the screen content), much tighter than the wide hero ring. */
  --ring-spread-front: 1.3;
}

/* Desktop: drop the 26vh cap (it shrank the phone to ~220px and made the screen
   look crunchy) and give the hero a bit more width for a sharper downscale. */
@media (min-width: 1025px) {
  .x-explore { --phw: clamp(260px, 22vw, 360px); }
}

/* ---------- Phone (shared by both layouts) ---------- */
.xphone {
  position: relative;
  z-index: 2;
  width: var(--phw);
  aspect-ratio: 343 / 744;
  background: #000;
  border-radius: 17% / 7.84%;
  /* Bezel must scale with the PHONE's width. A plain `%` resolves against the
     containing block (the full-width pinned stage), which on desktop blew the
     bezel up to ~48px and crushed/cropped the screen. */
  padding: calc(var(--phw) * 0.033);
}
.xphone__screens {
  position: relative;
  width: 100%;
  height: 100%;
  border-radius: 14.67% / 6.52%; /* concentric with the 17%/7.84% bezel minus the 3.3% padding (~0.137W corner) */
  overflow: hidden;
  background: #fff;
  container-type: inline-size;
}
/* Modal backdrop: dims the transaction list inside the screen bezel. Lives as a
   sibling between .xphone__screens and .xtray so it never tints the sheet. */
.xscrim {
  position: absolute;
  top: calc(var(--phw) * 0.033);
  right: calc(var(--phw) * 0.033);
  bottom: calc(var(--phw) * 0.033);
  left: calc(var(--phw) * 0.033);
  z-index: 2;
  border-radius: 14.67% / 6.52%;
  background: #000;
  opacity: 0;
  pointer-events: none;
}
.xscreen { position: absolute; inset: 0; }
.xscreen__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top center;
}
/* Full-screen capture (phone1.png): aspect matches the screen (343/744) so
   fill = 1:1, no crop, no letterboxing. contain was leaving a second resize
   pass; cover cropped to just the card. */
.xscreen--purch .xscreen__img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: fill;
  object-position: center;
}
.xscreen__img.is-dim { filter: brightness(0.82) saturate(0.94); }

/* ---------- Purchases screen: card + list scroll under fixed chrome ----------
   The .xpurch__scroll layer (card + "My Purchases" + 8 rows) starts just below
   the fixed status bar and is translated UP by JS on F3 so the card scrolls away
   and the full list fills the screen, then the win-it-back sheet rises. The two
   chrome images (status bar, tab bar) stay pinned, so the list scrolls behind
   them like a real app. Slice geometry: status 7.34%, tab 9.32% of the screen;
   the card is 26.28% of the scroll layer's height (see .refbuild geometry). */
.xpurch__scroll {
  position: absolute;
  top: 7.34%;
  left: 0;
  width: 100%;
  will-change: transform;
}
.xpurch__scroll img { display: block; width: 100%; }
.xpurch__chrome {
  position: absolute;
  left: 0;
  width: 100%;
  display: block;
  z-index: 2;
}
.xpurch__chrome--top { top: 0; }
.xpurch__chrome--bot { bottom: 0; }

/* ---------- Shared headings / CTA ---------- */
.xtitle {
  margin: 0;
  font-weight: 700;
  letter-spacing: -0.019em;
  line-height: 1.04;
  font-size: 2.5rem; /* 40px @ 1440; scales with the root on larger screens */
}
.xtitle--xl { font-weight: 900; font-size: clamp(38px, 2.4vw + 22px, 60px); } /* hero stays larger */
.xsub {
  margin: 1.05rem 0 0;
  max-width: 26rem;
  font-size: clamp(1.0625rem, 0.5vw + 0.95rem, 1.5rem);
  font-weight: 500;
  line-height: 1.45;
}
.xcta {
  margin-top: clamp(1.25rem, 2vw, 2rem);
  height: 3.75rem;
  font-size: 1.0625rem;
  padding-inline: 2rem;
}
.btn--black .btn__icon { filter: invert(1); }

/* ---------- Icon ring + floating props ----------
   Every floating object (hero icons + per-section props) shares .xic and
   lives in .xring, whose coordinate box reproduces the original sticker
   ring around the phone. Positions come from --cx/--cy/--w (0..1 within
   the ring box). The OUTER .xic carries the JS scatter transform; the
   INNER img carries the idle-float keyframe + base rotation — two
   transform contexts so motion never fights. */
.xring {
  position: absolute;
  left: 50%;
  top: 50%;
  width: calc(var(--phw) * 3.3);
  aspect-ratio: 2502 / 1842;
  translate: -50% -50%;
  z-index: 1;
  pointer-events: none;
}
/* The front ring shares the same box but renders ABOVE the phone so its props
   can overlap the screen content (e.g. popcorn spilling over the tray). */
.xring--front { z-index: 3; }

/* Desktop hero ring box. The hero icons use the Figma manifest --cx/--cy/--w
   (fractions of this box) at rest spread ~1, so the box size alone scales the
   whole sticker group relative to the phone. 4.6× the phone width reproduces the
   Figma hero ratio (e.g. plane ≈ 48%, golf ≈ 28% of the phone) and frames the
   device the way the design does. The front prop ring keeps the base 3.3× box so
   feature props are unchanged. Mobile/tablet size their ring in the block below. */
@media (min-width: 1025px) {
  .is-scrub .xring:not(.xring--front) { width: calc(var(--phw) * 4.6); }
}

/* ---------- "Win cool stuff" confetti ----------
   A burst of paper pieces (JS-generated) that erupts UP + OUT from the phone
   itself, then arcs back down with gravity. The whole layer is faded in by the
   scrub only on the final frame, and the pieces animate only while that frame is
   live (.is-on), so it stays idle the rest of the time. */
.xconfetti {
  position: absolute;
  inset: 0;
  z-index: 4;
  overflow: hidden;
  pointer-events: none;
  opacity: 0;
}
.xconfetti__piece {
  position: absolute;
  /* Origin = the phone itself (centre of the stage); every piece launches here. */
  top: 46%;
  left: 50%;
  width: var(--w);
  height: var(--h);
  background: var(--c);
  border-radius: var(--r);
  will-change: transform, opacity;
  animation: confettiBurst var(--dur) linear var(--delay) infinite;
  animation-play-state: paused;
}
.xconfetti.is-on .xconfetti__piece { animation-play-state: running; }
@keyframes confettiBurst {
  0% {
    transform: translate3d(-50%, -50%, 0) scale(0.5) rotate(0deg);
    opacity: 0;
    /* Fast launch out of the device, decelerating toward the peak. */
    animation-timing-function: cubic-bezier(0.12, 0.75, 0.3, 1);
  }
  10% { opacity: 1; }
  34% {
    transform: translate3d(calc(-50% + var(--bx) * 0.72), calc(-50% + var(--by)), 0) scale(1)
      rotate(calc(var(--spin) * 0.42));
    /* Past the peak, gravity accelerates the fall. */
    animation-timing-function: cubic-bezier(0.4, 0, 0.75, 1);
  }
  88% { opacity: 1; }
  100% {
    transform: translate3d(calc(-50% + var(--bx)), calc(-50% + var(--fy)), 0) scale(1)
      rotate(var(--spin));
    opacity: 0;
  }
}
.xic {
  position: absolute;
  /* Place from the ring centre and scale the offset by --ring-spread so the
     icons fan further out from the phone while keeping their own size. */
  left: calc(50% + (var(--cx) - 0.5) * var(--ring-spread) * 100%);
  top: calc(50% + (var(--cy) - 0.5) * var(--ring-spread) * 100%);
  width: calc(var(--w) * 100%);
  translate: -50% -50%;
  will-change: transform, opacity;
}
.xic--front {
  z-index: 3;
  /* Props frame the phone closely via their own (tighter) spread. */
  left: calc(50% + (var(--cx) - 0.5) * var(--ring-spread-front) * 100%);
  top: calc(50% + (var(--cy) - 0.5) * var(--ring-spread-front) * 100%);
}
.xic__img {
  display: block;
  width: 100%;
  height: auto;
  /* Duration + delay are individualised from JS; the keyframe adds a soft
     vertical bob, a little horizontal sway, a rotation wobble and a faint
     scale-pulse, each at a per-icon amplitude (--fa/--fx/--fr/--fs) so the idle
     drift varies in size, distance and tempo from one icon to the next. */
  animation: xFloatY var(--fd, 7s) cubic-bezier(0.37, 0, 0.63, 1) infinite;
  animation-delay: var(--ad, 0s);
}
@keyframes xFloatY {
  0%   { transform: translate(0, 0) rotate(var(--rot, 0deg)) scale(1); }
  25%  { transform: translate(var(--fx, 0%), calc(var(--fa, -7%) * 0.5)) rotate(calc(var(--rot, 0deg) + var(--fr, 0deg))) scale(var(--fs, 1)); }
  50%  { transform: translate(0, var(--fa, -7%)) rotate(var(--rot, 0deg)) scale(1); }
  75%  { transform: translate(calc(-1 * var(--fx, 0%)), calc(var(--fa, -7%) * 0.5)) rotate(calc(var(--rot, 0deg) - var(--fr, 0deg))) scale(var(--fs, 1)); }
  100% { transform: translate(0, 0) rotate(var(--rot, 0deg)) scale(1); }
}

/* ---------- Copy panels ---------- */
.xpanel { max-width: 30rem; }
.xpanel--hero { text-align: center; }

/* The dedicated mobile/tablet stack (.xm) is desktop-hidden; the scrub shows
   instead. Below 1025px the media query flips these (scrub hidden, .xm shown). */
.xm { display: none; }

/* ---------- Win-it-back sheet (lifts out of the phone on F3) ----------
   Lives OUTSIDE the screens' overflow clip (a direct child of .xphone), so it
   can rest a touch WIDER than the device and spill a hair below it — reading as
   a card lifted off the phone toward you. It's its own query container, so the
   logo / text / button scale to the SHEET width; the outer box + padding are
   sized off --phw (fixed length) to avoid a container-unit cycle. JS grows it
   out of the phone (scales up from centre). */
.xtray {
  position: absolute;
  left: 50%;
  bottom: -3%;                          /* spills a hair below the phone bottom */
  z-index: 3;                           /* above .xscrim — sheet stays bright */
  width: calc(var(--phw) * 1.077);      /* ~5% larger than prior 1.026× sheet */
  opacity: 0;                           /* JS reveals it on the win-it-back frame */
  background: var(--white);
  border-radius: calc(var(--phw) * 0.086); /* ~15% rounder corners */
  padding: calc(var(--phw) * 0.085) calc(var(--phw) * 0.07) calc(var(--phw) * 0.07);
  box-shadow: 0 22px 60px -18px rgba(0, 0, 0, 0.28);
  transform: translateX(-50%);          /* JS appends translateY + scale */
  transform-origin: center;             /* grows out of the phone (scales from centre) */
  will-change: transform, opacity;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  container-type: inline-size;          /* internals scale to the sheet width */
}
.xtray__logo {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36cqw;
  height: 36cqw;
  border-radius: 50%;
  background: #000;
  color: #fff;
  font-size: 9.5cqw;
  font-weight: 700;
  letter-spacing: -0.03em;
}
.xtray__name { margin: 6cqw 0 0; font-size: 9cqw; font-weight: 700; letter-spacing: -0.02em; }
.xtray__amount { margin: 2.4cqw 0 0; font-size: 7cqw; font-weight: 600; letter-spacing: -0.02em; }
.xtray__meta { margin: 3.4cqw 0 0; font-size: 3.4cqw; font-weight: 500; letter-spacing: -0.01em; color: #b3b3b3; }
.xtray__btn { margin-top: 7cqw; width: 100%; padding: 6.2cqw 0; border-radius: 100px; background: var(--yellow-card); color: #000; font-size: 7.6cqw; font-weight: 700; }

/* ---------- PS5 prize + players (screen 3 overlay) ---------- */
.xprize__ps5 { position: absolute; left: 50%; top: 17%; translate: -50% 0; height: 52%; width: auto; z-index: 3; }
.xprize__players { position: absolute; left: 50%; top: 63%; translate: -50% 0; z-index: 3; width: 78%; display: flex; flex-direction: column; align-items: center; gap: 2.5cqw; }
.xprize__count { margin: 0; font-size: 4.6cqw; font-weight: 500; letter-spacing: -0.02em; }
.xprize__count strong { font-weight: 800; }
.xprize__avatars { width: 64%; height: auto; }

/* ---------- Sports "Tinder" swipe card (screen 4 overlay) ----------
   .xpick-zone lives OUTSIDE .xphone__screens so the swiping front card can spill
   past the device bezel. .xpick keeps the original deck box + entrance motion. */
.xpick-zone {
  position: absolute;
  top: calc(var(--phw) * 0.033);
  right: calc(var(--phw) * 0.033);
  bottom: calc(var(--phw) * 0.033);
  left: calc(var(--phw) * 0.033);
  z-index: 4;
  overflow: visible;
  pointer-events: none;
}
.xpick {
  position: absolute;
  left: 50%;
  top: 45%;
  z-index: 1;
  width: 82%;
  aspect-ratio: 259 / 327;
  container-type: inline-size;
  transform: translate(-50%, -50%);
  transform-origin: center;
  will-change: transform, opacity;
  opacity: 0;
  overflow: visible;
}
.xpick__media {
  display: block;
  position: absolute;
  inset: 0;
  border-radius: 7cqw;
  overflow: hidden;
  border: 0.4cqw solid rgba(255, 255, 255, 0.35);
  box-shadow: 0 6cqw 14cqw rgba(0, 0, 0, 0.3);
  transform-origin: 50% 120%;
  will-change: transform;
}
/* The deck: a card behind the swipe card. The front card slides + tilts over
   it (Tinder style); JS scrubs the reveal, these are the resting positions used
   by the static fallback and the mobile stack. */
.xpick__media--back {
  z-index: 1;
  transform: translateX(-8%) rotate(-5deg) scale(0.95);
}
.xpick__media--front {
  z-index: 2;
  transform: translateX(13%) rotate(8deg);
}
.xpick__media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center center;
}
.xpick__media--front::after {
  /* Front PNG already includes a bottom vignette; skip the extra overlay. */
  content: none;
}
.xpick__q {
  position: absolute;
  left: 10%;
  right: 10%;
  bottom: 8.5%;
  z-index: 2;
  margin: 0;
  text-align: center;
  font-family: var(--font);
  color: #fff;
  font-size: 7.25cqw;
  font-weight: 700;
  line-height: 1.16;
  letter-spacing: -0.025em;
}

/* ===================================================================
   FALLBACK LAYOUT (no .is-scrub): stacked + readable, no motion.
   =================================================================== */
.xpin { position: relative; }
.xslide { display: flex; justify-content: center; padding-top: clamp(24px, 5vw, 56px); }
.xring { display: none; }                 /* decorative; needs the scrub to make sense */
.xscreen { opacity: 0; }
.xscreen[data-screen="0"] { opacity: 1; } /* show the first app state */
.xpanels {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(40px, 8vw, 96px);
  padding: clamp(48px, 9vw, 110px) var(--gutter) clamp(32px, 6vw, 72px);
  text-align: center;
}
.xpanels .xpanel { text-align: center; }
.xpanels .xsub { margin-inline: auto; }
.xpanels .xcta { display: inline-flex; }

/* ===================================================================
   SCRUB LAYOUT (.is-scrub added by JS): pin the stage, drive by scroll.
   =================================================================== */
.is-scrub .xtrack { height: 1150svh; }
/* The shared header is in-flow (it pushes content down by --header-h), which
   would otherwise park the sticky pin --header-h below the viewport top until
   you scroll past it — dropping the centred hero copy and the phone's peek low
   on load. Pull the whole scrub stage up under the header so the pin fills the
   viewport from the very top; the header (same yellow, z-index:50) simply floats
   over the top of the stage and scrolls away as normal. Desktop only — the
   tablet/mobile band layout anchors its copy at the top, so it stays in flow. */
@media (min-width: 1025px) {
  .x-explore.is-scrub { margin-top: calc(-1 * var(--header-h)); }
  .x-explore.is-scrub { margin-bottom: clamp(-12rem, -32vh, -6rem); }
  /* The stage now sits UNDER the header, so a solid header background would mask
     the top of the hero + its floating icons (and unbalance the centred copy).
     Drop it so the pinned stage shows straight through; the header's logo/links/
     buttons still float on top, and it scrolls away as normal. */
  body:has(.x-explore.is-scrub) .site-header { background: transparent; }
}
.is-scrub .xpin {
  position: sticky;
  top: 0;
  /* STABLE *and* gap-free: use lvh (the LARGEST the viewport ever gets, i.e. with
     the iOS toolbar collapsed). This is the only height that fixes BOTH bugs at
     once:
       • dvh  -> no yellow gap, but RELAYOUTS every frame while the toolbar resizes
                 during a momentum swipe -> the rapid micro-shaking.
       • svh  -> rock-steady, but when the toolbar collapses the svh->lvh band opens
                 BELOW the bottom-anchored phone -> the yellow bar returns.
       • lvh  -> a FIXED value (never changes mid-scroll, so zero per-frame relayout
                 = no shake) that already spans the collapsed-toolbar viewport (so the
                 phone, anchored to the lvh bottom, always reaches the real bottom =
                 no yellow gap). When the toolbar is *shown* the stage is simply a bit
                 taller than the visible area and its bottom tucks behind the toolbar —
                 revealing it as the toolbar collapses needs NO layout change. */
  height: 100svh; /* fallback for very old engines without lvh */
  height: 100lvh;
  /* Deliberately NO overflow clip here: the floating icons splash past the stage
     edges and must stay fully visible. Sideways page scroll is contained by
     `overflow-x: clip` on .x-explore (clip doesn't break this sticky pin); any
     vertical overflow falls off-screen above/below it. */
}
.is-scrub .xslide {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  /* No will-change here — xslide wraps the phone; promoting this layer to the GPU
     resamples the screen image and makes phone1.png look crunchy. */
}
.is-scrub .xring { display: block; }
.is-scrub .xic { opacity: 0; }            /* JS reveals per phase */
.is-scrub .xscreen { opacity: 0; transition: none; }

.is-scrub .xpanels {
  display: block;
  padding: 0;
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.is-scrub .xpanel {
  position: absolute;
  /* Copy never fades — it slides (translateY via --pty) and simply travels
     off-screen above/below the pinned viewport at the ends of its range. */
  opacity: 1;
  will-change: transform;
}
/* Hero: centred horizontally; rests a touch (40px) above the vertical centre so
   it sits high over the phone peeking below. Slides up via --pty on scroll. */
.is-scrub .xpanel--hero {
  left: 50%;
  top: 50%;
  width: min(94%, 52rem);
  /* Override the base .xpanel 30rem cap: the one-line (nowrap) headline is wider
     than 30rem, so capping the panel made the headline overflow its box to the
     RIGHT (text-align:center can't recentre an overflowing line) and read as
     shifted right. A roomy panel lets the headline sit truly centred. */
  max-width: none;
  transform: translate(-50%, calc(-50% - 40px + var(--pty, 0px)));
}
/* Keep the hero headline (and sub) on one line on desktop so the centred copy
   block stays compact and leaves clean room for the phone peeking below it.
   Size the headline to its own content and centre it with auto margins rather
   than relying on text-align over a wider box — so it can never spill to one
   side the way the old 30rem panel cap made it overflow right. */
.is-scrub .xpanel--hero .xtitle {
  white-space: nowrap;
  width: max-content;
  max-width: 100%;
  margin-inline: auto;
}
.is-scrub .xpanel--hero .xsub { max-width: none; }
/* Side panels: vertically centered against the pinned phone. They start parked
   below the fold (--pty) so they don't flash at centre before the scrubber runs;
   JS then slides them up through centre and out the top. */
.is-scrub .xpanel--right,
.is-scrub .xpanel--left {
  top: 50%;
  width: min(38%, 18.5rem);   /* narrow copy column matching the Figma callouts */
  --pty: 100vh;
}
.is-scrub .xpanel--right {
  right: var(--gutter);
  text-align: left; /* copy stays on the right side but reads left-aligned */
  transform: translateY(calc(-50% + var(--pty, 0px)));
}
.is-scrub .xpanel--right .xsub { max-width: 17rem; margin: 1.125rem auto 0 0; font-size: 1.25rem; line-height: 1.5; }
.is-scrub .xpanel--left {
  left: var(--gutter);
  text-align: left;
  transform: translateY(calc(-50% + var(--pty, 0px)));
}
.is-scrub .xpanel--left .xsub { max-width: 17rem; margin: 1.125rem auto 0 0; font-size: 1.25rem; line-height: 1.5; }
.is-scrub .xpanel a { pointer-events: auto; }
/* All three callout copy columns share the narrow Figma width set on the side
   panels above: "Win it all back" + "Win cool stuff" each sit on one line, and the
   longer "Sports picks, Tinder style" wraps to two — matching the design. */

/* ===================================================================
   EXPLORE — TABLET + MOBILE (<= 1024px)
   A centered phone leaves no room for side copy on a portrait/tablet
   viewport, so below desktop we switch layouts: copy stacks at the TOP
   (centered), the phone is bottom-anchored, and the icons float in a
   horizontal band in the open space between them.
   =================================================================== */
@media (max-width: 1024px) {
  /* Default mobile/tablet shows the static .xm fallback (no-JS / reduced motion).
     When JS adds .is-scrub, the SAME continuous scroll engine the desktop uses
     drives the pinned .xtrack — apply()'s vw<=1024 branch lays the phone/copy/
     props out for a portrait viewport (copy centred, phone bottom-anchored). */
  .xtrack { display: none; }
  .is-scrub .xtrack { display: block; height: 650svh; }
  .xm { display: block; overflow-x: clip; }
  .is-scrub .xm { display: none; }

  /* Solid yellow stage so iOS Safari (which tints its status bar + bottom toolbar
     by sampling the page's EDGE pixels) always reads yellow where the phone isn't —
     no white/transparent flash during the dvh toolbar resize. */
  .is-scrub .xpin { background: var(--yellow); }

  .x-explore.is-scrub {
    margin-top: 0;
    margin-bottom: 0;            /* WGYB flows normally below on mobile (no tuck) */
    /* NB: deliberately no overflow:hidden/auto here — that kind of overflow
       ancestor would break the sticky phone. The sideways icon spill is clipped
       by `overflow-x: clip` on .x-explore (clip is sticky-safe). */
    /* Phone widths mirror the static .xm blocks (design spec). JS morphs --phw
       from hero → feature as you scroll; these are the resting values at each end. */
    --phw-hero: min(76vw, 300px);
    --phw-feat: min(56vw, 226px);
    --phw: var(--phw-hero);
    --feat-half: calc(var(--phw) * 1.085);
    --feat-gap: clamp(22px, 6vw, 42px);
    --ring-spread: 1;
    --ring-spread-front: 1;
  }

  /* Bottom-anchor the phone so the hero can peek from the bottom edge (design).
     JS translateY pushes it down at load, then eases it up to centre for features. */
  .is-scrub .xslide {
    align-items: flex-end;
    justify-content: center;
    backface-visibility: hidden;
    -webkit-backface-visibility: hidden;
  }

  /* Hero icons live in the UPPER copy zone (like .xm-floats), not around the
     bottom-peek phone. The front ring stays viewport-centred for feature props. */
  .is-scrub .xring:not(.xring--front) {
    /* Taller + wider + centred a touch higher so the hero icons spread across the
       whole hero (above the title down to the phone) and push out to the screen
       edges — matching the Figma placement instead of clustering in the middle. */
    top: clamp(170px, 46svh, 360px);
    left: 50%;
    width: min(112vw, 31rem);
    height: clamp(460px, 124vw, 760px);
    aspect-ratio: unset;
    --ring-spread: 1;
    translate: -50% -50%;
    transform: translateY(var(--hero-lift, 0px));
  }

  /* Tablet portrait (641-1024px): scale the hero icon ring UP so it fills the
     screen and stays proportional to the now-larger tablet phone — matching the
     Figma hero density instead of the small, centred 31rem cluster. Phones
     (<=640px) keep the rule above untouched. */
  @media (min-width: 641px) {
    .is-scrub .xring:not(.xring--front) {
      width: min(118vw, 62rem);
      height: clamp(560px, 150vw, 1040px);
      top: clamp(220px, 40svh, 460px);
    }
  }

  /* SCRUB MECHANICS on mobile are identical to desktop: the global rules
     `.is-scrub .xpin { position: sticky; height: 100svh }` and the
     `.is-scrub .xtrack { height: 650svh }` above give the pin its scroll travel.
     The phone, its screen crossfades, the tray/scrim/pick props and the copy are
     ALL driven per-frame by the scrub's apply() (vw<=1024 branch) — so there are
     NO CSS transitions here (they'd lag/smear against the per-frame writes) and
     no snap stops. The pin scrolls away after the last scene to hand off to "We
     Got Your Back", which stays in normal flow below. The base .is-scrub rules
     (.xslide, .xpanels, .xpanel, .xring, .xscreen, .xic) already apply here. */

  /* ---- Hero copy (scene 0): mirrors .xm-hero — large title block in the
     upper area with generous gap before the bottom-peek phone. ---- */
  .is-scrub .xpanel--hero {
    left: 50%;
    right: auto;
    top: clamp(96px, 22vw, 160px);
    bottom: auto;
    width: min(92%, 22rem);
    max-width: none;
    text-align: center;
    transform: translate(-50%, var(--pty, 0px));
    backface-visibility: hidden;
    -webkit-backface-visibility: hidden;
  }
  .is-scrub .xpanel--hero .xtitle {
    white-space: normal;
    width: auto;
    max-width: 7em;
    margin-inline: auto;
    font-size: clamp(42px, 13.8vw, 58px);
    font-weight: 900;
    letter-spacing: -0.025em;
    line-height: 1.03;
  }
  .is-scrub .xpanel--hero .xcta {
    margin-top: clamp(22px, 5.5vw, 34px);
    height: 3.5rem;
    font-size: 1.0625rem;
    padding-inline: 1.75rem;
  }

  /* ---- Feature scenes (1-3): title centred ABOVE the phone, sub centred BELOW
     it. The panel fills the viewport (inset:0) so the title/sub anchor to the
     screen centre — that's the fix for copy drifting off to the left. The scrub
     fades each panel in/out via inline opacity; --pty stays 0 for these. ---- */
  .is-scrub .xpanel--left,
  .is-scrub .xpanel--right {
    inset: 0;
    width: auto;
    max-width: none;
    transform: translateY(var(--pty, 0px));
  }
  .is-scrub .xpanel--left .xtitle,
  .is-scrub .xpanel--right .xtitle {
    position: absolute;
    left: 50%;
    top: calc(50% - var(--feat-half) - var(--feat-gap));
    width: min(92%, 22rem);
    margin: 0;
    z-index: 2;
    text-align: center;
    transform: translate(-50%, -100%);
  }
  .is-scrub .xpanel--left .xsub,
  .is-scrub .xpanel--right .xsub {
    position: absolute;
    left: 50%;
    top: calc(50% + var(--feat-half) + var(--feat-gap) * 0.92);
    bottom: auto;
    width: min(92%, 22rem);
    margin: 0;
    z-index: 2;
    text-align: center;
    transform: translateX(-50%);
  }
  /* Shared sub sizing for every scene. */
  .is-scrub .xpanel--hero .xsub,
  .is-scrub .xpanel--left .xsub,
  .is-scrub .xpanel--right .xsub {
    max-width: 19rem;
    margin-inline: auto;
    font-size: clamp(17px, 4.4vw, 20px);
    line-height: 1.45;
  }
  .is-scrub .xpanel--hero .xsub { margin-top: clamp(12px, 3.2vw, 20px); }
  .is-scrub .xpanel .xtitle:not(.xtitle--xl) {
    font-size: clamp(36px, 10vw, 46px); /* matches the Figma feature headline (~40px) */
    font-weight: 800;
    letter-spacing: -0.025em;
    line-height: 1.03;
  }

  /* ---- shared mobile typography (static .xm fallback) ---- */
  .xm-title {
    margin: 0;
    text-align: center;
    font-weight: 800;
    letter-spacing: -0.025em;
    line-height: 1.03;
    font-size: clamp(34px, 8.4vw, 44px);
  }
  .xm-title--hero { font-weight: 900; font-size: clamp(46px, 15.5vw, 64px); max-width: 7em; }
  .xm-sub {
    margin: clamp(14px, 3.5vw, 22px) auto 0;
    max-width: 19rem;
    text-align: center;
    font-size: clamp(17px, 4.4vw, 20px);
    font-weight: 500;
    line-height: 1.45;
  }
  .xm-cta { display: inline-flex; margin-top: clamp(20px, 5vw, 30px); height: 3.5rem; font-size: 1.0625rem; padding-inline: 1.75rem; }

  /* ---- hero ---- */
  .xm-hero {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: clamp(8px, 3vw, 28px) 24px 0;
  }
  .xm-floats {
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    height: clamp(470px, 152vw, 700px);
    --ring-spread: 1;
    --ring-spread-front: 1;
    pointer-events: none;
    z-index: 0;
  }
  .xm-hero .xm-title,
  .xm-hero .xm-sub,
  .xm-hero .xm-cta { position: relative; z-index: 1; }
  .xm-hero .xm-title { margin-top: clamp(40px, 14vw, 84px); }
  .xm-phone--hero { --phw: min(76vw, 300px); margin-top: clamp(72px, 22.5vw, 88px); }

  /* ---- feature blocks (heading -> phone + props -> subline) ---- */
  .xm-feat {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: clamp(44px, 12vw, 96px) 24px 0;
  }
  .xm-stage {
    position: relative;
    width: 100%;
    max-width: 27rem;
    margin-top: clamp(22px, 6vw, 42px);
    display: flex;
    justify-content: center;
  }
  .xm-stage .xm-phone { --phw: min(56vw, 226px); }
  .xm-props {
    position: absolute;
    inset: 0;
    --ring-spread: 1;
    --ring-spread-front: 1;
    pointer-events: none;
    z-index: 5; /* props (popcorn etc.) read IN FRONT of the popped sheet */
  }

  /* ---- mobile phone frame (mirror of .xphone, sized per context) ---- */
  .xm-phone {
    position: relative;
    z-index: 2;
    width: var(--phw);
    aspect-ratio: 343 / 744;
    background: #000;
    border-radius: 17% / 7.84%;
    padding: calc(var(--phw) * 0.033);
  }
  .xm .xscreen { opacity: 1; } /* static stack: every screen is shown */

  /* win-it-back sheet: shown, popped over the lower phone, a touch wider. */
  .xm .xtray {
    opacity: 1;
    bottom: 8%;
    width: calc(var(--phw) * 1.134); /* ~5% larger than prior 1.08× sheet */
    box-shadow: 0 14px 36px -14px rgba(0, 0, 0, 0.28);
  }
  /* sports swipe card: shown at its rest tilt. */
  .xm .xpick { opacity: 1; }
}

/* ===================================================================
   EXPLORE — small phones (<= 640px): tighten the vertical stack.
   =================================================================== */
@media (max-width: 640px) {
  .x-explore.is-scrub {
    --phw-hero: min(80vw, 290px);
    --phw-feat: min(62vw, 220px);
  }
  .xm-hero { padding-top: 4px; }
  .xm-phone--hero { --phw: min(80vw, 290px); }
  .xm-stage .xm-phone { --phw: min(62vw, 220px); }
  .xm-feat { padding-top: clamp(40px, 13vw, 72px); }
}

/* ===================================================================
   EXPLORE — reduced motion: keep the readable fallback, kill animation.
   =================================================================== */
@media (prefers-reduced-motion: reduce) {
  .xic__img { animation: none !important; }
}

/* ===================================================================
   EXPLORE — "We Got Your Back" + reviews (normal flow, below the scrub)
   =================================================================== */
/* Paint an opaque yellow (and fold the section gap into padding rather than a
   transparent margin). The root background flips yellow->white by scroll near
   the footer (refreshThemeColor, for the iOS overscroll tint); a transparent
   section would reveal that white. The footer solves the same problem with a
   yellow border-top — these sections do it with their own background. */
.wgyb {
  padding-top: var(--section-gap);
  background: var(--yellow);
}
/* During the scrub (DESKTOP ONLY), tuck WGYB one viewport higher so it can rise
   in as the sports stage lifts off — fills the yellow void at the tail. On
   mobile/tablet WGYB stays in normal flow: the pinned stage simply scrolls away
   to reveal it (the -120svh tuck used to leak WGYB into the pinned phone). */
@media (min-width: 1025px) {
  body:has(.x-explore.is-scrub) .wgyb {
    position: relative;
    z-index: 3;
    margin-top: calc(-120svh + clamp(2rem, 5vh, 3.5rem));
    padding-top: clamp(0.75rem, 1.5vw, 1.25rem);
    will-change: transform;
  }
}
/* Matches the shared homepage .section-title (it carries that class); only the
   section's own bottom spacing lives here. */
.wgyb__title {
  margin: 0 0 clamp(1.75rem, 3vw, 2.75rem);
}
.wgyb__cards {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: clamp(1.25rem, 2.4vw, 2.75rem);
  max-width: 68.125rem;
  margin-inline: auto;
}
.wgyb-card {
  position: relative;
  display: block;
  aspect-ratio: 523 / 468;
  border-radius: 2.5rem;
  overflow: hidden;
  background: var(--yellow-card);
  text-decoration: none;
  color: inherit;
}
a.wgyb-card:focus-visible {
  outline: 2px solid var(--black);
  outline-offset: 4px;
}
.wgyb-card__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.wgyb-card__img--answers { object-position: center 28%; }
.wgyb-card::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(0, 0, 0, 0) 40%, rgba(0, 0, 0, 0.6) 100%);
}
.wgyb-card__body {
  position: absolute;
  left: clamp(1.5rem, 2.6vw, 2.375rem);
  right: clamp(1.5rem, 2.6vw, 2.375rem);
  bottom: clamp(1.75rem, 2.6vw, 2.5rem);
  z-index: 2;
  color: var(--white);
}
.wgyb-card__icon {
  display: block;
  width: 1.875rem;
  height: 1.875rem;
  margin-bottom: 1.125rem;
  color: var(--white);
}
.wgyb-card__label {
  margin: 0;
  max-width: 20rem;
  color: var(--white);
  font-size: clamp(28px, 1.6vw + 16px, 40px);
  font-weight: 700;
  line-height: 1.05;
  letter-spacing: -0.01em;
}

.wgyb__cta { margin-top: clamp(3rem, 5vw, 4.5rem); text-align: center; }
.wgyb__lead {
  margin: 0 auto;
  max-width: 33rem;
  font-size: clamp(1.25rem, 0.6vw + 1.05rem, 1.625rem);
  font-weight: 700;
  letter-spacing: -0.01em;
}
.wgyb__btn { display: inline-flex; margin-top: 1.5rem; height: 4rem; }
.wgyb__btn .btn__icon { filter: invert(1); }
.wgyb__rating {
  margin: 1.5rem 0 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  font-size: 1.0625rem;
  font-weight: 600;
}
.wgyb__stars { color: #111; letter-spacing: 0.08em; }
.wgyb__dot { color: var(--ink-40); }

/* ---------- Reviews marquee ---------- */
.reviews {
  padding-top: var(--section-gap);
  overflow: hidden;
  background: var(--yellow); /* opaque so it never reveals the white root near the footer */
}
.reviews__viewport {
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
  /* Click-and-drag to scrub the strip (JS drives a transform marquee + drag on
     pointer devices; touch uses native scrolling). */
  cursor: grab;
}
.reviews__viewport.is-grabbing { cursor: grabbing; user-select: none; }
.reviews__track {
  display: flex;
  width: max-content;
  margin: 0;
  padding: 0;
  list-style: none;
  /* CSS marquee is the no-JS fallback; script.js sets animation:none and drives
     the motion via transform so it can also be dragged. */
  animation: reviewsScroll 46s linear infinite;
  will-change: transform;
}
.reviews:hover .reviews__track,
.reviews:focus-within .reviews__track { animation-play-state: paused; }
@keyframes reviewsScroll {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}
.review {
  flex: 0 0 auto;
  width: clamp(17rem, 24vw, 23.75rem);
  margin-right: 1.5rem;
  padding: 1.75rem 2rem;
  border-radius: 1.5rem;
  /* Outlined, not white-filled: a thin dark border on the yellow band. */
  background: transparent;
  border: 1.5px solid rgba(17, 17, 17, 0.12);
}
.review__stars { color: #00aeff; font-size: 1.1rem; letter-spacing: 0.12em; }
.review__text {
  margin: 0.9rem 0 0;
  font-size: 1.25rem;
  font-weight: 600;
  line-height: 1.32;
  letter-spacing: -0.01em;
}
.review__name {
  margin: 1.1rem 0 0;
  display: flex;
  align-items: center;
  gap: 0.5em;
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--ink-50);
}
/* Store glyph by the author (Apple by default; Google Play for Play-store reviews). */
.review__name::before {
  content: "";
  flex: 0 0 auto;
  width: 1.05em;
  height: 1.05em;
  background: url(assets/icon-getapp.svg) center / contain no-repeat;
}
.review--play .review__name::before { background-image: url(assets/icon-playstore.svg); }

/* Pagination dots for the mobile reviews carousel (hidden on desktop, where the
   reviews auto-scroll as a marquee instead). */
.reviews__dots {
  display: none;
  justify-content: center;
  gap: 8px;
  margin-top: 1.75rem;
}
.reviews__dot {
  width: 8px;
  height: 8px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: rgba(17, 17, 17, 0.22);
  cursor: pointer;
  transition: width 0.25s ease, background 0.25s ease, border-radius 0.25s ease;
}
.reviews__dot.is-active { width: 20px; border-radius: 4px; background: #111; }

@media (max-width: 1024px) {
  .wgyb-card__label { font-size: clamp(24px, 3vw + 12px, 34px); }
}
@media (max-width: 640px) {
  .wgyb__cards { grid-template-columns: 1fr; max-width: 26rem; }
  .wgyb-card { aspect-ratio: 343 / 300; }

  /* Reviews become a swipeable single-card carousel (matching the Figma mobile
     design): an outlined card on yellow, blue stars, an Apple glyph by the
     author, and pagination dots below. The marquee animation is switched off and
     the same track becomes a horizontal scroll-snap strip. */
  .reviews__viewport {
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
    cursor: auto; /* mobile uses native touch scrolling, not pointer-drag */
  }
  .reviews__viewport::-webkit-scrollbar { display: none; }
  .reviews__track {
    animation: none;
    width: auto;
    padding-inline: 11vw;
  }
  .review[aria-hidden] { display: none; } /* carousel shows the real set once */
  .review {
    flex: 0 0 78vw;
    width: auto;
    max-width: 21rem;
    margin-right: 14px;
    padding: 1.75rem;
    scroll-snap-align: center;
    background: transparent;
    border: 1.5px solid rgba(17, 17, 17, 0.12);
  }
  .review__stars { color: #00aeff; font-size: 1.25rem; letter-spacing: 0.14em; }
  .review__text { font-size: 1.25rem; }
  .review__name { display: flex; align-items: center; gap: 0.5em; }
  .review__name::before {
    content: "";
    flex: 0 0 auto;
    width: 1.1em;
    height: 1.1em;
    background: url(assets/icon-getapp.svg) center / contain no-repeat;
  }

  .reviews__dots { display: flex; }
}
@media (prefers-reduced-motion: reduce) {
  .reviews__track { animation: none; }
  .reviews__viewport {
    overflow-x: auto;
    -webkit-mask-image: none;
    mask-image: none;
  }
}

/* ===================================================================
   NATIVE-SCROLL SCENES  —  the "butter" path (phone + portrait tablet)
   ===================================================================
   On iOS, momentum scroll is composited on a SEPARATE thread. Anything that pins
   a stage to the viewport and drives it from a main-thread rAF reading scrollY is
   always a frame+ behind that thread — it "chases" the finger (jitter) and gets
   dragged around when the address bar shows/hides (the shake). Desktop has no
   separate momentum thread, so its pinned scrub is flawless; a phone cannot be.

   So below 1025px we DON'T pin anything. JS skips the scrub entirely and the
   native-flow .xm stack scrolls 1:1 with the finger — pure native momentum, the
   smoothest thing iOS can do. On top of that native scroll we add:
     1. gentle proximity scroll-snap so each scene settles;
     2. a one-shot fade-in for the copy + props as each scene enters (.is-in,
        toggled once by an IntersectionObserver);
     3. the "website-style" bit — a CONTINUOUS scroll-driven scale/rise on the
        PHONE as its scene passes through the viewport. This uses
        `animation-timeline: view()`, so the browser ties it to scroll ON THE
        COMPOSITOR THREAD (same thread as the momentum scroll) — it tracks the
        finger with zero main-thread work, which is the only way to get that
        continuous morph smooth on iOS. Copy + props stay simple fades so there's
        little to go wrong. Everything is scoped to html.x-native, which the JS
        sets only when the pinned scrub is NOT running. */
html.x-native {
  scroll-snap-type: y proximity;
}
@media (max-width: 1024px) {
  /* Each scene is a full screen and a snap point; below the last one the page
     (We Got Your Back, reviews, footer) scrolls freely (no snap-align). */
  .x-native .xm-hero,
  .x-native .xm-feat {
    min-height: 100svh;
    justify-content: center;
    scroll-snap-align: start;
  }

  /* ---- Copy + props: one-shot fade (+ small rise for text) on enter. ---- */
  .x-native .xm-title,
  .x-native .xm-sub,
  .x-native .xm-cta,
  .x-native .xm-props,
  .x-native .xm-floats {
    opacity: 0;
    transition: opacity 0.55s ease, transform 0.6s cubic-bezier(0.22, 1, 0.36, 1);
  }
  .x-native .xm-title,
  .x-native .xm-sub,
  .x-native .xm-cta { transform: translateY(22px); }
  .x-native .is-in .xm-title,
  .x-native .is-in .xm-sub,
  .x-native .is-in .xm-cta,
  .x-native .is-in .xm-props,
  .x-native .is-in .xm-floats {
    opacity: 1;
    transform: none;
  }
  /* Slight stagger so the scene assembles rather than popping all at once. */
  .x-native .is-in .xm-sub { transition-delay: 0.10s; }
  .x-native .is-in .xm-cta { transition-delay: 0.16s; }

  /* ---- Phone + props: continuous scroll-driven motion (the morph). ---- */
  @supports (animation-timeline: view()) {
    .x-native .xm-phone {
      animation: xm-phone-scrub linear both;
      animation-timeline: view();
      /* Start the morph as the phone enters from the bottom; finish it a little
         past the viewport centre so it's settled at rest while the scene is read.
         It then holds (no exit shrink) and the next scene's phone takes over. */
      animation-range: entry 6% cover 52%;
      transform-origin: center bottom;
      will-change: transform;
    }
    /* The hero phone travels a touch further (bigger lead-in) to echo the
       desktop hero → feature "settle" without a pinned single phone. */
    .x-native .xm-phone--hero { animation-range: entry 10% cover 56%; }

    /* Each prop/icon eases in along its OWN outward radius (derived from its
       --cx/--cy) as the scene scrolls up — a gentle gather around the phone, not
       a fade. The outer .xic centres itself with the `translate` property and the
       inner img owns the idle bob, so this `transform` animation composes cleanly
       with both. Kept modest + on ONE uniform range so they move together (no
       per-prop rate differences) and SETTLE before the scene is centred — so
       they're at rest while you read it, never drifting under the copy. */
    .x-native .xm-props .xic,
    .x-native .xm-floats .xic {
      animation: xm-prop-in linear both;
      animation-timeline: view();
      animation-range: entry 12% cover 46%;
      will-change: transform;
    }
  }
}
@keyframes xm-phone-scrub {
  from { transform: translateY(54px) scale(0.86); }
  to   { transform: translateY(0) scale(1); }
}
@keyframes xm-prop-in {
  from {
    transform: translate(calc((var(--cx) - 0.5) * 56px), calc((var(--cy) - 0.5) * 56px))
               scale(0.78) rotate(calc(var(--rot, 0deg) * 0.8));
  }
  to { transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  html.x-native { scroll-snap-type: none; }
  .x-native .xm-title,
  .x-native .xm-sub,
  .x-native .xm-cta,
  .x-native .xm-props,
  .x-native .xm-floats { opacity: 1; transform: none; transition: none; }
  .x-native .xm-phone { animation: none; transform: none; }
}
