/* ============================================================
   OFFlore — design system
   Tokens lifted verbatim from OFFloreKit/Design/OFFloreTheme.swift
   so the site and the app speak the same language.

   The one rule that governs everything: --sun marks progress,
   confidence, selection and saved state. Nothing else. The moment
   orange decorates, it stops meaning anything — so CTAs are charcoal.

   Mobile first. Desktop is the enhancement, not the baseline.
   ============================================================ */

/* ---------- Inter (self-hosted: no third-party request, keeps the
   privacy policy honest) ---------- */
@font-face {
  font-family: 'InterVar';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('../assets/fonts/InterVariable.woff2') format('woff2');
}

:root {
  /* Brand */
  --charcoal: #0A0C0F;
  --glacier: #F3F5F7;
  --sun: #F26B1D;
  --sun-soft: #FBB040;

  /* Surface */
  --surface-base: #E7EAEE;
  --raised: #FFFFFF;
  --elevated: #EDF0F3;
  --subtle: rgba(10, 12, 15, .05);

  /* Glass */
  --glass: rgba(255, 255, 255, .34);
  --glass-strong: rgba(255, 255, 255, .52);
  --glass-edge: rgba(255, 255, 255, .85);

  /* Dark glass — panes that sit on charcoal instead of glacier.
     The alphas are tuned so white body text clears WCAG AA on top. */
  --glass-dark: rgba(255, 255, 255, .07);
  --glass-dark-strong: rgba(255, 255, 255, .12);
  --glass-dark-edge: rgba(255, 255, 255, .16);

  /* Stroke */
  --hairline: rgba(10, 12, 15, .08);
  --stroke: rgba(10, 12, 15, .14);
  --stroke-strong: rgba(10, 12, 15, .26);

  /* Ink */
  --ink: #0A0C0F;
  --ink-2: #3F4854;
  --ink-3: #6B7481;
  --ink-4: #9AA2AD;
  --ink-inverse: #FFFFFF;

  /* Semantic */
  --success: #34C77B;
  --warning: #F5A524;
  --danger: #FF5A5F;
  --route: #3B82F6;

  /* Space */
  --xxs: 4px;  --xs: 8px;   --sm: 12px;  --md: 16px;
  --lg: 20px;  --xl: 24px;  --xxl: 32px; --xxxl: 44px;
  --gutter: 20px;

  /* Radius */
  --r-xs: 8px;  --r-sm: 12px; --r-md: 18px;
  --r-lg: 24px; --r-xl: 28px; --r-sheet: 32px; --r-pill: 999px;

  /* Shadow */
  --sh-card: 0 6px 14px rgba(10, 12, 15, .07);
  --sh-floating: 0 10px 22px rgba(10, 12, 15, .11);
  --sh-marker: 0 2px 6px rgba(10, 12, 15, .16);
  --sh-phone: 0 24px 60px rgba(10, 12, 15, .18), 0 4px 14px rgba(10, 12, 15, .10);

  /* Motion — mirrors Theme.Motion springs */
  --ease-out: cubic-bezier(.22, .61, .36, 1);
  --ease-spring: cubic-bezier(.34, 1.36, .64, 1);

  --maxw: 1240px;
}

/* ---------- reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body, h1, h2, h3, h4, p, figure, ul, ol { margin: 0; }
ul, ol { padding: 0; list-style: none; }
img, svg, canvas, video { display: block; max-width: 100%; }
button, input, select, textarea { font: inherit; color: inherit; }
a { color: inherit; text-decoration: none; }

body {
  font-family: 'InterVar', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
  font-size: 16px;
  line-height: 1.55;
  color: var(--ink);
  background: var(--glacier);
  overflow-x: clip;             /* never let a bleeding phone scroll the page sideways */
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  font-feature-settings: 'cv05' 1, 'ss03' 1;   /* single-storey g, rounded quotes */
}

:focus-visible { outline: 2px solid var(--charcoal); outline-offset: 3px; border-radius: 4px; }

/* ============================================================
   Ambient background — the brand signature.
   A blurred, saturated photograph under an hour-of-day gradient.
   The four gradients are the ones defined in OFFloreTheme (321-327);
   the hero uses the evening pair.
   ============================================================ */
.ambient {
  position: fixed;
  inset: 0;
  z-index: -2;
  overflow: hidden;
  background: var(--glacier);
}
.ambient__photo {
  position: absolute;
  inset: -6%;                    /* bleed so the blur has no soft edge */
  background-image: image-set(url('../assets/img/hero.webp') 1x);
  /* The plate is square with its ridgelines in the lower half. Anchoring to
     the bottom keeps the mountains on screen; anchoring to the centre showed
     nothing but sky, which is to say nothing at all. */
  background-size: cover;
  background-position: center bottom;
  /* Light blur only: the plate is already atmospheric, and over-blurring
     throws away the ridgelines that ground the whole composition. */
  filter: blur(14px) saturate(1.16);
  opacity: .92;
  transform: scale(1.04);
}
@media (max-width: 699px) {
  .ambient__photo {
    background-image: image-set(url('../assets/img/hero_sm.webp') 1x);
    filter: blur(10px) saturate(1.16);
    /* Portrait viewport against a square plate: cover crops the sides hard,
       so zoom out and sit the range along the lower third instead. */
    background-size: 190% auto;
    background-position: 52% 78%;
  }
}
/* A veil, not a lid. The first version ended on opaque glacier at the bottom
   and painted over the ridgelines — the one part of the plate worth seeing.
   It never reaches full opacity now; legibility comes from the frosted panes
   the text actually sits on, which is what they are for. */
.ambient__wash {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(90% 50% at 14% 0%, rgba(255, 233, 220, .30) 0%, transparent 60%),
    linear-gradient(180deg,
      rgba(243, 245, 247, .30) 0%,
      rgba(243, 245, 247, .10) 38%,
      rgba(243, 245, 247, .26) 74%,
      rgba(243, 245, 247, .52) 100%);
}
/* The soft planetary curve in the upper right of the reference. */
.ambient__orb {
  position: absolute;
  top: -46vw; right: -34vw;
  width: 108vw; height: 108vw;
  border-radius: 50%;
  background: radial-gradient(circle at 34% 66%,
              rgba(255, 255, 255, .58) 0%,
              rgba(255, 255, 255, .22) 44%,
              rgba(255, 255, 255, 0) 68%);
  filter: blur(2px);
}

/* ============================================================
   Glass — one surface, used everywhere
   ============================================================ */
.glass {
  background: var(--glass);
  -webkit-backdrop-filter: blur(22px) saturate(1.5);
  backdrop-filter: blur(22px) saturate(1.5);
  border: 1px solid var(--glass-edge);
  box-shadow: var(--sh-card);
}
.glass--strong { background: var(--glass-strong); }
/* Top highlight: reads as a lit edge, the way the app's panes do.
   It must sit UNDER the content: painted above it, the veil washed every
   heading inside a lit panel to a sickly grey. */
.glass--lit { position: relative; }
.glass--lit::before {
  content: '';
  position: absolute; inset: 0;
  z-index: 0;
  border-radius: inherit;
  background: linear-gradient(180deg, rgba(255,255,255,.62), rgba(255,255,255,0) 46%);
  pointer-events: none;
}
.glass--lit > * { position: relative; z-index: 1; }

/* ============================================================
   Layout
   ============================================================ */
.wrap {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
section { position: relative; }

/* Round 4 verdict: a full-width fade band reads as smear, not as cover.
   The pill itself carries the separation now — near-opaque frosted fill
   with a sharp hairline — so the scrim retires. */
.topscrim { display: none; }

/* ---------- nav ---------- */
.nav {
  position: fixed;
  top: var(--sm);
  left: var(--sm);
  right: var(--sm);
  z-index: 60;
  display: flex;
  align-items: center;
  gap: var(--sm);
  padding: var(--xs) var(--xs) var(--xs) var(--md);
  border-radius: var(--r-pill);
  transition: box-shadow .3s var(--ease-out), background .3s var(--ease-out);
}
/* Sharp-edged frosted pill: content disappears under a defined boundary
   instead of dissolving into a milky veil. */
.nav {
  background: rgba(255, 255, 255, .86);
  border: 1px solid rgba(10, 12, 15, .07);
}
.nav.is-scrolled { background: rgba(255, 255, 255, .93); box-shadow: var(--sh-floating); }
/* Wordmark: the app-icon tile takes the place of the O — [⏻]FFlore.
   The tile has to KERN INTO the word (cap-height, negative gap, same
   baseline) or fresh eyes read the brand as "FFlore". */
.nav__brand { display: flex; align-items: center; gap: 0; margin-right: auto; }
.nav__mark { width: 26px; height: 26px; flex: none; }
.nav__logo {
  width: 24px; height: 24px; flex: none;
  margin-right: 1px;
  border-radius: 27%;
  box-shadow: 0 1px 3px rgba(10, 12, 15, .22), 0 0 0 .5px rgba(10, 12, 15, .06);
}
.nav__word { letter-spacing: -.012em; }
.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}
.nav__word { font-size: 19px; font-weight: 700; letter-spacing: -.022em; }
.nav__links { display: none; }
.nav__burger {
  display: grid; place-items: center;
  width: 40px; height: 40px; flex: none;
  border: 0; background: transparent; border-radius: var(--r-pill);
  cursor: pointer;
}

/* ---------- buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 15px var(--xl);
  border-radius: var(--r-pill);
  border: 1px solid transparent;
  font-size: 16px;
  font-weight: 600;
  letter-spacing: -.012em;
  cursor: pointer;
  transition: transform .22s var(--ease-out), box-shadow .22s var(--ease-out), background .22s var(--ease-out);
}
.btn svg { flex: none; }
.btn--primary {
  background: var(--charcoal);
  color: var(--ink-inverse);
  box-shadow: var(--sh-floating);
}
.btn--primary:hover { transform: translateY(-2px); box-shadow: 0 14px 30px rgba(10,12,15,.22); }
.btn--ghost {
  background: var(--glass-strong);
  -webkit-backdrop-filter: blur(18px) saturate(1.5);
  backdrop-filter: blur(18px) saturate(1.5);
  border-color: var(--glass-edge);
  color: var(--ink);
  box-shadow: var(--sh-card);
}
.btn--ghost:hover { transform: translateY(-2px); background: rgba(255,255,255,.68); }
.btn--sm { padding: 10px var(--lg); font-size: 15px; }

/* ---------- type ---------- */
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 9px var(--md) 9px 13px;
  border-radius: var(--r-pill);
  font-size: 14px;
  font-weight: 500;
  color: var(--ink-2);
}
.eyebrow::before {
  content: '';
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--sun);          /* orange: this is a state marker, allowed */
  flex: none;
}

h1, .h1 {
  font-size: clamp(40px, 11.4vw, 74px);
  line-height: 1.03;
  font-weight: 700;
  letter-spacing: -.038em;
}
h2, .h2 {
  font-size: clamp(28px, 6.6vw, 46px);
  line-height: 1.1;
  font-weight: 700;
  letter-spacing: -.03em;
}
h3, .h3 {
  font-size: clamp(19px, 4.6vw, 23px);
  line-height: 1.22;
  font-weight: 600;
  letter-spacing: -.02em;
}
.muted { color: var(--ink-3); }
.lede { font-size: clamp(16px, 4.1vw, 18px); line-height: 1.55; color: var(--ink-2); }
.small { font-size: 14px; line-height: 1.5; color: var(--ink-3); }
.micro { font-size: 12px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase; color: var(--ink-3); }

/* ============================================================
   Hero
   ============================================================ */
.hero {
  position: relative;
  padding-top: 104px;
  padding-bottom: var(--xxl);
  min-height: 100svh;
  display: flex;
  flex-direction: column;
}
.hero__inner { position: relative; z-index: 2; }
.hero h1 { margin-block: var(--md) 0; }
/* Each sentence owns its lines: the black→grey hand-off happens at a line
   start, never mid-line, and balance keeps the rag from staircasing. */
.hero h1 > span { display: block; text-wrap: balance; }
.hero h1 .is-dim { color: var(--ink-3); }
.hero__lede { margin-top: var(--lg); max-width: 30ch; }
.hero__cta {
  margin-top: var(--xl);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--sm);
}
.hero__cta .btn { width: min(100%, 260px); }
.hero__proof { margin-top: var(--md); }

/* Mobile: the device is its own block below the copy. Text never crosses
   the photo — and nothing hangs past the viewport edge: an off-screen
   absolute box widens the mobile layout viewport, which shrank the whole
   page and clipped the nav CTA. */
.hero__device {
  position: relative;
  z-index: 1;
  margin: var(--xxl) auto 0;
  width: min(70vw, 300px);
  pointer-events: none;
}
/* A soft pool of light behind the phone, so it sits on a stage
   instead of floating over the blur. */
.hero__device::before {
  content: '';
  position: absolute;
  inset: -14% -22%;
  z-index: -1;
  border-radius: 50%;
  background: radial-gradient(50% 50% at 50% 42%,
              rgba(255, 255, 255, .60) 0%,
              rgba(255, 255, 255, 0) 70%);
  filter: blur(8px);
}

/* Overlapping feature cards */
.hero__cards {
  position: relative;
  z-index: 2;
  margin-top: var(--xxxl);
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0;
}
.fcard {
  border-radius: var(--r-lg);
  padding: var(--md);
  max-width: 210px;
}
.fcard__icon { color: var(--ink); margin-bottom: 10px; }
.fcard__title { font-size: 15px; font-weight: 600; line-height: 1.24; letter-spacing: -.016em; }
.fcard__body { margin-top: 6px; font-size: 13px; line-height: 1.42; color: var(--ink-3); }
/* Stagger: each card overlaps its neighbour, like a loose stack of panes. */
.fcard:nth-child(1) { grid-area: 1 / 1 / 2 / 2; transform: rotate(-1.5deg); z-index: 3; }
.fcard:nth-child(2) { grid-area: 1 / 2 / 2 / 3; transform: translate(-14px, 26px) rotate(1deg); z-index: 2; }
.fcard:nth-child(3) { grid-area: 2 / 1 / 3 / 3; justify-self: center; transform: translateY(-4px) rotate(-.5deg); z-index: 1; }

/* ---------- platform bar ---------- */
.platforms {
  margin-top: var(--xxxl);
  padding: var(--lg);
  border-radius: var(--r-xl);
}
.platforms__label { text-align: center; margin-bottom: var(--md); }
.platforms__row {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: var(--lg) var(--xl);
  color: var(--ink-2);
}
.platforms__row svg { opacity: .78; }

/* ============================================================
   How it works — the pinned, scroll-scrubbed shot
   ============================================================ */
.shot { position: relative; }
/* Three rows on one 100svh canvas: head, phone, captions. Everything lives
   in normal flow — the first build absolutely-positioned head and captions
   over a centered phone, and on any viewport under ~1000px they met in the
   middle. Rows cannot collide. */
.shot__stage {
  position: relative;
  height: 100svh;
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto;
  justify-items: center;
  row-gap: var(--lg);
  padding: max(88px, 10svh) var(--gutter) max(24px, 4svh);
  overflow: hidden;
}
.shot__head {
  z-index: 4;
  text-align: center;
}
.shot__head h2 { margin-bottom: var(--xs); text-wrap: balance; }
.shot__head .small { max-width: 60ch; margin-inline: auto; }

/* Device frame drawn in CSS: the frames carry screen content only, so the
   bezel stays crisp at every DPR and the asset stays small. */
.device {
  position: relative;
  width: min(72vw, 300px);
  aspect-ratio: 402 / 874;
  border-radius: 13.5%/6.2%;
  padding: 3.1%;
  background: linear-gradient(158deg, #E8EBEF 0%, #BFC5CD 26%, #F5F7F9 52%, #AEB5BE 76%, #DDE2E7 100%);
  box-shadow: var(--sh-phone);
}
.device::after {                 /* rim highlight */
  content: '';
  position: absolute; inset: 0;
  border-radius: inherit;
  border: 1px solid rgba(255,255,255,.6);
  pointer-events: none;
}
.device__screen {
  position: relative;
  width: 100%; height: 100%;
  border-radius: 11%/5.4%;
  overflow: hidden;
  background: var(--glacier);
}
.device__screen > canvas,
.device__screen > img { width: 100%; height: 100%; object-fit: cover; }
.device__notch {
  position: absolute;
  top: 1.4%; left: 50%;
  transform: translateX(-50%);
  width: 31%; height: 3.6%;
  border-radius: var(--r-pill);
  background: #0A0C0F;
  z-index: 3;
}

.shot__device {
  position: relative;
  z-index: 2;
  display: grid;
  place-items: center;
  min-height: 0;
}
/* Sized by the row the head and captions leave over: height drives width
   through the aspect ratio, so the phone shrinks before it ever touches
   its neighbours. */
.shot__device .device {
  width: auto;
  height: 100%;
  max-height: 640px;
  max-width: min(72vw, 300px);
  /* Without this the poster's intrinsic height becomes the device's
     content minimum and quietly pushes it into the captions row. */
  min-height: 0;
}

/* Phase captions, timed to the real pipeline phases. Their row reserves
   space, so the crossfading pills never sit on the phone. */
.caps {
  z-index: 5;
  display: grid;
  align-items: end;
  min-height: 68px;
  pointer-events: none;
}
.cap {
  grid-area: 1 / 1;
  justify-self: center;
  display: flex;
  align-items: center;
  gap: var(--sm);
  padding: 12px var(--lg) 12px 14px;
  border-radius: var(--r-pill);
  opacity: 0;
  max-width: 100%;
}
.cap__n {
  display: grid; place-items: center;
  width: 26px; height: 26px; flex: none;
  border-radius: 50%;
  background: var(--sun);          /* progress marker — allowed */
  color: #fff;
  font-size: 13px; font-weight: 700;
}
.cap__t { font-size: 15px; font-weight: 600; letter-spacing: -.014em; }
.cap__s { font-size: 13px; color: var(--ink-3); }

/* Scroll hint */
.hint {
  position: absolute;
  bottom: var(--lg); left: 50%;
  transform: translateX(-50%);
  z-index: 5;
  display: grid; place-items: center;
  width: 42px; height: 42px;
  border-radius: 50%;
  color: var(--ink-2);
}

/* ============================================================
   Steps — the written quick reference under the pinned take.
   Three compact columns from 700px up (stacked on mobile), each a
   single glass pane: number, title, two lines of body, evidence chip.
   The old version wrapped full-width rows in a second mega-panel and
   re-told the scrub story with 70% of every row left empty.
   ============================================================ */
.panel {
  border-radius: var(--r-sheet);
  padding: var(--xl) var(--lg) var(--xxl);
}
.steps { margin-top: var(--xl); display: grid; gap: var(--sm); }
.step {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  border-radius: var(--r-xl);
  padding: var(--lg);
}
.step__n {
  display: grid; place-items: center;
  width: 34px; height: 34px;
  border-radius: 50%;
  border: 1.5px solid var(--sun);   /* step marker — allowed */
  color: var(--sun);
  font-size: 15px; font-weight: 600;
  background: rgba(255,255,255,.5);
  margin-bottom: var(--md);
}
.step__title { font-size: 16px; font-weight: 600; letter-spacing: -.016em; }
.step__body { margin-top: 5px; font-size: 14px; line-height: 1.45; color: var(--ink-3); }
/* Pinned to the pane's bottom edge, so the three evidence rows land on one
   shared baseline no matter how the bodies wrap. */
.step__extra {
  margin-top: auto;
  padding-top: var(--md);
  align-self: stretch;
  display: flex; align-items: center; gap: var(--xs); flex-wrap: wrap;
}
/* Icon-only platform chips: slimmer padding so all four stay on one row
   even in the narrowest three-up column. */
.step__extra .chip:not(.chip--sun) { padding-inline: 7px; }
@media (min-width: 700px) {
  .steps { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--md); }
}

.chip {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 7px 12px;
  border-radius: var(--r-pill);
  background: rgba(255,255,255,.55);
  border: 1px solid var(--glass-edge);
  font-size: 13px; font-weight: 500;
}
.chip--sun { color: var(--sun); }

/* Confidence bar — orange because it encodes certainty */
.bar { height: 5px; border-radius: var(--r-pill); background: var(--subtle); overflow: hidden; flex: 1; min-width: 90px; }
.bar > i { display: block; height: 100%; border-radius: inherit; background: linear-gradient(90deg, var(--sun), var(--sun-soft)); }

/* ============================================================
   Generic content sections
   ============================================================ */
/* One rhythm for every band — two stacked paddings must never add up to a
   dead viewport between sections. */
.band { padding-block: clamp(48px, 9vw, 96px); }
.band__head { max-width: 34ch; }
.band__head h2 + p { margin-top: var(--sm); }

.grid { display: grid; gap: var(--sm); margin-top: var(--xl); }
.tile {
  display: flex;
  flex-direction: column;
  overflow: hidden;               /* the topo vignette bleeds to the edges */
  border-radius: var(--r-xl);
  padding: var(--lg);
  transition: transform .28s var(--ease-out), box-shadow .28s var(--ease-out);
}
.tile:hover { transform: translateY(-4px); box-shadow: var(--sh-floating); }
.tile__icon {
  display: grid; place-items: center;
  width: 46px; height: 46px;
  border-radius: var(--r-sm);
  background: var(--charcoal);
  color: var(--ink-inverse);
  box-shadow: var(--sh-marker);
  margin-bottom: var(--md);
}
.tile h3 + p { margin-top: var(--xs); }

/* ---------- tile vignettes: text on top, evidence at the bottom.
   Every card ends in a bottom-anchored slice of mini app UI, so the four
   tiles fill to equal height instead of trailing off into blank glass. */
.tile__visual {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  margin-top: var(--lg);
  /* min-height only from 700px up: single-column mobile cards are as tall
     as their content, and a forced height just punches a hole into them. */
}
.tile__visual--flush {                 /* the map slice runs edge to edge */
  margin: var(--lg) calc(-1 * var(--lg)) calc(-1 * var(--lg));
  min-height: 168px;
}
.mini { display: grid; gap: 8px; align-content: end; }

/* Signal chips funnelling into one confirmed place */
.mini__chips { display: flex; flex-wrap: wrap; gap: 6px; }
.mchip {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 5px 9px;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, .60);
  border: 1px solid var(--glass-edge);
  font-size: 12px; font-weight: 500; color: var(--ink-2);
}
.mchip svg { width: 13px; height: 13px; }
.mini__link {                          /* the dashed drop from chips to result */
  width: 2px; height: 14px;
  margin-left: 22px;
  border-radius: 1px;
  background: repeating-linear-gradient(180deg, var(--stroke-strong) 0 3px, transparent 3px 6px);
}
.mrow {
  display: flex; align-items: center; gap: 8px;
  padding: 9px 11px;
  border-radius: var(--r-sm);
  background: rgba(255, 255, 255, .62);
  border: 1px solid var(--glass-edge);
  font-size: 13px;
}
.mrow svg { flex: none; width: 15px; height: 15px; }
.mrow--result { font-weight: 600; background: rgba(255, 255, 255, .74); box-shadow: var(--sh-card); }
.mrow--result > svg { color: var(--sun); }         /* identified place — selection */
.mrow__check { margin-left: auto; display: grid; color: var(--success); }
.mrow--conf { justify-content: space-between; gap: var(--xs); font-weight: 600; }
.mrow__place { letter-spacing: -.012em; }
.badge--sun {
  flex: none;
  padding: 4px 9px;
  border-radius: var(--r-pill);
  background: rgba(242, 107, 29, .13);
  color: var(--sun);                                 /* confidence — allowed */
  font-size: 11.5px; font-weight: 600; letter-spacing: 0;
}
.mrow--alt { color: var(--ink-3); font-size: 12.5px; background: rgba(255, 255, 255, .38); }
.mrow--alt > svg { color: var(--ink-4); }            /* not chosen: stays grey */
.mini .bar { min-width: 0; }

/* Saved bucketlist rows */
.srow {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px;
  border-radius: var(--r-sm);
  background: rgba(255, 255, 255, .62);
  border: 1px solid var(--glass-edge);
}
.srow__thumb { width: 34px; height: 34px; border-radius: 9px; flex: none; }
.srow__thumb--a { background: linear-gradient(140deg, #7FD4C1 0%, #2E8B72 55%, #1F5D4E 100%); }
.srow__thumb--b { background: linear-gradient(150deg, #D8CDBB 0%, #98A08B 50%, #5A6B58 100%); }
.srow__text { display: grid; line-height: 1.25; min-width: 0; }
.srow__text strong { font-size: 13px; font-weight: 600; letter-spacing: -.012em; }
.srow__text em { font-style: normal; font-size: 11.5px; color: var(--ink-3); }
.srow__bm { margin-left: auto; display: grid; color: var(--sun); }  /* saved — allowed */

/* Topo slice with dashed route */
.mini--topo {
  position: relative;
  flex: 1;
  min-height: 160px;
  overflow: hidden;
  border-top: 1px solid var(--glass-edge);
  background: linear-gradient(155deg, #EDF3EC 0%, #E2ECE4 45%, #D3E2D8 100%);
}
.topo__art { position: absolute; inset: 0; width: 100%; height: 100%; }
.topo__c { fill: none; stroke: rgba(10, 12, 15, .10); stroke-width: 1.2; }
.topo__route { fill: none; stroke: var(--route); stroke-width: 2.4; stroke-linecap: round; stroke-dasharray: 1 8; }
.topo__stop { fill: #fff; stroke: var(--charcoal); stroke-width: 1.6; }
.topo__end { fill: var(--sun); stroke: #fff; stroke-width: 2; }   /* saved spot */
.topo__end-dot { fill: #fff; }
.topo__eta {
  position: absolute;
  right: var(--md); bottom: var(--md);   /* bottom-right: the route never runs there */
  background: rgba(255, 255, 255, .82);
  box-shadow: var(--sh-card);
}

/* ---------- download ---------- */
.download { text-align: center; }
.download__inner {
  position: relative;
  border-radius: var(--r-sheet);
  padding: var(--xxl) var(--lg);
  overflow: hidden;
}
.download__flag { margin-bottom: var(--md); }
.download .btn { margin-top: var(--xl); position: relative; z-index: 1; }
.badge-store { height: 52px; width: auto; margin-inline: auto; }
/* A corner of the app leans into the card, so the closing moment shows the
   product one last time instead of ending on empty glass. */
.download__peek {
  position: absolute;
  right: -36px;
  bottom: -110px;
  width: 220px;
  transform: rotate(-9deg);
  border-radius: 28px;
  box-shadow: var(--sh-phone);
  opacity: .96;
  pointer-events: none;
}
@media (max-width: 699px) { .download__peek { display: none; } }

/* ---------- footer ---------- */
.foot { padding-block: var(--xxl) var(--xl); border-top: 1px solid var(--hairline); margin-top: var(--xxl); }
.foot__grid { display: grid; gap: var(--xl); }
.foot__brand { display: flex; align-items: center; gap: 1px; }
.foot h4 { font-size: 13px; font-weight: 600; letter-spacing: .03em; text-transform: uppercase; color: var(--ink-3); margin-bottom: var(--sm); }
.foot li + li { margin-top: 9px; }
.foot a { color: var(--ink-2); transition: color .18s var(--ease-out); }
.foot a:hover { color: var(--ink); }
.foot__legal { margin-top: var(--xxl); padding-top: var(--lg); border-top: 1px solid var(--hairline); display: grid; gap: var(--xs); }
.foot__social { display: flex; gap: var(--sm); }
.foot__social a {
  display: grid; place-items: center;
  width: 38px; height: 38px;
  border-radius: 50%;
  background: rgba(255,255,255,.5);
  border: 1px solid var(--glass-edge);
}

/* ============================================================
   Legal pages
   ============================================================ */
.doc { padding-top: 112px; padding-bottom: var(--xxxl); max-width: 74ch; }
.doc h1 { font-size: clamp(30px, 8vw, 46px); }
.doc h2 { font-size: clamp(20px, 5vw, 25px); margin-top: var(--xxl); }
.doc h3 { margin-top: var(--xl); }
.doc p, .doc li { color: var(--ink-2); }
.doc p + p, .doc h2 + p, .doc h3 + p { margin-top: var(--sm); }
.doc ul { margin-top: var(--sm); display: grid; gap: var(--xs); }
.doc li { padding-left: var(--lg); position: relative; }
.doc li::before { content: ''; position: absolute; left: 4px; top: 11px; width: 5px; height: 5px; border-radius: 50%; background: var(--ink-4); }
.doc address { font-style: normal; margin-top: var(--sm); }
.doc__meta { margin-top: var(--xxl); padding-top: var(--md); border-top: 1px solid var(--hairline); }
.doc a[href^="mailto"], .doc a[href^="http"] { color: var(--ink); text-decoration: underline; text-underline-offset: 3px; }

/* ============================================================
   Reveals — opt-in, disabled wholesale under reduced motion
   ============================================================ */
/* Gated on .js exactly like the hero: if the class is dropped before
   ScrollTrigger ever fires, these become visible instead of staying blank. */
.js .reveal { opacity: 0; transform: translateY(18px); }

/* Entrance pre-hide. Gated on .js so a browser without scripting — or one
   where a script dies — always shows the content. main.js drops the class. */
.js .hero .eyebrow,
.js .hero h1 > span,
.js .hero__lede,
.js .hero__cta > *,
.js .hero__proof,
.js .hero__device,
.js .fcard { opacity: 0; }

/* ============================================================
   Skip link
   ============================================================ */
.skip {
  position: absolute;
  left: var(--sm); top: -100px;
  z-index: 100;
  padding: 12px var(--lg);
  border-radius: var(--r-pill);
  background: var(--charcoal);
  color: var(--ink-inverse);
  font-size: 15px; font-weight: 600;
  transition: top .2s var(--ease-out);
}
.skip:focus { top: var(--sm); }

/* ============================================================
   Mobile menu
   ============================================================ */
.mobilemenu {
  position: fixed;
  inset: 0;
  z-index: 55;
  background: rgba(243, 245, 247, .72);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  padding: 84px var(--sm) var(--sm);
}
.mobilemenu[hidden] { display: none; }
.mobilemenu__panel {
  border-radius: var(--r-sheet);
  padding: var(--lg);
  display: grid;
  gap: var(--xs);
}
.mobilemenu__panel > a {
  padding: var(--sm) var(--md);
  border-radius: var(--r-md);
  font-size: 18px; font-weight: 600; letter-spacing: -.018em;
}
.mobilemenu__panel > a:active { background: var(--subtle); }
.mobilemenu__langs {
  margin-top: var(--sm);
  padding-top: var(--md);
  border-top: 1px solid var(--hairline);
  display: flex; gap: var(--xs);
}
.mobilemenu__langs a {
  padding: 8px var(--md);
  border-radius: var(--r-pill);
  font-size: 14px; font-weight: 500;
  color: var(--ink-3);
  border: 1px solid var(--stroke);
}
.mobilemenu__langs a[aria-current] { color: var(--ink); border-color: var(--charcoal); }

/* ============================================================
   Platform bar items
   ============================================================ */
.platforms__item { display: grid; place-items: center; }

/* ============================================================
   Sequence poster — carries the section until frames exist, and
   is the permanent state under reduced motion.
   ============================================================ */
.seq-poster { position: absolute; inset: 0; }
.has-frames .seq-poster { display: none; }
.no-frames .seq { display: none; }
@media (prefers-reduced-motion: reduce) {
  .seq { display: none; }
  .seq-poster { display: block !important; }
}

/* ============================================================
   Explore panel — the one dark moment on the page. Charcoal
   ground, light type, dark glass: a counterpoint to the glacier
   sections around it. Orange still only marks state (pins on the
   weather and nearby cards = marked places).
   ============================================================ */
.explore__panel {
  position: relative;
  overflow: hidden;
  display: grid;
  gap: var(--xl);
  justify-items: center;
  text-align: center;
  background: var(--charcoal);
  border-color: rgba(255, 255, 255, .09);
  box-shadow: 0 24px 56px rgba(10, 12, 15, .30);
  color: var(--ink-inverse);
}
/* Re-tint the lit edge for dark ground, and pour a faint ice-blue
   aurora into the corners so the charcoal doesn't read as a void. */
.explore__panel::before { background: linear-gradient(180deg, rgba(255, 255, 255, .10), rgba(255, 255, 255, 0) 42%); }
.explore__panel::after {
  content: '';
  position: absolute; inset: 0;
  background:
    radial-gradient(56% 48% at 86% 6%, rgba(96, 165, 250, .17) 0%, transparent 70%),
    radial-gradient(50% 44% at 6% 98%, rgba(147, 197, 253, .11) 0%, transparent 70%);
  pointer-events: none;
}
.explore__panel > * { position: relative; z-index: 1; }
.explore__panel h2 { color: var(--ink-inverse); }
.explore__panel .lede { color: rgba(255, 255, 255, .78); margin-top: var(--sm); }
.explore__device { width: min(64vw, 250px); }
.explore__device .device { width: 100%; }

/* The floating stack: weather, route, nearby — staggered like a loose
   hand of cards. */
.explore__stack { display: grid; gap: var(--sm); width: min(100%, 280px); }
.xcard {
  display: flex; align-items: center; gap: var(--sm);
  padding: 14px var(--md);
  border-radius: var(--r-lg);
  background: var(--glass-dark);
  border: 1px solid var(--glass-dark-edge);
  box-shadow: var(--sh-floating);
  -webkit-backdrop-filter: blur(14px) saturate(1.2);
  backdrop-filter: blur(14px) saturate(1.2);
  text-align: left;
}
.explore__stack .xcard:nth-child(1) { transform: rotate(-1.6deg); }
.explore__stack .xcard:nth-child(2) { transform: rotate(1.2deg) translateX(10px); }
.explore__stack .xcard:nth-child(3) { transform: rotate(-.8deg) translateX(-6px); }
.xcard__icon {
  display: grid; place-items: center;
  width: 40px; height: 40px; flex: none;
  border-radius: var(--r-sm);
  background: var(--glass-dark-strong);
  border: 1px solid rgba(255, 255, 255, .10);
  color: #A9D6F2;
}
.xcard__stack { display: grid; line-height: 1.25; min-width: 0; }
.xcard__label { font-size: 11px; font-weight: 600; letter-spacing: .05em; text-transform: uppercase; color: rgba(255, 255, 255, .62); }
.xcard__temp { font-size: 24px; font-weight: 700; letter-spacing: -.02em; }
.xcard__value { font-size: 15px; font-weight: 600; letter-spacing: -.01em; white-space: nowrap; }
.xcard__place { margin-left: auto; display: inline-flex; align-items: center; gap: 5px; font-size: 13px; font-weight: 500; color: rgba(255, 255, 255, .78); }
.xcard__place svg, .xcard__row svg { width: 14px; height: 14px; flex: none; color: var(--sun); }  /* marked place */
.xcard--nearby { display: grid; gap: 9px; }
.xcard__row { display: flex; align-items: center; gap: 7px; font-size: 13.5px; font-weight: 500; }
.xcard__row em { font-style: normal; margin-left: auto; font-size: 12.5px; color: rgba(255, 255, 255, .62); }

/* From 700px: phone left, copy and cards in the right column — the stack
   tucks under the copy and leans onto the phone's edge, reading as data
   pulled straight out of the app. */
@media (min-width: 700px) {
  .explore__panel {
    grid-template-areas: 'device copy' 'device stack';
    grid-template-columns: auto minmax(0, 1fr);
    align-content: center;
    align-items: center;
    text-align: left;
    justify-items: start;
    gap: var(--lg) var(--xl);
    padding: var(--xl);
  }
  .explore__device { grid-area: device; width: 230px; }
  .explore__copy { grid-area: copy; align-self: end; max-width: 44ch; }
  .explore__stack { grid-area: stack; align-self: start; margin-left: -40px; z-index: 2; }
}
/* Desktop: phone | cards | copy. The three elements form one tight cluster
   — the old 'device copy stack' spread stretched the copy column to 1fr and
   left the panel's middle dead. The cards overlap the phone's right edge. */
@media (min-width: 1024px) {
  .explore__panel {
    grid-template-areas: 'device stack copy';
    grid-template-columns: auto auto minmax(0, 1fr);
    align-items: center;
    gap: var(--xl);
    padding: var(--xxl);
  }
  .explore__device { width: 260px; }
  .explore__stack { width: 280px; align-self: center; margin-left: -52px; }
  .explore__copy { align-self: center; max-width: 38ch; justify-self: center; padding-inline: var(--lg); }
}

/* ============================================================
   Tablet
   ============================================================ */
@media (min-width: 700px) {
  :root { --gutter: 32px; }

  .hero { padding-top: 132px; }
  /* From tablet up the phone floats beside the copy again — inside the
     viewport, so the layout viewport never grows. */
  .hero__device {
    position: absolute;
    margin: 0;
    top: 96px;
    right: var(--gutter);
    width: min(38vw, 340px);
    transform: rotate(-6deg);
  }
  .hero__inner {
    max-width: 56%;
    min-height: calc(100svh - 132px - 48px);
    display: flex;
    flex-direction: column;
    justify-content: center;
    /* Never stretch: a stretched eyebrow pill reads as an empty search box. */
    align-items: flex-start;
  }
  .hero__lede { max-width: 38ch; }
  .hero__cta { flex-direction: row; align-items: center; }
  .hero__cta .btn { width: auto; }
  /* One row, one baseline: the grid stretches all three panes to equal
     height and the translateY stagger is gone — the tilt alone carries the
     playfulness. Cards that started 10-14px apart read as misalignment,
     not intent. */
  .hero__cards { max-width: 560px; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sm); align-items: stretch; }
  .fcard { max-width: none; }
  .fcard:nth-child(1) { grid-area: 1 / 1 / 2 / 2; transform: rotate(-1.2deg); }
  .fcard:nth-child(2) { grid-area: 1 / 2 / 2 / 3; transform: rotate(.8deg); }
  .fcard:nth-child(3) { grid-area: 1 / 3 / 2 / 4; transform: rotate(-.6deg); }

  .grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--md); }
  /* Fixed zones across the row: icon / title (two-line reserve) / body /
     demo. The point is that all mini-UI vignettes START on one shared
     y-line instead of drifting with ragged text lengths. */
  .tile h3 { min-height: 2.44em; }             /* 2 lines × 1.22 */
  .tile > .small { min-height: 4.35em; }       /* fallback body reserve */
  .tile__visual { min-height: 152px; }
  .tile__visual--flush { min-height: 168px; }
  /* Where subgrid exists (all evergreen browsers), the four tiles share
     literal row tracks, so the alignment holds for any translation length.
     row-gap 0: the zones keep their rhythm from the child margins. */
  @supports (grid-template-rows: subgrid) {
    .tile { display: grid; grid-row: span 4; grid-template-rows: subgrid; row-gap: 0; }
    .tile > .small { min-height: 0; }
  }
  .device { width: min(46vw, 330px); }
  .panel { padding: var(--xxl); }
  .foot__grid { grid-template-columns: 1.4fr 1fr 1fr 1fr; }
}

/* ============================================================
   Desktop
   ============================================================ */
@media (min-width: 1024px) {
  .nav { top: var(--lg); left: 50%; right: auto; transform: translateX(-50%); width: min(calc(100% - 48px), var(--maxw)); }
  .nav__links { display: flex; align-items: center; gap: var(--xl); margin-right: var(--md); }
  .nav__links a { font-size: 15px; font-weight: 500; color: var(--ink-2); transition: color .18s var(--ease-out); }
  .nav__links a:hover { color: var(--ink); }
  .nav__burger { display: none; }

  .hero { padding-top: 168px; display: grid; align-content: start; }
  /* The first viewport belongs to claim + phone; the cards start below the
     fold instead of being beheaded by it. */
  .hero__inner { max-width: 56%; min-height: calc(100svh - 168px - 48px); }
  .hero__device {
    top: 50%;
    right: max(var(--gutter), calc((100vw - var(--maxw)) / 2));
    translate: 0 -50%;
    width: min(30vw, 380px);
    transform: rotate(-5deg);
  }
  .hero__cards { margin-top: 48px; max-width: 640px; }

  .grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  /* Narrow 4-up columns wrap bodies to up to five lines; the fallback
     reserve grows with them (subgrid path zeroes this again). */
  @supports not (grid-template-rows: subgrid) {
    .tile > .small { min-height: 7.5em; }
  }
  .device { width: 340px; }
  .cap { padding: 14px var(--xl) 14px var(--md); }
}

/* ============================================================
   Reduced motion — the sequence is replaced by its poster and the
   page becomes an ordinary document. Non-negotiable.
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
  .reveal { opacity: 1; transform: none; }
  .shot__stage { height: auto; padding-block: var(--xxxl); }
  .caps { position: static; margin-top: var(--xl); gap: var(--xs); }
  .cap { grid-area: auto; opacity: 1; }
  .hint { display: none; }
}

/* The real share sheet, cropped to its app row: the one moment the
   whole product hinges on, shown as-is. Sits above the platform chips
   in step 1. */
.step__shot {
  /* width/height attributes reserve layout space, but once max-width
     clamps the box the height MUST follow — without this the crops render
     vertically stretched and read as "blurry". */
  width: 100%;
  height: auto;
  margin-top: var(--sm);
  border-radius: var(--r-sm);
  border: 1px solid var(--stroke);
  box-shadow: var(--sh-card);
}

/* ============================================================
   Small-screen refinements from the round-3 panel
   ============================================================ */
@media (max-width: 699px) {
  /* The scroll hint and the caption pills share the stage bottom on a
     phone — one of them has to go, and the captions carry the story. */
  .hint { display: none; }
  /* Stronger top fade: the floating pill nav needs more cover when
     sections land underneath it. */
  .topscrim {
    height: 96px;
    background: linear-gradient(180deg,
      rgba(243, 245, 247, .97) 0%,
      rgba(243, 245, 247, .72) 52%,
      rgba(243, 245, 247, 0) 100%);
  }
}

/* Language switcher in the desktop nav — the footer and mobile menu had
   one all along, the desktop rail did not. */
.nav__langs { display: none; }
@media (min-width: 1024px) {
  .nav__langs {
    display: flex;
    align-items: center;
    gap: 2px;
    margin-right: var(--xs);
  }
  .nav__langs a {
    padding: 6px 8px;
    border-radius: var(--r-pill);
    font-size: 13px;
    font-weight: 600;
    letter-spacing: .02em;
    color: var(--ink-3);
    transition: color .18s var(--ease-out), background .18s var(--ease-out);
  }
  .nav__langs a:hover { color: var(--ink); }
  .nav__langs a[aria-current] { color: var(--ink); background: var(--subtle); }
}
