/* Petites animations gérées en JS vanilla (remplacent framer-motion) :
   révélation au scroll, entrée du hero, apparition des bulles de chat et
   de la modale de prestation. Tout le reste vient de style.css (bundle
   compilé du site Next.js d'origine) — on ne touche pas à ces classes. */

.reveal-init {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity .75s cubic-bezier(.22,1,.36,1), transform .75s cubic-bezier(.22,1,.36,1);
}
.reveal-init.in-view { opacity: 1; transform: translateY(0); }

.hero-cta { opacity: 0; animation: heroCta .8s .3s cubic-bezier(.22,1,.36,1) forwards; }
.hero-row { opacity: 0; animation: heroRow 1s .45s ease forwards; }
@keyframes heroCta { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: translateY(0); } }
@keyframes heroRow { from { opacity: 0; } to { opacity: 1; } }

.services-modal-backdrop { opacity: 0; animation: fadeIn .25s ease forwards; }
.services-modal { opacity: 0; transform: scale(.97); animation: modalIn .3s cubic-bezier(.22,1,.36,1) forwards; }
@keyframes fadeIn { to { opacity: 1; } }
@keyframes modalIn { to { opacity: 1; transform: scale(1); } }

.chat-bubble, .chat-card, .chat-typing { animation: bubbleIn .3s cubic-bezier(.22,1,.36,1) both; }
@keyframes bubbleIn { from { opacity: 0; transform: translateY(8px) scale(.98); } to { opacity: 1; transform: translateY(0) scale(1); } }

@media (prefers-reduced-motion: reduce) {
  .reveal-init, .hero-cta, .hero-row, .services-modal-backdrop, .services-modal, .chat-bubble, .chat-card, .chat-typing {
    animation: none !important; transition: none !important; opacity: 1 !important; transform: none !important;
  }
}

/* ---- Contenus riches gérés depuis l'espace admin -------------------------
   Les paragraphes héritent déjà du style de leur section ; on ne définit ici
   que ce que l'éditeur peut produire en plus : listes, liens, emphase. */
.rich-body > :first-child { margin-top: 1.8rem; }
.rich-body ul, .rich-body ol { max-width: 32rem; margin: 1.1rem 0 0; padding-left: 1.2rem; color: var(--muted); line-height: 1.8; }
.rich-body li + li { margin-top: .35rem; }
.rich-body ul { list-style: disc; }
.rich-body ol { list-style: decimal; }
.rich-body strong { color: var(--bordeaux); font-weight: 600; }
.rich-body em { font-style: italic; }
.rich-body a, blockquote a, .footer-tag a { text-decoration: underline; text-underline-offset: .18em; }
.rich-body a:hover, blockquote a:hover, .footer-tag a:hover { opacity: .7; }

/* ---- Hero : visuel dédié au mobile --------------------------------------
   <picture> est inline par défaut : sans cela l'image perdrait sa hauteur. */
.hero-media picture { display: block; width: 100%; height: 100%; }
@media (max-width: 767px) {
  /* Le visuel portrait est déjà cadré pour le mobile : on recentre. */
  .hero-media img { object-position: center center; }
}

/* ==========================================================================
   ROBUSTESSE RESPONSIVE
   Deux mécanismes CSS, invisibles tant que le contenu est court, font éclater
   la mise en page dès qu'un texte inhabituel arrive. Corrigés ici à la source
   plutôt que page par page.
   ========================================================================== */

/* 1. Un mot, une URL ou une chaîne collée sans espace impose sa largeur à tout
      son conteneur. Sans coupure autorisée, la page entière s'élargit. */
:where(p, h1, h2, h3, h4, h5, li, blockquote, dd, dt, figcaption, label, td, th, .eyebrow) {
  overflow-wrap: break-word;
}
.rich-body, .rich-body p, .footer-tag, blockquote { overflow-wrap: anywhere; }

/* 2. Une piste « 1fr » vaut « minmax(auto, 1fr) » : son minimum est le contenu
      le plus large et insécable, jamais zéro. Idem pour un enfant de flex.
      Sans min-width:0, la colonne refuse de se réduire et déborde. */
.philosophy > *, .feature > *, .footer-top > *, .categories-grid > *,
.pin-gallery-sticky > *, .gallery-grid > *, .booking-card > *, .chat-days > *,
.row2 > *, .philosophy-copy > *, .feature-copy > * {
  min-width: 0;
}

/* 3. Filet de sécurité : aucune image ne doit pouvoir dépasser son conteneur. */
img, video, svg { max-width: 100%; }

/* ---- Réservation : densité mobile ---------------------------------------
   Trois conteneurs imbriqués appliquaient chacun une marge pensée pour le
   bureau. Sur un écran de 375 px il ne restait que 223 px utiles, soit des
   jours de calendrier larges de 27 px. Les valeurs desktop sont inchangées. */
@media (max-width: 640px) {
  .chat-booking { padding-left: .75rem; padding-right: .75rem; padding-top: 2.5rem; }
  .chat-log { padding: 1.25rem 1rem; min-height: 24rem; }
  .chat-card { padding: .875rem .8rem; }
  .chat-days { gap: .25rem; }
}

/* ---- Cibles tactiles ----------------------------------------------------
   Appliqué au pointeur grossier uniquement : le rendu à la souris ne bouge
   pas. Les liens de pied de page faisaient 17 px de haut. */
@media (pointer: coarse) {
  .chat-chip, .chat-day, .chat-time, .chat-cta { min-height: 44px; }
  .chat-day { display: flex; flex-direction: column; align-items: center; justify-content: center; }
  .footer-col a, .nav-overlay-foot a { display: inline-block; padding-block: .55rem; }
  .footer-col span { display: inline-block; padding-block: .3rem; }
  .text-link { display: inline-flex; align-items: center; min-height: 44px; }
}

/* ---- Formulaire de réservation sur mobile -------------------------------
   Sous 16px, iOS Safari zoome la page dès qu'un champ prend le focus et ne
   dézoome jamais : la saisie devient pénible et le reste de la page sort de
   l'écran. 16px est le seuil exact qui désactive ce comportement. */
@media (max-width: 640px) {
  .chat-form input[type=text], .chat-form input[type=email], .chat-form input[type=tel],
  .chat-form input:not([type]), .chat-form textarea {
    font-size: 16px;
    min-height: 44px;
    padding: .6rem .7rem;
  }
  .chat-form textarea { min-height: 5rem; }
  /* Deux champs côte à côte deviennent illisibles sous 400px. */
  .row2 { grid-template-columns: 1fr; }
}
/* ---- Case à cocher du consentement ---------------------------------------
   La règle générale « .chat-form input » impose width:100%, un fond, une
   bordure et du padding : appliquée aussi à la case à cocher, elle en faisait
   un bloc large de la moitié de la ligne, avec la coche dessinée au milieu et
   le texte repoussé loin à droite. On la sort de ce moule. */
.chat-form input[type=checkbox] {
  width: 1.125rem;
  height: 1.125rem;
  flex: 0 0 auto;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  accent-color: var(--bordeaux);
  cursor: pointer;
}
.chat-form .consent {
  align-items: center;
  gap: .55rem;
  cursor: pointer;
  padding-block: .25rem;
}
.chat-form .consent span { flex: 1; min-width: 0; }

@media (pointer: coarse) {
  /* Une case de 13px n'est pas atteignable au doigt. */
  .chat-form input[type=checkbox] { width: 1.375rem; height: 1.375rem; }
  .chat-form .consent { padding-block: .5rem; }
}

/* ---- Chat de réservation : valeurs saisies très longues ------------------
   Un nom ou un email sans espace débordait de sa bulle et sortait du cadre.
   Le conteneur masque le dépassement : le texte était donc perdu, pas juste
   décalé. */
.chat-bubble, .chat-card, .chat-recap, .chat-recap *, .chat-success {
  overflow-wrap: anywhere;
  min-width: 0;
}

/* ---- Titres de page sur très petits écrans -------------------------------
   Un enfant de flex a min-width:auto : il refuse de descendre sous la largeur
   de son mot le plus long. « Réservation » en 57,6px mesure 324px et poussait
   la page au-delà de 320px de large. */
.inner-hero > *, .hero-row > *, .footer-brand-block > *, .feature-copy > *,
.nav > *, .quote > * { min-width: 0; }

@media (max-width: 400px) {
  /* En dessous de cette largeur le titre doit céder, sinon c'est la page. */
  .inner-hero h1 { font-size: clamp(2.3rem, 13vw, 3.6rem); }
}

/* ==========================================================================
   PRESTATIONS — section unique
   Les anciennes tuiles de catégories faisaient doublon avec la grille photo :
   elles ne servaient qu'à pointer vers la section juste en dessous. Elles sont
   devenues les filtres de cette grille.
   ========================================================================== */
.services-title {
  margin: .6rem 0 0;
  font: 400 clamp(2.6rem, 4.6vw, 4.4rem)/1.05 var(--font-editorial), serif;
  letter-spacing: -.02em;
  text-wrap: balance;
}

.service-filters {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  margin-top: 2.6rem;
}
.service-chip {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  padding: .6rem 1rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: transparent;
  color: var(--muted);
  font: 400 .85rem var(--font-ui), sans-serif;
  cursor: pointer;
  transition: background-color .3s var(--ease), border-color .3s var(--ease), color .3s var(--ease);
}
.service-chip svg { width: 16px; height: 16px; opacity: .7; flex: 0 0 auto; transition: opacity .3s var(--ease); }
.service-chip .n { font-size: .66rem; font-weight: 600; letter-spacing: .04em; opacity: .55; }
.service-chip:hover { border-color: var(--muted); color: var(--bordeaux); }
.service-chip:hover svg { opacity: 1; }
.service-chip[aria-pressed="true"] {
  background: var(--bordeaux);
  border-color: var(--bordeaux);
  color: var(--ivoire);
}
.service-chip[aria-pressed="true"] svg { opacity: 1; }
.service-chip[aria-pressed="true"] .n { opacity: .7; }

/* La carte réapparaît en fondu montant quand un filtre la ramène. */
.services-showcase-card[hidden] { display: none; }
.services-showcase-card.filtering { animation: serviceRise .42s cubic-bezier(.22,1,.36,1) both; }
@keyframes serviceRise { from { opacity: 0; transform: translateY(14px); } }

.services-empty {
  grid-column: 1 / -1;
  margin: 0;
  padding: 3.5rem 1rem;
  text-align: center;
  color: var(--muted);
  font-size: .9rem;
  border: 1px dashed var(--line);
  border-radius: .5rem;
}

@media (pointer: coarse) { .service-chip { min-height: 44px; } }
@media (max-width: 600px) { .service-filters { margin-top: 2rem; } }

@media (prefers-reduced-motion: reduce) { .services-showcase-card.filtering { animation: none; } }

/* ==========================================================================
   ÉCHELLE — resserrage sur grand écran
   Les tailles et les marges étaient pilotées par des clamp() dont le plafond
   se déclenchait dès 1400px : 160px de vide par section et des titres de 70 à
   136px. Sur un écran large la page faisait plus de six hauteurs d'écran.
   Les valeurs basses (mobile) sont conservées : seuls les plafonds baissent.
   ========================================================================== */

/* Rythme vertical des sections */
.shell { padding: clamp(3.5rem, 7vw, 6.5rem) var(--gutter); }
.quote { padding: clamp(3.5rem, 7vw, 6.5rem) var(--gutter); }
.cta   { padding: clamp(3.5rem, 7.5vw, 7rem) var(--gutter); }
.philosophy-copy { padding: clamp(2.5rem, 4vw, 4.5rem) clamp(1.5rem, 5vw, 5rem); }
.site-footer { padding-top: clamp(3rem, 5vw, 4.5rem); }
.footer-top { padding-bottom: clamp(2rem, 3.5vw, 3rem); gap: clamp(1.5rem, 3vw, 2.5rem); }

/* Échelle typographique : mêmes proportions, plafonds plus bas */
.philosophy-copy h2,
.feature-copy h2,
.services-title { font-size: clamp(2.1rem, 3.4vw, 3.4rem); }
.quote blockquote { font-size: clamp(1.7rem, 3.2vw, 2.8rem); }
.cta h2 { font-size: clamp(2.6rem, 6.5vw, 5.5rem); }

/* Cartes de prestation : une rangée de moins à parcourir */
.services-showcase-card { height: clamp(16rem, 22vw, 19rem); }
.services-showcase { padding-bottom: clamp(2.5rem, 5vw, 4rem); }

/* Bandeau photo de l'institut */
.institut-band { max-height: 26rem; }

/* Au-delà de 1500px, trois colonnes laissaient une rangée presque vide et
   allongeaient la page pour rien : quatre colonnes tirent mieux parti de la
   largeur et retirent une rangée à parcourir. */
@media (min-width: 1500px) {
  .services-showcase { grid-template-columns: repeat(4, 1fr); }
}

/* ==========================================================================
   PIED DE PAGE
   L'ancien mot « ANA RITA » était un texte aligné à gauche à 176px : il
   laissait la moitié droite du bloc vide. Il est désormais tracé en SVG sur
   toute la largeur, en filigrane, et sert de ligne de signature.
   ========================================================================== */
.footer-mark { display: flex; align-items: center; gap: .9rem; }
.footer-mark strong {
  font: 400 1.05rem/1 var(--font-editorial), serif;
  letter-spacing: .12em;
  color: var(--ivoire);
}
.footer-brand-block { gap: 1.1rem; }

.footer-rule { height: 1px; background: #f8f6ef24; border: 0; margin: 0; }

.footer-word { width: 100%; margin-top: clamp(1.5rem, 3vw, 2.5rem); overflow: hidden; line-height: 0; }
.footer-word svg { display: block; width: 100%; height: auto; }
.footer-word text {
  font-family: var(--font-editorial), Georgia, serif;
  fill: var(--ivoire);
  opacity: .14;
}

.footer-bottom { padding-top: clamp(1rem, 2vw, 1.75rem); }
.footer-legal { display: flex; gap: 1.25rem; flex-wrap: wrap; }
.footer-legal a { color: #f8f6ef80; }
.footer-legal a:hover { color: var(--ivoire); }

@media (pointer: coarse) { .footer-legal a { padding-block: .4rem; } }

/* La colonne « Suivez-nous » disparaît tant qu'aucun réseau n'est renseigné.
   Une grille à quatre colonnes fixes laisserait alors un vide à droite : en
   flex, les colonnes restantes se répartissent toute la largeur. */
.footer-top {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(1.5rem, 3vw, 3rem);
  padding-bottom: clamp(2rem, 3.5vw, 3rem);
  border-bottom: 0;
}
.footer-brand-block { flex: 1 1 17rem; }
.footer-col { flex: 1 1 10rem; }

/* ==========================================================================
   RÉSERVATION — choix des soins
   Les pastilles de texte demandaient de lire sept libellés pour choisir. La
   photo fait le travail beaucoup plus vite, et l'état sélectionné devient
   lisible d'un coup d'œil.
   ========================================================================== */
.chat-picks {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
  gap: .6rem;
  align-self: stretch;
  width: 100%;
}
.chat-pick {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: .6rem;
  background: #fff;
  text-align: left;
  cursor: pointer;
  overflow: hidden;
  transition: border-color .2s var(--ease), box-shadow .2s var(--ease), transform .2s var(--ease);
}
.chat-pick:hover { border-color: var(--bordeaux); transform: translateY(-2px); }
.chat-pick:focus-visible { outline: 2px solid var(--bordeaux); outline-offset: 2px; }

.chat-pick-media {
  position: relative;
  display: block;
  aspect-ratio: 4 / 3;
  background: var(--nude);
  overflow: hidden;
}
.chat-pick-media img {
  width: 100%; height: 100%;
  object-fit: cover; display: block;
  transition: transform .45s var(--ease);
}
.chat-pick:hover .chat-pick-media img { transform: scale(1.05); }

/* Pastille de sélection : posée sur la photo, donc visible sans relire le nom. */
.chat-pick-check {
  position: absolute;
  top: .4rem; right: .4rem;
  width: 1.5rem; height: 1.5rem;
  border-radius: 50%;
  background: var(--bordeaux);
  color: var(--ivoire);
  display: flex; align-items: center; justify-content: center;
  opacity: 0; transform: scale(.6);
  transition: opacity .2s var(--ease), transform .25s var(--ease);
}
.chat-pick-check svg { width: 12px; height: 12px; }

.chat-pick-body { display: block; padding: .55rem .65rem .65rem; }
.chat-pick-name {
  display: block;
  font: 500 .8rem/1.3 var(--font-ui), sans-serif;
  color: var(--bordeaux);
  overflow-wrap: anywhere;
}
.chat-pick-meta {
  display: block;
  margin-top: .2rem;
  font-size: .72rem;
  color: var(--muted);
}

/* État sélectionné : bordure, ombre portée douce et pastille visible. */
.chat-pick.picked {
  border-color: var(--bordeaux);
  box-shadow: 0 0 0 1px var(--bordeaux);
}
.chat-pick.picked .chat-pick-check { opacity: 1; transform: scale(1); }

.chat-cta--picks { align-self: stretch; margin-top: .5rem; }

@media (max-width: 640px) {
  .chat-picks { grid-template-columns: repeat(auto-fill, minmax(8.5rem, 1fr)); gap: .5rem; }
  .chat-pick-name { font-size: .78rem; }
}
@media (pointer: coarse) { .chat-pick { min-height: 44px; } }
@media (prefers-reduced-motion: reduce) {
  .chat-pick, .chat-pick-media img, .chat-pick-check { transition: none; }
  .chat-pick:hover { transform: none; }
}

/* ==========================================================================
   RÉSERVATION — choix du jour et de l'heure
   Une seule rangée de sept boutons sans mois ne disait ni où l'on se trouve
   dans le calendrier, ni quelles autres dates étaient possibles. La grille
   reprend la forme d'un calendrier sur trois semaines.
   ========================================================================== */
.chat-cal-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}
.chat-cal-head .lbl { margin-bottom: 0; }
.chat-cal-month {
  font-size: .72rem;
  color: var(--muted);
  text-transform: capitalize;
}

.chat-weekdays {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: .35rem;
  margin: .8rem 0 .35rem;
}
.chat-weekdays span {
  text-align: center;
  font-size: .6rem;
  font-weight: 600;
  letter-spacing: .06em;
  color: var(--muted);
  opacity: .7;
}

.chat-days { grid-template-columns: repeat(7, 1fr); }
.chat-day-empty { aspect-ratio: 1; }

.chat-day {
  gap: .1rem;
  transition: background-color .18s var(--ease), border-color .18s var(--ease),
              color .18s var(--ease), transform .18s var(--ease);
}
.chat-day .n { font-weight: 600; font-variant-numeric: tabular-nums; }
.chat-day:hover { border-color: var(--bordeaux); transform: translateY(-1px); }
.chat-day:focus-visible { outline: 2px solid var(--bordeaux); outline-offset: 2px; }

/* Créneaux : le moment de la journée avant l'heure précise. */
.chat-times { flex-direction: column; gap: .7rem; align-items: stretch; }
.chat-times-lbl { margin: 0; text-transform: capitalize; }
.chat-slot-group { display: flex; align-items: center; gap: .7rem; flex-wrap: wrap; }
.chat-slot-when {
  flex: 0 0 5.2rem;
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted);
}
.chat-slot-row { display: flex; flex-wrap: wrap; gap: .4rem; flex: 1; }
.chat-time {
  transition: background-color .18s var(--ease), border-color .18s var(--ease), color .18s var(--ease);
}
.chat-time:hover { border-color: var(--bordeaux); }
.chat-time.picked { background: var(--bordeaux); border-color: var(--bordeaux); color: var(--ivoire); }

@media (max-width: 480px) {
  .chat-slot-when { flex-basis: 100%; }
  .chat-day { font-size: .66rem; }
}
@media (prefers-reduced-motion: reduce) {
  .chat-day, .chat-time { transition: none; }
  .chat-day:hover { transform: none; }
}

/* Sept colonnes dans 375px laissaient des cases de 34px, sous le seuil
   confortable au doigt. On récupère de la largeur sur les écarts et on donne
   de la hauteur plutôt que de garder un carré parfait. */
@media (max-width: 560px) {
  .chat-days, .chat-weekdays { gap: .2rem; }
  .chat-day {
    aspect-ratio: auto;
    min-height: 44px;
    padding: .25rem 0;
  }
  .chat-day-empty { aspect-ratio: auto; min-height: 44px; }
  .chat-day .d { font-size: .52rem; }
  .chat-day .n { font-size: .82rem; }
}

/* Le logo est désormais une image, plus un tracé SVG approximatif : on fige
   ses dimensions pour qu'il ne provoque aucun décalage au chargement. */
.logo-mark { display: block; border-radius: 50%; object-fit: contain; }
.logo-mark-wrap { display: block; flex: 0 0 auto; line-height: 0; }

/* La mention du lieu a quitté le hero : elle faisait doublon avec le pied de
   page. « DÉCOUVRIR » reste aligné à droite comme avant. */
/* Bas du hero : l'appel à l'action et « DÉCOUVRIR » sur une seule ligne.
   Le repère vertical animé de « DÉCOUVRIR » est plus haut que le lien : c'est
   le bas des deux blocs qui est aligné, pas leur milieu. */
.hero-scroll { margin-left: auto; }
.hero-row { align-items: flex-end; }
.hero-row .hero-cta { margin: 0; padding: 0; }
.hero-scroll i { margin-bottom: -.15rem; }

@media (max-width: 900px) {
  .hero-scroll { margin-left: 0; }
  /* En colonne, « DÉCOUVRIR » repasse sous le lien, sans l'écarter du bord. */
  .hero-row { align-items: flex-start; gap: 1.6rem; }
}

/* ==========================================================================
   PRÉCHARGEUR « LE SCEAU »
   L'anneau se trace autour de l'emblème, puis le voile se lève.
   Il ne paraît qu'à la première page d'une visite (voir le script du <head>).
   ========================================================================== */

/* Pendant l'intro, la page ne défile pas sous le voile. */
html.pl-lock, html.pl-lock body { overflow: hidden; }
html.pl-off .preloader { display: none; }

.preloader {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--ivoire);
  /* Le retrait est porté par le CSS avec un long délai : même si le script
     ne s'exécute jamais, le voile finit par se lever. Le script se contente
     de ramener ce délai à zéro dès que la page est prête. */
  animation: pl-lift .55s var(--ease) 3.2s both;
}
/* Sortie pilotée par le script, en deux temps : l'emblème se retire d'abord,
   puis le voile se lève seul. Les deux mouvements ne se superposent pas, ce qui
   évite l'effet « logo qui part en glissade ». */
html.pl-ready .preloader {
  animation: pl-lift .85s cubic-bezier(.72, 0, .16, 1) .3s both;
  will-change: transform;
}
@keyframes pl-lift {
  to { transform: translateY(-100%); visibility: hidden; }
}

.preloader-seal { position: relative; width: clamp(96px, 13vw, 150px); aspect-ratio: 1; }

.preloader-seal svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  transform: rotate(-90deg);   /* le tracé démarre en haut */
}
.preloader-ring {
  fill: none;
  stroke: var(--bordeaux);
  stroke-width: 1.4;
  opacity: .5;
  stroke-dasharray: 302;        /* 2πr, r = 48 */
  stroke-dashoffset: 302;
  animation: pl-trace 1.05s var(--ease) .05s both;
}
@keyframes pl-trace { to { stroke-dashoffset: 0; } }

.preloader-seal picture { display: block; position: absolute; inset: 11%; }
.preloader-seal img {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  display: block;
  opacity: 0;
  transform: scale(.82);
  animation: pl-mark .6s var(--ease) .45s both;
}
@keyframes pl-mark { to { opacity: 1; transform: scale(1); } }

/* Premier temps : l'emblème se contracte à peine et s'efface. */
html.pl-ready .preloader-seal { animation: pl-seal-out .34s cubic-bezier(.4, 0, .2, 1) both; }
@keyframes pl-seal-out { to { opacity: 0; transform: scale(.92); } }

@media (prefers-reduced-motion: reduce) {
  /* Sans mouvement : l'emblème est simplement posé, puis le voile s'efface. */
  .preloader-ring { animation: none; stroke-dashoffset: 0; }
  .preloader-seal img { animation: none; opacity: 1; transform: none; }
  .preloader { animation: pl-fade .35s ease 2.5s both; }
  html.pl-ready .preloader { animation-delay: 0s; }
  html.pl-ready .preloader-seal { animation: none; }
  @keyframes pl-fade { to { opacity: 0; visibility: hidden; } }
}

/* Jour sans disponibilité : visible mais clairement hors-jeu. */
.chat-day[disabled]{opacity:.32;cursor:not-allowed;pointer-events:none}
.chat-day[disabled] .n{text-decoration:line-through}
.chat-slot-none{font-size:.8125rem;opacity:.7;margin:.5rem 0 0}

/* ---- Annulation depuis le lien reçu par email ---------------------------- */
.cancel-wrap { display: flex; justify-content: center; padding: 3rem 1.25rem 5rem; }
.cancel-card {
  width: 100%; max-width: 32rem; background: #fff;
  border: 1px solid rgba(28,22,19,.1); border-radius: 18px; padding: 2rem 1.75rem;
  box-shadow: 0 18px 48px -24px rgba(28,22,19,.3);
}
.cancel-lead { font-size: 1.0625rem; line-height: 1.6; margin: 0 0 .75rem; }
.cancel-note { font-size: .9375rem; line-height: 1.7; color: var(--muted); margin: 1.25rem 0 0; }
.cancel-note a { text-decoration: underline; }
.cancel-error {
  margin: 0 0 1.25rem; padding: .75rem .875rem; border-radius: 10px;
  background: #f9ece9; color: #a3372c; font-size: .9375rem; line-height: 1.5;
}
.cancel-rows { margin: 0 0 1.75rem; }
.cancel-rows > div {
  display: flex; justify-content: space-between; gap: 1.25rem;
  padding: .75rem 0; border-bottom: 1px solid rgba(28,22,19,.09);
}
.cancel-rows > div:last-child { border-bottom: 0; }
.cancel-rows dt { color: var(--muted); font-size: .9375rem; }
.cancel-rows dd { margin: 0; font-weight: 600; text-align: right; font-size: .9375rem; }
.cancel-form { margin: 0; }
.cancel-btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 3rem; padding: 0 1.5rem; border: 1px solid transparent; border-radius: 999px;
  background: var(--bordeaux, #4a342a); color: #fdfcfa; cursor: pointer;
  font-size: .9375rem; font-weight: 600; letter-spacing: .01em;
  transition: opacity .2s ease, background-color .2s ease;
}
.cancel-btn:hover { opacity: .88; }
.cancel-btn.ghost { background: transparent; color: inherit; border-color: rgba(28,22,19,.2); }
.cancel-btn.danger { background: #a3372c; width: 100%; }
.cancel-btn.danger:hover { background: #8d2f25; }

@media (max-width: 520px) {
  .cancel-card { padding: 1.5rem 1.125rem; }
  .cancel-rows > div { flex-direction: column; gap: .25rem; }
  .cancel-rows dd { text-align: left; }
}

/* Ancres internes : le menu reste posé en haut, il faut lui laisser sa place
   sinon le titre de la section arrive dessous et reste invisible. */
#prestations, #philosophie, #avis, #contact, #cta-final { scroll-margin-top: 5rem; }

/* ---- Présentation de l'esthéticienne -------------------------------------
   Le portrait avant le protocole. Section volontairement basse : sa hauteur
   suit son contenu, elle ne prend jamais l'écran entier comme le faisait
   l'ancienne section « philosophie ». Aucune couleur ni ombre ajoutée — le
   caractère vient de la typographie et du cadrage de la photo. */
/* .shell porte déjà sa propre marge verticale : en rajouter une sur la section
   doublait l'espace et faisait retomber le bloc à 80 % de l'écran. */
.about { background: var(--ivoire); }
/* .shell n'a pas de largeur maximale : sans bride, le couple photo + texte
   s'étirait sur toute la page alors que le texte plafonne, laissant un grand
   vide à droite. On le borne et on le centre. */
.about .shell {
  padding-block: clamp(2.5rem, 5vw, 4rem);
  max-width: 68rem;
  margin-inline: auto;
}
.about-grid {
  display: grid;
  /* Sans portrait, la colonne image n'existe pas et le texte prend la largeur. */
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: center;
}
/* Deux colonnes dès qu'un portrait est choisi — uniquement au-dessus de 860 px.
   La condition de largeur est DANS le sélecteur, pas seulement dans une media
   query : `:has()` pèse plus lourd qu'un simple `.about-grid`, et une media
   query n'ajoute aucune spécificité. Sans ça, la règle deux colonnes gagnait
   aussi sur téléphone et écrasait le texte à zéro pixel de large. */
@media (min-width: 861px) {
  .about-grid:has(.about-media) {
    grid-template-columns: minmax(0, 360px) minmax(0, 1fr);
  }
}
/* Médaillon rond, de taille fixe : la section garde exactement la même allure
   quelle que soit la photo déposée — carrée, portrait ou paysage. */
.about-media { position: relative; aspect-ratio: 1 / 1; overflow: hidden; border-radius: 50%; }
.about-media img {
  width: 100%; height: 100%; display: block;
  object-fit: cover;
  /* Cadrage sur le tiers supérieur : c'est là que se trouvent les visages.
     Un centrage strict décapite les portraits pris de loin. */
  object-position: center 35%;
}
.about-copy { color: var(--bordeaux); max-width: 40rem; }
.about-copy h2 {
  font: 400 clamp(2rem, 3.4vw, 3.1rem)/1.1 var(--font-editorial), serif;
  margin: .9rem 0 0;
}
.about-copy .rich-body > :first-child { margin-top: 1.4rem; }
.about-copy .rich-body p { color: var(--muted); line-height: 1.8; margin: 1.1rem 0 0; }
.about-sign {
  margin: 1.8rem 0 0; padding-top: 1.2rem;
  border-top: 1px solid var(--line);
  font-family: var(--font-editorial), serif; font-style: italic;
  color: var(--bordeaux); font-size: 1.0625rem;
}

@media (max-width: 860px) {
  /* Sur téléphone, le médaillon se centre et le texte se range sous lui :
     une photo calée à gauche laissait un vide à sa droite qui se lisait
     comme un défaut de mise en page. */
  .about-grid { justify-items: center; text-align: center; gap: 1.5rem; }
  .about-media { width: 190px; }
  .about-copy { margin-inline: auto; }
  /* Le filet au-dessus de la signature découpe mal un bloc centré. */
  .about-sign { border-top: 0; padding-top: .4rem; }
}
