/* =========================================================================
   ESDI — habillage du thème
   Reprend l'identité du site Astro : dégradés de marque, cartes arrondies,
   mode sombre, apparitions au défilement.

   Ce qui n'est PAS repris, volontairement : les halos flous décoratifs et le
   défilement horizontal épinglé. Sur le site Astro, 85 flous cumulés sur la
   page d'accueil dépassaient la limite mémoire d'un onglet Safari, qui
   abandonnait alors le rendu de zones entières — d'où les pages blanches
   constatées sur iPhone. Voir sites/esdi-pro/charte.md.

   CHARTE — pourquoi le dégradé « brand-deep » existe (theme.json, gradients)
   Le dégradé de marque « brand » démarre au turquoise #3fbecc. Or le blanc
   #ffffff sur ce turquoise ne donne que 2,22:1, sous le seuil WCAG de 4,5:1 :
   du texte blanc y est donc illisible. « brand-deep »
   (linear-gradient(135deg, #164d8f 0%, #1b5aa8 100%)) reprend la moitié
   profonde du même dégradé et devient LE fond des sections à texte blanc.
   Le turquoise reste réservé aux filets, puces, icônes et fonds de boutons
   à texte sombre.
   ========================================================================= */

:root {
  /* Courbes d'animation. « ease-out » natif est trop mou : l'élément flotte.
     Celle-ci démarre vite et se pose net — c'est ce qui rend une transition
     de 200 ms perçue comme instantanée. La seconde sert au mouvement qui
     reste à l'écran (glissement, morphing), jamais aux entrées. */
  --esdi-sortie:   cubic-bezier(0.23, 1, 0.32, 1);
  --esdi-mouvement: cubic-bezier(0.77, 0, 0.175, 1);

  --esdi-turquoise: #3fbecc;
  --esdi-bleu: #1b5aa8;
  --esdi-degrade: linear-gradient(135deg, #3fbecc 0%, #1b5aa8 100%);
  --esdi-surface: #f8fafc;
  --esdi-bordure: rgb(15 23 42 / 0.08);
  --esdi-rayon: 1rem;

  /* --- Échelle d'ombres -------------------------------------------------
     Trois marches, dépensées PAR RÔLE et non stampées partout. Une ombre
     unique posée sur chaque bloc aplatit la hiérarchie : plus rien ne
     ressort, puisque tout ressort autant.

       repos   — la carte au repos. Volontairement à la limite du visible :
                 elle pose l'objet sur la page, elle ne le décolle pas.
       levee   — réservée à l'élément survolé ou au bloc principal d'une
                 section. C'est la seule marche qui a le droit de porter.
       ancrage — le bloc posé sur une surface déjà teintée, où l'ombre doit
                 dire « posé sur » et non « flottant au-dessus ».

     Chaque ombre porte un décalage vertical ET un flou : un halo coloré
     sans décalage n'est pas de la profondeur, c'est de la décoration. */
  --esdi-ombre-repos: 0 1px 2px rgb(15 23 42 / 0.04),
                      0 4px 16px -6px rgb(15 23 42 / 0.08);
  --esdi-ombre-levee: 0 2px 4px rgb(15 23 42 / 0.05),
                      0 18px 40px -12px rgb(15 23 42 / 0.18);
  --esdi-ombre-ancrage: 0 1px 3px rgb(15 23 42 / 0.06);

  /* Anciens noms conservés : des patterns déjà écrits s'y réfèrent, et une
     variable morte ne produit aucune erreur visible — juste une ombre qui
     disparaît sans prévenir. */
  --esdi-ombre: var(--esdi-ombre-repos);
  --esdi-ombre-forte: var(--esdi-ombre-levee);

  /* --- Anneau de focus ---------------------------------------------------
     CALCULÉ, pas supposé : un indicateur de focus doit atteindre 3:1 contre
     ce qui l'entoure. Le turquoise #3fbecc ne donne que 2,22:1 sur blanc et
     2,12:1 sur la surface #f8fafc — il ÉCHOUE comme couleur d'anneau en
     mode clair. Le bleu profond #164d8f y donne 8,43:1 sur blanc et 8,05:1
     sur la surface : c'est lui qui porte le focus sur fond clair.
     Le turquoise reste réservé aux filets, puces et icônes. */
  --esdi-focus: #164d8f;
  --esdi-focus-epaisseur: 3px;
  --esdi-focus-ecart: 3px;
}

/* --- Mode sombre --------------------------------------------------------
   Piloté par une classe sur <html>, posée avant le rendu pour éviter le
   clignotement, et mémorisée dans le navigateur.

   Le mode sombre reçoit le même soin que le clair, pas un repli. Les ombres
   en particulier : les supprimer purement et simplement — ce que faisait la
   version précédente avec « --esdi-ombre: none » — retirait au survol des
   cartes tout retour visuel de profondeur, le déplacement de 4 px restant
   le seul indice. Sur fond sombre une ombre noire ne se voit pas ; la
   profondeur s'y obtient par un liseré clair sur l'arête supérieure et une
   ombre portée franchement plus dense. */
html.esdi-sombre {
  --esdi-surface: #202021;
  --esdi-bordure: rgb(255 255 255 / 0.10);

  --esdi-ombre-repos: inset 0 1px 0 rgb(255 255 255 / 0.05),
                      0 2px 8px -4px rgb(0 0 0 / 0.55);
  --esdi-ombre-levee: inset 0 1px 0 rgb(255 255 255 / 0.09),
                      0 18px 40px -12px rgb(0 0 0 / 0.75);
  --esdi-ombre-ancrage: inset 0 1px 0 rgb(255 255 255 / 0.04);

  /* Sur #1a1a1b le bleu #164d8f tomberait à 1,9:1 : invisible. Le jeton
     primary-on-dark #7dd6e0 y donne 10,41:1. */
  --esdi-focus: #7dd6e0;

  background-color: #1a1a1b;
}
html.esdi-sombre body { background-color: #1a1a1b; color: #e2e8f0; }

/* Le texte secondaire vaut #475569 en clair : un gris sombre, illisible sur
   fond noir (2,1:1). WordPress ne redéfinit pas les jetons de palette selon
   le thème, il faut donc le faire ici, une fois, pour tout le site — sinon
   chaque paragraphe secondaire disparaît en mode sombre. */
html.esdi-sombre {
  --wp--preset--color--contrast:   #f1f5f9;
  --wp--preset--color--contrast-2: #a8b8c8;
  --wp--preset--color--accent:     #7dd6e0;
  --wp--preset--color--base:       #1a1a1b;
  --wp--preset--color--base-2:     #202021;
}
html.esdi-sombre .has-contrast-2-color { color: #a8b8c8 !important; }
html.esdi-sombre .has-contrast-color   { color: #f1f5f9 !important; }
html.esdi-sombre .has-accent-color     { color: #7dd6e0 !important; }
html.esdi-sombre .has-base-background-color { background-color: #1a1a1b !important; }
html.esdi-sombre h1, html.esdi-sombre h2,
html.esdi-sombre h3, html.esdi-sombre h4 { color: #f8fafc; }
html.esdi-sombre .esdi-carte { background: rgb(255 255 255 / 0.05); }
html.esdi-sombre .has-base-2-background-color { background-color: #202021 !important; }

/* Liens courants en mode sombre.
   theme.json peint les liens en « accent » #1b5aa8 : 2,55:1 sur #1a1a1b,
   très en dessous du seuil de 4,5:1. Sans cette règle, tout lien du corps
   de texte devenait illisible dès le mode sombre actif — le cas n'était
   traité que dans trois patterns, section par section. Le jeton
   primary-on-dark donne 10,41:1. */
html.esdi-sombre a { color: var(--wp--preset--color--primary-on-dark, #7dd6e0); }

/* --- Surfaces rendues par le navigateur ---------------------------------
   Elles ne sont pas dessinées par le thème mais s'affichent dedans.
   Laissées par défaut, la sélection de texte et les contrôles natifs
   appartiennent à aucune charte. */
::selection { background: rgb(63 190 204 / 0.28); color: #0f172a; }
html.esdi-sombre ::selection { background: rgb(125 214 224 / 0.30); color: #f1f5f9; }

/* Indique au navigateur quelles teintes employer pour ce qu'il dessine
   lui-même : barres de défilement, cases à cocher, curseur de saisie. */
:root { color-scheme: light; accent-color: #1b5aa8; }
html.esdi-sombre { color-scheme: dark; accent-color: #7dd6e0; }

/* --- Anneau de focus, règle de base --------------------------------------
   :focus-visible et non :focus : le navigateur ne pose l'anneau que lorsque
   l'utilisateur navigue au clavier, jamais après un clic à la souris.

   C'est le filet de sécurité du thème : tout élément focusable reçoit un
   anneau, y compris ceux qu'aucune règle plus précise ne vise — liens du
   corps de texte, champs du formulaire de contact rendus par l'extension,
   éléments ajoutés plus tard. Le focus n'est JAMAIS retiré sans
   remplacement. */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: var(--esdi-focus-epaisseur) solid var(--esdi-focus);
  outline-offset: var(--esdi-focus-ecart);
  border-radius: .35rem;
}

/* Les navigateurs sans :focus-visible (Safari antérieur à 15.4) doivent
   conserver un anneau. @supports sert ici de test d'existence du sélecteur :
   sans cette précaution, n'écrire que :focus-visible reviendrait à supprimer
   purement et simplement le focus sur ces navigateurs. */
@supports not selector(:focus-visible) {
  :where(a, button, input, select, textarea, summary, [tabindex]):focus {
    outline: var(--esdi-focus-epaisseur) solid var(--esdi-focus);
    outline-offset: var(--esdi-focus-ecart);
  }
}

/* --- Texte en dégradé de marque ----------------------------------------
   Le texte est d'abord peint en bleu de marque. Le découpage du dégradé
   n'est appliqué que là où background-clip:text est réellement honoré :
   sans cette garde, un moteur qui ignore la propriété rendait le texte
   transparent, donc invisible. */
.esdi-degrade-texte {
  color: #1b5aa8;
}

@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .esdi-degrade-texte {
    background: var(--esdi-degrade);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
  }
}

/* --- Cartes -------------------------------------------------------------
   Repos discret, survol affirmé : c'est l'écart entre les deux marches de
   l'échelle d'ombres qui fait lire le mouvement, pas le déplacement seul.

   Les transitions ne portent que sur transform, box-shadow et les couleurs.
   Jamais sur width/height/top/left : ces propriétés forcent le navigateur à
   recalculer la mise en page à chaque image, et l'animation saccade dès que
   la page est un peu chargée. transform est composé par le processeur
   graphique, sans repasser par la mise en page. */
.esdi-carte {
  background: #fff;
  border: 1px solid var(--esdi-bordure);
  border-radius: var(--esdi-rayon);
  box-shadow: var(--esdi-ombre-repos);
  padding: 1.75rem;
  height: 100%;
  transition: transform .2s var(--esdi-sortie),
              box-shadow .2s var(--esdi-sortie),
              border-color .2s var(--esdi-sortie);
}
@media (hover: hover) and (pointer: fine) { .esdi-carte:hover {
  transform: translateY(-4px);
  box-shadow: var(--esdi-ombre-levee);
  border-color: rgb(63 190 204 / 0.45);
} }

/* Une carte qui contient un lien doit réagir quand ce lien reçoit le focus
   clavier : sans :focus-within, l'utilisateur au clavier traverse la grille
   sans qu'aucune carte ne se distingue, alors qu'elle se soulève à la
   souris. L'anneau reste posé sur le lien lui-même, qui est la vraie cible. */
.esdi-carte:focus-within {
  transform: translateY(-4px);
  box-shadow: var(--esdi-ombre-levee);
  border-color: var(--esdi-focus);
}

/* --- Boutons ------------------------------------------------------------
   Le survol assombrit le fond (theme.json, primary-dark) et soulève de 2 px.
   Le focus clavier ne rejoue pas ce soulèvement : il doit être reconnaissable
   comme un état distinct du survol, pas comme sa copie. */
.wp-block-button__link {
  transition: background-color .2s var(--esdi-sortie),
              border-color .2s var(--esdi-sortie),
              color .2s var(--esdi-sortie),
              transform .15s var(--esdi-sortie),
              box-shadow .2s var(--esdi-sortie);
}
@media (hover: hover) and (pointer: fine) {
  .wp-block-button__link:hover {
    transform: translateY(-2px);
    box-shadow: var(--esdi-ombre-levee);
  }
}

/* Pression : le bouton s'enfonce. C'est le retour le plus élémentaire —
   l'interface confirme qu'elle a senti le doigt. Sans lui, un tap sur
   téléphone ne produit rien de visible avant le changement de page. */
.wp-block-button__link:active,
.esdi-services__lien:active,
.esdi-carte a:active,
.wp-block-navigation a:active {
  transform: scale(.97);
  transition-duration: .1s;
}

/* L'anneau se pose à l'extérieur du bouton, dont le rayon est celui défini
   dans theme.json (0.75rem). Le bouton ne bouge pas : au clavier, un élément
   qui se déplace au moment où il reçoit le focus est désorientant. */
.wp-block-button__link:focus-visible {
  outline: var(--esdi-focus-epaisseur) solid var(--esdi-focus);
  outline-offset: var(--esdi-focus-ecart);
  border-radius: .75rem;
  transform: none;
}

/* État désactivé : le bouton doit cesser de promettre une action. Ni
   soulèvement, ni ombre, ni curseur de clic. */
.wp-block-button__link[disabled],
.wp-block-button__link[aria-disabled="true"] {
  opacity: .55;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}

/* Bouton au trait, sur fond CLAIR. La restriction :not() est indispensable :
   sans elle, cette règle — chargée après les styles des patterns — imposait
   son bleu aux boutons posés sur un fond de marque, où il devenait invisible.
   Les sections à fond profond définissent leur propre variante en blanc. */
.wp-block-button.is-style-outline .wp-block-button__link:not(
  .esdi-cta__bouton-secondaire .wp-block-button__link
) {
  border: 2px solid var(--esdi-turquoise);
  color: var(--esdi-bleu);
  background: transparent;
}

/* Sur tout fond de marque, le bouton au trait passe en blanc. */
.has-brand-gradient-background .wp-block-button.is-style-outline .wp-block-button__link,
.has-brand-deep-gradient-background .wp-block-button.is-style-outline .wp-block-button__link,
.esdi-cta .wp-block-button.is-style-outline .wp-block-button__link,
.esdi-ia__produit .wp-block-button.is-style-outline .wp-block-button__link {
  border-color: rgb(255 255 255 / 0.65);
  color: #ffffff;
  background: transparent;
}
.has-brand-gradient-background .wp-block-button.is-style-outline .wp-block-button__link:hover,
.has-brand-deep-gradient-background .wp-block-button.is-style-outline .wp-block-button__link:hover,
.esdi-cta .wp-block-button.is-style-outline .wp-block-button__link:hover,
.esdi-ia__produit .wp-block-button.is-style-outline .wp-block-button__link:hover {
  border-color: #ffffff;
  background: rgb(255 255 255 / 0.14);
  color: #ffffff;
}
/* Le bouton contour n'a pas de fond à assombrir : son survol se lit sur le
   trait et sur un fond turquoise très dilué. Il reste un bouton secondaire,
   il ne doit pas se mettre à peser autant que le principal. */
.wp-block-button.is-style-outline .wp-block-button__link:hover {
  border-color: var(--esdi-bleu);
  background: rgb(63 190 204 / 0.10);
  box-shadow: none;
}
html.esdi-sombre .wp-block-button.is-style-outline .wp-block-button__link { color: #7dd6e0; }
html.esdi-sombre .wp-block-button.is-style-outline .wp-block-button__link:hover {
  border-color: #7dd6e0;
  background: rgb(125 214 224 / 0.12);
}

/* --- Chiffres clés ------------------------------------------------------
   Même précaution que pour .esdi-degrade-texte : couleur de repli d'abord,
   découpage du dégradé seulement s'il est pris en charge. Un compteur animé
   invisible est une perte sèche d'information. */
.esdi-chiffre {
  font-size: clamp(2rem, 5vw, 3rem);
  font-weight: 800;
  line-height: 1;
  color: #1b5aa8;
}

@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .esdi-chiffre {
    background: var(--esdi-degrade);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
  }
}

/* --- Apparition au défilement -------------------------------------------
   Transition CSS pilotée par IntersectionObserver : aucune bibliothèque, et
   le fil principal n'est jamais bloqué. */
/* L'apparition est le seul mouvement long du thème, et c'est délibéré : les
   états d'interface (survol, focus) répondent en 150-250 ms parce qu'ils
   répondent à un geste, tandis qu'une entrée de section accompagne le
   défilement et se lit sur une durée plus ample.

   La courbe est une décélération marquée — cubic-bezier(0.16, 1, 0.3, 1) —
   et non « ease » : l'élément arrive vite puis se pose, au lieu de flotter.
   Le déplacement reste modeste (16 px) : au-delà, l'œil suit l'objet plutôt
   que de lire le texte. */
/* Le contenu est VISIBLE par défaut. L'animation ne s'applique que sous
   .esdi-anime, classe posée par le JavaScript une fois qu'il a vérifié
   pouvoir la piloter.

   L'inverse — masquer d'abord, révéler ensuite — a été essayé et retiré :
   il suffit d'une seule défaillance (script bloqué, observateur qui ne se
   déclenche pas, capture d'écran avant défilement, lecteur de flux) pour que
   des sections entières restent invisibles. C'est précisément ce qui s'est
   produit ici : 28 éléments sur 32 étaient bloqués à opacité nulle. Une page
   doit être lisible au repos, avant tout défilement. */
.esdi-anime .esdi-apparait:not(.est-visible) {
  opacity: 0;
  transform: translateY(16px);
}
.esdi-apparait {
  transition: opacity .3s var(--esdi-sortie),
              transform .3s var(--esdi-sortie);
  /* « auto » évite d'immobiliser de la mémoire graphique sur des dizaines
     d'éléments — le point qui faisait tomber Safari iOS sur la version Astro. */
  will-change: auto;
}
.esdi-apparait.est-visible { opacity: 1; transform: none; }

/* --- En-tête ------------------------------------------------------------ */
.esdi-entete {
  position: sticky;
  top: 0;
  z-index: 100;
  background: rgb(255 255 255 / 0.92);
  border-bottom: 1px solid var(--esdi-bordure);
}
html.esdi-sombre .esdi-entete { background: rgb(26 26 27 / 0.92); }

/* Le flou d'arrière-plan n'est appliqué qu'à partir du bureau : c'est un
   effet coûteux sur téléphone, pour un gain visuel très faible. */
@media (min-width: 1024px) {
  .esdi-entete { backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); }
}

/* --- Bandeau d'accueil -------------------------------------------------- */
.esdi-hero {
  background:
    radial-gradient(60% 60% at 20% 10%, rgb(63 190 204 / 0.12) 0%, transparent 60%),
    radial-gradient(50% 50% at 85% 25%, rgb(27 90 168 / 0.10) 0%, transparent 60%),
    var(--esdi-surface);
}
html.esdi-sombre .esdi-hero { background: var(--esdi-surface); }

/* --- Respect du réglage système -----------------------------------------
   « Réduire les animations » est un réglage d'accessibilité : pour une
   partie des utilisateurs, le mouvement à l'écran déclenche des vertiges ou
   des migraines. Il ne s'agit donc pas d'une préférence esthétique.

   La règle universelle ci-dessous neutralise TOUT ce que pilote le CSS,
   y compris les règles écrites plus tard et celles des patterns. Trois
   points la complètent :
     — animation-iteration-count, sans quoi une animation en boucle
       continuerait de tourner, seulement plus vite ;
     — scroll-behavior, le défilement fluide étant lui aussi du mouvement ;
     — .esdi-apparait, qui part d'une opacité nulle : neutraliser sa
       transition sans rétablir son état final laisserait la page vide.
   Le JavaScript refait le même test de son côté (esdi.js) : le CSS ne peut
   brider que ce qu'il pilote lui-même. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto !important; }

  /* On ne coupe QUE le déplacement. Les fondus d'opacité et les changements
     de couleur restent : ils n'induisent pas de vertige et leur suppression
     rendrait chaque survol brutal — l'inverse de ce que demande le réglage. */
  *, *::before, *::after {
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
  }
  .esdi-apparait,
  .esdi-carte, .esdi-carte:hover,
  .wp-block-button__link, .wp-block-button__link:hover, .wp-block-button__link:active,
  .esdi-icone, a:hover .esdi-icone,
  .esdi-bascule:active {
    transform: none !important;
    transition-property: opacity, color, background-color, border-color, box-shadow !important;
  }

  /* Les apparitions au défilement s'affichent d'emblée, sans transition. */
  .esdi-apparait { opacity: 1 !important; transform: none !important; }

  /* Les états de survol qui déplacent un objet sont supprimés, pas
     accélérés : un saut instantané de 4 px reste un mouvement. */
  .esdi-carte:hover,
  .esdi-carte:focus-within,
  .wp-block-button__link:hover { transform: none; }

  /* Les filets qui se déplient au survol s'affichent en entier ou pas du
     tout, sans balayage. */
  .esdi-entete .wp-block-navigation a::after { transition: none; }
}

/* --- Bascule clair / sombre --------------------------------------------- */
.esdi-bascule {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  margin-left: .75rem;
  border: 1px solid var(--esdi-bordure);
  border-radius: .75rem;
  background: transparent;
  color: inherit;
  cursor: pointer;
  transition: background-color .2s var(--esdi-sortie),
              border-color .2s var(--esdi-sortie),
              color .2s var(--esdi-sortie);
}
/* Survol : le trait prend la couleur de marque et un fond turquoise très
   dilué apparaît. La bascule est un bouton d'icône sans libellé — il lui
   faut un retour visuel plus net qu'un simple changement de bordure. */
.esdi-bascule:hover {
  border-color: var(--esdi-turquoise);
  background: rgb(63 190 204 / 0.12);
  color: var(--esdi-bleu);
}
html.esdi-sombre .esdi-bascule:hover {
  background: rgb(125 214 224 / 0.14);
  color: var(--wp--preset--color--primary-on-dark, #7dd6e0);
}

/* Focus clavier : anneau du thème, distinct du survol qui, lui, ne teinte
   que le fond et le trait. Le rayon reprend celui du bouton. */
.esdi-bascule:focus-visible {
  outline: var(--esdi-focus-epaisseur) solid var(--esdi-focus);
  outline-offset: var(--esdi-focus-ecart);
  border-radius: .75rem;
}

/* Enfoncement : retour tactile bref, sur transform uniquement. */
.esdi-bascule:active { transform: scale(.94); }
@media (prefers-reduced-motion: reduce) {
  .esdi-bascule:active { transform: none; }
}

.esdi-bascule svg { display: block; }

/* Lune en thème clair, soleil en thème sombre. */
.esdi-bascule .esdi-icone-soleil { display: none; }
html.esdi-sombre .esdi-bascule .esdi-icone-lune { display: none; }
html.esdi-sombre .esdi-bascule .esdi-icone-soleil { display: block; }

/* --- Navigation ---------------------------------------------------------
   Le survol était peint en turquoise #3fbecc : 2,22:1 sur le fond blanc de
   l'en-tête. Un libellé de menu qui devient MOINS lisible au moment où on le
   vise est un contresens. Le survol passe donc au bleu profond (8,43:1) et
   la couleur de marque revient en filet sous le libellé, où elle n'a pas de
   texte à porter.

   Le filet est animé en transform: scaleX, pas en width : une largeur
   animée force un recalcul de mise en page à chaque image. */
.esdi-entete .wp-block-navigation a {
  text-decoration: none;
  position: relative;
  transition: color .2s var(--esdi-sortie);
}
.esdi-entete .wp-block-navigation a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -.25rem;
  height: 2px;
  background: var(--esdi-degrade);
  border-radius: 2px;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform .2s var(--esdi-sortie);
}
.esdi-entete .wp-block-navigation a:hover,
.esdi-entete .wp-block-navigation a:focus-visible {
  color: #164d8f;
}
.esdi-entete .wp-block-navigation a:hover::after,
.esdi-entete .wp-block-navigation a:focus-visible::after {
  transform: scaleX(1);
}
html.esdi-sombre .esdi-entete .wp-block-navigation a:hover,
html.esdi-sombre .esdi-entete .wp-block-navigation a:focus-visible {
  color: var(--wp--preset--color--primary-on-dark, #7dd6e0);
}

/* La page courante est signalée en permanence, sans survol. */
.esdi-entete .wp-block-navigation .current-menu-item a::after,
.esdi-entete .wp-block-navigation [aria-current="page"]::after {
  transform: scaleX(1);
}

/* Le menu déroulant sur téléphone est rendu par WordPress dans un calque
   dédié : le filet n'y a pas de sens, les entrées y sont déjà pleine
   largeur et empilées. */
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation a::after {
  display: none;
}

/* Le bouton d'ouverture du menu sur téléphone est un élément cliquable comme
   un autre : il lui faut son anneau. */
.wp-block-navigation__responsive-container-open:focus-visible,
.wp-block-navigation__responsive-container-close:focus-visible {
  outline: var(--esdi-focus-epaisseur) solid var(--esdi-focus);
  outline-offset: var(--esdi-focus-ecart);
  border-radius: .35rem;
}

/* --- Marges latérales sur téléphone -------------------------------------
   Sans cela, le texte touche les bords de l'écran.

   La liste des sélecteurs était nominative (group, columns, p, h1, h2). Les
   sections de la page d'accueil posent désormais aussi des <div>, <dl>, <ul>,
   <nav> et <h3> en enfants directs d'un groupe pleine largeur — via wp:html —
   et ceux-là ne recevaient aucune marge : le texte venait coller au bord de
   l'écran. On cible donc tout enfant direct, puis on retire la marge des
   éléments qui portent déjà la leur, pour ne pas la doubler.

   :not() reste préférable à une nouvelle liste nominative : la prochaine
   section qui introduira une balise non prévue sera correctement traitée
   sans qu'il faille repasser ici. */
@media (max-width: 781px) {
  .wp-block-group.alignfull > *:not(.alignfull):not(.alignwide) {
    padding-left: 1.25rem;
    padding-right: 1.25rem;
  }

  /* Ces sections peignent un fond d'un bord à l'autre et gèrent elles-mêmes
     leur marge intérieure : la leur ajouter ici la doublerait. */
  .esdi-hero.alignfull > *,
  .esdi-cta.alignfull > *,
  .esdi-manager.alignfull > * {
    padding-left: 0;
    padding-right: 0;
  }
  /* Les colonnes s'empilent : on rétablit un écart vertical lisible. */
  .wp-block-columns.is-not-stacked-on-mobile { gap: 1.5rem; }
}

/* --- Champs de formulaire -----------------------------------------------
   Le formulaire de contact est rendu par une extension (FluentForm) : son
   habillage par défaut ignore la charte. Les sélecteurs restent volontairement
   larges — l'extension change ses classes d'une version à l'autre — et ne
   posent que le strict nécessaire : bordure, rayon, et surtout l'état de
   focus, que l'anneau générique du thème couvre déjà mais qu'on double ici
   d'un changement de bordure pour que le champ actif se repère d'un coup
   d'œil, sans dépendre du seul contour. */
input:not([type="submit"]):not([type="button"]):not([type="checkbox"]):not([type="radio"]),
select,
textarea {
  border: 1px solid var(--esdi-bordure);
  border-radius: .5rem;
  background: #ffffff;
  color: #0f172a;
  font-family: inherit;
  font-size: 1rem;
  transition: border-color .2s var(--esdi-sortie), box-shadow .2s var(--esdi-sortie);
}

input:not([type="submit"]):not([type="button"]):not([type="checkbox"]):not([type="radio"]):focus,
select:focus,
textarea:focus {
  border-color: var(--esdi-focus);
}

/* Le texte indicatif doit rester lisible : gris par défaut, il tombe souvent
   sous le seuil de contraste. #475569 donne 7,5:1 sur blanc. */
::placeholder { color: #475569; opacity: 1; }

html.esdi-sombre input:not([type="submit"]):not([type="button"]):not([type="checkbox"]):not([type="radio"]),
html.esdi-sombre select,
html.esdi-sombre textarea {
  background: #202021;
  color: #f1f5f9;
}
html.esdi-sombre ::placeholder { color: #cbd5e1; }

/* Champ en erreur : la couleur ne peut pas être le seul signal — un
   utilisateur daltonien ne la perçoit pas. L'extension affiche déjà un
   message texte ; la bordure vient l'appuyer, elle ne le remplace pas.
   #b42318 donne 6,57:1 sur blanc. */
input[aria-invalid="true"],
select[aria-invalid="true"],
textarea[aria-invalid="true"] {
  border-color: #b42318;
}

/* En mode sombre, ce même rouge tombe à 2,48:1 sur #202021 : sous le seuil
   de 3:1 exigé d'un élément non textuel, la bordure d'erreur deviendrait
   invisible là où elle compte le plus. #f97066 y donne 5,84:1. */
html.esdi-sombre input[aria-invalid="true"],
html.esdi-sombre select[aria-invalid="true"],
html.esdi-sombre textarea[aria-invalid="true"] {
  border-color: #f97066;
}

/* --- Séparateur du pied de page ----------------------------------------- */
.wp-block-separator { border-color: var(--esdi-bordure); opacity: 1; }

/* --- Liens du pied de page ----------------------------------------------
   Le soulignement n'apparaît qu'au survol et au focus : dans une colonne de
   liens empilés, souligner en permanence produit un pavé de traits.
   text-underline-offset écarte le trait de la ligne de base — un
   soulignement collé aux jambages est le réglage par défaut du navigateur,
   pas un choix. */
footer a {
  text-decoration: none;
  text-underline-offset: .2em;
  transition: color .2s var(--esdi-sortie);
}
footer a:hover,
footer a:focus-visible {
  text-decoration: underline;
  color: #164d8f;
}
html.esdi-sombre footer a:hover,
html.esdi-sombre footer a:focus-visible {
  color: var(--wp--preset--color--primary-on-dark, #7dd6e0);
}

/* Le pied de page est posé sur la surface #f8fafc : l'anneau bleu profond y
   donne 8,05:1. */
footer a:focus-visible {
  outline: var(--esdi-focus-epaisseur) solid var(--esdi-focus);
  outline-offset: var(--esdi-focus-ecart);
  border-radius: .25rem;
}

/* --- Logo ---------------------------------------------------------------
   Le logo est un SVG sans dimensions intrinsèques : la largeur demandée par le
   bloc est ignorée et l'image s'affiche à une taille arbitraire.
   Mesuré sur le site original : 64 x 64 px dans l'en-tête. */
.esdi-entete .wp-block-site-logo img {
  width: auto;
  height: 40px;
  max-width: 160px;
}
footer .wp-block-site-logo img { width: auto; height: 36px; max-width: 150px; }

@media (max-width: 781px) {
  .esdi-entete .wp-block-site-logo img { height: 34px; }
}

/* --- Bandeau d'accueil pleine largeur ------------------------------------
   Le groupe est en alignfull, mais son contenu doit rester lisible : on borne
   la largeur du texte tout en laissant le fond filer d'un bord à l'autre. */
.esdi-hero { padding-left: 1.25rem; padding-right: 1.25rem; }
.esdi-hero > * { max-width: 1180px; margin-left: auto; margin-right: auto; }

/* --- Texte réservé aux lecteurs d'écran ---------------------------------
   Dix patterns posent une mention « (nouvel onglet) » dans cette classe.
   Sans la règle, ces mentions s'affichaient en clair au milieu du texte.
   Règle standard WordPress : l'élément reste dans l'arbre d'accessibilité
   mais disparaît visuellement. */
.screen-reader-text {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Au focus clavier, le texte redevient visible : c'est ce qui rend
   utilisables les liens d'évitement. */
.screen-reader-text:focus {
  position: static;
  width: auto;
  height: auto;
  padding: .75rem 1.25rem;
  margin: 0;
  overflow: visible;
  clip: auto;
  clip-path: none;
  white-space: normal;
  z-index: 1000;
  background: #ffffff;
  color: #0f172a;
  border-radius: .5rem;
  box-shadow: var(--esdi-ombre-levee);
  text-decoration: underline;
  outline: var(--esdi-focus-epaisseur) solid var(--esdi-focus);
  outline-offset: var(--esdi-focus-ecart);
}

/* Le lien d'évitement doit rester lisible en mode sombre : sur fond blanc
   forcé, l'encre sombre est conservée telle quelle et seul l'anneau change. */
html.esdi-sombre .screen-reader-text:focus {
  background: #f1f5f9;
  color: #0f172a;
}

/* =========================================================================
   TYPOGRAPHIE
   Inter est la seule police du site. Elle porte donc à elle seule toute la
   hiérarchie : c'est la précision des réglages qui distingue les niveaux, et
   non un changement de famille.

   L'ÉCHELLE vit dans theme.json et suit désormais un rapport constant :
     14 → 16 → 21,33 → 32 → 48 → 72 px
     rapports : 8/7 (palier d'interface), puis 4/3, puis 3/2, 3/2, 3/2.

   Les valeurs 16 px (corps), 14 px (menu) et 72 px (h1) sont relevées sur le
   site d'origine à 1440 px ; les trois autres s'en déduisent par le rapport.
   L'ancienne suite — 14 / 16 / 20 / 36 / 48 / 72 — n'était pas une échelle :
   ses rapports successifs valaient 1,143 puis 1,25, 1,80, 1,33, 1,50. Le saut
   de 1,80 entre le chapeau et le titre de section ouvrait un trou, sans
   aucune taille disponible entre les deux.
   Ne pas insérer de palier intermédiaire : cela casserait la progression.
   ========================================================================= */

/* --- Repli de police calibré ---------------------------------------------
   Inter est chargée en font-display: swap : le texte s'affiche immédiatement
   dans une police système, puis bascule sur Inter dès sa réception. C'est le
   bon réglage — masquer le texte en attendant une police est bien pire — mais
   la bascule déplace la mise en page si les deux polices n'ont pas les mêmes
   proportions.

   Mesuré : la hauteur d'x d'Inter vaut 0,5455 em contre 0,5186 em pour Arial,
   soit 5,19 % de plus. À l'arrivée d'Inter, chaque ligne s'allonge et les
   paragraphes se recomposent — le fameux sursaut du texte au chargement.

   « Inter secours » est la police système redimensionnée pour coïncider avec
   Inter. Elle ne télécharge rien : local() ne fait que désigner une police
   déjà présente sur la machine. Placée AVANT les replis génériques dans la
   pile de theme.json, elle rend la bascule pratiquement invisible.

   Les valeurs d'ascendante et de descendante sont celles d'Inter (2728 et 680
   sur 2816 unités), pour que la hauteur de ligne soit elle aussi identique
   avant et après la bascule. */
@font-face {
  font-family: 'Inter secours';
  src: local('Arial'), local('Helvetica Neue'), local('Liberation Sans');
  font-weight: 400 800;
  font-style: normal;
  font-display: swap;
  size-adjust: 105.19%;
  ascent-override: 96.88%;
  descent-override: 24.15%;
  line-gap-override: 0%;
}


/* --- Rendu d'Inter -------------------------------------------------------
   Inter possède de véritables variantes de caractères. « cv11 » donne un « a »
   et un « g » à étage unique, plus lisibles en petit corps ; « ss01 » redresse
   les terminaisons. Ces réglages ne s'appliquent que si la police est
   réellement chargée : avec le repli système, ils sont ignorés sans effet de
   bord. */
body {
  font-feature-settings: 'cv11', 'ss01';
  font-optical-sizing: auto;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* --- Grands titres -------------------------------------------------------
   Plus le corps grandit, plus l'espacement entre lettres doit se resserrer :
   à 72 px, l'espacement par défaut d'Inter creuse des vides visibles entre
   les mots. Le -0,025em de theme.json convient aux titres de section ; les
   deux plus grands paliers en demandent davantage.

   text-wrap: balance répartit les mots sur toutes les lignes au lieu de
   laisser un mot seul sur la dernière. Un titre d'affiche qui se termine par
   un orphelin perd la moitié de sa force. La propriété est simplement ignorée
   par les moteurs qui ne la connaissent pas : le titre y reste composé au fil
   du texte, sans dégradation. */
h1,
.has-display-font-size,
.has-xx-large-font-size {
  letter-spacing: -0.032em;
  text-wrap: balance;
}

/* 72 px × 1,1 = 79,2 px : l'interligne relevé sur l'original. */
h1 {
  line-height: 1.1;
}

/* Les titres de section conservent le réglage de theme.json et gagnent
   l'équilibrage des lignes. */
h2, h3, h4, h5, h6,
.has-x-large-font-size {
  text-wrap: balance;
}

/* Un titre ne se coupe jamais, et ne reste pas seul en bas d'un bloc. */
h1, h2, h3, h4, h5, h6 {
  hyphens: none;
  -webkit-hyphens: none;
  break-after: avoid;
}

/* --- Chapeaux ------------------------------------------------------------
   Au-delà de 20 px, l'interligne de 1,7 du corps devient trop aéré et le
   paragraphe se délite en lignes flottantes. On le resserre, et on retire une
   part de l'espacement entre lettres devenu excessif à cette taille. */
.has-large-font-size {
  line-height: 1.5;
  letter-spacing: -0.011em;
}

/* --- Largeur de lecture --------------------------------------------------
   Au-delà d'environ 65 caractères par ligne, l'œil accroche mal le début de
   la ligne suivante et la lecture décroche. 34rem place la mesure autour de
   cette valeur pour Inter à 16 px.

   La règle vise la PROSE, jamais la mise en page. Elle ne s'applique donc
   qu'au contenu d'article et aux pages légales — là où le texte est
   réellement long. Partout ailleurs, c'est la carte, la colonne ou la grille
   qui fixe déjà la largeur, et une contrainte de plus ne ferait que
   désaligner les blocs. */
.wp-block-post-content > p,
.wp-block-post-content > ul,
.wp-block-post-content > ol {
  max-width: 34rem;
}

/* --- Pages légales : de la lecture pure ----------------------------------
   Mentions légales et politique de confidentialité sont de longs textes
   suivis. Leurs groupes déclarent déjà une largeur de contenu (44rem et
   760 px) qui convient aux titres et aux séparateurs, mais laisse les
   paragraphes filer à environ 85 caractères — bien au-delà du confort.

   On borne donc la prose seule, sans toucher à la largeur du conteneur : les
   titres continuent de couvrir toute la colonne, ce qui accentue la structure
   du document au lieu de l'aplatir.

   La classe se pose sur le groupe de la page ; à défaut, la règle suivante
   rattrape les deux patterns existants par leur largeur de contenu déclarée. */
.esdi-page-legale p,
.esdi-page-legale li,
.esdi-page-legale ul,
.esdi-page-legale ol {
  max-width: 34rem;
}

/* Le texte juridique se lit lentement : un cran d'interligne en plus, et des
   entrées de liste qui se détachent les unes des autres — ce sont des
   obligations distinctes, pas une phrase découpée. */
.esdi-page-legale p,
.esdi-page-legale li {
  line-height: 1.75;
}

.esdi-page-legale li + li {
  margin-top: .5rem;
}

/* --- Étiquettes en majuscules --------------------------------------------
   Une suite de capitales composée à l'espacement du bas de casse paraît
   compressée : les capitales d'Inter sont dessinées pour être crénées entre
   elles. 0,1em rétablit une lecture nette.

   Les patterns posent déjà cet espacement en style en ligne (0,04em, 0,06em
   et 0,08em selon les fichiers) — trois valeurs pour un même rôle, et toutes
   trop faibles. Un style en ligne l'emporte sur une règle de classe : on cible
   donc l'attribut de style lui-même, ce qui corrige d'un coup les vingt
   étiquettes existantes sans avoir à rouvrir chaque pattern. Le !important
   ne sert qu'à cela : reprendre la main sur un style en ligne, ce qu'aucune
   spécificité de sélecteur ne permet de faire. */
[style*="text-transform:uppercase"],
[style*="text-transform: uppercase"],
.esdi-etiquette {
  letter-spacing: 0.1em !important;
  hyphens: none;
  -webkit-hyphens: none;
}

/* Classe utilitaire pour les étiquettes à venir : elle évite de recopier le
   style en ligne dans un nouveau pattern. Le corps de 14 px et la graisse 600
   reprennent ce que font déjà les patterns. */
.esdi-etiquette {
  font-size: var(--wp--preset--font-size--small);
  font-weight: 600;
  line-height: 1.4;
  text-transform: uppercase;
}

/* --- Chiffres ------------------------------------------------------------
   Les chiffres d'Inter sont proportionnels par défaut : le « 1 » y est plus
   étroit que le « 8 ». Deux conséquences, toutes deux visibles ici.

   Dans une colonne de compteurs, les nombres ne s'alignent pas verticalement.
   Et surtout, un compteur animé qui traverse toutes les valeurs de 0 à 500
   change de largeur à chaque incrément : le nombre tremble pendant toute
   l'animation, et le texte placé dessous se décale avec lui. Les chiffres
   tabulaires leur donnent une chasse identique, et le mouvement cesse.

   « lining-nums » force en outre les chiffres à hauteur de capitale, pour
   qu'aucun ne descende sous la ligne de base. */
.esdi-chiffre,
[data-compteur],
table td,
table th {
  font-variant-numeric: tabular-nums lining-nums;
  font-feature-settings: 'tnum', 'lnum';
}

/* Le nombre est l'argument de la section : il se resserre comme un titre.
   Sa taille reste celle définie plus haut, on ne touche qu'au crénage. */
.esdi-chiffre {
  letter-spacing: -0.03em;
}

/* --- Équilibre du texte courant ------------------------------------------
   text-wrap: pretty ne redistribue pas les lignes comme le fait « balance » :
   il empêche seulement la dernière ligne d'un paragraphe de se réduire à un
   mot isolé. Appliqué au corps, il est invisible partout sauf là où il évite
   une veuve. */
p, li, figcaption, blockquote, dd, dt {
  text-wrap: pretty;
}

/* --- Citations -----------------------------------------------------------
   Le filet turquoise défini dans theme.json marque déjà la citation : la
   typographie n'a pas besoin d'y ajouter de l'italique. Elle se distingue par
   la taille et par un interligne plus généreux, rien de plus. */
.wp-block-quote {
  font-size: var(--wp--preset--font-size--large);
  line-height: 1.55;
  letter-spacing: -0.011em;
  max-width: 34rem;
}

/* L'attribution n'est pas la citation : elle redescend au corps d'interface,
   sans italique, et prend la couleur du texte secondaire. */
.wp-block-quote cite {
  display: block;
  margin-top: .75rem;
  font-size: var(--wp--preset--font-size--small);
  font-style: normal;
  font-weight: 500;
  letter-spacing: 0;
  color: var(--wp--preset--color--contrast-2);
}
html.esdi-sombre .wp-block-quote cite {
  color: var(--wp--preset--color--contrast-2-on-dark, #cbd5e1);
}

/* --- Libellés de boutons -------------------------------------------------
   Un libellé de bouton est un ordre court : il ne se coupe pas en deux. */
.wp-block-button__link {
  letter-spacing: -0.006em;
  text-wrap: nowrap;
}

/* --- Césure sur petit écran ----------------------------------------------
   Sur téléphone la colonne devient étroite, et un mot long (« développement »,
   « personnalisation ») rejeté à la ligne creuse une lézarde blanche dans le
   paragraphe. La césure française, limitée aux écrans étroits, la referme.
   Jamais sur un titre, une étiquette ni un chiffre : le rappel est nécessaire,
   car ces éléments héritent sinon de la règle. */
@media (max-width: 600px) {
  p, li {
    hyphens: auto;
    -webkit-hyphens: auto;
  }
  h1, h2, h3, h4, h5, h6,
  .esdi-chiffre,
  .esdi-etiquette,
  [style*="text-transform:uppercase"],
  [style*="text-transform: uppercase"] {
    hyphens: none;
    -webkit-hyphens: none;
  }
}

/* =========================================================================
   Échelle typographique — définie ici en dernier ressort.

   Le thème parent déclare typography.fluid = true dans son theme.json.
   WordPress fusionne les deux fichiers et recalcule alors chaque taille en
   fonction de la largeur de l'écran, en ignorant les bornes du thème enfant :
   le corps du texte ressortait à 20 px et l'accroche à 36 px, ce qui donnait
   des blocs démesurés. Redéfinir les jetons ici, après la feuille générée,
   règle le problème quel que soit le résultat de la fusion.
   ========================================================================= */
:root {
  --wp--preset--font-size--small:    0.875rem;                                    /* 14 px */
  --wp--preset--font-size--medium:   1rem;                                        /* 16 px */
  --wp--preset--font-size--large:    clamp(1.0625rem, 0.4vw + 0.97rem, 1.125rem); /* 17 → 18 px */
  --wp--preset--font-size--x-large:  clamp(1.25rem,  0.9vw + 1.05rem, 1.5rem);    /* 20 → 24 px */
  --wp--preset--font-size--xx-large: clamp(1.75rem,  2.2vw + 1.1rem,  2.25rem);   /* 28 → 36 px */
  --wp--preset--font-size--display:  clamp(2.25rem,  4.5vw + 0.9rem,  3.5rem);    /* 36 → 56 px */
}

body,
.wp-site-blocks {
  font-size: var(--wp--preset--font-size--medium);
  line-height: 1.65;
}

/* Les classes de taille des blocs suivent les mêmes jetons. */
.has-small-font-size    { font-size: var(--wp--preset--font-size--small) !important; }
.has-medium-font-size   { font-size: var(--wp--preset--font-size--medium) !important; }
.has-large-font-size    { font-size: var(--wp--preset--font-size--large) !important; }
.has-x-large-font-size  { font-size: var(--wp--preset--font-size--x-large) !important; }
.has-xx-large-font-size { font-size: var(--wp--preset--font-size--xx-large) !important; }
.has-display-font-size  { font-size: var(--wp--preset--font-size--display) !important; }

/* Largeur de lecture : au-delà d'environ 70 caractères, l'œil perd la ligne
   en revenant à la gauche. Ne s'applique qu'à la prose, jamais aux grilles. */
p:not([class*="has-"]):not(.esdi-chiffre) { max-width: 68ch; }

/* =========================================================================
   Icônes Lucide — même banque que celle d'ESDI Manager.

   Elles sont écrites <i data-lucide="nom"></i> et remplacées par un SVG au
   chargement. Tant que le remplacement n'a pas eu lieu, la balise garde sa
   place : sans dimensions réservées, le texte voisin sauterait au moment où
   l'icône apparaît. Aucune information ne repose sur une icône seule — si le
   CDN est injoignable, il ne manque qu'un ornement.
   ========================================================================= */
.esdi-icone {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  vertical-align: -0.135em;
  width: 1.125em;
  height: 1.125em;
}
svg.esdi-icone { display: inline-block; }

/* Tailles fixes, employées là où l'icône ne doit pas suivre le corps du texte. */
.esdi-icone--16 { width: 16px; height: 16px; }
.esdi-icone--18 { width: 18px; height: 18px; }
.esdi-icone--20 { width: 20px; height: 20px; }

/* Le trait suit la couleur du texte, sauf mention contraire. */
.esdi-icone { stroke: currentColor; }
.esdi-icone--marque { stroke: var(--esdi-turquoise); }
html.esdi-sombre .esdi-icone--marque { stroke: #7dd6e0; }

/* Une icône qui accompagne un lien avance légèrement au survol : le mouvement
   confirme l'action sans rien déplacer d'autre. */
@media (hover: hover) and (pointer: fine) {
  a:hover .esdi-icone[data-lucide="arrow-right"] { transform: translateX(2px); }
}
.esdi-icone[data-lucide="arrow-right"] { transition: transform .2s var(--esdi-sortie); }
@media (prefers-reduced-motion: reduce) {
  .esdi-icone { transition: none !important; }
  a:hover .esdi-icone { transform: none !important; }
}

/* =========================================================================
   Rythme des grilles.

   Le bloc « colonnes » de WordPress hérite du blockGap du thème, ici 60 px :
   entre un titre et le texte qu'il annonce, cet écart se lit comme une
   séparation et non comme un lien. On resserre, et on laisse la respiration
   aux transitions ENTRE sections, là où elle a du sens.
   ========================================================================= */
.wp-block-columns {
  gap: clamp(1.5rem, 3vw, 2.5rem) !important;
}

/* Les paires titre/valeur d'une même ligne restent solidaires. */
.esdi-apropos__valeurs .wp-block-columns,
.wp-block-columns.is-not-stacked-on-mobile {
  gap: clamp(1rem, 2.5vw, 2rem) !important;
}

/* Un titre de section et sa phrase d'accroche appartiennent au même bloc :
   ils s'alignent en haut, jamais répartis sur toute la largeur. */
.wp-block-columns.are-vertically-aligned-top > .wp-block-column {
  align-self: start;
}
