/* ===================================================================
   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-16: rgba(0, 0, 0, 0.16);
  --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%;
}
html.is-menu-open { overflow: hidden; }
/* Freeze the page in place while the menu is open. Plain overflow:hidden on
   iOS Safari shrinks the layout viewport and leaves a white band above the
   floating toolbar; position:fixed keeps the hero pinned where it was.
   The Explore scrub page skips position:fixed — it breaks the sticky pin. */
body.is-menu-open {
  position: fixed;
  left: 0;
  right: 0;
  width: 100%;
  overflow: hidden;
}
html.is-menu-open .x-explore { pointer-events: none; }

/* 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. */
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: center;
  flex: none;
  flex-shrink: 0;
  height: 1rem;
  line-height: 1rem;
}
.btn__space {
  display: inline-block;
  height: 1rem;
  overflow: hidden;
}
.btn__roll {
  display: block;
  overflow: hidden;
  flex: none;
  flex-shrink: 0;
}
.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 one line of text; each stacked copy matches the line box so -50%
   lands on the duplicate. display:block keeps rolls from collapsing in flex btns. */
.btn .btn__roll { height: 1rem; margin-block: 0; }
.btn .btn__roll-item {
  display: block;
  height: 1rem;
  line-height: 1rem;
  white-space: nowrap;
}
/* Fixed-height 4rem pills: use a 2rem line box so labels read at full scale. */
.cashback__buttons .btn {
  padding-block: 1rem;
}
.cashback__buttons .btn .btn__wave,
.cashback__buttons .btn .btn__roll,
.cashback__buttons .btn .btn__roll-item,
.cashback__buttons .btn .btn__space {
  height: 2rem;
  line-height: 2rem;
}
.icon-btn .btn__roll,
.icon-btn .btn__roll-item { height: 2rem; }
/* 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-16); }
.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-16);
  background: var(--yellow);
}
.icon-btn img { width: auto; height: 1.125rem; }

/* ===================================================================
   HEADER / NAV
   =================================================================== */
/* In-flow yellow bar — same on every page (Support, Home, etc.). No overlay,
   blur, or border; the hero sits below this block, not behind it. */
.site-header {
  position: relative;
  z-index: 50;
  background: var(--yellow);
}
/* Explore's pinned scrub stage sits tight under the header; keep nav tappable. */
.page-explore .site-header { z-index: 60; }

.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%, calc(-50% - 2px));
}
.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;
  /* Cover the full visual viewport on iOS (inset:0 alone can leave a sliver
     above the floating toolbar when the page is scroll-locked). */
  min-height: 100vh;
  min-height: 100dvh;
  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.22s 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.32s 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.26s cubic-bezier(0.4, 0, 0.85, 0.55) 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: grid;
  grid-template-columns: 1.75rem 1fr 1.75rem;
  align-items: center;
  height: 6.125rem;
}
.menu-overlay__top .nav__logo {
  position: static;
  grid-column: 1 / -1;
  grid-row: 1;
  justify-self: center;
  transform: translateY(-2px);
}
.menu-overlay__close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  grid-column: 1;
  grid-row: 1;
  width: 1.75rem; height: 1.75rem;
  background: none; border: none; cursor: pointer; color: var(--black);
}
.menu-overlay__close svg {
  width: 1.75rem;
  height: 1.75rem;
}
.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; white-space: nowrap; }
.rating {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  margin-top: 1.625rem;
  color: var(--ink-40);
}
.rating__star { width: 1.125rem; height: 1.125rem; flex-shrink: 0; }
.rating__text { font-size: 1.125rem; font-weight: 500; letter-spacing: -0.04em; }
.rating__dot { margin: 0 0.5rem; }
.wgyb__cta .rating { margin-top: var(--wgyb-gap-stack); }

/* ===================================================================
   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;
}

/* Subtle image zoom on card hover — overflow:hidden on the card clips the scale. */
.feature-card__img,
.wgyb-card__img,
.press-card__bg {
  transition: transform 0.45s ease;
}
@media (hover: hover) {
  .feature-card:hover .feature-card__img,
  .wgyb-card:hover .wgyb-card__img,
  .wgyb-card:focus-visible .wgyb-card__img,
  .press-card:hover .press-card__bg,
  .press-card:focus-visible .press-card__bg {
    transform: scale(1.04);
  }
}

/* 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; }
.investors__list li:last-child { border-bottom: none; }
/* 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;
  object-fit: contain;
}
.investors__list li img[alt="a16z"] { height: 1.125rem; }

/* ---------- Press card ---------- */
.press-card {
  display: block;
  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;
  color: inherit;
  text-decoration: none;
}
.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: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  column-gap: clamp(3rem, 7vw, 7rem);
  width: min(100%, 42rem);
  margin-inline: auto;
}
.featured__logos img { width: auto; opacity: 0.9; }
.featured__logos img:nth-child(1) { justify-self: end; height: 1.625rem; }
.featured__logos img:nth-child(2) { justify-self: center; height: 2.375rem; }
.featured__logos img:nth-child(3) { justify-self: start; 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); }

@media (max-width: 640px) {
  .legal-hero { padding-top: clamp(24px, 8vw, 48px); }
  .legal-doc h2 { font-size: 1.25rem; }
}

   /* =================================================================
   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);
  /* Fluid top/bottom padding; bottom extends into the home-indicator /
     safe area. Scales smoothly from phone → desktop. */
  padding: clamp(3.5rem, 8vw, 7.125rem) 0
           calc(clamp(2.5rem, 4vw, 3.75rem) + env(safe-area-inset-bottom));
}

/* ---- ≥769px: logo · three balanced link columns · store pills ----
   Every measurement is fluid so the same layout holds from the 1440 desktop
   frame down to the 1024 tablet frame (and the gap to ~769) without breaking;
   below 769 it drops to the two-column layout further down. */
.footer__top {
  display: flex;
  align-items: flex-start;
  gap: 0;
}
.footer__logo { flex: 0 0 auto; }
.footer__logo img { width: clamp(3.25rem, 2rem + 2.8vw, 5rem); height: auto; }

/* Single ordered link list that CSS multi-column splits into 3 balanced
   columns (4 / 4 / 3), reading top-to-bottom then left-to-right.

   The nav GROWS to fill the space between the logo and the store buttons
   (`flex: 1`), so the three equal columns spread/span with the viewport at
   every width — they never bunch up. A `max-width` caps that growth on large
   desktops: past the cap the nav stops widening and `margin-left:auto` on the
   stores opens the airy gap before them seen in the design. Because each
   column is a third of the (wide) nav and the text is left-aligned, the empty
   right portion of the last column reads as that gap.

   The logo→columns offset is a fluid expression tuned to the design's measured
   spacing: logo→col1 ≈ 143px @1440 and ≈ 96px @1024; the resulting
   column-to-column spacing lands ≈ 296px @1440 and ≈ 205px @1024. */
.footer__nav {
  flex: 1 1 auto;
  min-width: 0;
  max-width: 56rem;
  margin-left: clamp(2rem, 11.3vw - 1.25rem, 12rem);
  column-count: 3;
  column-gap: clamp(1rem, 3vw, 1.5rem);
  column-fill: balance;
  font-size: clamp(0.9375rem, 0.85rem + 0.35vw, 1rem);
  font-weight: 500;
}
.footer__nav a {
  display: block;
  break-inside: avoid;
  white-space: nowrap;
  margin-bottom: clamp(1.125rem, 1rem + 0.35vw, 1.625rem);
}
.footer__nav a:hover { opacity: 0.6; }

/* White pills (icon centred, fluid left/right padding) like the header stores.
   `margin-left: auto` keeps them pinned to the right edge — and opens the gap
   before them once the nav hits its max-width on large desktops. */
.footer__stores { display: flex; flex: 0 0 auto; gap: 0.75rem; margin-left: auto; }
.footer__stores .icon-btn { background: var(--white); width: auto; padding-inline: clamp(1rem, 2.5vw, 1.5rem); }

.footer__divider {
  height: 1px;
  background: var(--ink-08);
  /* Fluid breathing room above the divider. */
  margin: clamp(3rem, 5vw, 5.5rem) 0 0;
}
.footer__wordmark { margin-top: clamp(2.5rem, 5vw, 5.5rem); }
.footer__wordmark img { width: 100%; height: auto; }
.footer__copy {
  /* Fluid gap between the wordmark and the ©2026 line. */
  margin: clamp(2.5rem, 7vw, 7.75rem) 0 0;
  text-align: center;
  font-size: clamp(0.875rem, 0.8rem + 0.25vw, 1rem);
  font-weight: 500;
  color: var(--ink-20);
}

/* ---- ≤640px: logo on its own row; links reflow into two columns (7 / 4)
   with the bare store glyphs tucked into the bottom-right of the empty space
   beneath the shorter second column. The spanning 3-column layout above fits
   down to ~641px, so this phone layout takes over at 640 (matching the site's
   global mobile breakpoint and the Figma mobile frame).

   Plain block flow (NOT grid): the logo sits on its own row, the link list
   reflows into two columns, and the store glyphs are absolutely positioned.
   This avoids putting a fixed-height multi-column element inside a grid track,
   which Safari/iOS sizes unreliably (it would collapse the columns). The nav
   is capped at `max-width` so on the wider two-column screens the columns stay
   grouped on the left, and the store glyphs are pinned to the RIGHT EDGE OF
   THE COLUMN BLOCK (via `left: min(<cap>, 100%)` + a -100% self-shift) rather
   than the far edge of the viewport — so they stay tucked under the shorter
   second column at every width, matching the design. */
@media (max-width: 640px) {
  .footer__top {
    --footer-nav-w: min(22rem, 100%);
    display: block;
    position: relative;
    padding-bottom: 0.375rem;
    overflow: visible;
  }

  .footer__logo { margin: 0 0 clamp(1.75rem, 5vw, 2.25rem); }
  .footer__logo img { width: clamp(3rem, 6vw, 4rem); height: auto; }

  /* Two columns (7 / 4) via column-first grid — no fixed height, so the
     block grows naturally and the store glyphs stay pinned to its bottom. */
  .footer__nav {
    display: grid;
    grid-template-columns: max-content max-content;
    grid-template-rows: repeat(7, auto);
    grid-auto-flow: column;
    align-content: start;
    column-count: unset;
    margin: 0;
    max-width: var(--footer-nav-w);
    height: auto;
    column-gap: clamp(1.25rem, 6vw, 3.5rem);
    row-gap: 0;
    font-size: clamp(1rem, 0.95rem + 0.35vw, 1.125rem);
    font-weight: 600;
  }
  .footer__nav a {
    width: auto;
    white-space: nowrap;
    margin-bottom: clamp(1.375rem, 3.5vw, 1.75rem);
  }

  /* Bare Play/Apple glyphs (no circle), ordered Play then Apple. Pinned to the
     bottom-right of the column block (right edge = min(nav cap, 100%)). */
  .footer__stores {
    position: absolute;
    bottom: 0.375rem;
    left: var(--footer-nav-w);
    transform: translateX(-100%);
    flex-direction: row-reverse;
    align-items: center;
    gap: clamp(1rem, 4vw, 1.25rem);
    overflow: visible;
  }
  .footer__stores .icon-btn {
    display: flex;
    width: auto;
    height: 1.625rem;
    border: none;
    border-radius: 0;
    background: transparent;
    padding: 0;
    overflow: visible;
    flex-shrink: 0;
  }
  .footer__stores .icon-btn img {
    display: block;
    height: 1.625rem;
    width: auto;
    max-width: none;
  }

  .footer__divider { margin-top: clamp(2.5rem, 4vw, 3.5rem); }
  .footer__wordmark { margin-top: clamp(2.5rem, 6vw, 3rem); }
  .footer__copy { text-align: center; }
}

/* ---- 641–1024px: three columns stay, but tighten logo→nav offset and store
   pill padding so the row stays full without crowding at the tablet frame. ---- */
@media (min-width: 641px) and (max-width: 1024px) {
  .footer__nav {
    margin-left: clamp(1.5rem, 6vw, 6rem);
    column-gap: clamp(0.875rem, 2vw, 1.25rem);
  }
  .footer__stores .icon-btn {
    padding-inline: clamp(0.875rem, 2vw, 1.25rem);
  }
}

/* ===================================================================
   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; }
.support-item__a a.nowrap { white-space: nowrap; }

/* ---- 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.
     Opacity is omitted — pairing it with grid rows jitters on mobile Safari.
     JS wraps copy in `.faq__a-inner` so this grid always has one child. */
  display: grid;
  grid-template-rows: 0fr;
  overflow: hidden;
  transition: grid-template-rows 0.36s cubic-bezier(0.4, 0, 0.2, 1);
}
.faq__a-inner {
  overflow: hidden;
  min-height: 0;
}
.faq.is-open .faq__a {
  grid-template-rows: 1fr;
}
.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);
}
/* Yellow breathing room between the reviews carousel and the white footer. */
body.page-explore .reviews { padding-bottom: 100px; }

/* ===================================================================
   COMPANY PAGE
   Hero video frame · Our Story · team grid with portrait cards.
   =================================================================== */
.company-hero {
  width: 100%;
  max-width: var(--container-max);
  margin-inline: auto;
  padding: 0 var(--hero-gap);
}
.company-hero__card {
  position: relative;
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  aspect-ratio: 1312 / 649;
  border-radius: clamp(28px, 3.8cqw, 50px);
  overflow: hidden;
  container-type: inline-size;
  background: transparent;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.company-hero__card:focus-visible {
  outline: 2px solid var(--black);
  outline-offset: 4px;
}
.company-hero__bg {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

.company-section { margin-top: clamp(88px, 10vw, 170px); }
.company-inner { max-width: 68.125rem; margin-inline: auto; }

.company-row {
  display: grid;
  grid-template-columns: 39fr 61fr;
  column-gap: 2rem;
  align-items: start;
  row-gap: 1.5rem;
}
.company-row__label {
  margin: 0;
  font-size: 2.5rem;
  font-weight: 700;
  letter-spacing: -0.019em;
  line-height: 1.2;
}

.company-story { min-width: 0; }
.company-story__lead {
  margin: 0 0 1.125rem;
  font-size: 1.25rem;
  font-weight: 900;
  line-height: 1.3;
}
.company-story__body p {
  margin: 0 0 1.25rem;
  font-size: 1.25rem;
  font-weight: 500;
  line-height: 1.4;
}
.company-story__body p:last-child { margin-bottom: 0; }

.company-team { margin-top: clamp(88px, 10vw, 144px); }
.company-team__title {
  margin: 0 0 clamp(48px, 6vw, 64px);
  font-size: 2.5rem;
  font-weight: 700;
  letter-spacing: -0.019em;
  line-height: 1.2;
}
.company-team__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(48px, 5vw, 72px) clamp(32px, 4vw, 48px);
}

.team-card { min-width: 0; }
.team-card__photo {
  display: block;
  aspect-ratio: 509 / 349;
  border-radius: 2.5rem;
  overflow: hidden;
}
.team-card__photo:focus-visible {
  outline: 2px solid var(--black);
  outline-offset: 4px;
}
.team-card__photo img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.45s ease;
}
@media (hover: hover) {
  .team-card__photo:hover img,
  .team-card__photo:focus-visible img {
    transform: scale(1.04);
  }
}
.team-card__info { margin-top: 1.5rem; }
.team-card__name {
  margin: 0;
  font-size: 2rem;
  font-weight: 700;
  line-height: 1.2;
}
.team-card__role {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 0.375rem;
  font-size: 1.25rem;
  font-weight: 500;
  line-height: 1.3;
}
.team-card__linkedin {
  flex-shrink: 0;
  display: inline-flex;
  border-radius: 4px;
  transition: opacity 0.2s ease;
}
.team-card__linkedin:hover { opacity: 0.65; }
.team-card__linkedin img { display: block; width: 1.25rem; height: 1.25rem; }
.team-card__bio {
  margin: 1.125rem 0 0;
  font-size: 1rem;
  font-weight: 500;
  line-height: 1.4;
}

.company {
  padding-bottom: clamp(88px, 10vw, 160px);
}
.company + .site-footer {
  border-top: 0;
  padding-top: clamp(3rem, 5vw, 4.5rem);
}

.video-modal {
  position: fixed;
  inset: 0;
  z-index: 150;
  display: grid;
  place-items: center;
  padding: clamp(1rem, 4vw, 2.5rem);
}
.video-modal[hidden] { display: none; }
.video-modal__backdrop {
  position: absolute;
  inset: 0;
  border: 0;
  padding: 0;
  background: rgba(0, 0, 0, 0.72);
  cursor: pointer;
}
.video-modal__dialog {
  position: relative;
  z-index: 1;
  width: min(72rem, 100%);
}
.video-modal__close {
  position: absolute;
  top: -3rem;
  right: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.625rem;
  height: 2.625rem;
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.45);
  color: var(--white);
  cursor: pointer;
}
.video-modal__close:hover { background: rgba(0, 0, 0, 0.65); }
.video-modal__player {
  display: block;
  width: 100%;
  max-height: calc(100vh - 6rem);
  border-radius: clamp(16px, 2vw, 24px);
  background: var(--black);
}

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

  /* Back to the plain gutter so the menu button + logo align with content. */
  .nav {
    display: grid;
    grid-template-columns: 1.75rem 1fr 1.75rem;
    align-items: center;
    padding-inline: var(--gutter);
  }
  .nav__menu-btn {
    display: flex;
    grid-column: 1;
    grid-row: 1;
    justify-self: start;
    position: relative;
    z-index: 2;
  }
  /* Logo spans the full nav row for layout; limit hit-testing to the mark itself
     so it doesn't steal taps from the menu button in column 1. */
  .nav__logo { pointer-events: none; }
  .nav__logo a { pointer-events: auto; }
  .nav__logo {
    position: static;
    grid-column: 1 / -1;
    grid-row: 1;
    justify-self: center;
    transform: translateY(-2px);
  }
  .nav__links { display: none; }
  /* Store buttons live in the dropdown menu on tablet/mobile, not the nav. */
  .nav__actions { display: none; }

  .featured__logos { column-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;
  }
  /* Slightly smaller titles so longer copy (e.g. "Earn up to 100x points") wraps cleanly. */
  .feature-card__title { font-size: 34px; line-height: 1.05; }
  .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; }

  .company-hero__card { aspect-ratio: 928 / 420; }
  .company-hero { padding-inline: 48px; }
  .company-row { grid-template-columns: 34fr 66fr; }
  .company-team__grid { gap: clamp(40px, 5vw, 64px) clamp(24px, 3vw, 48px); }
}

/* ===================================================================
   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; }
  /* iOS Safari's floating toolbar sits over the page; lvh reaches behind it. */
  .is-ios-safari .menu-overlay { min-height: 100lvh; }

  /* 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; }

  /* 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.
     Shrink-wrap to the wider label — same height/padding as desktop, no stretch. */
  .cashback__buttons {
    flex-direction: column-reverse;
    align-items: stretch;
    width: max-content;
    max-width: 100%;
    gap: 1.125rem;
    margin-top: 1.5rem;
  }
  .cashback__buttons .btn { flex: none; }
  .cashback .rating { margin-top: 1.625rem; }
  .rating__text { font-size: 0.8125rem; }

  /* Card titles on small phones — keep in step with the carousel sizing above. */
  .feature-card__title { font-size: 2.125rem; line-height: 1.05; }

  .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 { column-gap: 2.25rem; width: 100%; }
  .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; }

  .support {
    padding-bottom: clamp(88px, 14vw, 160px);
  }
  .support + .site-footer {
    padding-top: 3.5rem;
  }
  /* Footer layout/spacing is handled by the dedicated ≤768px breakpoint near
     the FOOTER rules above; no footer overrides needed here. */

  /* ---- 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; }

  /* ---- Company page (mobile) ---- */
  .company-hero { padding: 0 var(--hero-gap); }
  .company-hero__card { aspect-ratio: 385 / 390; border-radius: 32px; }

  .company-section { margin-top: clamp(56px, 18vw, 88px); }
  .company-team { margin-top: clamp(72px, 22vw, 100px); }
  .company-row { grid-template-columns: 1fr; row-gap: 2.5rem; }
  .company-row__label,
  .company-team__title { font-size: 2rem; }
  .company-team__title { margin-bottom: clamp(40px, 12vw, 56px); }
  .company-team__grid { grid-template-columns: 1fr; gap: clamp(56px, 16vw, 76px); }
  .team-card__photo { aspect-ratio: 346 / 260; border-radius: 1.75rem; }
  .team-card__name { font-size: 1.75rem; }
  .team-card__role { font-size: 1.25rem; }
  .company-story__lead { font-size: 1.25rem; }
  .company-story__body p { font-size: 1rem; }

  .video-modal__close {
    top: -2.75rem;
    right: 0.25rem;
  }
}

/* ============ 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; }
  .feature-card__img,
  .wgyb-card__img,
  .press-card__bg { transition: none; }
  /* Native explore merged intro: snap the hero->Uber handoff, no eased motion. */
  .x-native .xm-intro .xm-copy,
  .x-native .xm-intro .xtray,
  .x-native .xm-intro .xscrim,
  .x-native .xm-intro .xm-floats,
  .x-native .xm-intro .xm-props--intro,
  .x-native .xm-intro .xm-phone--intro { transition: 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,
.xm-phone {
  /* ~48px corners at the 343px-wide design phone; scales with --phw. */
  --xscreen-r: calc(var(--phw) * 0.14);
}
.xphone {
  position: relative;
  z-index: 2;
  width: var(--phw);
  aspect-ratio: 343 / 744;
  background: #000;
  border-radius: 17% / 7.84%;
  overflow: visible;
  /* Promote the phone shell (not the whole xslide) so scroll-driven motion stays
     on the compositor without resampling the screen bitmap like xslide will-change. */
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
  /* 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 {
  /* Inset from --phw (not %) so the screen keeps the bezel ratio even when the
     phone is a flex child — a %-based fill was collapsing/stretching on mobile
     hero when the column ran taller than 100svh and flex-shrink squashed the
     phone's height while its width stayed fixed. */
  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);
  border-radius: var(--xscreen-r);
  overflow: hidden;
  isolation: isolate;
  /* clip-path survives ancestor transforms better than border-radius alone. */
  clip-path: inset(0 round var(--xscreen-r));
  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: var(--xscreen-r);
  clip-path: inset(0 round var(--xscreen-r));
  overflow: hidden;
  background: #000;
  opacity: 0;
  pointer-events: none;
}
.xscreen {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  overflow: hidden;
}
.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 viewport (card + "My Purchases" + 8 rows) sits between
   the fixed status bar and tab bar. JS translates the inner image UP on F3 so
   the card scrolls away and the list fills the screen, then the win-it-back
   sheet rises. Chrome heights are locked to the phone1.png slice fractions so
   they never drift from intrinsic image rounding as the list scrolls. */
.xscreen--purch {
  --purch-status: calc(301 / 4096 * 100%);
  --purch-tab: calc(382 / 4096 * 100%);
}
.xpurch__scroll {
  position: absolute;
  top: var(--purch-status);
  bottom: var(--purch-tab);
  left: 0;
  width: 100%;
  overflow: hidden;
}
.xpurch__scroll img {
  display: block;
  width: 100%;
  height: auto;
  will-change: transform;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
}
.xpurch__chrome {
  position: absolute;
  left: 0;
  width: 100%;
  display: block;
  z-index: 2;
  pointer-events: none;
  object-fit: fill;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
}
.xpurch__chrome--top { top: 0; height: var(--purch-status); }
.xpurch__chrome--bot { bottom: 0; height: var(--purch-tab); }

/* ---------- 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 ----------
   Soft burst from a single origin on the PS5 — scoped to the phone screen,
   faded in by the scrub. Each piece carries --scale depth so near/far reads
   with size; pieces launch from centre and fan out, not rain down. */
.xphone > .xconfetti,
.xm-phone > .xconfetti {
  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: 6;
  overflow: visible;
  pointer-events: none;
  opacity: 0;
}
.xconfetti--mobile {
  opacity: 1;
}
.xconfetti--mobile.is-on .xconfetti__piece,
.xconfetti--mobile .xconfetti__piece {
  animation-play-state: running;
}
.xconfetti__piece {
  position: absolute;
  top: 30%;
  left: 50%;
  width: var(--w);
  height: var(--h);
  background: var(--c);
  border-radius: var(--r);
  box-shadow: 0 1px 2px rgba(0, 0, 0, calc(var(--scale, 1) * 0.16));
  filter: saturate(1.18);
  opacity: 0;
  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(calc(var(--scale, 1) * 0.2)) rotate(0deg);
    opacity: 0;
    animation-timing-function: cubic-bezier(0.08, 0.88, 0.18, 1);
  }
  8% { opacity: calc(var(--peak, 0.7) * 1); }
  32% {
    transform: translate3d(calc(-50% + var(--bx) * 0.82), calc(-50% + var(--by)), 0)
      scale(var(--scale, 1)) rotate(calc(var(--spin) * 0.38));
    animation-timing-function: cubic-bezier(0.5, 0, 0.85, 0.4);
  }
  72% { opacity: calc(var(--peak, 0.7) * 0.9); }
  100% {
    transform: translate3d(calc(-50% + var(--bx)), calc(-50% + var(--fy)), 0)
      scale(calc(var(--scale, 1) * 0.88)) rotate(calc(var(--spin) * 0.72));
    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; }

/* ---------- Lifestyle prize zone (screen 3 overlay) ----------
   Sibling of .xphone__screens — same inset as .xpick-zone. All positions/sizes
   are plain % of the screen box (Figma phone 55 3, 307×666). No cqw — avoids
   fallback to intrinsic asset px when container queries misfire. */
.xprize-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: 5;
  overflow: visible;
  pointer-events: none;
  opacity: 0;
}
.xprize-zone img {
  display: block;
  max-width: none;
  position: absolute;
  height: auto;
}
.xprize__pad,
.xprize__avatars {
  opacity: 0;
  will-change: transform, opacity;
}
.xprize__ps5 {
  left: 50%;
  top: 22%;
  width: 83%;
  z-index: 3;
  transform: translate(-50%, 0);
}
.xprize__pad--back {
  left: calc(62% + 20px);
  top: 59.2%;
  width: 57.1%;
  z-index: 1;
  transform: translate(calc(-50% + var(--ptx, 0px)), var(--pty, 0px)) rotate(-16.6deg) scale(var(--psc, 1));
}
.xprize__pad--front {
  left: -22%;
  top: 60.6%;
  width: 80.9%;
  z-index: 5;
  transform: translate(var(--ptx, 0px), var(--pty, 0px)) rotate(10.4deg) scale(var(--psc, 1));
}
.xprize__logo {
  left: 10.1%;
  bottom: 13.5%;
  width: 12.1%;
  z-index: 4;
}
.xprize__avatars {
  left: 55.6%;
  bottom: 15.7%;
  width: 50.7%;
  z-index: 6;
  transform: translate(var(--ptx, 0px), var(--pty, 0px)) scale(var(--psc, 1));
}
@media (max-width: 1024px) {
  .x-native .xprize-zone,
  .xm .xprize-zone {
    opacity: 1;
  }
  .x-native .xprize-zone img,
  .xm .xprize-zone img {
    opacity: 1;
    --ptx: 0px;
    --pty: 0px;
    --psc: 1;
  }
  .x-native .xprize__ps5,
  .x-native .xprize__logo,
  .xm .xprize__ps5,
  .xm .xprize__logo {
    opacity: 1;
  }
}

/* ---------- 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;
  /* Match the baked corner radius in sports-card-*.png (~40px @ 518w). */
  border-radius: 7.7% / 6.1%;
  overflow: hidden;
  background: #0a0a0a;
  /* PNGs already carry the card edge — skip the extra white rim (it read as a
     mismatched "clear" corner against the photo). Shadow only, no border. */
  border: none;
  box-shadow: 0 3.5cqw 9cqw rgba(0, 0, 0, 0.32);
  transform-origin: 50% 120%;
  will-change: transform;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
}
/* 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;
  /* Bleed past the clip so baked-in white corner fringes from the PNG export
     don't peek through when the cards tilt. */
  transform: scale(1.06);
  transform-origin: 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; }
/* Hero icon fan-out is compositor-only during scrub: ring scale, not --ring-spread
   (which rewrites left/top every frame and shakes on iOS). */
.is-scrub { --ring-spread: 1; }
.is-scrub .xring:not(.xring--front) {
  transform-origin: center center;
}
/* 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; visibility: hidden; }
.is-scrub .xscreen.is-lit { visibility: visible; }

.is-scrub .xpanels {
  display: block;
  padding: 0;
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.is-scrub .xpanel {
  position: absolute;
  /* Slides via --pty; opacity is scroll-driven in JS (same band() as props/screens). */
  will-change: transform, opacity;
}
/* 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: 14vh;
}
.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: 1050svh; }
  .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;
  }

  /* Centre the phone like desktop — JS rises it from a low peek (not bottom-pinned). */
  .is-scrub .xslide {
    align-items: center;
    justify-content: center;
    backface-visibility: hidden;
    -webkit-backface-visibility: hidden;
  }

  .is-scrub .xphone {
    will-change: transform;
  }

  /* Hero icons frame the phone (same ring box as desktop), not a separate top band. */
  .is-scrub .xring:not(.xring--front) {
    top: 50%;
    left: 50%;
    width: calc(var(--phw) * 4.6);
    height: auto;
    aspect-ratio: 2502 / 1842;
    translate: -50% -50%;
  }

  @media (min-width: 641px) {
    .is-scrub .xring:not(.xring--front) {
      width: calc(var(--phw) * 4.6);
    }
  }

  /* SCRUB MECHANICS on mobile are identical to desktop: the global rules
     `.is-scrub .xpin { position: sticky; height: 100svh }` and the
     `.is-scrub .xtrack { height: 1050svh }` 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; }

  /* Float layer shared by the intro scene (positioned by .xm-intro rules). */
  .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-phone--hero { --phw: min(76vw, 300px); margin-top: 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;
    flex-shrink: 0; /* never squash the device in the hero/feature flex columns */
    width: var(--phw);
    aspect-ratio: 343 / 744;
    background: #000;
    border-radius: 17% / 7.84%;
    padding: calc(var(--phw) * 0.033);
    overflow: visible;
  }
  .xm .xprize-zone { opacity: 1; }
  .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; }

  /* ===== HERO + "Win it all back" — one shared phone, NATURAL scroll =====
     The purchases phone scrolls normally (NOT pinned). A view() timeline scrubs
     the handoff to the scene's own scroll position: the headline cross-fades
     "Play purchases back" -> "Win it all back", the phone's purchases LIST scrolls
     up, the "Win it Back" sheet rises onto it, a scrim dims it, and the hero icons
     swap to money/popcorn props — then it scrolls on to PS5. Everything is
     transform/opacity on the compositor, scrubbed by scroll (no per-frame JS, no
     pin). The hero state is held flat for the first ~46% of the timeline so the
     top-of-page load (where the scene's view progress already starts ~0.36) shows
     a clean hero, with no mid-animation flash. */
  .x-native .xm-intro {
    position: relative;
    /* Scroll length of the pinned, scrubbed handoff. The sticky stage consumes
       this scroll, so there's no dead gap after it. Long enough that the scene's
       view-progress at top-of-page load sits comfortably inside the hero-hold
       band, and the "Win it back" scrub reads as a deliberate assemble (not a
       flick-past). Tune alongside the xi-* keyframe bands. */
    min-height: 180svh;
  }
  /* The whole scene PINS for ~one screen so the phone + headline hold still while
     the hero animates out and the Uber state fades in, then it releases into PS5.
     Pinning the STAGE (not just the headline) is what stops the headline/phone
     overlap — nothing scrolls into anything else during the handoff. */
  .x-native .xm-intro__stage {
    position: sticky;
    top: 0;
    height: 100svh;
    overflow: clip;
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: clamp(36px, 11vw, 84px) 24px 0;
  }
  .x-native .xm-intro__head {
    position: relative;
    width: 100%;
    z-index: 6;
  }
  .x-native .xm-intro .xm-copy {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    pointer-events: none;
  }
  .x-native .xm-intro .xm-copy a { pointer-events: auto; }
  .x-native .xm-intro .xm-copy--uber {
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    padding: 0 24px;
  }
  .x-native .xm-intro .xm-copy--uber .xm-sub { margin-top: clamp(12px, 3.2vw, 20px); }

  /* The phone + its sub-copy are one group that tucks together so the sub stays
     BELOW the phone (like the other scenes). transform-origin top so it shrinks
     under the short headline. The TUCK is scroll-scrubbed (see @supports below). */
  .x-native .xm-intro__device {
    display: flex;
    flex-direction: column;
    align-items: center;
    width: 100%;
    margin-top: clamp(20px, 6vw, 44px);
    transform-origin: center top;
  }
  .x-native .xm-intro .xm-phone--intro {
    --phw: min(70vw, 264px);
    position: relative;
    z-index: 2;
    animation: none;                /* the shared phone scrubs via the device group */
  }
  .x-native .xm-intro .xm-sub--uber {
    margin-top: clamp(14px, 4vw, 24px);
    text-align: center;
    opacity: 0;                     /* revealed by the scrub */
  }
  /* hero floats + uber props pinned to the first screen, behind/around the phone */
  .x-native .xm-intro .xm-floats,
  .x-native .xm-intro .xm-props--intro {
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    height: 100svh;
    --ring-spread: 1;
    --ring-spread-front: 1;
    pointer-events: none;
  }
  .x-native .xm-intro .xm-floats { z-index: 0; }
  .x-native .xm-intro .xm-props--intro { z-index: 5; opacity: 0; } /* popcorn in front of sheet */
  .x-native .xm-intro .xic { animation: none; }
  /* Hero icons rise in once on load (one-shot entrance; the scrub slides the whole
     float layer away on scroll). */
  .x-native .xm-intro .xm-floats .xic {
    animation: xm-float-rise 0.8s var(--x-ease) both;
  }
  .x-native .xm-intro .xm-floats .xic:nth-child(3n + 2) { animation-delay: 0.06s; }
  .x-native .xm-intro .xm-floats .xic:nth-child(3n + 3) { animation-delay: 0.12s; }

  /* DEFAULT (no view() support) = hero only; the Uber assets stay hidden. */
  .x-native .xm-intro .xm-copy--uber { opacity: 0; }
  .x-native .xm-intro .xscrim { opacity: 0; }
  .x-native .xm .xm-intro .xtray {
    opacity: 0;
    bottom: 12%;
    width: calc(var(--phw) * 1.04);
    box-shadow: 0 16px 40px -14px rgba(0, 0, 0, 0.32);
  }

  /* ---- The hero -> "Win it back" handoff, SCROLL-SCRUBBED to this pinned scene's
     own view progress (same engine as every other scene). Bidirectional by
     construction — scroll up runs it backward — so there's no stateful desync on
     a scroll-up-then-down. Held flat early so the above-the-fold load is a clean
     hero. Tune the cross-over band in the xi-* keyframes. ---- */
  @supports (animation-timeline: view()) {
    .x-native .xm-intro { view-timeline: --xintro block; }
    .x-native .xm-intro .xm-copy--hero,
    .x-native .xm-intro .xm-copy--uber,
    .x-native .xm-intro .xm-floats,
    .x-native .xm-intro__device,
    .x-native .xm-intro .xm-props--intro,
    .x-native .xm-intro .xscrim,
    .x-native .xm .xm-intro .xtray,
    .x-native .xm-intro .xm-sub--uber,
    .x-native .xm-intro .xpurch__scroll img {
      animation-timeline: --xintro;
      animation-range: cover 0% cover 100%;
      animation-fill-mode: both;
    }
    .x-native .xm-intro .xm-copy--hero      { animation-name: xi-hero-out; }
    .x-native .xm-intro .xm-copy--uber      { animation-name: xi-uber-in; }
    .x-native .xm-intro .xm-floats          { animation-name: xi-floats-up; }
    .x-native .xm-intro__device             { animation-name: xi-device-tuck; }
    .x-native .xm-intro .xm-props--intro    { animation-name: xi-fade-in; }
    .x-native .xm-intro .xscrim             { animation-name: xi-scrim-in; }
    .x-native .xm .xm-intro .xtray          { animation-name: xi-fade-in; }
    .x-native .xm-intro .xm-sub--uber       { animation-name: xi-fade-in; }
    .x-native .xm-intro .xpurch__scroll img { animation-name: xi-list-scroll; }
  }
}

/* Intro handoff keyframes — % is this scene's view() progress. Held flat through
   the first ~46% so the top-of-page load lands on a clean hero. */
@keyframes xi-hero-out {
  0%, 46%   { opacity: 1; transform: translateY(0); }
  60%, 100% { opacity: 0; transform: translateY(-30px); }
}
@keyframes xi-uber-in {
  0%, 50%   { opacity: 0; transform: translateY(12px); }
  64%, 100% { opacity: 1; transform: translateY(0); }
}
@keyframes xi-floats-up {
  0%, 44%   { transform: translateY(0); }
  62%, 100% { transform: translateY(-92svh); }
}
@keyframes xi-device-tuck {
  0%, 48%   { transform: translateY(0) scale(1); }
  64%, 100% { transform: translateY(clamp(-320px, -72vw, -240px)) scale(0.78); }
}
@keyframes xi-fade-in {
  0%, 52%   { opacity: 0; }
  66%, 100% { opacity: 1; }
}
@keyframes xi-scrim-in {
  0%, 50%   { opacity: 0; }
  64%, 100% { opacity: 0.42; }
}
@keyframes xi-list-scroll {
  0%, 46%   { transform: translateY(0); }
  100%      { transform: translateY(-22%); }
}

@keyframes xm-float-rise {
  from { transform: translateY(46px); }
  to   { transform: translateY(0); }
}

/* ===================================================================
   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-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; }
  .x-native .xm-intro .xm-floats .xic { 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: calc(var(--section-gap) - 128px);
  padding-bottom: clamp(4.5rem, 6vw, 5.5rem);
  background: var(--yellow);
  --wgyb-gap-title: clamp(2rem, 3vw, 3rem);
  --wgyb-gap-cta: clamp(3rem, 4.5vw, 4.5rem);
  --wgyb-gap-stack: 1.25rem;
  --wgyb-gap-cards: 1.25rem;
}
/* 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) - 128px);
    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 var(--wgyb-gap-title);
}
.wgyb__cards {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--wgyb-gap-cards);
  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: var(--wgyb-gap-cta); text-align: center; }
.wgyb__lead {
  margin: 0 auto;
  max-width: none;
  font-size: 20px;
  font-weight: 700;
  letter-spacing: -0.01em;
}
@media (min-width: 641px) {
  .wgyb__lead { white-space: nowrap; }
}
.wgyb__btn { display: inline-flex; margin-top: var(--wgyb-gap-stack); height: 4rem; }
.wgyb__btn .btn__icon { filter: invert(1); }

/* ---------- Reviews marquee ---------- */
.reviews {
  padding-top: 0;
  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) {
  body.page-explore .wgyb {
    margin-top: 160px;
  }
  .wgyb-card__label { font-size: clamp(24px, 3vw + 12px, 34px); }
}
@media (max-width: 640px) {
  .wgyb {
    --wgyb-gap-title: 2rem;
    --wgyb-gap-cta: 2.75rem;
    --wgyb-gap-stack: 1rem;
    --wgyb-gap-cards: 1rem;
    padding-bottom: 4rem;
  }
  .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 {
  /* Gentle proximity snap — scenes settle softly but never grab the scroll
     (low friction); mandatory snap felt sticky, none felt loose. */
  scroll-snap-type: y proximity;
  scroll-padding-top: var(--header-h);

  /* ===== EXPLORE MOBILE — ONE SYSTEM (tokens) =====
     Every scene shares these so spacing/motion/timing are identical. All motion
     is SCROLL-SCRUBBED (animation-timeline) — a pure function of scroll position,
     so it's bidirectional by construction (scroll up = the animation in reverse).
     There is no triggered state to desync on a scroll-up-then-down. Tune here. */
  --x-ease: cubic-bezier(0.33, 1, 0.68, 1);
  --x-rise: 26px;                              /* content rise-in distance */
  --x-reveal: entry 8% cover 42%;              /* shared content-reveal scrub band */
  --x-reveal-late: entry 16% cover 50%;        /* sub-copy, a beat later */
}
/* The shared reveal every scene's copy/props ride (fade + rise, scrubbed). */
@keyframes xm-reveal {
  from { opacity: 0; transform: translateY(var(--x-rise)); }
  to   { opacity: 1; transform: translateY(0); }
}
@media (max-width: 1024px) {
  .x-native .xm-feat {
    min-height: 100svh;
    justify-content: center;
    scroll-snap-align: start;
  }

  /* ---- Copy reveal: SCROLL-SCRUBBED (bidirectional), same band as every scene.
     Base opacity:1 is the no-view() fallback (content just shows). ---- */
  @supports (animation-timeline: view()) {
    .x-native .xm-feat .xm-title,
    .x-native .xm-feat .xm-sub {
      animation: xm-reveal linear both;
      animation-timeline: view();
      animation-range: var(--x-reveal);
    }
    .x-native .xm-feat .xm-sub { animation-range: var(--x-reveal-late); }
  }

  /* Scene overlays (tray, PS5, pick card) — always visible in the static stack. */
  .x-native .xm .xscreen,
  .x-native .xm .xtray,
  .x-native .xm .xpick,
  .x-native .xm .xprize-zone,
  .x-native .xm .xprize-zone img {
    opacity: 1;
  }

  /* ---- Phone + props: scroll-driven motion on every scene. ---- */
  @supports (animation-timeline: view()) {
    .x-native .xm-phone {
      animation: xm-phone-scrub linear both;
      animation-timeline: view();
      animation-range: entry 6% cover 52%;
      transform-origin: center bottom;
      will-change: transform;
    }
    .x-native .xm-phone--hero {
      animation-name: xm-phone-hero-scrub;
      animation-range: entry 10% cover 56%;
      transform-origin: center top;
    }

    .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-phone-hero-scrub {
  from { transform: scale(0.92); }
  to   { transform: scale(1); }
}
@keyframes xm-prop-in {
  from {
    opacity: 0;
    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 { opacity: 1; 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; }
}

/* ===================================================================
   DESKTOP QA  (>= 1025px)
   =================================================================== */
@media (min-width: 1025px) {
  /* —— HOME: logo —— */
  .nav__logo img { width: 8.75rem; }

  /* Mission / community copy rhythm (cashback desc + explore caption). */
  .cashback__desc,
  .explore__caption {
    font-size: 1.125rem;
    line-height: 1.5;
  }

  /* Feature cards: 20px gap, full-bleed images, centred grid. */
  .explore__cards {
    gap: 20px;
    justify-content: center;
  }

  /* —— LEGAL: consistent type —— */
  .legal-doc,
  .legal-hero__title {
    font-family: var(--font);
  }

  /* —— EXPLORE: phone shadow, typography, card spacing —— */
  .is-scrub .xphone {
    box-shadow: 0 28px 80px -24px rgba(0, 0, 0, 0.45);
  }

  .is-scrub .xpanel--hero,
  .is-scrub .xpanel--left,
  .is-scrub .xpanel--right {
    text-align: center;
  }
  .is-scrub .xpanel--left,
  .is-scrub .xpanel--right {
    text-align: left;
  }

  .wgyb {
    --wgyb-gap-title: 3rem;
    --wgyb-gap-cta: 4.5rem;
    --wgyb-gap-stack: 1.25rem;
    --wgyb-gap-cards: 1.25rem;
    padding-bottom: 5.5rem;
  }

  .wgyb__cta { text-align: center; }

  .reviews__viewport {
    max-width: var(--container-max);
    margin-inline: auto;
  }

}
