* { box-sizing: border-box; }
/* Le `hidden` HTML doit l'emporter sur nos `display:flex/block` (sinon les
   panneaux masqués et la modale note restent visibles). */
[hidden] { display: none !important; }
html, body { height: 100%; margin: 0; }
body {
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  color: #1f2937;
}
#map { position: absolute; inset: 0; z-index: 0; }

/* --- Rail de filtres (haut-gauche) : boutons collés, style barre de zoom ---
   Le rail lui-même ne porte plus ni fond ni ombre : ce sont ses `.tool-card`
   qui les portent, séparées par un `gap`. Deux cards, deux familles de filtres
   qui ne se combinent pas pareil (équipements d'une aire, en ET ; autres lieux,
   en OU) : l'écart est ce qui dit qu'elles ne jouent pas le même rôle. */
#toolbar {
  position: absolute;
  top: 12px;
  left: 12px;
  z-index: 1000;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.tool-card {
  position: relative;   /* ancre du popover de note, aligné sur SON bouton ⭐ */
  display: flex;
  flex-direction: column;
  background: #fff;
  border-radius: 8px;
  box-shadow: 0 1px 5px rgba(0, 0, 0, 0.4);
}
.tool-group { display: flex; flex-direction: column; }
.tool-btn {
  position: relative;
  width: 34px;
  height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  line-height: 1;
  border: none;
  border-bottom: 1px solid #dcdcdc;
  border-radius: 0;
  background: #fff;
  cursor: pointer;
}
.tool-btn:hover { background: #f4f4f4; }
/* Picto image (à la place d'un emoji), même gabarit optique que les emojis */
.tool-ico-img { width: 19px; height: 19px; object-fit: contain; display: block; }
/* Duo d'emojis superposés (« café » = une tasse ET un croissant) : le second
   passe DERRIÈRE, décalé en haut à droite, pour que le premier reste le
   pictogramme lu. Même encombrement qu'un emoji seul : le rail garde son pas. */
.tool-duo { position: relative; display: block; width: 19px; height: 19px; }
.tool-duo span { position: absolute; font-size: 13px; line-height: 1; }
/* Croissant en haut à GAUCHE : le coin haut-droit est déjà pris par la coche
   de sélection du filtre, qui le recouvrirait dès qu'on l'active. */
.tool-duo .duo-b { top: -2px;
  left: -4px;
  transform: rotate(187deg); }
.tool-duo .duo-a { bottom: 0; right: 0; }
/* Coins arrondis seulement en haut du 1er et en bas du dernier bouton de chaque
   card (le rail en compte deux, chacune se referme sur elle-même) */
.tool-card .tool-group:first-child .tool-btn:first-child {
  border-top-left-radius: 8px;
  border-top-right-radius: 8px;
}
.tool-card > :last-child .tool-btn:last-child,
#btnNote {
  border-bottom: none;
  border-bottom-left-radius: 8px;
  border-bottom-right-radius: 8px;
}
/* Sélection : liseré vert + petite coche dans le coin (à l'intérieur du bouton) */
.tool-btn.active { box-shadow: inset 0 0 0 2px #16a34a; }
.tool-group .tool-btn.active::after {
  content: '✓';
  position: absolute;
  top: 2px;
  right: 2px;
  width: 13px;
  height: 13px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #16a34a;
  color: #fff;
  font-size: 9px;
  font-weight: 700;
  line-height: 1;
  border-radius: 50%;
}
/* Second groupe : un « + » plutôt qu'une coche. Ces filtres n'affinent pas la
   sélection, ils ajoutent d'autres lieux à ce que la carte montre déjà — c'est
   toute la différence entre les deux barres, et le badge est l'endroit où elle
   se lit sans avoir à survoler le bouton. */
.tool-group.ajout .tool-btn.active::after { content: '+'; font-size: 11px; }

/* Témoin de chargement : flottant en bas à droite, sans cadre. Posé au-dessus de
   la ligne d'attribution Leaflet, et transparent aux gestes, il passe sur la
   carte, il ne doit pas la bloquer. Le halo blanc lui donne son contraste sur
   les fonds satellite, à défaut de fond opaque. */
#loadIndicator {
  /* Posé sous le rail de filtres, dans son axe : `top:100%` le colle au bas de
     la card quelle que soit sa hauteur (le nombre de filtres vient du contrat
     d'équipements, il n'est pas connu ici), et `width` reprend la colonne des
     boutons pour que le pictogramme tombe pile dans leur axe. Hors flux, donc
     sans effet sur la hauteur du rail ; hors de la card, donc sans son fond
     blanc ni son ombre, c'est un témoin, pas un bouton de plus. */
  position: absolute;
  top: 100%;
  left: 0;
  width: 34px;
  margin-top: 7px;
  z-index: 1000;
  display: flex;
  justify-content: center;
  color: #16a34a;
  pointer-events: none;
  filter: drop-shadow(0 0 2px rgba(255, 255, 255, .95))
          drop-shadow(0 1px 3px rgba(0, 0, 0, .35));
}
#loadIndicator svg { display: block; animation: tourne 0.9s linear infinite; }
@keyframes tourne { to { transform: rotate(360deg); } }
/* Le mouvement est l'information : sans lui, un arc vert fixe ne dit rien. */
@media (prefers-reduced-motion: reduce) {
  #loadIndicator svg { animation-duration: 2.4s; }
}
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* Barre de contrôles maison (zoom, ma position, fond de carte) : le balisage est
   celui de MapLibre (`maplibregl-ctrl-group`, qui pose le fond et l'ombre), les
   boutons sont les nôtres. */
.carte-ctrl .ctrl-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 29px;
  height: 29px;
  padding: 0;
  border: none;
  background: transparent;
  color: #333;
  font-size: 17px;
  line-height: 1;
  cursor: pointer;
}
.carte-ctrl .ctrl-btn + .ctrl-btn { border-top: 1px solid #ddd; }
.carte-ctrl .ctrl-btn:hover { background: #f2f2f2; color: #16a34a; }
.carte-ctrl .ctrl-btn svg { display: block; }

/* Menu de choix de fond de carte, ancré au-dessus de la barre de contrôles */
.layer-menu {
  position: absolute;
  left: 52px;
  bottom: 18px;
  z-index: 1000;
  background: #fff;
  border-radius: 10px;
  box-shadow: 0 1px 6px rgba(0, 0, 0, 0.35);
  padding: 6px;
  display: grid;
  grid-template-columns: repeat(2, 1fr); /* 2 colonnes × 3 lignes */
  gap: 6px;
  width: 210px;
}
.layer-item {
  padding: 0;
  border: 1px solid #e5e7eb;
  border-radius: 8px;
  background: #fff;
  overflow: hidden;
  cursor: pointer;
  display: flex;
  flex-direction: column;
}
.layer-item:hover { border-color: #16a34a; }
.layer-item.active { border-color: #16a34a; box-shadow: 0 0 0 2px rgba(22, 163, 74, .3); }
.layer-thumb { width: 100%; height: 46px; object-fit: cover; display: block; background: #f3f4f6; }
.layer-name { font-size: 11px; color: #374151; padding: 4px 2px; text-align: center; }
.layer-item.active .layer-name { color: #15803d; font-weight: 700; }

/* Badge de plage de note sur ⭐ (dans le coin, à l'intérieur) */
.badge {
  position: absolute;
  bottom: 2px;
  right: 2px;
  background: #16a34a;
  color: #fff;
  font-size: 8px;
  font-weight: 700;
  line-height: 1;
  padding: 1px 3px;
  border-radius: 6px;
}

/* Popover (note) ancré à droite du rail, aligné sur le bouton ⭐ (en bas) */
.popover {
  position: absolute;
  left: calc(100% + 8px);
  bottom: 0;
  z-index: 1100;
  width: 190px;
  background: #fff;
  border-radius: 10px;
  box-shadow: 0 1px 6px rgba(0, 0, 0, .35);
  padding: 12px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.popover::before { /* petite flèche vers le bouton ⭐ (bas du rail) */
  content: '';
  position: absolute;
  left: -5px;
  bottom: 12px;
  width: 11px; height: 11px;
  background: #fff;
  transform: rotate(45deg);
  box-shadow: -2px 2px 4px rgba(0,0,0,.06);
}
/* Menu des variantes d'un filtre (« tous les cafés » / « grandes enseignes »).
   Même habillage que le popover de note, mais placé en coordonnées ÉCRAN par le
   JS (`position:fixed`) : le rail compte plusieurs boutons et passe en bas à
   droite sur petit écran, où un ancrage sur la card l'aurait envoyé hors champ.
   La flèche désigne le bouton cliqué, à gauche ou à droite selon le côté. */
.eq-pop {
  position: fixed;
  left: 0;
  bottom: auto;
  width: 214px;   /* « Grandes enseignes seulement » tient sur une ligne */
  padding: 8px;
  gap: 2px;
}
.eq-pop::before { bottom: auto; top: 11px; }
.eq-pop.vers-gauche::before {
  left: auto;
  right: -5px;
  box-shadow: 2px -2px 4px rgba(0, 0, 0, .06);
}
.eq-opt {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 8px;
  border: none;
  border-radius: 7px;
  background: none;
  font: inherit;
  font-size: 13px;
  text-align: left;
  cursor: pointer;
}
.eq-opt:hover { background: #f3f4f6; }
.eq-opt.on { background: #eaf7ef; color: #15803d; font-weight: 600; }
.eq-opt-ico { width: 17px; font-size: 14px; line-height: 1; text-align: center; }
.eq-opt-nom { flex: 1; }
/* L'extinction n'est pas une troisième façon d'afficher : un filet la sépare
   des variantes, et elle reste grise tant qu'elle n'est pas retenue. */
.eq-opt-off { margin-top: 4px; border-top: 1px solid #eee; border-radius: 0 0 7px 7px; color: #6b7280; }
.eq-opt-off.on { color: #b91c1c; background: #fef2f2; }
/* La variante retenue se lit sur le bouton du rail, en bas à gauche — le coin
   haut-droit porte déjà le « + » du groupe. Sans elle, le menu refermé, rien ne
   distinguerait « tous les cafés » de « grandes enseignes ». */
.tool-btn.variante::before {
  content: attr(data-badge);
  position: absolute;
  bottom: 1px;
  left: 1px;
  font-size: 9px;
  line-height: 1;
  filter: drop-shadow(0 0 1px #fff) drop-shadow(0 0 1px #fff);
}

.pop-head { font-size: 13px; font-weight: 700; }
.pop-row { display: flex; gap: 8px; }
.pop-row label { flex: 1; display: flex; flex-direction: column; gap: 3px; font-size: 11px; color: #6b7280; }
.pop-row input { width: 100%; padding: 6px 8px; border: 1px solid #d1d5db; border-radius: 8px; font-size: 14px; }
.pop-actions { display: flex; justify-content: space-between; gap: 8px; }
.primary-btn.small { padding: 7px 12px; font-size: 13px; }

/* --- Panneau de recherche unifié (droite) --- */
/* Pas d'overflow:hidden : sinon le menu d'autocomplétion (position absolute) est
   coupé quand il déborde sous le panneau (cas du champ Lieu, seul dans un panneau
   court). Les coins hauts du segmented control sont arrondis explicitement. */
/* Colonne droite : card de marque + card de recherche empilées */
#rightStack {
  position: absolute;
  top: 12px;
  right: 12px;
  z-index: 1000;
  width: 320px;
  max-width: calc(100vw - 24px);
  display: flex;
  flex-direction: column;
  gap: 10px;
  /* La colonne ne descend jamais sous le bas de la fenêtre : un itinéraire à
     dix étapes poussait la card de recherche hors de l'écran, emportant avec
     elle sa barre d'actions. `dvh` (avec repli `vh`) parce que la barre d'URL
     mobile fait varier la hauteur réellement visible. Ce qui déborde est absorbé
     par le corps de l'itinéraire, qui devient scrollable : pas par la card. */
  max-height: calc(100vh - 24px);
  max-height: calc(100dvh - 24px);
}
/* La card de marque garde sa taille ; c'est la card de recherche qui encaisse. */
/* --- « Charger les lieux dans cette zone » -------------------------------
   Un déplacement de la carte ne lance plus de requête, il la propose. Le bouton
   est posé au CENTRE-BAS, la seule bande vraiment libre : le haut porte la card
   de recherche (pleine largeur sur mobile), le coin bas-gauche les contrôles de
   zoom, le coin bas-droit le rail de filtres sur petit écran.
   Son `z-index` passe AU-DESSUS de tout ce qui flotte sur la carte (colonne de
   cards 1000, popovers 1100) : à l'étroit il croise la card de recherche, et un
   bouton d'action à moitié recouvert ne sert à rien. Il reste sous les modales
   (2000), qui, elles, attendent une réponse avant tout le reste.
   La règle d'ID l'emportant sur le `display:none` du navigateur, [hidden] est
   repris explicitement (même précédent que #itinActions). */
#btnLoadZone {
  position: absolute;
  z-index: 1500;
  left: 50%;
  bottom: 30px;                      /* au-dessus de l'attribution */
  transform: translateX(-50%);
  display: inline-flex;
  align-items: center;
  gap: 8px;
  max-width: calc(100vw - 24px);
  padding: 10px 16px;
  border: 1px solid #16a34a;
  border-radius: 999px;
  background: #fff;
  color: #15803d;
  font: inherit;
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1.1;
  cursor: pointer;
  box-shadow: 0 3px 12px rgba(0, 0, 0, .3);
}
#btnLoadZone[hidden] { display: none; }
#btnLoadZone:hover { background: #f0fdf4; }
#btnLoadZone:active { transform: translateX(-50%) scale(.97); }
#btnLoadZone span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

#brandCard { flex: 0 0 auto; }
#brandCard {
  position: relative;      /* ancre du popover de compte */
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 12px;
  background: #fff;
  border-radius: 10px;
  box-shadow: 0 1px 6px rgba(0, 0, 0, 0.35);
  padding: 10px 14px;
}
.brand-logo-img { flex: 0 0 auto; height: 34px; width: auto; display: block; }
/* Le logo est cliquable (remise à zéro) mais ne doit pas ressembler à un
   bouton : la card l'a toujours montré nu, seul le curseur et un léger
   assombrissement au survol annoncent l'action. */
.brand-logo-btn {
  flex: 0 0 auto;
  padding: 0;
  border: none;
  background: none;
  cursor: pointer;
  line-height: 0;
  border-radius: 6px;
}
.brand-logo-btn:hover .brand-logo-img { filter: brightness(.88); }
.brand-logo-btn:focus-visible { outline: 2px solid #16a34a; outline-offset: 2px; }

/* --- Langue : bouton drapeau dans la card de marque + son menu -----------
   Même gabarit que le bouton de compte, à ceci près qu'il est RECTANGULAIRE :
   un drapeau tronqué en rond ne se reconnaît plus, et c'est tout ce qu'on lui
   demande. */
.lang-btn {
  flex: 0 0 auto;
  width: 30px; height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 1px solid #e5e7eb;
  border-radius: 8px;
  background: #fff;
  cursor: pointer;
}
.lang-btn:hover { border-color: #16a34a; }
/* Le filet gris qui cerne le drapeau lui rend sa silhouette sur fond blanc :
   sans lui, la bande blanche du drapeau français se confond avec la card. */
.lang-drapeau {
  display: block;
  border-radius: 2px;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, .18);
}
/* Le menu pend sous SON bouton, pas sous la card : d'où la flèche décalée vers
   la gauche, le bouton de compte occupant le coin droit. */
.lang-pop {
  left: auto; bottom: auto;
  top: calc(100% + 8px);
  right: 0;
  width: 178px;
  padding: 8px;
  gap: 2px;
}
.lang-pop::before { left: auto; right: 62px; top: -5px; bottom: auto; box-shadow: -2px -2px 4px rgba(0, 0, 0, .06); }
.lang-opt {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 7px 8px;
  border: none;
  border-radius: 7px;
  background: none;
  font: inherit;
  font-size: 13px;
  text-align: left;
  cursor: pointer;
}
.lang-opt:hover { background: #f3f4f6; }
.lang-opt.on { background: #eaf7ef; color: #15803d; font-weight: 600; }
.lang-nom { flex: 1; }

/* --- Compte : bouton dans la card de marque + son menu ------------------- */
.account-btn {
  flex: 0 0 auto;
  width: 30px; height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 1px solid #e5e7eb;
  border-radius: 50%;
  background: #fff;
  color: #374151;
  cursor: pointer;
  overflow: hidden;        /* l'avatar Google est rond comme le bouton */
}
.account-btn:hover { border-color: #16a34a; color: #16a34a; }
/* Connecté : le bouton porte l'avatar ou l'initiale, en vert plein, l'état de
   connexion se lit sans ouvrir le menu. */
.account-btn.connecte { background: #16a34a; border-color: #16a34a; color: #fff; font-weight: 700; font-size: 13px; }
.account-btn img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Le popover générique s'ouvre à DROITE du rail de filtres ; celui-ci pend sous
   son bouton, aligné à droite de la card. */
.account-pop {
  left: auto; bottom: auto;
  top: calc(100% + 8px);
  right: 0;
  width: 200px;
  gap: 6px;
}
.account-pop::before { left: auto; right: 12px; top: -5px; bottom: auto; box-shadow: -2px -2px 4px rgba(0, 0, 0, .06); }
.account-pop .mini-btn { text-align: left; }
/* « Administration » est un LIEN (elle change de page) là où ses voisines sont
   des boutons : sans cette règle, le menu afficherait une ligne bleue soulignée
   au milieu de ses boutons. Rien d'autre ne la distingue, et c'est voulu. */
.account-pop a.mini-btn { color: inherit; text-decoration: none; }
.account-who { font-size: 11px; color: #6b7280; font-weight: 500; overflow: hidden; text-overflow: ellipsis; }

/* --- Modale générique --------------------------------------------------- */
.modal-back {
  position: fixed;
  inset: 0;
  z-index: 2000;
  background: rgba(17, 24, 39, .45);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
}
.modal {
  width: 100%;
  max-width: 380px;
  max-height: calc(100dvh - 32px);
  display: flex;
  flex-direction: column;
  background: #fff;
  border-radius: 12px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, .35);
}
.modal-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 14px;
  border-bottom: 1px solid #f0f0f0;
}
.modal-titre { flex: 1; font-size: 15px; font-weight: 700; }
.modal-close {
  flex: 0 0 auto;
  border: none;
  background: transparent;
  color: #9ca3af;
  font-size: 22px;
  line-height: 1;
  padding: 0 2px;
  cursor: pointer;
}
.modal-close:hover { color: #dc2626; }
/* Le corps seul défile : l'en-tête et sa croix restent atteignables même sur une
   longue liste d'itinéraires. */
.modal-body { padding: 14px; overflow-y: auto; display: flex; flex-direction: column; gap: 10px; }
.modal-body label { display: flex; flex-direction: column; gap: 3px; font-size: 12px; color: #6b7280; }
.modal-body input[type="email"], .modal-body input[type="password"] {
  width: 100%;
  padding: 9px 10px;
  border: 1px solid #d1d5db;
  border-radius: 9px;
  font-size: 14px;
}
.modal-err { font-size: 12px; font-weight: 600; color: #b91c1c; }
.modal-ok { font-size: 12px; font-weight: 600; color: #15803d; }
.modal-hint { font-size: 12px; color: #6b7280; }
.modal-lien { background: none; border: none; padding: 0; font: inherit; font-size: 12px; color: #16a34a; font-weight: 600; cursor: pointer; text-align: left; }
.modal-sep { display: flex; align-items: center; gap: 8px; font-size: 11px; color: #9ca3af; }
.modal-sep::before, .modal-sep::after { content: ''; flex: 1; height: 1px; background: #e5e7eb; }
.compte-ligne { display: flex; justify-content: space-between; gap: 10px; font-size: 13px; }
.compte-ligne span:first-child { color: #6b7280; }

/* Réglages : un bloc par option, pour que la suivante s'ajoute sans rien
   redessiner. */
.reglage-bloc { display: flex; flex-direction: column; gap: 7px; }
.reglage-titre { font-size: 13px; font-weight: 700; color: #111827; }
/* Choix de l'appli de navigation : deux cartes plutôt que deux boutons radio.
   Le logo est ce qu'on reconnaît, pas l'intitulé, et la ligne du bas dit la
   différence qui compte (les étapes passent, ou non). */
.nav-choix { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.nav-carte {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  padding: 10px 6px;
  border: 1px solid #d1d5db;
  border-radius: 10px;
  background: #fff;
  cursor: pointer;
  font: inherit;
  text-align: center;
}
.nav-carte:hover { border-color: #16a34a; }
.nav-carte.actif { border-color: #16a34a; background: #f0fdf4; box-shadow: inset 0 0 0 1px #16a34a; }
.nav-carte img { display: block; border-radius: 5px; }
.nav-carte-nom { font-size: 13px; font-weight: 600; color: #111827; }
.nav-carte-note { font-size: 10.5px; color: #6b7280; }
/* Un itinéraire de la liste : cliquable en entier, il rouvre le trajet AVEC le
   droit d'édition (le lien porte le jeton, cf. listItinerairesDe). */
.itin-item {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 9px 11px;
  border: 1px solid #e5e7eb;
  border-radius: 9px;
  background: #fff;
  text-align: left;
  cursor: pointer;
  font: inherit;
}
.itin-item:hover { border-color: #16a34a; background: #f0fdf4; }
.itin-titre { font-size: 13px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.itin-meta { font-size: 11px; color: #6b7280; }

/* --- Rangement en voyages et dossiers (modale « Mes itinéraires ») -------- */
/* La modale s'élargit pour ce seul usage : une arborescence à deux niveaux avec
   des poignées de déplacement ne tient pas dans 380 px. */
.modal.modal-large { max-width: 620px; }
.voyage { display: flex; flex-direction: column; gap: 6px; }
.voyage + .voyage { margin-top: 6px; }
.voyage.glisse { opacity: .9; }
.voyage-tete {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 4px 0 3px;
  border-bottom: 1px solid #e5e7eb;
}
.voyage-ico, .dossier-ico { flex: 0 0 auto; color: #16a34a; font-size: 12px; }
.voyage-nom { flex: 1; font-size: 13.5px; font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.voyage-act, .dossier-act {
  flex: 0 0 auto;
  width: 24px; height: 22px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid #e5e7eb;
  background: #fff;
  border-radius: 7px;
  font-size: 11px;
  color: #6b7280;
  cursor: pointer;
}
.voyage-act:hover, .dossier-act:hover { border-color: #16a34a; color: #15803d; }
.voyage-act.danger:hover, .dossier-act.danger:hover { border-color: #dc2626; color: #dc2626; }
/* Poignées : `touch-action:none` est indispensable, sinon le doigt fait défiler
   la modale au lieu de déplacer l'élément. */
.voyage-grip, .itin-grip {
  flex: 0 0 auto;
  color: #cbd5e1;
  font-size: 12px;
  cursor: grab;
  touch-action: none;
  padding: 0 2px;
}
.voyage-grip:active, .itin-grip:active { cursor: grabbing; }
/* Le dossier est en retrait : ce décalage dit qu'il est DANS le voyage sans
   avoir à l'écrire. */
.dossier {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-left: 12px;
  padding-left: 10px;
  border-left: 2px solid #e5e7eb;
}
.dossier-tete { display: flex; align-items: center; gap: 7px; }
.dossier-nom { flex: 1; font-size: 12.5px; font-weight: 650; color: #374151; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.voyage-defaut .voyage-ico { color: #6b7280; }

/* Zone de dépôt : le contenu d'un voyage ou d'un dossier. Sa hauteur minimale
   n'est pas cosmétique : c'est elle qui garde une zone vidée atteignable au
   doigt, sans quoi on ne pourrait plus jamais rien y remettre. */
.zone { display: flex; flex-direction: column; gap: 5px; min-height: 30px; border-radius: 9px; padding: 2px; }
.zone.survol { background: #f0fdf4; box-shadow: inset 0 0 0 2px #bbf7d0; }
.zone-vide { font-size: 11.5px; color: #9ca3af; font-style: italic; padding: 5px 4px; }

.itin-ligne { display: flex; align-items: stretch; gap: 6px; }
.itin-ligne .itin-item { flex: 1; min-width: 0; }
.itin-ligne.glisse { position: relative; z-index: 5; opacity: .95; box-shadow: 0 6px 16px rgba(0, 0, 0, .2); border-radius: 9px; }
/* « … » : l'historique des versions de CETTE ligne. Discret au repos — c'est un
   filet de sécurité, pas une action de tous les jours. */
.itin-plus {
  flex: none;
  width: 30px;
  border: none;
  border-radius: 8px;
  background: none;
  color: #9ca3af;
  font-size: 14px;
  cursor: pointer;
}
.itin-plus:hover { background: #f3f4f6; color: #374151; }

/* --- Historique des versions --- */
.ver-liste { list-style: none; margin: 10px 0 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.ver-ligne {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border: 1px solid #e5e7eb;
  border-radius: 9px;
  background: #fff;
}
/* La version courante est celle d'où l'on part : elle se repère d'un coup d'œil,
   sinon on cherche « celle d'aujourd'hui » dans une liste d'horodatages. */
.ver-ligne.ver-courante { border-color: #16a34a; background: #f0fdf4; }
.ver-info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.ver-titre { font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ver-meta { font-size: 11px; color: #6b7280; }
.ver-actes { flex: none; display: flex; gap: 6px; }
.ver-actes .mini-btn { padding: 6px 9px; text-decoration: none; }

/* Bandeau de consultation d'une ancienne version. Posé en haut au centre, au
   même étage que le bouton « charger cette zone » : il passe au-dessus des cards
   parce qu'il dit à quoi ressemble tout ce qui est en dessous. */
#versionBanner {
  position: absolute;
  top: 12px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 1200;
  max-width: min(560px, calc(100vw - 24px));
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  border-radius: 999px;
  background: #78350f;
  color: #fff;
  font-size: 13px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, .35);
}
#versionBanner a { color: #fde68a; }
@media (max-width: 640px) {
  /* En haut au centre, le bandeau croise la card de recherche pleine largeur :
     il passe sous elle, où il reste lisible sans rien recouvrir. */
  #versionBanner { top: auto; bottom: 12px; }
}
.itin-grip { display: flex; align-items: center; }

@media (max-width: 640px) {
  /* À l'étroit, la modale de rangement prend toute la largeur : l'arborescence
     à deux niveaux n'a rien à donner de plus. */
  .modal.modal-large { max-width: none; }
  .dossier { margin-left: 6px; padding-left: 8px; }
}
.brand-texte { flex: 1; min-width: 0; padding-left: 12px; border-left: 1px solid #f0f0f0; }
.brand-nom {
  display: none;
  font-size: 14px;
  font-weight: 750;
  letter-spacing: -.2px;
  color: #15803d;
  text-decoration: none;
}
.brand-nom:hover { text-decoration: underline; }
.brand-tagline {
  flex: 1;
  font-size: 12px;
  line-height: 1.3;
  color: #6b7280;
}

#searchPanel {
  width: 100%;
  background: #fff;
  border-radius: 10px;
  box-shadow: 0 1px 6px rgba(0, 0, 0, 0.35);
  /* Colonne flex pour que le corps de l'itinéraire puisse RÉTRÉCIR sous la
     hauteur de son contenu : `min-height:0` lève la taille minimale automatique
     d'un item flex, sans laquelle un enfant en `overflow:auto` ne scrolle jamais
, il pousse simplement son parent. */
  display: flex;
  flex-direction: column;
  min-height: 0;
}
/* Onglets et barre d'actions restent visibles quoi qu'il arrive : ils encadrent
   la partie qui, elle, défile. */
#searchPanel > .seg, #searchPanel > .panel-foot { flex: 0 0 auto; }
/* Seul le mode Itinéraire défile : il est le seul à pouvoir devenir long (liste
   d'étapes, tracés proposés, récap, partage). Le mode Lieu, lui, doit garder son
   débordement visible : son menu d'autocomplétion sort de la card (cf. plus
   haut). Dans l'itinéraire, les champs Départ/Arrivée sont en haut d'un panneau
   qui n'est haut que quand l'écran l'est : leur menu a la place de s'ouvrir. */
#panelItineraire {
  overflow-y: auto;
  min-height: 0;
  overscroll-behavior: contain;   /* arrivé en bout de course, on ne fait pas défiler la carte */
}
.seg {
  display: flex;
  background: #f3f4f6;
  border-top-left-radius: 10px;
  border-top-right-radius: 10px;
  overflow: hidden;
}
.seg-btn {
  flex: 1;
  padding: 9px;
  border: none;
  background: transparent;
  font-size: 14px;
  font-weight: 600;
  color: #6b7280;
  cursor: pointer;
}
.seg-btn.active { background: #fff; color: #16a34a; box-shadow: inset 0 -2px 0 #16a34a; }
.panel-body { padding: 10px; display: flex; flex-direction: column; gap: 9px; }

/* Pied du panneau : les actions du trajet à gauche, replier à droite. Il reste
   affiché quand la card est réduite, c'est justement là qu'on veut pouvoir la
   rouvrir et vérifier que le trajet est enregistré. */
.panel-foot { display: flex; align-items: center; gap: 6px; padding: 0 10px 8px; }
.panel-foot .icon-btn { width: 26px; height: 26px; }
.panel-foot .icon-btn img { display: block; }
/* Google Maps / PDF / partage : un groupe, pour qu'un seul `hidden` les couvre
   tous les trois, mais des carrés séparés au même pas que le reste de la barre.
   La règle d'ID l'emporte sur le `display:none` de la feuille du navigateur,
   d'où la reprise explicite de [hidden]. */
#itinActions.foot-actions { display: flex; gap: 6px; }
#itinActions.foot-actions[hidden] { display: none; }
/* Google Maps scindé : le lien (tout l'itinéraire, depuis le départ) et son
   chevron (une étape, ou le reste du trajet, depuis ma position).
   UNE SEULE PASTILLE, deux zones cliquables : le cadre, le fond et l'arrondi
   appartiennent au GROUPE, ses deux moitiés ne sont séparées que par un filet.
   Un chevron dans sa propre bulle se lirait comme un bouton de plus dans la
   barre, alors qu'il ne fait qu'ouvrir les variantes de celui d'à côté.
   Pas d'`overflow:hidden` ici : le menu est un calque qui SORT du groupe (il
   est même en `position:fixed`), il serait rogné. Ce sont donc les moitiés qui portent l'arrondi
   correspondant à leur bout (7px = 8 du groupe moins son cadre), sans quoi un
   fond de survol carré déborderait du coin arrondi. */
.maps-split {
  position: relative;
  display: flex;
  align-items: stretch;
  border: 1px solid #d1d5db;
  border-radius: 8px;
  background: #fff;
}
.maps-split:hover, .maps-split.ouvert { border-color: #16a34a; }
.maps-split > .icon-btn { border: none; background: none; }
.panel-foot .maps-split > .icon-btn { height: 24px; }   /* 26 du pied moins le cadre */
.maps-split > #mapsLink { border-radius: 7px 0 0 7px; }
.panel-foot .maps-split .icon-btn.maps-chevron {
  width: 15px;
  font-size: 9px;
  border-radius: 0 7px 7px 0;
  border-left: 1px solid #e5e7eb;   /* un filet, pas une seconde bulle */
}
.maps-split.ouvert .maps-chevron { background: #f3f4f6; color: #16a34a; }
/* Le menu s'ouvre VERS LE HAUT : le pied est la dernière ligne d'une card
   ancrée en haut de l'écran mais qui peut descendre jusqu'en bas (la colonne
   est plafonnée à la hauteur de la fenêtre) ; vers le bas, il sortirait du
   cadre. Vers le haut, il recouvre le corps du panneau, exactement là où un
   menu passager a sa place. */
.foot-menu {
  /* Placé en coordonnées de FENÊTRE par `placerMenuMaps()` (top/left inline) :
     le pied de card est à quelques pixels du bord droit sur un téléphone, un
     positionnement relatif au bouton faisait sortir le menu de l'écran. Rien
     ici ne scrolle sous lui (le pied est figé dans la card, la carte ne défile
     pas), `fixed` n'a donc aucun décrochage à craindre. */
  position: fixed;
  top: 0;
  left: 0;
  z-index: 1600;
  /* Large et haut plutôt qu'étroit : les libellés (« Itinéraire complet depuis
     ma position », un nom d'étape) sont des phrases, pas des mots. À 230 px ils
     se cassaient en trois lignes serrées. On prend la largeur disponible, et la
     hauteur suit — un menu qui respire se lit d'un coup d'œil, ce qui est tout
     ce qu'on lui demande. */
  width: max-content;
  min-width: 250px;
  max-width: min(340px, calc(100vw - 16px));   /* 8 px de marge de chaque bord */
  max-height: 62vh;      /* dix étapes ne doivent pas sortir de l'écran… */
  overflow-y: auto;      /* …le menu défile alors sur lui-même */
  overscroll-behavior: contain;
  border: 1px solid #e5e7eb;
  border-radius: 10px;
  background: #fff;
  box-shadow: 0 6px 20px rgba(0, 0, 0, .22);
  padding: 5px;
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.foot-menu[hidden] { display: none; }
.foot-menu .etape-menu-item {
  padding: 8px 8px;
  font-size: 13px;
  line-height: 1.35;
  align-items: center;
  gap: 9px;
}
.foot-menu .etape-menu-item:hover { background: #f3f4f6; }
/* Les noms d'étape s'y écrivent en entier, sur deux lignes s'il le faut : le
   menu sert à RECONNAÎTRE une étape, et « Parc du Colonel Lau… » ne le permet
   pas toujours. (Dans la popup, où la place manque, l'ellipse reste.) */
.foot-menu .etape-menu-nom { white-space: normal; overflow: visible; }
/* Ligne « itinéraire complet » : c'est l'action principale du menu, elle est
   détachée de la liste des étapes par un filet. */
.foot-menu-suite { font-weight: 600; color: #111827; align-items: flex-start; }
.foot-menu-suite i { margin-top: 3px; }
.foot-menu-txt { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.foot-menu-sous { font-size: 11.5px; font-weight: 400; color: #6b7280; line-height: 1.35; white-space: normal; }
.foot-menu-sep { height: 1px; background: #e5e7eb; margin: 5px 2px; }
.foot-menu-vide { font-size: 12px; color: #9ca3af; padding: 6px 8px; }
/* Le titre de section doit rester une ligne : c'est un intertitre, pas un item. */
.foot-menu .etape-menu-titre { padding: 6px 8px 3px; }
#btnCollapsePanel { margin-left: auto; }
.icon-btn.loading { position: relative; color: transparent !important; pointer-events: none; }
.icon-btn.loading::after {
  content: '';
  position: absolute;
  top: 50%; left: 50%;
  width: 13px; height: 13px;
  margin: -6.5px 0 0 -6.5px;
  border: 2px solid rgba(0, 0, 0, .2);
  border-top-color: #374151;
  border-radius: 50%;
  animation: btnspin .6s linear infinite;
}
.icon-btn:disabled { opacity: .45; cursor: default; }
.icon-btn:disabled:hover { color: #374151; border-color: #d1d5db; }
/* Accusé de réception de l'enregistrement (s'efface tout seul). */
.save-flash {
  min-width: 0;
  font-size: 11px;
  font-weight: 600;
  color: #16a34a;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.save-flash.err { color: #dc2626; }

/* Card réduite : affichée à la place du panneau, à toute largeur. Sur grand
   écran elle GARDE la largeur de la colonne, donc celle de la card de marque
   au-dessus : deux cards empilées de largeurs différentes se lisent comme un
   décalage, pas comme un repli. Seul le petit écran la rétrécit à son contenu
   (cf. la media query), où rendre l'écran à la carte prime. */
#panelMini { display: none; }
#searchPanel.collapsed > .seg,
#searchPanel.collapsed > .panel-body { display: none; }
#searchPanel.collapsed #panelMini { display: flex; }
/* Réduite, le chevron fait l'inverse : il rouvre, donc il pointe vers le bas. */
#searchPanel.collapsed #btnCollapsePanel i { transform: rotate(180deg); }
.panel-mini {
  flex-direction: column;
  align-items: flex-start;
  gap: 1px;
  width: 100%;
  padding: 8px 12px;
  border: none;
  background: transparent;
  border-radius: 10px;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.mini-title { font-size: 13px; font-weight: 700; color: #16a34a; }
.mini-summary {
  max-width: 100%;
  font-size: 12px;
  color: #374151;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.mini-cta { font-size: 10px; color: #9ca3af; }

.field { position: relative; }
.field input[type="text"], .field input[type="time"], .field input[type="date"], .time-label input {
  width: 100%;
  padding: 9px 30px 9px 10px;
  border: 1px solid #d1d5db;
  border-radius: 9px;
  font-size: 14px;
}
.clear-btn {
  position: absolute;
  top: 50%;
  right: 6px;
  transform: translateY(-50%);
  border: none;
  background: transparent;
  font-size: 18px;
  color: #9ca3af;
  cursor: pointer;
  line-height: 1;
}
.clear-btn:hover { color: #374151; }

/* --- Autocomplete --- */
.autocomplete { position: relative; }
.suggestions {
  list-style: none;
  margin: 2px 0 0;
  padding: 0;
  position: absolute;
  left: 0; right: 0;
  z-index: 1200;
  background: #fff;
  border: 1px solid #e5e7eb;
  border-radius: 9px;
  box-shadow: 0 6px 16px rgba(0, 0, 0, .15);
  max-height: 260px;
  overflow-y: auto;
  display: none;
}
.suggestions.open { display: block; }
.suggestions li {
  padding: 8px 10px;
  cursor: pointer;
  font-size: 13.5px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.suggestions li:hover, .suggestions li.active { background: #ecfdf5; }

#itinForm { display: flex; flex-direction: column; gap: 10px; }

/* Résumé compact de l'itinéraire (après calcul) */
#itinSummary {
  display: flex;
  flex-direction: column;
  gap: 4px;
  background: #f0fdf4;
  border: 1px solid #bbf7d0;
  border-radius: 10px;
  padding: 9px 11px;
}
.summary-main { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.summary-actions { display: flex; gap: 6px; flex: 0 0 auto; }
.summary-route {
  font-weight: 700;
  font-size: 14px;
  color: #111827;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.summary-sub { font-size: 12.5px; color: #4b5563; }
.icon-btn {
  flex: 0 0 auto;
  width: 30px;
  height: 30px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid #d1d5db;
  border-radius: 8px;
  background: #fff;
  color: #6b7280;
  cursor: pointer;
}
.icon-btn:hover { color: #16a34a; border-color: #16a34a; }

.swap-row { display: flex; justify-content: center; }
.mini-btn {
  border: 1px solid #d1d5db;
  background: #fff;
  border-radius: 8px;
  padding: 6px 12px;
  cursor: pointer;
  font-size: 14px;
}
.mini-btn:hover { background: #f3f4f6; }

.mode-row { display: flex; gap: 14px; font-size: 14px; }
.mode-row label { cursor: pointer; }

.link { color: #16a34a; font-size: 13px; text-decoration: none; cursor: pointer; }
.link:hover { text-decoration: underline; }

.time-label { display: flex; flex-direction: column; gap: 3px; font-size: 12.5px; color: #6b7280; }
/* Date et heure côte à côte : deux champs courts qui répondent à la même
   question (« quand part-on ? »), même s'ils ne servent pas à la même chose —
   l'heure date les jalons du trajet, la date choisit un jour de prévision. */
.time-row { display: flex; gap: 8px; }
.time-row .time-label { flex: 1; min-width: 0; }
#timeFields { display: flex; flex-direction: column; gap: 8px; }
#sensRow { font-size: 13px; }

/* --- Prévisions Bison Futé ---------------------------------------------
   Les quatre niveaux de la source. Le vert n'a pas de pastille : une portion
   fluide n'est pas colorée sur la carte, l'annoncer dans la légende ferait
   chercher une couleur qui n'y est pas. */
.trafic-box {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 9px 10px;
  border: 1px solid #e5e7eb;
  border-radius: 9px;
  background: #fafafa;
  font-size: 12.5px;
}
.trafic-head { font-size: 12px; font-weight: 700; color: #374151; }
.trafic-vieux { font-weight: 400; color: #9ca3af; }
.trafic-nat { display: flex; align-items: center; gap: 6px; }
.trafic-vide { color: #6b7280; }
.trafic-puce {
  flex: none;
  width: 10px; height: 10px;
  border-radius: 50%;
  background: #16a34a;              /* n0 : circulation normale */
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .15);
}
.trafic-puce.n1 { background: #f59e0b; }
.trafic-puce.n2 { background: #dc2626; }
.trafic-puce.n3 { background: #7f1d1d; }
.trafic-deps { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 3px; }
.trafic-deps li { display: flex; align-items: center; gap: 6px; }
.trafic-dep-nom { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.trafic-dep-niv { color: #6b7280; font-size: 11.5px; }
/* Le bulletin est replié : trois paragraphes de prose dans une card de 320 px
   noieraient la légende, qui est ce qu'on vient lire. */
.trafic-bulletin summary { cursor: pointer; color: #16a34a; }
.trafic-bulletin p { margin: 6px 0 0; color: #374151; line-height: 1.4; }
.trafic-bulletin a { display: inline-block; margin-top: 6px; color: #16a34a; }

.slider-row { display: flex; flex-direction: column; gap: 4px; }
#distLabel { font-size: 13px; font-weight: 600; }
/* Rayon déplacé mais pas encore appliqué : il ne le sera qu'au prochain calcul
   d'itinéraire (un recalcul à chaque cran du curseur coûte trop cher). */
#distLabel.pending { color: #b45309; }
#distLabel.pending::after { content: ', à appliquer'; font-weight: 500; }
.primary-btn.pending { box-shadow: 0 0 0 2px #fcd34d; }
input[type="range"] { width: 100%; accent-color: #16a34a; }

.primary-btn {
  background: #16a34a;
  color: #fff;
  border: none;
  border-radius: 9px;
  padding: 10px;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}
.primary-btn:hover { background: #15803d; }
.primary-btn:disabled { opacity: .8; cursor: progress; }

/* Spinner de chargement sur les boutons du form (ex. « Itinéraire ») */
.primary-btn.loading, .mini-btn.loading { position: relative; color: transparent !important; pointer-events: none; }
.primary-btn.loading::after, .mini-btn.loading::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 16px;
  height: 16px;
  margin: -8px 0 0 -8px;
  border: 2px solid rgba(255, 255, 255, .45);
  border-top-color: #fff;
  border-radius: 50%;
  animation: btnspin .6s linear infinite;
}
.mini-btn.loading::after { border-color: rgba(0,0,0,.25); border-top-color: #374151; }
@keyframes btnspin { to { transform: rotate(360deg); } }

/* --- Étapes du trajet (liste réordonnable par glisser-déposer) --- */
#etapesBox { display: flex; flex-direction: column; gap: 6px; }
.etapes-head { font-size: 12px; font-weight: 700; color: #374151; }
.toggle-row {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 12.5px;
  color: #374151;
  cursor: pointer;
}
.toggle-row input { accent-color: #16a34a; width: 15px; height: 15px; cursor: pointer; }
.etapes-hint { font-size: 11px; color: #9ca3af; }
/* Récap final : total du trajet + surcoût des étapes */
.etape-recap {
  display: flex;
  flex-direction: column;
  gap: 2px;
  background: #f0fdf4;
  border: 1px solid #bbf7d0;
  border-radius: 8px;
  padding: 6px 9px;
}
.recap-total { font-size: 13px; font-weight: 700; color: #111827; }
.recap-delta { font-size: 11.5px; color: #4b5563; }
/* Heure d'arrivée : même bleu que les jalons horaires et les heures d'étape */
.recap-arrivee { font-size: 12.5px; color: #1d4ed8; }
.recap-arrivee strong { font-variant-numeric: tabular-nums; }
/* « dont 30 min d'arrêt » : la part du total qui n'est pas du roulage */
.recap-pause { font-size: 11px; font-weight: 500; color: #6b7280; }
.etape-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
.etape-list li {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12.5px;
  border: 1px solid #e5e7eb;
  border-radius: 8px;
  padding: 6px 8px;
  background: #fff;
}
.etape-list li.etape-fixed { border-style: dashed; color: #6b7280; background: #fafafa; }
/* Tronçon entre deux points du trajet : distance + durée, sans cadre */
.etape-list li.etape-leg {
  border: none;
  background: none;
  padding: 0 0 0 13px;
  gap: 7px;
  font-size: 11.5px;
  color: #6b7280;
}
.etape-list li.etape-leg::before {
  content: '';
  flex: 0 0 auto;
  width: 0;
  height: 13px;
  border-left: 2px dotted #d1d5db;
}
/* `touch-action:none` : indispensable pour que le drag au doigt ne scrolle pas la page */
.etape-list li.etape-item { cursor: grab; touch-action: none; user-select: none; }
.etape-list li.dragging {
  cursor: grabbing;
  position: relative;
  z-index: 5;
  border-color: #ea580c;
  box-shadow: 0 4px 12px rgba(0, 0, 0, .18);
}
.etape-grip { color: #cbd5e1; letter-spacing: -2px; }
.etape-num {
  flex: 0 0 auto;
  width: 16px; height: 16px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: #ea580c;
  color: #fff;
  font-size: 9px;
  font-weight: 700;
  border-radius: 50%;
}
.etape-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Heure d'arrivée au point, quand l'heure de départ est saisie. Même bleu que
   les jalons horaires du tracé : c'est le même décompte, lu autrement. */
.etape-time {
  flex: 0 0 auto;
  font-size: 11px;
  font-weight: 700;
  color: #1d4ed8;
  background: #eff6ff;
  border: 1px solid #bfdbfe;
  border-radius: 999px;
  padding: 1px 6px;
  font-variant-numeric: tabular-nums;
}
.etape-del {
  flex: 0 0 auto;
  border: none;
  background: transparent;
  color: #9ca3af;
  font-size: 16px;
  line-height: 1;
  padding: 0 2px;
  cursor: pointer;
}
.etape-del:hover { color: #dc2626; }
/* Interrupteur d'étape : la garder dans la liste sans la mettre dans le trajet.
   Orange à l'état actif, comme l'épingle numérotée qu'elle porte alors. */
.etape-switch {
  flex: 0 0 auto;
  position: relative;
  width: 26px; height: 15px;
  padding: 0;
  border: none;
  border-radius: 999px;
  background: #d1d5db;
  cursor: pointer;
  transition: background .15s;
}
.etape-switch::after {
  content: '';
  position: absolute;
  top: 2px; left: 2px;
  width: 11px; height: 11px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .3);
  transition: transform .15s;
}
.etape-switch[aria-checked="true"] { background: #ea580c; }
.etape-switch[aria-checked="true"]::after { transform: translateX(11px); }
/* Étape ignorée : toujours lisible et déplaçable, mais visiblement hors trajet */
.etape-list li.etape-off { background: #fafafa; border-style: dashed; color: #9ca3af; }
.etape-list li.etape-off .etape-name { text-decoration: line-through; }
.etape-num.etape-num-off { background: #e5e7eb; color: #9ca3af; }

/* --- Variantes d'une étape ----------------------------------------------
   Plusieurs lieux voisins candidats au MÊME arrêt, un seul retenu à la fois.
   La liste vit à l'intérieur du <li> de l'étape (le glisser-déposer déplace des
   <li> : en frère, elle aurait suivi le mauvais voisin), d'où le retour à la
   ligne par `flex-wrap` et la base 100 %.
   Les règles ci-dessous DÉFONT `.etape-list li` sur les variantes : ce sélecteur
   atteint tous les <li> descendants, y compris ceux-là, qui hériteraient sinon
   du cadre et du fond d'une étape. */
.etape-list li.etape-item { flex-wrap: wrap; }
.etape-list li.etape-groupe { border-color: #fed7aa; }
/* Un groupe nommé porte un titre d'ARRÊT (« Pause déjeuner ») et non de lieu :
   il se distingue de la reprise automatique du nom du lieu retenu. */
.etape-name.etape-nomme { font-weight: 600; color: #9a3412; }
.etape-rename {
  flex: 0 0 auto;
  border: none;
  background: transparent;
  color: #cbd5e1;
  font-size: 11px;
  line-height: 1;
  padding: 0 2px;
  cursor: pointer;
}
.etape-rename:hover { color: #ea580c; }
.etape-variantes {
  list-style: none;
  margin: 5px 0 1px;
  padding: 0 0 0 22px;      /* aligné sous le nom, pas sous la poignée */
  flex: 0 0 100%;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.etape-list li.variante { border: none; background: none; padding: 0; gap: 4px; font-size: 12px; }
.variante-lab { display: flex; align-items: center; gap: 5px; flex: 1; min-width: 0; cursor: pointer; color: #6b7280; }
.variante-lab.on { color: #c2410c; font-weight: 600; }
.variante-lab input { accent-color: #ea580c; margin: 0; flex: 0 0 auto; }
.variante-nom { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* La commune est ce qui départage deux variantes homonymes, mais elle reste une
   précision : plus petite et plus pâle que le nom, y compris sur la retenue, qui
   est en gras. Elle vit DANS `.variante-nom` pour partager son ellipse — deux
   éléments frères se seraient tronqués chacun de leur côté. */
.variante-loc { font-size: .92em; font-weight: 400; color: #9ca3af; }
.variante-del {
  flex: 0 0 auto;
  border: none;
  background: transparent;
  color: #d1d5db;
  font-size: 12px;
  line-height: 1;
  padding: 0 2px;
  cursor: pointer;
}
.variante-del:hover { color: #dc2626; }

/* --- Bouton d'étape scindé de la fiche, et son menu ----------------------
   À gauche l'action courante, à droite un chevron qui ouvre les gestes de
   regroupement. Même règle que le bouton Maps du pied de panneau : UNE SEULE
   pastille, deux zones cliquables, séparées par un filet. Le cadre, le fond et
   l'arrondi sont portés par le groupe — c'est lui, du coup, qui porte aussi
   l'état `on` (étape au trajet), que la moitié gauche portait auparavant.
   Le menu est un bloc DANS la popup, et SIBLING du groupe : celle-ci est déjà
   positionnée à la main par MapLibre, un calque flottant par-dessus n'aurait
   apporté que des débordements à rattraper. */
.etape-actions {
  display: flex;
  align-items: stretch;
  margin-top: 6px;
  border: 1px solid #d1d5db;
  border-radius: 8px;
  background: #fff;
}
.etape-actions.on { border-color: #ea580c; }
.etape-actions > .mini-btn { border: none; background: none; border-radius: 0; }
.etape-actions .etape-btn { width: auto; flex: 1; margin-top: 0; border-radius: 7px 0 0 7px; }
/* Seul enfant visible (rien à proposer dans le menu) : il reprend les deux
   bouts, sinon le bouton paraîtrait coupé à droite pour rien. */
.etape-actions .etape-btn:only-child,
.etape-actions .etape-chevron[hidden] + .etape-btn,
.etape-actions .etape-btn:has(+ .etape-chevron[hidden]) { border-radius: 7px; }
.etape-chevron {
  flex: 0 0 auto;
  padding: 6px 9px;
  font-size: 11px;
  color: #6b7280;
  border-radius: 0 7px 7px 0;
  border-left: 1px solid #e5e7eb;   /* un filet, pas une seconde bulle */
}
.etape-actions.on .etape-chevron { border-left-color: #fed7aa; }
.etape-chevron.ouvert { background: #f3f4f6; color: #c2410c; }
.etape-menu {
  margin-top: 4px;
  border: 1px solid #e5e7eb;
  border-radius: 8px;
  background: #fafafa;
  padding: 4px;
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.etape-menu-titre {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: .3px;
  color: #9ca3af;
  padding: 5px 6px 2px;
}
.etape-menu-item {
  display: flex;
  align-items: center;
  gap: 6px;
  width: 100%;
  text-align: left;
  border: none;
  background: none;
  font: inherit;
  font-size: 12px;
  color: #374151;
  padding: 5px 6px;
  border-radius: 6px;
  cursor: pointer;
}
.etape-menu-item:hover { background: #fff; }
.etape-menu-num {
  flex: 0 0 auto;
  width: 16px; height: 16px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: #ea580c;
  color: #fff;
  font-size: 10px;
  font-weight: 700;
}
.etape-menu-num.off { background: #e5e7eb; color: #9ca3af; }
.etape-menu-nom { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.etape-btn { width: 100%; margin-top: 6px; font-size: 13px; }
.etape-btn.on { color: #c2410c; }   /* le cadre est celui du groupe (.etape-actions.on) */

.route-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.route-list li {
  border: 1px solid #d1d5db;
  border-radius: 8px;
  padding: 8px 10px;
  font-size: 13px;
  cursor: pointer;
  display: flex;
  justify-content: space-between;
}
.route-list li.active { border-color: #16a34a; background: #ecfdf5; }

/* --- Boutons accolés de la fiche d'un lieu (Street View, satellite, source) --- */
.btn-addons { display: flex; }
.addon-btn {
  flex: 1;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid #d1d5db;
  background: #fff;
  color: #6b7280;
  cursor: pointer;
  text-decoration: none;
}
.addon-btn + .addon-btn { border-left: none; }
.btn-addons .addon-btn:first-child { border-radius: 8px 0 0 8px; }
.btn-addons .addon-btn:last-child { border-radius: 0 8px 8px 0; }
.addon-btn:hover { background: #f3f4f6; color: #16a34a; }
.addon-btn img, .addon-btn svg { display: block; }
/* Le partage de la fiche est un <button> au milieu d'une barre de liens : les
   défauts du navigateur (police, padding) le décaleraient de ses voisins. */
button.addon-btn { padding: 0; font: inherit; }
.addon-btn.copied { color: #16a34a; }
/* Retouche de la fiche (administrateurs) : dernière de la barre et ambrée, pour
   qu'on ne la confonde pas avec les liens vers les services voisins. Elle ne
   consulte pas, elle modifie. */
.addon-btn.addon-admin { color: #b45309; background: #fffbeb; }
.addon-btn.addon-admin:hover { background: #fef3c7; color: #92400e; }

.share-result { display: flex; flex-direction: column; gap: 3px; }
.share-result input {
  width: 100%;
  padding: 6px 8px;
  border: 1px solid #bbf7d0;
  border-radius: 8px;
  background: #f0fdf4;
  font-size: 12px;
  color: #166534;
}
.share-msg { font-size: 11px; color: #6b7280; }
/* Bascule « lecture seule / modifiable » du lien partagé */
.share-modes { display: flex; gap: 4px; }
.share-mode {
  flex: 1;
  padding: 4px 6px;
  border: 1px solid #d1d5db;
  border-radius: 7px;
  background: #fff;
  color: #4b5563;
  font-size: 11.5px;
  cursor: pointer;
}
.share-mode:hover { border-color: #86efac; }
.share-mode.active { border-color: #16a34a; background: #ecfdf5; color: #166534; font-weight: 600; }

/* Jalons horaires du trajet : « 1 h », « 2 h »… posés sur la ligne bleue.
   Le marqueur GL centre lui-même son élément (`anchor: 'center'`), la pastille
   n'a donc rien à recaler ; elle reste lisible quel que soit le nombre de
   chiffres (« 10 h »). Transparente au clic : c'est le tracé, dessous, qui doit
   recevoir le geste. */
.hour-mark { pointer-events: none; }
.hour-pill {
  display: inline-block;
  padding: 2px 6px;
  border: 2px solid #fff;
  border-radius: 9px;
  background: #2563eb;
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  line-height: 1.1;
  white-space: nowrap;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .35);
}

/* Repères du trajet : rond blanc au départ, drapeau à damier à l'arrivée */
.route-endpoint { background: none; border: none; }
.route-endpoint svg { display: block; filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .45)); }

/* Points synthétiques : la pastille d'un point de passage et la goutte
   numérotée d'une position ajoutée à la main. Contrairement aux jalons et à la
   pastille de position, ceux-là sont INTERACTIFS — on les saisit et on les
   clique — donc surtout pas de `pointer-events: none`. Le curseur dit lequel
   des deux gestes est possible. */
.passage-mark,
.position-mark { background: none; border: none; cursor: grab; }
.passage-mark:active,
.position-mark:active { cursor: grabbing; }
.passage-mark svg,
.position-mark svg { display: block; filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .45)); }
/* Le fantôme suit le doigt pendant qu'on tire le tracé : il montre où le point
   se posera, il n'est pas encore le point. Transparent au clic, sinon il
   intercepterait le `mouseup` qui termine le geste. */
.passage-mark.fantome { opacity: .75; pointer-events: none; }
/* Étape ignorée : même traitement que sa ligne dans la liste. */
.synth-off { opacity: .45; filter: grayscale(1); }

/* Pastille « vous êtes ici » du mode itinéraire. Transparente au clic, comme
   les jalons horaires : le geste doit atteindre le tracé, dessous. Le halo
   pulse pour la distinguer d'une épingle, qui, elle, désigne un lieu. */
.pos-mark { pointer-events: none; }
.pos-dot {
  width: 16px; height: 16px;
  border-radius: 50%;
  background: #2563eb;
  border: 3px solid #fff;
  box-shadow: 0 1px 4px rgba(0, 0, 0, .45);
}
.pos-dot::before {
  content: '';
  display: block;
  width: 100%; height: 100%;
  border-radius: 50%;
  background: rgba(37, 99, 235, .35);
  animation: pospulse 2.2s ease-out infinite;
}
@keyframes pospulse {
  0%   { transform: scale(1); opacity: .8; }
  100% { transform: scale(3.4); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .pos-dot::before { animation: none; }
}

/* --- Popups ---
   MapLibre habille sa popup autrement que Leaflet : on lui rend le cadre blanc
   arrondi de l'application, et la fiche d'un lieu reçoit une LARGEUR FIXE, la
   galerie s'accroche sur la largeur de la piste, qui doit donc être stable
   (sinon le défilement s'arrête entre deux photos). */
.maplibregl-popup-content {
  padding: 10px;
  border-radius: 10px;
  box-shadow: 0 1px 6px rgba(0, 0, 0, .35);
  font: inherit;
  color: inherit;
}
.popup-lieu .maplibregl-popup-content { width: 250px; }
.maplibregl-popup-close-button {
  width: 22px;
  height: 22px;
  font-size: 17px;
  line-height: 1;
  color: #9ca3af;
  border-radius: 6px;
}
.maplibregl-popup-close-button:hover { background: #f3f4f6; color: #374151; }
/* Infobulle de survol (meneur de groupe, agrégat) : ni cadre ni flèche. */
.tip-popup .maplibregl-popup-content {
  padding: 3px 8px;
  border-radius: 7px;
  font-size: 12px;
  box-shadow: 0 1px 4px rgba(0, 0, 0, .3);
}
.tip-popup .maplibregl-popup-tip { display: none; }

.popup-title { font-weight: 700; font-size: 15px; }
.popup-title a { color: #15803d; text-decoration: none; }
/* Galerie de la fiche : défilement horizontal, une photo à la fois */
.popup-gallery { position: relative; margin: 6px 0; }
.pg-track {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  border-radius: 6px;
  scrollbar-width: none;          /* la nav suffit */
  -ms-overflow-style: none;
}
.pg-track::-webkit-scrollbar { display: none; }
.pg-slide { position: relative; flex: 0 0 100%; margin: 0; scroll-snap-align: start; }
.pg-slide img {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: 6px;
  background: #f3f4f6;
}
.pg-slide figcaption {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  padding: 8px 6px 3px;
  font-size: 9px;
  color: #fff;
  background: linear-gradient(transparent, rgba(0, 0, 0, .6));
  border-radius: 0 0 6px 6px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.pg-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 24px; height: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: 50%;
  background: rgba(255, 255, 255, .88);
  color: #374151;
  font-size: 17px;
  line-height: 1;
  cursor: pointer;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .35);
}
.pg-prev { left: 5px; }
.pg-next { right: 5px; }
.pg-nav:hover { background: #fff; color: #16a34a; }
.pg-nav:disabled { opacity: 0; pointer-events: none; }
.pg-dots { position: absolute; left: 0; right: 0; bottom: 17px; display: flex; justify-content: center; gap: 4px; }
.pg-dots span {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: rgba(255, 255, 255, .55);
  box-shadow: 0 0 2px rgba(0, 0, 0, .6);
  cursor: pointer;
}
.pg-dots span.on { background: #fff; }
.popup-eq { font-size: 13px; margin: 4px 0; }
.popup-source { font-size: 12px; color: #6b7280; margin: 2px 0 4px; }
/* Barre de liens de la fiche (Street View + satellite + source), boutons accolés */
.popup-actions { margin: 6px 0 2px; }
.popup-actions .addon-btn { height: 28px; }

/* (Les épingles ne sont plus des éléments du DOM mais des textures GL : leur
   ombre portée est cuite dans l'image, voir `ajouterPin` dans app.js.) */
.popup-etape { font-size: 12.5px; color: #6b7280; margin: 4px 0; }
/* Horaires d'un commerce : l'état du moment, coloré comme une réponse, la
   chaîne OSM complète reste en `title`. Gris quand la syntaxe dépasse ce que le
   lecteur sait interpréter : on affiche alors le tag brut, sans le qualifier. */
.popup-horaires { font-size: 12px; font-weight: 600; color: #6b7280; margin: 3px 0; }
.popup-horaires.ouvert { color: #15803d; }
.popup-horaires.ferme { color: #b91c1c; }
.notation { margin-top: 6px; border-top: 1px solid #eee; padding-top: 6px; }
.stars { font-size: 16px; color: #f59e0b; letter-spacing: 1px; }
.rate-stars span { cursor: pointer; font-size: 18px; color: #d1d5db; }
.rate-stars span.hot { color: #f59e0b; }
.note-summary { font-size: 12px; color: #6b7280; }

/* --- Mobile : rail de filtres en bas à droite, boutons/emoji plus petits --- */
@media (max-width: 640px) {
  #toolbar {
    top: auto;
    left: auto;
    bottom: 24px;   /* au-dessus de l'attribution */
    right: 12px;
    gap: 8px;       /* deux cards à loger en hauteur : l'écart se resserre */
  }
  .tool-btn { width: 30px; height: 30px; font-size: 13px; }
  .tool-ico-img { width: 16px; height: 16px; }
  .tool-group .tool-btn.active::after { width: 12px; height: 12px; font-size: 8px; }
  .tool-group.ajout .tool-btn.active::after { font-size: 10px; }

  /* Le popover de note s'ouvre vers la gauche (le rail est à droite).
     Ciblé sur #notePop et NON sur `.popover` : le menu du compte porte la même
     classe, et cette règle, à égalité de spécificité mais plus bas dans la
     feuille, écrasait son `right:0` — le menu partait 8 px à GAUCHE de la card
     de marque, c'est-à-dire hors de l'écran. Le bug ne se voyait pas tant que
     le bouton compte ouvrait directement la modale de connexion. */
  #notePop {
    left: auto;
    right: calc(100% + 8px);
    bottom: 0;
  }
  #notePop::before {
    left: auto;
    right: -5px;
    bottom: 12px;
    box-shadow: 2px -2px 4px rgba(0, 0, 0, .06);
  }

  /* Panneau réduit : toucher la carte rend l'écran au doigt, il ne reste qu'une
     petite card (onglet + résumé de la recherche) qui se rouvre au toucher.
     Les règles de l'état réduit sont communes à toutes les largeurs, plus
     haut ; ici, seulement ce qui tient à l'étroitesse de l'écran, dont le
     rétrécissement à son contenu, calé à droite. */
  #rightStack.collapsed { align-items: flex-end; }
  #searchPanel.collapsed { width: auto; max-width: 78vw; }

  /* La barre de marque reste, mais réduite au logo : la tagline coûte deux
     lignes de carte pour une information déjà portée par le logo. */
  #brandCard { padding: 6px 10px; }
  .brand-logo-img { height: 22px; }
  .brand-tagline { display: none; }

  /* La card resserrée (10 px de marge au lieu de 14) rapproche le drapeau du
     bord : la flèche du menu le suit. */
  .lang-pop::before { right: 58px; }

  /* Le rail occupe le coin BAS-droit sur petit écran : le témoin passe donc
     au-dessus de lui, toujours dans son axe, dessous, il tomberait sur
     l'attribution, voire hors de l'écran. */
  #loadIndicator {
    top: auto;
    bottom: 100%;
    width: 30px;
    margin: 0 0 7px;
  }
}

