/* ==========================================================================
   Groupe Serge Comtesse — feuille de style unique
   --------------------------------------------------------------------------
   Le brief demande une maison : historique, alsacienne, familiale, et
   pourtant haut de gamme. La page alterne donc deux régimes, et jamais
   autre chose :

     · les blocs « nuit » — noir profond, pleine largeur, une nappe de mèches
       en filigrane, très peu de texte en grandes capitales : on regarde ;
     · les blocs « jour » — ivoire, colonne étroite, filets or plutôt que
       boîtes : on lit.

   Trois interdits tiennent tout le reste : pas de carte arrondie à ombre
   douce, pas de grille de trois colonnes identiques, pas d'or sur l'ivoire
   en petit corps. Les deux premiers sont les réflexes de tout le monde, et
   un groupe de 22 salons qui les enchaîne n'appartient à personne. Le
   troisième est une question de contraste, expliquée plus bas.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Caractères — servis avec le site (voir outils/polices.sh)
   Cinzel pour les titres : une romaine à capitales gravées, demandée par le
   brief pour « le côté maison historique ». Elle n'a pas de bas-de-casse
   dessiné pour le texte courant, ce qui tombe bien — elle n'est employée
   qu'en capitales, et jamais en dessous de 13 px.
   Montserrat pour le texte : la géométrique du brief, très lisible en petit
   corps sur mobile.
   Les héberger nous-mêmes évite d'envoyer l'adresse IP de chaque visiteur à
   Google, ce que les mentions légales affirment ne pas faire.
   -------------------------------------------------------------------------- */
@font-face {
  font-family: 'Titres'; font-style: normal; font-weight: 400 900; font-display: swap;
  src: url('../fonts/titres-latin.woff2') 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: 'Titres'; font-style: normal; font-weight: 400 900; font-display: swap;
  src: url('../fonts/titres-latin-ext.woff2') 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: 'Texte'; font-style: normal; font-weight: 300 700; font-display: swap;
  src: url('../fonts/texte-latin.woff2') 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: 'Texte'; font-style: normal; font-weight: 300 700; font-display: swap;
  src: url('../fonts/texte-latin-ext.woff2') 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: 'Texte'; font-style: italic; font-weight: 300 500; font-display: swap;
  src: url('../fonts/texte-italique-latin.woff2') 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;
}

/* --------------------------------------------------------------------------
   Jetons

   Contrastes, tous vérifiés (voir outils/contrastes.py) :
     or       #D6AA53 sur noir    8.8 : 1   ✔ texte courant
     or       #D6AA53 sur ivoire  2.0 : 1   ✘ — ornements et filets seulement
     or-encre #7E611F sur ivoire  5.3 : 1   ✔ c'est l'or du texte sur clair
     gris     #55524C sur ivoire  7.2 : 1   ✔
     brume    #B7B7B7 sur noir    9.0 : 1   ✔

   D'où la règle qui revient le plus souvent dans ce fichier : sur l'ivoire,
   l'or ne trace que des filets ; dès qu'il porte du texte, il passe à
   --or-encre.
   -------------------------------------------------------------------------- */
:root {
  /* Le noir, l'or et le gris ne sont pas choisis : ils sont RELEVÉS sur le
     site actuel du groupe, dont le brief demande la cohérence
     (references/sergecomtesse/releve.json, valeurs calculées par le
     navigateur). C'est la même maison, ce sont donc les mêmes teintes. */
  --noir:         #101010;   /* fond du site actuel */
  --noir-doux:    #181818;
  --noir-relief:  #1D1D1D;   /* leur surface détachée, à l'octet près */
  --filet-nuit:   rgba(214, 170, 83, 0.24);
  --filet-nuit-2: rgba(255, 255, 255, 0.09);

  --ivoire:       #F7F5F1;
  --ivoire-creux: #EFEBE4;
  --blanc:        #FFFFFF;
  --filet-jour:   #DFD9CF;

  --or:           #D6AA53;   /* leur or, exactement */
  --or-clair:     #E7C57F;
  --or-encre:     #7E611F;   /* le même or, assombri pour porter du texte sur l'ivoire */
  --gris:         #55524C;
  --brume:        #B7B7B7;   /* leur gris de texte secondaire */

  --titres: 'Titres', 'Cinzel', 'Times New Roman', Times, serif;
  --texte:  'Texte', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
            Helvetica, Arial, sans-serif;

  /* Une seule échelle d'espacement, avec deux paliers fluides pour les
     respirations de section — c'est ce qui tient le rythme de la page. */
  --pas-1: 0.5rem;
  --pas-2: 1rem;
  --pas-3: 1.5rem;
  --pas-4: 2.25rem;
  --pas-5: 3.5rem;
  --pas-6: clamp(4rem, 8vw, 7rem);
  --pas-7: clamp(5.5rem, 11vw, 10rem);

  --gouttiere: clamp(1.25rem, 5vw, 4.5rem);
  --mesure: 38rem;          /* largeur de lecture confortable */
  --large: 78rem;           /* largeur maximale d'un bloc */

  --entete: 5.25rem;        /* hauteur de l'en-tête fixe */
}

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--entete) + 1rem);
}

body {
  margin: 0;
  background: var(--ivoire);
  color: var(--noir);
  font-family: var(--texte);
  font-size: clamp(1rem, 0.96rem + 0.2vw, 1.0625rem);
  font-weight: 300;
  line-height: 1.75;
  overflow-x: hidden;
  -moz-osx-font-smoothing: grayscale;
  -webkit-font-smoothing: antialiased;
}

img, svg { max-width: 100%; height: auto; display: block; }
[hidden] { display: none !important; }

/* --------------------------------------------------------------------------
   Titres et surtitres
   Cinzel n'existe qu'en capitales : on ne lui demande donc jamais de porter
   un paragraphe. Elle porte les titres, les chiffres et les noms de salon.
   L'interlettrage se resserre quand le corps grandit, sinon un grand titre
   se délite.
   -------------------------------------------------------------------------- */
h1, h2, h3, h4 {
  font-family: var(--titres);
  font-weight: 400;
  text-transform: uppercase;
  line-height: 1.14;
  margin: 0;
  hyphens: none;
}

h1 {
  font-size: clamp(2.1rem, 1.1rem + 4.4vw, 4.6rem);
  letter-spacing: 0.045em;
  line-height: 1.06;
}
h2 {
  font-size: clamp(1.6rem, 1.1rem + 2.1vw, 2.75rem);
  letter-spacing: 0.06em;
}
h3 {
  font-size: clamp(1.15rem, 1rem + 0.7vw, 1.5rem);
  letter-spacing: 0.08em;
}
h4 {
  font-size: 1rem;
  letter-spacing: 0.1em;
}

/* Le surtitre — la petite ligne très espacée qui annonce la section. C'est
   elle qui donne au site son air de registre plutôt que de brochure. */
.surtitre {
  font-family: var(--texte);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--or-encre);
  margin: 0 0 var(--pas-3);
  display: flex;
  align-items: center;
  gap: 0.9rem;
}
/* Le filet qui prolonge le surtitre : il tient lieu de soulignement, et
   c'est le seul ornement qui se répète d'un bout à l'autre du site. */
.surtitre::after {
  content: '';
  flex: 0 0 auto;
  width: clamp(1.5rem, 5vw, 3.25rem);
  height: 1px;
  background: currentColor;
  opacity: 0.5;
}
.surtitre--centre { justify-content: center; }
.surtitre--centre::before {
  content: '';
  width: clamp(1.5rem, 5vw, 3.25rem);
  height: 1px;
  background: currentColor;
  opacity: 0.5;
}

p { margin: 0 0 var(--pas-3); }
p:last-child { margin-bottom: 0; }

.chapeau {
  font-size: clamp(1.0625rem, 1rem + 0.5vw, 1.3125rem);
  line-height: 1.65;
  font-weight: 300;
  color: var(--gris);
}

.exergue {
  font-family: var(--titres);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: clamp(1.05rem, 0.95rem + 0.6vw, 1.4rem);
  line-height: 1.4;
}

a { color: inherit; }

/* --------------------------------------------------------------------------
   Utilitaires — et pourquoi ils existent

   La politique de sécurité du site n'accorde pas 'unsafe-inline' à
   style-src : le navigateur IGNORE donc tout attribut style="…". C'est
   voulu — c'est aussi ce qui empêche Netlify d'injecter sa barre et son
   badge — mais cela interdit d'écrire le moindre style dans le HTML.

   Ces quelques classes couvrent ce qu'on écrivait en ligne : des
   respirations, deux largeurs de lecture, trois tailles de note. Elles sont
   volontairement peu nombreuses ; tout le reste appartient aux composants.

   outils/contrastes.py échoue si un attribut style= réapparaît dans une
   page produite : la faute ne peut donc pas revenir en silence.
   -------------------------------------------------------------------------- */
.sans-marge { margin: 0; }
.espace-2 { margin-top: var(--pas-2); }
.espace-3 { margin-top: var(--pas-3); }
.espace-4 { margin-top: var(--pas-4); }
.espace-5 { margin-top: var(--pas-5); }
.espace-6 { margin-top: var(--pas-6); }
.espace-menu { margin-top: 0.6rem; }
.intertitre-bassin { margin: var(--pas-5) 0 var(--pas-2); }
.pleine-largeur { width: 100%; }
.hors-flux { position: absolute; }
.mesure-38 { max-width: 38rem; }
.mesure-34 { max-width: 34rem; }

/* Les trois tailles de note. Sur les blocs nuit, la couleur suit d'elle-même :
   le gris chaud n'y passerait pas le contraste. */
.note        { font-size: 0.875rem;  color: var(--gris); }
.note-moyenne{ font-size: 0.9375rem; color: var(--gris); }
.note-menue  { font-size: 0.8125rem; color: var(--gris); }
.bloc--nuit .note,
.bloc--nuit .note-moyenne,
.bloc--nuit .note-menue { color: var(--brume); }

/* Un « à venir » employé comme phrase entière, et non comme étiquette :
   l'italique du losange conviendrait à un mot, pas à une ligne. */
.droit { font-style: normal; }

/* Un nom mis en avant dans un paragraphe posé sur le noir. */
.sur-noir-fort { color: var(--blanc); font-weight: 400; }

/* --------------------------------------------------------------------------
   Régimes de bloc
   -------------------------------------------------------------------------- */
.bloc {
  padding-block: var(--pas-7);
  padding-inline: var(--gouttiere);
  position: relative;
}
.bloc--serre { padding-block: var(--pas-6); }

.bloc--nuit {
  background: var(--noir);
  color: var(--blanc);
}
/* « .appel » est une bande sombre qui n'est PAS un bloc--nuit : elle gardait
   l'or d'encre et le gris d'encre, faits pour l'ivoire, et son chapeau
   tombait à 2,44 : 1 sur le noir. Le contrôle par paires ne pouvait pas le
   voir — les deux couleurs y figurent, chacune sur SON fond. C'est
   outils/contraste-rendu.js qui l'a trouvé, sur la page rendue. */
.bloc--nuit .surtitre,
.appel .surtitre { color: var(--or); }
.bloc--nuit .chapeau,
.appel .chapeau { color: var(--brume); }

.bloc--jour {
  background: var(--ivoire);
  color: var(--noir);
}
.bloc--creux { background: var(--ivoire-creux); }

/* La nappe de mèches : posée en filigrane sur les blocs nuit, jamais sur
   l'ivoire — sur fond clair elle se lirait comme une rayure. */
.bloc--meches::before {
  content: '';
  position: absolute;
  inset: 0;
  background: url('../img/motif/nappe.svg') center / cover no-repeat;
  /* Très en retrait : à 0,55 les mèches passaient dans les citations et les
     hachaient. Le motif doit se deviner, pas se lire. */
  opacity: 0.28;
  pointer-events: none;
}
.bloc--meches > * { position: relative; }

.centre { max-width: var(--large); margin-inline: auto; }
.mesure { max-width: var(--mesure); }
.mesure--centre { max-width: var(--mesure); margin-inline: auto; }
.texte-centre { text-align: center; }

/* --------------------------------------------------------------------------
   Lien d'évitement
   -------------------------------------------------------------------------- */
.saut {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 200;
  background: var(--noir);
  color: var(--or);
  padding: 0.85rem 1.25rem;
  font-size: 0.8125rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-decoration: none;
}
.saut:focus { left: 0; }

:where(a, button, input, select, textarea, summary):focus-visible {
  outline: 2px solid var(--or);
  outline-offset: 3px;
}
.bloc--jour :where(a, button, input, select, textarea, summary):focus-visible {
  outline-color: var(--or-encre);
}

/* --------------------------------------------------------------------------
   En-tête
   L'en-tête est noire partout, y compris par-dessus le grand titre de
   l'accueil. Une en-tête qui change de couleur au défilement demande de
   surveiller un état, et se trompe une fois sur dix — sur un site de 30
   pages, mieux vaut une barre qui ne mente jamais.
   -------------------------------------------------------------------------- */
.entete {
  position: sticky;
  top: 0;
  z-index: 100;
  background: var(--noir);
  border-bottom: 1px solid var(--filet-nuit);
  padding-inline: var(--gouttiere);
}
.entete__interieur {
  max-width: var(--large);
  margin-inline: auto;
  min-height: var(--entete);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--pas-3);
}
.entete__marque { display: block; flex: 0 0 auto; }
/* Le logo du client est plus trapu que le logotype qu’il remplace —
   3,31 de rapport au lieu de 5 — et paraissait donc rétréci à hauteur
   égale. On le remonte en hauteur, ce que la barre supporte : au point
   le plus serré (1121 px, juste avant le menu replié), il reste 155 px
   de marge entre le logo, la navigation et le bouton. Mesuré. */
.entete__marque img { height: clamp(2.1rem, 3.6vw, 2.55rem); width: auto; }

.nav { display: flex; align-items: center; gap: clamp(0.9rem, 1.8vw, 1.7rem); }
.nav__liste {
  display: flex;
  align-items: center;
  gap: clamp(0.9rem, 1.8vw, 1.7rem);
  list-style: none;
  margin: 0;
  padding: 0;
}
.nav__lien {
  display: inline-block;
  font-size: 0.75rem;
  font-weight: 400;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--blanc);
  padding-block: 0.35rem;
  position: relative;
  white-space: nowrap;
  transition: color 0.25s;
}
.nav__lien::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 1px;
  background: var(--or);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.3s;
}
.nav__lien:hover { color: var(--or-clair); }
.nav__lien:hover::after,
.nav__lien[aria-current='page']::after { transform: scaleX(1); }
.nav__lien[aria-current='page'] { color: var(--or); }

/* --------------------------------------------------------------------------
   Boutons
   Deux seulement : l'or plein pour l'action attendue, le contour pour tout
   le reste. Rien n'est arrondi : la maison est gravée, pas moulée.
   -------------------------------------------------------------------------- */
.bouton {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.7rem;
  font-family: var(--texte);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  text-decoration: none;
  padding: 1.05rem 1.9rem;
  border: 1px solid transparent;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color 0.28s, color 0.28s, border-color 0.28s;
}
.bouton--or {
  background: var(--or);
  color: var(--noir);
  border-color: var(--or);
}
.bouton--or:hover { background: var(--or-clair); border-color: var(--or-clair); }

.bouton--contour {
  background: transparent;
  color: var(--or);
  border-color: var(--filet-nuit);
}
.bouton--contour:hover { border-color: var(--or); background: rgba(214, 170, 83, 0.08); }

/* Sur l'ivoire, le contour passe à l'encre : l'or clair y serait illisible. */
.bloc--jour .bouton--contour,
.bouton--contour-encre {
  color: var(--noir);
  border-color: var(--noir);
}
.bloc--jour .bouton--contour:hover,
.bouton--contour-encre:hover { background: var(--noir); color: var(--ivoire); }

.bouton--menu {
  display: none;
  background: none;
  border: 0;
  padding: 0.6rem;
  margin-right: -0.6rem;
  color: var(--blanc);
}
.bouton--menu svg { width: 26px; height: 26px; }

.bouton--compact { padding: 0.8rem 1.35rem; }

.boutons { display: flex; flex-wrap: wrap; gap: var(--pas-2); }
.boutons--centre { justify-content: center; }
/* Deux liens-flèches côte à côte : ils gardent leur gouttière même
   quand ils passent à la ligne, ce que ne fait pas un simple <p>. */
.boutons--lignes { gap: var(--pas-2) var(--pas-4); margin: 0; }

/* Le lien fléché : employé partout où l'on quitte une section pour une page
   plus détaillée. */
.lien-fleche {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--or-encre);
  border-bottom: 1px solid currentColor;
  padding-bottom: 0.3rem;
  transition: gap 0.25s, color 0.25s;
}
.lien-fleche::after { content: '→'; font-size: 1em; letter-spacing: 0; }
.lien-fleche:hover { gap: 1rem; }
.bloc--nuit .lien-fleche { color: var(--or); }

/* --------------------------------------------------------------------------
   Menu mobile — plein écran, ouvert par le bouton de l'en-tête
   -------------------------------------------------------------------------- */
.voile {
  position: fixed;
  inset: 0;
  z-index: 150;
  background: var(--noir);
  display: flex;
  flex-direction: column;
  padding: var(--pas-4) var(--gouttiere) var(--pas-5);
  overflow-y: auto;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.3s, visibility 0.3s;
}
.voile[data-ouvert] { opacity: 1; visibility: visible; }
.voile__haut { display: flex; align-items: center; justify-content: space-between; }
.voile__haut img { height: 2.2rem; width: auto; }
.voile__fermer { background: none; border: 0; color: var(--blanc); padding: 0.6rem; margin-right: -0.6rem; }
.voile__fermer svg { width: 26px; height: 26px; }
.voile__liste {
  list-style: none;
  margin: var(--pas-5) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
}
.voile__liste li { border-top: 1px solid var(--filet-nuit-2); }
.voile__liste li:last-child { border-bottom: 1px solid var(--filet-nuit-2); }
.voile__lien {
  display: block;
  padding: 1.15rem 0;
  font-family: var(--titres);
  font-size: 1.25rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--blanc);
}
.voile__lien[aria-current='page'] { color: var(--or); }
.voile__bas { margin-top: auto; padding-top: var(--pas-5); }
.voile__bas .bouton { width: 100%; }

/* --------------------------------------------------------------------------
   Accueil — le grand titre
   -------------------------------------------------------------------------- */
.accueil {
  background: var(--noir);
  color: var(--blanc);
  padding: var(--pas-7) var(--gouttiere) var(--pas-6);
  position: relative;
  overflow: hidden;
  min-height: min(86vh, 54rem);
  display: flex;
  align-items: center;
}
/* La photographie du bandeau. Elle n'occupe que la DROITE : le cliché est
   un portrait vertical, et l'étaler sur toute la largeur en rognerait la
   tête et les épaules pour ne garder qu'une tranche horizontale.
   « object-position » cale le cadrage sur le visage plutôt que sur le
   centre géométrique, qui tomberait sur le bras. */
.accueil__photo {
  position: absolute;
  inset: 0 0 0 auto;
  width: min(52%, 46rem);
  height: 100%;
  object-fit: cover;
  object-position: 54% 22%;
  pointer-events: none;
  /* Sans masque, le bord gauche de la photo trace une arête verticale nette
     en plein milieu du bandeau : le fond du studio et le noir de la page ne
     sont pas exactement le même noir, et l'œil voit la couture. Le dégradé
     la dissout sur un cinquième de la largeur. */
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 22%);
  mask-image: linear-gradient(90deg, transparent 0, #000 22%);
}
/* Un dégradé retient la nappe derrière le titre : sans lui, les mèches
   passent dans les capitales et les hachent. */
.accueil__voile {
  position: absolute;
  inset: 0;
  background: linear-gradient(100deg,
              var(--noir) 0%, var(--noir) 34%,
              rgba(16, 16, 16, 0.82) 55%, rgba(16, 16, 16, 0.35) 100%);
  pointer-events: none;
}
.accueil__interieur { position: relative; max-width: var(--large); margin-inline: auto; width: 100%; }
.accueil__titre { max-width: 20ch; }
.accueil__titre em {
  display: block;
  font-style: normal;
  color: var(--or);
}
.accueil__chapeau { max-width: 42ch; margin-top: var(--pas-4); }
.accueil .boutons { margin-top: var(--pas-5); }

/* L'invitation à descendre — discrète, et jamais par-dessus le texte. */
.descendre {
  position: absolute;
  left: 0;
  bottom: calc(-1 * var(--pas-5));
  display: inline-flex;
  align-items: center;
  gap: 0.75rem;
  font-size: 0.625rem;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--brume);
  text-decoration: none;
}
.descendre__trait {
  display: block;
  width: 3rem;
  height: 1px;
  background: var(--or);
  transform-origin: left;
  animation: filer 2.6s ease-in-out infinite;
}
@keyframes filer {
  0%, 100% { transform: scaleX(0.35); opacity: 0.5; }
  50%      { transform: scaleX(1);    opacity: 1; }
}

/* En-tête de page intérieure — même noir, sans la hauteur du grand titre. */
.chapiteau {
  background: var(--noir);
  color: var(--blanc);
  padding: var(--pas-6) var(--gouttiere);
  position: relative;
  overflow: hidden;
}
.chapiteau__meches {
  position: absolute;
  inset: 0;
  background: url('../img/motif/filet.svg') center / cover no-repeat;
  opacity: 0.5;
  pointer-events: none;
}
.chapiteau__interieur { position: relative; max-width: var(--large); margin-inline: auto; }
/* Un chapiteau qui porte une photographie, à côté du titre et non derrière :
   un texte posé sur un cliché demande de vérifier le contraste pixel par
   pixel à chaque changement de photo, et ce chapiteau-ci n'a pas besoin de
   ça pour faire son travail. Les cinq autres pages gardent le chapiteau nu.
   Les proportions : le texte garde la part principale, la photographie
   occupe ce qui restait vide à droite. */
.chapiteau--photo .chapiteau__interieur {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.75fr);
  gap: var(--pas-5) clamp(2rem, 5vw, 4.5rem);
  align-items: center;
}
.chapiteau--photo .chapiteau__texte { min-width: 0; }
.chapiteau__photo {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  object-position: 50% 30%;
  background: var(--noir-doux);
}
.chapiteau .surtitre { color: var(--or); }
.chapiteau__chapeau { color: var(--brume); max-width: 52ch; margin-top: var(--pas-3); }

/* Fil d'Ariane */
.fil {
  font-size: 0.6875rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--brume);
  margin-bottom: var(--pas-3);
}
.fil a { text-decoration: none; color: var(--or); }
.fil a:hover { text-decoration: underline; }
.fil span { opacity: 0.5; margin-inline: 0.5rem; }

/* --------------------------------------------------------------------------
   Bandeau de chiffres
   Quatre chiffres, séparés par des filets verticaux. Ils ne sont pas dans
   une grille régulière : le premier et le dernier respirent davantage, ce
   qui empêche le bandeau de ressembler à un tableau de bord.
   -------------------------------------------------------------------------- */
.chiffres {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: var(--pas-4) 0;
  max-width: var(--large);
  margin-inline: auto;
}
.chiffre { padding-inline: clamp(1rem, 3vw, 2.5rem); border-left: 1px solid var(--filet-nuit); }
.chiffre:first-child { border-left: 0; padding-left: 0; }
.chiffre__valeur {
  display: block;
  font-family: var(--titres);
  font-size: clamp(2.2rem, 1.4rem + 2.6vw, 3.4rem);
  line-height: 1;
  color: var(--or);
  letter-spacing: 0.02em;
}
.chiffre__libelle {
  display: block;
  margin-top: 0.8rem;
  font-size: 0.75rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--brume);
}

/* --------------------------------------------------------------------------
   Duo — un texte et un panneau, en colonnes inégales
   C'est la structure de base des sections de contenu : jamais 50/50.
   -------------------------------------------------------------------------- */
.duo {
  display: grid;
  gap: var(--pas-6) clamp(2rem, 6vw, 5.5rem);
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
  align-items: start;
  max-width: var(--large);
  margin-inline: auto;
}
.duo--inverse { grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr); }
.duo--large   { grid-template-columns: minmax(0, 1fr) minmax(0, 1.6fr); }
.duo__aside { position: sticky; top: calc(var(--entete) + var(--pas-4)); }

/* Quand la colonne de gauche ne porte qu'un surtitre et un titre, deux
   choses la font lire comme à moitié vide :

     · les proportions étaient à l'envers — le duo donne 1,15 à gauche et
       0,85 à droite, donc la colonne LARGE portait trois mots et le texte
       se comprimait dans l'étroite. On les échange ;
     · elle restait creuse sur toute la hauteur du texte d'à côté. Le titre
       suit donc la lecture, comme l'encadré des fiches de salon.

   Posé uniquement là où la colonne se réduit vraiment à son titre :
   ailleurs, ce serait du contenu qu'on collerait. */
.duo--titre-colle {
  grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.5fr);
}
@media (min-width: 60.01rem) {
  .duo--titre-colle > :first-child {
    position: sticky;
    top: calc(var(--entete) + var(--pas-5));
    align-self: start;
  }
}

/* --------------------------------------------------------------------------
   Emplacement photo en attente
   Le client n'a pas encore fourni les visuels des salons et des équipes. Un
   trou se verrait ; un cadre dessiné, monogrammé et mèché se lit comme un
   parti pris. Le jour où les photos arrivent, on remplace le bloc par une
   <img> et le reste ne bouge pas.
   -------------------------------------------------------------------------- */
.attente {
  position: relative;
  overflow: hidden;
  background: var(--noir-doux);
  border: 1px solid var(--filet-nuit);
  aspect-ratio: 4 / 5;
  display: grid;
  place-items: center;
}
.attente--paysage { aspect-ratio: 16 / 10; }
.attente--bandeau { aspect-ratio: 21 / 9; }
.attente::before {
  content: '';
  position: absolute;
  inset: 0;
  background: url('../img/motif/colonne.svg') center / cover no-repeat;
  opacity: 0.7;
}
.attente__marque {
  position: relative;
  width: clamp(3.5rem, 9vw, 5.25rem);
  opacity: 0.75;
}
.attente__note {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  padding: 0.7rem 1rem;
  font-size: 0.625rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  text-align: center;
  color: var(--brume);
  background: linear-gradient(transparent, rgba(16, 16, 16, 0.9));
}

/* --------------------------------------------------------------------------
   Univers — la liste des concepts du groupe
   Des rangées pleine largeur séparées par des filets, avec un chiffre romain
   en or. Pas de cartes : trois blocs identiques côte à côte donneraient à
   l'ICE le même poids qu'un salon, ce qui est faux.
   -------------------------------------------------------------------------- */
.univers { max-width: var(--large); margin-inline: auto; }
.univers__rangee {
  display: grid;
  grid-template-columns: 4.5rem minmax(0, 1fr) minmax(0, 1.25fr);
  gap: var(--pas-3) clamp(1.5rem, 4vw, 3.5rem);
  align-items: baseline;
  padding-block: var(--pas-5);
  border-top: 1px solid var(--filet-nuit);
}
.univers__rangee:last-child { border-bottom: 1px solid var(--filet-nuit); }
.univers__numero {
  font-family: var(--titres);
  font-size: 0.875rem;
  letter-spacing: 0.2em;
  /* Le chiffre romain est du texte, et il se lit : il lui faut donc l'or qui
     convient à SON fond. L'or clair vaut 1,98 : 1 sur l'ivoire, l'or d'encre
     3,28 : 1 sur le noir — ni l'un ni l'autre ne passe partout. Les blocs
     « univers » existent dans les deux teintes, sur trois pages. */
  color: var(--or-encre);
}
.bloc--nuit .univers__numero,
.appel .univers__numero { color: var(--or); }
.univers__titre { margin-bottom: var(--pas-2); }
/* La photographie d'une rangée. Elle se pose SOUS le sous-titre, dans la
   colonne du milieu, qui était presque vide : le client a trouvé la section
   creuse, et elle l'était — deux lignes de texte en face de cinq.
   Le rapport est imposé pour que les quatre rangées s'alignent, quelles que
   soient les proportions des clichés d'origine. */
.univers__photo {
  display: block;
  width: 100%;
  height: auto;
  /* 3/2 et non 4/3 : en 4/3 la photographie faisait trois cents pixels de
     haut, la rangée en faisait cinq cents, et le vide que le client avait
     signalé au milieu réapparaissait à droite, sous un texte de quatre
     lignes. C'est aussi le format natif de la plupart de ces clichés, donc
     le recadrage prend moins. */
  aspect-ratio: 3 / 2;
  object-fit: cover;
  /* Par défaut, le tiers haut : c'est là que sont les visages sur la
     plupart de ces clichés. Mais pas sur tous — et un recadrage choisi une
     fois pour toutes coupait les deux élèves en bas d'une photo, les
     fauteuils de bac d'une autre, et laissait un mur occuper la moitié de
     la case. D'où les réglages ci-dessous, un par cliché qui en a besoin.
     Ils ne peuvent pas s'écrire en attribut « style » : la politique de
     sécurité du site refuse le style en ligne. */
  object-position: 50% 28%;
  margin-top: var(--pas-3);
  background: var(--noir-doux);
}
.univers__texte { color: var(--brume); }
.univers__texte .lien-fleche { margin-top: var(--pas-3); }

/* --------------------------------------------------------------------------
   Valeurs — cinq entrées, en deux colonnes de hauteurs inégales
   -------------------------------------------------------------------------- */
.valeurs {
  columns: 2;
  column-gap: clamp(2rem, 6vw, 5rem);
  max-width: var(--large);
  margin-inline: auto;
  list-style: none;
  padding: 0;
}
.valeurs li {
  break-inside: avoid;
  padding: var(--pas-4) 0;
  border-top: 1px solid var(--filet-jour);
}
.valeurs h3 { margin-bottom: 0.6rem; }
.valeurs p { color: var(--gris); margin: 0; }
.bloc--nuit .valeurs li { border-color: var(--filet-nuit); }
.bloc--nuit .valeurs p { color: var(--brume); }

/* --------------------------------------------------------------------------
   Le réseau — les bassins de vie et leurs communes
   -------------------------------------------------------------------------- */
.bassins { max-width: var(--large); margin-inline: auto; }
.bassin {
  display: grid;
  grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.6fr);
  gap: var(--pas-2) clamp(1.5rem, 5vw, 4rem);
  padding-block: var(--pas-4);
  border-top: 1px solid var(--filet-jour);
}
.bassin:last-child { border-bottom: 1px solid var(--filet-jour); }
.bassin__nom { display: flex; flex-direction: column; gap: 0.4rem; }
.bassin__compte {
  font-size: 0.6875rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--or-encre);
}
.bassin__resume { margin: 0 0 var(--pas-2); color: var(--gris); }
.bassin__communes { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 0.4rem 0; }
.bassin__communes li { display: inline; }
.bassin__communes li::after { content: '·'; color: var(--or); margin-inline: 0.55rem; }
.bassin__communes li:last-child::after { content: none; }
.bassin__communes a { text-decoration: none; border-bottom: 1px solid var(--filet-jour); transition: border-color 0.25s; }
.bassin__communes a:hover { border-color: var(--or-encre); }

/* --------------------------------------------------------------------------
   Carte du réseau

   Dessinée, servie avec le site, sans tuile ni script d'un domaine tiers —
   la politique de sécurité l'interdit, et on ne la desserre pas. Voir
   outils/carte.py pour la provenance des coordonnées.

   L'Alsace est haute et étroite : la carte occupe donc une colonne, et le
   texte l'autre. C'est le seul endroit du site où les deux colonnes sont de
   force comparable — ici, l'image porte autant que le mot.
   -------------------------------------------------------------------------- */
.duo--carte { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: start; }
@media (min-width: 60.01rem) {
  .duo--carte > :first-child {
    position: sticky;
    top: calc(var(--entete) + var(--pas-5));
  }
}

.carte { margin: 0; overflow: hidden; }
.carte__dessin { width: 100%; height: auto; display: block; }

/* Le contour : un filet or, et un aplat à peine détaché du fond. Pas de
   remplissage franc — la carte doit rester un dessin, pas un graphique. */
.carte__contour {
  fill: rgba(214, 170, 83, 0.05);
  stroke: var(--or);
  stroke-width: 1.6;
  stroke-opacity: 0.7;
  vector-effect: non-scaling-stroke;
}

/* En dessous de 60rem, la colonne de noms n'a pas la place : quatre noms de
   l'amas de Strasbourg se recouvriraient. On la retire, et on élargit le
   dessin pour que sa partie géographique — 1000 unités sur 1330 — occupe
   toute la largeur. Les noms restent accessibles : chaque point porte un
   <title>, et l'annuaire complet suit immédiatement. */
.carte__dit-points { display: none; }
@media (max-width: 60rem) {
  .carte__nom, .carte__amarre, .carte__cible { display: none; }
  /* Plus de noms sur le dessin : la légende change de phrase (cf. le
     commentaire dans construire.py). */
  .carte__dit-noms { display: none; }
  .carte__dit-points { display: block; }
  /* max-width vient du reset « img, svg » et plafonnerait les 133 % à 100 % :
     le dessin resterait cadré sur la gouttière vide. */
  /* 143 % = largeur du cadre / largeur de la partie géographique, soit
     1430 / 1000. Le chiffre vient de data/carte.json et doit le suivre :
     outils/contrastes.py échoue si les deux divergent — la gouttière a déjà
     été élargie une fois, et cette ligne serait restée en arrière. */
  .carte__dessin { width: 143%; max-width: none; }
}

/* --------------------------------------------------------------------------
   Les galeries de photographies
   Une bande de portraits ou de reportage, en grille qui se replie. Les
   clichés n'ont pas tous les mêmes proportions — studio en 2/3, coulisses en
   7/10, groupes en 3/4 — et les laisser tels quels ferait une frise en dents
   de scie. On impose donc un cadre commun et c'est le recadrage qui cède,
   pas l'alignement.
   -------------------------------------------------------------------------- */
.galerie { margin: 0; }
.galerie__grille {
  display: grid;
  /* « min(13rem, 100%) » et non « 13rem » : une piste dont le minimum
     dépasse la largeur disponible ne se replie pas, elle déborde. À 320 px,
     les grilles à 20 et 21 rem poussaient la page 36 px hors cadre. Le min()
     laisse la piste rétrécir quand il n'y a plus la place. */
  grid-template-columns: repeat(auto-fit, minmax(min(13rem, 100%), 1fr));
  gap: var(--pas-2);
}
.galerie img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  /* Les visages sont dans le tiers haut de presque tous ces clichés : un
     recadrage centré leur couperait le front. */
  object-position: 50% 22%;
  /* Pas de liseré. « --filet-nuit » est un or à 24 % : discret sur un aplat
     noir, où il sert de filet, il devient un cadre doré autour d'une
     photographie claire — et un cadre doré autour d'une photo, c'est du
     cadre de supermarché. Le fond ne sert plus qu'à tenir la place avant
     que l'image n'arrive. */
  background: var(--noir-doux);
}
/* Un cliché isolé, avec sa légende. Pas de grille, pas de rapport imposé :
   une archive se montre entière — son format fait partie de ce qu'elle
   raconte, et la rogner pour l'aligner sur une grille, c'est la dater une
   seconde fois. */
.cliche { margin: 0; }
/* « .cliche__image » nomme la même chose : un marqueur <!--CLICHE:...-->
   pose une classe sur l'image, et sans nom à lui donner elle n'en aurait
   aucune. Les deux sélecteurs désignent le même objet. */
.cliche img,
.cliche__image {
  display: block;
  width: 100%;
  height: auto;
  background: var(--noir-doux);
}
/* Un portrait posé à côté d'un chapeau de trois lignes. Laissé à ses
   proportions, il faisait six cent cinquante pixels de haut contre cent
   soixante de texte : le vide que le client avait signalé au milieu du bloc
   repassait simplement à gauche. Resserré en 4/5, et cadré haut pour garder
   le visage plutôt que les mains. */
.cliche--portrait img {
  aspect-ratio: 4 / 5;
  object-fit: cover;
  /* 10 % et non 18 % : à 18 la chevelure arrivait à quelques pixels du bord
     haut et le portrait paraissait à l'étroit. 10 laisse l'air que le
     photographe avait laissé, sans descendre jusqu'au dégradé clair du fond
     de studio, qui apparaît au-dessus de 5. */
  object-position: 50% 10%;
}

/* Une archive aplatie dans un PDF fait 350 px de large : étalée sur la
   colonne, elle serait floue. Elle s'arrête à sa propre définition. */
.cliche--menu img { max-width: 350px; }
.cliche--menu figcaption { max-width: 350px; }
.cliche figcaption {
  margin-top: var(--pas-2);
  font-size: 0.8125rem;
  line-height: 1.6;
  color: var(--gris);
  max-width: 46ch;
}
.bloc--nuit .cliche figcaption { color: var(--brume); }

.galerie__legende {
  margin-top: var(--pas-2);
  font-size: 0.8125rem;
  line-height: 1.6;
  /* La brume est le gris des fonds sombres. Sur l'ivoire d'un bloc clair,
     elle tombe à 1,9 : 1 — la légende de la page formation était illisible.
     Le gris d'encre prend le relais là, comme pour les autres notes du site. */
  color: var(--brume);
  max-width: 54ch;
}
.bloc--jour .galerie__legende,
.bloc--creux .galerie__legende { color: var(--gris); }
/* Deux photos seulement : une grille à deux colonnes les étirerait en
   vignettes perdues dans la largeur. On leur donne un format de reportage. */
.galerie--2 .galerie__grille { grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 1fr)); }
.galerie--2 img { aspect-ratio: 4 / 3; object-position: 50% 42%; }
/* Une seule photo n'a pas de voisine avec qui s'aligner : le cadre commun
   n'a plus d'objet, et l'imposer recadrerait une vitrine panoramique en
   portrait. Elle garde donc ses proportions — et une largeur plafonnée, car
   les clichés que le client a pu fournir pour ces salons-là font 680 px de
   large : étalés sur les 1150 px de la colonne, ils seraient flous. */
.galerie--1 img { aspect-ratio: auto; }
.galerie--1 .galerie__grille { grid-template-columns: minmax(0, 42rem); }
/* La grille par défaut tient cinq colonnes au plus. De une à cinq photos,
   elle les range sur une ligne pleine. Au-delà, elle laisse une orpheline
   sur la ligne du dessous : 5 + 1, 5 + 2. On élargit donc la colonne
   minimale pour ces deux cas, et les lignes redeviennent pleines — 3 + 3 et
   4 + 3 — avec des clichés plus grands par-dessus le marché. */
.galerie--6 .galerie__grille { grid-template-columns: repeat(auto-fit, minmax(min(21rem, 100%), 1fr)); }
.galerie--7 .galerie__grille { grid-template-columns: repeat(auto-fit, minmax(min(17rem, 100%), 1fr)); }

@media (max-width: 40rem) {
  /* Deux par ligne plutôt qu'une seule : cinq portraits empilés en pleine
     largeur font défiler l'écran six fois pour une bande d'illustration. */
  .galerie__grille { grid-template-columns: 1fr 1fr; }
  .galerie--2 .galerie__grille { grid-template-columns: 1fr; }
  /* La règle des six colonnes est plus spécifique que celle-ci et gagnait
     même ici : les six clichés de Miss Alsace s'empilaient sur une colonne,
     deux mille pixels de haut. Elle revient donc à deux par ligne. */
  .galerie--6 .galerie__grille,
  .galerie--7 .galerie__grille { grid-template-columns: 1fr 1fr; }
}

/* La photographie d'un salon, quand le client en a fourni une.
   Elle garde SES proportions : le repère qu'elle remplace est en 4/5, et
   forcer une vitrine panoramique dans ce cadre en rognerait les deux tiers.
   Le filet et le fond restent ceux du repère, pour que la colonne garde la
   même assise qu'un salon encore sans photo. */
.photo-salon {
  position: relative;
  overflow: hidden;
  background: var(--noir-doux);
}
.photo-salon img { display: block; width: 100%; height: auto; }

/* Les villes sans salon : présentes pour se repérer, jamais au premier plan. */
.carte__repere circle { fill: var(--brume); opacity: 0.5; }
.carte__repere text {
  fill: var(--brume);
  font-family: var(--texte);
  font-size: 26px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  opacity: 0.65;
}

.carte__nom {
  fill: var(--blanc);
  font-family: var(--texte);
  font-size: 28px;
  font-weight: 400;
  letter-spacing: 0.05em;
  transition: fill 0.2s;
}
/* Le nom est la vraie cible : il fait toute la largeur de la gouttière là
   où le point ne fait que neuf unités. Le rectangle qui le double rend la
   ligne cliquable sur toute sa hauteur — viser des lettres, c'est viser
   entre les lettres. Transparent, donc invisible ; présent, donc saisissable. */
.carte__cible { fill: transparent; }
.carte__salon:hover .carte__nom,
.carte__salon:focus-visible .carte__nom { fill: var(--or-clair); }
.carte__salon:hover .carte__amarre,
.carte__salon:focus-visible .carte__amarre { stroke-opacity: 1; }
.carte__amarre {
  stroke: var(--or);
  stroke-width: 1;
  stroke-opacity: 0.4;
  fill: none;
  vector-effect: non-scaling-stroke;
}

/* Le halo est transparent : il n'existe que pour élargir la cible. Sept
   pixels de rayon se visent mal à la souris et pas du tout au doigt. */
.carte__halo { fill: transparent; }
.carte__point {
  fill: var(--or);
  stroke: var(--noir);
  stroke-width: 3;
  r: 9;
  transition: fill 0.2s, r 0.2s;
}
.carte__salon { cursor: pointer; }
.carte__salon:hover .carte__point,
.carte__salon:focus-visible .carte__point { fill: var(--blanc); r: 13; }
.carte__salon:focus-visible { outline: none; }
.carte__salon:focus-visible .carte__halo {
  fill: rgba(214, 170, 83, 0.22);
  stroke: var(--or);
  stroke-width: 2;
}

.carte__legende { margin-top: var(--pas-4); }
.carte__hors {
  margin: var(--pas-3) 0 0.5rem;
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--or);
}
/* Le salon hors carte reprend la grille des salons voisins. Une seule
   cellule s'y étirerait sur toute la largeur de la colonne : on la borne à
   la largeur d'une cellule de cette grille. */
.carte__hors-liste { grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 20rem)); }

/* --------------------------------------------------------------------------
   Annuaire des salons — un registre, pas une galerie de cartes
   -------------------------------------------------------------------------- */
.filtres {
  display: flex;
  flex-wrap: wrap;
  gap: var(--pas-2) var(--pas-3);
  align-items: flex-end;
  padding-block: var(--pas-4);
  border-bottom: 1px solid var(--filet-jour);
  max-width: var(--large);
  margin-inline: auto;
}
.champ { display: flex; flex-direction: column; gap: 0.45rem; }
.champ label,
.formulaire label {
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--gris);
}
.champ select,
.champ input,
.formulaire input,
.formulaire select,
.formulaire textarea {
  font-family: var(--texte);
  font-size: 0.9375rem;
  font-weight: 300;
  color: var(--noir);
  background: var(--blanc);
  border: 1px solid var(--filet-jour);
  padding: 0.8rem 0.95rem;
  min-width: 12rem;
  border-radius: 0;
  appearance: none;
}
.champ select { padding-right: 2.4rem; background-image: linear-gradient(transparent, transparent); }
.champ__enveloppe { position: relative; display: inline-flex; }
.champ__enveloppe::after {
  content: '';
  position: absolute;
  right: 1rem; top: 50%;
  width: 0.45rem; height: 0.45rem;
  border-right: 1px solid var(--gris);
  border-bottom: 1px solid var(--gris);
  transform: translateY(-70%) rotate(45deg);
  pointer-events: none;
}
.filtres__compte {
  margin-left: auto;
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--gris);
  padding-bottom: 0.85rem;
}

.registre { max-width: var(--large); margin-inline: auto; list-style: none; margin-block: 0; padding: 0; }
.registre__vide {
  padding-block: var(--pas-6);
  text-align: center;
  color: var(--gris);
}
.salon-ligne {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.25fr) auto;
  gap: var(--pas-2) clamp(1.5rem, 4vw, 3.5rem);
  align-items: center;
  padding-block: var(--pas-4);
  border-bottom: 1px solid var(--filet-jour);
}
.salon-ligne__identite { display: flex; flex-direction: column; gap: 0.5rem; }
.salon-ligne__nom {
  font-family: var(--titres);
  font-size: clamp(1.1rem, 1rem + 0.5vw, 1.4rem);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  text-decoration: none;
  line-height: 1.2;
}
.salon-ligne__nom:hover { color: var(--or-encre); }
.salon-ligne__lieu {
  font-size: 0.75rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--gris);
}
.salon-ligne__accroche { color: var(--gris); }
.salon-ligne__actions { display: flex; flex-direction: column; gap: 0.55rem; align-items: flex-end; }

/* Dans le chapiteau d'une fiche, le fond est noir : l'or d'encre et le
   filet clair y perdent toute lisibilité. */
.chapiteau .etiquette { color: var(--or); border-color: var(--filet-nuit); }
.etiquettes { display: flex; flex-wrap: wrap; gap: 0.4rem; list-style: none; margin: 0; padding: 0; }
.etiquette {
  font-size: 0.625rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--or-encre);
  border: 1px solid var(--filet-jour);
  padding: 0.28rem 0.6rem;
}
.bloc--nuit .etiquette { color: var(--or); border-color: var(--filet-nuit); }

/* --------------------------------------------------------------------------
   Fiche salon
   -------------------------------------------------------------------------- */
.coordonnees { list-style: none; margin: 0; padding: 0; }
.coordonnees li {
  display: grid;
  grid-template-columns: 8.5rem minmax(0, 1fr);
  gap: 0.5rem var(--pas-2);
  padding-block: var(--pas-2);
  border-top: 1px solid var(--filet-jour);
}
.coordonnees li:last-child { border-bottom: 1px solid var(--filet-jour); }
.coordonnees dt,
.coordonnees__cle {
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--gris);
  padding-top: 0.35rem;
}
.coordonnees a { text-decoration: none; border-bottom: 1px solid var(--filet-jour); }
.coordonnees a:hover { border-color: var(--or-encre); }

/* Ce qui manque encore est dit, pas caché : une information absente et
   signalée est réparable, une information absente et muette ne l'est pas. */
.a-venir {
  color: var(--gris);
  font-style: italic;
}
.a-venir::before {
  content: '';
  display: inline-block;
  width: 0.5rem; height: 0.5rem;
  margin-right: 0.55rem;
  border: 1px solid var(--or-encre);
  transform: rotate(45deg);
}

.reseaux-salon { display: flex; flex-wrap: wrap; gap: var(--pas-2); }
.reseau-lien {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  text-decoration: none;
  border: 1px solid var(--filet-jour);
  padding: 0.7rem 1.05rem;
  transition: border-color 0.25s, background-color 0.25s;
}
.reseau-lien svg { width: 16px; height: 16px; flex: 0 0 auto; }
.reseau-lien:hover { border-color: var(--noir); background: var(--blanc); }
.bloc--nuit .reseau-lien { border-color: var(--filet-nuit); color: var(--blanc); }
.bloc--nuit .reseau-lien:hover { border-color: var(--or); background: rgba(214, 170, 83, 0.08); }

/* Les salons voisins, en pied de fiche */
.voisins {
  display: grid;
  /* auto-fit et non auto-fill : le fond du conteneur est ce qui dessine les
     filets entre les cellules, et une piste vide laissée par auto-fill se
     verrait donc comme une cinquième cellule grise. */
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 1px;
  background: var(--filet-nuit);
  border: 1px solid var(--filet-nuit);
  list-style: none;
  margin: 0;
  padding: 0;
}
.voisins a {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  height: 100%;
  padding: var(--pas-3);
  background: var(--noir);
  text-decoration: none;
  transition: background-color 0.25s;
}
.voisins a:hover { background: var(--noir-relief); }
.voisins__nom {
  font-family: var(--titres);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: 1rem;
}
.voisins__lieu { font-size: 0.75rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--brume); }

/* --------------------------------------------------------------------------
   Prestations
   -------------------------------------------------------------------------- */
.prestations { max-width: var(--large); margin-inline: auto; }
.prestation {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.5fr);
  gap: var(--pas-2) clamp(1.5rem, 5vw, 4rem);
  padding-block: var(--pas-5);
  border-top: 1px solid var(--filet-jour);
}
.prestation:last-child { border-bottom: 1px solid var(--filet-jour); }
.prestation__detail { color: var(--gris); }
.prestation__liste { list-style: none; margin: var(--pas-2) 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: 0.4rem 0; }
.prestation__liste li::after { content: '·'; color: var(--or); margin-inline: 0.55rem; }
.prestation__liste li:last-child::after { content: none; }

/* L'encart des tarifs : l'année se met à jour depuis main.js, pour qu'une
   grille laissée en place ne finisse pas par mentir sur sa date. */
.encart {
  border-left: 2px solid var(--or);
  background: var(--ivoire-creux);
  padding: var(--pas-4);
  max-width: 44rem;
}
.bloc--nuit .encart { background: var(--noir-doux); border-color: var(--or); }
.encart h3 { margin-bottom: var(--pas-2); }
.encart p { color: var(--gris); }
.bloc--nuit .encart p { color: var(--brume); }
.encart :last-child { margin-bottom: 0; }

/* --------------------------------------------------------------------------
   Le mot de la maison
   Le seul endroit du site où le texte est en italique et sans capitales :
   c'est une lettre d'accueil signée, pas une section de brochure, et elle
   doit se distinguer de tout le reste sans crier.
   -------------------------------------------------------------------------- */
.mot-maison {
  margin: 0;
  font-size: clamp(1.0625rem, 1rem + 0.45vw, 1.25rem);
  line-height: 1.8;
  color: var(--gris);
  border-left: 1px solid var(--or);
  padding-left: clamp(1.25rem, 3vw, 2.25rem);
}
.mot-maison p:first-child::first-letter {
  font-family: var(--titres);
  font-size: 2.6em;
  float: left;
  line-height: 0.86;
  margin: 0.1em 0.12em 0 0;
  color: var(--noir);
}
.mot-maison__signature {
  margin-top: var(--pas-3);
  padding-left: clamp(1.25rem, 3vw, 2.25rem);
  font-family: var(--titres);
  text-transform: uppercase;
  letter-spacing: 0.18em;
  font-size: 0.8125rem;
  color: var(--or-encre);
}
.mot-maison__signature::before { content: '— '; }

/* --------------------------------------------------------------------------
   La bande des logos (/prestations/#marques)
   À ne pas confondre avec .marques, la liste typographique de l'accueil, plus
   bas dans cette feuille : ici ce sont les logotypes eux-mêmes, fournis par
   le client, en version inversée parce que la section est sur fond noir.
   Quatre marques, quatre logotypes qui n'ont rien en commun : un mot long et
   bas, un monogramme haut et étroit, un cartouche carré. Leur donner la même
   HAUTEUR les déséquilibre ; on leur donne le même POIDS, ce qui se règle à
   l'œil, une marque à la fois. Les hauteurs ci-dessous sont celles de
   data/marques.json, écrites là parce que le CSS ne lit pas le JSON — les
   deux sont à tenir ensemble.
   -------------------------------------------------------------------------- */
.logos {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: clamp(2rem, 5vw, 4.5rem);
}
/* Sur l'accueil, la bande surplombe une grille de quatre fiches, une par
   marque. Centrée en ligne, elle les survolait toutes les quatre sans se
   caler sur aucune : le premier logo tombait au-dessus de la deuxième
   fiche. Elle reprend donc les MÊMES colonnes que la liste — même
   minmax(13rem, 1fr), même gouttière d'un pixel — pour qu'elles se brisent
   aux mêmes largeurs et que chaque logo reste au-dessus de sa fiche. */
.logos--colonnes {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  justify-items: center;
  align-items: center;
  gap: var(--pas-4) 1px;
  max-width: var(--large);
  margin-inline: auto;
}
.logo { display: block; width: auto; }
.logo--loreal { height: 1.75rem; }
.logo--kerastase { height: 1.3rem; }
.logo--american-crew { height: 3rem; }
.logo--mulato { height: 2.75rem; }

/* --------------------------------------------------------------------------
   Les vidéos
   Même traitement que les photographies : pas de liseré doré autour d'une
   image claire, un fond sombre pour tenir la place avant que l'affiche
   n'arrive, et les proportions de la source. Le lecteur natif du navigateur
   fait le reste — on ne lui substitue pas un lecteur maison pour trois
   boutons, ce serait du JavaScript à maintenir contre un navigateur qui sait
   déjà faire.
   -------------------------------------------------------------------------- */
.videos {
  display: grid;
  /* « minmax(0, …) » et non « 1fr » : une piste prend la largeur intrinsèque
     de son contenu, et une vidéo de 1280 px déborderait une page de 320. */
  grid-template-columns: repeat(auto-fit, minmax(min(22rem, 100%), 1fr));
  gap: var(--pas-3);
}
.videos--1 { grid-template-columns: minmax(0, 1fr); max-width: var(--large); margin-inline: auto; }
.video { margin: 0; display: grid; gap: var(--pas-2); }
.video__cadre {
  display: block;
  width: 100%;
  height: auto;
  background: var(--noir-doux);
}
.video__legende {
  font-size: 0.875rem;
  color: var(--brume);
  line-height: 1.6;
}
.bloc--jour .video__legende,
.bloc--creux .video__legende { color: var(--gris); }

/* --------------------------------------------------------------------------
   La plaquette de tarifs
   Le client préfère remplacer un fichier plutôt que de faire reporter ses
   prix. Ce sont les PAGES RENDUES EN IMAGE qui s'affichent, et non le PDF
   dans un <object> : un <object> ne rend un PDF que sur un ordinateur, et
   sur un téléphone il montre son contenu de repli — la moitié des visiteurs
   aurait eu un bouton à la place des prix.
   Les images gardent donc leurs proportions, celles de la plaquette, et le
   lien de téléchargement ferme la série.
   -------------------------------------------------------------------------- */
.plaquette {
  margin: 0;
  display: grid;
  /* « minmax(0, 1fr) » et non « 1fr » : une piste de grille prend par défaut
     la largeur intrinsèque de son contenu, et le contenu est ici une image de
     1600 px dans un lien. Sans ce minimum à zéro, la page débordait de 90 px
     à 320 px de large — relevé par le balayage, pas à l'œil. */
  grid-template-columns: minmax(0, 1fr);
  gap: var(--pas-4);
  max-width: var(--large);
  margin-inline: auto;
}
.plaquette__page {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--filet-jour);
  background: var(--ivoire-creux);
}
.plaquette__ouvrir { display: block; }
.plaquette__ouvrir:hover .plaquette__page,
.plaquette__ouvrir:focus-visible .plaquette__page { border-color: var(--or); }
.plaquette__lien { margin: 0; text-align: center; }
/* Le bouton général est en « white-space: nowrap », ce qui vaut pour un
   libellé de deux mots. « Télécharger la plaquette » avec 0,18 em
   d'interlettrage fait 390 px : il poussait la page hors cadre sur tous les
   téléphones. Ici, et ici seulement, il a le droit de passer à la ligne. */
.plaquette .bouton {
  max-width: 100%;
  white-space: normal;
  flex-direction: column;
  gap: 0.35rem;
  text-align: center;
}
.plaquette .bouton small {
  font-size: 0.6875rem;
  letter-spacing: 0.08em;
  opacity: 0.7;
}

/* --------------------------------------------------------------------------
   Grille de tarifs
   Une carte de coiffeur est une liste de prix, pas un tableau de bord : les
   catégories sont posées en colonnes typographiques, chacune insécable, et
   le prix se cale à droite d'un filet. Aucune boîte, aucune ombre.
   -------------------------------------------------------------------------- */
.tarifs {
  columns: 2;
  column-gap: clamp(2rem, 6vw, 5rem);
  max-width: var(--large);
  margin-inline: auto;
  margin-top: var(--pas-6);
}
.tarif-groupe {
  break-inside: avoid;
  margin-bottom: var(--pas-6);
}
.tarif-groupe--large {
  max-width: var(--large);
  margin-inline: auto;
  margin-bottom: 0;
}
.tarif-groupe__sous {
  font-size: 0.8125rem;
  color: var(--gris);
  margin: 0.6rem 0 0;
}
.bloc--nuit .tarif-groupe__sous { color: var(--brume); }

.tarif-liste {
  list-style: none;
  margin: var(--pas-3) 0 0;
  padding: 0;
}
.tarif-ligne {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--pas-2);
  padding-block: 0.7rem;
  border-top: 1px solid var(--filet-jour);
}
.tarif-ligne:last-child { border-bottom: 1px solid var(--filet-jour); }
.bloc--nuit .tarif-ligne { border-color: var(--filet-nuit); }

.tarif-ligne__nom { display: flex; flex-direction: column; gap: 0.15rem; }
.tarif-ligne__note {
  font-size: 0.75rem;
  line-height: 1.5;
  color: var(--gris);
}
.tarif-ligne__prix {
  flex: 0 0 auto;
  font-family: var(--titres);
  font-size: 1.0625rem;
  letter-spacing: 0.03em;
  white-space: nowrap;
  /* Les prix s'alignent entre eux plutôt que de flotter contre les noms :
     une colonne de montants se lit verticalement. */
  min-width: 4.5ch;
  text-align: right;
}
.tarif-ligne__depuis {
  display: block;
  font-family: var(--texte);
  font-size: 0.625rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--or-encre);
}

/* Le menu mèches croise deux variables — grammage et nombre de patines :
   c'est un vrai tableau, avec ses en-têtes de ligne et de colonne. Il
   défile horizontalement sur mobile plutôt que d'écraser ses colonnes, et
   le conteneur est focusable pour qu'on puisse le faire défiler au clavier. */
.tarif-defilant { overflow-x: auto; margin-top: var(--pas-3); }
/* L'indice de défilement ne sert qu'au mobile : sur un écran large le
   tableau tient en entier et la phrase serait fausse. */
.tarif-defilant__indice { display: none; }
.tarif-tableau {
  width: 100%;
  min-width: 34rem;
  border-collapse: collapse;
  text-align: left;
}
.tarif-tableau th,
.tarif-tableau td {
  padding: 0.8rem var(--pas-2) 0.8rem 0;
  border-top: 1px solid var(--filet-jour);
  vertical-align: baseline;
}
.tarif-tableau thead th {
  border-top: 0;
  border-bottom: 1px solid var(--or-encre);
  font-family: var(--texte);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--gris);
  line-height: 1.5;
}
.tarif-tableau tbody th {
  font-family: var(--titres);
  font-weight: 400;
  letter-spacing: 0.06em;
}
.tarif-tableau td data {
  font-family: var(--titres);
  font-size: 1.0625rem;
  letter-spacing: 0.03em;
  white-space: nowrap;
}

/* --------------------------------------------------------------------------
   Avantages — abonnements, clubs, fidélité
   Le chiffre est gros, mais la condition qui le gouverne est juste à côté et
   non en note : un « −20 % » sans « les mardis » est un mensonge.
   -------------------------------------------------------------------------- */
.avantages { max-width: var(--large); margin-inline: auto; }
.avantage {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--pas-2) clamp(1.5rem, 5vw, 4rem);
  align-items: baseline;
  padding-block: var(--pas-4);
  border-top: 1px solid var(--filet-nuit);
}
.avantage:last-child { border-bottom: 1px solid var(--filet-nuit); }
.avantage__detail { color: var(--brume); margin: 0.5rem 0 0; }
.avantage__valeur {
  font-family: var(--titres);
  font-size: clamp(1.6rem, 1.2rem + 1.4vw, 2.25rem);
  line-height: 1.1;
  color: var(--or);
  letter-spacing: 0.02em;
}
.avantage__valeur small {
  display: block;
  margin-top: 0.7rem;
  font-family: var(--texte);
  font-size: 0.8125rem;
  letter-spacing: 0;
  line-height: 1.6;
  color: var(--brume);
}

/* --------------------------------------------------------------------------
   Avis clients
   Des citations de largeurs inégales, décalées : un mur de blocs identiques
   aurait l'air d'un carrousel d'avis acheté.
   -------------------------------------------------------------------------- */
.avis {
  max-width: var(--large);
  margin-inline: auto;
  columns: 2;
  column-gap: clamp(2rem, 5vw, 4rem);
}
.avis figure {
  break-inside: avoid;
  margin: 0 0 clamp(2rem, 5vw, 3.5rem);
  padding-top: var(--pas-3);
  border-top: 1px solid var(--filet-nuit);
}
.avis blockquote {
  margin: 0;
  font-size: clamp(1rem, 0.95rem + 0.3vw, 1.125rem);
  line-height: 1.7;
  color: var(--blanc);
}
.avis blockquote p::before { content: '« '; color: var(--or); }
.avis blockquote p::after  { content: ' »'; color: var(--or); }
.avis figcaption {
  margin-top: var(--pas-2);
  font-size: 0.6875rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--brume);
  display: flex;
  align-items: center;
  gap: 0.6rem;
}
.etoiles { color: var(--or); letter-spacing: 0.1em; font-size: 0.8125rem; }

/* --------------------------------------------------------------------------
   Marques partenaires — les noms, en typographie (accueil)
   Sur l'accueil les quatre maisons sont citées par leur nom, avec une ligne
   de description chacune. Les logotypes eux-mêmes sont posés ailleurs, sur
   /prestations/#marques — voir « La bande des logos » plus haut dans cette
   feuille. Deux blocs, deux usages : ne pas confondre .marques (cette
   liste-ci) et .logos (la bande).
   -------------------------------------------------------------------------- */
.marques {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: 1px;
  background: var(--filet-jour);
  border: 1px solid var(--filet-jour);
  max-width: var(--large);
  margin-inline: auto;
  list-style: none;
  padding: 0;
}
.marques li { background: var(--ivoire); padding: var(--pas-4) var(--pas-3); }
.marques__nom {
  font-family: var(--titres);
  font-size: 1.0625rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  display: block;
  margin-bottom: 0.6rem;
}
.marques p { font-size: 0.9375rem; color: var(--gris); margin: 0; }

/* --------------------------------------------------------------------------
   Bandeau d'appel
   -------------------------------------------------------------------------- */
.appel {
  background: var(--noir);
  color: var(--blanc);
  padding: var(--pas-6) var(--gouttiere);
  position: relative;
  overflow: hidden;
  text-align: center;
}
.appel__meches {
  position: absolute; inset: 0;
  background: url('../img/motif/filet.svg') center / cover no-repeat;
  opacity: 0.45;
  pointer-events: none;
}
.appel__interieur { position: relative; max-width: 52rem; margin-inline: auto; }
.appel .chapeau { margin-top: var(--pas-3); }
.appel .boutons { margin-top: var(--pas-4); justify-content: center; }

/* La signature de la maison, dessinée en Cinzel très espacée. */
.signature {
  font-family: var(--titres);
  text-transform: uppercase;
  letter-spacing: 0.3em;
  font-size: clamp(0.75rem, 0.7rem + 0.3vw, 0.9375rem);
  color: var(--or);
}

/* --------------------------------------------------------------------------
   Formulaire
   -------------------------------------------------------------------------- */
.formulaire { display: grid; gap: var(--pas-3); max-width: 34rem; }
.formulaire__paire { display: grid; gap: var(--pas-3); grid-template-columns: 1fr 1fr; }
.formulaire p { display: flex; flex-direction: column; gap: 0.45rem; margin: 0; }
.formulaire input,
.formulaire select,
.formulaire textarea { width: 100%; min-width: 0; }
.formulaire textarea { min-height: 9rem; resize: vertical; }
.formulaire__cache { position: absolute; left: -9999px; }
/* Sélecteur redondant en apparence, nécessaire en réalité : « .formulaire p »
   pose flex-direction: column et pèse plus lourd qu'une simple classe. La
   case se retrouvait au-dessus de son libellé. */
.formulaire p.formulaire__consentement {
  flex-direction: row;
  align-items: flex-start;
  gap: 0.75rem;
  font-size: 0.875rem;
  color: var(--gris);
}
.formulaire__consentement input {
  width: 1.1rem; height: 1.1rem;
  flex: 0 0 auto;
  margin-top: 0.2rem;
  accent-color: var(--or-encre);
  appearance: auto;
}
.formulaire__consentement span { line-height: 1.6; }
/* Le consentement est une phrase à lire, pas un intitulé de champ : il
   échappe donc aux capitales et à l'interlettrage de « .formulaire label ».
   C'est ce que faisait un style en ligne, que la politique de sécurité
   supprimait — d'où un paragraphe en capitales serrées en ligne. */
.formulaire label.consentement__texte {
  display: inline;
  font-size: 0.875rem;
  font-weight: 300;
  letter-spacing: 0;
  line-height: 1.7;
  text-transform: none;
  color: var(--gris);
}

/* La ligne d'envoi : le bouton et le retour côte à côte. */
.formulaire p.ligne-envoi {
  flex-direction: row;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--pas-3);
}

/* Un bouton qui n'a que le texte : employé pour « tout afficher » sous
   l'annuaire vide. */
.bouton-nu {
  background: none;
  border: 0;
  border-bottom: 1px solid currentColor;
  cursor: pointer;
  margin-left: 0.5rem;
}
.formulaire__retour { font-size: 0.9375rem; }
.formulaire__retour[data-etat='succes'] { color: var(--or-encre); }
.formulaire__retour[data-etat='erreur'] { color: #A3301C; }

/* --------------------------------------------------------------------------
   Dépliants — questions fréquentes et mentions légales
   -------------------------------------------------------------------------- */
.depliant { border-top: 1px solid var(--filet-jour); }
.depliant:last-of-type { border-bottom: 1px solid var(--filet-jour); }
.depliant summary {
  cursor: pointer;
  list-style: none;
  padding: var(--pas-3) 2.5rem var(--pas-3) 0;
  position: relative;
  font-family: var(--titres);
  font-size: clamp(0.9375rem, 0.9rem + 0.3vw, 1.0625rem);
  text-transform: uppercase;
  letter-spacing: 0.07em;
  line-height: 1.35;
}
.depliant summary::-webkit-details-marker { display: none; }
.depliant summary::after {
  content: '';
  position: absolute;
  right: 0.35rem; top: calc(var(--pas-3) + 0.55em);
  width: 0.6rem; height: 0.6rem;
  border-right: 1px solid var(--or-encre);
  border-bottom: 1px solid var(--or-encre);
  transform: rotate(45deg);
  transition: transform 0.25s;
}
.depliant[open] summary::after { transform: rotate(-135deg); }
.depliant__corps { padding-bottom: var(--pas-4); color: var(--gris); max-width: var(--mesure); }
.depliant__corps :last-child { margin-bottom: 0; }

/* --------------------------------------------------------------------------
   Pied de page
   -------------------------------------------------------------------------- */
.pied {
  background: var(--noir);
  color: var(--brume);
  padding: var(--pas-6) var(--gouttiere) var(--pas-4);
  font-size: 0.9375rem;
}
.pied__haut {
  max-width: var(--large);
  margin-inline: auto;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.5fr);
  gap: var(--pas-5) clamp(2rem, 6vw, 5rem);
  padding-bottom: var(--pas-5);
  border-bottom: 1px solid var(--filet-nuit);
}
/* 5,5 rem donnent 292 px de large au logo, pour 287 px à la signature
   qui le suit : les deux blocs sont calés l’un sur l’autre, comme sur
   la carte de la maison. La colonne fait 344 px au plus étroit. */
.pied__marque img { height: 5.5rem; width: auto; }
/* Composée comme sur la carte de la maison : très espacée, calée sous le
   filet du logotype, et assez grande pour se lire. */
.pied__baseline {
  margin: 0.55rem 0 0;
  font-size: 0.6875rem;
  font-weight: 400;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--or);
}
.pied__marque .signature { display: block; margin-top: var(--pas-3); }
.pied__colonnes {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: var(--pas-4) var(--pas-3);
}
.pied h4 { color: var(--or); font-size: 0.6875rem; letter-spacing: 0.2em; margin-bottom: var(--pas-2); }
.pied ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.6rem; }
.pied a { text-decoration: none; transition: color 0.22s; }
.pied a:hover { color: var(--or-clair); }
.pied__reseaux { display: flex; gap: var(--pas-2); margin-top: var(--pas-2); }
.pied__reseaux a {
  display: grid;
  place-items: center;
  width: 2.5rem; height: 2.5rem;
  border: 1px solid var(--filet-nuit);
  color: var(--blanc);
  transition: border-color 0.25s, color 0.25s;
}
.pied__reseaux a:hover { border-color: var(--or); color: var(--or); }
.pied__reseaux svg { width: 17px; height: 17px; }
.pied__bas {
  max-width: var(--large);
  margin-inline: auto;
  padding-top: var(--pas-4);
  display: flex;
  flex-wrap: wrap;
  gap: var(--pas-2) var(--pas-3);
  align-items: center;
  justify-content: space-between;
  font-size: 0.75rem;
  letter-spacing: 0.08em;
}
.pied__bas nav { display: flex; flex-wrap: wrap; gap: var(--pas-2) var(--pas-3); }

/* --------------------------------------------------------------------------
   Apparitions au défilement
   Neutralisées pour qui demande moins de mouvement — et jamais appliquées
   au contenu de l'annuaire, qui doit rester lisible même si le script ne
   part pas.
   -------------------------------------------------------------------------- */
.apparait { opacity: 0; transform: translateY(1.35rem); }
html.js .apparait { transition: opacity 0.75s ease, transform 0.75s cubic-bezier(0.22, 1, 0.36, 1); }
.apparait[data-vu] { opacity: 1; transform: none; }
html:not(.js) .apparait { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .apparait, html.js .apparait { opacity: 1 !important; transform: none !important; transition: none !important; }
  .descendre__trait { animation: none; transform: scaleX(1); }
  *, *::before, *::after { transition-duration: 0.01ms !important; }
}

/* --------------------------------------------------------------------------
   Tablette
   -------------------------------------------------------------------------- */
/* --------------------------------------------------------------------------
   Recadrages
   Le point de fuite d'un cliché, en pourcentage de sa hauteur. Nommés par
   leur valeur plutôt que par une intention : « plus bas » ne dit pas de
   combien, et il en faut trois réglages différents.

   ELLES SONT ICI, ET PAS PLUS HAUT. Déclarées avant « .univers__photo »,
   elles perdaient contre lui : même spécificité, et c'est alors la dernière
   écrite qui l'emporte. Les photographies restaient cadrées à 28 % sans que
   rien ne le signale. Une classe utilitaire se pose après les composants
   qu'elle corrige.
   -------------------------------------------------------------------------- */
.cadre-y45 { object-position: 50% 45%; }
.cadre-y60 { object-position: 50% 60%; }
.cadre-y80 { object-position: 50% 80%; }

@media (max-width: 70rem) {
  :root { --entete: 4.5rem; }
  .nav__liste { display: none; }
  .nav .bouton { display: none; }
  .bouton--menu { display: block; }
}

@media (max-width: 60rem) {
  .duo, .duo--inverse, .duo--large { grid-template-columns: minmax(0, 1fr); }
  .chapiteau--photo .chapiteau__interieur { grid-template-columns: minmax(0, 1fr); }
  /* Couchée, elle prend moins de hauteur sous le titre. */
  .chapiteau__photo { aspect-ratio: 3 / 2; }
  .duo__aside { position: static; }
  .univers__rangee { grid-template-columns: 3rem minmax(0, 1fr); }
  .univers__rangee > .univers__texte { grid-column: 2; }
  .bassin { grid-template-columns: minmax(0, 1fr); }
  .prestation { grid-template-columns: minmax(0, 1fr); }
  .salon-ligne { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .salon-ligne__actions { grid-column: 1 / -1; flex-direction: row; align-items: center; justify-content: flex-start; }
  .pied__haut { grid-template-columns: minmax(0, 1fr); }
}

/* --------------------------------------------------------------------------
   Mobile
   -------------------------------------------------------------------------- */
@media (max-width: 40rem) {
  /* L'ÉCHELLE D'ESPACEMENT SE RESSERRE.
     Les grands pas sont écrits en clamp(plancher, vw, plafond) ; sur un
     écran étroit c'est le PLANCHER qui l'emporte, jamais le vw. Résultat,
     « --pas-7 » valait 88 px en haut ET en bas de chaque bloc : 176 px de
     vide par section, une dizaine de sections, près de deux écrans de rien
     sur la seule page d'accueil. Un rythme pensé pour 1440 px n'a pas de
     sens à 390. */
  :root {
    --pas-4: 1.75rem;
    --pas-5: 2.5rem;
    --pas-6: 2.75rem;
    --pas-7: 3.5rem;
  }

  /* Les étiquettes de la carte sont dimensionnées en unités du viewBox :
     réduite à 350 px de large, elles deviendraient minuscules. On les
     agrandit dans le repère du dessin pour qu'elles restent lisibles. */
  .carte__repere text { font-size: 34px; }
  .carte__point { r: 13; }
  .carte__contour { stroke-width: 2; }

  /* Une photographie en portrait occupait un écran entier à elle seule :
     900 × 1200 affichés sur 350 px de large font 467 px de haut, soit plus
     de la moitié de la hauteur visible. On la plafonne et on la recadre —
     mieux vaut un cadrage que l'on choisit qu'une image qui chasse le texte
     hors de l'écran. */
  .photo-salon img { max-height: 46vh; object-fit: cover; object-position: 50% 30%; }
  .attente { aspect-ratio: 4 / 3; }
  .galerie img { aspect-ratio: 1 / 1; }
  .galerie--2 img { aspect-ratio: 3 / 2; }
  /* Deux colonnes et cinq photos : la dernière restait seule sur sa ligne, à
     côté d'un trou de la taille d'une vignette. Elle prend donc toute la
     largeur et change de format — une image de pied de série plutôt qu'une
     case vide. Vaut pour tout nombre impair, une comprise. */
  .galerie__grille > :nth-child(odd):last-child {
    grid-column: 1 / -1;
    aspect-ratio: 3 / 2;
  }
  .galerie--1 img, .galerie--1 .galerie__grille > :last-child { aspect-ratio: auto; }

  /* Quatre logos en ligne tiennent sur 1280 px, pas sur 350 : le quatrième
     tombait seul sous les trois autres, et une bande de marques bancale
     dessert les marques qu'elle montre. Deux par deux, c'est régulier. */
  .logos {
    display: grid;
    grid-template-columns: 1fr 1fr;
    justify-items: center;
    align-items: center;
    gap: var(--pas-5) var(--pas-4);
  }

  .tarifs { columns: 1; }
  /* Cinquante-quatre lignes de prix : chaque demi-rem rendue par ligne vaut
     un tiers d'écran sur l'ensemble de la grille. On resserre l'interligne
     des prix sans toucher à celui du texte courant. */
  .tarif-ligne { padding-block: 0.5rem; }
  .tarif-defilant__indice { display: block; margin-top: var(--pas-2); }
  .tarif-groupe { margin-bottom: var(--pas-5); }
  .avantage { grid-template-columns: minmax(0, 1fr); }
  /* Vingt-deux salons à la file : la même économie que pour les prix. */
  .salon-ligne { padding-block: var(--pas-3); }

  /* Le filet du surtitre suppose un surtitre d'une seule ligne. Sur mobile
     la plupart en font deux, et le trait se retrouve suspendu au milieu du
     bloc, rattaché à rien. On le retire plutôt que de le laisser flotter. */
  .surtitre::after, .surtitre--centre::before { display: none; }

  /* La colonne du chiffre romain prenait 3 rem sur les 350 px utiles, soit
     un septième de la largeur pour deux caractères — et le texte, resserré
     d'autant, dépliait la rangée sur 767 px de haut. Le chiffre passe donc
     AU-DESSUS du titre, et la rangée récupère toute la largeur. */
  .univers__rangee {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--pas-2);
    padding-block: var(--pas-4);
  }
  .univers__rangee > .univers__texte,
  .univers__rangee > .prestation__detail { grid-column: 1; }
  .univers__numero { font-size: 0.75rem; }

  .avis { columns: 1; }
  .valeurs { columns: 1; }
  .chiffres { grid-template-columns: 1fr 1fr; }
  .chiffre { padding-inline: 0; border-left: 0; border-top: 1px solid var(--filet-nuit); padding-top: var(--pas-3); }
  .chiffre:first-child, .chiffre:nth-child(2) { border-top: 0; padding-top: 0; }
  .salon-ligne { grid-template-columns: minmax(0, 1fr); }
  .formulaire__paire { grid-template-columns: minmax(0, 1fr); }
  .coordonnees li { grid-template-columns: minmax(0, 1fr); }
  .coordonnees dt, .coordonnees__cle { padding-top: 0; }
  /* LA PHOTOGRAPHIE PASSE DERRIÈRE LE TEXTE, EN TRANSPARENCE.
     Cantonnée à la moitié droite comme au bureau, elle se retrouverait
     coupée de tous côtés derrière le titre. Elle prend donc tout le bandeau,
     et c'est le voile qui la tient en arrière-plan.
     Le voile, justement, est le point délicat : à 90 % d'opacité la photo ne
     se voyait plus du tout — ni fond ni sujet, une tache sombre sous les
     capitales. Il descend donc à 60-70 %, assez pour que le cliché respire,
     et le dégradé se charge du reste : plus dense en haut, où courent le
     surtitre et le titre, plus clair en bas, où la photo n'a face à elle que
     des boutons qui portent leur propre fond. Les rapports de contraste sont
     mesurés sur le rendu, pixel par pixel, par outils/contraste-photo.js. */
  .accueil {
    min-height: 0;
    padding-block: var(--pas-6) var(--pas-7);
  }
  .accueil__photo {
    inset: 0;
    width: 100%;
    height: 100%;
    object-position: 52% 10%;
    -webkit-mask-image: none;
    mask-image: none;
  }
  .accueil__voile {
    background: linear-gradient(176deg,
                rgba(16, 16, 16, 0.8) 0%, rgba(16, 16, 16, 0.78) 45%,
                rgba(16, 16, 16, 0.72) 75%, rgba(16, 16, 16, 0.6) 100%);
  }
  .boutons .bouton { width: 100%; }
  .descendre { position: static; margin-top: var(--pas-5); display: none; }
}

/* --------------------------------------------------------------------------
   Une image qu'on ne recadre pas
   Les chapiteaux recadrent leur photographie pour que les pages s'alignent.
   Une image qui N'EST PAS une photographie — une carte, une affiche — porte
   son propre cadrage : la rogner lui coupe un titre ou une légende. Elle
   garde donc ses proportions.

   APRÈS LES REQUÊTES MÉDIA, ET PAS AVANT. « .chapiteau__photo » y est
   redéfini en 3/2 sous 60 rem ; une requête média n'ajoute pas de
   spécificité, donc à égalité c'est la dernière écrite qui gagne. Posée
   plus haut, cette règle aurait été ignorée sur téléphone — et seulement
   sur téléphone.
   -------------------------------------------------------------------------- */
.chapiteau__photo--entiere {
  aspect-ratio: auto;
  object-fit: contain;
}

/* --------------------------------------------------------------------------
   Impression — on garde le texte, on jette le décor
   -------------------------------------------------------------------------- */
@media print {
  .entete, .voile, .descendre, .appel, .pied__reseaux, .bouton { display: none !important; }
  body { background: #fff; color: #000; font-size: 11pt; }
  .bloc--nuit, .accueil, .chapiteau { background: #fff !important; color: #000 !important; }
  .bloc--nuit .surtitre, .chapiteau .surtitre { color: #000 !important; }
  .accueil__photo, .accueil__voile, .chapiteau__meches, .bloc--meches::before { display: none !important; }
  .attente { display: none !important; }
  a { text-decoration: underline; }
}
