
/* Polices servies LOCALEMENT, sans requête tierce. SEULES déclarations
   @font-face du site : styles/site.css n'en répète aucune.

   Trois familles depuis le 19/09/2026 (client) : Archivo pour les titres,
   Roboto pour le texte courant, IBM Plex Mono 400 et 600 pour les
   étiquettes. Newsreader, puis Source Serif 4 qui l'avait remplacée le
   13/08, ne sont plus servies : les titres de la maquette passent en
   Archivo, voir §3bis bis de tools/cloner-reference.mjs. */
@font-face{font-family:'Archivo';src:url('/polices/archivo-latin-variable.woff2') format('woff2-variations');font-weight:100 900;font-style:normal;font-display:swap}
@font-face{font-family:'Archivo';src:url('/polices/archivo-latin-variable-italic.woff2') format('woff2-variations');font-weight:100 900;font-style:italic;font-display:swap}
@font-face{font-family:'IBM Plex Mono';src:url('/polices/ibm-plex-mono-latin-400.woff2') format('woff2');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:'IBM Plex Mono';src:url('/polices/ibm-plex-mono-latin-600.woff2') format('woff2');font-weight:600;font-style:normal;font-display:swap}
/* font-stretch DOIT etre declare ici, sinon le navigateur ignore l'axe de
   chasse du fichier et toute valeur de font-stretch rend la meme largeur.
   75 a 100 % est l'etendue de l'axe wdth de Roboto : 75 % donne le dessin
   de Roboto Condensed sans servir un second fichier. */
@font-face{font-family:'Roboto';src:url('/polices/roboto-latin-variable.woff2') format('woff2-variations');font-weight:100 900;font-stretch:75% 100%;font-style:normal;font-display:swap}

/* Fond photographique du hero (§3quater). Il vit ici et non dans un
   attribut style parce qu'il lui faut une variante allégée sur petit
   écran — 67 Ko au lieu de 176 — et qu'une media query ne s'écrit pas
   dans un attribut. La déclaration url() précède image-set() : les
   navigateurs qui ignorent image-set() gardent le JPEG, les autres
   écrasent avec le WebP. */
.fond-hero{
  background-image:url('/assets/photos/hero.jpg');
  background-image:image-set(url('/assets/photos/hero.webp') type('image/webp'),url('/assets/photos/hero.jpg') type('image/jpeg'));
  background-size:cover;
  background-position:center 42%;
  background-repeat:no-repeat;
}
@media (max-width:700px){
  .fond-hero{
    background-image:url('/assets/photos/hero-960.jpg');
    background-image:image-set(url('/assets/photos/hero-960.webp') type('image/webp'),url('/assets/photos/hero-960.jpg') type('image/jpeg'));
  }
}

/* Bande de navigation, deux états.

   L'ÉTAT PAR DÉFAUT est la bande claire — celui qui est lisible partout.
   C'est délibéré : sans JavaScript, aucune classe n'est posée, et le site
   reste parfaitement navigable (SPEC §2). Le script n'AJOUTE que l'état
   « sur le hero », qui est l'agrément, jamais la condition de lisibilité.

   Sur le hero, la bande porte un DÉGRADÉ DE BLANC (demande du client du
   15/08), dense en haut et qui s'allège vers le bas. Il n'est pas
   décoratif : le texte de navigation est en pétrole dans les DEUX états,
   et le pétrole ne tient pas sur une photo nue — mesuré, 100 % de la
   bande sous 4,5:1 sans ce voile. C'est lui qui rend la couleur lisible. */
/* La marge négative vit ICI et non dans l'attribut style : c'est elle qui
   met la barre en surimpression sur le hero, et le menu mobile doit
   pouvoir l'annuler. Or les classes extraites des attributs style sont
   écrites en FIN de feuille — à spécificité égale, elles gagneraient
   contre toute media query placée avant. */
.entete{
  margin-bottom:-88px;
  background:rgba(255,255,255,.94);
  backdrop-filter:blur(10px);
  -webkit-backdrop-filter:blur(10px);
  border-bottom:1px solid rgba(1,73,88,.12);
  box-shadow:0 1px 12px rgba(14,26,29,.10);
}

/* Les transitions n'existent qu'à partir de la classe « prete », posée au
   frame suivant le premier rendu. Sans ce délai, le passage à l'état
   « sur le hero » — que le script applique au chargement — s'ANIMERAIT :
   la bande claire apparaîtrait puis se dissoudrait sous les yeux du
   visiteur. On veut l'état initial d'emblée, et l'animation seulement
   pour les bascules provoquées par le défilement. */
.entete.prete{
  transition:background-color .25s ease,box-shadow .25s ease,border-color .25s ease;
}
.entete.prete .lien-nav{transition:color .18s ease}
.entete .lien-nav{color:var(--brand-petrole)}

/* Dégradé de blanc, le plus opaque en haut. Les trois opacités sont le
   réglage le PLUS TRANSPARENT qui garde le texte de navigation lisible :
   mesuré sur la photo réelle, .91/.77/.46 donne 4,67:1 au pire, et
   .90/.76/.44 tombe à 4,48 — sous le seuil de 4,5:1. Ce n'est donc pas
   une valeur de goût, c'est une limite. */
.entete.est-sur-hero{
  background:linear-gradient(180deg,rgba(255,255,255,.91) 0%,rgba(255,255,255,.77) 55%,rgba(255,255,255,.46) 100%);
  border-bottom-color:transparent;
  box-shadow:none;
}

/* Menu mobile — le balisage est piloté par src/scripts/menu-mobile.js.

   Tout est sous media query : au-dessus de 60rem, le bouton reste caché
   et la navigation garde exactement la disposition de la maquette.

   Sous 60rem, l'en-tête cesse de chevaucher le hero. C'est ce qui rend le
   repli sûr : la barre blanche grandit avec son contenu au lieu de le
   laisser déborder sur la photo, y compris SANS JavaScript, où la
   navigation reste déployée sur plusieurs lignes. */
.entete__bascule{
  display:none;
  align-items:center;
  gap:10px;
  background:none;
  border:0;
  padding:10px 2px;
  cursor:pointer;
  font:500 15.5px/1 'Archivo',sans-serif;
  letter-spacing:.02em;
  color:var(--brand-petrole);
}
.entete__bascule[hidden]{display:none}
.entete__bascule-icone{width:26px;height:26px}
.entete__bascule:hover,.entete__bascule:focus-visible{color:var(--brand-jaune)}

@media (max-width:60rem){
  .entete{margin-bottom:0}
  /* Sélecteur à deux classes, et non « .entete__barre » seul : la classe
     extraite de l'attribut style porte « height:88px » et est écrite plus
     bas dans la feuille. À 0-1-0 contre 0-1-0, elle l'emporterait, et la
     barre ne pourrait pas grandir pour accueillir le menu déployé. */
  .entete .entete__barre{
    grid-template-columns:1fr auto;
    height:auto;
    min-height:88px;
    row-gap:0;
  }
  .entete__bascule:not([hidden]){display:flex;grid-column:2;grid-row:1;justify-self:end}
  #navigation-principale{
    grid-column:1 / -1;
    grid-row:2;
    justify-self:stretch;
    flex-direction:column;
    align-items:stretch;
    justify-content:flex-start;
    gap:0;
  }
  #navigation-principale .lien-nav{
    padding:14px 0;
    text-align:left;
    border-top:1px solid rgba(1,73,88,.12);
  }
  /* Le bloc d'action suit la navigation : il se replie avec elle plutôt
     que de rester seul en travers de la barre. Il vise .entete__actions
     et non le bouton : depuis le 19/08 le bouton n'est plus enfant direct
     de la grille, il est dans ce conteneur avec le selecteur de langue. */
  .entete__barre > .entete__actions{
    grid-column:1 / -1;
    grid-row:3;
    justify-self:stretch;
    margin:4px 0 18px;
    flex-direction:column-reverse;
    align-items:stretch;
    gap:14px;
  }
  #navigation-principale[data-replie="true"],
  #navigation-principale[data-replie="true"] ~ .entete__actions{display:none}
}

/* Agrandissement ponctuel d'un logo partenaire (§4septies). Le facteur
   voyage dans une variable posée sur l'élément, pour que la règle reste
   valable quel que soit le logo concerné.

   Le seuil de 56.25rem (900 px) est celui au-dessus duquel la grille des
   partenaires tient sur UNE seule rangée. En dessous elle se replie, et
   le débordement d'un logo agrandi recouvrirait ses voisins. */
@media (min-width:56.25rem){
  .logo-agrandi{transform:scale(var(--echelle,1))}
}

/* Boutons de sortie de section (§4octies). Aplat pétrole au repos, jaune
   de la charte au survol — texte encre foncé, 9,2:1.

   LE BALAYAGE. Le jaune n'est pas une couleur de fond mais un DÉGRADÉ,
   dont seule la largeur est animée : de 0 à 100 %, ancré à gauche. D'où
   l'effet de tapis qu'on déroule, sans pseudo-élément ni balise en plus,
   et le texte reste au-dessus sans avoir à le repositionner — un fond
   est toujours derrière son contenu.

   C'est pour ça que les attributs style des trois boutons déclarent
   background-color et non le raccourci background : le raccourci
   remettrait background-image à zéro, et les classes extraites étant
   écrites plus bas dans la feuille, elles effaceraient le dégradé.

   La couleur du texte ne se FOND pas, elle BASCULE d'un coup à 0,19 s,
   soit aux trois quarts du balayage. Un fondu avait été essayé : il fait
   passer le texte par un gris intermédiaire pendant ~150 ms, illisible
   aussi bien sur le pétrole que sur le jaune. Une bascule sèche évite ce
   moment mort. Aucune couleur ne tient sur les deux fonds — clair sur
   jaune donne 1,55:1, foncé sur pétrole 1,37:1 — le compromis est donc
   de choisir QUAND basculer, pas de l'adoucir.

   MAINTENIR LE BLANC CASSÉ PENDANT TOUT LE SURVOL a été essayé le 17/08
   à la demande du client, puis annulé : le libellé tombait à 1,55:1 sur
   le jaune, contre 9,14:1 au repos.

   Sous prefers-reduced-motion, le balayage devient instantané : les
   couleurs changent, le mouvement disparaît. */
.bouton-plein{
  background-image:linear-gradient(to right,var(--brand-jaune) 0 100%);
  background-repeat:no-repeat;
  background-size:0 100%;
  transition:background-size .38s cubic-bezier(.22,.61,.36,1),color 0s linear .19s;
}
.bouton-plein:hover,.bouton-plein:focus-visible{
  background-size:100% 100%;
  color:var(--survol-texte,#0A2A26);
}
@media (prefers-reduced-motion:reduce){
  .bouton-plein{transition-duration:.01ms;transition-delay:0s}
}

/* Vidéo de fond du hero. Elle recouvre exactement la photo qui lui sert
   d'affiche, dans le même cadre : même recadrage, même point de fuite.
   L'affiche reste visible tant que la vidéo n'a pas de première image, et
   à jamais si aucune source ne correspond (petit écran, animations
   coupées, économie de données) — voir §3quater.

   object-position reprend le cadrage de la photo pour que le passage de
   l'une à l'autre ne fasse pas sauter l'image. */
.fond-hero__video{
  position:absolute;
  inset:0;
  width:100%;
  height:100%;
  object-fit:cover;
  object-position:center 42%;
  display:block;
}

/* Icônes de réseaux sociaux du pied de page (§4septdecies), en carrés
   arrondis.

   LA GÉOMÉTRIE N'EST PAS LIBRE : le client veut la rangée exactement
   alignée sur le logo au-dessus, bord gauche du premier carré sur le bord
   gauche du logo, bord droit du dernier sur son bord droit. Le logo fait
   144 px. Trois carrés et deux écarts doivent donc totaliser 144 :
   3 x 40 + 2 x 12 = 144. Ces valeurs se tiennent — changer la taille du
   logo oblige à les recalculer.

   40 px de côté reste sous les 44 px de confort tactile recommandés ;
   c'est la contrainte d'alignement qui l'impose, et on reste très
   au-dessus du minimum de 24 px de WCAG 2.5.8.

   LE VOILE A CHANGÉ DE SENS le 17/08, quand le haut du pied est passé au
   blanc : un voile clair sur fond clair ne se voit plus, et une icone en
   blanc casse y disparait. Voile sombre et icone en encre, donc, ce qui
   porte le pictogramme a 13,8:1 — tres au-dessus des 3:1 que WCAG 1.4.11
   demande.

   Jaune au survol ET au focus clavier, comme les liens de navigation. */
.lien-social{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  width:40px;
  height:40px;
  border-radius:8px;
  background:rgba(1,73,88,.14);
  color:var(--neutral-encre);
  transition:color .18s ease,background-color .18s ease;
}
.lien-social:hover,.lien-social:focus-visible{
  color:#0A3A34;
  background:var(--brand-jaune);
}

/* Plan du site : GRAS ET JAUNE au survol et au focus clavier (arbitrage
   du client, 17/08, apres essai du soulignement puis de l'aplat).

   QUATRE ETATS AURONT ETE MESURES AVANT CELUI-CI :

     texte en jaune      libelle a 1,53:1  — on ne lit plus le mot
     soulignement jaune  libelle a 15,90:1 — trait de 2 px a 1,53:1
     aplat jaune         libelle a 10,42:1 — aplat a 1,53:1
     gras + jaune        libelle a 1,53:1  — retenu

   LE CHIFFRE EST CONNU ET ASSUME : 1,53:1 contre les 4,5:1 exiges. Le
   gras epaissit le trait des lettres, ce qui aide a percevoir le
   changement d'etat, mais ne deplace pas le seuil — celui du gros texte
   ne commence qu'a 18,66 px en gras, et ces libelles font 14,08 px. La
   cause reste le fond : sur le vert tres pale du haut de pied, aucun
   emploi du jaune de marque en TEXTE n'atteint 4,5:1.

   Roboto est servie en variable de 100 a 900, donc le 700 est dessine et
   non synthetise. La boite du lien ne bouge pas : les liens sont des
   elements flex etires sur la largeur de la colonne, le gras s'y elargit
   sans rien deplacer autour. Le focus clavier est traite avec le survol,
   sans quoi la mise en valeur n'existerait qu'a la souris. */
.plan-du-site a,.plan-du-site button{transition:color .18s ease}
.plan-du-site a:hover,.plan-du-site a:focus-visible,
.plan-du-site button:hover,.plan-du-site button:focus-visible{
  color:var(--brand-jaune);
  font-weight:700;
}
@media (prefers-reduced-motion:reduce){
  .plan-du-site a,.plan-du-site button{transition-duration:.01ms}
}

/* Cartes « Ce que nous faisons » (§4quinquies) : titre seul en bas au
   repos, description devoilee au survol (demande du client, 18/08).

   LE RANG QUI S'OUVRE. Le bloc de texte est une grille de deux rangs :
   le titre en auto, la description en 0fr qui passe a 1fr. Le
   contenu etant colle en bas de la carte, l'ouverture du second rang
   POUSSE le titre vers le haut — c'est le mouvement demande, et il ne
   coute aucune valeur en dur : rien ne dit ici combien de lignes fait
   une description.

   min-height:0 et overflow:hidden sur le paragraphe sont
   indispensables : sans eux, la hauteur minimale automatique d'un
   element de grille l'empeche de descendre sous sa hauteur de contenu,
   et le rang a 0fr resterait ouvert.

   SI LE NAVIGATEUR N'ANIME PAS grid-template-rows (avant Chrome 107,
   Safari 17.2, Firefox 120), la description apparait d'un coup au lieu
   de se derouler. Le contenu reste accessible, seul le fondu disparait :
   c'est une degradation acceptable, pas une panne.

   AU TOUCHER, TOUT EST OUVERT. Il n'y a pas de survol au doigt : laisser
   la description derriere un :hover la rendrait inatteignable sur
   telephone. Sous pointer:coarse les cartes sont donc affichees
   ouvertes en permanence.

   :focus-within accompagne :hover : la carte est un <button>, elle
   s'atteint au clavier, et la description doit s'ouvrir la aussi. */
.carte-domaine__texte{
  display:grid;
  grid-template-rows:auto 0fr;
  transition:grid-template-rows .42s cubic-bezier(.22,.61,.36,1);
}
.carte-domaine__texte > p{
  min-height:0;
  overflow:hidden;
  opacity:0;
  transition:opacity .26s ease .06s;
}
.carte-domaine:hover .carte-domaine__texte,
.carte-domaine:focus-within .carte-domaine__texte{
  grid-template-rows:auto 1fr;
}
.carte-domaine:hover .carte-domaine__texte > p,
.carte-domaine:focus-within .carte-domaine__texte > p{
  opacity:1;
}

@media (pointer:coarse){
  .carte-domaine__texte{grid-template-rows:auto 1fr}
  .carte-domaine__texte > p{opacity:1}
}
@media (prefers-reduced-motion:reduce){
  .carte-domaine__texte,.carte-domaine__texte > p{transition-duration:.01ms}
}

/* Grille des domaines : 4 colonnes, puis 2, puis 1.

   LES SEUILS SORTENT DE LA LARGEUR DES CARTES, pas de tailles
   d'appareils. 68rem est la largeur au-dessous de laquelle une carte sur
   quatre passe sous 230 px — mesuree, c'est la ou un titre de trois mots
   commence a se couper. 34rem est celle ou une carte sur deux passe sous
   240 px, meme raison.

   LA REGLE SUR LES <div> N'EST PAS COSMETIQUE. Les deux blocs de bas de
   grille — le texte d'introduction et le bouton — portent
   grid-column:span 2. Sur une grille a UNE colonne, span 2 ne se contente
   pas de deborder : il cree une deuxieme colonne implicite, et toute la
   grille se retrouve a deux colonnes de largeurs inegales. Les remettre a
   auto est ce qui rend le passage a une colonne possible.

   Le selecteur > div ne touche que ces deux blocs : les cartes sont des
   <button>. */
.grille-domaines{grid-template-columns:repeat(4,minmax(0,1fr))}
@media (max-width:68rem){
  .grille-domaines{grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media (max-width:34rem){
  .grille-domaines{grid-template-columns:minmax(0,1fr)}
  .grille-domaines > div{grid-column:auto}
}

/* Grille des deux projets (§4nonies bis) : 2 colonnes, puis 1.

   40rem est la largeur au-dessous de laquelle une vignette sur deux
   passe sous 280 px — le meme seuil que la grille des actualites, qui
   l'obtient toute seule avec repeat(auto-fit,minmax(280px,1fr)). Meme
   contenu, meme largeur utile, donc meme valeur : une vignette 4/3
   surmontee d'un surtitre, d'un titre et d'une description.

   Pas de regle sur les enfants ici : la grille ne contient que les deux
   cartes, aucune ne porte de grid-column. */
.grille-projets{grid-template-columns:repeat(2,minmax(0,1fr))}
@media (max-width:40rem){
  .grille-projets{grid-template-columns:minmax(0,1fr)}
}

/* FONDS PHOTOGRAPHIQUES (fichiers du client, 18/08). L'image de chaque
   carte arrive par --carte-fond, posee par cloner-reference.mjs.

   LE VOILE N'EST PAS DECORATIF. Le titre est en #0A2A26 et la
   description en #3C4A47 : deux valeurs sombres qui ne tiennent sur
   aucune photo sans fond clair sous elles.

   IL NE COUVRE QUE LE BAS DE LA CARTE (demande du client, 18/08), la ou
   le texte se pose. Il n'est donc plus dimensionne en cover comme la
   photo, mais en hauteur propre, cale sur le bord bas. Au-dessus, la
   photo est nue.

   ET IL GRANDIT AVEC LE TEXTE. Au repos la carte n'affiche que son
   titre : 150 px suffisent. Au survol la description s'ouvre en dessous
   et la zone a couvrir descend d'autant : le voile passe a 270 px, dans
   le meme mouvement et sur la meme duree que le rang qui s'ouvre. Une
   hauteur fixe aurait force a prendre la plus grande des deux, donc a
   voiler au repos une bande vide de texte — exactement ce qu'on
   cherchait a supprimer.

   background-size est ANIMABLE, et c'est lui qu'on anime : la couleur du
   degrade ne bouge pas, seule la hauteur de sa boite change. Le degrade
   s'eteint a zero en haut, donc son bord superieur ne se voit pas, et
   une hauteur legerement trop grande ne coute rien.

   Les 270 px du survol tiennent le pire cas mesure : rembourrage bas 36,
   description jusqu'a 100 px quand elle passe a quatre lignes en colonne
   etroite, ecart 8, titre 46 — soit 190 px de texte, plus la zone de
   fondu.

   ALPHAS. Concentre sur 150 px au lieu des 406 px de la carte, le voile
   d'avant serait bien plus dense sous le texte. Les valeurs ont donc ete
   reprises a zero par balayage, en mesurant le PIXEL LE PLUS CLAIR sous
   chaque zone de texte — le pire cas — sur les quatre photos, a 1440 et
   a 390 px, au repos et au survol.

   Le voile est monte en PREMIERE couche de background-image : les
   couches se peignent de la derniere vers la premiere, donc la premiere
   est celle du dessus. Chaque couche a sa propre taille et sa propre
   position, dans le meme ordre.

   Pas de repli si --carte-fond manque : les quatre cartes ont leur
   image, et une carte sans fond garderait simplement l'aplat papier
   avec un voile clair pose dessus, ce qui ne se voit pas. */
.carte-domaine{
  background-image:linear-gradient(to top,rgba(250,248,243,.88) 0%,rgba(250,248,243,.72) 46%,rgba(250,248,243,0) 100%),var(--carte-fond);
  background-repeat:no-repeat;
  background-position:bottom center,center;
  background-size:100% 150px,cover;
  transition:background-size .42s cubic-bezier(.22,.61,.36,1);
}
.carte-domaine:hover,.carte-domaine:focus-within{
  background-size:100% 270px,cover;
}
@media (pointer:coarse){
  .carte-domaine{background-size:100% 270px,cover}
}
@media (prefers-reduced-motion:reduce){
  .carte-domaine{transition-duration:.01ms}
}

/* TITRES ALIGNES AU REPOS (demande du client, 18/08) : un titre d'une
   seule ligne doit se poser sur la PREMIERE ligne des titres qui en font
   deux, pas sur la seconde.

   Le contenu etant colle en bas de carte, un titre court remontait
   naturellement d'une ligne par rapport a un titre long. On reserve donc
   a tous les titres la hauteur de deux lignes, et le texte s'y range par
   le haut. 2.64em, c'est 2 x l'interligne de 1.32 declare sur le titre —
   exprime en em, donc juste quel que soit le corps.

   La valeur est un MINIMUM : si une largeur d'ecran faisait passer un
   titre a trois lignes, il grandirait et l'alignement se perdrait sur
   cette carte-la. Verifie de 320 a 1920 px, aucun titre ne depasse deux
   lignes. */
.carte-domaine h3{
  min-height:2.64em;
}

/* Bloc d'action de l'en-tete : selecteur de langue + bouton d'appel
   (§3sexies). Il occupe la troisieme colonne de la grille, celle que le
   bouton occupait seul avant le partage de l'en-tete avec le reste du
   site.

   LE SELECTEUR EST RESTYLE POUR CETTE BARRE. site.css le dessine en
   blanc, pour l'ancien en-tete pose sur un aplat sombre ; ici la bande
   est claire et le blanc y serait invisible. Les regles sont montees a
   .entete .selecteur-langue__lien (0-2-0) pour passer devant celles de
   site.css (0-1-0) quel que soit l'ordre de chargement des feuilles.

   Jaune au survol, comme les liens de navigation voisins : meme
   traitement, et meme reserve mesuree — le jaune de marque sur cette
   bande claire ne tient pas les 4,5:1. C'est le choix pose par le client
   pour la navigation, applique ici par coherence. */
.entete__actions{
  justify-self:end;
  display:flex;
  align-items:center;
  gap:clamp(12px,1.6vw,22px);
}
/* Le panneau est en POSITION ABSOLUE, et c'est ce qui rend le repli
   inoffensif : deroule, il se pose PAR-DESSUS la page au lieu de
   pousser la barre de navigation et de faire sauter tout le contenu. Le
   z-index le place devant les sections. */
.entete .selecteur-langue__boite{position:relative}
.entete .selecteur-langue__actuel{
  display:inline-flex;
  align-items:center;
  gap:6px;
  font:600 12px/1 'IBM Plex Mono',monospace;
  letter-spacing:.08em;
  color:var(--brand-petrole);
  padding:8px 10px;
  border:1px solid rgba(1,73,88,.22);
  border-radius:2px;
  cursor:pointer;
  user-select:none;
  transition:color .18s ease,border-color .18s ease;
}
/* Le triangle par defaut de <summary> est retire dans les deux syntaxes
   qui existent : la standard et celle, prefixee, de WebKit. Sans les
   deux, un chevron se retrouve a cote de l'autre. */
.entete .selecteur-langue__actuel{list-style:none}
.entete .selecteur-langue__actuel::-webkit-details-marker{display:none}
.entete .selecteur-langue__actuel:hover,
.entete .selecteur-langue__actuel:focus-visible{
  color:var(--brand-jaune);
  border-color:rgba(1,73,88,.42);
}
.entete .selecteur-langue__chevron{transition:transform .18s ease}
.entete .selecteur-langue__boite[open] .selecteur-langue__chevron{transform:rotate(180deg)}
.entete .selecteur-langue__liste{
  position:absolute;
  top:calc(100% + 6px);
  right:0;
  z-index:200;
  display:flex;
  flex-direction:column;
  gap:2px;
  min-width:100%;
  list-style:none;
  margin:0;
  padding:6px;
  background:#FFFFFF;
  border:1px solid rgba(1,73,88,.16);
  border-radius:2px;
  box-shadow:0 6px 20px rgba(14,26,29,.14);
}
.entete .selecteur-langue__lien{
  display:block;
  font:600 12px/1 'IBM Plex Mono',monospace;
  letter-spacing:.08em;
  color:var(--brand-petrole);
  text-decoration:none;
  padding:8px 12px;
  border:0;
  border-radius:2px;
  white-space:nowrap;
  transition:color .18s ease,background-color .18s ease;
}
.entete .selecteur-langue__lien[aria-current="true"]{
  color:#0A2A26;
  background:rgba(1,73,88,.10);
}
.entete .selecteur-langue__lien:hover,
.entete .selecteur-langue__lien:focus-visible{color:var(--brand-jaune)}

/* Sous 60rem la barre s'empile et le bloc d'action s'etire : le panneau
   se cale alors a gauche, sous le bouton, plutot que de deborder a
   droite. */
@media (max-width:60rem){
  .entete .selecteur-langue__actuel{justify-content:center}
  .entete .selecteur-langue__liste{right:auto;left:0}
}

/* Pages interieures : l'en-tete ne chevauche pas leur mini hero, il ne
   doit donc pas remonter le contenu de 88 px sous lui. La classe est
   posee sur <body> par base.njk ; 0-2-0 passe devant le .entete de la
   maquette quel que soit l'ordre des feuilles. */
.page-interieure .entete{margin-bottom:0}

/* Mini hero des pages interieures (partials/hero-mini.njk).

   50vh, LA MOITIE DES 100vh DU HERO DE L'ACCUEIL. Le rapport est exprime
   dans la meme unite que l'original : en pixels il ne vaudrait que pour
   une taille d'ecran.

   Un PLANCHER de 320 px l'accompagne. Sur un telephone couche, 50vh
   tombe sous 200 px : le titre y toucherait les deux bords. Le plancher
   ne se declenche que la, et ne change rien en portrait ni en desktop.

   LE VOILE EST PLUS DENSE QUE CELUI DE L'ACCUEIL, et c'est la hauteur
   qui l'impose. Sur l'accueil le titre vit dans le tiers bas de l'image,
   la ou le degrade est le plus charge ; ici il occupe toute la bande, y
   compris le haut que l'accueil laisse clair. Le voile est donc uniforme
   et plus soutenu — valeur mesuree sur la photo reelle, voir la note du
   rapport de generation. */
.hero-mini{
  position:relative;
  min-height:max(50vh,320px);
  display:flex;
  align-items:flex-end;
  overflow:hidden;
  color:#F3F1EA;
}
.hero-mini__fond{position:absolute;inset:0}
.hero-mini__voile{
  position:absolute;
  inset:0;
  background:linear-gradient(180deg,rgba(1,88,80,.62) 0%,rgba(1,88,80,.70) 60%,rgba(1,88,80,.78) 100%);
}
/* Le titre est cale en bas du hero ; c'est donc le rembourrage BAS qui
   determine sa hauteur dans la bande. Remonte le 20/08 a la demande du
   client : clamp(32px,5vw,64px) → clamp(48px,7vw,100px). */
.hero-mini__contenu{
  position:relative;
  width:100%;
  max-width:1280px;
  margin:0 auto;
  padding:clamp(32px,5vw,64px) clamp(20px,4vw,56px) clamp(48px,7vw,100px);
}
/* Titre reduit le 20/08 a la demande du client : de clamp(1.7,4.2vw,3.4)
   a clamp(1.4,3.2vw,2.6). Les trois bornes baissent ensemble, sinon le
   rapport ne vaudrait qu'a une largeur. */
.hero-mini__titre{
  font:italic 900 clamp(1.4rem,3.2vw,2.6rem)/1.1 'Archivo',sans-serif;
  letter-spacing:-.02em;
  margin:0;
  max-width:24ch;
  color:#F3F1EA;
}
/* SUR ECRAN D'ORDINATEUR, LE TITRE TIENT SUR UNE LIGNE (demande du
   client, 20/08). Deux choses l'en empechaient : la largeur maximale de
   24ch, qui le repliait bien avant le bord, et la taille, trop grande
   pour que le plus long titre du site passe en une ligne.

   LES DEUX TERMES DU min() NE PROTEGENT PAS LA MEME CHOSE, et c'est ce
   qui permet d'agrandir sans casser la ligne unique. Le conteneur du hero
   est plafonne a 1280 px : au-dela, la largeur disponible ne bouge plus,
   alors que 2,3vw continuerait de croitre. C'est donc le PLAFOND EN rem
   qui tient les grands ecrans, et le terme en vw qui dessine tout le
   reste.

   Agrandi le 20/08 a la demande du client : 2vw → 2,3vw, plafond
   inchange a 2,1rem. Mesure du plus long titre du site — celui de cette
   page, 63 signes — rapportee a la largeur disponible :

     1024 px   73 % → 84 %
     1440 px   82 % → 95 %
     1920 px   96 % → 96 %   (plafond atteint, rien ne change)

   PAS DE white-space:nowrap. Le mini hero sert toutes les pages : un
   titre plus long que celui-ci deborderait de la fenetre au lieu de se
   replier. En le laissant se replier, le pire cas reste deux lignes. */
@media (min-width:64rem){
  .hero-mini__titre{
    max-width:none;
    font-size:min(2.3vw,2.1rem);
  }
}
/* Tag du mini hero : meme registre que les surtitres de section de
   l'accueil — mono, capitales, interlettrage large — mais en jaune de
   marque, seule couleur d'accent qui tienne sur le voile vert. Mesure a
   l'appui : 5,8:1 contre le voile, la ou le petrole tomberait a 1,3:1. */
.hero-mini__tag{
  font:400 11px/1 'IBM Plex Mono',monospace;
  letter-spacing:.18em;
  text-transform:uppercase;
  color:var(--brand-jaune);
  margin:0 0 clamp(14px,1.6vw,20px);
}

/* Bouton aimante du hero (§4ter bis). Le deplacement est calcule par
   src/scripts/aimant.js, qui n'ecrit que deux variables : --aimant-x et
   --aimant-y. Tout le reste est ici.

   POURQUOI DES VARIABLES ET NON UN transform ECRIT PAR LE SCRIPT : la
   forme du transform reste dans la feuille, donc modifiable sans
   toucher au script, et surtout le RETOUR au repos est une simple
   transition CSS sur des variables remises a zero. Aucune boucle
   d'animation ne tourne.

   Le retour est plus long que la poursuite (.45s contre .12s) : on suit
   le curseur au plus pres tant qu'il est la, et on se detend en douceur
   quand il part. La courbe du retour depasse legerement puis revient,
   ce qui donne le rappel elastique de l'aimant qu'on lache.

   Le survol garde son propre changement de couleur, s'il en a un : cette
   regle ne touche qu'au transform. */
.bouton-aimante{
  transform:translate3d(var(--aimant-x,0),var(--aimant-y,0),0);
  transition:transform .45s cubic-bezier(.34,1.56,.64,1);
}
.bouton-aimante[data-aimante="oui"]{
  transition:transform .12s ease-out;
}
/* Mouvement coupe net si le visiteur le demande. Le script s'arrete de
   lui-meme dans ce cas, cette regle est la ceinture. */
@media (prefers-reduced-motion:reduce){
  .bouton-aimante{transform:none;transition:none}
}

/* Défilement horizontal continu des témoignages (§4duodecies).

   La piste contient DEUX fois la série de cartes et se translate de
   -50 % : au terme du cycle, la copie occupe exactement la place de
   l'original, et le retour à zéro ne se voit pas. width:max-content
   empêche la piste de se contraindre à la largeur de son conteneur.

   La copie est un simple conteneur display:contents : elle ne crée
   aucune boîte, les cartes restent des enfants directs de la piste et
   l'espacement reste régulier de part et d'autre de la jointure.

   Le défilement s'arrête au survol et au focus clavier — sans quoi un
   texte qu'on essaie de lire s'échapperait, et une carte atteinte au
   clavier continuerait de fuir.

   Durée calée sur ~40 px/s : assez lent pour se lire, assez vif pour
   qu'on voie que ça bouge.

   L'ESPACEMENT N'EST PAS UN gap, ET CE N'EST PAS UN DETAIL. Avec un gap,
   la piste mesure 12 cartes + 11 ecarts ; la moitie de cette largeur
   vaut 6 cartes + 5,5 ecarts, alors qu'une serie complete vaut 6 cartes
   + 6 ecarts. La boucle saute donc d'un demi-ecart a chaque tour. Chaque
   carte porte donc SA marge droite : la piste vaut 12 x (carte + marge),
   la moitie vaut exactement une serie, et le raccord est juste quelle
   que soit la valeur.

   L'ecart est repasse a 2 px le 18/08, la valeur de la maquette, apres
   un essai a 20 px. Le mecanisme de marge, lui, est conserve : a 2 px le
   gap d'origine decalait la boucle d'un pixel a chaque tour — invisible,
   mais faux. Ce n'est plus le cas.

   La marge est posee sur les enfants des DEUX conteneurs : la copie est
   en display:contents, elle ne cree aucune boite, une marge posee sur
   elle serait ignoree. */
.defilement__piste{
  display:flex;
  gap:0;
  width:max-content;
  animation:defiler 45s linear infinite;
}
.defilement__piste > *,
.defilement__copie > *{margin-right:2px}
.defilement__copie{display:contents}
.defilement:hover .defilement__piste,
.defilement:focus-within .defilement__piste{animation-play-state:paused}
@keyframes defiler{
  from{transform:translateX(0)}
  to{transform:translateX(-50%)}
}

/* Animations coupées : la piste s'immobilise et le défilement manuel
   reprend ses droits, sinon les derniers témoignages deviendraient
   inatteignables. */
@media (prefers-reduced-motion:reduce){
  .defilement__piste{animation:none}
  .defilement > div:last-of-type{overflow-x:auto}
}

/* Navigation principale : jaune au survol et au focus clavier. Le focus
   est traité avec le survol, sans quoi la mise en valeur n'existerait
   qu'à la souris.

   Les sélecteurs sont montés en spécificité pour passer devant les règles
   d'état ci-dessus (0-2-0 et 0-3-0) : sans ça, le survol serait sans
   effet dès que la bande porte une classe d'état. */
.entete .lien-nav:hover,.entete .lien-nav:focus-visible{color:var(--brand-jaune)}


/* Lien d'évitement — seul ajout au style de la référence. Il ne se voit
   qu'au clavier et ne modifie donc pas le rendu de la page. */
.lien-evitement{position:absolute;left:8px;top:8px;z-index:300;transform:translateY(-200%);background:var(--brand-jaune);color:#0A3A34;font:600 13px/1 'Archivo',sans-serif;text-decoration:none;padding:12px 20px;border-radius:2px}
.lien-evitement:focus{transform:translateY(0)}
main:focus{outline:none}
a:focus-visible,button:focus-visible{outline:3px solid var(--brand-jaune);outline-offset:2px}

/* Les <button> de la maquette devenus <a> : un bouton est inline-block et
   centre son texte, un lien est inline. Sans ces deux déclarations, le
   rembourrage ne pousserait pas la ligne et la boîte différerait.

   Sélecteur de classe SIMPLE, et non « a.lien-maquette » : les styles de
   la maquette sont désormais des classes eux aussi (voir §3bis), à
   spécificité 0-1-0. Une règle « a.lien-maquette » (0-1-1) l'emporterait
   sur elles et recentrerait, par exemple, les liens du pied de page que
   la maquette aligne à gauche. À spécificité égale, c'est l'ordre qui
   tranche : les classes de la maquette sont écrites après, donc gagnent —
   exactement ce que faisait l'attribut style="" avant. */
.lien-maquette{display:inline-block;text-align:center;box-sizing:border-box}

/* CIBLES TACTILES DU PIED DE PAGE (25/09/2026), mesurées à 390 px.
 *
 * Trois relevés au téléphone :
 *   — les cinq liens du plan du site faisaient 25 px de haut. Pleine
 *     largeur, donc faciles à viser horizontalement, mais 25 px de
 *     hauteur pour cinq lignes empilées, c'est le doigt qui décide ;
 *   — les icônes de réseaux faisaient 40 px de côté : au-dessus du
 *     plancher de 24 px du critère WCAG 2.5.8, sous le confort de 44 px
 *     du critère 2.5.5 ;
 *   — les deux liens légaux s'affichaient en 10,5 px, la taille de la
 *     petite ligne de la maquette.
 *
 * TOUT EST SOUS MEDIA QUERY, et rien ne change au-dessus de 48rem : le
 * pied garde la disposition de la maquette sur ordinateur, où la souris
 * n'a pas besoin de 44 px. La demande venait du mobile, la réponse y
 * reste.
 *
 * LES SÉLECTEURS SONT SÉMANTIQUES — .plan-du-site, .lien-social,
 * .lien-legal — et jamais des classes .mNN : celles-là sont NUMÉROTÉES
 * dans l'ordre d'extraction des attributs style de la maquette, et une
 * règle écrite à la main qui les viserait changerait de cible en silence
 * le jour où reference/index.html évolue. C'est aussi pourquoi la ligne
 * de copyright garde ses 10,5 px : elle n'a pas de classe sémantique, et
 * la corriger demanderait de viser .m92. */
@media (max-width:48rem){
  .plan-du-site a{padding-block:10px}
  .lien-social{width:44px;height:44px}
  /* « inline-block » EST NÉCESSAIRE AVANT LE REMBOURRAGE : un lien en
     ligne ignore les rembourrages haut et bas pour le calcul de sa boîte,
     et la cible n'aurait pas grandi. Les deux liens passent ainsi de 15 à
     35 px de hauteur, sans atteindre 44 — la bande légale ne peut pas
     grandir davantage sans devenir un bloc à elle seule.

     PAS D'ACCENT GRAVE DANS CE COMMENTAIRE : il vit dans un gabarit
     JavaScript, et un accent grave y fermerait la chaîne. Le cloneur a
     refusé de se charger pour cette raison le 25/09/2026. */
  .lien-legal{font-size:12px;display:inline-block;padding-block:10px}
}
* { box-sizing: border-box; }
  body { margin: 0; font-family: 'Roboto', sans-serif; }
  button { font-family: inherit; }
  a { text-decoration: none; }

  

  /* Étiquettes de zone fictive */
  .exemple {
    position: relative;
    outline: 2px dashed var(--brand-jaune);
    outline-offset: -2px;
  }
  .exemple::before {
    content: attr(data-exemple);
    position: absolute; top: 8px; right: 8px; z-index: 5;
    background: #0A2A26; color: var(--brand-jaune);
    font: 700 9.5px/1 'IBM Plex Mono', monospace;
    letter-spacing: .08em; text-transform: uppercase;
    padding: 5px 9px;
  }
  .tag-exemple {
    display: inline-block; margin-top: 10px;
    background: #0A2A26; color: var(--brand-jaune);
    font: 700 9.5px/1 'IBM Plex Mono', monospace;
    letter-spacing: .06em; text-transform: uppercase;
    padding: 5px 9px;
  }

  /* Étiquette de champ non sourcé (composé, pas verbatim JSON) */
  .a-verifier { outline: 2px dotted var(--brand-jaune); outline-offset: -2px; }

  @keyframes fadein { from{opacity:0} to{opacity:1} }

/* Styles de la maquette, extraits des attributs style="" par
   tools/cloner-reference.mjs. Ne pas modifier à la main : ce bloc est
   réécrit à chaque `npm run cloner`. */
.m1{position:sticky;top:0;left:0;right:0;z-index:50}
.m2{max-width:1280px;margin:0 auto;padding:0 clamp(20px,4vw,56px);height:88px;display:grid;grid-template-columns:1fr auto 1fr;align-items:center;gap:24px}
.m3{display:flex;align-items:center;background:none;border:0;padding:0;cursor:pointer;justify-self:start;margin-left:calc(clamp(20px,4vw,56px) * -0.55)}
.m4{width:76px;height:76px;object-fit:contain}
.m5{display:flex;align-items:center;gap:clamp(10px,2vw,32px);flex-wrap:wrap;justify-content:center;justify-self:center}
.m6{position:relative;background:none;border:0;padding:10px 2px;cursor:pointer;font:500 15.5px/1 'Archivo',sans-serif;letter-spacing:.02em;color:#F3F1EA}
.m7{justify-self:end;background:var(--brand-jaune);color:#0A3A34;border:0;padding:12px 22px;border-radius:2px;font:600 13px/1 'Archivo',sans-serif;letter-spacing:.03em;cursor:pointer;white-space:nowrap}
.m8{position:relative;color:#F3F1EA;overflow:hidden;min-height:100vh;display:flex;flex-direction:column}
.m9{position:absolute;inset:0}
.m10{position:absolute;inset:0;background:linear-gradient(180deg,rgba(1,88,80,0) 50%,rgba(1,88,80,.26) 60%,rgba(1,88,80,.48) 66%,rgba(1,88,80,.56) 100%),rgba(1,88,80,.20)}
.m11{position:relative;z-index:2;max-width:1280px;margin:0 auto;padding:clamp(20px,4vw,56px);flex:1;display:flex;flex-direction:column;justify-content:center;align-items:center;width:100%}
.m12{max-width:96ch;display:flex;flex-direction:column;align-items:center;text-align:center}
.m13{font:italic 900 clamp(1.95rem,6.2vw,5.2rem)/1.04 'Archivo',sans-serif;letter-spacing:-.02em;margin:clamp(128px,23vh,320px) auto 26px;text-align:center}
.m14{position:relative;z-index:2;padding:0 clamp(20px,4vw,56px) clamp(28px,3.5vw,48px);display:flex;flex-direction:column;align-items:center;gap:22px;text-align:center}
.m15{font:400 1.02rem/1.7 'Roboto',sans-serif;color:#F3F1EA;max-width:60ch;margin:0}
.m16{background:var(--brand-jaune);color:#0A3A34;border:0;padding:16px 28px;border-radius:2px;font:600 14px/1 'Archivo',sans-serif;letter-spacing:.03em;cursor:pointer}
.m17{background:#FBFAF7;color:#0A2A26}
.m18{max-width:1280px;margin:0 auto;padding:clamp(36px,4vw,60px) clamp(20px,4vw,56px)}
.m19{font:600 clamp(1.7rem,4.4vw,3.1rem)/1.1 'Archivo',sans-serif;letter-spacing:-.01em;margin:0 0 14px;color:var(--brand-petrole);display:flex;flex-wrap:wrap;justify-content:center;gap:20px;text-align:center}
.m20{color:var(--brand-petrole)}
.m21{font:400 1.05rem/1.4 'Archivo',sans-serif;color:#494846;margin:0 0 22px;font-style:italic;text-align:center}
.m22{text-decoration-line:none}
.m23{max-width:66ch;margin:0 auto}
.m24{font:400 1.02rem/1.7 'Roboto',sans-serif;color:#3C4A47;margin:0 auto 20px;max-width:66ch;text-align:center}
.m25{font:400 1.02rem/1.7 'Archivo',sans-serif;color:#3C4A47;margin:0 auto 32px;max-width:66ch;text-align:center;font-style:italic}
.m26{display:flex;justify-content:center}
.m27{--survol-texte:#0A3A34;background-color:var(--brand-petrole);color:var(--neutral-papier);border:0;padding:16px 28px;border-radius:2px;font:600 14px/1 'Archivo',sans-serif;letter-spacing:.03em;cursor:pointer}
.m28{background:#FFFFFF;border-bottom:1px solid rgba(11,31,28,.08)}
.m29{max-width:1280px;margin:0 auto;padding:clamp(22px,2.25vw,37px) clamp(20px,4vw,56px) clamp(44px,4.5vw,74px)}
.m30{max-width:62ch;margin:0 0 clamp(28px,3vw,42px)}
.m31{font:400 11px/1 'IBM Plex Mono',monospace;letter-spacing:.18em;text-transform:uppercase;color:var(--brand-petrole)}
.m32{font:600 clamp(1.7rem,4.4vw,3.1rem)/1.1 'Archivo',sans-serif;letter-spacing:-.01em;margin:20px 0 14px;color:var(--brand-petrole)}
.m33{display:grid;gap:clamp(16px,2vw,24px)}
.m34{--carte-fond:url(/assets/photos/cartes/domaine-ingenierie.webp);background-color:var(--neutral-papier);border:1px solid rgba(11,31,28,.14);border-radius:10px;cursor:pointer;padding:clamp(28px,3vw,36px) clamp(24px,2.6vw,28px);display:flex;flex-direction:column;justify-content:flex-end;min-height:406px;gap:20px;text-align:left}
.m35{font:600 1.08rem/1.32 'Archivo',sans-serif;margin:0 0 8px;color:#0A2A26;letter-spacing:-.005em}
.m36{font:400 .92rem/1.7 'Roboto',sans-serif;margin:0;color:#0A3A34}
.m37{--carte-fond:url(/assets/photos/cartes/domaine-genie-civil.webp);background-color:var(--neutral-papier);border:1px solid rgba(11,31,28,.14);border-radius:10px;cursor:pointer;padding:clamp(28px,3vw,36px) clamp(24px,2.6vw,28px);display:flex;flex-direction:column;justify-content:flex-end;min-height:406px;gap:20px;text-align:left}
.m38{--carte-fond:url(/assets/photos/cartes/domaine-menuiserie.webp);background-color:var(--neutral-papier);border:1px solid rgba(11,31,28,.14);border-radius:10px;cursor:pointer;padding:clamp(28px,3vw,36px) clamp(24px,2.6vw,28px);display:flex;flex-direction:column;justify-content:flex-end;min-height:406px;gap:20px;text-align:left}
.m39{--carte-fond:url(/assets/photos/cartes/domaine-commerce.webp);background-color:var(--neutral-papier);border:1px solid rgba(11,31,28,.14);border-radius:10px;cursor:pointer;padding:clamp(28px,3vw,36px) clamp(24px,2.6vw,28px);display:flex;flex-direction:column;justify-content:flex-end;min-height:406px;gap:20px;text-align:left}
.m40{grid-column:span 2;display:flex;align-items:center}
.m41{font:400 1.08rem/1.6 'Roboto',sans-serif;margin:0;color:#0A2A26;text-align:left}
.m42{grid-column:span 2;display:flex;align-items:center;justify-content:flex-start}
.m43{background-color:var(--brand-petrole);color:var(--neutral-papier);border:0;padding:16px 28px;border-radius:2px;font:600 14px/1 'Archivo',sans-serif;letter-spacing:.03em;cursor:pointer}
.m44{background:#014958}
.m45{padding:clamp(44px,4.6vw,64px) 0 clamp(32px,3.4vw,48px);text-align:center}
.m46{font:600 clamp(1.7rem,4.4vw,3.1rem)/1.1 'Archivo',sans-serif;letter-spacing:-.01em;margin:0;color:#F3F1EA}
.m47{overflow:hidden;padding:0 10px clamp(56px,6vw,84px);scrollbar-width:none}
.m48{flex:0 0 clamp(240px,22vw,300px);padding:24px;display:flex;flex-direction:column;gap:16px;justify-content:space-between;min-height:176px;background-color:#F5EFE4}
.m49{font:400 .92rem/1.6 'Roboto',sans-serif;color:#3C4A47;margin:0}
.m50{font:700 .82rem/1.4 'Roboto',sans-serif;letter-spacing:.02em;text-transform:uppercase;color:#12211E;margin:0 0 4px}
.m51{font:400 .78rem/1.4 'Roboto',sans-serif;color:#6B6258;margin:0}
.m52{max-width:1280px;margin:0 auto;padding:clamp(34px,3.6vw,58px) clamp(20px,4vw,56px) clamp(44px,4.5vw,74px)}
.m53{display:flex;justify-content:space-between;align-items:flex-end;gap:32px;flex-wrap:wrap;margin-bottom:52px}
.m54{font:600 clamp(1.7rem,4.4vw,3.1rem)/1.1 'Archivo',sans-serif;letter-spacing:-.01em;margin:20px 0 0;color:var(--brand-petrole)}
.m55{display:grid;gap:clamp(20px,2.4vw,32px)}
.m56{text-align:left;background:none;border:0;padding:0;cursor:pointer;display:flex;flex-direction:column;gap:18px}
.m57{position:relative;aspect-ratio:4/3;overflow:hidden;border:1px solid rgba(11,31,28,.12)}
.m58{width:100%;height:100%;object-fit:cover;display:block}
.m59{font:400 11px/1 'IBM Plex Mono',monospace;letter-spacing:.12em;text-transform:uppercase;color:var(--brand-petrole)}
.m60{font:600 1.28rem/1.28 'Archivo',sans-serif;margin:12px 0 8px;color:#0A2A26}
.m61{font:400 .93rem/1.6 'Roboto',sans-serif;color:#5C6764;margin:0}
.m62{background:#F1EEE6}
.m63{max-width:1280px;margin:0 auto;padding:clamp(22px,2.25vw,35px) clamp(20px,4vw,56px) clamp(44px,4.5vw,70px)}
.m64{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:clamp(20px,2.4vw,32px)}
.m65{font:600 1.18rem/1.28 'Archivo',sans-serif;margin:12px 0 8px;color:#0A2A26}
.m66{font:400 .93rem/1.6 'Roboto',sans-serif;color:#5C6764;margin:0}
.m67{background:#014958;border-bottom:1px solid rgba(11,31,28,.1)}
.m68{max-width:1280px;margin:0 auto;padding:clamp(32px,3.5vw,50px) clamp(20px,4vw,56px)}
.m69{font:400 11px/1 'IBM Plex Mono',monospace;letter-spacing:.18em;text-transform:uppercase;color:var(--brand-jaune)}
.m70{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:20px;margin-top:28px}
.m71{aspect-ratio:16/9;display:flex;align-items:center;justify-content:center;padding:14px}
.m72{max-width:100%;max-height:100%;width:auto;height:auto;object-fit:contain}
.m73{font:500 11px/1.3 'Archivo',sans-serif;color:#F3F1EA;text-align:center}
.m74{--echelle:2.5;max-width:100%;max-height:100%;width:auto;height:auto;object-fit:contain}
.m75{max-width:1280px;margin:0 auto;padding:clamp(88px,9vw,140px) clamp(20px,4vw,56px);display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:clamp(32px,5vw,72px);align-items:center}
.m76{font:600 clamp(1.7rem,4.4vw,3.1rem)/1.1 'Archivo',sans-serif;letter-spacing:-.01em;margin:0;color:var(--brand-petrole);max-width:16ch}
.m77{font:400 1.06rem/1.7 'Roboto',sans-serif;color:#3C4A47;margin:0 0 30px;max-width:48ch}
.m78{display:flex;gap:14px;flex-wrap:wrap}
.m79{background-color:var(--brand-petrole);color:var(--neutral-papier);border:0;padding:17px 30px;border-radius:2px;font:600 14px/1 'Archivo',sans-serif;letter-spacing:.03em;cursor:pointer}
.m80{display:inline-flex;align-items:center;padding:17px 30px;border:1px solid rgba(11,31,28,.28);border-radius:2px;font:600 14px/1 'Archivo',sans-serif;letter-spacing:.03em;color:#0A2A26}
.m81{background:#EDF4F2;color:var(--neutral-encre)}
.m82{max-width:1280px;margin:0 auto;padding:clamp(48px,5.5vw,72px) clamp(20px,4vw,56px) clamp(24px,2.75vw,36px);display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:clamp(28px,4vw,56px)}
.m83{width:144px;height:144px;object-fit:contain;margin-bottom:18px}
.m84{display:flex;gap:12px;align-items:center}
.m85{font:600 10.5px/1 'IBM Plex Mono',monospace;letter-spacing:.14em;text-transform:uppercase;color:var(--brand-petrole)}
.m86{display:flex;flex-direction:column;gap:12px;margin-top:18px}
.m87{background:none;border:0;padding:0;cursor:pointer;text-align:left;font:400 .88rem/1.8 'Roboto',sans-serif;letter-spacing:.03em;color:var(--neutral-encre)}
.m88{font:400 .88rem/1.8 'Roboto',sans-serif;letter-spacing:.03em;text-transform:uppercase;margin:18px 0 0;color:var(--neutral-encre)}
.m89{font:400 .88rem/1.8 'Roboto',sans-serif;letter-spacing:.03em;margin:18px 0 0;color:var(--neutral-encre)}
.m90{color:var(--neutral-encre)}
.m91{background:#0A3A34;padding:22px calc(max(0px,(100% - 1280px)/2) + clamp(20px,4vw,56px)) 40px;border-top:1px solid rgba(243,241,234,.14);display:flex;justify-content:space-between;gap:20px;flex-wrap:wrap;font:400 10.5px/1.6 'IBM Plex Mono',monospace;letter-spacing:.08em;text-transform:uppercase;color:rgba(243,241,234,.6)}
.m92{color:var(--brand-jaune)}

/* Apparition au défilement (§3bis quater). */
.avec-apparition .apparition{opacity:0;transform:translateY(16px);transition:opacity 700ms cubic-bezier(.33,0,.2,1),transform 700ms cubic-bezier(.33,0,.2,1)}
.avec-apparition .apparition--vue{opacity:1;transform:none}
.avec-apparition .apparition .grille-domaines > *{opacity:0;transform:translateY(14px);transition:opacity 1400ms cubic-bezier(.33,0,.2,1),transform 1400ms cubic-bezier(.33,0,.2,1)}
.avec-apparition .apparition--vue .grille-domaines > *{opacity:1;transform:none}
.avec-apparition .apparition--vue .grille-domaines > *:nth-child(2){transition-delay:200ms}
.avec-apparition .apparition--vue .grille-domaines > *:nth-child(3){transition-delay:400ms}
.avec-apparition .apparition--vue .grille-domaines > *:nth-child(4){transition-delay:600ms}
.avec-apparition .apparition--vue .grille-domaines > *:nth-child(5){transition-delay:800ms}
.avec-apparition .apparition--vue .grille-domaines > *:nth-child(6){transition-delay:1000ms}
/* Surtitres de section : filet, et olive foncé sur fond clair (§3bis ter). */
span.m31{display:inline-flex;align-items:center;gap:10px;color:#667618}
span.m31::before{content:"";width:28px;height:1px;background:currentColor;flex:none}
/* « Nos partenaires » : sur aplat pétrole, il garde le jaune de la charte. */
span.m69{display:inline-flex;align-items:center;gap:10px}
span.m69::before{content:"";width:28px;height:1px;background:currentColor;flex:none}
/* Aplat de la section Actualités : blanc cassé (§3bis ter). */
section.m62{background-color:#FBFAF7}
/* Cartes de témoignages : fond papier (§3bis ter). */
div.m48{background-color:var(--neutral-papier)}
/* Paragraphe du titre des Réalisations (§3bis ter). */
.realisations__intro{font:400 1.02rem/1.7 'Roboto',sans-serif;color:#3C4A47;max-width:62ch;margin:14px 0 0}
/* Bloc titre + texte des Réalisations : largeur bornée (§3bis ter). */
.realisations__entete{flex:1 1 380px;min-width:0}
/* Survol des cartes de projets : zoom de la photo (§3bis ter). */
.grille-projets button img{transition:transform 600ms cubic-bezier(.33,0,.2,1)}
.grille-projets button:hover img,.grille-projets button:focus-visible img{transform:scale(1.05)}
@media (prefers-reduced-motion:reduce){.grille-projets button img{transition:none}.grille-projets button:hover img,.grille-projets button:focus-visible img{transform:none}}
/* Liens des pages légales dans le pied (§3bis ter). */
.lien-legal{color:inherit;text-decoration:none}
.lien-legal:hover,.lien-legal:focus-visible{text-decoration:underline;text-underline-offset:3px}
/* Survol des cartes d'actualités : zoom de la photo (§3bis ter). */
section.m62 button img{transition:transform 600ms cubic-bezier(.33,0,.2,1)}
section.m62 button:hover img,section.m62 button:focus-visible img{transform:scale(1.05)}
@media (prefers-reduced-motion:reduce){section.m62 button img{transition:none}section.m62 button:hover img,section.m62 button:focus-visible img{transform:none}}
