/* Self-hosted fonts, the reference site's own pairing (extracted from its
   published stylesheet): Lora for display headings, Inter for body copy,
   nav and buttons. Both SIL OFL 1.1, both variable fonts (one file each
   covers every weight we use), both served from our own /fonts/
   directory, never a CDN. Latin-only subset (Basic Latin + Latin-1
   Supplement, which covers every accented French character we use:
   é è ê ë à â ù û ô î ï ç œ, plus €), since the page is French-only and
   the other Google-served subsets (Cyrillic, Greek, Vietnamese, latin-ext,
   math, symbols) would just be dead weight on a mobile ad click.
   See site/fonts/OFL-Lora.txt and site/fonts/OFL-Inter.txt. */
@font-face {
  font-family: "Lora";
  src: url("/fonts/lora-variable.woff2") format("woff2");
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("/fonts/inter-variable.woff2") format("woff2");
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
}

/* ---------------------------------------------------------------------------
   Tokens

   Two registers, alternating down the page: light editorial (white / very
   pale blue, dark text) and night (near-black, white text, green energy).
   The green is the *charge* colour: it fills gauges, marks the donor side of
   a transfer, and prints the figures on the dark band. It is never a button
   fill, white-on-green only clears AA at large-text sizes, and a page whose
   every call to action is a bright green pill is exactly the generic look
   this design is running away from. Primary buttons are ink on light, white
   on dark: unambiguous, and the highest-contrast pairing available.

   Amber is the *empty* colour, used only where something is running out (the
   receiving car, its calipers, the timeline clock).
--------------------------------------------------------------------------- */
:root {
  --bg: #ffffff;
  --bg-soft: #f2f5f8;        /* cool, faintly blue, the reference's mood */
  --ink: #0b0f11;            /* near-black: text, and the primary button fill */
  --ink-soft: #23292c;       /* button hover */
  --text-muted: #566069;     /* 6.4:1 on white */
  --accent: #cbe800;         /* Porsche acid green: fills, gauges, graphics, CTA (ink text on it ≈15:1) */
  --accent-text: #5e7000;    /* dark lime, legible green text on white (~5.5:1); acid green would vanish */
  --accent-bright: #cbe800;  /* acid green on night surfaces (pops on black) */
  --amber: #b45309;          /* 5.0:1 on white */
  --amber-bright: #f59e0b;   /* on night surfaces only */
  --amber-soft: #fff1de;
  --danger: #a3271e;
  --night: #0b0f11;
  --night-2: #141a1d;
  --line: rgba(11, 15, 17, 0.1);
  --line-night: rgba(255, 255, 255, 0.14);
  --shadow-sm: 0 1px 2px rgba(15, 25, 35, 0.05), 0 6px 16px rgba(15, 25, 35, 0.04);
  --shadow-md: 0 2px 6px rgba(15, 25, 35, 0.05), 0 18px 44px rgba(15, 25, 35, 0.07);
  --shadow-lg: 0 10px 24px rgba(11, 20, 28, 0.1), 0 40px 80px rgba(11, 20, 28, 0.16);
  --radius: 24px;
  --radius-sm: 14px;
  --radius-xl: 32px;
  --container: 1120px;
  --step: clamp(5rem, 11vw, 9rem);
  --font-sans: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-serif: "Lora", Georgia, "Times New Roman", serif;
  --font-mono: ui-monospace, "SF Mono", "SFMono-Regular", Menlo, Consolas, "Liberation Mono", monospace;
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
}

* { box-sizing: border-box; }

@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

[id] { scroll-margin-top: 104px; }

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: 1.0625rem;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  /* `clip`, not `hidden`, hidden creates a new scroll container which
     breaks `position: sticky` (the nav, the showcase stage) anywhere it's
     nested under body. `clip` still hard-contains any stray horizontal
     overflow without establishing a scroll container. */
  overflow-x: clip;
}

h1, h2, h3 { margin: 0 0 0.5em; color: inherit; }
h1, h2 {
  font-family: var(--font-serif);
  font-weight: 500;
  line-height: 1.04;
  letter-spacing: -0.03em;
  text-wrap: balance;
}
h2 { font-size: clamp(2rem, 4.4vw, 3.25rem); }
h3 {
  font-family: var(--font-serif);
  font-weight: 600;
  font-size: 1.375rem;
  line-height: 1.2;
  letter-spacing: -0.02em;
}
p { margin: 0 0 1rem; max-width: 62ch; }
a { color: var(--accent-text); }

.container {
  width: 100%;
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 1.5rem;
}

.section { padding: var(--step) 0; }
.section--soft { background: var(--bg-soft); }

.lead {
  font-size: 1.1875rem;
  line-height: 1.55;
  color: var(--text-muted);
  max-width: 48ch;
  margin-top: 1.25rem;
}
.lead--center { margin-left: auto; margin-right: auto; text-align: center; }

/* Small uppercase label above a heading. Deliberately rare: four instances on
   the whole page (the showcase blocks), where they carry a real "which of the
   four is this" wayfinding job. Every other section leads with its heading. */
.tag {
  display: inline-block;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent-text);
  margin-bottom: 0.75rem;
}

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ---------------------------------------------------------------------------
   Scroll-triggered entrance animations

   Base state: every element fully visible, no transform. That's what
   prefers-reduced-motion:reduce users get, and what everyone gets before the
   IntersectionObserver in src/browser/reveal.ts has run, nothing is ever
   stuck at opacity:0.
--------------------------------------------------------------------------- */
.reveal, .reveal-scale { opacity: 1; transform: none; }

@media (prefers-reduced-motion: no-preference) {
  .reveal {
    opacity: 0;
    transform: translateY(26px);
    transition: opacity 0.7s var(--ease), transform 0.7s var(--ease);
  }
  .reveal.is-visible { opacity: 1; transform: none; }

  .reveal-scale {
    opacity: 0;
    transform: translateY(32px) scale(0.97);
    transition: opacity 0.8s var(--ease), transform 0.8s var(--ease);
  }
  .reveal-scale.is-visible { opacity: 1; transform: none; }

  /* Cards that sit side by side rise with a small stagger rather than in
     perfect lockstep. `:nth-child(2n)` works because each use site is a flat
     row of direct-child cards. */
  .reveal--pair { transition-duration: 0.9s; }
  .reveal--pair:nth-child(2) { transition-delay: 0.08s; }
  .reveal--pair:nth-child(3) { transition-delay: 0.16s; }
  .reveal--pair:nth-child(4) { transition-delay: 0.24s; }
}

/* ---------------------------------------------------------------------------
   State-of-charge scroll indicator
--------------------------------------------------------------------------- */
.charge {
  position: fixed;
  top: 0; left: 0; right: 0;
  height: 3px;
  z-index: 40;
  background: rgba(11, 15, 17, 0.08);
  pointer-events: none;
}
.charge__bar {
  display: block;
  height: 100%;
  width: 100%;
  transform: scaleX(0.04);
  transform-origin: left center;
  background: linear-gradient(90deg, var(--amber-bright) 0%, var(--accent) 55%, var(--accent) 100%);
  transition: transform 0.12s linear;
}

/* ---------------------------------------------------------------------------
   Buttons, pill shaped, three registers.
   .btn--primary  ink on light backgrounds   (white on #0b0f11, 17:1)
   .btn--light    white on dark/photo        (ink on white, 17:1)
   .btn--ghost    hairline on dark/photo     (white text, white border)
--------------------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.9rem 1.6rem;
  border-radius: 999px;
  border: 1px solid transparent;
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-size: 1.0625rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;
  transition: transform 0.2s var(--ease), background 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
}
.btn--primary {
  background: var(--ink);
  color: #fff;
  box-shadow: 0 1px 2px rgba(11, 15, 17, 0.18), 0 8px 22px rgba(11, 15, 17, 0.14);
}
.btn--primary:hover { background: var(--ink-soft); transform: translateY(-2px); box-shadow: 0 2px 4px rgba(11, 15, 17, 0.2), 0 14px 30px rgba(11, 15, 17, 0.2); }
.btn--light {
  background: #fff;
  color: var(--ink);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.14), 0 10px 30px rgba(0, 0, 0, 0.18);
}
.btn--light:hover { transform: translateY(-2px); box-shadow: 0 2px 6px rgba(0, 0, 0, 0.18), 0 16px 36px rgba(0, 0, 0, 0.24); }
.btn--ghost {
  color: #fff;
  border-color: rgba(255, 255, 255, 0.55);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
}
.btn--ghost:hover { border-color: #fff; background: rgba(255, 255, 255, 0.12); transform: translateY(-2px); }
.btn--sm { padding: 0.6rem 1.15rem; font-size: 0.9375rem; }
.btn--lg { padding: 1.1rem 2.2rem; font-size: 1.1875rem; }
.btn:disabled { opacity: 0.45; cursor: not-allowed; transform: none; }

/* Primary conversion CTA, the "Tester ma voiture" button is the whole point of
   the page (collect signups), so it gets the brand's vivid green with a soft
   green glow to stand out on any background. Dark ink text keeps it AA at every
   size (ink on #cbe800 ≈ 6.8:1). Targeted by the shared data attribute so
   every CTA button matches regardless of its other btn-* classes; the
   0,2,x specificity outranks .btn--primary / .btn--light. */
.btn[data-eligibilite-open] {
  background: var(--accent);
  color: var(--ink);
  border-color: var(--accent);
  font-weight: 700;
  box-shadow: 0 1px 2px rgba(11, 15, 17, 0.12), 0 10px 26px rgba(203, 232, 0, 0.4);
}
.btn[data-eligibilite-open]:hover {
  background: var(--accent-bright);
  border-color: var(--accent-bright);
  transform: translateY(-2px);
  box-shadow: 0 2px 4px rgba(11, 15, 17, 0.14), 0 16px 36px rgba(203, 232, 0, 0.55);
}
/* Same acid CTA as above, for pages where the trigger is a plain link (region
   pages) rather than the modal button. */
.btn--cta {
  background: var(--accent);
  color: var(--ink);
  border-color: var(--accent);
  font-weight: 700;
  box-shadow: 0 1px 2px rgba(11, 15, 17, 0.12), 0 10px 26px rgba(203, 232, 0, 0.4);
}
.btn--cta:hover {
  background: var(--accent-bright);
  border-color: var(--accent-bright);
  transform: translateY(-2px);
  box-shadow: 0 2px 4px rgba(11, 15, 17, 0.14), 0 16px 36px rgba(203, 232, 0, 0.55);
}

/* ---------------------------------------------------------------------------
   Navigation, fixed, transparent header. Wordmark pill top-left (with the
   live charge readout), links + CTA in a floating pill, centred.
--------------------------------------------------------------------------- */
.nav {
  position: fixed;
  top: 3px;
  left: 0;
  right: 0;
  z-index: 30;
  padding: 1.1rem 0;
  pointer-events: none;
}
.nav__row {
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
}
/* Mobile scroll glitch fix, .nav__brand/.nav__inner are position:fixed AND
   carry backdrop-filter, which stays on screen for the whole page scroll.
   Fixed elements with a live backdrop-filter are the textbook case of mobile
   Safari's repaint bug: the blur has to be recomposited against newly
   scrolled-under content every frame, and WebKit can fail to promote the
   element to its own layer, reading as a flicker at the pill on every scroll
   frame. Forcing a compositing layer up front composites the blur once. */
.nav__brand, .nav__inner { will-change: transform; }
.nav__brand {
  position: absolute;
  left: 1.5rem;
  top: 50%;
  transform: translateY(-50%) translateZ(0);
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  font-weight: 700;
  font-size: 1.0625rem;
  letter-spacing: -0.02em;
  color: var(--ink);
  text-decoration: none;
  background: rgba(255, 255, 255, 0.94);
  border-radius: 999px;
  box-shadow: var(--shadow-md);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  padding: 0.6rem 1.05rem;
  pointer-events: auto;
}
/* The wordmark's charge readout: a small cell that fills as the page scrolls,
   with the percentage beside it. Same battery language as everything else. */
.nav__charge {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding-left: 0.7rem;
  border-left: 1px solid var(--line);
}
.nav__cell {
  position: relative;
  display: block;
  width: 26px;
  height: 13px;
  border: 1.5px solid rgba(11, 15, 17, 0.35);
  border-radius: 4px;
  padding: 1.5px;
}
.nav__cell::after {
  content: "";
  position: absolute;
  right: -4px;
  top: 50%;
  transform: translateY(-50%);
  width: 2.5px;
  height: 5px;
  border-radius: 0 2px 2px 0;
  background: rgba(11, 15, 17, 0.35);
}
.nav__level {
  display: block;
  height: 100%;
  width: 100%;
  border-radius: 1.5px;
  background: var(--accent);
  transform: scaleX(0.04);
  transform-origin: left center;
  transition: transform 0.12s linear;
}
.nav__percent {
  font-size: 0.8125rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
  min-width: 3.1em;
}
.nav__inner {
  margin: 0 auto;
  display: flex;
  align-items: center;
  background: rgba(255, 255, 255, 0.94);
  border-radius: 999px;
  box-shadow: var(--shadow-md);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  padding: 0.45rem 0.45rem 0.45rem 1.4rem;
  pointer-events: auto;
  transform: translateZ(0);
}
.nav__links { display: flex; align-items: center; gap: 1.5rem; }
.nav__links a:not(.btn) {
  color: var(--text-muted);
  text-decoration: none;
  font-size: 0.9375rem;
  font-weight: 500;
  transition: color 0.2s ease;
}
.nav__links a:not(.btn):hover { color: var(--ink); }

@media (max-width: 860px) {
  .nav__charge { display: none; }
}
@media (max-width: 640px) {
  .nav__links a:not(.btn) { display: none; }
  .nav__row { justify-content: space-between; }
  .nav__brand {
    position: static;
    transform: translateZ(0);
    margin-right: auto;
    font-size: 0.9375rem;
    padding: 0.5rem 0.85rem;
  }
  .nav__inner { padding: 0.35rem; }
}

/* ---------------------------------------------------------------------------
   Hero, full-bleed photograph, headline set directly on it in white.

   No frosted card: the photo *is* the hero (site/img/hero-charging-cable.jpg,
   a hand plugging a connector into a car). Legibility comes from a bottom-up
   scrim, which leaves the top two thirds of the frame completely clear and
   only darkens the strip the copy actually sits in. Over the scrim's own
   floor (rgba(6,10,12,0.82) on the photo's lightest region) white text
   measures well past 10:1.
--------------------------------------------------------------------------- */
.hero {
  position: relative;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: 160px 0 clamp(4rem, 9vh, 7rem);
  color: #fff;
  background-image: url("/img/hero-charging-cable.jpg");
  background-size: cover;
  background-position: center 42%;
  background-repeat: no-repeat;
  isolation: isolate;
}
.hero::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(180deg, rgba(6, 10, 12, 0.42) 0%, rgba(6, 10, 12, 0.12) 26%, rgba(6, 10, 12, 0.62) 66%, rgba(6, 10, 12, 0.88) 100%);
}
.hero__inner { text-align: center; }
.hero__title {
  font-family: var(--font-serif);
  font-weight: 500;
  font-size: clamp(2.5rem, 6.4vw, 5.5rem);
  line-height: 1.02;
  letter-spacing: -0.035em;
  margin: 0 0 1.5rem;
  text-shadow: 0 2px 30px rgba(0, 0, 0, 0.35);
}
.hero__title .line { display: block; overflow: hidden; }
.hero__title .line > span { display: block; }
/* Two-colour antithesis: the empty battery reads amber, the full one green, a
   subtle vertical gradient inside each word (background-clip: text). A soft
   dark drop-shadow keeps them legible on the photo, since the transparent text
   fill drops the title's own text-shadow. */
.hero-em {
  font-style: normal;
  background-clip: text;
  -webkit-background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  filter: drop-shadow(0 2px 10px rgba(0, 0, 0, 0.45));
}
.hero-em--empty { background-image: linear-gradient(170deg, #ffcf87 0%, #f7a833 48%, #ef8a12 100%); }
.hero-em--full { background-image: linear-gradient(170deg, #e4ff5c 0%, #cbe800 48%, #a6c400 100%); }
.hero__lead {
  font-size: clamp(1.0625rem, 1.6vw, 1.3125rem);
  line-height: 1.5;
  color: rgba(255, 255, 255, 0.92);
  max-width: 46ch;
  margin: 0 auto;
  text-shadow: 0 1px 20px rgba(0, 0, 0, 0.4);
}
.hero__cta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  justify-content: center;
  margin-top: 2rem;
}
.hero__note {
  margin: 1.25rem auto 0;
  font-size: 0.9375rem;
  color: rgba(255, 255, 255, 0.75);
}
.hero__scroll {
  position: absolute;
  left: 50%;
  bottom: 1.5rem;
  transform: translateX(-50%);
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
}
.hero__scroll span {
  display: block;
  width: 1px;
  height: 22px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 100%);
}
@media (prefers-reduced-motion: no-preference) and (pointer: fine) {
  .hero__scroll span { animation: scroll-hint 2.4s var(--ease) infinite; }
}
@keyframes scroll-hint {
  0% { transform: translateY(-6px) scaleY(0.6); opacity: 0; }
  40% { opacity: 1; }
  100% { transform: translateY(8px) scaleY(1); opacity: 0; }
}

/* Hero entrance: each headline line rises through its own mask, then the
   lead, buttons and note follow. `is-ready` is added on the frame after
   first paint (src/browser/intro.ts); the base state above is the finished
   state, so a reduced-motion visitor and a no-JS visitor both simply see it. */
@media (prefers-reduced-motion: no-preference) {
  .hero[data-intro] .hero__title .line > span,
  .hero[data-intro] .hero__lead,
  .hero[data-intro] .hero__cta,
  .hero[data-intro] .hero__note,
  .hero[data-intro] .hero__scroll {
    opacity: 0;
    transform: translateY(1.1em);
    transition: opacity 0.9s var(--ease), transform 0.9s var(--ease);
  }
  .hero[data-intro] .hero__lead,
  .hero[data-intro] .hero__cta,
  .hero[data-intro] .hero__note,
  .hero[data-intro] .hero__scroll { transform: translateY(16px); }
  .hero[data-intro] .hero__title .line:nth-child(2) > span { transition-delay: 0.1s; }
  .hero[data-intro] .hero__lead { transition-delay: 0.28s; }
  .hero[data-intro] .hero__cta { transition-delay: 0.38s; }
  .hero[data-intro] .hero__note { transition-delay: 0.46s; }
  .hero[data-intro] .hero__scroll { transition-delay: 0.7s; }
  .hero.is-ready .hero__title .line > span,
  .hero.is-ready .hero__lead,
  .hero.is-ready .hero__cta,
  .hero.is-ready .hero__note,
  .hero.is-ready .hero__scroll { opacity: 1; transform: none; }
}

/* ---------------------------------------------------------------------------
   The principle, one statement, then the transfer scene.
--------------------------------------------------------------------------- */
.section--principe { text-align: center; padding-top: clamp(4rem, 8vw, 7rem); }
.display {
  font-size: clamp(2.25rem, 5.6vw, 4.25rem);
  margin: 0 auto;
  max-width: 18ch;
}

/* The scene: a night card holding one SVG (both cars, the ground, the cable)
   with the battery chips and the readout as HTML on top, positioned in
   percentages off the same box so they track the SVG at every width. */
.scene {
  margin: clamp(2.5rem, 6vw, 4.5rem) auto 0;
  max-width: 960px;
}
.scene__stage {
  position: relative;
  border-radius: var(--radius-xl);
  background:
    radial-gradient(120% 90% at 50% 120%, #1d262a 0%, rgba(29, 38, 42, 0) 62%),
    linear-gradient(180deg, #0d1214 0%, #0b0f11 100%);
  box-shadow: var(--shadow-lg);
  padding: clamp(1rem, 3vw, 2rem);
  overflow: hidden;
}
/* A faint sweep of light across the top of the card, so the night surface
   reads as a lit stage rather than a flat black rectangle. */
.scene__stage::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(90% 60% at 50% -10%, rgba(120, 190, 220, 0.16) 0%, rgba(120, 190, 220, 0) 70%);
  pointer-events: none;
}
/* Two real car cutouts, bottom-aligned on a shared ground line, facing each
   other, with the cable SVG stretched across the same box so its coordinates
   track the cars at every width. The aspect-ratio box is what keeps the cable
   endpoints landing on the cars regardless of viewport size. */
.scene__cars {
  position: relative;
  width: 100%;
  aspect-ratio: 900 / 320;
}
.scene__car {
  position: absolute;
  bottom: 8%;
  width: 45%;
  height: auto;
  /* a soft dark ground-shadow so each car sits on the stage rather than
     floating; the cutouts' own baked-in light shadows would otherwise read as
     pale halos on the near-black surface. */
  filter: drop-shadow(0 18px 16px rgba(0, 0, 0, 0.55));
}
.scene__car--donor { left: 0; }
/* Peugeot e-2008 cutout: its frame carries some empty space below the wheels,
   so it's nudged down to sit its wheels on the same ground line as the tighter
   Ioniq 5 crop, and sized so both cars read at a comparable real scale. */
.scene__car--taker { right: 0; width: 44%; transform: translateY(11%); }
.scene__cable-layer {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}

.scene__cable {
  stroke-dasharray: 14 10;
  stroke-dashoffset: 0;
  filter: drop-shadow(0 0 6px rgba(203, 232, 0, 0.45));
}
.scene__spark {
  offset-path: path("M366,196 C420,256 480,256 534,196");
  offset-distance: 0%;
  opacity: 0;
  filter: drop-shadow(0 0 8px rgba(200, 247, 221, 0.9));
}
/* Finite, and only once the scene is actually on screen (`is-live` is added
   by src/browser/transfer.ts). A permanently looping mid-page animation is
   exactly the always-on main-thread cost that made mobile scrolling stutter
   before this rebuild, so nothing here loops forever. */
@media (prefers-reduced-motion: no-preference) {
  .scene.is-live .scene__cable { animation: cable-flow 1.1s linear 4; }
  .scene.is-live .scene__spark { animation: spark-travel 1.4s ease-in-out 3; }
}
@keyframes cable-flow {
  to { stroke-dashoffset: -24; }
}
@keyframes spark-travel {
  0% { offset-distance: 0%; opacity: 0; }
  12% { opacity: 1; }
  88% { opacity: 1; }
  100% { offset-distance: 100%; opacity: 0; }
}

.scene__chip {
  position: absolute;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  min-width: 116px;
  padding: 0.7rem 0.9rem;
  border-radius: var(--radius-sm);
  background: rgba(255, 255, 255, 0.07);
  border: 1px solid var(--line-night);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  text-align: left;
}
.scene__chip--donor { top: 8%; left: 5%; }
.scene__chip--taker { top: 8%; right: 5%; }
.scene__role {
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.7);
}
.scene__pct {
  font-family: var(--font-serif);
  font-size: 1.5rem;
  font-weight: 600;
  line-height: 1;
  color: #fff;
  font-variant-numeric: tabular-nums;
}
.scene__gauge {
  display: block;
  height: 5px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.18);
  overflow: hidden;
}
.scene__fill {
  display: block;
  height: 100%;
  width: 100%;
  border-radius: 999px;
  transform-origin: left center;
  transition: transform 1.3s var(--ease) 0.1s;
}
.scene__fill--donor { background: var(--accent-bright); }
.scene__fill--taker { background: var(--amber-bright); }

.scene__readout {
  position: absolute;
  left: 50%;
  bottom: 12%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 0.5rem 1.1rem;
  border-radius: 999px;
  background: rgba(11, 15, 17, 0.72);
  border: 1px solid var(--line-night);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  white-space: nowrap;
}
.scene__readout-value {
  font-family: var(--font-serif);
  font-size: 1.25rem;
  font-weight: 600;
  line-height: 1.1;
  color: var(--accent-bright);
  font-variant-numeric: tabular-nums;
}
.scene__readout-label {
  font-size: 0.6875rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.6);
}
.scene__caption {
  margin: 1.25rem auto 0;
  max-width: 52ch;
  font-size: 0.875rem;
  color: var(--text-muted);
  text-align: center;
}
@media (max-width: 640px) {
  .scene__chip { min-width: 0; padding: 0.5rem 0.6rem; }
  .scene__chip--donor { left: 3%; }
  .scene__chip--taker { right: 3%; }
  .scene__pct { font-size: 1.125rem; }
  .scene__readout { bottom: 6%; padding: 0.4rem 0.85rem; }
  .scene__readout-value { font-size: 1rem; }
}

/* ---------------------------------------------------------------------------
   Brand marquee, a slow, seamless horizontal scroll of monochrome EV brand
   marks. src/browser/marquee.ts clones the single authored set so the -50%
   loop has no seam.
--------------------------------------------------------------------------- */
.marquee {
  margin-top: clamp(3rem, 7vw, 5rem);
  text-align: center;
}
.marquee__label {
  margin: 0 0 1.75rem;
  max-width: none; /* override the global p { max-width: 62ch } so it centres */
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.marquee__viewport {
  overflow: hidden;
  /* fade both edges so logos slide in and out of nothing rather than being
     hard-clipped at the container edge */
  -webkit-mask: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  mask: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.marquee__track {
  display: flex;
  width: max-content;
}
/* 60s, not 46s: the strip went from 10 hand-drawn marks to 15 real ones, so a
   shorter duration would have sped the scroll up by a third. */
.marquee__track.is-cloned {
  animation: marquee-scroll 60s linear infinite;
}
/* No-JS fallback: the single (uncloned) set just centres and wraps. */
.marquee__track:not(.is-cloned) {
  width: 100%;
  flex-wrap: wrap;
  justify-content: center;
  row-gap: 1.5rem;
}
.marquee__set {
  display: flex;
  align-items: center;
  gap: clamp(2.5rem, 5vw, 4.5rem);
  padding-right: clamp(2.5rem, 5vw, 4.5rem);
  flex: none;
}
/* Wrapping the *track* isn't enough: the track only ever holds one or two
   children, so it's the set itself that has to wrap or the row of logos runs
   off under the viewport's overflow:hidden. Applies to both still states, no
   JS (uncloned) and reduced motion, because the strip is a full set of brands
   in each, and half a strip reads as a bug rather than a design. */
.marquee__track:not(.is-cloned) .marquee__set {
  flex: 1 1 auto;
  flex-wrap: wrap;
  justify-content: center;
  row-gap: 1.5rem;
  padding-right: 0;
}
/* Every mark is a <use> into /img/brands.svg, so each one arrives on the same
   24×24 grid: a fixed square cell is what makes fifteen different logos sit
   together. Wide marks (Kia, Dacia, Audi) fill the cell horizontally and tall
   ones (Tesla, Polestar) vertically, which is how the grid is drawn to balance
   optically, don't switch to height + width:auto, that shrinks the wide ones. */
.marquee__logo {
  width: 38px;
  height: 38px;
  flex: none;
  color: var(--ink);
  opacity: 0.42;
  transition: opacity 0.2s ease;
}
@media (hover: hover) {
  .marquee__logo:hover { opacity: 0.85; }
  .marquee:hover .marquee__track.is-cloned { animation-play-state: paused; }
}
@keyframes marquee-scroll {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) {
  .marquee__track { animation: none !important; width: 100%; flex-wrap: wrap; justify-content: center; row-gap: 1.5rem; }
  .marquee__set { flex: 1 1 auto; flex-wrap: wrap; justify-content: center; row-gap: 1.5rem; padding-right: 0; }
  .marquee__set--clone { display: none; }
  .marquee__viewport { -webkit-mask: none; mask: none; }
}

/* ---------------------------------------------------------------------------
   App showcase (#fonctionnement), a central tilted phone overlapping a light
   "steps" panel (left) and a dark CTA panel (right). Desktop composite; on
   narrow screens it stacks phone-first.
--------------------------------------------------------------------------- */
.appshow {
  position: relative;
  margin-top: clamp(2rem, 4vw, 3rem);
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: center;
  min-height: 600px;
}
.appshow__panel {
  border-radius: var(--radius-xl);
  padding: clamp(2rem, 4vw, 3.25rem);
  min-height: 380px;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.appshow__panel--steps {
  background: linear-gradient(158deg, #dbe8f6 0%, #eef1f6 42%, #f8ede1 100%);
  margin-right: -32px;
  padding-right: clamp(3rem, 12vw, 9rem);
  color: var(--ink);
}
.appshow__panel--cta {
  background: var(--night);
  color: #fff;
  margin-left: -32px;
  padding-left: clamp(3rem, 12vw, 9rem);
  align-items: flex-end;
  text-align: right;
}
.appshow__title {
  font-family: var(--font-serif);
  font-weight: 500;
  font-size: clamp(1.75rem, 3vw, 2.5rem);
  line-height: 1.08;
  letter-spacing: -0.025em;
  margin: 0 0 1.75rem;
}
.appshow__title--light { color: #fff; }
.appshow__steps { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 1.1rem; }
.appshow__steps li {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  font-size: 1.0625rem;
  font-weight: 500;
}
.appshow__num {
  flex: none;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: 1px solid rgba(11, 15, 17, 0.18);
  background: rgba(255, 255, 255, 0.6);
  display: grid;
  place-items: center;
  font-size: 0.875rem;
  font-weight: 700;
  color: var(--ink);
}
.appshow__pill {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 2rem;
  padding: 0.5rem 0.9rem;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.75);
  box-shadow: var(--shadow-sm);
  font-size: 0.8125rem;
  font-weight: 600;
}
.appshow__pill-ck {
  width: 18px; height: 18px;
  border-radius: 50%;
  background: var(--ink);
  color: #fff;
  display: grid;
  place-items: center;
  font-size: 0.625rem;
}
.appshow__price {
  font-family: var(--font-serif);
  font-weight: 600;
  font-size: clamp(3.5rem, 7vw, 5.5rem);
  line-height: 1;
  letter-spacing: -0.04em;
  margin: 0 0 0.5rem;
  color: #fff;
}
.appshow__cta-sub { color: rgba(255, 255, 255, 0.65); font-size: 0.9375rem; margin: 0 0 1.75rem; max-width: 22ch; }
.appshow__panel--cta .btn { align-self: flex-end; }

.appshow__phone {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 288px;                 /* definite width so the deck (all-absolute
                                   children) still gives the phone its size */
  transform: translate(-50%, -50%) rotate(3deg);
  z-index: 3;
  filter: drop-shadow(0 30px 50px rgba(11, 20, 28, 0.32));
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.85rem;
}
.phone--hero { width: 288px; max-width: 288px; }

/* Store badges: Apple's and Google's own official badge images (hotlinked
   from their own badge services, see the HTML comment above each usage),
   opening the closed-beta e-mail capture rather than a real store listing.
   The button is a bare frame around the badge image; all the visual design
   (black pill, logo, wordmark) is the image itself. */
.storebadges { display: flex; align-items: center; gap: 0.7rem; flex-wrap: wrap; }
.storebadge {
  display: inline-flex;
  padding: 0;
  border: none;
  background: transparent;
  line-height: 0;
  cursor: pointer;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.14)) drop-shadow(0 8px 20px rgba(0, 0, 0, 0.16));
  transition: transform 0.2s var(--ease);
}
.storebadge:hover { transform: translateY(-2px); }
.storebadge img { display: block; height: 40px; width: auto; }
/* Google's official PNG badge bakes in ~23% of transparent vertical padding
   around the black pill (Apple's SVG badge has none), so at the same image
   height the two visible marks read as different sizes. Sized up so the
   visible pill itself lines up with Apple's, not the image's own box. */
.storebadge--google img { height: 52px; }
.footer__badges { margin-top: 1.1rem; }
.hero__badges { justify-content: center; margin-top: 1rem; }

@media (max-width: 900px) {
  .appshow {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 1.25rem;
    min-height: 0;
  }
  .appshow__phone { position: static; transform: none; order: -1; align-self: center; margin-bottom: 0.5rem; }
  .appshow__panel {
    min-height: 0;
    margin: 0;
    padding: clamp(1.75rem, 6vw, 2.5rem);
    align-items: flex-start;
    text-align: left;
  }
  .appshow__panel--cta { align-items: flex-start; text-align: left; }
  .appshow__panel--cta .btn { align-self: flex-start; }
  .appshow__title { margin-bottom: 1.25rem; }
  .appshow__title br { display: none; }
}

/* Screen deck, three .appui screens stacked in the phone, cross-fading on a
   timer (src/browser/deck.ts). Only `.is-active` is visible; the rest sit at
   opacity 0. Under reduced motion the timer never runs, so the HTML's default
   `.is-active` (the dashboard) is the single static screen shown. */
.appui-deck { position: relative; width: 100%; height: 100%; }
.appui-deck .appui {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 0.8s var(--ease);
}
.appui-deck .appui.is-active { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .appui-deck .appui { transition: none; }
}

/* ---------------------------------------------------------------------------
   .appui, the finished-looking app screen inside the showcase phone. Serif
   for the vehicle name, small-caps section heads, soft rounded cards, green
   compatibility ticks. Deliberately richer than a wireframe.
--------------------------------------------------------------------------- */
.appui {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  color: var(--ink);
  overflow: hidden;
}
.pa { gap: 9px; background: #f4f6f8; padding: 34px 13px 10px; }

/* status bar */
.pa-status { display: flex; justify-content: space-between; align-items: center; font-size: 0.75rem; font-weight: 700; flex: none; padding: 0 4px 2px; }
.pa-status-ic { display: inline-flex; align-items: center; gap: 3px; }
.pa-status-ic i, .pa-status-ic b { display: block; width: 13px; height: 9px; border-radius: 2px; background: var(--ink); }
.pa-status-ic i:first-child { width: 15px; }
.pa-status-ic b { width: 20px; }

/* top bar: circular icon buttons + centred title */
.pa-bar { display: flex; align-items: center; justify-content: space-between; gap: 8px; flex: none; padding: 0 2px; }
.pa-icobtn { width: 34px; height: 34px; border-radius: 50%; background: #fff; color: var(--ink); display: grid; place-items: center; flex: none; box-shadow: 0 1px 2px rgba(15, 25, 35, 0.07); }
.pa-icobtn svg { width: 17px; height: 17px; }
.pa-icobtn--ghost { background: transparent; box-shadow: none; }
.pa-bar-title { display: flex; flex-direction: column; align-items: center; font-size: 0.8125rem; font-weight: 700; line-height: 1.15; text-align: center; }
.pa-bar-title small { font-size: 0.625rem; font-weight: 600; color: var(--accent-text); }
.pa-bar-title--c { font-family: var(--font-serif); font-size: 1.0625rem; }

/* car render */
.pa-carwrap { position: relative; flex: none; padding: 2px 6px 6px; }
.pa-car { display: block; width: 100%; height: auto; filter: drop-shadow(0 10px 10px rgba(0, 0, 0, 0.12)); }
.pa-car-line { position: absolute; left: 14%; right: 14%; bottom: 2px; height: 20px; border-bottom: 2px solid var(--accent); border-radius: 50%; opacity: 0.55; }
.pa-carwrap--glow::before { content: ""; position: absolute; inset: -4% 4% 6%; background: radial-gradient(58% 58% at 50% 55%, rgba(203, 232, 0, 0.4) 0%, rgba(203, 232, 0, 0) 70%); }
.pa-carwrap--glow .pa-car { position: relative; }

/* cards */
.pa-card { background: #fff; border-radius: 16px; box-shadow: 0 1px 2px rgba(15, 25, 35, 0.05), 0 6px 14px rgba(15, 25, 35, 0.04); padding: 11px 12px; flex: none; }
.pa-card-head { display: flex; justify-content: space-between; align-items: center; font-size: 0.75rem; font-weight: 700; margin-bottom: 9px; }
.pa-dots { color: var(--text-muted); letter-spacing: 1px; font-size: 0.5rem; }
.pa-chev { color: var(--text-muted); font-weight: 700; }

/* segmented battery */
.pa-seg { display: flex; gap: 3px; margin-bottom: 10px; }
.pa-seg i { flex: 1; height: 14px; border-radius: 3px; background: #e7eaee; }
.pa-seg i.f { background: var(--accent); }
.pa-batrow { display: flex; align-items: flex-end; justify-content: space-between; }
.pa-big { font-size: 1.25rem; font-weight: 800; display: flex; flex-direction: column; line-height: 1; }
.pa-big small { font-size: 0.5rem; font-weight: 600; color: var(--text-muted); margin-top: 3px; }
.pa-km { display: inline-flex; align-items: center; gap: 3px; font-size: 1rem; font-weight: 800; color: var(--accent-text); }
.pa-km svg { width: 13px; height: 13px; }

/* controls grid */
.pa-ctrls { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; }
.pa-ctrl { display: flex; flex-direction: column; align-items: center; gap: 5px; }
.pa-ctrl-ic { width: 40px; height: 40px; border-radius: 50%; border: 1px solid var(--line); background: #fff; display: grid; place-items: center; color: var(--ink); }
.pa-ctrl-ic svg { width: 18px; height: 18px; }
.pa-ctrl-ic.is-on { background: var(--accent); border-color: var(--accent); }
.pa-ctrl small { font-size: 0.5625rem; color: var(--text-muted); font-weight: 600; }

/* floating tab bar */
.pa-tabs { margin-top: auto; display: flex; justify-content: space-around; align-items: center; background: #fff; border-radius: 999px; padding: 7px 8px; flex: none; box-shadow: 0 4px 16px rgba(15, 25, 35, 0.1); }
.pa-tab { width: 34px; height: 34px; border-radius: 50%; display: grid; place-items: center; color: var(--text-muted); }
.pa-tab svg { width: 18px; height: 18px; }
.pa-tab.is-active { background: var(--accent); color: var(--ink); }

/* map screen */
.pa--map { padding: 0; background: #dfe4ea; position: relative; }
.pa-status--onmap { position: absolute; top: 0; left: 0; right: 0; padding: 12px 17px 0; z-index: 3; }
.pa-map { position: relative; flex: 1; background: linear-gradient(160deg, #e4e9ee, #d8dee6); overflow: hidden; }
.pa-map-streets { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0.85; }
.pa-map-top { position: absolute; top: 34px; left: 12px; right: 12px; display: flex; gap: 8px; align-items: center; z-index: 2; }
.pa-search { flex: 1; display: flex; align-items: center; gap: 6px; background: #fff; border-radius: 999px; padding: 8px 12px; font-size: 0.6875rem; font-weight: 600; box-shadow: 0 2px 8px rgba(15, 25, 35, 0.12); }
.pa-search svg { width: 13px; height: 13px; color: var(--text-muted); flex: none; }
.pa-mappin { position: absolute; width: 12px; height: 12px; border-radius: 50%; background: var(--accent); border: 2px solid #fff; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); transform: translate(-50%, -50%); }
.pa-mappin--sel { width: 30px; height: 30px; display: grid; place-items: center; box-shadow: 0 3px 8px rgba(0, 0, 0, 0.3); }
.pa-mappin--sel svg { width: 15px; height: 15px; }
.pa-chips { position: absolute; left: 12px; bottom: 10px; display: flex; gap: 6px; z-index: 2; }
.pa-chip { background: #fff; border-radius: 999px; padding: 6px 12px; font-size: 0.625rem; font-weight: 700; box-shadow: 0 2px 6px rgba(15, 25, 35, 0.12); }
.pa-sheet { background: #fff; border-radius: 20px 20px 0 0; padding: 14px 14px 16px; flex: none; box-shadow: 0 -4px 16px rgba(15, 25, 35, 0.08); }
.pa-sheet-head { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 9px; }
.pa-sheet-t { display: flex; flex-direction: column; font-size: 0.875rem; font-weight: 800; }
.pa-sheet-t small { font-size: 0.625rem; font-weight: 600; color: var(--text-muted); margin-top: 2px; }
.pa-dist { display: inline-flex; align-items: center; gap: 3px; font-size: 0.6875rem; font-weight: 700; color: var(--accent-text); }
.pa-dist svg { width: 12px; height: 12px; }
.pa-sheet-row { display: flex; align-items: center; gap: 7px; font-size: 0.6875rem; font-weight: 600; color: var(--text-muted); padding: 3px 0; }
.pa-sheet-row svg { width: 14px; height: 14px; color: var(--accent-text); flex: none; }
.pa-sheet-btns { display: grid; grid-template-columns: 1fr 1.25fr; gap: 8px; margin-top: 12px; }
.pa-btn { text-align: center; border-radius: 999px; padding: 11px; font-size: 0.75rem; font-weight: 700; }
.pa-btn--dark { background: var(--ink); color: #fff; }
.pa-btn--acid { background: var(--accent); color: var(--ink); }

/* charging screen */
.pa-card--charger { display: flex; align-items: center; gap: 9px; padding: 9px 11px; }
.pa-plug { width: 30px; height: 30px; border-radius: 9px; background: var(--accent); display: grid; place-items: center; flex: none; }
.pa-plug svg { width: 16px; height: 16px; }
.pa-charger-b { display: flex; flex-direction: column; flex: 1; font-size: 0.75rem; font-weight: 700; min-width: 0; }
.pa-charger-b small { font-size: 0.625rem; font-weight: 600; color: var(--text-muted); margin-top: 1px; }
.pa-i { width: 16px; height: 16px; border-radius: 50%; border: 1px solid var(--line); display: grid; place-items: center; font-style: italic; font-family: var(--font-serif); font-size: 0.625rem; color: var(--text-muted); flex: none; }
.pa-charge-head { display: flex; justify-content: space-between; align-items: flex-end; padding: 0 4px; flex: none; }
.pa-charge-t { display: flex; flex-direction: column; font-size: 1rem; font-weight: 800; }
.pa-charge-t small { font-size: 0.5625rem; font-weight: 600; color: var(--accent-text); margin-top: 2px; }
.pa-pct { display: flex; flex-direction: column; align-items: flex-end; font-size: 1.25rem; font-weight: 800; line-height: 1; }
.pa-pct small { font-size: 0.5rem; font-weight: 600; color: var(--text-muted); margin-top: 3px; }
.pa-prog { height: 30px; border-radius: 10px; background: #e7eaee; overflow: hidden; flex: none; }
.pa-prog-fill { display: flex; align-items: center; width: 72%; height: 100%; background: var(--accent); border-radius: 10px; padding-left: 10px; }
.pa-prog-fill span { font-size: 0.5625rem; font-weight: 700; color: var(--ink); white-space: nowrap; }
.pa-listrow { display: flex; align-items: center; justify-content: space-between; background: #fff; border-radius: 14px; padding: 11px 12px; font-size: 0.75rem; font-weight: 600; flex: none; box-shadow: 0 1px 2px rgba(15, 25, 35, 0.04); }
.pa-listrow b { font-weight: 800; }

/* CSS-drawn phone frame: no licensed device artwork required. */
.phone {
  position: relative;
  width: min(258px, 100%);
  max-width: 258px;
  aspect-ratio: 9 / 19.5;
  background: #ffffff;
  border: 10px solid #101314;
  border-radius: 42px;
  box-shadow: var(--shadow-md);
  overflow: hidden;
  flex: none;
}
.phone::before {
  content: "";
  position: absolute;
  top: 0; left: 50%;
  transform: translateX(-50%);
  width: 108px; height: 26px;
  background: #101314;
  border-radius: 0 0 16px 16px;
  z-index: 2;
}

/* Mocked app UI inside the phone frame */
.app-screen {
  width: 100%; height: 100%;
  display: flex;
  flex-direction: column;
  gap: 10px;
  background: linear-gradient(180deg, #fbfcfd 0%, #f3f5f7 100%);
  padding: 40px 14px 14px;
  font-family: var(--font-sans);
  color: var(--ink);
  overflow: hidden;
}
.app-screen__status {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 0.6875rem;
  font-weight: 700;
  color: var(--text-muted);
  padding: 0 2px 2px;
  flex: none;
}
.app-screen__title {
  font-size: 0.9375rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  margin: 0;
  flex: none;
}
.app-datestrip { display: flex; gap: 5px; flex: none; }
.app-datestrip__day {
  flex: 1;
  text-align: center;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 5px 2px;
  font-size: 0.5625rem;
  font-weight: 700;
  color: var(--text-muted);
}
.app-datestrip__day--active { background: var(--accent); color: #fff; border-color: var(--accent); }

.app-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 0.625rem;
  font-weight: 700;
  align-self: flex-start;
  flex: none;
}
.app-chip--green { background: #eef6c9; color: #5e7000; }
.app-chip--blue { background: #e7edff; color: #3450c9; }
.app-chip--grey { background: #eef0f2; color: #566069; }
.app-chip--purple { background: #f1e9fb; color: #7440b8; }
.app-chip-row { display: flex; gap: 6px; flex: none; }

.app-row {
  display: flex;
  align-items: center;
  gap: 8px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 8px 10px;
  flex: none;
}
.app-row__avatar {
  width: 28px; height: 28px;
  border-radius: 50%;
  background: #dfe6ff;
  color: #33408a;
  font-size: 0.5625rem;
  font-weight: 700;
  display: flex; align-items: center; justify-content: center;
  flex: none;
}
.app-row__body { display: flex; flex-direction: column; flex: 1; min-width: 0; }
.app-row__body strong { font-size: 0.75rem; font-weight: 700; }
.app-row__body span { font-size: 0.625rem; color: var(--text-muted); }
.app-row__kv { display: flex; justify-content: space-between; flex: 1; font-size: 0.75rem; }
.app-row__kv span:first-child { color: var(--text-muted); }
.app-row__kv strong { font-weight: 700; }

.app-arc {
  position: relative;
  width: 108px; height: 108px;
  margin: 2px auto 0;
  border-radius: 50%;
  background: conic-gradient(var(--accent) 0deg 216deg, #e6e9ec 216deg 360deg);
  display: flex; align-items: center; justify-content: center;
  flex: none;
}
.app-arc::before { content: ""; position: absolute; inset: 10px; border-radius: 50%; background: #fff; }
.app-arc__inner { position: relative; display: flex; flex-direction: column; align-items: center; }
.app-arc__value { font-family: var(--font-serif); font-size: 1.1875rem; font-weight: 600; line-height: 1; }
.app-arc__label { font-size: 0.5625rem; color: var(--text-muted); margin-top: 2px; }

.app-notif {
  display: flex;
  gap: 8px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: 10px;
  align-items: flex-start;
  flex: none;
}
.app-notif__icon {
  width: 26px; height: 26px;
  border-radius: 50%;
  background: #eef6c9;
  display: flex; align-items: center; justify-content: center;
  flex: none;
  font-size: 0.75rem;
}
.app-notif__body strong { display: block; font-size: 0.75rem; font-weight: 700; line-height: 1.3; }
.app-notif__body span { font-size: 0.625rem; color: var(--text-muted); }

.app-map {
  position: relative;
  flex: 1;
  min-height: 110px;
  border-radius: 16px;
  background: linear-gradient(150deg, #e7eefc 0%, #eef1fa 60%, #eaf5f1 100%);
  overflow: hidden;
  border: 1px solid var(--line);
}
.app-map::before {
  content: "";
  position: absolute; inset: 0;
  background-image:
    linear-gradient(rgba(11, 15, 17, 0.05) 1px, transparent 1px),
    linear-gradient(90deg, rgba(11, 15, 17, 0.05) 1px, transparent 1px);
  background-size: 18px 18px;
}
.app-map__pin {
  position: absolute;
  width: 10px; height: 10px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 4px rgba(203, 232, 0, 0.22);
}

.app-pill-row { display: flex; flex-direction: column; gap: 6px; flex: none; }
.app-pill {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 4px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 7px 11px;
  font-size: 0.625rem;
  font-weight: 600;
  color: var(--text-muted);
  white-space: nowrap;
}
.app-pill strong { font-weight: 700; color: var(--ink); }

.app-cta {
  margin-top: auto;
  text-align: center;
  border-radius: 999px;
  padding: 10px;
  font-size: 0.75rem;
  font-weight: 700;
  flex: none;
}
.app-cta--primary { background: var(--ink); color: #fff; }
.app-cta--outline { background: #fff; border: 1px solid var(--line); color: var(--ink); }

.app-tabbar {
  display: flex;
  justify-content: space-around;
  border-top: 1px solid var(--line);
  padding-top: 8px;
  flex: none;
}
.app-tabbar__item { font-size: 0.5625rem; font-weight: 600; color: var(--text-muted); }
.app-tabbar__item--active { color: var(--accent-text); }

/* ---------------------------------------------------------------------------
   Conversation, a donor ("Jade") <-> receiver ("toi") chat, kept
   short and clean: soft borderless bubbles, no chrome, and two hand-drawn
   annotations pointing out who is who. The T+ labels keep the same real
   sequence the old timeline carried (0 -> 20 min). Jade's avatar is a photo
   (free-licence stock, see site/img/README.md) rather than an illustrated
   glyph: a face makes the exchange read as human.
--------------------------------------------------------------------------- */
.chat {
  position: relative;
  margin: clamp(3rem, 6vw, 4.5rem) auto 0;
  max-width: 560px;
}
/* The 2px acid ring is deliberate: the glyph this photo replaced was a solid
   acid-green disc, and the ring keeps the "this is the side with charge" cue
   that a bare photo would drop. It doubles as the placeholder colour if the
   JPEG is slow or missing, so the avatar never reads as a blank hole. */
.chat__avatar {
  flex: none;
  width: 42px;
  height: 42px;
  border-radius: 50%;
  overflow: hidden;
  display: block;
  background: #cbe800;
  border: 2px solid #cbe800;
}
.chat__avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  border-radius: 50%;
}

.chat__thread {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}
.msg {
  display: grid;
  align-items: end;
  gap: 0.4rem 0.65rem;
  max-width: 84%;
}
/* them (Jade): small avatar on the left, name + bubble stacked to its right */
.msg--them {
  grid-template-columns: auto 1fr;
  justify-self: start;
}
.msg--them .chat__avatar { grid-row: 1 / span 2; width: 36px; height: 36px; align-self: end; }
.msg--them .msg__time { grid-column: 2; padding-left: 0.25rem; }
.msg__stack { display: flex; flex-direction: column; gap: 0.3rem; min-width: 0; }
.msg__from {
  font-size: 0.75rem;
  font-weight: 700;
  color: var(--accent-text);
  padding-left: 0.25rem;
}
/* you (receiver): bubble on the right, no avatar */
.msg--you { justify-self: end; justify-items: end; }
.msg--you .msg__time { padding-right: 0.25rem; }

/* Clean, borderless bubbles, soft grey for Jade, ink for you, generously
   rounded with a single tail corner. */
.msg__bubble {
  padding: 0.75rem 1.05rem;
  border-radius: 20px;
  font-size: 0.9375rem;
  line-height: 1.45;
  width: fit-content;
  max-width: 100%;
}
.msg--them .msg__bubble {
  background: var(--bg-soft);
  color: var(--ink);
  border-bottom-left-radius: 6px;
}
.msg--you .msg__bubble {
  background: var(--ink);
  color: #fff;
  border-bottom-right-radius: 6px;
}
.msg__time {
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

/* Hand-drawn annotations, a sketched arrow plus an italic label, pointing out
   the receiver and the donor. Positioned outside the thread on wide screens;
   hidden on narrow ones where there's no side room. Decorative (aria-hidden). */
.chat__hand {
  position: absolute;
  display: flex;
  align-items: center;
  gap: 0.1rem;
  color: var(--text-muted);
}
.chat__hand-label {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: 1.0625rem;
  white-space: nowrap;
}
.chat__hand-arrow { width: 64px; height: 50px; overflow: visible; }
.chat__hand--you {
  top: -2.6rem;
  right: -1.5rem;
  color: var(--amber);
  transform: rotate(3deg);
}
.chat__hand--donor {
  bottom: 2.4rem;
  left: -5.5rem;
  color: var(--accent-text);
  transform: rotate(-3deg);
}
@media (max-width: 900px) {
  .chat__hand { display: none; }
}

.chat__note {
  margin: 2.5rem auto 0;
  max-width: 60ch;
  text-align: center;
  font-size: 0.875rem;
  color: var(--text-muted);
}

/* ---------------------------------------------------------------------------
   Cost, in a dark telemetry treatment (inspirations/stats.png): a dotted car
   sits behind a central data card. The card reads the pain up top (200-500 €
   tow, mono stats) and the V2V answer in green below (12-25 €, estimated) with
   an equalizer of green bars. Honest hedges kept.
--------------------------------------------------------------------------- */
.stats {
  background: var(--night);
  color: #fff;
  text-align: center;
}
.stats__title { color: #fff; margin: 0 auto 1rem; max-width: 18ch; }
.stats__lead { color: rgba(255, 255, 255, 0.66); margin: 0 auto; }
.stats__note {
  margin: 2.5rem auto 0;
  max-width: 72ch;
  font-size: 0.8125rem;
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.5);
}

.telemetry {
  position: relative;
  margin: clamp(2.5rem, 6vw, 4rem) auto 0;
  max-width: 760px;
  min-height: 340px;
  display: grid;
  place-items: center;
  isolation: isolate;
}
/* Dashed blueprint frame */
.telemetry::before {
  content: "";
  position: absolute;
  inset: 0 clamp(0px, 6vw, 60px);
  border: 1px dashed rgba(255, 255, 255, 0.14);
  z-index: -2;
  pointer-events: none;
}
/* Dotted car, large, behind the card */
.telemetry__car {
  position: absolute;
  width: min(660px, 96%);
  height: auto;
  z-index: -1;
  opacity: 0.42;
  pointer-events: none;
}

.telemetry__card {
  width: min(400px, 100%);
  text-align: left;
  padding: clamp(1.5rem, 4vw, 2rem);
  border-radius: 6px;
  background: rgba(9, 13, 12, 0.72);
  border: 1px solid rgba(255, 255, 255, 0.12);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
}
.telemetry__label {
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.06em;
  color: rgba(255, 255, 255, 0.4);
  margin-bottom: 0.75rem;
}
.telemetry__top { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; }
.telemetry__hero {
  font-weight: 600;
  font-size: clamp(2.75rem, 7vw, 3.75rem);
  line-height: 0.95;
  letter-spacing: -0.03em;
  color: #fff;
  display: inline-flex;
  align-items: baseline;
}
.telemetry__dash { margin: 0 0.03em; font-weight: 400; }
.telemetry__unit { font-size: 0.4em; font-weight: 600; margin-left: 0.2em; color: rgba(255, 255, 255, 0.75); }
.telemetry__icon { width: 40px; height: auto; color: rgba(255, 255, 255, 0.55); flex: none; margin-top: 0.35rem; }

.telemetry__stats {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem 1.5rem;
  margin-top: 1rem;
  font-family: var(--font-mono);
  font-size: 0.75rem;
}
.telemetry__stat { display: inline-flex; align-items: center; gap: 0.5rem; }
.telemetry__k { color: rgba(255, 255, 255, 0.45); letter-spacing: 0.04em; }
.telemetry__k::before { content: "› "; color: rgba(255, 255, 255, 0.3); }
.telemetry__v { color: rgba(255, 255, 255, 0.85); font-weight: 700; }

.telemetry__answer {
  margin-top: 1.6rem;
  font-family: var(--font-mono);
  font-size: 0.9375rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--accent-bright);
}
.telemetry__answer em { font-style: normal; font-size: 0.7em; color: rgba(255, 255, 255, 0.4); letter-spacing: 0.06em; text-transform: uppercase; }
.telemetry__bars {
  margin-top: 0.6rem;
  height: 54px;
  display: flex;
  align-items: flex-end;
  gap: 3px;
}
.telemetry__bars i {
  flex: 1;
  min-width: 0;
  border-radius: 1.5px 1.5px 0 0;
  background: linear-gradient(180deg, var(--accent-bright) 0%, #5e7000 100%);
  box-shadow: 0 0 6px rgba(203, 232, 0, 0.35);
}
.telemetry__foot {
  margin-top: 0.7rem;
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.06em;
  color: rgba(203, 232, 0, 0.75);
}

/* ---------------------------------------------------------------------------
   Report page (/rapport-v2v), a data dossier: hero, key figures, the park
   density chart, an opportunity thesis, and cited sources. Reuses the site
   system; these classes add the report-specific rhythm.
--------------------------------------------------------------------------- */
.report__hero {
  padding-top: clamp(9rem, 16vh, 12rem);
  padding-bottom: clamp(2.5rem, 6vw, 4rem);
}
.report__h1 {
  font-family: var(--font-serif);
  font-weight: 500;
  font-size: clamp(2.5rem, 6vw, 4.5rem);
  line-height: 1.03;
  letter-spacing: -0.03em;
  margin: 0.75rem 0 1.5rem;
  text-wrap: balance;
}
.report__lede { font-size: 1.1875rem; line-height: 1.6; color: var(--text-muted); max-width: 62ch; }
.report__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  align-items: center;
  margin-top: 2rem;
  font-size: 0.875rem;
  color: var(--text-muted);
}
.report__meta strong { color: var(--ink); font-weight: 600; }

.report__section { padding: clamp(3rem, 6vw, 5rem) 0; }
.report__section--soft { background: var(--bg-soft); }
.report__section > .container > h2,
.report__section > h2 { margin-bottom: 1.5rem; }
.report__p { font-size: 1.0625rem; line-height: 1.7; color: var(--text-muted); max-width: 68ch; }
.report__p--muted { font-size: 0.9375rem; }
.report__p strong { color: var(--ink); }

.report__figures {
  margin-top: 2.5rem;
  display: grid;
  gap: 1.25rem;
  grid-template-columns: repeat(2, 1fr);
}
@media (min-width: 820px) { .report__figures { grid-template-columns: repeat(4, 1fr); } }
.report__figure {
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.75rem;
  box-shadow: var(--shadow-sm);
}
.report__section--soft .report__figure { background: var(--bg); }
.report__figure-value {
  display: block;
  font-family: var(--font-serif);
  font-weight: 600;
  font-size: clamp(1.75rem, 3vw, 2.375rem);
  letter-spacing: -0.03em;
  color: var(--accent-text);
  margin-bottom: 0.75rem;
  font-variant-numeric: tabular-nums;
}
.report__figure-label { font-size: 0.875rem; line-height: 1.5; color: var(--text-muted); }

/* Superscript citation link */
.report__cite {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.1em;
  height: 1.1em;
  margin-left: 0.15em;
  padding: 0 0.25em;
  border-radius: 4px;
  background: var(--bg-soft);
  color: var(--accent-text);
  font-size: 0.7em;
  font-weight: 700;
  text-decoration: none;
  vertical-align: super;
  line-height: 1;
}
.report__cite:hover { background: var(--accent); color: #fff; }

.report__placeholder {
  margin-top: 2rem;
  padding: 2rem;
  border: 1px dashed var(--line);
  border-radius: var(--radius);
  background: var(--bg-soft);
  color: var(--text-muted);
  font-size: 0.9375rem;
  line-height: 1.6;
}
.report__placeholder strong { color: var(--ink); }

.report__sources { margin: 2rem 0 0; padding-left: 1.5rem; max-width: 74ch; }
.report__sources li { margin-bottom: 1.1rem; font-size: 0.9375rem; line-height: 1.6; color: var(--text-muted); }
.report__sources li strong { color: var(--ink); font-weight: 600; }
.report__sources li em { font-style: italic; color: var(--text-muted); }
.report__sources li:target { background: var(--amber-soft); border-radius: 6px; padding: 0.25rem 0.5rem; margin-left: -0.5rem; }
.report__sources a { color: var(--accent-text); font-weight: 600; }

/* Region interlinks (report + region pages) */
.region-links {
  list-style: none;
  margin: 1.5rem 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 0.5rem 1.5rem;
}
.region-links a {
  display: inline-block;
  padding: 0.5rem 0;
  color: var(--ink);
  text-decoration: none;
  font-weight: 600;
  font-size: 0.9375rem;
  border-bottom: 1px solid transparent;
}
.region-links a:hover { color: var(--accent-text); border-bottom-color: var(--accent); }

/* ---------------------------------------------------------------------------
   Closing CTA, a light "energy" panel where the page's signature cable flows
   into the button (V2V, plugged in). Breaks the dark-band rhythm on purpose.
--------------------------------------------------------------------------- */
.cta {
  position: relative;
  overflow: hidden;
  padding: clamp(5rem, 12vw, 8rem) 0;
  text-align: center;
  color: var(--ink);
  background:
    radial-gradient(58% 68% at 50% 34%, rgba(203, 232, 0, 0.16) 0%, rgba(203, 232, 0, 0) 62%),
    linear-gradient(180deg, #f1f7f3 0%, #eaf1f9 100%);
}
/* Fading dot grid, masked to the centre so edges stay clean */
.cta::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: radial-gradient(rgba(11, 15, 17, 0.055) 1px, transparent 1px);
  background-size: 22px 22px;
  -webkit-mask: radial-gradient(66% 68% at 50% 40%, #000 0%, transparent 72%);
  mask: radial-gradient(66% 68% at 50% 40%, #000 0%, transparent 72%);
  pointer-events: none;
}
.cta__inner { position: relative; z-index: 1; display: flex; flex-direction: column; align-items: center; }
.cta__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.4rem 0.95rem;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.8);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-sm);
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--accent-text);
}
.cta__bolt { font-size: 0.9em; }
.cta__title {
  font-family: var(--font-serif);
  font-weight: 500;
  font-size: clamp(2.25rem, 5vw, 4rem);
  line-height: 1.04;
  letter-spacing: -0.03em;
  margin: 1.25rem 0 0.85rem;
  max-width: 16ch;
}
.cta__sub { color: var(--text-muted); max-width: 44ch; font-size: 1.0625rem; margin: 0; }

.cta__plug {
  display: inline-flex;
  align-items: center;
  margin: 2.75rem 0 0;
}
.cta__cable { width: 108px; height: 44px; overflow: visible; flex: none; margin-right: -10px; }
.cta__cable-path { stroke-dasharray: 5 8; filter: drop-shadow(0 0 5px rgba(203, 232, 0, 0.5)); }
.cta__cable-spark { opacity: 0; offset-path: path("M4 30 Q 42 8 78 30 T 146 30"); offset-distance: 0%; filter: drop-shadow(0 0 6px rgba(200, 247, 221, 0.9)); }
@media (prefers-reduced-motion: no-preference) and (pointer: fine) {
  .cta__cable-path { animation: cable-flow 0.9s linear infinite; }
  .cta__cable-spark { animation: cta-spark 1.8s ease-in-out infinite; }
}
@keyframes cta-spark {
  0% { offset-distance: 0%; opacity: 0; }
  15% { opacity: 1; }
  85% { opacity: 1; }
  100% { offset-distance: 100%; opacity: 0; }
}
@media (max-width: 560px) { .cta__cable { display: none; } }

.cta__btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  padding: 1.1rem 2.2rem;
  border: none;
  border-radius: 999px;
  background: var(--accent);
  color: var(--ink);
  font: inherit;
  font-size: 1.1875rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  cursor: pointer;
  box-shadow: 0 2px 4px rgba(11, 15, 17, 0.14), 0 16px 38px rgba(203, 232, 0, 0.5);
  transition: transform 0.2s var(--ease), box-shadow 0.2s ease, background 0.2s ease;
}
.cta__btn:hover { background: var(--accent-bright); transform: translateY(-2px); box-shadow: 0 4px 8px rgba(11, 15, 17, 0.16), 0 22px 48px rgba(203, 232, 0, 0.6); }
.cta__btn:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }
/* The connector "port" the cable plugs into, a dark ring on the green button */
.cta__port {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--ink);
  box-shadow: 0 0 0 3px rgba(11, 15, 17, 0.18);
  flex: none;
}

.cta__reassure {
  list-style: none;
  margin: 2.25rem 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.6rem;
}
.cta__reassure li {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.4rem 0.9rem;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.7);
  border: 1px solid var(--line);
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--text-muted);
}
.cta__reassure li::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent);
}

/* FAQ, two columns: an intro/heading rail (sticky on desktop) beside the
   accordion, with a chevron toggle that pivots and greens on open. */
.faq {
  display: grid;
  grid-template-columns: 1fr;
  gap: 2.5rem;
}
@media (min-width: 900px) {
  .faq {
    grid-template-columns: 0.82fr 1.18fr;
    gap: clamp(3rem, 6vw, 6rem);
    align-items: start;
  }
  .faq__intro { position: sticky; top: 120px; }
}
.faq__intro h2 { margin: 0.75rem 0 1rem; }
.faq__lead { color: var(--text-muted); font-size: 1.0625rem; max-width: 34ch; margin: 0 0 1.25rem; }
.faq__contact {
  display: inline-block;
  color: var(--accent-text);
  font-weight: 600;
  text-decoration: none;
  border-bottom: 1px solid rgba(94, 112, 0, 0.35);
  padding-bottom: 1px;
}
.faq__contact:hover { border-bottom-color: var(--accent-text); }

.faq__list { margin: 0; }
.faq__item { border-top: 1px solid var(--line); }
.faq__item:last-child { border-bottom: 1px solid var(--line); }
.faq__item summary {
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 1.25rem;
  padding: 1.4rem 0;
  font-weight: 600;
  font-size: 1.0625rem;
  line-height: 1.4;
  list-style: none;
  transition: color 0.2s ease;
}
.faq__item summary:hover { color: var(--accent-text); }
.faq__item[open] summary { color: var(--ink); }
.faq__item summary::-webkit-details-marker { display: none; }
/* Chevron toggle, a down-caret that flips up and greens when the item opens */
.faq__item summary::after {
  content: "";
  flex: none;
  width: 9px;
  height: 9px;
  margin-left: auto;
  margin-top: -3px;
  border-right: 2px solid var(--text-muted);
  border-bottom: 2px solid var(--text-muted);
  transform: rotate(45deg);
  transition: transform 0.3s var(--ease), border-color 0.2s ease;
}
.faq__item summary:hover::after { border-color: var(--accent-text); }
.faq__item[open] summary::after { transform: rotate(-135deg); margin-top: 3px; border-color: var(--accent-text); }
.faq__item p { color: var(--text-muted); padding-bottom: 1.75rem; margin: 0; max-width: 64ch; }
@media (prefers-reduced-motion: no-preference) {
  .faq__item[open] > p { animation: faq-reveal 0.35s var(--ease); }
}
@keyframes faq-reveal {
  from { opacity: 0; transform: translateY(-6px); }
  to { opacity: 1; transform: none; }
}

/* ---------------------------------------------------------------------------
   Footer, dark closing block. Link columns and a legal bar over a giant
   ChargeV2V wordmark that is cropped at the page's bottom edge (only its top
   shows) and "charges" bottom-up to full on entry (src/browser/footer.ts),
   closing the state-of-charge motif.
--------------------------------------------------------------------------- */
.footer {
  background: var(--night);
  color: rgba(255, 255, 255, 0.72);
  padding-top: clamp(3.5rem, 8vw, 6rem);
  overflow: hidden;
}
.footer__top {
  display: grid;
  grid-template-columns: 1.3fr 2fr;
  gap: clamp(2.5rem, 6vw, 5rem);
  padding-bottom: clamp(2.5rem, 6vw, 4rem);
}
@media (max-width: 860px) {
  .footer__top { grid-template-columns: 1fr; gap: 3rem; }
}
.footer__brand-name {
  font-family: var(--font-serif);
  font-size: 1.5rem;
  font-weight: 600;
  letter-spacing: -0.02em;
  color: #fff;
}
.footer__brand-tag {
  margin: 0.9rem 0 1.5rem;
  max-width: 34ch;
  font-size: 0.9375rem;
  line-height: 1.55;
  color: rgba(255, 255, 255, 0.6);
}
.footer__cols {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 2rem 1.5rem;
}
@media (max-width: 560px) {
  .footer__cols { grid-template-columns: repeat(2, 1fr); gap: 2rem 1rem; }
}
.footer__col h3 {
  font-family: var(--font-sans);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.45);
  margin: 0 0 1rem;
}
.footer__col ul { list-style: none; margin: 0; padding: 0; }
.footer__col li { margin-bottom: 0.7rem; }
.footer__col a {
  color: rgba(255, 255, 255, 0.72);
  text-decoration: none;
  font-size: 0.9375rem;
  transition: color 0.2s ease;
}
.footer__col a:hover { color: #fff; }

.footer__bar {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  justify-content: space-between;
  align-items: center;
  padding: 1.5rem 0;
  border-top: 1px solid var(--line-night);
  font-size: 0.8125rem;
  color: rgba(255, 255, 255, 0.5);
}
.footer__charge { display: inline-flex; align-items: center; gap: 0.55rem; }
.footer__battery {
  position: relative;
  display: inline-block;
  width: 26px;
  height: 13px;
  border: 1.5px solid rgba(255, 255, 255, 0.4);
  border-radius: 4px;
  padding: 1.5px;
}
.footer__battery::after {
  content: "";
  position: absolute;
  right: -4px;
  top: 50%;
  transform: translateY(-50%);
  width: 2.5px;
  height: 5px;
  border-radius: 0 2px 2px 0;
  background: rgba(255, 255, 255, 0.4);
}
.footer__battery-fill {
  display: block;
  height: 100%;
  width: 100%;
  border-radius: 1.5px;
  background: var(--accent-bright);
  transform-origin: left center;
  transition: transform 1.4s var(--ease);
}

/* Giant cropped wordmark. Two stacked copies: a faint base and a solid fill
   clipped from the top down, so the fill reveals from the bottom edge upward
   (footer.ts animates the clip). The container is shorter than the glyphs, so
   the bottom of the letters sits below the page edge. */
.footer__brandmark {
  position: relative;
  font-family: var(--font-serif);
  font-weight: 600;
  font-size: clamp(4rem, 22vw, 18rem);
  line-height: 1;
  letter-spacing: -0.04em;
  text-align: center;
  height: 0.72em;
  margin-top: clamp(1rem, 3vw, 2.5rem);
  user-select: none;
}
.footer__mark-base,
.footer__mark-fill {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  display: block;
}
.footer__mark-base { color: rgba(255, 255, 255, 0.08); }
.footer__mark-fill {
  color: #fff;
  clip-path: inset(0 0 0 0);
  transition: clip-path 1.6s var(--ease);
}


.legal { max-width: 68ch; margin: 0 auto; padding: 6rem 1.5rem; }
.legal h2 { margin-top: 2.75rem; }
.legal p { color: var(--text-muted); }
.legal ul { color: var(--text-muted); margin: 1rem 0; padding-left: 1.25rem; }
.legal li { margin-bottom: 0.5rem; line-height: 1.6; }
.legal li::marker { color: var(--accent-text); }

/* ---------------------------------------------------------------------------
   Qualification form, mounted into #eligibilite-form and driven entirely by
   src/browser/form.ts, which swaps its innerHTML per step. Every element
   created there is present from that first swap (no `.reveal` class is ever
   applied inside it), so nothing here can get stuck at opacity:0.
--------------------------------------------------------------------------- */
.form {
  background: var(--bg);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-md);
  padding: clamp(1.75rem, 5vw, 3rem);
  max-width: 560px;
  margin: 3rem auto 0;
}

/* Eligibility modal. Inside the dialog the `.modal__panel` is the visual card
   (so there's only ever one border/shadow/radius around the wizard, not two
   nested ones) and `.modal .form` strips its own card styling back to a plain
   content block. No open/close transition is defined anywhere in this block,
   deliberately: that makes the modal motion-exempt for free. */
.modal {
  /* Centered via top/left/transform rather than inset:0 + margin:auto,
     auto-margin centering on a fixed box needs an explicit height on all four
     insets to resolve in every engine, and this dialog's height is
     intentionally auto (it shrinks to whatever the current step needs). */
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  margin: 0;
  padding: 0;
  border: none;
  width: min(600px, calc(100vw - 2rem));
  max-height: min(90dvh, 720px);
  background: transparent;
  color: inherit;
}
.modal::backdrop { background: rgba(8, 12, 14, 0.62); }
.modal__panel {
  position: relative;
  max-height: min(90dvh, 720px);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  background: var(--bg);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-lg);
  /* Scroll works, scrollbar is never drawn, the visible track read as ugly
     chrome on the wizard. */
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.modal__panel::-webkit-scrollbar { width: 0; height: 0; display: none; }
/* Sticky, not static, the close button stays reachable once a tall step
   scrolls the panel's own content. */
.modal__bar {
  position: sticky;
  top: 0;
  z-index: 2;
  display: flex;
  justify-content: flex-end;
  padding: 0.85rem 0.85rem 0;
  background: linear-gradient(180deg, var(--bg) 68%, rgba(255, 255, 255, 0));
}
.modal__close {
  width: 36px;
  height: 36px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: var(--bg);
  color: var(--text-muted);
  display: grid;
  place-items: center;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, transform 0.15s ease;
}
.modal__close svg { width: 16px; height: 16px; }
.modal__close:hover { background: var(--ink); color: #fff; transform: rotate(90deg); }
.modal .form {
  background: transparent;
  box-shadow: none;
  margin: 0;
  max-width: none;
  padding: 0.25rem clamp(1.5rem, 5vw, 3rem) clamp(1.75rem, 5vw, 3rem);
}
@media (max-width: 640px) {
  .modal {
    top: 0;
    left: 0;
    transform: none;
    width: 100vw;
    height: 100dvh;
    max-height: 100dvh;
    margin: 0;
  }
  .modal__panel { max-height: 100dvh; height: 100%; border-radius: 0; }
}

/* Segmented progress, one bar per step, filling acid green as the visitor
   advances (clearer and friendlier than a single sliding bar), with a small
   "3 / 6" count. */
.form__prog { display: flex; align-items: center; gap: 0.85rem; margin-bottom: 1.75rem; }
.form__segs { display: flex; gap: 5px; flex: 1; }
.form__seg { flex: 1; height: 5px; border-radius: 999px; background: var(--line); transition: background 0.35s var(--ease); }
.form__seg.is-done { background: var(--accent); }
.form__prog-count { flex: none; font-size: 0.8125rem; font-weight: 800; color: var(--ink); font-variant-numeric: tabular-nums; }
.form__prog-count i { color: var(--text-muted); font-style: normal; font-weight: 600; }

.form__title { font-family: var(--font-serif); font-size: 1.625rem; line-height: 1.15; letter-spacing: -0.02em; margin: 0 0 1.4rem; }
/* The step heading receives a programmatic focus() on every transition (see
   focusStepHeading in form.ts) so screen readers announce the new question.
   It's a non-interactive heading, so no visible ring, that box read as an
   errant border. Screen-reader announcement doesn't need the outline. */
.form__title:focus, .form__title:focus-visible { outline: none; }
.form__body { color: var(--text-muted); }
.form__hint { font-size: 0.875rem; color: var(--text-muted); margin: -0.5rem 0 1.25rem; }
.form__error { color: var(--danger); font-size: 0.875rem; font-weight: 600; margin: -0.5rem 0 1.25rem; }

.form__ref {
  display: block;
  width: 100%;
  max-width: 280px;
  margin: 0 auto 1.25rem;
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-sm);
}

.form__label { display: block; font-size: 0.875rem; font-weight: 700; margin-bottom: 0.5rem; }
.form__input {
  width: 100%;
  padding: 0.9rem 1.1rem;
  font: inherit;
  color: var(--ink);
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  margin-bottom: 1.25rem;
}
.form__input:focus-visible { outline: 2px solid var(--accent-text); outline-offset: 2px; }

.form__consent {
  display: flex;
  gap: 0.65rem;
  align-items: flex-start;
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--text-muted);
  margin: 0 0 1.5rem;
  cursor: pointer;
}
.form__consent input {
  flex: none;
  margin-top: 0.2rem;
  width: 1.1rem;
  height: 1.1rem;
  accent-color: var(--accent);
}

/* "Retour", a small, quiet pill. */
.form__back {
  display: inline-flex;
  width: auto;
  justify-content: center;
  margin: 1.4rem auto 0;
  font-size: 0.9375rem;
  padding: 0.5rem 1.1rem;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--text-muted);
}
.form__back:hover { background: var(--bg-soft); color: var(--ink); }
/* "Ma voiture n'est pas dans la liste", a plain text link, not a button, so
   it doesn't compete with the real choices. */
.form__link {
  display: block;
  width: 100%;
  justify-content: center;
  margin-top: 0.9rem;
  padding: 0.5rem;
  border: none;
  background: transparent;
  color: var(--text-muted);
  font-size: 0.9375rem;
  text-decoration: underline;
  text-decoration-color: var(--line);
  text-underline-offset: 3px;
}
.form__link:hover { color: var(--accent-text); text-decoration-color: currentColor; background: transparent; }

.choices { list-style: none; padding: 0; margin: 0 0 0.25rem; display: flex; flex-direction: column; gap: 0.6rem; }
.choice {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  width: 100%;
  text-align: left;
  padding: 0.95rem 1.1rem 0.95rem 1.25rem;
  font: inherit;
  font-size: 1.0625rem;
  font-weight: 600;
  color: var(--ink);
  background: var(--bg);
  border: 1.5px solid var(--line);
  border-radius: 15px;
  cursor: pointer;
  transition: border-color 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
}
.choice__txt { display: flex; flex-direction: column; gap: 0.15rem; flex: 1; min-width: 0; }
/* Brand mark on the "quelle marque ?" step, the same /img/brands.svg sprite
   the landing-page strip uses. The slot keeps its width even when the sprite
   has no symbol for that make, so one unknown brand can't knock the column of
   labels out of alignment. Muted at rest so the strip of marks doesn't shout
   over the names, full strength on the row you're pointing at. */
.choice__mark { flex: none; width: 28px; height: 28px; }
.choice__logo { width: 100%; height: 100%; color: var(--ink); opacity: 0.62; transition: opacity 0.15s ease; }
.choice:hover .choice__logo { opacity: 1; }
.choice small { color: var(--text-muted); font-size: 0.8125rem; font-weight: 500; line-height: 1.35; }
/* trailing chevron that slides on hover */
.choice::after {
  content: "";
  flex: none;
  width: 8px;
  height: 8px;
  border-top: 2px solid var(--text-muted);
  border-right: 2px solid var(--text-muted);
  transform: rotate(45deg);
  opacity: 0.55;
  transition: transform 0.2s var(--ease), border-color 0.2s ease, opacity 0.2s ease;
}
.choice:hover {
  border-color: var(--accent);
  background: #fbfde9;
  transform: translateY(-1px);
  box-shadow: 0 2px 4px rgba(15, 25, 35, 0.04), 0 10px 20px rgba(203, 232, 0, 0.18);
}
.choice:hover::after { border-color: var(--accent-text); opacity: 1; transform: translateX(3px) rotate(45deg); }
.choice:active { transform: translateY(0); }

/* Form action buttons in acid green (dark text), matching the site CTA. */
.form .btn--primary {
  width: 100%;
  margin-top: 0.25rem;
  background: var(--accent);
  color: var(--ink);
  border-color: var(--accent);
  font-weight: 700;
}
.form .btn--primary:hover { background: #bcd800; border-color: #bcd800; }

/* ---------------------------------------------------------------------------
   Map section, a bar-style density read-out (no mapping library). Built at
   compile time by scripts/build-seo-content.ts from the real Agence ORE
   density data — no client-side fetch, no fallback view needed.
--------------------------------------------------------------------------- */
.map { margin-top: 2.5rem; }
.map__bars { list-style: none; padding: 0; margin: 1.5rem 0 0; }
.map__bar { display: grid; grid-template-columns: 2.5rem 1fr 5rem; gap: 0.75rem; align-items: center; padding: 0.3rem 0; font-size: 0.875rem; }
.map__dep { color: var(--text-muted); font-variant-numeric: tabular-nums; }
.map__track { background: rgba(11, 15, 17, 0.06); border-radius: 999px; height: 10px; overflow: hidden; }
.map__fill { display: block; height: 100%; background: linear-gradient(90deg, var(--accent) 0%, var(--accent-text) 100%); border-radius: 999px; }
.map__count { text-align: right; color: var(--text-muted); font-variant-numeric: tabular-nums; }

/* ---------------------------------------------------------------------------
   Compatibility table on compatibilite.html, generated at build time by
   scripts/build-seo-content.ts from data/vehicles.json.
--------------------------------------------------------------------------- */
.compat-table-wrap { overflow-x: auto; border: 1.5px solid var(--line); border-radius: 16px; margin: 1.5rem 0; }
.compat-table { width: 100%; border-collapse: collapse; font-size: 0.875rem; }
.compat-table th, .compat-table td { padding: 0.6rem 0.75rem; text-align: left; border-bottom: 1px solid var(--line); white-space: nowrap; }
.compat-table th { font-size: 0.7rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-muted); }
.compat-table tr:last-child td { border-bottom: none; }
.compat-pill { display: inline-block; font-size: 0.75rem; font-weight: 700; padding: 0.2rem 0.55rem; border-radius: 999px; border: 1.5px solid; }
.compat-pill--yes { color: #4a5c00; border-color: #b6cf3a; background: #f2f9d6; }
.compat-pill--not_yet { color: #8a5a00; border-color: #e0b96a; background: #fbf3e3; }
.compat-pill--no { color: #6b7075; border-color: var(--line); background: #f4f6f7; }
