/* Site de vente Rupteur - même langage visuel que l'app : monochrome, noir
   habitacle, hairlines, rouge réservé à la zone rouge. Le site assume le
   thème nuit en permanence : c'est l'ambiance du produit. */

/* ---------- Police, auto-hébergée ----------
   Mêmes fichiers que l'app (fonts/ à la racine du dépôt), copiés ici.
   Jusqu'au 02/09/2026 la vitrine appelait fonts.googleapis.com : une
   feuille bloquante avant le premier rendu, et l'adresse IP de chaque
   visiteur envoyée à Google sur une page qui promet « pas de collecte ».
   C'était le seul tiers de la page. Police variable : un fichier pour
   400 à 600, et la latine est préchargée depuis index.html. */

@font-face {
  font-family: 'Montserrat';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url('fonts/montserrat-var-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Montserrat';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url('fonts/montserrat-var-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

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

:root {
  --bg: #0e0e0e;
  --surface: #1a1a1a;
  --raised: rgba(255, 255, 255, 0.06);
  --raised-2: rgba(255, 255, 255, 0.12);
  --line: rgba(255, 255, 255, 0.09);
  --text: #eaeaea;
  --muted: #9a9a9a;
  /* Le gris faible porte du texte de 12 à 13 px : à #616161 il faisait
     3,1:1 sur le fond et 2,8:1 sur une carte, sous les 4,5:1 que demande
     le texte courant, et c'étaient les lignes de réassurance (« sans
     compte », « paiement unique »). #858585 fait 5,2:1 et 4,7:1. Les grands
     titres effacés gardent l'ancien gris (--efface) : à 40 px et plus,
     3:1 suffit, et c'est lui qui fait le contraste des deux tons. */
  --faint: #858585;
  --efface: #616161;
  --red: #e82127;
  /* La pilule collante occupe le bas de l'écran : deux liens de 44 px, 5 px
     de rembourrage et 14 px de marge. Ce qui doit rester lisible ou
     touchable en bas d'une page ou d'un écran lui réserve cette hauteur. */
  --pilule-reserve: calc(54px + 14px + env(safe-area-inset-bottom, 0px));
  --ok: #4caf50;
  --r: 8px;
  --r-lg: 14px;
  /* Hauteur de la barre collante : les ancres s'en servent pour ne pas
     atterrir dessous. */
  --barre: 60px;
  --font: 'Montserrat', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
}

html {
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--barre) + 14px);
}

body {
  background: var(--bg);
  color: var(--text);
  font: 400 16px/1.6 var(--font);
  -webkit-font-smoothing: antialiased;
  /* iOS gonfle le texte en paysage si on ne l'en empêche pas. */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  /* Ceinture : clip (et pas hidden) ne casse pas la barre collante. */
  overflow-x: clip;
}

/* LE CORÉEN SE COUPE ENTRE LES MOTS, PAS ENTRE LES SYLLABES. Par défaut le
   navigateur le traite comme le chinois et coupe n'importe où : « 라이선스 »
   en fin de ligne devient « 라이선 / 스 », ce qu'aucun lecteur coréen n'écrit.
   `keep-all` garde chaque mot entier et ne coupe qu'aux espaces. */
:lang(ko) { word-break: keep-all; }

a { color: inherit; }

/* Le bleu de sélection du navigateur est le seul endroit où une couleur
   entrait sans y avoir été invitée : l'adresse de l'app se sélectionne
   pour être copiée à la main. */
::selection { background: rgba(255, 255, 255, 0.22); color: #fff; }

.contenu { max-width: 1060px; margin: 0 auto; padding: 0 clamp(18px, 5vw, 24px); }

/* ---------- Barre ---------- */

.barre {
  position: sticky;
  top: 0;
  z-index: 10;
  background: rgba(14, 14, 14, 0.82);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--line);
}
.barre .contenu {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: var(--barre);
  gap: 12px;
}
.logo {
  font-weight: 600;
  font-size: 20px;
  letter-spacing: 6px;
  text-decoration: none;
  white-space: nowrap;
}
.barre nav { display: flex; gap: 10px; align-items: center; }
.barre nav a { text-decoration: none; font-size: 14px; color: var(--muted); padding: 8px 10px; }

/* ---------- Boutons ---------- */

.bouton {
  display: inline-block;
  background: #eaeaea;
  color: #0e0e0e;
  border: 0;
  border-radius: var(--r);
  padding: 13px 26px;
  font: 600 15px var(--font);
  text-decoration: none;
  cursor: pointer;
  /* Le survol s'adoucit, la pression répond au quart de tour. */
  transition: filter 150ms ease, transform 120ms cubic-bezier(0.215, 0.61, 0.355, 1);
}
.bouton.discret {
  background: var(--raised);
  color: var(--text);
  border: 1px solid var(--line);
}
.bouton.large { padding: 16px 34px; font-size: 17px; }
.bouton s { opacity: 0.45; font-weight: 400; margin-left: 2px; }
/* Sous-ligne du bouton d'achat : « paiement unique », dans le bouton et pas
   a cote. C'est la, au moment de cliquer, que la question de l'abonnement se
   pose ; une precision posee sous le bouton arrive trop tard (demande
   d'Arthur, 01/09/2026). Le bouton passe en bloc pour porter deux lignes. */
.bouton small {
  display: block;
  font: 500 12px var(--font);
  opacity: 0.62;
  margin-top: 3px;
  letter-spacing: 0.01em;
}
.bouton:has(small) { line-height: 1.15; }
/* Sur un téléphone rien ne survole : le seul retour possible est la
   pression. Trois pour cent d'enfoncement suffisent à sentir le contact. */
.bouton:active { transform: scale(0.97); }
.faq summary:active { opacity: 0.65; }

@media (hover: hover) and (pointer: fine) {
  .bouton:hover { filter: brightness(0.88); }
  .bouton.discret:hover { background: var(--raised-2); filter: none; }
  .barre nav a:hover { color: var(--text); }
  .ouverture .ecouter:hover { color: var(--text); border-color: var(--muted); }
  .rappel-essai:hover { filter: brightness(0.88); }
  .rappel-prix:hover { color: var(--text); }
}

/* ---------- Le rappel collant ----------
   Une pilule fine en bas d'écran, révélée par le script une fois le hero
   passé. Fond translucide flouté et hairline : elle flotte sur la page
   sans jamais peser dessus. Invisible par défaut : sans JavaScript, elle
   n'existe pas. */
.rappel {
  position: fixed;
  left: 50%;
  bottom: calc(14px + env(safe-area-inset-bottom, 0px));
  z-index: 30;
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 5px;
  background: rgba(14, 14, 14, 0.72);
  -webkit-backdrop-filter: blur(16px);
  backdrop-filter: blur(16px);
  border: 1px solid rgba(255, 255, 255, 0.13);
  border-radius: 999px;
  box-shadow: 0 12px 34px rgba(0, 0, 0, 0.5);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transform: translate(-50%, 14px);
  transition: opacity 240ms ease, transform 240ms cubic-bezier(0.215, 0.61, 0.355, 1),
              visibility 0s 240ms;
}
.rappel.visible {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transform: translate(-50%, 0);
  transition-delay: 0s;
}
.rappel a {
  display: block;
  font: 600 14px var(--font);
  /* 13 px et non 9 : au doigt, un lien de 36 px de haut se rate. À 44 px
     la pilule reste fine, elle gagne 8 px. */
  padding: 13px 16px;
  border-radius: 999px;
  text-decoration: none;
  white-space: nowrap;
}
.rappel-essai { background: #eaeaea; color: #0e0e0e; }
.rappel-prix { color: var(--muted); }
/* Test des deux parcours (24/09/2026) : dans le parcours b, l'achat passe
   devant et prend le plein, l'essai recule. */
html.parcours-b .rappel-prix { order: -1; background: #eaeaea; color: #0e0e0e; }
html.parcours-b .rappel-essai { background: transparent; color: var(--muted); }
.ouverture .parcours-etapes { margin-top: 12px; }
/* Le verbe court ne sert que sur les petits écrans, quand « Premium · »
   n'a plus la place : un prix seul n'est pas une action. */
.rappel .court { display: none; }

/* ---------- Hero ---------- */

.ouverture .ecran { padding-top: 96px; padding-bottom: 72px; text-align: center; }
/* Le titre en deux tons : le constat s'efface, le manque prend toute la
   lumière. Le blanc pur est réservé à ce qui doit dominer. */
.ouverture h1 {
  font-size: clamp(40px, min(11vw, 8.5svh), 104px);
  font-weight: 600;
  line-height: 1.05;
  letter-spacing: -0.02em;
  max-width: 15ch;
  margin: 0 auto;
  text-wrap: balance;
}
/* La phrase est une antithèse : on concède, puis on retourne. Le premier
   membre doit donc se LIRE, sinon la chute tombe dans le vide. À 0,44 em
   et en --muted, il portait exactement la couleur de la ligne « Synthèse
   explosion... » juste en dessous : le lecteur y voyait un sous-titre
   parmi deux, pas la première ligne du titre. À 0,62 em et en gris clair,
   il redevient un membre de la phrase, sans jamais disputer la vedette à
   la chute, qui garde le blanc pur et 1,6 fois sa taille. */
.ouverture .constat {
  display: block;
  font-size: 0.62em;
  font-weight: 500;
  letter-spacing: -0.01em;
  color: #c4c4c4;
  margin-bottom: 0.34em;
}
.ouverture .punch { display: block; color: #fff; }
.ouverture .sous {
  max-width: 40ch;
  margin: clamp(18px, 2.6svh, 28px) auto 0;
  color: var(--muted);
  font-size: clamp(15px, min(1.9vw, 2.2svh), 19px);
  text-wrap: balance;
}
.ouverture .actions {
  display: flex;
  gap: 14px;
  justify-content: center;
  flex-wrap: wrap;
  margin-top: 34px;
}
/* Côte à côte, les deux boutons prennent la hauteur du plus grand : celui
   d'achat porte une seconde ligne (« paiement unique »). Le texte
   d'« Essayer dans ta Tesla » restait alors collé en haut de son bouton
   étiré (Arthur, 25/09/2026). Un bouton d'une seule ligne se centre donc
   dans sa hauteur ; celui qui porte la sous-ligne la remplit déjà. */
.ouverture .actions .bouton:not(:has(small)) {
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.ouverture .precision { margin-top: 14px; color: var(--faint); font-size: 13px; }
/* La consigne du téléphone : le seul geste qui mène à l'app, donc plus
   lisible que la ligne de rassurance, et jamais sacrifiée sur un petit
   écran : c'est le passage du téléphone à la voiture. */
.ouverture .consigne-telephone { margin-top: 14px; font-size: 15px; line-height: 1.45; color: var(--muted); }
.ouverture .consigne-telephone strong { color: var(--text); font-weight: 600; white-space: nowrap; }
.dans-la-voiture .ouverture .consigne-telephone { display: none; }
/* L'écoute, entre l'accroche et les boutons. Depuis un téléphone, entendre
   est la seule chose que la page peut vraiment donner, et c'est le geste qui
   prédit l'achat : elle passe donc AVANT les deux boutons, pas après. Un
   lien, pas un troisième bouton : la hiérarchie essayer / débloquer reste,
   l'écoute s'y glisse. Dans la voiture on entend le vrai, le lien s'efface. */
.ouverture .ecoute-invite { margin-top: 20px; }
.ouverture .ecouter {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  color: var(--muted);
  font: 500 14px var(--font);
  text-decoration: none;
  border-bottom: 1px solid var(--raised-2);
  padding-bottom: 3px;
}
.ouverture .ecouter svg { width: 11px; height: 11px; fill: currentColor; flex: none; }
.dans-la-voiture .ouverture .ecoute-invite { display: none; }

/* LE LECTEUR DE L'ACCROCHE. Pas une carte : dans le hero il n'y a rien
   d'autre que du texte centré, et une boîte y ferait un bloc de formulaire.
   Un bouton rond plein et une onde suffisent à dire « ça se joue », et le
   bouton blanc sur le fond noir est ce que l'oeil trouve en premier après
   le titre. Largeur bornée : sur un écran large, une onde de 900 px se lit
   comme une frise décorative, pas comme un lecteur. */
.ouverture .ecoute-hero {
  width: 100%;
  margin: 20px auto 0;
  max-width: 430px;
  text-align: left;
}
.ouverture .ecoute-hero .ecoute-piste { margin-top: 0; gap: 14px; }
/* Plus petit qu'en bas de page : là-bas le lecteur est le sujet de la
   section, ici il partage l'écran avec l'accroche et deux boutons. */
.ouverture .ecoute-hero .ecoute-bouton { width: 44px; height: 44px; }
.ouverture .ecoute-hero .ecoute-bouton svg { width: 18px; height: 18px; }
.ecoute-hero-corps { flex: 1; min-width: 0; display: block; }
.ecoute-hero-tete {
  display: block;
  font: 500 13px/1.3 var(--font);
  color: var(--muted);
}
.ouverture .ecoute-hero .ecoute-onde-cadre { margin-top: 7px; }
.ouverture .ecoute-hero .ecoute-onde { height: 30px; }
.dans-la-voiture .ouverture .ecoute-hero { display: none; }

/* Le témoin de lancement : un voyant de tableau de bord, seul rouge de la
   page. Il respire lentement, comme un témoin allumé, pas comme une alerte. */
.temoin {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--red);
  box-shadow: 0 0 0 3px rgba(232, 33, 39, 0.16);
  align-self: center;
  flex: none;
  animation: respire 2.6s ease-in-out infinite;
}
@keyframes respire { 50% { opacity: 0.3; } }

/* Le quota : la raison de ne pas remettre à demain, en une ligne sobre.
   Le témoin reste dans le fil du texte (et non en colonne flex), sinon il
   se décolle de sa phrase dès qu'elle est centrée ou repliée. */
.quota-offre {
  color: var(--muted);
  font-size: 13px;
  margin-top: 10px;
}
.quota-offre .temoin {
  display: inline-block;
  vertical-align: middle;
  margin-right: 8px;
  position: relative;
  top: -1px;
}
.prix-bloc .quota-offre { max-width: 34ch; margin-inline: auto; }

/* ---------- Sections ---------- */

section { padding: 72px 0; border-top: 1px solid var(--line); }
.titre-section {
  font-size: clamp(24px, 4vw, 34px);
  font-weight: 600;
  letter-spacing: -0.3px;
  max-width: 24ch;
  text-wrap: balance;
}
.intro-section { color: var(--muted); max-width: 64ch; margin-top: 14px; }

/* ---------- L'extrait sonore ----------
   Le seul endroit de la page où le produit se juge sur ce qu'il est. Tout
   le reste en parle.

   Le lecteur natif tient la place tant que le script n'a pas pris la main :
   la page ne doit pas se retrouver avec un bouton mort si le JavaScript
   échoue. C'est aussi pour ça que le bloc n'est pas caché par défaut. */

.ecoute {
  margin-top: 34px;
  padding: clamp(18px, 2.6vw, 24px) clamp(18px, 2.6vw, 26px);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
}
.ecoute-tete {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 16px;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: var(--faint);
}
.ecoute-duree { flex: none; font-variant-numeric: tabular-nums; }
.ecoute-natif { display: block; width: 100%; margin-top: 16px; }
/* Le lecteur natif s'efface dès que le script a pris la main. Il n'est pas
   retiré du document : il reste la source du son. */
.ecoute-natif.cache { display: none; }

.ecoute-piste {
  display: flex;
  align-items: center;
  gap: clamp(14px, 2.4vw, 22px);
  margin-top: 18px;
}
.ecoute-bouton {
  flex: none;
  width: 52px;
  height: 52px;
  border: 0;
  border-radius: 50%;
  background: var(--text);
  color: var(--bg);
  cursor: pointer;
  display: grid;
  place-items: center;
  padding: 0;
  transition: transform 120ms ease;
}
.ecoute-bouton:active { transform: scale(0.94); }
.ecoute-bouton svg { width: 22px; height: 22px; fill: currentColor; grid-area: 1 / 1; }
/* Un seul des deux pictogrammes à la fois, et ils se superposent : la
   largeur du bouton ne bouge pas au moment où on appuie. */
.ecoute-bouton .ecoute-pause { display: none; }
.ecoute-piste.joue .ecoute-bouton .ecoute-lire { display: none; }
.ecoute-piste.joue .ecoute-bouton .ecoute-pause { display: block; }

/* L'onde. Deux fois les mêmes barres : les mortes en gris, les vives en
   blanc, découpées par un rectangle que la lecture pousse vers la droite.
   Un seul jeu de barres dans le HTML, le second est un <use>. */
/* Le cadre porte la largeur, le SVG la remplit. Un SVG posé directement en
   item de flex garde sa taille intrinsèque (600 x 64 unités) et peint
   par-dessus les bords de la carte : constaté, l'onde traversait la page
   d'un bord à l'autre. */
.ecoute-onde-cadre {
  flex: 1;
  min-width: 0;
  overflow: hidden;
}
.ecoute-onde {
  display: block;
  width: 100%;
  height: 64px;
  cursor: pointer;
  touch-action: manipulation;
}
.ecoute-onde-morte { fill: var(--raised-2); }
.ecoute-onde-vive { fill: #fff; }

.ecoute-garde {
  margin-top: 16px;
  color: var(--faint);
  font-size: 13px;
  max-width: 62ch;
}

@media (max-width: 720px) {
  .ecoute { margin-top: 26px; }
  .ecoute-tete { font-size: 10px; letter-spacing: 1.2px; }
  .ecoute-bouton { width: 46px; height: 46px; }
  .ecoute-onde { height: 52px; }
  .ecoute-garde { font-size: 12.5px; }
}

/* ---------- La fiche technique ----------
   Six lignes numérotées, plus six pavés. Les cartes d'avant portaient
   quatre lignes de prose chacune sur fond gris : elles pesaient autant
   qu'une capture d'écran pour un contenu que personne ne lit debout au
   milieu d'une page de vente. Ici le numéro sert de repère, le nom porte
   l'argument, et la ligne dessous tient en une phrase. Pas de fond, pas
   de bordure : un filet par ligne, comme une vraie fiche. */
.fiche {
  list-style: none;
  counter-reset: fiche;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(310px, 100%), 1fr));
  gap: 0 clamp(24px, 4.5vw, 56px);
  margin-top: 44px;
}
.fiche li {
  counter-increment: fiche;
  display: grid;
  grid-template-columns: 32px 1fr;
  padding: 17px 0;
  border-top: 1px solid var(--line);
}
.fiche li::before {
  content: counter(fiche, decimal-leading-zero);
  grid-row: 1 / 3;
  align-self: start;
  padding-top: 3px;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 1px;
  color: var(--faint);
  font-variant-numeric: tabular-nums;
}
.fiche strong { font-size: 15.5px; font-weight: 600; color: var(--text); }
.fiche span {
  color: var(--muted);
  font-size: 14px;
  line-height: 1.5;
  margin-top: 3px;
}

/* ---------- Le bloc des versions ----------
   Le seul argument de la page qui parle de la voiture DU LECTEUR : il
   garde un fond, c'est ce qui le détache de la fiche juste au-dessus. */
.versions {
  margin-top: clamp(40px, 6vw, 64px);
  padding: clamp(22px, 3.4vw, 32px);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
}
.versions h3 { font-size: clamp(18px, 2.4vw, 22px); font-weight: 600; }
.versions > p {
  color: var(--muted);
  font-size: 14.5px;
  margin-top: 8px;
  max-width: 62ch;
}
/* Les quatre réglages qui bougent, en instruments : le nom au-dessus, la
   raison en dessous. Quatre d'affilée dès qu'il y a de la place, empilés
   sur un téléphone : chaque case porte une phrase entière, pas un chiffre,
   et deux colonnes de 146 px la hacheraient. */
.recale {
  list-style: none;
  display: grid;
  gap: 18px clamp(16px, 2.4vw, 28px);
  margin-top: 22px;
}
/* Un, deux ou quatre colonnes, jamais trois : à trois, la quatrième case
   reste seule sur une deuxième rangée et la lecture s'arrête dessus. */
@media (min-width: 560px) { .recale { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 940px) { .recale { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.recale li { border-top: 1px solid var(--line); padding-top: 12px; }
.recale strong {
  display: block;
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  margin-bottom: 5px;
}
.recale span { display: block; color: var(--muted); font-size: 13px; line-height: 1.45; }

/* ---------- Garage ----------
   EN PHOTOS depuis le 30/09/2026 : les voitures du studio de la boutique et
   de l'app, sur des cartes, là où il n'y avait que des noms. */

/* Ce que la licence contient, dit une fois, juste au-dessus des cinq. Coche
   neutre et pas verte : le vert dit « c'est à toi », et le lecteur n'a encore
   rien acheté. */
.garage-inclus {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 22px;
  font-size: 14.5px;
  font-weight: 500;
}
.garage-inclus .coche {
  flex: none;
  width: 22px;
  height: 22px;
  padding: 6px 5px;
  border-radius: 50%;
  background: var(--raised-2);
  fill: none;
  stroke: var(--text);
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.galerie {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
  margin-top: 18px;
}
/* Sur un téléphone, l'Audi RS 3 prend toute la largeur et les quatre autres
   vont deux par deux : en deux colonnes, la cinquième carte restait seule au
   bout, et c'est la voix de l'accroche qui ouvre le garage. */
.galerie .voiture:first-child { grid-column: 1 / -1; }
/* Dès qu'il y a la place, fenêtre de la voiture comprise (773 px) : trois
   puis deux, centrées. Six colonnes, deux par carte, et la quatrième commence
   à la deuxième. */
@media (min-width: 560px) {
  .galerie { grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 12px; }
  .galerie .voiture,
  .galerie .voiture:first-child { grid-column: span 2; }
  .galerie .voiture:nth-child(4) { grid-column: 2 / span 2; }
}
.voiture {
  display: flex;
  flex-direction: column;
  background: var(--raised);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  overflow: hidden;
  transition: border-color 200ms ease;
}
.voiture img { display: block; width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: cover; }
.voiture-corps { display: flex; flex-direction: column; flex: 1; min-width: 0; padding: 12px 14px 14px; }
.voiture-nom { display: block; font-size: 15px; font-weight: 600; line-height: 1.3; }
.voiture-sous { display: block; font-size: 12.5px; line-height: 1.45; color: var(--muted); margin-top: 2px; }
/* Le bouton descend au pied de la carte : sur une même rangée, les
   « Écouter » s'alignent quelle que soit la longueur des sous-titres. */
.voiture-corps > .bouton.ecouter { align-self: flex-start; margin-top: auto; }
.galerie .voiture-sous { margin-bottom: 12px; }
.voiture .moteur-plan { width: 34px; height: 17px; fill: var(--muted); }
.voiture .bouton.ecouter { padding: 7px 12px; font-size: 13px; }
/* Celle qu'on écoute se détache, sans couleur : un filet plus clair. */
.voiture.joue { border-color: rgba(255, 255, 255, 0.34); }

/* Le plan à gauche, la pastille à droite : une tête de plaque. Avant, la
   pastille suivait le sous-titre en ligne et se lisait « Phase 2
   GRATUIT », au milieu d'une phrase. */
.moteur-tete {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 7px;
}
.voiture.libre em { font-style: normal; color: var(--ok); font-size: 11.5px; letter-spacing: 1px; }

/* LA COMMUNAUTÉ, dans un panneau : ce qui n'est pas dans la licence ne doit
   pas se lire comme la suite des cinq cartes. Sur un téléphone, le bouton
   vient APRÈS le classement, qu'il prolonge ; sur un écran large, deux
   colonnes (le texte et son bouton, le classement) et les moteurs vendus à
   l'unité en travers dessous, l'un sous l'autre. Sans classement (serveur muet), une seule colonne : une
   moitié vide se lirait comme une panne. */
.communaute {
  display: grid;
  grid-template-areas: "tete" "top" "lien" "nouveau" "note";
  gap: 26px;
  margin-top: clamp(40px, 6vw, 60px);
  padding: clamp(20px, 3vw, 32px);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
}
.communaute-tete { grid-area: tete; }
.communaute-top { grid-area: top; }
.communaute-lien { grid-area: lien; }
.communaute .nouveaux-moteurs { grid-area: nouveau; display: grid; gap: 16px; }
.communaute-note { grid-area: note; }
@media (min-width: 860px) {
  .communaute {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    grid-template-areas: "tete top" "lien top" "nouveau nouveau" "note note";
    column-gap: clamp(28px, 4vw, 48px);
  }
  .communaute:has(> .communaute-top[hidden]) {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "tete" "lien" "nouveau" "note";
  }
  .communaute-lien { align-self: start; }
}
.communaute-etiquette,
.communaute-sous {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 1.8px;
  text-transform: uppercase;
  color: var(--muted);
}
.communaute-titre {
  margin-top: 8px;
  font-size: clamp(22px, 3vw, 28px);
  font-weight: 600;
  letter-spacing: -0.3px;
  line-height: 1.2;
  text-wrap: balance;
}
.communaute-texte { margin-top: 10px; color: var(--muted); font-size: 15px; max-width: 46ch; }
.communaute-chiffres { list-style: none; display: flex; gap: clamp(24px, 4vw, 40px); margin-top: 22px; }
/* `display: flex` l'emporterait sur `hidden` : sans chiffres, pas d'étiquettes seules. */
.communaute-chiffres[hidden] { display: none; }
.communaute-chiffres li { display: flex; flex-direction: column; }
.communaute-chiffres strong {
  font-size: clamp(30px, 4vw, 40px);
  font-weight: 600;
  letter-spacing: -0.5px;
  line-height: 1.05;
  font-variant-numeric: tabular-nums;
}
.communaute-chiffres span { font-size: 12.5px; color: var(--muted); margin-top: 4px; }
.communaute-sous { margin-bottom: 10px; }

/* Le classement : même dessin que les cartes de /what-next, en lecture
   seule (le vote se fait là-bas, licence en main). */
.demandes { list-style: none; display: grid; gap: 8px; counter-reset: rang; }
.demande {
  counter-increment: rang;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px 10px 10px;
  background: var(--raised);
  border: 1px solid var(--line);
  border-radius: var(--r);
}
.demande::before {
  content: counter(rang);
  flex: none;
  width: 14px;
  text-align: center;
  font-size: 14px;
  font-weight: 600;
  color: var(--muted);
}
.demande img { flex: none; width: 88px; height: auto; aspect-ratio: 16 / 9; object-fit: cover; border-radius: 6px; }
.demande-texte { flex: 1; min-width: 0; }
/* Un nom de soixante caractères sans espace ne doit pas pousser les voix
   hors de la carte. */
.demande-nom { display: block; font-size: 14.5px; font-weight: 600; line-height: 1.3; overflow-wrap: anywhere; }
.demande-par { display: block; font-size: 12px; color: var(--muted); margin-top: 1px; }
.demande-votes {
  flex: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  min-width: 46px;
  padding: 7px 4px;
  border: 1px solid var(--line);
  border-radius: var(--r);
  font-size: 14px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.demande-votes svg { width: 11px; height: 7px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; opacity: 0.75; }

/* Le moteur vendu à l'unité : une carte couchée, la photo à gauche dès qu'il
   y a la place. */
@media (min-width: 560px) {
  .nouveau-moteur { flex-direction: row; }
  .nouveau-moteur img { flex: none; width: 44%; max-width: 400px; align-self: stretch; height: auto; }
  .nouveau-moteur .voiture-corps { justify-content: center; padding: 16px 20px; }
}
.nouveau-moteur .carte-statut { flex: none; }
.nouveau-moteur .voiture-nom { font-size: 18px; }
.nouveau-prix { margin-top: 12px; font-size: 13.5px; color: var(--muted); }
.nouveau-prix strong { color: var(--text); font-size: 17px; font-weight: 600; margin-right: 4px; }
.voiture-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 18px; margin-top: 14px; }
.lien-boutique { font-size: 14px; color: var(--text); text-underline-offset: 3px; }
.communaute-note { font-size: 13px; line-height: 1.55; color: var(--faint); }

/* Le plan de cylindres : un point par cylindre, posés comme dans le bloc.
   Il porte ce que le sous-titre ne disait qu'à moitié - en ligne, en V, à
   plat - et il le porte SANS une phrase de plus, ce qui est tout l'objet
   de la manoeuvre. Le sprite ne doit pas se replier en display: none :
   certains navigateurs cessent alors de servir ses symboles au <use>. */
.plans { position: absolute; width: 0; height: 0; overflow: hidden; }
.moteur-plan {
  display: block;
  width: 40px;
  height: 20px;
  flex: none;
  fill: var(--faint);
}

/* ---------- Étapes ---------- */

.etapes { counter-reset: etape; display: grid; gap: 0; margin-top: 36px; }
.etape {
  counter-increment: etape;
  display: grid;
  grid-template-columns: 56px 1fr;
  gap: 18px;
  padding: 22px 0;
  border-top: 1px solid var(--line);
}
.etape::before {
  content: counter(etape);
  font-size: 26px;
  font-weight: 600;
  color: var(--faint);
}
.etape h3 { font-size: 16px; font-weight: 600; }
.etape p { color: var(--muted); font-size: 14.5px; margin-top: 4px; }
.etape code {
  font: 500 13.5px ui-monospace, 'SF Mono', Menlo, monospace;
  background: var(--raised);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 2px 8px;
}

/* ---------- Lancer l'app : deux écrans, deux gestes ----------
   Sur un téléphone, il n'y a rien à lancer : l'adresse est l'objet du
   bloc, en grand, copiable. Sur l'écran de la voiture, c'est l'inverse,
   et les deux versions s'échangent sur la classe posée dans le <head>. */

.lancer {
  margin-top: 28px;
  padding: 26px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
}
.lancer-quoi { color: var(--muted); font-size: 14px; }
.adresse-app {
  font: 600 clamp(22px, 4.6vw, 34px)/1.25 var(--font);
  letter-spacing: -0.01em;
  margin-top: 8px;
  /* Une adresse qu'on va retaper au doigt sur un écran de voiture ne doit
     jamais être coupée en deux lignes muettes. */
  overflow-wrap: anywhere;
}
/* Deux boutons : un flex avec gouttière, pour qu'ils ne se touchent ni
   côte à côte ni empilés sur un téléphone. */
.lancer-actions { margin-top: 18px; display: flex; flex-wrap: wrap; gap: 10px; }
.lancer-secours { margin-top: 16px; color: var(--faint); font-size: 13px; }
.lancer-secours a { color: var(--muted); }
/* Le secours sert à une voiture que le test du <head> n'a pas reconnue. Un
   téléphone, lui, s'en servait pour lancer sur place l'app faite pour la
   voiture, et souvent. Aucune voiture ne s'annonce comme un
   téléphone, donc ce secours-là reste entier pour elles. L'écoute et l'achat
   ont leurs propres boutons plus haut. */
.sur-telephone .lancer-secours { display: none; }

/* La version voiture n'existe que là-bas, et l'adresse n'y sert plus. */
.lancer-voiture { display: none; }
.lancer-voiture span { display: block; margin-top: 14px; color: var(--muted); font-size: 14px; }
.dans-la-voiture .lancer-adresse { display: none; }

/* Le lien par email : sous les boutons, séparé d'un filet, un champ et un
   bouton côte à côte (empilés sous 400 px, où ils se disputeraient la
   largeur). 16 px pile dans le champ : en dessous, iOS zoome à la saisie. */
.lien-mail { margin-top: 20px; padding-top: 18px; border-top: 1px solid var(--line); max-width: 460px; }
.lien-mail label { display: block; color: var(--muted); font-size: 14px; }
.lien-mail-ligne { display: flex; gap: 10px; margin-top: 10px; }
.lien-mail input {
  flex: 1;
  min-width: 0;
  background: var(--raised);
  border: 1px solid var(--line);
  border-radius: var(--r);
  color: var(--text);
  padding: 11px 14px;
  font: 400 16px var(--font);
}
.lien-mail .bouton:disabled { opacity: 0.55; cursor: default; }
.lien-mail-note { margin-top: 10px; color: var(--faint); font-size: 12.5px; max-width: 54ch; }
.lien-mail-note a { color: var(--muted); }
.lien-mail-retour { margin-top: 10px; font-size: 14px; }
.lien-mail-retour:empty { display: none; }
@media (max-width: 400px) {
  .lien-mail-ligne { flex-direction: column; }
  .lien-mail .bouton { width: 100%; }
}
.dans-la-voiture .lancer-voiture { display: block; }
/* L'étape « ouvre le navigateur de la voiture, tape l'adresse » n'a pas de
   sens quand on la lit dans ce navigateur : elle s'efface, et le compteur
   des étapes repart de un tout seul. */
.dans-la-voiture .etape:first-child { display: none; }

/* LA VOITURE QUI NE PEUT PAS FAIRE TOURNER L'APP (classe `navigateur-ancien`,
   posée dans le <head> de la vitrine et de /achat, 21/10/2026) : une Model S
   ou X restée sur son écran d'origine (MCU1). Tout ce qui mène à l'app ou au
   paiement disparaît, et l'avis dit pourquoi à la place. Le lien d'achat de
   la FAQ reste : il est au milieu d'une phrase, et la FAQ dit l'exception.
   Couleurs en clair AVANT les variables : rien ne garantit que ce navigateur
   lise les propriétés personnalisées. */
.avis-ancien { display: none; }
.navigateur-ancien .avis-ancien {
  display: block;
  max-width: 560px;
  margin: 26px auto 8px;
  padding: 16px 18px;
  border: 1px solid #3a3a3a;
  border: 1px solid var(--raised-2);
  border-radius: 14px;
  border-radius: var(--r-lg);
  text-align: left;
}
.avis-ancien strong { display: block; font-size: 17px; font-weight: 600; margin-bottom: 6px; }
.avis-ancien span { display: block; font-size: 15px; line-height: 1.5; color: #9a9a9a; color: var(--muted); }
.navigateur-ancien .ancien-autre,
.navigateur-ancien.mcu1 .ancien-mcu1 { display: block; }
.navigateur-ancien .ancien-mcu1,
.navigateur-ancien.mcu1 .ancien-autre { display: none; }
.navigateur-ancien #cta-app,
.navigateur-ancien [data-lien-app],
.navigateur-ancien a.bouton[href^="/achat"],
.navigateur-ancien #rappel,
.navigateur-ancien .lancer-voiture,
.navigateur-ancien .lancer-secours,
.navigateur-ancien #payer-ligne,
.navigateur-ancien #offre-tout,
.navigateur-ancien #ouvrir-app,
.navigateur-ancien #note-tesla,
.navigateur-ancien #note-appairage { display: none !important; }

/* ---------- Prix ---------- */

/* Le nombre de licences vendues, juste au-dessus des cartes (27/10/2026). */
.preuve-offres { color: var(--text); font-size: 15px; font-weight: 500; margin-top: 18px; }
.offres {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
  gap: 16px;
  margin-top: 40px;
  max-width: 760px;
}
.offre {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: 30px 28px;
  display: flex;
  flex-direction: column;
  gap: 0;
}
.offre.mise-en-avant { border-color: rgba(255, 255, 255, 0.28); }
/* La carte du tout inclus : le contour le plus net de la page, une pastille,
   et le prix en blanc et plus grand que les autres (16/10/2026). */
.offre.offre-tout { border: 1.5px solid #eaeaea; position: relative; background: linear-gradient(180deg, rgba(255, 255, 255, 0.06), var(--surface) 55%); }
.offre.offre-tout .prix { font-size: 48px; color: #fff; }
.offre.offre-tout h3 { color: var(--text); }
.offre-badge {
  position: absolute;
  top: -12px;
  right: 22px;
  background: #eaeaea;
  color: #0e0e0e;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  padding: 5px 11px;
  border-radius: 100px;
}
.offre h3 { font-size: 15px; font-weight: 600; letter-spacing: 2px; text-transform: uppercase; color: var(--muted); }
.offre .prix { font-size: 40px; font-weight: 600; margin-top: 10px; }
.offre .periode { color: var(--faint); font-size: 13px; margin-top: 2px; }
.offre ul { list-style: none; margin: 22px 0 26px; display: grid; gap: 10px; }
.offre li { font-size: 14.5px; padding-left: 26px; position: relative; color: var(--text); }
.offre li.non { color: var(--faint); }
.offre li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 7px;
  width: 14px;
  height: 8px;
  border-left: 2px solid var(--muted);
  border-bottom: 2px solid var(--muted);
  transform: rotate(-45deg);
}
.offre li.non::before { border-color: var(--faint); width: 12px; height: 0; transform: none; top: 11px; }
/* Rembourrage latéral réduit : à 26 px la sous-ligne « Paiement unique, à
   vie. Pas un abonnement. » se repliait sur deux lignes dans la colonne de
   372 px du bureau. */
.offre .bouton { margin-top: auto; text-align: center; padding-inline: 16px; }
.offre .bouton small { white-space: nowrap; }
.offre .precision-offre { margin-top: 10px; color: var(--faint); font-size: 12.5px; line-height: 1.5; }
/* Ces deux lignes disent où aller depuis un téléphone. Sur l'écran de la
   voiture on y est déjà, et les boutons pointent alors sur l'app. */
.dans-la-voiture .offre .precision-offre { display: none; }
/* LES LIGNES DES DEUX CARTES EN FACE L'UNE DE L'AUTRE (27/10/2026). Les deux
   cartes portent les mêmes six lignes, dans le même ordre, pour se comparer
   d'un coup d'oeil ; mais le prix du tout inclus est plus grand et certaines
   lignes passent sur deux lignes d'un seul côté, et chaque liste dérivait de
   l'autre. Une grille commune (subgrid) donne à chaque rangée la hauteur de
   la plus haute des deux. Onze rangées : titre, prix, période, six lignes,
   bouton, précision ; la pastille, en position absolue, n'en prend aucune.
   Sans subgrid, la mise en page d'avant reste telle quelle. */
@supports (grid-template-rows: subgrid) {
  .offre { display: grid; grid-row: span 11; grid-template-rows: subgrid; row-gap: 0; }
  .offre ul { display: contents; }
  .offre li { margin-top: 10px; }
  .offre li:first-child { margin-top: 22px; }
  .offre .bouton { margin-top: 26px; align-self: end; }
}

/* ---------- FAQ ---------- */

.faq { max-width: 760px; margin-top: 36px; }
.faq details { border-top: 1px solid var(--line); }
.faq summary {
  cursor: pointer;
  padding: 18px 0;
  font-weight: 600;
  font-size: 15.5px;
  list-style: none;
  display: flex;
  justify-content: space-between;
  gap: 16px;
}
.faq summary::after { content: '+'; color: var(--faint); font-size: 20px; }
.faq details[open] summary::after { content: '\2212'; }
.faq details p { color: var(--muted); font-size: 14.5px; padding: 0 0 18px; max-width: 68ch; }
/* La hauteur ne s'anime pas (elle coûte une mise en page par image) : la
   réponse se pose en fondu, l'oeil suit au lieu de sursauter. */
.faq details[open] p { animation: pose 180ms cubic-bezier(0.215, 0.61, 0.355, 1); }
@keyframes pose { from { opacity: 0; transform: translateY(-4px); } }


/* ---------- Pied ---------- */

footer { border-top: 1px solid var(--line); padding: 40px 0 60px; }
/* Sous la vitrine, la pilule collante est toujours là en bas de page : sans
   cette réserve elle recouvrait « Mentions légales », « CGV » et
   « Contact », les seuls liens légaux et le seul contact de la page. */
footer.avec-rappel { padding-bottom: calc(60px + var(--pilule-reserve)); }
footer .contenu { display: flex; flex-wrap: wrap; gap: 24px; justify-content: space-between; align-items: baseline; }
footer p, footer a { color: var(--faint); font-size: 13px; }
footer nav { display: flex; gap: 20px; flex-wrap: wrap; align-items: center; }

/* Le choix de langue du pied de page. Discret comme les liens qui l'entourent :
   c'est un réglage, pas une invitation. */
.choix-langue select {
  appearance: none;
  background: transparent url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='7'><path d='M1 1l4 4 4-4' stroke='%23777' stroke-width='1.6' fill='none' stroke-linecap='round' stroke-linejoin='round'/></svg>") no-repeat right center;
  border: 0;
  padding: 2px 16px 2px 0;
  color: var(--faint);
  font: inherit;
  font-size: 13px;
  cursor: pointer;
}
.choix-langue select:hover { color: var(--text); }

/* ---------- Pages achat / merci ---------- */

.page-etroite {
  max-width: 560px;
  margin: 0 auto;
  padding: 80px 24px 120px;
  text-align: center;
}
.page-etroite h1 { font-size: 32px; font-weight: 600; letter-spacing: -0.3px; }
.page-etroite .sous { color: var(--muted); margin-top: 14px; }
.prix-bloc { margin: 34px 0 8px; }
.prix-bloc strong { font-size: 56px; font-weight: 600; }
.prix-bloc s { font-size: 24px; color: var(--faint); margin-left: 12px; }
.prix-bloc .periode { color: var(--muted); font-size: 14px; margin-top: 4px; }
/* Le tout inclus de la page d'achat (16/10/2026) : un second bloc, séparé du
   premier par un filet, sous Premium ou au-dessus quand la voiture l'a choisi. */
.offre-achat-tout { margin: 28px 0; padding-top: 24px; border-top: 1px solid var(--line); }
.offre-achat-titre { font-size: 20px; font-weight: 600; margin: 0; }
.offre-achat-tout .sous { margin-top: 6px; }
.avantages {
  list-style: none;
  text-align: left;
  margin: 30px auto;
  max-width: 380px;
  display: grid;
  gap: 10px;
  color: var(--muted);
  font-size: 14.5px;
}
.avantages li { padding-left: 24px; position: relative; }
.avantages li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 7px;
  width: 13px;
  height: 7px;
  border-left: 2px solid var(--muted);
  border-bottom: 2px solid var(--muted);
  transform: rotate(-45deg);
}
/* La question de la page merci : des réponses en pastilles qui passent à la
   ligne, la choisie en clair, les autres en retrait. Monochrome, comme le
   reste : une couleur d'accent ferait croire à une réponse attendue. */
.decouverte { margin-top: 38px; padding-top: 26px; border-top: 1px solid var(--line); }
.decouverte-q { color: var(--text); font-size: 15px; }
.decouverte-choix { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; margin-top: 14px; }
.decouverte-choix .bouton { padding: 10px 14px; font-size: 14px; font-weight: 500; }
.decouverte-choix .bouton[aria-pressed="true"] { background: #eaeaea; color: #0e0e0e; border-color: #eaeaea; }
.decouverte-merci { margin-top: 12px; color: var(--muted); font-size: 14px; }
.decouverte-merci:empty { display: none; }
.appairage-note {
  background: var(--raised);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 12px 16px;
  font-size: 13.5px;
  color: var(--muted);
  margin: 22px 0;
}
.code-licence {
  font: 600 30px ui-monospace, 'SF Mono', Menlo, monospace;
  letter-spacing: 3px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: 22px 18px;
  margin: 30px 0 12px;
  user-select: all;
}
.attente { color: var(--muted); animation: pulse 1.6s ease-in-out infinite; }
@keyframes pulse { 50% { opacity: 0.45; } }
/* Merci sur un téléphone : la consigne remplace le bouton qui ouvrait l'app
   sur place. Même encadré que la note d'appairage de la page d'achat : c'est
   la dernière chose à faire, elle doit se détacher du texte courant. */
.consigne-voiture { margin-top: 26px; font-size: 14.5px; line-height: 1.55; }
.consigne-voiture strong { color: var(--text); white-space: nowrap; }

/* ---------- rupteur.app/1 et /2 hors de la voiture ----------
   Ces adresses se tapent dans la voiture et y mènent droit à l'app. Ouvertes
   ailleurs, elles le disent, et l'adresse est l'objet de la page : en très
   gros, pour être relue d'un coup d'œil au moment de la retaper sur l'écran
   de la Tesla. */
.page-garde h1 { font-size: clamp(24px, 6.4vw, 32px); line-height: 1.25; text-wrap: balance; }
.page-garde .adresse-app { font-size: clamp(38px, 12vw, 56px); margin-top: 26px; }
.garde-actions { margin-top: 18px; }
.garde-aide { margin-top: 26px; color: var(--muted); font-size: 15px; line-height: 1.55; }
.garde-ecouter { margin-top: 30px; }
.garde-ici { margin-top: 30px; font-size: 13px; }
.garde-ici a { color: var(--faint); }

/* ---------- Pages légales ---------- */

.legal { max-width: 720px; margin: 0 auto; padding: 60px 24px 100px; }
.legal h1 { font-size: 30px; font-weight: 600; margin-bottom: 8px; }
.legal h2 { font-size: 18px; font-weight: 600; margin: 34px 0 10px; }
.legal p, .legal li { color: var(--muted); font-size: 14.5px; }
.legal ul { padding-left: 20px; }
.legal .date { color: var(--faint); font-size: 13px; }

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}

/* Le E du logotype : trois barres, sans fût (voir styles.css de l'app). */
.logo-e { height: 0.66em; width: auto; fill: currentColor; margin-right: 6px; }

/* ---------- Vraies captures de l'app ---------- */

.cadre-app { margin: 0; }
.cadre-app img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 14px;
  border: 1px solid var(--line);
  box-shadow: 0 30px 90px rgba(0, 0, 0, 0.55);
}
/* La grande capture qui ouvre le détail : l'app en situation, plein cadre. */
.capture-large { max-width: 880px; margin: 48px auto 0; }
.duo-captures {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
  gap: 20px;
  margin-top: 44px;
}
/* La légende appartient à la capture, pas à la grille qui la porte : la
   grande capture du mode d'emploi en a une aussi depuis que la section
   du QR a fondu dedans. */
.cadre-app figcaption {
  color: var(--faint);
  font-size: 13px;
  margin-top: 12px;
  max-width: 46ch;
}
.capture-large figcaption { max-width: 62ch; }

/* ---------- Rupteur Sound Technology ---------- */

/* La plaque RST : un badge de certification, pas un titre. Le monogramme
   à trois barres, un filet, le sigle en gros, le nom en petites capitales.
   width: fit-content : en item de grille, inline-flex se blockifie et
   s'étirerait sur toute la colonne. */
.plaque-rst {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  width: fit-content;
  padding: 11px 16px;
  background: var(--raised);
  border: 1px solid var(--raised-2);
  border-radius: 10px;
}
.plaque-rst svg { display: block; height: 24px; width: auto; fill: #fff; }
.plaque-rst .rst-texte {
  display: block;
  padding-left: 14px;
  border-left: 1px solid var(--line);
  text-align: left;
}
/* L'interlettrage se pose aussi après la dernière lettre : la marge
   négative le reprend pour que la plaque soit optiquement symétrique. */
.plaque-rst .rst-sigle {
  display: block;
  font-size: 19px;
  font-weight: 600;
  line-height: 1;
  letter-spacing: 7px;
  margin-right: -7px;
  color: #fff;
}
/* Le ™ s'aligne sur le SOMMET DES CAPITALES, pas au petit bonheur.
   Mesuré au canvas dans Montserrat 600 : une capitale monte à 0,70 em du
   corps, et le glyphe ™ monte à 0,70 em du SIEN (il est déjà surélevé, il
   ne descend jamais sous 0,285 em). Pour que les deux sommets coïncident :
   0,42 em de corps, remonté de 0,965 em de son propre corps, soit
   0,42 x (0,965 + 0,70) = 0,70 em du parent. Les deux valeurs sont
   solidaires : changer l'une sans l'autre décroche le ™. */
.tm {
  font-size: 0.42em;
  font-weight: 600;
  letter-spacing: 0;
  vertical-align: 0.965em;
}
/* Dans le sigle seul : l'interlettrage de 7 px se pose aussi après le T,
   et laisserait le ™ flotter loin de la lettre. */
.rst-sigle .tm { margin-left: -5px; }
/* Dans le logotype aussi : l'interlettrage de 6 px suit le R final et
   décollerait le ™ (marque déposée à l'INPI le 13/10/2026, n° 5308670). */
.logo .tm { margin-left: -5px; }
.plaque-rst .rst-nom {
  display: block;
  margin-top: 5px;
  font-size: 8.5px;
  font-weight: 500;
  line-height: 1;
  letter-spacing: 3.1px;
  margin-right: -3.1px;
  text-transform: uppercase;
  color: var(--muted);
}
.scene .plaque-rst { margin-bottom: min(24px, 2.8svh); }
#technique .plaque-rst { margin-bottom: 20px; }
/* ---------- Le mot du fondateur ----------
   Le seul endroit de la page où quelqu'un parle à la première personne.
   Pas de guillemets dessinés, pas de portrait : un trait vertical qui se
   trace en descendant, et une signature qui se pose. C'est un aparté dans
   la démonstration, pas un témoignage client. */

#atelier { padding: clamp(56px, 9vw, 104px) 0; }
.mot {
  position: relative;
  max-width: 62ch;
  margin: 0 auto;
  padding-left: clamp(22px, 4vw, 40px);
}
/* Le trait tient lieu de marge de cahier : il court sur toute la hauteur
   du texte et se trace du haut vers le bas, à la vitesse du pouce. */
.mot-trait {
  position: absolute;
  left: 0;
  top: 4px;
  bottom: 4px;
  width: 1px;
  background: linear-gradient(180deg, var(--raised-2), rgba(255, 255, 255, 0.02));
  transform-origin: top;
}
.mot-etiquette {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 3px;
  text-transform: uppercase;
  color: var(--faint);
  margin-bottom: 22px;
}
.mot p + p { margin-top: 16px; }
.mot p { color: var(--muted); }
/* La première phrase porte la voix : elle passe en blanc et au corps du
   sous-titre, le reste redescend au gris du texte courant. */
.mot p.mot-ouverture {
  color: #fff;
  font-size: clamp(20px, 2.8vw, 28px);
  font-weight: 500;
  line-height: 1.35;
  letter-spacing: -0.01em;
  text-wrap: balance;
}
.mot-signature {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-top: 30px;
  font-size: 14px;
  font-weight: 500;
  color: var(--text);
}
/* Le paraphe : un trait qui se tire de gauche à droite, comme on signe. */
.paraphe {
  display: block;
  width: clamp(34px, 6vw, 56px);
  height: 1px;
  background: var(--text);
  transform-origin: left;
  flex: none;
}

/* ---------- Ton prochain trajet ----------
   Le seul endroit de la page où le lecteur est au volant. Traité comme une
   respiration et pas comme une section : pas de titre, pas de carte, pas de
   bouton. Centré, parce que tout le reste du bas de page est aligné à
   gauche et que ce bloc doit s'entendre comme un aparté - le même geste que
   les scènes du haut, à qui il emprunte sa voix.

   Pas de CTA ici, et c'est délibéré : le rappel collant est déjà à un pouce
   en bas d'écran. Un bouton de plus au moment où on vient de projeter
   quelqu'un dans sa voiture, c'est une main sur l'épaule. */

#trajet { text-align: center; }
.trajet-etiquette {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 3px;
  text-transform: uppercase;
  color: var(--faint);
}
/* La scène passe en blanc et au corps d'un sous-titre : c'est le seul
   paragraphe de la page basse qui monte à ce niveau, et il le mérite. */
.trajet-scene {
  /* 34ch et pas 30 : à 30, la scène tombe sur cinq lignes au bureau et
     casse « le rupteur / arrive » en deux. */
  max-width: 34ch;
  margin: 20px auto 0;
  color: #fff;
  font-size: clamp(21px, 3vw, 28px);
  font-weight: 500;
  line-height: 1.32;
  letter-spacing: -0.01em;
  text-wrap: balance;
}
/* La chute redescend au gris : elle ne raconte plus, elle conclut. */
.trajet-chute {
  max-width: 44ch;
  margin: 22px auto 0;
  color: var(--muted);
  font-size: clamp(15px, 1.9vw, 18px);
}

/* ---------- Ce qu'ils en disent ----------
   Un mur de vidéos, des citations courtes en gros entre guillemets, une
   note légale en petit (28/09/2026 au soir, Arthur : « des trucs qui
   claquent »). Pas d'étoiles de notation ni de note moyenne : ce sont des
   paroles, pas des produits à comparer.

   La section porte `hidden` tant que la liste est vide, et c'est le script
   du bas de page qui la révèle. Aucune règle ici ne doit donc supposer
   qu'elle est affichée. */

/* Le mur : deux colonnes sur un téléphone, les portraits côte à côte et le
   paysage dessous sur toute la largeur ; sur un écran large, les trois sur
   une ligne, à HAUTEUR ÉGALE. Les colonnes sont dans le rapport des
   largeurs à hauteur égale : un portrait 9:16 fait 0,5625 fois sa hauteur,
   le paysage de Pete (960 x 552) 1,74 fois, soit 3,09 portraits. Chaque
   vidéo tire ses proportions de ses attributs width et height. Plafonné à
   560 px en deux colonnes : au-delà, la vidéo de Nicolas (268 px de large)
   serait agrandie, et un flou d'agrandissement ferait passer une vraie
   prise pour une mauvaise. */
.avis-videos {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  align-items: start;
  max-width: 560px;
  margin-top: 28px;
}
.avis-clip { margin: 0; min-width: 0; }
.avis-clip.paysage { grid-column: 1 / -1; }
@media (min-width: 720px) {
  .avis-videos { grid-template-columns: 1fr 1fr 3.09fr; gap: 16px; max-width: none; }
  .avis-clip.paysage { grid-column: auto; }
}
.avis-video {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--r);
  background: #000;
}
.avis-clip .avis-qui { margin-top: 8px; font-size: 12.5px; }

/* Les citations : courtes, grosses, blanches, entre guillemets. Les
   guillemets sont dessinés ici et non écrits dans les textes : la même
   citation vit dans dix langues, et ce sont un motif de la page, en gris,
   avec l'espace insécable du français. */
.avis { list-style: none; margin-top: 48px; }
.avis li { margin-top: 30px; }
.avis li:first-child { margin-top: 0; }
/* Les cinq étoiles au-dessus de chaque citation (14/10/2026). Elles ne sont
   pas une note donnée par le client, la mention le dit : voir `avis.note`. */
.avis-note {
  margin: 0 0 8px;
  color: #fff;
  font-size: 15px;
  letter-spacing: 0.18em;
  line-height: 1;
}
.avis blockquote {
  margin: 0;
  color: #fff;
  font-size: clamp(24px, 4.2vw, 40px);
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: -0.015em;
  /* Des lignes équilibrées : un mot seul en fin de citation la ferait
     passer pour un slogan rédigé. */
  text-wrap: balance;
}
.avis blockquote::before { content: '«\A0'; color: var(--muted); font-weight: 500; }
.avis blockquote::after { content: '\A0»'; color: var(--muted); font-weight: 500; }
/* La signature, sur une ligne : prénom et pays, modèle ou moteur, date de
   publication, « traduit » s'il y a lieu, et l'étoile de la contrepartie.
   Un nom complet n'ajoute rien et expose quelqu'un qui n'a pas demandé ça. */
.avis-qui {
  margin-top: 10px;
  color: var(--faint);
  font-size: 13px;
}
.avis-date::before,
.avis-trad:not(:empty)::before { content: ' · '; }
.avis-etoile { margin-left: 3px; }
/* La note que la loi veut à côté des avis (D111-10 : contrôle, dates,
   classement), la contrepartie que l'étoile annonce (DMCC Act) et le lien
   vers la rubrique des mentions légales, où vivent les délais : le gris de
   la signature, une information, pas un argument. */
.avis-mention {
  margin-top: 40px;
  max-width: 72ch;
  color: var(--faint);
  font-size: 12.5px;
  line-height: 1.5;
}
.avis-mention a { display: block; width: fit-content; margin-top: 4px; color: var(--muted); }

/* « Ils parlent de nous » : les vidéos YouTube, en vignettes qui ouvrent
   YouTube. Deux colonnes au téléphone (une vignette 16:9 seule prendrait
   un écran), TOUTES sur une ligne dès 720 px. Le triangle de lecture est
   dessiné ici : il dit « vidéo » sans copier le logo de YouTube.
   Une colonne par vidéo et non un nombre fixe (31/10/2026) : la grille en
   comptait cinq, et la sixième vidéo, celle d'Elektro Ronny, tombait seule
   sur une seconde ligne. */
.yt-titre {
  margin-top: 56px;
  color: #fff;
  font-size: 20px;
  font-weight: 600;
}
.yt-liens {
  list-style: none;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px 12px;
  margin-top: 18px;
}
@media (min-width: 720px) {
  .yt-liens { grid-template-columns: none; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 16px; }
}
.yt-liens li { min-width: 0; }
.yt-lien { display: block; text-decoration: none; color: inherit; }
.yt-vignette {
  position: relative;
  display: block;
  border-radius: var(--r);
  overflow: hidden;
  background: #000;
}
.yt-vignette img { display: block; width: 100%; height: auto; transition: opacity 0.2s; }
.yt-vignette::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 50%;
  width: 44px;
  height: 44px;
  margin: -22px 0 0 -22px;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.62)
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M9 7v10l8-5z' fill='%23fff'/%3E%3C/svg%3E")
    center / 26px no-repeat;
}
.yt-lien:hover .yt-vignette img,
.yt-lien:focus-visible .yt-vignette img { opacity: 0.8; }
.yt-lien .avis-qui { display: block; margin-top: 8px; font-size: 12.5px; }
.yt-lien .avis-qui > span:first-child { color: var(--muted); }
.yt-mention { margin-top: 20px; }

/* Le garde-fou du téléphone : la phrase qui dit pourquoi on ne lance rien
   ici, et ce qu'il reste à faire à la place. */
.lancer-garde {
  margin-top: 14px;
  color: var(--muted);
  font-size: 13.5px;
  max-width: 46ch;
}

/* ---------- Le dernier mot ----------
   Le P.S. : lu par presque tout le monde, donc traité comme un bloc et
   pas comme une note de bas de page. */

#dernier-mot {
  padding: clamp(56px, 9vw, 96px) 0 clamp(40px, 6vw, 72px);
  border-top: 1px solid var(--line);
  text-align: center;
}
.ps-etiquette {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 3px;
  text-transform: uppercase;
  color: var(--faint);
}
.ps-texte {
  max-width: 54ch;
  margin: 18px auto 0;
  color: var(--muted);
  font-size: clamp(15px, 1.9vw, 18px);
}
.ps-texte sup { font-size: 0.65em; vertical-align: super; }
.ps-action { margin-top: 32px; }

/* ---------- Téléphone ----------
   Le site se lit d'abord sur un téléphone : le QR de la voiture y renvoie,
   et c'est là que le paiement se fait. Tout ce qui suit part donc du petit
   écran, pas d'un bureau rétréci. */

/* Le doigt n'est pas une souris : rien de cliquable sous 44 px de haut. */
@media (pointer: coarse) {
  .barre nav a,
  .faq summary,
  footer nav a { min-height: 44px; display: flex; align-items: center; }
  .faq summary { justify-content: space-between; }
}

@media (max-width: 720px) {
  :root { --barre: 54px; }

  /* La barre ne garde que le logo : les trois ancres tiendraient au prix
     d'un empilement illisible, la page se parcourt au pouce et le rappel
     collant porte déjà l'action. Les pages secondaires (achat, merci),
     dont la nav n'a pas cette classe, gardent leur lien unique. */
  .barre .nav-vitrine { display: none; }
  .logo { font-size: 17px; letter-spacing: 4px; }
  .logo .tm { margin-left: -3px; }

  .ouverture .ecran { padding-top: 56px; padding-bottom: 56px; }
  .ouverture .precision { margin-top: 18px; }

  /* Deux boutons côte à côte deviennent deux moignons : on les empile,
     pleine largeur, dans l'ordre de lecture. */
  .ouverture .actions {
    flex-direction: column;
    align-items: stretch;
    gap: 10px;
    margin-top: 28px;
  }
  .ouverture .actions .bouton { width: 100%; }
  .bouton.large { padding: 15px 20px; font-size: 16px; }

  section { padding: 52px 0; }
  .titre-section { font-size: clamp(22px, 6.2vw, 28px); max-width: 20ch; }
  .intro-section { font-size: 15.5px; margin-top: 12px; }

  .fiche { margin-top: 30px; }
  .fiche li { padding: 15px 0; }
  .fiche span { font-size: 13.5px; }
  .versions { padding: 20px; }

  /* Le garage est un argument de volume : deux colonnes serrées le
     montrent d'un coup d'œil. Les quatre petites cartes font 160 px de
     large sur un téléphone, leur texte se resserre d'un cran. */
  .galerie { gap: 8px; }
  .galerie .voiture:not(:first-child) .voiture-corps { padding: 10px 11px 12px; }
  .galerie .voiture:not(:first-child) .voiture-nom { font-size: 14px; }
  .galerie .voiture:not(:first-child) .voiture-sous { font-size: 12px; }
  .voiture.libre em { font-size: 10.5px; letter-spacing: 0.5px; }
  .communaute { gap: 22px; }

  .lancer { padding: 20px; margin-top: 24px; }
  .lancer-actions .bouton { display: block; width: 100%; text-align: center; }

  .etapes { margin-top: 26px; }
  .etape { grid-template-columns: 34px 1fr; gap: 12px; padding: 18px 0; }
  .etape::before { font-size: 22px; line-height: 1.3; }
  /* L'adresse de l'app doit rester copiable d'un regard, jamais coupée. */
  .etape code { overflow-wrap: anywhere; }

  .offres { margin-top: 28px; gap: 12px; }
  .offre { padding: 24px 20px; }
  .offre .prix { font-size: 34px; }
  /* La sous-ligne du bouton ne tient sur une ligne qu'au bureau : à 375 px,
     en néerlandais (« Eenmalige betaling, voor altijd. Geen abonnement. »),
     elle élargissait la carte et toute la page de 13 px (28/10/2026). */
  .offre .bouton small { white-space: normal; }
  .offre ul { margin: 18px 0 22px; }
  @supports (grid-template-rows: subgrid) {
    .offre li:first-child { margin-top: 18px; }
    .offre .bouton { margin-top: 22px; }
  }

  .faq { margin-top: 26px; }
  .faq summary { font-size: 15px; padding: 15px 0; gap: 12px; }
  .faq details p { font-size: 14px; }

  /* Les captures sont des paysages 773x601 : à 375 px de large, une ombre
     de 90 px de flou n'est plus qu'une tache. */
  .cadre-app img { border-radius: 10px; box-shadow: 0 14px 40px rgba(0, 0, 0, 0.5); }
  .capture-large { margin-top: 30px; }
  .duo-captures { margin-top: 30px; gap: 24px; }

  footer { padding: 32px 0 44px; }
  footer.avec-rappel { padding-bottom: calc(44px + var(--pilule-reserve)); }
  footer .contenu { flex-direction: column; gap: 14px; align-items: flex-start; }
  footer nav { gap: 18px; }

  /* Achat, merci, mentions : mêmes gouttières que le reste. */
  .page-etroite { padding: 48px 20px 80px; }
  .page-etroite h1 { font-size: 27px; }
  .prix-bloc { margin: 26px 0 8px; }
  .prix-bloc strong { font-size: 46px; }
  .prix-bloc s { font-size: 20px; margin-left: 10px; }
  .page-etroite .bouton.large { display: block; width: 100%; }
  .avantages { margin: 26px auto; max-width: none; }
  .legal { padding: 44px 20px 72px; }
  .legal h1 { font-size: 25px; }
}

/* Le formulaire de récupération de code : sur un téléphone, un champ email
   et un bouton côte à côte se disputent 300 px. */
.retrouver { display: flex; gap: 10px; max-width: 400px; margin: 16px auto 0; }
.retrouver input {
  flex: 1;
  min-width: 0;
  background: var(--raised);
  border: 1px solid var(--line);
  border-radius: var(--r);
  color: var(--text);
  padding: 11px 14px;
  /* 16 px pile : en dessous, iOS zoome sur le formulaire à la saisie. */
  font: 400 16px var(--font);
}
@media (max-width: 560px) {
  .retrouver { flex-direction: column; }
  .retrouver .bouton { width: 100%; }
}

/* Le code de licence : 14 caractères en chasse fixe, à faire tenir sur un
   iPhone SE sans rogner la lettre. */
.code-licence { font-size: clamp(19px, 6.4vw, 30px); letter-spacing: clamp(1px, 0.8vw, 3px); }

@media (max-width: 400px) {
  /* Sous 400 px, « Premium · 4,99 € 9,99 € » pousse le rappel hors de
     l'écran. Un prix seul ne disait pas ce que fait le bouton : on garde
     un verbe court et on lâche le prix barré, que la scène du prix et la
     grille des offres redisent. */
  .rappel .long, .rappel s { display: none; }
  .rappel .court { display: inline; }
  /* Le classement de la communauté : la photo cède 16 px au nom. */
  .demande { gap: 10px; }
  .demande img { width: 72px; }
}

/* Les écrans d'avant l'iPhone 12 (320 à 360 px) : dernière réduction. */
@media (max-width: 360px) {
  .logo { font-size: 15px; letter-spacing: 3px; }
  .logo .tm { margin-left: -2px; }
  /* Le prix barré ferait passer les boutons sur deux lignes : la phrase de
     rareté juste en dessous rappelle déjà les 9,99 €. */
  .bouton s, .rappel s { display: none; }
}

/* ---------- La page se dévoile en roulant ----------
   Tout est piloté par le scroll en CSS natif (view() et scroll()) : pas
   une ligne de JavaScript, donc rien à charger et tout sur le
   compositeur. Règle de survie : l'état caché ne vit QUE dans les
   keyframes. Sans support ou en mouvement réduit, la page s'affiche
   entière, jamais blanche. */

@keyframes entree {
  from { opacity: 0; transform: translateY(14px); }
}
@keyframes apparait {
  from { opacity: 0; transform: translateY(22px); }
}
/* Les deux traits qui s'écrivent : le premier descend, l'autre se tire. */
@keyframes trace-bas { from { transform: scaleY(0); } }
@keyframes trace-droite { from { transform: scaleX(0); } }
/* Les captures se redressent comme un écran qu'on relève. */
@keyframes redresse {
  from { opacity: 0; transform: perspective(1400px) rotateX(8deg) translateY(28px) scale(0.98); }
}

@media (prefers-reduced-motion: no-preference) {
  /* Le hero, lui, ne peut pas attendre le scroll : il est déjà à l'écran.
     Entrée classique, en cascade, du titre vers la capture. */
  /* Les deux membres entrent l'un après l'autre : le temps qui les sépare
     est la respiration du point final, celle qu'on marque à l'oral avant
     de retourner la phrase. */
  .ouverture .constat { animation: entree 520ms cubic-bezier(0.215, 0.61, 0.355, 1) both; }
  .ouverture .punch { animation: entree 560ms cubic-bezier(0.215, 0.61, 0.355, 1) 150ms both; }
  .ouverture .sous { animation: entree 520ms cubic-bezier(0.215, 0.61, 0.355, 1) 300ms both; }
  .ouverture .ecoute-invite { animation: entree 520ms cubic-bezier(0.215, 0.61, 0.355, 1) 370ms both; }
  .ouverture .ecoute-hero { animation: entree 520ms cubic-bezier(0.215, 0.61, 0.355, 1) 370ms both; }
  .ouverture .actions { animation: entree 520ms cubic-bezier(0.215, 0.61, 0.355, 1) 430ms both; }
  .ouverture .precision { animation: entree 520ms cubic-bezier(0.215, 0.61, 0.355, 1) 490ms both; }
  .ouverture .invite { animation: entree 520ms cubic-bezier(0.215, 0.61, 0.355, 1) 560ms both; }
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .titre-section,
    .intro-section,
    .plaque-rst,
    .fiche li,
    .versions,
    .ecoute,
    .garage-inclus,
    .voiture,
    .communaute > *,
    .etape,
    .offre,
    .faq details,
    .duo-captures figcaption,
    .mot > p,
    .mot-signature,
    .avis li,
    .avis-clip,
    .yt-liens li,
    #trajet .contenu > *,
    #dernier-mot .contenu > *,
    footer .contenu > * {
      animation: apparait linear both;
      animation-timeline: view();
      animation-range: entry 12% entry 82%;
    }

    /* Les deux seuls gestes ajoutés à la page : un trait qui descend le
       long du mot du fondateur, et un paraphe qui se tire à la fin. Le
       reste du bloc entre comme n'importe quelle carte : un aparté ne se
       met pas en scène, sinon ce n'est plus un aparté. */
    .mot-trait {
      animation: trace-bas linear both;
      animation-timeline: view();
      /* Plage en entry/cover uniquement : contain est vide dès que le bloc
         dépasse la hauteur d'écran, et le trait resterait à zéro. */
      animation-range: entry 25% cover 58%;
    }
    .paraphe {
      animation: trace-droite linear both;
      animation-timeline: view();
      animation-range: entry 45% entry 95%;
    }
    /* Une rangée entière qui surgit d'un bloc fait rideau : la seconde
       colonne suit d'un cheveu, et la lecture reste en diagonale. */
    .fiche li:nth-child(2n),
    .galerie .voiture:nth-child(2n) {
      animation-range: entry 20% entry 92%;
    }
    section:not(.scene) .cadre-app {
      animation: redresse linear both;
      animation-timeline: view();
      animation-range: entry 5% entry 78%;
      /* Le passage GPU peut décaler l'image d'un pixel au démarrage. */
      will-change: transform;
    }
  }
}

/* ---------- Les chiffres qui montent ----------
   Le régime du cadran est TIRÉ par le scroll : il est physiquement lié à
   la jauge. Les mesures de la scène RST, elles, comptent TOUTES SEULES :
   le scroll ne fait que lever un drapeau (--vu) à l'arrivée de la scène,
   et une transition temporelle sur --n fait la montée, ligne après ligne.
   Toujours zéro JavaScript : un steps() sur une timeline de scène sert
   d'interrupteur, la transition fait le chrono. */
@property --n {
  syntax: '<integer>';
  initial-value: 0;
  inherits: false;
}
@property --vu {
  syntax: '<number>';
  initial-value: 0;
  inherits: true;
}
@keyframes compte { to { --n: var(--valeur, 0); } }
@keyframes mesures-vues { to { --vu: 1; } }

@supports (animation-timeline: view()) and (animation-name: compte) {
  @media (prefers-reduced-motion: no-preference) {
    /* Préfixés par .scene : ces règles doivent battre les couleurs de
       base des chiffres, déclarées plus bas dans la feuille. */
    .scene .mesure strong,
    .scene .regime-lu strong {
      /* Le chiffre du HTML reste en place pour les lecteurs d'écran et
         pour les navigateurs sans compteur animé : on ne fait que le
         cacher sous celui qui monte. */
      position: relative;
      color: transparent;
      counter-reset: n var(--n);
    }
    .scene .mesure strong::after,
    .scene .regime-lu strong::after {
      content: counter(n) var(--suffixe, '');
      position: absolute;
      inset: 0;
      color: #fff;
      white-space: pre;
    }
    /* Le régime est calé sur la jauge, jusque dans l'exit. */
    .scene .regime-lu strong {
      animation: compte linear both;
      animation-timeline: --scene;
      animation-range: contain 0% exit 30%;
    }

    /* L'interrupteur des mesures : le drapeau --vu monte sur la toute
       fin de l'entrée de la scène (une centaine de pixels de scroll,
       avalés d'un coup de pouce), et la transition sur --n fait le
       reste au chrono. Rampe linéaire et non steps() : les plages en
       marches d'escalier laissent l'animation figée « finished » au
       retour en arrière (constaté), la rampe se rejoue dans les deux
       sens comme toutes les traversées. */
    .s-mesures .ecran {
      animation: mesures-vues linear both;
      animation-timeline: --scene;
      animation-range: entry 85% entry 100%;
    }
    .scene .mesure strong {
      --n: calc(var(--vu) * var(--valeur, 0));
      transition: --n 1200ms cubic-bezier(0.22, 0.61, 0.36, 1);
    }
    .mesure + .mesure strong { transition-delay: 140ms; }
    .mesure + .mesure + .mesure strong { transition-delay: 280ms; }
    .mesure + .mesure + .mesure + .mesure strong { transition-delay: 420ms; }
  }
}

/* ---------- Le bandeau de régime ----------
   La ligne de tirets du shift light de l'app, posée en haut de l'écran :
   elle se remplit avec le scroll et les derniers tirets partent au rouge,
   comme le rupteur qui approche. */
@property --regime {
  syntax: '<percentage>';
  initial-value: 0%;
  inherits: false;
}
.regime {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  z-index: 20;
  pointer-events: none;
}
.regime span {
  display: block;
  height: 100%;
  background: linear-gradient(90deg, var(--muted) 0%, var(--text) 62%, var(--red) 94%);
  -webkit-mask-image:
    repeating-linear-gradient(90deg, #000 0 13px, transparent 13px 21px),
    linear-gradient(90deg, #000 var(--regime), transparent 0);
  mask-image:
    repeating-linear-gradient(90deg, #000 0 13px, transparent 13px 21px),
    linear-gradient(90deg, #000 var(--regime), transparent 0);
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
}
@keyframes monte-en-regime { to { --regime: 100%; } }

@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    .regime span {
      animation: monte-en-regime linear both;
      animation-timeline: scroll(root);
    }
  }
}

/* ---------- Les scènes ----------
   Chaque argument occupe l'écran le temps qu'on le traverse, puis cède la
   place au suivant. Le principe : la section sert de RAIL (deux ou trois
   hauteurs d'écran de scroll) et son contenu reste collé au centre
   pendant qu'on le parcourt. La progression dans le rail pilote
   l'apparition et la sortie.

   Sans scroll-timeline ou en mouvement réduit, aucune de ces règles ne
   s'applique : les scènes redeviennent des sections qui se lisent à la
   suite, et rien ne manque. */

.scene { border-top: 1px solid var(--line); }
.scene:first-child { border-top: 0; }
/* padding-block seulement : le padding raccourci écraserait les gouttières
   horizontales héritées de .contenu (même élément, règle plus tardive). */
.ecran { padding-block: 72px; text-align: center; }
.gauche { text-align: left; }

/* Le blanc pur est réservé aux titres et aux chiffres : c'est lui qui fait
   la hiérarchie sur le noir, pas la taille seule. L'effacé fait le reste. */
.titre-scene {
  font-size: clamp(32px, min(10.5vw, 7svh), 80px);
  font-weight: 600;
  line-height: 1.07;
  letter-spacing: -0.02em;
  color: #fff;
  text-wrap: balance;
}
.efface { color: var(--efface); }
.dit-scene {
  color: var(--muted);
  font-size: clamp(15px, min(1.9vw, 2.2svh), 19px);
  max-width: 44ch;
  margin: min(20px, 2.4svh) auto 0;
}
.scene .quota-offre { margin-top: 18px; }

/* ----- Scène 2 : le silence -----
   UN seul instrument, et il n'affiche rien. Le tracé du son moteur reste
   plat pendant que la voiture fait son 0 à 100 : c'est la ligne morte du
   moniteur, elle se lit sans légende et sans comparaison.

   La version d'avant posait deux jauges identiques l'une sous l'autre et
   demandait au lecteur de les comparer pour trouver l'argument. Deux
   défauts, et le second est le vrai : le rail de fond court sur toute la
   largeur en gris clair, si bien que la piste muette se lisait comme une
   jauge PLEINE aux trois quarts, exactement le contraire du propos.
   D'où la règle ici : rien ne se remplit. Une barre qui monte, même
   blanche, dit un niveau atteint ; le silence ne se dessine pas en
   jauge. */

.trace {
  width: min(100%, 660px);
  margin: min(44px, 5svh) auto 0;
}
.trace-tete,
.trace-pied {
  display: flex;
  justify-content: space-between;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 2.5px;
  text-transform: uppercase;
  color: var(--faint);
}
/* Le zéro est la seule valeur de la scène, et c'est une valeur absente :
   il reste au gris de sa ligne au lieu de passer en blanc. */
.trace-lu {
  font-size: 13px;
  letter-spacing: 0;
  font-variant-numeric: tabular-nums;
}
.trace-pied {
  margin-top: 14px;
  letter-spacing: 1.6px;
}
/* La piste : une ligne d'un bout à l'autre, et deux bornes verticales qui
   la datent. C'est un enregistrement, il dure 4,2 secondes, il est vide. */
.trace-piste {
  position: relative;
  /* Haute exprès : c'est la bande VIDE qui porte l'argument, pas la
     ligne. Un tracé plat sur 20 px se lit comme un filet de séparation. */
  height: min(96px, 11.5svh);
  margin-top: 14px;
}
.trace-piste::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: 1px;
  background: var(--raised-2);
}
.trace-piste::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: 11px;
  margin-top: -5.5px;
  border-left: 1px solid var(--raised-2);
  border-right: 1px solid var(--raised-2);
}
/* La tête de lecture : elle balaie la piste et ne trouve rien. C'est le
   seul point vivant de la scène, et c'est bien le problème. Sans
   scroll-timeline elle s'arrête ici, au milieu du tracé : une lecture en
   cours, pas une lecture terminée. */
.trace-balai {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 56%;
  width: 1px;
  background: linear-gradient(180deg, transparent, rgba(255, 255, 255, 0.45), transparent);
}
.trace-balai::after {
  content: '';
  position: absolute;
  left: -4px;
  top: 50%;
  width: 9px;
  height: 9px;
  margin-top: -4.5px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 0 14px rgba(255, 255, 255, 0.7);
}

.s-silence .chute {
  color: var(--muted);
  font-size: clamp(14px, min(1.8vw, 2svh), 17px);
  max-width: 44ch;
  margin: min(30px, 3.6svh) auto 0;
}

/* ----- Scène 3 : le cadran ----- */

/* Le shift light de l'app : douze diodes, les quatre dernières au rouge.
   Le dégradé est découpé en diodes par le même masque que le bandeau de
   régime, et --regime décide combien sont allumées. */
.leds { width: min(304px, 78vw); height: 5px; margin: min(30px, 3.4svh) auto 0; }
.leds span {
  display: block;
  height: 100%;
  background: linear-gradient(90deg, #6f6f6f 0 33.5%, var(--text) 33.5% 66.5%, var(--red) 66.5%);
  -webkit-mask-image:
    repeating-linear-gradient(90deg, #000 0 18px, transparent 18px 26px),
    linear-gradient(90deg, #000 var(--regime), transparent 0);
  mask-image:
    repeating-linear-gradient(90deg, #000 0 18px, transparent 18px 26px),
    linear-gradient(90deg, #000 var(--regime), transparent 0);
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
}

/* Le cadran se plafonne en hauteur d'écran autant qu'en largeur :
   55.8svh = 46svh de haut multiplié par le ratio 400/330 du viewBox. */
.cadran-scene { position: relative; width: fit-content; margin: min(22px, 2.6svh) auto 0; }
.cadran-scene svg { display: block; width: min(88vw, 420px, 55.8svh); height: auto; }
.regime-lu {
  position: absolute;
  left: 50%;
  top: 58%;
  transform: translate(-50%, -50%);
  margin: 0;
  line-height: 1;
  text-align: center;
}
.regime-lu strong {
  display: block;
  font-size: clamp(38px, min(12vw, 8svh), 68px);
  font-weight: 600;
  letter-spacing: -0.03em;
  color: #fff;
}
.regime-lu span {
  display: block;
  margin-top: 10px;
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 2.5px;
  text-transform: uppercase;
  color: var(--faint);
}

/* ----- Scène 3 bis : Rupteur Sensor -----
   Le discours d'un côté, le téléphone de l'autre, comme la scène des
   mesures. Les rangées vides en haut et en bas centrent le texte à côté
   du téléphone : sans elles, la hauteur de l'image se répartit entre le
   titre, le discours et la note, et les trois se décollent. */

.s-sensor .ecran {
  display: grid;
  align-content: center;
  justify-items: center;
  gap: clamp(12px, 2svh, 22px) clamp(28px, 5vw, 70px);
  grid-template-areas: 'titre' 'dit' 'tel' 'note';
}
.s-sensor .titre-scene { grid-area: titre; }
.s-sensor .dit-scene { grid-area: dit; margin: 0; }
.sensor-note { grid-area: note; color: var(--faint); font-size: 13px; max-width: 40ch; }
.sensor-tel { grid-area: tel; }
.sensor-tel img {
  display: block;
  height: clamp(110px, 21svh, 240px);
  width: auto;
  /* Le fond de la photo n'est pas le noir de la page : le halo et le sol
     sont gris. Un masque fond les quatre bords, sans mode de fusion (les
     animations de scène le neutralisent, voir la scène des mesures). */
  -webkit-mask-image: linear-gradient(to right, transparent, #000 14%, #000 86%, transparent),
                      linear-gradient(transparent, #000 9%, #000 84%, transparent);
  -webkit-mask-composite: source-in;
  mask-image: linear-gradient(to right, transparent, #000 14%, #000 86%, transparent),
              linear-gradient(transparent, #000 9%, #000 84%, transparent);
  mask-composite: intersect;
}

/* Les téléphones (664 px utiles sur un iPhone, 600 sur les petits) : le
   titre y tient sur quatre lignes et la note passait sous la pilule
   collante (mesuré : 4 px à 390x664, 40 px à 375x600). Le téléphone cède,
   le discours et la note restent entiers. */
@media (max-height: 730px) {
  .s-sensor .ecran { gap: 10px; }
  .s-sensor .dit-scene { font-size: 14px; }
  .sensor-note { font-size: 12px; }
  .sensor-tel img { height: min(19svh, 200px); }
}

@media (min-width: 740px) {
  .s-sensor .ecran {
    text-align: left;
    justify-items: start;
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
    grid-template-rows: 1fr auto auto auto 1fr;
    grid-template-areas:
      '.     tel'
      'titre tel'
      'dit   tel'
      'note  tel'
      '.     tel';
  }
  .sensor-tel { justify-self: center; align-self: center; }
  .sensor-tel img { height: min(62svh, 520px); }
}

/* ----- Scène 4 : les mesures -----
   Le rendu Tesla de la voiture vue de dessus, et sous lui la bande de
   chiffres. Le discours tient la colonne de gauche, l'image porte la
   preuve : les deux sources que RST fait jouer dans l'habitacle. */

.s-mesures .ecran {
  display: grid;
  align-content: center;
  justify-items: stretch;
  text-align: left;
  gap: clamp(14px, 2.4svh, 26px) clamp(28px, 5vw, 70px);
  grid-template-areas: 'plaque' 'titre' 'dit' 'plan' 'chiffres';
}
.s-mesures .plaque-rst { grid-area: plaque; }
.s-mesures .titre-scene { grid-area: titre; }
.s-mesures .dit-scene { grid-area: dit; margin: 0; max-width: 42ch; }
.habitacle {
  grid-area: plan;
  width: 100%;
  position: relative;
  /* Pas de lueur ajoutée : le rendu Tesla porte son propre éclairage, et
     mix-blend-mode: screen additionnerait la moindre lumière de fond. */
}
.chiffres { grid-area: chiffres; }


/* Le rendu officiel Tesla porte la voiture ; le SVG posé dessus ne porte
   plus que NOS repères. Pas de mode de fusion : les animations de scène
   isolent le contexte et le neutralisent (constaté). Le noir du JPEG est
   calé PILE sur le fond de la page (#0e0e0e), bords fondus dans le
   fichier : la couture est invisible sans aucune astuce de rendu. */
.planche { position: relative; width: fit-content; margin: 0 auto; }
.planche img { display: block; height: min(33svh, 290px); width: auto; }
.annotations { position: absolute; inset: 0; width: 100%; height: 100%; }
/* Les deux sources sont les seuls blancs pleins du plan, et elles
   rayonnent : c'est d'elles que part tout le reste du dessin. */
.pointe {
  fill: #fff;
  transform-box: fill-box;
  transform-origin: center;
  filter: drop-shadow(0 0 7px rgba(255, 255, 255, 0.55));
}
/* La ligne à retard : le tuyau posé une fois pour toutes, et l'impulsion
   qui le remonte à chaque explosion. */
.tuyau { stroke: rgba(255, 255, 255, 0.13); stroke-width: 2.5; }
.impulsion {
  stroke: #fff;
  stroke-width: 3;
  stroke-linecap: round;
  /* Un segment de 7 % du parcours : assez court pour se lire comme une
     impulsion, assez long pour ne pas clignoter. */
  stroke-dasharray: 7 93;
  stroke-dashoffset: 100;
  opacity: 0;
}
.onde {
  fill: none;
  stroke: #fff;
  stroke-width: 2;
  /* Invisible au repos : l'anneau n'existe que le temps de sa course. En
     mouvement réduit, où toutes les animations tombent, le plan garde ses
     deux points sans un cercle figé au milieu de nulle part. */
  opacity: 0;
  transform-box: fill-box;
  transform-origin: center;
}
.etiq {
  fill: var(--muted);
  font: 500 22px var(--font);
  letter-spacing: 3px;
}
/* Le plan garde son viewBox quelle que soit sa taille rendue : sur un
   téléphone, une étiquette de 22 unités tomberait sous 8 px à l'écran. */
@media (max-width: 700px) {
  .etiq { font-size: 30px; letter-spacing: 4px; }
}

/* La bande de chiffres : deux cases par ligne sur un téléphone, quatre
   d'affilée dès qu'il y a de la place. */
.chiffres {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  width: 100%;
}
.mesure { border-top: 1px solid var(--line); padding: min(12px, 1.5svh) 0 0; }
.mesure:nth-child(2n) { border-left: 1px solid var(--line); padding-left: clamp(12px, 2.5vw, 22px); }
.mesure strong {
  display: block;
  font-size: clamp(30px, min(7.5vw, 5.4svh), 58px);
  font-weight: 600;
  line-height: 1;
  letter-spacing: -0.03em;
  color: #fff;
}
.mesure span {
  display: block;
  margin-top: 6px;
  color: var(--muted);
  font-size: clamp(11.5px, 1.3vw, 14px);
  line-height: 1.35;
}

/* Les téléphones courts (iPhone SE et cie) : la scène doit tenir d'un
   seul écran, sinon le plan passe sous la scène suivante. Le dessin cède
   en premier, le discours et les chiffres restent entiers. */
@media (max-height: 730px) {
  .planche img { height: min(30svh, 240px); }
  .s-mesures .ecran { gap: 12px; }
  .s-mesures .dit-scene { font-size: 14px; }
}
/* Les téléphones HAUTS aussi (iPhone 12 à 16 : 812 et 844 px). Mesuré le
   02/09/2026 : à 375x812 le panneau débordait de 14 px, de 7 à 390x844, et
   c'était la seconde rangée de chiffres, la conclusion de la scène, qui
   passait sous la pilule collante. Le dessin cède, encore : 26 svh au lieu
   de 33, et il reste 23 px de marge une fois la pilule réservée. */
@media (max-width: 720px) and (max-height: 860px) {
  .planche img { height: min(26svh, 220px); }
  .s-mesures .ecran { gap: 12px; }
  .s-mesures .dit-scene { font-size: 14px; }
}

/* 740 px et pas 900 : l'écran du navigateur Tesla fait 773x601, et c'est
   LE format où cette scène doit tenir d'un bloc. En dessous de 740, tout
   s'empile ; au-dessus, la composition de l'écran audio Tesla : le
   discours d'un côté, la voiture de l'autre, sur toute la hauteur. */
@media (min-width: 740px) {
  .s-mesures .ecran {
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
    grid-template-areas:
      'plaque   plan'
      'titre    plan'
      'dit      plan'
      'chiffres plan';
  }
  .habitacle { align-self: center; }
  .planche img { height: min(56svh, 480px); }
}

/* Les deux sources battent toutes seules : une scène dont chaque geste est
   tiré par le pouce meurt dès qu'on arrête de descendre. L'anneau part du
   point et s'éteint avant le bord, comme une explosion dans l'habitacle ;
   la ligne répond au bloc à contretemps, c'est la scène en deux temps. */
@keyframes onde-part {
  0% { transform: scale(0.3); opacity: 0.72; }
  70% { opacity: 0.09; }
  100% { transform: scale(3.2); opacity: 0; }
}
@keyframes bat {
  0% { transform: scale(1.75); }
  26%, 100% { transform: scale(1); }
}
/* L'impulsion descend le tuyau une fois par cycle, puis s'éteint le temps
   que le bloc explose à nouveau : le tuyau ne doit pas ruisseler en
   continu, ce serait un flux, pas des explosions. */
@keyframes file {
  0% { stroke-dashoffset: 100; opacity: 0; }
  8% { opacity: 0.9; }
  62% { stroke-dashoffset: 0; opacity: 0.9; }
  70%, 100% { stroke-dashoffset: 0; opacity: 0; }
}
/* Un cycle de 1,6 s, dans l'ordre où ça se passe vraiment : le bloc
   explose, l'impulsion file dans la ligne, le pot répond un temps après.
   Rien de tout cela ne dépend du scroll : la scène vit même à l'arrêt,
   et c'est ce qui manquait aux chiffres qui montaient tout seuls. */
@media (prefers-reduced-motion: no-preference) {
  .pointe { animation: bat 1.6s cubic-bezier(0.22, 0.61, 0.36, 1) infinite; }
  .onde { animation: onde-part 3.2s cubic-bezier(0.22, 0.61, 0.36, 1) infinite; }
  .onde.o2 { animation-delay: 1.6s; }
  .impulsion { animation: file 1.6s linear infinite; }
  /* Le pot part quand l'impulsion arrive au bout, pas avant. */
  .source.arriere .pointe { animation-delay: 1s; }
  .source.arriere .onde { animation-delay: 1s; }
  .source.arriere .onde.o2 { animation-delay: 2.6s; }
}

/* ----- Scène 5 : le générique du garage ----- */

/* « 23 moteurs. » est court : il peut se payer un corps au-dessus des
   autres titres sans jamais déborder. */
.s-garage .titre-scene { font-size: clamp(42px, min(14vw, 8.5svh), 112px); letter-spacing: -0.03em; }
.s-garage .efface {
  display: block;
  font-size: 0.6em;
  margin-top: 0.18em;
  letter-spacing: -0.01em;
}
.defile-moteurs {
  margin-top: min(26px, 3svh);
  height: min(38svh, 320px);
  overflow: hidden;
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 20%, #000 78%, transparent);
  mask-image: linear-gradient(180deg, transparent, #000 20%, #000 78%, transparent);
}
.defile-moteurs ul { list-style: none; display: grid; gap: clamp(10px, 1.6svh, 16px); }
.defile-moteurs li {
  font-size: clamp(19px, min(5.6vw, 4.2svh), 34px);
  font-weight: 600;
  line-height: 1.25;
  color: var(--efface);
}
.defile-moteurs .libre { color: #fff; }
.defile-moteurs .libre em {
  font-style: normal;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 2px;
  text-transform: uppercase;
  vertical-align: middle;
  margin-left: 12px;
  padding: 4px 10px;
  border: 1px solid var(--raised-2);
  border-radius: 100px;
  position: relative;
  top: -0.35em;
}

/* ----- Scène 6 : le prix ----- */

.avant-prix {
  font-size: clamp(16px, min(2.2vw, 2.4svh), 21px);
  font-weight: 500;
  color: var(--muted);
}
.scene .bouton.large { margin-top: min(30px, 3.4svh); }
/* Les deux offres en tableau (28/10/2026). Tout est en svh : la scène est
   collée à l'écran et doit tenir entière à 664 px de haut (téléphone, barres
   de Safari posées) comme à 601 (la Tesla), barre et pilule déduites. La
   colonne du tout inclus est ENCADRÉE, du prix au bouton : c'est le cadre
   des 9,99 € du 16/10 (« faut que ça claque »), étiré sur sa colonne. */
.comparatif {
  width: min(100%, 620px);
  margin: min(20px, 2.6svh) auto 0;
  border-collapse: separate;
  border-spacing: 0;
  text-align: center;
}
.comparatif th, .comparatif td { padding: min(9px, 1.25svh) 10px; vertical-align: middle; }
.comparatif tbody th {
  text-align: left;
  font-weight: 400;
  font-size: clamp(13px, min(1.7vw, 2.2svh), 16px);
  line-height: 1.3;
  color: var(--text);
  padding-left: 0;
}
.comparatif tbody tr > * { border-top: 1px solid var(--line); }
/* Calé par le BAS : un nom d'offre qui passe sur deux lignes (« ALLES
   INKLUSIVE » sur un téléphone) ne doit pas décaler son prix de l'autre. */
.comparatif thead th { padding-top: min(14px, 1.8svh); padding-bottom: min(12px, 1.6svh); width: 30%; vertical-align: bottom; }
.cmp-nom {
  display: block;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--muted);
}
.comparatif thead strong {
  display: block;
  margin-top: 4px;
  font-size: clamp(24px, min(5.5vw, 5svh), 42px);
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 1;
  color: #fff;
  white-space: nowrap;
}
.cmp-non { font-size: clamp(12px, min(1.5vw, 2svh), 14px); color: var(--faint); line-height: 1.25; }
/* La coche des cartes du bas, dessinée pareil ; le mot « Inclus » reste
   dans la cellule pour les lecteurs d'écran, poussé hors de la boîte. */
.cmp-oui {
  display: inline-block;
  position: relative;
  width: 16px;
  height: 14px;
  overflow: hidden;
  text-indent: 100px;
  white-space: nowrap;
  vertical-align: middle;
}
.cmp-oui::before {
  content: '';
  position: absolute;
  left: 1px;
  top: 2px;
  width: 13px;
  height: 7px;
  border-left: 2px solid var(--text);
  border-bottom: 2px solid var(--text);
  transform: rotate(-45deg);
}
.comparatif tfoot td { padding-top: min(14px, 1.8svh); padding-bottom: min(14px, 1.8svh); }
.comparatif .bouton { display: block; padding: min(12px, 1.6svh) 8px; font-size: 15px; }
/* Le même trait, transparent, sur les autres cellules d'en-tête et de pied :
   sans lui le cadre décalait de 1,5 px le prix et le bouton du tout inclus
   par rapport à ceux de Premium. */
.comparatif thead tr > * { border-top: 1.5px solid transparent; }
.comparatif tfoot td { border-bottom: 1.5px solid transparent; }
.comparatif .cmp-t { border-inline: 1.5px solid #eaeaea; }
.comparatif thead .cmp-t { border-top: 1.5px solid #eaeaea; border-radius: var(--r-lg) var(--r-lg) 0 0; }
.comparatif tfoot .cmp-t { border-bottom: 1.5px solid #eaeaea; border-radius: 0 0 var(--r-lg) var(--r-lg); }
.comparatif.sans-tout .cmp-t { display: none; }
.cmp-sous { margin-top: min(12px, 1.6svh); font-size: 12.5px; color: var(--faint); }
@media (max-width: 480px) {
  .comparatif th, .comparatif td { padding-inline: 6px; }
  .comparatif thead th { width: 32%; }
  .cmp-nom { font-size: 10.5px; letter-spacing: 1px; }
  .comparatif .bouton { font-size: 14px; padding-inline: 4px; }
}
.invite { display: none; }

/* Le maintien n'est jamais immobile : une dérive lente de 20 px répond au
   pouce pendant toute la traversée. Un écran qui ne bouge plus du tout
   sous le doigt se lit comme un blocage, pas comme une pause. */
@keyframes traverse {
  0% { opacity: 0; transform: translateY(46px); }
  24% { opacity: 1; transform: translateY(10px); }
  72% { opacity: 1; transform: translateY(-10px); }
  100% { opacity: 0; transform: translateY(-40px); }
}
@keyframes sortie {
  0% { opacity: 1; transform: none; }
  52% { opacity: 1; transform: translateY(-9px); }
  100% { opacity: 0; transform: translateY(-44px); }
}
@keyframes defile {
  from { transform: translateY(4%); }
  to { transform: translateY(-64%); }
}
@keyframes respire-invite {
  50% { opacity: 0.35; transform: translateY(4px); }
}
/* La tête de lecture traverse la piste de bout en bout. Elle part de la
   borne de gauche et s'arrête à celle de droite : le tracé est lu en
   entier, il n'y a rien dessus. */
@keyframes balaie {
  from { left: 2%; }
  /* 97 et non 100 : le halo de la tête déborderait la gouttière de la
     page et se ferait couper au bord de l'écran. */
  to { left: 97%; }
}

/* pathLength 100 sur la jauge : l'offset se lit en pourcents de cadran.
   4 et non 0 : la jauge s'arrête au rupteur, pas au bout du monde. */
@keyframes jauge-monte {
  from { stroke-dashoffset: 100; }
  to { stroke-dashoffset: 4; }
}
@keyframes leds-montent {
  from { --regime: 0%; }
  to { --regime: 100%; }
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .scene {
      /* Le rail : sa hauteur est la durée de la scène. Une scène statique
         n'a pas droit à plus d'un écran et demi de scroll : au-delà, le
         maintien se lit comme une page bloquée. Les scènes qui ANIMENT
         (cadran, générique) gagnent un peu de route, jamais le double. */
      height: 220vh;
      border-top: 0;
      padding: 0;
      view-timeline-name: --scene;
    }
    .scene.s-cadran, .scene.s-garage { height: 250vh; }
    /* L'ouverture est déjà à l'écran en arrivant : elle a moins de route
       à faire, elle n'a que sa sortie à jouer. À 150vh, sa fin de fondu
       coïncide avec l'entrée de la scène suivante : pas d'écran mort. */
    .scene.ouverture { height: 150vh; }

    .ecran {
      position: sticky;
      top: 0;
      min-height: 100svh;
      display: grid;
      align-content: center;
      padding-top: calc(var(--barre) + 20px);
      padding-bottom: 40px;
    }

    /* Chaque élément traverse la scène, décalé d'un cheveu sur le
       précédent : le regard descend au lieu de tout prendre d'un bloc.
       La plage COMMENCE dans l'entrée et FINIT dans l'exit : le panneau
       collé reste à l'écran une pleine hauteur après contain 100% (la
       phase exit, où il défile vers le haut), et une sortie jouée avant
       laissait un écran noir entre deux arguments. Là, la scène sortante
       s'efface en glissant pendant que la suivante monte, déjà visible :
       un fondu croisé, jamais de trou. */
    .scene:not(.ouverture) .ecran > * {
      animation: traverse linear both;
      animation-timeline: --scene;
      animation-range: entry 50% exit 70%;
    }
    .scene:not(.ouverture) .ecran > *:nth-child(2) { animation-range: entry 60% exit 70%; }
    .scene:not(.ouverture) .ecran > *:nth-child(3) { animation-range: entry 70% exit 70%; }
    .scene:not(.ouverture) .ecran > *:nth-child(4) { animation-range: entry 80% exit 70%; }
    .scene:not(.ouverture) .ecran > *:nth-child(5) { animation-range: entry 90% exit 70%; }
    .scene:not(.ouverture) .ecran > *:nth-child(6) { animation-range: contain 0% exit 70%; }
    .scene:not(.ouverture) .ecran > *:nth-child(7) { animation-range: contain 5% exit 70%; }

    /* L'ouverture entre au chargement (animations minutées plus haut) :
       c'est l'écran entier qui s'efface, pas chaque ligne. Le fondu court
       jusque dans l'exit, pour croiser l'entrée de la scène suivante. */
    .ouverture .ecran {
      animation: sortie linear both;
      animation-timeline: --scene;
      animation-range: contain 0% exit 85%;
    }
    .invite {
      display: block;
      margin-top: 30px;
      color: var(--faint);
      font-size: 11px;
      letter-spacing: 3px;
      text-transform: uppercase;
    }
    .invite::after {
      content: '';
      display: block;
      width: 1px;
      height: 26px;
      margin: 10px auto 0;
      background: linear-gradient(var(--faint), transparent);
      animation: respire-invite 2.4s ease-in-out infinite;
    }

    .defile-moteurs ul {
      animation: defile linear both;
      animation-timeline: --scene;
      animation-range: contain 0% exit 40%;
      will-change: transform;
    }

    /* La montée en régime : jauge, diodes et chiffre occupent toute la
       traversée et finissent dans l'exit : le moteur touche le rupteur
       au moment où la scène s'en va, jamais un cadran figé sous le pouce. */
    .jauge {
      animation: jauge-monte linear both;
      animation-timeline: --scene;
      animation-range: contain 0% exit 30%;
    }
    .leds span {
      animation: leds-montent linear both;
      animation-timeline: --scene;
      animation-range: contain 5% exit 30%;
    }

    /* La tête balaie la piste pendant la traversée et RESTE au bout avant
       que la scène s'en aille : le constat doit pouvoir se lire à
       l'arrêt, pas seulement en passant. Rien d'autre ne bouge dans la
       scène, et c'est tout le propos. */
    .trace-balai {
      animation: balaie linear both;
      animation-timeline: --scene;
      animation-range: contain 0% contain 78%;
    }

    .ouverture .actions { margin-top: min(34px, 4svh); }
    .ouverture .precision { margin-top: min(14px, 1.8svh); }

    /* SOUS 700 PX DE HAUT, C'EST-À-DIRE SUR PRESQUE TOUS LES TÉLÉPHONES :
       un iPhone de 390 x 844 ne donne que 664 px à la page une fois les
       barres de Safari posées, et c'est de là que vient tout le trafic de
       publicité (le 18/09/2026, 469 visiteurs iOS et 201 Android, pas une
       seule voiture). À cette hauteur l'accroche, le lecteur, les deux
       boutons et la consigne du téléphone ne tiennent pas tous : on
       resserre les gouttières, la consigne passe sur une ligne et la ligne
       de rassurance s'efface - elle est redite plus bas, pas eux. */
    @media (max-height: 700px) {
      .ouverture .precision { display: none; }
      .ouverture .actions { margin-top: 12px; gap: 10px; }
      .ouverture .ecoute-invite { margin-top: 14px; }
      .ouverture .ecoute-hero { margin-top: 10px; }
      .ouverture .ecoute-hero .ecoute-bouton { width: 40px; height: 40px; }
      .ouverture .ecoute-hero .ecoute-bouton svg { width: 16px; height: 16px; }
      .ouverture .ecoute-hero .ecoute-piste { gap: 11px; }
      .ouverture .ecoute-hero .ecoute-hero-tete { font-size: 12px; }
      .ouverture .ecoute-hero .ecoute-onde-cadre { margin-top: 5px; }
      .ouverture .ecoute-hero .ecoute-onde { height: 20px; }
      /* La consigne tient sur une ligne au lieu de deux : c'est là que sont
         les pixels, et c'est le passage du téléphone à la voiture - il se
         lit sans défiler ou il ne sert à rien. */
      .ouverture .consigne-telephone { margin-top: 8px; font-size: 13px; line-height: 1.35; }
      .invite { margin-top: 14px; }
    }

    /* Sous 640 px de haut, le repère de défilement passe à la trappe :
       mieux vaut un écran qui respire qu'un écran complet.
       L'ÉCOUTE, ELLE, RESTE. Elle sautait ici jusqu'au 18/09/2026, effacée
       par un `display: none`, et c'est le seul geste que le téléphone
       puisse faire : 17 visiteurs sur 652 lançaient l'extrait ce jour-là,
       et les acheteurs sortent presque tous de ceux qui ont écouté. On
       resserre des gouttières pour lui faire la place, on ne la retire
       pas. */
    @media (max-height: 640px) {
      .invite { display: none; }
      /* La pilule collante est réservée dans le bas du panneau : à 773x601
         (l'écran de la voiture) elle recouvrait le bas du cadran, et le
         cadran lui-même perd 8 svh pour tenir au-dessus. Mesuré : 33 px de
         recouvrement avant, 20 px de marge après. */
      .ecran { padding-top: calc(var(--barre) + 10px); padding-bottom: calc(20px + 54px); }
      .cadran-scene svg { width: min(88vw, 420px, 45svh); }
    }
  }
}

/* Sur un téléphone, tout se traverse au pouce : un pouce déplace à peu
   près un écran, donc une scène statique doit se plier en gros en un
   coup de pouce et demi (175vh - 100 d'écran = 0,75 écran de maintien).
   Le cadran et le générique, qui rejouent quelque chose pendant toute la
   traversée, gardent deux coups de pouce. */
@media (max-width: 720px) {
  @supports (animation-timeline: view()) {
    @media (prefers-reduced-motion: no-preference) {
      .scene { height: 175vh; }
      .scene.s-cadran, .scene.s-garage { height: 205vh; }
      .scene.ouverture { height: 125vh; }
      /* Le bas du panneau réserve la pilule collante (54 px) : le contenu
         se centre au-dessus d'elle au lieu de passer dessous. L'accroche
         garde ses propres marges, la pilule n'y est pas encore. */
      .ecran { padding-top: calc(var(--barre) + 12px); padding-bottom: calc(28px + 54px); }
    }
  }
}

/* ---------- Le bandeau de consentement ----------
   Posé par consentement.js, et lui seul : sans JavaScript il n'y a pas de
   bandeau, mais il n'y a pas de pixel non plus, donc rien a consentir.
   Il occupe le bas de l'ecran, la ou la pilule collante vit deja : celle-ci
   remonte tant que le bandeau est la (.avec-consentement), sinon les deux se
   recouvrent sur telephone. Le z-index passe devant tout, barre comprise :
   un bandeau qu'on peut faire defiler hors de vue ne vaut pas consentement. */
.consentement {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 14px 22px;
  padding: 16px 20px calc(16px + env(safe-area-inset-bottom, 0px));
  background: rgba(20, 20, 20, 0.94);
  -webkit-backdrop-filter: blur(18px);
  backdrop-filter: blur(18px);
  border-top: 1px solid var(--line);
  box-shadow: 0 -10px 34px rgba(0, 0, 0, 0.45);
}
.consentement p {
  flex: 1 1 320px;
  max-width: 640px;
  color: var(--text);
  font: 400 13px/1.5 var(--font);
}
/* Les deux boutons ont la MEME taille et le MEME poids visuel : refuser doit
   couter exactement un clic, comme accepter. Un refus rendu plus penible que
   l'accord ne vaut pas consentement. */
.consentement-boutons { display: flex; gap: 10px; flex: 0 0 auto; }
.consentement-boutons .bouton {
  padding: 11px 22px;
  font-size: 14px;
  min-width: 116px;
  text-align: center;
}
/* La pilule se pose au-dessus de la hauteur MESURÉE du bandeau ou de la
   question Tesla (--h-consentement, posée par consentement.js, zone de
   sécurité comprise). Deux hauteurs supposées, 112 et 150 px, ne tenaient
   plus dès qu'une phrase allemande allongeait le bandeau. */
html.avec-consentement .rappel { bottom: calc(var(--h-consentement, 98px) + 14px); }

/* La question Tesla s'ouvre sur la question elle-même, en gras : c'est
   elle qu'on lit, le reste explique. */
.consentement strong { font-weight: 600; }
.consentement a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }

@media (max-width: 560px) {
  .consentement { gap: 12px; }
  .consentement p { flex-basis: 100%; font-size: 12.5px; }
  .consentement-boutons { width: 100%; }
  .consentement-boutons .bouton { flex: 1 1 0; min-width: 0; }
}

/* Le lien qui rend le choix revocable, dans le pied de page. Il ressemble aux
   autres liens du pied : le retrait doit etre aussi simple que l'accord, pas
   plus visible pour autant. */
.lien-traceurs {
  background: none;
  border: 0;
  padding: 0;
  color: inherit;
  font: inherit;
  cursor: pointer;
  text-decoration: underline;
}

/* TEST DE PRIX (20/09/2026). Sur une variante, rien ne parle plus du prix
   barré : 9,99 € barré à côté d'un prix testé à 9,99 € ne dit rien, et un barré
   jamais pratiqué contrevient à la règle française de l'annonce de réduction.
   `details:has()` retire la question entière, pas seulement son titre. */
html.test-prix [data-hors-test],
html.test-prix details:has(> [data-hors-test]) { display: none; }
/* LA CORÉE PAIE 9,99 € (config.js, 25/09/2026) : rien de ce qui lui promet le
   prix de lancement des 5 000 premières licences ne s'affiche, les CGV l'en
   excluent (article 2). */
html.prix-coree [data-lancement],
html.prix-coree details:has(> [data-lancement]) { display: none; }
/* LA FENÊTRE PAYANTE (config.js, 27/09/2026) : la carte « Gratuit » et les
   pastilles « offert » partent masquées dans le HTML et i18n.js les rend à la
   fin de la fenêtre. `!important` parce que `.offre` pose `display: flex`, qui
   l'emporterait sur l'attribut `hidden`. Seule, la carte Premium ne s'étire
   pas sur la largeur de deux. */
[data-hors-fenetre][hidden] { display: none !important; }
/* AVEC LE TOUT INCLUS (16/10/2026), DEUX CARTES : la limite d'une seule
   carte ne vaut plus, sinon Premium et Tout inclus s'empilent sur ordinateur
   et le 9,99 € tombe loin sous la ligne de flottaison. Une carte masquée par
   l'attribut `hidden` doit l'être pour de bon : `.offre` pose `display: flex`. */
.offre[hidden] { display: none !important; }
.offres:has(> [data-hors-fenetre][hidden]):not(:has(> #offre-tout:not([hidden]))) { max-width: 380px; }

/* ---------- Le prochain moteur (what-next.html, 29/09/2026) ----------
   Les cartes reprennent la plaque du garage (fond relevé, filet, plan de
   cylindres) : une proposition se lit comme un moteur qui n'y est pas
   encore. Le vote est une case à droite, chevron et nombre, qui passe en
   pilule claire à texte sombre une fois votée, comme un segment actif de
   l'app. Rouge pour les erreurs seulement. */
.prochain .sous { max-width: 470px; margin-left: auto; margin-right: auto; }
.prochain-acces {
  margin-top: 34px;
  padding: 22px 20px 18px;
  background: var(--raised);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
}
.prochain-acces h2 { font-size: 17px; font-weight: 600; }
.prochain-acces > p { color: var(--muted); font-size: 14px; margin-top: 8px; }
.prochain-acces .retrouver input { letter-spacing: 1px; text-transform: uppercase; }
.prochain-note { font-size: 13px; color: var(--faint); }
.prochain-acces .prochain-note { margin-top: 12px; }
.prochain-note a { color: var(--muted); }
.prochain-note span { margin: 0 6px; }

.lien-texte {
  background: none;
  border: 0;
  padding: 0;
  color: var(--muted);
  font: inherit;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 2px;
}
.prochain-form { margin-top: 18px; text-align: left; }
.prochain-client { font-size: 12.5px; color: var(--faint); margin-top: 22px; text-align: left; }
.prochain-client span[aria-hidden] { margin: 0 4px; }
.prochain-form input,
.prochain-form select {
  width: 100%;
  background: var(--raised);
  border: 1px solid var(--line);
  border-radius: var(--r);
  color: var(--text);
  padding: 11px 14px;
  /* 16 px pile : en dessous, iOS zoome sur le champ à la saisie. */
  font: 400 16px var(--font);
}
.prochain-form input::placeholder { color: var(--faint); }
.prochain-ligne { display: flex; gap: 10px; margin-top: 10px; }
.prochain-ligne input { flex: 1; min-width: 0; }
.prochain-ligne select {
  flex: 1;
  min-width: 0;
  appearance: none;
  -webkit-appearance: none;
  padding-right: 36px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%239a9a9a' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
  background-size: 12px 8px;
  cursor: pointer;
}
.prochain-ligne select option { background: var(--surface); color: var(--text); }
.prochain-ligne .bouton { flex: none; }
.prochain-aide { font-size: 12.5px; color: var(--faint); margin-top: 10px; }
.prochain-message { min-height: 1.5em; margin-top: 14px; font-size: 14px; text-align: left; }
.prochain-message:empty { min-height: 0; margin-top: 0; }
.prochain-message.erreur { color: var(--red); }

.prochain-tri {
  display: flex;
  width: max-content;
  max-width: 100%;
  margin-top: 30px;
  padding: 3px;
  background: var(--raised);
  border: 1px solid var(--line);
  border-radius: 999px;
}
.prochain-tri button {
  background: none;
  border: 0;
  border-radius: 999px;
  padding: 7px 14px;
  color: var(--muted);
  font: 500 13px var(--font);
  cursor: pointer;
}
.prochain-tri button.on { background: #eaeaea; color: #0e0e0e; }

.prochain-cartes { list-style: none; margin-top: 14px; display: grid; gap: 8px; text-align: left; }
.carte-prochain {
  display: flex;
  align-items: stretch;
  gap: 12px;
  padding: 12px 12px 12px 16px;
  background: var(--raised);
  border: 1px solid var(--line);
  border-radius: var(--r);
}
.carte-prochain.mienne { outline: 1px solid var(--raised-2); }
.carte-texte { flex: 1; min-width: 0; display: flex; flex-direction: column; justify-content: center; }
.carte-tete { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 9px; margin-bottom: 6px; }
.carte-tete .moteur-plan { width: 32px; height: 16px; fill: var(--muted); }
.carte-archi { font-size: 12px; color: var(--muted); }
.carte-statut {
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.8px;
  text-transform: uppercase;
  color: var(--text);
  border: 1px solid var(--raised-2);
  border-radius: 999px;
  padding: 1px 8px;
}
.carte-statut.statut-garage { color: var(--ok); border-color: rgba(76, 175, 80, 0.35); }
/* « En développement » : un point qui bat, le travail en cours. Blanc et pas
   vert : le vert dit « c'est à toi », et l'élue n'est encore à personne. */
.carte-statut.statut-elu { display: inline-flex; align-items: center; gap: 6px; border-color: rgba(255, 255, 255, 0.3); }
.carte-statut.statut-elu::before { content: ''; flex: none; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
@media (prefers-reduced-motion: no-preference) {
  .carte-statut.statut-elu::before { animation: elue-pouls 1.8s ease-in-out infinite; }
}
@keyframes elue-pouls { 50% { opacity: 0.2; } }

/* L'ÉLUE (01/10/2026) : la plaque d'un produit de la boutique, en plus
   grand, avant la question du vote suivant. */
.elue { margin-bottom: 44px; text-align: left; }
.elue[hidden] { display: none; }
.elue-carte {
  background: var(--raised);
  border: 1px solid var(--raised-2);
  border-radius: var(--r-lg);
  overflow: hidden;
}
.elue-carte + .elue-carte { margin-top: 14px; }
.elue-carte img { display: block; width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: cover; }
.elue-corps { padding: 16px 20px 20px; }
.elue-titre { font-size: 12px; font-weight: 700; letter-spacing: 1.1px; text-transform: uppercase; }
.elue-nom { font-size: 25px; font-weight: 600; letter-spacing: -0.3px; line-height: 1.2; margin-top: 6px; overflow-wrap: anywhere; }
.elue .carte-tete { margin: 10px 0 0; }
.elue-voix { font-size: 12px; color: var(--muted); }
.elue-texte { margin-top: 12px; font-size: 14.5px; line-height: 1.5; color: var(--muted); }
/* Un nom de soixante caractères sans espace ne doit pas pousser la case de
   vote hors de la carte. */
.carte-nom { display: block; font-size: 15.5px; font-weight: 600; line-height: 1.35; overflow-wrap: anywhere; }
.carte-pied { font-size: 12px; color: var(--faint); margin-top: 6px; }
.carte-pied .lien-texte { color: var(--faint); }
.vote {
  flex: none;
  width: 56px;
  min-height: 56px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  padding: 8px 0;
  background: transparent;
  border: 1px solid var(--line);
  border-radius: var(--r);
  color: var(--text);
  font: 600 15px var(--font);
  cursor: pointer;
  transition: background 150ms ease, color 150ms ease, border-color 150ms ease, transform 120ms cubic-bezier(0.215, 0.61, 0.355, 1);
}
.vote svg { width: 12px; height: 8px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; opacity: 0.75; }
.vote[aria-pressed="true"] { background: #eaeaea; border-color: #eaeaea; color: #0e0e0e; }
.vote[aria-pressed="true"] svg { opacity: 1; }
.vote:active { transform: scale(0.95); }
@media (hover: hover) and (pointer: fine) {
  .vote:hover { border-color: var(--muted); }
  .vote[aria-pressed="true"]:hover { filter: brightness(0.9); }
  .prochain-tri button:not(.on):hover { color: var(--text); }
  .lien-texte:hover, .prochain-note a:hover { color: var(--text); }
}
.prochain-vide { color: var(--muted); font-size: 14px; margin-top: 18px; text-align: left; }
.prochain-offre { margin-top: 44px; font-size: 14px; color: var(--muted); }
.prochain-legal { margin-top: 12px; font-size: 12px; line-height: 1.55; color: var(--faint); }
.prochain-legal a { color: var(--faint); }
@media (prefers-reduced-motion: no-preference) {
  .carte-prochain.nouvelle { animation: carte-signalee 1.6s ease-out; }
}
@keyframes carte-signalee {
  from { box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.55); }
  to { box-shadow: 0 0 0 2px rgba(255, 255, 255, 0); }
}
@media (max-width: 440px) {
  .prochain-ligne { flex-direction: column; }
  .prochain-ligne .bouton { width: 100%; }
}

/* La vitrine y mène depuis le garage : une ligne, pas un bloc. */
.garage-prochain { margin-top: 18px; font-size: 14px; color: var(--muted); }
.garage-prochain a { color: var(--text); white-space: nowrap; }

/* ---------- Les rayons : boutique, licence, vote (29/09/2026) ----------
   Les visuels sont générés dans un même studio sombre (tools/visuels-
   moteurs.mjs) : sur le fond de la page, la voiture sort du noir sans cadre
   à dessiner. Le vert ne dit qu'une chose, « c'est à toi », comme la
   pastille du moteur offert sur la vitrine. */
/* `section` porte, sur toute la vitrine, un filet et 72 px de marge : le
   filet sépare ici les rayons, la marge est ramenée à l'échelle de la page. */
.rayon { margin-top: 40px; padding: 34px 0 0; text-align: left; }
.rayon-titre { font-size: 20px; font-weight: 600; letter-spacing: -0.2px; }
.rayon-intro { color: var(--muted); font-size: 14px; margin-top: 6px; }
.prochain-achat {
  margin-top: 26px;
  padding: 14px 16px;
  background: var(--raised);
  border: 1px solid var(--raised-2);
  border-radius: var(--r);
  font-size: 14.5px;
  text-align: left;
}
.prochain-achat.erreur { color: var(--red); border-color: rgba(232, 33, 39, 0.35); }

.boutique { display: grid; gap: 14px; margin-top: 16px; }
.produit {
  background: var(--raised);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  overflow: hidden;
}
.produit img { display: block; width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: cover; }
.produit-corps { padding: 14px 18px 18px; }
.produit-nom { font-size: 21px; font-weight: 600; letter-spacing: -0.2px; }
.produit-sous { color: var(--muted); font-size: 13.5px; margin-top: 2px; }
.produit-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-top: 16px; }
.produit-possede { color: var(--ok); font-size: 14px; font-weight: 600; }
.produit-note { color: var(--faint); font-size: 12.5px; margin-top: 12px; }
/* Le passage au tout inclus : pas de photo, un contour plus net que les
   moteurs pour qu'il se lise comme une offre et non comme un moteur de plus. */
.produit-tout { border-color: var(--muted); }
.bouton.ecouter { display: inline-flex; align-items: center; gap: 8px; padding: 11px 18px; }
.bouton.ecouter svg { width: 9px; height: 11px; fill: currentColor; }
.bouton.ecouter[aria-pressed="true"] { background: var(--raised-2); }

.garage5 {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
  margin-top: 16px;
}
@media (min-width: 560px) { .garage5 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.garage5-carte {
  display: flex;
  flex-direction: column;
  background: var(--raised);
  border: 1px solid var(--line);
  border-radius: var(--r);
  overflow: hidden;
}
.garage5-carte img { display: block; width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: cover; }
.garage5-carte .carte-tete { margin: 10px 12px 0; }
.garage5-nom { display: block; margin: 2px 12px 0; font-size: 14px; font-weight: 600; line-height: 1.3; }
.garage5-carte .bouton.ecouter { align-self: flex-start; margin: 10px 12px 12px; padding: 7px 12px; font-size: 13px; }

.carte-prochain .carte-visuel {
  flex: none;
  align-self: center;
  width: 104px;
  height: auto;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: 6px;
}
.carte-demande { font-size: 12.5px; color: var(--muted); margin-top: 2px; }
@media (max-width: 400px) {
  .carte-prochain .carte-visuel { width: 78px; }
  .carte-prochain { gap: 10px; padding-left: 12px; }
}
