/* =========================================================================
   Rally — landing page
   Fluid unit system: every value is authored against a 1920px canvas and
   scales linearly with the viewport, clamped between 1024px and 2560px.
   calc(170 * var(--px)) === 170px at 1920w, 127.5px at 1440w.
   ========================================================================= */

:root {
  --container-min: 1024px;
  --container-max: 2560px;
  --container: clamp(var(--container-min), 100vw, var(--container-max));
  --px: calc(var(--container) / 1920);

  /* Palette: forest + cream */
  --cream: #faf7f0;
  --cream-deep: #f2ede1;
  --wash: #f6f2e8;
  --surface: #ffffff;
  --forest: #14532d;
  --forest-lift: #1c6b3c;
  --forest-deep: #0d3b20;
  --amber: #d97706;      /* graphics only; 2.9:1 on cream, too low for text */
  --amber-ink: #8a4c05;  /* the text-safe amber */
  --ink: #1c1917;
  --ink-soft: #57534e;
  --ink-faint: #6f675c;  /* 5.2:1 on cream, 5.0:1 on wash */
  --line: rgba(28, 25, 23, 0.12);
  --line-soft: rgba(28, 25, 23, 0.07);

  /* Phone geometry. Ratios taken from a 16 Pro: 71.5 x 149.6 x 8.25mm gives
     h/w 2.09 and d/w 0.115, so the body reads as the real proportion. */
  --pw: calc(330 * var(--px));
  --ph: calc(690 * var(--px));
  --pd: calc(38 * var(--px));
  --pr: calc(50 * var(--px));
  --cw: calc(134 * var(--px));  /* camera plateau, 40% of body width */
  --cd: calc(9 * var(--px));    /* how far the bump stands off the back */
  --crad: calc(44 * var(--px)); /* plateau corner radius; walls inset by it */

  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
}

*,
*::before,
*::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  color-scheme: light;
}

body {
  margin: 0;
  background: var(--cream);
  color: var(--ink);
  font-family: "Outfit", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  font-size: calc(16 * var(--px));
  font-weight: 400;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

img, svg { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; border: 0; background: none; cursor: pointer; }

:where(a, button, summary, [tabindex]):focus-visible {
  outline: calc(3 * var(--px)) solid var(--forest);
  outline-offset: calc(3 * var(--px));
  border-radius: calc(6 * var(--px));
}

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0);
  white-space: nowrap; border: 0;
}

.skip-link {
  position: absolute;
  top: calc(12 * var(--px));
  left: calc(12 * var(--px));
  z-index: 200;
  padding: calc(12 * var(--px)) calc(20 * var(--px));
  background: var(--forest);
  color: var(--cream);
  border-radius: calc(999 * var(--px));
  transform: translateY(-200%);
  transition: transform 0.2s var(--ease);
}
.skip-link:focus { transform: translateY(0); }

/* ---------- Type scale (matches Flowty's ratios, re-skinned) ---------- */

/* The size modifiers are used on their own, without the base class, so the
   shared properties have to be listed for all three. */
.display,
.display--xl,
.display--md {
  font-weight: 400;
  letter-spacing: -0.02em;
  color: var(--forest);
  margin: 0;
}

/* 170 resolves to 127.5px at 1440, flowty.co's exact hero size. The hero
   headline is broken into four short lines so it stays clear of the device
   sitting centre-right; the threaded chapters below split their headline
   left and right of the dead-centre device. */
.display     { font-size: calc(170 * var(--px)); line-height: 0.88; }
.display--xl { font-size: calc(250 * var(--px)); line-height: 0.94; letter-spacing: -0.025em; }
.display--md { font-size: calc(96 * var(--px));  line-height: 0.96; }

.title-sm {
  font-size: calc(48 * var(--px));
  line-height: 1.04;
  letter-spacing: -0.02em;
  font-weight: 400;
  color: var(--forest);
  margin: 0;
}

.lede {
  font-size: calc(22 * var(--px));
  line-height: 1.4;
  letter-spacing: -0.01em;
  color: var(--ink-soft);
  margin: 0;
  max-width: calc(660 * var(--px));
}

.body-lg {
  font-size: calc(36 * var(--px));
  line-height: 1.2;
  letter-spacing: -0.02em;
  color: var(--ink);
  margin: 0;
}

.eyebrow {
  font-size: calc(15 * var(--px));
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin: 0 0 calc(24 * var(--px));
}

/* ---------- Layout ---------- */

.shell {
  width: 100%;
  padding-inline: calc(64 * var(--px));
}

section { position: relative; }

/* ---------- Header ---------- */

.masthead {
  position: absolute;
  inset: 0 0 auto 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: calc(38 * var(--px)) calc(64 * var(--px));
}

.wordmark {
  display: inline-flex;
  align-items: center;
  gap: calc(10 * var(--px));
  font-size: calc(26 * var(--px));
  letter-spacing: -0.03em;
  color: var(--forest);
}
.wordmark svg { width: calc(22 * var(--px)); height: calc(22 * var(--px)); }

.masthead nav {
  display: flex;
  align-items: center;
  gap: calc(36 * var(--px));
  font-size: calc(17 * var(--px));
  color: var(--ink-soft);
}
.masthead nav a:hover { color: var(--forest); }

/* ---------- Buttons ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: calc(10 * var(--px));
  height: calc(56 * var(--px));
  padding-inline: calc(30 * var(--px));
  border-radius: calc(999 * var(--px));
  font-size: calc(17 * var(--px));
  letter-spacing: -0.01em;
  white-space: nowrap;
  transition: transform 0.25s var(--ease), background-color 0.25s var(--ease),
              color 0.25s var(--ease), box-shadow 0.25s var(--ease);
}
.btn:hover { transform: translateY(calc(-2 * var(--px))); }
.btn:active { transform: translateY(0); }

.btn--primary {
  background: var(--forest);
  color: #f4fbf6;
  box-shadow: 0 calc(6 * var(--px)) calc(18 * var(--px)) rgba(20, 83, 45, 0.22);
}
.btn--primary:hover {
  background: var(--forest-lift);
  box-shadow: 0 calc(12 * var(--px)) calc(28 * var(--px)) rgba(20, 83, 45, 0.28);
}

.btn--ghost {
  background: var(--surface);
  color: var(--forest);
  border: 1px solid var(--line);
}
.btn--ghost:hover { border-color: var(--forest); }

.btn--icon {
  width: calc(56 * var(--px));
  padding: 0;
}
.btn--icon svg { width: calc(20 * var(--px)); height: calc(20 * var(--px)); }

/* ---------- Floating pill (Flowty's signature fixed chip) ---------- */

.pill {
  position: fixed;
  left: 50%;
  bottom: calc(40 * var(--px));
  transform: translateX(-50%);
  z-index: 70;
  display: flex;
  align-items: center;
  gap: calc(6 * var(--px));
  padding: calc(8 * var(--px));
  border-radius: calc(999 * var(--px));
  background: rgba(255, 255, 255, 0.72);
  border: 1px solid var(--line-soft);
  backdrop-filter: blur(calc(18 * var(--px))) saturate(1.4);
  -webkit-backdrop-filter: blur(calc(18 * var(--px))) saturate(1.4);
  box-shadow: 0 calc(10 * var(--px)) calc(34 * var(--px)) rgba(28, 25, 23, 0.1);
  transition: opacity 0.4s var(--ease), transform 0.4s var(--ease);
}
.pill__mark {
  display: grid;
  place-items: center;
  width: calc(44 * var(--px));
  height: calc(44 * var(--px));
  border-radius: calc(999 * var(--px));
  background: var(--forest);
  color: var(--cream);
}
.pill__mark svg { width: calc(19 * var(--px)); height: calc(19 * var(--px)); }
.pill .btn { height: calc(44 * var(--px)); font-size: calc(16 * var(--px)); }
.pill__link {
  padding-inline: calc(20 * var(--px));
  font-size: calc(16 * var(--px));
  color: var(--ink-soft);
}
.pill__link:hover { color: var(--forest); }

/* ---------- Ambient background wash ---------- */

.aura {
  position: absolute;
  border-radius: 50%;
  filter: blur(calc(120 * var(--px)));
  pointer-events: none;
  z-index: 0;
}

/* =========================================================================
   Scroll track — sticky 3D phone + three chapters
   ========================================================================= */

/* A short tail (not a full viewport) extends the sticky travel just past the
   third chapter's centre so the device is solidly pinned while that chapter
   is framed, then releases and scrolls up together with the chapter into the
   next section. A full 100vh here left an empty band after the device exited
   before the next section arrived. */
.track { position: relative; z-index: 1; padding-bottom: 30vh; }

/* The chapters are pulled up over the stage with a negative margin-top on
   THEM, not a negative margin-bottom here. A negative bottom margin would
   collapse this element's margin box to zero height, and sticky release is
   measured against the margin box, so the phone would stay pinned forever
   and bleed over every section below the track. */
.stage-wrap {
  position: sticky;
  top: 0;
  height: 100vh;
  z-index: 2;
  pointer-events: none;
  display: grid;
  place-items: center;
}

.stage {
  position: relative;
  width: 100%;
  height: 100%;
  perspective: calc(2000 * var(--px));
  /* dead centre: the device sits in the middle of the viewport and the
     headline threads around it, left and right */
  perspective-origin: 50% 50%;
}

.phone {
  position: absolute;
  top: 50%;
  left: 50%;
  width: var(--pw);
  height: var(--ph);
  margin: calc(var(--ph) / -2) 0 0 calc(var(--pw) / -2);
  transform-style: preserve-3d;
  will-change: transform;
}

.face {
  position: absolute;
  top: 50%;
  left: 50%;
  backface-visibility: hidden;
  border-radius: var(--pr);
}

.face--front,
.face--back {
  width: var(--pw);
  height: var(--ph);
  margin: calc(var(--ph) / -2) 0 0 calc(var(--pw) / -2);
}

/* Black titanium. The reference device is very dark: the brightest point on
   the entire body barely clears #5d. Earlier revisions used near-chrome rails
   and the whole thing read as cheap plastic, so keep the range low. */
.face--front {
  transform: translateZ(calc(var(--pd) / 2));
  background: linear-gradient(152deg, #34383e 0%, #24272c 18%, #191b1f 55%, #202329 100%);
  padding: calc(5 * var(--px));
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.13);
}

/* preserve-3d, and deliberately NOT overflow:hidden — an overflow clip forces
   a flat rendering context, which would collapse the camera bump back into
   the panel and undo the whole point of it. */
.face--back {
  transform: rotateY(180deg) translateZ(calc(var(--pd) / 2));
  transform-style: preserve-3d;
  background:
    radial-gradient(120% 80% at 24% 10%, rgba(255, 255, 255, 0.05), transparent 55%),
    linear-gradient(158deg, #2b2e34 0%, #1e2126 16%, #15171a 52%, #1b1e22 100%);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12);
}
.face--back::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: linear-gradient(118deg, transparent 34%, rgba(255, 255, 255, 0.035) 49%, transparent 64%);
}

/* ---------- camera bump ----------
   A real box, not a flat decal: the plateau is pushed out along the back
   face's local +Z and four side walls span the gap back to the panel. That
   silhouette is what keeps the edge-on frame of the tumble readable. */

.camera {
  position: absolute;
  top: calc(26 * var(--px));
  left: calc(26 * var(--px));
  width: var(--cw);
  height: var(--cw);
  border-radius: var(--crad);
  transform: translateZ(var(--cd));
  transform-style: preserve-3d;
  backface-visibility: hidden;
  background:
    radial-gradient(120% 95% at 22% 12%, rgba(255, 255, 255, 0.07), transparent 62%),
    linear-gradient(152deg, #2c3036, #212429 48%, #191c20);
  /* A hard 1px inset rim drew a bright wire around the plateau and made it
     read as pasted on. The rim is a soft gradient now, top-left only, the
     way a machined edge actually catches light. */
  box-shadow: 0 calc(5 * var(--px)) calc(18 * var(--px)) rgba(0, 0, 0, 0.6);
}
.camera::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  background: linear-gradient(148deg, rgba(255, 255, 255, 0.17), rgba(255, 255, 255, 0.03) 26%, transparent 45%);
  -webkit-mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  padding: 1px;
}

/* Walls sit in the bump's own shadow, so they read darker than both the
   plateau above them and the panel they rise from.

   Each one is inset by the corner radius. Full-width walls overshot the
   plateau's rounded corners and drew a hard square halo behind it, which is
   what made the whole module look like a sticker rather than machined into
   the back. */
.cam-wall {
  position: absolute;
  background: linear-gradient(180deg, #14171b, #0a0c0f);
}
.cam-wall--l,
.cam-wall--r {
  width: var(--cd);
  height: calc(100% - var(--crad) * 1.5);
  top: calc(var(--crad) * 0.75);
}
.cam-wall--l {
  left: 0;
  transform-origin: 0 50%;
  transform: rotateY(90deg);
}
.cam-wall--r {
  right: 0;
  transform-origin: 100% 50%;
  transform: rotateY(-90deg);
}
.cam-wall--t,
.cam-wall--b {
  height: var(--cd);
  width: calc(100% - var(--crad) * 1.5);
  left: calc(var(--crad) * 0.75);
}
.cam-wall--t {
  top: 0;
  transform-origin: 50% 0;
  transform: rotateX(-90deg);
}
.cam-wall--b {
  bottom: 0;
  transform-origin: 50% 100%;
  transform: rotateX(90deg);
}

/* Lens triangle: two down the left, one on the right slightly lower, which
   is the actual Pro arrangement. Flash sits top-right outside the triangle,
   LiDAR bottom-right.

   The barrels are 38% of the plateau. At 34% they read as small grey discs;
   on the real device they dominate the module. Each one is a machined ring
   with a bright crown, a dark socket around it, and deep glass inside. */
.lens {
  position: absolute;
  width: calc(51 * var(--px));
  height: calc(51 * var(--px));
  border-radius: 50%;
  background:
    radial-gradient(circle at 50% 50%,
      #03050a 0 29%,
      #070a0e 35%,
      #191d22 40%,
      #454c55 44%,
      #737b86 47.5%,
      #454c56 51%,
      #262b31 55%,
      #171a1e 62%,
      #101317 100%);
  box-shadow:
    0 calc(2 * var(--px)) calc(6 * var(--px)) rgba(0, 0, 0, 0.8),
    0 0 0 calc(1 * var(--px)) rgba(0, 0, 0, 0.5),
    inset 0 calc(1 * var(--px)) calc(1.5 * var(--px)) rgba(255, 255, 255, 0.2);
}
/* coating flare across the glass */
.lens::before {
  content: "";
  position: absolute;
  inset: 30%;
  border-radius: 50%;
  background:
    radial-gradient(circle at 66% 72%, rgba(62, 116, 148, 0.5), rgba(16, 50, 68, 0.16) 55%, transparent 74%),
    radial-gradient(circle at 30% 26%, rgba(120, 90, 160, 0.16), transparent 60%);
}
/* specular pin on the glass */
.lens::after {
  content: "";
  position: absolute;
  top: 31%; left: 30%;
  width: 15%; height: 11%;
  border-radius: 50%;
  background: rgba(222, 238, 255, 0.78);
  filter: blur(calc(0.6 * var(--px)));
}
.lens--1 { top: calc(11 * var(--px)); left: calc(11 * var(--px)); }
.lens--2 { bottom: calc(11 * var(--px)); left: calc(11 * var(--px)); }
.lens--3 { top: calc(41 * var(--px)); right: calc(9 * var(--px)); }

.flash {
  position: absolute;
  top: calc(13 * var(--px));
  right: calc(19 * var(--px));
  width: calc(17 * var(--px));
  height: calc(17 * var(--px));
  border-radius: 50%;
  background: radial-gradient(circle at 42% 36%, #fffdf2 0 22%, #ddd5bd 44%, #6a6456 78%, #2e2b26 100%);
  box-shadow: 0 0 0 calc(1 * var(--px)) rgba(0, 0, 0, 0.45);
}
.lidar {
  position: absolute;
  bottom: calc(18 * var(--px));
  right: calc(21 * var(--px));
  width: calc(14 * var(--px));
  height: calc(14 * var(--px));
  border-radius: 50%;
  background: radial-gradient(circle at 40% 36%, #262b33 0 32%, #0c0e12 74%);
  box-shadow: 0 0 0 calc(1 * var(--px)) rgba(0, 0, 0, 0.45);
}

/* Flowty's render carries an Apple logo here. Rally's own mark goes on
   instead: putting Apple's trademark on our marketing implies an
   endorsement that does not exist. */
.badge-back {
  position: absolute;
  left: 50%;
  top: 52%;
  transform: translate(-50%, -50%);
  color: rgba(255, 255, 255, 0.1);
  font-size: calc(34 * var(--px));
  letter-spacing: -0.03em;
}

/* ---------- rails ---------- */

/* preserve-3d so the buttons can stand proud of the rail face.
   backface-visibility matters as much: without it the far rail keeps
   rendering and, once the body turns past 90 degrees, perspective throws it
   clear of the silhouette as a detached floating bar. */
.side {
  position: absolute;
  top: 50%;
  left: 50%;
  transform-style: preserve-3d;
  backface-visibility: hidden;
  background: linear-gradient(90deg,
    #0f1115 0%,
    #262a30 15%,
    #454a52 34%,
    #5d636c 50%,
    #414750 66%,
    #22262c 85%,
    #0e1014 100%);
}

.side--l,
.side--r {
  width: var(--pd);
  height: calc(var(--ph) - var(--pr) * 1.8);
  margin: calc((var(--ph) - var(--pr) * 1.8) / -2) 0 0 calc(var(--pd) / -2);
  border-radius: calc(var(--pd) / 2);
}
.side--l { transform: rotateY(-90deg) translateZ(calc(var(--pw) / 2)); }
.side--r { transform: rotateY(90deg) translateZ(calc(var(--pw) / 2)); }

.side--t,
.side--b {
  width: calc(var(--pw) - var(--pr) * 1.8);
  height: var(--pd);
  margin: calc(var(--pd) / -2) 0 0 calc((var(--pw) - var(--pr) * 1.8) / -2);
  border-radius: calc(var(--pd) / 2);
  background: linear-gradient(180deg,
    #0f1115 0%, #262a30 15%, #454a52 34%, #5d636c 50%,
    #414750 66%, #22262c 85%, #0e1014 100%);
}
.side--t { transform: rotateX(90deg) translateZ(calc(var(--ph) / 2)); }
.side--b { transform: rotateX(-90deg) translateZ(calc(var(--ph) / 2)); }

/* Buttons stand off the rail by a couple of px. In profile they break the
   straight edge, which is most of what sells the side view. */
.nub {
  position: absolute;
  border-radius: calc(3 * var(--px));
  background: linear-gradient(90deg, #16191d 0%, #454a53 32%, #666d77 52%, #383d45 74%, #14171b 100%);
  backface-visibility: hidden;
  transform: translateZ(calc(2.5 * var(--px)));
  box-shadow: 0 0 calc(3 * var(--px)) rgba(0, 0, 0, 0.55);
}
.side--l .nub { left: calc(-2 * var(--px)); width: calc(var(--pd) + 4 * var(--px)); }
.nub--action { top: 15%; height: calc(30 * var(--px)); }
.nub--vol1 { top: 24%; height: calc(48 * var(--px)); }
.nub--vol2 { top: 34%; height: calc(48 * var(--px)); }
.side--r .nub { right: calc(-2 * var(--px)); width: calc(var(--pd) + 4 * var(--px)); top: 27%; height: calc(74 * var(--px)); }

/* Line-reveal masks. Each line of a display heading rises out of its own
   clipped box, staggered by 90ms. The mask has to be a block so it clips the
   full line box; an inline wrapper leaves descenders showing above it. */
.line-mask { display: block; overflow: hidden; padding-bottom: 0.04em; }
.line-mask > i {
  display: block;
  font-style: normal;
  transform: translateY(106%);
  transition: transform 0.9s var(--ease);
}
[data-lines].in .line-mask > i { transform: none; }

/* The WebGL surface. Hidden until phone3d.js confirms it initialised, so a
   browser without WebGL shows the CSS device rather than an empty canvas. */
.stage-gl {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: none;
}
.stage.is-gl .stage-gl { display: block; }
.stage.is-gl .phone { display: none; }

/* ---------- corners ----------
   Generated in main.js: a fan of narrow planes tangent to each corner arc.
   Without them the four vertical corners are open, because the rails have to
   stop short of the rounded outline, and at grazing angles you see straight
   through the body. Closing them is most of what makes the pieces read as
   one object. */
.corner {
  position: absolute;
  top: 50%;
  left: 50%;
  width: var(--pd);
  backface-visibility: hidden;
  background: linear-gradient(90deg,
    #0e1014 0%, #262a30 15%, #454a52 34%, #5d636c 50%,
    #414750 66%, #22262c 85%, #0d0f13 100%);
}

/* ---------- key light ----------
   --lit is written every frame by main.js: this face's normal, rotated into
   world space and dotted with a fixed key light. Before this, every panel
   carried the same gradient whichever way it was pointing, so as the body
   turned the shading never moved and the faces read as separate flat
   stickers taped together rather than one machined solid. */
.face--back::before,
.side::after,
.corner::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  transform: translateZ(calc(0.3 * var(--px)));
  /* Restrained on the white side: the reference device is nearly black, and
     a strong key washed it out to mid grey. Most of the modelling comes from
     the shade term instead. */
  background: rgba(226, 238, 255, calc(var(--lit, 0.35) * 0.15));
  box-shadow: inset 0 0 0 9999px rgba(4, 6, 9, calc((1 - var(--lit, 0.35)) * 0.62));
}

/* ---------- screen ---------- */

.screen {
  position: relative;
  width: 100%;
  height: 100%;
  border-radius: calc(var(--pr) - 5 * var(--px));
  overflow: hidden;
  background: #0a0a0b;
  color: #e9e9ef;
}
/* glass: a faint diagonal sheen over everything on the display */
.screen::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 8;
  pointer-events: none;
  border-radius: inherit;
  background: linear-gradient(122deg,
    rgba(255, 255, 255, 0.07) 0%,
    rgba(255, 255, 255, 0.025) 22%,
    transparent 42%);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.06);
}

/* Dynamic Island, not a notch. The reference is a current Pro. */
.island {
  position: absolute;
  top: calc(13 * var(--px));
  left: 50%;
  transform: translateX(-50%);
  width: calc(98 * var(--px));
  height: calc(30 * var(--px));
  border-radius: calc(999 * var(--px));
  background: #000;
  z-index: 6;
}
.island::after {
  content: "";
  position: absolute;
  right: calc(8 * var(--px));
  top: 50%;
  transform: translateY(-50%);
  width: calc(12 * var(--px));
  height: calc(12 * var(--px));
  border-radius: 50%;
  background: radial-gradient(circle at 38% 34%, #1d2a3a 0 38%, #080b0f 76%);
}

.scr {
  position: absolute;
  inset: 0;
  transition: opacity 0.5s var(--ease);
}

/* --- portrait home screen --- */
.scr--home {
  padding: calc(62 * var(--px)) calc(22 * var(--px)) calc(22 * var(--px));
  display: flex;
  flex-direction: column;
  gap: calc(14 * var(--px));
  background:
    radial-gradient(120% 80% at 20% 0%, rgba(31, 107, 60, 0.5), transparent 60%),
    #0a0a0b;
}
/* Pinned level with the Dynamic Island rather than sitting under it, which
   is where iOS actually puts it. */
.scr__status {
  position: absolute;
  top: calc(19 * var(--px));
  left: calc(30 * var(--px));
  right: calc(28 * var(--px));
  z-index: 7;
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: calc(14 * var(--px));
  font-weight: 500;
  color: #e9e9ef;
}
.scr__status svg {
  height: calc(13 * var(--px));
  width: auto;
  opacity: 0.95;
}
.scr__icons { display: flex; align-items: center; gap: calc(5 * var(--px)); }
.scr__hello {
  font-size: calc(26 * var(--px));
  line-height: 1.1;
  letter-spacing: -0.02em;
}
.scr__hello span { color: rgba(233, 233, 239, 0.5); }
.mini-card {
  border-radius: calc(20 * var(--px));
  padding: calc(16 * var(--px));
  background: rgba(255, 255, 255, 0.07);
  border: 1px solid rgba(255, 255, 255, 0.09);
}
.mini-card__tag {
  font-size: calc(11 * var(--px));
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #8fd7a8;
  margin-bottom: calc(8 * var(--px));
}
.mini-card__title { font-size: calc(17 * var(--px)); line-height: 1.2; }
.mini-card__meta {
  font-size: calc(12.5 * var(--px));
  color: rgba(233, 233, 239, 0.55);
  margin-top: calc(6 * var(--px));
}
.mini-bar {
  margin-top: calc(12 * var(--px));
  height: calc(6 * var(--px));
  border-radius: calc(999 * var(--px));
  background: rgba(255, 255, 255, 0.12);
  overflow: hidden;
}
.mini-bar i {
  display: block;
  height: 100%;
  width: 62%;
  border-radius: inherit;
  background: linear-gradient(90deg, #4ea86e, #8fd7a8);
}

/* --- landscape shift screen (rotated inside the portrait glass) ---
   Absolute centring rather than grid: the child is deliberately wider than
   its container, and overflowing grid items get start-aligned, not centred. */
.scr--shift { opacity: 0; }

.shift-ui {
  position: absolute;
  top: 50%;
  left: 50%;
  width: var(--ph);
  height: var(--pw);
  transform: translate(-50%, -50%) rotate(90deg);
  padding: calc(20 * var(--px)) calc(26 * var(--px));
  background:
    radial-gradient(90% 120% at 50% 120%, rgba(31, 107, 60, 0.35), transparent 62%),
    #0a0a0b;
  display: grid;
  grid-template-rows: auto 1fr auto;
}

.tui__top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
}
.tui__back {
  display: grid;
  place-items: center;
  width: calc(34 * var(--px));
  height: calc(34 * var(--px));
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.08);
  font-size: calc(16 * var(--px));
  color: rgba(233, 233, 239, 0.8);
}
.tui__seg {
  display: flex;
  align-items: center;
  gap: calc(4 * var(--px));
  font-size: calc(13 * var(--px));
}
.tui__seg b {
  font-weight: 400;
  padding: calc(5 * var(--px)) calc(14 * var(--px));
  border-radius: calc(999 * var(--px));
  background: #eceaf2;
  color: #0a0a0b;
}
.tui__seg i { font-style: normal; color: rgba(233, 233, 239, 0.4); padding-inline: calc(8 * var(--px)); }
.tui__clock { text-align: right; font-size: calc(13 * var(--px)); line-height: 1.3; }
.tui__clock small { display: block; color: rgba(233, 233, 239, 0.45); font-size: calc(11 * var(--px)); }

.tui__count {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(4 * var(--px));
  font-size: calc(96 * var(--px));
  line-height: 1;
  letter-spacing: -0.04em;
}
.tui__count sup {
  font-size: calc(14 * var(--px));
  vertical-align: super;
  color: rgba(233, 233, 239, 0.5);
}
.tui__count .dim { color: rgba(233, 233, 239, 0.32); }

.tui__foot {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  font-size: calc(12.5 * var(--px));
}
.tui__mode { display: flex; align-items: center; gap: calc(7 * var(--px)); }
.tui__mode em {
  width: calc(7 * var(--px));
  height: calc(7 * var(--px));
  border-radius: 50%;
  background: #8fd7a8;
}
.tui__mode small { display: block; color: rgba(233, 233, 239, 0.45); font-size: calc(11 * var(--px)); }
.tui__cycle { color: rgba(233, 233, 239, 0.7); }

.tui__controls {
  position: absolute;
  left: 50%;
  bottom: calc(14 * var(--px));
  transform: translateX(-50%);
  display: flex;
  gap: calc(8 * var(--px));
}
.tui__btn {
  display: flex;
  align-items: center;
  gap: calc(8 * var(--px));
  height: calc(34 * var(--px));
  padding-inline: calc(16 * var(--px));
  border-radius: calc(999 * var(--px));
  background: rgba(255, 255, 255, 0.09);
  font-size: calc(13 * var(--px));
}
.tui__btn span {
  width: calc(11 * var(--px));
  height: calc(11 * var(--px));
  border-radius: calc(3 * var(--px));
  border: calc(2 * var(--px)) solid #ef4444;
}
.tui__btn--round { width: calc(34 * var(--px)); padding: 0; justify-content: center; }

/* ---------- Chapters ---------- */

.chapters { position: relative; z-index: 3; margin-top: -100vh; }

.chapter {
  position: relative;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: calc(150 * var(--px)) calc(64 * var(--px)) calc(120 * var(--px));
  pointer-events: none;
}
.chapter > * { pointer-events: auto; }
.chapter__head { max-width: calc(1560 * var(--px)); }
.chapter__foot { max-width: calc(620 * var(--px)); }

/* Threaded chapters: the big headline splits left and right of the
   dead-centre device, both halves vertically centred, so the text reads as
   wrapping around the phone the way flowty's "On Your Wrist" section does. */
.chapter--thread {
  justify-content: center;
  padding-block: calc(120 * var(--px));
}
/* A three-column grid keeps the device gap dead-centre no matter how wide
   each headline half is: two equal 1fr columns flank a fixed centre column
   the width of the device. space-between was jamming the halves to the
   viewport edges and leaving a lopsided gap to the phone. The halves now hug
   the device symmetrically, right-aligned on the left and left-aligned on the
   right, with a consistent breathing gap set by the padding. */
.thread {
  display: grid;
  grid-template-columns: 1fr calc(380 * var(--px)) 1fr;
  align-items: center;
  width: 100%;
  font-size: calc(132 * var(--px));
  line-height: 0.9;
}
.thread__l {
  grid-column: 1;
  text-align: right;
  padding-right: calc(56 * var(--px));
}
.thread__r {
  grid-column: 3;
  text-align: left;
  padding-left: calc(56 * var(--px));
}
/* the supporting line sits under the right half, clear of the device */
.thread__lede {
  position: absolute;
  right: calc(64 * var(--px));
  bottom: calc(96 * var(--px));
  text-align: right;
  max-width: calc(520 * var(--px));
}

/* ---------- Full-bleed parallax band ----------
   A cinematic scroll moment in flowty's idiom: a full-width image that drifts
   against the scroll behind a line-revealed headline. The media box is taller
   than the section and offset, so the image has room to travel without ever
   exposing an edge. */
.band {
  position: relative;
  height: 86vh;
  overflow: hidden;
  display: grid;
  place-items: center;
  text-align: center;
}
.band__media { position: absolute; inset: -14% 0; }
.band__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform: translate3d(0, var(--band-drift, 0%), 0) scale(1.06);
  will-change: transform;
}
.band__scrim {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg, rgba(9,20,13,0.42), rgba(9,20,13,0.30) 40%, rgba(9,20,13,0.66)),
    radial-gradient(120% 90% at 50% 50%, rgba(9,20,13,0.10), rgba(9,20,13,0.55));
}
.band__inner {
  position: relative;
  z-index: 2;
  padding-inline: calc(64 * var(--px));
  max-width: calc(1200 * var(--px));
}
.band__eyebrow { color: rgba(250,247,240,0.72); }
.band__h { color: #faf7f0; }
.band__lede {
  color: rgba(250,247,240,0.86);
  margin: calc(28 * var(--px)) auto 0;
  max-width: calc(560 * var(--px));
}

.hero-actions {
  display: flex;
  align-items: center;
  gap: calc(12 * var(--px));
  margin-top: calc(28 * var(--px));
}
.footnote {
  margin: calc(16 * var(--px)) 0 0;
  font-size: calc(14 * var(--px));
  color: var(--ink-faint);
}

.h1-mark {
  display: inline-block;
  width: calc(78 * var(--px));
  height: calc(78 * var(--px));
  vertical-align: baseline;
  color: var(--amber);
  transform: translateY(calc(6 * var(--px)));
}

/* =========================================================================
   Stat counter
   ========================================================================= */

.stat {
  padding: calc(220 * var(--px)) calc(64 * var(--px));
  text-align: center;
}
.odo {
  display: inline-flex;
  align-items: baseline;
  justify-content: center;
  gap: calc(4 * var(--px));
  font-size: calc(250 * var(--px));
  line-height: 0.92;
  letter-spacing: -0.03em;
  color: var(--forest);
}
.odo__reel {
  height: calc(230 * var(--px));
  overflow: hidden;
}
.odo__strip {
  display: flex;
  flex-direction: column;
  transform: translateY(0);
  transition: transform 1.5s cubic-bezier(0.16, 1, 0.3, 1);
}
.odo__strip span {
  height: calc(230 * var(--px));
  display: grid;
  place-items: center;
}
.stat p {
  max-width: calc(900 * var(--px));
  margin: calc(40 * var(--px)) auto 0;
}

/* =========================================================================
   Causes marquee
   ========================================================================= */

.causes { padding-block: calc(120 * var(--px)) calc(180 * var(--px)); overflow: hidden; }
.causes__intro { padding-inline: calc(64 * var(--px)); margin-bottom: calc(64 * var(--px)); }
.causes__head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: calc(40 * var(--px));
  flex-wrap: wrap;
}

.marquee {
  display: flex;
  gap: calc(24 * var(--px));
  width: max-content;
  animation: slide 46s linear infinite;
}
/* Pausing on section hover was stopping the strip whenever the cursor was
   anywhere near it, which read as broken. The button is the only pause now. */
.marquee[data-paused] { animation-play-state: paused; }
@keyframes slide {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}

/* WCAG 2.2.2: motion that starts on its own and runs past five seconds needs
   a mechanism to stop it that does not depend on hovering. */
.marquee-toggle {
  display: inline-flex;
  align-items: center;
  gap: calc(10 * var(--px));
  height: calc(46 * var(--px));
  padding-inline: calc(22 * var(--px));
  border-radius: calc(999 * var(--px));
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink-soft);
  font-size: calc(15 * var(--px));
  white-space: nowrap;
  transition: border-color 0.25s var(--ease), color 0.25s var(--ease);
}
.marquee-toggle:hover { border-color: var(--forest); color: var(--forest); }
.marquee-toggle svg { width: calc(14 * var(--px)); height: calc(14 * var(--px)); }
.marquee-toggle .ico-play { display: none; }
.marquee-toggle[aria-pressed="true"] .ico-play { display: block; }
.marquee-toggle[aria-pressed="true"] .ico-pause { display: none; }

.cause {
  --tint: #14532d;
  position: relative;
  width: calc(300 * var(--px));
  height: calc(400 * var(--px));
  border-radius: calc(34 * var(--px));
  overflow: hidden;
  flex: none;
  display: flex;
  align-items: flex-end;
  padding: calc(26 * var(--px));
  color: #f7fbf8;
  background: var(--tint);
  isolation: isolate;
}
.cause img {
  position: absolute;
  inset: 0;
  z-index: -2;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* pulled toward the card's tint so six photos from six photographers still
     read as one set rather than a stock-photo grab bag */
  filter: saturate(0.72) contrast(1.04);
  /* Parallax, driven by --drift on the strip from main.js. The scale gives
     the photo room to move inside its frame without exposing an edge. */
  transform: translate3d(0, var(--drift, 0%), 0) scale(1.1);
}
.cause::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(180deg, rgba(10, 20, 14, 0.18) 0%, transparent 34%, rgba(6, 16, 10, 0.55) 62%, rgba(4, 12, 8, 0.88) 100%),
    linear-gradient(180deg, transparent 40%, var(--tint) 130%);
}
.cause__icon {
  position: absolute;
  top: calc(26 * var(--px));
  left: calc(26 * var(--px));
  width: calc(32 * var(--px));
  height: calc(32 * var(--px));
  opacity: 0.95;
  filter: drop-shadow(0 calc(2 * var(--px)) calc(6 * var(--px)) rgba(0, 0, 0, 0.5));
}
.cause__body { position: relative; }
.cause h3 {
  margin: 0;
  font-size: calc(26 * var(--px));
  font-weight: 400;
  letter-spacing: -0.02em;
  text-shadow: 0 calc(1 * var(--px)) calc(10 * var(--px)) rgba(0, 0, 0, 0.5);
}
.cause p {
  margin: calc(6 * var(--px)) 0 0;
  font-size: calc(14.5 * var(--px));
  color: rgba(247, 251, 248, 0.86);
  text-shadow: 0 calc(1 * var(--px)) calc(8 * var(--px)) rgba(0, 0, 0, 0.55);
}

/* =========================================================================
   Matcher (tabs)
   ========================================================================= */

.matcher { padding: calc(60 * var(--px)) calc(64 * var(--px)) calc(180 * var(--px)); }
.matcher__grid {
  display: grid;
  grid-template-columns: 1fr calc(430 * var(--px));
  gap: calc(90 * var(--px));
  align-items: start;
  margin-top: calc(80 * var(--px));
}

.tabs { display: flex; gap: calc(10 * var(--px)); margin-bottom: calc(40 * var(--px)); }
.tab {
  height: calc(48 * var(--px));
  padding-inline: calc(24 * var(--px));
  border-radius: calc(999 * var(--px));
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink-soft);
  font-size: calc(16 * var(--px));
  transition: all 0.25s var(--ease);
}
.tab:hover { border-color: var(--forest); color: var(--forest); }
.tab[aria-selected="true"] {
  background: var(--forest);
  border-color: var(--forest);
  color: #f4fbf6;
}
.tab[aria-selected="true"]:hover { background: var(--forest-lift); color: #f4fbf6; }

.panel { display: none; }
.panel[data-active] { display: block; animation: rise 0.5s var(--ease) both; }
@keyframes rise {
  from { opacity: 0; transform: translateY(calc(14 * var(--px))); }
  to { opacity: 1; transform: none; }
}
.panel h3 { margin: 0 0 calc(18 * var(--px)); font-size: calc(40 * var(--px)); font-weight: 400; letter-spacing: -0.02em; color: var(--forest); line-height: 1.05; }

.strengths { list-style: none; margin: calc(34 * var(--px)) 0 0; padding: 0; display: grid; gap: calc(14 * var(--px)); max-width: calc(560 * var(--px)); }
.strengths li {
  display: grid;
  grid-template-columns: calc(150 * var(--px)) 1fr auto;
  align-items: center;
  gap: calc(18 * var(--px));
  font-size: calc(16 * var(--px));
}
.strengths .meter { height: calc(8 * var(--px)); border-radius: 999px; background: var(--cream-deep); overflow: hidden; }
.strengths .meter i { display: block; height: 100%; border-radius: inherit; background: var(--forest); width: 0; transition: width 1.1s var(--ease); }
.strengths .pct { color: var(--ink-faint); font-size: calc(14 * var(--px)); }

.matches { list-style: none; margin: calc(34 * var(--px)) 0 0; padding: 0; display: grid; gap: calc(12 * var(--px)); max-width: calc(600 * var(--px)); }
.matches li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: calc(20 * var(--px));
  padding: calc(20 * var(--px)) calc(24 * var(--px));
  border-radius: calc(20 * var(--px));
  background: var(--surface);
  border: 1px solid var(--line-soft);
}
.matches strong { font-weight: 400; font-size: calc(18 * var(--px)); }
.matches small { display: block; color: var(--ink-faint); font-size: calc(14 * var(--px)); }
.matches .fit {
  font-size: calc(14 * var(--px));
  color: var(--forest);
  background: rgba(20, 83, 45, 0.09);
  padding: calc(6 * var(--px)) calc(12 * var(--px));
  border-radius: 999px;
  white-space: nowrap;
}

/* phone frame used as a static prop in the matcher */
.prop {
  position: relative;
  width: calc(360 * var(--px));
  height: calc(730 * var(--px));
  margin-inline: auto;
  border-radius: calc(52 * var(--px));
  padding: calc(9 * var(--px));
  background: linear-gradient(155deg, #3a3f45, #17191d 45%, #101215);
  box-shadow: 0 calc(40 * var(--px)) calc(80 * var(--px)) rgba(28, 25, 23, 0.22),
              inset 0 0 0 1px rgba(255, 255, 255, 0.13);
}
.prop .screen { border-radius: calc(44 * var(--px)); }

/* =========================================================================
   Feature cards
   ========================================================================= */

.features { padding: 0 calc(64 * var(--px)) calc(180 * var(--px)); }
.features__grid { display: grid; grid-template-columns: 1fr 1fr; gap: calc(24 * var(--px)); margin-top: calc(70 * var(--px)); }

.fcard {
  border-radius: calc(48 * var(--px));
  padding: calc(64 * var(--px));
  background: var(--surface);
  border: 1px solid var(--line-soft);
  display: flex;
  flex-direction: column;
  gap: calc(20 * var(--px));
  min-height: calc(420 * var(--px));
}
.fcard h3 { margin: 0; font-size: calc(40 * var(--px)); font-weight: 400; letter-spacing: -0.02em; color: var(--forest); line-height: 1.05; }
.fcard__viz { margin-top: auto; }

/* Dark variant is declared after the base rules on purpose: `.fcard--dark h3`
   and `.fcard h3` have identical specificity, so source order decides. */
.fcard--dark { background: var(--forest); border-color: var(--forest); color: #eaf5ee; }
.fcard--dark h3 { color: #f4fbf6; }
.fcard--dark .lede { color: rgba(234, 245, 238, 0.78); }

.ledger { display: grid; gap: calc(10 * var(--px)); }
.ledger__row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: calc(14 * var(--px)) calc(18 * var(--px));
  border-radius: calc(14 * var(--px));
  background: var(--wash);
  font-size: calc(15 * var(--px));
}
.ledger__row b { font-weight: 400; }
.ledger__row .ok { color: var(--forest); }
.ledger__total {
  display: flex;
  justify-content: space-between;
  padding-top: calc(16 * var(--px));
  border-top: 1px solid var(--line);
  font-size: calc(20 * var(--px));
  color: var(--forest);
}

.roster { display: grid; gap: calc(10 * var(--px)); }
.roster__row {
  display: flex;
  align-items: center;
  gap: calc(14 * var(--px));
  padding: calc(14 * var(--px)) calc(18 * var(--px));
  border-radius: calc(14 * var(--px));
  background: rgba(255, 255, 255, 0.1);
  font-size: calc(15 * var(--px));
}
.roster__num {
  display: grid;
  place-items: center;
  width: calc(32 * var(--px));
  height: calc(32 * var(--px));
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.16);
  font-size: calc(14 * var(--px));
}
.roster__row.open { border: 1px dashed rgba(234, 245, 238, 0.4); background: transparent; color: rgba(234, 245, 238, 0.75); }

/* =========================================================================
   How it works
   ========================================================================= */

.steps { padding: 0 calc(64 * var(--px)) calc(180 * var(--px)); }
.steps__grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: calc(24 * var(--px)); margin-top: calc(70 * var(--px)); counter-reset: step; }
.step {
  padding: calc(48 * var(--px)) calc(44 * var(--px));
  border-radius: calc(36 * var(--px));
  background: var(--wash);
  counter-increment: step;
}
.step::before {
  content: counter(step, decimal-leading-zero);
  display: block;
  font-size: calc(15 * var(--px));
  letter-spacing: 0.12em;
  color: var(--amber-ink);
  margin-bottom: calc(28 * var(--px));
}
.step h3 { margin: 0 0 calc(12 * var(--px)); font-size: calc(28 * var(--px)); font-weight: 400; letter-spacing: -0.02em; color: var(--forest); line-height: 1.1; }
.step p { margin: 0; font-size: calc(17 * var(--px)); color: var(--ink-soft); line-height: 1.45; }

/* =========================================================================
   For organizations
   ========================================================================= */

.orgs {
  margin: 0 calc(64 * var(--px)) calc(180 * var(--px));
  padding: calc(120 * var(--px)) calc(90 * var(--px));
  border-radius: calc(60 * var(--px));
  background: var(--forest);
  color: #eaf5ee;
  position: relative;
  overflow: hidden;
}
.orgs .display--md { color: #f4fbf6; }
.orgs .lede { color: rgba(234, 245, 238, 0.74); }
.orgs__grid { display: grid; grid-template-columns: 1fr calc(520 * var(--px)); gap: calc(90 * var(--px)); align-items: end; }

.price {
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: calc(36 * var(--px));
  padding: calc(48 * var(--px));
  backdrop-filter: blur(calc(10 * var(--px)));
}
.price__amount { display: flex; align-items: baseline; gap: calc(8 * var(--px)); }
.price__amount b { font-size: calc(84 * var(--px)); font-weight: 400; letter-spacing: -0.03em; line-height: 1; }
.price__amount span { color: rgba(234, 245, 238, 0.86); font-size: calc(18 * var(--px)); }
.price ul { list-style: none; margin: calc(32 * var(--px)) 0 0; padding: 0; display: grid; gap: calc(14 * var(--px)); }
.price li { display: flex; gap: calc(12 * var(--px)); font-size: calc(17 * var(--px)); color: rgba(234, 245, 238, 0.88); }
.price li svg { flex: none; width: calc(20 * var(--px)); height: calc(20 * var(--px)); margin-top: calc(3 * var(--px)); color: #8fd7a8; }
.price .btn { margin-top: calc(36 * var(--px)); width: 100%; background: #f4fbf6; color: var(--forest); }

/* =========================================================================
   FAQ
   ========================================================================= */

.faq { padding: 0 calc(64 * var(--px)) calc(180 * var(--px)); }
.faq__grid { display: grid; grid-template-columns: calc(560 * var(--px)) 1fr; gap: calc(90 * var(--px)); align-items: start; }
.faq__list { border-top: 1px solid var(--line); }

details {
  border-bottom: 1px solid var(--line);
}
summary {
  list-style: none;
  cursor: pointer;
  padding: calc(34 * var(--px)) 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: calc(30 * var(--px));
  font-size: calc(24 * var(--px));
  letter-spacing: -0.01em;
  color: var(--forest);
}
summary::-webkit-details-marker { display: none; }
summary:hover { color: var(--forest-lift); }
summary:hover .chev { transform: scale(1.12); }
details[open] summary:hover .chev { transform: rotate(45deg) scale(1.12); }
summary .chev {
  flex: none;
  width: calc(22 * var(--px));
  height: calc(22 * var(--px));
  transition: transform 0.3s var(--ease);
}
details[open] summary .chev { transform: rotate(45deg); }
details p {
  margin: 0;
  padding: 0 calc(60 * var(--px)) calc(34 * var(--px)) 0;
  font-size: calc(18 * var(--px));
  line-height: 1.5;
  color: var(--ink-soft);
  max-width: calc(760 * var(--px));
}

/* =========================================================================
   Final CTA + footer
   ========================================================================= */

.finale {
  padding: calc(180 * var(--px)) calc(64 * var(--px)) calc(160 * var(--px));
  text-align: center;
}
.finale .lede { margin-inline: auto; margin-top: calc(34 * var(--px)); }
.finale .hero-actions { justify-content: center; margin-top: calc(44 * var(--px)); }

.foot {
  padding: calc(70 * var(--px)) calc(64 * var(--px)) calc(150 * var(--px));
  border-top: 1px solid var(--line);
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: calc(60 * var(--px));
  flex-wrap: wrap;
}
.foot__legal { display: flex; gap: calc(30 * var(--px)); flex-wrap: wrap; font-size: calc(16 * var(--px)); color: var(--ink-soft); }
.foot__legal a:hover { color: var(--forest); }
.foot__note { font-size: calc(15 * var(--px)); color: var(--ink-faint); max-width: calc(420 * var(--px)); margin: calc(14 * var(--px)) 0 0; }

/* =========================================================================
   Reveal-on-scroll
   ========================================================================= */

[data-reveal] {
  opacity: 0;
  transform: translateY(calc(26 * var(--px)));
  transition: opacity 0.8s var(--ease), transform 0.8s var(--ease);
}
[data-reveal].in { opacity: 1; transform: none; }

/* =========================================================================
   Responsive
   ========================================================================= */

@media (max-width: 1024px) {
  :root {
    --px: calc(100vw / 1180);
    --pw: calc(268 * var(--px));
    --ph: calc(560 * var(--px));
    --pd: calc(31 * var(--px));
    --pr: calc(41 * var(--px));
    --cw: calc(109 * var(--px));
    --cd: calc(7.5 * var(--px));
    --crad: calc(36 * var(--px));
  }
  /* The desktop display sizes assume a wide viewport. Carried into the
     tablet band unchanged, the h1 wrapped to four lines and pushed the lede
     and both buttons below the fold on a 1024 by 768 iPad in landscape. */
  .display     { font-size: calc(104 * var(--px)); }
  .display--xl { font-size: calc(164 * var(--px)); }
  .display--md { font-size: calc(72 * var(--px)); }
  .title-sm    { font-size: calc(40 * var(--px)); }

  .matcher__grid,
  .orgs__grid,
  .faq__grid { grid-template-columns: 1fr; gap: calc(70 * var(--px)); }
  .features__grid { grid-template-columns: 1fr; }
  .steps__grid { grid-template-columns: 1fr; }
  .masthead nav a:not(.btn) { display: none; }

  /* Single column, and the stage stays pinned so the device holds the
     screen the way it does on desktop.

     In one column the copy has nowhere to move sideways, so it does cross
     the phone between sections. Rather than let that read as a collision,
     main.js measures the overlap each frame and fades the device back to a
     backdrop while text is over it. flowty.co has the same crossing and
     simply hides it, being light type on a dark page. */
  .stage { perspective-origin: 50% 50%; }
  .stage-wrap { transition: opacity 0.25s var(--ease); }
  .chapter {
    padding-top: calc(150 * var(--px));
    padding-bottom: calc(120 * var(--px));
  }
}

@media (max-width: 720px) {
  :root {
    --px: calc(100vw / 620);
    --pw: calc(230 * var(--px));
    --ph: calc(478 * var(--px));
    --pd: calc(20 * var(--px));
    --pr: calc(34 * var(--px));
  }
  body { font-size: calc(17 * var(--px)); }

  .display { font-size: calc(78 * var(--px)); }
  .display--xl { font-size: calc(120 * var(--px)); }
  .display--md { font-size: calc(58 * var(--px)); }
  .title-sm { font-size: calc(36 * var(--px)); }
  .lede { font-size: calc(19 * var(--px)); }
  .body-lg { font-size: calc(26 * var(--px)); }

  .shell,
  .masthead,
  .chapter,
  .stat,
  .causes__intro,
  .matcher,
  .features,
  .steps,
  .faq,
  .finale,
  .foot { padding-inline: calc(24 * var(--px)); }

  .orgs { margin-inline: calc(24 * var(--px)); padding: calc(70 * var(--px)) calc(34 * var(--px)); border-radius: calc(40 * var(--px)); }
  .fcard { padding: calc(40 * var(--px)); border-radius: calc(34 * var(--px)); }

  .chapter {
    padding-top: calc(130 * var(--px));
    padding-bottom: calc(90 * var(--px));
  }
  .stage { perspective-origin: 50% 50%; }
  /* the inline mark lands mid-wrap at this width and reads as a stray glyph */
  .h1-mark { display: none; }

  .odo { font-size: calc(150 * var(--px)); }
  .odo__reel, .odo__strip span { height: calc(140 * var(--px)); }

  .cause { width: calc(220 * var(--px)); height: calc(300 * var(--px)); }
  .prop { width: calc(290 * var(--px)); height: calc(590 * var(--px)); }
  .strengths li { grid-template-columns: calc(120 * var(--px)) 1fr auto; gap: calc(12 * var(--px)); }
  .pill { bottom: calc(20 * var(--px)); }
  .pill__link { display: none; }
  summary { font-size: calc(20 * var(--px)); }
}

/* =========================================================================
   Reduced motion — park the phone in its final pose, drop the scrubbing
   ========================================================================= */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .marquee { animation: none; }
  [data-reveal] { opacity: 1; transform: none; transition: none; }
  .odo__strip { transition: none; }
  .strengths .meter i { transition: none; }
  .scr { transition: none; }

  /* The chapters normally sit on top of the pinned stage via a negative
     margin. With nothing pinned, that margin has to go, and the stage becomes
     an ordinary block. Order puts the headline first and the phone after the
     three chapters, as the payoff rather than a lead-in. */
  .track { display: flex; flex-direction: column; }
  .chapters { order: 1; margin-top: 0; }
  .stage-wrap {
    order: 2;
    position: relative;
    height: auto;
    padding-block: calc(40 * var(--px)) calc(20 * var(--px));
  }
  .phone {
    position: relative;
    top: auto; left: auto; margin: 0 auto;
    transform: rotateX(-4deg) rotateY(-16deg) rotateZ(0deg) !important;
  }
  /* The WebGL canvas is absolutely positioned inside the stage, and with
     nothing pinned the stage has no height at all, so the device silently
     vanished in this branch. Both need a real block size here. */
  .stage { position: relative; height: auto; }
  .stage.is-gl .stage-gl {
    position: relative;
    height: calc(660 * var(--px));
  }

  .scr--home { opacity: 1 !important; }
  .scr--shift { opacity: 0 !important; }
  .chapter { min-height: 0; padding-block: calc(90 * var(--px)); }
  /* clear the absolutely positioned masthead */
  .chapter:first-child { padding-top: calc(190 * var(--px)); }
}

/* =========================================================================
   Sub-page chrome (legal documents, early access) — shared, so it lives
   here rather than in legal.css which the form page does not load.
   ========================================================================= */

.doc-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: calc(30 * var(--px));
  padding: calc(38 * var(--px)) calc(64 * var(--px));
  border-bottom: 1px solid var(--line);
}
.doc-head .btn { height: calc(46 * var(--px)); font-size: calc(16 * var(--px)); }
.doc-foot {
  border-top: 1px solid var(--line);
  padding: calc(50 * var(--px)) calc(64 * var(--px)) calc(90 * var(--px));
  display: flex;
  flex-wrap: wrap;
  gap: calc(30 * var(--px));
  font-size: calc(16 * var(--px));
  color: var(--ink-soft);
}
.doc-foot a:hover { color: var(--forest); }
.doc-foot a[aria-current="page"] { color: var(--forest); }

@media (max-width: 720px) {
  .doc-head { padding: calc(28 * var(--px)) calc(24 * var(--px)); }
  .doc-foot { padding: calc(40 * var(--px)) calc(24 * var(--px)) calc(70 * var(--px)); gap: calc(18 * var(--px)); }
}
