/* ─────────────────────────────────────────────────────────
   Émotivance · Coque comportementale — habillage des pièces
   pilotées par app.js, portées dans la DA Dermato.

   Quatre pièces transverses qu'app.js injecte ou anime sur
   toutes les surfaces — révélations au scroll, loader de page,
   modales légales, carrousel de témoignages. Elles vivaient
   dans l'ancienne feuille `styles.css`, mêlées au corps des
   pages ; les en extraire est ce qui a permis aux pages de s'en
   passer une à une. Depuis la phase 6, plus aucune surface ne
   charge `styles.css`.

   Aucune classe n'est renommée — app.js n'est pas touché.
   Dépend de tokens.css et base.css.
   ───────────────────────────────────────────────────────── */


/* ═══ Révélation au défilement ════════════════════════
   app.js pose `js-ready` sur <html>, puis `.is-in` sur chaque
   `.reveal` entrant dans le viewport. Le filet de sécurité à
   1,6 s force `.is-in` partout : aucun contenu ne peut rester
   invisible si l'observateur échoue.                        */

@media (prefers-reduced-motion: no-preference) {
  .js-ready .reveal {
    opacity: 0;
    transform: translate3d(0, 18px, 0);
    transition:
      opacity   0.85s var(--ease-out),
      transform 0.85s var(--ease-out),
      filter    0.85s var(--ease-out);
    will-change: opacity, transform;
  }
  .js-ready .reveal.is-in {
    opacity: 1;
    transform: none;
    filter: none;
  }

  /* Variantes — se posent à côté de .reveal. */
  .js-ready .reveal--left  { transform: translate3d(-28px, 0, 0); }
  .js-ready .reveal--right { transform: translate3d(28px, 0, 0); }
  .js-ready .reveal--scale { transform: scale(0.96); }
  .js-ready .reveal--blur  { filter: blur(6px); }
  .js-ready .reveal--up-lg { transform: translate3d(0, 32px, 0); }
  .js-ready .reveal--tilt  { transform: translate3d(0, 24px, 0) rotate(-1.6deg); }
  .js-ready .reveal--zoom  { transform: scale(0.88); filter: blur(4px); }
  .js-ready .reveal--rise  { transform: translate3d(0, 44px, 0); transition-duration: 1.1s; }

  /* Fondu seul, sans transform — se combine avec .parallax, qui
     réquisitionne `transform` en style inline. */
  .js-ready .reveal--fade {
    transform: none;
    filter: blur(8px);
    transition: opacity 1s var(--ease-out), filter 1s var(--ease-out);
  }
  .js-ready .reveal--fade.is-in { filter: none; }

  /* Grands titres : le texte se dévoile par le bas sous un masque. */
  .js-ready .reveal--mask {
    -webkit-mask-image: linear-gradient(180deg, #000 0 70%, transparent 100%);
            mask-image: linear-gradient(180deg, #000 0 70%, transparent 100%);
    -webkit-mask-size: 100% 200%;         mask-size: 100% 200%;
    -webkit-mask-position: 0 100%;        mask-position: 0 100%;
    transition:
      opacity   0.85s var(--ease-out),
      transform 0.85s var(--ease-out),
      -webkit-mask-position 1.1s var(--ease-out),
              mask-position 1.1s var(--ease-out);
  }
  .js-ready .reveal--mask.is-in {
    -webkit-mask-position: 0 0; mask-position: 0 0;
  }

  /* Cascade sur un parent .stagger → .reveal-group (app.js).
     NB : ces délais vivaient dans l'ancienne feuille à l'intérieur
     d'un bloc `prefers-reduced-motion: reduce`, donc ne s'appliquaient
     qu'aux utilisateurs pour qui les révélations sont désactivées —
     autrement dit jamais. Ils sont ici du bon côté de la requête. */
  .js-ready .reveal-group > .reveal:nth-child(1)   { transition-delay:   0ms; }
  .js-ready .reveal-group > .reveal:nth-child(2)   { transition-delay:  80ms; }
  .js-ready .reveal-group > .reveal:nth-child(3)   { transition-delay: 160ms; }
  .js-ready .reveal-group > .reveal:nth-child(4)   { transition-delay: 240ms; }
  .js-ready .reveal-group > .reveal:nth-child(5)   { transition-delay: 320ms; }
  .js-ready .reveal-group > .reveal:nth-child(6)   { transition-delay: 400ms; }
  .js-ready .reveal-group > .reveal:nth-child(7)   { transition-delay: 480ms; }
  .js-ready .reveal-group > .reveal:nth-child(n+8) { transition-delay: 560ms; }

  /* Parallax : app.js écrit un translate3d inline, la cascade ne
     doit donc rien poser sur `transform` ici. */
  .parallax { will-change: transform; }
  .parallax--rise { --parallax-sign: -1; }
  .parallax--sink { --parallax-sign:  1; }

  .spin-slow { animation: spin-slow 90s linear infinite; }
  @keyframes spin-slow { to { transform: rotate(360deg); } }
}

@media (prefers-reduced-motion: reduce) {
  .js-ready .reveal,
  .js-ready .reveal.is-in { opacity: 1; transform: none; filter: none; transition: none; }
  .parallax  { transform: none !important; }
  .spin-slow { animation: none !important; }
}


/* ═══ Loader de page ══════════════════════════════════
   Visible tant que <html> porte `is-loading`. Retiré par
   cms-loader.js dès que le contenu CMS est posé, ou par le
   timeout de secours d'app.js.                              */

.page-loader {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: grid;
  place-items: center;
  background:
    radial-gradient(circle at 50% 42%, var(--accent-10), transparent 38%),
    var(--bg);
  opacity: 1;
  visibility: visible;
  transition: opacity 0.45s ease, visibility 0.45s ease;
}
html:not(.is-loading) .page-loader {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}
.page-loader__inner {
  display: grid;
  place-items: center;
  gap: 14px;
  transform: translateY(-1vh);
}
.page-loader__spinner {
  width: 112px;
  height: 112px;
  filter: url(#em-pl-goo);
}
/* Le dégradé du spinner court du bronze au brun : la palette
   Dermato n'a pas de seconde couleur d'accent. */
.page-loader__stop-1 { stop-color: var(--primary-1); }
.page-loader__stop-2 { stop-color: var(--primary-3); }
.page-loader__half {
  animation: emPlSpin 10s infinite linear;
  stroke-dasharray: 180 800;
  fill: none;
  stroke: url(#em-pl-gradient);
  stroke-width: 22;
  stroke-linecap: round;
}
.page-loader__dash {
  animation: emPlSpin 3s infinite linear;
  stroke-dasharray: 26 54;
  fill: none;
  stroke: url(#em-pl-gradient);
  stroke-width: 22;
  stroke-linecap: round;
}
.page-loader__label {
  font-size: var(--t-xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--ink-3);
}
@keyframes emPlSpin {
  from { stroke-dashoffset: 0; }
  to   { stroke-dashoffset: -403px; }
}
@media (prefers-reduced-motion: reduce) {
  .page-loader__half,
  .page-loader__dash { animation-duration: 18s; }
}


/* ═══ Modale légale ═══════════════════════════════════
   Injectée à la demande par app.js (liens [data-legal]).    */

.legal-modal {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: grid;
  place-items: center;
  padding: var(--sp-6);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--dur) ease, visibility var(--dur) ease;
}
.legal-modal.is-open { opacity: 1; visibility: visible; }

.legal-modal__backdrop {
  position: absolute;
  inset: 0;
  background: color-mix(in srgb, var(--primary-3) 32%, transparent);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
}
.legal-modal__panel {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: 720px;
  max-height: min(86vh, 800px);
  overflow: hidden;
  background: var(--bg);
  border: 1px solid var(--line-gold);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-lg);
  transform: translateY(12px) scale(0.98);
  transition: transform 0.4s var(--ease-out);
}
.legal-modal.is-open .legal-modal__panel { transform: none; }

.legal-modal__close {
  position: absolute;
  top: 14px;
  right: 14px;
  z-index: 2;
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--white);
  color: var(--ink-2);
  font: 400 22px/1 var(--font-heading);
  transition: background-color var(--dur-fast) ease, color var(--dur-fast) ease;
}
.legal-modal__close:hover { background: var(--accent); color: var(--accent-ink); }

.legal-modal__head {
  padding: var(--sp-7) var(--sp-6) var(--sp-4);
  border-bottom: 1px solid var(--line);
}
.legal-modal__eyebrow {
  margin: 0 0 6px;
  font-size: var(--t-xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--ink-3);
}
.legal-modal__title {
  margin: 0;
  font-family: var(--font-heading);
  font-weight: 400;
  font-size: var(--t-h3);
  line-height: var(--lh-heading);
  letter-spacing: var(--tracking-tight);
  color: var(--ink);
}
.legal-modal__body {
  padding: var(--sp-5) var(--sp-6) var(--sp-6);
  overflow-y: auto;
  font-size: var(--t-sm);
  line-height: 1.65;
  color: var(--ink-2);
}
.legal-modal__body h2 {
  margin: 22px 0 8px;
  font-size: var(--t-h5);
  color: var(--ink);
}
.legal-modal__body h2:first-child { margin-top: 0; }
.legal-modal__body h3 {
  margin: 18px 0 6px;
  font-family: var(--font-body);
  font-size: var(--t-xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--ink-3);
}
.legal-modal__body p  { margin: 0 0 12px; }
.legal-modal__body ul { margin: 0 0 12px; padding-left: 20px; }
.legal-modal__body li { margin: 4px 0; }
.legal-modal__body a  {
  color: var(--accent-text);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}
.legal-modal__body strong { color: var(--ink); font-weight: 600; }

.legal-modal__skel {
  height: 12px;
  margin: 0 0 10px;
  border-radius: 6px;
  background: linear-gradient(90deg, var(--surface), var(--accent-10), var(--surface));
  background-size: 200% 100%;
  animation: legal-shimmer 1.4s ease-in-out infinite;
}
.legal-modal__skel.is-short { width: 60%; }
@keyframes legal-shimmer {
  from { background-position: 200% 0; }
  to   { background-position: -200% 0; }
}

body.legal-open { overflow: hidden; }

@media (max-width: 600px) {
  .legal-modal { padding: 0; }
  .legal-modal__panel { height: 100vh; max-height: 100vh; border-radius: 0; }
}


/* ═══ Carrousel de témoignages ════════════════════════
   Cartes blanches empilées en fondu, points, flèches et barre
   de progression. app.js mesure la hauteur de la carte active
   et la pose en inline sur le track.                        */

.testimonials {
  position: relative;
  width: 100%;
  max-width: 760px;
  margin-inline: auto;
}

.testimonials__quote {
  position: absolute;
  top: -26px;
  left: -10px;
  z-index: 2;
  color: var(--ornament);
  pointer-events: none;
}

.testimonials__track {
  position: relative;
  display: grid;
  min-height: 260px;
}

.testimonial {
  grid-column: 1;
  grid-row: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-5);
  padding: clamp(28px, 4vw, 50px);
  border-radius: var(--r-2xl);
  background: var(--white);
  border: 1px solid var(--line-gold);
  text-align: center;
  opacity: 0;
  visibility: hidden;
  transform: translateY(10px) scale(0.985);
  transition:
    opacity    0.6s var(--ease-out),
    transform  0.6s var(--ease-out),
    box-shadow 0.6s var(--ease-out),
    visibility 0s linear 0.6s;
}
.testimonial.is-on {
  opacity: 1;
  visibility: visible;
  transform: none;
  box-shadow: var(--shadow);
  transition:
    opacity    0.6s var(--ease-out),
    transform  0.6s var(--ease-out),
    box-shadow 0.6s var(--ease-out);
}

.testimonial__rating {
  display: flex;
  gap: 3px;
  color: var(--ornament);
  font-size: 15px;
  line-height: 1;
  letter-spacing: 3px;
}

.testimonial blockquote {
  max-width: 580px;
  margin: 0;
  font-family: var(--font-heading);
  font-size: var(--t-h4);
  line-height: var(--lh-snug);
  letter-spacing: var(--tracking-tight);
  color: var(--ink);
}

.testimonial__author {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  margin-top: var(--sp-1);
}
.testimonial__avatar {
  flex: 0 0 48px;
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  border-radius: var(--r-pill);
  background: var(--accent-10);
  color: var(--accent-text);
  font-family: var(--font-heading);
  font-size: var(--t-h5);
}
.testimonial__info {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  text-align: left;
}
.testimonial__name { font-size: var(--t-sm); font-weight: 600; color: var(--ink); }
.testimonial__meta { font-size: var(--t-xs); color: var(--ink-3); }

.testimonials__nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-5);
  margin-top: var(--sp-5);
}
.testimonials__arrow {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 0;
  border-radius: var(--r-pill);
  background: var(--white);
  color: var(--ink);
  transition: background-color var(--dur-fast) ease, color var(--dur-fast) ease;
}
.testimonials__arrow:hover { background: var(--accent); color: var(--accent-ink); }

.testimonials__dots { display: flex; justify-content: center; gap: var(--sp-2); }
.testimonial-dot {
  width: 8px;
  height: 8px;
  padding: 0;
  border: 1px solid var(--ornament-deep);
  border-radius: var(--r-pill);
  background: transparent;
  transition: background-color var(--dur) ease, border-color var(--dur) ease, transform var(--dur) ease;
}
.testimonial-dot:hover { background: var(--accent-40); }
.testimonial-dot.is-on {
  background: var(--accent);
  border-color: var(--accent);
  transform: scale(1.25);
}

.testimonials__progress {
  position: relative;
  width: 120px;
  height: 2px;
  margin: var(--sp-5) auto 0;
  overflow: hidden;
  border-radius: var(--r-pill);
  background: var(--accent-15);
  pointer-events: none;
}
.testimonials__progress::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
  animation: testi-progress var(--testi-duration, 6s) linear infinite;
}
.testimonials.is-paused .testimonials__progress::after { animation-play-state: paused; }
.testimonials[data-paged] .testimonials__progress::after { animation: none; transform: scaleX(0); }
@keyframes testi-progress { to { transform: scaleX(1); } }

@media (prefers-reduced-motion: reduce) {
  .testimonial { transform: none; transition: opacity 0.2s ease; }
  .testimonials__progress::after { animation: none; }
}

/* Au doigt, les commandes du carrousel respectent 44×44 (WCAG 2.5.5).
   Le point garde ses 8px à l'œil : c'est sa zone de frappe qui
   s'étend, via un pseudo-élément transparent. */
@media (pointer: coarse) {
  .testimonials__arrow { width: 44px; height: 44px; }
  .testimonials__dots { gap: var(--sp-4); }
  .testimonial-dot { position: relative; }
  .testimonial-dot::after {
    content: "";
    position: absolute;
    inset: -18px;
  }
}


/* ═══ Téléphone — < 600px ═════════════════════════════
   La citation était calée sur --t-h4 : sur 350px de large, un
   témoignage un peu long remplissait l'écran, et la piste du
   carrousel — dimensionnée sur la plus haute des cartes — creusait
   un vide sous les plus courtes.                              */

@media (max-width: 599px) {
  .testimonial blockquote { font-size: var(--t-h5); }
  .testimonial { padding: var(--sp-5); gap: var(--sp-4); }
  .testimonials__track { min-height: 0; }
  .testimonials__quote { top: -18px; left: -4px; }
  .testimonials__quote svg { width: 54px; height: auto; }
  .testimonials__nav { gap: var(--sp-4); margin-top: var(--sp-4); }
}
