/* ==========================================================================
   vivant.css : rendre la page d'accueil habitee.

   Constat de depart, mesure et non ressenti : le site possede 53 photos moto
   professionnelles, et ZERO n'apparaissait sur la page d'accueil. Ses 5 images
   etaient toutes des vignettes YouTube. La page ouvrait sur un bloc gris
   portant "Bienvenue sur mon site". Le probleme n'etait pas le manque
   d'animation (19 keyframes, 84 transitions existent deja), c'etait l'absence
   de PRESENCE.

   Cette feuille ne change ni la palette ni l'identite : carbone et lime
   Kawasaki restent. Elle rend ce que la passe de sobriete precedente avait
   retire, ou j'avais pose 48 "box-shadow: none" au nom de la retenue.

   Contraintes respectees, elles ne sont pas negociables :
   - CSP style-src 'self' : aucun style inline, tout passe par des classes.
   - Contraste WCAG : le voile du heros est calcule pour que du texte blanc
     tienne au-dessus de N'IMPORTE QUELLE photo, y compris claire (les 53 le
     sont : luminosite mesuree entre 125 et 150 sur 255).
   - prefers-reduced-motion : tout le mouvement se coupe.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. LE HEROS
   -------------------------------------------------------------------------- */

/* Changer la photo d'accueil se fait ICI, sur cette seule ligne. */
:root {
  --heros-image: url('/images/hero/accueil.6e2bd79fee81.webp');
  --heros-image-mobile: url('/images/hero/accueil-mobile.d99db24a76cc.webp');
  /* De combien un panneau glisse pendant qu'on s'attarde dessus. Declaree ici
     parce que DEUX endroits en dependent : la derive elle-meme, pilotee par
     vivant.js qui lit cette valeur, et la hauteur des panneaux, majoree
     d'autant pour qu'en remontant ils ne decouvrent pas de bande au bas de
     l'ecran. Un seul nombre a changer pour doser l'effet. */
  --groupe-derive-max: 26px;
}

/* Le heros occupe TOUT l'ecran et RESTE en place pendant le defilement. La
   feuille de contenu glisse par-dessus lui, et il s'efface progressivement.

   Pourquoi position: fixed et non sticky. Avec sticky, epingler le heros
   suppose un conteneur PLUS HAUT que lui : la difference de hauteur devient un
   vide qui apparait des qu'il se decroche. Avec fixed, le heros sort du flux,
   la feuille demarre a 100svh et remonte par-dessus : aucun vide possible, et
   le comportement ne depend d'aucune hauteur de conteneur.

   svh et non vh : sur mobile, vh vaut la hauteur AVEC les barres du navigateur
   retractees. Un heros en 100vh y depasse donc l'ecran de la hauteur de la
   barre d'adresse tant qu'elle est visible. svh prend la hauteur reellement
   disponible.

   Le heros reste sous la feuille (z-index 0 contre 1) : une fois recouvert, il
   ne peut plus capter ni clic ni survol, sans qu'il faille le neutraliser. */
.hero,
.hero-photo {
  position: fixed;
  inset: 0 0 auto 0;
  /* Plein cadre, sans exception. Ce sont des <section>, et base.css borne
     TOUTE section a --largeur-site avec des marges automatiques : sans ces
     trois remises a zero, le heros restait a 1870px de large sur un ecran de
     1920 et flottait a 10px du haut. */
  width: 100%;
  max-width: none;
  margin: 0;
  height: 100svh;
  min-height: 0;               /* annule le clamp des anciens bandeaux */
  z-index: 0;
  isolation: isolate;          /* le voile ne deborde pas sur le reste */
  overflow: hidden;
  display: flex;
  align-items: center;
  /* Le retrait HAUT vaut la hauteur de la barre de navigation, et ce n'est pas
     cosmetique. Le heros mesure 100svh et centre son contenu sur cette hauteur
     entiere, mais la barre est OPAQUE et en recouvre les 80 premiers pixels.
     Sur une fenetre haute la marge absorbe l'ecart ; sur une fenetre courte
     (telephone en paysage, ou bureau a 200 % de zoom) le titre passe sous la
     barre, et overflow: hidden rend ce debordement irrecuperable -- on ne peut
     meme pas le retrouver en defilant. Le retrait fait centrer le contenu dans
     la zone REELLEMENT visible. */
  padding: var(--nav-height, 80px) clamp(20px, 5vw, 110px) 0;
  border: none;
  border-radius: 0;            /* plein cadre : plus de coins arrondis */
  background: var(--carbon);   /* repli si l'image ne charge pas */
  /* Pilote par scripts/vivant.js au fil du defilement. La valeur par defaut
     compte : sans JavaScript, le heros reste simplement visible. */
  opacity: var(--heros-fondu, 1);
  /* will-change: opacity et non transform. C'est l'opacite qui change ici, et
     l'annoncer promeut le heros sur sa PROPRE couche de composition : le fondu
     devient alors une operation du compositeur, sans repeindre quoi que ce
     soit. Sans cette ligne, chaque image redessine une surface plein ecran
     contenant une photo -- c'est le defilement lent qui a ete signale. */
  will-change: opacity;
}

/* La feuille : un aplat opaque qui monte par-dessus le heros. C'est elle qui
   le fait disparaitre ; le fondu ne fait qu'accompagner le mouvement.
   Sans enveloppe UNIQUE, les intervalles entre sections laisseraient voir le
   heros au travers, ce qui donnerait un clignotement a chaque separation. */
.feuille-contenu {
  position: relative;
  z-index: 1;
  /* 150svh, et non 100 : c'est ce demi-ecran supplementaire qui cree le
     "puis". A 100svh, la feuille entrait dans l'ecran des le premier pixel de
     defilement et grignotait la photo en continu ; il n'y avait pas de temps
     ou le heros tenait l'ecran seul, donc pas de bascule a percevoir. Avec
     150svh, le premier demi-ecran ne montre que la photo qui derive, puis la
     feuille arrive et prend le relais.
     Le defilement reste rigoureusement 1:1 avec la page : on ajoute du vide
     au-dessus du contenu, on ne detourne pas le defilement, ce qui se sentirait
     immediatement comme une perte de controle.
     La hauteur de la barre de navigation est DEDUITE : le corps de page porte
     deja padding-top: var(--nav-height), donc une marge pleine poussait la
     feuille 80px sous le bas de l'ecran. */
  margin-top: calc(150svh - var(--nav-height, 80px));
  background: var(--bg);
  /* Lisiere marquee : sans elle, la feuille et le heros se confondent en
     theme sombre et la superposition ne se lit plus. */
  box-shadow: 0 -30px 60px rgba(0, 0, 0, 0.55);
}

/* Les groupes de contenu : chacun vient recouvrir le precedent.
   -------------------------------------------------------------------------
   Meme geste que le heros et la feuille, applique un cran plus bas : un bloc
   se fige, le suivant remonte par-dessus et le remplace.

   `top` est calcule par vivant.js et non ecrit ici, parce qu'il depend de la
   HAUTEUR du bloc :
     - un bloc plus court que l'ecran se fige sous la barre ;
     - un bloc plus haut se fige a une valeur NEGATIVE, de sorte qu'on puisse
       le lire jusqu'en bas avant qu'il ne se fige. Avec top: 0 fixe, un bloc
       plus haut que l'ecran se collerait des son apparition et sa fin
       deviendrait inatteignable.

   Le fond passe par :where(), donc a specificite ZERO : n'importe quelle
   regle existante d'une section garde la main. Il ne sert qu'a rendre opaques
   celles qui n'avaient pas de fond, sans quoi on verrait le bloc precedent au
   travers et l'empilement ne se lirait pas. */
:where(.a-heros-fixe .feuille-contenu > section) {
  background-color: var(--bg);
}

.a-heros-fixe .feuille-contenu > section {
  position: sticky;
  top: var(--groupe-haut, 80px);
  /* Le bord haut est ce qui rend le recouvrement LISIBLE. Une ombre seule ne
     suffit pas : le fond du theme sombre est #0B0B0B, une ombre noire y est
     litteralement invisible. La lisiere, elle, se voit dans les deux themes
     (#2E2E2E sur #0B0B0B, #E2E2E2 sur blanc), et c'est elle qu'on voit
     remonter en tranchant le bloc precedent.
     L'ombre reste, pour le theme clair ou elle porte reellement. Les freres
     suivants peignent au-dessus des precedents : elle tombe donc dans le bon
     sens sans avoir a toucher aux z-index. */
  border-top: 1px solid var(--border-color);
  box-shadow: 0 -18px 36px rgba(0, 0, 0, 0.30);
}

/* Un groupe occupe l'ecran entier : c'est ce qui fait qu'on passe d'un bloc au
   suivant plutot que de faire defiler une page continue.

   La classe est posee par vivant.js et non ecrite ici, parce qu'elle ne doit
   PAS s'appliquer a tout : la barre de filtres de la galerie ne fait que 67px,
   lui donner un ecran entier serait absurde. Le script mesure la hauteur
   naturelle et n'exclut que ces barres utilitaires.

   `align-content` centre le contenu dans la hauteur restante, et c'est la
   seule propriete qui le fasse aussi bien pour un conteneur bloc (l'accueil)
   que pour une grille (les essais, l'equipement). Passer les blocs en flex
   aurait marche aussi, mais en changeant le modele de mise en page de tous
   leurs enfants : fusion des marges supprimee, enfants devenus des elements
   flex. Ici rien ne change, le contenu est seulement recentre. */
.a-heros-fixe .feuille-contenu > section.groupe-plein {
  /* La hauteur d'ecran, PLUS l'amplitude de la derive. Ce supplement n'est pas
     decoratif : en remontant de 26px, le panneau decouvrirait sinon une bande
     de 26px au bas de l'ecran. Invisible sur un panneau au fond de la page,
     mais pas sur ceux qui ont leur propre fond (l'appel a l'action de
     l'accueil est en #171717 sur un fond #0B0B0B). En etant plus haut
     d'autant, son bas retombe exactement au bas de l'ecran une fois derive. */
  min-height: calc(100svh - var(--nav-height, 80px) + var(--groupe-derive-max, 26px));
  align-content: center;
  /* On s'attarde sur chaque panneau avant de passer au suivant.
     La marge basse n'ajoute pas de vide : le panneau est colle, il reste donc
     affiche pendant toute sa duree, et c'est le panneau SUIVANT qui est
     retarde d'autant. C'est ce qui donne le temps de lire.
     Le defilement n'est jamais confisque, contrairement au calage essaye puis
     retire : la page suit le geste au pixel, il en faut simplement un peu plus
     pour changer de panneau. UN SEUL NOMBRE regle la duree.
     Les marges hautes, elles, disparaissent : elles variaient d'une page a
     l'autre (30px sur A propos, 8px sur l'accueil) et dereglaient le rythme. */
  margin-block: 0 var(--groupe-attente, 55svh);

}

/* L'appel a l'action redevient une SECTION, pas une carte.
   -------------------------------------------------------------------------
   home.css le dessine comme une carte : fond --carbon plus clair que la page,
   cerne sur les quatre cotes, coins arrondis. C'etait coherent quand les
   sections se suivaient au fil d'une page continue, ou une carte se
   distinguait de son voisinage.

   Ce n'est plus le cas depuis que chaque bloc occupe l'ecran entier : la carte
   ne fait que 289px de haut sur un panneau de 1000, elle flotte donc au milieu
   d'un grand vide plus clair, et la serie se casse a cet endroit precis. Les
   quatre autres sections de l'accueil sont des bandes plates, mesure faite :
   meme fond que la page, meme largeur, sans arrondi.

   L'habillage n'est retire QUE lorsque le bloc est un panneau. Partout
   ailleurs, la carte garde tout son sens et son dessin d'origine.

   La lisiere HAUTE est reposee explicitement : `border: none` effacerait aussi
   celle du panneau, qui est ce qui rend le recouvrement lisible. */
.a-heros-fixe .feuille-contenu > section.groupe-plein.cta-section {
  background-color: var(--bg);
  background-image: none;      /* le theme clair y pose un degrade */
  border: none;
  border-top: 1px solid var(--border-color);
  border-radius: 0;
  /* Le retrait lateral n'est plus fixe ici : la regle de forme commune, plus
     bas, aligne desormais TOUS les panneaux sur la meme valeur. Le garder
     laissait ce bloc a 20px quand les autres passaient a 56, soit exactement
     le decalage qu'il devait corriger, mais dans l'autre sens. */
}

/* Meme chose pour l'infolettre, ou la carte est INTERIEURE.
   Aplatir la seule section n'avait donc rien change : mesure sur grand ecran,
   le bloc communaute etait devenu une bande plate pendant que l'infolettre
   gardait son encadre (fond #141414, cerne sur les quatre cotes, arrondi).
   Les deux blocs de bas de page ne se ressemblaient plus entre eux, ce qui
   se voit d'autant plus qu'ils se suivent.
   Le retrait interieur passe a zero : le contenu s'aligne alors sur celui des
   autres sections au lieu d'etre rentre de 28px de plus. */
/* La carte de l'appel a l'action de la page A propos avait echappe a cette
   passe, et presentait exactement le meme defaut : sa SECTION etait bien
   aplatie par la regle ci-dessus, mais la carte a l'interieur gardait son fond
   #141414, son cerne sur les quatre cotes, son arrondi et ses 40px/32px de
   retrait. Un bandeau plat contenant un encadre, donc, alors que les autres
   panneaux de la page presentent leur contenu a nu.
   Le retrait remis a zero n'est pas cosmetique : releve avant correction, les
   titres des quatre panneaux de la page demarraient a 76, 76, 109 et 116px.
   Les 32px de la carte etaient la cause des 109. */
.a-heros-fixe .feuille-contenu > section.groupe-plein.newsletter-section .newsletter-card,
.a-heros-fixe .feuille-contenu > section.groupe-plein.cta-section .cta-card {
  background: transparent;
  border: none;
  border-radius: 0;
  padding: 0;
}

/* UNE SEULE FORME POUR TOUS LES PANNEAUX.
   -------------------------------------------------------------------------
   Chaque page avait grandi de son cote : releve avant ecriture, les retraits
   lateraux des sections valaient 16px sur l'accueil, 20px sur la galerie et
   l'infolettre, 24px sur l'appel a l'action, 32px sur la FAQ. Tant que les
   sections defilaient a la suite, l'ecart passait inapercu. Il ne le peut plus
   depuis que chaque bloc occupe l'ecran : on compare desormais des PAGES
   PLEINES les unes aux autres, et un titre qui se decale de 16px d'un ecran au
   suivant se voit immediatement.

   Ces regles ne s'appliquent qu'aux panneaux, avec `:where()` pour la
   typographie afin qu'une page gardant un besoin propre puisse toujours
   reprendre la main sans se battre contre une specificite. */

/* 1. Le meme retrait lateral partout, qui respire sur les grands ecrans.
      Il grandit avec la fenetre plutot que de rester fixe : un texte colle a
      20px du bord se lit mal sur 1920px de large. */
.a-heros-fixe .feuille-contenu > section.groupe-plein {
  padding-inline: clamp(20px, 3vw, 56px);
}

/* 2. Le meme rythme vertical. Il ne sert que si le contenu deborde du
      panneau ; sinon `align-content: center` s'en charge. */
.a-heros-fixe .feuille-contenu > section.groupe-plein {
  padding-block: clamp(28px, 4vh, 64px);
}

/* 3. La meme echelle de titre. Trois classes coexistaient pour un meme role,
      section-title, cta-title et newsletter-title, chacune avec sa taille, et
      trois pages titraient leurs sections avec un h2 NU, reste a 39px quand
      les autres montaient a 44.
      Le h2 nu est pris par `> h2`, donc en ENFANT DIRECT du panneau, et c'est
      ce qui rend la regle sure : releve sur les trois pages concernees, un
      titre de section est toujours enfant direct (section.roadmap > h2), un
      titre de CARTE ne l'est jamais (article.a2-card > h2,
      header.essai-head > h2, div.card-header > h2). Les cartes gardent donc
      leur echelle propre, ce qui est bien le but : ce sont des objets dans une
      page, pas des annonces de page. */
:where(.a-heros-fixe .feuille-contenu > section.groupe-plein) > h2,
:where(.a-heros-fixe .feuille-contenu > section.groupe-plein)
  :is(.section-title, .cta-title, .newsletter-title) {
  font-size: clamp(1.75rem, 2.6vw, 2.75rem);
  line-height: 1.12;
  margin-block: 0 0.5em;
}

/* 4. Le meme espace entre l'en-tete d'une section et ce qu'elle presente. */
:where(.a-heros-fixe .feuille-contenu > section.groupe-plein) .section-header {
  margin-block: 0 clamp(20px, 3vh, 44px);
}

/* 5. La meme largeur de lecture pour les textes d'introduction. Sans bornes,
      une description court sur 1800px et l'oeil perd la ligne. */
:where(.a-heros-fixe .feuille-contenu > section.groupe-plein)
  :is(.section-description, .cta-description, .newsletter-description) {
  max-width: var(--container-text, 52ch);
}

/* 5 bis. LA MEME LARGEUR.
      -----------------------------------------------------------------------
      La regle 1 avait unifie les RETRAITS, en notant qu'un titre decale de
      16px d'un ecran au suivant se voit immediatement. Elle avait laisse
      passer bien pire : les LARGEURS. Releve sur la page A propos en
      1920x1080, ses quatre panneaux mesuraient 1870, 1000, 1870 puis 800px.
      La page se retrecissait et s'elargissait a chaque ecran, 1070px d'ecart
      entre le plus large et le plus etroit.

      Second effet, mesure lui aussi : borne a 1000px, la grille des quatre
      cartes de contenu n'en tenait que trois de front et laissait la
      quatrieme orpheline sur une deuxieme ligne, ce qui portait le panneau a
      1153px, au-dela de l'ecran de 1026. A la largeur commune elles tiennent
      sur une seule ligne et le panneau rentre dans son ecran.

      La regle vit ICI et non dans about.css, pour deux raisons. Elle ne doit
      s'appliquer qu'aux PANNEAUX : les memes sections servent aux mentions
      legales et a la confidentialite, qui ne sont pas des pages a panneaux et
      ou 1000px reste la bonne mesure pour du texte suivi. Et posee dans la
      forme commune, elle vaut d'avance pour toute page future qui arriverait
      avec sa propre largeur.
      Releve avant ecriture : ces deux sections etaient les SEULES du site a
      figer une largeur en pixels. La regle est donc sans effet ailleurs. */
.a-heros-fixe .feuille-contenu > section.groupe-plein {
  max-width: var(--largeur-site, 1200px);
}

/* 6. L'en-tete traverse la grille.
      -----------------------------------------------------------------------
      Quatre panneaux sur cinq sont des GRILLES (.a2-grid, .equipment-grid,
      .gallery-grid, .contact-methods). Un en-tete pose en enfant direct y
      devient une CELLULE : le titre se retrouve dans la premiere colonne, a
      cote d'une carte, au lieu d'annoncer l'ecran entier.
      C'est exactement le defaut deja corrige plus bas pour les filtres de la
      galerie ; la regle est generalisee ici pour ne pas la reecrire a chaque
      page. Sur une section qui n'est pas une grille, `grid-column` est sans
      objet et donc sans effet.

      SANS `.groupe-plein`, et la nuance a coute une mesure : vivant.js ne
      classe des panneaux qu'a partir de DEUX blocs (un bloc seul n'a rien a
      recouvrir). La galerie n'ayant qu'une section, aucun panneau n'y est
      declare, et un en-tete conditionne au panneau y restait coince dans la
      premiere colonne, a cote d'une vignette. Le piege de la cellule ne depend
      pas du recouvrement : la regle ne doit pas en dependre non plus. */
.a-heros-fixe .feuille-contenu > section > .section-header {
  grid-column: 1 / -1;
}

/* 7. Le surtitre : de quelle NATURE est cet ecran.
      -----------------------------------------------------------------------
      Pourquoi un troisieme niveau plutot qu'un titre plus long. Les panneaux
      se remplacent les uns les autres : on arrive sur un ecran sans voir ce
      qui precede, et le titre seul repond a "quoi" sans repondre a "ou".
      "Ce qui filme" est clair une fois qu'on sait qu'on est dans le materiel ;
      "Pendant le tournage" le pose en une ligne.

      En BAS DE CASSE, et c'est le point. La regle `h1, h2 { text-transform:
      uppercase }` de base.css met deja tous les titres en capitales : un
      surtitre egalement capitalise empilerait deux cris et le bloc se lirait
      comme une seule masse. La minuscule espacee donne deux voix au groupe,
      une qui situe et une qui annonce.

      Pas de numerotation. Elle n'encoderait rien ici : quatre motos ne sont
      pas quatre etapes, trois categories de materiel non plus. Le seul
      enchainement reel du site est le guide A2, et ses cartes portent deja
      leur rang dans leur propre titre. */
:where(.a-heros-fixe .feuille-contenu > section.groupe-plein) .section-genre {
  margin-block: 0 0.7em;
  font-size: var(--text-sm, 14px);
  font-weight: 600;
  letter-spacing: 0.08em;
  /* --accent-text et non --accent : le lime pur tient 10:1 sur le carbone
     mais tombe a 2.4:1 sur le blanc du theme clair. La variable porte deja
     la version assombrie (#3C7000, 5.98:1). */
  color: var(--accent-text);
}

/* 8. LES PANNEAUX DE CLOTURE PARLENT PLUS FORT.
      -----------------------------------------------------------------------
      Ce sont les cinq derniers ecrans du site : les deux appels a l'action,
      l'infolettre, le conseil final du guide et l'invitation a devenir
      partenaire. Ils etaient les plus vides, et de loin. Mesure en 953x956 sur
      l'accueil : 188px de contenu dans un panneau de 902 (21 %) pour l'appel a
      l'action, 248px (27 %) pour l'infolettre, quand les panneaux de contenu
      de la meme page tenaient 83 a 93 %.

      Le diagnostic compte plus que le chiffre : ces panneaux n'ont pas trop
      PEU de contenu, ils sont regles pour un contenu qu'ils n'ont pas. Une
      invitation, c'est une phrase et un bouton ; la rembourrer serait mentir
      sur sa nature. Le remede est donc l'ECHELLE et non le remplissage, ce que
      ces pages appellent depuis le debut : traiter le vide par la typographie.

      Le titre passe au-dessus de l'echelle de section (44px au maximum, regle
      3) sans atteindre celle du titre de page (61px) : une conclusion doit
      porter plus loin qu'un intertitre, jamais couvrir le titre de la page.
      La phrase qui l'accompagne grandit dans la meme proportion, sinon le
      titre grossi la ferait paraitre une note de bas de page.

      Selecteurs nommes un a un plutot qu'un `:not(:has(.section-genre))`
      astucieux : la regle qui distingue les panneaux de cloture est
      editoriale, pas structurelle, et une liste se lit et se corrige. */
.a-heros-fixe .feuille-contenu > section.groupe-plein:is(
  .cta-section, .newsletter-section, .note-box, .partners-cta
) :is(h2, .section-title, .cta-title, .newsletter-title) {
  font-size: clamp(2rem, 4.2vw, 3.75rem);
  line-height: 1.05;
  text-wrap: balance;
}

.a-heros-fixe .feuille-contenu > section.groupe-plein:is(
  .cta-section, .newsletter-section, .note-box, .partners-cta
) :is(p, .cta-description, .newsletter-description) {
  font-size: clamp(1.05rem, 1.35vw, 1.3rem);
  line-height: 1.6;
}

/* L'action respire a la mesure du texte qui la precede. */
.a-heros-fixe .feuille-contenu > section.groupe-plein:is(
  .cta-section, .newsletter-section, .note-box, .partners-cta
) :is(.cta-buttons, .cta-link, .newsletter-form, form) {
  margin-top: clamp(20px, 3vh, 40px);
}

/* Les filtres de la galerie, une fois DANS la grille.
   -------------------------------------------------------------------------
   Ils y deviennent un element de grille : sans cette regle ils occuperaient
   une seule colonne et se retrouveraient a cote d'une vignette. Ils occupent
   donc toute la largeur, sur leur propre ligne.
   Les retraits lateraux sont annules : la grille en pose deja, les cumuler
   rentrerait les filtres de 20px de plus que les vignettes qu'ils commandent,
   ce qui se verrait immediatement puisqu'ils sont maintenant voisins. */
.gallery-grid > .filter-section {
  grid-column: 1 / -1;
  max-width: none;
  padding-inline: 0;
  /* Les marges laterales automatiques doivent sauter, et pas seulement pour
     la forme : sur un ELEMENT DE GRILLE, `margin: 0 auto` ne centre pas une
     boite pleine largeur, il la reduit a son contenu puis la centre. Les
     filtres se retrouvaient a 747px du bord quand les vignettes commencaient
     a 40px. */
  margin-inline: 0;
}

/* La derive du panneau pendant qu'on s'attarde dessus.
   -------------------------------------------------------------------------
   Sans elle, un panneau qui reste affiche une demi-page de defilement parait
   fige, et l'attente se lit comme un blocage plutot que comme une pause. Le
   contenu glisse donc lentement vers le haut, de quelques dizaines de pixels
   seulement : assez pour que l'oeil sente que la page repond, pas assez pour
   deranger la lecture.

   Reservee aux ecrans larges. Sous 700px, theme.css fait passer l'infobulle
   des badges en position: fixed pour qu'elle echappe a sa carte ; une
   transformation sur le panneau en deviendrait le referentiel et l'y
   renfermerait. C'est un defaut deja rencontre et corrige sur ce site, inutile
   de le recreer un cran plus haut.

   `translate` et NON `transform`, et ce n'est pas un detail de style :
   scroll-reveal.js ecrit `transform` en STYLE EN LIGNE sur ces memes sections
   pour son animation d'entree, et un style en ligne bat toujours une regle de
   feuille. Une derive posee en `transform` etait donc purement et simplement
   ignoree, ce que la mesure a montre (derive calculee a -26px, transformation
   reelle inchangee). `translate` est une propriete independante : les deux se
   composent au lieu de s'ecraser. */
@media (min-width: 701px) {
  .a-heros-fixe .feuille-contenu > section.groupe-plein {
    translate: 0 var(--groupe-derive, 0px);
  }
}

/* PAS DE CALAGE AU DEFILEMENT (scroll-snap), et c'est un essai ecarte.
   -------------------------------------------------------------------------
   Il a ete implemente puis retire le 2026-08-05 : a l'usage, il donnait la
   sensation que le site se bloquait. La geometrie etait pourtant juste, le
   calage tombait au pixel sur chaque panneau. Ce qui echouait, c'est le
   RESSENTI, sur un site qui adoucit deja la molette lui-meme
   (scripts/defilement.js) : deux mecanismes rappellent alors la page, l'un
   apres l'autre, et le geste n'appartient plus a celui qui defile.

   Ne pas le remettre sans avoir d'abord teste a la main, avec une vraie
   molette. Aucune mesure ne repond a cette question : des evenements `wheel`
   synthetiques n'atteignent meme pas le script de defilement, et une
   verification de positions declare conforme un comportement desagreable. */

/* La photo, sur une couche propre : elle peut ainsi bouger en parallaxe
   sans entrainer le texte avec elle. */
.hero::before {
  content: '';
  position: absolute;
  inset: -8% 0 -8% 0;          /* marge haute et basse pour la parallaxe */
  z-index: -2;
  background-image: var(--heros-image);
  background-size: cover;
  background-position: center 40%;
  /* Deux mouvements sur la meme couche : la derive lente au defilement, puis
     un leger rapprochement pendant que le contenu prend le relais. Le zoom ne
     peut qu'AJOUTER du recouvrement, il ne risque donc jamais de decouvrir un
     bord, contrairement a une reduction. */
  transform: translate3d(0, var(--heros-decalage, 0px), 0) scale(var(--heros-echelle, 1));
}

/* Le voile. Deux dégradés superposés :
   - horizontal, tres dense a gauche ou vit le texte, transparent a droite
     pour laisser respirer la photo ;
   - vertical, pour ancrer le bas du bloc.
   A 0.80 d'opacite sur une photo de luminosite 150/255, le blanc ressort a
   plus de 15:1. Meme sur une zone tres claire (230/255) il reste au-dessus de
   11:1. C'est ce qui rend la photo interchangeable sans revérifier. */
.hero::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(100deg,
      rgba(8, 8, 8, 0.94) 0%,
      rgba(8, 8, 8, 0.80) 42%,
      rgba(8, 8, 8, 0.42) 72%,
      rgba(8, 8, 8, 0.28) 100%),
    linear-gradient(to top,
      rgba(8, 8, 8, 0.55) 0%,
      rgba(8, 8, 8, 0) 45%);
}

.hero .hero-content,
.hero-photo .hero-content {
  position: relative;
  z-index: 1;
  max-width: 62ch;
  padding: 0;
  /* Remises a zero INDISPENSABLES : plusieurs feuilles de page posent un fond
     opaque, une bordure et "margin: 0 auto" sur .hero-content. Le fond
     recouvrirait la photo ; les marges automatiques, dans un heros en
     display:flex, absorbent tout l'espace libre et poussent le titre au milieu
     au lieu du bord gauche, la ou le voile est justement dense. */
  background: none;
  border: none;
  box-shadow: none;
  margin-inline: 0;
}

/* Le filet lime sous le titre : l'accent revient par la ligne, pas par un
   remplissage du texte. C'est la regle etablie a la refonte, on la garde. */
.hero .hero-title::after {
  content: '';
  display: block;
  width: 84px;
  height: 4px;
  margin-top: 18px;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--accent) 0%, rgba(110, 205, 0, 0) 100%);
  transform-origin: left center;
  animation: filet-course 900ms cubic-bezier(.16, 1, .3, 1) both;
}

@keyframes filet-course {
  from { transform: scaleX(0); opacity: 0; }
  to   { transform: scaleX(1); opacity: 1; }
}

.hero .hero-subtitle {
  color: #E6E6E6;
  text-shadow: 0 1px 12px rgba(0, 0, 0, 0.6);
}

/* --------------------------------------------------------------------------
   2. LES CHIFFRES, RENDUS VIVANTS
   Ils existaient deja mais s'affichaient a 0 puis sautaient a leur valeur.
   Ils comptent desormais, et se detachent du fond photo.
   -------------------------------------------------------------------------- */

.hero .hero-stats {
  gap: 16px;
  margin-top: 32px;
}

.hero .stat-item {
  /* 0.82 et non 0.72 : le flou d'arriere-plan qui detachait ces cartes a ete
     retire (voir ci-dessous), un fond un peu plus dense reprend ce role sans
     rien couter. */
  background: rgba(20, 20, 20, 0.82);
  border: 1px solid rgba(255, 255, 255, 0.10);
  border-radius: var(--radius-md);
  /* Flou d'arriere-plan RETIRE : il vivait dans un element dont l'opacite
     s'anime, ce qui impose un rendu hors ecran plein ecran a chaque image.
     Sur un voile deja opaque a 80-94 %, il ne se voyait pas. */
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.45);
  transition: transform .35s cubic-bezier(.16, 1, .3, 1),
              border-color .35s ease,
              box-shadow .35s ease;
}

.hero .stat-item:hover {
  transform: translateY(-4px);
  border-color: rgba(110, 205, 0, 0.55);
  box-shadow: 0 14px 38px rgba(0, 0, 0, 0.55),
              0 0 0 1px rgba(110, 205, 0, 0.25);
}

.hero .stat-number {
  color: #FFFFFF;
  font-variant-numeric: tabular-nums;   /* le compteur ne fait pas sautiller la mise en page */
}

/* --------------------------------------------------------------------------
   3. LES HEROS DES AUTRES PAGES

   Onze pages sur treize n'affichaient AUCUNE photo. Elles ouvraient toutes sur
   le meme bloc carbone plat, avec un emoji en guise d'illustration. Chacune
   recoit ici un bandeau photo choisi pour son sujet.

   Le principe est celui de l'accueil, en plus compact : couche image en
   arriere-plan (-2), voile (-1), contenu au-dessus. Deux differences :
   - le bandeau est moins haut, c'est un en-tete de page et non une ouverture ;
   - le voile est plus uniforme. Sur l'accueil le texte occupe une colonne
     etroite a gauche, on peut donc degager la droite. Ici les titres sont
     courts mais les photos ont leur sujet vers 40 % de la largeur : un degrade
     trop contraste l'aurait coupe en deux.

   ATTENTION : tout bloc qui recoit .hero-photo devient carbone dans les DEUX
   themes. Il doit donc figurer dans le bloc de contexte carbone de theme.css,
   et toute regle [data-theme="light"] qui lui donnait un fond clair doit etre
   neutralisee, sinon son titre passe en sombre sur sombre. Fait pour les sept.
   -------------------------------------------------------------------------- */

/* L'ancienne definition du bandeau (bloc compact dans le flux, hauteur en
   clamp, coins arrondis) a ete SUPPRIMEE ici : les bandeaux sont desormais
   plein ecran et fixes, definis en haut de cette feuille avec .hero. Elle
   etait chargee APRES la nouvelle et lui reimposait position: relative, ce
   qui remettait les sept bandeaux dans le flux sans que rien ne le signale :
   l'accueil fonctionnait, les sept autres non. */

.hero-photo::before {
  content: '';
  position: absolute;
  inset: -10% 0 -10% 0;        /* marge pour la derive au defilement */
  z-index: -2;
  background-image: var(--bandeau-image);
  background-size: cover;
  background-position: center 45%;
  transform: translate3d(0, var(--bandeau-decalage, 0px), 0) scale(var(--bandeau-echelle, 1));
}

/* Voile : dense a gauche ou vit le titre, allege a droite ou la photo respire,
   plus un fond vertical qui ancre le bas. Mesure sur la plus claire des sept
   (le lever de soleil, dont le ciel monte a 250/255) : le blanc y ressort
   au-dessus de 9:1 meme dans la zone la moins couverte. */
.hero-photo::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(95deg,
      rgba(8, 8, 8, 0.93) 0%,
      rgba(8, 8, 8, 0.84) 38%,
      rgba(8, 8, 8, 0.66) 70%,
      rgba(8, 8, 8, 0.54) 100%),
    linear-gradient(to top,
      rgba(8, 8, 8, 0.45) 0%,
      rgba(8, 8, 8, 0) 55%);
}

.hero-photo .hero-content {
  position: relative;
  z-index: 1;
  max-width: 62ch;
  padding: 0;
  /* INDISPENSABLE. Trois pages (essais-moto, guide-a2, partners) donnent a
     .hero-content son PROPRE fond opaque et sa bordure : sur ces pages, le
     bloc carbone n'etait pas la section mais son contenu. Sans cette remise a
     zero, ce bloc se pose en aplat plein PAR-DESSUS la photo, qui ne
     transparait plus qu'en liseré autour. Le fond et le voile sont desormais
     portes par .hero-photo lui-meme ; le contenu doit rester transparent. */
  background: none;
  border: none;
  box-shadow: none;
  /* margin remis a zero AUSSI : about.css, contact.css et stuff.css posent
     "margin: 0 auto" sur .hero-content. Dans un bandeau en display:flex, les
     marges auto absorbent tout l'espace libre : mesure a 1600px, le bloc
     titre demarrait a 32,7 % de la largeur au lieu du bord gauche, alors que
     le voile est justement construit dense a gauche pour l'accueillir. */
  margin-inline: 0;
}

/* Le meme filet lime que l'accueil, pour que les pages se repondent. */
.hero-photo .hero-title::after {
  content: '';
  display: block;
  width: 72px;
  height: 4px;
  margin-top: 16px;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--accent) 0%, rgba(110, 205, 0, 0) 100%);
  transform-origin: left center;
  animation: filet-course 900ms cubic-bezier(.16, 1, .3, 1) both;
}

.hero-photo .hero-subtitle {
  color: #E6E6E6;
  text-shadow: 0 1px 12px rgba(0, 0, 0, 0.6);
}

/* Changer la photo d'une page se fait ICI, sur une seule ligne. */
.hero-photo--about       { --bandeau-image: url('/images/hero/about.f6495c3b2c3f.webp'); --bandeau-image-mobile: url('/images/hero/about-mobile.485d5643de53.webp'); }
.hero-photo--essais      { --bandeau-image: url('/images/hero/essais.25c57cf3a1f5.webp'); --bandeau-image-mobile: url('/images/hero/essais-mobile.47b7671e8a0c.webp'); }
.hero-photo--guide       { --bandeau-image: url('/images/hero/guide.b6cefae9e265.webp'); --bandeau-image-mobile: url('/images/hero/guide-mobile.06f25525a19a.webp'); }
.hero-photo--equipement  { --bandeau-image: url('/images/hero/equipement.feb1640f6c09.webp'); --bandeau-image-mobile: url('/images/hero/equipement-mobile.7eda39ff7eb6.webp'); }
.hero-photo--galerie     { --bandeau-image: url('/images/hero/galerie.5d2ac730745e.webp'); --bandeau-image-mobile: url('/images/hero/galerie-mobile.b55f9fd53859.webp'); }
.hero-photo--partenaires { --bandeau-image: url('/images/hero/partenaires.e061f2453c52.webp'); --bandeau-image-mobile: url('/images/hero/partenaires-mobile.82d798837db4.webp'); }
.hero-photo--contact     { --bandeau-image: url('/images/hero/contact.fa6fc2530eb5.webp'); --bandeau-image-mobile: url('/images/hero/contact-mobile.4f632d9197bc.webp'); }
.hero-photo--faq         { --bandeau-image: url('/images/hero/faq.856fe3042af3.webp'); --bandeau-image-mobile: url('/images/hero/faq-mobile.afff24c7d87c.webp'); }

/* ANCRAGE VERTICAL. Le heros est plein ecran : sur un ecran plus large
   que 1.5, l'image est mise a l'echelle sur la LARGEUR et rognee en
   hauteur. Ou porte ce rognage depend de ce point d'ancrage.
   - contact s'ancre en HAUT. Il etait a 62 %, pose sur l'idee que "son sujet
     est bas dans le cadre". C'etait faux, et la mesure l'a montre : la moto
     occupe 3 % a 62 % de la hauteur de l'image, donc les deux tiers
     SUPERIEURS. A 62 %, la fenetre visible allait de 12,4 % a 92,4 % : le
     haut de la moto etait coupe et pres d'un tiers du cadre ne montrait que
     du gravier. En haut, la fenetre part de 0 % et la moto tient entiere,
     quel que soit le rapport de l'ecran.
   - guide revient au reglage par defaut (45 %). Son nouveau cadrage
     remonte pour retrouver le ciel de coucher de soleil, qu'un ancrage
     a 62 % aurait aussitot recoupe : le recadrage et l'ancrage doivent
     etre choisis ENSEMBLE, changer l'un sans l'autre annule le gain. */
.hero-photo--contact::before { background-position: center top; }

/* ...mais uniquement sur le cadrage horizontal : la variante verticale de
   contact est cadree sur son sujet, un ancrage bas la decalerait. */
@media (max-width: 700px) {
  .hero-photo--contact::before { background-position: center center; }
}

/* --------------------------------------------------------------------------
   4. LA BANDE PHOTO
   53 photos dormaient dans la galerie. En voici une trace sur l'accueil, qui
   renvoie vers elle.
   -------------------------------------------------------------------------- */

.bande-photos {
  max-width: var(--largeur-site, 1200px);
  margin: var(--space-7) auto 0;
  padding: 0 20px;
}

.bande-photos-grille {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 420px));
  justify-content: center;
  gap: 12px;
}

.bande-photos-vignette {
  position: relative;
  display: block;
  aspect-ratio: 3 / 2;
  overflow: hidden;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-color);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.30);
  transition: transform .4s cubic-bezier(.16, 1, .3, 1), box-shadow .4s ease;
}

.bande-photos-vignette img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform .7s cubic-bezier(.16, 1, .3, 1), filter .4s ease;
  filter: saturate(0.92);
}

.bande-photos-vignette:hover {
  transform: translateY(-4px);
  box-shadow: 0 16px 40px rgba(0, 0, 0, 0.45);
}

.bande-photos-vignette:hover img {
  transform: scale(1.07);
  filter: saturate(1.05);
}

/* Le lien vers la galerie occupe la derniere case, il n'est pas une vignette
   de plus : il annonce ce qu'il y a derriere. */
.bande-photos-plus {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  aspect-ratio: 3 / 2;
  border-radius: var(--radius-sm);
  border: 1px solid var(--accent-line);
  background: var(--card-bg);
  color: var(--accent-text);
  text-decoration: none;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: var(--text-sm);
  transition: background .3s ease, transform .35s cubic-bezier(.16, 1, .3, 1);
}

.bande-photos-plus:hover {
  background: var(--card-bg-hover);
  transform: translateY(-4px);
}

.bande-photos-plus span:first-child {
  font-size: var(--text-2xl);
  line-height: 1;
}

/* --------------------------------------------------------------------------
   4 bis. LES PICTOGRAMMES DES APPELS A L'ACTION

   Ils remplacent les emoji qui decoraient les trois boutons de l'accueil. Un
   emoji est rendu par la police systeme : il change de dessin selon la machine,
   ne suit pas la couleur du texte et se lit a voix haute. Un SVG en
   currentColor suit le theme et l'etat de survol sans une ligne de plus, et
   reste muet pour les lecteurs d'ecran grace a aria-hidden.
   -------------------------------------------------------------------------- */

.cta-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
}

.cta-icone {
  flex: 0 0 auto;
  /* Le trait optique d'une icone parait toujours un cheveu trop haut a cote
     d'une capitale : on la redescend d'un pixel. */
  transform: translateY(1px);
}

/* Les trois compteurs du heros et les trois reseaux de la page A propos. Les
   conteneurs (.stat-icon, .social-icon) etaient dimensionnes pour un emoji,
   c'est-a-dire un caractere : ils portent une taille de police, pas une taille
   de boite. On donne donc au SVG une dimension propre, en em pour qu'il suive
   exactement la taille que ces conteneurs avaient deja choisie. */
.stat-icon .ico-stat {
  display: block;
  width: 1em;      /* .stat-icon vaut 18px : l'icone suit */
  height: 1em;
  margin: 0 auto;
  color: var(--accent-text);
}

/* Les conteneurs sociaux sont regles a 48-56px, une taille pensee pour un
   glyphe. A cette echelle un trait de 2 unites dans un viewBox de 24 rend
   4px reels, beaucoup trop epais. On fixe donc une taille de boite raisonnable
   et on affine le trait : stroke-width est une propriete presentationnelle,
   le CSS la surcharge sans toucher au balisage. */
.social-icon .ico-reseau {
  display: block;
  width: 42px;
  height: 42px;
  margin: 0 auto;
  color: var(--accent-text);
}

.social-icon .ico-reseau [stroke] {
  stroke-width: 1.5;
}

.stat-icon,
.social-icon {
  display: block;
  line-height: 0;   /* l'interligne d'un caractere n'a plus lieu d'etre */
}

/* --------------------------------------------------------------------------
   5. RESPONSIVE
   -------------------------------------------------------------------------- */

/* FENETRE COURTE : telephone en paysage, ou bureau a fort zoom.
   Le retrait haut suffit a degager la barre de navigation, mais pas a faire
   TENIR le contenu : mesure a 844x390, le bloc titre demande 338px pour 310px
   disponibles, et overflow: hidden rend ces 28px irrecuperables -- on ne peut
   meme pas les retrouver en defilant.
   On libere donc de la place au lieu de deplacer le probleme. Les compteurs
   sont ce qui coute le plus (environ 120px avec leur marge) et ce dont on se
   passe le mieux : ils restent lisibles plus bas dans la page.
   Le calage en haut plutot qu'au centre garantit qu'un debordement residuel
   mange le BAS, jamais le titre. */
@media (max-height: 560px) {
  .hero,
  .hero-photo {
    align-items: flex-start;
  }

  .hero .hero-stats {
    display: none;
  }

  .hero .hero-title,
  .hero-photo .hero-title {
    font-size: clamp(24px, 5vw, 36px);
  }
}

@media (max-width: 900px) {
  .bande-photos-grille { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 700px) {
  /* Le heros reste plein ecran sur mobile, c'est la ou l'effet porte le plus.
     On reduit seulement le retrait lateral, la largeur y etant precieuse. */
  .hero {
    padding-inline: 20px;
  }
  /* CADRAGE VERTICAL SUR TELEPHONE.
     Les photos de heros sont horizontales (rapport 1.5) alors que la
     boite fait environ 0.46 sur un telephone. Avec background-size:
     cover, l'image est alors mise a l'echelle sur la HAUTEUR et on ne
     voit qu'une tranche verticale du centre : 31 % de la largeur,
     mesure a 390x844. D'ou l'impression de photo trop zoomee et mal
     rognee -- et l'ancienne image -mobile de l'accueil n'y changeait
     rien, elle avait le meme rapport, elle etait seulement plus legere.
     Chaque heros a desormais une variante VERTICALE (780x1400, rapport
     0.557), recadree une par une sur son sujet et regardee : la part
     visible passe de 31 % a environ 83 %.
     Le repli sur la variante horizontale est volontaire : une page qui
     oublierait sa variante verticale reste correcte au lieu de n'avoir
     aucun fond. */
  .hero::before {
    background-image: var(--heros-image-mobile, var(--heros-image));
    background-position: center center;
  }

  .hero-photo::before {
    background-image: var(--bandeau-image-mobile, var(--bandeau-image));
    background-position: center center;
  }
  /* Le voile devient plus uniforme : sur un ecran etroit le texte occupe
     toute la largeur, un degrade horizontal le laisserait a decouvert. */
  .hero::after,
  .hero-photo::after {
    background:
      linear-gradient(180deg,
        rgba(8, 8, 8, 0.72) 0%,
        rgba(8, 8, 8, 0.86) 100%);
  }

  /* Meme raison sur les bandeaux de page : ils deviennent plus compacts, et le
     titre s'etale sur toute la largeur disponible. */
  /* Le bandeau est desormais plein ecran comme l'accueil : seul le retrait
     lateral se resserre, la largeur etant precieuse sur un telephone. */
  .hero-photo {
    padding-inline: 20px;
  }
}

/* --------------------------------------------------------------------------
   6. MOUVEMENT REDUIT
   Non negociable : tout ce qui bouge doit pouvoir s'arreter. La parallaxe est
   neutralisee cote JS, et le reste ici.
   -------------------------------------------------------------------------- */

/* Ne concerne QUE les elements propres a cette page. Les cartes sont stylees
   dans theme.css, chargee partout : leur neutralisation y vit aussi, sinon
   les survols continueraient de bouger sur les douze autres pages. */
@media (prefers-reduced-motion: reduce) {
  /* Le heros redevient un bloc ORDINAIRE. Un element plein ecran qui reste
     sous les yeux pendant que le contenu glisse dessus est precisement le
     genre de mouvement qui peut declencher un malaise : on ne se contente
     donc pas de supprimer le fondu, on supprime le principe meme. */
  .hero,
  .hero-photo {
    position: relative;
    height: auto;
    min-height: min(70vh, 520px);
    opacity: 1;
    border-radius: var(--radius-lg);
    max-width: var(--largeur-site, 1200px);
    margin-inline: auto;
  }

  .feuille-contenu {
    margin-top: 0;
    box-shadow: none;
  }

  .hero::before,
  .hero-photo::before { transform: none !important; }

  /* Les groupes ne se recouvrent plus : du contenu qui vient en masquer un
     autre est un mouvement, meme sans transition. La page redevient une
     simple suite de blocs. */
  .a-heros-fixe .feuille-contenu > section {
    position: static;
    box-shadow: none;
  }

  /* L'attente et la derive n'ont plus de sens une fois les panneaux remis dans
     le flux : la marge basse deviendrait un vrai trou blanc a traverser, et la
     derive un mouvement subi. */
  .a-heros-fixe .feuille-contenu > section.groupe-plein {
    margin-block: 0;
    translate: none;
  }

  .hero .hero-title::after,
  .hero-photo .hero-title::after { animation: none; }

  .bande-photos-vignette,
  .bande-photos-plus,
  .hero .stat-item {
    transition: none;
  }

  .bande-photos-vignette:hover,
  .bande-photos-plus:hover,
  .hero .stat-item:hover {
    transform: none;
  }

  .bande-photos-vignette:hover img {
    transform: none;
  }
}


/* --------------------------------------------------------------------------
   7. LE RACCORD AVEC LE PIED DE PAGE

   Un heros FIXE transparait par toute zone laissee transparente au-dessus de
   lui. Entre le bas de la feuille et le pied de page, il en restait 60px,
   decomposes exactement ainsi (mesure) : 20px de main { padding-bottom } et
   40px de ooter { margin-top }, tous deux HORS de la feuille.

   On ne supprime pas cet espacement, on le RAPATRIE a l'interieur de la
   feuille : le blanc tournant reste identique, mais il est desormais peint.

   Pourquoi pas un simple fond opaque sur main : main n'est pas positionne,
   son fond est donc peint SOUS les elements positionnes, et le heros fixe
   repasserait par-dessus. Seul un element positionne peut le masquer.
   -------------------------------------------------------------------------- */

.a-heros-fixe main {
  padding-bottom: 0;
  /* ANIMATION D'ENTREE REMPLACEE, et ce n'est pas cosmetique.
     base.css pose `main { animation: fadeIn 0.8s ease-out !important }`, dont
     les images cles deplacent un transform (translateY 50px -> 0). Or un
     transform sur un ANCETRE change le referentiel d'un descendant en
     position: fixed : celui-ci s'ancre alors sur cet ancetre au lieu de la
     fenetre. Mesure : avec un transform sur main, le heros passe de 0 a 128px
     du haut. Pendant les 800 premieres millisecondes de CHAQUE page, le heros
     glissait donc au lieu de rester fixe.
     Le fondu ci-dessous n'anime que l'opacite. L'opacite cree un contexte
     d'empilement mais PAS de referentiel : le heros reste ancre a la fenetre.
     Les memes proprietes sont a proscrire ici : filter, perspective,
     backdrop-filter, contain: paint et will-change: transform. */
  animation: fondu-entree 0.6s ease-out !important;
}

@keyframes fondu-entree {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.a-heros-fixe footer {
  margin-top: 0;
  /* RANG EXPLICITE, indispensable. Le pied de page etait en position: relative
     mais z-index: auto, donc sans rang declare : il ne devait au heros que
     l'ordre du document. Depuis que le heros porte will-change: opacity, il
     vit sur sa PROPRE couche de composition, et une couche promue peut passer
     au-dessus d'un element non promu que rien ne place explicitement plus
     haut. La photo reapparaissait alors derriere le pied pendant le fondu,
     alors meme que la geometrie ne laissait aucun creux -- c'est pourquoi une
     mesure de positions ne pouvait pas le detecter.
     z-index: 1 le place sans ambiguite au-dessus du heros (z-index: 0), au
     meme rang que la feuille de contenu. */
  position: relative;
  z-index: 1;
  /* Le fond n'est PAS redeclare : il vaut deja rgb(15,15,15), opaque, et suit
     le theme via le bloc de contexte carbone. Le repeindre ici risquerait de
     modifier une couleur qui fonctionne, pour rien. */
}

/* Meme raison pour les commandes flottantes : elles sont fixes et doivent
   rester au-dessus du heros en toute circonstance. */
.a-heros-fixe .social-bar,
.a-heros-fixe #scroll-to-top,
.a-heros-fixe #theme-toggle,
.a-heros-fixe #cookie-settings-btn {
  z-index: 1000;
}

/* SOUS 769px, LA BARRE SOCIALE N'EST PLUS FIXE.
   base.css la repasse en position: static a cette largeur : elle quitte alors
   la couche flottante et redevient un bloc du flux, place entre </main> et
   <footer>, donc HORS de la feuille opaque. Elle y occupe une cinquantaine de
   pixels que rien ne peint, et le heros fixe transparait par cette bande le
   temps que le fondu s'acheve.
   Deux precisions qui expliquent pourquoi le defaut a survecu aux corrections
   precedentes : le z-index declare ci-dessus est INERTE sur un element
   static, et cette barre n'a AUCUN fond propre. Il ne suffit donc pas de la
   hisser, il faut la PEINDRE.
   Elle est aussi sortie du flux visuel du bas de page : le fond de la page,
   applique ici, la raccorde a la feuille et au pied. */
@media (max-width: 768px) {
  .a-heros-fixe .social-bar {
    position: relative;
    z-index: 1;
    background: var(--bg);
  }
}

.a-heros-fixe .feuille-contenu {
  /* display: flow-root empeche la marge du dernier bloc de s'echapper de la
     feuille, ce qui laisserait reapparaitre une bande transparente. */
  display: flow-root;
  padding-bottom: 60px;
}


/* ==========================================================================
   CINQ CORRECTIONS ISSUES DE LA REVUE DES ETATS TRANSITOIRES
   ========================================================================== */

/* --- 1. La bascule de theme laissait une bande de l'ancien theme.
   Entre le moment ou le heros atteint l'opacite 0 et celui ou la feuille
   arrive en haut de l'ecran, le haut de la fenetre est peint par le FOND DU
   CORPS DE PAGE, vu a travers un heros devenu transparent. Or body porte
   `transition: background-color 0.3s` tandis que la feuille n'en avait
   aucune : pendant 300ms les deux surfaces changeaient de theme a des
   vitesses differentes, et une bande de l'ancien theme, jusqu'a 144px de
   haut, restait posee au-dessus du contenu.
   La feuille suit desormais exactement la meme transition que le corps. */
.feuille-contenu {
  transition: background-color 0.3s ease, color 0.3s ease;
}

/* --- 2. L'infobulle des badges etait enfermee par sa carte.
   Sous 600px, theme.css fait passer l'infobulle en position: fixed pour
   qu'elle s'echappe de la carte et se centre sur l'ecran. Mais la carte
   revelee porte `transform: translateY(0) !important` et
   `will-change: transform, filter` : l'une comme l'autre creent un
   REFERENTIEL. L'infobulle s'ancrait donc sur la carte au lieu de la fenetre,
   et son z-index de 1000 se retrouvait enferme dans le contexte d'empilement
   de cette meme carte. Resultat mesure sur telephone : elle s'affichait au
   centre de la CARTE, par-dessus la vignette video.

   Il ne suffisait PAS de retirer will-change : une transformation explicite
   cree un referentiel a elle seule, et translateY(0) en est une.

   La levee est limitee au moment ou l'infobulle est reellement affichee. Une
   regle permanente sur .visible aurait supprime le glissement de revelation
   de ces cartes, et retirer l'indication de performance au moment meme ou la
   transition en a besoin aurait ete un contresens. translateY(0) et none sont
   visuellement identiques : la bascule ne produit aucun saut. */
@media (max-width: 600px) {
  .visible:has([data-tooltip]:hover),
  .visible:has([data-tooltip]:focus-visible) {
    transform: none !important;
    will-change: auto;
  }
}

@media (prefers-reduced-motion: reduce) {
  /* --- 3. L'animation d'entree de main survivait a la reduction des
     animations. base.css la coupe bien par `main, nav { animation: none }`,
     mais la regle que j'ai posee sur .a-heros-fixe main porte !important --
     il le fallait pour battre le !important de base.css -- et l'emportait
     donc aussi sur cette coupure. Le contenu continuait d'apparaitre en fondu
     pendant 600ms chez quelqu'un qui a explicitement demande l'arret des
     animations. Il faut donc un !important ici aussi. */
  .a-heros-fixe main {
    animation: none !important;
  }

  /* Les coupures du bandeau cookies et de la bascule de theme ont ete
     DEPLACEES vers theme.css : elles concernent des elements presents sur
     les 14 pages, alors que cette feuille n'est chargee que sur les 8 pages
     a heros. Six pages ne les recevaient donc pas. */
  .feuille-contenu {
    transition: none;
  }
}