/* ==========================================================================
   OBJECTIF NATURE - FEUILLE MOBILE (Chérubin, lot 1 : LE SOCLE - 22/07/2026 ;
   lot 1bis : réparations - 22/07/2026 ; lot 2 : pilule/footer - 22/07/2026 ;
   lot 3 : planisphère/zones - 22/07/2026 ; lot 4 : revirement pilule TOUJOURS
   visible + planisphère lisible + flèches de zone + volet/footer resserrés -
   22/07/2026 ; lot 5 : 7 familles sans scroll latéral + points de zone
   circulaires (fix de spécificité) + confirmation pilule toujours visible -
   22/07/2026)

   RÈGLE ABSOLUE : le desktop est validé, aucun pixel ne bouge au-dessus de 1024px.
   - Ce fichier est chargé APRÈS css/style.css -> à spécificité égale, il gagne
     par l'ordre de cascade. AUCUN !important n'est donc nécessaire ici.
   - css/style.css n'est PAS modifié.
   - Tout vit sous @media (max-width:1024px) [mobile + tablette]
     ou @media (max-width:640px) [téléphone], sauf :
       * le bloc @media (hover:none) (ne matche jamais une souris de bureau),
       * le display:none de base du menu mobile (composants qui n'existent pas
         dans style.css, injectés par js/mobile.js).

   Sommaire :
     1. Menu mobile - base (hors MQ, composants neufs)
     2. Tokens mobile (<=640)
     3. Header mobile (<=1024)
     4. Menu bas : burger + volet (<=1024)
     5. Plein écran : vh -> dvh/svh (<=1024)
     6. Grilles génériques (<=1024 / <=640)
     7. Footer (<=1024 / <=640)
     8. Boutons flottants : scroll-top, newsletter (<=1024 / <=640)
     9. Cibles tactiles (<=640)
    10. Hover -> touch (@media (hover:none))
    11. Page index (LOT 1bis) : #stackv carrousel à swipe, ruban de statut,
        titres XL, #departs (<=1024)
    12. Hero / planisphère mobile (LOT 3 + LOT 4) : fond lisible, flèches de zone
    13. Volet espèces mobile (#mobSpecies)
    14. Heros de page "titre seul" réduits de moitié (LOT 6 - 22/07) : offres,
        présentation/équipe/charte/actions-nature, accompagnateurs, récits,
        sur-mesure. Ne touche PAS voyage/pays/animal/accompagnateur/récit (hero
        avec contenu réel, pas de classe .vf-hero--page).
   ========================================================================== */


/* ==========================================================================
   1. MENU MOBILE - BASE
   Composants NEUFS (n'existent pas dans style.css) injectés par js/mobile.js.
   Masqués par défaut ; l'affichage est rendu en §4 sous <=1024px.
   ========================================================================== */
.mob-fab,
.mob-burger,
.mob-menu,
.hero-zonenav,
.an-panel-bar{ display:none; }


/* ==========================================================================
   2. TOKENS MOBILE (<=640px)
   L'échelle typo du site est centralisée dans :root (--fs-*) et AUCUN composant
   ne porte de font-size en dur (cf. commentaire style.css l.33-35) : redéfinir
   les tokens ici rebascule tout le site d'un coup, sans toucher un composant.
   Seules les valeurs qui posent réellement problème au téléphone sont changées.
   ========================================================================== */
@media (max-width:640px){
  :root{
    /* --fs-title était clamp(40px,5.6vw,76px) : plancher 40px -> ~8 caractères
       par ligne sur un 375px. Plancher descendu à 30px, plafond mobile 52px. */
    --fs-title: clamp(30px, 8vw, 52px);
    /* les 5 autres tokens typo (h3 20 / body 18 / small 15 / label 13 / nav 14)
       et --btn-h (52px, = cible tactile mini) tiennent tels quels au téléphone. */
    --gutter: clamp(16px, 4vw, 64px);
  }

  /* Respiration verticale des sections : 70px en haut ET en bas d'une section
     sur un écran de 667px de haut, c'est un cinquième de l'écran perdu. */
  section[id]{ padding:clamp(48px, 9vw, 130px) 0; }
}


/* ==========================================================================
   3. HEADER MOBILE (<=1024px)
   Logo SEUL, centré. Hauteur fixe 72px, pas de collapse au scroll.
   Le menu, le CTA Contact et le burger d'origine restent DANS LE DOM
   (display:none) : aucun recalcul de grille, aucun risque de régression.
   ========================================================================== */
@media (max-width:1024px){
  :root{
    /* Les 3 hauteurs de header passent à 72px. Comme .nav et
       .site-header.is-solid .nav lisent ces variables, le collapse au scroll
       devient un non-événement : le header garde 72px en permanence.
       --header-h est également relu par js/main.js (garde mobile posée dans
       main.js), donc TOUS les sticky se calent bien sur 72px.
       BUG CORRIGÉ (LOT 6, 22/07, cause racine du logo header qui bougeait) :
       ce bloc contenait, à la place de ce paragraphe, un commentaire CSS
       refermé PAR ERREUR en plein milieu par une paire de délimiteurs de
       commentaire imbriquée (CSS ne sait pas imbriquer les commentaires) -
       tout le texte qui suivait jusqu'à la prochaine ponctuation de fin de
       déclaration retombait en CSS invalide et était donc AVALÉ par le
       parseur, --nav-h y compris. --nav-h restait donc à 112px (style.css)
       alors que --nav-h-collapsed et --header-h passaient bien à 72px juste
       en dessous, vérifié via rule.style.cssText en DevTools - d'où le
       header 112px au chargement puis 72px dès le premier scroll (bascule
       .is-solid, qui lit --nav-h-collapsed, correcte celle-là). */
    --nav-h:           72px;
    --nav-h-collapsed: 72px;
    --header-h:        72px;
  }

  /* LOT 11 (24/07), retour Nicolas « le logo semble décentré vers la droite » : la barre
     redevient une simple BOÎTE FLEX CENTRÉE (voir .nav__logo ci-dessous), au lieu de la
     grille desktop 3 colonnes dans laquelle le logo était positionné en absolu. */
  .nav{ position:relative; gap:0; padding-inline:0;
    display:flex; align-items:center; justify-content:center; }

  /* LOT 2 : filet de sécurité pour toute ancre (#departs, #photographes...) qui atterrirait SOUS
     le header fixe - le scroll piloté par Lenis (js/main.js anchorLinks) calcule déjà son propre
     offset depuis --header-h, mais un lien d'ancre natif (retour navigateur, Lenis non chargé,
     futur ajout) doit rester correct sans dépendre du JS. */
  section[id]{ scroll-margin-top:72px; }

  /* Logo centré dans la barre.
     3 classes -> bat .site-header.is-solid .nav__logo (3 classes) par l'ordre.
     LOT 11 (24/07), retour Nicolas : le logo était centré par `position:absolute; left:50%`
     DANS une grille CSS (.nav, display:grid côté style.css). Or le bloc conteneur d'un enfant
     ABSOLU d'une grille n'est pas interprété de la même façon partout : Chrome prend la boîte
     de padding du conteneur de grille (mesuré ici : centre à 187,5px pour 375px de large, dans
     les 3 états haut de page / scrollé / menu ouvert - donc rien à corriger côté Chrome), mais
     WebKit peut prendre la ZONE DE GRILLE de l'élément, qui est vide et collapsée à 0 ici (les
     2 autres colonnes, menu + CTA, sont en display:none) -> logo décalé sur un vrai iPhone,
     invisible en device mode. On retire donc l'absolu : .nav redevient une boîte flex centrée
     (ci-dessus) et le logo, seul enfant visible, est centré par le flux. Aucun moteur ne peut
     plus diverger. */
  .site-header .nav .nav__logo{
    position:relative;
    left:auto; top:auto;
    transform:none;
    justify-self:unset;
    height:52px;
  }

  /* ---- APLAT CLAIR PERMANENT derrière le logo - LOT 11 (24/07), retour Nicolas :
     « pour protéger le logo je mettrais tout le temps un aplat blanc comme pour la section
     Voyages à ne pas manquer ». En desktop le header a 4 états pilotés par main.js selon la
     section survolée (.is-solid noir / .on-light crème / .on-dark sombre translucide /
     .on-hero transparent au-dessus du planisphère) : en mobile on fige l'état .on-light,
     c'est-à-dire EXACTEMENT l'aplat de la section citée (var(--creme) + la même ombre douce,
     style.css l.229) - aucune couleur nouvelle n'est introduite ici.
     ⚠️ Spécificité : les règles à battre montent à 3 classes (.site-header.on-hero.on-dark),
     on reprend donc la même liste de sélecteurs - mobile.css charge après style.css, l'ordre
     de cascade suffit, aucun !important. */
  .site-header,
  .site-header.is-solid,
  .site-header.on-light,
  .site-header.on-dark,
  .site-header.on-hero,
  .site-header.on-hero.is-solid,
  .site-header.on-hero.on-dark{
    background:var(--creme);
    -webkit-backdrop-filter:none; backdrop-filter:none;
    box-shadow:0 6px 24px rgba(0,0,0,.10);
  }
  /* Le logo suit : sur fond clair c'est la VRAIE version à texte noir qui doit s'afficher
     (les 2 SVG sont superposés et pilotés en opacité, style.css l.187-194) - sinon le logo
     blanc devient invisible sur l'aplat crème. Même parade de spécificité. */
  .site-header .nav__logo-img--light,
  .site-header.on-dark .nav__logo-img--light{ opacity:0; }
  .site-header .nav__logo-img--dark,
  .site-header.on-dark .nav__logo-img--dark{ opacity:1; }

  /* Navigation desktop : présente dans le DOM, invisible. */
  .nav__menu,
  .nav__cta,
  .nav__burger{ display:none; }
}


/* ==========================================================================
   4. PILULE FLOTTANTE - retour · burger · haut de page (<=1024px)
   Parti pris Fix (spécification figée, cf. définition §3) : UNE SEULE pilule
   flottante bas-centre qui regroupe les 3 contrôles mobiles. Le bouton du
   milieu ouvre/ferme le volet (les 3 barres deviennent une croix, sur place),
   volet qui monte du bas, logo centré en haut.
   Structure/mécanique (pilule à 3 contrôles) reprises d'une barre déjà
   construite et éprouvée par Fix sur un autre site (DropZone-Gaming :
   templates/layout.php l.583-596 + assets/css/main.css bloc MOBILE BOTTOM BAR
   l.5454-5549) - MAIS l'habillage (couleurs, fond, ombres) est entièrement
   recomposé sur les tokens Objectif Nature : la référence est un site gaming
   cyan/sombre, AUCUNE de ses couleurs n'est reprise ici.
   LOT 4 (22/07), revirement Fix : la pilule NE S'EFFACE PLUS JAMAIS au
   défilement (l'effacement du LOT 2 est retiré, voir plus bas) - « elle doit
   être par-dessus tout le site, à tous les endroits ».
   ========================================================================== */
@media (max-width:1024px){

  /* ---- La pilule (toujours AU-DESSUS du volet 1300 ET du header 1000) ---- */
  .mob-fab{
    display:flex; align-items:center; gap:4px;
    position:fixed;
    /* LOT 11 (24/07), retour Nicolas : « à l'arrivée sur le site la pilule est légèrement
       coupée, puis vient se mettre en bonne position au scroll ». Cause : un élément
       `position:fixed` se cale sur le viewport LARGE (`vh` = `lvh` = barre d'URL rétractée),
       alors qu'au chargement la barre d'URL est DÉPLOYÉE - le bas de la pilule tombe donc
       sous la zone réellement visible, et "revient" dès que le premier défilement rétracte
       la barre. `100vh - 100dvh` vaut exactement la hauteur de la barre du moment (0 quand
       elle est rétractée, donc rien ne bouge une fois en place) : la pilule garde un écart
       constant au bas VISIBLE, à tout instant. `env(safe-area-inset-bottom)` traite le cas
       distinct de la barre d'accueil iPhone (indicateur home).
       ⚠️ Invisible en device mode Chrome (aucune barre d'URL) : validation sur téléphone.
       LOT 12 (26/07), retour Nicolas sur iPhone : « le bouton est un peu haut dans la
       page ». La compensation ci-dessus était FAUSSE sur iOS - `100vh - 100dvh` mesure
       la somme des DEUX barres (URL en haut + outils en bas, ~118px), et Safari cale
       déjà `position:fixed` sur le viewport VISIBLE : la pilule était donc remontée une
       deuxième fois, d'où les ~170px d'écart au-dessus de la barre d'outils. Retirée.
       Demande Fix dans la foulée : « il faut le placer en bas de page » -> l'écart de
       repos passe de clamp(20px,4vw,32px) à 8px ; la pilule est posée au bas de la zone
       visible, juste au-dessus de la zone sûre de l'appareil (indicateur home). */
    bottom:calc(8px + env(safe-area-inset-bottom, 0px));
    left:50%;
    transform:translateX(-50%);
    z-index:1400;
    padding:4px;
    border-radius:999px;
    background:rgba(14,14,14,.92);
    -webkit-backdrop-filter:blur(16px);
    backdrop-filter:blur(16px);
    box-shadow:0 8px 28px -6px rgba(0,0,0,.45);
    transition:transform .3s var(--ease), opacity .3s var(--ease);
  }
  /* LOT 4 (22/07), revirement Fix : PLUS D'EFFACEMENT au défilement (le mécanisme
     fabAutoHide de js/mobile.js est retiré, ainsi que la classe .mob-fab--hide qui
     allait avec) - « la pilule doit être par-dessus tout le site, à tous les endroits ».
     La parade au chevauchement passe désormais par le CONTENU : chaque section
     réserve sa propre marge basse (cf. §11/§7 plus bas) plutôt que de faire
     disparaître le contrôle. */

  /* Retour / haut de page : ronds transparents sur le fond de la pilule, cible >= 44px */
  .mob-fab__btn{
    display:flex; align-items:center; justify-content:center; line-height:1;
    width:44px; height:44px; border-radius:50%; flex:0 0 auto;
    background:none; border:none; color:var(--blanc); cursor:pointer;
    touch-action:manipulation;
  }
  .mob-fab__btn:disabled{ opacity:.3; pointer-events:none; }   /* pas d'historique -> inactif */

  /* Haut de page : c'est le VRAI #scrollTop desktop, reparenté dans la pilule par js/mobile.js
     (mêmes écouteurs main.js, inchangés) - toujours visible ICI (3 contrôles fixes dans la
     pilule), sa logique .is-visible d'origine (apparition après 400px de scroll) ne vaut que
     pour son ancienne position flottante desktop. */
  .mob-fab .scroll-top{
    position:static; width:44px; height:44px;
    opacity:1; visibility:visible; transform:none;
    background:none; color:var(--blanc); box-shadow:none;
  }

  /* Burger : pastille JAUNE DOMINANTE (52px), légèrement en avant du reste de la pilule -
     seul élément qui n'est PAS transparent, pour rester l'évidence visuelle du groupe. */
  .mob-burger{
    display:flex;
    position:relative;
    margin:-4px 3px;                /* dépasse légèrement la pilule en haut/bas : pop visuel */
    z-index:1;
    width:52px; height:52px;        /* cible tactile : 52px > 44px */
    border-radius:50%;
    background:var(--jaune);
    color:var(--noir);
    border:none; padding:0;
    cursor:pointer;
    touch-action:manipulation;      /* supprime le délai de 300ms au tap */
    align-items:center; justify-content:center; flex-direction:column; gap:5px;
    box-shadow:0 6px 16px -4px rgba(0,0,0,.5);
    transition:background .2s var(--ease), box-shadow .2s var(--ease);
  }
  .mob-burger .burger-line{
    display:block; width:22px; height:2px;
    background:var(--noir); border-radius:2px;
    transform-origin:center;
    transition:transform .3s var(--ease), opacity .3s var(--ease);
  }
  /* Burger -> croix : piloté par l'attribut ARIA, pas par une classe en plus
     (l'état visuel et l'état accessible ne peuvent donc pas diverger). */
  .mob-burger[aria-expanded="true"] .burger-line:nth-child(1){ transform:translateY(7px) rotate(45deg); }
  .mob-burger[aria-expanded="true"] .burger-line:nth-child(2){ opacity:0; transform:scaleX(0); }
  .mob-burger[aria-expanded="true"] .burger-line:nth-child(3){ transform:translateY(-7px) rotate(-45deg); }

  /* ---- Le volet ---- */
  .mob-menu{
    display:flex;
    position:fixed; inset:0; height:100dvh; z-index:1300;   /* > header (1000) : le volet doit recouvrir le header, pas passer dessous */
    background:rgba(14,14,14,.94);
    -webkit-backdrop-filter:blur(20px);
    backdrop-filter:blur(20px);
    transform:translateY(100%);
    transition:transform .4s cubic-bezier(.22,.61,.36,1);
    flex-direction:column; align-items:center;
    /* Le volet est plus haut que l'écran (logo + 9 entrées + 4 sous-entrées +
       Contact) -> c'est LUI qui défile, pas le fond de page. data-lenis-prevent
       (posé en JS par mobile.js) + lenis.stop()/start() à l'ouverture/fermeture
       empêchent Lenis de capter le geste à la place du scroll natif ci-dessous
       (piège déjà documenté dans le CLAUDE.md du projet). */
    overflow-y:auto;
    -webkit-overflow-scrolling:touch;
    overscroll-behavior:contain;
    scrollbar-width:none;
  }
  .mob-menu::-webkit-scrollbar{ display:none; }
  .mob-menu.is-open{ transform:translateY(0); }

  .mob-menu__logo{
    position:absolute; left:50%;
    /* LOT 4 (22/07), retour Fix : collé tout en haut du volet - le volet RECOUVRE
       déjà le header (z-index 1300 > 1000), donc rien à dégager en-dessous de lui ;
       l'ancien offset de 72px (hauteur header) était une marge morte. Gain ~56px
       reversé aux entrées ci-dessous (.mob-menu__nav padding-top).
       LOT 11 (24/07), retour Nicolas : « quand la pilule est en bonne position et qu'on
       ouvre le menu, cela coupe le logo Objectif Nature en haut du volet ». Même famille
       de cause que la pilule ci-dessus, à l'autre bout : le volet est `position:fixed;
       inset:0`, donc son `top:0` est celui du viewport LARGE - une fois la barre du
       navigateur rétractée (donc précisément « quand la pilule est en bonne position »),
       ce haut passe DERRIÈRE la barre minimisée et rogne le logo. On ajoute la zone sûre
       de l'appareil (encoche/barre d'état) et on relève le plancher de 14 à 24px pour que
       quelques pixels de chrome navigateur ne mordent plus dessus. Le padding-haut des
       entrées (arithmétique ci-dessous) suit la MÊME formule, sinon le logo repasserait
       par-dessus la première entrée. */
    top:calc(env(safe-area-inset-top, 0px) + clamp(24px,3.5vw,30px));
    transform:translateX(-50%);
    height:34px; width:auto;
    opacity:0; transition:opacity .4s ease .2s;
  }
  .mob-menu.is-open .mob-menu__logo{ opacity:1; }

  /* ARITHMÉTIQUE DU VOLET : le padding haut dégage le logo (collé en haut,
     ci-dessus), le padding bas dégage le burger flottant. Sans ça, la dernière
     entrée passe SOUS le bouton et devient intappable.
     LOT 1bis (22/07) : densifié — 6 entrées + sous-menu fermé + Contact
     doivent tenir SANS défilement sur un écran de 667px (retour Fix, mesuré
     881px avant correctif -> le sous-menu s'affichait entièrement déplié en
     permanence, cf. .mob-menu__sub ci-dessous). Le défilement (overflow-y du
     .mob-menu lui-même, §4 plus haut) reste en filet de sécurité.
     LOT 4 (22/07) : padding-top allégé de 126px à ~74px (logo recollé en haut,
     ci-dessus) - gain de 52px rendu aux entrées.
     LOT 11 (24/07) : le haut suit le nouvel offset du logo (zone sûre de l'appareil +
     30px au lieu de 22px) - la formule reste « offset du logo + hauteur du logo (34px) +
     respiration (18px) », toujours calée sur .mob-menu__logo, jamais recopiée en dur.
     Le bas suit la pilule : même formule qu'elle (§4), pour que la dernière entrée ne
     puisse jamais repasser dessous.
     LOT 12 (26/07) : la pilule est descendue en bas de page (compensation 100vh-100dvh
     retirée, écart de repos 8px) - la réserve suit, sinon ~150px de vide en bas du volet. */
  .mob-menu__nav{
    width:100%;
    margin:0;
    padding:calc(env(safe-area-inset-top, 0px) + 30px + 34px + 18px) 24px
            calc(52px + 8px + env(safe-area-inset-bottom, 0px) + 14px);
    list-style:none;
    display:flex; flex-direction:column; align-items:stretch;
  }
  .mob-menu__nav > li > a,
  .mob-menu__nav > li > .mob-menu__trig{
    display:flex; align-items:center; justify-content:center; gap:6px;
    width:100%; text-align:center;
    font-family:var(--serif); font-weight:400;
    font-size:clamp(17px,4.6vw,21px); line-height:1.2;
    color:var(--blanc);
    padding:12px 0;                          /* + line-height -> cible >= 44px de haut */
    border-bottom:1px solid rgba(255,255,255,.1);
    text-decoration:none;
    background:none; border-left:none; border-right:none; border-top:none;
    cursor:pointer; touch-action:manipulation;
    opacity:0; transform:translateY(14px);
    transition:opacity .3s ease, transform .3s ease, color .2s;
    transition-delay:var(--d, 0s);
  }
  .mob-menu.is-open .mob-menu__nav > li > a,
  .mob-menu.is-open .mob-menu__nav > li > .mob-menu__trig{ opacity:1; transform:translateY(0); }

  /* Page courante : même code couleur que le menu desktop.
     (spécificité : doit battre la règle générale .mob-menu__nav > li > .mob-menu__trig
     ci-dessus -> même chemin + .is-current, pas juste .mob-menu__trig.is-current seul.) */
  .mob-menu__nav > li.is-active > a,
  .mob-menu__nav > li > a[aria-current="page"],
  .mob-menu__nav > li > .mob-menu__trig.is-current{ color:var(--jaune); }

  /* Chevron de l'accordéon « Qui sommes-nous » : tourne à l'ouverture. */
  .mob-menu__chev{ transition:transform .25s var(--ease); }
  .mob-menu__trig[aria-expanded="true"] .mob-menu__chev{ transform:rotate(180deg); }

  /* SOUS-ENTRÉES « Qui sommes-nous » — ACCORDÉON replié par défaut (retour Fix
     22/07) : le méga-menu desktop est en :hover pur (mort au doigt) ET la
     version précédente les affichait TOUJOURS dépliées (4 lignes en trop en
     permanence). Un seul niveau, pas de survol : fermé tant que
     .mob-menu__trig n'a pas été tapé (aria-expanded piloté par mobile.js). */
  .mob-menu__sub{
    list-style:none; margin:0; padding:0;
    max-height:0; overflow:hidden;
    display:flex; flex-direction:column; align-items:center;
    transition:max-height .3s var(--ease);
  }
  .mob-menu__sub.is-open{ max-height:260px; padding:0 0 6px; }
  .mob-menu__sub > li > a{
    display:block; text-align:center;
    font-family:var(--sans);
    /* LOT 11 (24/07), retour Nicolas : « interlignage plus petit entre le bouton du sous-menu
       de Qui sommes-nous et ses entrées, et typo des items du sous-menu réduite d'un point ».
       --fs-small (15px) -> 14px, padding 12 -> 8px, et le petit padding haut du bloc déplié
       est retiré (le sous-menu se recolle à son bouton).
       ⚠️ La cible tactile de CES entrées passe d'environ 44px à ~36px : même arbitrage que
       celui déjà accepté explicitement par Fix pour les liens du footer au LOT 10. Aucune
       autre cible du site n'est concernée. */
    font-size:14px;
    color:rgba(255,255,255,.62);
    padding:8px 14px;
    text-decoration:none;
    touch-action:manipulation;
  }
  .mob-menu__sub > li > a[aria-current="page"]{ color:var(--jaune); }

  /* Entrée Contact : mise en avant, pas de filet du bas. */
  .mob-menu__nav > li.mob-menu__cta > a{
    color:var(--jaune);
    border-bottom:none;
    margin-top:8px;
  }

  /* Volet ouvert : la pilule (donc le burger, qui doit rester le bouton de fermeture) reste
     TOUJOURS visible par-dessus - plus de règle qui l'efface ici (elle a été retirée : la
     spécification figée exige explicitement que la pilule reste visible volet ouvert). */
}

@media (prefers-reduced-motion: reduce){
  .mob-menu{ transition:none; }
  .mob-menu__nav > li > a,
  .mob-menu__nav > li > .mob-menu__trig,
  .mob-menu__sub{ transition:none; transition-delay:0s; }
  .mob-burger .burger-line{ transition:none; }
}


/* ==========================================================================
   5. PLEIN ÉCRAN : vh -> dvh / svh (<=1024px)
   Sur iOS/Android, 100vh = hauteur AVEC la barre d'URL rétractée -> un bloc en
   100vh dépasse toujours de l'écran visible. dvh suit la barre d'URL ;
   svh est la valeur STABLE (barre déployée), utilisée là où deux valeurs
   doivent rester rigoureusement égales entre elles.
   ========================================================================== */
@media (max-width:1024px){
  /* LOT 11 (24/07), retour Nicolas « les images du hero sont trop grosses » + arbitrage Fix
     (« raccourcir le hero ») : les 3 photos font 2560x1428 (16:9) et le cadre mobile est en
     9:16 -> en `cover`, l'image est calée sur la HAUTEUR du cadre et c'est la largeur qui
     déborde : à 375x667 on n'en voyait que 31 %. Le zoom ne dépend donc PAS de la taille du
     cadre mais de son RAPPORT : plus le cadre est haut, plus la photo est rognée en largeur.
     -> on raccourcit le cadre. `min(120vw, 78dvh)` garde un rapport constant quel que soit le
     téléphone (à 375px : 450px de haut -> 46 % de la photo visible au lieu de 31 %) sans jamais
     dépasser les 3/4 de l'écran ; le plancher 420px garantit que le bloc titre + texte
     (225px mesurés) + le header (72px) + l'indicateur de scroll tiennent toujours. */
  .intro-hero{ height:min(120vw, 78dvh); min-height:420px; }
  .hero{ height:100dvh; min-height:100dvh; }
  .cfiche{ height:80dvh; }
  /* LOT 7 (22/07), retour Fix : la section faisait pile 100dvh et le texte (centré par
     .feature{align-items:center}, non touché) occupait toute la hauteur visible dès l'arrivée -
     aucun bout de vidéo n'était visible avant lui. +72px de hauteur -> le flex centré répartit
     l'espace en trop pour moitié AU-DESSUS de la carte texte (un peu de vidéo apparaît en
     premier) et pour moitié en dessous. .feature__fix (couche vidéo "fenêtre découpée", pilotée
     par featureFixedBg dans main.js sur la hauteur RÉELLE de #feature, cf. commentaire JS) reste
     à 100dvh : c'est la fenêtre fixe elle-même, pas la section - rien à changer là. */
  .feature{ min-height:calc(100dvh + 72px); }
  .feature__fix{ height:100dvh; }
  .py-culture__bg, .band-img__bg{ height:100dvh; }

  /* Popups « Poser une option » / « S'inscrire ». */
  .opt-overlay{ padding:clamp(16px,4dvh,48px); }
  /* LOT 11 (24/07), retour Nicolas : « on peut bouger le formulaire vers la gauche
     horizontalement » sur « S'inscrire » et « Poser une option », mais pas sur « Nous
     contacter ». `.opt` est le conteneur de défilement de la popup (overflow:auto,
     style.css l.2432) : il défile donc AUSSI en horizontal dès qu'un enfant dépasse.
     Trouvé à la mesure : la barre d'action collante du formulaire d'inscription
     (`.ins-nav`) sort volontairement de la colonne de texte par des marges négatives
     de 24px pour venir toucher les bords de la popup (`margin:18px -24px -24px`,
     style.css l.2572) - c'est un débord VOULU, mais sur un écran étroit il devient une
     course de défilement. « Nous contacter » n'a ni cette barre ni l'en-tête récap,
     d'où l'absence du défaut là-bas, exactement comme constaté.
     On garde le débord (il est juste, la barre doit toucher les bords) et on supprime la
     COURSE : le défilement de la popup redevient strictement vertical. Le débord est alors
     rogné pile aux bords de la popup, c'est-à-dire là où il s'arrêtait déjà - aucun pixel
     visible en moins. */
  .opt{ max-height:92dvh; overflow-x:hidden; }

  /* Galerie plein écran (lightbox) */
  .gal-lb__img{ max-height:calc(100dvh - 230px); }
  .gal-lb--solo .gal-lb__img{ max-height:calc(100dvh - 80px); }
}
@media (max-width:640px){
  /* même offset que style.css:3026, juste vh -> dvh (règle plus étroite, gagne à cette largeur) */
  .gal-lb__img{ max-height:calc(100dvh - 190px); }
}

/* LOT 1bis (22/07) : .about-pin__sticky vh->dvh RESTREINT à 861-1024px. En dessous, style.css a
   SA PROPRE MQ (max-width:860px) qui DÉPIN déjà la section "Qui sommes-nous" (position:static;
   height:auto) - la mettre ici sans restriction (comme les autres sélecteurs ci-dessus) la
   REBASCULAIT en hauteur FIXE (calc(100dvh - header), soit 595px mesurés à 375x667) par-dessus
   cette dépin, alors que mobile.css est chargé APRÈS style.css et gagne à spécificité égale :
   la grille empilée (4 cellules, 1591px mesurés) débordait alors de ~476px hors de la section
   (position:static + overflow:visible + hauteur EXPLICITE du parent -> le débordement n'agrandit
   jamais la boîte parente), texte des 2 dernières cellules coupé. Au-dessus de 860px la pin
   desktop reste active (pas de dépin côté style.css) : le correctif dvh y garde son utilité. */
@media (min-width:861px) and (max-width:1024px){
  .about-pin__sticky{ height:calc(100dvh - var(--header-h, 112px)); }
}


/* ==========================================================================
   6. GRILLES GÉNÉRIQUES (<=1024 : 2 colonnes / <=640 : 1 colonne)
   NB : .of-grid (900px -> 1fr), .gd-grid (1100/760/440), .pg-bloc__grid
   (900px -> 1fr) et .eq-grille__grid (auto-fit minmax 270px) ont DÉJÀ leurs
   propres paliers dans style.css - on ne pose rien dessus pour ne pas créer
   deux règles concurrentes. Seules les grilles qui restaient en 3 ou 4
   colonnes jusqu'au téléphone sont traitées ici.
   ========================================================================== */
@media (max-width:1024px){
  .depforts__grid,
  .blog__grid,
  .testimonials__grid{ grid-template-columns:repeat(2,1fr); }
  .footer__top{ grid-template-columns:1fr 1fr; gap:clamp(20px,4vw,36px); }

  /* LOT 4 (22/07), trouvaille de l'audit templates : `.vf-sejour__grid` passe déjà
     à 1 colonne dès 980px (style.css l.1771, non modifié) - mais ses 2 enfants
     (.vf-timeline/.vf-side, fiche voyage) gardent min-width:auto par défaut -> un
     enfant de grille garde pour minimum SON PROPRE min-content, qui dépassait le
     tracé "1fr" de 32px (mesuré sur voyage.html?t=V1 à 375px, MASQUÉ par le
     html,body{overflow-x:hidden} de style.css - même piège que le footer plus
     haut). Root-cause générique CSS Grid, même famille de correctif. */
  .vf-sejour__grid > *, .vf-duo > *, .vf-esprit__grid > *, .vf-contact__grid > *{ min-width:0; }
  /* même piège UN CRAN PLUS BAS : .vf-jour (flex) -> .vf-jour__body (flex:0 1 auto,
     min-width:auto par défaut) débordait encore de la carte "jour" une fois le
     grid-parent corrigé ci-dessus. */
  .vf-jour__body{ min-width:0; }

  /* Trouvaille de l'audit templates (fiche voyage, cartes "Rencontre") : le tag
     ".vf-jour__tag" (icône + "Rencontre · <animal>") est un inline-flex SANS
     flex-wrap - à l'étroit (~166px mesurés), le flex-shrink par défaut réduisait
     l'ICÔNE à 0px de large et repliait le texte sur 2 lignes, faisant flotter le
     nom de l'espèce à mi-hauteur, décroché de "Rencontre" (lisibilité cassée,
     règle 4bis). L'icône ne doit jamais rétrécir ; le reste peut passer à la
     ligne EN BLOC (flex-wrap) plutôt que de se redécouper mot à mot. */
  .vf-jour__tag{ flex-wrap:wrap; row-gap:2px; }
  .vf-jour__tag svg{ flex-shrink:0; }
}

@media (max-width:640px){
  .depforts__grid,
  .blog__grid,
  .testimonials__grid{ grid-template-columns:1fr; gap:clamp(16px,4vw,24px); }
  /* footer__top reste à 2 colonnes même au téléphone (voir §7, LOT 4, 22/07) -
     règle Fix : "2 colonnes plutôt qu'une longue pile" pour réduire la hauteur. */
}


/* ==========================================================================
   7. FOOTER (<=1024px)
   C'est le composant le plus cassé du site en mobile. En desktop les liens sont
   posés en ABSOLU (bottom:24px) par-dessus une scène décorative dont la hauteur
   suit la LARGEUR (images 1800x720, ratio 2,5:1) : à 375px la scène ne fait plus
   que ~150px de haut alors que les liens en font ~600 -> tout déborde.
   -> en mobile, les liens repassent EN FLUX NORMAL sous la scène.
   ========================================================================== */
@media (max-width:1024px){
  /* Parallaxe coupée : --links-y n'a plus de sens une fois en flux. */
  .footer__links{
    position:relative;
    left:auto; right:auto; bottom:auto;
    transform:none;
    will-change:auto;
    background:#0a0704;                      /* fond opaque : plus de dégradé */
    /* Réserve basse = hauteur de la pilule + son décalage + une marge de confort.
       Cette marge est passée de 28 à 56px (suggestion de Fix, 22/07) : au repos "bas de page",
       le dégagement sous le dernier lien passe de 27 à ~55px, et surtout la course de
       défilement supplémentaire permet de remonter n'importe quel lien du footer AU-DESSUS
       de la bande de la pilule - ce que la réserve précédente ne garantissait pas. */
    padding:clamp(28px,6vw,48px) 0
            calc(52px + clamp(20px,4vw,32px) + 56px);
  }
  .footer__links::before{ display:none; }    /* voile dégradé du desktop */
  .site-footer::after{ display:none; }       /* masque bas de la scène */
  .footer__scene{ pointer-events:none; }

  /* LOT 2 (22/07) : la scène suivait la LARGEUR (ratio 1800:720 des calques) -> à 375px elle ne
     fait plus que ~150px de haut et le grand logo (course JS de +210 à -55px, réglée pour une
     scène desktop ~600-700px) tourne entièrement HORS CADRE, dans le vide. Décision Fix : hauteur
     UTILE forcée, calques recadrés dessus (object-fit:cover, ancrés sur le bas = le sol/la colline
     ne bouge pas), logo redimensionné + repositionné pour une VRAIE course dans ce cadre plus
     court. .site-footer garde son overflow:hidden (style.css) : tout excédent de course reste
     proprement coupé, pas besoin d'y toucher. */
  .footer__scene{ height:clamp(220px,58vw,300px); }
  .footer__back,
  .footer__front{
    position:absolute; inset:0; width:100%; height:100%;
    object-fit:cover; object-position:center bottom;   /* ancre le sol -> ne recadre que le ciel */
    margin-bottom:0;
  }
  /* Le front gardait sa translation desktop translate(-50%, --front-y) : sans le left:50% qui
     allait avec (remplacé par inset:0 ci-dessus), -50% l'aurait décalé d'une demi-largeur hors champ. */
  .footer__front{ left:0; transform:translateY(var(--front-y,0px)); }
  /* Logo : plus petit (la scène est bien plus basse), centré aux 2/3 -> la course réduite du JS
     (cf. /* mobile: */ dans main.js footerParallax) le fait émerger visiblement depuis derrière la
     colline (front, z-index:3 > logo z-index:2) au lieu de rester cadré en dur. */
  .footer__biglogo{ width:min(52%,210px); top:66%; }

  /* LOT 4 (22/07), retour Fix : "diminuer l'espace vertical et réorganiser les
     éléments... sur 2 colonnes... qu'ils prennent moins de place en hauteur" - la
     grille §6 pose déjà 2 colonnes (repassait à 1 seule/longue pile au téléphone
     avant ce lot, cf. §6) ; ici on resserre le gap + centre le contenu de chaque
     bloc pour un rendu compact en 2x2 plutôt qu'un empilement de 4 blocs pleine
     largeur alignés à gauche. */
  .footer__top{ padding-bottom:24px; gap:clamp(20px,5vw,36px) clamp(16px,4vw,28px); }
  /* min-width:0 sur les 4 items de la grille : un enfant de grille garde par défaut
     min-width:auto (= le min-content de SON contenu) -> le champ e-mail (largeur
     min intrinsèque d'un <input>, ~200px dans Chrome) forçait sa colonne à déborder
     du cadre de 29px (mesuré à 375px, MASQUÉ par le html,body{overflow-x:hidden} de
     style.css - piège documenté dans le CLAUDE.md, trouvé ici à la mesure du scroll
     réel plutôt qu'à l'oeil). Root-cause fix générique CSS Grid, pas un correctif
     du seul champ newsletter. */
  .footer__brand, .footer__col, .footer__news{ min-width:0; }
  .footer__brand, .footer__news{ text-align:center; }     /* blocs simples (pas flex) */
  .footer__col{ align-items:center; text-align:center; }  /* flex column (style.css) */
  .footer__soc{ justify-content:center; }

  /* LOT 5 (22/07), demande Fix : "le champ e-mail A CÔTÉ des réseaux sociaux, ce qui
     permet de mettre Agence et Nos offres CÔTE À CÔTE" - le DOM reste dans son ordre
     (brand, col "Nos offres", col "L'agence", news) car le desktop l'utilise tel quel
     (4 colonnes sur 1 ligne, style.css) ; seul l'ordre visuel de la grille 2 colonnes
     mobile change, via `order` (grid en auto-flow row : order 1/2 -> ligne 1, 3/4 ->
     ligne 2). Aucune règle desktop touchée, `order` est ignoré au-dessus de 1024px. */
  .footer__brand{ order:1; }
  .footer__news{ order:2; }
  .footer__col:nth-of-type(1){ order:3; }  /* "Nos offres" */
  .footer__col:nth-of-type(2){ order:4; }  /* "L'agence" */

  /* LOT 6 (22/07), retour Fix "marge pour la pilule" : à la position de repos "haut du
     footer aligné au haut de l'écran" (méthode d'audit §4bis), mesuré sur 375x667 - les 2
     PREMIERS liens de CHAQUE colonne tombaient dans la bande de la pilule (596-647px) : le
     1er lien (558-603px) la chevauchait déjà de 8px, le 2e (611-655px) y était presque
     entièrement. Cause : ~276px de bloc "brand + newsletter" au-dessus des colonnes, sur un
     écran de 667px de haut. Correctif PRIS SUR L'ESPACE MORT (règle §4ter) : row-gap de la
     grille resserré ici (ne touche PAS le column-gap qui espace les 2 colonnes de liens ni
     le gap ENTRE deux liens, cf. §9). Gagne les 2 colonnes ~18px plus haut - marge de
     sécurité mesurée (pas juste l'absence de recouvrement), vérifiée aussi 393x852/768x1024
     (aucun risque : plus l'écran est haut, plus la marge est grande). */
  .footer__top{ row-gap:6px; }
}

@media (max-width:640px){
  .footer__bottom{
    flex-direction:column;
    align-items:center;
    gap:10px;
    text-align:center;
  }
  /* Champ e-mail + bouton CÔTE À CÔTE (Fix 22/07), dans une colonne de ~164px : un bouton
     portant le mot « S'inscrire » n'y tient pas. Le bouton devient donc une pastille flèche
     de 44px (cible tactile respectée), et le libellé passe en aria-label -> il reste lu par
     les lecteurs d'écran, rien n'est perdu pour l'accessibilité. Le texte du bouton est
     masqué visuellement, pas supprimé du DOM (le desktop l'affiche toujours). */
  .footer__form{ flex-wrap:nowrap; align-items:center; gap:8px; }
  .footer__form input{ flex:1 1 auto; min-width:0; }
  /* anneau de focus du navigateur = BLEU, hors charte. Sur un champ de saisie on le GARDE
     (l'utilisateur doit voir où il tape) : on le redessine simplement en jaune. */
  .footer__form input:focus{ outline:2px solid var(--jaune); outline-offset:1px; }
  .footer__form .btn{
    flex:0 0 auto; height:44px; min-height:44px; padding:0 14px;
    display:flex; align-items:center; justify-content:center; white-space:nowrap;
    font-size:0;                       /* masque « S'inscrire » sans le retirer du DOM */
  }
  /* « Valider » plutôt que « S'inscrire » en mobile (Fix 22/07) : le libellé desktop est validé
     par la cliente et ne doit pas changer dans le HTML -> on l'affiche par contenu généré,
     le vrai texte reste dans le DOM et l'aria-label porte l'intitulé complet. */
  .footer__form .btn::after{ content:'Valider'; font-size:var(--fs-small); font-weight:600; }

  /* Le couple champ + bouton ne tient pas dans une demi-largeur : le bloc newsletter prend
     donc TOUTE la largeur du footer et le couple y est centré (repli prévu par Fix).
     La rangée « accroche + réseaux » passe pleine largeur elle aussi, sinon elle resterait
     à moitié vide. */
  .footer__brand, .footer__news{ grid-column:1 / -1; }
  .footer__form{ justify-content:center; max-width:340px; margin-inline:auto; }
}


/* ==========================================================================
   8. BOUTONS FLOTTANTS (<=1024px)
   Le "haut de page" (#scrollTop) n'est plus un élément flottant isolé : il est
   reparenté DANS la pilule par js/mobile.js et stylé en §4 (.mob-fab .scroll-top).
   Reste ici uniquement ce qui n'a pas sa place dans la pilule.
   ========================================================================== */
@media (max-width:1024px){
  /* LOT 1bis (22/07) : la carte newsletter n'a pas d'intérêt sur téléphone et
     encombre l'écran (retour Fix) -> masquée. Garde matchMedia côté JS
     (main.js) pour ne pas écrire dans sessionStorage / poser un écouteur de
     scroll pour rien. */
  .news-pop{ display:none; }

  /* LOT 3 (22/07) : « voyage/destination/animal au hasard » (pays.html, voyage.html,
     animal.html) - bouton ISOLÉ bottom:18px, centré, EXACTEMENT dans la zone de la pilule
     (trouvé à la mesure sur voyage.html : chevauche #mobFab dès le chargement, avant même
     tout scroll). La règle est absolue : la pilule est le SEUL élément flottant en mobile,
     aucun autre bouton isolé ne partage sa zone. Masqué (son mécanisme .is-tucked, pensé
     pour le desktop, ne suffit pas : il ne se déclenche qu'au survol d'une grille précise,
     pas en permanence comme il le faudrait ici). */
  .py-hasard{ display:none; }
  /* Même raisonnement pour les flèches fixes « précédent / suivant » (demande Fix 22/07 sur les
     fiches voyage ; masquées sur TOUTES les fiches qui les portent - pays, voyage, animal,
     accompagnateur, récit - parce que c'est le même composant flottant, avec le même défaut :
     posé en fixed à mi-hauteur, il recouvre le contenu sur un écran étroit).
     Rien n'est perdu : la navigation reste possible par la flèche « retour » de la pilule,
     par le menu, et par les liens de la page. Le desktop les conserve. */
  .py-nav, .rcp-nav{ display:none; }
  /* Trouvaille de l'audit templates (LOT 8, animal.html) : `.an-hero__back` ("← Retour", position:
     absolute top:calc(112px+16px)) chevauchait le titre dès le chargement (mesuré sur
     animal.html?a=lynx-iberique : bouton posé en plein milieu de "Lynx Ibérique"). Même défaut ET
     même redondance que .py-nav/.rcp-nav ci-dessus : il ne fait que `history.back()`, exactement la
     fonction du bouton retour de la pilule - masqué pour la même raison, rien n'est perdu. */
  .an-hero__back{ display:none; }
}


/* ==========================================================================
   9. CIBLES TACTILES (<=640px)
   Objectif : >= 44px de haut sur tout ce qui se tape.
   ========================================================================== */
@media (max-width:640px){
  .footer__soc a{ width:48px; height:48px; }
  .footer__legal a{ display:inline-block; padding:6px 2px; }

  /* LOT 9 (22/07), retour Fix : resserrer les 2 colonnes de liens ("Nos offres"/"L'agence"),
     jugées "trop aérées". Arbitrage initial (22/07) : plancher 44px tenu (padding 10px,
     gap 8px), la place reprise sur l'espace mort autour (titre de colonne, padding bas
     de .footer__top).
     ⚠️ LOT 10 (23/07), Fix retranche : toujours "trop séparées" - autorisation EXPLICITE
     cette fois de descendre sous le plancher 44px pour CES liens précisément (aucune autre
     cible du site n'est concernée). padding 10px -> 6px (cible 36px) + gap 8px -> 4px
     (espacement minimal entre 2 cibles, plancher habituel non respecté ici, sciemment).
     Mesuré 375x667 : hauteur de colonne (titre + 4 liens) 229px -> 181px (-48px, -21%). */
  .footer__col h4{ margin-bottom:0; }
  .footer__col{ gap:4px; }
  .footer__col a{ padding:6px 0; }
  .footer__top{ padding-bottom:12px; }
  /* Un peu d'air autour du champ newsletter, qui touchait ses voisins (demande Fix).
     LOT 11 (24/07), retour Nicolas : « idem, je mettrais un espace entre le champ e-mail et
     les 2 titres qui suivent, Nos offres et L'agence ». Marge basse 12 -> 26px (le row-gap de
     6px de la grille s'y ajoute) : écart mesuré 375x667 18px -> 32px. Même parti pris qu'au
     point précédent : on ne touche pas au row-gap commun, la respiration reste locale. */
  .footer__form{ margin-block:12px 26px; }

  /* LOT 6 (22/07), suite du correctif "marge pilule" ci-dessus (§7) : encore de l'espace
     mort au-dessus des colonnes (marge du slogan, titre + texte de la newsletter, padding
     du bloc liens) - AUCUN de ces éléments n'est une cible tactile, resserrage sans risque.
     Avec le row-gap du §7, gagne les colonnes ~78px plus haut au total : les 2 premiers
     liens dégagent la pilule avec ~18px de marge à 375x667 (mesuré Chrome, avant : les 2
     chevauchaient). .footer__news h4 AJOUTÉ au sélecteur existant (.footer__col h4 ne le
     couvrait pas - le titre "Newsletter" gardait sa marge desktop de 16px). */
  .footer__tag{ margin-bottom:4px; }
  /* LOT 11 (24/07), retour Nicolas : « je mettrais un espace entre les 3 icônes des réseaux
     sociaux et le titre NEWSLETTER, pour que ce ne soit pas trop collé ». Les 2 blocs sont
     2 lignes de la grille du footer, dont le row-gap a été resserré à 6px au LOT 6 pour
     dégager les colonnes de liens de la zone de la pilule. On ne rouvre donc PAS ce row-gap
     (ça ramènerait le chevauchement) : la respiration est posée localement sur le bloc
     newsletter. Mesuré 375x667 : écart réseaux -> titre 6px -> 20px. */
  .footer__news{ margin-top:14px; }
  /* LOT 10 (23/07), retour Fix "encore plus serré" : cette règle écrasait le
     margin-bottom:0 de .footer__col h4 posé juste au-dessus (ligne ~630) - les
     2 titres de colonne liens gardaient 4px de trop, jamais vraiment "collés"
     comme le disait le commentaire. .footer__news garde sa propre règle. */
  .footer__news h4{ margin-bottom:4px; }
  .footer__news p{ margin-bottom:6px; }
  .footer__links{ padding-top:16px; }
}


/* ==========================================================================
   10. HOVER -> TOUCH
   On ne DÉSACTIVE pas le survol : on RE-DÉCLARE l'état de repos. Le bouton
   reste parfaitement fonctionnel, seul l'effet décoratif disparaît - sinon
   l'état de survol reste « collé » après un tap sur mobile.
   Ne sont visés QUE les effets décoratifs (transform / box-shadow / scale) :
   les :hover qui portent une INFORMATION (couleur d'un onglet actif, cadre
   jaune d'une vignette sélectionnée...) sont volontairement conservés.
   @media (hover:none) ne matche jamais une souris -> desktop intact.
   ========================================================================== */
@media (hover:none){
  /* Boutons (système .btn) */
  .btn--primary:hover,
  .btn--ghost:hover,
  .btn--blanc:hover,
  .btn--noir:hover,
  .btn--light:hover,
  .btn--vert:hover{ transform:none; box-shadow:none; }
  .btn--primary:hover{ background:var(--jaune); }
  .btn--ghost:hover{ background:none; color:inherit; }
  .btn--blanc:hover{ background:var(--blanc); color:var(--noir); }
  .btn--noir:hover{ background:var(--noir); }
  .btn--light:hover{ background:rgba(20,17,12,.4); border-color:rgba(255,255,255,.4); color:var(--blanc); }
  .btn--vert:hover{ background:var(--vert); }
  .cta-devis .btn--primary:hover{ background:var(--jaune); box-shadow:none; }

  /* Vignettes / cartes */
  .trip:hover{ transform:none; border-color:rgba(255,255,255,.14); }
  .trip--light:hover{ transform:none; box-shadow:0 14px 40px rgba(0,0,0,.08); border-color:var(--creme-2); }
  .post:hover{ transform:none; box-shadow:0 14px 40px rgba(0,0,0,.08); }
  /* box-shadow ramené à la valeur de REPOS (pas "none" : ces 3 cartes ont une ombre
     de base, la retirer aurait rendu les cartes plates en permanence sur mobile). */
  .vf-info:hover{ transform:none; box-shadow:0 14px 40px rgba(0,0,0,.07); }
  .eq-carte:hover{ transform:none; box-shadow:none; }
  .gd-carte:hover{ box-shadow:0 14px 40px -20px rgba(0,0,0,.35); }
  .rc-carte__link:hover{ transform:none; box-shadow:0 14px 40px -22px rgba(0,0,0,.35); }
  .rcp-mini:hover{ transform:none; }
  .pg-dest__item:hover{ transform:none; }
  .pgr-item:hover .pgr-item__photo{ transform:none; filter:grayscale(.25); }
  .pgr-marquee:hover .pgr-row{ animation-play-state:running; }   /* un tap ne fige pas le défilement */

  /* Éléments de navigation / contrôles — flèches rondes jaunes : la teinte foncée +
     l'ombre agrandie du survol ne doivent pas rester "collées" après un tap.
     .stackv__nav SANS transform ici (BUG CORRIGÉ 22/07) : en <=1024px son repos n'est plus
     translateY(-50%) mais transform:none (carrousel à plat, cf. §11) - remettre translateY(-50%)
     au survol la faisait "sauter" au tap. En ne déclarant pas transform ici, c'est la règle de
     repos qui gagne dans chaque contexte (desktop : translateY(-50%) inchangé ; mobile : none). */
  .stackv__nav:hover{ background:var(--jaune); box-shadow:0 14px 34px -10px rgba(0,0,0,.6); }
  .gp-gal__nav:hover{ background:var(--jaune); transform:translateY(-50%); box-shadow:0 14px 34px -10px rgba(0,0,0,.6); }
  .gal-lb__fermer:hover, .gal-lb__nav:hover{ background:rgba(255,255,255,.12); color:var(--blanc); }
  .gal-lb__nav:hover{ transform:translateY(-50%); }
  .gal-lb__vig:hover{ opacity:.45; }
  .cfiche__back:hover{ transform:translateX(-50%); }
  .py-hasard:hover{ transform:translateX(-50%); filter:none; }
  .opt__x:hover{ transform:none; }
  .map-pin:hover .pin-shape{ transform:none; }
  .footer__soc a:hover{ transform:none; box-shadow:none; background:var(--jaune); }
  .footer__col a:hover{ color:rgba(255,255,255,.68); }
  .footer__legal a:hover{ color:rgba(255,255,255,.82); }
  .scroll-top:hover{ background:var(--noir); color:var(--blanc); }

  /* Familles / espèces (hero planisphère) */
  .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); }

  /* Filtres (offres / sur-mesure / accompagnateurs / récits) — juste la bordure de
     survol, l'état choisi (.is-sel/.is-active/.is-on) n'est jamais touché ici. */
  .gd-fbtn:hover, .rc-fbtn:hover{ border-color:transparent; }
  .of-chip__btn:hover{ border-color:transparent; }
  .of-opt:hover{ border-color:transparent; }
  .of-opt--line:hover{ background:transparent; }
  .of-cal__all:hover{ border-color:transparent; }
  .of-cal__m:hover{ border-color:transparent; }
  .of-grad:hover{ border-color:transparent; }
  .of-grad__info:hover{ background:var(--creme-2); color:var(--noir); }
  .of-toggle:hover{ background:var(--blanc); border-color:var(--blanc); }
  .of-reset:hover{ border-color:rgba(255,255,255,.35); background:transparent; color:var(--blanc); }
  .of-type:hover{ border-color:transparent; }
  .voy-annee:hover{ border-color:rgba(0,0,0,.10); }
  a.voy-table__guide:hover{ color:inherit; }
  a.voy-table__guide:hover .voy-table__guide-pic{ box-shadow:none; }
  .ins-add:hover{ background:transparent; color:var(--vert); }
  .ins-del:hover{ background:var(--creme-2); color:var(--noir); }
  .ins-pack:hover{ border-color:rgba(14,14,14,.14); }
  .news-pop__close:hover{ color:var(--noir-50); }

  /* Méga-menu desktop : jamais ouvert au doigt (le volet mobile le remplace). */
  .nav__has-sub:hover .megamenu{ opacity:0; visibility:hidden; pointer-events:none; }

  /* LOT 2 (22/07) : complément d'inventaire - obturateur/viseur des portraits (accompagnateurs,
     photographes, pastilles rondes), animés en CSS pur par .iris-trigger:hover, jamais suivis d'un
     mouseleave -> un tap qui reste "collé" en :hover (Safari iOS, tap sur un lien sans handler
     dédié) rejouerait le cycle en boucle. Purement décoratif (la photo, elle, reste toujours
     visible et cliquable). */
  .iris-trigger:hover .iris,
  .iris-trigger:hover .iris .iris__rot,
  .iris-trigger:hover .iris .iris__blade,
  .iris-trigger:hover .iris .iris__edge,
  .iris-trigger:hover .iris-pic{ animation:none; }

  /* Reste de l'inventaire (décoratif, hors planisphère #hero qui est hors périmètre) */
  .rc-carte__link:hover .rc-carte__more{ color:var(--noir); }
  .on-lien:hover, .vf-rencontre__lien:hover{ border-bottom-color:transparent; }
  .trip__guide[data-guide]:hover strong,
  .voy-table__guide[data-guide]:hover,
  .on-guide[data-guide]:hover strong{ color:inherit; }
  .an-dock__item:hover .an-dock__bar{ background:inherit; }
  .an-where__item:hover{ color:inherit; }
  .an-where__item:hover .an-where__map svg path{ stroke:inherit; }
  .intro-hero__scroll:hover{ color:inherit; }
  .searchbar__go:hover{ background:var(--jaune); }
}


/* ==========================================================================
   11. PAGE INDEX (LOT 1bis, 22/07) : #stackv carrousel, ruban, titres XL,
       #departs — réparations demandées après audit par captures d'écran.
   ========================================================================== */
@media (max-width:1024px){

  /* ---- TITRES XL (.sec-title--xl) : trouvaille en mesurant #departs -----
     Le token --fs-title a déjà un plancher mobile abaissé (§2), mais
     .sec-title--xl porte SON PROPRE clamp desktop (52..98px), jamais
     couvert par ce correctif. Plancher desktop 52px + vw quasi nul à 375px
     -> "Nos voyages à la une" / "Nos voyages à ne pas manquer" passaient sur
     3 lignes (header mesuré à 239px) et gonflaient #stackv ET #departs. */
  .sec-title--xl{ font-size:clamp(30px, 8.6vw, 46px); }

  /* ---- RUBAN DE STATUT (.trip__tag) --------------------------------------
     En desktop il déborde volontairement à droite (right:-13px, -27px sur
     les polaroïds) pour sortir du cadre — effet de style voulu. Sous
     1024px ça sortait de l'ÉCRAN (masqué par le overflow-x:hidden du html,
     donc invisible en DevTools scrollWidth mais bien un ruban tronqué/hors
     champ à l'œil). Remis à plat dans la carte (pattern du guide
     d'extraction, feature 8). */
  .trip__tag,
  .stackv__photo .trip__tag{ right:0; border-radius:6px 6px 0 0; }
  .trip__tag::after{ display:none; }        /* pli triangulaire : n'a de sens que dans le débord */
  .depforts__grid .trip,
  .trip--light,
  .stackv__card{ overflow:hidden; }

  /* ---- #stackv « Nos voyages à la une » : titre densifié -----------------
     BUG TROUVÉ À LA MESURE (LOT 3, 22/07) : à l'alignement "haut de section
     = haut d'écran" (méthode d'audit imposée §4bis), le bloc titre + sous-
     titre mesurait 190px sur 375x667 -> la 1re carte (491px) débordait de
     20px SOUS l'écran, et son CTA "Voir le voyage" (bas de carte, carte =
     UN SEUL <a> sur toute sa surface) tombait pile dans la bande de la
     pilule (y:595-647) - dépassait même à DROITE de la pilule (carte 300px
     plus large que la pilule 162px) : un bout du bouton restait visible et
     cliquable à côté de la pilule. Sous-titre décoratif retiré (this
     section only - .depforts/.blog gardent le leur) : gagne ~90px, la 1re
     carte tient alors entière au-dessus de la pilule. */
  .stackv .sec-sub{ display:none; }
  .stackv .sec-head{ padding-top:8px; }   /* marge de sécurité mesurée (voir commentaire ci-dessus) */

  /* ---- #stackv « Nos voyages à la une » : CARROUSEL À SWIPE --------------
     Décision Fix : sous 1024px on abandonne le battage (cassé — mesuré en
     Chrome à 375px : cartes qui se chevauchent de ~34px, ruban hors écran,
     titres illisibles). Cause racine du chevauchement/des fragments blancs :
     .stackv__card est un <a>, et l'ancienne règle mobile de style.css
     (<=760px) le repasse en position:relative SANS display:block — un <a>
     sans display explicite retombe en display:inline (seul position:absolute
     le "blockifiait" gratuitement en desktop), d'où width/padding/background
     qui cessent de s'appliquer proprement. Le rend flex-item ci-dessous
     blockifie la carte correctement et règle ça du même coup, sans avoir à
     toucher style.css.
     Neutralise aussi la mécanique de pin desktop (fond sticky, marge
     négative, --stack-h) : la section retombe à une hauteur normale. */
  .stackv__bg{ position:absolute; inset:0; height:100%; }
  .stackv__track{ margin-top:0; padding-top:0; height:auto; }
  .stackv__pin{ height:auto; }
  .stackv__stage{
    position:static; min-height:0; perspective:none;
    display:flex; flex-direction:column; align-items:center; gap:14px;
    padding:0;
  }
  /* ANCRAGE MAGNÉTIQUE (25/07, retour Fix : « ça s'arrête un peu à moitié »).
     Avant : snap "x proximity" + align "start" -> le navigateur ne recalait QUE si
     le doigt s'arrêtait déjà près d'un point d'ancrage, et alignait sur le bord
     GAUCHE de la piste. Désormais "x mandatory" + align "center" : à chaque
     relâchement du doigt, une carte se cale au CENTRE de l'écran, jamais deux
     demi-cartes.
     Le padding latéral vaut la moitié du vide restant (--card-w) : sans ça, la 1re
     et la dernière carte ne peuvent PHYSIQUEMENT pas atteindre le centre (il
     faudrait un scrollLeft négatif) et resteraient les seules décalées.
     scroll-padding-inline supprimé : il ne servait qu'à rattraper un bug du snap
     "start" (scrollLeft qui valait 22.5px au repos, fragment blanc au bord
     gauche) - avec l'ancrage centré, la position de repos de la 1re carte est
     exactement scrollLeft:0. */
  .stackv__piste{
    --card-w:min(320px,80vw);
    width:100%;
    display:flex; gap:14px;
    overflow-x:auto; -webkit-overflow-scrolling:touch;
    overscroll-behavior-x:contain; scroll-snap-type:x mandatory;
    scrollbar-width:none;
    padding:6px calc((100% - var(--card-w)) / 2) 6px;
    /* affordance de bord : montre qu'il y a d'autres cartes à swiper */
    mask-image:linear-gradient(to right, transparent 0, #000 22px, #000 calc(100% - 22px), transparent 100%);
    -webkit-mask-image:linear-gradient(to right, transparent 0, #000 22px, #000 calc(100% - 22px), transparent 100%);
  }
  .stackv__piste::-webkit-scrollbar{ display:none; }
  .stackv__card{
    position:relative; left:auto; top:auto;
    flex:0 0 auto; width:var(--card-w,min(320px,80vw)); margin:0;
    scroll-snap-align:center;
    transform:none;
  }
  /* « Voir le voyage » recentré dans le polaroïd (25/07, retour Fix). Mesuré à
     500px : bouton collé à droite (155px de marge à gauche contre 22px à droite).
     Cause : style.css l.1239 pose margin-left:auto sur .stackv__cta - légitime en
     desktop où le pied de carte porte AUSSI une seconde info à gauche, mais ici le
     pied ne contient que le bouton, qui part donc à droite tout seul. Corrigé par
     spécificité (0,2,0 > 0,1,0), sans !important et sans toucher style.css. */
  .stackv__piste .stackv__cta{ margin-inline:auto; }
  /* Flèches ← → existantes (main.js) recâblées par mobile.js pour scroller la
     piste d'une carte -> ALTERNATIVE VISIBLE au geste de swipe (jamais le
     seul chemin), posées sous le carrousel plutôt que dans le tas de cartes. */
  /* LOT 1bis (22/07), réparation : les 2 flèches étaient groupées au centre de la piste
     (navRow simple flex, centré par align-items:center du parent .stackv__stage) -> mesurées
     PILE dans l'axe du burger flottant, cas exactement interdit par « la zone réservée du
     burger ». Écartées aux 2 bords du carrousel (space-between sur toute la largeur).
     LOT 2 (22/07, pilule) : la flèche de remontée n'est plus un élément flottant séparé à
     droite (right:clamp(...)) - elle est désormais À L'INTÉRIEUR de la pilule, centrée en
     bas. Le padding-right dédié au scroll-top devient donc caduc ; les 2 côtés reprennent la
     MÊME marge que .stackv__piste, symétrique - les flèches restent de toute façon largement
     à l'écart du faible encombrement horizontal de la pilule (centrée, ~220px), qu'importe où
     la section défile sous elle. */
  .stackv__navrow{
    display:flex; width:100%;
    justify-content:space-between; align-items:center;
    padding-inline: clamp(16px,6vw,28px);
  }
  .stackv__nav{
    position:static; display:flex;
    align-items:center; justify-content:center;    /* réparation : centre le chevron SVG dans le
      cercle - sans ces 2 lignes, le display:flex (posé ici pour sortir .stackv__nav de son
      position:absolute desktop) perd le place-items:center de style.css -> le SVG restait
      flush au bord de départ (justify-content:normal = flex-start), mesuré collé au bord gauche
      du bouton (24px d'icône dans 44px de bouton, 0px de marge à gauche contre 20px à droite). */
    line-height:1;
    width:44px; height:44px;                 /* cible tactile mini */
    transform:none;
  }

  /* ---- #departs : hauteur mesurée = contenu légitime (6 vraies cartes +
     titre 3 lignes), pas de bug de layout (display/position déjà corrects).
     Le fix du titre XL ci-dessus fait déjà l'essentiel ; densification
     légère de la carte pour le reste. Ruban/pastille vérifiés au pixel (6 cartes,
     375/768px) : AUCUN chevauchement .trip__tag/.trip__mode mesuré (6px d'écart mini) -
     déjà réglé par le right:0 + overflow:hidden ci-dessus, rien de plus à faire. */
  .depforts__grid .trip__body{ padding:22px 22px 24px; gap:9px; }
  .depforts__grid{ gap:12px; }

  /* ---- #photographes : bande défilante (.pgr-marquee) — correctif Chérubin de juin RETROUVÉ
     absent (feature 13 du guide de réapplication) : `overflow:hidden` reposé (défensif, la section
     .photographers l'a déjà mais un fondu de bord vaut mieux qu'une coupe nette) + AFFORDANCE DE
     BORD (fondu, même pattern que .stackv__piste) pour que les noms tronqués ("Stéphan
     Bonneau"/"Gilles Laurent") se fondent au lieu d'être sectionnés à vif. Contraste : le sous-
     titre (spécialité) est en --noir-50 (50% opacité) - illisible sur le fond --creme-2 de la
     section une fois mêlé aux items voisins qui défilent ; remonté à ~70% pour le mobile. */
  .pgr-marquee{
    overflow:hidden;
    mask-image:linear-gradient(to right, transparent 0, #000 40px, #000 calc(100% - 40px), transparent 100%);
    -webkit-mask-image:linear-gradient(to right, transparent 0, #000 40px, #000 calc(100% - 40px), transparent 100%);
  }
  .pgr-item__spe{ color:rgba(14,14,14,.7); font-weight:600; }
}


/* ==========================================================================
   12. HERO / PLANISPHÈRE MOBILE (LOT 3, 22/07 ; LOT 4, 22/07) — index.html, <=1024px
   Parti pris Fix : rangée des 7 familles EN TÊTE (scroll horizontal natif,
   même pattern que le guide d'extraction : piste-wrap/wrapper "display:contents"/
   piste), la carte UNE ZONE À LA FOIS (swipe + points + FLÈCHES aux bords, LOT 4),
   pays cliquables élargis, volet espèces qui descend du haut.
   ========================================================================== */
@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). */
  .marker-label{ opacity:1; }

  /* ---- 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); }
}


/* ==========================================================================
   13. HERO PHOTOGRAPHE (#intro) MOBILE — LOT 6 (22/07)
   Retour Fix : le bloc entier (sur-titre + slogan + descriptif) doit respirer
   sur un écran de 667px de haut - tout descend d'un cran, de façon cohérente
   (inventaire complet du bloc, pas seulement le h1). La photo, elle, ne défile
   plus : une seule image (celle aux éléphants), cadrée à droite (le sujet).
   ========================================================================== */
@media (max-width:1024px){
  /* sur-titre : 13px -> 11px */
  .intro-hero .eyebrow{ font-size:11px; letter-spacing:.14em; }
  /* slogan : plancher desktop 46px -> 32px (le vw du clamp reste, seul le plancher change) */
  .intro-hero__slogan{ font-size:clamp(32px,8.4vw,64px); margin:10px 0 16px; }
  /* descriptif : fs-body (18px) -> fs-small (15px), un cran plus bas dans l'échelle typo */
  .intro-hero__txt{ font-size:var(--fs-small); line-height:1.55; max-width:32ch; }
  /* indicateur de scroll : fs-label (13px) -> 11px, remonté (le bloc de texte est plus compact) */
  .intro-hero__scroll{ font-size:11px; bottom:16px; }

  /* Cadrage : sujet à droite. LOT 11 (24/07) : la photo n'est plus figée - la garde de
     main.js (heroDefile) qui coupait le défilement sous 1024px a été retirée, les 3 photos
     défilent en fondu comme en desktop. Le dézoom, lui, se joue sur la HAUTEUR du cadre
     (cf. .intro-hero, §5), pas ici : `cover` est déjà le zoom minimal pour un cadre donné. */
  .intro-hero__bg{ background-position:right center; }
}

/* Retour Fix (LOT 10, 23/07) : le texte de ce hero (et des autres blocs texte-sur-photo
   pleine largeur) touche le bord de l'écran - .container ne donne que --gutter (16px à
   375/393px). Respiration calée sur la marge perçue des cartes récits (.rc-carte__body,
   padding:18px 20px 22px -> 20px) : 24px de chaque côté ici, dans le haut de la fourchette
   demandée (20-30px). mobile.css charge après style.css -> gagne par cascade sans !important.
   Mesuré 375x667 : 16px -> 24px sur .intro-hero__inner, .feature__inner, .cta-devis__inner. */
@media (max-width:640px){
  .intro-hero__inner, .feature__inner, .cta-devis__inner{ padding-inline:24px; }
}


/* ==========================================================================
   14. FAMILLES (hero planisphère) — dégradé de bord CONDITIONNEL — LOT 6 (22/07)
   Retour Fix : depuis que les 7 familles tiennent sans défilement (flex:1 1 0,
   §12), le fondu de bord ne devait plus rien annoncer - IL MENTAIT (règle §3
   "une affordance ne ment jamais"). Le mask-image par défaut est retiré d'ici ;
   js/mobile.js mesure scrollWidth > clientWidth et pose `.is-scrollable`, SEULE
   condition qui réintroduit le fondu - donc uniquement si la piste déborde
   réellement (écran très étroit, ou libellés qui s'allongent). Remesuré au resize.
   ========================================================================== */
@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%);
  }
}


/* ==========================================================================
   15. PHOTOGRAPHES (#pgrMarquee) — 2 LIGNES en mobile — LOT 6 (22/07)
   Retour Fix : sur mobile, 2 lignes plutôt que 3 - la place gagnée agrandit
   portraits et noms. js/mobile.js redistribue les 9 photographes de main.js
   (buildPhotographers, 3 lignes desktop) sur les 2 premières lignes et vide la
   3e (masquée ici) - AUCUNE donnée dupliquée, mêmes items HTML déjà construits.
   ========================================================================== */
@media (max-width:1024px){
  .pgr-marquee[data-mob-rows] .pgr-row:nth-child(3){ display:none; }
  .pgr-marquee{ gap:clamp(20px,5vw,32px); margin-top:clamp(22px,5vw,34px); }
  .pgr-row{ gap:clamp(22px,6vw,36px); }
  .pgr-item{ gap:16px; }
  .pgr-item__photo{ width:clamp(88px,24vw,112px); height:clamp(88px,24vw,112px); border-radius:22px; }
  .pgr-item__name{ font-size:clamp(28px,7.6vw,36px); }
  .pgr-item__spe{ font-size:13px; }
}


/* ==========================================================================
   16. CARNET DE VOYAGE (#blog) — bouton "Lire la suite" CENTRÉ — LOT 6 (22/07)
   .btn est display:inline-flex (style.css) -> span inline-level dans le flux de
   .post__body : bascule en flex (block) + margin-inline:auto pour le centrer,
   sans toucher au reste de la carte (titre/extrait restent alignés à gauche).
   ========================================================================== */
@media (max-width:1024px){
  .post__more{ display:flex; margin:16px auto 0; width:fit-content; }
}


/* ==========================================================================
   17. BOUTONS CENTRÉS — RÈGLE GLOBALE — LOT 7 (22/07)
   Retour Fix (nouvelle règle permanente, définition Chérubin §5) : « le principe
   de centrer les boutons sur la largeur du téléphone, garde-le pour tout le site
   de manière globale quand il y a un bouton sur un bloc ». §16 ci-dessus le
   faisait déjà pour .post__more (seul) ; ici on couvre les CTA solitaires
   restants trouvés à l'audit (grep de tout `.btn` du site, HTML par HTML).
   EXCLU DÉLIBÉRÉMENT (rangées/barres d'action - le centrage y casserait
   l'alignement) : .cta-trio (S'inscrire/Poser une option/Nous contacter),
   .pg-suite__btns et .sec-cta/.sm-cta (déjà centrés en desktop, cf. style.css),
   .vf-contact__actions, .voy-table__actions, les filtres/formulaires. Déjà
   centrés par ailleurs et non retouchés ici : .cfiche__back, .vf-hero__retour
   (voyage.html), .about__cta (choix éditorial explicite de Fix 06/07, colonne
   de texte alignée à gauche - à confirmer si Fix veut l'inclure lui aussi).
   ========================================================================== */
@media (max-width:1024px){
  /* p.vf-esprit__cta (tag qualifié) : cette MÊME classe sert aussi de simple
     modificateur sur un <a> À L'INTÉRIEUR de .cta-trio (voyage.html, déjà
     aligné par la rangée) - le sélecteur ne doit matcher QUE le <p> qui
     enveloppe seul le bouton (sur-mesure.html), jamais l'ancre du trio. */
  p.vf-esprit__cta,
  .gp-bio__site,             /* accompagnateur.html : "Voir son site", seul dans son <p> */
  .gp-hero__topbar{          /* accompagnateur.html : "Retour aux accompagnateurs", seul dans ce bloc */
    text-align:center;
  }
  /* .band-img__cta partage son parent (.band-img__inner) avec un titre et un texte
     VOLONTAIREMENT alignés à gauche (.band-img__titre{text-align:left}, style.css) -
     on centre donc le BOUTON lui-même (même technique que .post__more ci-dessus),
     pas le bloc entier (qui recentrerait aussi le titre). */
  .band-img__cta{ display:flex; width:fit-content; margin-inline:auto; }
  /* .about__cta : le choix éditorial du 06/07 était de l'aligner à gauche dans sa
     colonne de texte. Fix a tranché le 22/07 -> il rejoint la règle de centrage
     comme les autres CTA solitaires. Même technique que .band-img__cta : on centre
     le BOUTON, pas le bloc (le texte de la colonne reste aligné à gauche). */
  .about__cta{ display:flex; width:fit-content; margin-inline:auto; }
  /* LOT 9 (22/07), trouvaille de l'audit templates (actions-nature.html) : `.pg-asso__site`
     (bouton "gorilla.fr"/"wildlifeangel.org"…, 8 occurrences) est un CTA solitaire en fin de
     colonne de texte, oublié du grep initial du 22/07 (règle §17 posée avant que ce template
     soit passé en revue) - resté aligné à gauche comme les paragraphes qui le précèdent, alors
     que la règle globale de Fix s'applique à "tout bouton sur un bloc". Même technique que
     .band-img__cta/.about__cta : seul le bouton se centre, le logo et le texte au-dessus
     restent alignés à gauche (inchangés). */
  .pg-asso__site{ display:flex; width:fit-content; margin-inline:auto; }
  /* actions-nature.html : les 8 logos d'association sont des cartes posées au-dessus du nom,
     alignées à gauche comme le texte. Fix les veut centrés en largeur (même logique que les
     boutons : en colonne unique mobile, un élément isolé se centre). */
  .pg-asso__logo{ margin-inline:auto; }

  /* ⚠️ RÉVISION (Fix, 22/07) : l'en-tête de cette section excluait les RANGÉES de boutons du
     centrage, par crainte de casser leur alignement. Fix a tranché l'inverse, capture à l'appui
     (bloc contact : « 01 53 44 74 30 » + « Nous contacter » collés à gauche) - « il faut centrer
     les boutons sur la largeur, de manière globale dans tout le site ».
     Les boutons gardent leur alignement RELATIF entre eux : c'est le GROUPE qui se centre. */
  .vf-contact__actions,
  .cta-trio,
  .vf-duo__actions,
  .voy-table__actions,
  .pg-suite__btns,
  .sec-cta, .sm-cta{
    justify-content:center;
    flex-wrap:wrap;   /* à 375px, 2 boutons côte à côte débordent : ils passent l'un sous
                         l'autre plutôt que d'être rognés, et restent centrés */
  }
}


/* ==========================================================================
   18. PANNEAU DE FILTRES OFF-CANVAS — offres.html — LOT 7 (22/07)
   Retour Fix : « un gros bouton qui affiche les filtres... tu décales le site
   vers la DROITE quasiment de 80% et tu prends toute l'espace de gauche sur un
   fond noir pour mettre les filtres ». Construit par js/mobile.js (ofPanel) qui
   RÉUTILISE (reparente, ne duplique jamais) les 8 filtres existants d'offres.js
   (.of-types, #ofFiltres, #ofToggle) — offres.js continue de lire/écrire ces
   mêmes éléments par ID, où qu'ils vivent dans le DOM : syncUI() n'a rien à
   savoir de ce panneau. Élément neuf (composants .of-panel/.of-scrim/.of-mob-btn
   n'existent pas dans style.css) : display:none par défaut, comme au §1.
   ========================================================================== */
.of-panel, .of-scrim, .of-mob-btn{ display:none; }

@media (max-width:1024px){
  :root{ --of-panel-w: min(80vw, 340px); }   /* "quasiment 80%", plafonné pour ne pas devenir énorme sur tablette */

  /* ---- Le site DÉCALÉ vers la droite pendant que le panneau est ouvert ----
     .site-header (fixed) + #main-content (le hero + .site-content) : le COUPLE
     exact demandé (§3 de la définition) - PAS body (casserait le header fixe et
     ferait dériver la pilule, qui est un enfant DIRECT de body, jamais de main). */
  .site-header, #main-content{ transition:transform .4s cubic-bezier(.22,.61,.36,1); }
  html.of-open .site-header,
  html.of-open #main-content{ transform:translateX(var(--of-panel-w)); }

  /* Rideau plein écran : capte le tap sur la bande de site visible à droite (ferme le panneau)
     et l'assombrit légèrement - sous le panneau (1240 < 1250), au-dessus du reste. */
  .of-scrim{
    display:block; position:fixed; inset:0; z-index:1240;
    background:rgba(14,14,14,.45);
    opacity:0; pointer-events:none; transition:opacity .3s var(--ease);
  }
  .of-scrim.is-open{ opacity:1; pointer-events:auto; }

  /* ---- Le panneau lui-même : monte... pardon, vient DE LA GAUCHE ----
     z-index sous 1400 (échelle en place : header 1000 · .mob-species 1200 ·
     .mob-menu 1300 · .mob-fab 1400) - placé à 1250, juste au-dessus du rideau. */
  .of-panel{
    display:flex; flex-direction:column;
    position:fixed; top:0; left:0; bottom:0; width:var(--of-panel-w);
    z-index:1250; background:#0e0e0e;
    box-shadow:24px 0 60px -20px rgba(0,0,0,.6);
    transform:translateX(-100%);
    transition:transform .4s cubic-bezier(.22,.61,.36,1);
  }
  .of-panel.is-open{ transform:translateX(0); }

  .of-panel__head{
    flex:0 0 auto; display:flex; align-items:center; justify-content:space-between;
    gap:12px; padding:calc(env(safe-area-inset-top,0px) + 20px) 20px 16px;
    border-bottom:1px solid rgba(255,255,255,.12);
  }
  .of-panel__title{ font-family:var(--serif); font-size:clamp(20px,5.5vw,24px); color:var(--blanc); margin-right:auto; }
  /* Réinitialiser : petit bouton CARRÉ noir, icône blanche (demande Fix 22/07). Carré et non
     pilule : c'est une action utilitaire, pas un CTA - cohérent avec la règle projet
     "cliquable = pilule, utilitaire/informatif = angles droits". */
  .of-panel__reset{
    flex:0 0 auto; width:40px; height:40px; border-radius:6px;
    background:var(--noir); border:1px solid rgba(255,255,255,.18); color:var(--blanc);
    display:flex; align-items:center; justify-content:center; cursor:pointer;
    touch-action:manipulation; -webkit-tap-highlight-color:transparent;
  }
  /* le vrai #ofReset reste dans wrapF (sa délégation y est branchée) mais n'a plus à s'afficher :
     le bouton d'en-tête le relaie. */
  .of-panel__body #ofReset{ display:none; }
  .of-panel__close{
    flex:0 0 auto; width:40px; height:40px; border-radius:50%;
    background:rgba(255,255,255,.08); border:none; color:var(--blanc);
    display:flex; align-items:center; justify-content:center; cursor:pointer;
    touch-action:manipulation;
  }
  /* L'anneau de focus par défaut de Chrome est BLEU -> hors charte, et très visible
     sur le fond noir du panneau. On ne le SUPPRIME pas (c'est une aide clavier) :
     on le redessine en jaune de la charte, et via :focus-visible pour qu'il
     n'apparaisse qu'au clavier, jamais au tap. Même traitement sur les 3 boutons
     de la pilule, pour la même raison. */
  .of-panel__close:focus,
  .of-panel__reset:focus,
  .mob-fab .mob-burger:focus,
  .mob-fab .mob-fab__btn:focus,
  .mob-fab .scroll-top:focus{ outline:none; }
  .of-panel__close:focus-visible,
  .of-panel__reset:focus-visible,
  .mob-fab .mob-burger:focus-visible,
  .mob-fab .mob-fab__btn:focus-visible,
  .mob-fab .scroll-top:focus-visible{
    outline:2px solid var(--jaune); outline-offset:2px;
  }

  /* Corps scrollable : c'est LUI qui défile si les filtres dépassent l'écran (pas le fond de
     page) - data-lenis-prevent (posé en JS) empêche Lenis de capter le geste à sa place
     (même piège que le volet menu, documenté dans le CLAUDE.md du projet). */
  .of-panel__body{
    flex:1 1 auto; overflow-y:auto; -webkit-overflow-scrolling:touch; overscroll-behavior:contain;
    scrollbar-width:none;
    padding:18px 20px 24px; display:flex; flex-direction:column; gap:16px;
  }
  .of-panel__body::-webkit-scrollbar{ display:none; }

  .of-panel__foot{
    flex:0 0 auto; padding:14px 20px calc(14px + env(safe-area-inset-bottom,0px));
    border-top:1px solid rgba(255,255,255,.12);
  }
  .of-panel__see{ width:100%; justify-content:center; }

  /* ---- Reflow des 8 filtres : de la RANGÉE horizontale (desktop) à la PILE verticale
     pleine largeur - les composants sont RÉUTILISÉS tels quels (mêmes classes/couleurs),
     seule leur mise en page change ici. ---- */
  .of-panel__body .of-types{ padding:0; justify-content:flex-start; }
  .of-panel__body .of-filtres__inner{
    display:flex; flex-direction:column; align-items:stretch; gap:12px; padding:0;
  }
  .of-panel__body #ofToggle{ width:100%; justify-content:center; margin:0; }
  .of-panel__body .of-chip{ width:100%; }
  .of-panel__body .of-chip__btn{ width:100%; justify-content:space-between; }
  .of-panel__body .of-grad,
  .of-panel__body .of-slider{ display:flex; width:100%; justify-content:space-between; }
  .of-panel__body .of-slider__range{ flex:1 1 auto; width:auto; }
  /* le panneau déroulant devient un ACCORDÉON EN FLUX (pousse le reste vers le bas) au lieu
     d'un overlay flottant qui recouvrirait les filtres suivants. */
  .of-panel__body .of-pop{
    position:static; width:100%; min-width:0; max-width:none; margin-top:8px;
    box-shadow:none; border-color:rgba(255,255,255,.14); background:var(--blanc);
  }
  .of-panel__body .of-list--pays,
  .of-panel__body .of-list--fam{ min-width:0; }
  .of-panel__body .of-list--pays{ grid-template-columns:1fr; }
  .of-panel__body .of-cal{ min-width:0; }
  /* le panneau d'info "i" (niveau) reste ABSOLU dans le desktop mais déborderait à droite du
     panneau (min-width:400px) - ancré en bas du panneau, largeur = panneau. */
  .of-panel__body .of-nivpop{
    position:fixed; left:20px; right:20px; bottom:calc(90px + env(safe-area-inset-bottom,0px));
    width:auto; top:auto; transform:none;
  }
  /* Réinitialiser : ce bouton pleine largeur en bas de la pile a été REMPLACÉ (Fix 22/07) par le
     petit bouton carré de l'en-tête (.of-panel__reset, §18 plus haut). Le vrai #ofReset reste
     dans le DOM parce que sa délégation y est branchée (offres.js:337) - il est juste masqué,
     l'en-tête lui relaie le clic. Ne pas le rendre visible sans retirer celui de l'en-tête. */

  /* ---- Le bouton "Filtres" qui remplace la barre en place ----
     .of-types/#ofFiltres restent des enfants de .of-filtres (sticky) UNE FOIS reparentés dans
     le panneau par mobile.js -> masqués ICI dans leur position d'ORIGINE (avant reparentage,
     et si jamais le reparentage échouait). */
  /* Scopé à leur position D'ORIGINE (descendant de .of-filtres) : une fois reparentés dans le
     panneau par mobile.js, ces mêmes éléments ne sont plus décrits par ce sélecteur -> ils
     redeviennent visibles là-bas (cf. règles .of-panel__body plus haut). Un sélecteur d'ID nu
     (`#ofFiltres{display:none}`) les aurait masqués PARTOUT, y compris une fois déplacés. */
  .of-filtres .of-types,
  .of-filtres #ofFiltres{ display:none; }
  .of-filtres .container{ padding-top:14px; padding-bottom:14px; }
  .of-mob-btn{
    display:flex; align-items:center; justify-content:center; gap:10px; width:100%;
    padding:14px 18px; border-radius:14px; border:none; cursor:pointer;
    background:var(--jaune); color:var(--noir); font:inherit; font-size:var(--fs-small);
    font-weight:700; touch-action:manipulation;
  }
  .of-mob-btn__n{ font-weight:600; opacity:.7; }

  /* La pilule (burger/retour/haut de page) s'efface pendant que CE panneau modal est ouvert -
     EXCEPTION EXPLICITE à la règle "toujours visible" du §4 : Fix distingue l'effacement au
     DÉFILEMENT (rejeté, cf. §4) d'un effacement d'ÉTAT MODAL (demandé ici, un panneau plein-
     hauteur qui se substitue à toute la navigation le temps d'être ouvert). */
  html.of-open .mob-fab{
    opacity:0; pointer-events:none; visibility:hidden;   /* visibility (pas juste opacity) : sort aussi le
      burger caché de l'ordre de tabulation clavier - sinon un Tab pourrait encore l'atteindre et ouvrir
      le volet menu PAR-DESSUS ce panneau modal. */
    transition:opacity .2s var(--ease), visibility 0s .2s;
  }
}
@media (prefers-reduced-motion:reduce){
  .of-panel, .site-header, #main-content, .of-scrim, html.of-open .mob-fab{ transition:none; }
}


/* ==========================================================================
   VOLET ESPÈCES MOBILE (#mobSpecies, construit par js/mobile.js) — descend du
   HAUT, liste sur 2 colonnes (pattern du guide d'extraction, feature 3, adapté).
   ========================================================================== */
.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; }
}


/* ==========================================================================
   14. HEROS DE PAGE "TITRE SEUL" - hauteur divisée par deux (<=1024px)
   Demande Fix (22/07) : .vf-hero--page ne porte qu'un eyebrow + un H1 (+ la
   pilule "prochains départs" sur offres.html) - le calage en 52vh (≈347px à
   667 de haut) est donc presque entièrement du vide. Les heros à contenu réel
   (voyage/pays/animal/accompagnateur/récit) n'ont PAS cette classe, ils ne
   sont donc jamais concernés.
   On abandonne le vh au profit d'un calage sur le CONTENU réel : header fixe
   + petit surplus, puis le bloc titre, puis petit surplus bas - ce qui donne
   ~une division par deux SANS jamais écraser un titre sur 2-3 lignes (la
   hauteur suit le texte au lieu de forcer une valeur fixe).
   ========================================================================== */
@media (max-width:1024px){
  .vf-hero--page{
    min-height:0;
    padding:calc(var(--nav-h) + 20px) 0 28px;
  }
  /* hero offres : la pilule "prochains départs" est poussée en bas par
     margin-top:auto DANS un inner à min-height:calc(52vh - 80px) (style.css) -
     sans ce min-height forcé, la même règle rendrait le hero à nouveau grand.
     On repasse en flux normal (petit écart fixe sous le titre). */
  .vf-hero--page .vf-hero__inner:has(.of-toggle){ min-height:0; }
  .vf-hero--page .of-toggle{ margin-top:24px; }
}

/* Retour Fix (LOT 10, 23/07) : même défaut que le hero d'accueil (§13 ci-dessus) sur TOUS
   les héros de page qui partagent .vf-hero__inner (accompagnateurs/actions-nature/charte/
   equipe/offres/presentation/recits/sur-mesure/voyage) - texte collé à --gutter (16px).
   Un seul point de correction pour 9 gabarits (composant partagé). Contenu déjà centré/
   auto-largeur dans tous ces héros (vérifié) : resserrer le conteneur ne casse rien. */
@media (max-width:640px){
  .vf-hero__inner{ padding-inline:24px; }
}


/* ==========================================================================
   15. HERO FICHE PAYS (.cfiche) — pays.html — LOT 8 (22/07)
   Constat Fix : les 3 mini-fiches voyage du hero (.cpanel__trips, position:absolute
   left:38%) tentaient de tenir 3 cartes dans les ~38-58% de largeur restants une fois
   la colonne de gauche (COL_LEFT=96px, pays.js) retirée — sur un écran de 375px ça ne
   laisse que quelques pixels : les cartes s'écrasaient et se chevauchaient en éventail,
   qui plus est en position:absolute vertical centré (top:50%) débordant JUSQU'AU
   HEADER fixe. Mesuré : cartes visibles sous le logo dès le chargement, aucune lecture
   possible. Les MÊMES voyages sont déjà listés intégralement plus bas dans #pyVoyGrid
   (pays.js: le tableau `trips` sert les deux sections) -> aucune perte de contenu à
   les masquer ici, aucun doublon à gérer (vérifié : pyVoyGrid rend TOUS les voyages du
   pays, hero compris, cf. commentaire de pays.js).
   Parti pris Fix ("titre à gauche + espèces, carte à droite") jugé intenable à 375px
   (retenu : EMPILÉ) : à cette largeur, les 2 colonnes n'auraient eu qu'environ 160px
   chacune - ni le nom du pays (parfois long : "Afrique du Sud"), ni la forme, n'y
   restent lisibles. Empilé : titre+espèces PLEINE LARGEUR sur la bande photo (logique
   desktop, juste repliée), puis la forme du pays SEULE, en dessous, sur fond uni sombre
   -> chaque élément garde sa pleine largeur pour respirer. */
@media (max-width:1024px){
  /* Mini-fiches : masquées ici, présentes plus bas dans #pyVoyGrid (aucune duplication). */
  .cpanel__trips{ display:none; }

  /* Le hero n'est plus calé à 80dvh fixe (contenu réel -> pas la réduction du §14) mais son ancienne
     hauteur pleine page n'a plus de sens une fois les mini-fiches parties : .cpanel (bande photo +
     texte) et #countryShape (forme, fond uni) deviennent 2 bandes empilées EN FLUX NORMAL, chacune
     dimensionnée par son propre contenu — .cfiche n'a donc plus besoin d'imposer sa hauteur. */
  .cfiche{ height:auto; min-height:0; display:flex; flex-direction:column; overflow:visible; }

  /* ---- Bande 1 : photo + titre + espèces (reprend .cpanel, remis en FLUX normal) ----
     ⚠️ Spécificité : style.css impose `position:absolute` via `.cfiche .cpanel`/`.cfiche
     .cpanel__body` etc. (2 classes) - un sélecteur nu `.cpanel{...}` (1 classe) PERD ce duel
     malgré l'ordre de cascade (mobile.css après style.css ne suffit pas à égalité de
     spécificité, encore moins en-dessous). Les sélecteurs ci-dessous reprennent donc le même
     préfixe `.cfiche` pour gagner honnêtement, sans `!important`. */
  .cfiche .cpanel{ position:relative; inset:auto; visibility:visible; pointer-events:auto; }
  .cfiche .cpanel.show{ transition:none; }   /* l'apparition en cercle n'a de sens que plein écran (desktop) */
  .cfiche .cpanel__photo{ clip-path:none; opacity:1; }   /* révélation en cercle impossible dans une bande courte : photo visible d'emblée */
  .cfiche .cpanel__photo::after{
    /* dégradé pensé pour une photo PLEINE LARGEUR de texte (plus de "moitié gauche" à assombrir) */
    background:linear-gradient(to top, rgba(14,14,14,.86) 0%, rgba(14,14,14,.55) 55%, rgba(14,14,14,.15) 100%);
  }
  .cfiche .cpanel__body{
    position:relative; inset:auto; width:100%; opacity:1; visibility:visible; pointer-events:auto;
    padding:calc(var(--nav-h) + 28px) clamp(20px,5vw,32px) 28px;
    gap:10px;
  }
  .cpanel__title{ font-size:clamp(30px,8vw,44px); }
  .cpanel__fams{ flex-wrap:wrap; gap:8px 12px; }

  /* ---- Bande 2 : la forme SEULE, sur fond uni sombre (.cfiche garde son background:#241d12) ---- */
  .cfiche #countryShape{
    position:relative; left:auto; top:auto; inset:auto;
    display:block; width:min(72vw,260px); height:min(72vw,260px);
    margin:24px auto 40px; will-change:auto;
  }

  /* LOT 9 (22/07), nouvelle règle Fix : « la pilule rend redondants les boutons de navigation
     de page - masque-les ». "Retour à la carte" ne fait qu'un `history.back()`-équivalent (lien
     vers index.html#hero) déjà couvert par la flèche retour de la pilule -> masqué, comme
     .an-hero__back (§16) et .py-nav/.rcp-nav (§8). Le margin-bottom ajouté à #countryShape
     ci-dessus reprend le rôle d'espace de sortie de section que portait ce bouton. */
  .cfiche__back{ display:none; }
}


/* ==========================================================================
   16. FICHE ANIMAL — ancres "Où l'observer" + panneau "Chercher un autre animal"
   — animal.html — LOT 8 (22/07)
   ========================================================================== */
@media (max-width:1024px){
  /* ---- B1 : ancres pays plus petites, centrées quand il y en a peu ----
     `.an-where` gardait une grille à colonnes de 116px (taille desktop) : avec 1-2 pays,
     `width:max-content` la fait déjà correspondre au nombre réel de colonnes, mais rien ne la
     RECENTRAIT dans sa colonne de grille pleine largeur (`.an-hero__inner` passe à 1 colonne
     sous 860px, style.css) - mesuré alignée à gauche plutôt que centrée. Cellules rétrécies
     (moins de place qu'en desktop) et centrage forcé, quel que soit le nombre de pays. */
  /* ⚠️ Trouvaille de l'audit (mesure, pas à l'œil) : avec `--cols` posé par animal.js pour la
     largeur DESKTOP (116px/colonne, jusqu'à 4-6 colonnes), une espèce à beaucoup de pays (ex.
     "hermine", 10 pays -> --cols=4) débordait de 31px à droite de l'écran à 375px avec des colonnes
     resserrées à 84px (`#anWhere` mesuré x:16 -> right:406 ; `scrollWidth` masquait le débord
     derrière `overflow-x:hidden`, piège documenté). Le nombre de colonnes est replafonné à 3 en
     mobile par `js/mobile.js` (`--cols` réécrit, jamais recalculé en dur ici - relit simplement la
     valeur déjà posée par animal.js et la borne) : 3 colonnes de 84px tiennent toujours (300px de
     grille dans une fenêtre utile de ~343px), le reste passe à la ligne plutôt que de déborder. */
  .an-where{ margin-inline:auto; padding:18px 20px; }
  .an-where__grid{ grid-template-columns:repeat(var(--cols,3), 84px); gap:0 4px; }
  .an-where__map{ max-width:56px; }
  .an-where__nom{ font-size:12px; }
  .an-where__item{ padding:10px 6px; }

  /* ---- B2 : le dock façon Mac (mousemove mort au doigt, cf. an-dock:hover(none) déjà neutralisé
     côté animation) est REMPLACÉ par un bouton qui ouvre le panneau off-canvas (construit par
     mobile.js -> anPanel, réutilise EXACTEMENT le composant .of-panel/.of-scrim d'offres.html,
     généralisé pour l'occasion, cf. mobile.js). Le dock reste dans le DOM (réversible au resize),
     simplement masqué ; le bouton (.an-panel-bar, injecté par mobile.js) prend sa place visuelle. */
  .an-dockwrap{ display:none; }
  .an-panel-bar{ display:block; background:var(--noir); padding:16px clamp(16px,4vw,44px); }

  /* Corps du panneau : liste alphabétique dense des 83 espèces (repère de lettre collant en tête
     de groupe) - choix Fix-validé "l'alphabétique c'est très bien" : plus rapide à scanner quand on
     connaît déjà le nom cherché, sans le tap supplémentaire d'un accordéon à ouvrir/fermer. */
  /* ⚠️ Le repère de lettre est `sticky`, et `sticky` se cale sur la BOÎTE DE PADDING du
     conteneur défilant, pas sur le haut de sa zone visible. Le `padding-top:18px` de
     .of-panel__body figeait donc la lettre 18px trop bas, et on voyait les items défiler
     dans cette bande au-dessus d'elle (constaté par Fix, mesuré : lettre à 95px pour un
     corps commençant à 77px). On déplace ce padding DANS le contenu défilant : la lettre
     se cale alors bien à 0, et les 18px s'en vont avec le défilement comme il se doit. */
  .of-panel__body:has(.an-panel-list){ padding-top:0; }
  .an-panel-list{ display:flex; flex-direction:column; padding-top:18px; }
  .an-panel-letter{
    position:sticky; top:0; z-index:1; background:#0e0e0e;
    color:rgba(255,255,255,.5); font-size:11px; font-weight:700; letter-spacing:.1em;
    text-transform:uppercase; padding:10px 4px 6px;
  }
  .an-panel-item{
    display:block; padding:12px 4px; color:var(--blanc); text-decoration:none;
    border-bottom:1px solid rgba(255,255,255,.08);
    font-family:var(--serif); font-size:16px; touch-action:manipulation;
    -webkit-tap-highlight-color:transparent;
  }
  .an-panel-item[aria-current="page"]{ color:var(--jaune); font-weight:600; }
}
/* .an-panel-bar{display:none} de base déplacé en §1 (BUG CORRIGÉ : posé ici, APRÈS la media query
   qui l'affiche, il gagnait à égalité de spécificité par l'ordre de cascade et l'annulait toujours -
   mesuré : display:none à 375px alors que la media query ci-dessus le passait bien en display:block).
   .an-where__item:hover / .an-where__map svg path déjà neutralisés en §10 (hover:none) - pas de doublon ici. */
@media (hover:none){
  .an-panel-item:hover{ color:var(--blanc); }
}


/* ==========================================================================
   17. BOUTONS "RETOUR" MASQUÉS PARTOUT — LOT 9 (22/07)
   Nouvelle règle Fix (définition Chérubin §3) : « la pilule rend redondants les
   boutons de navigation de page - masque-les ». La pilule porte déjà une
   flèche retour permanente -> tout bouton de CORPS de page qui ne fait que
   remonter à la page précédente (ou vers une page-liste "mère") est redondant.
   Déjà traités ailleurs (pas dupliqués ici) : .an-hero__back (§16, position:
   absolute, masqué), .py-nav/.rcp-nav (§8, blocs de nav inter-fiches),
   .cfiche__back (§15, ci-dessus, converti de "repositionné" à "masqué" dans
   ce même lot).
   ========================================================================== */
@media (max-width:1024px){
  /* ---- voyage.html : "← Retour à nos offres" ----
     Contenu bottom-aligné dans .vf-hero__inner (justify-content:flex-end,
     style.css) : masquer le lien laisse le reste du bloc (eyebrow/titre/
     difficulté) glisser vers le bas du hero de la hauteur libérée - aucun
     nouveau chevauchement possible (le hero garde son min-height:62vh, la
     pile qui reste est plus courte). --retour-gap n'a plus de bouton à
     compenser : on redonne au hero un padding-top standard (mesuré : sans ce
     correctif, le padding-top restait amputé de 20px sans qu'aucun élément
     n'en profite - petit gain de propreté, pas un bug visuel en soi). */
  .vf-hero__retour{ display:none; }
  .vf-hero--voyage{ padding-top:calc(var(--nav-h) + 40px); }

  /* ---- accompagnateur.html : "← Retour aux accompagnateurs" ----
     .gp-hero__topbar est le SEUL contenu du hero (photo de fond + voile
     seulement autour) - le masquer ne change rien d'autre : .gp-hero garde
     son min-height:52vh (style.css, non touché), l'identité (portrait+nom)
     vit dans .site-content EN DESSOUS du hero, jamais concernée. */
  .gp-hero__topbar{ display:none; }
}


/* ==========================================================================
   18. CASSURE DES MOTS LONGS (URLs) — correctif générique, LOT 9 (22/07)
   TROUVAILLE DE L'AUDIT (mesure, pas à l'œil) : accompagnateur.html?g=vincent-
   beccaro débordait de 15px (scrollWidth 391 sur 375, MASQUÉ par le
   html,body{overflow-x:hidden} de style.css - piège documenté dans le
   CLAUDE.md, trouvé ici à la mesure du scroll réel). Cause : plusieurs bios
   de `ON_GUIDE_FICHE` (data-carte.js) contiennent une URL brute en texte
   (ex. "https://www.facebook.com/vincent.beccaro") jamais coupée
   (overflow-wrap:normal par défaut) - un seul mot de 40+ caractères ne tient
   pas dans la largeur d'une colonne de texte à 375px.
   Racine commune plutôt que correctif au cas par cas (une seule règle
   corrige les 7 bios concernées ET tout autre bloc de texte éditorial qui
   contiendrait un jour une URL/mot long) : tout <p> peut légitimement casser
   un mot trop long en mobile, sans conséquence sur le texte normal (seul un
   mot qui déborde réellement est concerné). #vfInfosGrid .vf-info p a déjà
   sa propre règle équivalente (style.css l.1799, cas déjà traité) : aucun
   conflit, les 2 règles disent la même chose.

   LOT 12 (25/07), retour Nicolas « Ce prix comprend / ne comprend pas coupés
   à droite » (fiche voyage) : même cause racine, mais dans des <li>, pas des
   <p>. La règle ci-dessus (LOT 9) ne touchait que les <p> et manquait donc
   ces listes. V59 (Yukon-Alaska) porte deux URLs brutes dans « ce prix ne
   comprend pas » (esta.cbp.dhs.gov, la page canada.ca/.../ave.html de 84
   caractères d'un seul tenant). Piège de mesure : Chrome casse ces URLs aux
   « / » -> à l'œil et au scrollWidth, rien ne déborde en device mode. Mais
   Safari/iPhone (l'appareil de Nicolas) ne coupe pas aux « / » -> l'URL sort
   du cadre à droite. On étend donc la même règle aux <li> (seul un mot qui
   déborde réellement casse ; les libellés de menu/nav sont trop courts pour
   être concernés). À CONFIRMER SUR IPHONE, comme les points 1 et 3. */
@media (max-width:1024px){
  p, li{ overflow-wrap:anywhere; }
}


/* ==========================================================================
   19. DIAPORAMA « BATTAGE » AU MILIEU D'UN RÉCIT (.rcp-diapo) — recit.html
   LOT 9 (22/07)
   TROUVAILLE DE L'AUDIT (mesure, pas à l'œil) : recit.html?a=colombie-paradis-
   des-oiseaux débordait de 49px (scrollWidth 424 sur 375). Cause : la variante
   `.rcp-diapo__stage .gp-gal__card` (style.css) impose `height:clamp(300px,
   36vw,480px)` - à 375px, 36vw = 135px < le PLANCHER 300px -> la carte se
   cale sur ce plancher, et comme elle a `aspect-ratio:3/2`, ça lui donne une
   LARGEUR de 450px, bien plus que les ~343px de largeur utile du corps de
   récit. Le plancher desktop (pensé pour tablette/petit desktop) n'avait
   jamais été vérifié à la largeur téléphone (même famille de bug que les
   §14/§4ter : un plancher de clamp choisi pour du desktop). Le carrousel
   « battage » (galerie.js, positions absolues centrées) n'a pas de garde-fou
   de largeur propre : c'est la carte elle-même qui doit rester dans le cadre.
   Repris en LARGEUR d'abord (min(),  hauteur dérivée par l'aspect-ratio déjà
   posé), pas l'inverse : plus fiable pour rester sous la largeur du conteneur
   quel que soit l'écran. */
@media (max-width:640px){
  .rcp-diapo__stage{ height:240px; }
  .rcp-diapo__stage .gp-gal__card{ width:min(280px,82vw); height:auto; }
}


/* ==========================================================================
   20. ONGLETS DE FILTRE PAR ZONE (.rc-fbtn / .gd-fbtn) — UNE SEULE LIGNE
   LOT 10 (23/07), retour Fix.
   Composant partagé (style.css l.1990) entre recits.html (#rcFiltres, filtre
   continent) et accompagnateurs.html (#gdFiltres, filtre zone) : 5 boutons
   « Tous / Afrique / Amériques / Asie / Europe », affichés EN LIGNE (pas dans
   un volet off-canvas - contrairement aux filtres du catalogue offres.html,
   déjà traités en panneau §18). À 375px, ils passaient sur 2 lignes
   (« Europe » retombait seul) : mesuré Chrome, 416px de texte+padding pour
   343px de largeur utile (bar dans .container, gutter 16px).
   Priorité PADDING, pas police (garde --fs-small = 15px partout, donc la
   hauteur ~45px et la lisibilité ne bougent pas) : le padding horizontal
   9px 15px -> 9px 4px est la valeur MINIMALE mesurée qui tient sur une seule
   ligne à 375px (pad 5px repasse à 2 lignes - testé). Le gap ENTRE les
   boutons reste à 8px (plancher tactile du site, §9/§5 - pas touché).
   Mesuré : "Asie" tombe à 43px de large (1px sous les 44px cibles) mais
   conserve sa hauteur pleine (45px) - seul écart mineur, sur la dimension
   la moins critique au tap, pour tenir la règle "une ligne d'abord". */
@media (max-width:640px){
  .rc-fbtn, .gd-fbtn{ padding:9px 4px; }
}


/* ==========================================================================
   21. CHIFFRES CLÉS (.trust) — GRILLE 2 x 2 — LOT 11 (24/07)
   Retour Nicolas : « tu peux passer "Associations soutenues" sur 2 lignes pour
   aligner plus les chiffres clés entre eux ? ». Les 4 chiffres vivaient dans un
   flex-wrap centré : chaque colonne prenait la largeur de SON libellé, et le plus
   long (« associations soutenues », 208px mesurés à 375px) ne tenait à côté
   d'aucun autre -> répartition 2 / 1 / 1, chiffres décalés d'une ligne à l'autre.
   On passe en grille 2 colonnes ÉGALES : les 4 chiffres s'alignent 2 par 2, et le
   libellé le plus long passe de lui-même sur 2 lignes (163px de colonne) - sans
   valeur de coupure écrite en dur, donc juste aussi si le texte change.
   ========================================================================== */
@media (max-width:640px){
  .trust__stats{
    display:grid; grid-template-columns:1fr 1fr;
    gap:clamp(20px,5vw,30px) clamp(12px,4vw,20px);
    align-items:start;
  }
}


/* ==========================================================================
   22. TABLEAU DES DÉPARTS EN CARTES — voyage.html — LOT 11 (24/07)
   Retour Nicolas : « le tableau du bloc Prochains départs est à revoir, il manque
   beaucoup d'infos à l'affichage ». Mesuré à 375px : le tableau fait 1307px de
   large (6 colonnes en white-space:nowrap) dans un cadre de 335px -> 26 % visible,
   et rien n'indique qu'il faut le faire défiler latéralement : les 4 dernières
   colonnes (prix, accompagnateur, disponibilité, boutons) sont invisibles.
   -> UNE CARTE PAR DÉPART, en CSS seul : aucune ligne de js/voyage.js n'est
   touchée (le générateur reste l'unique source de vérité, et le desktop garde son
   vrai tableau). Les intitulés de colonnes, masqués avec le <thead>, sont rendus
   devant chaque valeur par un ::before indexé sur la position de la cellule -
   l'ordre des 6 colonnes est figé par le générateur (voyage.js l.300-305).
   ========================================================================== */
@media (max-width:1024px){
  /* le cadre n'a plus à déborder du container pour "tout tenir sur une ligne" */
  .voy-table__wrap{ overflow-x:visible; width:100%; margin-inline:0; padding:6px; }
  .voy-table thead{ display:none; }
  .voy-table, .voy-table tbody, .voy-table tr, .voy-table td{ display:block; width:auto; }

  .voy-table tr{
    padding:14px 14px 12px;
    border-bottom:1px solid var(--creme-2);
  }
  .voy-table tr:last-child{ border-bottom:none; }

  .voy-table td{
    display:flex; align-items:baseline; justify-content:space-between; gap:14px;
    white-space:normal; text-align:right;
    padding:5px 0; border:none;
  }
  /* intitulé de colonne repris du <thead> masqué, même habillage que les <th> */
  .voy-table td::before{
    flex:0 0 auto; text-align:left;
    font-size:var(--fs-label); font-weight:600; letter-spacing:.1em;
    text-transform:uppercase; color:var(--noir-50);
  }
  .voy-table td:nth-child(1)::before{ content:"Référence"; }
  .voy-table td:nth-child(2)::before{ content:"Dates"; }
  .voy-table td:nth-child(3)::before{ content:"Prix / pers."; }
  .voy-table td:nth-child(4)::before{ content:"Accompagnateur"; }
  .voy-table td:nth-child(5)::before{ content:"Disponibilité"; }
  /* 6e cellule = les 2 boutons d'action : pas d'intitulé, pleine largeur, centrés */
  .voy-table td:nth-child(6){ display:block; padding-top:12px; }
  .voy-table td:nth-child(6)::before{ display:none; }

  /* l'accompagnateur (portrait + nom) reste lisible aligné à droite avec sa photo */
  .voy-table__guide{ justify-content:flex-end; text-align:right; }
}


/* ==========================================================================
   23. INFOS PRATIQUES — ICÔNE CENTRÉE, TEXTE DESSOUS — voyage.html — LOT 12 (25/07)
   Retour Nicolas : sur la fiche voyage, les cartes d'infos pratiques mettent
   l'icône À GAUCHE et le texte à droite (mode `#vfInfosGrid .vf-info`, une
   grille `auto 1fr`, style.css l.1794) - trop serré au téléphone. La version
   statique `.vf-info` (base, style.css l.1780) est DÉJÀ centrée (icône dessus,
   texte dessous). On revient donc simplement à ce rendu centré sous 1024px :
   la carte redevient un bloc, l'icône reprend `margin:0 auto`, le texte passe
   dessous et se recentre. Rien à changer côté HTML/JS. En display:block, les
   `grid-column`/`align-self`/`justify-self` des enfants (h3, p, __more) sont
   sans effet - pas besoin de les neutraliser un par un. */
@media (max-width:1024px){
  #vfInfosGrid .vf-info{ display:block; text-align:center; }
  #vfInfosGrid .vf-info__ico{ margin:0 auto 14px; }
}


/* ==========================================================================
   24. CONSEILS PHOTOGRAPHES — UN BLOC PAR LIGNE — voyage.html — LOT 12 (25/07)
   Retour Nicolas : la grille des conseils photo (`.voy-photo__grid`, 4 colonnes
   en desktop, style.css l.1586) passe déjà à 2 colonnes sous 900px (l.1599) -
   mais à 2 par ligne sur téléphone les cartes sont encore trop étroites. Un
   seul bloc par ligne sous 640px. */
@media (max-width:640px){
  .voy-photo__grid{ grid-template-columns:1fr; }
}


/* ==========================================================================
   25. BARRE D'ONGLETS NOIRE — INTERLIGNE RESSERRÉ — voyage.html — LOT 12 (25/07)
   Retour Nicolas : les 6 onglets de la fiche (`.vf-tabs`, sticky noire sous le
   header) retombent sur 2-3 lignes au téléphone, avec un écart vertical trop
   grand entre les lignes. Cause : `row-gap:6px` (style.css l.1681) + `padding:
   4px 0` sur chaque lien (l.1684) -> ~14px de blanc entre deux lignes. Sous
   1024px, on resserre le row-gap et le padding vertical des liens (le col-gap
   34px et la police restent - lisibilité et zone de tap horizontale intactes). */
@media (max-width:1024px){
  .vf-tabs__inner{ row-gap:2px; }
  .vf-tabs a{ padding:2px 0; }
}


/* ==========================================================================
   26. PANNEAU DE FILTRES — VERROU DÉFILEMENT HORIZONTAL — offres.html — LOT 12 (25/07)
   Retour Nicolas/Fix : le panneau de filtres off-canvas (§18) pouvait encore
   défiler latéralement. Mesuré à 375px (panneau = 300px) : le corps déborde de
   24px, cause UNIQUE = `.of-slider__val{min-width:88px}` (la valeur du budget,
   style.css l.2111) - la seule largeur mini desktop pas encore neutralisée
   (.of-pop, .of-list--*, .of-cal, .of-nivpop le sont déjà, §18). On neutralise
   ce min-width ET on pose le verrou `overflow-x:hidden` explicitement demandé
   par Fix (ceinture + bretelles : plus aucun débordement horizontal possible,
   quel que soit un futur filtre). Même cause racine que le point 17 (budget
   coupé), traité juste après pour la mise en forme du slider. */
@media (max-width:1024px){
  .of-panel__body{ overflow-x:hidden; }
  .of-panel__body .of-slider__val{ min-width:0; }
}


/* ==========================================================================
   27. BUDGET — SLIDER SUR 2 LIGNES — offres.html — LOT 12 (25/07)
   Retour Nicolas : dans le panneau de filtres, la valeur du budget (« ≤ 14 000 €»)
   est à l'étroit à droite - sur une seule ligne, le curseur (flex) et la valeur
   se disputent la largeur du panneau. Même cause racine que le point 16.
   Deux leviers, comme proposé par Fix : (1) panneau un peu plus large
   (min(80vw,340px) -> min(86vw,360px)) ; (2) le slider passe en grille 2 lignes :
   libellé + valeur en haut, curseur PLEINE LARGEUR dessous. `min-width:0` sur le
   range et la valeur pour qu'ils ne forcent aucune largeur mini. */
@media (max-width:1024px){
  :root{ --of-panel-w: min(86vw, 360px); }

  .of-panel__body .of-slider{
    display:grid; grid-template-columns:1fr auto; align-items:center;
    gap:12px 10px;
  }
  /* lignes explicites : libellé + valeur SUR LA MÊME 1re ligne, curseur pleine
     largeur en 2e ligne (sans grid-row imposé, l'auto-placement renvoyait la
     valeur sous le curseur -> 3 lignes). */
  .of-panel__body .of-slider__lbl{ grid-column:1; grid-row:1; }
  .of-panel__body .of-slider__val{ grid-column:2; grid-row:1; min-width:0; text-align:right; }
  .of-panel__body .of-slider__range{ grid-column:1 / -1; grid-row:2; width:100%; min-width:0; }
}


/* ==========================================================================
   28. RETOUCHES TACTILES DU PANNEAU DE FILTRES — offres.html — LOT 12 (25/07)
   Retours Fix, version mobile :
   (a) Budget : agrandir le cercle de la tirette (thumb 16px -> 26px) pour un
       tap au doigt plus facile. Le rail (4px) est inchangé, le thumb déborde
       dessus, c'est normal.
   (b) Filtre « Animal » : c'était le seul chip avec une icône, et le
       justify-content:space-between (§18) renvoyait son libellé au centre.
       On le ferre à gauche comme les autres chips : label JUSTE APRÈS l'icône
       (gap 8px hérité), chevron repoussé à droite par margin-left:auto. Les
       chips sans icône (Destination, Départ...) restent identiques (label déjà
       à gauche, chevron à droite). Icône un peu agrandie (18px -> 24px). */
@media (max-width:1024px){
  .of-panel__body .of-slider__range::-webkit-slider-thumb{ width:26px; height:26px; }
  .of-panel__body .of-slider__range::-moz-range-thumb{ width:26px; height:26px; }

  .of-panel__body .of-chip__btn{ justify-content:flex-start; }
  .of-panel__body .of-chip__car{ margin-left:auto; }
  .of-panel__body .of-chip .of-pic{ width:24px; height:24px; }

  /* Filtre Animal (retour Fix 25/07) : icône masquée tant qu'aucune famille n'est
     choisie -> juste le titre « Animal ». Une fois une famille sélectionnée, le chip
     devient .is-active et l'icône (mise à jour vers la famille par offres.js) réapparaît. */
  .of-panel__body .of-chip[data-chip="fam"]:not(.is-active) .of-pic{ display:none; }

  /* Filtre Niveau (retour Fix 25/07) : pattes plus grandes (16 -> 20px), ferrées à
     gauche juste après « Niveau » (justify-content:flex-start au lieu du space-between
     du §18) avec un léger espace (pattes pas collées au libellé), « TOUS/Difficile » +
     le « i » repoussés à droite (margin-left:auto). Côté droit : on écarte nettement le
     libellé de niveau du bouton « i » (retour Fix : « Difficile » passait sous le i). */
  .of-panel__body .of-grad{ justify-content:flex-start; }
  .of-panel__body .of-grad__pattes{ margin-left:6px; }
  .of-panel__body .of-grad__txt{ margin-left:auto; }
  .of-panel__body .of-grad__info{ margin-left:12px; }
  .of-panel__body .of-patte{ width:20px; height:20px; }
