/* ==========================================================================
   INSTITUT DE BEAUTÉ MARINE — Design System v2
   Registre éditorial : typographie massive, aplats plein écran,
   contrastes francs. Palette sable & marine, claire.
   ========================================================================== */

/* --- 1. Tokens ---------------------------------------------------------- */
:root {
  /* Neutres — ivoire légèrement chaud, pour contraster le bleu froid */
  --c-ivory:    #FBF9F5;
  --c-cream:    #F2EDE4;
  --c-sand:     #E4DACA;
  --c-sand-dk:  #C7B79F;

  /* Bleu océan — profondeur marine, pas de dérive verte */
  --c-marine-50:  #EDF3F8;
  --c-marine-200: #A9C9DC;
  --c-marine-400: #4A88AB;
  --c-marine:     #175A83;
  --c-marine-dk:  #12455F;
  --c-marine-ink: #08283D;

  /* Encre */
  --c-ink:      #10161B;
  --c-ink-soft: #434B52;
  --c-ink-mute: #5A646C;
  --c-line:     #DED5C7;
  --c-white:    #FFFFFF;

  /* Signal */
  --c-no:       #A6452F;
  --c-no-bg:    #F8ECE7;

  /* Typographie */
  --f-display: 'Bodoni Moda', 'Didot', 'Bodoni MT', 'Times New Roman', serif;
  --f-body:    'Jost', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;

  --fs-xs: .75rem;  --fs-sm: .875rem; --fs-base: 1rem;
  --fs-md: 1.125rem; --fs-lg: 1.375rem;

  /* Échelle éditoriale (fluide) */
  --fs-h3:   clamp(1.25rem, 1.9vw, 1.625rem);
  --fs-h2:   clamp(1.875rem, 4.2vw, 3.25rem);
  --fs-h1:   clamp(2.5rem, 7.5vw, 6rem);
  --fs-huge: clamp(3rem, 12vw, 11rem);

  /* Espacements */
  --s-1:.25rem; --s-2:.5rem;  --s-3:.75rem; --s-4:1rem;
  --s-5:1.5rem; --s-6:2rem;   --s-7:3.5rem; --s-8:5.5rem;
  --s-9:8rem;   --s-10:11rem; --s-11:15rem;

  --radius: 2px;
  --radius-lg: 4px;
  --max-w: 1360px;
  --measure: 58ch;
  --ease: cubic-bezier(.22,.61,.36,1);
  --ease-io: cubic-bezier(.65,.05,.36,1);
  /* Échelle d'easing, transposée des courbes GSAP. Une seule courbe pour tout
     le site aplatissait la hiérarchie : une pastille qui grossit et un bandeau
     plein cadre ne doivent pas décélérer pareil. Plus le mouvement est ample,
     plus la sortie est longue.
       out-2  : micro-interactions (survol, flèche, filet)
       out-3  : entrées de blocs
       out-4  : grands déplacements, masques d'images
       back   : ce qui doit « se poser » (pastilles, compteurs) */
  --ease-out-2: cubic-bezier(.165,.84,.44,1);
  --ease-out-3: cubic-bezier(.215,.61,.355,1);
  --ease-out-4: cubic-bezier(.23,1,.32,1);
  --ease-back: cubic-bezier(.34,1.4,.64,1);
  --header-h: 84px;
}


/* --- 1b. Grain ---------------------------------------------------------- */
/* Texture de bruit à très faible opacité : casse l'aspect « aplat écran ».
   Invisible consciemment, mais c'est ce qui distingue une impression d'un PNG. */
body::after {
  content: '';
  position: fixed; inset: 0; z-index: 9999;
  pointer-events: none;
  opacity: .035;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
  mix-blend-mode: multiply;
}
.section--marine::after, .cta::after {
  content: '';
  position: absolute; inset: 0; pointer-events: none;
  opacity: .07;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n2'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n2)'/%3E%3C/svg%3E");
  mix-blend-mode: overlay;
}

/* --- 2. Reset ----------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  margin: 0;
  font-family: var(--f-body);
  font-weight: 300;
  font-size: var(--fs-base);
  line-height: 1.75;
  color: var(--c-ink-soft);
  background: var(--c-ivory);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
body.is-locked { overflow: hidden; }
img { max-width: 100%; height: auto; display: block; }
a { color: inherit; text-decoration: none; transition: color .25s var(--ease); }
ul { margin: 0; padding: 0; list-style: none; }
button { font: inherit; }
p { margin: 0 0 var(--s-4); max-width: 64ch; }
h1,h2,h3,h4 { margin: 0 0 var(--s-5); font-weight: 400; }

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

/* --- 2b. Micro-typographie éditoriale ----------------------------------- */
/* Équilibre des titres, pas de veuves dans les paragraphes, césure française */
.display, .h2, .h3, .price-block__head h3 { text-wrap: balance; }
p, .acc__body, .lead { text-wrap: pretty; }
p, .acc__body { hyphens: auto; hyphenate-limit-chars: 7 4 3; }

.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 9999;
  background: var(--c-marine-ink); color: #fff; padding: var(--s-3) var(--s-5);
}
.skip-link:focus { left: 0; }

/* --- 3. Typographie éditoriale ------------------------------------------ */
.display {
  font-family: var(--f-display);
  font-size: var(--fs-h1);
  line-height: 1.02;
  letter-spacing: -.015em;
  color: var(--c-ink);
  font-weight: 400;
}
/* L'italique de Bodoni est très dessinée : elle suffit à marquer l'accent,
   sans avoir besoin de capitales ni de changement de graisse. */
.display em { font-style: italic; letter-spacing: -.005em; }

.h2 {
  font-family: var(--f-display);
  font-size: var(--fs-h2);
  line-height: 1.08;
  letter-spacing: -.012em;
  color: var(--c-ink);
  font-weight: 400;
}
.h2 em { font-style: italic; letter-spacing: -.004em; }

.h3 { font-family: var(--f-display); font-size: var(--fs-h3); line-height: 1.25; color: var(--c-ink); letter-spacing: -.005em; }

.label {
  font-size: var(--fs-xs);
  letter-spacing: .34em;
  text-transform: uppercase;
  font-weight: 400;
  color: var(--c-marine);
  display: block;
  margin-bottom: var(--s-5);
}
/* Numérotation éditoriale des sections : romain en Bodoni italique */
.label__num {
  font-family: var(--f-display); font-style: italic;
  text-transform: none; letter-spacing: .04em;
  font-size: 1.3em; margin-right: .45em;
  color: var(--c-marine-400);
}
.section--marine .label__num { color: var(--c-marine-200); }

/* Légendes d'images : petit corps espacé */
.caption {
  display: block; margin-top: var(--s-3);
  font-size: .66rem; letter-spacing: .22em; text-transform: uppercase;
  color: var(--c-ink-mute);
}

.label--rule { display: flex; align-items: center; gap: var(--s-4); }
.label--rule::after { content: ''; flex: 1; height: 1px; background: var(--c-line); }
.lead { font-size: var(--fs-md); max-width: var(--measure); line-height: 1.6; }
.muted { color: var(--c-ink-mute); }
.center { text-align: center; }
.center .lead { margin-inline: auto; }


/* --- 3b. Axes des polices variables ------------------------------------- */
/* Bodoni Moda expose opsz (6..96) et wght (400..700). Le principe d'une
   didone : plus le corps est grand, plus l'axe optique monte et plus les
   déliés s'affinent. C'est cette finesse qui fait le caractère « presse
   mode » — à l'inverse d'une graisse uniforme qui empâte les grands titres.
   On ne dépasse jamais 400 sur les titres : au-delà, la didone s'alourdit. */
.display {
  font-variation-settings: 'opsz' 96, 'wght' 400;
  font-optical-sizing: auto;
}
.h2 {
  font-variation-settings: 'opsz' 72, 'wght' 400;
  font-optical-sizing: auto;
}
.h3, .price-block__head h3, .card__body h3, .slide__body h3 {
  font-variation-settings: 'opsz' 28, 'wght' 400;
}
.acc summary, .loader__word, .overlay__link {
  font-variation-settings: 'opsz' 60, 'wght' 400;
}
.swap__stat b, .figure b, .slide__price, .brand-card__logo {
  font-variation-settings: 'opsz' 36, 'wght' 400;
}
.footer__big { font-variation-settings: 'opsz' 96, 'wght' 400; }
.display em, .h2 em { font-variation-settings: 'opsz' 96, 'wght' 400; }

@supports not (font-variation-settings: 'wght' 400) {
  .display, .h2, .footer__big { font-weight: 400; }
}

/* --- 4. Layout ---------------------------------------------------------- */
.wrap { width: 100%; max-width: var(--max-w); margin-inline: auto; padding-inline: clamp(var(--s-5), 5vw, var(--s-9)); }
.wrap--narrow { max-width: 780px; }
.section { padding: var(--s-10) 0; position: relative; }
.section--xl { padding: var(--s-11) 0; }
.section--sm { padding: var(--s-8) 0; }
.section--cream  { background: var(--c-cream); }
.section--marine { background: var(--c-marine-ink); color: rgba(255,255,255,.78); }
.section--marine .h2, .section--marine .h3, .section--marine .display { color: #fff; }
.section--marine .label { color: var(--c-marine-200); }

.divider { height: 1px; background: var(--c-line); border: 0; margin: 0; }

/* --- 5. LOADER ---------------------------------------------------------- */
.loader {
  position: fixed; inset: 0; z-index: 9000;
  background: var(--c-ivory);
  display: grid; place-items: center;
  transition: opacity .7s var(--ease), visibility .7s;
}
.loader.is-done { opacity: 0; visibility: hidden; }
.loader__inner { text-align: center; width: min(90vw, 520px); }
.loader__mark { margin: 0 auto var(--s-6); animation: floaty 3s ease-in-out infinite; }
@keyframes floaty { 0%,100% { transform: translateY(0) } 50% { transform: translateY(-9px) } }
.loader__word {
  font-family: var(--f-display);
  font-size: clamp(1.5rem, 4.5vw, 2.5rem); line-height: 1.15;
  letter-spacing: -.01em; color: var(--c-ink); margin-bottom: var(--s-6);
}
.loader__track { height: 1px; background: var(--c-sand); position: relative; overflow: hidden; }
.loader__bar { position: absolute; inset: 0 100% 0 0; background: var(--c-marine); transition: right .25s linear; }
.loader__pct {
  margin-top: var(--s-3); font-size: var(--fs-xs);
  letter-spacing: .28em; color: var(--c-ink-mute); font-variant-numeric: tabular-nums;
}

/* --- 6. HEADER + MENU OVERLAY ------------------------------------------- */
.header {
  position: fixed; top: 0; left: 0; right: 0; z-index: 300;
  height: var(--header-h);
  display: flex; align-items: center;
  transition: background .4s var(--ease), border-color .4s var(--ease);
  border-bottom: 1px solid transparent;
}
.header.is-stuck { background: rgba(251,249,245,.9); backdrop-filter: blur(16px); border-bottom-color: var(--c-line); }
.header__bar { display: flex; align-items: center; justify-content: space-between; width: 100%; gap: var(--s-4); }

.brand { display: flex; align-items: center; gap: var(--s-3); }

.header__right { display: flex; align-items: center; gap: var(--s-4); }

.menu-btn {
  background: none; border: 0; cursor: pointer;
  display: flex; align-items: center; gap: var(--s-3);
  font-size: var(--fs-xs); letter-spacing: .28em; text-transform: uppercase;
  color: var(--c-ink); padding: var(--s-2) 0;
}
.menu-btn__lines { display: grid; gap: 4px; width: 22px; }
.menu-btn__lines i { display: block; height: 1.5px; background: currentColor; transition: transform .35s var(--ease), opacity .35s var(--ease); }
.menu-btn[aria-expanded="true"] { color: #fff; }

/* Menu ouvert : le header (au-dessus de l'overlay) passe en clair, sinon
   logo encre sur fond marine et bouton marine sur marine (constat d'audit) */
.menu-open .brand svg circle,
.menu-open .brand svg path[stroke] { stroke: var(--c-marine-200); }
.menu-open .header .btn--fill { background: #fff; color: var(--c-marine-ink); }
.menu-open .header .btn--fill:hover { background: var(--c-marine-200); }
.menu-btn[aria-expanded="true"] .menu-btn__lines i:nth-child(1) { transform: translateY(5.5px) rotate(45deg); }
.menu-btn[aria-expanded="true"] .menu-btn__lines i:nth-child(2) { opacity: 0; }
.menu-btn[aria-expanded="true"] .menu-btn__lines i:nth-child(3) { transform: translateY(-5.5px) rotate(-45deg); }

.overlay {
  position: fixed; inset: 0; z-index: 250;
  background: var(--c-marine-ink);
  clip-path: inset(0 0 100% 0);
  transition: clip-path .7s var(--ease-io);
  display: flex; flex-direction: column; justify-content: center;
  padding: var(--header-h) 0 var(--s-6);
  overflow-y: auto;
}
.overlay.is-open { clip-path: inset(0 0 0 0); }
.overlay__nav { display: grid; gap: var(--s-2); }
.overlay__item { overflow: hidden; }
.overlay__link {
  display: flex; align-items: baseline; gap: var(--s-4);
  font-family: var(--f-display);
  font-size: clamp(1.75rem, 6vw, 3.75rem); line-height: 1.18;
  letter-spacing: -.01em; color: #fff;
  transform: translateY(105%); transition: transform .6s var(--ease), color .3s var(--ease);
  padding: var(--s-1) 0;
}
.overlay.is-open .overlay__link { transform: translateY(0); }
.overlay__nav li:nth-child(1) .overlay__link { transition-delay: .10s }
.overlay__nav li:nth-child(2) .overlay__link { transition-delay: .16s }
.overlay__nav li:nth-child(3) .overlay__link { transition-delay: .22s }
.overlay__nav li:nth-child(4) .overlay__link { transition-delay: .28s }
.overlay__nav li:nth-child(5) .overlay__link { transition-delay: .34s }
.overlay__nav li:nth-child(6) .overlay__link { transition-delay: .40s }
.overlay__link:hover { color: var(--c-marine-200); }
.overlay__num { font-family: var(--f-body); font-size: var(--fs-xs); letter-spacing: .2em; color: var(--c-marine-200); flex: none; width: 3em; }
.overlay__foot {
  margin-top: var(--s-8); padding-top: var(--s-5);
  border-top: 1px solid rgba(255,255,255,.14);
  display: flex; flex-wrap: wrap; gap: var(--s-5) var(--s-7);
  justify-content: space-between; align-items: center;
  font-size: var(--fs-sm); color: rgba(255,255,255,.65);
  opacity: 0; transition: opacity .5s var(--ease) .5s;
}
.overlay.is-open .overlay__foot { opacity: 1; }
.overlay__foot a { color: #fff; }
.overlay__foot a:hover { color: var(--c-marine-200); }

/* --- 7. Boutons --------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s-3);
  font-size: var(--fs-xs); letter-spacing: .2em; text-transform: uppercase; font-weight: 500;
  padding: var(--s-4) var(--s-7); border: 1px solid transparent; border-radius: var(--radius);
  cursor: pointer; transition: all .35s var(--ease); position: relative; overflow: hidden;
  white-space: nowrap;
}
.btn--fill  { background: var(--c-marine-ink); color: #fff; }
.btn--fill:hover  { background: var(--c-marine); transform: translateY(-2px); }
.btn--line  { border-color: var(--c-ink); color: var(--c-ink); }
.btn--line:hover  { background: var(--c-ink); color: var(--c-ivory); transform: translateY(-2px); }
.btn--light { background: #fff; color: var(--c-ink); }
.btn--light:hover { background: var(--c-marine-200); transform: translateY(-2px); }
.btn--ghostw { border-color: rgba(255,255,255,.4); color: #fff; }
.btn--ghostw:hover { background: #fff; color: var(--c-ink); }
.btn--sm { padding: var(--s-3) var(--s-5); }
.btn--block { width: 100%; }

/* --- 8. HERO ------------------------------------------------------------ */
.hero { position: relative; min-height: 100svh; display: flex; align-items: flex-end; overflow: hidden; background: var(--c-cream); }
.hero__bg { position: absolute; inset: 0; }
.hero__bg img { width: 100%; height: 100%; object-fit: cover; transform: scale(1.06); }
.hero__bg::after {
  content: ''; position: absolute; inset: 0;
  /* Deux couches : un voile latéral dense côté texte (le titre vit à gauche),
     dégagé côté image ; et le fondu vertical vers l'ivoire du bas de page. */
  /* La devanture porte sa propre enseigne verticale (INSTITUT ESTHEDERM,
     ÉPILATION, MAQUILLAGE…) exactement derrière la colonne de titre : à .52
     d'opacité au milieu, ces lettres traversaient « au rythme » et le chapô.
     Le voile est donc dense et tenu jusqu'à ~46 %, puis s'ouvre franchement :
     la vitrine reste lisible à droite, où elle raconte l'identité. */
  background:
    linear-gradient(90deg, rgba(251,249,245,.93) 0%, rgba(251,249,245,.88) 30%, rgba(251,249,245,.66) 46%, rgba(251,249,245,.16) 72%, rgba(251,249,245,0) 100%),
    linear-gradient(180deg, rgba(251,249,245,.42) 0%, rgba(251,249,245,.18) 42%, rgba(251,249,245,.85) 88%, var(--c-ivory) 100%);
}
.hero__inner { position: relative; z-index: 2; width: 100%; padding-bottom: var(--s-8); padding-top: calc(var(--header-h) + var(--s-9)); }
.hero__title { margin-bottom: var(--s-7); }
.hero__title .line { display: block; overflow: hidden; }
.hero__title .line > span { display: block; transform: translateY(105%); transition: transform 1s var(--ease); }
.is-ready .hero__title .line > span { transform: translateY(0); }
.is-ready .hero__title .line:nth-child(2) > span { transition-delay: .09s }
.is-ready .hero__title .line:nth-child(3) > span { transition-delay: .18s }
.hero__meta { display: flex; flex-wrap: wrap; gap: var(--s-6) var(--s-9); align-items: flex-end; justify-content: space-between; }
.hero__actions { display: flex; flex-wrap: wrap; gap: var(--s-3); }
.hero__scroll { display: flex; align-items: center; gap: var(--s-3); font-size: var(--fs-xs); letter-spacing: .2em; text-transform: uppercase; color: var(--c-ink-mute); }
.hero__scroll .dot { width: 1px; height: 34px; background: var(--c-sand-dk); position: relative; overflow: hidden; }
.hero__scroll .dot::after { content:''; position: absolute; inset: 0; background: var(--c-marine); animation: scrollpulse 2s var(--ease) infinite; }
@keyframes scrollpulse { 0% { transform: translateY(-100%) } 60%,100% { transform: translateY(100%) } }

/* --- 9. MARQUEE --------------------------------------------------------- */
.marquee { overflow: hidden; border-block: 1px solid var(--c-line); padding: var(--s-4) 0; background: var(--c-ivory); }
.marquee__track { display: flex; gap: var(--s-7); width: max-content; animation: slide 38s linear infinite; }
.marquee__track span {
  font-family: var(--f-display); font-size: clamp(1rem, 2vw, 1.5rem);
  font-style: italic; letter-spacing: 0; color: var(--c-ink);
  display: flex; align-items: center; gap: var(--s-7); white-space: nowrap;
}
.marquee__track span::after { content: '✦'; color: var(--c-marine-400); font-size: .6em; }
@keyframes slide { to { transform: translateX(-50%) } }
.marquee:hover .marquee__track { animation-play-state: paused; }

/* --- 10. CARROUSEL D'UNIVERS -------------------------------------------- */
/* overflow: clip (et non hidden) : hidden ferait de la section le « scroll
   container » le plus proche, ce qui neutralise position:sticky et fige les
   timelines scroll() des enfants. clip borne le débord sans créer de scrollport. */
.universe { position: relative; background: var(--c-cream); overflow: clip; transition: background .8s var(--ease); }
.universe__head { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: flex-end; gap: var(--s-6); margin-bottom: var(--s-9); }
.universe__count { font-family: var(--f-display); font-size: var(--fs-md); letter-spacing: .04em; color: var(--c-ink-mute); font-variant-numeric: tabular-nums; }

.rail {
  display: flex; gap: var(--s-5);
  overflow-x: auto; scroll-snap-type: x mandatory;
  padding-bottom: var(--s-5);
  scrollbar-width: none; -ms-overflow-style: none;
  cursor: grab;
}
.rail::-webkit-scrollbar { display: none; }
.rail.is-dragging { cursor: grabbing; scroll-snap-type: none; }
.rail.is-dragging a { pointer-events: none; }

.slide {
  flex: 0 0 clamp(260px, 30vw, 380px);
  scroll-snap-align: start;
  background: none; border: 0; border-top: 1px solid var(--c-ink);
  border-radius: 0; padding-top: var(--s-4);
  display: flex; flex-direction: column;
}
.slide__media { aspect-ratio: 3/4; overflow: hidden; position: relative; background: var(--c-sand); order: 2; margin-top: var(--s-4); }
.slide__media img { width: 100%; height: 100%; object-fit: cover; transition: transform 1.1s var(--ease-out-4); }
/* Hors grille des univers : zoom au survol. Dans la grille, la dérive au
   défilement occupe déjà le canal `transform` — deux mouvements sur la même
   propriété se seraient annulés, le survol y passe donc par la luminosité. */
.slide:not(.universe__grid .slide):hover .slide__media img { transform: scale(1.07); }
.universe__grid .slide__media img { transition: filter .5s var(--ease-out-2); }

.universe__grid .slide:hover .slide__media img { filter: saturate(1.12) contrast(1.05) brightness(1.03); }
/* Pastille pleine plutôt que blanc + ombre : sur les visuels produits à fond
   clair, le chiffre disparaissait (contraste 1:1 mesuré à l'audit) */
.slide__idx {
  position: absolute; top: 0; left: 0; z-index: 2;
  font-family: var(--f-display); font-size: 1.5rem; line-height: 1; color: #fff;
  background: var(--c-marine-ink);
  padding: var(--s-2) var(--s-3) var(--s-1);
}
.slide__body { padding: var(--s-4) 0 0; flex: 1; display: flex; flex-direction: column; gap: var(--s-2); }
.slide__body h3 { font-family: var(--f-display); font-size: var(--fs-h3); letter-spacing: -.005em; color: var(--c-ink); margin: 0; }
.slide__body p { font-size: var(--fs-sm); flex: 1; margin: 0; }
.slide__price { font-family: var(--f-display); font-size: var(--fs-lg); color: var(--c-marine); }
.slide__go { font-size: var(--fs-xs); letter-spacing: .18em; text-transform: uppercase; color: var(--c-marine); display: inline-flex; gap: var(--s-2); align-items: center; }
.slide__go .arrow { transition: transform .42s var(--ease-back); }
.slide:hover .slide__go .arrow { transform: translateX(7px); }

.rail-nav { display: flex; gap: var(--s-3); margin-top: var(--s-5); }
.rail-nav button {
  width: 54px; height: 54px; border-radius: 0;
  border: 1px solid var(--c-ink); background: none;
  cursor: pointer; display: grid; place-items: center; color: var(--c-ink);
  transition: all .3s var(--ease);
}
.rail-nav button:hover:not(:disabled) { background: var(--c-marine-ink); color: #fff; border-color: var(--c-marine-ink); }
.rail-nav button:disabled { opacity: .3; cursor: default; }

/* --- 11. ENGAGEMENTS ✗ → ✓ ---------------------------------------------- */
.swap { display: grid; gap: var(--s-11); }
.swap__row { display: grid; grid-template-columns: 1fr 1.1fr; gap: clamp(var(--s-6), 6vw, var(--s-10)); align-items: center; }
.swap__row:nth-child(even) .swap__visual { order: -1; }
.swap__no {
  display: inline-flex; align-items: center; gap: var(--s-3);
  font-family: var(--f-display); font-size: clamp(1.05rem, 2.2vw, 1.5rem);
  color: var(--c-no); text-decoration: line-through;
  text-decoration-thickness: 1px; text-underline-offset: 2px; opacity: .8;
  letter-spacing: -.005em; margin-bottom: var(--s-3);
}
.swap__no .x {
  width: 22px; height: 22px; flex: none; border-radius: 0;
  border: 1px solid currentColor; background: none; color: var(--c-no);
  display: grid; place-items: center; font-size: .8rem;
  text-decoration: none; font-family: var(--f-body);
}
.swap__yes { margin-bottom: var(--s-4); }
.swap__visual { position: relative; }
.swap__visual img { width: 100%; aspect-ratio: 5/4; object-fit: cover; border-radius: 0; filter: saturate(.92); }
.swap__stat {
  position: absolute; left: 0; bottom: 0;
  background: var(--c-ivory); border: 0; border-top: 1px solid var(--c-ink);
  border-radius: 0; padding: var(--s-3) var(--s-5) var(--s-3) var(--s-4);
  text-align: left; min-width: 150px;
}
.swap__stat b { display: block; font-family: var(--f-display); font-size: 2.4rem; line-height: 1; color: var(--c-marine); }
.swap__stat span { font-size: var(--fs-xs); letter-spacing: .14em; text-transform: uppercase; color: var(--c-ink-mute); }

/* --- 12. Chiffres ------------------------------------------------------- */
.figures { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--s-7); }
.figure { text-align: center; }
.figure b { display: block; font-family: var(--f-display); font-size: clamp(2.5rem, 6vw, 4.5rem); line-height: 1; color: var(--c-ink); letter-spacing: -.02em; }
.section--marine .figure b { color: #fff; }
.figure span { font-size: var(--fs-xs); letter-spacing: .18em; text-transform: uppercase; color: var(--c-ink-mute); }
.section--marine .figure span { color: var(--c-marine-200); }

/* --- 13. Système éditorial (remplace les cartes) ------------------------ */
/* Plus de border-radius + ombre + translateY : c'est la signature Bootstrap.
   Ici : filet supérieur, numérotation, légende. Le vide fait le travail. */
.grid { display: grid; gap: var(--s-6); }
.grid--2 { grid-template-columns: repeat(2, 1fr); }
.grid--3 { grid-template-columns: repeat(3, 1fr); }
.grid--4 { grid-template-columns: repeat(4, 1fr); }
.grid--rule { gap: 0; }
.grid--rule > * { border-left: 1px solid var(--c-line); padding: var(--s-6) var(--s-6) var(--s-5); }
.grid--rule > *:first-child { border-left: 0; padding-left: 0; }

.card {
  display: flex; flex-direction: column;
  background: none; border: 0; border-top: 1px solid var(--c-ink);
  border-radius: 0; padding-top: var(--s-5);
  transition: none;
}
.card:hover { transform: none; box-shadow: none; }
.card__media {
  aspect-ratio: 4/5; overflow: hidden; background: var(--c-sand);
  order: 2; margin-top: var(--s-5);
  clip-path: inset(0 0 0 0);
}
.card__media img {
  width: 100%; height: 100%; object-fit: cover;
  transition: transform 1.4s var(--ease), filter 1.4s var(--ease);
  filter: saturate(.92);
}
.card:hover .card__media img { transform: scale(1.04); filter: saturate(1); }
.card__body { padding: 0; display: flex; flex-direction: column; gap: var(--s-3); }
.card__body h3 {
  font-family: var(--f-display); font-size: var(--fs-h3);
  color: var(--c-ink); margin: 0;
  letter-spacing: -.015em;
}
.card__body p { font-size: var(--fs-sm); margin: 0; max-width: 40ch; }
.card__num {
  font-size: var(--fs-xs); letter-spacing: .3em; color: var(--c-ink-mute);
  font-variant-numeric: tabular-nums; margin-bottom: var(--s-2);
}
.card__go {
  font-size: var(--fs-xs); letter-spacing: .2em; text-transform: uppercase;
  color: var(--c-ink); display: inline-flex; gap: var(--s-2); align-items: center;
  padding-bottom: 3px; border-bottom: 1px solid var(--c-sand-dk);
  align-self: flex-start; transition: border-color .4s var(--ease), color .4s var(--ease);
}
.card:hover .card__go { border-color: var(--c-marine); color: var(--c-marine); }
.card__go .arrow { transition: transform .4s var(--ease); }
.card:hover .card__go .arrow { transform: translateX(6px); }

/* --- 14. Split ---------------------------------------------------------- */
.split { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(var(--s-6), 6vw, var(--s-10)); align-items: center; }
.split--rev .split__media { order: -1; }
.split__media img { width: 100%; aspect-ratio: 4/5; object-fit: cover; border-radius: 0; filter: saturate(.92); }
.split__media--wide img { aspect-ratio: 4/3; }

/* --- 15. Tarifs --------------------------------------------------------- */
.price-block {
  background: none; border: 0; border-top: 1px solid var(--c-ink);
  border-radius: 0; padding: var(--s-5) 0 0; height: 100%;
}
.price-block--boxed {
  background: var(--c-white); border: 1px solid var(--c-line);
  padding: var(--s-6); border-top-color: var(--c-line);
}
.price-block__head { margin-bottom: var(--s-5); }
.price-block__head h3 { font-family: var(--f-display); font-size: var(--fs-h3); color: var(--c-ink); margin: 0 0 var(--s-1); }
.price-block__head p { font-size: var(--fs-sm); color: var(--c-ink-mute); margin: 0; }

.price-list li { display: flex; align-items: baseline; gap: var(--s-3); padding: var(--s-3) 0; border-bottom: 1px dashed var(--c-line); }
.price-list li:last-child { border-bottom: 0; padding-bottom: 0; }
.price-list .p-name { flex: 1; color: var(--c-ink); font-size: var(--fs-sm); }
.price-list .p-name em { display: block; font-style: normal; font-size: var(--fs-xs); color: var(--c-ink-mute); margin-top: 2px; }
.price-list .p-dur { font-size: var(--fs-xs); color: var(--c-ink-mute); letter-spacing: .06em; white-space: nowrap; }
/* Les valeurs sont en Jost, pas en Bodoni : à ~22 px la diagonale hairline du
   « 4 » de la didone disparaît à l'écran (40 € se lisait 10 € à l'audit).
   Les tarifs font foi : aucune ambiguïté possible. */
.price-list .p-val {
  font-family: var(--f-body); font-weight: 450;
  font-size: var(--fs-base); letter-spacing: .05em;
  font-variant-numeric: tabular-nums lining-nums;
  color: var(--c-marine-dk); white-space: nowrap; min-width: 62px; text-align: right;
}
.price-list li.is-highlight { background: var(--c-marine-50); margin-inline: calc(var(--s-3) * -1); padding-inline: var(--s-3); border-radius: var(--radius); }

.badge { display: inline-block; font-size: .6rem; letter-spacing: .16em; text-transform: uppercase; padding: 4px 10px; border-radius: 0; background: var(--c-sand); color: var(--c-marine-dk); vertical-align: middle; margin-left: var(--s-2); }
.badge--new { background: var(--c-marine-ink); color: #fff; }

/* --- 16. Onglets -------------------------------------------------------- */
.tabs { display: flex; flex-wrap: wrap; gap: var(--s-2); border-bottom: 1px solid var(--c-line); margin-bottom: var(--s-6); padding-bottom: var(--s-2); }
.tab {
  background: none; border: 0; cursor: pointer;
  font-size: var(--fs-xs); letter-spacing: .16em; text-transform: uppercase;
  color: var(--c-ink-mute); padding: var(--s-3) var(--s-4);
  border-radius: var(--radius); transition: all .3s var(--ease);
}
.tab:hover { color: var(--c-ink); background: var(--c-cream); }
.tab[aria-selected="true"] { background: var(--c-marine-ink); color: #fff; }
.tab-panel[hidden] { display: none; }

/* --- 17. Accordéon ------------------------------------------------------ */
.acc { border-bottom: 1px solid var(--c-line); }
.acc:first-of-type { border-top: 1px solid var(--c-line); }
.acc summary {
  padding: var(--s-5) 0; cursor: pointer; list-style: none;
  display: flex; justify-content: space-between; align-items: center; gap: var(--s-5);
  font-family: var(--f-display); font-size: clamp(1.05rem, 2.1vw, 1.4rem);
  color: var(--c-ink); letter-spacing: -.005em;
  transition: color .3s var(--ease);
}
.acc summary:hover { color: var(--c-marine); }
.acc summary::-webkit-details-marker { display: none; }
.acc summary::after { content: '+'; font-size: 1.6rem; color: var(--c-marine); transition: transform .35s var(--ease); flex: none; }
.acc[open] summary::after { transform: rotate(45deg); }
.acc__body { padding: 0 0 var(--s-5); font-size: var(--fs-sm); max-width: 72ch; }
.section--marine .acc { border-color: rgba(255,255,255,.16); }
.section--marine .acc summary { color: #fff; }
.section--marine .acc summary::after { color: var(--c-marine-200); }

/* --- 18. Formulaire ----------------------------------------------------- */
.form { display: grid; gap: var(--s-4); }
.field { display: grid; gap: var(--s-2); }
.field label { font-size: var(--fs-xs); letter-spacing: .14em; text-transform: uppercase; color: var(--c-ink); }
.field .hint { font-size: var(--fs-xs); color: var(--c-ink-mute); letter-spacing: 0; text-transform: none; }
.field input, .field select, .field textarea {
  font-family: var(--f-body); font-size: var(--fs-base);
  padding: var(--s-4); width: 100%;
  border: 1px solid var(--c-line); border-radius: var(--radius);
  background: var(--c-white); color: var(--c-ink);
  transition: border-color .25s var(--ease), box-shadow .25s var(--ease);
}
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none; border-color: var(--c-marine); box-shadow: 0 0 0 3px rgba(23,90,131,.13);
}
.field textarea { resize: vertical; min-height: 130px; }
.form__row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-4); }
.consent { display: flex; gap: var(--s-3); align-items: flex-start; font-size: var(--fs-xs); color: var(--c-ink-mute); }
/* La case de consentement fait 13 px en natif : sous le pouce, c'est un pari.
   On l'agrandit à 24 px et on étend la zone cliquable à toute l'étiquette
   (un <label> englobant : cocher en touchant le texte). */
.consent input { width: auto; margin-top: 3px; inline-size: 24px; block-size: 24px; accent-color: var(--c-marine); flex: none; }
@media (pointer: coarse) {
  .consent { padding-block: var(--s-2); align-items: center; }
  .consent input { inline-size: 28px; block-size: 28px; margin-top: 0; }
}
.note { background: none; border-left: 1px solid var(--c-marine); padding: var(--s-2) 0 var(--s-2) var(--s-5); border-radius: 0; font-size: var(--fs-sm); }
.form-status { font-size: var(--fs-sm); padding: var(--s-3) var(--s-4); border-radius: var(--radius); display: none; }
.form-status.is-ok  { display: block; background: var(--c-marine-50); color: var(--c-marine-dk); }
.form-status.is-err { display: block; background: var(--c-no-bg); color: var(--c-no); }

/* --- 19. Infos ---------------------------------------------------------- */
.info-list { display: grid; gap: var(--s-5); }
.info-list li { display: flex; gap: var(--s-4); align-items: flex-start; }
.info-list .ico { flex: none; color: var(--c-marine); margin-top: 3px; }
.info-list strong { display: block; font-size: var(--fs-xs); letter-spacing: .14em; text-transform: uppercase; color: var(--c-ink); margin-bottom: 3px; }
.info-list span { font-size: var(--fs-sm); }

.hours li { display: flex; justify-content: space-between; gap: var(--s-4); padding: var(--s-3) 0; border-bottom: 1px dashed var(--c-line); font-size: var(--fs-sm); }
.hours li:last-child { border-bottom: 0; }
.hours .day { color: var(--c-ink); }
.hours .time { color: var(--c-ink-mute); font-variant-numeric: tabular-nums; }
.hours .closed { color: var(--c-ink-mute); font-style: italic; }

.map-embed { width: 100%; aspect-ratio: 16/9; border: 0; border-radius: 0; filter: saturate(.8) contrast(.95); }

/* --- 20. Page-hero (pages internes) ------------------------------------- */
.page-hero { position: relative; min-height: 72svh; display: flex; align-items: flex-end; overflow: hidden; background: var(--c-cream); }
.page-hero__bg { position: absolute; inset: 0; }
.page-hero__bg img { width: 100%; height: 100%; object-fit: cover; }
.page-hero__bg::after {
  content: ''; position: absolute; inset: 0;
  background:
    linear-gradient(90deg, rgba(251,249,245,.80) 0%, rgba(251,249,245,.55) 42%, rgba(251,249,245,.14) 78%, rgba(251,249,245,.05) 100%),
    linear-gradient(180deg, rgba(251,249,245,.35) 0%, rgba(251,249,245,.60) 55%, var(--c-ivory) 100%);
}
/* padding-BLOCK uniquement : le raccourci `padding: X 0 Y` écrasait le
   padding-inline de .wrap (déclaré plus haut), ce qui collait le fil d'Ariane,
   le titre et le chapô au bord — texte rogné sur mobile, héros désaligné de la
   grille sur desktop. */
.page-hero__inner { position: relative; z-index: 2; width: 100%; padding-block: calc(var(--header-h) + var(--s-8)) var(--s-8); }

/* Héros sans photographie.
   Corps & épilation et Nouveautés n'ont aucun visuel disponible qui tienne le
   plein cadre : les photos d'origine sont en 450–500 px (étirées ×3 à ×4) et
   les seuls visuels de marque disponibles sont des key visuals produit qui, en
   fond de héros, lisent comme une publicité de revendeur (vérifié en capture).
   Plutôt qu'une image qui dessert la page, le titre porte seul, sur ivoire.
   Le filet marine tient le bas du bloc et raccorde à la grille du site. */
.page-hero--plain { min-height: auto; background: var(--c-ivory); }
.page-hero--plain .page-hero__inner::after {
  content: ''; display: block; margin-top: var(--s-7);
  height: 1px; background: var(--c-line);
}
/* Sans image, le filet ferme déjà le bloc : le creux cumulé (filet 3,5rem +
   fond de héros 3,5rem + entête de section 11rem) ouvrait un trou de près de
   290 px qui se lisait comme un oubli, pas comme une respiration. Le filet
   porte la césure, la section qui suit reprend d'un cran plus haut. */
.page-hero--plain .page-hero__inner { padding-bottom: 0; }
.page-hero--plain + .section { padding-top: var(--s-8); }
.crumbs { font-size: var(--fs-xs); letter-spacing: .18em; text-transform: uppercase; color: var(--c-ink-mute); margin-bottom: var(--s-5); }
/* Sur un héros en image, le gris sourd du fil d'Ariane se dissolvait dans la
   photo — illisible sur la vitrine de contact.html en portrait. Sur ivoire
   (héros sans image) il garde sa discrétion voulue ; sur photo il passe au
   marine, seule couleur de la palette qui tienne sur un fond variable. */
.page-hero:not(.page-hero--plain) .crumbs,
.page-hero:not(.page-hero--plain) .crumbs a { color: var(--c-marine-dk); }
.crumbs a:hover { color: var(--c-marine); }
.crumbs span { margin: 0 var(--s-2); opacity: .45; }

/* --- 21. CTA final ------------------------------------------------------ */
.cta { background: var(--c-marine-ink); color: #fff; padding: var(--s-10) 0; text-align: center; position: relative; overflow: hidden; }
.cta::before { content: ''; position: absolute; inset: 0; background: radial-gradient(ellipse at 50% -10%, rgba(169,201,220,.18), transparent 62%); }
.cta > * { position: relative; z-index: 1; }
.cta .h2, .cta .display { color: #fff; }
.cta p { color: rgba(255,255,255,.76); max-width: 52ch; margin-inline: auto; }
.cta__actions { display: flex; justify-content: center; flex-wrap: wrap; gap: var(--s-3); margin-top: var(--s-6); }

/* --- 22. Footer --------------------------------------------------------- */
.footer { background: var(--c-ivory); border-top: 1px solid var(--c-line); padding: var(--s-9) 0 var(--s-5); }
.footer__big { font-family: var(--f-display); font-size: var(--fs-huge); line-height: .9; letter-spacing: -.02em; color: var(--c-sand); margin-bottom: var(--s-8); user-select: none; font-style: italic; }
.footer__grid { display: grid; grid-template-columns: 1.5fr 1fr 1fr 1.2fr; gap: var(--s-6); }
.footer h4 { font-size: var(--fs-xs); letter-spacing: .22em; text-transform: uppercase; color: var(--c-ink); margin-bottom: var(--s-4); }
.footer ul { display: grid; gap: var(--s-2); }
.footer a, .footer p, .footer li { font-size: var(--fs-sm); color: var(--c-ink-soft); }
.footer a:hover { color: var(--c-marine); }
.socials { display: flex; gap: var(--s-3); margin-top: var(--s-4); }
.socials a { width: 44px; height: 44px; display: grid; place-items: center; border: 1px solid var(--c-line); border-radius: 0; color: var(--c-marine); transition: all .3s var(--ease); }
.socials a:hover { background: var(--c-marine-ink); color: #fff; border-color: var(--c-marine-ink); transform: translateY(-3px); }
.footer__bottom { margin-top: var(--s-7); padding-top: var(--s-5); border-top: 1px solid var(--c-line); display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--s-3); font-size: var(--fs-xs); color: var(--c-ink-mute); }

/* --- 23. Barre mobile --------------------------------------------------- */
.mobile-cta {
  display: none; position: fixed; bottom: 0; left: 0; right: 0; z-index: 200;
  background: rgba(251,249,245,.96); backdrop-filter: blur(14px);
  border-top: 1px solid var(--c-line); padding: var(--s-3) var(--s-4); gap: var(--s-3);
}
.mobile-cta .btn { flex: 1; }

/* --- 24. Révélations pilotées par le scroll ----------------------------- */
/* Deux implémentations superposées :
   1. animation-timeline: view() — natif, 0 ligne de JS, lié à la position
      exacte de l'élément dans le viewport. C'est le chemin par défaut.
   2. Repli IntersectionObserver dans main.js pour les navigateurs anciens :
      il n'ajoute la classe .in que si scroll-timeline n'est pas supporté. */

@keyframes rise {
  from { opacity: 0; transform: translateY(34px); }
  to   { opacity: 1; transform: none; }
}
@keyframes unmask {
  from { clip-path: inset(0 0 100% 0); }
  to   { clip-path: inset(0 0 0 0); }
}
@keyframes drift {
  from { transform: translateY(6%) scale(1.08); }
  to   { transform: translateY(-6%) scale(1.08); }
}
@keyframes widen {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

@supports (animation-timeline: view()) {
  .rv {
    animation: rise linear both;
    animation-timeline: view();
    animation-range: entry 5% cover 26%;
  }
  .rv[data-d="1"] { animation-range: entry 2% cover 28%; }
  .rv[data-d="2"] { animation-range: entry 0% cover 30%; }
  .rv[data-d="3"] { animation-range: entry 0% cover 32%; }
  .rv[data-d="4"] { animation-range: entry 0% cover 34%; }

  /* Exception : ce qui est DÉJÀ visible au chargement.
     Une révélation pilotée par `view()` fige l'élément à sa progression du
     moment tant que le visiteur n'a pas défilé. Le bloc d'actions du héros
     restait donc à 70 % d'opacité — mesuré rgb(80,102,116) au lieu du marine
     rgb(8,40,61) — c'est-à-dire le bouton « Prendre rendez-vous », premier
     geste du parcours, délavé sur le premier écran. Ces éléments suivent
     l'entrée du titre (.is-ready), pas le défilement. */
  .hero .rv,
  .rv--visible-au-chargement {
    animation: none;
    opacity: 0; transform: translateY(30px);
    transition: opacity .9s var(--ease) .34s, transform .9s var(--ease) .34s;
  }
  .is-ready .hero .rv,
  .is-ready .rv--visible-au-chargement { opacity: 1; transform: none; }

  /* Images dévoilées par masque plutôt que par simple fondu */
  .reveal-img { overflow: hidden; }
  .reveal-img > img,
  .card__media, .split__media, .swap__visual img {
    animation: unmask linear both;
    animation-timeline: view();
    animation-range: entry 8% cover 34%;
  }

  /* Parallaxe multicouche sur les fonds de héros (pas la doublure floutée) */
  .hero__bg img:not(.hero__blur), .page-hero__bg img:not(.hero__blur) {
    animation: drift linear both;
    animation-timeline: scroll(root);
  }

  /* Filets qui se tracent */
  .divider, .label--rule::after {
    transform-origin: left;
    animation: widen linear both;
    animation-timeline: view();
    animation-range: entry 10% cover 24%;
  }

  /* Les filets supérieurs des blocs éditoriaux se tracent aussi :
     le border-top est remplacé par un ::before animable */
  .price-block, .card, .slide { border-top: 0; position: relative; }
  .price-block::before, .card::before, .slide::before {
    content: ''; position: absolute; top: 0; left: 0; right: 0; height: 1px;
    background: var(--c-ink);
    transform-origin: left;
    animation: widen linear both;
    animation-timeline: view();
    animation-range: entry 10% cover 22%;
  }
}

/* Repli : sans scroll-timeline, la classe .in est posée par main.js */
@supports not (animation-timeline: view()) {
  .rv { opacity: 0; transform: translateY(30px); transition: opacity .9s var(--ease), transform .9s var(--ease); }
  .rv.in { opacity: 1; transform: none; }
  .rv[data-d="1"] { transition-delay: .09s } .rv[data-d="2"] { transition-delay: .18s }
  .rv[data-d="3"] { transition-delay: .27s } .rv[data-d="4"] { transition-delay: .36s }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; scroll-behavior: auto !important; }
  .rv { opacity: 1 !important; transform: none !important; animation: none !important; }
  .hero__title .line > span { transform: none; }
  .overlay__link { transform: none; }
  .marquee__track { animation: none; }
  .card__media, .split__media, .swap__visual img, .reveal-img > img { animation: none !important; clip-path: none !important; }
  .hero__bg img, .page-hero__bg img { animation: none !important; }
}

/* --- 25. Responsive ----------------------------------------------------- */
@media (max-width: 1080px) {
  .grid--4 { grid-template-columns: repeat(2, 1fr); }
  .figures { grid-template-columns: repeat(2, 1fr); gap: var(--s-7); }
  .footer__grid { grid-template-columns: 1fr 1fr; gap: var(--s-7); }
  .swap__row { gap: var(--s-6); }
}

@media (max-width: 860px) {
  :root { --header-h: 70px; }
  .grid--2, .grid--3 { grid-template-columns: 1fr; }
  .split, .split--rev { grid-template-columns: 1fr; }
  .split--rev .split__media { order: 0; }
  .split__media img { aspect-ratio: 4/3; }
  .swap__row { grid-template-columns: 1fr; gap: var(--s-5); }
  .swap__row:nth-child(even) .swap__visual { order: 0; }
  .swap { gap: var(--s-8); }
  .swap__stat { right: var(--s-4); bottom: var(--s-4); min-width: 108px; padding: var(--s-3) var(--s-4); }
  .section { padding: var(--s-8) 0; }
  .hero { min-height: 92svh; }
  .mobile-cta { display: flex; }
  body { padding-bottom: 76px; }
  .form__row { grid-template-columns: 1fr; }
  .slide { flex-basis: 78vw; }
  .overlay { justify-content: flex-start; padding-top: calc(var(--header-h) + var(--s-5)); }
  .footer__big { font-size: clamp(3rem, 22vw, 7rem); }
}

@media (max-width: 640px) {
  /* La barre basse Écrire/Appeler prend le relais : le bouton téléphone du
     header éclatait sur trois lignes à 390 px (constat d'audit) */
  .header__right .btn { display: none; }
}

@media (max-width: 520px) {
  .grid--4 { grid-template-columns: 1fr; }
  .figures { grid-template-columns: 1fr; gap: var(--s-5); }
  .footer__grid { grid-template-columns: 1fr; }
  .price-block { padding: var(--s-5) var(--s-4); }
  .price-list li { flex-wrap: wrap; }
  .price-list .p-val { min-width: auto; }
  .hero__meta { align-items: flex-start; }
  .hero__scroll { display: none; }
}


/* --- 27. Transitions entre pages (View Transitions API) ----------------- */
/* @view-transition active la navigation cross-document : plus de flash blanc
   entre deux pages. Les éléments partageant un view-transition-name sont
   morphés d'une page à l'autre plutôt que redessinés. */
@view-transition { navigation: auto; }

::view-transition-old(root) {
  animation: vt-out .32s cubic-bezier(.4,0,1,1) both;
}
::view-transition-new(root) {
  animation: vt-in .46s cubic-bezier(0,0,.2,1) both;
}
@keyframes vt-out { to { opacity: 0; transform: translateY(-10px); } }
@keyframes vt-in  { from { opacity: 0; transform: translateY(14px); } }

/* Éléments persistants : ils ne clignotent pas, ils restent en place */
.header      { view-transition-name: site-header; }
.footer      { view-transition-name: site-footer; }
.mobile-cta  { view-transition-name: site-mobilecta; }
.brand       { view-transition-name: site-brand; }

::view-transition-group(site-header),
::view-transition-group(site-footer),
::view-transition-group(site-mobilecta),
::view-transition-group(site-brand) { animation-duration: .38s; }

::view-transition-old(site-header), ::view-transition-new(site-header),
::view-transition-old(site-footer), ::view-transition-new(site-footer),
::view-transition-old(site-mobilecta), ::view-transition-new(site-mobilecta) {
  animation: none; mix-blend-mode: normal;
}

/* Le visuel du héros se déplace d'une page à l'autre.
   :not(.hero__blur) est vital : deux éléments portant le même
   view-transition-name sur une page annulent la transition. */
.hero__bg img:not(.hero__blur), .page-hero__bg img:not(.hero__blur) { view-transition-name: hero-media; }
::view-transition-group(hero-media) {
  animation-duration: .5s;
  animation-timing-function: cubic-bezier(.22,.61,.36,1);
}

@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root), ::view-transition-new(root) { animation: none; }
  ::view-transition-group(*) { animation-duration: .01ms !important; }
}


/* --- 28. Micro-interactions --------------------------------------------- */
/* Bouton magnétique : le déplacement est piloté en JS via ces deux variables,
   ce qui évite de réécrire transform et de casser les autres animations. */
.btn, .rail-nav button {
  --mx: 0px; --my: 0px;
  transform: translate(var(--mx), var(--my));
  will-change: transform;
}
.btn:hover, .rail-nav button:hover:not(:disabled) { transform: translate(var(--mx), var(--my)); }
.btn--fill:hover, .btn--line:hover, .btn--light:hover, .btn--ghostw:hover {
  transform: translate(var(--mx), calc(var(--my) - 2px));
}

/* Remplissage progressif au survol, plutôt qu'un simple changement de fond */
.btn--line { position: relative; overflow: hidden; z-index: 0; }
.btn--line::before {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background: var(--c-ink);
  transform: scaleY(0); transform-origin: bottom;
  transition: transform .45s var(--ease);
}
.btn--line:hover::before { transform: scaleY(1); transform-origin: top; }
.btn--line:hover { color: var(--c-ivory); border-color: var(--c-ink); background: none; }

/* Liens de navigation : filet qui se trace depuis la gauche */
.overlay__link { position: relative; }
.overlay__link::after {
  content: ''; position: absolute; left: 0; bottom: .08em; height: 1px; width: 100%;
  background: currentColor; transform: scaleX(0); transform-origin: right;
  transition: transform .5s var(--ease);
}
.overlay__link:hover::after { transform: scaleX(1); transform-origin: left; }

/* Curseur : anneau discret qui grossit sur les zones interactives */
.cursor {
  position: fixed; top: 0; left: 0; z-index: 8000;
  width: 26px; height: 26px; margin: -13px 0 0 -13px;
  border: 1px solid #fff; border-radius: 50%;
  pointer-events: none; opacity: 0;
  /* Exception assumée au « n'anime pas width/height » : la position du curseur
     passe par transform (posé par le JS à chaque frame), donc le grossissement
     ne peut pas emprunter le même canal sans @property. Le coût réel est nul :
     l'élément est position:fixed, hors flux, seul sur sa couche de compositing
     (mix-blend-mode), et la transition ne se déclenche qu'au changement de
     classe — deux fois par survol, jamais par frame. */
  transition: opacity .3s var(--ease), width .3s var(--ease), height .3s var(--ease),
              margin .3s var(--ease), background-color .3s var(--ease);
  /* exclusion : sombre sur l'ivoire, clair sur le marine — multiply devenait
     une tache opaque sur les fonds sombres (constat d'audit) */
  mix-blend-mode: exclusion;
}
.cursor.is-on { opacity: .5; }
.cursor.is-hot {
  width: 58px; height: 58px; margin: -29px 0 0 -29px;
  background: rgba(255,255,255,.12); opacity: .8;
}
@media (hover: none), (pointer: coarse) { .cursor { display: none; } }
@media (prefers-reduced-motion: reduce) { .cursor { display: none; } }

/* Curseur contextuel : l'anneau se remplit et annonce l'action */
.cursor span {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  font-family: var(--f-body); font-size: .58rem; font-weight: 500;
  letter-spacing: .18em; text-transform: uppercase;
  color: #fff; opacity: 0; transition: opacity .25s var(--ease);
}
.cursor.is-label {
  width: 66px; height: 66px; margin: -33px 0 0 -33px;
  background: var(--c-marine-ink); border-color: var(--c-marine-ink);
  mix-blend-mode: normal; opacity: 1;
}
.cursor.is-label span { opacity: 1; }

/* Compteur à chiffres roulants (section épinglée) */
.odo {
  display: inline-block; height: 1em; overflow: hidden;
  vertical-align: baseline; line-height: 1;
}
.odo__col {
  display: inline-flex; flex-direction: column; line-height: 1;
  transition: transform .5s var(--ease);
  will-change: transform;
}
.odo__col span { display: block; height: 1em; }

/* Découpe typographique mot à mot (posée par main.js, jamais sans JS) */
.is-split .w { display: inline-block; overflow: hidden; vertical-align: bottom; }
.is-split .w > span {
  display: inline-block;
  /* respiration pour les débords de l'italique (f, y…) sans casser le masque */
  padding: 0 .06em .08em; margin: 0 -.06em -.08em;
  transform: translateY(112%);
  transition: transform .75s var(--ease);
  transition-delay: calc(var(--wi, 0) * 48ms);
}
.is-split.in .w > span { transform: none; }
@media (prefers-reduced-motion: reduce) {
  .is-split .w > span { transform: none !important; transition: none !important; }
}

/* Ligne de tarif : glissement discret au survol.
   Le décalage porte sur le libellé via transform, pas sur le padding de la
   ligne : animer le padding relayout la liste entière à chaque survol (54
   lignes), et déplacerait aussi le prix, calé à droite. */
.price-list .p-name { transition: transform .35s var(--ease); }
.price-list li:hover .p-name { transform: translateX(var(--s-3)); }

/* Accordéon : le + pivote et se colore */
.acc summary::after { transition: transform .4s var(--ease), color .4s var(--ease); }
.acc summary:hover::after { color: var(--c-ink); }


/* --- 29. Section épinglée ----------------------------------------------- */
/* La section se fige pendant que les univers défilent horizontalement, liés
   à la progression du scroll vertical. Le visiteur n'a rien à cliquer : il
   continue simplement à descendre. C'est ce qui distingue une narration d'un
   carrousel — un carrousel demande un effort, une section épinglée raconte.
   Sans support de scroll-timeline, on retombe sur le rail à défilement libre. */

/* --- Les six univers de soin : grille verticale ---------------------------
   La section était épinglée sur 420vh, avec un rail qui défilait
   horizontalement au fil du scroll. Remplacée par une grille qui suit le
   défilement vertical de la page : les six soins sont visibles d'un coup
   d'œil, sans geste d'apprentissage, sans détournement de la molette, et
   la page raccourcit d'environ 3 400 px. Les flèches, le compteur et la
   barre de progression n'avaient plus d'objet et ont été retirés. */
.universe__grid {
  display: grid;
  gap: var(--s-8) var(--s-6);
  grid-template-columns: repeat(3, 1fr);
}
@media (max-width: 980px) { .universe__grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 620px) { .universe__grid { grid-template-columns: 1fr; gap: var(--s-7); } }

/* Entrée en cascade des six univers.
   Principe emprunté au stagger : les cartes ne montent pas ensemble mais se
   décalent de 70 ms, en lisant l'ordre de la grille. Le décalage se fait sur
   la PLAGE de la timeline de vue, pas sur un delay — un delay ne veut rien
   dire quand c'est le défilement qui pilote, et il se voit au rebours. */
@supports (animation-timeline: view()) {
  .universe__grid .slide {
    animation: rise linear both;
    animation-timeline: view();
    animation-range: entry 4% cover 24%;
  }
  .universe__grid .slide:nth-child(3n+2) { animation-range: entry 4% cover 28%; }
  .universe__grid .slide:nth-child(3n)   { animation-range: entry 4% cover 32%; }
}
@supports not (animation-timeline: view()) {
  .universe__grid .slide { opacity: 0; transform: translateY(34px);
    transition: opacity .9s var(--ease-out-3), transform .9s var(--ease-out-3); }
  .universe__grid .slide.in { opacity: 1; transform: none; }
  .universe__grid .slide:nth-child(3n+2) { transition-delay: .07s; }
  .universe__grid .slide:nth-child(3n)   { transition-delay: .14s; }
}

/* Le visuel dérive doucement dans son cadre pendant qu'on le dépasse.
   Amplitude volontairement faible (3 %) : au-delà, sur une photo de produit,
   ça se voit comme un défaut de calage plutôt que comme une profondeur. */
@supports (animation-timeline: view()) {
  .universe__grid .slide__media img {
    animation: derive linear both;
    animation-timeline: view();
    animation-range: cover 0% cover 100%;
  }
  @keyframes derive {
    from { transform: scale(1.06) translateY(3%); }
    to   { transform: scale(1.06) translateY(-3%); }
  }
  /* le survol reprend la main sur la dérive */
  .universe__grid .slide:hover .slide__media img { animation-play-state: paused; }
}

@media (prefers-reduced-motion: reduce) {
  .universe__grid .slide,
  .universe__grid .slide__media img { animation: none !important; opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .pin { height: auto !important; }
  .pin__sticky { position: static !important; height: auto !important; }
  .pin__track { animation: none !important; transform: none !important; overflow-x: auto; }
  .pin__progress { display: none; }
  .pin .rail-nav { display: flex !important; }
}

@media (max-width: 860px) {
  .pin { height: auto !important; }
  .pin__sticky { position: static !important; height: auto !important; overflow: visible; }
  .pin__track {
    animation: none !important; transform: none !important;
    overflow-x: auto; scroll-snap-type: x mandatory; width: auto;
    padding-inline: 0;
  }
  .pin__track .slide { flex-basis: 76vw; scroll-snap-align: start; }
  .pin__progress { display: none; }
  .pin .rail-nav { display: flex !important; }
}


/* --- 30. Adaptation aux photographies d'origine ------------------------- */
/* Les images du site historique vont de 250 à 1050 px de large. Étirées
   sur un héros plein écran, elles pixellisent. Trois mesures pour limiter
   la casse sans les remplacer :
     1. lissage forcé à l'agrandissement (image-rendering)
     2. sur les héros, un fond flouté de la même image comble le hors-cadre,
        pendant que l'image nette reste centrée à sa taille utile
     3. saturation et contraste très légèrement relevés : les JPEG anciens
        sont ternes, ça les remet à niveau sans les dénaturer */

img { image-rendering: auto; }

.hero__bg, .page-hero__bg { background: var(--c-cream); }
.hero__bg img:not(.hero__blur), .page-hero__bg img:not(.hero__blur) {
  filter: saturate(1.04) contrast(1.03);
}

/* Héros : doublure floutée derrière l'image, pour éviter la sur-dilatation.
   C'est un vrai <img class="hero__blur"> dupliqué dans le HTML : une URL
   relative dans une custom property inline serait résolue contre style.css
   (d'où les 404 constatés à l'audit), et un vrai img profite du cache. */
img.hero__blur {
  position: absolute; inset: -6%;
  width: 112%; height: 112%;
  object-fit: cover;
  filter: blur(38px) saturate(1.15) brightness(1.04);
  z-index: 0;
}
.hero__bg img:not(.hero__blur), .page-hero__bg img:not(.hero__blur) { position: relative; z-index: 1; }
/* Le voile de lisibilité DOIT passer au-dessus de l'image nette (z-index 1) */
.hero__bg::after, .page-hero__bg::after { z-index: 2; }

/* La vitrine est en 1050 px : elle supporte le plein cadre.
   Les autres héros, plus petits, sont contenus et centrés. */
.hero__bg img { object-fit: cover; object-position: center 42%; }
.page-hero__bg img { object-fit: cover; object-position: center 38%; }

/* Héros des pages intérieures : duotone marine.
   Les visuels de marque disponibles sont des key visuals publicitaires — or,
   orange, lilas selon la gamme. Bruts, ils cassaient la palette (violet sur
   Visage, rouge sur Nouveautés, constatés en capture). La bichromie les ramène
   dans le marine/ivoire par construction et les fait lire comme une matière,
   plus comme une réclame. Le héros d'accueil en est exclu : la devanture bleu
   roi est l'identité, elle reste en couleur. */
.page-hero__bg img:not(.hero__blur) { filter: saturate(1.04) contrast(1.03); }
.page-hero__bg img.hero__blur { filter: blur(38px) saturate(1.15) brightness(1.04); }

/* Visuels de produit : fond clair, pas de recadrage destructeur */
.slide__media, .card__media {
  background: var(--c-white);
}
.slide__media img, .card__media img {
  object-fit: cover;
  filter: saturate(1.03);
}

/* --- 30b. Images en couleur ----------------------------------------------
   La bichromie marine a été retirée : les photos sont rendues en couleur.
   Un très léger relèvement de saturation et de contraste reste, pour
   rattraper la fadeur des anciens JPEG sans les dénaturer. */
.slide__media img, .card__media img, .swap__visual img, .split__media img {
  filter: saturate(1.05) contrast(1.03);
  transition: transform 1.1s var(--ease);
}

/* Grain renforcé sur les images uniquement : homogénéise des textures
   hétérogènes et assume le caractère imprimé */
.slide__media, .card__media, .swap__visual .media, .split__media { position: relative; }
.slide__media::after, .card__media::after, .swap__visual .media::after, .split__media::after {
  content: ''; position: absolute; inset: 0; z-index: 1;
  pointer-events: none; opacity: .16; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23g)'/%3E%3C/svg%3E");
}
/* le grain ne doit pas recouvrir l'encart chiffré des comparaisons */
.swap__stat { z-index: 2; }

/* Trame d'impression sur les images les plus dégradées : le point de trame
   absorbe le flou d'agrandissement en parti pris graphique (test) */
.media--trame::after {
  background-image:
    radial-gradient(circle, rgba(8,40,61,.30) 1px, transparent 1.3px),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23g)'/%3E%3C/svg%3E");
  background-size: 4px 4px, 120px 120px;
  opacity: .5; mix-blend-mode: multiply;
}

@media (prefers-reduced-motion: reduce) {
  .slide__media img, .card__media img, .swap__visual img, .split__media img { transition: none; }
}

/* Les affiches de marque sont souvent en portrait étroit : on évite
   de les rogner en pleine largeur sur les blocs de comparaison */
.swap__visual img { object-fit: cover; object-position: center 40%; }

/* Le plan d'accès historique remplace avantageusement rien du tout :
   il est affiché à sa taille native, sans étirement */
.plan-img {
  width: 100%; max-width: 615px; height: auto;
  border: 1px solid var(--c-line);
  background: var(--c-white);
}

@media (max-width: 860px) {
  .hero__blur { filter: blur(26px) saturate(1.15); }
  /* En portrait, l'image (paysage 1050×821) est calée sur la hauteur par
     `cover` : aucune marge verticale, le lettrage peint du store tombe donc
     fatalement derrière le sur-titre, quel que soit le recadrage. Plutôt que
     d'alourdir le voile sur toute la bande — ce qui délave la devanture, qui
     est l'identité — on détache la ligne par un halo ivoire : le texte se
     décolle du lettrage sans que la photo perde sa lumière. */
  .hero .label,
  .page-hero:not(.page-hero--plain) .label,
  .page-hero:not(.page-hero--plain) .crumbs {
    text-shadow: 0 0 10px var(--c-ivory), 0 0 22px rgba(251,249,245,.9);
  }
  /* Sur mobile le texte occupe toute la largeur : le voile vertical reprend
     la main, renforcé dans la bande du titre. */
  .hero__bg::after, .page-hero__bg::after {
    /* Le creux à 40 % laissait le sur-titre et la première ligne du H1 tomber
       sur l'enseigne peinte de la devanture — deux typographies blanches
       superposées, illisibles sur iPhone. Le voile garde donc la main sur
       toute la bande du titre au lieu de s'ouvrir au milieu. */
    background:
      linear-gradient(180deg, rgba(251,249,245,.62) 0%, rgba(251,249,245,.60) 30%, rgba(251,249,245,.62) 58%, rgba(251,249,245,.90) 86%, var(--c-ivory) 100%);
  }
}
@media (prefers-reduced-motion: reduce) {
  .hero__blur { filter: blur(30px); }
}

/* --- 26. Impression ----------------------------------------------------- */
/* Le cas d'usage réel : une cliente imprime la page des tarifs pour l'emporter
   ou la poser près du téléphone. La feuille précédente masquait à la fois le
   CTA final et le pied de page — la page sortait donc SANS adresse ni numéro,
   c'est-à-dire sans le seul élément qui sert à prendre rendez-vous. */
@media print {
  .header, .mobile-cta, .loader, .overlay, .marquee,
  .hero__bg, .page-hero__bg, .cursor, .footer__big,
  .hero__scroll, .rail__nav, .tabs { display: none !important; }

  body { background: #fff; color: #000; padding: 0; }
  .section, .page-hero__inner, .hero__inner { padding-block: 12pt; }

  /* on rétablit tout ce qui porte de l'information utile */
  .rv, .split__media, .swap__visual { opacity: 1 !important; transform: none !important; }
  .card, .price-block, .slide, .price-row { break-inside: avoid; border-color: #999; }
  .rail { overflow: visible; flex-wrap: wrap; }
  h1, h2, h3 { break-after: avoid; }

  /* les images en duotone sortent en aplats sales sur papier */
  img { filter: none !important; max-width: 100%; }
  .slide__media::after, .card__media::after,
  .swap__visual .media::after, .split__media::after { display: none !important; }

  /* l'URL derrière un lien n'existe pas sur papier : on l'imprime */
  main a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 8pt; word-break: break-all; }
  main a[href^="tel:"]::after, main a[href^="mailto:"]::after,
  main a[href^="#"]::after, .crumbs a::after { content: ""; }

  /* pied de page réduit à l'essentiel commercial */
  .footer { background: none !important; color: #000 !important; border-top: 1px solid #999; }
  .footer__grid > div:not(:first-child):not(:last-child) { display: none; }
  .cta { background: none !important; color: #000 !important; }
  .cta a, .footer a { color: #000 !important; }

  @page { margin: 14mm; }
}

/* Navigation de secours de la page 404 : un visiteur arrivé là par un lien
   mort doit pouvoir rejoindre une prestation, pas seulement l'accueil. */
.err-nav {
  margin-top: var(--s-7); display: flex; flex-wrap: wrap;
  gap: var(--s-3) var(--s-5); justify-content: center;
  font-size: var(--fs-xs); letter-spacing: .14em; text-transform: uppercase;
}
.err-nav a { color: var(--c-ink-mute); }
.err-nav a:hover, .err-nav a:focus-visible { color: var(--c-marine); }
@media (pointer: coarse) { .err-nav a { display: inline-flex; align-items: center; min-height: 44px; } }

/* --- 31. Cibles tactiles ------------------------------------------------- */
/* Sur iPhone — le terminal critique — toute cible d'action doit faire au moins
   44 × 44 px (Apple HIG, WCAG 2.5.5). Les listes de liens du pied de page et
   du menu tombaient entre 20 et 41 px : atteignables au clic, pénibles au
   pouce. Cadré sur `pointer: coarse` pour ne pas relâcher la densité
   typographique du desktop, où la souris est précise. */
@media (pointer: coarse) {
  .footer__grid ul li a,
  .footer__grid p a,
  .footer__bottom a,
  .overlay__foot a,
  .slide__go, .card__go,
  .crumbs a {
    display: inline-flex; align-items: center;
    min-height: 44px;
  }
  /* les listes perdent la puce visuelle du retrait : on compense l'interligne */
  .footer__grid ul li { margin-block: 0; }

  .socials a { display: inline-flex; align-items: center; justify-content: center; min-width: 44px; min-height: 44px; }
  /* Bloc de coordonnées : le téléphone y est le premier geste du parcours,
     il ne peut pas être une cible de 20 px de haut. */
  .info-list a { display: inline-flex; align-items: center; min-height: 44px; }
  .overlay__link { min-height: 48px; display: flex; align-items: center; }
  .brand { min-height: 44px; }
  .menu-btn { min-height: 44px; padding-block: 4px; }
}

/* ==========================================================================
   31. IDENTITÉ « MARÉE »
   --------------------------------------------------------------------------
   La baie de Vieux-Port–Port-Vallon a le plus grand marnage d'Europe : 13 à 14 m
   entre basse et pleine mer, deux fois par jour, devant la boutique. La
   signature du site — « La beauté au rythme de la mer » — cesse d'être
   décorative et devient littérale.

   Trois conséquences, et une seule règle graphique :

   1. LA PALETTE EST UNE COLONNE D'EAU. Les quatre bleus du brief ne sont plus
      posés côte à côte : ils s'échelonnent du fond de l'estuaire à l'écume.
      Aucune teinte ajoutée, aucune retirée — --c-fond est le marine du brief
      assombri, rien de plus.
   2. LA LIGNE DE FLOTTAISON est le SEUL trait du site. Séparateur, filet sous
      les titres, soulignement de lien. Un geste, répété.
   3. TOUT ENTRE PAR LE BAS, à la vitesse de l'eau. Jamais de rebond, jamais
      d'entrée latérale.
   ========================================================================== */

:root {
  --c-fond: #061B29;              /* -14 m — basse mer, le fond */
  /* --c-ink #08283D  -8 m — eau profonde   (déjà défini, couleur du brief) */
  /* --c-marine #175A83 -3 m — pleine eau   (déjà défini, couleur du brief) */
  /* --c-marine-200 #A9C9DC 0 m — la surface (déjà défini, couleur du brief) */
  /* --c-ivory #FBF9F5   + — l'écume        (déjà défini, couleur du brief) */

  /* La montée d'eau : lente à l'amorce, ferme à l'arrivée. Ce n'est pas une
     courbe de rebond — une marée n'hésite pas et ne dépasse pas. */
  --ease-eau: cubic-bezier(.37, 0, .24, 1);
  --t-eau: 1.15s;
}

/* --- 31a. La ligne de flottaison ---------------------------------------- */
/* Le trait unique. Partout où le site sépare, souligne ou pose un filet,
   c'est ce trait — pâle, fin, avec une remontée de lumière au-dessus. */
.flottaison {
  position: relative; height: 1px; border: 0; margin: 0;
  background: var(--c-line);
}
.flottaison::before {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 34px;
  background: linear-gradient(180deg, transparent, rgba(169,201,220,.14));
  pointer-events: none;
}

/* --- 31b. Scène sombre : la colonne d'eau ------------------------------- */
.nuit { background: var(--c-fond); color: var(--c-ivory); }
.nuit h1, .nuit h2, .nuit h3, .nuit .h2 { color: var(--c-ivory); }
.nuit p { color: rgba(251,249,245,.62); }
.nuit .label { color: var(--c-marine-200); }

/* --- 31c. Révélations montantes ------------------------------------------ */
/* Le contenu ne glisse plus de côté : il monte, comme l'eau. Amplitude plus
   courte que l'ancienne (34 px → 22 px) parce qu'un mouvement lent sur une
   grande distance traîne ; lent et court, il pèse. */
@keyframes montee {
  from { opacity: 0; transform: translateY(22px); }
  to   { opacity: 1; transform: none; }
}

/* --- 31d. Révélation d'image par montée d'eau ---------------------------- */
/* L'image n'apparaît pas en fondu : elle se découvre par le bas, comme un
   estran qui se démasque. `clip-path` est composité, donc gratuit au GPU. */
.eau-monte { clip-path: inset(100% 0 0 0); }
.is-ready .eau-monte,
.eau-monte.in { clip-path: inset(0 0 0 0); transition: clip-path var(--t-eau) var(--ease-eau); }

@media (prefers-reduced-motion: reduce) {
  .eau-monte, .is-ready .eau-monte, .eau-monte.in {
    clip-path: none; transition: none; animation: none;
  }
}

/* --- 31e. L'échelle de marée : la carte des soins ------------------------ */
/* Transposition des réglettes graduées peintes sur les quais bretons.
   Six graduations, six univers. On survole un nom, l'eau monte à son niveau,
   la promesse se déplie et l'image se découvre par le bas.
   Ce n'est pas un carrousel : rien ne défile, c'est le niveau qui change. */
.maree { position: relative; background: var(--c-fond); overflow: hidden; }
.maree__stage { position: relative; min-height: min(100svh, 820px); }

.maree__bg { position: absolute; inset: 0; }
.maree__bg figure {
  position: absolute; inset: 0; margin: 0;
  clip-path: inset(100% 0 0 0);
  transition: clip-path var(--t-eau) var(--ease-eau);
}
.maree__bg figure.on { clip-path: inset(0 0 0 0); }
.maree__bg img { width: 100%; height: 100%; object-fit: cover; filter: saturate(.86) contrast(1.05); }
/* Le voile est LATÉRAL et sombre, pas ivoire : le texte vit à gauche, la
   photo respire à droite. C'est l'inverse exact de l'ancien héros, qui
   délavait l'image sous un voile clair pour faire passer le texte. */
.maree__bg::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(90deg,
    rgba(6,27,41,.96) 0%, rgba(6,27,41,.90) 40%,
    rgba(6,27,41,.72) 72%, rgba(6,27,41,.58) 100%);
}

/* la ligne d'eau : elle se cale sur le BAS du soin actif, jamais sur un
   pourcentage arbitraire — sinon le soin paraît noyé au lieu d'être atteint */
.maree__flot {
  position: absolute; left: 0; right: 0; height: 1px; top: 84%;
  background: var(--c-marine-200); opacity: .55; z-index: 3;
  transition: top var(--t-eau) var(--ease-eau); pointer-events: none;
}
.maree__flot::before {
  content: ''; position: absolute; left: 0; right: 0; top: -40px; height: 40px;
  background: linear-gradient(180deg, transparent, rgba(169,201,220,.13));
}

.maree__fg {
  position: relative; z-index: 4; min-height: inherit;
  display: flex; align-items: center; gap: clamp(1.5rem, 4vw, 3rem);
  /* L'en-tête est fixe et opaque : sans dégagement, le titre de section et la
     première graduation passaient dessous. On réserve sa hauteur. */
  padding: calc(var(--header-h) + var(--s-6)) 0 clamp(2rem, 5vw, 4rem);
}

/* la réglette graduée */
.regle { flex: none; width: 56px; position: relative; align-self: stretch;
         display: flex; flex-direction: column; justify-content: center; }
.regle::before { content: ''; position: absolute; left: 26px; top: 8%; bottom: 8%;
         width: 1px; background: rgba(251,249,245,.22); }
.regle span { position: relative; flex: 1; display: flex; align-items: center; }
.regle i { display: block; width: 14px; height: 1px; background: rgba(251,249,245,.30);
         margin-left: 19px; transition: width .5s var(--ease), background .5s var(--ease); }
.regle span.on i { width: 26px; background: var(--c-marine-200); margin-left: 13px; }
.regle b { position: absolute; left: 0; font-weight: 400; font-size: .6rem;
         letter-spacing: .1em; color: rgba(251,249,245,.28);
         transition: color .5s var(--ease); font-variant-numeric: tabular-nums; }
.regle span.on b { color: var(--c-marine-200); }

.maree__liste { flex: 1; min-width: 0; max-width: 660px; }
.maree__item {
  border-top: 1px solid rgba(251,249,245,.13);
  padding: clamp(.55rem, 1.6svh, 1rem) 0;
  display: flex; gap: 1.2rem; align-items: baseline; cursor: pointer;
  opacity: .30; transition: opacity .55s var(--ease), transform .55s var(--ease);
}
.maree__item:last-child { border-bottom: 1px solid rgba(251,249,245,.13); }
.maree__item.on { opacity: 1; transform: translateX(6px); }
.maree__item h3 {
  font-family: var(--f-display); font-weight: 400; color: var(--c-ivory);
  font-size: clamp(1.6rem, 3.8vw, 2.8rem); line-height: 1.04;
  margin: 0; letter-spacing: -.01em;
}
.maree__item p {
  max-height: 0; overflow: hidden; opacity: 0; margin: 0;
  color: rgba(251,249,245,.62); max-width: 44ch; font-size: var(--fs-sm); 
  transition: max-height .6s var(--ease), opacity .5s var(--ease), margin .6s var(--ease);
}
.maree__item.on p { max-height: 9rem; opacity: 1; margin-top: .45rem; }
.maree__col { flex: 1; min-width: 0; }
.maree__prix { font-size: var(--fs-xs); letter-spacing: .12em; flex: none;
  /* 28 % d'ivoire donnait 2,43:1 : un prix illisible sur la carte d'un
     institut, c'est le pire endroit où économiser du contraste. */
  color: rgba(251,249,245,.62); transition: color .5s var(--ease); }
.maree__item.on .maree__prix { color: var(--c-marine-200); }
.maree__go {
  display: inline-flex; align-items: center; gap: var(--s-2); margin-top: var(--s-3);
  font-size: var(--fs-xs); letter-spacing: .18em; text-transform: uppercase;
  color: var(--c-marine-200); max-height: 0; overflow: hidden; opacity: 0;
  transition: max-height .6s var(--ease), opacity .5s var(--ease), margin .6s var(--ease);
}
.maree__item.on .maree__go { max-height: 3rem; opacity: 1; }

/* le coefficient de marée : un vrai marqueur local, pas un ornement */
.maree__coef {
  position: absolute; right: clamp(1.25rem, 4vw, 3rem); bottom: clamp(1.25rem, 4vw, 3rem);
  z-index: 5; text-align: right; color: rgba(251,249,245,.62);
  font-size: .64rem; letter-spacing: .16em; text-transform: uppercase;
}
.maree__coef b {
  display: block; font-family: var(--f-display); font-style: italic; font-weight: 400;
  font-size: 1.5rem; color: var(--c-marine-200); letter-spacing: 0; text-transform: none;
  font-variant-numeric: tabular-nums;
}

@media (max-width: 860px) {
  /* La réglette et le coefficient sont des raffinements de desktop : sur un
     écran de 390 px ils volent la largeur au texte, qui est l'essentiel. */
  .regle, .maree__coef { display: none; }
  .maree__stage { min-height: auto; }
  .maree__bg::after {
    background: linear-gradient(180deg, rgba(6,27,41,.90) 0%, rgba(6,27,41,.82) 50%, rgba(6,27,41,.94) 100%);
  }
  /* En tactile il n'y a pas de survol : tout est lisible d'emblée. */
  .maree__item { opacity: 1; transform: none; }
  .maree__item p { max-height: 9rem; opacity: 1; margin-top: .45rem; }
  .maree__item .maree__go { max-height: 3rem; opacity: 1; }
  .maree__flot { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .maree__bg figure { clip-path: none; opacity: 0; transition: opacity .4s; }
  .maree__bg figure.on { opacity: 1; }
  .maree__flot { transition: none; }
}

/* --- 31f. Bandeau de consentement ---------------------------------------- */
/* Refuser doit être aussi simple qu'accepter : deux boutons de même taille,
   sur la même ligne, dans le même ordre de lecture. C'est exactement ce que
   la CNIL sanctionne quand ce n'est pas le cas. */
.consent {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 9998;
  background: var(--c-fond); color: var(--c-ivory);
  border-top: 1px solid rgba(169,201,220,.30);
  transform: translateY(100%); transition: transform .6s var(--ease-eau);
  box-shadow: 0 -18px 50px -30px rgba(6,27,41,.9);
}
.consent.is-on { transform: none; }
.consent__in {
  max-width: var(--wrap, 1240px); margin: 0 auto;
  padding: var(--s-5) clamp(var(--s-4), 5vw, var(--s-7));
  display: flex; flex-wrap: wrap; gap: var(--s-5) var(--s-7);
  align-items: center; justify-content: space-between;
}
.consent__txt { flex: 1 1 32ch; }
.consent__t {
  font-family: var(--f-display); font-size: var(--fs-md);
  margin: 0 0 var(--s-2); color: var(--c-ivory);
}
.consent__d { margin: 0; font-size: var(--fs-sm); color: rgba(251,249,245,.72); max-width: 68ch; }
.consent__d a { color: var(--c-marine-200); text-decoration: underline; text-underline-offset: 3px; }
.consent__act { display: flex; gap: var(--s-3); flex: none; }
.consent .btn { min-height: 44px; }
/* La règle de base .btn pose un fond gris opaque (#EFEFEF) : sans le
   neutraliser, on obtenait de l'ivoire sur du gris clair — 1,09:1, illisible.
   Mesuré par test-contraste, pas supposé. */
.consent .btn--line { border-color: rgba(251,249,245,.55); color: var(--c-ivory);
  background: transparent; }
.consent .btn--line:hover { background: rgba(251,249,245,.14); }
.consent .btn--fill { background: var(--c-ivory); color: var(--c-fond); border-color: var(--c-ivory); }
.consent .btn--fill:hover { background: var(--c-marine-200); border-color: var(--c-marine-200); }

/* la barre d'appel mobile ne doit pas passer sous le bandeau */
.consent ~ .mobile-cta { bottom: auto; }
@media (max-width: 640px) {
  .consent__act { width: 100%; }
  .consent__act .btn { flex: 1; justify-content: center; }
}
@media (prefers-reduced-motion: reduce) { .consent { transition: none; } }

/* Repli de carte : ce qu'on montre TANT QUE le consentement n'est pas donné.
   Ce n'est pas un trou — c'est le plan d'accès historique et un lien
   d'itinéraire, qui suffisent à venir à l'institut. */
.carte-repli { position: relative; background: var(--c-white); border: 1px solid var(--c-line);
  padding: var(--s-6); text-align: center; }
.carte-repli p { margin: 0 auto var(--s-4); max-width: 46ch; color: var(--c-ink-mute); font-size: var(--fs-sm); }
.carte-repli__act { display: flex; gap: var(--s-3); flex-wrap: wrap; justify-content: center; }

/* --- 31g. FAQ, tableaux de données, prose légale ------------------------- */
.faq { max-width: 78ch; }
.faq__i { border-bottom: 1px solid var(--c-line); }
.faq__i summary {
  list-style: none; cursor: pointer; padding: var(--s-5) 0;
  display: flex; align-items: baseline; gap: var(--s-4);
  font-family: var(--f-display); font-size: var(--fs-md); color: var(--c-ink);
  min-height: 44px;
}
.faq__i summary::-webkit-details-marker { display: none; }
.faq__i summary::after {
  content: ''; margin-left: auto; flex: none;
  width: 11px; height: 11px; border-right: 1px solid var(--c-marine);
  border-bottom: 1px solid var(--c-marine); transform: rotate(45deg) translate(-3px,-3px);
  transition: transform .4s var(--ease-out-3);
}
.faq__i[open] summary::after { transform: rotate(-135deg) translate(-3px,-3px); }
.faq__i summary:hover { color: var(--c-marine); }
.faq__i summary:focus-visible { outline: 2px solid var(--c-marine); outline-offset: 3px; }
.faq__r { padding: 0 0 var(--s-5); }
.faq__r p { margin: 0; max-width: 66ch; color: var(--c-ink-mute); }

.tbl { width: 100%; border-collapse: collapse; margin: var(--s-5) 0 var(--s-6); font-size: var(--fs-sm); }
.tbl th, .tbl td { text-align: left; vertical-align: top; padding: var(--s-4) var(--s-4) var(--s-4) 0;
  border-bottom: 1px solid var(--c-line); }
.tbl th { font-weight: 500; font-size: var(--fs-xs); letter-spacing: .12em;
  text-transform: uppercase; color: var(--c-marine); }
.tbl td em { font-style: normal; color: var(--c-ink-mute); font-size: .92em; display: block; }
/* Un tableau de 4 colonnes ne rentre pas sur 390 px : il défile dans son
   propre cadre plutôt que de pousser la page en travers. */
@media (max-width: 700px) {
  .tbl { display: block; overflow-x: auto; white-space: nowrap; }
  .tbl td, .tbl th { white-space: normal; min-width: 12rem; }
}

.prose h2 { margin-top: var(--s-8); }
.prose p, .prose li { max-width: 72ch; }
.prose ul { padding-left: 1.1rem; }
.prose li { margin-bottom: var(--s-3); }
.consent-etat { font-size: var(--fs-xs); color: var(--c-ink-mute); align-self: center; }

/* --- 31h. Avis clients ---------------------------------------------------- */
/* Aucun avis n'est écrit en dur : ce bloc est un réceptacle. Inventer des
   témoignages serait faux et, sur un site commercial, trompeur. */
.avis { display: grid; gap: var(--s-6); grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.avis__i { border-top: 1px solid var(--c-line); padding-top: var(--s-5); }
.avis__note { font-family: var(--f-display); font-size: var(--fs-lg); color: var(--c-marine);
  font-variant-numeric: tabular-nums; }
.avis__txt { margin: var(--s-3) 0; color: var(--c-ink); }
.avis__qui { font-size: var(--fs-xs); letter-spacing: .12em; text-transform: uppercase;
  color: var(--c-ink-mute); }
.avis-vide { border: 1px dashed var(--c-line); padding: var(--s-6); text-align: center;
  color: var(--c-ink-mute); font-size: var(--fs-sm); }

/* --- 31i. Lisibilité dans la scène sombre -------------------------------- */
/* Deux corrections mesurées par test-contraste, pas supposées :
   - les graduations à 28 % d'ivoire donnaient 2,43:1 sur le fond marine ;
   - le sur-titre « La carte » restait en --c-marine (#175A83) sur #061B29,
     soit 2,36:1 — un bleu sur un bleu.
   Le contraste passe désormais par la teinte de surface de la palette, qui
   est précisément là pour ça. */
.regle b { color: rgba(251,249,245,.62); }
.maree .label, .maree .label__num { color: var(--c-marine-200); }

/* --- 31j. Héros d'accueil : fondu enseigne / mer -------------------------- */
/* L'enseigne peinte se dépose DANS l'eau au lieu d'être posée dessus.
   Deux décisions techniques portent l'effet :

   1. `mix-blend-mode: multiply` — l'enseigne est fournie sur fond blanc, sans
      transparence. En multiply, le blanc devient neutre et disparaît : il ne
      reste que le tracé bleu et le filet bordeaux, qui se teintent de l'eau
      qu'ils recouvrent. Aucun détourage nécessaire.
   2. Un masque en dégradé sur la photo — la mer ne s'arrête pas net, elle
      s'éteint vers le haut dans le marine profond et vers le bas dans
      l'ivoire. C'est la colonne d'eau du site, appliquée au premier écran.

   La photo source fait 450 × 300 : agrandie, elle serait molle en plein cadre.
   Le parti pris l'assume — l'écume est floue par nature, et le dégradé la
   dissout avant qu'on puisse lui reprocher son piqué. */
.hero--fondu { background: var(--c-fond); }
.hero--fondu .hero__bg { overflow: hidden; }
.hero__mer {
  width: 100%; height: 100%; object-fit: cover; object-position: center 62%;
  transform: scale(1.08);
  filter: saturate(.92) contrast(1.04);
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 26%, #000 62%, transparent 96%);
          mask-image: linear-gradient(180deg, transparent 0%, #000 26%, #000 62%, transparent 96%);
}
/* le fondu vers l'ivoire du bas de page, et vers le marine du haut */
.hero--fondu .hero__bg::after {
  content: ''; position: absolute; inset: 0; z-index: 2;
  background:
    linear-gradient(180deg, rgba(6,27,41,.92) 0%, rgba(6,27,41,.35) 30%,
                            rgba(6,27,41,.42) 62%, rgba(251,249,245,.92) 92%, var(--c-ivory) 100%),
    linear-gradient(90deg, rgba(6,27,41,.72) 0%, rgba(6,27,41,.30) 46%, transparent 78%);
}

.hero__enseigne {
  position: absolute; z-index: 3; margin: 0;
  top: calc(var(--header-h) + var(--s-6)); right: clamp(1rem, 5vw, 5rem);
  width: min(46vw, 620px);
  mix-blend-mode: multiply;
  opacity: .92;
  pointer-events: none;
}
.hero__enseigne img { width: 100%; height: auto; }

/* Le texte passe devant l'enseigne et devant l'eau */
.hero--fondu .hero__inner { z-index: 4; }
.hero--fondu .hero__title, .hero--fondu .label { color: var(--c-ivory); }
.hero--fondu .lead { color: rgba(251,249,245,.82); }
.hero--fondu .hero__scroll { color: rgba(251,249,245,.62); }
.hero--fondu .hero__scroll .dot { background: rgba(251,249,245,.35); }
.hero--fondu .btn--line { color: var(--c-ivory); border-color: rgba(251,249,245,.55); background: transparent; }
.hero--fondu .btn--line:hover { background: rgba(251,249,245,.14); }
.hero--fondu .btn--fill { background: var(--c-ivory); color: var(--c-fond); border-color: var(--c-ivory); }
.hero--fondu .btn--fill:hover { background: var(--c-marine-200); border-color: var(--c-marine-200); }

@media (max-width: 860px) {
  /* En portrait, l'enseigne passerait derrière le titre : elle remonte en
     bandeau au-dessus du texte, à demi-transparente, et cède la place. */
  .hero__enseigne {
    top: calc(var(--header-h) + var(--s-4)); right: auto;
    left: 50%; transform: translateX(-50%);
    width: min(78vw, 420px); opacity: .78;
  }
  .hero--fondu .hero__bg::after {
    background:
      linear-gradient(180deg, rgba(6,27,41,.80) 0%, rgba(6,27,41,.50) 34%,
                              rgba(6,27,41,.66) 66%, rgba(251,249,245,.94) 94%, var(--c-ivory) 100%);
  }
}
@media (prefers-reduced-motion: reduce) { .hero__mer { transform: none; } }

/* --- 31k. En-tête sur héros sombre --------------------------------------- */
/* Tant que l'en-tête est transparent (avant défilement) et qu'il surplombe le
   héros en fondu, son marine se posait sur du marine : le nom de l'institut
   était illisible en haut à gauche, mesuré à l'œil sur capture. Il passe en
   ivoire tant qu'il flotte, et reprend ses couleurs dès qu'il se fige sur
   l'ivoire au défilement. */
/* Un voile sombre sous l'en-tête flottant : sans lui, l'ivoire du nom ne
   tient que si la photo charge. Si elle échoue, on obtient de l'ivoire sur
   l'ivoire — 1,00:1, invisible. Le voile garantit le contraste quoi qu'il
   arrive, et il assoit visuellement l'en-tête sur l'eau. */
body:has(.hero--fondu) .header:not(.is-stuck) {
  /* `background-color` ET `background-image` séparément : le raccourci
     `background` remet la couleur à transparent, et le voile ne tenait alors
     que par l'image — donc pas du tout si elle échoue. */
  background-color: rgba(6,27,41,.66);
  background-image: linear-gradient(180deg, rgba(6,27,41,.55) 0%, rgba(6,27,41,.10) 70%, transparent 100%);
  border-bottom-color: transparent;
}
body:has(.hero--fondu) .header:not(.is-stuck) .brand,
body:has(.hero--fondu) .header:not(.is-stuck) .menu-btn { color: var(--c-ivory); }
body:has(.hero--fondu) .header:not(.is-stuck) .menu-btn__lines i { background: var(--c-ivory); }
/* L'enseigne n'a plus besoin d'être recolorée sur fond sombre : son propre
   fond bleu pâle la détache déjà. */

/* Le bandeau de consentement masquait « Prendre rendez-vous » à la première
   visite : le premier geste du parcours commercial, caché par une formalité.
   Le héros se raccourcit tant que le bandeau est là. */
body:has(.consent) .hero--fondu { min-height: calc(100svh - 9rem); }
@media (max-width: 640px) { body:has(.consent) .hero--fondu { min-height: calc(100svh - 14rem); } }

/* --- 31j. La scène marine, applicable à une section de contenu ------------
   L'accueil avait basculé dans l'identité marée, pas le reste : les pages
   Marques, Nouveautés, Contact, FAQ et Merci restaient en ivoire plat, sans
   fond marine, sans ligne de flottaison, sans révélation montante. Vues à la
   suite de l'accueil, elles lisaient comme un autre site.

   `.nuit` porte donc maintenant tout ce qu'une section de contenu contient :
   filets, liens, cartes, chiffres, boutons. Une seule classe suffit à faire
   passer un bloc de l'écume au fond de l'eau. */
.nuit { background: var(--c-fond); color: var(--c-ivory); position: relative; }
.nuit .lead { color: rgba(251,249,245,.78); }
.nuit .muted, .nuit .caption, .nuit figcaption { color: rgba(251,249,245,.48); }
.nuit em { color: var(--c-marine-200); }

/* filets et bordures : la ligne de flottaison, pâle sur le fond */
.nuit hr,
.nuit .card, .nuit .price-block, .nuit .swap__row,
.nuit .faq__i, .nuit .tbl th, .nuit .tbl td { border-color: rgba(251,249,245,.16); }
.nuit .card { background: transparent; }

/* liens : le pâle de surface, jamais le marine moyen qui disparaît */
.nuit a { color: var(--c-marine-200); }
.nuit a:hover { color: var(--c-ivory); }
.nuit .crumbs, .nuit .crumbs a { color: rgba(251,249,245,.62); }

/* prix et chiffres : ils gardent leur poids, en pâle */
.nuit .p-val, .nuit .slide__price, .nuit .swap__stat b,
.nuit .figure b, .nuit .card__num { color: var(--c-marine-200); }
.nuit .p-dur, .nuit .p-name em { color: rgba(251,249,245,.55); }
.nuit .swap__stat { background: var(--c-fond); }

/* boutons : le contour pâle, le plein en ivoire — comme le bandeau */
.nuit .btn { color: var(--c-ivory); border-color: rgba(251,249,245,.45); background: transparent; }
.nuit .btn:hover { background: rgba(251,249,245,.12); }
.nuit .btn--fill { background: var(--c-ivory); color: var(--c-fond); border-color: var(--c-ivory); }
.nuit .btn--fill:hover { background: var(--c-marine-200); border-color: var(--c-marine-200); }

/* accordéon FAQ dans la scène */
.nuit .faq__i summary { color: var(--c-ivory); }
.nuit .faq__i summary:hover { color: var(--c-marine-200); }
.nuit .faq__i summary::after { border-color: var(--c-marine-200); }
.nuit .faq__r p { color: rgba(251,249,245,.62); }

/* La ligne de flottaison ferme la scène par le haut : c'est le trait qui
   signe le site, et il marque ici le passage de l'écume à l'eau profonde. */
.nuit::before {
  content: ''; position: absolute; top: 0; left: 0; right: 0; height: 1px;
  background: var(--c-marine-200); opacity: .45;
}

/* Les images d'une scène marine se découvrent par le bas, comme l'estran. */
.nuit .card__media img, .nuit .swap__visual img, .nuit .split__media img {
  filter: saturate(.92) contrast(1.04);
}

/* Le repli de carte gardait son fond blanc dans la scène marine : le bouton
   « Afficher la carte » y devenait ivoire sur blanc — 1,05:1, invisible.
   Mesuré par test-contraste. Le repli suit désormais la scène. */
.nuit .carte-repli { background: transparent; border-color: rgba(251,249,245,.22); }
.nuit .carte-repli p { color: rgba(251,249,245,.62); }

/* ==========================================================================
   32. LES PARTIS PRIS — la remontée
   --------------------------------------------------------------------------
   L'ancienne section « Ce qu'on refuse, ce qu'on a choisi » était en gris
   clair (section--cream), coincée ENTRE deux blocs marine : l'échelle de
   marée avant, les chiffres après. Elle ouvrait un trou lumineux au milieu
   de la colonne d'eau — c'était ça, la rupture de continuité.

   Elle reste donc immergée, et devient le raccord : le fond part exactement
   du #061B29 où finit l'échelle de marée et arrive exactement au marine des
   chiffres. Aucune couture visible entre les trois sections.

   La mise en scène suit le propos : ce qu'on refuse est barré et reste au
   fond, ce qu'on a choisi remonte en grand. Typographie surdimensionnée et
   grands blancs — le registre « Exaggerated Minimalism » relevé par le skill
   /ui-ux-pro-max, qui est déjà celui du Bodoni de ce site.
   ========================================================================== */
.partis {
  position: relative;
  /* Fond solide SOUS le dégradé : un `background` en dégradé laisse
     `backgroundColor` transparent, si bien que l'audit de contraste remontait
     jusqu'à l'ivoire du body et croyait lire de l'ivoire sur de l'ivoire.
     C'est aussi le repli correct si le dégradé ne peint pas. */
  background-color: var(--c-fond);
  background-image: linear-gradient(180deg,
    var(--c-fond) 0%, #071f2e 38%, #0a2b41 72%, var(--c-marine-ink) 100%);
  color: var(--c-ivory);
  padding: var(--s-10) 0;
}
.partis .label { color: var(--c-marine-200); }
.partis .h2 { color: var(--c-ivory); }

.partis__liste { margin-top: var(--s-9); }

.parti {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
  gap: var(--s-6) clamp(var(--s-6), 5vw, var(--s-9));
  align-items: start;
  padding: var(--s-8) 0;
  border-top: 1px solid rgba(169,201,220,.28);   /* la ligne de flottaison */
  position: relative;
}
.parti:last-child { border-bottom: 1px solid rgba(169,201,220,.28); }

/* --- ce qu'on refuse : barré, au fond ----------------------------------- */
/* Pas de « ✕ » : un caractère typographique n'est pas une icône, et les
   lecteurs d'écran l'annoncent. Le refus est dit par une vraie rature. */
.parti__refus {
  font-size: var(--fs-xs); letter-spacing: .18em; text-transform: uppercase;
  color: rgba(251,249,245,.55); margin: 0 0 var(--s-3);
  display: inline-block; position: relative;
}
.parti__refus::after {
  content: ''; position: absolute; left: 0; right: 0; top: 52%;
  height: 1px; background: rgba(251,249,245,.55);
  transform: scaleX(0); transform-origin: left;
  transition: transform .55s var(--ease-out-3) .15s;
}
.parti.in .parti__refus::after,
.is-ready .parti__refus::after { transform: scaleX(1); }

/* --- ce qu'on a choisi : remonte, en grand ------------------------------ */
.parti__choix {
  font-family: var(--f-display); font-weight: 400; color: var(--c-ivory);
  font-size: clamp(1.9rem, 4.4vw, 3.4rem); line-height: 1.02;
  letter-spacing: -.015em; margin: 0;
}
.parti__choix em { font-style: italic; color: var(--c-marine-200); }

.parti__txt { color: rgba(251,249,245,.72); margin: 0 0 var(--s-5); max-width: 52ch; }

/* le chiffre : l'ancre visuelle de chaque parti pris */
.parti__chiffre {
  display: flex; align-items: baseline; gap: var(--s-3);
  margin-bottom: var(--s-5);
}
.parti__chiffre b {
  font-family: var(--f-display); font-weight: 400;
  font-size: clamp(2.6rem, 6vw, 4.6rem); line-height: .9;
  color: var(--c-marine-200); font-variant-numeric: tabular-nums;
}
.parti__chiffre span {
  font-size: var(--fs-xs); letter-spacing: .16em; text-transform: uppercase;
  color: rgba(251,249,245,.55);
}

.parti .btn {
  color: var(--c-ivory); border-color: rgba(251,249,245,.45); background: transparent;
}
.parti .btn:hover { background: rgba(251,249,245,.12); }

/* --- entrée : tout monte, jamais de côté -------------------------------- */
@supports (animation-timeline: view()) {
  .parti {
    animation: montee linear both;
    animation-timeline: view();
    animation-range: entry 4% cover 26%;
  }
}
@supports not (animation-timeline: view()) {
  .parti { opacity: 0; transform: translateY(22px);
           transition: opacity .45s var(--ease-out-3), transform .45s var(--ease-out-3); }
  .parti.in { opacity: 1; transform: none; }
}

@media (max-width: 760px) {
  .parti { grid-template-columns: 1fr; gap: var(--s-4); padding: var(--s-7) 0; }
  .parti__chiffre { margin-bottom: var(--s-4); }
}
@media (prefers-reduced-motion: reduce) {
  .parti { animation: none !important; opacity: 1; transform: none; }
  .parti__refus::after { transform: scaleX(1); transition: none; }
}

/* ==========================================================================
   33. LE BON CADEAU — la descente
   --------------------------------------------------------------------------
   Même diagnostic que pour les partis pris : la section était en gris clair
   (section--cream), coincée entre la sélection en ivoire et « Avant de venir »
   en marine. Elle ne raccordait rien et cassait net sur le bloc sombre suivant.

   Elle devient donc la descente : le fond part de l'ivoire exact de la section
   précédente et arrive au marine exact de la suivante. La marée monte et
   descend deux fois par jour — la page fait de même.

   Le contenu vit dans la partie basse, déjà sombre, pour que le contraste soit
   constant et vérifiable. Et l'image de pochettes cadeaux (500 × 293, faible)
   disparaît : le propos est « offrez un moment, pas un objet » — montrer
   l'objet le contredisait.
   ========================================================================== */
.cadeau {
  position: relative;
  /* La bascule est RAPIDE : le raccord clair n'est qu'une couture, pas une
     moitié de section. Étalé sur 46 %, il laissait le titre en ivoire tomber
     sur un bleu pâle — illisible, constaté en capture. L'eau profonde est
     atteinte à 40 %, bien avant le premier mot. */
  background: linear-gradient(180deg,
    var(--c-ivory) 0%, #dce6ee 6%, #7d9cb2 14%, #23516f 22%, #123f5c 27%,
    var(--c-marine-ink) 33%, var(--c-marine-ink) 100%);
  padding: var(--s-9) 0 var(--s-10);
}
/* le contenu commence une fois l'eau profonde atteinte */
.cadeau__in { padding-top: clamp(var(--s-8), 12vw, var(--s-10)); }
.cadeau .label { color: var(--c-marine-200); }
.cadeau .h2, .cadeau .display { color: var(--c-ivory); }
.cadeau .lead { color: rgba(251,249,245,.82); }
.cadeau p { color: rgba(251,249,245,.72); }

.cadeau__grid {
  display: grid; grid-template-columns: minmax(0,1fr) minmax(0,1fr);
  gap: var(--s-6) clamp(var(--s-7), 6vw, var(--s-10));
  align-items: start; margin-top: var(--s-8);
}

/* Trois formules, en graduations — le même objet graphique que l'échelle
   de marée : un filet, un chiffre pâle, un intitulé qui porte. */
.formule {
  display: grid; grid-template-columns: 2.6rem minmax(0,1fr);
  gap: var(--s-4); align-items: baseline;
  padding: var(--s-5) 0; border-top: 1px solid rgba(169,201,220,.28);
}
.formule:last-child { border-bottom: 1px solid rgba(169,201,220,.28); }
.formule__n {
  font-family: var(--f-display); font-style: italic; color: var(--c-marine-200);
  font-size: var(--fs-md); font-variant-numeric: tabular-nums;
}
.formule__t {
  font-family: var(--f-display); font-weight: 400; color: var(--c-ivory);
  font-size: clamp(1.25rem, 2.6vw, 1.7rem); line-height: 1.1; margin: 0 0 var(--s-2);
}
.formule__d { font-size: var(--fs-sm); color: rgba(251,249,245,.68); margin: 0; }

.cadeau .btn { color: var(--c-ivory); border-color: rgba(251,249,245,.45); background: transparent; }
.cadeau .btn:hover { background: rgba(251,249,245,.12); }
.cadeau .btn--fill { background: var(--c-ivory); color: var(--c-marine-ink); border-color: var(--c-ivory); }
.cadeau .btn--fill:hover { background: var(--c-marine-200); border-color: var(--c-marine-200); }

@supports (animation-timeline: view()) {
  .formule { animation: montee linear both; animation-timeline: view();
             animation-range: entry 4% cover 26%; }
}
@supports not (animation-timeline: view()) {
  .formule { opacity: 0; transform: translateY(22px);
             transition: opacity .45s var(--ease-out-3), transform .45s var(--ease-out-3); }
  .formule.in { opacity: 1; transform: none; }
}

@media (max-width: 860px) {
  .cadeau__grid { grid-template-columns: 1fr; gap: var(--s-6); }
  .cadeau__in { padding-top: clamp(var(--s-7), 22vw, var(--s-9)); }
}
@media (prefers-reduced-motion: reduce) {
  .formule { animation: none !important; opacity: 1; transform: none; }
}

/* ==========================================================================
   34. LE LOGO — la vraie enseigne
   --------------------------------------------------------------------------
   Le bandeau portait un mark dessiné pour l'occasion (cercle + vague + goutte)
   pendant que le héros affichait l'enseigne réelle : deux marques différentes
   sur la même page. L'enseigne peinte est le seul actif de marque authentique
   du dossier — c'est elle qui monte en haut à gauche.

   Elle remplace AUSSI le nom en Bodoni qui l'accompagnait : l'enseigne porte
   déjà « Institut de Beauté Azurine ». Le garder revenait à écrire le nom deux
   fois côte à côte.

   Testée à 56 px de haut : le lettrage reste lisible. Les coins blancs autour
   de l'arc ont été rendus transparents par remplissage depuis les bords —
   sinon un rectangle blanc se serait détaché sur l'ivoire du bandeau.
   ========================================================================== */
.brand__logo {
  height: 56px; width: auto; display: block;
  transition: opacity .35s var(--ease-out-2);
}
.brand:hover .brand__logo { opacity: .82; }
.brand { gap: 0; }

/* Sur l'overlay ouvert et sur les fonds sombres, l'enseigne garde son propre
   fond bleu pâle : elle reste lisible sans inversion. */
.menu-open .brand__logo { opacity: 1; }

/* Loader : même enseigne, plus grande, le temps du chargement. */
img.loader__mark {
  height: auto; width: min(240px, 54vw);
  margin-inline: auto;
}

@media (max-width: 860px) {
  /* Le bandeau se resserre : l'enseigne suit, sans jamais passer sous le
     seuil où son lettrage devient illisible (44 px mesurés). */
  .brand__logo { height: 46px; }
}
@media (max-width: 380px) {
  .brand__logo { height: 40px; }
}
@media (prefers-reduced-motion: reduce) {
  .brand__logo { transition: none; }
}

/* L'ancre d'un onglet est un repère invisible placé en tête de panneau :
   elle donne au lien profond un point d'arrivée qui tient compte de l'en-tête
   fixe, sans ajouter d'espace visible. */
.ancre-onglet {
  display: block; height: 0;
  scroll-margin-top: calc(var(--header-h) + var(--s-5));
}

/* --- Onglets en mode ciblé ------------------------------------------------
   Arriver par un lien « voir les tarifs » n'affiche que la prestation visée.
   L'onglet restant cesse d'être un onglet — il devient le titre de ce qu'on
   regarde — et un retour discret ramène à la carte complète. */
.tabs--ciblee { justify-content: flex-start; }
.tabs--ciblee .tab[aria-selected="true"] {
  background: transparent; color: var(--c-ink); border-color: transparent;
  padding-left: 0; cursor: default; pointer-events: none;
}
.tabs__retour {
  margin-left: auto; background: transparent; border: 0; cursor: pointer;
  font: inherit; font-size: var(--fs-xs); letter-spacing: .16em;
  text-transform: uppercase; color: var(--c-marine);
  display: inline-flex; align-items: center; gap: var(--s-2);
  min-height: 44px; padding: 0 var(--s-2);
  border-bottom: 1px solid transparent;
  transition: border-color .35s var(--ease-out-2), color .35s var(--ease-out-2);
}
.tabs__retour::before { content: '←'; }
.tabs__retour:hover { color: var(--c-ink); border-bottom-color: var(--c-marine); }
.tabs__retour:focus-visible { outline: 2px solid var(--c-marine); outline-offset: 3px; }
@media (max-width: 640px) {
  .tabs__retour { margin-left: 0; width: 100%; justify-content: flex-start; }
}

/* --- Bandeau de maquette (ajouté par outils/depersonnaliser-institut.py) ---
   Volontairement impossible à confondre avec le site : un visiteur ne doit
   jamais croire qu'il a affaire à un institut réel. */
.bandeau-maquette {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 9000;
  background: #123D5C;
  color: #FBF9F5;
  font-family: system-ui, -apple-system, sans-serif;
  font-size: 13px;
  line-height: 1.5;
  text-align: center;
  padding: 10px 16px;
  box-shadow: 0 -6px 20px rgba(0, 0, 0, .25);
}
/* Réserve sous le contenu : sans elle, le bandeau masque le pied de page. */
body { padding-bottom: 52px; }
.bandeau-maquette strong { color: #FFFFFF; }

/* --- Cibles tactiles (WCAG 2.5.8) --------------------------------------
   Les liens de pied de page et les liens utilitaires mesuraient 20 px de
   haut : sous le seuil AA de 24 px. Relevés par outils/verifier-accessibilite.mjs.
   ---------------------------------------------------------------------- */
.maree__go, .crumbs a, .pied a, .pied__liens a, footer a, .legal a,
a[href^="tel:"], a[href^="mailto:"], .contact__lien, a.lien {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
}
