/* Runa · feuille unique, aucune police distante, aucun CDN.
   Une maquette qui charge sa mise en forme depuis le réseau s'affiche nue
   dès qu'on est hors ligne, et c'est exactement ce qu'on veut éviter dans
   une app qu'on ouvre dehors. */

:root {
  color-scheme: dark;
  --fond: #101215;
  --carte: #0d0f12;
  --panneau: #171a1f;
  --case: #21262d;
  --case-active: #2c333c;
  --trait: #2a3038;
  --texte: #e8eaed;
  /* ⚠️ Était #8b9299, mesuré à 4,05:1 sur une carte de boucle : sous le
     seuil de 4,5 pour du texte de 13 px. Ce gris-ci donne 4,94 sur la
     surface la plus claire de l'app, et davantage partout ailleurs. */
  --gris: #9aa2aa;
  --vert: #6ee7a0;
  --rouge: #ff7b72;
  --jaune: #ffc457;
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

/* ⚠️ LA HAUTEUR DE LA PAGE, cinquième et, cette fois, dernière approche.

   Les quatre premières jouaient sur l'UNITÉ :
   · `height: 100%` sur `html` se résolvait sur le grand viewport, celui d'une
     barre d'adresse masquée : un ascenseur apparaissait sans que rien ne
     déborde (Pixel 9a sous Brave) ;
   · `100dvh` restait un ou deux pixels trop grand : ascenseur fantôme ;
   · `overflow: hidden` en plus a COUPÉ le bouton principal, inatteignable ;
   · `100svh` devait régler tout ça. Mais une règle `body { height: 100dvh }`
     placée juste en dessous l'écrasait : la correction n'a jamais atteint le
     corps de page, seulement `html`.

   Et le défaut revenait « à chaque mise à jour », disait-elle : à chaque
   version, le service worker fait recharger la page juste après son
   ouverture. Sur ce rechargement le téléphone calculait une hauteur plus
   grande que ce qu'il montrait, d'environ la barre de navigation. Le bas de
   la page passait dessous. Et rien ne pouvait le faire remonter : le panneau
   retient ses défilements (`overscroll-behavior: contain`) et la carte
   capture tous les gestes (`touch-action: none`). Le bouton « Trouver trois
   boucles » était coupé, sans aucun moyen de l'atteindre.

   On ne demande donc plus d'unité du tout. Le corps est FIXÉ aux quatre bords
   de la fenêtre : c'est le navigateur qui le dimensionne, sur ce qu'il
   affiche réellement, et il le refait de lui-même à chaque changement, y
   compris quand un rechargement règle ses marges après coup. */
html, body {
  margin: 0;
  overscroll-behavior: none;
}

body {
  background: #07090b;
  color: var(--texte);
  font: 16px/1.4 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  display: flex;
  flex-direction: column;
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  padding-top: env(safe-area-inset-top);

  /* ⚠️ Sur un écran large, l'app s'étirait sur toute la fenêtre : des
     boutons de durée de 278 px, un panneau de 1440 px de large et une carte
     écrasée en bandeau. Ça se lit comme une app cassée alors qu'elle
     fonctionne. Elle est dessinée pour un téléphone : elle garde donc une
     largeur de téléphone, centrée, quelle que soit la fenêtre. Avec les deux
     bords posés, `margin: auto` centre la colonne. */
  max-width: 460px;
  margin: 0 auto;
  box-shadow: 0 0 0 1px var(--trait);
}

/* Les éléments posés en absolu se repèrent sur le corps de page, donc sur la
   colonne centrée, et non sur la fenêtre entière. */
#etat, #installe { position: absolute; }

/* ---------------------------------------------------------------- carte */

#carte {
  /* Une base de 0 px, et non de 0 % : une base en pourcentage retombe sur la
     taille propre du canevas si la hauteur du parent n'est pas encore
     connue, et celle-ci vaut le DOUBLE de sa taille à l'écran sur un écran
     dense. La carte repoussait alors le panneau hors de la page. */
  flex: 1 1 0px;
  min-height: 0;          /* sans ça, la carte pousse le panneau dehors */
  width: 100%;
  display: block;
  touch-action: none;     /* on gère nous-mêmes le déplacement */
  background: var(--carte);
}

/* Le bandeau d'état doit être impossible à manquer pendant une attente d'une
   minute : sans lui, l'écran noir de la carte se lit comme une app plantée. */
#etat {
  position: absolute;
  top: calc(10px + env(safe-area-inset-top));
  left: 12px;
  right: 12px;
  background: rgba(23, 26, 31, .93);
  border: 1px solid var(--trait);
  border-radius: 10px;
  padding: 10px 12px;
  font-size: .88rem;
  color: var(--gris);
}
#etat[hidden] { display: none; }
#etat.erreur { color: var(--rouge); border-color: var(--rouge); }

/* La barre d'avancement. Sans elle, une minute d'attente sur une carte noire
   se lit comme une panne, et on ferme l'app. */
#etat-barre {
  display: block;
  height: 5px;
  margin-top: 9px;
  background: var(--case);
  border-radius: 3px;
  overflow: hidden;
}
#etat-barre[hidden] { display: none; }
#etat-barre i {
  display: block;
  height: 100%;
  width: 0;
  background: var(--vert);
  border-radius: 3px;
  transition: width .35s ease-out;
}
/* Avant le premier octet, Overpass prepare sa reponse et rien ne progresse :
   une barre figee a zero ferait croire a un blocage, une barre qui va et
   vient dit honnetement qu'on attend. */
#etat-barre.attente i {
  width: 40%;
  animation: va-et-vient 1.6s ease-in-out infinite;
}
/* Un va-et-vient perpétuel et une barre qui glisse sont exactement ce que
   « mouvement réduit » demande de couper. La barre reste, elle saute d'un
   état à l'autre au lieu de glisser. */
@media (prefers-reduced-motion: reduce) {
  #etat-barre i { transition: none; }
  #etat-barre.attente i { animation: none; width: 100%; opacity: .5; }
}

@keyframes va-et-vient {
  0%   { margin-left: -40%; }
  100% { margin-left: 100%; }
}

/* Le bandeau d'installation. ⚠️ La version precedente etait un bouton
   discret en bas de panneau : invisible en pratique, elle ne l'a pas vu.
   Un navigateur ne propose plus rien tout seul, donc c'est a l'app de le
   faire, et de le faire voir. */
#installe {
  position: absolute;
  top: calc(10px + env(safe-area-inset-top));
  left: 12px;
  right: 12px;
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--vert);
  color: #0d0f12;
  border-radius: 12px;
  padding: 8px 8px 8px 14px;
  box-shadow: 0 8px 24px rgba(0,0,0,.45);
}
#installe[hidden] { display: none; }
#installe .quoi { flex: 1; font-weight: 600; font-size: .95rem; }
#installe .oui {
  min-height: 44px; padding: 0 16px;
  border: 0; border-radius: 9px;
  background: #0d0f12; color: var(--vert);
  font-family: inherit;
  font-weight: 600;
  font-size: .95rem;
  line-height: 1;
}
#installe .non {
  width: 44px; height: 44px;
  border: 0; border-radius: 9px;
  background: transparent; color: #0d0f12;
  font-size: 1.05rem;
}

/* -------------------------------------------------------------- panneau */

#panneau {
  /* Et si un panneau devenait vraiment trop grand, c'est LUI qui défile,
     pas la page : rien ne devient inatteignable. En pourcentage de la page,
     pas en unité d'écran : c'est la page qu'il ne doit pas dépasser. */
  max-height: 82%;
  overflow-y: auto;
  overscroll-behavior: contain;
  background: var(--panneau);
  border-top: 1px solid var(--trait);
  padding: 12px 12px calc(12px + env(safe-area-inset-bottom));
  display: flex;
  flex-direction: column;
  gap: 10px;
  flex: 0 0 auto;
}

.titre {
  font-size: .7rem;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--gris);
  margin: 0;
}

/* Les durées : des options nommées et visibles, pas un curseur qu'il faut
   viser au pixel près à une main. */
.chips { display: flex; gap: 6px; }
/* ⚠️ `display: flex` bat la règle `[hidden]` du navigateur : sans cette
   ligne, les durées resteraient à l'écran quand on choisit une distance. */
.chips[hidden], #bloc-distance[hidden] { display: none; }

/* Distance ou durée : deux boutons, l'un est toujours choisi. */
.bascule {
  /* ⚠️ L'écran de réglages n'espace pas ses lignes : elles se touchent. Sans
     bordure ça ne se voit pas, mais la bascule et le champ (ou les durées)
     en ont chacun une, et les deux traits collés se lisaient comme un
     chevauchement d'un ou deux pixels. */
  margin-bottom: 8px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 4px;
  padding: 3px;
  background: var(--case);
  border: 1px solid var(--trait);
  border-radius: 12px;
}
.bascule button {
  min-height: 44px;
  border: 0;
  border-radius: 9px;
  background: transparent;
  color: var(--texte);
  font-family: inherit;
  font-weight: 600;
  font-size: .95rem;
}
.bascule button[aria-pressed="true"] { background: var(--vert); color: #0d0f12; }

/* La distance se tape : un seul champ, le clavier numérique, l'unité à côté.
   ⚠️ Exactement la hauteur d'une durée (46 px) : passer de l'un à l'autre
   faisait grandir puis rétrécir le panneau, champ de 56 px plus une ligne
   d'aide que la rangée de durées n'a pas. */
.champ {
  display: flex;
  align-items: center;
  gap: 8px;
  height: 46px;
  padding: 0 12px;
  background: var(--case);
  border: 1px solid var(--trait);
  border-radius: 10px;
  cursor: text;
}
.champ:focus-within { border-color: var(--vert); }
.champ input {
  width: 3.1em;
  min-width: 0;
  flex: 0 1 auto;
  border: 0;
  outline: 0;
  padding: 0;
  background: transparent;
  color: var(--texte);
  font-family: inherit;
  font-size: 1.15rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.champ .unite { font-size: .95rem; color: var(--gris); }
.champ .equiv { margin-left: auto; font-size: .82rem; color: var(--gris); white-space: nowrap; font-variant-numeric: tabular-nums; }
.champ.faux { border-color: var(--rouge); }
.champ.faux .equiv { color: var(--rouge); }
.chip {
  flex: 1;
  min-height: 46px;
  border: 1px solid var(--trait);
  background: var(--case);
  color: var(--texte);
  border-radius: 10px;
  font-family: inherit;
  font-weight: 600;
  font-size: .95rem;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.chip[aria-pressed="true"] {
  background: var(--vert);
  border-color: var(--vert);
  color: #0d0f12;
}

.ligne {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 48px;
}
.ligne .nom { flex: 1; }
.ligne .val {
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  min-width: 76px;
  text-align: right;
}
.rond {
  width: 46px; height: 46px;
  border-radius: 50%;
  border: 1px solid var(--trait);
  background: var(--case);
  color: var(--texte);
  font-size: 1.35rem;
  line-height: 1;
}

/* Une option est une ligne nommée avec une coche, pas un interrupteur muet :
   on doit lire ce qu'on active. */
.option {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 48px;
  width: 100%;
  background: none;
  border: 0;
  color: var(--texte);
  font: inherit;
  text-align: left;
  padding: 0;
}
.option .coche {
  width: 26px; height: 26px;
  flex: 0 0 26px;
  border-radius: 7px;
  border: 1px solid var(--trait);
  background: var(--case);
  display: grid;
  place-items: center;
  font-size: .95rem;
  color: transparent;
}
/* ⚠️ Deux de ces lignes ne cochent rien : elles ouvrent un écran. Elles
   avaient pourtant l'allure exacte d'un interrupteur, ce qu'un audit
   d'accessibilité relève aussi — elles n'annoncent aucun état parce
   qu'elles n'en ont pas. Le chevron dit « ça mène ailleurs », et il le dit
   par la FORME, pas par la couleur. */
.option .chevron {
  margin-left: auto;
  flex: 0 0 auto;
  color: var(--gris);
  font-size: 1.5rem;
  line-height: 1;
  padding-left: 4px;
}

/* L'étoile des favoris n'est pas une case à cocher : elle est toujours
   pleine, c'est une porte vers une liste. */
.coche.etoile { background: var(--case); border-color: var(--trait); color: var(--jaune); }
#ouvrir-favoris[hidden] { display: none; }

.option[aria-pressed="true"] .coche {
  background: var(--vert);
  border-color: var(--vert);
  color: #0d0f12;
}
.sous { display: block; font-size: .78rem; color: var(--gris); font-weight: 400; }
.sous.vieux { color: var(--jaune); }
.sous.faux { color: var(--rouge); }

button.principal {
  min-height: 54px;
  border: 0;
  border-radius: 12px;
  background: var(--vert);
  color: #0d0f12;
  font-family: inherit;
  font-weight: 700;
  font-size: 1rem;
  /* 1.2 et pas 1 : « Reprendre le parcours commencé il y a 45 min » passe
     sur deux lignes en 360 px, qui se touchaient à 1. */
  line-height: 1.2;
  padding: 6px 14px;
  width: 100%;
}
button.principal:disabled { opacity: .4; }

button.secondaire {
  min-height: 46px;
  border: 1px solid var(--trait);
  border-radius: 11px;
  background: var(--case);
  color: var(--texte);
  font-family: inherit;
  font-weight: 500;
  font-size: .95rem;
  line-height: 1;
  padding: 0 14px;
}

/* ------------------------------------------------------------ résultats */

#choix { display: flex; flex-direction: column; gap: 10px; }
#boucles { display: flex; flex-direction: column; gap: 8px; }

.boucle {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 62px;
  padding: 10px 10px;
  border: 1px solid var(--trait);
  border-radius: 12px;
  background: var(--case);
  color: var(--texte);
  font: inherit;
  text-align: left;
}
.boucle[aria-pressed="true"] {
  border-color: var(--vert);
  background: var(--case-active);
}
.boucle .km {
  font-size: 1.3rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  min-width: 78px;
}
.boucle .detail { flex: 1; font-size: .82rem; color: var(--gris); line-height: 1.35; }
.boucle .detail b { color: var(--texte); font-weight: 600; }
.boucle .puce {
  width: 12px; height: 12px; border-radius: 50%;
  border: 2px solid var(--trait);
}
.boucle[aria-pressed="true"] .puce { background: var(--vert); border-color: var(--vert); }

.rangee { display: flex; gap: 8px; margin-top: 8px; }
.rangee > * { flex: 1; }

.pied { font-size: .76rem; color: var(--gris); text-align: center; margin: 0; }
/* La meteo se lit au meme rang que le reste des reglages, alignee a gauche
   comme les lignes qu'elle complete, et non centree comme une note de bas
   de page. */
.pied.meteo { text-align: left; margin-top: -4px; }
.pied.meteo[hidden] { display: none; }
/* En course, ce qui reste à courir devient l'information principale de
   l'écran : c'est le seul chiffre qu'on lit en une seconde, bras tendu. */
#course { display: flex; flex-direction: column; gap: 10px; }
#course[hidden], #choix[hidden] { display: none; }

#suivi { margin: 0; font-size: 1.05rem; color: var(--gris); text-align: center; }
#suivi.dehors { color: var(--jaune); }
#suivi b {
  color: var(--texte);
  font-variant-numeric: tabular-nums;
  font-size: 2rem;
  font-weight: 700;
  display: block;
  line-height: 1.1;
  margin-bottom: 2px;
}

/* Le filet de sécurité : ce qui s'affiche quand le module principal n'a pas
   pu démarrer. Sans lui, l'app reste un HTML mort dont aucun bouton ne
   répond, et rien à l'écran ne dit pourquoi. */
#secours {
  position: fixed;
  left: 12px; right: 12px;
  bottom: calc(12px + env(safe-area-inset-bottom));
  z-index: 10;
  background: var(--panneau);
  border: 1px solid var(--rouge);
  border-radius: 12px;
  padding: 14px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
#secours[hidden] { display: none; }
#secours b { color: var(--rouge); font-size: .95rem; }
#secours button {
  min-height: 48px;
  border: 0; border-radius: 11px;
  background: var(--vert); color: #0d0f12;
  font-family: inherit;
  font-weight: 700;
  font-size: .95rem;
  line-height: 1;
}

/* ------------------------------------------------------- parcours gardés */

#mesparcours { display: flex; flex-direction: column; gap: 10px; }
#mesparcours[hidden] { display: none; }
#liste-favoris { display: flex; flex-direction: column; gap: 8px; }

.favori {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 62px;
  padding: 10px;
  border: 1px solid var(--trait);
  border-radius: 12px;
  background: var(--case);
}
.favori .ouvrir {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 12px;
  background: none;
  border: 0;
  color: var(--texte);
  font: inherit;
  text-align: left;
  min-height: 44px;
  padding: 0;
}
.favori .km {
  font-size: 1.3rem; font-weight: 700;
  font-variant-numeric: tabular-nums; min-width: 78px;
}
.favori .detail { font-size: .82rem; color: var(--gris); line-height: 1.35; }
.favori .detail b { color: var(--texte); font-weight: 600; }
.favori .jeter {
  width: 44px; height: 44px; flex: 0 0 44px;
  border: 0; border-radius: 10px;
  background: transparent; color: var(--gris);
  font-size: 1.05rem;
}

#garder[aria-pressed="true"] {
  border-color: var(--jaune);
  color: var(--jaune);
}

.vide { color: var(--gris); font-size: .88rem; font-style: italic; margin: 0; }

/* ------------------------------------------------- découverte et conquête */

/* Deux jeux, pas deux habillages : mesuré sur douze sorties, les boucles
   retenues par l'un et par l'autre ne se recouvrent qu'à 9 % en médiane. */
.onglets {
  display: flex;
  gap: 6px;
  background: var(--case);
  border-radius: 12px;
  padding: 4px;
  margin-bottom: 6px;
}
.ong {
  flex: 1;
  /* 44 px, la règle native, pas le minimum web de 24 px. Mesuré à 40. */
  min-height: 44px;
  border: 0;
  border-radius: 9px;
  background: transparent;
  color: var(--gris);
  font: inherit;
  font-weight: 600;
}
.ong[aria-selected="true"] {
  background: var(--fond);
  color: var(--texte);
  box-shadow: 0 1px 3px rgba(0, 0, 0, .4);
}
#mode-quoi { margin: 0; }
#mode-quoi[hidden] { display: none; }
#onglets[hidden] { display: none; }

/* La phrase qui remplace le popup d'accueil : même texte, mais lue au moment
   où elle sert, sans rien bloquer, et une seule fois. */
.note {
  margin: 0;
  font-size: .82rem;
  color: var(--texte);
  background: #1a2333;
  border-left: 3px solid #5b6bb0;
  padding: 9px 11px;
  border-radius: 0 8px 8px 0;
}
.note[hidden] { display: none; }
#recu b { color: #8ea2ff; }

/* La mise en garde reste affichée en permanence : une boucle part et revient
   de chez soi, donc le lien révèle l'adresse de qui l'envoie. Ça se dit
   avant, pas après. */
#partage-quoi { margin-top: -4px; }

/* Le score de la boucle selon le mode : c'est le critère qui manquait pour
   trancher entre trois boucles de même longueur. */
.score {
  display: block;
  color: #8ea2ff;
  font-weight: 600;
  margin-top: 2px;
}

/* Le parcours à retenir. Il arrive après les trois autres, quelques secondes
   plus tard : sans une marque qui le distingue, une carte qui apparaît toute
   seule ressemble à un défaut d'affichage. */
.boucle .marque {
  display: block;
  margin-top: 2px;
  font-size: .62rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--vert);
}
/* Les chevrons entre les rues sont de la ponctuation, pas du texte : ils ne
   doivent pas peser autant que les noms qu'ils séparent. */
.boucle .fleche { color: var(--trait2, #4a535e); font-weight: 700; }
/* La fleche d'amorce : elle dit « on rejoint la boucle ici », ce qui n'est
   pas la meme chose qu'un simple enchainement de rues. */
.boucle .vers { color: var(--vert); font-weight: 700; }
/* Le nombre de tours se lit AVANT de choisir : quatre tours d'un kilometre
   et une boucle unique de quatre ne sont pas la meme sortie. */
.boucle .tours { display: block; margin-top: 2px; color: var(--texte); font-weight: 600; }

/* -------------------------------------------------------- mon quartier */

#monquartier { display: flex; flex-direction: column; gap: 10px; }
#monquartier[hidden] { display: none; }
#ouvrir-quartier[hidden] { display: none; }
.coche.rond-plein { background: var(--case); border-color: var(--trait); color: #8ea2ff; }

.jauge { display: flex; flex-direction: column; gap: 8px; }
.chiffre { display: flex; align-items: baseline; gap: 8px; }
.chiffre b {
  font-size: 2.1rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: #8ea2ff;
}
.chiffre span { color: var(--gris); font-size: .9rem; }
.barre { height: 10px; background: var(--case); border-radius: 5px; overflow: hidden; }
.barre[hidden] { display: none; }
.barre i { display: block; height: 100%; background: #5b6bb0; border-radius: 5px; }
.detail-jauge { margin: 0; font-size: .82rem; color: var(--gris); }

.legende-carte { display: flex; gap: 16px; font-size: .78rem; color: var(--gris); }
.legende-carte span { display: flex; align-items: center; gap: 6px; }
.pastille { width: 14px; height: 3px; border-radius: 2px; display: inline-block; }
.pastille.faite { background: #5b6bb0; }
.pastille.terrain { background: rgba(91, 107, 176, .55); height: 10px; border-radius: 3px; }

/* La version, discrète mais lisible : sans elle, impossible de savoir
   téléphone en main si la mise à jour est bien arrivée. */
#version { opacity: .55; font-size: .7rem; margin-top: -4px; }

/* Reprendre une course interrompue : proposé sur l'écran d'accueil, jamais
   imposé à sa place. */
/* Aussi précis que `button.principal`, sinon il perd et sort du même vert. */
button.principal.reprendre { background: var(--jaune); color: #2a1e06; }
.reprendre[hidden] { display: none; }
