/* =============================================================================
   Brizeet — the home page
   ---------------------------------------------------------------------------
   Loaded only by index.html. styles.css carries the tokens, the type scale and
   the cut-paper primitives (.btn, .card, .sticker, mark.marker, .tile); this
   file is the page built out of them.

   THE IDEA  The old page was a route diagram: a hairline down the left gutter,
             one accent, no pictures, nothing that moved except on scroll. The
             app it advertises is none of those things — it is cut paper,
             twenty-three illustrations with people in them, a highlighter
             through the headings and a sticker on every card. So the page is
             rebuilt out of the app's own parts rather than out of a house style
             that happened to share its palette.

   HUE       every section declares its lead once, as --lead / --lead-soft /
             --lead-ink, and everything inside reads those three. It used to be
             one of five decorative hues per section; the palette is the saffron
             and a neutral ramp now, so all five resolve to the same pale wash
             and the same bronze glyph. The mechanism stays — nothing inside a
             section reaches for a colour by name, so the whole page still turns
             on three declarations.

   SHAPE     no section is a box. Structure comes from a blob of the palest
             saffron bled off the edge, and content sits on cards with the app's
             own radius, hairline and shadow.

   MOTION    one sequence per section, played once when it is reached, on the
             app's own durations and its 35ms stagger. Two things loop, and both
             are the same two that loop in the app: the corridor's dashes (the
             thesis, moving) and a four-unit bob under whatever a scene wants to
             feel alive. Everything else rests in its finished state, so a page
             that never gets the observer is a page that is merely still.
   ========================================================================== */

/* ═════════════════════════════════════════════════════════════ the frame */

.sec {
  position: relative;
  /* The default lead. */
  --lead: var(--h-saffron);
  --lead-soft: var(--h-saffron-soft);
  --lead-ink: var(--h-saffron-ink);
}
/* Unchanged, and deliberately: all five --h-* triples resolve to the same pale
   saffron now, so these five rules render identically. Leaving them alone keeps
   index.html's section classes meaningful and keeps the whole question in the
   token block, which is the one place a second appearance would go back in. */
.hue-saffron { --lead: var(--h-saffron); --lead-soft: var(--h-saffron-soft); --lead-ink: var(--h-saffron-ink); }
.hue-magenta { --lead: var(--h-magenta); --lead-soft: var(--h-magenta-soft); --lead-ink: var(--h-magenta-ink); }
.hue-violet  { --lead: var(--h-violet);  --lead-soft: var(--h-violet-soft);  --lead-ink: var(--h-violet-ink); }
.hue-cobalt  { --lead: var(--h-cobalt);  --lead-soft: var(--h-cobalt-soft);  --lead-ink: var(--h-cobalt-ink); }
.hue-cyan    { --lead: var(--h-cyan);    --lead-soft: var(--h-cyan-soft);    --lead-ink: var(--h-cyan-ink); }

.sec-wrap {
  position: relative; z-index: 1;
  max-width: var(--measure); margin-inline: auto;
  padding: clamp(56px, 8vw, 104px) var(--gutter);
}

/* Two or three soft shapes behind a section, bled off the edges, at a weight
   somewhere between wallpaper and nothing — components/ui/BlobBackdrop.tsx.
   `soft` rather than a translucent `base`: soft is already the palest step of
   the saffron and is measured, where a translucent base over the page is a
   colour nothing has ever checked. */
.blobs {
  position: absolute; inset: 0;
  overflow: hidden; pointer-events: none;
  z-index: 0;
}
.blobs span {
  position: absolute;
  background: var(--lead-soft);
  opacity: .85;
}
:root[data-theme="dark"] .blobs span { opacity: .5; }
.blob-a {
  width: 46vw; height: 46vw; max-width: 620px; max-height: 620px;
  top: -14%; right: -12%;
  border-radius: 58% 42% 47% 53% / 44% 51% 49% 56%;
}
.blob-b {
  width: 34vw; height: 34vw; max-width: 440px; max-height: 440px;
  bottom: -16%; left: -10%;
  border-radius: 43% 57% 62% 38% / 55% 40% 60% 45%;
}
/* Two or three shapes, and not all in one hue — that is what BlobBackdrop does,
   and here it is load-bearing rather than decorative: the courier's own ground
   is magenta-soft, so a magenta wash behind it erases the scene's backdrop and
   the figure ends up floating on the page. Cobalt behind the art and saffron
   under the copy keeps the drawing's own ground readable as a shape. */
.hero .blob-a { background: var(--h-cobalt-soft); }
.hero .blob-b { background: var(--h-saffron-soft); }

/* The heading block. A kicker set as a sticker, a two-tone display headline,
   and a lede — in that order on every section, so the page has one rhythm. */
.sec-head { max-width: 62ch; }
.sec-head .kicker {
  display: inline-flex; align-items: center; gap: 8px;
  margin-bottom: var(--sp-lg);
  padding: 6px 14px;
  background: var(--lead-soft); color: var(--lead-ink);
  border-radius: var(--r-pill);
  letter-spacing: 0.12em;
}
.sec-head .kicker .icon { width: 15px; height: 15px; stroke-width: 2.2; }
.sec-head h2 { margin-bottom: var(--sp-lg); }
.sec-head .lede { max-width: 54ch; }
.sec-centred { text-align: center; }
.sec-centred .sec-head { margin-inline: auto; }
.sec-centred .lede { margin-inline: auto; }

/* ═══════════════════════════════════════════════════════════════════ hero */

.hero { position: relative; overflow: clip; }
.hero-inner {
  position: relative; z-index: 1;
  max-width: var(--measure); margin-inline: auto;
  padding: clamp(32px, 5vw, 64px) var(--gutter) clamp(40px, 6vw, 72px);
  display: grid; gap: clamp(32px, 5vw, 56px);
  align-items: center;
}
@media (min-width: 980px) {
  .hero-inner { grid-template-columns: minmax(0, 1.02fr) minmax(0, 0.98fr); }
}

.hero-copy > * + * { margin-top: var(--sp-xl); }
.hero-copy h1 { margin-top: var(--sp-lg); }
/* The two-tone headline, which is the app's signature pairing: one line set
   regular, the next line set heavy, both at the same size. It only reads as one
   voice if the contrast comes from inside one family — see src/theme/fonts.ts,
   which loads a real 900 rather than letting the platform synthesise one. */
.hero-copy h1 .line { display: block; }
.hero-copy .lede { font-size: clamp(17px, 1.15vw, 20px); max-width: 46ch; }

.hero-kicker {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 6px 14px;
  background: var(--lead-soft); color: var(--lead-ink);
  border-radius: var(--r-pill);
  font: 500 11.5px/1 var(--font-mono);
  letter-spacing: 0.12em; text-transform: uppercase;
}
.hero-kicker .icon { width: 15px; height: 15px; stroke-width: 2.2; }

.hero-actions {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-md) var(--sp-lg);
}

/* The small print under the download button. It opts out of the copy column's
   own rhythm because it is the caption to the button row rather than the next
   thing in the sequence. */
.dl-note {
  display: grid; gap: 5px;
  margin-top: var(--sp-md) !important;
  font-size: 12.5px; line-height: 1.55;
  color: var(--muted);
  max-width: 52ch;
}
/* It wraps. Holding the four figures on one line fits today's string into a
   phone and nothing else. */
.dl-meta { letter-spacing: 0.02em; }
.dl-sideload { color: var(--muted); }
.dl-note a { color: var(--route); text-underline-offset: 3px; }
.dl-note a:hover { text-decoration-thickness: 2px; }

/* ------------------------------------------------------------- the hero art
   The courier scene from components/ui/Illustration.tsx, drawn at the size it
   was always meant to be: a 200×240 canvas rather than a 60pt slot above a
   heading. It carries its own stickers, which is the same joke the app makes on
   a job card — the picture is the product, and the label stuck to it is what
   the product says. */
.hero-art {
  position: relative;
  justify-self: center;
  width: min(100%, 460px);
}
.hero-art .scene { width: 100%; height: auto; }

/* The stickers float over the drawing rather than sitting under it: they are
   labels stuck on a photograph, not a caption. Absolute at every width, and
   they scale with the art because their offsets are percentages. */
.hero-tag { position: absolute; z-index: 2; }
.hero-tag-a { top: 6%;  left: -4%; }
.hero-tag-b { top: 40%; right: -6%; }
.hero-tag-c { bottom: 8%; left: 2%; }
@media (max-width: 520px) {
  .hero-tag-a { left: 0; }
  .hero-tag-b { right: 0; }
}

/* Four facts, as pressed-out pills. First on the page, because geography used
   to appear only inside illustrative content — so a visitor in Calgary could
   read the whole page, download 112 MB, sign up and post an errand into a void,
   which is a one-star review rather than a bounce. */
.hero-facts {
  position: relative; z-index: 1;
  max-width: var(--measure); margin-inline: auto;
  padding: 0 var(--gutter) clamp(40px, 6vw, 64px);
  display: flex; flex-wrap: wrap; gap: var(--sp-md);
}
.hero-facts li {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 9px 16px;
  background: var(--raised);
  border: 1px solid var(--rule); border-radius: var(--r-pill);
  font: 500 12.5px/1 var(--font-mono);
  letter-spacing: 0.04em;
}
.hero-facts .icon { width: 16px; height: 16px; stroke-width: 2.1; }
.hero-facts li:nth-child(1) .icon { color: var(--h-magenta-ink); }
.hero-facts li:nth-child(2) .icon { color: var(--h-cobalt-ink); }
.hero-facts li:nth-child(3) .icon { color: var(--h-violet-ink); }
.hero-facts li:nth-child(4) .icon { color: var(--h-cyan-ink); }

/* ══════════════════════════════════════════════════════════════ the film */
/* The first picture of the actual app anywhere on this site. Everything else
   here is a drawing, so a stranger was being asked to download 112 MB from an
   unknown domain on the strength of illustrations.

   Click to play, never autoplay: it carries an audio score, it is five
   megabytes, and a hero that starts moving on its own is the thing that makes
   people close a tab. The poster is a real frame, so with JavaScript off or the
   video blocked this is still a picture of the app rather than an empty box. */

.film-split {
  display: grid; gap: clamp(28px, 4vw, 48px); align-items: center;
}
@media (min-width: 900px) {
  .film-split { grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr); }
}
.hero-film {
  position: relative;
  margin: 0;
  border-radius: var(--r-xl);
  overflow: hidden;
  background: var(--sunken);
  aspect-ratio: 1 / 1;
  box-shadow: var(--shadow-raised);
}
/* `contain`, not `cover`. The film is square (1080×1080) but `launch-poster.png`
   is a 16:9 export of the same render, so a square box cropping to fill cut the
   sentence out of the poster frame. `contain` costs the video nothing — a square
   source in a square box fills it either way — and shows the poster whole, with
   the sunken ground behind it doing the letterboxing. */
.hero-film video { width: 100%; height: 100%; object-fit: contain; }
.hero-film-play {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  border: 0; padding: 0; margin: 0;
  background: transparent; cursor: pointer;
  color: var(--paint-ink);
}
.hero-film-play::before {
  content: "";
  position: absolute; inset: 0;
  background: radial-gradient(circle at 50% 50%, rgba(0,0,0,0.14), rgba(0,0,0,0.32));
}
.hero-film-play span {
  position: relative;
  display: grid; place-items: center;
  width: 76px; height: 76px;
  border-radius: var(--r-pill);
  background: var(--paint);
  transition: transform var(--d-base) var(--ease-pop);
}
.hero-film-play:hover span { transform: scale(1.06); }
.hero-film-play span svg { width: 28px; height: 28px; margin-left: 4px; }
.hero-film.is-playing .hero-film-play { display: none; }

/* ═══════════════════════════════════════════════════════ what people send */

.things {
  display: grid; gap: var(--sp-lg);
  grid-template-columns: repeat(auto-fit, minmax(138px, 1fr));
  margin-top: var(--sp-xxl);
}
.things li {
  display: grid; justify-items: center; gap: var(--sp-md);
  padding: var(--sp-xl) var(--sp-md);
  background: var(--raised);
  border: 1px solid var(--rule); border-radius: var(--r-lg);
  box-shadow: var(--shadow);
  font: 600 13.5px/1.3 var(--font-sans);
  text-align: center;
  transition: transform var(--d-base) var(--ease-out);
}
.things li:hover { transform: translateY(-4px); }
/* The tiles used to cycle five hues so the row read as the app's palette rather
   than as six of one colour. All five resolve to the same pale saffron now, so
   the row is one tint and the tiles are told apart by their glyphs. The cycle is
   kept because it is where a second appearance would go back in. */
.things li:nth-child(5n+1) .tile { background: var(--h-saffron-soft); color: var(--h-saffron-ink); }
.things li:nth-child(5n+2) .tile { background: var(--h-magenta-soft); color: var(--h-magenta-ink); }
.things li:nth-child(5n+3) .tile { background: var(--h-violet-soft);  color: var(--h-violet-ink); }
.things li:nth-child(5n+4) .tile { background: var(--h-cobalt-soft);  color: var(--h-cobalt-ink); }
.things li:nth-child(5n+5) .tile { background: var(--h-cyan-soft);    color: var(--h-cyan-ink); }

/* ═══════════════════════════════════════════════════════════ why it exists */

.reasons {
  display: grid; gap: var(--sp-xl);
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  margin-top: var(--sp-xxxl);
}
.reasons li {
  display: grid; gap: var(--sp-md);
  align-content: start;
  padding: var(--sp-xl);
  background: var(--raised);
  border: 1px solid var(--rule); border-radius: var(--r-xl);
  box-shadow: var(--shadow);
}
.reasons li:nth-child(1) .tile { background: var(--h-magenta-soft); color: var(--h-magenta-ink); }
.reasons li:nth-child(2) .tile { background: var(--h-violet-soft);  color: var(--h-violet-ink); }
.reasons li:nth-child(3) .tile { background: var(--h-cyan-soft);    color: var(--h-cyan-ink); }
.reasons p { color: var(--muted); font-size: 15px; }

/* The sentence the three cards add up to, set as a headline with the
   highlighter through the question it asks. */
.pull {
  margin-top: var(--sp-xxxl);
  font-family: var(--font-display);
  font-size: clamp(23px, 2.9vw, 34px);
  font-weight: 700; line-height: 1.2; letter-spacing: -0.02em;
  text-wrap: balance;
}

/* ══════════════════════════════════════════════════════════ how it works */

.how-split {
  display: grid; gap: clamp(32px, 4vw, 56px);
  margin-top: var(--sp-xxxl);
  align-items: start;
}
@media (min-width: 960px) {
  .how-split { grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr); }
}

/* Four stops on one road. The corridor behind them is the same shape the
   illustration set draws five times over, laid vertically: a recessive rail
   band with the cobalt dashes travelling along it. */
.stops { position: relative; display: grid; gap: var(--sp-lg); }
.stops::before {
  content: "";
  position: absolute; left: 39px; top: 40px; bottom: 40px; width: 10px;
  background: var(--sc-rail);
  border-radius: var(--r-pill);
  opacity: .28;
}
.stops li {
  position: relative;
  display: grid; grid-template-columns: 56px minmax(0, 1fr);
  gap: var(--sp-lg);
  align-items: start;
  padding: var(--sp-lg);
  background: var(--raised);
  border: 1px solid var(--rule); border-radius: var(--r-lg);
  box-shadow: var(--shadow);
}
/* The number, in a saffron disc. This is the only place on
   the page that carries numbers, because it is the only place where the order
   tells you something. */
.stop-n {
  display: grid; place-items: center;
  width: 56px; height: 56px;
  background: var(--paint); color: var(--paint-ink);
  border-radius: var(--r-pill);
  font: 700 17px/1 var(--font-mono);
  font-variant-numeric: tabular-nums;
}
.stop-body { display: grid; gap: 5px; }
.stop-body .icon { width: 17px; height: 17px; color: var(--lead-ink); }
.stop-head { display: flex; align-items: center; gap: var(--sp-sm); }
.stop-t { color: var(--muted); font-size: 14.5px; }
.stop-t em { font-style: normal; color: var(--route); font-weight: 600; }

/* The sample request card. Boxed, because it is boxed in the app — this is a
   `Card` with a `SummaryRow` per fact and a `Sticker` on the corner, drawn the
   way the app draws it rather than the way a marketing page would. */
.req-card {
  position: relative;
  margin: 0;
  padding: var(--sp-xl);
  background: var(--raised);
  border: 1px solid var(--rule); border-radius: var(--r-xl);
  box-shadow: 6px 6px 0 var(--lead-soft), var(--shadow);
}
.req-sticker { position: absolute; top: -14px; right: 18px; z-index: 2; }
.req-cap {
  font: 500 11px/1 var(--font-mono);
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--subtle);
}
.req-head {
  display: flex; align-items: center; gap: var(--sp-md);
  margin-top: var(--sp-lg);
  font-family: var(--font-display); font-size: 24px; font-weight: 700;
  letter-spacing: -0.02em;
}
.req-head .tile { width: 44px; height: 44px; }
.req-head .tile .icon { width: 22px; height: 22px; }
.req-rows { margin-top: var(--sp-xl); display: grid; gap: 2px; }
.req-rows li {
  display: grid; grid-template-columns: 22px 58px minmax(0, 1fr);
  align-items: center; gap: var(--sp-md);
  padding: var(--sp-md) 0;
  border-bottom: 1px solid var(--rule);
}
.req-rows li:last-child { border-bottom: 0; }
.req-rows .icon { width: 18px; height: 18px; color: var(--muted); }
.req-k {
  font: 500 11px/1 var(--font-mono);
  letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--subtle);
}
.req-rows b { font-size: 15px; font-weight: 600; text-align: right; }
.req-foot {
  display: flex; align-items: center; gap: var(--sp-sm);
  margin-top: var(--sp-lg); padding-top: var(--sp-lg);
  border-top: 2px dashed var(--rule);
  font: 500 12.5px/1.4 var(--font-mono);
  color: var(--good);
}
.req-foot .icon { width: 17px; height: 17px; stroke-width: 2.3; }

/* ══════════════════════════════════════════════════ route matching (thesis) */

.corridor-split {
  display: grid; gap: clamp(32px, 4vw, 52px);
  margin-top: var(--sp-xxxl);
  align-items: start;
}
@media (min-width: 980px) {
  .corridor-split { grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr); }
}

.corridor-figure { margin: 0; }
.corridor-figure svg {
  width: 100%; height: auto;
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-raised);
}
.corridor-figure figcaption {
  display: flex; flex-wrap: wrap; gap: var(--sp-lg);
  margin-top: var(--sp-lg);
  font-family: var(--font-mono);
  font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--muted);
}
.corridor-figure figcaption span { display: inline-flex; align-items: center; gap: 8px; }
/* The key has to be the thing it is a key to. Off-route pins on this map are
   paper with a recessive centre, not grey discs, so the shared .swatch — which
   is a grey disc, because on the install page that is what it marks — is
   repainted here rather than left saying something the drawing does not. */
.corridor-figure .swatch { background: var(--sc-paper); }

/* The driver's own route, stated the way the app states it: a card, with the
   trip in display type and the window in the mono. */
.board-route {
  display: grid; gap: 4px;
  padding: var(--sp-lg) var(--sp-xl);
  background: var(--lead-soft); color: var(--lead-ink);
  border-radius: var(--r-lg);
}
.board-route-line {
  font-family: var(--font-display); font-size: clamp(19px, 2vw, 24px);
  font-weight: 900; letter-spacing: -0.02em;
}
.board-route-when { font: 500 11.5px/1.4 var(--font-mono); letter-spacing: 0.04em; }

.board-title {
  margin: var(--sp-xl) 0 var(--sp-md);
  font: 500 11px/1 var(--font-mono);
  letter-spacing: 0.14em; text-transform: uppercase;
  /* On the page, not on a card — so --muted. See `.priorities legend`. */
  color: var(--muted);
}

/* Each job is a row off the driver's feed, drawn as the app draws it: an icon
   tile, the thing, where it is, and how far off the route — with the sticker
   that is the whole product on the three that are on it. */
.jobs { display: grid; gap: var(--sp-md); }
.jobs li {
  display: grid;
  grid-template-columns: 44px minmax(0, 1fr) auto;
  grid-template-areas: "tile name off" "tile where tag";
  align-items: center; gap: 2px var(--sp-md);
  padding: var(--sp-md) var(--sp-lg);
  background: var(--raised);
  border: 1px solid var(--rule); border-radius: var(--r-md);
  box-shadow: var(--shadow);
}
.jobs .tile { grid-area: tile; width: 44px; height: 44px; }
.jobs .tile .icon { width: 21px; height: 21px; }
.job-name { grid-area: name; font-weight: 600; font-size: 15px; }
.job-where { grid-area: where; font: 12px/1.3 var(--font-mono); color: var(--subtle); }
.job-off {
  grid-area: off; justify-self: end;
  font: 600 13px/1 var(--font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--text);
}
.job-tag {
  grid-area: tag; justify-self: end;
  padding: 4px 10px;
  font: 600 10.5px/1 var(--font-mono);
  letter-spacing: 0.06em; text-transform: uppercase;
  background: var(--h-cobalt-soft); color: var(--h-cobalt-ink);
  border-radius: var(--r-pill);
  transform: rotate(-1.5deg);
}
/* A detour is still a job, so it is not greyed out — it simply stops carrying
   the badge that says it is on the way. */
.jobs .is-far { opacity: .72; }
.jobs .is-far .job-tag {
  background: var(--raised-alt); color: var(--muted);
  transform: none;
  border: 1px solid var(--rule-strong);
}
.jobs + .footnote { margin-top: var(--sp-lg); }

/* ═════════════════════════════════════════════════════════════════ timing */

.timing { margin-top: var(--sp-xxxl); }
.priorities legend {
  font: 500 11px/1 var(--font-mono);
  letter-spacing: 0.14em; text-transform: uppercase;
  /* --muted rather than --subtle: this sits on the page, where --subtle measures
     4.15:1. It is comfortable on a white card and marginal here. */
  color: var(--muted);
}

/* The chart is the control. Four bars drawn to the price each deadline
   suggests, so the trade-off is visible at rest rather than one number at a
   time — and picking a deadline is picking a bar. */
.price-chart {
  margin-top: var(--sp-xl);
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  /* No gap, because the four bar wells butt together to draw one continuous
     baseline — four outlined boxes floating on nothing read as four boxes, and
     the line under them is what makes them a measurement. The bars are already
     capped narrower than their column, so the air between them costs nothing. */
  gap: 0;
}
.pri-col input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.pri-col label {
  display: grid; grid-template-rows: auto minmax(0, 1fr) auto;
  gap: var(--sp-sm);
  height: clamp(184px, 26vw, 240px);
  cursor: pointer; text-align: center;
}
.price-amt {
  font-family: var(--font-mono);
  font-size: clamp(12.5px, 1.5vw, 15px); font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  transition: color var(--d-base) var(--ease);
}
.price-bar-wrap {
  display: flex; align-items: flex-end; justify-content: center;
  border-bottom: 1px solid var(--rule);
}
.price-bar {
  /* Narrower than its column twice over: an absolute cap so the tallest bar on
     a wide screen reads as a measurement rather than a block, and a percentage
     so four of them on a phone do not butt together into one shape with double
     rims between the bars. */
  width: min(72%, 88px); height: var(--h, 0%);
  background: var(--raised-alt);
  border: 1px solid var(--rule);
  border-bottom: 0;
  border-radius: var(--r-md) var(--r-md) 0 0;
  transition: background-color var(--d-base) var(--ease);
}
.price-when {
  min-height: 30px;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-mono);
  font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--muted);
  transition: color var(--d-base) var(--ease);
}
.pri-col label:hover .price-bar { background: var(--lead-soft); }
.pri-col input:checked + label .price-bar { background: var(--paint); }
.pri-col input:checked + label .price-amt,
.pri-col input:checked + label .price-when { color: var(--text); font-weight: 700; }
.pri-col input:focus-visible + label { outline: 2px solid var(--focus); outline-offset: 4px; border-radius: var(--r-md); }
.pri-col input:disabled + label { cursor: not-allowed; }
.pri-col input:disabled + label .price-bar { opacity: .3; }
.pri-col input:disabled + label .price-amt { opacity: .4; }
.pri-col input:disabled + label .price-when { opacity: .5; text-decoration: line-through; }

.closed-note {
  margin-top: var(--sp-lg);
  padding: var(--sp-md) var(--sp-lg);
  background: var(--warn-soft); color: var(--warn);
  border-radius: var(--r-md);
  font-size: 13.5px;
}

/* What the app would tell you, in the app's own two lines. */
.readout {
  display: grid; gap: var(--sp-lg);
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  margin-top: var(--sp-xl);
}
.readout > div {
  padding: var(--sp-lg) var(--sp-xl);
  background: var(--raised);
  border: 1px solid var(--rule); border-radius: var(--r-lg);
  box-shadow: var(--shadow);
}
.readout dt {
  font: 500 11px/1 var(--font-mono);
  letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--subtle);
}
.readout dd {
  margin-top: 7px;
  font-family: var(--font-display); font-size: clamp(21px, 2.2vw, 27px);
  font-weight: 900; letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.timing .footnote { margin-top: var(--sp-lg); }

/* ════════════════════════════════════════════════════════════════ privacy */

.privacy {
  display: grid; gap: clamp(32px, 4vw, 52px);
  margin-top: var(--sp-xxxl);
  align-items: start;
}
@media (min-width: 960px) { .privacy { grid-template-columns: 1fr 1fr; } }

/* The segmented control, as the app draws it: a sunken pill track with the
   chosen half filled in the brand. */
.tabs {
  display: grid; grid-template-columns: 1fr 1fr; gap: 4px;
  padding: 4px;
  background: var(--sunken);
  border: 1px solid var(--rule); border-radius: var(--r-pill);
}
.tab input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.tab label {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 42px; padding: 0 var(--sp-md);
  border-radius: var(--r-pill);
  font: 600 12.5px/1.2 var(--font-sans);
  color: var(--muted); cursor: pointer; text-align: center;
  transition: background-color var(--d-base) var(--ease), color var(--d-base) var(--ease);
}
.tab label .icon { width: 17px; height: 17px; }
.tab input:checked + label {
  background: var(--paint); color: var(--paint-ink);
}
.tab input:focus-visible + label { outline: 2px solid var(--focus); outline-offset: 3px; }

.reveal-panel { margin-top: var(--sp-xl); }
.ticks { display: grid; gap: var(--sp-sm); }
.ticks li {
  display: flex; align-items: center; gap: var(--sp-md);
  padding: var(--sp-md) var(--sp-lg);
  background: var(--raised);
  border: 1px solid var(--rule); border-radius: var(--r-md);
  font-size: 14.5px;
}
.ticks .icon { width: 20px; height: 20px; flex: none; stroke-width: 2.4; padding: 2px; border-radius: var(--r-pill); }
.ticks .yes .icon { background: var(--good-soft); color: var(--good); }
.ticks .no .icon  { background: var(--warn-soft); color: var(--warn); }
.ticks .no { color: var(--muted); }
.privacy .footnote { margin-top: var(--sp-lg); }

.privacy-figure { margin: 0; }
.privacy-figure svg {
  width: 100%; height: auto;
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-raised);
}
.privacy-figure figcaption {
  margin-top: var(--sp-lg);
  padding: var(--sp-md) var(--sp-lg);
  background: var(--raised);
  border: 1px solid var(--rule); border-radius: var(--r-md);
  font: 500 12.5px/1.4 var(--font-mono);
  color: var(--text);
}
/* One caption at a time. Written twice on purpose: `data-state` is what JS
   sets, `:has()` keeps the control honest with scripting off. */
.privacy-figure figcaption [data-caption] { display: none; }
.privacy[data-state="before"] [data-caption="before"],
.privacy[data-state="after"]  [data-caption="after"]  { display: block; }
.privacy:has(#rev-before:checked) [data-caption="before"] { display: block; }
.privacy:has(#rev-after:checked)  [data-caption="after"]  { display: block; }
.privacy:has(#rev-before:checked) [data-caption="after"]  { display: none; }
.privacy:has(#rev-after:checked)  [data-caption="before"] { display: none; }

/* The two states of the drawing, switched by the same control. */
.privacy-figure .layer-after { opacity: 0; }
.privacy[data-state="after"] .layer-before,
.privacy:has(#rev-after:checked) .layer-before { opacity: 0; }
.privacy[data-state="after"] .layer-after,
.privacy:has(#rev-after:checked) .layer-after { opacity: 1; }
.privacy-figure .layer { transition: opacity var(--d-slow) var(--ease); }

/* ═════════════════════════════════════════════ proof — the change of key */
/* The page inverts here: a full-bleed ink slab, which is `heroSurface` in the
   app — the one surface there that is neither the page nor a card. It reads as
   a change of key in both themes, and it is the only place the saffron gets to
   sit on something dark. */

.sec-band {
  background: var(--hero-band);
  color: var(--on-hero);
}
.sec-band .kicker { background: rgba(255,255,255,0.1); color: var(--on-hero); }
.sec-band .lede, .sec-band .footnote { color: var(--on-hero-muted); }
.sec-band .footnote em { font-style: normal; color: var(--marker); font-weight: 600; }
.sec-band h2 em { color: var(--marker); }
.sec-band .blobs span { background: rgba(255,255,255,0.05); }

.proof {
  display: grid; gap: clamp(32px, 5vw, 56px); align-items: center;
}
@media (min-width: 900px) { .proof { grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr); } }
.proof > div > * + * { margin-top: var(--sp-lg); }

.pin-demo { display: grid; justify-items: center; gap: var(--sp-xl); }
/* Not an ink rim: on the slab the well takes the highlighter as its edge, the
   one place the saffron sits on something dark. */
.sec-band .pin-box {
  background: rgba(255,255,255,0.08);
  border: 2px solid var(--marker);
  color: var(--on-hero);
}
.sec-band .pin-verdict {
  background: var(--marker); color: var(--ink-880);
}

/* ════════════════════════════════════════════════════════════════ drivers */

.drivers {
  display: grid; gap: clamp(32px, 4vw, 52px);
  margin-top: var(--sp-xxxl);
  align-items: start;
}
@media (min-width: 960px) { .drivers { grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr); } }

.driver-figure { margin: 0; }
.driver-figure .scene {
  width: 100%; height: auto;
  background: var(--lead-soft);
  border-radius: var(--r-xl);
}

/* A driver's first question is "what does this actually pay?", so it is
   answered in two numbers before any of the four claims below it. */
.earnings {
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-md);
  margin-top: var(--sp-lg);
}
.earnings li {
  display: grid; gap: 3px;
  padding: var(--sp-lg);
  background: var(--raised);
  border: 1px solid var(--rule); border-radius: var(--r-lg);
  box-shadow: 4px 4px 0 var(--lead-soft);
}
.e-when { font: 500 10.5px/1 var(--font-mono); letter-spacing: 0.12em; text-transform: uppercase; color: var(--subtle); }
.e-amt {
  font-family: var(--font-display); font-size: clamp(24px, 3vw, 32px);
  font-weight: 900; letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
}
.e-n { font: 12px/1 var(--font-mono); color: var(--muted); }
.driver-aside .footnote { margin-top: var(--sp-md); }

.perks { display: grid; gap: var(--sp-lg); grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
.perks li {
  display: grid; gap: var(--sp-md); align-content: start;
  padding: var(--sp-xl);
  background: var(--raised);
  border: 1px solid var(--rule); border-radius: var(--r-xl);
  box-shadow: var(--shadow);
}
.perks li:nth-child(1) .tile { background: var(--h-saffron-soft); color: var(--h-saffron-ink); }
.perks li:nth-child(2) .tile { background: var(--h-cobalt-soft);  color: var(--h-cobalt-ink); }
.perks li:nth-child(3) .tile { background: var(--h-magenta-soft); color: var(--h-magenta-ink); }
.perks li:nth-child(4) .tile { background: var(--h-violet-soft);  color: var(--h-violet-ink); }
.perks p { color: var(--muted); font-size: 14.5px; }
.footnote-wide { margin-top: var(--sp-xxl); max-width: none; }

/* ════════════════════════════════════════════════════════════════════ faq */

.faq { display: grid; gap: var(--sp-md); margin-top: var(--sp-xxxl); }
.faq details {
  background: var(--raised);
  border: 1px solid var(--rule); border-radius: var(--r-lg);
  box-shadow: var(--shadow);
  overflow: hidden;
}
.faq summary {
  display: flex; align-items: center; gap: var(--sp-md);
  padding: var(--sp-lg) var(--sp-xl);
  min-height: var(--touch);
  font-weight: 600; font-size: 15.5px;
  cursor: pointer; list-style: none;
}
.faq summary::-webkit-details-marker { display: none; }
/* The icon answers "is this my question?" before the sentence is read. */
.faq summary .icon { width: 19px; height: 19px; flex: none; color: var(--lead-ink); }
.faq summary span { flex: 1; }
/* A plus that loses its upright on open, so the marker says "collapse" rather
   than "there is more of this". */
.faq summary::after {
  content: "";
  width: 26px; height: 26px; flex: none;
  background:
    linear-gradient(var(--text), var(--text)) center/11px 2px no-repeat,
    linear-gradient(var(--text), var(--text)) center/2px 11px no-repeat;
  border: 1px solid var(--rule); border-radius: var(--r-pill);
  transition: transform var(--d-base) var(--ease), background-size var(--d-base) var(--ease);
}
.faq details[open] summary::after {
  background:
    linear-gradient(var(--text), var(--text)) center/11px 2px no-repeat,
    linear-gradient(var(--text), var(--text)) center/2px 0 no-repeat;
  transform: rotate(180deg);
}
.faq details[open] summary { padding-bottom: var(--sp-md); }
.faq details > p {
  padding: 0 var(--sp-xl) var(--sp-xl) calc(var(--sp-xl) + 19px + var(--sp-md));
  color: var(--muted); font-size: 15px;
  max-width: 72ch;
}
.faq details > p a { color: var(--route); text-underline-offset: 3px; }
.faq strong { color: var(--text); }
.faq em { font-style: normal; color: var(--route); font-weight: 600; }

/* ════════════════════════════════════════════════════════════════════ end */

.sec-end { background: var(--lead-soft); border-top: 1px solid var(--rule); }
.end-split {
  display: grid; gap: clamp(32px, 5vw, 56px); align-items: center;
}
@media (min-width: 900px) { .end-split { grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr); } }
.end-split .hero-actions { margin-top: var(--sp-xl); }
.end-art { justify-self: center; width: min(100%, 360px); }
.end-art .scene { width: 100%; height: auto; }

/* ═══════════════════════════════════════════════════════════════ the scenes
   Every drawing on this page is inline SVG using the --sc-* record, so it
   inverts with the theme instead of sitting on the page as a bright rectangle.
   The rules below are the only styling they need: a rim width, and the two
   motions the app's own scenes are allowed.
   ========================================================================= */

.scene { display: block; }

/* The corridor's dashes travel, and this is the one loop on the page that is
   not decoration: cobalt is the corridor everywhere in the app, so the dashes
   moving along it are the thesis moving. One full dash period is 20 units, so
   travelling exactly that far loops seamlessly. */
@keyframes corridor { to { stroke-dashoffset: -20; } }
.sc-dash { animation: corridor 1.6s linear infinite; }

/* Whatever is inside rises four units and settles, forever — `Rise` in
   Illustration.tsx. A scene names at most two groups this, and everything else
   stands still on purpose: a padlock that breathes is unsettling, not alive. */
@keyframes bob { 50% { transform: translateY(-4px); } }
.sc-bob { animation: bob 3.4s ease-in-out infinite; }

/* ══════════════════════════════════════════════════════════════════ motion
   One sequence per section, played once when it is reached. Each rests in its
   finished state, so a browser that never fires the observer shows a page that
   is merely still.
   ========================================================================= */

/* The highlighter is drawn rather than painted: the stroke grows in from the
   left, the way a felt tip actually crosses a word. `background-size` rather
   than a transform, because the paint is the mark's own background now — see
   the note on `mark.marker` in styles.css for why it had to stop being a
   pseudo-element. */
@keyframes swipe { from { background-size: 0 100%; } }
.hero mark.marker {
  animation: swipe var(--d-deliberate) var(--ease-out) 620ms both;
}

/* The hero lands in sequence: kicker, headline, lede, buttons, then the art. */
@keyframes rise { from { opacity: 0; transform: translateY(14px); } }
@keyframes pop { from { opacity: 0; transform: scale(0.86) rotate(-8deg); } }
html.js .hero-kicker { animation: rise var(--d-slow) var(--ease-out) both; }
html.js .hero-copy h1 { animation: rise var(--d-deliberate) var(--ease-out) 80ms both; }
html.js .hero-copy .lede { animation: rise var(--d-deliberate) var(--ease-out) 200ms both; }
html.js .hero-actions { animation: rise var(--d-deliberate) var(--ease-out) 280ms both; }
html.js .hero-copy .dl-note { animation: rise var(--d-deliberate) var(--ease-out) 340ms both; }
html.js .hero-art .scene { animation: rise var(--d-deliberate) var(--ease-out) 160ms both; }
/* The stickers land last and land hard: springs.pop is the one overshoot the
   app allows, and a sticker being pressed onto paper is one of the two things
   it allows it for. */
html.js .hero-tag { animation: pop var(--d-slow) var(--ease-pop) both; }
html.js .hero-tag-a { animation-delay: 760ms; }
html.js .hero-tag-b { animation-delay: 860ms; }
html.js .hero-tag-c { animation-delay: 960ms; }
html.js .hero-facts li { animation: rise var(--d-slow) var(--ease-out) both; }
html.js .hero-facts li:nth-child(1) { animation-delay: 420ms; }
html.js .hero-facts li:nth-child(2) { animation-delay: 455ms; }
html.js .hero-facts li:nth-child(3) { animation-delay: 490ms; }
html.js .hero-facts li:nth-child(4) { animation-delay: 525ms; }

/* The map pins land as the corridor reaches them. */
@keyframes drop { from { opacity: 0; transform: translateY(-16px); } }
.corridor-figure .pin { transform-box: fill-box; transform-origin: bottom center; }
[data-animate="corridor"].is-playing .pin {
  animation: drop var(--d-slow) var(--ease-out) both;
  animation-delay: calc(var(--i) * 120ms + 200ms);
}

/* The four bars grow to the price they mean, once, when the chart is reached.
   They do not redraw afterwards — only which one is filled changes — because
   the comparison is the point and a chart that redraws on every click cannot be
   compared. */
@keyframes grow { from { height: 0; } }
[data-animate="price"].is-playing .price-bar {
  animation: grow var(--d-deliberate) var(--ease-out) both;
  animation-delay: calc(var(--i) * 70ms);
}

/* The code arrives a digit at a time, then the verdict. */
@keyframes fade { from { opacity: 0; } }
[data-animate="pin"].is-playing .pin-box {
  animation: fade var(--d-slow) linear both;
  animation-delay: calc(var(--i) * 150ms + 200ms);
}
[data-animate="pin"].is-playing .pin-box b {
  animation: drop var(--d-slow) var(--ease-out) both;
  animation-delay: calc(var(--i) * 150ms + 220ms);
}
[data-animate="pin"].is-playing .pin-verdict {
  animation: pop var(--d-slow) var(--ease-pop) 900ms both;
}

@media (prefers-reduced-motion: reduce) {
  /* Nothing loops and nothing plays in. The corridor's dashes stop where they
     are, which is still a dashed road; the bob settles; every sequence above
     lands on its finished value rather than being damped, because an overshoot
     is precisely the motion this setting exists to refuse. */
  .sc-dash, .sc-bob { animation: none; }
  .hero mark.marker { animation: none; }
}
