/* Outvroom - habillage écran de bord, langage visuel Tesla : monochrome,
   blanc le jour, noir la nuit, hairlines discrètes, rouge réservé à la
   zone rouge et aux erreurs. Aucun décor, aucune couleur d'accent.
   Cible unique : le navigateur de la Model 3 (fenêtre 773x601, tactile). */

/* ---------- Police, auto-hébergée ----------
   Le service worker ne met en cache que l'origine : une fonte Google
   disparaîtrait hors ligne, donc dans la voiture. Elle vit ici.
   Montserrat est le clone libre du Gotham de l'interface Tesla ;
   fichier variable, une seule ressource pour 400 à 600. */

@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;
}

/* ---------- Thèmes ----------
   Nuit par défaut : au volant, un écran blanc imprévu éblouit, l'inverse
   ne fait que manquer de contraste. Le jour arrive par la préférence
   système de la voiture, ou par le réglage Apparence qui force. Le canvas
   du compte-tours lit les jetons --gauge-* à la reconstruction du cadran. */

:root {
  /* `color-scheme` DIT AU NAVIGATEUR dans quel thème dessiner ce qu'il dessine
     LUI-MÊME : la liste qui s'ouvre sous un <select>, les barres de
     défilement. Sans lui, la liste des moteurs s'ouvrait en blanc système
     sous un thème nuit, avec notre texte clair hérité par-dessus : illisible
     (Arthur, dans la voiture, 20/09/2026). Il suit le thème dans les deux
     blocs « jour » plus bas. */
  color-scheme: dark;
  --bg: #0e0e0e; /* noir neutre, aucune composante bleutée */
  --surface: #1a1a1a; /* panneaux et cartes */
  --raised: rgba(255, 255, 255, 0.06); /* contrôles au repos */
  --raised-2: rgba(255, 255, 255, 0.14); /* contrôles pressés */
  --line: rgba(255, 255, 255, 0.08);
  --text: #eaeaea;
  --muted: #9a9a9a;
  --faint: #616161;
  --primary: #eaeaea; /* bouton principal : pilule blanche la nuit */
  --primary-text: #0e0e0e;
  --pill: #eaeaea; /* segment actif */
  --pill-text: #0e0e0e;
  --pill-shadow: none;
  --red: #e82127; /* zone rouge, erreurs, rien d'autre */
  --red-text: #ff7377;
  --warn: #f0b64c; /* attentes et indications */
  --ok: #4caf50;
  --overlay: rgba(0, 0, 0, 0.6);
  --gauge-rail: rgba(255, 255, 255, 0.1);
  --gauge-tick: rgba(255, 255, 255, 0.28);
  --gauge-tick-min: rgba(255, 255, 255, 0.12);
  --gauge-red-rail: rgba(232, 33, 39, 0.35);
  --gauge-red-tick: rgba(232, 33, 39, 0.7);
  --gauge-red-text: #ff5a5f;
  --r: 8px;
  --r-lg: 12px;
  --font:
    "Montserrat", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
    sans-serif;
}

/* Jour : mêmes jetons, valeurs claires. Deux blocs identiques parce que
   le CSS ne sait pas encore factoriser "média OU attribut". */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    color-scheme: light;
    --bg: #f4f4f4;
    --surface: #ffffff;
    --raised: rgba(0, 0, 0, 0.05);
    --raised-2: rgba(0, 0, 0, 0.14);
    --line: rgba(0, 0, 0, 0.08);
    --text: #0e0e0e;
    --muted: #5c5c5c;
    --faint: #9a9a9a;
    --primary: #0e0e0e;
    --primary-text: #ffffff;
    --pill: #ffffff;
    --pill-text: #0e0e0e;
    --pill-shadow: 0 1px 4px rgba(0, 0, 0, 0.18);
    --red-text: #c4181d;
    --warn: #a8791f;
    --ok: #2e7d32;
    --overlay: rgba(125, 125, 130, 0.4);
    --gauge-rail: rgba(0, 0, 0, 0.08);
    --gauge-tick: rgba(0, 0, 0, 0.35);
    --gauge-tick-min: rgba(0, 0, 0, 0.14);
    --gauge-red-rail: rgba(232, 33, 39, 0.25);
    --gauge-red-tick: rgba(232, 33, 39, 0.6);
    --gauge-red-text: #d31a20;
  }
}
:root[data-theme="light"] {
  color-scheme: light;
  --bg: #f4f4f4;
  --surface: #ffffff;
  --raised: rgba(0, 0, 0, 0.05);
  --raised-2: rgba(0, 0, 0, 0.14);
  --line: rgba(0, 0, 0, 0.08);
  --text: #0e0e0e;
  --muted: #5c5c5c;
  --faint: #9a9a9a;
  --primary: #0e0e0e;
  --primary-text: #ffffff;
  --pill: #ffffff;
  --pill-text: #0e0e0e;
  --pill-shadow: 0 1px 4px rgba(0, 0, 0, 0.18);
  --red-text: #c4181d;
  --warn: #a8791f;
  --ok: #2e7d32;
  --overlay: rgba(125, 125, 130, 0.4);
  --gauge-rail: rgba(0, 0, 0, 0.08);
  --gauge-tick: rgba(0, 0, 0, 0.35);
  --gauge-tick-min: rgba(0, 0, 0, 0.14);
  --gauge-red-rail: rgba(232, 33, 39, 0.25);
  --gauge-red-tick: rgba(232, 33, 39, 0.6);
  --gauge-red-text: #d31a20;
}

* {
  box-sizing: border-box;
}

html,
body {
  height: 100%;
  margin: 0;
}

body {
  background: var(--bg);
  color: var(--text);
  font: 15px/1.45 var(--font);
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
  overscroll-behavior: none;
  display: flex;
  flex-direction: column;
  padding-bottom: env(safe-area-inset-bottom);
}

/* 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;
}

/* Un sélecteur de classe portant display: bat l'attribut [hidden] de la
   feuille navigateur. Sans ce garde, .panel et .pedals restent visibles. */
[hidden] {
  display: none !important;
}

button,
select,
input {
  font: inherit;
  color: inherit;
}
button {
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.muted {
  color: var(--muted);
}
.small {
  font-size: 13px;
}

/* Barres de défilement discrètes, assorties au fond. */
::-webkit-scrollbar {
  width: 6px;
  height: 6px;
}
::-webkit-scrollbar-track {
  background: transparent;
}
::-webkit-scrollbar-thumb {
  background: var(--raised-2);
  border-radius: 3px;
}

/* ---------- Barre supérieure ---------- */

.bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 5px 16px;
  border-bottom: 1px solid var(--line);
  flex: 0 0 auto;
}

.brand {
  display: flex;
  align-items: center;
  gap: 14px;
  min-width: 0;
}

/* Marque en capitales espacées, comme le lettrage T E S L A. */
.logo {
  font-weight: 500;
  font-size: 15px;
  letter-spacing: 0.42em;
  margin-right: -0.42em; /* compense l'espacement après la dernière lettre */
  color: var(--text);
  /* Jamais sur deux lignes : quand la barre manque de place, c'est la
     version qui cède (voir .version), pas la marque. */
  flex: none;
  white-space: nowrap;
}

.status {
  font-size: 12px;
  line-height: 1.3;
  color: var(--muted);
  /* Deux lignes au plus, puis les points de suspension : un refus de
     localisation tronqué après « Localisation refusé… » ne disait plus
     comment s'en sortir. La barre a la hauteur de l'icône des réglages
     (44 px), deux lignes y tiennent sans la faire grandir. */
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
  min-width: 0;
}
.status::before {
  content: "";
  display: inline-block;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  margin-right: 8px;
  background: var(--faint);
  vertical-align: middle;
}
.status.ok::before {
  background: var(--ok);
}
.status.wait::before {
  background: var(--warn);
  animation: pulse 1.4s ease-in-out infinite;
}
.status.bad {
  color: var(--red-text);
}
.status.bad::before {
  background: var(--red);
}

/* NAVIGATEUR TROP ANCIEN (second script d'index.html) : le message prend la
   place de la scène, et tout ce qui ne peut pas marcher disparaît. Chaque
   couleur est écrite en clair AVANT sa variable : rien ne garantit que le
   navigateur d'une MCU1 lise les propriétés personnalisées. */
.navigateur-ancien .stage,
.navigateur-ancien .shiftlights,
.navigateur-ancien .pedals,
.navigateur-ancien .liaisons,
.navigateur-ancien .bar-actions,
.navigateur-ancien .version {
  display: none !important;
}
.refus-ancien {
  max-width: 560px;
  margin: 48px auto 0;
  padding: 0 24px;
}
.refus-ancien h1 {
  font-size: 26px;
  font-weight: 600;
  line-height: 1.25;
  margin: 0 0 14px;
}
.refus-ancien p {
  font-size: 17px;
  line-height: 1.5;
  color: #9a9a9a;
  color: var(--muted);
  margin: 0 0 12px;
}
.refus-ancien .refus-force {
  font-size: 13px;
  color: #616161;
  color: var(--faint);
}

/* Le GPS et le téléphone (bêta, refaits le 12/10/2026). La première version
   (08/10) était deux pastilles à point vert ou rouge, le téléphone sans un
   mot : on y voyait un rouge sans savoir de quoi, ni qu'il se touchait. Ici,
   comme les témoins de la barre d'état Tesla : une icône et des mots, sans
   cadre ni point. Blanc quand ça marche, gris quand ça attend ou dort, rouge
   seulement pour une panne. L'icône respire tant qu'on attend quelque chose. */
.liaisons {
  display: flex;
  align-items: center;
  gap: 18px;
  margin-left: auto; /* contre les réglages, loin du message d'état */
  flex: 0 0 auto;
}
.liaison {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--muted);
  font: inherit;
  font-size: 13px;
  line-height: 1;
  white-space: nowrap;
}
.liaison-ico {
  width: 17px;
  height: 17px;
  flex: 0 0 auto;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linejoin: round;
  stroke-linecap: round;
}
.liaison.ok {
  color: var(--text);
}
.liaison.ok .liaison-ico {
  fill: currentColor;
}
.liaison.ok .liaison-ico path {
  stroke: var(--bg);
}
#pastille-gps.ok .liaison-ico path {
  stroke: currentColor;
}
.liaison.attend .liaison-ico {
  animation: pulse 1.4s ease-in-out infinite;
}
.liaison.consigne {
  color: var(--text);
}
.liaison.panne {
  color: var(--red-text);
}
/* Le téléphone se touche : une vraie zone de doigt (44 px de haut), et la
   flèche quand le toucher mène quelque part (le QR à scanner), comme
   « Changer de voiture ». */
.liaison-tel {
  min-height: 44px;
  margin: -6px 0;
  cursor: pointer;
}
.liaison-suite {
  display: none;
  width: 7px;
  height: 12px;
  margin-left: 1px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.liaison-tel.suite .liaison-suite {
  display: block;
}
.liaison-tel.agir {
  color: var(--text);
}
.liaison-tel:active {
  opacity: 0.6;
}

/* Ligne sans objet (claquements de décélération, clapets fermés). */
.field.row.grise {
  opacity: 0.4;
}

/* Version réellement en service (celle du service worker qui contrôle la
   page) : le seul moyen, depuis la voiture, de savoir si une mise à jour
   est passée ou si l'écran rejoue encore l'ancienne. */
.version {
  font-size: 11px;
  color: var(--muted);
  opacity: 0.65;
  white-space: nowrap;
  /* Cède la place en premier, tronquée par la fin : « 3.42-beta-20de… »
     dit encore la version, alors qu'un message d'état coupé ne dit plus
     rien (bêta, où les témoins GPS et téléphone prennent la droite). */
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  flex-shrink: 4;
}

/* Pastille de mise à jour : une nouvelle version a pris le contrôle pendant
   que la page tournait, le code en mémoire est en retard. On le DIT, on ne
   recharge jamais tout seul : pas en roulant. */
.maj {
  position: fixed;
  left: 16px;
  bottom: 16px;
  z-index: 80;
  padding: 11px 16px;
  border: 0;
  border-radius: var(--r);
  background: var(--primary);
  color: var(--primary-text);
  font-weight: 600;
  font-size: 13px;
  box-shadow: 0 4px 18px rgba(0, 0, 0, 0.35);
}
.maj:active {
  filter: brightness(0.85);
}

/* ---------- Nouvelle version : la fenêtre ----------
   Au-dessus de la pastille (80), qui se cache pendant qu'elle est ouverte.
   Le numéro de version en grand, comme le rapport engagé du compte-tours :
   c'est la seule chose qu'on doit lire d'un coup d'œil. Tout tient dans
   773x601 sans défiler, quatre nouveautés sur deux lignes comprises. */
.maj-fond {
  z-index: 90;
}
/* Double classe : `.panel-inner`, déclaré plus bas, imposerait sinon ses 880 px. */
.panel-inner.maj-carte {
  width: min(660px, 100%);
  padding: 28px 30px 22px;
  animation: maj-entree 0.32s cubic-bezier(0.2, 0.8, 0.2, 1) both;
}
.maj-titre {
  margin: 0;
  display: grid;
  gap: 4px;
  font-weight: 600;
}
/* Le téléphone capteur (bêta) : le QR à gauche sur fond clair (un téléphone
   le lit mal sur le noir), le texte à droite. Tient dans 773x601. */
.panel-inner.tel-carte {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 26px;
  align-items: center;
}
.tel-qr {
  background: #fff;
  padding: 10px;
  border-radius: 10px;
  line-height: 0;
}
.tel-qr canvas {
  width: 180px;
  height: 180px;
}
.tel-grand {
  font-size: 24px;
  line-height: 1.2;
}
.tel-etat {
  margin: 4px 0 14px;
  font-size: 14px;
  color: var(--text);
  min-height: 1.4em;
}
.maj-sur {
  font-size: 11px;
  letter-spacing: 2.2px;
  text-transform: uppercase;
  color: var(--muted);
}
.maj-numero {
  font-size: 56px;
  line-height: 1;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}
.maj-intro {
  margin: 20px 0 8px;
  font-size: 13px;
  color: var(--muted);
}
.maj-liste {
  list-style: none;
  margin: 0;
  padding: 0;
}
.maj-liste li {
  display: grid;
  grid-template-columns: 22px 1fr;
  gap: 8px;
  padding: 10px 0;
  border-top: 1px solid var(--line);
  font-size: 15px;
  line-height: 1.4;
}
.maj-liste li:last-child {
  border-bottom: 1px solid var(--line);
}
/* Une coche tracée en bordures : elle prend la couleur du thème, là où une
   image aurait figé un blanc ou un noir. */
.maj-liste li::before {
  content: "";
  width: 6px;
  height: 11px;
  margin: 3px 0 0 6px;
  border: solid var(--text);
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}
.maj-actions {
  display: flex;
  gap: 10px;
  margin-top: 22px;
}
/* Moteur en route, `.primary.big` passe au gris (bouton Arrêter) : ici le
   rechargement reste l'action principale, en blanc la nuit, noir le jour. */
#majpanel .primary.big {
  flex: 1 1 auto;
  background: var(--primary);
  color: var(--primary-text);
}
.maj-secondaire {
  flex: 0 0 auto;
  border: 0;
  border-radius: var(--r);
  padding: 14px 20px;
  background: var(--raised);
  color: var(--text);
  font-weight: 600;
  font-size: 16px;
}
.maj-secondaire:active {
  background: var(--raised-2);
}
.maj-pied {
  margin: 12px 0 0;
  text-align: center;
}
/* La case « Ne plus afficher » de l'alerte volume : une cible de doigt, pas de souris. */
.vol-muet {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 16px 0 0;
  padding: 6px 0;
  cursor: pointer;
}
.vol-muet input {
  width: 22px;
  height: 22px;
  margin: 0;
  accent-color: var(--text, #111);
}
@keyframes maj-entree {
  from {
    opacity: 0;
    transform: translateY(12px) scale(0.98);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
@media (prefers-reduced-motion: reduce) {
  .maj-carte {
    animation: none;
  }
}

@keyframes pulse {
  50% {
    opacity: 0.25;
  }
}

.bar-actions {
  display: flex;
  gap: 4px;
  flex: 0 0 auto;
}

/* Icônes de barre : glyphe seul, sans boîte, comme la barre Tesla. */
.icon {
  width: 44px;
  height: 44px;
  border: 0;
  border-radius: var(--r);
  background: transparent;
  color: var(--muted);
  font-size: 20px;
  line-height: 1;
  display: grid;
  place-items: center;
}
.icon svg {
  display: block;
}
.icon:active {
  background: var(--raised);
  color: var(--text);
}

/* ---------- Rampe de passage de rapport ---------- */

/* Discrète au repos, elle se remplit dans la couleur du texte puis en
   rouge à l'approche de la zone rouge. Pas de halo. */
.shiftlights {
  display: flex;
  justify-content: center;
  gap: clamp(4px, 1vw, 8px);
  padding: 6px 16px 1px;
  flex: 0 0 auto;
}
.shiftlights i {
  width: clamp(18px, 3vw, 30px);
  height: 5px;
  border-radius: 3px;
  background: var(--gauge-rail);
  transition: background 0.05s;
}
.shiftlights i.on {
  background: var(--text);
}
.shiftlights i.on:nth-child(n + 9) {
  background: var(--red);
}
/* Outvroom : tout clignote. */
.shiftlights.lim i {
  animation: limiter 0.14s steps(2, end) infinite;
}
@keyframes limiter {
  50% {
    opacity: 0.2;
  }
}

/* ---------- Scène ---------- */

/* Calé sur la fenêtre du navigateur Tesla : 773x601. La colonne de droite
   prend environ 300 px là-dessus, et respire si la fenêtre grandit. */
.stage {
  flex: 1 1 auto;
  min-height: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr) clamp(280px, 39vw, 380px);
  gap: 16px;
  padding: 6px 16px 12px;
}

/* Zone gauche : le cadran prend toute la hauteur disponible ; en boîte
   manuelle, le bouton Rétrograder s'installe dessous, près du volant. */
.dial-wrap {
  position: relative;
  min-height: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}

#tacho {
  flex: 1 1 0;
  min-height: 0;
  max-width: 100%;
  max-height: 100%;
  aspect-ratio: 1;
}

/* ---------- Colonne latérale ---------- */

/* La colonne se découpe en deux : une zone qui défile, et un pied fixe.
   Le bouton principal ne doit jamais recouvrir un réglage : sur un écran de
   voiture, un contrôle masqué est un contrôle inutilisable. */
.side {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-height: 0;
}

.side-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding-right: 4px;
}

.field {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
/* Ligne label + commande. Si la commande ne tient pas à côté du label dans
   la colonne Tesla, elle passe dessous, pleine largeur, sans déborder. */
.field.row {
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 5px 10px;
}
.field.row .seg {
  flex: 1 1 auto;
}
.field label {
  font-size: 12px;
  font-weight: 500;
  color: var(--muted);
}

select {
  appearance: none;
  background: var(--raised)
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='8'><path d='M1 1l5 5 5-5' stroke='%239a9a9a' stroke-width='1.8' fill='none' stroke-linecap='round' stroke-linejoin='round'/></svg>")
    no-repeat right 12px center;
  border: 0;
  border-radius: var(--r);
  padding: 10px 34px 10px 12px;
  width: 100%;
  font-weight: 500;
  font-size: 14px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
select:disabled {
  opacity: 0.5;
}
/* La ceinture avec les bretelles : le Chromium de la Tesla (Linux) peint les
   options avec leurs propres couleurs quand on les lui donne. Fond OPAQUE :
   --raised est une transparence, qui laisserait voir le blanc du système. */
select option,
select optgroup {
  background-color: var(--surface);
  color: var(--text);
}

/* Commande segmentée : rail discret, segment actif en pilule claire.
   Le motif Tesla, sans couleur par mode. */
.seg {
  display: flex;
  background: var(--raised);
  border-radius: var(--r);
  padding: 2px;
  gap: 2px;
}
.seg button {
  border: 0;
  background: transparent;
  color: var(--muted);
  padding: 6px 10px;
  border-radius: 6px;
  font-weight: 500;
  font-size: 13px;
  min-height: 34px;
  white-space: nowrap;
  flex: 1 1 auto;
}
.seg button.on {
  background: var(--pill);
  color: var(--pill-text);
  font-weight: 600;
  box-shadow: var(--pill-shadow);
}

/* « Ma Tesla » : une rangée comme les autres, un seul bouton au gris des
   sélecteurs, le nom coupé proprement s'il est long (Grande Autonomie
   Transmission Intégrale). */
.tesla-bouton {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  min-height: 38px;
  padding: 6px 12px;
  border: 0;
  border-radius: var(--r);
  background: var(--raised);
  color: inherit;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  text-align: left;
}
.tesla-bouton:active {
  background: var(--raised-2);
}
#tesla-nom {
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Le son d'une électrique : à quatre sons (bêta, 12/10/2026) la rangée ne
   tient plus dans la colonne à 773 px, « Hot hatch » sortait coupé. Deux
   lignes de deux, chaque bouton à moitié de largeur. */
#ligne-son-elec .seg:has(#son-elec-3:not([hidden])) {
  display: grid;
  grid-template-columns: 1fr 1fr;
}
#ligne-son-toon .seg {
  display: grid;
  grid-template-columns: 1fr 1fr;
}
/* LE CURSEUR À LA TESLA (volume du ralenti électrique, 20/10/2026), comme
   la luminosité de l'écran : le rail des commandes segmentées et, dedans,
   une pilule qui s'étend de la gauche jusqu'à la valeur, le pourcentage à
   son bout. Mêmes jetons que `.seg` et `.seg button.on`, donc les deux
   thèmes suivent. `--v` (0 à 1) est écrit par main.js. La pilule garde une
   largeur minimale pour que « 0 % » y tienne. */
#ligne-ralenti-elec {
  flex-wrap: nowrap;
}
.curseur-tesla {
  --ct-min: 58px;
  position: relative;
  flex: 1 1 auto;
  min-width: 0;
  height: 38px;
  background: var(--raised);
  border-radius: var(--r);
}
.ct-plein {
  position: absolute;
  top: 2px;
  bottom: 2px;
  left: 2px;
  width: calc(var(--ct-min) + (100% - 4px - var(--ct-min)) * var(--v, 0.5));
  max-width: calc(100% - 4px);
  display: flex;
  align-items: center;
  justify-content: flex-end;
  padding: 0 12px;
  box-sizing: border-box;
  border-radius: 6px;
  background: var(--pill);
  color: var(--pill-text);
  box-shadow: var(--pill-shadow);
  font-size: 13px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  pointer-events: none;
}
/* Le doigt est lu par le grand rectangle lui-même (main.js,
   brancherCurseurTesla) : aucun défilement ni zoom ne doit le lui voler. Le
   curseur natif, invisible et hors du pointeur, ne sert qu'au clavier et à
   l'accessibilité. */
.curseur-tesla {
  touch-action: none;
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
}
.curseur-tesla input[type="range"] {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  pointer-events: none;
}
.curseur-tesla:has(input:focus-visible) {
  outline: 2px solid var(--muted);
  outline-offset: 2px;
}

.modes .seg {
  flex: 1 1 auto;
}
.modes .seg button {
  flex: 1 1 0;
  padding: 10px 6px;
}

input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 34px;
  background: transparent;
}
input[type="range"]::-webkit-slider-runnable-track {
  height: 4px;
  background: var(--raised-2);
  border-radius: 2px;
}
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 26px;
  height: 26px;
  margin-top: -11px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
}
input[type="range"]::-moz-range-track {
  height: 4px;
  background: var(--raised-2);
  border-radius: 2px;
}
input[type="range"]::-moz-range-thumb {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: #fff;
  border: 0;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
}

/* Bouton principal : pilule pleine, monochrome. Blanche la nuit, anthracite
   le jour, comme les boutons de premier plan de l'écran Tesla. */
.primary {
  background: var(--primary);
  color: var(--primary-text);
  border: 0;
  border-radius: var(--r);
  padding: 12px 18px;
  font-weight: 600;
  font-size: 15px;
}
.primary:active {
  filter: brightness(0.85);
}
.primary:disabled {
  opacity: 0.35;
}

.primary.big {
  padding: 14px;
  font-size: 16px;
  flex: 0 0 auto;
}
/* En route, le même bouton devient Arrêter : gris neutre, jamais rouge,
   pour ne pas ressembler à une alerte permanente. */
body.running .primary.big {
  background: var(--raised);
  color: var(--text);
}

/* Rétrogradage du mode manuel : TOUTE la zone gauche est la cible, cadran
   compris. Au volant on tape large, on ne vise pas un bouton. Tuile grise
   arrondie visible au repos, comme les pédales : la zone se lit d'un coup
   d'oeil comme une commande. Le fond est translucide, le cadran reste
   lisible au travers. La montée, elle, vit sur la molette du volant. */
.retro-big {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding: 0 0 6px;
  background: var(--raised);
  border: 0;
  border-radius: var(--r-lg);
  color: var(--muted);
  font-weight: 600;
  font-size: 14px;
  touch-action: manipulation;
  -webkit-user-select: none;
  user-select: none;
}
.retro-big:active {
  background: var(--raised-2);
  color: var(--text);
}

/* ---------- Pédales du mode démo ---------- */

.pedals {
  display: grid;
  grid-template-columns: 1fr 2fr;
  gap: 10px;
  padding: 0 16px 10px;
  flex: 0 0 auto;
}
.pedal {
  border: 0;
  border-radius: var(--r-lg);
  background: var(--raised);
  color: var(--text);
  padding: 12px;
  font-weight: 500;
  font-size: 15px;
  touch-action: none;
  user-select: none;
  transition: background 0.06s;
}
.pedal.gas.down {
  background: var(--raised-2);
}
/* Le frein s'allume en rouge : réflexe feux stop, lisible sans lire. */
.pedal.brake.down {
  background: rgba(232, 33, 39, 0.3);
}

/* ---------- Panneaux ---------- */

.panel {
  position: fixed;
  inset: 0;
  background: var(--overlay);
  backdrop-filter: blur(16px);
  z-index: 20;
  display: grid;
  place-items: center;
  padding: 20px;
  /* LE CLAVIER DE LA VOITURE MASQUE LE BAS DE L'ECRAN, et le champ de code
     vit justement en bas du panneau : il etait litteralement invisible
     pendant qu'on le remplissait. `--clavier` est pose par paywall.js depuis
     visualViewport ; a zero, rien ne change. La grille recentre alors le
     panneau dans ce qui reste visible. */
  padding-bottom: calc(20px + var(--clavier, 0px));
}
/* Mode allégé (calculateur Atom, main.js) : un flou plein écran se recalcule
   à chaque image du cadran qui tourne dessous, panneau de réglages ouvert
   moteur en marche. La carte du panneau est opaque, elle reste lisible. */
.allege .panel {
  backdrop-filter: none;
}
.panel-inner {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 14px;
  width: min(880px, 100%);
  max-height: 100%;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 20px;
  border-bottom: 1px solid var(--line);
  flex: 0 0 auto;
}
.panel-head h2 {
  margin: 0;
  font-size: 17px;
  font-weight: 600;
}
.panel-body {
  padding: 20px;
  overflow-y: auto;
}
.panel-body h3 {
  font-size: 15px;
  margin: 24px 0 10px;
  font-weight: 600;
}
/* ---------- Panneau de réglages ---------- */

.panel-head-actions {
  display: flex;
  gap: 8px;
  align-items: center;
}
.panel-head-actions > button:not(.icon) {
  background: var(--raised);
  border: 0;
  border-radius: var(--r);
  padding: 10px 14px;
  color: var(--muted);
  font-size: 13px;
  font-weight: 500;
}
.panel-head-actions > button:not(.icon):active {
  background: var(--raised-2);
  color: var(--text);
}

.tn-group {
  margin-bottom: 26px;
}
.tn-group h3 {
  font-size: 15px;
  margin: 0 0 4px;
  font-weight: 600;
  color: var(--text);
}
.tn-group > p {
  margin: 0 0 12px;
}

.tn-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 190px 82px;
  gap: 14px;
  align-items: center;
  padding: 9px 0;
  border-bottom: 1px solid var(--line);
}
.tn-row:last-child {
  border-bottom: 0;
}
.tn-label {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.tn-label span {
  font-size: 14px;
}
.tn-label small {
  font-size: 11px;
  color: var(--muted);
  line-height: 1.35;
}
.tn-val {
  font-variant-numeric: tabular-nums;
  font-size: 13px;
  font-weight: 500;
  color: var(--muted);
  text-align: right;
}
.tn-range {
  width: 100%;
  height: 30px;
}

.tn-toggle {
  grid-column: 2 / 4;
  justify-self: end;
  background: var(--raised);
  border: 0;
  border-radius: var(--r);
  padding: 10px 22px;
  color: var(--muted);
  font-weight: 500;
  min-width: 84px;
}
.tn-toggle.on {
  background: var(--pill);
  color: var(--pill-text);
  font-weight: 600;
  box-shadow: var(--pill-shadow);
}
/* « Faire connaître Outvroom » sans les mesures de fonctionnement ne fait
   rien : grisé et à « non », il le montre sans rien cacher. */
.tn-toggle:disabled {
  opacity: 0.45;
}

/* Bloc d'essai d'écoute : une consigne, un bouton, une ligne d'état. Détaché
   des curseurs par un fond, parce qu'on ne le règle pas, on le déclenche. */
.tn-essai {
  margin-top: 14px;
  padding: 14px;
  background: var(--raised);
  border-radius: var(--r);
}
.tn-essai > p {
  margin: 0;
  font-size: 11px;
  color: var(--muted);
  line-height: 1.45;
}
.tn-essai-go {
  margin: 12px 0 0;
  background: var(--pill);
  color: var(--pill-text);
  border: 0;
  border-radius: var(--r);
  padding: 11px 22px;
  font-weight: 600;
  box-shadow: var(--pill-shadow);
}
.tn-essai-go:disabled {
  opacity: 0.55;
}
/* L'état ne réserve sa place que lorsqu'il parle : vide, il ne creuse pas
   un blanc sous le bouton. */
.tn-essai-etat:empty {
  display: none;
}
.tn-essai-etat {
  margin-top: 10px !important;
  font-weight: 600;
  color: var(--text) !important;
}

/* Apparence : Auto suit le jour/nuit de la voiture, Clair et Sombre
   forcent. Rangé ici, avec les réglages, comme sur l'écran Tesla. */
.tn-apparence {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 20px;
  border-top: 1px solid var(--line);
  flex: 0 0 auto;
}
.tn-apparence label {
  font-size: 13px;
  font-weight: 500;
  color: var(--muted);
}
.tn-apparence .seg {
  flex: 0 1 320px;
}
/* Le sélecteur de langue tient la même colonne que la commande segmentée
   d'à côté : `select` est en largeur 100 %, ce qui ferait déborder la ligne
   d'un conteneur en espacement réparti. */
.tn-langue {
  flex: 0 1 320px;
  width: auto;
}

.tn-foot {
  padding: 12px 20px;
  border-top: 1px solid var(--line);
  margin: 0;
  flex: 0 0 auto;
}

/* Attribution du pack courant. Obligatoire pour les licences CC BY / CC BY-SA. */
.credit {
  margin: 2px 0 0;
  font-size: 11px;
  line-height: 1.35;
  color: var(--faint);
}
.credit a {
  color: var(--faint);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.credit a:hover {
  color: var(--muted);
}
/* Le lien des propositions est une invitation, pas une mention légale : un
   cran plus lisible que le crédit d'un enregistrement. */
.credit a.lien-prochain {
  color: var(--muted);
}
.credit a.lien-prochain:hover {
  color: var(--text);
}

/* ---------- Adaptations ---------- */

/* Tout est calé sur la fenêtre du navigateur Tesla (773x601). Si le
   navigateur passe en plein écran, on respire un peu plus, c'est tout. */
@media (min-height: 700px) and (min-width: 1100px) {
  .stage {
    gap: 32px;
    padding: 18px 28px 24px;
  }
  .side {
    gap: 16px;
  }
}

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

/* ---------- Outvroom Premium ----------
   Le panneau d'achat suit le langage des autres panneaux : surface, hairlines,
   monochrome. Seul écart : le fond du QR reste blanc dans les deux thèmes,
   parce que c'est l'appareil photo du téléphone qui le lit, pas l'oeil. */

.premium-cta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
  background: var(--raised);
  border: 1px solid var(--line);
  border-radius: var(--r);
  color: var(--text);
  padding: 12px 14px;
  font-weight: 600;
  font-size: 14px;
}
.premium-cta:active {
  background: var(--raised-2);
}
.premium-prix {
  color: var(--muted);
  font-weight: 400;
  font-size: 13px;
}

.panel-inner.pw {
  width: min(720px, 100%);
}

/* ---------- Changer de voiture (29/09/2026, pour tous depuis la 2.87) ----------
   Le bouton de l'écran principal montre la voiture au volant ; la fenêtre
   range toutes les voitures en cartes à photo. Les photos sortent d'un même
   studio sombre (tools/visuels-moteurs.mjs) : leur fond de vignette est ce
   gris-là dans les deux thèmes, pour qu'une photo absente laisse une place
   propre. Monochrome : l'étoile d'un favori se remplit, elle ne se colore pas. */
.cv-bouton {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  background: var(--raised);
  border: 0;
  border-radius: var(--r-lg);
  padding: 8px 14px 8px 8px;
  text-align: left;
}
.cv-bouton:active {
  background: var(--raised-2);
}
.cv-bouton:disabled {
  opacity: 0.5;
}
.cv-bouton .cv-visuel {
  flex: 0 0 96px;
  width: 96px;
  border-radius: var(--r);
}
.cv-texte {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.cv-texte strong {
  font-size: 15px;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cv-action {
  font-size: 12px;
  color: var(--muted);
}
.cv-chevron {
  flex: 0 0 8px;
  width: 8px;
  height: 12px;
  fill: none;
  stroke: var(--muted);
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.cv-visuel {
  display: block;
  position: relative;
  aspect-ratio: 16 / 9;
  background: #151515;
  overflow: hidden;
}
.cv-visuel img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.cv-visuel.sans-photo img {
  visibility: hidden;
}
/* Un dessin entre en entier dans sa case (choix-voiture.js, `estDessin`). */
.cv-visuel.dessin img {
  object-fit: contain;
  padding: 6% 5%;
}

/* Pleine hauteur : la fenêtre ne change pas de taille d'une section à l'autre. */
.panel-inner.cv {
  width: min(880px, 100%);
  height: 100%;
}
.cv .panel-body {
  flex: 1 1 auto;
  min-height: 0;
  padding: 2px 20px 20px;
}
.cv-section h3 {
  margin: 16px 0 10px;
}
.cv-grille {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 12px;
}
.cv-carte {
  position: relative;
}
.cv-choisir,
.cv-pack-corps {
  display: flex;
  flex-direction: column;
  gap: 2px;
  width: 100%;
  height: 100%;
  background: var(--raised);
  border: 2px solid transparent;
  border-radius: var(--r-lg);
  padding: 0 0 10px;
  text-align: left;
  overflow: hidden;
}
.cv-choisir:active {
  background: var(--raised-2);
}
.cv-choisir > .cv-visuel,
.cv-mosaique {
  margin-bottom: 6px;
}
.cv-carte.en-cours .cv-choisir {
  border-color: var(--text);
}
.cv-nom {
  padding: 0 10px;
  font-size: 14px;
  font-weight: 600;
  line-height: 1.25;
}
.cv-sous {
  padding: 0 10px;
  font-size: 11.5px;
  line-height: 1.3;
  color: var(--muted);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.cv-etat {
  margin: 4px 10px 0;
  font-size: 12px;
  font-weight: 600;
  color: var(--text);
}
.cv-apercu {
  color: var(--muted);
  font-weight: 500;
}
/* L'étoile se pose sur la photo, toujours sombre : blanc sur voile noir dans
   les deux thèmes. 40 px de cible, un doigt en roulant n'est pas une souris. */
.cv-etoile {
  position: absolute;
  top: 4px;
  right: 4px;
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.45);
  color: #fff;
}
.cv-etoile svg {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linejoin: round;
}
.cv-etoile[aria-pressed="true"] svg {
  fill: currentColor;
}
.cv-vide {
  margin: 0;
  font-size: 13px;
  color: var(--muted);
}
.cv-pack {
  grid-column: span 2;
}
.cv-mosaique {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 2px;
}
/* ---------- Aide de la boîte manuelle ---------- */

/* Le dessin à gauche, le texte à droite, lisibles ensemble sans faire défiler
   dans une voiture. La fenêtre du navigateur Tesla fait 773 px de large : le
   panneau tient dedans avec ses marges. */
.panel-inner.aide {
  width: min(700px, 100%);
}
.aide .panel-body {
  display: grid;
  grid-template-columns: 300px 1fr;
  gap: 18px 26px;
  align-items: center;
}
.aide-fig {
  margin: 0;
  display: grid;
  justify-items: center;
  gap: 8px;
}
.aide-image {
  position: relative;
  width: 100%;
  border-radius: var(--r-lg);
  overflow: hidden;
  /* Le même gris que le fond de l'image : les coins arrondis ne laissent
     apparaître aucun liseré, dans les deux thèmes. */
  background: #1a1a1a;
}
.aide-image img {
  display: block;
  width: 100%;
  height: auto;
}
.aide-fig figcaption {
  font-size: 12px;
  color: var(--muted);
  text-align: center;
}
.aide-liste {
  margin: 0;
  padding: 0 0 0 20px;
  display: grid;
  gap: 12px;
  font-size: 14px;
  line-height: 1.45;
  color: var(--muted);
}
.aide-liste li::marker {
  color: var(--faint);
}
.aide-liste b {
  color: var(--text);
  font-weight: 600;
}
/* Le bouton tient la largeur des deux colonnes : c'est la seule action. */
.aide #aide-ok {
  grid-column: 1 / -1;
}

/* L'ONDE SUR LA MOLETTE ET LE RAPPORT QUI PASSE, au même rythme, trois secondes.
   La position de l'onde est celle de la molette dans l'image (46 % en x, 52 %
   en y) : l'image ne bouge pas, ce sont les seules pièces animées. Sur l'image
   sombre, tout est blanc quel que soit le thème. */
.aide-onde {
  position: absolute;
  left: 46%;
  top: 52%;
  width: 34px;
  height: 34px;
  margin: -17px 0 0 -17px;
  border: 2px solid #fff;
  border-radius: 50%;
  opacity: 0;
  animation: aide-onde 3s ease-out infinite;
}
.aide-rapport {
  position: absolute;
  right: 12px;
  bottom: 10px;
  display: grid;
  justify-items: end;
  line-height: 1;
  color: #fff;
}
.aide-rapport-titre {
  font-size: 10px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  opacity: 0.55;
  margin-bottom: 4px;
}
.aide-rapport-avant,
.aide-rapport-apres {
  font-size: 30px;
  font-weight: 600;
  grid-area: 2 / 1;
}
.aide-rapport-avant {
  animation: aide-avant 3s steps(1, end) infinite;
}
.aide-rapport-apres {
  animation: aide-apres 3s steps(1, end) infinite;
}

@keyframes aide-onde {
  0%,
  30% {
    opacity: 0;
    transform: scale(0.55);
  }
  36% {
    opacity: 0.9;
    transform: scale(0.7);
  }
  70%,
  100% {
    opacity: 0;
    transform: scale(1.6);
  }
}
@keyframes aide-avant {
  0%,
  37% {
    opacity: 1;
  }
  38%,
  100% {
    opacity: 0;
  }
}
@keyframes aide-apres {
  0%,
  37% {
    opacity: 0;
  }
  38%,
  100% {
    opacity: 1;
  }
}

/* Sans animation : l'onde reste posée sur la molette, le rapport est passé. */
@media (prefers-reduced-motion: reduce) {
  .aide-onde,
  .aide-rapport-avant,
  .aide-rapport-apres {
    animation: none;
  }
  .aide-onde {
    opacity: 0.8;
    transform: scale(0.7);
  }
  .aide-rapport-avant {
    opacity: 0;
  }
  .aide-rapport-apres {
    opacity: 1;
  }
}

@media (max-width: 640px) {
  .panel-inner.aide {
    width: 100%;
  }
  .aide .panel-body {
    grid-template-columns: 1fr;
  }
}

.pw-raison {
  margin: 0 0 14px;
  font-size: 15px;
  color: var(--muted);
}
.pw-attente {
  display: grid;
  gap: 10px;
  max-width: 520px;
}
.pw-attente p {
  margin: 0;
}
.pw-attente-titre {
  font-size: 22px;
  font-weight: 600;
}
.pw-attente-code {
  font-size: 15px;
  letter-spacing: 1px;
  color: var(--text);
}
.pw-attente-texte {
  font-size: 14px;
  color: var(--muted);
}
.pw-attente-aide {
  font-size: 13px;
  color: var(--faint);
}
/* Le bouton « même Tesla » et son repli vers l'offre, sur une ligne à 773 px. */
.pw-profil-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
}
.pw-profil-offre {
  background: var(--raised);
  border: 1px solid var(--line);
  border-radius: var(--r);
  color: var(--text);
  padding: 10px 14px;
  font-weight: 600;
  font-size: 13px;
}
.pw-cols {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 24px;
  align-items: start;
}
.pw-prix {
  margin: 0;
  display: flex;
  align-items: baseline;
  gap: 10px;
}
.pw-prix strong {
  font-size: 34px;
  font-weight: 600;
  letter-spacing: 0.5px;
}
.pw-prix s {
  color: var(--faint);
  font-size: 18px;
}
.pw-vie {
  margin: 2px 0 14px;
  color: var(--muted);
  font-size: 13px;
}
.pw-liste {
  margin: 0;
  padding: 0 0 0 18px;
  display: grid;
  gap: 8px;
  font-size: 14px;
}
.pw-liste li::marker {
  color: var(--faint);
}
/* Écouter avant d'acheter : une pastille par moteur payant, sous la liste. */
.pw-ecoute {
  margin-top: 14px;
}
.pw-ecoute-titre {
  margin: 0 0 8px;
  font-size: 13px;
  color: var(--muted);
}
.pw-ecoute-liste {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.pw-extrait {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: var(--raised);
  border: 1px solid var(--line);
  border-radius: var(--r);
  color: var(--text);
  padding: 8px 12px;
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
}
.pw-extrait:active,
.pw-extrait.joue {
  background: var(--raised-2);
}
/* Lecture : un triangle ; en cours : un carré. Dessinés, pas de glyphe. */
.pw-extrait-icone {
  width: 0;
  height: 0;
  border-style: solid;
  border-width: 5px 0 5px 8px;
  border-color: transparent transparent transparent currentColor;
}
.pw-extrait.joue .pw-extrait-icone {
  width: 9px;
  height: 9px;
  border: 0;
  background: currentColor;
}
.pw-achat {
  display: grid;
  justify-items: center;
  gap: 8px;
  align-content: start;
}
/* Le bouton d'achat occupe la place du QR tant qu'on n'a pas cliqué : même
   colonne, même largeur, pour que le panneau ne saute pas quand le QR le
   remplace. 210 px, c'est la taille du QR dessiné. */
.pw-acheter {
  width: 210px;
}
/* Les deux offres (16/10/2026) : deux boutons de même taille, le prix en
   gros et l'offre dessous. Le tout inclus porte un contour, pas une couleur :
   le langage reste monochrome. */
.pw-choix {
  display: grid;
  justify-items: center;
  gap: 8px;
}
.pw-offre-btn {
  display: grid;
  justify-items: center;
  gap: 2px;
  padding: 10px 18px;
}
.pw-offre-prix {
  font-size: 20px;
  font-weight: 600;
  letter-spacing: 0.3px;
}
.pw-offre-nom {
  font-size: 13px;
  font-weight: 600;
}
.pw-offre-tout {
  background: var(--raised);
  color: var(--text);
  border: 1px solid var(--text);
  border-radius: var(--r);
  font-weight: 600;
  font-size: 15px;
}
.pw-offre-tout:active {
  background: var(--raised-2);
}
.pw-offre-note {
  margin: 0;
  text-align: center;
  font-size: 12px;
  color: var(--muted);
  max-width: 210px;
}
.pw-offre-choisie {
  margin: 0;
  font-size: 14px;
  font-weight: 600;
}
.pw-quand {
  margin: 0;
  text-align: center;
  font-size: 12px;
  color: var(--muted);
  max-width: 210px;
}
.pw-qrbloc {
  display: grid;
  justify-items: center;
  gap: 8px;
}
.pw-achat canvas {
  border-radius: var(--r);
  /* Zone de silence supplémentaire : le blanc vient du dessin lui-même. */
  box-shadow: 0 0 0 1px var(--line);
}
.pw-scan {
  margin: 0;
  text-align: center;
  font-size: 12px;
  color: var(--muted);
}
.pw-codeph {
  margin: 0;
  font-size: 12px;
  color: var(--faint);
  letter-spacing: 1px;
  min-height: 16px;
}
/* « Ou payer sur cet écran » (boutique) : jamais le bleu du navigateur. */
.pw-codeph a {
  color: var(--muted);
  text-underline-offset: 2px;
}
.pw-deja {
  display: flex;
  gap: 10px;
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px solid var(--line);
}
/* Le prefixe ENG- vit DANS le cadre, a gauche du champ : le client voit le
   code entier se former, sans avoir a le taper. */
.pw-champ {
  flex: 1;
  display: flex;
  align-items: center;
  background: var(--raised);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 0 12px;
}
.pw-champ:focus-within {
  border-color: var(--text);
}
.pw-prefixe {
  font: 500 14px var(--font);
  letter-spacing: 1px;
  color: var(--muted);
  padding-right: 1px;
  user-select: none;
}
.pw-deja input {
  flex: 1;
  min-width: 0;
  background: none;
  border: 0;
  color: var(--text);
  padding: 10px 0;
  font: 500 14px var(--font);
  letter-spacing: 1px;
  text-transform: uppercase;
}
.pw-deja input:focus {
  outline: none;
}
.pw-deja input::placeholder {
  color: var(--faint);
  letter-spacing: 1px;
}
.pw-deja button {
  background: var(--raised);
  border: 1px solid var(--line);
  border-radius: var(--r);
  color: var(--text);
  padding: 10px 14px;
  font-weight: 600;
  font-size: 13px;
  white-space: nowrap;
}
.pw-deja button:active {
  background: var(--raised-2);
}
/* .hint portait ces trois proprietes ; elle vivait dans le CSS du gestionnaire
   de packs, parti avec l'import. Le min-height compte : sans lui le panneau
   sautait de 20 px a chaque apparition du message. */
.pw-statut {
  margin: 10px 0 0;
  font-size: 13px;
  color: var(--warn);
  min-height: 20px;
}
.pw-statut.ok {
  color: var(--ok);
}
.pw-statut.bad {
  color: var(--red-text);
}

/* La fenêtre Tesla fait 773x601 : les deux colonnes tiennent, mais si un
   jour le panneau s'ouvre sur plus étroit, le QR passe dessous. */
@media (max-width: 640px) {
  .pw-cols {
    grid-template-columns: 1fr;
  }
  .pw-achat {
    justify-items: start;
  }
  .pw-qrbloc {
    justify-items: start;
  }
  .pw-quand {
    text-align: left;
  }
  .pw-choix {
    justify-items: start;
  }
  .pw-offre-note {
    text-align: left;
  }
}

/* Le E du logotype : trois barres horizontales, sans fût, à la manière du
   lettrage du tableau de bord. Dessiné en SVG pour suivre currentColor
   dans les deux thèmes ; la marge droite rejoue le letter-spacing que
   l'élément remplacé ne reçoit pas. */
.logo-e {
  height: 0.68em;
  width: auto;
  fill: currentColor;
  margin-right: 0.42em;
}

/* Le ™ de la marque (déposée à l'INPI le 13/10/2026, n° 5308670), calé sur
   le sommet des capitales comme sur la vitrine : 0,42 em de corps remonté
   de 0,965 em du sien. La marge négative reprend l'interlettrage qui suit
   le R, sans quoi le ™ flotterait à 0,42 em de la lettre. Mesuré à
   773x601 : 7,7 px entre le ™ et la pastille d'état qui suit. */
.logo .tm {
  font-size: 0.42em;
  font-weight: 600;
  letter-spacing: 0;
  vertical-align: 0.965em;
  margin-left: -0.8em;
}

/* LE MOTEUR ÉLECTRIQUE (08/10/2026, bêta) : ni boîte, ni mode, ni clapets, ni
   claquements, ni rendu extérieur. Arthur : « il n'y a pas de clapets ni
   sonorité extérieure ni pop and bang pour ce son moteur, donc faut pas
   afficher les boutons ». main.js pose `moteur-electrique` sur <body> dès la
   sélection ; `!important` passe devant le `hidden` que main.js retire en
   boîte manuelle (bouton Rétrograder, aide des palettes). */
.moteur-electrique .thermique-seul {
  display: none !important;
}
/* Et l'inverse : ce qui n'a de sens que sur une électrique (la rangée Son). */
body:not(.moteur-electrique) .electrique-seul {
  display: none !important;
}
/* Les voix d'un moteur qui en a plusieurs (pack Éponge folle) : sur lui seul. */
body:not(.moteur-voix) .voix-seul {
  display: none !important;
}
/* Un son imposé par le moteur (le mode Roadster) : rien à choisir. */
body.son-fixe #ligne-son-elec {
  display: none !important;
}

/* ---------- LE MODE ROADSTER (17/10/2026, bêta) ----------
   Arthur, photo de l'écran de la voiture à l'appui : « quand on choisit le
   mode Tesla Roadster, que tout l'affichage ressemble à ça ». Rouge sur noir,
   une trame de points, des boutons cerclés de rouge et le choix plein, dans
   les deux thèmes : c'est l'écran de la voiture, pas un thème du système.
   main.js pose `ecran-roadster` sur <html> pour un moteur à `ecran:
   'roadster'` ; le cadran a son propre écran (src/ui/tacho.js). Ici on ne
   fait que redéfinir les jetons et les quelques fonds qui n'en dépendent pas :
   rien de la mise en page ne bouge, et tout le reste de l'app reste juste.
   Placé en DERNIER : à spécificité égale, il doit passer après les deux blocs
   « jour » du haut. Toujours aucun bleu. */
:root.ecran-roadster {
  color-scheme: dark;
  --bg: #000;
  --surface: #070101;
  --raised: rgba(255, 43, 43, 0.07);
  --raised-2: rgba(255, 43, 43, 0.2);
  --line: rgba(255, 43, 43, 0.32);
  --text: #ff3b3b;
  --muted: rgba(255, 70, 70, 0.72);
  --faint: rgba(255, 70, 70, 0.45);
  --primary: #ff2b2b;
  --primary-text: #000;
  --pill: #ff2b2b;
  --pill-text: #000;
  --pill-shadow: 0 0 12px rgba(255, 43, 43, 0.5);
  --red: #ff2b2b;
  --red-text: #ffc9c9;
  --warn: #ff7a45;
  --ok: #ff2b2b;
  --overlay: rgba(0, 0, 0, 0.74);
}
:root.ecran-roadster,
:root.ecran-roadster body {
  background: #000
    radial-gradient(circle, rgba(255, 43, 43, 0.2) 0.9px, transparent 1.4px) 0
    0 / 16px 16px;
}
.ecran-roadster .logo {
  text-shadow: 0 0 10px rgba(255, 43, 43, 0.55);
}
.ecran-roadster .logo-e {
  filter: drop-shadow(0 0 4px rgba(255, 43, 43, 0.55));
}
/* Les commandes : cerclées de rouge, le choix plein et lumineux. */
.ecran-roadster .seg,
.ecran-roadster .cv-bouton,
.ecran-roadster .tesla-bouton,
.ecran-roadster .pedal,
.ecran-roadster select,
.ecran-roadster body.running .primary.big,
.ecran-roadster .panel-head-actions > button:not(.icon) {
  box-shadow: inset 0 0 0 1px var(--line);
}
.ecran-roadster .seg {
  background: rgba(0, 0, 0, 0.6);
}
.ecran-roadster .seg button {
  letter-spacing: 0.03em;
}
.ecran-roadster .primary {
  box-shadow: 0 0 14px rgba(255, 43, 43, 0.45);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.ecran-roadster body.running .primary.big {
  background: rgba(0, 0, 0, 0.6);
}
.ecran-roadster .cv-visuel {
  background: #000;
}
/* La scène du cadran (src/ui/tacho.js, 18/10/2026) prend toute la zone
   gauche : plus de carré, la hauteur sert la vitesse, la voiture et le sol. */
.ecran-roadster #tacho {
  aspect-ratio: auto;
  width: 100%;
}
.ecran-roadster .pedal {
  background: rgba(0, 0, 0, 0.6);
}
.ecran-roadster .pedal.gas.down {
  background: var(--raised-2);
  box-shadow:
    inset 0 0 0 1px var(--text),
    0 0 14px rgba(255, 43, 43, 0.45);
}
.ecran-roadster select {
  background: rgba(0, 0, 0, 0.6)
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='8'><path d='M1 1l5 5 5-5' stroke='%23ff3b3b' stroke-width='1.8' fill='none' stroke-linecap='round' stroke-linejoin='round'/></svg>")
    no-repeat right 12px center;
}
.ecran-roadster input[type="range"]::-webkit-slider-thumb {
  background: #ff2b2b;
  box-shadow: 0 0 10px rgba(255, 43, 43, 0.6);
}
.ecran-roadster input[type="range"]::-moz-range-thumb {
  background: #ff2b2b;
}
.ecran-roadster .shiftlights i.on {
  box-shadow: 0 0 8px rgba(255, 43, 43, 0.6);
}

/* ---------- L'ÉCRAN SOUS-MARIN (19/10/2026, pack Éponge folle, bêta) ----------
   Arthur : « pas de pop, que de la boîte auto, juste du fun maximum », puis,
   entre trois maquettes faites par Gemini à partir de notre vrai écran, la
   « A » : un dessin animé à gros traits noirs, jaune soleil, filets, bouées,
   coffre, scaphandre et planches de surf, dans la mise en page de l'app.
   main.js pose `ecran-ocean` sur <html> et `imposerFun` impose ce que l'écran
   cache ; le cadran est un hublot (tacho.js, `setTheme('ocean')`). RIEN DE LA
   SÉRIE : ni personnage, ni lieu, ni ananas, ni fleurs dans le ciel, ni
   bateau blanc et rouge, ni police du générique. Décor en SVG tracés ici,
   derrière les commandes ; bulles et rayons fixes en mode allégé (Atom) et
   pour qui demande moins de mouvement. Placé en DERNIER, comme le Roadster. */
:root.ecran-ocean {
  color-scheme: light;
  --bg: #2a9fd2;
  --surface: #fff6df;
  --raised: #b6e3f2;
  --raised-2: #ffd400;
  --line: #111;
  --text: #0d1b24;
  --muted: #23404e;
  --faint: #44616e;
  --primary: #ffd400;
  --primary-text: #111;
  --pill: #ffd400;
  --pill-text: #111;
  --pill-shadow: 0 3px 0 #111, 0 0 12px rgba(255, 212, 0, 0.75);
  --red: #ff5a3c;
  --red-text: #ff5a3c;
  --warn: #ffd400;
  --ok: #1f9d55;
  --overlay: rgba(8, 56, 84, 0.55);
}
:root.ecran-ocean,
:root.ecran-ocean body {
  background: linear-gradient(
      180deg,
      #9be3f7 0%,
      #48b9e2 26%,
      #2a96cc 58%,
      #1b78aa 86%,
      #f0d695 97%,
      #f6e2a8 100%
    )
    fixed;
}
:root.ecran-ocean body {
  isolation: isolate;
}
/* Le décor : UNE ILLUSTRATION peinte par Gemini dans le style de la maquette
   A (img/fond-ocean.webp, servie avec l'app) : filets, bouées, coffre,
   planches de surf, scaphandre, coraux, poissons, rayons. Des formes tracées
   ici en CSS et en SVG ont été jugées « affreuses » par Arthur le 19/10 :
   le décor reste une vraie illustration. */
:root.ecran-ocean body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: #2a96cc url("img/fond-ocean.webp") center bottom / cover no-repeat;
}
/* Des bulles qui montent : quatre tailles, quatre colonnes, un seul calque. */
:root.ecran-ocean body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    radial-gradient(
      circle at 35% 35%,
      #fff 0 2px,
      rgba(255, 255, 255, 0.25) 3px 6px,
      rgba(17, 17, 17, 0.35) 6.5px 7px,
      transparent 7.5px
    ),
    radial-gradient(
      circle at 35% 35%,
      #fff 0 1.5px,
      rgba(255, 255, 255, 0.2) 2.5px 4px,
      rgba(17, 17, 17, 0.3) 4.5px 5px,
      transparent 5.5px
    ),
    radial-gradient(
      circle at 35% 35%,
      #fff 0 2.5px,
      rgba(255, 255, 255, 0.22) 3.5px 9px,
      rgba(17, 17, 17, 0.35) 9.5px 10px,
      transparent 10.5px
    ),
    radial-gradient(
      circle at 35% 35%,
      #fff 0 1px,
      rgba(255, 255, 255, 0.2) 2px 3px,
      transparent 4px
    );
  background-size:
    190px 260px,
    130px 210px,
    310px 380px,
    90px 150px;
  background-position:
    20px 0,
    75px 40px,
    160px 120px,
    40px 90px;
  animation: ocean-bulles 14s linear infinite;
}
@keyframes ocean-bulles {
  from {
    background-position:
      20px 0,
      75px 40px,
      160px 120px,
      40px 90px;
  }
  to {
    background-position:
      30px -260px,
      65px -380px,
      170px -260px,
      45px -450px;
  }
}
.allege.ecran-ocean body::before,
.allege.ecran-ocean body::after {
  animation: none;
}
@media (prefers-reduced-motion: reduce) {
  :root.ecran-ocean body::before,
  :root.ecran-ocean body::after {
    animation: none;
  }
}
/* Le logotype : noir et gras, le E en jaune cerclé de noir. */
.ecran-ocean .logo {
  color: #111;
  font-weight: 800;
  font-size: 17px;
  letter-spacing: 0.1em;
  margin-right: -0.1em;
}
.ecran-ocean .logo-e {
  color: #ffd400;
  stroke: #111;
  stroke-width: 1.4px;
  paint-order: stroke;
  margin-right: 0.1em;
}
/* Le décor peint passe derrière tout : la barre du haut et les libellés
   prennent un fond crème à trait noir pour rester lisibles. */
.ecran-ocean .bar {
  background: #fff6df;
  border-bottom: 3px solid #111;
}
.ecran-ocean .field label {
  color: #111;
  font-weight: 800;
  font-size: 12px;
  background: #fff6df;
  border: 2px solid #111;
  border-radius: 8px;
  padding: 2px 6px;
  align-self: center;
}
/* Les commandes : des pièces de dessin animé, bleu clair à gros trait noir,
   une ombre portée pleine, le choix en jaune soleil. */
.ecran-ocean .seg {
  background: transparent;
  box-shadow: none;
  padding: 0 0 3px;
  gap: 6px;
}
.ecran-ocean .seg button,
.ecran-ocean .tesla-bouton {
  background: #b6e3f2;
  color: #0d1b24;
  border: 2.5px solid #111;
  border-radius: 12px;
  box-shadow: 0 3px 0 #111;
  font-weight: 700;
}
.ecran-ocean .seg button.on {
  background: #ffd400;
  color: #111;
  font-weight: 800;
  box-shadow: var(--pill-shadow);
}
.ecran-ocean .seg button:active,
.ecran-ocean .tesla-bouton:active {
  transform: translateY(2px);
  box-shadow: 0 1px 0 #111;
}
/* La carte de la voiture : un carton crème, la photo dans un cadre noir. */
.ecran-ocean .cv-bouton {
  background: #fff6df;
  color: #111;
  border: 3px solid #111;
  border-radius: 16px;
  box-shadow: 0 4px 0 #111;
}
.ecran-ocean .cv-bouton .cv-visuel {
  border-radius: 10px;
  box-shadow: 0 0 0 2.5px #111;
}
.ecran-ocean .cv-action {
  color: #23404e;
}
/* Démarrer jaune, Arrêter corail : gros trait, ombre pleine. */
.ecran-ocean .primary {
  background: #ffd400;
  color: #111;
  border: 3px solid #111;
  border-radius: 16px;
  box-shadow: 0 4px 0 #111;
  font-weight: 800;
}
.ecran-ocean body.running .primary.big {
  background: #ff5a3c;
  color: #fff;
  text-shadow: 0 2px 0 #111;
}
/* Les pédales : des planches de bois cerclées de jaune et de noir. */
.ecran-ocean .pedal {
  background: repeating-linear-gradient(
    90deg,
    #a46f3c 0 26px,
    #7d5128 26px 28px
  );
  color: #fff;
  border: 3px solid #111;
  border-radius: 16px;
  box-shadow:
    inset 0 0 0 5px #ffd400,
    inset 0 0 0 7px #111,
    0 4px 0 #111;
  font-weight: 800;
  text-shadow:
    0 2px 0 #111,
    0 0 3px #111;
}
.ecran-ocean .pedal.gas.down,
.ecran-ocean .pedal.brake.down {
  transform: translateY(3px);
  box-shadow:
    inset 0 0 0 5px #fff36b,
    inset 0 0 0 7px #111,
    0 1px 0 #111;
}
/* Les fenêtres : du carton crème à gros trait. */
.ecran-ocean .panel {
  backdrop-filter: none;
}
.ecran-ocean .panel-inner {
  background: #fff6df;
  border: 3px solid #111;
  box-shadow: 0 6px 0 #111;
}
.ecran-ocean input[type="range"]::-webkit-slider-thumb {
  background: #ffd400;
  border: 2px solid #111;
}
.ecran-ocean input[type="range"]::-moz-range-thumb {
  background: #ffd400;
  border: 2px solid #111;
}
/* Rien de connaisseur : boîte, mode, clapets, pop & bang, rendu sonore. */
.ecran-ocean .thermique-seul,
.ecran-ocean #ligne-popdecel,
.ecran-ocean .shiftlights {
  display: none !important;
}

/* LA CITROUILLE D'HALLOWEEN (19/10/2026) : posée juste après le ™, à la
   hauteur des capitales plus la tige. Sans marge propre : le .logo rend
   déjà 0,42 em de son interlettrage, ce qui la rattache à la marque. Rien
   de plus en couleur : c'est le seul orange de l'écran, et seulement
   quatorze jours par an. */
.citrouille {
  width: 20px;
  height: 20px;
  flex: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transform-origin: 50% 90%;
}
.citrouille.vacille {
  animation: citrouille-vacille 0.7s ease-out;
}
@keyframes citrouille-vacille {
  0%,
  100% {
    transform: rotate(0);
  }
  20% {
    transform: rotate(-14deg);
  }
  45% {
    transform: rotate(10deg);
  }
  70% {
    transform: rotate(-5deg);
  }
}
@media (prefers-reduced-motion: reduce) {
  .citrouille.vacille {
    animation: none;
  }
}
