@charset "utf-8";
/* ==========================================================================
   SWADCOIFF · Académie du Lissage Brésilien — Rouen
   Feuille de style unique. Direction artistique figée dans /DESIGN.md.
   Toute valeur ici doit correspondre à un token de ce fichier.
   ========================================================================== */

/* =========================================================================
   Polices hÃ©bergÃ©es localement â Spectral et Jost
   =========================================================================
   Servies depuis ce serveur et non plus depuis fonts.googleapis.com et
   fonts.gstatic.com. Le chargement depuis Google transmettait l'adresse IP
   de chaque visiteur Ã  un tiers Ã©tabli hors de l'Union europÃ©enne, sur les
   vingt pages du site â y compris la page de confidentialitÃ© elle-mÃªme.

   Seuls les sous-ensembles Â« latin Â» et Â« latin-ext Â» sont conservÃ©s : ils
   couvrent l'intÃ©gralitÃ© des caractÃ¨res employÃ©s ici, tiret cadratin, guillemet
   typographique, symbole euro et le Â« Â· Â» de la signature graphique compris.
   Cyrillique, grec et vietnamien ont Ã©tÃ© Ã©cartÃ©s â ils n'auraient jamais servi.

   font-display: swap est conservÃ©, Ã  l'identique du paramÃ¨tre ?display=swap
   qui figurait dans l'URL Google : le texte reste lisible pendant le
   chargement, dans une police de repli.
   ========================================================================= */

@font-face {
  font-family: 'Jost';
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url('../assets/fonts/jost-300-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: 'Jost';
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url('../assets/fonts/jost-300-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: 'Jost';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../assets/fonts/jost-300-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: 'Jost';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../assets/fonts/jost-300-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: 'Spectral';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('../assets/fonts/spectral-400-italique-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: 'Spectral';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('../assets/fonts/spectral-400-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;
}

@font-face {
  font-family: 'Spectral';
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url('../assets/fonts/spectral-300-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: 'Spectral';
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url('../assets/fonts/spectral-300-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: 'Spectral';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../assets/fonts/spectral-400-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: 'Spectral';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../assets/fonts/spectral-400-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: 'Spectral';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../assets/fonts/spectral-500-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: 'Spectral';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../assets/fonts/spectral-500-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;
}

/* --------------------------------------------------------------------------
   1. TOKENS
   -------------------------------------------------------------------------- */
:root {
  /* Couleur — §3.2 DESIGN.md */
  --noir:            #050505;
  --encre:           #0B0B0B;
  --os:              #F5F5F0;
  --os-attenue:      #8E8B84;   /* 7.3:1 sur --noir */
  --champagne:       #B9A88A;   /* accent unique */
  --champagne-sourd: #6E6552;
  --buriti:          #5E1A17;   /* aplat de section uniquement */

  --prisme: linear-gradient(90deg, #B9A88A, #6E7F8D, #8A6E7F, #B9A88A);

  /* Typographie — §3.1 */
  --display: "Spectral", "Iowan Old Style", "Palatino Linotype", Georgia, serif;
  --texte:   "Jost", "Futura", "Century Gothic", sans-serif;

  --t-display: clamp(3.2rem, 11vw, 9.5rem);
  --t-h1:      clamp(2.4rem, 6.5vw, 5.2rem);
  --t-h2:      clamp(1.9rem, 4vw, 3.1rem);
  --t-h3:      clamp(1.35rem, 2.2vw, 1.75rem);
  --t-body:    clamp(0.95rem, 1.05vw, 1.05rem);
  --t-label:   0.7rem;

  /* Grille — §3.3 */
  --bord: clamp(1.25rem, 5vw, 5.5rem);

  /* Rythme — §3.4 : deux régimes opposés, jamais uniforme */
  --air-campagne: clamp(9rem, 22vh, 15rem);
  --air-document: clamp(4rem, 8vh, 6rem);

  /* Mouvement */
  --transition: 900ms cubic-bezier(.16, 1, .3, 1);
  --transition-court: 320ms cubic-bezier(.16, 1, .3, 1);
}

/* --------------------------------------------------------------------------
   1 bis. RÔLES DE COULEUR — la couche que consomme le reste de la feuille
   --------------------------------------------------------------------------
   Les tokens ci-dessus nomment des PIGMENTS (--noir, --os, --champagne).
   Ceux-ci nomment des USAGES. Seules ces variables-là sont employées dans les
   règles : basculer tout le site revient donc à réécrire huit valeurs.

   Le mode nuit reste le défaut, à l'identique de l'existant — arriver sur le
   site sans préférence enregistrée donne exactement le rendu d'avant.
   Le mode jour est un choix du visiteur, jamais un état initial. */
:root {
  --fond:           var(--noir);
  --fond-rgb:       5, 5, 5;
  --relief:         var(--encre);
  --plume:          var(--os);
  --plume-attenuee: var(--os-attenue);
  --accent:         var(--champagne);
  --accent-sourd:   var(--champagne-sourd);
  --filet-rgb:      110, 101, 82;

  /* Voile posé SUR une photographie pour qu'un texte clair y reste lisible.
     Il ne bascule JAMAIS : on ne peut pas « éclaircir » une photographie, donc
     le texte qu'elle porte reste clair dans les deux modes. C'est la seule
     couleur du site volontairement insensible au thème. */
  /* Vert de disponibilite. Aucun vert unique ne tient 4,5:1 sur les DEUX
     fonds : mesure a l'appui, #6E9E6B donne 6,6:1 sur le noir mais 2,5:1
     sur le gris chaud. Il est donc declare par theme, comme les autres roles. */
  --vert-stock:     #6E9E6B;   /* 6,6:1 sur --fond */

  --scrim-rgb:      5, 5, 5;

  color-scheme: dark;
}

/* Mode jour. Ni la grille, ni les graisses, ni les espacements ne bougent :
   seules les valeurs de rôle sont réécrites. Les ratios notés en regard sont
   mesurés, pas estimés — voir le tableau en fin de DESIGN.md. */
:root[data-theme="light"] {
  --fond:           #E9E6DF;   /* gris chaud doux, et non un blanc atténué */
  --fond-rgb:       233, 230, 223;
  --relief:         #E1DED6;   /* surface en léger retrait */
  --plume:          #14120F;   /* anthracite chaud — 15,0:1 */
  --plume-attenuee: #5F5C56;   /*  5,4:1 — calé sur le ratio du mode nuit */
  --accent:         #6E582C;   /*  5,4:1 — le champagne descendu en bronze */
  --accent-sourd:   #8A7B57;   /* décoratif seul */
  --filet-rgb:      110, 101, 82;

  /* Le prisme conserve ses quatre teintes mais assombries : sur fond clair,
     les valeurs de nuit disparaissaient purement et simplement. */
  --vert-stock:     #456B43;   /* 4,9:1 sur --fond */

  --prisme: linear-gradient(90deg, #6E582C, #3C4A54, #604451, #6E582C);

  color-scheme: light;
}

/* Îlots sombres — les endroits où un texte se pose SUR une photographie.
   La palette de nuit y reprend la main dans les DEUX modes : le voile qui
   porte ce texte reste sombre, un anthracite y serait illisible. Redéclarer
   les rôles sur le conteneur suffit, les descendants héritent — aucune règle
   enfant n'a besoin d'être dupliquée. */
.hero,
.section-campagne,
.gamme-banniere,
.triptyque figcaption {
  --plume:          var(--os);
  --plume-attenuee: var(--os-attenue);
  --accent:         var(--champagne);
  --accent-sourd:   var(--champagne-sourd);
  --filet-rgb:      110, 101, 82;

  /* Le fond aussi doit rester sombre dans l'îlot : .bouton-plein pose
     color: var(--fond) sur un aplat var(--accent). Sans cette ligne, un
     bouton posé sur une campagne affichait du crème sur du champagne —
     2,23:1. Trouvé par le balayage, invisible à l'œil sur maquette. */
  --fond:           var(--noir);
  --fond-rgb:       5, 5, 5;

  /* INDISPENSABLE — et non redondant avec --plume ci-dessus.
     L'héritage CSS transmet la couleur DÉJÀ CALCULÉE par body, pas
     l'expression var(). Sans cette ligne, redéclarer --plume sur le
     conteneur ne change rien pour les descendants qui héritent : le
     titre du hero restait anthracite sur la photo sombre. Vérifié. */
  color: var(--plume);
}

/* --------------------------------------------------------------------------
   2. SOCLE
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

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

body {
  margin: 0;
  background: var(--fond);
  color: var(--plume);
  font-family: var(--texte);
  font-weight: 300;
  font-size: var(--t-body);
  line-height: 1.85;
  overflow-x: hidden;            /* aucun défilement horizontal — §5 */
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* Grain argentique — §3.5 — RETIRÉ le 29/08/2026 pour la fluidité du
   défilement. C'était un calque fixe plein écran en mix-blend-mode: overlay :
   le fondu dépend de ce qui est dessous, donc le navigateur devait relire et
   recomposer tout le viewport à chaque image, sans pouvoir rien mettre en
   cache côté processeur graphique.
   Code complet et marche à suivre pour le remettre :
   scratchpad/RESTAURER-grain-argentique.md */

img, video { max-width: 100%; display: block; }

a { color: inherit; }

::selection { background: var(--accent); color: var(--fond); }

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

.saut-contenu {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--accent);
  color: var(--fond);
  padding: .9rem 1.4rem;
  font-family: var(--texte);
  font-size: var(--t-label);
  letter-spacing: .32em;
  text-transform: uppercase;
  z-index: 10000;
}
.saut-contenu:focus { left: var(--bord); top: .75rem; }

.invisible {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* --------------------------------------------------------------------------
   3. TYPOGRAPHIE
   -------------------------------------------------------------------------- */
h1, h2, h3, h4 {
  font-family: var(--display);
  font-weight: 400;
  margin: 0;
  line-height: 1.02;
}

.display {
  font-size: var(--t-display);
  text-transform: uppercase;
  letter-spacing: .08em;
  line-height: .92;
}

h1, .h1 {
  font-size: var(--t-h1);
  text-transform: uppercase;
  letter-spacing: .1em;
}

h2, .h2 {
  font-size: var(--t-h2);
  text-transform: uppercase;
  letter-spacing: .14em;
}

h3, .h3 {
  font-size: var(--t-h3);
  letter-spacing: .06em;
}

p { margin: 0 0 1.35em; }

.mesure  { max-width: 38ch; }   /* mesure bloquée — §3.3 */
.mesure-large { max-width: 54ch; }

.attenue { color: var(--plume-attenuee); }

/* Sur-titre : le geste signature en préfixe — §3.7-1 */
.surtitre {
  font-family: var(--texte);
  font-weight: 400;
  font-size: var(--t-label);
  letter-spacing: .32em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 1.6rem;
  display: block;
}
/* Chiffres romains des prestations — §3.7-7
   Le chiffre est du contenu (il numérote la prestation) : il lui faut 4.5:1.
   --champagne-sourd ne donne que 3.54:1 sur le noir, on le réserve donc au
   « ··· » décoratif qui le précède. */
.romain {
  font-family: var(--display);
  font-size: var(--t-label);
  letter-spacing: .3em;
  color: var(--plume-attenuee);      /* 5.99:1 sur --noir */
  font-variant-numeric: normal;
}

/* Lien : soulignement pointillé qui se densifie — §3.7-5 */
.lien {
  text-decoration: none;
  border-bottom: 1px dotted var(--accent-sourd);
  padding-bottom: .18em;
  color: var(--accent);
  transition: border-color var(--transition-court), color var(--transition-court);
}
.lien:hover, .lien:focus-visible {
  border-bottom-style: solid;
  border-bottom-color: var(--accent);
  color: var(--plume);
}

/* Une action qui a l'allure d'un lien mais qui n'en est pas une : elle ne mène
   nulle part, elle agit sur la page. Un <a href="#"> aurait menti au lecteur
   d'écran et sali l'historique de navigation. */
.lien-bouton {
  appearance: none;
  background: none;
  border: 0;
  border-bottom: 1px dotted var(--accent-sourd);
  padding: 0 0 .18em;
  font: inherit;
  color: var(--accent);
  cursor: pointer;
  transition: border-color var(--transition-court), color var(--transition-court);
}
.lien-bouton:hover, .lien-bouton:focus-visible {
  border-bottom-style: solid;
  border-bottom-color: var(--accent);
  color: var(--plume);
}

/* Fil d'Ariane. L'écart entre les étapes était porté par le séparateur
   décoratif « ··· », retiré le 29/08/2026 : sans lui, les items tombaient à
   6 px l'un de l'autre au lieu d'environ 38 px, et se lisaient comme une
   seule suite de mots. L'espacement est donc porté par les items eux-mêmes.
   Le sélecteur « * + * » épargne le premier — pas de retrait parasite à
   gauche — et un margin plutôt qu'un word-spacing, car plusieurs libellés
   font deux mots (« Lissage brésilien », « Couleurs & mèches ») : un
   word-spacing les aurait disloqués de l'intérieur. */
.fil-ariane > * + * { margin-left: 1.6em; }

/* --------------------------------------------------------------------------
   4. GESTE SIGNATURE — le filet pointillé — §3.7
   -------------------------------------------------------------------------- */
.filet {
  height: 1px;
  border: 0;
  margin: 0;
  background-image: radial-gradient(circle, var(--accent-sourd) 0 1px, transparent 1.2px);
  background-size: 9px 1px;
  background-repeat: repeat-x;
  background-position: 0 50%;
}

/* Le filet se trace de gauche à droite quand il entre à l'écran — §4 */
.filet.tracer {
  background-size: 0 1px;
  transition: background-size 500ms cubic-bezier(.16, 1, .3, 1);
}
.filet.tracer.vu { background-size: 9px 1px; }

.filet-prisme {
  height: 1px;
  border: 0;
  margin: 0;
  background: var(--prisme);
  opacity: .55;
}

/* Puces — §3.7-4 */
.liste-points { list-style: none; margin: 0; padding: 0; }
.liste-points li {
  margin-bottom: .7em;
}

/* --------------------------------------------------------------------------
   5. GRILLE — §3.3
   -------------------------------------------------------------------------- */
.grille {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  column-gap: clamp(1rem, 2.2vw, 2rem);
  padding-inline: var(--bord);
}

/* Décalage éditorial : le titre démarre en colonne 2, jamais en 1 */
.col-titre { grid-column: 2 / span 6; }
.col-texte { grid-column: 7 / span 5; }
.col-plein { grid-column: 1 / -1; }
.col-large { grid-column: 2 / span 10; }

@media (max-width: 900px) {
  .grille { grid-template-columns: 1fr; }
  .col-titre, .col-texte, .col-large { grid-column: 1 / -1; }
}

.section-campagne { padding-block: var(--air-campagne); }
.section-document { padding-block: var(--air-document); }

.pleine-largeur {
  width: 100vw;
  margin-left: calc(50% - 50vw);
}

/* --------------------------------------------------------------------------
   6. IMAGE — §3.6 : deux traitements strictement séparés
   -------------------------------------------------------------------------- */

/* Zone campagne : la photo émerge du noir.
   La COULEUR est conservée. Seul le hero reste en noir et blanc (règle propre
   à .hero-media, §9) : c'est le moment « affiche » du site. Partout ailleurs,
   les visuels Amaxxon gardent leur rouge buriti, leur vert forêt et leurs
   reflets prismatiques — les désaturer privait le site de sa seule chaleur. */
.img-campagne {
  filter: contrast(1.06) saturate(1.04);
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.cadre-campagne {
  position: relative;
  overflow: hidden;
  background: var(--fond);
}
/* Vignettage — §3.5 */
.cadre-campagne::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(120% 90% at 50% 45%, transparent 40%, rgba(var(--fond-rgb), .72) 100%);
}

/* Image placée EN FOND de section, avec du texte par-dessus.
   Le cadrage change à chaque largeur d'écran : sans voile fixe, une zone
   claire de la photo peut passer sous le texte et faire tomber le contraste
   sous le seuil AA. Le voile est donc calculé pour le pire cas. */
.cadre-campagne.fond .img-campagne {
  filter: contrast(1.04) saturate(.92) brightness(.46);
}
.cadre-campagne.fond::after {
  background:
    linear-gradient(rgba(var(--scrim-rgb), .82), rgba(var(--scrim-rgb), .88)),
    radial-gradient(120% 90% at 50% 45%, transparent 30%, rgba(var(--scrim-rgb), .6) 100%);
}

/* Fondu vers le noir sur un bord : la photo n'est jamais un rectangle posé */
/* Fondu d'un bord vers le noir de la page.
   ATTENTION : réalisé en calque ::after et NON avec mask-image. Le masque fait
   disparaître l'image entière sur certains moteurs de rendu — vérifié sur ce
   projet. La classe se pose sur le CADRE, pas sur l'<img>. */
.cadre-campagne.fondu-droite::after {
  background:
    linear-gradient(to right, transparent 52%, rgba(var(--fond-rgb), .6) 80%, var(--fond) 100%),
    radial-gradient(120% 90% at 50% 45%, transparent 40%, rgba(var(--fond-rgb), .72) 100%);
}
.cadre-campagne.fondu-gauche::after {
  background:
    linear-gradient(to left, transparent 52%, rgba(var(--fond-rgb), .6) 80%, var(--fond) 100%),
    radial-gradient(120% 90% at 50% 45%, transparent 40%, rgba(var(--fond-rgb), .72) 100%);
}
.cadre-campagne.fondu-bas::after {
  background:
    linear-gradient(to bottom, transparent 48%, rgba(var(--fond-rgb), .6) 78%, var(--fond) 100%),
    radial-gradient(120% 90% at 50% 45%, transparent 40%, rgba(var(--fond-rgb), .72) 100%);
}

/* Sur mobile les blocs s'empilent : un fondu latéral n'a plus de sens,
   il masquerait un tiers de l'image. */
@media (max-width: 900px) {
  .cadre-campagne.fondu-droite::after,
  .cadre-campagne.fondu-gauche::after {
    background: radial-gradient(120% 90% at 50% 45%, transparent 45%, rgba(var(--fond-rgb), .6) 100%);
  }
}

/* Boutique : couleur intacte, aucun filtre — lisibilité commerciale */
/* Cadre carré : les packshots fournis sont en 700×500 (paysage). Un cadre
   portrait 4/5 en rognerait près de la moitié de la largeur et couperait les
   flacons ; le carré ne prend qu'environ 20 % et garde le produit entier. */
/* Le cadre porte le format (carré), l'image s'y inscrit en entier.
   Auparavant : aspect-ratio sur l'IMAGE + object-fit: cover. Les seize
   packshots produit sont en 700×500 (ratio 1,4) ; forcés au carré en « cover »,
   ils étaient rognés d'un quart sur les côtés — les flacons sortaient du cadre.
   Seules les deux vignettes de routine, carrées d'origine, tombaient juste :
   d'où des cartes visuellement dépareillées.
   En « contain », le flacon est entier et centré, et les bandes libres prennent
   le fond du cadre. Même motif que .suggestion-media, qui l'utilisait déjà. */
.img-produit {
  width: 100%;
  height: 100%;
  max-width: 100%;
  display: block;
  object-fit: contain;
  object-position: center;
  transition: transform var(--transition);
}

/* --------------------------------------------------------------------------
   7. EN-TÊTE
   -------------------------------------------------------------------------- */
.entete {
  position: sticky;
  top: 0;
  z-index: 900;
  /* .90 et non .82 : la barre est translucide et passe au-dessus du hero.
     À .82, une zone claire de la photo remontait sous la navigation et
     faisait tomber les liens à 3,99:1 — sous le seuil AA. Défaut mesuré,
     pas supposé : il existait déjà avant le mode jour. */
  background: rgba(var(--fond-rgb), .90);

  /* L'en-tête redéclare son propre ton atténué, calibré pour le pire
     recouvrement. Le reste du site garde le sien : inutile d'assombrir
     toutes les mentions secondaires du site pour un cas propre à la barre. */
  --plume-attenuee: #A6A39B;   /* 6.8:1 sur le pire fond composé */
  /* Plus de flou d'arrière-plan : recalculé à chaque image du défilement,
     c'était l'effet le plus coûteux de la page. Fond quasi opaque à la place. */
  background: rgba(var(--fond-rgb), .97);
  border-bottom: 1px solid rgba(var(--filet-rgb), .28);
}

/* L'en-tête porte logo + 8 liens + panier + téléphone + bouton. Il n'a pas la
   même marge de bord que le contenu, sinon il déborde dès 1440px. */
.entete-interne {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: clamp(.75rem, 1.5vw, 1.5rem);
  padding: .95rem clamp(1.25rem, 2.5vw, 2.75rem);
}

/* Logotype : didone trackée + le ··· du sous-texte — M1/M2 */
.logo {
  text-decoration: none;
  display: inline-block;
  line-height: 1;
  flex-shrink: 0;
}
.logo-nom {
  font-family: var(--display);
  font-size: clamp(1.1rem, 2vw, 1.5rem);
  letter-spacing: .3em;
  text-transform: uppercase;
  display: block;
  color: var(--plume);
}
/* Pas de « ··· » ici : le geste signature reste réservé au contenu
   (sur-titres, séparateurs de section). Sur le logo et dans la navigation,
   il surchargeait une zone déjà dense. */
.logo-sous {
  font-family: var(--texte);
  font-size: .5rem;
  font-weight: 400;
  letter-spacing: .38em;
  text-transform: uppercase;
  color: var(--plume-attenuee);
  display: block;
  margin-top: .42em;
}

.logo::after {
  content: "";
  display: block;
  height: 1px;
  margin-top: .5em;
  background: var(--prisme);
  opacity: 0;
  transition: opacity var(--transition-court);
}
.logo:hover::after, .logo:focus-visible::after { opacity: .75; }

/* Navigation — séparateur ··· entre les items — §3.7-2 */
.nav { display: flex; align-items: center; gap: 0; }

.nav a {
  font-family: var(--texte);
  font-size: var(--t-label);
  font-weight: 400;
  letter-spacing: .28em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--plume-attenuee);
  padding: .95rem clamp(.4rem, .8vw, .85rem);   /* cible ≥ 44px de haut */
  position: relative;
  white-space: nowrap;
  transition: color var(--transition-court);
}

/* Entre 1280 et 1600px, on resserre le tracking de la navigation pour que
   la barre tienne sans renvoyer les portables vers le menu burger. */
/* Bande 1280–1600px : le portable doit garder la navigation complète plutôt
   que basculer sur le menu burger. À 1280px, l'en-tête demandait 1352px
   pour 1280 disponibles — la page défilait latéralement. Mesuré, pas estimé.
   On resserre donc marges, gouttières et interlettrage plutôt que de
   sacrifier un élément : le téléphone reste visible (§5). */
@media (min-width: 1280px) and (max-width: 1600px) {
  .entete-interne { padding-inline: 1.25rem; gap: .55rem; }
  .nav a { letter-spacing: .1em; padding-inline: .3rem; }
  .entete-actions { gap: .3rem; }
  .tel-entete { letter-spacing: .06em; padding-inline: .35rem; }
  .panier-entete { letter-spacing: .08em; padding-inline: .35rem; }
  .entete-actions .bouton { padding: .95rem 1rem; letter-spacing: .14em; }
  .bascule-theme { width: 38px; }
}
.nav a:hover, .nav a:focus-visible { color: var(--plume); }

/* La boutique est le seul item marchand du menu : elle porte la couleur
   d'accent, celle qui signale déjà les liens actionnables ailleurs. Pas un
   second bouton — « Réserver » en est déjà un, et deux boutons dans une même
   barre se seraient neutralisés. Le :not() laisse la page courante garder son
   traitement habituel, sans bataille de spécificité. */
.nav a.nav-boutique:not([aria-current]) { color: var(--accent); }
.nav a.nav-boutique:not([aria-current]):hover,
.nav a.nav-boutique:not([aria-current]):focus-visible { color: var(--plume); }

/* Aucun séparateur « ··· » entre les items : l'espacement suffit à les
   distinguer, et le motif reste ainsi le marqueur du CONTENU. */

/* Filet prismatique sous l'onglet actif — §3.7-6 */
.nav a[aria-current="page"] { color: var(--plume); }
.nav a[aria-current="page"]::after {
  content: "";
  position: absolute;
  left: .85rem; right: .85rem; bottom: .55rem;
  height: 1px;
  background: var(--prisme);
}

.entete-actions { display: flex; align-items: center; gap: .55rem; flex-shrink: 0; }

/* Téléphone toujours visible — §5 */
.tel-entete {
  font-family: var(--texte);
  font-size: var(--t-label);
  letter-spacing: .18em;
  text-decoration: none;
  color: var(--plume);
  white-space: nowrap;
  padding: .8rem .5rem;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  border-bottom: 1px dotted var(--accent-sourd);
}
.tel-entete:hover { border-bottom-style: solid; border-bottom-color: var(--accent); }

/* --------------------------------------------------------------------------
   8. BOUTONS
   -------------------------------------------------------------------------- */
.bouton {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: .95rem 2.1rem;
  font-family: var(--texte);
  font-size: var(--t-label);
  font-weight: 400;
  letter-spacing: .3em;
  text-transform: uppercase;
  text-decoration: none;
  border: 1px solid var(--accent);
  background: transparent;
  color: var(--accent);
  cursor: pointer;
  border-radius: 0;              /* zéro arrondi — §3.5 */
  transition: background var(--transition-court), color var(--transition-court);
}
.bouton:hover, .bouton:focus-visible {
  background: var(--accent);
  color: var(--fond);
}

/* Micro-interactions — le retour au clic.
   Rien ne doit paraître inerte : chaque élément actionnable s'enfonce
   légèrement quand on appuie, ce qui confirme la prise en compte du geste
   avant même que la page ne réagisse. Amplitude volontairement faible :
   le registre du site est retenu. */
.bouton,
.produit-ajouter,
.qte-bouton,
.config-onglet,
.variante-bouton {
  transition:
    background var(--transition-court),
    color var(--transition-court),
    border-color var(--transition-court),
    transform 140ms cubic-bezier(.16, 1, .3, 1);
}
.bouton:active,
.produit-ajouter:active,
.qte-bouton:active,
.config-onglet:active,
.variante-bouton:active { transform: translateY(1px) scale(.985); }

/* Les tuiles produit se soulèvent d'un cheveu au survol : c'est ce qui
   signale qu'elles sont vivantes, sans ombre portée (interdite au §3.5). */
.produit {
  transition: transform 420ms cubic-bezier(.16, 1, .3, 1);
}
.produit:hover,
.produit:focus-within { transform: translateY(-4px); }

.bouton-plein {
  background: var(--accent);
  color: var(--fond);
}
.bouton-plein:hover, .bouton-plein:focus-visible {
  background: var(--plume);
  border-color: var(--plume);
  color: var(--fond);
}

/* --------------------------------------------------------------------------
   9. HERO — asymétrique, texte ancré en bas à gauche. Jamais centré. — §9
   -------------------------------------------------------------------------- */
.hero {
  position: relative;
  min-height: min(92vh, 900px);
  display: flex;
  align-items: flex-end;
  overflow: hidden;
  background: var(--fond);
}

.hero-media {
  position: absolute;
  inset: 0;                      /* parallax retiré (site.js) */
  z-index: 0;
}
.hero-media img, .hero-media video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 46% 26%;   /* dézoomé : le cadrage initial (52%/30%) serrait trop */
  /* Le hero est le seul moment noir et blanc du site (§3.6) : son effet
     « affiche ». Partout ailleurs la couleur des visuels est conservée. */
  filter: grayscale(1) contrast(1.15) brightness(.88);
  /* Ken Burns : 1 % d'amplitude sur 40 secondes, aller-retour. À cette
     lenteur l'œil ne suit pas le mouvement, il perçoit seulement que
     l'image n'est pas figée. Au-delà, ça devient un diaporama. */
  animation: respiration 40s ease-in-out infinite alternate;
  transform-origin: 52% 35%;
}

/* Hero sorti de l'écran : on relâche tout. L'attribut est posé par
   heroAuRepos() dans site.js. Le Ken Burns s'arrête et la couche réservée au
   parallax est rendue — deux charges que le compositeur portait à chaque
   image du défilement pour un effet devenu invisible. Aucun changement à
   l'œil : hors champ, il n'y a rien à voir. */
.hero-media[data-repos] { will-change: auto; }
.hero-media[data-repos] img,
.hero-media[data-repos] video { animation-play-state: paused; }

@keyframes respiration {
  /* Amplitude ramenée de 6 % à 3 % : au-delà, l'agrandissement coûtait de la
     netteté sur un visuel déjà proche de sa taille native. */
  from { transform: scale(1); }
  to   { transform: scale(1.03); }
}
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    linear-gradient(to top,   rgba(var(--scrim-rgb), .94) 0%, rgba(var(--scrim-rgb), .35) 48%, rgba(var(--scrim-rgb), .55) 100%),
    linear-gradient(to right, rgba(var(--scrim-rgb), .82) 0%, transparent 55%);
}

.hero-contenu {
  position: relative;
  z-index: 2;
  padding: 0 var(--bord) clamp(3.5rem, 9vh, 7rem);
  max-width: 58rem;
}

.hero-titre {
  font-family: var(--display);
  font-size: var(--t-display);
  text-transform: uppercase;
  letter-spacing: .05em;
  line-height: .9;
  margin: 0 0 1.6rem;
}
.hero-titre em {
  display: block;
  font-style: italic;
  text-transform: none;
  letter-spacing: .01em;
  color: var(--accent);
  font-size: .46em;
  line-height: 1.1;
  margin-top: .35em;
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1.6rem;
  margin-top: 2.4rem;
}

.hero-bas {
  position: absolute;
  z-index: 2;
  right: var(--bord);
  bottom: clamp(3.5rem, 9vh, 7rem);
  text-align: right;
  font-size: var(--t-label);
  letter-spacing: .26em;
  text-transform: uppercase;
  color: var(--plume-attenuee);
  line-height: 2.1;
}
@media (max-width: 1100px) { .hero-bas { display: none; } }

/* --------------------------------------------------------------------------
   10. RÉGIME DOCUMENT — tableau éditorial des prestations — §3.4
   -------------------------------------------------------------------------- */
.tableau-prestations { border-top: 1px solid rgba(var(--filet-rgb), .3); }

.ligne-prestation {
  display: grid;
  grid-template-columns: 4.5rem 1fr auto;
  align-items: baseline;
  gap: clamp(1rem, 3vw, 2.5rem);
  padding: clamp(1.6rem, 3vw, 2.4rem) 0;
  text-decoration: none;
  color: inherit;
  border-bottom: 1px solid transparent;
  background-image: radial-gradient(circle, var(--accent-sourd) 0 1px, transparent 1.2px);
  background-size: 9px 1px;
  background-repeat: repeat-x;
  background-position: 0 100%;
  transition: padding-inline var(--transition), color var(--transition-court);
}
.ligne-prestation:hover,
.ligne-prestation:focus-visible { padding-inline: .9rem; }
.ligne-prestation:hover .ligne-nom { color: var(--accent); }

.ligne-nom {
  font-family: var(--display);
  font-size: clamp(1.5rem, 3.4vw, 2.6rem);
  text-transform: uppercase;
  letter-spacing: .07em;
  line-height: 1.05;
  transition: color var(--transition-court);
}
.ligne-note {
  display: block;
  font-family: var(--texte);
  font-size: var(--t-body);
  letter-spacing: 0;
  text-transform: none;
  color: var(--plume-attenuee);
  margin-top: .6rem;
  max-width: 46ch;
  line-height: 1.7;
}
.ligne-prix {
  font-family: var(--texte);
  font-size: var(--t-label);
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--accent);
  white-space: nowrap;
}

@media (max-width: 700px) {
  .ligne-prestation { grid-template-columns: 1fr; gap: .5rem; }
  .ligne-prestation:hover { padding-inline: 0; }
}

/* Tableau de tarifs / horaires — dense, filets pointillés */
.tableau-info { width: 100%; border-collapse: collapse; text-align: left; }
.tableau-info caption {
  text-align: left;
  font-family: var(--texte);
  font-size: var(--t-label);
  letter-spacing: .32em;
  text-transform: uppercase;
  color: var(--accent);
  padding-bottom: 1.4rem;
}
.tableau-info th, .tableau-info td {
  padding: .95rem 0;
  font-weight: 300;
  vertical-align: baseline;
  background-image: radial-gradient(circle, var(--accent-sourd) 0 1px, transparent 1.2px);
  background-size: 9px 1px;
  background-repeat: repeat-x;
  background-position: 0 100%;
}
.tableau-info th {
  font-family: var(--texte);
  font-size: var(--t-label);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--plume-attenuee);
  padding-right: 1.5rem;
}
.tableau-info td { color: var(--plume); }
.tableau-info td.prix { text-align: right; color: var(--accent); white-space: nowrap; }

/* --------------------------------------------------------------------------
   11. BOUTIQUE
   -------------------------------------------------------------------------- */
.gamme-titre {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 2rem;
  flex-wrap: wrap;
  margin-bottom: 2.5rem;
}

.grille-produits {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: clamp(1.5rem, 3vw, 3rem) clamp(1rem, 2vw, 2rem);
  margin: 0 0 var(--air-document);
  padding: 0;
  list-style: none;
}

.produit { display: flex; flex-direction: column; }

.produit-media {
  overflow: hidden;
  /* Le format est porté ICI et non par l'image : le cadre fait donc la même
     hauteur sur toutes les cartes, quelles que soient les dimensions du
     fichier. C'est ce qui aligne la grille. */
  display: block;
  aspect-ratio: 1 / 1;
  /* La tuile reste en léger retrait sur le fond de page. L'écart --relief /
     --fond ne fait que 3 % de luminance : voulu discret, il était en pratique
     imperceptible, et le carré du produit se confondait avec la page.
     On ne touche pas à --relief pour autant — dix autres composants s'en
     servent, et l'assombrir aurait ramené le contraste dur « beige contre
     blanc » qu'on avait justement corrigé. C'est le filet ci-dessous qui
     porte la limite : un trait franc mais fin dit où s'arrête le carré, sans
     ajouter le moindre aplat. */
  background: var(--relief);
  /* 1px, dans la famille de filets du site (§3.7). L'opacité .45 existe déjà
     ailleurs dans la feuille : ni un cadre, ni une bordure de carte — la même
     ligne d'un pixel qui sépare partout le reste. Le border-box global fait
     que ce trait ne décale rien : la tuile garde exactement sa taille. */
  border: 1px solid rgba(var(--filet-rgb), .45);
  margin-bottom: 1.1rem;
}
.produit:hover .img-produit,
.produit:focus-within .img-produit { transform: scale(1.04); }

.produit-nom {
  font-family: var(--display);
  font-size: 1.1rem;
  letter-spacing: .05em;
  margin: 0 0 .35rem;
  line-height: 1.25;
}
.produit-format {
  font-family: var(--texte);
  font-size: var(--t-label);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--plume-attenuee);
  margin: 0 0 .85rem;
}

/* Description : mesure courte, interlignage serré — c'est du texte de
   catalogue, pas du texte de lecture. */
.produit-desc {
  font-size: .85rem;
  line-height: 1.65;
  color: var(--plume-attenuee);
  margin: 0 0 1rem;
}

/* --------------------------------------------------------------------------
   Mise en avant boutique — §accueil
   Aucun style neuf : les références phares de l'accueil réutilisent les mêmes
   classes que les fiches de la boutique. On ajoute seulement ce qui manquait
   là-bas — un argument court, un bouton d'achat — en restant sur les tokens
   existants. Une boutique qui aurait sa propre typographie ferait tache.
   -------------------------------------------------------------------------- */
.grille-phares { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }

/* Badge. Discret par choix : un aplat criard sur fond noir casserait la
   direction artistique. Filet fin, capitales espacées, couleur d'accent —
   le même vocabulaire que les sur-titres. */
.produit-badge {
  /* .produit est un conteneur flex en colonne : il « blockifie » ses enfants,
     si bien qu'un inline-block s'étirerait sur toute la largeur de la carte.
     align-self ramène le badge à la largeur de son texte. */
  align-self: flex-start;
  font-family: var(--texte);
  font-size: .58rem;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--accent);
  border: 1px solid rgba(var(--filet-rgb), .6);
  padding: .3em .8em;
  margin: 0 0 .6rem;
  line-height: 1.4;
}

/* L'argument de vente : une phrase, pas une fiche technique. Le nom seul ne
   dit pas pourquoi acheter. */
.produit-argument {
  font-size: .85rem;
  line-height: 1.6;
  color: var(--plume-attenuee);
  margin: 0 0 .9rem;
}

/* Le bouton ferme la carte : il vient après le prix, et occupe toute la
   largeur pour rester une cible confortable au doigt. */
.produit-acheter {
  display: block;
  text-align: center;
  margin-top: .2rem;
}

/* Rappel des engagements sous les produits phares, là où la décision se
   prend. Repris à l'identique du pied de page, sans nouvel élément visuel. */
.phares-rassurance,
.boutique-rassurance {
  font-family: var(--texte);
  font-size: var(--t-label);
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--plume-attenuee);
  text-align: center;
  margin: clamp(1.5rem, 4vw, 2.5rem) 0 0;
  line-height: 2;
}
/* En haut de la boutique, la ligne respire de part et d'autre et s'aligne sur
   la marge de bord du site plutôt que sur une colonne de grille. */
.boutique-rassurance {
  margin: clamp(1.5rem, 4vw, 2.5rem) var(--bord) 0;
  padding-bottom: clamp(1rem, 3vw, 2rem);
}

/* Le prix est l'information que l'œil cherche : didone, pas de capitales. */
.produit-prix {
  font-family: var(--display);
  font-size: 1.25rem;
  letter-spacing: .04em;
  color: var(--plume);
  margin: 0 0 .5rem;
}
.produit-lien {
  font-family: var(--texte);
  font-size: var(--t-label);
  letter-spacing: .22em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--accent);
  border-bottom: 1px dotted var(--accent-sourd);
  padding: .5rem 0;
  margin-top: auto;
  align-self: flex-start;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  transition: border-color var(--transition-court), color var(--transition-court);
}
.produit-lien:hover, .produit-lien:focus-visible {
  border-bottom-style: solid;
  border-bottom-color: var(--accent);
  color: var(--plume);
}

/* --------------------------------------------------------------------------
   12. CONFIGURATEUR — trois textures — M5 / §4
   -------------------------------------------------------------------------- */
.configurateur { display: grid; gap: clamp(2rem, 5vw, 4rem); }
@media (min-width: 900px) {
  .configurateur { grid-template-columns: 1fr 1fr; align-items: center; }
}

.config-onglets {
  display: flex;
  flex-direction: column;
  gap: 0;
  border-top: 1px solid rgba(var(--filet-rgb), .3);
}

.config-onglet {
  appearance: none;
  background: transparent;
  border: 0;
  border-radius: 0;
  text-align: left;
  cursor: pointer;
  color: var(--plume-attenuee);
  font-family: var(--display);
  font-size: clamp(1.4rem, 3vw, 2.2rem);
  text-transform: uppercase;
  letter-spacing: .1em;
  padding: clamp(1.1rem, 2.4vw, 1.7rem) 0;
  min-height: 48px;
  background-image: radial-gradient(circle, var(--accent-sourd) 0 1px, transparent 1.2px);
  background-size: 9px 1px;
  background-repeat: repeat-x;
  background-position: 0 100%;
  transition: color var(--transition-court), padding-left var(--transition);
}
.config-onglet:hover { color: var(--plume); padding-left: .8rem; }
.config-onglet[aria-selected="true"] { color: var(--accent); padding-left: .8rem; }

.config-panneau[hidden] { display: none; }
.config-visuel { position: relative; overflow: hidden; }
.config-visuel img { width: 100%; aspect-ratio: 4/5; object-fit: cover; }

/* --------------------------------------------------------------------------
   13. FORMULAIRE — libellés visibles, jamais de placeholder seul — §5
   -------------------------------------------------------------------------- */
.champ { margin-bottom: 1.9rem; }

.champ label {
  display: block;
  font-family: var(--texte);
  font-size: var(--t-label);
  font-weight: 400;
  letter-spacing: .28em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: .75rem;
}
.champ .aide {
  display: block;
  font-size: .8rem;
  letter-spacing: 0;
  text-transform: none;
  color: var(--plume-attenuee);
  margin-top: .4rem;
  line-height: 1.6;
}

.champ input,
.champ textarea,
.champ select {
  width: 100%;
  min-height: 48px;
  background: var(--relief);
  border: 1px solid rgba(var(--filet-rgb), .42);
  border-radius: 0;
  color: var(--plume);
  font-family: var(--texte);
  font-weight: 300;
  font-size: var(--t-body);
  padding: .85rem 1rem;
  transition: border-color var(--transition-court);
}
.champ textarea { min-height: 10rem; resize: vertical; line-height: 1.7; }
.champ input:focus, .champ textarea:focus, .champ select:focus {
  border-color: var(--accent);
  outline: none;
}
.champ input:focus-visible, .champ textarea:focus-visible, .champ select:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.champ-case {
  display: flex;
  align-items: flex-start;
  gap: .9rem;
  margin-bottom: 1.9rem;
}
.champ-case input {
  width: 20px; height: 20px;
  margin: .25rem 0 0;
  min-height: 0;
  accent-color: var(--accent);
  flex-shrink: 0;
}
.champ-case label {
  font-family: var(--texte);
  font-size: .85rem;
  letter-spacing: 0;
  text-transform: none;
  color: var(--plume-attenuee);
  line-height: 1.65;
  margin: 0;
}

.form-etat {
  border-left: 1px solid var(--accent);
  padding: 1rem 0 1rem 1.3rem;
  color: var(--accent);
  font-size: .9rem;
  margin-bottom: 1.5rem;
}

/* Précision contextuelle, révélée selon le choix du formulaire */
.form-note {
  border-left: 1px solid var(--accent-sourd);
  padding: .2rem 0 .2rem 1.3rem;
  color: var(--plume-attenuee);
  font-size: .85rem;
  line-height: 1.7;
  margin: -.6rem 0 1.9rem;
}

/* --------------------------------------------------------------------------
   14. PIED DE PAGE
   -------------------------------------------------------------------------- */
.pied { padding: var(--air-document) 0 3rem; border-top: 1px solid rgba(var(--filet-rgb), .28); }

.pied-grille {
  display: grid;
  gap: clamp(2.5rem, 5vw, 4rem);
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  padding-inline: var(--bord);
}

.pied h3 {
  font-family: var(--texte);
  font-size: var(--t-label);
  font-weight: 400;
  letter-spacing: .32em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 1.5rem;
}

.pied ul { list-style: none; margin: 0; padding: 0; }
.pied li { margin-bottom: .2rem; }
.pied a {
  text-decoration: none;
  color: var(--plume-attenuee);
  font-size: .9rem;
  padding: .55rem 0;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  transition: color var(--transition-court);
}
.pied a:hover, .pied a:focus-visible { color: var(--plume); }
.pied address { font-style: normal; color: var(--plume-attenuee); font-size: .9rem; }

.pied-bas {
  margin-top: clamp(3rem, 6vw, 5rem);
  padding: 2rem var(--bord) 0;
  display: flex;
  flex-wrap: wrap;
  gap: 1rem 2rem;
  justify-content: space-between;
  align-items: center;
  font-size: var(--t-label);
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--plume-attenuee);
}

/* --------------------------------------------------------------------------
   15. BANDEAU COOKIES — refuser aussi simple qu'accepter (CNIL)
   -------------------------------------------------------------------------- */
.cookies {
  position: fixed;
  left: var(--bord);
  right: var(--bord);
  bottom: clamp(1rem, 3vh, 2rem);
  z-index: 9000;
  background: var(--relief);
  border: 1px solid rgba(var(--filet-rgb), .5);
  padding: clamp(1.4rem, 3vw, 2rem);
  display: none;
  gap: 1.5rem;
  align-items: center;
  flex-wrap: wrap;
  justify-content: space-between;
  max-width: 62rem;
  margin-inline: auto;
}
.cookies[data-visible="true"] { display: flex; }
.cookies p { margin: 0; max-width: 46ch; font-size: .88rem; line-height: 1.7; color: var(--plume-attenuee); }
.cookies-actions { display: flex; gap: .8rem; flex-wrap: wrap; }
.cookies-actions .bouton { padding: .8rem 1.5rem; min-height: 44px; }

/* --------------------------------------------------------------------------
   16. RÉVÉLATION AU DÉFILEMENT — §4
   Mouvements distincts par section. Jamais un fondu uniforme.
   -------------------------------------------------------------------------- */
/* Sécurité : l'état masqué n'est appliqué QUE si le JS a démarré (classe .js
   posée sur <html>). Sans JavaScript, tout le contenu reste visible. */
.js [data-anim] { opacity: 0; }
/* will-change UNIQUEMENT pendant le mouvement — la classe .anime est posée puis
   retirée par site.js. Appliqué en permanence, il forçait une couche GPU par
   élément animé (33 sur l'accueil, 27 sur la boutique) que le navigateur ne
   libérait jamais : la mémoire graphique enflait et chaque image du défilement
   coûtait plus cher. Un will-change permanent est contre-productif — c'est un
   avertissement ponctuel, pas un réglage. */
.js [data-anim].anime { will-change: transform, opacity; }
.js [data-anim].vu { opacity: 1; }

/* Apparitions courtes (≤ 400 ms) : le contenu doit suivre le défilement,
   pas le faire attendre. Plus de rideau (clip-path, coûteux à peindre). */
.js [data-anim="monter"]   { transform: translateY(12px); transition: opacity 350ms ease, transform 400ms cubic-bezier(.16,1,.3,1); }
.js [data-anim="glisser"]  { transform: translateY(10px); transition: opacity 300ms ease, transform 350ms cubic-bezier(.16,1,.3,1); }
.js [data-anim="zoom"]     { transform: scale(1.02);      transition: opacity 350ms ease, transform 400ms cubic-bezier(.16,1,.3,1); }
.js [data-anim="rideau"]   { transition: opacity 350ms ease; }

.js [data-anim].vu { transform: none; }

/* Téléphones / tablettes (classe posée par site.js) : aucun effet. */
.leger .filet.tracer { background-size: 9px 1px !important; transition: none !important; }
.leger [data-anim] { opacity: 1 !important; transform: none !important; transition: none !important; }
.leger .hero-media { will-change: auto; }
.leger .hero-media img, .leger .hero-media video { animation: none; }

/* --------------------------------------------------------------------------
   17. ACCESSIBILITÉ — mouvement réduit
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  .js [data-anim] { opacity: 1 !important; transform: none !important; clip-path: none !important; }
  .filet.tracer { background-size: 9px 1px !important; }
  .hero-media { transform: none !important; }

  /* Ambiance et micro-interactions neutralisées : le Ken Burns du hero et la
     pulsation du compteur sont du confort, jamais de l'information. Le toast
     reste affiché, lui — c'est un retour fonctionnel, pas une animation. */
  .hero-media img, .hero-media video { animation: none !important; transform: none !important; }
  .panier-nombre.pulse { animation: none !important; }
  .produit:hover, .produit:focus-within { transform: none !important; }
  .toast { transition: none !important; }
}

/* --------------------------------------------------------------------------
   18. NAVIGATION MOBILE
   -------------------------------------------------------------------------- */
.burger {
  display: none;
  appearance: none;
  background: transparent;
  border: 1px solid rgba(var(--filet-rgb), .5);
  border-radius: 0;
  color: var(--plume);
  font-family: var(--texte);
  font-size: var(--t-label);
  letter-spacing: .26em;
  text-transform: uppercase;
  min-height: 44px;
  padding: .7rem 1rem;
  cursor: pointer;
}

@media (max-width: 1279px) {
  .burger { display: inline-block; }

  /* IMPORTANT : un ancêtre porteur de backdrop-filter devient bloc conteneur
     des descendants en position:fixed. Le panneau de navigation resterait
     alors enfermé dans la hauteur de l'en-tête. On retire donc le flou en
     mobile — l'en-tête y est opaque, ce qui préserve aussi le contraste. */
  .entete {
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    background: var(--fond);
  }

  .nav {
    position: fixed;
    inset: 0;
    background: var(--fond);
    flex-direction: column;
    align-items: flex-start;
    justify-content: flex-start;   /* jamais center : le contenu déborderait
                                      vers le haut, hors d'atteinte */
    gap: .2rem;
    padding: 5.5rem var(--bord) 3rem;
    transform: translateY(-100%);
    transition: transform 620ms cubic-bezier(.16,1,.3,1);
    z-index: 950;
    overflow-y: auto;
    overscroll-behavior: contain;
  }
  .nav[data-ouvert="true"] { transform: translateY(0); }

  .nav a {
    font-family: var(--display);
    font-size: clamp(1.5rem, 7vw, 2.4rem);
    letter-spacing: .1em;
    padding: .55rem 0;
    color: var(--plume);
    width: 100%;
  }
  /* Panneau mobile : pas de « ··· » non plus, seulement de l'espacement. */
  .nav a { padding-block: .7rem; }
  .nav a[aria-current="page"]::after { left: 0; right: auto; width: 4rem; bottom: .3rem; }

  .nav-fermer {
    position: absolute;
    top: 1rem; right: var(--bord);
    background: transparent;
    border: 1px solid rgba(var(--filet-rgb), .5);
    border-radius: 0;
    color: var(--plume);
    font-family: var(--texte);
    font-size: var(--t-label);
    letter-spacing: .26em;
    text-transform: uppercase;
    min-height: 44px;
    padding: .7rem 1rem;
    cursor: pointer;
  }
}
@media (min-width: 1280px) { .nav-fermer { display: none; } }

/* CTA « Réserver » et lien « Panier » à l'intérieur du panneau de navigation
   mobile. Masqués en desktop, où l'en-tête les porte déjà. */
.nav-reserver,
.nav-panier { display: none; }

@media (max-width: 1279px) {
  .nav-panier { display: block; }

  /* .nav a.nav-reserver et non .nav-reserver : la règle .nav a plus haut
     a une spécificité supérieure (0-1-1 contre 0-1-0) et imposait le texte
     clair sur le fond champagne du bouton — 2,13:1, très en dessous du
     seuil. Défaut antérieur au mode jour, révélé par le balayage automatique. */
  .nav a.nav-reserver {
    display: inline-flex;
    margin-top: 2rem;
    width: auto;
    font-family: var(--texte);
    font-size: var(--t-label);
    letter-spacing: .3em;
    color: var(--fond);
  }
  .nav a.nav-reserver + a::before,
  .nav a + a.nav-reserver::before { content: none; }
  .nav a.nav-reserver:hover, .nav a.nav-reserver:focus-visible { color: var(--fond); }
}

/* En dessous de 680px, l'en-tête ne peut plus tenir logo + téléphone + menu
   + bouton sans déborder. Le bouton passe dans le panneau de navigation ;
   le téléphone, lui, reste visible en permanence (exigence du §5). */
@media (max-width: 680px) {
  .entete-actions .bouton { display: none; }
}

@media (max-width: 520px) {
  .tel-entete { font-size: .66rem; letter-spacing: .08em; }
  .panier-entete { font-size: .66rem; letter-spacing: .08em; padding-inline: .35rem; }
  .logo-sous { display: none; }
  .logo-nom { font-size: 1rem; letter-spacing: .22em; }
  .burger { padding: .7rem .8rem; letter-spacing: .18em; }
}

/* ==========================================================================
   ADAPTATION MOBILE
   Le trafic d'un salon vient majoritairement du téléphone : ces règles ne
   sont pas un repli, elles définissent la mise en page de référence.
   ========================================================================== */
@media (max-width: 760px) {

  /* La boutique doit ressembler à une boutique : deux colonnes de produits,
     comme sur n'importe quelle application d'achat. */
  .grille-produits {
    grid-template-columns: 1fr 1fr;
    gap: clamp(1.5rem, 5vw, 2.2rem) clamp(.8rem, 3vw, 1.2rem);
  }
  .produit-nom { font-size: .95rem; }
  .produit-format { font-size: .58rem; letter-spacing: .14em; }
  .produit-prix { font-size: 1.1rem; }
  .produit-prix::before { font-size: .5rem; margin-bottom: .35rem; }
  .produit-ajouter { font-size: .58rem; letter-spacing: .12em; padding: .8rem .4rem; }

  /* La description détaillée alourdit une grille à deux colonnes sur 375px.
     Elle reste dans le HTML pour le référencement et les lecteurs d'écran. */
  .produit-desc { display: none; }

  /* Titres : on desserre le tracking, sinon les mots se coupent mal */
  h1, .h1 { letter-spacing: .05em; }
  h2, .h2 { letter-spacing: .07em; }
  .hero-titre { letter-spacing: .02em; }
  .bloc-citation { max-width: none; }

  /* Tableaux d'information : libellé au-dessus de la valeur */
  .tableau-info th,
  .tableau-info td { display: block; width: 100%; }
  .tableau-info th { padding-bottom: .2rem; background-image: none; }
  .tableau-info td { padding-top: 0; }
  .tableau-info td.prix { text-align: left; }

  /* Deux colonnes d'avis deviennent une seule */
  .avis-liste { columns: 1; }

  .panier-recap { padding-top: 1.5rem; }

  /* Les blocs image + texte s'empilent avec l'image d'abord */
  .duo.inverse > :first-child { order: 0; }

  /* Respiration : on réduit les grands aplats, coûteux en scroll sur mobile */
  .section-campagne { padding-block: clamp(5rem, 14vh, 8rem); }
}

/* Les téléphones courants font 390 à 430 px de large : ils gardent les deux
   colonnes, comme n'importe quelle application d'achat. La colonne unique est
   réservée aux écrans vraiment étroits, où deux tuiles seraient illisibles. */
@media (max-width: 359px) {
  .grille-produits { grid-template-columns: 1fr; }
  .produit-desc { display: block; }
  .produit-nom { font-size: 1.05rem; }
}

/* --------------------------------------------------------------------------
   19. BLOCS ÉDITORIAUX DIVERS
   -------------------------------------------------------------------------- */
/* --------------------------------------------------------------------------
   PANIER
   -------------------------------------------------------------------------- */

/* Lien panier dans l'en-tête, au même gabarit que le téléphone */
.panier-entete {
  font-family: var(--texte);
  font-size: var(--t-label);
  letter-spacing: .22em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--plume);
  white-space: nowrap;
  padding: .8rem .5rem;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  border-bottom: 1px dotted var(--accent-sourd);
  transition: border-color var(--transition-court);
}
.panier-entete:hover, .panier-entete:focus-visible {
  border-bottom-style: solid;
  border-bottom-color: var(--accent);
}

.panier-nombre {
  font-family: var(--display);
  font-size: .95rem;
  letter-spacing: 0;
  color: var(--accent);
  min-width: 1.4em;
  text-align: center;
}
.panier-nombre[data-vide="true"] { color: var(--plume-attenuee); }

/* Bouton « Ajouter au panier » sur les fiches produits */
.produit-ajouter {
  appearance: none;
  width: 100%;
  min-height: 48px;
  margin-top: auto;
  padding: .85rem 1rem;
  border: 1px solid var(--accent);
  border-radius: 0;
  background: transparent;
  color: var(--accent);
  font-family: var(--texte);
  font-size: var(--t-label);
  font-weight: 400;
  letter-spacing: .24em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background var(--transition-court), color var(--transition-court);
}
.produit-ajouter:hover, .produit-ajouter:focus-visible {
  background: var(--accent);
  color: var(--fond);
}
.produit-ajouter[data-ajoute="true"] {
  background: var(--accent);
  color: var(--fond);
  border-color: var(--accent);
}

/* Liste du panier */
.panier-liste { list-style: none; margin: 0; padding: 0; }

.panier-ligne {
  display: grid;
  grid-template-columns: 88px 1fr auto auto auto;
  align-items: center;
  gap: clamp(1rem, 2.5vw, 2rem);
  padding: clamp(1.4rem, 3vw, 2rem) 0;
  background-image: radial-gradient(circle, var(--accent-sourd) 0 1px, transparent 1.2px);
  background-size: 9px 1px;
  background-repeat: repeat-x;
  background-position: 0 100%;
}

.panier-visuel { background: var(--relief); }
.panier-visuel img { width: 88px; height: 88px; object-fit: cover; }

.panier-nom {
  font-family: var(--display);
  font-size: 1.05rem;
  letter-spacing: .04em;
  margin: 0 0 .3rem;
  line-height: 1.3;
}
.panier-format,
.panier-pu {
  font-family: var(--texte);
  font-size: var(--t-label);
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--plume-attenuee);
  margin: 0;
}

.panier-qte { display: flex; align-items: center; gap: .3rem; }

.qte-bouton {
  appearance: none;
  width: 44px; height: 44px;
  border: 1px solid rgba(var(--filet-rgb), .5);
  border-radius: 0;
  background: transparent;
  color: var(--plume);
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  transition: border-color var(--transition-court), color var(--transition-court);
}
.qte-bouton:hover, .qte-bouton:focus-visible {
  border-color: var(--accent);
  color: var(--accent);
}

.qte-champ {
  width: 3.5rem;
  min-height: 44px;
  text-align: center;
  background: var(--relief);
  border: 1px solid rgba(var(--filet-rgb), .5);
  border-radius: 0;
  color: var(--plume);
  font-family: var(--texte);
  font-size: .95rem;
}

.panier-ligne-total {
  font-family: var(--display);
  font-size: 1.15rem;
  color: var(--plume);
  margin: 0;
  white-space: nowrap;
}

.panier-retirer {
  appearance: none;
  background: transparent;
  border: 0;
  border-bottom: 1px dotted var(--accent-sourd);
  border-radius: 0;
  color: var(--plume-attenuee);
  font-family: var(--texte);
  font-size: var(--t-label);
  letter-spacing: .18em;
  text-transform: uppercase;
  padding: .5rem 0;
  min-height: 44px;
  cursor: pointer;
  transition: color var(--transition-court), border-color var(--transition-court);
}
.panier-retirer:hover, .panier-retirer:focus-visible {
  color: var(--plume);
  border-bottom-style: solid;
  border-bottom-color: var(--accent);
}

@media (max-width: 760px) {
  .panier-ligne {
    grid-template-columns: 72px 1fr;
    grid-template-areas:
      "visuel infos"
      "qte    total"
      "retirer retirer";
    row-gap: 1rem;
  }
  .panier-visuel { grid-area: visuel; }
  .panier-visuel img { width: 72px; height: 72px; }
  .panier-infos { grid-area: infos; }
  .panier-qte { grid-area: qte; }
  .panier-ligne-total { grid-area: total; text-align: right; align-self: center; }
  .panier-retirer { grid-area: retirer; justify-self: start; }
}

/* Récapitulatif */
.panier-recap { border-top: 1px solid rgba(var(--filet-rgb), .35); padding-top: 2rem; }

.panier-total-ligne {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 2rem;
  padding: .8rem 0;
  font-family: var(--texte);
  font-size: var(--t-label);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--plume-attenuee);
}
.panier-total-ligne span:last-child { color: var(--plume); }

.panier-total-ligne.majeur {
  border-top: 1px solid rgba(var(--filet-rgb), .35);
  margin-top: .8rem;
  padding-top: 1.4rem;
}
.panier-total-ligne.majeur span:last-child {
  font-family: var(--display);
  font-size: 1.6rem;
  letter-spacing: .03em;
  text-transform: none;
  color: var(--accent);
}

.panier-franco {
  font-family: var(--texte);
  font-size: .82rem;
  color: var(--accent);
  margin: 1rem 0 0;
}

/* ==========================================================================
   MARQUE AMAXXON
   Le logotype réel est une didone capitale à très large tracking, suivie de
   « ···PREMIUM COSMETICS ». On le rejoue en HTML plutôt qu'en image : net à
   toute taille, sélectionnable, et lisible par un moteur de recherche.
   ========================================================================== */
/* Visuel de campagne, seul et sans voile : la photo est déjà sur fond noir et
   porte le logotype de la marque. Un fondu du bas la raccorde à la page. */
.marque-visuel {
  position: relative;
  background: var(--fond);
  overflow: hidden;
}
/* Le visuel source fait 1080×1350. Étiré sur toute la largeur d'un écran de
   1440px, il était agrandi d'un tiers — d'où le flou. On le présente donc à
   sa taille native, centré sur le noir : jamais d'agrandissement, et le
   cadrage complet reste visible au lieu d'être rogné. */
.marque-visuel img {
  width: 100%;
  max-width: 1080px;      /* = largeur native, plafond absolu */
  margin-inline: auto;
  height: auto;
  aspect-ratio: 1080 / 1350;
  object-fit: contain;
  filter: contrast(1.04) saturate(1.04);
}

/* Fondu vers le noir de la page. Réalisé avec un calque en surimpression et
   non avec mask-image : le masque fait disparaître l'image entière sur
   certains moteurs de rendu. */
.marque-visuel::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 30%;
  pointer-events: none;
  background: linear-gradient(to bottom, rgba(var(--fond-rgb), 0) 0%, rgba(var(--fond-rgb), .7) 60%, var(--fond) 100%);
}

.marque-intro {
  text-align: center;
  padding: clamp(2.5rem, 6vh, 4rem) var(--bord) clamp(3rem, 7vh, 5rem);
  margin-top: -6vh;              /* remonte dans le fondu de l'image */
  position: relative;
  z-index: 2;
}

/* « Boutique produits », au-dessus du logotype et dans le même h1. Registre
   des sur-titres du site : Jost, capitales espacées, couleur d'accent. Il
   annonce ce qu'est la page sans venir concurrencer le nom de la marque. */
.marque-logo-sur {
  display: block;
  font-family: var(--texte);
  font-weight: 400;
  font-size: var(--t-label);
  letter-spacing: .32em;
  text-transform: uppercase;
  color: var(--accent);
  /* Le logotype porte un text-indent de .18em pour compenser son tracking ;
     cette ligne-ci a le sien, il faut donc neutraliser l'hérité. */
  text-indent: 0;
  margin-bottom: clamp(.9rem, 2vw, 1.4rem);
}

.marque-logo {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(2.4rem, 11vw, 8rem);
  letter-spacing: .18em;
  text-transform: uppercase;
  line-height: 1;
  margin: 0;
  /* Le tracking pousse la dernière lettre : on recentre optiquement. */
  text-indent: .18em;
  color: var(--plume);
}

.marque-sous {
  font-family: var(--texte);
  font-weight: 400;
  font-size: clamp(.6rem, 1.4vw, .8rem);
  letter-spacing: .52em;
  text-transform: uppercase;
  color: var(--plume-attenuee);
  margin: clamp(1rem, 2.5vw, 1.8rem) 0 0;
  text-indent: .52em;
}

.marque-accroche {
  font-family: var(--display);
  font-style: italic;
  font-size: clamp(1.05rem, 2.4vw, 1.6rem);
  line-height: 1.4;
  color: var(--accent);
  max-width: 34ch;
  margin: clamp(2rem, 5vw, 3rem) auto 0;
}

/* Bandeau de preuves — remplace les « 3 cartes à icônes » par une ligne
   typographique séparée par des filets pointillés verticaux. */
.marque-preuves {
  list-style: none;
  margin: 0;
  padding: clamp(2rem, 4vw, 3rem) var(--bord);
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: clamp(1rem, 2vw, 2rem);
  border-block: 1px solid rgba(var(--filet-rgb), .3);
}
.marque-preuves li {
  text-align: center;
  font-family: var(--texte);
  font-size: var(--t-label);
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--plume-attenuee);
  line-height: 1.9;
  position: relative;
}
.marque-preuves li + li::before {
  content: "";
  position: absolute;
  left: calc(-1 * clamp(.5rem, 1vw, 1rem));
  top: 10%; bottom: 10%;
  width: 1px;
  background-image: radial-gradient(circle, var(--accent-sourd) 0 1px, transparent 1.2px);
  background-size: 1px 9px;
  background-repeat: repeat-y;
}
.marque-preuves strong {
  display: block;
  font-family: var(--display);
  font-size: clamp(1.4rem, 3vw, 2.1rem);
  font-weight: 400;
  letter-spacing: .04em;
  text-transform: none;
  color: var(--accent);
  margin-bottom: .4rem;
}
/* En dessous de 700px la ligne devient une grille 2×2 : les filets verticaux
   n'ont plus de sens (ils tomberaient en bord de grille), l'espacement suffit. */
@media (max-width: 700px) {
  .marque-preuves {
    grid-template-columns: 1fr 1fr;
    gap: clamp(1.6rem, 5vw, 2.2rem) 1rem;
  }
  .marque-preuves li + li::before { display: none; }
}

/* Bandeau d'ouverture de gamme : image pleine largeur + nom en surimpression */
.gamme-banniere {
  position: relative;
  overflow: hidden;
  min-height: clamp(220px, 32vw, 380px);
  display: flex;
  align-items: flex-end;
  /* <figure> porte une marge latérale de 40px par défaut : elle rétrécirait
     la bannière de 80px et casserait le plein cadre. */
  margin: 0 0 clamp(2.5rem, 6vw, 4rem);
}
.gamme-banniere img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  filter: contrast(1.05) saturate(1.02) brightness(.62);
  transition: transform 1400ms cubic-bezier(.16, 1, .3, 1);
}
.gamme-banniere:hover img { transform: scale(1.04); }
.gamme-banniere::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(var(--scrim-rgb), .94) 0%, rgba(var(--scrim-rgb), .25) 70%);
}
.gamme-banniere-texte {
  position: relative;
  z-index: 2;
  padding: clamp(1.5rem, 4vw, 2.5rem) clamp(1.5rem, 4vw, 3rem);
}
.gamme-banniere-nom {
  font-family: var(--display);
  font-size: clamp(1.8rem, 5.5vw, 3.4rem);
  text-transform: uppercase;
  letter-spacing: .12em;
  line-height: 1;
  margin: 0;
  color: var(--plume);
}
.gamme-banniere-tag {
  font-family: var(--texte);
  font-size: var(--t-label);
  letter-spacing: .3em;
  text-transform: uppercase;
  color: var(--accent);
  margin: .9rem 0 0;
}

/* ==========================================================================
   FICHE PRODUIT — contenance, quantité, ajout
   ========================================================================== */

/* Boutons de contenance. Un seul actif, signalé par le champagne plein —
   pas de coche ni d'icône, le site n'en utilise aucune. */
.variantes {
  display: flex;
  flex-wrap: wrap;
  gap: .4rem;
  margin: 0 0 1rem;
  padding: 0;
  list-style: none;
}

.variante-bouton {
  appearance: none;
  background: transparent;
  border: 1px solid rgba(var(--filet-rgb), .5);
  border-radius: 0;
  color: var(--plume-attenuee);
  font-family: var(--texte);
  font-size: var(--t-label);
  letter-spacing: .16em;
  text-transform: uppercase;
  padding: .6rem .85rem;
  min-height: 40px;
  cursor: pointer;
}
.variante-bouton:hover { border-color: var(--accent); color: var(--plume); }
.variante-bouton[aria-pressed="true"] {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--fond);
}
/* Une seule contenance : le bouton devient une simple étiquette, non cliquable */
.variantes[data-unique="true"] .variante-bouton {
  cursor: default;
  pointer-events: none;
  background: transparent;
  border-color: rgba(var(--filet-rgb), .35);
  color: var(--plume-attenuee);
}

/* Ligne quantité + ajout */
.produit-achat {
  display: flex;
  align-items: stretch;
  gap: .5rem;
  margin-top: auto;
}
.produit-achat .produit-ajouter { margin-top: 0; flex: 1 1 auto; }

.qte-groupe {
  display: flex;
  align-items: stretch;
  flex: 0 0 auto;
  border: 1px solid rgba(var(--filet-rgb), .5);
}
.qte-groupe .qte-bouton {
  width: 36px;
  height: auto;
  min-height: 48px;
  border: 0;
  background: transparent;
}
.qte-groupe .qte-champ {
  width: 2.6rem;
  min-height: 48px;
  border: 0;
  border-inline: 1px solid rgba(var(--filet-rgb), .5);
  background: transparent;
  font-size: .9rem;
  -moz-appearance: textfield;
}
.qte-groupe .qte-champ::-webkit-outer-spin-button,
.qte-groupe .qte-champ::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

@media (max-width: 760px) {
  .produit-achat { flex-wrap: wrap; }
  .qte-groupe { flex: 1 1 100%; justify-content: center; }
  .produit-achat .produit-ajouter { flex: 1 1 100%; }
  .variante-bouton { font-size: .58rem; letter-spacing: .1em; padding: .55rem .6rem; }
}

/* ==========================================================================
   VALIDATION DE COMMANDE — choix du mode de remise
   Pas de cartes à ombre : la même liste à filets pointillés que les
   prestations, le choix actif se signalant par le champagne.
   ========================================================================== */
.modes-remise {
  list-style: none;
  margin: 0 0 clamp(2rem, 5vw, 3rem);
  padding: 0;
  border-top: 1px solid rgba(var(--filet-rgb), .3);
}

.mode-remise { position: relative; }

/* Le bouton radio natif reste présent pour le clavier et les lecteurs
   d'écran, mais il est masqué visuellement : c'est le libellé entier qui
   devient la cible, bien plus large que 44px. */
.mode-remise input {
  position: absolute;
  opacity: 0;
  width: 1px; height: 1px;
  margin: 0;
}

.mode-remise label {
  display: grid;
  grid-template-columns: 1.6rem 1fr auto;
  align-items: baseline;
  gap: clamp(.8rem, 2vw, 1.4rem);
  padding: clamp(1.3rem, 3vw, 1.9rem) 0;
  cursor: pointer;
  background-image: radial-gradient(circle, var(--accent-sourd) 0 1px, transparent 1.2px);
  background-size: 9px 1px;
  background-repeat: repeat-x;
  background-position: 0 100%;
  transition: padding-inline var(--transition);
}
.mode-remise label:hover { padding-inline: .7rem; }

/* Pastille de sélection, dessinée en CSS — aucune icône sur ce site */
.mode-remise label::before {
  content: "";
  width: 14px; height: 14px;
  border: 1px solid var(--accent-sourd);
  border-radius: 50%;
  transform: translateY(.15em);
  transition: background var(--transition-court), border-color var(--transition-court);
}
.mode-remise input:checked + label::before {
  background: var(--accent);
  border-color: var(--accent);
  box-shadow: inset 0 0 0 3px var(--fond);
}
.mode-remise input:focus-visible + label {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}
.mode-remise input:checked + label { padding-inline: .7rem; }

.mode-nom {
  font-family: var(--display);
  font-size: clamp(1.1rem, 2.4vw, 1.45rem);
  letter-spacing: .05em;
  color: var(--plume-attenuee);
  transition: color var(--transition-court);
}
.mode-remise input:checked + label .mode-nom { color: var(--plume); }

.mode-detail {
  display: block;
  font-family: var(--texte);
  font-size: .85rem;
  line-height: 1.65;
  color: var(--plume-attenuee);
  margin-top: .45rem;
  max-width: 46ch;
}

.mode-prix {
  font-family: var(--texte);
  font-size: var(--t-label);
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--accent);
  white-space: nowrap;
}

@media (max-width: 620px) {
  .mode-remise label { grid-template-columns: 1.2rem 1fr; row-gap: .5rem; }
  .mode-prix { grid-column: 2; }
}

/* Groupe de champs révélé selon le mode choisi */
.champs-conditionnels[hidden] { display: none; }
.champs-conditionnels {
  border-left: 1px solid var(--accent-sourd);
  padding-left: clamp(1.2rem, 3vw, 1.8rem);
  margin-bottom: 2rem;
}

/* Récapitulatif compact de la commande */
.recap-ligne {
  display: flex;
  justify-content: space-between;
  gap: 1.5rem;
  padding: .7rem 0;
  font-size: .9rem;
  color: var(--plume-attenuee);
  background-image: radial-gradient(circle, var(--accent-sourd) 0 1px, transparent 1.2px);
  background-size: 9px 1px;
  background-repeat: repeat-x;
  background-position: 0 100%;
}
.recap-ligne span:last-child { color: var(--plume); white-space: nowrap; }

/* ==========================================================================
   RETOUR VISUEL À L'AJOUT AU PANIER
   ========================================================================== */
.toast {
  position: fixed;
  z-index: 9500;
  left: var(--bord);
  right: var(--bord);
  bottom: clamp(1rem, 3vh, 2rem);
  max-width: 26rem;
  margin-left: auto;            /* ancré à droite en desktop */
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: .9rem 1rem;
  background: var(--relief);
  border: 1px solid var(--accent-sourd);
  /* Le filet prismatique signe l'événement, sans introduire de couleur vive */
  border-top: 1px solid transparent;
  border-image: var(--prisme) 1;
  border-image-slice: 1;
  opacity: 0;
  transform: translateY(12px);
  pointer-events: none;
  transition: opacity 320ms ease, transform 420ms cubic-bezier(.16, 1, .3, 1);
}
.toast[data-visible="true"] {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}

.toast img {
  width: 48px; height: 48px;
  object-fit: cover;
  background: var(--fond);
  flex-shrink: 0;
}
.toast-corps { flex: 1 1 auto; min-width: 0; }
.toast-titre {
  font-family: var(--texte);
  font-size: var(--t-label);
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 .25rem;
}
.toast-produit {
  font-family: var(--display);
  font-size: .95rem;
  color: var(--plume);
  margin: 0;
  line-height: 1.3;
}
.toast-lien {
  font-family: var(--texte);
  font-size: var(--t-label);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--accent);
  text-decoration: none;
  border-bottom: 1px dotted var(--accent-sourd);
  padding: .5rem 0;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
}
.toast-lien:hover { border-bottom-style: solid; border-bottom-color: var(--accent); }

.toast-fermer {
  appearance: none;
  background: transparent;
  border: 0;
  color: var(--plume-attenuee);
  font-size: 1.1rem;
  line-height: 1;
  width: 44px; height: 44px;
  cursor: pointer;
  flex-shrink: 0;
}
.toast-fermer:hover { color: var(--plume); }

@media (max-width: 560px) {
  .toast { flex-wrap: wrap; }
  .toast-lien { flex: 1 1 100%; }
}

/* Pulsation du compteur : il grossit brièvement, sans changer de couleur */
.panier-nombre.pulse { animation: pulse-panier 620ms cubic-bezier(.16, 1, .3, 1); }
@keyframes pulse-panier {
  0%   { transform: scale(1); }
  35%  { transform: scale(1.5); color: var(--plume); }
  100% { transform: scale(1); }
}

.aplat-buriti { background: var(--buriti); }

/* --------------------------------------------------------------------------
   AVIS CLIENTS
   Pas de cartes à ombre : chaque avis est séparé par le filet pointillé, et
   la note se lit en didone comme un prix. Colonnes en maçonnerie sur desktop.
   -------------------------------------------------------------------------- */
.avis-liste { columns: 1; }
@media (min-width: 900px) { .avis-liste { columns: 2; column-gap: clamp(2rem, 5vw, 4rem); } }

.avis {
  break-inside: avoid;
  padding-bottom: clamp(2rem, 4vw, 3rem);
  margin-bottom: clamp(2rem, 4vw, 3rem);
  background-image: radial-gradient(circle, var(--accent-sourd) 0 1px, transparent 1.2px);
  background-size: 9px 1px;
  background-repeat: repeat-x;
  background-position: 0 100%;
}

.avis-tete { margin-bottom: 1.4rem; }

.avis-note {
  font-family: var(--display);
  font-size: 1.5rem;
  letter-spacing: .06em;
  color: var(--accent);
  margin: 0 0 .5rem;
}

.avis-auteur {
  font-family: var(--display);
  font-size: 1.05rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--plume);
  margin: 0 0 .35rem;
}

.avis-meta {
  font-family: var(--texte);
  font-size: var(--t-label);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--plume-attenuee);
  margin: 0;
}

.avis-texte {
  margin: 0;
  padding-left: 1.4rem;
  border-left: 1px solid var(--accent-sourd);
  color: var(--plume-attenuee);
  font-size: .92rem;
  line-height: 1.8;
}
.avis-texte p:last-child { margin-bottom: 0; }

/* --------------------------------------------------------------------------
   TRIPTYQUE — bande d'images en couleur, pleine largeur.
   Sert à combler les grands aplats noirs entre deux sections et à réintroduire
   la couleur des visuels Amaxxon (vert forêt, rouge buriti, reflets prismatiques).
   -------------------------------------------------------------------------- */
.triptyque {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 2px;                       /* un filet de noir, pas une gouttière */
  margin: 0;
  padding: 0;
  list-style: none;
}

.triptyque li { position: relative; overflow: hidden; background: var(--relief); }

.triptyque img {
  width: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  filter: contrast(1.05) saturate(1.05);
  transition: transform 1200ms cubic-bezier(.16, 1, .3, 1);
}
.triptyque li:hover img { transform: scale(1.05); }

/* Légende posée sur l'image, lisible grâce au dégradé du bas */
.triptyque figcaption {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  padding: 3.5rem 1.4rem 1.2rem;
  font-family: var(--texte);
  font-size: var(--t-label);
  letter-spacing: .28em;
  text-transform: uppercase;
  color: var(--plume);
  background: linear-gradient(to top, rgba(var(--scrim-rgb), .92), transparent);
}

@media (max-width: 700px) {
  .triptyque { grid-template-columns: 1fr 1fr; }
  .triptyque li:first-child { grid-column: 1 / -1; }
  .triptyque img { aspect-ratio: 1 / 1; }
  .triptyque li:first-child img { aspect-ratio: 4 / 3; }
  .triptyque figcaption { padding: 2.5rem 1rem .9rem; font-size: .6rem; letter-spacing: .2em; }
}

.bloc-citation {
  font-family: var(--display);
  font-size: clamp(1.6rem, 3.6vw, 2.9rem);
  line-height: 1.22;
  letter-spacing: .02em;
  font-style: italic;
  max-width: 22ch;
  margin: 0;
}

.duo {
  display: grid;
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: center;
}
@media (min-width: 900px) {
  .duo { grid-template-columns: 1fr 1fr; }
  .duo.inverse > :first-child { order: 2; }
}

.encart {
  border-left: 1px solid var(--accent-sourd);
  padding-left: clamp(1.2rem, 3vw, 2.2rem);
}

.carte-plan {
  width: 100%;
  min-height: 380px;
  border: 1px solid rgba(var(--filet-rgb), .35);
  filter: grayscale(1) contrast(1.05) invert(.92);
}

.etat-vide {
  border: 1px dashed rgba(var(--filet-rgb), .55);
  padding: clamp(2rem, 5vw, 3.5rem);
  color: var(--plume-attenuee);
}

/* Contenu légal : lecture longue, mesure large */
.texte-legal { max-width: 68ch; }
.texte-legal h2 { margin-top: 3.2rem; margin-bottom: 1.2rem; font-size: var(--t-h3); letter-spacing: .1em; }
.texte-legal h3 { margin-top: 2.2rem; margin-bottom: .8rem; font-size: 1.05rem; letter-spacing: .08em; color: var(--accent); }
.texte-legal p, .texte-legal li { color: var(--plume-attenuee); }
.texte-legal strong { color: var(--plume); font-weight: 400; }

/* ==========================================================================
   20. BASCULE JOUR / NUIT
   ==========================================================================
   EXCEPTION ASSUMÉE à la règle « aucune icône » (§3.5). Le pictogramme
   soleil/lune a été demandé explicitement : c'est le seul signe qu'un
   visiteur identifie sans légende, et une bascule de thème doit se
   comprendre en une fraction de seconde. Il est donc dessiné dans le
   vocabulaire du site — trait de 1,25px, aucun aplat, aucun arrondi, aucune
   ombre — et reste le SEUL pictogramme des dix-neuf pages. Toute autre icône
   reste interdite.

   Le dessin affiché est celui de la DESTINATION, pas de l'état courant :
   en mode nuit on voit un soleil, parce que cliquer amène le jour. Le
   libellé accessible dit la même chose en toutes lettres. */
.bascule-theme {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;                 /* cible tactile de 44px, comme le reste de l'en-tête */
  padding: 0;
  border: 1px solid transparent;
  border-radius: 0;
  background: transparent;
  color: var(--accent);
  cursor: pointer;
  transition: color var(--transition-court),
              border-color var(--transition-court),
              transform 140ms cubic-bezier(.16, 1, .3, 1);
}
.bascule-theme:hover,
.bascule-theme:focus-visible {
  color: var(--plume);
  border-color: rgba(var(--filet-rgb), .5);
}
.bascule-theme:active { transform: translateY(1px) scale(.985); }

.bascule-icone { display: block; width: 19px; height: 19px; }
.bascule-icone .soleil,
.bascule-icone .lune {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.25;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Un seul des deux dessins à la fois. */
.bascule-icone .lune { display: none; }
/* Pendant du ton atténué de l'en-tête, côté jour. */
:root[data-theme="light"] .entete { --plume-attenuee: #58554F; }   /* 5.7:1 sur le pire fond composé */

:root[data-theme="light"] .bascule-icone .soleil { display: none; }
:root[data-theme="light"] .bascule-icone .lune   { display: block; }

/* Sous 520px l'en-tête porte déjà logo + burger + panier + téléphone :
   on resserre la bascule sans descendre sous la cible tactile de 44px. */
@media (max-width: 520px) {
  .bascule-theme { width: 40px; }
  .bascule-icone { width: 17px; height: 17px; }
}

/* Téléphones étroits (360px et moins : Galaxy A, anciens Android).
   L'en-tête y débordait DÉJÀ avant l'ajout de la bascule — environ 450px
   demandés pour 360 disponibles, la page défilait latéralement. Mesuré.
   On resserre logo, burger, panier et téléphone plutôt que d'en masquer un :
   le numéro reste visible (§5) et le panier garde son libellé. */
@media (max-width: 520px) {
  .entete-interne { padding-inline: .9rem; gap: .3rem; }
  .logo-nom      { font-size: .92rem; letter-spacing: .12em; }
  .burger        { padding: .6rem; letter-spacing: .08em; font-size: .62rem; }
  .bascule-theme { width: 36px; }
  .bascule-icone { width: 16px; height: 16px; }
  .panier-entete { font-size: .62rem; letter-spacing: .02em; padding-inline: .25rem; }
  .tel-entete    { font-size: .58rem; letter-spacing: .02em; padding-inline: .25rem; }
}

/* Cran supplémentaire sous 380px (iPhone SE, Galaxy A). En dessous de cette
   largeur, le resserrement précédent ne suffit plus : il manquait 16px. */
@media (max-width: 380px) {
  .entete-interne { padding-inline: .7rem; gap: .2rem; }
  .logo-nom      { font-size: .85rem; letter-spacing: .08em; }
  .burger        { padding: .55rem .45rem; font-size: .58rem; letter-spacing: .04em; }
  .bascule-theme { width: 32px; }
  .panier-entete { font-size: .58rem; padding-inline: .2rem; }
  .tel-entete    { font-size: .54rem; padding-inline: .2rem; }
}

/* Débordement latéral de la grille sur les petits écrans.
   Un élément de grille a min-width:auto par défaut : il refuse de descendre
   sous sa largeur de contenu minimale, et pousse alors la page au-delà du
   viewport. Sur boutique.html, 401px étaient exigés pour 360 disponibles.
   Défaut antérieur au mode jour (472px avec l'ancienne feuille), mesuré aux
   deux états. min-width:0 lève le blocage et ne change rien au-dessus de
   414px — vérifié de 320 à 1920. */
.grille > * { min-width: 0; }

/* Dernier cran, 340px et moins (iPhone SE 1re génération). Il manquait 15px.
   En dessous de cette largeur on ne resserre plus : il faudrait sacrifier
   le numéro de téléphone, que le §5 impose de garder visible. */
@media (max-width: 340px) {
  .entete-interne { padding-inline: .5rem; gap: .15rem; }
  .logo-nom      { font-size: .78rem; letter-spacing: .05em; }
  .burger        { padding: .5rem .35rem; font-size: .54rem; letter-spacing: .02em; }
  .bascule-theme { width: 30px; }
  .bascule-icone { width: 15px; height: 15px; }
  .panier-entete { font-size: .54rem; padding-inline: .15rem; }
  .tel-entete    { font-size: .5rem;  padding-inline: .15rem; }
  .hero-contenu  { padding-inline: .9rem; }
}

/* Titres sur écran étroit.
   « CONFIDENTIALITÉ » en capitales tracées à .1em fait 401px : il ne peut pas
   se couper et poussait la page hors du viewport. Le défaut existait déjà en
   Bodoni (384px) ; Spectral, plus large, l'aggravait de 17px.
   On abaisse le plancher des titres sous 440px — 38px de capitales sur un
   écran de 375 était de toute façon disproportionné — et on autorise la
   césure française en dernier recours, la page portant bien lang="fr". */
@media (max-width: 440px) {
  :root {
    --t-display: clamp(2.4rem, 13vw, 3.4rem);
    --t-h1:      clamp(1.75rem, 7.4vw, 2.6rem);
    --t-h2:      clamp(1.5rem, 5.6vw, 2.1rem);
  }
  h1, .h1, .display, h2, .h2 { hyphens: auto; }
}

/* ==========================================================================
   21. LIENS SOCIAUX — pied de page
   ==========================================================================
   SECONDE ET DERNIÈRE EXCEPTION à la règle « aucune icône » (§3.5), demandée
   explicitement. Traitées comme la bascule : trait de 1,25px, aucun aplat,
   aucune couleur de marque. Les logotypes officiels d'Instagram et TikTok
   sont polychromes et auraient introduit six teintes étrangères dans une
   palette qui n'en compte que trois — ils sont donc redessinés au filet, en
   currentColor, et suivent le thème actif.
   Le libellé texte est conservé à côté : une icône seule oblige à deviner. */
.lien-social {
  display: inline-flex;
  align-items: center;
  gap: .6em;
}
.icone-sociale {
  width: 15px;
  height: 15px;
  flex-shrink: 0;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.25;
  stroke-linecap: round;
  stroke-linejoin: round;
  /* Le point de l'appareil photo Instagram est le seul aplat toléré :
     à 15px, un cercle vide de 1px de diamètre ne se voit pas. */
}
.icone-sociale .plein { fill: currentColor; stroke: none; }

/* ==========================================================================
   22. FONDU DES BORDS D'IMAGE
   ==========================================================================
   Les packshots de la boutique sont des PNG à fond OPAQUE, et pas du même
   fond d'un produit à l'autre : blanc pur pour Protein Amazon, bleu-vert
   rgb(126,171,179) pour CurlYou. Posés tels quels, ce sont des rectangles
   pleins découpés au couteau sur la page — c'est la coupure signalée.

   Le fondu est réalisé en calque ::after, JAMAIS en mask-image : le masque
   fait disparaître l'image entière sur certains moteurs, piège déjà relevé
   §6. Il fond vers var(--fond), donc il suit le thème actif.

   Non traités, volontairement :
   — .hero-media, plein cadre : ses bords latéraux SONT ceux de l'écran ;
   — .cadre-campagne, qui porte déjà .fondu-droite / .fondu-gauche ;
   — .carte-plan, iframe OpenStreetMap encadrée d'un filet : ce n'est pas une
     photographie, estomper ses bords nuirait à la lecture du plan.
   -------------------------------------------------------------------------- */

/* Bannières de gamme — fondu latéral uniquement.
   ORDRE DES COUCHES CRITIQUE : le voile sombre est déclaré EN PREMIER, donc
   dessiné au-dessus. Le texte de la bannière reste clair dans les deux modes
   (îlot sombre) ; si le fondu vers le crème passait par-dessus le voile, le
   nom de gamme deviendrait illisible en mode jour. */
.gamme-banniere::after {
  background:
    linear-gradient(to top, rgba(var(--scrim-rgb), .94) 0%, rgba(var(--scrim-rgb), .25) 70%),
    linear-gradient(to right,
      var(--fond) 0%, rgba(var(--fond-rgb), 0) 14%,
      rgba(var(--fond-rgb), 0) 86%, var(--fond) 100%);
}

/* Visuel de marque — le fondu du bas existait déjà, on ajoute les côtés. */
.marque-visuel::after {
  left: 0; right: 0; bottom: 0; top: 0;
  height: auto;
  background:
    linear-gradient(to bottom,
      rgba(var(--fond-rgb), 0) 60%, rgba(var(--fond-rgb), .7) 85%, var(--fond) 100%),
    linear-gradient(to right,
      var(--fond) 0%, rgba(var(--fond-rgb), 0) 12%,
      rgba(var(--fond-rgb), 0) 88%, var(--fond) 100%);
}

/* Le plan n'est inversé qu'en mode nuit. OpenStreetMap est une carte claire :
   l'inversion la rend sombre, ce qu'il faut sur fond noir et surtout pas sur
   fond crème, où elle donnait un rectangle noir. */
:root[data-theme="light"] .carte-plan {
  filter: grayscale(1) contrast(1.05);
}

/* ==========================================================================
   23. FONDU DE BASCULE ENTRE LES MODES
   ==========================================================================
   La transition ne porte QUE sur les surfaces et le texte, jamais sur les
   transformations ni les opacités : l'animer largement ferait rejouer les
   révélations au défilement à chaque bascule.

   Elle est neutralisée sous prefers-reduced-motion (§17) : un changement de
   luminosité progressif sur toute la page est précisément le type de mouvement
   que ce réglage sert à éviter. */
body,
.entete,
.pied,
.produit-media,
.panier-recap,
.toast,
.cookies,
.carte-plan {
  transition: background-color 380ms ease, color 380ms ease, border-color 380ms ease;
}

/* ==========================================================================
   24. IMAGES PRODUIT
   ==========================================================================
   AUCUN fondu, dans aucun des deux modes. Le halo ne convainquait ni sur
   fond noir ni sur fond clair : il signalait surtout que le packshot avait
   un fond opaque à cacher. Onze des seize packshots sont désormais détourés
   pour de bon (fond transparent) — ils se posent directement sur la tuile,
   sans artifice. Les cinq CurlYou, indétourables (voir DESIGN.md), restent
   opaques et sans fondu eux non plus : mieux vaut un cadre franc assumé
   qu'un effet qui attire l'œil sur le défaut.
   -------------------------------------------------------------------------- */
/* ==========================================================================
   25. FICHE PRODUIT — note, disponibilité, livraison
   ==========================================================================
   NOTE : l'emplacement est prêt, il est VIDE. Aucune donnée d'avis par
   produit n'existe à ce jour et rien n'est inventé — les 73 avis Google
   affichés page « Avis » portent sur le salon, pas sur les références.
   Le jour où des avis produit existent, il suffit de renseigner data-note
   (0 à 5) et data-avis (un entier) : les étoiles se remplissent seules et
   le libellé se réécrit. Voir js/site.js, fonction notes().
   -------------------------------------------------------------------------- */
.produit-note {
  display: flex;
  align-items: center;
  gap: .55em;
  margin: -.4rem 0 .9rem;
  font-family: var(--texte);
  font-size: .72rem;
  letter-spacing: .06em;
  color: var(--plume-attenuee);
}

/* Les étoiles sont des CARACTÈRES, pas des icônes : le site n'en utilise
   aucune hors de la bascule de thème et des deux liens sociaux. Le taux de
   remplissage est un simple recouvrement en largeur. */
.note-etoiles {
  position: relative;
  display: inline-block;
  font-size: .95rem;
  line-height: 1;
  letter-spacing: .1em;
  color: var(--accent-sourd);
  white-space: nowrap;
}
.note-etoiles::before { content: "★★★★★"; }
.note-pleine {
  position: absolute;
  inset: 0;
  width: 0;                       /* réglé par data-note */
  overflow: hidden;
  color: var(--accent);
}
.note-pleine::before { content: "★★★★★"; }

.produit-note[data-note=""] .note-etoiles { opacity: .45; }

/* Disponibilité. Pastille dessinée en CSS, jamais une image. */
.produit-stock {
  display: flex;
  align-items: center;
  gap: .5em;
  margin: .9rem 0 .35rem;
  font-family: var(--texte);
  font-size: .72rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--plume-attenuee);
}
.produit-stock::before {
  content: "";
  width: 7px; height: 7px;
  flex-shrink: 0;
  background: currentColor;
}
.produit-stock[data-stock="en-stock"] { color: var(--vert-stock); }
.produit-stock[data-stock="limite"]   { color: var(--accent); }
.produit-stock[data-stock="rupture"]  { color: var(--plume-attenuee); }

/* Livraison — l'information avant le panier, pas après. */
.produit-livraison {
  margin: 0;
  font-family: var(--texte);
  font-size: .7rem;
  line-height: 1.75;
  letter-spacing: .02em;
  color: var(--plume-attenuee);
  border-top: 1px solid rgba(var(--filet-rgb), .3);
  padding-top: .7rem;
}
.produit-livraison strong { font-weight: 400; color: var(--plume); }
.livraison-delai {
  display: block;
  /* --plume-attenuee et non --accent-sourd : un délai de livraison est une
     information, pas un ornement. Le ton décoratif ne tient pas 4,5:1. */
  color: var(--plume-attenuee);
  letter-spacing: .14em;
  text-transform: uppercase;
  font-size: .62rem;
  margin-top: .25rem;
}

/* ==========================================================================
   26. BANDEAU DE RÉASSURANCE
   ==========================================================================
   TROISIÈME et dernière exception à la règle « aucune icône » (§3.5), demandée
   explicitement. Même traitement que la bascule de thème et les liens sociaux :
   trait de 1,25px, currentColor, aucun aplat, aucune couleur de marque.
   -------------------------------------------------------------------------- */
.reassurance {
  border-block: 1px solid rgba(var(--filet-rgb), .3);
  padding: clamp(1.4rem, 3vw, 2rem) var(--bord);
}
.reassurance ul {
  list-style: none; margin: 0; padding: 0;
  display: grid;
  /* Grille explicite et non auto-fit : avec quatre elements, auto-fit
     creait une cinquieme piste vide et cassait la repartition. */
  /* Une seule colonne sous 560px : a deux colonnes, chaque element reclamait
     191px et la grille debordait des le 320px. Mesure, pas supposition. */
  grid-template-columns: 1fr;
  gap: clamp(1.2rem, 3vw, 2.4rem);
}
.reassurance li {
  display: flex; align-items: flex-start; gap: .9em;
  font-family: var(--texte);
}
.ico-rea {
  width: 26px; height: 26px; flex-shrink: 0; margin-top: .1em;
  fill: none; stroke: var(--accent);
  stroke-width: 1.25; stroke-linecap: round; stroke-linejoin: round;
}
.reassurance b {
  display: block; font-weight: 400;
  font-size: .74rem; letter-spacing: .16em; text-transform: uppercase;
  color: var(--plume);
}
.reassurance span {
  display: block; font-size: .74rem; letter-spacing: .02em;
  color: var(--plume-attenuee); margin-top: .25em;
}

/* --------------------------------------------------------------------------
   27. BARRE DE PAIEMENT — pied de page
   --------------------------------------------------------------------------
   Les moyens sont écrits en toutes lettres plutôt que reproduits en logos :
   les marques Visa et Mastercard imposent des chartes couleur que la palette
   du site ne peut pas respecter, et un logo redessiné approximativement est
   pire qu'un mot. Ne figure ici que ce que la config Stripe accepte vraiment.
   -------------------------------------------------------------------------- */
.barre-paiement {
  display: flex; flex-wrap: wrap; align-items: center;
  justify-content: space-between; gap: 1rem;
  margin: clamp(2rem, 4vw, 3rem) var(--bord) 0;
  padding-top: clamp(1.5rem, 3vw, 2rem);
  border-top: 1px solid rgba(var(--filet-rgb), .3);
  font-family: var(--texte);
}
.zone-livraison {
  font-size: .72rem; letter-spacing: .18em; text-transform: uppercase;
  color: var(--plume-attenuee);
}
.moyens-paiement { list-style: none; margin: 0; padding: 0; display: flex; gap: .5rem; flex-wrap: wrap; }
/* Les marques conservent leurs couleurs officielles : un logo de paiement
   redessine dans une autre teinte n'est plus le logo, et la reconnaissance
   immediate est precisement sa raison d'etre. Seule la carte qui les porte
   suit le theme. */
.moyens-paiement li { display: flex; }
.moyens-paiement svg { width: 44px; height: 29px; display: block; }
.moyens-paiement .carte-fond {
  fill: var(--relief);
  stroke: rgba(var(--filet-rgb), .5);
}
.moyens-paiement .glyphe { fill: var(--plume); }

/* --------------------------------------------------------------------------
   28. BLOC COORDONNÉES — checkout
   -------------------------------------------------------------------------- */
.bloc-coordonnees {
  border: 1px solid rgba(var(--filet-rgb), .35);
  background: var(--relief);
  padding: clamp(1.5rem, 4vw, 2.4rem);
}
.bloc-coordonnees .surtitre { margin-bottom: 1rem; }

/* --------------------------------------------------------------------------
   29. INFO-BULLE EXPÉDITION
   -------------------------------------------------------------------------- */
.libelle-livraison { display: inline-flex; align-items: center; gap: .5em; }
.aide-expedition {
  width: 18px; height: 18px; flex-shrink: 0;
  border: 1px solid var(--accent-sourd);
  border-radius: 0;
  background: transparent; color: var(--accent);
  font-family: var(--texte); font-size: .62rem; line-height: 1;
  cursor: pointer; padding: 0;
  transition: background var(--transition-court), color var(--transition-court);
}
.aide-expedition:hover, .aide-expedition:focus-visible {
  background: var(--accent); color: var(--fond);
}
.modale-expedition {
  position: fixed; inset: 0; z-index: 1200;
  display: flex; align-items: center; justify-content: center;
  padding: var(--bord);
  background: rgba(var(--scrim-rgb), .82);
}
.modale-expedition[hidden] { display: none; }
.modale-panneau {
  position: relative;
  max-width: 46rem; max-height: 84vh; overflow-y: auto;
  background: var(--fond);
  border: 1px solid rgba(var(--filet-rgb), .45);
  padding: clamp(1.8rem, 5vw, 3.2rem);
}
.modale-fermer {
  position: absolute; top: .6rem; right: .6rem;
  width: 44px; height: 44px;
  background: transparent; border: 0; cursor: pointer;
  color: var(--plume-attenuee); font-size: 1.4rem; line-height: 1;
}
.modale-fermer:hover, .modale-fermer:focus-visible { color: var(--plume); }
.liste-politique { margin: 0; }
.liste-politique dt {
  font-family: var(--texte); font-size: .7rem;
  letter-spacing: .18em; text-transform: uppercase;
  color: var(--accent); margin-top: 1.5rem;
}
.liste-politique dd {
  margin: .5rem 0 0; padding: 0;
  color: var(--plume-attenuee); font-size: .92rem; line-height: 1.8;
}
.liste-politique dd strong { color: var(--plume); font-weight: 400; }

/* --------------------------------------------------------------------------
   30. CARTE DES POINTS RELAIS
   -------------------------------------------------------------------------- */
/* Sendcloud ouvre sa carte en surimpression, sur toute la fenêtre : il n'y a
   plus d'îlot blanc encastré dans la page comme avec l'ancien widget. Seul
   subsiste le récapitulatif du point retenu, qui reste dans la palette du
   site puisque nous le dessinons nous-mêmes. */
.relais-resume {
  border: 1px solid rgba(var(--filet-rgb), .45);
  border-left: 2px solid var(--accent-sourd);
  padding: clamp(1.1rem, 3vw, 1.6rem);
  margin-bottom: 1.4rem;
}
.relais-resume-nom {
  margin: 0 0 .3rem;
  font-family: var(--display);
  font-size: 1.05rem;
  letter-spacing: .04em;
  color: var(--plume);
}
.relais-resume-adresse {
  margin: 0 0 .5rem;
  font-size: .88rem;
  color: var(--plume-attenuee);
}
.relais-resume-transporteur {
  margin: 0 0 .9rem;
  font-family: var(--texte);
  font-size: var(--t-label);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--accent);
}

/* Choix du réseau, avant ouverture. Sendcloud mélange les deux transporteurs
   dans sa liste, chacun avec son logo, mais n'offre pas de filtre par
   transporteur dans son interface — seulement par type de point. Ce filtre-ci
   comble ce manque, pour la cliente qui a une préférence. */
.relais-transporteurs {
  border: 0;
  margin: 0 0 1.2rem;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: .5rem 1.4rem;
  align-items: center;
}
.relais-transporteurs legend {
  padding: 0;
  margin-bottom: .5rem;
  font-family: var(--texte);
  font-size: var(--t-label);
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--plume-attenuee);
}
.relais-transporteurs label {
  display: inline-flex;
  align-items: center;
  gap: .45em;
  font-size: .9rem;
  color: var(--plume);
  cursor: pointer;
}
.relais-transporteurs input { accent-color: var(--accent); }

/* Consentement avant chargement du sélecteur — §RGPD.
   Sendcloud ne dépose aucun cookie, mais l'ouverture transmet l'adresse IP à
   un tiers. On demande donc avant, et non après : une fois le script chargé,
   la requête est partie et le consentement n'aurait plus d'objet. */
.relais-consentement {
  border: 1px dashed rgba(var(--filet-rgb), .55);
  padding: clamp(1.4rem, 4vw, 2.2rem);
  margin-bottom: 1.4rem;
}
.relais-consentement-titre {
  margin: 0 0 .7rem;
  font-family: var(--texte);
  font-size: var(--t-label);
  letter-spacing: .26em;
  text-transform: uppercase;
  color: var(--plume);
}
.relais-consentement p:not(.relais-consentement-titre) {
  margin: 0 0 1.2rem;
  color: var(--plume-attenuee);
  font-size: .92rem;
}
.relais-consentement-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .9rem 1.4rem;
}
/* L'alternative est annoncée à côté du bouton, pas en dessous : personne ne
   doit avoir l'impression que refuser bloque la commande. */
.relais-consentement-actions .aide { margin: 0; flex: 1 1 16rem; }

/* --------------------------------------------------------------------------
   31. SUGGESTIONS DE ROUTINE — panier
   -------------------------------------------------------------------------- */
.grille-suggestions {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: clamp(1.4rem, 3vw, 2.4rem);
}
.suggestion { display: flex; flex-direction: column; }
.suggestion-media { background: var(--relief); margin-bottom: .9rem; overflow: hidden; }
.suggestion-media img { width: 100%; aspect-ratio: 1/1; object-fit: contain; display: block; }
.suggestion-gamme {
  font-family: var(--texte); font-size: .62rem;
  letter-spacing: .2em; text-transform: uppercase; color: var(--accent);
}
.suggestion-nom { font-size: 1.05rem; margin: .4rem 0 .2rem; letter-spacing: .02em; }
.suggestion-format,
.suggestion-prix { font-family: var(--texte); margin: 0; }
.suggestion-format { font-size: .72rem; color: var(--plume-attenuee); }
.suggestion-prix { font-size: 1rem; color: var(--plume); margin: .5rem 0 .9rem; }
.suggestion-ajouter { margin-top: auto; width: 100%; }

/* Quatre colonnes dès qu'il y a la place ; deux en dessous. */
@media (min-width: 900px) {
  .reassurance ul { grid-template-columns: repeat(4, 1fr); }
}

/* Deux colonnes dès 560px — en dessous, une seule (voir .reassurance ul). */
@media (min-width: 560px) and (max-width: 899px) {
  .reassurance ul { grid-template-columns: repeat(2, 1fr); }
}

/* Le bandeau vit désormais dans le pied : il ne doit pas y porter le filet
   supérieur du haut de page, qui doublerait celui du pied. */
.reassurance-pied {
  border-top: 0;
  border-bottom: 0;
  padding-top: clamp(2rem, 4vw, 3rem);
  padding-bottom: 0;
}

/* ==========================================================================
   32. FORMULAIRE DE CONTACT — piège à robots et confirmation
   ==========================================================================
   Le piège est retiré de l'affichage ET de l'ordre de tabulation. Il n'est
   pas masqué par `display:none` : certains robots ignorent les champs ainsi
   masqués, alors qu'ils remplissent ceux qu'ils croient simplement décalés. */
.piege {
  position: absolute !important;
  left: -9999px !important;
  width: 1px; height: 1px;
  overflow: hidden;
}

/* Confirmation d'envoi. Elle REMPLACE le formulaire : le laisser visible
   inviterait à renvoyer, et laisserait douter que le message soit parti. */
.envoi-confirme {
  border: 1px solid rgba(var(--filet-rgb), .35);
  background: var(--relief);
  padding: clamp(2rem, 5vw, 3.2rem);
}
.envoi-confirme:focus { outline: none; }
.envoi-confirme:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* État d'erreur du formulaire : lisible, jamais rouge vif — le rouge n'existe
   pas dans la palette, et un message d'aide n'est pas une alarme. */
.form-etat {
  border-left: 2px solid var(--accent);
  padding: .9rem 0 .9rem 1rem;
  margin-bottom: 1.8rem;
  font-family: var(--texte);
  font-size: .88rem;
  line-height: 1.7;
  color: var(--plume);
}

/* Pesée du colis, sous la ligne « Livraison » du récapitulatif de commande.
   Registre des notes de bas de bloc : petit, atténué, sans ornement. Elle est
   là pour être vérifiée, pas pour être lue. */
.pesee {
  margin: .4rem 0 .9rem;
  font-family: var(--texte);
  font-size: .78rem;
  color: var(--plume-attenuee);
}

.pesee > summary {
  cursor: pointer;
  letter-spacing: .04em;
  padding: .2rem 0;
}

.pesee > summary:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: 3px;
}

.pesee ul {
  list-style: none;
  margin: .5rem 0 0;
  padding: 0;
}

.pesee li {
  padding: .18rem 0;
  /* Les poids doivent s'aligner à l'œil d'une ligne à l'autre. */
  font-variant-numeric: tabular-nums;
}

.pesee > p {
  margin: .5rem 0 0;
  padding-top: .5rem;
  border-top: 1px solid var(--filet);
  color: var(--plume);
  font-variant-numeric: tabular-nums;
}

/* --------------------------------------------------------------------------
   LES DEUX SALONS — le-salon.html
   Deux blocs de trame identique. Toute la difficulté est là : la répétition
   doit se lire comme « deux lieux comparables », jamais comme « la même fiche
   affichée deux fois ». D'où le numéro d'index et la ville portée au corps du
   h1 — ce sont les deux seuls signes qui différencient les blocs au premier
   coup d'œil, avant même la lecture de l'adresse.
   -------------------------------------------------------------------------- */
.salon-numero {
  font-family: var(--display);
  font-size: clamp(2.6rem, 6vw, 4.2rem);
  line-height: 1;
  letter-spacing: .06em;
  color: var(--accent);
  /* Un index, pas un titre : il compte les salons sans réclamer l'attention. */
  opacity: .38;
  margin: 0 0 clamp(1rem, 2.5vw, 1.8rem);
}

/* La ville est le seul mot qui distingue vraiment les deux blocs : elle est
   donc composée un cran au-dessus des autres h2 de la page. */
.salon-ville {
  font-size: var(--t-h1);
  letter-spacing: .1em;
  margin-bottom: 1.8rem;
}

/* Le filet sépare deux salons de même rang ; il ne doit pas se lire comme le
   début d'une sous-partie du précédent. */
.salon + .salon,
.salon {
  scroll-margin-top: clamp(5rem, 12vh, 7rem);   /* ancres #rouen / #tourville */
}

/* --- Dépliage des avis (le-salon.html) ---------------------------------- */
/* Six avis visibles, le reste replié. Un <details> plutôt qu'un bouton en
   JavaScript : le dépliage marche sans script, à l'impression et pour les
   moteurs, qui lisent le contenu même replié. */
.avis-plus { margin-top: clamp(1rem, 2.5vw, 1.6rem); }

.avis-plus > summary {
  display: inline-block;
  cursor: pointer;
  font-family: var(--texte);
  font-size: var(--t-label);
  letter-spacing: .28em;
  text-transform: uppercase;
  color: var(--accent);
  padding: .9rem 0;
  /* Cible tactile : 44px de haut, comme les liens de navigation. */
  min-height: 44px;
  border-bottom: 1px solid var(--accent-sourd);
  transition: color var(--transition-court), border-color var(--transition-court);
}

.avis-plus > summary::-webkit-details-marker { display: none; }
.avis-plus > summary::marker { content: ""; }

.avis-plus > summary:hover,
.avis-plus > summary:focus-visible { color: var(--plume); border-bottom-color: var(--accent); }

/* Un seul des deux libellés à la fois — le <details> porte l'état, pas le JS. */
.avis-plus > summary .avis-plus-fermer { display: none; }
.avis-plus[open] > summary .avis-plus-ouvrir { display: none; }
.avis-plus[open] > summary .avis-plus-fermer { display: inline; }

.avis-plus[open] > summary { margin-bottom: clamp(1.8rem, 4vw, 2.6rem); }

/* --- La note en tête de chaque avis (le-salon.html) --------------------- */
/* La note et le nom partagent une ligne : « 5 / 5 · Lou Szabo ». Alignés sur
   la ligne de base, sinon le chiffre en display de 1,5rem flotte au-dessus du
   nom composé plus petit.
   Portée limitée à #avis-salons : avis.html garde sa présentation empilée,
   elle n'entrait pas dans la demande. */
#avis-salons .avis-tete {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .1rem .7rem;
}

/* La méta passe seule sous la ligne note + nom. */
#avis-salons .avis-tete > .avis-meta { flex-basis: 100%; margin-top: .2rem; }

#avis-salons .avis-tete > .avis-note,
#avis-salons .avis-tete > .avis-auteur { margin-bottom: 0; }

/* Un 1/5 ne doit pas s'afficher dans la couleur d'accent, réservée à ce que
   le site met en avant. Il reste parfaitement lisible, simplement neutre. */
.avis-negatif .avis-note { color: var(--plume-attenuee); }
.avis-negatif .avis-texte { border-left-color: rgba(var(--filet-rgb), .55); }

/* --- Toute la carte est cliquable --------------------------------------- */
/* Un lien qui enveloppe le contenu plutôt qu'un gestionnaire de clic : le
   clic milieu, le « ouvrir dans un nouvel onglet » et la navigation au
   clavier fonctionnent sans une ligne de script. */
.avis-lien {
  display: block;
  color: inherit;
  text-decoration: none;
  /* La zone cliquable déborde légèrement du texte, sinon les blancs entre
     les paragraphes ne réagissent pas au clic. */
  margin: calc(-1 * clamp(.6rem, 1.5vw, 1rem));
  padding: clamp(.6rem, 1.5vw, 1rem);
  transition: background-color var(--transition-court), border-color var(--transition-court);
}

.avis-lien:hover .avis-texte,
.avis-lien:focus-visible .avis-texte { border-left-color: var(--accent); }

.avis-lien:hover .avis-auteur,
.avis-lien:focus-visible .avis-auteur { color: var(--accent); }

.avis-lien:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: 2px;
}

/* --- Réponse publique du salon sous un avis (aucune posée à ce jour) ----- */
/* Gabarit prêt. Pour l'utiliser, placer juste après le <blockquote>, DANS
   le lien de la carte :
   <p class="avis-reponse"><strong>Réponse du salon</strong> Texte de la réponse.</p> */
.avis-reponse {
  margin: 1.1rem 0 0;
  padding: .9rem 0 0 1.4rem;
  border-left: 1px solid rgba(var(--filet-rgb), .35);
  font-size: .86rem;
  line-height: 1.75;
  color: var(--plume-attenuee);
}

.avis-reponse strong {
  display: block;
  font-weight: 400;
  font-family: var(--texte);
  font-size: var(--t-label);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: .4rem;
}

/* Les deux adresses du pied de page. Sans séparation, les six lignes se
   lisent comme une seule adresse mal découpée : le filet et l'écart tranchent. */
.pied-adresses > span {
  display: block;
}

.pied-adresses > span + span {
  margin-top: 1.1rem;
  padding-top: 1.1rem;
  border-top: 1px solid rgba(var(--filet-rgb), .35);
}

.pied-adresses strong {
  font-weight: 400;
  color: var(--accent);
  letter-spacing: .08em;
}

/* ==========================================================================
   AJOUTS DU 15/09/2026 — routines, quiz, cookies, produits pro
   Aucun token nouveau : tout repose sur les variables existantes.
   ========================================================================== */

/* « Gérer les cookies » dans le pied : un bouton (il agit sur la page), habillé
   exactement comme les liens voisins. */
.pied-bouton {
  appearance: none;
  background: none;
  border: 0;
  font: inherit;
  text-align: left;
  color: var(--plume-attenuee);
  font-size: .9rem;
  padding: .55rem 0;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  cursor: pointer;
  transition: color var(--transition-court);
}
.pied-bouton:hover, .pied-bouton:focus-visible { color: var(--plume); }

/* Une tuile ne doit jamais élargir sa colonne (grille 1fr 1fr sur mobile). */
.grille-produits > li { min-width: 0; }

/* Bannières de gamme sur téléphone : « PROFESSIONNELLE » en capitales
   espacées faisait 316 px pour 287 disponibles à 375 px, et la fin du mot
   était coupée par l'overflow de la bannière. */
@media (max-width: 760px) {
  .gamme-banniere-nom { letter-spacing: .06em; }
}
@media (max-width: 420px) {
  .gamme-banniere-nom { font-size: 1.55rem; }
}

/* --- Routines (boutique) ---------------------------------------------- */
.routines {
  display: grid;
  gap: clamp(1.5rem, 4vw, 3rem);
  margin: 0 0 clamp(1.5rem, 4vw, 2.5rem);
  padding: 0;
  list-style: none;
}
@media (min-width: 900px) {
  .routines { grid-template-columns: 1fr 1fr; }
}
.routine {
  display: flex;
  flex-direction: column;
  border: 1px solid rgba(var(--filet-rgb), .45);
  background: var(--relief);
}
.routine-media { overflow: hidden; }
.routine-media img { width: 100%; aspect-ratio: 16 / 10; object-fit: cover; display: block; }
.routine-corps {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  padding: clamp(1.25rem, 3vw, 2rem);
}
.routine-nom {
  font-family: var(--display);
  font-size: clamp(1.35rem, 2.4vw, 1.7rem);
  letter-spacing: .04em;
  margin: 0 0 .6rem;
  line-height: 1.2;
}
.routine-pour { font-size: .9rem; line-height: 1.65; color: var(--plume-attenuee); margin: 0 0 1.2rem; }
.routine-liste,
.quiz-etapes {
  list-style: none;
  margin: 0 0 1.2rem;
  padding: 0;
  counter-reset: etape;
}
.routine-liste li,
.quiz-etapes li {
  counter-increment: etape;
  position: relative;
  padding: .7rem 0 .7rem 2.2rem;
  border-top: 1px solid rgba(var(--filet-rgb), .3);
  font-size: .9rem;
}
.routine-liste li::before,
.quiz-etapes li::before {
  content: counter(etape, upper-roman);
  position: absolute;
  left: 0;
  top: .75rem;
  font-family: var(--display);
  font-size: var(--t-label);
  letter-spacing: .2em;
  color: var(--accent);
}
.routine-liste .prix,
.quiz-etape-prix { float: right; color: var(--plume-attenuee); font-variant-numeric: tabular-nums; }
.routine-total,
.quiz-total {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  border-top: 1px solid rgba(var(--filet-rgb), .6);
  padding-top: .9rem;
  margin: 0 0 .4rem;
  font-family: var(--texte);
  font-size: var(--t-label);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--plume-attenuee);
}
.routine-total strong,
.quiz-total strong {
  font-family: var(--display);
  font-size: 1.6rem;
  font-weight: 400;
  letter-spacing: .03em;
  text-transform: none;
  color: var(--plume);
}
.routine-offert,
.quiz-rassurance {
  font-size: .82rem;
  color: var(--accent);
  margin: 0 0 1.3rem;
}
.routine .produit-ajouter { margin-top: auto; }
.routines-aide { text-align: center; margin: 0; }

/* --- Quiz ------------------------------------------------------------- */
/* Cibles d'ancre : l'en-tête fixe ne doit pas masquer le haut du bloc. */
#routine, #routines, .quiz { scroll-margin-top: clamp(5.5rem, 13vh, 7.5rem); }
.quiz { margin-top: clamp(1.5rem, 4vw, 2.5rem); }
.quiz-entete {
  display: flex;
  align-items: center;
  gap: 1.2rem;
  margin-bottom: 1.4rem;
}
.quiz-progression {
  margin: 0;
  flex: 0 0 auto;
  font-family: var(--texte);
  font-size: var(--t-label);
  letter-spacing: .32em;
  text-transform: uppercase;
  color: var(--accent);
}
.quiz-barre {
  flex: 1 1 auto;
  height: 1px;
  background: rgba(var(--filet-rgb), .45);
  position: relative;
}
.quiz-barre span {
  position: absolute;
  inset: -1px auto -1px 0;
  background: var(--accent);
  transition: width var(--transition);
}
.quiz-question {
  font-family: var(--display);
  font-size: clamp(1.6rem, 3.6vw, 2.6rem);
  font-weight: 300;
  letter-spacing: .01em;
  line-height: 1.15;
  margin: 0 0 clamp(1.4rem, 3vw, 2.2rem);
  max-width: 24ch;
}
.quiz-question:focus,
.quiz-routine-nom:focus { outline: none; }
.quiz-choix {
  list-style: none;
  margin: 0 0 1.4rem;
  padding: 0;
  display: grid;
  gap: .7rem;
  max-width: 40rem;
}
.quiz-option {
  appearance: none;
  width: 100%;
  min-height: 56px;
  padding: 1rem 1.3rem;
  text-align: left;
  background: transparent;
  color: var(--plume);
  border: 1px solid rgba(var(--filet-rgb), .6);
  border-radius: 0;
  font: inherit;
  font-size: 1rem;
  cursor: pointer;
  transition: border-color var(--transition-court), color var(--transition-court),
              padding var(--transition-court), transform 140ms cubic-bezier(.16, 1, .3, 1);
}
.quiz-option:hover,
.quiz-option:focus-visible {
  border-color: var(--accent);
  color: var(--accent);
  padding-left: 1.6rem;
}
.quiz-option:active { transform: translateY(1px) scale(.995); }
.quiz-option[aria-pressed="true"] { border-color: var(--accent); color: var(--accent); }
.quiz-retour { font-size: .88rem; }

.quiz-resultat {
  display: grid;
  gap: clamp(1.5rem, 4vw, 3.5rem);
  align-items: start;
}
@media (min-width: 900px) {
  .quiz-resultat { grid-template-columns: 5fr 7fr; }
}
.quiz-visuel { overflow: hidden; border: 1px solid rgba(var(--filet-rgb), .45); }
.quiz-visuel img { width: 100%; aspect-ratio: 4 / 5; object-fit: cover; display: block; }
.quiz-corps .surtitre { margin-bottom: 1rem; }
.quiz-routine-nom {
  font-family: var(--display);
  font-size: clamp(1.8rem, 4vw, 2.8rem);
  font-weight: 300;
  line-height: 1.1;
  margin: 0 0 1.2rem;
}
.quiz-conseil { font-size: .95rem; line-height: 1.7; max-width: 52ch; margin: 0 0 .8rem; }
.quiz-etapes { margin-top: 1.4rem; }
.quiz-etape-nom { margin: 0; color: var(--plume); }
.quiz-etape-geste {
  margin: .2rem 0 0;
  font-size: .8rem;
  color: var(--plume-attenuee);
}
.quiz-acheter { width: 100%; }
@media (min-width: 560px) { .quiz-acheter { width: auto; } }
.quiz-suite { margin: 1.3rem 0 0; font-size: .9rem; color: var(--plume-attenuee); }

/* ==========================================================================
   AJOUTS DU 16/09/2026 — e-mails et avis
   ========================================================================== */

/* --- Inscription depuis le résultat du quiz --------------------------- */
.quiz-inscription {
  margin-top: clamp(1.8rem, 4vw, 2.6rem);
  padding-top: 1.4rem;
  border-top: 1px solid rgba(var(--filet-rgb), .45);
  max-width: 36rem;
}
.quiz-inscription-titre {
  margin: 0 0 .8rem;
  font-family: var(--texte);
  font-size: var(--t-label);
  letter-spacing: .28em;
  text-transform: uppercase;
  color: var(--accent);
}
.quiz-inscription-ligne { display: flex; gap: .5rem; flex-wrap: wrap; margin-bottom: 1rem; }
.quiz-inscription-ligne[hidden], .quiz-inscription .champ-case[hidden] { display: none; }
.quiz-inscription-ligne input {
  flex: 1 1 14rem;
  min-width: 0;
  min-height: 48px;
  padding: .8rem 1rem;
  font: inherit;
  color: var(--plume);
  background: transparent;
  border: 1px solid rgba(var(--filet-rgb), .7);
  border-radius: 0;
}
.quiz-inscription-ligne input:focus-visible { outline: 1px solid var(--accent); outline-offset: 2px; }
.quiz-inscription .champ-case label { font-size: .82rem; }

/* --- Dépôt d'avis ------------------------------------------------------ */
.avis-depot { margin-top: clamp(1.5rem, 4vw, 2.5rem); max-width: 44rem; }
.avis-produit {
  border: 1px solid rgba(var(--filet-rgb), .45);
  margin: 0 0 1.2rem;
  padding: clamp(1rem, 3vw, 1.6rem);
  min-width: 0;
}
.avis-produit-fait { opacity: .7; }
.avis-produit-tete { display: flex; gap: 1rem; align-items: center; margin-bottom: 1rem; }
.avis-produit-tete img {
  width: 72px; height: 72px; object-fit: cover; flex: 0 0 auto;
  background: var(--relief); border: 1px solid rgba(var(--filet-rgb), .45);
}
.avis-produit-tete .produit-nom,
.avis-produit-tete .produit-format { margin-bottom: .2rem; }

/* Étoiles de saisie : de vrais boutons radio (clavier : flèches), rangés en
   ordre inverse pour que le survol et la sélection colorent les étoiles
   « jusqu'à » celle visée, sans JavaScript. */
.etoiles-saisie {
  display: inline-flex;
  flex-direction: row-reverse;
  justify-content: flex-end;
  gap: .15rem;
  margin: 0 0 1.2rem;
}
.etoiles-saisie input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.etoiles-saisie label {
  cursor: pointer;
  font-size: 2rem;
  line-height: 1;
  padding: .2rem .15rem;
  min-width: 44px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--accent-sourd);
  transition: color var(--transition-court), transform 140ms;
}
.etoiles-saisie input:checked ~ label,
.etoiles-saisie label:hover,
.etoiles-saisie label:hover ~ label { color: var(--accent); }
.etoiles-saisie input:focus-visible + label { outline: 1px solid var(--accent); outline-offset: 2px; }
.etoiles-saisie label:active { transform: scale(.92); }
.avis-formulaire .champ textarea { min-height: 6rem; }
.avis-formulaire .bouton { margin-top: 1rem; }
.avis-merci:focus { outline: none; }

/* --- Avis publiés, sous la note d'une fiche ---------------------------- */
.produit-avis { margin: .2rem 0 .9rem; font-size: .82rem; }
.produit-avis summary {
  cursor: pointer;
  color: var(--accent);
  min-height: 44px;
  display: flex;
  align-items: center;
  list-style: none;
}
.produit-avis summary::-webkit-details-marker { display: none; }
.produit-avis summary::after { content: "+"; margin-left: .4em; }
.produit-avis[open] summary::after { content: "−"; }
.produit-avis ul { list-style: none; margin: 0 0 .6rem; padding: 0; }
.produit-avis li { padding: .7rem 0; border-top: 1px solid rgba(var(--filet-rgb), .3); }
.produit-avis-tete { margin: 0 0 .3rem; display: flex; gap: .6rem; align-items: baseline; flex-wrap: wrap; }
.produit-avis-tete strong { font-weight: 400; color: var(--plume); }
.produit-avis-note { color: var(--accent); letter-spacing: .1em; }
.produit-avis-texte { margin: 0 0 .3rem; line-height: 1.6; color: var(--plume); overflow-wrap: anywhere; }
.produit-avis-meta { margin: 0; font-size: .72rem; color: var(--plume-attenuee); }
.produit-avis-reponse {
  margin: .5rem 0 0;
  padding-left: .8rem;
  border-left: 1px solid rgba(var(--filet-rgb), .5);
  color: var(--plume-attenuee);
}
.produit-avis-reponse strong {
  display: block; font-weight: 400; font-size: .68rem; letter-spacing: .18em;
  text-transform: uppercase; color: var(--accent); margin-bottom: .2rem;
}

/* --- Donner mon avis : lien sous chaque produit et demande de lien ----- */
.produit-avis-inviter { margin: -.5rem 0 .9rem; font-size: .78rem; }
.produit-avis + .produit-avis-inviter { margin-top: 0; }
.avis-demande {
  border: 1px solid rgba(var(--filet-rgb), .45);
  padding: clamp(1.2rem, 4vw, 2rem);
}
.avis-demande-titre { font-size: clamp(1.3rem, 3.5vw, 1.7rem); margin: 0 0 .8rem; }
.avis-demande .attenue { margin-bottom: 1.2rem; }
.avis-demande-aide { font-size: .82rem; margin: 1rem 0 0 !important; }

/* ==========================================================================
   PAGES PRODUIT — /produits/
   ==========================================================================
   Une page par produit, reprenant la fiche de la boutique telle quelle : même
   balisage, mêmes classes, donc panier.js et avis.js s'y branchent sans
   savoir qu'ils ont changé de page. Seule la mise en page diffère — deux
   colonnes au lieu d'une tuile — et le nom passe en h1.
   -------------------------------------------------------------------------- */
.fiche-produit {
  display: grid;
  gap: clamp(1.8rem, 5vw, 3.5rem);
  /* Pas de translateY au survol ici : sur une tuile de boutique le soulèvement
     signale un lien, sur une page produit il n'y a nulle part à aller. */
  transition: none;
}
.fiche-produit:hover, .fiche-produit:focus-within { transform: none; }

@media (min-width: 900px) {
  /* L'image garde le carré du packshot ; le texte prend le reste. */
  .fiche-produit { grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr); align-items: start; }
}

.fiche-produit > .produit-media { margin-bottom: 0; }

/* Le nom du produit est le h1 de la page : il ne peut pas rester à 1,1 rem
   comme dans une grille de seize tuiles. */
.fiche-produit .produit-nom {
  font-size: var(--t-h2);
  text-transform: uppercase;
  letter-spacing: .1em;
  line-height: 1.05;
  margin: 0 0 .9rem;
}

.fiche-produit .produit-desc { font-size: .95rem; margin-bottom: 1.4rem; }
.fiche-produit .produit-prix { font-size: 1.6rem; }
.fiche-produit .produit-achat { margin-top: 1.2rem; }

/* --- Section des avis vérifiés ------------------------------------------- */
.avis-produit-resume {
  font-family: var(--display);
  font-size: 1.25rem;
  letter-spacing: .04em;
  color: var(--accent);
  margin: 0 0 1.2rem;
}

.avis-liste-produit {
  list-style: none;
  margin: 0;
  padding: 0;
}

.avis-liste-produit > li + li {
  margin-top: clamp(1.4rem, 3vw, 2rem);
  padding-top: clamp(1.4rem, 3vw, 2rem);
  border-top: 1px solid rgba(var(--filet-rgb), .3);
}

/* --- Autres produits de la gamme ----------------------------------------- */
/* Maillage interne : depuis une page produit, on doit pouvoir rejoindre ses
   voisines sans repasser par la boutique. */
.produits-lies {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: clamp(1.2rem, 3vw, 2rem);
  grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
}

.produits-lies a {
  display: block;
  text-decoration: none;
  color: inherit;
}

.produits-lies .produit-media { margin-bottom: .8rem; }

.produits-lies .produit-nom {
  font-size: .95rem;
  margin-bottom: .2rem;
}

.produits-lies a:hover .produit-nom,
.produits-lies a:focus-visible .produit-nom { color: var(--accent); }

.produits-lies .produit-prix { font-size: 1rem; margin: 0; }

/* --- Composition d'une routine ------------------------------------------- */
/* Les produits d'une routine portent data-fiche pour que avis.js y pose leur
   note réelle, et data-avis-compact pour qu'il s'arrête là : le détail des
   avis est sur la page du produit, pas répété ici. */
.routine-composants {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: clamp(1.2rem, 3vw, 2rem);
  grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr));
}

.routine-composants > li { display: flex; flex-direction: column; }
.routine-composants .produit-media { margin-bottom: .8rem; }
.routine-composants .produit-nom { font-size: .95rem; }
.routine-composants .produit-format { margin-bottom: .3rem; }
.routine-composants .produit-prix { font-size: 1rem; margin: .2rem 0 .6rem; }
.routine-composants a { text-decoration: none; color: inherit; }
.routine-composants a:hover .produit-nom,
.routine-composants a:focus-visible .produit-nom { color: var(--accent); }

/* --- Lien depuis les tuiles de la boutique ------------------------------- */
/* La tuile entière ne peut pas devenir un lien : elle contient déjà des
   boutons (variantes, quantité, ajout). Seuls l'image et le nom le sont.
   NOM DE CLASSE : ne pas revenir à « produit-lien ». Cette classe-là existe
   déjà, plus haut dans cette feuille, pour un LIEN TEXTE (« Voir le produit »
   sur l'accueil) : elle porte un border-bottom pointillé et un margin-top:auto.
   Réutilisée sur cette enveloppe, elle dessinait un trait entre le nom et la
   ligne d'avis, et poussait le bloc en bas de la carte — les deux défauts
   signalés. */
.produit-vignette {
  display: block;
  text-decoration: none;
  color: inherit;
}
.produit-vignette:hover .produit-nom,
.produit-vignette:focus-visible .produit-nom { color: var(--accent); }

/* --- Alignement des cartes de la grille ---------------------------------- */
/* Les descriptions n'ont pas la même longueur : sans cela, le prix et le
   bouton flottaient à des hauteurs différentes d'une carte à l'autre. On
   pousse le bloc d'achat en bas, d'un seul tenant — prix, quantité, ajout,
   stock et livraison restent groupés et alignés sur toute la ligne.
   Portée limitée à la grille : sur une page produit, la colonne n'est pas
   étirée et un margin-top:auto y creuserait un vide. */
.grille-produits > .produit > .produit-prix { margin-top: auto; }
.grille-produits > .produit > .produit-achat { margin-top: .6rem; }
