/* ==========================================================================
   BLOC — Le planisphère (`planisphere`) — la section `#hero` de la maquette.

   Repris de `style.css` (l. 334-507, 516-522, 550-607, 623-705, 920-943) et de
   `mobile.css` (§5 l. 452, §10 l. 834-837, §12, §14 et le volet espèces), bornes
   calculées sur les titres de section. Les commentaires de Fix sont gardés tels quels :
   ce sont eux qui disent POURQUOI chaque valeur est là.

   ⚠️ QUATRE ÉCARTS DE SÉLECTEUR, tous mécaniques :
   · `#planisphere` → `.planisphere` : l'identifiant vient du fichier SVG, et notre
     convention interdit les sélecteurs d'id. `js/blocs/planisphere.js` pose la classe
     à l'injection. Toutes les règles perdent le même id, leur ordre relatif est intact ;
   · `#hero.is-zooming` → `.hero.is-zooming` ; `#countryPulses` → `.planisphere__ondes` ;
   · les ÉPINGLES et les MARQUEURS (`.map-pin`, `.map-marker`, `.marker-label`) ne sont pas
     repris : la maquette les masque au démarrage (« TEST réversible ») et ils ne
     s'affichent jamais. Leurs règles seraient du style que rien n'habite.
   ⚠️ Et ce qui n'existe pas dans la maquette, chacun avec son encadré en fin de partie
   bureau : l'ancre `#carte`, l'affiche en `<img>`, la pastille de zone
   rendue côté serveur, l'entrée de l'accroche sans GSAP.
   ========================================================================== */

/* Depuis le 03/07 : le hero planisphère N'EST PLUS sticky — il recouvre le hero intro (photo,
   sticky top:0 sous lui) en remontant, puis défile NORMALEMENT avec le reste du site
   (plus de recouvrement par .site-content, demande client). */
.hero{ position:relative; height:100vh; min-height:100vh; overflow:hidden;
  display:flex; flex-direction:column;
  padding-top:calc(var(--nav-h) + var(--topbar-h));
  transform:translateZ(0); backface-visibility:hidden; }   /* couche GPU : évite les gros repaints au scroll */

/* --- Fond hero : 2 couches superposées (profondeur) --- */
.hero__bg{ position:absolute; inset:0; z-index:0; background:#0e0e0e; }   /* fond NOIR : visible le temps que la vidéo 1 charge */
/* COUCHE 1 : le sol (VIDÉO éléphants/aérienne) -> par-dessus le fond noir */
.hero__ground{ position:absolute; inset:0; }
.hero__layer{
  position:absolute; inset:0; background-size:cover; background-position:center;
  opacity:0; transition:opacity .9s var(--ease);   /* image FIXE : aucun scale/zoom */
}
.hero__layer.is-on{ opacity:1; }
/* calque VIDÉO de fond : remplit le cadre comme une image (cover), sans déformation */
video.hero__layer{ width:100%; height:100%; object-fit:cover; }
/* COUCHE 2 : nuages + oiseaux par-dessus (effet profondeur) — DÉSACTIVÉE tant que l'asset n'est pas fourni.
   IMPORTANT : mix-blend-mode + animation infinie forçaient un RE-COMPOSITING GPU permanent de toute la
   pile (photo + carte) -> scintillement continu au zoom. On neutralise la couche tant qu'il n'y a pas d'image.
   POUR RÉACTIVER quand l'image nuages arrivera : remettre mix-blend-mode:screen + animation:cloudsDrift,
   et retirer le display:none ci-dessous (idéalement n'activer le blend QUE si une image est réellement posée). */
.hero__clouds{
  position:absolute; top:0; right:0; left:auto; z-index:1; pointer-events:none;   /* SOUS le voile (z:2) - Fix 09/07 */
  width:20.93%; height:auto;     /* +15% (18.2% -> 20.93%, demande Fix 09/07) ; ancrée EN HAUT À DROITE -> grossit vers la gauche/bas sans décaler le coin */
  object-fit:contain; object-position:right top;
  filter:url(#greenKey);         /* chroma-key : retire le fond vert -> seuls les oiseaux restent */
  opacity:.95;
  transition:opacity .6s var(--ease);   /* fondu doux entre 2 passages (toutes les 30 s) */
}
/* @keyframes cloudsDrift{ from{ background-position:0% 50%; } to{ background-position:100% 50%; } } */
.hero__veil{ /* voile allégé (Fix 10/07 : plus clair, la savane est plus présente sous la carte). */
  position:absolute; inset:0; z-index:2;   /* sous la couche oiseaux (z3) */
  background:
    radial-gradient(130% 100% at 50% 45%, rgba(14,14,14,.25) 0%, rgba(14,14,14,.5) 100%),
    linear-gradient(to bottom, rgba(14,14,14,.45) 0%, rgba(14,14,14,.32) 30%, rgba(14,14,14,.38) 60%, rgba(14,14,14,.55) 100%);
}

/* --- FENÊTRE maximisée : [zone gauche] [planisphère] côte à côte (zéro chevauchement) --- */
/* Hauteur calée sur la plus longue liste (Oiseaux, 20 esp.) — pas de scroll. Le planisphère ne bouge pas. */
/* Fenêtre = en-tête (libellés) + corps [familles|espèces|carte] + accroche bas */
.hero__panel{
  position:absolute; z-index:1; left:50%; top:50%;
  transform:translate(-50%,-48%);
  width:calc(100% - 2*var(--gutter));              /* pleine largeur utile - Fix 09/07 */
  height:min(94vh, 940px);
  display:flex; flex-direction:column; gap:12px;   /* gaps réduits -> plus de hauteur pour la carte */
  padding:24px 22px 16px;                          /* paddings réduits */
  background:none; border:0; border-radius:0; box-shadow:none;
  transition:transform .5s var(--ease);
}
/* Légende du BAS : 2 libellés reliés par un filet jaune, chacun surmonté d'une flèche ↑ */
/* Légende calée sur le corps : zone gauche 470px (= .leftcol) puis filet + libellé pays
   CENTRÉ sous le planisphère. Grid [470px | filet | "pays" centré | filet]. */
.hero__panel-head{
  display:grid; grid-template-columns:470px 1fr auto 1fr;
  align-items:flex-end; flex:0 0 auto; gap:16px; padding:0;   /* compact -> gagne de la hauteur */
}
.hero__panel-head .hero__hint--left{ justify-self:start; }   /* espèce calé à gauche dans les 470px */
.hero__panel-head .hero__hint--map{ justify-self:center; }   /* pays centré sous la carte */
.hero__hint{
  font-size:var(--fs-label); font-weight:600; letter-spacing:.14em; text-transform:uppercase;
  color:rgba(255,255,255,.88); white-space:nowrap; flex:0 0 auto;
  display:inline-flex; flex-direction:column; align-items:center; gap:7px;
}
/* flèche vers le HAUT, centrée au-dessus de chaque libellé (= "ça se passe au-dessus") */
.hero__hint::before{
  content:""; width:10px; height:10px;
  border-left:2px solid var(--jaune); border-top:2px solid var(--jaune);
  transform:rotate(45deg);
}
/* le filet s'aligne sur la LIGNE du texte (bas), pas au milieu flèche+texte */
.hero__panel-head .hero__rule{ margin-bottom:5px; }
/* le filet jaune occupe tout l'espace entre les deux phrases, terminé par 2 points */
.hero__rule{
  flex:1 1 auto; height:1px; position:relative;
  background:linear-gradient(to right,
    rgba(244,183,33,0) 0%, var(--jaune) 12%, var(--jaune) 88%, rgba(244,183,33,0) 100%);
}
.hero__rule::before,.hero__rule::after{
  content:""; position:absolute; top:50%; width:5px; height:5px; margin-top:-2.5px;
  border-radius:50%; background:var(--jaune);
}
.hero__rule::before{ left:0; }
.hero__rule::after{ right:0; }
/* Corps : familles + espèces + carte */
.hero__panel-body{ flex:1 1 auto; min-height:0; display:flex; gap:18px; align-items:stretch; }
/* Accroche en HAUT, centrée — plus grande, avec de l'air sous elle (espace avant la carte) */
/* COLONNE GAUCHE (Fix 10/07) : accroche (2 lignes) AU-DESSUS, puis .leftcol (familles + espèces
   côte à côte) INCHANGÉE en dessous. Largeur = ancienne .leftcol (470px) -> la carte garde sa place.
   L'accroche en haut libère la bande du haut -> planisphère plus grand. */
.hero__left-wrap{ flex:0 0 470px; display:flex; flex-direction:column; min-height:0; }
.hero__left-wrap .leftcol{ flex:1 1 auto; width:auto; min-height:0; }   /* la leftcol remplit la hauteur sous l'accroche */
/* ⚠️ ÉCART VOULU À LA MAQUETTE (fiche sprint 2026-11-09 n° 8) : les deux `min-height:0` — ici et
   sur `.species` — n'y sont pas. Sans eux, un élément flex ne descend jamais sous la hauteur de son
   contenu : la leftcol S'ALLONGE avec la liste d'espèces au lieu de la faire défiler, sort de la
   section (`overflow:hidden`) et emporte les familles, centrées sur sa hauteur. Mesuré à 773 px
   utiles : Tigre, Pélican blanc, puis « Faune marine » et « Reptiles » ne recevaient plus le clic.
   La maquette ne le voyait pas, ses listes étaient courtes ; depuis D147 elles viennent des
   rattachements `espece_pays` (23 oiseaux). Ne pas les retirer pour « revenir à la maquette ». */
/* accroche : alignée à gauche, forcée sur 2 lignes (max-width serrée), espacement sous elle. */
.hero__panel .hero__tagline{
  flex:0 0 auto; text-align:left; color:var(--blanc);
  font-size:clamp(24px,1.9vw,34px); line-height:1.08; margin:0 0 clamp(20px,3vh,40px); padding:0;
  max-width:16ch;   /* force le passage sur ~2 lignes */
  text-shadow:0 2px 18px rgba(0,0,0,.5);
}
.hero__tag-l, .hero__tag-r{ display:inline-block; }
.hero__panel .hero__tagline .accent{ color:var(--jaune); }
/* ZONE GAUCHE : largeur FIXE réservée (familles + espace espèces) => la carte ne bouge jamais */
.leftcol{
  flex:0 0 auto; width:470px;                    /* espace réservé (familles + menu espèces élargi) */
  display:flex; align-items:stretch; gap:14px;
}
/* PLANISPHÈRE : prend tout le reste, ne chevauche jamais la zone gauche */
.hero .map{
  flex:1 1 auto; min-width:0; position:relative;
  display:flex; align-items:center; justify-content:center;
  pointer-events:none;
  overflow:hidden;   /* clippe le SVG zoomé (transform scale) dans le cadre carte - sinon il déborde sur la page */
}
/* ÉQUERRES DE CADRAGE style viseur photo aux 4 coins du cadre carte (Fix 10/07). Chaque pseudo dessine
   2 coins opposés (border en L). ::before = haut-gauche + bas-droite, ::after = haut-droite + bas-gauche.
   Fixes : ne bougent pas au zoom (posées sur .map, pas sur le SVG zoomé). --cnr = bras, --cnw = trait. */
.hero .map{ --cnr:26px; --cnw:2px; --cnc:rgba(255,255,255,.85); --cno:0px; }   /* corners collés au bord (Fix 10/07) */
.hero .map::before, .hero .map::after{
  content:""; position:absolute; z-index:5; pointer-events:none;
  top:var(--cno); left:var(--cno); right:var(--cno); bottom:var(--cno);
  /* le trait n'apparaît qu'aux coins grâce au border-image conique ci-dessous. */
}
/* HAUT-GAUCHE */
.hero .map::before{
  background:
    linear-gradient(var(--cnc),var(--cnc)) left top   /var(--cnw) var(--cnr) no-repeat,
    linear-gradient(var(--cnc),var(--cnc)) left top   /var(--cnr) var(--cnw) no-repeat,
    linear-gradient(var(--cnc),var(--cnc)) right bottom/var(--cnw) var(--cnr) no-repeat,
    linear-gradient(var(--cnc),var(--cnc)) right bottom/var(--cnr) var(--cnw) no-repeat;
}
/* HAUT-DROITE + BAS-GAUCHE */
.hero .map::after{
  background:
    linear-gradient(var(--cnc),var(--cnc)) right top   /var(--cnw) var(--cnr) no-repeat,
    linear-gradient(var(--cnc),var(--cnc)) right top   /var(--cnr) var(--cnw) no-repeat,
    linear-gradient(var(--cnc),var(--cnc)) left bottom /var(--cnw) var(--cnr) no-repeat,
    linear-gradient(var(--cnc),var(--cnc)) left bottom /var(--cnr) var(--cnw) no-repeat;
}
.hero .map svg{
  width:100%; height:100%;        /* planisphère AGRANDI au maximum (Fix 09/07) */
  overflow:hidden; pointer-events:auto;
}

/* ---- BARRE DE ZONES : reset sous la colonne familles (470px), zones CENTRÉES sous la carte ---- */
.zones{ flex:0 0 auto; display:flex; align-items:center; gap:14px; padding:4px 0 0; }
.map__reset--corner{ flex:0 0 470px; }   /* même largeur que .leftcol -> aligné sous les familles */
/* les zones logent dans la largeur de la CARTE (l'espace restant après les 470px) et sont CENTRÉES. */
.zones__list{ flex:1 1 auto; display:flex; align-items:stretch; justify-content:center;
  gap:clamp(8px,1.2vw,22px); flex-wrap:nowrap; }
/* bouton zone = .family en LIGNE (pastille + label côte à côte), largeur au contenu (pas étiré).
   .family.family--zone (2 classes) bat .family{width:100%} définie plus bas dans le fichier. */
.family.family--zone{ flex:0 0 auto; width:auto; flex-direction:row; justify-content:center;
  text-align:center; gap:9px; padding:8px 12px; }
.family--zone .family__label{ font-size:var(--fs-label); white-space:nowrap; }
.family--zone .family__ico{ flex:0 0 auto; font-weight:700; font-size:15px; }
/* famille GRISÉE quand aucune espèce de sa famille n'est présente dans la zone active. */
.family.is-disabled{ opacity:.3; pointer-events:none; }
/* ZONE ACTIVE (Fix 10/07, allégé) : UNE seule règle. Les pays AVEC voyage (.dest) ne sont PAS touchés
   (opacité inchangée). Seuls les fonds neutres (sans voyage) passent à 25%. Aucun path modifié en JS
   -> beaucoup moins de repaints = plus de clipping résiduel. */
.planisphere.zone-active path:not(.dest){ opacity:.25; transition:opacity .5s var(--ease); }
/* PENDANT le zoom (.is-zooming, classe DÉDIÉE - PAS .zooming qui passe le cadre en overflow:visible) :
   couper les transitions des ~230 paths/marqueurs, sinon elles se relancent à chaque changement de
   zone = repaints empilés (le clipping cumulatif). shape-rendering:optimizeSpeed allège la
   rastérisation à chaque frame de l'animation du <g>. */
.hero.is-zooming .planisphere path{
  transition:none !important;
  shape-rendering:optimizeSpeed;
}

/* (style.css l. 516) — la règle de BASE de l'accroche ; `.hero__panel .hero__tagline` la surcharge plus haut. */
/* Accroche en bas, centrée, une seule ligne */
.hero__tagline{
  color:var(--blanc); text-align:center; white-space:nowrap;
  font-size:clamp(30px,4.2vw,58px); line-height:1;
  text-shadow:0 2px 30px rgba(0,0,0,.55);
}


/* --- Familles : colonne verticale (icône + titre), dans la zone gauche --- */
.families{ display:flex; flex-direction:column; gap:10px; justify-content:center; align-self:center; }
.family{
  display:flex; flex-direction:row; align-items:center; gap:11px;
  background:none; border:none; padding:6px 8px; border-radius:12px;
  color:var(--blanc); width:100%; text-align:left; white-space:nowrap;
  transition:background .2s var(--ease);
}
.family:hover{ background:rgba(255,255,255,.06); }
.family__ico{
  width:46px; height:46px; flex:0 0 auto; border-radius:50%;
  display:grid; place-items:center;
  background:rgba(255,255,255,.07);
  border:1.5px solid rgba(255,255,255,.5);
  color:var(--blanc);
  transition:background .25s var(--ease), border-color .25s var(--ease), color .25s var(--ease);
}
.family__ico svg{ width:40px; height:40px; }   /* dessin plus gros dans le cercle */
.family__label{
  font-size:var(--fs-label); font-weight:600; line-height:1.2; letter-spacing:.06em; text-transform:uppercase;
  color:rgba(255,255,255,.95);
}
.family:hover .family__ico{ background:var(--jaune); border-color:var(--jaune); color:var(--noir); }
.family:hover .family__label{ color:var(--jaune); }
.family.is-active .family__ico{ background:var(--jaune); border-color:var(--jaune); color:var(--noir); }
.family.is-active .family__label{ color:var(--jaune); }

/* Colonne familles : bouton "Tout afficher" en haut + liste familles */
.famcol-inner{ flex:0 0 150px; display:flex; flex-direction:column; justify-content:center; gap:10px; padding:0 4px; }
.famcol-inner .families{ flex:0 0 auto; }
/* Listing d'espèces : occupe l'espace déjà réservé (la carte ne bouge pas), juste un fondu */
.species{
  flex:1 1 auto; min-width:0; min-height:0;
  display:flex; flex-direction:column; height:100%;
  background:rgba(14,14,14,.5);
  color:var(--blanc); border-radius:14px;
  border:1px solid rgba(255,255,255,.12);
  padding:14px 6px 14px 14px;
  opacity:0; visibility:hidden; transition:opacity .3s var(--ease);
}
.leftcol.species-open .species{ opacity:1; visibility:visible; }
.species__list{ flex:1 1 auto; overflow-y:auto; padding-right:8px; }

/* Scrollbar fine, élégante, jaune */
.species__list{ scrollbar-width:thin; scrollbar-color:var(--jaune) transparent; }
.species__list::-webkit-scrollbar{ width:4px; }
.species__list::-webkit-scrollbar-track{ background:transparent; }
.species__list::-webkit-scrollbar-thumb{ background:var(--jaune); border-radius:4px; }
/* listing vertical : une espèce par ligne */
.species__list{ display:flex; flex-direction:column; gap:2px; }
.species__list span{
  display:block; font-size:var(--fs-small); padding:8px 10px; border-radius:8px;
  color:rgba(255,255,255,.92); border-bottom:1px solid rgba(255,255,255,.08);
  cursor:pointer; transition:background .2s var(--ease), color .2s var(--ease);
}
.species__list span:hover{ background:rgba(244,183,33,.15); color:var(--jaune); }
.species__list span.is-active{ background:var(--jaune); color:var(--noir); font-weight:600; }


/* ==========================================================================
   PLANISPHÈRE (dans la colonne droite du hero)
   Carte posée sur le fond photo : pays clairs translucides, accent jaune
   ========================================================================== */
.planisphere path{
  fill:rgba(255,255,255,.14); stroke:rgba(255,255,255,.42); stroke-width:1.5;   /* pays SANS destination : atténués */
  vector-effect:non-scaling-stroke;
  pointer-events:none;   /* pays non-destinations : non cliquables */
  transition:fill .25s var(--ease), opacity .5s var(--ease);   /* fondu doux au zoom */
}


/* pays Objectif Nature (destinations) — plus visibles ET CLIQUABLES (sur leur forme) */
.planisphere path.dest{ fill:rgba(255,255,255,.52); pointer-events:auto; cursor:pointer; }
/* pays au SURVOL = JAUNE (accent), SANS contour noir */
.planisphere path.dest.hovered{
  fill:var(--jaune);
  stroke:var(--jaune); stroke-width:1.5; vector-effect:non-scaling-stroke;
}
/* petite BOX du nom du pays, suit la souris au survol */
.map-tip{
  position:fixed; z-index:300; pointer-events:none;
  padding:6px 12px; border-radius:8px;
  background:var(--jaune); color:var(--noir);
  font-family:var(--sans); font-size:var(--fs-label); font-weight:700; letter-spacing:.01em; white-space:nowrap;
  box-shadow:0 6px 18px -6px rgba(0,0,0,.5);
  opacity:0; transform:translateY(4px); transition:opacity .15s var(--ease), transform .15s var(--ease);
}
.map-tip.show{ opacity:1; transform:translateY(0); }
/* pays ACTIF / filtré (clic, match de filtre) = BLANC OPAQUE (même rendu que le pays zoomé) */
.planisphere path.match,
.planisphere path.actif{
  fill:rgba(255,255,255,.9);
  stroke:rgba(255,255,255,.95); stroke-width:1.8; vector-effect:non-scaling-stroke;
}
/* état filtré : pays non concernés -> filigrane léger (toujours visibles en fond) */
.planisphere.filtering path:not(.match){ opacity:.32; }


/* ONDE AUTOUR DU PAYS (filtre espèce) : écho radar jaune, grossit + s'efface en boucle.
   Centrée sur le pays -> repère bien sa position, y compris les petits pays / îles. */
.planisphere__ondes .country-ping{
  fill:rgba(244,183,33,.10); stroke:var(--jaune); stroke-width:2; vector-effect:non-scaling-stroke;
  transform-box:fill-box; transform-origin:center; pointer-events:none;
  opacity:0;                                   /* caché tant que l'anim n'a pas démarré (évite le cercle figé) */
  animation:countryPing 2s linear infinite both;
}
@keyframes countryPing{
  0%   { transform:scale(.5); opacity:0; }     /* démarre invisible + petit -> pas de cercle stationnaire */
  15%  { opacity:.9; }                          /* l'onde "naît" en mouvement */
  100% { transform:scale(2.6); opacity:0; }
}

/* « RÉINITIALISER » — dernière entrée SOUS Reptiles (remplace le bouton « Tout afficher »).
   Pas un bouton : un TEXTE SOULIGNÉ précédé d'une flèche circulaire qui tourne sur elle-même
   au survol. Aligné sur la gouttière des familles (46px d'icône + 11px de gap) pour que le
   libellé tombe sous ceux des familles. */
.map__reset{
  display:flex; align-items:center; gap:11px;
  background:none; border:none; padding:6px 8px; margin-top:4px;
  color:var(--blanc); width:100%; text-align:left; cursor:pointer;
}
.map__reset__ico{
  width:46px; height:46px; flex:0 0 auto;      /* même gouttière que .family__ico */
  display:grid; place-items:center; color:var(--jaune);
}
/* tourne sur elle-même : ANIMATION (une transition vers rotate(360deg) = rotate(0), donc immobile) */
.map__reset__ico svg{ width:19px; height:19px; }
.map__reset:hover .map__reset__ico svg{ animation:resetSpin .6s var(--ease); }
@keyframes resetSpin{ from{ transform:rotate(0); } to{ transform:rotate(360deg); } }
.map__reset__txt{
  font-size:var(--fs-small); font-weight:600; white-space:nowrap;
  text-decoration:underline; text-underline-offset:3px;
  text-decoration-color:rgba(255,255,255,.45); transition:text-decoration-color .2s var(--ease);
}
.map__reset:hover .map__reset__txt{ text-decoration-color:var(--jaune); color:var(--jaune); }
@media (prefers-reduced-motion: reduce){ .map__reset:hover .map__reset__ico svg{ animation:none; } }

/* ---- AJOUTS PROPRES AU PORTAGE (aucun équivalent dans la maquette) ---- */

/* L'ancre stable `#carte` — cible du bouton « Retour à la carte » de la fiche destination.
   Nos sections ont un identifiant généré, d'où cet élément vide en tête de section. */
.hero__ancre{ position:absolute; top:0; left:0; width:1px; height:1px; pointer-events:none; }

/* Le SVG qui porte le filtre `#greenKey` : il ne doit occuper aucune place. */
.hero__filtres{ position:absolute; width:0; height:0; overflow:hidden; }

/* ⚠️ L'AFFICHE est une `<img>` (la maquette n'avait qu'une `<video>` avec `poster`) : elle
   reprend la règle de cadrage de la vidéo, sans quoi elle s'afficherait à sa taille native. */
img.hero__layer{ width:100%; height:100%; object-fit:cover; }

/* ⚠️ La pastille d'initiales des zones est rendue CÔTÉ SERVEUR (la maquette l'ajoutait par
   `mobile.js`, sur téléphone seulement). Sa seule règle étant dans la partie mobile, il faut
   la masquer ici — sinon « AN », « AS »… s'affichent à côté des libellés sur écran large.
   ⚠️ Bornée à l'écran large : la règle mobile ne dit rien de `display`, une règle globale ici
   viderait donc les pastilles sur téléphone — mesuré, c'est ce que donnait la première version. */
@media (min-width:1301px){ .family__zone-init{ display:none; } }

/* ⚠️ ÉCART VOULU À LA MAQUETTE — LA BARRE DES ZONES SUR ÉCRAN MOYEN (fiche sprint 2026-11-09
   n° 8, arbitrage d'Alexandre). Dans la maquette elle ne rétrécit jamais (`nowrap`, aucune
   compression) : mesuré, elle sortait de l'écran sous ~1 540 px de large — à 1 280 px la
   dernière zone était ENTIÈREMENT hors champ, d'où le « trop long pour l'affichage » de la
   cliente. Deux paliers :
   · 1 301 → 1 600 px : la même barre, COMPRESSÉE (cercles 34 px, texte 12 px, espacements
     réduits). Mesuré : elle tient dans le cadre de la carte à partir de ~1 300 px, et la barre
     d'origine déborde encore de quelques pixels vers 1 540 px ;
   · 1 025 → 1 300 px : la carte n'a que 400 à 620 px de large, cinq libellés ne peuvent pas
     y tenir sur une ligne. Chaque zone devient un CERCLE À INITIALES, le principe déjà retenu
     sous 1 024 px. Le libellé complet reste en `aria-label` et en info-bulle (`title`).
   Le numéro et le libellé ne sont que MASQUÉS : `planisphere.js` ne lit que `data-zone`. */
@media (min-width:1025px) and (max-width:1600px){
  .zones__list{ min-width:0; gap:6px; }
  .family.family--zone{ padding:6px; gap:6px; }
  .family--zone .family__ico{ width:34px; height:34px; font-size:13px; }
  .family--zone .family__label{ font-size:12px; letter-spacing:.03em; }
}
@media (min-width:1025px) and (max-width:1300px){
  .zones__list{ gap:10px; }
  .family.family--zone{
    width:46px; height:46px; padding:0; gap:0; border-radius:50%;
    background:rgba(255,255,255,.07); border:1.5px solid rgba(255,255,255,.5);
  }
  .family--zone .family__ico,
  .family--zone .family__label{ display:none; }
  .family.family--zone:hover{ background:rgba(255,255,255,.14); }
  .family.family--zone.is-active{ background:var(--jaune); border-color:var(--jaune); }
  .family__zone-init{
    font-family:var(--sans); font-weight:700; font-size:13px; letter-spacing:.02em; color:var(--blanc);
  }
  .family.family--zone.is-active .family__zone-init{ color:var(--noir); }
}

/* Les flèches de zone sont construites à toutes les largeurs, mais n'ont de règle d'affichage
   que sous 1024 px (`mobile.css` §12). Sur écran large elles n'existent pas dans le rendu de
   la maquette : on les masque, la règle mobile plus bas les rétablit. */
.hero-zonenav{ display:none; }

/* Carte indisponible (fichier SVG introuvable) — le style inline de `carte.js:38`. */
.map__indispo{ color:var(--blanc); text-align:center; }

/* ⚠️ L'ENTRÉE DE L'ACCROCHE PAR LA GAUCHE, en CSS pur : la maquette la fait en GSAP
   (`main.js:83`, `xPercent:-120 → 0`, 0,9 s, `power3.out`, délai 0,15 s), écarté par D121.
   Même courbe en `cubic-bezier` ; aucun script, donc rien qui puisse ne pas s'exécuter. */
.hero__tag-l{ animation:heroTagIn .9s cubic-bezier(.215,.61,.355,1) .15s both; }
@keyframes heroTagIn{ from{ transform:translateX(-120%); opacity:0; } to{ transform:none; opacity:1; } }
@media (prefers-reduced-motion: reduce){ .hero__tag-l{ animation:none; } }

/* ==========================================================================
   MOBILE
   ========================================================================== */

/* mobile.css §5 (l. 452) — la règle partage sa `@media` avec `.intro-hero`, `.cfiche`,
   `.feature` : seule la ligne du hero est reprise ici. */
@media (max-width:1024px){
  .hero{ height:100dvh; min-height:100dvh; }
}

/* mobile.css §10 (l. 834-837) — les survols neutralisés au doigt. */
@media (hover:none){
  .family:hover{ background:none; }
  .family:hover .family__ico{ background:rgba(255,255,255,.07); border-color:rgba(255,255,255,.5); color:var(--blanc); }
  .family:hover .family__label{ color:rgba(255,255,255,.95); }
  .species__list span:hover{ background:none; color:rgba(255,255,255,.92); }
}

/* mobile.css §12 — HERO / PLANISPHÈRE MOBILE */
@media (max-width:1024px){
  /* LOT 4 (22/07) : FOND LISIBLE — constat Fix : la carte se dessinait en clair
     PAR-DESSUS la vidéo de savane du hero, sur fond photo chargé -> contraste
     quasi nul, aucun pays ne ressortait. Les couches vidéo (sol + oiseaux) sont
     masquées : .hero__bg garde SON PROPRE fond #0e0e0e/--noir (style.css l.343,
     posé à l'origine comme fallback "le temps que la vidéo 1 charge") -> ce fond
     UNI devient donc le fond PERMANENT en mobile, sans aucune couleur nouvelle
     ajoutée ici. Les pays (path.dest, blanc translucide) ressortent nettement
     dessus, comme sur le fallback desktop déjà éprouvé. */
  .hero__ground, .hero__clouds{ display:none; }

  .hero__panel{
    position:absolute; inset:0; transform:none;
    width:100%; height:100%;
    /* arithmétique identique au volet menu (§4) : le haut dégage le header,
       le bas dégage la pilule flottante - sinon la barre de zones passe dessous. */
    padding:calc(72px + 10px) 14px calc(52px + clamp(20px,4vw,32px) + 14px);
    gap:8px;
  }
  .hero__panel-body{ flex-direction:column; gap:8px; min-height:0; }
  /* Légende desktop (2 libellés + filets) : calée sur une grille 470px qui n'existe plus en
     mobile, et son rôle (expliquer le geste) est repris par l'interaction elle-même
     (rangée de familles visible, points de zone, tap direct sur un pays). */
  .hero__panel-head{ display:none; }

  .hero__left-wrap{ flex:0 0 auto; width:100%; }
  .hero__panel .hero__tagline{
    text-align:center; max-width:none; margin:0 0 4px;
    font-size:clamp(15px,4.2vw,18px); line-height:1.2;
  }

  /* ---- Rangée FAMILLES : scroll horizontal natif ----
     .leftcol = piste-wrap (overflow-x) ; .famcol-inner = wrapper aplati (display:contents,
     sinon son flex:0 0 150px desktop mesurerait une largeur figée et casserait le scroll) ;
     .families = la piste (inline-flex, largeur = contenu -> overflow-x se déclenche).
     LOT 6 (22/07) : le fondu de bord (mask-image) N'EST PLUS ici en base - les 7 familles
     tiennent désormais sans déborder (flex:1 1 0 ci-dessous) donc le fondu ne devait plus
     rien annoncer. Il est reposé PLUS BAS (§14), sous `.leftcol.is-scrollable` uniquement -
     classe posée par js/mobile.js quand (et seulement quand) scrollWidth > clientWidth. */
  .hero__left-wrap .leftcol{ flex:0 0 auto; width:100%; }
  .leftcol{
    display:block; min-width:0;
    overflow-x:auto; overflow-y:visible; scrollbar-width:none;
    -webkit-overflow-scrolling:touch; overscroll-behavior-x:contain;
  }
  .leftcol::-webkit-scrollbar{ display:none; }
  .famcol-inner{ display:contents; }
  /* LOT 5 (22/07) : les 7 familles doivent TENIR sans défilement (retour Fix).
     display:flex (PAS inline-flex) + flex:1 1 0 sur chaque famille -> les 7
     colonnes se partagent exactement la largeur réelle du conteneur, quelle que
     soit la largeur d'écran (calcul fait par le flex-box, pas une estimation en
     dur) : plus besoin de scroll-snap/white-space:nowrap, plus jamais de scroll
     latéral par construction. overflow-x:auto reste en garde-fou sur .leftcol
     (§ ci-dessus) mais ne se déclenchera plus. */
  .families{
    display:flex; flex-direction:row; flex-wrap:nowrap; width:100%; gap:4px; padding:2px 0;
  }
  .family{
    flex:1 1 0; min-width:0; flex-direction:column; gap:4px;
    padding:6px 0; border-radius:10px;
    white-space:normal; text-align:center;
  }
  /* icône : width ET height pilotés par la MÊME formule en vw (pas d'aspect-ratio -
     testé, aspect-ratio + display:grid + svg en % donne une hauteur incohérente avec
     la largeur, cf. contrôle Chrome) - plafonnée à 44px (plus grosse qu'avant : 38px
     -> jusqu'à 44px), reste toujours < la largeur de sa colonne (mesurée par Fix :
     ~46px à 375px, ~38px à 320px) donc jamais de débordement, à aucune largeur. */
  .family__ico{ width:min(11vw,44px); height:min(11vw,44px); margin:0 auto; }
  .family__ico svg{ width:60%; height:60%; }
  /* libellé : très petit (ordre de grandeur du travail de juin). hyphens:auto (natif,
     dictionnaire FR - <html lang="fr">) coupe au tiret à la syllabe plutôt qu'au
     caractère si un mot (ex. "PRÉDATEURS") ne tient pas seul sur sa colonne ;
     overflow-wrap:break-word reste le garde-fou qui empêche tout débordement
     (donc tout risque de scroll latéral), hyphens ne fait qu'améliorer l'endroit
     de la coupe. */
  .family__label{
    font-size:8px; letter-spacing:0; line-height:1.15;
    overflow-wrap:break-word; word-break:normal; hyphens:auto;
  }
  /* Panneau espèces desktop (glisse À CÔTÉ des familles) : remplacé par le volet
     #mobSpecies qui descend du HAUT (ci-dessous) - jamais affiché en mobile. */
  .species{ display:none; }

  /* ---- Carte ----
     LOT 11 (24/07), retour Nicolas « je diminuerais un peu la hauteur du cadre de la carte » :
     la carte prenait TOUT l'espace vertical restant (flex:1 1 auto -> 518px mesurés à 500px de
     large), alors que le planisphère en vue monde ne dessine qu'une bande d'environ 230px de
     haut - le reste était du vide à l'intérieur du cadre à équerres. Le cadre est désormais
     calé sur la LARGEUR (le planisphère est un objet large et bas : sa hauteur utile suit sa
     largeur, pas celle de l'écran), avec un plafond en dvh pour les écrans très courts.
     Mesuré : 518 -> 350px à 500px de large, 262px à 375px.
     La section garde sa hauteur plein écran (demande limitée au cadre) : l'espace libéré est
     réparti autour du couple familles + carte, qui se centre verticalement. */
  .hero .map{ width:100%; flex:0 1 auto; min-height:0; height:min(70vw, 44dvh); }
  .hero__panel-body{ justify-content:center; }

  /* ---- FLÈCHES DE ZONE (LOT 4, 22/07) : « même fonctionnement que les polaroïds »
     (retour Fix) - le swipe déjà en place (js/mobile.js heroMobile/goZone) reçoit son
     ALTERNATIVE VISIBLE, même pattern que .stackv__navrow (§11) : 2 boutons ÉCARTÉS AU
     MAXIMUM aux bords gauche/droite de l'écran (jamais groupés au centre - zone
     réservée de la pilule). Ajoutés en enfants DIRECTS de #map par js/mobile.js, une
     fois le SVG injecté (MutationObserver - sinon le fetch de carte.js les effacerait
     en écrasant mapEl.innerHTML). position:absolute -> sortis du flux : ne perturbent
     pas le display:flex/justify-content:center de .map (style.css, inchangé) qui
     centre le SVG. Les points de zone (.family--zone, ci-dessus) restent l'indicateur
     de position ; les flèches sont l'action explicite demandée par Fix. */
  .hero-zonenav{
    display:flex; align-items:center; justify-content:center; line-height:1;
    position:absolute; top:50%; transform:translateY(-50%); z-index:50;
    width:44px; height:44px; border-radius:50%; flex:0 0 auto;
    background:var(--jaune); color:var(--noir); border:none; padding:0;
    cursor:pointer; pointer-events:auto; touch-action:manipulation;
    box-shadow:0 8px 22px -6px rgba(0,0,0,.5);
  }
  /* LOT 11 (24/07), retour Fix : chevron trop gros dans la pastille jaune. 20 -> 15px, et
     centrage rendu strict - le <svg> est un élément INLINE par défaut, il repose donc sur la
     ligne de base et embarque le talon de descendante de la police du bouton (~3px sous le
     glyphe), ce qui décentrait la flèche vers le haut malgré le align-items:center du parent.
     `display:block` supprime cette boîte de ligne : le centrage flex porte alors sur la boîte
     réelle du dessin, pas sur une ligne de texte.
     ⚠️ Spécificité : les flèches sont des enfants de #map, donc décrites par
     `.hero .map svg{width:100%;height:100%}` (style.css l.475) - qui les étirait à la taille
     entière du bouton (44px mesurés). Il faut donc au moins 2 classes ici pour gagner. */
  .hero .hero-zonenav svg{ display:block; width:15px; height:15px; }
  .hero-zonenav--prev{ left:6px; }
  .hero-zonenav--next{ right:6px; }

  /* Cibles tactiles des pays ÉLARGIES (retour cliente d'origine : petits pays/îles
     injoignables au doigt - le point le plus important de ce lot). Trait transparent
     (toujours "peint" au sens SVG -> reste cliquable) ; vector-effect:non-scaling-stroke
     hérité de la règle desktop (style.css) garde cette marge CONSTANTE à l'écran, quel
     que soit le niveau de zoom de la zone. Ne change ni la couleur ni l'épaisseur du
     filet blanc visible (propriétés non déclarées ici -> héritées, inchangées). */
  .planisphere path.dest{ stroke:rgba(0,0,0,0); stroke-width:14px; }
  /* Nom du pays : ne portait l'info qu'au survol (.map-marker:hover .marker-label,
     mort au doigt) - rendu PERMANENT ici, sinon l'information disparaît purement et
     simplement en mobile (règle : jamais d'info accessible au seul survol). */

  /* ---- Barre de zones : reset réduit à une icône, les 5 zones deviennent de VRAIES
     PASTILLES DE RÉGION (initiales lisibles, alternative visible au swipe de la carte,
     cf. règle "geste + bouton toujours"). Mêmes boutons/handlers que le desktop
     (carte.js setupZones) : seul l'habillage change.
     LOT 6 (22/07), retour Fix : les points de LOT 5 (13px, neutres, groupés au centre)
     étaient trop petits pour porter une info - agrandis en pastilles ovales à initiales,
     ÉTALÉES sur toute la largeur (justify-content:space-between, quitte à s'approcher
     du bouton de réinitialisation à gauche - accepté explicitement par Fix). */
  /* LOT 11 (24/07), retour Nicolas/Fix : « un menu en dessous avec les 5 zones ET le bouton
     réinitialiser, lui aussi dans un cercle, cercles un peu plus gros, répartis sur la largeur
     avec une légère marge à droite et à gauche ».
     Parade : `.zones__list{display:contents}` (même technique que `.famcol-inner` §12) aplatit
     le conteneur des 5 zones -> les 6 boutons deviennent des frères DIRECTS de `.zones` et se
     répartissent d'un seul `space-between`, avec un écart rigoureusement identique entre tous
     (avant : le réinitialiser était hors du groupe, donc à un écart différent des autres).
     Taille commune en vw plafonnée : 6 pastilles de 54px + 24px de marges tiennent dès 328px
     de large, donc à toutes les largeurs de téléphone. */
  .zones{ flex:0 0 auto; padding:10px 12px 0; gap:0; justify-content:space-between; }
  .map__reset--corner{
    flex:0 0 auto; margin:0; padding:0;
    width:min(13.5vw,54px); height:min(13.5vw,54px); border-radius:50%;
    display:flex; align-items:center; justify-content:center;
    background:rgba(255,255,255,.14); border:1px solid rgba(255,255,255,.22);
  }
  .map__reset--corner .map__reset__txt{ display:none; }
  .map__reset--corner .map__reset__ico{ width:auto; height:auto; display:flex; }
  .zones__list{ display:contents; }
  /* `.family.family--zone` (2 classes) : même parade de spécificité que le LOT 5 - matche
     `.family.family--zone` (style.css) plutôt que `.family--zone` seul pour rester à
     spécificité égale, l'ordre de cascade (mobile.css après style.css) fait gagner ce
     fichier sans !important. */
  .family.family--zone{
    position:relative; width:min(13.5vw,54px); height:min(13.5vw,54px); min-width:0; padding:0; gap:0;
    border-radius:50%; background:rgba(255,255,255,.14); border:1px solid rgba(255,255,255,.22);
    display:flex; align-items:center; justify-content:center; line-height:1;
  }
  .family--zone .family__ico,
  .family--zone .family__label{ display:none; }   /* libellé complet gardé dans le DOM -> aria-label posé par mobile.js */
  .family.family--zone.is-active{ background:var(--jaune); border-color:var(--jaune); }
  /* pastille d'initiales (AN/AS/EU/AF/AO) : élément ajouté par mobile.js, cf. zone.init
     (data-carte.js) - optiquement centrée (flex+line-height:1 sur le bouton parent ci-dessus). */
  .family__zone-init{
    font-family:var(--sans); font-weight:700; font-size:14px; letter-spacing:.02em;
    color:var(--blanc);
  }
  .family.family--zone.is-active .family__zone-init{ color:var(--noir); }
}

/* mobile.css §14 — dégradé de bord CONDITIONNEL de la rangée des familles */
@media (max-width:1024px){
  .leftcol.is-scrollable{
    mask-image:linear-gradient(to right, transparent 0, #000 12px, #000 calc(100% - 12px), transparent 100%);
    -webkit-mask-image:linear-gradient(to right, transparent 0, #000 12px, #000 calc(100% - 12px), transparent 100%);
  }
}

/* mobile.css — VOLET ESPÈCES (`.mob-species`, construit par `js/blocs/planisphere.js`) */
.mob-species{ display:none; }
.mob-species{ display:none; }
@media (max-width:1024px){
  .mob-species{
    display:block; position:fixed; left:0; right:0; top:72px; bottom:0;
    z-index:1200; pointer-events:none; overflow:hidden;   /* > header 1000, < pilule 1400 */
  }
  .mob-species__backdrop{
    position:absolute; inset:0; background:rgba(14,14,14,.55);
    -webkit-backdrop-filter:blur(4px); backdrop-filter:blur(4px);
    opacity:0; transition:opacity .35s ease;
  }
  .mob-species__panel{
    position:absolute; left:0; right:0; top:0; max-height:85%;
    background:var(--creme); border-radius:0 0 20px 20px;
    box-shadow:0 12px 40px -10px rgba(0,0,0,.45);
    display:flex; flex-direction:column;
    transform:translateY(-100%);
    transition:transform .4s cubic-bezier(.22,.61,.36,1);
    overflow:hidden;
  }
  .mob-species__head{
    display:flex; align-items:center; justify-content:space-between; gap:12px;
    padding:16px 18px; border-bottom:1px solid rgba(14,14,14,.1);
    position:sticky; top:0; background:var(--creme); z-index:1;
  }
  .mob-species__fam-label{
    font-family:var(--display,var(--sans)); font-size:var(--fs-small);
    letter-spacing:.06em; text-transform:uppercase; color:var(--noir);
  }
  .mob-species__close{
    width:40px; height:40px; border-radius:50%; background:rgba(14,14,14,.08);
    border:none; cursor:pointer; display:flex; align-items:center; justify-content:center;
    color:var(--noir); flex:0 0 40px; touch-action:manipulation;
  }
  .mob-species__list{
    overflow-y:auto; -webkit-overflow-scrolling:touch;
    display:grid; grid-template-columns:1fr 1fr; gap:2px;
    padding:8px 14px 20px;
  }
  .mob-species__item{
    text-align:left; background:none; border:none; border-bottom:1px solid rgba(14,14,14,.07);
    font-family:var(--serif); font-size:15px; color:var(--noir);
    padding:12px 6px; cursor:pointer; touch-action:manipulation;
  }
  .mob-species__item.is-active{ color:var(--jaune-d); font-weight:600; }

  .mob-species.is-open{ pointer-events:auto; }
  .mob-species.is-open .mob-species__backdrop{ opacity:1; }
  .mob-species.is-open .mob-species__panel{ transform:translateY(0); }
}
@media (hover:none){
  .mob-species__close:hover{ background:rgba(14,14,14,.08); }
}
@media (prefers-reduced-motion:reduce){
  .mob-species__panel, .mob-species__backdrop{ transition:none; }
}


