/**
 * APULIA HEALTH CENTER — Feuilles de style globales et composants
 * Agence : Roots Agency · Version : 1.0 (Août 2026)
 */

/* ==========================================================================
   1. TOPBAR & NAVIGATION GLOBALE
   ========================================================================== */

.topbar {
  background-color: var(--inchiostro);
  color: var(--calce);
  font-size: var(--text-sm);
  height: 42px;
  display: flex;
  align-items: center;
  border-bottom: 1px solid var(--border-dark);
  position: relative;
  z-index: 100;
}

.topbar-content {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
}

.topbar-infos {
  display: flex;
  align-items: center;
  gap: 20px;
}

.topbar-item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: rgba(251, 250, 248, 0.82);
}

.topbar-sep {
  opacity: 0.3;
}

.topbar-actions {
  display: flex;
  align-items: center;
  gap: 20px;
}

.topbar-link {
  text-decoration: underline;
  text-underline-offset: 3px;
  color: var(--brun-clair);
}

.topbar-lang {
  display: flex;
  gap: 6px;
  font-weight: 500;
}

.topbar-lang .active {
  color: var(--sale);
  font-weight: 600;
}

.topbar-lang .disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

@media (max-width: 860px) {
  .topbar {
    display: none;
  }
}

/* Header Sticky */
.site-header {
  position: sticky;
  top: 0;
  left: 0;
  right: 0;
  height: 80px;
  z-index: 90;
  transition: background-color var(--dur-medium) ease, border-color var(--dur-medium) ease;
  background-color: transparent;
  display: flex;
  align-items: center;
}

.site-header.header-opaque {
  background-color: var(--sale);
  border-bottom: 1px solid var(--border-light);
}

.site-header.header-opaque .nav-link {
  color: var(--inchiostro);
}

.site-header.header-opaque .burger-bar {
  background-color: var(--inchiostro);
}

.header-container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
}

/* Logo de barre — signature complète, arbre compris.
   La largeur est calée sur la hauteur de barre disponible (80 px) plutôt que
   sur le plancher de 180 px de la charte : à 180 px la signature remplit la
   barre de bord à bord. 132 px sur mobile et 148 px sur desktop donnent 47 et
   52 px de haut, ce qui laisse respirer au-dessus et en dessous.
   Deux fichiers superposés : le blanc pour la barre transparente posée sur le
   hero, le brun dès qu'elle devient opaque. Le fondu remplace le changement de
   couleur que permettait l'ancien lettrage en texte. */
.brand-logo {
  position: relative;
  display: block;
  width: 132px;
  line-height: 0;
  text-decoration: none;
}

@media (min-width: 1024px) {
  .brand-logo { width: 148px; }
}

.brand-mark {
  display: block;
  width: 100%;
  height: auto;
  transition: opacity var(--dur-medium) ease;
}

.brand-mark--brun {
  position: absolute;
  inset: 0;
  opacity: 0;
}

.site-header.header-opaque .brand-mark--blanc,
body.page-light .brand-mark--blanc { opacity: 0; }

.site-header.header-opaque .brand-mark--brun,
body.page-light .brand-mark--brun { opacity: 1; }

/* Le tiroir mobile s'ouvre sur fond encre : il ne connaît que la version
   blanche, quelle que soit l'apparence de la barre au moment de l'ouverture. */
.mobile-drawer .brand-mark--blanc { opacity: 1; }
.mobile-drawer .brand-mark--brun { opacity: 0; }

/* Navigation Desktop */
.nav-desktop {
  display: none;
}

@media (min-width: 1024px) {
  .nav-desktop {
    display: flex;
    align-items: center;
    gap: 32px;
  }

  .nav-menu {
    display: flex;
    align-items: center;
    list-style: none;
    gap: 24px;
  }

  .nav-item {
    position: relative;
  }

  .nav-link {
    font-size: var(--text-base);
    font-weight: 500;
    color: rgba(251, 250, 248, 0.9);
    padding: 8px 0;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    transition: color var(--dur-fast) ease;
  }

  .nav-link:hover,
  .nav-link:focus {
    color: var(--theme-accent);
  }

  /* Dropdowns */
  .dropdown-menu {
    position: absolute;
    top: 100%;
    left: -16px;
    min-width: 260px;
    background-color: var(--sale);
    border: 1px solid var(--border-medium);
    border-radius: var(--radius);
    padding: 12px 0;
    list-style: none;
    opacity: 0;
    visibility: hidden;
    transform: translateY(8px);
    transition: opacity var(--dur-medium) ease, transform var(--dur-medium) ease, visibility var(--dur-medium);
  }

  .nav-item:hover .dropdown-menu,
  .nav-item:focus-within .dropdown-menu {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
  }

  .dropdown-link {
    display: block;
    padding: 10px 20px;
    font-size: var(--text-base);
    color: var(--inchiostro);
    line-height: 1.4;
  }

  .dropdown-link:hover,
  .dropdown-link:focus {
    background-color: var(--calce);
    color: var(--theme-accent);
  }
}

/* Boutons d'action */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 17px 26px;
  min-height: 48px;
  border-radius: var(--radius-btn);
  cursor: pointer;
  transition: opacity var(--dur-fast) ease, background-color var(--dur-fast) ease;
  white-space: nowrap;
  line-height: 1;
}

.btn:hover {
  opacity: 0.88;
}

.btn-primary {
  background-color: var(--theme-accent);
  color: var(--theme-accent-contrast);
}

.btn-secondary {
  background-color: var(--inchiostro);
  color: var(--sale);
}

.btn-outline {
  border: 1px solid var(--border-medium);
  color: var(--inchiostro);
  background-color: transparent;
}

.btn-outline-light {
  border: 1px solid rgba(251, 250, 248, 0.4);
  color: var(--sale);
  background-color: transparent;
}

.btn-outline-light:hover {
  opacity: 0.88;
}

.btn-sm {
  padding: 10px 18px;
  font-size: var(--text-xs);
}

/* Header sur page claire initiale */
body.page-light .site-header {
  background-color: var(--sale);
  border-bottom: 1px solid var(--border-light);
}
body.page-light .nav-link {
  color: var(--inchiostro);
}
body.page-light .burger-bar {
  background-color: var(--inchiostro);
}

/* ==========================================================================
   2. BURGER & MENU MOBILE LATÉRAL (Gaucherie 80%)
   ========================================================================== */

.burger-btn {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-end;
  gap: 6px;
  width: 44px;
  height: 44px;
  background: transparent;
  border: none;
  cursor: pointer;
  z-index: 120;
}

@media (min-width: 1024px) {
  .burger-btn {
    display: none;
  }
}

.burger-bar {
  width: 24px;
  height: 1.5px;
  background-color: var(--sale);
  transition: transform var(--dur-medium) ease, opacity var(--dur-medium) ease, background-color var(--dur-medium) ease;
}

.burger-btn.is-active .burger-bar:first-child {
  transform: translateY(7.5px) rotate(45deg);
  background-color: var(--sale);
}

.burger-btn.is-active .burger-bar:last-child {
  transform: translateY(-0px) rotate(-45deg);
  background-color: var(--sale);
}

/* Drawer Mobile */
.mobile-overlay {
  position: fixed;
  inset: 0;
  background-color: rgba(23, 28, 25, 0.65);
  backdrop-filter: blur(4px);
  z-index: 100;
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--dur-medium) ease, visibility var(--dur-medium);
}

.mobile-overlay.is-active {
  opacity: 1;
  visibility: visible;
}

.mobile-drawer {
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  width: 80%;
  max-width: 380px;
  background-color: var(--inchiostro);
  border-right: 1px solid var(--brun-clair);
  z-index: 110;
  transform: translateX(-100%);
  transition: transform var(--dur-drawer) var(--ease-standard);
  overflow-y: auto;
  padding: 24px;
  display: flex;
  flex-direction: column;
}

.mobile-drawer.is-active {
  transform: translateX(0);
}

.drawer-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 24px;
}

.drawer-cta {
  margin-bottom: 28px;
}

.drawer-cta .btn {
  width: 100%;
}

.mobile-nav-list {
  list-style: none;
  border-top: 1px solid var(--border-dark);
}

.mobile-nav-item {
  border-bottom: 1px solid var(--border-dark);
}

.mobile-nav-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: 16px 0;
  font-family: var(--font-display);
  font-size: 22px;
  color: var(--sale);
  text-align: left;
}

.mobile-nav-toggle {
  font-family: var(--font-body);
  font-size: 18px;
  color: var(--brun-clair);
  font-weight: 300;
  transition: transform var(--dur-fast) ease;
}

.mobile-sub-menu {
  display: none;
  list-style: none;
  padding: 0 0 16px 12px;
}

.mobile-sub-menu.is-open {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.mobile-sub-link {
  font-size: var(--text-md);
  color: rgba(251, 250, 248, 0.78);
  display: block;
  padding: 4px 0;
}

.drawer-footer {
  margin-top: auto;
  padding-top: 32px;
  font-size: var(--text-sm);
  color: rgba(251, 250, 248, 0.6);
  line-height: 1.6;
}

/* Barre Fixe Basse Mobile */
.mobile-sticky-bar {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  display: flex;
  background-color: var(--sale);
  border-top: 1px solid var(--border-light);
  z-index: 85;
}

@media (min-width: 768px) {
  .mobile-sticky-bar {
    display: none;
  }
}

.mobile-sticky-bar .btn {
  flex: 1;
  border-radius: 0;
  padding: 16px;
  font-size: 12px;
}

/* ==========================================================================
   3. SECTIONS HERO & ACCUEIL
   ========================================================================== */

.hero-home {
  position: relative;
  height: 100svh;
  min-height: 600px;
  background-color: var(--inchiostro);
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  color: var(--sale);
  overflow: hidden;
  margin-top: -80px; /* Fusionne avec le header transparent */
  padding-bottom: 60px;
}

.hero-media-container {
  position: absolute;
  inset: 0;
  z-index: 1;
}

.hero-video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.hero-overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(23, 28, 25, 0.42) 0%, rgba(23, 28, 25, 0.30) 38%, rgba(23, 28, 25, 0.88) 100%);
  z-index: 2;
}

.hero-content {
  position: relative;
  z-index: 3;
}

.hero-title {
  font-size: clamp(38px, 5.6vw, var(--text-5xl));
  color: var(--sale);
  margin-bottom: 20px;
  max-width: 18ch;
}

.hero-sub {
  font-size: clamp(16px, 2vw, 18px);
  color: rgba(251, 250, 248, 0.88);
  margin-bottom: 32px;
  max-width: 54ch;
}

.hero-actions {
  display: flex;
  align-items: center;
  gap: 20px;
  flex-wrap: wrap;
}

/* Hero standard (pages internes)
   Le header est en flux (position: sticky, pas fixed) : sa hauteur est déjà
   réservée au-dessus du hero. La recompter dans le padding poussait le fil
   d'Ariane et le titre 200 px plus bas sur les pages services. */
.page-hero {
  background-color: var(--inchiostro);
  color: var(--sale);
  padding: var(--sp-hero) 0;
  position: relative;
}

.page-hero.hero-light {
  background-color: var(--calce);
  color: var(--inchiostro);
}

.page-hero.hero-light h1 {
  color: var(--inchiostro);
}

.breadcrumb {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: var(--text-xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 16px;
}

.breadcrumb a {
  color: inherit;
}

.breadcrumb-active {
  color: var(--inchiostro);
  font-weight: 500;
}

/* Bandeau de Réassurance */
.reassurance-bar {
  background-color: var(--sale);
  border-bottom: 1px solid var(--border-light);
}

.reassurance-grid {
  display: grid;
  grid-template-columns: 1fr;
}

@media (min-width: 640px) {
  .reassurance-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 1024px) {
  .reassurance-grid {
    grid-template-columns: repeat(4, 1fr);
  }
}

/* Icône du bandeau de réassurance. Dessin au trait plutôt qu'émoji : le trait
   fin reprend celui de l'arbre du logo, et la couleur suit le libellé au lieu
   d'imposer la palette d'un jeu d'émoji système. Le SVG est en ligne — ni
   police d'icônes ni requête supplémentaire, et rien à autoriser dans la CSP.
   Masquée aux lecteurs d'écran : « cadenas » lu avant « spa entièrement
   privatisé » n'apporte rien à qui écoute la page.
   La charte §5 excluait tout pictogramme décoratif ici ; l'ajout est fait à la
   demande de la direction. */
.reassurance-icone {
  flex: none;
  display: inline-flex;
  color: var(--theme-accent);
}

.reassurance-icone svg {
  display: block;
  width: 20px;
  height: 20px;
}

.reassurance-item {
  padding: 24px 20px;
  font-size: var(--text-sm);
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--oliva);
  border-bottom: 1px solid var(--border-light);
  display: flex;
  align-items: center;
  gap: 12px;
}

@media (min-width: 1024px) {
  .reassurance-item {
    border-bottom: none;
    border-left: 1px solid var(--border-light);
    padding: 30px 24px;
  }
  .reassurance-item:first-child {
    border-left: none;
  }
}

/* ==========================================================================
   4. SÉLECTEUR D'INTENTION (ÉLÉMENT SIGNATURE)
   ========================================================================== */

.intention-section {
  padding: var(--section-gap) 0;
  background-color: var(--sale);
}

.intention-header {
  margin-bottom: 40px;
}

/* Panneaux Desktop */
.intention-grid {
  display: flex;
  gap: 12px;
  height: 62vh;
  min-height: 480px;
  max-height: 640px;
}

.intention-panel {
  flex: 1;
  position: relative;
  overflow: hidden;
  /* Fond de repli en encre, pas en chaux. Le panneau porte un titre en blanc
     de sel : quand la photographie manque — « Sur mesure » n'en a pas — le
     titre se retrouvait à 1,16:1 sur un gris clair, donc illisible. La photo,
     lorsqu'elle existe, couvre entièrement ce fond : rien ne change pour les
     autres panneaux. */
  background-color: var(--inchiostro);
  border-radius: var(--radius);
  transition: flex var(--dur-signature) var(--ease-standard);
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: 32px 28px;
  text-decoration: none;
  color: var(--sale);
}

.intention-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: saturate(0.65) brightness(0.85);
  transition: filter var(--dur-signature) var(--ease-standard), transform var(--dur-signature) var(--ease-standard);
  z-index: 1;
}

.intention-panel::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(23, 28, 25, 0.1) 0%, rgba(23, 28, 25, 0.8) 100%);
  z-index: 2;
}

.intention-border {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  height: 3px;
  background-color: var(--brun-clair);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dur-signature) var(--ease-standard);
  z-index: 4;
}

.intention-content {
  position: relative;
  z-index: 3;
}

.intention-title {
  font-family: var(--font-display);
  font-size: clamp(28px, 2.5vw, 40px);
  color: var(--sale);
  margin-bottom: 8px;
  line-height: 1.1;
}

.intention-meta {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--brun-clair);
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.intention-arrow {
  transition: transform var(--dur-fast) ease;
}

@media (min-width: 1024px) {
  .intention-panel:hover {
    flex: 1.6;
  }

  .intention-panel:hover .intention-bg {
    filter: saturate(1) brightness(0.95);
  }

  .intention-panel:hover .intention-border {
    transform: scaleX(1);
  }

  .intention-panel:hover .intention-arrow {
    transform: translateX(4px);
  }
}

/* Mobile Scroll-Snap */
@media (max-width: 1023px) {
  .intention-grid {
    display: flex;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    height: 420px;
    gap: 16px;
    padding-bottom: 16px;
    -webkit-overflow-scrolling: touch;
  }

  .intention-panel {
    flex: 0 0 280px;
    scroll-snap-align: start;
  }

  .intention-border {
    transform: scaleX(1);
  }
}

/* ==========================================================================
   5. SECTIONS FORMULES & TARIFS
   ========================================================================== */

.section-formules {
  padding: var(--section-gap-lg) 0;
  background-color: var(--sale);
}

.formules-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 24px;
  margin-top: 48px;
}

@media (min-width: 768px) {
  .formules-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 1200px) {
  .formules-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

.carte-formule {
  background-color: var(--sale);
  border: 1px solid var(--border-light);
  border-radius: var(--radius);
  padding: 36px 30px;
  display: flex;
  flex-direction: column;
  position: relative;
}

.carte-formule.carte-vedette {
  background-color: var(--calce);
  border-color: var(--theme-accent);
}

.carte-badge {
  position: absolute;
  top: 16px;
  right: 20px;
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--oliva);
  background-color: rgba(78, 91, 69, 0.1);
  padding: 4px 8px;
  border-radius: var(--radius);
}

.carte-duree {
  font-size: var(--text-xs);
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--oliva);
  margin-bottom: 8px;
}

.carte-titre {
  font-size: 28px;
  margin-bottom: 12px;
}

.carte-desc {
  font-size: var(--text-md);
  color: var(--text-muted);
  margin-bottom: 24px;
  line-height: 1.5;
}

.carte-inclus {
  list-style: none;
  margin-bottom: 32px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.carte-inclus li {
  font-size: 14px;
  color: var(--inchiostro);
  display: flex;
  align-items: flex-start;
  gap: 8px;
}

.carte-inclus li::before {
  content: '✓';
  color: var(--oliva);
  font-weight: 600;
}

.carte-tarifs {
  margin-top: auto;
  padding-top: 24px;
  border-top: 1px solid var(--border-light);
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 24px;
}

.prix-ligne {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
}

.prix-montant {
  font-family: var(--font-display);
  font-size: 28px;
  color: var(--inchiostro);
}

.carte-vedette .prix-montant {
  color: #8f6e34;
}

.prix-label {
  font-size: var(--text-sm);
  color: var(--text-muted);
}

/* Deux actions au pied de la carte — « Réserver Dolce Vita » et son jumeau
   WhatsApp — l'une sous l'autre, pour la même raison que .soin-actions sur
   /soins-esthetiques/ : les libellés des boutons ne se coupent jamais
   (.btn est en white-space: nowrap), et dans une grille de trois colonnes ils
   déborderaient côte à côte. Empilés, ce sont deux cibles de 48 px de haut
   sur toute la largeur de la carte. */
.carte-actions {
  display: grid;
  grid-template-columns: 1fr;
  gap: 10px;
}

.carte-actions .btn { width: 100%; }

/* Le même couple de boutons, mais au fil d'un texte — une colonne de prose,
   un encadré de tarif. Ici ils gardent leur largeur propre : pleine largeur,
   ils se liraient comme deux bandeaux empilés sous le paragraphe. Ils passent
   l'un sous l'autre d'eux-mêmes quand la colonne se resserre. */
.actions-duo {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
}

/* Tableau Comparatif de Tarifs */
.table-responsive {
  width: 100%;
  overflow-x: auto;
  margin: 40px 0;
}

.grille-tarifs {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-md);
}

.grille-tarifs th,
.grille-tarifs td {
  padding: 16px 20px;
  text-align: left;
  border-bottom: 1px solid var(--border-light);
}

.grille-tarifs th {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-muted);
  background-color: var(--calce);
}

.grille-tarifs tr:hover td {
  background-color: rgba(233, 234, 229, 0.4);
}

/* ==========================================================================
   6. SECTIONS IMMERSIVES & NUITÉE
   ========================================================================== */

.section-sombre {
  background-color: var(--inchiostro);
  color: var(--sale);
  padding: var(--section-gap) 0;
}

.section-sombre h2,
.section-sombre h3 {
  color: var(--sale);
}

.split-layout {
  display: grid;
  grid-template-columns: 1fr;
  gap: 48px;
  align-items: center;
}

@media (min-width: 1024px) {
  .split-layout {
    grid-template-columns: 1fr 1fr;
    gap: 80px;
  }
}

/* --- Règlement d'ordre intérieur ---------------------------------------
   Un article par section, numéroté en marge. Le numéro est décoratif : il est
   déjà porté par le titre, on ne le lit pas deux fois. */
.roi-article + .roi-article { margin-top: 48px; }

.roi-article h2 {
  font-size: var(--text-xl);
  margin-bottom: 16px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--border-light);
}

.roi-num {
  display: inline-block;
  margin-right: 12px;
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: 600;
  letter-spacing: 0.1em;
  color: var(--theme-accent);
  vertical-align: 3px;
}

.roi-article p { font-size: var(--text-base); color: var(--text-muted); }
.roi-article p strong { color: var(--inchiostro); font-weight: 600; }

/* --- Les occasions en vidéo --------------------------------------------
   Trois formats verticaux 9:16, ceux des reels. Sur desktop ils tiennent en
   trois colonnes ; sous 900 px la rangée devient un carrousel à accroche,
   comme le sélecteur d'intention — c'est le seul geste qui garde trois
   vidéos lisibles sur un téléphone sans les réduire à des timbres-poste.
   La lecture ne démarre qu'une fois la vidéo à l'écran, et jamais si le
   visiteur a demandé moins de mouvement. */
.occasions-videos {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--gutter);
}

@media (max-width: 899px) {
  .occasions-videos {
    display: flex;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    gap: 16px;
    padding-bottom: 16px;
    -webkit-overflow-scrolling: touch;
    /* Le carrousel déborde volontairement de la gouttière pour que la vidéo
       suivante s'amorce au bord de l'écran. */
    margin-inline: calc(var(--page-padding) * -1);
    padding-inline: var(--page-padding);
  }

  .occasion-video {
    flex: 0 0 min(74vw, 300px);
    scroll-snap-align: start;
  }
}

.occasion-video-lien {
  position: relative;
  display: block;
  overflow: hidden;
  border-radius: var(--radius);
  background-color: var(--calce);
}

.occasion-video-media {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 9 / 16;
  object-fit: cover;
}

/* Le texte se pose sur la vidéo : le dégradé lui garantit son contraste quelle
   que soit l'image derrière. */
.occasion-video-texte {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  display: block;
  padding: 72px 24px 24px;
  background: linear-gradient(180deg, rgba(23, 28, 25, 0) 0%, rgba(23, 28, 25, 0.82) 62%);
}

.occasion-video-titre {
  display: block;
  font-family: var(--font-display);
  font-size: var(--text-xl);
  line-height: 1.25;
  color: var(--sale);
}

.occasion-video-note {
  display: block;
  margin-top: 6px;
  font-size: var(--text-base);
  color: rgba(251, 250, 248, 0.82);
}

.occasion-video-lien-libelle {
  display: block;
  margin-top: 14px;
  color: var(--brun-clair);
}

@media (hover: hover) {
  .occasion-video-lien:hover .occasion-video-media { transform: scale(1.03); }
  .occasion-video-media { transition: transform var(--dur-signature) var(--ease-standard); }
}

@media (prefers-reduced-motion: reduce) {
  .occasion-video-media { transition: none; }
  .occasion-video-lien:hover .occasion-video-media { transform: none; }
}

/* --- La carte : boissons et restauration --------------------------------
   Trois colonnes de listes, chaque ligne tenant l'intitulé à gauche et le
   prix à droite, séparés par un filet en pointillé. Les lignes sont écrites
   par le liant de données : aucun prix ne vit dans le HTML. */
.carte-grille {
  display: grid;
  grid-template-columns: 1fr;
  gap: 40px 64px;
}

@media (min-width: 640px)  { .carte-grille { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .carte-grille { grid-template-columns: repeat(3, 1fr); } }

.carte-groupe h3 {
  font-size: var(--text-xl);
  margin-bottom: 16px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--theme-accent);
}

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

.carte-ligne {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 9px 0;
  border-bottom: 1px solid var(--border-light);
}

.carte-ligne:last-child { border-bottom: none; }

.carte-item {
  font-size: var(--text-base);
  color: var(--inchiostro);
}

.carte-prix {
  margin-left: auto;
  flex: none;
  font-family: var(--font-display);
  font-size: var(--text-lg);
  font-variant-numeric: tabular-nums;
  color: var(--theme-accent);
}

/* --- Modèle de page de service santé -----------------------------------
   Deux composants, et rien d'autre :

   .bloc-alterne        texte / image, puis image / texte au bloc suivant.
                        L'alternance est portée par --inverse, pas par l'ordre
                        du markup : le mobile empile toujours le texte d'abord,
                        quel que soit le sens choisi sur desktop.
   .bloc-paragraphe     titre, texte, bouton. Sans image, pour les passages
                        qui n'ont rien à montrer.
   ----------------------------------------------------------------------- */

.bloc-alterne {
  display: grid;
  grid-template-columns: 1fr;
  gap: 40px;
  align-items: center;
}

@media (min-width: 1024px) {
  .bloc-alterne {
    grid-template-columns: 1fr 1fr;
    gap: 80px;
  }

  /* Image à gauche, texte à droite — sans toucher à l'ordre du DOM, donc sans
     rien casser au clavier ni sur mobile. */
  .bloc-alterne--inverse .bloc-alterne-texte { order: 2; }
  .bloc-alterne--inverse .bloc-alterne-media { order: 1; }
}

.bloc-alterne + .bloc-alterne { margin-top: var(--section-gap); }

.bloc-alterne-texte > h2,
.bloc-alterne-texte > h3 { margin-bottom: 16px; }

.bloc-alterne-texte p { margin-bottom: 16px; }
.bloc-alterne-texte p:last-of-type { margin-bottom: 0; }
.bloc-alterne-texte .btn,
.bloc-alterne-texte .link-underline { margin-top: 24px; }

.bloc-alterne-media img {
  width: 100%;
  height: auto;
  max-height: 520px;
  object-fit: cover;
  border-radius: var(--radius);
}

.bloc-paragraphe {
  max-width: 62ch;
}

.bloc-paragraphe h2,
.bloc-paragraphe h3 { margin-bottom: 16px; }
.bloc-paragraphe p { margin-bottom: 16px; }
.bloc-paragraphe .btn { margin-top: 24px; }

/* Note de source : d'où vient une donnée chiffrée, ou ce qui reste à faire
   valider. Sur une page de santé, l'origine d'un chiffre fait partie du
   contenu. */
.note-clinique {
  margin-top: 20px;
  padding-left: 16px;
  border-left: 2px solid var(--theme-accent);
  font-size: var(--text-base);
  color: var(--text-muted);
}

.split-media {
  display: block;
  position: relative;
  overflow: hidden;
  border-radius: var(--radius);
}

.split-media img {
  width: 100%;
  height: 100%;
  max-height: 540px;
  object-fit: cover;
}

/* ==========================================================================
   7. FORMULAIRE DE CONTACT & PRISES DE RENDEZ-VOUS
   ========================================================================== */

/* --- Formulaire de devis : image à gauche, formulaire à droite ----------
   Le duo tient dans la gouttière de page comme n'importe quelle autre
   section : le `minmax(0, …)` empêche la colonne de formulaire de gonfler
   au-delà de sa part de grille — sans lui, un <select> ou un mot long
   pousse la colonne et fait déborder l'ensemble hors des marges. */
.form-duo {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 32px;
  align-items: stretch;
}

@media (min-width: 900px) {
  .form-duo {
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    gap: 48px;
  }
}

/* Sur la page contact, le formulaire est seul : les coordonnées et la carte
   sont déjà au-dessus, une image de plus ne dirait rien. La grille repasse à
   une colonne, calée sur une largeur de lecture plutôt qu'étirée d'un bord à
   l'autre. */
.form-duo--seul { grid-template-columns: minmax(0, 1fr); }

@media (min-width: 900px) {
  .form-duo--seul { grid-template-columns: minmax(0, 1fr); max-width: 760px; }
}

.form-duo-media {
  position: relative;
  min-height: 260px;
  border-radius: var(--radius);
  overflow: hidden;
}

.form-duo-media img,
.form-duo-media picture {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.form-duo-media .media-placeholder {
  height: 100%;
  aspect-ratio: auto;
}

/* Le formulaire ne déborde jamais de sa colonne, quel que soit son contenu. */
.form-duo .form-container { min-width: 0; }
.form-apulia { min-width: 0; }
.form-input,
.form-select,
.form-textarea { max-width: 100%; }

.form-container {
  background-color: var(--sale);
  border: 1px solid var(--border-light);
  border-radius: var(--radius);
  padding: 40px;
}

@media (max-width: 640px) {
  .form-container {
    padding: 24px 20px;
  }
}

.form-group {
  margin-bottom: 24px;
}

.form-label {
  display: block;
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--oliva);
  margin-bottom: 8px;
}

.form-input,
.form-select,
.form-textarea {
  width: 100%;
  padding: 14px 16px;
  background-color: #ffffff;
  border: 1px solid var(--border-medium);
  border-radius: var(--radius);
  color: var(--inchiostro);
  font-size: var(--text-md);
  transition: border-color var(--dur-fast) ease, outline var(--dur-fast) ease;
}

.form-input:focus,
.form-select:focus,
.form-textarea:focus {
  border-color: var(--theme-accent);
  outline: 2px solid var(--theme-accent);
}

.form-grid-2 {
  display: grid;
  grid-template-columns: 1fr;
  gap: 20px;
}

@media (min-width: 640px) {
  .form-grid-2 {
    grid-template-columns: 1fr 1fr;
  }
}

.form-checkbox-label {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  font-size: 14px;
  color: var(--text-muted);
  cursor: pointer;
  /* Sans cette respiration, la zone cliquable tombait à 21 px de haut : la
     hauteur de ligne d'un texte de 14 px, et rien de plus. Trois pixels sous
     le seuil de 24 px de WCAG 2.2 (SC 2.5.8), sur la case RGPD — c'est-à-dire
     sur un champ obligatoire, au doigt, sur téléphone. Les options de
     réservation, elles, ont leur propre padding et ne sont pas concernées. */
  padding-block: 4px;
}

.form-checkbox-label input {
  margin-top: 4px;
}

/* Honeypot Masqué */
.antispam-field {
  opacity: 0;
  position: absolute;
  top: 0;
  left: 0;
  height: 0;
  width: 0;
  z-index: -1;
}

/* Messages d'état de formulaire */
.form-status {
  padding: 16px;
  border-radius: var(--radius);
  margin-bottom: 24px;
  font-size: 14px;
  display: none;
}

.form-status.status-error {
  display: block;
  background-color: #fde8e8;
  color: #9b1c1c;
  border: 1px solid #f8b4b4;
}

.form-status.status-loading {
  display: block;
  background-color: var(--calce);
  color: var(--inchiostro);
}

/* Accueil d'une demande de réservation arrivée depuis un bouton « Réserver » :
   une note de contexte, pas une alerte. Le liseré brun la rattache au parcours
   de réservation sans emprunter le rouge de l'erreur. */
.form-status.status-info {
  display: block;
  background-color: var(--calce);
  color: var(--inchiostro);
  border-left: 3px solid var(--brun-apulia);
}

/* ==========================================================================
   8. ACCORDÉONS FAQ
   ========================================================================== */

/* FAQ — liste de filets, pas de cartes (maquette 2l).
   Chaque question est une ligne fine séparée par un filet ; sur desktop la
   liste passe à deux colonnes, chaque ligne s'ouvrant sans déplacer la
   colonne voisine puisque les cellules sont alignées en haut. */
.faq-list {
  margin-top: 32px;
  border-bottom: 1px solid var(--border-light);
}

/* Deux colonnes seulement là où la liste est longue et le conteneur large :
   la page FAQ et le contact. Dans un conteneur étroit — le rappel de cinq
   questions en accueil — la colonne unique reste la bonne largeur de lecture. */
@media (min-width: 900px) {
  .faq-list--deux-colonnes {
    display: grid;
    grid-template-columns: 1fr 1fr;
    align-items: start;
    column-gap: 64px;
  }
}

.faq-item {
  border-top: 1px solid var(--border-light);
}

/* En deux colonnes, la première ligne de la colonne de droite doit garder son
   filet haut : elle n'est pas la suite de la colonne de gauche. */
.faq-question {
  width: 100%;
  padding: 22px 0;
  text-align: left;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 24px;
  cursor: pointer;
  background: none;
  font-family: var(--font-display);
  font-size: var(--text-lg);
  line-height: 1.3;
  color: var(--inchiostro);
  transition: color var(--dur-fast) ease;
}

.faq-question:hover { color: var(--theme-accent); }

.faq-icon {
  flex: none;
  font-family: var(--font-body);
  font-size: 22px;
  font-weight: 300;
  line-height: 1;
  color: var(--theme-accent);
  transition: transform var(--dur-medium) ease;
}

.faq-item.is-open .faq-icon {
  transform: rotate(45deg);
}

.faq-answer {
  max-height: 0;
  overflow: hidden;
  transition: max-height var(--dur-medium) ease, padding var(--dur-medium) ease;
  padding: 0;
  color: var(--text-muted);
  font-size: var(--text-md);
}

.faq-item.is-open .faq-answer {
  max-height: 400px;
  padding: 0 48px 24px 0;
}

.faq-answer p { margin-bottom: 0; }

/* ==========================================================================
   9. BANDEAU DE CONSENTEMENT (Consent Mode v2)
   ========================================================================== */

/* --------------------------------------------------------------------------
   Ambiance sonore — interrupteur fixe
   En bas à gauche, en pendant du socle d'actions de droite. Fixe et non posé
   dans le hero : la musique démarre au premier geste du visiteur, elle doit
   pouvoir être coupée depuis n'importe quel endroit de la page. Un son qu'on
   ne sait pas arrêter est un son qu'on subit.
   ------------------------------------------------------------------------ */
.ambiance-bouton {
  position: fixed;
  left: 24px;
  bottom: 24px;
  z-index: 80;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 16px 10px 12px;
  background-color: var(--sale);
  border: 1px solid var(--border-medium);
  border-radius: var(--radius);
  box-shadow: 0 8px 28px rgba(23, 28, 25, 0.20);
  color: var(--inchiostro);
  font: inherit;
  font-size: var(--text-sm);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background-color var(--dur-medium) ease, color var(--dur-medium) ease;
}

@media (min-width: 1024px) {
  .ambiance-bouton { left: 32px; bottom: 32px; }
}

/* Sur mobile, il se pose au-dessus de la barre fixe basse, comme le socle. */
@media (max-width: 767px) {
  .ambiance-bouton { bottom: calc(64px + env(safe-area-inset-bottom)); }
  .ambiance-texte { display: none; }
  .ambiance-bouton { padding: 10px 12px; }
}

.ambiance-bouton:hover,
.ambiance-bouton:focus-visible {
  background-color: var(--calce);
}

/* En marche, le bouton prend l'accent : l'état se lit d'un coup d'œil, même
   de loin, sans avoir à distinguer l'icône. */
.ambiance-bouton[aria-pressed="true"] {
  background-color: var(--theme-accent);
  border-color: var(--theme-accent);
  color: var(--theme-accent-contrast);
}

.ambiance-icone { display: flex; }

/* Éteint : la barre oblique est là, les ondes sont absentes. En marche,
   l'inverse. Deux états lisibles sans recours à la couleur. */
.ambiance-onde { opacity: 0; transition: opacity var(--dur-medium) ease; }
.ambiance-barre { opacity: 1; transition: opacity var(--dur-medium) ease; }
.ambiance-bouton[aria-pressed="true"] .ambiance-onde { opacity: 1; }
.ambiance-bouton[aria-pressed="true"] .ambiance-barre { opacity: 0; }

/* Rien ne flotte par-dessus le tiroir de navigation ni le bandeau cookies :
   même règle que pour le socle de droite. */
body.is-locked .ambiance-bouton,
body.has-cookie-banner .ambiance-bouton {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

/* Réservé aux lecteurs d'écran : le libellé d'un interrupteur dont l'état
   visible est porté par la piste colorée, invisible pour eux. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* « Gérer les cookies » : un bouton qui doit se lire comme le reste du pied
   de page, pas comme une action de formulaire. */
.footer-cookies {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  font-size: 12px;
  color: inherit;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 2px;
  text-align: left;
}

.footer-cookies:hover { color: var(--sale); }

/* Carte compacte, en bas à droite : deux boutons de même poids visuel, et le
   refus en lien nu juste dessous. Un refus doit rester aussi atteignable
   qu'un accord — c'est la condition d'un consentement libre. */
.cookie-banner {
  position: fixed;
  bottom: 24px;
  left: 24px;
  right: 24px;
  max-width: 440px;
  background-color: var(--sale);
  border: 1px solid var(--border-medium);
  border-top: 2px solid var(--theme-accent);
  border-radius: var(--radius);
  box-shadow: 0 18px 48px rgba(23, 28, 25, 0.18);
  padding: 24px;
  z-index: 200;
  display: none;
  flex-direction: column;
  gap: 12px;
}

@media (min-width: 640px) {
  .cookie-banner { left: auto; right: 24px; }
}

.cookie-banner.is-visible { display: flex; }

.cookie-title {
  font-family: var(--font-display);
  font-size: var(--text-lg);
  margin: 0;
}

.cookie-text {
  font-size: var(--text-base);
  line-height: 1.6;
  color: var(--text-muted);
  margin: 0;
}

.cookie-text a {
  color: var(--theme-accent);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.cookie-actions {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
}

.cookie-actions .btn { flex: 1 1 0; }

/* Le refus n'est pas un bouton : c'est un lien, posé au centre sous les deux
   actions, comme sur le site de rendez-vous de la clinique. */
.cookie-sans {
  background: none;
  border: 0;
  padding: 2px;
  margin: 0 auto;
  font: inherit;
  font-size: var(--text-sm);
  color: var(--text-muted);
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.cookie-sans:hover { color: var(--inchiostro); }

/* --------------------------------------------------------------------------
   Fenêtre de préférences : une catégorie par accordéon, son interrupteur à
   côté du titre. Déplier n'accorde rien, et cocher ne déplie pas : les deux
   gestes sont distincts, pour qu'aucun accord ne parte d'un clic de lecture.
   ------------------------------------------------------------------------ */
.cookie-modal {
  position: fixed;
  inset: 0;
  z-index: 210;
  display: grid;
  place-items: center;
  padding: 16px;
}

.cookie-modal[hidden] { display: none; }

.cookie-modal-voile {
  position: absolute;
  inset: 0;
  background-color: rgba(23, 28, 25, 0.55);
}

.cookie-modal-carte {
  position: relative;
  background-color: var(--sale);
  border-radius: var(--radius);
  border-top: 2px solid var(--theme-accent);
  box-shadow: 0 24px 64px rgba(23, 28, 25, 0.28);
  width: 100%;
  max-width: 620px;
  max-height: min(84vh, 680px);
  display: flex;
  flex-direction: column;
}

.cookie-modal-tete {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 20px 24px;
  border-bottom: 1px solid var(--border-light);
}

.cookie-modal-tete h2 {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  margin: 0;
}

.cookie-modal-fermer {
  background: none;
  border: 0;
  cursor: pointer;
  font-size: 26px;
  line-height: 1;
  color: var(--text-muted);
  padding: 2px 8px;
}

.cookie-modal-fermer:hover { color: var(--inchiostro); }

.cookie-modal-corps {
  padding: 18px 24px 8px;
  overflow-y: auto;
}

.cookie-modal-intro {
  font-size: var(--text-base);
  line-height: 1.6;
  color: var(--text-muted);
  padding-bottom: 16px;
  margin: 0;
}

.cookie-modal-intro a {
  color: var(--theme-accent);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.cookie-cat {
  border-top: 1px solid var(--border-light);
  padding: 12px 0;
}

.cookie-cat-tete {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
}

.cookie-cat-toggle {
  display: flex;
  align-items: center;
  gap: 10px;
  background: none;
  border: 0;
  padding: 4px 0;
  font: inherit;
  font-size: var(--text-md);
  font-weight: 600;
  color: var(--inchiostro);
  cursor: pointer;
  text-align: left;
}

.cookie-cat-chevron {
  width: 8px;
  height: 8px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  rotate: -45deg;
  transition: rotate var(--dur-fast) var(--ease-out-quad);
  flex: 0 0 auto;
}

.cookie-cat-toggle[aria-expanded="true"] .cookie-cat-chevron { rotate: 45deg; }

.cookie-cat-etat {
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--oliva);
  white-space: nowrap;
}

.cookie-cat-corps p {
  font-size: var(--text-base);
  line-height: 1.6;
  color: var(--text-muted);
  padding: 6px 0 4px 18px;
  margin: 0;
}

/* Interrupteur rectangulaire : la charte interdit l'arrondi organique, la
   pastille ronde des interrupteurs habituels avec. */
.cookie-switch {
  position: relative;
  display: inline-flex;
  flex: 0 0 auto;
  cursor: pointer;
}

.cookie-switch input {
  position: absolute;
  inset: 0;
  opacity: 0;
  margin: 0;
  cursor: pointer;
}

.cookie-switch-piste {
  width: 42px;
  height: 22px;
  border-radius: var(--radius);
  background-color: var(--border-medium);
  transition: background-color var(--dur-fast) ease;
  position: relative;
}

.cookie-switch-piste::after {
  content: "";
  position: absolute;
  top: 3px;
  left: 3px;
  width: 16px;
  height: 16px;
  border-radius: var(--radius);
  background-color: var(--sale);
  transition: translate var(--dur-fast) var(--ease-out-quad);
}

.cookie-switch input:checked + .cookie-switch-piste {
  background-color: var(--theme-accent);
}

.cookie-switch input:checked + .cookie-switch-piste::after { translate: 20px 0; }

.cookie-switch input:focus-visible + .cookie-switch-piste {
  outline: 2px solid var(--theme-accent);
  outline-offset: 2px;
}

.cookie-modal-pied {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  padding: 16px 24px;
  border-top: 1px solid var(--border-light);
}

.cookie-modal-pied .btn { flex: 1 1 180px; }

/* --------------------------------------------------------------------------
   Plan d'accès
   Tout le monde voit un plan : une image composée depuis OpenStreetMap et
   servie par le site, qui n'appelle personne. Le plan interactif de Google la
   remplace après accord. La mention se pose en bandeau sur le bas du cadre,
   là où une carte porte d'ordinaire son attribution.
   ------------------------------------------------------------------------ */
.carte-statique {
  position: absolute;
  inset: 0;
  display: block;
}

.carte-statique[hidden] { display: none; }

.carte-statique img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.carte-consentement {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  padding: 12px 16px;
  background-color: rgba(251, 250, 248, 0.94);
  border-top: 1px solid var(--border-light);
}

.carte-consentement p {
  font-size: var(--text-sm);
  line-height: 1.5;
  color: var(--text-muted);
  margin: 0;
  max-width: 52ch;
}

.carte-consentement .btn { flex: 0 0 auto; }

/* Sous 600 px, le bandeau prendrait la moitié du cadre : le bouton passe sous
   le texte, et la mention se resserre. */
@media (max-width: 599px) {
  .carte-consentement { padding: 10px 12px; gap: 8px; }
  .carte-consentement p { font-size: var(--text-xs); }
  .carte-consentement .btn { width: 100%; }
}

/* ==========================================================================
   10. FOOTER GLOBAL & MAILLAGE LOCAL
   ========================================================================== */

.site-footer {
  background-color: var(--inchiostro);
  color: var(--calce);
  padding: 80px 0 40px;
  margin-top: auto;
  border-top: 1px solid var(--border-dark);
}

.footer-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 48px;
  margin-bottom: 60px;
}

@media (min-width: 640px) {
  .footer-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 1024px) {
  .footer-grid {
    grid-template-columns: 1.5fr 1fr 1fr 1.2fr;
  }
}

.footer-title {
  font-family: var(--font-display);
  font-size: 18px;
  color: var(--sale);
  margin-bottom: 20px;
}

.footer-links {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 12px;
  font-size: 14px;
}

.footer-links a {
  color: rgba(251, 250, 248, 0.75);
}

.footer-links a:hover {
  color: var(--brun-clair);
}

.footer-seo-links {
  border-top: 1px solid var(--border-dark);
  padding-top: 32px;
  margin-bottom: 32px;
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  font-size: 12px;
  color: rgba(251, 250, 248, 0.5);
}

.footer-seo-links a {
  color: inherit;
}

.footer-bottom {
  border-top: 1px solid var(--border-dark);
  padding-top: 24px;
  display: flex;
  flex-direction: column;
  gap: 16px;
  font-size: 12px;
  color: rgba(251, 250, 248, 0.5);
}

@media (min-width: 768px) {
  .footer-bottom {
    flex-direction: row;
    justify-content: space-between;
  }
}

/* Signature de l'agence.
   Elle vit dans la phrase du copyright, pas sur une ligne à elle : la rangée
   reste donc un `space-between` à trois éléments — copyright, cookies, langue
   — et son équilibre n'est pas redistribué. Seul le premier s'allonge.

   Le lien monte à 0,75 d'opacité là où la phrase qui le porte est à 0,50,
   soit 9,68:1 contre 5,02:1 sur l'encre du footer. Un nom propre au milieu
   d'une phrase doit se voir comme un lien sans qu'on ait à le survoler, d'où
   aussi le soulignement : la couleur seule ne suffit pas à signaler un lien.
   Le brun clair du survol tient 4,86:1. */
.footer-signature {
  color: rgba(251, 250, 248, 0.75);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}

.footer-signature:hover,
.footer-signature:focus-visible {
  color: var(--brun-clair);
}

/* Sur téléphone, la signature prend sa propre ligne.
   La rangée passe déjà en colonne sous 768 px, mais la phrase du copyright
   reste un seul bloc de texte : la signature s'y accrochait en fin de ligne,
   au gré du repli. Elle devient un bloc, donc elle commence sa ligne.

   Le séparateur part avec elle et disparaît : laissé dans la phrase, le « · »
   serait resté pendu après « réservés », à la fin d'une ligne qui ne sépare
   plus rien. */
@media (max-width: 767px) {
  .footer-credit { display: block; }
  .footer-credit-separateur { display: none; }
}

/* ==========================================================================
   11. ANIMATIONS & SCROLL REVEAL
   ========================================================================== */

.reveal-on-scroll.reveal-armed {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity var(--dur-reveal) ease, transform var(--dur-reveal) ease;
}

.reveal-on-scroll.reveal-armed.is-revealed {
  opacity: 1;
  transform: translateY(0);
}

/* ==========================================================================
   12. CARROUSEL DU HERO (charte §6.5 — fondu croisé 800 ms, avance 7 s)
   ========================================================================== */

.hero-slides {
  position: absolute;
  inset: 0;
  z-index: 1;
}

.hero-slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity var(--dur-slow) ease-in-out;
}

.hero-slide.is-active {
  opacity: 1;
}

.hero-slide video,
.hero-slide img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.hero-dots {
  position: absolute;
  right: var(--page-padding);
  bottom: 34px;
  z-index: 4;
  display: flex;
  gap: 10px;
}

.hero-dot {
  width: 40px;
  height: 2px;
  background-color: rgba(251, 250, 248, 0.4);
  border-radius: 0;
  cursor: pointer;
  padding: 12px 0;
  background-clip: content-box;
  transition: background-color var(--dur-medium) ease;
}

.hero-dot.is-active {
  background-color: var(--brun-clair);
}

/* ==========================================================================
   13. SÉQUENCE DE CHARGEMENT DE L'ACCUEIL (charte §6.1 — 900 ms, une fois)
   ========================================================================== */

.seq-run .hero-slide.is-active { animation: seqMedia 600ms ease both; }
.seq-run .hero-title           { animation: seqTitle 700ms cubic-bezier(.16,1,.3,1) 200ms both; }
.seq-run .hero-sub,
.seq-run .hero-actions         { animation: seqRise 450ms ease-out 450ms both; }
.seq-run .site-header          { animation: seqFade 300ms ease 600ms both; }

@keyframes seqMedia { from { opacity: 0 } to { opacity: 1 } }
@keyframes seqTitle {
  from { clip-path: inset(100% 0 0 0) }
  to   { clip-path: inset(0 0 0 0) }
}
@keyframes seqRise  { from { opacity: 0; transform: translateY(16px) } to { opacity: 1; transform: none } }
@keyframes seqFade  { from { opacity: 0 } to { opacity: 1 } }

/* ==========================================================================
   14. APLAT DE REMPLACEMENT (charte §5 — « tant qu'une photo manque »)
   ========================================================================== */

.media-placeholder {
  position: relative;
  display: flex;
  align-items: flex-end;
  aspect-ratio: 4 / 3;
  border: 1px solid var(--border-light);
  border-radius: var(--radius);
  background-image: repeating-linear-gradient(
    135deg,
    var(--calce) 0 10px,
    rgba(78, 91, 69, 0.10) 10px 20px
  );
}

/* Carte Google — cadre 16:9 sur desktop, plus haut sur mobile où une carte
   large et basse ne montre plus rien d'utile. Le filet reprend celui des
   médias voisins pour que l'iframe ne tranche pas dans la page. */
.carte-embed {
  position: relative;
  aspect-ratio: 16 / 9;
  border: 1px solid var(--border-light);
  border-radius: var(--radius);
  overflow: hidden;
  background-color: var(--calce);
}

.carte-embed iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
}

@media (max-width: 767px) {
  .carte-embed { aspect-ratio: 4 / 3; }
}

.carte-legende {
  margin-top: 16px;
  font-size: var(--text-sm);
  color: var(--text-muted);
}

.media-placeholder[data-ratio="3:4"] { aspect-ratio: 3 / 4; }
.media-placeholder[data-ratio="4:5"] { aspect-ratio: 4 / 5; }
.media-placeholder[data-ratio="16:9"] { aspect-ratio: 16 / 9; }

.media-placeholder span {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  line-height: 1.5;
  color: var(--oliva);
  background-color: var(--sale);
  border: 1px solid var(--border-light);
  padding: 6px 10px;
  margin: 16px;
  max-width: calc(100% - 32px);
}

/* ==========================================================================
   15. TABLEAU DE PRIX ET EXTRAS (charte §5)
   ========================================================================== */

.prix-table-wrap { overflow-x: visible; }

.prix-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-base);
}

.prix-table th,
.prix-table td {
  text-align: left;
  padding: 18px 16px;
  border-bottom: 1px solid var(--border-light);
  vertical-align: top;
}

.prix-table thead th {
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--oliva);
  border-bottom: 1px solid var(--border-medium);
}

.prix-table .col-prix {
  font-family: var(--font-display);
  font-size: var(--text-2xl);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.prix-table tr.is-featured {
  background-color: var(--calce);
}

/* La ligne mise en avant se signale par son fond et par son badge « la plus
   demandée ». Elle portait en plus un filet d'un pixel sur sa seule première
   cellule : dans un tableau sans bordure verticale, ce trait isolé ne se
   lisait pas comme une mise en avant mais comme un défaut d'affichage. */

.formule-nom {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  display: block;
  margin-bottom: 4px;
}

.formule-duree {
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--oliva);
}

.badge-signature {
  display: inline-block;
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--oliva);
  border: 1px solid var(--theme-accent);
  padding: 3px 8px;
  border-radius: var(--radius);
  margin-left: 8px;
}

/* La dernière colonne d'un tableau de prix porte jusqu'à deux actions : le
   bouton de réservation et son jumeau WhatsApp. Empilés, ils laissent la
   colonne étroite ; côte à côte, ils prendraient la place des montants. La
   règle vaut aussi sous 640 px, où le tableau devient des cartes : elle
   l'emporte sur le display: block posé plus bas, et c'est voulu. */
.prix-table .cellule-actions {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 8px;
}

/* Sous 640 px, le tableau devient des cartes empilées — jamais un défilement */
@media (max-width: 639px) {
  .prix-table, .prix-table tbody, .prix-table tr, .prix-table td { display: block; width: 100%; }
  .prix-table thead { display: none; }
  .prix-table tr {
    border: 1px solid var(--border-light);
    border-radius: var(--radius);
    padding: 18px;
    margin-bottom: 16px;
  }
  .prix-table td { border-bottom: none; padding: 4px 0; }
  .prix-table td[data-label]::before {
    content: attr(data-label);
    display: block;
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--oliva);
    margin-top: 10px;
  }
}

/* ==========================================================================
   16. ÉQUIPEMENTS AVEC STATUT (planche 2f)
   ========================================================================== */

.equipement-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 1px;
  background-color: var(--border-light);
  border: 1px solid var(--border-light);
  border-radius: var(--radius);
}

.equipement-item {
  background-color: var(--sale);
  padding: 24px;
}

/* Intertitre de groupe : il sépare ce qui est compris dans le spa de ce qui
   n'existe que dans la Suite Riposo. La distinction est commerciale avant
   d'être décorative — elle ne doit jamais passer inaperçue. */
.equipement-groupe {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  margin-bottom: 8px;
}

.equipement-grid + .equipement-groupe {
  margin-top: 48px;
}

.equipement-groupe-note {
  font-size: var(--text-base);
  color: var(--text-muted);
  max-width: 68ch;
  margin-bottom: 20px;
}

.equipement-groupe + .equipement-grid {
  margin-top: 20px;
}

.equipement-item h3 {
  font-size: var(--text-xl);
  margin-bottom: 6px;
}

.equipement-item p {
  font-size: var(--text-base);
  color: var(--text-muted);
  margin-bottom: 12px;
}

.statut {
  display: inline-block;
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--oliva);
  border: 1px solid var(--border-medium);
  padding: 3px 8px;
  border-radius: var(--radius);
}

/* ==========================================================================
   17. SÉLECTEUR DE MONTANT — CHÈQUE CADEAU (planche 1b)
   ========================================================================== */

.gift-amounts {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 20px;
}

.gift-amount {
  font-family: var(--font-body);
  font-size: var(--text-base);
  font-weight: 600;
  letter-spacing: 0.06em;
  min-height: 48px;
  padding: 12px 22px;
  border: 1px solid var(--border-medium);
  border-radius: var(--radius);
  background-color: transparent;
  cursor: pointer;
  transition: border-color var(--dur-fast) ease, opacity var(--dur-fast) ease;
}

.gift-amount:hover { opacity: 0.88; }

.gift-amount.is-active {
  border-color: var(--theme-accent);
  border-width: 2px;
}

.gift-custom {
  min-height: 48px;
  padding: 12px 16px;
  border: 1px solid var(--border-medium);
  border-radius: var(--radius);
  background-color: var(--sale);
  width: 180px;
  margin-bottom: 20px;
}

.gift-total {
  font-family: var(--font-display);
  font-size: var(--text-3xl);
  display: block;
  margin-bottom: 20px;
  font-variant-numeric: tabular-nums;
}

/* ==========================================================================
   18. DIVERS
   ========================================================================== */

body.is-locked { overflow: hidden; }

.mobile-nav-toggle-btn {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  min-height: 48px;
  cursor: pointer;
  text-align: left;
}

/* Deuxième ligne d'une cellule de tableau : le sous-titre du soin, sous son
   nom, sans peser autant que lui. */
.soin-desc {
  display: block;
  margin-top: 4px;
  font-size: var(--text-sm);
  color: var(--text-muted);
}

.note-source {
  font-size: var(--text-base);
  color: var(--text-muted);
  border-left: 2px solid var(--border-medium);
  padding-left: 16px;
  margin-top: 24px;
}

/* Mouvement réduit — charte §6.7 :
   largeurs du sélecteur figées, seul le filet d'accent apparaît. */
@media (prefers-reduced-motion: reduce) {
  .intention-panel:hover { flex: 1; }
  .intention-panel:hover .intention-bg { filter: saturate(0.65) brightness(0.85); }
  .hero-slide { transition: none; }
  .seq-run .hero-slide.is-active,
  .seq-run .hero-title,
  .seq-run .hero-sub,
  .seq-run .hero-actions,
  .seq-run .site-header { animation: none; }
}

/* ==========================================================================
   19. PIED DE PAGE — classes du gabarit partagé
   ========================================================================== */

/* Le pied de page porte la signature complète, arbre compris : c'est le seul
   endroit du site qui lui donne la largeur minimale demandée par la charte. */
.footer-brand {
  display: block;
  width: 148px;
  max-width: 100%;
  margin-bottom: 24px;
  line-height: 0;
}

@media (min-width: 1024px) {
  .footer-brand { width: 176px; }
}

.footer-brand img {
  display: block;
  width: 100%;
  height: auto;
}

.footer-baseline {
  font-size: var(--text-base);
  color: var(--text-muted-dark);
  margin-bottom: 20px;
}

.footer-coords {
  font-size: var(--text-base);
  color: var(--text-muted-dark);
  line-height: 1.9;
}

.footer-coords a:hover { opacity: 0.88; }

.footer-lang {
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.14em;
}

.cookie-details {
  font-size: var(--text-sm);
  color: var(--text-muted);
  align-self: center;
  text-decoration: underline;
}

.drawer-close {
  color: var(--sale);
  font-size: var(--text-xl);
  cursor: pointer;
  min-width: 48px;
  min-height: 48px;
}

.drawer-footer a:hover { opacity: 0.88; }

/* ==========================================================================
   20. GABARITS DE SECTION
   ========================================================================== */

/* --- Rythme vertical ------------------------------------------------------
   Règle unique : c'est toujours la section qui S'OUVRE qui pose le pas.
   Une section transparente ne referme rien en bas ; un bandeau coloré, si,
   parce qu'il dessine un bord visible. Deux paddings ne se cumulent donc
   jamais, et aucun titre ne peut se retrouver collé au bord de son bandeau.
   ------------------------------------------------------------------------- */

.section {
  padding-top: var(--section-gap);
  padding-bottom: 0;
}

/* Fonds de bandeau — en classes, jamais en style en ligne : c'est ce qui
   permet aux garde-fous ci-dessous de faire leur travail. */
.bg-sale        { background-color: var(--sale); }
.bg-calce       { background-color: var(--calce); }
.bg-inchiostro  { background-color: var(--inchiostro); color: var(--sale); }
.bg-inchiostro h2,
.bg-inchiostro h3 { color: var(--sale); }

/* La section qui suit immédiatement le hero d'une page reprend au demi-pas :
   le hero a déjà donné sa respiration basse. */
.page-hero + .section { padding-top: var(--section-gap-sm); }

/* GARDE-FOU DE RYTHME — ne pas retirer.
   Un bandeau qui porte son propre fond garde sa respiration complète, en haut
   comme en bas, quelle que soit sa position dans la page. C'est ce qui empêche
   « Les extras » — ou n'importe quel autre titre de bandeau — de se coller au
   bord de son aplat de couleur. */
.section.bg-sale,
.section.bg-calce,
.section.bg-inchiostro,
.page-hero + .section.bg-sale,
.page-hero + .section.bg-calce,
.page-hero + .section.bg-inchiostro {
  padding-top: var(--section-gap-lg);
  padding-bottom: var(--section-gap-lg);
}

/* Les bandeaux qui ne passent pas par .section suivent la même règle : ils
   portent une couleur, ils prennent le pas large. (.section-formules et
   .section-cta portent la leur sur leur propre déclaration, plus bas dans le
   fichier — la déclarer ici ne servirait à rien.) */
.section-sombre,
.intention-section { padding: var(--section-gap-lg) 0; }

/* Une section transparente qui précède un bandeau doit se refermer : sans
   cela, son dernier élément vient buter contre l'aplat de couleur et les deux
   sections se lisent comme une seule. Le :not() empêche la règle de retomber
   sur un bandeau — il a déjà son pas large ci-dessus.

   `:not(.premier-feature)` est la seule exception, et elle est délibérée : ce
   bloc-là est tenu à 40 px en bas par la direction. Sans cette réserve, la
   règle l'emporterait — un :has() pèse la spécificité de son argument, ce qui
   met ces sélecteurs à 0-6-0, hors d'atteinte de toute liste raisonnable. */
.section:not(.bg-sale):not(.bg-calce):not(.bg-inchiostro):not(.premier-feature):has(+ .section.bg-sale),
.section:not(.bg-sale):not(.bg-calce):not(.bg-inchiostro):not(.premier-feature):has(+ .section.bg-calce),
.section:not(.bg-sale):not(.bg-calce):not(.bg-inchiostro):not(.premier-feature):has(+ .section.bg-inchiostro),
.section:not(.bg-sale):not(.bg-calce):not(.bg-inchiostro):not(.premier-feature):has(+ .section-sombre),
.section:not(.bg-sale):not(.bg-calce):not(.bg-inchiostro):not(.premier-feature):has(+ .section-formules),
.section:not(.bg-sale):not(.bg-calce):not(.bg-inchiostro):not(.premier-feature):has(+ .section-cta) {
  padding-bottom: var(--section-gap);
}

/* Après un bandeau, le fond change : le demi-pas suffit à marquer la reprise.
   Le :where() garde ce sélecteur à une spécificité de simple classe, pour que
   le garde-fou ci-dessus reste prioritaire quand deux bandeaux se suivent. */
:where(.section.bg-sale,
       .section.bg-calce,
       .section.bg-inchiostro,
       .section-sombre,
       .section-formules) + .section { padding-top: var(--section-gap-sm); }

/* Une dernière section transparente doit quand même se refermer avant le pied
   de page, si aucun bandeau de conversion ne la suit. */
main > .section:last-child { padding-bottom: var(--section-gap); }

/* Dernier filet de sécurité, si un style en ligne réintroduit le problème
   qu'on vient de corriger sur l'ensemble du site. */
.section[style*="background"][style*="padding-top: 0"],
.section[style*="background"][style*="padding-top:0"] {
  padding-top: var(--section-gap) !important;
}

/* Les ancres internes ne doivent pas atterrir sous la barre collante. */
main [id],
section[id] { scroll-margin-top: calc(var(--header-h) + 24px); }

.section-head { margin-bottom: 48px; }
.section-head h2 { margin-bottom: 20px; }

.split-media-duo {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--gutter);
  align-items: start;
}

.split-media-duo picture:last-child { margin-top: 40px; }

.split-media-duo img {
  width: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  border-radius: var(--radius);
}

/* Lien de texte : filet d'accent de gauche à droite (charte §6.5) */
/* Lien dans le fil du texte. `.link-underline` est un lien de bloc — capitales,
   graisse 600, marge à gauche : il ne peut pas se glisser au milieu d'une
   phrase sans en casser la ligne. */
.lien-inline {
  color: var(--theme-accent);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  text-decoration-color: rgba(190, 154, 92, 0.5);
}

.lien-inline:hover { text-decoration-color: currentColor; }

.link-underline {
  position: relative;
  display: inline-block;
  font-size: var(--text-base);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  margin-left: 24px;
  padding-bottom: 3px;
}

.link-underline::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 1px;
  background-color: var(--theme-accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 200ms ease-out;
}

.link-underline:hover::after,
.link-underline:focus-visible::after { transform: scaleX(1); }

@media (max-width: 639px) {
  .link-underline { margin-left: 0; margin-top: 16px; display: block; }
}

/* Prix en ligne dans un bloc éditorial */
.prix-inline {
  margin: 28px 0;
  padding: 18px 0;
  border-top: 1px solid var(--border-dark);
  border-bottom: 1px solid var(--border-dark);
}

.prix-inline-montant {
  font-family: var(--font-display);
  font-size: var(--text-2xl);
  color: var(--sale);
  font-variant-numeric: tabular-nums;
}

.prix-inline-note {
  font-size: var(--text-base);
  color: var(--text-muted-dark);
  margin-left: 12px;
}

/* Carte produit (massage) */
.produit-card {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 24px;
  background-color: var(--calce);
  border-radius: var(--radius);
  padding: 24px;
  margin: 28px 0;
}

.produit-nom {
  display: block;
  font-family: var(--font-display);
  font-size: var(--text-xl);
}

.produit-meta {
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--oliva);
}

.produit-prix {
  font-family: var(--font-display);
  font-size: var(--text-2xl);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* Étiquette de lien en display. Tout ce qui est petit était en sans, en
   capitales, à +0,14 em : net, mais administratif. Le serif descendu à 15 px,
   sans capitales et sans interlettrage, rend le ton éditorial sans changer la
   hiérarchie. Les surtitres, eux, restent en sans capitales : ce sont des
   étiquettes de rubrique, pas des mots à lire. */
.libelle-display {
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 500;
  letter-spacing: normal;
  text-transform: none;
  line-height: 1.3;
}

/* Étiquette de lien des vignettes vidéo. Elle portait l'accent adriatique du
   pôle santé ; elle reprend l'accent de la maison. */
.lien-libelle {
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 500;
  letter-spacing: normal;
  text-transform: none;
  color: var(--theme-accent);
}

/* Liste d'informations pratiques */
.infos-list {
  list-style: none;
  margin: 0 0 32px;
  padding: 0;
  max-width: 44ch;
}

.infos-list li {
  padding: 14px 0;
  border-bottom: 1px solid var(--border-light);
  font-size: var(--text-base);
}

.infos-list li:last-child { border-bottom: none; }

/* Bandeau de conversion final */
.section-cta {
  padding: var(--section-gap-lg) 0;
  background-color: var(--inchiostro);
  color: var(--sale);
  text-align: center;
}

.section-cta h2 { color: var(--sale); margin-bottom: 20px; }

.section-cta p {
  color: var(--text-muted-dark);
  max-width: 52ch;
  margin: 0 auto 36px;
}

.cta-actions {
  display: flex;
  gap: 20px;
  justify-content: center;
  flex-wrap: wrap;
}

.faq-more { margin-top: 32px; }

/* Bandeau de réassurance — sans pictogramme décoratif (charte §5) */
.reassurance-item {
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

/* Cadrage des panneaux du sélecteur : le sujet reste dans le champ */
.intention-bg { object-position: center 45%; }

/* ==========================================================================
   21. ÉTAPES NUMÉROTÉES — uniquement pour une séquence réelle
   ========================================================================== */

.etapes {
  list-style: none;
  display: grid;
  grid-template-columns: 1fr;
  gap: 1px;
  background-color: var(--border-light);
  border: 1px solid var(--border-light);
  border-radius: var(--radius);
  margin: 0;
  padding: 0;
  counter-reset: none;
}

@media (min-width: 640px)  { .etapes { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .etapes { grid-template-columns: repeat(4, 1fr); } }

.etapes li {
  background-color: var(--sale);
  padding: 28px 24px;
}

.etape-no {
  display: block;
  font-family: var(--font-body);
  font-variant-numeric: tabular-nums;
  font-size: var(--text-sm);
  letter-spacing: 0.14em;
  color: var(--theme-accent);
  margin-bottom: 14px;
}

.etapes h3 { font-size: var(--text-xl); margin-bottom: 8px; }

.etapes p {
  font-size: var(--text-base);
  color: var(--text-muted);
  margin: 0;
}

.lede {
  font-size: var(--text-lg);
  color: var(--text-muted);
  max-width: 62ch;
  margin-bottom: 28px;
}

.breadcrumb {
  font-size: var(--text-sm);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 28px;
}

.breadcrumb a:hover { opacity: 0.88; }
.breadcrumb-active { color: var(--inchiostro); }

/* ==========================================================================
   22. GALERIE
   ========================================================================== */

.galerie {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--gutter);
}

@media (min-width: 640px)  { .galerie { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .galerie { grid-template-columns: repeat(3, 1fr); } }

.galerie figure { margin: 0; }

@media (min-width: 640px) {
  .galerie-large { grid-column: span 2; }
}

.galerie img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: var(--radius);
}

.galerie-large img { aspect-ratio: 16 / 9; }

.galerie figcaption {
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--oliva);
  margin-top: 10px;
}

/* Visuel principal de page */
.media-lead-inner img {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: var(--radius);
}

/* La barre fixe mobile ne doit pas recouvrir le second CTA du hero */
@media (max-width: 767px) {
  .hero-home { padding-bottom: calc(96px + env(safe-area-inset-bottom)); }
  main { padding-bottom: calc(72px + env(safe-area-inset-bottom)); }
}

/* ==========================================================================
   23. MÉGA-MENU (desktop ≥ 1024 px)
   Panneau pleine largeur ancré sous la barre. Aucune ombre, filet 1 px,
   rayon 2 px, fondu + translation de 8 px en 200 ms (charte §6.4).
   ========================================================================== */

@media (min-width: 1024px) {

  /* Le panneau s'ancre sur la barre, pas sur l'item : il occupe toute la largeur */
  .nav-item.has-mega { position: static; }

  /* Le lien s'arrête 20 px au-dessus du bas de la barre, et le panneau commence
     exactement à ce bas : entre les deux, une bande morte qui n'appartient ni à
     l'un ni à l'autre. Le curseur qui descendait vers le panneau y perdait le
     survol, et le panneau se refermait en route. Ce prolongement invisible du
     lien relie les deux zones ; le panneau, déclaré après dans le DOM, reste
     peint au-dessus et garde ses liens cliquables. */
  .nav-item.has-mega > .nav-link { position: relative; }

  .nav-item.has-mega > .nav-link::after {
    content: '';
    position: absolute;
    top: 100%;
    left: -16px;
    right: -16px;
    height: 22px;
  }

  /* Le panneau n'occupe plus toute la largeur : c'est une carte, calée sur la
     marge droite de la page et large de ce que son contenu demande, pas de ce
     que l'écran permet. Elle reste solidaire du bas de la barre — aucun écart
     à franchir, donc le survol ne se perd pas en chemin — et ne dépasse jamais
     la gouttière, quelle que soit la largeur d'écran. */
  .mega-panel {
    position: absolute;
    top: 100%;
    left: auto;
    right: var(--page-padding);
    width: min(880px, calc(100vw - var(--page-padding) * 2));
    border: 1px solid var(--border-light);
    border-top-color: transparent;
    border-radius: 0 0 var(--radius-btn) var(--radius-btn);
    box-shadow: 0 24px 48px -24px rgba(23, 28, 25, 0.22);
    background-color: var(--sale);
    opacity: 0;
    visibility: hidden;
    transform: translateY(8px);
    transition: opacity var(--dur-medium) ease,
                transform var(--dur-medium) ease,
                visibility var(--dur-medium);
    /* Fermeture retardée : le passage d'un item à l'autre, ou un écart de
       quelques pixels, ne doit pas faire clignoter le panneau. */
    transition-delay: 140ms;
  }

  .nav-item.has-mega:hover .mega-panel,
  .nav-item.has-mega:focus-within .mega-panel {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
    transition-delay: 0s;
  }

  /* Fermé à Escape : le :focus-within ci-dessus garderait sinon le panneau
     ouvert, le focus revenant sur le lien. Même spécificité, déclaré après. */
  .nav-item.has-mega.is-dismissed .mega-panel {
    opacity: 0;
    visibility: hidden;
    transform: translateY(8px);
  }

  /* La barre devient opaque tant qu'un panneau est ouvert */
  .site-header.mega-open {
    background-color: var(--sale);
  }

  /* Voile de mise à distance — la charte interdit l'ombre portée (§6.4), c'est
     donc l'assombrissement de la page qui dit que le méga-menu est un calque
     posé par-dessus, et non un morceau du contenu. Même principe que la
     surface d'occultation du tiroir mobile.
     z-index 86 : sous la barre (90), au-dessus du contenu et du socle
     d'actions flottantes (80). */
  body::after {
    content: '';
    position: fixed;
    inset: 0;
    background-color: rgba(23, 28, 25, 0.34);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    z-index: 86;
    transition: opacity var(--dur-medium) ease, visibility var(--dur-medium);
  }

  body.mega-open::after {
    opacity: 1;
    visibility: visible;
  }

  /* Rien ne flotte devant le voile. */
  body.mega-open .floating-actions {
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
  }
  .site-header.mega-open .nav-link { color: var(--inchiostro); }
  /* Barre opaque tant que le panneau est ouvert : la signature passe au brun. */
  .site-header.mega-open .brand-mark--blanc { opacity: 0; }
  .site-header.mega-open .brand-mark--brun { opacity: 1; }

  /* Dans la carte, le conteneur de page n'a plus lieu d'être : il rajouterait
     sa propre gouttière à celle de la carte. */
  .mega-panel .container {
    max-width: none;
    padding-left: 32px;
    padding-right: 32px;
  }

  .mega-inner {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) 240px;
    gap: 36px;
    padding-top: 32px;
    padding-bottom: 32px;
    align-items: start;
  }

  .mega-inner-2 { grid-template-columns: minmax(0, 1fr) 240px; }

  /* Deux colonnes de liens seulement : la carte se resserre d'autant. */
  .mega-panel:has(.mega-inner-2) { width: min(620px, calc(100vw - var(--page-padding) * 2)); }

  .mega-title {
    font-family: var(--font-body);
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--oliva);
    margin: 0 0 18px;
    padding-bottom: 12px;
    border-bottom: 1px solid var(--border-light);
  }


  .mega-list { list-style: none; margin: 0; padding: 0; }

  .mega-list a {
    display: block;
    padding: 10px 0;
    border-bottom: 1px solid var(--rule-hair, rgba(23, 28, 25, 0.06));
    transition: opacity var(--dur-fast) ease;
  }

  .mega-list li:last-child a { border-bottom: none; }
  .mega-list a:hover { opacity: 0.88; }

  .mega-nom {
    display: block;
    font-size: var(--text-lg);
    font-weight: 500;
    color: var(--inchiostro);
    line-height: 1.3;
  }

  .mega-note {
    display: block;
    font-size: var(--text-base);
    color: var(--text-muted);
    margin-top: 3px;
    line-height: 1.45;
  }

  /* Filet d'accent qui monte sous l'intitulé survolé */
  .mega-list a { position: relative; }
  .mega-list a::after {
    content: '';
    position: absolute;
    left: 0;
    bottom: -1px;
    width: 100%;
    height: 1px;
    background-color: var(--theme-accent);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform 200ms ease-out;
  }
  .mega-list a:hover::after,
  .mega-list a:focus-visible::after { transform: scaleX(1); }

  /* Carte mise en avant */
  .mega-feature {
    display: block;
    background-color: var(--calce);
    border-radius: var(--radius);
    padding: 20px;
    transition: opacity var(--dur-fast) ease;
  }

  .mega-feature:hover { opacity: 0.88; }

  .mega-feature img {
    width: 100%;
    aspect-ratio: 16 / 9;
    object-fit: cover;
    border-radius: var(--radius);
    margin-bottom: 16px;
  }

  .mega-feature-texte {
    border-top: 2px solid var(--theme-accent);
  }


  .mega-feature-eyebrow {
    display: block;
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--oliva);
    margin-bottom: 8px;
  }


  .mega-feature-titre {
    display: block;
    font-family: var(--font-display);
    font-size: var(--text-xl);
    line-height: 1.15;
    color: var(--inchiostro);
  }

  .mega-feature-note {
    display: block;
    font-size: var(--text-base);
    color: var(--text-muted);
    margin-top: 8px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .mega-panel { transition: none; transform: none; }
  .mega-list a::after { transition: none; }
}

/* ==========================================================================
   24. LISIBILITÉ DES TITRES — Commissioner
   Poids 500 partout où le caractère display est employé. Commissioner est
   une variable : le 500 est un vrai dessin intermédiaire, pas une graisse
   synthétisée, et il tient aussi bien sur fond clair que sur fond sombre.
   ========================================================================== */

.footer-brand,
.footer-title,
.cookie-title,
.formule-nom,
.gift-total,
.intention-title,
.prix-inline-montant,
.prix-montant,
.produit-nom,
.produit-prix,
.prix-table .col-prix,
.mega-feature-titre,
.carte-titre,
.hero-title,
[style*="--font-display"] {
  font-weight: 500;
}

/* ==========================================================================
   25. ACTIONS FLOTTANTES & RETOUR EN HAUT DE PAGE
   ========================================================================== */

/* Le socle est toujours présent dans le DOM : c'est lui qui se montre au
   scroll, jamais ses enfants un par un. Sans JavaScript, le lien de retour
   fonctionne quand même — c'est une ancre vers #haut-de-page. */
.floating-actions {
  position: fixed;
  right: 24px;
  bottom: 24px;
  z-index: 80;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 10px;
  pointer-events: none;
}

.floating-actions > * {
  pointer-events: auto;
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px);
  transition: opacity var(--dur-medium) var(--ease-standard),
              transform var(--dur-medium) var(--ease-standard),
              visibility var(--dur-medium);
}

.floating-actions.is-visible > * {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

/* Réserver et Appeler ne s'affichent qu'à partir du desktop : en dessous,
   c'est la barre fixe basse qui porte les deux mêmes actions. */
.floating-cta { display: none; }

@media (min-width: 768px) {
  .floating-actions { right: 32px; bottom: 32px; }
  .floating-cta {
    display: inline-flex;
    min-width: 176px;
    box-shadow: 0 8px 28px rgba(23, 28, 25, 0.20);
  }
}

/* Appeler est encre sur encre : au-dessus d'un bandeau sombre, le bouton se
   confondait avec le fond et il ne restait que son texte en l'air. Le filet
   clair lui rend un bord sur les fonds foncés, sans rien changer sur clair. */
.floating-cta.btn-secondary { border: 1px solid var(--border-dark); }

.back-to-top {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border-radius: var(--radius-btn);
  background-color: var(--inchiostro);
  color: var(--sale);
  border: 1px solid var(--border-dark);
  font-size: var(--text-lg);
  line-height: 1;
  cursor: pointer;
  box-shadow: 0 8px 28px rgba(23, 28, 25, 0.20);
}

.back-to-top:hover { background-color: var(--theme-accent); color: var(--theme-accent-contrast); }

/* Sur mobile, le socle se pose au-dessus de la barre fixe basse. */
@media (max-width: 767px) {
  .floating-actions { bottom: calc(64px + env(safe-area-inset-bottom)); }
}

/* Rien ne flotte par-dessus le tiroir de navigation ni le bandeau cookies. */
body.is-locked .floating-actions,
body.has-cookie-banner .floating-actions {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

/* ==========================================================================
   26. GRILLE À TROIS COLONNES & ENCADRÉS PRATIQUES
   ========================================================================== */

.grille-3 {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--gutter);
}

@media (min-width: 640px)  { .grille-3 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .grille-3 { grid-template-columns: repeat(3, 1fr); } }

/* Encadré d'appui : un fait, une phrase. Pas une carte de service. */
/* Le filet complet garantit que la carte se détache aussi bien sur le fond
   sel que sur le fond chaux : elle n'est jamais invisible. */
.carte-point {
  background-color: var(--sale);
  border: 1px solid var(--border-light);
  border-top: 2px solid var(--theme-accent);
  border-radius: var(--radius);
  padding: 28px 24px;
}

.carte-point h3 {
  font-size: var(--text-xl);
  color: var(--theme-accent);
  margin-bottom: 10px;
}

.carte-point p {
  font-size: var(--text-base);
  color: var(--text-muted);
  margin: 0;
}

/* Les CTA d'un hero s'alignent sur le texte, pas au centre comme en bandeau. */
.cta-actions-gauche { justify-content: flex-start; }

/* Encadré tarifaire adossé à un bloc éditorial */
.encadre-tarifs {
  background-color: var(--calce);
  border-radius: var(--radius);
  border-left: 2px solid var(--theme-accent);
  padding: 28px 24px;
}

.encadre-tarifs h2,
.encadre-tarifs h3 {
  font-size: var(--text-xl);
  color: var(--theme-accent);
  margin-bottom: 12px;
}

.encadre-tarifs p {
  font-size: var(--text-base);
  color: var(--text-muted);
}

.encadre-tarifs-lien { margin-top: 20px; }

/* Maillage latéral entre services : des pastilles, pas des cartes. */
.liens-services {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  list-style: none;
  margin: 0;
  padding: 0;
}

.liens-services a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 10px 18px;
  border: 1px solid var(--border-light);
  border-radius: var(--radius);
  background-color: var(--sale);
  font-size: var(--text-base);
  transition: border-color var(--dur-fast) ease, color var(--dur-fast) ease;
}

.liens-services a:hover {
  border-color: var(--theme-accent);
  color: var(--theme-accent);
  opacity: 1;
}
/* ==========================================================================
   APULIA — COMPOSANTS DE LA REFONTE VISUELLE (août 2026)
   À concaténer à la fin de css/style.css, ou à charger après lui.
   Aucun jeton nouveau : tout vient de css/tokens.css.
   HTML/CSS/JS vanilla. Aucune librairie.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. EN-TÊTE DE PAGE IMMERSIF — remplace .page-hero sur les pages intérieures
   -------------------------------------------------------------------------- */

/* Hauteur plancher, pas hauteur imposée.
   Le hero valait `height: 50vh; min-height: 420px` avec `overflow: hidden` :
   une boîte fermée. Sur un téléphone étroit, une page au titre long dépassait
   cette boîte et se faisait rogner par le haut — sur Formules & tarifs en
   375 px, 440 px de contenu dans 420 px de cadre : le fil d'Ariane et le
   surtitre disparaissaient entièrement, et le titre perdait sa première
   ligne. Le défaut ne se voyait pas sur un écran large, où tout entre.

   `min-height` remplace `height` : le hero garde exactement la même taille
   quand le contenu tient — et il grandit quand il ne tient pas, au lieu de
   couper. Le `clamp` de la version large reproduit l'ancien trio
   560 / 60vh / 720 comme plancher, sans plafonner ce qui déborderait.

   Le hero devient aussi son propre conteneur flex : c'est lui qui cale le
   contenu en bas désormais. L'enfant ne peut plus le faire, puisqu'il n'a
   plus de hauteur fixe contre laquelle s'aligner. Le média reste en absolu,
   donc hors flux : il remplit la hauteur, quelle qu'elle soit. */
.hero-immersif {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: max(50vh, 420px);
  overflow: hidden;
  background-color: var(--inchiostro);
  color: var(--sale);
  /* La barre collante est en flux au-dessus : ne pas recompter --header-h. */
}

@media (min-width: 1024px) {
  .hero-immersif { min-height: clamp(560px, 60vh, 720px); }
}

/* Le média : vidéo quand la page en a une, sinon <picture>. Même règle. */
.hero-immersif-media,
.hero-immersif-media img,
.hero-immersif-media video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.hero-immersif-media img,
.hero-immersif-media video { filter: saturate(0.8); }

/* Voile dégradé bas → haut. Le titre doit tenir 4,5:1 minimum ; la butée
   haute à 0,45 est ce qui permet à la barre transparente et à son logo blanc
   de rester lisibles sur un plafond clair. */
.hero-immersif::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(
    0deg,
    rgba(23, 28, 25, 0.88) 0%,
    rgba(23, 28, 25, 0.55) 42%,
    rgba(23, 28, 25, 0.45) 100%
  );
}

/* Le contenu est calé en bas du hero, avec 40 px de garde en haut comme en
   bas. Les 40 px du bas sont une respiration ; ceux du haut sont une butée.

   Le hero a une hauteur fixe — 50vh, au moins 420 px — et `overflow: hidden`.
   Un titre court flotte donc en bas sans rien toucher, mais un titre de trois
   lignes remonte jusqu'au bord : sur Formules & tarifs, « FORMULES & TARIFS »
   arrivait au ras du haut du cadre. La garde l'en empêche.

   La règle porte sur le contenu, pas sur `.hero-immersif` : celui-ci a une
   hauteur imposée et son enfant fait `height: 100%`, donc un padding posé sur
   le parent pousserait l'enfant hors du cadre au lieu de l'espacer. Avec
   `box-sizing: border-box`, le padding se prend à l'intérieur des 100 %, ce
   qui est exactement ce qu'on veut.

   Au-dessus de 1024 px le bas garde ses 64 px : le hero y fait 560 à 720 px
   de haut, la respiration est proportionnée, et 40 px serait un
   rétrécissement — la butée du haut, elle, s'applique à toutes les tailles. */
.hero-immersif-contenu {
  position: relative;
  z-index: 2;
  width: 100%;
  padding-top: 40px;
  padding-bottom: 40px;
}

@media (min-width: 1024px) {
  .hero-immersif-contenu { padding-bottom: 64px; }
}

.hero-immersif .breadcrumb {
  color: rgba(251, 250, 248, 0.76);
  margin-bottom: 16px;
}

.hero-immersif .breadcrumb-active { color: var(--sale); }

.hero-immersif .eyebrow { color: var(--brun-clair); margin-bottom: 12px; }

.hero-immersif h1 {
  color: var(--sale);
  max-width: 16ch;
  margin-bottom: 12px;
}

@media (min-width: 1024px) {
  .hero-immersif .breadcrumb { margin-bottom: 28px; }
  .hero-immersif .eyebrow { margin-bottom: 16px; }
  .hero-immersif h1 { margin-bottom: 20px; }
}

.hero-immersif .lede {
  color: rgba(251, 250, 248, 0.86);
  max-width: 56ch;
  margin-bottom: 20px;
}

.hero-immersif-actions {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

@media (min-width: 640px) {
  .hero-immersif-actions { flex-direction: row; gap: 16px; }
}

/* Ancre de défilement */
.hero-ancre {
  position: absolute;
  left: 50%;
  bottom: 20px;
  z-index: 3;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  color: rgba(251, 250, 248, 0.7);
}

.hero-ancre::before {
  content: '';
  width: 1px;
  height: 26px;
  background: linear-gradient(180deg, rgba(251, 250, 248, 0), rgba(251, 250, 248, 0.6));
}

.hero-ancre svg { width: 16px; height: 10px; }

@media (max-width: 767px) { .hero-ancre { display: none; } }

/* En-tête compact — /contact/ uniquement. Cette page sert, elle ne séduit pas. */
.hero-compact {
  background-color: var(--calce);
  color: var(--inchiostro);
  padding: var(--sp-hero) 0;
  min-height: 0;
  max-height: 30vh;
}


/* --------------------------------------------------------------------------
   2. BULLE DE SERVICE — remplace .equipement-grid et les listes à puces
   -------------------------------------------------------------------------- */

.services-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 20px;
}

@media (min-width: 640px)  { .services-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .services-grid { grid-template-columns: repeat(3, 1fr); } }

/* Le rayon de 10 px des boutons est levé ici, et ici seulement, pour les
   cartes de service. La levée est systématique : toutes les cartes de service
   du site, sur toutes les pages, ou aucune. */
.service-card {
  background-color: var(--sale);
  border: 1px solid var(--border-light);
  border-radius: var(--radius-btn);
  padding: 26px 22px;
  transition: border-color var(--dur-medium) ease;
  /* Pas d'ombre. */
}

@media (min-width: 1024px) { .service-card { padding: 32px 28px; } }

.service-card:hover,
.service-card:focus-within { border-color: var(--theme-accent); }

.service-bulle {
  width: 88px;
  height: 88px;
  border-radius: 50%;
  border: 1px solid var(--border-light);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--theme-accent);
  margin-bottom: 18px;
}

.service-bulle svg { width: 36px; height: 36px; }

@media (min-width: 1024px) {
  .service-bulle { width: 96px; height: 96px; margin-bottom: 22px; }
  .service-bulle svg { width: 40px; height: 40px; }
}

.service-card h3,
.service-card h4 {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--text-xl);
  line-height: 1.25;
  margin-bottom: 8px;
}

.service-card p {
  font-size: var(--text-md);
  color: var(--text-muted);
  margin-bottom: 16px;
}

.service-pied {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  border-top: 1px solid var(--border-light);
  padding-top: 14px;
}

.service-statut {
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--oliva);
}

.service-prix {
  font-family: var(--font-display);
  font-size: var(--text-lg);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* Variante fond sombre — utilisée pour le groupe « Suite Riposo » sur
   /le-lieu/. L'accent bascule sur le brun clair : même teinte, seule valeur
   qui tienne le contraste sur l'encre. Pas de seconde couleur. */
.bg-inchiostro .service-card,
.services-sombre .service-card {
  background-color: rgba(251, 250, 248, 0.04);
  border-color: var(--border-dark);
}

.bg-inchiostro .service-card:hover,
.services-sombre .service-card:hover { border-color: var(--brun-clair); }

.bg-inchiostro .service-bulle,
.services-sombre .service-bulle {
  border-color: var(--border-dark);
  color: var(--brun-clair);
}

.bg-inchiostro .service-card h3,
.bg-inchiostro .service-card h4,
.services-sombre .service-card h3,
.services-sombre .service-card h4 { color: var(--sale); }

.bg-inchiostro .service-card p,
.services-sombre .service-card p { color: var(--text-muted-dark); }

.bg-inchiostro .service-pied,
.services-sombre .service-pied { border-top-color: var(--border-dark); }

.bg-inchiostro .service-statut,
.services-sombre .service-statut { color: var(--brun-clair); }

.bg-inchiostro .service-prix,
.services-sombre .service-prix { color: var(--sale); }


/* --------------------------------------------------------------------------
   3. CARTE D'OCCASION — déclinaison compacte du sélecteur d'intention.
      Le sélecteur d'accueil n'est pas touché.
   -------------------------------------------------------------------------- */

.occasions-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 20px;
}

@media (max-width: 1023px) {
  .occasions-grid {
    display: flex;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    gap: 14px;
    padding-bottom: 12px;
    -webkit-overflow-scrolling: touch;
  }
  .occasions-grid > .occasion-card { flex: 0 0 68%; scroll-snap-align: start; }
}

.occasion-card {
  position: relative;
  display: block;
  aspect-ratio: 4 / 5;
  border-radius: var(--radius-btn);
  overflow: hidden;
  background-color: var(--inchiostro);
  text-decoration: none;
}

.occasion-card img,
.occasion-card video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: saturate(0.75) brightness(0.9);
  transition: transform var(--dur-signature) var(--ease-standard);
}

/* Au survol : le fond se rapproche de 3 %. Rien d'autre ne bouge. */
@media (min-width: 1024px) {
  .occasion-card:hover img,
  .occasion-card:hover video { transform: scale(1.03); }
}

.occasion-card::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(23, 28, 25, 0.08) 0%, rgba(23, 28, 25, 0.82) 100%);
}

.occasion-contenu {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 2;
  padding: 22px 20px;
}

@media (min-width: 1024px) { .occasion-contenu { padding: 28px 24px; } }

.occasion-titre {
  display: block;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(28px, 2.2vw, var(--text-2xl));
  line-height: 1.1;
  color: var(--sale);
  margin-bottom: 10px;
}

.occasion-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--brun-clair);
}


/* --------------------------------------------------------------------------
   4. GALERIE SANS LÉGENDE — mosaïque de projection
      Utilisée sur /le-lieu/, les pages d'occasion et la nuitée.
   -------------------------------------------------------------------------- */

.galerie-mosaique {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
}

@media (min-width: 1024px) {
  .galerie-mosaique { grid-template-columns: repeat(3, 1fr); gap: var(--gutter); }
}

.galerie-mosaique img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: var(--radius);
}

.galerie-mosaique .large { grid-column: span 2; }
.galerie-mosaique .large img { aspect-ratio: 16 / 9; }

/* Les légendes sautent : on regarde, on ne lit pas encore. Le lieu n'est
   nommé qu'une fois, dans la section équipements. */
.galerie-mosaique figcaption { display: none; }


/* --------------------------------------------------------------------------
   5. LIGNE D'EXTRA — levier de panier sur les pages d'occasion
   -------------------------------------------------------------------------- */

.extras-liste {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.extra-ligne {
  display: flex;
  align-items: center;
  gap: 16px;
  border: 1px solid var(--border-light);
  border-radius: var(--radius-btn);
  padding: 16px 18px;
}

@media (min-width: 1024px) { .extra-ligne { padding: 18px 20px; } }

.extra-ligne > span:first-child { flex: 1; min-width: 0; }

.extra-nom {
  display: block;
  font-size: var(--text-md);
  font-weight: 500;
  line-height: 1.4;
}

.extra-detail {
  display: block;
  font-size: var(--text-base);
  color: var(--text-muted);
  line-height: 1.4;
}

.extra-prix {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}


/* --------------------------------------------------------------------------
   6. CARTE DE FORMULE RECOMMANDÉE
   -------------------------------------------------------------------------- */

.formule-reco {
  border: 1px solid var(--theme-accent);
  border-radius: var(--radius-btn);
  background-color: var(--sale);
  padding: 28px 24px;
}

@media (min-width: 1024px) { .formule-reco { padding: 40px 36px; } }

.formule-reco-nom {
  display: block;
  font-family: var(--font-display);
  font-size: var(--text-2xl);
  line-height: 1.1;
  margin-bottom: 4px;
}

.formule-reco-duree {
  display: block;
  font-size: var(--text-md);
  color: var(--text-muted);
}

.formule-reco-prix {
  font-family: var(--font-display);
  font-size: var(--text-2xl);
  font-variant-numeric: tabular-nums;
}

.formule-reco-inclus {
  list-style: none;
  margin: 20px 0 28px;
  padding: 20px 0 0;
  border-top: 1px solid var(--border-light);
  display: flex;
  flex-direction: column;
  gap: 10px;
  font-size: var(--text-md);
}


/* --------------------------------------------------------------------------
   7. BLOC DE CONTACT EN TROIS COLONNES — /contact/, sous l'en-tête compact
   -------------------------------------------------------------------------- */

.contact-triptyque {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1px;
  background-color: var(--border-light);
  border: 1px solid var(--border-light);
  border-radius: var(--radius);
}

@media (min-width: 768px) {
  .contact-triptyque { grid-template-columns: repeat(3, 1fr); }
}

.contact-colonne {
  background-color: var(--sale);
  padding: 28px 24px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

@media (min-width: 1024px) { .contact-colonne { padding: 36px 32px; } }

.contact-label {
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--oliva);
}

/* Le téléphone en gros : c'est la première action de la page. */
.contact-tel {
  font-family: var(--font-display);
  font-size: clamp(26px, 2.4vw, 34px);
  line-height: 1.15;
  color: var(--theme-accent);
  font-variant-numeric: tabular-nums;
  text-decoration: none;
}

.contact-tel:hover { color: var(--theme-accent-hover); }

/* Formulaire et carte à parts égales : la carte cesse d'occuper la pleine
   largeur, et le formulaire remonte d'un écran. */
.contact-duo {
  display: grid;
  grid-template-columns: 1fr;
  gap: 32px;
  align-items: start;
}

@media (min-width: 1024px) {
  .contact-duo { grid-template-columns: 1fr 1fr; gap: 40px; }
}

/* Bandeau de repère d'arrivée, en bas de page */
.contact-bandeau img {
  width: 100%;
  height: 220px;
  object-fit: cover;
  border-radius: var(--radius);
}

@media (min-width: 1024px) { .contact-bandeau img { height: 300px; } }


/* --------------------------------------------------------------------------
   8. CADRE DE REPÉRAGE — média à commander, jamais une image d'ambiance
      générique. Reprend .media-placeholder existant, en 16:9 par défaut.
   -------------------------------------------------------------------------- */

.repere { aspect-ratio: 16 / 9; }


/* --------------------------------------------------------------------------
   9. MOUVEMENT
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .occasion-card img,
  .occasion-card video { transition: none; }
  .occasion-card:hover img,
  .occasion-card:hover video { transform: none; }
}

/* Icônes de service — sprite SVG collé après <body>, cf. livraison/icones/. */
.service-icone {
  width: 36px;
  height: 36px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.25;
  stroke-linecap: round;
  stroke-linejoin: round;
}

@media (min-width: 1024px) {
  .service-icone { width: 40px; height: 40px; }
}

/* Correction mesurée sur /spa-privatif/le-lieu/ : le surtitre en brun clair
   tient 4,9:1 sur l'encre pleine, mais retombe à 1,89:1 sur le voile d'une
   affiche claire — le titre, lui, tient 6,4:1. Dans un en-tête immersif, le
   surtitre et le fil d'Ariane passent donc au blanc de sel. L'accent reste
   porté par les boutons, qui ont leur propre fond. */
.hero-immersif .eyebrow,
.hero-immersif .eyebrow-light {
  color: var(--sale);
  opacity: 0.92;
}

/* Sur fond clair, le statut est en olive : un label discret, jamais l'accent.
   La variante sombre le passait au brun clair, à 4,38:1 sur la carte — sous
   les 4,5:1 exigés pour un texte de 12 px. Il reprend ici son rôle neutre,
   avec le jeton prévu pour le texte secondaire sur fond sombre. */
.bg-inchiostro .service-statut,
.services-sombre .service-statut {
  color: var(--text-muted-dark);
}

/* --------------------------------------------------------------------------
   MÉDIA CLIENT — séquences tournées au téléphone, 640 px de large au plus.
   Elles ne peuvent pas tenir un bandeau : cadrées en portrait et plafonnées,
   elles restent nettes et gardent leur registre — quelqu'un, pas un décor.
   -------------------------------------------------------------------------- */

.media-client {
  position: relative;
  border-radius: var(--radius-btn);
  overflow: hidden;
  background-color: var(--calce);
  max-width: 360px;
}

.media-client video,
.media-client img {
  display: block;
  width: 100%;
  aspect-ratio: 9 / 16;
  object-fit: cover;
  filter: saturate(0.85);
}

.media-client figcaption {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 32px 18px 14px;
  font-size: var(--text-xs);
  letter-spacing: 0.06em;
  color: var(--sale);
  background: linear-gradient(180deg, rgba(23, 28, 25, 0), rgba(23, 28, 25, 0.78));
}

@media (min-width: 1024px) {
  .media-client { max-width: 340px; margin-left: auto; }
  .split-layout > .media-client { align-self: center; }
}

/* Cartes des deux formules de nuitée : contenus inégaux, boutons alignés.
   La carte s'étire en colonne et pousse son bouton en pied — les deux
   « Réserver » tombent sur la même ligne quelle que soit la longueur des
   listes au-dessus. */
.carte-nuitee {
  display: flex;
  flex-direction: column;
  padding: 32px;
  border-radius: var(--radius);
}

.carte-nuitee > a.btn {
  margin-top: auto;
  align-self: stretch;
}

/* --------------------------------------------------------------------------
   LISTE D'INCLUS — les « features » d'une formule.
   Remplace les ✓ tapés en texte : une pastille au trait porte la coche, le
   libellé respire, et le tout tient l'alignement sur deux lignes.
   -------------------------------------------------------------------------- */

.liste-inclus {
  list-style: none;
  margin: 24px 0 28px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.liste-inclus li {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  font-size: var(--text-md);
  line-height: 1.55;
  color: var(--inchiostro);
}

.liste-inclus li::before {
  content: '';
  flex: 0 0 26px;
  width: 26px;
  height: 26px;
  margin-top: 1px;
  border: 1px solid var(--border-medium);
  border-radius: 50%;
  background-color: var(--sale);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3.5 8.5l3 3 6-6' fill='none' stroke='%23694117' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-size: 14px;
  background-position: center;
  background-repeat: no-repeat;
}

/* Sur fond sombre, la coche passe au brun clair et la pastille s'éteint. */
.section-sombre .liste-inclus li,
.bg-inchiostro .liste-inclus li { color: var(--sale); }

.section-sombre .liste-inclus li::before,
.bg-inchiostro .liste-inclus li::before {
  border-color: var(--border-dark);
  background-color: transparent;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3.5 8.5l3 3 6-6' fill='none' stroke='%23C0772A' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

/* Le montant « inline » est blanc parce qu'il est né dans la section sombre
   de l'accueil. Posé dans un encadré tarifaire — fond chaux — il devenait
   invisible : dans ce contexte, il reprend l'encre. */
.encadre-tarifs .prix-inline-montant,
.bg-calce .encadre-tarifs .prix-inline-montant,
.bg-sale .prix-inline-montant {
  color: var(--inchiostro);
}

/* Variante courte de l'en-tête immersif — la page contact sert avant de
   séduire : 40vh suffisent à poser le lieu sans repousser le téléphone. */
/* Variante courte — page Contact. Même correction que le hero plein : une
   hauteur plancher, pas une hauteur imposée, sinon elle réimpose la boîte
   fermée que la règle de base vient d'ouvrir. Elle coupait le fil d'Ariane
   au-dessus de 1024 px. */
.hero-immersif--court { min-height: max(40vh, 340px); }
@media (min-width: 1024px) { .hero-immersif--court { min-height: clamp(380px, 42vh, 480px); } }

/* --------------------------------------------------------------------------
   DEMANDE DE RÉSERVATION — le bloc #reservation, en pied de page SPA
   --------------------------------------------------------------------------
   Un seul dessin pour les huit pages. Ce qui change d'une page à l'autre,
   c'est le contenu du menu des formules et de la liste d'options — jamais la
   structure, jamais les classes, jamais le script. Tout est bâti sur les
   composants de formulaire existants (.form-container, .form-group,
   .form-label, .form-input…) : rien n'est réinventé ici, on ne fait qu'ajouter
   les deux dispositions dont le formulaire de contact n'avait pas besoin —
   une rangée de trois champs et une grille de cases à cocher.
   -------------------------------------------------------------------------- */

/* Le formulaire est le bout du parcours : il tient une colonne de lecture,
   centrée, plutôt que toute la largeur du bandeau. */
.reservation-carte {
  max-width: 860px;
  margin-left: auto;
  margin-right: auto;
}

/* Date, heure et nombre de personnes vont ensemble : trois champs courts sur
   une ligne au-dessus de 640 px, empilés en dessous. */
.form-grid-3 {
  display: grid;
  grid-template-columns: 1fr;
  gap: 20px;
}

@media (min-width: 640px) {
  .form-grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* Un groupe de cases à cocher est un vrai <fieldset> : le lecteur d'écran
   annonce l'intitulé du groupe avant chaque option. Il ne doit pas pour autant
   ramener la bordure et les marges par défaut du navigateur. */
.form-fieldset {
  border: none;
  padding: 0;
  margin: 0 0 24px;
  min-width: 0; /* sans quoi un <fieldset> refuse de rétrécir dans une grille */
}

.form-fieldset .form-label { margin-bottom: 4px; }

.form-legende {
  display: block;
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--oliva);
  margin-bottom: 12px;
  padding: 0;
}

.form-options {
  display: grid;
  grid-template-columns: 1fr;
  gap: 10px;
}

@media (min-width: 640px) {
  .form-options--deux { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* Une option cochable est une cible de clic à part entière, pas une ligne de
   texte avec une case devant : le cadre lui donne sa surface, et l'accent
   marque le choix sans recourir à la couleur seule — la case reste cochée. */
.form-options .form-checkbox-label {
  align-items: flex-start;
  padding: 12px 14px;
  border: 1px solid var(--border-light);
  border-radius: var(--radius);
  background-color: #ffffff;
  color: var(--inchiostro);
  transition: border-color var(--dur-fast) ease, background-color var(--dur-fast) ease;
}

.form-options .form-checkbox-label:hover { border-color: var(--border-medium); }

.form-options .form-checkbox-label:has(input:checked) {
  border-color: var(--theme-accent);
  background-color: var(--calce);
}

.form-options .form-checkbox-label:has(input:focus-visible) {
  outline: 2px solid var(--theme-accent);
  outline-offset: 2px;
}

/* Le prix d'une option, à droite du libellé : la même hiérarchie que dans les
   tableaux de tarifs — le nom porte l'information, le montant l'accompagne. */
.option-prix {
  color: var(--text-muted);
  white-space: nowrap;
}

/* Mention des champs obligatoires, et petite ligne d'engagement sous le
   bouton d'envoi. */
.form-note {
  font-size: var(--text-sm);
  color: var(--text-muted);
  margin-top: 12px;
  max-width: none;
}

.form-note--haut { margin: 0 0 24px; }

.form-submit { width: 100%; }

/* Un champ en erreur se signale par autre chose que la couleur : le filet
   s'épaissit et le message, lui, est écrit en toutes lettres au-dessus. */
.form-input.is-invalid,
.form-select.is-invalid,
.form-textarea.is-invalid {
  border-color: #9b1c1c;
  border-width: 2px;
}

.form-status.status-ok {
  display: block;
  background-color: var(--calce);
  color: var(--inchiostro);
  border-left: 3px solid var(--oliva);
}

/* Le titre du bloc reçoit le focus quand un bouton « Réserver » y amène : il
   ne doit pas pour autant afficher un cadre de focus au clic à la souris —
   :focus-visible s'en charge, et le contour reste pour le clavier. */
.section-reservation h2:focus { outline: none; }

/* --------------------------------------------------------------------------
   PREMIER FEATURE DE PAGE
   --------------------------------------------------------------------------
   Le bloc qui suit le hero, sur les onze pages où la direction l'a demandé.
   Il ne suit pas le rythme vertical du reste du site : exactement 40 px en
   haut, 40 px en bas, et son texte d'introduction centré.

   40 px est un nombre fixe, et voulu comme tel — ni --section-gap, ni un
   calc(). C'est la demande, mesurée au pixel sur les quatre largeurs de
   référence, et c'est pourquoi il ne bouge dans aucune media query : le
   contrôle porte sur 390 px comme sur 1440 px.

   La liste de sélecteurs est longue parce que les règles de rythme de la §14
   combinent jusqu'à trois classes (`.page-hero + .section.bg-calce`, à 0-3-0).
   Un simple `.premier-feature` perdrait contre elles et les bandeaux colorés
   reprendraient leur pas large. Les listes explicites montent à 0-4-0 et
   règlent la question sans !important.
   -------------------------------------------------------------------------- */

.section.premier-feature,
.page-hero + .section.premier-feature,
.section.premier-feature.bg-sale,
.section.premier-feature.bg-calce,
.section.premier-feature.bg-inchiostro,
.page-hero + .section.premier-feature.bg-sale,
.page-hero + .section.premier-feature.bg-calce,
.page-hero + .section.premier-feature.bg-inchiostro {
  padding-top: 40px;
  padding-bottom: 40px;
}

/* Le conteneur textuel, et lui seul.
   Les grilles de cartes qui suivent l'introduction gardent leur alignement à
   gauche : une carte centrée devient pénible à lire dès la deuxième ligne.
   C'est pourquoi le centrage passe par une classe posée dans le markup plutôt
   que par un sélecteur qui ratisserait toute la section. */
.premier-feature-texte {
  text-align: center;
  margin-inline: auto;
}

/* Les paragraphes portent un max-width de confort de lecture. Sans marge
   automatique, le texte serait centré à l'intérieur d'un bloc qui, lui,
   resterait calé à gauche — le défaut est invisible sur une ligne courte et
   saute aux yeux sur trois. */
.premier-feature-texte p { margin-inline: auto; }

/* --------------------------------------------------------------------------
   BANDEAU DE CONVERSION, VARIANTE PHOTOGRAPHIQUE
   --------------------------------------------------------------------------
   Le même composant .section-cta, avec la façade d'Apulia derrière le texte.
   Réservée aux bandeaux qui invitent à venir et à réserver : là, montrer le
   lieu ajoute quelque chose. Les bandeaux qui aiguillent vers une demande
   particulière — sur mesure, question sans réponse — gardent l'aplat, et la
   variante claire d'À propos n'est pas concernée.

   L'architecture reprend celle de .hero-immersif, déjà en place plus haut :
   média en absolu, object-fit cover, voile en ::after, contenu au-dessus.
   C'est volontairement le même motif — deux façons de poser une image de fond
   dans le même site seraient une de trop.

   AUCUN DÉCALAGE DE MISE EN PAGE
   La hauteur du bandeau vient de son contenu et de son padding, jamais de
   l'image : celle-ci est en position absolue et ne participe pas au flux. La
   section occupe donc sa hauteur définitive avant que la photo n'arrive, et
   son fond reste --inchiostro entre-temps. Si l'image ne charge jamais, le
   bandeau est exactement celui d'avant.
   -------------------------------------------------------------------------- */

.section-cta--photo {
  position: relative;
  overflow: hidden;
  /* Le voile et le contenu s'empilent dans ce seul bandeau, sans que son
     z-index n'aille concurrencer la barre collante ou le socle d'actions. */
  isolation: isolate;
}

.section-cta-media,
.section-cta-media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Point focal.
   La photographie est une contre-plongée : l'olivier occupe le centre et
   monte jusqu'en haut du cadre, la porte au logo tient le bas à gauche, et
   le quart supérieur n'est que du ciel. Les deux valeurs ne jouent jamais
   en même temps, et c'est ce qui permet de n'en poser qu'une seule paire.

   `cover` ne rogne que sur l'axe où l'image déborde. Le bandeau est plus
   large que 16/9 dès 768 px — il l'est jusqu'à 4,1/1 sur « Le lieu » en
   1920 — donc au-delà de cette largeur la photo est montrée sur toute sa
   largeur et c'est seulement la verticale qui se joue : le pourcentage
   horizontal n'a alors rien à faire glisser. En dessous, le bandeau devient
   plus haut que large (0,70/1 sur l'accueil en 390 px) et la situation
   s'inverse exactement. Une règle unique suffit donc aux deux régimes, là où
   la version précédente demandait une media query.

   92 % en vertical : il faut descendre pour que « APULIA SPA & WELLNESS »,
   qui occupe la bande 85,6 %–94,2 % de la hauteur d'origine, reste dans le
   champ même sur le bandeau le plus écrasé. En 1920 px sur « Le lieu », la
   fenêtre visible ne fait plus que 43 % de la hauteur : sous 90 % le logo
   passe sous le bord. Descendre évacue en prime le ciel vide, qui ne dit
   rien du lieu et coûte cher en contraste.

   16 % en horizontal : sur un téléphone la fenêtre ne montre plus que 39 %
   de la largeur. 16 % la cale sur 9,7 %–49,1 %, ce qui tient ensemble le
   logo (10,4 %–24,5 %) et le tronc de l'olivier (47,5 %). Plus à gauche on
   perd l'arbre, plus à droite on perd la porte. */
.section-cta-media img {
  object-position: 16% 92%;
  /* La photo est prise en plein soleil ; une pointe de désaturation la
     rapproche des autres visuels du site et évite que le bleu du ciel ne
     tire l'œil à travers le voile. */
  filter: saturate(0.82);
}

/* Le voile.
   Un dégradé vertical, plus dense en haut et en bas qu'au centre. En haut
   parce que le ciel reste dans le champ tant que le bandeau n'est pas trop
   écrasé — jusque vers 1024 px la photo est montrée presque entière — et
   qu'un ciel presque blanc ruinerait le contraste du surtitre. Au centre, là
   où le texte se pose, le voile s'ouvre juste assez pour qu'on lise le
   bardage, l'olivier et la porte.

   Les valeurs ne sont pas choisies à l'œil : elles sont celles qui font tenir
   le pire pixel derrière chaque texte au-dessus de son seuil, mesuré sur le
   rendu composité — onze largeurs de 360 à 1920 px, les onze pages, et
   chacun des huit fichiers réellement servis, pas seulement l'original.

   Elles ont été refaites pour la photographie à l'olivier, qui est plus
   claire que la précédente : le bardage blanc occupe désormais le milieu du
   cadre là où l'ancienne vue donnait du pavé gris. À voile égal, la marge
   la plus mince tombait de ×1,049 à ×1,014 au-dessus du seuil — conforme,
   mais d'un cheveu, et d'un cheveu plus mince que l'incertitude de la
   mesure. Un point de plus en haut et deux au centre la ramènent à ×1,049,
   exactement ce que le bandeau tenait avant : c'est le prix mesuré du
   changement d'image, pas un assombrissement de confort. Plus léger, le
   voile ne tient plus le seuil ; plus lourd, il noircit sans rien gagner.

   Le texte le plus tendu n'est d'ailleurs pas un texte mais le filet du
   bouton en contour, un trait d'un pixel à 40 % d'opacité : composant
   d'interface, seuil 3:1, il tombe à 3,14:1 quand le titre tient 10,79:1 et
   le surtitre 5,08:1. C'est lui qui fixe le voile, et c'est lui qu'il faut
   remesurer au prochain changement de photographie. */
.section-cta--photo::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(
    180deg,
    rgba(23, 28, 25, 0.94) 0%,
    rgba(23, 28, 25, 0.86) 38%,
    rgba(23, 28, 25, 0.86) 62%,
    rgba(23, 28, 25, 0.94) 100%
  );
}

.section-cta--photo > .container {
  position: relative;
  z-index: 2;
}

/* Le surtitre est le seul texte du bandeau qui soit à la fois petit et
   coloré : c'est lui qui fixe la force du voile. Le brun clair tient 4,9:1
   sur l'aplat d'encre, mais perd la marge nécessaire dès qu'une photo passe
   dessous. Sur cette variante il reprend la même teinte, éclaircie d'un cran
   — le geste que --brun-clair fait déjà par rapport à --theme-accent. */
.section-cta--photo .eyebrow-light { color: var(--brun-photo); }

/* --------------------------------------------------------------------------
   BANDEAU DE CONVERSION, VARIANTE CLAIRE
   --------------------------------------------------------------------------
   Demandée pour la seule section « Venir voir le lieu » d'À propos, où elle
   suit un bandeau à l'encre : deux aplats sombres à la suite fermaient la
   page trop tôt. Le modificateur ne touche pas .section-cta ailleurs sur le
   site — c'est bien un cas particulier de page, et il reste réutilisable.

   Tout ce qui était calé pour un fond sombre repasse du côté clair : le
   --text-muted-dark tomberait à 1,4:1 sur le blanc de sel, et le surtitre en
   brun clair à 2,9:1. Ils reprennent leurs jetons de fond clair, qui tiennent
   respectivement 5,4:1 et 6,8:1.
   -------------------------------------------------------------------------- */

.section-cta--clair {
  background-color: var(--sale);
  color: var(--inchiostro);
}

.section-cta--clair h2 { color: var(--inchiostro); }
.section-cta--clair p { color: var(--text-muted); }

.section-cta--clair .eyebrow,
.section-cta--clair .eyebrow-light { color: var(--oliva); }

/* --------------------------------------------------------------------------
   WHATSAPP
   --------------------------------------------------------------------------
   Lien officiel « Click to Chat » (wa.me), pas de widget tiers : un <a>, une
   icône SVG posée dans le markup, zéro requête et zéro script en plus. Le
   bouton prend le dessin des boutons du site — même hauteur, même rayon,
   mêmes graisses — et c'est l'icône qui porte la reconnaissance, pas un vert
   étranger à la charte.

   Il s'insère dans les deux socles déjà en place : le dock flottant du
   desktop (Réserver — WhatsApp — Appeler — ↑) et la barre fixe basse du
   mobile (Réserver — WhatsApp — Appeler).
   -------------------------------------------------------------------------- */

.btn-whatsapp { gap: 10px; }

.icone-whatsapp {
  width: 18px;
  height: 18px;
  flex: 0 0 18px;
  fill: currentColor;
}

/* Trois boutons au lieu de deux dans la barre basse : la gouttière latérale
   se resserre pour que les trois libellés tiennent sans être coupés, jusqu'aux
   petits téléphones. La hauteur de frappe, elle, ne bouge pas. */
@media (max-width: 767px) {
  .mobile-sticky-bar .btn { padding: 16px 8px; letter-spacing: 0.06em; }
  .mobile-sticky-bar .btn-whatsapp { gap: 8px; }
  .mobile-sticky-bar .icone-whatsapp { width: 16px; height: 16px; flex-basis: 16px; }
}

/* Sous 360 px, le libellé cède la place à l'icône seule — le bouton garde son
   nom pour les lecteurs d'écran par son aria-label. */
@media (max-width: 359px) {
  .mobile-sticky-bar .btn-whatsapp span { display: none; }
  .mobile-sticky-bar .btn-whatsapp { gap: 0; }
}

/* La barre basse se pose au-dessus de l'indicateur d'accueil des iPhone :
   sans cette réserve, le tiers inférieur des boutons tombait dessous. */
.mobile-sticky-bar { padding-bottom: env(safe-area-inset-bottom); }

/* Le socle flottant s'efface devant un formulaire : ses trois actions n'ont
   plus rien à proposer à quelqu'un qui est en train de remplir la demande, et
   elles recouvraient des champs. Le retour en haut de page reste — cf.
   initFloatingActions() dans js/main.js. */
.floating-actions.sans-cta .floating-cta {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

/* --------------------------------------------------------------------------
   NOTE GOOGLE — contenu local, lisible sans consentement
   --------------------------------------------------------------------------
   Le bloc est écrit par js/main.js à partir de js/data/formules.js. Il ne
   dépend d'aucun script tiers, donc il s'affiche quel que soit le choix du
   visiteur sur les cookies. Le seul lien vers Google est sortant.
   -------------------------------------------------------------------------- */

.avis-google {
  margin-top: 24px;
  padding-top: 20px;
  border-top: 1px solid var(--border-light);
}

.avis-ligne {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 8px;
  max-width: none;
}

.avis-note {
  font-size: var(--text-xl);
  font-weight: 600;
  line-height: 1;
  color: var(--inchiostro);
}

.avis-etoiles {
  width: 110px;
  height: 22px;
  flex: 0 0 auto;
}

.avis-source,
.avis-releve,
.avis-vide {
  font-size: var(--text-sm);
  color: var(--text-muted);
}

.avis-lien { margin: 0; font-size: var(--text-base); }
.avis-releve { margin: 6px 0 0; }
.avis-vide { margin: 0; max-width: none; }

/* --------------------------------------------------------------------------
   PLAN D'ACCÈS STATIQUE — sous le cadre de la carte interactive
   --------------------------------------------------------------------------
   L'image est servie depuis nos propres fichiers : elle situe le lieu sans
   qu'aucune ressource tierce ne parte, donc sans rien demander au visiteur.
   La carte interactive de Google, elle, garde son bandeau de consentement —
   c'est elle qui dépose des cookies, pas ce plan.
   -------------------------------------------------------------------------- */

.carte-statique {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.carte-statique img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* appliquerPlans() masque le plan statique dès que le plan interactif est
   accepté. Le `display: block` que le reset pose sur toute image l'emporterait
   sur le display: none du navigateur pour [hidden] : cette règle le remet
   dans l'ordre, sans !important. */
.carte-statique[hidden] { display: none; }

/* Un bouton dont le libellé ne tient pas dans la largeur de l'écran ne doit
   pas pousser la page : « Voir les dates disponibles pour la nuitée » sortait
   de 12 px à 390 px, et c'est toute la page qui se mettait à défiler
   horizontalement. Sous 768 px, le texte des boutons revient donc à la ligne.

   Les deux socles gardent leur nowrap : leurs libellés sont courts, leur
   hauteur est comptée, et un retour à la ligne y ferait grandir une barre
   fixe posée sur le contenu. */
@media (max-width: 767px) {
  .btn { white-space: normal; }
  .mobile-sticky-bar .btn,
  .floating-actions .btn { white-space: nowrap; }
}

/* La case à cocher du navigateur fait 13 px de côté : la zone de frappe reste
   celle du libellé qui l'entoure — 384 × 47 px sur mobile, largement au-delà
   du minimum — mais la case elle-même méritait d'être visée sans hésiter, et
   de porter l'accent de la marque quand elle est cochée. */
.form-checkbox-label input[type="checkbox"] {
  width: 18px;
  height: 18px;
  flex: 0 0 18px;
  margin-top: 2px;
  accent-color: var(--theme-accent);
  cursor: pointer;
}

/* --------------------------------------------------------------------------
   SOINS ESTHÉTIQUES — /soins-esthetiques/
   --------------------------------------------------------------------------
   Une offre distincte du spa privatif : quatorze prestations, quatre
   praticiens, quatre univers. Ce qui suit n'ajoute que ce qui n'existait pas.

   CE QUI EST REPRIS TEL QUEL, ET NE FIGURE DONC PAS ICI
   Les boutons (.btn, .btn-primary, .btn-outline, .btn-whatsapp et son icône),
   l'en-tête de page (.hero-immersif), le rythme des bandeaux (.section,
   .bg-calce, .bg-sale, .section-head), le pied de carte (.service-pied,
   .service-statut, .service-prix), les lignes de tarif (.carte-ligne,
   .carte-item, .carte-prix), la mise en avant d'une offre (.formule-reco),
   le badge (.badge-signature), la note de bas de bloc (.note-source) et tout
   le bloc #reservation. Un soin et un équipement partagent la même mécanique
   de pied de carte — un statut à gauche, un montant à droite : redessiner
   celle-ci aurait donné deux composants pour un seul rôle.

   CE QUI EST NOUVEAU
   La carte photographique d'une prestation, et la barre d'accès aux univers.
   Aucune couleur, aucune graisse et aucun rayon qui ne soit déjà un jeton.
   -------------------------------------------------------------------------- */

/* Accès rapide aux quatre univers, sous l'introduction. Des ancres, pas un
   menu : la page reste une page, et chaque lien descend à son bandeau.

   Le composant est .liens-services, déjà en place sur les pages de service —
   des pastilles, pas des cartes, c'est exactement le rôle. Ce modificateur ne
   change que deux choses : la rangée est centrée sous une introduction qui
   l'est aussi, et sous 640 px elle défile au lieu d'empiler quatre lignes —
   même geste que .occasions-grid. */
.liens-services--univers {
  justify-content: center;
  margin-top: 28px;
}

@media (max-width: 639px) {
  .liens-services--univers {
    flex-wrap: nowrap;
    overflow-x: auto;
    justify-content: flex-start;
    scroll-snap-type: x proximity;
    padding-bottom: 8px;
    -webkit-overflow-scrolling: touch;
    /* La rangée part du bord de l'écran plutôt que de la gouttière : une
       liste qui défile doit montrer qu'elle continue. */
    margin-inline: calc(var(--page-padding) * -1);
    padding-inline: var(--page-padding);
  }
  .liens-services--univers li { scroll-snap-align: start; }
  .liens-services--univers a { white-space: nowrap; }
}

/* --- La grille ----------------------------------------------------------- */
.soins-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 20px;
}

@media (min-width: 640px)  { .soins-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1024px) { .soins-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--gutter); } }

/* --- La carte ------------------------------------------------------------ */
.soin-card {
  display: flex;
  flex-direction: column;
  background-color: var(--sale);
  border: 1px solid var(--border-light);
  border-radius: var(--radius-btn);
  overflow: hidden;
  transition: border-color var(--dur-medium) ease;
  /* Pas d'ombre — charte §5, comme .service-card. */
}

.soin-card:hover,
.soin-card:focus-within { border-color: var(--theme-accent); }

/* Le média occupe une proportion fixe : la hauteur de la carte est donc
   connue avant que la photo n'arrive, et rien ne saute au chargement. */
.soin-media {
  position: relative;
  aspect-ratio: 4 / 3;
  background-color: var(--calce);
  overflow: hidden;
}

/* <picture> est un bloc sans hauteur propre : sans cette ligne, l'image se
   contente de son ratio naturel et laisse un fond nu sous elle dès que la
   boîte est plus haute qu'elle — ce qui arrive à la variante horizontale, dont
   la hauteur vient de la colonne de texte. */
.soin-media picture {
  display: block;
  width: 100%;
  height: 100%;
}

.soin-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Même désaturation légère que les autres photos du site, pour que les
     quatorze visuels tiennent ensemble malgré quatorze photographes. */
  filter: saturate(0.85);
  transition: transform var(--dur-signature) var(--ease-standard);
}

@media (min-width: 1024px) {
  .soin-card:hover .soin-media img { transform: scale(1.03); }
}

.soin-corps {
  display: flex;
  flex-direction: column;
  flex: 1;
  padding: 24px 22px;
}

@media (min-width: 1024px) { .soin-corps { padding: 28px 26px; } }

.soin-card h3 {
  font-size: var(--text-xl);
  line-height: 1.25;
  margin-bottom: 6px;
}

/* L'accroche du soin — « Nettoie · Hydrate · Illumine ». Elle porte l'accent
   de la maison : trois mots qui disent ce que le soin travaille, avant la
   description qui dit comment. */
.soin-accroche {
  display: block;
  font-size: var(--text-md);
  font-weight: 500;
  line-height: 1.35;
  color: var(--theme-accent);
  margin-bottom: 14px;
}

.soin-texte {
  font-size: var(--text-md);
  line-height: 1.55;
  color: var(--text-muted);
  margin-bottom: 18px;
  max-width: none;
}

/* Trois bénéfices, jamais plus : au-delà, on ne lit plus une carte, on lit
   un argumentaire. La puce est un filet, pas un pictogramme. */
.soin-benefices {
  list-style: none;
  margin: 0 0 20px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 7px;
}

.soin-benefice {
  position: relative;
  padding-left: 18px;
  font-size: var(--text-base);
  line-height: 1.4;
  color: var(--inchiostro);
}

.soin-benefice::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.62em;
  width: 10px;
  height: 1px;
  background-color: var(--oliva);
}

/* Grille de tarifs, quand la prestation en a plusieurs — les trois volumes
   d'extensions de cils, les trois étendues de la hijama. Les lignes reprennent
   .carte-ligne ; seul l'encadrement est posé ici. */
.soin-tarifs {
  list-style: none;
  margin: 0 0 18px;
  padding: 0;
  border-top: 1px solid var(--border-light);
}

.tarif-retouche {
  font-size: var(--text-sm);
  color: var(--text-muted);
}

/* Retouche, délai, précision de protocole : la petite ligne qui évite un
   appel téléphonique. */
.soin-note {
  font-size: var(--text-sm);
  line-height: 1.45;
  color: var(--text-muted);
  margin-bottom: 18px;
  max-width: none;
}

/* Le pied de carte est repris de .service-pied ; seul le montant monte d'un
   cran, parce qu'ici c'est lui qu'on vient chercher. Il reste en dessous du
   titre du soin : identifiable d'un coup d'œil, jamais dominant. */
.soin-card .service-pied,
.soin-reco-pied {
  margin-top: auto;
}

.soin-card .service-prix { font-size: var(--text-xl); }

/* Deux actions, l'une sous l'autre. Côte à côte, « Réserver via WhatsApp »
   et « Demander ce soin » ne tiennent pas dans une colonne de grille à
   1024 px sans que leurs libellés se coupent — et empilés, ils offrent deux
   cibles de 48 px de haut sur toute la largeur, ce qui est exactement ce
   qu'on veut au doigt. */
.soin-actions {
  display: grid;
  grid-template-columns: 1fr;
  gap: 10px;
  margin-top: 18px;
}

.soin-actions .btn { width: 100%; }

/* DEUX VARIANTES HORIZONTALES, ET ELLES NE RÉPONDENT PAS À LA MÊME QUESTION.

   `--seule` : l'univers ne compte qu'une prestation — la hijama. Une carte
   seule dans une grille de trois se lit comme un reliquat, à toutes les
   largeurs. Elle prend donc la ligne entière dès la première colonne.

   `--large` : la prestation ferme une ligne incomplète. À trois colonnes, un
   univers de quatre soins laisse un trou de deux colonnes, un univers de cinq
   en laisse un ; les dernières cartes passent en pleine largeur et la ligne se
   referme. En dessous de 1024 px la grille n'a que deux colonnes : le compte
   tombe autrement, et ces cartes redeviennent des cartes ordinaires. */
.soin-card--seule { grid-column: 1 / -1; }

@media (min-width: 1024px) {
  .soin-card--large { grid-column: 1 / -1; }
}

@media (min-width: 900px) {
  .soin-card--seule { flex-direction: row; }
  .soin-card--seule .soin-media { flex: 0 0 44%; aspect-ratio: auto; }
  .soin-card--seule .soin-corps { padding: 36px 34px; }
  .soin-card--seule .soin-actions { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 1024px) {
  .soin-card--large { flex-direction: row; }
  .soin-card--large .soin-media { flex: 0 0 44%; aspect-ratio: auto; }
  .soin-card--large .soin-corps { padding: 36px 34px; }
  .soin-card--large .soin-actions { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* La formule combinée PRP reprend .formule-reco — le composant de mise en
   avant déjà en place sur les pages d'occasion. Ce qui suit ne fait que le
   poser dans la grille et aligner ses actions sur celles des cartes. */
/* Elle est posée sous la grille, pas dedans : dans la grille, elle coupait la
   ligne des cartes PRP en deux et laissait la vitaminothérapie seule en
   dessous. Sous la grille, elle referme l'univers. */
.soin-reco {
  display: flex;
  flex-direction: column;
  margin-top: 20px;
}

@media (min-width: 1024px) { .soin-reco { margin-top: var(--gutter); } }

/* Le badge ouvre le bloc : la marge gauche qu'il porte ailleurs, où il suit un
   nom de formule, le décalerait du titre qu'il annonce. */
.soin-reco .badge-signature { margin: 0 0 10px; }

.soin-reco-tete {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}

@media (min-width: 900px) {
  .soin-reco .soin-actions {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    max-width: 560px;
  }
}

/* Un groupe de cases obligatoire qui n'a pas été rempli se signale comme les
   champs texte : autre chose que la couleur, et le message est écrit en
   toutes lettres en haut du formulaire. */
.form-options .form-checkbox-label:has(input.is-invalid) {
  border-color: #9b1c1c;
  border-width: 2px;
}
