
/* ===== anim-hover.css ===== */
/* ==========================================================================
   Lot hover : micro-interactions au survol (animations ilem v2, HANDOFF 28/10).
   Fichier propre a ce lot. Uniquement transform (proprietes individuelles
   translate/scale, independantes du `transform` des reveals) et opacity.
   - effets de survol : seulement sous (hover:hover) and (pointer:fine) ;
   - equivalent clavier via :focus-visible ;
   - prefers-reduced-motion: reduce -> aucune regle de ce fichier ne s'applique.
   ========================================================================== */

:root {
  --hv-ease: cubic-bezier(0.2, 0.7, 0.2, 1); /* meme courbe que les reveals */
  --hv-lift: -5px;
  --hv-dur-lift: 520ms;
  --hv-dur-zoom: 700ms; /* zoom image plus lent que le soulevement : effet « pose » */
  --hv-dur-line: 420ms; /* glissement des fleches */
  --hv-zoom: 1.04;
  /* ombre teintee du bleu ilem (#09284c), tres diffuse : on la sent plus qu'on ne la voit */
  --hv-shadow: 0 22px 44px -22px rgb(9 40 76 / 0.32), 0 2px 8px rgb(9 40 76 / 0.05);
}

@media (prefers-reduced-motion: no-preference) {
  /* ------------------------------------------------------------ cartes
     Cartes sans fond (offres, offres liees, partenaires, emplois) : un panneau
     blanc ombre « emerge » autour du contenu. Cartes a fond (actualites) :
     l'ombre epouse la carte. */
  a.offer,
  .related-offer,
  a > .partner,
  .job,
  .insights .insight,
  .success-story,
  .owl-carousel-success .owl-item > a {
    position: relative;
    isolation: isolate; /* le panneau z-index:-1 reste au-dessus du fond de section */
    transition: translate var(--hv-dur-lift) var(--hv-ease);
  }

  a.offer::before,
  .related-offer::before,
  a > .partner::before,
  .job::before,
  .insights .insight::before,
  .success-story::before,
  .owl-carousel-success .owl-item > a::before {
    content: "";
    position: absolute;
    inset: -14px; /* respire dans la gouttiere de 24 px sans toucher la carte voisine */
    z-index: -1;
    background: var(--white, #fff);
    box-shadow: var(--hv-shadow);
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--hv-dur-lift) var(--hv-ease);
  }

  .job::before {
    inset: -18px -24px; /* bloc texte large : marge laterale plus genereuse */
  }

  .insights .insight::before {
    inset: 0; /* la carte a deja son fond gris : seule l'ombre apparait */
    background: none;
  }

  /* conteneurs d'image : le zoom reste dans son cadre (aucun changement de taille) */
  .insight-media,
  a.offer > div:first-child,
  .related-offer > div:first-child,
  .partner > div:first-child {
    overflow: hidden;
  }

  .insight-media img,
  a.offer > div:first-child img,
  .related-offer > div:first-child img,
  .partner > div:first-child img {
    transition: scale var(--hv-dur-zoom) var(--hv-ease);
  }

  /* fleches cercle des cartes et des liens d'appel */
  a.offer .icon-arrow-circle,
  .related-offer .icon-arrow-circle,
  .success-story .icon-arrow-circle,
  .owl-carousel-success .owl-item > a .icon-arrow-circle,
  .btn-link .icon-arrow-circle {
    transition: translate var(--hv-dur-line) var(--hv-ease);
  }

  /* liens d'appel a fleche (btn-link) : seule la fleche glisse, aucun soulignement
     (consigne 28/10 ; le gabarit n'en pose pas : a { text-decoration: inherit }) */

  /* ------------------------------------------------------- boutons pilules
     garde l'inversion de couleurs existante (dist/style.css) et ajoute un
     soulevement de 2 px ; la transition d'origine est reprise a l'identique */
  .btn:not(.btn-link),
  a.btn:not(.btn-link) {
    /* a.btn : meme specificite que « a.btn:hover » du gabarit, qui sinon couperait la transition */
    transition: background 0.3s, color 0.3s, border 0.3s, translate 360ms var(--hv-ease);
  }

  /* ------------------------------------------------------------ pied de page
     (footer.php, fond bleu #09284c) : icones sociales et TeamViewer se soulevent
     de 2 px ; liens texte du menu (sans fleche) : trait blanc trace de gauche a
     droite, seul soulignement du site (consigne : jamais sous un lien a fleche). */
  #footer a.fill-white,
  #footer a[href*="teamviewer"] {
    transition: translate 360ms var(--hv-ease), opacity 360ms var(--hv-ease);
  }

  #menu-footer a {
    position: relative; /* reste inline : aucun changement de mise en page */
  }

  #menu-footer a::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: -3px;
    height: 1px;
    background: currentColor; /* blanc sur bleu : contraste 14:1 */
    transform-origin: left center;
    scale: 0 1;
    pointer-events: none;
    transition: scale var(--hv-dur-line) var(--hv-ease);
  }

  /* ============================================================== etats actifs */
  @media (hover: hover) and (pointer: fine) {
    a.offer:hover,
    .related-offer:hover,
    a:hover > .partner,
    .job:hover,
    .insights .insight:hover,
    .success-story:hover,
    .owl-carousel-success .owl-item > a:hover {
      translate: 0 var(--hv-lift);
    }

    a.offer:hover::before,
    .related-offer:hover::before,
    a:hover > .partner::before,
    .job:hover::before,
    .insights .insight:hover::before,
    .success-story:hover::before,
    .owl-carousel-success .owl-item > a:hover::before {
      opacity: 1;
    }

    .insights .insight:hover .insight-media img,
    a.offer:hover > div:first-child img,
    .related-offer:hover > div:first-child img,
    a:hover > .partner > div:first-child img {
      scale: var(--hv-zoom);
    }

    a.offer:hover .icon-arrow-circle,
    .related-offer:hover .icon-arrow-circle,
    .success-story:hover .icon-arrow-circle,
    .owl-carousel-success .owl-item > a:hover .icon-arrow-circle,
    .insights .insight:hover .btn-link .icon-arrow-circle,
    .btn-link:hover .icon-arrow-circle {
      translate: 4px 0;
    }

    .btn:not(.btn-link):hover,
    #footer a.fill-white:hover,
    #footer a[href*="teamviewer"]:hover {
      translate: 0 -2px;
    }

    #footer a[href*="teamviewer"]:hover {
      opacity: 0.88; /* le logo orange s'adoucit legerement, l'icone sociale a deja son effet */
    }

    #menu-footer a:hover::after {
      scale: 1 1;
    }
  }

  /* clavier : memes etats, sans dependre du pointeur */
  a.offer:focus-visible,
  .related-offer:focus-visible,
  a:focus-visible > .partner,
  .job:has(a:focus-visible),
  .insights .insight:has(a:focus-visible),
  .success-story:focus-visible,
  .owl-carousel-success .owl-item > a:focus-visible {
    translate: 0 var(--hv-lift);
  }

  a.offer:focus-visible::before,
  .related-offer:focus-visible::before,
  a:focus-visible > .partner::before,
  .job:has(a:focus-visible)::before,
  .insights .insight:has(a:focus-visible)::before,
  .success-story:focus-visible::before,
  .owl-carousel-success .owl-item > a:focus-visible::before {
    opacity: 1;
  }

  .insights .insight:has(a:focus-visible) .insight-media img,
  a.offer:focus-visible > div:first-child img,
  .related-offer:focus-visible > div:first-child img,
  a:focus-visible > .partner > div:first-child img {
    scale: var(--hv-zoom);
  }

  a.offer:focus-visible .icon-arrow-circle,
  .related-offer:focus-visible .icon-arrow-circle,
  .success-story:focus-visible .icon-arrow-circle,
  .btn-link:focus-visible .icon-arrow-circle {
    translate: 4px 0;
  }

  .btn:not(.btn-link):focus-visible,
  #footer a.fill-white:focus-visible,
  #footer a[href*="teamviewer"]:focus-visible {
    translate: 0 -2px;
  }

  #menu-footer a:focus-visible::after {
    scale: 1 1;
  }
}

/* image enveloppee par components/InsightPost.php : rendu identique a l'image seule
   (bloc, pas d'espace de ligne de base sous l'image) */
.insight-media > img,
.insight-media > .ilem-pic > img {
  display: block;
}

/* --------------------------------------------------------------------------
   Cartes d'actualite cliquables en entier (« stretched link », sans JS) :
   le lien « Decouvrir » (components/InsightPost.php, .card-link) etend sa zone
   de clic a toute la carte. Un seul arret de tabulation, focus sur le lien.
   Hors media query : comportement fonctionnel, identique avec reduced-motion.
   Les cartes d'offres (a.offer, .related-offer) sont deja un <a> entier.
   -------------------------------------------------------------------------- */
.insight {
  position: relative;
}

.insight .card-link::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
}

/* liens eventuels dans l'extrait (contenu editorial) : restent cliquables au-dessus */
.insight .text a {
  position: relative;
  z-index: 2;
}

/* Pied de page : le <style> de footer.php remplace au survol la bordure transparente
   de 4 px des <li> du menu par « border-bottom: white » (largeur 0) -> le lien sautait
   de 2 px (deja le cas en prod). On garde la bordure transparente : plus de saut. */
#footer #menu-footer li:hover {
  border-bottom: 4px solid transparent;
}

/* Ecrans tactiles / sans pointeur fin : les panneaux d'ombre ne s'affichent jamais ;
   on ne les cree pas (leur marge negative elargissait la page, ex. .job en mobile : +24 px de defilement horizontal). */
@media not ((hover: hover) and (pointer: fine)) {
  a.offer::before,
  .related-offer::before,
  a > .partner::before,
  .job::before,
  .insights .insight::before,
  .success-story::before,
  .owl-carousel-success .owl-item > a::before {
    content: none;
  }
}

/* ------------------------------------------------------------ page contact : choix du bureau
   Boutons pilules a la place de la liste deroulante (components/Offices.php, contact.js).
   Le bouton actif (btn-primary) reste orange plein, y compris au survol ; l'inversion des boutons
   inactifs n'a lieu qu'avec une vraie souris (sinon elle « colle » apres un toucher sur mobile). */
.offices-switch {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

.btn-office.btn-primary,
.btn-office.btn-primary:hover {
  background-color: var(--color-primary-2, orange);
  color: var(--white);
  cursor: default;
}

.btn-office.btn-secondary:hover {
  background-color: rgba(0, 0, 0, 0);
  color: var(--color-primary-2, orange);
}

@media (hover: hover) and (pointer: fine) {
  .btn-office.btn-secondary:hover {
    background-color: var(--color-primary-2, orange);
    color: var(--white);
  }
}

@media (max-width: 1023px) {
  .offices-switch {
    gap: 8px;
  }
}

/* ===== anim-hero.css ===== */
/* ==========================================================================
   ilem - lot hero (animations v2) : hero de l'accueil.
   Classes posees par assets/js/anim-hero.js (inclus en ligne dans
   components/hero_home.php) : sans JS ou avec prefers-reduced-motion: reduce,
   aucune de ces regles ne s'applique et le hero est identique a l'existant.
   Uniquement transform / opacity. Courbe = celle des reveals (perf.css).
   ========================================================================== */

/* copie du titre pour les lecteurs d'ecran (les mots animes sont aria-hidden) */
.ilem-hero-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* mot decoupe : inline-block (necessaire a transform), espaces d'origine entre les mots
   -> memes retours a la ligne et meme hauteur de ligne que le titre d'origine */
.ilem-hero-w {
  display: inline-block;
}

@media screen and (prefers-reduced-motion: no-preference) {
  .ilem-hero-fx-text {
    --hero-base: 100ms; /* laisse passer le 1er rendu avant le depart */
    --hero-step: 70ms; /* entre deux mots */
    --hero-dur: 640ms;
    --hero-ease: cubic-bezier(0.2, 0.7, 0.2, 1);
  }

  /* 1. titre : chaque mot monte de 0.4em en apparaissant, en cascade.
        Les mots ne sont pas l'element LCP (mobile : .text, desktop : .icon-header). */
  .ilem-hero-fx-text .ilem-hero-w {
    animation: ilem-hero-word var(--hero-dur) var(--hero-ease) both;
    animation-delay: calc(var(--hero-base) + var(--i, 0) * var(--hero-step));
  }

  /* 2. texte d'introduction : suit le dernier mot. Seulement >= 1024 px : sur mobile
        c'est l'element LCP, il reste donc affiche immediatement (jamais masque). */
  @media (min-width: 1024px) {
    .ilem-hero-fx-text .page-title ~ .text {
      animation: ilem-hero-intro var(--hero-dur) var(--hero-ease) both;
      animation-delay: calc(var(--hero-base) + var(--hero-words, 6) * var(--hero-step) + 80ms);
    }
  }
}

@keyframes ilem-hero-word {
  from {
    opacity: 0;
    transform: translate3d(0, 0.4em, 0);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes ilem-hero-intro {
  from {
    opacity: 0;
    transform: translate3d(0, 14px, 0);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* --------------------------------------------------------------------------
   3. Parallaxe legere de l'image de fond (facteur 0,2 : 120 px sur les 600 premiers px
      de defilement). CSS scroll-driven animation (fil du compositeur, aucun JS au
      scroll) ; navigateurs sans animation-timeline : pas d'effet.
      Calque = ::before qui herite du fond du bloc .image (meme image, meme cadrage
      « cover », deja en cache) : l'element LCP et son chargement ne changent pas, le
      fond d'origine reste peint dessous. Le calque descend : la zone degagee en haut
      du bloc est toujours sous l'en-tete sticky (hauteur >= deplacement), et le bas
      du bloc reste couvert -> aucun espace vide.
      Desactivee : ecrans < 1024 px (image dans le flux, 200 px), tactile / sans
      survol, reduced-motion, impression.
   -------------------------------------------------------------------------- */
@supports (animation-timeline: scroll()) {
  @media screen and (min-width: 1024px) and (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
    .hero_home.ilem-hero-fx > .image {
      overflow: hidden;
    }

    .hero_home.ilem-hero-fx > .image::before {
      content: "";
      position: absolute;
      inset: 0;
      background: inherit;
      pointer-events: none;
      will-change: transform;
      animation: ilem-hero-parallax linear both;
      animation-timeline: scroll(root block);
      animation-range: 0 600px;
    }
  }
}

@keyframes ilem-hero-parallax {
  from {
    transform: none;
  }
  to {
    transform: translate3d(0, 120px, 0);
  }
}

/* ===== anim-nav.css ===== */
/* ==========================================================================
   ilem - lot navigation (animations v2, voir HANDOFF 28/10). Fichier propre a ce lot.
   1. En-tete au defilement (classe body.scrolled posee par dist/app.js)
   2. Menu mobile (#btn-menu-mobile, body.menu-mobile-open, panneau .menu-mobile
      cree par assets/js/navigation.js)
   3. Transitions de page : morphing image carte d'actualite -> image principale
      de l'article (complete @view-transition de perf.css, sans le modifier)
   Uniquement transform / opacity. Sans JS : rendu identique (body.scrolled et le
   panneau mobile n'existent pas). prefers-reduced-motion: reduce -> rien ici.
   ========================================================================== */

@media (prefers-reduced-motion: no-preference) {
  :root {
    --nav-ease: cubic-bezier(0.2, 0.7, 0.2, 1);
  }

  /* ------------------------------------------------------------------------
     1. En-tete au defilement
     La boite du header ne change JAMAIS de taille (70 / 90 px, sticky) : aucune
     incidence sur la mise en page (CLS nul). La « reduction » est visuelle.
     ------------------------------------------------------------------------ */
  #header {
    transition: transform 420ms var(--nav-ease);
  }

  /* ombre portee douce : opacite d'un pseudo-element sous la bordure */
  #header::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    top: calc(100% + 1px);
    height: 14px;
    background: linear-gradient(to bottom, rgba(9, 40, 76, 0.09), rgba(9, 40, 76, 0));
    opacity: 0;
    pointer-events: none;
    transition: opacity 420ms var(--nav-ease);
  }

  body.scrolled #header::after {
    opacity: 1;
  }

  /* logo : legere reduction, ancree a gauche */
  #header .logo-container > svg,
  #header .logo-container > img {
    transform-origin: 0 50%;
    transition: transform 420ms var(--nav-ease);
  }

  body.scrolled #header .logo-container > svg,
  body.scrolled #header .logo-container > img {
    transform: scale(0.86);
  }

  /* menu ouvert : pas d'ombre sur le panneau blanc */
  body.menu-mobile-open #header::after {
    opacity: 0;
  }

  /* Bureau : l'en-tete remonte de 14 px (90 -> 76 px visibles) et son contenu
     redescend de 7 px pour rester centre. Reserve au bureau : un transform sur
     #header ferait de lui le bloc conteneur du panneau mobile (position: fixed).
     (Fond translucide + backdrop-filter essaye puis retire : -6 img/s au defilement.) */
  @media (min-width: 1024px) {
    #header > div {
      transition: transform 420ms var(--nav-ease);
    }

    body.scrolled #header {
      transform: translate3d(0, -14px, 0);
    }

    body.scrolled #header > div {
      transform: translate3d(0, 7px, 0);
    }
  }

  /* ------------------------------------------------------------------------
     2. Menu mobile
     ------------------------------------------------------------------------ */
  /* panneau : fondu + glissement court depuis l'en-tete */
  .menu-mobile {
    animation: ilem-nav-panel-in 340ms var(--nav-ease) both;
  }

  /* liens en cascade (50 ms), apres l'amorce du panneau */
  .menu-mobile .menu > li {
    animation: ilem-nav-item-in 420ms var(--nav-ease) both;
    animation-delay: calc(90ms + var(--nav-i, 8) * 50ms);
  }
  .menu-mobile .menu > li:nth-child(1) { --nav-i: 0; }
  .menu-mobile .menu > li:nth-child(2) { --nav-i: 1; }
  .menu-mobile .menu > li:nth-child(3) { --nav-i: 2; }
  .menu-mobile .menu > li:nth-child(4) { --nav-i: 3; }
  .menu-mobile .menu > li:nth-child(5) { --nav-i: 4; }
  .menu-mobile .menu > li:nth-child(6) { --nav-i: 5; }
  .menu-mobile .menu > li:nth-child(7) { --nav-i: 6; }
  .menu-mobile .menu > li:nth-child(8) { --nav-i: 7; }

  /* fermeture : copie inerte du panneau posee par anim-nav.js, qui s'efface */
  .menu-mobile.ilem-nav-leaving {
    animation: ilem-nav-panel-out 220ms cubic-bezier(0.4, 0, 1, 1) both;
    pointer-events: none;
  }
  .menu-mobile.ilem-nav-leaving .menu > li {
    animation: none;
  }

  /* icone : burger -> croix (et retour) par rotation + fondu ; les deux SVG sont
     alternes en display par dist/style.css, l'animation rejoue a chaque bascule */
  #btn-menu-mobile .icon {
    transform-box: fill-box;
    transform-origin: 50% 50%;
  }
  body.menu-mobile-open #btn-menu-mobile .icon-close {
    animation: ilem-nav-icon-in 320ms var(--nav-ease) both;
  }
  body.ilem-nav-closed:not(.menu-mobile-open) #btn-menu-mobile .icon-menu {
    animation: ilem-nav-icon-back 320ms var(--nav-ease) both;
  }

  /* ------------------------------------------------------------------------
     3. Transitions de page : image de carte -> image principale de l'article
     Cote liste, le nom est pose sur l'image de la carte cliquee par anim-nav.js
     (evenements pageswap / pagereveal). Cote article, sur l'image du hero ; la
     plupart des articles n'en ont pas : c'est alors le bandeau hero entier qui
     recoit le nom (la carte « s'ouvre » en en-tete d'article).
     ------------------------------------------------------------------------ */
  body.single-post .hero .image,
  body.single-post .hero:not(:has(.image)) {
    view-transition-name: hero-img;
  }

  ::view-transition-group(hero-img) {
    animation-duration: 560ms;
    animation-timing-function: var(--nav-ease);
    overflow: clip;
  }

  /* proportions differentes (carte ~ carree, hero panoramique) : recadrage cover */
  ::view-transition-old(hero-img),
  ::view-transition-new(hero-img) {
    height: 100%;
    object-fit: cover;
    animation-duration: 560ms;
    animation-timing-function: var(--nav-ease);
  }

  /* image seule (arrivee depuis le menu, depart vers une autre page) : meme fondu
     que la page (perf.css), pas d'image « fantome » */
  ::view-transition-old(hero-img):only-child {
    animation: 160ms cubic-bezier(0.4, 0, 1, 1) both ilem-vt-out;
  }
  ::view-transition-new(hero-img):only-child {
    animation: 260ms var(--nav-ease) 60ms both ilem-vt-in;
  }

  /* en-tete stable (duree 0 dans perf.css) et toujours au-dessus de l'image en vol */
  ::view-transition-group(ilem-header) {
    z-index: 10;
  }
}

@keyframes ilem-nav-panel-in {
  from {
    opacity: 0;
    transform: translate3d(0, -12px, 0);
  }
}

@keyframes ilem-nav-panel-out {
  to {
    opacity: 0;
    transform: translate3d(0, -8px, 0);
  }
}

@keyframes ilem-nav-item-in {
  from {
    opacity: 0;
    transform: translate3d(0, 10px, 0);
  }
}

@keyframes ilem-nav-icon-in {
  from {
    opacity: 0;
    transform: rotate(-90deg) scale(0.6);
  }
}

@keyframes ilem-nav-icon-back {
  from {
    opacity: 0;
    transform: rotate(90deg) scale(0.6);
  }
}

/* ===== anim-type.css ===== */
/* ==========================================================================
   Lot « typographie editoriale » (vague 2) - charge seulement si ilem_v2()
   (cookie ilem_v2=1) tant que non valide par Usman.
   CSS seul : polices existantes (MarkPro / NotoSans, deja prechargees), couleurs
   de la charte, mise en page inchangee. Aucune animation dans ce fichier.
   Hero (lot hero), titre du bandeau partenaires (lot marquee) et barre de contact collante (.bloc.contact.small) non touches.
   Note : <html lang="en-US"> (reglage WordPress) -> pas de cesure automatique
   (elle suivrait les regles anglaises) ; les mots longs passent par overflow-wrap.
   ========================================================================== */

:root {
  /* Echelle fluide : 412 px -> 1440 px */
  --type-h2: clamp(2.75rem, 2rem + 3vw, 4.25rem); /* 44 -> 68 px (avant 45 / 55) */
  --type-h2-lh: 1.06;
  --type-h2-ls: -0.04em; /* serre mais lisible (l'existant : -4px fixe = -0.073em) */
  --type-h3: clamp(1.875rem, 1.5rem + 1vw, 2.5rem); /* 30 -> 40 px (avant 30 / 35) */
  --type-stat: clamp(6rem, 4rem + 5vw, 8.5rem); /* 96 -> 136 px (avant 95 partout) */
  --type-label: color-mix(in oklab, var(--grey-basic, #2f2f2f) 75%, white); /* ~#646464, AA sur blanc */
  --type-measure: 70ch;
  /* rythme vertical entre sections de .page-content */
  --type-section-gap: 4.5rem; /* mobile : 72 px (avant 60) */
}

@media (min-width: 1024px) {
  :root {
    --type-section-gap: 8rem; /* desktop : 128 px (avant 90) */
  }
}

/* --------------------------------------------------------------------------
   Titres : equilibrage des lignes, pas de debordement sur mobile
   -------------------------------------------------------------------------- */
.site-content :is(h1, h2, h3, h4):not(.hero *) {
  text-wrap: balance;
  overflow-wrap: break-word;
}

/* Titres de section (H2) : plus grands, interlignage serre, approche negative */
.site-content h2:not(.hero h2):not(.small h2):not(.article-content h2):not([class*="ilem-mq"]) {
  font-size: var(--type-h2);
  line-height: var(--type-h2-lh);
  letter-spacing: var(--type-h2-ls);
}

/* H3 de section (blocs alternes de l'accueil, texte + image) ; les H3 des
   colonnes etroites (services, bureaux) gardent leur taille */
.site-content :is(.bloc.list h3, .text_image h3, .text_image .heading-3, .page-content > section > h4.heading-3) {
  font-size: var(--type-h3);
  line-height: 1.12;
  letter-spacing: -0.02em;
}

.site-content h3 {
  line-height: 1.15;
}

.site-content h4 {
  line-height: 1.2;
}

/* --------------------------------------------------------------------------
   Paragraphes : derniere ligne sans mot orphelin, mesure limitee
   -------------------------------------------------------------------------- */
.site-content :is(p, .text):not(.hero *) {
  text-wrap: pretty;
}

/* Texte justifie sans cesure = « rivieres » (cartes d'actualites, a propos) :
   fer a gauche, plus calme a la lecture */
.site-content .text-justify {
  text-align: start;
}

/* Introductions de section : ~70 caracteres par ligne au lieu de ~110 */
.site-content .bloc.title_text > .text {
  max-width: var(--type-measure);
}

.site-content .bloc.title_text {
  row-gap: 2rem;
}

/* Article : corps un peu plus grand et colonne de lecture (~68 caracteres) */
.single-post .site-content .bloc.title_text > .text {
  max-width: 72ch;
}

.single-post .site-content .bloc.title_text > .text :is(p, li) {
  font-size: 16px;
  line-height: 1.75;
}

.single-post .site-content .bloc.title_text > .text :is(h2, h3, h4) {
  margin-top: 1.5rem;
}

/* --------------------------------------------------------------------------
   Rythme vertical : plus d'air entre les sections
   -------------------------------------------------------------------------- */
.site-content .page-content.opt-gap-y-15 > :not(:first-child) {
  margin-top: var(--type-section-gap);
}

/* --------------------------------------------------------------------------
   Chiffres cles
   Chasse fixe (tnum present dans MarkPro) : le compteur anime ne fait pas
   bouger la mise en page ; boite de 3 chiffres sur l'accueil (5 / 25 / 200).
   -------------------------------------------------------------------------- */
.big-black {
  font-variant-numeric: tabular-nums lining-nums;
  letter-spacing: -0.03em;
}

.home .statistiques .statistique .big-black {
  font-size: var(--type-stat);
  line-height: 0.9;
  letter-spacing: -0.045em;
}

.home .statistiques .count-animation {
  min-width: 3ch; /* largeur de « 200 » reservee pendant le comptage */
  text-align: center;
}

/* libelle discret sous le chiffre */
.home .statistiques .statistique .stat > .text {
  font-size: 12px;
  line-height: 16px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--type-label);
}

/* ===== anim-marquee.css ===== */
/* ==========================================================================
   Vague 2 - bandeau de logos partenaires (components/LogosMarquee.php)
   Charge seulement si ilem_v2() (cookie ilem_v2=1) tant que non valide.

   Choregraphie : defilement lineaire et lent (~45 px/s), boucle sans couture
   (2 copies identiques, translation de -50 %), uniquement `transform`.
   Pause au survol (pointeur fin) et au focus clavier (lien du titre).
   Fondu des bords par mask-image. Logos discrets (desatures, attenues) et
   couleur ilem au survol d'un logo, desktop seulement.
   Les vignettes sont carrees, fond #09284c (= --color-primary-1, celui du
   bandeau) avec le logo au centre : rognees en 2:1 par object-fit, le fond se
   confond avec le bandeau ; les variantes WebP (avec perte) et le fondu de
   couleur decalent ce bleu de 1 a 3 niveaux : un masque adoucit les bords de
   chaque vignette pour qu'aucun rectangle ne se devine. Desaturation = calque ::after en mix-blend-mode:color
   (le bleu reste bleu, le jaune devient blanc bleute) dont on anime l'opacite.
   Sans JS : identique (le JS ne fait que suspendre l'animation hors ecran).
   Reduced motion : rangee statique centree, 2e copie masquee.
   ========================================================================== */

.ilem-mq {
  --mq-item-w: 144px;
  --mq-item-h: 72px;
  --mq-gap: 8px;
  --mq-fade: 40px;
  --mq-duration: 45s;
  --mq-ease: cubic-bezier(0.2, 0.7, 0.2, 1);
  padding-block: 56px;
  color: var(--white, #fff);
}

@media (min-width: 1024px) {
  .ilem-mq {
    --mq-item-w: 192px;
    --mq-item-h: 96px;
    --mq-gap: 24px;
    --mq-fade: 120px;
    --mq-duration: 50s;
    padding-block: 72px;
  }
}

.ilem-mq__head {
  margin-bottom: 32px;
}

@media (min-width: 1024px) {
  .ilem-mq__head {
    margin-bottom: 40px;
  }
}

/* titre existant (« Nos partenaires »), sobre : plus petit qu'un h2 de section */
.ilem-mq__title {
  margin: 0;
  color: var(--white, #fff);
  font-size: 24px;
  line-height: 28px;
  letter-spacing: -0.5px;
  text-align: center;
}

@media (min-width: 1024px) {
  .ilem-mq__title {
    font-size: 32px;
    line-height: 36px;
    letter-spacing: -1px;
  }
}

.ilem-mq__title a {
  color: inherit;
  text-decoration: underline;
  text-decoration-color: transparent;
  text-decoration-thickness: 2px;
  text-underline-offset: 6px;
  transition: text-decoration-color 300ms var(--mq-ease);
}

.ilem-mq__title a:hover,
.ilem-mq__title a:focus-visible {
  text-decoration-color: var(--color-secondary-1, #fdf4a7);
}

.ilem-mq__title a:focus-visible {
  outline: 2px solid var(--color-secondary-1, #fdf4a7);
  outline-offset: 4px;
}

/* fenetre pleine largeur, plafonnee a la largeur d'UNE copie (--mq-n logos, pose par le PHP)
   et a 1920 px : la boucle reste sans trou quel que soit le nombre de logos ;
   hauteur reservee (pas de CLS), bords en fondu */
.ilem-mq__viewport {
  max-width: min(1920px, calc(var(--mq-n, 9) * (var(--mq-item-w) + var(--mq-gap))));
  margin-inline: auto;
  overflow: hidden;
  height: var(--mq-item-h);
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 var(--mq-fade), #000 calc(100% - var(--mq-fade)), transparent 100%);
  mask-image: linear-gradient(90deg, transparent 0, #000 var(--mq-fade), #000 calc(100% - var(--mq-fade)), transparent 100%);
}

.ilem-mq__track {
  display: flex;
  width: max-content;
  animation: ilem-mq-scroll var(--mq-duration) linear infinite;
  will-change: transform;
}

/* chaque copie porte un gap de fin : -50 % de la piste = exactement une copie */
.ilem-mq__list {
  display: flex;
  flex: none;
  gap: var(--mq-gap);
  margin: 0;
  padding: 0 var(--mq-gap) 0 0;
  list-style: none;
}

.ilem-mq__item {
  position: relative;
  flex: none;
  width: var(--mq-item-w);
  height: var(--mq-item-h);
  isolation: isolate;
  list-style: none;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent), linear-gradient(180deg, transparent, #000 10%, #000 90%, transparent);
  -webkit-mask-composite: source-in;
  mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent), linear-gradient(180deg, transparent, #000 10%, #000 90%, transparent);
  mask-composite: intersect;
}

.ilem-mq__logo {
  display: block;
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: cover;
  object-position: 50% 50%;
  opacity: 0.72;
  transition: opacity 400ms var(--mq-ease);
}

/* desaturation : teinte du bandeau appliquee aux logos (le fond bleu ne bouge pas) */
.ilem-mq__item::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--color-primary-1, #09284c);
  mix-blend-mode: color;
  pointer-events: none;
  transition: opacity 400ms var(--mq-ease);
}

@keyframes ilem-mq-scroll {
  from {
    transform: translate3d(0, 0, 0);
  }
  to {
    transform: translate3d(-50%, 0, 0);
  }
}

/* pause : survol (pointeur fin seulement, pas de « hover collant » au toucher),
   focus clavier dans le bloc, ou hors ecran (classe posee par anim-marquee.js) */
@media (hover: hover) and (pointer: fine) {
  .ilem-mq__viewport:hover .ilem-mq__track {
    animation-play-state: paused;
  }

  .ilem-mq__item:hover .ilem-mq__logo {
    opacity: 1;
  }

  .ilem-mq__item:hover::after {
    opacity: 0;
  }
}

.ilem-mq:focus-within .ilem-mq__track,
.ilem-mq.is-offscreen .ilem-mq__track {
  animation-play-state: paused;
}

/* mouvement reduit : pas de defilement, rangee statique centree qui se replie */
@media (prefers-reduced-motion: reduce) {
  .ilem-mq__viewport {
    height: auto;
    -webkit-mask-image: none;
    mask-image: none;
  }

  .ilem-mq__track {
    width: auto;
    animation: none;
    will-change: auto;
  }

  .ilem-mq__list {
    flex-wrap: wrap;
    justify-content: center;
    padding: 0 20px;
    width: 100%;
  }

  .ilem-mq__list[aria-hidden="true"] {
    display: none;
  }

  /* mobile : 3 logos par rangee (3 rangees au lieu de 5) */
  @media (max-width: 1023px) {
    .ilem-mq {
      --mq-item-w: 108px;
      --mq-item-h: 54px;
    }
  }

  .ilem-mq__logo,
  .ilem-mq__item::after,
  .ilem-mq__title a {
    transition: none;
  }
}

@media print {
  .ilem-mq__track {
    animation: none;
  }
}

/* ===== anim-band.css ===== */
/* ==========================================================================
   Vague 2 - lot « bandeau » : charge seulement si ilem_v2() (cookie ilem_v2=1).
   Blocs .bloc.list.has-bg (accueil, /talents/) : au lieu d'afficher le fond
   jaune d'un coup, un bandeau de cette couleur se deroule depuis le bord de la
   fenetre jusqu'a l'image, puis le texte arrive en leger decalage.
   - Tout est pilote par assets/js/anim-band.js, qui pose data-band sur les
     entrees SOUS la ligne de flottaison au chargement. Sans JS / sans cookie /
     sous reduced-motion : aucun attribut -> rendu d'origine, rien de cache.
   - Le bandeau est un ::before de la cellule qui porte le fond (transform:
     scaleX uniquement, origine = bord exterieur, qui est aussi le bord de la
     fenetre) ; il reste dans la boite de la cellule -> aucun debordement.
   - En fin d'animation le JS retire data-band : le fond d'origine reprend sa
     place (meme couleur, meme rectangle) -> rendu final identique a l'existant.
   ========================================================================== */

.bloc.list.has-bg > .entry[data-band] {
  --band-dur: 850ms;
  --band-ease: cubic-bezier(0.2, 0.7, 0.2, 1);
  --band-text-delay: 320ms; /* le texte arrive quand le ruban a fait ~3/4 du chemin */
  --band-stagger: 90ms;
}

@media (max-width: 1023px) {
  .bloc.list.has-bg > .entry[data-band] {
    --band-dur: 550ms;
    --band-text-delay: 200ms;
    --band-stagger: 80ms;
  }
}

/* Le reveal generique (motion.js : fondu + montee de toute l'entree) est remplace
   pour ces entrees par la choregraphie ci-dessous (sinon le ruban arriverait
   lui-meme en fondu, effet « boueux »). */
.bloc.list.has-bg > .entry[data-band].reveal-pending,
.bloc.list.has-bg > .entry[data-band].reveal-in {
  opacity: 1;
  transform: none;
  transition: none;
}

/* ---------------------------------------------------------------- bandeau */
/* fond d'origine masque tant que le ruban joue */
.bloc.list.has-bg > .entry[data-band] .band-cell,
.bloc.list.has-bg > .entry[data-band].band-cell {
  background-color: transparent;
  position: relative;
  isolation: isolate; /* le ::before (z-index -1) reste sous le texte / l'image */
}

.bloc.list.has-bg > .entry[data-band] .band-cell::before,
.bloc.list.has-bg > .entry[data-band].band-cell::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  width: var(--band-w, 100%);
  z-index: -1;
  background-color: var(--color-secondary-1);
  transform: scaleX(0);
  pointer-events: none;
}

/* depart au bord gauche de la fenetre, deroulement vers la droite */
.bloc.list.has-bg > .entry[data-band][data-band-from="left"] .band-cell::before,
.bloc.list.has-bg > .entry[data-band][data-band-from="left"].band-cell::before {
  left: 0;
  transform-origin: 0 50%;
}

/* depart au bord droit de la fenetre, deroulement vers la gauche */
.bloc.list.has-bg > .entry[data-band][data-band-from="right"] .band-cell::before,
.bloc.list.has-bg > .entry[data-band][data-band-from="right"].band-cell::before {
  right: 0;
  transform-origin: 100% 50%;
}

.bloc.list.has-bg > .entry[data-band="pending"] .band-cell::before,
.bloc.list.has-bg > .entry[data-band="pending"].band-cell::before {
  will-change: transform;
}

.bloc.list.has-bg > .entry[data-band="in"] .band-cell::before,
.bloc.list.has-bg > .entry[data-band="in"].band-cell::before {
  transform: scaleX(1);
  transition: transform var(--band-dur) var(--band-ease);
  will-change: transform;
}

/* ------------------------------------------------- image + texte en cascade */
.bloc.list.has-bg > .entry[data-band] .image img,
.bloc.list.has-bg > .entry[data-band] .content .half-site-width > * {
  opacity: 0;
  transform: translate3d(0, 16px, 0);
}

.bloc.list.has-bg > .entry[data-band="in"] .image img,
.bloc.list.has-bg > .entry[data-band="in"] .content .half-site-width > * {
  opacity: 1;
  transform: none;
  transition:
    opacity 560ms var(--band-ease) var(--d, 0ms),
    transform 560ms var(--band-ease) var(--d, 0ms);
}

/* l'image accompagne le debut du ruban (elle n'est pas sur son trajet) */
.bloc.list.has-bg > .entry[data-band="in"] .image img {
  --d: 60ms;
}

/* titre, texte, boutons : par-dessus le ruban, 90 ms d'ecart */
.bloc.list.has-bg > .entry[data-band="in"] .content .half-site-width > :nth-child(1) {
  --d: var(--band-text-delay);
}

.bloc.list.has-bg > .entry[data-band="in"] .content .half-site-width > :nth-child(2) {
  --d: calc(var(--band-text-delay) + var(--band-stagger));
}

.bloc.list.has-bg > .entry[data-band="in"] .content .half-site-width > :nth-child(n + 3) {
  --d: calc(var(--band-text-delay) + 2 * var(--band-stagger));
}

/* ------------------------------------------------------- garde-fous */
@media (prefers-reduced-motion: reduce) {
  .bloc.list.has-bg > .entry[data-band] .band-cell,
  .bloc.list.has-bg > .entry[data-band].band-cell {
    background-color: var(--color-secondary-1);
  }

  .bloc.list.has-bg > .entry[data-band] .band-cell::before,
  .bloc.list.has-bg > .entry[data-band].band-cell::before {
    content: none;
  }

  .bloc.list.has-bg > .entry[data-band] .image img,
  .bloc.list.has-bg > .entry[data-band] .content .half-site-width > * {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
}

@media print {
  .bloc.list.has-bg > .entry[data-band] .band-cell,
  .bloc.list.has-bg > .entry[data-band].band-cell {
    background-color: var(--color-secondary-1);
  }

  .bloc.list.has-bg > .entry[data-band] .band-cell::before,
  .bloc.list.has-bg > .entry[data-band].band-cell::before {
    content: none;
  }

  .bloc.list.has-bg > .entry[data-band] .image img,
  .bloc.list.has-bg > .entry[data-band] .content .half-site-width > * {
    opacity: 1 !important;
    transform: none !important;
  }
}
