:root {
  --rg-cyan: #21D4ED;
  --rg-neon-blue: #2E9BFF;
  --rg-bg-deep: #020305;
  --rg-glass-bg: rgba(255, 255, 255, 0.055);
  --rg-glass-border: rgba(255, 255, 255, 0.10);
  --rg-grad-cta: linear-gradient(180deg, #2E9BFF 0%, #0A3399 100%);

  /* Semantic theme tokens — drive page surface/text so the theme engine works
     end-to-end. In dark these resolve to the original values (no visual change). */
  --rg-page-bg: var(--rg-bg-deep);
  --rg-text: #ffffff;
  --rg-text-2: rgba(255, 255, 255, 0.55);  /* muted secondary text (trust badges, hints) */
  color-scheme: dark;
}

/* Light mode (spec §4): cinematic car/parking backgrounds ALWAYS stay dark;
   only text/surface blocks invert. This is the token + color-scheme scaffold so
   the toggle works now — full per-section light styling lands in Phase 7. */
:root[data-theme="light"] {
  --rg-page-bg: #F5F7FA;
  --rg-text: #0B0E14;
  --rg-glass-bg: rgba(255, 255, 255, 0.75);
  --rg-glass-border: rgba(0, 0, 0, 0.08);
  color-scheme: light;
}

* { box-sizing: border-box; }

body {
  background-color: var(--rg-page-bg);
  color: var(--rg-text);
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "Inter", sans-serif;
  margin: 0;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
}

/* Hero entrance: hidden pre-paint (head flag `rg-hero-arming`) so the GSAP intro
   never flashes these at their natural position (the "buttons jump" bug). JS
   reveals them — animated when visible, instant otherwise — via inline opacity
   that overrides this. If the flag is absent (hidden tab / reduced-motion / no
   JS) the hero stays fully visible. */
.rg-hero-arming #hero-text h1,
.rg-hero-arming #hero-text p[data-i18n="hero.sub"],
.rg-hero-arming #hero-cta > *,
.rg-hero-arming .hero-trust > span {
  opacity: 0;
  will-change: opacity, transform;
  /* Kill the Tailwind `transition` utility on the CTA buttons WHILE the entrance
     plays — otherwise every per-frame opacity/transform GSAP sets re-triggers a
     0.15s CSS transition, double-animating into a stutter. Re-enabled once the
     `rg-hero-arming` flag is removed (intro done), so hover/press still animate. */
  transition: none !important;
}

/* Scroll track length. Tightened 700vh → 600vh together with the compressed
   intro beats so the story feels responsive to a normal mouse-wheel scroll
   (fewer pixels per beat) without losing the cinematic scrub. */
/* Grows WITH the story so the pixels-per-beat never changes: the track solves
   (h·vh − vh) / beats ≈ 227px at a 720px viewport. 1000vh held 28.6 beats;
   the report tail and its pan took it to 32.2, hence 1113vh. */
.scroll-viewport { height: 1113vh; }
.cinema-container { position: fixed; inset: 0; height: 100svh; overflow: hidden; }

.rg-glass {
  background: var(--rg-glass-bg);
  backdrop-filter: blur(22px);
  -webkit-backdrop-filter: blur(22px);
  border: 1px solid var(--rg-glass-border);
}

/* image-set: AVIF → WebP → PNG fallback for the two background photos.
   (Generated by optimize.mjs; the .png you drop in stays as the fallback.) */
.bg-main {
  background-image: image-set(
    url("MAIN-hero.avif") type("image/avif"),
    url("MAIN-hero.webp") type("image/webp"),
    url("MAIN-hero.png")  type("image/png"));
  background-image: -webkit-image-set(
    url("MAIN-hero.avif") type("image/avif"),
    url("MAIN-hero.webp") type("image/webp"),
    url("MAIN-hero.png")  type("image/png"));
}
.bg-scooter {
  background-image: image-set(
    url("Scooter-hero.avif") type("image/avif"),
    url("Scooter-hero.webp") type("image/webp"),
    url("Scooter-hero.png")  type("image/png"));
  background-image: -webkit-image-set(
    url("Scooter-hero.avif") type("image/avif"),
    url("Scooter-hero.webp") type("image/webp"),
    url("Scooter-hero.png")  type("image/png"));
}

/* New hero backdrop — vehicles on the right, free space on the left for text.
   (Only the page-hero #bg-layer uses this; the phone viewfinder keeps .bg-main.)
   AVIF → WebP → PNG fallback (2 MB PNG → ~100 KB AVIF). */
.bg-hero {
  background-image: image-set(
    url("hero-bg.avif") type("image/avif"),
    url("hero-bg.webp") type("image/webp"),
    url("hero-bg.png")  type("image/png"));
  background-image: -webkit-image-set(
    url("hero-bg.avif") type("image/avif"),
    url("hero-bg.webp") type("image/webp"),
    url("hero-bg.png")  type("image/png"));
}

/* ===========================================================================
   PROBLEM SCENE — "REAL SCAMS" case carousel (stage 1.5 of the scroll story).
   Clean parking photos (problem-bg1..3); the front-facing glass form, cyan
   beam, price chip, pagination dots and arrows are ALL live HTML/SVG. 16:9
   "stage" mimics background-size:cover; cqw units scale type with the stage.
   =========================================================================== */
.bg-pbg1 {
  background-image: image-set(
    url("problem-bg1.avif") type("image/avif"),
    url("problem-bg1.webp") type("image/webp"),
    url("problem-bg1.png")  type("image/png"));
  background-image: -webkit-image-set(
    url("problem-bg1.avif") type("image/avif"),
    url("problem-bg1.webp") type("image/webp"),
    url("problem-bg1.png")  type("image/png"));
}
.bg-pbg2 {
  background-image: image-set(
    url("problem-bg2.avif") type("image/avif"),
    url("problem-bg2.webp") type("image/webp"),
    url("problem-bg2.png")  type("image/png"));
  background-image: -webkit-image-set(
    url("problem-bg2.avif") type("image/avif"),
    url("problem-bg2.webp") type("image/webp"),
    url("problem-bg2.png")  type("image/png"));
}
.bg-pbg3 {
  background-image: image-set(
    url("problem-bg3.avif") type("image/avif"),
    url("problem-bg3.webp") type("image/webp"),
    url("problem-bg3.png")  type("image/png"));
  background-image: -webkit-image-set(
    url("problem-bg3.avif") type("image/avif"),
    url("problem-bg3.webp") type("image/webp"),
    url("problem-bg3.png")  type("image/png"));
}

/* 16:9 stage that emulates cover-cropping of the art.
   Centering lives in GSAP (xPercent/yPercent, like #phone-container) so the
   scale tween composes cleanly instead of clobbering a CSS transform. */
.problem-stage {
  position: absolute;
  left: 50%;
  top: 50%;
  width: max(100vw, 177.78svh);
  aspect-ratio: 16 / 9;
  container-type: size;
}

/* Slides are just grouping containers now; the background layer (.p-art) owns the
   cross-fade opacity, so all three arts stack absolutely and blend on switch. */
.p-slide { position: absolute; inset: 0; }
.p-art { position: absolute; inset: 0; background-size: 100% 100%; background-repeat: no-repeat; opacity: 0; will-change: opacity, transform; }

/* Cyan "evidence beam" from the damage point to the form's left edge (SVG spans
   the whole stage, preserveAspectRatio:none → 1600×900 coords map to stage %). */
.p-beam {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  filter: drop-shadow(0 0 5px rgba(33, 212, 237, 0.5));
}

/* Live "radar" target — soft infinite ping around the damage point (pure CSS).
   Scales about its own centre (fill-box) so it stays a clean expanding ring. */
.p-radar {
  fill: none;
  stroke: var(--rg-cyan);
  stroke-width: 2;
  transform-box: fill-box;
  transform-origin: center;
  animation: p-radar 2.6s cubic-bezier(0.16, 1, 0.3, 1) infinite;
  will-change: transform, opacity;
}
@keyframes p-radar {
  0%   { transform: scale(0.55); opacity: 0; }
  18%  { opacity: 0.5; }
  100% { transform: scale(2.9); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .p-radar { animation: none; opacity: 0; }
}
/* radar pulses only on the active slide (it's CSS-driven, so JS arm/reveal can't
   gate it) — otherwise all three rings ping over each other at once. */
.p-slide:not(.is-active) .p-radar { visibility: hidden; }

/* Bottom scrim for screen 2 — sits above the parking art but below the headline,
   mobile sheet and the scroll pill, so the pill reads over the reflective floor. */
.p-bottom-scrim {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 30svh;
  background: linear-gradient(to top, rgba(0,0,0,0.9) 0%, rgba(0,0,0,0.42) 40%, transparent 100%);
  pointer-events: none;
}

/* Headline wrapper — flex column, vertically centred so the copy balances
   against the glass form's centre; left-aligned with a right gutter clear of it. */
.p-headline-wrap {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;         /* top-aligned… */
  align-items: flex-start;
  padding: 26.5vh 44% 0 clamp(24px, 5vw, 64px);  /* …to the glass form's top edge (top: 26.5%) */
  pointer-events: none;
}
.p-headline {
  text-align: left;
  font-size: clamp(17px, 2.3vw, 36px);
  line-height: 1.16;
  font-weight: 800;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  text-shadow: 0 2px 16px rgba(0,0,0,0.9), 0 0 3px rgba(0,0,0,0.85);
}
/* high contrast on the parking: setup lines near-white, the punch line full white */
.p-headline span { display: block; color: rgba(255,255,255,0.88); }
.p-headline span:last-child { color: #fff; }

/* Price chip — premium frosted-glass HUD tag. Centering (−50%/−50%) is applied
   by GSAP (xPercent/yPercent) so its spring-scale composes cleanly. */
.p-chip {
  position: absolute;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.15cqw;
  line-height: 1.1;
  pointer-events: none;
  padding: 0.7cqw 1.25cqw;
  border-radius: 0.9cqw;
  background: rgba(2, 6, 23, 0.5);                 /* slate-950/50 */
  border: 1px solid rgba(255, 255, 255, 0.1);      /* white/10 */
  backdrop-filter: blur(12px);                     /* backdrop-blur-md */
  -webkit-backdrop-filter: blur(12px);
  box-shadow: 0 1.6cqw 3.2cqw -0.8cqw rgba(0,0,0,0.7), 0 0.4cqw 1cqw rgba(0,0,0,0.5); /* shadow-2xl */
}
/* amount — gradient text, exactly like the logo (cyan-400 → blue-500) */
.p-chip-amount {
  font-size: 22px; font-size: 1.95cqw;
  font-weight: 700;
  line-height: 1.05;
  background: linear-gradient(90deg, #22d3ee 0%, #3b82f6 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
}
/* label — small, uppercase, muted grey */
.p-chip-label  {
  font-size: 10px; font-size: 0.74cqw;
  font-weight: 600;
  letter-spacing: 0.08em;                          /* tracking-wider */
  color: rgba(255, 255, 255, 0.6);                 /* white/60 */
  text-transform: uppercase;
  white-space: nowrap;
}
/* #3 — chips moved onto free, dark areas so they don't blend with the vehicle
   (tune per-image in a real browser; the beam endpoints below track these). */
.p-chip-1 { left: 45%;  top: 73%; }   /* below-right of the wheel */
.p-chip-2 { left: 20%;  top: 76%; }   /* left of the scooter's wheel */
.p-chip-3 { left: 42%;  top: 70%; }   /* raised off the bottom edge so it stays in view */
/* Case 3 sits on near-black wet asphalt, so the shared translucent slate-950 fill
   sinks into it and $270 reads as a dark blob. Give this one chip a slightly
   lighter, more opaque frosted base so it lifts off the floor and matches the
   legibility of chips 1 & 2. */
.p-chip-2 { background: rgba(23, 31, 51, 0.62); }
.p-chip-3 { background: rgba(23, 31, 51, 0.62); }

/* FRONT-FACING GLASS FORM (right). Fixed position; content crossfades in place.
   .rg-glass supplies the frosted fill + blur; we add a cyan HUD edge + glow. */
.p-panel {
  position: absolute;
  left: 60%;
  top: 26.5%;
  width: 33%;
  height: 47%;
  border-radius: 1.3cqw;
  border: 1px solid rgba(33, 212, 237, 0.3);
  box-shadow: 0 1.6cqw 4cqw rgba(0,0,0,0.55), 0 0 0 1px rgba(255,255,255,0.04) inset, 0 0 2.4cqw rgba(33,212,237,0.14);
  color: #fff;
  text-shadow: 0 1px 6px rgba(0,0,0,0.45);
}
/* HUD corner brackets (top-left + bottom-right) */
.p-panel::before, .p-panel::after {
  content: "";
  position: absolute;
  width: 1.5cqw; height: 1.5cqw;
  border: 0.16cqw solid var(--rg-cyan);
  opacity: 0.85;
}
.p-panel::before { top: -0.1cqw; left: -0.1cqw; border-right: none; border-bottom: none; border-top-left-radius: 1.3cqw; }
.p-panel::after  { bottom: -0.1cqw; right: -0.1cqw; border-left: none; border-top: none; border-bottom-right-radius: 1.3cqw; }

/* Text container is clipped (overflow:hidden) so the slide-out / slide-in of the
   HUD copy is masked at the form's edge (#4.3). */
.p-content-wrap { position: absolute; inset: 0; overflow: hidden; border-radius: 1.3cqw; }
.p-content {
  position: absolute;
  inset: 0;
  padding: 7% 8% 18%;
  display: flex;
  flex-direction: column;      /* header + body top, CTA pinned to the bottom */
  opacity: 0;
  visibility: hidden;
}
/* `inherit`, NOT `visible`: visibility is inheritable and a descendant that says
   `visible` un-hides itself inside a hidden ancestor. GSAP hides the whole
   problem stage with autoAlpha when the scene is over, but the active slide was
   overriding that — so its news links stayed hit-testable for the rest of the
   page and a click on empty space beside the phone opened one. Inheriting keeps
   slide switching working while letting the stage's own hiding win. */
.p-content.is-active { opacity: 1; visibility: inherit; }

/* pagination dots (centred in the form footer, between the arrows) */
.p-dots {
  display: flex;
  align-items: center;
  gap: 0.7cqw;
  pointer-events: auto;              /* dots are clickable navigation (desktop) */
}
.p-dot {
  width: 1.05cqw;
  height: 1.05cqw;
  min-width: 9px; min-height: 9px;
  border-radius: 50%;
  background: rgba(148, 163, 180, 0.6);
  padding: 0;
  border: none;
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
  transition: background 0.3s ease, box-shadow 0.3s ease, transform 0.25s ease;
}
.p-dot:hover { background: rgba(33, 212, 237, 0.75); transform: scale(1.25); }
.p-dot:focus-visible { outline: 2px solid rgba(33, 212, 237, 0.8); outline-offset: 3px; }
.p-dot.is-active {
  background: var(--rg-cyan);
  box-shadow: 0 0 10px rgba(33, 212, 237, 0.95);
}

/* top-align so a 1- vs 2-line case title never shifts the avatar vertically */
.p-card-head { display: flex; align-items: flex-start; gap: 12px; gap: 1.0cqw; }
.p-ava {
  flex: none;
  width: 48px; height: 48px;
  width: 5.2cqw; height: 5.2cqw;
  border-radius: 50%;
  border: 0.16cqw solid rgba(33, 212, 237, 0.7);
  box-shadow: 0 0 0.9cqw rgba(33, 212, 237, 0.35);
  background: radial-gradient(circle at 50% 38%, rgba(33,212,237,0.16), rgba(10,18,28,0.9));
  display: flex;
  align-items: center;
  justify-content: center;
  color: #bfe9f6;
}
.p-ava svg { width: 66%; height: 66%; display: block; }

.p-card-titles h3 { font-size: 16px; font-size: 1.32cqw; font-weight: 800; letter-spacing: 0.02em; margin: 0; }
.p-card-titles p  { font-size: 13px; font-size: 1.08cqw; color: rgba(255,255,255,0.66); margin: 2px 0 0; }
.p-body { font-size: 14px; font-size: 1.08cqw; line-height: 1.65; color: rgba(255,255,255,0.88); margin: 1.2cqw 0 0; }
.p-body b { color: #fff; }

/* Case link — a full-width frosted-glass CTA pill (easy to hit, esp. on mobile).
   White label for maximum legibility; the glass fill + border live on ::before.
   A trailing ↗ nudges up-right on hover while the whole pill lifts + glows. */
.p-link {
  position: relative;
  isolation: isolate;                    /* keep ::before z-index local */
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.4cqw;
  width: 100%;
  margin: auto 0 0;            /* top:auto pins the CTA to the card bottom (no jump) */
  padding: 0.7cqw 1.35cqw;
  font-size: 12px; font-size: 0.98cqw;
  font-weight: 700;
  letter-spacing: 0.02em;
  text-decoration: none;
  pointer-events: auto;
  color: #fff;
  transition: filter 0.28s ease, transform 0.2s ease;
}
.p-link::before {                        /* the glass pill itself, behind the text */
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: 999px;
  background: rgba(33, 212, 237, 0.12);
  border: 1px solid rgba(33, 212, 237, 0.42);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  transition: background 0.28s ease, border-color 0.28s ease, box-shadow 0.28s ease;
}
.p-link::after {                         /* external-link arrow */
  content: "↗";
  color: rgba(255, 255, 255, 0.85);
  font-size: 1.05em;
  line-height: 1;
  transition: transform 0.28s cubic-bezier(0.22, 1, 0.36, 1);
}
.p-link:hover { filter: brightness(1.12); transform: translateY(-1px); }
.p-link:hover::before {
  background: rgba(33, 212, 237, 0.22);
  border-color: rgba(33, 212, 237, 0.95);
  box-shadow: 0 0 20px rgba(33, 212, 237, 0.35);
}
.p-link:hover::after { transform: translate(2px, -2px); }
.p-link:active { transform: translateY(0) scale(0.97); }
.p-link:focus-visible { outline: 2px solid rgba(33, 212, 237, 0.75); outline-offset: 2px; border-radius: 999px; }

/* Carousel arrows — frosted rounded squares with a cyan hover glow */
.p-arrow {
  width: 44px; height: 44px;
  width: 3.1cqw; height: 3.1cqw;
  min-width: 38px; min-height: 38px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 24%;
  background: rgba(10, 16, 24, 0.55);
  border: 1px solid rgba(120, 200, 255, 0.35);
  color: #9FDCFF;
  cursor: pointer;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  transition: border-color 0.25s ease, color 0.25s ease, box-shadow 0.25s ease, scale 0.25s ease;
  pointer-events: auto;
  padding: 0;
}
.p-arrow svg { width: 58%; height: 58%; }
/* hover glow only on real pointers — on touch, :hover STICKS after a tap, so the
   last-tapped ("next") arrow would stay lit forever. (pointer:fine) excludes touch. */
@media (hover: hover) and (pointer: fine) {
  .p-arrow:hover { border-color: rgba(33, 212, 237, 0.95); color: #fff; box-shadow: 0 0 18px rgba(33, 212, 237, 0.45); scale: 1.08; }
}
.p-arrow:active { scale: 0.92; }

/* Attention nudge on the "next" arrow — an expanding cyan ring + a lit border/icon
   that say "there's more to read here". JS adds .is-hint on load and strips it on
   the first carousel interaction (any step); it never returns until reload.
   Animates box-shadow/border only, so it can't fight the arrow's `scale` hover. */
@keyframes p-arrow-hint {
  0%   { box-shadow: 0 0 0 0 rgba(33, 212, 237, 0.55); }
  70%  { box-shadow: 0 0 0 12px rgba(33, 212, 237, 0); }
  100% { box-shadow: 0 0 0 0 rgba(33, 212, 237, 0); }
}
.p-arrow.is-hint {
  border-color: rgba(33, 212, 237, 0.95);
  color: #fff;
  animation: p-arrow-hint 1.7s cubic-bezier(0.16, 1, 0.3, 1) infinite;
}
@media (prefers-reduced-motion: reduce) {
  .p-arrow.is-hint { animation: none; }
}

/* form footer: prev · dots · next, front-facing, anchored to the panel bottom */
.p-nav {
  position: absolute;
  left: 8%; right: 8%;
  bottom: 6%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  z-index: 2;
}

/* Mobile bottom sheet — hidden on desktop */
.p-mobile { display: none; }

@media (max-width: 767px) {
  /* SCREEN 2 ON MOBILE — "cinematic evidence band". A 16:9 plate can't full-bleed
     a portrait phone without extreme zoom, so the photo becomes an edge-to-edge
     horizontal band. --band-w drives the crop: bigger = tighter zoom on the wheel /
     less context / taller band (tune live, ~150–185vw). */
  /* Opaque backdrop for the scene — WITHOUT it the shared #bg-layer hero parking
     photo shows around/behind the band, so the wheel strip sat on a SECOND parking
     photo (visual mush). This covers it with a clean dark-slate backdrop; it fades
     in/out with the scene's autoAlpha, so #bg-layer returns for the phone climax. */
  #problem-scene { background: linear-gradient(180deg, #0c1119 0%, #06090f 55%, #04060b 100%); }

  .problem-stage {
    --band-w: 165vw;
    left: calc(var(--band-w) / 2);   /* pins the art's LEFT edge to screen x0 (GSAP adds xPercent:-50) */
    top: 40%;                        /* band vertical placement (GSAP adds yPercent:-50) */
    width: var(--band-w);
    /* no CSS transform here — GSAP owns translate(-50%,-50%) + the Ken Burns scale */
  }

  /* Soft blend: fade the band's top & bottom edges into the backdrop (colours picked
     to match the #problem-scene gradient at those heights). Scrims sit ABOVE the photo
     but only at the edges, so the beam/radar/chip (mid-band) stay crisp. Only on the
     active slide, so stacked inactive slides don't pile up overlays. */
  .p-slide.is-active::before,
  .p-slide.is-active::after {
    content: ""; position: absolute; left: 0; right: 0; height: 48px;
    pointer-events: none; z-index: 4;
  }
  .p-slide.is-active::before { top: 0;    background: linear-gradient(to bottom, #0a0f16, rgba(10, 15, 22, 0)); }
  .p-slide.is-active::after  { bottom: 0; background: linear-gradient(to top,    #05080e, rgba(5, 8, 14, 0)); }

  /* These plates are dark studio shots (subject = left third, rest is dark garage),
     so a zoomed-out band read as a dark blue rectangle. Lift the photo and let it
     fill the band with a clean edge — NO mask-image (it was mishandled on iOS Safari
     and dimmed the edges). The filter hits ONLY the photo; beam/radar/chip are separate. */
  .p-art { filter: brightness(1.2) contrast(1.08) saturate(1.06); }

  /* beam is back ON (it maps into the band; chips already sit at the beam tips).
     Only the desktop in-stage glass form stays hidden — the mobile sheet replaces it. */
  .p-panel { display: none; }

  /* chips keep their desktop base left/top % (tuned to the beam tips) — only resized for phone */
  .p-chip { padding: 8px 12px; border-radius: 12px; box-shadow: 0 12px 28px -8px rgba(0,0,0,0.7); }
  .p-chip-amount { font-size: 18px; }
  .p-chip-label  { font-size: 9px; letter-spacing: 0.08em; }

  .p-mobile {
    display: grid;
    position: absolute;
    left: 12px; right: 12px;
    bottom: calc(78px + env(safe-area-inset-bottom));   /* raised so the scroll-hint badge fits below */
    gap: 12px;
  }
  .p-mcard {
    grid-row: 1; grid-column: 1;
    opacity: 0; visibility: hidden;
    border-radius: 16px;
    border: 1px solid rgba(33, 212, 237, 0.28);
    padding: 14px 16px;
    color: #fff;
    /* Equal card height was not enough on its own: the content sat top-aligned, so
       the CTA and the dots followed the length of the body copy and shifted 20px
       between the short case and the long one on every switch. Column flex plus an
       auto top margin on the link pins both to the bottom edge, which is where the
       longest case already put them. */
    display: flex;
    flex-direction: column;
  }
  .p-mcard.is-active { opacity: 1; visibility: visible; }
  /* all cards share one grid cell → equal height (= the tallest case), so switching
     never reflows the sheet and the card cross-fades in place instead of jumping. */
  .p-mcard .p-card-head { align-items: flex-start; }
  .p-mcard .p-ava { width: 40px; height: 40px; border-width: 2px; }
  .p-mcard h3 { font-size: 13.5px; font-weight: 800; margin: 0; }
  .p-mcard .p-card-titles p { font-size: 11.5px; color: rgba(255,255,255,0.66); margin: 1px 0 0; }
  .p-mcard .p-body { font-size: 12.5px; line-height: 1.6; margin: 9px 0 12px; }
  /* auto top margin: eats the slack on the short cases, collapses to nothing on the
     long one. The 12px gap under the body is what keeps them apart when it does. */
  .p-mcard .p-link { font-size: 13px; margin: auto 0 2px; padding: 11px 20px; gap: 6px; }
  .p-mnav {
    grid-row: 2; grid-column: 1;
    display: flex;
    justify-content: center;
    gap: 22px;
  }
  .p-mnav .p-arrow { width: 44px; height: 44px; }   /* iOS HIG min tap target */

  /* case-count indicator — sits INSIDE each card, centred under the CTA button. Pure
     indicator: plain spans, no click handler (unlike the clickable desktop .p-dot). */
  .p-mdots { display: flex; justify-content: center; gap: 8px; margin-top: 12px; }
  .p-mdot  { width: 7px; height: 7px; border-radius: 50%; background: rgba(148, 163, 180, 0.5);
             transition: background 0.3s ease, box-shadow 0.3s ease; }
  .p-mdot.is-active { background: var(--rg-cyan); box-shadow: 0 0 8px rgba(33, 212, 237, 0.9); }

  /* mobile: headline near the top but with breathing room under the fixed header */
  .p-headline-wrap { justify-content: flex-start; padding: 100px 16px 0; }
  .p-headline { font-size: 14px; letter-spacing: 0.05em; }

  /* scroll-hint badge — shown at the very bottom, below the raised form (where the
     dots used to be). Timeline autoAlpha still fades it in/out with the scene.
     Force one line (iOS renders the font wider and wrapped it to two) + widen. */
  /* All three bottom cues, not just this one. They hand over to each other in the
     same spot, so a different offset per cue makes the pill jump at each handover;
     and without the safe-area inset the last two sat in the home-indicator strip,
     where the phone's own UI covers them. */
  #demo-hint, #scroll-hint, #next-step-badge { bottom: calc(16px + env(safe-area-inset-bottom)); }
}

/* Neon AI bounding box */
.ai-bounding-box {
  border: 2px solid var(--rg-cyan);
  box-shadow: 0 0 15px rgba(33, 212, 237, 0.6), inset 0 0 15px rgba(33, 212, 237, 0.3);
  background: rgba(33, 212, 237, 0.05);
}

.will-t { will-change: transform; }
.will-to { will-change: transform, opacity; }

/* Shared scroll-hint badge — identical frosted pill on the hero (#scroll-hint) and
   the problem scene (#demo-hint): label + a down-chevron that bounces (only the svg). */
.scroll-cue {
  display: inline-flex; align-items: center; gap: 8px;
  pointer-events: none;   /* it's a hint, never a target — must not intercept taps
                             (invisible faded-out badge was blocking the carousel arrows) */
  padding: 6px 16px; border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.12);
  background: rgba(255, 255, 255, 0.05);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  font-size: 11px; font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase;
  color: rgba(255, 255, 255, 0.62); white-space: nowrap;
  text-shadow: 0 1px 8px rgba(0, 0, 0, 0.6);
}
.scroll-cue svg { width: 12px; height: 12px; flex: none; }

/* Clickable cue badges (hero → problem → demo steps). autoAlpha keeps them
   visibility:hidden while faded out, so they never intercept stray taps. */
.scroll-cue--btn { pointer-events: auto; cursor: pointer;
  transition: background .25s ease, color .25s ease, border-color .25s ease; }
.scroll-cue--btn:hover { background: rgba(255,255,255,0.12); color: rgba(255,255,255,0.92);
  border-color: rgba(255,255,255,0.22); }

/* Story chapter titles in the header (mobile only). Absolutely centred over the
   pill rather than swapped INTO the flex row: the brand and the title have very
   different widths, so sharing the row would shift the burger and the language
   toggle every time the chapter changed. Both start hidden — the story fades
   them against #hdr-brand. */
.hdr-chapter { display: none; }
@media (max-width: 767.98px) {
  .hdr-chapter { display: block; position: absolute; left: 50%; top: 50%;
    transform: translate(-50%, -50%); white-space: nowrap; pointer-events: none;
    font-size: 15px; font-weight: 700; letter-spacing: -0.01em; color: #fff;
    opacity: 0; visibility: hidden; }
}

/* The demo phone sits a touch below centre so it clears the fixed header. */
#phone-container { top: 54%; }
/* Mobile hangs it off the HEADER instead of the viewport centre. At 54% the gap
   under the header measured 44.6px while the caption ran 102px up into the
   phone — space sitting idle at the top of a screen that has none to spare.
   GSAP centres the element (yPercent:-50), so `top` is its CENTRE: header bottom
   (16 + 66) + a 16px gap + half the phone. The half is re-derived from the same
   expression the inline width uses (78vh·9/19.5 == 36vh), so it stays exact when
   the 310px or 82vw cap wins instead — a plain vh figure would drift there. */
@media (max-width: 767.98px) {
  #phone-container { top: calc(98px + min(310px, 82vw, 36vh) * 1.083333); }
}

/* Static fallback when the user prefers reduced motion: no scroll story. */
@media (prefers-reduced-motion: reduce) {
  .scroll-viewport { height: 100svh; }
}

/* ---- Page sections (below the cinematic story) ---- */
#page-sections {
  position: relative;
  z-index: 10;               /* above the fixed cinema layer during the crossfade */
  background: var(--rg-bg-deep); /* sections stay dark for now; full light-mode styling is Phase 7 */
}

/* FAQ accordion (native <details> — zero JS) */
.faq-item > summary { list-style: none; cursor: pointer; }
.faq-item > summary::-webkit-details-marker { display: none; }
.faq-item .faq-chevron { transition: transform .3s ease; }
.faq-item[open] .faq-chevron { transform: rotate(180deg); }

/* ===========================================================================
   FEATURES — four panels, one objection each. The paper, the phone screen and
   the folder are DRAWINGS OF PRODUCT SURFACES: they keep their own colours in
   both themes, because a document that restyles itself is not evidence.
   =========================================================================== */
.fx-head { text-align: center; max-width: 720px; margin: 0 auto; }
.fx-head-h { margin: 0; font-size: clamp(28px, 5vw, 44px); font-weight: 800;
  letter-spacing: -0.025em; line-height: 1.1; color: var(--rg-text); }
.fx-head-s { margin: 16px 0 0; font-size: 15px; line-height: 1.6; color: rgba(255,255,255,0.55); }

.fx-grid { display: grid; gap: 18px; margin-top: 40px; grid-template-columns: minmax(0, 1fr); }
/* 24 columns so the pair can be 13/11 and then 11/13: the row rhythm alternates
   which side carries the wider panel, which is what stops a 2x2 reading as a
   spreadsheet. */
@media (min-width: 1000px) {
  .fx-grid { grid-template-columns: repeat(24, minmax(0, 1fr)); gap: 20px; }
  .fx-b1 { grid-column: span 13; }
  .fx-b2 { grid-column: span 11; }
  .fx-b3 { grid-column: span 11; }
  .fx-b4 { grid-column: span 13; }
}

.fx-block { position: relative; overflow: hidden; display: flex; flex-direction: column;
  border-radius: 26px; padding: 26px 26px 28px;
  background: #0B0D11; border: 1px solid rgba(255,255,255,0.055); }
:root[data-theme="light"] .fx-block { background: rgba(255,255,255,0.78); border-color: rgba(0,0,0,0.08); }

.fx-b-head { display: block; }
.fx-b-head--inline { display: flex; align-items: center; gap: 14px; }
.fx-num { display: inline-flex; align-items: center; justify-content: center;
  min-width: 36px; height: 28px; padding: 0 9px; border-radius: 9px;
  font-size: 12px; font-weight: 700; letter-spacing: 0.04em;
  color: var(--rg-neon-blue); border: 1px solid rgba(46,155,255,0.42);
  background: rgba(46,155,255,0.10); }
.fx-b-t { margin: 0; font-size: clamp(19px, 2.2vw, 23px); font-weight: 700;
  letter-spacing: -0.015em; color: var(--rg-text); }
.fx-b-head:not(.fx-b-head--inline) .fx-b-t { margin-top: 14px; }
.fx-b-s { margin: 8px 0 0; font-size: 13.5px; line-height: 1.55; color: rgba(255,255,255,0.52); }
:root[data-theme="light"] .fx-head-s,
:root[data-theme="light"] .fx-b-s { color: rgba(11,14,20,0.58); }

/* ---- the icon + title + line rows, shared by blocks 01 and 03 ---- */
.fx-points { list-style: none; margin: 22px 0 0; padding: 0; }
.fx-point { display: flex; gap: 14px; padding: 16px 0;
  border-top: 1px solid rgba(255,255,255,0.07); }
.fx-point:first-child { border-top: 0; padding-top: 0; }
.fx-point:last-child { padding-bottom: 0; }
.fx-point-ic { flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; border-radius: 13px; color: var(--rg-neon-blue);
  background: rgba(255,255,255,0.045); border: 1px solid rgba(255,255,255,0.075); }
.fx-point-ic svg { width: 21px; height: 21px; }
/* Supplied artwork, pure black on transparent, so it is used as a MASK rather
   than as an image: the colour then comes from `color` like every other icon
   here, which is what lets it be grey on the dark panel and dark on the light
   one instead of being stuck black. */
.fx-ico-nowifi { display: block; width: 22px; height: 22px; background-color: currentColor;
  -webkit-mask: url("nowifi-icon.png") no-repeat center / contain;
  mask: url("nowifi-icon.png") no-repeat center / contain; }
.fx-points--linked .fx-point:first-child .fx-point-ic { color: rgba(255,255,255,0.62); }
:root[data-theme="light"] .fx-points--linked .fx-point:first-child .fx-point-ic { color: rgba(11,14,20,0.55); }
.fx-point-x { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.fx-point-x b { font-size: 14px; font-weight: 700; color: var(--rg-text); }
.fx-point-x i { font-style: normal; font-size: 12.5px; line-height: 1.5; color: rgba(255,255,255,0.56); }
:root[data-theme="light"] .fx-point { border-top-color: rgba(0,0,0,0.08); }
:root[data-theme="light"] .fx-point-ic { background: rgba(0,0,0,0.04); border-color: rgba(0,0,0,0.08); }
:root[data-theme="light"] .fx-point-x i { color: rgba(11,14,20,0.6); }

/* Block 03 links its two points with a dashed run between the icon tiles, so
   "saved here" and "then synced there" read as one sequence. */
.fx-points--linked { position: relative; }
.fx-points--linked .fx-point { border-top: 0; padding: 0 0 38px; }
.fx-points--linked .fx-point:last-child { padding-bottom: 0; }
.fx-points--linked .fx-point:first-child { position: relative; }
.fx-points--linked .fx-point:first-child::after {
  content: ""; position: absolute; left: 21px; top: 44px; bottom: 0; width: 0;
  border-left: 2px dashed rgba(255,255,255,0.16); }
:root[data-theme="light"] .fx-points--linked .fx-point:first-child::after { border-left-color: rgba(0,0,0,0.16); }

/* ---- 01: paper + the pages behind it ---- */
.fx-b1-body { display: grid; gap: 24px; margin-top: 4px; flex: 1; align-items: center; }
@media (min-width: 620px) { .fx-b1-body { grid-template-columns: minmax(0, 0.78fr) minmax(0, 1.22fr); } }
.fx-block-art { perspective: 1500px; }
.fx-stack { position: relative; transform-style: preserve-3d; transform: rotateY(-13deg) rotateX(3deg); }
.fx-doc { position: relative; z-index: 5; width: min(88%, 268px);
  filter: drop-shadow(0 26px 50px rgba(0,0,0,0.55)); }
.fx-pg { position: absolute; top: 5%; border-radius: 13px;
  background: #14171D no-repeat center / cover; border: 1px solid rgba(255,255,255,0.06);
  box-shadow: 0 16px 34px rgba(0,0,0,0.45); }
.fx-pg i { position: absolute; top: 9px; right: 11px; font-style: normal; font-size: 9.5px;
  font-weight: 600; letter-spacing: 0.04em; color: rgba(255,255,255,0.66);
  text-shadow: 0 1px 4px rgba(0,0,0,0.85); }
.fx-pg-2 { left: 62%; right: -2%; height: 88%; transform: translateZ(-24px);
  background-image: url("scratch-macro.jpg"); background-position: 44% 58%; }
.fx-pg-3 { left: 74%; right: -12%; height: 79%; top: 10%; transform: translateZ(-50px);
  background-image: url("review-bike.jpg"); background-position: 60% 40%; }
.fx-pg-4 { left: 86%; right: -22%; height: 70%; top: 15%; transform: translateZ(-76px); }
.fx-pg-4 i { color: rgba(255,255,255,0.52); }

/* The report, at page scale. White in BOTH themes: it is a document, and a
   document that restyles itself is not evidence. Literal hex only in here —
   a var(--rg-*) would turn white-on-white the moment the theme flips. */
.fx-paper { background: #fff; border-radius: 15px; padding: 18px 20px;
  box-shadow: 0 20px 44px rgba(0,0,0,0.34); }
.fx-pv { display: flex; align-items: center; gap: 9px; }
.fx-pv-ic { display: inline-flex; align-items: center; justify-content: center;
  width: 19px; height: 19px; border-radius: 50%; background: #21B15B; color: #fff; flex: none; }
.fx-pv-ic svg { width: 11px; height: 11px; }
.fx-pv-t { font-size: 12px; font-weight: 700; letter-spacing: 0.02em; color: #21B15B;
  white-space: nowrap; }
.fx-pv-badge { margin-left: auto; font-size: 9px; font-weight: 700; color: #fff;
  background: #2E9BFF; border-radius: 6px; padding: 3px 9px; letter-spacing: 0.5px;
  white-space: nowrap; flex: none; }
.fx-veh { margin-top: 14px; padding-top: 14px; border-top: 1px solid #ECECEE; }
.fx-veh b { display: block; font-size: 20px; font-weight: 800; color: #111; letter-spacing: -0.02em; }
.fx-veh i { display: flex; align-items: center; flex-wrap: wrap; gap: 6px;
  margin-top: 5px; font-size: 10.5px; font-style: normal; color: #777; }
.fx-sep { width: 3px; height: 3px; border-radius: 50%; background: #C9C9CE; flex: none; }

.fx-cloud { display: flex; align-items: flex-start; gap: 11px;
  margin-top: 14px; padding-top: 14px; border-top: 1px solid #ECECEE; }
.fx-cloud-qr { flex: none; width: 56px; height: 56px; }
.fx-cloud-qr svg { display: block; width: 100%; height: 100%; }
.fx-cloud-t { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.fx-cloud-t b { font-size: 12px; font-weight: 700; color: #111; }
/* The mock's link blue (#2E9BFF) measures 2.9:1 on white and fails AA. Darkened
   to the same family at 5.8:1 — same read, legible. */
.fx-cloud-u { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 9.5px; color: #125FD4; overflow-wrap: anywhere; }
.fx-cloud-h { margin-top: 5px; font-size: 11px; line-height: 1.45; color: #67676E; }

/* #8A8A90 is what the app uses here; at 10px on white it measures 3.43:1 and
   fails AA, so the page darkens it. */
.fx-seal { display: flex; flex-direction: column; align-items: flex-start; gap: 6px;
  margin-top: 14px; padding-top: 12px; border-top: 1px solid #ECECEE;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 10px; color: #67676E; }
.fx-seal-h { display: inline-flex; align-items: center; gap: 7px;
  font-size: 11px; font-weight: 600; letter-spacing: 0.05em; color: #111; }
.fx-seal-h svg { width: 14px; height: 14px; color: #55555C; flex: none; }
.fx-seal-m { display: inline-flex; align-items: center; gap: 7px; }

/* ---- 02: one frame, wiped between pick-up and return ----
   ONE photo, not two. scratch-macro.jpg is the only shot of this panel there
   has ever been: the "clean" state was already a fake — a feathered ellipse in
   the local paint colour painted over the scratch (see .fx-wipe-clean::after).
   With a wipe the same two fakes do more work, because the eye compares them at
   the SAME pixels instead of across a 30px gap.

   The frame is 19/10 on purpose. It keeps the panel at the height two 5/6
   frames gave it (441x232 at 1440px), so row 1 of the grid does not move — and
   because the source is portrait and `cover` fills the width, one wide frame
   renders the photo at 441/592 = 0.745 scale against the old 194/592 = 0.328.
   The scratch lands on screen 2.27x larger than it was in either thumbnail. */
.fx-cmp { margin: 20px 0 16px; }
/* 26%, not the middle. The scratch is a fixed feature of the photo: it sits at
   40.5% of the width and its marked box spans 120..238px of a 441px frame. Put
   the handle at 50% and the damage falls on the PICK-UP side, i.e. under the
   patch, and the block opens showing two identical halves — the one thing it
   must not do. At 26% (115px) the whole box clears the divider by 5px and the
   PICK-UP caption, which ends at 77px, still has its own air. */
.fx-wipe { position: relative; --x: 26%; --xn: 0.26; }
/* The RETURN state is the BASE layer: the photo exactly as it was shot. */
.fx-wipe-frame { position: relative; overflow: hidden; border-radius: 14px;
  aspect-ratio: 19 / 10; border: 1px solid rgba(255,255,255,0.08);
  background: #14171D url("scratch-macro.jpg") no-repeat 50% 51% / cover; }
/* The PICK-UP state on top, clipped to the left of the handle. `inherit` copies
   the frame's whole background shorthand, so the crop is identical to the pixel
   and the wipe cannot slide the photo under itself. */
/* z-index 2 puts it over the damage box and the RETURN caption, which are z 1
   on the base layer. Without it the box painted straight through the pick-up
   photo — a positioned element with z-index 1 wins over a positioned one with
   z-index auto whatever the source order, so being later in the markup was not
   enough. It also opens a stacking context, which is what keeps the RETURN
   caption underneath instead of letting a higher z-index escape upwards. */
.fx-wipe-clean { position: absolute; inset: 0; z-index: 2; background: inherit;
  clip-path: inset(0 calc(100% - var(--x)) 0 0); }
/* Where the scratch actually is, settled by a luminance profile across the
   panel rather than by eye. Walking left to right, the peak at x=240 measures
   211 while every other column reads 49..119 — and scratch-free stretches of
   this same bodywork measure 82..120. So the scratch is ONE compact spot at
   image (240, 687) = 40.5% / 50.9%; the diagonal "streak" running up to 65% of
   the width is the fairing's crease highlight, which a clean panel has too.
   background-position-X is 50% on purpose: the photo is portrait and cover
   crops it vertically only, so X changes nothing. Y=51% puts the spot in the
   middle of the band, which is why `top` stays put however wide the frame gets.
   PICK-UP is the same panel BEFORE the scratch: a feathered ellipse in the
   local paint colour, rotated to the scratch's own -24deg. Simulated in canvas
   before it was written — peak luminance there drops 188 -> 64, i.e. below the
   82..120 the clean bodywork reads, so what is left is paint, not a patch.
   HEIGHTS are per-frame, so they had to be rescaled with the aspect: the old
   5/6 frame showed 52.4% of the image, this one shows 23.1%, so a span that was
   19% of frame height is 43% of it now. Widths are untouched — the image fills
   the width in both. */
.fx-wipe-clean::after { content: ""; position: absolute; z-index: 1; pointer-events: none;
  left: 40.5%; top: 50.8%; width: 30%; height: 43%;
  transform: translate(-50%, -50%) rotate(-24deg);
  background: radial-gradient(closest-side, #10161B 0%, #10161B 42%,
    rgba(16,22,27,0.82) 68%, rgba(16,22,27,0) 100%); }
/* The label sits INSIDE the box: above it, the frame's overflow clips it. */
.fx-scratch { position: absolute; left: 40.5%; top: 51%; width: 27%; height: 48%;
  transform: translate(-50%, -50%); z-index: 1;
  border: 2px solid #FFCE2B; border-radius: 4px; }
.fx-scratch i { position: absolute; top: -1px; left: -2px; font-style: normal;
  font-size: 8.5px; font-weight: 800; letter-spacing: 0.04em; color: #1A1400;
  background: #FFCE2B; padding: 2px 5px; border-radius: 3px 3px 3px 0;
  transform: translateY(-100%); white-space: nowrap; }
/* A caption leaves when its own photo is gone: drag all the way to PICK-UP and
   RETURN goes, and the other way round.

   It FADES rather than being clipped with its side. Clipping was the first
   version and it is wrong here: the RETURN caption occupies 366..429px of a
   441px frame, so it is only fully covered past 97.3% of travel and spends the
   14% before that sliced down the middle — a half-drawn word reads as a broken
   render, not as a wipe.

   --ta / --tb are the handle positions at which each caption's own side stops
   having room for it, MEASURED from the captions themselves (see main.js), not
   typed in here: the captions are fixed px inside a fluid frame, so the same
   caption crosses that point at 20% of the desktop frame and 29% of the phone
   one. A pair of hand-written breakpoints would have been two more numbers to
   keep in step. The *25 spreads the fade over 4% of travel, which under a drag
   is a fade rather than a blink. */
.fx-wipe-tag { position: absolute; top: 10px; z-index: 3; display: flex;
  flex-direction: column; gap: 2px; padding: 5px 9px; border-radius: 9px;
  background: rgba(8,12,18,0.62); backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px); pointer-events: none; }
.fx-wipe-tag b { font-size: 10px; font-weight: 700; letter-spacing: 0.08em; color: #fff; }
.fx-wipe-tag i { font-style: normal; font-size: 11px; color: rgba(255,255,255,0.72); }
.fx-wipe-tag i.on { color: #6FBBFF; }
.fx-wipe-a { left: 11px;
  opacity: clamp(0, calc((var(--xn) - var(--ta, 0)) * 25 + 1), 1); }
.fx-wipe-b { right: 11px; align-items: flex-end;
  opacity: clamp(0, calc((var(--tb, 1) - var(--xn)) * 25 + 1), 1); }
/* The handle. 2px line + a 30px knob, the same shape this block carried before
   the pair of thumbnails replaced it. */
.fx-wipe-bar { position: absolute; top: 0; bottom: 0; left: var(--x); width: 2px;
  transform: translateX(-1px); z-index: 4; pointer-events: none;
  background: rgba(255,255,255,0.9); box-shadow: 0 0 12px rgba(0,0,0,0.5); }
.fx-wipe-bar::after { content: ""; position: absolute; top: 50%; left: 50%;
  width: 30px; height: 30px; transform: translate(-50%, -50%); border-radius: 50%;
  background: rgba(255,255,255,0.94); box-shadow: 0 2px 10px rgba(0,0,0,0.45); }
.fx-wipe-bar::before { content: ""; position: absolute; top: 50%; left: 50%;
  width: 13px; height: 8px; transform: translate(-50%, -50%);
  background: #12161C; clip-path: polygon(0 50%, 38% 0, 38% 100%, 62% 0, 62% 100%, 100% 50%); }
/* The real control: a range input laid over the frame at zero opacity. It is
   the whole reason this works with a keyboard, with a screen reader and under a
   thumb — a mousemove handler would have had none of the three. */
.fx-wipe-range { position: absolute; inset: 0; width: 100%; height: 100%;
  margin: 0; padding: 0; opacity: 0; cursor: ew-resize; z-index: 5; }
.fx-wipe:has(.fx-wipe-range:focus-visible) .fx-wipe-frame {
  outline: 2px solid var(--rg-cyan); outline-offset: 2px; }

.fx-note { display: flex; align-items: flex-start; gap: 11px; margin-top: auto;
  padding: 13px 14px; border-radius: 13px;
  background: rgba(255,255,255,0.04); border: 1px solid rgba(255,255,255,0.07); }
.fx-note-ic { flex: none; color: var(--rg-neon-blue); display: inline-flex; }
.fx-note-ic svg { width: 19px; height: 19px; }
.fx-note-x { display: flex; flex-direction: column; gap: 3px; }
.fx-note-x b { font-size: 13.5px; font-weight: 700; color: var(--rg-text); }
.fx-note-x i { font-style: normal; font-size: 12.5px; color: rgba(255,255,255,0.56); }
:root[data-theme="light"] .fx-note { background: rgba(0,0,0,0.035); border-color: rgba(0,0,0,0.08); }
:root[data-theme="light"] .fx-note-x i { color: rgba(11,14,20,0.6); }

/* ---- 03: the phone ---- */
/* copy + points | phone. Same shape as blocks 01 and 04: the words on the left,
   the product surface on the right. The mock puts the points in a third column;
   at this container width that costs the phone its proportions — see the note in
   the markup. */
.fx-b3 { display: grid; gap: 20px; align-items: center; }
@media (min-width: 720px) {
  .fx-b3 { grid-template-columns: minmax(0, 1.06fr) minmax(0, 1fr); gap: 20px; }
}
/* The badges of 03 and 04 line up with each other because both copy columns
   start at the panel's top padding; the phone and the folder beside them stay
   centred. */
.fx-b3-copy, .fx-b4-copy { align-self: start; }
@media (min-width: 720px) {
  /* The cut has to land on empty phone body, not on the offline card, so the
     screen carries dead space below it that the panel then eats. */
  .fx-b3 .fx-phone { align-self: start; margin-bottom: -74px; }
  .fx-b3 .fx-ph-screen { padding-bottom: 68px; }
}
/* The phone, from the designer's block-03 sketch. Everything inside it is a
   drawing of a product surface, so it keeps its own colours in both themes for
   the same reason the paper in block 01 stays white. */
.fx-phone { position: relative; border-radius: 30px; padding: 6px; background: #16181E;
  border: 1px solid rgba(255,255,255,0.11); box-shadow: 0 22px 48px rgba(0,0,0,0.5); }
.fx-ph-notch { position: absolute; z-index: 2; top: 11px; left: 50%; transform: translateX(-50%);
  width: 38%; height: 12px; border-radius: 99px; background: #0A0C10; }
.fx-ph-notch::before { content: ""; position: absolute; top: 50%; left: 22%;
  transform: translateY(-50%); width: 5px; height: 5px; border-radius: 50%;
  background: radial-gradient(circle at 34% 32%, #33465C 0%, #16202B 55%, #080B0F 100%);
  box-shadow: 0 0 0 0.5px rgba(255,255,255,0.10); }
.fx-ph-notch::after { content: ""; position: absolute; top: 50%; left: 42%;
  transform: translateY(-50%); width: 30%; height: 2.5px; border-radius: 2px;
  background: rgba(255,255,255,0.10); }
.fx-ph-screen { border-radius: 25px; padding: 9px 9px 10px; background: #0A0C10;
  border: 1px solid rgba(255,255,255,0.05); }

.fx-ph-status { display: flex; align-items: center; justify-content: space-between;
  padding: 3px 4px 0; font-size: 8.5px; font-weight: 600; color: #fff; }
.fx-ph-status-r { display: inline-flex; align-items: center; gap: 4px; }
.fx-ph-status-r svg { width: 8px; height: 8px; }
.fx-ph-batt { width: 15px; height: 8px; border-radius: 2.5px; border: 1px solid rgba(255,255,255,0.55);
  position: relative; }
.fx-ph-batt::before { content: ""; position: absolute; inset: 1.5px; border-radius: 1px; background: #fff; }
.fx-ph-batt::after { content: ""; position: absolute; top: 2.5px; right: -2.5px; width: 1.5px; height: 3px;
  border-radius: 0 1px 1px 0; background: rgba(255,255,255,0.55); }

.fx-ph-t { margin: 9px 0 0; text-align: center; font-size: 12.5px; font-weight: 700; color: #fff; }
.fx-ph-n { display: flex; align-items: center; justify-content: center; gap: 3px;
  margin: 4px 0 0; font-size: 12.5px; font-weight: 700; }
.fx-ph-n b { color: var(--rg-neon-blue); }
.fx-ph-n u { text-decoration: none; color: rgba(46,155,255,0.55); font-weight: 500; }
.fx-ph-bar { display: block; height: 4px; margin-top: 8px; border-radius: 99px;
  background: rgba(255,255,255,0.10); }
.fx-ph-bar i { display: block; width: 86%; height: 100%; border-radius: 99px;
  background: var(--rg-neon-blue); }

/* The zones sit around the vehicle rather than in a list: it is a map, and a
   map says "every side of it" in a way seven rows of text do not. */
.fx-ph-map { position: relative; margin-top: 10px; aspect-ratio: 1 / 1.28; }
.fx-ph-ring { position: absolute; inset: 10% 18% 26%; border-radius: 50%;
  border: 1px dashed rgba(255,255,255,0.13); }
.fx-ph-ring::before { content: ""; position: absolute; inset: -14%; border-radius: 50%;
  background: radial-gradient(closest-side, rgba(46,155,255,0.22), rgba(46,155,255,0) 72%); }
/* Sat slightly above centre: the two bottom labels and the progress pill need
   the room, and a top-down vehicle reads fine off-centre. */
.fx-ph-veh { position: absolute; left: 50%; top: 43%; transform: translate(-50%, -50%);
  height: 50%; width: auto; }

.fx-zn { position: absolute; display: flex; flex-direction: column; align-items: center; gap: 3px; }
.fx-zn em { font-style: normal; font-size: 8px; font-weight: 600; color: rgba(255,255,255,0.9);
  white-space: nowrap; }
.fx-zn i { display: inline-flex; align-items: center; justify-content: center;
  width: 15px; height: 15px; border-radius: 50%; background: #22B04E; color: #fff; }
.fx-zn i svg { width: 9px; height: 9px; }
.fx-zn-front  { top: 0;    left: 50%; transform: translateX(-50%); }
.fx-zn-left   { top: 24%;  left: 0; }
.fx-zn-right  { top: 24%;  right: 0; }
/* Rear at the tail, wheels on the lower flank — the placement the report
   (.zl-rear / .zl-wheels, .zm-rear / .zm-wheels) and the summary plate already
   use. This phone had the two swapped, so the same vehicle was labelled two
   different ways in three places on one page. */
.fx-zn-rear   { bottom: 13%; left: 50%; transform: translateX(-50%); }
.fx-zn-seat   { top: 52%;  right: 0; }
.fx-zn-wheels { top: 52%;  left: 0; }
.fx-ph-count { position: absolute; bottom: 0; left: 50%; transform: translateX(-50%);
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 28px; height: 20px; padding: 0 6px; border-radius: 99px;
  background: var(--rg-neon-blue); color: #fff; font-size: 9px; font-weight: 700; }

.fx-ph-card { display: flex; align-items: center; gap: 6px; margin-top: 10px;
  padding: 7px; border-radius: 13px; background: rgba(255,255,255,0.05);
  border: 1px solid rgba(255,255,255,0.07); }
.fx-ph-card-ic { flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; border-radius: 50%; background: rgba(46,155,255,0.16);
  color: var(--rg-neon-blue); }
.fx-ph-card-ic svg { width: 13px; height: 13px; }
.fx-ph-card-ic .fx-ico-nowifi { width: 14px; height: 14px; }
.fx-ph-card-x { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.fx-ph-card-x b { font-size: 8px; font-weight: 700; letter-spacing: 0.03em;
  color: var(--rg-neon-blue); white-space: nowrap; }
.fx-ph-card-x i { font-style: normal; font-size: 8px; color: rgba(255,255,255,0.62);
  white-space: nowrap; }
.fx-ph-card-go { margin-left: auto; flex: none; display: inline-flex; align-items: center; gap: 2px;
  padding: 5px 6px; border-radius: 8px; background: rgba(255,255,255,0.09);
  font-size: 8px; font-weight: 600; color: #fff; white-space: nowrap; }
.fx-ph-card-go svg { width: 8px; height: 8px; }

/* ---- 04: the document list and the folder ---- */
.fx-b4 { display: grid; gap: 20px; align-items: center; }
@media (min-width: 720px) {
  /* The artwork is wider than the list in the sketch, and it is width-limited
     here (contain), so the split leans its way. */
  .fx-b4 { grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr); gap: 24px; }
}
.fx-b4-copy .fx-docs { margin-top: 20px; }
.fx-docs { list-style: none; margin: 0; padding: 0; border-radius: 14px; overflow: hidden;
  border: 1px solid rgba(255,255,255,0.07); background: rgba(255,255,255,0.03); }
.fx-doc-row { display: flex; align-items: center; gap: 12px; padding: 13px 14px;
  font-size: 13.5px; color: var(--rg-text);
  border-top: 1px solid rgba(255,255,255,0.06); }
.fx-doc-row:first-child { border-top: 0; }
.fx-doc-go { margin-left: auto; display: inline-flex; color: rgba(255,255,255,0.3); }
.fx-doc-go svg { width: 15px; height: 15px; }
:root[data-theme="light"] .fx-docs { border-color: rgba(0,0,0,0.08); background: rgba(0,0,0,0.025); }
:root[data-theme="light"] .fx-doc-row { border-top-color: rgba(0,0,0,0.07); }
:root[data-theme="light"] .fx-doc-go { color: rgba(11,14,20,0.3); }

/* ---- 04: the document list and the card holder ---- */
/* The list's first row is the active one, as in the sketch: it is what a reader
   would tap first and it tells the eye the list is live, not a bullet list. */
.fx-doc-row:first-child { background: rgba(46,155,255,0.09);
  border: 1px solid rgba(46,155,255,0.34); border-radius: 13px; }
.fx-doc-row:nth-child(2) { border-top: 0; }
.fx-doc-ic { flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; border-radius: 50%; color: var(--rg-neon-blue);
  background: rgba(46,155,255,0.13); }
.fx-doc-ic svg { width: 16px; height: 16px; }
:root[data-theme="light"] .fx-doc-row:first-child { background: rgba(46,155,255,0.10);
  border-color: rgba(46,155,255,0.4); }

.fx-b4-art { display: flex; flex-direction: column; }
/* The artwork is a transparent cutout with its own glow, so it sits straight on
   the panel with nothing behind it. Aspect ratio is the trimmed file's own. */
.fx-wallet { aspect-ratio: 968 / 973; background-repeat: no-repeat;
  background-position: center; background-size: contain;
  background-image: image-set(
    url("docs-wallet.avif") type("image/avif"),
    url("docs-wallet.webp") type("image/webp"),
    url("docs-wallet.png") type("image/png"));
  background-image: -webkit-image-set(
    url("docs-wallet.avif") type("image/avif"),
    url("docs-wallet.webp") type("image/webp"),
    url("docs-wallet.png") type("image/png")); }

.fx-wallet-note { display: flex; align-items: center; justify-content: center; gap: 10px;
  margin: 14px 0 0; font-size: 12px; line-height: 1.45; color: rgba(255,255,255,0.56); }
.fx-wallet-note-ic { flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; border-radius: 50%; color: var(--rg-neon-blue);
  background: rgba(46,155,255,0.13); }
.fx-wallet-note-ic svg { width: 15px; height: 15px; }
:root[data-theme="light"] .fx-wallet-note { color: rgba(11,14,20,0.6); }

/* The four panels cross the threshold together, so without a stagger they arrive
   as one slab. Border-color is pinned to 0s so hover stays instant. These carry
   .reveal AND .fx-block on the same element and .reveal is declared later in this
   file, so the whole shorthand has to be restated to win. */
#features .fx-block { transition: opacity .7s cubic-bezier(0.16, 1, 0.3, 1),
  transform .7s cubic-bezier(0.16, 1, 0.3, 1), border-color .25s ease; }
#features .fx-block:nth-of-type(2) { transition-delay: .07s, .07s, 0s; }
#features .fx-block:nth-of-type(3) { transition-delay: .14s, .14s, 0s; }
#features .fx-block:nth-of-type(4) { transition-delay: .21s, .21s, 0s; }

/* Below the two-column width the fan has nowhere to go: flatten the tilt and
   drop the deepest page. A 3D fan squeezed into 360px is a smear, not a stack. */
@media (max-width: 719.98px) {
  .fx-b3, .fx-b4 { display: flex; }
  .fx-b4-copy .fx-docs { margin-top: 18px; }
  /* Every child of .fx-wallet is absolutely positioned, so it has no intrinsic
     width; once the panel stops being a grid, the inherited align-items:center
     collapses the column to zero. Give it an explicit width here and the aspect
     ratio supplies the height. */
  .fx-b4-art { width: min(320px, 100%); }
}
@media (max-width: 619.98px) {
  .fx-block { padding: 22px 18px 24px; border-radius: 22px; }
  .fx-stack { transform: none; }
  .fx-doc { width: 90%; }
  .fx-pg-4 { display: none; }
  .fx-pg-2 { left: 66%; right: -4%; }
  .fx-pg-3 { left: 82%; right: -12%; }
  /* One column wide, 19/10 would be a 176px letterbox strip. 3/2 gives the
     photo back its height; the panel is alone in its row here, so growing is
     free. The scratch stays put — it is pinned to the middle of the band.
     Heights are re-derived, not guessed: both spans must cover the same SOURCE
     region as on desktop (box 148px, patch 133px of a 1350px-tall image), and
     at 297x198 the photo renders at 297/592 = 0.502, so 148*0.502/198 = 37.5%
     and 133*0.502/198 = 33.7%. Widths never change — the image fills the width
     at every frame size, so a width percentage is already a fraction of it. */
  /* The frame is a third narrower here, so its chrome has to be too. At the
     desktop size the PICK-UP caption needs 87px of a 297px frame — more than
     the 77px the resting handle leaves it — and it sat at 0.15 opacity, which
     reads as a broken render rather than as a caption. Measured, not guessed:
     the fade threshold is (11 + caption + 10) / frame, so the caption has to
     come in under 56px for the handle's resting 26% to clear it. */
  .fx-wipe-tag { padding: 4px 7px; }
  .fx-wipe-tag b { font-size: 9px; letter-spacing: 0.06em; }
  .fx-wipe-tag i { font-size: 10px; }
  /* 8px, not 11: at 11 the caption came out at exactly the resting handle
     position and sat at 0.99 opacity — correct, but one font metric away from
     dipping under on a device that measures the word differently. */
  .fx-wipe-a { left: 8px; }
  .fx-wipe-b { right: 8px; }
  .fx-wipe-frame { aspect-ratio: 3 / 2; }
  .fx-wipe-clean::after { height: 33.7%; }
  .fx-scratch { height: 37.5%; }
}

@media (prefers-reduced-motion: reduce) {
  #features .fx-block { transition: none; transition-delay: 0s; }
}

/* ===========================================================================
   B2C → B2B — the audience switch, made physical.
   =========================================================================== */
/* The whole B2B stretch sits on its own surface, not just a thin rule. A band
   alone was too quiet to register as "this part is not addressed to you". */
.b2b-zone { margin: 56px 0; background: rgba(255, 255, 255, 0.032);
  border-top: 1px solid rgba(255, 255, 255, 0.09);
  border-bottom: 1px solid rgba(255, 255, 255, 0.09); }
:root[data-theme="light"] .b2b-zone { background: rgba(0, 0, 0, 0.035);
  border-color: rgba(0, 0, 0, 0.10); }
.b2b-zone > .section { padding-top: 8px; }
.b2b-break { display: flex; justify-content: center; padding: 30px 24px 0; }
.b2b-break-mark { display: inline-flex; align-items: center; gap: 10px;
  padding: 7px 16px; border-radius: 999px;
  background: rgba(33, 212, 237, 0.10); border: 1px solid rgba(33, 212, 237, 0.28);
  font-size: 11.5px; font-weight: 700; letter-spacing: 0.13em; text-transform: uppercase;
  color: var(--rg-cyan); }
.b2b-break-mark svg { width: 16px; height: 16px; flex: none; }

/* --- /fleet dashboard mock. A window, a rail, a feed and a map: the shape of the
   product, not three numbers in rounded boxes. */
.fleet-mock { border-radius: 16px; overflow: hidden;
  border: 1px solid var(--rg-glass-border); background: #0A0D12;
  box-shadow: 0 26px 60px rgba(0, 0, 0, 0.5); }
:root[data-theme="light"] .fleet-mock { background: #0A0D12; }
.fm-chrome { display: flex; align-items: center; gap: 12px; padding: 9px 12px;
  background: rgba(255, 255, 255, 0.05); border-bottom: 1px solid rgba(255, 255, 255, 0.07); }
.fm-dots { display: flex; gap: 5px; flex: none; }
.fm-dots i { width: 8px; height: 8px; border-radius: 50%; background: rgba(255, 255, 255, 0.18); }
.fm-url { flex: 1; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 10px; color: rgba(255, 255, 255, 0.45); text-align: center;
  background: rgba(255, 255, 255, 0.05); border-radius: 6px; padding: 3px 8px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fm-body { display: flex; }
.fm-rail { flex: none; width: 34px; padding: 12px 0; display: flex; flex-direction: column;
  align-items: center; gap: 10px; border-right: 1px solid rgba(255, 255, 255, 0.07); }
.fm-rail-i { width: 15px; height: 15px; border-radius: 5px; background: rgba(255, 255, 255, 0.10); }
.fm-rail-i.is-on { background: var(--rg-cyan); }
.fm-main { flex: 1; min-width: 0; padding: 13px 14px 15px; }
.fm-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 9px; }
.fm-stat { border-radius: 9px; background: rgba(255, 255, 255, 0.045); padding: 8px 10px; }
.fm-stat b { display: block; font-size: 19px; font-weight: 800; color: #fff; line-height: 1.1; }
.fm-stat span { display: block; margin-top: 2px; font-size: 9.5px; color: rgba(255, 255, 255, 0.5); }
.fm-stat.is-alert b { color: var(--rg-cyan); }
.fm-cols { display: grid; grid-template-columns: 1.55fr 1fr; gap: 9px; margin-top: 11px; }
.fm-h { font-size: 9px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  color: rgba(255, 255, 255, 0.38); margin-bottom: 7px; }
.fm-feed, .fm-map { border-radius: 9px; background: rgba(255, 255, 255, 0.03); padding: 9px 10px; }
.fm-row { display: flex; align-items: center; gap: 8px; padding: 5px 0;
  border-top: 1px solid rgba(255, 255, 255, 0.055); }
.fm-feed .fm-row:first-of-type { border-top: 0; }
.fm-pl { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 9.5px; color: rgba(255, 255, 255, 0.85); flex: none; }
.fm-nm { flex: 1; min-width: 0; font-size: 10px; color: rgba(255, 255, 255, 0.5);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fm-st { flex: none; font-size: 8.5px; font-weight: 700; padding: 2px 7px; border-radius: 999px; }
.fm-st.is-ok { color: #33D166; background: rgba(51, 209, 102, 0.14); }
.fm-st.is-warn { color: var(--rg-yellow); background: rgba(255, 214, 10, 0.15); }
.fm-map-body { position: relative; display: flex; align-items: center; justify-content: center;
  min-height: 96px; }
.fm-map-body img { height: 92px; width: auto; opacity: 0.85; }
/* Dots land one after another, so the map reads as filling in rather than as a
   picture that was always there. Opacity only: the dots carry translateX for
   centring, and animating transform would fight it. */
.fm-dot { position: absolute; width: 7px; height: 7px; border-radius: 50%;
  background: #33D166; box-shadow: 0 0 0 3px rgba(51, 209, 102, 0.2);
  opacity: 0; transition: opacity .4s ease; }
.reveal.in .fm-dot { opacity: 1; }
.reveal.in .fm-dot-1 { transition-delay: .45s; }
.reveal.in .fm-dot-2 { transition-delay: .6s; }
.reveal.in .fm-dot-3 { transition-delay: .75s; }
.fm-dot.is-warn { background: var(--rg-yellow); box-shadow: 0 0 0 3px rgba(255, 214, 10, 0.22); }
.fm-dot-1 { top: 16%; left: 50%; transform: translateX(-50%); }
.fm-dot-2 { top: 74%; left: 50%; transform: translateX(-50%); }
.fm-dot-3 { top: 46%; left: calc(50% + 15px); }
/* Belt and braces: with reduced motion AND no JS, .in never lands, and the dots
   would be the one thing on the map that never shows up. */
@media (prefers-reduced-motion: reduce) { .fm-dot { opacity: 1; transition: none; } }

/* ===========================================================================
   SECURITY — four claims in a list, not four cards. Green checks because the
   claims are verified facts about the product; a cyan rounded-square icon over
   each one was the tenth repeat of the same badge on this page.
   =========================================================================== */
.sec-claims { display: grid; gap: 26px 44px; grid-template-columns: 1fr; }
/* Three claims, so one row of three rather than 2x2 with a hole in it. The
   fourth used to be the GDPR / 152-FZ line; it came out because the site cannot
   make a legal claim true on its own — that needs a policy, an export path and
   a delete path first. Put one back and this goes to repeat(2, 1fr). */
@media (min-width: 768px) { .sec-claims { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 26px 32px; } }
.sec-claim { display: flex; gap: 14px; align-items: flex-start; }
.sec-ic { flex: none; width: 22px; height: 22px; margin-top: 2px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  color: #33D166; background: rgba(51, 209, 102, 0.14); }
.sec-ic svg { width: 12px; height: 12px; }

/* Progressive disclosure for the architecture terms. */
.sec-tech { margin-top: 34px; border-top: 1px solid var(--rg-glass-border);
  border-bottom: 1px solid var(--rg-glass-border); }
.sec-tech > summary { list-style: none; cursor: pointer; padding: 16px 2px;
  display: flex; align-items: center; gap: 8px;
  font-size: 14px; font-weight: 600; color: var(--rg-cyan); }
.sec-tech > summary::-webkit-details-marker { display: none; }
.sec-chevron { width: 15px; height: 15px; transition: transform .3s ease; }
.sec-tech[open] .sec-chevron { transform: rotate(180deg); }
.sec-tech-body { padding: 0 2px 20px; display: grid; gap: 16px; }
@media (min-width: 768px) { .sec-tech-body { grid-template-columns: 1fr 1fr; gap: 18px 44px; } }
.sec-tech-body dt { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12px; color: var(--rg-text); }
/* Not --rg-text-2 (55% white): at 13px that lands under 4.5:1. */
.sec-tech-body dd { margin: 5px 0 0; font-size: 13px; line-height: 1.6;
  color: rgba(255, 255, 255, 0.64); }
:root[data-theme="light"] .sec-tech-body dd { color: rgba(11, 14, 20, 0.64); }
@media (prefers-reduced-motion: reduce) { .sec-chevron { transition: none; } }

/* Footer download strip. No QR yet: a QR is a promise that scanning it installs
   the app, and every store link on this site is still href="#" because the app is
   not published. A code that encodes nothing is worse than no code. */
.foot-get { display: flex; flex-wrap: wrap; align-items: center; gap: 20px 28px;
  padding-bottom: 34px; margin-bottom: 34px; border-bottom: 1px solid var(--rg-glass-border); }
.foot-get-t { flex: 1 1 320px; min-width: 0; }
.foot-get-b { display: flex; flex-wrap: wrap; gap: 10px; }

/* Footer link columns. A 14px line is a 17px tap target, and the footer is the
   one place on the page where three of them stack 10px apart — measured at 375px:
   Features 57x17, Pricing 45x17, For business 84x17. Under a pointer that is fine
   and the compact column is the better footer, so the row only grows where the
   input is a thumb. 44px is the iOS HIG minimum the carousel arrows already use
   (.p-mnav .p-arrow); the existing 10px gap between rows covers HIG's separation. */
@media (max-width: 767.98px) {
  .foot-links > li > a { display: flex; align-items: center; min-height: 44px; }
}

/* ===========================================================================
   LEGAL PAGES — privacy and terms. Long-form prose, which the rest of this site
   has none of, so it gets its own measure rather than the section grid's.

   34rem, and the number is measured rather than estimated. The first attempt was
   42rem on the reasoning that a character averages half its font size; measuring
   the actual face at 16px gives 7.84px per character, so 42rem was running 86
   characters to the line against the 45..75 a reader tracks comfortably. At
   34rem the line is 69. Colours come from the tokens, so these pages follow the
   theme without a second set of rules.
   =========================================================================== */
.legal { max-width: 34rem; }
.legal-eyebrow { margin: 0; font-size: 12px; font-weight: 700; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--rg-cyan); }
.legal-h1 { margin: 14px 0 0; font-size: clamp(30px, 5vw, 42px); font-weight: 800;
  letter-spacing: -0.025em; line-height: 1.12; color: var(--rg-text); }
.legal-lead { margin: 18px 0 0; font-size: 17px; line-height: 1.65; color: rgba(255,255,255,0.62); }
.legal-updated { margin: 20px 0 0; padding-bottom: 26px; font-size: 13px;
  color: rgba(255,255,255,0.55); border-bottom: 1px solid var(--rg-glass-border); }
.legal h2 { margin: 40px 0 0; font-size: 19px; font-weight: 700; letter-spacing: -0.015em;
  color: var(--rg-text); }
.legal p { margin: 14px 0 0; font-size: 16px; line-height: 1.7; color: rgba(255,255,255,0.72); }
.legal strong { font-weight: 700; color: var(--rg-text); }
.legal ul { margin: 14px 0 0; padding: 0 0 0 20px; }
.legal li { margin-top: 9px; font-size: 16px; line-height: 1.7; color: rgba(255,255,255,0.72); }
.legal code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 14px; padding: 1px 5px; border-radius: 5px;
  background: rgba(255,255,255,0.07); color: var(--rg-text); }
/* The one place on the site where a link sits inside a paragraph, so it needs an
   underline: colour alone is not a signal a colour-blind reader can use. */
.legal a { color: var(--rg-cyan); text-decoration: underline; text-underline-offset: 3px; }
.legal a:hover { text-decoration-thickness: 2px; }
:root[data-theme="light"] .legal-lead,
:root[data-theme="light"] .legal-updated { color: rgba(11,14,20,0.62); }
:root[data-theme="light"] .legal p,
:root[data-theme="light"] .legal li { color: rgba(11,14,20,0.74); }
:root[data-theme="light"] .legal code { background: rgba(0,0,0,0.06); }

/* Long-jump cover for the pinned story. Always the deep background, never the
   theme's page colour: the destination is a cinematic scene that stays dark in
   light mode too, so fading through white would be a flash on the way in. */
#story-cut { position: fixed; inset: 0; z-index: 45; background: var(--rg-bg-deep);
  opacity: 0; visibility: hidden; pointer-events: none; }

/* Pricing fleet-size slider */
input[type="range"].fleet-range { accent-color: var(--rg-cyan); }

/* Pricing audience groups. The label is a real subheading with a rule running off
   to the right, NOT another tracked micro-eyebrow: the page already carried one of
   those over every section below the story, which is most of why the lower half
   read as a template. Tokens, not hard-coded white, so light mode follows. */
.pr-grp { display: flex; align-items: center; gap: 14px;
  font-size: 15px; font-weight: 700; letter-spacing: -0.01em; color: var(--rg-text); }
.pr-grp::after { content: ""; flex: 1 1 auto; height: 1px; background: var(--rg-glass-border); }
/* Page-level cards had NO hover state at all before this — every :hover in this
   file belonged to the pinned story or the in-phone screens. */
.pr-card { transition: transform .28s cubic-bezier(0.22, 1, 0.36, 1), border-color .28s ease; }
.pr-card:hover { transform: translateY(-2px); border-color: rgba(255, 255, 255, 0.2); }
:root[data-theme="light"] .pr-card:hover { border-color: rgba(0, 0, 0, 0.16); }
/* The white iOS badge loses its edge on the light page background. */
@media (prefers-reduced-motion: reduce) {
  .pr-card, .pr-card:hover { transition: none; transform: none; }
}

/* ---- B2B onboarding wizard (mockup) ---- */
.wiz-capsule {
  padding: 7px 14px;
  border-radius: 9999px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  font-size: 13px;
  color: rgba(255, 255, 255, 0.7);
  transition: all .2s ease;
}
.wiz-capsule:hover { border-color: rgba(255, 255, 255, 0.3); }
.wiz-capsule.active { border-color: var(--rg-cyan); color: #fff; background: rgba(33, 212, 237, 0.14); }
.wizard-dot { background: rgba(255, 255, 255, 0.16); transition: background .3s ease; }
.wizard-dot.active { background: var(--rg-cyan); }

/* ============================================================================
   IN-PHONE LIVE APP UI — guided-scan story (ported/scaled from figma-export).
   Four stacked screens inside #phone-container's screen; GSAP fades between
   them. Sized in px tuned for the ~248–310px phone width. --rg-yellow is the
   annotation box colour (matches the app's Define-Damage-Details box).
   ========================================================================= */
:root { --rg-yellow: #FFD60A; }

.rgapp-screen { position: absolute; inset: 0; overflow: hidden; }
#app-summary { background: #09101B; }
#app-pdf { background: #000; }

/* --- viewfinder feed (colour-boosted so the live shot pops vs the muted hero) */
.vf-feed { position: absolute; inset: 0; background-size: cover; }
#vf-wide { background-position: 19% 56%; filter: saturate(1.4) brightness(1.1) contrast(1.05); }
/* scratch-macro.jpg is already cut to the screen's aspect — cover shows it whole.
   Same colour boost as the wide feed so the crossfade doesn't shift tone. */
#vf-macro { width: 100%; height: 100%; object-fit: cover; object-position: 50% 50%; opacity: 0;
  filter: saturate(1.4) brightness(1.1) contrast(1.05); }
.vf-scrim-top { position: absolute; top: 0; left: 0; right: 0; height: 22%;
  background: linear-gradient(180deg, rgba(0,0,0,0.5), transparent); }
.vf-scrim-bottom { position: absolute; bottom: 0; left: 0; right: 0; height: 40%;
  background: linear-gradient(0deg, rgba(0,0,0,0.72), transparent); }

/* --- top chrome: ✕ · Photo/Video · Done --- */
.cam-chrome { position: absolute; top: 30px; left: 11px; right: 11px; z-index: 6;
  display: flex; align-items: center; justify-content: space-between; }
.cam-btn { width: 30px; height: 30px; border-radius: 50%; display: flex; align-items: center;
  justify-content: center; font-size: 13px; color: #fff; background: rgba(30,30,32,0.7);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); }
/* The segment is pinned to the screen's centre rather than left to flex
   space-between: the X (30px) and Done are different widths, so space-between
   parked the pill ~14px left of centre. Both side controls are slimmer now so
   the three sit with comfortable gaps. */
.cam-seg { position: absolute; left: 50%; transform: translateX(-50%);
  display: flex; background: rgba(30,30,32,0.7); border-radius: 999px; padding: 3px;
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); }
.cam-seg b { font-size: 11.5px; font-weight: 600; padding: 4.5px 12px; border-radius: 999px;
  color: rgba(255,255,255,0.85); }
.cam-seg b.on { background: #fff; color: #000; }
.cam-done { padding: 5.5px 9px; border-radius: 999px; font-size: 11px; font-weight: 600;
  color: rgba(255,255,255,0.45); background: rgba(30,30,32,0.7);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); }

/* --- centred zone guide card: horizontal rectangle, art dead-centre --- */
.zone-guide { position: absolute; top: 72px; left: 50%; transform: translateX(-50%); z-index: 5;
  width: 118px; text-align: center; padding: 8px 10px 7px; border-radius: 14px;
  background: rgba(28,28,30,0.72); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); }
/* zone-right.svg is the app's own camera-hint outline, recoloured white at the
   source with a 55u stroke to thicken the traced contours. It replaces a raster
   that was being forced white by `brightness(0) invert(1)` — that burned out the
   anti-aliasing and read as a low-quality image. Vector, so it stays crisp. */
.zone-guide img { display: block; margin: 0 auto; width: 78px; height: 46px;
  object-fit: contain; opacity: 0.95; }
.zone-guide span { display: block; margin-top: 4px; font-size: 10.5px; font-weight: 600; color: #fff; }

/* --- vertical zoom control (compact, roomy spacing) --- */
.cam-zoom { position: absolute; right: 9px; top: 54%; z-index: 6; width: 24px;
  display: flex; flex-direction: column; align-items: center; gap: 12px; padding: 11px 0;
  border-radius: 14px; background: rgba(0,0,0,0.5); border: 0.5px solid rgba(255,255,255,0.18); }
.cam-zoom span { font-size: 8px; font-weight: 600; color: rgba(255,255,255,0.9); }
.cam-zoom span.on { width: 17px; height: 17px; border-radius: 50%; background: #fff; color: #000;
  display: flex; align-items: center; justify-content: center; font-size: 7.5px; font-weight: 700; }

/* --- zone counter ("0 of 7 zones") sits just above the chip strip --- */
.zone-count { position: absolute; left: 12px; bottom: 140px; z-index: 6;
  /* It sits free over the photo with nothing to collide with, so the only reason
     it was 8.5px was habit. */
  font-size: 9.2px; font-weight: 600; color: rgba(255,255,255,0.95);
  text-shadow: 0 1px 4px rgba(0,0,0,0.6); }

/* --- zone chips: fixed-width, horizontally scrolling strip. The track is
   pinned at the phone's horizontal centre (left:50%) and shifted left by the
   selected chip's centre (chip pitch 78px → Right Side at index 3 = 270px), so
   "Right Side" always sits dead-centre regardless of phone width, like the app
   (Rear · Right Side · Seat visible, more zones off-screen). --- */
/* Chip geometry lives here as tokens because the track's offset is DERIVED from
   it. It used to be a bare translateX(-270px), a number hand-computed for 72px
   chips; widening them to 84px silently pushed the active zone off centre, since
   nothing tied the two values together. Now the offset is expressed as "start of
   chip 3, plus half a chip", so changing --chip-w keeps the selected zone
   centred by construction. */
.zone-strip { position: absolute; left: 0; right: 0; bottom: 88px; z-index: 6;
  height: 46px; overflow: hidden;
  --chip-w: 84px; --chip-gap: 6px; --active-chip: 3; }   /* 3 = Right Side */
.zone-track { position: absolute; left: 50%; top: 0; display: flex;
  gap: var(--chip-gap);
  transform: translateX(calc(-1 * (var(--active-chip) * (var(--chip-w) + var(--chip-gap))
                                   + var(--chip-w) / 2))); }
/* 84, up from 72. At 72 the label had 43.8px to live in, and "Dashboard" needed
   44.9px even at the old 8.5px size — it was already being ellipsised, just off
   the visible end of the strip. The strip scrolls, so the only cost is roughly
   half a chip fewer in view. */
.zchip { box-sizing: border-box; flex: 0 0 var(--chip-w); width: var(--chip-w); display: flex;
  flex-direction: column; gap: 6px; padding: 7px 8px; border-radius: 9px;
  background: rgba(20,20,22,0.65); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  border: 0.6px solid rgba(255,255,255,0.10); }
.zc-row { display: flex; align-items: center; gap: 3px; }
.zc-radio { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 8px;
  border: 1.3px solid rgba(255,255,255,0.5); }
/* The chips are the list the reader actually scans, and they had 9–35px of unused
   width each, so this costs nothing. The strip already scrolls horizontally. */
.zc-row span { font-size: 9.2px; font-weight: 600; color: #fff; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; }
.zc-bar { height: 3px; border-radius: 2px; background: rgba(255,255,255,0.14); overflow: hidden; }
.zc-bar i { display: block; height: 100%; width: 0%; border-radius: 2px;
  background: #33D166; box-shadow: 0 0 6px rgba(51,209,102,0.7); }
.zchip.selected { border: 1.5px solid var(--rg-cyan); box-shadow: 0 0 9px rgba(33,212,237,0.45); }
.zchip.selected .zc-radio { border-color: var(--rg-cyan); }

/* --- bottom controls: gallery · shutter · torch --- */
.cam-bottom { position: absolute; left: 0; right: 0; bottom: 30px; z-index: 6;
  display: flex; align-items: center; justify-content: space-between; padding: 0 26px; }
/* square, so it matches the torch button and leaves the shutter dead-centre */
.cam-gallery { position: relative; overflow: hidden;
  width: 35px; height: 35px; border-radius: 9px; background: rgba(30,30,32,0.7);
  display: flex; align-items: center; justify-content: center; color: rgba(255,255,255,0.92); }
/* the frame that was just captured, fading in over the icon after the shutter */
/* the frame that was just shot — same photo and framing as the wide viewfinder */
.gal-thumb { position: absolute; inset: 0; opacity: 0;
  background-size: cover; background-position: 19% 56%;
  filter: saturate(1.4) brightness(1.1) contrast(1.05); }
/* --- "Define Damage Details" sheet -----------------------------------------
   Matched against the app screenshot (27.07/"Define damage details.jpg"):
   FILLED icons, white bold tile labels, grey section labels, and a filled blue
   circle for the close button. Sizes are the app's scaled ~0.59 to the 237px
   screen. Total height ~200px, so it clears the damage box by ~29px.
   Selected states are NOT baked in here — GSAP animates the tiles from
   inactive to active so the demo can show them being tapped. */
.dmg-sheet { position: absolute; left: 0; right: 0; bottom: 0; z-index: 40;
  background: #1C1C1E; border-radius: 14px 14px 0 0; padding: 6px 10px 10px;
  box-shadow: 0 -2px 12px rgba(0,0,0,0.35); }
.ds-grab { display: block; width: 26px; height: 3.5px; border-radius: 2px;
  background: rgba(255,255,255,0.28); margin: 0 auto 7px; }
.ds-head { position: relative; display: flex; align-items: center; justify-content: center;
  margin-bottom: 9px; }
.ds-head b { font-size: 12.5px; font-weight: 700; color: #fff; letter-spacing: -0.01em; }
.ds-head .ds-x { position: absolute; right: 0; top: 50%; transform: translateY(-50%);
  width: 14px; height: 14px; border-radius: 50%; background: #0A84FF;
  display: flex; align-items: center; justify-content: center;
  font-size: 7px; font-style: normal; color: #fff; }
.ds-label { font-size: 8.6px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px;
  color: rgba(255,255,255,0.55); margin: 0 1px 6px; }

.ds-types { display: grid; grid-template-columns: repeat(4, 1fr); gap: 5px; margin-bottom: 10px; }
.ds-type { display: flex; flex-direction: column; align-items: center; gap: 4px;
  padding: 7px 2px 6px; min-height: 46px; border-radius: 7px;
  background: #2A2A2C; border: 1px solid rgba(255,255,255,0.06); }
.ds-type svg { width: 17px; height: 17px; color: var(--rg-neon-blue); flex: none; }
.ds-type b { font-size: 7.2px; line-height: 1.28; font-weight: 700; text-transform: uppercase;
  text-align: center; color: rgba(255,255,255,0.92); }

.ds-sevs { display: flex; gap: 6px; margin-bottom: 10px; }
.ds-sev { flex: 1; text-align: center; padding: 8px 2px 7px; border-radius: 7px;
  background: #2A2A2C; border: 1.2px solid transparent; }
.ds-sev b { display: block; font-size: 10.5px; font-weight: 800; line-height: 1.1; }
.ds-sev i { display: block; font-size: 7.2px; font-style: normal; font-weight: 600;
  margin-top: 2px; line-height: 1.1; }
.ds-sev.light  { border-color: #FFC107; color: #FFC107; }
.ds-sev.med    { border-color: #FF8C00; color: #FF8C00; }
.ds-sev.heavy  { border-color: #E53935; color: #E53935; }

.ds-save { height: 28px; border-radius: 8px; background: #0A84FF;
  display: flex; align-items: center; justify-content: center; gap: 5px;
  font-size: 11px; font-weight: 600; color: #fff; }
.ds-save svg { width: 11px; height: 11px; flex: none; }

.cam-torch { width: 35px; height: 35px; border-radius: 50%; background: rgba(30,30,32,0.7);
  display: flex; align-items: center; justify-content: center; color: rgba(255,255,255,0.92); }
.cam-gallery svg { width: 19px; height: 19px; }
.cam-torch svg { width: 17px; height: 17px; }
.cam-shutter { width: 44px; height: 44px; border-radius: 50%; border: 2.5px solid #fff; position: relative; }
.cam-shutter::after { content: ""; position: absolute; inset: 3.5px; border-radius: 50%; background: #fff; }

/* --- shutter flash + finger cursor + yellow damage box --- */
.shutter-flash { position: absolute; inset: 0; z-index: 8; background: #fff; opacity: 0; pointer-events: none; }
.finger { position: absolute; z-index: 7; width: 24px; height: 24px; border-radius: 50%;
  border: 2px solid #fff; background: rgba(33,212,237,0.4); box-shadow: 0 0 14px var(--rg-cyan);
  opacity: 0; pointer-events: none; }
/* z 5 = same plane as the AR zone guide: the box lives ON the photo, under the
   camera HUD (z 6) — its right edge would otherwise cut through the zoom chips. */
.dmg-box { position: absolute; z-index: 5; border: 2px solid var(--rg-yellow); border-radius: 6px;
  box-shadow: 0 0 12px rgba(255,214,10,0.55), inset 0 0 10px rgba(255,214,10,0.22);
  opacity: 0; }
.dmg-box span { position: absolute; top: 5px; left: 6px; font-size: 8.5px; font-weight: 700;
  color: #111; background: var(--rg-yellow); padding: 1px 6px; border-radius: 3px; }

/* --- SUMMARY (shield) --- */
/* Nav matches the app: Back on the left, title centred, close on the right, and
   sitting low enough to clear the phone shell's corner radius. */
.sum-nav { position: absolute; top: 0; left: 0; right: 0; height: 46px; z-index: 3;
  padding-top: 16px; display: flex; align-items: flex-start; justify-content: center;
  background: rgba(9,16,27,0.72); backdrop-filter: blur(14px) saturate(1.3);
  -webkit-backdrop-filter: blur(14px) saturate(1.3);
  border-bottom: 0.5px solid rgba(255,255,255,0.10); }
.sum-nav .ti { font-size: 12px; font-weight: 700; color: #fff; }
/* same baseline tuning: Back was riding 2.47px high at top:17px */
.sum-nav .bk { position: absolute; left: 15px; top: 19.47px; display: inline-flex; align-items: center;
  gap: 2.5px; font-size: 9.5px; font-weight: 500; color: #0A84FF; }
.sum-nav .bk svg { width: 7.5px; height: 7.5px; flex: none; }
.sum-nav .cl { position: absolute; right: 13px; top: 14px; width: 17px; height: 17px;
  border-radius: 50%; background: rgba(255,255,255,0.10); color: #0A84FF;
  display: flex; align-items: center; justify-content: center; }
.sum-nav .cl svg { width: 9px; height: 9px; }

/* The summary now OVERFLOWS its screen (shield through the report button), so
   its children live in a flow column that GSAP pans, exactly like .rev-scroll.
   Absolute tops could not have grown with the extra blocks. */
.sum-scroll { position: absolute; top: 46px; left: 0; right: 0; padding: 0 13px 14px;
  display: flex; flex-direction: column; align-items: stretch; gap: 10px; }
.sum-shield { position: relative; align-self: center; margin-top: 16px;
  width: 80px; height: 72px; display: flex; align-items: center; justify-content: center; }
/* halo trimmed at the TOP only: at a symmetric -34 it reached y=16, i.e. 30px
   up under a nav that ends at 46, and glowed through its glass. Sides and
   bottom keep their reach so it still reads as round. */
.sum-shield .glow { position: absolute; inset: -14px -34px -34px; border-radius: 50%;
  background: radial-gradient(circle, rgba(51,209,102,0.34), rgba(51,209,102,0) 70%); }
.sum-shield img { position: relative; width: 80px; height: 72px; object-fit: contain; }
/* four-point sparks around the shield, as in the app */
.sum-shield .sparks { position: absolute; inset: -30px -34px; pointer-events: none; }
.sum-shield .sparks i { position: absolute; background: #4AE07E;
  clip-path: polygon(50% 0, 60% 40%, 100% 50%, 60% 60%, 50% 100%, 40% 60%, 0 50%, 40% 40%);
  opacity: 0.85; animation: sumSpark 2.6s ease-in-out infinite; }
@keyframes sumSpark { 0%, 100% { opacity: 0.25; transform: scale(0.75); }
                      50%      { opacity: 0.95; transform: scale(1); } }
@media (prefers-reduced-motion: reduce) { .sum-shield .sparks i { animation: none; opacity: 0.7; } }

.sum-title { text-align: center; margin-top: 6px;
  font-size: 20px; font-weight: 700; letter-spacing: -0.5px; color: #fff; }
.sum-sub { text-align: center; margin: -4px 11px 0;
  font-size: 10px; line-height: 1.5; color: rgba(255,255,255,0.6); }
/* Gap 4 and side padding 1, down from 6 and 2: "Timestamp" was measured filling
   46.2px of a 46.2px content box, i.e. exactly at the limit, so the labels could
   not be grown a single step without this. The two changes hand each cell about
   4px back. */
.sum-trust { display: flex; gap: 3px; }
.sum-trust .cell { flex: 1; padding: 8px 1px; border-radius: 11px; background: #1F2838;
  display: flex; flex-direction: column; align-items: center; gap: 3px; }
/* disc #2E9BFF with a white glyph — both sampled from the app screenshot
   (median of a patch above each glyph gave #2e99f9 / #2397fc) */
.sum-trust .cell .ic { width: 23px; height: 23px; border-radius: 50%; background: #2E9BFF;
  display: flex; align-items: center; justify-content: center; color: #fff; }
.sum-trust .cell .ic svg { width: 12px; height: 12px; }
/* 9.0, not 9.2: at 9.2 "Timestamp" measured 50.0px inside a 50.0px content box,
   flush against the edge. This file already carries a note that iOS renders this
   face wider and once wrapped a cue to two lines, so the widest label keeps a
   couple of pixels in hand rather than sitting exactly on the limit. */
.sum-trust .cell .nm { font-size: 9px; font-weight: 600; color: #fff; }
/* Was 7.5px at 42% white, which measured 3.85:1 against the #1F2838 cell and
   failed AA outright. The size bump is the smaller half of the fix; the opacity
   is what makes it readable. This label had 23px of unused width, so it grows
   without touching the layout. */
.sum-trust .cell .st { font-size: 8.4px; color: rgba(255,255,255,0.64); }

/* Vehicle card — sits between the trust tiles and Zone Overview, mirroring the
   app's .veh-card (44px glyph disc, name over plate/colour, blue Pickup pill). */
.sum-veh { height: 42px;
  display: flex; align-items: center; gap: 8px; padding: 0 10px;
  border-radius: 11px; background: rgba(255,255,255,0.045); }
.sum-veh .v-ic { width: 26px; height: 26px; border-radius: 50%; flex: none;
  display: flex; align-items: center; justify-content: center;
  color: #4A8CFF; background: rgba(46,155,255,0.12); }
/* The scooter is the app's own glyph, colour-keyed out of the summary
   screenshot into an ALPHA MASK — so the authentic shape (classic scooter facing
   LEFT; the figma export's svg was a different bike facing right) is kept while
   the colour still comes from CSS. Sized to the measured ink ratios: 0.569 of the
   disc wide and 0.452 tall, against the app's 0.568 / 0.455. */
.sum-veh .v-glyph { display: block; width: 14.8px; height: 11.7px;
  background-color: currentColor;
  -webkit-mask: url("veh-scooter.png") no-repeat center / contain;
  mask: url("veh-scooter.png") no-repeat center / contain; }
.sum-veh .v-txt { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.sum-veh .v-txt b { font-size: 10.5px; font-weight: 700; color: #fff;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sum-veh .v-txt i { font-style: normal; font-size: 8.5px; color: rgba(255,255,255,0.55);
  display: flex; align-items: center; }
.sum-veh .v-sep { width: 5px; height: 5px; border: 1px solid #3A4354; border-radius: 50%;
  display: inline-block; margin: 0 4px; flex: none; }
.sum-veh .v-pill { flex: none; display: flex; align-items: center; gap: 3px;
  font-size: 9px; font-weight: 600; padding: 4px 9px; border-radius: 999px;
  color: #4A8CFF; background: rgba(46,124,246,0.16); }
.sum-veh .v-pill svg { width: 9px; height: 9px; }

/* Zone Overview card */
/* The render is transparent now, so the card can carry the same tint as the
   other cards instead of matching a crop's baked-in background. */
.sum-zones { height: 268px; flex: none;
  border-radius: 12px; background: rgba(255,255,255,0.045); padding: 8px 8px 6px; }
.sum-zones .hd { display: flex; align-items: center; gap: 5px;
  font-size: 10.2px; font-weight: 700; color: #fff; margin-bottom: 2px; }
.sum-zones .hd svg { width: 11px; height: 11px; color: #fff; flex: none; }
.sum-zones .plate { position: relative; height: calc(100% - 18px); }
/* The clean render is 0.532 wide-to-tall (the old screenshot crop was 0.344), so
   at the same height it would be half again as wide and crowd the side labels.
   Sized to 80% of the plate → ~121px wide, leaving ~38px each side for text. */
.sum-zones .bike { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  height: 70%; aspect-ratio: 234 / 440; }   /* card shrank; bike keeps its size */
.sum-zones .bike > img { display: block; width: 100%; height: 100%; }
/* Zone outlines AND leader lines come from the app's vector exports
   (scooter_outlines.json + scooter_leader_lines.json), both normalised to the
   same 208x221 VehicleTopDownMoto frame. The svg carries that whole frame as its
   viewBox, so every published coordinate is used verbatim; the element is offset
   and scaled so the outline box lands on this render's measured body
   (x 23.6-75.1%, cowl-to-tail) — hence the negative left/top and >100% size.
   preserveAspectRatio="none" carries the fit, non-scaling-stroke keeps weights
   even through it. Leader `d` is written at runtime from the real dot centres,
   which is what the export says to do. */
.sum-zones .zone-svg { position: absolute; left: -42.67%; top: -4.66%;
  width: 184.59%; height: 110.97%; overflow: visible; pointer-events: none; }
.sum-zones .zone-svg .zp { fill: none; stroke: #33D166; stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round; vector-effect: non-scaling-stroke;
  filter: drop-shadow(0 0 2px rgba(51,209,102,0.7)); }
.sum-zones .zone-svg .zp.dmg { stroke: var(--rg-yellow);
  filter: drop-shadow(0 0 2px rgba(255,214,10,0.8)); }
/* Color.secondary.opacity(0.35), lineWidth 1, round caps — as published */
.sum-zones .zone-svg .ld { fill: none; stroke: rgba(235,235,245,0.35); stroke-width: 1;
  stroke-linecap: round; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
.sum-zones .zl { position: absolute; display: flex; align-items: center; gap: 3px; }
.sum-zones .zl.l { flex-direction: row-reverse; }
.sum-zones .zl span { display: flex; flex-direction: column; line-height: 1.15; }
.sum-zones .zl.l span { align-items: flex-end; text-align: right; }
/* The seven zone labels sit around the plate with the closest pair 28.8px apart,
   so there is room to grow. Held to about a 10% step: the labels are positioned
   by percentage against the bike, and a larger jump starts crowding the leader
   lines rather than the neighbouring label. */
.sum-zones .zl b { font-size: 9.4px; font-weight: 700; color: #33D166; }
.sum-zones .zl span { font-size: 8.2px; color: rgba(255,255,255,0.62); }
.sum-zones .zl.dmg b { color: var(--rg-yellow); }
.sum-zones .zl .d { width: 5px; height: 5px; border-radius: 50%; flex: none; }
.sum-zones .zl .d.g { background: #33D166; box-shadow: 0 0 5px rgba(51,209,102,0.8); }
.sum-zones .zl .d.y { background: var(--rg-yellow); box-shadow: 0 0 5px rgba(255,214,10,0.8); }
.sum-zones .zl.c { flex-direction: column; gap: 1px; }
.sum-zones .zl.c span { align-items: center; }

/* Damage Summary — same card language as Zone Overview. "By Type" is the live
   tab, so the ring and the row below it are the per-type view. */
.sum-dmg { border-radius: 12px; background: rgba(255,255,255,0.045); padding: 9px 10px 10px; }
.sum-dmg .hd { display: flex; align-items: center; justify-content: space-between; }
.sum-dmg .hd .t { display: flex; align-items: center; gap: 5px;
  font-size: 9.5px; font-weight: 700; color: #fff; }
.sum-dmg .hd .t svg { width: 11px; height: 11px; flex: none; }
/* 57.7px of glyph in a header row with 134.8px free — room was not the limit. */
.sum-dmg .pill { font-size: 8.6px; font-weight: 600; padding: 3px 8px; border-radius: 999px;
  color: #FF6B6B; background: rgba(255,69,58,0.16); }
.sum-dmg .seg { display: flex; gap: 2px; margin-top: 8px; padding: 2px;
  border-radius: 7px; background: rgba(255,255,255,0.07); }
.sum-dmg .seg .sg { flex: 1; text-align: center; padding: 4px 0; border: 0; border-radius: 5px;
  /* "By Severity" used 43.8px of a 114.9px tab. */
  font-size: 9.2px; font-weight: 600; color: rgba(255,255,255,0.66); background: transparent;
  font-family: inherit; cursor: pointer; -webkit-appearance: none; appearance: none;
  transition: background-color 0.18s ease, color 0.18s ease; }
.sum-dmg .seg .sg.on { background: rgba(255,255,255,0.16); color: #fff; }
.sum-dmg .seg .sg:hover:not(.on) { color: rgba(255,255,255,0.8); }
.sum-dmg .dv[hidden] { display: none; }
/* By Severity is the same shape in the severity palette — Light is amber,
   matching the LIGHT chip in the app's damage-details sheet. */
.sum-dmg .dmg-ring.sev circle { stroke: var(--rg-yellow); }
.sum-dmg .row .sw { width: 9px; height: 9px; border-radius: 3px; flex: none;
  background: var(--rg-yellow); box-shadow: 0 0 6px rgba(255,214,10,0.55); }
/* NOT .ring — that is a Tailwind utility, and it painted a blue focus halo
   as a box-shadow behind the donut. */
.sum-dmg .dmg-ring { position: relative; height: 82px; margin: 9px auto 4px; width: 82px; }
.sum-dmg .dmg-ring svg { width: 100%; height: 100%; transform: rotate(-90deg); }
.sum-dmg .dmg-ring circle { fill: none; stroke: var(--rg-cyan); stroke-width: 15; }
.sum-dmg .dmg-ring .v { position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 1px; }
.sum-dmg .dmg-ring .v b { font-size: 19px; font-weight: 700; color: #fff; line-height: 1; }
.sum-dmg .dmg-ring .v i { font-style: normal; font-size: 7.5px; color: rgba(255,255,255,0.5); }
.sum-dmg .row { display: flex; align-items: center; gap: 6px; padding-top: 7px;
  border-top: 0.5px solid rgba(255,255,255,0.08); font-size: 10.2px; color: #fff; }
.sum-dmg .row svg { width: 12px; height: 12px; flex: none; color: var(--rg-cyan); }
.sum-dmg .row span { flex: 1; font-weight: 500; }
.sum-dmg .row b { font-weight: 600; }

/* Report CTA — a real button: it scrolls the story to the PDF beat. */
.sum-cta { width: 100%; cursor: pointer; }
.sum-cta svg { width: 12px; height: 12px; flex: none; }
.rgapp-cta:hover { filter: brightness(1.08); }
.rgapp-cta:active { transform: scale(0.98); }

/* --- LANGUAGE picker --- */
/* --- REVIEW INSPECTION (ported from Inspection_review1/2) ---
   Fixed nav, and an inner column taller than the screen that GSAP pans up —
   the phone appears to scroll itself while the page scrolls. --- */
#app-review { background: #09101B; }
.rev-nav { position: absolute; top: 0; left: 0; right: 0; height: 38px; z-index: 3;
  padding-top: 8px;
  display: flex; align-items: center; justify-content: center;
  background: rgba(9,16,27,0.72); backdrop-filter: blur(14px) saturate(1.3);
  -webkit-backdrop-filter: blur(14px) saturate(1.3);
  border-bottom: 0.5px solid rgba(255,255,255,0.10); }
/* top tuned so the Back text sits on the TITLE's baseline, not merely near it:
   measured 8.97px of lift at top:8px, so 16.97 */
.rev-nav .bk { position: absolute; left: 15px; top: 16.97px; display: inline-flex; align-items: center; gap: 2.5px;
  font-size: 9.5px; font-weight: 500; color: #0A84FF; }
.rev-nav .bk svg { width: 7.5px; height: 7.5px; flex: none; }
.rev-nav .ti { font-size: 12px; font-weight: 700; color: #fff; }
.rev-scroll { position: absolute; top: 38px; left: 0; right: 0; padding: 9px 12px 12px;
  display: flex; flex-direction: column; gap: 9px; }
/* Coverage pill: sized to its content and centred, not stretched edge to edge,
   and in the app's blue rather than the landing's cyan. */
.rev-cov { display: flex; align-items: center; justify-content: center; gap: 9px;
  width: fit-content; margin: 0 auto; padding: 6px 18px; border-radius: 11px;
  border: 1px solid rgba(46,155,255,0.55); background: rgba(46,155,255,0.10);
  color: #2E9BFF; box-shadow: 0 0 16px rgba(46,155,255,0.18); }
/* 24, up from 19: the badge measures 147.5px wide inside a 281.8px screen, so
   the shield was small by choice rather than by constraint. */
.rev-cov svg { width: 29px; height: 29px; flex: none; }
/* label above the number, as in the app — that stacking is what keeps the pill
   compact instead of a single line spanning the whole screen */
.rev-cov .ct { display: flex; flex-direction: column; align-items: flex-start; line-height: 1.05; }
.rev-cov .cl { font-size: 9px; font-weight: 600; letter-spacing: 0.01em; }
.rev-cov .cv { font-size: 22px; font-weight: 800; letter-spacing: -0.02em; }
/* --- Review: live 3D scooter ---------------------------------------------
   Aspect is locked so the block reserves its height before the model loads and
   the column below never jumps. Canvas sits over the fallback image; the blue
   stage ellipse is CSS, so it costs no polygons and stays crisp. */
.rev-bike { position: relative; width: 100%; aspect-ratio: 620 / 400; }
.rev-bike-fallback { position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: contain; border-radius: 8px; }
#bike-canvas { position: absolute; inset: 0; width: 100%; height: 100%;
  opacity: 0; transition: opacity 0.35s ease; }
#bike-canvas.on { opacity: 1; }
/* once the canvas is live the baked JPEG must go — it carries its own dots */
.rev-bike.is3d .rev-bike-fallback { opacity: 0; }
.rev-stage { position: absolute; left: 50%; bottom: 12%; transform: translateX(-50%);
  width: 74%; aspect-ratio: 3 / 1; border-radius: 50%; opacity: 0;
  border: 1.5px solid rgba(46,155,255,0.9);
  box-shadow: 0 0 14px rgba(46,155,255,0.45), inset 0 0 18px rgba(46,155,255,0.18); }
.rev-bike.is3d .rev-stage { opacity: 1; }
.rev-dots { position: absolute; inset: 0; pointer-events: none; }
.rev-dots i { position: absolute; width: 9px; height: 9px; margin: -4.5px 0 0 -4.5px;
  border-radius: 50%; background: #30D158; opacity: 0;
  box-shadow: 0 0 0 2.5px rgba(48,209,88,0.22), 0 0 8px rgba(48,209,88,0.7); }
.rev-dots i.dmg { background: #FFC107;
  box-shadow: 0 0 0 2.5px rgba(255,193,7,0.22), 0 0 8px rgba(255,193,7,0.75); }
.rev-bike.is3d .rev-dots i { opacity: 1; }
/* 4.52:1 measured at 45% white — over the 4.5 line by two hundredths, which is
   not a margin. Bigger and brighter. */
.rev-hint { text-align: center; font-size: 8.4px; color: rgba(255,255,255,0.62); }
.rev-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.rv-card { position: relative; overflow: hidden; padding: 6px 7px; border-radius: 7px;
  background: rgba(255,255,255,0.045); border-left: 3px solid #33D166; min-height: 40px; }
/* Held to a small step, and 11.4 rather than 11.6: the zone drawing is absolutely
   positioned, so a name that outgrows its room slides UNDER the artwork instead of
   being clipped at the card edge. "Dashboard" is the binding case — 57.8px of the
   64.7px beside its drawing before this change, 4.8px of headroom after. */
.rv-card .nm { display: block; font-size: 11.4px; font-weight: 700; letter-spacing: -0.01em; color: #33D166; }
.rv-card .st { display: block; font-size: 9.1px; font-weight: 500; color: rgba(255,255,255,0.7); margin-top: 2px; }
/* Constrain by HEIGHT: front/rear are portrait drawings and side views are
   landscape, so a fixed width overflowed the card on the portrait ones. */
.rv-card img { position: absolute; right: 7px; top: 50%; transform: translateY(-50%);
  height: 28px; width: auto; max-width: 46px; object-fit: contain; opacity: 0.62; }
/* Front and Rear are narrow head-on drawings, so a uniform right inset left them
   hard against the card edge with a pool of empty space to their left. */
.rv-card img[src="zone-front.svg"], .rv-card img[src="zone-rear.svg"] { right: 17px; }
/* The dashboard drawing carries more width than the rest at the same height. */
.rv-card img[src="zone-dash.svg"] { height: 24px; }
.rv-card img[src="zone-left.svg"], .rv-card img[src="zone-right.svg"] { height: 25.5px; }

/* photo-count glyph in the card's status line, as in the app */
.rv-card .st { display: flex; align-items: center; gap: 3px; }
/* Filled, not stroked: at this size an outline glyph rendered a 0.7px stroke
   and disappeared. The app uses a filled plate with the sun and mountain
   knocked out, which survives being small. */
.rv-card .st .ph { width: 11.5px; height: 8.6px; flex: none; opacity: 0.85; margin-left: 1px; }
.rv-card.dmg { border-left-color: var(--rg-yellow); }
.rv-card.dmg .nm { color: var(--rg-yellow); }
.rev-dsum .hd { font-size: 10.8px; font-weight: 700; color: #fff; margin-bottom: 5px; }
.rev-dsum .cnt { display: grid; grid-template-columns: repeat(4, 1fr); gap: 5px; }
.rev-dsum .c { text-align: center; padding: 5px 2px; border-radius: 6px; background: rgba(255,255,255,0.045); }
.rev-dsum .c b { display: block; font-size: 14.5px; font-weight: 800; color: #fff; }
/* 6.5px was the smallest text anywhere on this screen, and the least justified:
   the widest of these captions ("Medium") used 28.6px of a 60.7px cell, so more
   than half the box was empty. */
.rev-dsum .c i { display: block; font-size: 8px; font-style: normal; text-transform: uppercase;
  letter-spacing: 0.04em; color: rgba(255,255,255,0.66); margin-top: 1px; }
.rev-dsum .lt b { color: var(--rg-yellow); }
.rev-dsum .md b { color: #FF9F0A; }
.rev-dsum .hv b { color: #FF453A; }
.rev-lang { padding: 8px; border-radius: 8px; background: rgba(255,255,255,0.045); }
.rev-lang .t { font-size: 9.4px; font-weight: 600; color: #fff; }
.rev-lang .pick { display: flex; align-items: center; gap: 8px; margin-top: 6px;
  padding: 6px 8px; border-radius: 6px; background: rgba(255,255,255,0.07); }
.rev-lang .pick .nm { flex: 1; font-size: 11px; font-weight: 600; color: #fff; }
.rev-lang .pick .nm small { display: block; font-size: 8.4px; font-weight: 400; color: rgba(255,255,255,0.66); }
.rev-lang .pick .cv { font-size: 10px; color: rgba(255,255,255,0.5); }
/* ONE button for every in-phone screen. There were three looks: a cyan->blue
   gradient on Review, a vertical blue gradient on Summary, and the flat blue
   baked into the PDF asset. The PDF one could not be restyled, so it set the
   standard — #0192FF, eyedropped off the old report-pdf.jpg. That asset is gone
   (the report is live UI now); the value stays as the shared fill. */
.rgapp-cta { height: 30px; border-radius: 9px; display: flex; align-items: center;
  justify-content: center; gap: 5px; font-size: 11px; font-weight: 700; color: #fff;
  /* flat, no resting glow: the PDF's baked button has none, and Review's press
     tween starts from a transparent box-shadow which would permanently
     override a CSS one there but not on Summary — so the two would drift */
  background: #0192FF;
  border: 0; font-family: inherit; -webkit-appearance: none; appearance: none; }
.rev-cta { }

/* --- Report Language: a bottom sheet over the review screen --- */
.rgapp-sheet { position: absolute; left: 0; right: 0; bottom: 0; top: 26%; z-index: 9;
  background: #16181C; border-radius: 16px 16px 0 0; overflow: hidden;
  box-shadow: 0 -8px 30px rgba(0,0,0,0.6); }
.rgapp-sheet .grabber { width: 34px; height: 3.5px; border-radius: 2px; margin: 7px auto 0;
  background: rgba(255,255,255,0.28); }
.lang-head { padding: 10px 14px 0; }
.lang-head .t { font-size: 13px; font-weight: 700; color: #fff; }
.lang-head .srch { margin-top: 8px; padding: 6px 10px; border-radius: 9px;
  display: flex; align-items: center; gap: 6px;
  /* 9.5px at 45% white measured 4.14:1 and failed AA. The line uses 91px of a
     253.8px field, so there was never a space reason to keep it small. */
  background: rgba(255,255,255,0.08); font-size: 10.5px; color: rgba(255,255,255,0.62); }
.lang-list { padding: 8px 14px 0; display: flex; flex-direction: column; gap: 4px; }
.lang-row { display: flex; align-items: center; gap: 9px; padding: 6px 10px; border-radius: 9px;
  background: rgba(255,255,255,0.05); border: 0.5px solid rgba(255,255,255,0.10); }
.lang-row .flag, .rev-lang .pick .flag {
  width: 22px; height: 15px; border-radius: 2px; overflow: hidden; flex: 0 0 22px;
  display: flex; flex-direction: column; box-shadow: 0 1px 2px rgba(0,0,0,0.4); }
.rev-lang .pick .flag { width: 18px; height: 12px; flex-basis: 18px; }
.lang-row .flag i, .rev-lang .pick .flag i { display: block; flex: 1; }
/* US/VN/CN can't be drawn as plain bars — stripes alone made the US flag read as
   the Dutch one and dropped the VN/CN stars — so those three are inline SVG. */
.lang-row .flag svg, .rev-lang .pick .flag svg { display: block; width: 100%; height: 100%; }
.lang-row .nm { flex: 1; font-size: 11px; font-weight: 600; color: #fff; line-height: 1.15; }
/* The grey native name sat at 4.69:1, a hair over the line. Widest of them
   ("Tiếng Việt") used 44.5px of a 180.4px row. */
.lang-row .nm small { display: block; font-size: 9px; font-weight: 400; color: rgba(255,255,255,0.64); }
.lang-row.sel { border: 1.5px solid var(--rg-cyan); background: rgba(33,212,237,0.12);
  box-shadow: 0 0 10px rgba(33,212,237,0.3); }
.lang-row .chk { color: var(--rg-cyan); font-size: 13px; opacity: 0; }
.lang-row.sel .chk { opacity: 1; }

/* --- REPORT (live UI, was a screenshot) ---
   The page is authored FOR this 237px screen, not scaled down to it. A faithful
   miniature of the A4 sheet cannot work here: the app lays the report out for a
   402pt device, so fitting the whole page puts its 7-10px type at 4-6px however
   it is rendered. Same content, one column instead of two, type at the sizes the
   other in-phone screens already use. */
#app-pdf { background: #0B0B0C; }
.pdf-nav { position: absolute; top: 0; left: 0; right: 0; height: 46px; z-index: 3;
  padding-top: 16px; display: flex; align-items: flex-start; justify-content: center;
  background: rgba(9,16,27,0.72); backdrop-filter: blur(14px) saturate(1.3);
  -webkit-backdrop-filter: blur(14px) saturate(1.3);
  border-bottom: 0.5px solid rgba(255,255,255,0.10); }
.pdf-nav .ti { font-size: 12px; font-weight: 700; color: #fff; }
.pdf-nav .cl { position: absolute; right: 13px; top: 14px; width: 17px; height: 17px;
  border-radius: 50%; background: rgba(255,255,255,0.10); color: #0A84FF;
  display: flex; align-items: center; justify-content: center; }
.pdf-nav .cl svg { width: 9px; height: 9px; }
/* Column taller than the screen, panned by GSAP — same device as .rev-scroll
   and .sum-scroll, so the phone appears to scroll itself. */
.pdf-scroll { position: absolute; top: 46px; left: 0; right: 0; padding: 0 3px; }
.pdf-page { background: #fff; color: #1A1A1A; border-radius: 2px; padding: 13px 13px 9px;
  display: flex; flex-direction: column; gap: 9px; }

.pp-head { display: flex; align-items: flex-start; gap: 7px; }
.pp-logo { width: 26px; height: 26px; flex: none; border-radius: 7px; background: #0B1220;
  display: flex; align-items: center; justify-content: center; overflow: hidden; }
.pp-logo img { width: 22px; height: 22px; object-fit: contain; }
.pp-brand { flex: 1; display: flex; flex-direction: column; min-width: 0; }
.pp-brand i { font-style: normal; font-size: 8px; font-weight: 800; color: #111; line-height: 1.2; }
/* 9.5px, and the QR caption held to 46px: at 10.5px against an 82px QR block the
   title broke into THREE lines. Two is the app's own shape. */
.pp-brand b { font-size: 9.5px; font-weight: 800; color: #111; line-height: 1.2; letter-spacing: -0.2px; }
.pp-brand em { font-style: normal; font-size: 7.4px; color: #6B6B72; margin-top: 2px; }
.pp-qr { flex: none; display: flex; align-items: flex-start; gap: 4px; }
.pp-qr svg { width: 24px; height: 24px; flex: none; }
.pp-qr i { font-style: normal; font-size: 6.6px; line-height: 1.35; color: #6B6B72; width: 54px; }
.pp-qr u { display: block; text-decoration: none; color: #2E9BFF; margin-top: 2px; word-break: break-all; }

.pp-verified { display: flex; align-items: center; gap: 9px; background: #F6F6F8;
  border-radius: 9px; padding: 7px 10px; }
.pv-l { flex: 1.05; display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.pv-t { display: flex; align-items: center; gap: 6px; font-size: 8.4px; font-weight: 800;
  color: #157A37; text-transform: uppercase; letter-spacing: 0.6px; }
.pv-ic { width: 15px; height: 15px; flex: none; border-radius: 50%; background: #33D166; color: #fff;
  display: flex; align-items: center; justify-content: center; }
.pv-ic svg { width: 9px; height: 9px; }
.pv-badge { align-self: flex-start; font-size: 6.8px; font-weight: 700; color: #fff;
  background: #1565C0; border-radius: 5px; padding: 2px 7px; letter-spacing: 0.5px; margin-left: 21px; }
.pv-r { flex: 1; display: flex; flex-direction: column; gap: 1px;
  border-left: 1px solid #E7E7EA; padding-left: 9px; }
.pv-r b { font-size: 9px; font-weight: 800; color: #111; }
.pv-r i { font-style: normal; font-size: 7.4px; color: #63636A; line-height: 1.35; }
.pv-r u { text-decoration: none; color: #111; font-weight: 700; }

.pp-meta { display: flex; flex-direction: column; gap: 6px; padding: 0 1px; }
.pm { display: flex; align-items: flex-start; gap: 6px; }
.pm-ic { width: 12px; height: 12px; flex: none; color: #2E9BFF; margin-top: 1px; }
.pm-ic svg { width: 12px; height: 12px; display: block; }
.pm-x { display: flex; flex-direction: column; min-width: 0; }
.pm-x i { font-style: normal; font-size: 7.2px; font-weight: 700; color: #1668B8; margin-bottom: 1px; }
.pm-x b { font-size: 8.4px; font-weight: 700; color: #111; line-height: 1.3; }

.pp-sec { display: flex; align-items: baseline; justify-content: space-between;
  font-size: 8.4px; font-weight: 800; color: #5E5E66; text-transform: uppercase; letter-spacing: 1.1px;
  border-top: 1px solid #ECECEE; padding-top: 8px; }
.pp-cnt { font-size: 7.2px; font-weight: 700; color: #1668B8; letter-spacing: 0.3px; text-transform: none; }

.pp-cond { border: 1px solid #ECECEE; border-radius: 9px; padding: 8px 10px;
  display: flex; justify-content: center; }
/* 152/104, not the original 128/118: the Front and Rear labels are two lines
   each (19.6px) and sit at the box edges, so the clearance has to exceed that.
   (152−104)/2 − 19.6 = 4.4px of daylight; the plate PNG is trimmed to its ink,
   so any less and the labels touch the scooter — measured at 1.6px of overlap
   when the box was 140. */
.pc-bike { position: relative; width: 100%; height: 152px; display: flex;
  align-items: center; justify-content: center; }
.pc-plate { position: relative; display: block; height: 104px; }
.pc-plate img { height: 104px; width: auto; display: block; }
/* Labels flank the plate; positions mirror the app's own report diagram. */
.pc-bike .zl { position: absolute; font-style: normal; font-size: 6.4px; font-weight: 700;
  white-space: nowrap; display: flex; flex-direction: column; gap: 1px; color: #28B85C; }
.pc-bike .zl u { text-decoration: none; font-size: 6px; font-weight: 500; color: #999; }
.pc-bike .zl.amb, .pc-bike .zl.amb u { color: #E8A200; }
.zl-front  { top: 0; left: 50%; transform: translateX(-50%); align-items: center; }
.zl-rear   { bottom: 0; left: 50%; transform: translateX(-50%); align-items: center; }
.zl-dash   { top: 24%; left: calc(50% + 36px); }
.zl-right  { top: 42%; left: calc(50% + 36px); }
.zl-seat   { top: 60%; left: calc(50% + 36px); }
.zl-left   { top: 34%; right: calc(50% + 36px); align-items: flex-end; text-align: right; }
.zl-wheels { top: 58%; right: calc(50% + 36px); align-items: flex-end; text-align: right; }
/* Percentages of the PLATE, not of the outer box — so changing the clearance
   above cannot walk them off the scooter. */
.pc-plate .zm { position: absolute; width: 7px; height: 7px; border-radius: 50%;
  border: 1.8px solid #28B85C; background: #fff; }
.pc-plate .zm.amb { border-color: #E8A200; }
.zm-front  { top: 9.2%; left: 50%; transform: translateX(-50%); }
.zm-rear   { top: 90.7%; left: 50%; transform: translateX(-50%); }
.zm-dash   { top: 26.2%; left: calc(50% + 13.2px); }
.zm-right  { top: 46.5%; left: calc(50% + 15.9px); }
.zm-seat   { top: 65.8%; left: calc(50% + 11.5px); }
.zm-left   { top: 37.5%; left: calc(50% - 22px); }
.zm-wheels { top: 64.7%; left: calc(50% - 19.4px); }

.pp-charts { display: flex; gap: 9px; }
.pch { flex: 1; min-width: 0; }
.pch-h { display: block; font-size: 6.8px; font-weight: 800; color: #8A8A90;
  text-transform: uppercase; letter-spacing: 0.9px; margin-bottom: 5px; }
.pch-row { display: flex; align-items: center; gap: 7px; }
.pdo { position: relative; width: 40px; height: 40px; flex: none; }
.pdo svg { width: 40px; height: 40px; display: block; }
.pdo circle { fill: none; stroke: #EDEDF0; stroke-width: 5; }
.pdo circle.v { stroke: var(--rg-yellow); }
.pdo.cyn circle.v { stroke: var(--rg-cyan); }
.pdo u { position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; text-decoration: none;
  font-size: 11px; font-weight: 800; color: #111; line-height: 1; }
.pdo u i { font-style: normal; font-size: 4.2px; font-weight: 700; color: #999;
  letter-spacing: 0.5px; margin-top: 1px; }
.pch-l { flex: 1; display: flex; align-items: center; gap: 4px; font-size: 7px;
  font-weight: 600; color: #333; min-width: 0; }
.pch-l .dot { width: 6px; height: 6px; border-radius: 50%; flex: none; background: var(--rg-yellow); }
.pch-l .dot.cyn { background: var(--rg-cyan); }
.pch-l b { margin-left: auto; font-weight: 700; color: #111; }

.pp-stats { display: grid; grid-template-columns: 1fr 1fr; gap: 1px;
  border: 1px solid #ECECEE; border-radius: 9px; overflow: hidden; background: #ECECEE; }
.ps { background: #fff; padding: 7px 4px; display: flex; flex-direction: column;
  align-items: center; gap: 2px; }
.ps b { font-size: 12px; font-weight: 800; color: #111; line-height: 1; }
.ps b.red { color: #F03E3E; }
.ps b.blu { color: #2E9BFF; }
.ps i { font-style: normal; font-size: 6px; font-weight: 600; color: #8A8A90;
  text-transform: uppercase; letter-spacing: 0.5px; }

.pp-zd { border: 1px solid #ECECEE; border-radius: 9px; padding: 8px 9px;
  display: flex; flex-direction: column; gap: 6px; }
.pz-h { display: flex; align-items: center; gap: 6px; }
.pz-h b { font-size: 8.5px; font-weight: 800; color: #111; }
.pz-h em { font-style: normal; font-size: 6.8px; font-weight: 700; color: #7A5508;
  background: rgba(232,162,0,0.12); border-radius: 5px; padding: 2px 6px; }
.pz-shot { position: relative; display: block; border-radius: 6px; overflow: hidden;
  height: 96px; background: #111; }
.pz-shot img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* The scratch is a diagonal, running from roughly (32%, 67%) at the lower left up
   to (66%, 40%) at the upper right — read off an enlarged render rather than
   guessed. The original box at top 34% framed the paint ABOVE it; a first move to
   44% then clipped its upper end. These numbers wrap the whole diagonal with a
   margin on each side, and still sit lower than where it started. */
.pz-box { position: absolute; left: 29%; top: 40%; width: 40%; height: 30%;
  border: 1.4px solid var(--rg-yellow); border-radius: 3px; }
.pz-box u { position: absolute; left: -1.4px; top: -12px; text-decoration: none;
  font-size: 6.8px; font-weight: 700; color: #111; background: var(--rg-yellow);
  border-radius: 3px; padding: 1px 4px; white-space: nowrap; }
.pz-tags { display: flex; gap: 5px; }
.pz-tags em { font-style: normal; font-size: 6.8px; font-weight: 700; border-radius: 5px; padding: 2px 7px; }
.pz-tags em.cyn { color: #0A6C7E; background: rgba(33,212,237,0.14); }
.pz-tags em.amb { color: #96690A; background: rgba(232,162,0,0.12); }
.pz-cap { font-size: 6.8px; line-height: 1.4; color: #63636A; letter-spacing: 0.1px; }
/* The address is the line a human actually reads, so it carries the weight; the
   timestamp and hash sit under it as supporting detail. The negative margin pulls
   the pair together against .pp-zd's 6px gap, so they read as one caption. */
.pz-addr { font-weight: 700; color: #333; margin-bottom: -4px; }

.pp-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 5px; }
/* Backgrounds rather than <img>: at 300% each cell is a genuinely different
   close-up. At cover the six crops were near-identical and read as one photo
   repeated six times.
   Source is the macro, NOT review-bike.jpg — that one is the 3D render with the
   app's zone status dots baked in, so every crop of it carried a stray green or
   yellow blob that read as a rendering artifact. */
.pg { position: relative; display: block; border-radius: 5px; overflow: hidden; height: 44px;
  background: #111 url(scratch-macro.jpg) no-repeat; background-size: 300%; }
.pg i { position: absolute; left: 0; right: 0; bottom: 0; font-style: normal;
  font-size: 6.4px; font-weight: 700; color: #fff; padding: 7px 4px 2px;
  background: linear-gradient(to top, rgba(0,0,0,0.72), transparent); }

.pp-note { font-size: 6.8px; line-height: 1.5; color: #63636A; }
.pp-foot { border-top: 1px solid #ECECEE; padding-top: 6px; text-align: center;
  font-size: 6.8px; color: #63636A; }

/* --- Story caption: "How it works" eyebrow + three stacked blocks A/B/C that
       cross-fade by beat (fully scrub-safe in both scroll directions). Mobile:
       bottom-centre under the phone. Desktop (≥768px): left of the phone —
       the phone is shifted right over the bike, so the left half is free. --- */
#demo-caption { position: absolute; bottom: 2.5%; left: 50%; transform: translateX(-50%);
  z-index: 35; width: min(86vw, 380px); height: 140px; pointer-events: none; }
#demo-caption::before { content: ""; position: absolute; left: 50%; bottom: -18px; transform: translateX(-50%);
  width: 130%; height: 180px; z-index: -1;
  background: radial-gradient(60% 60% at 50% 60%, rgba(0,0,0,0.6), transparent 72%); }
#demo-caption .cap-eyebrow { position: absolute; top: 0; left: 0; right: 0; text-align: center;
  font-size: 11px; font-weight: 600; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--rg-cyan); text-shadow: 0 1px 10px rgba(0,0,0,0.75); opacity: 0; }
#demo-caption .cap { position: absolute; top: 26px; left: 0; right: 0; text-align: center; opacity: 0; }
#demo-caption .cap-line { font-size: clamp(16px, 3.9vw, 21px); font-weight: 700; color: #fff;
  letter-spacing: -0.01em;
  text-shadow: 0 1px 3px rgba(0,0,0,0.9), 0 2px 16px rgba(0,0,0,0.75); }
/* Sub-titles are STACKED in one grid cell: they cross-fade in place, so the
   heading above and the chips below never shift as the line changes. The
   wrapper takes the height of the tallest line, reserved from the start. */
#demo-caption .cap-subs { display: grid; margin-top: 5px; }
#demo-caption .cap-subs > .cap-sub { grid-area: 1 / 1; }
/* 0.92, not 0.75, and a TIGHT shadow under the soft one. The garage photo behind
   this column is mid-grey and busy; a single 10px halo spreads too far to draw an
   edge, so the description was reading as part of the picture. */
/* 3.2vw, not 2.6: at 2.6 the middle term never won on a phone (2.6vw is 10.1px
   at 390), so every handset got the 11px floor regardless of how much room it
   had. 3.2 lets the size follow the screen — 11.5px at 360, 12.5px at 390 —
   while the floor and cap stay put, which is what keeps the description at TWO
   lines. Three lines is the real limit here, not the type size: the third line
   is what puts the text under the Next step badge. */
#demo-caption .cap-sub { font-size: clamp(11px, 3.2vw, 13px); color: rgba(255,255,255,0.92);
  line-height: 1.5;
  text-shadow: 0 1px 3px rgba(0,0,0,0.92), 0 2px 14px rgba(0,0,0,0.65); }
#demo-caption .cap-benefits { display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; margin-top: 11px; }
#demo-caption .cap-benefits span { font-size: 10.5px; font-weight: 600; color: rgba(255,255,255,0.88);
  padding: 4px 10px; border-radius: 999px; background: rgba(255,255,255,0.10);
  border: 0.5px solid rgba(255,255,255,0.16); backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); }
/* Mobile: the eyebrow moved into the header, so the caption drops it AND the
   26px it was holding — the block is bottom-anchored, so the reclaimed height
   comes off the top, which is the edge that was intruding on the phone. */
@media (max-width: 767.98px) {
  #demo-caption { height: 114px; }
  #demo-caption .cap-eyebrow { display: none; }
  #demo-caption .cap { top: 0; }
  /* The ring is hidden here, so the number carries the ordinal on its own, set
     inline ahead of the title. */
  .cap-num { font-size: inherit; color: var(--rg-cyan); }
  .cap-num::after { content: "—"; padding: 0 5px;
    color: rgba(255,255,255,0.55); }
  /* The four benefit chips wrap to two rows here and simply do not fit: they
     pushed the block up into the phone at the one beat where the phone is
     showing the report. Desktop keeps them — it has the column width. */
  #demo-caption .cap-benefits { display: none; }
}

/* Ring and number are one marker. The number is centred over the ring rather
   than sitting beside it, so a step carries ONE token instead of an ordinal and
   a progress indicator competing next to each other. */
.cap-marker { position: relative; display: inline-flex; align-items: center;
  justify-content: center; flex: none; }
.cap-num { font-style: normal; font-weight: 700; color: var(--rg-cyan);
  letter-spacing: 0.02em; }
.cap-ring { display: none; }
/* step marker ring: r=9.5 → circumference 59.69, so dashoffset 59.69 = empty, 0 = full */
.cap-ring circle { fill: none; stroke-width: 3; }
.cap-ring .ring-track { stroke: rgba(255,255,255,0.20); }
.cap-ring .ring-fill { stroke: var(--rg-cyan); stroke-linecap: round;
  stroke-dasharray: 59.69; stroke-dashoffset: 59.69;
  transform: rotate(-90deg); transform-origin: 50% 50%; }
/* once the ring is full it hands over to a green check (cyan = running, green = done) */
.cap-ring .ring-check { fill: none; stroke: #33D166; stroke-width: 2.8;
  stroke-linecap: round; stroke-linejoin: round; opacity: 0; }
@media (min-width: 768px) {
  /* Desktop: the caption block is an ACCUMULATING checklist — steps stack in
     flow and stay visible; a finished step dims and gets a green check. */
  /* Left edge lines up with the top nav pill, which is a fixed 896px centred
     block — so its edge is calc(50% - 448px). Clamped so the caption can't
     run off-screen on the narrow end of this breakpoint. The right edge
     stops short of the phone (pinned at left:61%, ~310px wide), which is
     what buys the headings their extra line width. */
  /* The 34px is the marker gutter: `left` moves 34px earlier and the same 34px
     returns as padding, so the TEXT column stays exactly where it was (lined up
     with the nav pill) while the ring hangs in the gutter to its left. Keeping
     the ring inside the element box is what stops it being clipped at the narrow
     end of this breakpoint, where `left` bottoms out at the 16px clamp. */
  #demo-caption { left: max(16px, calc(50% - 482px)); right: calc(39% + 178px);
    padding-left: 34px;
    bottom: auto; top: 50%; transform: translateY(-50%);
    width: auto; height: auto; min-height: 150px;
    display: flex; flex-direction: column; gap: 18px; }
  /* Reverted to the shared radial. A left-anchored linear wash was tried here and
     failed for a reason worth recording: linear-gradient fades along ONE axis, so
     the panel kept hard horizontal edges at its top and bottom and read as a dark
     rectangle laid over the garage. The radial fades in every direction, which is
     why it never shows a seam. */
  #demo-caption::before { left: 40%; bottom: auto; top: 50%; transform: translate(-50%, -50%);
    width: 170%; height: 220%; }
  #demo-caption .cap-eyebrow { position: static; text-align: left; margin-bottom: 4px;
    font-size: 13px; letter-spacing: 0.2em; }
  #demo-caption .cap { position: static; text-align: left; }
  #demo-caption .cap-line { font-size: clamp(19px, 1.7vw, 22px); position: relative; }
  /* Pinned to the FIRST line of the title, not the middle of the block: a title
     that wraps to two lines would otherwise drag the ring down between them. */
  #demo-caption .cap-marker { position: absolute; left: -34px; top: 0; height: 1.5em; }
  #demo-caption .cap-subs { margin-top: 9px; }
  #demo-caption .cap-sub { font-size: 15.5px; line-height: 1.5; }
  #demo-caption .cap-benefits { justify-content: flex-start; }
  /* 24px, up from 20: a numeral inside a 20px ring lands at about 8px, and we
     spent three passes fixing text that small elsewhere on this page. */
  .cap-ring { display: inline-flex; flex: none; width: 24px; height: 24px;
    filter: drop-shadow(0 0 6px rgba(33,212,237,0.45)); }
  .cap-num { position: absolute; inset: 0; display: flex; align-items: center;
    justify-content: center; font-size: 10.5px; }
}

@keyframes rg-shimmer {
  0% { background-position: -200% 0; }
  100% { background-position: 200% 0; }
}
.rg-skeleton {
  border-radius: 10px;
  background: linear-gradient(90deg, rgba(33, 212, 237, 0.06) 25%, rgba(33, 212, 237, 0.20) 37%, rgba(33, 212, 237, 0.06) 63%);
  background-size: 200% 100%;
  animation: rg-shimmer 1.4s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) { .rg-skeleton { animation: none; } }

/* ===========================================================================
   LIGHT MODE (spec §4). Content (page sections + footer) inverts to a light
   surface with dark ink; cinematic image panels stay dark; chrome (nav, modals)
   stays dark for legibility. The report is handled separately above.
   Scoped so nothing here affects the dark theme.
   =========================================================================== */
:root[data-theme="light"] #page-sections { background: #F5F7FA; }
:root[data-theme="light"] footer { background: #F5F7FA !important; }

/* Ink — invert the white text utilities inside content (keep grad-CTA text white) */
:root[data-theme="light"] #page-sections .text-white:not([style*="grad-cta"]),
:root[data-theme="light"] footer .text-white:not([style*="grad-cta"]) { color: #0B0E14; }
:root[data-theme="light"] #page-sections .text-white\/90, :root[data-theme="light"] footer .text-white\/90 { color: rgba(11,14,20,0.90); }
:root[data-theme="light"] #page-sections .text-white\/70, :root[data-theme="light"] footer .text-white\/70 { color: rgba(11,14,20,0.72); }
:root[data-theme="light"] #page-sections .text-white\/60, :root[data-theme="light"] footer .text-white\/60 { color: rgba(11,14,20,0.62); }
:root[data-theme="light"] #page-sections .text-white\/55, :root[data-theme="light"] footer .text-white\/55 { color: rgba(11,14,20,0.58); }
:root[data-theme="light"] #page-sections .text-white\/50, :root[data-theme="light"] footer .text-white\/50 { color: rgba(11,14,20,0.55); }
:root[data-theme="light"] #page-sections .text-white\/45, :root[data-theme="light"] footer .text-white\/45 { color: rgba(11,14,20,0.50); }
:root[data-theme="light"] #page-sections .text-white\/40, :root[data-theme="light"] footer .text-white\/40 { color: rgba(11,14,20,0.45); }

/* Borders + inner surfaces */
:root[data-theme="light"] #page-sections .border-white\/10, :root[data-theme="light"] footer .border-white\/10 { border-color: rgba(0,0,0,0.08); }
:root[data-theme="light"] #page-sections .border-white\/15 { border-color: rgba(0,0,0,0.12); }
:root[data-theme="light"] #page-sections .border-white\/20 { border-color: rgba(0,0,0,0.14); }
:root[data-theme="light"] #page-sections .bg-white\/\[0\.03\] { background: rgba(0,0,0,0.025); }
:root[data-theme="light"] #page-sections .bg-white\/\[0\.04\] { background: rgba(0,0,0,0.035); }
:root[data-theme="light"] #page-sections .bg-white\/\[0\.06\] { background: rgba(0,0,0,0.05); }

/* Chrome stays dark in light mode (readability): floating nav + modal panels */
:root[data-theme="light"] header { background: rgba(16,20,26,0.72); border-color: rgba(255,255,255,0.10); }
:root[data-theme="light"] #wizard .rg-glass,
:root[data-theme="light"] #checkout .rg-glass,
:root[data-theme="light"] #waitlist .rg-glass { background: rgba(16,20,26,0.94); border-color: rgba(255,255,255,0.10); }

/* Inline form-error feedback (invalid email) */
@keyframes rg-shake { 0%, 100% { transform: translateX(0); } 25% { transform: translateX(-4px); } 75% { transform: translateX(4px); } }
.rg-invalid { border-color: #FF3B30 !important; animation: rg-shake .3s ease; }
.section {
  max-width: 72rem;
  margin: 0 auto;
  padding: 96px 24px;        /* 8px grid */
}
/* Two sections stacked put 96px + 96px between them, which on a 375px screen is
   more than half a viewport of empty dark. The rhythm is a desktop one; phones
   get a tighter version. */
@media (max-width: 767.98px) {
  .section { padding: 56px 20px; }
}

/* Reveal-on-scroll (IntersectionObserver adds .in). */
.reveal {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity .7s cubic-bezier(.23, 1, .32, 1), transform .7s cubic-bezier(.23, 1, .32, 1);
}
.reveal.in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; transition: none; }
}

.lang-head .srch svg { width: 10px; height: 10px; flex: none; opacity: 0.75; }

/* Mobile language switcher — the locale reads as a circular flag, centre-cropped
   from the real 2:1 / 3:2 flag by preserveAspectRatio="slice", instead of a
   two-letter code. Which flag shows is driven by <html lang>, which the i18n
   apply() already sets, so nothing in JS enumerates the flags. The seven mock
   locales have no flag, so for those the two-letter code comes back. */
[data-lang-toggle] { --flag: 24px; }
[data-lang-toggle].lang-toggle--sm { --flag: 20px; }
[data-lang-toggle] .lang-code { display: none; }
[data-lang-toggle] .lang-flag { display: none; width: var(--flag); height: var(--flag); flex: none;
  border-radius: 999px; overflow: hidden;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,0.3), 0 1px 3px rgba(0,0,0,0.4); }
[data-lang-toggle] .lang-flag svg { display: block; width: 100%; height: 100%; }
html[lang="en"] [data-lang-toggle] .lang-flag-en,
html[lang="ru"] [data-lang-toggle] .lang-flag-ru { display: block; }
html:not([lang="en"]):not([lang="ru"]) [data-lang-toggle] .lang-code { display: inline; }

/* ---------------------------------------------------------------------------
   STORE BUTTONS — one component behind every App Store / Android button on the
   site. Before this there were seven Apple buttons spread over four heights,
   three icon sizes and three different labels, and four Android buttons in
   three different glass treatments (one of them carrying an older, slightly
   different robot path). Sizes are carried by custom properties, so a size
   variant sets numbers instead of restating the rules.
--------------------------------------------------------------------------- */
.store-btn {
  --sb-h: 44px; --sb-icon: 20px; --sb-sm: 9px; --sb-lg: 15px; --sb-px: 20px; --sb-gap: 8px;
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  gap: var(--sb-gap); height: var(--sb-h); padding: 0 var(--sb-px);
  border-radius: 999px;
  transition: transform .18s ease, background-color .18s ease, border-color .18s ease;
}
.store-btn:active { transform: scale(0.97); }
.store-btn__icon { width: var(--sb-icon); height: var(--sb-icon); flex: none; }
.store-btn__label { display: flex; flex-direction: column; line-height: 1; text-align: left; }
.store-btn__label > span:first-child { font-size: var(--sb-sm); font-weight: 500; letter-spacing: 0.025em; }
.store-btn__label > span:last-child { font-size: var(--sb-lg); font-weight: 600; margin-top: -2px; }

.store-btn--lg { --sb-h: 48px; --sb-icon: 22px; --sb-lg: 17px; --sb-px: 16px; }
.store-btn--sm { --sb-h: 36px; --sb-icon: 16px; --sb-sm: 8px; --sb-lg: 13px; --sb-px: 14px; --sb-gap: 7px; }
/* The large size only gets its own numbers where there is room for them. Below
   360px the hero splits the row in two and "App Store" at 17px needs 81.9px
   against the 72px that exist — so it steps down to the medium numbers rather
   than wrapping inside the pill. Above 1024px the pills sit in a free-flowing
   row, so they can afford the wider side padding. */
@media (max-width: 359.98px) { .store-btn--lg { --sb-icon: 20px; --sb-lg: 15px; --sb-px: 12px; } }
@media (min-width: 1024px) { .store-btn--lg { --sb-px: 20px; } }

.store-btn--apple { background: #fff; color: #000; }
.store-btn--android { color: #fff; border: 1.5px solid rgba(255,255,255,0.35);
  background: rgba(255,255,255,0.08);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); }
.store-btn--android:hover { border-color: rgba(255,255,255,0.6); background: rgba(255,255,255,0.16); }
/* Only where the button sits on a photograph and needs to lift off it. */
.store-btn--lift { box-shadow: 0 8px 24px rgba(0,0,0,0.45); }
:root[data-theme="light"] .store-btn { box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12); }

@media (prefers-reduced-motion: reduce) { .store-btn { transition: none; } .store-btn:active { transform: none; } }
