/* Polices auto-hébergées. Aucun appel à un CDN : la CNIL considère l'appel à
   fonts.googleapis.com comme un transfert de données non consenti. */
@font-face {
  font-family: 'Julius Sans One';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/julius-sans-one-latin.woff2?v=bbb7f985') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Julius Sans One';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/julius-sans-one-latin-ext.woff2?v=42023a1e') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Baskervville';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/baskervville-normal-latin-ext.woff2?v=8bae0b4d') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Baskervville';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/baskervville-normal-latin.woff2?v=9b89dee8') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Baskervville';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/baskervville-italic-latin.woff2?v=ca2bae38') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@charset "utf-8";
/* ADLD — Atelier de la Déco. Feuille unique.

   Parti pris visuel, refondu le 27/08/2026 d'après la PRÉSENTATION ENVOYÉE PAR
   LE CLIENT le 26/08 (« Présentation Atelier — Atelier de la Déco », 13 pages).
   Le document est intégralement en nuit acier avec un seul accent, l'or. Ses
   valeurs sont reprises telles quelles, relevées dans le PDF :

       #121820  le fond            #18202A  les surfaces
       #D4A359  l'accent           #94A3B8  le texte secondaire

   Ce que ça remplace : le registre lin/ivoire/laiton du 25/08. Le raisonnement
   du 25 tient toujours — UN SEUL accent, aucun rayon, aucune ombre, des filets
   d'un pixel — mais il se joue désormais sur fond sombre. Un métallier d'art
   qui se présente lui-même en acier et en laiton n'a pas à être servi en beige.

   L'or remplace le noir sur les appels à l'action : sur un fond nuit, un bouton
   noir n'existe plus. L'intention de départ (« plus luxueux ») est tenue par le
   métal, pas par le noir.

   Les polices ne changent pas : Copperplate en titres, Baskervville en corps.
   Copperplate n'a qu'une graisse, la hiérarchie se fait donc par la taille,
   l'interlettrage et la couleur, jamais par le gras. Sur fond sombre un serif
   fin maigrit : le corps monte à #CBD5E1 et l'interligne reste à 1,75.

   Aucune couleur en dur hors de :root. Aucun style en ligne nulle part : la CSP
   du site interdit style="". */

/* ------------------------------------------------------------------ jetons */
:root {
  /* couleurs — trois profondeurs de nuit, deux valeurs de texte, un accent */
  --nuit:         #121820;   /* fond de page, relevé dans la présentation client */
  --nuit-creux:   #0D1218;   /* bande alternée : une respiration, pas une rupture */
  --acier:        #18202A;   /* surfaces posées sur la nuit : encarts, champs, cartes */
  --acier-clair:  #222C39;   /* survol d'une surface */
  --blanc:        #FFFFFF;   /* titres (18,4:1 sur la nuit) */
  --texte:        #CBD5E1;   /* corps de texte (10,7:1) */
  --gris:         #94A3B8;   /* texte secondaire, légendes (6,6:1) */
  --or:           #D4A359;   /* l'accent, hex du document client (8,1:1 en texte) */
  --or-clair:     #E6C088;   /* survol, et accent sur les aplats les plus sombres */
  --or-sourd:     #8A6A3C;   /* filets et amorces : présent, jamais bavard */
  --bordure:      #26303D;   /* le cheveu qui court sous un titre ou une carte */
  --bordure-champ:#63748A;   /* contour d'un élément d'interface : 3,3:1, exigé par la WCAG 1.4.11 */
  --alerte:       #F87171;   /* erreur de formulaire (6,2:1) */
  --focus:        var(--or);

  /* espacement, multiples de 4, et rien en dehors */
  --e1: 4px;  --e2: 8px;  --e3: 12px; --e4: 16px; --e6: 24px;
  --e8: 32px; --e12: 48px; --e16: 64px; --e24: 96px; --e32: 128px;

  /* gabarit */
  --contenu: 1200px;
  --prose: 34rem;
  --marge: var(--e6);

  /* typographie */
  --titre: 'Copperplate', 'Copperplate Gothic Light', 'Optima', serif;
  --texte-police: 'Baskervville', 'Times New Roman', Times, serif;
  --t-h1: clamp(2rem, 1.05rem + 4.6vw, 4.25rem);
  --t-h2: clamp(1.625rem, 1.16rem + 2.1vw, 2.75rem);
  --t-h3: clamp(1.1875rem, 1.04rem + 0.6vw, 1.625rem);
  --t-chapeau: clamp(1.1875rem, 1.07rem + 0.55vw, 1.4375rem);
  --t-surtitre: clamp(0.75rem, 0.72rem + 0.13vw, 0.8125rem);
  --t-corps: clamp(1.0625rem, 1.03rem + 0.16vw, 1.125rem);
  --t-legende: 0.9375rem;

  /* échelle d'empilement : 10, 20, 30, 50, et rien d'autre */
  --z-flux: 10;
  --z-entete: 20;
  --z-deroulant: 30;
  --z-panneau: 50;

  --duree: 200ms;

  /* >>> refonte visuelle du 27/08/2026 — le mouvement
     Trois durées, trois usages, et rien d'autre. La courbe est la même
     partout : une sortie franche puis un freinage long, ce qui donne au
     mouvement l'inertie d'une pièce d'acier plutôt que le rebond d'un jouet. */
  --duree-lente:  680ms;   /* une révélation au défilement */
  --duree-trace: 1100ms;   /* un trait de trame qui se dessine */
  --courbe: cubic-bezier(.16, .84, .28, 1);

  /* la trame de verrière : son trait, et le pas de sa grille */
  --trame-trait: rgba(212, 163, 89, .30);
  --trame-pas: 14%;
}

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; background: var(--nuit); }

body {
  margin: 0;
  background: var(--nuit);
  color: var(--texte);
  font-family: var(--texte-police);
  font-size: var(--t-corps);
  line-height: 1.75;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

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

a { color: var(--or); text-underline-offset: 0.2em; text-decoration-thickness: 1px; }
a:hover { color: var(--or-clair); }

h1, h2, h3, h4 {
  font-family: var(--titre);
  font-weight: 400;               /* Copperplate n'a qu'une graisse : jamais de gras */
  text-transform: uppercase;
  margin: 0;
  color: var(--blanc);
}
/* Plus le titre est gros, plus il se serre : c'est ce qui fait la tenue. */
h1 { font-size: var(--t-h1); letter-spacing: 0.035em; line-height: 1.12; }
h2 { font-size: var(--t-h2); letter-spacing: 0.05em; line-height: 1.16; }
h3 { font-size: var(--t-h3); letter-spacing: 0.09em; line-height: 1.25; }
h4 { font-size: 1.0625rem; letter-spacing: 0.1em; line-height: 1.3; }

p, ul, ol { margin: 0 0 var(--e4); }
ul, ol { padding-left: 1.15em; }
li { margin-bottom: var(--e2); }

:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
  border-radius: 0;
}

::selection { background: var(--or); color: var(--nuit); }

/* --------------------------------------------------------------- utilitaires */
.contenu {
  width: 100%;
  max-width: var(--contenu);
  margin-inline: auto;
  padding-inline: var(--marge);
}
.prose { max-width: var(--prose); }
.prose-large { max-width: 46rem; }

/* Le chapeau : un cran au-dessus du corps, jamais au niveau du titre. */
.prose-large > p:first-child,
.chapeau {
  font-size: var(--t-chapeau);
  line-height: 1.55;
  color: var(--gris);
}

.surtitre {
  font-family: var(--titre);
  font-size: var(--t-surtitre);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--or);
  margin: 0 0 var(--e4);
  display: block;
}

.legende { font-size: var(--t-legende); color: var(--gris); line-height: 1.6; }

.evitement {
  position: absolute;
  left: var(--e4);
  top: -100px;
  z-index: var(--z-panneau);
  background: var(--or);
  color: var(--nuit);
  padding: var(--e3) var(--e4);
  font-family: var(--titre);
  font-size: var(--t-surtitre);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-decoration: none;
}
.evitement:focus { top: var(--e4); color: var(--nuit); }

.hors-ecran {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%);
  white-space: nowrap; border: 0;
}

/* ---------------------------------------------------------------- sections */
section { scroll-margin-top: 96px; }

.bande { padding-block: var(--e24); }
@media (min-width: 768px) { .bande { padding-block: var(--e32); } }

.bande--serree { padding-block: var(--e16); }
@media (min-width: 768px) { .bande--serree { padding-block: var(--e24); } }

/* Les trois fonds. Les noms viennent du gabarit et n'ont pas bougé : ce sont
   les valeurs qui ont basculé, pour que build.py n'ait pas à être réécrit. */
.bande--lin   { background: var(--nuit); }
.bande--blanc { background: var(--nuit-creux); }
.bande--encre { background: var(--acier); border-top: 1px solid var(--or-sourd); }

.bande--encre h2, .bande--encre h3 { color: var(--blanc); }
/* :not(.bouton) est indispensable : sans lui, « .bande--encre a » l'emporte en
   spécificité sur « .bouton--blanc » et repeint le texte d'un bouton clair.
   Le défaut ne se voit qu'à la capture. */
.bande--encre a:not(.bouton) { color: var(--or); }
.bande--encre a:not(.bouton):hover { color: var(--or-clair); }
.bande--encre .chapeau, .bande--encre .prose-large > p:first-child { color: var(--texte); }

/* un titre appartient au bloc qui le suit : plus d'air dessus que dessous */
.bande > .contenu > h2 { margin-bottom: var(--e6); }

/* Le filet : une amorce d'or, puis un cheveu qui court sur la largeur. */
.filet {
  width: 100%; height: 1px; border: 0;
  margin: 0 0 var(--e8);
  background: linear-gradient(90deg, var(--or) 0 56px, var(--bordure) 56px);
}

/* ------------------------------------------------------------------ en-tête */
.entete {
  position: sticky; top: 0;
  z-index: var(--z-entete);
  background: var(--nuit);
  border-bottom: 1px solid var(--bordure);
}
.entete__interieur {
  display: flex; align-items: center; gap: var(--e6);
  min-height: 84px;
}
.entete__logo { flex: none; margin-right: auto; display: block; padding-block: var(--e2); }
.entete__logo img { width: 160px; height: 67px; object-fit: contain; }

.nav { display: none; }
.nav__liste {
  display: flex; align-items: center; gap: var(--e6);
  list-style: none; margin: 0; padding: 0;
}
.nav__liste li { margin: 0; }
.nav__lien {
  font-family: var(--titre);
  font-size: var(--t-surtitre);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--texte);
  padding-block: var(--e3);
  display: inline-block;
  position: relative;
  white-space: nowrap;      /* sans lui, « Portes en acier » se casse sur trois lignes */
  transition: color var(--duree) ease-out;
}
/* Un cheveu d'or qui se pose sous le lien, pas une barre de 2 px. */
.nav__lien::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0;
  height: 1px; background: var(--or);
  opacity: 0; transition: opacity var(--duree) ease-out;
}
.nav__lien:hover { color: var(--or); }
.nav__lien:hover::after { opacity: 1; }
.nav__lien[aria-current="page"] { color: var(--or); }
.nav__lien[aria-current="page"]::after { opacity: 1; }

.entete__tel { flex: none; }

.bascule {
  flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  width: 48px; height: 48px;
  background: transparent;
  border: 1px solid var(--bordure-champ);
  border-radius: 0;
  color: var(--texte);
  cursor: pointer;
  transition: background-color var(--duree) ease-out, color var(--duree) ease-out, border-color var(--duree) ease-out;
}
.bascule:hover { background: var(--or); color: var(--nuit); border-color: var(--or); }
.bascule svg { width: 22px; height: 22px; }

/* Sous 600 px, l'en-tête tient sur une ligne sans pousser le viewport :
   logo, numéro en clair, bouton de menu. Un débordement de quelques pixels
   élargirait le viewport de mise en page et rapetisserait toute la page. */
@media (max-width: 599px) {
  :root { --marge: 20px; }
  .entete__interieur { gap: var(--e2); min-height: 64px; }
  .entete__logo img { width: 112px; height: 47px; }
  .entete__tel .bouton {
    padding: var(--e2) var(--e3);
    font-size: 0.6875rem;
    letter-spacing: 0.03em;
    gap: var(--e1);
    min-height: 44px;
  }
  .entete__tel .bouton svg { width: 15px; height: 15px; }
  .bascule { width: 44px; height: 44px; }
  .bascule svg { width: 20px; height: 20px; }
}

/* Sur les écrans très étroits, un seul mot peut être plus large que la colonne :
   « CONFIDENTIALITÉ » en capitales interlettrées débordait de 8 px à 320 px, et
   ces 8 px élargissaient le viewport. La coupure ne se déclenche que là. */
@media (max-width: 400px) {
  h1, h2, h3 { hyphens: auto; overflow-wrap: break-word; }
}

/* iPhone SE et consorts : à 320 px l'en-tête demandait 340 px. Vingt pixels de
   trop suffisent à élargir le viewport de mise en page et à rapetisser la page
   entière. Le logo se resserre, l'icône du bouton téléphone sort, le numéro reste. */
@media (max-width: 359px) {
  :root { --marge: var(--e4); }
  .entete__interieur { gap: var(--e1); }
  .entete__logo img { width: 92px; height: 39px; }
  .entete__tel .bouton { padding-inline: var(--e2); }
  .entete__tel .bouton svg { display: none; }
}

/* Seuil du menu, REMESURÉ le 27/08/2026 avec huit onglets (« Conseils » s'ajoute
   à « Réalisations »). Mesure faite au navigateur, largeur demandée par la barre
   entière, logo et bouton téléphone compris, marges de page incluses :

       gap 24 px, interlettrage 0,13em .......... 1492 px
       gap 24 px, interlettrage 0,09em .......... 1377 px
       gap 16 px, interlettrage 0,06em .......... 1288 px

   D'où trois paliers plutôt qu'un seuil unique : la barre apparaît resserrée à
   1300 px, puis reprend de l'air à 1400 et à 1600. Sans ce resserrement, il aurait
   fallu attendre 1520 px pour afficher la barre, et presque aucun portable ne
   l'aurait vue. Un débordement de quelques pixels élargit le viewport et rapetisse
   toute la page sans que rien ne le signale : ces valeurs se remesurent à chaque
   onglet ajouté, elles ne se devinent pas.
       ADLD_PAGES=/conseils/ python3 outils/controle.py <base> */
@media (min-width: 1360px) {
  .nav { display: block; }
  .bascule { display: none; }
  .entete__logo img { width: 184px; height: 77px; }
  .nav__liste { gap: var(--e4); }
  .nav__lien { letter-spacing: 0.06em; }
}
@media (min-width: 1400px) {
  .nav__liste { gap: var(--e6); }
  .nav__lien { letter-spacing: 0.09em; }
}
/* Au-delà de 1600 px, la barre respire : on rend l'air à la navigation. */
@media (min-width: 1800px) {
  .nav__liste { gap: var(--e8); }
  .nav__lien { letter-spacing: 0.16em; }
}

/* --------------------------------------------------------- panneau mobile */
.panneau {
  position: fixed; inset: 0;
  z-index: var(--z-panneau);
  background: var(--nuit-creux);
  color: var(--texte);
  display: flex; flex-direction: column;
  padding: var(--e6) var(--marge) var(--e12);
  overflow-y: auto;
}
.panneau[hidden] { display: none; }
.panneau__haut { display: flex; justify-content: flex-end; margin-bottom: var(--e12); }
.panneau__fermer {
  width: 48px; height: 48px;
  background: transparent; border: 1px solid var(--bordure-champ);
  border-radius: 0; color: var(--texte); cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background-color var(--duree) ease-out, color var(--duree) ease-out, border-color var(--duree) ease-out;
}
.panneau__fermer:hover { background: var(--or); color: var(--nuit); border-color: var(--or); }
.panneau__fermer svg { width: 22px; height: 22px; }
.panneau__liste { list-style: none; margin: 0 0 var(--e12); padding: 0; }
.panneau__liste li { margin: 0; border-bottom: 1px solid var(--bordure); }
.panneau__lien {
  display: block;
  padding: var(--e4) 0;
  font-family: var(--titre);
  font-size: 1.3125rem; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--blanc); text-decoration: none;
  transition: color var(--duree) ease-out;
}
.panneau__lien:hover, .panneau__lien[aria-current="page"] { color: var(--or); }
.panneau__tels { display: grid; gap: var(--e3); }
.panneau .legende { color: var(--gris); }
body.fige { overflow: hidden; }

/* ------------------------------------------------------------------ boutons */
/* Deux niveaux, pas trois : un aplat d'or, un contour clair. Sur la nuit, un
   bouton noir n'existe plus : c'est le métal qui porte l'appel. L'or tient
   7,1:1 avec la nuit posée dessus. Angles vifs, le métal a des arêtes. */
.bouton {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--e3);
  min-height: 52px;
  padding: var(--e4) var(--e8);
  border-radius: 0;
  border: 1px solid transparent;
  font-family: var(--titre);
  font-size: var(--t-surtitre);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--duree) ease-out, color var(--duree) ease-out, border-color var(--duree) ease-out;
}
.bouton--plein { background: var(--or); color: var(--nuit); border-color: var(--or); }
.bouton--plein:hover { background: var(--or-clair); border-color: var(--or-clair); color: var(--nuit); }
.bouton--contour { background: transparent; color: var(--or); border-color: var(--or-sourd); }
.bouton--contour:hover { background: var(--or); color: var(--nuit); border-color: var(--or); }
.bouton--clair { background: transparent; color: var(--texte); border-color: var(--bordure-champ); }
.bouton--clair:hover { background: var(--blanc); color: var(--nuit); border-color: var(--blanc); }
.bouton--blanc { background: var(--blanc); color: var(--nuit); border-color: var(--blanc); }
.bouton--blanc:hover { background: var(--or); color: var(--nuit); border-color: var(--or); }
.bouton svg { width: 18px; height: 18px; flex: none; }
.bouton[disabled] { opacity: .55; cursor: not-allowed; }
@media (max-width: 599px) { .bouton { min-height: 48px; padding: var(--e3) var(--e6); } }

.lien-fleche {
  font-family: var(--titre);
  font-size: var(--t-surtitre);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--blanc);
  display: inline-flex; align-items: center; gap: var(--e3);
  min-height: 44px;
  border-bottom: 1px solid var(--or-sourd);
  transition: color var(--duree) ease-out, border-color var(--duree) ease-out;
}
.lien-fleche::after { content: "\2192"; transition: transform var(--duree) ease-out; }
.lien-fleche:hover { color: var(--or); border-bottom-color: var(--or); }
.lien-fleche:hover::after { transform: translateX(5px); }

/* --------------------------------------------------------------------- hero */
/* Refondu le 27/08/2026. Ce qui a changé, et pourquoi :

   1. Le hero occupe la hauteur de l'écran moins l'en-tête. Un métallier d'art
      se juge d'abord sur ce qu'il pose : la photo passe avant le texte.
   2. La trame de verrière se trace par-dessus, montant par montant. C'est le
      dessin du métier, pas un ornement pris ailleurs.
   3. Rien de ce qui s'anime n'est l'élément LCP. La photo est préchargée,
      peinte immédiatement, et n'a ni fondu ni retard : seuls le mot-symbole,
      l'accroche et la trame entrent. Un h1 en fondu avait déjà coûté
      1,3 s de LCP sur un autre chantier ; on ne le repaie pas ici.
   4. La parallaxe se fait à la timeline de défilement du navigateur, sans une
      ligne de JavaScript. Là où elle n'existe pas (Safari), la photo est fixe
      et rien ne manque. */
.hero {
  position: relative;
  background: var(--nuit);
  overflow: hidden;
  isolation: isolate;
}
.hero__cadre { overflow: hidden; }
.hero__image {
  display: block; width: 100%;
  height: clamp(500px, calc(100svh - 64px), 760px);
  object-fit: cover;
  /* Le cadrage part légèrement agrandi : la parallaxe peut alors déplacer la
     photo sans découvrir de bande vide en bas. */
  transform: scale(1.07);
  transform-origin: 50% 40%;
}
/* Le voile n'est pas décoratif. Il porte deux charges : sans lui le mot-symbole
   clair se pose sur un mur clair et disparaît, et sans son pied opaque la photo
   se coupe net sur la nuit de la page. Elle y descend au lieu de s'arrêter. */
.hero__voile {
  position: absolute; inset: 0;
  /* Deux couches, et chacune repond a un defaut vu a la capture. L'ellipse tient
     le seul bloc de marque ; le degrade vertical assombrit le haut, ou la barre
     de navigation flotte, et ferme le bas, sans quoi la photo se couperait net
     sur la nuit de la page. */
  background:
    radial-gradient(ellipse 64% 50% at 50% 44%,
      rgba(13,18,24,.52) 0%,
      rgba(13,18,24,.24) 58%,
      rgba(13,18,24,0) 100%),
    linear-gradient(180deg,
      rgba(18,24,32,.62) 0%,
      rgba(18,24,32,.18) 30%,
      rgba(18,24,32,.44) 70%,
      rgba(18,24,32,.97) 100%);
}

/* La lueur d'atelier : une lampe d'or que la souris promène sur la verrière.
   Elle n'existe qu'au survol, elle ne se voit pas au repos, et le tactile ne
   la déclenche jamais (le script n'écoute que pointer: fine). */
.hero__lueur {
  position: absolute; inset: 0;
  pointer-events: none;
  opacity: 0;
  transition: opacity 600ms ease-out;
  background: radial-gradient(340px circle at var(--sx, 50%) var(--sy, 50%),
    rgba(212,163,89,.16) 0%, rgba(212,163,89,.06) 42%, transparent 72%);
}
.hero[data-lueur] .hero__lueur { opacity: 1; }

.hero__marque {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--e8);
  padding: var(--e12) var(--marge) var(--e24);
  text-align: center;
}
.hero__logo img {
  width: clamp(210px, 32vw, 360px);
  height: auto;
}
/* L'accroche du client, mot pour mot : « L'art de la métallerie sur mesure ».
   Ce n'est pas le h1 — le h1 reste le nom de la marque, dans la bande en
   dessous, peint immédiatement et jamais animé. */
.hero__accroche {
  font-family: var(--titre);
  font-size: clamp(0.8125rem, 0.72rem + 0.5vw, 1.0625rem);
  letter-spacing: 0.28em;
  text-transform: uppercase;
  /* >>> lisibilité du hero (27/08/2026)
     L'accroche était en or : 2,28:1 sur la photo, mesuré. La WCAG en demande
     4,5. L'or tient ses 8,1:1 sur un aplat de nuit, pas sur une photo. Le blanc
     donne 5,21:1 sur ce même fond, et il tient quelle que soit la photo qui
     passera ensuite. L'or reste sur le filet dessous, qui n'est pas du texte.
     ⚠️ À remesurer si la photo du hero change. */
  color: var(--blanc);
  margin: 0;
  max-width: 34em;
  /* 34em, pas 24 : plus court, la phrase se cassait entre le « sur » et le
     « mesure », et une accroche coupee au milieu d'un groupe se lit deux fois. */
  text-wrap: balance;
}
/* <<< fin lisibilité du hero */
.hero__accroche span { display: inline-block; }
.hero__accroche::after {
  content: ""; display: block;
  width: 56px; height: 1px; background: var(--or);
  margin: var(--e6) auto 0;
}

/* Les trois mentions du bas : où, quoi, comment. Elles tiennent le pied de la
   photo, qui sans elles se termine sur un dégradé vide. Décoratives au sens
   strict — tout y est écrit ailleurs en clair — donc aria-hidden. */
.hero__pied {
  position: absolute; left: 0; right: 0; bottom: var(--e8);
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: var(--e3) var(--e6);
  margin: 0; padding: 0 var(--marge);
  list-style: none;
  font-family: var(--titre);
  font-size: 0.6875rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--gris);
}
.hero__pied li { margin: 0; display: flex; align-items: center; gap: var(--e6); }
.hero__pied li + li::before {
  content: ""; width: 22px; height: 1px; background: var(--or-sourd);
}
@media (max-width: 560px) { .hero__pied li:last-child { display: none; } }

/* Le repère de défilement : un trait qui descend le long d'un rail, en boucle
   lente. Il ne dit rien qui ne soit dit ailleurs — d'où le libellé hors écran
   pour ceux qui l'atteignent au clavier. */
.hero__descendre {
  position: absolute; left: 50%; bottom: calc(var(--e8) + 34px);
  width: 44px; height: 44px;
  transform: translateX(-50%);
  display: flex; align-items: flex-end; justify-content: center;
}
.hero__trait {
  display: block; width: 1px; height: 34px;
  background: linear-gradient(180deg, transparent, var(--or-sourd));
  overflow: hidden;
}
@media (prefers-reduced-motion: no-preference) {
  .hero__trait::after {
    content: ""; display: block;
    width: 1px; height: 14px; background: var(--or-clair);
    animation: hero-descendre 2.4s var(--courbe) infinite;
  }
}
@keyframes hero-descendre {
  0%   { transform: translateY(-16px); opacity: 0; }
  35%  { opacity: 1; }
  100% { transform: translateY(34px); opacity: 0; }
}

@media (min-width: 768px) {
  .hero__image { height: clamp(600px, calc(100svh - 84px), 920px); }
  .hero__marque { gap: var(--e12); }
  .hero__pied { bottom: var(--e12); }
  .hero__descendre { bottom: calc(var(--e12) + 40px); }
}

/* ------------------------------------------------- l'entrée, et la parallaxe */
/* Tout ce bloc est suspendu à `prefers-reduced-motion` : sans lui rien n'entre,
   rien ne glisse, et la page est complète dès le premier rendu. */
@media (prefers-reduced-motion: no-preference) {
  .js-anim .hero__logo,
  .js-anim .hero__bouton,
  .js-anim .hero__pied {
    opacity: 0;
    transform: translateY(18px);
    animation: hero-entree 900ms var(--courbe) forwards;
  }
  .js-anim .hero__logo   { animation-delay: 120ms; }
  .js-anim .hero__bouton { animation-delay: 640ms; }
  .js-anim .hero__pied   { animation-delay: 860ms; }

  /* L'accroche ne monte pas : elle se découvre de gauche à droite, comme un
     trait tiré à la règle. C'est le geste du métier. */
  .js-anim .hero__accroche span {
    clip-path: inset(0 100% 0 0);
    animation: hero-tirer 1000ms var(--courbe) 380ms forwards;
  }
  .js-anim .hero__accroche::after {
    transform: scaleX(0);
    animation: hero-filet 700ms var(--courbe) 900ms forwards;
  }
}
@keyframes hero-entree { to { opacity: 1; transform: none; } }
@keyframes hero-tirer  { to { clip-path: inset(0 0 0 0); } }
@keyframes hero-filet  { to { transform: scaleX(1); } }

/* La parallaxe, à la timeline du navigateur : zéro JavaScript, zéro rAF, et
   rien à nettoyer. Là où `animation-timeline` n'existe pas, la photo est fixe
   et le hero reste juste. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .hero__image {
      animation: hero-glisse linear both;
      animation-timeline: scroll();
      animation-range: 0 90svh;
    }
    .hero__marque {
      animation: hero-recule linear both;
      animation-timeline: scroll();
      animation-range: 0 70svh;
    }
    @keyframes hero-glisse {
      from { transform: scale(1.07) translateY(0); }
      to   { transform: scale(1.07) translateY(6%); }
    }
    @keyframes hero-recule {
      from { opacity: 1; transform: translateY(0); }
      to   { opacity: 0; transform: translateY(-40px); }
    }
  }
}

/* -------------------------------------------------------------- bloc titre */
.titre-page { text-align: center; }
.titre-page h1 { margin-bottom: var(--e6); }
.titre-page .marque { display: block; }
.titre-page .metier {
  display: block;
  font-size: 0.52em;
  letter-spacing: 0.1em;
  line-height: 1.3;
  margin-top: var(--e6);
  color: var(--or);
}
.titre-page .zone {
  font-size: var(--t-corps);
  color: var(--gris);
  margin: 0 auto var(--e12);
  max-width: 38rem;
}
/* Un cheveu d'or sous le mot-symbole, en guise de ponctuation. */
.titre-page h1::after {
  content: ""; display: block;
  width: 56px; height: 1px; background: var(--or);
  margin: var(--e8) auto 0;
}

.tels { display: grid; gap: var(--e3); justify-content: center; }
@media (min-width: 560px) { .tels { grid-auto-flow: column; } }

/* --------------------------------------------------------- cartes métiers */
/* Pas de carte à bord ni d'ombre : une planche de catalogue. Un cheveu en tête,
   un numéro en or, le picto, le nom. Rien ne se soulève au survol. */
.cartes {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--e12) var(--e8);
  list-style: none; margin: 0; padding: 0;
  counter-reset: ouvrage;
}
.cartes li { margin: 0; }

/* Le nombre de colonnes est choisi pour que la dernière rangée tombe ronde.
   Une rangée de quatre cartes qui se casse en 3 + 1 se voit tout de suite,
   et on ne centre jamais la dernière rangée. */
@media (min-width: 620px) and (max-width: 1199px) {
  .cartes--quatre { grid-template-columns: repeat(2, 1fr); }
  .cartes--trois { grid-template-columns: repeat(2, 1fr); }
  .cartes--trois li:last-child { grid-column: 1 / -1; }
}
@media (min-width: 1200px) { .cartes--quatre { grid-template-columns: repeat(4, 1fr); } }
@media (min-width: 900px) { .cartes--trois { grid-template-columns: repeat(3, 1fr); } }

.carte {
  position: relative;
  height: 100%;
  display: flex; flex-direction: column;
  background: transparent;
  border-top: 1px solid var(--bordure);
  padding: var(--e6) 0 0;
  transition: border-color var(--duree) ease-out;
}
.carte:hover { border-top-color: var(--or); }
.cartes--quatre .carte::before {
  counter-increment: ouvrage;
  content: counter(ouvrage, decimal-leading-zero) " /";
  font-family: var(--titre);
  font-size: var(--t-surtitre);
  letter-spacing: 0.16em;
  color: var(--or);
  margin-bottom: var(--e6);
}
.carte__picto { width: 84px; height: 84px; margin-bottom: var(--e6); }
.carte h3 { margin-bottom: var(--e3); font-size: 1.0625rem; letter-spacing: 0.14em; }
.carte h3 a { color: inherit; text-decoration: none; transition: color var(--duree) ease-out; }
.carte h3 a::after { content: ""; position: absolute; inset: 0; }
.carte p { margin: 0; font-size: var(--t-legende); color: var(--gris); line-height: 1.65; }
.carte:hover h3 a { color: var(--or); }

/* ------------------------------------------------------------- les repères */
/* Les quatre chiffres que le client met en avant dans sa présentation : 400 m²
   d'atelier, trois artisans, le sur-mesure intégral, Challans. Ce sont ses
   chiffres, pas les nôtres : rien n'est ajouté ici qu'il n'ait écrit. */
.reperes {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1px;
  background: var(--bordure);
  border: 1px solid var(--bordure);
  list-style: none; margin: 0; padding: 0;
}
@media (min-width: 900px) { .reperes { grid-template-columns: repeat(4, 1fr); } }
.reperes li {
  margin: 0;
  background: var(--nuit);
  padding: var(--e8) var(--e6);
  text-align: center;
}
.reperes b {
  display: block;
  font-family: var(--titre);
  font-weight: 400;
  font-size: clamp(1.75rem, 1.2rem + 2.2vw, 2.625rem);
  letter-spacing: 0.04em;
  line-height: 1.1;
  color: var(--or);
  margin-bottom: var(--e3);
}
.reperes span {
  display: block;
  font-family: var(--titre);
  font-size: var(--t-surtitre);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--gris);
  line-height: 1.4;
}

/* ------------------------------------------------------------- les étapes */
/* Le parcours en trois temps de la présentation client : relevé, fabrication,
   pose. Trois surfaces d'acier posées sur la nuit, numérotées en or.

   Chaque étape porte son icône, un dessin au trait qui s'écrit tout seul quand
   la section arrive à l'écran. Le mécanisme est celui, déjà en place, de
   `.anim` / `.vu` : aucun script de plus, et si le JavaScript ne tourne pas,
   les icônes sont simplement là, entières et immobiles. Le dessin est un
   `stroke-dashoffset` mené par une transition — jamais une image-clé — pour
   que `prefers-reduced-motion`, qui ramène toutes les durées à 0,001 ms, les
   affiche d'un coup au lieu de les faire clignoter. */
.parcours {
  display: grid;
  gap: var(--e6);
  list-style: none; margin: 0; padding: 0;
  counter-reset: pas;
}
@media (min-width: 900px) { .parcours { grid-template-columns: repeat(3, 1fr); gap: var(--e8); } }
.parcours li {
  counter-increment: pas;
  position: relative;
  margin: 0;
  background: var(--acier);
  border: 1px solid var(--bordure);
  border-top: 1px solid var(--or-sourd);
  padding: var(--e8) var(--e6) var(--e6);
  transition: border-color var(--duree) ease-out, background-color var(--duree) ease-out;
}
.parcours li:hover { background: var(--acier-clair); border-top-color: var(--or); }
/* le numéro va se loger en haut à droite : la place de gauche est à l'icône */
.parcours li::before {
  content: counter(pas, decimal-leading-zero) " /";
  position: absolute;
  top: var(--e8); right: var(--e6);
  font-family: var(--titre);
  font-size: var(--t-surtitre);
  letter-spacing: 0.18em;
  color: var(--or);
}
.parcours h3 { font-size: 1.0625rem; letter-spacing: 0.13em; margin-bottom: var(--e4); }
.parcours p { margin: 0; color: var(--gris); font-size: var(--t-legende); line-height: 1.7; }

/* l'icône */
.parcours__ico {
  display: block;
  width: 56px; height: 56px;
  margin-bottom: var(--e6);
  color: var(--texte);
  transition: color var(--duree) ease-out, transform 420ms cubic-bezier(0.22, 0.61, 0.36, 1);
}
.parcours__ico svg { display: block; width: 100%; height: 100%; overflow: visible; }
.parcours__ico .t {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.25;
  stroke-linecap: square;
  stroke-linejoin: miter;
  /* surtout pas de vector-effect: non-scaling-stroke ici — combiné à
     pathLength il fait calculer les tirets dans une autre unité et le tracé
     arrive troué, définitivement. Le SVG est carré et mis à l'échelle
     uniformément : 1,25 dans un viewBox de 64 rendu à 56 px vaut 1,09 px. */
}
.parcours__ico .a { stroke: var(--or); }
.parcours__ico .p { fill: var(--or); stroke: none; }
.parcours li:hover .parcours__ico { color: var(--blanc); transform: translateY(-2px); }
.parcours li:hover .parcours__ico .a { stroke: var(--or-clair); }
.parcours li:hover .parcours__ico .p { fill: var(--or-clair); }

/* ce qui bouge au survol : un geste par métier, jamais deux */
.parcours__ico g {
  transition: transform 420ms cubic-bezier(0.22, 0.61, 0.36, 1);
  transform-box: fill-box;
}
/* la cote s'ouvre depuis son milieu, comme un mètre qu'on déplie */
.parcours__ico .g-cote { transform-origin: 50% 50%; }
.parcours li:hover .parcours__ico .g-cote { transform: scaleX(1.14); }
/* la gerbe d'étincelles part vers le haut */
.parcours__ico .g-gerbe { transform-origin: 100% 100%; }
.parcours li:hover .parcours__ico .g-gerbe { transform: translate(-2px, -2.5px) scale(1.1); }
/* la bulle du niveau se cale entre ses deux repères, puis se stabilise.
   Au repos elle est centrée : hors survol — sur un téléphone, donc — une bulle
   décalée passerait pour un dessin de travers, pas pour une intention. */
.parcours__ico .g-bulle { transform-origin: 50% 50%; }
@keyframes caler-la-bulle {
  0%   { transform: translateX(0); }
  28%  { transform: translateX(-3.2px); }
  62%  { transform: translateX(1.6px); }
  100% { transform: translateX(0); }
}
.parcours li:hover .parcours__ico .g-bulle .p {
  animation: caler-la-bulle 760ms cubic-bezier(0.4, 0, 0.2, 1);
}

/* le dessin, à l'entrée de la section — inerte tant que .anim n'est pas armé */
.js-anim .parcours__ico .t { stroke-dasharray: 1; stroke-dashoffset: 1; }
.js-anim .parcours__ico .p { opacity: 0; }
.js-anim .anim.vu .parcours__ico .t {
  stroke-dashoffset: 0;
  transition: stroke-dashoffset 620ms cubic-bezier(0.65, 0.02, 0.3, 1) var(--retard, 0ms),
              stroke var(--duree) ease-out;
}
.js-anim .anim.vu .parcours__ico .p {
  opacity: 1;
  transition: opacity 320ms ease-out var(--retard, 0ms), fill var(--duree) ease-out;
}
/* trois rangs dans l'icône, trois départs décalés entre les cartes : le
   parcours s'écrit de la première étape à la dernière, dans l'ordre du texte */
.js-anim .anim.vu .parcours li:nth-child(1) .parcours__ico { --pas: 60ms; }
.js-anim .anim.vu .parcours li:nth-child(2) .parcours__ico { --pas: 260ms; }
.js-anim .anim.vu .parcours li:nth-child(3) .parcours__ico { --pas: 460ms; }
.js-anim .anim.vu .parcours__ico .t1 { --retard: var(--pas); }
.js-anim .anim.vu .parcours__ico .t2 { --retard: calc(var(--pas) + 170ms); }
.js-anim .anim.vu .parcours__ico .t3,
.js-anim .anim.vu .parcours__ico .p  { --retard: calc(var(--pas) + 330ms); }

@media (prefers-reduced-motion: reduce) {
  .js-anim .parcours__ico .t { stroke-dashoffset: 0; }
  .js-anim .parcours__ico .p { opacity: 1; }
}

/* --------------------------------------------------------- les exigences */
/* Les quatre points techniques que le client appelle sa signature. Un tiret
   d'or en guise de puce, le terme du métier en tête, l'explication derrière. */
.exigences { list-style: none; padding: 0; margin: 0; }
.exigences li {
  position: relative;
  padding: var(--e6) 0 var(--e6) var(--e12);
  border-bottom: 1px solid var(--bordure);
  margin: 0;
}
.exigences li:first-child { border-top: 1px solid var(--bordure); }
.exigences li::before {
  content: ""; position: absolute; left: 0; top: 2.05em;
  width: 24px; height: 1px; background: var(--or);
}
.exigences b {
  font-family: var(--titre);
  font-weight: 400;
  font-size: 1rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--blanc);
  display: block;
  margin-bottom: var(--e2);
}
.exigences span { color: var(--gris); }

/* -------------------------------------------------------- le comparatif */
/* Le tableau de la présentation client : le standard de série face au
   sur-mesure. Il défile dans son propre conteneur : jamais le corps de page. */
.comparatif-cadre { overflow-x: auto; border: 1px solid var(--bordure); }
.comparatif {
  width: 100%;
  min-width: 640px;
  border-collapse: collapse;
  font-size: var(--t-legende);
  text-align: left;
}
.comparatif th, .comparatif td {
  padding: var(--e4) var(--e6);
  border-bottom: 1px solid var(--bordure);
  vertical-align: top;
}
.comparatif thead th {
  font-family: var(--titre);
  font-weight: 400;
  font-size: var(--t-surtitre);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--or);
  background: var(--acier);
  border-bottom-color: var(--or-sourd);
}
.comparatif tbody th {
  font-family: var(--texte-police);
  font-weight: 400;
  color: var(--texte);
}
.comparatif td { color: var(--gris); }
/* La colonne d'ADLD est celle qu'on lit : elle est tenue par un fond d'acier
   et un texte clair. Le fond seul ne suffirait pas, c'est aussi la valeur du
   texte qui la désigne — la couleur n'est jamais le seul indice. */
.comparatif .nous { background: var(--acier); color: var(--texte); }
.comparatif thead .nous { color: var(--or-clair); }
.comparatif tbody tr:last-child th, .comparatif tbody tr:last-child td { border-bottom: 0; }

/* --------------------------------------------------------- deux colonnes */
.duo {
  display: grid;
  gap: var(--e12);
  align-items: center;
}
@media (min-width: 900px) {
  .duo { grid-template-columns: 1fr 1fr; gap: var(--e24); }
  .duo--decale { grid-template-columns: 5fr 7fr; }   /* asymétrie assumée */
  .duo--inverse > :first-child { order: 2; }
}
.duo img { width: 100%; height: auto; }
/* Une photo claire posée sur la nuit a besoin d'un bord, sinon elle flotte.
   Un cheveu d'acier, pas un cadre. */
.duo picture img, .duo > div > img { border: 1px solid var(--bordure); }

/* Une photo qui tient toute la largeur : c'est elle qui porte la page. */
.bande--photo { padding: 0; background: var(--nuit); position: relative; }
.bande--photo img {
  width: 100%;
  height: clamp(300px, 54vw, 640px);
  object-fit: cover;
}
/* Le raccord haut et bas : la photo entre dans la nuit et en ressort, elle ne
   se coupe pas au couteau. Le voile est inerte au pointeur. */
.bande--photo::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background:
    linear-gradient(180deg,
      rgba(18,24,32,.55) 0%,
      rgba(18,24,32,0) 22%,
      rgba(18,24,32,0) 78%,
      rgba(18,24,32,.55) 100%);
}

/* ------------------------------------------------------------------ listes */
.liste-ouvrages { list-style: none; padding: 0; margin: 0; }
.liste-ouvrages li {
  padding: var(--e4) 0 var(--e4) var(--e8);
  border-bottom: 1px solid var(--bordure);
  position: relative;
  margin: 0;
}
.liste-ouvrages li:first-child { border-top: 1px solid var(--bordure); }
.liste-ouvrages li::before {
  content: ""; position: absolute; left: 0; top: 1.5em;
  width: 16px; height: 1px; background: var(--or);
}

.questions { margin: 0; }
.questions h3 { margin-bottom: var(--e4); font-size: 1.0625rem; letter-spacing: 0.12em; }
.questions > div { padding-block: var(--e8); border-top: 1px solid var(--bordure); }
.questions > div:last-child { border-bottom: 1px solid var(--bordure); }
.questions p { max-width: var(--prose); margin-bottom: 0; }

/* --------------------------------------------------------------- contact */
.coordonnees { display: grid; gap: var(--e12); }
@media (min-width: 900px) { .coordonnees { grid-template-columns: 1fr 1fr; gap: var(--e24); } }
.tel-grand {
  display: flex; align-items: center; gap: var(--e4);
  font-family: var(--titre);
  font-size: clamp(1.5rem, 1rem + 2vw, 2.125rem);
  letter-spacing: 0.05em;
  text-decoration: none;
  color: var(--blanc);
  padding-block: var(--e4);
  border-bottom: 1px solid var(--bordure);
  transition: color var(--duree) ease-out, border-color var(--duree) ease-out;
}
.tel-grand:first-of-type { border-top: 1px solid var(--bordure); }
.tel-grand:hover { color: var(--or); border-bottom-color: var(--or); }
.tel-grand svg { width: 24px; height: 24px; flex: none; color: var(--or); }

address { font-style: normal; }
.etapes { counter-reset: etape; list-style: none; padding: 0; margin: 0; }
.etapes li {
  counter-increment: etape;
  position: relative;
  padding-left: var(--e16);
  padding-block: var(--e4);
  margin: 0;
  border-bottom: 1px solid var(--bordure);
}
.etapes li:first-child { border-top: 1px solid var(--bordure); }
.etapes li::before {
  content: counter(etape, decimal-leading-zero) " /";
  position: absolute; left: 0; top: 1.15em;
  font-family: var(--titre);
  font-size: var(--t-surtitre);
  letter-spacing: 0.16em;
  color: var(--or);
}

/* ------------------------------------------------------------- formulaire */
.formulaire { display: grid; gap: var(--e8); max-width: 40rem; }
.champ { display: grid; gap: var(--e3); }
.champ label {
  font-family: var(--titre);
  font-size: var(--t-surtitre);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--texte);
}
.champ input, .champ select, .champ textarea {
  font-family: var(--texte-police);
  font-size: var(--t-corps);
  line-height: 1.5;
  color: var(--blanc);
  background: var(--acier);
  border: 1px solid var(--bordure-champ);
  border-radius: 0;
  padding: var(--e4);
  min-height: 52px;
  width: 100%;
  transition: border-color var(--duree) ease-out;
}
/* Sans cette règle, Chrome peint le menu déroulant en clair sur un champ
   sombre et la valeur choisie devient illisible dans la liste ouverte. */
.champ select option { background: var(--acier); color: var(--blanc); }
.champ textarea { min-height: 180px; resize: vertical; }
.champ input:focus-visible, .champ select:focus-visible, .champ textarea:focus-visible {
  border-color: var(--or);
}
.champ input::placeholder, .champ textarea::placeholder { color: var(--gris); opacity: 1; }
.champ .aide { font-size: var(--t-legende); color: var(--gris); }
.champ .erreur {
  font-size: var(--t-legende);
  color: var(--alerte);
  display: none;
  align-items: center; gap: var(--e2);
}
.champ[data-erreur] .erreur { display: flex; }
.champ[data-erreur] input, .champ[data-erreur] select, .champ[data-erreur] textarea { border-color: var(--alerte); }
.requis { color: var(--or); }
.piege { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.message-envoi {
  padding: var(--e6);
  border-left: 2px solid var(--or);
  background: var(--acier);
  margin-bottom: var(--e8);
}
.message-envoi[hidden] { display: none; }

/* -------------------------------------------------------------- carte SVG */
.carte-lieu { max-width: 460px; }
.carte-lieu svg { width: 100%; height: auto; }
.carte-lieu .contour { fill: none; stroke: var(--bordure-champ); stroke-width: 1.5; }
.carte-lieu .point { fill: var(--or); }
.carte-lieu .etiquette {
  font-family: var(--titre); font-size: 24px; letter-spacing: 3px;
  fill: var(--blanc); text-transform: uppercase;
}

/* ----------------------------------------------------------------- pied */
.pied { background: var(--nuit-creux); color: var(--texte); padding-block: var(--e24) var(--e8); border-top: 1px solid var(--bordure); }
.pied a { color: var(--texte); text-decoration: none; transition: color var(--duree) ease-out; }
.pied a:hover { color: var(--or); text-decoration: underline; text-underline-offset: 0.25em; }
.pied__colonnes { display: grid; gap: var(--e12); }
@media (min-width: 760px) { .pied__colonnes { grid-template-columns: 1.3fr 1fr 1fr; gap: var(--e16); } }
.pied h2 {
  font-size: var(--t-surtitre); letter-spacing: 0.2em;
  color: var(--or); margin-bottom: var(--e6);
}
.pied ul { list-style: none; padding: 0; margin: 0; }
.pied li { margin-bottom: var(--e3); }
.pied__logo { width: 158px; height: auto; margin-bottom: var(--e6); }
.pied .legende { color: var(--gris); }
.pied__bas {
  margin-top: var(--e16);
  padding-top: var(--e6);
  border-top: 1px solid var(--bordure);
  display: flex; flex-wrap: wrap; gap: var(--e4) var(--e8);
  align-items: center; justify-content: space-between;
  font-size: var(--t-legende);
  color: var(--gris);
}
.pied__bas a { color: var(--gris); }
.pied__bas a:hover { color: var(--or); }

/* --------------------------------------------------------------- 404 */
.erreur-page { text-align: center; padding-block: var(--e32); }

/* =========================================================================
   LA TRAME DE VERRIÈRE
   Le motif du site. Des montants verticaux d'un pixel, deux traverses, et du
   vide entre les deux : le dessin d'une verrière d'atelier. Elle se construit
   quand sa section entre à l'écran — les montants descendent, les traverses
   les traversent ensuite — puis elle ne bouge plus.

   Deux dégradés et deux `transform: scale`, rien d'autre. Le pas de la grille
   est porté par la variante, jamais par un style en ligne (la CSP l'interdit).
   ========================================================================= */
.trame {
  position: absolute; inset: 0;
  pointer-events: none;
  overflow: hidden;
}
.trame span { position: absolute; inset: 0; display: block; }

.trame__montants {
  background-image: repeating-linear-gradient(90deg,
    var(--trame-trait) 0 1px, transparent 1px var(--trame-pas));
  transform-origin: 50% 0;
}
.trame__traverses {
  background-repeat: no-repeat;
  background-image:
    linear-gradient(var(--trame-trait), var(--trame-trait)),
    linear-gradient(var(--trame-trait), var(--trame-trait));
  background-size: 100% 1px, 100% 1px;
  background-position: 0 24%, 0 62%;
  transform-origin: 0 50%;
}

/* Les variantes : le pas de la grille, et la hauteur des traverses. */
.trame--hero    { --trame-pas: 14.2857%; }
.trame--hero .trame__traverses    { background-position: 0 22%, 0 58%; }
/* Au centre du hero il y a déjà une verrière sur la photo, et le mot-symbole
   par-dessus. Une grille de plus y ferait du bruit : elle s'efface au milieu
   et ne tient que les bords, là où la photo se ferme sur la nuit de la page. */
.trame--hero span {
  -webkit-mask-image: radial-gradient(ellipse 52% 42% at 50% 46%,
    transparent 0%, rgba(0,0,0,.55) 62%, #000 100%);
  mask-image: radial-gradient(ellipse 52% 42% at 50% 46%,
    transparent 0%, rgba(0,0,0,.55) 62%, #000 100%);
}
/* Dans une vitrine, la trame ne se construit pas au défilement : elle se
   construit SOUS LE CURSEUR, montants d'abord. Deux transitions suffisent, le
   script n'a rien à savoir, et l'effet part aussi au clavier (:focus-within). */
.trame--vitrine { --trame-pas: 25%; opacity: 0; transition: opacity 420ms var(--courbe); }
.trame--vitrine .trame__traverses { background-position: 0 30%, 0 66%; }
.trame--vitrine .trame__montants  { transform: scaleY(0); transition: transform 760ms var(--courbe); }
/* Sur une photo, un filet d'or seul se perd dans les hautes lumières. Chaque
   montant est donc GRAVÉ : un pixel d'or, un pixel de nuit juste à côté. C'est
   ce que fait une vraie arête de métal contre un mur clair, et ça ne coûte
   qu'une étape de plus dans le même dégradé — aucun filtre, aucune ombre. */
.trame--vitrine .trame__montants {
  background-image: repeating-linear-gradient(90deg,
    rgba(212,163,89,.42) 0 1px, rgba(13,18,24,.34) 1px 2px, transparent 2px var(--trame-pas));
}
.trame--vitrine .trame__traverses {
  background-image:
    linear-gradient(rgba(212,163,89,.42) 0 1px, rgba(13,18,24,.34) 1px 2px, transparent 2px),
    linear-gradient(rgba(212,163,89,.42) 0 1px, rgba(13,18,24,.34) 1px 2px, transparent 2px);
  background-size: 100% 2px, 100% 2px;
}
.trame--vitrine .trame__traverses { transform: scaleX(0); transition: transform 620ms var(--courbe) 240ms; }
.vitrine:hover .trame--vitrine .trame__montants,
.vitrine:focus-within .trame--vitrine .trame__montants { transform: scaleY(1); }
.vitrine:hover .trame--vitrine .trame__traverses,
.vitrine:focus-within .trame--vitrine .trame__traverses { transform: scaleX(1); }
.trame--bande   { --trame-pas: 16.6666%; }

/* La construction. Elle ne part que si le script a posé .js-anim, et elle est
   entièrement suspendue à prefers-reduced-motion : sans mouvement, la grille
   est là dès le premier rendu, entière. */
@media (prefers-reduced-motion: no-preference) {
  .js-anim .trame--hero .trame__montants {
    transform: scaleY(0);
    animation: trame-descendre var(--duree-trace) var(--courbe) 260ms forwards;
  }
  .js-anim .trame--hero .trame__traverses {
    transform: scaleX(0);
    animation: trame-traverser 900ms var(--courbe) 900ms forwards;
  }
}
@keyframes trame-descendre  { to { transform: scaleY(1); } }
@keyframes trame-traverser  { to { transform: scaleX(1); } }

/* ------------------------------------------------------------- le raccord */
/* Le pied d'une verrière, posé entre deux sections de même fond, là où rien ne
   disait qu'on changeait de sujet. Un filet, et cinq montants qui s'y plantent. */
.raccord {
  height: 34px;
  position: relative;
  overflow: hidden;
}
.raccord span {
  position: absolute; inset: 0;
  background-repeat: no-repeat;
  background-image:
    linear-gradient(90deg, transparent, var(--or-sourd) 22%, var(--or-sourd) 78%, transparent),
    repeating-linear-gradient(90deg, var(--bordure) 0 1px, transparent 1px 12.5%);
  background-size: 100% 1px, 62% 22px;
  background-position: 0 100%, 50% calc(100% - 1px);
}

/* =========================================================================
   LES VITRINES — les quatre ouvrages sur l'accueil
   Un métallier d'art se juge sur ce qu'il pose. La photo porte la carte ; le
   nom reste sur un aplat de nuit, jamais au milieu de l'image, sinon il
   dépend du cliché pour être lisible.
   ========================================================================= */
.vitrines {
  display: grid;
  gap: var(--e12);
  list-style: none; margin: 0; padding: 0;
}
@media (min-width: 700px)  { .vitrines { grid-template-columns: repeat(2, 1fr); gap: var(--e16) var(--e8); } }
.vitrines li { margin: 0; }

.vitrine {
  position: relative;
  height: 100%;
  display: flex; flex-direction: column;
}
.vitrine__media {
  position: relative;
  overflow: hidden;
  background: var(--acier);
  aspect-ratio: 4 / 3;
  border: 1px solid var(--bordure);
  transition: border-color var(--duree) ease-out;
}
.vitrine__media picture, .vitrine__media img {
  width: 100%; height: 100%;
  object-fit: cover;
}
.vitrine__media img {
  transform: scale(1.001);
  transition: transform 900ms var(--courbe), filter 600ms ease-out;
  filter: saturate(.92) brightness(.88);
}
.vitrine__voile {
  position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(13,18,24,.05) 0%, rgba(13,18,24,.62) 100%);
  transition: opacity 600ms ease-out;
}

.vitrine__texte { padding-top: var(--e6); }
.vitrine__num {
  display: flex; align-items: center; gap: var(--e4);
  font-family: var(--titre);
  font-size: var(--t-surtitre);
  letter-spacing: 0.16em;
  color: var(--or);
  margin: 0 0 var(--e4);
}
.vitrine__barre {
  display: block; height: 1px; width: 34px;
  background: var(--or-sourd);
  transition: width 600ms var(--courbe), background-color var(--duree) ease-out;
}
.vitrine h3 { margin: 0 0 var(--e3); font-size: var(--t-h3); letter-spacing: 0.1em; }
.vitrine h3 a { color: inherit; text-decoration: none; transition: color var(--duree) ease-out; }
/* Le lien du titre couvre la carte entière : la photo est cliquable sans qu'un
   second lien vienne doubler la cible dans la navigation au clavier. */
.vitrine h3 a::after { content: ""; position: absolute; inset: 0; z-index: 1; }
.vitrine__phrase { margin: 0; color: var(--gris); font-size: var(--t-legende); line-height: 1.7; }
.vitrine__fleche {
  display: inline-flex; align-items: center; gap: var(--e2);
  margin-top: var(--e4);
  font-family: var(--titre);
  font-size: var(--t-surtitre);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--gris);
  transition: color var(--duree) ease-out;
}
.vitrine__fleche::after { content: "\2192"; transition: transform var(--duree) ease-out; }

/* Le survol : la photo s'ouvre, la trame s'allume, la barre s'allonge.
   Rien ne se soulève et rien ne change de taille — aucun décalage de mise en
   page, donc rien ne saute sous le curseur. */
.vitrine:hover .vitrine__media img,
.vitrine:focus-within .vitrine__media img { transform: scale(1.06); filter: saturate(1) brightness(1); }
.vitrine:hover .vitrine__voile,
.vitrine:focus-within .vitrine__voile { opacity: .55; }
.vitrine:hover .trame--vitrine,
.vitrine:focus-within .trame--vitrine { opacity: 1; }
.vitrine:hover .vitrine__media,
.vitrine:focus-within .vitrine__media { border-color: var(--or-sourd); }
.vitrine:hover h3 a, .vitrine:focus-within h3 a { color: var(--or); }
.vitrine:hover .vitrine__barre, .vitrine:focus-within .vitrine__barre { width: 64px; background: var(--or); }
.vitrine:hover .vitrine__fleche, .vitrine:focus-within .vitrine__fleche { color: var(--or); }
.vitrine:hover .vitrine__fleche::after, .vitrine:focus-within .vitrine__fleche::after { transform: translateX(5px); }

/* =========================================================================
   LES RÉVÉLATIONS AU DÉFILEMENT
   Le contenu est visible par défaut. Le script pose .js-anim sur <html> puis
   dégrade, de sorte qu'un échec du script ne cache jamais rien.

   Ce qui a changé le 27/08/2026 : ce n'est plus le bloc entier qui monte d'un
   coup, ce sont ses enfants directs, en cascade de 90 ms. Un titre, son filet,
   son texte : trois temps au lieu d'un. Aucune classe à poser dans le HTML —
   la cascade se fait au sélecteur, sur les quarante-six pages à la fois.
   ========================================================================= */
.js-anim .anim { opacity: 0; }
.js-anim .anim > * {
  opacity: 0;
  transform: translateY(22px);
}
.js-anim .anim.vu { opacity: 1; }
.js-anim .anim.vu > * {
  opacity: 1;
  transform: none;
  transition: opacity var(--duree-lente) var(--courbe), transform var(--duree-lente) var(--courbe);
}
.js-anim .anim.vu > :nth-child(1) { transition-delay: 0ms; }
.js-anim .anim.vu > :nth-child(2) { transition-delay: 90ms; }
.js-anim .anim.vu > :nth-child(3) { transition-delay: 180ms; }
.js-anim .anim.vu > :nth-child(4) { transition-delay: 270ms; }
.js-anim .anim.vu > :nth-child(n+5) { transition-delay: 340ms; }

/* Le filet ne monte pas : il se tire, de la gauche vers la droite. */
.js-anim .anim > .filet { transform: scaleX(0); transform-origin: 0 50%; }
.js-anim .anim.vu > .filet { transform: scaleX(1); }

/* Dans une grille, ce sont les cases qui entrent l'une après l'autre, pas la
   grille d'un bloc. Sans ça, quatre vitrines apparaissent comme un mur. */
.js-anim .vitrines > li,
.js-anim .cartes > li,
.js-anim .reperes > li,
.js-anim .parcours > li,
.js-anim .notes > li {
  opacity: 0;
  transform: translateY(26px);
}
.js-anim .anim.vu .vitrines > li,
.js-anim .anim.vu .cartes > li,
.js-anim .anim.vu .reperes > li,
.js-anim .anim.vu .parcours > li,
.js-anim .anim.vu .notes > li {
  opacity: 1; transform: none;
  transition: opacity var(--duree-lente) var(--courbe), transform var(--duree-lente) var(--courbe);
}
.js-anim .anim.vu li:nth-child(1) { transition-delay: 80ms; }
.js-anim .anim.vu li:nth-child(2) { transition-delay: 200ms; }
.js-anim .anim.vu li:nth-child(3) { transition-delay: 320ms; }
.js-anim .anim.vu li:nth-child(4) { transition-delay: 440ms; }
.js-anim .anim.vu li:nth-child(n+5) { transition-delay: 520ms; }

/* Une photo ne monte pas et ne s'estompe pas : elle se découvre par le bas,
   comme un voile qu'on retire d'un ouvrage. */
.js-anim .anim > div > picture img,
.js-anim .anim picture.revele img { clip-path: inset(0 0 100% 0); transform: none; }
.js-anim .anim.vu > div > picture img,
.js-anim .anim.vu picture.revele img {
  clip-path: inset(0 0 0 0);
  transition: clip-path 1000ms var(--courbe) 120ms;
}

/* Le h1 de l'accueil se découvre au masque. Il n'est jamais l'élément LCP —
   c'est la photo du hero, préchargée, qui l'est — et il reste peint en clair
   si le script ne tourne pas. */
.js-anim .revele > span { clip-path: inset(0 0 110% 0); display: block; }
.js-anim .revele.vu > span {
  clip-path: inset(-20% -20% -20% -20%);
  transition: clip-path 900ms var(--courbe);
}
.js-anim .revele.vu > span:nth-child(2) { transition-delay: 180ms; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  .js-anim .anim,
  .js-anim .anim > *,
  .js-anim .vitrines > li, .js-anim .cartes > li, .js-anim .reperes > li,
  .js-anim .parcours > li, .js-anim .notes > li { opacity: 1; transform: none; }
  .js-anim .anim > .filet { transform: none; }
  .js-anim .anim > div > picture img,
  .js-anim .anim picture.revele img,
  .js-anim .revele > span { clip-path: none; }
  .trame--vitrine { opacity: 1; }
}

/* ---- pictogrammes : début du bloc posé par outils/patch-pictos-css.py ---- */
/* Six tracés SVG inline, un par ouvrage et un par rubrique de conseils, rendus
   par outils/pictos.py. Ils ont remplacé le 27/08/2026 les PNG du client, qui
   étaient quatre fois le même dessin de verrière teinté d'or par un
   `filter: invert()`.

   Le SVG hérite de `color` : une seule ligne suffit à faire monter l'icône vers
   l'or clair quand la carte est survolée, et le trait reste net à toute taille.
   Aucun aplat, aucun rayon, aucune ombre : le vocabulaire du site.

   Deux animations, et rien d'autre :
     · à l'apparition, l'icône se DESSINE, couche par couche — le sol, la
       structure, la trame, l'accent — dans l'ordre où on la construirait ;
     · au survol, un reflet oblique traverse le métal, une seule fois.

   Le tracé passe par `pathLength="1"` posé sur chaque <path> : sans lui, un
   stroke-dasharray fixe rendrait un trait court invisible pendant presque toute
   la durée. Même mécanique que `.parcours__ico`, autre bloc de cette feuille. */
.picto {
  color: var(--or);
  transition: color var(--duree) ease-out;
}

/* LA GRAISSE. Les trois familles d'icônes du site rendent le même trait à
   l'écran, environ 1,18 px — le filet d'un pixel de la charte. C'est ce qui les
   fait tenir ensemble, et ça se règle sur le trait RENDU, jamais sur la valeur
   nominale : l'interface est en 1,6 sur une grille de 24 servie à 18 px, le
   parcours en 1,25 sur 64 servi à 56 px.

   Ces pictos-ci sont servis à TROIS tailles, donc un stroke-width unique
   donnerait trois traits différents. L'attribut du SVG porte 0,9 (la carte,
   seize occurrences) et les deux autres contextes sont corrigés ici.

   ⚠️ Surtout pas `vector-effect: non-scaling-stroke`, qui résoudrait ça d'une
   ligne : combiné au `pathLength="1"` des tracés, il fait calculer les tirets
   dans une autre unité et les icônes arrivent TROUÉES, sans une erreur. Piège
   déjà payé sur les icônes du parcours de ce site. */
.carte__picto    { stroke-width: 0.9; }   /* 84 px -> 1,18 px */
.rubrique__picto { stroke-width: 1.2; }   /* 64 px -> 1,20 px */
.carte:hover .picto,
.carte:focus-within .picto { color: var(--or-clair); }

/* Le reflet n'existe qu'au survol. Au repos il est invisible, sans exception :
   c'est cette règle qui saute en premier si la feuille est réécrite, et ça se
   voit tout de suite — deux traits obliques en travers de chaque icône. */
.picto__reflet { opacity: 0; }
.picto__reflet path { stroke: var(--or-clair); stroke-width: 2.5; }

@media (prefers-reduced-motion: no-preference) {
  /* L'état de départ n'est posé que si le script est là pour donner le .vu :
     sans JavaScript, l'icône est dessinée d'emblée et ne disparaît jamais. */
  .js-anim .anim .picto__t path { stroke-dasharray: 1; stroke-dashoffset: 1; }
  .js-anim .anim.vu .picto__t path {
    animation: picto-tracer 760ms cubic-bezier(0.45, 0, 0.15, 1) forwards;
  }
  .js-anim .anim.vu .picto__t--2 path { animation-delay: 90ms; }
  .js-anim .anim.vu .picto__t--3 path { animation-delay: 180ms; }
  .js-anim .anim.vu .picto__t--4 path { animation-delay: 270ms; }

  /* Une animation, pas une transition : quand la souris ressort, la règle tombe
     et le reflet redevient invisible net, sans repartir en marche arrière. */
  .carte:hover .picto__reflet,
  .carte:focus-within .picto__reflet { animation: picto-reflet 820ms ease-out; }
}

/* En mobile la feuille descend l'en-tête de rubrique à 48 px : sans ce
   rattrapage le trait tomberait à 0,90 px et l'icône s'effacerait. */
@media (max-width: 599px) {
  .rubrique__picto { stroke-width: 1.55; }   /* 48 px -> 1,16 px */
}

/* =========================================================================
   L'EMBLÈME — un pictogramme servi grand, là où il n'y a pas de photo

   Il y a des blocs dont aucune photo ne dit le sujet. L'atelier de Challans en
   est un : les clichés du client montrent des ouvrages posés chez des
   particuliers, aucun ne montre l'atelier. Y mettre un escalier revient à le
   faire passer pour l'atelier.

   L'emblème remplit alors la colonne qu'une photo occuperait — même place dans
   le duo, même cheveu d'acier autour — avec la trame de verrière derrière et le
   dessin au trait au centre.

   ⚠️ LA GRAISSE, encore : le SVG arrive avec stroke-width 0,9 sur une grille de
   64, taillé pour les 84 px de la carte. Servi à 176 px il rendrait 2,47 px,
   soit plus du double du filet du site. D'où les deux corrections ci-dessous,
   calculées comme les autres sur le trait RENDU. Surtout pas
   `vector-effect: non-scaling-stroke` : avec pathLength="1" l'icône arrive
   trouée, sans une erreur (piège déjà payé deux fois sur ce site).
   ========================================================================= */
.embleme {
  position: relative;
  display: grid;
  place-items: center;
  aspect-ratio: 16 / 9;
  background: var(--acier);
  border: 1px solid var(--bordure);
  overflow: hidden;
}
.embleme__vue { position: relative; z-index: 1; display: block; }
.embleme__picto { width: 160px; height: 160px; stroke-width: 0.472; }   /* 160 px -> 1,18 px */

/* En colonne, le panneau est large et court : 16/9 et une icône aux deux tiers
   de sa hauteur. À partir de 900 px il reprend la place d'une photo dans le
   duo, donc le 4/3 d'un cliché — et l'icône grandit d'autant, sinon elle flotte
   au milieu d'un carré vide. Le rapport icône/hauteur reste le même : 62 %. */
@media (min-width: 900px) {
  .embleme { aspect-ratio: 4 / 3; }
  .embleme__picto { width: 240px; height: 240px; stroke-width: 0.315; } /* 240 px -> 1,18 px */
}


@keyframes picto-tracer { to { stroke-dashoffset: 0; } }
@keyframes picto-reflet {
  0%   { opacity: 0;    transform: translateX(-30px); }
  30%  { opacity: 0.55; }
  100% { opacity: 0;    transform: translateX(34px); }
}
/* ---- pictogrammes : fin du bloc ---- */

/* >>> nos conseils */
/* La rubrique éditoriale : la liste par thème et le gabarit d'article.
   Rien de neuf dans le vocabulaire visuel : une carte y est une surface acier
   sur la nuit, coiffée du même filet d'un pixel qui vire à l'or au survol. */

/* les raccourcis vers les rubriques, sous le chapeau de /conseils/ */
.raccourcis { margin-top: var(--e8); }
.raccourcis ul { display: flex; flex-wrap: wrap; gap: var(--e3) var(--e6); list-style: none; margin: 0; padding: 0; }
.raccourcis li { margin: 0; }
.raccourci {
  font-family: var(--titre);
  font-size: var(--t-surtitre);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--texte);
  display: inline-block;
  padding-block: var(--e2);
  border-bottom: 1px solid var(--bordure);
  transition: color var(--duree) ease-out, border-color var(--duree) ease-out;
}
.raccourci:hover { color: var(--or); border-bottom-color: var(--or-sourd); }

/* L'en-tête sticky recouvrirait le titre visé par une ancre. */
.bande[id], .article > h2 { scroll-margin-top: 96px; }

/* l'en-tête d'une rubrique */
.rubrique__tete { display: flex; align-items: flex-start; gap: var(--e6); margin-bottom: var(--e12); }
.rubrique__picto { width: 64px; height: 64px; flex: none; }
.rubrique__tete h2 { margin-bottom: var(--e4); }
.rubrique__tete .filet { margin-bottom: var(--e4); }
.rubrique__lien { margin: var(--e8) 0 0; }

/* la carte d'un conseil */
.notes { list-style: none; display: grid; gap: var(--e6); margin: 0; padding: 0; }
@media (min-width: 700px)  { .notes { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1080px) { .notes { grid-template-columns: repeat(3, 1fr); } }
.notes li { margin: 0; }
.note {
  position: relative;
  height: 100%;
  display: flex; flex-direction: column;
  background: var(--acier);
  border: 1px solid var(--bordure);
  border-top-width: 2px;
  padding: var(--e6);
  transition: border-top-color var(--duree) ease-out, background-color var(--duree) ease-out;
}
.note:hover { border-top-color: var(--or); background: var(--acier-clair); }
.note h3 { font-size: 1rem; letter-spacing: 0.09em; line-height: 1.4; margin-bottom: var(--e3); }
.note h3 a { color: inherit; text-decoration: none; transition: color var(--duree) ease-out; }
/* toute la carte devient cliquable, le lien reste le seul élément focalisable */
.note h3 a::after { content: ""; position: absolute; inset: 0; }
.note:hover h3 a { color: var(--or); }
.note p { margin: 0; font-size: var(--t-legende); color: var(--gris); line-height: 1.65; }

/* le fil de retour, au-dessus du titre d'un article */
.surtitre a { color: inherit; text-decoration: none; border-bottom: 1px solid var(--bordure); }
.surtitre a:hover { color: var(--or-clair); border-bottom-color: var(--or-sourd); }
.surtitre span { padding-inline: var(--e1); color: var(--or-sourd); }

/* le corps d'un article : une seule colonne, mesure de lecture tenue */
.article { max-width: 40rem; }
.article > h2 {
  font-size: clamp(1.3125rem, 1.15rem + 0.75vw, 1.75rem);
  letter-spacing: 0.05em;
  line-height: 1.25;
  margin: var(--e16) 0 var(--e4);
  padding-top: var(--e6);
  border-top: 1px solid var(--bordure);
}
.article > h2:first-of-type { margin-top: 0; }
/* Sous 400 px, la feuille coupe les titres à la césure pour qu'un mot très long
   n'élargisse pas le viewport. Un titre de section d'article n'en a pas besoin :
   le plus long mot de la rubrique fait treize signes et tient à 320 px. La
   césure y produisait « DE-VIENT » en capitales interlettrées. */
.article > h2 { hyphens: manual; }
.article ul { list-style: none; padding-left: var(--e6); margin: 0 0 var(--e4); }
.article li { position: relative; }
.article li::before {
  content: ""; position: absolute; left: calc(var(--e6) * -1); top: 0.72em;
  width: 10px; height: 1px; background: var(--or-sourd);
}

/* le sommaire */
.sommaire {
  background: var(--acier);
  border-left: 2px solid var(--or-sourd);
  padding: var(--e6) var(--e8);
  margin-bottom: var(--e16);
}
.sommaire__titre {
  font-family: var(--titre);
  font-size: var(--t-surtitre);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--gris);
  margin-bottom: var(--e4);
}
.sommaire ul { list-style: none; margin: 0; padding: 0; }
.sommaire li { margin-bottom: var(--e2); }
.sommaire li:last-child { margin-bottom: 0; }
.sommaire a {
  color: var(--texte); text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: color var(--duree) ease-out, border-color var(--duree) ease-out;
}
.sommaire a:hover { color: var(--or); border-bottom-color: var(--or-sourd); }

/* Au-delà de 1080 px, le sommaire passe en colonne et suit la lecture. Il reste
   le premier enfant dans le DOM : l'ordre au clavier ne change pas, et sur
   mobile il s'affiche là où on l'attend, au-dessus du texte.
   L'étendue sur toutes les lignes rend le sticky possible : sans elle, la
   cellule fait la hauteur du sommaire et il n'a nulle part où coller.
   Piège : « grid-row: 1 / -1 » ne vaut rien ici, faute de grille explicite en
   lignes. Le -1 retombe sur la ligne 1, le sommaire occupe la seule première
   ligne, il l'étire à sa hauteur et creuse un vide sous le premier titre.
   Une étendue chiffrée crée les lignes implicites qui manquent. */
@media (min-width: 1080px) {
  .article {
    max-width: none;
    display: grid;
    grid-template-columns: minmax(0, 40rem) minmax(200px, 1fr);
    gap: 0 var(--e24);
    align-items: start;
  }
  .article > * { grid-column: 1; }
  .article > .sommaire {
    grid-column: 2; grid-row: 1 / span 200;
    align-self: start; position: sticky; top: 108px;
    margin-bottom: 0;
  }
}

@media (max-width: 599px) {
  /* Un résumé de carte à 15 px se lit mal sur un téléphone : il repasse à 16. */
  .note p { font-size: 1rem; }
  /* Le picto au-dessus : à côté, il décale le chapeau de soixante pixels. */
  .rubrique__tete { display: block; margin-bottom: var(--e8); }
  .rubrique__picto { width: 48px; height: 48px; margin-bottom: var(--e4); }
  .sommaire { padding: var(--e6); }
}
/* <<< fin nos conseils */

/* >>> signature Odratta — ne pas éditer ici, source : ~/.odratta/signature/signature.css */
a.odratta-signature{display:inline-flex;align-items:baseline;gap:.4em;font:400 .8125rem/1.2 inherit;font-family:inherit;color:inherit;text-decoration:none;text-transform:none;letter-spacing:normal;padding:.45em 0;white-space:nowrap}
a.odratta-signature svg{height:.8em;width:auto;flex:none}
a.odratta-signature:hover,a.odratta-signature:focus-visible{text-decoration:underline;text-underline-offset:.3em}
a.odratta-signature:focus-visible{outline:2px solid currentColor;outline-offset:4px;border-radius:3px;text-decoration:none}
/* <<< fin signature Odratta */
.pied__bas a.odratta-signature { color: var(--gris); }

/* >>> zone d’intervention : la carte, la liste des communes, le pied */
/* Les communes de la zone, posées sur le contour du département. Discrètes :
   c'est Challans que l'œil doit trouver d'abord. */
.carte-lieu .commune { fill: var(--or-sourd); }

/* La liste par secteur. Quatre colonnes sur grand écran, deux sur tablette,
   une sur téléphone : une colonne de vingt-trois noms serait un mur. */
.communes { display: grid; gap: var(--e8); }
@media (min-width: 620px)  { .communes { grid-template-columns: repeat(2, 1fr); gap: var(--e8) var(--e6); } }
@media (min-width: 1000px) { .communes { grid-template-columns: repeat(4, 1fr); } }
.communes h3 {
  font-size: var(--t-surtitre);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--or);
  margin-bottom: var(--e4);
  padding-bottom: var(--e3);
  border-bottom: 1px solid var(--bordure);
  line-height: 1.45;
}
/* Deux lignes réservées au titre : « Vers le bocage et la Vie » en tient une,
   les trois autres en tiennent deux, et la quatrième colonne démarrait plus
   haut que ses voisines. Seulement quand les colonnes sont côte à côte. */
@media (min-width: 620px) { .communes h3 { min-height: calc(2 * 1.45em + var(--e3)); } }
.communes__liste { list-style: none; padding: 0; margin: 0; }
.communes__liste li { margin: 0 0 var(--e3); line-height: 1.4; }
.communes__liste span { margin-left: 0.4em; font-size: var(--t-legende); color: var(--gris); }
.communes__note { margin-top: var(--e8); }

.pied__zone { margin-bottom: var(--e8); }
/* <<< fin zone d’intervention */


/* --------------------------------------------------------------- galerie */
/* Page Réalisations, ajoutée le 27/08/2026 avec les photos de chantier du client.
   Un rapport 4/3 imposé à toutes les vignettes : les photos arrivent en portrait
   comme en paysage, et une grille aux hauteurs inégales fait désordre là où le
   reste du site est réglé au pixel. object-fit recadre au centre. */
.galerie {
  list-style: none;
  padding: 0;
  margin: var(--e12) 0 0;
  display: grid;
  gap: var(--e4);
  grid-template-columns: 1fr;
}
/* Deux colonnes dès 380 px : en une seule, les quarante vignettes donnaient une
   page de 16 500 px sur téléphone, mesurée en ligne. Personne ne descend ça.
   Sous 380 px la vignette tomberait à 140 px de large : on repasse à une colonne. */
@media (min-width: 380px)  { .galerie { grid-template-columns: repeat(2, 1fr); gap: var(--e2); } }
@media (min-width: 700px)  { .galerie { grid-template-columns: repeat(2, 1fr); gap: var(--e4); } }
@media (min-width: 1100px) { .galerie { grid-template-columns: repeat(3, 1fr); } }
.galerie li { margin: 0; }
.galerie__image {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  /* le fond porte pendant le chargement : sans lui, un rectangle blanc clignote
     sur la nuit, et ça se voit sur une page qui porte quarante vignettes */
  background: var(--acier);
}
/* <<< fin galerie */


/* >>> barre large (27/08/2026)
   Huit onglets tiennent dans la barre, pas dans un conteneur de 1200 px.
   Mesuré au navigateur, à 1440 px : logo 184 + nav 968 + bouton 220 + deux gaps
   de 24 = 1420 px pour 1152 px utiles. Le document partait à 1564 px, soit
   124 px de débordement — et un débordement élargit le viewport, donc rapetisse
   toute la page, sans que rien ne le signale.

   Trois gestes, dans cet ordre d'importance : la barre déborde du gabarit de
   texte (une navigation n'a pas à tenir dans la largeur d'un paragraphe), les
   écarts se resserrent, le logo perd 34 px. Le seuil du menu déroulant monte
   de 1360 à 1400 px en conséquence.

   ⚠️ Ces valeurs se REMESURENT à chaque onglet ajouté ou renommé :
   python3 /private/tmp/.../mesurer-entete.py, recopié dans LIVRAISON.md. */
@media (min-width: 1400px) {
  .entete .contenu { max-width: 1480px; }
  .entete__interieur { gap: var(--e4); }
  .entete__logo img { width: 150px; height: 63px; }
  .nav__liste { gap: var(--e4); }
  .nav__lien { letter-spacing: 0.11em; }
}
/* <<< fin barre large */


/* =========================================================================
   REFONTE VISUELLE DU 27/08/2026 — LA MATIÈRE, LE MOUVEMENT
   Ce qui suit vient après tout le reste et ne remplace rien : la feuille des
   25 et 27 août tient toujours, on lui ajoute une couche. Chaque bloc dit ce
   qu'il fait et pourquoi il coûte ce qu'il coûte.
   ========================================================================= */

/* ------------------------------------------------------ le fond d'atelier */
/* Deux lampes d'or très diffuses, fixes, et un grain. Un aplat de nuit sur
   2 000 px de haut se lit comme un fond de gabarit ; une lumière posée derrière
   lui donne une profondeur, et le grain empêche le dégradé de faire des bandes
   sur un écran 8 bits.

   Le grain a d'abord été un feTurbulence SVG en data-uri, puis une tuile PNG
   de 64 px. Le motif du remplacement N'EST PAS le LCP : mesuré le 27/08/2026
   sur l'accueil, à profil de navigateur neuf, en Slow 4G et CPU ÷ 4, les trois
   variantes rendent 1 304 ms (SVG), 1 304 ms (PNG) et 1 296 ms (sans grain).
   Le grain ne coûte rien au premier rendu, quelle que soit sa forme.

   ⚠️ Piège de mesure payé ici : une première série donnait 1 256 ms avec le SVG
   contre 800 ms sans, et concluait à 456 ms de surcoût. C'était un artefact de
   cache — la mesure « avec » partait d'un profil Chrome neuf, la mesure « sans »
   réutilisait le profil déjà chaud. **Une comparaison de LCP n'a de sens qu'à
   état de cache identique**, donc profil supprimé avant chaque essai.

   Ce qui a été gardé de l'épisode : la tuile PNG reste préférable au filtre SVG,
   parce qu'un feTurbulence est recalculé à chaque PEINTURE, pas seulement au
   premier rendu — un fond fixe repeint au défilement le paie en continu, là où
   une tuile n'est qu'un blit. Le premier rendu ne le voit pas, le défilement si.

   Coût des deux lampes : deux pseudo-éléments sur <body>, peints une fois,
   jamais repeints (position: fixed, pointer-events: none, aucune animation).
   Ni l'un ni l'autre ne fait une requête de plus. */
/* ⚠️ <body> doit rester TRANSPARENT. Un pseudo-élément en z-index négatif se
   peint derrière le contenu mais devant le fond du canvas — pas devant l'aplat
   de son propre parent. Un `background` sur body effacerait les deux lampes
   sans qu'aucune règle ne paraisse fautive. La nuit reste posée sur <html>. */
body { position: relative; background: transparent; }
body::before {
  content: "";
  position: fixed; inset: 0;
  z-index: -2;
  pointer-events: none;
  background:
    radial-gradient(60% 42% at 82% 8%,  rgba(212,163,89,.055) 0%, transparent 62%),
    radial-gradient(52% 40% at 8%  78%, rgba(212,163,89,.038) 0%, transparent 66%);
}
body::after {
  content: "";
  position: fixed; inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: .13;
  background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAQAAAAAYLlVAAAUO0lEQVR42iXS8YejCaLu8e9T73oJLy8hhFwhhBDqyBVCCFlFHXXVqqtWHXX0qqNWr161evTq1avHjGkzeszoMW3ajtOmTJk2bdsWbcsWZcspW7ZMUU4IIW4IIYQQQgghbng994f7+Rs+ImLXQ1LUONOIBjGXPGHqjIak3WGihcekdI8bYi+YcMCt6sy8o7bPmbDLgX7uqiak6VIn8UITJ2wAXepc6nsmfOg5oR5z5zsCXuh35FmwJcqse0GXXU51jyzvnFPXKWVpse93KnmpCSm+4UPvklPH1/xN/+qV0pTAdyQc8lbwkDFLz9nlQx7Q0sBzbTAAD7VLyn2V3VLoDkVW7OulM5rLD5VlypRzl9lgQKh33mGshZcKyLlPjr62PCSlx/yOqVNakWfqoirukWampYf8F/9bKz9Vn3Mf6S0f+VIzD9nkLS/oMWGDP5BSjYAO6+6p5A731zTyW94A9zRUpB4t/kxJKwbUWfmhntDn0Hl1tO3/cNafABFZP6LPBUWy6nlCmd9r4SZT3hDpNQmnmnpXERO26NCjqQF/4x+e0yNylpg7arTlJ/rKOWX9ia64pghck3OZx/ySDVWZuk1DX5LQZEHKGWKudegzyhoSkfGN0gxd0JIlBxSd8EqbntFVlizXLGkwYEKThRMNqXFnSDRm36s1zVyiSFlTBwzdpu0codqckuLGA0+0xx1pQneJaJPWGwq+ZU/XLjBnRc77HLDDitgBmzrVF76kx5QbGt53jhu6JAy8YEBMiykz7RjyzNZ4rwkB+/6QlNGcpu4TcaCEGc/1RmM/46ELXinnrrNqUeVOfd2y1NA5LlXhDVVesuEDAv8LFX/FAQO+NnzAawXkCGh6pRlTx07YYwna8zvSa4Qs2OK1Ak5Vd4rExy4aXuuBLmnQUcQHzPS9F8pp5AIjpZwwc8EDrlwgRZV3bPmMAXPtus+QmJJ+zRds61Nv+sjbrmjkIjF5TR0ILrlSRvk1wwY9w1Qz99hnpTlZjUg79qWHHHlKxJyvqHlAnltPnWflWDvK8oAmGWJnNKXBjIU/VY6vdaaAJUNXecVEf1SPlSOtVOPMka544sgHlP1qjYQGM3qkeKiVrhjxVN96wT21VNaGvwJN9Qlj3bIyyhOqqyMe+M6BlqT5lhkdVoSk1ebfuOEl1yxd1J2GzNXykYe6Jcelu3yj2InbGuhbtyiuUeWWHHte0qPgjIf+nKWu3fIdaWeJtcfKd24w0YHynqjkBz6hTYssJ7zyBteU6GmuARENB7SdIs0DntDxgftKlHGXHuss9LH3VVbdW95XX+EabRdUZErImLJ6CpSQIVJCTFHvOPSSuVDgRyROk2dfc71QV3klxNQ1Jas7Nki88B2vqJFV4hI3rlPRQg2/Y1MVavRoeq4pVaMR6y64uqYqIedktGTEhHskHJD3ynPGhAQaMfUTElr03WehPq997VPqFAwhQ8aaOO0ZS7rsUNZ7Muzxhhn/kwVnbAqPHeqWB8pSoM5LFVxQRSO1IXJIgV3H3Pd3ZCkCKdJ8QZ0tbxF7i5hdF90gImCPP1Pzrh+44j2nifkTWT92BhxR9vcO+NRFN5zxT0CZAruusE2OmG2+8AYhUCD0Hn+SH9BipMhVXXhDXW9p6o4Cr+uabS9YkNBhm3NCNb2j35Lzfb32C/3OTU1cps+IKhlG5Njnc6W5I0WZuR/owjMt6fARbzlyR4FPtelLHdFiCh7/TCOavvKWYnd1Q1aRryiS0oZvmZNol8/J+wwU0dcz/uln9B0zdaCUh0p5qho9YrcU+VpjZ7XtGi8V6iWBVh5RYqofecmI+8q6p5pjShSI6K4x8FAljnmmbdYJKdFUl00u+IG5OoxJvEusFAG7xPybIoXcZ0jTLUrOUPSFh/6EMkda0KTARBek+M5Tz9njkWK94ef06frOQ7Vd15XGnOqcjhzxUF+y6Z4qzmjmidqGKiv6rLRBj6p7ij0jYaUmWY7J+YBTZVh4RlNFPvYBOW3S81u1HKnO0Js6cZUNTd0mYkBKVQbc48wVlWk7rWMXlFrTUsd840Blh9zR0zZFhSqqqIZSLAid1dceM1aWnFe+ZJOppsTOe51YZ75zVjFv3PGdIEveK/ZZ+f+qr3MG9DXWE0Xc0vaJ5+r6HXleu6wOGfmBrr2tnhMN2PepdrzUqQ/V4YV/pcd+pbIzjBTR8deq+l+AUAsiMp6QU5cSC8fcI9A7T9igp4VTmlOjwLVDYnU9Z1ctr5QDZl4x1wY9UpTX+I6Jptyo4DkprfOajtO68JJfUvCMshdccEiaqn7lf9eG8mSoEtKgSoodEjKM+ZIUiUq0tGSkpu9zS4ct7bOkokA3VCiQUPOQrArGm3R9saYL8ixc5459zin5IyK2PGHiEkO9ZKC0/qT3nHjoQ6V863X6njLzKQERc0/JEhNzwiOvK+GRa54qdJp1f8UNCThw7BsVXfUxNbVpqkHN6O/iv7jwsapMPOQJr2go4sopUsqxcsCKQB0CAv9JZ+5r4J/4DZEmDrXPtRcUKXGu0Ed8pibvnWFdebrOUNQ5eS/VZ+4i68w0cp6UMi5yrDSYNV9wQ5rEm9znjlhTFk6oa50MU60009KHpB3qK/qa8ZCvCJl7i5lzjCkq0FulPdGQyBk/1IYGXBl6es8DslSc44kWOqfolWqCtlLkXGfIao2sR6qy0KVm6mmPknuKde6eNx0y9MIJp06x4Slb/MgpdeW00lA7fOmFtnzlovta50ppjrVD2Y/IqMqYAm+d1kBHXvobN9VV6DYjhrzWkpiCjnBI2s9ddo2IhgsOHJIi4+c0CH3PT5zzvo9oUnKNIxrsEjrnvznjXZfYd5YCsX9wnT0i5wm8zk+k/SOBm2QIHfivxBzyg4v8RIWH1Il8QNV1ucKAUEdeMFPgkLeUNOG520y5UtUTTb2uNEv3VXFab2gAcOuMXvA5AQMeOa2+V7okcaL73NEmcJYcLXJasMPKp0qTMPM6Swra4fcE7PhKHHFM2g0NvdQh12RJuUJBY39AwLpGXugbf05JOV9pQc0FLlVxREWJMzrj2g80pOOYPnn2dOy8Gj4hrSz3fEdOx8ypuk9eVc68y1ih56R1xe7P6LHpGTv8ljwnXnLDpq6cocM66xobAs41dcO3LGk40bknFHTEfzhLwY8I9S1Zp6lqBVy4omvfp6YFoa/UduglNZbKUKTlpVJu+5G64LyWa144UFNX/gt1p5nqqZYeaeiqllr4jhiYkOJSBUouMaCuomc+dYEec92qzcqbWjB3iSppZt7kcwK2WJJyJLRJRjNqbAC7jrSrG99wRhl+xkC4qyb/DuyyR58NRl5p6Ym+0zklEnZ8rgED4VsSLkix0AaQMl5QVKRzGmqzJPF3vKRLoBJdd2kTe8lCsZuqsyTQrcu+1VNlfK1LQpFxXZcU6ZNj6h/5FQ0Sxe4zoEQoGLD0OjE9RX6kN050SMKxJ1Q1o+G+Ei+UYcmM0GPBLm8JfY+htj3Qkvc0yPpcEzY8JaSoMzYZMnW8xo5WpOm7SoNP9VIPmGrBoYqgFBkqpByqpAILp9R3WTM+5w0rNcnQ40JF0izJs/TQXSI2eOu6AwKOuFDFRV645ZZyTrunica68pbb7rmkRI5VcsRMCwJmPPArNrnmn3zGioGe+GN2uGFLr/2csd47ryJZ5/ijXviCIUtN+Ds3/pID3TmnJnk6nFN1yClZNpio6yo9cqpzRY8jv6WohjO0SUSNkUPhsR6TY4sr3zBVgann3GnbSyJ1qXPtmV7wzm3BPgEZlj6lTE5j7oh8qNfkGZH4nt6zzdK3mlNyTTPn9JoKZd8qdKKH7uitSzzlQi34MxUy3vZzB96gQs4BD5ziqXPec4V9AoeUHPqAHfLU2eMvLjkkT92f8ID7xD50xqFDvibtr73nmNCxv/F3lLxDiYfe4q/e8CNMzTWX/RFHTjm9xsfMXNEFxzRVJHSof3hEhQp57TA3REp7pjSn7nnihGufqKifKNIlT5sOBSbaIKO/+RlzukyISKugYy6NrsjyhqpfKsMJ/8MZ+gx064SqCmueu6rIkX7g0AuPlPr/I3xCi19rWx1HLCkSa4smRQ3IMPaK/0WBQBf0wF0GblPnt4INzrWrkJIXTqutAXnnqeu9Cj4nIqNr7SjHjfoa017TNnMWqvkddZ2R8qf6uSJGuqPijF8DS47Ud+grvSEm5aV6yvm5r1nngk2WHGkHdO4GMS3t+swBWSYqUXLVD3XKyPf8ji3tUffKV84QMCHh/6z5TgmJc9zpnBwTfeiVW9QJ2FOBNGNqvCNgj4gUE0KqlHirpf7CmCINhnrPNRkizl0j8rkyJFwo5ZFLCvSKew40VYq+l2zpiClLcECWX64pQ9kDWox5423dY0JOBYrU+Iw5VX+kS29SYZOIRIlnfOIJW/7Yx+TBXfZYsqTvRAkpByoYhaxcp6wOT2gyI+YtC1Xo8p5rfaKRn+seU6fXWPpaZW0r8VCvnKZI3RXOGFN3wDVz/skFM/1ciQMWWucPWjHWE70j7SlzQldJq0TgLNfa944GfMGWrvWOOs8YOsP3LP3QVyw9Js9r/5WO37NDKB65rZCxFxQ1YegdTbkhR40pHSrMGDurBqesE9Ajw9Lfc6y0z7TFkIFzmjpmwaESbj3SD/5KQ4/Jkqjvx4wYqcXf+dJDNbxkopjEKc0peLrGt2px54XSVCmy0oCxD930uRcOKLHLISNSTvm5237qCQf8Som7+pSuC15q4ppS+kKf+ZwMu7zUHYli5npMzI3ONPWRf+++mlwCWwyZqciSoVprTvu//ZF+9IJvfcseoRcs9J48VUqc0OaAhDst9DsVecZ997Ttnsq8Aj0m5U3dsuTckSIizhiwInRWKw8pMHfeJbrkqXPKipISDwm4doWu02uq83Pd8YE+1QE13zAgxT5FJspq5pClbym64KpT3Cfhhlta3OfOYxb8lgynzjN0S3sOyDFi4HUStnyoCw4VE9LhTvd1wwZlnXmoLHMf8c57you0aySas2SHE3CNS8r0te0b7TGm4LY61OgSM+QFiSHSH8iRdlqRb4mUZuos68zVouq+IAJPSPSfDvULKg7U9Bt9ypgrQqe16Q+oMFN+zQ2umLNJ2nfUqWpFTI4f6avGa66cIiTtjlfO0OAx7/VHfeXnzI2Kvua+YnIuaaiMIKBLj9AjDoQ2+YBnHDoidI9H/j05Yj7SLedCicbOymk1HTDkCcds8yU1zek4T0PviF0go1uvK+UFMd/wUhNn9YYsQ5oOCHRHQtYjSho6r4eMeA9kKBiuyChiSM7rxAS8JtR/+xfkKOi9v9CJkf/Cb9ilS6Ss58rRIvEDnbiiATvu6cJ5Krp0SJqEpZaEXmrDCQ1dMWboDeaqcu6BYh7S9ZiFZg5JE6rjB3rvhFAPeeZ1ZbjlIcfk2PW3JArW9BtibStN1bfcsmTKfd46YUDgqQocqag77ythohITZ1lo4bEOOGPsBZugpWc0FXrOletaUHSkpqY0qCtFkZJCv/UWBdqUfeF7Tjwgokq85gIVzlzmnHUiHpNhTJkybcY6dpcv3WTKlAkPOSRPigI7iv0hXRYEvlWWjCbMyBG4zY0D3SnlnjOEpAyHKjivQHPm5KlrrDeMKbOlGYU1bavvuXpap6RN/4bIb3RBVv9g05tMnWLgiAeOdM179VVwkRQwIu+Z7ulrL+i64Rl7FHika2o+oE+JRK+94JLP2CRx3UU6nrvrx87oL/R4yzafiJoTPfEHrIiV9pgZVerk+VILb6nHwhkCZdwl0YRPufVCaW/rW+fU8goIdJ+Ic0YOWWddr1xgxgs+1tLP6eraiQrMmHupLImLunBe932hnC/W3FffZ6oopUc80VJPlNEFFWKHmnpAXX3WvaECcwLecl8DD/mcPncsVFRD23TJu0pROWJ9S04haU1V8UopnTOn4K4nXuo71vmeTbb4jnf8wBlPxDp4AoRAjg5VzVkQMnGRp/q180q5qD64xDUpUNabOiFPiqbPyCmi4iFLrhQxoeImZ4Sa8tTPtEXdb+irQI6sB9zjVisPQDMf6JbGGgPXyZMQUaDNU/WZOeU8ddC33GNJR7EbTnFFVbHG7uq9N4jAY2L63mOgd9S1Sd5fOOBMY5Y85yURFyzpKeW6Z+6oS4eVewqZOsVLdx2IklGfgJqrGnHuHXVd0g4tbtzgUL9woE36rDwmo5mXCgiJvccZY/JsccwGLe6rw5yFJ0o51piY2OucUaKiQ/9CETEHblFjzkJpX4L2/H6NPR6y6/92nSuu2WKDbQ04p8JcKX7Bc7Y8osqIisbO6mu2iVior09UVE7vlNGV0lqSYeocC/9VVWqO6CunbcYa8IwdVp67RYkTnahHlwFDn6iz5mN9RksXnOiAHS71ihNvuOWW12kr5SELjVmxrh2/0JCpb71Jzmk/c+TI+4Zd0j5ziT+rrJL6RM4T+yePmeqAEbfc46lgQJ9NypQYKU1GFWLxlAEzj/Tcl3rDnq+17URp92jqWy+UcMA1E/7hP9BVkwl1d9Ql53XutHBDC/peZ5sThpQVeqktup7TUexHmvCOCl2atF1W6A4lEl2QpeZz0nKaQ97psUe8pqp7fOhAWz7XHteekiPRtidakHWKSK9cYUyWlZq+pU/AAyXukNG279RiQUzoSFN6rhAJt1Sg78dqe58VJyoSM3KiGWnfKf4ZGVYsyfClttzmpfc0Y1cBp+xzyC3v6apDQJZtXbHFjf7THcVuaO45Rb1niz4Zzul7ocAz5mSYkdGAkJBND9SkxaFmHmjhczLM2adOiwxHIs+UIlPPCVXhln1CXyniIee03ORKVW5d1iF3fOo3tKjoygMFVL2ptzzimKkr6hIDfTZcVtXH5DSk5DTXWndXCz/gWh2yLN2gpxwjzxQy/39JKb+V9Gk2KAAAAABJRU5ErkJggg==");
  background-repeat: repeat;
}
/* Les bandes doivent rester au-dessus du fond, sinon leur aplat le recouvre. */
.bande, .hero, .pied, .bande--photo { position: relative; }
/* ⚠️ .entete et .panneau NE SONT PLUS de cette liste : elle écrasait
   « position: sticky » de la barre et « position: fixed; inset: 0 » du
   panneau, qui retombait dans le flux sous la barre et dont le bas
   devenait inatteignable (body.fige interdit de défiler). Leurs z-index
   (20 et 50) les tiennent déjà au-dessus du grain de fond. */
/* … et laisser voir la lumière : les deux fonds de bande deviennent des voiles. */
.bande--lin   { background: rgba(18,24,32,.72); }
.bande--blanc { background: rgba(13,18,24,.78); }

/* --------------------------------------------------- l'en-tête au défilement */
/* Passé le hero, la barre se resserre et se voile. C'est le seul endroit du
   site où un backdrop-filter est employé : sur 84 px de haut il ne coûte rien,
   et il donne au verre de la barre la même matière qu'à une verrière.
   La hauteur ne change PAS : une barre qui rétrécit décale tout ce qui suit. */
.entete {
  transition: background-color 320ms ease-out, border-color 320ms ease-out;
}
.entete--posee {
  background: rgba(13,18,24,.86);
  border-bottom-color: var(--or-sourd);
}
@supports (backdrop-filter: blur(1px)) {
  .entete--posee { background: rgba(13,18,24,.62); backdrop-filter: blur(16px) saturate(1.4); }
}

/* -------------------------------------------------------- le reflet d'un bouton */
/* Un bouton en or est une pièce de métal : au survol, une lumière le balaie.
   Le reflet est un dégradé en translation, sur le compositeur, et il est coupé
   par overflow — il ne déborde jamais du bouton et ne décale rien. */
.bouton { position: relative; overflow: hidden; isolation: isolate; }
.bouton > * { position: relative; z-index: 1; }
.bouton::before {
  content: "";
  position: absolute; top: 0; bottom: 0; left: -60%;
  width: 45%;
  z-index: 0;
  background: linear-gradient(100deg, transparent, rgba(255,255,255,.32), transparent);
  transform: translateX(0);
  opacity: 0;
}
@media (prefers-reduced-motion: no-preference) {
  .bouton:hover::before, .bouton:focus-visible::before {
    opacity: 1;
    transition: transform 780ms var(--courbe), opacity 120ms linear;
    transform: translateX(360%);
  }
}
/* Sur un bouton clair, un reflet blanc ne se voit pas : il passe à l'or. */
.bouton--blanc::before, .bouton--clair:hover::before {
  background: linear-gradient(100deg, transparent, rgba(212,163,89,.42), transparent);
}

/* ------------------------------------------------- la photo pleine largeur */
/* Les photos bord à bord des pages d'ouvrage portent la trame en surimpression,
   très basse, et un léger agrandissement au défilement là où le navigateur sait
   le faire sans JavaScript. */
.bande--photo { overflow: hidden; }
.bande--photo::before {
  content: "";
  position: absolute; inset: 0;
  z-index: 1;
  pointer-events: none;
  background-image: repeating-linear-gradient(90deg,
    rgba(212,163,89,.16) 0 1px, transparent 1px 16.6666%);
}
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .bande--photo img {
      animation: photo-respire linear both;
      animation-timeline: view();
      animation-range: entry 0% exit 100%;
    }
    @keyframes photo-respire {
      from { transform: scale(1.09) translateY(-1.4%); }
      to   { transform: scale(1.09) translateY(1.4%); }
    }
  }
}

/* --------------------------------------------------------------- les repères */
/* Les quatre chiffres du client. Ils comptent depuis zéro quand ils entrent à
   l'écran — le script écrit le nombre dans un <span> dédié et laisse l'unité
   tranquille, sinon « 400 m² » perdrait son unité pendant le décompte.
   Sans script, le nombre final est déjà dans le HTML : rien ne dépend de lui. */
.reperes li { position: relative; overflow: hidden; }
.reperes li::after {
  content: "";
  position: absolute; left: 0; right: 0; bottom: 0;
  height: 1px;
  background: var(--or);
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform 700ms var(--courbe);
}
.js-anim .anim.vu .reperes li::after { transform: scaleX(1); }
.js-anim .anim.vu .reperes li:nth-child(2)::after { transition-delay: 140ms; }
.js-anim .anim.vu .reperes li:nth-child(3)::after { transition-delay: 280ms; }
.js-anim .anim.vu .reperes li:nth-child(4)::after { transition-delay: 420ms; }
/* Le chiffre ne doit pas changer de largeur pendant qu'il compte, sinon la
   colonne tremble. Les chiffres tabulaires règlent ça d'une déclaration. */
.reperes b { font-variant-numeric: tabular-nums; }

/* --------------------------------------------------- le titre de l'accueil */
/* Le mot-symbole gagne un cheveu d'or qui se tire sous lui, et la ligne de
   métier entre après. Le h1 lui-même n'est jamais l'élément LCP : c'est la
   photo du hero, préchargée. */
.titre-page h1::after {
  transform: scaleX(0);
  transform-origin: 50% 50%;
  transition: transform 800ms var(--courbe) 420ms;
}
.js-anim .revele.vu::after { transform: scaleX(1); }

/* ------------------------------------------------- les transitions de page */
/* Une page qui se remplace d'un coup casse la continuité d'une visite. Le
   navigateur sait faire le raccord tout seul depuis les View Transitions :
   une déclaration, zéro octet de JavaScript, et rien du tout là où ce n'est
   pas supporté. */
@view-transition { navigation: auto; }
@media (prefers-reduced-motion: no-preference) {
  ::view-transition-old(root) { animation: page-sort 220ms ease-in both; }
  ::view-transition-new(root) { animation: page-entre 420ms var(--courbe) both; }
}
@keyframes page-sort  { to   { opacity: 0; } }
@keyframes page-entre { from { opacity: 0; transform: translateY(14px); } }
@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root), ::view-transition-new(root) { animation: none; }
}

/* ------------------------------------------------------ la galerie qui vit */
/* Sur /realisations/, une vignette s'ouvre au survol au lieu de rester plate.
   Aucun décalage : c'est l'image qui grandit dans son cadre, pas le cadre. */
.galerie li { overflow: hidden; position: relative; background: var(--acier); }
.galerie__image {
  transition: transform 900ms var(--courbe), filter 500ms ease-out;
  filter: saturate(.9) brightness(.86);
}
.galerie li:hover .galerie__image { transform: scale(1.06); filter: saturate(1) brightness(1); }
/* La trame se pose sur la vignette survolée : la photo passe derrière une
   verrière. Deux dégradés, aucun élément de plus dans le HTML — la page en
   porte déjà quarante. */
.galerie li::after {
  content: "";
  position: absolute; inset: 0;
  pointer-events: none;
  opacity: 0;
  transition: opacity 420ms var(--courbe);
  background-image:
    repeating-linear-gradient(90deg, rgba(212,163,89,.34) 0 1px, transparent 1px 25%),
    linear-gradient(rgba(212,163,89,.34), rgba(212,163,89,.34));
  background-repeat: repeat, no-repeat;
  background-size: auto, 100% 1px;
  background-position: 0 0, 0 50%;
}
.galerie li:hover::after { opacity: 1; }

/* La sentinelle de l'en-tête : posée par le script, jamais dans le HTML. Hors
   flux et de largeur nulle, elle ne décale rien ; sa hauteur est la distance à
   parcourir avant que la barre se voile. */
.sentinelle-entete {
  position: absolute; top: 0; left: 0;
  width: 1px; height: 120px;
  pointer-events: none;
}

/* ------------------------------------------------ l'ouverture d'une page */
/* Le haut d'une page intérieure n'a pas de photo : le surtitre, le h1, le
   chapeau et deux numéros posés sur un aplat de nuit. Une trame de verrière
   très basse, prise dans un angle, lui donne le fond que la photo donne à
   l'accueil — sans un octet de plus et sans toucher au HTML des 46 pages.

   `main > .bande:first-child` ne peut pas viser l'accueil : son premier enfant
   est le hero. C'est voulu.

   Le h1 d'une page intérieure est souvent son élément LCP : rien ici ne
   l'anime, ne le décale ni ne le masque. */
main > .bande:first-child { overflow: hidden; }
main > .bande:first-child::before {
  content: "";
  position: absolute; top: 0; right: 0;
  width: min(46%, 620px); height: 100%;
  pointer-events: none;
  background-image:
    repeating-linear-gradient(90deg, rgba(212,163,89,.13) 0 1px, transparent 1px 16.6666%),
    linear-gradient(rgba(212,163,89,.13), rgba(212,163,89,.13));
  background-repeat: repeat, no-repeat;
  background-size: auto, 100% 1px;
  background-position: 0 0, 0 38%;
  -webkit-mask-image: linear-gradient(255deg, #000 0%, rgba(0,0,0,.35) 58%, transparent 92%);
  mask-image: linear-gradient(255deg, #000 0%, rgba(0,0,0,.35) 58%, transparent 92%);
}
/* … et une lampe d'or dans le même angle, pour que le coin ne soit pas noir. */
main > .bande:first-child::after {
  content: "";
  position: absolute; top: -20%; right: -6%;
  width: 44%; height: 150%;
  pointer-events: none;
  background: radial-gradient(closest-side, rgba(212,163,89,.10), transparent 76%);
}
/* Le contenu repasse devant les deux : sans ça, le chapeau se lit à travers. */
main > .bande:first-child > .contenu { position: relative; z-index: 1; }
@media (max-width: 760px) {
  /* Sur téléphone le titre occupe toute la largeur : la trame passerait
     derrière le texte au lieu de rester dans son angle. */
  main > .bande:first-child::before { display: none; }
}

/* ------------------------------------------------------ le bandeau d'appel */
/* Le dernier bloc d'une page est celui qui doit décrocher le téléphone. Il
   était un encart de plus ; il devient une pièce d'acier : trame en fond,
   filet d'or en tête, et le numéro en grand. */
.bande--encre {
  overflow: hidden;
  background: linear-gradient(180deg, var(--acier) 0%, rgba(24,32,42,.72) 100%);
}
.bande--encre::before {
  content: "";
  position: absolute; inset: 0;
  pointer-events: none;
  background-image: repeating-linear-gradient(90deg,
    rgba(212,163,89,.11) 0 1px, transparent 1px 12.5%);
  -webkit-mask-image: linear-gradient(180deg, #000, transparent 78%);
  mask-image: linear-gradient(180deg, #000, transparent 78%);
}
.bande--encre > .contenu { position: relative; z-index: 1; }
.bande--encre h2 { text-wrap: balance; }

/* ------------------------------------------- la trame sur un petit écran */
/* Mesuré à 390 px : sept montants sur 390 px, c'est un montant tous les 56 px,
   et le masque radial qui les efface au centre couvre proportionnellement bien
   moins de surface qu'à 1440. Résultat, la grille traverse le canapé au lieu
   de border la photo. Trois montants au lieu de six, et le trait baisse. */
@media (max-width: 760px) {
  .trame--hero { --trame-pas: 25%; --trame-trait: rgba(212,163,89,.20); }
  .trame--hero .trame__traverses { background-position: 0 18%, 0 66%; }
  .trame--hero span {
    -webkit-mask-image: radial-gradient(ellipse 76% 34% at 50% 42%,
      transparent 0%, rgba(0,0,0,.5) 66%, #000 100%);
    mask-image: radial-gradient(ellipse 76% 34% at 50% 42%,
      transparent 0%, rgba(0,0,0,.5) 66%, #000 100%);
  }
  /* Les trois mentions du pied s'empilaient, et le tiret de séparation, prévu
     pour une ligne, se retrouvait à la verticale entre deux lignes. Une seule
     mention tient le pied d'une photo de téléphone. */
  .hero__pied li:nth-child(n+2) { display: none; }
}

/* -------------------------------------------------------------- le pied */
/* Le pied fermait la page sur un aplat. Il la ferme désormais comme un ouvrage
   se termine : un filet d'or en tête, et le pied d'une verrière derrière les
   trois colonnes. Rien d'animé — on est en bas de page, personne n'attend un
   spectacle, on attend un numéro de téléphone lisible. */
.pied { overflow: hidden; border-top-color: var(--or-sourd); }
.pied::before {
  content: "";
  position: absolute; top: 0; left: 0; right: 0;
  height: 220px;
  pointer-events: none;
  background-image: repeating-linear-gradient(90deg,
    rgba(212,163,89,.10) 0 1px, transparent 1px 12.5%);
  -webkit-mask-image: linear-gradient(180deg, #000, transparent);
  mask-image: linear-gradient(180deg, #000, transparent);
}
.pied > .contenu { position: relative; z-index: 1; }
.pied__logo { transition: opacity var(--duree) ease-out; }
/* Les intitulés de colonne prennent l'or : trois repères dans une page dense. */
.pied h2 { color: var(--or); }

/* ------------------------------------------------- une carte de conseil */
/* La note portait déjà un filet qui virait à l'or au survol. Elle gagne le
   geste des vitrines : la barre du titre s'allonge, la flèche avance. Aucun
   soulèvement, aucune ombre — la carte ne bouge pas de sa case. */
.note { transition: border-top-color var(--duree) ease-out, background-color var(--duree) ease-out; }
.note::after {
  content: "";
  position: absolute; left: 0; bottom: 0;
  height: 1px; width: 0;
  background: var(--or);
  transition: width 520ms var(--courbe);
}
.note:hover::after, .note:focus-within::after { width: 100%; }

/* --------------------------------------------------- la carte de la zone */
/* Les points de commune s'allument l'un après l'autre quand la carte entre à
   l'écran. Ce sont des positions calculées, pas une décoration : elles ne
   changent pas, seule leur arrivée est mise en scène. */
@media (prefers-reduced-motion: no-preference) {
  .js-anim .anim .carte-lieu .point { opacity: 0; }
  .js-anim .anim.vu .carte-lieu .point {
    opacity: 1;
    transition: opacity 520ms var(--courbe);
  }
  .js-anim .anim.vu .carte-lieu .point:nth-of-type(2n)   { transition-delay: 160ms; }
  .js-anim .anim.vu .carte-lieu .point:nth-of-type(3n)   { transition-delay: 320ms; }
  .js-anim .anim.vu .carte-lieu .point:nth-of-type(5n)   { transition-delay: 480ms; }
}

/* ------------------------------------------- les vitrines au doigt */
/* Sur un écran tactile il n'y a pas de survol : la trame d'une vitrine ne se
   serait jamais construite, et l'effet n'aurait existé que pour ceux qui ont
   une souris — c'est-à-dire la minorité du trafic de ce site. Au doigt, elle
   se construit donc quand la rangée entre à l'écran, une carte après l'autre. */
@media (hover: none) {
  .trame--vitrine { opacity: 1; }
  .js-anim .anim .trame--vitrine { opacity: 0; }
  .js-anim .anim.vu .trame--vitrine { opacity: .85; }
  .js-anim .anim.vu .vitrine .trame__montants  { transform: scaleY(1); }
  .js-anim .anim.vu .vitrine .trame__traverses { transform: scaleX(1); }
  .vitrines li:nth-child(2) .trame--vitrine span { transition-delay: 140ms; }
  .vitrines li:nth-child(3) .trame--vitrine span { transition-delay: 280ms; }
  .vitrines li:nth-child(4) .trame--vitrine span { transition-delay: 420ms; }
  /* Sans survol, la photo ne s'éclaircit jamais non plus : elle part claire. */
  .vitrine__media img { filter: none; }
  .vitrine__voile { opacity: .75; }
}


/* ---- raffinement : début du bloc posé par outils/patch-premium.py ---- */
/* =========================================================================
   LE RAFFINEMENT — 27/08/2026
   Posé APRÈS tout le reste : ce bloc ne modifie aucune règle en amont, il les
   recouvre par la cascade. Le retirer rend exactement la feuille d'avant.
   ========================================================================= */

/* ------------------------------------------------------- 1. les titres */
/* Copperplate n'a qu'une graisse : à 4,25 rem, un titre en capitales occupe
   toute la largeur et se lit comme une enseigne. Trois réglages, ensemble :
   la taille descend, l'interlettrage s'ouvre (une capitale a besoin d'air,
   d'autant plus qu'elle est grande), et la ligne est bornée en signes pour que
   la casse tombe là où on l'a voulue et pas là où le viewport la met. */
:root {
  --t-h1: clamp(1.875rem, 1.22rem + 2.7vw, 3.0625rem);
  --t-h2: clamp(1.5rem, 1.2rem + 1.35vw, 2.125rem);
  --t-h3: clamp(1.125rem, 1.04rem + 0.36vw, 1.375rem);
  --t-chapeau: clamp(1.1875rem, 1.06rem + 0.6vw, 1.4375rem);
  /* Une septième valeur d'espacement, réservée aux bandes des grands écrans. */
  --e40: 160px;
}
h1 {
  letter-spacing: 0.06em;
  line-height: 1.2;
  max-width: 24ch;
  /* `balance` égalise la longueur des lignes, ce qui sur un titre de trois
     lignes en capitales produit une ligne du milieu nettement plus courte que
     les deux autres — l'inverse de l'effet cherché. `pretty` se contente de
     refuser les orphelines, c'est tout ce qu'on lui demande. */
  text-wrap: pretty;
}
/* Pas de borne en signes sur les h2 : « Ce que nous fabriquons » se cassait en
   deux à 24ch, parce que le `ch` de Copperplate est étroit là où ses capitales
   espacées sont larges. `balance` suffit : il ne coupe que ce qui dépasse. */
h2 { letter-spacing: 0.075em; line-height: 1.22; max-width: 30ch; text-wrap: balance; }
h3 { letter-spacing: 0.1em; }

/* Le filet sous un titre : plus long, plus discret. Il ponctue, il ne souligne
   pas. Sa partie or ne fait que le premier tiers — le reste s'éteint. */
.filet {
  background: linear-gradient(90deg, var(--or) 0 72px, var(--bordure) 72px 100%);
}

/* Le surtitre gagne une amorce : un cheveu d'or de 22 px avant le mot. C'est le
   geste éditorial d'une double page de magazine, et il coûte un pseudo-élément. */
.surtitre { letter-spacing: 0.24em; }
.surtitre::before {
  content: "";
  display: inline-block;
  width: 22px; height: 1px;
  background: var(--or-sourd);
  vertical-align: middle;
  margin-right: var(--e3);
  margin-bottom: 0.18em;
}
/* Sauf dans le fil d'Ariane et les listes de conseils, où le surtitre porte des
   liens : une amorce devant un chemin de navigation n'a pas de sens. */
.surtitre:has(a)::before { display: none; }

/* -------------------------------------------------------- 2. l'en-tête */
/* Quatre-vingt-quatre pixels de haut pour huit onglets et un pavé d'or : la
   barre était pleine. Elle monte à 96, le logo avec elle, et le numéro perd son
   aplat. Le seuil de bascule du menu ne change pas — il est mesuré ailleurs. */
@media (min-width: 900px) {
  .entete__interieur { min-height: 96px; gap: var(--e8); }
  .entete__logo img { width: 172px; height: 72px; }
}
/* Le numéro de l'en-tête : contour, pas aplat. Il reste le premier élément
   cliquable de la page, il cesse d'être le plus criard. La classe elle-même est
   changée dans build.py ; ces deux lignes tiennent le cas où elle ne l'est pas. */
.entete__tel .bouton {
  background: transparent;
  color: var(--or);
  border-color: var(--or-sourd);
}
.entete__tel .bouton:hover {
  background: var(--or);
  color: var(--nuit);
  border-color: var(--or);
}

/* --------------------------------------------------------- 3. boutons */
/* Plus haut, plus large, la lettre plus espacée : un bouton de marque, pas un
   bouton d'interface. La transition passe de 200 à 320 ms — au-dessus, un
   bouton traîne ; en dessous, il claque. */
.bouton {
  min-height: 56px;
  padding: var(--e4) var(--e12);
  letter-spacing: 0.2em;
  transition-duration: 320ms;
}
@media (max-width: 599px) { .bouton { min-height: 50px; padding: var(--e3) var(--e6); } }

/* Le lien-flèche gagne la même respiration que les boutons : c'est lui qui
   remplace l'aplat d'or partout où l'aplat était de trop. */
.lien-fleche { letter-spacing: 0.2em; gap: var(--e4); }

/* Les deux appels d'un bloc titre ne se touchent plus — et ils s'alignent sur
   le texte. Ils étaient centrés partout, y compris sur les pages d'ouvrage où
   le titre, le filet et le chapeau sont tous ferrés à gauche : deux boutons au
   milieu sous une colonne alignée à gauche, ça se voit à trois mètres. Seul
   l'accueil, dont le bloc entier est centré, garde le centrage. */
.tels { gap: var(--e4); justify-content: start; }
@media (min-width: 560px) { .tels { gap: var(--e6); align-items: center; } }
.titre-page .tels { justify-content: center; }

/* Le numéro posé à côté d'un bouton, en clair : le second appel d'un bloc titre
   n'a plus besoin d'une boîte pour exister. */
.tel-ligne {
  display: inline-flex; align-items: center; gap: var(--e3);
  min-height: 44px;
  font-family: var(--titre);
  font-size: var(--t-surtitre);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--texte);
  transition: color var(--duree) ease-out;
}
.tel-ligne svg { width: 17px; height: 17px; flex: none; color: var(--or); }
.tel-ligne:hover { color: var(--or); }

/* ------------------------------------------------ 4. le titre d'accueil */
/* Le sous-titre était en capitales d'or, aussi long que le nom au-dessus : deux
   lignes de capitales à la file, dont la seconde en couleur. Il passe en
   Baskervville bas de casse. C'est le seul endroit du site où la police de
   labeur monte à cette taille, et c'est ce contraste qui pose le ton. */
.titre-page .metier {
  font-family: var(--texte-police);
  font-size: 0.5em;
  letter-spacing: 0.005em;
  line-height: 1.4;
  text-transform: none;
  color: var(--texte);
  margin-top: var(--e6);
  /* 40 signes : « L'acier au cœur de votre habitation » tient sur une ligne
     jusqu'en dessous de 700 px, et se casse au bon endroit en dessous. */
  max-width: 40ch;
  margin-inline: auto;
}
.titre-page h1 { max-width: 24ch; margin-inline: auto; }
.titre-page .zone {
  font-size: var(--t-chapeau);
  line-height: 1.6;
  max-width: 40rem;
  margin-bottom: var(--e16);
}
.titre-page h1::after { margin-top: var(--e12); }

/* -------------------------------------------------------- 5. les repères */
/* Quatre cases encadrées deviennent quatre colonnes entre deux filets. Le
   cadre extérieur disparaît, les séparateurs restent : moins de traits pour la
   même lecture, et le chiffre gagne la place que la boîte prenait. */
.reperes {
  background: transparent;
  border: 0;
  border-block: 1px solid var(--bordure);
  gap: 0;
}
.reperes li {
  background: transparent;
  padding: var(--e12) var(--e4);
  border-left: 1px solid var(--bordure);
}
.reperes li:nth-child(2n+1) { border-left: 0; }
.reperes li:nth-child(n+3) { border-top: 1px solid var(--bordure); }
@media (min-width: 900px) {
  .reperes li { border-left: 1px solid var(--bordure); border-top: 0; padding-inline: var(--e6); }
  .reperes li:first-child { border-left: 0; }
  .reperes li:nth-child(2n+1) { border-left: 1px solid var(--bordure); }
  .reperes li:first-child { border-left: 0; }
}
.reperes b {
  font-size: clamp(1.875rem, 1.15rem + 2.6vw, 3rem);
  letter-spacing: 0.02em;
  margin-bottom: var(--e4);
}
.reperes span {
  font-size: 0.6875rem;
  letter-spacing: 0.18em;
  line-height: 1.5;
}
/* Le filet d'or qui se tire sous une colonne à l'apparition. Une fois les
   quatre tirés, ils formaient une barre d'or continue sur toute la largeur —
   plus large que les deux filets gris qui encadrent la bande, donc plus fort
   qu'eux, ce qui est l'inverse de la hiérarchie voulue. Il ne court plus que
   sur le premier tiers de chaque colonne : le geste reste visible, l'or reste
   un accent. */
.reperes li::after {
  height: 1px;
  right: auto;
  width: 34%;
}

/* --------------------------------------------------------- 6. le raccord */
/* La pièce portait cinq montants sur un filet, sur 62 % de la largeur. Sur le
   grain du fond, cet empilement rendait une bande grise granuleuse — un
   artefact, pas un ornement. Il ne reste que le filet, plus long, plus fin,
   éteint à ses deux bouts. Le vocabulaire de la verrière est déjà porté par
   la trame, six fois dans la page ; il n'a pas à l'être ici aussi. */
.raccord { height: 56px; }
/* ⚠️ LE VRAI DÉFAUT ÉTAIT AILLEURS. Le raccord n'a jamais porté de fond : entre
   deux bandes qui, elles, voilent le fond d'atelier à 72 et 78 %, il laissait
   voir le GRAIN À NU sur toute la largeur — une bande grise granuleuse, prise
   pour un ornement raté alors que c'était un trou dans le voile. Il porte
   désormais le dégradé d'un voile à l'autre, et la couture disparaît. */
.raccord { background: linear-gradient(180deg, rgba(18,24,32,.72), rgba(13,18,24,.78)); }
.raccord span {
  background-image: linear-gradient(90deg,
    transparent 0%, var(--or-sourd) 34%, var(--or-sourd) 66%, transparent 100%);
  background-size: 52% 1px;
  background-position: 50% 50%;
}

/* ----------------------------------------------------- 7. les photographies */
/* Les images du site viennent de sources différentes : certaines tirent au
   jaune, d'autres au bleu, les contrastes ne se ressemblent pas. Rien ne trahit
   davantage un site rassemblé à la hâte. Une correction unique les fait tenir
   dans la même lumière — la saturation retombe, le contraste monte d'un poil,
   la luminosité descend pour que le fond nuit ne soit pas percé.
   ⚠️ Elle s'applique aussi au survol des vitrines, sinon la photo saute d'un
   étalonnage à l'autre au passage de la souris. */
.vitrine__media img,
.duo picture img,
.duo > div > img,
.bande--photo img,
.galerie__image img {
  filter: saturate(.86) contrast(1.06) brightness(.97);
}
.vitrine:hover .vitrine__media img,
.vitrine:focus-within .vitrine__media img {
  filter: saturate(.96) contrast(1.04) brightness(1.03);
}
@media (hover: none) {
  .vitrine__media img { filter: saturate(.9) contrast(1.05) brightness(1); }
}
/* Un cheveu autour de chaque photo de contenu : le cadre d'une planche. */
.bande--photo img { border-block: 1px solid var(--bordure); }

/* ------------------------------------------------------------- 8. l'air */
/* Au-delà de 1100 px, la page a de la place à donner. Les bandes la prennent :
   c'est le blanc autour d'un objet qui dit qu'il vaut cher, pas l'objet. */
@media (min-width: 1100px) {
  .bande { padding-block: var(--e40); }
  .bande--serree { padding-block: var(--e32); }
  .bande > .contenu > h2 { margin-bottom: var(--e8); }
}

/* Un bloc de prose seul dans une largeur de 1200 px flotte à gauche sans rien
   qui le tienne. Un cheveu vertical l'ancre au bord du texte, et l'ensemble
   se décale de la largeur du filet — le geste de la colonne de magazine. */
@media (min-width: 900px) {
  .bande--serree .contenu > .prose-large {
    padding-left: var(--e8);
    border-left: 1px solid var(--bordure);
  }
}

/* --------------------------------------------------------- 9. les vitrines */
/* Le nom d'un ouvrage et sa phrase se serrent, le numéro s'éloigne : la carte
   se lit en deux temps au lieu de trois blocs égaux. */
.vitrine__texte { padding-top: var(--e8); }
.vitrine__num { letter-spacing: 0.22em; }
.vitrine h3 { letter-spacing: 0.12em; }
.vitrine__phrase { max-width: 34ch; }

/* ------------------------------------------------------- 10. le pied de page */
/* Trois colonnes de largeurs inégales laissaient un vide sous les coordonnées
   et faisaient descendre la troisième plus bas que les deux autres. Elles
   passent égales, l'écart se resserre, et le soulignement au survol disparaît :
   sur fond nuit, le passage à l'or suffit à dire qu'un lien répond. */
@media (min-width: 760px) {
  .pied__colonnes { grid-template-columns: 1.1fr 1fr 1fr; gap: var(--e12); }
}
.pied { padding-block: var(--e32) var(--e8); }
.pied a:hover { text-decoration: none; color: var(--or); }
.pied__logo { width: 140px; margin-bottom: var(--e8); }
.pied h2 { letter-spacing: 0.22em; margin-bottom: var(--e8); }
.pied li { margin-bottom: var(--e4); }
.pied__zone { margin-bottom: var(--e12); }
/* « Toutes les communes » est un lien posé derrière un <br> : il se collait
   sous la dernière ligne du paragraphe, à l'interligne près, et se lisait comme
   une quatrième ligne de la liste plutôt que comme un lien. */
.pied__zone a {
  display: inline-block;
  margin-top: var(--e4);
  border-bottom: 1px solid var(--bordure);
}
.pied__zone a:hover { border-bottom-color: var(--or-sourd); }

/* ------------------------------------------------------ 11. le hero */
/* Le bouton du hero perd son aplat : sur une photographie, un rectangle d'or
   plein de 200 px de large est la seule chose que l'oeil voit. Le lien-flèche
   blanc dit la même chose et laisse la photo au premier plan. La classe est
   changée dans build.py ; ces règles tiennent la mise en page du lien. */
.hero__bouton { margin-top: var(--e2); }
.hero .lien-fleche { color: var(--blanc); border-bottom-color: rgba(255,255,255,.45); }
.hero .lien-fleche:hover { color: var(--or-clair); border-bottom-color: var(--or); }
/* L'accroche du hero et le mot-symbole se rapprochent : ils forment un bloc. */
.hero__accroche { letter-spacing: 0.3em; }

/* ------------------------------------------- 12. le formulaire et les champs */
/* Un champ de saisie sur fond nuit se lit mieux avec de la hauteur qu'avec un
   contour plus clair : la hauteur ne coûte rien au contraste. */
.champ input, .champ select, .champ textarea { padding-block: var(--e4); }
.champ label { letter-spacing: 0.18em; }

/* ---- raffinement : fin du bloc ---- */

/* >>> patch-section-camion : début — ne pas écrire à l’intérieur */
/* =========================================================================
   LE FOURGON — section « Nous venons jusqu’à vous », accueil
   Posée le 27/08/2026 par `outils/patch-section-camion.py`, à rejouer après
   toute réécriture de cette feuille.

   La photo est une vignette de 424 px de large : tout le parti pris part de là.
   Une colonne portrait étroite, un fondu au lieu d’un cadre, un halo d’or qui
   pose le fourgon dans la nuit plutôt qu’un bord qui souligne ses pixels.
   ========================================================================= */
/* Le halo déborde du cadre, exprès : c'est la section qui le contient, pas la
   figure — sinon il serait rogné et il n'y aurait plus de lueur. Sans ce
   `overflow`, le halo pousse le document à 441 px sur un écran de 390 et
   RAPETISSE la page entière, sans la moindre erreur ni barre de défilement.
   Mesuré le 27/08/2026 : viewport 441 px pour un appareil de 390. */
.camion { overflow: hidden; }

.camion__grille { display: grid; gap: var(--e12); align-items: center; }
@media (min-width: 900px) {
  .camion__grille { grid-template-columns: 1fr minmax(300px, 400px); gap: var(--e24); }
}
.camion__texte > p { max-width: var(--prose); }
.camion__texte > .lien-fleche { margin-top: var(--e6); }

.camion__cadre {
  margin: 0;
  justify-self: center;
  width: 100%;
  max-width: 400px;
}

/* La trame et le halo se règlent sur la PHOTO, pas sur la figure : sinon les
   montants descendent en travers de la légende et lui passent dessus.
   Vu à la capture du 27/08/2026, corrigé en sortant la légende du cadre. */
.camion__vue { position: relative; }

/* Le halo. z-index 0 sur le pseudo-élément et 1 sur l’image : un z-index
   NÉGATIF passerait derrière le fond de la section et la lueur disparaîtrait
   sans la moindre erreur — le piège payé le 27/08 sur le hero. */
.camion__vue::before {
  content: "";
  position: absolute;
  inset: -14% -20% -10%;
  background: radial-gradient(58% 48% at 50% 56%, rgba(212, 163, 89, .17), transparent 72%);
  z-index: 0;
  pointer-events: none;
}
.camion__vue picture { position: relative; z-index: 1; }

/* La photo n’a pas de bord : elle se fond dans la nuit par le haut et par le
   bas. C’est ce fondu qui remplace le cadre, et qui fait tenir une vignette
   dans une section de cette taille. */
.camion__cadre img {
  width: 100%;
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 17%, #000 87%, transparent 100%);
  mask-image: linear-gradient(180deg, transparent 0%, #000 17%, #000 87%, transparent 100%);
}

.camion__cadre figcaption {
  margin-top: var(--e4);
  color: var(--gris);
  font-size: var(--t-legende);
  line-height: 1.5;
  text-align: center;
}

/* La trame derrière le fourgon : même signature que partout, un pas plus large
   parce que la colonne est étroite. */
.trame--camion { --trame-pas: 20%; }
.trame--camion .trame__traverses { background-position: 0 28%, 0 64%; }

/* Ce qui entre à l’écran. Tout est suspendu à .js-anim et à
   prefers-reduced-motion : sans script ni mouvement, la section est complète
   et immobile dès le premier rendu. */
@media (prefers-reduced-motion: no-preference) {
  .js-anim .anim .trame--camion .trame__montants { transform: scaleY(0); }
  .js-anim .anim.vu .trame--camion .trame__montants {
    transform: scaleY(1);
    transition: transform var(--duree-trace) var(--courbe) 180ms;
  }
  .js-anim .anim .trame--camion .trame__traverses { transform: scaleX(0); }
  .js-anim .anim.vu .trame--camion .trame__traverses {
    transform: scaleX(1);
    transition: transform 820ms var(--courbe) 620ms;
  }

  /* le filet du titre n’est pas enfant direct de .anim ici : il se tire quand même */
  .js-anim .anim .camion__texte > .filet { transform: scaleX(0); transform-origin: 0 50%; }
  .js-anim .anim.vu .camion__texte > .filet {
    transform: scaleX(1);
    transition: transform var(--duree-lente) var(--courbe) 220ms;
  }

  /* la photo se découvre par le bas, comme partout ailleurs sur le site */
  .js-anim .anim .camion__cadre img { clip-path: inset(0 0 100% 0); }
  .js-anim .anim.vu .camion__cadre img {
    clip-path: inset(0 0 0 0);
    transition: clip-path 1000ms var(--courbe) 160ms;
  }
}

/* La parallaxe, à la timeline du navigateur : zéro JavaScript, rien à nettoyer.
   Là où `animation-timeline` n’existe pas, le fourgon est simplement fixe. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .camion__cadre picture {
      display: block;
      animation: camion-glisse linear both;
      animation-timeline: view();
      animation-range: entry 10% exit 90%;
    }
    @keyframes camion-glisse {
      from { transform: translateY(22px); }
      to   { transform: translateY(-22px); }
    }
  }
}
/* <<< patch-section-camion : fin */

/* >>> patch-retour-client : début — ne pas écrire à l’intérieur */
/* =========================================================================
   LE RETOUR DU CLIENT — 28/08/2026
   Posé APRÈS tout le reste, y compris le raffinement et la section du fourgon :
   ce bloc ne modifie aucune règle en amont, il les recouvre par la cascade.
   Le retirer rend exactement la feuille d'avant.
   Source : « retour 1.docx », Atelier de la Déco, 27/08/2026 au soir.
   ========================================================================= */

/* ---------------------------------------------- 1. l'interlettrage, resserré
   « le lettrrage est trop espacer » (mail), puis six fois dans le document :
   en haut de l'accueil, au milieu, sur le vitrage, sur le premier paragraphe,
   sur les conseils, « reserer toujours l'espace entre les lettrages ».
   Copperplate est une capitale : elle a besoin d'air, mais l'échelle posée le
   27/08 montait à 0,30 em sur l'accroche du hero — un mot y occupait la place
   de deux. Chaque valeur perd environ un tiers ; les écarts entre les niveaux
   sont conservés, c'est l'échelle entière qui descend d'un cran.
   La barre de navigation n'est PAS touchée : son interlettrage a été calibré
   au pixel contre le débordement à neuf onglets (1 300 / 1 400 / 1 600 px). */
h1 { letter-spacing: 0.04em; }
h2 { letter-spacing: 0.05em; }
h3 { letter-spacing: 0.065em; }
h4 { letter-spacing: 0.07em; }
.surtitre { letter-spacing: 0.15em; }
.hero__accroche { letter-spacing: 0.18em; }
.bouton, .lien-fleche, .tel-ligne, .tel-grand, .evitement { letter-spacing: 0.1em; }
.reperes span, .carte h3, .parcours h3, .questions h3,
.note h3, .champ label, .vitrine h3 { letter-spacing: 0.085em; }
.vitrine__num, .pied h2 { letter-spacing: 0.14em; }

/* ------------------------------------------ 2. le texte, d'un cran plus haut
   « sous titre et paragraphe doivent être pareil » · « De l atelier a votre
   domicile un peu plus gros » · « Titre idem taille plus haut et texte idem
   taille plus haut ».
   Le chapeau tombe sur la valeur du corps : ils ne se distinguent plus que par
   la couleur, ce qu'il demande. Le corps, lui, monte — un serif fin sur fond
   nuit gagne à être servi grand. */
:root {
  --t-corps: clamp(1.125rem, 1.06rem + 0.3vw, 1.25rem);
  --t-chapeau: clamp(1.125rem, 1.06rem + 0.3vw, 1.25rem);
  --t-surtitre: clamp(0.8125rem, 0.77rem + 0.2vw, 0.9375rem);
  --t-h2: clamp(1.5625rem, 1.24rem + 1.5vw, 2.375rem);
}
/* « Premier paragraphe moins d espace et le paraghraphe resserer » : le chapeau
   d'une page d'ouvrage respirait à 1,55 d'interligne, à la taille d'un titre. */
.prose-large > p:first-child,
.chapeau { line-height: 1.5; }
/* ⚠️ Sur l'ACCUEIL, le sous-titre visé par cette phrase n'est pas un `.chapeau` :
   c'est `.titre-page .metier` (« L'acier au cœur de votre habitation »), dimensionné
   en `em` du h1 — donc 24,5 px à 1 440 contre 20 px au paragraphe, et 16,5 px contre
   18,5 px à 500 px de large. Les deux ne sont pas seulement différents : l'écart
   CHANGE DE SENS avec la largeur. Il tombe sur la valeur du corps, et ne se distingue
   plus que par la couleur et l'espace au-dessus — ce que le client demande. */
.titre-page .metier { font-size: var(--t-corps); }

/* ------------------------------------------------ 3. le numéro de téléphone
   « numero un peu plus gros on le voit mal », dit deux fois pour l'accueil puis
   « et ce pour toute les pages du site ». Il était servi à la taille d'un
   surtitre — 13 px — sous chaque titre de page. */
.tel-ligne { font-size: 1.0625rem; letter-spacing: 0.06em; }
.tel-ligne svg { width: 19px; height: 19px; }
/* « Tel plus grand » dans le bandeau d'appel de bas de page. */
.bouton--tel { font-size: 1rem; letter-spacing: 0.06em; }
.bouton--tel svg { width: 20px; height: 20px; }

/* ------------------------- 4. « Nous écrire » devient l'adresse, en dessous
   « nous écrire devient l adresse mail, mais juste au dessus on note nous
   écrire.. » — le libellé reste, il coiffe l'adresse au lieu de la remplacer.
   Le mail est en Baskervville bas de casse : une adresse en capitales espacées
   ne se lit pas, et se recopie encore moins. */
.bandeau__ecrire { margin: 0; text-align: left; }
.bandeau__ecrire .surtitre { margin-bottom: var(--e2); }
.bandeau__mail {
  font-family: var(--texte-police);
  font-size: 1.125rem;
  /* Pas de `color` ici : le bandeau est toujours une bande d'encre, et
     `.bande--encre a:not(.bouton)` l'emporte de toute façon en spécificité.
     L'adresse est donc en or, comme tout lien de cette bande — 8,1:1. */
  text-decoration: none;
  border-bottom: 1px solid var(--or-sourd);
  padding-bottom: 2px;
  word-break: break-word;
}
.bandeau__mail:hover { color: var(--or-clair); border-bottom-color: var(--or); }
@media (min-width: 560px) { .tels--bandeau { align-items: center; } }

/* ------------------------- 4 bis. la zone de chalandise, au pied, plus grande
   « la zone de chalandise doit être plus grande » (28/08/2026). Le bloc était
   servi en `.legende` — 15 px, la taille d'une mention — à côté d'une adresse à
   18,5 px, alors qu'il porte désormais la portée du déplacement. Il prend la
   taille du corps ; le lien « Toutes les communes » garde son air. */
.pied__zone { font-size: var(--t-corps); color: var(--gris); line-height: 1.6; }

/* ------------------------------------------------------- 5. les quatre repères
   « Sous 400m,3, 100, vendee grossir le lettrage » : le chiffre et son libellé. */
.reperes b { font-size: clamp(2rem, 1.4rem + 2.5vw, 3rem); }
.reperes span { font-size: 0.875rem; }

/* --------------------------------------------- 6. les chiffres, droits enfin
   « En pied de page changer la police parce que les numero ne sont pas droit ».
   Ce ne sont pas les numéros qui sont de travers : Baskervville dessine des
   chiffres elzéviriens, qui montent et descendent autour de la ligne. Sur
   « 06 99 32 56 08 » le 9 plonge, le 6 monte, et l'ensemble ondule.
   La fonte servie porte la fonctionnalité OpenType `lnum` (vérifié dans le
   woff2) : les chiffres alignés existent dans le fichier, il suffit de les
   demander. La police ne change pas, la charte non plus.
   Hérité : une seule déclaration redresse tout le site — téléphones, adresse,
   horaires, repères, dates d'actualités, prix éventuels. */
body { font-variant-numeric: lining-nums; }

/* ------------------------------------ 7. la police de titre, enfin libre
   Copperplate sortait de macOS : marque de Heidelberger Druckmaschinen AG,
   sous licence exclusive Linotype, « All rights reserved ». La servir depuis
   adld.fr était une redistribution illicite — pour le client comme pour nous.
   Julius Sans One (SIL OFL) la remplace : capitales fines et géométriques,
   UNE seule graisse comme elle (la charte tient : la hiérarchie se fait par la
   taille, l'interlettrage et la couleur, jamais par le gras), et des chiffres
   DROITS — 0/H = 1,03, 9/H = 1,05, mesuré sur le woff2 servi.
   ⚠️ Le repli ne cite plus aucune police Apple sous licence : Optima et Avenir
   Next ne sont que des noms locaux, jamais téléchargés, et `sans-serif` ferme
   la liste — un serif générique en repli d'une linéale changeait tout le
   caractère de la page sur les machines qui n'ont ni l'une ni l'autre. */
:root { --titre: 'Julius Sans One', 'Optima', 'Avenir Next', sans-serif; }
/* <<< patch-retour-client : fin */

/* >>> patch-menu.py — début */
/* ===================================================== le menu, 28/08/2026 ==
   Le panneau n'est pas une liste de liens posée sur un fond : c'est un écran.
   Il porte sa barre, ses vitrines et son appel, et il s'assemble à l'ouverture
   comme une verrière se monte — la nappe, puis les blocs, en cascade et au
   sélecteur : aucune classe à poser dans les 46 pages, aucun JavaScript.
   Tout est désarmé par prefers-reduced-motion.                             */

/* ------------------------------------------------------- la nappe */
.panneau {
  position: fixed; inset: 0;
  z-index: var(--z-panneau);
  background: var(--nuit-creux);
  color: var(--texte);
  display: flex; flex-direction: column;
  padding: 0;
  overflow-y: auto;
  overscroll-behavior: contain;   /* le doigt ne fait pas défiler la page dessous */
}
/* La trame de verrière — la signature du site — court derrière le panneau.
   En CSS pur : un tracé SVG se décalerait sur une grille étirée. */
.panneau::before {
  content: "";
  position: absolute; inset: 0;
  pointer-events: none;
  opacity: .5;
  background-image:
    linear-gradient(90deg, var(--bordure) 1px, transparent 1px),
    linear-gradient(var(--bordure) 1px, transparent 1px);
  background-size: 33.333% 100%, 100% 210px;
  mask-image: linear-gradient(180deg, rgba(0,0,0,.85), rgba(0,0,0,.12) 62%, transparent);
}
.panneau > * { position: relative; }

/* --------------------------------- la barre du panneau, calée sur la vraie */
.panneau__barre {
  flex: none;
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--e4);
  min-height: 64px;
  padding-inline: var(--marge);
  border-bottom: 1px solid var(--bordure);
}
.panneau__logo { display: block; padding-block: var(--e2); }
.panneau__logo img { width: 112px; height: 47px; object-fit: contain; }
.panneau__fermer {
  flex: none;
  width: 44px; height: 44px;
  background: transparent; border: 1px solid var(--bordure-champ);
  border-radius: 0; color: var(--texte); cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background-color var(--duree) ease-out, color var(--duree) ease-out,
              border-color var(--duree) ease-out;
}
.panneau__fermer:hover { background: var(--or); color: var(--nuit); border-color: var(--or); }
.panneau__fermer svg { width: 20px; height: 20px; }

.panneau__corps {
  flex: 1 1 auto;
  display: flex; flex-direction: column;
  padding: var(--e6) var(--marge) 0;
}
.panneau__nav { flex: 1 1 auto; }

/* --------------------------------------------------------- les intertitres */
.panneau__titre {
  margin: 0 0 var(--e3);
  font-family: var(--titre);
  font-size: var(--t-surtitre);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--or);
  display: flex; align-items: center; gap: var(--e3);
}
.panneau__titre::after {
  content: ""; flex: 1 1 auto; height: 1px;
  background: linear-gradient(90deg, var(--or-sourd), transparent);
}

/* ------------------------------------------- les quatre ouvrages en vitrine */
.panneau__vitrines {
  list-style: none; margin: 0 0 var(--e6); padding: 0;
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--e3);
}
.panneau__vitrines li { margin: 0; }
.vignette {
  display: block; text-decoration: none;
  border: 1px solid var(--bordure);
  background: var(--acier);
  transition: border-color var(--duree) ease-out;
}
.vignette__photo {
  display: block; position: relative;
  aspect-ratio: 3 / 2; overflow: hidden;
  background: var(--acier);   /* la photo arrive au clic : pas de trou blanc */
}
.vignette__img, .vignette__photo picture { display: block; height: 100%; }
.vignette__img {
  width: 100%; height: 100%; object-fit: cover;
  filter: saturate(.85) contrast(1.04);
  transition: transform 520ms cubic-bezier(.22,.61,.36,1), filter var(--duree) ease-out;
}
.vignette__nom {
  display: block;
  padding: var(--e3);
  font-family: var(--titre);
  font-size: 0.9375rem; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--blanc);
  border-top: 1px solid transparent;
  transition: color var(--duree) ease-out, border-color var(--duree) ease-out;
}
.vignette:hover { border-color: var(--or-sourd); }
.vignette:hover .vignette__img { transform: scale(1.06); filter: saturate(1) contrast(1.08); }
.vignette:hover .vignette__nom { color: var(--or); border-top-color: var(--or-sourd); }
.vignette--ici { border-color: var(--or-sourd); }
.vignette--ici .vignette__nom { color: var(--or); }

/* --------------------------------------------------------------- la liste */
.panneau__liste { list-style: none; margin: 0 0 var(--e8); padding: 0; }
.panneau__liste li { margin: 0; border-bottom: 1px solid var(--bordure); }
.panneau__liste li:first-child { border-top: 1px solid var(--bordure); }
.panneau__lien {
  display: flex; align-items: center;
  min-height: 46px; padding: var(--e2) 0;
  font-family: var(--titre);
  font-size: 1.0625rem; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--blanc); text-decoration: none;
  position: relative;
  transition: color var(--duree) ease-out, padding-left var(--duree) ease-out;
}
/* Un cheveu d'or pousse depuis la gauche, il n'apparaît pas : le même geste
   que sous les onglets de la barre. */
.panneau__lien::before {
  content: ""; position: absolute; left: 0; top: 50%;
  width: var(--e4); height: 1px; margin-top: -1px;
  background: var(--or);
  transform: scaleX(0); transform-origin: left;
  transition: transform var(--duree) cubic-bezier(.22,.61,.36,1);
}
.panneau__lien:hover, .panneau__lien[aria-current="page"] { color: var(--or); padding-left: var(--e6); }
.panneau__lien:hover::before, .panneau__lien[aria-current="page"]::before { transform: scaleX(1); }

/* ------------------------------------------ le pied : l'appel reste sous la main */
.panneau__pied {
  position: sticky; bottom: 0;
  margin-inline: calc(var(--marge) * -1);
  padding: var(--e4) var(--marge) var(--e6);
  display: grid; gap: var(--e3);
  background: var(--nuit-creux);
  border-top: 1px solid var(--bordure);
}
.panneau__pied::before {
  content: ""; position: absolute; left: 0; right: 0; top: -56px; height: 56px;
  pointer-events: none;
  background: linear-gradient(180deg, transparent, var(--nuit-creux));
}
.panneau__appel { width: 100%; white-space: nowrap; }
.panneau__tels {
  margin: 0;
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--e2);
}
.panneau__tel {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--e2);
  min-height: 44px;
  font-family: var(--titre);
  font-size: 0.875rem; letter-spacing: 0.04em;
  color: var(--texte); text-decoration: none;
  border: 1px solid var(--bordure);
  transition: color var(--duree) ease-out, border-color var(--duree) ease-out;
}
.panneau__tel svg { width: 15px; height: 15px; }
.panneau__tel:hover { color: var(--or); border-color: var(--or-sourd); }
@media (max-width: 359px) { .panneau__tels { grid-template-columns: 1fr; } }

/* ------------------------------------ au-delà de 720 px : deux colonnes */
/* Le panneau sert jusqu'au seuil de la barre : sur une tablette ou un petit
   portable, une colonne de liens au milieu d'un écran vide serait pauvre. */
@media (min-width: 720px) {
  .panneau__barre { min-height: 84px; padding-inline: var(--e12); }
  .panneau__logo img { width: 160px; height: 67px; }
  .panneau__corps { padding-inline: var(--e12); }
  .panneau__nav {
    display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
    grid-template-areas: "t1 t2" "v l";
    column-gap: var(--e12);
    align-items: start; align-content: start;  /* sinon la rangée des intertitres
       s'étire sur la hauteur libre et creuse 112 px sous eux */
    max-width: 1100px; margin-inline: auto; width: 100%;
  }
  .panneau__titre:nth-of-type(1) { grid-area: t1; }
  .panneau__titre:nth-of-type(2) { grid-area: t2; }
  .panneau__vitrines { grid-area: v; margin-bottom: 0; }
  .panneau__liste { grid-area: l; margin-bottom: 0; }
  .panneau__lien { min-height: 52px; font-size: 1.125rem; }
  /* L'air se répartit au-dessus ET au-dessous du bloc au lieu de tomber d'un
     seul côté. Par marge auto, jamais par justify-content: center, qui rend le
     haut d'un contenu trop grand inatteignable dans un conteneur qui défile. */
  .panneau__nav { flex: none; margin-block: auto; }
  .panneau__pied {
    margin-inline: calc(var(--e12) * -1);
    padding-inline: var(--e12);
    grid-template-columns: minmax(0, 300px) minmax(0, 1fr);
    align-items: center; gap: var(--e6);
  }
  .panneau__tels { grid-template-columns: repeat(2, minmax(0, 200px)); }
}

/* ------------------------------------------------------- l'assemblage */
/* Une animation CSS se rejoue quand l'élément repasse de display:none à
   display:flex — le panneau s'assemble donc à chaque ouverture, sans que le
   script ait à poser quoi que ce soit. */
@keyframes menu-nappe { from { opacity: 0; } to { opacity: 1; } }
@keyframes menu-bloc {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}
@keyframes menu-filet { from { transform: scaleY(0); } to { transform: scaleY(1); } }

@media (prefers-reduced-motion: no-preference) {
  .panneau { animation: menu-nappe 220ms ease-out both; }
  .panneau::before { transform-origin: top; animation: menu-filet 640ms 120ms cubic-bezier(.22,.61,.36,1) both; }
  .panneau__titre,
  .panneau__vitrines li,
  .panneau__liste li,
  .panneau__pied { animation: menu-bloc 420ms cubic-bezier(.22,.61,.36,1) both; }
  .panneau__titre:nth-of-type(1)  { animation-delay: 90ms; }
  .panneau__vitrines li:nth-child(1) { animation-delay: 130ms; }
  .panneau__vitrines li:nth-child(2) { animation-delay: 170ms; }
  .panneau__vitrines li:nth-child(3) { animation-delay: 210ms; }
  .panneau__vitrines li:nth-child(4) { animation-delay: 250ms; }
  .panneau__titre:nth-of-type(2)  { animation-delay: 230ms; }
  .panneau__liste li:nth-child(1) { animation-delay: 265ms; }
  .panneau__liste li:nth-child(2) { animation-delay: 295ms; }
  .panneau__liste li:nth-child(3) { animation-delay: 325ms; }
  .panneau__liste li:nth-child(4) { animation-delay: 355ms; }
  .panneau__liste li:nth-child(5) { animation-delay: 385ms; }
  .panneau__liste li:nth-child(6) { animation-delay: 415ms; }
  .panneau__pied { animation-delay: 300ms; }
}

/* ----------------------------------------- la barre : le filet qui pousse */
/* Le cheveu d'or ne s'allume plus, il se trace de la gauche vers la droite.
   C'est un transform : rien ne se recalcule, tout est sur le compositeur. */
.nav__lien::after {
  transform: scaleX(0); transform-origin: left;
  opacity: 1;
  transition: transform 260ms cubic-bezier(.22,.61,.36,1), color var(--duree) ease-out;
}
.nav__lien:hover::after,
.nav__lien[aria-current="page"]::after { transform: scaleX(1); }
@media (prefers-reduced-motion: reduce) {
  .nav__lien::after { transition: none; }
}
/* <<< patch-menu.py — fin */

/* >>> patch-r2-01-visuel-global : début — ne pas écrire à l’intérieur */
/* =========================================================================
   LE VISUEL GLOBAL — lot 01 du retour client du 28/08/2026
   Posé APRÈS tout ce que contient cette feuille : raffinement, fourgon,
   retour client, menu. Il ne remplace aucune règle en amont, il les recouvre.
   Le retirer rend exactement la feuille d’avant.
   ========================================================================= */

/* --------------------------------------------------- 0. deux voiles, deux halos
   « Aucune couleur en dur hors de :root » : les quatre valeurs de service
   utilisées plus bas sont donc des jetons. Ce sont des transparences, pas des
   couleurs nouvelles — la palette nuit acier + or ne bouge pas d’un
   hexadécimal. Le voile est un fond presque invisible qui donne du corps à un
   bouton au repos ; le halo est l’anneau discret qui apparaît au survol. */
:root {
  --or-voile:    rgba(212, 163, 89, .07);
  --or-halo:     rgba(212, 163, 89, .22);
  --clair-voile: rgba(255, 255, 255, .05);
  --clair-halo:  rgba(255, 255, 255, .14);
}

/* ------------------------------------------------------------ 1. le logo
   « Grossir la taille du logo sur le menu. »

   Le logo vit à DEUX endroits : la barre (`entete()` de build.py) et le
   panneau plein écran (patch-menu.py). Les deux grossissent, du même geste.

   ⚠️ CE QUE ÇA COÛTE EN LARGEUR, MESURÉ AU NAVIGATEUR le 28/08/2026 sur le
   site construit (Chrome, polices réelles, neuf onglets). « marge » = la
   place qui reste dans la barre une fois logo + navigation + bouton
   téléphone + écarts posés. Un débordement élargirait le viewport et
   rapetisserait la page entière sans rien signaler : ces chiffres sont la
   seule raison pour laquelle les valeurs ci-dessous sont celles-là.

       largeur   logo avant -> après      marge avant -> après
        320 px    92x39  ->  104x44        +43,7  ->  +31,7 px
        360 px   112x47  ->  124x52        +20,7  ->   +8,7 px   <-- le point dur
        600 px   160x67  ->  176x74        +53,7  ->  +37,7 px
        900 px   172x72  ->  192x80       +320,6  -> +300,6 px
       1300 px   144x60  ->  176x74       +216,5  -> +184,5 px
       1512 px   160x67  ->  184x77       +236,3  -> +212,3 px
       1700 px   172x72  ->  192x80       +188,2  -> +168,2 px

   Le point dur est le téléphone de 360 px : il ne reste que 8,7 px. C’est
   une marge DÉTERMINISTE (trois boîtes en pixels fixes, aucun texte
   variable), mais elle est à son plancher : le logo de la barre ne peut
   plus grossir sous 600 px sans reprendre de la place au bouton téléphone.

   ⚠️ LA HAUTEUR DE LA BARRE NE BOUGE PAS — 64 / 84 / 96 px avant comme
   après, vérifié aux mêmes largeurs. Sous 900 px la respiration du logo
   passe de 8 à 4 px pour absorber la hauteur gagnée ; au-delà, 80 px de
   logo plus deux fois 8 font très exactement les 96 px de la barre. Une
   barre plus haute aurait déplacé toute la page sous elle. */
@media (max-width: 899px) { .entete .entete__logo { padding-block: var(--e1); } }

.entete .entete__logo img { width: 176px; height: 74px; }
@media (max-width: 599px)  { .entete .entete__logo img { width: 124px; height: 52px; } }
@media (max-width: 359px)  { .entete .entete__logo img { width: 104px; height: 44px; } }
@media (min-width: 900px)  { .entete .entete__logo img { width: 192px; height: 80px; } }
/* Les trois paliers de la barre à neuf onglets. Deux classes, exprès : le
   dernier bloc de la feuille servie (outils/actualites.py) redéfinit
   `.entete__logo img` à ces trois seuils, et gagnerait par l’ordre. */
@media (min-width: 1360px) { .entete .entete__logo img { width: 176px; height: 74px; } }
@media (min-width: 1512px) { .entete .entete__logo img { width: 184px; height: 77px; } }
@media (min-width: 1800px) { .entete .entete__logo img { width: 192px; height: 80px; } }

/* Le logo du panneau plein écran suit le même mouvement. Sa respiration passe
   elle aussi à 4 px : la barre du panneau reste à 64 px (84 au-delà de
   720 px), donc la croix tombe très exactement là où était le burger — c’est
   la raison d’être de cette barre, elle ne se déplace pas d’un pixel. */
.panneau .panneau__logo { padding-block: var(--e1); }
.panneau .panneau__logo img { width: 132px; height: 55px; }
@media (min-width: 720px) { .panneau .panneau__logo img { width: 176px; height: 74px; } }

/* ------------------------------------------------- 2. l’interlettrage, un cran
   « rapprocher les lettres de la police, un totu petit peu »
   « LES titres aussi, rapprocher asuusi les lettres »

   C’est le SECOND resserrage : celui du 28/08 au matin (patch-retour-client)
   avait déjà fait tomber l’échelle d’un tiers. On enlève ici un cran de plus,
   et les familles ne se traitent pas ensemble :

     · les CAPITALES (Julius Sans One, tous les titres) se resserrent peu —
       0,02 em sur les titres, 0,03 em sur les surtitres et les grandes
       capitales. Une capitale trop serrée devient une masse illisible ;
     · le CORPS (Baskervville, bas de casse) part de zéro et descend à
       −0,01 em, soit −0,2 px à 20 px. C’est un souffle, pas un écrasement :
       un serif fin sur fond nuit ne supporte pas davantage.

   Valeurs, avant -> après :
       h1 .................... 0,040 -> 0,020 em
       h2 .................... 0,050 -> 0,030 em
       h3 .................... 0,065 -> 0,045 em
       h4 .................... 0,070 -> 0,050 em
       .surtitre ............. 0,150 -> 0,120 em
       .hero__accroche ....... 0,180 -> 0,150 em
       boutons et liens ...... 0,100 -> 0,080 em
       titres de carte ....... 0,085 -> 0,065 em
       .vitrine__num, .pied h2 0,140 -> 0,110 em
       panneau : intertitres . 0,220 -> 0,180 em
       panneau : liens ....... 0,140 -> 0,110 em
       panneau : vignettes ... 0,120 -> 0,100 em
       corps de texte ........ 0 (normal) -> −0,010 em

   ⚠️ DEUX FAMILLES NE SONT PAS TOUCHÉES, ET C’EST VOULU :
     · `.nav__lien` — l’interlettrage de la barre est calibré au pixel contre
       le débordement à neuf onglets (0,01 / 0,04 / 0,10 em selon le palier,
       dans outils/actualites.py). Y toucher rouvre le piège du viewport ;
     · `.tel-ligne` et `.bouton--tel` — descendus à 0,06 em le 28/08 au matin
       pour un numéro « un peu plus gros on le voit mal ». Ils sont déjà plus
       serrés que la valeur posée ici : `.bouton--tel` est redéclaré plus bas
       pour que la règle générale des boutons ne le desserre pas.

   ⚠️ L’accroche du hero tient sur deux lignes grâce à ses espaces
   insécables : on la RESSERRE, donc la ligne raccourcit — aucun risque de
   casse supplémentaire. Vérifié à 320, 360, 390, 430 px. */
body { letter-spacing: -0.01em; }
h1 { letter-spacing: 0.02em; }
h2 { letter-spacing: 0.03em; }
h3 { letter-spacing: 0.045em; }
h4 { letter-spacing: 0.05em; }
.surtitre { letter-spacing: 0.12em; }
.hero__accroche { letter-spacing: 0.15em; }
.bouton, .lien-fleche, .tel-grand, .evitement { letter-spacing: 0.08em; }
/* redéclaré APRÈS la règle générale : la décision du 28/08 au matin tient. */
.bouton--tel { letter-spacing: 0.06em; }
.reperes span, .carte h3, .parcours h3, .questions h3,
.note h3, .champ label, .vitrine h3 { letter-spacing: 0.065em; }
.vitrine__num, .pied h2 { letter-spacing: 0.11em; }
.panneau__titre { letter-spacing: 0.18em; }
.panneau__lien { letter-spacing: 0.11em; }
.vignette__nom { letter-spacing: 0.1em; }

/* --------------------------------------- 3. les titres cliquables au survol
   « Les titres aussi quand je passe la souris dessus je veux que ca change
     de couleur »

   ⚠️ SEULS LES TITRES CLIQUABLES RÉAGISSENT. Un h2 de section qui change de
   couleur sous la souris promet un lien qui n’existe pas : c’est un mensonge
   d’affordance, et le visiteur clique dans le vide. Les titres cliquables de
   ce site sont exactement trois familles, toutes en `h3 > a` : les cartes
   métier (.carte), les vitrines d’ouvrage (.vitrine), les notes de conseil et
   d’actualité (.note).

   Ce qui existait déjà : le titre passait à l’or quand la CARTE était
   survolée. Ce qui manque, et qu’on ajoute :
     · le survol du titre lui-même (`a:hover`), pour que la règle ne dépende
       plus du seul conteneur ;
     · la PARITÉ CLAVIER (`:focus-within`) : .carte et .note ne l’avaient pas,
       un utilisateur au clavier ne voyait rien virer ;
     · un SOULIGNEMENT d’or : la couleur n’est jamais le seul indice (WCAG
       1.4.1). Il est là au repos mais transparent, ce qui le rend animable
       et n’ajoute pas un pixel de mise en page. Il est tiré en `--or`, pas
       en `--or-sourd` : l’or sourd ne fait que 2,8:1 sur l’acier clair, le
       fond que `.note` prend justement au survol — un repère qu’on ne voit
       pas là où il doit servir n’est pas un repère. En `--or` : 7,8 / 7,2 /
       6,2:1 sur les trois fonds, comme la lettre qu’il souligne.

   Contrastes, mesurés sur les trois fonds où ces cartes vivent :
     blanc au repos ...... 17,8:1 (nuit) · 16,4:1 (acier)
     or au survol .........  7,8:1 (nuit) ·  7,2:1 (acier) · 6,2:1 (acier
                             clair, le fond que prend .note au survol)
   AA est tenu dans les deux états, sur les trois fonds. */
.carte h3 a, .vitrine h3 a, .note h3 a {
  text-decoration-line: underline;
  text-decoration-color: transparent;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.28em;
  transition: color var(--duree) ease-out, text-decoration-color var(--duree) ease-out;
}
.carte:hover h3 a, .carte h3 a:hover, .carte:focus-within h3 a,
.vitrine:hover h3 a, .vitrine h3 a:hover, .vitrine:focus-within h3 a,
.note:hover h3 a, .note h3 a:hover, .note:focus-within h3 a {
  color: var(--or);
  text-decoration-color: var(--or);
}

/* ------------------------------------------------------------- 4. les boutons
   « Rend boutons plus visible, quand on survole etc sur tout le site dans
     les pages services »

   Trois états travaillés, pas seulement le survol : le REPOS, le SURVOL et le
   FOCUS CLAVIER. La palette ne bouge pas ; ce qui change est le poids.

   ⚠️ RÈGLE DE LA MAISON : UN SEUL APLAT D’OR PAR ÉCRAN. Aucun bouton ne
   devient doré ici. Le bouton d’or (`--plein`) reste le seul, et les autres
   gagnent un contour franc et un fond presque invisible — un voile à 7 %
   n’est pas un aplat.

   AU REPOS
     · `--contour` : le filet passe de l’or sourd (3,6:1) à l’or (7,8:1), la
       lettre de l’or à l’or clair (10,4:1), et un voile d’or à 7 % donne au
       bouton un corps au lieu d’un vide. ⚠️ Le bouton téléphone de l’en-tête
       porte cette classe mais N’EST PAS touché : `.entete__tel .bouton` du
       bloc « raffinement » l’emporte en spécificité, et la barre reste telle
       qu’elle a été calibrée.
     · `--clair` (le téléphone du bandeau « Une idée ? Un projet ? », le seul
       bouton de fin de page des pages d’ouvrage) : son filet passe du gris
       d’interface (3,3:1, le minimum légal) au gris clair du texte (11,1:1),
       la lettre au blanc, et un voile blanc à 5 % le pose. C’est le bouton
       que le client voit en bas de chaque page de service : c’était le plus
       effacé du site, c’est celui qui gagne le plus.

   AU SURVOL — un anneau de 4 px, franc mais transparent, autour du bouton.
   Il ne déplace rien (une ombre n’occupe pas de place), il se voit de loin
   sur fond nuit, et il reste dans la grammaire de filets de la maison.

   AU FOCUS CLAVIER — l’anneau global du site fait 2 px d’or ; sur un bouton
   il passe à 3 px d’or clair (10,4:1 sur la nuit), donc visible aussi bien
   contre la nuit que contre l’aplat d’or du bouton principal. Cette règle est
   déclarée APRÈS celles de survol : un bouton survolé ET focalisé montre son
   anneau de focus, pas son halo. */
.bouton {
  box-shadow: 0 0 0 0 transparent;
  transition: background-color 320ms ease-out, color 320ms ease-out,
              border-color 320ms ease-out, box-shadow 320ms ease-out;
}
.bouton--contour {
  background: var(--or-voile);
  border-color: var(--or);
  color: var(--or-clair);
}
.bouton--contour:hover {
  background: var(--or); color: var(--nuit); border-color: var(--or);
  box-shadow: 0 0 0 4px var(--or-halo);
}
.bouton--plein:hover {
  background: var(--or-clair); border-color: var(--or-clair); color: var(--nuit);
  box-shadow: 0 0 0 4px var(--or-halo);
}
.bouton--clair {
  background: var(--clair-voile);
  border-color: var(--texte);
  color: var(--blanc);
}
.bouton--clair:hover {
  background: var(--blanc); color: var(--nuit); border-color: var(--blanc);
  box-shadow: 0 0 0 4px var(--clair-halo);
}
.bouton--blanc:hover { box-shadow: 0 0 0 4px var(--or-halo); }
.bouton:focus-visible { outline: 3px solid var(--or-clair); outline-offset: 3px; }
/* Un bouton désactivé ne s’allume pas : il n’y a rien à survoler. */
.bouton[disabled], .bouton[disabled]:hover { box-shadow: 0 0 0 0 transparent; }

/* ------------------------------- 5. « De l’atelier à votre domicile », plus gros
   « De l’atelier à votre domicile pour le sous titre, grossi le aussi.
     au dessus de nous venons, jusqua vous. »

   Le TEXTE de ce surtitre est posé par le lot 03 (textes canoniques, T2).
   Ici, seulement sa taille : c’est le seul surtitre du site qui doit se lire
   comme une phrase et non comme une étiquette. Il passe de la taille d’un
   surtitre (13 à 15 px) à 16 px sur téléphone et 20 px sur grand écran. Il
   reste nettement sous le h2 qu’il annonce (25 à 38 px) : il l’introduit,
   il ne le double pas. L’amorce d’or qui le précède s’allonge en proportion.
   Contraste de l’or sur le fond de cette bande (nuit creuse) : 8,2:1. */
.camion__texte > .surtitre {
  font-size: clamp(1rem, 0.9rem + 0.5vw, 1.25rem);
  letter-spacing: 0.1em;
  margin-bottom: var(--e6);
}
.camion__texte > .surtitre::before { width: 34px; margin-right: var(--e4); }

/* ------------------------------------------------------- 6. le pied, plus petit
   « dans le footeur ... met le texte plus petit »

   Le pied était servi à la taille du corps de texte — 18 à 20 px pour une
   adresse, deux numéros, un courriel et deux colonnes de liens. C’est la
   taille d’un paragraphe qu’on lit, pas d’un pied qu’on consulte.

       adresse, numéros, listes de liens  18–20 px -> 16 px
       la zone de chalandise ............ 18–20 px -> 15 px
       les horaires (.legende) .......... 15 px    -> 14 px
       la ligne du bas (mentions, ©) .... 15 px    -> 14 px

   ⚠️ PLANCHER : rien ne descend sous 14 px, y compris sur téléphone. Les
   intitulés de colonne restent à leur taille (13–15 px, `--t-surtitre`
   remonté le 28/08 au matin) : ce sont déjà des
   étiquettes, les réduire les rendrait illisibles.
   Contrastes conservés : texte clair sur nuit creuse 11,8:1, gris sur nuit
   creuse 7,3:1 — AA tenu à 14 px. */
.pied { font-size: 1rem; }
.pied__zone { font-size: 0.9375rem; }
.pied .legende { font-size: 0.875rem; }
.pied__bas { font-size: 0.875rem; }

/* --------------------------------------------------- 7. le mouvement, désarmé
   La feuille porte déjà une coupure globale (`transition-duration: 0.001ms
   !important` sous prefers-reduced-motion). Elle suffit ; celle-ci la double
   explicitement sur ce que ce bloc anime, pour que le jour où la règle
   globale bougerait, ce bloc reste conforme tout seul. */
@media (prefers-reduced-motion: reduce) {
  .bouton,
  .carte h3 a, .vitrine h3 a, .note h3 a { transition: none; }
}
/* <<< patch-r2-01-visuel-global : fin */

/* >>> patch-r2-02-accueil : début — ne pas écrire à l’intérieur */
/* ------------------------------------ le surtitre de « Nos exigences » */
/* Le client a remplacé « Ce qui se voit une fois posé » (28 signes) par une
   phrase de 61 : « Ce que nous pouvons retenir d'un travail confié à notre
   équipe ». En capitales, à 13 px, avec 0,15em d'interlettrage, elle occupe
   trois lignes sur un téléphone à 320 px et l'interlettrage la rend pénible
   à lire. Le texte est canonique, on ne le coupe pas : on le compose.
   Rien d'autre que .surtitre--exigences n'est touché — les autres surtitres
   gardent exactement le réglage posé par patch-retour-client.py.
   Le sélecteur double `.surtitre.surtitre--exigences` n'est pas une coquette :
   patch-r2-01 pose `.surtitre { letter-spacing: 0.12em }` dans SON bloc de fin
   de feuille. À spécificité égale, le dernier bloc écrit gagnerait — et l'ordre
   des blocs dépend de l'ordre où les patchs sont rejoués. Deux classes, et la
   question ne se pose plus.
   `text-wrap: balance` est une amélioration progressive : là où le navigateur
   ne le connaît pas, le paragraphe se coupe comme avant. Aucune animation,
   donc rien à protéger côté prefers-reduced-motion, et aucune couleur touchée,
   donc aucun contraste changé. */
.surtitre.surtitre--exigences {
  letter-spacing: 0.1em;
  line-height: 1.55;
  text-wrap: balance;
}

/* <<< patch-r2-02-accueil : fin */

/* ---- portée : début du bloc posé par outils/patch-r2-04-zone-et-carte.py ---- */
/* =========================================================================
   LA PORTÉE — la carte de France de /zone-interventions/, 28/08/2026
   Posé après tout le reste : ce bloc ne modifie aucune règle en amont.
   Aucune couleur nouvelle, rien que les jetons de :root. Aucune animation,
   donc rien à désarmer sous prefers-reduced-motion.
   ========================================================================= */
.portee { margin-top: var(--e12); }
/* Le titre reprend le traitement de `.communes h3` : la carte est le second
   temps de la même section, pas une section de plus. */
.portee__titre {
  font-size: var(--t-surtitre);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--or);
  margin-bottom: var(--e6);
  padding-bottom: var(--e3);
  border-bottom: 1px solid var(--bordure);
}
/* Le viewBox porte le rapport de forme : la place est réservée avant le
   rendu, il n'y a pas de saut de mise en page à surveiller. */
.portee__carte {
  display: block;
  width: 100%; height: auto;
  max-width: 660px;
  margin-inline: auto;
}
/* La terre : une surface d'acier posée sur la nuit, et un contour à 3,3:1.
   Le dessin ne tient pas au remplissage, il tient au trait. */
.portee__terre {
  fill: var(--acier);
  stroke: var(--bordure-champ);
  stroke-width: 1.4;
  stroke-linejoin: round;
}
/* L'aire annoncée. L'opacité est portée par le GROUPE, pas par le fond ni par
   le contour : sinon le contour repasse sur le fond et dessine un liseré plus
   dense là où les deux se recouvrent. Le contour épais aux jointures rondes
   arrondit l'enveloppe — une portée n'a pas d'arête. */
.portee__zone { opacity: .26; }
.portee__zone path {
  fill: var(--or-sourd);
  stroke: var(--or-sourd);
  stroke-width: 26;
  stroke-linejoin: round;
}
/* Les trois axes, en tirets : le tiret est un indice de forme, il tient sans
   la couleur. */
.portee__axes line {
  stroke: var(--or);
  stroke-width: 2.6;
  stroke-dasharray: 11 9;
  stroke-linecap: round;
}
.portee__lieu { fill: var(--texte); stroke: var(--nuit); stroke-width: 2.5; }
.portee__halo { fill: none; stroke: var(--or); stroke-width: 2.5; }
.portee__atelier { fill: var(--or); stroke: var(--nuit); stroke-width: 2; }
/* Baskervville et non Copperplate : quatre noms de lieux sur une carte se
   lisent en bas de casse, et les capitales espacées seraient deux fois plus
   larges pour la même hauteur d'œil. */
.portee__nom { font-family: var(--texte-police); font-size: 23px; fill: var(--texte); }
.portee__nom--atelier { fill: var(--or-clair); font-size: 26px; }
.portee__cle {
  color: var(--gris);
  font-size: var(--t-legende);
  max-width: var(--prose);
  margin: var(--e6) auto 0;
}
.portee .legende { text-align: center; margin-top: var(--e2); }
/* Le texte d'une carte est à l'échelle de son viewBox : sur un téléphone, la
   carte fait 340 px de large pour 663 unités, et 23 unités tombent à 12 px.
   Les noms grossissent donc quand la carte rétrécit. L'interligne suit,
   parce qu'il est écrit en `em` dans le SVG. */
@media (max-width: 700px) {
  .portee__nom { font-size: 30px; }
  .portee__nom--atelier { font-size: 33px; }
}
/* ---- portée : fin du bloc ---- */

/* ---- déontologie : début du bloc posé par outils/patch-r2-05-atelier.py ---- */
/* =========================================================================
   « NOTRE DÉONTOLOGIE » — page /atelier/, retour client du 28/08/2026
   Deux entrées sous icône, « En intérieur » et « En extérieur ». Aucun
   vocabulaire nouveau : c'est la surface d'acier des étapes du parcours, son
   filet d'or en tête, et le même pictogramme au trait qui se dessine.
   ========================================================================= */

/* LA COUTURE. La page alterne lin/blanc sans exception ; la section s'intercale
   entre deux bandes et prend donc le fond de sa voisine, sinon il faudrait
   décaler l'alternance d'un cran sur les six sections suivantes. Un cheveu d'un
   pixel — celui qui court déjà sous les titres — dit où l'une finit et où
   l'autre commence. */
.bande--deonto { border-top: 1px solid var(--bordure); }

.deonto {
  display: grid;
  gap: var(--e6);
  list-style: none;
  margin: var(--e8) 0 0;
  padding: 0;
}
/* Deux colonnes dès qu'il y a la place. En dessous, elles s'empilent : à 320 px
   une carte de 64 px d'icône et deux lignes de titre tient sans déborder, et
   c'est le débordement horizontal qui rapetisserait la page entière. */
@media (min-width: 760px) {
  .deonto { grid-template-columns: repeat(2, 1fr); gap: var(--e8); }
}
.deonto li {
  margin: 0;
  background: var(--acier);
  border: 1px solid var(--bordure);
  border-top: 1px solid var(--or-sourd);
  padding: var(--e8) var(--e6) var(--e6);
  transition: background-color var(--duree) ease-out, border-color var(--duree) ease-out;
}
.deonto li:hover { background: var(--acier-clair); border-top-color: var(--or); }

/* L'icône. Servie à 64 px sur une grille de 64 : le stroke-width nominal de
   1,18 porté par le SVG rend donc 1,18 px, le filet de la charte, sans aucune
   correction ici — et une seule taille, donc aucune correction en mobile non
   plus. Ne pas lui donner de largeur en % : elle repasserait sous le filet. */
.deonto__picto { margin-bottom: var(--e4); }
/* .picto pose `color: var(--or)` sur le SVG lui-même : la couleur du survol ne
   peut donc pas venir par héritage du <li>, elle se pose sur le SVG. */
.deonto li:hover .deonto__picto { color: var(--or-clair); }

.deonto h3 {
  font-size: 1.0625rem;
  letter-spacing: 0.13em;
  margin-bottom: var(--e4);
}
.deonto p {
  margin: 0;
  color: var(--gris);
  font-size: var(--t-legende);
  line-height: 1.7;
}

/* Le tracé des icônes et son extinction sous prefers-reduced-motion sont déjà
   tenus par le bloc « pictogrammes » de cette feuille : .picto__t / .anim.vu.
   Rien à redire ici, et surtout rien à dupliquer. */

/* ---- déontologie : fin du bloc ---- */

/* ---- blocs partagés (lot 06) : début du bloc posé par outils/patch-r2-06-blocs-partages.py ---- */
/* =========================================================================
   LA PHRASE DE POSE, SOUS LE PARCOURS — 28/08/2026
   Une seule règle, et elle n'existe que parce que `.parcours` porte
   `margin: 0` : sans marge haute, le paragraphe viendrait coller la dernière
   case de la grille. La largeur est celle de `.prose-large` (46rem) : sur
   l'accueil comme sur /atelier/, le parcours occupe les 1200 px de `.contenu`,
   une ligne de texte de cette longueur ne se lit plus.

   Aucune couleur nouvelle : `--texte` sur `--nuit`, soit 10,7:1.
   Aucune animation : le paragraphe est un enfant direct de `.contenu.anim` et
   suit le dévoilement déjà en place, `prefers-reduced-motion` compris.
   ========================================================================= */
.parcours__note {
  max-width: 46rem;
  margin: var(--e8) 0 0;
  color: var(--texte);
}
@media (min-width: 900px) {
  /* La grille passe à trois colonnes : l'écart se creuse pour que la phrase se
     lise comme une suite, pas comme une légende collée sous les cases. */
  .parcours__note { margin-top: var(--e12); }
}

/* ---- blocs partagés (lot 06) : fin du bloc ---- */

/* ---- pictos ADLD : début du bloc posé par outils/patch-r2-09-pictos-adld.py ---- */
/* LA COUCHE DE FOND DES PICTOGRAMMES DU CLIENT

   Ses quatre pictogrammes sont UN SEUL dessin — une verrière cintrée — dont
   chaque ouvrage éclaire une partie et laisse le reste en gris. Le gris, chez
   lui, est un noir à 30 % sur blanc (relevé dans ses PDF : `0 0 0 0.3 k`).

   Ici il n'y a ni gris ni seconde couleur : la même couleur, éteinte. Pourquoi —
   `color` porte déjà le survol de la carte (var(--or) → var(--or-clair), bloc
   « pictogrammes » de cette feuille). Une couleur en dur sur la couche de fond
   figerait ce survol, et le dessin se couperait en deux au passage de la souris.

   Ce que ça ne fait pas : porter de l'information. Les pictos sont
   aria-hidden, l'ouvrage est écrit en toutes lettres dans le h3 juste dessous,
   et la partie qui le nomme reste à var(--or) plein — 8,1:1 sur la nuit. La
   couleur n'est jamais le seul indice, et rien ne se joue sur le contraste de
   la couche éteinte. */
.picto__fond { opacity: 0.42; }

/* Au survol de la carte, le fond monte d'un cran — sans jamais rattraper la
   partie allumée : c'est l'ÉCART entre les deux qui dit l'ouvrage. */
.carte:hover .picto__fond,
.carte:focus-within .picto__fond { opacity: 0.58; }

/* La transition n'existe que si le visiteur n'a pas demandé moins d'animation.
   Posée dans un `no-preference` plutôt qu'annulée dans un `reduce` : rien à
   défaire, donc rien à oublier. */
@media (prefers-reduced-motion: no-preference) {
  .picto__fond { transition: opacity var(--duree) ease-out; }
}
/* ---- pictos ADLD : fin du bloc ---- */

/* >>> patch-r2-10-fabrique-en-vendee : début — ne pas écrire à l’intérieur */
/* ==================================== le sceau « Fabriqué en Vendée » (28/08)
   « dans vendée meme dans les liste KPI met le logo de la vandée, avec un truc
   du genre Fabriqué en vendée, ajoute ca aussi dans la page contact ».

   Le logo du département est une marque déposée : ce qui est dessiné ici est le
   CONTOUR géographique — un fait — plus la mention, dans la charte de la maison.

   LE TRAIT est réglé en unités du viewBox (620 de large, marge comprise) et non
   en pixels : il tombe donc sur le cheveu d'un pixel du site à toutes les
   tailles rendues — 11 × 86/620 = 1,53 px au plus grand, 1,03 px au plus petit.
   Rien à recalculer par emplacement.

   AUCUNE ANIMATION n'est ajoutée : la case hérite de la révélation de
   `.reperes > li`, déjà neutralisée sous `prefers-reduced-motion`. */

.sceau-vendee__forme { display: block; }
.sceau-vendee__forme svg {
  display: block;
  /* Le sceau tient la largeur d'un chiffre de repère : 86 px au plus large, et
     il se serre jusqu'à 58 px sur un téléphone de 320 px, où la colonne d'une
     case ne fait que 104 px de contenu. */
  width: clamp(58px, 16vw, 86px);
  height: auto;
  margin-inline: auto;
}
.sceau-vendee__contour {
  fill: none;
  stroke: var(--or);
  stroke-width: 11;
  stroke-linejoin: round;
  stroke-linecap: round;
}
/* L'atelier, à Challans. Le point de la carte de /zone-interventions/, au même
   endroit et dans le même or clair : le sceau dit où, pas seulement quoi. */
.sceau-vendee__atelier { fill: var(--or-clair); }

/* ---------------------------------------------- dans les repères chiffrés */
/* La case du sceau se lit comme ses trois voisines : le visuel là où elles ont
   leur chiffre, la mention là où elles ont leur libellé. `.reperes span` habille
   déjà la mention (police de titre, petites capitales, gris) — on ne redit rien
   ici, on ne pose que l'écart que `<b>` posait sous le chiffre. */
.sceau-vendee--repere .sceau-vendee__forme { margin-bottom: var(--e4); }

/* ------------------------------------------------------ sur /contact/ */
/* Un cartouche : filet d'un pixel, fond acier, le contour puis la mention. Il
   se range au pied de la colonne « Venir à l'atelier », sous le lien du plan. */
.sceau-vendee--contact {
  display: grid;
  gap: var(--e3);
  justify-items: start;
  width: max-content;
  max-width: 100%;
  margin-top: var(--e6);
  padding: var(--e4);
  border: 1px solid var(--bordure);
  background: var(--acier);
}
.sceau-vendee--contact .sceau-vendee__mention {
  display: block;
  font-family: var(--titre);
  font-size: 0.875rem;
  letter-spacing: 0.085em;
  line-height: 1.5;
  text-transform: uppercase;
  color: var(--texte);
}
/* Sous 420 px, le contour et la mention s'empilent : côte à côte, ils
   demandaient 269 px de large là où un téléphone de 320 px n'en laisse que
   272 — et 14 px de débordement rapetissent la page entière sans rien dire. */
@media (min-width: 420px) {
  .sceau-vendee--contact {
    grid-auto-flow: column;
    /* `auto`, et surtout PAS `max-content` : une colonne max-content ne se
       resserre jamais. Sur un navigateur réglé en corps 20 px la mention passe
       d'environ 209 px à 287 px, le cartouche en demande 417 là où un écran de
       420 px n'en laisse que 372 : quinze pixels de débordement, et le viewport
       de mise en page s'élargit en rapetissant la page entière sans rien dire.
       Avec `auto` la mention se replie sur deux lignes au lieu de déborder, et
       son minimum reste son mot le plus long. Le contour, lui, ne descend pas
       sous les 58 px de son `clamp()`. */
    grid-auto-columns: auto;
    align-items: center;
    gap: var(--e4);
    padding-right: var(--e6);
  }
  .sceau-vendee--contact .sceau-vendee__mention {
    padding-left: var(--e4);
    border-left: 1px solid var(--bordure);
  }
}
/* <<< patch-r2-10-fabrique-en-vendee : fin */

/* ---- nuancier RAL (lot 12) : début du bloc posé par outils/patch-r2-12-nuancier-ral.py ---- */
/* =========================================================================
   LE NUANCIER DES FINITIONS — 28/08/2026
   « ajoute un RAL … sur chaque page service » (client, 28/08/2026).

   La charte du site, sans rien inventer : la nuit acier en fond, l'or en
   filets d'un pixel, aucun rayon, aucune ombre, aucune boîte. Les teintes se
   posent entre deux cheveux comme les quatre points de « Nos exigences » —
   c'est le même geste, celui de la planche de catalogue.

   ⚠️ SEUL ENDROIT DE LA FEUILLE OÙ UNE COULEUR EST ÉCRITE EN DUR hors de
   :root, et c'est délibéré : ces valeurs ne sont pas des couleurs de marque,
   ce sont des RÉFÉRENCES RAL. Elles ne deviennent pas des jetons, elles ne se
   réutilisent nulle part, et elles ne suivent aucun thème.

   ⚠️ Elles sont écrites ici et NON en style="" : la CSP de production bloque
   le style en ligne. La liste de build.py (TEINTES_RAL) et celle-ci sont
   posées ensemble par outils/patch-r2-12-nuancier-ral.py, depuis la même
   source. Une teinte ajoutée d'un seul côté rend une pastille transparente.

   Aucune animation propre : la section est un `.contenu.anim` ordinaire et
   suit le dévoilement déjà en place, garde `prefers-reduced-motion` comprise.
   ========================================================================= */

/* Le nuancier appartient à « La finition » qui le précède, et les deux bandes
   partagent le même fond : le haut se resserre pour que ça se lise comme une
   suite, le bas garde l'air d'une fin de chapitre. Asymétrie voulue. */
.nuancier { padding-top: var(--e8); }
@media (min-width: 768px)  { .nuancier { padding-top: var(--e12); } }
@media (min-width: 1100px) { .nuancier { padding-top: var(--e16); } }

.nuancier__grille {
  list-style: none;
  margin: var(--e12) 0 0;
  padding: 0;
  display: grid;
}
.nuancier__teinte {
  display: flex;
  align-items: center;
  gap: var(--e4);
  margin: 0;
  padding: var(--e4) 0;
  border-bottom: 1px solid var(--bordure);
}
/* Le filet du haut se pose sur la PREMIÈRE RANGÉE, dont la longueur change
   avec le nombre de colonnes. D'où les trois règles, cumulatives : à trois
   colonnes, les cases 1, 2 et 3 l'ont toutes les trois. */
.nuancier__teinte:first-child { border-top: 1px solid var(--bordure); }
@media (min-width: 560px) {
  .nuancier__grille { grid-template-columns: repeat(2, 1fr); column-gap: var(--e8); }
  .nuancier__teinte:nth-child(2) { border-top: 1px solid var(--bordure); }
}
@media (min-width: 900px) {
  .nuancier__grille { grid-template-columns: repeat(3, 1fr); column-gap: var(--e12); }
  .nuancier__teinte:nth-child(3) { border-top: 1px solid var(--bordure); }
}

/* La pastille est DÉCORATIVE (aria-hidden) : le code et le nom sont écrits à
   côté. Son filet d'or n'est pas un ornement — sans lui, RAL 9005 (#0A0A0A)
   disparaît dans la nuit du fond et la case paraît vide. */
.nuancier__pastille {
  flex: 0 0 auto;
  width: 46px;
  height: 46px;
  border: 1px solid var(--or-sourd);
}
.nuancier__texte { min-width: 0; }   /* sans ça, un nom long pousse la grille */
.nuancier__code {
  display: block;
  font-family: var(--titre);
  font-weight: 400;                  /* la police de titre n'a qu'une graisse */
  font-size: 0.9375rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--blanc);
}
.nuancier__nom {
  display: block;
  font-size: var(--t-legende);
  line-height: 1.4;
  color: var(--gris);
}

/* La mention n'est pas une note de bas de page : c'est ce qui empêche un
   client de commander une couleur vue sur un écran. Elle est tenue par un
   cheveu d'or, comme une citation. */
.nuancier__mention {
  max-width: 46rem;
  margin: var(--e12) 0 0;
  padding-left: var(--e6);
  border-left: 1px solid var(--or-sourd);
  font-size: var(--t-legende);
  color: var(--texte);
}

/* ------------------------------------------------------- les teintes RAL */
.nuancier__pastille--ral-9005 { background-color: #0A0A0A; }   /* RAL 9005 — Noir foncé */
.nuancier__pastille--ral-7021 { background-color: #23282B; }   /* RAL 7021 — Gris noir */
.nuancier__pastille--ral-7016 { background-color: #383E42; }   /* RAL 7016 — Gris anthracite */
.nuancier__pastille--ral-8019 { background-color: #3D3635; }   /* RAL 8019 — Brun gris */
.nuancier__pastille--ral-7039 { background-color: #6C6960; }   /* RAL 7039 — Gris quartz */
.nuancier__pastille--ral-9010 { background-color: #F1ECE1; }   /* RAL 9010 — Blanc pur */

/* ---- nuancier RAL (lot 12) : fin du bloc ---- */

/* >>> patch-r2-13-contact-et-nous-ecrire : début — ne pas écrire à l’intérieur */
/* ===================== « Nous écrire » en rectangle, au-dessus du téléphone
   « Une idee un projet, dans chaque page projet, le nous ecrire dans un
   rectangle comme l’autre bouton tel mais au dessus met nous ecrire. »
   (retour client du 28/08/2026)

   1. LE PAVÉ PASSE AU-DESSUS, À TOUTES LES LARGEURS. `.tels--bandeau` héritait
      de `.tels`, qui passe en `grid-auto-flow: column` au-delà de 560 px : les
      deux appels étaient CÔTE À CÔTE sur ordinateur, empilés sur téléphone.
      « Au-dessus » ne voulait donc rien dire au-delà de 560 px. La bande d’appel
      reste en colonne unique partout, et c’est l’ordre du DOM qui place le mail
      en premier — aucun `order`, pour que la tabulation suive ce qu’on voit.
   2. LES DEUX RECTANGLES ONT LA MÊME LARGEUR. La colonne se dimensionne sur le
      plus large des deux (`justify-content: start`), les deux items s’y étirent.
   3. L’ADRESSE RESTE LISIBLE. `.bouton` est en Copperplate, capitales, 0,16 em
      d’interlettrage : une adresse écrite comme ça ne se lit pas et ne se
      recopie pas (c’est la raison qui avait sorti le mail de la boîte le 27/08).
      `.bouton--mail` lui rend le Baskervville bas de casse, comme `.bouton--tel`
      avait rendu au numéro sa taille. La boîte, elle, est bien celle d’un bouton.
   4. UN SEUL APLAT D’OR PAR ÉCRAN. Le téléphone garde `bouton--clair`,
      l’adresse prend `bouton--contour`. Aucun aplat n’est ajouté : l’or plein
      de la page reste celui du bloc de titre, `appel_etude()`.
      ⚠️ Les couleurs qui rendent ne sont pas celles de la feuille nue :
      `patch-r2-01-visuel-global.py` passe AVANT ce patch et repeint les deux
      variantes (contour = voile d’or, filet d’or, texte or clair ; clair =
      voile blanc, filet texte, texte blanc). Contrastes sur le fond de la
      bande (dégradé #18202A → #161E27 ; au point le plus défavorable) :
        adresse, texte #E6C088 sur voile d’or ..... 8,5:1  (AA texte : 4,5)
        adresse, filet #D4A359 .................... 6,3:1  (WCAG 1.4.11 : 3)
        adresse au survol, nuit #121820 sur or .... 7,8:1
        téléphone, texte #FFFFFF sur voile clair .. 14,2:1
        téléphone, filet #CBD5E1 .................. 9,6:1
        libellé « Nous écrire », or #D4A359 ....... 7,0:1
      Sur la feuille nue, sans le lot 01 : 7,0:1 pour l’adresse et 3,2:1 pour
      son filet — AA tenu dans les deux jeux.
      La couleur n’est pas le seul indice : chaque bouton porte son icône
      (enveloppe, combiné) et son contenu dit ce qu’il est.
   5. Rien ne s’anime ici : pas de `prefers-reduced-motion` à prévoir. Le reflet
      de survol des boutons est déjà sous garde, plus haut dans la feuille. */
.tels--bandeau {
  grid-auto-flow: row;
  justify-content: start;
  justify-items: stretch;
}
.tels--bandeau > .bouton,
.tels--bandeau .bandeau__ecrire .bouton { display: flex; width: 100%; }
.bandeau__ecrire { margin: 0; text-align: left; }
.bouton--mail {
  font-family: var(--texte-police);
  font-size: 1.0625rem;
  letter-spacing: 0.02em;
  text-transform: none;
  word-break: break-word;
}
.bouton--mail svg { width: 20px; height: 20px; }
/* <<< patch-r2-13-contact-et-nous-ecrire : fin */

/* ---- pages neuves (lot 14) : début du bloc posé par outils/patch-r2-14-pages-neuves.py ---- */
/* =========================================================================
   TROIS PAGES DE PLUS — 28/08/2026
   « Ajouter une page jardin d'hiver, pergola et forge ( tres important ) »

   Quatre sujets, et rien d'autre. Aucune règle existante n'est modifiée : ce
   bloc est ajouté en FIN de feuille et la cascade fait le reste, de sorte que
   deux patchs ne se disputent jamais une déclaration.

     1. le marteau qui tape, page /forge/
     2. le pavé « À compléter », les trois pages
     3. sept ouvrages au lieu de quatre : la grille des vitrines de l'accueil
     4. sept ouvrages au lieu de quatre : les cartes et le panneau du menu
   ========================================================================= */

/* ----------------------------------------- 1. le marteau qui tape, /forge/ */
/* Le SVG est rendu par forge_marteau() dans build.py, avec le markup exact de
   picto() : il hérite donc de `.picto` (l'or de la charte) et de
   `.embleme__picto` (160 puis 240 px, avec la graisse corrigée pour que le
   trait rendu reste à 1,18 px comme les autres familles d'icônes), et ses
   quatre couches se tracent à l'apparition par le bloc « pictogrammes ».

   ⚠️ AU REPOS, LE MARTEAU EST POSÉ. La position écrite dans le SVG est la tête
   sur la pièce, et l'animation part de là pour y revenir. Sans JavaScript,
   avant le défilement, et sous `prefers-reduced-motion`, le dessin montre un
   marteau au repos sur son enclume. Jamais figé en l'air.

   ⚠️ TROIS FRAPPES, PUIS LE REPOS. Le site anime à l'APPARITION, par
   l'observateur `.anim` / `.vu` déjà en place : le marteau suit la convention
   et s'arrête. Aucune boucle, aucun repaint permanent, zéro JavaScript ajouté.

   Le pivot est la main, en 54 14 dans le repère du viewBox. `transform-box:
   view-box` fait résoudre `transform-origin` dans les unités du viewBox et non
   dans la boîte de l'élément. C'est la valeur initiale de la propriété, mais
   Safari a longtemps résolu l'origine sur la boîte englobante : écrite, elle
   ne coûte rien et lève le doute. Là où elle manquerait, l'origine retombe au
   centre et le marteau bascule autour de son milieu, ce qui se lit encore. */
.forge__marteau {
  transform-box: view-box;
  transform-origin: 54px 14px;
}
/* Les étincelles ne sont pas une couche de tracé : elles restent invisibles
   tant que l'animation ne les allume pas, et elles y retournent. C'est la
   règle qui saute en premier si la feuille est réécrite, et ça se voit tout de
   suite — quatre traits d'or en travers du marteau. */
.forge__etincelles { opacity: 0; }
.forge__etincelles path { stroke: var(--or-clair); }

@keyframes forge-frappe {
  /* La levée freine, la chute accélère : ce contraste fait le poids de
     l'outil. Chaque étape porte donc sa propre courbe. */
  0%        { transform: rotate(0deg);  animation-timing-function: cubic-bezier(.25,.6,.4,1); }
  10%       { transform: rotate(26deg); animation-timing-function: cubic-bezier(.6,0,.95,.4); }
  19%       { transform: rotate(0deg);  animation-timing-function: cubic-bezier(.2,.9,.4,1); }
  23%       { transform: rotate(5deg);  animation-timing-function: cubic-bezier(.25,.6,.4,1); }
  34%       { transform: rotate(26deg); animation-timing-function: cubic-bezier(.6,0,.95,.4); }
  43%       { transform: rotate(0deg);  animation-timing-function: cubic-bezier(.2,.9,.4,1); }
  47%       { transform: rotate(5deg);  animation-timing-function: cubic-bezier(.25,.6,.4,1); }
  58%       { transform: rotate(21deg); animation-timing-function: cubic-bezier(.6,0,.95,.4); }
  67%       { transform: rotate(0deg);  animation-timing-function: cubic-bezier(.2,.9,.4,1); }
  71%       { transform: rotate(3deg);  animation-timing-function: cubic-bezier(.4,0,.6,1); }
  80%, 100% { transform: rotate(0deg); }
}
@keyframes forge-etincelle {
  /* Trois éclats, calés sur les trois impacts de forge-frappe (19, 43, 67 %),
     puis plus rien. Une opacité qui retombe à zéro et une animation finie : le
     compositeur n'a plus rien à repeindre après 2,6 s. */
  0%, 18%   { opacity: 0; }
  19%       { opacity: .95; }
  26%, 42%  { opacity: 0; }
  43%       { opacity: .95; }
  50%, 66%  { opacity: 0; }
  67%       { opacity: .8; }
  74%, 100% { opacity: 0; }
}

@media (prefers-reduced-motion: no-preference) {
  /* `.js-anim` n'est posé par le script que si l'utilisateur n'a pas demandé
     moins de mouvement : la garde est double, et c'est voulu.
     Le retard de 1150 ms laisse le tracé des quatre couches se terminer
     (760 ms + 270 ms de retard sur la dernière) avant que l'outil ne bouge.
     `both` fige l'état final, soit le marteau posé. */
  .js-anim .anim.vu .forge__marteau,
  .js-anim .anim.vu .forge__etincelles {
    animation-duration: 2600ms;
    animation-delay: 1150ms;
    animation-iteration-count: 1;
    animation-fill-mode: both;
    animation-timing-function: linear;   /* chaque étape porte la sienne */
  }
  .js-anim .anim.vu .forge__marteau    { animation-name: forge-frappe; }
  .js-anim .anim.vu .forge__etincelles { animation-name: forge-etincelle; }
}

/* --------------------------------------------- 2. le pavé « À compléter » */
/* Il est VOULU voyant. Les trois pages neuves n'ont reçu aucun texte du
   client : ce qui manque est écrit dans la page plutôt que comblé par du
   plausible, et `outils/verifier.py` refuse « À COMPLÉTER » en production, ce
   qui interdit une mise en ligne par distraction.
   Or sur acier : 7,3:1, au-dessus du AA. Trait pointillé et titre en toutes
   lettres : la couleur n'est jamais le seul indice. */
.todo-client {
  border: 1px dashed var(--or);
  background: var(--acier);
  padding: var(--e6);
}
.todo-client__titre {
  margin: 0 0 var(--e4);
  font-family: var(--titre);
  font-size: var(--t-surtitre);
  /* 0,12 em : la valeur que le lot 01 donne à `.surtitre` depuis le
     « rapprocher les lettres » du client. 0,16 em détonnait. */
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--or);
}
.todo-client ul { margin: 0; padding-left: var(--e6); }
.todo-client li { margin: 0 0 var(--e2); color: var(--texte); }
.todo-client__pied {
  margin: var(--e4) 0 0;
  color: var(--gris);
  font-size: var(--t-legende);
}

/* ------------------------------ 3. sept vitrines au lieu de quatre, accueil */
/* `vitrines_ouvrages()` lit OUVRAGES : la section « Nos créations » de
   l'accueil passe donc de quatre à sept cartes, sur une grille de deux
   colonnes. La septième se retrouverait seule, avec un trou à sa droite.
   Elle prend la ligne entière, et sa photo passe en 21/9 : gardée en 4/3, une
   vitrine pleine largeur ferait un mur de 900 px de haut sur un grand écran.
   La règle est écrite sur `:last-child:nth-child(odd)`, elle se désarme donc
   toute seule si OUVRAGES revient à un nombre pair. */
@media (min-width: 700px) {
  .vitrines > li:last-child:nth-child(odd) { grid-column: 1 / -1; }
  .vitrines > li:last-child:nth-child(odd) .vitrine__media { aspect-ratio: 21 / 9; }
}

/* ------------------- 4. sept cartes et sept vignettes : les dernières rangées */
/* `cartes_ouvrages()` sert SEPT cartes sur /atelier/ et sur la 404, et SIX en
   pied de chaque page d'ouvrage (l'ouvrage courant est retiré).
   Le commentaire de `.cartes` dit la règle de la maison : « le nombre de
   colonnes est choisi pour que la dernière rangée tombe ronde », et « on ne
   centre jamais la dernière rangée ». Deux rattrapages suffisent. */
@media (min-width: 620px) and (max-width: 1199px) {
  /* Deux colonnes : sept cartes tombent en 3 rangées + 1. La dernière prend la
     ligne, comme le fait déjà `.cartes--trois li:last-child`. */
  .cartes--quatre > li:last-child:nth-child(odd) { grid-column: 1 / -1; }
}
@media (min-width: 1200px) {
  /* Six cartes en quatre colonnes donneraient 4 + 2. Trois colonnes donnent
     deux rangées pleines. Sept cartes restent en quatre colonnes (4 + 3), avec
     une seule case vide au bout. */
  .cartes--quatre:has(> li:nth-child(6)):not(:has(> li:nth-child(7))) {
    grid-template-columns: repeat(3, 1fr);
  }
}

/* Le panneau du menu porte les mêmes sept ouvrages en vignettes photo, sur
   deux colonnes. Même traitement pour la septième, avec un cadre plus plat :
   le panneau doit rester parcourable d'un écran de téléphone. */
.panneau__vitrines > li:last-child:nth-child(odd) { grid-column: 1 / -1; }
.panneau__vitrines > li:last-child:nth-child(odd) .vignette__photo { aspect-ratio: 3 / 1; }

/* ⚠️ AU-DELÀ DE 1 024 px, TROIS COLONNES AU LIEU DE DEUX. Mesuré au navigateur :
   sept vignettes sur deux colonnes donnent un corps de panneau de 1 146 px, et
   sur un écran de 760 px de haut les trois pages neuves tombaient sous la ligne
   de flottaison DU MENU — le seul endroit de la navigation où elles
   apparaissent, la barre restant à neuf onglets. Trois colonnes ramènent le
   corps à 686 px : les sept ouvrages se voient d'un coup d'oeil.

   Le seuil est 1 024 et non 720, où le panneau passe en deux colonnes : à
   768 px, la colonne des vignettes ne fait que 359 px et trois vignettes y
   tomberaient à 101 px de large, pour un libellé qui en demande 143. Entre 720
   et 1 023 px le panneau garde donc ses deux colonnes et se déroule, comme il
   le fait déjà sur un téléphone. Au-delà de 1 300 px il n'y a plus de bouton
   de menu : cette règle ne sert qu'entre les deux.

   `:nth-child(7):last-child` et non `:last-child:nth-child(odd)` : sur trois
   colonnes, seule une septième vignette est seule sur sa rangée. */
@media (min-width: 1024px) {
  .panneau__vitrines { grid-template-columns: repeat(3, 1fr); }
  .panneau__vitrines > li:last-child:nth-child(odd) { grid-column: auto; }
  .panneau__vitrines > li:last-child:nth-child(odd) .vignette__photo { aspect-ratio: 3 / 2; }
  .panneau__vitrines > li:nth-child(7):last-child { grid-column: 1 / -1; }
  .panneau__vitrines > li:nth-child(7):last-child .vignette__photo { aspect-ratio: 4 / 1; }
  /* Un cran de moins sur le libellé : dans une vignette de 160 px,
     « GARDE-CORPS » se coupait sur son trait d'union et « JARDIN D'HIVER »
     passait à la ligne, ce qui déformait la rangée entière (une grille
     s'aligne sur sa cellule la plus haute). Mesuré au navigateur. */
  .panneau__vitrines .vignette__nom {
    padding: var(--e2) var(--e3);
    font-size: 0.8125rem;
    letter-spacing: 0.08em;
  }
}

@media (prefers-reduced-motion: no-preference) {
  /* L'assemblage du panneau ne cascadait que jusqu'à la quatrième vignette.
     Sans ces trois retards, les vignettes 5 à 7 arriveraient AVANT les quatre
     premières, ce qui se voit immédiatement. */
  .panneau__vitrines li:nth-child(5) { animation-delay: 290ms; }
  .panneau__vitrines li:nth-child(6) { animation-delay: 330ms; }
  .panneau__vitrines li:nth-child(7) { animation-delay: 370ms; }
}

/* ---- pages neuves (lot 14) : fin du bloc ---- */

/* >>> r2-16 : les interlettrages restés en arrière (28/08/2026) */
/* ⚠️ DEUX FOIS LE MÊME PIÈGE, PAYÉ ICI. Un commentaire CSS n'a pas de niveaux :
   il se ferme à la PREMIÈRE fermeture rencontrée, et ce qui suit devient un
   sélecteur invalide qui avale la règle d'après. Elle est alors présente dans le
   fichier, jamais appliquée, et rien ne le signale — ni erreur, ni console.
   Mesuré les deux fois : .hero__pied li restait à 2,2px là où la règle demandait
   1,76px.
     1. le marqueur au-dessus est un commentaire COMPLET ; enchaîner derrière des
        lignes en etoile puis une fermeture orpheline le casse ;
     2. et ce commentaire-ci, qui expliquait le piege, contenait la sequence de
        fermeture ecrite en toutes lettres — donc se coupait en son milieu.
   D'ou : aucune sequence de fermeture dans le corps d'un commentaire, et chaque
   commentaire de ce bloc s'ouvre et se ferme sur lui-meme.

   Mesuré au navigateur APRÈS le lot 01 : les sélecteurs ci-dessous n'avaient pas
   bougé, alors qu'ils sont les plus espacés de la page. Aucun ne descend bas : ce
   sont tous des CAPITALES, qui se resserrent beaucoup moins que le bas de casse
   sans devenir illisibles. */

/* La ligne de repères sous le hero — la plus espacée du site, 0.20em. */
.hero__pied li { letter-spacing: 0.16em; }

/* Les en-têtes du tableau « Pourquoi le sur-mesure ». */
.comparatif thead th { letter-spacing: 0.13em; }

/* « Découvrir » sous chaque vitrine d'ouvrage, et le numéro qui l'accompagne. */
.vitrine__fleche { letter-spacing: 0.13em; }
.vitrine__num { letter-spacing: 0.13em; }

/* Les titres de secteur de /zone-interventions/ et celui de la carte de France. */
.communes h3 { letter-spacing: 0.13em; }
.portee__titre { letter-spacing: 0.13em; }

/* Le sommaire des articles de conseils. */
.sommaire__titre { letter-spacing: 0.13em; }

/* Les libellés du formulaire et la numérotation des étapes. */
.champ label { letter-spacing: 0.13em; }
.etapes li::before { letter-spacing: 0.13em; }

/* Les noms de villes DANS le SVG de la carte. ⚠️ `letter-spacing` s'y exprime en
 * unités du viewBox, pas en em : la valeur rendue dépend donc de `font-size`, qui
 * vaut 23 (26 pour l'atelier, 30 et 33 sous 700 px). Premier jet posé à 3px — soit
 * exactement ce qui existait déjà, 3/24 = 0,125em : mesuré après coup, rien n'avait
 * bougé. C'est le piège de l'unité relative déguisée en absolue. 2,5px ramène le
 * rendu à ~0,105em, cohérent avec les autres capitales du site. */
.portee__nom { letter-spacing: 2.5px; }

/* Et la MÊME chose sur l'autre carte, celle de la Vendée : ses étiquettes sont
 * un `<text class="etiquette">` réglé à 3px sur une police de 24, soit 0,125em.
 * Deux cartes, deux sélecteurs — la première mesure n'avait vu que celle-ci,
 * parce que le script de relevé ne lisait pas les classes des éléments SVG et
 * les rangeait toutes sous la même clé. Corrigé dans mesurer-lettrage.py. */
.carte-lieu .etiquette { letter-spacing: 2.5px; }

/* <<< r2-16 */

/* >>> r2-17 : le logo du département de la Vendée (28/08/2026) */
/* Le logo est servi à DEUX endroits, dans deux contextes différents :
     · dans les repères chiffrés de l'accueil et de /atelier/, sous `.reperes` ;
     · sur /contact/, par un appel direct, HORS de `.reperes`.
   D'où deux jeux de règles. Le premier habille le logo partout ; le second ne
   corrige que ce que la feuille écrase sous `.reperes`. Écrire le tout sous
   `.reperes` laissait la page contact sans style — constaté en comptant les
   occurrences page par page, pas en relisant la feuille. */

/* --- 1. le logo, dans n'importe quel contexte ------------------------------ */
.logo-vendee { display: block; text-align: center; }
.logo-vendee__pastille {
  display: inline-flex; align-items: center; justify-content: center;
  /* Sans borne, la pastille s'étire sur toute la colonne pour un logo de 47 px —
     un grand rectangle blanc au milieu d'une page nuit. `margin-inline` centre
     même si elle repasse en `block` : le centrage ne suppose rien du `display`. */
  width: max-content; margin-inline: auto;
  background: #fff; padding: 9px 12px;
}
.logo-vendee__pastille img { display: block; height: 72px; width: auto; }
.logo-vendee__mention {
  display: block; margin-top: var(--e4);
  font-family: var(--titre); font-size: var(--t-surtitre);
  letter-spacing: 0.12em; text-transform: uppercase; color: var(--mut);
  text-align: center;
}

/* --- 2. la surcharge, sous .reperes seulement ------------------------------ */
/* ⚠️ La feuille porte `.reperes span { display: block; letter-spacing: .18em }`,
   de spécificité (0,1,1) : elle bat un simple `.logo-vendee__pastille` (0,1,0).
   Mesuré avant correction : la pastille était calculée en `block` au lieu
   d'`inline-flex`, donc collée à 84 px du centre de sa colonne, et la mention
   prenait 0,18em au lieu des 0,12em demandés. La règle était bien dans le
   fichier — elle perdait la cascade, ce qui ne se voit nulle part.
   `.reperes .logo-vendee__pastille` vaut (0,2,0) et passe devant. */
.reperes .logo-vendee__pastille {
  display: inline-flex; width: max-content; margin-inline: auto;
}
.reperes .logo-vendee__mention { display: block; letter-spacing: 0.12em; }

@media (max-width: 600px) {
  .logo-vendee__pastille img { height: 58px; }
  .logo-vendee__pastille { padding: 8px 11px; }
}

/* <<< r2-17 */

/* >>> patch-r3-03-logo-vendee-or : début — ne pas écrire à l’intérieur */
/* Le cartouche du logo Vendée — retour client du 29/08/2026
   « Peut on avoir un truc avec des contour doré. Comme les autre logo ce serait
     plus précieux je pense »

   La pastille blanche reste (le logo porte un bloc-texte noir et ne se recolore
   pas) ; elle est encadrée de deux filets d'or séparés par le fond de la page.
   `outline` + `outline-offset` plutôt que des box-shadow empilées : l'offset
   laisse voir le fond RÉEL, nuit sur l'accueil comme lin sur /contact/, là où
   une box-shadow opaque aurait imposé une couleur en dur. */

.logo-vendee__pastille {
  /* le filet intérieur, au contact du blanc */
  border: 1px solid var(--or);
  /* le filet extérieur, en retrait : le vide entre les deux montre le fond */
  outline: 1px solid var(--or-sourd);
  outline-offset: 5px;
  /* `outline` déborde de la boîte : sans marge, le filet extérieur se fait
     rogner par la grille des repères sur téléphone. */
  margin-block: 8px;
}

/* Sous `.reperes`, la feuille rétablit `margin-inline: auto` pour le centrage
   (spécificité 0,2,0). `margin-block` y est donc reposé, sinon la règle courte
   ci-dessus est écrasée par le raccourci et le filet extérieur se fait rogner. */
.reperes .logo-vendee__pastille { margin-block: 8px; }

@media (max-width: 600px) {
  /* Le logo passe de 72 à 58 px : l'écart des filets suit, sinon le cartouche
     paraît lâche autour d'une image plus petite. */
  .logo-vendee__pastille { outline-offset: 4px; margin-block: 7px; }
  .reperes .logo-vendee__pastille { margin-block: 7px; }
}
/* <<< patch-r3-03-logo-vendee-or : fin */

/* >>> patch-r3-04-nuancier-eventail : début — ne pas écrire à l’intérieur */
/* Le pictogramme du nuancier — retour client du 29/08/2026, deuxième version.

   La première était un éventail de 26 lames en aplats de couleur. Joseph l'a
   retirée le jour même : « le ral c'est moche, met juste l'icone ». Vingt-six
   aplats saturés dans une page qui n'a que des filets d'or, c'est un corps
   étranger — le site tient par le trait, pas par l'effet.

   Le picto se déploie couche par couche comme les neuf autres : sa mécanique
   vit dans le bloc « pictogrammes » de la feuille, il n'y a rien à ajouter. */

.nuancier__embleme {
  display: flex;
  justify-content: center;
  margin: var(--e6) 0 var(--e5);
}

/* ⚠️ La graisse suit la taille servie : 0,59 x 128 / 64 = 1,18 px rendu, le
   filet du site. Toucher à `width` sans refaire ce calcul désaccorde ce picto
   de tous les autres. */
.nuancier__picto { width: 128px; height: 128px; stroke-width: 0.59; }

@media (max-width: 600px) {
  .nuancier__picto { width: 102px; height: 102px; stroke-width: 0.74; }
}

/* --- Au large, le picto REJOINT LE TITRE -----------------------------------

   Servi seul entre le chapeau et la liste, il flottait : 128 px au milieu d'une
   section de 1 140, avec deux cents pixels de vide au-dessus et en dessous. Un
   pictogramme qui flotte se lit comme une décoration ; posé contre le titre, il
   annonce la section.

   ⚠️ C'est la GRILLE qui place, le DOM ne bouge pas — et c'est la raison du
   choix. Les révélations du site ciblent les ENFANTS DIRECTS de `.contenu.anim`
   (`.anim.vu > *`, et `.anim > .filet` qui tire le filet de gauche à droite).
   Emballer le titre dans un conteneur aurait sorti quatre éléments de cette
   portée : le filet aurait cessé de se tirer, et les autres d'entrer en
   cascade. Rien ne l'aurait signalé — le bloc serait simplement apparu d'un
   coup. `grid-column` obtient la même composition sans toucher à la parenté.

   1 000 px est le seuil : en dessous, une colonne de 200 px prise au texte le
   serre plus qu'elle ne l'aide. */
@media (min-width: 1000px) {
  .nuancier .contenu {
    display: grid;
    grid-template-columns: 200px minmax(0, 1fr);
    column-gap: var(--e12);
    align-items: start;
  }
  .nuancier .surtitre,
  .nuancier h2,
  .nuancier .filet,
  .nuancier .prose-large { grid-column: 2; }

  /* Le picto tient la colonne de gauche sur toute la hauteur du bloc titre,
     et se centre dessus. `grid-row` est explicite : sans lui, l'ordre du DOM
     le placerait après la prose. */
  .nuancier__embleme {
    grid-column: 1;
    grid-row: 1 / span 4;
    align-self: center;
    margin: 0;
  }
  .nuancier__picto { width: 168px; height: 168px; stroke-width: 0.45; }  /* 168 px -> 1,18 px */

  /* La liste et la mention reprennent toute la largeur : ce sont elles qui
     portent l'information, elles n'ont pas à se serrer dans une colonne. */
  .nuancier__grille,
  .nuancier__mention { grid-column: 1 / -1; }
}

/* Les six teintes ajoutées à la liste — c'est ICI que la couleur reste, et
   c'est là qu'elle sert : à côté d'un code et d'un nom. (Les six premières sont
   posées par patch-r2-12-nuancier-ral.py.) */
.nuancier__pastille--ral-6005 { background: #0F4336; }
.nuancier__pastille--ral-5011 { background: #1A2B3C; }
.nuancier__pastille--ral-3005 { background: #59191F; }
.nuancier__pastille--ral-1019 { background: #9E8B71; }
.nuancier__pastille--ral-8017 { background: #442F29; }
.nuancier__pastille--ral-6009 { background: #27352A; }
/* <<< patch-r3-04-nuancier-eventail : fin */

/* >>> actualités */
/* =========================================================================
   LA RUBRIQUE ACTUALITÉS
   Les pages sont rendues par PHP à partir du gabarit de build.py : elles
   n'ont donc droit qu'aux classes qui existent déjà. Ce bloc n'ajoute que
   ce qu'aucune page du site ne savait faire : une carte à vignette, une
   photo de tête, une galerie et une pagination.
   ========================================================================= */

/* une carte d'actualité : la vignette occupe toute la largeur de la carte,
   le texte garde le retrait des autres cartes du site */
.note--actu { padding: 0; overflow: hidden; }
.note__photo { display: block; background: var(--nuit-creux); }
.note__photo img {
  display: block; width: 100%; height: auto;
  aspect-ratio: 4 / 3; object-fit: cover;
  filter: saturate(.92) contrast(1.02);
  transition: transform var(--duree-lente, 680ms) var(--courbe, ease-out);
}
.note--actu:hover .note__photo img { transform: scale(1.03); }
.note__texte { padding: var(--e6); display: flex; flex-direction: column; gap: var(--e3); }
.note__texte > * { margin: 0; }
.note__date {
  font-family: var(--titre);
  font-size: var(--t-surtitre);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  /* l'or sourd ne fait que 3,5:1 sur l'acier : sous le seuil AA d'un texte
     de cette taille. Le gris des légendes du site tient 6,2:1. */
  color: var(--gris);
  display: flex; align-items: center; gap: var(--e3); flex-wrap: wrap;
}
.note__brouillon {
  font-size: 0.6875rem; letter-spacing: 0.08em;
  color: var(--nuit); background: var(--or); padding: 2px var(--e2);
}

/* la photo de tête d'une actualité : pleine largeur du contenu, jamais de
   cadre net (les photos du client sont de définitions très inégales) */
.actu__figure { margin: 0 0 var(--e12); }
.actu__une {
  display: block; width: 100%; height: auto;
  max-height: 62vh; object-fit: cover;
}
.actu__avis {
  margin-top: var(--e6);
  border-left: 2px solid var(--or);
  padding: var(--e3) var(--e4);
  background: var(--acier);
  color: var(--texte);
  font-size: var(--t-legende);
}

/* une citation dans le corps d'un article */
.article blockquote {
  margin: var(--e8) 0;
  padding: var(--e2) 0 var(--e2) var(--e6);
  border-left: 1px solid var(--or-sourd);
}
.article blockquote p {
  margin: 0;
  font-size: var(--t-chapeau);
  line-height: 1.5;
  color: var(--blanc);
}

/* la galerie de fin d'article */
.actu__galerie { margin-top: var(--e16); }
.actu__galerie .filet { margin-bottom: var(--e8); }
.galerie-actu {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: var(--e4);
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
}
.galerie-actu li { margin: 0; }
.galerie-actu img {
  display: block; width: 100%; height: auto;
  aspect-ratio: 4 / 3; object-fit: cover;
  border: 1px solid var(--bordure);
}

/* la pagination : deux liens et un repère, rien de plus */
.pagination {
  margin-top: var(--e16);
  padding-top: var(--e6);
  border-top: 1px solid var(--bordure);
  display: flex; flex-wrap: wrap; align-items: baseline;
  justify-content: space-between; gap: var(--e4);
}
.pagination__liens { display: flex; flex-wrap: wrap; gap: var(--e8); }
.lien-fleche--retour::after { content: ""; }
.lien-fleche--retour::before {
  content: "\2190"; padding-right: var(--e2);
  display: inline-block; transition: transform var(--duree) ease-out;
}
.lien-fleche--retour:hover::before { transform: translateX(-5px); }

/* -------------------------------------------------- la barre à neuf onglets
   L'onglet « Actualités » fait le neuvième. Mesuré au navigateur : à 1 300 px
   la barre demandait 1 365 px pour 1 200 utiles, le document partait à
   1 438 px — et un débordement élargit le viewport, donc rapetisse toute la
   page sans que rien ne le signale.

   ⚠️ Ce réglage est ICI, en fin de feuille servie, et non dans le bloc
   « barre large » de modele/site.css : la refonte du 27/08 repose
   `.entete__interieur { gap }` et `.entete__logo img` à partir de 900 px,
   plus bas dans la feuille, et écrasait donc deux des quatre gestes. Le
   dernier bloc gagne : c'est celui-ci.

   Quatre gestes à 1 300 px, du plus payant au moins : la barre sort du
   gabarit de texte (+52), l'interlettrage tombe à 0,04em (−45), le logo perd
   28 px, les écarts se resserrent. L'air revient à 1 512 px, puis à 1 700 px
   où le gabarit s'élargit encore.
   Ces valeurs se REMESURENT à chaque onglet ajouté ou renommé. */
@media (min-width: 1360px) {
  .entete .contenu { max-width: 1480px; }
  .entete__interieur { gap: var(--e2); }
  .entete__logo img { width: 144px; height: 60px; }
  .nav__liste { gap: var(--e2); }
  .nav__lien { letter-spacing: 0.01em; font-size: 0.8125rem; }
  .entete__tel .bouton { padding-inline: var(--e3); letter-spacing: 0.04em; }
}
@media (min-width: 1512px) {
  .entete__interieur { gap: var(--e4); }
  .entete__logo img { width: 160px; height: 67px; }
  .nav__liste { gap: var(--e3); }
  .nav__lien { letter-spacing: 0.04em; font-size: 0.875rem; }
  .entete__tel .bouton { padding-inline: var(--e4); letter-spacing: 0.06em; }
}
@media (min-width: 1800px) {
  .entete .contenu { max-width: 1760px; }
  .entete__interieur { gap: var(--e8); }
  .entete__logo img { width: 172px; height: 72px; }
  .nav__liste { gap: var(--e6); }
  .nav__lien { letter-spacing: 0.10em; }
}
/* <<< fin actualités */
