/*
THESIS: the homepage IS the logbook — an instrument cluster that records and
classifies as you scroll, proving the product by being it. Refuses the
hero-screenshot + three-feature-card template the category always ships.
OWN-WORLD: DESIGN.md inherited — instrument charcoal / cool paper duals,
violet primary for what you can press and green reserved for what a number is
worth, 1px hairlines carrying structure, tabular numerals at heavy weight,
odometer rolls, confidence dials, route-hairline glyphs.
STORY: a driver watches a week record itself, sees the claim climb, starts free.
FIRST VIEWPORT: full-bleed cluster — rolling FY odometer, live claim readout,
one headline, primary action.
FORM: candidate 6 of 7 (page-as-logbook); seed key bd99b12d.
*/

/* ---- palette ----
   These tokens are the app's, not the site's own: DESIGN.md § Colour is the
   source of truth and this file mirrors it value for value. The page is the
   last thing a driver sees before the app opens, so a button that changes
   colour across that boundary reads as two products. Violet is what you can
   press; green is what a number is worth; blue is the Personal category and
   is never pressable. Change them in src/index.css first, then here. */
:root {
  --bg: #f7f9fc;
  --surface: #ffffff;
  --surface-2: #f5f3fd;
  --border: #e2e7f2;
  --ink: #141b2b;
  --ink-2: #424752;
  --ink-3: #6b7280;

  /* Primary: what you can press. Violet, per DESIGN.md. */
  --primary: #7a1fe0;
  --primary-strong: #4a0fa6;
  --primary-ink: #ffffff;
  --primary-soft: rgba(122, 31, 224, 0.1);
  /* Legacy alias — `accent` means "primary action", matching the app. Only
     --primary is redefined per theme below; these follow it automatically. */
  --accent: var(--primary);
  --accent-ink: var(--primary-ink);
  --accent-soft: var(--primary-soft);

  /* Money: what a number MEANS. Never used for anything pressable. */
  --money: #0c7a53;
  --money-soft: rgba(12, 122, 83, 0.1);

  /* Categories, matching the app exactly. Business IS the money, so it keeps
     the money green. Personal is blue because violet is spoken for — a violet
     category chip beside violet buttons reads as pressable. */
  --cat-business: #0c7a53;
  --cat-personal: #2a78d6;

  /* Hero backdrop. Kept as tokens rather than literals in the rule, because the
     right strength differs per theme: a wash that reads as a hint on paper is a
     spotlight on a dark ground. */
  --hero-glow-a: rgba(122, 31, 224, 0.2);
  --hero-glow-b: rgba(74, 15, 166, 0.14);
  --hero-grid: rgba(20, 27, 43, 0.07);
  --shadow-1: 0 1px 2px rgb(16 24 40 / 0.05);
  --shadow-2: 0 1px 2px rgb(16 24 40 / 0.04), 0 8px 24px rgb(16 24 40 / 0.07);
  --sans: ui-sans-serif, system-ui, 'Segoe UI Variable Text', 'Segoe UI', -apple-system, sans-serif;
  color-scheme: light;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) {
    --bg: #0b0e14;
    --surface: #141821;
    --surface-2: #1b2029;
    --border: #2a3140;
    --ink: #eef1f8;
    --ink-2: #a8b0c0;
    --ink-3: #7a8496;

    --primary: #a97bff;
    --primary-strong: #c9a9ff;
    --primary-ink: #1a0b33;
    --primary-soft: rgba(169, 123, 255, 0.14);

    --money: #17ad74;
    --money-soft: rgba(23, 173, 116, 0.14);

    --cat-business: #17ad74;
    --cat-personal: #3987e5;

    --hero-glow-a: rgba(169, 123, 255, 0.16);
    --hero-glow-b: rgba(122, 31, 224, 0.2);
    --hero-grid: rgba(238, 241, 248, 0.055);
    --shadow-1: none;
    --shadow-2: none;
    color-scheme: dark;
  }
}

:root[data-theme='dark'] {
  --bg: #0b0e14;
  --surface: #141821;
  --surface-2: #1b2029;
  --border: #2a3140;
  --ink: #eef1f8;
  --ink-2: #a8b0c0;
  --ink-3: #7a8496;

  --primary: #a97bff;
  --primary-strong: #c9a9ff;
  --primary-ink: #1a0b33;
  --primary-soft: rgba(169, 123, 255, 0.14);

  --money: #17ad74;
  --money-soft: rgba(23, 173, 116, 0.14);

  --cat-business: #17ad74;
  --cat-personal: #3987e5;

  --hero-glow-a: rgba(169, 123, 255, 0.16);
  --hero-glow-b: rgba(122, 31, 224, 0.2);
  --hero-grid: rgba(238, 241, 248, 0.055);
  --shadow-1: none;
  --shadow-2: none;
  color-scheme: dark;
}

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

html {
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

h1,
h2,
h3 {
  margin: 0;
  letter-spacing: -0.025em;
  text-wrap: balance;
  line-height: 1.1;
}

p {
  margin: 0;
  text-wrap: pretty;
}

a {
  color: inherit;
}

::selection {
  background: var(--accent);
  color: var(--accent-ink);
}

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

.wrap {
  width: 100%;
  max-width: 1120px;
  margin: 0 auto;
  padding-inline: max(20px, env(safe-area-inset-left));
}

.num {
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}

.eyebrow {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--accent);
}

/* ---------- controls ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 46px;
  padding: 0 20px;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 15px;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  transition:
    background 150ms ease-out,
    border-color 150ms ease-out,
    transform 100ms ease-out;
}
.btn:hover {
  background: var(--surface-2);
}
.btn:active {
  transform: translateY(1px);
}
.btn-primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
  box-shadow: var(--shadow-2);
}
.btn-primary:hover {
  background: var(--accent);
  filter: brightness(1.06);
}
.btn-sm {
  height: 38px;
  padding: 0 14px;
  font-size: 14px;
}
.btn-ghost {
  background: transparent;
  border-color: transparent;
}
.btn-ghost:hover {
  background: var(--surface-2);
}

/* Store badges — the stores' own artwork, self-hosted and unmodified. These are
   the one place on the page that isn't drawn in the site's idiom, because both
   badges are trademarked assets with published rules: don't redraw, don't
   recolour, don't crop, and leave clear space around them.

   The two ship differently, which is why their boxes differ. Google's PNG
   carries its clear space inside the canvas — 41px around a 168px badge, its
   own quarter-of-the-height rule — so an 80px-tall box renders a 54px badge.
   Apple's SVG is edge-to-edge at 119.66x40, so 54px tall is 54px of badge and
   the clear space has to be margin. Both carry a grey outline of their own, so
   neither needs help to stay legible on the dark theme. */
.store-badges {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  margin-top: 16px;
}
.store-badge {
  display: inline-flex;
  text-decoration: none;
  transition:
    opacity 150ms ease-out,
    transform 100ms ease-out;
}
.store-badge:hover {
  opacity: 0.88;
}
.store-badge:active {
  transform: translateY(1px);
}
.store-badge img {
  display: block;
  height: auto;
  max-width: 100%;
}
/* Apple asks for clear space of at least 10% of the badge height; at 54px that
   is 5.4px, and the flex gap alone would only cover one side. */
.store-badge-apple {
  margin: 6px;
}

/* ---------- nav ---------- */

.nav {
  position: sticky;
  top: 0;
  z-index: 50;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid transparent;
  transition: border-color 200ms ease-out;
  padding-top: env(safe-area-inset-top);
}
.nav[data-stuck='true'] {
  border-bottom-color: var(--border);
}
.nav-inner {
  display: flex;
  align-items: center;
  gap: 16px;
  height: 62px;
}
.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  font-weight: 700;
  font-size: 15px;
  letter-spacing: -0.01em;
  text-decoration: none;
  min-width: 0;
}
.brand svg {
  flex: none;
}
.nav-links {
  display: none;
  gap: 4px;
  margin-inline-start: auto;
}
.nav-links a {
  padding: 8px 12px;
  border-radius: 8px;
  font-size: 14px;
  font-weight: 550;
  color: var(--ink-2);
  text-decoration: none;
  transition: color 150ms ease-out, background 150ms ease-out;
}
.nav-links a:hover {
  color: var(--ink);
  background: var(--surface-2);
}
.nav-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-inline-start: auto;
}
.nav-links + .nav-actions {
  margin-inline-start: 0;
}
@media (min-width: 900px) {
  .nav-links {
    display: flex;
  }
}

/* ---------- hero: the instrument cluster ---------- */

.hero {
  position: relative;
  /* Isolated so the two backdrop layers below can sit at z-index -1 — behind
     the copy, still in front of the page. Clipped so the drifting field never
     bleeds into the section underneath. */
  isolation: isolate;
  overflow: hidden;
  padding: clamp(48px, 9vw, 104px) 0 clamp(40px, 6vw, 72px);
}

/* Layer 1 — the ruled page. A logbook is squared paper, so the hero is drawn
   on some: a 1px grid, masked to an ellipse so it fades out rather than ending
   at an edge. Static; this is the paper, not the weather. */
.hero::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image:
    linear-gradient(to right, var(--hero-grid) 1px, transparent 1px),
    linear-gradient(to bottom, var(--hero-grid) 1px, transparent 1px);
  background-size: 68px 68px;
  -webkit-mask-image: radial-gradient(ellipse 78% 68% at 50% 34%, #000 32%, transparent 76%);
  mask-image: radial-gradient(ellipse 78% 68% at 50% 34%, #000 32%, transparent 76%);
  pointer-events: none;
}

/* Layer 2 — two fields of violet that drift across it on a 38s loop. Slow
   enough to read as light changing rather than as an animation playing: the
   page never announces the movement, you just notice it isn't static.
   Transform-only, so it composites on the GPU and never repaints the grid. */
.hero::before {
  content: '';
  position: absolute;
  inset: -35% -25%;
  z-index: -1;
  background:
    radial-gradient(38% 44% at 24% 30%, var(--hero-glow-a), transparent 70%),
    radial-gradient(34% 40% at 76% 16%, var(--hero-glow-b), transparent 68%);
  animation: hero-drift 38s ease-in-out infinite alternate;
  will-change: transform;
  pointer-events: none;
}

@keyframes hero-drift {
  from {
    transform: translate3d(-2.5%, -1.5%, 0) scale(1);
  }
  to {
    transform: translate3d(3.5%, 2.5%, 0) scale(1.14);
  }
}
.hero-grid {
  position: relative;
  display: grid;
  gap: clamp(32px, 5vw, 56px);
  align-items: center;
}
@media (min-width: 980px) {
  .hero-grid {
    grid-template-columns: 1.05fr 1fr;
  }
}
.hero h1 {
  font-size: clamp(38px, 6.4vw, 66px);
  font-weight: 700;
}
.hero .lede {
  margin-top: 18px;
  max-width: 46ch;
  font-size: clamp(16px, 1.6vw, 18.5px);
  color: var(--ink-2);
}
.hero-actions {
  margin-top: 28px;
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}
.hero-note {
  margin-top: 14px;
  font-size: 13px;
  color: var(--ink-3);
}

/* The cluster itself */
.cluster {
  border: 1px solid var(--border);
  border-radius: 16px;
  background: var(--surface);
  box-shadow: var(--shadow-2);
  overflow: hidden;
}
.cluster-top {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 20px;
  padding: 22px 22px 18px;
}
.readout-label {
  font-size: 11.5px;
  font-weight: 500;
  color: var(--ink-3);
  margin-top: 6px;
}
.odo-value {
  display: flex;
  align-items: baseline;
  gap: 6px;
  font-size: clamp(34px, 5vw, 46px);
  font-weight: 700;
  line-height: 1;
}
.odo-value .unit {
  font-size: 15px;
  font-weight: 500;
  color: var(--ink-3);
}
.claim-value {
  font-size: clamp(26px, 3.4vw, 32px);
  font-weight: 700;
  line-height: 1;
  color: var(--money);
}

/* Odometer digit roll */
.odo {
  display: inline-flex;
  overflow: hidden;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}
.odo-cell {
  height: 1.05em;
  overflow: hidden;
}
.odo-strip {
  display: flex;
  flex-direction: column;
  transition: transform 900ms cubic-bezier(0.2, 0.7, 0.3, 1);
}
.odo-strip > span {
  height: 1.05em;
  line-height: 1.05em;
  text-align: center;
}

.ratio {
  display: flex;
  height: 10px;
  gap: 2px;
  margin: 0 22px;
  border-radius: 999px;
  overflow: hidden;
  /* Wipes in on transform, never on width: no layout thrash mid-animation. */
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 900ms cubic-bezier(0.2, 0.7, 0.3, 1);
}
.cluster[data-shown='true'] .ratio {
  transform: scaleX(1);
}
.ratio-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  padding: 10px 22px 16px;
  font-size: 11.5px;
  font-weight: 500;
  color: var(--ink-2);
}
.ratio-legend b {
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}
.dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 999px;
  margin-inline-end: 6px;
}

/* Trip rows — the product's list-item signature */
.rows {
  border-top: 1px solid var(--border);
}
.row {
  display: flex;
  gap: 12px;
  padding: 13px 22px;
  border-bottom: 1px solid var(--border);
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 400ms ease-out, transform 400ms cubic-bezier(0.2, 0.7, 0.3, 1);
}
.row:last-child {
  border-bottom: 0;
}
.row[data-shown='true'] {
  opacity: 1;
  transform: none;
}
.glyph {
  display: flex;
  flex-direction: column;
  align-items: center;
  align-self: stretch;
  width: 10px;
  padding: 5px 0;
  flex: none;
}
.glyph::before,
.glyph::after {
  content: '';
  width: 7px;
  height: 7px;
  border-radius: 999px;
  border: 2px solid var(--ink-3);
  flex: none;
}
.glyph::after {
  border-color: var(--glyph, var(--ink-3));
  background: var(--glyph, var(--ink-3));
  transition: border-color 500ms ease-out, background 500ms ease-out;
}
.glyph i {
  flex: 1;
  width: 2px;
  min-height: 10px;
  margin: 3px 0;
  border-radius: 2px;
  background: var(--border);
}
.row-main {
  flex: 1;
  min-width: 0;
}
.row-top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}
.row-route {
  font-size: 13.5px;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.row-route .arrow {
  color: var(--ink-3);
  font-weight: 400;
}
.row-km {
  font-size: 13px;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
  flex: none;
}
.row-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 3px;
  font-size: 12px;
  color: var(--ink-3);
}
.pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 21px;
  padding: 0 9px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  margin-inline-start: auto;
  flex: none;
  opacity: 0;
  transform: scale(0.9);
  transition: opacity 350ms ease-out, transform 350ms cubic-bezier(0.2, 0.7, 0.3, 1);
}
.row[data-classified='true'] .pill {
  opacity: 1;
  transform: none;
}

/* Confidence dial */
.dial {
  position: relative;
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  flex: none;
}
.dial svg {
  transform: rotate(-90deg);
}
.dial circle {
  fill: none;
  stroke-width: 3.5;
  stroke-linecap: round;
}
.dial .track {
  stroke: var(--surface-2);
}
.dial .value {
  stroke: var(--glyph, var(--accent));
  stroke-dasharray: 113;
  stroke-dashoffset: 113;
  transition: stroke-dashoffset 900ms cubic-bezier(0.2, 0.7, 0.3, 1);
}
.dial b {
  position: absolute;
  font-size: 11px;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
  color: var(--glyph, var(--accent));
}

.cluster-foot {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 13px 22px;
  border-top: 1px solid var(--border);
  background: var(--surface-2);
  font-size: 12.5px;
  color: var(--ink-2);
}

/* ---------- generic sections ---------- */

.section {
  padding: clamp(56px, 8vw, 104px) 0;
  border-top: 1px solid var(--border);
}
.section-head {
  max-width: 62ch;
}
.section-head h2 {
  margin-top: 12px;
  font-size: clamp(27px, 3.8vw, 40px);
  font-weight: 700;
}
.section-head p {
  margin-top: 14px;
  font-size: clamp(15px, 1.5vw, 17px);
  color: var(--ink-2);
}

.features {
  display: grid;
  gap: 20px;
  margin-top: 44px;
}
@media (min-width: 720px) {
  .features {
    grid-template-columns: repeat(2, 1fr);
  }
}
@media (min-width: 1040px) {
  .features {
    grid-template-columns: repeat(3, 1fr);
  }
}
.feature {
  padding: 22px;
  border: 1px solid var(--border);
  border-radius: 14px;
  background: var(--surface);
  box-shadow: var(--shadow-1);
}
.feature h3 {
  font-size: 16.5px;
  font-weight: 650;
  letter-spacing: -0.01em;
}
.feature p {
  margin-top: 8px;
  font-size: 14px;
  color: var(--ink-2);
}
.feature .icon {
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  margin-bottom: 14px;
  border-radius: 10px;
  background: var(--accent-soft);
  color: var(--accent);
}
.feature .icon svg {
  width: 19px;
  height: 19px;
}

/* Receipt + tax split band */
.split {
  display: grid;
  gap: clamp(28px, 4vw, 52px);
  align-items: center;
  margin-top: 44px;
}
@media (min-width: 900px) {
  .split {
    grid-template-columns: 1fr 1fr;
  }
  .split.reverse > *:first-child {
    order: 2;
  }
}
.panel {
  border: 1px solid var(--border);
  border-radius: 14px;
  background: var(--surface);
  box-shadow: var(--shadow-1);
  overflow: hidden;
}
.panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--border);
  font-size: 12.5px;
  font-weight: 650;
  color: var(--ink-2);
}
.kv {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 14px;
  padding: 11px 16px;
  border-bottom: 1px solid var(--border);
  font-size: 13.5px;
}
.kv:last-child {
  border-bottom: 0;
}
.kv span {
  color: var(--ink-2);
}
.kv b {
  font-weight: 650;
  font-variant-numeric: tabular-nums;
}
.kv b.money {
  color: var(--money);
}
.kv b.accent {
  color: var(--accent);
}

/* ---------- the cap meter ----------

   The page's second authored moment, and the only one outside the hero. It
   exists because "capped 5,000 km" is the single line in the tax panel that a
   reader either skims or misunderstands, and it is exactly the line that makes
   the claim defensible. So the bar shows the misunderstanding first — it runs
   out to all 7,806 km you drove — and then retracts to the 5,000 the method
   actually allows, leaving the excess behind as a hatched ghost.

   Everything animates on transform, never width: the track's geometry is fixed
   and only scaleX changes, so the row never reflows mid-sequence. */
.cap {
  padding: 16px 16px 14px;
  border-bottom: 1px solid var(--border);
}
.cap-track {
  position: relative;
  height: 12px;
  border-radius: 999px;
  background: var(--surface-2);
  overflow: hidden;
}
/* The meter's default is its FINISHED state, and main.js winds it back to zero
   only in the same breath as it starts watching. An unrun sequence therefore
   leaves a complete, readable meter rather than an empty track. */
.cap-driven,
.cap-counted {
  position: absolute;
  inset: 0;
  transform-origin: left center;
  transform: scaleX(1);
  border-radius: 999px;
}
.cap[data-watching] .cap-driven,
.cap[data-watching] .cap-counted {
  transform: scaleX(0);
}
/* The full distance driven, drawn as a hatch so it reads as measured-but-not-
   counted the moment the counted bar lands on top of it. */
.cap-driven {
  background-image: repeating-linear-gradient(
    -45deg,
    var(--ink-3) 0 3px,
    transparent 3px 7px
  );
  opacity: 0.55;
  transition: transform 820ms cubic-bezier(0.16, 1, 0.3, 1);
}
/* 5,000 of 7,806 km = 64.05%. The counted bar carries the money green, because
   this is the part that is worth something. */
.cap-counted {
  right: 35.95%;
  background: var(--money);
  transition: transform 720ms cubic-bezier(0.16, 1, 0.3, 1);
}
.cap[data-phase='driven'] .cap-driven,
.cap[data-phase='counted'] .cap-driven {
  transform: scaleX(1);
}
.cap[data-phase='counted'] .cap-counted {
  transform: scaleX(1);
}
.cap-line {
  position: absolute;
  top: -3px;
  bottom: -3px;
  left: 64.05%;
  width: 2px;
  border-radius: 2px;
  background: var(--ink);
  opacity: 1;
  transition:
    opacity 240ms ease-out,
    transform 380ms cubic-bezier(0.16, 1, 0.3, 1);
}
.cap[data-watching] .cap-line {
  opacity: 0;
  transform: scaleY(0.4);
}
.cap[data-phase='driven'] .cap-line,
.cap[data-phase='counted'] .cap-line {
  opacity: 1;
  transform: none;
}
.cap-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  margin-top: 10px;
  font-size: 11.5px;
  font-weight: 500;
  color: var(--ink-2);
}
.cap-key {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  transition: opacity 300ms ease-out;
}
.cap[data-watching] .cap-key {
  opacity: 0;
}
.cap[data-phase='counted'] .cap-key {
  opacity: 1;
}
.cap-key-over {
  transition-delay: 90ms;
}
.cap-key i {
  width: 8px;
  height: 8px;
  border-radius: 2px;
  flex: none;
}
.cap-key-counted i {
  background: var(--money);
}
.cap-key-over i {
  background-image: repeating-linear-gradient(
    -45deg,
    var(--ink-3) 0 2px,
    transparent 2px 4px
  );
  outline: 1px solid var(--border);
}
.split-title {
  font-size: clamp(23px, 2.9vw, 29px);
  font-weight: 650;
  letter-spacing: -0.02em;
}
.split-lede {
  margin-top: 14px;
  font-size: 15.5px;
  color: var(--ink-2);
}
.fine {
  margin-top: 18px;
  font-size: 12.5px;
  color: var(--ink-3);
}

.list {
  margin: 22px 0 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 12px;
}
.list li {
  display: flex;
  gap: 10px;
  font-size: 14.5px;
  color: var(--ink-2);
}
.list svg {
  flex: none;
  margin-top: 3px;
  color: var(--accent);
}

/* Countries */
.countries {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 22px;
}
.chip {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 7px 12px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  font-size: 13px;
  font-weight: 550;
}
.chip small {
  color: var(--ink-3);
  font-weight: 500;
}

/* ---------- pricing ---------- */

.plans {
  display: grid;
  gap: 20px;
  margin-top: 44px;
  align-items: start;
}
@media (min-width: 900px) {
  .plans {
    grid-template-columns: repeat(3, 1fr);
  }
}
.plan {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: 26px 22px;
  border: 1px solid var(--border);
  border-radius: 16px;
  background: var(--surface);
  box-shadow: var(--shadow-1);
}
.plan[data-featured='true'] {
  border-color: var(--accent);
  box-shadow: var(--shadow-2);
}
.plan-badge {
  position: absolute;
  top: -11px;
  left: 22px;
  padding: 3px 10px;
  border-radius: 999px;
  background: var(--accent);
  color: var(--accent-ink);
  font-size: 11px;
  font-weight: 650;
  letter-spacing: 0.02em;
}
.plan h3 {
  font-size: 17px;
  font-weight: 650;
}
.plan .price {
  display: flex;
  align-items: baseline;
  gap: 5px;
  margin-top: 14px;
  font-size: 38px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.03em;
}
.plan .price small {
  font-size: 14px;
  font-weight: 500;
  color: var(--ink-3);
  letter-spacing: 0;
}
.plan .who {
  margin-top: 8px;
  font-size: 13.5px;
  color: var(--ink-2);
  min-height: 40px;
}
.plan .btn {
  margin-top: 20px;
  width: 100%;
}
.plan ul {
  margin: 22px 0 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 11px;
  border-top: 1px solid var(--border);
  padding-top: 20px;
}
.plan li {
  display: flex;
  gap: 9px;
  font-size: 13.8px;
  color: var(--ink-2);
}
.plan li svg {
  flex: none;
  margin-top: 3px;
  color: var(--accent);
}
.soon {
  display: inline-block;
  margin-inline-start: 6px;
  padding: 1px 6px;
  border-radius: 999px;
  border: 1px solid var(--border);
  font-size: 10.5px;
  font-weight: 600;
  color: var(--ink-3);
  vertical-align: 1px;
}
.price-note {
  margin-top: 22px;
  font-size: 13px;
  color: var(--ink-3);
  max-width: 62ch;
}

/* ---------- faq ---------- */

.faq {
  margin-top: 40px;
  display: grid;
  gap: 0;
  border-top: 1px solid var(--border);
}
.faq details {
  border-bottom: 1px solid var(--border);
}
.faq summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 18px 0;
  font-size: 15.5px;
  font-weight: 600;
  cursor: pointer;
  list-style: none;
}
.faq summary::-webkit-details-marker {
  display: none;
}
.faq summary::after {
  content: '';
  flex: none;
  width: 10px;
  height: 10px;
  border-right: 2px solid var(--ink-3);
  border-bottom: 2px solid var(--ink-3);
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform 200ms cubic-bezier(0.2, 0.7, 0.3, 1);
}
.faq details[open] summary::after {
  transform: rotate(-135deg) translate(-3px, -3px);
}
/* While closing, `open` is still set so the body can animate its height down.
   The chevron should not wait for that — it answers the click immediately. */
.faq details[data-animating='closing'] summary::after {
  transform: rotate(45deg) translate(-2px, -2px);
}
.faq p {
  padding: 0 0 20px;
  max-width: 72ch;
  font-size: 14.5px;
  color: var(--ink-2);
}
/* An answer opens by making room for itself rather than appearing at full
   height, so the questions below are pushed rather than jumped.

   The row runs 0fr → 1fr rather than 0 → height: the intrinsic keyword means
   the browser resolves the open size itself, so nothing has to measure
   scrollHeight or force a synchronous reflow to find a start value. `open`
   stays set for the length of a close (a closed <details> renders nothing to
   animate), and JS clears it when the transition lands.

   `.faq-body` is unstyled without `.js`, which is what a browser with no
   script gets: the answer, open, in place. */
.js .faq-body {
  display: grid;
  grid-template-rows: 1fr;
}
/* `open` remains the truth for the open size, so a details opened by anything
   other than a click — find-in-page, a hash link, reduced-motion falling
   through to the native toggle — is rendered at full height without help.
   `data-collapsed` is set only for the frames an animation is running. */
.js .faq details:not([open]) .faq-body,
.js .faq details[data-collapsed] .faq-body {
  grid-template-rows: 0fr;
}
.js .faq-body > * {
  min-height: 0;
  overflow: hidden;
}
.js .faq details[data-animating] .faq-body {
  transition: grid-template-rows 300ms cubic-bezier(0.16, 1, 0.3, 1);
}

/* ---------- close ---------- */

.close-cta {
  margin: clamp(56px, 8vw, 96px) 0;
  padding: clamp(36px, 6vw, 64px) clamp(24px, 5vw, 56px);
  border: 1px solid var(--border);
  border-radius: 20px;
  background: var(--surface);
  box-shadow: var(--shadow-2);
  text-align: center;
}
.close-cta h2 {
  font-size: clamp(26px, 3.6vw, 38px);
  font-weight: 700;
}
.close-cta p {
  margin: 14px auto 0;
  max-width: 52ch;
  color: var(--ink-2);
}
.close-cta .hero-actions {
  justify-content: center;
}
.close-cta .store-badges {
  justify-content: center;
}

footer {
  border-top: 1px solid var(--border);
  padding: 36px 0 calc(36px + env(safe-area-inset-bottom));
  font-size: 13.5px;
  color: var(--ink-3);
}
.foot-inner {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  align-items: center;
  justify-content: space-between;
}
.foot-links {
  display: flex;
  flex-wrap: wrap;
  gap: 18px;
}
.foot-links a {
  color: var(--ink-2);
  text-decoration: none;
}
.foot-links a:hover {
  color: var(--ink);
}

/* ---------- motion ----------

   Two entrances, and they mean different things. A heading is *printed* — it
   wipes down under its own baseline, because a logbook is written onto paper.
   A list *arrives* — the feature grid staggers, once, capped. Panels, plans and
   the FAQ get nothing at all: they are evidence you scrolled to read, and
   evidence that fades up on approach reads as a slideshow.

   Entrances are gated on `data-watching`, which main.js sets on an element in
   the same statement that starts observing it. That is deliberately narrower
   than a `html.js` class: the class is written by the inline head script, so it
   survives main.js being stale, cached, broken or 404, and content gated on it
   stays invisible forever. An element can only be hidden here by the code that
   is already holding the handle to reveal it. */

.reveal[data-watching] {
  opacity: 0;
  /* Wipe from the top edge so the text appears to be written, not to fly in.
     Paired with a 4px lift so it settles rather than simply uncovering. */
  clip-path: inset(-2px -2px 100% -2px);
  transform: translateY(4px);
  transition:
    opacity 260ms ease-out,
    clip-path 380ms cubic-bezier(0.16, 1, 0.3, 1),
    transform 380ms cubic-bezier(0.16, 1, 0.3, 1);
}
.reveal[data-shown='true'] {
  opacity: 1;
  clip-path: inset(-2px -2px -2px -2px);
  transform: none;
}
/* The closing card is the one .reveal that is not a block of text. A wipe would
   crop its shadow and cut across its border radius, so it only lifts. */
.close-cta.reveal[data-watching] {
  clip-path: none;
  transform: translateY(10px);
}
.close-cta.reveal[data-shown='true'] {
  clip-path: none;
  transform: none;
}

/* The feature grid is the one place a stagger is honest: six peers, read as a
   set. Delay is per-item and capped at the sixth so the last card never waits
   on a queue the eye has already finished scanning. */
.features[data-watching] .feature {
  opacity: 0;
  transform: translateY(10px);
  transition:
    opacity 320ms ease-out,
    transform 420ms cubic-bezier(0.16, 1, 0.3, 1);
}
.features[data-watching] .feature:nth-child(2) {
  transition-delay: 60ms;
}
.features[data-watching] .feature:nth-child(3) {
  transition-delay: 120ms;
}
.features[data-watching] .feature:nth-child(4) {
  transition-delay: 180ms;
}
.features[data-watching] .feature:nth-child(5) {
  transition-delay: 240ms;
}
.features[data-watching] .feature:nth-child(n + 6) {
  transition-delay: 300ms;
}
.features[data-shown='true'] .feature {
  opacity: 1;
  transform: none;
}

/* Theme swap. The transition is attached only for the ~320ms of the swap, so
   the page carries no colour transition while scrolling or on first paint —
   where it would fight the entrances and cost a repaint on every hover. */
.theming,
.theming * {
  transition:
    background-color 280ms ease,
    border-color 280ms ease,
    color 280ms ease,
    fill 280ms ease,
    stroke 280ms ease !important;
}
#theme svg {
  transition: transform 420ms cubic-bezier(0.16, 1, 0.3, 1);
}
#theme[data-spun='true'] svg {
  transform: rotate(180deg);
}

/* Paper has no scroll, so an entrance waiting on an intersection that will
   never happen prints blank — five empty sections, on the page a driver is most
   likely to hand to an accountant. Print takes the finished state of
   everything. The same rules make the page render whole in any headless
   capture that does not scroll. */
@media print {
  .reveal,
  .features .feature,
  .row,
  .ratio,
  .pill,
  .cap-line,
  .cap-key {
    opacity: 1 !important;
    transform: none !important;
    clip-path: none !important;
  }
  .cap-driven,
  .cap-counted {
    transform: scaleX(1) !important;
  }
  .js .faq-body {
    grid-template-rows: 1fr !important;
  }
  .hero::before {
    animation: none !important;
  }
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  .reveal,
  .features .feature,
  .row,
  .ratio {
    opacity: 1 !important;
    transform: none !important;
    clip-path: none !important;
    transition: none !important;
  }
  .odo-strip,
  .dial .value,
  .ratio span,
  .pill,
  .cap-driven,
  .cap-counted,
  .cap-line,
  #theme svg,
  .faq-body {
    transition: none !important;
  }
  .theming,
  .theming * {
    transition: none !important;
  }
  .pill {
    opacity: 1 !important;
    transform: none !important;
  }
  /* The hero keeps its colour, loses its drift — the field is composition, the
     movement is decoration, and only the decoration is what was opted out of. */
  .hero::before {
    animation: none !important;
    transform: translate3d(0, 0, 0) scale(1.06);
  }
}
