/* Reach marketing site — brand-matched to the mobile app's dark theme.
   Colors mirror mobile/theme.ts DARK + ACCENT. */

:root {
    --bg: #010912;
    --fg: #FFFFFF;
    --muted: #C6CDD4; /* was #8D9094 — unreadable on phones; now matches app BODY_TEXT */
    --accent: #19cbbf;
    --hero-blue: #86DBFF; /* the rotating word, and the hero paragraph under it */
    --card: #14181C;
    --border: #2A3038;
    --divider: #1A222A;
    --track: #1F262E;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
    background: var(--bg);
    color: var(--fg);
    font-family: 'Nunito', system-ui, sans-serif;
    font-weight: 300;
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; }
a { color: var(--accent); text-decoration: none; }

/* Nav, footer, and every section ride this — widening it widens the whole site,
   which is where the hero's three columns get the room to breathe. */
.r-shell { max-width: 1320px; margin: 0 auto; padding: 0 24px; }
.r-section { padding: 96px 0; }

/* ── Type ── */
.r-h2 {
    font-family: 'Nunito', sans-serif;
    font-weight: 800;
    font-size: clamp(34px, 6vw, 56px);
    line-height: 1.1;
    letter-spacing: -0.5px;
    margin-bottom: 40px;
}
.r-h2-center { text-align: center; }
/* The original eyebrow voice — Montserrat caps in accent cyan — promoted to
   full headline size. Tracking is tighter than the 12px original so FEATURES
   fits one line on small phones. */
.r-h2-eyebrow {
    font-family: 'Montserrat', sans-serif;
    font-weight: 600;
    letter-spacing: 0.18em;
    margin-right: -0.18em; /* trim trailing letter-space so the word centers on its ink */
    text-transform: uppercase;
    color: var(--accent);
}

/* ── Shimmer text ──
   The app's SessionComplete idle shine, painted through glyphs instead of
   muscles: one gradient three times the word's width, swept across it, clipped
   to the letters. Stops are the app's sharedDefs shine — cyan with a 2% white
   peak — so the streak reads as one continuous sweep over the whole word. */
.r-shine {
    background-image: linear-gradient(100deg,
        #19cbbf 0%, #19cbbf 41%, #5de8e2 46%, #b8f8f5 49%,
        #ffffff 50%,
        #b8f8f5 51%, #5de8e2 54%, #19cbbf 59%, #19cbbf 100%);
    background-size: 300% 100%;
    background-repeat: no-repeat;
    background-position: 100% 0;
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    -webkit-text-fill-color: transparent;
    /* Starts on load and comes round often — the sweep is the thing that makes
       the word read as "interesting", so waiting on it is wasted. */
    animation: r-shine-sweep 3s ease-in-out infinite;
}
/* Both ends of the loop sit on flat cyan, so the reset never shows. */
@keyframes r-shine-sweep {
    0% { background-position: 100% 0; }
    72% { background-position: 0% 0; }
    100% { background-position: 0% 0; }
}

/* ── Buttons ── */
.r-btn {
    display: inline-block;
    font-family: 'Nunito', sans-serif;
    font-weight: 700;
    font-size: 16px;
    border: none;
    border-radius: 14px;
    padding: 14px 26px;
    cursor: pointer;
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.r-btn:hover { transform: translateY(-1px); }
.r-btn-primary {
    background: var(--accent);
    color: var(--bg);
    box-shadow: 0 4px 24px rgba(25,203,191,0.35);
}
.r-btn-sm { padding: 8px 18px; font-size: 14px; border-radius: 10px; }

/* ── Nav ── */
.r-nav {
    position: fixed;
    top: 0; width: 100%;
    z-index: 50;
    background: rgba(1,9,18,0.78);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    border-bottom: 1px solid var(--divider);
}
.r-nav-inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding-top: 12px;
    padding-bottom: 12px;
}
.r-lockup { display: flex; align-items: center; gap: 10px; }
.r-lockup-icon { width: 45px; height: 45px; }
.r-lockup-word {
    font-family: 'Montserrat', sans-serif;
    font-weight: 500;
    font-size: 24px;
    letter-spacing: 0.4em;
    color: var(--fg);
}
.r-nav-links { display: flex; align-items: center; gap: 28px; }
.r-nav-links a { color: var(--fg); font-weight: 600; font-size: 15px; opacity: 0.85; }
.r-nav-links a:hover { opacity: 1; }
.r-nav-links a.r-btn { opacity: 1; color: var(--bg); }
.r-nav-cta-narrow { display: none; }

/* ── Hero ── */
.r-hero {
    position: relative;
    overflow: hidden;
    min-height: 100svh;
    display: flex;
    align-items: center;
    padding: 96px 0 28px;
}
/* Painted as gradients, not as blurred solids. A 130px blur on a 480px box is
   re-rasterized on the CPU in Safari on every restyle — with ten webfonts
   swapping in, that alone cost ~3.2s of blocked main thread. */
.r-glow {
    position: absolute;
    border-radius: 50%;
    pointer-events: none;
}
.r-glow-a {
    width: 740px; height: 740px; top: -250px; right: -210px;
    background: radial-gradient(closest-side, rgba(25,203,191,0.15), rgba(25,203,191,0.06) 52%, transparent 78%);
}
.r-glow-b {
    width: 620px; height: 620px; bottom: -270px; left: -250px;
    background: radial-gradient(closest-side, rgba(25,203,191,0.09), rgba(25,203,191,0.035) 52%, transparent 78%);
}

.r-hero-grid {
    position: relative;
    display: grid;
    grid-template-columns: var(--map-col) minmax(0, 1fr) max-content; /* map | copy | phone */
    column-gap: 0; /* the two gaps differ — see .r-hero-copy padding */
    align-items: start; /* map + phone hang from the same line as the logo */
    width: 100%;
    /* Height matters as much as width here — the phone runs past the row, so a
       short window has to shrink the whole pair or the fade gets clipped. */
    --rail: clamp(300px, min(42vw, 60vh), 540px);
    /* The map runs taller than the phone's rail — it's a sparse figure, so it
       needs more size to carry the same visual weight as the solid slab. */
    --map-rail: min(calc(var(--rail) * 1.28), 74vh);
    /* site.js sets --map-ratio from the figure's real ink bbox; 0.407 is the
       female figure's ratio, used until the SVG lands. */
    --map-width: calc(var(--map-rail) * var(--map-ratio, 0.407));
    /* The copy sits over the map's *box*, never its ink. The figure only fills
       its bbox at the hands; beside the paragraph it's legs, which sit ~24% in.
       Capped well under that so the copy can never reach the body. */
    --map-overlap: min(calc(var(--map-width) * 0.14), 46px);
    /* The map's column is narrower than the map, so the figure bleeds right
       under the copy column instead of pushing the copy away. */
    --map-col: calc(var(--map-width) - var(--map-overlap));
    /* One gap, measured from ink to ink: the figure bleeds --map-overlap past
       its column, so the copy's left inset has to clear that first. Equal ink
       gaps put the lockup on the midpoint between the figure and the phone —
       the visual centre, which is not the section's geometric centre. */
    --gap-copy: clamp(20px, 2.5vw, 38px);
}
/* Vertical lockup mirroring the app splash: icon on top, REACH beneath,
   cycling word under that — everything centered on the letters' ink. */
.r-hero-copy {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    /* Copy box rides into the map's bbox — the ink beside it is legs, ~24%
       inside the bbox, so zero padding still leaves clear air to the figure. */
    padding-left: 0;
    padding-right: var(--gap-copy);
}
.r-hero-brand { display: flex; flex-direction: column; align-items: center; margin-bottom: 26px; }
.r-hero-icon { width: clamp(96px, 13vw, 122px); height: auto; margin-bottom: 10px; }
.r-hero-word {
    font-family: 'Montserrat', sans-serif;
    font-weight: 500;
    font-size: clamp(36px, 5vw, 52px);
    letter-spacing: 0.4em;
    margin-right: -0.4em; /* trim trailing letter-space so bounds = letter ink */
    color: var(--fg);
    line-height: 1;
}
.r-rotator {
    height: 1.4em;
    text-align: center;
    font-family: 'Montserrat', sans-serif;
    font-weight: 300;
    font-size: clamp(19px, 2.8vw, 29px);
    letter-spacing: 0.5em;
    color: var(--hero-blue);
    margin-top: 14px;
}
.r-rotator span { margin-right: -0.5em; } /* trim trailing letter-space so the word centers on its ink */
/* Long fade on purpose: the word changes often, but slowly enough that the
   change registers as breathing rather than as a swap. */
.r-rotator span { display: inline-block; transition: opacity 1.8s ease-in-out, transform 1.8s ease-in-out; }
.r-rotator span.out { opacity: 0; transform: translateY(4px); }

/* Same Montserrat voice as REACH and the rotating word — this is a caption
   under a wordmark, not a second headline. */
.r-hero-h1 {
    font-family: 'Montserrat', sans-serif;
    font-weight: 500;
    font-size: clamp(14px, 1.5vw, 18px);
    letter-spacing: 0.08em;
    line-height: 1.75;
    color: var(--fg);
    margin-bottom: 18px;
}
/* Runs wide on purpose — lines that reach the column edge give the centred copy
   a firmer optical edge, so the body map stops looking stranded beside it. */
.r-hero-h1 em { font-style: italic; }
/* Sub's italic is the one phrase that names the feature — lifted to full white
   and bold so it reads first out of the muted paragraph. */
.r-hero-sub em { font-style: italic; color: var(--fg); font-weight: 700; }
.r-hero-sub {
    color: var(--muted);
    font-size: 18px;
    max-width: 60ch;
    margin-bottom: 28px;
}
.r-fun { color: #86DBFF; font-weight: 600; }

/* Last item in the copy column, so it centres on REACH rather than on the
   section — the two have different centres. */
.r-scroll {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    margin-top: 40px;
    color: var(--muted);
    font-family: 'Montserrat', sans-serif;
    font-size: 12px;
    letter-spacing: 0.3em;
    text-transform: uppercase;
}
/* Short window: the copy nearly fills it, so the cue tucks up under the
   paragraph rather than falling off the first screen. */
@media (max-height: 820px) {
    .r-scroll { margin-top: 12px; }
}
.r-scroll:hover { color: var(--fg); }
.r-scroll svg { animation: r-bob 1.6s ease-in-out infinite; }
@keyframes r-bob {
    0%, 100% { transform: translateY(0); }
    50% { transform: translateY(6px); }
}

.r-notify { display: flex; gap: 12px; flex-wrap: wrap; justify-content: center; scroll-margin-top: 120px; }
.r-notify input[type="email"] {
    flex: 1;
    min-width: 220px;
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 14px 18px;
    color: var(--fg);
    font-family: 'Nunito', sans-serif;
    font-size: 16px;
}
.r-notify input[type="email"]::placeholder { color: var(--muted); }
.r-notify input[type="email"]:focus { outline: none; border-color: var(--accent); }
/* Drawn-attention state after a signup button click: accent outline, subtle
   teal wash, and a soft double-pulse of glow — same palette as the CTAs. */
.r-notify input[type="email"].r-attn {
    border-color: var(--accent);
    background: rgba(25,203,191,0.07);
    animation: r-attn-pulse 1.4s ease 2;
}
@keyframes r-attn-pulse {
    0%, 100% { box-shadow: 0 0 0 0 rgba(25,203,191,0); }
    50% { box-shadow: 0 0 0 5px rgba(25,203,191,0.16), 0 0 28px rgba(25,203,191,0.35); }
}
.r-honeypot { display: none; }
.r-notify-done { color: var(--accent); font-weight: 700; margin-top: 12px; }

/* ── Store lockups ── */
/* Store-badge shaped, but inert: nothing to open until launch, so they get no
   href, no hover lift, and no pointer. */
.r-stores { display: flex; gap: 12px; flex-wrap: wrap; justify-content: center; margin-top: 26px; }
.r-store {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    min-width: 176px;
    padding: 9px 18px 9px 15px;
    border: 1px solid rgba(255,255,255,0.22);
    border-radius: 12px;
    background: #000;
    color: var(--fg);
    cursor: default;
    opacity: 0.72;
}
.r-store-glyph { width: 25px; height: 25px; flex: none; }
.r-store-text { display: flex; flex-direction: column; line-height: 1.1; text-align: left; }
.r-store-text small {
    font-family: 'Montserrat', sans-serif;
    font-size: 9.5px;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: #C6C9CC;
}
.r-store-text strong {
    font-family: 'Montserrat', sans-serif;
    font-weight: 500;
    font-size: 19px;
    letter-spacing: -0.2px;
    margin-top: 2px;
}

/* ── Signup band (sits just below the hero, off the first screen) ── */
.r-signup {
    padding: 46px 0 56px;
    text-align: center;
    background: radial-gradient(ellipse at 50% 0%, rgba(25,203,191,0.07), transparent 68%);
}
/* The form used to sit in the hero's narrow column; the band is full-shell
   width, so it needs its own measure or the input runs the whole page. */
.r-signup .r-notify { max-width: 620px; margin: 0 auto; }

/* ── Body map ── */
/* Sized off --map-rail, which runs taller than the phone's rail. Width comes
   from --map-ratio (the figure's real ink ratio, set by site.js once the SVG
   lands) so the box is exactly as wide as the figure — no dead padding. */
.r-hero-map {
    height: var(--map-rail);
    width: var(--map-width);
    overflow: visible; /* wider than its column on purpose — see --map-overlap */
}
.r-hero-map svg {
    width: 100%;
    height: 100%;
    overflow: visible;
    opacity: 0;
    transition: opacity 1.4s ease;
}
.r-hero-map svg.shown { opacity: 1; }
.r-hero-map .m {
    stroke: var(--bg);
    stroke-width: 0.5;
}
/* Every muscle stays lit. The paint is the shared sweep gradient injected by
   site.js — one gradient across the whole figure, so the white streak reads as
   a single shine engulfing the body rather than one shimmer per muscle. Flat
   accent is the fallback if the gradient never lands. */
.r-hero-map .m:not(.nm) {
    fill: url(#heroShine) #19cbbf;
}
.r-hero-map .m.nm {
    fill: #787878; /* app NON_MUSCLE_FILL — head, hands, feet, knees… never lights */
}

/* ── Hero demo phone ── */
/* The row is --rail tall, but the phone inside is taller and runs past the
   bottom, faded out — it reads as bigger than the frame it sits in. */
.r-hero-device {
    position: relative;
    display: flex;
    justify-content: center;
    align-items: flex-start; /* stretch would override the phone's aspect-derived height */
    height: var(--rail);
}
.r-hero-device::before { /* accent bloom behind the device, same recipe as .r-glow */
    content: '';
    position: absolute;
    inset: -8% -46% -6%;
    background: radial-gradient(closest-side, rgba(25,203,191,0.15), rgba(25,203,191,0.05) 55%, transparent 80%);
    border-radius: 50%;
    pointer-events: none;
}
/* Sized by width now; the height follows from the screen ratio, which runs it
   well past the row. Only the last tenth fades, and it finishes on the frame's
   own bottom edge — so the phone reads whole, not as a cropped strip. The 0.86
   scale is what keeps the fade ending on the same line the map's feet end on:
   the old mask died at 86% of a bigger frame. */
.r-phone.r-phone-hero { /* two classes: .r-phone's width is declared further down */
    position: relative;
    /* 42vh caps it by height as well as by the rail: the frame is 2.18× as tall
       as it is wide, and the fade has to finish above the fold. */
    width: calc(clamp(240px, min(calc(var(--rail) * 0.7), 42vh), 400px) * 0.86);
    -webkit-mask-image: linear-gradient(to bottom, #000 90%, transparent 100%);
    mask-image: linear-gradient(to bottom, #000 90%, transparent 100%);
}
.r-phone-hero .r-phone-screen { background: #000; }

.r-hero-video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
/* Frame 1, sat over the video until the decoder has a real frame up. Same
   image, so the handover is a no-op on screen; the fade only covers the
   slight colour difference between the JPEG and the decoded video. */
.r-hero-still {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    transition: opacity 0.18s linear;
    pointer-events: none;
}
.r-hero-still.is-gone { opacity: 0; }

.r-video-play {
    position: absolute;
    inset: 0;
    margin: auto;
    width: 58px; height: 58px;
    display: grid;
    place-items: center;
    border: none;
    border-radius: 50%;
    background: var(--accent);
    color: var(--bg);
    cursor: pointer;
    box-shadow: 0 8px 30px rgba(0,0,0,0.5);
}
.r-video-play[hidden] { display: none; }

/* Covers the phone at the end of each pass — the body map takes its one shine
   while this is up, so the two never compete for attention. */
.r-phone-dark {
    position: absolute;
    inset: 0;
    background: #000;
    opacity: 0;
    transition: opacity 1.5s ease-in-out;
    pointer-events: none;
}
.r-phone-dark.on { opacity: 1; }
/* Mobile loop restart: a blink, not an interlude — the body map is hidden
   there, so there is nothing to watch during a long black. */
.r-phone-dark.fast { transition: opacity 0.2s ease-in-out; }

/* ── Features tour: one screen and its label at a time ── */
/* One centred stack at every width — no desktop variant, so the two layouts
   cannot drift apart. */
.r-tour {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 26px;
}
/* The divider belongs to the heading, so it sits closer to it than the default
   section gap allows. */
#features .r-h2 { margin-bottom: 26px; }
/* The stage's bloom (::before) bleeds ~34% past the phone on each side; without
   this clip its invisible tail widens the page and iPhones side-scroll. */
main { overflow-x: clip; }
.r-tour-stage { position: relative; }
.r-tour-stage::before { /* accent bloom, same recipe as the hero device */
    content: '';
    position: absolute;
    inset: -6% -34%;
    background: radial-gradient(closest-side, rgba(25,203,191,0.14), rgba(25,203,191,0.05) 55%, transparent 80%);
    border-radius: 50%;
    pointer-events: none;
}
/* Sized off the label, not the screenshot: the phone is 2.18x as tall as it is
   wide, so anything over ~210px pushes the label below the fold. */
/* Frame geometry is the hero device's, unscaled: the thinned 2px/30px bezel
   read as a rounded rectangle around a picture rather than a phone, because the
   corners stopped being concentric with the screen's. Width is the only thing
   that differs between the two devices. */
.r-phone.r-phone-tour {
    width: min(70vw, 280px);
    touch-action: pan-y; /* the stage reads horizontal swipes itself */
}
/* Stacked and swiped, not crossfaded: the screen leaves left and the next one
   arrives from the right, which is how the app itself is navigated. Fully
   opaque throughout — the parked shots sit outside .r-phone-screen's clip, so
   nothing needs fading to stay hidden. The two custom properties are flipped by
   site.js so a backwards move runs the other way. */
/* Stacked and crossfaded — the frame keeps its height whichever screen is up.
   Brisk on purpose: the divider and the words above carry the change, so the
   screen only has to keep up with them. */
.r-tour-shot {
    position: absolute;
    inset: 0;
    opacity: 0;
    transition: opacity 0.3s ease;
}
.r-tour-shot.is-on { opacity: 1; }

/* Prev/next chevrons flanking the phone — same accent as the dots. */
.r-tour-arrow {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    display: grid;
    place-items: center;
    padding: 12px 8px;
    border: none;
    background: none;
    color: var(--accent);
    cursor: pointer;
    opacity: 0.8;
    transition: opacity 0.2s ease;
}
.r-tour-arrow:hover { opacity: 1; }
.r-tour-prev { left: -52px; }
.r-tour-next { right: -52px; }

/* Divider + label, sat between the heading and the phone. The head owns its own
   height so the phone below is placed once, on first render, and never moves
   again as the tour advances. */
.r-tour-head {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 20px;
    width: 100%;
}
/* The app's welcome-slide divider: 2px accent line, grown from its centre. It
   re-runs on every advance because the line finishing is the cue that the words
   under it have changed. */
.r-tour-rule {
    width: 64px;
    height: 2px;
    border-radius: 999px;
    background: var(--accent);
    opacity: 0.6;
}
.r-tour-rule.is-swap {
    animation: r-rule-swap 780ms cubic-bezier(0.22, 0.61, 0.36, 1);
}
/* Past 100% at the midpoint, then settles back — a line that only grows to its
   width reads as arriving; one that overshoots reads as a beat. */
@keyframes r-rule-swap {
    0%   { transform: scaleX(0); opacity: 0.15; }
    55%  { transform: scaleX(1.22); opacity: 0.95; }
    100% { transform: scaleX(1); opacity: 0.6; }
}

/* Height is reserved for the longest label so the phone — and everything below
   it — holds still while the tour advances. */
.r-tour-labels {
    position: relative;
    width: 100%;
    max-width: 30ch;
    min-height: 6em;
}
.r-tour-label {
    position: absolute;
    inset: 0;
    margin: 0;
    opacity: 0;
    /* Rises into place like the app's WelcomeReveal rather than just fading —
       the movement is what makes the change register at a glance. */
    transform: translateY(14px);
    text-align: center;
    color: #F5F7FA;
    font-family: 'Montserrat', sans-serif;
    font-size: 16px;
    line-height: 1.5;
    letter-spacing: -0.1px;
    transition: opacity 0.4s ease, transform 0.5s cubic-bezier(0.22, 0.61, 0.36, 1);
}
/* Delayed just past the divider's overshoot, so the line leads and the words
   land on it. */
.r-tour-label.is-on {
    opacity: 1;
    transform: none;
    transition-delay: 0.14s;
}

.r-tour-dots {
    display: flex;
    gap: 10px;
}
.r-tour-dot {
    position: relative;
    width: 8px;
    height: 8px;
    padding: 0;
    border: none;
    border-radius: 50%;
    background: var(--track);
    cursor: pointer;
    transition: background 0.35s ease, transform 0.35s ease;
}
.r-tour-dot::after { /* 8px is the mark, not the target — this is the thumb's share */
    content: '';
    position: absolute;
    inset: -16px -9px;
}
.r-tour-dot.is-on {
    background: var(--accent);
    transform: scale(1.25);
}

/* ── Phone frames ── */
/* Height is derived from the screen, not set here — the bezel adds to it. Putting
   the ratio on the frame instead squeezed the screen to 0.442 against the
   recording's 0.459, and object-fit quietly cropped the sides. */
.r-phone {
    position: relative;
    width: 240px;
    background: #06101a;
    border: 3px solid var(--border);
    border-radius: 40px;
    padding: 7px;
    box-shadow: 0 28px 64px rgba(0,0,0,0.6), 0 0 40px rgba(25,203,191,0.07);
}
.r-phone::after { /* thin inner highlight so the bezel reads as glass, not a border */
    content: '';
    position: absolute;
    inset: 1px;
    border-radius: 38px;
    border: 1px solid rgba(255,255,255,0.07);
    pointer-events: none;
}
.r-phone-screen {
    position: relative;
    width: 100%;
    aspect-ratio: 496 / 1080; /* the recording's exact ratio — nothing gets cropped */
    border-radius: 33px;
    overflow: hidden;
    background: var(--bg);
}
.r-phone-screen img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ── Science page ── */
/* Claims are quoted verbatim from the app's References screen; the markers and
   the numbered list mirror its CitationMarker + CitationSheet pairing. */
/* Science rides the same top clearance as the legal pages — the nav is fixed,
   so the section's own padding is all that separates the h1 from its line. */
.r-section.r-science-page { padding-top: 140px; } /* double class: outranks the mobile .r-section padding override */
.r-science-intro {
    color: var(--muted);
    font-size: 18px;
    max-width: 62ch;
    margin: 0 auto 52px;
    text-align: center;
}
/* One column on phones, body before mind; the desktop rule splits it in two. */
.r-sci-grid {
    display: grid;
    gap: 44px;
    max-width: 900px;
    margin: 0 auto;
    align-items: start; /* the shorter column ends where it ends — no padding it out */
}
.r-sci-col-head {
    font-family: 'Montserrat', sans-serif;
    font-weight: 600;
    font-size: 22px;
    /* Tracking eased from the 12px eyebrow's 0.28em — at this size that much
       spacing pushes the caps line wider than its column. */
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--accent);
    margin-bottom: 22px;
    text-align: center;
}
.r-sci-list { list-style: none; }
.r-sci-claim {
    font-family: 'Nunito', sans-serif;
    /* 300 is the only hosted Nunito weight below 600 — no 400/500 files. */
    font-weight: 300;
    font-size: 19px;
    line-height: 1.5;
    color: #F5F7FA;
    padding-left: 22px;
    margin-bottom: 26px;
    position: relative;
}
.r-sci-claim::before { /* the same lit dot the app uses for a worked muscle */
    content: '';
    position: absolute;
    left: 0;
    top: 10px;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--accent);
    box-shadow: 0 0 0 3px rgba(25,203,191,0.16), 0 0 14px rgba(25,203,191,0.5);
}
.r-sci-mark {
    font-size: 0.62em;
    vertical-align: super;
    color: var(--accent);
    margin-left: 3px;
}

.r-refs {
    max-width: 900px;
    margin: 56px auto 0;
    padding-top: 28px;
    border-top: 1px solid var(--divider);
}
.r-refs-head {
    font-family: 'Montserrat', sans-serif;
    font-weight: 600;
    font-size: 12px;
    letter-spacing: 0.28em;
    text-transform: uppercase;
    color: var(--muted);
    margin-bottom: 18px;
    text-align: center;
}
.r-refs-list {
    list-style: decimal;
    padding-left: 20px;
    color: var(--muted);
    font-family: 'Montserrat', sans-serif;
    font-size: 14px;
    line-height: 1.9;
}
.r-science-note {
    margin-top: 28px;
    text-align: center;
    color: #8D9094; /* deliberately quieter than --muted — fine-print, not body copy */
    font-size: 14px;
}

/* ── CTA band ── */
.r-cta {
    text-align: center;
    padding: 96px 0;
    background:
        radial-gradient(ellipse at center, rgba(25,203,191,0.08), transparent 70%);
    border-top: 1px solid var(--divider);
}
.r-cta p { color: var(--muted); margin-bottom: 28px; }
.r-cta-collage {
    width: min(340px, 74vw);
    height: auto;
    margin: 0 auto 56px;
    display: block;
}
.r-cta-lockup {
    font-family: 'Nunito', sans-serif;
    font-weight: 700;
    font-size: clamp(38px, 6.4vw, 72px);
    line-height: 1.24;
    letter-spacing: -0.5px;
    margin-bottom: 24px;
}
.r-cta-lockup span { display: block; }
.r-cta-accent { color: var(--accent); }
.r-cta-plain { color: var(--fg); }

/* ── Footer ── */
.r-footer { border-top: 1px solid var(--divider); padding: 48px 0; }
.r-footer-inner { display: flex; flex-direction: column; align-items: center; gap: 20px; text-align: center; }
.r-footer-links { display: flex; gap: 24px; flex-wrap: wrap; justify-content: center; }
.r-footer-links a { color: var(--muted); font-size: 14px; font-weight: 600; }
.r-footer-links a:hover { color: var(--fg); }
.r-footer-note { color: var(--muted); font-size: 13px; max-width: 60ch; }
.r-footer-copy { color: var(--muted); font-size: 13px; }

/* ── Scroll reveal ── */
.r-rise { opacity: 0; transform: translateY(24px); transition: opacity 0.6s ease, transform 0.6s ease; }
.r-rise.on { opacity: 1; transform: none; }

/* ── Legal pages ── */
/* Side padding lives here, not on .r-shell — this rule is later in the file,
   so `0` sides would win and put the text at the screen edge. */
.r-legal { padding: 140px clamp(28px, 7vw, 48px) 80px; max-width: 780px; }
.r-legal h1 { font-family: 'Nunito', sans-serif; font-weight: 800; font-size: 36px; margin-bottom: 8px; }
.r-legal h2 { font-family: 'Nunito', sans-serif; font-weight: 700; font-size: 24px; margin: 40px 0 12px; }
.r-legal h3 { font-family: 'Nunito', sans-serif; font-weight: 700; font-size: 18px; margin: 28px 0 8px; }
.r-legal p, .r-legal li { color: #D5DAE0; font-size: 16px; margin-bottom: 12px; }
.r-legal ul { padding-left: 24px; margin-bottom: 16px; }
.r-legal .r-legal-meta { color: var(--muted); font-size: 14px; margin-bottom: 32px; }
.r-legal table { width: 100%; border-collapse: collapse; margin: 16px 0 24px; font-size: 14px; }
.r-legal th, .r-legal td { border: 1px solid var(--border); padding: 10px 12px; text-align: left; color: #C6C9CC; vertical-align: top; }
.r-legal th { background: var(--card); color: var(--fg); font-family: 'Nunito', sans-serif; font-weight: 700; }
.r-legal-table-wrap { overflow-x: auto; }
.r-legal strong { color: var(--fg); }

/* ── About page accents ── */
/* The app's WelcomeDivider — 56×2 cyan pill at 60% — between sections. */
.r-wdivider {
    width: 56px;
    height: 2px;
    border-radius: 999px;
    background: var(--accent);
    opacity: 0.6;
    margin: 48px auto 0;
}
.r-wdivider + h2 { margin-top: 28px; }
.r-about-cta { text-align: center; margin-top: 44px; }

/* ── Responsive ── */
/* Wide enough for the science claims to run body-beside-mind. The tour is one
   centred stack at every width — no desktop variant. */
@media (min-width: 861px) {
    /* Desktop only: sized off the hero device instead of the label — same rail
       math, ~88% of it, so the tour reads as the same phone seen again. Mobile
       keeps the label-driven width above. */
    .r-phone.r-phone-tour {
        --tour-rail: clamp(300px, min(42vw, 60vh), 540px);
        width: clamp(220px, min(calc(var(--tour-rail) * 0.62), 38vh), 360px);
    }
    /* The small-phone bloom banded once the frame grew — same alpha spread over
       ~1.7x the area shows its stops. Wider, weaker, longer falloff plus a blur,
       so it reads as ambient light like the CTA band rather than a painted blob. */
    .r-tour-stage::before {
        inset: -16% -40%;
        background: radial-gradient(ellipse at 50% 48%,
            rgba(25,203,191,0.10),
            rgba(25,203,191,0.045) 40%,
            rgba(25,203,191,0.015) 64%,
            transparent 82%);
        filter: blur(36px);
    }
    .r-tour-labels { max-width: 44ch; min-height: 4.6em; }
    .r-tour-label { font-size: 17px; }

    .r-sci-grid { grid-template-columns: 1fr 1fr; gap: 56px; }
}
@media (min-width: 1041px) {
    /* Three-column layout only: drop the pair to the logo's ink line. */
    .r-hero-map, .r-hero-device { margin-top: var(--logo-ink-offset, 0px); }

    /* Desktop header + footer lockup, sized as one system off a single knob.
       --nav-icon is the only thing here that reads the viewport; the bar's
       padding, the wordmark, the links and the CTA are all fractions of it, so
       the header grows continuously with the window and its inner spacing keeps
       the same proportions at every width instead of snapping. Every multiplier
       reproduces the original 45px-icon bar exactly at the clamp's floor. */
    .r-nav-inner, .r-footer-inner { --nav-icon: clamp(45px, 3.4vw, 56px); }
    .r-nav-inner {
        padding-top: calc(var(--nav-icon) * 0.27);
        padding-bottom: calc(var(--nav-icon) * 0.27);
    }
    .r-lockup { gap: calc(var(--nav-icon) * 0.22); }
    .r-lockup-icon { width: var(--nav-icon); height: var(--nav-icon); }
    .r-lockup-word { font-size: calc(var(--nav-icon) * 0.55); }
    .r-nav-links { gap: calc(var(--nav-icon) * 0.62); }
    /* :not(.r-btn) or this outranks .r-nav-cta below and resizes the button. */
    .r-nav-links a:not(.r-btn) { font-size: calc(var(--nav-icon) * 0.32); }
    /* Written as .r-nav-links a.r-nav-cta so it outranks the base
       `.r-nav-links a` font-size, which is one specificity step above a lone
       class and was pinning the button at 15px. */
    .r-nav-links a.r-nav-cta {
        font-size: max(15px, calc(var(--nav-icon) * 0.31));
        padding: calc(var(--nav-icon) * 0.175) calc(var(--nav-icon) * 0.4);
    }
    /* The shell widens continuously too, so nothing about the header's
       geometry snaps at 1500 or 1900. */
    .r-shell { max-width: clamp(1320px, 82vw, 1560px); }
}
/* ── Big screens ──
   Every size in this sheet is px, and the clamps all top out around a 1000px
   viewport — so past ~1440 the page stops growing and reads shrunken with a
   sea of margin either side. These two tiers put the scale back. The device
   rails only raise their *caps*: their min(…vh) terms still gate on height, so
   a short window is untouched. */
@media (min-width: 1500px) {
    /* Width and the header live in the fluid 1041 block above — nothing that
       affects the nav's geometry belongs in a stepped tier. */
    .r-section { padding: 118px 0; }
    .r-h2 { font-size: 64px; }

    /* :not() is load-bearing — the nav CTA is .r-btn.r-btn-sm, and this block
       sits after .r-btn-sm in the sheet, so a bare .r-btn here would win and
       blow the button out past the nav's own height. */
    .r-btn:not(.r-btn-sm) { font-size: 17px; padding: 16px 30px; }

    .r-hero-grid {
        --rail: clamp(300px, min(42vw, 60vh), 620px);
        --gap-copy: clamp(20px, 2.5vw, 46px);
    }
    .r-phone.r-phone-hero { width: calc(clamp(240px, min(calc(var(--rail) * 0.7), 42vh), 470px) * 0.86); }
    .r-hero-icon { width: 140px; }
    .r-hero-word { font-size: 60px; }
    .r-rotator { font-size: 33px; }
    .r-hero-h1 { font-size: 21px; }
    .r-hero-sub { font-size: 20px; }

    .r-notify input[type="email"] { font-size: 17px; padding: 16px 20px; }
    .r-signup .r-notify { max-width: 700px; }
    .r-store { min-width: 200px; padding: 11px 22px 11px 18px; }
    .r-store-glyph { width: 28px; height: 28px; }
    .r-store-text small { font-size: 10.5px; }
    .r-store-text strong { font-size: 21px; }

    .r-phone.r-phone-tour {
        --tour-rail: clamp(300px, min(42vw, 60vh), 620px); /* mirrors the hero rail above */
        width: clamp(220px, min(calc(var(--tour-rail) * 0.62), 38vh), 420px);
    }
    .r-tour-labels { max-width: 46ch; }
    .r-tour-label { font-size: 20px; }
    .r-tour-dot { width: 9px; height: 9px; }

    .r-science-intro { font-size: 20px; }
    .r-sci-grid { max-width: 1040px; }
    .r-sci-col-head { font-size: 25px; }
    .r-sci-claim { font-size: 21px; }
    .r-refs { max-width: 1040px; }
    .r-refs-head { font-size: 13px; }
    .r-refs-list { font-size: 16px; }
    .r-science-note { font-size: 15px; }

    .r-cta-collage { width: 400px; }
    /* :not() again — .r-cta-lockup is a <p>, so a bare `.r-cta p` outranks it
       and shrank the three-line lockup to body size. */
    .r-cta p:not(.r-cta-lockup) { font-size: 19px; }

    .r-footer-links a { font-size: 15px; }
    .r-footer-note, .r-footer-copy { font-size: 14px; }

    /* Measure stays tight — legal copy is read, not scanned — but the type grows
       with everything else. */
    .r-legal { max-width: 860px; }
    .r-legal h1 { font-size: 42px; }
    .r-legal h2 { font-size: 27px; }
    .r-legal h3 { font-size: 20px; }
    .r-legal p, .r-legal li { font-size: 18px; }
    .r-legal .r-legal-meta { font-size: 15px; }
    .r-legal table { font-size: 15px; }
}
@media (min-width: 1900px) {
    .r-section { padding: 136px 0; }
    .r-h2 { font-size: 70px; }

    .r-hero-grid { --rail: clamp(300px, min(42vw, 62vh), 680px); }
    .r-phone.r-phone-hero { width: calc(clamp(240px, min(calc(var(--rail) * 0.7), 44vh), 510px) * 0.86); }
    .r-hero-icon { width: 152px; }
    .r-hero-word { font-size: 66px; }
    .r-rotator { font-size: 36px; }
    .r-hero-h1 { font-size: 23px; }
    .r-hero-sub { font-size: 21px; }

    .r-phone.r-phone-tour {
        --tour-rail: clamp(300px, min(42vw, 62vh), 680px);
        width: clamp(220px, min(calc(var(--tour-rail) * 0.62), 40vh), 460px);
    }
    .r-tour-label { font-size: 21px; }

    .r-sci-claim { font-size: 22px; }
    .r-legal p, .r-legal li { font-size: 19px; }
}
@media (max-width: 1040px) {
    /* copy on top, map and phone side by side beneath it — still a matched pair */
    .r-hero-grid {
        grid-template-columns: max-content max-content;
        justify-content: center;
        align-items: start;
        gap: clamp(28px, 8vw, 72px);
        --rail: clamp(300px, 40vw, 400px);
        /* map and phone sit side by side here — matched pair, no bleed */
        --map-rail: var(--rail);
        --map-overlap: 0px;
    }
    .r-hero-copy { grid-column: 1 / -1; grid-row: 1; margin-bottom: 12px; }
    .r-hero { padding-top: 110px; }
    .r-scroll { display: none; } /* copy alone no longer fills the viewport */
}
@media (max-width: 900px) {
    .r-grid-4 { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 720px) {
    /* Mobile hero: headline first, phone peeking above the fold. The nav carries
       the logo lockup, so the hero drops its own rather than showing it twice. */
    .r-nav-links a:not(.r-btn) { display: none; }
    .r-nav-links { gap: 0; }
    .r-nav-cta-wide { display: none; }
    .r-nav-cta-narrow { display: inline; }
    .r-lockup-icon { width: 46px; height: 46px; }
    .r-lockup-word { font-size: 24px; letter-spacing: 0.3em; }

    .r-hero { display: block; min-height: 0; padding: 0 0 32px; }
    .r-hero-grid {
        display: flex;
        flex-direction: column;
        align-items: center;
        /* One gap, spent twice: nav → headline, and paragraph → phone. Equal by
           construction, so the copy reads as suspended between the two. */
        --hero-gap: clamp(44px, calc(8 * var(--vh1, 1svh)), 76px);
        --nav-h: 71px; /* 46px lockup + 12px padding top/bottom + 1px border */
    }
    .r-hero-map { display: none; } /* the body map is decorative — the phone is the payload */
    .r-hero-brand { display: none; }
    .r-hero-copy {
        justify-content: flex-start;
        min-height: 0;
        padding: calc(var(--nav-h) + var(--hero-gap)) 6px 0;
        margin-bottom: 0;
    }
    /* Promoted from caption to headline — it is the only thing on the screen. */
    .r-hero-h1 {
        font-size: clamp(34px, 9.6vw, 46px);
        font-weight: 600;
        letter-spacing: -0.01em;
        line-height: 1.14;
        margin-bottom: 16px;
    }
    /* The emphasis is the air, not a colour — italic plus tracking. The negative
       margin gives back the trailing letter-space so the period stays tight. */
    .r-hero-h1 em {
        letter-spacing: 0.06em;
        margin-right: -0.06em;
    }
    .r-hero-sub { font-size: 18px; max-width: 34ch; margin-bottom: 0; }

    /* The gap is matched by ink, not by boxes: the headline's cap sits ~13px below
       its line box and the paragraph's last line ends ~5px above its own, so the
       phone's box has to come up by the difference to look equally spaced. */
    .r-hero-device { height: auto; margin-top: calc(var(--hero-gap) - 25px); }
    /* Height-capped as well as width-capped: the frame is 2.18× as tall as it is
       wide and still has to fit the screen whole once scrolled to. Only the last
       eighth fades, so the phone reads as a phone, not as a cropped strip. */
    .r-phone.r-phone-hero {
        width: min(88vw, calc(84 * var(--vh1, 1svh) / 2.18), 420px);
        -webkit-mask-image: linear-gradient(to bottom, #000 87%, transparent 100%);
        mask-image: linear-gradient(to bottom, #000 87%, transparent 100%);
    }

    /* Field and button stack full-width — side by side they wrapped into a
       ragged two-row block below ~380px. */
    .r-notify { flex-direction: column; gap: 10px; }
    .r-notify input[type="email"] { width: 100%; }
    .r-notify .r-btn { width: 100%; padding: 15px 20px; }
    .r-store { flex: 1 1 46%; min-width: 0; justify-content: center; padding: 9px 12px; }
    .r-store-text strong { font-size: 17px; }
}
@media (max-width: 640px) {
    .r-section { padding: 64px 0; }
}
@media (max-width: 720px) {
    /* Never past the screen edge: the stage is the phone's width, so half the
       leftover viewport is the biggest safe overhang. */
    .r-tour-prev { left: max(-52px, calc((100% - 100vw) / 2 + 6px)); }
    .r-tour-next { right: max(-52px, calc((100% - 100vw) / 2 + 6px)); }
}

/* Tablet / iPad held upright. Map and phone side by side leaves both too small
   to read, so the map goes — same call as mobile — and the phone runs full
   width under the copy. The hero grows to the phone's real height instead of
   clipping it, so scrolling reveals the rest of the frame rather than a cut
   edge sitting on the next section's background. Landscape keeps the map. */
@media (min-width: 721px) and (max-width: 1040px) and (orientation: portrait) {
    .r-hero {
        display: block;
        min-height: 0;
        padding: 110px 0 44px;
    }
    .r-hero-grid {
        display: flex;
        flex-direction: column;
        align-items: center;
    }
    .r-hero-map { display: none; }
    .r-hero-copy {
        padding-left: 0;
        padding-right: 0;
        margin-bottom: clamp(30px, 5vw, 52px);
    }
    /* Auto, not --rail: the row has to be as tall as the phone or the hero's
       overflow clips the frame mid-body. */
    .r-hero-device { height: auto; }
    .r-phone.r-phone-hero {
        width: min(64vw, 460px);
        -webkit-mask-image: linear-gradient(to bottom, #000 90%, transparent 100%);
        mask-image: linear-gradient(to bottom, #000 90%, transparent 100%);
    }
}
/* Phone turned sideways: ~390px of height for everything. Nothing that stacks
   fits, so the hero goes back to two columns — copy beside the phone — with the
   phone sized off height and the map dropped. Placed after the ≤720 block on
   purpose: small phones in landscape match both, and this one has to win. */
@media (max-width: 1040px) and (orientation: landscape) and (max-height: 560px) {
    .r-hero {
        display: flex;
        align-items: center;
        min-height: 0;
        padding: 92px 0 24px;
    }
    .r-hero-grid {
        display: grid;
        grid-template-columns: minmax(0, 1fr) max-content;
        justify-content: center;
        align-items: center;
        gap: clamp(24px, 4vw, 52px);
    }
    .r-hero-map { display: none; }
    .r-hero-brand { display: none; } /* the nav already carries the lockup */
    .r-hero-copy {
        grid-column: auto;
        grid-row: auto;
        padding: 0;
        margin-bottom: 0;
    }
    .r-hero-h1 {
        font-size: clamp(22px, 3.4vw, 30px);
        font-weight: 600;
        line-height: 1.2;
        margin-bottom: 12px;
    }
    .r-hero-sub { font-size: 15px; max-width: 42ch; margin-bottom: 0; }
    .r-hero-device { height: auto; }
    .r-phone.r-phone-hero {
        width: min(38vw, calc(76 * var(--vh1, 1svh) / 2.18), 300px);
        -webkit-mask-image: linear-gradient(to bottom, #000 90%, transparent 100%);
        mask-image: linear-gradient(to bottom, #000 90%, transparent 100%);
    }
    .r-scroll { display: none; }
}

@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    .r-rise { opacity: 1; transform: none; transition: none; }
    .r-rotator span { transition: none; }
    .r-phone-dark { transition: none; }
    .r-notify input[type="email"].r-attn { animation: none; } /* keep the static outline + wash */
    /* No sweep: the word just sits in brand cyan. */
    .r-shine {
        animation: none;
        background-image: none;
        color: var(--accent);
        -webkit-text-fill-color: var(--accent);
    }
    .r-tour-shot, .r-tour-label, .r-tour-dot { transition: none; }
    /* The line still marks the change, it just doesn't grow into place. */
    .r-tour-rule.is-swap { animation: none; }
}
