/* Thème sombre : l'outil s'utilise en regardant un nuage de points sur fond
   noir, une interface claire à côté éblouit et fausse la lecture des couleurs
   de classification. */

:root {
  --fond: #0b0e13;
  --fond-2: #12161e;
  --fond-3: #1a202b;
  --bord: #262d3a;
  --texte: #dbe1ea;
  --texte-2: #8b95a6;
  --accent: #5ec8f0;
  --accent-2: #4ade80;
  --alerte: #ff6b52;
  --or: #ffd24a;
}

* { box-sizing: border-box; }

/* `hidden` doit l'emporter, toujours.
   La feuille du navigateur pose `[hidden] { display: none }`, mais une règle
   d'auteur qui donne un `display` au même élément la surclasse — les deux ont la
   même spécificité et l'auteur passe après. Un `display: grid` ou `flex` posé
   sur une classe rend donc l'attribut `hidden` totalement inopérant, sans le
   moindre avertissement.
   C'est ce qui affichait le voile d'attente au démarrage, et c'est ce qui
   laissait voir en permanence le détail de dalle et les exports de sentiers. */
[hidden] { display: none !important; }

html, body {
  margin: 0;
  height: 100%;
  background: var(--fond);
  color: var(--texte);
  font: 14px/1.5 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  overflow: hidden;
}

/* ── Barre de titre ──────────────────────────────────────────────────────── */

.barre {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: 10px 16px;
  background: var(--fond-2);
  border-bottom: 1px solid var(--bord);
  height: 46px;
}
/* Masqué par défaut : n'apparaît que sous 900 px, où le panneau devient un
   tiroir (voir le media query plus bas). */
.btn-menu {
  display: none;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  /* Sans ça, un enfant flex rétrécit sous sa largeur posée dès que ses voisins
     (titre, sous-titre, état) manquent de place — mesuré à 380 px : 30 px
     tombait à 15. Le bouton doit garder sa taille tactile quoi qu'il arrive. */
  flex-shrink: 0;
  padding: 0;
  background: var(--fond-3);
  border: 1px solid var(--bord);
  border-radius: 6px;
  color: var(--texte);
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
  align-self: center;
}
/* Masqué par défaut, comme `.btn-menu` : n'existe que sous 900 px. */
.fond-panneau { display: none; }
.barre h1 {
  margin: 0;
  font-size: 17px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
  font-weight: 600;
}
.sous-titre { color: var(--texte-2); font-size: 12px; }
.etat {
  margin-left: auto;
  font-size: 12px;
  color: var(--texte-2);
  font-variant-numeric: tabular-nums;
  /* Les messages qui disent quoi faire (pas seulement ce qu'il y a) font
     souvent deux lignes, et débordaient sous la barre de 46 px. Tronqué à une
     ligne : le message complet est de toute façon dans l'alerte, faite pour
     être lue. `min-width: 0` est nécessaire ici — sans lui, un enfant flex ne
     rétrécit jamais sous la largeur de son contenu et l'ellipse ne se déclenche
     pas. */
  max-width: 42vw;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.etat.travail { color: var(--or); }
.etat.erreur { color: var(--alerte); }

/* ── Mise en page ────────────────────────────────────────────────────────── */

.grille {
  display: grid;
  grid-template-columns: 380px 1fr;
  height: calc(100% - 46px);
}

.panneau {
  overflow-y: auto;
  /* Sans `min-height: 0`, un élément de grille refuse de devenir plus petit que
     son contenu : la rangée s'étire, le panneau déborde et `overflow-y` n'a
     plus rien à faire défiler. */
  min-height: 0;
  border-right: 1px solid var(--bord);
  background: var(--fond-2);
  padding-bottom: 24px;
}
.panneau::-webkit-scrollbar { width: 9px; }
.panneau::-webkit-scrollbar-thumb { background: var(--bord); border-radius: 5px; }

.scene { position: relative; display: flex; flex-direction: column; min-width: 0; min-height: 0; }
.vue { flex: 1; min-height: 0; position: relative; }
#vue-carte { background: #0e1116; }
#canvas3d, #canvas-2d { width: 100%; height: 100%; display: block; touch-action: none; cursor: grab; }
/* Mode Sélection : la flèche plutôt que la main, pour dire « cliquer un point »
   plutôt que « glisser pour déplacer ». Déclarée avant `:active` et à
   spécificité égale (id + classe contre id + pseudo-classe) : la règle qui
   suit l'emporte à égalité, donc `:active` garde le dernier mot pendant un
   glissé effectif — le geste de glisser continue toujours de déplacer, en
   sélection comme ailleurs, seul le curseur au repos change. */
#canvas3d.mode-selection, #canvas-2d.mode-selection { cursor: default; }
#canvas3d:active, #canvas-2d:active { cursor: grabbing; }

.onglets {
  display: flex;
  gap: 2px;
  padding: 6px 10px;
  background: var(--fond-2);
  border-bottom: 1px solid var(--bord);
  align-items: center;
}
.onglets button {
  background: transparent;
  border: 1px solid transparent;
  color: var(--texte-2);
  padding: 5px 14px;
  border-radius: 6px;
  cursor: pointer;
  font-size: 13px;
}
.onglets button.actif { background: var(--fond-3); color: var(--texte); border-color: var(--bord); }
.aide { margin-left: auto; color: var(--texte-2); font-size: 11px; }

/* Boutons à icône seule (sous-barre Déplacement/Sélection) : le nom passe en
   infobulle (`title`) plutôt qu'en texte visible, deux mots étant de trop pour
   une barre déjà partagée avec les onglets. `.onglets button` en spécificité
   égale suffirait à fixer le padding, mais pas à annuler `width`/`height` —
   d'où `.onglets button.btn-mode`, plus spécifique, pour tout regrouper. */
.onglets button.btn-mode {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 30px;
  padding: 0;
}
.btn-mode .icone { width: 16px; height: 16px; fill: currentColor; display: block; }

/* ── Étapes ──────────────────────────────────────────────────────────────── */

.etape { padding: 14px 16px; border-bottom: 1px solid var(--bord); }
.etape h2 {
  margin: 0 0 10px;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--texte-2);
  display: flex;
  align-items: center;
  gap: 8px;
}

/* Le panneau suit la vue : `data-vue` déclare l'onglet où une section a un sens,
   et le panneau porte l'onglet courant. Une section sans `data-vue` vaut pour
   toutes. Rien à câbler en JavaScript au-delà de l'attribut.

   La règle est écrite en négatif — « tout ce qui n'est pas de la vue courante »
   — et non paire par paire : avec deux vues, deux règles suffisaient ; avec
   trois, il en faudrait six, et l'ancienne paire laissait justement la section
   du relief visible dans les deux autres onglets.

   `~=` plutôt que `=` : une section peut valoir pour plusieurs onglets à la
   fois (`data-vue="2d 3d"`, la sélection d'un point) sans dupliquer son
   balisage, chaque token de la liste étant comparé séparément. */
.panneau[data-vue="carte"] [data-vue]:not([data-vue~="carte"]),
.panneau[data-vue="2d"] [data-vue]:not([data-vue~="2d"]),
.panneau[data-vue="3d"] [data-vue]:not([data-vue~="3d"]) { display: none; }

/* Bandeau du nuage chargé. Collant en haut du panneau, qui est le seul
   conteneur défilant : il reste sous les yeux quelle que soit la position dans
   la liste des résultats. */
.bandeau-nuage {
  position: sticky;
  top: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 12px 9px 14px;
  background: var(--fond-3);
  border-bottom: 1px solid var(--bord);
  font-size: 12px;
}
.bandeau-nuage .pastille-etat {
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--accent-2);
  flex: none;
}
.bandeau-nuage .nom {
  color: var(--texte);
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.bandeau-nuage .info { color: var(--texte-2); margin-left: auto; white-space: nowrap; }
.bandeau-nuage .fermer {
  flex: none;
  background: transparent;
  border-color: transparent;
  color: var(--texte-2);
  padding: 2px 7px;
  font-size: 13px;
}
.bandeau-nuage .fermer:hover { background: var(--fond-2); color: var(--alerte); border-color: var(--bord); }

/* Compteur porté par un onglet de volet — se tait tant qu'il est vide. */
.pastille {
  background: rgba(0, 0, 0, 0.28);
  border-radius: 9px;
  padding: 0 6px;
  margin-left: 5px;
  font-size: 10.5px;
  font-variant-numeric: tabular-nums;
}
.pastille:empty { display: none; }

/* Seuils repliés. Quinze curseurs dépliés en permanence noyaient les deux
   boutons qui comptent ; on les ouvre quand on vient les régler. */
.repli {
  border: 1px solid var(--bord);
  border-radius: 6px;
  background: var(--fond-3);
  margin-bottom: 10px;
}
.repli > summary {
  cursor: pointer;
  padding: 7px 11px;
  font-size: 12px;
  color: var(--texte-2);
  list-style: none;
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.repli > summary::-webkit-details-marker { display: none; }
.repli > summary::after { content: "▾"; font-size: 10px; }
.repli[open] > summary::after { content: "▴"; }
.repli > summary:hover { color: var(--texte); }
.repli[open] > summary { border-bottom: 1px solid var(--bord); }
.repli > *:not(summary) { padding: 10px 11px 0; }
.repli > .rangee { padding-bottom: 11px; }
.repli .secondaire { width: 100%; font-size: 12px; }

/* Rendu à la résolution native de la grille de travail des sentiers (souvent
   bien plus large que le panneau) : `max-width` la ramène à la largeur
   disponible sans jamais faire déborder le panneau, `image-rendering` évite
   un flou d'interpolation qui masquerait le grain que le diagnostic veut
   justement montrer. */
.diag-canvas {
  display: block;
  width: 100%;
  max-width: 100%;
  height: auto;
  margin: 10px 0;
  border: 1px solid var(--bord);
  border-radius: 4px;
  background: #000;
  image-rendering: pixelated;
}

.vide { color: var(--texte-2); font-size: 12.5px; line-height: 1.6; }

.detail { margin: 0 0 12px; display: grid; grid-template-columns: auto 1fr; gap: 3px 12px; font-size: 12.5px; }
.detail dt { color: var(--texte-2); }
.detail dd { margin: 0; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }

/* ── Contrôles ───────────────────────────────────────────────────────────── */

button {
  font: inherit;
  cursor: pointer;
  border-radius: 6px;
  border: 1px solid var(--bord);
  transition: background 0.12s, border-color 0.12s;
}
button:disabled { opacity: 0.42; cursor: not-allowed; }

.primaire {
  width: 100%;
  padding: 9px;
  background: var(--accent);
  border-color: var(--accent);
  color: #06202b;
  font-weight: 600;
}
.primaire:hover:not(:disabled) { background: #7ad6f7; }

.secondaire { padding: 9px 12px; background: var(--fond-3); color: var(--texte); }
.secondaire:hover:not(:disabled) { background: #232b38; }

.rangee { display: flex; gap: 8px; margin-top: 8px; }
.rangee .primaire { flex: 1; }
.exports button { flex: 1; padding: 7px; font-size: 12.5px; }

.champ { display: block; margin-bottom: 11px; font-size: 12.5px; }
.champ > span { display: flex; justify-content: space-between; color: var(--texte-2); margin-bottom: 4px; }
.champ b { color: var(--texte); font-variant-numeric: tabular-nums; font-weight: 600; }

/* La zone cliquable (`height`, sur l'élément lui-même) est volontairement plus
   haute que la piste visible (4 px, sur les pseudo-éléments de piste) : à la
   souris personne ne remarque la différence, au doigt un pouce de 14 px sur
   une ligne de 4 px est sous les tailles tactiles recommandées (WCAG 2.5.5,
   24 px minimum). Mesuré sur l'app à 380 px de large — voir TODO.md. */
input[type=range] {
  width: 100%;
  height: 28px;
  padding: 0;
  margin: 0;
  appearance: none;
  background: transparent;
  outline: none;
  cursor: pointer;
}
/* Le curseur reste en place pendant la lecture de l'index, mais inerte : il
   doit le dire, comme le fait le bouton juste dessous. `opacity` sur
   l'élément lui-même dimme aussi ses pseudo-éléments de piste et de pouce. */
input[type=range]:disabled { cursor: not-allowed; opacity: 0.42; }
input[type=range]::-webkit-slider-runnable-track {
  height: 4px;
  background: var(--fond-3);
  border-radius: 2px;
}
input[type=range]::-moz-range-track {
  height: 4px;
  background: var(--fond-3);
  border-radius: 2px;
}
input[type=range]::-webkit-slider-thumb {
  appearance: none;
  width: 18px; height: 18px;
  margin-top: -7px;   /* recentre le pouce sur la piste de 4 px : -(18-4)/2 */
  border-radius: 50%;
  background: var(--accent);
  cursor: pointer;
  border: 2px solid var(--fond-2);
}
input[type=range]::-moz-range-thumb {
  width: 16px; height: 16px;
  border-radius: 50%;
  background: var(--accent);
  cursor: pointer;
  border: 2px solid var(--fond-2);
}

.case { display: flex; align-items: center; gap: 7px; font-size: 12.5px; color: var(--texte-2); margin-bottom: 9px; cursor: pointer; }
.case input { accent-color: var(--accent); }

.segments { display: grid; grid-template-columns: 1fr 1fr; gap: 5px; margin-bottom: 12px; }
.segments button {
  padding: 6px;
  font-size: 12px;
  background: var(--fond-3);
  color: var(--texte-2);
}
.segments button.actif { background: var(--accent); border-color: var(--accent); color: #06202b; font-weight: 600; }
/* Cinq couches de relief : la dernière occuperait une demi-ligne, autant lui
   donner toute la largeur plutôt qu'un trou à côté d'elle. */

.cout {
  background: var(--fond-3);
  border: 1px solid var(--bord);
  border-radius: 6px;
  padding: 8px 10px;
  font-size: 12px;
  color: var(--texte-2);
  font-variant-numeric: tabular-nums;
  line-height: 1.7;
}
.cout b { color: var(--texte); }
.cout .att { color: var(--or); }
.cout .doux { color: #6c7686; }

/* Le téléchargement est le moment le plus long de l'outil (une trentaine de
   secondes à pleine résolution) et, avant ceci, celui qui montrait le moins :
   un fil de 4 px sans texte, et un compteur qui ne défilait que dans le coin
   haut droit de l'en-tête — facile à ne jamais regarder. */
.progression { margin-top: 9px; }
.progression-piste {
  position: relative;
  height: 22px;
  background: var(--fond-3);
  border-radius: 6px;
  overflow: hidden;
}
#barre-progression { height: 100%; width: 0; background: var(--accent-2); transition: width 0.15s; }
.progression-pct {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--texte);
  /* Lisible aussi bien sur la piste vide que sur la barre remplie, sans
     synchroniser une couleur de texte avec l'avancement : une ombre portée
     plutôt qu'un habillage à deux états. */
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.85), 0 0 5px rgba(0, 0, 0, 0.6);
}
.progression-detail {
  margin-top: 6px;
  font-size: 12px;
  color: var(--texte-2);
  font-variant-numeric: tabular-nums;
}

.stats {
  margin-top: 11px;
  font-size: 11.5px;
  color: var(--texte-2);
  background: var(--fond-3);
  border-radius: 6px;
  padding: 8px 10px;
  line-height: 1.75;
  font-variant-numeric: tabular-nums;
}
.stats b { color: var(--texte); }

.reglages { display: grid; gap: 2px; }

.note { margin: 0 0 11px; font-size: 12px; color: var(--texte-2); line-height: 1.55; }
.note b { color: var(--texte); }

/* ── Recherche de lieu ───────────────────────────────────────────────────── */

.recherche { display: flex; gap: 6px; margin-bottom: 10px; }
.recherche input {
  flex: 1;
  min-width: 0;
  font: inherit;
  font-size: 12.5px;
  padding: 7px 10px;
  border-radius: 6px;
  border: 1px solid var(--bord);
  background: var(--fond-3);
  color: var(--texte);
}
.recherche input:focus { outline: none; border-color: var(--accent); }
.recherche input::placeholder { color: var(--texte-2); }
.recherche button { padding: 7px 11px; }

.suggestions { list-style: none; margin: 0 0 10px; padding: 0; }
.suggestions li {
  padding: 6px 10px;
  font-size: 12.5px;
  border: 1px solid var(--bord);
  border-radius: 6px;
  margin-bottom: 4px;
  cursor: pointer;
  background: var(--fond-3);
  color: var(--texte-2);
}
.suggestions li:hover { border-color: var(--accent); color: var(--texte); }

/* ── Légende / filtre des classes ────────────────────────────────────────── */

.legende { margin-top: 12px; }
.legende .echelle { font-size: 11px; color: var(--texte-2); margin-bottom: 9px; line-height: 1.5; }
.legende .titre-filtre {
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--texte-2);
  margin-bottom: 6px;
}
.legende button.cls {
  display: flex;
  align-items: center;
  gap: 7px;
  width: 100%;
  padding: 5px 8px;
  margin-bottom: 3px;
  font-size: 12px;
  text-align: left;
  background: var(--fond-3);
  color: var(--texte);
}
.legende button.cls:hover { background: #232b38; }
.legende button.cls b {
  margin-left: auto;
  font-weight: 500;
  color: var(--texte-2);
  font-variant-numeric: tabular-nums;
}
.legende button.cls i { width: 11px; height: 11px; border-radius: 2px; flex: none; }
/* Masquée : le nom est barré et tout s'éteint, mais la pastille de couleur
   reste lisible pour qu'on sache quoi rétablir. */
.legende button.cls.off { opacity: 0.42; }
.legende button.cls.off i { box-shadow: inset 0 0 0 99px rgba(11, 14, 19, 0.55); }
.legende button.cls.off span, .legende button.cls.off { text-decoration: line-through; }

/* ── Liste des résultats ─────────────────────────────────────────────────── */

/* Pas de `max-height` ni d'`overflow` ici : un conteneur défilant imbriqué dans
   le panneau piège la molette dès que le curseur le survole, et donne
   l'impression que le panneau ne défile plus. Le panneau est le seul à défiler. */
.liste { list-style: none; margin: 11px 0 0; padding: 0; }
.liste:empty { margin: 0; }
.liste li {
  border: 1px solid var(--bord);
  border-radius: 7px;
  padding: 8px 10px;
  margin-bottom: 6px;
  cursor: pointer;
  background: var(--fond-3);
  transition: border-color 0.12s;
}
.liste li:hover { border-color: var(--accent); }
.liste li.actif { border-color: var(--or); background: #1e2432; }
.liste li.repertorie { opacity: 0.5; }

.ligne-titre { display: flex; align-items: baseline; gap: 8px; }
.ligne-titre .rang { color: var(--texte-2); font-size: 11px; }
.ligne-titre .score { font-weight: 700; font-variant-numeric: tabular-nums; }
.ligne-titre .puce { width: 8px; height: 8px; border-radius: 50%; margin-left: auto; }

.mesures { font-size: 11.5px; color: var(--texte-2); font-variant-numeric: tabular-nums; margin-top: 3px; }
.coords { font-size: 11px; color: var(--texte-2); font-family: ui-monospace, "SF Mono", Menlo, monospace; margin-top: 3px; }
.actions { display: flex; gap: 9px; margin-top: 6px; font-size: 11.5px; }
.actions a { color: var(--accent); text-decoration: none; }
.actions a:hover { text-decoration: underline; }
.marque { font-size: 10.5px; color: var(--texte-2); border: 1px solid var(--bord); border-radius: 4px; padding: 0 5px; }
/* La voie qui a trouvé le candidat : lisible d'un coup d'œil, parce que les
   deux voies ne se règlent pas avec les mêmes seuils. */
.marque.voie { color: var(--accent); border-color: var(--accent); }

/* ── Divers ──────────────────────────────────────────────────────────────── */

.pied { padding: 14px 16px; font-size: 11px; color: var(--texte-2); line-height: 1.65; }
.pied a { color: var(--texte-2); }

.hud {
  position: absolute;
  left: 12px; bottom: 12px;
  background: rgba(11, 14, 19, 0.82);
  border: 1px solid var(--bord);
  border-radius: 6px;
  padding: 7px 11px;
  font-size: 11.5px;
  color: var(--texte-2);
  font-variant-numeric: tabular-nums;
  pointer-events: none;
  line-height: 1.6;
}

/* Boussole 3D. Le SVG laisse passer les gestes : seules les poignées répondent,
   sans quoi son carré volerait au canevas les glissés de son coin. */
.boussole {
  position: absolute;
  right: 12px; top: 12px;
  width: 92px; height: 92px;
  pointer-events: none;
  user-select: none;
}
.boussole .fond { fill: rgba(11, 14, 19, 0.72); stroke: var(--bord); stroke-width: 1; }
.boussole .horizon { fill: none; stroke: var(--bord); stroke-width: 1.3; }
.boussole .axe-vertical { stroke: var(--bord); stroke-width: 1.3; }

.boussole .poignee { pointer-events: auto; cursor: pointer; }
.boussole .poignee circle { fill: var(--fond-3); stroke: var(--bord); stroke-width: 1; }
.boussole .poignee text {
  fill: var(--texte-2);
  font-size: 12px;
  font-weight: 600;
  text-anchor: middle;
  dominant-baseline: central;
}
/* Le nord se repère sans être lu — c'est l'aiguille. */
.boussole .poignee.nord circle { fill: var(--or); stroke: var(--or); }
.boussole .poignee.nord text { fill: #06202b; }
/* De l'autre côté de la sphère : présent, lisible, mais en retrait. */
.boussole .poignee.loin { opacity: 0.45; }
.boussole .poignee:hover circle,
.boussole .poignee:focus-visible circle { stroke: var(--accent); stroke-width: 1.6; }
.boussole .poignee:not(.nord):hover text { fill: var(--texte); }
.boussole .poignee:focus { outline: none; }

/* Voile d'attente.
   La roue n'anime QUE `transform` : c'est ce qui permet au compositeur de la
   faire tourner sur son propre fil pendant qu'un calcul synchrone bloque le fil
   principal. Y ajouter une propriété qui demande un recalcul de style ou une
   mise en page la figerait — une roue arrêtée étant pire que pas de roue. */
.attente {
  position: fixed;
  inset: 0;
  z-index: 2500;
  display: grid;
  place-items: center;
  background: rgba(11, 14, 19, 0.66);
  cursor: progress;
}
.attente-boite {
  display: grid;
  justify-items: center;
  gap: 12px;
  padding: 22px 30px;
  background: var(--fond-2);
  border: 1px solid var(--bord);
  border-radius: 10px;
  box-shadow: 0 10px 34px rgba(0, 0, 0, 0.5);
  min-width: 230px;
}
.rotor {
  width: 32px; height: 32px;
  border-radius: 50%;
  border: 3px solid var(--fond-3);
  border-top-color: var(--accent);
  animation: rotor 0.85s linear infinite;
  will-change: transform;
}
@keyframes rotor { to { transform: rotate(360deg); } }

.attente .titre { font-size: 13.5px; color: var(--texte); }
.attente .detail-attente { font-size: 11.5px; color: var(--texte-2); min-height: 1em; }
.attente .detail-attente:empty { min-height: 0; }

.alerte {
  position: fixed;
  bottom: 18px;
  left: 50%;
  transform: translateX(-50%);
  background: var(--alerte);
  color: #fff;
  padding: 9px 18px;
  border-radius: 7px;
  font-size: 13px;
  z-index: 3000;
  max-width: 60vw;
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.45);
}

/* Leaflet : le thème clair par défaut jure avec le reste. */
.leaflet-container { background: #0e1116; font: inherit; }
.leaflet-control-layers, .leaflet-bar a, .leaflet-control-attribution {
  background: var(--fond-2) !important;
  color: var(--texte-2) !important;
  border-color: var(--bord) !important;
}
.leaflet-bar a { color: var(--texte) !important; }
.leaflet-control-attribution a { color: var(--accent) !important; }
.leaflet-tooltip {
  background: var(--fond-2);
  border: 1px solid var(--bord);
  color: var(--texte);
  box-shadow: none;
}
.leaflet-tooltip-top::before { border-top-color: var(--bord); }

/* Avis de zoom maximal. Discret — c'est une explication, pas une alerte — et
   posé en bas à gauche, le seul coin que Leaflet laisse libre : le zoom occupe
   le haut gauche, le sélecteur de couches le haut droit, l'attribution le bas
   droit. */
.avis-zoom {
  max-width: 260px;
  margin: 0 0 10px 10px !important;
  padding: 6px 9px;
  background: rgba(11, 14, 19, 0.86);
  border: 1px solid var(--bord);
  border-left: 3px solid var(--or);
  border-radius: 6px;
  color: var(--texte-2);
  font-size: 11.5px;
  line-height: 1.5;
  pointer-events: none;
}

@media (max-width: 900px) {
  /* Sous 900 px, le panneau (380 px) ne laisse plus de place à la scène — un
     empilement 45 %/55 % essayé d'abord ne réglait rien, la carte comme le
     nuage restant écrasés sur une bande de quelques centimètres. Le panneau
     devient donc un tiroir hors du flux de la grille (`position: fixed`),
     qui se pose *par-dessus* la scène au lieu de partager l'écran avec elle :
     `.grille` repasse à une seule colonne, entièrement pour la scène. */
  .grille { grid-template-columns: 1fr; }
  .btn-menu { display: flex; }

  /* Fermé par défaut, glissé hors écran plutôt que masqué par `hidden` : un
     `display: none` empêcherait toute transition d'ouverture. Sous l'accueil,
     le voile d'attente et les alertes (2000 et plus), au-dessus de la scène
     et du rideau d'arrière-plan. */
  .panneau {
    position: fixed;
    top: 46px;
    left: 0;
    bottom: 0;
    width: min(85vw, 380px);
    border-right: 1px solid var(--bord);
    z-index: 1500;
    transform: translateX(-100%);
    transition: transform 0.22s ease;
    box-shadow: 4px 0 24px rgba(0, 0, 0, 0.5);
  }
  .panneau.ouvert { transform: translateX(0); }

  /* Capte le clic pour refermer le tiroir et assombrit la scène pendant
     qu'il est ouvert. */
  .fond-panneau:not([hidden]) {
    display: block;
    position: fixed;
    top: 46px;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.5);
    z-index: 1400;
  }
}

/* Avis persistant : une capacité qui manque, et ce qui marche quand même. Il
   n'expire pas comme une alerte — le fait, lui, ne passe pas. */
.avis {
  margin: 12px 16px 0;
  padding: 9px 11px;
  border: 1px solid var(--bord);
  border-left: 3px solid var(--or);
  border-radius: 6px;
  background: var(--fond-3);
  font-size: 12px;
  line-height: 1.55;
  color: var(--texte-2);
}
.avis b { color: var(--texte); }
.avis-detail { display: block; margin-top: 4px; font-size: 11px; opacity: 0.75; }
.avis-detail:empty { display: none; }

/* ── Rideau de comparaison ───────────────────────────────────────────────────
   La bande sensible fait 22 px de large sur toute la hauteur du canevas : c'est
   ce qui dispense de viser la poignée, et c'est pourquoi le rideau ne se pose
   pas au clic. Le trait, lui, reste fin — c'est une ligne de comparaison, pas
   une séparation. */

.rideau {
  position: absolute;
  top: 0; bottom: 0;
  width: 22px;
  margin-left: -11px;
  cursor: col-resize;
  touch-action: none;
  z-index: 2;
}
/* Le trait, centré dans la bande. Doublé d'une ombre : il doit rester visible
   aussi bien sur une photo claire que sur un relief sombre. */
.rideau::before {
  content: "";
  position: absolute;
  left: 10px; top: 0; bottom: 0;
  width: 2px;
  background: #dbe1ea;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.5);
}
.rideau-poignee {
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: 30px; height: 30px;
  border-radius: 50%;
  background: rgba(11, 14, 19, 0.85);
  border: 2px solid #dbe1ea;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.5);
}
/* Deux chevrons, qui disent dans quel sens la poignée se tire. */
.rideau-poignee::before {
  content: "‹ ›";
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #dbe1ea;
  font-size: 13px;
  letter-spacing: -1px;
}
.rideau:hover .rideau-poignee, .rideau.tire .rideau-poignee { background: var(--accent); border-color: #fff; }
.rideau.tire .rideau-poignee::before { color: #06202b; }

/* Les deux sélecteurs de couche, côte à côte comme les deux moitiés de l'image. */
.deux-cotes { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.deux-cotes .champ { margin-bottom: 8px; }
select {
  width: 100%;
  font: inherit;
  font-size: 12.5px;
  padding: 6px 7px;
  color: var(--texte);
  background: var(--fond-3);
  border: 1px solid var(--bord);
  border-radius: 6px;
}
select:focus { outline: 1px solid var(--accent); }

/* ── Page d'accueil ──────────────────────────────────────────────────────────
   Un seul écran, une action dominante, et le même thème sombre que l'outil —
   une accueil claire suivie d'une application sombre fait un à-coup visuel, et
   le sombre est là pour une raison : on regarde ensuite un nuage de points sur
   fond noir.

   `display: grid` ici serait précisément le piège documenté en tête de fichier
   si la règle `[hidden] { display: none !important }` disparaissait : l'attribut
   `hidden` deviendrait sans effet et l'accueil ne se fermerait plus. */

/* Le reste de l'interface existe déjà dans le DOM et tourne — la carte est
   construite au chargement du script, avant même que l'accueil ne soit posé
   dessus. Tant que l'accueil est ouvert, elle doit rester invisible (elle
   transparaîtrait sous le voile, encombrée) et hors du clavier, sans qu'une
   ligne de JavaScript n'ait à le piloter : `#accueil` porte déjà l'attribut
   `hidden` que `masquerAccueil()` pose, sur le même principe que `data-vue`. */
#accueil:not([hidden]) ~ .barre,
#accueil:not([hidden]) ~ .grille .panneau,
#accueil:not([hidden]) ~ .grille .onglets {
  visibility: hidden;
}
/* La colonne du panneau (380px fixes) doit disparaître, pas seulement devenir
   invisible : sinon la carte qui sert de fond à l'accueil resterait décalée
   d'autant vers la droite, visible sur les trois quarts de l'écran seulement. */
#accueil:not([hidden]) ~ .grille {
  grid-template-columns: 0 1fr;
}

.accueil {
  position: fixed;
  inset: 0;
  /* Sous le voile d'attente (2500) et sous les alertes (3000) : rien ne se
     calcule tant que l'accueil est là, mais l'ordre doit rester juste. */
  z-index: 2000;
  /* Centrage par flex : un enfant `width: 100%; max-width: …` est borné par son
     conteneur quoi qu'il contienne, là où une colonne de grille `auto` se
     dimensionne, elle, sur son contenu. Précaution et non correction — mesuré
     dans un iframe de 380 px (la fenêtre de Chrome headless ne descend pas sous
     ~500 px, et son cliché rogné donnait l'illusion d'un débordement), les deux
     variantes tiennent aussi bien.
     `safe` garde le haut du texte visible quand la fenêtre est plus courte que
     la page. */
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: safe center;
  padding: clamp(14px, 3.5vh, 36px) 20px;
  /* Un voile, pas un aplat : la carte Leaflet tourne dessous et sert de fond —
     plus vraie et plus légère que le schéma dessiné qu'elle remplace. Piège à
     ne pas reproduire : un `background-color` opaque ici, même sous un
     `background-image` translucide, bloque entièrement ce qu'il y a derrière —
     les deux couches ne se mélangent qu'entre elles, jamais avec le contenu
     sous l'élément. Seul un dégradé dont aucun arrêt n'est opaque laisse
     passer la carte. Il assombrit davantage les bords que le centre, pour que
     les tuiles claires du fond ne viennent jamais rivaliser avec les coins de
     l'écran ; la carte de texte, elle, porte son propre fond quasi opaque et
     n'a besoin d'aucune aide au milieu. */
  background: radial-gradient(ellipse 85% 65% at 50% 42%,
    rgba(11, 14, 19, 0.55) 0%, rgba(11, 14, 19, 0.86) 100%);
  /* Soupape : la page est dimensionnée pour tenir sans défilement, mais une
     fenêtre très basse ne doit pas tronquer le texte pour autant. */
  overflow-y: auto;
}

/* La carte de texte flotte sur la carte géographique : fond quasi opaque pour
   rester lisible quel que soit ce qu'il y a dessous (tuile claire, zone bleue
   de couverture), `backdrop-filter` en confort visuel plutôt qu'en nécessité —
   sans lui la carte reste lisible, juste moins « posée ». */
.accueil-boite {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 14px;
  width: 100%;
  max-width: 620px;
  padding: clamp(26px, 4vh, 40px) clamp(22px, 5vw, 42px);
  background: rgba(15, 19, 26, 0.88);
  border: 1px solid var(--bord);
  border-radius: 16px;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  box-shadow: 0 24px 60px -20px rgba(0, 0, 0, 0.65);
}
.accueil-boite-texte { gap: 18px; }

.accueil-titre {
  margin: 0;
  font-size: clamp(23px, 4vw, 33px);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--accent);
  font-weight: 600;
}
.accueil-phrase {
  margin: 0;
  max-width: 48ch;
  font-size: clamp(14.5px, 2.1vw, 17.5px);
  line-height: 1.5;
}

.accueil-actions {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 16px;
  margin-top: 2px;
}
/* `.primaire` est pleine largeur dans le panneau ; ici c'est un bouton, et le
   seul élément coloré de l'écran. */
.accueil-agir {
  width: auto;
  padding: 12px 30px;
  font-size: 15.5px;
  border-radius: 8px;
}
.accueil-lien {
  background: transparent;
  border-color: transparent;
  color: var(--texte-2);
  padding: 12px 6px;
  font-size: 13.5px;
}
.accueil-lien:hover { color: var(--texte); text-decoration: underline; }

.accueil-limites {
  margin: 0;
  max-width: 64ch;
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--texte-2);
}
.accueil-criteres {
  margin: 0;
  padding-left: 18px;
  max-width: 62ch;
  text-align: left;
  font-size: 13px;
  line-height: 1.6;
  color: var(--texte-2);
}
.accueil-criteres b { color: var(--texte); font-weight: 600; }
.accueil-credit { margin: 0; font-size: 11.5px; color: var(--texte-2); }
.accueil-credit a { color: var(--texte-2); }
/* L'écran de l'exemple porte une phrase en titre, pas un nom : les capitales
   espacées du logotype la rendraient illisible. */
.accueil-titre-simple {
  text-transform: none;
  letter-spacing: 0;
  color: var(--texte);
  font-size: clamp(19px, 3vw, 25px);
}

/* Fenêtre basse : la carte perd du confort, pas de contenu — il n'y a plus de
   figure à céder, seulement moins de respiration autour du texte. */
@media (max-height: 760px) {
  .accueil-boite { gap: 10px; padding: 20px 24px; }
}
