/* Poppins, la police de la maquette. SERVIE PAR NOUS et jamais appelee chez un
   tiers : VIVANT fonctionne hors ligne, une police distante la rendrait
   dependante du reseau pour s'afficher juste, et ferait fuiter l'adresse IP de
   chaque utilisateur a chaque ouverture. Quatre graisses, sous-ensemble latin,
   8 Ko piece. `swap` : le texte s'affiche tout de suite dans la police de
   secours plutot que de rester invisible le temps du chargement. */
@font-face {
  font-family: "Poppins"; font-style: normal; font-weight: 400; font-display: swap;
  src: url("polices/poppins-400.woff2") format("woff2");
}
@font-face {
  font-family: "Poppins"; font-style: normal; font-weight: 500; font-display: swap;
  src: url("polices/poppins-500.woff2") format("woff2");
}
@font-face {
  font-family: "Poppins"; font-style: normal; font-weight: 600; font-display: swap;
  src: url("polices/poppins-600.woff2") format("woff2");
}
@font-face {
  font-family: "Poppins"; font-style: normal; font-weight: 700; font-display: swap;
  src: url("polices/poppins-700.woff2") format("woff2");
}

/* VIVANT - carnet d'especes.
   Un instrument de terrain : lisible en plein soleil, sobre, une seule couleur
   d'accent, aucune decoration qui ne porte pas d'information. */

:root {
  color-scheme: dark light;

  --fond:            #0a1410;
  --fond-2:          #0e1c15;
  --surface:         #14261c;
  --surface-haute:   #1b3324;
  --bord:            #22402f;
  --bord-net:        #2f5540;

  --texte:           #eaf3ec;
  --texte-doux:      #a2bdaa;
  /* Eclairci apres MESURE : a #6f8a79 le rapport tombait a 4,22 sur la surface
     des cartes, sous le seuil de 4,5. La couleur convenait sur l ancien fond
     gris-sarcelle ; elle ne convenait plus sur le vert, qui est plus clair.
     Une bascule de palette se verifie au contraste, pas a l oeil. */
  --texte-faible:    #7f9b88;

  --accent:          #46c26d;
  --accent-sourd:    #1e4a2e;
  --accent-texte:    #06210f;

  /* L'or ne disparait pas : la maquette le garde pour les etoiles de
     rarete et les badges. Le vert dit « agis », l'or dit « ceci vaut ».
     Deux accents, mais deux FONCTIONS distinctes, jamais interchangeables. */
  --or:              #e0a63a;
  --or-sourd:        #7a5c22;

  /* Rarete : echelle ordinale a teinte unique, du neutre vers l'accent.
     La couleur porte le rang, pas une humeur. */
  --r1: #7c8683;
  --r2: #9d9a76;
  --r3: #bda85c;
  --r4: #d9b445;
  --r5: #f5c542;

  /* Statut UICN : couleurs de la nomenclature officielle, desaturees pour
     rester lisibles sur fond sombre. */
  --uicn-lc: #5aa469;
  --uicn-nt: #9fbf4a;
  --uicn-vu: #e0b93c;
  --uicn-en: #e0853c;
  --uicn-cr: #d95f5b;
  --uicn-nd: #7b8794;

  --rayon:    18px;
  --rayon-s:  12px;
  --rayon-pil: 999px;

  --pas: 0.35s cubic-bezier(0.16, 1, 0.3, 1);

  --police: "Poppins", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --mono: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, Consolas, monospace;
}

@media (prefers-color-scheme: light) {
  :root {
    --fond:          #f2f6f2;
    --fond-2:        #e7efe8;
    --surface:       #ffffff;
    --surface-haute: #ffffff;
    --bord:          #d8e4da;
    --bord-net:      #bcd0c1;
    --texte:         #141a1c;
    --texte-doux:    #52605c;
    --texte-faible:  #7d8a86;
    /* Le thème clair suit la même bascule : le vert devient l'action, l'or
       reste la valeur. Assombri par rapport au vert du thème sombre, sinon il
       ne passe pas le contraste requis sur un fond presque blanc. */
    --accent:        #1e7a41;
    --accent-sourd:  #cce8d5;
    --accent-texte:  #ffffff;
    --or:            #a2701a;
    --or-sourd:      #e8d4a8;
    --r1: #7c8683; --r2: #8a8455; --r3: #a08631; --r4: #8f6d1c; --r5: #7a5710;
  }
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--fond);
  color: var(--texte);
  font-family: var(--police);
  -webkit-font-smoothing: antialiased;
  overscroll-behavior-y: none;
}

body {
  min-height: 100dvh;
  padding-bottom: calc(64px + env(safe-area-inset-bottom));
}

button { font: inherit; color: inherit; cursor: pointer; }
img { max-width: 100%; display: block; }

.mono { font-family: var(--mono); font-variant-numeric: tabular-nums; }

/* ---------------------------------------------------------------- entete */

.entete {
  position: sticky;
  top: 0;
  z-index: 20;
  background: color-mix(in srgb, var(--fond) 88%, transparent);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--bord);
  padding: calc(10px + env(safe-area-inset-top)) 16px 10px;
}

.entete-ligne {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}

.marque {
  font-size: 15px;
  font-weight: 620;
  letter-spacing: 0.16em;
  margin: 0;
}

.compteur {
  font-family: var(--mono);
  font-size: 13px;
  color: var(--texte-doux);
}
.compteur b { color: var(--accent); font-weight: 600; }

.jauge {
  height: 3px;
  margin-top: 9px;
  border-radius: var(--rayon-pil);
  background: var(--bord);
  overflow: hidden;
}
.jauge span {
  display: block;
  height: 100%;
  background: var(--accent);
  transition: width 0.7s cubic-bezier(0.16, 1, 0.3, 1);
}

/* --------------------------------------------------------------- filtres */

.barre-outils { padding: 12px 16px 4px; display: grid; gap: 10px; }

.recherche {
  display: flex;
  align-items: center;
  gap: 9px;
  background: var(--surface);
  border: 1px solid var(--bord);
  border-radius: var(--rayon);
  padding: 0 12px;
}
.recherche img { width: 17px; height: 17px; opacity: 0.55; flex: none; }
.recherche input {
  flex: 1;
  border: 0;
  outline: 0;
  background: transparent;
  color: var(--texte);
  font: inherit;
  padding: 11px 0;
  min-width: 0;
}
.recherche input::placeholder { color: var(--texte-faible); }
.recherche:focus-within { border-color: var(--accent); }

.rangee-puces {
  display: flex;
  gap: 7px;
  overflow-x: auto;
  scrollbar-width: none;
  padding-bottom: 2px;
  scroll-snap-type: x proximity;
}
.rangee-puces::-webkit-scrollbar { display: none; }

.puce {
  flex: none;
  scroll-snap-align: start;
  background: var(--surface);
  border: 1px solid var(--bord);
  border-radius: var(--rayon-pil);
  padding: 7px 13px;
  font-size: 13px;
  color: var(--texte-doux);
  white-space: nowrap;
  transition: background var(--pas), color var(--pas), border-color var(--pas);
}
.puce[aria-pressed="true"] {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-texte);
  font-weight: 600;
}

/* ------------------------------------------------------------ grille dex */

.grille {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
  padding: 12px 16px 24px;
}
@media (min-width: 560px) { .grille { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 860px) {
  .grille { grid-template-columns: repeat(4, 1fr); max-width: 1100px; margin: 0 auto; }
}

.carte {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--bord);
  border-radius: var(--rayon);
  overflow: hidden;
  text-align: left;
  padding: 0;
  display: flex;
  flex-direction: column;
  transition: transform 0.18s ease, border-color var(--pas);
}
.carte:active { transform: scale(0.975); }
.carte.vue { border-color: var(--accent-sourd); }

.vignette {
  aspect-ratio: 1 / 1;
  background: var(--fond-2);
  position: relative;
  overflow: hidden;
}
.vignette img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Espece non observee : la vraie photo, floutee et desaturee. On percoit une
   masse et une posture, pas une identite. Un aplat noir n'apprendrait rien et
   ne donnerait envie de rien. */
.carte:not(.vue) .vignette img {
  filter: grayscale(1) contrast(1.15) brightness(0.55) blur(9px);
  transform: scale(1.15); /* evite les bords transparents laisses par le flou */
}
.carte:not(.vue) .vignette::after {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at 50% 45%,
              transparent 30%, color-mix(in srgb, var(--fond) 55%, transparent));
}

.numero {
  position: absolute;
  top: 7px;
  left: 7px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.04em;
  color: var(--texte-doux);
  background: color-mix(in srgb, var(--fond) 78%, transparent);
  border-radius: var(--rayon-s);
  padding: 3px 6px;
}

.cadenas {
  position: absolute;
  right: 7px;
  bottom: 7px;
  width: 16px;
  height: 16px;
  opacity: 0.4;
}

.corps-carte { padding: 9px 10px 11px; display: grid; gap: 3px; }

.nom {
  font-size: 13.5px;
  font-weight: 560;
  line-height: 1.25;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.carte:not(.vue) .nom { color: var(--texte-doux); }

.latin {
  font-size: 11px;
  font-style: italic;
  color: var(--texte-faible);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  line-height: 1.3;
  padding-bottom: 1px;
}

.rarete { font-size: 10.5px; letter-spacing: 0.07em; text-transform: uppercase; font-weight: 600; }

/* Dans la clé de détermination, la photo doit être NETTE : on demande à
   l'observateur de reconnaître l'animal, la masquer viderait l'écran de son
   sens. Et la justification chiffrée se lit, elle ne se crie pas. */
.carte.cle .vignette img { filter: none; transform: none; }
.carte.cle .vignette::after { display: none; }
/* Le nom est ce qu'on vient chercher : il se lit en entier, quitte a prendre
   deux lignes. « Moineau domestiq... » ne sert a personne. */
.carte.cle .nom, .carte.cle .latin {
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
}
.carte.cle .presence {
  font-size: 11px;
  color: var(--texte-doux);
  line-height: 1.35;
  font-variant-numeric: tabular-nums;
}
.r-commune     { color: var(--r1); }
.r-frequente   { color: var(--r2); }
.r-peu-commune { color: var(--r3); }
.r-rare        { color: var(--r4); }
.r-tres-rare   { color: var(--r5); }

/* ----------------------------------------------------------------- fiche */

.fiche {
  position: fixed;
  inset: 0;
  z-index: 60;
  background: var(--fond);
  overflow-y: auto;
  overscroll-behavior: contain;
}

.fiche-image {
  position: relative;
  aspect-ratio: 4 / 3;
  background: var(--fond-2);
}
.fiche-image img { width: 100%; height: 100%; object-fit: cover; }
.fiche-image::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 45%;
  background: linear-gradient(to top, var(--fond), transparent);
  pointer-events: none;
}

.retour {
  position: absolute;
  top: calc(12px + env(safe-area-inset-top));
  left: 12px;
  z-index: 2;
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  border: 1px solid var(--bord-net);
  border-radius: var(--rayon-pil);
  background: color-mix(in srgb, var(--fond) 76%, transparent);
  backdrop-filter: blur(8px);
}
.retour img { width: 18px; height: 18px; }

.fiche-corps { padding: 0 18px 40px; margin-top: -34px; position: relative; }

.fiche-titre { font-size: 25px; font-weight: 640; margin: 0 0 2px; line-height: 1.15; }
.fiche-latin { font-style: italic; color: var(--texte-doux); margin: 0 0 14px; font-size: 14px; }

.etiquettes { display: flex; flex-wrap: wrap; gap: 7px; margin-bottom: 18px; }
.etiquette {
  font-size: 11.5px;
  border: 1px solid var(--bord-net);
  border-radius: var(--rayon-pil);
  padding: 4px 10px;
  color: var(--texte-doux);
}
.etiquette.uicn { border-color: currentColor; font-weight: 600; }
.u-LC { color: var(--uicn-lc); } .u-NT { color: var(--uicn-nt); }
.u-VU { color: var(--uicn-vu); } .u-EN { color: var(--uicn-en); }
.u-CR { color: var(--uicn-cr); } .u-nd { color: var(--uicn-nd); }

.section-titre {
  font-size: 12px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--texte-faible);
  margin: 26px 0 10px;
  font-weight: 600;
}

.texte { line-height: 1.65; color: var(--texte-doux); font-size: 14.5px; margin: 0; }
.texte a { color: var(--accent); }

.tableau { display: grid; gap: 0; }
.tableau div {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  padding: 10px 0;
  font-size: 14px;
}
.tableau div + div { border-top: 1px solid var(--bord); }
.tableau dt, .tableau .cle { color: var(--texte-faible); }
.tableau .valeur { text-align: right; }

.retirer {
  background: none;
  border: 0;
  padding: 0 0 0 12px;
  display: grid;
  place-items: center;
  opacity: 0.45;
  transition: opacity var(--pas);
}
.retirer:hover, .retirer:focus-visible { opacity: 1; }
.retirer img { width: 15px; height: 15px; }
.retirer[disabled] { opacity: 0.2; }

.credit { font-size: 11px; color: var(--texte-faible); margin-top: 26px; line-height: 1.5; }
.credit a { color: var(--texte-doux); }

/* ------------------------------------------------------- identification */

.ecran { padding: 16px 16px 32px; max-width: 640px; margin: 0 auto; }

.zone-capture {
  border: 1px dashed var(--bord-net);
  border-radius: var(--rayon);
  background: var(--surface);
  padding: 34px 20px;
  text-align: center;
  display: grid;
  justify-items: center;
  gap: 12px;
}
.zone-capture img.pictogramme { width: 34px; height: 34px; opacity: 0.5; }
.zone-capture p { margin: 0; color: var(--texte-doux); font-size: 14px; line-height: 1.5; }

.apercu { border-radius: var(--rayon); overflow: hidden; border: 1px solid var(--bord); }
.apercu img { width: 100%; max-height: 46dvh; object-fit: cover; }

.bouton {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  padding: 14px 18px;
  border: 1px solid var(--accent);
  border-radius: var(--rayon);
  background: var(--accent);
  color: var(--accent-texte);
  font-weight: 620;
  font-size: 15px;
  white-space: nowrap;
  transition: transform 0.12s ease, opacity var(--pas);
}
.bouton:active { transform: translateY(1px); }
/* Anneau de focus AUX COULEURS DU PRODUIT. Le navigateur en pose deja un, et il
   ne faut surtout pas le supprimer : c est le seul repere de la navigation au
   clavier. Mais son blanc par defaut, sur une interface verte, se lit comme un
   artefact. On le remplace, on ne l enleve pas. */
.bouton:focus-visible,
.nav button:focus-visible,
.puce:focus-visible {
  outline: 2px solid var(--texte);
  outline-offset: 3px;
  border-radius: var(--rayon);
}
.bouton[disabled] { opacity: 0.5; cursor: not-allowed; }
.bouton.sobre {
  background: transparent;
  color: var(--texte);
  border-color: var(--bord-net);
}
.bouton.danger { background: transparent; border-color: var(--uicn-cr); color: var(--uicn-cr); }
.bouton img { width: 18px; height: 18px; }

.pile { display: grid; gap: 12px; margin-top: 16px; }

.etape {
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--texte-doux);
  font-size: 14px;
  padding: 11px 0;
}
.etape .pastille {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--bord-net); flex: none;
}
.etape.active .pastille { background: var(--accent); }
.etape.active { color: var(--texte); }
.etape.faite .pastille { background: var(--uicn-lc); }

/* Squelette de chargement : la forme du resultat attendu, pas un tourniquet. */
.squelette {
  background: linear-gradient(100deg, var(--surface) 30%, var(--surface-haute) 50%, var(--surface) 70%);
  background-size: 220% 100%;
  border-radius: var(--rayon);
  animation: glisse 1.5s linear infinite;
}
@keyframes glisse { to { background-position: -220% 0; } }

.candidat {
  display: grid;
  grid-template-columns: 62px 1fr;
  gap: 12px;
  align-items: center;
  width: 100%;
  text-align: left;
  background: var(--surface);
  border: 1px solid var(--bord);
  border-radius: var(--rayon);
  padding: 11px;
  transition: border-color var(--pas), background var(--pas);
}
.candidat[aria-pressed="true"] { border-color: var(--accent); background: var(--surface-haute); }
.candidat .miniature {
  width: 62px; height: 62px; border-radius: var(--rayon-s);
  object-fit: cover; background: var(--fond-2);
}
.candidat .nom { font-size: 15px; white-space: normal; }
.candidat .raisons { font-size: 12px; color: var(--texte-faible); line-height: 1.45; margin-top: 3px; }

.mesure { display: flex; align-items: center; gap: 8px; margin-top: 6px; }
.mesure .barre { flex: 1; height: 4px; border-radius: var(--rayon-pil); background: var(--bord); overflow: hidden; }
.mesure .barre span { display: block; height: 100%; background: var(--accent); }
.mesure .valeur { font-family: var(--mono); font-size: 12px; color: var(--texte-doux); }

.avis {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  border: 1px solid var(--bord-net);
  border-left: 2px solid var(--accent);
  border-radius: var(--rayon-s);
  padding: 12px 13px;
  font-size: 13px;
  line-height: 1.55;
  color: var(--texte-doux);
  background: var(--surface);
}
.avis img { width: 17px; height: 17px; flex: none; margin-top: 1px; opacity: 0.7; }

.vide {
  text-align: center;
  padding: 54px 24px;
  color: var(--texte-faible);
  display: grid;
  justify-items: center;
  gap: 12px;
}
.vide img { width: 30px; height: 30px; opacity: 0.35; }
.vide p { margin: 0; font-size: 14px; line-height: 1.6; max-width: 34ch; }

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

#carte { height: calc(100dvh - 64px - 62px); width: 100%; background: var(--fond-2); }
.leaflet-container { background: var(--fond-2); font-family: var(--police); }

/* ------------------------------------------------------- carte en sombre */
/* Voir l'en-tete de tmp/carte_sombre.py pour le raisonnement complet : on
   filtre les TUILES, jamais le conteneur, et seulement en theme sombre. */
@media (prefers-color-scheme: dark) {
  .leaflet-tile-pane {
    filter: invert(1) hue-rotate(180deg) brightness(0.92) contrast(0.88) saturate(0.62);
  }
  /* L'attribution devient claire sur sombre. Elle n'est PAS decorative :
     OpenStreetMap l'exige, et la masquer serait un manquement a sa licence. */
  .leaflet-control-attribution {
    background: color-mix(in srgb, var(--fond) 78%, transparent);
    color: var(--texte-doux);
    border-radius: var(--rayon-s) 0 0 0;
  }
  .leaflet-control-attribution a { color: var(--texte); }
  /* Les commandes de zoom, laissees claires, tranchaient comme deux timbres
     blancs sur une carte devenue sombre. */
  .leaflet-bar a {
    background: var(--surface);
    color: var(--texte);
    border-bottom-color: var(--bord);
  }
  .leaflet-bar a:hover { background: var(--surface-haute); }
}
.marqueur-obs {
  background: var(--accent);
  border: 2px solid var(--fond);
  border-radius: 50%;
  width: 14px; height: 14px;
  box-shadow: 0 0 0 1px var(--accent-sourd);
}

/* ------------------------------------------------------------ navigation */

.nav {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 40;
  display: grid;
  /* Le nombre de colonnes suit le nombre d'onglets. Il etait fige a 3 : le
     quatrieme ("Ici") passait a la ligne et la barre mangeait deux fois plus
     de hauteur. `auto-fit` evite d'avoir a corriger cette valeur a chaque
     onglet ajoute. */
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  background: color-mix(in srgb, var(--fond) 92%, transparent);
  backdrop-filter: blur(14px);
  border-top: 1px solid var(--bord);
  padding-bottom: env(safe-area-inset-bottom);
}
.nav button {
  background: none;
  border: 0;
  padding: 9px 0 10px;
  display: grid;
  justify-items: center;
  gap: 3px;
  color: var(--texte-faible);
  font-size: 10.5px;
  letter-spacing: 0.03em;
}
.nav button img { width: 22px; height: 22px; opacity: 0.65; }
.nav button[aria-current="page"] { color: var(--accent); }
.nav button[aria-current="page"] img { opacity: 1; }

/* Les icones sont des fichiers SVG noirs : ce filtre les repeint a la
   couleur du texte courant, sans dupliquer chaque glyphe par theme. */
.icone { filter: invert(88%) sepia(6%) saturate(180%) hue-rotate(120deg); }
@media (prefers-color-scheme: light) { .icone { filter: none; } }

/* Sur le bouton principal, l'icone doit suivre la couleur du texte du bouton,
   pas celle de la page : en theme clair le texte est blanc sur ambre, une
   icone noire y ferait tache et perdrait en lisibilite. */
.bouton:not(.sobre):not(.danger) .icone { filter: none; }
@media (prefers-color-scheme: light) {
  .bouton:not(.sobre):not(.danger) .icone { filter: invert(1); }
}
/* Les icônes de la barre sont des <img>, donc leur `currentColor` ne reçoit
   PAS la couleur du bouton : seul un filtre peut les teinter. Cette chaîne
   était réglée pour l'ancien accent doré (`hue-rotate(2deg)`), si bien qu'après
   le passage au vert l'onglet actif affichait un libellé vert sous une icône
   restée dorée. Les valeurs ci-dessous ont été RÉGLÉES PAR MESURE du pixel
   rendu, pas estimées : viser une couleur à travers une chaîne de filtres à
   l'œil ne converge pas. */
.nav button[aria-current="page"] .icone {
  filter: invert(63%) sepia(42%) saturate(560%) hue-rotate(93deg) brightness(96%);
}

.brindille { text-align: center; color: var(--texte-faible); font-size: 12px; padding: 18px; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}

/* --------------------------------------------------------- ici, maintenant */

/* Le nombre porte tout le message : c'est lui qu'on lit en une fraction de
   seconde avant de decider de sortir ou non. */
.mission {
  display: flex;
  align-items: center;
  gap: 16px;
  background: var(--surface);
  border: 1px solid var(--bord);
  border-radius: var(--rayon);
  padding: 18px 20px;
  margin-bottom: 18px;
}
.mission-nombre {
  font-size: 40px;
  font-weight: 700;
  line-height: 1;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}
.mission-titre { font-size: 15px; line-height: 1.35; }
.mission .brindille { text-align: left; padding: 6px 0 0; }

/* Sur cet ecran l'espece n'est PAS masquee : on ne cache pas ce qu'on propose
   d'aller chercher. La vignette reste donc nette, contrairement au carnet.
   Les selecteurs reprennent EXACTEMENT la forme de ceux du carnet
   (`.carte:not(.vue) ...`) avec une classe de plus : sans cela ils ont une
   specificite plus faible et le flou du carnet l'emporte silencieusement. */
.carte.carte-ici:not(.vue) .vignette img { filter: none; }
.carte.carte-ici:not(.vue) .vignette::after { content: none; }
.carte.carte-ici:not(.vue) .nom { color: var(--texte); }
.carte-ici .corps-carte .latin { font-style: normal; }

/* ------------------------------------------------------ premiere rencontre */

.sacre {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: grid;
  place-items: center;
  padding: 24px;
  background: rgb(0 0 0 / .72);
  animation: sacre-fondu .22s ease-out;
}
.sacre-carte {
  width: 100%;
  max-width: 330px;
  text-align: center;
  background: var(--surface);
  border: 1px solid var(--bord-net);
  border-radius: var(--rayon);
  padding: 26px 22px;
  animation: sacre-monte .3s cubic-bezier(.2,.8,.2,1);
}
.sacre-sur {
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 14px;
}
.sacre-image {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: var(--rayon);
  margin-bottom: 14px;
}
.sacre-numero { color: var(--texte-faible); font-size: 13px; }
.sacre-carte h2 { font-size: 21px; margin: 2px 0 2px; }
.sacre-carte .latin { color: var(--texte-doux); font-size: 13.5px; font-style: italic; }
.sacre-carte .rarete { display: inline-block; margin: 12px 0 10px; }
.sacre-carte .bouton { width: 100%; justify-content: center; }

@keyframes sacre-fondu { from { opacity: 0 } to { opacity: 1 } }
@keyframes sacre-monte {
  from { opacity: 0; transform: translateY(14px) scale(.97) }
  to   { opacity: 1; transform: none }
}
.sacre-note { color: var(--texte-doux); font-size: 13px; margin: 0 0 14px; }

/* ------------------------------------------------------------------ radar */

.bandeau-score {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  background: var(--surface);
  border: 1px solid var(--bord);
  border-radius: var(--rayon);
  padding: 12px 16px;
  margin-bottom: 12px;
}
.score-points { font-size: 27px; font-weight: 700; color: var(--accent); line-height: 1; }
.score-unite { font-size: 12px; color: var(--texte-faible); margin-left: 6px; }
.score-rang { text-align: right; font-size: 13.5px; font-weight: 600; }

.radar-tete {
  display: flex;
  align-items: center;
  gap: 16px;
  background: var(--surface);
  border: 1px solid var(--bord);
  border-radius: var(--rayon);
  padding: 16px;
  margin-bottom: 16px;
}

/* Le balayage n'est pas de la decoration gratuite : il dit que la lecture est
   liee a un LIEU et a un INSTANT, pas a un catalogue fige. */
.radar-oeil {
  position: relative;
  flex: none;
  width: 62px;
  height: 62px;
  border-radius: 50%;
  border: 1px solid var(--bord-net);
  background:
    radial-gradient(circle, transparent 30%, color-mix(in srgb, var(--accent) 8%, transparent) 31%, transparent 32%),
    radial-gradient(circle, transparent 60%, color-mix(in srgb, var(--accent) 8%, transparent) 61%, transparent 62%);
  overflow: hidden;
}
.radar-balayage {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: conic-gradient(from 0deg,
              color-mix(in srgb, var(--accent) 42%, transparent) 0deg,
              transparent 70deg);
  animation: balayage 3.2s linear infinite;
}
.radar-centre {
  position: absolute;
  top: 50%; left: 50%;
  width: 6px; height: 6px;
  margin: -3px 0 0 -3px;
  border-radius: 50%;
  background: var(--accent);
}
@keyframes balayage { to { transform: rotate(360deg); } }

/* Valeur de l'espece, lisible sur la vignette : c'est la raison d'y aller. */
.prix {
  position: absolute;
  right: 7px;
  top: 7px;
  font-size: 11.5px;
  font-weight: 700;
  color: var(--accent-texte);
  background: var(--accent);
  border-radius: var(--rayon-s);
  padding: 3px 7px;
}

/* ---------------------------------------------------------------- astuces */

.fiche-tete {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 14px;
}
.prix-fiche {
  font-size: 15px;
  font-weight: 700;
  color: var(--accent-texte);
  background: var(--accent);
  border-radius: var(--rayon-pil);
  padding: 5px 13px;
}
.astuce {
  background: var(--surface);
  border: 1px solid var(--bord);
  border-radius: var(--rayon);
  padding: 14px 16px;
  margin-top: 10px;
}
.astuce h3 { font-size: 14.5px; margin: 0 0 5px; }
.astuce p { font-size: 14px; line-height: 1.45; margin: 0; color: var(--texte-doux); }
/* La source est ce qui distingue un conseil d'une opinion : elle est toujours
   visible, jamais repliee derriere un geste. */
.astuce .source {
  margin-top: 9px;
  font-size: 11.5px;
  color: var(--texte-faible);
  font-style: italic;
}
.astuce--contexte { border-style: dashed; }

/* ---------------------------------------------------------------- terrain */

/* La carte est l'ecran d'accueil : elle repond a « ou je vais », la grille ne
   repond qu'a « qu'est-ce qui existe ». */
.terrain { margin-bottom: 16px; }
#carte-terrain {
  height: 46vh;
  min-height: 260px;
  border-radius: var(--rayon);
  border: 1px solid var(--bord);
  overflow: hidden;
  background: var(--surface);
}
.terrain-note {
  color: var(--texte-faible);
  font-size: 12px;
  line-height: 1.45;
  padding: 9px 2px 0;
}

/* Portee : rend les 50 km lisibles au lieu de les laisser deviner. */
.portee {
  stroke: var(--accent);
  stroke-opacity: .35;
  stroke-dasharray: 5 6;
  fill: var(--accent);
  fill-opacity: .05;
}

/* Position de l'observateur. Un seul point, sans halo clignotant : le
   clignotement attire l'oeil sur soi alors que l'interet est autour. */
.moi span {
  display: block;
  width: 16px; height: 16px;
  margin: 3px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent) 28%, transparent);
}

/* Jeton d'espece. L'anneau porte la rarete : la couleur est la MEME echelle
   ordinale que dans le carnet, pour qu'on n'ait pas deux langages a apprendre. */
.jeton { background: none; border: 0; }
.jeton-corps {
  display: block;
  position: relative;
  width: 54px; height: 54px;
  border-radius: 50%;
  overflow: visible;
  border: 3px solid var(--r1);
  background: var(--surface);
  box-shadow: 0 3px 10px rgb(0 0 0 / .35);
  transition: transform .16s ease;
}
.jeton-corps img {
  width: 100%; height: 100%;
  border-radius: 50%;
  object-fit: cover;
}
.jeton-muet {
  display: block; width: 100%; height: 100%;
  border-radius: 50%;
  background: var(--fond-2);
}
.jeton:hover .jeton-corps,
.jeton:focus-visible .jeton-corps { transform: scale(1.12); }

.jeton--r1 .jeton-corps { border-color: var(--r1); }
.jeton--r2 .jeton-corps { border-color: var(--r2); }
.jeton--r3 .jeton-corps { border-color: var(--r3); }
.jeton--r4 .jeton-corps { border-color: var(--r4); }
/* Seule la plus haute rarete recoit un halo. Un halo sur tout n'attire plus
   sur rien, et c'est exactement ce qu'on veut faire remarquer. */
.jeton--r5 .jeton-corps {
  border-color: var(--r5);
  box-shadow: 0 3px 10px rgb(0 0 0 / .35),
              0 0 0 4px color-mix(in srgb, var(--r5) 30%, transparent);
}

.jeton-prix {
  position: absolute;
  bottom: -7px; left: 50%;
  transform: translateX(-50%);
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 700;
  color: var(--accent-texte);
  background: var(--accent);
  border-radius: var(--rayon-pil);
  padding: 1px 6px;
  white-space: nowrap;
}

/* Le fond de carte OSM est clair : en theme sombre il jure avec tout le reste.
   On le desature et on l'assombrit plutot que d'imposer un theme clair a la
   seule carte. */
@media (prefers-color-scheme: dark) {
  /* Le radar reçoit LE MÊME traitement que la carte plein écran. Il gardait
     son propre filtre, réglé pour l'ancienne palette : sur le vert profond, il
     formait un rectangle gris clair au milieu d'un écran sombre, et
     l'application montrait deux cartes dans deux langages différents.
     Une seule application, un seul traitement de carte. */
  #carte-terrain .leaflet-tile-pane {
    filter: invert(1) hue-rotate(180deg) brightness(0.92) contrast(0.88) saturate(0.62);
  }
}

/* ---------------------------------------------------------------- accueil */

.accueil {
  position: fixed;
  inset: 0;
  z-index: 70;
  display: grid;
  place-items: center;
  padding: 24px;
  background: var(--fond);
}
.accueil-carte {
  width: 100%;
  max-width: 340px;
  text-align: center;
}
.accueil-icone { width: 46px; height: 46px; margin: 0 auto 20px; }
.accueil-carte h2 { font-size: 22px; line-height: 1.25; margin: 0 0 12px; }
.accueil-carte p {
  color: var(--texte-doux);
  font-size: 15px;
  line-height: 1.5;
  margin: 0 0 26px;
}
.accueil-points {
  display: flex;
  justify-content: center;
  gap: 7px;
  margin-bottom: 22px;
}
.accueil-points span {
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--bord-net);
}
.accueil-points span.actif { background: var(--accent); }
.accueil-carte .bouton { width: 100%; justify-content: center; }

/* « Passer » reste visible et atteignable : le cacher pour forcer la lecture
   fait fuir au lieu d'instruire. */
.lien-discret {
  display: block;
  width: 100%;
  margin-top: 14px;
  padding: 8px;
  background: none;
  border: 0;
  color: var(--texte-faible);
  font-size: 13.5px;
  text-decoration: underline;
}
.lien-discret:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ------------------------------------------------------- calendrier annuel */

/* Douze barres valent mieux qu'une phrase : elles montrent d'un coup la
   difference entre une espece visible toute l'annee et une qui n'apparait que
   six semaines. Lisible sans savoir lire. */
.calendrier {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 3px;
  align-items: end;
  margin: 4px 0 10px;
}
.mois { display: flex; flex-direction: column; align-items: center; gap: 4px; }
.mois-barre {
  width: 100%;
  height: 46px;
  display: flex;
  align-items: flex-end;
  background: var(--fond-2);
  border-radius: 3px;
  overflow: hidden;
}
.mois-barre span {
  width: 100%;
  background: var(--accent-sourd);
  border-radius: 3px 3px 0 0;
}
.mois-lettre { font-size: 10px; color: var(--texte-faible); font-family: var(--mono); }

/* Le mois en cours : c'est LA question qu'on se pose devant ce graphique,
   « est-ce le bon moment, maintenant ? ». Un seul mois marque, sinon le
   marquage n'attire plus l'attention sur rien. */
.mois--maintenant .mois-barre span { background: var(--accent); }
.mois--maintenant .mois-lettre { color: var(--accent); font-weight: 700; }

/* ------------------------------------------------------ ou croiser l espece */

.carte-ou {
  height: 190px;
  border-radius: var(--rayon-s);
  border: 1px solid var(--bord);
  overflow: hidden;
  margin: 10px 0;
  background: var(--fond-2);
}
/* Chaque point est une observation REELLE : on lui donne la couleur d'accent,
   pas une teinte de rarete. Ce n'est pas une valeur, c'est un fait. */
.point-obs { color: var(--accent); fill: var(--accent); fill-opacity: .55; }

/* Les lieux-dits : on dit ou aller avec un NOM, pas des coordonnees. */
.lieux { list-style: none; margin: 4px 0 0; padding: 0; }
.lieux li {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 7px 0;
  border-bottom: 1px solid var(--bord);
  font-size: 13.5px;
}
.lieux li:last-child { border-bottom: 0; }
.lieux span { color: var(--texte); }
.lieux b { color: var(--texte-faible); font-family: var(--mono); font-weight: 600; }

/* ------------------------------------------------- hierarchie des calques */

/* Leaflet place ses propres calques a des z-index eleves : 400 pour les
   tuiles, 600 pour les marqueurs, 700 pour les infobulles. Ces valeurs sont
   RELATIVES au contexte d'empilement du conteneur de carte ; si ce conteneur
   n'en cree pas, elles se comparent a celles de toute la page.
   Resultat mesure : la carte du radar, avec ses jetons, traversait la fiche
   ouverte par-dessus et s'affichait au milieu du texte.
   Deux corrections complementaires plutot qu'une surenchere de z-index :
     1. chaque carte est ISOLEE, ses calques restent chez elle ;
     2. la fiche passe au-dessus de tout ce qui n'est pas l'accueil. */
#carte-terrain, #carte-ou, #carte { isolation: isolate; position: relative; z-index: 0; }
.fiche { z-index: 65; }

/* -------------------------------------------------- photo et son attribution */

.fiche-photo { margin: 0 0 14px; }
.fiche-photo img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: var(--rayon);
  background: var(--fond-2);
}
/* Le credit n'est pas decoratif : ces images sont sous licence Creative
   Commons, souvent BY-NC. Les republier sans nommer l'auteur viole la licence.
   Il reste donc TOUJOURS visible, jamais replie derriere un geste. */
.fiche-photo figcaption {
  margin-top: 6px;
  font-size: 11.5px;
  color: var(--texte-faible);
  font-style: italic;
}

/* ----------------------------------------------------------------- profil */
/* Ecran 6 + 9 de la maquette. Tout y est deduit du carnet : aucun compte,
   aucune donnee qui sorte de l appareil. */

.profil { display: grid; gap: 12px; }

.carte-profil {
  background: var(--surface);
  border: 1px solid var(--bord);
  border-radius: var(--rayon);
  padding: 16px;
}
.carte-profil h3 {
  margin: 0 0 12px;
  font-size: 13px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--texte-faible);
  font-weight: 600;
}

.rang { display: flex; gap: 14px; align-items: center; }
.rang h2 { margin: 0; font-size: 21px; letter-spacing: -0.02em; }
.rang p { margin: 2px 0 0; color: var(--texte-doux); font-size: 13px; }
.rang > div:last-child { flex: 1; min-width: 0; }
/* La medaille de rang remplace l avatar de la maquette : il n y a pas de
   compte, donc pas de portrait a montrer. Un disque qui porte l accent dit la
   meme chose sans rien demander. */
.rang-medaille {
  width: 52px; height: 52px; flex: none;
  border-radius: 50%;
  background: radial-gradient(circle at 32% 28%,
    color-mix(in srgb, var(--accent) 90%, white 10%), var(--accent-sourd));
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent);
}

.stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.stat {
  background: var(--surface);
  border: 1px solid var(--bord);
  border-radius: var(--rayon);
  padding: 14px 8px;
  text-align: center;
}
.stat b { display: block; font-size: 22px; color: var(--texte); }
.stat span { display: block; margin-top: 3px; font-size: 11px; color: var(--texte-faible); }

/* Douze mois reels. Barres en , jamais animees : c est une lecture,
   pas un effet. */
.histo { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 5px; height: 96px; align-items: end; }
/* ⚠️ FLEX ET NON GRID, et ce n est pas un detail de style : une hauteur en
   POURCENTAGE ne se resout que contre un parent de hauteur DEFINIE. Dans une
   cellule de grille auto-dimensionnee,  se resout contre zero, et
   les douze barres sortaient toutes plates a leur hauteur minimale — un
   graphique parfaitement vide, sans la moindre erreur pour le signaler. */
.histo-col { display: flex; flex-direction: column; justify-content: flex-end; gap: 5px; height: 100%; }
.histo-barre {
  background: linear-gradient(180deg, var(--accent), var(--accent-sourd));
  border-radius: 4px 4px 2px 2px;
  min-height: 2px;
}

.defi { margin-bottom: 12px; }
.defi:last-of-type { margin-bottom: 4px; }
.defi-ligne { display: flex; justify-content: space-between; gap: 10px; font-size: 14px; margin-bottom: 6px; }
.defi-ligne b { color: var(--texte-doux); font-size: 13px; }
.defi.tenu .defi-ligne b { color: var(--accent); }
.defi .jauge { height: 6px; }

.badges { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
.badge { text-align: center; opacity: 0.42; }
.badge.tenu { opacity: 1; }
.badge span { display: block; margin-top: 6px; font-size: 11.5px; line-height: 1.3; }
.badge small { display: block; margin-top: 2px; font-size: 10px; color: var(--texte-faible); line-height: 1.25; }
/* L or, pas le vert : dans la maquette comme ici, le vert dit « agis » et l or
   dit « ceci vaut ». Un badge est une valeur acquise, pas une action. */
.badge-rond {
  width: 42px; height: 42px; margin: 0 auto;
  border-radius: 50%;
  background: var(--surface-haute);
  border: 2px solid var(--bord-net);
}
.badge.tenu .badge-rond {
  background: radial-gradient(circle at 34% 30%,
    color-mix(in srgb, var(--or) 88%, white 12%), var(--or-sourd));
  border-color: transparent;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--or) 20%, transparent);
}

.recurrentes { list-style: none; margin: 0; padding: 0; }
.recurrentes li {
  display: flex; justify-content: space-between; gap: 12px;
  padding: 9px 0; font-size: 14px;
  border-bottom: 1px solid var(--bord);
}
.recurrentes li:last-child { border-bottom: 0; }
.recurrentes b { color: var(--texte-doux); }

.vide { text-align: center; padding: 56px 24px; color: var(--texte-doux); }
.vide .icone { width: 34px; height: 34px; opacity: 0.4; margin: 0 auto 14px; }
.vide p { margin: 0; font-size: 14px; line-height: 1.6; }
