/* ==========================================================================
   YONA COSMETICS : moteur de mise en page
   Aucune valeur esthétique en dur : tout vient de tokens.css.

   Ce qui a disparu de la v2 (R6) : les grilles de « petites cases »
   icône + titre + phrase. Remplacées par des chiffres en colonne, des
   listes à filets et des blocs asymétriques portés par une photo.
   ========================================================================== */

*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{margin:0;background:var(--ivoire);color:var(--encre);
  font-family:var(--f-texte);font-size:var(--t-corps);font-weight:var(--g-corps);
  line-height:1.62;overflow-x:hidden}
img{max-width:100%;height:auto;display:block}
a{color:inherit}
button{font:inherit;color:inherit}
h1,h2,h3,h4{margin:0;font-family:var(--f-titre);font-weight:var(--g-titre);
  line-height:1.12;letter-spacing:-.01em}
p{margin:0}
ul,ol{margin:0;padding:0;list-style:none}
strong,b{font-weight:var(--g-fort)}
:focus-visible{outline:2px solid var(--or);outline-offset:3px}
.sur-sombre :focus-visible{outline-color:var(--blanc)}
.sur-clair :focus-visible{outline-color:var(--encre)}
::selection{background:var(--bleu);color:var(--encre)}

/* ---------- primitives ---------- */
.page{width:min(var(--page),100% - var(--gouttiere)*2);margin-inline:auto}
/* WordPress pose AUSSI la classe `page` sur le <body> des pages (diagnostic,
   laboratoire, revendeuse, contact, livraison, panier) : notre conteneur
   encadrait alors tout le corps, entête, héros et pied compris (349 px de
   large au lieu de 390 au téléphone, mesuré le 11/09). */
body.page{width:auto;margin-inline:0}
.section{padding-block:var(--section)}
.section--court{padding-block:var(--e6)}
.mesure{max-width:var(--texte-large)}
.vh{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
.sprite{display:none}

.sur-titre{font-size:var(--t-label);letter-spacing:var(--ls-label);text-transform:uppercase;
  font-weight:var(--g-label);color:var(--or);margin:0}
.sur-titre--clair{color:var(--or-clair)}
.sur-titre--encre{color:var(--encre)}
.h2{font-size:var(--t-h2);font-variation-settings:'opsz' 30}
.h3{font-size:var(--t-h3);font-variation-settings:'opsz' 24}
.h4{font-size:var(--t-h4);font-variation-settings:'opsz' 20}
.lead{font-size:var(--t-lead);color:var(--encre-douce);max-width:52ch;line-height:1.52}
.lead--court{max-width:36ch}
/* Le mot accentué d'un titre. Figtree n'a pas d'italique dans le thème : un italique fabriqué par le
   navigateur est une police penchée de force. L'accent passe donc par la graisse. */
.ital{font-style:normal;font-weight:var(--g-fort)}

.mt-2{margin-top:var(--e2)}
.mt-3{margin-top:var(--e3)}
.mt-4{margin-top:var(--e4)}
.mt-5{margin-top:var(--e5)}
.mt-6{margin-top:var(--e6)}

/* ---------- boutons : casse normale, 16 px (R5) ---------- */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:.5em;
  min-height:54px;padding:0 var(--e5);border:1px solid transparent;border-radius:var(--r-0);
  font-size:var(--t-menu);font-weight:var(--g-fort);letter-spacing:.005em;
  text-decoration:none;cursor:pointer;
  transition:background var(--duree-court) var(--courbe),color var(--duree-court) var(--courbe),
    border-color var(--duree-court) var(--courbe)}
.btn--plein{background:var(--encre);color:var(--ivoire)}
.btn--plein:hover{background:var(--bleu-nuit)}
.btn--fil{background:transparent;color:var(--encre);border-color:var(--filet-fort)}
.btn--fil:hover{background:var(--encre);color:var(--ivoire);border-color:var(--encre)}
.btn--clair{background:var(--blanc);color:var(--encre)}
.btn--clair:hover{background:var(--encre);color:var(--blanc)}
.btn--fil-clair{background:transparent;color:var(--blanc);border-color:var(--filet-clair)}
.btn--fil-clair:hover{background:var(--blanc);color:var(--encre);border-color:var(--blanc)}
.btn--petit{min-height:46px;padding:0 var(--e4);font-size:var(--t-petit)}
.btn--large{width:100%}
.btn svg{width:1.1em;height:1.1em;flex:none}
/* Deux boutons voisins partagent une ligne et un écart, ou s'empilent sans se toucher
   (mesuré le 17/09 sur l'accueil : 4 px de décalage au bureau, 0 px d'écart au téléphone). */
.actions{display:flex;flex-wrap:wrap;align-items:center;gap:var(--e3)}

.lien-fleche{display:inline-flex;align-items:center;gap:.5em;text-decoration:none;
  font-size:var(--t-menu);font-weight:var(--g-fort);
  border-bottom:1px solid var(--filet-fort);padding-bottom:.3em;
  transition:border-color var(--duree-court)}
.lien-fleche:hover{border-color:currentColor}
.lien-fleche svg{width:1.05em;height:1.05em;transition:transform var(--duree-court) var(--courbe)}
.lien-fleche:hover svg{transform:translateX(5px)}
.sur-sombre .lien-fleche{border-color:var(--filet-clair)}

/* ==========================================================================
   BANDE DE SERVICE (V4, R2)
   Transposée de la bande de réassurance de la boutique de L'Art des Sens :
   trois faits depuis le 11/09 (la case WhatsApp est partie), et aucune
   promesse commerciale inventée. Sans pictogramme : les icônes en rangée
   ont été retirées de ce site.

   Hauteur FIXE : une rangée partout, réservée pour deux lignes. C'est ce qui
   empêche la police de repli de pousser la page au chargement. La version
   d'avant s'en protégeait par `white-space:nowrap`, ce qui interdisait
   d'écrire plus d'une ligne.
   ========================================================================== */
.annonce{background:var(--encre-nuit);color:rgba(255,255,255,.9)}
.serv{display:grid;grid-template-columns:repeat(3,1fr);gap:1px;
  background:rgba(255,255,255,.10);margin:0;padding:0;list-style:none}
/* Trois cases depuis le 11/09 (la case WhatsApp est partie, retour Rayan) :
   une seule rangée au téléphone aussi. Chaque titre y tient sur deux lignes,
   et la hauteur est réservée pour deux : que la police de repli coupe une
   ligne de plus ou de moins, rien ne bouge sous la bande. */
.serv__case{background:var(--encre-nuit);display:flex;flex-direction:column;
  justify-content:center;align-items:center;text-align:center;gap:.15rem;
  min-height:3.4rem;padding:.5rem .6rem}
.serv__mot{font-family:var(--f-texte);font-size:var(--t-mini);font-weight:var(--g-fort);
  color:var(--blanc);line-height:1.25;letter-spacing:.01em}
/* Le détail n'apparaît qu'à partir de la largeur où il tient sans serrer :
   au téléphone, les quatre titres se suffisent à eux-mêmes. */
.serv__det{display:none;font-size:var(--t-mini);line-height:1.3;
  color:rgba(255,255,255,.72)}
@media (min-width:760px){
  .serv__case{min-height:58px;padding-inline:var(--e4)}
  .serv__det{display:block}
}

/* ---------- entête ---------- */
.entete{position:sticky;top:0;z-index:60;
  transition:background var(--duree-court),box-shadow var(--duree-court),color var(--duree-court)}
.entete__in{position:relative;display:flex;align-items:center;justify-content:space-between;
  gap:var(--e4);min-height:var(--entete-h)}
.marque{display:flex;flex-direction:column;line-height:1;text-decoration:none;color:inherit}
.marque b{font-family:var(--f-marque);font-weight:var(--g-marque);font-size:1.85rem;
  letter-spacing:.09em;font-variation-settings:'opsz' 20}
/* 14 px : le plancher vaut aussi pour le bloc-marque, la casse a été
   rééquilibrée pour que COSMETICS tienne sous YONA */
.marque span{font-size:var(--t-mini);letter-spacing:.155em;font-weight:var(--g-fort);
  padding-left:.14em;opacity:.9;line-height:1.35}
.nav{display:flex;align-items:center;gap:clamp(.9rem,1.7vw,1.9rem)}
.nav a{text-decoration:none;font-size:var(--t-menu);font-weight:var(--g-corps);
  position:relative;padding-block:.4rem}
.nav a::after{content:"";position:absolute;left:0;right:100%;bottom:.15rem;height:1px;
  background:currentColor;transition:right var(--duree-court) var(--courbe)}
.nav a:hover::after,.nav a[aria-current]::after{right:0}
.nav a[aria-current]{font-weight:var(--g-fort)}
/* Posé sur une tête photographique, l'entête est transparent et clair ; il ne
   se solidifie qu'au défilement. Sur une tête claire (ivoire), il est encre
   dès le départ. Sur une page sans photo (fiche, panier), il est plein.
   La classe vient de yona_teinte_courante() : UNE fonction décide. */
.entete--sur-photo{color:var(--ivoire)}
.entete--sur-photo .btn--fil{color:var(--ivoire);border-color:var(--filet-clair)}
.entete--sur-photo .btn--fil:hover{background:var(--ivoire);color:var(--encre);border-color:var(--ivoire)}
/* Lisibilité mesurée le 11/09 : sur les photos claires, le logo et « Panier »
   tombaient entre 1,7:1 et 2,9:1 (cheveux, revendeuse, contact, boutique,
   visage, laboratoire, accueil). Sur une tête photographique, l'entête prend
   donc le verre fumé de la bande de service, comme l'entête de la boutique de
   L'Art des Sens : la photo reste devinée, le texte ne dépend plus d'elle. */
.entete--sur-photo:not(.est-fixe){background:rgba(12,18,22,.86);
  -webkit-backdrop-filter:blur(10px) saturate(1.1);backdrop-filter:blur(10px) saturate(1.1)}
.entete--sur-clair{color:var(--encre)}
.entete--plein{background:var(--ivoire);color:var(--encre)}
.entete.est-fixe{background:var(--ivoire);color:var(--encre);box-shadow:0 1px 0 var(--filet)}
.entete.est-fixe .btn--fil{color:var(--encre);border-color:var(--filet-fort)}
.entete.est-fixe .btn--fil:hover{background:var(--encre);color:var(--ivoire);border-color:var(--encre)}
/* Le choix de langue (GTranslate) : la même pastille que sur la boutique de
   L'Art des Sens, drapeau + code + chevron, liste déroulante hors flux. Le
   widget arrive en pavé blanc avec sa propre police : on le ramène à la
   maison. La pastille suit `currentColor`, donc les trois états de l'entête
   (sur photo, sur clair, plein) sans une règle par état. */
.entete__langue{position:relative;display:flex;align-items:center}
.entete__langue .gt_float_switcher{
  font-family:var(--f-texte);font-size:var(--t-mini);box-shadow:none;overflow:visible;
  background:transparent;color:inherit;
  border:1px solid color-mix(in srgb,currentColor 32%,transparent);border-radius:999px}
.entete__langue .gt_float_switcher img{width:16px;height:auto;border-radius:2px}
.entete__langue .gt_float_switcher .gt-selected{background:transparent}
.entete__langue .gt_float_switcher .gt-selected .gt-current-lang{
  display:flex;align-items:center;gap:6px;padding:7px 11px;color:inherit}
.entete__langue .gt_float_switcher .gt-lang-code{
  font-weight:var(--g-fort);font-size:var(--t-label);letter-spacing:.12em;text-transform:uppercase;color:inherit}
/* Le chevron d'origine est une image sombre, invisible sur le verre fumé :
   on le masque et on dessine le nôtre, à la couleur du texte. */
.entete__langue .gt_float_switcher .gt_float_switcher-arrow{display:none!important}
.entete__langue .gt_float_switcher .gt-current-lang::after{
  content:"";width:6px;height:6px;flex:none;margin-top:-4px;
  border-right:1.4px solid currentColor;border-bottom:1.4px solid currentColor;
  transform:rotate(45deg)}
/* Le widget « float » empile sa liste DANS le flux : ouverte, elle ferait
   grandir l'entête (82 → 332 px mesurés chez L'Art des Sens le 21/08). Ici la
   liste est un vrai menu déroulant : hors flux, sous la pastille, à droite.
   Elle est ivoire dans les trois états, comme le menu déplié du téléphone. */
.entete__langue .gt_float_switcher .gt_options{
  position:absolute;top:calc(100% + 6px);right:0;left:auto;z-index:130;
  min-width:176px;width:max-content;max-height:min(60vh,420px);overflow-y:auto;
  background:var(--ivoire-clair);border-radius:10px;border:1px solid var(--filet);
  box-shadow:0 14px 34px rgba(12,18,22,.18)}
.entete__langue .gt_float_switcher .gt_options a{display:block;white-space:nowrap;
  font-size:var(--t-mini);line-height:1.3;padding:10px 14px;color:var(--encre);text-decoration:none}
.entete__langue .gt_float_switcher .gt_options a:hover,
.entete__langue .gt_float_switcher .gt_options a.gt-current{background:var(--sable);color:var(--encre)}
.entete__langue .gt_float_switcher .gt_options a img{width:16px;height:auto;margin-right:8px}
@media (max-width:640px){
  /* Au téléphone, le code céderait la place à la marque : drapeau et chevron seuls. */
  .entete__langue .gt_float_switcher .gt-selected .gt-current-lang span.gt-lang-code{display:none}
}

.burger{display:none;width:46px;height:46px;align-items:center;justify-content:center;
  background:none;border:0;cursor:pointer;margin-right:-11px}
.burger span{display:block;width:24px;height:2px;background:currentColor;position:relative}
.burger span::before,.burger span::after{content:"";position:absolute;left:0;width:24px;height:2px;
  background:currentColor;transition:transform var(--duree-court) var(--courbe)}
.burger span::before{top:-7px}.burger span::after{top:7px}
.burger[aria-expanded="true"] span{background:transparent}
.burger[aria-expanded="true"] span::before{transform:translateY(7px) rotate(45deg)}
.burger[aria-expanded="true"] span::after{transform:translateY(-7px) rotate(-45deg)}

@media (max-width:980px){
  .burger{display:flex}
  .nav{position:absolute;inset:var(--entete-h) 0 auto;flex-direction:column;align-items:stretch;gap:0;
    background:var(--ivoire);color:var(--encre);
    padding:var(--e3) var(--gouttiere) var(--e5);
    box-shadow:0 20px 44px rgba(12,18,22,.16);
    max-height:calc(100svh - var(--entete-h));overflow:auto}
  .nav[hidden]{display:none}
  .nav a{padding-block:1rem;border-bottom:1px solid var(--filet);font-size:1.0625rem}
  .nav .btn{margin-top:var(--e3)}
  /* Le menu déplié est ivoire : sur une tête photographique, le bouton
     WhatsApp y gardait l'ivoire de l'entête et s'écrivait ivoire sur ivoire,
     une case vide (vu à la capture le 11/09). Il reprend l'encre. */
  .entete--sur-photo .nav .btn--fil{color:var(--encre);border-color:var(--filet-fort)}
  .entete--sur-photo .nav .btn--fil:hover{background:var(--encre);color:var(--ivoire);border-color:var(--encre)}
}

/* ==========================================================================
   LE TEXTE SUR LA PHOTO (V4, R1 et R3)
   -----------------------------------------------------------------------
   UNE seule recette d'ombre pour tout le site : le héros, les têtes de page,
   les gammes en diapositives et les moments produit la partagent. Mêmes
   angles, mêmes paliers, mêmes opacités. Seule la TEINTE change.

   Deux couches, jamais une :
     1. `--teinte-fond` verse la couleur de la page sur la photo. C'est ce
        qui donne à chaque tête sa couleur (R3) sans tuer l'image.
     2. le dégradé garantit le contraste À L'ENDROIT du texte, pas en
        moyenne : il est opaque en bas, où le texte se pose, et transparent
        en haut, où le produit reste visible et entier.

   Les valeurs ne sont pas choisies au goût : le texte est mesuré au pixel
   sur le rendu (voir §7 de LISEZ-MOI.md), jamais estimé.
   ========================================================================== */
/* L'ombre n'est PAS grise : elle est teintée. Une ombre neutre posée sur le
   bleu de marque le rend boueux ; la même ombre en bleu profond le garde
   bleu, et donne à la page sa couleur (R3) au lieu de la lui retirer.
   `--ombre-rgb` est la seule chose qui change d'une teinte à l'autre. */
.chapeau,.hero,.moment{--ombre-rgb:12 18 22}
.chapeau--bleu,.gamme--bleu,.hero__plan--bleu,.moment--bleu{--ombre-rgb:1 81 110}
.chapeau--cuivre,.gamme--cuivre{--ombre-rgb:108 36 4}
.chapeau--encre,.gamme--encre,.moment--encre{--ombre-rgb:12 18 22}
.hero__plan--carmin,.moment--carmin{--ombre-rgb:117 1 2}
.chapeau--ivoire,.gamme--ivoire{--ombre-rgb:246 240 235}

/* Le voile GLOBAL ne sert plus qu'à une chose : lier le bas de la photo à la
   section suivante. Il ne teinte plus l'image et ne monte plus jusqu'en haut.
   Retour Rayan sur le rendu en ligne : le bleu ciel de la marque virait au
   bleu nuit et le flacon disparaissait. Le contraste est désormais obtenu par
   l'ombre LOCALE, sous le texte seul (voir plus bas) ; la photo respire. */
.chapeau__ombre,.hero__ombre,.gamme__ombre{
  position:absolute;inset:0;z-index:1;pointer-events:none;
  background-image:linear-gradient(to top,
    rgb(var(--ombre-rgb) / .30) 0%,
    rgb(var(--ombre-rgb) / .10) 30%,
    rgb(var(--ombre-rgb) / 0) 58%)}
/* Sur une teinte claire, la MÊME recette : c'est l'ivoire qui monte, et le
   texte reste encre. Un fond clair ne se traite jamais en baissant l'opacité
   du texte, il se traite en remontant le fond. Les paliers y sont plus bas :
   l'encre sur ivoire garde 15:1 de marge, la photo peut respirer. */
.sur-clair .chapeau__ombre,.sur-clair .gamme__ombre{
  background-image:linear-gradient(to top,
    rgb(var(--ombre-rgb) / .34) 0%,
    rgb(var(--ombre-rgb) / .12) 30%,
    rgb(var(--ombre-rgb) / 0) 58%)}

/* ==========================================================================
   HÉROS de l'accueil : plein écran, diaporama de trois plans, texte dessus.
   ========================================================================== */
.hero{position:relative;isolation:isolate;overflow:hidden;
  background:var(--encre-nuit);color:var(--ivoire);
  margin-top:calc(var(--entete-h) * -1);
  min-height:var(--hero-h);display:grid;align-items:end}
.hero__plans{position:absolute;inset:0;z-index:0}
/* Sans JavaScript, seul le premier plan porte `est-actif` : il s'affiche, et
   le diaporama n'existe simplement pas. Rien ne disparaît. */
.hero__plan{position:absolute;inset:0;opacity:0}
.hero__plan.est-actif{opacity:1}
.hero__plan picture{display:block;width:100%;height:100%}
.hero__plan img{width:100%;height:100%;object-fit:cover}
/* l'ombre est DANS le plan : elle prend la teinte de sa photo et fond avec elle */
.hero__plan .hero__ombre{z-index:1}
.js .hero__plan{transition:opacity var(--fondu) var(--courbe)}
.hero__in{position:relative;z-index:2;
  padding-block:calc(var(--entete-h) + var(--e5)) calc(var(--e6) + var(--e3))}
/* ==========================================================================
   L'OMBRE LOCALE DU BLOC DE TEXTE
   -----------------------------------------------------------------------
   Le dégradé de fond ne suffit pas, et ça se MESURE : le sur-titre doré, qui
   ouvre le bloc, tombait à 1,60:1 sur le héros parce qu'il se trouve haut,
   là où l'ombre de fond est presque transparente. Assombrir tout le dégradé
   pour lui aurait noyé la photo entière : c'est ce qu'on a essayé d'abord, et
   le bleu de marque en ressortait boueux.

   L'ombre est donc posée SOUS LE TEXTE, à sa hauteur exacte, pleine largeur.
   La photo garde son haut intact, le texte a son fond, et les deux se
   rejoignent sans couture. Mesuré après : sur-titre 4,8:1, titre 6,2:1.
   ========================================================================== */
.hero__in::before,.chapeau__in::before{content:"";position:absolute;z-index:-1;
  top:calc(var(--e6) * -1);bottom:calc(var(--e6) * -1);
  left:50%;transform:translateX(-50%);width:100vw;pointer-events:none;
  background:linear-gradient(to top,
    rgb(var(--ombre-rgb) / .80) 0%,
    rgb(var(--ombre-rgb) / .74) 62%,
    rgb(var(--ombre-rgb) / .60) 86%,
    rgb(var(--ombre-rgb) / 0) 100%)}
/* Au bureau, l'ombre ne traverse plus l'écran : elle tient la COLONNE DE
   GAUCHE, celle du texte, et s'efface avant la moitié. La photo reste claire
   et entière à droite, comme sur le site actuel de la marque. */
@media (min-width:900px){
  .hero__in::before,.chapeau__in::before{
    top:0;bottom:0;left:calc(50% - 50vw);transform:none;
    width:min(100vw,70rem);
    background:linear-gradient(to right,
      rgb(var(--ombre-rgb) / .86) 0%,
      rgb(var(--ombre-rgb) / .82) 46%,
      rgb(var(--ombre-rgb) / .60) 68%,
      rgb(var(--ombre-rgb) / 0) 100%)}
}
/* Sur une teinte claire, la même ombre, plus légère : l'encre sur ivoire
   garde une marge énorme, la photo n'a pas besoin d'être effacée. */
.sur-clair .chapeau__in::before{
  background:linear-gradient(to top,
    rgb(var(--ombre-rgb) / .93) 0%,
    rgb(var(--ombre-rgb) / .90) 62%,
    rgb(var(--ombre-rgb) / .86) 90%,
    rgb(var(--ombre-rgb) / 0) 100%)}
@media (min-width:900px){
  .sur-clair .chapeau__in::before{
    background:linear-gradient(to right,
      rgb(var(--ombre-rgb) / .90) 0%,
      rgb(var(--ombre-rgb) / .86) 46%,
      rgb(var(--ombre-rgb) / .64) 68%,
      rgb(var(--ombre-rgb) / 0) 100%)}
}

.hero h1{font-size:var(--t-display);margin:var(--e4) 0 0;letter-spacing:-.022em;
  font-variation-settings:'opsz' 34;max-width:14ch}
.hero .lead{color:var(--ivoire);margin-top:var(--e4);max-width:40ch}
/* Au téléphone, l'accroche revient au corps courant : quatre lignes de 1,19rem
   poussaient le bloc de texte jusqu'au milieu du flacon et son étiquette
   passait derrière le titre. Trois lignes, et le nom du soin reste lisible. */
@media (max-width:899.98px){.hero .lead{font-size:var(--t-corps)}}
.hero__actions{display:flex;flex-wrap:wrap;gap:var(--e2);margin-top:var(--e5)}
@media (min-width:900px){
  .hero__in{padding-block:calc(var(--entete-h) + var(--e6)) var(--section)}
  .hero h1{max-width:12ch}
  /* le texte tient la colonne de gauche, la photo garde la droite */
  .hero__in>*{max-width:34rem}
}

/* ==========================================================================
   TÊTE DE PAGE : la photo de la page, sa teinte, et le titre par-dessus.
   Elle remplace le titre sur ivoire nu suivi d'une bande photo : c'était
   deux blocs pour une seule idée, et le texte n'était jamais sur l'image.
   ========================================================================== */
.chapeau{position:relative;isolation:isolate;overflow:hidden;
  background:var(--encre-nuit);color:var(--ivoire);
  margin-top:calc(var(--entete-h) * -1);
  min-height:var(--chapeau-h);display:grid;align-items:end}
.chapeau.sur-clair{color:var(--encre)}
.chapeau__media{position:absolute;inset:0;z-index:0}
.chapeau__media picture{display:block;width:100%;height:100%}
.chapeau__media img{width:100%;height:100%;object-fit:cover}
.chapeau__in{position:relative;z-index:2;
  padding-block:calc(var(--entete-h) + var(--e5)) var(--e6)}
@media (min-width:900px){.chapeau__in>*{max-width:38rem}}
/* Au téléphone seulement. Placée sans condition APRÈS la règle du bureau,
   elle l'écrasait (même spécificité, plus tardive) : au bureau, l'ombre de
   gauche s'arrêtait net à 70rem au lieu de s'effacer, une couture verticale
   sur la photo de chaque tête de page (vue le 11/09). */
@media (max-width:899.98px){
  .chapeau__in::before{background:linear-gradient(to top,
    rgb(var(--ombre-rgb) / .84) 0%,
    rgb(var(--ombre-rgb) / .80) 62%,
    rgb(var(--ombre-rgb) / .70) 88%,
    rgb(var(--ombre-rgb) / 0) 100%)}
}
.chapeau h1{font-size:var(--t-display);margin-top:var(--e3);max-width:15ch;
  font-variation-settings:'opsz' 34}
/* Le titre prend la couleur de sa tête (ivoire sur fond sombre, encre sur clair) :
   sans cela une règle de titre globale l'écrit encre sur encre. Vu sur
   « Ma commande » (page de confirmation), 10/09. */
.chapeau h1,.chapeau .entry-title,.chapeau .page-title{color:inherit}
.chapeau .lead{color:rgba(255,255,255,.90);margin-top:var(--e4)}
.chapeau.sur-clair .lead{color:var(--encre-douce)}
/* Sur une PHOTO, l'étiquette est ivoire ; sur l'ivoire, elle est dorée.
   Mesuré : le doré pâle demande un fond sous 0,066 de luminance pour tenir
   4,5:1 à 13 px. Une photo de soie ivoire n'y descend jamais sans être
   effacée. L'ivoire, lui, tient 6:1 sur les mêmes pixels. */
.chapeau .sur-titre,.hero .sur-titre{color:var(--ivoire)}
.chapeau.sur-clair .sur-titre{color:var(--or)}
.chapeau .fil{padding-top:0;color:rgba(255,255,255,.72)}
.chapeau.sur-clair .fil{color:var(--encre-douce)}
.chapeau__bas{display:flex;flex-wrap:wrap;align-items:flex-end;
  justify-content:space-between;gap:var(--e3) var(--e5)}
.chapeau__n{font-family:var(--f-titre);font-weight:var(--g-titre);
  font-size:clamp(3rem,1.6rem + 5vw,5.5rem);line-height:.9;letter-spacing:-.03em;
  font-variation-settings:'opsz' 40}
.chapeau__n small{font-family:var(--f-texte);font-size:var(--t-petit);font-weight:var(--g-fort);
  letter-spacing:0;margin-left:.5rem;vertical-align:.85em;opacity:.85}
/* Le panier et la commande : pas de photo, mais pas de fond nu pour autant.
   Une lumière qui dérive depuis le haut, et le grain du site par-dessus. */
.chapeau--compacte{min-height:0;
  background-image:radial-gradient(120% 150% at 12% -10%,rgba(30,162,204,.28) 0%,rgba(12,18,22,0) 60%)}
.chapeau--compacte .chapeau__in{padding-block:calc(var(--entete-h) + var(--e4)) var(--e5)}
.chapeau--compacte h1{font-size:var(--t-h2)}

/* ==========================================================================
   LES TROIS GAMMES, EN DIAPOSITIVES (V4, R2)
   Une gamme par vue au téléphone, glissement au doigt (scroll-snap natif,
   aucune bibliothèque), points de navigation. Les trois côte à côte au
   bureau, et les points disparaissent.
   ========================================================================== */
.gammes{padding-block:0}
.gammes__piste{display:flex;gap:var(--e2);margin:0;
  padding-inline:var(--gouttiere);scroll-padding-inline:var(--gouttiere);
  overflow-x:auto;overscroll-behavior-x:contain;scroll-snap-type:x mandatory;
  -webkit-overflow-scrolling:touch;scrollbar-width:none;
  /* Sans confinement, les vues hors écran élargissent la largeur de
     défilement du DOCUMENT : le débordement ne se voit qu'à la mesure. */
  contain:paint}
.gammes__piste::-webkit-scrollbar{display:none}
/* V7 (17/09, retour Rayan : « rajoute des photos avec les produits YONA dans les trois
   catégories ») : la photo de la gamme se montre EN CLAIR, au-dessus, et le texte se pose sur un
   panneau plein à la teinte de la gamme. Avant, le texte était sur la photo, sous un voile à
   90 % prolongé d'un fondu de la hauteur du texte : sur une carte de 600 px, 460 px étaient
   teintés et le produit ne se voyait plus. */
.gamme{position:relative;isolation:isolate;overflow:hidden;
  flex:0 0 86%;scroll-snap-align:center;
  display:flex;flex-direction:column;text-decoration:none;color:var(--ivoire);
  background:rgb(var(--ombre-rgb))}
.gamme.sur-clair{color:var(--encre)}
.gamme__media{position:relative;z-index:0;aspect-ratio:4/5;overflow:hidden}
.gamme__media img{width:100%;height:100%;object-fit:cover;
  transition:transform 1.4s var(--courbe)}
.gamme:hover .gamme__media img{transform:scale(1.05)}
.gamme__ombre{display:none}
.gamme__texte{position:relative;z-index:2;flex:1;padding:var(--e4) var(--e4) var(--e5)}
.gamme h2{font-size:var(--t-h2);margin-top:var(--e2)}
.gamme p{font-size:var(--t-petit);margin-top:var(--e2);max-width:34ch;
  color:var(--ivoire)}
.gamme.sur-clair p{color:var(--encre)}
/* même règle que les têtes : sur une photo, l'étiquette est ivoire */
.gamme .sur-titre{color:var(--ivoire)}
.gamme.sur-clair .sur-titre{color:var(--or)}
.gamme .lien-fleche{margin-top:var(--e4);border-color:var(--filet-clair)}
.gamme.sur-clair .lien-fleche{border-color:var(--filet-fort)}
.gamme:hover .lien-fleche svg{transform:translateX(5px)}

.gammes__points{display:flex;justify-content:center;align-items:center;
  gap:.2rem;margin-top:var(--e3)}
/* Le point visuel fait 8 px ; c'est le remplissage qui porte la zone
   tactile, 26 × 28 px, au-dessus du minimum de 24 px (WCAG 2.2). */
.gammes__point{appearance:none;-webkit-appearance:none;border:0;cursor:pointer;
  box-sizing:content-box;width:8px;height:8px;padding:10px 9px;border-radius:99px;
  background-color:var(--filet-fort);background-clip:content-box;
  transition:width var(--duree-court) var(--courbe),background-color var(--duree-court)}
.gammes__point.est-actif{width:28px;background-color:var(--encre)}
@media (min-width:820px){
  .gammes__piste{display:grid;grid-template-columns:repeat(3,1fr);gap:1px;
    background:var(--filet);padding-inline:0;overflow:visible}
  .gamme{aspect-ratio:auto}
  .gamme__media{aspect-ratio:1}   /* au bureau, photo carrée : trois cartes côte à côte restent sous 700 px */
  .gammes__points{display:none}
}

/* ==========================================================================
   Bande défilante : les pourcentages imprimés sur les flacons.
   Une information vraie, pas une décoration.
   ========================================================================== */
.defile{background:var(--encre);color:var(--ivoire);overflow:hidden;padding-block:var(--e4);
  border-block:1px solid var(--encre)}
.defile__piste{display:flex;width:max-content;will-change:transform}
.defile__lot{display:flex;align-items:baseline;gap:clamp(1.4rem,3vw,3rem);
  padding-right:clamp(1.4rem,3vw,3rem)}
.defile b{font-family:var(--f-titre);font-weight:var(--g-titre);
  font-size:clamp(1.7rem,1.1rem + 2.1vw,2.9rem);letter-spacing:-.02em;
  font-variation-settings:'opsz' 30}
.defile i{font-style:normal;font-size:var(--t-mini);letter-spacing:.14em;text-transform:uppercase;
  color:var(--or-clair);font-weight:var(--g-label)}

/* ==========================================================================
   R6 : les chiffres à filets remplacent les 4 « petites cases ».
   ========================================================================== */
.chiffres{border-top:1px solid var(--filet)}
.chiffres__item{display:grid;gap:var(--e2) var(--e5);padding-block:var(--e5);
  border-bottom:1px solid var(--filet);align-items:baseline}
.chiffres__n{font-family:var(--f-titre);font-weight:var(--g-titre);
  font-size:clamp(2.6rem,1.4rem + 4.4vw,5.2rem);line-height:.94;letter-spacing:-.03em;
  font-variation-settings:'opsz' 44;white-space:nowrap}
.chiffres__n em{font-style:normal;font-size:.42em;letter-spacing:-.01em;margin-left:.15em}
.chiffres h3{font-size:var(--t-h4);margin-bottom:.2rem}
.chiffres p{color:var(--encre-douce);max-width:46ch}
@media (min-width:760px){
  /* 14 rem : la colonne contient le plus large des trois chiffres à toutes
     les largeurs. Bridée à 7,5 rem, les glyphes débordaient par-dessus le
     titre sans que la boîte ne bouge d'un pixel. */
  .chiffres__item{grid-template-columns:14rem minmax(0,1fr);
    padding-block:var(--e6)}
  .chiffres__texte{max-width:52ch}
}

/* ---------- en-tête de section ---------- */
.tete{display:flex;flex-wrap:wrap;align-items:flex-end;justify-content:space-between;
  gap:var(--e4);margin-bottom:var(--e6)}
.tete__t{max-width:30ch}
.tete h2{margin-top:var(--e3)}
.chapeau .lead{margin-top:var(--e3)}

/* ==========================================================================
   Grille de produits. Une carte est ici légitime : objet discret, répété,
   comparable. La prose, elle, n'est jamais mise en boîte.
   ========================================================================== */
.produits{display:grid;gap:var(--e6) var(--e4);grid-template-columns:repeat(2,1fr)}
@media (min-width:780px){.produits{grid-template-columns:repeat(3,1fr);gap:var(--e6) var(--e5)}}
.produits--4{grid-template-columns:repeat(2,1fr)}
@media (min-width:780px){.produits--4{grid-template-columns:repeat(4,1fr)}}
.carte{position:relative;display:flex;flex-direction:column}
.carte[hidden]{display:none!important}
.carte__vue{position:relative;aspect-ratio:1;overflow:hidden;background:var(--ivoire-clair)}
.carte__vue img{width:100%;height:100%;object-fit:cover;
  transition:transform 1.2s var(--courbe),opacity var(--duree-court) var(--courbe)}
.carte__vue .est-second{position:absolute;inset:0;opacity:0}
.carte:hover .carte__vue img{transform:scale(1.04)}
.carte:hover .carte__vue .est-second{opacity:1}
.carte__pct{position:absolute;left:0;top:0;background:var(--ivoire);color:var(--encre);
  font-size:var(--t-mini);font-weight:var(--g-fort);padding:.4rem .7rem}
.carte__nom{font-family:var(--f-titre);font-size:var(--t-h4);font-weight:var(--g-titre);
  margin-top:var(--e3);font-variation-settings:'opsz' 20}
.carte__nom a{text-decoration:none}
.carte__nom a::after{content:"";position:absolute;inset:0}
.carte__type{font-size:var(--t-petit);color:var(--encre-douce);margin-top:.15rem;line-height:1.45}
.carte__bas{display:flex;align-items:baseline;justify-content:space-between;gap:var(--e2);
  margin-top:var(--e3);padding-top:var(--e2);border-top:1px solid var(--filet)}
.prix{font-family:var(--f-titre);font-size:1.35rem;font-weight:var(--g-titre);white-space:nowrap;
  font-variation-settings:'opsz' 20}
.prix small{font-size:var(--t-mini);font-family:var(--f-texte);font-weight:var(--g-fort);
  margin-left:.22em;color:var(--encre-douce)}
.carte .btn{margin-top:var(--e3);width:100%;position:relative;z-index:1}
/* Les boutons d'une même rangée s'alignent (11/09 : jusqu'à 47 px d'écart
   quand un nom ou une accroche passe sur deux lignes). Le bas de carte (prix,
   accroche, bouton) se cale en bas, le haut (photo, nom, type) reste en haut. */
.carte>.carte__bas{margin-top:auto}
.carte>.carte__type{margin-bottom:var(--e3)}

/* ---------- filtres : depuis le 27/10, ceux du catalogue vivent dans navigation.css (familles, besoins, tri) ---------- */

/* ==========================================================================
   LA VITRINE : le haut de l'accueil (V6, 17/09). Réplique du héros de Glow Recipe
   (champ de couleur, titre sans empattement, bouton, la gamme alignée), passée à
   la DA de YONA : bleu de marque, texte à l'encre (6,0:1 mesuré ; l'ivoire n'y
   donne que 2,96:1), et les neuf vrais flacons détourés, posés sur l'arête du
   bloc. Les pots passent devant (`est-devant`) quand la largeur fait se chevaucher
   les flacons. Le mouvement : chaque flacon monte à son tour, puis se soulève au
   survol ; rien ne bouge si la personne a demandé moins de mouvement.
   ========================================================================== */
.vitrine{position:relative;isolation:isolate;overflow:hidden;background:var(--bleu);color:var(--encre);
  --marge:max(var(--gouttiere),calc((100% - var(--page)) / 2));
  display:grid;grid-template-columns:minmax(0,1fr);padding-top:var(--e5)}
.vitrine::before{content:"";position:absolute;z-index:-1;left:50%;bottom:-32%;width:max(150%,70rem);
  aspect-ratio:2.2/1;transform:translateX(-50%);pointer-events:none;
  background:radial-gradient(closest-side,rgba(255,255,255,.62),rgba(255,255,255,0))}
/* Le conteneur de texte s'efface (`display:contents`) : ses enfants et la gamme partagent UNE
   grille, ce qui permet au téléphone de glisser la gamme juste sous le titre. Sans ça, neuf
   flacons passaient sous la ligne de flottaison et le premier écran n'était que du texte. */
.vitrine__in{display:contents}
.vitrine__in>*{margin-inline:var(--marge)}
.vitrine h1{font-size:clamp(2.6rem,1.7rem + 4.3vw,4.6rem);font-weight:500;letter-spacing:-.015em;line-height:1.06;margin-top:var(--e3)}
.vitrine .sur-titre{color:var(--encre)}
.vitrine .lead{color:var(--encre);max-width:44ch;margin-top:var(--e4);font-size:var(--t-corps)}
.vitrine__actions{display:flex;flex-wrap:wrap;gap:var(--e2);margin-top:var(--e4)}
.vitrine__actions .btn{flex:1 1 auto}
.vitrine .btn--fil{border-color:var(--filet-encre);color:var(--encre)}
.vitrine .btn--fil:hover{background:var(--encre);color:var(--blanc);border-color:var(--encre)}
/* ordre au téléphone : sur-titre, titre, LA GAMME, puis la ligne d'argument et les boutons */
.vitrine__in>.sur-titre{order:1}.vitrine__in>h1{order:2}.vitrine__gamme{order:3}
.vitrine__in>.lead{order:4}.vitrine__in>.vitrine__actions{order:5;margin-bottom:var(--e5)}
.vitrine__gamme{--H:12.5rem;--ecart:-1.25rem;display:flex;align-items:flex-end;justify-content:center;
  margin:var(--e4) 0 0;padding:0 var(--gouttiere) var(--e3);list-style:none;
  border-bottom:1px solid var(--filet-encre)}
.vitrine__flacon{position:relative;flex:none;margin-inline:calc(var(--ecart) / 2);
  animation:vitrine-monte .95s var(--courbe) both;animation-delay:calc(.2s + var(--i) * 75ms)}
.vitrine__flacon.est-devant{z-index:2}
.vitrine__flacon a{display:block;text-decoration:none}
.vitrine__flacon img{display:block;height:calc(var(--H) * var(--h));width:auto;max-width:none;
  filter:drop-shadow(0 14px 12px rgba(1,60,84,.30));transition:transform .5s var(--courbe)}
.vitrine__nom{position:absolute;left:50%;bottom:calc(100% + .5rem);transform:translate(-50%,.4rem);opacity:0;
  white-space:nowrap;padding:.3rem .7rem;background:var(--encre);color:var(--ivoire);
  font-size:var(--t-mini);font-weight:var(--g-fort);pointer-events:none;
  transition:opacity var(--duree-court) var(--courbe),transform var(--duree-court) var(--courbe)}
@media (hover:hover){
  .vitrine__flacon a:hover img,.vitrine__flacon a:focus-visible img{transform:translateY(-.9rem)}
  .vitrine__flacon a:hover .vitrine__nom,.vitrine__flacon a:focus-visible .vitrine__nom{opacity:1;transform:translate(-50%,-.6rem)}
}
@keyframes vitrine-monte{from{opacity:0;transform:translateY(3.2rem)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion:reduce){.vitrine__flacon{animation:none}.vitrine__flacon img{transition:none}}
@media (min-width:560px){.vitrine__gamme{--H:min(37vw,19rem);--ecart:-.5rem}.vitrine__actions .btn{flex:0 0 auto}}
@media (min-width:900px){
  /* Bureau : une seule colonne de texte, calée à gauche (sur-titre, titre sur deux lignes, une
     ligne d'argument, deux boutons), puis la gamme posée sur l'arête du bloc. Tout tient dans
     le premier écran (mesuré à 1440 × 900). */
  .vitrine{padding-inline:var(--marge);padding-top:var(--e5)}
  .vitrine__in>*{margin-inline:0}
  /* même spécificité que les règles d'ordre du téléphone, sinon elles gagnent et la gamme passe au-dessus du titre */
  .vitrine__in>.sur-titre,.vitrine__in>h1,.vitrine__in>.lead,.vitrine__in>.vitrine__actions{order:0}
  .vitrine__in>.lead{margin-top:var(--e3)}
  .vitrine__in>.vitrine__actions{margin-bottom:0}
  .vitrine__gamme{order:1;--H:min(23.5vw,21.5rem,42svh);--ecart:clamp(.2rem,1.3vw,1.7rem);
    margin-top:var(--e4);padding:0;border-bottom:0}
}

/* ==========================================================================
   « Toutes les peaux » : deux visages de part et d'autre d'une phrase, juste sous
   la vitrine (retour Rayan du 17/09). Portraits d'illustration, cadrés sous les yeux.
   Au téléphone : les deux visages côte à côte, puis le texte.
   ========================================================================== */
.visages{display:grid;grid-template-columns:1fr 1fr;background:var(--ivoire)}
.visages__vue{margin:0;aspect-ratio:4/5;overflow:hidden;background:var(--sable)}
.visages__vue img{width:100%;height:100%;object-fit:cover}
.visages__texte{grid-column:1/-1;padding:var(--e6) var(--gouttiere) var(--section)}
.visages__texte .lead{max-width:40ch}
.visages__mention{margin-top:var(--e5);font-size:var(--t-mini);color:var(--encre-douce)}
@media (min-width:900px){
  .visages{grid-template-columns:minmax(0,1fr) minmax(0,1.15fr) minmax(0,1fr);align-items:stretch}
  .visages__vue{aspect-ratio:auto;min-height:min(86svh,46rem)}
  .visages__vue--a{grid-column:1;grid-row:1}
  .visages__vue--b{grid-column:3;grid-row:1}
  .visages__texte{grid-column:2;grid-row:1;align-self:center;padding:var(--e6) clamp(2rem,4.5vw,5rem)}
}

/* ==========================================================================
   MOMENT pleine largeur
   -----------------------------------------------------------------------
   La photo d'un côté, le panneau de couleur de l'autre : côte à côte au
   BUREAU, l'une au-dessus de l'autre au TÉLÉPHONE (voir la note du 17/09
   plus bas, qui remplace le texte posé sur la photo de la V4).

   Le seul panneau clair est le bleu : quatre règles y remettent les boutons
   à l'endroit. Mesuré : l'ivoire sur ce bleu ne donne que 2,96:1, l'encre
   donne 6,0:1.
   ========================================================================== */
.moment{position:relative;overflow:hidden;isolation:isolate;
  background:var(--encre-nuit);color:var(--ivoire)}
.moment--bleu{background:var(--bleu)}
.moment--carmin{background:var(--carmin)}
.moment--encre{background:var(--encre)}
/* Téléphone (17/09) : le texte d'abord, sur le panneau de couleur, puis la photo ENTIÈRE à
   son format 4/5. Avant, le texte se posait sur la photo sous une ombre à 78 % : dès qu'il
   dépassait la moitié du bloc, le produit disparaissait dessous (mesuré sur PORCELAINE :
   230 px de bleu vide, pot invisible). Les photos de produit gardent leur vide EN HAUT
   (le pot PORCELAINE occupe le bas du cadre) : c'est là que le panneau se raccorde, par un
   fondu du bleu de marque sur le haut de la photo, loin du produit. Le texte reste ainsi
   « sur » le bleu de la photo, et le pot n'est ni noyé ni rogné. Une seule règle de couleur
   de texte, à toutes les largeurs : celle du panneau. */
.moment__grille{display:grid}
.moment__media{position:relative;overflow:hidden;aspect-ratio:4/5;order:2}
.moment__media img{width:100%;height:100%;object-fit:cover}
.moment--bleu .moment__media::before{content:"";position:absolute;inset:0 0 auto;height:26%;z-index:1;
  pointer-events:none;background:linear-gradient(to bottom,var(--bleu),rgb(30 162 204 / 0))}
.moment__texte{position:relative;z-index:2;order:1;
  padding:var(--e6) var(--gouttiere) var(--e6)}
.moment h2{font-size:var(--t-h2);margin-top:var(--e3);font-variation-settings:'opsz' 30}
.moment p{margin-top:var(--e4);max-width:44ch;font-size:var(--t-lead);line-height:1.5;
  color:rgba(255,255,255,.92)}
.moment .sur-titre{color:var(--or-clair)}
/* le panneau bleu est le seul fond clair : il reprend l'encre */
.moment--bleu{color:var(--encre)}
.moment--bleu p{color:var(--encre)}
.moment--bleu .sur-titre{color:var(--encre)}
.moment--bleu .btn--clair{background:var(--encre);color:var(--ivoire)}
.moment--bleu .btn--clair:hover{background:var(--bleu-nuit);color:var(--ivoire)}
.moment--bleu .btn--fil-clair{color:var(--encre);border-color:var(--filet-encre)}
.moment--bleu .btn--fil-clair:hover{background:var(--encre);color:var(--blanc);border-color:var(--encre)}
.moment--bleu .lien-fleche{border-color:var(--filet-encre)}
.moment__actions{display:flex;flex-wrap:wrap;align-items:center;gap:var(--e3);margin-top:var(--e5)}
/* Les deux choix du diagnostic ont la même largeur, côte à côte ou empilés. */
.moment__actions--choix .btn{flex:1 1 14rem;max-width:24rem}
.moment__prix{font-family:var(--f-titre);font-size:1.7rem;font-weight:var(--g-titre);
  font-variation-settings:'opsz' 20}
/* Tablette debout : une photo 4/5 de 768 px de large ferait 960 px de haut, plus que
   l'écran. On la borne, et PORCELAINE garde le bas de son cadre, là où est le pot. */
@media (min-width:600px) and (max-width:899.98px){
  .moment__media{aspect-ratio:auto;height:min(70svh,40rem)}
  .moment--bleu .moment__media img{object-position:50% 100%}
}
@media (min-width:900px){
  .moment__grille{grid-template-columns:1fr 1fr;min-height:min(82svh,820px)}
  /* Le 4/5 donne sa hauteur à la rangée ; `stretch` fait suivre la photo si le texte est
     plus haut qu'elle, pour qu'aucune bande de fond n'apparaisse sous la photo. */
  .moment__media{grid-area:1/2;align-self:stretch}
  .moment--gauche .moment__media{grid-area:1/1}
  .moment--bleu .moment__media::before{display:none}   /* au bureau le raccord est latéral : le bleu est relevé sur ce bord */
  .moment__texte{grid-area:1/1;align-self:center;
    display:flex;flex-direction:column;justify-content:center;
    padding:var(--section) clamp(2rem,4.5vw,5rem)}
  .moment--gauche .moment__texte{grid-area:1/2}
}

/* ==========================================================================
   Triptyque éditorial
   ========================================================================== */
.tript{display:grid;gap:var(--e6) var(--e5)}
@media (min-width:880px){
  .tript{grid-template-columns:repeat(12,1fr);align-items:start}
  .tript__i:nth-child(1){grid-column:1/5}
  .tript__i:nth-child(2){grid-column:6/10;margin-top:var(--e6)}
  .tript__i:nth-child(3){grid-column:10/13;margin-top:calc(var(--e6) * -.45)}
}
.tript__i figure{margin:0}
.tript__i img{width:100%;aspect-ratio:4/5;object-fit:cover}
.tript__i figcaption{margin-top:var(--e3)}
.tript__i h3{font-size:var(--t-h3);margin-bottom:.45rem}
.tript__i p{font-size:var(--t-petit);color:var(--encre-douce)}
.tript__i .lien-fleche{margin-top:var(--e4)}

/* ---------- bandes de fond ---------- */
.sable{background:var(--sable);
  background-image:radial-gradient(120% 90% at 10% 0%,rgba(255,255,255,.7) 0%,rgba(255,255,255,0) 60%)}
.encre{background:var(--encre);color:var(--blanc)}
.encre .lead,.encre p{color:rgba(255,255,255,.84)}
.encre .sur-titre{color:var(--or-clair)}

/* ==========================================================================
   R6 : la bande de conditions remplace les 3 cases de réassurance.
   Une phrase éditoriale, puis trois lignes à filets. Aucune icône en rangée.
   ========================================================================== */
.conditions{border-block:1px solid var(--filet)}
.conditions__in{display:grid;gap:var(--e5);padding-block:var(--e6)}
.conditions__mot{font-family:var(--f-titre);font-weight:var(--g-titre);
  font-size:clamp(1.7rem,1.15rem + 2.2vw,2.8rem);line-height:1.16;max-width:16ch;
  font-variation-settings:'opsz' 30}
.conditions dl{display:grid;gap:0;margin:0}
/* `dl>div`, jamais `.conditions div` : ce sélecteur-là attrapait aussi le conteneur
   `.conditions__in` et lui imposait 16 px de marge et une colonne de titre de 240 px
   (mesuré le 17/09 : titre sur cinq lignes, collé à 19 px du bloc précédent). */
.conditions dl>div{display:grid;gap:.2rem var(--e4);padding-block:var(--e3);
  border-top:1px solid var(--filet)}
.conditions dl>div:last-child{border-bottom:1px solid var(--filet)}
.conditions dt{font-weight:var(--g-fort)}
.conditions dd{margin:0;color:var(--encre-douce);font-size:var(--t-petit)}
@media (min-width:820px){
  .conditions__in{grid-template-columns:minmax(0,.85fr) minmax(0,1.15fr);
    gap:var(--e6);align-items:start}
  .conditions dl>div{grid-template-columns:minmax(0,15rem) minmax(0,1fr);align-items:baseline}
}

/* ---------- avis ---------- */
.avis figure{margin:0}
.avis blockquote{margin:0;font-family:var(--f-titre);font-weight:var(--g-titre);
  font-size:clamp(1.65rem,1.1rem + 2.2vw,2.9rem);line-height:1.2;max-width:20ch;
  font-variation-settings:'opsz' 34;margin-top:var(--e4)}
.avis figcaption{margin-top:var(--e4);font-size:var(--t-petit);color:var(--encre-douce)}
.avis__grille{display:grid;gap:var(--e5)}
@media (min-width:880px){.avis__grille{grid-template-columns:1.3fr .7fr;align-items:end;gap:var(--e6)}}

/* ==========================================================================
   R6 + R9 : la section revendeuse, en éditorial qui respire.
   Deux colonnes de texte, une liste numérotée à filets, une photo qui porte.
   ========================================================================== */
.rev{position:relative}
.rev__grille{display:grid;gap:var(--e6)}
.rev__media img{width:100%;aspect-ratio:4/5;object-fit:cover}
.rev__col2{column-gap:var(--e6)}
@media (min-width:900px){
  .rev__grille{grid-template-columns:.82fr 1.18fr;gap:var(--e6);align-items:start}
  .rev__col2{column-count:2}
  /* La photo accompagne la lecture : le texte est presque deux fois plus haut qu'elle
     (641 contre 1 116 px mesurés), elle laissait 475 px de fond vide sous elle. */
  .rev__grille .rev__media{position:sticky;top:calc(var(--entete-h) + var(--e4))}   /* deux classes : `.masque`, plus bas, repose `relative` */
}
.rev__col2 p+p{margin-top:var(--e3)}
.etapes{counter-reset:e;display:grid;margin-top:var(--e6)}
.etapes li{counter-increment:e;display:grid;gap:.15rem var(--e4);
  padding-block:var(--e4);border-top:1px solid var(--filet-clair)}
.etapes li:last-child{border-bottom:1px solid var(--filet-clair)}
.etapes li::before{content:counter(e,decimal-leading-zero);font-family:var(--f-titre);
  font-weight:var(--g-titre);color:var(--or-clair);font-size:1.5rem;line-height:1.1;
  font-variation-settings:'opsz' 20}
.etapes b{font-size:var(--t-h4);font-family:var(--f-titre);font-weight:var(--g-titre);
  font-variation-settings:'opsz' 20}
.etapes p{color:rgba(255,255,255,.82);font-size:var(--t-petit);max-width:46ch}
@media (min-width:620px){
  .etapes li{grid-template-columns:3.5rem minmax(0,1fr);align-items:baseline}
  .etapes li::before{grid-row:span 2}
}

/* ==========================================================================
   Fiche produit
   ========================================================================== */
.fil{padding-top:var(--e5);font-size:var(--t-petit);color:var(--encre-douce)}
.fil a{text-decoration:none}
.fil a:hover{text-decoration:underline;text-underline-offset:.25em}

/* ==========================================================================
   LA FICHE PRODUIT (refonte du 17/09)
   -----------------------------------------------------------------------
   L'ordre du DOM est celui du TÉLÉPHONE : la vue, ce qu'on achète, les
   autres vues, le texte. Au bureau, `.fiche__media` se reconstitue en
   colonne collante à gauche. Une seule source, deux mises en page.

   Références regardées avant d'écrire (Typology, Topicals, Merit) : une
   seule vue en tête, l'achat tout de suite, le prix DANS le bouton.
   ========================================================================== */
.fiche{display:grid;gap:var(--e5)}
/* Au téléphone, tout ce qui sépare la photo du bouton retarde l'achat d'autant :
   les écarts du haut sont donc resserrés, et seulement là. Mesuré le 17/09 :
   sans ça, le bouton d'un sérum finissait à 1 036 px sur un écran de 844. */
@media (max-width:619px){
  .fiche{gap:var(--e4)}
  .fiche__essentiel h1{margin-top:var(--e1)}
  .fiche__essentiel .lead{font-size:var(--t-petit);margin-top:var(--e2)}
  .fiche__essentiel .pct{margin-top:var(--e3)}
  .fiche__ligne{margin-top:var(--e1)}
}
/* min-width:0 : sans ça, une ligne insécable de la composition impose sa
   largeur minimale à toute la colonne et fait déborder la page à 320 px */
.fiche>*{min-width:0}
/* `display:contents` : au téléphone les trois morceaux du média remontent dans
   la grille de la fiche, pour que l'essentiel puisse se glisser entre la vue
   et les vignettes sans être écrit deux fois. */
.fiche__media{display:contents}
.fiche__vue{order:1}
.fiche__essentiel{order:2}
.fiche__vignettes{order:3}
.fiche__note--media{order:4}
.fiche__texte{order:5}

.fiche__vue{background:var(--ivoire-clair);overflow:hidden;position:relative}
/* Au téléphone la photo est BORNÉE EN HAUTEUR, pas en proportion : une photo
   carrée sur un écran de 390 px fait 390 px de haut, et avec la bande de
   service, l'entête et le fil d'Ariane, le bouton d'achat retombait sous la
   ligne de flottaison — le défaut même qu'on corrige. 38 svh laisse la place
   au titre, au résumé, à la preuve et au bouton dans le premier écran. */
.fiche__vue img{width:100%;height:auto;aspect-ratio:1;object-fit:cover} /* 25/09 : la photo entière, la barre d'achat collante garde le prix à l'écran */
@media (min-width:620px){.fiche__vue img{height:auto;max-height:none;aspect-ratio:4/5}}
/* Le fil d'Ariane d'une fiche se fait discret : au téléphone il coûtait 60 px
   au-dessus de la photo, pour une information que le menu porte déjà. */
@media (max-width:619px){
  .fiche-produit>.page:first-child{font-size:var(--t-mini)}
  .fiche-produit>.page:first-child .fil{margin-block:var(--e2)}
}

/* Les autres vues : une bande qui glisse au doigt, pas une grille de carrés. */
.fiche__vignettes{display:flex;gap:var(--e2);overflow-x:auto;scroll-snap-type:x mandatory;
  scrollbar-width:none;margin-top:calc(var(--e5) * -1 + var(--e2))}
.fiche__vignettes::-webkit-scrollbar{display:none}
.vignette{flex:0 0 5.25rem;scroll-snap-align:start;padding:0;border:1px solid transparent;
  background:var(--ivoire-clair);cursor:pointer;overflow:hidden;
  transition:border-color var(--duree-court)}
.vignette img{width:100%;aspect-ratio:1;object-fit:cover}
.vignette[aria-current="true"]{border-color:var(--encre)}

.fiche h1{font-size:clamp(2.1rem,1.5rem + 2.4vw,3.2rem);margin-top:var(--e2);line-height:1.06}
/* Le type et la contenance, la ligne que Typology pose sous son titre. */
.fiche__ligne{margin-top:var(--e2);color:var(--encre-douce);font-size:var(--t-petit)}
.fiche__essentiel .lead{max-width:46ch}
.pct{display:inline-flex;align-items:center;gap:.5em;font-size:var(--t-petit);
  font-weight:var(--g-fort);border:1px solid var(--filet-fort);padding:.35rem .75rem}
.pct i{width:7px;height:7px;background:var(--or);border-radius:50%;display:block;flex:none}

.fiche__achat{display:grid;gap:var(--e2);margin-top:var(--e4)}
.fiche__prix-seul{font-size:1.6rem;font-weight:var(--g-fort)}
.fiche__note{margin-top:var(--e3);font-size:var(--t-petit);color:var(--encre-douce)}
.fiche__note--media{margin-top:var(--e2)}

/* Le prix DANS le bouton, séparé du libellé par un filet. C'est la seule place
   du prix sur la fiche (Typology, Topicals et Merit font pareil) : plus
   d'aller-retour de l'œil entre un prix posé en haut et un bouton plus bas. */
/* Les pseudo-éléments « clearfix » de WooCommerce (::before et ::after du
   formulaire) devenaient des cellules fantômes dans la rangée flexible : chacun
   coûtait un écart de 10 px, décalait la quantité, raccourcissait le bouton et
   le faisait passer à la ligne (mesuré le 22/09, au bureau comme au téléphone). */
/* sélecteur renforcé : WooCommerce les déclare en `.woocommerce div.product form.cart::before`,
   plus spécifique qu'un simple `.fiche__achat form.cart::before`, qui perdait (mesuré le 22/09) */
.fiche-produit .fiche__achat form.cart.cart::before,
.fiche-produit .fiche__achat form.cart.cart::after{content:none;display:none}
.fiche__achat form.cart{flex-wrap:nowrap}
.fiche__achat form.cart .quantity{flex:0 0 auto}
.fiche__achat form.cart .quantity input.qty{width:4rem}
/* Le libellé et le prix restent GROUPÉS au centre, séparés par un filet : sur
   un bouton de 535 px au bureau, un libellé collé à gauche et un prix collé à
   droite se lisaient comme deux choses (regardé le 22/09). */
.fiche__achat form.cart .single_add_to_cart_button.button{flex:1 1 auto;min-width:0;
  justify-content:center;gap:var(--e3);padding-inline:var(--e4)}
@media (max-width:419px){.btn__t-long{display:none}}
.fiche__achat .btn__prix{padding-left:var(--e4);border-left:1px solid rgba(255,255,255,.28);
  white-space:nowrap;font-variant-numeric:tabular-nums}

@media (min-width:980px){
  /* Au bureau : le média à gauche, collant ; l'essentiel puis le texte à droite. */
  .fiche{grid-template-columns:1.02fr .98fr;gap:var(--e6);align-items:start;
    grid-template-areas:"media essentiel" "media texte"}
  .fiche__media{display:grid;grid-area:media;gap:var(--e2);
    grid-template-columns:4.75rem minmax(0,1fr);align-items:start;
    position:sticky;top:calc(var(--entete-h) + var(--e3))}
  .fiche__essentiel{grid-area:essentiel}
  .fiche__texte{grid-area:texte}
  /* l'ordre du téléphone ne doit pas survivre ici : il remonterait les vignettes */
  .fiche__vue,.fiche__vignettes,.fiche__note--media{order:0}
  .fiche__vue{grid-area:1/2}
  .fiche__vue img{max-height:calc(100svh - var(--entete-h) - 9rem)}
  /* la bande redevient une colonne verticale à gauche de la vue */
  .fiche__vignettes{grid-area:1/1;flex-direction:column;overflow:visible;margin-top:0}
  .vignette{flex:0 0 auto}
  .fiche__note--media{grid-area:2/1/3/-1}
  /* une seule photo : pas de bande, la vue prend toute la largeur */
  .fiche__vue:only-child,.fiche__vue:first-child:nth-last-child(2){grid-column:1/-1}
}

/* ==========================================================================
   LA BARRE D'ACHAT COLLANTE (téléphone) : acheter sans remonter
   -----------------------------------------------------------------------
   Elle n'existe qu'au téléphone, et ne se montre QUE lorsque le bouton
   principal est sorti de l'écran (classe posée par app.js). `hidden` tant que
   le script n'a pas tourné : une barre fixe qui s'affiche sans pouvoir se
   cacher masquerait le bas de la page pour rien.
   Le lien dedans est un VRAI lien d'ajout au panier : il marche sans script.
   ========================================================================== */
.barre-achat{display:none}
@media (max-width:979px){
  .js .barre-achat{display:flex;align-items:center;justify-content:space-between;gap:var(--e3);
    position:fixed;left:0;right:0;bottom:0;z-index:70;
    padding:var(--e3) var(--gouttiere) calc(var(--e3) + env(safe-area-inset-bottom));
    background:var(--ivoire-clair);border-top:1px solid var(--filet);
    box-shadow:0 -8px 28px rgba(12,18,22,.10);
    transform:translateY(105%);transition:transform var(--duree-court) var(--courbe);
    /* invisible tant qu'elle est sortie : sinon elle happe les clics du bas de page */
    visibility:hidden}
  .js .barre-achat.est-vue{transform:translateY(0);visibility:visible}
  .barre-achat__quoi{display:grid;gap:.1rem;min-width:0}
  .barre-achat__nom{font-weight:var(--g-fort);font-size:var(--t-petit);
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .barre-achat__prix{font-size:var(--t-mini);color:var(--encre-douce);font-variant-numeric:tabular-nums}
  .barre-achat .btn{flex:0 0 auto}
  /* la bulle WhatsApp se range au-dessus de la barre, elles se superposaient */
  .barre-achat.est-vue ~ .bulle-wa,
  body:has(.barre-achat.est-vue) .bulle-wa{bottom:calc(5.5rem + env(safe-area-inset-bottom))}
}

.bloc{margin-top:var(--e6);padding-top:var(--e4);border-top:1px solid var(--filet)}
.bloc h2{font-size:var(--t-h3);margin-bottom:var(--e4);font-variation-settings:'opsz' 24}
.bloc p+p{margin-top:var(--e3)}

.ingr li{display:grid;grid-template-columns:auto minmax(0,1fr);align-items:baseline;gap:.75em;
  padding:.85rem 0;border-bottom:1px solid var(--filet);color:var(--encre-douce);line-height:1.55}
/* Le dernier actif ne referme pas la liste : le bloc suivant ouvre déjà par un trait, et les deux
   se retrouvaient à 42 px l'un de l'autre, deux lignes parallèles pour une seule séparation
   (mesuré le 17/09 sur PORCELAINE et GLASS SKIN, vu à la capture). */
.ingr li:last-child{border-bottom:0}
.ingr b{font-weight:var(--g-titre);color:var(--encre);font-family:var(--f-titre);
  font-size:var(--t-h4);font-variation-settings:'opsz' 20}
.ingr li::before{content:"";width:6px;height:6px;background:var(--or);border-radius:50%;
  margin-top:.6rem;align-self:start}
.ingr__t{display:block}

.usage{display:grid;gap:var(--e4)}
@media (min-width:620px){.usage{grid-template-columns:repeat(3,1fr)}}
.usage b{display:block;font-size:var(--t-petit);color:var(--or);
  margin-bottom:.35rem;font-weight:var(--g-fort)}
.usage p{color:var(--encre-douce);font-size:var(--t-petit)}

.franchise{border-left:3px solid var(--or);padding:var(--e2) 0 var(--e2) var(--e4);
  margin-top:var(--e5);color:var(--encre-douce);max-width:56ch}

.faq details{border-bottom:1px solid var(--filet)}
.faq summary{cursor:pointer;list-style:none;padding:var(--e4) 0;font-weight:var(--g-fort);
  display:flex;justify-content:space-between;gap:var(--e3);align-items:center}
.faq summary::-webkit-details-marker{display:none}
.faq summary::after{content:"+";font-family:var(--f-titre);font-size:1.5rem;line-height:1;
  color:var(--or);transition:transform var(--duree-court) var(--courbe);flex:none}
.faq details[open] summary::after{transform:rotate(45deg)}
.faq p{padding-bottom:var(--e4);color:var(--encre-douce);max-width:62ch}

.compo{display:grid;gap:var(--e2)}
.compo li{display:flex;align-items:baseline;justify-content:space-between;gap:var(--e3);
  padding-block:var(--e3);border-top:1px solid var(--filet)}
.compo li:last-child{border-bottom:1px solid var(--filet)}
.compo a{font-family:var(--f-titre);font-size:var(--t-h4);font-weight:var(--g-titre);
  text-decoration:none;font-variation-settings:'opsz' 20}
.compo a:hover{text-decoration:underline;text-underline-offset:.2em}
.compo span{color:var(--encre-douce);font-size:var(--t-petit);text-align:right}

/* ==========================================================================
   Diagnostic
   ========================================================================== */
.diag{max-width:44rem}
.diag__etape{border-top:1px solid var(--filet);padding-top:var(--e5);margin-top:var(--e5)}
.diag__etape:first-child{border-top:0;padding-top:0;margin-top:0}
.diag__etape[hidden]{display:none!important}
/* Avant que le script ne prenne la main, seule la première question est
   à l'écran : sinon le repli se voit comme un décalage de 0,10 de CLS.
   Sans JavaScript, la classe .js n'existe pas et tout reste visible. */
.js #diag-form:not(.diag--pilote) .diag__etape + .diag__etape{display:none}
.diag legend{padding:0;font-family:var(--f-titre);font-weight:var(--g-titre);
  font-size:var(--t-h3);line-height:1.15;font-variation-settings:'opsz' 24}
.diag fieldset{border:0;padding:0;margin:0}
.diag__pas{font-size:var(--t-petit);color:var(--encre-douce);margin-bottom:var(--e2)}
.choix{display:grid;gap:var(--e2);margin-top:var(--e4)}
.choix label{display:flex;align-items:center;gap:var(--e3);min-height:56px;
  padding:var(--e3) var(--e4);border:1px solid var(--filet);cursor:pointer;
  transition:border-color var(--duree-court),background var(--duree-court)}
.choix label:hover{border-color:var(--encre)}
.choix input{width:20px;height:20px;flex:none;accent-color:var(--bleu-nuit);margin:0}
.choix input:checked+span{font-weight:var(--g-fort)}
.choix label:has(input:checked){border-color:var(--encre);background:var(--ivoire-clair)}
.diag__barre{display:flex;flex-wrap:wrap;gap:var(--e3);align-items:center;margin-top:var(--e5)}
.diag__retour{background:none;border:0;padding:.4rem 0;cursor:pointer;
  color:var(--encre-douce);text-decoration:underline;text-underline-offset:.25em;
  font-size:var(--t-petit)}

.reponse{margin-top:var(--e6);padding-top:var(--e5);border-top:2px solid var(--encre)}
.reponse[hidden]{display:none!important}
.reponse__t{font-size:var(--t-h2);font-family:var(--f-titre);font-weight:var(--g-titre);
  line-height:1.1;margin-bottom:var(--e2);font-variation-settings:'opsz' 30}
.reco{display:grid;gap:var(--e5);margin-top:var(--e5)}
.reco__i{display:grid;gap:var(--e4);padding-top:var(--e5);border-top:1px solid var(--filet)}
.reco__i:first-child{border-top:0;padding-top:0}
.reco__i img{width:100%;aspect-ratio:1;object-fit:cover;background:var(--ivoire-clair)}
.reco__rang{font-size:var(--t-petit);color:var(--or);font-weight:var(--g-fort)}
.reco__i h3{font-size:var(--t-h3);margin-top:var(--e2)}
.reco__i p{color:var(--encre-douce);margin-top:var(--e3);max-width:52ch}
.reco__bas{display:flex;flex-wrap:wrap;align-items:center;gap:var(--e3);margin-top:var(--e4)}
@media (min-width:440px){
  .reco__i{grid-template-columns:minmax(0,9.5rem) minmax(0,1fr);align-items:start;gap:var(--e4)}
}
@media (min-width:820px){
  .reco__i{grid-template-columns:minmax(0,13rem) minmax(0,1fr);gap:var(--e5)}
}
.secours{margin-top:var(--e6);padding-top:var(--e4);border-top:1px solid var(--filet);
  display:flex;flex-wrap:wrap;align-items:center;gap:var(--e3) var(--e4)}
.secours p{color:var(--encre-douce);max-width:38ch}

.table-corr{margin-top:var(--e6)}
.table-corr h2{font-size:var(--t-h3);margin-bottom:var(--e4)}
.table-corr li{display:grid;gap:.2rem var(--e4);padding-block:var(--e3);
  border-top:1px solid var(--filet)}
.table-corr li:last-child{border-bottom:1px solid var(--filet)}
.table-corr b{font-weight:var(--g-fort)}
.table-corr span{color:var(--encre-douce);font-size:var(--t-petit)}
@media (min-width:720px){
  .table-corr li{grid-template-columns:minmax(0,22rem) minmax(0,1fr);align-items:baseline}
}

/* ==========================================================================
   Pages de contenu : prose éditoriale, jamais en boîte
   ========================================================================== */
.prose{max-width:var(--texte-large)}
.prose>*+*{margin-top:var(--e4)}
.prose h2{font-size:var(--t-h3);margin-top:var(--e6);font-variation-settings:'opsz' 24}
.prose h2:first-child{margin-top:0}
.prose p{color:var(--encre-douce)}
.prose p.intro{font-size:var(--t-lead);color:var(--encre);line-height:1.5;max-width:44ch}
.prose ul{display:grid;gap:0}
.prose ul li{padding-block:var(--e3);border-top:1px solid var(--filet);color:var(--encre-douce)}
.prose ul li:last-child{border-bottom:1px solid var(--filet)}
.prose a:not(.btn){color:var(--bleu-nuit);text-underline-offset:.2em}

.deux-col{display:grid;gap:var(--e6)}
@media (min-width:900px){
  .deux-col{grid-template-columns:minmax(0,.9fr) minmax(0,1.1fr);gap:var(--e6);align-items:start}
  .deux-col--inv{grid-template-columns:minmax(0,1.1fr) minmax(0,.9fr)}
}
.deux-col img{width:100%;object-fit:cover}
.figure-large{position:relative;overflow:hidden}
.figure-large img{width:100%;aspect-ratio:16/10;object-fit:cover}
.figure-large figcaption{margin-top:var(--e3);font-size:var(--t-petit);color:var(--encre-douce)}

.coord{display:grid;gap:0;margin-top:var(--e5)}
.coord div{display:grid;gap:.2rem var(--e4);padding-block:var(--e4);border-top:1px solid var(--filet)}
.coord div:last-child{border-bottom:1px solid var(--filet)}
.coord dt{font-size:var(--t-petit);color:var(--or);font-weight:var(--g-fort)}
.coord dd{margin:0;font-size:var(--t-h4);font-family:var(--f-titre);font-weight:var(--g-titre);
  font-variation-settings:'opsz' 20}
.coord dd a{text-decoration:none}
.coord dd a:hover{text-decoration:underline;text-underline-offset:.2em}
.coord dd small{display:block;font-family:var(--f-texte);font-size:var(--t-petit);
  font-weight:var(--g-corps);color:var(--encre-douce);margin-top:.25rem}
@media (min-width:720px){
  .coord div{grid-template-columns:minmax(0,12rem) minmax(0,1fr);align-items:baseline}
}

/* ==========================================================================
   LA PRISE DE CONTACT (page Contact, retour Rayan 11/09)
   Sur le modèle de la page Contact de L'Art des Sens : une question à la
   fois, le message s'écrit tout seul et part sur WhatsApp. Elle reprend les
   pièces du diagnostic (légende, cases, compteur, retour) : un seul système
   visuel d'un outil à l'autre.
   ========================================================================== */
#ecrire{scroll-margin-top:calc(var(--entete-h) + var(--e3))}
.ecrire{max-width:44rem}
.ecrire__via{display:flex;align-items:flex-start;gap:var(--e3);
  margin-bottom:var(--e5);padding:var(--e3) var(--e4);
  background:var(--ivoire-clair);border:1px solid var(--filet);
  font-size:var(--t-petit);line-height:1.5}
.ecrire__via svg{width:22px;height:22px;flex:none;margin-top:.1rem;color:var(--bleu-nuit)}
/* Sans JavaScript, ni questions ni bandeau : un lien WhatsApp direct. */
html:not(.js) .ecrire__via,html:not(.js) .ecrire__form{display:none}
.js .ecrire__repli{display:none}
.ecrire__repli{display:grid;gap:var(--e4);justify-items:start;color:var(--encre-douce)}
.ecrire__etape{border:0;padding:0;margin:0;min-width:0}
/* une classe qui pose un display écraserait [hidden] : on le redit (leçon 19/08) */
.ecrire__etape[hidden],.ecrire [data-si][hidden],.champ__fac[hidden]{display:none!important}
.ecrire__etape:focus{outline:none}
.ecrire legend,.ecrire__titre{padding:0;font-family:var(--f-titre);font-weight:var(--g-titre);
  font-size:var(--t-h3);line-height:1.15;font-variation-settings:'opsz' 24}
.choix label>span small{display:block;margin-top:.15rem;font-size:var(--t-petit);
  font-weight:var(--g-corps);color:var(--encre-douce);line-height:1.4}
.choix input:checked+span small{font-weight:var(--g-corps)}
.ecrire__astuce{margin-top:var(--e4);padding-left:var(--e4);border-left:3px solid var(--or);
  font-size:var(--t-petit);color:var(--encre-douce);max-width:52ch}
.ecrire__astuce a{color:var(--bleu-nuit);font-weight:var(--g-fort);text-underline-offset:.2em}
.ecrire__champs{display:grid;gap:var(--e4);margin-top:var(--e4)}
@media (min-width:560px){.ecrire__champs{grid-template-columns:1fr 1fr}}
.champ{display:grid;gap:.4rem;margin-top:var(--e4)}
.ecrire__champs .champ{margin-top:0}
.champ label{font-size:var(--t-petit);font-weight:var(--g-fort)}
.champ__fac{font-weight:var(--g-corps);color:var(--encre-douce)}
.champ input,.champ textarea{width:100%;min-height:54px;padding:.8rem 1rem;
  background:var(--ivoire-clair);color:var(--encre);border:1px solid var(--filet-fort);
  border-radius:var(--r-0);font:inherit;font-size:var(--t-corps);
  transition:border-color var(--duree-court),box-shadow var(--duree-court)}
.champ textarea{min-height:7.5rem;resize:vertical;line-height:1.5}
.champ input:focus,.champ textarea:focus{outline:none;border-color:var(--encre);
  box-shadow:0 0 0 3px rgba(1,81,110,.18)}
.ecrire__voir{margin-top:var(--e5)}
.ecrire__voir:disabled{opacity:.38;cursor:not-allowed}
.ecrire__voir:disabled:hover{background:var(--encre)}
.ecrire__apercu{margin-top:var(--e4);padding:var(--e4);white-space:pre-line;
  background:var(--ivoire-clair);border-left:3px solid var(--bleu);
  font-size:var(--t-petit);line-height:1.6;color:var(--encre);overflow-wrap:anywhere}
.ecrire [data-envoyer]{margin-top:var(--e5)}
.ecrire__note{margin-top:var(--e3);font-size:var(--t-petit);color:var(--encre-douce)}
.ecrire [data-retour]{margin-top:var(--e4)}

/* ==========================================================================
   LA BULLE WHATSAPP (retour Rayan 11/09, modèle L'Art des Sens)
   Elle mène à la prise de contact, jamais directement à WhatsApp. Absente du
   tunnel et de la page Contact (yona_bulle_visible()). Encre cerclée d'un
   filet clair : elle reste visible sur les quatre fonds du site (ivoire,
   bleu, carmin, encre). Sous l'entête (z-index 60) : le menu ouvert au
   téléphone passe par-dessus elle, jamais l'inverse.
   ========================================================================== */
.bulle-wa{position:fixed;z-index:55;
  right:max(16px,env(safe-area-inset-right));bottom:max(16px,env(safe-area-inset-bottom));
  display:flex;align-items:center;justify-content:center;
  min-width:56px;height:56px;padding:0 16px;border-radius:999px;
  background:var(--encre);color:var(--ivoire);text-decoration:none;
  box-shadow:0 0 0 1px rgba(255,255,255,.32),0 12px 30px rgba(12,18,22,.30);
  transition:background var(--duree-court) var(--courbe),opacity var(--duree-court) var(--courbe),
    visibility var(--duree-court),bottom var(--duree-court) var(--courbe)}
.bulle-wa:hover{background:var(--bleu-nuit)}
@media (max-width:979px){
  /* Sur une fiche, tant que le bouton d'achat principal est à l'écran, la bulle
     s'efface : elle chevauchait son coin droit (mesuré le 22/09), et
     « Commander sur WhatsApp » est juste en dessous. Elle revient dès qu'on
     défile (classe posée par app.js). */
  body.achat-en-vue .bulle-wa{opacity:0;visibility:hidden}
}
.bulle-wa svg{width:24px;height:24px;flex:none}
.bulle-wa__mot{max-width:0;overflow:hidden;white-space:nowrap;opacity:0;
  font-size:var(--t-petit);font-weight:var(--g-fort);
  transition:max-width var(--duree-court) var(--courbe),opacity var(--duree-court),margin var(--duree-court)}
@media (hover:hover) and (pointer:fine){
  .bulle-wa:hover .bulle-wa__mot,.bulle-wa:focus-visible .bulle-wa__mot{max-width:16rem;opacity:1;margin-left:.6rem}
}
@media (prefers-reduced-motion:no-preference){
  .bulle-wa{animation:bulle-flotte 5s ease-in-out infinite}
}
@keyframes bulle-flotte{0%,100%{translate:0 -3px}50%{translate:0 3px}}
/* la dernière ligne du pied de page ne passe jamais sous la bulle */
.a-bulle .pied{padding-bottom:calc(var(--e5) + 72px)}

/* ==========================================================================
   R9 : la fin de page. Bande d'appel, puis un pied structuré et lisible.
   ========================================================================== */
.appel{background:var(--bleu);color:var(--encre);text-align:left}
.appel__in{display:grid;gap:var(--e5);padding-block:var(--e6)}
.appel h2{font-size:var(--t-h2);max-width:18ch;font-variation-settings:'opsz' 30}
.appel p{max-width:40ch;font-size:var(--t-lead);line-height:1.5}
.appel__actions{display:flex;flex-wrap:wrap;gap:var(--e2);align-self:end}
.appel .btn--fil{border-color:var(--filet-encre);color:var(--encre)}
.appel .btn--fil:hover{background:var(--encre);color:var(--blanc)}
@media (min-width:900px){
  .appel__in{grid-template-columns:1.1fr .9fr;align-items:end;gap:var(--e6)}
}

.pied{background:var(--encre-nuit);color:rgba(255,255,255,.78);
  padding-block:var(--e6) var(--e5);font-size:var(--t-petit)}
.pied a{text-decoration:none;color:rgba(255,255,255,.86)}
.pied a:hover{color:var(--blanc);text-decoration:underline;text-underline-offset:.25em}
.pied__grille{display:grid;gap:var(--e5)}
.pied h3{font-size:var(--t-petit);font-family:var(--f-texte);font-weight:var(--g-fort);
  color:var(--blanc);margin-bottom:var(--e3)}
.pied li+li{margin-top:.7rem}
.pied .marque{color:var(--blanc);margin-bottom:var(--e3)}
.pied__intro{max-width:34ch}
.pied__bas{margin-top:var(--e6);padding-top:var(--e4);border-top:1px solid rgba(255,255,255,.16);
  display:flex;flex-wrap:wrap;gap:var(--e3) var(--e5);justify-content:space-between;
  font-size:var(--t-mini);color:rgba(255,255,255,.68)}
@media (min-width:760px){.pied__grille{grid-template-columns:1.5fr 1fr 1fr 1.25fr;gap:var(--e5)}}

/* ==========================================================================
   Matière : la soie de la séance photo remplace l'ivoire uni du fond de page
   -----------------------------------------------------------------------
   Retour Rayan du 17/09, sur la tête de la page Packs : « remplace le blanc
   de la boutique par cette texture, elle donne de la matière au site ».
   Tout l'ivoire du site venait d'UNE ligne, le fond du `body` : une seule
   couche suffit donc, aucune section n'est touchée. Celles qui portent leur
   propre fond (bleu, sable, encre, photos) passent devant, comme avant.

   La texture est la vraie soie de la photo 42, zone sans produit, ramenée à
   l'ivoire par `_tools/soie_yona.py` : même clarté moyenne que `--ivoire`,
   et son pli le PLUS SOMBRE laisse encore 4,5:1 au texte secondaire et au
   doré des sur-titres (mesuré sur le fichier, pas estimé). 13 Ko par fichier.
   Dose : force 2 depuis le second retour de Rayan (« prononce la nuance un
   peu plus ») : tons moyens amplifiés, extrêmes tassés sous le plancher.
   `?v=` : le fichier garde son nom, le serveur n'envoie aucune durée de
   cache ; changer la texture sans changer ce numéro, c'est laisser
   l'ancienne dans les téléphones déjà passés.

   Couche FIXE, et non un motif répété : une soie qui se répète montre ses
   raccords, une soie fixe n'en a pas. `100lvh` et non `inset:0` : sur
   téléphone la barre d'adresse se replie au défilement, la hauteur visible
   change, et un fond en `cover` calé dessus zoomerait à chaque geste.
   `--ivoire` reste dessous : tant que l'image n'est pas arrivée, la page est
   exactement celle d'avant.
   ========================================================================== */
body::before{content:"";position:fixed;left:0;top:0;z-index:-1;width:100%;height:100vh;height:100lvh;
  pointer-events:none;background:var(--ivoire) url(img/soie-p.webp?v=2) center/cover no-repeat}
@media (min-aspect-ratio:1/1){
  body::before{background-image:url(img/soie-l.webp?v=2)}
}
@media print{body::before{display:none}}

/* ==========================================================================
   Matière : un grain fin unifie les photos venues de fonds différents
   ========================================================================== */
body::after{content:"";position:fixed;inset:0;z-index:1;pointer-events:none;opacity:.05;
  mix-blend-mode:multiply;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='2'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23g)'/%3E%3C/svg%3E");
  background-size:140px 140px}

/* ==========================================================================
   MOUVEMENT (R4)
   Tout est en transform / opacity : rien ne touche la mise en page,
   donc CLS reste à 0 et le thread principal reste libre.
   Sans JavaScript, la classe .js est absente : tout est visible.
   ========================================================================== */
.js [data-reveal]{opacity:0;transform:translateY(18px)}
.js [data-reveal].est-vu{opacity:1;transform:none;
  transition:opacity var(--duree-reveal) var(--courbe),transform var(--duree-reveal) var(--courbe);
  transition-delay:var(--r,0ms)}

/* révélation d'image par masque : un voile qui remonte, jamais un clip-path */
.masque{position:relative;overflow:hidden}
.voile{display:none}
.js .voile{display:block;position:absolute;inset:0;background:var(--ivoire);
  transform:translateY(0);z-index:2;pointer-events:none}
.js .voile--bleu{background:var(--bleu)}
.js .voile--encre{background:var(--encre)}
.js .voile--carmin{background:var(--carmin)}
.js .masque.est-vu .voile{transform:translateY(-101%);
  transition:transform 1100ms var(--courbe);transition-delay:var(--r,0ms)}
.js .masque img{transform:scale(1.12)}
.js .masque.est-vu img{transform:scale(1);
  transition:transform 1600ms var(--courbe);transition-delay:var(--r,0ms)}
.js .masque.est-vu .kb{transition:none}

/* titre en lignes qui montent */
.lignes{display:block}
.ligne{display:block;overflow:hidden}
.ligne>span{display:block}
.js .ligne>span{transform:translateY(105%)}
.js .est-vu .ligne>span{transform:translateY(0);
  transition:transform 1000ms var(--courbe)}
.js .est-vu .ligne:nth-child(2)>span{transition-delay:90ms}
.js .est-vu .ligne:nth-child(3)>span{transition-delay:180ms}

/* Ken-Burns lent, en pause hors écran */
.kb{animation:kb var(--kenburns) ease-in-out infinite alternate;will-change:transform}
.kb--inv{animation-direction:alternate-reverse}
@keyframes kb{from{transform:scale(1.004)}to{transform:scale(1.075)}}
.hors-vue .kb{animation-play-state:paused}

/* parallaxe : pilotée par GSAP, la classe sert juste de repère */
[data-parallaxe]{will-change:transform}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.001ms!important;animation-iteration-count:1!important;
    transition-duration:.001ms!important;scroll-behavior:auto!important}
  .js [data-reveal]{opacity:1;transform:none}
  .js .voile{display:none}
  .js .masque img,.js .ligne>span{transform:none}
  .defile__piste{transform:none!important}
}

/* ---------- délais de révélation (pas de style en ligne) ---------- */
.d1{--r:90ms}.d2{--r:180ms}.d3{--r:270ms}.d4{--r:360ms}.d5{--r:450ms}

/* ==========================================================================
   RANGÉES DE SOINS QUI DÉFILENT (V4, R2)
   Reprises de la page « Nos gammes » de la boutique de L'Art des Sens : le
   nom de la gamme, « Tout voir », puis les vraies cartes produit qui filent
   latéralement, bouton d'ajout au panier compris.

   Le rail est CONFINÉ. Sans ça, les cartes hors écran élargissent la largeur
   de défilement du document : mesuré chez L'Art des Sens, 1075 px au lieu de
   390 sur téléphone. `overflow-x:auto` fait défiler mais n'isole pas le rail
   du calcul de la page ; `body{overflow-x:hidden}` masque le symptôme, il ne
   le corrige pas.
   ========================================================================== */
.rangee{--marge:max(var(--gouttiere),calc((100% - var(--page)) / 2));
  margin-top:var(--e6)}
.rangee:first-of-type{margin-top:0}
.rangee__tete{display:flex;flex-wrap:wrap;align-items:flex-end;
  justify-content:space-between;gap:var(--e3) var(--e4);
  padding-inline:var(--marge);margin-bottom:var(--e4)}
.rangee__nom{font-size:var(--t-h3);margin-top:var(--e2)}
.rangee__mot{color:var(--encre-douce);font-size:var(--t-petit);
  max-width:52ch;margin-top:.4rem}
.rangee__outils{display:flex;align-items:center;gap:var(--e4);flex:0 0 auto}
.rangee__nav{display:none;gap:.4rem}
.rangee__nav.est-on{display:flex}
.rangee__fleche{display:grid;place-items:center;width:44px;height:44px;
  border:1px solid var(--filet-fort);background:none;cursor:pointer;
  color:var(--encre);border-radius:var(--r-0);
  transition:background var(--duree-court),border-color var(--duree-court),opacity var(--duree-court)}
.rangee__fleche:hover{background:var(--encre);color:var(--ivoire);border-color:var(--encre)}
.rangee__fleche:disabled{opacity:.3;cursor:default;background:none;color:var(--encre);
  border-color:var(--filet)}
.rangee__fleche svg{width:18px;height:18px}
.rangee__rail{display:flex;gap:var(--e4);margin:0;padding:0;list-style:none;
  padding-inline:var(--marge);scroll-padding-inline:var(--marge);
  overflow-x:auto;overscroll-behavior-x:contain;scroll-snap-type:x mandatory;
  -webkit-overflow-scrolling:touch;scrollbar-width:none;contain:paint}
.rangee__rail::-webkit-scrollbar{display:none}
.rangee__rail>.carte{flex:0 0 clamp(14rem,62vw,18rem);scroll-snap-align:start}
@media (max-width:819.98px){
  .rangee__nav{display:none!important}   /* au doigt, les flèches ne servent pas */
}

/* ---------- carte : le bas se déplie quand la colonne est étroite ---------- */
@media (max-width:560px){
  .carte__bas{flex-direction:column;align-items:flex-start;gap:.15rem}
  /* En grille à deux colonnes, l'accroche tient sur une ou deux lignes selon la carte :
     deux lignes réservées, et les prix d'une même rangée restent alignés (23 px d'écart
     mesurés le 17/09 entre LIKE MILK et NECTAR). */
  .produits .carte__bas .carte__type{min-height:2.9em}
}
/* « Ce qui va avec » au téléphone : trois cartes dans une grille à deux colonnes laissaient
   la troisième seule sur sa rangée. Elles défilent au doigt, comme les rangées de l'accueil. */
@media (max-width:779.98px){
  .associes .produits{display:flex;gap:var(--e4);overflow-x:auto;scroll-snap-type:x mandatory;
    overscroll-behavior-x:contain;-webkit-overflow-scrolling:touch;scrollbar-width:none;
    margin-inline:calc(var(--gouttiere) * -1);padding-inline:var(--gouttiere);
    scroll-padding-inline:var(--gouttiere)}
  .associes .produits::-webkit-scrollbar{display:none}
  .associes .produits>.carte{flex:0 0 clamp(14rem,62vw,18rem);scroll-snap-align:start}
  .associes .produits .carte__bas .carte__type{min-height:0}
}

/* ==========================================================================
   LE TÉLÉPHONE EN MOUVEMENT (V8, 17/09, retour de Rayan depuis son téléphone :
   « super bien sur PC mais pas sur téléphone, fusionne ces deux parties, fais
   les mêmes effets que sur PC, des effets de ouf »).

   Le constat mesuré : au bureau, le mouvement vient du SURVOL (flacons qui se
   soulèvent, seconde photo des cartes), des photos COLLANTES qui accompagnent
   la lecture et du défilement lissé. Rien de cela n'existe au doigt : le
   téléphone recevait la mise en page, pas l'expérience. Ce bloc lui donne la
   sienne, avec ses propres moyens :

   - LE RIDEAU : la photo du diagnostic reste épinglée sous l'entête, et le
     panneau de texte monte PAR-DESSUS, son bord fondu dans la photo. Un seul
     bloc au lieu de deux. C'est du `position:sticky`, donc porté par le
     compositeur du navigateur : aucun script, aucune saccade ;
   - les effets LIÉS AU DÉFILEMENT passent par `animation-timeline` (dérive des
     deux visages en sens opposés, profondeur dans les gammes qui glissent,
     recul de la photo sous le rideau). Ils tournent hors du fil principal, ce
     qu'un script ne sait pas faire au doigt. Un navigateur qui ne connaît pas
     la propriété garde la page fixe et juste : rien ne dépend d'eux ;
   - ce que la souris déclenche au SURVOL se joue ici tout seul : la gamme du
     haut se présente flacon par flacon, avec son nom ; la carte qui entre à
     l'écran montre sa seconde photo (classe `est-survol`, posée par app.js).

   Tout reste en transform / opacity et s'éteint si la personne a demandé
   moins de mouvement. Le bureau n'est pas touché.
   ========================================================================== */

/* ---------- le rideau : photo épinglée, texte qui monte dessus ---------- */
@media (max-width:899.98px){
  /* `clip` et non `hidden` : `hidden` ferait du bloc un conteneur de défilement et le collant ne collerait plus */
  .moment--rideau{overflow:clip}
  .moment--rideau .moment__grille{display:block}
  .moment--rideau .moment__media{position:sticky;top:var(--entete-h);z-index:0;aspect-ratio:auto;
    height:min(125vw,calc(100svh - var(--entete-h) - 5rem))}
  .moment--rideau .moment__media::after{content:"";position:absolute;inset:0;pointer-events:none;
    background:var(--encre);opacity:0}
  /* Le panneau recouvre le bas de la photo sur 7,5 rem ; le texte ne commence qu'une fois le voile plein. */
  .moment--rideau .moment__texte{margin-top:-7.5rem;padding-top:calc(7.5rem + var(--e4));
    background:linear-gradient(to bottom,rgb(18 25 30 / 0) 0,rgb(18 25 30 / .42) 2rem,
      rgb(18 25 30 / .86) 4.75rem,var(--encre) 7.5rem)}
}

/* ---------- ce que le survol fait au bureau, joué tout seul au doigt ---------- */
.carte.est-survol .carte__vue img{transform:scale(1.04)}
.carte.est-survol .carte__vue .est-second{opacity:1}
@media (hover:none){
  a,button{-webkit-tap-highlight-color:transparent}
  .btn,.carte .button{transition:transform .18s var(--courbe),background var(--duree-court) var(--courbe),
    color var(--duree-court) var(--courbe),border-color var(--duree-court) var(--courbe)}
  .btn:active,.carte .button:active{transform:scale(.97)}
  /* les deux noms du bord s'alignent sur leur flacon : centrés, ils sortaient de l'écran */
  .vitrine__flacon:first-child .vitrine__nom{left:0;transform:translate(0,.4rem)}
  .vitrine__flacon:last-child .vitrine__nom{left:auto;right:0;transform:translate(0,.4rem)}
}
@media (hover:none) and (max-width:899.98px){
  /* Au téléphone la gamme est juste sous le titre : affiché AU-DESSUS de son flacon, le nom
     recouvrait la deuxième ligne du titre (vu à la sonde du 17/09). Il se pose SOUS l'arête, dans
     l'espace que la ligne d'argument lui laisse. */
  .vitrine__nom{top:calc(100% + var(--e3) + .45rem);bottom:auto;transform:translateX(-50%)}
  .vitrine__flacon:first-child .vitrine__nom,.vitrine__flacon:last-child .vitrine__nom{transform:none}
  .vitrine__in>.lead{margin-top:calc(var(--e4) + 1.5rem)}
}
@media (hover:none) and (prefers-reduced-motion:no-preference){
  /* La gamme se présente : chaque flacon se soulève à son tour et dit son nom, puis la vague
     repasse. Le `li` porte l'entrée, l'image porte la vague : deux animations, deux éléments. */
  .vitrine__flacon img{animation:vitrine-vague 16s var(--courbe) infinite;
    animation-delay:calc(2.6s + var(--i) * .8s)}
  .vitrine__nom{animation:vitrine-nom 16s var(--courbe) infinite;
    animation-delay:calc(2.6s + var(--i) * .8s)}
  .vitrine::before{animation:vitrine-halo 7s ease-in-out infinite alternate}
  .vitrine.hors-vue .vitrine__flacon img,.vitrine.hors-vue .vitrine__nom,
  .vitrine.hors-vue::before{animation-play-state:paused}
}
@media (hover:none) and (max-width:899.98px) and (prefers-reduced-motion:no-preference){
  .vitrine__nom{animation-name:vitrine-nom-bas}
}
/* Un tour de gamme dure 7,2 s (neuf flacons, 0,8 s d'écart), puis la gamme se repose. Un nom
   reste 0,75 s, moins que l'écart : deux noms ne sont jamais à l'écran ensemble. */
@keyframes vitrine-vague{0%,7%,100%{translate:0 0}3%{translate:0 -.85rem}}
@keyframes vitrine-nom{0%,4.7%,100%{opacity:0;translate:0 0}.9%,3.8%{opacity:1;translate:0 -1rem}}
@keyframes vitrine-nom-bas{0%,4.7%,100%{opacity:0;translate:0 -.35rem}.9%,3.8%{opacity:1;translate:0 0}}
@keyframes vitrine-halo{from{opacity:.72;scale:1}to{opacity:1;scale:1.14}}

/* ---------- les soins d'une rangée arrivent de la droite, l'un après l'autre ---------- */
@media (max-width:819.98px) and (prefers-reduced-motion:no-preference){
  /* Le mouvement est porté par le CONTENU de la carte, jamais par la carte : elle est un point
     d'accroche du glissement (scroll-snap), et la déplacer décale la rangée de 20 à 30 px le
     temps que le navigateur se recale (vu au film du 17/09). */
  .js .rangee .carte>*{opacity:0;translate:3.25rem 0}
  /* `none` à l'arrivée, pas `0 0` : une translation, même nulle, ferait du titre le repère de son
     lien étendu (`.carte__nom a::after`), et la photo de la carte ne serait plus cliquable. */
  .js .rangee.est-vu .carte>*{opacity:1;translate:none;
    transition:opacity .7s var(--courbe),translate .95s var(--courbe),transform .18s var(--courbe),
      background var(--duree-court) var(--courbe),color var(--duree-court) var(--courbe);
    transition-delay:calc(180ms + var(--k,0) * 90ms),calc(180ms + var(--k,0) * 90ms),0s,0s,0s}
  .rangee .carte:nth-child(2){--k:1}.rangee .carte:nth-child(3){--k:2}.rangee .carte:nth-child(4){--k:3}
  .rangee .carte:nth-child(5){--k:4}.rangee .carte:nth-child(6){--k:5}.rangee .carte:nth-child(7){--k:6}
}

/* ---------- effets liés au défilement, hors du fil principal ---------- */
@supports (animation-timeline:view()){
  @media (max-width:899.98px) and (prefers-reduced-motion:no-preference){
    /* Chaque repère de défilement est NOMMÉ et posé sur le cadre, pas laissé à `view()` sur
       l'image : un cadre en `overflow:hidden` est un conteneur de défilement pour le navigateur,
       `view()` s'y accrochait et l'image, immobile dans son cadre, restait figée à mi-course
       (mesuré le 17/09 : translate 0 % du haut en bas de la page). Le cadre, lui, se mesure
       par rapport à la page, ou par rapport à la piste des gammes pour le glissement latéral. */

    /* Les deux visages dérivent en sens opposés. L'agrandissement permanent est la marge de la
       dérive : sans lui, l'image découvrirait le fond de son cadre (leçon de la parallaxe du 17/09). */
    .visages__vue{view-timeline:--visage block}
    .visages__vue img{scale:1.16;animation:derive-recule linear both;animation-timeline:--visage;
      animation-range:cover 0% cover 100%}
    .visages__vue--b img{animation-name:derive-avance}

    /* Les gammes qui glissent : la photo bouge moins vite que sa carte, elle paraît derrière une
       vitre. Le repère est sur la carte (elle aussi en `overflow:hidden`), mesurée dans la piste.
       Le lent zoom existant (`kb`) reste en première position de la liste. */
    .gamme{view-timeline:--gamme inline}
    .gamme__media img{scale:1.16;
      animation:kb var(--kenburns) ease-in-out infinite alternate,glisse-profondeur linear both;
      animation-timeline:auto,--gamme;animation-range:normal,cover 0% cover 100%}

    /* La photo revendeuse : même profondeur, à la verticale. */
    .rev__media{view-timeline:--rev block}
    .rev__media img{scale:1.12;
      animation:kb var(--kenburns) ease-in-out infinite alternate-reverse,derive-recule-court linear both;
      animation-timeline:auto,--rev;animation-range:normal,cover 0% cover 100%}

    /* Sous le rideau : la photo recule pendant que le panneau la recouvre, puis passe dans l'ombre. */
    .moment--rideau{view-timeline:--rideau block}
    .moment--rideau .moment__media img{animation:rideau-recul linear both;animation-timeline:--rideau;
      animation-range:cover 0% cover 62%}
    .moment--rideau .moment__media::after{animation:rideau-nuit linear both;animation-timeline:--rideau;
      animation-range:cover 40% cover 66%}

    /* Hors écran, seul le lent zoom se met en pause : une animation liée au défilement n'a rien
       à suspendre, et la figer la ferait sauter d'un cran au retour. */
    .hors-vue .gamme__media img,.hors-vue .rev__media img{animation-play-state:paused,running}
  }
}
@keyframes derive-recule{from{translate:0 -6.5%}to{translate:0 6.5%}}
@keyframes derive-avance{from{translate:0 6.5%}to{translate:0 -6.5%}}
@keyframes derive-recule-court{from{translate:0 -4.5%}to{translate:0 4.5%}}
@keyframes glisse-profondeur{from{translate:-6.5% 0}to{translate:6.5% 0}}
@keyframes rideau-recul{from{scale:1.22}to{scale:1}}
@keyframes rideau-nuit{to{opacity:.55}}

/* Les noms de soins écrits dans un texte sont des liens vers leur fiche (inc/liens.php, Rayan 25/09) :
   soulignement fin dans la couleur du texte, plein au survol ; la couleur ne change pas, pour rester
   lisible sur les fonds sombres comme sur les clairs. */
.lien-soin{color:inherit;font-weight:inherit;text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:.2em;text-decoration-color:color-mix(in srgb,currentColor 45%,transparent);transition:text-decoration-color .2s}
.lien-soin:hover,.lien-soin:focus-visible{text-decoration-color:currentColor}

/* LES PACKS, MONTRÉS (template-parts/packs-composition.php, 25/09) : la photo du pack, puis ses soins en
   vrais flacons, nom, type, prix, et le total qui tombe au dirham près. */
.pcompo{display:grid;gap:var(--e5);margin-top:var(--e5)}
.pcompo__pack{display:grid;gap:var(--e4);background:var(--ivoire);border:1px solid var(--filet);padding:var(--e4)}
.pcompo__photo{display:block;aspect-ratio:1;overflow:hidden;background:var(--sable)}
.pcompo__photo img{display:block;width:100%;height:100%;object-fit:cover}
.pcompo__corps{display:grid;gap:var(--e3);align-content:start}
.pcompo__nom{font-family:var(--f-titre);font-size:var(--t-h3);font-weight:var(--g-titre);line-height:1.1;margin:0}
.pcompo__nom a{text-decoration:none}
.pcompo__nom a:hover{text-decoration:underline;text-underline-offset:.2em}
.pcompo__soins{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--e2)}
.pcompo__soins a{display:grid;gap:var(--e1);text-decoration:none;color:inherit}
.pcompo__flacon{position:relative;display:block;aspect-ratio:3/4;background:var(--sable);overflow:hidden}
.pcompo__flacon img{position:absolute;inset:9%;width:82%;height:82%;object-fit:contain;transition:transform .35s}
.pcompo__soins a:hover .pcompo__flacon img{transform:translateY(-.35rem)}
.pcompo__snom{font-weight:var(--g-fort);font-size:var(--t-petit);line-height:1.2;margin-top:var(--e1)}
.pcompo__stype{color:var(--encre-douce);font-size:var(--t-mini);line-height:1.3}
.pcompo__soins li{display:grid}
.pcompo__soins a{grid-template-rows:auto auto 1fr auto}
.pcompo__sprix{font-weight:var(--g-fort);font-size:var(--t-petit);align-self:end}
.pcompo__total{display:grid;gap:var(--e1);margin:0;padding-top:var(--e3);border-top:1px solid var(--filet)}
.pcompo__calcul{font-size:var(--t-h4);font-variant-numeric:tabular-nums}
.pcompo__note{color:var(--encre-douce);font-size:var(--t-mini)}
.pcompo__actions{display:grid;gap:var(--e2)}
.pcompo__actions .btn{width:100%}
.pcompo--fiche .pcompo__pack{padding:0;border:0;background:none}
@media (min-width:780px){
  .pcompo--page .pcompo__pack{grid-template-columns:minmax(0,34fr) minmax(0,66fr);gap:var(--e5);padding:var(--e5)}
  .pcompo__actions{grid-template-columns:auto auto;justify-content:start}
  .pcompo__actions .btn{width:auto}
}
@media (max-width:420px){
  .pcompo__soins{gap:var(--e1)}
  .pcompo__stype{display:none}
}

/* Les pages légales (page-legal.php, 25/09) : une colonne de lecture, un sommaire quand la page est longue. */
.legal{max-width:var(--texte-large);display:grid;gap:var(--e4)}
.legal__maj{color:var(--encre-douce);font-size:var(--t-mini)}
.legal__sommaire ol{margin:0;padding-left:1.4em;columns:1;display:grid;gap:var(--e1)}
.legal__sommaire a{color:var(--bleu-nuit);text-underline-offset:.2em}
.legal__corps h2{scroll-margin-top:6rem}
.legal__corps p+ul{margin-top:var(--e2)}
.legal__corps ul li{padding-block:var(--e2)}
.legal .trou,.legal__corps p:has(> .trou){background:rgba(122,92,30,.08)}
@media (min-width:780px){.legal__sommaire ol{grid-template-columns:1fr 1fr}}
.pied__legal{display:flex;flex-wrap:wrap;gap:var(--e2) var(--e4);flex-basis:100%;margin-top:var(--e2)}
.pied__legal a{color:inherit;font-size:var(--t-mini);text-decoration:none;opacity:.8}
.pied__legal a:hover{opacity:1;text-decoration:underline;text-underline-offset:.2em}
