/* Charte graphique Patrigeon : jaune #ffce44, noir #1d1d1b, blanc.
   Fonts : Inter (validée 28/08/2026, remplace Raleway pour la lisibilité) + script (Great Vibes). */
/* Polices auto-hébergées (fiabilité + RGPD) : voir static/fonts/ */

:root {
  --noir: #141412;
  --noir-2: #1d1d1b;
  --or: #ffce44;
  --or-clair: #ffce44;
  --or-doux: #e9bd3f;
  --blanc: #ffffff;
  --gris: #8a8a8a;
  --sans: "Inter", "Helvetica Neue", Arial, sans-serif;
  --script: "Great Vibes", cursive;
}

* { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }
body {
  font-family: var(--sans);
  font-weight: 400;
  background: var(--noir);
  color: var(--blanc);
  -webkit-font-smoothing: antialiased;
}
img, video { max-width: 100%; display: block; }
/* Vidéo posée à la place d'une image (WebM / MP4 acceptés partout où une
   image l'était) : elle remplit le cadre de son conteneur comme l'image
   qu'elle remplace. Les cadres à rapport fixe sont repris ci-dessous, règle
   par règle, à côté de leur `img`. */
.media-video { width: 100%; height: 100%; object-fit: cover; }
/* Masque a l'oeil, lu par les lecteurs d'ecran et par les moteurs (issue #111).
   Surtout pas `display: none`, qui sortirait aussi le texte de l'arbre
   d'accessibilite : le <h1> de l'accueil deviendrait alors invisible pour tout
   le monde, ce qui etait justement le probleme. */
.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}
/* Lien d'évitement (WCAG 2.4.1, issue #129). L'en-tête porte un méga-menu de
   sept univers et leurs sous-familles : sans lui, un visiteur au clavier
   traverse plusieurs dizaines de liens avant le contenu, et sur chaque page.
   Hors focus il est poussé hors de l'écran, jamais `display: none` — même
   raison que `.sr-only` juste au-dessus : un lien retiré de l'arbre
   d'accessibilité n'est plus atteignable au clavier, donc n'existe pas.
   Le z-index passe devant l'en-tête fixe (z-index 50). */
.skip-link {
  position: fixed; top: .8rem; left: .8rem; z-index: 100;
  transform: translateY(-250%);
  background: var(--noir-2); color: var(--or-clair);
  border: 1px solid var(--or); padding: .9rem 1.6rem;
  font-size: .78rem; letter-spacing: .2em; text-transform: uppercase;
}
.skip-link:focus { transform: none; }
/* La cible du lien reçoit le focus pour que la tabulation reparte de là. Son
   contour ne servirait à rien : l'utilisateur vient de l'y envoyer lui-même. */
main:focus { outline: none; }
a { color: inherit; text-decoration: none; }
h1, h2, h3 { font-family: var(--sans); font-weight: 500; }

/* ---------- header ---------- */
.site-header {
  position: fixed; inset: 0 0 auto 0; z-index: 50;
  background: linear-gradient(to bottom, rgba(13,13,13,.92), rgba(13,13,13,.75) 70%, transparent);
  transition: background .3s;
}
/* Une seule rangée : univers à gauche, logo centré, liens à droite */
.header-row {
  display: flex; align-items: center; position: relative;
  padding: 1.5rem 2.2rem 1.3rem; min-height: 74px;
}
.site-nav { display: flex; justify-content: space-between; align-items: center; width: 100%; }
.site-nav ul { display: flex; align-items: center; gap: .95rem; list-style: none; }
.site-header .brand {
  display: flex; align-items: center; gap: .7rem;
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  white-space: nowrap;
}
.site-header .brand-mark { height: 46px; width: auto; }
.brand-text { display: flex; flex-direction: column; align-items: center; }
.brand-name {
  font-family: var(--sans); font-weight: 500; font-size: 1.32rem;
  letter-spacing: .34em; text-transform: uppercase; color: var(--blanc);
  margin-right: -.34em;
}
.brand-sub {
  font-family: var(--sans); font-weight: 400; font-size: .64rem;
  letter-spacing: .17em; color: var(--or); margin-right: -.17em;
}
.burger { display: none; background: none; border: 0; cursor: pointer; padding: .4rem; }
.burger span { display: block; width: 26px; height: 1px; background: var(--blanc); margin: 7px 0; transition: .3s; }

.menu-item > a {
  font-size: .70rem; font-weight: 500; letter-spacing: .07em; text-transform: uppercase;
  color: var(--blanc);
  padding-bottom: .35rem; position: relative; display: inline-block;
}
.menu-item > a::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: var(--or); transform: scaleX(0); transform-origin: center;
  transition: transform .35s;
}
.menu-item:hover > a::after,
.menu-item.active > a::after,
.menu-item.mega-current > a::after,
.menu-item.carousel-active > a::after { transform: scaleX(1); }

/* Le soulignement doré est dessiné sur la toute dernière rangée de pixels du
   lien : sa bordure basse *est* la frontière de la zone de survol. Viser la
   ligne, c'est donc viser le bord, et un pixel de trop refermait le panneau
   (issue #51). Cette cible invisible étend la zone du lien à toute la hauteur
   du bandeau et à la moitié de l'écart qui le sépare de ses voisins : le
   soulignement, les trous entre deux entrées et la descente vers le haut du
   panneau sont dedans. Elle ne change pas la mise en page, donc pas la hauteur
   du bandeau, et donne au passage une cible de plus de 44 px au doigt (#62).
   Réservée au grand écran : dans l'accordéon mobile elle déborderait sur les
   lignes voisines et volerait leurs taps. */
@media (min-width: 1431px) {
  .menu-item > a::before {
    content: ""; position: absolute; z-index: -1;
    left: -.475rem; right: -.475rem; top: -1.15rem; bottom: -1.5rem;
  }
}
/* mega-menu ouvert : seul l'univers survolé est souligné, les emphases carousel/page s'effacent */
body.mega-open .menu-item.carousel-active:not(.mega-current):not(:hover) > a::after,
body.mega-open .menu-item.active:not(.mega-current):not(:hover) > a::after { transform: scaleX(0); }
body.mega-open .menu-item.carousel-active:not(.mega-current) > a { color: var(--blanc); }
.menu-item.carousel-active > a { color: var(--or-clair); }
.menu-realisations > a { color: var(--blanc); }

.menu-item { position: relative; }
.submenu-toggle { display: none; }
.nav-mobile-foot { display: none; }
.submenu {
  position: absolute; top: 100%; left: 50%; transform: translateX(-50%);
  background: rgba(13,13,13,.96); border: 1px solid rgba(185,154,91,.25);
  min-width: 220px; padding: .8rem 0; list-style: none;
  opacity: 0; visibility: hidden; transition: opacity .25s;
}
/* le dropdown .submenu ne sert plus que dans le menu mobile (le desktop a le mega-menu) */
.submenu a {
  display: block; padding: .45rem 1.4rem; font-size: .78rem; letter-spacing: .12em;
}
.submenu a:hover { color: var(--or-clair); background: rgba(185,154,91,.08); }

/* ---------- mega-menu (desktop) ---------- */
/* Le panneau ne descend pas jusqu'en bas : la bande libre laissee sous lui est la
   sortie de secours a la souris. Sans elle, le curseur ne peut quitter le panneau
   que par le haut de la fenetre et le menu reste ouvert (ticket #12).
   72px au minimum, soit la hauteur du bandeau d'en-tete : c'est la course qu'un
   geste descendant franchit sans viser. 9vh pour rester proportionne, plafonne a
   120px pour ne pas amputer le menu sur les grands ecrans. */
.mega {
  --mega-gap: clamp(72px, 9vh, 120px);
  position: fixed; top: 74px; bottom: var(--mega-gap); left: 0; right: 0; z-index: 45;
  display: none; grid-template-columns: 2fr 3fr;
  box-shadow: 0 18px 34px -22px rgba(0, 0, 0, .8);
}
.mega.open { display: grid; animation: mega-in .25s ease; }
@keyframes mega-in { from { opacity: 0; } to { opacity: 1; } }
.mega-left {
  background: var(--noir-2); color: var(--blanc);
  border-top: 1px solid rgba(255,206,68,.18);
  padding: 3.2rem 4rem; overflow-y: auto; min-height: 0;
  /* Colonne : le lien d'univers est poussé en bas par margin-top: auto (#62).
     On garde l'étirement par défaut pour ne pas rétrécir la liste en deux
     colonnes ; c'est le lien seul qui s'aligne à gauche. */
  display: flex; flex-direction: column;
}
.mega-title {
  font-size: .76rem; font-weight: 600; letter-spacing: .18em; text-transform: uppercase;
  color: var(--or); margin-bottom: 1.3rem;
}
.mega-cats { columns: 2; column-gap: 3rem; list-style: none; max-width: 480px; }
.mega-cats li { margin-bottom: .75rem; break-inside: avoid; }
.mega-cats a, .mega-highlights a { color: #e8e8e8; font-size: .95rem; border-bottom: 1px solid transparent; }
.mega-cats a:hover, .mega-highlights a:hover { border-bottom-color: var(--or); }
.mega-highlights { list-style: none; }
.mega-highlights li { margin-bottom: .7rem; }
.mega-left .mega-cats + .mega-title { margin-top: 2.6rem; }
/* Section « Configurateurs » du méga-menu (issue #71). Même facture que « À la
   une », avec une pastille dorée pour la distinguer d'une simple liste de
   liens : ce n'est pas une catégorie de produits, c'est un outil. */
.mega-configurateurs { list-style: none; }
.mega-configurateurs li { margin-bottom: .7rem; }
.mega-configurateurs a {
  display: inline-flex; align-items: center; gap: .6rem;
  color: #e8e8e8; font-size: .95rem; border-bottom: 1px solid transparent;
}
.mega-configurateurs a::before {
  content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: var(--or); flex: none;
}
.mega-configurateurs a:hover { border-bottom-color: var(--or); }
.mega-left .mega-highlights + .mega-title,
.mega-left .mega-configurateurs + .mega-title { margin-top: 2.6rem; }
/* Sur grand écran l'entrée du bandeau n'ouvre plus la page d'univers, elle
   ouvre le panneau : c'est ce lien qui la remplace, en bas de la colonne des
   catégories (issue #62). Il doit rester visible sans avoir à chercher, d'où
   la couleur dorée et le trait, et faire 44 px de haut pour le doigt. */
.mega-universe {
  margin-top: auto; padding-top: 2.4rem; align-self: flex-start;
  display: inline-flex; align-items: center; gap: .55rem; min-height: 44px;
  font-size: .76rem; font-weight: 600; letter-spacing: .16em; text-transform: uppercase;
  color: var(--or);
}
.mega-universe::after {
  content: ""; width: 1.7rem; height: 1px; background: currentColor;
  transition: width .25s;
}
.mega-universe:hover, .mega-universe:focus-visible { color: var(--or-clair); }
.mega-universe:hover::after, .mega-universe:focus-visible::after { width: 2.8rem; }
.mega-universe:focus-visible { outline: 2px solid var(--blanc); outline-offset: 3px; }
.mega-right {
  /* Durées du carousel du mega-menu, définies ici et relues par le JS (comme .carousel).
     Plus court que l'accueil : le panneau ne reste ouvert que quelques secondes,
     il faut que le visiteur voie défiler deux ou trois produits sans toucher aux flèches. */
  --mega-interval: 3200ms;   /* temps d'affichage plein d'une slide */
  --mega-fade: 600ms;        /* fondu entre deux slides */
  /* La slide sortante reste visible pendant tout le fondu : le zoom doit couvrir
     l'affichage plein ET le fondu, sinon l'image se fige avant de disparaître. */
  --mega-kenburns: calc(var(--mega-interval) + var(--mega-fade));
  position: relative; overflow: hidden; background: var(--noir-2);
}
.mega-slide {
  position: absolute; inset: 0; opacity: 0;
  transition: opacity var(--mega-fade) ease; pointer-events: none;
}
.mega-slide.current { opacity: 1; pointer-events: auto; }
.mega-slide img, .mega-slide video { width: 100%; height: 100%; object-fit: cover; }
/* Video du mega-menu (issue #167). Meme cadrage que la photo, mais AUCUN Ken
   Burns : la video bouge deja, lui ajouter un zoom donnerait deux mouvements
   qui se contrarient. Le fond noir couvre l'instant ou le poster a disparu et
   ou la premiere frame n'est pas encore decodee. */
.mega-video { background: var(--noir-2); }
.mega-video video { display: block; width: 100%; height: 100%; object-fit: cover; }
/* Pas de scrim : le degrade sombre du pied de diapositive existe pour rendre la
   legende lisible, et la video n'en porte pas. L'y laisser assombrirait le bas
   de l'image pour rien. */
.mega-video::after { content: none; }
/* Ken Burns, même principe que le bandeau d'accueil : l'animation est portée par
   .mega-slide et non par .mega-slide.current, sinon l'image sortante reviendrait
   d'un coup à sa taille d'origine en plein fondu. Le JS la relance à chaque prise
   de vue. Amplitude plus faible qu'à l'accueil : la vignette est petite et le
   cycle court, un zoom trop large donnerait un mouvement nerveux. */
.mega-slide img { animation: mega-kenburns-a var(--mega-kenburns) linear forwards; }
.mega-slide:nth-child(even) img { animation-name: mega-kenburns-b; }
@keyframes mega-kenburns-a {
  from { transform: scale(1.03) translate(.6%, .4%); }
  to   { transform: scale(1.09) translate(-.8%, -.6%); }
}
@keyframes mega-kenburns-b {
  from { transform: scale(1.03) translate(-.6%, .4%); }
  to   { transform: scale(1.09) translate(.8%, -.6%); }
}
/* scrim : dégradé sombre en pied d'image pour la lisibilité du texte, quelle que soit la photo */
.mega-slide::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 45%;
  background: linear-gradient(transparent, rgba(13,13,13,.72));
  pointer-events: none;
}
.mega-caption {
  position: absolute; left: 0; right: 0; bottom: 2.6rem; text-align: center; color: var(--blanc);
  text-shadow: 0 2px 18px rgba(0,0,0,.55); z-index: 1;
}
.mega-name { display: block; font-size: 1.7rem; font-weight: 600; letter-spacing: .04em; }
.mega-more { display: inline-block; margin-top: .5rem; font-size: .82rem; border-bottom: 1px solid var(--blanc); }
.mega-prev, .mega-next {
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 2;
  width: 42px; height: 42px; border-radius: 50%; border: 1px solid rgba(255,255,255,.7);
  background: rgba(13,13,13,.25); color: var(--blanc); font-size: 1.4rem; line-height: 1;
  cursor: pointer; transition: background .3s;
}
.mega-prev:hover, .mega-next:hover { background: rgba(13,13,13,.6); }
.mega-prev { left: 1.6rem; }
.mega-next { right: 1.6rem; }

/* ---------- mega-menu rallume (issue #49) ---------- */
/* Univers Luminaire : la photo ne se promene pas, elle s'allume. Un seul canvas
   pour tout le panneau, sous les legendes : au moment du changement de photo le
   gradateur est a zero, donc l'ecran est noir et il n'y a rien a fondre. */
.mega-lit .mega-right {
  /* Cadence du gradateur, relue par le JS (meme principe que --mega-interval).
     La montee doit se voir monter : plus longue qu'un fondu de carousel. */
  --mega-lit-ramp: 2600ms;   /* montee de 0 a 100 % */
  --mega-lit-ramp-first: 900ms; /* premiere montee du panneau : plus vive, pour ne pas laisser un ecran noir (issue #72) */
  --mega-lit-hold: 2600ms;   /* palier a pleine lumiere avant de passer a la suite */
  --mega-lit-fall: 900ms;    /* extinction, le filament refroidit plus lentement */
  background: #04050a;
}
.mega-lit .mega-slide img { animation: none; }   /* pas de Ken Burns ici */
.mega-canvas { position: absolute; inset: 0; display: block; width: 100%; height: 100%; z-index: 0; }
.mega-lit .mega-slide { z-index: 1; }
/* Le moteur est debout : la photo passe la main au canvas. Tant qu'il ne l'est
   pas (WebGL refuse, script non charge, mouvement reduit), l'image reste
   visible et le panneau se comporte comme les autres, sans pan/zoom. */
.mega-lit.is-relighting .mega-slide img { opacity: 0; }
/* Seul ce lien ouvre la fiche produit : la photo elle-meme ne clique plus. */
.mega-cta { display: inline-block; color: inherit; }
.mega-cta:hover .mega-more { border-bottom-color: var(--or); }

.site-header.scrolled { background: rgba(13,13,13,.96); }

/* header opaque quand le mega-menu est ouvert, dans la continuité du panneau */
.brand-mark-dark { display: none; }
body.mega-open .site-header { background: rgba(13,13,13,.98); }

.mobile-category {
  display: none; text-align: center; font-size: .7rem; letter-spacing: .3em;
  text-transform: uppercase; color: var(--gris); padding-bottom: .5rem;
}

/* ---------- carousel ---------- */
/* Source de vérité unique des durées du carousel : le JS lit --carousel-interval
   sur .carousel pour cadencer la rotation, le CSS s'en sert pour le fondu et le
   Ken Burns. Ne pas redéfinir ces valeurs ailleurs. */
.carousel {
  --carousel-interval: 6000ms;   /* temps d'affichage plein d'une slide */
  --carousel-fade: 1200ms;       /* fondu entre deux slides */
  /* La slide sortante reste visible pendant tout le fondu : le zoom doit couvrir
     l'affichage plein ET le fondu, sinon l'image se fige avant de disparaître. */
  --carousel-kenburns: calc(var(--carousel-interval) + var(--carousel-fade));
  position: relative; height: 100vh; min-height: 540px; overflow: hidden; background: var(--noir);
}
.slide {
  position: absolute; inset: 0; opacity: 0; transition: opacity var(--carousel-fade) ease; pointer-events: none;
}
.slide.current { opacity: 1; pointer-events: auto; }
.slide::after {
  content: ""; position: absolute; inset: 55% 0 0 0; pointer-events: none;
  background: linear-gradient(transparent, rgba(13,13,13,.55));
}
.slide img, .slide video { width: 100%; height: 100%; object-fit: cover; filter: brightness(.72); }
/* Ken Burns : pan/zoom lent sur les photos (pas les vidéos), direction alternée.
   L'animation est portée par .slide et non par .slide.current : perdre la classe
   .current annulerait l'animation d'un coup et l'image sortante reviendrait à
   sa taille d'origine en plein fondu. Le JS la relance à chaque prise de vue.
   Timing linéaire : avec un ease-out le mouvement devient imperceptible bien
   avant la fin, ce qui donne l'impression d'une image figée. */
.slide img { animation: kenburns-a var(--carousel-kenburns) linear forwards; }
.slide:nth-child(even) img { animation-name: kenburns-b; }
@keyframes kenburns-a {
  from { transform: scale(1.04) translate(.8%, .6%); }
  to   { transform: scale(1.14) translate(-1.2%, -.9%); }
}
@keyframes kenburns-b {
  from { transform: scale(1.04) translate(-.8%, .6%); }
  to   { transform: scale(1.14) translate(1.2%, -.9%); }
}
.slide-caption {
  position: absolute; left: 50%; bottom: 12vh; transform: translateX(-50%);
  text-align: center; max-width: 90%;
}
/* Le nom de l'univers a l'allure d'un titre mais n'en est pas un (issue #111) :
   sept legendes d'un mot ne sont pas sept sections. Le rendu est inchange au
   pixel pres, seule la balise a change — d'ou la remise a zero des marges et
   du poids qu'un <h2> tenait de la feuille par defaut. */
.slide-caption .slide-titre {
  margin: 0; font-weight: 500;
  font-size: clamp(2.2rem, 5vw, 4rem); letter-spacing: .12em; text-transform: uppercase;
  text-shadow: 0 2px 30px rgba(0,0,0,.6);
}
/* `:not()` obligatoire depuis que le nom de l'univers est lui aussi un <p> :
   sans lui, il heriterait de la couleur et de la taille de l'accroche. */
.slide-caption p:not(.slide-titre) { margin: .8rem 0 1.4rem; font-size: 1.02rem; color: #eee; letter-spacing: .05em; }
.carousel-dots {
  position: absolute; right: 2.2rem; bottom: 2rem;
  display: flex; align-items: center; gap: 0; z-index: 5;
}
/* Cible de 24 px pour un point qui reste dessiné à 9 px (WCAG 2.5.8, issue
   #129). Les sept points sont les seules commandes du carrousel, et viser 9 px
   au doigt tient de la tête d'épingle.

   Le bouton porte la surface, un pseudo-élément porte le point. Le `padding`
   + `background-clip: content-box` conviendrait au fond mais pas à la bordure
   dorée, qui dessinerait alors un cercle de 24 px.

   Le `gap` tombe à 0 : deux cibles de 24 px ne peuvent pas se chevaucher sans
   redevenir ambiguës, et 24 px est le minimum du critère. Seul l'espace *vide*
   entre deux points s'élargit (9,6 px → 15 px) ; les points eux-mêmes sont
   inchangés au pixel près. */
.carousel-dots button {
  width: 24px; height: 24px; padding: 0; border: 0; background: transparent;
  cursor: pointer; display: grid; place-items: center;
}
.carousel-dots button::before {
  content: ""; width: 9px; height: 9px; border-radius: 50%;
  border: 1px solid var(--or); background: transparent; transition: background .3s;
}
.carousel-dots button.current::before { background: var(--or); }
/* Le bouton pause (WCAG 2.2.2). Deux barres, un triangle une fois en pause ;
   la logique est dans static/site.js, qui pose la classe. Les sélecteurs sont
   qualifiés par `.carousel-dots` pour passer devant `.carousel-dots button`. */
.carousel-dots .carousel-pause { margin-right: .3rem; }
.carousel-dots .carousel-pause::before {
  width: 8px; height: 11px; border-radius: 0; background: transparent;
  border: 0; border-left: 2px solid var(--or); border-right: 2px solid var(--or);
  transition: none;
}
.carousel-dots .carousel-pause.en-pause::before {
  width: 0; height: 0; margin-left: 3px;
  border: 6px solid transparent; border-right: 0; border-left: 10px solid var(--or);
}

.btn-gold {
  display: inline-block; padding: .8rem 2.4rem; border: 1px solid var(--or);
  color: var(--or-clair); font-size: .78rem; letter-spacing: .3em; text-transform: uppercase;
  transition: background .3s, color .3s;
}
.btn-gold:hover { background: var(--or); color: var(--noir-2); }
.footer-baseline {
  /* Trois fois plus grande que les 2rem d'origine, illisibles a l'ecran (issue
     #194). Le 6rem n'est tenable que sur large : « Createur d'emotions » fait
     dix-neuf caracteres, et Great Vibes deborderait d'un telephone. D'ou le
     clamp — la valeur haute est la demande, la valeur basse ce qui tient sur
     360px de large, et le vw fait la transition sans point de rupture. La
     hauteur de ligne se resserre parce qu'un script de 96px herite sinon d'un
     interligne qui decolle le pied de page. */
  text-align: center; font-family: var(--script);
  font-size: clamp(3rem, 9vw, 6rem); line-height: 1.15; color: var(--or);
  margin-top: 2.6rem;
}

/* ---------- sections ---------- */
main { min-height: 60vh; }
body:not(.home) main { padding-top: 8.5rem; }

/* ==========================================================================
   Accueil « Éditorial » (issue #97)
   --------------------------------------------------------------------------
   La direction éditoriale tient ici sur trois leviers, et pas sur un serif :
   la graisse fine (Inter 200/300 sur les grands titres), les tailles, et les
   interlignes serrés. Cormorant avait été retiré à la demande du client et
   « Inter partout » validé le 28/08 : rouvrir cette décision demande son
   accord, pas une initiative d'intégration.

   Une seule largeur de contenu pour toutes les sections nouvelles, `--hw`,
   pour qu'elles s'alignent au pixel entre elles.
   ========================================================================== */

:root { --hw: min(1360px, 92vw); }

.home-univers,
.home-selection { width: var(--hw); margin: 0 auto; padding: clamp(4.5rem, 9vh, 8.5rem) 0; }

/* En-tête de section : sur-titre + titre à gauche, chapô à droite, filet dessous. */
.shead {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 2.5rem; padding-bottom: 2rem; margin-bottom: 3.4rem;
  border-bottom: 1px solid rgba(255,255,255,.12);
}
.shead h2 {
  font-size: clamp(2.1rem, 4.4vw, 3.7rem); font-weight: 200;
  line-height: 1.05; letter-spacing: -.015em; text-transform: none;
}
.shead p { max-width: 40ch; color: var(--gris); font-size: .95rem; line-height: 1.65; }
.eyebrow {
  display: block; font-size: .69rem; font-weight: 500; letter-spacing: .34em;
  text-transform: uppercase; color: var(--or); margin-bottom: .85rem;
}

/* ---------- 1. sept univers : grille éditoriale asymétrique ---------- */

/* La HAUTEUR est portée par la rangée (classes .h-hi / .h-md / .h-lo), pas par
   la tuile : deux tuiles de la même rangée ont donc forcément la même hauteur,
   quel que soit le format de leur photo. Le prototype posait un `aspect-ratio`
   par tuile et laissait un trou sous « Pianos » ; c'est ce piège-là que la
   règle évite, par construction et non par réglage. */
.hu-grid { display: grid; grid-template-columns: repeat(12, 1fr); gap: clamp(.6rem, 1.6vw, 1.7rem); }
.hu {
  position: relative; overflow: hidden; background: var(--noir-2);
  display: block; isolation: isolate;
}
.hu.s4 { grid-column: span 4; } .hu.s5 { grid-column: span 5; }
.hu.s7 { grid-column: span 7; } .hu.s8 { grid-column: span 8; } .hu.s12 { grid-column: span 12; }
.hu.h-hi { height: clamp(300px, 31vw, 470px); }
.hu.h-md { height: clamp(250px, 25vw, 370px); }
.hu.h-lo { height: clamp(260px, 27vw, 400px); }
.hu img {
  width: 100%; height: 100%; object-fit: cover;
  transition: transform 1.1s cubic-bezier(.2,.7,.3,1);
}
.hu:hover img, .hu:focus-visible img { transform: scale(1.06); }
.hu::after {
  content: ""; position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(180deg, transparent 28%, rgba(13,13,11,.9));
  transition: background .4s;
}
.hu:hover::after, .hu:focus-within::after {
  background: linear-gradient(180deg, rgba(13,13,11,.18) 8%, rgba(13,13,11,.94));
}
.hu-cap {
  position: absolute; inset: auto 0 0 0; z-index: 2;
  padding: clamp(1.1rem, 2.1vw, 2.1rem); display: block;
}
.hu-num {
  display: block; font-size: .69rem; letter-spacing: .28em; color: var(--or);
  font-weight: 500; margin-bottom: .5rem;
}
.hu-nom {
  display: block; font-size: clamp(1.35rem, 2.5vw, 2.35rem); font-weight: 200;
  line-height: 1.06; letter-spacing: -.01em;
}
/* La description se déplie par la rangée de grille : pas de `max-height`
   deviné, donc pas de texte tronqué quand le client écrit trois lignes. */
.hu-desc {
  display: grid; grid-template-rows: 0fr; opacity: 0;
  transition: grid-template-rows .45s cubic-bezier(.16,1,.3,1), opacity .35s;
}
.hu-desc > span {
  overflow: hidden; display: block; font-size: .84rem; line-height: 1.55;
  color: #c3bfb6; max-width: 44ch;
}
.hu:hover .hu-desc, .hu:focus-within .hu-desc { grid-template-rows: 1fr; opacity: 1; }
.hu:hover .hu-desc > span, .hu:focus-within .hu-desc > span { padding-top: .6rem; }
.hu:focus-visible { outline: 2px solid var(--or); outline-offset: -2px; }

/* Sans survol — donc au doigt — la description ne serait jamais atteignable :
   elle est visible d'emblée. C'est la règle, pas une dégradation. */
@media (hover: none) {
  .hu-desc { grid-template-rows: 1fr; opacity: 1; }
  .hu-desc > span { padding-top: .6rem; }
  .hu::after { background: linear-gradient(180deg, rgba(13,13,11,.15) 8%, rgba(13,13,11,.94)); }
}

/* ---------- 2. manifeste et chiffres ---------- */

.home-manifeste {
  background: var(--noir-2);
  border-top: 1px solid rgba(255,255,255,.12);
  border-bottom: 1px solid rgba(255,255,255,.12);
  padding: clamp(4.5rem, 9vh, 8rem) 0;
}
.hm-wrap {
  width: var(--hw); margin: 0 auto;
  display: grid; grid-template-columns: 1.05fr .95fr; gap: clamp(2.5rem, 6vw, 6rem);
  align-items: center;
}
.hm-dit blockquote {
  font-size: clamp(1.5rem, 3.1vw, 2.85rem); font-weight: 200;
  line-height: 1.22; letter-spacing: -.012em; margin-top: .3rem;
}
/* L'emphase or : la seule mise en valeur que l'éditeur riche laisse passer sur
   ce champ. Elle ne s'italicise pas, elle change de couleur. */
.hm-dit blockquote em { font-style: normal; color: var(--or); }
.hm-dit blockquote strong { font-weight: 400; }
.hm-qui {
  margin-top: 1.7rem; font-size: .74rem; letter-spacing: .2em;
  text-transform: uppercase; color: var(--gris);
}

/* Les chiffres : une ligne posée sur un filet or, sans cadre fermé.
   Le cadre 2×2 bordé du prototype faisait tableau et cassait l'élégance du
   reste ; la valeur est en grand corps léger, le libellé en petites capitales
   espacées dessous, et il n'y a aucun séparateur vertical. */
.home-chiffres { align-self: center; }
.home-chiffres dl {
  display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
  gap: clamp(1rem, 2.5vw, 2.4rem);
  border-top: 1px solid rgba(255,206,68,.5); padding-top: 1.6rem;
}
.home-chiffres .chiffre { min-width: 0; }
.home-chiffres dt {
  font-size: clamp(1.9rem, 3.6vw, 3.1rem); font-weight: 200; line-height: 1;
  color: var(--or); letter-spacing: -.02em;
}
.home-chiffres dd {
  margin-top: .7rem; font-size: .66rem; letter-spacing: .18em;
  text-transform: uppercase; color: var(--gris); line-height: 1.5;
}

/* ---------- 3. sélection : rail horizontal ---------- */

.hs-rail {
  display: grid; grid-auto-flow: column;
  grid-auto-columns: clamp(220px, 24vw, 330px);
  gap: clamp(1rem, 1.8vw, 1.5rem);
  overflow-x: auto; overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory; scroll-padding-left: 0;
  padding-bottom: 1.1rem;
  scrollbar-width: thin; scrollbar-color: var(--or-doux) transparent;
}
.hs-rail::-webkit-scrollbar { height: 3px; }
.hs-rail::-webkit-scrollbar-thumb { background: var(--or-doux); }
.hs-rail:focus-visible { outline: 2px solid var(--or); outline-offset: 4px; }
.hs-carte { scroll-snap-align: start; display: block; }
.hs-ph { display: block; overflow: hidden; background: var(--noir-2); }
.hs-ph img, .hs-ph video { width: 100%; height: auto; aspect-ratio: 3/4; object-fit: cover; transition: transform 1s; }
.hs-carte:hover img, .hs-carte:focus-visible img { transform: scale(1.05); }
.hs-nom { display: block; margin-top: 1rem; font-size: 1.15rem; font-weight: 300; }
.hs-sous {
  display: block; margin-top: .35rem; font-size: .66rem; letter-spacing: .2em;
  text-transform: uppercase; color: var(--gris);
}

/* ---------- 4. contact ---------- */

.home-contact {
  background: linear-gradient(180deg, var(--noir), #0e0e0c);
  padding: clamp(4.5rem, 9vh, 8rem) 0;
  border-top: 1px solid rgba(255,255,255,.12);
}
.hc-wrap {
  width: var(--hw); margin: 0 auto;
  display: grid; grid-template-columns: 1.1fr .9fr; gap: clamp(2.5rem, 6vw, 5.5rem);
  align-items: start;
}
.hc-info h2 {
  font-size: clamp(2rem, 4.2vw, 3.4rem); font-weight: 200;
  line-height: 1.06; letter-spacing: -.015em; margin-bottom: 2rem;
}
.hc-info dl { display: grid; gap: 1.4rem; }
.hc-info dt {
  font-size: .65rem; letter-spacing: .28em; text-transform: uppercase;
  color: var(--or); margin-bottom: .45rem;
}
.hc-info dd { font-size: 1.05rem; font-weight: 300; line-height: 1.55; }
.hc-info dd a { border-bottom: 1px solid rgba(255,255,255,.25); }
.hc-info dd a:hover { border-bottom-color: var(--or); color: var(--or); }
.hc-note { margin-top: 1.6rem; font-size: .85rem; color: var(--gris); line-height: 1.6; max-width: 42ch; }
.hc-form {
  border: 1px solid rgba(255,255,255,.12);
  padding: clamp(1.5rem, 3vw, 2.6rem);
  background: rgba(255,255,255,.02);
}
.hc-intro { font-size: .9rem; color: var(--gris); margin-bottom: 1.6rem; line-height: 1.6; }
.hc-form label {
  display: block; font-size: .65rem; letter-spacing: .24em; text-transform: uppercase;
  color: var(--gris); margin-bottom: 1.4rem;
}
.hc-form input, .hc-form textarea {
  display: block; width: 100%; margin-top: .5rem;
  background: transparent; border: 0; border-bottom: 1px solid rgba(255,255,255,.16);
  color: var(--blanc); font: 400 .95rem var(--sans); letter-spacing: normal; text-transform: none;
  padding: .5rem 0 .7rem; outline: none; transition: border-color .3s;
}
.hc-form input:focus, .hc-form textarea:focus { border-bottom-color: var(--or); }
.hc-form textarea { resize: vertical; }
.hc-form .btn-gold { width: 100%; text-align: center; }
.hc-form .flash { margin: 0; }

@media (max-width: 980px) {
  .hu-grid > .hu { grid-column: span 12; height: clamp(230px, 56vw, 340px); }
  .hm-wrap, .hc-wrap { grid-template-columns: 1fr; }
  .shead { flex-direction: column; align-items: flex-start; gap: 1rem; }
  .home-chiffres dl { grid-auto-flow: row; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); }
}
@media (prefers-reduced-motion: reduce) {
  .hu img, .hs-ph img, .hu-desc { transition: none; }
}

.home-realisations { padding: 5rem 2rem; text-align: center; }
.home-realisations > h2 { font-size: 2.2rem; letter-spacing: .15em; text-transform: uppercase; margin-bottom: 2.5rem; }
.center { text-align: center; margin-top: 2.5rem; }

.brand-slider { overflow: hidden; border-top: 1px solid rgba(185,154,91,.2); padding: 2.4rem 0; }
.brand-track { display: flex; gap: 4.5rem; align-items: center; width: max-content; animation: brands 90s linear infinite; padding: 0 2rem; }
@keyframes brands { to { transform: translateX(-50%); } }
.brand-logo { font-family: var(--sans); font-size: 1.25rem; letter-spacing: .2em; color: var(--gris); text-transform: uppercase; white-space: nowrap; }
.brand-logo img { height: 46px; width: auto; opacity: .72; transition: opacity .25s; }
.brand-logo img:hover { opacity: 1; }

/* Logos partenaires hors charte (issue #96). Les logos normalises sont en
   #f5f5f3 sur fond transparent ; un envoi qui ne l'est pas est ramene a la
   meme teinte ici, sans toucher au fichier d'origine. La classe est posee par
   le serveur (media.logo_tone), parce que le CSS ne sait pas lire des pixels.

   brightness(0) ecrase toute couleur en noir en gardant le canal alpha, donc la
   decoupe du logo ; invert(.961) reteint ce noir en rgb(245,245,245), soit
   #f5f5f3 a deux unites de bleu pres, invisibles. Faire l'inverse (invert puis
   brightness) donnerait un resultat different sur un logo deja clair. */
.logo-mono { filter: brightness(0) invert(.961); }

.brand-dup { display: contents; } /* le doublon doit rester des items du flex, pas un bloc */
.brand-slider:hover .brand-track { animation-play-state: paused; }
@media (prefers-reduced-motion: reduce) {
  .brand-track { animation: none; }
  /* les deux sélecteurs sont nécessaires : sinon .slide:nth-child(even) img
     réimposerait animation-name plus loin dans la cascade */
  .slide img, .slide:nth-child(even) img { animation: none; }
  .mega-slide img, .mega-slide:nth-child(even) img { animation: none; }
}

/* ---------- pages univers / catalogues ---------- */
.universe-hero { position: relative; height: 58vh; min-height: 380px; overflow: hidden; margin-top: -8.5rem; }
body:not(.home) main > .universe-hero:first-child { margin-top: 0; }
.universe-page main { padding-top: 0 !important; }
.universe-hero img, .universe-hero video { width: 100%; height: 100%; object-fit: cover; filter: brightness(.6); }
.hero-caption { position: absolute; left: 50%; bottom: 3.4rem; transform: translateX(-50%); text-align: center; width: 90%; }
.hero-caption h1 { font-size: clamp(2.2rem, 4.5vw, 3.6rem); letter-spacing: .14em; text-transform: uppercase; }
.hero-caption p { color: #ddd; margin-top: .6rem; letter-spacing: .05em; }

.universe-body, .catalog, .page { max-width: 1200px; margin: 0 auto; padding: 3rem 2rem 5rem; }
.universe-description { font-family: var(--sans); font-size: 1.25rem; line-height: 1.8; color: #ddd; max-width: 800px; margin: 0 auto 3rem; text-align: center; }
.zone-title { font-size: 1.6rem; letter-spacing: .2em; text-transform: uppercase; margin: 3rem 0 1.4rem; color: var(--or-clair); }

.family-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 1.6rem; }
.family-card {
  display: block; border: 1px solid rgba(185,154,91,.3); background: var(--noir-2);
  transition: border-color .3s, background .3s;
}
.family-card:hover { border-color: var(--or); background: rgba(185,154,91,.06); }
.family-visual { display: block; overflow: hidden; }
.family-visual img {
  display: block; width: 100%; aspect-ratio: 4/3; object-fit: cover;
  transition: transform .5s, opacity .4s;
}
.family-card:hover .family-visual img { transform: scale(1.03); opacity: .9; }
.family-body { display: block; padding: 1.5rem 1.6rem 1.7rem; }
.family-card h3 { font-size: 1.35rem; letter-spacing: .08em; }
.family-count { display: block; margin-top: .5rem; font-size: .78rem; color: var(--gris); letter-spacing: .1em; }

.breadcrumb { font-size: .78rem; letter-spacing: .15em; text-transform: uppercase; color: var(--gris); margin-bottom: 2rem; }
.breadcrumb a:hover { color: var(--or-clair); }
.catalog h1, .page h1 { font-size: 2.4rem; letter-spacing: .12em; text-transform: uppercase; margin-bottom: 2rem; }
.lead { color: #ccc; max-width: 720px; margin-bottom: 2.6rem; line-height: 1.7; }
.empty { color: var(--gris); font-size: 1.05rem; }
.empty a { color: var(--or-clair); }

.product-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 2.2rem; }
.product-card { background: var(--noir-2); }
.product-card img, .product-card video { aspect-ratio: 4/3; width: 100%; object-fit: cover; transition: opacity .4s; }
.product-card:hover img { opacity: .85; }
.product-card h3 { font-size: 1.2rem; letter-spacing: .06em; padding: 1rem 1.2rem .2rem; }
.product-card .brand { display: block; padding: 0 1.2rem; font-size: .75rem; letter-spacing: .2em; text-transform: uppercase; color: var(--gris); }
.product-card .price { display: block; padding: .5rem 1.2rem 1.2rem; color: var(--or-clair); letter-spacing: .05em; }

/* ---------- fiche produit ---------- */
.product-page { padding: 0 0 5rem; }
.product-layout { display: grid; grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); gap: 0; align-items: start; }
.product-gallery { display: flex; flex-direction: column; gap: 1px; background: var(--noir-2); padding: 2.2rem 2rem 0; }
.product-gallery .breadcrumb { margin-bottom: 1.6rem; }
.product-shot { margin: 0 0 1px; background: var(--noir); }
.product-shot img, .product-shot video { display: block; width: 100%; height: auto; }

.product-aside { padding: 2.2rem 3.4rem 0 3.4rem; }
.product-info { position: sticky; top: 7rem; }
.product-info h1 { font-size: 2rem; letter-spacing: .08em; margin-bottom: .5rem; }
.product-info .brand {
  font-size: .75rem; letter-spacing: .25em; text-transform: uppercase;
  color: var(--gris); margin-bottom: 1.4rem;
}
.product-info .description { line-height: 1.8; color: #ddd; font-size: .93rem; }
.product-info .description[data-clamp] {
  display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden;
}
.product-info .description.open { display: block; }
.product-info .link-more {
  background: none; border: 0; padding: .5rem 0 0; cursor: pointer;
  font-family: var(--sans); font-size: .78rem; letter-spacing: .2em;
  text-transform: uppercase; color: var(--or-clair); text-decoration: underline;
  text-underline-offset: 4px;
}
.product-info .link-more:hover { color: var(--or); }

.info-block { margin-top: 1.8rem; padding-top: 1.8rem; border-top: 1px solid rgba(255,255,255,.12); }
.product-specs { margin: 0; }
.product-specs .spec-title {
  font-size: .95rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--blanc); margin-bottom: .8rem;
}
.product-specs .spec-title + .spec-row { margin-top: 0; }
.product-specs .spec-row { display: flex; gap: 1rem; margin-top: .45rem; font-size: .85rem; }
.product-specs dt { color: var(--gris); letter-spacing: .1em; text-transform: uppercase; min-width: 8.5rem; }
.product-specs dd { margin: 0; color: #ddd; }

.price-block .price { font-size: 1.7rem; color: var(--or-clair); letter-spacing: .04em; margin: 0; }
.price-block .price-note { font-size: .74rem; color: var(--gris); letter-spacing: .06em; margin-top: .5rem; }

.cta-row { display: grid; grid-template-columns: 1fr 1fr; gap: .8rem; margin-top: 1.8rem; }
.cta-row .btn-gold, .cta-row .btn-ghost {
  display: flex; align-items: center; justify-content: center; text-align: center;
  padding: .95rem .6rem; font-size: .7rem; letter-spacing: .18em;
  text-transform: uppercase; line-height: 1.4; border: 1px solid var(--or);
  transition: background .3s, color .3s, border-color .3s;
}
.cta-row .btn-gold { background: var(--or); color: var(--noir); }
.cta-row .btn-gold:hover { background: var(--or-doux); border-color: var(--or-doux); color: var(--noir); }
.cta-row .btn-ghost { background: none; color: var(--blanc); border-color: rgba(255,255,255,.35); }
.cta-row .btn-ghost:hover { border-color: var(--or); color: var(--or-clair); }

.product-note {
  margin-top: 1.6rem; padding: 1.1rem 1.2rem; background: var(--noir-2);
  display: flex; flex-direction: column; gap: .35rem;
}
.product-note strong {
  font-size: .78rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--blanc); font-weight: 500;
}
.product-note span { font-size: .82rem; color: var(--gris); }

/* ---------- options de produit (couleurs en carrés ou variantes en liste) ---------- */
.product-options .options-title {
  display: block; font-size: .78rem; font-weight: 500; letter-spacing: .18em;
  text-transform: uppercase; color: var(--blanc); margin: 0 0 .9rem;
}
.option-swatches { display: flex; flex-wrap: wrap; gap: .55rem; }
.swatch {
  width: 36px; height: 36px; padding: 2px; cursor: pointer;
  background: none; border: 1px solid rgba(255,255,255,.28);
  transition: border-color .25s;
}
.swatch:hover { border-color: rgba(255,206,68,.65); }
.swatch.selected { border: 2px solid var(--or); padding: 1px; }
.swatch:focus-visible { outline: 2px solid var(--or); outline-offset: 2px; }
.swatch-color, .swatch img { display: block; width: 100%; height: 100%; object-fit: cover; }
.swatch-color { background: var(--noir-2); }
.option-name { margin: .7rem 0 0; font-size: .85rem; color: #ddd; letter-spacing: .05em; }
.product-options select {
  width: 100%; padding: .75rem .9rem; background: var(--noir-2);
  border: 1px solid rgba(185,154,91,.3); color: var(--blanc);
  font-family: var(--sans); font-size: .95rem; cursor: pointer;
}
.product-options select:focus { outline: none; border-color: var(--or); }
.product-options select:focus-visible { outline: 2px solid var(--or); outline-offset: 2px; }

/* ---------- réalisations ---------- */
.realisation-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 2rem; }
.realisation-card { position: relative; background: var(--noir-2); overflow: hidden; }
.realisation-card img, .realisation-card video { aspect-ratio: 4/3; width: 100%; object-fit: cover; opacity: .85; transition: transform .8s; }
.realisation-card:hover img { transform: scale(1.05); }
.realisation-card .period {
  position: absolute; top: 1rem; left: 1rem; font-size: .72rem; letter-spacing: .25em;
  text-transform: uppercase; color: var(--or-clair); background: rgba(13,13,13,.75); padding: .35rem .8rem;
}
.realisation-card h3 { padding: 1.1rem 1.2rem 1.3rem; font-size: 1.25rem; letter-spacing: .06em; }
.realisation-detail { max-width: 1000px; margin: 0 auto; padding: 3rem 2rem 5rem; }
.realisation-detail h1 { font-size: 2.3rem; letter-spacing: .1em; }
.realisation-detail .period { color: var(--or-clair); letter-spacing: .25em; text-transform: uppercase; font-size: .8rem; margin: .5rem 0 2rem; }
.realisation-detail .description { line-height: 1.8; color: #ddd; margin-bottom: 2.6rem; }
.realisation-medias { display: grid; gap: 1.6rem; }
.realisation-medias figcaption { font-size: .82rem; color: var(--gris); padding-top: .5rem; }

/* ---------- bloc coordonnées (issues #29 et #30) ----------
   Un seul jeu de règles pour les trois endroits qui affichent les coordonnées :
   page Contact, pied de page et encart showroom d'une fiche produit. Le
   pictogramme tient lieu d'intitulé ; il est aligné sur la première ligne du
   texte pour qu'une adresse qui passe à la ligne reste lisible. */
.coords { font-style: normal; display: flex; flex-direction: column; gap: .55rem; }
.coords-name {
  font-size: .8rem; letter-spacing: .18em; text-transform: uppercase;
  color: var(--or-clair); margin-bottom: .3rem;
}
.coords-line {
  display: flex; align-items: flex-start; gap: .6rem; line-height: 1.5;
  color: #ccc; transition: color .2s;
}
.coords-line:hover, .coords-line:focus-visible { color: var(--or-clair); }
.coords-ic { width: 1.05em; height: 1.05em; flex: none; margin-top: .18em; color: var(--or); }
.coords-line:hover .coords-ic { color: var(--or-clair); }
/* Le lien carte est le seul du bloc à quitter le site : il se souligne au
   survol pour annoncer qu'il ouvre autre chose. */
.map-link:hover span, .map-link:focus-visible span { text-decoration: underline; }

/* Page Contact : le bloc est la colonne de gauche, on lui donne de l'air. */
.coords-page { gap: .85rem; font-size: 1rem; margin-bottom: 2rem; }
.coords-page .coords-name { font-size: 1.05rem; letter-spacing: .2em; }
.coords-page .coords-line { color: #ddd; }

/* Pied de page : même bloc, à l'échelle du reste du pied. */
.coords-footer { gap: .45rem; font-size: .92rem; }

/* Encart showroom d'une fiche produit : les lignes se suivent horizontalement
   tant que la place le permet. */
.coords-inline { flex-direction: row; flex-wrap: wrap; gap: .3rem 1.1rem; font-size: .82rem; }
.coords-inline .coords-line { color: var(--gris); gap: .4rem; }

/* ---------- pages / contact ---------- */
/* Pages éditoriales longues : mentions légales et compagnie (issue #46).
   Le corps du site remet toutes les marges à zéro (`* { margin: 0 }`) : sans les
   règles ci-dessous, les titres se collent au paragraphe précédent et la page
   arrive comme un seul pavé. La colonne de texte est bornée en `ch` : c'est la
   longueur de ligne qui fatigue l'œil, pas la largeur de l'écran. */
/* Moins large que les pages de catalogue : à deux colonnes, 1200px laissaient
   un tiers de blanc à droite du texte. */
.page-article { max-width: 62rem; }
.page-article .page-grid { display: block; }
.page-body {
  font-size: 1.02rem; line-height: 1.8; color: #d5d5d5;
  max-width: 62ch; text-wrap: pretty;
}
.page-body p { margin-bottom: 1.15rem; }
.page-body > *:first-child { margin-top: 0; padding-top: 0; border-top: 0; }

/* Un filet et beaucoup d'air au-dessus : c'est ce qui permet de repérer une
   section en faisant défiler, ce que ne faisait aucun titre auparavant. */
.page-body h2 {
  margin: 3.4rem 0 1.1rem; padding-top: 1.8rem;
  border-top: 1px solid rgba(255,206,68,.22);
  font-size: 1.42rem; line-height: 1.3; letter-spacing: .03em; color: var(--or);
}
.page-body h3 {
  margin: 2.3rem 0 .7rem;
  font-size: 1.08rem; letter-spacing: .06em; text-transform: uppercase; color: var(--blanc);
}
/* Le bandeau est fixe : sans cette marge, une ancre dépose son titre dessous. */
.page-body h2, .page-body h3 { scroll-margin-top: 7rem; }
.page-body strong, .page-body b { color: var(--blanc); font-weight: 600; }
.page-body ul, .page-body ol { margin: 0 0 1.4rem; padding-left: 1.35rem; }
.page-body ul { list-style: none; }
.page-body li { margin-bottom: .65rem; position: relative; }
.page-body ul > li::before {
  content: ""; position: absolute; left: -1.35rem; top: .78em;
  width: .42rem; height: 1px; background: var(--or);
}
.page-body a { color: var(--or); border-bottom: 1px solid rgba(255,206,68,.35); }
.page-body a:hover { border-bottom-color: var(--or); }
.page-body hr { border: 0; border-top: 1px solid rgba(255,255,255,.12); margin: 2.4rem 0; }

/* Sommaire : la page fait une dizaine de sections, personne ne défile à
   l'aveugle. Il reste sous les yeux tant que l'écran est assez large. */
.page-toc { margin-bottom: 2.8rem; border-left: 2px solid rgba(255,206,68,.35); padding-left: 1.2rem; }
.page-toc .toc-title {
  font-size: .72rem; letter-spacing: .22em; text-transform: uppercase;
  color: var(--gris); margin-bottom: .9rem; font-weight: 500;
}
.page-toc ol { list-style: none; display: grid; gap: .5rem; }
.page-toc a {
  display: block; font-size: .86rem; line-height: 1.45; color: #c9c9c9;
  border-left: 2px solid transparent; margin-left: -1.2rem; padding-left: 1.2rem;
  transition: color .2s, border-color .2s;
}
.page-toc a:hover { color: var(--or); }
/* La section en cours de lecture, suivie par site.js. */
.page-toc a.is-current { color: var(--or); border-left-color: var(--or); }

@media (min-width: 900px) {
  .page-article .page-grid {
    display: grid; grid-template-columns: 15rem minmax(0, 1fr); gap: 3.5rem;
    align-items: start;
  }
  .page-toc { position: sticky; top: 7rem; margin-bottom: 0; max-height: calc(100vh - 10rem); overflow-y: auto; }
}
@media (max-width: 640px) {
  .page-article { padding: 2rem 1.3rem 4rem; }
  .page-body { font-size: 1rem; line-height: 1.75; }
  .page-body h2 { font-size: 1.24rem; margin-top: 2.8rem; padding-top: 1.4rem; }
  .page-body h3 { font-size: 1rem; }
  .catalog h1, .page h1 { font-size: 1.7rem; margin-bottom: 1.4rem; }
}
/* Page « entreprise » : la carte de visite du magasin ferme la page (issue #78).
   Elle sort du meme fabricant que le pied de page et la page contact, donc les
   coordonnees restent d'accord partout. Le decalage sur grand ecran la remet
   sous la colonne de texte, a droite du sommaire. */
.page-coords { margin-top: 3.4rem; padding-top: 1.8rem; border-top: 1px solid rgba(255,206,68,.22); }
@media (min-width: 900px) { .page-article .page-grid + .page-coords { margin-left: 18.5rem; } }

.contact-cols { display: grid; grid-template-columns: 1fr 2fr; gap: 3rem; }
.contact-form label, .newsletter-form label { display: block; }
.contact-form label { margin-bottom: 1.1rem; font-size: .8rem; letter-spacing: .18em; text-transform: uppercase; color: var(--gris); }
.contact-form input, .contact-form textarea {
  width: 100%; margin-top: .4rem; padding: .75rem .9rem; background: var(--noir-2);
  border: 1px solid rgba(185,154,91,.3); color: var(--blanc); font-family: var(--sans); font-size: 1rem;
}
.contact-form input:focus, .contact-form textarea:focus { outline: none; border-color: var(--or); }
.flash { padding: 1rem 1.2rem; border: 1px solid var(--or); color: var(--or-clair); margin-bottom: 1.4rem; }

/* Piege a robots des formulaires de contact (issue #108). Hors ecran, et non
   `display: none` : les robots qui inspectent la feuille de style sautent
   justement ce qui est masque ainsi, alors qu'un champ pousse hors du cadre
   leur parait ordinaire. Il ne reste ni au clavier (tabindex="-1") ni pour un
   lecteur d'ecran (aria-hidden), donc aucun visiteur ne peut le remplir. */
.piege { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* ---------- carte du magasin, page contact (issue #48) ---------- */
/* Le plan est un SVG servi par le site, pose dans un cadre a rapport fixe.
   Deux consequences a garder en tete si on y touche :

   - Le rapport du cadre n'est pas celui du dessin (8/5). C'est voulu : `cover`
     recadre au centre, et le magasin est au centre du dessin, donc il reste
     visible quel que soit le rapport choisi. On peut changer l'un sans l'autre.
   - Sur telephone, la carte n'est pas retrecie, elle est agrandie. A 360 px de
     large, un plan de 600 m ne se lit plus : `scale()` zoome autour du repere,
     ce qui redonne aux noms de rue une taille de doigt. C'est un zoom, pas un
     recadrage : le trace reste vectoriel, donc net. */
.storemap-block { margin-top: 4rem; }
.storemap-title {
  font-size: 1.05rem; letter-spacing: .2em; text-transform: uppercase;
  color: var(--or-clair); margin-bottom: 1.2rem;
}
.storemap { margin: 0; }
.storemap-frame {
  position: relative; overflow: hidden;
  aspect-ratio: 16 / 7; background: var(--noir);
  border: 1px solid rgba(185,154,91,.28);
}
.storemap-plan { width: 100%; height: 100%; object-fit: cover; }

/* Le bouton d'itineraire est pose sur la carte, pas dessous : c'est la ou le
   doigt le cherche une fois qu'il a trouve le repere. */
.storemap-route {
  position: absolute; right: 1rem; bottom: 1rem;
  display: inline-flex; align-items: center; gap: .45rem;
  /* 44 px de haut : la recommandation tactile. Sur un plan, ce bouton est la
     seule chose qu'on vise avec le pouce. */
  min-height: 44px; padding: .62rem 1.05rem;
  font-size: .72rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--or-clair); background: rgba(13, 13, 13, .86);
  border: 1px solid var(--or); transition: background .25s, color .25s;
}
.storemap-route .storemap-ic { width: 15px; height: 15px; flex: none; }
.storemap-route:hover, .storemap-route:focus-visible { background: var(--or); color: var(--noir); }
.storemap-route:focus-visible { outline: 2px solid var(--blanc); outline-offset: 2px; }
/* La regle generale de .map-link souligne le libelle au survol : sur un bouton
   plein, c'est du bruit. */
.storemap-route:hover span, .storemap-route:focus-visible span { text-decoration: none; }

.storemap-legend {
  display: flex; flex-wrap: wrap; justify-content: space-between;
  gap: .5rem 1.5rem; margin-top: .8rem;
  font-size: .76rem; letter-spacing: .06em; color: var(--gris);
}
.storemap-credit a { border-bottom: 1px solid rgba(255, 255, 255, .2); }
.storemap-credit a:hover, .storemap-credit a:focus-visible { color: var(--or-clair); }

@media (max-width: 900px) {
  .storemap-block { margin-top: 3rem; }
  .storemap-frame { aspect-ratio: 4 / 3; }
  .storemap-plan { transform: scale(1.5); }
  .storemap-route { right: .7rem; bottom: .7rem; padding: .7rem 1rem; }
  .storemap-legend { justify-content: flex-start; }
}

/* Sur un telephone tenu a la main, un cadre panoramique ne laisse plus qu'une
   bande de deux cent cinquante pixels : la carte devient carree pour recuperer
   la hauteur que la largeur ne peut pas donner. */
@media (max-width: 560px) {
  .storemap-frame { aspect-ratio: 1 / 1; }
  .storemap-plan { transform: scale(1.45); }
}

/* ---------- footer ---------- */
.site-footer { border-top: 1px solid rgba(185,154,91,.25); padding: 3.5rem 2rem 2rem; margin-top: 4rem; }
.footer-cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 2.5rem; max-width: 1200px; margin: 0 auto; }
.site-footer h3 { font-size: 1.05rem; letter-spacing: .2em; text-transform: uppercase; color: var(--or-clair); margin-bottom: 1rem; }
.site-footer p { line-height: 2; color: #ccc; font-size: .92rem; }
.site-footer a:hover { color: var(--or-clair); }
.newsletter-form { display: flex; gap: .5rem; }
.newsletter-form input {
  flex: 1; padding: .65rem .8rem; background: var(--noir-2);
  border: 1px solid rgba(185,154,91,.3); color: var(--blanc);
}
.newsletter-form button {
  padding: .65rem 1.1rem; background: transparent; border: 1px solid var(--or);
  color: var(--or-clair); letter-spacing: .12em; text-transform: uppercase; font-size: .72rem; cursor: pointer;
}
.newsletter-form button:hover { background: var(--or); color: var(--noir); }

/* Information au point de collecte et consentement a la newsletter (issue #117).

   Deux exigences se rencontrent ici. La mention doit etre lue sans defilement
   supplementaire, donc elle se pose au-dessus du bouton d'envoi et reste
   discrete sans devenir illisible : 0.78rem sur le gris du site, jamais plus
   petit. Et la case de consentement doit rester une vraie case cochable au
   doigt : d'ou la ligne en `flex` avec la case alignee sur la premiere ligne du
   texte, et non un `float` qui la deporterait.

   La regle `.newsletter-form input` habille le champ e-mail (fond noir, bordure
   doree) ; la case n'en veut rien, d'ou la remise a plat qui suit. */
.rgpd-mention, .rgpd-note {
  font-size: .78rem; line-height: 1.65; color: var(--gris);
  letter-spacing: 0; text-transform: none; margin: 0 0 1.1rem;
}
.rgpd-mention a, .rgpd-note a { color: var(--or-clair); text-decoration: underline; }
.consentement {
  display: flex; align-items: flex-start; gap: .55rem;
  font-size: .82rem; line-height: 1.5; color: #ccc;
  letter-spacing: 0; text-transform: none; margin: .2rem 0 .6rem;
}
.consentement input {
  flex: 0 0 auto; width: 1.05rem; height: 1.05rem; margin-top: .18rem;
  padding: 0; background: none; border: 0; accent-color: var(--or);
}
/* Le pied de page pose le champ et le bouton sur une ligne : la case et sa note
   prennent la largeur entiere sous eux plutot que de s'y glisser. */
.newsletter-form { flex-wrap: wrap; }
.newsletter-form .consentement, .newsletter-form .rgpd-note { flex: 1 0 100%; }
/* `.newsletter-form label { display: block }` est plus specifique que
   `.consentement` : sans cette ligne, la case reviendrait au-dessus du texte. */
.newsletter-form .consentement { display: flex; }
.newsletter-form .rgpd-note { margin-bottom: 0; }
/* Reseaux sociaux (issue #124) : sous les coordonnees du pied de page, en
   pictogrammes a l'or du site. La cible tactile fait 2.4rem alors que le
   glyphe n'en fait que 1.25 : un lien de 20 px se rate au doigt. */
.footer-social { display: flex; gap: .5rem; margin-top: .9rem; }
.reseau-lien {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2.4rem; height: 2.4rem; margin-left: -.55rem; border-radius: 50%;
  color: var(--or); transition: color .2s, background .2s;
}
.reseau-lien:hover, .reseau-lien:focus-visible {
  color: var(--or-clair); background: rgba(255,206,68,.1);
}
.reseau-ic { width: 1.25rem; height: 1.25rem; }
.footer-legal { text-align: center; color: var(--gris); font-size: .78rem; margin-top: 3rem; letter-spacing: .08em; }
/* Mediateur de la consommation (issue #116) : mention legale obligatoire, donc
   lisible — meme taille que la ligne de copyright, pas plus petite. Elle prend
   la place de la marge haute de .footer-legal quand elle est presente. */
.footer-mediateur {
  text-align: center; color: var(--gris); font-size: .78rem;
  margin: 3rem auto 0; max-width: 46rem; line-height: 1.7;
}
.footer-mediateur + .footer-legal { margin-top: .6rem; }
.footer-mediateur a { color: var(--or-clair); }
.page-mediateur { margin-top: 3rem; }
.coords-mediateur { font-style: normal; line-height: 1.8; }
.coords-mediateur .mediateur-nom { font-weight: 600; }

/* ---------- mobile ---------- */
@media (max-width: 1430px) {
  .burger { display: block; }
  .mega { display: none !important; }
  .header-contact { display: none; }
  .brand-mark { height: 40px; }
  .brand-name { font-size: 1.05rem; letter-spacing: .28em; margin-right: -.28em; }
  .brand-sub { font-size: .58rem; }
  .site-nav { display: none; }

  /* ---------- menu mobile plein ecran (accordeon) ---------- */
  body.nav-open { overflow: hidden; }
  body.nav-open .site-nav {
    display: block; position: fixed; inset: 0; z-index: 60;
    background: #0d0d0d; padding: 4.8rem 0 3rem; overflow-y: auto;
    -webkit-overflow-scrolling: touch;
  }
  body.nav-open .site-nav .nav-left,
  body.nav-open .site-nav .nav-right { display: block; width: 100%; }
  body.nav-open .site-nav ul { display: block; gap: 0; }
  body.nav-open .site-nav .menu-item {
    display: flex; flex-wrap: wrap; align-items: stretch;
    border-bottom: 1px solid rgba(255,255,255,.08);
  }
  body.nav-open .site-nav .menu-item > a {
    flex: 1; padding: 1.15rem 1.6rem; font-size: .88rem; letter-spacing: .18em;
    text-transform: uppercase; color: var(--blanc);
  }
  body.nav-open .site-nav .menu-item > a::after { display: none; }
  body.nav-open .site-nav .menu-item.active > a { color: var(--or-clair); }
  body.nav-open .site-nav .menu-item.open > a { color: var(--or-clair); }
  body.nav-open .site-nav .nav-right .menu-item > a { color: var(--gris); }

  .submenu-toggle {
    display: flex; align-items: center; justify-content: center;
    width: 58px; background: none; border: 0; border-left: 1px solid rgba(255,255,255,.08);
    cursor: pointer; position: relative; flex: none;
  }
  .submenu-toggle span {
    position: absolute; width: 13px; height: 1px; background: var(--or);
    transition: transform .25s, opacity .25s;
  }
  .submenu-toggle span:nth-child(2) { transform: rotate(90deg); }
  .menu-item.open .submenu-toggle span:nth-child(2) { transform: rotate(0); opacity: 0; }

  body.nav-open .site-nav .submenu {
    display: none; position: static; transform: none; opacity: 1; visibility: visible;
    width: 100%; min-width: 0; border: 0; background: #141412;
    text-align: left; padding: .5rem 0 .9rem;
  }
  body.nav-open .site-nav .menu-item.open > .submenu { display: block; }
  body.nav-open .site-nav .submenu li { display: block; }
  body.nav-open .site-nav .submenu a {
    display: block; padding: .62rem 1.6rem .62rem 2.6rem;
    font-size: .8rem; letter-spacing: .1em; text-transform: none; color: #cfcfcf;
  }
  body.nav-open .site-nav .submenu a:hover { color: var(--or-clair); background: none; }
  body.nav-open .site-nav .submenu .submenu-all a {
    color: var(--or); font-size: .72rem; letter-spacing: .2em; text-transform: uppercase;
    padding-top: .8rem;
  }
  /* Menu mobile : le panneau .mega est réservé au grand écran, le lien du
     configurateur vit donc dans le sous-menu des catégories (issue #71). Il
     porte la couleur dorée et un filet pour ne pas se confondre avec une
     catégorie de produits, et garde 44 px de haut pour le doigt. */
  body.nav-open .site-nav .submenu .submenu-conf a {
    color: var(--or); font-weight: 600; letter-spacing: .06em;
    margin-top: .35rem; padding-top: .75rem; min-height: 44px;
    border-top: 1px solid rgba(185,154,91,.28);
  }
  .nav-mobile-foot { display: block; padding: 2rem 1.6rem 0; }
  .nav-mobile-foot a {
    display: flex; font-size: .82rem; letter-spacing: .1em; color: var(--gris);
    padding: .35rem 0;
  }
  .nav-mobile-foot a:hover { color: var(--or-clair); }

  body.nav-open .burger { position: fixed; top: 1.15rem; left: 1.4rem; z-index: 70; }
  body.nav-open .burger span:nth-child(1) { transform: translateY(8px) rotate(45deg); }
  body.nav-open .burger span:nth-child(2) { opacity: 0; }
  body.nav-open .burger span:nth-child(3) { transform: translateY(-8px) rotate(-45deg); }
  body.nav-open .site-header .brand { opacity: 0; pointer-events: none; }
  /* rappel discret de la catégorie courante (CdC mobile) */
  .mobile-category { display: block; }
  .product-layout, .contact-cols { grid-template-columns: 1fr; }
  .product-gallery { padding: 1.4rem 1.2rem 0; }
  .product-aside { padding: 2rem 1.4rem 0; }
  .product-info { position: static; }
  .cta-row { grid-template-columns: 1fr; }
  .carousel { height: 88vh; }
  body:not(.home) main { padding-top: 6.4rem; }
  .universe-hero { margin-top: 0; }
}

/* ---------- recherche instantanée du bandeau (issue #38) ---------- */
/* Tout le bloc vit ici, y compris sa version compacte : le champ, la loupe et
   la liste de suggestions se règlent ensemble, les séparer sur deux endroits du
   fichier fait diverger les deux moitiés au premier ajustement.
   Sur grand écran le champ est posé à droite du bandeau, donc à droite du logo,
   et la liste tombe sous lui. En dessous de 1430px, le bandeau n'a plus la
   place : seule la loupe reste, et elle déplie le champ sur toute la largeur. */
.site-search { position: relative; flex: none; display: flex; align-items: center; margin-left: 1.2rem; }

.search-toggle {
  display: none; align-items: center; justify-content: center;
  width: 42px; height: 42px; padding: 0;
  background: none; border: 0; color: var(--blanc); cursor: pointer;
}
.search-ic { width: 17px; height: 17px; flex: none; opacity: .8; }
.search-form:focus-within .search-ic { opacity: 1; color: var(--or); }
.search-panel { position: relative; }

.search-form {
  display: flex; align-items: center; gap: .5rem; width: 190px;
  padding: .42rem .8rem; border-radius: 999px;
  border: 1px solid rgba(255,255,255,.22); background: rgba(255,255,255,.06);
  transition: width .25s, border-color .25s, background .25s;
}
.search-form:focus-within {
  width: 265px; border-color: var(--or); background: rgba(255,255,255,.1);
}
.search-input {
  flex: 1; min-width: 0; padding: 0; background: none; border: 0; outline: none;
  color: var(--blanc); font-family: var(--sans); font-size: .78rem; letter-spacing: .03em;
  -webkit-appearance: none; appearance: none;
}
.search-input::placeholder { color: var(--gris); }
/* La croix native de <input type="search"> double la nôtre et ne se style pas. */
.search-input::-webkit-search-cancel-button,
.search-input::-webkit-search-decoration { -webkit-appearance: none; display: none; }
.search-clear {
  flex: none; padding: 0 .15rem; background: none; border: 0; cursor: pointer;
  color: var(--gris); font-size: 1.05rem; line-height: 1;
}
.search-clear:hover { color: var(--blanc); }
/* Le clavier doit voir où il est : la loupe et la croix n'ont pas le cadre du champ. */
.search-toggle:focus-visible, .search-clear:focus-visible {
  outline: 2px solid var(--or); outline-offset: 2px; border-radius: 4px;
}

.search-results {
  position: absolute; z-index: 60; top: calc(100% + .7rem); right: 0;
  width: 380px; max-width: calc(100vw - 2rem);
  max-height: min(70vh, 30rem); overflow-y: auto; overscroll-behavior: contain;
  background: #141412; border: 1px solid rgba(255,255,255,.12);
  box-shadow: 0 18px 44px rgba(0,0,0,.55);
}
.search-list { list-style: none; margin: 0; padding: .3rem 0; }
.search-opt > a { display: flex; align-items: center; gap: .85rem; padding: .5rem .85rem; }
.search-opt img, .search-thumb-empty {
  flex: none; width: 46px; height: 46px; object-fit: cover;
  background: var(--noir-2); border: 1px solid rgba(255,255,255,.07);
}
.search-body { flex: 1; min-width: 0; }
/* Un nom de produit peut être très long : il se coupe plutôt qu'il n'élargit la liste. */
.search-name, .search-meta {
  display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.search-name { font-size: .82rem; color: var(--blanc); }
.search-meta {
  margin-top: .2rem; font-size: .64rem; letter-spacing: .13em;
  text-transform: uppercase; color: var(--gris);
}
/* Survol souris et sélection clavier disent la même chose : c'est cette ligne
   qu'un Entrée ouvrirait. */
.search-opt > a:hover, .search-opt.selected > a { background: rgba(255,206,68,.13); }
.search-opt.selected .search-name { color: var(--or-clair); }
.search-empty { padding: 1.1rem .95rem; font-size: .8rem; color: var(--gris); }

@media (max-width: 1430px) {
  /* La loupe se colle à droite du bandeau ; le panneau se repère sur
     .header-row (d'où le position: static ici) pour tenir toute la largeur. */
  .site-search { position: static; margin-left: auto; }
  .search-toggle { display: flex; }
  .search-panel {
    display: none; position: absolute; top: 100%; left: 0; right: 0;
    padding: .1rem 1.1rem 1.1rem; background: rgba(13,13,13,.98);
    border-bottom: 1px solid rgba(255,255,255,.1);
  }
  .site-search.open .search-panel { display: block; }
  .search-form, .search-form:focus-within { width: 100%; }
  .search-input { font-size: 16px; }  /* en dessous, iOS zoome sur le champ */
  .search-results {
    position: static; width: auto; max-width: none; margin-top: .7rem;
    box-shadow: none;
    /* Le clavier virtuel mange le bas de l'écran : dvh suit sa hauteur réelle,
       vh reste le repli pour les navigateurs qui ne le connaissent pas. */
    max-height: min(58vh, 26rem);
    max-height: min(58dvh, 26rem);
  }
  .search-opt > a { padding: .62rem .8rem; }
  .search-name { font-size: .88rem; }
  /* Menu plein écran ouvert : la loupe n'a plus rien à faire dessous. */
  body.nav-open .site-search { display: none; }
  /* Bandeau opaque tant que le panneau est déplié, sinon le dégradé du header
     laisse voir la page à travers le champ. */
  body.search-open .site-header { background: rgba(13,13,13,.98); }
}

/* Repli sans JavaScript : la page /recherche reprend la liste de suggestions,
   en page entière (voir searchPage() dans src/search.ts). */
.search-page { max-width: 720px; }
.search-page-q { color: var(--gris); font-size: .9rem; margin: -.6rem 0 1.6rem; }
.search-page .search-list { border: 1px solid rgba(255,255,255,.12); background: var(--noir-2); }
