/* ============================================================
   ÉNERGIE·MOBILE — terminal de charge. Dark, accent lime, numériques mono.
   Mobile-first, low-data : zéro font externe, zéro image (SVG/CSS only).
   ============================================================ */
:root {
  --bg:#0a0b0d; --bg2:#0e1116; --surface:#14181d; --surface2:#1a1f26;
  --line:rgba(255,255,255,.08); --line-strong:rgba(255,255,255,.14);
  --accent:#c8ff2e; --accent-soft:rgba(200,255,46,.16); --accent-dim:#7e9c14;
  --amber:#ffb23e; --danger:#ff5d5d;
  --text:#e9eef1; --muted:#8b949c;
  /* Lot 8 (item c) : #5c656d mesurait 3.32:1 sur --bg, 3.00:1 sur --surface, 2.79:1 sur --surface2 —
     sous le seuil AA (4.5:1) pour du texte normal (forfeitNote, sous-libellés de chip, footer). Valeur
     recalculée pour rester ≥4.5:1 sur les TROIS fonds réels où elle est utilisée (marge la plus
     serrée : 4.51:1 sur --surface2) — cf calcul WCAG dans le plan Lot 8, jamais une estimation à l'œil. */
  --muted2:#808a92;
  --mono:"SFMono-Regular","SF Mono","Cascadia Code","JetBrains Mono","Roboto Mono",ui-monospace,monospace;
  --sans:system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
  --r:16px;
}
*{box-sizing:border-box;margin:0;padding:0}
html,body{height:100%}
body{
  font-family:var(--sans); color:var(--text); background:var(--bg);
  -webkit-font-smoothing:antialiased; text-rendering:optimizeLegibility;
  background-image:
    radial-gradient(120% 60% at 50% -10%, rgba(200,255,46,.10), transparent 60%),
    linear-gradient(transparent 96%, rgba(255,255,255,.025) 96%),
    linear-gradient(90deg, transparent 96%, rgba(255,255,255,.025) 96%);
  background-size:100% 100%, 22px 22px, 22px 22px;
}
.mono{font-family:var(--mono);font-feature-settings:"tnum" 1}
.dim{color:var(--muted)} .small{font-size:.78rem} .center{text-align:center}
b{font-weight:700}

#app{
  max-width:460px; min-height:100%; margin:0 auto; padding:0 20px env(safe-area-inset-bottom);
  display:flex; flex-direction:column;
}

/* ---- Topbar ---- */
.topbar{display:flex;align-items:center;justify-content:space-between;
  padding:18px 2px 22px;position:sticky;top:0;background:linear-gradient(var(--bg),rgba(10,11,13,.6));z-index:5}
.brand{display:inline-flex;align-items:center;gap:9px;font-weight:800;letter-spacing:.14em;font-size:.82rem}
.brand__mark{width:18px;height:18px;fill:var(--accent);filter:drop-shadow(0 0 6px rgba(200,255,46,.6))}
.brand__name i{color:var(--accent-dim);font-style:normal;margin:0 1px}
.net{display:inline-flex;align-items:center;gap:7px;font-size:.7rem;letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}
.net i{width:7px;height:7px;border-radius:50%;background:var(--muted2)}
.net[data-net="online"] i{background:var(--accent);box-shadow:0 0 0 0 var(--accent-soft);animation:ping 2.4s ease-out infinite}
.net[data-net="offline"]{color:var(--danger)} .net[data-net="offline"] i{background:var(--danger);animation:none}
@keyframes ping{0%{box-shadow:0 0 0 0 rgba(200,255,46,.5)}100%{box-shadow:0 0 0 9px transparent}}

/* ---- Stage / screens ---- */
.stage{flex:1;display:flex;flex-direction:column;justify-content:center;padding:8px 0 28px}
.screen{display:none;flex-direction:column;gap:18px}
#app[data-state="boot"]    [data-screen="boot"],
#app[data-state="idle"]    [data-screen="idle"],
#app[data-state="pending"] [data-screen="pending"],
#app[data-state="done"]    [data-screen="done"],
#app[data-state="return"]  [data-screen="return"],
#app[data-state="fail"]    [data-screen="fail"]{display:flex}

/* Liste « où rendre » */
.returnlist{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:10px}
.returnlist__item{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:14px 16px;border:1px solid rgba(255,255,255,.08);border-radius:14px;background:rgba(255,255,255,.03)}
.returnlist__meta{display:flex;flex-direction:column;gap:2px;min-width:0}
.returnlist__meta b{font-weight:700}
.returnlist__meta span{font-size:.85rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.returnlist__free{flex:none;font-weight:700;color:#39d98a}

.kicker{font-family:var(--mono);font-size:.66rem;letter-spacing:.34em;color:var(--accent-dim);text-transform:uppercase}
h1.station__name{font-size:2rem;line-height:1.05;font-weight:800;letter-spacing:-.01em;margin-top:6px}
.station__loc{color:var(--muted);font-size:.86rem;margin-top:6px}

/* ---- Battery motif ---- */
.battery{display:flex;align-items:center;justify-content:center;gap:6px;position:relative;padding:8px 0}
.battery__body{position:relative;width:208px;height:86px;border:2px solid var(--line-strong);border-radius:14px;
  background:var(--bg2);overflow:hidden;box-shadow:inset 0 0 24px rgba(0,0,0,.6)}
.battery__cap{width:9px;height:38px;border-radius:0 5px 5px 0;background:var(--line-strong)}
.battery__fill{position:absolute;inset:4px auto 4px 4px;width:0;border-radius:9px;
  background:linear-gradient(180deg,var(--accent),var(--accent-dim));
  box-shadow:0 0 18px rgba(200,255,46,.45);transition:width .9s cubic-bezier(.2,.8,.2,1)}
.battery__scan{position:absolute;top:0;bottom:0;width:40%;
  background:linear-gradient(90deg,transparent,rgba(255,255,255,.07),transparent);transform:translateX(-120%)}
.battery__pct{position:absolute;right:16px;top:50%;transform:translateY(-50%);font-weight:700;font-size:1.1rem;color:var(--bg);mix-blend-mode:difference}
.battery__bolt{position:absolute;width:34px;height:34px;left:50%;top:50%;transform:translate(-50%,-50%);
  fill:var(--bg);filter:drop-shadow(0 0 4px rgba(0,0,0,.5));animation:bolt 1.3s ease-in-out infinite}
.battery.charging .battery__fill{
  width:62%;
  background:repeating-linear-gradient(115deg,var(--accent) 0 14px,var(--accent-dim) 14px 28px);
  background-size:200% 100%;animation:flow 1s linear infinite, breathe 2.6s ease-in-out infinite}
.battery.charging .battery__scan{animation:scan 1.8s ease-in-out infinite}
@keyframes flow{to{background-position:200% 0}}
@keyframes breathe{0%,100%{filter:brightness(1)}50%{filter:brightness(1.25)}}
@keyframes scan{0%{transform:translateX(-120%)}60%,100%{transform:translateX(360%)}}
@keyframes bolt{0%,100%{opacity:.5;transform:translate(-50%,-50%) scale(.94)}50%{opacity:1;transform:translate(-50%,-50%) scale(1.04)}}
.stock b{color:var(--text);font-family:var(--mono)}

/* ---- Ticket (prix) ---- */
.ticket{background:var(--surface);border:1px solid var(--line);border-radius:var(--r);padding:6px 16px;
  position:relative;overflow:hidden}
.ticket::before{content:"";position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--accent)}
.ticket__row{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:13px 0;
  border-bottom:1px dashed var(--line)}
.ticket__row:last-child{border-bottom:0}
.ticket__row span i{color:var(--muted2);font-style:normal;font-size:.78rem}
.ticket__row b{font-size:1.05rem}
.ticket__row.amber b{color:var(--amber)}
.ticket__row.total span{font-weight:800;letter-spacing:.08em;font-size:.82rem}
.ticket__row.total b{font-size:1.5rem;color:var(--accent)}

/* ---- Form ---- */
.form{display:flex;flex-direction:column;gap:18px;margin-top:2px}
.field{display:flex;flex-direction:column;gap:9px}
.field__label{font-family:var(--mono);font-size:.66rem;letter-spacing:.22em;color:var(--muted)}
.field__phone{display:flex;align-items:center;gap:10px;background:var(--surface);border:1px solid var(--line-strong);
  border-radius:12px;padding:0 14px;transition:border-color .2s,box-shadow .2s}
.field__phone:focus-within{border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}
.field__phone em{color:var(--muted);font-style:normal;font-size:1.05rem}
/* CORRECTIF (revue adversariale post-Lot 9, Playwright — débordement horizontal RÉEL à 320px sur
   l'écran client idle) : cause RACINE identifiée par introspection DOM (scrollWidth/getBoundingClient-
   Rect de chaque nœud à 320px) — le champ <input name="phone">, seul, débordait de 20px (right≈340px)
   alors que sa TAILLE VISIBLE (scrollWidth 255px) tenait dans le conteneur. `flex:1` sans
   `min-width:0` ne suffit PAS à faire céder un <input> : les navigateurs lui donnent une largeur
   minimale de compression INTRINSÈQUE (héritée de l'attribut historique `size`, ~170-200px selon la
   police), IGNORÉE par flex-basis/flex-grow mais PAS par le calcul de largeur minimale du flex-item —
   `min-width:0` est le correctif standard (jamais un simple oubli visuel : invisible à l'œil sur un
   écran normal, seul un viewport ≤340px environ le révèle). */
.field__phone input{flex:1;min-width:0;background:none;border:0;outline:0;color:var(--text);font-size:1.25rem;
  font-family:var(--mono);letter-spacing:.04em;padding:16px 0}
.field__phone input::placeholder{color:var(--muted2)}
.chips{display:flex;gap:10px}
.methodchips .chip{min-height:64px}
/* CORRECTIF (revue adversariale post-Lot 9, Playwright — débordement horizontal RÉEL à 320px sur
   l'écran client idle) : un enfant flex a par défaut `min-width:auto`, PAS 0 — sa largeur minimale
   de compression est celle de son contenu NON-cassable (le plus long "mot" insécable), jamais moins.
   Avec FLEXPAY_CARD_ENABLED, `.chips.methodchips` affiche 2 chips flex:1 côte à côte ; le sous-titre
   mono `letter-spacing:.18em` de l'un ("M-PESA · ORANGE · AIRTEL · AFRIMONEY") est plus large qu'un
   demi-conteneur à 320px et empêchait le chip de se COMPRESSER sous cette largeur — d'où la barre de
   défilement horizontale mesurée par Playwright (20px de débordement), invisible en relecture de
   code (le rendu à une largeur d'écran normale ne le montre jamais). `min-width:0` autorise le chip
   à se comprimer sous son contenu ; `overflow-wrap:break-word` sur le sous-titre garantit qu'un mot
   trop long CASSE plutôt que de forcer, lui, un nouveau débordement. */
.chip{flex:1;min-width:0;cursor:pointer;border:1px solid var(--line-strong);background:var(--surface);border-radius:12px;
  padding:14px 10px;text-align:center;font-weight:700;letter-spacing:.02em;color:var(--muted);
  transition:all .18s;-webkit-tap-highlight-color:transparent}
.chip small{display:block;overflow-wrap:break-word;font-family:var(--mono);font-size:.6rem;letter-spacing:.18em;margin-top:3px;color:var(--muted2)}
.chip[aria-pressed="true"]{color:var(--bg);background:var(--accent);border-color:var(--accent);
  box-shadow:0 0 22px rgba(200,255,46,.3)}
.chip[aria-pressed="true"] small{color:rgba(10,11,13,.65)}

.btn{position:relative;display:flex;align-items:center;justify-content:center;gap:10px;width:100%;
  border:0;border-radius:13px;padding:19px;font-family:var(--sans);font-size:1.05rem;font-weight:800;
  letter-spacing:.06em;color:var(--bg);background:var(--accent);cursor:pointer;
  box-shadow:0 8px 24px -8px rgba(200,255,46,.5);transition:transform .12s,filter .2s,opacity .2s}
.btn:active{transform:translateY(2px) scale(.995)}
/* CORRECTIF (calcul WCAG manuel, PAS un signalement Axe — Axe/axe-core exclut par construction les
   contrôles `disabled` de la règle color-contrast, vérifié empiriquement : forcer ce bouton
   `disabled` et relancer le scan Axe local retourne toujours ZÉRO violation, alors que le calcul de
   composition ci-dessous montre bien un défaut réel — un outil automatisé ne le verra donc jamais,
   ce qui ne veut pas dire qu'un ŒIL humain ne le voit pas) : `opacity:.45` sur .btn composite le
   texte ET le fond vers le fond de PAGE (--bg) dans les mêmes proportions — .btn__label (var(--bg)
   sur var(--accent), 16.69:1 au repos) retombe à 3.97:1 sous le seuil AA (4.5:1) dès que le bouton
   est `disabled` (borne hors-ligne à l'ouverture de l'écran client, cf `btn.disabled = !online`
   dans app.js — un état RÉEL et PERMANENT tant que la borne reste injoignable, pas un instant de
   transition). Même mécanisme, même correctif que `.langbtn` plus bas dans ce fichier : couleur
   EXPLICITE plutôt qu'opacité, immunisée à la dilution de contraste par construction. `--accent-dim`
   (déjà dans la palette — kicker/marque) donne un fond lime éteint, cohérent avec l'identité
   visuelle et sans couleur ad hoc ; `--bg` dessus reste à 6.24:1. */
.btn[disabled]{background:var(--accent-dim);box-shadow:none;cursor:not-allowed}
.btn.ghost{background:transparent;color:var(--accent);border:1px solid var(--accent);box-shadow:none}
/* CORRECTIF (revue adversariale, régression introduite par le correctif ci-dessus) : `.btn[disabled]`
   et `.btn.ghost` ont la MÊME spécificité (0,2,0) — `.btn.ghost` étant déclaré APRÈS, son
   `background:transparent` écrase le `background:var(--accent-dim)` du bouton désactivé, et comme
   `.btn.ghost` ne redéfinit ni `opacity` ni `filter` (supprimés par le correctif ci-dessus), l'état
   ghost désactivé devenait visuellement IDENTIQUE à l'état actif (vérifié via getComputedStyle).
   Impact réel : app.js crée le bouton « renvoyer la demande » en `btn ghost`, désactivé pendant le
   POST /rentals/initiate — sans cette règle, l'utilisateur tactile (pas de :hover ni de curseur pour
   voir `cursor:not-allowed`) n'a plus AUCUN signal d'inactivité et peut re-soumettre. Couleur
   explicite (pas d'opacité, même raison qu'au-dessus) : `--accent-dim` sur `--bg` = 6.24:1, AA ok. */
.btn.ghost[disabled]{background:transparent;color:var(--accent-dim);border-color:var(--accent-dim)}
.btn__spin{display:none;width:18px;height:18px;border:2px solid rgba(10,11,13,.4);border-top-color:var(--bg);
  border-radius:50%;animation:spin .7s linear infinite}
.btn.busy .btn__spin{display:block} .btn.busy .btn__label{opacity:.7}
@keyframes spin{to{transform:rotate(360deg)}}
.form__err{color:var(--danger);font-size:.84rem;min-height:1em;text-align:center}

/* ---- Pending ---- */
[data-screen="pending"] h2{font-size:1.5rem;font-weight:800;margin-top:6px}
.pulsebar{height:4px;border-radius:4px;background:var(--surface2);overflow:hidden}
.pulsebar span{display:block;height:100%;width:35%;border-radius:4px;background:var(--accent);
  box-shadow:0 0 12px var(--accent);animation:slide 1.4s ease-in-out infinite}
@keyframes slide{0%{transform:translateX(-110%)}100%{transform:translateX(330%)}}

/* ---- Done ---- */
.slotpop{display:flex;flex-direction:column;align-items:center;gap:4px;animation:pop .5s cubic-bezier(.2,1.4,.4,1) both}
.slot{font-size:5.5rem;font-weight:800;line-height:1;color:var(--accent);text-shadow:0 0 40px rgba(200,255,46,.5)}
.slot__sub{font-family:var(--mono);letter-spacing:.4em;font-size:.7rem;color:var(--muted)}
@keyframes pop{from{opacity:0;transform:scale(.6)}to{opacity:1;transform:scale(1)}}
.ticket.done{margin-top:6px}

/* ---- Fail ---- */
.xmark{width:74px;height:74px;margin:0 auto;border-radius:50%;border:2px solid var(--danger);
  display:grid;place-items:center;animation:pop .4s both}
.xmark svg{width:36px;height:36px;stroke:var(--danger);stroke-width:2.5;fill:none;stroke-linecap:round}
[data-screen="fail"] h2{font-size:1.4rem;font-weight:800}

/* ---- Loader / footer ---- */
.loader{display:flex;gap:8px;justify-content:center;padding:20px}
.loader span{width:11px;height:11px;border-radius:50%;background:var(--accent-dim);animation:blink 1s ease-in-out infinite}
.loader span:nth-child(2){animation-delay:.15s}.loader span:nth-child(3){animation-delay:.3s}
@keyframes blink{0%,100%{opacity:.25;transform:scale(.8)}50%{opacity:1;transform:scale(1);background:var(--accent)}}
.foot{padding:18px 0;text-align:center;font-size:.64rem;letter-spacing:.24em;color:var(--muted2);text-transform:uppercase}

/* ---- Staggered reveal ---- */
.reveal{opacity:0;transform:translateY(14px);animation:rise .55s cubic-bezier(.2,.8,.2,1) forwards}
.r1{animation-delay:.02s}.r2{animation-delay:.12s}.r3{animation-delay:.22s}.r4{animation-delay:.32s}
@keyframes rise{to{opacity:1;transform:none}}
@media (prefers-reduced-motion:reduce){*{animation-duration:.01ms!important;animation-iteration-count:1!important;transition:none!important}.reveal{opacity:1;transform:none}}

/* i18n — sélecteur de langue (footer). Construit par i18n.js dans [data-i18n-switch]. */
.foot { display: flex; flex-direction: column; gap: 8px; align-items: center; }
.foot__top { display: flex; justify-content: space-between; align-items: center; gap: 12px; width: 100%; }
/* Lot 8 (item c) : contact support + liens légaux — texte normal (pas la majuscule/letter-spacing
   du reste du footer, illisible sur un email/téléphone) et couleur héritée pour rester lisible sur
   les deux thèmes sans dupliquer les tokens de contraste. */
.foot__support, .foot__legal { text-transform: none; letter-spacing: normal; font-size: 0.72rem; }
.foot__legal { display: flex; gap: 12px; flex-wrap: wrap; justify-content: center; }
.foot__legal a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
.langswitch { display: inline-flex; gap: 6px; }
.langbtn {
  background: none; border: 1px solid currentColor; border-radius: 4px;
  /* Lot 8 (item c) : `color:inherit` + `opacity:.6` composaient avec --muted2 vers ~2.7:1 sur --bg
     (l'opacité éclaircit visuellement MAIS dilue le contraste réel vers le fond, l'inverse de l'effet
     recherché) — couleur explicite + suppression de l'opacité pour rester ≥4.5:1 dans les deux états. */
  color: var(--muted); font: inherit; font-size: 0.85em; padding: 2px 8px; cursor: pointer;
}
.langbtn[aria-pressed="true"] { font-weight: 700; color: var(--text); }

/* ---- Documents légaux (Lot 8 item c, public/legal/*.html) — gabarits À VALIDER JURIDIQUEMENT ---- */
.legal { max-width: 640px; margin: 0 auto; padding: 8px 4px 40px; text-align: left; line-height: 1.55; }
.legal h1 { font-size: 1.3rem; margin: 0 0 4px; }
.legal h2 { font-size: 1rem; margin: 1.6em 0 .4em; color: var(--accent); }
.legal p, .legal li { color: var(--text); font-size: .92rem; }
.legal ul { padding-left: 1.2em; }
.legal a { color: var(--accent); }
.legal .btn.ghost { margin-top: 24px; display: inline-block; text-decoration: none; text-align: center; }
/* Bandeau d'avertissement « gabarit non validé » — --amber déjà vérifié ≥AA sur --bg (a11y-static.test.js). */
.legal__notice {
  border: 1px solid var(--amber); color: var(--amber); background: rgba(255, 178, 62, .08);
  border-radius: 8px; padding: 12px 14px; font-size: .82rem; font-weight: 600; margin: 12px 0 20px;
}

/* ---- Bandeau mise à jour PWA (masqué/affiché via show()=CSSOM, jamais style= inline) ---- */
.updatebar{position:fixed;left:50%;bottom:14px;transform:translateX(-50%);z-index:40;
  display:flex;align-items:center;gap:14px;max-width:92vw;
  background:var(--surface2);border:1px solid var(--line-strong);border-left:3px solid var(--accent);
  border-radius:12px;padding:10px 14px;box-shadow:0 12px 30px -10px rgba(0,0,0,.6)}
.updatebar span{font-size:.86rem}
.updatebar .btn{width:auto;padding:8px 14px;font-size:.78rem;white-space:nowrap}
