/* ============================================================
   COGEMOB BTP — feuille de style du site
   ------------------------------------------------------------
   Se charge APRÈS tokens/cogemob-tokens.css, qui est le fichier
   contractuel et n'est jamais modifié.

   AUCUNE couleur littérale dans ce fichier : toute valeur
   colorimétrique passe par une variable de jetons. La seule
   exception est `transparent`.

   Registre : plan d'exécution. Angles vifs, filets fins, aucune
   ombre portée, aucun dégradé.
   ============================================================ */

/* --- 0. Dérogations aux jetons, tracées ------------------- */

:root {
  /*
   * DÉROGATION VALIDÉE PAR LE CLIENT (arbitrage G, 10 août 2026).
   *
   * Les jetons imposent `--radius-sm: 2px` et le registre « angles vifs ».
   * Le client a choisi de suivre la maquette sur ce point précis : les
   * cartes portent un rayon de 10 px.
   *
   * La dérogation vit ICI et non dans tokens/cogemob-tokens.css, qui est
   * contractuel et reste intact. Portée strictement limitée aux cartes :
   * puces et boutons conservent `--radius-sm`, l'interdiction d'ombre
   * portée reste entière.
   */
  --radius-card: 10px;

  /*
   * DÉROGATION VALIDÉE PAR LE CLIENT (19 septembre 2026).
   *
   * Les jetons font de Source Serif 4 la police de lecture. Le client
   * a retenu Roboto pour tout le texte courant, et Archivo pour les
   * titres : deux familles de texte, plus IBM Plex Mono pour les
   * étiquettes. Source Serif 4 n'est plus servie.
   *
   * Même principe que ci-dessus : la dérogation vit ici, les jetons
   * restent intacts.
   */
  --font-body: 'Roboto', system-ui, sans-serif;
  --font-fallback-body: Arial, Helvetica, sans-serif;

  /* Gouttière responsive : les jetons ne fournissent qu'une valeur fixe
     (--gutter-page: 28px), retenue comme base. */
  --gutter-fluide: clamp(var(--space-5), 4vw, var(--gutter-page));
}

/* --- 1. Polices, hébergées localement -------------------- */
/* Trois familles, cinq fichiers WOFF2, sous-ensemble latin :
   Archivo (titres, droit et italique), Roboto (texte courant),
   IBM Plex Mono 400 et 600 (étiquettes). Jamais de Google Fonts :
   exigence RGPD et de performance (SPEC §7, SECURITE §5).

   Les @font-face sont déclarés UNE SEULE FOIS, dans
   styles/reference.css, chargée avant cette feuille sur toutes les
   pages (partials/tete.njk). Les répéter ici avait laissé les deux
   listes diverger. */

/* --- 2. Réinitialisation mesurée -------------------------- */

*,
*::before,
*::after {
  box-sizing: border-box;
}

body,
h1, h2, h3, h4,
p, figure, blockquote,
dl, dd, ul, ol {
  margin: 0;
}

ul, ol {
  padding: 0;
  list-style: none;
}

img {
  display: block;
  max-width: 100%;
  height: auto;
}

/* L'ATTRIBUT `hidden` DOIT L'EMPORTER SUR TOUTE DÉCLARATION `display`.
 *
 * Le navigateur ne lui donne qu'un `display: none` de feuille par défaut,
 * que la moindre règle d'auteur écrase. Or scripts/carrousel.js masque
 * ses commandes par cet attribut, et la mise en forme des carrousels leur
 * pose `display: grid` et `display: flex` : les chevrons et les pastilles
 * du bas de page d'article restaient donc AFFICHÉS ET INERTES alors que
 * le script les avait masqués, faute de quoi que ce soit à faire défiler.
 * Constaté sur le rendu — l'attribut était bien posé, l'élément mesurait
 * toujours 40 × 40.
 *
 * Le défaut existait depuis l'écriture du premier carrousel sans jamais
 * se voir : sur la page Réalisations, les quatre pistes débordent
 * toujours, donc rien n'y est jamais masqué.
 *
 * `!important` est ici à sa place : c'est la seule façon qu'une règle
 * générale l'emporte sur des règles de composant plus spécifiques, et
 * `hidden` n'a de sens que s'il est inconditionnel. */
[hidden] {
  display: none !important;
}

/* --- 3. Socle ------------------------------------------- */

html {
  -webkit-text-size-adjust: 100%;
}

body {
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-body);
  font-size: var(--type-body);
  font-weight: var(--weight-regular);
  line-height: var(--leading-body);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

main {
  flex: 1 0 auto;
}

main:focus {
  outline: none;
}

h1, h2, h3, h4 {
  font-family: var(--font-display);
  color: var(--color-heading);
  line-height: var(--leading-snug);
  letter-spacing: var(--tracking-heading);
  text-wrap: balance;
}

a {
  color: var(--color-heading);
}

/* Toute donnée vérifiable est en chasse fixe : référence, agrément,
   quantité, téléphone. C'est ce qui distingue visuellement une
   affirmation d'une preuve (DESIGN-SYSTEM.md §4). */
.donnee {
  font-family: var(--font-mono);
  font-weight: var(--weight-regular);
  font-variant-numeric: tabular-nums;
  letter-spacing: var(--tracking-mono);
}

/* --- 4. Focus visible ------------------------------------ */
/* Jamais `outline: none` sans remplacement (SPEC §6).
   Pétrole sur fond clair : ratio 9,67. */

:focus-visible {
  outline: 3px solid var(--brand-petrole);
  outline-offset: 2px;
}

/* Sur les aplats pétrole, le pétrole serait invisible : on passe au
   jaune, seule combinaison autorisée sur ce fond (ratio 5,89). */
.entete :focus-visible,
.pied :focus-visible {
  outline-color: var(--brand-jaune);
}

/* --- 5. Lien d'évitement --------------------------------- */

.lien-evitement {
  position: absolute;
  left: var(--space-2);
  top: var(--space-2);
  z-index: 10;
  transform: translateY(-200%);
  background: var(--brand-jaune);
  /* Texte pétrole sur jaune : seule combinaison texte/accent autorisée. */
  color: var(--brand-petrole);
  font-family: var(--font-display);
  font-weight: var(--weight-semibold);
  font-size: var(--type-small);
  text-decoration: none;
  padding: var(--space-3) var(--space-5);
  border-radius: var(--radius-sm);
}

.lien-evitement:focus {
  transform: translateY(0);
}

/* --- 6. Conteneur et rythme ------------------------------ */

.conteneur {
  width: 100%;
  max-width: var(--width-content);
  margin-inline: auto;
  padding-inline: var(--gutter-fluide);
}

.section {
  padding-block: var(--space-16);
}

/* --- 7. En-tête ------------------------------------------ */

/* L'EN-TÊTE DU SITE EST CELUI DE L'ACCUEIL depuis le 19/08 (demande du
   client) : son dessin vit dans styles/reference.css, et son balisage
   dans partials/entete-clone.njk, tous deux produits par
   tools/cloner-reference.mjs.

   Les règles ci-dessous habillaient l'ancien en-tête. Celles qui portent
   sur des classes que le nouveau n'emploie pas — .entete__interieur,
   .entete__nav, .entete__liste, .entete__lien, .entete__logo,
   .entete__cta, .entete__bascule-trait — sont conservées : elles ne
   s'appliquent plus à rien, et partials/entete.njk existe toujours si on
   veut y revenir.

   TROIS ONT DÛ PARTIR, parce qu'elles visent des classes que le nouvel
   en-tête emploie VRAIMENT et qu'elles l'emporteraient sur reference.css,
   chargé avant : `.entete`, `.entete__bascule` et `.entete__bascule:not([hidden])`.
   Une quatrième, `.entete__actions`, est traitée plus bas au même titre. */

.entete__interieur {
  display: flex;
  align-items: center;
  gap: var(--space-6);
  flex-wrap: wrap;
  padding-block: var(--space-4);
}

.entete__logo {
  display: block;
  flex: 0 0 auto;
  line-height: 0;
}

.entete__logo img {
  /* Taille minimale web du logotype : 100 px (DESIGN-SYSTEM.md §6). */
  width: 136px;
  height: auto;
}

.entete__nav {
  display: flex;
  align-items: center;
  gap: var(--space-8);
  margin-inline-start: auto;
}

.entete__liste {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-6);
}

.entete__lien {
  font-family: var(--font-display);
  font-size: var(--type-small);
  font-weight: var(--weight-medium);
  color: var(--color-text-invert);
  text-decoration: none;
  padding-block: var(--space-1);
  border-bottom: 2px solid transparent;
}

.entete__lien:hover,
.entete__lien[aria-current='page'] {
  border-bottom-color: var(--brand-jaune);
}

/* .entete__bascule et .entete__bascule:not([hidden]) retirées le 19/08 :
   le bouton de menu du nouvel en-tête porte les mêmes classes, et ces
   règles-ci l'auraient repeint en blanc sur blanc et redéployé de
   travers. Son dessin est dans reference.css. */

.entete__bascule-trait,
.entete__bascule-trait::before,
.entete__bascule-trait::after {
  display: block;
  width: 18px;
  height: 2px;
  background: var(--brand-jaune);
}

.entete__bascule-trait {
  position: relative;
}

.entete__bascule-trait::before,
.entete__bascule-trait::after {
  content: '';
  position: absolute;
  left: 0;
}

.entete__bascule-trait::before { top: -6px; }
.entete__bascule-trait::after  { top: 6px; }

/* --- 8. Sélecteur de langue ------------------------------ */

.selecteur-langue__liste {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.selecteur-langue__lien {
  font-family: var(--font-mono);
  font-size: var(--type-caption);
  letter-spacing: var(--tracking-mono);
  text-transform: uppercase;
  color: var(--color-text-invert);
  text-decoration: none;
  padding: var(--space-1) var(--space-2);
  border: var(--border-hairline);
  border-color: transparent;
  border-radius: var(--radius-sm);
}

.selecteur-langue__lien[aria-current='true'] {
  background: var(--brand-jaune);
  /* Texte pétrole sur jaune : ratio 5,89. */
  color: var(--brand-petrole);
}

.selecteur-langue__lien:not([aria-current='true']):hover {
  border-color: var(--color-text-invert);
}

/* --- 9. Titres de page ----------------------------------- */

.titre-page {
  font-size: var(--type-display-2);
  font-weight: var(--weight-black);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-display);
  max-width: 20ch;
}

/* --- 10. Encart de constat ------------------------------- */
/* Filet gauche : jaune pour un avertissement, olive pour une note,
   danger pour un interdit (DESIGN-SYSTEM.md §5). */

.encart {
  border-left: 3px solid var(--color-accent);
  background: var(--color-surface);
  padding: var(--space-4) var(--space-6);
  margin-block-start: var(--space-8);
  max-width: var(--measure-body);
  font-size: var(--type-small);
  color: var(--color-text-muted);
}

.encart--note      { border-left-color: var(--color-accent-alt); }
.encart--interdit  { border-left-color: var(--color-danger); }

/* --- 11. Carte ------------------------------------------- */
/* Rayon en dérogation validée : voir §0. Aucune ombre portée. */

.carte {
  background: var(--color-surface);
  border: var(--border-hairline);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-none);
  padding: var(--space-6);
}

/* --- 12. Pied de page ------------------------------------ */

.pied {
  background: var(--color-surface-invert);
  color: var(--color-text-invert);
  margin-block-start: var(--space-20);
  padding-block: var(--space-12) var(--space-6);
}

.pied__interieur {
  display: grid;
}

.pied__titre {
  font-family: var(--font-mono);
  font-size: var(--type-label);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  /* Le jaune ne porte jamais de texte sur fond clair ; sur aplat pétrole
     il est autorisé et lisible (ratio 5,89 en inverse). */
  color: var(--brand-jaune);
  margin-block-end: var(--space-4);
}

.pied__adresse {
  font-style: normal;
}

.pied__ligne,
.pied__liste li {
  font-size: var(--type-small);
  line-height: var(--leading-loose);
}

.pied__telephones {
  margin-block-start: var(--space-3);
}

.pied__lien,
.pied__telephones a {
  color: var(--color-text-invert);
  text-decoration: none;
  border-bottom: 1px solid transparent;
}

.pied__lien:hover,
.pied__telephones a:hover {
  border-bottom-color: var(--brand-jaune);
}

/* La ligne de bas du pied est désormais `.pied__bas` (L349-351). */

/* --- 13. Fonds de section -------------------------------- */
/*
 * REGISTRE DU SITE, pas celui des documents imprimables. Les fonds
 * alternent pour rythmer le défilement (MAQUETTE.md, « Avertissement —
 * deux registres visuels distincts »). Valeurs citées de
 * reference/index.html, converties aux jetons :
 *   L153  #FBFAF7  → --neutral-papier   (SPEC §8 correction 3)
 *   L168  #014958  → --brand-petrole    (valeur identique)
 *   L183  #FFFFFF  → --neutral-blanc    (valeur identique)
 */

.section--papier { background: var(--neutral-papier); }
.section--blanc  { background: var(--neutral-blanc); }

.section--petrole {
  background: var(--brand-petrole);
  color: var(--color-text-invert);
}

/* --- 13 bis. Titres de section --------------------------- */
/*
 * Trois traitements distincts, tous issus de la référence. Leur
 * alternance fait partie du dessin, ce n'est pas un oubli à uniformiser.
 * AUCUN badge « §NN », AUCUN filet jaune : registre imprimable.
 */

/* Statement court et percutant, Archivo gras. reference L155. */
.titre-statement {
  font-family: var(--font-display);
  font-size: clamp(1.7rem, 4.4vw, 3.1rem);
  font-weight: var(--weight-semibold);
  line-height: 1.1;
  letter-spacing: -0.01em;
  color: var(--color-heading);
  text-align: center;
  margin-block-end: var(--space-10);
}

.titre-statement--gauche {
  text-align: start;
}

/* Titre narratif. reference L187 — Newsreader 300, puis Source Serif 4,
   puis Archivo semi-gras comme tous les titres (client, 19/09/2026). */
.titre-narratif {
  font-family: var(--font-display);
  font-size: clamp(1.9rem, 3.2vw, 2.6rem);
  font-weight: var(--weight-semibold);
  line-height: 1.2;
  letter-spacing: -0.01em;
  color: var(--color-heading);
  max-width: 62ch;
  margin-block-end: var(--space-10);
}

/* Ligne mono. Pour Partenaires, la référence n'a pas de <h2> classique :
   le titre EST cette ligne (L170). Ailleurs, c'est un kicker (L186). */
.titre-kicker,
.kicker {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: var(--weight-regular);
  line-height: 1;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--brand-petrole);
  margin: 0;
}

/* Sur aplat pétrole : jaune, ratio 5,89 (reference L170). */
.titre-kicker--accent {
  color: var(--brand-jaune);
}

/* reference L187 : 20 px entre le kicker et le titre. */
.kicker + .titre-narratif {
  margin-block-start: var(--space-5);
}

.section__suite {
  margin-block-start: var(--space-8);
}

/* reference L217 : filet pétrole 1 px, jamais jaune. */
.lien-suite {
  font-family: var(--font-display);
  font-size: var(--type-small);
  font-weight: var(--weight-medium);
  color: var(--color-heading);
  text-decoration: none;
  border-bottom: 1px solid var(--brand-petrole);
  padding-block-end: 6px;
}

.lien-suite::after {
  content: ' →';
}

/* --- 14. Prose ------------------------------------------- */

.prose {
  max-width: var(--measure-body);
  font-size: var(--type-body-lg);
}

/* Bloc d'engagement : texte centré, colonne centrée. reference L159. */
.prose--centre {
  margin-inline: auto;
  text-align: center;
}

.prose p + p {
  margin-block-start: var(--space-5);
}

/* --- 15. Boutons ----------------------------------------- */

.bouton {
  display: inline-block;
  font-family: var(--font-display);
  font-size: var(--type-small);
  font-weight: var(--weight-semibold);
  text-decoration: none;
  padding: var(--space-3) var(--space-6);
  border-radius: var(--radius-sm);
  border: 2px solid transparent;
}

/* Texte pétrole sur aplat jaune : ratio 5,89. */
.bouton--accent {
  background: var(--brand-jaune);
  color: var(--brand-petrole);
}

.bouton--accent:hover {
  background: var(--color-surface-invert);
  color: var(--brand-jaune);
}

.bouton--fantome {
  border-color: var(--brand-petrole);
  color: var(--brand-petrole);
}

.bouton--fantome:hover {
  background: var(--brand-petrole);
  color: var(--color-text-invert);
}

/* --- 16. Bandeau principal — Direction A ----------------- */
/*
 * D'après reference/index.html §hero-A, validée le 10/08/2026.
 * Plein cadre, fond texturé, aucune photo, un seul bouton.
 *
 * ÉCARTS ASSUMÉS par rapport à la référence, tous documentés :
 *
 * 1. Couleurs. La référence emploie #0F4A42 / #12564D / rgba(7,28,26,…),
 *    hors palette. Les bandes reprennent pétrole et sapin, le voile est
 *    composé sur l'encre. SPEC §8 corrections 1 à 3.
 *
 * 2. Bandes pétrole + sapin. DESIGN-SYSTEM §3 règle 2 interdit de les
 *    juxtaposer en aplats voisins, au motif que leur écart de contraste
 *    (1,20) rend la frontière invisible. C'est précisément l'effet
 *    recherché ici : une texture, non deux codes couleur. Les deux teintes
 *    n'encodent rien et ne se distinguent pas — la règle vise l'usage
 *    signifiant, pas le motif. À confirmer.
 *
 * 3. Voile en dégradé. DESIGN-SYSTEM §2 proscrit les dégradés décoratifs ;
 *    MAQUETTE.md point 2 prescrit explicitement un « dégradé sombre en
 *    surimpression » pour ce bandeau. La consigne postérieure et
 *    spécifique l'emporte sur la règle générale.
 *
 * 4. `position: absolute` pour l'en-tête plutôt que le `sticky` de la
 *    référence. Un en-tête collant et transparent resterait transparent
 *    au-dessus du contenu clair, où son texte papier deviendrait
 *    illisible. Il défile donc avec le bandeau.
 */

.hero {
  position: relative;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  color: var(--neutral-papier);
}

.hero__texture,
.hero__voile {
  position: absolute;
  inset: 0;
}

.hero__texture {
  background: repeating-linear-gradient(
    135deg,
    var(--brand-petrole) 0 12px,
    var(--brand-sapin) 12px 24px
  );
}

/* Si color-mix n'est pas gérée, le voile est simplement absent : les
   bandes restent assez sombres (pétrole, 10,02 sous du papier) pour que
   le texte demeure lisible. */
.hero__voile {
  background: linear-gradient(
    180deg,
    color-mix(in srgb, var(--neutral-encre) 78%, transparent) 0%,
    color-mix(in srgb, var(--neutral-encre) 42%, transparent) 45%,
    color-mix(in srgb, var(--neutral-encre) 82%, transparent) 100%
  );
}

.hero__centre {
  position: relative;
  z-index: 2;
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  width: 100%;
  max-width: var(--width-content);
  margin-inline: auto;
  padding: var(--gutter-fluide);
  /* L'en-tête flotte au-dessus : on lui réserve sa hauteur. */
  padding-block-start: calc(var(--space-20) + var(--space-12));
}

.hero__titre {
  /* Échelle de la référence. Un titre : Archivo (client, 19/09/2026). */
  font-family: var(--font-display);
  font-size: clamp(2.9rem, 5.6vw, 4.6rem);
  font-weight: var(--weight-regular);
  line-height: 1.02;
  letter-spacing: -0.02em;
  color: var(--neutral-papier);
  text-align: center;
  text-wrap: balance;
  max-width: 20ch;
  margin: 0;
}

.hero__pied {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-5);
  text-align: center;
  width: 100%;
  max-width: var(--width-content);
  margin-inline: auto;
  padding: 0 var(--gutter-fluide) clamp(var(--space-8), 3.5vw, var(--space-12));
}

.hero__paragraphe {
  font-size: var(--type-body-lg);
  line-height: var(--leading-body);
  color: var(--neutral-papier);
  max-width: 60ch;
  margin: 0;
}

.hero__action {
  margin: 0;
}

/* En-tête en surimpression, accueil uniquement. */
.page-accueil .entete {
  position: absolute;
  inset-block-start: 0;
  inset-inline: 0;
  z-index: 50;
  background: linear-gradient(
    180deg,
    color-mix(in srgb, var(--neutral-encre) 60%, transparent) 0%,
    transparent 100%
  );
  border-bottom: 0;
}

.page-accueil {
  position: relative;
}

/* --- 19. Cartes ------------------------------------------ */

.cartes {
  display: grid;
  gap: var(--space-6);
}

/* Quatre colonnes, comme reference/index.html. Le repli en dessous de
   64 rem évite d'écraser les intitulés, plus longs que ceux de la
   maquette puisqu'ils viennent du JSON. */
.cartes--activites {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

@media (min-width: 64rem) {
  .cartes--activites {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

@media (max-width: 34rem) {
  .cartes--activites {
    grid-template-columns: minmax(0, 1fr);
  }
}

.cartes--projets {
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
}

.carte {
  position: relative;
  background: var(--color-surface);
  border: var(--border-hairline);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-none);
  padding: var(--space-6);
}

.carte--activite:hover {
  background: var(--color-bg);
  border-color: var(--brand-petrole);
}

.picto {
  color: var(--brand-petrole);
  margin-block-end: var(--space-4);
}

.carte__titre {
  font-size: var(--type-h3);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-snug);
}

.carte__num {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--type-caption);
  font-weight: var(--weight-regular);
  letter-spacing: var(--tracking-mono);
  color: var(--color-text-subtle);
  margin-block-end: var(--space-1);
}

.carte__lien {
  color: inherit;
  text-decoration: none;
}

/* Toute la carte est cliquable, mais le nom accessible reste celui du
   lien : une seule cible pour le clavier, pas de lien fantôme. */
.carte__lien::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: var(--radius-card);
}

.carte__lien:hover {
  text-decoration: underline;
  text-underline-offset: 3px;
}

.carte__texte {
  margin-block-start: var(--space-3);
  font-size: var(--type-small);
  color: var(--color-text-muted);
}

.carte__figure {
  margin: 0 0 var(--space-5);
}

.carte__image {
  width: 100%;
  height: auto;
  /* Carte projet : photo au format 16/10 (DESIGN-SYSTEM.md §5). */
  aspect-ratio: 16 / 10;
  object-fit: cover;
  border-radius: var(--radius-sm);
}

/* --- 20. Puces ------------------------------------------- */

.puce {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: var(--type-label);
  letter-spacing: var(--tracking-mono);
  text-transform: uppercase;
  color: var(--color-text-muted);
  background: var(--color-bg);
  border: var(--border-hairline);
  border-radius: var(--radius-sm);
  padding: var(--space-1) var(--space-3);
}

.lots {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-block-start: var(--space-5);
}

/* --- 20 bis. Gabarits étiquetés -------------------------- */
/*
 * Étiquette « Exemple — … à venir », obligatoire sur CHAQUE carte de
 * témoignage et d'actualité (SPEC §1, exception explicite). Un gabarit
 * affiché sans elle redevient une invention non signalée.
 *
 * Aplat pétrole, texte jaune : seule combinaison où le jaune peut porter
 * du texte (ratio 5,89). Jamais en petit caractère caché.
 */

.badge-exemple {
  display: inline-block;
  background: var(--brand-petrole);
  color: var(--brand-jaune);
  font-family: var(--font-mono);
  font-size: var(--type-label);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-mono);
  text-transform: uppercase;
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-sm);
  margin-block-end: var(--space-4);
}

/* Le marqueur de titre manquant a été retiré le 11/08/2026 : les deux
   titres de section sont désormais au JSON (temoignages.titre_section et
   actualites.titre_section). */

/* --- 20 ter. Témoignages --------------------------------- */

.temoignages {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--space-6);
}

.temoignage {
  display: flex;
  flex-direction: column;
  background: var(--color-surface);
  border: var(--border-hairline);
  border-radius: var(--radius-card);
  padding: var(--space-6);
}

.temoignage__texte {
  margin: 0 0 var(--space-6);
  flex: 1;
  font-size: var(--type-body);
  color: var(--color-text-muted);
}

.temoignage__auteur {
  margin: 0;
}

.temoignage__nom {
  display: block;
  font-family: var(--font-display);
  font-size: var(--type-small);
  font-weight: var(--weight-bold);
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: var(--color-text);
}

.temoignage__role {
  display: block;
  margin-block-start: var(--space-1);
  font-size: var(--type-caption);
  color: var(--color-text-muted);
}

/* --- 20 quater. Actualités ------------------------------- */

.cartes--actualites {
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
}

.actualite__date {
  margin: 0 0 var(--space-3);
  font-size: var(--type-caption);
  text-transform: uppercase;
  color: var(--color-heading);
}

/* --- 21. Partenaires ------------------------------------- */

/* Cases blanches 16/9 portant le nom en texte, d'après
   reference/index.html L171 (grille) et L172 (case). Aucun logo : ils ne
   sont pas en notre possession et leur usage requiert autorisation. */
.partenaires {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: var(--space-5);
  margin-block-start: var(--space-8);
}

.partenaire {
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  aspect-ratio: 16 / 9;
  padding: var(--space-4);
  background: var(--neutral-blanc);
  border: var(--border-hairline);
  font-family: var(--font-display);
  font-size: var(--type-caption);
  font-weight: var(--weight-medium);
  line-height: 1.3;
  /* Ardoise sur blanc : ratio 7,55. */
  color: var(--color-text-muted);
}

/* --- 22. Bloc contact ------------------------------------ */
/* Aplat pétrole pleine largeur, labels mono jaune sur fond foncé :
   le jaune y est autorisé (DESIGN-SYSTEM.md §5). */

/*
 * CTA FINAL — AUCUN aplat de fond, il hérite du fond de page.
 *
 * reference/index.html L304 ne porte aucune couleur de fond sur cette
 * section ; seul le PIED DE PAGE en a une (L318). DESIGN-SYSTEM.md §5
 * prescrivait par erreur le même traitement aux deux blocs — corrigé
 * dans le kit du 11/08/2026 22:48.
 */
.bloc-contact {
  padding-block: clamp(var(--space-20), 9vw, 140px);
}

.bloc-contact__interieur {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--space-12);
  align-items: start;
}

.bloc-contact__action {
  margin-block-start: var(--space-8);
}

.bloc-contact__coordonnees dt {
  font-family: var(--font-mono);
  font-size: var(--type-label);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  /* Sur fond clair, le jaune ne porte jamais de texte : pétrole. */
  color: var(--brand-petrole);
  margin-block-end: var(--space-4);
}

.bloc-contact__coordonnees dd {
  margin: 0 0 var(--space-5);
  font-size: var(--type-small);
}

.bloc-contact__ligne {
  display: block;
  line-height: var(--leading-loose);
}

.bloc-contact__tel {
  display: block;
  color: var(--color-text);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  width: fit-content;
}

.bloc-contact__tel:hover {
  border-bottom-color: var(--brand-petrole);
}

/* --- 23. Petits écrans ----------------------------------- */

@media (max-width: 60rem) {
  .entete__interieur {
    row-gap: var(--space-4);
  }

  .entete__nav {
    flex-basis: 100%;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-4);
    margin-inline-start: 0;
  }

  .entete__liste {
    flex-direction: column;
    gap: var(--space-3);
    width: 100%;
  }

  /* Replié UNIQUEMENT si le script a pris la main. Sans JavaScript,
     `[hidden]` reste sur le bouton et la navigation demeure ouverte. */
  .entete__bascule:not([hidden]) ~ .entete__nav[data-replie='true'] {
    display: none;
  }
}

/* --- 14. Mouvement réduit -------------------------------- */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ============================================================
   AUDIT DE FIDÉLITÉ DU 12/08/2026
   ------------------------------------------------------------
   Police, graisse, taille et couleur copiées LITTÉRALEMENT des
   lignes citées de reference/index.html. Seules les couleurs
   passent par les jetons, conformément à SPEC §8 :
     #F2C230 → --brand-jaune     #0C4F46 → --brand-petrole
     #0A2A26 → --color-heading    #F3F1EA → --neutral-papier
     #5C6764 → --neutral-ardoise  #7A8380 → --neutral-beton
   ============================================================ */

/* --- En-tête, bloc d'action (L116, L127) ----------------- */

.entete__interieur {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--space-6);
  padding-block: var(--space-4);
}

.entete__nav { justify-self: center; margin-inline-start: 0; }

/* .entete__actions retirée le 19/08 : le nouvel en-tête réunit sous cette
   même classe le sélecteur de langue et le bouton d'appel, et c'est
   reference.css qui la dessine — y compris son repliement sous 60rem. */

/* L127 : font:600 13px/1 'Archivo'; letter-spacing:.03em;
   padding:12px 22px; border-radius:2px; aplat jaune, texte pétrole. */
.entete__cta {
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: var(--weight-semibold);
  line-height: 1;
  letter-spacing: 0.03em;
  padding: 12px 22px;
  border-radius: var(--radius-sm);
  background: var(--brand-jaune);
  color: var(--brand-petrole);
  text-decoration: none;
  white-space: nowrap;
}

/* L121-125 : font:500 13.5px/1 'Archivo'; letter-spacing:.02em. */
.entete__lien {
  font-size: 13.5px;
  font-weight: var(--weight-medium);
  line-height: 1;
  letter-spacing: 0.02em;
}

/* L118 : logo 100 px. */
.entete__logo img { width: 100px; }

/* --- Activités : intro et bouton (L202-207) -------------- */
/* Deux blocs de deux colonnes chacun, sous les quatre cartes. */

.cartes__intro,
.cartes__action {
  display: flex;
  align-items: center;
}

.cartes__action { justify-content: flex-start; }

/* L203 : font:400 1.08rem/1.6 'Newsreader',serif → police de texte (Roboto). */
.activites__intro {
  font-family: var(--font-body);
  font-size: 1.08rem;
  font-weight: var(--weight-regular);
  line-height: 1.6;
  color: var(--color-heading);
  margin: 0;
}

@media (min-width: 64rem) {
  .cartes__intro,
  .cartes__action { grid-column: span 2; }
}

/* --- Emplacements photo en gabarit (L221-222) ------------ */
/* Consigne du client du 12/08 : aucune photo réelle pour l'instant.
 *
 * LE COMPOSANT LUI-MÊME EST DANS styles/emplacement-photo.css depuis le
 * 23/09/2026 — géométrie, hachure et légende. Il a été extrait pour être
 * partagé avec la PAGE D'ACCUEIL, qui ne charge pas cette feuille : sa
 * section Actualités affiche désormais les vrais articles, dont les
 * photos ne sont pas fournies. Le fichier extrait explique le partage.
 *
 * NE RESTENT ICI QUE LES DEUX PROPRIÉTÉS PROPRES AUX PAGES INTÉRIEURES,
 * celles que l'accueil ne doit pas recevoir : le rayon de 10 px, qui est
 * une dérogation aux jetons (§0 ci-dessus), et la marge basse, que les
 * cartes de la maquette donnent déjà autrement. */

.emplacement-photo {
  border-radius: var(--radius-sm);
  margin-block-end: var(--space-5);
}

/* --- CTA final : deux éléments (L308-310) ---------------- */

.bloc-contact__action {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  margin-block-start: var(--space-8);
}

/* L309 : aplat pétrole, texte papier, padding:17px 30px. */
.bouton--petrole {
  background: var(--brand-petrole);
  color: var(--neutral-papier);
  padding: 17px 30px;
}

/* L310 : contour 1 px, texte encre, mêmes proportions. */
.bouton--contour {
  border: 1px solid var(--neutral-trait);
  color: var(--color-text);
  padding: 17px 30px;
}

.bouton--contour:hover { border-color: var(--brand-petrole); }

/* --- Pied de page : 4 colonnes (L319-352) ---------------- */

.pied__interieur {
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: clamp(var(--space-6), 4vw, var(--space-16));
}

/* L321 : logo 64 px. */
.pied__logo { width: 64px; height: auto; }

/* L325, L335, L340 : font:400 10.5px/1 'IBM Plex Mono';
   letter-spacing:.14em; capitales; jaune. */
.pied__titre {
  font-size: 10.5px;
  letter-spacing: 0.14em;
  margin-block-end: 18px;
}

/* L336-337 : font:400 .88rem/1.8 'IBM Plex Mono'; letter-spacing:.03em. */
.pied__siege {
  font-family: var(--font-mono);
  font-size: 0.88rem;
  line-height: 1.8;
  letter-spacing: 0.03em;
  margin: 0;
}

.pied__siege + .pied__siege { margin-block-start: 18px; }

/* L337 : la mention de courriel manquant est en jaune. */
.pied__email { color: var(--brand-jaune); }

/* L341-346 : libellé 9.5px capitales atténué, valeur mono 600 .9rem. */
.identification { display: grid; gap: 16px; margin: 0; }

.identification__ligne dt {
  font-family: var(--font-mono);
  font-size: 9.5px;
  line-height: 1;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--neutral-beton);
  margin-block-end: 6px;
}

.identification__ligne dd {
  font-family: var(--font-mono);
  font-size: 0.9rem;
  font-weight: var(--weight-semibold);
  line-height: 1.3;
  letter-spacing: 0.02em;
  color: var(--neutral-papier);
  margin: 0;
}

/* L349-351 : deux éléments, séparés par un filet, mono 10.5px capitales. */
.pied__bas {
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 20px;
  margin-block-start: var(--space-12);
  padding-block: 22px 40px;
  border-top: 1px solid var(--neutral-ardoise);
  font-family: var(--font-mono);
  font-size: 10.5px;
  line-height: 1.6;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--neutral-papier);
}

.pied__bas-legal { display: flex; gap: var(--space-5); flex-wrap: wrap; }

@media (max-width: 60rem) {
  .entete__interieur { grid-template-columns: auto 1fr; }
  .entete__actions { grid-column: 1 / -1; justify-self: start; flex-wrap: wrap; }
  .entete__nav { grid-column: 1 / -1; justify-self: start; }
}

/* ============================================================
 * 12. Pages de contenu — composants communs
 *
 * Écrits pour la page Entreprise (19/08/2026), mais nommés sans
 * référence à elle : les pages Activités, Réalisations et Contact
 * reprendront les mêmes blocs.
 *
 * TYPOGRAPHIE : Archivo pour les titres, Roboto pour le texte courant.
 * C'est le couple retenu sur l'accueil au fil des arbitrages du client,
 * étendu à tout le site le 19/09/2026 : --font-body vaut désormais Roboto
 * (dérogation §0). Les surtitres restent en IBM Plex Mono, comme ceux de
 * l'accueil.
 *
 * RYTHME : les sections alternent papier / blanc / pétrole. C'est ce qui
 * donne à une page longue sa structure — sans cette alternance, quatre
 * blocs de texte se lisent comme un seul.
 * ============================================================ */

.section-page {
  /* Le rythme vertical passe par une variable parce qu'un élément doit
     pouvoir le RETRANCHER : voir .vision__photo, qui remonte dans le
     hero et doit donc annuler ce rembourrage avant de mordre dessus. */
  --rythme-section: clamp(56px, 7vw, 104px);
  padding-block: var(--rythme-section);
  background: var(--neutral-blanc);
}
.section-page--papier { background: var(--neutral-papier); }

/* Section qui doit laisser passer un élément remontant de la suivante :
   son rembourrage bas reçoit un supplément.
 *
 * LE SUPPLÉMENT S'AJOUTE AU RYTHME, il ne le remplace pas. Écrit en
 * valeur absolue, il faudrait le recalculer à chaque fois que le rythme
 * de la page change ; écrit en addition, il reste ce qu'il est — un
 * dégagement, en plus de la respiration normale.
 *
 * Il ne touche QUE le bas : le haut de la section garde le rythme commun,
 * sans quoi le décalage se verrait dans l'alignement des titres. */
/* Le supplément a été cherché par approches successives le 21/08 :
   clamp(28,3.4vw,52) → clamp(52,6.4vw,96) → clamp(80,9.6vw,144), puis
   redescendu à clamp(44,5.4vw,80). Le dégagement final tient donc entre
   les deuxième et troisième essais.

   À 1440 px, le rembourrage bas vaut alors 179 px contre 101 en haut :
   la section reste dissymétrique, mais d'une fois et demie et non du
   double, ce qui se lit encore comme une respiration. */
.section-page--degagement-bas {
  padding-bottom: calc(var(--rythme-section) + clamp(44px, 5.4vw, 80px));
}

/* .section-page--degagement-haut, le pendant en tête de section, a été
   retiré le 21/08 avec la section qui l'employait.
 *
 * Son contraire l'a remplacé le même jour : une tête SUPPRIMÉE, pour que
 * le bloc pleine largeur touche la section précédente sans laisser
 * paraître le fond de la sienne. Le rembourrage tombe à zéro, et la marge
 * haute du bloc avec lui — les deux formaient cette bande.
 *
 * CONSÉQUENCE ASSUMÉE : le portrait de la section précédente, qui
 * déborde de 15 à 26 px vers le bas, se pose désormais SUR le bloc blanc
 * au lieu du papier. Il reste visible — il porte un z-index qui le place
 * devant — et le chevauchement se lit comme un franchissement voulu, pas
 * comme un défaut. C'est la seule façon de n'avoir aucun papier : tant
 * qu'il en reste, ne serait-ce que 24 px, c'est le débordement qui le
 * dicte. */
.section-page--sans-tete {
  padding-top: 0;
}
.section-page--sans-tete .bande-blanche {
  margin-top: 0;
}

/* Section du mot du dirigeant : LE PORTRAIT DÉBORDE DE L'APLAT PÉTROLE,
   en haut comme en bas (demande du client, 21/08).
 *
 * LE MÉCANISME TIENT EN UNE MARGE NÉGATIVE. Un élément à marge négative
 * compte pour moins que sa hauteur dans le calcul de son parent : le
 * portrait mesure toujours autant, mais la section n'en compte qu'une
 * partie, et il dépasse du reste.
 *
 * La marge retirée vaut le rembourrage de la section PLUS le débordement
 * voulu. En développant, la hauteur de l'aplat se réduit à :
 *
 *     hauteur du portrait - (débordement haut + débordement bas)
 *
 * — le rembourrage s'annule de lui-même. L'aplat est donc toujours plus
 * court que la photo, exactement des débordements demandés, et ce quel
 * que soit le rythme vertical de la page.
 *
 * LES DEUX DÉBORDEMENTS SONT DISSYMÉTRIQUES depuis le 21/08 : le haut est
 * doublé, le bas réduit. Ils ont donc chacun leur variable, et non plus
 * un margin-block unique. Le haut plonge dans le rembourrage bas de la
 * section précédente — 101 px en desktop — il y a donc la place ; c'est
 * vérifié sur le rendu, pas supposé.
 *
 * Ça suppose que la colonne de texte reste plus courte que ce que la
 * photo laisse compter : elle fait environ 150 px pour 300 et plus, la
 * marge est large.
 *
 * z-index:1 EST INDISPENSABLE. La section suivante a un fond papier
 * opaque et vient après dans le document : sans cette élévation, elle
 * repeindrait par-dessus le débordement du bas, qui disparaîtrait.
 *
 * RIEN DE TOUT ÇA SOUS 56rem : la grille s'y empile, le texte passe sous
 * la photo, et une marge négative l'y ferait chevaucher. */
@media (min-width: 56rem) {
  .section-page--dirigeant .emplacement-photo--portrait {
    /* DÉBORDEMENT HAUT FIXÉ À 14 mm (client, 21/09/2026), et non plus
       proportionnel : il valait clamp(40px, 4.8vw, 72px) par-dessus le
       rythme de section, ce qui donnait 3,2 cm à 1440 px mais 2,2 cm à
       1024 — mesuré sur le rendu. La photo dépasse maintenant de la même
       hauteur quelle que soit la fenêtre.
       Réglé au millimètre le même jour — 2 cm, 16, 12, 15, puis 14 mm : le
       client remonte la bande par rapport au portrait, ce qui revient à
       réduire d'autant ce qui dépasse.
       Le calcul retire le rembourrage HAUT de la section, réduit de
       moitié le 21/09 : c'est lui qui place la photo dans la bande, et
       c'est donc de lui qu'il faut partir pour la faire ressortir. */
    --debord-haut: 14mm;
    --debord-bas: clamp(14px, 1.7vw, 26px);
    margin-top: calc(-1 * (var(--rythme-section) / 2 + var(--debord-haut)));
    margin-bottom: calc(-1 * (var(--rythme-section) + var(--debord-bas)));
    z-index: 1;
  }
}
.section-page--petrole {
  background: var(--brand-petrole);
  color: var(--neutral-blanc);
}

/* Surtitre de section, même registre que ceux de l'accueil. */
.surtitre-page {
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--brand-petrole);
  margin: 0 0 var(--space-4);
}
.surtitre-page--clair { color: var(--brand-jaune); }

.titre-page-section {
  font-family: var(--font-display);
  font-size: var(--type-h2);
  font-weight: var(--weight-semibold);
  line-height: 1.14;
  letter-spacing: var(--tracking-heading);
  color: var(--brand-petrole);
  margin: 0 0 clamp(28px, 3.4vw, 48px);
  max-width: 22ch;
}
.section-page--petrole .titre-page-section { color: var(--neutral-blanc); }

/* Sous-titre de section, sous le titre et aligné à gauche sur lui
   (demande du client, 20/08).
 *
 * MÊME FAMILLE, MÊME COULEUR que le titre, dont il se distingue par la
 * graisse, le corps et l'italique.
 *
 * IL A ÉTÉ DÉCALÉ, PUIS RECALÉ À GAUCHE. Le décalage devait le faire lire
 * comme la suite de la phrase du titre ; le client a préféré l'alignement
 * franc. Rien ne subsiste de ce retrait : ni marge de départ, ni
 * text-indent.
 *
 * PAS DE max-width. Il en portait une de 26ch, qui le repliait bien avant
 * le bord et l'empêchait de tenir sur une ligne : à 36,8 px, ces 26
 * caractères valaient environ 520 px pour 860 px disponibles. Le corps
 * réduit tient désormais largement. */
.titre-suite {
  font-family: var(--font-display);
  font-size: clamp(1rem, 1.7vw, 1.5rem);
  font-style: italic;
  font-weight: var(--weight-regular);
  line-height: 1.2;
  letter-spacing: var(--tracking-heading);
  color: var(--brand-petrole);
  /* Écart avec le contenu qui suit réduit de moitié — 48 → 24 px au plus
     large (client, 21/09/2026). Le sous-titre appartient au titre : il
     doit s'en lire comme la suite, pas flotter entre les deux blocs. */
  margin: 0 0 clamp(14px, 1.7vw, 24px);
}
.titre-page-section + .titre-suite { margin-top: calc(-1 * clamp(28px, 3.4vw, 48px)); }
.section-page--petrole .titre-suite { color: var(--neutral-blanc); }

/* Énoncé fort : la phrase qui porte la section, traitée comme un titre.
   Pas un <h2> pour autant — c'est une phrase, pas un intitulé, et la
   hiérarchie des titres ne doit pas servir à grossir du texte. */
.enonce-fort {
  font-family: var(--font-display);
  font-size: clamp(1.35rem, 2.5vw, 2rem);
  font-weight: var(--weight-semibold);
  line-height: 1.28;
  letter-spacing: var(--tracking-heading);
  color: var(--brand-petrole);
  max-width: 34ch;
  margin: 0 0 clamp(32px, 4vw, 56px);
  border-left: 3px solid var(--brand-jaune);
  padding-left: clamp(20px, 2.4vw, 32px);
}
/* .enonce-fort--fin a disparu le 21/08 : l'énoncé de clôture de la
   section Atouts est devenu .enonce-final, dans une bande blanche pleine
   largeur. */

/* Bande de fond pleine largeur à l'intérieur d'une section.
 *
 * ELLE N'A PAS BESOIN DE RUSE : c'est un enfant direct de <section>, qui
 * occupe déjà toute la largeur de la page. C'est .conteneur, réouvert à
 * l'intérieur, qui ramène le texte à la largeur de lecture commune. Le
 * plein cadre s'obtient en SORTANT du conteneur, pas en le contrariant
 * par des marges négatives.
 *
 * LA BANDE A GRANDI AUX DÉPENS DU PAPIER QUI LA PRÉCÈDE (demande du
 * client, 21/08), et c'est un simple transfert : ce qui était une MARGE
 * au-dessus de la bande est devenu un REMBOURRAGE à l'intérieur. La
 * distance entre la section précédente et le texte change à peine ; ce
 * qui change, c'est l'endroit où le blanc commence.
 *
 *   marge haute    clamp(96px, 11vw, 176px) → clamp(32px, 3.6vw, 56px)
 *   rembourrage    clamp(36px, 4.4vw, 64px) → clamp(96px, 11vw, 176px)
 *
 * Le rembourrage bas garde sa valeur d'origine : la demande ne portait
 * que sur le papier du dessus. */
.bande-blanche {
  background: var(--neutral-blanc);
  /* Marge haute réduite une seconde fois le 21/08 : clamp(32,3.6vw,56)
     → clamp(12,1.4vw,22). Elle s'ajoute au rembourrage de la section pour
     former le papier visible au-dessus de la bande ; les deux ont été
     resserrés ensemble. */
  margin-block: clamp(12px, 1.4vw, 22px) clamp(28px, 3.4vw, 48px);
  padding-block: clamp(96px, 11vw, 176px) clamp(36px, 4.4vw, 64px);
}

/* Énoncé de clôture : Roboto condensé, pleine largeur du conteneur.
 *
 * PAS DE max-width. Les autres énoncés forts de la page sont bornés à
 * 34 caractères ; celui-ci doit tenir toute la largeur, c'est la demande.
 * Il garde donc la mesure du conteneur, pas celle de la lecture. */
.enonce-final {
  font-family: 'Roboto', system-ui, sans-serif;
  font-stretch: 75%;
  font-size: clamp(1.15rem, 1.9vw, 1.6rem);
  font-weight: var(--weight-medium);
  line-height: 1.4;
  color: var(--brand-petrole);
  max-width: none;
  margin: 0;
}

/* Texte courant des pages de contenu.
 *
 * CHAQUE COMPOSANT EST NOMMÉ, il n'y a pas de règle générale sur les <p>
 * de la section. La première version en avait une — `.section-page p` —
 * et elle écrasait tous les composants ci-dessus : à 0-1-1 contre 0-1-0
 * elle l'emportait, et le surtitre sortait en Roboto 16,8 px au lieu de
 * mono 11 px. Mesuré sur le rendu, pas déduit. Le prix est une liste plus
 * longue ; le gain est qu'aucun composant n'a à se défendre. */
.colonnes-texte p,
.duo-texte__corps p,
.vision__texte p,
.liste-marquee li,
.conclusion-section,
.mot-gerant__texte p {
  font-family: 'Roboto', system-ui, sans-serif;
  font-size: var(--type-body-lg);
  line-height: var(--leading-body);
  color: var(--neutral-encre);
}
/* Le mot du dirigeant est sur l'aplat pétrole : son texte y passe en
   blanc cassé. Sélecteur repris de .mot-gerant__attente, la classe
   d'attente remplacée le 21/09/2026 par le message réel. */
.section-page--petrole .mot-gerant__texte p { color: var(--neutral-blanc); }

/* Deux colonnes de prose. Le seuil de 60rem est celui au-dessous duquel
   une colonne passerait sous 34 caractères — trop court pour se lire. */
.colonnes-texte {
  display: grid;
  gap: clamp(24px, 3vw, 48px);
  max-width: 92ch;
}
.colonnes-texte p { margin: 0; max-width: var(--measure-body); }
@media (min-width: 60rem) {
  .colonnes-texte { grid-template-columns: 1fr 1fr; }
}

/* Corps + panneaux latéraux.
 *
 * align-items:stretch — la valeur par défaut, écrite ici parce qu'elle
 * PORTE UNE INTENTION : les deux colonnes doivent finir à la même
 * hauteur, c'est ce qui permet à la photo d'aligner son bas sur celui du
 * second panneau. Un align-items:start, qui était la valeur précédente,
 * laissait chaque colonne à sa hauteur propre. */
.duo-texte {
  display: grid;
  gap: clamp(28px, 3.4vw, 56px);
  align-items: stretch;
}
@media (min-width: 62rem) {
  .duo-texte { grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); }

  /* LA PHOTO ALIGNE SON BAS SUR CELUI DU SECOND PANNEAU (demande du
     client, 20/08). Elle ne peut pas le faire avec une hauteur à elle :
     la colonne de droite mesure ce que mesurent ses deux panneaux, ce que
     le CSS ne sait pas d'avance.

     C'est donc la colonne de GAUCHE qui devient une pile flexible, et la
     photo le seul élément élastique : les deux paragraphes prennent leur
     hauteur naturelle, la photo absorbe tout le reste. Les colonnes étant
     étirées à la même hauteur par la grille, son bas tombe exactement sur
     celui du panneau.

     Son rapport 4/3 doit être annulé — un aspect-ratio impose une hauteur
     et l'empêcherait de s'étirer. Le plancher de 240 px la protège du cas
     inverse, une colonne de droite plus courte que la gauche. */
  .duo-texte__corps {
    display: flex;
    flex-direction: column;
  }
  .duo-texte__corps .emplacement-photo {
    aspect-ratio: auto;
    flex: 1 1 auto;
    min-height: clamp(240px, 24vw, 380px);
    margin-block-end: 0;
  }
}
/* Roboto Condensed comme dans « Vision & Mission » (demande du client,
   20/08) : la chasse 75 % s'applique à tout le texte courant de la
   section, prose et listes, pour que le bloc reste homogène. Le
   @font-face de reference.css déclare `font-stretch: 75% 100%` — sans
   cette déclaration l'axe est ignoré et la largeur reste normale. */
.duo-texte__corps p,
.duo-texte__panneau .liste-marquee li { font-stretch: 75%; }

.duo-texte__corps p { margin: 0 0 var(--space-5); max-width: var(--measure-body); }

/* Les deux panneaux s'empilent dans la colonne de droite, séparés par le
   même écart que celui des colonnes. */
.duo-texte__panneaux {
  display: flex;
  flex-direction: column;
  gap: clamp(20px, 2.4vw, 32px);
}

.duo-texte__panneau {
  background: var(--neutral-blanc);
  border: var(--border-hairline);
  border-top: 3px solid var(--brand-jaune);
  padding: clamp(24px, 2.8vw, 36px);
}

.panneau__intitule {
  font-family: var(--font-display);
  font-size: var(--type-h4);
  font-weight: var(--weight-semibold);
  line-height: 1.4;
  color: var(--brand-petrole);
  margin: 0 0 var(--space-5);
}

/* Liste à filets plutôt qu'à puces : une puce ronde sur une page
   institutionnelle fait note de service, un filet fait sommaire. */
.liste-marquee { list-style: none; margin: 0; padding: 0; }
.liste-marquee li {
  position: relative;
  padding: var(--space-3) 0 var(--space-3) var(--space-6);
  border-top: var(--border-hairline);
}
.liste-marquee li:first-child { border-top: 0; padding-top: 0; }
.liste-marquee li::before {
  content: '';
  position: absolute;
  left: 0;
  top: calc(var(--space-3) + 0.62em);
  width: 14px;
  height: 2px;
  background: var(--brand-jaune);
}
.liste-marquee li:first-child::before { top: 0.62em; }

/* .intitule-liste, .grille-piliers et .pilier__num ont été retirés le
   20/08 : la liste « réputation » a rejoint le panneau des expertises, au
   même traitement à filets, et plus rien n'employait ces trois règles. */

/* Second intitulé du panneau : il se détache du bloc précédent par une
   marge haute, sans quoi les deux listes se liraient comme une seule. */
.panneau__intitule--suite {
  margin-top: clamp(28px, 3vw, 40px);
  padding-top: clamp(24px, 2.6vw, 32px);
  border-top: var(--border-hairline);
}

/* Conclusion de section : pleine largeur, agrandie, mise en emphase
   (demande du client, 20/08).
 *
 * Elle sort de la mesure de lecture — 66 caractères — et c'est assumé :
 * ce n'est pas un paragraphe qu'on lit ligne à ligne mais une phrase de
 * clôture qu'on embrasse d'un regard, comme les énoncés forts des autres
 * sections.
 *
 * PAS DE FILET AU-DESSUS (retiré le 20/08). L'emphase tient donc au seul
 * couple corps + graisse, et à la marge qui la détache de ce qui précède.
 *
 * Corps réduit deux fois le 20/08 : clamp(1.25, 2.2vw, 1.85) →
 * clamp(1.1, 1.6vw, 1.35) → clamp(1.05, 1.4vw, 1.2). Les trois bornes
 * baissent ensemble à chaque fois. À ce stade l'écart au texte courant
 * de la section — 16,8 px — n'est plus que de 2,4 px en desktop : c'est
 * la graisse 600 qui porte désormais l'essentiel de l'emphase. Descendre
 * plus bas la ferait disparaître.
 *
 * Elle garde Roboto en chasse 75 %, comme le reste du texte de la
 * section : c'est la graisse qui porte l'emphase, pas un changement de
 * famille. */
.conclusion-section {
  /* Écart au bloc précédent réduit le 20/08 : clamp(44px,5vw,72px) →
     clamp(24px,2.6vw,38px). C'est le seul séparateur qui reste depuis le
     retrait du filet, mais la phrase n'a plus besoin d'autant d'air : son
     corps a baissé d'un tiers dans le même mouvement. */
  margin: clamp(24px, 2.6vw, 38px) 0 0;
  max-width: none;
  font-stretch: 75%;
  font-size: clamp(1.05rem, 1.4vw, 1.2rem);
  font-weight: var(--weight-semibold);
  line-height: 1.45;
  color: var(--brand-petrole);
}

/* Mot du dirigeant.
 *
 * TEXTE À GAUCHE, PORTRAIT À DROITE depuis le 20/08 — c'est l'ordre du
 * balisage, la grille ne fait que lui donner ses largeurs.
 *
 * LE PORTRAIT S'AGRANDIT SANS QUE LA SECTION GRANDISSE. Sa hauteur était
 * dictée par un rapport 3/4 sur une colonne de 320 px, soit 427 px, et
 * c'est elle qui fixait la hauteur de la section. En élargissant la
 * colonne à 427 px et en passant le rapport au carré, la photo gagne
 * 107 px de large et garde exactement la même hauteur. Le retrait du
 * surtitre libère en plus une trentaine de pixels, que la section rend
 * — d'où une hauteur au total très proche, vérifiée sur le rendu. */
.mot-gerant {
  display: grid;
  gap: clamp(28px, 3.4vw, 56px);
  align-items: start;
}
@media (min-width: 56rem) {
  .mot-gerant { grid-template-columns: minmax(0, 1fr) minmax(280px, 427px); }
}
/* MARGES LATÉRALES RESSERRÉES DE 4 cm DE CHAQUE CÔTÉ sur cette seule
 * section : 2 cm le 21/09/2026, puis 2 cm de plus le même jour, à la
 * demande du client. La colonne de contenu gagne donc 8 cm au total, soit
 * 302 px, et les blancs de gauche et de droite fondent d'autant.
 *
 * PASSE PAR max-width ET NON PAR UNE MARGE NÉGATIVE : le conteneur est
 * centré par `margin-inline: auto`, c'est sa largeur maximale qui
 * commande les blancs. Une marge négative aurait décalé le bloc au lieu
 * de l'élargir. Même idiome que .conteneur-large, déjà employé ailleurs.
 *
 * SANS EFFET SOUS 1382 px de fenêtre : la largeur maximale ne joue plus,
 * ce sont les gouttières qui tiennent les bords — et on ne peut pas
 * retirer 4 cm d'une gouttière qui en fait un demi. */
.section-page--dirigeant .conteneur {
  max-width: calc(var(--width-content) + 8cm);
}

/* Blanc au-dessus du texte réduit de moitié (client, 21/09/2026) :
 * 101 → 50 px à 1440.
 *
 * LE BAS DE LA BANDE PERD 2 cm dans la foulée, même demande : 101 → 25 px
 * à 1440. `max()` l'empêche de passer sous 12 px sur les fenêtres
 * étroites, où le rythme de section descend à 56 px et où retirer 2 cm
 * collerait la signature au bord de l'aplat. */
.section-page--dirigeant {
  padding-block-start: calc(var(--rythme-section) / 2);
  padding-block-end: max(12px, calc(var(--rythme-section) - 2cm));
}

/* Message du dirigeant, arrivé le 21/09/2026. Il remplace
 * .mot-gerant__attente, qui tenait la place en italique et dont les
 * styles sont supprimés avec elle.
 *
 * LE FILET JAUNE EST CONSERVÉ, et c'est maintenant son vrai rôle : il
 * tenait lieu d'avertissement, il marque désormais une parole rapportée.
 * Pas d'italique en revanche — cinq paragraphes en italique se lisent
 * mal, et la signature suffit à désigner l'auteur. */
.mot-gerant__texte {
  border-left: 3px solid var(--brand-jaune);
  padding-left: clamp(20px, 2.4vw, 32px);
  margin: 0 0 var(--space-8);
  /* LIGNES PLUS LONGUES QUE LA MESURE COMMUNE (client, 21/09/2026) : le
     message tient ainsi sur moins de lignes. 66ch, la valeur des jetons,
     puis 86ch, le repliaient avant le bord de la colonne élargie.
     PLUS DE PLAFOND DU TOUT depuis la deuxième demande : le texte occupe
     toute sa colonne et s'arrête à l'écart de grille du portrait, une
     cinquantaine de pixels. Le prix est une ligne d'environ 95
     caractères, au-delà de la mesure confortable (66 à 80) : c'est un
     choix assumé pour la compacité, sur un bloc de treize lignes lu
     d'une traite. */
  max-width: none;
}
.mot-gerant__texte p { margin: 0; }
/* Écart entre paragraphes resserré d'un cran (client, 21/09/2026) :
   20 → 16 px, les deux valeurs venant des jetons. « Très légèrement » :
   le cran suivant, 12 px, mettrait les paragraphes à moins d'un
   interligne l'un de l'autre et la coupure cesserait de se voir. */
.mot-gerant__texte p + p { margin-block-start: var(--space-4); }
/* SIGNATURE ALIGNÉE À DROITE (client, 21/09/2026), comme au bas d'une
 * lettre : elle se lit alors comme la fin du message et non comme un
 * nouveau bloc. Le nom et la fonction suivent ensemble, la fonction étant
 * un <span> en display:block qui hérite de l'alignement. */
.mot-gerant__signature {
  font-family: var(--font-display);
  font-size: var(--type-h3);
  font-weight: var(--weight-semibold);
  line-height: 1.3;
  margin: 0;
  text-align: right;
}
.mot-gerant__role {
  display: block;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: var(--weight-regular);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--brand-jaune);
  margin-top: var(--space-2);
}

/* La grille d'atouts, puis la pile d'encarts empilables qui l'avait
   remplacée, ont toutes deux été supprimées le 21/08 avec leur section. */

/* .action-section, .bouton-page et son survol ont été retirés le 21/08
   avec le bouton de bas de page qu'ils habillaient. Plus rien ne les
   employait : le bouton d'appel du site vit dans l'en-tête, dessiné par
   styles/reference.css. */

/* Section qui se termine par un bloc pleine largeur : son rembourrage bas
   ferait réapparaître le fond de section sous ce bloc, il est donc
   supprimé, et le bloc perd sa marge basse. Le bloc touche alors le pied
   de page. */
.section-page--fin-pleine { padding-bottom: 0; }
.section-page--fin-pleine .bande-blanche { margin-bottom: 0; }

/* Emplacements de photos : variantes de format. Le composant de base est
   au rapport 4/3, défini plus haut.
 *
 * .emplacement-photo--bandeau a été retiré le 20/08 : le bandeau
 * panoramique de la section Vision a laissé la place à la photo en
 * colonne, et plus rien n'employait cette variante.
 *
 * Le portrait a changé trois fois : 3/4 → 1/1, pour s'élargir sans
 * gagner de hauteur ; 1/1 → 5/6, quand le client a demandé plus de
 * hauteur ; puis 5/6 → 3/4 le 21/08, pour qu'il dépasse franchement de
 * l'aplat. Sur une colonne de 427 px : 427 → 512 → 569. */
.emplacement-photo--portrait { aspect-ratio: 3 / 4; margin-block-end: 0; }

/* --- Vision & Mission : image et texte condensé ----------------------
 *
 * L'IMAGE EST DESCENDUE DE 100 px LE 20/08, à la demande du client :
 * elle remontait dans le hero, elle se tient maintenant entièrement en
 * dessous. Le calcul garde trace du chemin plutôt que d'afficher un
 * résultat opaque :
 *
 *     100px  descente demandée
 *   - --rythme-section  le rembourrage haut de la section, que la
 *                       position précédente annulait
 *   - clamp(...)        la remontée dans le hero, désormais annulée
 *
 * Le solde est négatif en desktop, positif en mobile — c'est normal, le
 * rembourrage de section n'y vaut pas la même chose. Ce qui compte est
 * mesuré : la figure démarre 48 à 80 px SOUS le bas du hero selon la
 * largeur, sans jamais le toucher.
 *
 * Pourquoi la remontée était possible, et le reste si on y revient : la
 * figure appartient à cette section, pas au hero, et le hero ne la clippe
 * pas — son overflow:hidden ne vaut que pour ses propres enfants. Elle
 * passerait devant lui sans z-index, le hero étant en position relative
 * sans z-index, donc sans contexte d'empilement.
 */
.vision {
  display: grid;
  gap: clamp(28px, 3.4vw, 56px);
  align-items: start;
}
@media (min-width: 62rem) {
  .vision { grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr); }
}

/* Le rapport a bougé deux fois le 20/08 : 3/4 → 10/11 pour raccourcir la
   photo par le haut, puis 10/11 → 7/9 pour la rallonger, toujours par le
   haut, jusqu'à ce que son bord supérieur passe AU-DESSUS du titre
   « Vision & Mission ». Le bord bas n'a bougé dans aucun des deux sens. */
.vision__photo {
  position: relative;
  aspect-ratio: 7 / 9;
  margin-top: calc(100px - var(--rythme-section) - clamp(20px, 3.6vw, 52px));
  margin-bottom: 0;
}

/* EN DEUX COLONNES, LA PHOTO DÉMARRE AU-DESSUS DU TITRE « Vision &
   Mission » (demande du client, 20/08). Le titre est le premier élément
   de la colonne de droite : son haut se trouve donc exactement au
   rembourrage haut de la section. Une marge NÉGATIVE fait remonter la
   photo de cette avance-là, et rien d'autre.

   C'EST UNE AVANCE, PAS UNE POSITION ABSOLUE, et c'est ce qui a corrigé
   la version précédente. Celle-ci ancrait la photo sur une constante de
   100 px pendant que le titre, lui, suivait --rythme-section, qui va de
   56 à 104 px selon la largeur. Les deux se croisaient : mesuré, la photo
   passait bien avant le titre à 1440 px mais 10 px APRÈS lui à 1024. En
   partant du même rembourrage, l'avance est vraie partout.

   CETTE RÈGLE VIENT APRÈS LA RÈGLE DE BASE, et ce n'est pas indifférent :
   les deux pèsent 0-1-0, donc c'est la dernière écrite qui l'emporte. Un
   premier essai la plaçait plus haut dans le fichier — la media query
   était bien évaluée, mais la règle de base la réécrivait juste après.

   En dessous de ce seuil la grille s'empile : le titre passe SOUS la
   photo, il n'y a plus rien à devancer, et la règle de base s'applique. */
@media (min-width: 62rem) {
  .vision__photo {
    margin-top: calc(-1 * clamp(16px, 2.4vw, 34px));
  }
}

.vision__texte .titre-page-section { margin-block-end: clamp(20px, 2.4vw, 30px); }
.vision__texte p { margin: 0 0 var(--space-5); max-width: var(--measure-body); }
.vision__texte p:last-child { margin-bottom: 0; }

/* ROBOTO CONDENSED SANS SECOND FICHIER (demande du client, 20/08).
   Roboto Condensed est une famille distincte chez Google Fonts, donc un
   fichier de plus à servir. Le fichier variable de Roboto porte un axe de
   chasse : font-stretch: 75% en tire le même dessin. Le @font-face de
   reference.css déclare `font-stretch: 75% 100%` — sans cette déclaration
   le navigateur ignore l'axe et rend la largeur normale. */
.vision__texte p { font-stretch: 75%; }

/* SÉLECTEUR À DEUX CLASSES, et c'est nécessaire : `.vision__texte p`
   compte 0-1-1 et l'emporterait sur un `.enonce-fort--condense` seul, qui
   ne compte que 0-1-0. Mesuré avant correction, le paragraphe accentué
   sortait à 16,8 px au lieu de 24 — il gardait son filet et sa graisse,
   ce qui suffisait à le faire passer pour accentué à l'œil. C'est la même
   collision que celle corrigée plus haut sur les composants de section :
   une règle de contexte doit rester plus faible que les composants
   qu'elle contient, ou bien ceux-ci doivent monter avec elle. */
.vision__texte .enonce-fort--condense {
  font-family: 'Roboto', system-ui, sans-serif;
  font-stretch: 75%;
  font-weight: var(--weight-medium);
  /* Réduit le 20/08 : clamp(1.2, 1.9vw, 1.5) → clamp(1.1, 1.6vw, 1.3).
     Les trois bornes baissent ensemble. */
  font-size: clamp(1.1rem, 1.6vw, 1.3rem);
  line-height: 1.4;
  letter-spacing: 0;
  max-width: none;
}

/* --- Photos fournies ------------------------------------------------
 *
 * Le cadre garde sa classe .emplacement-photo : toute la mise en page
 * des colonnes y tient — rapport, étirement, marges négatives. Le
 * modificateur ne fait qu'une chose : retirer ce qui signalait
 * l'attente, la trame hachurée et le filet.
 *
 * L'image remplit le cadre en `cover`. C'est la mise en page qui décide
 * de la hauteur — la photo Vision suit un rapport 7/9, celle de
 * l'Héritage s'étire pour aligner son bas sur le panneau voisin — donc
 * aucun rapport ne peut être imposé au fichier lui-même. `cover` recadre
 * au centre plutôt que de déformer.
 *
 * <picture> sert le WebP aux navigateurs qui l'annoncent et le JPEG aux
 * autres. width et height sont déclarés sur le <img> pour que la place
 * soit réservée avant le chargement, sans saut de mise en page. */
.emplacement-photo--remplie {
  background: none;
  border: 0;
  padding: 0;
}
.emplacement-photo--remplie picture,
.emplacement-photo--remplie img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Photo raccourcie (client, 21/09/2026), pour la section Notre Héritage.
 *
 * ELLE ÉTAIT HAUTE PARCE QU'ELLE S'ÉTIRAIT, et non à cause du fichier :
 * en grand écran, `.duo-texte__corps .emplacement-photo` lui donne
 * `flex: 1 1 auto` et annule son rapport, pour qu'elle absorbe la hauteur
 * restante et que le bas de la colonne tombe sur celui du panneau voisin.
 * Elle mesurait ainsi 560 × 700.
 *
 * La photo reprend donc un rapport fixe — 4/3, celui du cadre par défaut
 * — et cesse de grandir. Le bas des deux colonnes ne coïncide plus
 * exactement ; comme le cadre n'a ni filet ni fond en `--remplie`, ce qui
 * reste sous la photo est du blanc, invisible.
 *
 * LE RECADRAGE EST CENTRÉ, par le `object-fit: cover` ci-dessus : rien
 * n'est déformé, le haut et le bas de la photo sont rognés.
 *
 * Sélecteur à deux classes pour l'emporter sur la règle d'étirement, de
 * même poids, et placé après elle. */
/* PUIS RALLONGÉE DE 4 cm (client, 21/09/2026), soit 151 px à l'écran —
 * un centimètre CSS valant 37,8 px par définition.
 *
 * La hauteur s'écrit « trois quarts de la largeur de la colonne, plus
 * 4 cm » : le 4/3 sert de base, l'ajout est constant, et l'ensemble suit
 * la largeur de la fenêtre. `cqw` mesure la largeur du conteneur, d'où le
 * `container-type` posé sur la colonne juste en dessous.
 *
 * `aspect-ratio` EST GARDÉ AVANT, comme repli : un navigateur qui ignore
 * les unités de conteneur ignore la ligne `height` et retombe sur le
 * cadre 4/3, sans photo démesurée. */
.duo-texte__corps { container-type: inline-size; }
.duo-texte__corps .emplacement-photo--surbaissee {
  aspect-ratio: 4 / 3;
  /* `width` EST INDISPENSABLE avec `height` : sous 60rem la colonne n'est
     plus un conteneur flex, la figure y est un bloc ordinaire, et une
     hauteur imposée sans largeur laissait le rapport 4/3 CALCULER la
     largeur — 414 px de haut donnaient 552 px de large, qui débordaient
     d'un écran de 390. */
  width: 100%;
  height: calc(75cqw + 4cm);
  flex: 0 0 auto;
  min-height: 0;
}

/* Fond du mini hero de la page Entreprise.
 *
 * Il remplace la photo du hero de l'accueil, servie par .fond-hero. Deux
 * largeurs : la petite est appelée sous 1200 px, où l'écran ne peut pas
 * tirer parti des 1920. 92 Ko contre 36, l'écart valait la media query.
 *
 * WebP seul, comme les fonds de cartes de l'accueil : un fond CSS n'a pas
 * de <picture> pour négocier le format, et WebP est lu partout depuis
 * 2020. Les deux déclarations de .fond-hero — url() puis image-set() —
 * sont remplacées d'un coup, la seconde ayant priorité dans la feuille
 * du clone. */
.hero-mini--entreprise .fond-hero {
  background-image: url('/assets/photos/entreprise/hero-entreprise-1100.webp');
  background-position: center 38%;
}
@media (min-width: 75rem) {
  .hero-mini--entreprise .fond-hero {
    background-image: url('/assets/photos/entreprise/hero-entreprise-1920.webp');
  }
}

/* Fonds des mini heros — Activités, Réalisations, Actualités.
 *
 * Photos fournies par le client, nommées d'après la page, préparées par
 * `npm run heros` (tools/preparer-heros.mjs) : deux largeurs, 1100 et
 * 1920, au format panoramique du mini hero.
 *
 * DEUX DÉCLARATIONS PAR RÈGLE, comme .fond-hero de la feuille du clone :
 * d'abord le WebP en `url()`, ensuite `image-set()` qui propose l'AVIF.
 * Un navigateur qui ignore `image-set()` garde la première ; les autres
 * prennent l'AVIF, deux fois plus léger. La seconde déclaration écrase la
 * première dans le même bloc — c'est le repli de format en CSS.
 *
 * La page Entreprise garde ses propres règles ci-dessus : ses fichiers
 * sortent d'un autre outil et n'ont pas d'AVIF. */
.hero-mini--activites .fond-hero {
  background-image: url('/assets/photos/heros/hero-activites-1100.webp');
  background-image: image-set(
    url('/assets/photos/heros/hero-activites-1100.avif') type('image/avif'),
    url('/assets/photos/heros/hero-activites-1100.webp') type('image/webp')
  );
  /* Cadrée sur le BAS de la photo (client, 22/09/2026) : le fichier est
     déjà rogné par le bas dans preparer-heros.mjs, et cette position
     garde le même parti pour le rognage résiduel — la bande du hero
     n'ayant pas exactement le rapport du fichier. */
  background-position: center bottom;
}
.hero-mini--realisations .fond-hero {
  background-image: url('/assets/photos/heros/hero-realisations-1100.webp');
  background-image: image-set(
    url('/assets/photos/heros/hero-realisations-1100.avif') type('image/avif'),
    url('/assets/photos/heros/hero-realisations-1100.webp') type('image/webp')
  );
  background-position: center 55%;
}
.hero-mini--actualites .fond-hero {
  background-image: url('/assets/photos/heros/hero-actualites-1100.webp');
  background-image: image-set(
    url('/assets/photos/heros/hero-actualites-1100.avif') type('image/avif'),
    url('/assets/photos/heros/hero-actualites-1100.webp') type('image/webp')
  );
  background-position: center center;
}
@media (min-width: 75rem) {
  .hero-mini--activites .fond-hero {
    background-image: url('/assets/photos/heros/hero-activites-1920.webp');
    background-image: image-set(
      url('/assets/photos/heros/hero-activites-1920.avif') type('image/avif'),
      url('/assets/photos/heros/hero-activites-1920.webp') type('image/webp')
    );
  }
  .hero-mini--realisations .fond-hero {
    background-image: url('/assets/photos/heros/hero-realisations-1920.webp');
    background-image: image-set(
      url('/assets/photos/heros/hero-realisations-1920.avif') type('image/avif'),
      url('/assets/photos/heros/hero-realisations-1920.webp') type('image/webp')
    );
  }
  .hero-mini--actualites .fond-hero {
    background-image: url('/assets/photos/heros/hero-actualites-1920.webp');
    background-image: image-set(
      url('/assets/photos/heros/hero-actualites-1920.avif') type('image/avif'),
      url('/assets/photos/heros/hero-actualites-1920.webp') type('image/webp')
    );
  }
}

/* --- Secteurs d'activités (page Activités) --------------------------
 *
 * Quatre blocs de même plan, dans quatre sections dont seul le fond
 * alterne. Le composant ne connaît donc pas son rang : il n'y a rien ici
 * qui distingue le premier secteur du dernier.
 *
 * DEUX COLONNES : à gauche le numéro, l'intitulé, l'accroche et la
 * photo ; à droite le panneau des sous-expertises. La colonne gauche est
 * un peu plus large — 1,15 contre 1 — parce qu'elle porte le titre, qui
 * a besoin de place pour ne pas se replier sur trois lignes, tandis que
 * la liste tient dans une colonne étroite.
 *
 * `align-items: stretch` est ici ce qu'il est dans .duo-texte, et pour
 * la même raison : la photo doit pouvoir s'étirer jusqu'au bas du
 * panneau voisin. */
.secteur {
  display: grid;
  gap: clamp(28px, 3.4vw, 56px);
  align-items: stretch;
}
@media (min-width: 62rem) {
  .secteur { grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); }

  /* LA PHOTO GARDE SON RAPPORT 4/3, celui des fichiers préparés : à 522 px
     de colonne elle mesure 391 px, la même hauteur dans les quatre
     secteurs. C'est ce qui les fait lire comme une série.

     Elle ne s'aligne donc PAS sur le bas du panneau voisin, contrairement
     à la photo de la page Entreprise. La différence est voulue : là-bas
     une seule photo devait fermer un bloc, ici quatre photos doivent se
     répondre, et une hauteur qui suivrait la longueur de chaque liste
     ferait quatre cadres différents — le secteur 04, cinq sous-expertises
     contre sept, aurait une photo visiblement plus courte.

     `flex: 0 0 auto` dans une colonne flexible : la pile sert à empiler,
     pas à étirer. Sans cette déclaration, la photo du secteur 01 gagnerait
     les quelques pixels qui séparent sa colonne de la colonne voisine et
     sortirait seule du rang. */
  .secteur__tete {
    display: flex;
    flex-direction: column;
  }
  .secteur__photo {
    flex: 0 0 auto;
    margin-block-end: 0;
  }

  /* SAUF SUR LES TROIS PREMIERS SECTEURS (client, 22/09/2026), où la photo
   * s'étire jusqu'au bas du panneau voisin. La série de quatre cadres
   * égaux, expliquée ci-dessus, cède donc devant l'alignement demandé.
   *
   * `aspect-ratio: auto` EST INDISPENSABLE : un rapport impose une hauteur
   * et empêche l'étirement. Les colonnes étant déjà étirées à la même
   * hauteur par la grille (align-items: stretch), la photo qui absorbe le
   * reste de la colonne tombe exactement sur le bas du panneau.
   *
   * Le quatrième secteur garde son rapport 4/3 : sa liste est plus courte
   * et sa photo dépasse déjà le panneau — l'étirer la raccourcirait. */
  .secteur--photo-alignee .secteur__photo {
    /* `flex-basis: 0` ET NON `auto` : avec `auto`, la taille de départ est
       celle de l'image — 396 px à 1100 px de fenêtre — et le cadre
       dépassait encore le panneau de 22 px sur le secteur 03, mesuré. À
       zéro, la photo prend exactement l'espace que le titre et l'accroche
       laissent, donc s'aligne au pixel. */
    flex: 1 1 0;
    aspect-ratio: auto;
    min-height: clamp(240px, 24vw, 391px);
  }
}

/* Le numéro n'est pas un titre : c'est un repère de lecture, au même
   registre que les surtitres du site — mono, capitales, interlettrage
   large.
 *
 * PÉTROLE ET NON JAUNE. Le jaune était le premier choix, et il était
 * illisible : 1,55:1 sur le papier, 1,70:1 sur le blanc, mesurés sur les
 * deux fonds que la page alterne. À 11 px il faut 4,5:1. Le pétrole donne
 * 9,14:1 et 10,02:1, et c'est déjà la couleur des surtitres du site sur
 * fond clair — le jaune y sert de filet, pas de texte. */
/* .secteur__num — la numérotation « 01 » à « 04 » qui précédait chaque
   intitulé de secteur — a été retirée le 22/09/2026 à la demande du
   client, avec ses styles. */

/* L'intitulé du secteur reprend .titre-page-section, dont la max-width de
   22ch est ANNULÉE : c'est la colonne qui doit décider du repli, pas un
   compte de caractères.

   Mesuré, la max-width donnait deux lignes aux trois premiers secteurs et
   TROIS au quatrième, « Commerce & Location d'équipements » étant le plus
   long des quatre. Un titre plus haut décale tout ce qui le suit — la
   photo du secteur 04 ne commençait plus à la même hauteur que les
   autres. Sans plafond, les quatre tiennent en deux lignes dans les
   522 px de la colonne.

   La marge basse se resserre : l'accroche appartient au titre, elle ne
   doit pas s'en détacher. */
.secteur .titre-page-section {
  max-width: none;
  margin-bottom: var(--space-4);
}

/* L'accroche dit ce que fait le secteur, en une phrase. Elle se lit comme
   une légende du titre : Roboto condensé, corps intermédiaire entre le
   titre et le texte courant, et le filet jaune qui marque partout ailleurs
   sur le site ce qui est mis en avant. */
.secteur__accroche {
  font-family: 'Roboto', system-ui, sans-serif;
  font-stretch: 75%;
  font-size: clamp(1.05rem, 1.5vw, 1.3rem);
  line-height: 1.45;
  color: var(--neutral-encre);
  max-width: 34ch;
  /* Écart avec la photo réduit de moitié (client, 22/09/2026) :
     40 → 20 px au plus large. L'accroche et la photo illustrent le même
     secteur, elles se tiennent de plus près. */
  margin: 0 0 clamp(14px, 1.5vw, 20px);
  padding-left: var(--space-5);
  border-left: 3px solid var(--brand-jaune);
}

/* CADRE ÉLARGI pour les deux accroches longues — « Génie civil &
 * Construction » et « Commerce & Location d'équipements » (client,
 * 22/09/2026). À 34ch, elles se repliaient sur trois lignes quand les
 * deux autres en tenaient deux.
 *
 * Les deux textes font 89 et 96 caractères : il en faut donc environ 48
 * par ligne. 52ch laisse la marge nécessaire aux coupures de mots, sans
 * dépasser la colonne. Le gabarit pose la classe d'après une clé du
 * tableau des secteurs, et non d'après un rang : si l'ordre change, le
 * cadre suit le bon texte. */
.secteur__accroche--large { max-width: 52ch; }

/* Le panneau ne se colle pas en haut de sa colonne : il descend jusqu'au
   pied de l'accroche, de sorte que la liste commence là où le propos du
   secteur est posé. `stretch` sur la grille l'étirerait sinon sur toute
   la hauteur, filet jaune compris, et les deux colonnes commenceraient
   ensemble — ce qui ferait lire la liste comme une seconde colonne du
   titre plutôt que comme son développement. */
@media (min-width: 62rem) {
  .secteur__panneau {
    align-self: start;
    margin-top: clamp(40px, 5vw, 76px);
  }

  /* SAUF LÀ OÙ LA PHOTO N'EST PAS ÉTIRÉE : le panneau descend alors au bas
   * de la colonne, et son pied tombe sur celui de la photo (client,
   * 22/09/2026). Cela ne vise aujourd'hui que le secteur 04, le seul dont
   * la photo dépasse le panneau — 47 px mesurés.
   *
   * LA RÈGLE SE LIT DE LA PHOTO, et non d'un rang ou d'un quatrième
   * drapeau : les deux réglages disent la même chose — aligner les pieds
   * des deux colonnes — et suivront ensemble si le contenu change de
   * longueur. La marge haute est conservée comme garde : elle empêche le
   * panneau de remonter coller au titre si la photo devenait très haute. */
  .secteur:not(.secteur--photo-alignee) .secteur__panneau {
    align-self: end;
  }
}

/* --- Réalisations ---------------------------------------------------
 *
 * Un projet par section, quatre sections dont seul le fond alterne. Le
 * plan reprend celui de la page Activités — surtitre, titre, deux
 * colonnes — mais la galerie le prolonge sur toute la largeur, et c'est
 * elle qui porte la page : sur un site de travaux, ce sont les photos de
 * chantier qui prouvent, pas le texte.
 *
 * LE SURTITRE EST LA CATÉGORIE, pas un numéro. Même traitement que
 * .surtitre-page — mono, capitales, interlettrage large, pétrole — dont
 * il ne se distingue que par son origine : celui-ci vient du JSON. */
.projet__categorie {
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--brand-petrole);
  margin: 0 0 var(--space-4);
}

/* Le titre d'un projet est long — « Unité de transformation d'anacarde —
   Péni, Bobo-Dioulasso » fait 52 caractères. La max-width de 22ch le
   replierait sur trois lignes alors qu'il occupe ici toute la largeur du
   conteneur, où il en tient une ou deux. Elle est portée à 34ch : assez
   pour ces titres, pas assez pour laisser une ligne courir sur les
   1280 px du conteneur, ce qui la rendrait pénible à suivre. */
.projet__titre {
  max-width: 34ch;
  /* Resserré le 22/08 à la demande du client : la phrase descriptive
     appartient au titre, elle ne doit pas s'en détacher. De
     clamp(24,2.8vw,36) à clamp(10,1.1vw,14) — 36 px à 14 px sur un écran
     ordinaire. */
  margin-bottom: clamp(10px, 1.1vw, 14px);
}

/* La phrase descriptive se lit sous le titre, avant les photos (demande
   du client, 22/08).
 *
 * SON CORPS A ÉTÉ RÉDUIT le 22/08, également à la demande du client : de
 * clamp(1.05rem, 1.5vw, 1.3rem) — 20,8 px sur un écran ordinaire — au
 * corps du texte courant du site. Elle était traitée en énoncé parce
 * qu'elle faisait face à un panneau de lots aujourd'hui disparu ; ce
 * n'est plus utile depuis que les photos occupent toute la largeur.
 *
 * `--measure-body` la replie avant le bord : sur 1280 px, une ligne
 * courrait sur une centaine de caractères et deviendrait pénible à
 * suivre. */
.projet__enonce {
  font-family: 'Roboto', system-ui, sans-serif;
  font-stretch: 75%;
  font-size: var(--type-body);
  line-height: var(--leading-body);
  color: var(--neutral-encre);
  max-width: var(--measure-body);
  /* Resserré DEUX FOIS le 22/08 à la demande du client : clamp(28,3.4vw,44)
     puis clamp(16,1.8vw,24) puis la valeur ci-dessous, soit 44 → 24 → 15 px
     sur un écran ordinaire. La phrase annonce la photo, elle ne s'en
     détache pas. */
  margin: 0 0 clamp(10px, 1.1vw, 15px);
}

/* --- Carrousel de chantier (page Réalisations) ----------------------
 *
 * Remplace la grille de galerie depuis le 22/08 (demande du client).
 *
 * LE DÉFILEMENT EST NATIF, il ne doit rien à JavaScript : une zone à
 * débordement horizontal et `scroll-snap-type` suffisent. Au doigt, au
 * pavé tactile, à la molette et aux flèches du clavier, la piste défile
 * déjà. scripts/carrousel.js n'ajoute que les chevrons et les points.
 *
 * UNE SEULE PHOTO AU REPOS depuis le 22/08 (demande du client, sur le
 * modèle d'Instagram et de TikTok).
 *
 * IL OCCUPE TOUTE LA LARGEUR DU CONTENEUR, et rien de plus. Il n'a donc
 * aucune largeur propre : celle de son parent lui suffit.
 *
 * Il est sorti du conteneur un moment le 22/08 — enfant direct de
 * <section>, il prenait alors la largeur de la fenêtre. Le client l'a
 * ramené dans les marges le jour même : le carrousel ne doit pas déborder
 * du gabarit de la page. Le plafond de 660 px qui le précédait ne revient
 * pas pour autant, il occupe bien toute la colonne.
 *
 * IL N'A PLUS QU'UNE RANGÉE DE GRILLE. Les points étaient en dessous ; ils
 * sont maintenant SUR la photo, donc dans la même cellule qu'elle. La
 * grille sert uniquement à superposer piste, voile, chevrons et points
 * sans positionnement absolu. */
/* IL N'Y A PLUS QU'UNE BORDURE, EN BAS (demande du client, 22/08). Le
 * cadre complet a existé une demi-journée : pétrole, puis anthracite,
 * puis blanc, avec un bas d'abord deux fois plus épais que les côtés,
 * puis trois, puis cinq. Les trois autres côtés sont retirés ; il ne
 * reste que cette bande.
 *
 * SON ÉPAISSEUR : 28 px sur mobile, 36 px sur ordinateur. Elle est écrite
 * directement, puisqu'il n'y a plus de côtés dont elle serait le multiple.
 *
 * ELLE A ÉTÉ ALLÉGÉE de 30/40 px à la demande du client (22/08), et le
 * plancher de 28 est le point d'arrêt : la rangée de points mesure 22 px,
 * et en dessous de 28 elle toucherait les bords de la bande. C'est ce
 * plancher, et non l'œil, qui borne toute réduction ultérieure.
 *
 * LE FILET EXTÉRIEUR A DISPARU AVEC LE CADRE. Il n'existait que pour
 * qu'un cadre blanc reste visible sur une section blanche ; une bande
 * sapin se voit d'elle-même — 7,62:1 sur le papier, 8,36:1 sur le blanc —
 * et un filet dessinerait de toute façon la boîte que le client vient de
 * supprimer.
 *
 * CE N'EST PLUS UN CADRE MAIS UN SOCLE, et il garde la fonction que le
 * bas avait prise : porter la rangée de points. C'est même son seul rôle
 * désormais, ce qui justifie qu'il soit resté aussi épais. */
.carrousel {
  --cadre-bas: clamp(28px, 2.6vw, 36px);
  position: relative;
  display: grid;
  border-bottom: var(--cadre-bas) solid var(--brand-sapin);
  /* CET ÉCART EST CELUI QUI SÉPARE LA BANDE VERTE DU FILET DES LOTS : le
     filet est le bord haut de .projet__lots, immédiatement sous le
     carrousel, donc rien d'autre ne s'intercale. Resserré DEUX FOIS le
     22/08 à la demande du client, de clamp(20,2.4vw,32) à
     clamp(12,1.3vw,18) puis à la valeur ci-dessous — 32 → 18 → 11 px sur
     un écran ordinaire. */
  margin-bottom: clamp(7px, 0.75vw, 11px);
}
.carrousel__piste { grid-area: 1 / 1; }

/* La piste est la zone qui défile. Elle reçoit le focus — une zone
   défilante inatteignable au clavier serait un cul-de-sac — et son
   contour de focus doit rester visible : il est décalé vers l'intérieur,
   sinon il tombe sous la section voisine.
 *
 * `overscroll-behavior-x: contain` empêche le geste de déborder sur
 * l'historique du navigateur : sur un pavé tactile, arriver en bout de
 * piste ne doit pas revenir à la page précédente.
 *
 * LA BARRE DE DÉFILEMENT EST MASQUÉE (demande du client, 22/08). Deux
 * déclarations sont nécessaires et ne se remplacent pas : `scrollbar-
 * width` est la propriété normalisée, lue par Firefox et par les Chrome
 * récents ; le pseudo-élément `-webkit-` couvre Safari, qui ne l'implémente
 * pas encore.
 *
 * MASQUER LA BARRE RETIRE UN REPÈRE. Elle disait à la fois qu'il restait
 * des photos et où l'on en était. Les points la remplacent dans ces deux
 * rôles — c'est pour cela qu'ils comptent, et non parce qu'ils décorent. */
.carrousel__piste {
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
}
.carrousel__piste::-webkit-scrollbar {
  display: none;
}
.carrousel__piste:focus-visible {
  outline: 3px solid var(--brand-jaune);
  outline-offset: -3px;
}

/* Le rail est la grille des vues, en colonnes que le contenu ne peut pas
   élargir : `grid-auto-columns: 100%` donne UNE VUE ET UNE SEULE par
   écran, à toutes les largeurs (demande du client, 22/08).
 *
 * Une version précédente laissait dépasser un aperçu de la vue suivante —
 * 46 % sur ordinateur, deux photos et un bout de la troisième. L'aperçu
 * servait de signal qu'il restait des photos ; ce sont les points qui
 * portent ce rôle maintenant.
 *
 * L'ÉCART DE 0 EST DÉLIBÉRÉ. Avec une vue par écran, un écart ne se voit
 * jamais au repos : il n'apparaît qu'en cours de glissement, comme une
 * fente entre deux photos. Il fausserait en plus le pas, qui vaut une vue
 * PLUS l'écart. */
.carrousel__rail {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 100%;
  gap: 0;
  list-style: none;
  margin: 0;
  padding: 0;
}

/* `scroll-snap-align: start` accroche le bord gauche de la vue au bord de
   la piste : après un pas, la première photo visible est entière. Un
   `center` la centrerait et couperait les deux voisines. */
.carrousel__vue {
  margin: 0;
  /* 16/9 depuis le 22/08 : à pleine largeur, un cadre carré ferait 1440 px
     de haut sur un écran ordinaire — plus d'un écran et demi. Le 16/9 le
     ramène à 810. Le même rapport est appliqué aux fichiers à la
     préparation, celui-ci ne fait que réserver la place avant leur
     chargement. */
  aspect-ratio: 16 / 9;
  overflow: hidden;
  scroll-snap-align: start;
  background: var(--neutral-papier);
}
.carrousel__vue picture,
.carrousel__vue img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Le fond de la vue est visible tant que la photo n'est pas chargée ; sur
   les sections en papier il faut l'autre teinte, sans quoi la piste est
   invisible pendant le chargement. */
.section-page--papier .carrousel__vue {
  background: var(--neutral-blanc);
}

/* Chevrons créés par scripts/carrousel.js. Ils n'existent donc pas si le
   script ne s'exécute pas, et le script les masque quand la piste ne
   déborde pas — Péni et la MUTRAF n'ont que deux photos, qui tiennent
   dans la largeur.
 *
 * ILS SONT PLACÉS PAR LA GRILLE, non en positionnement absolu. Posés dans
 * la MÊME CELLULE que la piste — rangée 1, colonne 1 — ils se centrent sur
 * la photo quelle que soit sa hauteur, sans aucun calcul à tenir à jour.
 *
 * Le fond est opaque et non translucide : au-dessus d'une photo de
 * chantier, un fond translucide donne un contraste qui dépend de ce qu'il
 * y a dessous, donc invérifiable. Pétrole sur blanc, le chevron est à
 * 10,02:1. */
.carrousel__bouton {
  grid-area: 1 / 1;
  align-self: center;
  z-index: 2;
  width: 48px;
  height: 48px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--neutral-blanc);
  box-shadow: 0 2px 12px rgb(14 26 29 / 0.28);
  cursor: pointer;
  display: grid;
  place-items: center;
  transition: background 160ms ease, opacity 160ms ease;
}
/* Ils sont RENTRÉS dans la photo, et non posés à cheval sur son bord :
   des marges négatives les pousseraient dans la marge de la page, que le
   carrousel ne doit pas franchir. */
.carrousel__bouton--precedent { justify-self: start; margin-left: clamp(12px, 2vw, 28px); }
.carrousel__bouton--suivant { justify-self: end; margin-right: clamp(12px, 2vw, 28px); }

.carrousel__bouton:hover { background: var(--brand-jaune); }
.carrousel__bouton:focus-visible {
  outline: 3px solid var(--brand-petrole);
  outline-offset: 2px;
}

/* Désactivé en bout de piste : atténué mais TOUJOURS VISIBLE. Le retirer
   ferait sauter l'autre bouton d'un bord à l'autre à chaque extrémité. */
.carrousel__bouton[disabled] {
  opacity: 0.38;
  cursor: default;
}
.carrousel__bouton[disabled]:hover { background: var(--neutral-blanc); }

/* Le chevron est dessiné avec deux bords d'un carré vide tourné de 45° :
   pas de fichier d'icône à charger pour deux traits. */
.carrousel__chevron {
  width: 11px;
  height: 11px;
  border-top: 2px solid var(--brand-petrole);
  border-right: 2px solid var(--brand-petrole);
}
.carrousel__bouton--suivant .carrousel__chevron {
  transform: translateX(-2px) rotate(45deg);
}
.carrousel__bouton--precedent .carrousel__chevron {
  transform: translateX(2px) rotate(-135deg);
}

/* Sous 48rem les chevrons sont retirés : le geste au doigt suffit, et à
   cette largeur ils couvriraient une part notable de la photo. Les points
   restent — c'est là qu'ils comptent le plus, puisque plus rien d'autre
   n'indique combien de photos il reste. */
@media (max-width: 47.99rem) {
  .carrousel__bouton { display: none; }
}

/* LES CHEVRONS N'APPARAISSENT QU'AU SURVOL (demande du client, 22/08).
 *
 * SOUS `@media (hover: hover)` ET NON SANS CONDITION. Sur un appareil
 * tactile il n'y a pas de survol : la règle y masquerait les chevrons
 * pour de bon, sans jamais rien pour les faire revenir. Une tablette de
 * plus de 48rem — au-dessus du seuil qui les retire — les garde donc
 * visibles en permanence.
 *
 * `:focus-within` accompagne `:hover` : la piste est focalisable, et
 * quelqu'un qui navigue au clavier doit voir les commandes qu'il atteint.
 * Sans cette clause, le chevron prendrait le focus en restant invisible.
 *
 * L'ÉTAT DÉSACTIVÉ EST NOMMÉ DANS LES DEUX SENS, et il l'a fallu.
 *
 * Au repos d'abord : `.carrousel__bouton[disabled]` vaut 0-2-0 contre
 * 0-1-0 pour le masquage, et l'emportait. Mesuré sur le rendu, le chevron
 * de bout de piste restait visible à 0,38 alors que son voisin actif
 * disparaissait bien — l'inverse exact de l'effet voulu.
 *
 * Au survol ensuite : à 0-2-0 contre 0-2-0, la règle de révélation
 * l'emporterait cette fois par simple ordre d'écriture, et le chevron
 * désactivé reviendrait à pleine opacité comme s'il était actif.
 *
 * `pointer-events` suit l'opacité : un bouton invisible ne doit pas
 * pouvoir être cliqué par mégarde. */
@media (hover: hover) {
  .carrousel__bouton,
  .carrousel__bouton[disabled] {
    opacity: 0;
    pointer-events: none;
  }
  .carrousel:hover .carrousel__bouton,
  .carrousel:focus-within .carrousel__bouton {
    opacity: 1;
    pointer-events: auto;
  }
  .carrousel:hover .carrousel__bouton[disabled],
  .carrousel:focus-within .carrousel__bouton[disabled] {
    opacity: 0.38;
  }
}

/* --- Points du carrousel --------------------------------------------
 *
 * Une pastille par photo, sur le modèle d'Instagram et de TikTok
 * (demande du client, 22/08). Créées par scripts/carrousel.js, elles
 * n'existent donc pas sans lui.
 *
 * ELLES SONT DANS L'ÉPAISSEUR DE LA BORDURE BASSE (demande du client,
 * 22/08). C'est leur troisième emplacement de la journée : d'abord sous
 * la photo, puis dessus avec un voile dégradé pour rendre leur contraste
 * vérifiable, maintenant dans le cadre.
 *
 * CE DÉPLACEMENT SUPPRIME LE VOILE, et c'est un gain net. Le voile
 * n'existait que parce que le fond des points était une photo, donc
 * inconnu — tantôt ciel clair, tantôt terre sombre — et qu'il fallait
 * l'uniformiser pour pouvoir mesurer quoi que ce soit. Sur l'anthracite
 * du cadre le fond est une couleur fixe : le contraste se lit
 * directement, 12,62:1 pour le point actif et 5,01:1 pour les inactifs,
 * là où le voile plafonnait à 6,57 et 3,24 dans le pire cas.
 *
 * POSITIONNEMENT ABSOLU, seul moyen de sortir de la boîte de contenu de
 * la grille : celle-ci s'arrête au bord intérieur du cadre, et les points
 * doivent se poser au-delà. Le décalage bas vaut exactement l'épaisseur
 * de la bordure — écrit avec la même variable, il suit toute révision de
 * celle-ci sans qu'on y revienne.
 *
 * La rangée occupe toute cette épaisseur et centre son contenu : les
 * points restent au milieu du cadre quelle que soit sa hauteur. */
.carrousel__points {
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(-1 * var(--cadre-bas));
  height: var(--cadre-bas);
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  list-style: none;
  margin: 0;
  padding: 0;
}

/* La CIBLE DE POINTAGE fait 24 px, la pastille visible 8. Un point de 8 px
   est un repère lisible mais une cible impossible : le rembourrage
   transparent porte la zone cliquable au minimum de 24 px exigé par le
   critère WCAG 2.5.8 (niveau AA), sans grossir le dessin.
 *
 * ELLE EN FAISAIT 22 JUSQU'AU 25/09/2026 — un rembourrage de 7 px — et ce
 * commentaire affirmait pourtant franchir le seuil. Mesuré au téléphone à
 * cette date : 22×22, donc sous le plancher. Un pixel de rembourrage de
 * plus suffit, et l'écart de 9 px entre deux points reste assez large
 * pour qu'ils ne se touchent pas.
 *
 * `background-clip: content-box` est ce qui rend le rembourrage
 * transparent : sans lui, le fond peindrait la cible entière et la
 * pastille ferait 24 px de diamètre. */
.carrousel__point {
  display: block;
  width: 8px;
  height: 8px;
  padding: 8px;
  box-sizing: content-box;
  border: 0;
  border-radius: 50%;
  /* BLANC EN TRANSPARENCE, la bande étant redevenue sombre. Les points
     ont suivi chaque teinte du socle : blancs sur le voile, gris pleins
     sur le cadre blanc, blancs de nouveau sur le sapin. Mesuré sur
     #015850, le point actif tient 8,36:1 et l'inactif 3,32:1 à 50 % de
     blanc — le taux le plus bas qui franchisse encore le seuil de 3:1
     des éléments non textuels, donc celui qui laisse le plus d'écart
     avec le point actif : 2,52:1.

     La transparence est DANS LA COULEUR, jamais un `opacity` sur le
     bouton : `opacity` atténuerait aussi le contour de focus, qui doit
     rester pleinement visible sur un point inactif. */
  background: rgb(255 255 255 / 0.5);
  background-clip: content-box;
  cursor: pointer;
  transition: background 160ms ease;
}
.carrousel__point:hover { background: rgb(255 255 255 / 0.78); background-clip: content-box; }

/* Le contour de focus revient au JAUNE, la bande étant de nouveau sombre :
   l'anthracite ne vaudrait que 1,51:1 sur le sapin. */
.carrousel__point:focus-visible {
  outline: 2px solid var(--brand-jaune);
  outline-offset: -2px;
}

/* Le point courant se distingue par le BLANC PLEIN — 8,36:1 sur la bande
   sapin — et non par une autre teinte : passer au jaune le distinguerait
   par la couleur plutôt que par la clarté, ce qui ne se lit pas en vision
   des couleurs déficiente. */
.carrousel__point--actif {
  background: rgb(255 255 255 / 1);
  background-clip: content-box;
}

/* --- Apparition au défilement ---------------------------------------
 *
 * Chaque projet entre en scène quand il arrive dans la fenêtre (demande
 * du client, 22/08).
 *
 * TOUT EST SOUS `.avec-apparition`, la classe que scripts/apparition.js
 * pose sur <html>. C'est la seule protection qui vaille : sans elle, un
 * visiteur sans JavaScript — ou dont le script n'a pas chargé — verrait
 * une page vide, les blocs restant à `opacity: 0` faute de quoi que ce
 * soit pour les révéler. Ici, pas de script, pas de classe, pas de
 * masquage.
 *
 * Le script s'abstient également de poser la classe quand le système
 * demande à réduire les animations : ce cas n'a donc PAS besoin d'être
 * traité une seconde fois ici, et le traiter en CSS aurait laissé le
 * masquage s'appliquer un instant avant que la règle ne le lève.
 *
 * RALENTIE ET AMPLIFIÉE le 22/08 : le client ne percevait pas l'effet.
 * 620 ms → 1200 ms, et 24 px de translation → 40 px.
 *
 * LA DURÉE N'ÉTAIT PAS SEULE EN CAUSE, et c'est pourquoi les deux valeurs
 * changent ensemble. Trois raisons se cumulaient :
 *
 *   - 24 px de déplacement sur un bloc de 600 px de haut, c'est 4 % de sa
 *     hauteur — un glissement qu'on ne voit pas s'il ne dure pas ;
 *   - l'ancienne courbe, cubic-bezier(0.22, 0.61, 0.36, 1), plaçait
 *     l'essentiel du mouvement dans le premier tiers du temps : elle
 *     paraissait deux fois plus rapide que sa durée nominale ;
 *   - le bloc n'est révélé qu'une fois entré de 12 % dans la fenêtre,
 *     donc l'animation démarrait déjà tard.
 *
 * La nouvelle courbe part LENTEMENT — 0.33, 0 — au lieu de bondir. Le
 * bloc reste un instant à sa place et à son opacité de départ, ce qui
 * donne à l'œil le temps de saisir qu'il se passe quelque chose.
 *
 * `will-change` n'est PAS déclaré : la page compte quatre blocs, chacun
 * animé une seule fois. Réserver une couche de composition pour chacun
 * coûterait plus de mémoire que l'animation n'économise de travail. */
.avec-apparition .apparition {
  opacity: 0;
  transform: translateY(40px);
  transition:
    opacity 1200ms cubic-bezier(0.33, 0, 0.2, 1),
    transform 1200ms cubic-bezier(0.33, 0, 0.2, 1);
}
.avec-apparition .apparition--vue {
  opacity: 1;
  transform: none;
}

/* --- Actualités -----------------------------------------------------
 *
 * Page créée le 22/08, SANS CONTENU : content.fr.json porte la mention
 * « STRUCTURE ACTIVE — CONTENU PLACEHOLDER » sur cette rubrique. Les
 * styles ci-dessous dessinent la liste telle qu'elle sera, et le bloc
 * d'attente qui la précède en attendant.
 *
 * L'AVIS D'ATTENTE S'ADRESSE AU VISITEUR, pas au développeur. Le filet
 * jaune à gauche est celui qui marque partout ailleurs sur le site ce qui
 * est mis en avant ; le fond blanc le détache du papier de la section. */
.avis-attente {
  font-family: 'Roboto', system-ui, sans-serif;
  font-stretch: 75%;
  font-size: var(--type-body-lg);
  line-height: var(--leading-body);
  color: var(--neutral-encre);
  max-width: var(--measure-body);
  margin: 0 0 clamp(32px, 4vw, 56px);
  padding: clamp(18px, 2vw, 24px) clamp(20px, 2.4vw, 28px);
  background: var(--neutral-blanc);
  border-left: 3px solid var(--brand-jaune);
}

/* DISPOSITION REPRISE DU MODÈLE FOURNI PAR LE CLIENT (22/08) : une
 * actualité à la une, photo à gauche et texte à droite, puis une rangée de
 * trois cartes, photo au-dessus et texte en dessous.
 *
 * L'ORGANISATION SEULE EST REPRISE, à la demande expresse du client : ni
 * les polices ni les couleurs du modèle. D'où trois écarts assumés avec
 * lui, et ce sont les seuls qui se voient :
 *
 *   - le surtitre du modèle est rose vif ; ici c'est une date en IBM Plex
 *     Mono capitales pétrole, le registre des surtitres de tout le site ;
 *   - ses titres sont en linéale grasse ; ici Archivo demi-gras, comme
 *     tous les titres du site ;
 *   - son texte courant est en linéale normale ; ici Roboto à chasse
 *     75 %, comme partout ailleurs.
 *
 * Le fond blanc des cartes sur fond papier, lui, est commun aux deux : le
 * site l'employait déjà pour ses panneaux. */
/* Conteneur élargi de 4 cm de chaque côté (demande du client, 22/08).
 *
 * LA VALEUR EST ÉCRITE EN CENTIMÈTRES parce qu'elle a été demandée ainsi.
 * CSS les convertit lui-même, à raison de 96 pixels au pouce : 4 cm valent
 * 151,2 px. L'écrire `8cm` — deux fois quatre — plutôt que `302.4px` garde
 * la demande lisible dans la feuille.
 *
 * LES 4 cm SONT RENDUS EXACTEMENT tant que la fenêtre est plus large que
 * le conteneur, et mesurés comme tels : 448 → 297 px de marge sur un écran
 * de 1920, 208 → 57 px sur 1440. Soit 151 px dans les deux cas, la valeur
 * exacte de 4 cm.
 *
 * EN DESSOUS DE ~1382 px, IL N'Y A PLUS RIEN À RETIRER. Le conteneur
 * n'atteint alors plus son plafond et sa marge se réduit à la gouttière
 * fluide — 28 px sur une tablette de 820, 20 px sur un mobile. La rubrique
 * y a exactement les mêmes marges que le reste du site, et c'est la seule
 * issue possible : le reste serait pris sur le texte.
 *
 * Le rembourrage reste celui du conteneur commun : il ne s'agit pas de
 * coller les cartes au bord de la fenêtre, mais de réduire la gouttière
 * du gabarit. */
.conteneur-large {
  width: 100%;
  max-width: calc(var(--width-content) + 8cm);
  margin-inline: auto;
  padding-inline: var(--gutter-fluide);
}

.actus {
  display: grid;
  gap: clamp(16px, 1.8vw, 24px);
}

/* --- L'actualité à la une ------------------------------------------- */

/* Photo et texte se partagent la carte, la photo un peu plus large : le
 * modèle lui donne à peu près la moitié, et le texte d'une actualité en
 * demande moins que sa photo pour être lu.
 *
 * `align-items: stretch` n'est pas décoratif ici : c'est lui qui fait
 * descendre la photo jusqu'au bas de la carte, comme dans le modèle où
 * elle en occupe toute la hauteur. */
.actu-une {
  position: relative;
  display: grid;
  gap: 0;
  align-items: stretch;
  background: var(--neutral-blanc);
  border: var(--border-hairline);
}
/* PALIER À 48rem ET NON 52. Mesuré sur une tablette de 820 px — au-dessus
   de 52rem par la largeur mais en dessous une fois le rembourrage du
   conteneur et la barre de défilement retranchés — la une s'empilait alors
   qu'il y avait place pour les deux colonnes. À 48rem elles font environ
   350 px chacune, assez pour le titre comme pour la photo. */
@media (min-width: 48rem) {
  .actu-une { grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr); }
}

/* --- Le cadre du média, à deux étages ------------------------------
 *
 * `.actu__media` rogne, `.actu__media__contenu` s'agrandit. Cette
 * séparation existe pour le zoom au survol (23/08) : agrandir directement
 * le cadre agrandirait la carte, et c'est la photo seule qui doit bouger.
 *
 * `overflow: hidden` est ce qui fait tout le travail — sans lui la photo
 * agrandie déborderait par-dessus le texte au lieu d'être rognée.
 *
 * Le contenu est en `absolute` et non en `width/height: 100%` : à 100 %,
 * une transformation d'échelle part du centre et découvre les bords sur
 * un pixel ou deux selon l'arrondi. Ancré aux quatre côtés, il couvre le
 * cadre quoi qu'il arrive. */
.actu__media {
  position: relative;
  overflow: hidden;
}
.actu__media__contenu {
  position: absolute;
  inset: 0;
  margin-block-end: 0;
  border: 0;
  border-radius: 0;
  transition: transform 480ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* L'emplacement de photo perd le rapport 4/3 et la marge basse que lui
   donne son composant d'origine : ici il remplit sa colonne, hauteur
   comprise. Le plancher le protège du cas où le texte serait très court. */
.actu-une__visuel {
  aspect-ratio: 16 / 9;
}
/* LE PLAFOND DE 380 px EST RESTÉ CELUI D'AVANT L'ÉLARGISSEMENT, et c'est
   volontaire : je l'avais monté à 460 en croyant que la colonne passerait
   à 790 px, puis la mesure a montré qu'elle reste à 654 — le conteneur
   élargi a lui-même un plafond, la fenêtre n'y change plus rien au-delà.
   À 654 px de large, 380 de haut font 1,72:1, presque le 16/9 des cartes
   voisines ; 460 les auraient mises à 1,42:1, plus carrées qu'elles. */
@media (min-width: 48rem) {
  .actu-une__visuel {
    aspect-ratio: auto;
    min-height: clamp(260px, 26vw, 380px);
  }
}

.actu-une__texte {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(24px, 3vw, 44px);
}

/* Le titre de la une est le plus gros de la page après celui du hero, et
   c'est voulu : dans le modèle, c'est lui qui porte la hiérarchie. */
.actu-une__titre {
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 2.6vw, 2.1rem);
  font-weight: var(--weight-semibold);
  line-height: 1.15;
  letter-spacing: var(--tracking-heading);
  color: var(--brand-petrole);
  margin: 0 0 var(--space-4);
  /* Portée de 20ch à 24ch avec l'élargissement du 22/08 : dans une colonne
     de texte devenue large de 700 px, un titre replié à 20 caractères
     laissait un vide franc à sa droite. */
  max-width: 24ch;
}

/* Le titre de la une porte le lien vers l'article. Il garde sa couleur —
   un lien coloré à l'écart du reste ferait deux titres de nature
   différente sur la même page — et se signale par un soulignement qui
   n'apparaît qu'au survol et au focus.
 *
 * PAS DE SOULIGNEMENT AU REPOS, contrairement à l'usage : le titre est le
 * seul lien de la carte, dans un bloc dont tout indique déjà qu'il est un
 * article. Au clavier le contour de focus prend le relais. */
.actu-une__titre a {
  color: inherit;
  text-decoration: none;
}
.actu-une__titre a:hover,
.actu-une__titre a:focus-visible {
  text-decoration: underline;
  text-underline-offset: 5px;
  text-decoration-thickness: 2px;
  text-decoration-color: var(--brand-jaune);
}

/* TOUTE LA CARTE EST CLIQUABLE (demande du client, 23/08).
 *
 * Le lien du titre s'étire par-dessus la carte entière : `inset: 0` sur un
 * pseudo-élément, la carte étant en `position: relative`. Rien n'est
 * ajouté au balisage, et le nom accessible du lien reste le seul titre —
 * un <a> enveloppant toute la carte ferait lire catégorie, date et résumé
 * d'une traite à chaque tabulation.
 *
 * CE MOTIF EMPÊCHE DE SÉLECTIONNER LE TEXTE de la carte à la souris, et
 * c'est inhérent : la surface cliquable est au-dessus. Aucun montage ne
 * permet à la fois de cliquer partout et de sélectionner partout.
 *
 * Le pseudo-élément est SOUS le contour de focus mais au-dessus du reste :
 * z-index 1, alors que la carte n'en pose aucun. */
.actu-une__titre a::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
}

/* Le contour de focus doit entourer la CARTE, pas le seul titre : c'est
   la carte que l'on active. Il est posé sur elle quand son lien a le
   focus clavier. */
.actu-une:has(a:focus-visible) {
  outline: 3px solid var(--brand-petrole);
  outline-offset: 3px;
}

/* --- Survol : relief et zoom ----------------------------------------
 *
 * `:has(a)` réserve l'effet aux cartes RÉELLEMENT LIÉES. Les trois cartes
 * secondaires n'ont pas encore de page : leur donner une ombre et un zoom
 * au survol promettrait un clic qui ne mène nulle part. Le jour où elles
 * reçoivent un lien, elles prennent le comportement sans qu'on y touche.
 *
 * `@media (hover: hover)` écarte les appareils tactiles, où le survol
 * n'existe pas et où l'état resterait collé après une pression. */
@media (hover: hover) {
  .actu-une:has(a) {
    transition: box-shadow 260ms ease, border-color 260ms ease;
  }
  .actu-une:has(a):hover {
    border-color: transparent;
    box-shadow: 0 10px 30px rgb(14 26 29 / 0.16), 0 2px 8px rgb(14 26 29 / 0.08);
  }
  /* Le zoom est léger — 4 % — et lent : sur une photo de chantier, un
     agrandissement plus franc donne un effet de secousse au passage de la
     souris. */
  .actu-une:has(a):hover .actu__media__contenu {
    transform: scale(1.04);
  }
}

/* Quelqu'un qui demande à réduire les animations garde le relief, qui ne
   bouge pas, mais pas le zoom. */
@media (prefers-reduced-motion: reduce) {
  .actu__media__contenu { transition: none; }
  .actu-une:has(a):hover .actu__media__contenu { transform: none; }
}

.actu-une__resume {
  font-family: 'Roboto', system-ui, sans-serif;
  font-stretch: 75%;
  font-size: var(--type-body-lg);
  line-height: var(--leading-body);
  color: var(--neutral-encre);
  max-width: var(--measure-body);
  margin: 0;
}

/* --- La rangée des suivantes ---------------------------------------- */

/* Trois colonnes fixes au-dessus de 48rem, comme le modèle. En dessous,
   `auto-fill` laisse la rangée tomber à deux puis à une colonne sans
   qu'aucun palier soit à écrire.
 *
 * LE PLANCHER EST À 210 px ET NON 240. Sur une tablette de 820 px, la
 * largeur réellement disponible est de 739 px une fois le rembourrage du
 * conteneur et la barre de défilement retranchés : à 240 px, trois
 * colonnes en demandaient 758 et la rangée retombait à deux, ce que le
 * modèle ne fait pas. */
/* --- Bannière de consentement à la mesure d'audience ------------------
 *
 * LE COMPOSANT EST DANS styles/consentement.css depuis le 25/09/2026. Il a
 * été extrait pour être partagé avec la PAGE D'ACCUEIL, qui inclut la
 * bannière depuis le 22/09 mais ne charge pas cette feuille : elle s'y
 * affichait sans aucun style. Le fichier extrait porte le détail, et les
 * deux gabarits le chargent — seulement si GA_ID est renseigné.
 *
 * RIEN NE RESTE ICI, volontairement : une règle résiduelle pour la
 * bannière rendrait à nouveau son apparence différente selon la page. */

/* Zone du bouton « Charger plus d'actualités » (client, 22/09/2026).
 *
 * Elle est créée par scripts/actus-plus.js et n'existe donc pas sans
 * JavaScript, où la grille s'affiche entière. Le compte des actualités
 * restantes est sous le bouton, dans une région annoncée aux lecteurs
 * d'écran — d'où un bloc et non une ligne. */
.actus-plus {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  margin-block-start: clamp(28px, 3vw, 44px);
}
/* `min-height` POUR UN SEUL PIXEL : le bouton faisait 43 px de haut,
   mesuré au téléphone le 25/09/2026 — le rembourrage de la classe
   .bouton plus sa ligne de texte. C'est le seul bouton du site à manquer
   les 44 px du critère WCAG 2.5.5, et d'aussi peu, alors qu'il est la
   commande principale de la rubrique. */
.actus-plus__bouton {
  cursor: pointer;
  min-height: 44px;
}

/* LE COMPTE N'EST PLUS AFFICHÉ (client, 22/09/2026) : il se lisait sous le
 * bouton, « 6 actualités affichées sur 15 ».
 *
 * IL N'EST PAS SUPPRIMÉ POUR AUTANT, il est masqué visuellement : c'est la
 * région annoncée aux lecteurs d'écran à chaque clic. Sans elle, une
 * personne qui ne voit pas la grille n'aurait aucun retour — le bouton, lui,
 * ne change pas de libellé. Même technique que .actu__separateur : un
 * pixel, hors cadre, sans débordement. Un `display: none` la rendrait
 * muette. */
.actus-plus__etat {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
/* L'article révélé reçoit le focus au script : il ne doit pas porter le
   contour de focus du site, qui signale une cible atteinte au clavier. */
.actus-grille > li:focus { outline: none; }

.actus-grille {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: clamp(16px, 1.8vw, 24px);
}
@media (min-width: 48rem) {
  .actus-grille { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* La carte est une colonne : photo, puis texte qui prend le reste. C'est
   ce qui aligne le bas des cartes entre elles quand un titre déborde sur
   une ligne de plus. */
.actu {
  position: relative;
  display: flex;
  flex-direction: column;
  height: 100%;
  background: var(--neutral-blanc);
  border: var(--border-hairline);
}

/* Les cartes secondaires reçoivent le MÊME comportement que la une —
   surface entièrement cliquable, relief et zoom au survol — mais il ne
   s'active qu'à la présence d'un lien.
 *
 * DEPUIS LE 23/09/2026, CERTAINES EN PORTENT UN : les entrées de
 * content.*.json qui portent un `slug` ont leur page d'article et leur
 * titre est lié. Les cartes gabarits restent inertes, et étiquetées
 * comme telles. Ces règles, écrites d'avance, n'ont pas eu à bouger. */
.actu__titre a {
  color: inherit;
  text-decoration: none;
}
.actu__titre a::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
}
.actu:has(a:focus-visible) {
  outline: 3px solid var(--brand-petrole);
  outline-offset: 3px;
}
/* MÊME SURVOL QUE LA UNE, ET SUR TOUTES LES CARTES (client, 22/09/2026) :
 * relief et zoom de 4 %, mêmes durées, même courbe.
 *
 * `:has(a)` A ÉTÉ LEVÉ pour ces deux effets. Il réservait le survol aux
 * cartes réellement liées, pour ne pas promettre un clic qui ne mène
 * nulle part. C'est un compromis assumé, et il ne concerne plus que les
 * cartes gabarits : les articles réels sont liés depuis le 23/09/2026, et
 * ces cartes-là portent le cartouche « Exemple », qui dit franchement au
 * visiteur qu'il n'y a rien derrière.
 *
 * LE SOULIGNEMENT DU TITRE, LUI, RESTE RÉSERVÉ AUX CARTES LIÉES : c'est un
 * signal de lien, pas une réaction visuelle. Souligner le titre d'une
 * carte inerte serait cette fois une fausse promesse pour de bon. */
@media (hover: hover) {
  .actu {
    transition: box-shadow 260ms ease, border-color 260ms ease;
  }
  .actu:hover {
    border-color: transparent;
    box-shadow: 0 10px 30px rgb(14 26 29 / 0.16), 0 2px 8px rgb(14 26 29 / 0.08);
  }
  .actu:hover .actu__media__contenu {
    transform: scale(1.04);
  }
  .actu:has(a):hover .actu__titre {
    text-decoration: underline;
    text-underline-offset: 5px;
    text-decoration-thickness: 2px;
    text-decoration-color: var(--brand-jaune);
  }
}
@media (prefers-reduced-motion: reduce) {
  .actu:hover .actu__media__contenu { transform: none; }
}
.actu__visuel {
  aspect-ratio: 16 / 9;
}
.actu__texte {
  flex: 1 1 auto;
  padding: clamp(16px, 1.8vw, 22px);
}

/* Le titre d'une carte est un cran sous celui de la une, et deux sous
   celui de la page : c'est la hiérarchie du modèle. */
.actu__titre {
  font-family: var(--font-display);
  font-size: var(--type-h3);
  font-weight: var(--weight-semibold);
  line-height: 1.25;
  letter-spacing: var(--tracking-heading);
  color: var(--brand-petrole);
  margin: 0;
}

/* --- Bandeau catégorie / date ---------------------------------------
 *
 * Repris du modèle du client : rubrique à gauche, date à droite. Le champ
 * `categorie` a été ajouté au contenu le 22/08 pour cela — les entrées ne
 * portaient jusque-là que date, titre et résumé.
 *
 * `justify-content: space-between` PLUTÔT QU'UN ALIGNEMENT À DROITE sur la
 * date : les deux libellés se poussent aux extrémités quelle que soit leur
 * longueur, et la ligne tient sans largeur imposée à l'un ou à l'autre.
 *
 * `gap` couvre le cas où les deux se touchent presque — une catégorie
 * longue dans une carte étroite — et `flex-wrap` les fait passer à la
 * ligne plutôt que de les écraser.
 *
 * LES DEUX SE DISTINGUENT PAR LA CLARTÉ, pas par la teinte : le modèle
 * emploie le même rose vif pour l'un et l'autre, mais il n'a pas
 * d'équivalent dans la charte. Ici la catégorie est en pétrole demi-gras
 * (10,02:1 sur blanc) et la date en ardoise, la couleur de texte
 * secondaire du site (7,55:1). L'écart entre elles n'est que de 1,33:1 —
 * c'est la graisse qui fait le reste du travail. */
.actu__bandeau {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 4px 12px;
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.3;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  margin: 0 0 var(--space-3);
}

.actu__categorie {
  font-weight: var(--weight-semibold);
  color: var(--brand-petrole);
}

.actu__date {
  color: var(--neutral-ardoise);
}

/* Le tiret n'existe QUE POUR LES LECTEURS D'ÉCRAN. À l'œil, l'écart entre
   les deux extrémités du bandeau sépare déjà les deux libellés ; à
   l'oreille, rien ne le ferait, et « Catégorie À venir » s'entendrait
   comme une seule information.
 *
 * Il est retiré du flux sans être retiré de l'accessibilité — un
 * `display: none` le rendrait muet lui aussi. La technique est celle du
 * masquage visuel standard : un pixel, hors cadre, sans débordement. */
.actu__separateur {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Le cartouche « Exemple — actualité à venir » vient de reference.css et
   se pose en haut à droite de l'élément étiqueté.
 *
 * IL ÉTIQUETTE MAINTENANT LES CARTES UNE À UNE, et non plus la rubrique
 * entière (client, 23/09/2026 : deux articles réels y figurent, et le
 * cartouche du bloc les désignait aussi comme des exemples). Sur une carte
 * de la grille, le cartouche tombe sur le coin de la photo : il n'y
 * recouvre aucun texte, et aucun rembourrage n'est à prévoir.
 *
 * LA CARTE À LA UNE, ELLE, EN A BESOIN : sa photo est à gauche et son
 * texte à droite, donc le cartouche se poserait sur le bandeau
 * catégorie / date. La règle est défensive — la une est un article réel
 * depuis le 23/09/2026, donc non étiquetée — mais elle doit tenir si une
 * entrée sans `slug` revenait en tête de rubrique. */
.actu-une.exemple .actu-une__texte {
  padding-top: clamp(40px, 4vw, 52px);
}

/* --- Page d'article --------------------------------------------------
 *
 * Disposition reprise du modèle fourni par le client (23/08) : grande
 * photo créditée en ouverture, puis un panneau de texte plus étroit qui
 * REMONTE SUR SON BAS. C'est ce chevauchement qui fait tout l'effet du
 * modèle — le panneau paraît posé sur la photo plutôt que rangé dessous.
 *
 * DEUX LARGEURS, ET ELLES NE SONT PAS ARBITRAIRES : la photo à 980 px, le
 * panneau à 820. La photo a intérêt à être large, le texte non — à 820 px
 * moins son rembourrage, la ligne fait environ 66 caractères, la mesure
 * de lecture que le site emploie partout ailleurs (--measure-body).
 *
 * Le panneau n'est PAS dans .conteneur : il porte sa propre largeur et se
 * centre lui-même, faute de quoi il hériterait des 1080 px du site et le
 * rapport des deux blocs serait perdu.
 *
 * La page n'a pas de mini hero — voir `sans_hero` dans base.njk — d'où le
 * rembourrage haut : sans lui, la photo toucherait l'en-tête. */
.article-actu {
  /* Le chevauchement du panneau sur la photo, en UNE SEULE variable : le
     panneau la retranche de sa marge haute, le crédit photo s'en écarte
     pour ne pas passer dessous. Écrite deux fois, elles se désaccorderaient
     au premier réglage. */
  --chevauchement: clamp(32px, 4vw, 56px);
  display: block;
  /* AUCUN REMBOURRAGE HAUT (demande du client, 23/08) : la photo doit
     toucher l'en-tête, sans le moindre filet de papier entre les deux.
     Les gouttières latérales restent — elles empêchent la photo et le
     panneau de coller aux bords sur un écran étroit. */
  padding: 0 var(--gutter-fluide) clamp(56px, 7vw, 104px);
  /* FOND BLANC (client, 23/09/2026) : la page d'article portait le papier
     de la charte, comme la rubrique avant qu'elle ne passe au blanc le
     22/09. Les deux se suivent à la lecture — la liste puis l'article —
     et le changement de fond entre les deux se voyait.

     LE PANNEAU DE TEXTE RESTE BLANC LUI AUSSI, donc il ne se détache plus
     de son fond que par son filet et par le chevauchement sur la photo.
     C'est voulu : le contraste du modèle venait de la photo, pas d'une
     nuance de gris. */
  background: var(--neutral-blanc);
}

/* ÉLARGIE DE 4 cm DE CHAQUE CÔTÉ (demande du client, 23/08), comme la
   page Actualités et selon le même procédé : la valeur est écrite en
   centimètres puisqu'elle a été demandée ainsi, CSS faisant lui-même la
   conversion à 96 pixels au pouce. */
.article-actu__visuel {
  position: relative;
  width: 100%;
  max-width: calc(980px + 8cm);
  margin: 0 auto;
}

/* Le cadre hachuré perd la marge basse de son composant d'origine : c'est
   le panneau qui vient s'y poser, il ne doit rien y avoir entre eux. */
.article-actu__cadre {
  aspect-ratio: 16 / 9;
  margin-block-end: 0;
}

/* Crédit posé SUR la photo, en bas à droite, comme dans le modèle.
 *
 * IL REMONTE AU-DESSUS DU CHEVAUCHEMENT. Posé à `bottom: 0`, il tombait
 * dans la bande que le panneau recouvre : sur le premier rendu, seuls les
 * deux derniers mots dépassaient sur la droite. Il s'écarte donc de la
 * hauteur du chevauchement plus 10 px de dégagement.
 *
 * FOND OPAQUE ET NON TRANSLUCIDE : au-dessus d'une photo quelconque, un
 * fond translucide donne un contraste qui dépend de ce qu'il y a dessous,
 * donc invérifiable. Blanc sur encre, ce texte est à 17,73:1 — et il en a
 * besoin, à 10 px c'est le plus petit de la page. */
.article-actu__credit {
  position: absolute;
  right: 0;
  bottom: calc(var(--chevauchement) + 10px);
  margin: 0;
  padding: 6px 10px;
  background: var(--neutral-encre);
  color: var(--neutral-blanc);
  font-family: var(--font-mono);
  font-size: 10px;
  line-height: 1.4;
  letter-spacing: 0.06em;
}

/* LE CHEVAUCHEMENT. La marge négative fait remonter le panneau sur la
   photo ; `position: relative` le place devant elle, sans quoi il
   passerait dessous et le chevauchement ne se verrait pas.
 *
 * Il est modeste — 32 à 56 px selon la largeur — parce qu'il doit mordre
 * sur la photo sans en manger le sujet. */
.article-actu__panneau {
  position: relative;
  z-index: 1;
  width: 100%;
  /* Élargi des mêmes 4 cm que la photo (23/08), pour que le rapport des
     deux blocs — le panneau plus étroit, posé sur elle — soit conservé.
     Sans cet accord, l'un se serait élargi et l'autre non. */
  max-width: calc(820px + 8cm);
  margin: calc(-1 * var(--chevauchement)) auto 0;
  padding: clamp(28px, 3.4vw, 48px);
  background: var(--neutral-blanc);
  /* AUCUN CADRE (client, 23/09/2026) : le panneau portait un filet sur ses
     quatre côtés. Il se justifiait quand le fond de la page était le
     papier de la charte — le filet séparait alors deux nuances. Depuis que
     la page est blanche, il encadrait du blanc sur du blanc.
     Le chevauchement sur la photo suffit à poser le panneau. */
}

/* Le cartouche « Exemple » se pose en haut à droite du panneau ; le
   rembourrage haut est augmenté pour qu'il ne recouvre pas le surtitre. */
.article-actu__panneau.exemple {
  padding-top: clamp(48px, 5vw, 64px);
}

/* Le titre est le plus gros de la page : c'est le <h1>, la page n'ayant
   pas de hero pour le porter. Le modèle le met en capitales ; la charte du
   site ne le fait nulle part, il reste donc en casse normale. */
.article-actu__titre {
  font-family: var(--font-display);
  font-size: clamp(1.7rem, 3.2vw, 2.6rem);
  font-weight: var(--weight-semibold);
  line-height: 1.12;
  letter-spacing: var(--tracking-heading);
  color: var(--brand-petrole);
  margin: 0 0 clamp(24px, 2.8vw, 36px);
  /* LARGEUR DU PANNEAU (client, 23/09/2026) : le titre était bridé à 22ch,
     ce qui le cassait en deux lignes courtes au milieu d'un panneau large
     de 1 029 px utiles. Comme pour le corps de l'article, il occupe
     maintenant toute la largeur disponible et ne se replie que quand la
     ligne ne tient plus — sur téléphone, notamment. */
  max-width: 100%;
}

/* Les points clés : une VRAIE liste à puces, contrairement aux listes à
   filets du reste du site.
 *
 * C'est un écart assumé, et il a une raison : ici la puce distingue d'un
 * coup d'œil ce sommaire du corps de l'article qui le suit immédiatement.
 * Un filet, employé partout ailleurs, ne les séparerait pas assez.
 *
 * La graisse vient du modèle, où ces points sont les seuls passages gras
 * de la page. */
.article-actu__points {
  /* `list-style: disc` EXPLICITE : la remise à zéro du haut de cette
     feuille met toutes les listes du site à `none`, et c'est bien ce
     qu'on veut partout ailleurs. Ici il faut la reprendre — sans cette
     ligne, les trois points s'affichaient décalés mais sans puce, ce qui
     ne les distinguait plus du corps de l'article. Constaté sur le
     rendu, pas déduit. */
  list-style: disc;
  margin: 0 0 clamp(28px, 3.2vw, 40px);
  padding-left: 1.2em;
  border-bottom: var(--border-hairline);
  padding-bottom: clamp(24px, 2.8vw, 36px);
}
.article-actu__points li {
  font-family: 'Roboto', system-ui, sans-serif;
  font-stretch: 75%;
  font-size: var(--type-body);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-body);
  color: var(--brand-petrole);
  margin-bottom: var(--space-3);
}
.article-actu__points li:last-child { margin-bottom: 0; }
/* Puce en pétrole et non en jaune : le jaune vaut 1,70:1 sur blanc, la
   puce y disparaîtrait alors qu'elle est ici le seul signe distinguant
   ce sommaire du corps de l'article. */
.article-actu__points li::marker { color: var(--brand-petrole); }

/* LA MESURE DE LECTURE A DÛ SUIVRE L'ÉLARGISSEMENT, et c'est le seul
   endroit où il coûte quelque chose.
 *
 * Le panneau passe de 820 à 1122 px. À `--measure-body` — 66 caractères,
 * la mesure du reste du site — chaque paragraphe se serait replié à
 * 724 px en laissant 300 px de blanc à sa droite, dans un panneau blanc :
 * le texte aurait paru rangé dans une colonne invisible.
 *
 * Le plafond passe donc à 85 caractères. C'est plus long que le reste du
 * site, mais cela reste dans les usages de la presse en ligne, et le
 * plafond garde son rôle : sans lui la ligne courrait sur 93 caractères,
 * mesurés. À dire si vous préférez tenir le panneau plus étroit — c'est
 * l'autre issue possible, et elle rend la mesure de 66. */
.article-actu__texte p {
  font-family: 'Roboto', system-ui, sans-serif;
  font-stretch: 75%;
  font-size: var(--type-body-lg);
  line-height: var(--leading-body);
  color: var(--neutral-encre);
  /* LE TEXTE OCCUPE TOUTE LA LARGEUR DU PANNEAU (client, 23/09/2026) : il
     s'arrêtait à 85ch, soit 705 px pour 1 027 px de panneau utile — un
     vide de 323 px à droite de chaque ligne, que le retrait du cadre
     rendait plus visible encore.
   *
   * CE QUE ÇA COÛTE, mesuré et non supposé : la ligne passe de 87 à
   * environ 127 caractères, au-delà des 66 que le site s'impose ailleurs
   * (--measure-body). C'est un arbitrage assumé du client sur cette page,
   * comme l'élargissement du mot du dirigeant. La ligne reste bornée par
   * la largeur du panneau, qui ne dépasse pas 1 122 px.
   *
   * L'interlignage de --leading-body reste celui du reste du site : sur
   * des lignes longues, c'est lui qui permet à l'œil de retrouver le
   * début de la ligne suivante. */
  max-width: 100%;
  margin: 0 0 var(--space-5);
}
.article-actu__texte p:last-child { margin-bottom: 0; }

/* L'intertitre est un cran sous le titre de l'article, et n'a pas à
   revenir au registre des surtitres : c'est un titre de partie, pas une
   étiquette. La marge haute est franche, la basse serrée — il appartient
   au paragraphe qui le suit. */
.article-actu__intertitre {
  font-family: var(--font-display);
  font-size: var(--type-h3);
  font-weight: var(--weight-semibold);
  line-height: 1.25;
  letter-spacing: var(--tracking-heading);
  color: var(--brand-petrole);
  margin: clamp(28px, 3.2vw, 40px) 0 var(--space-4);
}

/* Retour à la rubrique. Le modèle n'en montre pas, mais cette page
   n'apparaît dans aucun menu : sans ce lien, seule la flèche du navigateur
   en sort. */
/* --- Sources d'un article -------------------------------------------
 *
 * Ajouté le 23/09/2026 avec les deux premiers articles réels, qui sont
 * des articles d'analyse : ils avancent des prix, des puissances et des
 * dates, et le lecteur doit pouvoir les vérifier.
 *
 * Le bloc reprend la liste à filets du reste du site (.liste-marquee) et
 * n'ajoute qu'un traitement de lien : les URL sortent du site, elles sont
 * longues, et elles doivent se voir comme des liens sans imiter les
 * intertitres au-dessus d'elles.
 *
 * `word-break` n'est PAS employé : les libellés sont des phrases, pas des
 * URL brutes. Ce sont elles qui débordaient sur téléphone, et c'est
 * précisément pourquoi le contenu porte un titre lisible par source. */
.article-actu__sources {
  margin-top: clamp(32px, 3.6vw, 48px);
}
.article-actu__sources .liste-marquee {
  margin-top: var(--space-4);
}
.article-actu__sources a {
  color: var(--brand-petrole);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--brand-jaune);
  text-decoration-thickness: 2px;
}
.article-actu__sources a:hover,
.article-actu__sources a:focus-visible {
  color: var(--brand-sapin);
  text-decoration-color: currentColor;
}

.article-actu__retour {
  margin: clamp(32px, 3.6vw, 48px) 0 0;
  padding-top: clamp(20px, 2.4vw, 28px);
  border-top: var(--border-hairline);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
/* LA CIBLE TACTILE DU LIEN DE RETOUR faisait 14 px de haut, mesurée à
   390 px le 25/09/2026 : c'est la hauteur de sa ligne de texte en mono
   11 px. C'est le seul chemin de sortie de l'article, et il se visait au
   millimètre.
 *
 * `inline-block` PLUS UN REMBOURRAGE VERTICAL : un lien en ligne ignore
 * les rembourrages haut et bas pour le calcul de sa boîte, donc la cible
 * n'aurait pas grandi. La marge du paragraphe est réduite d'autant pour
 * que l'espacement visible reste celui d'avant. */
.article-actu__retour a {
  display: inline-block;
  padding-block: 15px;
  margin-block-start: -15px;
  color: var(--brand-petrole);
  text-decoration: underline;
  text-underline-offset: 4px;
}
.article-actu__retour a:hover { color: var(--brand-sapin); }

/* --- Dernières actus, bas de page d'article -------------------------
 *
 * Repris du modèle « modèle bas de page » fourni par le client (23/08) :
 * filet, titre, carrousel de cartes avec aperçu de la suivante, puis
 * chevrons encadrant des pastilles allongées.
 *
 * Le bloc s'aligne sur la PHOTO de l'article, pas sur son panneau de
 * texte : c'est la largeur qui porte la page. */
.dernieres-actus {
  /* BLANC COMME L'ARTICLE AU-DESSUS (client, 23/09/2026) : ce bloc suit
     l'article sans interruption, et le laisser en papier aurait posé une
     bande grise en bas de page — le changement de fond se serait lu comme
     une autre section, alors que c'est le bas de la même page.

     Les cartes du carrousel sont blanches à filet : elles restent
     détachées du fond par leur bordure, comme sur la page Actualités,
     blanche depuis le 22/09. */
  background: var(--neutral-blanc);
  padding: 0 var(--gutter-fluide) clamp(56px, 7vw, 96px);
}
.dernieres-actus__bloc {
  width: 100%;
  max-width: calc(980px + 8cm);
  margin: 0 auto;
  padding-top: clamp(32px, 4vw, 56px);
  border-top: var(--border-hairline);
}

/* Le titre reste en casse normale, là où le modèle le met en capitales :
   la charte du site ne met aucun titre en capitales. */
.dernieres-actus__titre {
  font-family: var(--font-display);
  font-size: var(--type-h3);
  font-weight: var(--weight-semibold);
  line-height: 1.2;
  letter-spacing: var(--tracking-heading);
  color: var(--brand-petrole);
  margin: 0 0 clamp(20px, 2.4vw, 28px);
}

/* --- La peau « bas de page » du carrousel ---------------------------
 *
 * MÊME COMPOSANT QUE LA PAGE RÉALISATIONS, même balisage et même script.
 * Seule cette classe change ce qui se voit. Les remises à zéro qui suivent
 * ne sont donc pas des rustines : elles défont les partis pris propres à
 * l'autre emploi — bande sapin, une vue par écran, cadre carré, commandes
 * posées sur la photo — qui n'ont pas cours ici.
 *
 * `display: grid` avec une deuxième rangée : la piste occupe toute la
 * première, les trois commandes se rangent au centre de la seconde. C'est
 * ce qui met les pastilles ENTRE les chevrons, comme dans le modèle. */
.carrousel--bas {
  border-bottom: 0;
  margin-bottom: 0;
  grid-template-rows: auto auto;
  grid-template-columns: 1fr auto auto auto 1fr;
  row-gap: clamp(16px, 2vw, 24px);
}
.carrousel--bas .carrousel__piste {
  grid-area: 1 / 1 / 2 / 6;
  /* La piste rogne les ombres des cartes au survol si elle ne se donne pas
     de quoi les laisser dépasser. */
  padding: 4px 4px 14px;
  margin: -4px -4px -14px;
}

/* DEUX CARTES ET DEMIE VISIBLES SUR ORDINATEUR, et non trois.
 *
 * Le modèle en montre un peu plus de trois, mais il illustre un site qui
 * publie tous les jours. Ici la rubrique compte quatre actualités dont
 * une est l'article courant : il en reste trois, et à trois par écran
 * RIEN NE DÉBORDE — le script masque alors de lui-même chevrons et
 * pastilles, et le bas de page n'est plus qu'une rangée de trois cartes.
 *
 * À 36 % de la piste, trois cartes en demandent 112 % : le défilement a
 * lieu, l'aperçu de la troisième se voit, les commandes servent. Les
 * cartes y gagnent en largeur — 464 px au lieu de 385.
 *
 * Le jour où la rubrique comptera davantage d'actualités, ce réglage
 * n'aura pas à changer : il montrera simplement plus de cartes à faire
 * défiler. */
.carrousel--bas .carrousel__rail--cartes {
  grid-auto-columns: 82%;
  gap: clamp(16px, 1.8vw, 24px);
}
@media (min-width: 48rem) {
  .carrousel--bas .carrousel__rail--cartes { grid-auto-columns: 46%; }
}
@media (min-width: 62rem) {
  .carrousel--bas .carrousel__rail--cartes { grid-auto-columns: 36%; }
}

/* La vue perd le cadre carré de l'autre emploi : ici elle contient une
   carte, dont la hauteur est celle de son contenu. `align-items` sur le
   rail les met toutes à la même. */
.carrousel--bas .carrousel__vue--carte {
  aspect-ratio: auto;
  overflow: visible;
  background: none;
}
.carrousel--bas .carrousel__rail--cartes { align-items: stretch; }

/* --- Chevrons : plus de pastille blanche posée sur la photo ---------
 *
 * Ils descendent dans la seconde rangée, deviennent transparents et
 * perdent leur ombre : dans le modèle ce sont deux chevrons nus, de part
 * et d'autre des pastilles. Ils gardent leur cible de 48 px — c'est la
 * surface qu'on vise, pas le dessin qu'on voit. */
.carrousel--bas .carrousel__bouton {
  grid-row: 2;
  align-self: center;
  background: none;
  box-shadow: none;
  width: 40px;
  height: 40px;
  margin: 0;
}
.carrousel--bas .carrousel__bouton--precedent { grid-column: 2; justify-self: end; }
.carrousel--bas .carrousel__bouton--suivant { grid-column: 4; justify-self: start; }
.carrousel--bas .carrousel__bouton:hover { background: none; }
.carrousel--bas .carrousel__bouton:hover .carrousel__chevron {
  border-color: var(--brand-sapin);
}
.carrousel--bas .carrousel__bouton[disabled]:hover { background: none; }

/* LES CHEVRONS RESTENT SUR MOBILE, contrairement à ceux de la page
   Réalisations que la règle générale retire sous 48rem. La raison de ce
   retrait ne vaut pas ici : là-bas ils sont posés SUR la photo et en
   couvriraient une part notable ; ici ils sont sous le carrousel et ne
   recouvrent rien. C'est justement sur un écran étroit que le carrousel
   déborde le plus, donc qu'ils servent le plus.
 *
 * Ils ne s'affichent PAS non plus au seul survol : la règle qui les
 * escamote jusqu'au survol vise le carrousel de Réalisations, où ils
 * masquent la photo au repos. Sous le carrousel, ils n'ont rien à cacher
 * et doivent se voir tout de suite. */
@media (max-width: 47.99rem) {
  .carrousel--bas .carrousel__bouton { display: grid; }
}
@media (hover: hover) {
  .carrousel--bas .carrousel__bouton {
    opacity: 1;
    pointer-events: auto;
  }
  .carrousel--bas .carrousel__bouton[disabled] { opacity: 0.34; }
}

/* --- Pastilles allongées, et non rondes ----------------------------
 *
 * C'est la différence visible avec le carrousel de Réalisations, et elle
 * vient du modèle : des barres arrondies plutôt que des points.
 *
 * ELLES SONT SUR LE PAPIER, plus sur une bande sombre : les couleurs
 * changent donc aussi. Pétrole plein pour la position courante — 9,14:1
 * sur le papier — et gris #82898D pour les autres, 3,24:1.
 *
 * PAS #8D9599, LE GRIS DES POINTS DE LA PAGE ACTUALITÉS : mesuré sur le
 * papier il ne donne que 2,78:1, sous le seuil de 3:1 des éléments non
 * textuels. Il passait sur le blanc des cartes (3,05:1), pas sur ce
 * fond-ci. Deux crans plus sombre suffisent à le rattraper sans que la
 * pastille inactive se confonde avec l'active. */
.carrousel--bas .carrousel__points {
  position: static;
  grid-row: 2;
  grid-column: 3;
  height: auto;
  align-self: center;
  gap: 7px;
  padding: 0;
}
.carrousel--bas .carrousel__point {
  width: 22px;
  height: 6px;
  padding: 9px 4px;
  border-radius: 99px;
  background: #82898D;
  background-clip: content-box;
}
.carrousel--bas .carrousel__point:hover {
  background: var(--neutral-ardoise);
  background-clip: content-box;
}
.carrousel--bas .carrousel__point--actif {
  background: var(--brand-petrole);
  background-clip: content-box;
}
.carrousel--bas .carrousel__point:focus-visible {
  outline: 2px solid var(--brand-petrole);
  outline-offset: 2px;
}

/* --- Lots réalisés, en une ligne sous le carrousel ------------------
 *
 * Demande du client (22/08) : « Lots réalisés : Bâtiment - Système de
 * drainage - Clôture périmétrique ». Ce n'est plus une liste mais une
 * phrase, et le balisage suit — voir le gabarit.
 *
 * L'intitulé se détache par la graisse et la couleur, pas par un retour à
 * la ligne : la ligne doit rester une ligne. */
.projet__lots {
  font-family: 'Roboto', system-ui, sans-serif;
  font-stretch: 75%;
  font-size: var(--type-body-lg);
  line-height: 1.5;
  color: var(--neutral-encre);
  margin: 0;
  padding-top: clamp(16px, 1.8vw, 24px);
  border-top: var(--border-hairline);
}
.projet__lots-intitule {
  font-weight: var(--weight-semibold);
  color: var(--brand-petrole);
}

/* --- Page Contact ----------------------------------------------------
 *
 * Refaite le 23/08 sur le modèle fourni par le client : une carte unique
 * qui REMONTE SUR LE HERO, coupée en deux — coordonnées à gauche sur fond
 * teinté, formulaire à droite sur fond blanc.
 *
 * Le modèle est bleu vif en linéale arrondie ; seule sa disposition est
 * reprise. Pétrole, papier, Archivo, Roboto condensé et IBM Plex Mono
 * comme partout ailleurs sur le site.
 *
 * LA REMONTÉE EST UNE MARGE NÉGATIVE, et la section n'a pas de fond à
 * elle : le papier de la page se voit de part et d'autre de la carte,
 * exactement comme dans le modèle où la carte flotte sur le fond clair. */
.zone-contact {
  padding-bottom: clamp(56px, 7vw, 104px);
}
.zone-contact .conteneur {
  /* Le chevauchement est borné par le TITRE DU HERO, qui s'arrête à une
     centaine de pixels de son bas : au-delà, la carte viendrait le
     couvrir.
   *
   * 28 px sur mobile et non 40 : mesuré, 40 ne laissait que 8 px entre le
   * bas du titre et le haut de la carte, sur un écran où le hero est déjà
   * court. À 28 px il en reste 20, et le chevauchement se voit toujours.
   * Sur ordinateur les 72 px laissent 28 px de dégagement.
   *
   * LA CARTE EST DESCENDUE DE 0,5 cm le 22/09/2026 (client), soit 19 px :
   * le chevauchement passe de 72 à 53 px sur ordinateur, de 28 à 9 px sur
   * téléphone. Les 0,5 cm s'AJOUTENT à la marge négative plutôt que de
   * remplacer ses bornes — la progression mesurée du chevauchement selon
   * la largeur reste celle réglée le 23/08, simplement décalée. */
  margin-top: calc(clamp(-72px, -6vw, -28px) + 0.5cm);
}

/* La carte porte l'ombre qui la détache du hero, comme dans le modèle.
   Elle est franche mais basse : une carte de 700 px de haut avec une
   ombre diffuse paraîtrait flotter. */
.carte-contact {
  position: relative;
  z-index: 1;
  display: grid;
  overflow: hidden;
  background: var(--neutral-blanc);
  box-shadow: 0 18px 48px rgb(14 26 29 / 0.16), 0 3px 10px rgb(14 26 29 / 0.06);
}
@media (min-width: 62rem) {
  /* Les coordonnées tiennent en moins de place que six champs : la
     colonne de gauche est la plus étroite des deux. */
  .carte-contact { grid-template-columns: minmax(0, 0.82fr) minmax(0, 1fr); }
}

/* --- Colonne des coordonnées ---------------------------------------- */

/* Fond papier contre le blanc du formulaire : c'est ce qui coupe la carte
   en deux dans le modèle, sans filet ni bordure. */
.carte-contact__coordonnees {
  background: var(--neutral-papier);
  padding: clamp(28px, 3.4vw, 48px);
}
.carte-contact__formulaire {
  padding: clamp(28px, 3.4vw, 48px);
}

.carte-contact__titre {
  font-family: var(--font-display);
  font-size: clamp(1.3rem, 2.2vw, 1.75rem);
  font-weight: var(--weight-semibold);
  line-height: 1.2;
  letter-spacing: var(--tracking-heading);
  color: var(--brand-petrole);
  margin: 0 0 clamp(16px, 1.8vw, 22px);
}

.carte-contact__intro {
  font-family: 'Roboto', system-ui, sans-serif;
  font-stretch: 75%;
  font-size: var(--type-body);
  line-height: var(--leading-body);
  color: var(--neutral-encre);
  margin: 0 0 clamp(24px, 2.8vw, 32px);
}

/* Avis affiché tant que l'envoi n'est pas branché. Filet jaune à gauche,
   comme partout ailleurs sur le site pour ce qui est mis en avant. */
.carte-contact__avis {
  font-family: 'Roboto', system-ui, sans-serif;
  font-stretch: 75%;
  font-size: 0.9rem;
  line-height: var(--leading-body);
  color: var(--neutral-encre);
  margin: 0 0 clamp(20px, 2.4vw, 28px);
  padding: 12px 16px;
  background: var(--neutral-papier);
  border-left: 3px solid var(--brand-jaune);
}

/* <address> est en italique par défaut dans tous les navigateurs. C'est
   la balise juste pour des coordonnées de contact, mais l'italique n'a
   rien à faire sur une adresse postale : il est annulé. */
.contacts {
  font-style: normal;
  display: grid;
  gap: clamp(20px, 2.4vw, 26px);
}

/* Pastille + texte, alignés en haut : les blocs d'adresse font trois
   lignes, la pastille doit rester au niveau de l'intitulé et non se
   centrer sur l'ensemble. */
.contacts__entree {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: clamp(12px, 1.4vw, 16px);
  align-items: start;
}

/* La pastille reprend le pétrole de la marque là où le modèle emploie son
   bleu. Le pictogramme est blanc dessus : 10,02:1.
 *
 * `flex-shrink` n'a pas cours en grille — c'est `auto` sur la colonne qui
 * garde la pastille à sa taille quel que soit le texte à côté. */
.contacts__pastille {
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  border-radius: 50%;
  background: var(--brand-petrole);
  color: var(--neutral-blanc);
}
.contacts__pastille svg {
  width: 20px;
  height: 20px;
}

.contacts__intitule {
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--brand-petrole);
  margin: 0 0 var(--space-3);
}

.contacts__detail {
  font-family: 'Roboto', system-ui, sans-serif;
  font-stretch: 75%;
  font-size: var(--type-body);
  line-height: 1.6;
  color: var(--neutral-encre);
  margin: 0;
}

/* Téléphones et courriel sont actionnables : ils sont soulignés au repos,
   contrairement aux liens de cartes du site — ici rien d'autre ne
   l'indiquerait. */
.contacts__detail a {
  color: var(--neutral-encre);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--neutral-trait);
}
.contacts__detail a:hover {
  color: var(--brand-petrole);
  text-decoration-color: var(--brand-jaune);
}

.contacts__note {
  font-family: 'Roboto', system-ui, sans-serif;
  font-stretch: 75%;
  font-size: 0.85rem;
  line-height: var(--leading-body);
  color: var(--neutral-ardoise);
  margin: clamp(20px, 2.4vw, 28px) 0 0;
  padding-top: clamp(16px, 1.8vw, 20px);
  border-top: var(--border-hairline);
}

/* --- Le formulaire --------------------------------------------------
 *
 * Champs par paires, objet et message sur toute la largeur : c'est la
 * disposition du modèle. Le seuil de 30rem est bas parce que la colonne
 * est déjà étroite ; en dessous, deux champs côte à côte deviendraient
 * illisibles. */
.formulaire__grille {
  display: grid;
  gap: clamp(14px, 1.6vw, 18px);
}
@media (min-width: 30rem) {
  .formulaire__grille { grid-template-columns: 1fr 1fr; }
  .champ--large { grid-column: 1 / -1; }
}

/* `justify-content: flex-end` ALIGNE LES CASES DE SAISIE d'une même
   rangée, quand bien même leurs étiquettes n'ont pas la même hauteur.
 *
 * Le cas se produit dès le premier rendu : « Adresse électronique
 * (obligatoire) » se replie sur deux lignes là où « Téléphone » en tient
 * une, et la case de droite descendait d'une ligne. En poussant le
 * contenu vers le bas de la cellule, le surplus va au-dessus de
 * l'étiquette et les deux cases retombent au même niveau. */
.champ {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 6px;
  margin: 0;
}

/* L'étiquette reste AU-DESSUS du champ et jamais dedans, contrairement au
   modèle qui pose le libellé en filigrane dans la case. Un libellé en
   filigrane disparaît dès qu'on tape, et l'on ne sait plus ce qu'on
   remplissait ; il n'est pas non plus rattaché au champ pour un lecteur
   d'écran. C'est le seul écart de fond avec le modèle. */
.champ label {
  font-family: var(--font-mono);
  font-size: 10.5px;
  /* 10,5 px EST LA TAILLE DE LA MAQUETTE, en capitales espacées de
     0,14 em : lisible sur un écran d'ordinateur, à la limite sur un
     téléphone tenu à bout de bras. Relevé le 25/09/2026 lors de la revue
     mobile. La taille passe donc à 12 px sous 48rem — voir la règle qui
     suit ce bloc. Le registre, lui, ne change pas : ces étiquettes
     restent en mono capitales, c'est la signature du formulaire. */
  line-height: 1.3;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--brand-petrole);
}


/* L'ASTÉRISQUE TRAVAILLE POUR L'ŒIL SEUL — il porte `aria-hidden` dans le
   gabarit. L'attribut `required` du champ annonce déjà l'obligation aux
   lecteurs d'écran ; un astérisque lu par-dessus ferait doublon, quand il
   est lu, car beaucoup l'ignorent.
 *
 * ENCRE, ET NON LE JAUNE DE LA MARQUE. Le jaune était le premier choix —
 * un signe vif dans une étiquette en petites capitales — et il ne tient
 * pas : à 1,70:1 sur blanc il est à peine visible, et c'est ici le SEUL
 * repère visuel de l'obligation pour qui voit la page. L'argument qu'un
 * astérisque serait un ornement dispensé des seuils ne vaut pas quand il
 * porte à lui seul l'information.
 *
 * L'encre donne 17,73:1 et se détache du pétrole de l'étiquette par sa
 * densité plutôt que par sa teinte. */
.champ__requis {
  color: var(--neutral-encre);
  font-weight: var(--weight-semibold);
  margin-left: 2px;
}


/* Légende des champs obligatoires, en tête du formulaire.
 *
 * ELLE EST INDISPENSABLE DEPUIS QUE L'ASTÉRISQUE A REMPLACÉ LA MENTION
 * ÉCRITE (demande du client, 23/08) : un astérisque seul ne veut rien
 * dire tant qu'on n'a pas dit ce qu'il signifie. Elle vient AVANT les
 * champs, et non après : lue en dernier, elle arriverait trop tard. */
.formulaire__legende {
  font-family: var(--font-mono);
  font-size: 10.5px;
  line-height: 1.4;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--neutral-ardoise);
  margin: 0 0 clamp(14px, 1.6vw, 18px);
}

/* TEXTES DU FORMULAIRE AGRANDIS AU TÉLÉPHONE (client, 25/09/2026), après
 * la revue mobile : les étiquettes des champs, la légende des champs
 * obligatoires et l'astérisque passent de 10,5 à 12 px sous 48rem.
 *
 * DEUX RAISONS DE NE LE FAIRE QUE LÀ : sur ordinateur, ces libellés sont
 * lus de près et la maquette validée les veut discrets ; et au téléphone,
 * c'est le formulaire lui-même qu'on remplit à une main, souvent dehors.
 *
 * L'ASTÉRISQUE SUIT LES ÉTIQUETTES, sans quoi il deviendrait un point
 * minuscule à côté d'un libellé plus grand. */
@media (max-width: 48rem) {
  .champ label,
  .formulaire__legende,
  .champ__requis {
    font-size: 12px;
  }
}

/* Le navigateur ne fait pas hériter la police des champs de saisie : sans
   ces déclarations ils repasseraient en police système. */
.champ input,
.champ textarea {
  font-family: 'Roboto', system-ui, sans-serif;
  font-stretch: 75%;
  font-size: var(--type-body);
  line-height: 1.5;
  color: var(--neutral-encre);
  width: 100%;
  padding: 11px 13px;
  background: var(--neutral-papier);
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
}

.champ textarea {
  resize: vertical;
  min-height: 130px;
}

/* Le contour de focus est PÉTROLE ET ÉPAIS, avec un décalage : sur un
   champ sans bordure visible, un contour fin ne se remarquerait pas, et
   l'on ne saurait pas où l'on est. */
.champ input:focus-visible,
.champ textarea:focus-visible {
  outline: 3px solid var(--brand-petrole);
  outline-offset: 2px;
  background: var(--neutral-blanc);
  border-color: var(--brand-petrole);
}

/* Champ leurre anti-robots. Il porte déjà `hidden` dans le balisage, et
   la règle générale [hidden] le retire du rendu. Cette déclaration ne
   sert qu'à ce qu'une recherche sur « leurre » dans la feuille trouve
   quelque chose et mène à cette explication. */
.formulaire__leurre { display: none; }

.formulaire__mention {
  font-family: 'Roboto', system-ui, sans-serif;
  font-stretch: 75%;
  font-size: 0.85rem;
  line-height: var(--leading-body);
  color: var(--neutral-ardoise);
  margin: clamp(18px, 2vw, 24px) 0 clamp(14px, 1.6vw, 18px);
}
.formulaire__mention a {
  color: var(--brand-petrole);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* Bouton PLEINE LARGEUR, comme dans le modèle. */
.bouton-envoi {
  display: block;
  width: 100%;
  font-family: var(--font-display);
  font-size: 0.875rem;
  font-weight: var(--weight-semibold);
  letter-spacing: 0.03em;
  color: var(--neutral-blanc);
  background: var(--brand-petrole);
  border: 0;
  border-radius: var(--radius-sm);
  padding: 16px 30px;
  cursor: pointer;
  transition: background 160ms ease;
}
.bouton-envoi:hover { background: var(--brand-sapin); }
.bouton-envoi:focus-visible {
  outline: 3px solid var(--brand-petrole);
  outline-offset: 3px;
}

/* DÉSACTIVÉ TANT QUE L'ENVOI N'EST PAS BRANCHÉ.
 *
 * Il reste LISIBLE — blanc sur ardoise, 7,55:1 — et non fantomatique : un
 * bouton qu'on distingue à peine se lit comme un défaut d'affichage,
 * alors qu'ici l'état est voulu et expliqué juste au-dessus.
 * `cursor: not-allowed` le confirme au pointeur. */
.bouton-envoi[disabled] {
  background: var(--neutral-ardoise);
  cursor: not-allowed;
}
.bouton-envoi[disabled]:hover { background: var(--neutral-ardoise); }

/* --- Plan de situation (page Contact) --------------------------------
 *
 * Ajouté le 23/08 à la demande du client, en dernière section avant le
 * pied de page.
 *
 * LE CADRE GARDE SA PLACE AVANT COMME APRÈS LE CLIC : c'est le rôle de
 * l'`aspect-ratio`. Sans lui, la page sauterait au moment où le plan
 * s'insère, et l'on perdrait ce qu'on lisait. */
/* PLEINE LARGEUR ET COLLÉE AU PIED (demande du client, 23/08).
 *
 * Plus aucun rembourrage bas : le plan touche le pied de page. Plus de
 * gouttière latérale non plus — le cadre est sorti du conteneur dans le
 * gabarit et prend la largeur de la fenêtre. Le titre, lui, reste dans
 * son conteneur, d'où le rembourrage haut conservé sur lui seul. */
.plan {
  padding: 0;
  background: var(--neutral-papier);
}


.plan__cadre {
  position: relative;
  display: grid;
  place-content: center;
  gap: clamp(14px, 1.6vw, 20px);
  /* HAUTEUR DÉCLARÉE, PLUS D'`aspect-ratio`.
   *
     Le cadre occupe maintenant toute la largeur de la fenêtre : un rapport
     donnerait 617 px de haut à 1440 px de large, et davantage encore sur
     un écran plus grand — une bande qui prendrait plus d'un écran de
     hauteur pour un plan de situation.
   *
     C'est aussi ce qui met fin au piège rencontré en chemin : plafonner un
     `aspect-ratio` par un `max-height` recalcule la LARGEUR à partir de la
     hauteur, et le cadre s'était retrouvé large de 853 px — exactement
     480 × 16/9 — au lieu de remplir sa colonne. Une hauteur déclarée n'a
     pas ce comportement.
   *
     PAS DE BORDURE : à pleine largeur, deux filets verticaux tomberaient
     aux bords de la fenêtre, et celui du bas séparerait le plan du pied
     de page qu'il doit toucher. */
  height: clamp(320px, 34vw, 520px);
  padding: clamp(20px, 2.4vw, 32px);
  text-align: center;
  background: var(--neutral-blanc);
}

/* Une fois le plan chargé, le cadre n'est plus qu'un contenant : le
   rembourrage et le centrage laisseraient une bordure blanche autour de
   l'image, et l'iframe doit le remplir entièrement. */
.plan__cadre--charge {
  display: block;
  padding: 0;
}

/* L'INTÉGRATION EST ANCRÉE AUX QUATRE CÔTÉS, et non dimensionnée en
   pourcentage. Mesuré : `height: 100%` laissait un bandeau blanc en bas
   du cadre — la hauteur du parent vient d'un `aspect-ratio` plafonné par
   `max-height`, et le pourcentage ne se résout pas contre la valeur
   plafonnée. Ancrée, elle remplit le cadre quelle que soit la façon dont
   celui-ci a obtenu sa hauteur. */
.plan__integration {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

/* L'avis dit ce que le clic déclenche. Il est en ardoise — 7,55:1 — et
   non en encre : c'est une mise en garde, pas le propos de la section. */
.plan__avis {
  font-family: 'Roboto', system-ui, sans-serif;
  font-stretch: 75%;
  font-size: 0.9rem;
  line-height: var(--leading-body);
  color: var(--neutral-ardoise);
  max-width: 48ch;
  margin: 0 auto;
}

/* Le bouton est créé par scripts/plan.js : sans JavaScript, il n'existe
   pas et seul le lien ci-dessous reste. */
.plan__bouton {
  justify-self: center;
  font-family: var(--font-display);
  font-size: 0.875rem;
  font-weight: var(--weight-semibold);
  letter-spacing: 0.03em;
  color: var(--neutral-blanc);
  background: var(--brand-petrole);
  border: 0;
  border-radius: var(--radius-sm);
  padding: 14px 28px;
  cursor: pointer;
  transition: background 160ms ease;
}
.plan__bouton:hover { background: var(--brand-sapin); }
.plan__bouton:focus-visible {
  outline: 3px solid var(--brand-petrole);
  outline-offset: 3px;
}

/* Le lien vers Google Maps est le repli sans JavaScript, et reste
   disponible même avec : quelqu'un qui ne veut rien charger ici peut
   toujours ouvrir le plan chez Google, dans un onglet. */
.plan__lien {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--brand-petrole);
  text-decoration: underline;
  text-underline-offset: 4px;
}
.plan__lien:hover { color: var(--brand-sapin); }

/* « (nouvel onglet) » est écrit, pas seulement figuré par un
   pictogramme : un lien qui change de contexte doit le dire, et un
   pictogramme seul n'est pas annoncé. */
.plan__lien-note {
  text-transform: none;
  letter-spacing: 0.04em;
  color: var(--neutral-ardoise);
}
