/* ─────────────────────────────────────────
   MLinguistique : Méga menu de l'en-tête
   Charge après main.css : lit ses tokens,
   n'en redéclare aucun.

   Fonctionne sans JavaScript : chaque panneau
   est un sous-menu visible au survol des
   pointeurs fins, ou déplié au clic une fois
   le script en place (voir le rapport du
   worker pour les attributs que le script
   doit gérer). En dessous de 900px, aucun
   méga menu : liste dépliable classique.
───────────────────────────────────────── */

/* ── Rubriques de premier niveau ──
   La pilule de survol a besoin de respirer : sans marge intérieure, elle colle
   aux lettres et se lit comme un défaut d'affichage, pas comme un état.

   Elle est payée par l'écart entre les rubriques, qui n'a plus à porter seul la
   séparation : la marge intérieure le fait désormais. L'écart de .ml-nav-links
   (24px dans main.css) tombe donc ici à 4px, et deux mots voisins restent
   séparés de 4 + 2 x 14 = 32px, un peu plus qu'avant.

   Pourquoi payer, plutôt que d'ajouter simplement de la marge : entre 900 et
   1100px, la barre est déjà pleine, et les libellés longs (« Apprendre les
   langues », « Formules spéciales ») s'y replient sur deux lignes. C'est le cas
   avant même cette marge intérieure : la barre est bornée à la largeur du
   contenu et le menu y tient tout juste. Élargir les rubriques sans reprendre
   l'écart aurait fait replier davantage de libellés, sur des largeurs où ils
   tiennent encore. Mesuré à 1024px : la largeur du menu et la hauteur de la
   barre sont restées identiques après le changement. */
.ml-mega-menu {
  align-items: center;
  gap: 4px;
}

.ml-mega-item {
  position: relative;
}

.ml-mega-link,
.ml-mega-bouton {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--ml-font-heading);
  font-size: var(--ml-fs-base);
  font-weight: 600;
  /* Suit la couleur de la barre : clair en transparent sur le hero, sombre
     dès qu'elle devient opaque (voir --ml-header-fg dans main.css). */
  color: var(--ml-header-fg, var(--ml-primary));
  background: none;
  border: 0;
  padding: var(--ml-space-xs) 14px;
  cursor: pointer;
  transition: color 160ms var(--ml-ease);
}

@media (prefers-reduced-motion: reduce) {
  .ml-mega-link,
  .ml-mega-bouton {
    transition: none;
  }
}

/* Le survol d'une rubrique ne change JAMAIS la couleur du texte. La barre est
   tantôt claire, tantôt en verre dépoli sur un haut de page sombre, et le
   violet est trop foncé pour se lire sur un fond sombre : la rubrique survolée
   y devenait illisible. Un voile prend donc le relais, et il se lit dans les
   deux états parce qu'il est fait de la couleur du texte elle même, à faible
   opacité : clair sur fond sombre, sombre sur fond clair, sans jamais avoir à
   savoir dans quel état on se trouve. */
.ml-mega-link,
.ml-mega-bouton {
  border-radius: var(--ml-radius-pill);
  transition: background-color 160ms var(--ml-ease);
}

.ml-mega-link:hover,
.ml-mega-bouton:hover {
  background-color: color-mix(in srgb, currentColor 12%, transparent);
}

/* Repli pour les navigateurs sans color-mix() : un voile clair, qui reste
   visible sur le verre dépoli (l'état où le défaut se voyait) et discret
   ailleurs. Mieux vaut un voile un peu pâle sur fond blanc qu'une rubrique
   illisible sur fond sombre. */
@supports not (background-color: color-mix(in srgb, currentColor 12%, transparent)) {
  .ml-mega-link:hover,
  .ml-mega-bouton:hover {
    background-color: rgba(127, 127, 127, 0.16);
  }
}

@media (prefers-reduced-motion: reduce) {
  .ml-mega-link,
  .ml-mega-bouton {
    transition: none;
  }
}

.ml-mega-chevron {
  inline-size: 8px;
  block-size: 8px;
  border-inline-end: 2px solid currentColor;
  border-block-end: 2px solid currentColor;
  rotate: 45deg;
  translate: 0 -2px;
  transition: rotate 200ms var(--ml-ease);
}

.ml-mega-bouton[aria-expanded="true"] .ml-mega-chevron {
  rotate: -135deg;
  translate: 0 2px;
}

/* ── Panneau ──
   Masqué par l'attribut hidden par défaut. Sans JavaScript, le survol sur
   pointeur fin le révèle malgré l'attribut hidden (voir plus bas) : c'est le
   repli qui garantit un menu utilisable même si le script ne se charge pas. */
/* Le panneau est centré sur sa rubrique : le milieu du panneau tombe sous le
   milieu du bouton, quelle que soit la place de celui ci dans la barre. Le
   bouton remplit son <li> (.ml-mega-item), le centre de l'un est donc le centre
   de l'autre.

   --ml-mega-decalage est le rattrapage posé par le script quand un panneau
   centré déborderait de la fenêtre (voir assets/js/mega-menu.js). Il vaut zéro
   par défaut : sans script, le panneau reste centré, c'est à dire correct
   partout sauf aux tout derniers pixels des rubriques de bord, où il est de
   toute façon inatteignable autrement qu'au clavier. */
.ml-mega-panel {
  --ml-mega-decalage: 0px;

  position: absolute;
  inset-inline-start: 50%;
  translate: calc(-50% + var(--ml-mega-decalage)) 0;
  top: 100%;
  z-index: 90;
  /* Un panneau à plusieurs colonnes a besoin de place : sans largeur minimale
     suffisante, les colonnes se replient les unes sous les autres. La largeur
     minimale cède devant la fenêtre : sur un écran étroit, un panneau plus
     large que la fenêtre ne pourrait jamais y être ramené.

     Le cas le plus large du site : Destinations, douze entrées, soit trois
     colonnes (quatre liens chacune, ML_MEGA_LIENS_PAR_COLONNE), plus la mise en
     avant. Le compte, à 1040px : 4 de bordure, 48 de marge intérieure, 272 pour
     la mise en avant (17rem), 40 d'écart, il reste 676 pour trois colonnes de
     199px séparées de 40. La colonne ne descend jamais sous ses 160px de
     plancher, elle ne se replie donc pas. Mesuré dans Chromium, pas déduit :
     676 = 3 x 199 + 2 x 40, et le panneau s'arrête à 1064px sur une fenêtre de
     1280. À 1000px de fenêtre, les colonnes tombent à 169px : encore au dessus
     du plancher, toujours trois colonnes. */
  min-inline-size: min(640px, calc(100vw - 2 * var(--ml-space-md)));
  max-inline-size: min(1040px, calc(100vw - 2 * var(--ml-space-md)));
  background: var(--ml-bg);
  /* Le trait des bulles de salutation (bulle-hola, bulle-hallo), transposé :
     violet franc, net, et des coins largement arrondis. Deux pixels, pas
     quatre : le panneau porte des colonnes de liens, une mise en avant et un
     pied. Un contour épais autour de tout cela ferait scolaire et écraserait le
     contenu, alors que la bulle, elle, ne porte qu'un mot.

     L'ombre s'allège d'autant (--ml-shadow-md, et non plus -lg) : c'est le
     trait qui détache maintenant le panneau du fond, l'ombre n'a plus à le
     faire seule. Les deux ensemble donnaient un relief lourd. */
  border: 2px solid var(--ml-accent);
  border-radius: var(--ml-radius-lg);
  box-shadow: var(--ml-shadow-md);
  margin-top: var(--ml-space-xs);
}

.ml-mega-panel[hidden] {
  display: none;
}

.ml-mega-panel-inner {
  padding: var(--ml-space-md);
}

/* Le « Voir tout » ferme le panneau, sous les colonnes et sous la carte. Il est
   hors de la grille du corps : il occupe donc naturellement toute la largeur du
   panneau, sans piste a lui, et sans deplacer la carte. Le filet le detache de
   ce qui precede, comme un pied de panneau. */
/* Au fond de la zone des liens, pas au fond du panneau : « auto » mange tout
   l'espace libre au dessus de lui.

   Ce « auto » était écrit, puis annulé quinze lignes plus bas par un second
   « margin-block-start: var(--ml-space-md) » dans la même règle : c'est la
   dernière déclaration qui gagne, et le « Voir tout » n'était donc plus poussé
   au fond de quoi que ce soit. Il s'ajoutait au contraire à l'écart de la
   colonne (24px de la grille, plus 24px de marge), ce qui ouvrait 48 pixels de
   blanc entre le dernier pays et le filet, puis étirait le panneau d'autant.
   Une seule déclaration, désormais : la marge est « auto », et elle ne vaut
   quelque chose que s'il reste vraiment de la place à combler. Mesuré : le
   panneau Destinations perd 24 pixels rien qu'en retirant le doublon. */
.ml-mega-lien-rubrique {
  margin-block-start: auto;

  display: flex;
  align-items: center;
  gap: 0.4em;
  justify-content: center;
  font-family: var(--ml-font-heading);
  font-weight: 600;
  color: var(--ml-accent);
  padding-block-start: var(--ml-space-sm);
  border-block-start: 1px solid var(--ml-border);
}

.ml-mega-lien-rubrique:hover,
.ml-mega-lien-rubrique:focus-visible {
  color: var(--ml-accent-dark);
}

.ml-mega-lien-rubrique-fleche {
  inline-size: 0.4em;
  block-size: 0.4em;
  border-block-start: 2px solid currentColor;
  border-inline-end: 2px solid currentColor;
  rotate: 45deg;
  transition: translate 160ms var(--ml-ease);
}

.ml-mega-lien-rubrique:hover .ml-mega-lien-rubrique-fleche,
.ml-mega-lien-rubrique:focus-visible .ml-mega-lien-rubrique-fleche {
  translate: 0.2em 0;
}

@media (prefers-reduced-motion: reduce) {
  .ml-mega-lien-rubrique-fleche {
    transition: none;
  }
}

/* Le corps du panneau : les colonnes de liens, puis la zone de mise en avant a
   droite. Sous 900px, la carte passe dessous, puis disparait dans le tiroir. */
.ml-mega-panel-corps {
  display: grid;
  gap: var(--ml-space-lg);
}
@media (min-width: 900px) {
  /* La piste de la carte n'existe que si la carte existe. Une piste réservée
     pour rien écrasait la zone des colonnes, qui se repliaient alors sur une
     seule. Le sélecteur :has() rend la grille conditionnelle à sa présence.

     Un navigateur sans :has() ignore ce bloc en entier : le panneau garde alors
     sa grille a une seule piste, colonnes puis carte l'une sous l'autre. C'est
     moins compact, mais tout reste lisible et rien ne se chevauche. */
  .ml-mega-panel-corps:has(.ml-mega-carte) {
    grid-template-columns: minmax(0, 1fr) 17rem;
    align-items: stretch;
  }
}

/* Le panneau s'elargit selon le nombre de colonnes qu'il porte.

   Le nombre est connu du code, jamais du style : le code le pose en variable
   sur le panneau, et le style calcule la place. Une regle par valeur possible
   (« si trois colonnes », « si quatre ») laissait un trou des qu'une valeur
   n'avait pas ete prevue : a deux colonnes, aucune regle ne s'appliquait, la
   piste des liens se reduisait, et les colonnes repassaient l'une sous l'autre.
   C'est exactement ce qui vient de se produire en passant a cinq liens par
   colonne, ou les neuf pays tiennent en deux colonnes.

   Une colonne fait --ml-mega-col-w au minimum, les ecarts font --ml-space-md.
   La piste des liens ne descend jamais sous ce total : c'est la seule chose qui
   empeche une colonne de repasser a la ligne. */
.ml-mega-panel {
  --ml-mega-cols: 1;
  --ml-mega-col-w: 160px;
  --ml-mega-liens-w: calc(
    var(--ml-mega-cols) * var(--ml-mega-col-w) +
    (var(--ml-mega-cols) - 1) * var(--ml-space-md)
  );
}

@media (min-width: 900px) {
  /* La largeur du panneau : les liens, la mise en avant (17rem), l'ecart large
     qui les separe, et le rembourrage du panneau. Bornee par la fenetre : un
     panneau plus large qu'elle ne pourrait jamais y etre ramene. */
  .ml-mega-panel:has(.ml-mega-carte) {
    max-inline-size: min(
      calc(var(--ml-mega-liens-w) + 17rem + var(--ml-space-lg) + 2 * var(--ml-space-md)),
      calc(100vw - 2 * var(--ml-space-md))
    );
  }

  .ml-mega-panel-corps:has(.ml-mega-carte) {
    grid-template-columns: minmax(var(--ml-mega-liens-w), 1fr) 17rem;
  }

  /* Les colonnes ne se replient jamais : la piste ci dessus leur garantit la
     place, le nowrap garantit qu'elles la prennent. */
  .ml-mega-colonnes-rangee {
    flex-wrap: nowrap;
  }
}

/* L'ecart entre deux colonnes de liens, et le plancher d'une colonne, sont
   calibres sur le cas le plus serre du site : Destinations, douze entrees, donc
   trois colonnes (quatre liens chacune) a cote de la mise en avant.

   A 900px de fenetre, le panneau ne fait plus que 852px, et il reste 488px pour
   les trois colonnes une fois la mise en avant (272px) et les marges deduites.
   Trois colonnes de 160px separees de 40px en demandaient 560 : la troisieme
   passait a la ligne, et le panneau s'affichait sur deux rangees entre 900 et
   970px de fenetre. Mesure dans Chromium, largeur par largeur.

   Un ecart de 24px et un plancher de 140px en demandent 468 : les trois colonnes
   tiennent. Au dela de 1100px, ou le panneau atteint sa largeur maximale, elles
   valent 209px chacune, le plancher ne joue plus. L'ecart entre les liens et la
   mise en avant, lui, reste large (--ml-space-lg sur la grille du corps) : c'est
   celui la qui separe deux natures de contenu, pas deux colonnes de la meme
   liste. */
/* La zone des liens est une colonne : les colonnes de liens en haut, le lien
   « Voir tout » au fond. C'est « margin-block-start: auto » sur ce dernier qui
   le pousse en bas, et donc qui comble le vide que la mise en avant, plus haute
   que les liens, laissait sous eux. */
.ml-mega-panel-colonnes {
  display: flex;
  flex-direction: column;
  gap: var(--ml-space-md);
}

/* Les colonnes de liens elles memes, cote a cote. */
.ml-mega-panel-colonnes > .ml-mega-colonnes-rangee {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ml-space-md);
}

.ml-mega-colonne {
  flex: 1 1 140px;
  min-inline-size: 140px;
}

/* ── Panneau court : une grille de cartes plutot qu'une colonne de liens ──
   Un panneau qui ne porte que quelques entrees (les quatre langues) tenait tout
   entier dans une colonne de 160px, et la mise en avant, large de 17rem, l'y
   ecrasait : le panneau paraissait vide. La grille, elle, prend toute la largeur
   qui reste. La bascule est decidee par le PHP (ML_MEGA_CARTES_MAX), jamais par
   le style : c'est le nombre d'entrees qui commande, pas la largeur d'ecran.

   Deux cartes par rangee : a quatre entrees, deux fois deux ; a six, trois fois
   deux. Quatre cartes en ligne a cote d'une mise en avant de 17rem ne feraient
   plus que 130px de large chacune, moins qu'un lien de colonne.

   La grille etire ses rangees (align-items: stretch par defaut) : une carte sans
   description reste de la meme hauteur que sa voisine qui en a une. Aucun trou. */
.ml-mega-cartes {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  /* Les rangees se partagent la hauteur a parts egales, et la grille occupe
     toute celle de sa zone. Sans cela, quatre cartes de 81px laissaient un vide
     de 170px sous elles, a cote d'une mise en avant qui fait 256px de haut : le
     panneau restait aussi desequilibre qu'avant, dans l'autre sens. Mesure. */
  grid-auto-rows: 1fr;
  block-size: 100%;
  gap: var(--ml-space-sm);
  inline-size: 100%;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* La case de la grille, et la carte qui la remplit entierement : c'est ce qui
   fait que deux cartes voisines ont la meme hauteur, meme quand l'une porte une
   description et l'autre non. */
.ml-mega-carte-lien-item {
  display: flex;
}

.ml-mega-carte-lien-item > .ml-mega-vignette {
  flex: 1 1 auto;
  min-inline-size: 0;
}

/* Sans mise en avant, toute la largeur du panneau revient aux cartes. Les pistes
   sont alors calculees sur la place reelle, et non fixees d'avance : quatre
   cartes s'y rangent en une seule ligne, six en deux lignes de trois, et la
   derniere rangee n'est jamais a moitie vide. Une grille de trois pistes figee
   laissait, a quatre cartes, un trou de deux cases. Mesure. */
@media (min-width: 900px) {
  .ml-mega-panel-corps:not(:has(.ml-mega-carte)) .ml-mega-cartes {
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  }
}

/* La zone des colonnes cesse d'etre une rangee de colonnes flexibles : elle
   n'accueille plus qu'une grille, qui doit occuper toute sa largeur et toute sa
   hauteur (la grille s'etire sur la mise en avant, qui est la plus haute). */
.ml-mega-panel-colonnes--cartes {
  display: block;
}

/* ── La carte d'une langue ──
   Elle portait le creme du site (--ml-bg-alt) sur le fond blanc du panneau :
   1,07:1. Autrement dit rien. Le client l'a dit a sa facon, « les cases ne se
   voient pas assez », et il avait raison au chiffre pres : a cote de l'encadre
   de mise en avant, qui est une photo sombre, ces quatre cartes n'existaient
   pas.

   Elles prennent donc le degrade de marque, celui qui sert deja de repli a
   l'encadre quinze lignes plus bas, au fond de bulle des cartes de langue de
   l'accueil (.ml-langue-card-bulle) et de repli aux cartes de formule
   (main.css) : violet en haut a gauche, aubergine nuit en bas a droite. Rien de
   nouveau n'est invente, c'est le meme degrade, aux memes tokens. La carte
   passe a 10,1:1 (bout violet) et 16,5:1 (bout aubergine) contre le panneau : on
   la voit.

   Le vrai gain est ailleurs. La bulle de salutation n'est PAS un aplat violet :
   c'est un ballon au VENTRE BLANC ET OPAQUE, cercle d'un trait violet (sonde
   des pixels : la moitie de l'image est du blanc plein, alpha 255). Sur le
   creme, ce ventre blanc tenait 1,05:1 : du blanc sur du blanc, la bulle etait
   invisible et seul son contour se devinait. Sur le marine, il tient 10,1:1 au
   repos. Foncer la carte ne fait donc pas disparaitre la bulle : c'est ce qui
   la fait enfin apparaitre. main.css le disait deja, sans que le menu en tienne
   compte : « le bandeau de la bulle, sur lequel la craie blanche du dessin se
   detache. Sur le creme de la carte, elle disparaitrait. »

   La bulle tombe en bas a droite, c'est a dire sur le bout marine du degrade :
   c'est la que son ventre blanc detache le mieux, et que les lettres, violettes
   sur ce ventre, gardent leur propre contraste.

   L'ombre teintee de l'accent, elle, ne bouge pas : c'est le vocabulaire des
   cartes du site (.ml-carte-destination, .ml-carte-formule), discrete au repos,
   qui s'ouvre au survol.

   Aucun rembourrage reserve a droite : la fleche n'est pas posee dans le coin,
   elle suit le nom dans le flux du lien. Le rembourrage du bas, lui, reserve la
   place de la bulle (voir .ml-mega-vignette:has(.ml-mega-vignette-bulle)). */
.ml-mega-vignette {
  position: relative;
  display: flex;
  flex-direction: column;
  block-size: 100%;
  padding: var(--ml-space-sm);
  border-radius: var(--ml-radius);
  background: linear-gradient(160deg, var(--ml-accent) 0%, var(--ml-primary) 100%);
  overflow: hidden;
  box-shadow: 0 8px 28px -14px rgba(102, 31, 128, 0.35);
  transition: box-shadow 320ms var(--ml-ease), scale 320ms var(--ml-ease);
}

/* Le survol se joue sur l'ombre et sur l'echelle, comme partout ailleurs sur le
   site (.ml-carte-destination, .ml-langue-card) : la carte se souleve. Le fond
   ne change pas de couleur, il n'aurait pas pu, un degrade ne se transitionne
   pas. Il n'en a pas besoin : la bulle se redresse, la fleche avance, l'ombre
   s'ouvre. Trois reponses valent mieux qu'un aplat qui clignote. */
.ml-mega-vignette:hover,
.ml-mega-vignette:focus-within {
  box-shadow: 0 24px 60px -18px rgba(102, 31, 128, 0.55);
  scale: 1.02;
}

@media (prefers-reduced-motion: reduce) {
  .ml-mega-vignette {
    transition: none;
  }
  .ml-mega-vignette:hover,
  .ml-mega-vignette:focus-within {
    scale: 1;
  }
}

/* Le titre porte le lien, et son pseudo element couvre la carte entiere : un
   seul arret a la tabulation, un seul intitule a lire. Le drapeau, purement
   decoratif, est place avant lui dans le flux et n'entre pas dans le lien : une
   synthese vocale ne lit donc que le nom.

   Blanc sur le degrade de la carte : 10,1:1 sur le bout violet, ou tombe le
   titre, et 15,1:1 sur le bout marine. Le sens d'usage du theme est respecte,
   le violet porte du texte blanc et jamais l'inverse.

   Il ne change pas de couleur au survol : il est deja blanc, et il n'y a rien
   au dessus du blanc. La carte repond autrement (ombre, echelle, bulle,
   fleche). */
.ml-mega-vignette-titre {
  /* Statique, et c'est le point qui rend la carte entierement cliquable : un
     lien positionne ancrerait son pseudo element sur lui meme, et la zone de
     clic se refermerait sur le seul titre. C'est ce qui se passait. La zone de
     texte au dessus (.ml-mega-vignette-zone) porte l'elevation a sa place.

     Le lien devient une rangee : le nom, puis la fleche a cote. Un flex reste
     un element non positionne, la regle ci dessus tient donc toujours.
     « align-items: baseline » cale la pointe de la fleche sur la ligne du nom :
     centree, elle flotterait au dessus sur un nom qui passe a la ligne. */
  position: static;
  display: flex;
  align-items: baseline;
  gap: 0.35em;
  font-family: var(--ml-font-heading);
  font-weight: 700;
  font-size: var(--ml-fs-base);
  color: #fff;
  text-wrap: balance;
}

/* Le calque cliquable : il couvre la carte entiere, il est transparent, et il
   reste SOUS le texte (z-index 0 contre 1 sur la zone de texte). Le nom de la
   langue ne peut donc pas disparaitre dessous. La bulle, elle aussi a zero mais
   ecrite plus tot dans le document, passe sous ce calque : elle ne perd rien,
   le calque n'a pas de fond, et sa regle pointer-events: none laisse de toute
   facon le clic la traverser. */
.ml-mega-vignette-titre::after {
  content: '';
  position: absolute;
  z-index: 0;
  inset: 0;
  border-radius: inherit;
}

/* Le trait de focus est blanc, comme celui du bouton de l'encadre de mise en
   avant : le violet du theme, pose sur une carte violette, ne se verrait pas.
   Blanc sur le bout violet du degrade : 10,1:1. */
.ml-mega-vignette-titre:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 2px;
  border-radius: var(--ml-radius-sm);
}

/* L'accroche : le ton du theme pour le texte pose sur un fond sombre
   (--ml-text-on-dark). 9,3:1 sur le bout violet du degrade, 13,9:1 sur le
   marine. Le gris moyen d'avant (--ml-text-mid), calibre pour le creme, y
   serait tombe sous la barre. */
.ml-mega-vignette-texte {
  display: block;
  margin-block-start: 4px;
  font-size: 0.8rem;
  line-height: 1.45;
  color: var(--ml-text-on-dark);
}

/* Le drapeau, quand il existe. Une entree qui vise une page ordinaire n'en a
   pas : rien n'est ecrit, et le titre part alors du haut de la carte, sans case
   vide reservee pour rien. */
.ml-mega-vignette .ml-mega-drapeau {
  align-self: flex-start;
  margin-inline-end: 0;
  margin-block-end: 4px;
  font-size: 1.25rem;
}

/* La fleche avance au survol, comme sur les cartes du site.

   Elle vit DANS le lien, a cote du nom, et non plus dans un coin de la carte.
   Posee en bas a droite, elle tombait sur la bulle de salutation, qui occupe ce
   coin : le dessin s'en trouvait coupe, et le client l'a vu tout de suite. A
   cote du nom, elle dit la meme chose sans rien recouvrir, et la bulle retrouve
   son coin entier.

   « flex: 0 0 auto » : elle ne se laisse ni ecraser ni etirer par le nom, qui
   peut passer a la ligne. Elle reste decorative (aria-hidden dans le balisage)
   et ne capte aucun clic : le calque du lien, qui couvre la carte, recoit le
   clic a travers elle. */
.ml-mega-vignette-fleche {
  pointer-events: none;
  flex: 0 0 auto;
  inline-size: 0.4em;
  block-size: 0.4em;
  /* Le carre tourne de 45 degres : sa pointe se cale sur la ligne du nom une
     fois releve d'un quart de sa hauteur. Sans ce rattrapage, il s'assoit sur la
     ligne de base et parait tomber sous le mot. Mesure, pas devine. */
  translate: 0 -0.1em;
  /* La couleur du nom qu'elle suit, c'est a dire blanche : un chevron violet
     sur une carte violette ne se verrait pas. Objet graphique, 10,1:1 sur le
     bout violet du degrade, la ou 3:1 sont exiges. */
  border-block-start: 2px solid currentColor;
  border-inline-end: 2px solid currentColor;
  rotate: 45deg;
  transition: translate 260ms var(--ml-ease);
}

.ml-mega-vignette:hover .ml-mega-vignette-fleche,
.ml-mega-vignette:focus-within .ml-mega-vignette-fleche {
  translate: 0.25em -0.1em;
}

@media (prefers-reduced-motion: reduce) {
  .ml-mega-vignette-fleche {
    transition: none;
  }
  .ml-mega-vignette:hover .ml-mega-vignette-fleche,
  .ml-mega-vignette:focus-within .ml-mega-vignette-fleche {
    translate: 0 -0.1em;
  }
}

.ml-mega-colonne-titre {
  display: block;
  font-family: var(--ml-font-heading);
  font-weight: 700;
  color: var(--ml-primary);
  margin-bottom: var(--ml-space-xs);
}

a.ml-mega-colonne-titre:hover {
  color: var(--ml-accent);
}

/* Les liens d'une meme colonne se lisent d'un bloc : un espacement large les
   ferait passer pour des sections distinctes. Quatre pixels, pas deux : la
   colonne des destinations est plus courte que la mise en avant posee a cote, et
   elle laissait un vide sous elle. Le respirer, plutot que l'etirer : au dela de
   quatre pixels, les liens cessent de former une liste et deviennent des blocs
   separes, ce qui est exactement ce qu'il ne faut pas. Le reste du comblement
   vient du corps du texte et du rembourrage des liens, plus bas. */
.ml-mega-colonne-liens {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

/* Le chevron est pose en pseudo-element, jamais dans le HTML : il ne porte
   aucune information, et un lecteur d'ecran ne doit pas le rencontrer.

   Au survol, le lien prend un fond : un simple changement de couleur du texte
   se voyait mal sur le fond clair du panneau. Le fond est le violet tres dilue
   du theme (--ml-accent-soft), le texte passe au violet fonce
   (--ml-accent-dark) : 11.3:1, bien au dela des 4.5:1 exiges. La pastille
   deborde du texte par une marge negative, pour qu'elle ne colle pas aux
   lettres sans decaler la colonne au repos. */
/* Le corps du texte d'un lien de destination : --ml-fs-base (16px), et non plus
   --ml-fs-sm (14px). Un nom de pays n'est pas une note de bas de page : il se
   lit du premier coup d'oeil, et il a la meme importance qu'une carte de
   langue, qui est deja a 16px. Cette taille la reste.

   Le rembourrage vertical, lui, revient de 9 a 6 pixels. Il avait ete gonfle
   pour combler le vide qu'on voyait sous les liens : c'etait soigner le
   symptome. Le vide venait en realite de la marge du « Voir tout », comptee
   deux fois (voir plus haut), et le client a fini par voir le resultat de ce
   remplissage : un panneau trop haut. On enleve la cause, on n'a plus a gonfler
   la consequence.

   La pastille de survol fait alors 38px de haut, contre 42. C'est la hauteur
   d'une ligne de menu, la cible reste large de toute la colonne, et le survol
   ne se joue ici qu'au pointeur fin : le doigt, lui, passe par le tiroir, ou le
   lien garde ses 44px (voir plus bas). Mesure sur la colonne des cinq pays :
   208px de liens, contre 238. */
.ml-mega-lien {
  display: block;
  position: relative;
  color: var(--ml-text);
  font-size: var(--ml-fs-base);
  padding-block: 6px;
  padding-inline: 0.5em 1.4em;
  margin-inline-start: -0.5em;
  border-radius: var(--ml-radius-sm);
  transition: color 160ms var(--ml-ease),
              background-color 160ms var(--ml-ease);
}

/* Le chevron se cale au milieu de la hauteur du lien, quelle que soit cette
   hauteur : il etait accroche a un « inset-block-start » fixe (0.85em), calibre
   sur l'ancien rembourrage, et il se serait retrouve au dessus du texte des que
   le lien a grandi. */
.ml-mega-lien::after {
  content: '';
  position: absolute;
  inset-inline-end: 0.5em;
  inset-block-start: 50%;
  inline-size: 0.36em;
  block-size: 0.36em;
  border-block-start: 1.5px solid currentColor;
  border-inline-end: 1.5px solid currentColor;
  rotate: 45deg;
  translate: -0.25em -50%;
  opacity: 0;
  transition: opacity 160ms var(--ml-ease), translate 160ms var(--ml-ease);
}

.ml-mega-lien:hover,
.ml-mega-lien:focus-visible {
  background-color: var(--ml-accent-soft);
  color: var(--ml-accent-dark);
}

.ml-mega-lien:hover::after,
.ml-mega-lien:focus-visible::after {
  opacity: 1;
  translate: 0 -50%;
}

/* Le focus garde son trait : la pastille seule ne suffit pas a distinguer le
   lien survole du lien atteint au clavier. */
.ml-mega-lien:focus-visible {
  outline: 2px solid var(--ml-accent);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  .ml-mega-lien,
  .ml-mega-lien::after {
    transition: none;
  }
}

/* La description suit le lien : sur la pastille violette, le gris pale du
   repos tomberait a 3.2:1. Le gris moyen y tient 6.6:1. */
.ml-mega-lien-description {
  display: block;
  font-size: 0.8rem;
  color: var(--ml-text-dim);
  padding-inline: 0.5em;
  margin-inline-start: -0.5em;
  margin-top: 2px;
  transition: color 160ms var(--ml-ease);
}

.ml-mega-lien:hover + .ml-mega-lien-description,
.ml-mega-lien:focus-visible + .ml-mega-lien-description {
  color: var(--ml-text-mid);
}

@media (prefers-reduced-motion: reduce) {
  .ml-mega-lien-description {
    transition: none;
  }
}

/* ── Carte de mise en avant ──
   L'image occupe tout le fond, le texte se pose dessus. Un voile la
   sombrit : sans lui, un visuel clair rendrait le texte blanc illisible,
   et le contraste ne dependrait plus que de la photo choisie.

   La hauteur minimale ne commande plus le panneau, elle le suit. Elle valait
   16rem (256px) alors que le contenu de l'encadre, mesure a 272px de large,
   n'en demande que 206 : cinquante pixels de photo vide au dessus du titre, et
   surtout un plancher que tout le panneau devait respecter. Sur le panneau des
   langues, dont les cartes sont courtes, c'etait litteralement l'encadre qui
   fixait la hauteur du menu.

   13rem (208px) : c'est la hauteur de son propre contenu, pas un chiffre choisi
   au jugé. En dessous, l'encadre serait un timbre poste et le bouton toucherait
   le titre. Au dessus, il impose au panneau une hauteur que rien ne justifie.
   La grille etire de toute facon l'encadre a la hauteur des colonnes quand
   celles ci sont plus hautes (align-items: stretch) : il gagne alors de la photo
   au lieu de perdre du texte. C'est l'encadre qui s'adapte aux colonnes,
   desormais, et non l'inverse. */
.ml-mega-carte {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-block-size: 13rem;
  padding: var(--ml-space-md);
  border-radius: var(--ml-radius);
  overflow: clip;
  /* La carte est son propre plan : les couches de l'image et du voile, posees
     en z-index negatif, restent enfermees dedans et ne passent jamais sous le
     fond du panneau. */
  isolation: isolate;
  /* Repli quand aucune image n'est choisie : jamais une carte vide, ni un
     rectangle blanc. Le degrade suffit a lui seul a porter le texte blanc. */
  background: linear-gradient(160deg, var(--ml-accent), var(--ml-primary));
}

.ml-mega-carte-image {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  z-index: -2;
}

/* Le voile n'a de raison d'etre que sous une image : sur le degrade de repli,
   il ne ferait que l'assombrir sans rien resoudre. */
.ml-mega-carte--avec-image::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(
    to top,
    rgba(30, 10, 42, 0.88) 0%,
    rgba(30, 10, 42, 0.55) 55%,
    rgba(30, 10, 42, 0.2) 100%
  );
}

.ml-mega-carte-contenu {
  color: #fff;
}

.ml-mega-carte-titre {
  font-family: var(--ml-font-heading);
  font-weight: 700;
  font-size: var(--ml-fs-lg);
  color: #fff;
  margin: 0 0 4px;
  text-wrap: balance;
}

.ml-mega-carte-texte {
  font-size: var(--ml-fs-sm);
  color: rgba(255, 255, 255, 0.92);
  margin: 0 0 var(--ml-space-sm);
}

.ml-mega-carte-lien {
  /* SANS position, et c'est tout le sujet.

     Le lien portait « position: relative » : il devenait donc le cadre de
     reference de son propre calque, qui se refermait sur le bouton au lieu de
     couvrir la carte. Mesure : sept virgule cinq pour cent de l'encadre etait
     cliquable, le bouton et rien d'autre. C'est le meme piege que sur les
     cartes de langue, de destination et de formule, et c'est la quatrieme fois
     qu'il se produit dans ce theme.

     Sans position, le calque se cale sur .ml-mega-carte, seul ancetre
     positionne, et couvre l'encadre entier. Le « z-index » suffit a garder le
     bouton au dessus de son propre calque : il s'applique ici parce que le
     bouton est un enfant flex, sans avoir besoin d'etre positionne. */
  z-index: 1;
  display: inline-flex;
  align-self: flex-start;
  align-items: center;
  gap: 0.4em;
  font-family: var(--ml-font-heading);
  font-weight: 600;
  font-size: var(--ml-fs-sm);
  color: #fff;
  /* Blanc sur violet : 10.1:1. Le sens d'usage du violet est respecte, il
     porte du texte blanc, jamais l'inverse. */
  background: var(--ml-accent);
  border-radius: var(--ml-radius-pill);
  padding: 8px var(--ml-space-md);
  transition: background-color 160ms var(--ml-ease), transform 160ms var(--ml-ease);
}

/* Toute la carte est cliquable, et c'est le bouton qui porte ce clic : un seul
   lien, donc un seul arret a la tabulation, et rien a lire deux fois pour une
   synthese vocale. Le calque se glisse sous le contenu, il ne masque rien. */
.ml-mega-carte-lien::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
}

/* Le survol de n'importe quel point de la carte allume son bouton : la carte
   entiere se comporte comme une seule cible, ce qu'elle est. */
.ml-mega-carte:hover .ml-mega-carte-lien,
.ml-mega-carte-lien:focus-visible {
  background: var(--ml-accent-dark);
  transform: translateY(-1px);
}

.ml-mega-carte-lien:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  .ml-mega-carte-lien { transition: none; }
  .ml-mega-carte:hover .ml-mega-carte-lien,
  .ml-mega-carte-lien:focus-visible { transform: none; }
}

/* ── Repli sans JavaScript ──
   Le panneau se déplie au focus de sa rubrique. Sur un pointeur fin, le survol
   suffit ; au doigt, l'appui sur le bouton lui donne le focus, ce qui revient
   au même. La règle vaut donc à toutes les largeurs, et n'est pas restreinte
   au survol : sur un téléphone sans JavaScript, le tiroir serait sinon une
   liste de boutons qui n'ouvrent rien.

   Le survol est normalement piloté par le script, qui retire l'attribut
   « hidden » et bascule « aria-expanded » ensemble. On ne force jamais
   l'affichage en CSS par dessus « hidden » quand le script est là : l'attribut
   masque aussi l'élément aux lecteurs d'écran, et le panneau serait alors
   visible à l'oeil mais absent pour l'assistance.

   Cette règle ne vaut QUE sans script : « html.ml-js-mega » est posée par
   assets/js/mega-menu.js. Avec le script, la laisser active lui ferait
   afficher, au focus, un panneau encore marqué « hidden », donc absent des
   lecteurs d'écran, et jamais recadré : centré sur une rubrique de bord, il
   sortait de la fenêtre. */
html:not(.ml-js-mega) .ml-mega-item-a-panneau:focus-within .ml-mega-panel[hidden] {
  display: block;
}

/* ═══════════════════════════════════════════════════════════════════════════
   PETIT DÉROULANT : une rubrique à sous-entrées, sans panneau de méga menu
   ═══════════════════════════════════════════════════════════════════════════

   Certaines rubriques du menu principal portent leurs sous-entrées à même ce
   menu (« Infos pratiques » et ses deux liens), sans qu'un panneau de méga menu
   soit relié à leur emplacement. Elles n'ouvrent pas un panneau pleine largeur,
   mais un petit déroulant : une liste verticale posée sous la rubrique, à la
   largeur de son contenu.

   La rubrique reste un bouton (voir inc/mega-menu.php), piloté par la même
   mécanique que les panneaux (ouverture au clic et au survol du pointeur fin,
   fermeture retardée, Échap, clic extérieur, recadrage dans la fenêtre). C'est
   un petit panneau, pas un second système.

   Il reste masqué par l'attribut « hidden », que seul le script retire : le
   style ne le montre jamais de sa propre autorité, sauf le repli sans script en
   fin de bloc, au focus de la rubrique. */
.ml-mega-deroulant {
  /* Rattrapage posé par le script quand le déroulant déborderait de la fenêtre,
     comme pour le panneau (recadrer() dans assets/js/mega-menu.js). Zéro par
     défaut : sans script, il reste aligné sous sa rubrique. */
  --ml-mega-decalage: 0px;

  position: absolute;
  top: 100%;
  inset-inline-start: 0;
  translate: var(--ml-mega-decalage) 0;
  z-index: 90;
  margin-top: var(--ml-space-xs);
  /* Largeur au contenu, bornée : ni plus étroite qu'un libellé confortable, ni
     plus large que la fenêtre. */
  inline-size: max-content;
  min-inline-size: 12rem;
  max-inline-size: min(20rem, calc(100vw - 2 * var(--ml-space-md)));
  background: var(--ml-bg);
  /* Le vocabulaire des surfaces posées du site : un liseré discret et l'ombre
     moyenne. Pas le contour accentué du panneau de méga menu, plus imposant :
     ce déroulant ne porte que quelques liens. */
  border: 1px solid var(--ml-border);
  border-radius: var(--ml-radius);
  box-shadow: var(--ml-shadow-md);
  padding: var(--ml-space-xs);
}

.ml-mega-deroulant[hidden] {
  display: none;
}

.ml-mega-deroulant-liste {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.ml-mega-deroulant-lien {
  display: block;
  padding: 8px 12px;
  border-radius: var(--ml-radius-sm);
  color: var(--ml-text);
  font-size: var(--ml-fs-base);
  transition: background-color 160ms var(--ml-ease), color 160ms var(--ml-ease);
}

/* Le survol et le focus prennent le violet très dilué du thème, et le texte le
   violet foncé : 11,3:1, le même vocabulaire que les liens des panneaux. */
.ml-mega-deroulant-lien:hover,
.ml-mega-deroulant-lien:focus-visible {
  background-color: var(--ml-accent-soft);
  color: var(--ml-accent-dark);
}

/* Le trait de focus reste visible en plus de la pastille : un lien atteint au
   clavier doit se distinguer d'un lien survolé. */
.ml-mega-deroulant-lien:focus-visible {
  outline: 2px solid var(--ml-accent);
  outline-offset: 2px;
}

/* ── L'INTERTITRE DU DÉROULANT ──
   Un repère non cliquable au milieu de la liste, avec son filet et sa pastille
   d'âge : « 18- » puis « Pour les moins de 18 ans » (demande de Marino, août
   2026). Il remplace la fenêtre modale qui reprenait ces mêmes formules dans un
   second écran.

   role="presentation" sur son élément de liste : ce n'est pas un article de la
   liste des liens, et le compter en ferait annoncer un de plus à la synthèse
   vocale. La pastille, elle, est purement décorative (aria-hidden) : le texte
   juste à côté dit déjà de quoi il s'agit, en toutes lettres. */
.ml-mega-deroulant-intertitre {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-block: 8px 2px;
  padding-block-end: 6px;
  padding-inline: 14px;
  /* LE FILET PASSE SOUS L'INTERTITRE, pas au dessus (demande de Marino).
     Au dessus, il coupait la liste avant le repère, qui se lisait alors comme
     un premier article du groupe du dessous plutôt que comme son titre. */
  border-block-end: 1px solid var(--ml-border);
  font-family: var(--ml-font-heading);
  font-size: var(--ml-fs-sm);
  font-weight: 700;
  color: var(--ml-text-mid);
}

.ml-mega-deroulant-badge {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-inline-size: 2.2em;
  padding: 2px 6px;
  border-radius: var(--ml-radius-pill);
  background: var(--ml-accent-soft);
  color: var(--ml-accent-dark);
  font-size: 0.85em;
  line-height: 1.2;
}

/* ── LA RUBRIQUE, DEVENUE UN LIEN, ET SON CHEVRON À CÔTÉ ──
   Le lien et le bouton sont deux éléments voisins dans le même <li> : c'est ce
   qui permet au clic de mener à la page et au chevron d'ouvrir le déroulant.
   Ils se collent l'un à l'autre pour se lire comme une seule rubrique, et le
   chevron garde une zone de touche confortable, puisque c'est le seul moyen
   d'ouvrir le déroulant au doigt.

   Les deux formes de rubrique sont concernées, celle à panneau comme celle à
   petit déroulant : toutes deux portent maintenant un lien suivi d'un chevron.

   flex-wrap, et le panneau en flex-basis: 100% : le panneau est le TROISIÈME
   enfant de ce <li>. Il est en position absolue la plupart du temps, donc hors
   du flux, mais pas toujours : sans script et sous 900px il repasse en statique
   pour se déplier sous sa rubrique. Il deviendrait alors une troisième colonne
   à côté du lien et du chevron. La base de 100 pour cent le renvoie à sa ligne
   dans tous les cas, sans avoir à deviner lequel s'applique. */
.ml-mega-item-deroulant,
.ml-mega-item-a-panneau {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
}

.ml-mega-item-deroulant > .ml-mega-deroulant,
.ml-mega-item-a-panneau > .ml-mega-panel {
  flex-basis: 100%;
}

.ml-mega-deroulant-rubrique {
  padding-inline-end: 4px;
}

.ml-mega-bouton--chevron {
  padding-inline: 6px;
  min-inline-size: 32px;
  min-block-size: 32px;
  justify-content: center;
}

/* SANS SCRIPT, LE CHEVRON DISPARAÎT. C'est le script, et lui seul, qui bascule
   « hidden » et « aria-expanded » : sans lui ce bouton ne fait rien, et le
   déroulant s'ouvre de toute façon au focus de la rubrique (règle plus bas) ou
   se déplie d'un bloc sous 900px. Un bouton inerte n'a rien à faire dans l'ordre
   de tabulation. */
html:not(.ml-js-mega) .ml-mega-bouton--chevron {
  display: none;
}

@media (prefers-reduced-motion: reduce) {
  .ml-mega-deroulant-lien {
    transition: none;
  }
}

/* Repli sans script : le déroulant s'ouvre au focus de sa rubrique, et seulement
   sans script. Avec le script, c'est lui qui retire « hidden » et bascule
   « aria-expanded » ensemble ; le forcer en CSS le rendrait visible à l'oeil
   mais absent des lecteurs d'écran, qui ignorent tout élément « hidden ». */
html:not(.ml-js-mega) .ml-mega-item-deroulant:focus-within .ml-mega-deroulant[hidden] {
  display: block;
}

/* ═══════════════════════════════════════════════════════════════════════════
   TIROIR DE NAVIGATION, SOUS 900px
   ═══════════════════════════════════════════════════════════════════════════

   Le conteneur « .ml-nav-tiroir » (identifiant « ml-mobile-menu », celui que
   le bouton du menu désigne par aria-controls) est transparent au dessus de
   900px : il ne fait qu'envelopper la barre de rubriques, sans rien changer.

   Sous 900px, il devient une couche plein écran, et la navigation se fait par
   piles qui glissent :

   - niveau 1 : la liste des rubriques (.ml-nav-links), en place ;
   - niveau 2 : le panneau d'une rubrique (.ml-mega-panel), posé par dessus,
     hors écran à droite, qui entre par la droite quand on ouvre la rubrique.

   Le niveau 1 ne disparaît pas, il glisse vers la gauche (classe
   « is-en-arriere », posée par le script) : deux plans qui se croisent, jamais
   deux affichages qui clignotent. Quand un niveau est sorti de l'écran, le
   script le rend inerte : on ne tabule pas dans le vide.

   Le mouvement est porté par « translate », jamais par « opacity » : rien ici
   n'est masqué par une opacité nulle, un script qui ne se charge pas ne peut
   donc laisser aucun élément invisible.
   ═══════════════════════════════════════════════════════════════════════════ */

/* L'en-tête d'un panneau (le retour et le nom de la rubrique) n'existe que
   dans le tiroir : au dessus de 900px, le panneau se pose sous sa rubrique, il
   n'a rien remplacé et il n'y a nulle part où revenir. */
.ml-mega-panel-tete {
  display: none;
}

/* LA BARRE DU TIROIR N'EXISTE QUE DANS LE TIROIR MOBILE OUVERT.

   Elle était masquée par une règle posée DANS le média « moins de 900px » :
   au dessus de cette largeur, plus aucune règle ne la visait, elle reprenait
   donc son affichage normal et le logo foncé apparaissait dans la barre de
   menu du bureau, à côté du vrai logo (constat de Marino).

   La règle de base vit donc ici, hors de tout média : masquée partout, et
   seule la règle du tiroir, plus spécifique et bornée au petit écran, la
   rallume. Sans JavaScript non plus elle n'apparaît pas, ce qui est juste :
   il n'y a alors aucun tiroir à fermer. */
.ml-tiroir-entete {
  display: none;
}

@media (max-width: 899.98px) {
  /* ── Les zones sûres du téléphone ──
     Encoche, coins arrondis, barre système du bas : posées une seule fois ici,
     reprises partout dans le tiroir et sur la barre fixe qui le coiffe (plus
     bas). Nulles tant que la balise meta de <head> ne porte pas
     « viewport-fit=cover » (voir header.php) : sans elle, env() renvoie
     toujours zéro sur iOS, et ces variables ne coûtent donc rien là où elles
     ne servent pas. */
  html.ml-js-mega {
    --ml-safe-t: env(safe-area-inset-top, 0px);
    --ml-safe-b: env(safe-area-inset-bottom, 0px);
    --ml-safe-l: env(safe-area-inset-left, 0px);
    --ml-safe-r: env(safe-area-inset-right, 0px);
  }

  /* ── La couche plein écran ──
     Un PLANCHER, jamais une hauteur fixe (demande de Marino) : le tiroir ne
     doit jamais être plus court qu'un écran, mais rien ne l'empêche d'être
     plus grand si son contenu le demande. Ses trois enfants (la barre d'en
     tête, la liste de rubriques, un panneau avancé) sont tous les trois en
     « position: absolute » : rien ne participe plus au flux normal pour
     pousser le tiroir plus haut que ce plancher, c'est la liste ou le panneau,
     bornés à sa taille, qui absorbent un éventuel surplus par leur propre
     défilement interne. Le plancher garantit seulement que le tiroir ne se
     referme jamais en une boîte plus petite que l'écran quand la liste est
     courte.

     Trois couches, chacune un progrès sur la précédente : un navigateur qui
     ne connaît pas une unité ignore silencieusement la ligne et garde la
     précédente.
       1. 100vh : le repli universel.
       2. 100svh : jamais 100vh seul, qui compte l'écran barres du navigateur
          RÉTRACTÉES, donc plus haut qu'il ne l'est au moment où le tiroir
          s'ouvre.
       3. 100dvh, et pas seulement 100svh : constaté par Marino en descendant
          dans une longue liste, la barre d'outils de Safari se rétracte au
          défilement, la fenêtre grandit d'autant, et 100svh, calé une fois
          pour toutes sur le plus petit des deux états, ne suivait pas : un
          vide apparaissait en bas du tiroir. « dvh » se recalcule à chaque
          changement de la fenêtre visible et grandit avec elle. */
  html.ml-js-mega .ml-nav-tiroir {
    position: fixed;
    inset-block-start: 0;
    inset-inline: 0;
    min-block-size: 100vh;
    min-block-size: 100svh;
    min-block-size: 100dvh;
    /* L'encoche ou les coins arrondis, en plus du rembourrage propre à
       chaque niveau : une réserve commune, jamais doublée par eux. */
    padding-inline: var(--ml-safe-l) var(--ml-safe-r);
    z-index: 120;
    /* Opaque, sans transparence : on doit pouvoir lire les liens, quelle que
       soit la page derrière. */
    background: var(--ml-bg);
    /* Les deux niveaux se déplacent à l'intérieur : ce qui sort par un bord ne
       doit pas produire de défilement de la page. */
    overflow: hidden;
    /* Hors écran par la droite au repos. Aucune opacité en jeu : le tiroir est
       simplement ailleurs. « visibility » l'ôte en plus du parcours de la
       tabulation tant qu'il est fermé, y compris pendant que le script pose
       l'inertie. */
    translate: 100% 0;
    visibility: hidden;
    transition: translate 320ms var(--ml-ease), visibility 0s linear 320ms;
  }

  html.ml-js-mega .ml-nav-tiroir.is-ouvert {
    translate: 0 0;
    visibility: visible;
    transition: translate 320ms var(--ml-ease), visibility 0s;
  }

  /* Tout le contenu du tiroir commence sous sa propre barre d'en-tête (juste
     plus bas) : la hauteur de la barre, plus l'espace qui la détache du haut
     de l'écran. Sans ce dégagement, la première rubrique passait sous elle.
     Mesuré, pas déduit. */
  html.ml-js-mega .ml-nav-tiroir {
    --ml-tiroir-degagement: calc(var(--ml-header-h) + var(--ml-space-sm) + var(--ml-safe-t));
  }

  /* ── Pourquoi le tiroir quitte l'en-tête de la page (assets/js/mega-menu.js,
     placerTiroir()) ──
     PIÈGE, trouvé en mesurant sur un vrai téléphone, pas en lisant : .ml-header
     porte « position: sticky » (voir main.css). Certains moteurs mobiles
     calculent alors mal le cadre de référence d'un descendant en
     « position: fixed » : au lieu de la fenêtre entière, le tiroir se calait
     sur la pilule de .ml-nav, plus étroite et plus courte qu'elle. À l'écran :
     une bande de la page derrière restait visible sur la droite et en bas.

     Le retirer de l'en-tête (le déplacer en enfant direct de <body> tant que
     l'écran est petit, comme les panneaux le sont déjà de .ml-nav-tiroir plus
     haut dans ce fichier) supprime la cause : plus aucun ancêtre collant entre
     le tiroir et la fenêtre.

     Sa barre d'en-tête à lui (juste en dessous) le suit dans ce déplacement :
     elle est un enfant DIRECT du tiroir, jamais de .ml-nav-links ni de
     .ml-mega-panel, les deux seuls éléments qui glissent en « translate » ici.
     Elle ne glisse donc jamais avec eux, et reste au dessus des deux quel que
     soit le niveau affiché (z-index 100, contre 90 pour un panneau avancé). */

  /* ── La barre d'en-tête du tiroir : le logo, à gauche, la croix de
     fermeture, à droite ──
     Demande de Marino : les deux vivent dans une seule barre FIXE en haut du
     tiroir, qui ne défile jamais avec la liste des rubriques et ne glisse
     jamais avec un sous-écran d'enfants.

     Le logo est un nouveau rendu (voir ml_mega_menu_tiroir_entete_html() dans
     inc/mega-menu.php), volontairement distinct de .ml-nav-logo : celui de la
     barre habituelle passe parfois en blanc pour se lire sur un haut de page
     sombre (voir main.css), une teinte invisible ici puisque cette barre est
     toujours claire. En portant sa propre classe, le logo du tiroir n'hérite
     jamais de ce filtre : il garde ses couleurs propres, toujours lisibles sur
     blanc, sans qu'aucun second fichier n'ait à être fourni.

     La croix, elle, n'est jamais dupliquée : c'est le MÊME bouton qu'avant
     l'ouverture (.ml-nav-burger), physiquement déplacé ici le temps que le
     tiroir est ouvert, puis remis à sa place dans la pilule à la fermeture
     (assets/js/mega-menu.js). */

  html.ml-js-mega .ml-nav-tiroir .ml-tiroir-entete {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--ml-space-sm);
    position: absolute;
    inset-block-start: 0;
    inset-inline: 0;
    /* Au dessus d'un panneau avancé (90) : elle reste visible quel que soit
       le sous-écran affiché sous elle. */
    z-index: 100;
    color: var(--ml-primary);
    block-size: var(--ml-tiroir-degagement);
    padding-inline: var(--ml-space-md);
    padding-block-start: var(--ml-safe-t);
    background: var(--ml-bg);
    border-block-end: 1px solid var(--ml-border);
  }

  .ml-tiroir-logo {
    display: block;
    line-height: 0;
    flex: 0 1 auto;
    min-inline-size: 0;
  }

  .ml-tiroir-logo-img {
    inline-size: auto;
    max-inline-size: 140px;
    max-block-size: calc(var(--ml-header-h) - 2 * var(--ml-space-xs) - 2px);
    block-size: auto;
    object-fit: contain;
  }

  /* Repli, si la cliente n'a pas encore réglé de logo : le nom de l'agence,
     dans le violet de marque, jamais un espace vide en tête du tiroir. */
  .ml-tiroir-logo-texte {
    display: block;
    font-family: var(--ml-font-heading);
    font-weight: 700;
    font-size: var(--ml-fs-base);
    color: var(--ml-accent);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  /* Le bouton du menu, déplacé ici le temps de l'ouverture : il garde sa
     forme (les trois traits qui deviennent une croix), seule sa position
     change. « margin-inline-start: auto » ne sert à rien de plus que
     « justify-content: space-between » sur la barre, mais protège la mise en
     page si le logo venait un jour à manquer et que la barre ne portait plus
     que la croix. */
  html.ml-js-mega .ml-nav-tiroir .ml-tiroir-entete .ml-nav-burger {
    flex: none;
    margin-inline-start: auto;
  }

  /* ── Niveau 1 : la liste des rubriques ──
     « position: absolute » et « inset: 0 », comme le panneau d'enfants plus
     bas : elle se cale ainsi tout entière sur le tiroir, à tout instant,
     jamais sur un pourcentage figé. C'est ce qui répond au constat de
     Marino : rétracter la barre d'outils de Safari en descendant dans la
     liste agrandit la fenêtre (dvh grandit avec elle), et sans ce calage la
     liste, elle, restait à son ancienne taille, laissant un vide en bas.

     Retirée du flux normal, elle ne compte plus dans le calcul de hauteur du
     tiroir (qui n'a alors plus AUCUN contenu en flux, et se limite donc très
     exactement à son plancher, voir plus haut) : les deux grandissent et
     rétrécissent ensemble, sans jamais se désaccorder.

     « overflow-y: auto » n'a de sens que sur un bloc à la taille bornée : ici
     bornée pile par le tiroir, qui l'est lui même par son plancher. Au delà,
     la liste défile sur elle même, sous la barre fixe, qui n'en fait pas
     partie et ne bouge donc jamais avec elle. */
  html.ml-js-mega .ml-nav-tiroir .ml-nav-links {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    position: absolute;
    inset: 0;
    overflow-y: auto;
    /* Le défilement du tiroir ne doit pas se propager à la page derrière lui,
       une fois le haut ou le bas de la liste atteint. */
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    /* La zone sûre du bas (barre système, coin arrondi) s'ajoute au
       rembourrage habituel : le dernier lien ne s'y perd jamais. */
    padding: var(--ml-tiroir-degagement) var(--ml-space-sm) calc(var(--ml-space-lg) + var(--ml-safe-b));
    transition: translate 320ms var(--ml-ease);
  }

  /* Le niveau 1 recule quand un panneau prend sa place. Il reste dans le DOM,
     et le script le rend inerte : il ne se retrouve jamais dans la tabulation
     alors qu'il est hors de l'écran. */
  html.ml-js-mega .ml-nav-tiroir.is-en-arriere .ml-nav-links {
    translate: -30% 0;
  }

  html.ml-js-mega .ml-nav-tiroir .ml-mega-item {
    position: static;
    border-block-end: 1px solid var(--ml-border);
  }

  /* ── LA RUBRIQUE À DEUX ZONES DANS LE TIROIR ──
     Depuis qu'une rubrique à page est un lien suivi d'un bouton chevron, la
     ligne du tiroir porte deux cibles : le nom, qui mène à la page, et le
     chevron, qui ouvre le niveau suivant. Le nom prend toute la place restante,
     le chevron garde une cible tactile pleine hauteur au bord.

     C'est le seul moyen d'ouvrir le déroulant au doigt, puisqu'il n'y a pas de
     survol : il ne doit jamais devenir un carré de huit pixels.

     LE DÉFAUT SIGNALÉ, à trois reprises avant d'être bien cerné : sur
     « Formules spéciales » (le plus long des libellés du menu), le chevron
     retombait seul sur sa propre ligne, alors que ses voisines, plus courtes,
     restaient correctes. La cause n'est pas un chemin de rendu distinct : les
     trois rubriques passent par la même fonction PHP (ml_mega_menu_commande())
     et portent les mêmes classes. C'est « min-inline-size », qui vaut « auto »
     par défaut sur un objet flexible : le lien refusait alors de rétrécir sous
     la largeur de son propre texte, et sur le libellé le plus long, cette
     largeur minimale plus les 56px réservés au chevron dépassaient l'écran.
     « flex-wrap: wrap », posé sur la ligne entière, rejetait alors le chevron
     entier à la ligne suivante plutôt que de laisser le texte se couper.

     « min-inline-size: 0 » l'autorise à rétrécir en dessous de cette largeur :
     le texte se coupe sur deux lignes s'il le faut, mais le chevron, lui, ne
     quitte plus jamais sa ligne, quelle que soit la longueur du libellé, y
     compris pour un futur intitulé plus long encore que celui-ci. */
  html.ml-js-mega .ml-nav-tiroir .ml-mega-deroulant-rubrique {
    inline-size: auto;
    min-inline-size: 0;
    flex: 1 1 auto;
  }

  html.ml-js-mega .ml-nav-tiroir .ml-mega-bouton--chevron {
    inline-size: auto;
    flex: none;
    min-inline-size: 56px;
    justify-content: flex-end;
    /* Un peu d'air à droite (demande de Marino) : le chevron léchait le bord du
       tiroir, alors que le libellé, lui, part d'une marge. Les deux bords de la
       ligne se répondent maintenant. La cible tactile ne perd rien, elle garde
       ses 56 pixels de large. */
    padding-inline-end: var(--ml-space-xs);
  }

  /* Base commune à tout lien ou bouton de rubrique dans le tiroir : couleur,
     taille, cible tactile. Qu'il soit seul sur sa ligne ou moitié d'une paire
     lien plus chevron, ces propriétés valent pour les deux. */
  html.ml-js-mega .ml-nav-tiroir .ml-mega-link,
  html.ml-js-mega .ml-nav-tiroir .ml-mega-bouton {
    /* Le texte du tiroir ne suit plus la couleur de la barre : le fond est
       toujours clair ici, même sur une page à haut de page sombre. */
    color: var(--ml-text);
    font-size: var(--ml-fs-lg);
    /* 56px de haut au minimum : la cible tactile recommandée. */
    min-block-size: 56px;
    padding-block: var(--ml-space-sm);
    /* La marge intérieure de la pilule de survol n'a pas lieu d'être ici : au
       doigt, il n'y a pas de survol, et la rubrique occupe déjà toute la
       largeur. Elle ne ferait que renfoncer le libellé par rapport au filet qui
       le souligne et aux titres de colonnes du panneau, qui partent tous du
       même bord. */
    padding-inline: 0;
    text-align: start;
    /* Presque droit, jamais la pilule aux bouts ronds du grand écran (demande
       de Marino) : une ligne de menu pleine largeur n'est pas un bouton, elle
       n'a pas à en avoir la forme. Le rayon hérité de la règle générale, plus
       haut dans ce fichier (var(--ml-radius-pill), pensée pour une pastille
       de survol étroite), s'y voyait comme un défaut d'affichage. */
    border-radius: 2px;
  }

  /* Un lien ou un bouton SEUL sur sa ligne (rubrique sans page : un bouton
     unique ; rubrique sans enfant : un lien seul) occupe toute la largeur, et
     pousse son propre contenu au bord droit.

     LE DÉFAUT D'ORIGINE était ici : cette règle, à spécificité égale et
     déclarée après celles de la paire lien plus chevron ci dessus, les
     emportait sur elles pour « inline-size ». Le lien d'une rubrique à page
     prenait alors 100% de la largeur à lui seul, et le chevron, qui partage
     pourtant le même élément parent, n'avait plus aucune place sur cette
     ligne. « :not() » exclut maintenant les deux moitiés d'une paire de cette
     règle, qui ne vaut donc plus que pour un lien ou un bouton réellement
     seul. */
  html.ml-js-mega .ml-nav-tiroir .ml-mega-link:not(.ml-mega-deroulant-rubrique),
  html.ml-js-mega .ml-nav-tiroir .ml-mega-bouton:not(.ml-mega-bouton--chevron) {
    inline-size: 100%;
    justify-content: space-between;
  }

  html.ml-js-mega .ml-nav-tiroir .ml-mega-bouton:hover,
  html.ml-js-mega .ml-nav-tiroir .ml-mega-link:hover {
    color: var(--ml-accent-dark);
  }

  /* Le chevron d'une rubrique du tiroir pointe vers la droite : il annonce un
     niveau qui arrive par la droite, pas un dépliage vers le bas. Il ne tourne
     donc plus à l'ouverture. */
  html.ml-js-mega .ml-nav-tiroir .ml-mega-chevron {
    rotate: -45deg;
    translate: 0 0;
  }
  html.ml-js-mega .ml-nav-tiroir .ml-mega-bouton[aria-expanded="true"] .ml-mega-chevron {
    rotate: -45deg;
    translate: 0 0;
  }

  /* ── Le petit déroulant dans le tiroir ──
     Pas de panneau qui glisse : les sous-entrées se déplient sous leur
     rubrique, en liste indentée, comme un sous-menu ordinaire. Le bouton reste
     un bouton de dépliage (aria-expanded), et le déroulant reste masqué par
     « hidden » tant que le script ne l'a pas ouvert.

     UN FOND DISTINCT (demande de Marino) : sans lui, ses enfants s'affichaient
     sur le même blanc que le reste du tiroir, seulement décalés d'un cran, et
     le lien de parenté avec leur rubrique ne se lisait pas. Ne concerne QUE ce
     déroulant, jamais un panneau de méga menu (« Langues », « Destinations ») :
     leurs enfants vivent dans un sous-écran séparé, la question d'un fond ne
     se pose pas pour eux.

     Un violet dilué à moitié, plus pâle encore que celui des liens survolés
     juste en dessous (--ml-accent-soft) : les deux doivent rester
     distinguables l'un de l'autre, sans quoi le survol ne se verrait plus.
     Sur ce fond très clair, le texte (--ml-text, presque noir) tient encore
     largement au dessus du seuil AA : ces liens sont du contenu, pas de la
     décoration. */
  html.ml-js-mega .ml-nav-tiroir .ml-mega-deroulant {
    position: static;
    inset: auto;
    translate: none;
    inline-size: auto;
    min-inline-size: 0;
    max-inline-size: none;
    margin: 0 0 var(--ml-space-xs);
    padding: 2px var(--ml-space-xs) var(--ml-space-xs);
    background: color-mix(in srgb, var(--ml-accent-soft) 55%, var(--ml-bg));
    border: 0;
    border-radius: var(--ml-radius-sm);
    box-shadow: none;
  }

  /* Repli pour les navigateurs sans color-mix() : le crème très pâle du site,
     moins parlant qu'une teinte violette mais toujours distinct du blanc qui
     l'entoure. */
  @supports not (background-color: color-mix(in srgb, red 50%, blue)) {
    html.ml-js-mega .ml-nav-tiroir .ml-mega-deroulant {
      background: var(--ml-bg-alt);
    }
  }

  html.ml-js-mega .ml-nav-tiroir .ml-mega-deroulant-liste {
    gap: 0;
    /* Les sous-entrées restent indentées sous leur rubrique, en plus du
       rembourrage du fond posé juste au dessus. */
    padding-inline-start: var(--ml-space-sm);
  }

  html.ml-js-mega .ml-nav-tiroir .ml-mega-deroulant-lien {
    display: flex;
    align-items: center;
    /* Cible tactile pleine. */
    min-block-size: 48px;
    font-size: var(--ml-fs-base);
  }

  /* Le chevron d'une rubrique à déroulant pointe vers le bas et pivote vers le
     haut au dépliage : c'est un dépliage sur place, pas un niveau qui arrive par
     la droite. Il se distingue ainsi du chevron des rubriques à panneau.

     Accroché à l'élément de liste, et non plus à une classe du bouton : depuis
     que la rubrique à page est un lien suivi d'un chevron, les deux formes de
     rubrique partagent le même bouton. C'est le <li> qui dit laquelle des deux
     on regarde. */
  html.ml-js-mega .ml-nav-tiroir .ml-mega-item-deroulant .ml-mega-bouton .ml-mega-chevron {
    rotate: 45deg;
    translate: 0 -2px;
  }
  html.ml-js-mega .ml-nav-tiroir .ml-mega-item-deroulant .ml-mega-bouton[aria-expanded="true"] .ml-mega-chevron {
    rotate: -135deg;
    translate: 0 2px;
  }

  /* ── Niveau 2 : le panneau, posé par dessus le niveau 1 ──
     PIÈGE trouvé en mesurant la cascade, pas en la lisant.

     La règle de base du panneau (hors tiroir, plus haut dans ce fichier) le
     positionne avec des propriétés LOGIQUES : « inset-inline-start: 50% ».
     Ici, le raccourci physique « inset: 0 » couvre bien les quatre bords à
     une spécificité plus forte, mais le bord de départ n'est vraiment
     ramené au même bord que si le moteur applique à la lettre la
     résolution logique/physique du standard entre les deux écritures. On ne
     s'y fie pas : la même propriété logique est reposée ici, en clair, à une
     spécificité qui l'emporte déjà. Plus aucune ambiguïté, quel que soit le
     moteur : le panneau colle aux quatre bords du tiroir, jamais centré à
     moitié hors champ comme sous sa forme de grand écran (c'est exactement
     ce qui donnait, au clic sur mobile, un panneau « décalé bien trop », dont
     seul un petit bout restait visible).

     La largeur ne dépasse jamais celle du tiroir (max-inline-size: 100%, et
     non plus « none ») : filet de sécurité si un contenu venait à pousser
     dessus, avec le débordement horizontal coupé (overflow-x) pour ne
     jamais laisser un pixel de plus s'échapper sur le côté.

     --ml-mega-cols et --ml-mega-col-w ne servent qu'au calcul de largeur du
     grand écran (la piste des liens à côté de la mise en avant, voir plus
     haut) : neutralisés ici, ils ne pourront plus jamais faire déborder le
     panneau si une future règle mobile venait un jour à les lire par
     erreur. */
  html.ml-js-mega .ml-nav-tiroir .ml-mega-panel {
    position: absolute;
    inset: 0;
    inset-block-start: 0;
    inset-inline-start: 0;
    inline-size: 100%;
    max-inline-size: 100%;
    min-inline-size: 0;
    /* Le centrage sous la rubrique et son rattrapage n'ont plus lieu d'être. */
    --ml-mega-decalage: 0px;
    --ml-mega-cols: 0;
    --ml-mega-col-w: 0px;
    background: var(--ml-bg);
    border: 0;
    border-radius: 0;
    box-shadow: none;
    margin-top: 0;
    overflow-y: auto;
    overflow-x: hidden;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    /* Le navigateur garde le défilement vertical, et rend l'horizontal au
       script. Sans cela, un balayage horizontal partirait en défilement natif,
       les évènements « pointermove » cesseraient d'être annulables, et le geste
       de retour ne pourrait plus être suivi. C'est ce qui fait cohabiter le
       balayage et le défilement dans le même panneau. */
    touch-action: pan-y;
    /* Entre par la droite. Le panneau reste marqué « hidden » tant que le
       script ne l'a pas ouvert : le style ne le montre jamais de sa propre
       autorité. */
    translate: 100% 0;
    transition: translate 320ms var(--ml-ease);
  }

  html.ml-js-mega .ml-nav-tiroir .ml-mega-panel.is-avancee {
    translate: 0 0;
  }

  html.ml-js-mega .ml-nav-tiroir .ml-mega-panel-inner {
    display: flex;
    flex-direction: column;
    min-block-size: 100%;
    padding: 0 var(--ml-space-sm) var(--ml-space-lg);
  }

  /* L'en-tête du panneau reste visible pendant qu'on fait défiler la liste :
     le retour ne doit jamais demander de remonter tout en haut. Sa marge haute
     dégage la croix de fermeture, et son fond opaque passe dessous : le contenu
     qui défile ne vient jamais se lire derrière elle.

     La croix reste au dessus (z-index 130 sur le bouton du menu), le titre de
     la rubrique passe dessous : ils ne se rencontrent pas. */
  html.ml-js-mega .ml-nav-tiroir .ml-mega-panel-tete {
    display: flex;
    align-items: center;
    gap: var(--ml-space-xs);
    position: sticky;
    inset-block-start: 0;
    /* AU DESSUS DE TOUT CE QUI DÉFILE SOUS ELLE (constat de Marino : des
       éléments passaient légèrement par dessus le bouton de retour). Elle était
       à 1, ce qui ne suffit pas dès qu'un enfant du panneau se positionne à son
       tour. Elle reste sous la barre du tiroir, qui porte la croix et vaut 100 :
       les deux ne se disputent donc jamais la place. */
    z-index: 50;
    background: var(--ml-bg);
    border-block-end: 1px solid var(--ml-border);
    margin-inline: calc(-1 * var(--ml-space-sm));
    padding-inline: var(--ml-space-sm);
    padding-block-start: var(--ml-tiroir-degagement);
  }

  .ml-mega-retour {
    display: inline-flex;
    align-items: center;
    gap: var(--ml-space-xs);
    font-family: var(--ml-font-heading);
    font-size: var(--ml-fs-base);
    font-weight: 600;
    color: var(--ml-accent-dark);
    background: none;
    border: 0;
    cursor: pointer;
    min-block-size: 56px;
    padding-inline: 0 var(--ml-space-xs);
  }

  .ml-mega-retour-fleche {
    inline-size: 9px;
    block-size: 9px;
    border-inline-start: 2px solid currentColor;
    border-block-end: 2px solid currentColor;
    rotate: 45deg;
  }

  .ml-mega-panel-titre {
    font-family: var(--ml-font-heading);
    font-weight: 700;
    font-size: var(--ml-fs-lg);
    color: var(--ml-primary);
    /* Le nom de la rubrique est déjà annoncé par le bouton de retour
       (screen-reader-text) : ce titre est un repère visuel, il ne doit pas être
       lu deux fois. D'où aria-hidden dans le HTML. */
    margin-inline-start: auto;
  }

  /* Dans le tiroir, le corps du panneau prend toute la hauteur restante
     (flex: 1) : le « Voir tout », qui le suit, se retrouve donc toujours tout
     en bas, apres les liens et apres la carte. C'est le dernier element du
     panneau, et le pouce le trouve la ou il est deja pose.

     La cible tactile fait 56px, comme les rubriques du niveau 1. */
  html.ml-js-mega .ml-nav-tiroir .ml-mega-lien-rubrique {
    margin-block-start: var(--ml-space-md);
    min-block-size: 56px;
  }

  html.ml-js-mega .ml-nav-tiroir .ml-mega-panel-corps {
    /* Les colonnes deviennent une liste à plat, et le corps du panneau occupe
       toute la hauteur qui reste : c'est ce qui permet à la carte, plus bas, de
       se pousser au fond avec une marge automatique quand la liste est courte,
       et de rester à la suite des liens quand elle est longue. */
    display: flex;
    flex-direction: column;
    gap: var(--ml-space-md);
    flex: 1;
    padding-block-start: var(--ml-space-sm);
  }

  /* LES COLONNES S'ÉTALENT SUR TOUTE LA LARGEUR (demande de Marino) : celle de
     gauche part du bord gauche du contenu, celle de droite finit au bord droit.
     Elles se serraient au milieu, chacune à la largeur de son plus long nom de
     pays, et le tiroir paraissait deux fois trop large pour ce qu'il portait.

     « flex: 1 1 0 » plutôt que « space-between » seul : deux colonnes qui se
     repoussent aux extrémités laisseraient un trou au milieu, alors que ce
     qu'on veut, c'est qu'elles se PARTAGENT la largeur. Chaque lien prend alors
     toute sa colonne, chevron au bord, comme au premier niveau.

     Le retour à la ligne reste permis : un panneau à trois colonnes ou plus ne
     tiendrait pas sur un téléphone, et deux de ses colonnes seraient illisibles
     avant de déborder. */
  html.ml-js-mega .ml-nav-tiroir .ml-mega-panel-colonnes {
    flex-direction: row;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: flex-start;
    gap: var(--ml-space-md);
  }

  html.ml-js-mega .ml-nav-tiroir .ml-mega-colonne {
    flex: 1 1 0;
    min-inline-size: 0;
  }

  /* La grille de cartes n'a pas de sens dans le tiroir : tout y est deja en
     liste verticale pleine largeur, et deux cartes cote a cote sur un telephone
     ne laisseraient plus la place au libelle. Une seule piste, donc, et une
     cible tactile pleine. Les cartes ne redeviennent pas des liens : elles
     gardent leur fond et leur fleche, ce qui evite un troisieme rendu a
     maintenir pour le meme contenu. */
  html.ml-js-mega .ml-nav-tiroir .ml-mega-cartes {
    grid-template-columns: minmax(0, 1fr);
    /* Dans le tiroir, chaque carte fait sa hauteur : etirer les rangees a parts
       egales gonflerait celles qui n'ont pas de description. */
    grid-auto-rows: auto;
    block-size: auto;
    gap: var(--ml-space-xs);
  }

  /* La carte s'aplatit en une ligne : le drapeau, puis le nom, puis la fleche.
     La description, si elle existe, passe dessous et n'occupe que la deuxieme
     piste : elle se cale sous le nom, pas sous le drapeau.

     Plus de filet : il cernait une carte creme sur un tiroir blanc, ou sans lui
     elle se serait fondue. La carte porte maintenant le degrade de marque, elle
     se detache toute seule, et un liseret pale sur un fond sombre ne serait plus
     qu'une salissure. L'ombre reste coupee : le tiroir est une liste a plat,
     rien n'y flotte. */
  html.ml-js-mega .ml-nav-tiroir .ml-mega-vignette {
    display: grid;
    grid-template-columns: auto 1fr;
    align-items: center;
    column-gap: 0.45em;
    min-block-size: 56px;
    box-shadow: none;
    border: 0;
  }

  /* Aucun drapeau (page ordinaire, adresse saisie a la main) : le nom prend les
     deux pistes, il ne reste pas de colonne vide a sa gauche. */
  html.ml-js-mega .ml-nav-tiroir .ml-mega-vignette-titre {
    grid-column: 1 / -1;
    font-size: var(--ml-fs-lg);
  }

  html.ml-js-mega .ml-nav-tiroir .ml-mega-drapeau + .ml-mega-vignette-titre {
    grid-column: 2;
  }

  html.ml-js-mega .ml-nav-tiroir .ml-mega-vignette-texte {
    grid-column: 2;
  }

  html.ml-js-mega .ml-nav-tiroir .ml-mega-vignette .ml-mega-drapeau {
    grid-row: 1;
    grid-column: 1;
    align-self: center;
    margin: 0;
  }

  html.ml-js-mega .ml-nav-tiroir .ml-mega-colonne-titre {
    /* Le titre d'une colonne devient un intertitre de la liste à plat. */
    font-size: var(--ml-fs-sm);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--ml-text-mid);
  }

  /* La colonne de continuation ne réserve plus de hauteur de titre : à plat,
     rien n'a besoin d'être aligné sur une colonne voisine. */
  html.ml-js-mega .ml-nav-tiroir .ml-mega-colonne-titre--vide {
    display: none;
  }

  /* LE LIEN PREND TOUTE LA LARGEUR DU TIROIR, son chevron poussé au bord
     (demande de Marino). Il se serrait sur la longueur de son libellé, si bien
     que « Pays de Galles » et « Irlande » n'avaient ni la même largeur ni leur
     chevron au même endroit : deux colonnes irrégulières là où le premier
     niveau, lui, aligne tout au bord droit.

     C'est aussi ce qui agrandit la cible : on touche la ligne entière, pas le
     seul mot. */
  html.ml-js-mega .ml-nav-tiroir .ml-mega-lien {
    font-size: var(--ml-fs-base);
    min-block-size: 44px;
    padding-block: 10px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    inline-size: 100%;
    /* Le chevron est posé en absolu par la règle de base : il doit repasser
       dans le flux pour que « space-between » puisse le pousser. */
    position: relative;
    padding-inline-end: var(--ml-space-sm);
  }

  html.ml-js-mega .ml-nav-tiroir .ml-mega-lien::after {
    position: static;
    flex: none;
    margin-inline-start: var(--ml-space-sm);
  }

  /* Le chevron du lien reste visible au doigt : il n'y a pas de survol pour le
     révéler, et un lien qui ne montre rien au repos paraît inerte. */
  html.ml-js-mega .ml-nav-tiroir .ml-mega-lien::after {
    opacity: 1;
    inset-block-start: 50%;
    translate: 0 -50%;
  }

  /* La description se colle au lien qu'elle décrit. Les liens du tiroir sont
     plus hauts (cible tactile), et l'espace ainsi créé plaçait la description à
     égale distance du lien du dessus et de celui du dessous : elle semblait
     appartenir aux deux. */
  html.ml-js-mega .ml-nav-tiroir .ml-mega-lien-description {
    margin-block: -8px 6px;
  }

  /* ── La carte d'appel à l'action, au fond du panneau ──
     Le client la veut sur le tiroir, alors qu'elle n'y était pas : plus large
     (toute la largeur du contenu) et moins haute qu'en grand écran, une carte
     paysage. Même mécanisme, même image mise en avant, même bouton : rien n'est
     réinventé, seules les proportions changent.

     ELLE SUIT LE DERNIER LIEN, elle ne tombe plus au fond de l'écran. Un
     « margin-block-start: auto » l'y collait, ce qui creusait un grand vide
     entre la liste et elle dès que la liste était courte, et c'est le cas des
     deux panneaux de méga menu (constat de Marino). Une simple marge la place
     à la suite de ce qui précède, comme n'importe quel bloc. */
  html.ml-js-mega .ml-nav-tiroir .ml-mega-carte {
    display: flex;
    margin-block-start: var(--ml-space-md);
    min-block-size: 0;
    /* Un rapport paysage, plutôt qu'une hauteur figée : la carte garde ses
       proportions quelle que soit la largeur du téléphone. Le contenu peut la
       faire grandir (min-block-size sur le texte), jamais rétrécir. */
    aspect-ratio: 16 / 9;
    padding: var(--ml-space-sm);
  }

  html.ml-js-mega .ml-nav-tiroir .ml-mega-carte-titre {
    font-size: var(--ml-fs-base);
  }

  /* La description de la carte tient sur une ligne ou deux : au delà, elle
     pousse le bouton hors de la carte paysage. */
  html.ml-js-mega .ml-nav-tiroir .ml-mega-carte-texte {
    margin-block-end: var(--ml-space-xs);
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    overflow: hidden;
  }

  html.ml-js-mega .ml-nav-tiroir .ml-mega-carte-lien {
    padding: 6px var(--ml-space-sm);
  }

  /* ── Sans script : liste dépliée, rien de mort ──
     Le tiroir n'existe pas. La liste passe sous le logo, sur toute la largeur
     de la barre, et chaque rubrique est un bouton qui prend le focus à
     l'appui : la règle de repli « :focus-within » plus haut ouvre alors son
     panneau, en bloc, dans le flux. Le méga menu n'y est plus qu'une liste,
     ce qui suffit.

     Le bouton du menu, lui, disparaît : sans script il n'ouvre rien, et un
     bouton qui ne fait rien ment sur ce qu'il est. */
  html:not(.ml-js-mega) .ml-nav {
    flex-wrap: wrap;
    border-radius: var(--ml-radius-lg);
  }

  html:not(.ml-js-mega) .ml-nav-burger {
    display: none;
  }

  html:not(.ml-js-mega) .ml-nav-tiroir {
    flex-basis: 100%;
  }

  html:not(.ml-js-mega) .ml-nav-links {
    display: flex;
    flex-direction: column;
    /* .ml-mega-menu centre ses rubriques : en colonne, cela les réduirait à la
       largeur de leur texte, et la cible tactile ne ferait plus la largeur de
       la barre. */
    align-items: stretch;
    gap: 0;
    padding-block-start: var(--ml-space-xs);
  }

  html:not(.ml-js-mega) .ml-mega-item {
    border-block-start: 1px solid var(--ml-border);
  }

  html:not(.ml-js-mega) .ml-mega-link,
  html:not(.ml-js-mega) .ml-mega-bouton {
    inline-size: 100%;
    justify-content: space-between;
    min-block-size: 48px;
  }

  html:not(.ml-js-mega) .ml-mega-panel {
    position: static;
    inset-inline-start: auto;
    translate: none;
    top: auto;
    min-inline-size: 0;
    max-inline-size: none;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    margin-top: 0;
  }

  html:not(.ml-js-mega) .ml-mega-panel-inner {
    padding: var(--ml-space-sm) 0 var(--ml-space-sm) var(--ml-space-md);
  }

  /* Le petit déroulant suit la même logique : sans script, il se déplie dans le
     flux de la barre au focus de sa rubrique, plutôt que de flotter par dessus
     les rubriques suivantes. */
  html:not(.ml-js-mega) .ml-mega-deroulant {
    position: static;
    inset: auto;
    translate: none;
    inline-size: auto;
    min-inline-size: 0;
    max-inline-size: none;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    margin-top: 0;
    padding: var(--ml-space-xs) 0 var(--ml-space-sm) var(--ml-space-md);
  }

  html:not(.ml-js-mega) .ml-mega-panel-colonnes {
    flex-direction: column;
    gap: var(--ml-space-sm);
  }

  /* Sans script, le panneau se deplie dans le flux de la barre : deux cartes
     cote a cote y seraient trop etroites pour leur libelle. Une seule piste. */
  html:not(.ml-js-mega) .ml-mega-cartes {
    grid-template-columns: minmax(0, 1fr);
    grid-auto-rows: auto;
    block-size: auto;
  }

  html:not(.ml-js-mega) .ml-mega-carte {
    display: none;
  }
}

/* ── La barre d'administration de WordPress, au dessus du tiroir ──
   Elle est fixe au dessus de 600px : un tiroir qui partirait de zéro passerait
   dessous, et la personne connectée ne pourrait plus quitter la page. Le tiroir
   commence donc sous elle, et perd d'autant de sa hauteur. À 600px et moins,
   elle défile avec la page (position: absolute) et libère le haut de la
   fenêtre : le tiroir repart de zéro. Ce sont les mêmes régimes que ceux de
   .ml-header dans main.css, aux mêmes seuils. */
@media (min-width: 783px) and (max-width: 899.98px) {
  html.ml-js-mega body.admin-bar .ml-nav-tiroir {
    inset-block-start: 32px;
    min-block-size: calc(100vh - 32px);
    min-block-size: calc(100svh - 32px);
    min-block-size: calc(100dvh - 32px);
  }
}

@media (min-width: 601px) and (max-width: 782px) {
  html.ml-js-mega body.admin-bar .ml-nav-tiroir {
    inset-block-start: 46px;
    min-block-size: calc(100vh - 46px);
    min-block-size: calc(100svh - 46px);
    min-block-size: calc(100dvh - 46px);
  }
}

/* Le mouvement latéral est un confort, pas une information : sous
   prefers-reduced-motion, les niveaux changent d'un coup, et la navigation par
   piles continue de fonctionner à l'identique. */
@media (prefers-reduced-motion: reduce) {
  .ml-mega-chevron {
    transition: none;
  }

  html.ml-js-mega .ml-nav-tiroir,
  html.ml-js-mega .ml-nav-tiroir.is-ouvert,
  html.ml-js-mega .ml-nav-tiroir .ml-nav-links,
  html.ml-js-mega .ml-nav-tiroir .ml-mega-panel {
    transition: none;
  }

  /* Le niveau 1 ne recule plus : il est simplement recouvert par le panneau,
     qui est opaque et occupe tout l'écran. */
  html.ml-js-mega .ml-nav-tiroir.is-en-arriere .ml-nav-links {
    translate: none;
  }
}

/* Le bouton du menu passe en croix quand le tiroir est ouvert : le même bouton
   ouvre et ferme, il doit dire lequel des deux il fait. */
.ml-nav-burger[aria-expanded="true"] {
  /* Au dessus du tiroir, qui est en position fixe : c'est la seule chose de la
     barre qui reste visible une fois le tiroir ouvert. */
  position: relative;
  z-index: 130;
}

.ml-nav-burger .ml-burger-bar {
  transition: translate 240ms var(--ml-ease), rotate 240ms var(--ml-ease), opacity 240ms var(--ml-ease);
}

/* Les trois traits suivent normalement la couleur de la barre (currentColor).
   Sur une page à haut de page sombre, cette couleur est blanche : la croix
   deviendrait invisible sur le fond clair du tiroir. Une fois le tiroir ouvert,
   elle prend donc la couleur du texte, quelle que soit la page. Contraste sur
   le fond du tiroir : 14,9:1. */
.ml-nav-burger[aria-expanded="true"] .ml-burger-bar {
  background: var(--ml-text);
}

.ml-nav-burger[aria-expanded="true"] .ml-burger-bar:nth-child(1) {
  translate: 0 7px;
  rotate: 45deg;
}

.ml-nav-burger[aria-expanded="true"] .ml-burger-bar:nth-child(2) {
  opacity: 0;
}

.ml-nav-burger[aria-expanded="true"] .ml-burger-bar:nth-child(3) {
  translate: 0 -7px;
  rotate: -45deg;
}

@media (prefers-reduced-motion: reduce) {
  .ml-nav-burger .ml-burger-bar {
    transition: none;
  }
}

/* Colonne de continuation : le titre est invisible mais occupe sa place,
   pour que les liens des deux colonnes restent alignes. */
.ml-mega-colonne-titre--vide {
  visibility: hidden;
}

/* Colonne d'un panneau compose a plat : aucun titre, donc aucun espace a
   reserver au dessus des liens. */
.ml-mega-colonne--sans-titre .ml-mega-colonne-liens {
  margin-block-start: 0;
}

/* ── Le drapeau des destinations ──
   Deduit du contenu vise par l'entree de menu (fiche Pays, ou pays parent
   d'une fiche Ville), jamais saisi : voir ml_mega_menu_drapeau() dans
   inc/mega-menu.php.

   Il est purement decoratif (aria-hidden) : c'est un emoji, donc du texte, et
   Windows le dessine en deux lettres de pays plutot qu'en couleur. Le libelle
   ecrit a cote porte seul l'information.

   Aucune largeur n'est reservee : une entree sans drapeau (une page ordinaire)
   ne montre aucune case vide et son libelle commence exactement la ou
   commencent ceux de ses voisines. Le drapeau pousse simplement le texte de sa
   propre largeur, comme le ferait un mot.

   La marge est en em : elle suit la taille du libelle, plus grand dans le
   tiroir que dans le panneau. Le drapeau se cale sur la ligne de base du texte
   qu'il precede, il ne flotte pas au dessus. */
.ml-mega-drapeau {
  display: inline-block;
  flex: 0 0 auto;
  margin-inline-end: 0.45em;
  /* L'emoji porte des hauteurs de ligne fantaisistes selon les systemes : une
     interligne fixe evite qu'un lien orne d'un drapeau soit plus haut que son
     voisin sans drapeau, et que la colonne se mette a bouger d'une ligne a
     l'autre. */
  line-height: 1;
  font-size: 1em;
}


/* ── La bulle de salutation dans la carte d'une langue ──
   « Hi », « Hallo », « Hola », « Ciao » : la salutation de la langue, dessinee
   a la main, dans sa carte.

   Ce n'est PAS un filigrane. Le trace est violet sur fond blanc, et a quatre
   vingt pour cent il se lit franchement : c'est un element de la carte, la
   langue qui dit bonjour, pas une ombre derriere le texte. Il est donc compose
   avec le nom, pas cache dessous.

   Elle se pose en bas a droite, la ou la carte est vide : le nom et l'accroche
   occupent le haut a gauche, la fleche le coin haut droit. Rien ne se croise.

   Elle deborde legerement du bord : une bulle entiere, posee bien au milieu de
   son coin, se lirait comme une vignette collee. Le conteneur la rogne, et ce
   debordement est ce qui la fait appartenir a la carte au lieu d'y flotter.

   Decorative, donc aria-hidden dans le balisage : le nom de la langue, ecrit a
   cote, porte seul l'information. ── */
.ml-mega-vignette-bulle {
  position: absolute;
  inset-block-end: -10%;
  inset-inline-end: -4%;
  z-index: 0;
  inline-size: 58%;
  max-inline-size: 132px;
  block-size: auto;
  opacity: 0.8;
  rotate: -6deg;
  pointer-events: none;
  transition: opacity 320ms var(--ml-ease), rotate 320ms var(--ml-ease),
              scale 320ms var(--ml-ease);
}

/* Au survol, elle se redresse et s'affirme : la carte repond. */
.ml-mega-vignette:hover .ml-mega-vignette-bulle,
.ml-mega-vignette:focus-within .ml-mega-vignette-bulle {
  opacity: 1;
  rotate: -2deg;
  scale: 1.06;
}

/* Tout ce qui se lit passe au dessus de la bulle ET au dessus du calque cliquable
   du lien : le nom de la langue ne doit jamais se lire par dessus le trace, la ou
   l'encre est la plus dense, ni disparaitre sous la zone de clic.

   Le texte du lien est eleve par un span pose DEDANS
   (.ml-mega-vignette-libelle), et non par un conteneur autour. La difference
   n'est pas cosmetique : un conteneur positionne autour du lien deviendrait le
   cadre de reference de son pseudo element, qui se recadrerait dessus au lieu de
   couvrir la carte. La carte ne serait alors cliquable que sur son titre. C'est
   precisement le defaut qui etait signale.

   Le drapeau, l'accroche et la fleche ne sont pas des ancetres du lien : ils
   peuvent, eux, etre positionnes sans rien casser. Ils ne captent aucun clic,
   n'ayant pas de fond (la fleche porte en plus pointer-events: none). */
.ml-mega-vignette-libelle,
.ml-mega-vignette-texte,
.ml-mega-vignette .ml-mega-drapeau {
  position: relative;
  z-index: 1;
}

/* Le drapeau et l'accroche sont au dessus du calque cliquable : sans cette
   regle, un clic pose dessus tomberait sur eux, et la carte ne s'ouvrirait pas.
   Ni l'un ni l'autre n'a de raison de recevoir un clic (le drapeau est
   decoratif, l'accroche est du texte mort), ils le laissent donc passer. Le
   libelle du lien, lui, garde ses clics : c'est le lien. */
.ml-mega-vignette-texte,
.ml-mega-vignette .ml-mega-drapeau {
  pointer-events: none;
}

/* La fleche vit maintenant dans le lien, a cote du nom. Elle monte au meme
   etage que lui : sans cela, le calque cliquable du lien (pseudo element
   positionne, donc peint au dessus du contenu non positionne) passerait par
   dessus elle. Il est transparent, elle resterait visible, mais rien ne
   garantit qu'il le reste toujours. Elle ne capte aucun clic malgre cet etage
   (pointer-events: none plus haut) : la carte entiere reste une seule cible. */
.ml-mega-vignette-fleche {
  position: relative;
  z-index: 1;
}

/* La carte reserve la place de la bulle : sans ce rembourrage, une accroche un
   peu longue viendrait courir sur le dessin. */
.ml-mega-vignette:has(.ml-mega-vignette-bulle) {
  padding-block-end: calc(var(--ml-space-sm) + 1.4rem);
}

/* ── La bulle quand la carte s'aplatit en une ligne, sous 900px ──
   Sur grand ecran, la bulle est POSEE SOUS le texte, dans le coin bas droit
   d'une carte en colonne : le rembourrage du bas ci dessus lui reserve sa bande,
   et rien ne se croise.

   Sous 900px, la carte devient une ligne (le nom a gauche, la bulle a droite),
   que ce soit dans le tiroir ou dans le repli sans script. Le texte n'arrive
   plus AU DESSUS de la bulle, il arrive A COTE, et il lui rentrait dedans : sur
   la carte « Anglais », « Canada, Australie » se lisait en travers du ventre de
   la bulle. Le ventre est blanc, l'accroche l'est presque : les deux derniers
   mots disparaissaient. Le defaut existait deja, mais il ne se voyait pas tant
   que la bulle etait blanche sur du creme, c'est a dire invisible.

   La bulle prend donc une largeur fixe, et la carte lui reserve exactement cette
   largeur a sa droite. Fixe, et non plus un pourcentage : on ne peut reserver
   proprement que ce dont on connait la taille. Le rembourrage du bas, lui,
   redevient ordinaire : il ne reserve plus la place de rien.

   Cette regle est ecrite APRES celle du dessus, et non dans le bloc du tiroir
   plus haut : a specificite egale, c'est la derniere qui gagne, et une requete
   de media n'ajoute aucune specificite. Placee plus haut, elle aurait ete
   silencieusement annulee par le rembourrage de grand ecran. */
@media (max-width: 899.98px) {
  .ml-mega-vignette-bulle {
    inline-size: 104px;
    max-inline-size: 104px;
  }

  .ml-mega-vignette:has(.ml-mega-vignette-bulle) {
    padding-inline-end: calc(104px + var(--ml-space-xs));
    padding-block-end: var(--ml-space-sm);
  }
}

@media (prefers-reduced-motion: reduce) {
  .ml-mega-vignette-bulle {
    transition: none;
  }
  .ml-mega-vignette:hover .ml-mega-vignette-bulle,
  .ml-mega-vignette:focus-within .ml-mega-vignette-bulle {
    rotate: -6deg;
    scale: 1;
  }
}

/* ── LES ACTIONS DE LA BARRE : contacter, puis rechercher ────────────────────
   Demande de Marino : la barre n'avait qu'un bouton de recherche à droite, et
   la page Contact ne s'atteignait qu'en dépliant une rubrique. Deux boutons
   voisins, de même hauteur et de même arrondi, rendent le bord droit lisible.

   La marge automatique vit ICI, plus sur le bouton de recherche : .ml-nav est
   en « space-between », et une marge portée par un seul des deux boutons aurait
   écarté les deux au lieu de les pousser ensemble. */
.ml-nav-actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-inline-start: auto;
}

/* Le bouton de contact : PLEIN ET VIOLET, là où la recherche n'est qu'un
   contour. Il était blanc bordé de gris, et il ne se voyait pas (constat de
   Marino) : sur une barre blanche, un bouton blanc n'est qu'un mot encadré.
   Celui ci est l'action de la barre, l'autre est un outil, et le violet dit
   lequel est lequel.

   Le sens d'usage de la marque est respecté : texte blanc sur fond violet,
   jamais l'inverse (voir la section « Design tokens » du CLAUDE.md). */
.ml-nav-contact {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.55rem 1.05rem;
  border: 1px solid var(--ml-accent);
  border-radius: var(--ml-radius-pill);
  background: var(--ml-accent);
  color: #fff;
  font-size: var(--ml-fs-sm);
  font-weight: 600;
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  transition: background-color 200ms var(--ml-ease), color 200ms var(--ml-ease),
    border-color 200ms var(--ml-ease);
}

.ml-nav-contact:hover,
.ml-nav-contact:focus-visible {
  background: var(--ml-accent-dark);
  border-color: var(--ml-accent-dark);
  color: #fff;
}

/* LE VIOLET « QUAND C'EST POSSIBLE », et ici ça ne l'est pas. Sur un haut de
   page sombre, tant que la barre reste transparente, le fond derrière est déjà
   violet ou photographique : un bouton violet s'y noierait, exactement le défaut
   qu'on vient de corriger. Il passe donc en blanc plein, qui ressort sur tout.

   LE SÉLECTEUR EST EXACTEMENT CELUI DE main.css pour le texte blanc du logo et
   des liens, et celui du survol du bouton de recherche : trois conditions
   écrites différemment se seraient désaccordées au premier changement. */
html.ml-js-scroll body.ml-has-dark-header .ml-header:not(.is-scrolled) .ml-nav-contact {
  background: #fff;
  border-color: #fff;
  color: var(--ml-primary);
}

html.ml-js-scroll body.ml-has-dark-header .ml-header:not(.is-scrolled) .ml-nav-contact:hover,
html.ml-js-scroll body.ml-has-dark-header .ml-header:not(.is-scrolled) .ml-nav-contact:focus-visible {
  background: var(--ml-accent-soft);
  border-color: var(--ml-accent-soft);
  color: var(--ml-accent-dark);
}

/* SOUS 900px, LE BOUTON CONTACT DISPARAIT (demande de Marino). La barre du
   menu déplié n'a que la place du logo, de la loupe et du bouton du menu : un
   quatrième élément la faisait déborder. Contact n'est pas perdu pour autant,
   il est dans le menu lui même, et la mascotte de Linguine reste posée en bas
   de chaque écran.

   Le retirer plutôt que le rétrécir : un bouton qui ne tient qu'en rognant ses
   marges finit par se coller à son voisin, et deux cibles collées se ratent
   toutes les deux au pouce. */
@media (max-width: 899.98px) {
  .ml-nav-contact {
    display: none;
  }
}

/* ── TROIS ZONES : logo à gauche, rubriques au centre, actions à droite ──────
   Demande de Marino. La barre était en « space-between » : les rubriques se
   posaient là où le hasard des largeurs les laissait, jamais au milieu, et le
   centre se déplaçait dès qu'un libellé changeait.

   Une grille de trois colonnes, dont les deux extérieures sont égales, met les
   rubriques au centre RÉEL de la barre, quelles que soient la longueur du logo
   et celle des boutons. C'est la seule façon de le tenir : avec des marges
   automatiques, le centre dépend encore de ce qu'il y a de chaque côté.

   Au dessus de 900px seulement : en dessous, le tiroir devient une couche
   plein écran et la barre n'a plus que le logo et le bouton du menu. */
@media (min-width: 900px) {
  .ml-nav {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
  }

  .ml-nav-logo {
    justify-self: start;
  }

  .ml-nav-tiroir {
    justify-self: center;
  }

  .ml-nav-actions {
    justify-self: end;
    /* La marge automatique n'a plus lieu d'être : c'est la grille qui place,
       et deux mécanismes de placement sur le même élément finissent toujours
       par se contredire. */
    margin-inline-start: 0;
  }
}

/* ══ LE TIROIR DANS UNE FENÊTRE MODALE NATIVE ═══════════════════════════════
   Demande de Marino, après trois correctifs qui n'ont pas refermé le défaut :
   « reconstruis cette zone pour que ça fonctionne ».

   LE POINT DÉCISIF, c'est que le décalage ne se reproduisait PAS en mode mobile
   sur un ordinateur, seulement sur son iPhone. Ce n'était donc pas une erreur de
   mise en page, mais une différence de moteur : un élément en « position: fixed »
   se cale sur la fenêtre de mise en page, et iOS ne la calcule pas comme un
   navigateur de bureau dès que quelque chose déborde de la page, qu'un ancêtre
   est collant, transformé ou filtré. Chercher lequel de ces cas s'applique,
   c'est chasser un symptôme.

   Une fenêtre modale native n'a pas ce problème, et c'est la seule chose qui la
   rend intéressante ici : le navigateur la sort de la page pour la peindre dans
   une couche à part, au dessus de tout. Elle ne dépend plus d'aucun ancêtre,
   d'aucun débordement, d'aucune transformation. Le défaut ne peut pas revenir
   par une autre porte, parce qu'il n'y a plus de porte.

   La fenêtre elle même ne peint RIEN : pas de fond, pas de bordure, pas de
   marge. Elle n'est qu'un cadre de la taille de l'écran, et c'est le tiroir
   qu'elle contient qui garde toute son apparence. */
.ml-tiroir-dialogue {
  position: fixed;
  inset: 0;
  inline-size: 100%;
  max-inline-size: 100%;
  block-size: 100%;
  max-block-size: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  overflow: hidden;
}

.ml-tiroir-dialogue::backdrop {
  background: rgba(30, 10, 42, 0.4);
}

/* DANS LA FENÊTRE, LE TIROIR NE SE POSITIONNE PLUS LUI MÊME. Il était en
   « fixed » pour se caler sur l'écran ; la fenêtre le fait désormais pour lui,
   et mieux. Le laisser en « fixed » ici, ce serait remettre exactement la
   propriété dont on cherche à se passer. */
/* LE SÉLECTEUR PORTE « html.ml-js-mega », ET CE N'EST PAS DE LA COQUETTERIE.

   La règle qui pose le tiroir en « fixed » sur petit écran s'écrit
   « html.ml-js-mega .ml-nav-tiroir » : deux classes ET un type, donc plus
   spécifique que « .ml-tiroir-dialogue .ml-nav-tiroir », qui n'a que deux
   classes. Ma première version perdait donc la cascade en silence, et le tiroir
   restait en « fixed » à l'intérieur de la fenêtre modale.

   C'est ce que le relevé posé à l'écran a montré, chiffres à l'appui : le
   tiroir mesurait « pos=fixed », et ses deux enfants placés en absolu se
   retrouvaient à 248 pixels À GAUCHE de lui. Un élément fixe à l'intérieur
   d'une couche supérieure n'a pas de cadre de référence fiable sur iOS : ses
   descendants absolus se calent sur un cadre calculé avant la promotion, et
   plus rien ne les remet en place tant qu'un geste ne force pas le recalcul.
   Tout le symptôme est là, y compris la correction au balayage.

   Dans la fenêtre, le tiroir n'a plus AUCUNE raison d'être fixe : c'est la
   fenêtre qui tient l'écran. Il redevient donc un bloc positionné ordinaire, et
   ses enfants retrouvent un cadre de référence normal. */
html.ml-js-mega .ml-tiroir-dialogue .ml-nav-tiroir {
  position: absolute;
  inset: 0;
  inline-size: auto;
  max-inline-size: none;
  /* Sa translation d'entrée et de sortie n'est PAS touchée : c'est elle qui
     fait glisser le tiroir hors de l'écran avant que la fenêtre ne se ferme,
     trois cents millisecondes plus tard. */
}

/* ══ iOS : LES DEUX NIVEAUX NE GLISSENT PLUS, ILS SE REMPLACENT ══════════════
   Demande de Marino, après cinq correctifs qui n'ont pas refermé le défaut :
   « reprends de fond en comble, propose un autre fonctionnement pour le même
   résultat visuel ».

   CE QUI EST COMMUN À TOUTES LES VERSIONS QUI ONT ÉCHOUÉ : les deux niveaux
   glissent en « translate ». Le tiroir a été sorti de son ancêtre collant, puis
   passé en fenêtre modale, puis rendu non fixe, la page a cessé d'être figée,
   une remise en page a été forcée : le décalage est resté. Le seul élément qui
   n'a jamais bougé, c'est la transformation.

   Et le dernier indice de Marino la désigne : un micro défilement VERTICAL
   corrige un décalage HORIZONTAL. La géométrie était juste, mesurée à zéro sur
   les trois éléments en jeu ; c'est la couche graphique produite par la
   transformation qui était peinte au mauvais endroit, et seul un défilement la
   forçait à se repeindre.

   ON RETIRE DONC LA TRANSFORMATION, pas ses symptômes. Le panneau ne glisse
   plus par dessus la liste : il la remplace. Aucune couche graphique n'est
   créée, il n'y a donc plus rien à mal peindre.

   Le résultat visuel est le même à l'arrivée, seule l'entrée change : le
   panneau apparaît au lieu d'entrer par la droite. Un fondu très court le rend
   moins brutal, sans créer de couche persistante. Si le glissement manque, il
   pourra revenir une fois la stabilité confirmée, et autrement qu'en
   transformant un conteneur plein écran. */
@media (max-width: 899.98px) {
  html.ml-js-mega .ml-tiroir-dialogue .ml-nav-links,
  html.ml-js-mega .ml-tiroir-dialogue .ml-mega-panel {
    translate: none;
    transform: none;
    transition: none;
  }

  /* Le niveau 1 s'efface quand un panneau prend sa place. « display » et non
     « visibility » : un élément seulement invisible garde sa hauteur, et le
     tiroir se retrouverait avec une zone de défilement deux fois trop longue. */
  html.ml-js-mega .ml-tiroir-dialogue .ml-nav-tiroir.is-en-arriere .ml-nav-links {
    display: none;
  }

  /* Le panneau n'existe à l'écran que lorsqu'il est au premier plan. Sans cette
     règle, il resterait affiché pendant les trois cents millisecondes qui
     séparent le retour de la remise à « hidden ». */
  html.ml-js-mega .ml-tiroir-dialogue .ml-mega-panel {
    display: none;
  }

  html.ml-js-mega .ml-tiroir-dialogue .ml-mega-panel.is-avancee {
    display: block;
  }

  @media (prefers-reduced-motion: no-preference) {
    html.ml-js-mega .ml-tiroir-dialogue .ml-mega-panel.is-avancee {
      animation: ml-tiroir-panneau-apparait 160ms ease-out;
    }
  }
}

@keyframes ml-tiroir-panneau-apparait {
  from { opacity: 0; }
  to   { opacity: 1; }
}
