/* ==================================================================
   Beauté Digitale — site public genere
   Direction artistique : epure chic. Blanc dominant, respiration
   genereuse, serif de titrage a fort contraste, details discrets.
   Le rendu reste pilote par les jetons de charte (variables CSS
   injectees par le layout) et par la classe de theme.
   ================================================================== */

*, *::before, *::after { box-sizing: border-box; }

/* --- Respiration ----------------------------------------------------------
   Echelle fluide plutot que des paliers. Le site passait de 6rem a 4rem de
   rythme vertical d'un coup a 900px, et la gouttiere de 1.75rem a 1.25rem a
   720px : entre les deux, un telephone large heritait d'espaces pensés pour
   un ecran d'ordinateur. Le clamp() interpole en continu, il n'y a plus de
   largeur « mal servie ».

   La borne basse vise 360px (le plus petit telephone encore courant), la
   borne haute 1180px (la largeur du contenu).
   -------------------------------------------------------------------------- */
:root {
    --gutter:         clamp(1.15rem, 0.75rem + 1.8vw, 1.75rem);
    --rythme-section: clamp(2.9rem,  1.8rem + 3.2vw, 5.5rem);
    --rythme-hero:    clamp(4.5rem,  2.2rem + 10vw,  8.5rem);
    --ecart-cartes:   clamp(1rem,    0.6rem + 1.8vw, 1.9rem);
    --ecart-bloc:     clamp(2.2rem,  1.4rem + 2.6vw, 3.5rem);
}

.site {
    margin: 0;
    font-family: var(--font-body, system-ui, sans-serif);
    color: var(--site-ink, #23211f);
    background: var(--site-bg, #ffffff);
    font-size: 1.0625rem;
    line-height: 1.7;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

/* --- Ambiance par defaut ----------------------------------------------
   Les ambiances vivent desormais dans les themes (public/themes/{slug}/
   theme.css), charges APRÈS ce fichier. Ces valeurs sont le socle : un
   theme absent, retire ou dont la feuille n'a pas ete envoyee en FTP
   laisse un site lisible plutot qu'un site sans couleurs.

   --site-veil : teinte des visuels generes quand aucune photo n'est
   fournie. --site-tint : aplat tres clair pour les respirations.
   -------------------------------------------------------------------- */
.site {
    --site-bg:#ffffff; --site-surface:#faf8f5; --site-tint:#f4f0ea;
    --site-ink:#23211f; --site-soft:#6f6961; --site-border:#ebe4da;
    --site-veil-a: 210,196,182; --site-veil-b: 176,186,172;
}

.site-wrap { max-width: 1180px; margin: 0 auto; padding: 0 var(--gutter); }

/* --- Titrage --------------------------------------------------------------
   `:where()` neutralise la specificite : sans lui, `.site p` (0,1,1) ecrase
   `.hero__lead` (0,1,0) et supprime ses marges `auto`, ce qui decentre le
   bloc. Les regles de base doivent toujours ceder devant un composant.
   -------------------------------------------------------------------------- */
:where(.site) :where(h1, h2, h3, h4) {
    font-family: var(--font-heading);
    color: var(--site-ink);
    margin: 0 0 0.5rem;
    font-weight: 500;
    line-height: 1.15;
    letter-spacing: -0.01em;
    text-wrap: balance;
}
:where(.site) :where(p) { margin: 0 0 1.1em; }
:where(.site) :where(p:last-child) { margin-bottom: 0; }
:where(.site) :where(a) { color: inherit; }

.site ::selection { background: var(--c-accent); color: #fff; }

.site :focus-visible {
    outline: 2px solid var(--c-accent);
    outline-offset: 3px;
    border-radius: 3px;
}

/* --- En-tete ------------------------------------------------------------- */
.site-header {
    position: sticky; top: 0; z-index: 20;
    background: color-mix(in srgb, var(--site-bg) 88%, transparent);
    backdrop-filter: saturate(140%) blur(10px);
    -webkit-backdrop-filter: saturate(140%) blur(10px);
    border-bottom: 1px solid var(--site-border);
}

/* Options de mise en page pilotées par le MODÈLE (classes posées sur .site par
   le gabarit selon les réglages de l'écran « Modèles »). */
.site--menu-static .site-header { position: static; }          /* menu non fixe : défile avec la page */
.site--menu-nosub .site-nav__sub { display: none !important; } /* sous-menus masqués : le survol n'ouvre plus le volet */
/* Menu non dynamique : le sous-menu ne s'ouvre plus → on masque aussi la petite
   flèche « ▾ » (desktop) et le chevron (mobile) qui annonçaient un sous-menu. */
.site--menu-nosub .site-nav__group > a > span[aria-hidden] { display: none !important; }
.site-header__inner {
    display: flex; align-items: center; justify-content: space-between;
    gap: 1.5rem; padding: 1.55rem var(--gutter);
}
/* L'en-tête « collé » (is-stuck) ne change NI sa hauteur NI la taille du logo :
   rétrécir la barre au défilement faisait « sauter » le logo et le burger (et,
   menu mobile ouvert, le bouton croix bougeait à la molette). Seul le décor
   (fond opaque sur les pages à hero) peut changer — géré dans le thème. */
.site-brand { text-decoration: none; flex: none; }
.site-title {
    font-family: var(--font-heading);
    font-size: 1.6rem; color: var(--site-ink);
    letter-spacing: -0.01em; display: inline-block;
}
.site-logo { max-height: 48px; display: block; width: auto; }
/* Accueil : échange du logo au défilement. Sur la bannière (en-tête transparent)
   on montre le logo par défaut (souvent blanc) ; une fois l'en-tête « collé »
   (opaque/crème), on bascule sur le logo intérieur (foncé) pour éviter le blanc
   sur blanc. Rendu seulement quand un logo intérieur distinct existe. */
.site-logo--stuck { display: none; }
.site-header.is-stuck .site-logo--hero { display: none; }
.site-header.is-stuck .site-logo--stuck { display: block; }

.site-nav { display: flex; align-items: center; gap: 1.6rem; }
/* `:where(a)` retire la specificite du selecteur de type : sans lui, cette
   regle (0,1,1) ecrase le rembourrage de `.site-btn` (0,1,0) et le libelle
   du bouton « Prendre rendez-vous » se retrouve colle a sa bordure. */
.site-nav :where(a) {
    text-decoration: none; color: var(--site-soft);
    font-weight: 500; font-size: 0.9375rem;
    position: relative; padding: 0.15rem 0;
    transition: color 0.2s ease;
}
.site-nav > a::after, .site-nav__group > a::after {
    content: ""; position: absolute; left: 0; right: 0; bottom: -2px;
    height: 1px; background: currentColor;
    transform: scaleX(0); transform-origin: left;
    transition: transform 0.25s ease;
}
.site-nav > a:hover::after, .site-nav > a.is-active::after,
.site-nav__group:hover > a::after,
.site-nav__group.is-active > a::after { transform: scaleX(1); }
.site-nav a:hover, .site-nav a.is-active,
.site-nav__group.is-active > a { color: var(--site-ink); }
.site-nav .site-btn::after { display: none; }

/* Sous-menu (2e niveau) */
/* `inline-flex` + `align-items:center` : le lien interne du groupe redevient un
   flex-item (comme les liens directs de la nav), donc son padding vertical
   compte dans sa hauteur — sinon, en `inline-block`, ce `<a>` inline était ~6px
   plus court et « Prestations » descendait de quelques pixels sous les autres. */
.site-nav__group { position: relative; display: inline-flex; align-items: center; }
.site-nav__group > a { cursor: pointer; }
.site-nav__sub {
    position: absolute; top: calc(100% + 0.6rem); left: 50%;
    transform: translateX(-50%);
    min-width: 210px; z-index: 30;
    background: var(--site-bg);
    border: 1px solid var(--site-border);
    border-radius: var(--radius-card, 10px); padding: 0.45rem;
    display: none; flex-direction: column;
    box-shadow: 0 2px 4px rgba(0,0,0,0.03), 0 18px 40px -12px rgba(0,0,0,0.16);
}
/* Pont invisible : comble l'écart entre le parent et le sous-menu pour que le
   survol ne se perde pas quand la souris descend (sinon le menu se referme
   avant qu'on l'atteigne). */
.site-nav__sub::before {
    content: ""; position: absolute; left: 0; right: 0;
    top: -0.8rem; height: 0.8rem;
}
.site-nav__group:hover .site-nav__sub,
.site-nav__group:focus-within .site-nav__sub { display: flex; }
.site-nav__sub a {
    padding: 0.5rem 0.75rem; border-radius: var(--radius-btn, 6px);
    white-space: nowrap; font-size: 0.9rem;
}
.site-nav__sub a:hover,
.site-nav__sub a.is-active { background: var(--site-tint); color: var(--site-ink); }
.site-nav__sub a.is-active { font-weight: 600; }
.site-nav__sub a::after { display: none; }

/* Option de modèle « Afficher les photos dans le sous-menu » : chaque catégorie
   montre sa vignette à gauche de son intitulé. */
.site-nav__sub a.has-thumb { display: flex; align-items: center; gap: 0.6rem; }
.site-nav__thumb {
    width: 34px; height: 34px; flex-shrink: 0;
    object-fit: cover; border-radius: var(--radius-btn, 6px); display: block;
    background: var(--site-tint);
}
.site--submenu-photos .site-nav__sub { min-width: 244px; }

/* En-tête de niveau 2 (Retour + titre), injecté par site.js dans CHAQUE
   sous-menu : masqué par défaut (ne doit pas apparaître dans le flyout desktop).
   La media query mobile plus bas le ré-affiche dans le panneau drillé. */
.site-nav__l2head { display: none; }

/* Sous-menu à RALLONGE : au-dela de 10 catégories, on l'affiche en 2 ou 3
   COLONNES (grille alignée) plutot qu'une liste verticale interminable.
   Desktop uniquement (sur mobile le sous-menu est déroulé en place, cf. media
   query plus bas). On passe le volet OUVERT en `display:grid` : une grille aligne
   proprement les colonnes (le flex-wrap donnait des colonnes en escalier avec les
   vignettes de largeurs inégales). Le sélecteur d'ouverture reprend la même
   spécificité (0,3,0) que la règle qui pose `display:flex`, en venant après, pour
   la battre — sans toucher au positionnement (absolu, `left`…), commun aux deux
   thèmes (barre haute ET colonne latérale). */
@media (min-width: 1025px) {
    /* Sous-menu plus large et plus aéré en desktop : le flyout respire, les
       intitulés ont de l'air, les vignettes sont plus lisibles. */
    .site-nav__sub {
        min-width: 340px;
        padding: 0.8rem;
        gap: 0.18rem;
    }
    .site-nav__sub a {
        padding: 0.72rem 1.2rem;
        font-size: 0.98rem;
        letter-spacing: 0.005em;
    }
    .site-nav__sub a.has-thumb { gap: 0.9rem; }
    .site-nav__thumb { width: 48px; height: 48px; }
    .site--submenu-photos .site-nav__sub { min-width: 400px; }

    .site-nav__group:hover .site-nav__sub--cols-2,
    .site-nav__group:focus-within .site-nav__sub--cols-2,
    .site-nav__group:hover .site-nav__sub--cols-3,
    .site-nav__group:focus-within .site-nav__sub--cols-3 {
        display: grid;
        align-content: start;
        gap: 0.1rem 0.7rem;
    }
    .site-nav__sub--cols-2 {
        width: min(94vw, 640px);
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
    .site-nav__sub--cols-3 {
        width: min(96vw, 920px);
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
    /* Les libellés peuvent s'enrouler dans leur colonne (le défaut est nowrap
       pour la liste simple ; en colonnes étroites il faut autoriser le retour). */
    .site-nav__sub--cols-2 a,
    .site-nav__sub--cols-3 a { white-space: normal; }
}

/* --- Boutons -------------------------------------------------------------- */
.site-btn {
    display: inline-block;
    background: var(--c-primary); color: #fff;
    text-decoration: none;
    padding: 0.8rem 1.6rem;
    border-radius: var(--radius-btn, 8px);
    font-weight: 500; font-size: 0.9375rem;
    letter-spacing: 0.01em;
    border: 1px solid var(--c-primary);
    transition: background 0.2s ease, border-color 0.2s ease, transform 0.1s ease, box-shadow 0.2s ease;
}
.site-btn:hover {
    box-shadow: 0 8px 22px -10px rgba(0,0,0,0.45);
    transform: translateY(-1px);
}
.site-btn:active { transform: translateY(0); }
.site-btn--ghost {
    background: transparent; color: var(--site-ink);
    border-color: var(--site-border);
}
/* Les boutons sont des <a> : `.site a { color: inherit }` (0,1,1) l'emporte
   sur `.site-btn` (0,1,0) et repeint le libelle avec l'encre du theme, d'ou
   un texte noir sur bouton noir. On remonte la specificite au-dessus de la
   regle de lien, pour TOUS les boutons et pas seulement ceux du menu. */
.site a.site-btn { color: #fff; }
.site a.site-btn--ghost { color: var(--site-ink); }
.site-btn--ghost:hover { border-color: var(--site-ink); box-shadow: none; }
.site-btn--nav { padding: 0.55rem 1.15rem; font-size: 0.9rem; }
.site-btn--block { display: block; text-align: center; width: 100%; }

/* --- Hero -----------------------------------------------------------------
   Sans photo, on ne laisse pas un aplat plat : un decor genere en degrades
   doux tient lieu de visuel et reste elegant. Il est remplace des qu'une
   image est renseignee.
   ------------------------------------------------------------------------- */
.hero {
    position: relative;
    overflow: hidden;
    border-bottom: 1px solid var(--site-border);
    background: var(--site-surface);
}
.hero::before {
    content: "";
    position: absolute; inset: 0;
    background:
        radial-gradient(900px 520px at 15% 0%,  rgba(var(--site-veil-a), 0.34), transparent 62%),
        radial-gradient(760px 480px at 88% 108%, rgba(var(--site-veil-b), 0.30), transparent 60%),
        radial-gradient(520px 320px at 60% 12%, rgba(var(--site-veil-a), 0.16), transparent 70%);
}
.hero::after {
    content: "";
    position: absolute; left: 50%; bottom: 0;
    width: 1px; height: 3.5rem;
    /* Repere de defilement : un segment d'accent descend le long du filet, en
       boucle douce. Sous reduced-motion, la regle globale gele l'animation. */
    background: linear-gradient(to bottom, transparent 10%, var(--c-accent) 50%, transparent 90%),
                linear-gradient(to bottom, transparent, var(--site-border));
    background-size: 100% 200%, 100% 100%;
    background-repeat: no-repeat;
    animation: hero-cue 2.6s cubic-bezier(0.6, 0, 0.4, 1) infinite;
}
@keyframes hero-cue {
    0%   { background-position: 0 -100%, 0 0; opacity: 0; }
    30%  { opacity: 1; }
    100% { background-position: 0 200%, 0 0; opacity: 0; }
}
.hero__inner {
    position: relative; z-index: 1;
    padding: var(--rythme-hero) var(--gutter) calc(var(--rythme-hero) + 0.5rem);
    text-align: center;
}
.hero__title {
    font-size: clamp(3rem, 1.7rem + 4.8vw, 5.6rem);
    line-height: 1.01; letter-spacing: -0.028em; font-weight: 600;
    margin-bottom: 0.5rem;
}
.hero__lead {
    max-width: 52ch; margin: 1.3rem auto 2.6rem;
    color: var(--site-soft);
    font-size: clamp(1.1rem, 1rem + 0.42vw, 1.32rem);
    line-height: 1.6;
}
.hero__actions { display: flex; gap: 0.8rem; justify-content: center; flex-wrap: wrap; }

/* Variante avec photo : le decor genere s'efface. */
.hero--image { background-size: cover; background-position: center; color: #fff; }
.hero--image::before { display: none; }

/* Calque image dédié : porte l'image (+ voile de lisibilité, en style inline).
   L'isoler dans un enfant permet un parallax propre — on translate CE calque,
   jamais le contenu. Surdimensionné (inset négatif) pour garder de la marge :
   pendant la translation, aucun bord n'apparaît. Statique sans JS. */
.hero__bg { position: absolute; inset: 0; z-index: 0; background-size: cover; background-position: center; }
.hero--image .hero__bg { inset: -15% 0; will-change: transform; }

/* --- Hero : diaporama multi-images ----------------------------------------
   Couches empilées ; la couche « is-active » est visible. La transition dépend
   de la classe du conteneur (fondu / masque / dissolve WebGL). Zoom Ken Burns
   optionnel sur la couche active. */
.hero__slides { position: absolute; inset: 0; z-index: 0; overflow: hidden; }
.hero__slide { position: absolute; inset: 0; opacity: 0; transition: opacity 1.2s ease; }
.hero__slide.is-active { opacity: 1; }
/* Calque image interne : porte le fond + le Ken Burns, séparé de l'opacité /
   masque / glissé de la couche (aucune interférence entre les deux). */
.hero__slide__img { position: absolute; inset: 0; background-size: cover; background-position: center; }

/* Ken Burns : zoom IN seulement (is-zoom, posé/retiré par le JS). La couche
   sortante garde son échelle pendant sa sortie ; la remise à l'échelle de base
   n'a lieu qu'une fois la couche invisible → AUCUN dézoom visible. */
.hero__slides--zoom .hero__slide__img { transform: scale(1.05); }
.hero__slides--zoom .hero__slide.is-zoom .hero__slide__img { transform: scale(1.16); transition: transform var(--hero-kb, 9s) ease-out; }

/* Fondu flou : la couche entrante se résout d'un léger flou (zoom Ken Burns géré
   à part sur le calque interne). */
.hero__slides--blur .hero__slide { filter: blur(16px); transition: opacity 1.4s ease, filter 1.4s ease; }
.hero__slides--blur .hero__slide.is-active { filter: blur(0); }

/* Masque balayé (2.2s, doux). */
.hero__slides--mask .hero__slide {
    opacity: 1;
    -webkit-mask-image: linear-gradient(62deg, #000 0 30%, transparent 66%);
    mask-image: linear-gradient(62deg, #000 0 30%, transparent 66%);
    -webkit-mask-size: 320% 100%; mask-size: 320% 100%;
    -webkit-mask-position: 100% 0; mask-position: 100% 0;
    transition: -webkit-mask-position 2.2s cubic-bezier(0.65, 0, 0.2, 1), mask-position 2.2s cubic-bezier(0.65, 0, 0.2, 1);
}
.hero__slides--mask .hero__slide.is-active { -webkit-mask-position: 0 0; mask-position: 0 0; }

/* Glissé : l'entrante arrive de la droite, la sortante part vers la gauche
   (is-prev). Les couches au repos sont INVISIBLES (opacity:0) — sinon un liseré
   de la suivante dépasse. Le JS repositionne hors-champ sans animer. */
.hero__slides--slide .hero__slide { opacity: 0; transform: translateX(100%); transition: transform 0.9s cubic-bezier(0.7, 0, 0.2, 1); }
.hero__slides--slide .hero__slide.is-active { opacity: 1; transform: translateX(0); }
.hero__slides--slide .hero__slide.is-prev { opacity: 1; transform: translateX(-100%); }

@media (prefers-reduced-motion: reduce) {
    .hero__slides--zoom .hero__slide.is-zoom .hero__slide__img { transition: none; transform: scale(1.05); }
    .hero__slides--mask .hero__slide { -webkit-mask-image: none; mask-image: none; opacity: 0; transition: opacity 0.6s ease; }
    .hero__slides--mask .hero__slide.is-active { opacity: 1; }
    .hero__slides--blur .hero__slide { filter: none; }
    .hero__slides--slide .hero__slide { transform: none; opacity: 0; transition: opacity 0.6s ease; }
    .hero__slides--slide .hero__slide.is-active { opacity: 1; }
    .hero__slides--slide .hero__slide.is-prev { opacity: 0; }
}
.hero--image::after { background: linear-gradient(to bottom, transparent, rgba(255,255,255,0.5)); }
.hero--image .hero__title, .hero--image .hero__lead { color: #fff; }
.hero--image .hero__lead { color: rgba(255,255,255,0.92); }
/* Meme specificite que `.site a.site-btn--ghost`, mais declaree plus bas :
   sur une photo, le contour fantome repasse en blanc. */
.hero--image a.site-btn--ghost { color: #fff; border-color: rgba(255,255,255,0.55); }
.hero--image a.site-btn--ghost:hover { border-color: #fff; background: rgba(255,255,255,0.1); }

/* --- Hero SPLIT : image plein-cadre d'un cote, texte de l'autre -------------
   L'ouverture editoriale des references (Beauty Pearl). Le texte repose sur le
   FOND du site (pas sur l'image) -> encre normale, jamais blanc. La demi-colonne
   image touche le bord de l'ecran ; sur mobile, tout s'empile (texte puis image). */
.hero--split {
    display: grid;
    grid-template-columns: 1.02fr 0.98fr;
    align-items: stretch;
    min-height: clamp(520px, 82vh, 880px);
    background: var(--site-surface);
    color: var(--site-ink);
    overflow: clip;
}
.hero--split::before, .hero--split::after { display: none; }   /* ni decor ni cue */
.hero--split .hero__media { position: relative; overflow: hidden; order: 2; }
.hero--split .hero__inner {
    order: 1; position: relative; z-index: 1;
    display: flex; flex-direction: column; justify-content: center; align-items: flex-start;
    text-align: left; max-width: none;
    padding: clamp(3rem, 5vw, 6.5rem) clamp(1.8rem, 5vw, 5.5rem);
}
.hero--split .hero__title { color: var(--site-ink); font-size: clamp(2.6rem, 1.8rem + 3vw, 4.4rem); }
.hero--split .hero__lead { color: var(--site-soft); margin: 1.3rem 0 2.4rem; max-width: 44ch; }
.hero--split .hero__actions { justify-content: flex-start; }
@media (max-width: 820px) {
    .hero--split { grid-template-columns: 1fr; min-height: 0; }
    .hero--split .hero__media { min-height: clamp(240px, 62vw, 400px); }
    .hero--split .hero__inner { padding: clamp(2.5rem, 8vw, 3.75rem) var(--gutter); }
}

/* --- Sections --------------------------------------------------------------- */
.section { padding: var(--rythme-section) var(--gutter); }
.section__title {
    font-size: clamp(2.1rem, 1.5rem + 2vw, 3.3rem);
    line-height: 1.06; letter-spacing: -0.02em; font-weight: 600;
    margin-bottom: 0.4rem;
}
/* Filet discret sous les titres de section : un marqueur editorial sobre. */
.section > .section__title::after {
    content: ""; display: block;
    width: 3rem; height: 2px;
    background: var(--c-accent);
    margin: 1.4rem 0 2.7rem;
}
.page-title { font-size: clamp(2.35rem, 1.6rem + 2.8vw, 3.8rem); line-height: 1.03; letter-spacing: -0.025em; font-weight: 600; margin-bottom: 0.85rem; }

/* --- Bandeau intérieur commun (pages secondaires) ------------------------
   Ergonomie unique pour catégorie / prestation / besoin / blog / contact… :
   un bandeau RÉDUIT (vs le hero d'accueil) avec fil d'ariane + titre. Le socle
   le pose ; chaque thème l'habille (le flagship le passe en crème/Georgia). */
.page-masthead {
    position: relative; overflow: hidden;
    border-bottom: 1px solid var(--site-border);
    padding: clamp(2.5rem, 5vw, 4.5rem) 0 clamp(1.8rem, 3.5vw, 3rem);
    background: var(--site-surface);
}
.page-masthead--image {
    color: #fff; border-bottom: 0;
    min-height: clamp(280px, 40vh, 460px);
    display: flex; align-items: flex-end;
    padding-bottom: clamp(2rem, 4vw, 3.5rem);
}
.page-masthead__bg { position: absolute; inset: 0; z-index: 0; background-size: cover; background-position: center; will-change: transform; }
.page-masthead--image .page-masthead__bg { inset: -8% 0; }
/* width:100% : sur un bandeau AVEC image, la section est en flex (align-items:
   flex-end) et sans cette largeur le .site-wrap se réduit à la largeur de son
   contenu puis se recentre (margin:auto) — le titre partait vers la droite au
   lieu de rester calé à gauche sur la gouttière, comme les sections. */
.page-masthead__inner { position: relative; z-index: 1; width: 100%; text-align: left; }
.page-masthead__title { font-family: var(--font-heading); font-size: clamp(2.1rem, 1.5rem + 2.2vw, 3.4rem); line-height: 1.05; letter-spacing: -0.02em; font-weight: 600; margin: 0.3rem 0 0; }
.page-masthead--image .page-masthead__title { color: #fff; }
.page-masthead__lead { color: var(--site-soft); font-size: clamp(1.05rem, 1rem + 0.4vw, 1.25rem); line-height: 1.6; max-width: 54ch; margin: 1rem 0 0; }
.page-masthead--image .page-masthead__lead { color: rgba(255, 255, 255, 0.9); }
.page-masthead__crumb { margin: 0 0 0.4rem; }
.page-masthead--image .breadcrumb, .page-masthead--image .breadcrumb a { color: rgba(255, 255, 255, 0.85); }
/* Chapô (lead) : la ligne d'intro qui ouvre une section. Plus grande et plus
   aeree que le corps, elle pose le ton — le geste editorial des references. */
.lead {
    color: var(--site-soft);
    font-size: clamp(1.15rem, 1.03rem + 0.55vw, 1.4rem);
    line-height: 1.6; max-width: 60ch;
    font-weight: 400; letter-spacing: -0.005em;
    margin-bottom: clamp(1.5rem, 3vw, 2.5rem);
}
/* Une légende (figcaption/caption) empruntant .lead ne doit pas hériter de
   cette marge basse : elle clôt son bloc. */
figcaption.lead, .block-caption.lead { margin-bottom: 0; }

/* Navigation Précédent / Suivant entre prestations (option Modèles). */
.service-nav { display: flex; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
.service-nav__link {
    display: flex; flex-direction: column; gap: 0.2rem;
    max-width: 22rem; padding: 0.9rem 1.3rem;
    border: 1px solid var(--site-border); border-radius: var(--radius-card, 12px);
    text-decoration: none; color: inherit; background: var(--site-bg);
    transition: border-color 0.2s ease, transform 0.2s ease, box-shadow 0.2s ease;
}
.service-nav__link:hover { border-color: color-mix(in srgb, var(--site-ink) 30%, var(--site-border)); transform: translateY(-2px); box-shadow: 0 14px 30px -20px rgba(0,0,0,0.4); }
.service-nav__link--next { text-align: right; margin-left: auto; }
.service-nav__dir { font-size: 0.78rem; letter-spacing: 0.02em; color: color-mix(in srgb, var(--c-accent) 58%, var(--site-ink)); font-weight: 500; }
.service-nav__name { font-size: 1.05rem; font-weight: 500; }
.service-nav__spacer { flex: 0 0 auto; }

/* Variante « Voir aussi » en listing sobre (sans photos). */
.related-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.4rem; }
.related-list a { display: flex; justify-content: space-between; gap: 1rem; padding: 0.7rem 0; border-bottom: 1px solid var(--site-border); text-decoration: none; color: inherit; }
.related-list a:hover { color: var(--c-accent); }

/* --- Moteur de recherche (loupe → overlay plein écran) --------------------- */
.site-search-btn {
    display: inline-flex; align-items: center; justify-content: center;
    width: 2.4rem; height: 2.4rem; padding: 0; margin-left: 0.35rem;
    background: transparent; border: 0; color: inherit; cursor: pointer;
    border-radius: 999px; transition: color 0.15s ease, opacity 0.15s ease;
}
.site-search-btn:hover { color: var(--c-accent); }
/* Sur l'accueil, l'en-tête est transparent sur la bannière : les liens du menu
   passent en blanc (règle des thèmes). La loupe suit le même sort (sinon elle
   resterait sombre, peu lisible sur la photo). Au défilement (is-stuck) ou hors
   accueil, elle reprend la couleur d'encre normale, comme les liens. */
.site:has(.hero--image) .site-header:not(.is-stuck) .site-search-btn { color: #fff; }

.site-search {
    position: fixed; inset: 0; z-index: 11000; overflow-y: auto;
    background: color-mix(in srgb, var(--site-bg, #ffffff) 97%, transparent);
    -webkit-backdrop-filter: blur(9px); backdrop-filter: blur(9px);
    opacity: 0; transition: opacity 0.25s ease;
    padding: clamp(3.5rem, 11vh, 8rem) var(--gutter, 1.25rem) 3rem;
}
.site-search.is-open { opacity: 1; }
.site-search[hidden] { display: none; }
.site-search__inner { max-width: 920px; margin: 0 auto; }
.site-search__close {
    position: fixed; top: 1.1rem; right: 1.2rem; z-index: 1;
    width: 2.8rem; height: 2.8rem; border: 0; border-radius: 999px; cursor: pointer;
    background: var(--site-surface, #eeeeee); color: var(--site-ink, #222222);
    font-size: 1.25rem; line-height: 1; display: flex; align-items: center; justify-content: center;
}
.site-search__close:hover { background: color-mix(in srgb, var(--site-ink) 14%, var(--site-surface)); }
.site-search__bar {
    display: flex; align-items: center; gap: 0.75rem;
    border-bottom: 2px solid var(--site-border, #dddddd); padding-bottom: 0.5rem;
}
.site-search__ico { flex: 0 0 auto; color: var(--site-soft, #888888); }
.site-search__input {
    flex: 1; min-width: 0; border: 0; background: transparent; outline: none;
    color: var(--site-ink, #111111); font-family: var(--font-heading, inherit);
    font-size: clamp(1.4rem, 1rem + 2.4vw, 2.6rem); line-height: 1.1; padding: 0.25rem 0;
}
.site-search__input::placeholder { color: var(--site-soft, #999999); }
/* Pas de liseré de focus (le champ occupe déjà toute la barre, souligné) : le
   contour d'accent global (.site :focus-visible) n'a pas de sens ici. */
.site-search__input:focus, .site-search__input:focus-visible { outline: none; box-shadow: none; }
/* Masque la petite croix native de vidage (héritée d'un ancien type=search). */
.site-search__input::-webkit-search-cancel-button,
.site-search__input::-webkit-search-decoration { -webkit-appearance: none; appearance: none; display: none; }
.site-search__hint { color: var(--site-soft, #888888); margin: 1rem 0 0; }
.site-search__results { margin-top: 1.6rem; }
.site-search__empty, .site-search__more { color: var(--site-soft, #888888); }
.site-search__more { margin-top: 1rem; font-size: 0.9rem; }
/* Résultats en cartes : grille compacte. On CONSERVE le décalage éditorial
   (stagger) du thème s'il existe — c'est `margin-block-start` sur :nth-child(even),
   qui réserve son espace, donc pas de chevauchement. `align-items:start` garde les
   cartes à hauteur naturelle. Les thèmes qui annulent le stagger (studio-blanc,
   margin-block-start:0) restent naturellement à plat. */
.site-search__results .cards--services { grid-template-columns: repeat(auto-fill, minmax(min(200px, 100%), 1fr)); align-items: start; }
.site-search__results .card__img { aspect-ratio: 4 / 3; height: auto; }

/* --- Surtitre (kicker) premium -------------------------------------------
   Petit intitulé en capitales espacées au-dessus d'un titre de section
   (« Nos soins », « Notre histoire »). Latent ici : l'en-tête de section
   structuré de l'étape 2 le renseignera avec du vrai texte. */
.eyebrow {
    display: inline-block; margin: 0 0 0.9rem;
    font-family: var(--font-body, system-ui, sans-serif);
    font-size: 0.74rem; font-weight: 600;
    letter-spacing: 0.22em; text-transform: uppercase;
    color: var(--c-accent);
}

/* --- Bande défilante (marquee) -------------------------------------------
   Deux groupes identiques dans la piste ; l'animation ne tourne que sur le
   site public (classe `--run`), jamais dans l'éditeur visuel. */
.marquee { overflow: hidden; border-block: 1px solid var(--site-border); background: var(--site-surface); padding: clamp(1.1rem, 0.7rem + 1.4vw, 1.9rem) 0; }
.marquee__track { display: flex; width: max-content; }
.marquee__group { display: flex; align-items: center; flex-shrink: 0; }
.marquee--run .marquee__group { animation: bd-marquee 34s linear infinite; }
.marquee__item {
    font-family: var(--font-heading); font-weight: 600; letter-spacing: -0.01em;
    font-size: clamp(1.4rem, 1rem + 1.5vw, 2.4rem); color: var(--site-ink);
    white-space: nowrap; padding: 0 clamp(1.2rem, 0.8rem + 1.2vw, 2.4rem);
}
.marquee__item::before { content: "•"; color: var(--c-accent); margin-right: clamp(1.2rem, 0.8rem + 1.2vw, 2.4rem); }
@keyframes bd-marquee { from { transform: translateX(0); } to { transform: translateX(-100%); } }
@media (prefers-reduced-motion: reduce) {
    .marquee--run .marquee__group { animation: none; }
    .marquee--run .marquee__group + .marquee__group { display: none; }
    .marquee__track { flex-wrap: wrap; justify-content: center; }
}

/* --- Chiffres clés (stats) ------------------------------------------------ */
.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: var(--ecart-cartes); }
.stat { text-align: center; padding: 1rem 0.5rem; }
.stat__value {
    display: block; font-family: var(--font-heading); font-weight: 700; line-height: 1;
    font-size: clamp(2.4rem, 1.6rem + 3vw, 4rem); letter-spacing: -0.02em; color: var(--site-ink);
}
.stat__label { display: block; margin-top: 0.6rem; font-size: 0.92rem; color: var(--site-soft); }

/* --- Descriptif deplie -------------------------------------------------------
   Le texte complet est TOUJOURS dans le HTML (referencement, lecteurs d'ecran) ;
   seule la version courte est montree. Sans JavaScript, `.has-js` est absente
   et c'est la version complete qui s'affiche : rien n'est jamais tronque
   definitivement.
   ----------------------------------------------------------------------------- */
.texte-long__court { display: none; }
.texte-long__plus { display: none; }
.has-js .texte-long__court { display: block; }
.has-js .texte-long__complet { display: none; }
.has-js .texte-long.is-open .texte-long__court { display: none; }
.has-js .texte-long.is-open .texte-long__complet { display: block; }
.has-js .texte-long__plus {
    display: inline-block;
    margin-top: 0.35rem;
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    font-size: 0.9rem;
    font-weight: 500;
    color: var(--c-accent);
    cursor: pointer;
    border-bottom: 1px solid currentColor;
}
.texte-long__plus:hover { color: var(--site-ink); }

/* --- Cartes -------------------------------------------------------------------
   Chaque carte recoit un bandeau visuel genere, decale en teinte selon son
   rang, pour eviter l'effet catalogue uniforme quand il n'y a pas de photo.
   ----------------------------------------------------------------------------- */
/* `min(300px, 100%)` : sous 300px de large, une piste fixe deborderait le
   conteneur — c'est la cause classique du defilement horizontal en 320px. */
.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(300px, 100%), 1fr)); gap: var(--ecart-cartes); }
/* Nombre de COLONNES desktop au choix (option Modèles). N'agit QUE si l'admin a
   choisi 2/3/4 (classe verrou `site--has-*cols` posée par layout.php) — sinon la
   mise en page native du modèle est conservée. En dessous de 900px on garde
   l'auto-fill responsif du socle. Le blog et les cartes libres ne sont pas touchés. */
@media (min-width: 900px) {
    /* Prestations : cartes (page catégorie, détail d'un besoin, catalog « cards »)
       ET grille des UNIVERS (page /prestations et catalog « univers »).
       Spécificité 0,3,0 → bat la valeur du thème (0,1,0). Riviera exclu (sa grille
       univers est éditoriale, avec des `.flag-uni` en span). */
    .site--has-scols .cards--services,
    .site--has-scols:not(.theme-riviera-solaire) .flag-univers__grid {
        grid-template-columns: repeat(var(--cards-cols, 3), minmax(0, 1fr));
    }
    .site--has-ncols .cards--besoins {
        grid-template-columns: repeat(var(--besoins-cols, 3), minmax(0, 1fr));
    }
    /* Ratio d'image COHÉRENT quel que soit le nombre de colonnes choisi. Sans ça,
       la hauteur (fixée en vw par les thèmes) reste identique quand les colonnes
       se resserrent → images très allongées à 4 colonnes. On pilote la hauteur
       par un aspect-ratio : elle suit la largeur, donc la proportion est la même
       en 2, 3 ou 4 colonnes. S'applique à TOUS les thèmes (Riviera exclu : il
       gère déjà ses propres proportions). */
    .site--has-scols:not(.theme-riviera-solaire) .flag-univers__grid .flag-uni__img {
        height: auto; min-height: 0; aspect-ratio: 4 / 5;
    }
    .site--has-scols .cards--services .card__img,
    .site--has-scols .cards--services .card::before,
    .site--has-ncols .cards--besoins .card__img,
    .site--has-ncols .cards--besoins .card::before {
        height: auto; aspect-ratio: 4 / 3;
    }
}
.card {
    display: flex; flex-direction: column;
    background: var(--site-bg);
    border: 1px solid var(--site-border);
    border-radius: var(--radius-card, 12px);
    padding: 0; overflow: hidden;
    text-decoration: none; color: inherit;
    transition: transform 0.25s ease, box-shadow 0.25s ease, border-color 0.25s ease;
}
.card::before {
    content: "";
    display: block; aspect-ratio: 4 / 3;
    background:
        radial-gradient(420px 220px at 22% 10%, rgba(var(--site-veil-a), 0.55), transparent 65%),
        radial-gradient(380px 240px at 82% 96%, rgba(var(--site-veil-b), 0.45), transparent 62%),
        var(--site-tint);
    border-bottom: 1px solid var(--site-border);
}
.card:nth-child(3n+2)::before { filter: hue-rotate(14deg); }
.card:nth-child(3n+3)::before { filter: hue-rotate(-12deg) saturate(0.9); }
.card:hover {
    transform: translateY(-4px);
    box-shadow: 0 2px 6px rgba(0,0,0,0.03), 0 24px 48px -20px rgba(0,0,0,0.22);
    border-color: color-mix(in srgb, var(--site-ink) 22%, var(--site-border));
}
/* Le contenu textuel de la carte */
.card > :not(.card__img) { padding-left: 1.6rem; padding-right: 1.6rem; }
.card__title { font-size: 1.4rem; margin-top: 1.5rem; margin-bottom: 0.4rem; }
.card p { color: var(--site-soft); font-size: 0.975rem; }
/* Description de prestation sur une page catégorie (option Modèles) : bornée à
   3 lignes pour garder des cartes régulières. */
.card__desc {
    margin: 0.15rem 0 0; line-height: 1.5;
    display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden;
}
/* L'accent est choisi librement par le client : tel quel il peut tomber sous
   le seuil de contraste. On le rapproche de l'encre du theme, ce qui fonce
   sur fond clair et eclaircit sur fond sombre — lisible quelle que soit la
   teinte retenue, tout en restant reconnaissable. */
.card__meta {
    display: block; margin-top: auto;
    padding-top: 0.5rem; padding-bottom: 1.6rem;
    color: color-mix(in srgb, var(--c-accent) 58%, var(--site-ink));
    font-weight: 500; font-size: 0.9rem;
    letter-spacing: 0.01em;
}
/* Si une vraie photo est fournie, elle remplace le bandeau genere. */
.card:has(.card__img)::before { display: none; }
.card__img {
    width: 100%; height: auto; aspect-ratio: 4 / 3; object-fit: cover;
    display: block; margin: 0;
    border-bottom: 1px solid var(--site-border);
}

/* --- Collaborateurs (bloc « team ») : grille de photos RONDES + prénom -------
   Récupérés à l'import (Planity) ou saisis à la main. Photo ronde recadrée en
   cover (object-fit) : un portrait quelconque reste centré. */
.team-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(clamp(130px, 15vw, 168px), 1fr));
    gap: clamp(1.6rem, 1rem + 2vw, 3rem) clamp(1.2rem, 0.8rem + 1.4vw, 2rem);
    justify-items: center;
    margin-top: clamp(1.6rem, 3vw, 2.6rem);
}
.team-member { margin: 0; text-align: center; max-width: 200px; }
.team-member__photo {
    display: block; width: clamp(96px, 13vw, 150px); aspect-ratio: 1 / 1;
    margin: 0 auto 0.9rem; border-radius: 50%; overflow: hidden;
    background: var(--site-tint);
    box-shadow: 0 10px 26px rgba(0, 0, 0, 0.12);
}
.team-member__photo img { width: 100%; height: 100%; object-fit: cover; object-position: center 30%; display: block; transition: transform 0.6s cubic-bezier(0.2, 0.7, 0.2, 1); }
.team-member:hover .team-member__photo img { transform: scale(1.05); }
.team-member__photo--ph { display: grid; place-items: center; font-family: var(--font-heading); font-size: clamp(2rem, 4vw, 3rem); color: var(--c-secondary); }
.team-member__name { font-family: var(--font-heading); font-weight: 600; font-size: clamp(1rem, 0.95rem + 0.3vw, 1.2rem); line-height: 1.2; }
.team-member__role { color: var(--site-soft); font-size: 0.86rem; line-height: 1.35; margin: 0.25rem 0 0; }

/* --- Micro-interactions --------------------------------------------------
   Zoom fluide de l'image au survol d'une carte (prestations, cartes photo).
   Le cadre .card a overflow:hidden : le débordement du zoom est masqué. */
.card__img, .card::before { transition: transform 0.65s cubic-bezier(0.2, 0.7, 0.2, 1); transform-origin: center; }
.card:hover .card__img, .card:hover::before { transform: scale(1.06); }
/* Le meta (« N prestations → ») glisse legerement : signal de clic discret. */
.card__meta { transition: transform 0.3s cubic-bezier(0.2, 0.7, 0.2, 1), color 0.2s ease; }
.card:hover .card__meta { transform: translateX(5px); color: var(--c-accent); }

/* Liens de contenu : soulignement TOUJOURS présent (accessibilité) mais discret,
   qui s'intensifie à l'accent et teinte le texte au survol (transition douce). */
.site .prose a {
    color: var(--site-ink);
    text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px;
    text-decoration-color: color-mix(in srgb, var(--c-accent) 45%, transparent);
    transition: text-decoration-color 0.25s ease, color 0.2s ease, text-decoration-thickness 0.2s ease;
}
.site .prose a:hover {
    color: var(--c-accent);
    text-decoration-color: var(--c-accent); text-decoration-thickness: 2px;
}

/* --- Listes de prix ------------------------------------------------------------ */
.cat-block { margin-bottom: var(--ecart-bloc); }
.theme-title {
    font-size: 1.05rem; color: var(--site-soft);
    margin: 2.2rem 0 0.4rem;
    font-family: var(--font-body); font-weight: 600;
    letter-spacing: 0.06em; text-transform: uppercase;
}
.theme-title a, .cat-block a { text-decoration: none; }
.price-list { list-style: none; padding: 0; margin: 0; }
.price-list__row {
    display: flex; align-items: baseline; gap: 0.75rem; flex-wrap: wrap;
    padding: 0.95rem 0;
    border-bottom: 1px solid var(--site-border);
}
/* Description de prestation dans le listing sobre (option Modèles) : passe à la
   ligne sous le nom/prix. */
.price-list__desc { flex-basis: 100%; margin: 0.2rem 0 0; color: var(--site-soft); font-size: 0.92rem; line-height: 1.5; }
/* La description reste sous le NOM et ne court pas sous le temps/prix : on réserve
   à droite la largeur de la colonne temps+prix. Desktop seulement (sur mobile la
   ligne s'empile, pleine largeur). */
@media (min-width: 640px) { .price-list__desc { padding-right: 11.5rem; } }
.price-list__row:last-child { border-bottom: 0; }
.price-list__name { font-weight: 500; text-decoration: none; transition: color 0.15s ease; }
a.price-list__name:hover { color: var(--c-accent); }
.price-list__dots { flex: 1; border-bottom: 1px dotted var(--site-border); transform: translateY(-4px); }
.price-list__meta { display: inline-flex; align-items: baseline; gap: 0.85rem; white-space: nowrap; font-variant-numeric: tabular-nums lining-nums; }
/* Temps et prix en COLONNES calées : largeur fixe + alignés à droite. Un prix à
   3 chiffres (ex. 100,00 €) ne décale plus le temps, et les « € » restent
   alignés d'une ligne à l'autre. */
.price-list__meta .dur   { display: inline-block; min-width: 4.5em; text-align: right; color: var(--site-soft); font-size: 0.9rem; }
.price-list__meta .price { display: inline-block; min-width: 5.2em; text-align: right; font-weight: 600; color: var(--site-ink); }

.cta-center { text-align: center; margin-top: 3.5rem; }

/* État vide d'une rubrique (blog sans article, etc.) : message centré discret. */
.section-empty { text-align: center; color: var(--muted, #6b6b6b); font-size: 1.05rem; padding: 2.5rem 0; margin: 0; }

/* --- Bandeau ------------------------------------------------------------------- */
.band {
    background: var(--site-surface);
    border-top: 1px solid var(--site-border);
    border-bottom: 1px solid var(--site-border);
}
.band__inner {
    display: flex; align-items: center; justify-content: space-between;
    gap: 2rem; padding: var(--rythme-section) var(--gutter); flex-wrap: wrap;
}
.band .section__title::after { display: none; }
.band .section__title { font-size: clamp(1.9rem, 1.3rem + 2vw, 3rem); margin-bottom: 0.35rem; }
.band p { color: var(--site-soft); font-size: 1.08rem; max-width: 48ch; }

/* --- Foire aux questions (page prestation) -------------------------------------- */
.faq__list { display: flex; flex-direction: column; gap: 0.6rem; margin-top: 1.5rem; }
.faq__item {
    border: 1px solid var(--site-border); border-radius: var(--radius-card, 12px);
    background: var(--site-surface); overflow: hidden;
}
.faq__q {
    cursor: pointer; list-style: none; padding: 1rem 1.2rem;
    font-weight: 600; display: flex; align-items: center; justify-content: space-between; gap: 1rem;
}
.faq__q::-webkit-details-marker { display: none; }
.faq__q::after { content: "+"; font-size: 1.3rem; line-height: 1; color: var(--site-soft); flex: none; }
.faq__item[open] .faq__q::after { content: "−"; }
.faq__q:hover { background: var(--site-tint); }
.faq__a { padding: 0 1.2rem 1.1rem; color: var(--site-soft); line-height: 1.65; }

/* --- Réseaux sociaux (pied de page) --------------------------------------------- */
.site-social { list-style: none; margin: 0.9rem 0 0; padding: 0; display: flex; gap: 0.55rem; }
.site-social a {
    display: inline-flex; align-items: center; justify-content: center;
    width: 2.3rem; height: 2.3rem; border-radius: 50%;
    border: 1px solid currentColor; opacity: 0.75;
    transition: opacity 0.2s ease, transform 0.2s ease;
}
.site-social a:hover { opacity: 1; transform: translateY(-2px); }

/* --- Avis clients (slider accueil) ---------------------------------------------- */
.reviews { padding: var(--rythme-section) 0; }
.reviews__title { text-align: center; }
/* Note globale + détail par critère. */
.reviews__summary {
    display: flex; gap: 2.5rem; flex-wrap: wrap; align-items: center; justify-content: center;
    margin-top: 1.75rem;
}
.reviews__score { text-align: center; }
.reviews__score-num { display: block; font-size: 2.8rem; font-weight: 700; line-height: 1; color: var(--site-ink); }
.reviews__score-max { font-size: 1.1rem; color: var(--site-soft); font-weight: 500; }
.reviews__score-stars { color: #e0a500; letter-spacing: 2px; }
.reviews__score-count { display: block; color: var(--site-soft); font-size: 0.9rem; margin-top: 0.2rem; }
.reviews__criteria {
    list-style: none; margin: 0; padding: 0; width: 100%;
    /* Petit écran : un critère par ligne (label à gauche, note à droite). */
    display: flex; flex-direction: column; gap: 0.6rem;
}
.reviews__criterion { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; }
/* Grand écran : tous les critères alignés sur une seule ligne. */
@media (min-width: 720px) {
    .reviews__criteria { flex-direction: row; flex-wrap: nowrap; justify-content: center; gap: 2.75rem; }
    .reviews__criterion { flex-direction: column; align-items: center; justify-content: center; gap: 0.2rem; text-align: center; }
    .reviews__criterion-note { font-size: 1.15rem; }
}
.reviews__criterion-label { color: var(--site-soft); }
.reviews__criterion-note { font-weight: 600; color: var(--site-ink); }
.reviews__viewport { margin-top: 2rem; }
.reviews__track {
    list-style: none; margin: 0; padding: 0.5rem 0.25rem 1.25rem;
    display: flex; gap: 1.25rem;
    overflow-x: auto; scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch; scrollbar-width: none;
}
.reviews__track::-webkit-scrollbar { display: none; }
.review-card {
    scroll-snap-align: center; flex: 0 0 min(360px, 82%);
    display: flex; flex-direction: column; gap: 0.9rem;
    background: var(--site-surface);
    border: 1px solid var(--site-border); border-radius: var(--radius-card, 14px);
    padding: 1.5rem 1.6rem;
}
.review-card__stars { color: #e0a500; letter-spacing: 2px; font-size: 1rem; }
.review-card__text {
    position: relative; margin: 0; quotes: none; color: var(--site-ink);
    font-size: 1.06rem; line-height: 1.62;
}
/* Grand guillemet decoratif, discret : le signe editorial des temoignages.
   Place au tout debut du texte (filigrane), sans remonter sur les etoiles. */
.review-card__text::before {
    content: "\201C"; position: absolute; top: -0.2rem; left: -0.2rem;
    font-family: var(--font-heading); font-size: 3rem; line-height: 1;
    color: var(--c-accent); opacity: 0.22; pointer-events: none;
}
.review-card__meta { display: flex; flex-direction: column; gap: 0.15rem; margin-top: auto; }
.review-card__author { font-weight: 600; }
.review-card__date { color: var(--site-soft); font-size: 0.85rem; }
.reviews__controls {
    display: flex; align-items: center; justify-content: center;
    gap: 1rem; margin-top: 1.5rem; flex-wrap: wrap;
}
.reviews__nav { display: flex; gap: 0.5rem; }
.reviews__btn {
    width: 2.6rem; height: 2.6rem; border-radius: 50%;
    border: 1px solid var(--site-border); background: var(--site-bg);
    color: var(--site-ink); font-size: 1.4rem; line-height: 1; cursor: pointer;
    transition: background 0.2s ease, color 0.2s ease;
}
.reviews__btn:hover { background: var(--site-tint); }

/* --- Avis : carrousel infini, GLISSABLE, avec accroche (classe posée par
   reviews.js). La position (transform) et l'accroche sont pilotées en JS ;
   `touch-action: pan-y` laisse le défilement vertical de page au navigateur
   tout en réservant le glissé horizontal au carrousel. */
.reviews--loop .reviews__viewport { overflow: hidden; }
.reviews--loop .reviews__track {
    overflow: visible; scroll-snap-type: none; flex-wrap: nowrap;
    width: max-content; padding-left: 0; padding-right: 0; will-change: transform;
    cursor: grab; user-select: none; -webkit-user-select: none; touch-action: pan-y;
}
.reviews--drag .reviews__track { cursor: grabbing; }
.reviews--loop .review-card { flex: 0 0 auto; width: min(360px, 82vw); scroll-snap-align: none; }
.reviews--loop .reviews__nav { display: none; }

/* --- Fil d'Ariane ---------------------------------------------------------------- */
.breadcrumb { color: var(--site-soft); font-size: 0.875rem; margin-bottom: 1.2rem; }
.breadcrumb a { text-decoration: none; }
.breadcrumb a:hover { color: var(--site-ink); }
.breadcrumb span { margin: 0 0.4rem; opacity: 0.5; }

/* --- Page prestation -------------------------------------------------------------- */
.service-layout { display: grid; grid-template-columns: 1fr 340px; gap: 3.5rem; align-items: start; }
.service-meta { display: flex; gap: 0.6rem; margin: 1rem 0 1.6rem; flex-wrap: wrap; }
.chip {
    background: var(--site-surface);
    border: 1px solid var(--site-border);
    border-radius: 999px; padding: 0.3rem 0.9rem;
    font-size: 0.875rem;
}
.chip--price { color: var(--site-ink); font-weight: 600; font-variant-numeric: tabular-nums; }
.service-img { width: 100%; border-radius: var(--radius-card); margin: 0.5rem 0 1.6rem; display: block; }
.service-desc { color: var(--site-ink); font-size: 1.0625rem; }
.booking-card {
    background: var(--site-surface);
    border: 1px solid var(--site-border);
    border-radius: var(--radius-card);
    padding: 1.75rem; position: sticky; top: 100px;
}
.booking-card__price {
    font-family: var(--font-heading);
    font-size: 2.4rem; color: var(--site-ink);
    line-height: 1; font-variant-numeric: tabular-nums lining-nums;
}
.theme-luxe .booking-card__price { color: var(--c-accent); }
.booking-card__dur { color: var(--site-soft); margin-bottom: 1.4rem; }

/* --- Contact / prose ---------------------------------------------------------------- */
.contact-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 3.5rem; }
.hours { border-collapse: collapse; width: 100%; }
.hours th {
    text-align: left; padding: 0.5rem 1.5rem 0.5rem 0;
    color: var(--site-soft); font-weight: 500;
}
.hours td { padding: 0.5rem 0; font-variant-numeric: tabular-nums; }
/* Image d'en-tête d'une page catégorie. */
.cat-hero { display: block; width: 100%; max-height: 420px; object-fit: cover; border-radius: var(--radius-card, 12px); margin: 1.6rem 0 var(--ecart-bloc); }

/* « Vos besoins » : liste de liens vers la page de chaque besoin. */
/* Les CARTES de « Vos besoins » réutilisent le composant .card (identique aux
   prestations) → chaque modèle les stylise pareil. Voir public/besoins.php. */

/* --- « Vos besoins » : LISTE (option classique, redessinée) ------------------ */
.needs-list { display: grid; gap: 0.7rem; margin-top: clamp(1.8rem, 3vw, 2.6rem); }
.need-link {
    display: flex; align-items: center; gap: 1rem;
    padding: 0.9rem 1.15rem; background: var(--site-surface); border: 1px solid var(--site-border);
    border-radius: var(--radius-card, 14px); text-decoration: none; color: inherit;
    transition: border-color 0.2s ease, transform 0.2s ease, box-shadow 0.2s ease;
}
.need-link:hover {
    border-color: color-mix(in srgb, var(--c-primary) 45%, var(--site-border));
    transform: translateX(4px); box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
}
.need-link__thumb { flex: none; width: 56px; height: 56px; border-radius: 50%; overflow: hidden; background: var(--site-tint); }
.need-link__thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.need-link__label { font-family: var(--font-heading, Georgia, serif); font-size: clamp(1.15rem, 1rem + 0.5vw, 1.4rem); line-height: 1.2; margin-right: auto; }
.need-link__meta { color: var(--site-soft); font-size: 0.9rem; white-space: nowrap; }

.prose { max-width: 68ch; }
.prose h2 { font-size: 1.45rem; margin-top: 2.4rem; }
.prose__note { color: var(--site-soft); font-size: 0.875rem; font-style: italic; margin-top: 2.5rem; }

/* --- Blocs : texte + image, colonnes, vidéo, galerie ----------------------------------- */
/* Texte + image côte à côte. La colonne image passe en premier sur .media--img-left,
   via l'ordre de grille — jamais de marges bricolées. Empilé en une colonne sur mobile. */
.media { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(2rem, 5vw, 4.5rem); align-items: center; }
.media .media__text { max-width: 58ch; }
/* Le rayon + overflow vivent sur la FIGURE (pas sur l'img) : avec le parallax,
   l'image surdimensionnee (scale 1.14) est recadree par la figure — sans rayon
   sur celle-ci, les coins arrondis disparaitraient. La figcaption reste en flux
   normal SOUS l'image, dans les bornes de la figure : overflow:hidden ne coupe
   que le debordement de l'image scalee, pas le texte. */
.media__figure { margin: 0; border-radius: var(--radius-card, 12px); overflow: hidden; }
.media__figure img { width: 100%; height: auto; display: block; }
.media__figure figcaption { color: var(--site-soft); font-size: 0.9rem; margin-top: 0.6rem; padding: 0 0.1rem; }
.media--img-left .media__text { order: 2; }
.media--img-left .media__figure { order: 1; }

/* --- Split PLEIN-CADRE (media--bleed) --------------------------------------
   La section occupe 100% de la largeur (pas de .site-wrap) : l'image touche le
   bord de l'écran de son côté, le texte s'aligne dans une demi-colonne aérée.
   L'ADN des sections média des références (Beauty Pearl). */
.media--bleed {
    grid-template-columns: 1fr 1fr;
    gap: 0; align-items: stretch;
    padding: 0;                       /* annule le padding de .section : image à ras bord */
    overflow: clip;                   /* garde-fou anti-débordement horizontal */
}
.media--bleed .media__text {
    max-width: none; width: 100%;         /* remplit la demi-colonne (annule le 58ch de .media) */
    display: flex; align-items: center;
    padding: clamp(2.75rem, 5vw, 5.5rem) clamp(1.8rem, 5vw, 5.5rem);
}
.media--bleed .media__text-inner { max-width: 36rem; }    /* mesure de lecture confortable */
.media--bleed .media__figure {
    border-radius: 0; overflow: hidden; margin: 0;
    min-height: clamp(380px, 54vh, 680px); height: 100%;
}
.media--bleed .media__figure img { width: 100%; height: 100%; object-fit: cover; }
@media (max-width: 820px) {
    .media--bleed { grid-template-columns: 1fr; }
    /* Image en premier (au-dessus du texte), quel que soit le sens desktop. */
    .media--bleed .media__figure { order: -1; min-height: clamp(240px, 62vw, 400px); }
    .media--bleed .media__text { padding: clamp(2rem, 8vw, 3.25rem) var(--gutter); }
}

/* Colonnes de texte. */
.txt-cols { display: grid; gap: clamp(1.8rem, 4vw, 3.6rem); }
.txt-cols--2 { grid-template-columns: repeat(2, 1fr); }
.txt-cols--3 { grid-template-columns: repeat(3, 1fr); }

/* Vidéo externe : cadre 16:9 fluide. */
.video-embed { position: relative; width: 100%; aspect-ratio: 16 / 9; border-radius: var(--radius-card, 12px); overflow: hidden; background: #000; }
.video-embed iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

/* Galerie photo. */
.gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(220px, 100%), 1fr)); gap: var(--ecart-cartes, 1.5rem); }
.gallery__item { margin: 0; }
.gallery__item img { width: 100%; height: 100%; aspect-ratio: 4 / 3; object-fit: cover; border-radius: var(--radius-card, 12px); display: block; cursor: zoom-in; transition: opacity 0.2s ease; }
.gallery__item img:hover { opacity: 0.92; }
.gallery__item figcaption { color: var(--site-soft); font-size: 0.85rem; margin-top: 0.4rem; }

/* Galerie CLASSIQUE : mosaïque fluide (masonry) en PROPORTIONS NATURELLES.
   Fini le recadrage carré 4/3 : chaque photo garde son ratio. Colonnes CSS —
   le nombre de colonnes se calcule sur la largeur disponible (fluide, du mobile
   au grand écran), les hauteurs s'imbriquent sans trou. Les dispositions
   spéciales (éventail / losange / helix) gardent leur propre mise en page. */
.gallery.gallery--classique {
    display: block;
    column-width: 260px;
    column-gap: var(--ecart-cartes, 1.5rem);
}
.gallery--classique .gallery__item {
    break-inside: avoid;
    -webkit-column-break-inside: avoid;
    margin: 0 0 var(--ecart-cartes, 1.5rem);
}
.gallery--classique .gallery__item img {
    height: auto;
    aspect-ratio: auto;      /* proportion naturelle de la photo */
}

/* --- Bloc texte : image de fond (richtext / colonnes) ----------------------
   Énoncé PLEIN ÉCRAN : la section occupe 100% de la largeur (aucun .site-wrap
   sur la section — le texte est cadré par un .site-wrap INTERNE), photo plein
   cadre, contenu centré verticalement. Le geste « respiration cinéma » des
   références (Obsidienne). Le voile dégradé est dans le background inline. */
.section--bg {
    background-size: cover; background-position: center; background-attachment: scroll;
    color: #fff;
    display: flex; flex-direction: column; justify-content: center;
    min-height: clamp(420px, 62vh, 720px);
    padding-block: clamp(3.5rem, 2rem + 5vw, 7rem);
    padding-inline: 0;               /* le .site-wrap interne gère la gouttière */
    box-shadow: inset 0 -160px 180px -90px rgba(0, 0, 0, 0.6);
    overflow: hidden;
}
/* Le contenu s'aligne à gauche dans sa colonne de lecture (éditorial), pas
   centré au milieu de l'écran — comme les énoncés des références. */
.section--bg > .site-wrap { width: 100%; }
.section--bg .prose { max-width: 62ch; }
.section--bg .section__title, .section--bg h2, .section--bg h3, .section--bg h4,
.section--bg p, .section--bg li, .section--bg strong, .section--bg blockquote, .section--bg .lead { color: #fff; }
.section--bg .section__title { font-size: clamp(2.3rem, 1.5rem + 2.6vw, 3.6rem); text-shadow: 0 1px 30px rgba(0, 0, 0, 0.35); }
.section--bg .eyebrow { color: rgba(255, 255, 255, 0.9); }
.section--bg > .section__title::after { background: rgba(255, 255, 255, 0.85); }
.section--bg .prose a { color: #fff; text-decoration-color: rgba(255, 255, 255, 0.7); }
/* Colonnes sur fond image : on garde le texte lisible en le bornant. */
.section--bg .txt-cols { max-width: 74ch; }

/* --- Galerie : ÉVENTAIL ----------------------------------------------------
   Les photos s'étalent en éventail depuis le bas ; au survol, la photo se
   redresse, se soulève et passe devant. */
.gallery--eventail {
    display: flex; justify-content: center; align-items: flex-end; gap: 0;
    min-height: clamp(240px, 34vw, 420px); padding-top: 2rem;
}
.gallery--eventail .gallery__item {
    --mid: calc((var(--n) - 1) / 2);
    width: clamp(140px, 18vw, 230px); flex: none; margin-inline: -3.4%;
    transform-origin: bottom center;
    transform: rotate(calc((var(--i) - var(--mid)) * 9deg));
    transition: transform 0.35s cubic-bezier(0.2, 0.7, 0.2, 1);
    filter: drop-shadow(0 14px 26px rgba(0, 0, 0, 0.28));
}
.gallery--eventail .gallery__item img { aspect-ratio: 3 / 4; border: 4px solid #fff; border-radius: 6px; }
.gallery--eventail .gallery__item:hover { transform: rotate(0deg) translateY(-26px) scale(1.06); z-index: 5; position: relative; }
.gallery--eventail .gallery__item figcaption { display: none; }

/* --- Galerie : LOSANGE (diamants clip-path, façon A. Montoro) ---------------
   Au survol, la photo redevient carrée (révélée) et les autres se ternissent. */
/* Diamants ARRONDIS imbriqués (carré tourné 45° + border-radius, image
   contre-tournée) : rangées paires décalées d'une demi-case + recouvrement
   vertical → mosaïque de losanges. */
.gallery--losange {
    display: grid; grid-template-columns: repeat(3, 1fr); gap: 0;
    max-width: 720px; margin: clamp(2rem, 6vw, 4rem) auto; padding: 0 5%;
}
.gallery--losange .gallery__item {
    aspect-ratio: 1; margin: -13% 0; /* recouvrement vertical (imbrication) */
    transform: rotate(45deg) scale(0.68);
    border-radius: 16px; overflow: hidden;
    box-shadow: 0 14px 30px -14px rgba(0, 0, 0, 0.35);
    transition: transform 0.35s cubic-bezier(0.2, 0.7, 0.2, 1), filter 0.6s ease;
}
.gallery--losange .gallery__item img { width: 100%; height: 100%; object-fit: cover; border-radius: 0; transform: rotate(-45deg) scale(1.42); }
/* Rangées paires (items 4-6, 10-12…) décalées d'une demi-case → imbrication. */
.gallery--losange .gallery__item:nth-child(6n+4),
.gallery--losange .gallery__item:nth-child(6n+5),
.gallery--losange .gallery__item:nth-child(6n+6) { transform: translateX(50%) rotate(45deg) scale(0.68); }
.gallery--losange .gallery__item:hover { transform: rotate(45deg) scale(0.78); z-index: 3; }
.gallery--losange .gallery__item:nth-child(6n+4):hover,
.gallery--losange .gallery__item:nth-child(6n+5):hover,
.gallery--losange .gallery__item:nth-child(6n+6):hover { transform: translateX(50%) rotate(45deg) scale(0.78); }
.gallery--losange:has(.gallery__item:hover) .gallery__item:not(:hover) { filter: brightness(0.5); }
.gallery--losange .gallery__item figcaption { display: none; }

/* --- Galerie : HELIX (hélice ADN 3D, Three.js — helix-gallery.js) -----------
   Sans WebGL, .gallery--helix garde la grille du socle (repli automatique).
   Avec WebGL, le JS ajoute .is-gl : les vignettes sont masquées et un <canvas>
   plein cadre affiche l'hélice (glisser pour explorer, rotation lente au repos). */
.gallery--helix.is-gl { display: block; position: relative; height: clamp(380px, 52vw, 620px); overflow: hidden; }
.gallery--helix.is-gl .gallery__item { display: none; }
.helix-canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; touch-action: none; }

/* Lightbox (clic pour agrandir une photo de galerie). */
.gallery-lightbox { position: fixed; inset: 0; z-index: 2000; display: none; align-items: center; justify-content: center; padding: clamp(1rem, 4vw, 3rem); background: rgba(0, 0, 0, 0.86); }
.gallery-lightbox.is-open { display: flex; }
.gallery-lightbox img { max-width: 95vw; max-height: 90vh; object-fit: contain; border-radius: 6px; box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5); cursor: zoom-out; }
.gallery-lightbox__close { position: absolute; top: clamp(0.5rem, 2vw, 1.2rem); right: clamp(0.75rem, 2vw, 1.5rem); background: transparent; border: 0; color: #fff; font-size: 2.4rem; line-height: 1; cursor: pointer; opacity: 0.8; }
.gallery-lightbox__close:hover { opacity: 1; }
.gallery-lightbox__nav {
    position: absolute; top: 50%; transform: translateY(-50%);
    background: rgba(255, 255, 255, 0.12); border: 0; color: #fff;
    width: 3rem; height: 3rem; border-radius: 50%; cursor: pointer;
    font-size: 1.8rem; line-height: 1; display: flex; align-items: center; justify-content: center;
    opacity: 0.85; transition: background 0.2s ease, opacity 0.2s ease;
}
.gallery-lightbox__nav:hover { background: rgba(255, 255, 255, 0.24); opacity: 1; }
.gallery-lightbox__nav--prev { left: clamp(0.5rem, 2vw, 1.5rem); }
.gallery-lightbox__nav--next { right: clamp(0.5rem, 2vw, 1.5rem); }
.gallery-lightbox.is-solo .gallery-lightbox__nav { display: none; }

@media (max-width: 720px) {
    .media, .txt-cols--2, .txt-cols--3 { grid-template-columns: 1fr; }
    .media--img-left .media__text { order: 0; }
    .media--img-left .media__figure { order: 0; }
}

/* --- Pied de page ---------------------------------------------------------------------- */
.site-footer {
    background: var(--site-surface);
    border-top: 1px solid var(--site-border);
    margin-top: 0;
}
.site-footer__inner {
    display: flex; justify-content: space-between; gap: 3rem;
    padding: 4rem 1.75rem 2.5rem; flex-wrap: wrap;
}
.site-footer p { color: var(--site-soft); margin-bottom: 0.3rem; }
.site-footer__nav { display: flex; flex-direction: column; gap: 0.55rem; }
.site-footer__nav a {
    color: var(--site-soft); text-decoration: none; font-size: 0.9375rem;
    transition: color 0.15s ease;
}
.site-footer__nav a:hover { color: var(--site-ink); }
.site-footer__legal {
    padding: 1.5rem 1.75rem 2.5rem;
    color: var(--site-soft); font-size: 0.8125rem;
    border-top: 1px solid var(--site-border);
}

/* --- Adaptatif --------------------------------------------------------------------------
   Le rythme vertical n'est plus repris ici : l'echelle fluide du haut de
   fichier (--rythme-section, --rythme-hero) le fait varier en continu.
   ---------------------------------------------------------------------------------------- */
@media (max-width: 900px) {
    .service-layout { grid-template-columns: 1fr; gap: 2rem; }
    .contact-grid { grid-template-columns: 1fr; gap: 2.5rem; }
    .booking-card { position: static; }
}
/* --- Menu mobile ---------------------------------------------------------
   Le bouton n'apparait qu'en dessous de 900px. Tant que JavaScript n'a pas
   pris la main (.has-js), la navigation reste visible : un site vitrine ne
   doit jamais devenir inutilisable a cause d'un script.
   ------------------------------------------------------------------------ */
.site-burger {
    display: none;
    flex-direction: column;
    justify-content: center;
    gap: 5px;
    width: 44px; height: 44px;        /* cible tactile confortable */
    padding: 0 10px;
    background: transparent;
    border: 1px solid var(--site-border);
    border-radius: var(--radius-btn, 8px);
    cursor: pointer;
    flex: none;
}
/* Epaisseur ENTIERE, et gouttiere entiere : a 1.5px, chaque trait tombait sur
   une position sous-pixel differente et l'arrondi du moteur en rendait un plus
   epais que les autres. Les trois traits doivent etre identiques. */
.site-burger__bar {
    display: block; height: 2px; width: 100%;
    background: var(--site-ink);
    border-radius: 1px;
    transition: transform 0.25s ease, opacity 0.2s ease;
}
/* Deplacement = ecart entre traits (gap 5px) + epaisseur (2px) = 7px. */
.site-burger[aria-expanded="true"] .site-burger__bar:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.site-burger[aria-expanded="true"] .site-burger__bar:nth-child(2) { opacity: 0; }
.site-burger[aria-expanded="true"] .site-burger__bar:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* --- Menu plein ecran ------------------------------------------------------
   Le deroule sous l'en-tete est remplace par un panneau qui occupe l'ecran.
   Sur un telephone, une liste de 6 liens coincee sous la barre obligeait a
   viser des cibles de 1rem separees de quelques pixels ; ici chaque lien est
   une ligne pleine largeur, au format du titrage.

   Bascule en menu burger dès 1024px (et non 900) : la barre horizontale (logo +
   liens + sous-menus) devient à l'étroit bien avant le téléphone, et le modèle
   « Latéral » (colonne de 264px) n'a plus la place sur tablette. Le CSS de la
   colonne latérale démarre donc, lui aussi, à min-width: 1025px.
   -------------------------------------------------------------------------- */
@media (max-width: 1024px) {
    /* ⚠ `backdrop-filter` doit disparaitre ici. Une valeur autre que `none`
       fait de l'en-tete un BLOC CONTENEUR pour ses descendants en
       `position: fixed` : le panneau plein ecran, pourtant en `inset: 0`,
       restait enferme dans la hauteur de la barre (147px au lieu de 844).
       Le flou n'apporte rien sur un en-tete mobile opaque, on le retire. */
    .site-header {
        backdrop-filter: none;
        -webkit-backdrop-filter: none;
        background: var(--site-bg);
    }

    .site-burger { display: flex; z-index: 60; position: relative; flex: none; }

    /* Nom d'établissement long : le burger doit RESTER visible. La marque peut
       rétrécir, le titre se tronque (…) et sa typo est réduite. Le logo, lui, ne
       rétrécit pas. Corrige le cas « titre trop long » qui poussait le burger
       hors écran. */
    .site-header__inner .site-brand { flex: 0 1 auto; min-width: 0; overflow: hidden; }
    .site-header__inner .site-logo { flex: none; }
    .site-header__inner .site-title {
        display: block; min-width: 0; max-width: 100%;
        white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
        font-size: 1.3rem;
    }

    .has-js .site-nav {
        position: fixed;
        inset: 0;
        z-index: 50;
        display: flex;
        flex-direction: column;
        align-items: stretch;
        /* Menu CALÉ À GAUCHE, contenu en haut sous la croix. Zéro filet : c'est
           l'espace (le rythme des lignes) qui sépare. CTA ancré en bas. */
        text-align: left;
        justify-content: flex-start;
        gap: 0;
        padding: 5.25rem var(--gutter) 2.25rem;
        background: var(--site-bg);
        overflow-y: auto;
        overflow-x: hidden;                 /* jamais de barre de défilement horizontale */
        overscroll-behavior: contain;
        scrollbar-width: none;
        -ms-overflow-style: none;

        /* Fermé : retiré du flux ET du parcours clavier (visibility, pas display,
           pour autoriser la transition). */
        opacity: 0;
        visibility: hidden;
        transform: translateY(-0.5rem);
        transition: opacity 0.3s ease, transform 0.3s ease, visibility 0s linear 0.3s;
    }
    .has-js .site-nav.is-open {
        opacity: 1;
        visibility: visible;
        transform: none;
        transition: opacity 0.3s ease, transform 0.3s ease, visibility 0s;
    }
    .has-js .site-nav::-webkit-scrollbar { display: none; }

    /* Surtitre discret en tête. */
    .has-js .site-nav::before {
        content: "Menu";
        align-self: flex-start;
        font-family: var(--font-body);
        font-size: 0.7rem;
        font-weight: 500;
        letter-spacing: 0.26em;
        text-transform: uppercase;
        color: var(--site-soft);
        margin-bottom: 1.4rem;
    }

    /* Liens : serif de titrage MESURÉ, calés à gauche, qui S'ENROULENT (en
       `block` — jamais de flex qui empêcherait le retour à la ligne). Aucun
       filet ; l'espace sépare. Préfixe « .site » pour battre le style de nav du
       thème (sinon MAJUSCULES 0.78rem). */
    .has-js .site .site-nav :where(a) {
        font-family: var(--font-heading);
        font-size: clamp(1.35rem, 1rem + 1.4vw, 1.6rem);
        font-weight: 500;
        line-height: 1.16;
        letter-spacing: -0.01em;
        text-transform: none;
        color: var(--site-ink);
        display: block;
        position: relative;
        padding: 0.5rem 0;
        border: 0;
        white-space: normal;         /* annule le nowrap de base : les libellés s'enroulent */
        overflow-wrap: anywhere;
    }
    .site-nav > a::after, .site-nav__group > a::after { display: none; }

    /* Chevron d'accès au 2e niveau : vrai chevron « › » dessiné aux bordures
       (net, pas le glyphe ▾ minuscule), en absolu à droite, centré verticalement
       (ne casse pas le retour à la ligne du libellé). */
    .has-js .site-nav__group > a { padding-right: 1.8rem; }
    .has-js .site-nav__group > a > span[aria-hidden] {
        position: absolute; right: 0.35rem; top: 50%;
        width: 0.46rem; height: 0.46rem;
        font-size: 0; color: transparent;
        border-top: 1.6px solid color-mix(in srgb, var(--site-ink) 45%, transparent);
        border-right: 1.6px solid color-mix(in srgb, var(--site-ink) 45%, transparent);
        transform: translateY(-50%) rotate(45deg);
    }

    /* Entrée active : fine barre dans la marge gauche (repère UNIQUE et discret,
       pas de filet). */
    .has-js .site-nav > a.is-active,
    .has-js .site-nav__group.is-active > a { color: var(--site-ink); }
    .has-js .site-nav > a.is-active::before,
    .has-js .site-nav__group.is-active > a::before {
        content: ""; position: absolute; left: -0.85rem; top: 50%;
        width: 5px; height: 5px; border-radius: 50%;
        transform: translateY(-50%);
        background: var(--site-ink);
    }

    /* ---- Arrivée : montée + fondu en cascade (expo-out). On n'anime QUE des
       liens et le surtitre — JAMAIS le conteneur .site-nav__group : il doit
       rester « plat » (sans transform/translate) pour que le panneau de niveau 2
       en position:absolute se cale sur le MENU et non sur le petit groupe. ---- */
    .has-js .site-nav > a,
    .has-js .site-nav__group > a,
    .has-js .site-nav::before {
        opacity: 0; translate: 0 0.7rem;
        transition: opacity 0.5s cubic-bezier(0.16, 1, 0.3, 1),
                    translate 0.7s cubic-bezier(0.16, 1, 0.3, 1);
    }
    .has-js .site-nav.is-open > a,
    .has-js .site-nav.is-open .site-nav__group > a,
    .has-js .site-nav.is-open::before { opacity: 1; translate: 0 0; }
    .has-js .site-nav.is-open::before { transition-delay: 0.02s; }
    .has-js .site-nav.is-open > *:nth-child(1),
    .has-js .site-nav.is-open > *:nth-child(1) > a { transition-delay: 0.09s; }
    .has-js .site-nav.is-open > *:nth-child(2),
    .has-js .site-nav.is-open > *:nth-child(2) > a { transition-delay: 0.14s; }
    .has-js .site-nav.is-open > *:nth-child(3),
    .has-js .site-nav.is-open > *:nth-child(3) > a { transition-delay: 0.19s; }
    .has-js .site-nav.is-open > *:nth-child(4),
    .has-js .site-nav.is-open > *:nth-child(4) > a { transition-delay: 0.24s; }
    .has-js .site-nav.is-open > *:nth-child(5),
    .has-js .site-nav.is-open > *:nth-child(5) > a { transition-delay: 0.29s; }
    .has-js .site-nav.is-open > *:nth-child(6),
    .has-js .site-nav.is-open > *:nth-child(6) > a { transition-delay: 0.34s; }
    .has-js .site-nav.is-open > *:nth-child(7),
    .has-js .site-nav.is-open > *:nth-child(7) > a { transition-delay: 0.39s; }
    .has-js .site-nav.is-open > *:nth-child(8),
    .has-js .site-nav.is-open > *:nth-child(8) > a { transition-delay: 0.44s; }

    /* ---- NIVEAU 2 (drill-down avec SLIDE GLOBAL) ------------------------
       Chaque sous-menu devient un PANNEAU plein et OPAQUE, garé hors écran à
       droite (`translateX(100%)`). Taper l'entrée (JS : is-drilled + is-open-sub)
       le fait GLISSER dans le cadre ; « Retour » le renvoie à droite. Enter ET
       exit sont animés (transition de transform). Le groupe reste `static` pour
       que le panneau se cale sur le menu. ---------------------------------- */
    .site-nav__group { display: block; position: static; }
    .has-js .site-nav__sub {
        display: flex; flex-direction: column; align-items: stretch;
        position: absolute; inset: 5.25rem 0 0 0;
        padding: 0 var(--gutter) 2.25rem;
        margin: 0; min-width: 0;
        background: var(--site-bg);
        border: 0; border-radius: 0; box-shadow: none;   /* pas de cadre du flyout desktop */
        overflow-y: auto; overflow-x: hidden;
        z-index: 5;
        transform: translateX(100%);
        visibility: hidden;
        transition: transform 0.44s cubic-bezier(0.16, 1, 0.3, 1), visibility 0s linear 0.44s;
    }
    .has-js .site-nav.is-drilled .site-nav__group.is-open-sub .site-nav__sub {
        transform: translateX(0);
        visibility: visible;
        transition: transform 0.44s cubic-bezier(0.16, 1, 0.3, 1);
    }
    .site-nav__sub::before { display: none; }

    /* En-tête du niveau 2 : « Retour » + titre-lien vers la page complète. */
    .site-nav__l2head {
        display: flex; flex-direction: column; align-items: flex-start;
        gap: 0.1rem; padding-bottom: 0.8rem;
    }
    .site-nav__back {
        display: inline-flex; align-items: center; gap: 0.5rem;
        background: none; border: 0; margin: 0 0 0.2rem; padding: 0.2rem 0; cursor: pointer;
        font-family: var(--font-body); font-size: 0.7rem; font-weight: 500;
        letter-spacing: 0.24em; text-transform: uppercase; color: var(--site-soft);
    }
    .site-nav__back::before { content: "\2190"; font-size: 1.2em; letter-spacing: 0; }
    .site-nav__back:active { color: var(--site-ink); }

    /* Catégories (niveau 2) : PHOTO de la prestation + libellé sur une ligne,
       serif, sans filet, le libellé s'enroule. */
    .has-js .site .site-nav__sub a:not(.site-nav__l2title) {
        display: flex; align-items: center; gap: 0.85rem;
        font-size: clamp(1.05rem, 0.9rem + 0.7vw, 1.25rem);
        color: var(--site-ink);
        padding: 0.45rem 0;
    }
    .has-js .site-nav__sub a:not(.site-nav__l2title) > span {
        min-width: 0; overflow-wrap: anywhere;   /* le libellé passe à la ligne dans le flex */
    }
    .has-js .site-nav__sub a.has-thumb .site-nav__thumb {
        display: block; flex: none;
        width: 3rem; height: 3rem;
        object-fit: cover; border-radius: var(--radius-btn, 9px);
        background: color-mix(in srgb, var(--site-ink) 8%, transparent);
    }
    .has-js .site .site-nav__sub a.is-active { color: var(--site-ink); font-weight: 600; }
    .has-js .site .site-nav__l2title { padding: 0 0 0.4rem; }

    /* ---- CTA « Prendre rendez-vous » : ancré en bas, filet charte + flèche
       animée à la pression (aucun survol sur mobile). ---- */
    .has-js .site-nav a.site-btn {
        margin-top: auto;
        align-self: stretch;
        text-align: center;
        padding-top: 0.95rem;
        padding-bottom: 0.95rem;
        transition: box-shadow 0.3s ease;
    }
    .has-js .site-nav a.site-btn::after {
        content: "\2192"; display: inline-block; margin-left: 0.6rem;
        transition: transform 0.35s cubic-bezier(0.16, 1, 0.3, 1);
    }
    .has-js .site-nav a.site-btn:active::after { transform: translateX(0.4rem); }
    .has-js .site-nav a.site-btn:active {
        box-shadow: inset 0 0 0 200px color-mix(in srgb, var(--site-ink) 8%, transparent);
    }
}

/* Verrou de defilement pendant l'ouverture.
   `html { overflow-y: scroll }` est pose en permanence : sans lui, masquer le
   defilement supprime la barre et decale toute la page d'une quinzaine de
   pixels a l'ouverture du menu. `scrollbar-gutter` ne rattrape pas ce cas sur
   tous les moteurs. */
html { overflow-y: scroll; }
html.has-menu-open { overflow: hidden; }

/* Menu mobile OUVERT : le panneau est un aplat opaque (crème). Les liens et la
   croix doivent donc TOUJOURS être en encre, JAMAIS le blanc « sur-hero » que le
   thème applique en haut de l'accueil (`:has(.hero--image) .site-header:not(.is-stuck)`).
   Sinon, sur l'accueil, le menu s'affiche en blanc sur blanc, et la molette —
   qui bascule is-stuck — fait clignoter les couleurs. `!important` car la règle
   du thème est très spécifique (0,5,0). */
.has-menu-open .site-nav a:not(.site-btn) { color: var(--site-ink) !important; }
.has-menu-open .site-nav__sub a:not(.is-active) { color: var(--site-soft) !important; }
.has-menu-open .site-burger__bar { background: var(--site-ink) !important; }
/* Le bouton d'action du menu = à la CHARTE, comme les autres boutons : fond
   transparent, un filet fin en HAUT et en BAS, texte en encre. On force ces
   valeurs (le thème le passe sinon en blanc sur l'accueil). Le filet dérive de
   l'encre → il suit la charte. */
.has-menu-open .site-nav a.site-btn {
    color: var(--site-ink) !important;
    background: transparent !important;
    border-radius: 0 !important;
    border-top: 1px solid color-mix(in srgb, var(--site-ink) 40%, transparent) !important;
    border-bottom: 1px solid color-mix(in srgb, var(--site-ink) 40%, transparent) !important;
}

@media (max-width: 720px) {
    .site-header__inner { padding: 0.9rem var(--gutter); gap: 0.75rem; }
    /* Écran étroit : titre encore réduit pour laisser respirer le burger. */
    .site-header__inner .site-title { font-size: 1.12rem; }
    .band__inner { padding: var(--rythme-section) var(--gutter); }
    .site-footer__inner { padding: var(--rythme-section) var(--gutter) 2rem; gap: 2rem; }
}

/* --- Moteur de revelation ---------------------------------------------------
   L'etat initial n'est applique que si `bd-anim` est present sur <html>. Cette
   classe est posee par un script inline dans le <head>, donc AVANT le premier
   rendu : sans elle, rien n'est jamais masque. Consequences :
     - pas de JavaScript  -> aucun contenu invisible ;
     - JavaScript present -> pas de flash de contenu deja visible qui
       disparaitrait au demarrage du moteur.
   ---------------------------------------------------------------------------- */
/* Le mouvement d'arrivee passe par les proprietes INDEPENDANTES `translate` et
   `scale` (pas `transform`) : elles se composent nativement avec un `transform`
   de survol (soulevement des cartes, etc.). Sans cela, `is-revealed` forcerait
   `transform:none` avec une specificite superieure et tuerait le :hover.
   Courbe expo-out (0.16,1,0.3,1) : depart franc, fin tres douce — la signature
   « premium » des references (Obsidienne, Beauty Pearl). */
.bd-anim [data-reveal] {
    opacity: 0;
    translate: 0 var(--reveal-y, 2.1rem);
    transition:
        opacity   0.7s cubic-bezier(0.16, 1, 0.3, 1) var(--reveal-delay, 0s),
        translate 0.95s cubic-bezier(0.16, 1, 0.3, 1) var(--reveal-delay, 0s),
        scale     0.95s cubic-bezier(0.16, 1, 0.3, 1) var(--reveal-delay, 0s),
        clip-path 1.05s cubic-bezier(0.16, 1, 0.3, 1) var(--reveal-delay, 0s);
    /* PAS de `will-change` ici : une page a 30+ éléments [data-reveal] ; le poser
       globalement crée autant de couches GPU PERMANENTES → compositeur saturé →
       reveal SACCADÉ (surtout sous Lenis + parallax GSAP). Le navigateur promeut
       de lui-même la couche le temps de la transition opacity/translate. */
}
.bd-anim [data-reveal].is-revealed {
    opacity: 1;
    translate: none;
    scale: none;
}

/* Le moteur de révélation pose sa propre `transition` (opacity/translate/scale)
   qui REMPLACE celle des éléments — pour les cartes c'est ok (leur survol se fait
   en `translate`, déjà couvert), mais `.need-link` (liste des besoins) survole en
   `transform` + border + box-shadow, non couverts → survol INSTANTANÉ. On rétablit
   ces transitions à spécificité supérieure (0,2,1 > 0,2,0) sans casser la
   révélation. */
.bd-anim [data-reveal].need-link {
    transition:
        opacity   0.7s cubic-bezier(0.16, 1, 0.3, 1) var(--reveal-delay, 0s),
        translate 0.95s cubic-bezier(0.16, 1, 0.3, 1) var(--reveal-delay, 0s),
        scale     0.95s cubic-bezier(0.16, 1, 0.3, 1) var(--reveal-delay, 0s),
        border-color 0.2s ease, transform 0.2s ease, box-shadow 0.2s ease;
}

/* Variantes : le mouvement dit quelque chose de l'element. */
.bd-anim [data-reveal="fade"]  { --reveal-y: 0; }
.bd-anim [data-reveal="rise"]  { --reveal-y: 3rem; }
.bd-anim [data-reveal="left"]  { translate: -1.6rem 0; }
.bd-anim [data-reveal="right"] { translate: 1.6rem 0; }

/* Zoom : l'image se pose en se resserrant legerement (echelle 1.06 -> 1). */
.bd-anim [data-reveal="zoom"] { --reveal-y: 0; scale: 1.06; }

/* Volet (mask) : l'image se devoile de bas en haut derriere un cache, avec une
   legere poussee d'echelle — l'effet « rideau » cinematographique des
   references. Pas de fondu (le volet porte l'arrivee) ; le clip-path degrade
   proprement sans JS (etat final = image entiere). */
.bd-anim [data-reveal="mask"] {
    opacity: 1;
    --reveal-y: 0;
    clip-path: inset(100% 0 0 0);
    scale: 1.06;
    /* Le volet est porté par une ANIMATION (voir .is-revealed), pas par la
       transition partagee : on neutralise donc la transition sur ces figures. */
    transition: none;
}
/* Révélé : une ANIMATION (et non une transition) déroule le volet. Une
   transition de clip-path déclenchée avant la première peinture — cas d'une
   figure révélée dès le chargement (en haut de page) — restait « running »
   bloquée à l'état initial, laissant l'IMAGE invisible (clip inset(100%)). Une
   animation a sa propre horloge et COMMIT l'état final (fill: both), donc
   l'image finit toujours visible, que la révélation vienne du chargement ou du
   défilement. */
.bd-anim [data-reveal="mask"].is-revealed {
    animation: bd-mask-reveal 1.05s cubic-bezier(0.16, 1, 0.3, 1) var(--reveal-delay, 0s) both;
}
@keyframes bd-mask-reveal {
    from { clip-path: inset(100% 0 0 0); scale: 1.06; }
    to   { clip-path: inset(0 0 0 0);   scale: 1; }
}
/* Rideau terminé (classe posée par site.js sur `animationend`) : on RETIRE le
   clip-path. Un clip-path résiduel — même `inset(0)`, pourtant sans effet
   visuel — empêche la mise sur couche GPU de la figure : le parallax de l'image
   (scale + translate au défilement) repeint alors tout à chaque trame et
   « saccade » une fois l'image révélée. `clip-path: none` est identique à l'œil
   mais laisse le compositeur travailler. On coupe aussi l'animation pour libérer
   la valeur figée (`fill`), sinon elle l'emporterait sur cette règle. */
.bd-anim [data-reveal="mask"].bd-mask-fini {
    animation: none;
    clip-path: none;
    scale: 1;
}

/* PARALLAX + volet = SCINTILLEMENT. Clipper un cadre dont l'enfant (le calque
   image) est animé en transform par le parallax empêche la mise sur couche GPU :
   si `bd-mask-fini` tarde (animationend peu fiable sous Lenis), le clip-path
   résiduel fait repeindre — donc SCINTILLER — l'image à chaque trame. Sur un
   cadre en parallax, on remplace donc le volet par un simple FONDU, porté par une
   ANIMATION (fill:both → jamais d'image figée invisible) et SANS aucun clip-path,
   pour que le compositeur travaille proprement. */
.bd-anim [data-parallax][data-reveal="mask"] { clip-path: none; animation: none; scale: 1; opacity: 0; }
.bd-anim [data-parallax][data-reveal="mask"].is-revealed {
    animation: bd-fade-in 0.85s cubic-bezier(0.16, 1, 0.3, 1) var(--reveal-delay, 0s) both;
}
@keyframes bd-fade-in { from { opacity: 0; } to { opacity: 1; } }

/* Cascade : `--reveal-i` est pose par le moteur sur les enfants directs d'un
   `[data-reveal-group]`. Le pas reste court — au-dela de ~90ms par element,
   une grille de six cartes se termine apres que le regard soit deja passe. */
.bd-anim [data-reveal-group] > [data-reveal] {
    --reveal-delay: calc(var(--reveal-i, 0) * var(--reveal-step, 70ms));
}

/* Parallax d'image de section : le calque image (surdimensionne) glisse au fil
   du defilement, pilote par motion.js (GSAP). Le conteneur masque le
   debordement ; sans GSAP, l'image reste simplement cadree (aucun trou). */
[data-parallax] { overflow: hidden; }
[data-parallax] > img { display: block; width: 100%; }

/* En-tete condense : la bordure et l'ombre n'apparaissent qu'une fois
   detache du haut de page. */
.site-header { transition: box-shadow 0.25s ease, border-color 0.25s ease; }
.site-header.is-stuck {
    border-bottom-color: transparent;
    box-shadow: 0 1px 2px rgba(0,0,0,0.03), 0 10px 30px -14px rgba(0,0,0,0.22);
}

@media (prefers-reduced-motion: reduce) {
    .site *, .site *::before, .site *::after {
        animation-duration: 0.01ms !important;
        transition-duration: 0.01ms !important;
    }
    .card:hover { transform: none; }
    .site-btn:hover { transform: none; }
    /* Le moteur ne s'arme pas dans ce mode, mais si l'utilisateur active le
       reglage APRES le chargement, rien ne doit rester invisible. Le clip-path
       du volet (mask) est reinitialise aussi, sinon l'image resterait coupee. */
    .bd-anim [data-reveal] { opacity: 1; translate: none; scale: none; transition: none; }
    .bd-anim [data-reveal="mask"], .bd-anim [data-reveal="mask"].is-revealed { clip-path: none; animation: none; scale: 1; }
}

/* ------------------------------------------------------------------ */
/* Fond de section (couleur de la charte) posé au canvas.             */
/* La couleur (var --c-*) est en style inline ; sur fond SOMBRE, on   */
/* force le texte en blanc pour rester lisible. Les cartes gardent    */
/* leur propre surface (elles restent lisibles).                      */
/* ------------------------------------------------------------------ */
.section-band { display: block; }
.section-band--dark { color: #fff; }
.section-band--dark h1, .section-band--dark h2, .section-band--dark h3,
.section-band--dark h4, .section-band--dark p, .section-band--dark li,
.section-band--dark .eyebrow, .section-band--dark .section__title,
.section-band--dark .lead, .section-band--dark blockquote,
.section-band--dark figcaption { color: #fff; }
.section-band--dark a:not(.btn):not(.button) { color: #fff; text-decoration: underline; text-underline-offset: 2px; }
.section-band--dark .section__title::after { background: rgba(255, 255, 255, 0.55); }
.section-band--dark .eyebrow { opacity: 0.9; }

/* ------------------------------------------------------------------ */
/* Message pop-up promotionnel (_promo.php + promo.js).               */
/* 3 types : popup centré, bandeau haut, bandeau bas. Fermeture       */
/* animée + « une fois par session » (sessionStorage côté JS).        */
/* ------------------------------------------------------------------ */
.site-promo[hidden] { display: none; }
.site-promo__title { font-weight: 700; margin: 0 0 0.3rem; }
.site-promo__text { line-height: 1.5; }
.site-promo__text p { margin: 0 0 0.4rem; }

/* Popup centré */
.site-promo--popup { position: fixed; inset: 0; z-index: 1200; display: flex; align-items: center; justify-content: center; padding: 1rem; opacity: 0; transition: opacity .25s ease; }
.site-promo--popup.is-open { opacity: 1; }
.site-promo--popup .site-promo__backdrop { position: absolute; inset: 0; background: rgba(20,22,34,.55); }
.site-promo--popup .site-promo__box { position: relative; background: #fff; color: #23211f; max-width: 460px; width: 100%;
  border-radius: 14px; padding: 1.8rem 1.6rem; box-shadow: 0 24px 70px rgba(0,0,0,.32); text-align: center;
  transform: translateY(8px) scale(.98); transition: transform .25s ease; }
.site-promo--popup.is-open .site-promo__box { transform: none; }
.site-promo--popup .site-promo__title { font-size: 1.25rem; }
.site-promo--popup .site-promo__text { margin: 0.4rem 0 1.2rem; }
.site-promo--popup .site-promo__btn { background: var(--c-primary,#23384c); color: #fff; border: 0; border-radius: 9px;
  padding: 0.6rem 1.6rem; font: inherit; font-weight: 600; cursor: pointer; }
.site-promo--popup .site-promo__btn:hover { filter: brightness(1.08); }

/* Bandeaux haut / bas */
.site-promo--top, .site-promo--bottom { position: fixed; left: 0; right: 0; z-index: 1200;
  background: var(--c-primary,#23384c); color: #fff; transition: transform .35s ease; }
.site-promo--top { top: 0; transform: translateY(-100%); }
.site-promo--top.is-open { transform: translateY(0); }
.site-promo--bottom { bottom: 0; transform: translateY(100%); }
.site-promo--bottom.is-open { transform: translateY(0); }
.site-promo--top .site-promo__box, .site-promo--bottom .site-promo__box {
  display: flex; align-items: center; gap: 1rem; max-width: 1180px; margin: 0 auto; padding: 0.7rem 1.2rem; }
.site-promo--top .site-promo__body, .site-promo--bottom .site-promo__body { flex: 1; min-width: 0; }
.site-promo--top .site-promo__title, .site-promo--bottom .site-promo__title { font-size: 1rem; }
.site-promo--top .site-promo__text, .site-promo--bottom .site-promo__text { font-size: 0.9rem; opacity: .95; }
.site-promo--top .site-promo__btn, .site-promo--bottom .site-promo__btn { flex: 0 0 auto;
  background: rgba(255,255,255,.18); color: #fff; border: 0; border-radius: 8px; padding: 0.42rem 1rem; font: inherit; cursor: pointer; }
.site-promo--top .site-promo__btn:hover, .site-promo--bottom .site-promo__btn:hover { background: rgba(255,255,255,.3); }
@media (max-width: 560px) { .site-promo--top .site-promo__box, .site-promo--bottom .site-promo__box { flex-direction: column; align-items: stretch; gap: 0.5rem; text-align: center; } }
