/* ============================================================================
   COMPOSANTS — copilote boulangerie
   Un bloc = un composant des maquettes. Le nœud Figma d'origine est indiqué
   en commentaire pour que la correspondance reste vérifiable.
   Aucune valeur brute : tout passe par les jetons de tokens.css.
   ========================================================================== */

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

body {
  margin: 0;
  font-family: var(--police-ui);
  color: var(--encre);
  -webkit-font-smoothing: antialiased;
  background: var(--primaire-20);
}

button { font: inherit; color: inherit; border: 0; background: none; cursor: pointer; }
:focus-visible { outline: 2px solid var(--primaire-vive); outline-offset: 3px; border-radius: var(--e-4); }
.icone { display: block; flex: none; }

/* --- Appareil ------------------------------------------------- 154:1615 -- */

.telephone {
  position: relative;
  width: var(--ecran-l);
  height: var(--ecran-h);
  border-radius: var(--e-40);
  overflow: hidden;
  box-shadow: var(--ombre-flotte);
  display: flex;
  flex-direction: column;
  padding: var(--e-16);
  /* Le fond porte le code couleur de phase. Deux dégradés très doux, en haut
     et en bas : assez pour qu'un coup d'œil suffise, assez discret pour ne pas
     abîmer la lisibilité du contenu. */
  background:
    radial-gradient(125% 62% at 50% -8%,  rgb(var(--phase-rgb) / .20) 0%, transparent 62%),
    radial-gradient(125% 55% at 50% 108%, rgb(var(--phase-rgb) / .13) 0%, transparent 58%),
    var(--fond);
  transition: background var(--duree-phase) var(--courbe);
}

/* Une phase = un triplet. Rien d'autre ne change de couleur. */
.telephone[data-phase="repos"]      { --phase-rgb: var(--phase-repos-rgb); }
.telephone[data-phase="geoloc"]     { --phase-rgb: var(--phase-geoloc-rgb); }
.telephone[data-phase="ecoute"]     { --phase-rgb: var(--phase-ecoute-rgb); }
.telephone[data-phase="traitement"] { --phase-rgb: var(--phase-traitement-rgb); }
.telephone[data-phase="recherche"]  { --phase-rgb: var(--phase-recherche-rgb); }
.telephone[data-phase="parole"]     { --phase-rgb: var(--phase-parole-rgb); }

.telephone__halo {
  position: absolute;
  width: 420px; height: 420px;
  background: var(--halo);
  pointer-events: none;
  transition: background var(--duree-phase) var(--courbe),
              transform var(--duree-phase) var(--courbe);
}
.telephone__halo--haut   { top: -260px; left: -220px; }
.telephone__halo--bas    { top: 804px;  left: 268px;  }
/* Le halo respire pendant le travail : la couleur dit QUOI, le mouvement dit
   QUE ça avance. Sur un écran sans texte lisible au volant, c'est le seul
   signal de vie. */
.telephone[data-phase="traitement"] .telephone__halo,
.telephone[data-phase="recherche"]  .telephone__halo {
  animation: halo-respire 2.6s var(--courbe) infinite;
}
@keyframes halo-respire {
  0%, 100% { transform: scale(1);    opacity: .85; }
  50%      { transform: scale(1.14); opacity: 1;   }
}

/* --- Scène : la colonne qui tient tout ------------------------- 154:1618 - */

.scene {
  position: relative;
  /* `flex: 1 0 0` ne règle que la hauteur : dans une colonne flex, l'axe
     principal est vertical. La LARGEUR de la scène, elle, dépendait du
     `align-items: center` de `.ecran` — c'est-à-dire qu'elle n'était pas
     étirée du tout, mais dimensionnée sur son contenu.

     Conséquence mesurée sur l'écran « La commande » : un nom de produit long
     et non sécable (« 4 Pain au Chocolat (2 Barres Pur Beurre de Cacao) »)
     imposait sa largeur à toute la colonne. La scène montait à 512 px dans un
     cadre de 402, et comme elle était centrée, elle débordait de 55 px À
     GAUCHE COMME À DROITE : le titre de la boulangerie était coupé au début,
     les prix coupés à la fin, la carte et le bouton Réserver à cheval sur les
     deux bords. L'en-tête, lui, portait `width: 100%` et restait en place —
     d'où l'impression bizarre d'un haut d'écran correct sur un contenu
     décalé.

     `width: 100%` fixe la largeur au cadre, et `min-width: 0` autorise les
     enfants à se comprimer sous leur taille de contenu — sans lui, la
     troncature par points de suspension ne s'applique jamais. */
  width: 100%;
  min-width: 0;
  flex: 1 0 0;
  min-height: 0;
  display: flex; flex-direction: column; align-items: center;
  justify-content: space-between;
  /* La barre d'état et l'indicateur d'accueil ont été retirés : la scène
     récupère l'espace qui leur était réservé. */
  padding: var(--e-8) 0 var(--e-8);
  gap: var(--e-16);
}
.scene--centree { justify-content: center; gap: var(--e-40); }
.scene__bas {
  width: 100%; min-width: 0;
  display: flex; flex-direction: column; gap: var(--e-16);
  /* `min-height: 0` manquait : sans lui, un enfant flex ne descend jamais
     sous sa taille de contenu, donc la colonne débordait du cadre au lieu de
     se comprimer ou de défiler. C'est l'origine des informations qui
     dépassaient sur l'écran confirmé et, plus discrètement, sur le détail. */
  min-height: 0;
}
.scene__bas--defilable {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  /* Un peu d'air en bas pour que la dernière ligne ne colle pas au bord. */
  padding-bottom: var(--e-4);
}
/* Un pied de scène ne défile jamais avec le contenu : le bouton d'action
   principal doit rester atteignable, quelle que soit la longueur du reste. */
.scene__pied { width: 100%; flex: none; display: flex; flex-direction: column; gap: var(--e-10); }

/* --- Entête : progression + bouton réglages -------------------- 154:1621 - */

.entete { width: 100%; flex: none;
          display: flex; align-items: center; justify-content: space-between; gap: var(--e-12); }

/* Regroupe recommencer + réglages à droite, pour que l'entête garde ses trois
   zones d'origine (clavier | progression | actions) plutôt que d'en éclater
   une quatrième que `space-between` répartirait n'importe où. */
.entete__actions { display: flex; align-items: center; gap: var(--e-8); flex: none; }

/* Fil de progression — répond directement au « je ne sais pas où j'en suis »
   du test. Quatre étapes : écouter, comparer, choisir, retirer. Il donne un
   avant et un après à chaque transition, ce qui manquait totalement. */
.progression { display: flex; align-items: center; gap: var(--e-6); }
.progression i {
  display: block; height: 4px; width: 14px; border-radius: 2px;
  background: var(--ligne);
  transition: width var(--duree-ecran) var(--courbe),
              background var(--duree-ecran) var(--courbe);
}
.progression i[data-etat="fait"]   { background: rgb(var(--phase-ecoute-rgb) / .45); }
.progression i[data-etat="ici"]    { width: 30px; background: var(--primaire-vive); }
.progression__libelle {
  font: var(--body-s-med); color: var(--gris-legende);
  margin-left: var(--e-4); white-space: nowrap;
}
.bouton-icone {
  width: 42px; height: 42px;
  display: flex; align-items: center; justify-content: center;
  background: var(--secondaire-vive);
  border-radius: var(--r-icone);
  color: var(--primaire-80);
  transition: transform var(--duree-courte) var(--courbe);
}
.bouton-icone:active { transform: scale(.94); }

/* Bouton clavier de l'en-tête — la seule porte vers la saisie de secours.
   Ouvert, il passe en primaire : on voit d'où vient le champ qui apparaît en
   bas, et on voit qu'il est encore ouvert. */
.bouton-icone[data-actif="oui"] {
  background: var(--primaire-vive);
  color: var(--couleur);
}
/* Fermée, la saisie est inerte (`disabled`) autant que masquée. Le style suit,
   pour le cas où elle serait rendue visible sans être réactivée. */
.saisie input:disabled,
.saisie button:disabled { opacity: .5; cursor: default; }

/* --- Titres ---------------------------------------------------- 154:1624 - */

.titre-xl  { font: var(--heading-xl); letter-spacing: -.5px; margin: 0; }
.titre-m   { font: var(--heading-m);  letter-spacing: -.2px; margin: 0; }
.titre-s   { font: var(--heading-s);  margin: 0; }

.titre-section {
  font: 700 20px/1.32 var(--police-contenu);
  color: var(--primaire-80); margin: 0;
}
.titre-bloc {
  font: 700 22px/1.32 var(--police-contenu);
  color: var(--primaire-80); margin: 0;
}
.legende {
  font: 400 13px/1.32 var(--police-contenu);
  color: var(--gris-legende); margin: 0;
}
.surtitre {
  font: 700 10px/1.34 var(--police-contenu);
  letter-spacing: .8px; text-transform: uppercase;
  color: var(--gris-legende); margin: 0;
}

/* --- Indicateur d'écoute --------------------------------------- 154:1625 - */

.indicateur { display: flex; align-items: center; gap: var(--e-10); }
.indicateur__point {
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--primaire-vive);
  animation: pulsation 1.6s var(--courbe) infinite;
}
.indicateur__texte { font: var(--heading-s); margin: 0; }

@keyframes pulsation {
  0%, 100% { transform: scale(1);   opacity: 1;  }
  50%      { transform: scale(1.5); opacity: .45; }
}

/* Indicateurs de travail ---------------------------------------- 154:1683 - */
/* Deux états, deux formes, deux couleurs. Avant, un seul indicateur libellé
   « Je cherche… » s'affichait dès qu'un tour partait vers l'API : l'utilisateur
   croyait qu'on cherchait une boulangerie alors qu'on lisait simplement sa
   phrase. « Je cherche » est maintenant réservé à un appel terrain réel. */

.travail {
  width: 100%;
  display: flex; align-items: center; justify-content: center; gap: var(--e-10);
  padding: var(--e-10) var(--e-14);
  border-radius: var(--r-chip);
  animation: entree var(--duree-courte) var(--courbe);
}
.travail__texte { font: var(--title-s); margin: 0; }

/* Traitement — ambre, trois points : on lit, on réfléchit, rien ne part. */
.travail--traitement { background: rgb(var(--phase-traitement-rgb) / .12); }
.travail--traitement .travail__texte { color: var(--warning-80); }
.travail__points { display: flex; align-items: center; gap: var(--e-4); }
.travail__points i {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--warning-60);
  animation: point-pense 1.1s var(--courbe) infinite;
}
.travail__points i:nth-child(2) { animation-delay: .16s; }
.travail__points i:nth-child(3) { animation-delay: .32s; }
@keyframes point-pense {
  0%, 100% { transform: translateY(0);    opacity: .35; }
  40%      { transform: translateY(-4px); opacity: 1;   }
}

/* Recherche — bleu, un radar : un vrai appel Overpass/OSRM est en cours. */
.travail--recherche { background: rgb(var(--phase-recherche-rgb) / .10); }
.travail--recherche .travail__texte { color: var(--info); }
.travail__radar {
  position: relative; flex: none;
  width: 16px; height: 16px; border-radius: 50%;
  border: 2px solid var(--info);
}
.travail__radar::after {
  content: ''; position: absolute; inset: -6px;
  border: 2px solid var(--info); border-radius: 50%;
  animation: onde 1.5s var(--courbe) infinite;
}

@keyframes rotation { to { transform: rotate(360deg); } }

/* --- Mascotte --------------------------------------------------- 154:1628 - */

.mascotte {
  position: relative;
  display: flex; align-items: center; justify-content: center;
  transition: width var(--duree-ecran) var(--courbe),
              height var(--duree-ecran) var(--courbe);
}
.mascotte__image {
  width: 100%; height: 100%; object-fit: contain; display: block;
  transition: transform var(--duree-ecran) var(--courbe);
}
.mascotte--taille-l { width: 203px; height: 231px; }  /* M2 écoute */
.mascotte--taille-m { width: 135px; height: 154px; }  /* M3, M5 */
.mascotte--taille-s { width: 101px; height: 115px; }  /* M4 détail */
.mascotte--taille-xl{ width: 193px; height: 220px; }  /* M6 confirmé */
.mascotte--taille-xs{ width: 200px; height: 227px; }  /* M1 accueil — x1.6 (voir l'ajustement de .scene plus bas pour l'espace repris) */

.mascotte[data-etat="ecoute"] .mascotte__image { animation: respiration 2.4s var(--courbe) infinite; }
.mascotte[data-etat="parole"] .mascotte__image { animation: hoche 1.1s var(--courbe) infinite; }
@keyframes respiration { 0%,100% { transform: scale(1); } 50% { transform: scale(1.035); } }
@keyframes hoche       { 0%,100% { transform: rotate(-1.2deg); } 50% { transform: rotate(1.2deg); } }

/* Pastille micro ------------------------------------------------- 154:1631 - */

.pastille-micro {
  position: absolute; right: -4%; bottom: 6%;
  display: flex; align-items: center; justify-content: center;
  padding: 10px;
  background: var(--primaire-vive); color: var(--couleur);
  border-radius: 50%;
  box-shadow: var(--ombre-mic);
  transition: transform var(--duree-courte) var(--courbe),
              background var(--duree-courte) var(--courbe);
}
.pastille-micro:active { transform: scale(.9); }
.pastille-micro[data-actif="oui"] { background: var(--danger-60); }
.pastille-micro[data-actif="oui"]::after {
  content: ''; position: absolute; inset: -6px;
  border: 2px solid var(--danger-60); border-radius: 50%;
  animation: onde 1.4s var(--courbe) infinite;
}
@keyframes onde {
  0%   { transform: scale(1);   opacity: .7; }
  100% { transform: scale(1.5); opacity: 0;  }
}

/* --- Boutons ---------------------------------------- 154:1641 / 154:1900 - */

.bouton {
  width: 100%;
  display: flex; align-items: center; justify-content: center; gap: var(--e-8);
  padding: var(--e-16) var(--e-16);
  border-radius: var(--r-chip);
  font: 700 16px/1.32 var(--police-contenu);
  transition: transform var(--duree-courte) var(--courbe),
              opacity var(--duree-courte) var(--courbe);
}
.bouton:active { transform: scale(.98); }
.bouton[disabled] { opacity: .45; pointer-events: none; }

.bouton--primaire  { background: var(--primaire-vive); color: var(--couleur); }
.bouton--secondaire{ background: var(--couleur); color: var(--primaire-vive);
                     border: 2px solid var(--primaire-vive); }
.bouton--pilule    { border-radius: var(--r-pilule); padding: 15px var(--e-16);
                     font: var(--title-s); }
.bouton--compact   { padding: 15px var(--e-16); font: 700 15px/1.32 var(--police-contenu); }

/* --- Chips ------------------------------------------ 154:1639 / 154:1693 - */

.chip {
  display: inline-flex; align-items: center;
  padding: var(--e-6) var(--e-10);
  border-radius: var(--r-chip);
  font: 510 13px/1.32 var(--police-contenu);
  white-space: nowrap;
}
.chip--trajet  { background: var(--primaire-20); color: var(--primaire-80); }
.chip--entite  { background: var(--couleur); color: var(--primaire-80);
                 border: 1px solid var(--ligne-chip); padding: var(--e-8) var(--e-12); }
.chip--info    { background: var(--info-fond); color: var(--info); }
.chip--danger  { background: var(--danger-20); color: var(--danger-60); }
.chip--succes  { background: var(--success-20); color: var(--success-60); }
.chip--attente { background: var(--warning-20); color: var(--warning-80); }

.chips { display: flex; flex-wrap: wrap; align-items: center; gap: var(--e-8); }

/* Badge de garantie : traduit `garantie` du prompt système en un signe visible.
   Les quatre valeurs du prompt, aucune de plus. */
.badge-garantie { display: inline-flex; align-items: center; gap: var(--e-4); }
.badge-garantie[data-niveau="reserve"]   { color: var(--success-60); }
.badge-garantie[data-niveau="vu_recent"] { color: var(--warning-80); }
.badge-garantie[data-niveau="inconnu"]   { color: var(--gris-faible); }
.badge-garantie[data-niveau="epuise"]    { color: var(--danger-60); }

/* --- Cartes ----------------------------------------------------- 154:1634 - */

.carte {
  width: 100%;
  background: var(--couleur);
  border-radius: var(--r-carte);
  padding: var(--e-16);
}
.carte--accent   { border: 1px solid var(--primaire-vive); border-radius: var(--r-carte-l);
                   padding: var(--e-18) var(--e-20); }
.carte--nue      { background: transparent; }
.carte--module   { border-radius: var(--r-module); padding: var(--e-14) var(--e-16); }

.carte-suggestion { display: flex; flex-direction: column; gap: var(--e-13); }
.carte-suggestion__titre {
  font: 700 19px/1.32 var(--police-contenu); color: var(--primaire-80); margin: 0;
}
.carte-suggestion__meta { display: flex; align-items: center; gap: var(--e-13); }
.carte-suggestion__detail {
  font: 400 14px/1.32 var(--police-contenu); color: var(--gris-texte); margin: 0;
}

/* Raccourcis bas d'accueil --------------------------------------- 154:1645 - */

.raccourcis { width: 100%; display: flex; flex-wrap: wrap;
              gap: var(--e-8); align-items: center; justify-content: center; }
.raccourci {
  width: 160px;
  display: flex; align-items: center; justify-content: center; gap: var(--e-8);
  padding: var(--e-10) var(--e-16);
  background: var(--secondaire-vive); border-radius: var(--r-pilule);
  font: var(--body-m-med); color: #000;
  transition: transform var(--duree-courte) var(--courbe);
}
.raccourci:active { transform: scale(.96); }

/* Raccourcis produits — carte d'accueil sans suggestion --------------------
   Remplacent le sous-titre générique de la carte. Ce sont de vrais <button>
   (voir ui.js) : focalisables et activables au clavier/lecteur d'écran sans
   rien ajouter ici, et déclenchés par le même repérage `[data-amorce]` que
   les autres raccourcis de l'écran — aucune logique d'envoi dupliquée. */
.raccourcis-produits {
  width: 100%; display: flex; flex-wrap: wrap; gap: var(--e-8);
}
.raccourci-produit {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 44px;
  padding: var(--e-12) var(--e-16);
  background: var(--primaire-20); color: var(--primaire-80);
  border-radius: var(--r-chip);
  font: var(--body-m-med);
  transition: transform var(--duree-courte) var(--courbe);
}
.raccourci-produit:active { transform: scale(.96); }

/* M1 accueil — équilibre après l'agrandissement de la mascotte -------------
   `.scene` répartit l'espace libre en `space-between` entre ses trois blocs
   (bonjour, mascotte, bas d'écran) : sur un écran haut, agrandir la mascotte
   agrandissait aussi le vide de part et d'autre d'elle, notamment entre elle
   et la carte. Ici le haut de l'écran reste groupé, et l'espace libre
   restant est renvoyé sous la carte plutôt qu'autour de la mascotte — la
   rangée « Mes favoris / Historique / Mon compte » garde ainsi sa place
   proche du bord, à 375–402px de large comme au-delà. */
.ecran[data-nom="accueil"] .scene { justify-content: flex-start; }
.ecran[data-nom="accueil"] .scene__bas { flex: 1 1 auto; min-height: 0; }
.ecran[data-nom="accueil"] .raccourcis { margin-top: auto; }

/* --- Option boulangerie ----------------------------------------- 154:1736 - */

.resultats { width: 100%; display: flex; flex-direction: column; gap: var(--e-12); }

.option {
  width: 100%; text-align: left;
  display: flex; align-items: center; gap: var(--e-16);
  padding: var(--e-18);
  background: var(--couleur);
  border: 1.5px solid var(--secondaire-vive);
  border-radius: var(--r-option);
  transition: border-color var(--duree-courte) var(--courbe),
              transform var(--duree-courte) var(--courbe);
}
.option:active { transform: scale(.99); }
.option[aria-selected="true"] { border: 2px solid var(--primaire-vive); }

.option__rang {
  flex: none; width: 40px; height: 40px;
  display: flex; align-items: center; justify-content: center;
  background: var(--secondaire-vive); color: #000;
  border-radius: var(--r-chip);
  font: 700 20px/1.26 var(--police-contenu);
}
.option[aria-selected="true"] .option__rang { background: var(--primaire-vive); color: var(--couleur); }

.option__corps { flex: 1 0 0; min-width: 0; display: flex; flex-direction: column; gap: var(--e-5); }
.option__nom {
  font: 700 20px/1.26 var(--police-contenu); color: var(--primaire-80); margin: 0;
}
.option[aria-selected="true"] .option__nom { color: var(--primaire-vive); }
.option__terrain {
  font: 510 16px/1.26 var(--police-contenu); color: var(--info); margin: 0;
}
.option__meta {
  font: 400 14px/1.26 var(--police-contenu); color: var(--gris-faible); margin: 0;
}

/* --- Module « se garer » ---------------------------------------- 154:1824 - */

.module-garage {
  width: 100%;
  display: flex; align-items: center; gap: var(--e-8);
  padding: var(--e-14) var(--e-16);
  background: var(--info-fond);
  border: 1px solid var(--info-ligne);
  border-radius: var(--r-module);
  color: var(--info);
}
.module-garage__corps { flex: 1 0 0; min-width: 0; display: flex; align-items: center; gap: var(--e-8); }
.module-garage__p {
  flex: none;
  padding: var(--e-3) var(--e-8);
  background: var(--info); color: var(--couleur);
  border-radius: var(--r-petit);
  font: 700 12px/1.32 var(--police-contenu);
}
.module-garage__titre { font: 700 15px/1.32 var(--police-contenu); margin: 0; }
.module-garage__note  { font: 400 13px/1.32 var(--police-contenu); margin: 0; flex: none; }

/* --- Lignes de commande ----------------------------------------- 154:1833 - */

.commande { width: 100%; display: flex; flex-direction: column; gap: var(--e-10); }

.ligne-produit {
  width: 100%;
  display: flex; align-items: center; justify-content: space-between; gap: var(--e-12);
}
/* `min-width: 0` doit descendre jusqu'à l'élément qui porte le texte, sinon
   la troncature ne s'applique jamais : un nom de produit long passait
   par-dessus le prix au lieu de se couper. */
.ligne-produit__gauche { display: flex; align-items: center; gap: var(--e-16);
                         min-width: 0; flex: 1 1 auto; }
.ligne-produit__gauche > .pile { min-width: 0; }
.ligne-produit__icone { flex: none; width: 32px; height: 32px; color: var(--primaire-60); }
.ligne-produit__nom {
  font: var(--title-m); color: #000; margin: 0; min-width: 0; max-width: 100%;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ligne-produit__prix {
  flex: none;
  /* Medium Italic 18/24 dans la maquette — 154:1883 */
  font: italic 500 18px/24px var(--police-ui);
  color: #000;
}
.ligne-produit[data-garantie="epuise"] .ligne-produit__nom { text-decoration: line-through; opacity: .6; }

/* --- Récapitulatif ---------------------------------------------- 154:1876 - */
/* Sans fond en Figma : le bloc respire sur le fond de l'écran. */

.recapitulatif {
  width: 100%;
  display: flex; flex-direction: column; gap: var(--e-12);
  padding: var(--e-16);
  border-radius: var(--r-carte);
}

.filet { width: 100%; height: 1px; background: var(--ligne); border: 0; margin: 0; }

.total {
  width: 100%; display: flex; align-items: center; justify-content: space-between;
  color: var(--primaire-80); font-family: var(--police-contenu); font-weight: 700;
}
.total__libelle { font-size: 16px; line-height: 1.32; }
.total__valeur  { font-size: 18px; line-height: 1.32; }

/* Rondelle d'attente : la réservation part vraiment, on ne saute pas à
   l'écran confirmé avant d'avoir la réponse. */
.rondelle {
  width: 16px; height: 16px; flex: none;
  border: 2px solid currentColor; border-top-color: transparent;
  border-radius: 50%;
  animation: rotation .8s linear infinite;
}
.bouton[data-attente="oui"] { opacity: 1; }

/* --- Écran confirmé --------------------------------------------- 154:1935 - */
/* Trois causes de débordement, corrigées ensemble :
   1. la colonne n'était pas défilable et n'avait pas `min-height: 0` — dès que
      le nom de la boulangerie tenait sur deux lignes, le bouton « M'y emmener »
      sortait du cadre ;
   2. `confirme__resume` recevait « nom · adresse » d'un bloc, sans césure : une
      adresse longue poussait la carte au-delà de la largeur ;
   3. le code de retrait était en 34 px fixes avec 2 px d'interlettrage, ce qui
      débordait sur les petits écrans. */

.confirme__entete { align-items: center; text-align: center; min-width: 0; }
.confirme__titre {
  font: 700 26px/1.32 var(--police-contenu); color: var(--primaire-80);
}
.confirme__resume {
  font: 400 14px/1.4 var(--police-contenu); color: var(--gris-legende);
  max-width: 100%;
  overflow-wrap: anywhere;
  /* Trois lignes suffisent à identifier le lieu ; au-delà c'est du bruit qui
     pousse le reste de l'écran vers le bas. */
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3;
  overflow: hidden;
}
/* La mascotte ne se laisse plus écraser par le contenu, et ne le pousse plus
   dehors non plus : taille fixe, le reste défile. */
.ecran[data-nom="confirme"] .mascotte { flex: none; }

/* --- Paiement --------------------------------------------------- 154:1894 - */

.paiement {
  width: 100%;
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--e-13) var(--e-16);
  background: var(--couleur);
  border: 1px solid var(--ligne);
  border-radius: var(--r-module);
}
.paiement__libelle {
  font: 700 11px/1.32 var(--police-contenu); letter-spacing: .6px;
  color: var(--gris-legende); margin: 0;
}
.paiement__valeur {
  font: 510 15px/1.32 var(--police-contenu); color: var(--primaire-80); margin: 0;
}
.paiement__action {
  font: 510 13px/1.32 var(--police-contenu); color: var(--primaire-60);
}

/* --- Code de retrait -------------------------------------------- 154:1938 - */

.code-retrait {
  width: 100%;
  display: flex; flex-direction: column; align-items: center; gap: var(--e-6);
  padding: var(--e-18) var(--e-16);
  background: var(--couleur);
  border: 2px solid var(--primaire-vive);
  border-radius: var(--r-carte);
  color: var(--primaire-vive);
  font-family: var(--police-contenu);
}
.code-retrait__libelle { font-size: 10px; font-weight: 700; letter-spacing: 1px;
                         text-align: center; }
.code-retrait__valeur  {
  font-size: clamp(26px, 9vw, 34px); font-weight: 700; letter-spacing: 2px;
  max-width: 100%; overflow-wrap: anywhere; text-align: center; line-height: 1.1;
}
.code-retrait__note    { font-size: 12px; font-weight: 400; color: var(--gris-legende);
                         text-align: center; max-width: 100%; }

/* --- Dialogue --------------------------------------------------- 154:1686 - */

.dialogue { width: 100%; display: flex; flex-direction: column; gap: var(--e-18); }

.replique { width: 100%; display: flex; }
.replique--utilisateur { justify-content: flex-end; padding-left: 48px; }
.replique--copilote    { justify-content: flex-start; padding-right: 48px; }

.replique--utilisateur p {
  margin: 0; text-align: right;
  font: var(--body-l-med); color: var(--encre-douce);
}
.replique--copilote p {
  margin: 0;
  font: var(--heading-m); letter-spacing: -.2px; color: #000;
}
.replique--copilote .fantome { color: var(--gris-fantome); }

/* --- Carte OpenStreetMap ---------------------------------------- 154:1792 - */

.carte-geo {
  width: 100%; height: 186px;
  border-radius: var(--r-carte);
  overflow: hidden;
  background: #d9d9d9;
  position: relative;
}
.carte-geo .leaflet-control-attribution { font-size: 9px; }
.carte-geo__pastille {
  position: absolute; z-index: 500;
  left: 50%; top: 58%; transform: translate(-50%, -50%);
  padding: var(--e-2) var(--e-8);
  background: var(--trajet); color: var(--couleur);
  border-radius: var(--r-petit);
  font: var(--body-s-med);
  pointer-events: none;
}
.carte-geo__vide {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  font: var(--body-s); color: var(--gris-texte); text-align: center; padding: var(--e-16);
}
.marqueur-boulangerie {
  width: 26px; height: 26px; border-radius: 50%;
  background: var(--primaire-vive); color: var(--couleur);
  display: flex; align-items: center; justify-content: center;
  font: 700 13px/1 var(--police-contenu);
  box-shadow: var(--ombre-mic);
  border: 2px solid var(--couleur);
}

/* --- Bandeau d'écart / rupture ----------------------------------------- */
/* Rend visible ce que le prompt système oblige à dire : écart, risque,
   rupture. Le bandeau ne remplace jamais la parole, il la double. */

.bandeau {
  width: 100%;
  display: flex; align-items: flex-start; gap: var(--e-8);
  padding: var(--e-12) var(--e-14);
  border-radius: var(--r-module);
  font: 500 13px/1.4 var(--police-contenu);
}
.bandeau--rupture { background: var(--danger-20);  color: var(--danger-80);  }
.bandeau--risque  { background: var(--warning-20); color: var(--warning-80); }
.bandeau--ok      { background: var(--success-20); color: var(--success-80); }
.bandeau--info    { background: var(--info-fond);  color: var(--info);       }

/* --- Géolocalisation : explication et refus ------------------------------- */
/* Au test, la fenêtre de permission du navigateur tombait sans un mot :
   personne ne savait ce qui était demandé ni pourquoi. Cette carte s'affiche
   AVANT la fenêtre système et reste pendant, puis laisse place au message de
   refus le cas échéant. */

.geoloc {
  width: 100%;
  display: flex; flex-direction: column; gap: var(--e-8);
  padding: var(--e-14) var(--e-16);
  border-radius: var(--r-carte);
  border: 1px solid var(--ligne);
  background: var(--couleur);
  animation: monte var(--duree-ecran) var(--courbe);
}
.geoloc__entete { display: flex; align-items: center; gap: var(--e-8); }
.geoloc__titre  { font: var(--title-m); margin: 0; }
.geoloc__texte  { font: 400 13px/1.4 var(--police-contenu); color: var(--gris-texte); margin: 0; }

.geoloc--demande { border-color: rgb(var(--phase-geoloc-rgb) / .55);
                   background: rgb(var(--phase-geoloc-rgb) / .07); }
.geoloc--demande .geoloc__titre { color: var(--primaire-vive); }
.geoloc--demande .geoloc__entete .icone { color: var(--primaire-vive); }

.geoloc--ok      { display: none; }

.geoloc--refus   { border-color: var(--warning-60);
                   background: var(--warning-20); }
.geoloc--refus .geoloc__titre { color: var(--warning-80); }
.geoloc--refus .geoloc__texte { color: var(--warning-80); }

/* Petit point qui bat pendant que le navigateur attend la réponse. */
.geoloc__attente {
  width: 8px; height: 8px; border-radius: 50%; flex: none;
  background: var(--primaire-vive);
  animation: pulsation 1.2s var(--courbe) infinite;
}

/* --- Waveform ---------------------------------------------------- 154:1699 - */

.waveform {
  width: 100%;
  display: flex; align-items: center; justify-content: center; gap: 3px;
  height: 17px;
}
.waveform i {
  display: block; width: 3px; border-radius: 2px;
  background: var(--primaire-80); opacity: .35;
  height: 5px;
  transition: height .1s linear, opacity .1s linear;
}
.waveform[data-actif="oui"] i { opacity: 1; animation: onduler .9s ease-in-out infinite; }
.waveform i:nth-child(2) { animation-delay: .1s; }
.waveform i:nth-child(3) { animation-delay: .2s; }
.waveform i:nth-child(4) { animation-delay: .3s; }
.waveform i:nth-child(5) { animation-delay: .15s; }
.waveform i:nth-child(6) { animation-delay: .25s; }
.waveform i:nth-child(7) { animation-delay: .05s; }
@keyframes onduler { 0%,100% { height: 5px; } 50% { height: 17px; } }

/* --- Écrans : transition ------------------------------------------------- */
/* Le parcours va de gauche à droite : accueil → écoute → résultats → détail →
   confirmé. Avancer fait entrer l'écran par la DROITE, revenir en arrière le
   fait entrer par la GAUCHE. Le sens de l'animation dit donc où l'on va.
   Avant, une seule animation « monte de 10 px » rejouait à chaque repeinture,
   plusieurs fois par tour, même sans changement d'écran : ça clignotait sans
   rien vouloir dire. `data-sens="aucun"` supprime purement l'animation quand
   seul le contenu change. */

/* `#ecrans` porte l'écran entrant ET, pendant sa sortie, l'écran précédent
   (voir ui.js/rendre) : celui-ci passe en position absolue le temps de son
   animation, plutôt que d'être coupé d'un coup, pour que le glissement des
   deux écrans se voie comme UN mouvement continu — l'un pousse l'autre,
   comme on avance d'une étape sur un parcours. */
#ecrans { position: relative; }

.ecran { display: none; width: 100%; flex: 1 0 0; min-height: 0;
         flex-direction: column; align-items: center; }
.ecran[data-visible="oui"] { display: flex; }

.ecran[data-sens="avant"]   { animation: entree-avant   var(--duree-ecran) var(--courbe); }
.ecran[data-sens="arriere"] { animation: entree-arriere var(--duree-ecran) var(--courbe); }
.ecran[data-sens="depart"]  { animation: entree         var(--duree-ecran) var(--courbe); }
.ecran[data-sens="aucun"]   { animation: none; }

@keyframes entree {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}
@keyframes entree-avant {
  from { opacity: 0; transform: translateX(36px); }
  to   { opacity: 1; transform: none; }
}
@keyframes entree-arriere {
  from { opacity: 0; transform: translateX(-36px); }
  to   { opacity: 1; transform: none; }
}

/* L'écran qui part : superposé en absolu (donc retiré du flux, il ne pousse
   plus la mise en page), il glisse dans le SENS INVERSE de celui qui entre —
   avancer le fait sortir par la gauche, revenir le fait sortir par la
   droite — pendant exactement la même durée. `pointer-events: none` évite de
   pouvoir encore cliquer dessus pendant qu'il s'efface, et `z-index` le garde
   au-dessus du nouvel écran le temps du fondu, pour que le mouvement se lise
   comme un panneau qui glisse et révèle le suivant. */
.ecran[data-sortant] {
  position: absolute; inset: 0; width: 100%;
  pointer-events: none; z-index: 2;
}
.ecran[data-sortant="avant"]   { animation: sortie-avant   var(--duree-ecran) var(--courbe) forwards; }
.ecran[data-sortant="arriere"] { animation: sortie-arriere var(--duree-ecran) var(--courbe) forwards; }

@keyframes sortie-avant {
  from { opacity: 1; transform: none; }
  to   { opacity: 0; transform: translateX(-36px); }
}
@keyframes sortie-arriere {
  from { opacity: 1; transform: none; }
  to   { opacity: 0; transform: translateX(36px); }
}

/* Les blocs de contenu qui apparaissent DANS un écran déjà en place glissent
   depuis le bas, jamais depuis le côté : le côté est réservé au changement
   d'étape. Deux vocabulaires d'animation, deux significations. */
.apparait { animation: monte var(--duree-ecran) var(--courbe); }
@keyframes monte {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: none; }
}

/* --- Compte à rebours de choix ------------------------------------------- */
/* L'écran de résultats basculait tout seul au bout de quatre secondes, sans
   prévenir : l'utilisateur n'avait pas fini d'écouter que c'était déjà passé.
   Le délai est plus long, et surtout il est VISIBLE et annulable. */

.rebours {
  width: 100%;
  display: flex; align-items: center; gap: var(--e-10);
  padding: var(--e-10) var(--e-14);
  background: var(--couleur);
  border: 1px solid var(--ligne);
  border-radius: var(--r-module);
}
.rebours__jauge {
  flex: 1 0 0; height: 4px; border-radius: 2px;
  background: var(--ligne); overflow: hidden;
}
.rebours__jauge span {
  display: block; height: 100%; width: 100%;
  background: var(--primaire-vive);
  transform-origin: left center;
  transition: transform .24s linear;
}
.rebours__texte {
  flex: none; font: var(--body-s-med); color: var(--gris-texte);
}
.rebours__annuler {
  flex: none; padding: var(--e-4) var(--e-10);
  border-radius: var(--r-chip);
  background: var(--secondaire-vive); color: var(--primaire-80);
  font: var(--body-s-med);
}

/* --- Saisie de secours --------------------------------------------------- */
/* Le micro peut manquer : navigateur non compatible, permission refusée,
   page ouverte hors localhost. On ne laisse jamais l'écran sans issue. */

.saisie {
  width: 100%; display: none; align-items: center; gap: var(--e-8);
  padding: var(--e-8); background: var(--couleur);
  border: 1px solid var(--ligne); border-radius: var(--r-chip);
}
.saisie[data-ouvert="oui"] { display: flex; }
.saisie input {
  flex: 1 0 0; min-width: 0; border: 0; background: none; outline: none;
  font: var(--body-l-med); padding: var(--e-8) var(--e-12);
}
.saisie button {
  flex: none; padding: var(--e-8) var(--e-16);
  background: var(--primaire-vive); color: var(--couleur);
  border-radius: var(--r-chip); font: var(--title-s);
}

/* --- Panneau réglages / banc d'essai ------------------------------------- */

.panneau {
  position: absolute; inset: 0; z-index: 10;
  background: var(--couleur);
  padding: var(--e-24) var(--e-16) var(--e-24);
  display: none; flex-direction: column; gap: var(--e-16);
  overflow-y: auto;
}
.panneau[data-ouvert="oui"] { display: flex; animation: entree var(--duree-ecran) var(--courbe); }
.panneau__entete { display: flex; align-items: center; justify-content: space-between; }
.panneau__groupe { display: flex; flex-direction: column; gap: var(--e-8); }
.panneau label { font: var(--body-s-med); color: var(--gris-legende); }
.panneau select, .panneau input[type="text"] {
  width: 100%; padding: var(--e-10) var(--e-12);
  border: 1px solid var(--ligne); border-radius: var(--r-module);
  font: var(--body-m-med); background: var(--fond);
}
.panneau__ligne { display: flex; align-items: center; justify-content: space-between; gap: var(--e-12); }

/* Journal : la règle appliquée à chaque tour, affichée hors écran principal.
   Sert à montrer au jury que le comportement vient du prompt, pas du hasard. */
.journal {
  display: flex; flex-direction: column; gap: var(--e-8);
  font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 11px;
  color: var(--gris-texte);
}
.journal__entree {
  padding: var(--e-8) var(--e-10);
  background: var(--fond); border-left: 2px solid var(--primaire-vive);
  border-radius: 0 var(--r-petit) var(--r-petit) 0;
  white-space: pre-wrap; word-break: break-word;
}
.journal__entree--erreur { border-left-color: var(--danger-60); color: var(--danger-80); }

/* Fenêtre de débogage : le JSON brut du modèle, sans reformulation. C'est ce
   qui permet de distinguer « le modèle a mal répondu » de « l'application a
   mal interprété une bonne réponse ». */
.debogage {
  margin: 0;
  max-height: 260px;
  overflow: auto;
  padding: var(--e-10);
  background: var(--primaire-80); color: #e9e2d6;
  border-radius: var(--r-petit);
  font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: 10px; line-height: 1.5;
  white-space: pre-wrap; word-break: break-word;
  -webkit-user-select: text; user-select: text;
}

/* --- Utilitaires --------------------------------------------------------- */

.pile      { display: flex; flex-direction: column; }
.pile--2   { gap: var(--e-2);  }
.pile--3   { gap: var(--e-3);  }
.pile--4   { gap: var(--e-4);  }
.pile--6   { gap: var(--e-6);  }
.pile--10  { gap: var(--e-10); }
.pile--8   { gap: var(--e-8);  }
.pile--12  { gap: var(--e-12); }
.pile--16  { gap: var(--e-16); }
.rangee    { display: flex; align-items: center; }
.rangee--entre { justify-content: space-between; }
.pleine    { width: 100%; }
.invisible { display: none !important; }
.lecteur-seul {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap;
}
