/* =============================================================================
   components.css — composants partages par TROIS types de blocs ou plus
   =============================================================================
   Boutons, en-tete de site, pied de page, bouton de remontee. Autrement dit :
   le mobilier present sur TOUTES les pages, plus ce que trois blocs ou plus
   se partagent.

   ⚠️ Le seuil de trois n'est pas decoratif. En dessous, le style appartient au
   bloc qui l'utilise : le promouvoir trop tot cree un composant que personne ne
   partage, et que plus personne n'ose modifier.

   ⚠️ Et la regle d'or vaut ici aussi : un bloc deplace vers une autre page doit
   rester correct. Si un « composant » ne tient que grace au contexte d'une page,
   ce n'est pas un composant.

   Repris de la maquette figee (`_ressources/httpdocs/css/style.css`). Les
   commentaires d'origine sont conserves : ils portent des motifs de conception
   qu'aucune autre source ne documente.
   ============================================================================= */

/* =============================================================================
   BOUTONS  —  maquette, section « 4. Boutons » (l. 78-154)
   ============================================================================= */
/* ---------- 4. Boutons ---------- */
/* HAUTEUR UNIQUE : --btn-h pilote TOUS les boutons du site (border-box -> la bordure du .btn--ghost
   et la hauteur forcée d'une carte n'y changent rien). align-self:center empêche un parent flex
   d'étirer un bouton à la hauteur de son voisin. Le padding vertical devient inutile. */
.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:.5em;
  box-sizing:border-box; min-height:var(--btn-h); align-self:center;
  font-family:var(--sans); font-weight:600; font-size:var(--fs-small);
  letter-spacing:.02em; padding:0 26px; border-radius:40px;
  /* CONFINEMENT DES TRACES DE PATTES (sur .btn, pas sur une variante : TOUS les boutons les ont).
     · position:relative -> les empreintes se placent sur le bouton, pas sur son 1er parent positionné
     · isolation:isolate -> crée un stacking context, sinon le z-index:-1 des pattes les renvoie
       DERRIÈRE le fond du bouton (donc invisibles)
     · overflow:hidden   -> la piste est coupée au bord arrondi */
  position:relative; overflow:hidden; isolation:isolate;
  transition:transform .3s var(--ease), background .3s var(--ease), color .3s var(--ease), box-shadow .3s var(--ease);
}
.btn--primary{ background:var(--jaune); color:var(--noir); }
/* ===== ANIMATION « traces de pattes » (Fix 07/07) : au survol, des empreintes de patte
   TRAVERSENT le bouton EN DIAGONALE et s'effacent les unes après les autres (comme un animal
   qui marche dessus). Empreintes injectées par `js/components.js` (port d'ON_applyPaws() de la
   maquette ; .btn__paws/.btn__paw), chacune animée avec un délai décalé (apparition -> disparition
   en cascade). ⚠️ Sans ce script, ces règles n'ont rien à animer et rien ne le signale : c'est
   ainsi que l'effet a manqué jusqu'au 2026-11-12. ===== */
.btn__paws{ position:absolute; inset:0; z-index:-1; pointer-events:none; overflow:hidden; }
/* left/top désignent le CENTRE de l'empreinte (marges négatives = moitié de la taille) :
   le JS place les pattes par leur centre le long de l'axe de marche. */
/* L'empreinte est un MASQUE colorié par `currentColor` (= la couleur du TEXTE du bouton), et non
   plus une image au brun figé : elle s'adapte donc à chaque variante — sombre sur un bouton jaune
   ou blanc, claire sur un bouton noir ou un filet qui se remplit de noir au survol. L'opacité
   (jadis dans le `fill` du SVG) est désormais portée par les keyframes. */
.btn__paw{ position:absolute; width:15px; height:20px; margin:-10px 0 0 -7px; opacity:0;
  background-color:currentColor;
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='64.7' height='82.2' viewBox='0 0 64.7 82.2'%3E%3Cg fill='%23000'%3E%3Cpath d='M22.6,52c.4-1.7-2.2-6.2-3.4-7.4-1.2-1.2-8.3-3.1-10.4-4.1-2.2-1-4-.1-5.5.8C-1.2,44.1,0,54.1.8,57.1c.9,3,4.4,5.4,5.8,5.7,1.4.4,3.7-2.2,5.1-3.1s4.4-1.2,6.8-1.8c2.4-.6,3.6-4.3,4-6Z'/%3E%3Cpath d='M15.5,35.5c2.1,1.8,5.6,2.3,7.2,2.2,1.6-.2,5-2.1,4.9-6.4,0-4.4-.6-9.7-1.9-11.6-1.3-1.9-3.7-7.6-9.7-5.1-1.9.8-2.9,2.7-3.9,5-1,2.3-2,6.6-1.5,8.4.4,1.8,2.8,5.9,4.9,7.7Z'/%3E%3Cpath d='M36.9,36.7c2.9,3,7.2-2,9.4-4,2.2-2,3.5-7.8,3.1-9.8-.4-1.9-4-5-5.2-6.6-1.2-1.7-5.3-4.7-6.7-4.2-5.9,2.2-5.8,7.8-6.9,13.7-1.1,5.9,3.4,8,6.3,10.9Z'/%3E%3Cpath d='M61,37.2c-1.3-1.8-5.8-.9-8.5-.9-2.7,0-5.4,4.7-7.6,5.7-5.3,2.2-2.2,8.9-.3,10.9,1.9,2.1,4.1,3.9,6.2,5.4,2.1,1.5,5.8.7,8.6,0,2.8-.8,4-5.7,5.1-9.8,1.1-4.2-2.2-9.4-3.5-11.1Z'/%3E%3Cpath d='M48.3,63.5c-2.1-1.8-6.2-4.8-8-7.8-1.8-3-4-2.8-8.5-3.3-4.5-.5-8.7,5.9-10.7,8.3-2.5,2.9-6.9,10-6.1,14.3.8,4.3,5.7,4.7,10,6.2,4.2,1.5,6.9.9,15,.6,8.2-.3,9.8-4.9,11.8-8.8,2-3.9-1.3-7.7-3.4-9.5Z'/%3E%3Cpath d='M56.5,34c2.1-.5,3.4-.5,2.8-1.8-.7-1.3-1.9-4.3-2.9-3.8-1.1.6-2.9,2.4-2.7,3.8.1,1.4.8,2.3,2.9,1.9Z'/%3E%3Cpath d='M17,8.6c.8-.4,1.9-.5,3,0,1.2.5,2.1-.7,2.3-2.7.2-1.9,1.1-6.2-1.5-5.9-2.5.2-3.9,4-4.5,5.8-.6,1.8-.2,3.3.7,2.8Z'/%3E%3Cpath d='M36.3,9.3c1.5-.6,5.1-1.2,4.7-2.4-.4-1.1-3.5-7.3-5.6-4.8-1.1,1.4.1,3-.3,4.7-.5,1.8-.3,3,1.2,2.4Z'/%3E%3Cpath d='M6.7,35.6c1.1-.5.5-2.4-.7-3.8-1.2-1.4-1.4-2.5-2.6-.7s-1.5,3.3-.9,4.9c.7,1.8,3.1.1,4.2-.4Z'/%3E%3C/g%3E%3C/svg%3E") no-repeat center/contain;
          mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='64.7' height='82.2' viewBox='0 0 64.7 82.2'%3E%3Cg fill='%23000'%3E%3Cpath d='M22.6,52c.4-1.7-2.2-6.2-3.4-7.4-1.2-1.2-8.3-3.1-10.4-4.1-2.2-1-4-.1-5.5.8C-1.2,44.1,0,54.1.8,57.1c.9,3,4.4,5.4,5.8,5.7,1.4.4,3.7-2.2,5.1-3.1s4.4-1.2,6.8-1.8c2.4-.6,3.6-4.3,4-6Z'/%3E%3Cpath d='M15.5,35.5c2.1,1.8,5.6,2.3,7.2,2.2,1.6-.2,5-2.1,4.9-6.4,0-4.4-.6-9.7-1.9-11.6-1.3-1.9-3.7-7.6-9.7-5.1-1.9.8-2.9,2.7-3.9,5-1,2.3-2,6.6-1.5,8.4.4,1.8,2.8,5.9,4.9,7.7Z'/%3E%3Cpath d='M36.9,36.7c2.9,3,7.2-2,9.4-4,2.2-2,3.5-7.8,3.1-9.8-.4-1.9-4-5-5.2-6.6-1.2-1.7-5.3-4.7-6.7-4.2-5.9,2.2-5.8,7.8-6.9,13.7-1.1,5.9,3.4,8,6.3,10.9Z'/%3E%3Cpath d='M61,37.2c-1.3-1.8-5.8-.9-8.5-.9-2.7,0-5.4,4.7-7.6,5.7-5.3,2.2-2.2,8.9-.3,10.9,1.9,2.1,4.1,3.9,6.2,5.4,2.1,1.5,5.8.7,8.6,0,2.8-.8,4-5.7,5.1-9.8,1.1-4.2-2.2-9.4-3.5-11.1Z'/%3E%3Cpath d='M48.3,63.5c-2.1-1.8-6.2-4.8-8-7.8-1.8-3-4-2.8-8.5-3.3-4.5-.5-8.7,5.9-10.7,8.3-2.5,2.9-6.9,10-6.1,14.3.8,4.3,5.7,4.7,10,6.2,4.2,1.5,6.9.9,15,.6,8.2-.3,9.8-4.9,11.8-8.8,2-3.9-1.3-7.7-3.4-9.5Z'/%3E%3Cpath d='M56.5,34c2.1-.5,3.4-.5,2.8-1.8-.7-1.3-1.9-4.3-2.9-3.8-1.1.6-2.9,2.4-2.7,3.8.1,1.4.8,2.3,2.9,1.9Z'/%3E%3Cpath d='M17,8.6c.8-.4,1.9-.5,3,0,1.2.5,2.1-.7,2.3-2.7.2-1.9,1.1-6.2-1.5-5.9-2.5.2-3.9,4-4.5,5.8-.6,1.8-.2,3.3.7,2.8Z'/%3E%3Cpath d='M36.3,9.3c1.5-.6,5.1-1.2,4.7-2.4-.4-1.1-3.5-7.3-5.6-4.8-1.1,1.4.1,3-.3,4.7-.5,1.8-.3,3,1.2,2.4Z'/%3E%3Cpath d='M6.7,35.6c1.1-.5.5-2.4-.7-3.8-1.2-1.4-1.4-2.5-2.6-.7s-1.5,3.3-.9,4.9c.7,1.8,3.1.1,4.2-.4Z'/%3E%3C/g%3E%3C/svg%3E") no-repeat center/contain; }
/* au survol : chaque empreinte fait UN SEUL cycle apparition->disparition, décalé par --d (cascade).
   Pas de `infinite` : l'animal traverse une fois, puis la piste reste vide tant qu'on ne ressort pas.
   L'anim étant portée par :hover, elle est retirée à la sortie -> elle rejoue au survol suivant.
   --r = rotation de la patte (elle pointe dans le sens de la marche) ; --ox/--oy = décalage
   PERPENDICULAIRE à l'axe (gauche/droite de la foulée). Les deux sont posés par JS à chaque survol. */
.btn:hover .btn__paw{ animation:btnPawStep 1.4s var(--ease) 1 both; animation-delay:var(--d,0s); }
/* .42 = l'opacité qui vivait autrefois dans le `fill` du SVG (rgba(40,26,10,0.42)). */
@keyframes btnPawStep{
  0%   { opacity:0;   transform:translate(var(--ox,0px),var(--oy,0px)) rotate(var(--r,35deg)) scale(.7); }
  18%  { opacity:.42; transform:translate(var(--ox,0px),var(--oy,0px)) rotate(var(--r,35deg)) scale(1); }
  55%  { opacity:.42; }
  80%  { opacity:0;   transform:translate(var(--ox,0px),var(--oy,0px)) rotate(var(--r,35deg)) scale(1); }
  100% { opacity:0; }
}
.btn--primary:hover{ background:var(--jaune-d); transform:translateY(-3px); box-shadow:0 10px 26px -6px rgba(244,183,33,.65); }
.btn--primary:active{ transform:translateY(-1px); }
@media (prefers-reduced-motion: reduce){ .btn__paws{ display:none; } }
.btn--ghost{ border:1.5px solid currentColor; transition:transform .3s var(--ease), background .3s var(--ease), color .3s var(--ease), box-shadow .3s var(--ease); }
.btn--ghost:hover{ background:var(--noir); color:var(--creme); transform:translateY(-3px); box-shadow:0 10px 26px -8px rgba(0,0,0,.5); }
/* ----- variante SOMBRE du bouton fantome (sur fond clair : beige, creme, blanc) -----
   ⚠️ ELLE MANQUAIT JUSQU'AU 2026-09-30, alors que trois pages la demandaient deja
   (`pg_suite` d'Equipe, de la Charte et de Presentation). Sans elle, la bordure prenait
   `currentColor` a pleine force au lieu du noir a 30 % : un cadre plus dur que ce que la
   maquette dessine. Assez discret pour avoir traverse trois relectures a l'oeil — c'est
   le controle de couverture qui l'a trouve, sur la 4e page a l'employer. */
.btn--dark{ color:var(--noir); border-color:rgba(14,14,14,.3); }
.btn--dark:hover{ background:var(--noir); color:var(--creme); }
/* --lg = bouton plus LARGE (respiration horizontale), meme hauteur et meme typo que
   les autres. ⚠️ Ajoutee le 2026-10-01 avec le bloc `cta_devis`, premier a l'employer.
   Deuxieme variante manquante trouvee de cette facon, apres `.btn--dark` le 2026-09-30 :
   le systeme `.btn` de la maquette porte des modificateurs qu'aucun bloc deja decoupe
   n'avait reclames. Les suivants sortiront de la meme maniere — par le geste 1, quand
   une vue les ecrit litteralement. */
.btn--lg{ padding:0 38px; }
/* ----- variante fond BLANC / texte noir (sur fond sombre ou photo) ----- */
.btn--blanc{ background:var(--blanc); color:var(--noir); border:1.5px solid currentColor; }
.btn--blanc:hover{ background:var(--noir); color:var(--blanc); transform:translateY(-3px); box-shadow:0 10px 26px -8px rgba(0,0,0,.45); }
/* ----- variante fond NOIR / texte blanc ----- */
.btn--noir{ background:var(--noir); color:var(--blanc); }
.btn--noir:hover{ background:#242018; transform:translateY(-3px); box-shadow:0 10px 26px -8px rgba(0,0,0,.55); }
/* ----- variante filet CLAIR (fond sombre) : bord blanc, se remplit au survol ----- */
.btn--light{ border:1.5px solid rgba(255,255,255,.4); color:var(--blanc); background:rgba(20,17,12,.4); }
.btn--light:hover{ background:var(--jaune); border-color:var(--jaune); color:var(--noir); transform:translateY(-3px); box-shadow:0 10px 26px -8px rgba(0,0,0,.5); }
/* ----- variante fond VERT / texte blanc : bouton « S'inscrire » du trio CTA (Nicolas 07/15).
   3 CTA côte à côte = 3 couleurs : S'inscrire (vert) · Poser une option (jaune) · Nous contacter (filet). ----- */
.btn--vert{ background:var(--vert); color:var(--blanc); }
.btn--vert:hover{ background:var(--vert-d); transform:translateY(-3px); box-shadow:0 10px 26px -8px rgba(74,100,50,.6); }

/* ----- TRIO de CTA côte à côte (S'inscrire / Poser une option / Nous contacter) -----
   flex-wrap : passe en colonne quand les 3 ne tiennent pas ; centré. */
/* 3 boutons RIGOUREUSEMENT identiques : MÊME largeur fixe, même hauteur, même arrondi, partout
   (carte duo, esprit, tableau des départs, contact) — indépendant de la largeur du conteneur. */
.cta-trio{ display:flex; flex-wrap:wrap; gap:12px; align-items:stretch; }
/* !important : neutralise les marges résiduelles d'anciennes classes (vf-esprit__cta/__option,
   vf-duo__*, voy-table__btn…) qui décalaient les boutons et cassaient l'alignement du trio. */
.cta-trio .btn{ flex:0 0 auto !important; width:170px !important; min-width:0; margin:0 !important;
  padding:0 12px !important; text-align:center; }
@media (max-width:560px){ .cta-trio{ flex-direction:column; } .cta-trio .btn{ width:100% !important; } }


/* =============================================================================
   HEADER / NAV  —  maquette, section « HEADER / NAV » (l. 158-286)
   ============================================================================= */
/* ==========================================================================
   HEADER / NAV
   ========================================================================== */
.site-header{
  position:fixed; inset:0 0 auto 0; z-index:1000;   /* AU-DESSUS DE TOUT (site-content z210, fiche pays z200…) */
  transition:background .4s var(--ease), box-shadow .4s var(--ease);
}
/* Top-bar utilitaire — MASQUÉE (gain de place). Styles enfants retirés (code mort, .topbar est display:none). */
.topbar{ display:none; }

/* Barre de navigation principale */
/* le header s'aligne sur la FENÊTRE NOIRE (.hero__panel = 100% - 2*gutter, sans max-width 1440) :
   logo bord gauche = bord gauche fenêtre ; bouton Contact bord droit = bord droit fenêtre ; nav au centre. */
.site-header .container{ max-width:none; }
/* grille 3 colonnes : logo (gauche) | menu (centré) | contact (droite) */
.nav{
  height:var(--nav-h);
  display:grid; grid-template-columns:auto 1fr auto; align-items:center; gap:24px;
  transition:height .35s var(--ease);       /* COLLAPSE doux au scroll */
}
/* conteneur des 2 versions (MÊME viewBox 740.9x172.6 -> même taille). Boîte à ratio fixe, les 2 SVG
   superposés en absolute -> switch clair/sombre = simple fondu, AUCUN décalage. */
.nav__logo{ justify-self:start; position:relative; display:block;
  height:75px; width:auto; aspect-ratio:740.9 / 172.6;   /* -25% (était 100px) */
  transition:height .35s var(--ease); }
/* les DEUX logos en absolute, contenus dans la boîte (object-fit:contain, alignés à gauche) */
.nav__logo-img{ position:absolute; left:0; top:0; width:100%; height:100%;
  object-fit:contain; object-position:left center; display:block;
  transition:opacity .3s var(--ease); }
.nav__logo-img--dark{ opacity:0; pointer-events:none; }
.nav__logo-img--light{ opacity:1; }
/* fond clair (on-light) -> on montre la version à TEXTE NOIR (vrai logo, pas un brightness:0) */
.site-header.on-light .nav__logo-img--light{ opacity:0; }
.site-header.on-light .nav__logo-img--dark{ opacity:1; }
/* fond sombre (on-dark / défaut) -> version claire */
.site-header.on-dark .nav__logo-img--light{ opacity:1; }
.site-header.on-dark .nav__logo-img--dark{ opacity:0; }
/* ===== HEADER COLLAPSE (au scroll, classe .is-solid) : header + logo réduits à ~75% ===== */
.site-header.is-solid .nav{ height:var(--nav-h-collapsed); }
.site-header.is-solid .nav__logo{ height:53px; }   /* -25% (était 70px) : collapse */
/* ⚠️ D111 — UNE ENTRÉE DE MENU N'EST PAS TOUJOURS UN LIEN. Un parent sans slug
   (« Qui sommes-nous ») ne fait que regrouper ses sous-pages : le gabarit rend alors
   un `<span class="nav__label">` et non un `<a>`. La maquette, elle, ne connaissait
   que des liens — tous ses sélecteurs sont en `> a`. Chaque règle du menu vaut donc
   AUSSI pour `> .nav__label`, sans quoi cette entrée perd majuscules, taille,
   soulignement et état actif, sans la moindre erreur. Ne pas « simplifier » en
   retirant ces sélecteurs doubles. */
.nav__menu{ display:flex; align-items:center; justify-content:center; gap:30px;
  justify-self:stretch; }   /* menu CENTRÉ dans l'espace libre logo <-> bouton Contact */
.nav__cta{ justify-self:end; }            /* bouton Contact collé au bord droit (= bord fenêtre) */
/* page active = .is-active sur le <li> OU aria-current="page" sur le <a> (les 2 conventions coexistaient). */
.nav__menu > li.is-active > a, .nav__menu > li.is-active > .nav__label,
.nav__menu > li > a[aria-current="page"], .nav__menu > li > .nav__label[aria-current="page"]{ color:var(--jaune); font-weight:400; }   /* page active : jaune + light (fond sombre = état par défaut) */
.nav__menu > li > a,
.nav__menu > li > .nav__label{
  font-size:var(--fs-nav); font-weight:500; letter-spacing:.06em; text-transform:uppercase;   /* menu principal en MAJUSCULES (hiérarchie, Fix 09/07) */
  color:var(--blanc); padding:8px 0; position:relative;
  transition:color .3s var(--ease);
}
.nav__menu > li > a::after,
.nav__menu > li > .nav__label::after{
  content:""; position:absolute; left:0; bottom:0; height:2px; width:0;
  background:var(--jaune); transition:width .3s var(--ease);
}
.nav__menu > li > a:hover::after,
.nav__menu > li.is-active > a::after,
.nav__menu > li.is-active > .nav__label::after,
.nav__menu > li > a[aria-current="page"]::after{ width:100%; }
.nav__has-sub > a::before{ content:""; }
.nav__has-sub > a span.caret,
.nav__has-sub > .nav__label span.caret{
  display:inline-block; margin-left:6px; font-size:10px; transform:translateY(-1px);
}
/* .nav__cta : placement géré par justify-self:end (grille) -> pas de margin-left ici */
/* ÉCRANS LARGES MAIS ÉTROITS (1025-1499 px) — sprint 2026-11-09. À sa taille de la maquette, le
   menu demande ~1470 px pour tenir sur une ligne (logo 322 px en haut de page, six entrées
   majuscules, 30 px entre elles), et la version téléphone ne prend le relais qu'à 1024 px :
   entre les deux, les entrées se cassaient sur deux ou trois lignes, « QUI SOMMES-NOUS ▾ »
   comprise. Resserré ici (texte, espacements, logo fluide), il tient sur une ligne dès
   ~1250 px ; en dessous, chaque entrée passe sur deux lignes centrées au plus. */
@media (min-width:1025px) and (max-width:1499px){
  .nav{ gap:16px; }
  .nav__logo{ height:clamp(46px, 4.4vw, 60px); }
  .site-header.is-solid .nav__logo{ height:clamp(42px, 3.8vw, 53px); }
  .nav__menu{ gap:clamp(12px, 1.4vw, 22px); }
  .nav__menu > li > a,
  .nav__menu > li > .nav__label{ font-size:13px; letter-spacing:.04em; line-height:1.25;
    display:inline-block; text-align:center; }
  .nav__has-sub > a span.caret,
  .nav__has-sub > .nav__label span.caret{ margin-left:4px; }
}

/* État solidifié (au scroll hors hero) — appliqué via JS */
.site-header.is-solid{
  background:var(--noir);
  box-shadow:0 6px 30px rgba(0,0,0,.18);
}
.site-header.is-solid .topbar{ border-color:rgba(255,255,255,.10); }

/* HEADER SUR FOND CLAIR : fond crème + textes/logo NOIRS -> lisible quand on scrolle sur le contenu clair. */
.site-header.on-light{ background:var(--creme); box-shadow:0 6px 24px rgba(0,0,0,.10); }
.site-header.on-light .topbar,
.site-header.on-light .nav__menu > li > a,
.site-header.on-light .nav__menu > li > .nav__label,
.site-header.on-light .nav__menu > li > a .caret,
.site-header.on-light .nav__menu > li > .nav__label .caret{ color:var(--noir); }
.site-header.on-light .nav__menu > li.is-active > a,
.site-header.on-light .nav__menu > li.is-active > .nav__label,
.site-header.on-light .nav__menu > li > a[aria-current="page"]{ color:var(--noir); }   /* fond clair : page active reste noire (juste soulignée) */
/* logo : sur fond clair on affiche la VRAIE version foncée (cf. .nav__logo-img--dark) -> plus de filtre. */
.site-header.on-light .nav__burger span{ background:var(--noir); }

/* HEADER SUR FOND SOMBRE : fond sombre translucide + textes/logo BLANCS -> lisible sur section sombre. */
.site-header.on-dark{ background:rgba(14,14,14,.55); backdrop-filter:blur(8px); box-shadow:0 6px 24px rgba(0,0,0,.25); }
.site-header.on-dark .nav__menu > li > a,
.site-header.on-dark .nav__menu > li > .nav__label,
.site-header.on-dark .nav__menu > li > a .caret,
.site-header.on-dark .nav__menu > li > .nav__label .caret{ color:var(--blanc); }
/* (la page active en jaune light est déjà gérée par .nav__menu > li.is-active > a ; on-light la repasse en noir) */
.site-header.on-dark .nav__logo img{ filter:none; }   /* logo d'origine (clair) -> visible sur sombre */
/* CAS PLANISPHÈRE : header transparent (ni fond noir, ni blur, ni ombre) -> on voit la carte et les
   oiseaux. Garde on-dark pour le texte/logo blancs. Prime sur is-solid ET on-dark (demande Fix 09/07). */
.site-header.on-hero,
.site-header.on-hero.is-solid,
.site-header.on-hero.on-dark{ background:transparent; backdrop-filter:none; box-shadow:none; }
.site-header.on-dark .nav__burger span{ background:var(--blanc); }

/* Mega-menu (Nos offres) */
.nav__has-sub{ position:relative; }
/* PONT invisible : comble l'espace entre le lien et le menu pour que le :hover ne se perde pas
   quand la souris descend vers le menu (sinon le menu se ferme avant qu'on l'atteigne). */
.nav__has-sub::after{
  content:""; position:absolute; top:100%; left:0; right:0; height:18px;
  opacity:0; pointer-events:none;
}
.nav__has-sub:hover::after{ pointer-events:auto; }
.megamenu{
  position:absolute; top:calc(100% + 16px); left:50%; transform:translateX(-50%) translateY(8px);
  z-index:120;                                  /* au-dessus de tout le header */
  background:var(--creme); color:var(--noir);
  min-width:300px; padding:24px 28px; border-radius:16px;
  box-shadow:0 24px 60px rgba(0,0,0,.22);
  opacity:0; visibility:hidden; pointer-events:none;
  transition:opacity .25s var(--ease), transform .25s var(--ease);
}
.nav__has-sub:hover .megamenu{ opacity:1; visibility:visible; pointer-events:auto; transform:translateX(-50%) translateY(0); }
.megamenu h4{ font-family:var(--display); font-size:var(--fs-small); letter-spacing:.08em; color:var(--noir-50); margin-bottom:14px; }
/* item = icône famille (pastille) + libellé */
.megamenu ul li a{
  display:flex; align-items:center; gap:12px; padding:9px 0; font-size:var(--fs-small); font-weight:500;
  border-bottom:1px solid var(--creme-2); transition:color .2s, padding .2s;
}
.megamenu ul li a:hover{ color:var(--jaune-d); padding-left:6px; }
.megamenu ul li a[aria-current="page"]{ color:var(--jaune-d); font-weight:600; }   /* sous-page courante */
.megamenu ul li:last-child a{ border-bottom:none; }

/* Burger (mobile) */
.nav__burger{ display:none; width:30px; height:22px; position:relative; }
.nav__burger span{ position:absolute; left:0; height:2px; width:100%; background:var(--blanc); transition:.3s var(--ease); }
.nav__burger span:nth-child(1){ top:0; }
.nav__burger span:nth-child(2){ top:10px; }
.nav__burger span:nth-child(3){ top:20px; }


/* =============================================================================
   FOOTER  —  maquette (l. 1412-1465)
   ============================================================================= */
/* ---- FOOTER ---- */
/* SCÈNE : back (dans le flux, donne la hauteur) + front superposé pixel-perfect + logo intercalé.
   Les LIENS sont par-dessus la savane (absolute, calés en bas). PARALLAXE douce.
   Fond = beige des nuages EN HAUT (jamais de bande noire) ; le bas est couvert par le front (savane). */
.site-footer{ position:relative; overflow:hidden; background:var(--beige-footer); color:rgba(255,255,255,.92); }
/* MASQUE BAS : recouvre toute bande BLEUE résiduelle (halo bas du back.png) sous la savane.
   Couleur = sol bas de la savane (#3b2c1f). z entre front(3) et liens(5). */
.site-footer::after{ content:""; position:absolute; left:0; right:0; bottom:-1px; height:14px;
  background:#3b2c1f; z-index:4; pointer-events:none; }

.footer__scene{ position:relative; width:100%; line-height:0; z-index:0; pointer-events:none; }
/* back EN FLUX, FIXE (non animé) : donne la hauteur du footer, jamais de bande au-dessus. */
.footer__back{ position:relative; display:block; width:100%; height:auto; z-index:1; margin-bottom:-1px; }
/* front : descend jusqu'en bas + plus large que back -> couvre toute bande résiduelle (plus de bleu). */
.footer__front{ position:absolute; left:50%; bottom:0; width:101%; height:auto; z-index:3;
  transform:translate(-50%, var(--front-y, 0px)); will-change:transform; }
/* LOGO géant intercalé (ENTRE back z1 et front z3), centré, remonte du bas vers le haut au scroll */
.footer__biglogo{ position:absolute; left:50%; top:22%;
  transform:translate(-50%, var(--logo-y, 0px)); width:min(46%, 560px); height:auto; z-index:2;
  filter:drop-shadow(0 8px 24px rgba(0,0,0,.30)); will-change:transform; }

/* liens du footer : PAR-DESSUS la scène, calés EN BAS (un peu remontés) + parallaxe (--links-y). */
.footer__links{ position:absolute; left:0; right:0; bottom:24px; z-index:5;
  transform:translateY(var(--links-y, 0px)); will-change:transform; }
.footer__links::before{ content:""; position:absolute; left:0; right:0; top:-40px; bottom:-40px; z-index:-1;
  background:linear-gradient(to top, rgba(10,7,4,.92) 0%, rgba(10,7,4,.72) 55%, rgba(10,7,4,0) 100%); }
.footer__top, .footer__bottom{ position:relative; z-index:5; }

.footer__top{ display:grid; grid-template-columns:1.6fr 1fr 1fr 1.4fr; gap:clamp(28px,3vw,56px); padding-bottom:46px;
  border-bottom:1px solid rgba(255,255,255,.12); }
.footer__tag{ font-size:var(--fs-small); line-height:1.5; margin-bottom:18px; color:rgba(255,255,255,.6); }
/* Réseaux sociaux : icônes dans des RONDS JAUNES (retour client 03/07) */
.footer__soc{ display:flex; gap:12px; }
.footer__soc a{ width:44px; height:44px; border-radius:50%;
  background:var(--jaune); color:var(--noir);
  display:grid; place-items:center;
  transition:background .2s var(--ease), transform .2s var(--ease), box-shadow .2s var(--ease); }
.footer__soc a:hover{ background:var(--jaune-d); transform:translateY(-3px);
  box-shadow:0 10px 22px -8px rgba(244,183,33,.6); }
.footer__soc svg{ width:22px; height:22px; fill:currentColor; }
/* Logos Atout France et Les Entreprises du Voyage (sprint 2026-11-09 n° 6). Élément de grille
   distinct de la marque : sur écran large il occupe la 1re colonne SOUS l'accroche et les
   réseaux, pendant que les deux colonnes de liens et la newsletter s'étendent sur les deux
   rangées. Le bloc des liens ne grandit donc pas (il est posé en absolu sur la scène). */
.footer__brand{ grid-column:1; grid-row:1; }
.footer__labels{ grid-column:1; grid-row:2; align-self:start;
  display:flex; flex-wrap:wrap; align-items:center; gap:14px 18px; }
.footer__col, .footer__news{ grid-row:1 / span 2; }
.footer__top{ row-gap:20px; }
/* Hauteurs FLUIDES : vers 1100 px la 1re colonne ne fait que ~250 px, et deux logos qui
   passent l'un sous l'autre font grandir le bloc des liens, qui remonte alors sur le grand
   logo de la scène. Calculé pour tenir sur une ligne dès 1025 px. */
.footer__label{ display:block; width:auto; height:var(--label-h, clamp(32px,2.7vw,38px)); }
/* Atout France : ses lettres n'occupent qu'une bande étroite du bloc ; à hauteur égale
   avec son voisin, il paraissait deux fois plus petit. */
.footer__label--af{ --label-h:clamp(37px,3.1vw,43px); }
.footer__col h4, .footer__news h4{ font-size:var(--fs-label); letter-spacing:.1em; text-transform:uppercase; color:var(--blanc); margin-bottom:16px; }
.footer__col{ display:flex; flex-direction:column; gap:11px; }
.footer__col a{ font-size:var(--fs-small); color:rgba(255,255,255,.68); transition:color .2s; }
.footer__col a:hover{ color:var(--jaune); }
.footer__news p{ font-size:var(--fs-small); line-height:1.5; color:rgba(255,255,255,.6); margin-bottom:16px; }
.footer__form{ display:flex; gap:8px; }
.footer__form input{ flex:1; min-width:0; padding:12px 16px; border-radius:30px; border:1px solid rgba(255,255,255,.2);
  background:rgba(255,255,255,.06); color:var(--blanc); font:inherit; font-size:var(--fs-small); }
.footer__form input::placeholder{ color:rgba(255,255,255,.4); }
.footer__form .btn{ padding:0 20px; }
/* Réponse du formulaire newsletter (D149) — AJOUT : la maquette n'envoyait rien et n'avait
   donc pas de réponse à afficher. Même corps de texte que le paragraphe d'accroche. */
.footer__news .footer__form-msg{ margin:12px 0 0; color:rgba(255,255,255,.85); }
.footer__news .footer__form-msg.is-ko{ color:var(--jaune); }
/* ⚠️ `display:flex` d'auteur l'emporte sur l'attribut `hidden` : sans cette règle, le
   formulaire resterait affiché après l'envoi. */
.footer__form[hidden]{ display:none; }
.footer__bottom{ display:flex; align-items:center; justify-content:space-between; padding-top:20px; font-size:var(--fs-small); color:rgba(255,255,255,.78); }
.footer__legal a{ color:rgba(255,255,255,.82); transition:color .2s; }
.footer__legal a:hover{ color:var(--jaune); }
.footer__design{ color:rgba(255,255,255,.78); }   /* crédit "Design : Agence K2" (droite) */
/* SCÈNE TROP BASSE ENTRE 1025 ET 1399 PX — sprint 2026-11-09. La scène suit la LARGEUR (calques
   1800x720, soit 40 % de la largeur), alors que le bloc des liens garde ~300 px : vers 1100 px la
   scène ne fait plus que 440 px, les liens remontent jusque sur le grand logo, et le bas du logo
   passait 34 px SOUS les titres des colonnes (mesuré dans Chrome). Hauteur plancher de 560 px,
   et les deux calques recadrés par le BAS (object-fit:cover) — même parade que le téléphone
   plus bas : le sol ne bouge pas, seul le ciel et les côtés sont rognés. Au-delà de 1400 px,
   40 % de la largeur dépasse 560 px : rien ne change. */
@media (min-width:1025px) and (max-width:1399px){
  .footer__scene{ height:560px; }
  .footer__back{ position:absolute; inset:0; width:100%; height:100%; margin-bottom:0;
    object-fit:cover; object-position:center bottom; }
  .footer__front{ top:0; height:100%; object-fit:cover; object-position:center bottom; }
}
/* ⚠️ AJOUT K2, ABSENT DE LA MAQUETTE (demande du 2026-09-28) : le crédit est devenu un
   lien vers l'agence, ouvert dans un nouvel onglet. Le rendu au repos ne doit PAS bouger
   — la couleur et l'absence de soulignement viennent du reset (`a{color:inherit;
   text-decoration:none}`), il n'y a donc rien à redéclarer ici. Seul le survol change. */
.footer__design a:hover{ text-decoration:underline; }

/* =============================================================================
   BOUTON « REMONTER EN HAUT »  —  maquette (l. 1490-1504)
   ============================================================================= */
/* ===== Bouton FLOATING "remonter en haut" (bas-droite) ===== */
.scroll-top{
  position:fixed; right:clamp(18px,2.4vw,32px); bottom:clamp(18px,2.4vw,32px);
  z-index:990; width:52px; height:52px; border:0; border-radius:50%;
  background:var(--noir); color:var(--blanc); cursor:pointer;
  display:flex; align-items:center; justify-content:center;
  box-shadow:0 12px 30px -8px rgba(0,0,0,.5);
  opacity:0; visibility:hidden; transform:translateY(14px) scale(.92);
  transition:opacity .3s ease, transform .3s ease, visibility .3s, background .2s;
}
.scroll-top.is-visible{ opacity:1; visibility:visible; transform:translateY(0) scale(1); }
.scroll-top:hover{ background:var(--jaune); color:var(--noir); }
.scroll-top svg{ display:block; }
@media (max-width:560px){ .scroll-top{ width:46px; height:46px; } }

/* #############################################################################
   RESPONSIVE DU GABARIT — repris de la maquette figee (`mobile.css`)
   #############################################################################
   ⚠️ OUBLI CORRIGE LE 2026-09-28 : la premiere extraction n'avait repris que
   `style.css`. Tout le comportement mobile de l'en-tete et du pied de page
   manquait — menu, pilule flottante, grille du footer, cibles tactiles. Le
   bureau etait juste, le telephone ne l'etait pas, et rien ne le signalait.
   Penser `mobile.css` AUTANT que `style.css` a chaque bloc decoupe.
   ############################################################################# */

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



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

  /* ---- Anneau de focus des TROIS boutons de la pilule ----
     L'anneau par defaut de Chrome est BLEU : hors charte, et tres visible sur le fond
     sombre. On ne le SUPPRIME pas — c'est une aide clavier — on le redessine en jaune,
     et via `:focus-visible` pour qu'il n'apparaisse qu'au clavier, jamais au tap.
     ⚠️ CES SIX LIGNES MANQUAIENT JUSQU'AU 2026-10-01, et pour la MEME raison que la
     grille du pied de page : dans `mobile.css` (l. 1464-1471) elles sont PARTAGEES
     avec `.of-panel__close` et `.of-panel__reset`, deux composants de la page Offres
     non decoupee. En extrayant par page, la part globale part avec.
     ⚠️ C'est donc le deuxieme cas du meme piege dans ce seul fichier : une `@media`
     ou une regle de la maquette melange du GLOBAL et du PAGE. Avant de sauter un
     bloc comme « page non decoupee », lire ses selecteurs un par un. */
  .mob-fab .mob-burger:focus,
  .mob-fab .mob-fab__btn:focus,
  .mob-fab .scroll-top:focus{ outline:none; }

  .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;
  }

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



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

  /* ⚠️ CETTE LIGNE MANQUAIT JUSQU'AU 2026-10-01, et c'est ce qui rendait le pied de
     page illisible sur telephone : la grille restait a QUATRE colonnes
     (`1.6fr 1fr 1fr 1.4fr`), donc « Nos offres » et « L'agence » tenaient chacune
     dans ~70 px sur un iPhone 13. Signale par Alexandre.
     ⚠️ POURQUOI ELLE AVAIT ETE PERDUE, parce que le cas se reproduira : dans
     `mobile.css` (l. 518) elle vit dans une `@media` PARTAGEE avec `.depforts__grid`,
     `.blog__grid` et `.testimonials__grid` — trois blocs de la page d'accueil non
     decoupee. Le bloc a ete saute comme « accueil seulement », et la ligne globale
     est partie avec. Une `@media` de la maquette melange des composants GLOBAUX et
     des blocs de page : la lire en entier, jamais la trier sur son premier selecteur.
     ⚠️ Elle doit rester AVANT les deux autres regles `.footer__top` de ce meme bloc,
     qui ne font qu'affiner `gap` et `row-gap` — les placer avant annulerait leur effet. */
  .footer__top{ grid-template-columns:1fr 1fr; gap:clamp(20px,4vw,36px); }    /* 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. le commentaire « 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" */
  /* Logos : placement du bureau annulé ; ils passent APRÈS les deux colonnes de liens, sur
     toute la largeur — avant elles, ils les pousseraient dans la bande de la pilule. */
  .footer__brand, .footer__labels, .footer__col, .footer__news{ grid-column:auto; grid-row:auto; }
  .footer__labels{ order:5; grid-column:1 / -1; justify-content:center; margin-top:14px; }

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

  /* ⚠️ TOUT CE QUI SUIT MANQUAIT JUSQU'AU 2026-10-01. Ce bloc s'arretait sur le
     commentaire « Vignettes / cartes » suivi de RIEN : une extraction interrompue en
     cours de route, qui ne se voyait pas — un `:hover` colle apres un tap n'a aucun
     symptome sur un poste de travail, et `@media (hover:none)` ne matche jamais une
     souris. Seules les entrees portant sur des classes que NOUS avons sont reprises ;
     le bloc de la maquette (`mobile.css` l. 780-885, 106 lignes) couvre aussi des
     pages non decoupees — les y reprendre n'aurait style personne. */

  /* Vignettes / cartes */
  .eq-carte:hover{ transform:none; box-shadow:none; }
  .rcp-mini:hover{ transform:none; }
  /* La carte d'article REVIENT A SON OMBRE DE REPOS, pas a `none` : elle en a une
     par defaut, la retirer la rendrait plate en permanence sur telephone. */
  .post:hover{ transform:none; box-shadow:0 14px 40px rgba(0,0,0,.08); }

  /* Bandeau des photographes : la photo revient a son gris de REPOS (`.25`), pas a
     `none` — elle est volontairement desaturee au repos. Et surtout, le defilement
     ne doit PAS se figer : `animation-play-state:paused` au survol est fait pour la
     souris ; au doigt, un tap figerait le bandeau sans moyen de le relancer. */
  .pgr-item:hover .pgr-item__photo{ transform:none; filter:grayscale(.25); }
  .pgr-marquee:hover .pgr-row{ animation-play-state:running; }
  .pg-dest__item:hover{ transform:none; }

  /* Pied de page et bouton de remontee */
  .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); }

  /* ⚠️ LA PLUS IMPORTANTE DES DEUX SUIVANTES. Le mega-menu desktop s'ouvre au seul
     `:hover` : au doigt, il est soit mort, soit colle. Le volet mobile le remplace
     (cf. `js/mobile.js`), donc on le neutralise franchement ici. */
  .nav__has-sub:hover .megamenu{ opacity:0; visibility:hidden; pointer-events:none; }

  /* L'obturateur est anime en CSS pur par `.iris-trigger:hover`, sans `mouseleave` :
     un tap qui reste colle en `:hover` (Safari iOS, lien sans gestionnaire dedie)
     rejouerait le cycle en boucle. Purement decoratif — la photo reste visible. */
  .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; }
}

/* ============================================================================
   NAVIGATION ENTRE FICHES — les deux fleches fixes a mi-hauteur
   ============================================================================
   Repris de `style.css` l. 2403-2412. Partagee : la fiche de RECIT l'emploie
   aujourd'hui, les fiches PAYS et VOYAGE l'emploieront (elles ne sont pas encore
   decoupees). D'ou `components.css` plutot que le CSS d'une page.

   Le nom de la cible se deplie au survol (`max-width` de 0 a 220px) : c'est ce qui
   permet a une fleche de tenir dans un rond de 44px sans etre muette.

   ⚠️ TOUTE CETTE NAVIGATION EST MASQUEE SOUS 1024px — la regle existe deja plus
   bas dans ce fichier (`.py-nav, .rcp-nav{ display:none; }`). Ce n'est pas une
   degradation : sur telephone, deux fleches fixes mangeraient les bords de l'ecran
   et entreraient en conflit avec la pilule du menu mobile. Ne pas les y ramener.
   ============================================================================ */
.py-nav{ position:fixed; top:50%; transform:translateY(-50%); z-index:600;
  display:flex; align-items:center; background:var(--blanc); color:var(--noir);
  border:1px solid rgba(14,14,14,.15); border-radius:999px; padding:11px;
  box-shadow:0 10px 30px rgba(0,0,0,.18); }
.py-nav svg{ width:22px; height:22px; flex:0 0 auto; }
.py-nav span{ max-width:0; overflow:hidden; white-space:nowrap; font-size:var(--fs-label);
  font-weight:700; transition:max-width .3s var(--ease), padding .3s var(--ease); }
.py-nav:hover span{ max-width:220px; }
.py-nav--prev{ left:14px; } .py-nav--prev:hover span{ padding-left:8px; }
.py-nav--next{ right:14px; flex-direction:row-reverse; } .py-nav--next:hover span{ padding-right:8px; }

/* ============================================================================
   APPARITIONS AU DEFILEMENT — le rendu du moteur `js/scroll-reveal.js`.
   ============================================================================
   Tout le rendu est ICI ; le JS ne pose que des NOMBRES (`--p` par element) et
   des CLASSES. La chaine est : `--p` (JS) -> `--pp` (progression locale, CSS) ->
   `--pw` (cascade par mot, CSS).

   Ces regles sont dans `components.css` et non dans un CSS de bloc parce que le
   systeme traverse DIX types de sections (cf. la liste de selecteurs de
   `scroll-reveal.js`) : le mettre dans l'un d'eux priverait les neuf autres de
   leur animation des qu'ils seraient seuls sur une page.

   ⚠️ L'EN-TETE DE CE BLOC DANS LA MAQUETTE EST PERIME — on ne l'a pas recopie.
   Il decrit un systeme `.rv-armed` / `.rv-in` pilote par IntersectionObserver qui
   n'existe PLUS (0 occurrence dans son JS). Le systeme vivant est celui-ci,
   pilote par le defilement et donc REVERSIBLE : on remonte, l'animation se
   replie. L'en-tete du bloc suivant, lui, est juste — il dit « systeme actif ».
   Lire D121 avant de toucher a ces regles.

   ⚠️ REGLE D'OR, et elle tient par le JS : l'etat « masque » n'existe QUE par les
   classes `.rv-part` / `.rv-scrub`, que seul `scroll-reveal.js` ajoute. Ne JAMAIS
   les ecrire dans une vue : la page deviendrait invisible si le JS ne tournait pas.

   ⚠️ `--span` ne doit jamais valoir 0 : la division de `--pp` rendrait la valeur
   invalide, et l'element resterait a `opacity:0` — invisible, sans erreur.
   ============================================================================ */

/* === SÉQUENCEMENT PAR SECTION (système actif) ===
   --p est posé sur la SECTION (progression scroll). Chaque élément a sa fenêtre [--from, --from+--span].
   Sa progression LOCALE --pp = (--p - --from) / --span, bornée 0..1. -> les éléments s'animent l'un
   APRÈS l'autre (le texte finit avant les cartes). Réversible (lié au scroll).
   --p est HÉRITÉ de la section (CSS custom props héritent). */
.rv-part, .rv-scrub.rv{ --from:0; --span:.22; }
.rv-part, .rv-scrub.rv{
  --pp:max(0, min(1, calc((var(--p, 0) - var(--from)) / var(--span))));
}

/* eyebrow + parts génériques : fondu + montée selon --pp. */
.rv-part{ opacity:var(--pp); transform:translateY(calc((1 - var(--pp)) * 50px)); }

/* cartes / blocs de contenu : fondu + montée selon --pp (chacun a un --from croissant -> 1 à 1, G->D). */
.rv-scrub.rv{ opacity:var(--pp); transform:translateY(calc((1 - var(--pp)) * 48px)); }

/* le TITRE (.rv-words) : le conteneur ne bouge pas ; chaque MOT se défloute selon --pp + rang --wi. */
.rv-part.rv-words{ opacity:1; transform:none; }

/* TEXTE DESCRIPTIF (.rv-wipe = sous-titre) : MASQUE qui s'ouvre de GAUCHE à DROITE selon --pp. */
.rv-part.rv-wipe{
  opacity:1; transform:none;
  clip-path:inset(0 calc((1 - var(--pp)) * 100%) 0 0);
}
.rv-words .rv-word{ display:inline-block;
  /* cascade G->D des mots À L'INTÉRIEUR de la fenêtre du titre : rang --wi sur --nw. */
  --pw:max(0, min(1, calc((var(--pp) - (var(--wi) / var(--nw, 6)) * 0.55) / 0.45)));
  opacity:var(--pw);
  filter:blur(calc((1 - var(--pw)) * 14px));
  transform:translateY(calc((1 - var(--pw)) * 8px));
}

/* ==========================================================================
   BOUTON DE FILTRE À CHOIX UNIQUE — composant partagé.

   La maquette le déclare tel quel (`style.css:1984-1996`) : « Bouton de filtre à CHOIX
   UNIQUE, partagé par accompagnateurs (.gd-fbtn) / récits (.rc-fbtn). Même forme (chip
   blanche coins arrondis 10px), même typo, mêmes états. »

   ⚠️ IL A VÉCU DANS `recits-liste.css` DU 2026-10-06 AU 2026-10-06 — le temps d'avoir un
   seul consommateur. La note qui l'accompagnait disait « au second consommateur,
   promouvoir ici et rétablir le sélecteur double » : c'est fait. Ne pas le redescendre
   dans un CSS de bloc, et ne pas le dupliquer — c'est le composant que Fix a unifié pour
   que tous les filtres du site se ressemblent.

   ⚠️ Les deux `@media` viennent avec lui, et la seconde a un motif MESURÉ par la maquette
   (`mobile.css:1879`) : à 375 px les boutons passaient sur DEUX lignes (« Europe »
   retombait seul), et c'est le PADDING qui cède, jamais la police — `--fs-small` reste à
   15 px, donc la hauteur tactile (~45 px) ne bouge pas. `9px 4px` est la valeur minimale
   testée qui tient sur une ligne ; 5 px repassait à deux.
   ========================================================================== */
.gd-fbtn, .rc-fbtn{
  display:inline-flex; align-items:center; gap:8px; font:inherit; font-size:var(--fs-small);
  font-weight:600; letter-spacing:0; color:var(--noir); background:var(--blanc);
  border:1.5px solid transparent; border-radius:10px; padding:9px 15px; cursor:pointer;
  transition:border-color .2s, background .2s, color .2s; }
.gd-fbtn:hover, .rc-fbtn:hover{ border-color:rgba(244,183,33,.5); }
.gd-fbtn.is-on, .rc-fbtn.is-on{ background:var(--jaune); border-color:var(--jaune); color:var(--noir); }

/* `mobile.css:782` — au doigt, le survol reste collé après le tap. */
@media (hover:none){
  .gd-fbtn:hover, .rc-fbtn:hover{ border-color:transparent; }
}

/* `mobile.css:1896` — tenir sur UNE ligne à 375 px, cf. l'encadré ci-dessus. */
@media (max-width:640px){
  .gd-fbtn, .rc-fbtn{ padding:9px 4px; }
}

/* ==========================================================================
   LIEN VERS UNE FICHE D'ACCOMPAGNATEUR — `[data-guide]`.

   Tout element portant `data-guide="<slug>"` mene a la fiche du guide. Le curseur est
   ici parce que le COMPORTEMENT est global lui aussi (delegation sur `document` dans
   `common.js`) : le style et le geste vivent au meme niveau.

   ⚠️ LA TEINTE DE SURVOL, ELLE, EST PROPRE A CHAQUE CONSOMMATEUR et reste dans son CSS
   de bloc. La maquette la declare en une regle MIXTE (`style.css:2243`) qui melange
   `.on-guide`, `.trip__guide` et `.voy-table__guide` — les deux dernieres appartiennent
   a des pages non decoupees. Ne pas les reprendre ici : elles viendront avec elles.

   ⚠️ Porte depuis le 2026-10-06 seulement, avec la fiche `/{lang}/accompagnateurs/{slug}`.
   Avant elle, un curseur de lien aurait designe une page en 404.
   ========================================================================== */
[data-guide]{ cursor:pointer; }
/* ==========================================================================
   CARTE DE VOYAGE `.trip` — COMPOSANT PARTAGÉ PAR SIX PAGES.

   ⚠️⚠️ ELLE EST DANS `components.css` ET NON DANS UN CSS DE BLOC, parce que
   `ON_realTripCardHTML` est définie UNE fois dans la maquette (`data-carte.js:756`) et
   appelée depuis **six** pages : accueil (`depforts`), `offres`, `pays`, `animal`,
   `voyage`, `accompagnateur`. La règle du socle — un composant partagé par 3 blocs ou
   plus monte ici — est donc largement remplie, même si **un seul** de ces six existe
   aujourd'hui chez nous. La dimensionner sur son consommateur du jour puis la confronter
   aux cinq autres, ce serait la réécrire.

   Source : `style.css:822-890` (structure) et `1289-1301` (variante claire), bornes
   CALCULÉES — la première tentative s'arrêtait à 891 et coupait en deux le commentaire du
   composant accompagnateur, laissant 19 ouvrants de commentaire pour 18 fermants.
   ⚠️ Cette phrase écrivait les DEUX SÉQUENCES en toutes lettres, et le fermant refermait CE
   commentaire sur place : la suite était lue comme du CSS jusqu'à la première accolade, et
   emportait la règle de base `.trip{…}` (flex, fond, rayon, ombre) sur TOUTES les pages, du
   2026-10-07 (b731765) au 2026-10-07 soir. Relevé en portant la vue liste du catalogue.

   ⚠️ `.trip__tag*` A ÉTÉ DÉPLACÉE DEPUIS `blocs/feature.css` : c'est sa promotion au
   second consommateur, exactement ce que le socle prévoit. Ne pas l'y laisser en double.

   ⚠️ CE QUI N'EST PAS PORTÉ, et pourquoi :
   · `.on-guide` / `.trip__guide` — **plus bas dans ce fichier**, section « LIGNE
     ACCOMPAGNATEUR ». Ne pas les réextraire : la maquette les définit au milieu de la
     carte, mais ce sont les règles du composant accompagnateur, mutualisé.
     ⚠️ Cette ligne a dit « déjà dans ce fichier (bloc `feature`) » jusqu'au 2026-10-07,
     et c'était faux : elles étaient dans `blocs/feature.css`. Donc la ligne guide d'une
     carte `.trip` n'était habillée QUE si le bloc `feature` était sur la même page.
   · ✅ `.trip__foot` / `.trip__cta` — PORTÉS le 2026-10-07 avec la fiche voyage, plus bas
     dans ce fichier (« LE BOUTON VOIR LE VOYAGE »).
   · ✅ `.trip--stage` / `.trip--surmesure` — les teintes par TYPE, PORTÉES le 2026-10-07
     (D145) en fin de ce fichier : 29 voyages sont typés depuis l'ancien site.
   · `.trip__mode` et `.trip__infos` — fabriqués par hachage dans la maquette, aucune
     source en base.
   ========================================================================== */

/* ============================================================
   CARTE VOYAGE — reproduction PIXEL-EXACTE du node Figma (360×413).
   Toutes les valeurs sont celles mesurées dans Figma, non interprétées.
   ============================================================ */
.trip{
  flex:1 1 0; min-width:0;
  background:rgba(20,17,12,.62); border:1px solid rgba(255,255,255,.14);
  border-radius:20px; backdrop-filter:blur(8px);
  display:flex; flex-direction:column;
  box-shadow:0 22px 60px rgba(0,0,0,.5);
  transition:transform .2s var(--ease), border-color .2s var(--ease);
  /* PAS d'overflow:hidden : l'étiquette prix déborde à droite (13px dans Figma) */
}
.trip:hover{ transform:translateY(-5px); border-color:rgba(244,183,33,.6); }
/* IMAGE — ratio 3:2 (format reflex, demande client 03/07 : « photos toujours en 2/3 ») */
.trip__media{
  position:relative; aspect-ratio:3/2; background:#241d12 center/cover no-repeat;
  border-radius:20px 20px 0 0;
}
.trip__media::after{ content:""; position:absolute; inset:0; border-radius:20px 20px 0 0;
  background:linear-gradient(to top, rgba(20,17,12,.85) 0%, rgba(20,17,12,0) 55%); }
/* NIVEAU DE DIFFICULTÉ — pastille 1 à 3 pattes (remplace l'icône famille, retour client 03/07) */
.trip__diff{
  position:absolute; bottom:-24px; left:28px; height:46px; padding:0 15px; border-radius:4px;
  display:flex; align-items:center; gap:4px; color:var(--blanc); z-index:3;
  background:rgba(20,17,12,.85); border:1.5px solid rgba(255,255,255,.6);
}
/* rendu UNIFORME partout (règle Fix 06/07) : angles droits (informatif), pattes remplies JAUNES */
.trip__diff svg{ width:21px; height:21px; fill:var(--jaune); }
.trip__diff svg.is-off{ fill:var(--blanc); opacity:.3; }
/* TAG commercial (remplace le prix, retour client 03/07) — même ruban à cheval image/corps.
   vert=Départ garanti · jaune=Coup de cœur · orange=Déjà des options · rouge=Reste X places. */
.trip__tag{
  position:absolute; right:-13px; bottom:-16px; z-index:3;
  box-sizing:border-box; display:flex; align-items:center;
  padding:10px 16px; background:var(--jaune); color:#241d12;
  border-radius:6px 0 0 6px; white-space:nowrap;
  box-shadow:0 8px 20px -8px rgba(0,0,0,.45);
  font-size:var(--fs-small); font-weight:700; letter-spacing:.02em; line-height:1;
}
/* queue/pli sous le coin bas-droit (ruban replié) — couleur assortie via --tag-fold */
.trip__tag::after{ content:""; position:absolute; right:0; bottom:-11px;
  border-width:11px 13px 0 0; border-style:solid;
  border-color:var(--tag-fold,#9c6f08) transparent transparent transparent; }
.trip__tag--vert{   background:#2e7d46; color:var(--blanc); --tag-fold:#1d5730; }   /* Départ garanti */
.trip__tag--jaune{  background:var(--jaune); color:var(--noir); --tag-fold:#9c6f08; }  /* mise en avant : coup de cœur, nouveauté… */
.trip__tag--rouge{  background:#e0492e; color:var(--blanc); --tag-fold:#9c2c18; }   /* urgence : dernières places */
.trip__tag--gris{   background:#5a5750; color:var(--blanc); --tag-fold:#3b3934; }   /* fermé : complet, reporté */
/* variante EN FLUX (pas de ruban à cheval sur une carte) : même box pleine couleur, position statique */
.trip__tag--inline{ position:static; border-radius:6px; box-shadow:none; }
.trip__tag--inline::after{ display:none; }
/* CORPS — Figma : padding 30/28/32, gap 11px */
.trip__body{ padding:30px 28px 32px; display:flex; flex-direction:column; gap:11px; flex:1; }
/* date — Figma : 12px SemiBold #f4b721 uppercase tracking 1.2px lh 1.6 */
.trip__date{ font-size:var(--fs-label); font-weight:600; letter-spacing:1.2px; text-transform:uppercase; color:var(--jaune); margin:0; line-height:1.6; }
/* nombre de places, sur la ligne date, discret et séparé (couleur atténuée pour ne pas concurrencer la date) */
/* ⚠️ ÉCART VOLONTAIRE À LA MAQUETTE (2026-11-12) : elle donne `--noir-50` à la carte SOMBRE aussi,
   donc du noir à 50 % sur fond noir, illisible (signalé sur la fiche destination). Sur la carte
   sombre, blanc atténué comme `.trip__sub` ; la carte claire garde son gris, ligne suivante. */
.trip__places{ color:rgba(255,255,255,.72); font-weight:600; }
.trip__places::before{ content:" · "; color:rgba(255,255,255,.72); }
.trip--light .trip__places, .trip--light .trip__places::before{ color:var(--noir-50); }
/* TITRE DE MINI-FICHE VOYAGE — SERIF, comme TOUS les titres de carte du site (polaroïds, récits,
   guides, équipe). Instrument Serif n'existe qu'en 400 : un font-weight:600 forcerait une graisse
   synthétique. Posé ici en CSS -> couvre d'un coup les 5 générateurs de vignette. */
.trip__title{ font-family:var(--serif); font-size:clamp(24px,2vw,29px); font-weight:400;
  /* "plus gras" demandé par le client : on DENSIFIE LE TRAIT au lieu de forcer un font-weight,
     qui donnerait le faux gras synthétique baveux de Chrome. currentColor = suit blanc/noir. */
  -webkit-text-stroke:.35px currentColor;
  line-height:1.15; letter-spacing:-.01em; color:var(--blanc); margin:0; }
/* sous-titre — Figma : 13px Regular rgba(255,255,255,.62) lh 1.4 */
.trip__sub{ font-size:var(--fs-small); font-weight:400; color:rgba(255,255,255,.62); margin:0; line-height:1.4; }

/* variante claire de la carte voyage (fond blanc, textes noirs) — réutilise toute la structure .trip__* */
.trip--light{
  background:var(--blanc); border:1px solid var(--creme-2); backdrop-filter:none;
  box-shadow:0 14px 40px rgba(0,0,0,.08);
}
.trip--light:hover{ transform:translateY(-6px); border-color:rgba(244,183,33,.5); box-shadow:0 24px 60px rgba(0,0,0,.14); }
/* (.trip--light .trip__diff : override retiré 06/07 — chip sombre UNIFORME sur toutes les cartes) */
.trip--light .trip__guide{ color:var(--noir-50); }
.trip--light .trip__guide strong{ color:var(--noir); }
.trip--light .trip__guide-pic{ border-color:rgba(14,14,14,.15); }
.trip--light .trip__date{ color:var(--jaune-d); }
.trip--light .trip__title{ color:var(--noir); }
.trip--light .trip__sub{ color:var(--noir-50); }

/* ==========================================================================
   MOBILE — repris de `mobile.css`. ⚠️ Les trois règles d'origine sont MIXTES : elles
   partagent leurs sélecteurs avec `.post`, `.eq-carte`, `.gd-carte`, `.stackv__card` et
   d'autres. Seule la part `.trip` est reprise ici — la règle mixte est le huitième cas
   du projet.
   ========================================================================== */
@media (hover:none){
  /* Pas de survol au doigt : l'élévation resterait collée après le tap. */
  .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); }
  .trip__guide[data-guide]:hover strong{ color:inherit; }
}
/* ⚠️⚠️ 1024 px ET NON 640 : CORRIGÉ LE 2026-10-07, ces trois règles étaient sous un
   `max-width:640px` que j'avais choisi seul — la maquette les met sous `max-width:1024px`
   (`mobile.css:892` → `909-911`), et son commentaire dit pourquoi : sous 1024 px le ruban
   « 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 ».
   ⚠️ LE DÉFAUT NE VIVAIT QUE DE 641 À 1024 px — soit exactement la bande qu'aucune de mes deux
   captures (1400 et 390) ne couvrait. Vérifier à deux largeurs et conclure sur toutes est la
   même faute que compter sans borne : la mesure est juste, sa portée est inventée. */
@media (max-width:1024px){
  /* Le ruban à cheval n'a pas la place de déborder : il se cale au bord et perd son pli. */
  .trip__tag{ right:0; border-radius:6px 6px 0 0; }
  .trip__tag::after{ display:none; }
  .trip--light{ overflow:hidden; }
}

/* ==========================================================================
   LIGNE ACCOMPAGNATEUR — `.on-guide` / `.trip__guide`.

   Source : `style.css:894-913`. DEPLACEE DEPUIS `blocs/feature.css` le 2026-10-07 :
   promotion au SECOND consommateur, comme le socle le prevoit. Le premier etait le bloc
   `feature` (le martin-pecheur), le second est la carte `.trip` du bloc `depforts` — et
   la maquette annonce elle-meme la mutualisation : « COMPOSANT ACCOMPAGNATEUR UNIQUE ».

   ⚠️⚠️ TANT QU'ELLE VIVAIT DANS UN CSS DE BLOC, ELLE N'ETAIT CHARGEE QUE SI CE BLOC ETAIT
   SUR LA PAGE. L'accueil porte les deux, donc rien ne se voyait ; `offres`, `pays`,
   `animal` et les deux fiches auraient rendu la ligne guide sans portrait ni mise en
   forme, sans la moindre erreur. C'est la regle d'or du socle, prise en flagrant delit.

   ⚠️ L'ALIAS `.trip__guide` EST REPRIS ICI, contrairement a ce que disait `feature.css` :
   notre carte `.trip` genere exactement ce balisage. Les modificateurs `--clair`,
   `--sombre` et `--md` suivent, parce qu'ils appartiennent au meme composant — les
   separer obligerait a savoir ou chacun habite.
   ========================================================================== */
.on-guide, .trip__guide{ display:flex; align-items:center; gap:10px; font-size:var(--fs-small); line-height:1.3;
  color:rgba(255,255,255,.72);
  --guide-pic-size: 36px; --guide-pic-radius: 50%; }
.on-guide__pic, .trip__guide-pic{ width:var(--guide-pic-size); height:var(--guide-pic-size);
  border-radius:var(--guide-pic-radius); flex:0 0 auto;
  background:#241d12 center/cover no-repeat; border:1.5px solid rgba(255,255,255,.5); }
.on-guide strong, .trip__guide strong{ font-weight:600; color:var(--blanc); }
.on-guide__txt em, .on-guide em{ display:block; font-style:normal; font-size:var(--fs-label); color:rgba(255,255,255,.55); }
/* modificateurs couleur (remplacent la réécriture dispersée .trip--light / .stackv__caption) */
.on-guide--sombre{ color:rgba(255,255,255,.72); }
.on-guide--sombre strong{ color:var(--blanc); }
.on-guide--clair{ color:var(--noir-50); }
.on-guide--clair strong{ color:var(--noir); }
.on-guide--clair .on-guide__pic{ border-color:rgba(14,14,14,.15); }
/* variante taille "moyenne" (52px) pour les blocs hors vignette : martin-pêcheur, carte voyage */
.on-guide--md{ --guide-pic-size: 52px; }
.on-guide--md .on-guide__pic{ border-width:2px; }

/* ⚠️ TEINTE DE SURVOL — extraite de la regle MIXTE `style.css:2243`, qui declare
   `.on-guide`, `.trip__guide` ET `.voy-table__guide` d'un seul tenant. Les DEUX premieres
   sont reprises (le bloc `feature` et la carte `.trip`) ; `.voy-table__guide` reste dehors,
   le tableau des departs de la fiche voyage n'etant pas decoupe.
   ⚠️⚠️ LA PART `.trip__guide` MANQUAIT jusqu'au 2026-10-07, et l'asymetrie etait VISIBLE
   dans le fichier sans qu'on la lise : le neutraliseur mobile
   `@media (hover:none){ .trip__guide[data-guide]:hover strong{ color:inherit } }` etait la,
   plus bas, a annuler une regle qui n'existait pas. Une regle qui en annule une absente est
   le signe d'une extraction partielle — la chercher au lieu de la supprimer. */
.on-guide[data-guide]:hover strong,
.trip__guide[data-guide]:hover strong{ color:var(--jaune-d); }

/* ==========================================================================
   INFO-BULLE DE NIVEAU — `.diff-tip`.

   Source : `style.css:2957-2965`, reprise integralement (aucune regle dans `mobile.css`,
   verifie). Posee en `position:fixed` par `infoBulleNiveau()` de `common.js`.

   ⚠️ Elle est dans `components.css` et non dans un CSS de bloc parce que son gestionnaire
   est DELEGUE sur `document` : le style et le comportement vivent au meme niveau, comme
   `[data-guide]` plus haut. La bulle est fabriquee dans `<body>`, hors de tout bloc.

   ⚠️ `pointer-events:none` n'est pas decoratif — le commentaire de la maquette le dit :
   sans lui la bulle intercepte le survol qui la maintient ouverte, et clignote.

   ⚠️ `.diff-tip` FIGURAIT DANS `classes_partagees` de `tests/decoupe/config.php` comme
   appartenant a une page non decoupee (mesure du 2026-10-06). Elle est a nous depuis le
   2026-10-07, et la note a ete rectifiee sur place.
   ========================================================================== */
.diff-tip{ position:fixed; z-index:9000; max-width:300px; padding:12px 14px; border-radius:12px;
  background:var(--noir); color:var(--blanc); font-size:var(--fs-small); line-height:1.45;
  box-shadow:0 18px 40px -12px rgba(0,0,0,.55); pointer-events:none;
  opacity:0; transform:translateY(4px); transition:opacity .16s ease, transform .16s ease; }
.diff-tip.is-on{ opacity:1; transform:none; }
.diff-tip b{ display:block; margin-bottom:4px; color:var(--jaune); font-weight:700; }
@media (prefers-reduced-motion: reduce){ .diff-tip{ transition:none; } }

/* ---------------------------------------------------------------------------
   `.on-lien` — LE NOM D'UNE ENTITE CLIQUABLE (pays, animal), `style.css:1634-1641`.
   Composant COMMUN de la maquette : « garde la couleur du texte, soulignement POINTILLE discret
   VISIBLE en permanence (donc perceptible aussi au tactile), passe en soulignement JAUNE plein
   au survol. A poser sur tout nom d'entite cliquable du site. » Premier consommateur : la fiche
   voyage (2026-10-07). ⚠️ La maquette le declare JUMELE a `.vf-rencontre__lien` dans une meme
   regle ; le second reste dans `pages/voyage.css`, ou il vit.
   --------------------------------------------------------------------------- */
.on-lien{ color:inherit; text-decoration:none; cursor:pointer;
  border-bottom:1.5px dotted color-mix(in srgb, currentColor 45%, transparent);
  transition:border-color .2s, border-bottom-style .2s; }
.on-lien:hover{ border-bottom:1.5px solid var(--jaune); }
.on-lien:focus-visible{ outline:2px solid var(--jaune); outline-offset:2px; border-radius:1px; }
/* `mobile.css:782` — au doigt, pas de soulignement jaune qui reste apres l'appui. */
@media (hover:none){
  .on-lien:hover{ border-bottom-color:transparent; }
}

/* ---------------------------------------------------------------------------
   LE BOUTON « VOIR LE VOYAGE » DE LA CARTE `.trip` — `style.css:914-917`.
   Ecarte jusqu'au 2026-10-07 faute de route ; il revient avec la fiche voyage, en meme temps
   que la carte redevient un lien. Le bouton porte `.btn.btn--primary` (hauteur, typo,
   animation de pattes communes au site) — ces deux regles ne font que le placer.
   --------------------------------------------------------------------------- */
.trip__foot{ margin-top:auto; padding-top:22px; display:flex; align-items:center; justify-content:center; gap:15px; }
.trip__cta{ padding:0 18px; white-space:nowrap; }

/* ============================================================
   TEINTES PAR TYPE DE VOYAGE — `style.css:3063-3082` de la maquette (C2, 19/07).
   ============================================================
   « Aucune teinte n'existe sur le site d'origine : c'est un apport de design K2, dérivé des
   couleurs de la charte » — commentaire de la maquette. Stage dérive du jaune, extension et
   sur-mesure du vert ; destination et circuit gardent le rendu standard. Réglage en UN endroit :
   les quatre variables.
   ⚠️ La classe est posée par `partials/trip_card.php` depuis le type STOCKÉ (D145), jamais
   deviné comme le faisait la maquette (hachage pour 101 voyages sur 110).
   ⚠️ `.vf-sejour.is-stage` / `.is-surmesure` (la même teinte sur la fiche voyage) ne sont pas
   ici : ce sont des règles de PAGE, dans `pages/voyage.css`. */
:root{
  --teinte-stage:      #fbe7b4;   /* jaune charte éclairci */
  --teinte-stage-fil:  #e0a510;   /* = --jaune-d */
  --teinte-sm:         #cfdcbd;   /* vert charte éclairci */
  --teinte-sm-fil:     #5c7a3f;   /* = --vert */
}
/* ⚠️⚠️ ÉCART VOULU (2026-10-07) : le FOND teinté ne vaut que pour la carte CLAIRE. La maquette
   l'appliquait aussi à la carte SOMBRE (`.trip--surmesure` seul), dont le titre et les textes sont
   BLANCS — un vert clair sous un titre blanc est illisible. Mesuré sur la fiche destination du
   Botswana, dont le bandeau porte des cartes sombres : la maquette ne l'avait pas vu parce que son
   type, deviné par hachage, n'y mettait aucun voyage sur-mesure. La carte sombre garde le FILET. */
.trip--stage.trip--light{ background:var(--teinte-stage); }
.trip--stage.trip--light .trip__body{ background:transparent; }
.trip--surmesure.trip--light{ background:var(--teinte-sm); }
.trip--surmesure.trip--light .trip__body{ background:transparent; }
/* Le filet supérieur : le signal discret du type, sans alourdir la carte. */
.trip--stage .trip__media{ box-shadow:inset 0 4px 0 var(--teinte-stage-fil); }
.trip--surmesure .trip__media{ box-shadow:inset 0 4px 0 var(--teinte-sm-fil); }
