/* ==========================================================================
   GoWorkout — goworkout.in

   Every token below is ported from the Flutter app rather than invented, so the
   site and the app cannot drift. Sources:

     mobile/lib/core/theme/app_theme.dart    colours, hero gradient, semantics
     mobile/lib/core/theme/spacing.dart      4pt scale + the radius rule
     mobile/lib/core/theme/text_theme.dart   type scale, tracking, stat numbers
     mobile/lib/core/theme/motion.dart       durations and curves

   Surface values were additionally sampled from real rendered pixels in the
   iOS simulator, because the M3 dark scheme is generated at runtime from the
   seed colour: the Dart source states the seed, not the resulting greys.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Typeface — the app's own file, converted to woff2. See assets/fonts/OFL.txt.
   -------------------------------------------------------------------------- */
@font-face {
  font-family: 'Jakarta';
  src: url('../fonts/PlusJakartaSans-Variable.woff2') format('woff2-variations');
  font-weight: 400 800;
  font-style: normal;
  font-display: swap;
}

/* --------------------------------------------------------------------------
   2. Tokens
   -------------------------------------------------------------------------- */
:root {
  /* Brand. Fixed in both app themes on purpose: a brand gradient should not
     invert with an OS setting. Both ends clear AA against white. */
  --brand: #2B4EE6;
  --brand-far: #3A63E8;
  --gradient-brand: linear-gradient(135deg, var(--brand) 0%, var(--brand-far) 100%);

  /* Dark surfaces, sampled from the running app. */
  --surface: #12131B;          /* page */
  --surface-card: #1E1F28;     /* cards, list rows */
  --surface-raised: #262733;   /* inputs, chips */
  --surface-high: #3C3D48;     /* progress tracks, locked states */

  --on-surface: #E6E0E9;       /* primary text */
  --on-surface-var: #C4C5D8;   /* secondary text */
  --on-surface-dim: #9394A8;   /* tertiary, captions */

  /* The M3 dark scheme resolves `primary` to a pale periwinkle. It is what the
     app paints filled buttons and links with, so the site does the same. */
  --primary: #BAC3FF;
  --on-primary: #00218D;

  /* Accents that carry meaning rather than brand. Warm for work being done,
     cool for the absence of it, gold for something earned. Dark-mode values. */
  --effort: #FF7847;
  --recovery: #4DD4C4;
  --gold: #E9A93C;
  --accent: #5B8DF6;

  --hairline: rgba(198, 197, 208, 0.14);
  --hairline-strong: rgba(198, 197, 208, 0.24);

  /* 4pt scale. Never hardcode a raw padding number. */
  --s-xs: 4px;
  --s-sm: 8px;
  --s-md: 16px;
  --s-lg: 24px;
  --s-xl: 32px;
  --s-xxl: 48px;

  /* Radius scales with the size of the thing it is applied to. This is a rule,
     not a palette to pick from. */
  --r-control: 12px;   /* buttons, inputs, small tappables */
  --r-card: 16px;      /* cards, list rows, containers */
  --r-hero: 24px;      /* large focal surfaces */
  --r-sheet: 28px;     /* panels that meet an edge */

  /* Motion, chosen by what the movement is for rather than by how big it looks. */
  --t-fast: 150ms;        /* a control acknowledging a touch */
  --t-normal: 250ms;      /* one piece of content replacing another */
  --t-emphasis: 350ms;    /* movement that carries meaning */
  --t-celebratory: 650ms; /* earned moments only */
  --ease: cubic-bezier(0.215, 0.61, 0.355, 1); /* easeOutCubic */

  --shell: 1200px;
  --shell-wide: 1360px;
  --gutter: var(--s-md);

  /* A hairline reads better than a shadow on flat surfaces, but a phone lifted
     off the page needs real depth. Tinted to the background hue, never black. */
  --lift: 0 32px 80px -24px rgba(6, 8, 24, 0.9), 0 4px 16px -6px rgba(6, 8, 24, 0.6);
  --lift-brand: 0 40px 90px -30px rgba(43, 78, 230, 0.55);

  color-scheme: dark;
}

@media (min-width: 768px) { :root { --gutter: var(--s-lg); } }
@media (min-width: 1280px) { :root { --gutter: var(--s-xl); } }

/* --------------------------------------------------------------------------
   3. Base
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 88px;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

body {
  margin: 0;
  background: var(--surface);
  color: var(--on-surface);
  font-family: 'Jakarta', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  font-size: 16px;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* `clip`, never `hidden`. `overflow-x: hidden` on body computes overflow-y to
     auto, which turns body into the scroll container and leaves the sticky nav
     pinned to the bottom of a scrollport that never scrolls. `clip` trims the
     same overflow without creating one. */
  overflow-x: clip;
}

img, svg, video { display: block; max-width: 100%; }
img { height: auto; }

/* Author styles beat the UA stylesheet regardless of specificity, so the rule
   above would otherwise un-hide `<svg hidden>` and render the icon sprite as a
   300x150 block at the top of every page. */
[hidden] { display: none !important; }

a { color: var(--primary); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 3px; }

button { font: inherit; color: inherit; }

:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 3px;
  border-radius: var(--s-xs);
}

::selection { background: var(--brand); color: #fff; }

.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

.skip-link {
  position: absolute; top: var(--s-sm); left: var(--s-sm);
  z-index: 200; padding: var(--s-sm) var(--s-md);
  background: var(--primary); color: var(--on-primary);
  border-radius: var(--r-control); font-weight: 600;
  transform: translateY(-200%);
}
.skip-link:focus { transform: translateY(0); text-decoration: none; }

/* --------------------------------------------------------------------------
   4. Type scale — Material 3, retuned for this face exactly as the app does.
      Display sizes get negative tracking; body gets 1.45+ line height.
   -------------------------------------------------------------------------- */
h1, h2, h3, h4 { margin: 0; text-wrap: balance; }
p { margin: 0; }

.display {
  font-size: clamp(2.25rem, 1.4rem + 3.6vw, 4rem);
  font-weight: 800;
  letter-spacing: -0.035em;
  line-height: 1.04;
}
.headline {
  font-size: clamp(1.75rem, 1.25rem + 2.1vw, 2.75rem);
  font-weight: 700;
  letter-spacing: -0.025em;
  line-height: 1.12;
}
.title {
  font-size: clamp(1.125rem, 1.05rem + 0.35vw, 1.3rem);
  font-weight: 700;
  letter-spacing: -0.012em;
  line-height: 1.28;
}
.body-lg {
  font-size: clamp(1.0625rem, 1rem + 0.3vw, 1.1875rem);
  color: var(--on-surface-var);
  line-height: 1.55;
}
.body { font-size: 1rem; color: var(--on-surface-var); line-height: 1.55; }
.body-sm { font-size: 0.875rem; color: var(--on-surface-var); line-height: 1.5; }
.measure { max-width: 62ch; }

/* The one place a number is the entire point of a widget and should look like
   it: tabular figures, tight tracking, no leading. Not part of the type scale. */
.stat-number {
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1;
}

/* The app's small-caps label. Rationed on this page: a label above every
   section is what makes a page read as a template. */
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--s-sm);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--on-surface-dim);
  margin: 0 0 var(--s-md);
}
.eyebrow .icon { color: var(--accent); }

/* --------------------------------------------------------------------------
   5. Layout
   -------------------------------------------------------------------------- */
.shell {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.shell-wide { max-width: var(--shell-wide); }

.section { padding-block: clamp(4rem, 2.5rem + 6vw, 8rem); }
.section-tight { padding-block: clamp(3rem, 2rem + 4vw, 5.5rem); }
.section-head { margin-bottom: clamp(2rem, 1.4rem + 2.4vw, 3.5rem); }
.section-head > p { margin-top: var(--s-md); }

.rule { border: 0; border-top: 1px solid var(--hairline); margin: 0; }

/* --------------------------------------------------------------------------
   6. Icons — Material Symbols Rounded, the same family the app renders.
   -------------------------------------------------------------------------- */
.icon {
  width: 1.25em; height: 1.25em;
  flex: none;
  fill: currentColor;
  display: inline-block;
  vertical-align: -0.28em;
}
.icon-sm { width: 1em; height: 1em; }

/* An icon on a soft tinted backdrop rather than bare on the surface. Ported
   from the app's IconBadge, including its radius ratio (size * 0.32). */
.icon-badge {
  --badge: 44px;
  --tint: var(--primary);
  width: var(--badge); height: var(--badge);
  border-radius: calc(var(--badge) * 0.32);
  display: grid; place-items: center;
  flex: none;
  background: color-mix(in srgb, var(--tint) 18%, transparent);
  color: var(--tint);
}
.icon-badge .icon { width: calc(var(--badge) * 0.5); height: calc(var(--badge) * 0.5); }
.icon-badge.is-gold { --tint: var(--gold); }
.icon-badge.is-effort { --tint: var(--effort); }
.icon-badge.is-recovery { --tint: var(--recovery); }
.icon-badge.is-accent { --tint: var(--accent); }

/* --------------------------------------------------------------------------
   7. Buttons — FilledButton / OutlinedButton at the app's own metrics:
      52px and 48px minimum heights, 12px radius, 600 weight.
   -------------------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-sm);
  min-height: 52px;
  padding: 0 var(--s-lg);
  border: 1px solid transparent;
  border-radius: var(--r-control);
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: -0.005em;
  white-space: nowrap;
  cursor: pointer;
  text-decoration: none;
  transition: background-color var(--t-fast) var(--ease),
              border-color var(--t-fast) var(--ease),
              transform var(--t-fast) var(--ease),
              box-shadow var(--t-fast) var(--ease);
}
.btn:hover { text-decoration: none; }
.btn:active { transform: translateY(1px); }

.btn-primary {
  background: var(--primary);
  color: var(--on-primary);
  box-shadow: 0 10px 30px -12px rgba(186, 195, 255, 0.5);
}
.btn-primary:hover { background: #CCD2FF; }

.btn-outline {
  background: transparent;
  color: var(--on-surface);
  border-color: var(--hairline-strong);
  min-height: 48px;
}
.btn-outline:hover { background: var(--surface-card); border-color: var(--on-surface-dim); }

/* On the brand gradient the ink is the seed blue, never the theme primary: the
   surface underneath does not move with the theme, so the label must not
   either. Measures 6.30:1 on white. */
.btn-on-brand { background: #fff; color: var(--brand); }
.btn-on-brand:hover { background: #EEF1FF; }

.btn-sm { min-height: 40px; padding: 0 var(--s-md); font-size: 0.9375rem; }

.btn-row { display: flex; flex-wrap: wrap; gap: var(--s-md); }
@media (max-width: 479px) { .btn-row .btn { width: 100%; } }

/* --------------------------------------------------------------------------
   8. Cards — flat, hairline-bordered. The app uses elevation 0 everywhere and
      a border instead of a shadow, because shadows are near invisible in dark.
   -------------------------------------------------------------------------- */
.card {
  background: var(--surface-card);
  border: 1px solid var(--hairline);
  border-radius: var(--r-card);
  padding: var(--s-lg);
}
.card-hero { border-radius: var(--r-hero); padding: clamp(var(--s-lg), 3vw, var(--s-xl)); }

.brand-panel {
  background: var(--gradient-brand);
  border-radius: var(--r-hero);
  border: 0;
  color: #fff;
}
.brand-panel p { color: rgba(255, 255, 255, 0.84); }

/* --------------------------------------------------------------------------
   9. Stat block — a number and what it means. Deliberately not a card: three
      of these separated by a hairline read as one comparable set; three cards
      read as three unrelated things that happen to be adjacent.
   -------------------------------------------------------------------------- */
.stat-row { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
.stat-row > * + * {
  border-left: 1px solid var(--hairline);
  padding-left: clamp(var(--s-md), 3vw, var(--s-lg));
  margin-left: clamp(var(--s-md), 3vw, var(--s-lg));
}

.stat { min-width: 0; }
.stat-value {
  display: flex;
  align-items: center;
  gap: var(--s-xs);
  font-size: clamp(1.5rem, 1.15rem + 1.5vw, 2rem);
  color: var(--on-surface);
}
.stat-label { margin-top: 6px; font-size: 0.875rem; color: var(--on-surface-var); }
.stat.is-gold .stat-value { color: var(--gold); }
.stat.is-effort .stat-value { color: var(--effort); }
.stat.is-recovery .stat-value { color: var(--recovery); }

@media (max-width: 559px) {
  .stat-row { grid-template-columns: repeat(2, minmax(0, 1fr)); row-gap: var(--s-lg); }
  .stat-row > :nth-child(odd) { border-left: 0; margin-left: 0; padding-left: 0; }
}

/* --------------------------------------------------------------------------
   10. Nav
   -------------------------------------------------------------------------- */
.nav {
  position: sticky;
  top: 0;
  z-index: 100;
  background: color-mix(in srgb, var(--surface) 82%, transparent);
  backdrop-filter: saturate(180%) blur(16px);
  -webkit-backdrop-filter: saturate(180%) blur(16px);
  border-bottom: 1px solid transparent;
  transition: border-color var(--t-normal) var(--ease),
              background-color var(--t-normal) var(--ease);
}
.nav.is-stuck {
  border-bottom-color: var(--hairline);
  background: color-mix(in srgb, var(--surface) 94%, transparent);
}
@supports not (backdrop-filter: blur(1px)) { .nav { background: var(--surface); } }

.nav-inner {
  height: 68px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-lg);
}

.brand-lockup {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  color: var(--on-surface);
  font-weight: 800;
  font-size: 1.0625rem;
  letter-spacing: -0.03em;
}
.brand-lockup:hover { text-decoration: none; }
.brand-mark {
  width: 32px; height: 32px;
  border-radius: 10px;
  background: var(--gradient-brand);
  display: grid; place-items: center;
  color: #fff;
  flex: none;
}
.brand-mark .icon { width: 20px; height: 20px; }

.nav-links {
  display: none;
  align-items: center;
  gap: var(--s-lg);
  list-style: none;
  margin: 0; padding: 0;
}
.nav-links a {
  color: var(--on-surface-var);
  font-size: 0.9375rem;
  font-weight: 500;
  /* The hit area, not the type, is what has to clear 24px (WCAG 2.5.8). The
     bar is 68px tall and centres its items, so this costs no layout. */
  padding-block: 12px;
  transition: color var(--t-fast) var(--ease);
}
.nav-links a:hover { color: var(--on-surface); text-decoration: none; }

.nav-actions { display: flex; align-items: center; gap: var(--s-sm); }
.nav-cta { display: none; }

.nav-toggle {
  display: inline-grid;
  place-items: center;
  width: 44px; height: 44px;
  background: transparent;
  border: 1px solid var(--hairline-strong);
  border-radius: var(--r-control);
  cursor: pointer;
}
.nav-toggle .icon { width: 22px; height: 22px; }
.nav-toggle .icon-close { display: none; }
.nav-toggle[aria-expanded='true'] .icon-menu { display: none; }
.nav-toggle[aria-expanded='true'] .icon-close { display: block; }

/* Mobile sheet, at the app's sheet radius. */
.nav-sheet {
  position: fixed;
  inset: 68px 0 auto;
  z-index: 99;
  background: var(--surface-card);
  border-bottom: 1px solid var(--hairline);
  border-radius: 0 0 var(--r-sheet) var(--r-sheet);
  padding: var(--s-lg) var(--gutter) var(--s-xl);
  transform: translateY(-8px);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--t-normal) var(--ease),
              transform var(--t-normal) var(--ease),
              visibility var(--t-normal);
}
.nav-sheet.is-open { opacity: 1; transform: translateY(0); visibility: visible; }
.nav-sheet ul { list-style: none; margin: 0 0 var(--s-lg); padding: 0; display: grid; gap: 2px; }
/* Scoped to the list, not to every anchor in the sheet. Unscoped, this rule
   sits after .btn-primary in the cascade and repainted the sheet's call to
   action in page-text grey on its own lavender fill: 1.31:1. */
.nav-sheet ul a {
  display: block;
  padding: var(--s-md) var(--s-sm);
  border-radius: var(--r-control);
  color: var(--on-surface);
  font-size: 1.0625rem;
  font-weight: 600;
}
.nav-sheet ul a:hover { background: var(--surface-raised); text-decoration: none; }
.nav-sheet .btn { width: 100%; }

@media (min-width: 768px) {
  .nav-links { display: flex; }
  .nav-cta { display: inline-flex; }
  .nav-toggle { display: none; }
  .nav-sheet { display: none; }
}

/* --------------------------------------------------------------------------
   11. Device frame — a bezel around a real screenshot. The screenshots already
       carry the status bar and the Dynamic Island, so the frame is only an edge.
   -------------------------------------------------------------------------- */
.phone {
  position: relative;
  width: 100%;
  border-radius: 40px;
  padding: 5px;
  background: linear-gradient(160deg, #3A3B47 0%, #191A22 45%, #2C2D38 100%);
  box-shadow: var(--lift);
}
.phone img {
  width: 100%;
  border-radius: 35px;
  background: var(--surface);
}
.phone::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 40px;
  border: 1px solid rgba(255, 255, 255, 0.09);
  pointer-events: none;
}

/* --------------------------------------------------------------------------
   12. Hero
   -------------------------------------------------------------------------- */
.hero {
  position: relative;
  /* Sized so the whole hero clears a 900px viewport with the nav above it: a
     full-height phone screenshot is 2.17x as tall as it is wide, and it is what
     decides this row's height, not the copy. */
  padding-top: clamp(2rem, 1rem + 3vw, 4rem);
  padding-bottom: clamp(3rem, 2rem + 4vw, 5rem);
  overflow: hidden;
}
/* One soft brand wash behind the phone. The page is otherwise flat, matching
   the app, which reserves the gradient for hero surfaces only. */
.hero::before {
  content: '';
  position: absolute;
  top: -22%;
  right: -12%;
  width: min(880px, 92vw);
  aspect-ratio: 1;
  background: radial-gradient(circle, rgba(43, 78, 230, 0.3) 0%, rgba(43, 78, 230, 0) 62%);
  pointer-events: none;
  z-index: 0;
}
.hero .shell { position: relative; z-index: 1; }

.hero-grid { display: grid; gap: clamp(2.5rem, 1rem + 6vw, 4.5rem); align-items: center; }
.hero-copy > * + * { margin-top: var(--s-lg); }
.hero-copy .btn-row { margin-top: var(--s-xl); }

.hero-visual { position: relative; justify-self: center; width: min(300px, 74vw); }
.hero-visual .phone { box-shadow: var(--lift), var(--lift-brand); }

/* The phone is shown whole, and on a short viewport it simply runs past the
   fold. Cropping it inside the frame was the alternative and it reads as a
   broken device: a straight cut across the middle of the app's own bottom
   navigation. The copy stays vertically centred, so the call to action is
   above the fold either way. */

@media (min-width: 900px) {
  .hero-grid { grid-template-columns: minmax(0, 1.12fr) minmax(0, 0.88fr); }
  .hero-visual { width: 300px; justify-self: center; }
}

/* --------------------------------------------------------------------------
   13. Showcase — copy beside one wide UI detail.
   -------------------------------------------------------------------------- */
.showcase-grid { display: grid; gap: clamp(2rem, 1rem + 4vw, 3.5rem); align-items: center; }
@media (min-width: 900px) {
  .showcase-grid { grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr); }
}
.showcase-copy > * + * { margin-top: var(--s-lg); }

.showcase-figure {
  margin: 0;
  border-radius: var(--r-hero);
  overflow: hidden;
  border: 1px solid var(--hairline);
  background: var(--surface-card);
  box-shadow: var(--lift);
}
.showcase-figure img { width: 100%; }
.showcase-caption {
  padding: var(--s-md) var(--s-lg);
  border-top: 1px solid var(--hairline);
  font-size: 0.875rem;
  color: var(--on-surface-dim);
}

/* --------------------------------------------------------------------------
   14. Steps — a numbered flow with a connecting hairline. The numbers are the
       progression; there is no "Stage 1" label doing the same job twice.
   -------------------------------------------------------------------------- */
.steps {
  list-style: none;
  margin: 0; padding: 0;
  display: grid;
  gap: var(--s-xl);
  counter-reset: step;
}
.step { position: relative; counter-increment: step; padding-left: 56px; }
.step::before {
  content: counter(step, decimal-leading-zero);
  position: absolute;
  left: 0; top: 0;
  width: 40px; height: 40px;
  border-radius: var(--r-control);
  display: grid; place-items: center;
  background: var(--surface-card);
  border: 1px solid var(--hairline-strong);
  color: var(--primary);
  font-size: 0.8125rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
/* The connecting line, drawn between markers rather than under the text. */
.step:not(:last-child)::after {
  content: '';
  position: absolute;
  left: 19px;
  top: 46px;
  bottom: calc(var(--s-xl) * -1 + 4px);
  border-left: 1px dashed var(--hairline-strong);
}
.step h3 { margin-bottom: var(--s-sm); }

/* Two by two on a tablet. Four full-width rows wastes an 800px screen, and
   four across at that width squeezes each step to about 170px. The connector
   is dropped here because it only reads as a sequence in a single line. */
@media (min-width: 620px) and (max-width: 859px) {
  .steps { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-xl) var(--s-lg); }
  .step:not(:last-child)::after { display: none; }
}

@media (min-width: 860px) {
  .steps { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--s-lg); }
  .step { padding-left: 0; padding-top: 56px; }
  .step:not(:last-child)::after {
    left: 48px;
    right: calc(var(--s-lg) * -1);
    top: 19px;
    bottom: auto;
    border-left: 0;
    border-top: 1px dashed var(--hairline-strong);
  }
}

/* --------------------------------------------------------------------------
   15. Screen rail — a scroll-snapping row of real screenshots. Breadth without
       forcing six phones into a grid that would shrink them past legibility.
   -------------------------------------------------------------------------- */
.rail-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--s-lg);
  flex-wrap: wrap;
}
.rail-controls { display: none; gap: var(--s-sm); }
@media (min-width: 768px) { .rail-controls { display: flex; } }

.rail-btn {
  width: 44px; height: 44px;
  display: grid; place-items: center;
  border-radius: var(--r-control);
  background: var(--surface-card);
  border: 1px solid var(--hairline-strong);
  color: var(--on-surface);
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease), opacity var(--t-fast) var(--ease);
}
.rail-btn:hover:not([disabled]) { background: var(--surface-raised); }
.rail-btn[disabled] { opacity: 0.32; cursor: default; }
.rail-btn .icon-prev { transform: rotate(180deg); }

.rail-viewport {
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  padding-block: var(--s-sm) var(--s-lg);
  /* Full-bleed so the rail runs to the viewport edge rather than stopping at
     the shell, which is what makes a rail read as scrollable. */
  margin-inline: calc(var(--gutter) * -1);
  padding-inline: var(--gutter);
}
.rail-viewport::-webkit-scrollbar { display: none; }

.rail {
  display: flex;
  gap: var(--s-lg);
  margin: 0; padding: 0;
  list-style: none;
  width: max-content;
}
.rail-item { scroll-snap-align: center; width: 232px; flex: none; }
.rail-item .phone { border-radius: 32px; padding: 4px; }
.rail-item .phone img { border-radius: 28px; }
.rail-item .phone::after { border-radius: 32px; }
.rail-caption { margin-top: var(--s-md); font-size: 0.875rem; font-weight: 600; color: var(--on-surface); }
.rail-caption span { display: block; font-weight: 400; color: var(--on-surface-dim); margin-top: 2px; }

@media (min-width: 768px) {
  .rail-item { width: 262px; }
  .rail { gap: var(--s-xl); }
}

/* --------------------------------------------------------------------------
   16. Bento — outcomes, not a feature list. Mixed cell sizes with real UI in
       three of them, so it is not five identical text tiles.
   -------------------------------------------------------------------------- */
.bento { display: grid; gap: var(--s-md); grid-template-columns: 1fr; }
.bento-cell {
  background: var(--surface-card);
  border: 1px solid var(--hairline);
  border-radius: var(--r-card);
  padding: var(--s-lg);
  display: flex;
  flex-direction: column;
  gap: var(--s-md);
  overflow: hidden;
}
.bento-cell h3 { max-width: 22ch; }

/* On narrow screens the wrapper is transparent: the cell is still a flex
   column and the copy stacks exactly as it does in every other tile. */
.bento-body { display: flex; flex-direction: column; gap: var(--s-md); }

/* A band, not the whole crop. The source images are phone screenshots, so
   letting them size themselves inside a landscape cell makes a tile six
   hundred pixels tall with a paragraph floating at the top of it. */
.bento-media {
  margin: auto calc(var(--s-lg) * -1) calc(var(--s-lg) * -1);
  border-top: 1px solid var(--hairline);
  background: var(--surface);
  height: clamp(150px, 16vw, 190px);
  overflow: hidden;
}
.bento-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center top;
}

/* The wide cell's screenshot: a band underneath the copy on narrow screens,
   and a column beside it once the tile is four columns across, which is the
   only way a portrait crop uses that width properly. One image either way,
   moved by CSS rather than duplicated into two downloads. */
.bento-aside {
  margin: auto calc(var(--s-lg) * -1) calc(var(--s-lg) * -1);
  border-top: 1px solid var(--hairline);
  background: var(--surface);
  height: clamp(150px, 16vw, 190px);
  overflow: hidden;
}
/* Centred, not top-anchored: as a narrow band this crop is a ring, and
   anchoring to the top slices the top off it. */
.bento-aside img { width: 100%; height: 100%; object-fit: cover; object-position: center; }

/* Text-only cells centre their content so the tile does not read as unfinished
   next to a neighbour that ends in a screenshot. */
.bento-cell.is-text { justify-content: center; }

.bento-cell.is-brand {
  background: var(--gradient-brand);
  border-color: transparent;
  color: #fff;
}
.bento-cell.is-brand p { color: rgba(255, 255, 255, 0.86); }
.bento-cell.is-brand .icon-badge { background: rgba(255, 255, 255, 0.2); color: #fff; }

@media (min-width: 720px) {
  .bento { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  .bento-a { grid-column: span 3; }
  .bento-b { grid-column: span 3; }
  .bento-c { grid-column: span 2; }
  .bento-d { grid-column: span 2; }
  .bento-e { grid-column: span 2; }
}
@media (min-width: 1024px) {
  .bento-a { grid-column: span 4; }
  .bento-b { grid-column: span 2; }

  /* The copy is one grid item, not three. Left as separate rows the grid
     distributes spare height between the badge, the heading and the paragraph,
     which pulls them to opposite ends of the tile. */
  .bento-cell.has-aside {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 290px);
    align-items: stretch;
    column-gap: var(--s-lg);
  }
  .bento-body { align-self: center; }
  .bento-aside {
    grid-column: 2;
    margin: calc(var(--s-lg) * -1) calc(var(--s-lg) * -1) calc(var(--s-lg) * -1) 0;
    border-top: 0;
    border-left: 1px solid var(--hairline);
    height: auto;
  }
  .bento-aside img { object-position: center top; }
}

/* --------------------------------------------------------------------------
   17. Premium — one contained card with a grid of entitlements inside.
   -------------------------------------------------------------------------- */
.tier-grid { display: grid; gap: var(--s-lg); margin-top: var(--s-xl); }
@media (min-width: 640px) { .tier-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

.tier-item { display: flex; gap: var(--s-md); align-items: flex-start; }
.tier-item h3 { margin-bottom: 2px; font-size: 1.0625rem; font-weight: 700; letter-spacing: -0.01em; }
.tier-item p { font-size: 0.9375rem; color: var(--on-surface-var); }

.tier-note {
  margin-top: var(--s-xl);
  padding-top: var(--s-lg);
  border-top: 1px solid var(--hairline);
  font-size: 0.875rem;
  color: var(--on-surface-dim);
  max-width: 66ch;
}

.free-line {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-sm) var(--s-lg);
  margin-top: var(--s-lg);
  padding: 0;
  list-style: none;
  font-size: 0.9375rem;
  color: var(--on-surface-var);
}
.free-line li { display: flex; align-items: center; gap: var(--s-sm); }
.free-line .icon { color: var(--recovery); }

/* --------------------------------------------------------------------------
   18. Final CTA + signup form
   -------------------------------------------------------------------------- */
.cta-panel {
  padding: clamp(2.5rem, 1.5rem + 4vw, 4.5rem) clamp(var(--s-lg), 4vw, 4rem);
  text-align: center;
}
.cta-panel h2 { color: #fff; }
.cta-panel .body-lg { margin: var(--s-md) auto 0; max-width: 52ch; color: rgba(255, 255, 255, 0.86); }

.signup {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-sm);
  justify-content: center;
  align-items: flex-end;
  margin: var(--s-xl) auto 0;
  max-width: 520px;
}
.signup .field { flex: 1 1 260px; text-align: left; }

/* Label above input, always. Never placeholder-as-label. */
.field label {
  display: block;
  font-size: 0.8125rem;
  font-weight: 600;
  margin-bottom: 6px;
  color: #fff;
}
.field input {
  width: 100%;
  min-height: 52px;
  padding: 0 var(--s-md);
  border-radius: var(--r-control);
  border: 1px solid rgba(255, 255, 255, 0.55);
  background: rgba(255, 255, 255, 0.16);
  color: #fff;
  font: inherit;
  transition: border-color var(--t-fast) var(--ease), background-color var(--t-fast) var(--ease);
}
.field input::placeholder { color: rgba(255, 255, 255, 0.78); }
.field input:focus {
  outline: none;
  border-color: #fff;
  background: rgba(255, 255, 255, 0.24);
  box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.3);
}
.signup .btn { flex: 0 0 auto; }
@media (max-width: 519px) { .signup .btn { width: 100%; } }

.form-msg {
  margin-top: var(--s-md);
  font-size: 0.9375rem;
  min-height: 1.4em;
  color: #fff;
}
.form-msg[data-state='error'] { color: #FFDCD0; }
.form-msg .icon { vertical-align: -0.22em; margin-right: 6px; }

.cta-foot { margin-top: var(--s-lg); font-size: 0.8125rem; color: rgba(255, 255, 255, 0.76); }

/* --------------------------------------------------------------------------
   19. Footer
   -------------------------------------------------------------------------- */
.footer {
  border-top: 1px solid var(--hairline);
  padding-block: clamp(3rem, 2rem + 3vw, 4.5rem) var(--s-xl);
}
.footer-grid { display: grid; gap: var(--s-xl); grid-template-columns: 1fr; }
@media (min-width: 640px) { .footer-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 960px) { .footer-grid { grid-template-columns: 1.7fr repeat(3, minmax(0, 1fr)); } }

.footer-about p { margin-top: var(--s-md); max-width: 34ch; font-size: 0.9375rem; }
.footer h2 {
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--on-surface-dim);
  margin-bottom: var(--s-md);
}
.footer ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
/* Vertical padding on an inline link grows the hit area without moving the
   line box, so the column keeps its rhythm and the target clears 24px. */
.footer ul a { color: var(--on-surface-var); font-size: 0.9375rem; padding-block: 5px; }
.footer ul a:hover { color: var(--on-surface); text-decoration: none; }

.footer-bar {
  margin-top: clamp(2.5rem, 2rem + 2vw, 3.5rem);
  padding-top: var(--s-lg);
  border-top: 1px solid var(--hairline);
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-sm) var(--s-lg);
  justify-content: space-between;
  font-size: 0.8125rem;
  color: var(--on-surface-dim);
}

.store-note {
  display: inline-flex;
  align-items: center;
  gap: var(--s-sm);
  margin-top: var(--s-lg);
  padding: 10px var(--s-md);
  border: 1px dashed var(--hairline-strong);
  border-radius: var(--r-control);
  font-size: 0.8125rem;
  color: var(--on-surface-dim);
}

/* --------------------------------------------------------------------------
   20. Legal pages
   -------------------------------------------------------------------------- */
.page-head { padding-block: clamp(3rem, 2rem + 3vw, 5rem) var(--s-xl); }
.prose { max-width: 68ch; padding-bottom: clamp(3rem, 2rem + 4vw, 6rem); }
.prose h2 {
  margin-top: var(--s-xxl);
  margin-bottom: var(--s-md);
  font-size: 1.375rem;
  font-weight: 700;
  letter-spacing: -0.02em;
}
.prose h3 { margin-top: var(--s-xl); margin-bottom: var(--s-sm); font-size: 1.0625rem; font-weight: 700; }
.prose p, .prose li { color: var(--on-surface-var); }
.prose p + p { margin-top: var(--s-md); }
.prose ul { margin: var(--s-md) 0 0; padding-left: 1.15rem; display: grid; gap: var(--s-sm); }
.prose .lede { color: var(--on-surface); font-size: 1.0625rem; }
.prose table { width: 100%; border-collapse: collapse; margin-top: var(--s-md); font-size: 0.9375rem; }
.prose th, .prose td {
  text-align: left;
  padding: 10px var(--s-md) 10px 0;
  border-bottom: 1px solid var(--hairline);
  vertical-align: top;
}
.prose th { color: var(--on-surface); font-weight: 600; }
.prose td { color: var(--on-surface-var); }
.table-scroll { overflow-x: auto; }

/* --------------------------------------------------------------------------
   21. Motion — entrances only, and only where sequence carries meaning.
       Everything collapses under prefers-reduced-motion.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: no-preference) {
  .reveal {
    opacity: 0;
    transform: translateY(18px);
    transition: opacity var(--t-celebratory) var(--ease),
                transform var(--t-celebratory) var(--ease);
    transition-delay: var(--reveal-delay, 0ms);
  }
  .reveal.is-in { opacity: 1; transform: none; }
}

/* --------------------------------------------------------------------------
   22. Principles

   Hairline-separated columns rather than three cards, which is the same call
   the app's StatBlock makes: separated by space and a rule, a set of three
   reads as one comparable group; boxed, it reads as three unrelated things
   that happen to sit next to each other.
   -------------------------------------------------------------------------- */
.principles {
  display: grid;
  gap: var(--s-xl);
  margin: 0;
  padding: 0;
  list-style: none;
}
.principle > h3 { margin-bottom: var(--s-sm); }
.principle > p { color: var(--on-surface-var); }
.principle-index {
  display: block;
  font-size: 0.8125rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.08em;
  color: var(--accent);
  margin-bottom: var(--s-md);
}

@media (min-width: 820px) {
  .principles { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0; }
  .principle + .principle {
    border-left: 1px solid var(--hairline);
    padding-left: clamp(var(--s-lg), 3vw, var(--s-xl));
    margin-left: clamp(var(--s-lg), 3vw, var(--s-xl));
  }
}

/* --------------------------------------------------------------------------
   23. FAQ

   Native <details>, so it opens with no JavaScript, is reachable by keyboard
   for free, and stays crawlable: search engines index the answer text whether
   or not the item is open.

   One hairline between rows, never a border on both edges of every row.
   -------------------------------------------------------------------------- */
/* Capped well short of the shell. Run full width and the chevron ends up
   seven hundred pixels from the question it belongs to. */
.faq { border-top: 1px solid var(--hairline); max-width: 860px; }

.faq-item { border-bottom: 1px solid var(--hairline); }

.faq-item summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-md);
  padding: var(--s-lg) 0;
  cursor: pointer;
  list-style: none;
  font-size: clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--on-surface);
  transition: color var(--t-fast) var(--ease);
}
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary:hover { color: var(--primary); }
.faq-item summary:focus-visible { outline-offset: -2px; }

.faq-item summary .icon {
  color: var(--on-surface-dim);
  flex: none;
  transition: transform var(--t-normal) var(--ease), color var(--t-fast) var(--ease);
}
.faq-item[open] summary .icon { transform: rotate(90deg); color: var(--primary); }

.faq-answer {
  padding: 0 0 var(--s-lg);
  max-width: 68ch;
  color: var(--on-surface-var);
  line-height: 1.6;
}
.faq-answer p + p { margin-top: var(--s-md); }

@media (prefers-reduced-motion: reduce) {
  .faq-item summary .icon { transition: none; }
}

/* --------------------------------------------------------------------------
   22. Utilities

   These exist so the pages carry no inline `style` attributes, which lets the
   site ship `style-src 'self'` with no `unsafe-inline` escape hatch. Stagger
   steps match the app's motion scale rather than being arbitrary.
   -------------------------------------------------------------------------- */
.d1 { --reveal-delay: 60ms; }
.d2 { --reveal-delay: 120ms; }
.d3 { --reveal-delay: 180ms; }
.d4 { --reveal-delay: 240ms; }

.mt-md { margin-top: var(--s-md); }
.mt-xl { margin-top: var(--s-xl); }
.footer-bar-solo { margin-top: 0; border-top: 0; }
