
  @property --ring-a{ syntax:'<angle>'; inherits:false; initial-value:0deg; }
  :root{
    --black:#0a0a0a;
    --black-soft:#151412;
    --line:#2a2822;
    --gold:#D2AC5A;
    --gold-light:#e8cc8f;
    --cream:#f5f0e6;
    --cream-dim:#c9c2b2;
    /* Curseur loupe personnalisé (remplace l'icône native "zoom-in" du
       système, jugée trop datée graphiquement) : cercle + croix + poignée,
       dans les couleurs du site. Point d'ancrage (13,13) = centre du cercle,
       pour que la loupe soit bien centrée sur le pixel survolé. */
    --zoom-cursor:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='34' height='34' viewBox='0 0 34 34'%3E%3Ccircle cx='13' cy='13' r='9' fill='rgba(21,20,18,.55)' stroke='%23D2AC5A' stroke-width='2'/%3E%3Cline x1='13' y1='8.5' x2='13' y2='17.5' stroke='%23D2AC5A' stroke-width='1.6' stroke-linecap='round'/%3E%3Cline x1='8.5' y1='13' x2='17.5' y2='13' stroke='%23D2AC5A' stroke-width='1.6' stroke-linecap='round'/%3E%3Cline x1='19.5' y1='19.5' x2='27' y2='27' stroke='%23D2AC5A' stroke-width='2.6' stroke-linecap='round'/%3E%3C/svg%3E") 13 13, zoom-in;
  }

  *{margin:0;padding:0;box-sizing:border-box;}
  /* overflow-x + overscroll-behavior-x sur html ET body : sur mobile, un
     léger dépassement horizontal (rubber-band / geste de balayage) suffit à
     décaler le contenu du site et à laisser apparaître par-dessous le calque
     photo en position:fixed (.parallax-band, page d'accueil) — visible sous
     forme de bande sur le bord de l'écran. overscroll-behavior-x:none coupe
     ce rebond élastique horizontal à la source. */
  html{ scroll-behavior:smooth; overflow-x:hidden; overscroll-behavior-x:none; }
  body{
    background:var(--black);
    color:var(--cream);
    font-family:'DM Sans', sans-serif;
    overflow-x:hidden;
    overscroll-behavior-x:none;
  }
  img{max-width:100%;display:block;}
  a{color:inherit;text-decoration:none;}
  /* Texte de paragraphe jugé trop petit sur ordinateur par comparaison à
     d'autres sites (demandé explicitement) — la plupart des paragraphes du
     site n'ont pas de font-size propre et héritent donc des 16px par défaut
     du navigateur. Relevé ici pour les grands écrans uniquement (une classe
     de paragraphe qui fixe déjà sa propre taille, ex. .flip-desc dans les
     flip-cards, garde la sienne — plus spécifique, prioritaire sur ce
     réglage de base). */
  @media(min-width:801px){
    p{ font-size:16px; } /* aligné sur la norme mesurée (stessygrabias.com et autres sites du secteur, 15-20px) */
  }

  .eyebrow{
    font-family:'DM Sans',sans-serif;
    font-size:.75rem;
    letter-spacing:.28em;
    text-transform:uppercase;
    color:var(--gold);
    font-weight:600;
  }

  h1,h2,h3{font-family:'Playfair Display',serif; font-weight:700; line-height:1.05;}

  .btn{
    display:inline-flex;
    align-items:center;
    gap:.6rem;
    padding:.9rem 2rem;
    border:1px solid var(--gold);
    color:var(--cream);
    font-size:.85rem;
    letter-spacing:.1em;
    text-transform:uppercase;
    font-weight:600;
    transition:.35s ease;
    background:transparent;
  }
  .btn:hover{background:var(--gold); color:var(--black);}
  .btn-solid{background:var(--gold); color:var(--black);}
  .btn-solid:hover{background:var(--gold-light);}

  /* --- Bouton d'envoi du formulaire --- */
  .send-btn .send-icon{display:inline-flex; flex:0 0 auto;}

  /* --- Barre de progression (façon téléchargement de fichier) pendant l'envoi --- */
  .send-progress-card{
    display:none;
    margin-top:1rem;
    padding:1rem 1.1rem;
    border:1px solid var(--line);
    background:var(--black-soft);
  }
  .send-progress-card.show{display:block;}
  .send-progress-head{
    display:flex; justify-content:space-between; align-items:baseline;
    margin-bottom:.6rem;
    font-family:'DM Sans',sans-serif; font-size:.85rem;
    color:var(--cream);
  }
  .send-progress-head strong{font-weight:600;}
  .send-progress-head span.pct{color:var(--cream-dim); font-size:.8rem;}
  .send-progress-track{
    height:6px;
    background:var(--line);
    overflow:hidden;
  }
  .send-progress-fill{
    height:100%; width:0%;
    background:#6C8CFF;
    transition:width .25s ease;
  }
  @media(prefers-reduced-motion:reduce){
    .send-progress-fill{transition:none;}
  }

  /* ============ HEADER ============ */
  header{
    position:fixed; top:0; left:0; width:100%;
    z-index:1000;
    display:flex; align-items:center; justify-content:space-between;
    padding:1.1rem 4vw;
    gap:1.5rem;
    /* Bandeau (fond + flou + bordure) transparent tant qu'on est en haut de
       page — n'apparaît qu'au premier scroll via .header-scrolled (déjà
       posée en JS, scrollY > 12). Le contenu du header (logo, menu, boutons)
       n'est pas concerné, seul le fond change. */
    background:rgba(10,10,10,0);
    backdrop-filter:none;
    border-bottom:1px solid transparent;
    box-shadow:none;
    transition:background .9s ease, backdrop-filter .9s ease, border-color .9s ease, box-shadow .5s ease;
    /* Sur Chrome Android, un position:fixed combiné à backdrop-filter peut se
       décaler/se faire couper pendant le scroll quand la barre d'adresse se
       replie (désync entre le viewport visuel et le viewport de mise en
       page) — le header semble alors "remonter" tout seul. Promouvoir le
       header sur sa propre couche GPU force le navigateur à le repositionner
       correctement par rapport au viewport plutôt que de le laisser dériver.
       Toujours actif (pas seulement une fois .header-scrolled posée) : le
       jank visé se produit potentiellement dès le tout début du scroll. */
    transform:translateZ(0);
    -webkit-transform:translateZ(0);
    backface-visibility:hidden;
    -webkit-backface-visibility:hidden;
  }
  header.header-scrolled{
    background:rgba(10,10,10,.72);
    backdrop-filter:blur(10px);
    border-bottom:1px solid rgba(210,172,90,.15);
  }
  header.header-scrolled{
    box-shadow:0 12px 24px -12px rgba(0,0,0,.55);
  }
  @media(max-width:820px){
    /* Historique (essais précédents, tous écartés) : position:fixed classique
       masquait/coupait le logo pendant le repli de la barre d'adresse ;
       position:sticky faisait carrément disparaître le header ; un pilotage
       JS en position:absolute (top puis transform, sur scroll puis sur une
       boucle requestAnimationFrame) réglait le positionnement mais restait
       perceptiblement saccadé — un header repositionné à la main en JS reste
       toujours un cran derrière le rendu natif du navigateur.
       Retour à position:fixed natif, sans AUCUN bricolage (pas de translateZ,
       pas de calque forcé) : c'est la configuration la plus simple possible,
       celle que Chrome gère nativement sur son thread de composition (donc
       sans saccade). Le flou est retiré (voir plus haut le comportement
       backdrop-filter+fixed) et remplacé par un fond plus opaque.
       Transparent tant qu'on est en haut (demandé explicitement, même
       principe que sur ordinateur) : toujours SANS flou ni translateZ ici,
       volontairement — c'est justement leur combinaison avec position:fixed
       qui causait le jank écarté ci-dessus ; seule la couleur de fond
       s'anime, rien d'autre. */
    header{
      position:fixed;
      backdrop-filter:none;
      -webkit-backdrop-filter:none;
      background:rgba(8,8,8,0);
      transition:background .5s ease;
      transform:none;
      -webkit-transform:none;
      backface-visibility:visible;
      -webkit-backface-visibility:visible;
    }
    header.header-scrolled{
      background:rgba(8,8,8,.94);
    }
  }

  /* ============ PROPOSITION PLEIN ÉCRAN (page d'accueil) ============
     Refonte demandée explicitement (le bandeau plein largeur précédent ne
     plaisait pas) : un simple texte + icône, discret, en bas de l'écran,
     qui arrive UNE FOIS la page bien installée (après la dernière animation
     d'entrée : les icônes du header, la plus tardive à ~7.2s — voir
     .header-icon-seq) plutôt qu'immédiatement au chargement. Disparaît au
     premier scroll si le visiteur n'a pas cliqué dessus (JS). Desktop
     uniquement : le header est déjà en position:fixed;top:0 (historique
     fragile, voir plus haut) donc on évite d'y toucher, et le manque de
     place signalé était sur ordinateur, pas mobile. */
  /* Un seul petit encadré (demandé explicitement) : texte à gauche, icône à
     droite, tous deux à l'intérieur du même cadre. bottom:6rem (pas 2rem) :
     le chevron "défiler vers le bas" du hero (.hero-scroll-chevron) est
     positionné vers bottom:1.8rem, quasi au même endroit — l'encadré le
     cachait complètement, signalé explicitement. */
  .fs-hint{
    position:fixed; left:50%; bottom:6rem; z-index:1001;
    transform:translate(-50%, calc(100% + 2rem));
    opacity:0;
    transition:transform .6s cubic-bezier(.16,1,.3,1), opacity .5s ease;
    display:flex; flex-direction:row; align-items:center; gap:.45rem;
    padding:.45rem .65rem .45rem .85rem;
    background:rgba(10,10,10,.8);
    backdrop-filter:blur(10px); -webkit-backdrop-filter:blur(10px);
    border:1px solid rgba(210,172,90,.4);
    border-radius:999px;
    color:var(--cream);
    font-family:inherit; font-size:.52rem;
    white-space:nowrap;
    cursor:pointer;
    pointer-events:none;
  }
  .fs-hint.fs-shown{ transform:translate(-50%, 0); opacity:1; pointer-events:auto; }
  .fs-hint-icon{
    display:flex; align-items:center; justify-content:center;
    width:22px; height:22px; border-radius:50%;
    border:1px solid rgba(210,172,90,.4);
  }
  .fs-hint-icon svg{ width:11px; height:11px; }
  /* Icône expand/compress selon l'état réel (voir JS, fullscreenchange) —
     sert de bouton "quitter" une fois actif : indispensable sur mobile,
     où l'icône du header est masquée en dessous de 560px (pas de place,
     voir plus haut) et où il n'y a donc plus que cette invite pour sortir
     du plein écran. */
  .fs-icon-compress{ display:none; }
  .fs-hint.fs-active .fs-icon-expand{ display:none; }
  .fs-hint.fs-active .fs-icon-compress{ display:block; }
  /* Même bascule expand/compress sur l'icône du header (.is-active posée
     en JS sur fullscreenchange). */
  .fullscreen-btn.is-active .fs-icon-expand{ display:none; }
  .fullscreen-btn.is-active .fs-icon-compress{ display:block; }
  /* Surbrillance dorée pendant que le plein écran est actif (demandé
     explicitement) : seul repère visuel une fois l'invite du bas repartie
     (qui ne sert plus qu'à entrer, pas à indiquer l'état) — sert aussi de
     bouton "quitter". */
  .fullscreen-btn.is-active{ background:var(--gold); border-color:var(--gold); color:var(--black); }
  .fullscreen-btn.is-active .btn-ring{ display:none; }
  /* Invite "reprendre le plein écran" sur la nouvelle page après un
     changement de page depuis une page en plein écran (voir JS,
     sessionStorage) : un halo doré qui pulse, pour attirer l'œil tout de
     suite sur ce bouton plutôt que de laisser deviner où re-cliquer —
     seule façon d'approcher une transition "invisible", un navigateur ne
     permet jamais de réactiver le plein écran sans clic. */
  @keyframes fsResumePulse{
    0%,100%{ box-shadow:0 0 0 0 rgba(210,172,90,.55); }
    50%{ box-shadow:0 0 0 7px rgba(210,172,90,0); }
  }
  .fullscreen-btn.fs-resume-pulse{
    border-color:var(--gold);
    animation:fsResumePulse 1.4s ease-in-out infinite;
  }
  .fs-hint:hover{ border-color:var(--gold); color:var(--gold); }
  .fs-hint:hover .fs-hint-icon{ border-color:var(--gold); }
  /* Plus limité au bureau (demandé explicitement) : le plein écran
     fonctionne aussi sur mobile/tablette (Android en tout cas), donc
     l'invite y est proposée aussi. */
  @media(max-width:480px){
    .fs-hint{ font-size:.48rem; padding:.4rem .55rem .4rem .7rem; }
  }

  .logo-block{ min-width:0; flex:1 1 auto; }
  .logo-sig{
    font-family:'Rock Salt', cursive;
    font-size:clamp(.975rem, 2.925vw, 1.365rem);
    color:var(--gold);
    line-height:1;
  }
  .logo-sub{
    display:block;
    font-family:'DM Sans',sans-serif;
    font-size:.58rem;
    letter-spacing:.08em;
    text-transform:uppercase;
    color:var(--cream-dim);
    margin-top:.15rem;
    white-space:nowrap;
    overflow:hidden;
    text-overflow:ellipsis;
  }
  /* Accueil uniquement (scope à la séquence du hero) : apparaît en dernier,
     lettre par lettre — même mécanique que le label "Nom & prénom" du
     formulaire de contact (.fl-char, délai par caractère via --i), rejouée
     ici en keyframes plutôt qu'en transition déclenchée par une classe
     .floated, puisqu'il n'y a pas d'état "replié" à quitter ici. */
  .logo-sub .fl-char{
    display:inline-block;
    opacity:0;
    transform:translateY(12px);
    animation:logoSubCharIn .4s cubic-bezier(.34,1.56,.64,1) forwards;
    animation-delay:calc(3.6s + var(--i, 0) * 25ms);
  }
  @keyframes logoSubCharIn{
    to{ opacity:1; transform:translateY(0); }
  }
  /* Suite de la séquence (accueil, écran large seulement — .cta-long n'est
     visible qu'à partir de 901px, voir plus bas) : "Demander un devis"
     lettre par lettre juste après le sous-titre, puis téléphone/mail/
     partage/burger un par un. */
  .header-cta .fl-char{
    display:inline-block;
    opacity:0;
    transform:translateY(10px);
    animation:logoSubCharIn .35s cubic-bezier(.34,1.56,.64,1) forwards;
    animation-delay:calc(5s + var(--i, 0) * 25ms);
  }
  .header-icon-seq{
    opacity:0;
    transform:translateY(-8px);
    animation:headerIconIn .4s ease forwards;
    animation-delay:calc(6s + var(--i, 0) * .2s);
  }
  @keyframes headerIconIn{
    to{ opacity:1; transform:translateY(0); }
  }
  @media(min-width:561px){
    .logo-sub{ font-size:16px; }
  }
  .header-actions{
    display:flex; align-items:center; gap:.7rem;
    flex:0 0 auto;
    z-index:1100;
  }
  .header-cta{
    display:inline-flex; align-items:center;
    padding:.6rem 1.3rem;
    background:transparent;
    color:var(--cream);
    font-size:.78rem;
    letter-spacing:.08em;
    text-transform:uppercase;
    font-weight:600;
    border:1px solid transparent;
    border-radius:999px;
    transition:color .3s ease;
    white-space:nowrap;
    position:relative;
  }
  .header-cta > span{ position:relative; z-index:1; }
  .header-cta::after{
    content:'';
    position:absolute; inset:-1.4px;
    border:1.4px solid var(--gold);
    border-radius:999px;
    pointer-events:none;
    --ring-a:0deg;
    transition:--ring-a .6s ease;
    -webkit-mask-image:conic-gradient(from 180deg, #000 var(--ring-a, 0deg), transparent 0);
    mask-image:conic-gradient(from 180deg, #000 var(--ring-a, 0deg), transparent 0);
  }
  .header-cta:hover::after{ --ring-a:360deg; }
  .header-cta:hover{ color:var(--gold); }
  .cta-short{ display:none; }
  @media(max-width:900px){
    .header-cta{ padding:.55rem 1rem; font-size:.7rem; letter-spacing:.05em; }
    .cta-long{ display:none; }
    .cta-short{ display:inline; }
  }
  @media(max-width:560px){
    /* Plutôt que de masquer le sous-titre pour tenir sur une seule ligne
       étroite (ce qui faisait aussi passer "Gwendal Larher" lui-même sur 2
       lignes, faute de place), le bandeau du header s'agrandit vers le bas :
       le bloc logo prend toute la largeur sur sa propre ligne, les icônes
       d'action suivent sur la ligne du dessous. Tout reste lisible sur une
       seule ligne chacun. */
    header{ flex-wrap:wrap; row-gap:.7rem; padding-top:.9rem; padding-bottom:.9rem; }
    .logo-block{ flex:1 1 100%; }
    .logo-sig{ white-space:nowrap; }
    .header-actions{ width:100%; justify-content:space-between; gap:.4rem; }
    /* Léger réajustement (demandé explicitement) : icônes un peu plus
       petites pour que le bord droit de la ligne d'actions retombe
       proprement sous le hamburger (juste au-dessus), comme le bord gauche
       retombe sous "Gwendal Larher". */
    .header-actions .header-icon-btn{ width:34px; height:34px; }
    .header-actions .btn-ring{ width:34px; height:34px; }
    /* La ligne d'actions a maintenant toute la largeur pour elle : le texte
       complet du bouton tient très bien, pas besoin de la version courte
       "Devis" — et le bouton s'étire pour équilibrer visuellement la ligne
       avec les icônes rondes. */
    .header-cta{ flex:1 1 auto; justify-content:center; padding:.6rem .9rem; font-size:.72rem; }
    .cta-long{ display:inline; }
    .cta-short{ display:none; }
    /* Hamburger remonté sur la ligne du logo (demandé explicitement) :
       sorti du flux normal de .header-actions (position:absolute, ancré sur
       <header> lui-même, déjà position:fixed donc déjà un contexte de
       positionnement) — ça libère aussi la place qui manquait en dessous
       pour les 5 icônes + le bouton Devis (le hamburger seul suffisait à
       tout faire déborder, écrasé à 0px de large auparavant), donc plus
       besoin de masquer l'icône plein écran ici. */
    .burger{ position:absolute; top:.9rem; right:4vw; }
  }
  .header-icon-btn{
    width:38px; height:38px;
    display:flex; align-items:center; justify-content:center;
    border:1px solid #fff;
    border-radius:50%;
    background:transparent;
    color:#fff;
    font:inherit;
    cursor:pointer;
    transition:color .3s ease;
    flex:0 0 auto;
    position:relative;
  }
  .btn-ring{
    position:absolute;
    top:-1px; left:-1px;
    width:38px; height:38px;
    transform:rotate(90deg);
    pointer-events:none;
  }
  .btn-ring circle{
    fill:none;
    stroke:var(--gold);
    stroke-width:1.4;
    stroke-dasharray:113;
    stroke-dashoffset:113;
    transition:stroke-dashoffset .6s ease;
  }
  .header-icon-btn svg:not(.btn-ring){ position:relative; z-index:1; }
  /* @media(hover:hover) : sur tactile, un tap peut activer un :hover
     "collé" (déjà rencontré avec les flip-cards) — sans cette garde, la
     bordure blanche pouvait disparaître après un simple tap sur mobile,
     restant sur son état survolé au lieu de rester blanche par défaut. */
  @media(hover:hover){
    .header-icon-btn:hover{ border-color:transparent; }
    .header-icon-btn:hover .btn-ring circle{ stroke-dashoffset:0; }
  }
  .header-icon-btn.disabled{
    color:var(--cream-dim);
    opacity:.65;
  }
  .header-share-note{
    position:absolute;
    top:calc(100% + .6rem);
    right:0;
    padding:.5rem .9rem;
    background:var(--black-soft);
    border:1px solid var(--gold);
    color:var(--gold);
    font-family:'DM Sans',sans-serif;
    font-size:.75rem;
    letter-spacing:.03em;
    white-space:nowrap;
    opacity:0;
    transform:translateY(-4px);
    pointer-events:none;
    transition:opacity .25s ease, transform .25s ease;
  }
  .share-btn.copied .header-share-note{
    opacity:1;
    transform:translateY(0);
  }
  /* Bouton téléphone sur ordinateur/tablette : au clic, affiche le numéro
     en gras juste sous l'icône, lettre par lettre en cascade (même
     animation .fl-char que le label "Nom & prénom" du formulaire de
     contact), au lieu de tenter un appel qui n'a pas de sens sans
     téléphonie — demandé explicitement, header et menu hamburger. Sur
     mobile, le lien tel: garde son comportement normal (voir script.js,
     condition sur la largeur d'écran). */
  .phone-reveal{
    position:absolute;
    top:calc(100% + .5rem);
    right:0;
    font-family:'DM Sans',sans-serif;
    font-weight:700;
    font-size:.85rem;
    letter-spacing:.04em;
    white-space:nowrap;
    pointer-events:none;
  }
  /* Header : bulle alignée à droite du bouton (grandit vers la gauche, côté
     "Demander un devis" — de la place). Menu hamburger : l'icône téléphone
     est la première (tout à gauche) de la rangée, donc alignée à gauche du
     bouton ici pour grandir vers la droite plutôt que déborder du panneau. */
  .nav-icon-row .phone-reveal{ left:0; right:auto; }
  .phone-reveal .fl-char{
    display:inline-block;
    color:var(--cream-dim);
    opacity:0;
    transform:translateY(10px);
    transition:transform .4s cubic-bezier(.34,1.56,.64,1), opacity .4s ease, color .4s ease;
    transition-delay:calc(var(--i, 0) * 40ms);
  }
  .phone-link.revealed .phone-reveal .fl-char{
    opacity:1;
    transform:translateY(0);
    color:var(--gold);
  }
  .burger{
    width:38px;height:38px;
    display:flex; flex-direction:column; justify-content:center; gap:6px;
    cursor:pointer; background:none; border:none; z-index:1100;
  }
  .burger span{
    display:block; height:1.5px; width:100%; background:var(--cream);
    transition:.35s ease;
  }
  .burger.open span:nth-child(1){transform:translateY(7.5px) rotate(45deg); background:var(--gold);}
  .burger.open span:nth-child(2){opacity:0;}
  .burger.open span:nth-child(3){transform:translateY(-7.5px) rotate(-45deg); background:var(--gold);}

  /* header{z-index:1000} est SOUS le panneau plein (.nav-overlay:2100) et
     son voile (.nav-dim:2099) : un enfant du header a beau porter un
     z-index élevé, il ne peut jamais dépasser un frère du header lui-même
     (contexte d'empilement) — sur mobile, où le panneau fait 100% de large,
     ça recouvrait entièrement le burger, rendant la croix invisible et
     impossible à cliquer pour refermer. On fait donc passer le header
     entier au-dessus, seulement pendant que le menu est ouvert. */
  /* header.menu-open passe aussi son propre fond à transparent : sinon,
     une fois la page scrollée (.header-scrolled = fond noir translucide +
     flou), ce fond restait visible par-dessus les tout premiers liens du
     panneau (Accueil, Collectivités) — repéré sur mobile en conditions
     réelles, ces liens apparaissaient flous/inaccessibles sous le bandeau
     du header alors qu'ils étaient bien là, juste recouverts. */
  header.menu-open{
    z-index:2200;
    background:transparent !important;
    backdrop-filter:none !important;
    border-bottom-color:transparent !important;
    box-shadow:none !important;
    /* Même invisible, le header restait au-dessus du panneau (z-index 2200)
       et continuait donc à intercepter la souris sur toute sa hauteur —
       ça empêchait de survoler Accueil/Collectivités juste en dessous.
       On neutralise les clics/survols sur le header entier, sauf le
       burger (croix de fermeture) qui doit rester cliquable. */
    pointer-events:none;
  }
  header.menu-open .burger{ pointer-events:auto; }

  /* Le reste du header (logo, devis, téléphone, mail, partage) disparaît
     tout de suite à l'ouverture du menu — seul le burger (qui devient la
     croix pour fermer) doit rester visible pendant que le panneau glisse.
     .header-icon-seq:not(.burger) couvre téléphone/mail/partage en une
     fois (le lien mail n'a pas d'id propre) ; !important est nécessaire
     car l'animation d'apparition au chargement (voir .header-icon-seq plus
     bas, animation-fill-mode:forwards) fixe opacity:1 une fois terminée —
     une déclaration normale ne peut pas la surpasser, seule une règle
     !important (ou une autre animation) le peut. */
  header.menu-open .logo-block,
  header.menu-open .header-cta,
  header.menu-open .header-icon-seq:not(.burger){
    opacity:0 !important;
    pointer-events:none;
    transition:opacity .15s ease;
  }

  /* Couche supplémentaire, discrète, qui assombrit légèrement le reste de
     l'écran en diagonale (comme ".overlay-nav" sur myet-art.fr, 50%
     d'opacité) — élément séparé du panneau car "position:fixed" à
     l'intérieur d'un parent transformé (le panneau glisse via transform)
     se recale sur ce parent au lieu du viewport. */
  .nav-dim{
    position:fixed; top:0; right:0; height:100%;
    width:calc(100% + 400px);
    background:#000;
    opacity:.25;
    z-index:2099;
    transform:translateX(-100%) skewX(-20deg);
    /* Démarre après le panneau plein (voir .nav-overlay, sans délai) :
       la diagonale opaque arrive en premier, le voile transparent la
       suit avec son propre décalage, comme une seconde vague séparée. */
    transition:transform .6s ease .3s;
    pointer-events:none;
  }
  .nav-dim.open{ transform:translateX(200px) skewX(-20deg); }

  /* Panneau plein qui glisse depuis la gauche (comme "nav" sur myet-art.fr),
     plus un ::before qui prolonge le noir au-delà du panneau en diagonale
     nette — angle et dimensions copiés exactement sur myet-art.fr
     (skewX(-20deg), largeur 350px, translateX(50%)), mesurés directement
     dans son CSS via javascript_exec plutôt qu'estimés à l'oeil. */
  .nav-overlay{
    position:fixed; top:0; left:0; height:100%;
    width:100%; max-width:560px;
    background:var(--black);
    /* Sur grand écran, 560px fixe laisse la diagonale trop collée à
       gauche : au-delà de 820px de large, le panneau prend la moitié de
       l'écran pour que la coupure diagonale tombe au centre. */
    z-index:2100; /* au-dessus de .lightbox (z-index:2000) : sinon, ouvrir le menu
                     pendant qu'une photo est en plein écran ne montrait que le
                     haut du menu, le reste passant derrière la visionneuse */
    /* -100% ne cache que le panneau lui-même : le ::before (taillé plus
       large, décalé vers la droite) dépasse encore de la largeur du
       panneau et resterait visible à l'écran une fois "fermé" sans la
       marge supplémentaire ci-dessous. */
    transform:translateX(calc(-100% - 900px));
    transition:transform .5s ease;
    pointer-events:none;
  }
  @media(min-width:821px){
    .nav-overlay{ max-width:30vw; }
  }
  .nav-overlay.open{
    transform:translateX(0);
    pointer-events:auto;
  }
  /* .nav-scroll : conteneur interne qui porte le flex + le scroll vertical,
     séparé de .nav-overlay lui-même — demandé explicitement pour corriger un
     bug constaté où overflow-y:auto posé directement sur .nav-overlay
     (l'élément qui porte aussi le ::before diagonal) force implicitement
     overflow-x:auto (règle CSS : dès qu'un axe overflow n'est pas "visible",
     l'autre axe resté "visible" est recalculé en "auto"), ce qui rognait le
     débord du ::before au-delà du panneau et transformait la découpe
     diagonale en un bord vertical droit sur certains navigateurs. En
     déplaçant le scroll sur cet enfant, .nav-overlay reste overflow:visible
     et le ::before peut déborder librement. */
  .nav-scroll{
    position:relative; z-index:1;
    height:100%; width:100%;
    display:flex; flex-direction:column; align-items:flex-start; justify-content:flex-start;
    gap:1.5rem;
    padding-left:clamp(2rem,7vw,4rem);
    padding-right:3.5rem;
    padding-top:1.5rem;
    padding-bottom:1.5rem;
    overflow-y:auto;
    scrollbar-width:none; -ms-overflow-style:none;
  }
  .nav-scroll::-webkit-scrollbar{ display:none; width:0; height:0; }
  .nav-overlay::before{
    content:'';
    position:absolute; top:0; right:0;
    width:350px; height:100%;
    background:var(--black);
    transform:translateX(50%) skewX(-20deg);
    z-index:0;
  }
  .nav-overlay a{
    font-family:'Playfair Display',serif;
    font-size:clamp(1.1rem,1.3vw,1.35rem);
    font-weight:700;
    text-transform:uppercase;
    letter-spacing:.04em;
    color:var(--cream);
    text-shadow:0 1px 2px rgba(0,0,0,.5), 0 2px 10px rgba(0,0,0,.35);
    position:relative;
    z-index:1;
    opacity:0;
    transform:translateY(16px);
    transition:color .3s, transform .55s cubic-bezier(.16,.84,.44,1), opacity .55s ease;
  }
  .nav-overlay a:hover{color:var(--gold);}
  /* Effet "balayage" au survol, copié sur myet-art.fr : un double du texte
     (attr(data-text), même contenu que le lien) posé en doré sur fond noir,
     révélé de gauche à droite via width:0%→100% + overflow:hidden — demandé
     explicitement, à l'identique du site de référence. */
  .nav-overlay a::after{
    content:attr(data-text);
    position:absolute; top:0; left:0;
    color:var(--gold); background:var(--black);
    width:0%; height:100%; overflow:hidden;
    white-space:nowrap;
    transition:.65s ease;
  }
  .nav-overlay a:hover::after{ width:100%; }
  /* Balayage retiré sur les sous-liens (Extérieurs/Intérieurs/Espaces
     piscine) — trop capricieux à cette taille de texte malgré plusieurs
     ajustements. Remplacé par la même animation "lettre par lettre" que le
     label flottant du formulaire de contact (Nom & prénom, etc., voir
     .form-field.floating-label .fl-char), mais déclenchée à l'ouverture du
     sous-menu (.nav-item.is-open) et non au survol — demandé explicitement :
     chaque lettre apparaît en cascade, pas de retour au survol. */
  .nav-submenu a::after{ display:none; }
  .nav-submenu a .fl-char{
    display:inline-block;
    opacity:0;
    transform:translateY(8px);
    transition:transform .4s cubic-bezier(.34,1.56,.64,1), opacity .4s ease;
    transition-delay:calc(var(--i, 0) * 50ms);
  }
  .nav-item.is-open .nav-submenu a .fl-char{
    opacity:1;
    transform:translateY(0);
  }
  @media(prefers-reduced-motion:reduce){
    .nav-submenu a .fl-char{transition:none;}
  }
  /* Bouton "Demander un devis" : fond plein doré, donc ni le balayage
     ::after (boîte noire qui glissait par-dessus) ni le survol doré du
     texte (invisible sur fond doré) n'ont de sens ici — retiré. */
  .nav-overlay a.nav-devis::after{ display:none; }
  .nav-overlay a.nav-devis:hover{ color:#0a0a0a; }
  /* Icônes tel/mail (des <a>, donc elles héritaient aussi du balayage
     ::after) : boîte invisible en temps normal (width:0%) mais qui
     interférait avec l'anneau doré au survol/à l'ouverture du menu — sans
     rapport avec ces icônes rondes, retiré. Le bouton "partage" (un
     <button>) n'était jamais concerné, d'où l'anneau correct sur lui seul. */
  .nav-overlay .nav-icon-row .header-icon-btn::after{ display:none; }
  /* Numéro masqué dans le menu — demandé explicitement (les 3 icônes
     tel/mail/partage juste en dessous suffisent). */
  .nav-overlay .nav-tel{ display:none; }
  /* Signature "Gwendal Larher" (même typo que .logo-sig du header) au-dessus
     de la rangée d'icônes tel/mail/partage (mêmes boutons que le header,
     .header-icon-btn) juste en dessous - demandé explicitement.
     Largeur alignée sur celle du bouton "Demander un devis" (221px, sa
     largeur naturelle est fixe car son padding/texte ne dépend pas de la
     largeur du panneau) au lieu de s'étirer sur toute la largeur — demandé
     explicitement. Cascade d'apparition identique aux liens ci-dessus
     (transition sur .open, pas l'animation à délai fixe du header qui ne
     rejouerait jamais à l'ouverture du menu). */
  .nav-overlay .nav-signature{
    align-self:flex-start;
    width:221px;
    font-family:'Rock Salt', cursive;
    font-size:1.1rem;
    color:var(--gold);
    position:relative;
    z-index:1;
    margin-top:0;
    padding-top:.7rem;
    border-top:1px solid rgba(255,255,255,.14);
    opacity:0;
    transform:translateY(16px);
    transition:opacity .55s ease, transform .55s cubic-bezier(.16,.84,.44,1);
  }
  /* Sous-titre sous la signature, même largeur (221px). Marge négative :
     .nav-scroll applique déjà un gap:1.5rem entre tous ses enfants directs
     (signature/sous-titre/icônes en font partie), ce qui donnait un écart
     bien plus grand que le reste du menu une fois cumulé avec margin-top —
     on retranche donc ce gap hérité pour revenir à un espacement resserré,
     cohérent avec le style au-dessus — demandé explicitement. */
  .nav-overlay .nav-signature-sub{
    display:block;
    align-self:flex-start;
    width:221px;
    font-family:'DM Sans',sans-serif;
    font-size:.7rem;
    line-height:1.5;
    letter-spacing:.03em;
    color:var(--cream-dim);
    position:relative;
    z-index:1;
    margin-top:calc(.35rem - 1.5rem);
    opacity:0;
    transform:translateY(16px);
    transition:opacity .55s ease, transform .55s cubic-bezier(.16,.84,.44,1);
  }
  /* Icônes agrandies (48px au lieu de 38px) et rangée alignée sur la même
     largeur que "Demander un devis" (221px, cf. .nav-signature ci-dessus),
     réparties avec justify-content:space-between plutôt qu'un gap fixe —
     demandé explicitement. Marge négative pour la même raison que
     .nav-signature-sub ci-dessus (retrancher le gap hérité de .nav-scroll). */
  .nav-overlay .nav-icon-row{
    align-self:flex-start;
    width:221px;
    display:flex;
    justify-content:space-between;
    margin-top:calc(.7rem - 1.5rem);
    position:relative;
    z-index:1;
  }
  .nav-overlay .nav-icon-row .header-icon-btn{
    width:48px; height:48px;
    opacity:0;
    transform:translateY(16px);
    transition:opacity .55s ease, transform .55s cubic-bezier(.16,.84,.44,1), color .3s ease;
  }
  .nav-overlay .nav-icon-row .header-icon-btn .btn-ring{ width:48px; height:48px; }
  .nav-overlay .nav-icon-row .header-icon-btn svg:not(.btn-ring){ width:22px; height:22px; }
  .nav-overlay.open .nav-signature,
  .nav-overlay.open .nav-signature-sub,
  .nav-overlay.open .nav-icon-row .header-icon-btn{
    opacity:1;
    transform:translateY(0);
  }
  .nav-overlay.open .nav-signature{transition-delay:.66s;}
  .nav-overlay.open .nav-signature-sub{transition-delay:.72s;}
  .nav-overlay.open .nav-icon-row .header-icon-btn:nth-child(1){transition-delay:.84s;}
  .nav-overlay.open .nav-icon-row .header-icon-btn:nth-child(2){transition-delay:.90s;}
  .nav-overlay.open .nav-icon-row .header-icon-btn:nth-child(3){transition-delay:.96s;}
  /* Apparition des liens en cascade, un par un, du haut vers le bas — le
     transition-delay n'existe QUE sur l'état .open : à la fermeture, tout
     redisparaît d'un coup (pas de cascade inversée), comme sur myet-art.fr. */
  .nav-overlay.open a,
  .nav-overlay.open .nav-item,
  .nav-overlay.open .nav-tel{
    opacity:1;
    transform:translateY(0);
  }
  .nav-overlay.open a:nth-child(2), .nav-overlay.open .nav-item:nth-child(2){transition-delay:.06s;}
  .nav-overlay.open a:nth-child(3), .nav-overlay.open .nav-item:nth-child(3){transition-delay:.12s;}
  .nav-overlay.open a:nth-child(4), .nav-overlay.open .nav-item:nth-child(4){transition-delay:.18s;}
  .nav-overlay.open a:nth-child(5), .nav-overlay.open .nav-item:nth-child(5){transition-delay:.24s;}
  .nav-overlay.open a:nth-child(6), .nav-overlay.open .nav-item:nth-child(6){transition-delay:.30s;}
  .nav-overlay.open a:nth-child(7), .nav-overlay.open .nav-item:nth-child(7){transition-delay:.36s;}
  .nav-overlay.open a:nth-child(8), .nav-overlay.open .nav-item:nth-child(8){transition-delay:.42s;}
  .nav-overlay.open a:nth-child(9), .nav-overlay.open .nav-item:nth-child(9){transition-delay:.48s;}
  .nav-overlay.open a:nth-child(10), .nav-overlay.open .nav-item:nth-child(10){transition-delay:.54s;}
  .nav-overlay.open a:nth-child(11), .nav-overlay.open .nav-item:nth-child(11){transition-delay:.60s;}
  .nav-overlay.open a:nth-child(12), .nav-overlay.open .nav-item:nth-child(12){transition-delay:.66s;}
  /* Sous-menu "Particuliers" (Extérieurs / Intérieurs / Espaces piscine) :
     accordéon compact (police et interlignage réduits par rapport aux
     entrées principales) pour que l'ouverture ne déclenche jamais de barre
     de scroll verticale sur .nav-scroll, demandé explicitement. */
  .nav-overlay .nav-item{
    align-self:stretch;
    position:relative; z-index:1;
    opacity:0; transform:translateY(16px);
    transition:transform .55s cubic-bezier(.16,.84,.44,1), opacity .55s ease;
  }
  .nav-toggle{
    display:flex; align-items:center; gap:.5rem;
    width:100%; background:none; border:none; padding:0; margin:0; cursor:pointer;
    font-family:'Playfair Display',serif;
    font-size:clamp(1.1rem,1.3vw,1.35rem);
    font-weight:700;
    text-transform:uppercase;
    letter-spacing:.04em;
    color:var(--cream);
    text-shadow:0 1px 2px rgba(0,0,0,.5), 0 2px 10px rgba(0,0,0,.35);
    transition:color .3s ease;
  }
  .nav-toggle:hover{ color:var(--gold); }
  /* Reste en or tant que le sous-menu est ouvert, pas seulement au survol
     — demandé explicitement. */
  .nav-item.is-open .nav-toggle{ color:var(--gold); }
  /* Même effet de balayage que les liens simples (Accueil, Contact…),
     posé sur le <span> du texte seul (pas sur le bouton entier) pour que
     la flèche à côté ne soit jamais recouverte par le survol — demandé
     explicitement : Particuliers/Entreprises en étaient dépourvus car ce
     sont des <button>, pas des <a>, donc hors de la règle .nav-overlay a::after. */
  .nav-toggle span{ position:relative; }
  .nav-toggle span::after{
    content:attr(data-text);
    position:absolute; top:0; left:0;
    color:var(--gold); background:var(--black);
    width:0%; height:100%; overflow:hidden;
    white-space:nowrap;
    transition:.65s ease;
  }
  .nav-toggle:hover span::after{ width:100%; }
  .nav-toggle .mt-arrow{ flex:none; transition:transform .35s ease; }
  .nav-item.is-open .nav-toggle .mt-arrow{ transform:rotate(180deg); }
  .nav-submenu{
    max-height:0; overflow:hidden;
    transition:max-height .4s ease;
  }
  /* max-height nettement plus proche du contenu réel (3 liens ≈ 5.2em) que
     l'ancienne valeur (10em) : un max-height très surdimensionné fait que
     le contenu est déjà entièrement révélé bien avant la fin réelle de la
     transition (le "reste" du temps ne change plus rien à l'écran), ce qui
     donnait un dépliage anormalement rapide/saccadé au lieu de profiter de
     toute la durée de l'animation — repéré et corrigé suite au retour
     explicite comme quoi le texte "bouge du haut vers le bas" trop vite. */
  .nav-item.is-open .nav-submenu{ max-height:6em; }
  .nav-submenu a{
    display:block;
    font-family:'Playfair Display',serif;
    font-size:clamp(.85rem,1vw,.95rem);
    font-weight:700;
    text-transform:uppercase;
    letter-spacing:.03em;
    color:var(--cream);
    text-shadow:0 1px 2px rgba(0,0,0,.5);
    padding:.3rem 0 .3rem 1.2rem;
  }
  /* Blanc lisible au repos, or au survol/clic (tactile compris) — inversé
     par rapport à avant, demandé explicitement. Pas de transition
     color/opacity ici : sur les liens simples, seul le balayage ::after
     (déjà transitionné) sert de retour visuel au survol — une transition
     color en plus, en parallèle, faisait "trembler"/décaler le texte car
     les deux animations n'étaient pas synchronisées. */
  .nav-submenu a:hover, .nav-submenu a:active, .nav-submenu a:focus-visible{ color:var(--gold); }
  .nav-overlay.open .nav-tel{transition-delay:.72s;}

  /* ============ HERO ============ */
  /* Le premier écran (hero + bandeau stats) doit tenir exactement dans la
     hauteur visible au chargement, quelle que soit la taille de l'écran —
     stats-caption doit rester sous le pli. En flex-column min-height:100svh,
     le hero (flex:1) absorbe l'espace restant une fois la hauteur des stats
     (flex:0 0 auto, sur son contenu réel) déduite, plutôt que deux hauteurs
     fixes indépendantes qui peuvent déborder du premier écran. */
  .hero-viewport{
    display:flex; flex-direction:column;
  }
  .hero{
    /* Photo plein écran seule (demandé explicitement, comme sur
       myet-art.fr) : le hero occupe maintenant tout le premier écran à lui
       seul, .stats est repoussée sous la ligne de flottaison plutôt que de
       partager les 100svh avec lui. */
    min-height:100svh;
    flex:none;
    display:flex; flex-direction:column; align-items:center; justify-content:center;
    text-align:center;
    padding:clamp(2.5rem, 10vh, 8rem) 5vw clamp(2.5rem, 10vh, 8.5rem);
    position:relative;
    overflow:hidden;
    background:var(--black);
  }
  .hero-bg{
    position:absolute; inset:0;
    width:100%; height:100%;
    object-fit:cover;
    z-index:0;
    /* désactive le glisser natif d'image du navigateur (comme
       .cylinder-carousel .carousel-hero img) : sans ça, un glisser sur la
       photo du header (souris ou tactile) déclenche le drag-and-drop natif
       de l'image au lieu du recadrage de l'outil "Recadrer les photos"
       (edit-toolkit.js), qui ne reçoit alors jamais les évènements pointeur. */
    -webkit-user-drag:none; user-select:none; -webkit-user-select:none;
    -webkit-touch-callout:none;
    /* Effet "Ken Burns" (test demandé, repéré sur myet-art.fr) : la photo
       démarre légèrement zoomée puis dézoome doucement une seule fois au
       chargement. .hero a déjà overflow:hidden, donc le zoom de départ ne
       déborde jamais du cadre. */
    animation:heroBgDezoom 10s ease-out forwards;
  }
  @keyframes heroBgDezoom{
    0%{ transform:scale(1.5); }
    100%{ transform:scale(1); }
  }
  /* Sur mobile (écran étroit), le cover ne garde qu'une bande verticale
     étroite de cette photo large — recadrée sur la fresque murale (voilier,
     tourelle rouge, arbre, ruines) plutôt que sur le centre géométrique par
     défaut (qui inclut trop de ciel/mur en pierre), demandé explicitement
     après un essai en transform:scale jugé inacceptable (laissait des
     bandes noires) : plein cadre garanti, seul le point focal change.
     Repositionné de 47% à 66% (étapes intermédiaires à 68% et 78%) : à
     47%, la fresque n'était que partiellement visible (juste la tourelle/
     le bateau, coupée par le mur en pierre voisin) ; à 78% elle était
     entière mais coupait le petit bateau échoué près des ruines — à 66%,
     ce petit bateau est bien visible avec le reste de la fresque (voilier,
     tourelle, arbre, ruines), demandé explicitement. */
  @media(max-width:560px){
    .hero-bg{ object-position:var(--bp-x,66%) center; }
  }
  .hero-bg-video{
    z-index:1;
    opacity:0;
    transition:opacity .8s ease;
  }
  .hero-bg-video.ready{opacity:1;}
  .hero::after{
    content:'';
    position:absolute; inset:0;
    background:linear-gradient(to bottom, transparent 35%, rgba(0,0,0,.75) 100%);
    z-index:1;
    pointer-events:none;
  }
  /* Voile noir qui glisse du bas vers le haut à l'arrivée sur la page (test
     demandé, repéré sur myet-art.fr) — même mécanique : un calque plein
     cadre à 40% d'opacité, translateY(100%) → 0. */
  .hero::before{
    content:'';
    position:absolute; inset:0;
    background:#000;
    opacity:.4;
    z-index:1;
    pointer-events:none;
    transform:translateY(100%);
    animation:heroVeilRise .7s ease 1.4s forwards;
  }
  @keyframes heroVeilRise{
    0%{ transform:translateY(100%); }
    100%{ transform:translateY(0); }
  }
  .hero-content{
    position:relative;
    z-index:2;
    display:flex; flex-direction:column; align-items:center;
    /* Halo sombre appliqué uniquement autour du texte — l'image reste pleinement lumineuse */
    text-shadow:
      0 1px 2px rgba(0,0,0,.4),
      0 2px 8px rgba(0,0,0,.28);
  }
  .hero-eyebrow{margin-bottom:1.3rem; font-size:clamp(.8rem, 2.2vw, 1.15rem); letter-spacing:.32em;}
  .hero h1{
    font-size:clamp(2.4rem, min(7vw, 9vh), 5.2rem);
    max-width:20ch;
    color:var(--cream);
  }
  .hero-line-gold{color:var(--gold); font-style:italic;}
  .hand-num{
    font-family:'Caveat', cursive;
    font-weight:700;
    font-style:italic;
    font-size:1.55em;
    letter-spacing:-.01em;
    display:inline-block;
    vertical-align:-0.09em;
    padding:0 .03em;
    margin-right:.2em;
  }

  /* Grille actualité — 6 photos */
  .a-propos-portrait{
    width:140px; height:140px; margin:0 auto 1.6rem;
    border-radius:50%;
    border:2px solid var(--gold);
    overflow:hidden;
  }
  .a-propos-portrait img{ width:100%; height:100%; object-fit:cover; object-position:50% 15%; display:block; }
  .bio-text{
    max-width:62ch;
    margin:0 auto 3.5rem;
    color:var(--cream-dim);
    font-size:1rem;
    line-height:1.85;
  }
  .bio-text p{ margin:0 0 1.3rem; }
  .bio-text p:last-child{ margin-bottom:0; }
  .bio-text em{ color:var(--gold); font-style:italic; }
  /* Sous-titres d'article au sein de la bio (ex. "Compagnonnage et ancrage
     breton") : même famille que les titres de section (Playfair Display),
     en doré pour bien les distinguer du corps de texte crème. */
  .bio-text h3{
    color:var(--gold);
    font-family:'Playfair Display',serif;
    font-weight:700;
    font-size:1.2rem;
    line-height:1.3;
    margin:1.8rem 0 1rem;
  }
  .bio-text h3:first-child{ margin-top:0; }
  .bio-text ul{ margin:0 0 1.3rem; padding-left:1.3rem; }
  .bio-text li{ margin-bottom:.6rem; }
  .bio-text li:last-child{ margin-bottom:0; }
  /* Effet "site de presse" : le texte visible s'arrête en pleine phrase, et un
     dégradé sur ses dernières lignes donne envie de cliquer "Lire la suite". */
  .bio-fade{ position:relative; }
  .bio-fade::after{
    content:"";
    position:absolute; left:0; right:0; bottom:0; height:13rem;
    background:linear-gradient(0deg, var(--black) 0%, rgba(14,13,12,.75) 35%, transparent 100%);
    pointer-events:none;
  }
  .bio-wrap.expanded .bio-fade::after{ display:none; }
  /* Bio de l'accueil (#a-propos) : pas de dégradé sur les dernières lignes,
     le texte reste lisible jusqu'au bout. Les autres .bio-fade gardent l'effet. */
  #a-propos .bio-fade::after{ display:none; }
  .bio-toggle{
    margin:.2rem 0 0;
    display:inline-flex;
    align-items:center;
    gap:.5rem;
    background:none;
    border:none;
    color:var(--gold);
    font-family:'DM Sans',sans-serif;
    font-size:.8rem;
    font-weight:600;
    letter-spacing:.12em;
    text-transform:uppercase;
    cursor:pointer;
    padding:.4rem 0;
  }
  .bio-toggle .mt-arrow{transition:transform .35s ease;}
  .bio-wrap.expanded .bio-toggle .mt-arrow{transform:rotate(180deg);}
  .bio-more{
    max-height:0;
    overflow:hidden;
    transition:max-height .5s ease;
  }
  .bio-wrap.expanded .bio-more{margin-top:1.3rem;}
  /* Sur mobile (#a-propos, bio de Gwendal), le paragraphe "Pour nourrir
     cette passion" (.bio-cursus, sorti de .bio-fade pour pouvoir le
     réordonner indépendamment) doit s'afficher APRÈS le bouton "Découvrir",
     juste en dessous du paragraphe "skate et hip-hop" - demandé
     explicitement. flex-direction:column sur .bio-wrap ne change rien par
     défaut (ordre naturel identique au flux bloc), seul le media query
     mobile réordonne. Scopé à #a-propos : .bio-wrap est réutilisé ailleurs
     (autres pages) avec un contenu différent, à ne pas affecter. */
  #a-propos .bio-wrap{ display:flex; flex-direction:column; }
  @media(max-width:640px){
    #a-propos .bio-cursus{ order:3; }
    #a-propos .bio-toggle{ order:2; }
    #a-propos .bio-more{ order:4; }
  }
  /* Grille de photos dans "À propos de l'artiste" (différente du bandeau
     défilant .strip-viewport/.strip-track utilisé ailleurs). 4 photos visibles
     d'entrée, 16 de plus à déplier (20 au total) — même logique déplier/replier
     que .bio-wrap et .metamorphose-copy. */
  .actu-wrap{
    max-width:900px;
    margin:0 auto;
    text-align:center;
  }
  .actu-grid{
    display:grid;
    grid-template-columns:repeat(4,1fr);
    grid-auto-rows:180px;
    gap:.8rem;
  }
  .actu-item{
    background-size:cover;
    background-position:center;
    border-radius:8px;
    cursor:pointer;
  }
  .actu-wrap .bio-toggle{margin:1.3rem auto 0;}
  .actu-wrap.expanded .actu-toggle .mt-arrow{transform:rotate(180deg);}
  .actu-more{
    max-height:0;
    overflow:hidden;
    transition:max-height .5s ease;
    display:grid;
    grid-template-columns:repeat(4,1fr);
    grid-auto-rows:180px;
    gap:.8rem;
  }
  .actu-wrap.expanded .actu-more{margin-top:.8rem;}
  @media(max-width:900px){
    .actu-more{grid-template-columns:repeat(2,1fr);}
  }

  /* Revue de presse — grille de coupures cliquables, ouvre le lightbox
     existant (avec loupe) plutôt qu'un mécanisme séparé. Un seul rang de 4
     articles est visible au départ ; la flèche qui clignote révèle le reste
     sans jamais retélécharger quoi que ce soit (les images restent en
     loading="lazy", chargées à la demande au scroll une fois révélées). */
  .presse-intro{
    max-width:60ch;
    margin:1.1rem auto 0;
    color:var(--cream-dim);
    font-size:.95rem;
    line-height:1.7;
  }
  .presse-grid{
    display:grid;
    grid-template-columns:repeat(4,1fr);
    grid-auto-rows:170px;
    gap:.6rem;
    max-width:1550px;
    margin:0 auto;
  }
  .presse-item{
    position:relative;
    display:block;
    padding:0;
    margin:0;
    border:1px solid var(--line);
    border-radius:6px;
    overflow:hidden;
    background:var(--black-soft);
    cursor:pointer;
    transition:border-color .3s ease;
  }
  .presse-item:hover{ border-color:var(--gold); }
  /* Origine de l'article (Le Télégramme, Ouest-France, etc.) — affichée uniquement
     quand le logo/nom du média est réellement visible sur le scan. */
  .presse-source{
    position:absolute; left:.4rem; bottom:.4rem; z-index:1;
    padding:.15rem .5rem;
    background:rgba(14,13,12,.85);
    border:1px solid var(--gold);
    border-radius:3px;
    font-family:'DM Sans',sans-serif; font-size:.6rem; font-weight:700;
    letter-spacing:.04em; text-transform:uppercase; color:var(--gold);
    pointer-events:none;
    max-width:calc(100% - .8rem);
    white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
  }
  .presse-item img{
    width:100%; height:100%;
    object-fit:cover;
    display:block;
    transition:transform .4s ease;
  }
  .presse-item:hover img{ transform:scale(1.06); }
  /* Grilles presse embarquées (accueil, collectivités, particuliers, pro) :
     2 rangs sur ordinateur (4 colonnes) / 4 rangs sur mobile (2 colonnes) =
     8 coupures visibles dans les deux cas, le reste reste lisible via le
     lien vers la page Presse complète — demandé explicitement. */
  .presse-item:nth-child(n+9){ display:none; }
  /* Page Presse (archive complète) : les 95 coupures sont toutes affichées
     d'emblée, sans bouton "voir plus" — demandé explicitement. */
  .presse-grid.presse-full .presse-item:nth-child(n+9){ display:block; }
  .presse-more{ display:flex; justify-content:center; margin-top:2rem; }
  .presse-more-btn{
    display:flex; flex-direction:column; align-items:center; gap:.5rem;
    background:none; border:none; cursor:pointer; padding:0;
    color:var(--cream-dim);
    font-family:'DM Sans',sans-serif;
    font-size:.8rem; letter-spacing:.12em; text-transform:uppercase; font-weight:600;
    transition:color .3s ease;
  }
  .presse-more-btn:hover{ color:var(--gold); }
  .presse-more-arrow{
    color:var(--gold);
  }
  .press-journalist-cta{
    display:flex; align-items:center; justify-content:center; gap:.6rem;
    width:fit-content;
    margin:1.8rem auto 0;
    padding:.85rem 1.6rem;
    border:1px solid var(--line);
    border-radius:999px;
    color:var(--cream-dim);
    font-family:'DM Sans',sans-serif;
    font-size:.85rem; font-weight:600;
    text-align:center;
    transition:color .3s ease, border-color .3s ease;
  }
  .press-journalist-cta svg{ color:var(--gold); flex:0 0 auto; }
  .press-journalist-cta:hover{ color:var(--gold); border-color:var(--gold); }
  @media(max-width:560px){
    .press-journalist-cta{ font-size:.78rem; padding:.8rem 1.2rem; }
  }

  /* Tableaux — vente entreprises/grands groupes ou particuliers.
     Titre centré au-dessus (comme les autres sections). En dessous : DEUX
     cadres dorés distincts côte à côte (un pour le texte, un pour la photo),
     même hauteur, qui tiennent ensemble dans le même rectangle visuel ; le
     carrousel de vignettes (identique aux flip-cards) juste en dessous, hors
     des cadres. Pas de légende ni de dégradé sur la photo. Ratio calé sur le
     format réel des photos (paysage, ~3:2 à 16:9), pas le portrait des
     cartes murales. */
  /* .tableaux-intro : texte de présentation plus long que le paragraphe
     court habituel de .section-head (limité à 46ch, centré) — colonne plus
     large et alignée à gauche pour rester lisible sur plusieurs paragraphes
     et deux sous-titres. */
  .tableaux-intro{
    max-width:65ch;
    margin:0 auto 3.5rem;
    text-align:left;
    color:var(--cream-dim);
    line-height:1.7;
  }
  .tableaux-intro p{ margin-top:1rem; }
  .tableaux-intro p:first-child{ margin-top:0; }
  .tableaux-intro-photo{ margin:1.5rem 0 0; }
  .tableaux-intro-photo img{
    display:block;
    width:100%;
    height:auto;
    border-radius:8px;
    border:1px solid var(--line);
  }
  .tableaux-intro h3{
    margin-top:2rem;
    color:var(--cream);
    font-size:clamp(1.15rem,2vw,1.4rem);
  }
  .tableaux-frame{
    display:grid;
    grid-template-columns:1fr;
    height:clamp(220px, 22vw, 320px);
    max-width:1300px;
    margin:2.8rem auto 0;
    border:2px solid var(--gold);
    position:relative; /* ancre pour la poignée d'étirement localhost (edit-toolkit.js) */
  }
  #tableauxCarousel .tableaux-frame .carousel-hero{
    flex:none; /* écrase le flex:0 0 63.9% générique : ici la taille vient de la grille, pas d'un flex parent */
    height:100%;
    background:var(--black);
  }
  #tableauxCarousel .carousel-hero img{ object-fit:cover; object-position:var(--bp-x,50%) center; filter:brightness(.7); -webkit-user-drag:none; user-select:none; -webkit-user-select:none; }
  /* margin-bottom : les vignettes débordent sous leur boîte (carrousel 3D,
     overflow:visible) et mangent une partie du padding-bottom standard de la
     section — sans cette marge, l'espace réel avant la section suivante est
     plus petit que partout ailleurs sur le site malgré un padding identique. */
  #tableauxCarousel .carousel-viewport{ max-width:1300px; height:140px; margin:6rem auto 4rem; }
  /* "Tableaux" : anneau 3D remplacé par le même bandeau défilant que la
     toile marouflée (demandé explicitement, "ce nouveau carrousel"), sans
     grande photo au-dessus cette fois non plus — voir #maroufleStrip pour
     le détail de chaque choix (reflet, liseret, plein format, marge du
     liseret). Même hauteur que la marouflée (demandé explicitement) : 336px
     / 252px, pas la taille de base. */
  #tableauxStrip.strip-viewport{ height:336px; margin:6rem auto 4rem; }
  #tableauxStrip .strip-track{ align-items:flex-start; height:100%; padding-top:2px; }
  #tableauxStrip .strip-item{ width:auto; aspect-ratio:auto; height:252px; }
  #tableauxStrip .strip-item-inner{ outline:1px solid var(--gold); outline-offset:0; }
  #tableauxStrip .strip-item-inner img{ width:auto; height:100%; object-fit:contain; cursor:pointer; }
  /* "Découvrir l'actualité" : mêmes effets (demandé explicitement) — plein
     format, liseret, reflet, même hauteur — voir #maroufleStrip pour le
     détail de chaque choix. */
  #actuStrip.strip-viewport{ height:336px; }
  #actuStrip .strip-track{ align-items:flex-start; height:100%; padding-top:2px; }
  #actuStrip .strip-item{ width:auto; aspect-ratio:auto; height:252px; }
  #actuStrip .strip-item-inner{ outline:1px solid var(--gold); outline-offset:0; position:relative; }
  /* Nom de la commune sur chaque photo — en haut à gauche pour ne pas
     recouvrir la signature/le site incrustés en bas à gauche des photos. */
  .strip-caption{
    position:absolute; top:.6rem; left:.6rem; z-index:1;
    padding:.22rem .7rem;
    background:rgba(14,13,12,.82);
    border:1px solid var(--gold);
    border-radius:999px;
    font-family:'DM Sans',sans-serif; font-size:.68rem; font-weight:700;
    letter-spacing:.1em; text-transform:uppercase;
    color:var(--gold);
    white-space:nowrap;
    pointer-events:none;
  }
  #actuStrip .strip-item-inner img{ width:auto; height:100%; object-fit:contain; cursor:pointer; }
  /* "Enseignement & stages" : mêmes effets (demandé explicitement) — plein
     format, liseret, reflet, même hauteur — voir #maroufleStrip pour le
     détail de chaque choix. */
  #enseignementStrip.strip-viewport{ height:336px; }
  #enseignementStrip .strip-track{ align-items:flex-start; height:100%; padding-top:2px; }
  #enseignementStrip .strip-item{ width:auto; aspect-ratio:auto; height:252px; }
  #enseignementStrip .strip-item-inner{ outline:1px solid var(--gold); outline-offset:0; }
  #enseignementStrip .strip-item-inner img{ width:auto; height:100%; object-fit:contain; }
  /* backface-visibility:hidden a été essayé ici pour corriger un "mélange" de
     vignettes constaté à 20 photos (trop de faces "de dos" visibles en même
     temps) — mais ça supprimait aussi l'effet d'anneau complet (les cartes qui
     passent derrière, assombries, donnant l'impression de 3D) que ce
     carrousel partage avec les 13 flip-cards du site. Le carrousel étant
     revenu à 10 photos (densité d'origine, jamais problématique), ce
     correctif n'est plus nécessaire et a été retiré — l'effet 3D complet est
     donc à nouveau actif ici comme partout ailleurs. Si le nombre de photos
     remonte significativement un jour, revoir cette décision. */
  /* Deux cartes voisines qui se touchent sans séparation visible (seule la
     carte active avait une bordure) pouvaient donner l'impression d'une
     seule image "mélangée" plutôt que de deux photos distinctes collées —
     surtout aux angles où l'une, très rapprochée par la perspective,
     déborde presque sur sa voisine. Une bordure fine et permanente sur
     TOUTES les cartes (pas seulement l'active) trace une séparation nette
     dans tous les cas. Scopé à ce carrousel, sans toucher au style des 13
     autres flip-cards. */
  #tableauxCarousel .carousel-item-inner{
    border:1px solid rgba(0,0,0,.7);
    box-shadow:0 4px 14px rgba(0,0,0,.45), 0 0 0 2px rgba(10,10,10,.6);
    /* border-radius + overflow:hidden peut échouer à découper correctement
       le contenu quand l'élément est enfant d'un parent en transformation 3D
       (.carousel-item, rotateY+translateZ) — bug de composition GPU connu :
       le clip "fuit" par endroits et une photo déborde visuellement sur sa
       voisine au lieu d'être proprement coupée à son propre cadre arrondi.
       Forcer cet élément sur sa propre couche de composition (au lieu de
       laisser le moteur essayer de le découper à l'intérieur de l'espace 3D
       du parent) résout ce type de fuite de clip. */
    transform:translateZ(0);
    -webkit-transform:translateZ(0);
    isolation:isolate;
  }
  .tableaux-cta{ display:flex; gap:1rem; flex-wrap:wrap; justify-content:center; margin-top:5.2rem; }
  /* "Acheter un tableau" : plus aucun article disponible à la vente — le
     bouton ne mène nulle part, il affiche juste un petit message au clic
     (même mécanique que .header-share-note pour "Lien copié !"). */
  .tableaux-buy-btn{ position:relative; font-family:'DM Sans',sans-serif; cursor:pointer; }
  .tableaux-buy-note{
    position:absolute;
    top:calc(100% + .6rem);
    left:50%;
    padding:.5rem .9rem;
    background:var(--black-soft);
    border:1px solid var(--gold);
    color:var(--gold);
    font-size:.75rem;
    letter-spacing:.03em;
    text-transform:none;
    white-space:nowrap;
    opacity:0;
    transform:translate(-50%, -4px);
    pointer-events:none;
    transition:opacity .25s ease, transform .25s ease;
  }
  .tableaux-buy-btn.show-note .tableaux-buy-note{
    opacity:1;
    transform:translate(-50%, 0);
  }
  /* --- Galerie des tableaux vendus. Sur galerie.html (.page-chantier),
     toujours affichée en entier. Sur l'accueil (.page-home), tronquée avec
     bouton "Découvrir plus de toiles" / "Réduire" (même logique déplier/
     replier que Métamorphose). ---
     Deux colonnes indépendantes (chacune un simple flex column empilé) plutôt
     qu'une grille : avec des photos au format réel (portrait, paysage, carré),
     une grille CSS classique force la hauteur de chaque RANGÉE sur sa case la
     plus haute, ce qui laisse des vides sous les photos plus courtes. En
     colonnes indépendantes, chaque photo ne pousse que celles qui la suivent
     dans SA colonne — jamais de vide. Correspond 1:1 aux "colonne gauche /
     colonne droite" de l'outil de réorganisation dans admin.html. */
  .toiles-more{
    display:flex;
    flex-wrap:wrap;
    align-items:flex-start;
    gap:1.4rem;
    max-width:1300px;
    margin:0 auto;
  }
  .page-chantier .toiles-more{ margin-top:2.6rem; }
  .page-home .toiles-more{
    max-height:0;
    overflow:hidden;
    transition:max-height .6s ease;
  }
  .page-home .toiles-wrap.expanded .toiles-more{ margin-top:2.6rem; }
  .toiles-toggle-row{ text-align:center; margin-top:1.6rem; }
  .toiles-wrap .bio-toggle{ margin:0 auto; }
  .toiles-wrap.expanded .toiles-toggle .mt-arrow{ transform:rotate(180deg); }
  .toiles-close-row{ flex-basis:100%; text-align:center; margin-top:.8rem; }
  .toiles-col{
    flex:1 1 300px;
    min-width:0;
    display:flex;
    flex-direction:column;
    gap:1.4rem;
  }
  /* Sur mobile, flex-basis:300px force le passage à une seule colonne
     (les deux dépassent la largeur de l'écran) — gardé demandé sur deux
     colonnes côte à côte comme sur ordinateur : flex-wrap:nowrap +
     flex:1 1 0 (comme .page-piscine .univers-picto-row-circles plus bas)
     pour que les deux colonnes se partagent la largeur à parts égales. */
  @media(max-width:640px){
    .toiles-more{ flex-wrap:nowrap; gap:3vw; }
    .toiles-col{ flex:1 1 0; gap:3vw; }
  }
  .toile-item{ text-align:center; }
  .toile-photo{
    display:block;
    width:100%;
    height:auto;
    border-radius:8px;
    border:1px solid var(--line);
  }
  .toile-vendu{
    display:inline-block;
    margin-top:.6rem;
    font-family:'DM Sans',sans-serif;
    font-size:.72rem;
    font-weight:700;
    letter-spacing:.14em;
    text-transform:uppercase;
    color:var(--gold);
  }
  .enseignement-cta{ display:flex; gap:1rem; flex-wrap:wrap; justify-content:center; margin-top:2.6rem; }
  .ens-cta-short{ display:none; }

  /* ============ TRAVAIL EN HAUTEUR ============ */
  .hauteur-list{
    display:flex;
    flex-direction:column;
    gap:2.6rem;
    max-width:1100px;
    margin:0 auto;
  }
  .hauteur-cols{
    display:grid;
    grid-template-columns:1fr 1fr;
    gap:3.2rem;
  }
  .hauteur-col{ display:flex; flex-direction:column; }
  .hauteur-col .hauteur-point{ margin-top:1.4rem; }
  .hauteur-photo{
    position:relative;
    overflow:hidden;
    border:2px solid var(--gold);
    aspect-ratio:2400/1349;
  }
  .hauteur-photo img{ width:100%; height:100%; object-fit:cover; display:block; }
  .hauteur-caption{
    position:absolute; left:0; right:0; bottom:0;
    padding:1.2rem 1.4rem;
    background:linear-gradient(0deg, rgba(0,0,0,.8), transparent);
    color:var(--cream);
    font-size:.78rem;
    letter-spacing:.04em;
  }
  .hauteur-point-full{
    max-width:56ch;
    margin:0 auto;
    text-align:center;
    padding-top:.6rem;
    border-top:1px solid var(--line);
  }
  .hauteur-num{
    font-family:'Anton',sans-serif;
    color:var(--gold);
    font-size:.9rem;
    letter-spacing:.1em;
  }
  .hauteur-point h3{ font-size:1.15rem; color:var(--cream); margin:.35rem 0 .5rem; }
  .hauteur-point p{ color:var(--cream-dim); line-height:1.7; font-size:.92rem; margin:0; }
  .hauteur-securite-toggle{ margin:.2rem auto 0; }
  .hauteur-securite-toggle .mt-arrow{ transition:transform .35s ease; }
  .hauteur-point-full.open .hauteur-securite-toggle .mt-arrow{ transform:rotate(180deg); }
  .hauteur-securite-more{
    max-height:0; overflow:hidden;
    transition:max-height .5s ease;
  }
  .hauteur-point-full.open .hauteur-securite-more{ margin-top:1rem; }

  /* ============ TOILE MAROUFLÉE ============ */
  .maroufle-wrap{
    display:grid;
    grid-template-columns:1fr 1.05fr;
    gap:3.2rem;
    max-width:1150px;
    margin:0 auto;
    align-items:start;
  }
  /* min-width:0 : sans ça, un enfant direct de grille CSS grandit pour
     épouser son propre contenu (ici le bandeau .strip-track, très large,
     width:max-content) au lieu de rester à la largeur de la colonne — le
     bandeau n'avait alors plus rien à faire défiler (clientWidth ==
     scrollWidth, 0 overflow). Bug classique de CSS Grid. */
  .maroufle-photo{ position:sticky; top:6rem; min-width:0; }
  .maroufle-points{ display:flex; flex-direction:column; }
  /* Même bandeau défilant que "Découvrir l'actualité"/"Enseignement"
     (.strip-viewport/.strip-track/.strip-item, molette+glisser+défilement
     auto+boucle infinie déjà génériques, voir initScrollStrip en JS) —
     demandé explicitement à la place de mon 1er essai (bandeau CSS maison).
     #maroufleStrip.strip-viewport plus haut que les items pour laisser de la
     place SOUS chaque photo, dans ce même cadre, pour le reflet — sinon
     overflow-y:hidden (hérité de .strip-viewport) le couperait net. */
  /* +20% (demandé explicitement) sur les deux dimensions, cadre et photo,
     pour garder les mêmes proportions/marge de reflet : 280→336, 210→252. */
  #maroufleStrip.strip-viewport{ height:336px; }
  /* padding-top:2px : le liseret (outline) dépasse tout juste au-dessus du
     bord de chaque photo — sans cette marge, les photos étaient collées au
     tout début du cadre (align-items:flex-start) et ce petit dépassement du
     haut du liseret se faisait couper net par overflow-y:hidden sur
     .strip-viewport. */
  #maroufleStrip .strip-track{ align-items:flex-start; height:100%; padding-top:2px; }
  /* Plein format demandé explicitement (pas de recadrage) : on annule ici
     le width:280px/aspect-ratio:4:3 fixes hérités de .strip-item (pensés
     pour des photos recadrées en 4:3, comme actuStrip/enseignementStrip) —
     seule la hauteur est fixée, la largeur suit le ratio propre à chaque
     photo. */
  #maroufleStrip .strip-item{
    width:auto; aspect-ratio:auto; height:252px;
    /* Opacité du reflet +30% depuis la base (demandé explicitement, remplace
       le +15% précédent) : .2 → .26. */
    --reflect-opacity:.26;
  }
  /* Liseret demandé explicitement : outline (pas border, jamais partie du
     modèle de boîte, contrairement à border en box-sizing:border-box global
     du site) + outline-offset:0 pour épouser le border-radius — même
     convention déjà utilisée sur les vignettes actives du caroussel 3D
     standard. Posé sur .strip-item-inner (le clipping/border-radius vit là
     désormais, voir plus haut), pas .strip-item. */
  #maroufleStrip .strip-item-inner{ outline:1px solid var(--gold); outline-offset:0; }
  #maroufleStrip .strip-item-inner img{ width:auto; height:100%; object-fit:contain; }
  /* Sur ordinateur (demandé explicitement) : le bandeau occupe toute la
     largeur de la page, la mini FAQ passe en dessous (au lieu d'à côté). */
  @media(min-width:901px){
    .maroufle-wrap{ grid-template-columns:1fr; max-width:none; gap:2.4rem; }
    .maroufle-photo{ position:static; width:100%; }
    .maroufle-points{ max-width:700px; margin:0 auto; width:100%; }
  }

  /* Le cadre doré épouse la photo elle-même (pas tout le bloc carrousel,
     vignettes comprises) — et sa taille s'adapte au format réel de chaque
     photo (portrait ou paysage selon les 10 photos du carrousel), plutôt
     qu'un ratio fixe qui aurait recadré certaines d'entre elles. */
  #maroufleCarousel{ aspect-ratio:auto; }
  #maroufleCarousel .carousel-hero{
    flex:none;
    width:auto; align-self:center;
    border:2px solid var(--gold);
    overflow:hidden;
  }
  #maroufleCarousel .carousel-hero img{
    position:static;
    width:auto; height:auto;
    max-width:100%; max-height:60vh;
    object-fit:contain;
    display:block; margin:0 auto;
  }
  #maroufleCarousel .carousel-viewport{
    flex:none; height:140px; margin-top:1.6rem;
  }
  @media(max-width:900px){
    #maroufleCarousel .carousel-hero img{ max-height:70vw; }
  }
  /* Accordéon, même logique que la FAQ (une seule réponse ouverte à la fois,
     déclenchée par clic sur l'en-tête) — classes propres pour ne pas
     interférer avec l'accordéon .faq-item, indépendant, plus bas sur la page. */
  .maroufle-item{ border-bottom:1px solid var(--line); }
  .maroufle-q{
    width:100%;
    display:flex; align-items:center; gap:1rem;
    padding:1.4rem 0;
    background:none; border:none;
    cursor:pointer; text-align:left;
  }
  .maroufle-q h3{ flex:1; margin:0; font-size:1.15rem; color:var(--cream); }
  .maroufle-q .plus{
    flex:0 0 auto;
    color:var(--gold);
    font-size:1.4rem;
    font-family:'DM Sans',sans-serif;
    transition:transform .3s ease;
  }
  .maroufle-item.open .plus{ transform:rotate(45deg); }
  .maroufle-a{
    max-height:0;
    overflow:hidden;
    transition:max-height .4s ease;
  }
  .maroufle-a p{
    padding-bottom:1.4rem;
    color:var(--cream-dim);
    line-height:1.7;
    margin:0;
  }

  @media(max-width:900px){
    .maroufle-wrap{ grid-template-columns:1fr; gap:1.6rem; }
    .maroufle-photo{ position:static; }
  }

  @media(max-width:900px){
    .hauteur-cols{ grid-template-columns:1fr; gap:2.2rem; }
    .hauteur-list{ gap:2.4rem; }
    /* Colonne unique déjà depuis le desktop (voir règles de base) — sur
       mobile on ajuste juste la hauteur du cadre photo. */
    .tableaux-frame{
      height:auto !important; /* écrase la hauteur fixe posée en JS (calée sur la largeur desktop) */
      margin-top:0; /* le titre a déjà sa marge standard (.section-head, 3.5rem) : cette marge s'ajoutait par-dessus et doublait l'écart, contrairement au reste du site */
    }
    #tableauxCarousel .tableaux-frame .carousel-hero{ height:clamp(240px, 70vw, 380px); }
    #tableauxCarousel .carousel-viewport{ max-width:100%; margin-bottom:0; } /* la marge basse "anti-débordement" est un réglage desktop, la position mobile est pilotée séparément */
    #tableauxStrip.strip-viewport{ max-width:100%; margin-bottom:0; }
  }

  /* Réseaux sociaux — sous le titre de la section actualité */
  .socials-row{
    display:flex; flex-wrap:wrap; justify-content:center; gap:.9rem;
    margin-top:1.6rem;
  }
  .social-pill{
    display:inline-flex; align-items:center;
    padding:.7rem 1.5rem;
    border:1px solid var(--line);
    border-radius:999px;
    font-size:.78rem; letter-spacing:.12em; text-transform:uppercase; font-weight:600;
    color:var(--cream);
    transition:color .3s ease, border-color .3s ease;
  }
  .social-pill:hover{ color:var(--gold); border-color:var(--gold); }

  /* Apparition des textes de section au scroll */
  .sr{
    opacity:0;
    transform:translateY(22px);
  }
  .sr.sr-in{
    animation:heroLineIn .8s cubic-bezier(.16,.84,.44,1) forwards;
  }
  @media(prefers-reduced-motion:reduce){
    .sr{ opacity:1; transform:none; }
    .sr.sr-in{ animation:none; }
  }

  /* Décalage manuel demandé pour équilibrer "Fresques murales" avec la
     ligne du dessous — voir .hero-title-lead et le @media plus bas pour la
     désactivation sur téléphone étroit, où le texte passe sur 2 lignes. */
  .hero-title{ transform:translateX(-.233em); }
  /* Apparition séquentielle des 3 lignes (eyebrow + 2 lignes du h1) */
  .reveal-line{
    display:inline-block;
    opacity:0;
    transform:translateY(22px);
  }
  /* Hero (demandé explicitement) : chaque ligne arrive de plus bas que le
     réglage générique de .reveal-line (utilisé sobrement ailleurs), pour un
     vrai effet de montée depuis le bas de l'écran. */
  .hero .reveal-line{
    transform:translateY(80px);
  }
  .hero.ready .reveal-line{
    animation:heroLineIn .8s cubic-bezier(.16,.84,.44,1) forwards;
  }
  @keyframes heroLineIn{
    to{opacity:1; transform:translateY(0);}
  }
  /* .hero-title-lead (espace invisible avant "Fresques") + le
     translateX(-.233em) sur .hero-title se compensent exactement pour
     centrer le texte sur UNE seule ligne (calibré à la demande — voir plus
     haut). En dessous de ~400px, "Fresques murales" passe sur deux lignes :
     l'espace ne concerne alors que la 1ʳᵉ ligne, mais le translateX
     s'applique aux deux, décalant "murales" hors du centre alors qu'il n'a
     besoin d'aucune correction. On neutralise donc les deux uniquement à
     cette largeur, où le rendu naturel (texte simplement centré) suffit. */
  @media(max-width:430px){
    .hero-title{ transform:none; }
    .hero-title-lead{ display:none; }
  }

  .hero-typewriter{
    margin-top:clamp(1rem, 5vh, 3.2rem);
    min-height:2.6rem;
  }
  #typewriter{
    font-family:'Playfair Display',serif;
    font-weight:700;
    font-style:italic;
    font-size:clamp(1.5rem, 3.4vw, 2.3rem);
    line-height:1.3;
    color:var(--cream);
    text-shadow:none;
  }
  @media(max-width:700px){
    /* En dessous de ~700px, #typewriter reste bloqué à sa taille plancher
       (1.5rem) : certains mots de la liste (ex. "Trompe-l'œil et peintures
       de street art") passent alors sur 2 lignes alors que d'autres tiennent
       sur 1 seule. Comme .hero-typewriter ne réservait de la place que pour
       1 ligne, le bandeau des chiffres (26 / 300+ / 4) juste en dessous se
       décalait de haut en bas à chaque changement de mot. On réserve donc
       toujours la hauteur du pire cas (2 lignes). */
    .hero-typewriter{ min-height:4.2rem; }
  }
  .contact-typewriter{
    border-right:3px solid var(--gold);
    padding-right:5px;
  }
  .hero p.lede{
    margin-top:1.8rem;
    max-width:42ch;
    color:var(--cream-dim);
    font-size:1.05rem;
    line-height:1.7;
  }
  .hero-cta{margin-top:2.6rem; display:flex; gap:1rem; flex-wrap:wrap; justify-content:center;}

  /* ============ STATS ============ */
  .stats{
    display:grid;
    grid-template-columns:repeat(3,1fr);
    flex:0 0 auto;
    border-top:1px solid rgba(210,172,90,.15);
    position:relative;
    z-index:3;
    /* Chevauchement retiré (demandé explicitement) : la photo du hero doit
       occuper tout le premier écran sans que la barre de chiffres n'empiète
       dessus — .stats est maintenant entièrement sous la ligne de
       flottaison, plus de margin-top négatif ici. */
    background:rgba(10,10,10,.72);
    backdrop-filter:blur(10px);
  }
  .stat{
    padding:clamp(1.2rem, 6vh, 3.2rem) 1rem;
    text-align:center;
    border-right:1px solid var(--line);
  }
  .stat:last-child{border-right:none;}
  /* "bretons" en plus uniquement sur mobile ("4 Départements bretons"),
     demandé explicitement — desktop reste juste "Départements". */
  .stat-label-bretons{ display:none; }
  @media(max-width:640px){
    .stat-label-bretons{ display:inline; }
  }
  .stat-num{
    font-family:'Anton', sans-serif;
    font-size:clamp(2.2rem, min(5vw, 6vh), 3.6rem);
    color:var(--gold);
    letter-spacing:.02em;
    white-space:nowrap;
  }
  /* .stat-num-inner : wrapper autour du seul chiffre (ex. "300"), sans le
     "+" — .stat-num centre ce wrapper (text-align hérité), donc le chiffre
     reste toujours centré avec le libellé en dessous, quel que soit le
     préfixe. Le "+" (.stat-suffix) est un enfant en position:absolute de ce
     wrapper : un enfant absolu ne compte pas dans la largeur du parent, donc
     il n'influence jamais ce centrage ("le + ne fait pas partie du
     centrage", demandé explicitement) — juste accroché immédiatement à
     gauche du chiffre via right:100%. */
  .stat-num-inner{
    position:relative;
    display:inline-block;
  }
  /* Le glyphe "+" est légèrement bas par défaut dans Anton par rapport au
     chiffre : son encre ne descend pas jusqu'à la ligne de base (mesuré via
     canvas measureText : centre du "+" à -10.5px de la baseline contre
     -15px pour "0"), donc recentré ici verticalement sur la hauteur du
     chiffre, demandé explicitement. */
  .stat-suffix{
    position:absolute;
    right:100%;
    /* top/bottom non précisés : reste à sa position verticale "statique"
       (celle qu'il aurait eue en flux normal, alignée sur la ligne de base
       comme avant le passage en absolute) — seul le décalage fin d'origine
       est repris, en transform plutôt qu'en top (qui ferait ici référence
       au bord du conteneur, pas à la position naturelle). */
    transform:translateY(-.13em);
  }
  .stat-label{
    margin-top:.5rem;
    font-size:.75rem;
    letter-spacing:.15em;
    text-transform:uppercase;
    color:var(--cream-dim);
  }
  .stats-caption{
    background:var(--black-soft);
    border-top:1px solid var(--line);
    border-bottom:1px solid var(--line);
    padding:2.6rem 5vw 3rem;
    display:flex; flex-direction:column; align-items:center; gap:1.3rem;
    text-align:center;
  }
  .stats-caption-row{
    display:flex; align-items:center; gap:1.8rem;
    text-align:left;
  }
  .stats-caption-map{ flex:0 0 auto; width:clamp(70px, 8vw, 100px); }
  .stats-caption-map svg{ width:100%; height:auto; display:block; }
  .stats-caption-map .bzh-dept{
    fill:rgba(210,172,90,.14);
    stroke:var(--gold);
    stroke-width:1.4;
    stroke-linejoin:round;
    stroke-dasharray:var(--len, 700);
    stroke-dashoffset:var(--len, 700);
  }
  /* Carte de Bretagne qui se dessine au scroll (même principe que le tracé
     des pictogrammes .surface-item : longueur réelle de chaque contour de
     département calculée en JS via getTotalLength(), voir script.js),
     demandé explicitement. Chaque département se dessine l'un après
     l'autre (délai croissant posé en JS). */
  .stats-caption-map.map-in .bzh-dept{
    animation:bzhMapDraw 1.3s ease forwards;
    animation-delay:var(--draw-delay, 0s);
  }
  @keyframes bzhMapDraw{ to{ stroke-dashoffset:0; } }
  @media(prefers-reduced-motion:reduce){
    .stats-caption-map .bzh-dept{ stroke-dasharray:none; stroke-dashoffset:0; }
    .stats-caption-map.map-in .bzh-dept{ animation:none; }
  }
  .stats-caption p{
    max-width:64ch;
    color:var(--cream-dim);
    font-size:1.02rem;
    line-height:1.75;
  }
  .stats-caption-lead{
    display:inline-block;
    margin-bottom:.6rem;
    color:var(--gold);
    font-family:'DM Sans',sans-serif;
    font-weight:600;
    font-size:.75rem;
    letter-spacing:.28em;
    text-transform:uppercase;
    line-height:1.3;
  }
  /* Sur ordinateur, "Studio et atelier d'art mural en Bretagne" tient
     largement sur une ligne — le retour à la ligne forcé n'est utile que
     sur mobile, où le bloc est plus étroit. */
  @media(min-width:801px){
    .stats-caption-lead-br{ display:none; }
  }
  .stats-caption-title{
    display:inline-block;
    margin:.3rem 0 .6rem;
    color:var(--cream);
    font-family:'Playfair Display',serif;
    font-weight:700;
    font-size:1.35rem;
    line-height:1.25;
  }
  @media(max-width:640px){
    .stats-caption-row{ flex-direction:column; text-align:center; }
    .stats-caption-map{ align-self:center; width:140px; }
    .stats-caption-map svg{ width:100%; height:auto; }
  }
  /* --- Surfaces d'intervention : mêmes pictogrammes (48x48, trait seul, pas
     de remplissage) que .shape-btn sur la page de contact ("Forme du mur"),
     demandé explicitement, mais en badges statiques (pas des boutons
     cliquables) puisqu'il s'agit ici d'une simple liste illustrée. --- */
  .surfaces-row{
    width:100%;
  }
  /* .stats-caption-surfaces : ce bloc sert aussi de zone tampon entre
     #pleybenLyceeBand (juste au-dessus) et #marianneBand (juste après, plus
     bas) — sans un espace au moins aussi grand que la hauteur d'écran entre
     deux bandeaux photo fixed, les deux se retrouvent actifs en même temps
     et se recouvrent (bug déjà rencontré). min-height:100vh garantit cette
     marge sur n'importe quelle taille d'écran, quel que soit le volume réel
     du texte/pictogrammes ; le contenu reste centré verticalement dedans. */
  .stats-caption-surfaces{
    min-height:calc(100vh + 120px);
    justify-content:center;
  }
  .surfaces-label{
    display:block;
    text-align:center;
    margin-bottom:.6rem;
    color:var(--gold);
    font-family:'DM Sans',sans-serif;
    font-weight:600;
    font-size:.75rem;
    letter-spacing:.28em;
    text-transform:uppercase;
  }
  .surfaces-title{
    text-align:center;
    margin:0 0 .8rem;
    color:var(--cream);
    font-family:'Playfair Display',serif;
    font-weight:700;
    font-size:1.5rem;
    line-height:1.3;
  }
  .surfaces-text{
    max-width:64ch;
    margin:0 auto 2.2rem;
    text-align:center;
    color:var(--cream-dim);
    font-size:1.02rem;
    line-height:1.75;
  }
  .surfaces-grid{
    display:flex;
    flex-wrap:wrap;
    justify-content:center;
    gap:.7rem;
  }
  .surface-item{
    flex:1; min-width:110px; max-width:150px; padding:1rem .8rem;
    background:var(--black-soft); border:1px solid var(--line); color:var(--cream-dim);
    font-family:'DM Sans',sans-serif; font-size:.78rem; letter-spacing:.02em; text-align:center;
    display:flex; flex-direction:column; align-items:center; gap:.6rem;
    transition:.25s;
  }
  .surface-item:hover{ border-color:var(--gold); color:var(--cream); }
  .surface-item svg{ width:40px; height:40px; stroke:currentColor; transition:.25s; }
  @media(max-width:640px){
    .surface-item{ min-width:90px; }
  }
  /* Pictos "Espaces intérieurs / extérieurs / aquatiques" (page d'accueil,
     sous "Studio et atelier d'art mural") : badges plus allongés que le
     standard .surface-item pour que "Espaces aquatiques" tienne sur une
     seule ligne, demandé explicitement. */
  .stats-caption-pictos .surface-item{ min-width:150px; max-width:190px; }
  /* Sur mobile, les 3 tiennent sur une seule ligne (demandé explicitement) :
     badges rétrécis pour repasser sous la largeur d'écran (le texte du
     libellé peut alors passer sur 2 lignes dans le badge, sans conséquence).
     :not(.stats-caption-pictos-many) — ne s'applique qu'à ce cas à 3 pictos :
     la variante à 7 pictos (page Entreprises & Commerces) serait illisible
     tassée sur une seule ligne, elle passe donc en grille 2 colonnes juste
     après (règle suivante), demandé explicitement. */
  @media(max-width:640px){
    .stats-caption-pictos:not(.stats-caption-pictos-many) .surface-item{ min-width:0; max-width:none; flex:1 1 0; padding:.8rem .4rem; }
    .stats-caption-pictos:not(.stats-caption-pictos-many) .surface-item svg{ width:28px; height:28px; }
    .stats-caption-pictos:not(.stats-caption-pictos-many) .surface-item span{ font-size:.68rem; }
  }
  /* Variante à beaucoup de pictos (7, page Entreprises & Commerces) : grille
     2 colonnes sur mobile plutôt qu'une ligne unique tassée, demandé
     explicitement — chaque badge garde une taille lisible. */
  @media(max-width:640px){
    .stats-caption-pictos-many{ justify-content:center; }
    .stats-caption-pictos-many .surface-item{ min-width:0; max-width:none; flex:0 1 calc(50% - .35rem); padding:.9rem .5rem; }
  }
  /* --- 3 pictogrammes "Mon métier" (index) : mêmes classes .surface-item que
     les surfaces d'intervention de collectivites.html (style graphique +
     animation de tracé identiques, gérés par le même JS générique), mais en
     ligne fixe de 3 (pas de flex-wrap) avec flex-basis rétréci sur mobile
     pour que les 3 tiennent toujours dans la largeur de l'écran. --- */
  .univers-picto-row{
    display:flex;
    justify-content:center;
    gap:1.2rem;
    margin:1.8rem 0 .4rem;
  }
  .univers-picto-row .surface-item{
    flex:0 1 150px;
    min-width:0;
  }
  @media(max-width:640px){
    .univers-picto-row{ gap:.5rem; }
    .univers-picto-row .surface-item{
      flex:1 1 0;
      padding:.6rem .3rem;
      font-size:.64rem;
      gap:.4rem;
    }
    .univers-picto-row .surface-item svg{ width:28px; height:28px; }
    /* L'anneau dépasse de 10px sous la photo sur mobile (voir plus bas) :
       le gap générique ci-dessus (.4rem, 6.4px) est trop court. */
    .univers-picto-row .univers-client-circle{ gap:1.2rem; }
    /* .surface-item{flex:1 1 0} ci-dessus (flex-basis:0, pensé pour les
       anciens badges rectangulaires) écrasait la taille voulue des 3
       ronds : chaque boîte se retrouvait comprimée à une part égale de
       l'espace dispo au lieu de sa taille réelle, la photo débordant
       alors de son propre conteneur (repéré : ronds tassés/superposés).
       flex:0 0 auto fige chaque rond à sa taille propre, sans grandir ni
       rétrécir, pour que les 3 tiennent sur une seule ligne sans jamais
       se chevaucher ni passer à la ligne. */
    .univers-picto-row .univers-client-circle{ flex:0 0 auto; }
  }
  /* Les 3 pictos du haut (.univers-top-ring : Particuliers/Collectivités/
     Entreprises) remplacés par une photo ronde par client — conteneur de
     taille fixe (cover + centré), comme toutes les photos du site, pour
     qu'aucun format ne déforme le rond. */
  .univers-picto-photo{
    display:block;
    width:208px; height:208px;
    flex:none;
    position:relative;
  }
  .univers-picto-photo img{
    width:100%; height:100%;
    border-radius:50%;
    object-fit:cover;
    object-position:var(--bp-x,50%) center;
    display:block;
    transition:transform .3s ease;
  }
  @media(max-width:640px){
    /* En vw plutôt qu'en px fixes (100px) : sur un téléphone réel plus
       étroit que les 375px testés en local, 100px fixes + les écarts fixes
       ne s'adaptaient plus et les ronds/anneaux finissaient par se
       toucher (constaté en ligne). En vw, ronds/écarts/marge (voir
       .univers-picto-row et l'anneau plus bas) restent proportionnels à
       la largeur réelle de l'écran, quel que soit le téléphone. */
    .univers-picto-photo{ width:23vw; height:23vw; }
  }
  /* Juste le rond, plus de cadre carré ni de liseret doré autour (demandé
     explicitement après avoir vu les 3 photos rondes dans leur carte
     .surface-item d'origine) : on retire fond/bordure/marge intérieure,
     .surface-item reste seulement pour la classe JS (déclenchement des
     sous-lignes) et l'apparition en fondu au scroll, partagées avec tous
     les autres badges du site. */
  .univers-client-circle{
    background:none;
    border:none;
    padding:0;
    /* L'anneau (::before plus bas) dépasse de 8px sous la photo : le gap
       hérité de .surface-item (.6rem, ~9.6px) suffisait presque, un peu
       agrandi pour un vrai espace net avec le libellé en dessous. */
    gap:1.2rem;
  }
  .univers-client-circle:hover{ border-color:transparent; }
  /* Repère "c'est cliquable", demandé après avoir retiré le cadre/liseret
     ci-dessus : un anneau doré qui se dessine (même technique que
     .surface-item::after ailleurs sur le site, adaptée en rond) + léger
     zoom de la photo. Positionné en ::before sur .univers-picto-photo
     (la boîte photo elle-même, taille fixe 208/152px) et centré via
     inset, PAS sur .univers-client-circle : ce dernier est un élément
     flex dont la largeur réelle peut légèrement différer de son
     flex-basis (arrondi du moteur flex selon le texte du libellé), ce qui
     décalait le rond de quelques pixels par rapport à la photo — inset
     sur la photo elle-même élimine ce calcul, le rond est alors
     mathématiquement centré sur la photo quel que soit le libellé. Le
     border-radius est passé sur l'<img> (qui se découpe tout seul, pas
     besoin d'overflow:hidden sur le conteneur) pour laisser justement ce
     conteneur héberger l'anneau sans le rogner lui-même. */
  .univers-picto-photo::before{
    content:'';
    position:absolute; inset:-8px;
    border-radius:50%;
    border:2px solid var(--gold);
    pointer-events:none;
    --ring-a:0deg;
    transition:--ring-a .6s ease;
    -webkit-mask-image:conic-gradient(from 180deg, #000 var(--ring-a,0deg), transparent 0);
    mask-image:conic-gradient(from 180deg, #000 var(--ring-a,0deg), transparent 0);
  }
  @media(max-width:640px){
    /* En vw, comme la taille du rond et l'écart de la rangée : garde un
       espace net entre anneaux voisins quelle que soit la largeur réelle
       de l'écran, plutôt qu'un 6px fixe qui pouvait devenir proportion-
       nellement trop grand sur un téléphone étroit et faire se toucher
       les anneaux. */
    .univers-picto-photo::before{ inset:-1.4vw; }
  }
  @media(hover:hover){
    .univers-client-circle:hover .univers-picto-photo img{ transform:scale(1.03); }
    .univers-client-circle:hover .univers-picto-photo::before{ --ring-a:360deg; }
  }
  /* Tactile (pas de survol) : l'anneau se dessine tout seul au scroll, un
     par un de gauche à droite, même délai que le fondu (voir script.js). */
  @media(hover:none){
    .univers-client-circle:nth-child(1) .univers-picto-photo::before{ transition-delay:.15s; }
    .univers-client-circle:nth-child(2) .univers-picto-photo::before{ transition-delay:.55s; }
    .univers-client-circle:nth-child(3) .univers-picto-photo::before{ transition-delay:.95s; }
    .univers-client-circle.si-in .univers-picto-photo::before{ --ring-a:360deg; }
  }
  /* Libellé (Particuliers/Collectivités/Entreprises) : même style que
     l'eyebrow "Mon métier" au-dessus (or, majuscules, même taille). */
  .univers-client-circle span:not(.univers-picto-photo){
    font-family:'DM Sans',sans-serif;
    font-size:.75rem;
    letter-spacing:.28em;
    text-transform:uppercase;
    color:var(--gold);
    font-weight:600;
  }
  /* Sur mobile, ce libellé (ex. "COLLECTIVITÉS") est plus large que son
     rond (100px) à cause du .28em d'écart entre lettres — l'élément se
     retrouve alors plus large que prévu et pousse la rangée hors de
     l'écran / fait chevaucher les libellés voisins. Réduit ici, mobile
     uniquement, pour que chaque libellé reste dans la largeur du rond. */
  @media(max-width:640px){
    .univers-client-circle span:not(.univers-picto-photo){
      font-size:.62rem;
      letter-spacing:.08em;
    }
  }
  /* .univers-picto-row .surface-item{flex:0 1 150px} (plus spécifique que
     .univers-client-circle seul) gagnait toujours et écrasait les ronds à
     150px de large malgré leurs 208px réels — d'où le tassement. Egalé en
     spécificité ici pour que les ronds gardent leur taille de contenu. */
  .univers-picto-row .univers-client-circle{ flex:0 1 auto; }
  /* .section-head limite la largeur à 46ch (colonne de texte) : sur
     ordinateur, où 46ch est bien plus étroit que l'écran, la rangée de
     ronds en sort pour occuper toute la largeur (demandé explicitement)
     via ce hack classique (width:100vw + margin négatif). Réservé à
     l'ordinateur (min-width:641px) : sur mobile ce hack s'est révélé
     instable sur téléphone réel (barre d'adresse dynamique, scrollbar
     virtuelle... — constaté en ligne : rangée décalée à droite, contenu
     rogné) alors que 46ch y dépasse de toute façon la largeur de l'écran
     — la rangée y est donc déjà quasi pleine largeur nativement, sans
     avoir besoin d'en sortir. */
  @media(min-width:641px){
    /* Scopé à #univers (rangée des 3 ronds photo tout en haut) : ce hack
       de sortie de colonne (46ch) ne doit pas s'appliquer à la rangée de
       pictos texte réutilisée sous chaque paire de flip-cards
       (.flip-group-links .univers-picto-row, "Découvrir votre univers"),
       qui matchait aussi ce sélecteur générique et se retrouvait décalée
       à droite (position:relative;left:50% calculé sur un autre
       conteneur/largeur que prévu) — bug constaté, corrigé en resserrant
       le sélecteur à la rangée d'origine. */
    #univers .univers-picto-row:not(.univers-picto-subrow){
      width:100vw;
      position:relative;
      left:50%;
      margin-left:-50vw;
      gap:12.5vw;
    }
  }
  @media(max-width:640px){
    /* En vw (pas en rem fixe) pour la même raison que la taille des ronds
       ci-dessus : constaté en ligne sur un téléphone réel, des valeurs
       fixes ne s'adaptaient pas à toutes les largeurs d'écran et les
       ronds finissaient par se toucher. gap élargi à 7vw / marge réduite à
       3vw (au lieu de 4vw / 5vw) : plus d'écart réel entre les ronds, moins
       de marge inutilisée sur les côtés, demandé explicitement — toujours
       largement sous les 100vw disponibles (3×23vw de rond + 2×7vw d'écart
       + 2×3vw de marge = 89vw). */
    #univers .univers-picto-row:not(.univers-picto-subrow){ gap:7vw; padding:0 3vw; box-sizing:border-box; }
  }
  /* Lien direct (Collectivités, une seule page) vs sous-ligne de 3 pictos au
     clic (Particuliers/Entreprises, plusieurs pages à venir chacun) — la
     sous-ligne réutilise .univers-picto-row (mêmes .surface-item, même
     taille/alignement que la ligne du haut, demandé explicitement après un
     essai en menu déroulant flottant écarté) plutôt qu'une nouvelle classe.
     .surface-item peut donc être un <a> ou un <div>, d'où text-decoration/
     color repris explicitement pour un rendu identique. */
  a.surface-item{ text-decoration:none; color:var(--cream-dim); }
  a.surface-item:hover{ text-decoration:none; }
  .univers-picto-trigger{ cursor:pointer; }
  .univers-picto-trigger.active{ border-color:var(--gold); color:var(--cream); }
  .univers-picto-subrow{
    display:none;
    margin-top:.4rem;
  }
  .univers-picto-subrow.open{ display:flex; }
  /* Au survol, les pictos de la sous-ligne (clic Particuliers/Entreprises),
     ceux sous chaque paire de flip-cards (.flip-group-links) ET les 3 pictos
     du haut de "Mon métier" (.univers-top-ring) gardent leur cadre
     rectangulaire, avec le même liseret doré "tournant" que le bouton Devis
     du header (.header-cta::after) au lieu du simple changement de couleur
     de bordure instantané — demandé explicitement (retour au cadre carré
     après un essai en rond ; les 3 pictos du haut alignés sur ce même
     comportement au survol après plusieurs essais d'un déclenchement
     automatique). */
  .univers-picto-subrow .surface-item,
  .flip-group-links .surface-item:not(.univers-client-circle),
  .univers-top-ring,
  .surfaces-grid .surface-item{ position:relative; }
  .univers-picto-subrow .surface-item:hover,
  .flip-group-links .surface-item:hover:not(.univers-client-circle),
  .univers-top-ring:hover,
  .surfaces-grid .surface-item:hover{ border-color:var(--line); }
  /* :not(.univers-client-circle) sur les 3 sélecteurs .flip-group-links
     ci-dessus/dessous : les pictos "Choisir votre univers" repris en rond-
     photo (mêmes classes que "Mon métier", voir .univers-client-circle plus
     bas) héritaient aussi de ce cadre rectangulaire animé — un rectangle qui
     se dessinait par-dessus le rond, sans rapport, demandé explicitement à
     retirer. Le rond garde son propre anneau circulaire (.univers-picto-
     photo::before plus bas), pas celui-ci. */
  .univers-picto-subrow .surface-item::after,
  .flip-group-links .surface-item:not(.univers-client-circle)::after,
  .univers-top-ring::after,
  .surfaces-grid .surface-item::after{
    content:'';
    position:absolute; inset:-1px;
    border:1.4px solid var(--gold);
    pointer-events:none;
    --ring-a:0deg;
    transition:--ring-a .6s ease;
    -webkit-mask-image:conic-gradient(from 180deg, #000 var(--ring-a,0deg), transparent 0);
    mask-image:conic-gradient(from 180deg, #000 var(--ring-a,0deg), transparent 0);
  }
  .univers-picto-subrow .surface-item:hover::after,
  .flip-group-links .surface-item:not(.univers-client-circle):hover::after,
  .univers-top-ring:hover::after,
  .surfaces-grid .surface-item:hover::after{ --ring-a:360deg; }
  /* En plus du survol ci-dessus (inchangé, tous écrans) : sur tactile
     uniquement (hover:none, pas de survol possible), les 3 pictos du haut
     ET les 3 pictos de chacune des rangées "Découvrir votre univers"
     (.flip-group-links, une par paire de flip-cards Particuliers/
     Collectivités/Entreprises) s'allument aussi tout seuls au scroll, un
     par un (1er enfant du HTML en premier, .15s/.45s/.75s), et restent
     figés dorés une fois leur tour terminé (classe .si-in posée une seule
     fois par l'IntersectionObserver plus bas, jamais retirée), demandé
     explicitement. Même réglage (1er enfant en premier) unifié sur les deux
     groupes après un premier essai en sens inverse sur .flip-group-links. */
  @media(hover:none){
    .univers-top-ring:nth-child(1)::after,
    .flip-group-links .surface-item:not(.univers-client-circle):nth-child(1)::after{ transition-delay:.15s; }
    .univers-top-ring:nth-child(2)::after,
    .flip-group-links .surface-item:not(.univers-client-circle):nth-child(2)::after{ transition-delay:.45s; }
    .univers-top-ring:nth-child(3)::after,
    .flip-group-links .surface-item:not(.univers-client-circle):nth-child(3)::after{ transition-delay:.75s; }
    .univers-top-ring.si-in::after,
    .flip-group-links .surface-item:not(.univers-client-circle).si-in::after{ --ring-a:360deg; }
    /* .surfaces-grid ("intervention", page Collectivités) : nombre
       d'éléments par ligne variable selon la largeur (flex-wrap), pas fixe
       comme les 3 pictos ci-dessus — délai calculé en JS par ligne réelle
       (voir script.js) et posé en --ring-delay sur chaque item, plutôt que
       des nth-child en dur. Gauche à droite PUIS ligne par ligne (une ligne
       termine son tour avant que la suivante commence), demandé
       explicitement. */
    .surfaces-grid .surface-item::after{ transition-delay:var(--ring-delay, 0s); }
    .surfaces-grid .surface-item.si-in::after{ --ring-a:360deg; }
  }
  /* Apparition au scroll des pictogrammes "Surfaces d'intervention" : même
     esprit dynamique que le compteur animé des stats (26/300+/4) juste
     au-dessus, mais adapté à des icônes plutôt qu'à des chiffres — chaque
     carte monte en fondu en cascade (délai croissant posé en JS) ET le
     tracé du pictogramme se dessine progressivement (stroke-dashoffset,
     longueur réelle de chaque tracé calculée en JS via getTotalLength). */
  .surface-item{
    opacity:0;
    transform:translateY(26px) scale(.9);
  }
  .surface-item.si-in{
    animation:surfaceItemIn .7s cubic-bezier(.16,.84,.44,1) forwards;
  }
  @keyframes surfaceItemIn{
    to{ opacity:1; transform:translateY(0) scale(1); }
  }
  .surface-item svg path, .surface-item svg rect, .surface-item svg ellipse{
    stroke-dasharray:var(--len, 260);
    stroke-dashoffset:var(--len, 260);
  }
  .surface-item.si-in svg path, .surface-item.si-in svg rect, .surface-item.si-in svg ellipse{
    animation:surfaceIconDraw 1.1s cubic-bezier(.65,0,.35,1) .18s forwards;
  }
  @keyframes surfaceIconDraw{
    to{ stroke-dashoffset:0; }
  }
  @media(prefers-reduced-motion:reduce){
    .surface-item{ opacity:1; transform:none; }
    .surface-item.si-in{ animation:none; }
    .surface-item svg path, .surface-item svg rect, .surface-item svg ellipse{ stroke-dasharray:none; stroke-dashoffset:0; }
    .surface-item.si-in svg path, .surface-item.si-in svg rect, .surface-item.si-in svg ellipse{ animation:none; }
  }
  /* --- Photo de fond permanente, entre "Studio et atelier d'art mural" et
     "Mon métier" (page d'accueil) : vraiment en arrière-plan (position:fixed,
     z-index négatif), immobile à l'écran. .parallax-spacer réserve la place
     dans le flux normal du document (position:fixed sort .parallax-band du
     flux : sans cet espace réservé juste avant, "Mon métier" arriverait
     immédiatement à la suite de "Studio et atelier", collé sans le moindre
     interstice — la photo, toujours peinte derrière, n'aurait alors jamais
     une seule ligne d'écran non recouverte où apparaître). Tant que ce
     bandeau transparent défile à l'écran, rien d'opaque ne la recouvre : elle
     est visible. Une fois ce bandeau franchi, "Mon métier" (fond opaque, via
     .section ci-dessous) arrive et la recouvre progressivement en montant
     depuis le bas de l'écran — le "peu à peu" vient simplement du défilement
     normal, sans JS. Elle reste recouverte au-delà puisque toutes les
     sections suivantes ont elles aussi un fond opaque. Deux essais
     précédents écartés : background-attachment:fixed (peu fiable sur mobile/
     iOS — l'utilisateur voyait la photo défiler avec le reste au lieu de
     rester fixe) et position:sticky dans une bande dédiée (fonctionnait,
     mais donnait une transition ponctuelle plutôt qu'un vrai fond de page
     qui reste recouvert une fois passé, comme demandé explicitement). */
  .parallax-spacer{ height:67.39vh; }
  .parallax-band{
    position:fixed;
    inset:0;
    z-index:-1;
    background-size:cover;
    background-position:center;
    background-repeat:no-repeat;
    /* Masqué par défaut : quand une page a plusieurs bandeaux (.parallax-
       band), tous partagent le même z-index -1 plein écran — sans ceci,
       le dernier du DOM recouvrirait en permanence tous les autres, quelle
       que soit la position de scroll (bug constaté : "Tabarly sur les
       deux" sur collectivites.html une fois un 2e bandeau ajouté). Rendu
       visible uniquement pendant que SON PROPRE .parallax-spacer est à
       l'écran, via script.js (IntersectionObserver, classe .is-active). */
    visibility:hidden;
  }
  .parallax-band.is-active{ visibility:visible; }
  /* Hauteur du bandeau réduite de 40% sur mobile (65vh → 39vh), demandé
     explicitement — générique, s'applique à tous les bandeaux photo
     (#tabarlyBand, #marianneBand...). Le cadrage précis (size/position),
     lui, est propre à chaque photo : voir les règles #tabarlyBand /
     #marianneBand ci-dessous plutôt qu'une règle .parallax-band générique. */
  @media(max-width:560px){
    .parallax-spacer{ height:24.96vh; }
  }
  /* Chaque bandeau ci-dessous utilise var(--bp-x, VALEUR) pour la composante
     horizontale de background-position : c'est la variable que pilote en
     direct l'outil "Recadrer les photos (gauche/droite)" de la barre
     d'outils (edit-toolkit.js), disponible uniquement dans l'aperçu
     smartphone. Sans réglage manuel, VALEUR (le cadrage déjà choisi
     ci-dessous) s'applique normalement. */
  /* --- #marianneBand (« Citoyen », Marianne, Trémel) : le portrait est sur
     la partie droite de la photo (pas au centre) — recadré sur la droite
     sur mobile/tablette pour ne jamais le couper, comme #tabarlyBand. --- */
  @media(max-width:900px){
    #marianneBand{ background-position:right center; }
  }
  /* Zoom réduit de 40% sur mobile par rapport au cover d'origine (~324% de
     large en cover sur cet écran étroit/haut vs cette photo panoramique →
     195%), aligné sur la convention générale des 40% (auparavant réduit de
     50%). */
  @media(max-width:560px){
    #marianneBand{ background-size:195% auto; background-position:var(--bp-x,100%) center; }
  }
  /* #guerlesquinGarageBand (ancien garage, pompe à essence vintage) : zoom
     réduit de 40% par rapport au cover d'origine (~326% → 195%), aligné sur
     la convention générale des 40% (auparavant réduit de 50%, comme
     #marianneBand) — repositionnée (73% 28%) pour montrer la pompe à
     essence bien dégagée (pigeon et cadran complets, marge tout autour) ET
     la voiture ancienne ensemble, avec un peu de la vitrine bleu-vert du
     garage à droite de la pompe, sans le pilier bleu du bord droit de la
     photo, tout en laissant apparaître les plantes grimpantes à gauche de
     la voiture. */
  @media(max-width:560px){
    #guerlesquinGarageBand{ background-size:195% auto; background-position:var(--bp-x,73%) 28%; }
  }
  /* #equipementsTabarlyBand (juste avant "Services & institutions") :
     réutilise la même photo qu'#tabarlyBand (portrait d'Éric Tabarly,
     atelier, Morlaix), demandé explicitement. Zoom réduit de 40% sur mobile
     par rapport au cover d'origine (~429% en cover sur cet écran étroit/
     haut → 257%, cadrage propre à ce bandeau, différent des 172% du
     bandeau d'origine), calée à droite (portrait) et 45% en hauteur. */
  @media(max-width:560px){
    #equipementsTabarlyBand{ background-size:257% auto; background-position:var(--bp-x,100%) 45%; }
  }
  /* #locquirecBand (arche trompe-l'œil, port) : zoom réduit de 40% sur
     mobile par rapport au cover d'origine (~385% de large en cover sur cet
     écran étroit/haut vs cette photo large → 231%), aligné sur la
     convention générale des 40% (auparavant réduit de 60%). */
  @media(max-width:560px){
    #locquirecBand{ background-size:231% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #compaySegundoBand (fresque street art, portrait de la Marianne à Morlaix,
     2400x1349, juste avant la section "L'art du portrait") : zoom réduit de 40%
     sur mobile par rapport au cover d'origine (~385% → 231%), centrée. */
  @media(max-width:560px){
    #compaySegundoBand{ background-size:231% auto; background-position:var(--bp-x,50%) center; }
  }
  /* Sur ordinateur, ce bandeau commence sous le header (--hdr-h, voir
     script.js) : le haut de la photo n'est plus coupé par le header. */
  @media(min-width:561px){
    #compaySegundoBand{ top:var(--hdr-h, 84px); }
  }
  /* #marinAustralieBand (portrait du jeune marin, École des Mousses, juste
     après la section "Transformateurs électriques") : zoom réduit de 40%
     sur mobile par rapport au cover d'origine (~385% de large en cover sur
     cet écran étroit/haut vs cette photo large → 231%), demandé
     explicitement (après un aller-retour avec un +20% entre-temps, revenu
     en arrière). */
  @media(max-width:560px){
    #marinAustralieBand{ background-size:231% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #perrosPiscineBand / #vannesNominoeBand (même format 2400x1580) : zoom
     réduit de 40% sur mobile par rapport au cover d'origine (~329% de large
     en cover sur cet écran étroit/haut → 197%), convention générale. */
  @media(max-width:560px){
    #perrosPiscineBand, #vannesNominoeBand{ background-size:197% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #pleybenToileBand (2400x1595, quasi identique) : zoom réduit de 40% sur
     mobile par rapport au cover d'origine (~326% → 196%), convention
     générale. */
  @media(max-width:560px){
    #pleybenToileBand, #pleybenToileBand2{ background-size:196% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #lannionFleursBand (2400x1599) : zoom réduit de 30% sur mobile (pas 40%,
     demandé explicitement pour ce bandeau) par rapport au cover d'origine
     (~326% → 228%). */
  @media(max-width:560px){
    #lannionFleursBand{ background-size:228% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #plouescatCinemaBand (4912x3264, même ratio) : zoom réduit de 40% sur
     mobile par rapport au cover d'origine (~326% → 196%), convention
     générale. */
  @media(max-width:560px){
    #plouescatCinemaBand{ background-size:196% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #morlaixAtelierBand (2400x1601, même ratio) : zoom réduit de 40% sur
     mobile par rapport au cover d'origine (~326% → 195%), convention
     générale. */
  @media(max-width:560px){
    #morlaixAtelierBand{ background-size:195% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #rennesBanquePopBand (2400x1349) : zoom réduit de 40% sur mobile par
     rapport au cover d'origine (~385% → 231%), convention générale. */
  @media(max-width:560px){
    #rennesBanquePopBand{ background-size:231% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #banquePopulaireBand (4912x2760, même ratio que 2400x1349) : zoom réduit
     de 40% sur mobile par rapport au cover d'origine (~385% → 231%). */
  @media(max-width:560px){
    #banquePopulaireBand{ background-size:231% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #prestationSanitaireBand (page hôtellerie, 2400x1580) : même convention,
     zoom réduit de 40% sur mobile. */
  @media(max-width:560px){
    #prestationSanitaireBand{ background-size:197% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #piscinePerrosGuirecBand (page hôtellerie, 2400x1580) : même convention,
     zoom réduit de 40% sur mobile. */
  @media(max-width:560px){
    #piscinePerrosGuirecBand{ background-size:197% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #piscineGuingampBand (page hôtellerie, 2400x1349, même ratio que
     #histoireRondeBand) : même convention, zoom réduit de 40% sur mobile. */
  @media(max-width:560px){
    #piscineGuingampBand, #piscineQuimperBand, #pignonFacadeBand, #mursMitoyensBand, #mursGaragesBand, #anatomieTeaserBand, #ploumanachSalonBand, #ploumanachSalonBand2{ background-size:231% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #locationStandingCarantecBand (page hôtellerie, 2400x1580) : même
     convention, zoom réduit de 40% sur mobile. */
  @media(max-width:560px){
    #locationStandingCarantecBand{ background-size:197% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #carnacFacadeBand (page hôtellerie, 2400x1580) : même convention, zoom
     réduit de 40% sur mobile. */
  @media(max-width:560px){
    #carnacFacadeBand{ background-size:197% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #awenNominoeBand (2400x1580) : même convention, zoom réduit de 40% sur
     mobile par rapport au cover d'origine (~329% → 197%). */
  @media(max-width:560px){
    #awenNominoeBand{ background-size:197% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #banquePopBand (2400x1595) : même convention, zoom réduit de 40% sur
     mobile par rapport au cover d'origine (~326% → 196%). */
  @media(max-width:560px){
    #banquePopBand{ background-size:196% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #breizhOdysseeBand (2400x1600) : même convention, zoom réduit de 40% sur
     mobile par rapport au cover d'origine. */
  @media(max-width:560px){
    #breizhOdysseeBand{ background-size:196% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #fleurDePotBand (2400x1580) : même convention, zoom réduit de 40% sur
     mobile par rapport au cover d'origine (~329% → 197%). */
  @media(max-width:560px){
    #fleurDePotBand{ background-size:197% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #fleurDePotBand2 (page commerces-entreprises, photo différente de
     #fleurDePotBand) : cadrage à partir du bord gauche, même convention de
     réduction de 40% sur mobile. */
  #fleurDePotBand2{ background-position:left center; }
  @media(max-width:560px){
    #fleurDePotBand2{ background-size:197% auto; background-position:left center; }
  }
  /* #entrPlouescatBand (2400x1349) : même convention, zoom réduit de 40% sur
     mobile par rapport au cover d'origine (~385% → 231%). */
  @media(max-width:560px){
    #entrPlouescatBand{ background-size:231% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #huitrierBand (2400x1580) : même convention, zoom réduit de 40% sur
     mobile par rapport au cover d'origine (~329% → 197%). */
  @media(max-width:560px){
    #huitrierBand{ background-size:197% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #plouescatNacelleBand (2400x1349) : même convention, zoom réduit de 40%
     sur mobile par rapport au cover d'origine (~385% → 231%). */
  @media(max-width:560px){
    #plouescatNacelleBand{ background-size:231% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #histoireRondeBand (2400x1349, même ratio) : même convention, zoom
     réduit de 40% sur mobile par rapport au cover d'origine (~385% → 231%). */
  @media(max-width:560px){
    #histoireRondeBand{ background-size:231% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #atelier29Band (2400x1595, même ratio) : même convention, zoom réduit
     de 40% sur mobile par rapport au cover d'origine (~326% → 196%). */
  @media(max-width:560px){
    #atelier29Band{ background-size:196% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #pizzeriaRomaBand (2400x1580) : même convention, zoom réduit de 40%
     sur mobile par rapport au cover d'origine (~329% → 197%). */
  @media(max-width:560px){
    #pizzeriaRomaBand{ background-size:197% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #pleybenToileBand, #pleybenToileBand2 (2400x1595, même ratio que
     #banquePopBand) : même convention, zoom réduit de 40% sur mobile. */
  @media(max-width:560px){
    #pleybenToileBand, #pleybenToileBand2{ background-size:196% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #tomCafeBand, #cliniqueBaieBand (2400x1580, même ratio que
     #pizzeriaRomaBand) : même convention. */
  @media(max-width:560px){
    #tomCafeBand, #cliniqueBaieBand{ background-size:197% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #climbUpBand (2400x1574) : même convention, zoom réduit de 40% sur
     mobile par rapport au cover d'origine (~330% → 198%). */
  @media(max-width:560px){
    #climbUpBand{ background-size:198% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #gwennHaDuBand (2048x2039, quasi carré) : même convention, zoom
     réduit de 40% sur mobile par rapport au cover d'origine (~217% → 130%).
     Cadrage demandé à partir du bord gauche de la photo. */
  @media(max-width:560px){
    #gwennHaDuBand{ background-size:130% auto; background-position:left center; }
  }
  /* #escaleExotiqueBand (2400x1595, même ratio que #banquePopBand) : même
     convention, zoom réduit de 40% sur mobile. */
  @media(max-width:560px){
    #escaleExotiqueBand{ background-size:196% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #metamorphoseCallacBand (2400x1594, même ratio) : même convention. */
  @media(max-width:560px){
    #metamorphoseCallacBand{ background-size:196% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #metamorphosePerrosBand : même photo que #perrosPiscineBand, on
     réutilise la même valeur mobile. */
  @media(max-width:560px){
    #metamorphosePerrosBand{ background-size:197% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #lannionFlowersBand : même photo que #lannionFleursBand, on réutilise
     la même valeur mobile. */
  @media(max-width:560px){
    #lannionFlowersBand{ background-size:228% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #vascoDeGamaBand (2400x1349, même ratio que #histoireRondeBand) :
     même convention, zoom réduit de 40% sur mobile. */
  @media(max-width:560px){
    #vascoDeGamaBand{ background-size:231% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #glazSeaBand (2400x1349, même ratio que #histoireRondeBand) : même
     convention, zoom réduit de 40% sur mobile. */
  @media(max-width:560px){
    #glazSeaBand{ background-size:231% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #jugeauElagageBand (2400x1349, même ratio que #histoireRondeBand) :
     même convention, zoom réduit de 40% sur mobile. */
  @media(max-width:560px){
    #jugeauElagageBand{ background-size:231% auto; background-position:var(--bp-x,50%) center; }
  }
  /* Page hôtellerie : mêmes conventions de réduction de 40% sur mobile. */
  @media(max-width:560px){
    #evasionPolynesienneBand, #maisonPecheurBand, #radeDeBrestBand, #piscineCarantecTableauBand, #piscinePaimpolBand, #terrassePatioBand, #chambreBand, #escalierMorlaixSaharaBand, #spaTropicalBand, #salleAMangerCarantecBand, #piscineCrozonBand, #cuisineQuimperBand{ background-size:197% auto; background-position:var(--bp-x,50%) center; }
    #campingMouettesBand, #plouescatBarBand, #plouescatBarBand2, #roscoffIleBatzBand{ background-size:195% auto; background-position:var(--bp-x,50%) center; }
    #maisonBonheurBand, #fermePedagogiqueBand, #locquirecEscalierBand{ background-size:231% auto; background-position:var(--bp-x,50%) center; }
    #capPhareBand{ background-size:100% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #warenghemBand (2400x1595) : background-size en pourcentage (cover
     d'origine sur desktop) au lieu du mot-clé "cover", pour que l'outil
     de recadrage (repoBandInfo, edit-toolkit.js) puisse calculer une marge
     de glissement (il renvoie toujours null avec "cover", non numérique).
     105% sur ordinateur (le cover réel y est ~100% avec ce ratio de photo,
     105% laisse une petite marge de sécurité). Sur mobile, réduit de 40% par
     rapport au cover d'origine (326% × 0.6 ≈ 196%), demandé explicitement. */
  #warenghemBand{ background-size:105% auto; background-position:var(--bp-x,50%) center; }
  @media(max-width:560px){
    #warenghemBand{ background-size:196% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #morlaixStreetArtBand (4912x2760, même ratio) : zoom réduit de 40% sur
     mobile par rapport au cover d'origine (~385% → 231%), convention
     générale. */
  @media(max-width:560px){
    #morlaixStreetArtBand{ background-size:231% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #morlaixTrompeOeilBand (1024x683, même ratio ~1.5) : zoom réduit de 40%
     sur mobile par rapport au cover d'origine (~326% → 195%), convention
     générale. */
  @media(max-width:560px){
    #morlaixTrompeOeilBand{ background-size:195% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #plageOceanBand (4912x2760, même ratio qu'#morlaixStreetArtBand) : zoom
     réduit de 40% sur mobile par rapport au cover d'origine (~385% → 231%),
     convention générale. */
  @media(max-width:560px){
    #plageOceanBand{ background-size:231% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #gwendalPortraitBand (1260x805) : zoom réduit de 40% sur mobile par
     rapport au cover d'origine (~339% → 203%), convention générale. */
  @media(max-width:560px){
    #gwendalPortraitBand{ background-size:203% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #presentoirOuestFranceBand (3264x2448, ratio 4:3) : zoom réduit de 40%
     sur mobile par rapport au cover d'origine (~289% → 173%), convention
     générale. */
  @media(max-width:560px){
    #presentoirOuestFranceBand{ background-size:173% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #tremelMairieBand (même format 2400x1212 qu'#tabarlyBand) : zoom réduit
     de 40% sur mobile par rapport au cover d'origine (~429% de large en
     cover sur cet écran étroit/haut → 257%), convention générale. */
  @media(max-width:560px){
    #tremelMairieBand{ background-size:257% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #edernCameraBand (chardonneret sur appareil photo ancien, livre ouvert,
     médiathèque d'Edern, juste avant "Le trompe-l'œil mural") : demandé
     explicitement visible dans toute sa largeur — background-size:100%
     (au lieu d'un cover qui déborde toujours en largeur sur cet écran
     étroit/haut), quitte à laisser du noir au-dessus/en dessous (déjà la
     couleur du site). */
  @media(max-width:560px){
    #edernCameraBand{ background-size:100% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #edernMediathequeBand (façade médiathèque d'Edern) : zoom réduit de 40%
     sur mobile par rapport au cover d'origine (~325% de large en cover sur
     cet écran étroit/haut vs cette photo large → 195%), recentré sur le
     garçon qui lit (~61,5% de la largeur de la photo d'origine, pas le
     centre géométrique de l'image) plutôt que sur le bord gauche, demandé
     explicitement. */
  @media(max-width:560px){
    #edernMediathequeBand{ background-size:195% auto; background-position:var(--bp-x,74%) center; }
  }
  /* #lannionFlowersBand (décor floral, façade commerce, Lannion/Plestin,
     juste avant "Orchestrez vos murs") : un essai à 195% (40% de réduction,
     alignée sur la convention générale) élargissait trop le cadre et
     montrait plusieurs fleurs à la fois au lieu d'une seule bien isolée —
     revenu volontairement au cover brut d'origine (pas de réduction ici),
     qui recadre nettement sur une fleur (la tulipe), comme demandé
     explicitement. Position tout de même rendue réglable (--bp-x) pour
     l'outil de recadrage à la main, taille cover inchangée. */
  @media(max-width:560px){
    #lannionFlowersBand{ background-position:var(--bp-x,50%) center; }
  }
  /* #clederMapBand (fresque monumentale en cours, échafaudage, Morlaix,
     juste avant "Monumentale") : photo au format portrait (contrairement
     aux autres bandeaux, presque tous en format large) — demandé
     explicitement en pleine largeur sur TOUS les écrans (pas seulement
     mobile) : background-size:100% (au lieu d'un cover qui, pour ce format
     portrait précis, peut légèrement déborder en largeur), quitte à laisser
     du noir au-dessus/en dessous. Règle non limitée à @media(max-width),
     volontairement. */
  #clederMapBand{ background-size:100% auto; background-position:var(--bp-x,50%) center; }
  /* #perrosGuirecPiscineBand (trompe-l'œil tropical, piscine, Quimper) :
     zoom réduit de 40% sur mobile par rapport au cover d'origine (~385% de
     large en cover sur cet écran étroit/haut vs cette photo large → 231%),
     demandé explicitement. */
  @media(max-width:560px){
    #perrosGuirecPiscineBand{ background-size:231% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #pleybenMarianneBand (portrait street art de la Marianne, lycée
     professionnel de Pleyben, juste avant "Métamorphose") : zoom réduit de
     40% sur mobile par rapport au cover d'origine (~329% de large en cover
     sur cet écran étroit/haut vs cette photo large → 197%), demandé
     explicitement. Réduit encore de 20% ensuite (197% → 158%). */
  @media(max-width:560px){
    #pleybenMarianneBand{ background-size:158% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #picassoMorlaixBand (portrait street art de Pablo Picasso, port de
     Morlaix) : la photo cadre large (garage + sculpture), le portrait
     n'occupe qu'une bande centrale — taille réduite à 150% et repositionnée
     (62% 45%) pour que le portrait ENTIER (chapeau à menton) tienne dans le
     cadre sur mobile, quitte à laisser du noir au-dessus/en dessous (déjà la
     couleur du site), demandé explicitement après un essai à 228% qui
     coupait le haut du chapeau.
     Aligné ensuite sur la convention générale des 40% (195%, au lieu des
     150% ci-dessus) : à ce zoom plus fort, chapeau ET menton ne tiennent
     plus tous les deux dans le cadre en même temps (repositionné à 58% 33%
     pour privilégier chapeau + œil + moustache ; menton légèrement coupé —
     compromis inévitable à 40% sur cette photo précise). */
  @media(max-width:560px){
    #picassoMorlaixBand{ background-size:195% auto; background-position:var(--bp-x,58%) 33%; }
  }
  /* #plouescatCinemaBand (fresque monumentale de Plouescat peinte depuis une
     nacelle, 2400x1349, juste avant "Formats king size") : zoom réduit de 40%
     sur mobile par rapport au cover d'origine (~385% → 231%), centrée. */
  @media(max-width:560px){
    #plouescatCinemaBand{ background-size:231% auto; background-position:var(--bp-x,50%) center; }
  }
  /* Sur ordinateur, ce bandeau commence sous le header (--hdr-h, voir
     script.js) : l'homme sur la nacelle, tout en haut de la photo, était
     masqué par le header. */
  @media(min-width:561px){
    #plouescatCinemaBand{ top:var(--hdr-h, 84px); }
  }
  /* #morlaixGraffeurBand (pots de peinture, palette de l'artiste, juste avant
     la FAQ collectivités) : zoom réduit de 40% sur mobile par rapport au
     cover d'origine (~385% en cover sur cet écran étroit/haut → 231%). */
  @media(max-width:560px){
    #morlaixGraffeurBand{ background-size:231% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #atelierMorlaixBand (bombes de peinture et toile de fleurs de
     frangipanier, chantier du lycée de Pleyben) : zoom réduit de 40% sur
     mobile par rapport au cover d'origine (~326% de large en cover sur cet
     écran étroit/haut vs cette photo large → 196%), position par défaut
     (centrée) conservée avec la nouvelle photo. */
  @media(max-width:560px){
    #atelierMorlaixBand{ background-size:196% auto; background-position:var(--bp-x,50%) center; }
  }
  /* #pleybenLyceeBand (fresque street art, décoration du lycée de Pleyben,
     avant la section Identité visuelle/Surfaces d'intervention) : réduit
     de 40% sur mobile par rapport au cover d'origine (~325% en cover sur
     cet écran étroit/haut → 195%), calée à 59% pour garder le portrait de
     l'homme avec les feuilles/fleurs roses sur la droite du cadre (reste
     de la fresque panoramique visible à gauche), sans montrer le globe
     terrestre à l'extrême droite de la photo. */
  @media(max-width:560px){
    #pleybenLyceeBand{ background-size:195% auto; background-position:var(--bp-x,59%) center; }
  }
  /* "Mon métier"/"philosophie" (#univers, juste après le bandeau photo) :
     padding-top réduit pour que le titre remonte plus près du haut de la
     fenêtre au lieu de laisser le padding standard (7rem, .section) créer
     un grand vide noir sous la photo. Même bandeau photo (Tabarly) sur
     index.html (.page-home) et collectivites.html (.page-coll, ex-anneau
     3D "Un mur vide n'est pas une fatalité", remplacé par la même photo de
     fond avec le même comportement, demandé explicitement). */
  .page-home #univers, .page-coll #univers{ padding-top:3rem; }
  /* .stats-caption utilise --black-soft partout ailleurs sur le site —
     juste au-dessus du bandeau photo, elle doit matcher son noir
     (.parallax-band/#univers, --black) pour une transition uniforme, sur
     les deux pages qui ont désormais ce bandeau. */
  .page-home .stats-caption, .page-coll .stats-caption{ background:var(--black); }
  /* Sur mobile, le trait fin sous .stats-caption est retiré (demandé
     explicitement sur la page d'accueil) — border-top conservée. */
  @media(max-width:560px){
    .page-home .stats-caption{ border-bottom:none; }
  }
  .stats-chevron{
    color:var(--gold);
    display:inline-flex;
    transition:color .3s ease;
    animation:scrollBounce 2s ease-in-out infinite;
  }
  .stats-chevron:hover{ color:var(--gold-light); }
  @keyframes scrollBounce{
    0%,100%{ transform:translateY(0); opacity:.55; }
    50%{ transform:translateY(6px); opacity:1; }
  }
  /* Même chevron, repositionné en bas du hero plein écran plutôt qu'inline
     dans .stats-caption (demandé explicitement, pour indiquer de scroller
     une fois la photo plein écran affichée). */
  .hero-scroll-chevron{
    position:absolute;
    left:50%; bottom:1.8rem;
    transform:translateX(-50%);
    z-index:2;
    /* Apparaît en tout dernier (demandé explicitement), une fois le burger
       affiché (6.6s + .4s) — remplace l'animation scrollBounce héritée de
       .stats-chevron par une version qui combine le centrage horizontal
       (translateX(-50%)) et le rebond, puisqu'une animation sur "transform"
       remplace entièrement la valeur de base pendant qu'elle tourne (sans
       ça, le centrage était perdu dès que le rebond démarrait). */
    opacity:0;
    animation:heroChevronIn .4s ease 7s forwards, heroChevronBounce 2s ease-in-out 7s infinite;
  }
  @keyframes heroChevronIn{
    to{ opacity:1; }
  }
  @keyframes heroChevronBounce{
    0%,100%{ transform:translateX(-50%) translateY(0); }
    50%{ transform:translateX(-50%) translateY(6px); }
  }

  /* ============ LOGOS CLIENTS ============ */
  .logos-strip{
    padding:2.6rem 5vw;
    border-bottom:1px solid var(--line);
    text-align:center;
    /* Poursuit l'alternance --black/--black-soft des sections précédentes
       (#presse juste avant est en --black-soft) : sans fond propre, cette
       section restait transparente et rompait le motif. */
    background:var(--black);
  }
  /* Idem : ferme l'alternance --black/--black-soft (elle suit .logos-strip,
     lui-même en --black). */
  #mentions-legales{ background:var(--black-soft); }
  .logos-strip-label{
    display:block;
    font-size:.7rem;
    letter-spacing:.2em;
    text-transform:uppercase;
    color:var(--gold);
    margin-bottom:1.6rem;
  }
  .logos-strip-row{
    display:flex;
    flex-wrap:wrap;
    justify-content:center;
    align-items:center;
    gap:2.8rem;
    max-width:1100px;
    margin:0 auto;
  }
  .logos-strip-row + .logos-strip-row{ margin-top:2.2rem; }
  .logos-strip-row:nth-of-type(2){ margin-top:1.4rem; }
  .logo-placeholder{
    height:44px;
    min-width:110px;
    display:flex; align-items:center; justify-content:center;
    color:var(--cream-dim);
    font-size:.68rem;
    letter-spacing:.05em;
    text-transform:uppercase;
    border:1px dashed var(--line);
    padding:0 1rem;
    opacity:.6;
    filter:grayscale(1);
    transition:.3s;
  }
  .logo-placeholder:hover{opacity:1; filter:grayscale(0);}
  /* Logos clients réels : carte blanche pour rester lisibles quelle que soit
     la couleur du logo (texte sombre, traits fins...) sur le fond sombre du
     site — même traitement gris/couleur au survol que les placeholders. */
  .trust-logo{
    height:44px;
    display:flex; align-items:center; justify-content:center;
    background:#fff;
    border-radius:6px;
    padding:.5rem 1.1rem;
    opacity:.7;
    filter:grayscale(1);
    transition:.3s;
  }
  .trust-logo:hover{opacity:1; filter:grayscale(0);}
  .trust-logo img{ max-height:100%; max-width:130px; width:auto; height:auto; display:block; object-fit:contain; }
  /* Certains logos clients sont fournis en version blanche/claire, pensée
     pour aller directement sur le fond sombre du site (pas de carte blanche
     qui les rendrait illisibles ou dénaturerait la couleur d'origine). */
  .trust-logo-plain{
    height:44px;
    display:flex; align-items:center; justify-content:center;
    opacity:.75;
    transition:.3s;
  }
  .trust-logo-plain:hover{opacity:1;}
  .trust-logo-plain img{ max-height:100%; max-width:150px; width:auto; height:auto; display:block; object-fit:contain; }
  .trust-logo-labeled{ height:auto; flex-direction:column; gap:.4rem; }
  .trust-logo-labeled img{ max-height:44px; }
  .trust-logo-caption{ font-size:.68rem; letter-spacing:.12em; text-transform:uppercase; color:#58b8b8; }
  .trust-logo-gestibase{ height:auto; gap:.6rem; }
  .trust-logo-gestibase img{ height:40px; width:auto; max-height:none; }
  .trust-logo-gestibase .gb-text{ display:flex; flex-direction:column; align-items:flex-start; line-height:1.15; }
  .trust-logo-gestibase .gb-name{ font-family:'Trebuchet MS','Segoe UI',sans-serif; font-weight:700; font-size:1.15rem; color:#25a944; }
  .trust-logo-gestibase .gb-tagline{ font-family:Georgia,'Times New Roman',serif; font-style:italic; font-size:.64rem; color:var(--cream-dim); }
  .trust-logo-carantec{ height:auto; flex-direction:column; gap:.3rem; }
  .trust-logo-carantec img{ max-height:44px; }
  .trust-logo-carantec .carantec-tagline{ font-family:'Trebuchet MS','Segoe UI',sans-serif; font-size:.6rem; letter-spacing:.14em; text-transform:uppercase; color:#84ac9c; }
  .trust-logo-carantec .carantec-tagline b{ font-weight:700; }
  .trust-logo-carantec .carantec-tagline span{ font-weight:400; }
  .trust-logo-shalimar{ height:auto; gap:.7rem; }
  .trust-logo-shalimar img{ height:54px; width:auto; max-height:none; }
  .trust-logo-shalimar .sh-text{ display:flex; flex-direction:column; align-items:flex-start; line-height:1.25; }
  .trust-logo-shalimar .sh-name{ font-family:'Playfair Display',Georgia,serif; font-weight:700; font-size:1.4rem; color:var(--gold); letter-spacing:.02em; }
  .trust-logo-shalimar .sh-tagline{ font-family:'DM Sans',sans-serif; font-size:.62rem; letter-spacing:.2em; text-transform:uppercase; color:var(--cream-dim); }

  /* ============ UNIVERS — FLIP CARDS ============ */
  /* background:var(--black) explicite (identique visuellement à avant, où
     seul le fond du body — déjà noir — se voyait au travers) : nécessaire
     depuis l'ajout de .parallax-band (page d'accueil, position:fixed,
     z-index négatif) — sans un fond opaque propre à chaque section, une
     section "transparente" laisse voir au travers tout ce qui est peint en
     dessous dans l'ordre d'empilement, y compris un élément en z-index
     négatif, et la photo de fond ne serait alors jamais vraiment recouverte
     en descendant la page. */
  .section{padding:7rem 5vw; background:var(--black);}

  /* --- Page contact.html : pas de hero au-dessus, donc rien ne pousse
     naturellement le contenu sous le header fixe (contrairement à
     l'accueil où .hero-viewport s'en charge). Le padding-top de .section
     suffit tout juste sur desktop mais colle au header sur mobile (header
     replié sur 2 lignes) — on ajoute une marge de respiration dédiée. */
  .page-contact #contact{ padding-top:9rem; }
  @media(max-width:560px){
    .page-contact #contact{ padding-top:8.5rem; }
  }
  .section-head{
    text-align:center;
    max-width:62ch;
    margin:0 auto 3.5rem;
  }
  .section-head h1{
    font-size:clamp(1.9rem,4vw,3rem);
    margin-top:.7rem;
    color:var(--cream);
    font-family:'Playfair Display',serif;
    font-weight:700;
  }
  /* Tous les h2 du site sont uniformisés à 1.5rem, Playfair Display gras
     (demandé explicitement, référence : "Quelles surfaces peuvent êtres
     valorisés ?" / .surfaces-title) — seuls les h1 (titres de page) gardent
     leur échelle responsive plus grande ci-dessus. */
  .section-head h2{
    font-size:1.5rem;
    margin-top:.7rem;
    color:var(--cream);
    font-family:'Playfair Display',serif;
    font-weight:700;
  }
  /* Agrandi sur ordinateur, même proportion (×1.375) que le relèvement des
     paragraphes à 22px demandé juste avant. */
  @media(min-width:801px){
    .section-head h1{ font-size:clamp(2.6rem,5.5vw,4.1rem); }
  }
  /* #tableaux utilise un h1 (promu depuis h2, voir galerie.html) — garde sa
     taille dédiée, distincte des h1 de page ci-dessus. */
  #tableaux .section-head h1{
    font-size:clamp(1.3rem,2.4vw,1.7rem);
  }
  /* Page Avis clients : titre à la taille standard des titres de section du
     site (1.5rem, comme les h2), pas à l'échelle des grands h1 de page. */
  #avis-clients .section-head h1{ font-size:1.5rem; }
  /* Section Savoir-faire (#savoir-faire) : pas de span .eyebrow separe ici,
     "Expertise" (.savoir-gold) joue ce role dans le meme <h2>, a cote du
     vrai titre "Definir un format, choisir un style" (.savoir-white). */
  #savoir-faire .savoir-title{ line-height:1.4; }
  #savoir-faire .savoir-gold{
    font-family:'DM Sans',sans-serif;
    font-size:.75rem;
    letter-spacing:.28em;
    text-transform:uppercase;
    font-weight:600;
    line-height:1.1;
  }
  #savoir-faire .savoir-white{
    font-size:1.5rem;
    /* Sans ceci, herite du line-height:1.2 de .savoir-title (parent h2) au
       lieu du 1.05 generique des autres titres de section (h1,h2,h3) -
       ecart d'espace interligne invisible dans les mesures de boite mais
       visible a l'oeil, constate en ligne. */
    line-height:1.05;
    margin-top:0;
  }
  /* Le line-height:1.16 de .savoir-title (voir plus haut) laisse aussi un
     peu plus de blanc sous .savoir-white avant le paragraphe que sur les
     autres sections (18.75px mesure vs 16px ailleurs) - resserre ici pour
     revenir exactement au meme ecart titre/paragraphe que partout, demande
     explicitement. */
  #savoir-faire .section-head p{ margin-top:.5rem; }
  .section-head p{
    margin-top:1rem;
    color:var(--cream-dim);
    line-height:1.7;
  }
  /* .section-head élargi de 46ch à 62ch (demandé explicitement, site entier) :
     les paragraphes longs se tassaient sur trop de lignes courtes malgré
     l'espace disponible sur desktop. Référence : "Blocs technique les
     transformateurs de Locquirec" (#transformateurs-electriques-1). */
  .metamorphose-caption{
    font-size:.8rem;
    color:var(--cream-dim);
    font-style:italic;
    max-width:44ch;
    margin:.8rem auto 0;
    line-height:1.6;
  }

  /* ============ MÉTAMORPHOSE — TEXTE "PRESSE" (aperçu + déplier) ============ */
  .metamorphose-copy{
    max-width:760px;
    margin:2.5rem auto 3.5rem;
    text-align:center;
  }
  .metamorphose-intro{
    color:var(--cream-dim);
    line-height:1.8;
    font-size:1rem;
    display:-webkit-box;
    -webkit-box-orient:vertical;
    -webkit-line-clamp:4;
    overflow:hidden;
  }
  .metamorphose-copy.expanded .metamorphose-intro{
    display:block;
    -webkit-line-clamp:unset;
    overflow:visible;
  }
  .metamorphose-toggle{
    margin:1.3rem auto 0;
    display:inline-flex;
    align-items:center;
    gap:.5rem;
    background:none;
    border:none;
    color:var(--gold);
    font-family:'DM Sans',sans-serif;
    font-size:.8rem;
    font-weight:600;
    letter-spacing:.12em;
    text-transform:uppercase;
    cursor:pointer;
    padding:.4rem 0;
  }
  .metamorphose-toggle .mt-arrow{transition:transform .35s ease;}
  .metamorphose-copy.expanded .metamorphose-toggle .mt-arrow{transform:rotate(180deg);}
  .metamorphose-articles{
    max-height:0;
    overflow:hidden;
    transition:max-height .5s ease;
    display:grid;
    grid-template-columns:repeat(2,1fr);
    gap:1.8rem 2.6rem;
    text-align:left;
  }
  .metamorphose-copy.expanded .metamorphose-articles{margin-top:2.2rem;}
  .ma-item h4{
    color:var(--cream);
    font-family:'Playfair Display',serif;
    font-size:1.05rem;
    font-weight:500;
    margin-bottom:.5rem;
    letter-spacing:.01em;
  }
  .ma-check{color:var(--gold); margin-right:.5rem;}
  .ma-item p{
    color:var(--cream-dim);
    line-height:1.7;
    font-size:.92rem;
  }
  @media (max-width:680px){
    .metamorphose-articles{grid-template-columns:1fr;}
  }

  .flip-grid{
    display:grid;
    grid-template-columns:repeat(2,1fr);
    gap:2rem;
    max-width:1550px;
    margin:0 auto;
  }
  /* Titre de sous-catégorie au-dessus de chaque paire de cartes (Particuliers /
     Collectivités / Entreprises) : span sur les 2 colonnes du flip-grid,
     sans casser la grille existante. */
  .flip-group-head{
    grid-column:1 / -1;
    text-align:center;
    margin:1.4rem 0 .2rem;
  }
  .flip-group-head:first-child{ margin-top:0; }
  /* Carte "Hôtellerie & campings" seule sur sa ligne (3e carte du groupe
     Entreprises, qui n'en compte que 2 comme les autres groupes) : span sur
     les 2 colonnes pour occuper la même largeur que les 2 cartes du dessus
     réunies, au lieu de laisser un vide à droite. */
  #hotellerie-camping{ grid-column:1 / -1; }
  /* Carte "Hôtellerie & campings" étant seule sur toute la largeur (voir
     ci-dessus), on profite de l'espace au verso pour séparer carrousel et
     photo côte à côte (carrousel à gauche, photo à droite) au lieu de
     l'empilement vertical générique — demandé explicitement, ordinateur et
     tablette seulement (même seuil que le passage en pleine largeur), la
     version mobile garde l'empilement vertical habituel. */
  @media(min-width:901px){
    #hotellerie-camping .cylinder-carousel{ flex-direction:row; }
    /* La photo reste TOUJOURS à droite, quelle que soit celle affichée
       (demandé explicitement — pas de bascule dynamique par photo). Sa
       largeur n'est pas figée à 50/50 : elle est calée sur le format
       (ratio) de la photo du gîte de Ploumanac'h (5236×3448) prise comme
       référence, pour que CETTE photo précise s'affiche toujours en plein
       format sans recadrage — le carrousel à gauche récupère le reste de
       la largeur. Les autres photos, de ratio différent, se recadrent
       normalement (object-fit:cover déjà générique) pour remplir ce même
       cadre, plutôt que d'en changer la taille à chaque clic de vignette. */
    #hotellerie-camping .cylinder-carousel .carousel-hero{
      /* width:auto explicite : la règle générique .cylinder-carousel
         .carousel-hero{width:100%} sinon prioritaire sur aspect-ratio (une
         largeur déjà déclarée empêche le ratio de la déduire de la hauteur). */
      order:2; flex:0 0 auto; width:auto; height:100%; aspect-ratio:5236/3448;
    }
    #hotellerie-camping .cylinder-carousel .carousel-viewport{ order:1; flex:1 1 auto; height:100%; min-width:0; }
    /* position:absolute (au lieu de position:relative générique) : cet
       overlay est vide (pas de contenu ni fond visible) mais réclamait
       quand même toute la largeur du conteneur comme élément flex du rang,
       écrasant le carrousel à 0px de large — sorti du flux flex ici pour
       ne plus interférer avec le partage carrousel/photo.
       Pas de inset:0 : ça étirait la boîte (vide) sur toute la carte
       (464px de haut), et sizeCylinder() (script.js) lit sa hauteur pour
       en déduire l'espace déjà pris par l'overlay au-dessus du bandeau de
       vignettes — avec inset:0 il "mangeait" toute la hauteur disponible et
       réduisait les vignettes du carrousel à une taille minuscule. Sans
       inset, la boîte vide se réduit naturellement à 0×0. */
    #hotellerie-camping .cylinder-carousel .flip-back-overlay{ position:absolute; }
    /* Même mise en page en ligne (photo à droite, caroussel à gauche) pour
       la version "reflect-carousel" de cette carte — équivalent exact des
       règles .cylinder-carousel ci-dessus, adapté aux classes .rc-*. */
    #hotellerie-camping .reflect-carousel{ flex-direction:row; }
    #hotellerie-camping .reflect-carousel .rc-hero{
      order:2; flex:0 0 auto; width:auto; height:100%; aspect-ratio:5236/3448;
    }
    #hotellerie-camping .reflect-carousel .rc-container{ order:1; flex:1 1 auto; height:100%; min-width:0; }
  }
  .flip-group-head h3{
    font-size:clamp(1.3rem,2.4vw,1.7rem);
    color:var(--cream);
    margin:.4rem 0 .5rem;
  }
  .flip-group-head p{
    color:var(--cream-dim);
    max-width:60ch;
    margin:0 auto;
  }
  /* Sous chaque paire de flip-cards (Particuliers/Collectivités/Entreprises) :
     invite à visiter la ou les pages complètes de la catégorie — un lien
     .btn simple pour Collectivités (une seule page), ou les 3 pictos de la
     catégorie (.univers-picto-row réutilisée, mêmes classes/tailles) pour
     Particuliers/Entreprises qui auront plusieurs pages. */
  .flip-group-links{
    grid-column:1 / -1;
    text-align:center;
    margin:1rem 0 1rem;
    /* min-width:0 : un enfant de grille garde par défaut la largeur minimale
       de son contenu (min-width:auto implicite), même si ce contenu dépasse
       la colonne — sur mobile, la rangée de ronds-photo (.univers-picto-row-
       circles, plus large que la colonne à cause de son padding/gap) faisait
       alors déborder toute la rangée hors de la grille et décalait la page
       à droite. Sans effet sur ordinateur (colonne assez large pour ne
       jamais déclencher cette protection), bug constaté seulement sur
       mobile. */
    min-width:0;
  }
  .flip-group-links > p{
    color:var(--gold);
    margin:0 0 1.2rem;
    font-size:.95rem;
    font-weight:600;
    letter-spacing:.03em;
    text-transform:uppercase;
  }
  .flip-group-links .univers-picto-row{ margin:0; }
  /* .univers-picto-row-circles ("Choisir votre univers" en ronds-photo,
     mêmes classes que "Mon métier" plus haut) : le gap générique de
     .univers-picto-row (1.2rem) est bien trop court pour des ronds-photo de
     208px de large logés dans une boîte flex qui, elle, se resserre sur la
     largeur du libellé texte — les photos, plus larges que leur boîte,
     débordaient alors les unes sur les autres. Repris le même gap généreux
     que la rangée du haut (12.5vw / 4vw mobile) pour garder l'écart réel
     entre les photos identique aux deux endroits, sans reprendre le hack de
     sortie de colonne (width:100vw) qui décalait la rangée à droite ici. */
  .flip-group-links .univers-picto-row-circles{ gap:12.5vw; }
  /* .stats-caption-surfaces .univers-picto-row-circles (page hôtellerie,
     4 ronds-photo "Espaces intérieurs/aquatiques/extérieurs/sanitaires") :
     même correctif que la rangée du haut de #univers (gap générique de
     .univers-picto-row trop court pour des ronds-photo de 208px, qui se
     chevauchaient) — même sortie de colonne en 100vw + même gap généreux,
     avec retour à la ligne (flex-wrap) pour le 4e rond. */
  @media(min-width:641px){
    .stats-caption-surfaces .univers-picto-row-circles{
      width:100vw; position:relative; left:50%; margin-left:-50vw;
      gap:3vw 12.5vw; flex-wrap:wrap; justify-content:center;
    }
  }
  @media(max-width:640px){
    .stats-caption-surfaces .univers-picto-row-circles{ gap:4vw; flex-wrap:wrap; justify-content:center; padding:0 5vw; box-sizing:border-box; }
  }
  /* #univers-maison (interieurs.html, 7 ronds-photo "pièces incontournables")
     et #univers-jardin (exterieurs.html, 5 ronds-photo "supports
     incontournables") : rangées de 3 au lieu du wrap par défaut calé sur la
     largeur du libellé (qui donnait 2 par rangée), demandé explicitement.
     Largeur fixe en vw (23vw, identique à .univers-picto-photo lui-même)
     au lieu d'un flex-basis calc(100% - gap)/3 : ce calc, tout juste
     inférieur à 33.33%, se faisait recouper par l'arrondi sub-pixel de
     certains navigateurs mobiles réels (Chrome Android notamment — testé
     correct ici en émulation desktop mais rapporté cassé (2 par rangée) sur
     un vrai téléphone Android) et retombait à 2 par rangée. Une largeur vw
     fixe, largement sous les 33% même avec le gap, ne dépend plus du calcul
     exact de la largeur du conteneur et ne bascule plus jamais par erreur.
     padding:0 (au lieu du 5vw générique hérité de .stats-caption-surfaces
     .univers-picto-row-circles juste au-dessus) : ce padding s'ajoutait à
     celui, identique, du conteneur #univers-jardin/#univers-maison lui-même
     — double marge de 10vw de chaque côté, gaspillant l'espace au lieu de
     l'utiliser pour l'écart entre les ronds (demandé explicitement, "à
     touche-touche" alors qu'il restait de la place à droite/gauche). */
  @media(max-width:640px){
    #univers-maison .univers-picto-row-circles{ gap:8vw; padding:0; }
    #univers-maison .univers-picto-row-circles .univers-client-circle{ flex:0 0 auto; width:23vw; max-width:23vw; min-width:0; }
  }
  @media(max-width:640px){
    #univers-jardin .univers-picto-row-circles{ gap:8vw; padding:0; }
    #univers-jardin .univers-picto-row-circles .univers-client-circle{ flex:0 0 auto; width:23vw; max-width:23vw; min-width:0; }
  }
  /* page-piscine (espace-piscine.html) : seulement 3 ronds-photo, pas 4
     comme sur la page hôtellerie dont elle est issue — les 3 doivent rester
     sur une seule ligne au lieu de retourner à la ligne comme prévu pour un
     4e rond. Même traitement que .flip-group-links (flex:1 1 0, sans wrap). */
  @media(max-width:640px){
    .page-piscine .stats-caption-surfaces .univers-picto-row-circles{ flex-wrap:nowrap; gap:3vw; }
    .page-piscine .stats-caption-surfaces .univers-picto-row-circles .univers-client-circle{ flex:1 1 0; min-width:0; }
  }
  @media(max-width:640px){
    .flip-group-links .univers-picto-row-circles{ gap:7vw; padding:0 3vw; box-sizing:border-box; }
    /* flex:1 1 0 (au lieu du flex:0 1 auto générique, calé sur le libellé) :
       une fois la rangée resserrée sur l'étroite largeur mobile (voir
       min-width:0 sur .flip-group-links plus haut), les 3 ronds se
       partageaient l'espace selon la longueur de leur texte — libellés
       courts (ex. "Art urbain") écrasés, libellés longs (ex. "Blocs
       techniques & transformateurs") gardant toute la place, d'où des
       écarts inégaux entre les photos. Base 0 = les 3 se partagent
       l'espace à parts égales, indépendamment du texte. */
    .flip-group-links .univers-picto-row-circles .univers-client-circle{ flex:1 1 0; }
  }
  .flip-card{
    perspective:1600px;
    /* En vh (plafonnée à 500px), pas en px fixe : à 500px fixes, une carte
       occupe une part bien plus grande d'un écran d'ordinateur "normal" à
       100% de zoom que sur un écran plus haut ou à un zoom réduit (78-80%,
       où la même valeur paraissait bien proportionnée) — constaté en ligne,
       demandé explicitement. Le plafond à 500px garde le rendu actuel
       inchangé sur les écrans hauts/zoom réduit ; le plancher à 400px
       (repris de la valeur mobile) évite qu'elle ne devienne trop petite sur
       un écran bas. */
    height:clamp(400px, 52vh, 500px);
    /* Retournement au tap géré via touchend en JS (voir script.js) plutôt
       que par survol seul ou par 'click' — évite le "il faut taper deux
       fois" d'un élément purement :hover sur tactile, et le clic annulé par
       le navigateur au moindre glissement du doigt pendant l'appui. */
    -webkit-user-select:none; user-select:none;
    -webkit-touch-callout:none;
    /* pan-y : le défilement vertical natif reste intact, mais le geste
       horizontal n'est plus capté par le navigateur (zoom/pan-x) — laissé
       entièrement au JS, qui l'utilise pour le glissement gauche/droite
       retournant aussi la carte (voir script.js). */
    touch-action:pan-y;
  }
  @media(max-width:640px){
    .flip-card{ height:400px; }
  }
  .flip-inner{
    position:relative; width:100%; height:100%;
    transition:transform .8s cubic-bezier(.4,.2,.2,1);
    -webkit-transform-style:preserve-3d;
    transform-style:preserve-3d;
    will-change:transform; /* promeut la couche GPU dès le départ (face avant + arrière, dont tout le carrousel caché) au lieu de la construire au milieu du retournement quand la face arrière franchit le seuil de visibilité */
  }
  .flip-card:hover .flip-inner{transform:rotateY(180deg);}
  /* Sur tactile, le survol CSS ne se relâche pas de façon fiable au tap —
     le retournement y est géré par touchend en JS (voir script.js) plutôt
     que par le survol, qui reste désactivé ici. */
  @media(hover:none){
    /* :not(.flipped) indispensable : un tap pose parfois un :hover
       persistant sur l'élément en plus d'ajouter .flipped via JS — sans
       cette exclusion, cette règle (plus spécifique que
       .flip-card.flipped .flip-inner plus bas) l'emportait et annulait la
       rotation malgré le retournement bien déclenché. */
    .flip-card:not(.coll-flip):not(.flipped):hover .flip-inner{ transform:none; }
  }
  /* mode édition de texte (edit-toolkit.js) : on désactive le retournement
     au survol, sinon impossible de cliquer dans le texte de la couverture
     sans que la carte ne se retourne avant. */
  body.et-text-mode .flip-card:hover .flip-inner{ transform:none; }
  /* Le blocage ci-dessus n'arrête que la rotation 3D : les règles d'opacité
     .flip-card:hover .flip-back/.flip-front plus bas s'appliquent quand même
     au survol et rendaient la face avant invisible (donc la carte paraissait
     noire, .flip-back gardant son fond var(--black) même non tournée
     visuellement — backface-visibility peu fiable, voir plus haut). */
  body.et-text-mode .flip-card:not(.flipped):hover .flip-back{ opacity:0; pointer-events:none; }
  body.et-text-mode .flip-card:not(.flipped):hover .flip-front{ opacity:1; pointer-events:auto; }
  /* Outil "Recadrer les photos" (edit-toolkit.js) : même besoin que le mode
     texte ci-dessus — sans ceci, survoler une couverture de flip-card pour
     la glisser la retournerait avant même le premier mousedown. Les cartes
     .coll-flip (collectivités) se retournent déjà seulement au clic (voir
     plus bas), donc rien à désactiver ici pour elles : la suppression du
     clic après un glisser (edit-toolkit.js, suppressNextClick) suffit.
     :not(.flipped) — indispensable pour les cartes génériques (.flip-card
     sans .coll-flip, ex. #tremel-flip) déjà ouvertes via le bouton "Retourner
     la carte" : sans cette exclusion, cette règle (plus spécifique que
     .flip-card.flipped .flip-inner ci-dessous) l'emportait dès qu'on survolait
     la carte pour attraper la grande photo du carrousel à glisser, et la
     refermait instantanément sous les yeux de l'utilisateur — perçu comme
     "la carte se retourne toute seule" pile au moment de vouloir la glisser. */
  body.et-repo-mode .flip-card:hover:not(.flipped) .flip-inner{ transform:none; }
  /* Meme lacune que les fixes et-text-mode/.coll-flip plus haut : bloquer la
     rotation 3D au survol ne suffit pas, les regles generiques
     .flip-card:hover .flip-back/.flip-front s'appliquent quand meme et
     rendaient la couverture invisible (opacity:0) des qu'on cliquait dessus
     pour la glisser en mode Recadrer - carte qui "disparait" au clic,
     constate explicitement. */
  body.et-repo-mode .flip-card:not(.flipped):hover .flip-back{ opacity:0; pointer-events:none; }
  body.et-repo-mode .flip-card:not(.flipped):hover .flip-front{ opacity:1; pointer-events:auto; }
  .flip-card.flipped .flip-inner{transform:rotateY(180deg);}  /* état verrouillé pendant le glisser / au tap (tactile) */
  .flip-face{
    position:absolute; inset:0;
    -webkit-backface-visibility:hidden;
    backface-visibility:hidden;
    border:2px solid var(--gold);
    display:flex; flex-direction:column; justify-content:flex-end;
    padding:2rem;
    /* backface-visibility:hidden seul ne suffit pas sur certains navigateurs
       mobiles : la face arrière peut rester peinte par-dessus l'avant même
       non retournée. Filet de sécurité générique ici, en plus du 3D. */
    transition:opacity .8s cubic-bezier(.4,.2,.2,1);
  }
  .flip-front{
    background:linear-gradient(180deg, transparent 40%, rgba(0,0,0,.85)), var(--black-soft);
    background-size:cover; background-position:var(--bp-x,50%) center;
  }
  .flip-back{ opacity:0; pointer-events:none; }
  .flip-card:hover .flip-back{ opacity:1; pointer-events:auto; }
  .flip-card:hover .flip-front{ opacity:0; pointer-events:none; }
  .flip-card.flipped .flip-back{ opacity:1; pointer-events:auto; }
  .flip-card.flipped .flip-front{ opacity:0; pointer-events:none; }
  @media(hover:none){
    .flip-card:not(.coll-flip):not(.flipped):hover .flip-back{ opacity:0; pointer-events:none; }
    .flip-card:not(.coll-flip):not(.flipped):hover .flip-front{ opacity:1; pointer-events:auto; }
  }
  .flip-front .num{
    font-family:'Anton',sans-serif;
    color:var(--gold);
    font-size:1rem;
    letter-spacing:.1em;
    margin-bottom:.5rem;
  }
  .flip-front h3{
    font-size:1.6rem;
    color:var(--cream);
    /* line-height explicite (au lieu d'hériter le 1.05 générique de h1,h2,h3
       plus haut) : à 1.05, les jambages/empattements de Playfair Display à
       cette taille débordent légèrement la boîte de ligne calculée — invisible
       quand le titre a de la marge (3 lignes réelles dans une réserve de 2,
       ex. "Collectivités"), mais assez pour quasi toucher le sous-titre
       .flip-sub juste en dessous quand le titre tient pile dans ses 2 lignes
       réservées sans aucune marge (ex. "Particuliers / Jardins & Piscines"),
       constaté en ligne. */
    line-height:1.15;
    /* Réserve toujours 2 lignes (titre le plus long du lot), pour que le
       numéro reste à la même hauteur d'une carte à l'autre même quand le
       titre tient sur une seule ligne. */
    min-height:calc(1.6rem * 1.15 * 2);
  }
  .flip-front .flip-sub{
    font-size:1.15rem;
    line-height:1.15;
    color:var(--gold);
    margin-top:.6rem;
    /* min-height:0 explicite, indispensable : .flip-sub est un h3 comme le
       grand titre au-dessus, donc sans cette ligne il retombe sur le
       min-height de la regle generique .flip-front h3 (calee sur 1.6rem,
       2 lignes DU GRAND TITRE), bien trop grand pour son propre texte a
       1.15rem. Sur les cartes ou le sous-titre tient sur 1 seule ligne
       ("Espaces exterieur"), ce blanc invisible sous le texte donnait un
       ecart avant le paragraphe nettement plus grand que sur les cartes a
       sous-titre 2 lignes (qui remplissaient presque la reserve) - demande
       explicitement corrige pour un ecart identique partout, quel que soit
       le nombre de lignes du sous-titre. */
    min-height:0;
  }
  .flip-front .flip-desc{
    color:#fff;
    font-size:.9rem;
    line-height:1.6;
    margin-top:.6rem;
    /* Idem : réserve toujours 3 lignes (description la plus longue du lot). */
    min-height:calc(.9rem * 1.6 * 3);
  }
  .flip-back{
    background:var(--black);
    transform:rotateY(180deg);
    justify-content:flex-end;
    padding:0;
    overflow:hidden;
  }
  /* --- Dos de carte texte seul, sans carrousel (10 cartes "philosophie"
     ajoutées sous "Découvrir plus de projets") : retournement simple
     .flip-front → .flip-back, pas de second retournement imbriqué comme
     .tremel-nested. Typographie reprise de .tremel-back-text pour rester
     visuellement cohérent avec les cartes qui ONT un carrousel. */
  .page-coll .flip-back-simple{
    padding:2rem;
    overflow-y:auto;
    scrollbar-width:none;
    -ms-overflow-style:none;
    justify-content:flex-start;
  }
  .page-coll .flip-back-simple::-webkit-scrollbar{ display:none; }
  .page-coll .flip-back-simple-inner{ margin:auto 0; width:100%; }
  .page-coll .flip-back-simple h3{
    color:var(--gold); font-family:'Playfair Display',serif; font-size:1.4rem; margin-bottom:1rem;
  }
  .page-coll .flip-back-simple p{
    color:var(--cream-dim); font-size:.85rem; line-height:1.6; margin-bottom:.9rem;
  }
  .page-coll .flip-back-simple p:last-child{ margin-bottom:0; }
  /* --- "Découvrir plus de projets" (philosophie) : même logique déplier/
     replier générique que Toiles & tableaux (index.html) et Métamorphose —
     extraite ici sous des noms neutres (.reveal-*) pour être réutilisable
     partout où ce même besoin ("N premiers visibles, le reste replié
     derrière un bouton") se représente, plutôt que de dupliquer la logique
     JS une troisième fois. Voir script.js. */
  .page-coll .reveal-toggle-row{ text-align:center; margin-top:2.4rem; }
  .page-coll .reveal-wrap .bio-toggle{ margin:0 auto; }
  .page-coll .reveal-wrap.expanded .reveal-toggle .mt-arrow{ transform:rotate(180deg); }
  .page-coll .reveal-more{
    max-height:0;
    overflow:hidden;
    transition:max-height .6s ease;
  }
  .page-coll .reveal-wrap.expanded .reveal-more{ margin-top:2.4rem; }
  .page-coll .reveal-more .flip-grid{ margin-top:0; }
  .page-coll .reveal-close-row{ text-align:center; margin-top:2.4rem; }
  .carousel-viewport{
    position:absolute; inset:0;
    overflow:hidden;
    display:flex; align-items:stretch;
  }
  .carousel-track{
    position:relative;
    display:flex; align-items:stretch;
    height:100%;
    width:max-content;
    animation:carouselLR 55s linear infinite;
    cursor:grab; touch-action:pan-y;
    -webkit-user-drag:none; user-select:none; -webkit-user-select:none;
  }
  .carousel-track.dragging{ cursor:grabbing; }
  .carousel-item{
    flex:0 0 auto;
    height:100%;
    width:auto;
    aspect-ratio:3/2;
    border-right:4px solid var(--black);
    background:var(--black-soft);
  }
  .carousel-item img{width:100%; height:100%; object-fit:cover; display:block; cursor:pointer;}
  .lightbox img.magnifying{cursor:none;}
  .magnifier-lens{
    position:fixed; z-index:2200; /* au-dessus du header (1000) : sinon, près du
      bord haut d'une photo en plein écran, la loupe passait visuellement sous
      le header au lieu de rester lisible par-dessus */
    width:160px; height:160px;
    border-radius:50%;
    border:3px solid var(--gold);
    box-shadow:0 12px 34px rgba(0,0,0,.55);
    pointer-events:none;
    display:none;
    background-repeat:no-repeat;
  }
  .carousel-track.paused{animation-play-state:paused;}

  /* --- Photo active + mini-carrousel cylindre 3D à glisser : port vanille
     d'un composant React (framer-motion) fourni par l'utilisateur, adapté
     en sélecteur. En haut, une grande photo pleine largeur (celle actuellement
     sélectionnée) — cliquer dessus ouvre la lightbox plein écran. En bas,
     un bandeau où les photos tournent librement et À L'INFINI autour d'un
     cylindre (glisser à la souris/au doigt, inertie au relâchement) ; cliquer
     une vignette (sans glisser) la fait passer en photo active en haut.
     Classe partagée par les cartes qui utilisent ce style (pour l'instant :
     particuliers extérieur et intérieur), les autres gardent le défilement
     classique ci-dessus. */
  .cylinder-carousel{
    -webkit-transform-style:preserve-3d;
    transform-style:preserve-3d;
    display:flex; flex-direction:column;
  }
  .cylinder-carousel .carousel-hero{
    position:relative;
    width:100%; flex:0 0 63.9%; min-height:0; /* hauteur validée à la main pendant le calibrage */
    overflow:hidden;
  }
  .cylinder-carousel .carousel-hero img{
    width:100%; height:100%; object-fit:cover; object-position:var(--bp-x,50%) center; display:block; cursor:var(--zoom-cursor);
    opacity:0; transition:opacity .4s ease;
    -webkit-user-drag:none; user-select:none; -webkit-user-select:none; /* évite le glisser natif d'image du navigateur, qui pouvait figer l'interaction au clic */
    -webkit-touch-callout:none;
  }
  .cylinder-carousel .carousel-hero img.loaded{opacity:1;}
  .cylinder-carousel .flip-back-overlay{
    position:relative; z-index:2; flex:0 0 auto;
    padding:.85rem 2rem;
    background:none; /* pas besoin du voile dégradé générique : ici le fond est déjà uni (noir), le dégradé faisait un bandeau visible */
  }

  /* --- Carte "Portraits" (cas à part) : deux univers Humains/Animaux, la
     carte s'ouvre directement sur "Humains" ; le lien "Galerie complète"
     bascule vers l'autre univers (voir script.js). --- */
  .universe-carousel{ flex-direction:column; min-height:0; width:100%; }
  .universe-carousel:not([hidden]){ display:flex; flex:1 1 auto; }
  /* .reflect-carousel{display:flex} (anneau 3D) l'emporte sur l'attribut
     [hidden] (display:none du navigateur) : l'univers masqué restait affiché
     et écrasait l'univers visible (photo + anneau réduits à ~90px). */
  .universe-carousel[hidden]{ display:none; }
  .cylinder-carousel .carousel-viewport{
    position:relative;
    flex:1 1 auto; width:100%; min-height:0;
    perspective:var(--persp, 900px);
    perspective-origin:50% 50%;
    align-items:center; justify-content:center;
    -webkit-transform-style:preserve-3d;
    transform-style:preserve-3d;
    /* Ce carrousel est un contexte 3D IMBRIQUÉ dans un autre (le retournement
       de la flip-card, lui-même en 3D) — contrairement au carrousel "Toiles &
       tableaux" qui n'est dans aucune flip-card et n'a donc qu'un seul niveau
       de 3D. Le preserve-3d imbriqué est un point fragile connu de certains
       compositeurs GPU mobiles (Android notamment) : l'ordre de profondeur
       des cartes peut s'afficher n'importe comment. On force ce niveau sur sa
       propre couche de composition, isolée du 3D de la carte parente. */
    will-change:transform;
    -webkit-transform:translateZ(0);
    transform:translateZ(0);
    overflow:visible; /* sinon le carrousel se fait couper net (bande noire) quand on le glisse au-delà de son bandeau — la carte elle-même (.flip-back) reste coupée à ses propres bords */
    /* flex:1 (au lieu d'une hauteur fixe) + align-items:center ci-dessus =
       le carrousel se centre tout seul entre la photo et "Galerie complète",
       quel que soit l'espace restant. */
  }
  /* Vignette : fait disparaître doucement les cartes qui s'éloignent sur les
     côtés dans le noir de fond, pour renvoyer l'impression d'un cercle
     complet de photos (comme la photo de référence) plutôt qu'un simple
     éventail de 3 cartes isolées. */
  .cylinder-carousel .carousel-viewport::after{
    content:''; position:absolute; inset:0; z-index:3; pointer-events:none;
    /* Fondu adouci : au lieu d'un mur opaque, un voile semi-transparent (les
       cartes qui s'éloignent se devinent encore, adoucies) — moins brutal
       que la coupure nette vers le noir plein, surtout sur les bords
       gauche/droite où l'ellipse resserre le fondu. Pas de backdrop-filter
       ici (essayé, puis retiré) : le flou s'appliquait à tout le bandeau, y
       compris la carte bien nette au centre — visible comme un halo flou
       autour du carrousel, surtout gênant sur les petites vignettes mobile
       (90×90px, un flou de 1px y pèse bien plus qu'à taille bureau). */
    /* Seuils resserrés (40%→92% avant, 38%→60% ici) : les vignettes qui
       arrivent presque de profil (juste après les cartes bien visibles)
       restent minces mais pas encore complètement fondues à l'ancien 92% —
       ce fin trait, à peine assombri, tranchait comme une bande noire nette
       à côté des photos. Le voile atteint maintenant l'opacité quasi
       maximale plus tôt (60% au lieu de 92%), avant ce point, sans changer
       le début du fondu (donc sans assombrir les cartes bien visibles
       proches du centre) ni l'écartement des cartes elles-mêmes. */
    background:radial-gradient(ellipse 60% 100% at 50% 50%, transparent 38%, rgba(14,13,12,.97) 60%);
  }
  .cylinder-carousel .carousel-track{
    position:relative;
    width:100%; height:100%;
    -webkit-transform-style:preserve-3d;
    transform-style:preserve-3d;
    animation:none; /* écrase le défilement carouselLR hérité de la règle générique */
    cursor:grab; touch-action:pan-y;
    will-change:transform; /* indique au navigateur de promouvoir la couche pour un glisser fluide */
    -webkit-user-drag:none; user-select:none; -webkit-user-select:none;
    -webkit-touch-callout:none; /* évite le menu contextuel iOS sur appui long */
  }
  .cylinder-carousel .carousel-track.dragging{cursor:grabbing;}
  .cylinder-carousel .carousel-item{
    position:absolute; top:50%; left:50%;
    width:var(--face-w, 100px); height:var(--face-h, 70px); /* rectangulaire : largeur et hauteur pilotées séparément pour que la bande reste basse même quand les cartes s'étalent en largeur */
    cursor:pointer;
    transform:translate(-50%,-50%) rotateY(calc(var(--i) * (360deg / var(--count)))) translateZ(var(--radius, 175px));
    will-change:transform; /* même logique que .flip-inner : promeut la couche de chaque vignette du cylindre (caché derrière la face avant) dès le chargement, au lieu de construire les ~10 couches d'un coup au premier retournement — c'était le reste du "gel" au premier flip une fois le chargement des photos réglé. */
  }
  /* Bords arrondis, ombre et clipping vivent ici (élément statique, jamais
     transformé lui-même) plutôt que sur .carousel-item — voir commentaire JS
     dans initCylinderCard : un élément transformé à chaque frame ET clippé
     (border-radius+overflow) force un repaint logiciel par frame. */
  .cylinder-carousel .carousel-item-inner{
    width:100%; height:100%;
    border-radius:10px;
    box-shadow:0 4px 14px rgba(0,0,0,.45); /* ombre plus discrète : une ombre trop portée vers le bas donnait l'impression que le bandeau n'était pas centré */
    background:var(--black-soft);
    /* Pas de backface-visibility:hidden ici : on VEUT que les cartes qui
       tournent sur le côté/vers l'arrière restent visibles (assombries par
       la vignette ci-dessus) pour donner l'impression d'un cercle complet
       de photos, comme sur la photo de référence, plutôt que des cartes
       qui disparaissent brutalement passé 90°. */
    overflow:hidden;
  }
  .cylinder-carousel .carousel-item.active .carousel-item-inner{border:1px solid var(--gold);}
  /* Empêche le glisser natif d'image du navigateur (ghost qui suit le
     curseur) de voler le geste à notre rotation personnalisée au clic-glisser. */
  .cylinder-carousel .carousel-item img{
    -webkit-user-drag:none; user-select:none; -webkit-user-select:none;
    -webkit-touch-callout:none;
    pointer-events:none; /* le clic est géré par la carte (le div) elle-même */
  }

  /* --- Carrousel 3D "sans bordure + reflet" (test demandé explicitement,
     en remplacement du cylinder-carousel standard, uniquement sur la carte
     #particuliers) : même mise en page que le cylinder-carousel standard
     (grande photo en haut, 63.9%, comme la carte 2 particuliers-interieur ;
     bandeau de vignettes en dessous), mais anneau complet (pas seulement
     les cartes de face), reflet miroir sous chaque vignette, fond noir uni. */
  .reflect-carousel{
    padding:0; overflow:hidden;
    display:flex; flex-direction:column;
    background:var(--black);
  }
  .reflect-carousel .rc-hero{
    position:relative;
    width:100%; flex:0 0 63.9%; min-height:0;
    overflow:hidden;
  }
  .reflect-carousel .rc-hero img{
    width:100%; height:100%; object-fit:cover; display:block;
    opacity:0; transition:opacity .4s ease;
    cursor:var(--zoom-cursor); /* curseur loupe, même signal visuel que la carte 2 */
    -webkit-user-drag:none; user-select:none; -webkit-user-select:none;
  }
  .reflect-carousel .rc-hero img.loaded{ opacity:1; }
  .rc-container{
    flex:1 1 auto; width:100%; min-height:0;
    perspective:var(--rc-persp, 1200px); /* calculé en JS à partir du rayon, comme --persp du cylinder-carousel standard */
    display:flex; justify-content:center; align-items:center;
    position:relative;
  }
  /* Voile léger sur les vignettes de côté/arrière (demandé explicitement,
     pour bien les détacher de la vignette de face) — même principe que la
     vignette du cylinder-carousel standard, mais volontairement plus
     discret (assombrissement max ~35% au lieu de ~97%, fondu qui commence
     plus tard) puisqu'ici le but est juste un léger recul visuel, pas de
     masquer une jointure. */
  .rc-container::after{
    content:''; position:absolute; inset:0; z-index:3; pointer-events:none;
    background:radial-gradient(ellipse 65% 100% at 50% 50%, transparent 45%, rgba(14,13,12,.35) 100%);
  }
  .rc-track{
    width:var(--rc-card-w, 280px); height:var(--rc-card-h, 320px);
    position:relative;
    transform-style:preserve-3d;
    /* Pas de transition CSS sur transform : la rotation (glisser + inertie)
       est pilotée image par image en JS (requestAnimationFrame, voir
       applyRotation/tick), comme .carousel-track du cylinder-carousel
       standard — une transition CSS restée ici en trop (d'une ancienne
       version à clic-résultat net, avant l'inertie) entrait en conflit
       avec ces mises à jour à chaque frame et donnait un mouvement qui
       "accrochait" par endroits. */
    cursor:grab;
    touch-action:pan-y;
    -webkit-user-drag:none; user-select:none; -webkit-user-select:none;
    will-change:transform; /* pour un glisser fluide, même logique que .carousel-track standard */
  }
  .rc-track.dragging{ cursor:grabbing; }
  /* Reflet miroir (remplace -webkit-box-reflect, confirmé absent sur
     Android/Chrome mobile — propriété non standard, jamais fiable partout,
     alors qu'elle s'affichait bien en test desktop). Posé sur .rc-card (le
     parent transformé), PAS .rc-card-inner (qui garde son overflow:hidden
     pour les coins arrondis de la photo — un pseudo-élément positionné hors
     de sa propre boîte s'y ferait couper net). --reflect-src (l'image de la
     carte, en background-image) posée en JS au moment de la création de
     chaque carte (voir photos.forEach dans initReflectCarousel). Technique
     par masque : bien plus largement supportée que box-reflect (Chrome,
     Safari, Android, iOS). Pas de flou JS répercuté ici (contrairement à
     .rc-card-inner) : cumuler filter+transform sur l'élément transformé
     lui-même reproduirait exactement le bug de rendu logiciel qui a motivé
     la séparation carte/carte-intérieure au départ — effet négligeable, le
     reflet étant déjà très subtil (max 20-26% d'opacité). */
  .rc-card::after{
    content:'';
    position:absolute; left:0; top:calc(100% + 8px); width:100%; height:100%;
    background-image:var(--reflect-src, none);
    background-size:cover; background-position:center;
    border-radius:9.6px;
    transform:scaleY(-1);
    /* Forme d'origine (demandée explicitement) : net dès le bas de la photo
       (pas de fondu d'entrée), puis dégradé UNIQUEMENT vers le bas — les
       stops sont posés à l'envers de l'apparence finale voulue, puisque
       transform:scaleY(-1) retourne aussi le masque : "transparent jusqu'à
       65%, puis dégradé vers l'opacité par 100%" AVANT le retournement
       donne, une fois affiché, "net dès le contact, dégradé vers le bas". */
    -webkit-mask-image:linear-gradient(to bottom, transparent 65%, rgba(255,255,255,.2) 100%);
    mask-image:linear-gradient(to bottom, transparent 65%, rgba(255,255,255,.2) 100%);
    pointer-events:none;
  }
  .rc-card{
    position:absolute; width:100%; height:100%; left:0; top:0;
    /* will-change:transform : promeut chaque vignette sur sa propre couche
       GPU en permanence, dès le chargement — même traitement que
       .carousel-item du cylinder-carousel standard (voir commentaire
       équivalent plus haut dans ce fichier). Sans ceci, le navigateur ne
       promeut la couche GPU que PENDANT le mouvement puis "rétrograde"/
       re-rasterise la carte une fois arrêtée — c'est cette étape de
       re-rasterisation à l'arrêt qui rendait la vignette de face nette en
       mouvement mais légèrement floue une fois immobile, quel que soit le
       flou (filter) réellement appliqué (déjà vérifié à none). */
    will-change:transform;
    /* Pas de backface-visibility:hidden (contrairement au code de référence) :
       ça faisait disparaître d'un coup les photos passé 90° de rotation —
       la carte "de dos" devenait un trou vide dans l'anneau. Même choix que
       le cylinder-carousel standard du site (voir commentaire équivalent
       plus haut) : on veut voir ces photos, assombries par la perspective,
       pour garder l'impression d'un anneau complet plutôt que 2-3 cartes
       isolées avec des trous entre elles. */
  }
  /* Pendant le glisser, le flou doit suivre le doigt/la souris 1:1 comme la
     rotation elle-même (transition:none sur .rc-track ci-dessus) — sinon il
     traîne en retard pendant tout le geste. La transition douce ci-dessous
     ne sert qu'au relâchement, quand la carte finit sa course toute seule. */
  .rc-track.dragging .rc-card-inner{ transition:none; }
  /* Bords arrondis, reflet et flou vivent sur .rc-card-inner (élément
     statique, jamais transformé lui-même) plutôt que sur .rc-card — même
     principe que .carousel-item-inner dans le cylinder-carousel standard :
     un élément à la fois transformé (.rc-card, rotateY+translateZ à chaque
     frame) ET clippé/flouté force un rendu logiciel non accéléré, qui
     rendait les vignettes visiblement moins nettes que la grande photo
     hero (non transformée) — signalé explicitement ("hero nette, miniature
     floue"). */
  .rc-card-inner{
    width:100%; height:100%;
    border:none; outline:none; overflow:hidden;
    border-radius:9.6px; /* -40% (16px → 9.6px), demandé explicitement */
    /* Force sa propre couche de composition — même correctif déjà en place
       ailleurs sur le site (#tableauxCarousel .carousel-item-inner) pour un
       élément clippé (border-radius+overflow) enfant d'un parent en 3D : la
       découpe peut sinon "fuir"/mal se recalculer, contribuant à ce rendu
       moins net une fois la rotation arrêtée. */
    transform:translateZ(0);
    -webkit-transform:translateZ(0);
    /* Pas de transition CSS sur filter : le flou est recalculé à chaque
       frame en JS pendant les 0.8s de rotation, à partir de l'angle
       RÉELLEMENT affiché (voir runSettleLoop côté JS) — une 2e transition
       CSS indépendante de celle du transform pouvait très légèrement se
       désynchroniser du mouvement réel (transform accéléré GPU, filter
       repeint sur le thread principal), et donnait l'impression que la
       vignette de face redevenait floue juste après s'être arrêtée. */
  }
  /* Garde-fou : la carte marquée "front" (la plus proche de la face, mise à
     jour en JS) ne peut jamais afficher de flou, quel que soit le calcul
     d'angle — demandé explicitement après plusieurs signalements de flou
     visible sur la carte de face malgré le calcul JS déjà correct. */
  .rc-card-inner.front{ filter:none !important; }
  /* Liseret sur la vignette actuellement sélectionnée (celle affichée en
     grand dans le header), en outline plutôt qu'en border : même si tout
     le site est en box-sizing:border-box, .rc-card-inner fait
     width/height:100% et son image à l'intérieur fait aussi 100% — un
     border ajouté par .active réduit la boîte de contenu de 2px (1px de
     chaque côté), donc l'image affichée dedans (100% de CETTE boîte)
     rétrécissait visiblement de 2px pile au moment de la sélection, perçu
     comme un "saut de taille"/flou. outline ne fait jamais partie du
     modèle de boîte (ni content-box ni border-box) : zéro impact sur la
     taille de l'image, quelle que soit l'épaisseur. */
  /* outline-offset:-1px (invisible, coupé par overflow:hidden) puis +1px
     (visible mais décollé du bord, coins pas nets) — outline-offset:0
     colle exactement au bord de la vignette (et suit son border-radius),
     sans jamais faire partie du modèle de boîte donc toujours hors de
     portée de overflow:hidden. */
  .rc-card-inner.active{ outline:1px solid var(--gold); outline-offset:0; }
  .rc-card-inner img{
    width:100%; height:100%; object-fit:cover; display:block; border:none;
    -webkit-user-drag:none; user-select:none; -webkit-user-select:none;
    pointer-events:none;
    /* Aide le navigateur à garder un ré-échantillonnage plus net à cette
       taille très réduite (pas un souci de résolution source, déjà à
       2400px — voir MAJ précédente sur .rc-card/.rc-card-inner). Pas de
       backface-visibility:hidden ici (contrairement à la suggestion
       reçue) : ça masquerait à nouveau les photos passé 90°, exactement
       le "trou dans l'anneau" corrigé plus tôt sur .rc-card — même
       logique 3D, l'image hérite de l'orientation accumulée de ses
       parents transformés. */
    image-rendering:-webkit-optimize-contrast;
    transform:translateZ(0);
  }
  .rc-controls{
    position:absolute; inset:0; z-index:4;
    display:flex; justify-content:space-between; align-items:center;
    padding:0 .5rem;
    pointer-events:none;
  }
  .rc-controls button{
    display:flex; align-items:center; justify-content:center;
    width:30px; height:30px; border-radius:50%; flex:0 0 auto;
    background:rgba(20,18,16,.55); color:var(--cream);
    border:1px solid rgba(255,255,255,.25);
    cursor:pointer; transition:background .2s, border-color .2s;
    pointer-events:auto;
  }
  .rc-controls button:hover{ background:rgba(255,255,255,.14); border-color:var(--gold); color:var(--gold); }
  /* Flèches prev/next retirées sur mobile (demandé explicitement) : le
     glisser tactile sur l'anneau suffit, les boutons n'apportent rien de
     plus et prennent de la place sur un petit écran. */
  @media(max-width:900px){ .rc-controls{ display:none; } }
  .rc-controls button:active{ transform:scale(.94); }

  /* --- Petite loupe dorée qui suit la souris au survol des photos
     agrandissables (lightbox.js) : signale que la photo est cliquable pour
     un visu plein écran, même esprit visuel que .magnifier-lens (cercle
     bordé d'or) mais sans grossir l'image. .lb-zoom-parent est posée en JS
     sur le parent direct de chaque image ciblée par le sélecteur de zoom
     (voir lightbox.js), qui met aussi à jour left/top au déplacement de la
     souris. */
  .lb-zoom-parent{ position:relative; overflow:hidden; }
  .lb-zoom-hint{
    position:absolute; z-index:3; left:50%; top:50%;
    width:44px; height:44px; margin:-22px 0 0 -22px;
    display:flex; align-items:center; justify-content:center;
    border-radius:50%; border:2px solid var(--gold);
    background:rgba(10,10,10,.45); color:var(--gold);
    box-shadow:0 6px 16px rgba(0,0,0,.5);
    opacity:0; transition:opacity .2s ease; pointer-events:none;
  }
  .lb-zoom-parent:hover .lb-zoom-hint{ opacity:1; }
  @media(hover:none){ .lb-zoom-hint{ display:none; } }

  /* --- Lightbox : agrandissement d'une photo de carrousel --- */
  .lightbox{
    position:fixed; inset:0; z-index:1000;
    display:flex; align-items:center; justify-content:center;
    padding:4vh 4vw;
    background:rgba(10,10,10,0);
    opacity:0; visibility:hidden; pointer-events:none;
    transition:background .35s ease, opacity .35s ease, visibility .35s ease;
  }
  .lightbox.open{
    opacity:1; visibility:visible; pointer-events:auto;
    background:rgba(10,10,10,.94);
  }
  .lightbox{perspective:1800px;}
  /* --- Revue de presse : article lisible sous la photo ---
     Quand un article est présent (.has-article), le lightbox devient une
     colonne défilable au lieu d'une simple boîte centrée sur l'image, et un
     bouton "Réduire" reste fixé en haut de l'écran pendant tout le défilement
     (le clic-en-dehors ferme toujours la boîte, mais un article long peut
     occuper tout l'écran, d'où ce bouton toujours accessible). */
  .lightbox.has-article{
    align-items:flex-start;
    overflow-y:auto;
    -webkit-overflow-scrolling:touch;
  }
  .lightbox-scroll{
    display:flex; flex-direction:column; align-items:center;
    width:100%; max-width:820px; margin:0 auto;
  }
  .lightbox.has-article .lightbox-scroll{ min-height:100%; padding-bottom:6vh; }
  .lightbox-fixed-reduce{
    position:fixed; top:1.4rem; right:1.6rem; z-index:1001;
    display:flex; align-items:center; gap:.5rem;
    background:rgba(14,13,12,.9); border:1px solid var(--gold); color:var(--gold);
    padding:.55rem 1.1rem; border-radius:999px; cursor:pointer;
    font-family:'DM Sans',sans-serif; font-size:.76rem; font-weight:700;
    letter-spacing:.1em; text-transform:uppercase;
  }
  .lightbox-article{
    width:100%; max-width:720px; margin-top:1.8rem;
    background:var(--black-soft); border:1px solid var(--line); border-radius:10px;
    padding:1.8rem 1.9rem 2rem;
    text-align:center;
  }
  .lightbox-article-title{
    color:var(--gold); font-family:'Playfair Display',serif; font-weight:700;
    font-size:clamp(1.3rem,3vw,1.7rem); line-height:1.15;
    text-align:left; margin:0 0 1.1rem;
  }
  .lightbox-article p{
    color:var(--cream-dim); font-size:.98rem; line-height:1.85;
    white-space:pre-line; text-align:left; margin:0 0 1.6rem;
  }
  .lightbox-source{
    border-top:1px solid var(--line); margin:0 0 1.6rem; padding-top:1.2rem;
  }
  .lightbox-source-link{
    display:inline-flex; align-items:center; gap:.6rem;
    color:var(--cream-dim); text-decoration:none;
    font-family:'DM Sans',sans-serif; font-size:.85rem; letter-spacing:.02em;
    transition:color .2s;
  }
  .lightbox-source-link:hover{ color:var(--gold); }
  .lightbox-source-link:hover .lightbox-source-logo{ opacity:1; }
  .lightbox-source-logo{
    height:16px; width:auto; display:block; opacity:.9; transition:opacity .2s;
  }
  .lightbox-source-name{ white-space:nowrap; }
  .lightbox-source-caption{
    white-space:nowrap; opacity:.6; font-size:.78rem;
  }
  .lightbox-source-caption:not(:empty)::before{ content:'— '; }
  .lightbox-source-arrow{ opacity:.65; flex-shrink:0; }
  .lightbox-article-reduce{
    display:inline-flex; align-items:center; gap:.5rem; margin:0 auto;
    background:none; border:1px solid var(--gold); color:var(--gold);
    padding:.6rem 1.4rem; border-radius:999px; cursor:pointer;
    font-family:'DM Sans',sans-serif; font-size:.8rem; font-weight:700;
    letter-spacing:.08em; text-transform:uppercase;
  }
  .lightbox-article-reduce svg{ transform:rotate(180deg); }
  .lightbox img{
    max-width:100%; max-height:100%;
    border:1px solid var(--line);
    box-shadow:0 30px 70px rgba(0,0,0,.65);
    cursor:pointer;
    transform-origin:50% 50%;
    -webkit-transform-style:preserve-3d;
    transform-style:preserve-3d;
    -webkit-backface-visibility:hidden;
    backface-visibility:hidden;
    -webkit-user-drag:none; user-select:none; -webkit-user-select:none;
    -webkit-touch-callout:none; /* évite le menu contextuel (copier/enregistrer l'image) sur appui long, notamment quand la loupe est active */
    touch-action:none; /* désactive tous les gestes natifs (dont le minuteur d'appui long) sur Chrome/Android, où -webkit-touch-callout n'a aucun effet */
  }
  /* Revue de presse : pas de loupe, donc pas besoin de bloquer les gestes
     tactiles natifs sur la photo — au contraire, il faut pouvoir continuer à
     faire défiler avec le doigt même en touchant l'image, pour atteindre le
     texte de l'article juste en dessous. */
  .lightbox.has-article img{ touch-action:pan-y; }
  @media(prefers-reduced-motion:reduce){
    .lightbox, .lightbox img{transition:none;}
  }
  .carousel-item.placeholder{
    display:flex; align-items:center; justify-content:center;
    font-size:.6rem; letter-spacing:.08em; text-transform:uppercase;
    color:var(--cream-dim); text-align:center; padding:.5rem;
  }
  @keyframes carouselLR{
    0%{transform:translateX(0%);}
    100%{transform:translateX(-50%);}
  }
  .flip-back-overlay{
    position:relative; z-index:2; width:100%;
    padding:2rem;
    background:linear-gradient(0deg, rgba(0,0,0,.92) 20%, transparent 100%);
  }
  .flip-back-overlay a{
    font-weight:700; font-size:.8rem; letter-spacing:.1em; text-transform:uppercase;
    color:var(--gold);
    border-bottom:2px solid var(--gold); padding-bottom:2px; width:fit-content;
    display:inline-block;
  }

  /* --- Carrousel qui défile tout seul (fondu enchaîné), sans navigation
     manuelle : utilisé pour tester la carte Trémel avant de généraliser. --- */
  .auto-carousel-track{ position:absolute; inset:0; }
  .auto-carousel-track .auto-slide{
    position:absolute; inset:0;
    width:100%; height:100%; object-fit:cover;
    opacity:0; transition:opacity 1.4s ease;
    -webkit-user-drag:none; user-select:none; -webkit-user-select:none; -webkit-touch-callout:none;
  }
  .auto-carousel-track .auto-slide.is-active{ opacity:1; }

  /* --- Carrousel simple (défilement CSS natif, pas de 3D ni de glisser
     personnalisé) : une rangée de photos dans des cadres carrés, cliquables,
     avec flèches précédent/suivant. Testé uniquement sur la carte Trémel
     pour l'instant. --- */
  .simple-carousel{ width:100%; display:flex; align-items:center; gap:.5rem; }
  .simple-carousel .sc-frame{
    position:relative;
    flex:1 1 auto; min-width:0;
    overflow:hidden;
    cursor:grab;
    touch-action:pan-y;
  }
  .simple-carousel .sc-frame.dragging{ cursor:grabbing; }
  /* Fondu aux bords via deux calques fixes (peints une fois, jamais recomposés
     pendant le glisser) plutôt qu'un mask-image sur le conteneur : un masque
     CSS force le compositeur à repasser par un chemin plus lent pour tout ce
     qui bouge en dessous, à chaque frame — un calque statique par-dessus,
     lui, ne coûte rien pendant l'animation. */
  .simple-carousel .sc-frame::before,
  .simple-carousel .sc-frame::after{
    content:''; position:absolute; top:0; bottom:0; width:32px; z-index:2; pointer-events:none;
  }
  .simple-carousel .sc-frame::before{ left:0; background:linear-gradient(to right, var(--black), transparent); }
  .simple-carousel .sc-frame::after{ right:0; background:linear-gradient(to left, var(--black), transparent); }
  .simple-carousel .sc-track{
    display:flex; gap:.6rem;
    padding:.25rem .4rem;
    width:fit-content;
    will-change:transform;
  }
  .simple-carousel .sc-card{
    flex:0 0 auto;
    width:90px; aspect-ratio:1/1;
    border-radius:8px;
    border:2px solid var(--gold);
    background:var(--black-soft);
    overflow:hidden;
    cursor:pointer;
    opacity:.55;
    transition:opacity .25s ease, border-color .25s ease;
  }
  .simple-carousel .sc-card.active{ opacity:1; border-color:var(--gold); }
  .simple-carousel .sc-card img{
    width:100%; height:100%; object-fit:cover;
    pointer-events:none;
    -webkit-user-drag:none; user-select:none; -webkit-user-select:none; -webkit-touch-callout:none;
  }

  /* ============ SAVOIR-FAIRE ============ */
  .savoir-title{
    font-size:clamp(1.9rem,4vw,3rem);
    line-height:1.2;
  }
  .savoir-gold{ color:var(--gold); }
  .savoir-white{ color:var(--cream); font-size:.62em; display:inline-block; margin-top:.4rem; }
  .savoir-grid{
    display:grid;
    grid-template-columns:repeat(2,1fr);
    gap:2rem;
    max-width:1550px;
    margin:0 auto;
  }
  /* Reprend exactement la même hauteur responsive que .flip-card (voir plus
     haut) : .savoir-card a son propre height:500px fixe, plus spécifique par
     ordre d'apparition dans le fichier, qui écrasait silencieusement le
     clamp() de .flip-card sur ces cartes précises (numérotées 01-08,
     "Illusion & trompe-l'œil"... "L'art du portrait") — c'est ce qui les
     faisait encore déborder tout l'écran à 100% de zoom malgré le premier
     correctif. */
  .savoir-card{ height:clamp(400px, 52vh, 500px); }
  .savoir-card .flip-back-overlay p{
    color:var(--cream-dim); font-size:.85rem; line-height:1.6; margin-bottom:1rem;
  }

  /* ============ MÉTAMORPHOSE — AVANT/APRÈS ============ */
  .ba-grid{
    display:grid;
    grid-template-columns:repeat(2, 1fr);
    gap:2.5rem;
    max-width:1200px;
    margin:0 auto;
  }
  .ba-item{ display:flex; flex-direction:column; gap:.9rem; }
  .ba-slider{
    position:relative;
    aspect-ratio:4/3;
    overflow:hidden;
    border:1px solid var(--line);
    user-select:none;
    -webkit-user-select:none;
  }
  /* --- .ba-slider-fixed : le même composant .ba-slider (glisser pour
     comparer), mais logé dans un .parallax-band (position:fixed, plein
     écran) à la place d'une simple background-image — remplace l'ancien
     #tabarlyBand entre "Studio et atelier" et "Mon métier", et un 2e
     exemplaire (#boqueoHomeBand) entre "Entreprises" et "Métamorphose"
     (page d'accueil). Sur ordinateur, la boîte occupe 100% de la largeur de
     l'écran (demandé explicitement), la hauteur suivant le ratio réel de
     CHAQUE photo (posé en JS, lu depuis les attributs width/height de sa
     propre .ba-image img — voir script.js) : elle peut donc dépasser
     l'écran en hauteur, rognée par overflow:hidden sur #carnacHomeBand/
     #boqueoHomeBand (ci-dessous, plus limité au mobile) — sans quoi
     .ba-divider (hauteur/largeur 100% de .ba-slider-fixed) resterait mal
     calé sur les bords réels de la photo. Un calcul CSS min()/vw/vh avait
     été essayé à la place du JS mais s'est révélé peu fiable dans cet outil
     de test (résultats incohérents avec le viewport réel). */
  .ba-slider-fixed{
    position:absolute;
    top:50%; left:50%;
    transform:translate(-50%,-50%);
    border:none;
  }
  #carnacHomeBand, #boqueoHomeBand{ overflow:hidden; }
  /* Sur mobile : même zoom que tous les autres bandeaux photo de fond (~195%,
     calculé pour #carnacHomeBand) appliqué tel quel aux deux bandeaux fixes
     avant/après. Réduit ensuite à 60% de cette largeur (195% → 130%), demandé
     explicitement pour #carnacHomeBand (juste au-dessus de "Mon métier")
     puis appliqué pareil à #boqueoHomeBand (juste au-dessus de
     "Métamorphose") — la boîte reste plus large que l'écran (130% > 100%)
     donc continue d'occuper tout l'écran une fois recadrée par
     overflow:hidden, juste avec moins de zoom. */
  @media(max-width:640px){
    .ba-slider-fixed{ width:130%; height:auto; }
  }
  /* #carnacHomeBand (Plouharnel) : largeur repassée à 70% de sa taille
     d'origine (195% → 137%), demandé explicitement — reste bien au-dessus
     de 100% donc continue d'occuper tout l'écran une fois recadrée par
     overflow:hidden (comme #boqueoHomeBand ci-dessus), juste avec moins de
     zoom que les 130% essayés entre-temps. */
  @media(max-width:640px){
    #carnacHomeBand .ba-slider-fixed{ width:137%; }
  }
  /* #carnacHomeBand : gouttière blanche à droite du pignon alignée sur le
     bord droit de l'écran, demandé explicitement (position calée d'après un
     trait rouge annoté directement sur l'aperçu mobile). */
  @media(max-width:640px){
    #carnacHomeBand .ba-image img{ object-position:12% center; }
  }
  /* #boqueoHomeBand : l'ouverture en trompe-l'œil (porte de garage) est le
     sujet de la photo, pas la façade en pierre autour — centrée à l'écran
     sur mobile, demandé explicitement. */
  @media(max-width:640px){
    #boqueoHomeBand .ba-image img{ object-position:80% center; }
  }
  /* --- #carnacHomeBand / #boqueoHomeBand : pas de bouton play/pause visible
     (simple fond animé, pas besoin de contrôle manuel ici) — le cercle
     disparaît mais l'autoplay continue de tourner normalement (script.js le
     retrouve toujours via querySelector, juste caché visuellement). --- */
  #carnacHomeBand .ba-handle, #boqueoHomeBand .ba-handle{ display:none; }
  /* Ville + technique sous chaque slider avant/après, demandé explicitement. */
  .ba-caption{
    text-align:center;
    font-size:.85rem;
    color:var(--cream-dim);
  }
  .ba-caption strong{ color:var(--gold); font-weight:600; }
  .ba-image{
    position:absolute; inset:0;
    background:var(--black);
  }
  .ba-image img{
    width:100%; height:100%; object-fit:cover; display:block;
    -webkit-user-drag:none; user-select:none; -webkit-user-select:none;
    -webkit-touch-callout:none;
  }
  /* .ba-slider-contain (terrasse Guingamp) : slider avant/après affiché en
     plein format, sans recadrage — cadre ajusté au ratio réel des photos
     (2000x1124) et object-fit:contain au lieu du cover par défaut,
     demandé explicitement. */
  .chantier-step-media.ba-slider-contain{ aspect-ratio:2000/1124; }
  .ba-slider-contain .ba-image img{ object-fit:contain; }
  .ba-placeholder{
    width:100%; height:100%;
    display:flex; align-items:center; justify-content:center;
    text-align:center;
    color:var(--cream-dim);
    font-size:.75rem;
    letter-spacing:.1em;
    text-transform:uppercase;
    background:var(--black-soft);
  }
  .ba-before{ z-index:1; }
  /* will-change:clip-path — sans ça, chaque image (photos sources à pleine
     résolution, plusieurs milliers de pixels de large) est repeinte en
     entier à chaque frame quand le clip bouge ; avec, le navigateur la place
     sur son propre calque et se contente de déplacer le masque au
     compositeur. Sans intérêt pour un glisser ponctuel à la souris, mais
     nécessaire pour que la lecture automatique (~60 images/s) reste fluide,
     demandé explicitement après un essai encore saccadé malgré le passage
     du curseur en transform (voir script.js). */
  .ba-after{
    z-index:2;
    clip-path:inset(0 50% 0 0);
    will-change:clip-path;
  }
  /* Position pilotée en JS via left (voir script.js) : left:0 sert de base
     neutre, écrasée par le premier update() (appelé de façon synchrone,
     avant le premier affichage) qui pose le vrai pourcentage. */
  .ba-divider{
    position:absolute; top:0; bottom:0;
    left:0;
    width:2px;
    background:var(--gold);
    /* z-index au-dessus de .ba-range (5) : .ba-divider crée son propre
       contexte d'empilement (position + z-index), donc le z-index:6 de son
       enfant .ba-handle ne compte que par rapport aux AUTRES enfants de ce
       contexte, pas par rapport à .ba-range — sans ce z-index-ci au moins
       aussi haut, le bouton reste visuellement au-dessus mais reçoit les
       clics/survol en dessous du range natif (curseur ew-resize au lieu du
       pointeur, clics qui retombent sur le slider entier). */
    z-index:7;
    pointer-events:none;
  }
  /* .ba-handle est à la fois la poignée de glisser ET le bouton play/pause
     (un seul rond, comme demandé) : positionné à 50% de .ba-divider, il
     suit donc naturellement le curseur puisque c'est .ba-divider qui se
     déplace en JS — plus besoin de repositionner un second bouton séparé
     en parallèle (ancien .ba-play, retiré : les deux ronds se
     désolidarisaient visuellement dès que la lecture automatique bougeait
     le curseur). z-index au-dessus de .ba-range (5) pour rester cliquable
     malgré l'input qui recouvre tout le slider. */
  .ba-handle{
    position:absolute; top:50%; left:50%;
    transform:translate(-50%,-50%);
    z-index:6;
    width:38px; height:38px;
    padding:0;
    border-radius:50%;
    border:1.5px solid var(--gold);
    background:rgba(10,10,10,.95);
    color:var(--gold);
    display:flex; align-items:center; justify-content:center;
    cursor:pointer;
    pointer-events:auto; /* réactive les clics/survol : hérite sinon pointer-events:none de son parent .ba-divider */
    box-shadow:0 4px 14px rgba(0,0,0,.4);
    transition:transform .2s ease;
  }
  .ba-handle:hover{ transform:translate(-50%,-50%) scale(1.08); }
  .ba-handle .ba-pause-icon{ display:none; }
  .ba-handle.is-playing .ba-play-icon{ display:none; }
  .ba-handle.is-playing .ba-pause-icon{ display:block; }
  .ba-label{
    display:none; /* retiré à la demande : les étiquettes AVANT/APRÈS alourdissaient visuellement le slider */
    position:absolute; top:1rem;
    font-size:.68rem; letter-spacing:.15em; text-transform:uppercase;
    color:var(--cream);
    background:rgba(10,10,10,.55);
    padding:.35rem .75rem;
    z-index:4;
    pointer-events:none;
  }
  .ba-label-before{ left:1rem; }
  .ba-label-after{ right:1rem; }
  .ba-range{
    position:absolute; inset:0;
    width:100%; height:100%;
    margin:0;
    opacity:0;
    cursor:pointer;
    z-index:5;
    -webkit-appearance:none;
    appearance:none;
    touch-action:pan-y;
  }
  .ba-range::-webkit-slider-thumb{
    -webkit-appearance:none;
    width:38px; height:100%;
  }
  @media (hover:none){
    /* Sur tactile, le geste de glisser natif d'un <input type="range">
       capture le toucher pour lui-même dès le départ, quel que soit
       touch-action — le scroll vertical de la page se bloquait dès qu'on
       posait le doigt sur un slider avant/après. On désactive donc son
       interaction native ici et on reprend la main entièrement en JS
       (voir script.js), avec une détection de direction qui laisse le
       scroll vertical intact et ne verrouille le glisser horizontal
       qu'une fois le geste clairement identifié comme tel. Le survol
       (desktop, souris) n'est pas concerné : le range natif y fonctionne
       très bien puisqu'il n'y a pas de scroll tactile à ménager. */
    .ba-range{ pointer-events:none; }
  }
  /* --- 4 sliders visibles d'entrée, 9 de plus à déplier (13 au total) —
     même logique déplier/replier que .bio-wrap/.actu-wrap, avec en plus un
     bouton "Réduire" tout en bas de la liste dépliée pour refermer sans
     avoir à remonter tout le défilement jusqu'en haut de la section. --- */
  .ba-toggle-row{ text-align:center; margin-top:2.5rem; }
  .ba-wrap.expanded .ba-toggle .mt-arrow{ transform:rotate(180deg); }
  .ba-more{
    max-height:0;
    overflow:hidden;
    transition:max-height .6s ease;
    display:grid;
    grid-template-columns:repeat(2, 1fr);
    gap:2.5rem;
    max-width:1200px;
    margin:0 auto;
  }
  .ba-wrap.expanded .ba-more{margin-top:2.5rem;}
  .ba-close-row{ grid-column:1/-1; text-align:center; margin-top:.5rem; }

  /* ============ PORTFOLIO ============ */
  .portfolio-grid{
    display:grid;
    grid-template-columns:repeat(4, 1fr);
    grid-auto-rows:220px;
    gap:.6rem;
    max-width:1300px;
    margin:0 auto;
  }
  .portfolio-item{
    position:relative;
    overflow:hidden;
    background:var(--black-soft);
    border:1px solid var(--line);
  }
  .portfolio-item.tall{grid-row:span 2;}
  .portfolio-item.wide{grid-column:span 2;}
  .portfolio-item img{width:100%; height:100%; object-fit:cover; transition:transform .6s ease;}
  .portfolio-item:hover img{transform:scale(1.06);}
  .portfolio-placeholder{
    width:100%; height:100%;
    display:flex; align-items:center; justify-content:center;
    flex-direction:column; gap:.3rem;
    color:var(--cream-dim);
    font-size:.7rem;
    letter-spacing:.1em;
    text-transform:uppercase;
    text-align:center;
    padding:1rem;
  }
  .portfolio-caption{
    position:absolute; left:0; right:0; bottom:0;
    padding:1rem;
    background:linear-gradient(0deg, rgba(0,0,0,.85), transparent);
    font-family:'Playfair Display',serif;
    font-style:italic;
    font-size:1rem;
    opacity:0; transition:.4s;
  }
  .portfolio-item:hover .portfolio-caption{opacity:1;}
  .portfolio-more{text-align:center; margin-top:3rem;}
  .portfolio-filters{
    display:flex; flex-wrap:wrap; justify-content:center; gap:.7rem;
    margin-bottom:2.5rem;
  }
  .filter-btn{
    background:none;
    border:1px solid var(--line);
    color:var(--cream-dim);
    padding:.55rem 1.3rem;
    font-size:.78rem;
    letter-spacing:.08em;
    text-transform:uppercase;
    cursor:pointer;
    transition:.3s ease;
  }
  .filter-btn:hover{border-color:var(--gold); color:var(--cream);}
  .filter-btn.active{background:var(--gold); border-color:var(--gold); color:var(--black); font-weight:600;}
  .portfolio-item.filtered-out{
    display:none;
  }

  /* ============ AVIS ============ */
  .avis-viewport{
    overflow-x:auto;
    overflow-y:hidden;
    max-width:1200px;
    margin:0 auto;
    -webkit-mask-image:linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
    mask-image:linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
    scrollbar-width:none;
    -ms-overflow-style:none;
    cursor:pointer;
  }
  .avis-viewport::-webkit-scrollbar{ display:none; }

  /* Bandeau de photos défilant (même mécanique que les avis : molette,
     glisser, défilement auto, boucle infinie) mais en version simple photo,
     réutilisé par "dernières créations" et "enseignement & stages". */
  .strip-viewport{
    overflow-x:auto; overflow-y:hidden;
    -webkit-mask-image:linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
    mask-image:linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
    scrollbar-width:none; -ms-overflow-style:none;
    cursor:grab; margin-top:2.4rem;
  }
  .strip-viewport::-webkit-scrollbar{ display:none; }
  .strip-viewport.dragging{ cursor:grabbing; }
  .strip-track{ display:flex; gap:1.2rem; width:max-content; padding:0 5vw; }
  .strip-item{
    flex:0 0 auto; width:280px; aspect-ratio:4/3;
    position:relative; /* ancre pour le reflet (::after), voir plus bas */
    background:var(--black-soft);
  }
  /* .strip-item-inner porte le clipping (bords arrondis) : ce clipping doit
     rester sur un élément DIFFÉRENT de celui qui porte le reflet (::after),
     sinon overflow:hidden couperait net ce pseudo-élément positionné hors de
     sa propre boîte (top:100%). */
  .strip-item-inner{ width:100%; height:100%; border-radius:8px; overflow:hidden; }
  .strip-item-inner img{ width:100%; height:100%; object-fit:cover; display:block; }
  /* Reflet miroir (remplace -webkit-box-reflect, confirmé absent sur
     Android/Chrome mobile — propriété non standard jamais fiable partout,
     alors qu'elle s'affichait en test desktop). --reflect-src (l'image de la
     vignette en background-image) et --reflect-opacity (intensité,
     surchargée pour la marouflée) posés en style inline sur .strip-item
     dans le HTML. Même technique par masque que .rc-card::after. */
  .strip-item::after{
    content:'';
    position:absolute; left:0; top:calc(100% + 8px); width:100%; height:100%;
    background-image:var(--reflect-src, none);
    background-size:cover; background-position:center;
    border-radius:8px;
    transform:scaleY(-1);
    /* Forme d'origine (demandée explicitement) : net dès le bas de la photo
       (pas de fondu d'entrée), dégradé UNIQUEMENT vers le bas — voir le
       commentaire équivalent sur .rc-card::after pour le pourquoi de l'ordre
       des stops (inversé par transform:scaleY(-1)). */
    -webkit-mask-image:linear-gradient(to bottom, transparent 65%, rgba(255,255,255,var(--reflect-opacity,.2)) 100%);
    mask-image:linear-gradient(to bottom, transparent 65%, rgba(255,255,255,var(--reflect-opacity,.2)) 100%);
    pointer-events:none;
  }
  #actuStrip .strip-item-inner img{ cursor:pointer; }
  #maroufleStrip .strip-item-inner img{ cursor:pointer; }

  .avis-track{
    display:flex; gap:1.6rem;
    width:max-content;
  }
  .avis-flip{
    flex:0 0 340px;
    height:320px;
    perspective:1600px;
    /* .flip-card (règle générique) impose touch-action:pan-y — pensé pour le
       glisser horizontal de retournement des autres cartes, mais ça empêche
       aussi le doigt de faire défiler nativement .avis-viewport
       (overflow-x:auto) à l'horizontale en partant d'une carte, puisque le
       geste horizontal n'est alors autorisé sur aucun ancêtre. Restauré ici
       pour permettre le défilement tactile du bandeau, signalé comme
       manquant. */
    touch-action:pan-x pan-y;
  }
  .avis-front{
    background:var(--black-soft);
    justify-content:center;
  }
  /* Le dos ne montre que la photo de réalisation, sans texte par-dessus. */
  .avis-back{
    background-color:var(--black-soft);
    background-size:cover;
    background-position:center;
  }
  /* Nom + étoiles sur la même ligne, en haut de la carte, extrait en
     dessous (demandé explicitement — ordre précédent : étoiles, extrait,
     nom en bas). */
  .avis-head{
    display:flex; flex-direction:column;
    gap:.3rem;
    margin-bottom:1rem;
  }
  .avis-stars{color:var(--gold); letter-spacing:.2em;}
  .avis-front p{color:var(--cream-dim); line-height:1.7; font-size:.94rem;}
  /* Logo Google retiré des cartes d'avis individuelles (demandé
     explicitement) : déjà aria-hidden="true" (purement décoratif), donc un
     simple display:none suffit, sans toucher aux 18 occurrences identiques
     dans le HTML. Il reste affiché une seule fois, à côté des 5 étoiles, sur
     le badge "voir les avis" juste au-dessus (.google-badge-logo). */
  .avis-google-badge{ display:none; }
  .google-badge{
    display:inline-flex; align-items:center; gap:.6rem;
    margin-top:1.2rem;
    padding:.6rem 1.2rem;
    border:1px solid var(--gold);
    color:var(--cream);
    font-size:.85rem;
    transition:.3s;
  }
  .google-badge:hover{background:var(--gold); color:var(--black);}
  .google-badge-logo{ width:18px; height:18px; flex:0 0 auto; }
  .google-badge-logo svg{ display:block; width:100%; height:100%; }
  .google-badge-stars{color:var(--gold); letter-spacing:.05em; font-size:.9rem;}
  .google-badge:hover .google-badge-stars{color:var(--black);}
  .avis-name{
    font-family:'Playfair Display',serif;
    font-style:italic;
    color:var(--cream);
  }

  /* Page "Avis clients" : avis complets, avec photo de la réalisation, lieu
     et type de commande (le carrousel de l'accueil n'en montre qu'un résumé). */
  .avis-full-grid{
    display:grid;
    grid-template-columns:repeat(2,minmax(0,1fr));
    gap:1.6rem;
    max-width:1200px;
    margin:0 auto;
  }
  .avis-full-card{
    display:flex; flex-direction:column;
    background:var(--black);
    border:1px solid var(--line);
    border-radius:10px;
    overflow:hidden;
  }
  .avis-full-photo{
    margin:0;
    aspect-ratio:16/10;
    background:var(--black-soft);
    overflow:hidden;
  }
  .avis-full-photo img{
    display:block; width:100%; height:100%;
    object-fit:cover;
    cursor:zoom-in;
    transition:transform .5s ease;
  }
  .avis-full-card:hover .avis-full-photo img{ transform:scale(1.04); }
  /* Plusieurs photos pour un même avis : une seule visible, flèches en dessous
     (convention du site : flèches sous la photo, rondes, liseré or). */
  .avis-full-slides{ position:relative; }
  .avis-full-slides img{ position:absolute; inset:0; opacity:0; transition:opacity .45s ease; }
  .avis-full-slides img.is-active{ opacity:1; }
  .avis-full-card:hover .avis-full-slides img{ transform:none; }
  .avis-full-nav{
    display:flex; align-items:center; justify-content:center; gap:1rem;
    padding:.7rem 0 0;
    background:var(--black);
  }
  .avis-full-arrow{
    width:34px; height:34px; border-radius:50%;
    display:flex; align-items:center; justify-content:center;
    background:rgba(10,10,10,.55);
    border:1px solid var(--gold);
    color:var(--gold);
    cursor:pointer;
    transition:background .25s ease, color .25s ease;
  }
  .avis-full-arrow:hover{ background:var(--gold); color:var(--black); }
  .avis-full-count{
    min-width:3.2rem; text-align:center;
    color:var(--cream-dim); font-size:.8rem; letter-spacing:.1em;
  }
  .avis-full-body{
    display:flex; flex-direction:column;
    gap:1rem;
    padding:1.5rem 1.6rem 1.7rem;
    flex:1;
  }
  .avis-full-stars{ color:var(--gold); letter-spacing:.2em; font-size:1rem; }
  .avis-full-body blockquote{ margin:0; }
  .avis-full-body blockquote p{
    margin:0;
    font-family:'Playfair Display',serif;
    font-style:italic;
    font-size:1.05rem;
    line-height:1.75;
    color:var(--cream);
  }
  .avis-full-body blockquote p + p{ margin-top:.9rem; }
  .avis-full-author{ display:flex; flex-direction:column; gap:.15rem; }
  .avis-full-name{
    font-family:'Playfair Display',serif;
    font-weight:700;
    color:var(--gold);
    font-size:1rem;
  }
  .avis-full-role{ color:var(--cream-dim); font-size:.85rem; }
  .avis-full-meta{
    list-style:none; margin:auto 0 0; padding:1.1rem 0 0;
    border-top:1px solid var(--line);
    display:flex; flex-direction:column;
  }
  .avis-full-meta li{
    display:grid; grid-template-columns:6.4rem minmax(0,1fr);
    align-items:baseline; column-gap:.9rem;
    padding:.5rem 0;
    border-bottom:1px solid rgba(255,255,255,.06);
    color:var(--cream); font-size:.9rem; line-height:1.45;
  }
  .avis-full-meta li:last-child{ border-bottom:none; padding-bottom:0; }
  .avis-full-label{
    color:var(--gold);
    font-size:.66rem; font-weight:700;
    letter-spacing:.14em; text-transform:uppercase;
  }
  @media(max-width:760px){
    .avis-full-grid{ grid-template-columns:minmax(0,1fr); gap:1.2rem; }
    .avis-full-body{ padding:1.3rem 1.2rem 1.5rem; }
    .avis-full-meta li{ grid-template-columns:5.2rem minmax(0,1fr); column-gap:.7rem; }
  }

  /* ============ FAQ ============ */
  .faq-list{max-width:820px; margin:0 auto;}
  .faq-item{border-bottom:1px solid var(--line);}
  .faq-q{
    width:100%;
    display:flex; align-items:center; justify-content:space-between;
    gap:1rem;
    padding:1.6rem 0;
    background:none; border:none;
    color:var(--cream);
    font-family:'Playfair Display',serif;
    font-size:1.15rem;
    text-align:left;
    cursor:pointer;
  }
  .faq-q .plus{
    flex:0 0 auto;
    color:var(--gold);
    font-size:1.4rem;
    font-family:'DM Sans',sans-serif;
    transition:transform .3s ease;
  }
  .faq-item.open .plus{transform:rotate(45deg);}
  .faq-a{
    max-height:0;
    overflow:hidden;
    transition:max-height .4s ease;
  }
  .faq-a p{
    padding-bottom:1.6rem;
    color:var(--cream-dim);
    line-height:1.7;
    max-width:70ch;
  }
  .faq-a p a{
    color:var(--gold);
    text-decoration:underline;
    text-underline-offset:2px;
    text-decoration-color:rgba(201,166,80,.4);
    transition:text-decoration-color .2s;
  }
  .faq-a p a:hover{ text-decoration-color:var(--gold); }

  /* ============ FIL FACEBOOK ============ */
  .fb-embed-frame{
    max-width:540px;
    margin:0 auto;
    padding:1rem;
    background:var(--cream);
    border:1px solid var(--gold);
    display:flex;
    justify-content:center;
    overflow:hidden;
  }

  /* ============ CONTACT ============ */
  .contact-wrap{
    display:grid;
    grid-template-columns:1fr 1.2fr;
    gap:4rem;
    max-width:1200px;
    margin:0 auto;
  }
  .contact-info h2{
    font-size:1.5rem; color:var(--cream); margin-top:.7rem;
    /* Réserve la hauteur de 2 lignes en permanence : l'accroche tape/efface
       en boucle des phrases de longueurs différentes (voir #contactTypewriter
       dans script.js), et son nombre de lignes affiché varie donc pendant
       l'animation — sans cette réserve, tout le bloc en dessous "rebondit"
       (monte/descend) à chaque changement de ligne. */
    min-height:2.1em;
  }
  .contact-locate + h2{ margin-top:2.4rem; }
  .contact-atelier-photo{
    margin-top:1.8rem;
    border-radius:10px;
    overflow:hidden;
    border:1px solid var(--line);
  }
  .contact-atelier-photo img{
    width:100%; height:9rem; object-fit:cover; display:block;
  }
  .contact-info p{color:var(--cream-dim); line-height:1.7; margin-top:1.2rem; max-width:36ch;}
  .contact-tel-block{margin-top:2.2rem;}
  .contact-locate{
    margin-top:1.4rem;
  }
  .contact-locate-text .contact-tel-block{ margin-top:1.4rem; margin-bottom:.8rem; }
  .contact-locate-name{
    display:block;
  }
  .contact-locate-tagline{
    margin-top:.5rem !important;
    font-size:.86rem;
  }
  .contact-locate-zone{
    margin-top:.4rem !important;
    font-size:.8rem;
    letter-spacing:.01em;
    color:var(--cream-dim);
    opacity:.85;
  }
  .contact-locate-zone .zone-region-list{ display:inline-block; white-space:nowrap; font-size:.65rem; letter-spacing:0; }
  @media(max-width:340px){
  .contact-locate-zone .zone-region-list{ white-space:normal; }
  }
  .contact-locate-zone .zone-label{
    display:block;
    margin-bottom:.3rem;
    color:var(--gold);
    text-transform:uppercase;
    letter-spacing:.06em;
    font-weight:600;
  }
  .contact-locate-zone .zone-num{ color:var(--gold); font-weight:600; }
  .contact-locate-zone .zone-name{ color:var(--cream-dim); }
  .contact-locate-addr-row{
    display:flex;
    align-items:flex-start;
    gap:1rem;
    margin-top:2.4rem;
  }
  .contact-locate-addr-row .dept-map{ flex:0 0 auto; width:8.3rem; height:4.85rem; }
  .contact-locate-addr-row .dept-map svg{ width:100%; height:100%; display:block; }
  .contact-locate-addr-row .bzh-dept{
    fill:rgba(210,172,90,.12);
    stroke:var(--gold);
    stroke-width:1.4;
    stroke-linejoin:round;
  }
  .contact-locate-addr-row .bzh-dept.is-active{ fill:var(--gold); }
  .contact-locate-addr-row .dept-pin .pin-ring{ fill:none; stroke:var(--black); stroke-width:2.2; }
  .contact-locate-addr-row .dept-pin .pin-dot{ fill:var(--black); }
  .contact-locate-addr-row .dept-pin .pin-pulse{
    fill:none;
    stroke:var(--black);
    stroke-width:2;
    transform-box:fill-box;
    transform-origin:center;
    animation:deptPulse 2.4s ease-out infinite;
  }
  .contact-locate-address{
    display:block;
    margin-top:0 !important;
    max-width:none !important;
    text-decoration:none;
  }
  .contact-locate-address-lines{
    display:block;
    color:var(--cream-dim);
    line-height:1.6;
    border-bottom:1px solid transparent;
    transition:color .25s ease, border-color .25s ease;
  }
  .contact-locate-address:hover .contact-locate-address-lines{
    color:var(--cream);
    border-bottom-color:var(--gold);
  }
  .contact-locate-itin{
    display:flex;
    align-items:center;
    gap:.3rem;
    margin-top:.4rem;
    color:var(--gold);
    font-size:.72rem;
    letter-spacing:.14em;
    text-transform:uppercase;
    font-weight:600;
  }
  .contact-locate-itin svg{ flex:0 0 auto; }
  @media(max-width:420px){
  .contact-locate-addr-row{ flex-direction:column; align-items:flex-start; gap:.6rem; }
  .contact-locate-addr-row .dept-map{ width:clamp(70px, 30vw, 100px); }
  .contact-locate-addr-row .dept-map svg{ width:100%; height:auto; }
  }
  .call-btn{
    display:inline-flex; align-items:center; gap:.7rem;
    padding:.9rem 2rem;
    border:1px solid var(--gold);
    color:var(--cream);
    font-size:.85rem;
    letter-spacing:.1em;
    text-transform:uppercase;
    font-weight:600;
    background:transparent;
    transition:.35s ease;
  }
  .call-btn svg{ flex:0 0 auto; }
  .call-btn:hover{ background:var(--gold); color:var(--black); }
  .call-btn.disabled{
    color:var(--cream-dim);
    border-color:var(--line);
    pointer-events:none;
  }
  .phone-mobile-label{ display:none; }
  @media(max-width:560px){
    /* Sur téléphone, le numéro complet prend trop de place et n'apporte
       rien de plus qu'un bouton "Appeler" direct — on masque le texte du
       numéro, le lien tel: reste bien sûr fonctionnel. */
    #phoneLabel{ display:none; }
    .phone-mobile-label{ display:inline; }
  }
  .contact-tel-note{
    margin-top:.7rem;
    font-size:.78rem;
    color:var(--cream-dim);
    letter-spacing:.03em;
  }
  .contact-tel-note.closed{color:var(--gold);}

  .form-field{margin-bottom:1.8rem;}
  /* Champ piège anti-spam (honeypot) : invisible pour un visiteur humain
     (hors-écran, pas display:none — certains bots ignorent ce cas), mais
     rempli automatiquement par la plupart des robots de spam qui remplissent
     tous les champs du formulaire ; traitement-contact.php rejette
     silencieusement tout envoi où ce champ n'est pas vide. */
  .cf-hp{ position:absolute; left:-9999px; top:-9999px; width:1px; height:1px; overflow:hidden; }
  .form-field label{
    display:block;
    font-size:.72rem;
    letter-spacing:.15em;
    text-transform:uppercase;
    color:var(--cream-dim);
    margin-bottom:.5rem;
  }
  /* Bordure en rgba(gold,.35) plutôt que var(--line) (demandé explicitement
     — "les cadres manquent de visibilité, c'est classe mais peu lisible" :
     var(--line) est un brun quasi noir (#2a2822), à peine distinguable du
     fond sur ce formulaire, pourtant la page de conversion client la plus
     importante du site. Un contour doré discret (pas le plein `--gold`,
     réservé au focus/actif) reste dans l'esprit "classe" tout en étant
     nettement plus visible. */
  .form-field input[type=text],
  .form-field input[type=email],
  .form-field input[type=tel],
  .form-field textarea{
    width:100%;
    background:var(--black-soft);
    border:1px solid rgba(210,172,90,.35);
    color:var(--cream);
    padding:.85rem 1rem;
    font-family:'DM Sans',sans-serif;
    font-size:.95rem;
  }
  .form-field input:focus,
  .form-field textarea:focus{outline:1px solid var(--gold); border-color:var(--gold);}
  .form-field textarea{min-height:130px; resize:vertical;}

  /* --- Label flottant : chaque lettre s'envole en cascade au focus / à la saisie --- */
  .form-field.floating-label{position:relative;}
  .form-field.floating-label label{
    position:absolute; left:1rem; top:50%;
    transform:translateY(-50%);
    display:flex; margin:0;
    font-size:.95rem; letter-spacing:normal; text-transform:none;
    color:var(--cream-dim);
    pointer-events:none;
  }
  .form-field.floating-label.is-area label{top:.85rem; transform:none;}
  .form-field.floating-label label .fl-char{
    display:inline-block;
    transition:transform .4s cubic-bezier(.34,1.56,.64,1), color .4s ease, font-size .4s ease;
    transition-delay:calc(var(--i, 0) * 25ms);
  }
  .form-field.floating-label.floated label .fl-char{
    transform:translateY(-3.3em);
    font-size:.72rem;
    color:var(--gold);
  }
  @media(prefers-reduced-motion:reduce){
    .form-field.floating-label label .fl-char{transition:none;}
  }

  /* Cadre pointillé remplacé par un tracé doré animé (demandé explicitement
     — le pointillé passait inaperçu/pas clair) : même principe que le
     dessin progressif des pictogrammes "Surfaces d'intervention"
     (stroke-dashoffset qui descend à 0 puis reste figé, voir .surface-item
     plus haut) mais appliqué à un simple rectangle plutôt qu'une icône. Pas
     besoin de getTotalLength() ici : avec un viewBox fixe en 0-100 et un
     rect 0.5/0.5/99/99, le périmètre (2*(99+99)=396) est connu d'avance,
     quelle que soit la taille réelle affichée (preserveAspectRatio="none"
     étire le tracé, vector-effect:non-scaling-stroke garde une épaisseur de
     trait constante malgré cet étirement non uniforme). */
  .file-drop{
    position:relative;
    border:none;
    padding:1.6rem;
    display:flex; align-items:center; justify-content:center; gap:1.2rem;
    text-align:left;
    cursor:pointer;
    transition:.3s;
  }
  /* Pictogramme photo (demandé explicitement, entre le bord gauche et le
     texte) : même style que les autres pictogrammes du site (trait doré,
     stroke-linejoin:round) et même tracé progressif que le cadre ci-dessus,
     synchronisé sur le même déclenchement (.fd-in). --len posé en JS via
     getTotalLength() (voir script.js), comme .surface-item. */
  .file-drop-icon{
    flex:0 0 auto;
    width:52px; height:52px;
    stroke:var(--gold);
  }
  .file-drop-icon path, .file-drop-icon rect, .file-drop-icon circle{
    stroke-dasharray:var(--len, 200);
    stroke-dashoffset:var(--len, 200);
  }
  .file-drop-border.fd-in ~ .file-drop-icon path,
  .file-drop-border.fd-in ~ .file-drop-icon rect,
  .file-drop-border.fd-in ~ .file-drop-icon circle{
    animation:fileDropDraw 1s cubic-bezier(.65,0,.35,1) .2s forwards;
  }
  @media(prefers-reduced-motion:reduce){
    .file-drop-icon path, .file-drop-icon rect, .file-drop-icon circle{ stroke-dasharray:none; stroke-dashoffset:0; }
  }
  .file-drop-border{
    position:absolute; inset:0; width:100%; height:100%;
    pointer-events:none;
  }
  .file-drop-border rect{
    fill:none;
    stroke:var(--gold);
    stroke-width:1.5;
    /* Pas de vector-effect:non-scaling-stroke ici : combiné à l'étirement
       non uniforme de preserveAspectRatio="none" (boîte bien plus large que
       haute), ça cassait carrément le rendu des deux bords verticaux
       (invisibles) — bug constaté visuellement, pas juste théorique. Sans
       cette propriété, l'épaisseur du trait varie légèrement selon l'axe,
       imperceptible à cette taille. */
    stroke-dasharray:396;
    stroke-dashoffset:396;
  }
  .file-drop-border.fd-in rect{
    animation:fileDropDraw 1.3s cubic-bezier(.65,0,.35,1) forwards;
  }
  @keyframes fileDropDraw{ to{ stroke-dashoffset:0; } }
  @media(prefers-reduced-motion:reduce){
    .file-drop-border rect{ stroke-dasharray:none; stroke-dashoffset:0; }
    .file-drop-border.fd-in rect{ animation:none; }
  }
  .file-drop:hover, .file-drop.dragover{background:rgba(210,172,90,.05);}
  .file-drop:hover .file-drop-border rect, .file-drop.dragover .file-drop-border rect{stroke-width:2;}
  .file-drop input{display:none;}
  .file-drop-label{font-size:.85rem; color:var(--cream-dim);}
  .file-drop-label strong{color:var(--gold);}
  .file-list{margin-top:.9rem; display:flex; flex-wrap:wrap; gap:.6rem;}
  .file-chip{
    font-size:.75rem;
    padding:.35rem .7rem;
    border:1px solid var(--line);
    color:var(--cream-dim);
    display:flex; align-items:center; gap:.5rem;
  }
  .file-chip button{
    background:none; border:none; color:var(--gold); cursor:pointer; font-size:.9rem; line-height:1;
  }

  .form-status{
    margin-top:1rem;
    font-size:.85rem;
    padding:.8rem 1rem;
    display:none;
  }
  .form-status.show{display:block;}
  .form-status.ok{border:1px solid var(--gold); color:var(--gold);}
  .form-status.err{border:1px solid #c9584f; color:#e08078;}

  .optional-tag{
    text-transform:none; letter-spacing:normal; color:var(--cream-dim);
    opacity:.6; font-size:.85em; margin-left:.3em;
  }

  /* --- Type de demande (Fresque / Tableau / Stage / Exposition / Presse) :
     bascule les groupes de champs marqués data-cf-modes, voir script.js. --- */
  .cf-mode-toggle{display:flex; flex-wrap:wrap; gap:.7rem; margin-top:1.6rem;}
  .cf-mode-btn{
    flex:1 1 auto; min-width:6.5rem; padding:.85rem 1rem;
    background:var(--black-soft); border:1px solid rgba(210,172,90,.35); color:var(--cream-dim);
    font-family:'DM Sans',sans-serif; font-size:.82rem; letter-spacing:.05em; text-transform:uppercase;
    font-weight:600;
    cursor:pointer; transition:.25s;
  }
  .cf-mode-btn:hover{border-color:var(--gold); color:var(--cream);}
  .cf-mode-btn.active{border-color:var(--gold); color:var(--gold); background:rgba(210,172,90,.08);}
  @media(max-width:480px){
    /* 5 onglets à flex:1 sur une seule ligne forçaient la page à déborder
       horizontalement sur mobile (même bug que le bandeau de chiffres plus
       haut : flex, comme grid, ne rétrécit pas sous le min-content du texte).
       On les laisse s'enrouler sur 2-3 lignes plutôt que de les compresser. */
    .cf-mode-btn{ flex:1 1 calc(33% - .5rem); min-width:0; padding:.7rem .5rem; font-size:.72rem; }
  }

  /* --- Intérieur / extérieur --- */
  .io-toggle{display:flex; gap:.7rem;}
  .io-btn{
    flex:1; padding:.75rem 1rem;
    background:var(--black-soft); border:1px solid rgba(210,172,90,.35); color:var(--cream-dim);
    font-family:'DM Sans',sans-serif; font-size:.85rem; letter-spacing:.03em;
    cursor:pointer; transition:.25s;
  }
  .io-btn:hover{border-color:var(--gold); color:var(--cream);}
  .io-btn.active{border-color:var(--gold); color:var(--gold); background:rgba(210,172,90,.08);}

  /* --- Lieu du chantier (département / autre région) --- */
  .dept-toggle{ display:flex; gap:.7rem; flex-wrap:wrap; }
  .dept-num-btn{
    flex:0 0 auto;
    min-width:62px;
    padding:.7rem 1rem;
    background:var(--black-soft); border:1px solid rgba(210,172,90,.35);
    display:flex; align-items:center; justify-content:center;
    cursor:pointer; transition:.25s;
  }
  .dept-num-btn .num{ margin:0; font-size:1.2rem; color:var(--gold); }
  .dept-num-btn:hover{ border-color:var(--gold); }
  .dept-num-btn.active{ border-color:var(--gold); background:rgba(210,172,90,.08); }
  .dept-other-check{
    display:inline-flex; align-items:center; gap:.6rem;
    margin-top:1rem;
    color:var(--cream-dim); font-family:'DM Sans',sans-serif; font-size:.85rem; letter-spacing:.03em;
    cursor:pointer; transition:.25s;
  }
  .dept-other-check:hover{ color:var(--cream); }
  .dept-other-check input[type="checkbox"]{
    position:absolute; opacity:0; width:18px; height:18px; margin:0; cursor:pointer;
  }
  .dept-other-check .check-box{
    flex:0 0 auto; width:18px; height:18px;
    background:var(--black-soft); border:1px solid var(--line);
    display:inline-flex; align-items:center; justify-content:center;
    transition:.25s;
  }
  .dept-other-check:hover .check-box{ border-color:var(--gold); }
  .dept-other-check input:checked + .check-box{ border-color:var(--gold); background:rgba(210,172,90,.15); }
  .dept-other-check input:checked + .check-box::after{ content:''; width:9px; height:9px; background:var(--gold); }
  .dept-region-select{
    margin-top:.7rem;
    width:100%;
    padding:.75rem 1rem;
    background:var(--black-soft); border:1px solid rgba(210,172,90,.35); color:var(--cream);
    font-family:'DM Sans',sans-serif; font-size:.85rem; letter-spacing:.03em;
    cursor:pointer;
  }
  .dept-region-select[hidden]{ display:none; }
  .dept-region-select:focus{ outline:none; border-color:var(--gold); }

  /* --- Forme du mur --- */
  .shape-picker{display:flex; gap:.7rem; flex-wrap:wrap;}
  .shape-btn{
    flex:1; min-width:110px; padding:1rem .8rem;
    background:var(--black-soft); border:1px solid rgba(210,172,90,.35); color:var(--cream-dim);
    font-family:'DM Sans',sans-serif; font-size:.78rem; letter-spacing:.02em; text-align:center;
    cursor:pointer; transition:.25s;
    display:flex; flex-direction:column; align-items:center; gap:.6rem;
  }
  .shape-btn svg{width:40px; height:40px; stroke:currentColor; transition:.25s;}
  .shape-btn:hover{border-color:var(--gold); color:var(--cream);}
  .shape-btn.active{border-color:var(--gold); color:var(--gold); background:rgba(210,172,90,.08);}
  .shape-btn[hidden]{display:none;} /* .shape-btn{display:flex} l'emporterait sinon sur [hidden] à spécificité égale */

  .measures-hint{
    margin-top:.9rem; font-size:.78rem; color:var(--cream-dim); opacity:.75; line-height:1.5;
  }
  .measures-hint[hidden]{display:none;}

  .shape-measures{
    margin-top:.7rem; display:flex; gap:1rem; flex-wrap:wrap;
  }
  .shape-measures[hidden]{display:none;}
  .measure-field{flex:1; min-width:140px;}
  .measure-field label{
    display:block; font-size:.7rem; letter-spacing:.1em; text-transform:uppercase;
    color:var(--cream-dim); margin-bottom:.4rem;
    line-height:1.35; min-height:2.1em; /* réserve la hauteur de 2 lignes même sur les libellés courts, sinon les champs voisins désalignent leur case de saisie quand un libellé passe sur 2 lignes et l'autre non */
  }
  .measure-field input{
    width:100%; background:var(--black-soft); border:1px solid var(--line); color:var(--cream);
    padding:.7rem .85rem; font-family:'DM Sans',sans-serif; font-size:.9rem;
  }
  .measure-field input:focus{outline:1px solid var(--gold); border-color:var(--gold);}

  /* ============ FOOTER ============ */
  footer{
    border-top:1px solid var(--line);
    padding:5rem 5vw 2.5rem;
  }
  .footer-top{
    display:flex; justify-content:space-between; flex-wrap:wrap; gap:3rem;
    max-width:1300px; margin:0 auto 3.5rem;
  }
  .footer-sig{font-family:'Rock Salt',cursive; font-size:1.8rem; color:var(--gold);}
  .footer-cols{display:flex; gap:4rem; flex-wrap:wrap;}
  .footer-col h4{
    font-size:.75rem; letter-spacing:.2em; text-transform:uppercase; color:var(--gold);
    margin-bottom:1rem;
  }
  .footer-col a, .footer-col p{
    display:block; margin-bottom:.6rem; color:var(--cream-dim); font-size:.9rem;
  }
  .footer-col a:hover{color:var(--gold);}
  /* Liste "Mes réalisations par ville" repliée par défaut (15 liens, trop
     long en brut) : le h4 devient un bouton cliquable, la liste se déplie
     en dessous — demandé explicitement. */
  .footer-col-toggle{
    all:unset; cursor:pointer;
    display:flex; align-items:center; gap:.5rem;
  }
  .footer-col-toggle .mt-arrow{ flex:none; transition:transform .35s ease; }
  .footer-col-toggle[aria-expanded="true"] .mt-arrow{ transform:rotate(180deg); }
  .footer-col-list{ max-height:0; overflow:hidden; transition:max-height .5s ease; }
  .footer-col-list.is-open{ max-height:40em; }
  /* Colonne "Navigation" du footer : "Particuliers"/"Entreprises" en
     accordéon (rétabli, demandé explicitement) proposant leurs 3 pages ;
     tous les liens de premier niveau (Collectivités, Particuliers,
     Entreprises, Toiles et tableaux, Galerie avant après, Blog) en blanc
     (pas or) avec accent or au survol seulement — demandé explicitement. */
  .footer-nav-item{ margin-bottom:.6rem; }
  .footer-nav-toggle{
    all:unset; cursor:pointer;
    display:flex; align-items:center; gap:.4rem;
    text-transform:uppercase;
    font-size:.75rem;
    letter-spacing:.2em;
    color:var(--cream-dim);
    transition:color .3s ease;
  }
  .footer-nav-toggle:hover{ color:var(--gold); }
  .footer-nav-toggle .mt-arrow{ width:10px; height:10px; flex:none; transition:transform .35s ease; }
  .footer-nav-toggle[aria-expanded="true"] .mt-arrow{ transform:rotate(180deg); }
  .footer-nav-list{ max-height:0; overflow:hidden; transition:max-height .4s ease; }
  .footer-nav-list.is-open{ max-height:10em; margin-top:.5rem; }
  .footer-nav-list a{ display:block; margin-bottom:.6rem; font-size:.9rem; }
  /* Liens de premier niveau (Collectivités, Toiles et tableaux, Galerie
     avant après, Blog) : même style que les boutons d'accordéon ci-dessus
     pour rester cohérent. .footer-nav-gap ajoute un espace supplémentaire
     avant "Toiles et tableaux", qui suivait directement la liste Entreprises
     sans séparation visuelle et s'y confondait. */
  .footer-col a.footer-nav-top{
    text-transform:uppercase;
    font-size:.75rem;
    letter-spacing:.2em;
    color:var(--cream-dim);
  }
  .footer-col a.footer-nav-top:hover{ color:var(--gold); }
  .footer-col a.footer-nav-gap{ margin-top:1rem; }
  .footer-bottom{
    max-width:1300px; margin:0 auto;
    padding-top:2rem; border-top:1px solid var(--line);
    display:flex; justify-content:space-between; flex-wrap:wrap; gap:1rem;
    font-size:.75rem; color:var(--cream-dim); letter-spacing:.05em;
  }

  @media(max-width:900px){
    .flip-grid{grid-template-columns:1fr;}
    .portfolio-grid{grid-template-columns:repeat(2,1fr);}
    .portfolio-item.wide{grid-column:span 2;}
    .contact-wrap{grid-template-columns:1fr;}
    .fb-embed-frame{padding:.6rem;}
    .ba-grid{grid-template-columns:1fr;}
    .ba-more{grid-template-columns:1fr;}
    .savoir-grid{grid-template-columns:repeat(2,1fr);}
    .actu-grid{grid-template-columns:repeat(2,1fr);}
  }
  @media(max-width:560px){
    .savoir-grid{grid-template-columns:1fr;}
    .presse-grid{grid-template-columns:repeat(2,1fr); grid-auto-rows:140px;}
    /* reste sur 3 colonnes (pas d'empilement) : un empilement vertical rend
       le bandeau stats trop haut pour tenir dans le premier écran avec le
       hero, ce qui est maintenant requis quelle que soit la taille d'écran
       (voir .hero-viewport). */
    .ens-cta-long{ display:none; }
    .ens-cta-short{ display:inline; }
  }

/* =========================================================
   RÈGLES COLLECTIVITÉS — portée .page-coll (voir collectivites.html)
   ========================================================= */
  /* Le header (position, logo, header-actions, header-cta) n'a plus de
     surcharge .page-coll dédiée : cette page utilisait un duplicata plus
     ancien de ces règles (fixed + backdrop-filter + translateZ, bouton
     "devis" plein sans cta-long/cta-short) qui n'avait jamais reçu les
     correctifs mobile appliqués depuis à la règle globale header{} —
     d'où le logo qui repassait sur 2 lignes et le bouton surdimensionné.
     Elle hérite maintenant exactement des mêmes règles que index.html. */
  /* hero-content / hero-typewriter / #typewriter n'ont plus de surcharge
     .page-coll dédiée non plus, pour la même raison que le header : ce
     duplicata avait une ombre de texte plus lourde et une couleur d'accent
     différente (gold) de la règle globale (cream) utilisée par l'accueil.
     Idem pour l'ancien widget .bzh-stat/.bzh-num/.bzh-wrap (carte + chiffres
     inline), remplacé par le vrai bandeau .stats de l'accueil — inutilisé
     depuis, supprimé. */
  .page-coll .carousel-item img{width:100%; height:100%; object-fit:cover; display:block;}
  /* Ancien bandeau "avis" à défilement CSS pur (animation, non interactif)
     retiré : la page utilise désormais la règle .avis-viewport/.avis-track
     de base (overflow-x:auto), glissable/scrollable comme sur la page
     d'accueil, via le même initScrollStrip (script.js) — demandé
     explicitement ("il faudrait qu'il soit scrollable"). */
  .page-coll .avis-card{
    flex:0 0 340px;
    border:1px solid var(--line);
    padding:2rem;
    background:var(--black-soft);
  }
  .page-coll .avis-card p{color:var(--cream-dim); line-height:1.7; font-size:.94rem;}
  .page-coll .form-field{margin-bottom:1.3rem;}
  .page-coll .coll-main{ padding-top:0; }
  .page-coll .coll-hero{
    padding:11rem 5vw 4rem;
    text-align:center;
    border-bottom:1px solid var(--line);
  }
  .page-coll .coll-hero h1{
    font-size:clamp(2rem,5vw,3.4rem);
    max-width:20ch;
    margin:.8rem auto 0;
    color:var(--cream);
  }
  .page-coll .coll-hero-lede{
    max-width:60ch;
    margin:1.4rem auto 0;
    color:var(--cream-dim);
    font-size:1.05rem;
    line-height:1.75;
  }
  .page-coll .coll-section{ border-bottom:1px solid var(--line); }
  .page-coll .coll-alt{ background:var(--black-soft); }
  .page-coll .coll-locate{
    display:flex;
    /* flex-start et non center : le bloc de texte (eyebrow + titre + sous-
       titre) est plus haut que la carte, donc le centrer verticalement
       faisait dépasser "Fresque identitaire" au-dessus du haut de la carte
       au lieu de démarrer au même niveau qu'elle. */
    align-items:flex-start;
    justify-content:flex-start;
    gap:1.8rem;
    max-width:1400px;
    margin:0 auto 3.5rem;
  }
  .page-coll .coll-locate-map-col{
    display:flex;
    flex-direction:column;
    align-items:flex-start;
    gap:.7rem;
    flex:0 0 auto;
  }
  .page-coll .coll-locate-head{ margin:0; text-align:left; max-width:none; }
  .page-coll .coll-locate-head h2.nowrap{ white-space:nowrap; }
  .page-coll .coll-locate-head .loc-title{
    display:flex;
    align-items:center;
    gap:.55rem;
    color:var(--gold);
    font-size:clamp(1.7rem, 3.6vw, 2.6rem);
    letter-spacing:.16em;
    text-transform:uppercase;
    line-height:1;
  }
  .page-coll .coll-locate-head .loc-pin{ flex:0 0 auto; color:var(--gold); }
  .page-coll .coll-locate-head .loc-sub{
    display:block;
    margin-top:.55rem;
    margin-left:1.6rem;
    color:var(--cream-dim);
    font-size:.72rem;
    letter-spacing:.2em;
    text-transform:uppercase;
  }
  .page-coll .loc-tagline{
    margin-left:auto;
    max-width:72ch;
    padding-left:2.4rem;
    border-left:1px solid var(--line);
    text-align:left;
  }
  .page-coll .loc-tagline-kicker{
    display:block;
    color:var(--gold);
    font-size:1.2rem;
    letter-spacing:.2em;
    text-transform:uppercase;
    font-weight:600;
  }
  .page-coll .loc-tagline-desc{
    margin-top:.7rem;
    color:var(--cream);
    font-family:'DM Sans',sans-serif;
    font-weight:300;
    font-size:clamp(.95rem, 1.7vw, 1.15rem);
    line-height:1.6;
  }
  @media(max-width:760px){
  .page-coll .loc-tagline{
      margin-left:0;
      padding-left:0;
      border-left:none;
      max-width:none;
    }
  }
  .page-coll .dept-map{ flex:0 0 auto; width:clamp(96px, 20vw, 150px); }
  .page-coll .dept-map svg{ width:100%; height:auto; display:block; overflow:visible; }
  .page-coll .dept-map .bzh-dept{
    fill:rgba(210,172,90,.12);
    stroke:var(--gold);
    stroke-width:1.4;
    stroke-linejoin:round;
  }
  .page-coll .dept-map .bzh-dept.is-active{ fill:var(--gold); }
  .page-coll .dept-pin .pin-ring{ fill:none; stroke:var(--black); stroke-width:2.2; }
  .page-coll .dept-pin .pin-dot{ fill:var(--black); }
  .page-coll .dept-pin .pin-pulse{
    fill:none;
    stroke:var(--black);
    stroke-width:2;
    transform-box:fill-box;
    transform-origin:center;
    animation:deptPulse 2.4s ease-out infinite;
  }
  @keyframes deptPulse {
    0%{ transform:scale(.55); opacity:.6; }
    70%{ opacity:0; }
    100%{ transform:scale(2.2); opacity:0; }
  }
  @media(max-width:560px){
  .page-coll .coll-locate{ flex-direction:column; gap:1rem; }
  .page-coll .coll-locate-head{ text-align:center; }
  }
  .page-coll .coll-figure{
    max-width:1100px;
    margin:0 auto;
    border:1px solid var(--line);
    background:var(--black-soft);
  }
  .page-coll .coll-figure img{ width:100%; height:auto; display:block; }
  .page-coll .coll-flip{
    display:block;
    max-width:1100px;
    margin:0 auto;
    height:clamp(320px,55vh,520px);
    cursor:pointer;
  }
  /* --- "L'art mural pour tous" : carrousel "à l'étau" (.sq-carousel) — un
     grand panneau ouvert à gauche suivi de colonnes de plus en plus étroites,
     puis une file de fines lamelles ; cliquer une lamelle la ramène au premier
     plan, toute la bande glisse et chaque colonne recalcule sa largeur en même
     temps (l'effet "squeeze"). Construit entièrement en JS (voir script.js,
     IIFE .sq-carousel) à partir de la liste cachée .sq-data — sans React ni
     dépendance externe, adapté d'un composant fourni par l'utilisateur.
     Volontairement SANS container queries (container-type/cqi) : le composant
     d'origine s'en servait pour que la largeur des colonnes suive celle du
     carrousel plutôt que celle de la fenêtre, mais le support réel sur
     mobile reste inégal (rencontré en test : le composant restait invisible
     sur téléphone, la hauteur de .sq-row calculée en cqi n'étant simplement
     pas appliquée). --sq-hero/--sq-room/hauteur de .sq-row sont donc calculés
     en JS à partir de getBoundingClientRect (voir setVars dans script.js),
     qui fonctionne partout et donne le même résultat visuel. */
  .page-coll .sq-carousel{
    max-width:1100px;
    margin:0 auto;
  }
  /* Photo du premier plan affichée en plus grand au-dessus du carrousel,
     téléphone uniquement (voir @media plus bas) : sur mobile le clic
     n'ouvre plus la visionneuse plein écran (voir script.js), donc c'est le
     seul moyen d'y voir la photo en grand. Hauteur fixe + object-fit:cover
     (conteneur d'image stable) puisque les photos n'ont pas toutes le même
     format — jamais de saut de mise en page selon la photo affichée. */
  .page-coll .sq-preview{ display:none; }
  .page-coll .sq-preview img{
    width:100%; height:100%;
    object-fit:cover; object-position:var(--bp-x,50%) center; display:block;
    -webkit-user-drag:none; user-select:none; -webkit-user-select:none;
  }
  .page-coll .sq-row{
    width:100%; overflow:hidden;
    height:clamp(200px,32vw,340px);
  }
  .page-coll .sq-strip{
    display:flex; height:100%; width:max-content;
    transition:transform var(--sq-ms,700ms) var(--sq-ease,cubic-bezier(.16,1,.3,1));
  }
  .page-coll .sq-strip.sq-no-transition{ transition:none; }
  .page-coll .sq-card{
    position:relative; isolation:isolate;
    height:100%; flex-shrink:0;
    overflow:hidden;
    background:var(--black-soft);
    border:none; padding:0; margin:0; font:inherit; cursor:pointer;
    border-radius:6px;
    transition-property:width, margin-left;
    transition-timing-function:var(--sq-ease,cubic-bezier(.16,1,.3,1));
    transition-duration:var(--sq-ms,700ms);
  }
  .page-coll .sq-card.sq-no-transition{ transition-duration:0s; }
  .page-coll .sq-card.is-front{ cursor:default; }
  .page-coll .sq-card img{
    position:absolute; top:0; left:50%;
    height:100%; width:var(--sq-hero); max-width:none;
    transform:translateX(-50%);
    object-fit:cover; display:block;
    -webkit-user-drag:none; user-select:none; -webkit-user-select:none;
  }
  .page-coll .sq-overlay{
    position:absolute; inset:0 0 0 0;
    display:flex; align-items:flex-end;
    padding:1rem;
    background:linear-gradient(0deg, rgba(10,10,10,.75), transparent 60%);
    opacity:0; transition:opacity var(--sq-ms,700ms) var(--sq-ease,cubic-bezier(.16,1,.3,1));
    pointer-events:none;
  }
  .page-coll .sq-card.is-front .sq-overlay{ opacity:1; }
  .page-coll .sq-overlay span{
    font-size:.72rem; letter-spacing:.16em; text-transform:uppercase;
    color:var(--gold); font-weight:600;
  }
  @media(max-width:560px){
  .page-coll .sq-row{ height:clamp(150px,36vw,230px); }
  .page-coll .sq-preview{
    display:block;
    height:clamp(220px,62vw,320px);
    margin-bottom:1rem;
    border:2px solid var(--gold);
    overflow:hidden;
  }
  }
  /* Deux cartes .coll-flip dans la même section (ex. fresques monumentales) :
     sans cette marge elles se touchent directement, .coll-flip n'ayant par
     défaut aucun espacement vertical propre (un seul exemplaire par section
     jusqu'ici). */
  .page-coll .coll-flip + .coll-flip{ margin-top:3rem; }
  /* .section-head n'a qu'une marge basse (voir règle générale) : quand une
     carte .coll-flip la précède directement dans la même section (ex.
     "Crevez l'écran" après Plouescat, "Maîtriser tous les codes" après
     Pleyben), le titre se retrouve collé au bas de la carte, sans la
     respiration donnée partout ailleurs entre un titre et ce qui le
     précède. */
  .page-coll .coll-flip + .section-head{ margin-top:3.5rem; }
  .page-coll .coll-flip .flip-front, .page-coll .coll-flip .flip-back{ padding:0; overflow:hidden; }
  .page-coll .coll-flip .flip-front > img{
    position:absolute; inset:0;
    width:100%; height:100%;
    object-fit:cover; object-position:var(--bp-x,50%) center;
    display:block;
    -webkit-user-drag:none; user-select:none; -webkit-user-select:none;
  }
  .page-coll .coll-flip .flip-front::after{
    content:'';
    position:absolute; inset:0;
    background:linear-gradient(0deg, rgba(10,10,10,.78) 0%, rgba(10,10,10,.12) 42%, transparent 100%);
    pointer-events:none;
  }
  .page-coll .coll-flip .flip-back{ background:var(--black); }
  .page-coll .coll-flip .carousel-item img{ cursor:var(--zoom-cursor); }
  .page-coll .flip-close{
    position:absolute; top:.8rem; right:.8rem; z-index:4;
    width:40px; height:40px; border-radius:50%;
    background:rgba(10,10,10,.6);
    border:1px solid var(--gold);
    color:var(--gold);
    font-size:1.4rem; line-height:1; cursor:pointer;
    display:flex; align-items:center; justify-content:center;
    transition:.3s ease;
  }
  .page-coll .flip-close:hover{ background:var(--gold); color:var(--black); }
  .page-coll .coll-flip:hover .flip-inner{ transform:none; }
  .page-coll .coll-flip.flipped .flip-inner{ transform:rotateY(180deg); }
  /* Le blocage ci-dessus n'arrete que la rotation 3D : les regles generiques
     .flip-card:hover .flip-back/.flip-front (plus haut) s'appliquent quand
     meme au survol et affichaient la face arriere sans la faire pivoter -
     .flip-back garde son propre transform:rotateY(180deg) et son fond noir
     (backface-visibility peu fiable, voir plus haut), d'ou une carte qui
     "disparait" (devient noire) des qu'on la survole sans avoir cliqué -
     constate explicitement sur la carte #igor-stravinsky juste apres
     fermeture (le curseur reste dessus). .coll-flip ne se retourne qu'au
     clic (classe .flipped) : le survol seul ne doit jamais afficher la face
     arriere. */
  .page-coll .coll-flip:not(.flipped):hover .flip-back{ opacity:0; pointer-events:none; }
  .page-coll .coll-flip:not(.flipped):hover .flip-front{ opacity:1; pointer-events:auto; }
  .page-coll .flip-decouvrir{
    position:absolute; z-index:2;
    left:50%; bottom:1.8rem; transform:translateX(-50%);
    font-family:'Playfair Display',serif;
    font-style:italic;
    font-size:clamp(1.5rem,4vw,2.3rem);
    color:var(--gold);
    padding:.7rem 2.2rem;
    border:1px solid var(--gold);
    background:rgba(10,10,10,.35);
    letter-spacing:.02em;
    white-space:nowrap;
    transition:.3s ease;
  }
  .page-coll .coll-flip:hover .flip-decouvrir{ background:var(--gold); color:var(--black); }
  /* Sur certains mobiles, backface-visibility:hidden ne suffit pas toujours à
     masquer la face avant une fois la carte retournée (le texte "Découvrir"
     restait visible par-dessus le dos de la carte) : on le masque aussi
     explicitement via opacity dès que .flipped est posé. */
  .page-coll .coll-flip.flipped .flip-decouvrir{ opacity:0; pointer-events:none; }
  .page-coll .flip-decouvrir.flip-decouvrir--sm{
    font-size:clamp(1.05rem,2.6vw,1.5rem);
    padding:.6rem 1.7rem;
  }
  .page-coll .coll-gallery{
    display:grid;
    grid-template-columns:repeat(auto-fit,minmax(240px,1fr));
    gap:.9rem;
    max-width:1200px;
    margin:0 auto;
  }
  .page-coll .coll-cell{
    border:1px solid var(--line);
    background:var(--black-soft);
    overflow:hidden;
  }
  .page-coll .coll-cell img{ width:100%; height:100%; object-fit:cover; display:block; cursor:var(--zoom-cursor); }
  .page-coll .coll-figure img{ cursor:var(--zoom-cursor); }
  .page-coll img.zoomable, .page-coll [data-zoomable] img{ cursor:var(--zoom-cursor); }
  .page-coll .lightbox{
    /* left/right/bottom fixes ; top est réajusté en JS à chaque ouverture
       (hauteur réelle du header, variable selon la largeur d'écran) pour
       laisser le header — et son bouton d'appel à l'action — visible et
       cliquable au-dessus, plutôt que recouvert. */
    position:fixed; left:0; right:0; bottom:0; top:0; z-index:2000;
    background:rgba(6,6,6,.93);
    /* Le fond est déjà presque opaque (.93) : le backdrop-filter:blur ne
       change quasiment rien à ce qu'on voit au travers, mais sur certains
       GPU/navigateurs, le flou de compositing appliqué à ce calque peut
       déteindre visuellement sur la photo posée par-dessus (rendue floue
       alors qu'elle est nette) — retiré, le gain visuel ne valait pas ce
       risque. */
    display:none;
    /* justify-content:flex-start (pas center) : quand la photo + les
       flèches + "Vous aimerez aussi" dépassent la hauteur disponible (petite
       fenêtre, écran court), un centrage vertical classique déborde à
       l'identique en haut ET en bas — la moitié qui déborde en haut sort
       alors de la boîte du lightbox et se retrouve visuellement derrière le
       header (repéré via elementFromPoint : le header restait la cible du
       clic à cet endroit malgré son z-index plus bas). Aligner au départ
       garantit qu'un éventuel dépassement se fait uniquement vers le bas,
       dans la zone défilable (overflow-y:auto), jamais vers le header. */
    align-items:center; flex-direction:column;
    justify-content:flex-start; /* repli sûr si "safe center" n'est pas supporté */
    justify-content:safe center;
    gap:1.1rem;
    padding:3vh 4vw;
    overflow-y:auto;
  }
  .page-coll .lightbox.open{ display:flex; }
  .page-coll .lb-stage{
    /* Hauteur fixe (plutôt qu'un simple max-height posé sur l'image) : les
       photos n'ont pas toutes le même format (paysage large, portrait
       étroit...), et sans ce cadre stable, les flèches et "Vous aimerez
       aussi" en dessous remontaient/descendaient à chaque changement de
       photo. La photo se centre à l'intérieur de ce cadre, quel que soit
       son format — seule sa taille affichée varie, jamais la position de
       ce qui suit. */
    position:relative;
    display:inline-flex; align-items:center; justify-content:center;
    max-width:100%;
    height:60vh;
    flex:0 0 auto;
  }
  .page-coll .lb-stage img{
    max-width:100%;
    max-height:100%;
    width:auto; height:auto;
    display:block;
    border:1px solid var(--gold);
    cursor:none;
    touch-action:none;
    transform-origin:center center;
    -webkit-user-drag:none; user-select:none; -webkit-user-select:none;
    -webkit-touch-callout:none;
  }
  .page-coll .lb-lens{
    /* position:fixed (relatif au viewport, pas à .lb-stage) et z-index élevé :
       en position:absolute dans .lb-stage, la loupe pouvait dépasser au-dessus
       de la boîte de .lightbox (overflow-y:auto) près du bord haut d'une
       photo — un contenu qui déborde ainsi un conteneur scrollable n'est pas
       peint par-dessus le header malgré un z-index plus élevé. En position
       fixe, la loupe échappe entièrement à ce découpage. */
    position:fixed;
    z-index:2200;
    pointer-events:none;
    width:220px; height:220px;
    border-radius:50%;
    border:2px solid var(--gold);
    box-shadow:0 8px 30px rgba(0,0,0,.6), inset 0 0 0 1px rgba(10,10,10,.4);
    background-repeat:no-repeat;
    background-color:var(--black);
    display:none;
  }
  .page-coll .lb-nav-row{
    flex:0 0 auto;
    display:flex; align-items:center; justify-content:center;
    gap:1.4rem;
  }
  .page-coll .lb-nav{
    width:52px; height:52px; border-radius:50%;
    background:rgba(10,10,10,.55);
    border:1px solid var(--gold); color:var(--gold);
    cursor:pointer; z-index:3;
    display:flex; align-items:center; justify-content:center;
    transition:.3s ease;
  }
  .page-coll .lb-nav:hover{ background:var(--gold); color:var(--black); }
  .page-coll .lb-nav[hidden]{ display:none; }
  .page-coll .lb-nav-row:has(.lb-nav[hidden]){ display:none; }
  @media(max-width:560px){
  .page-coll .lb-nav{ width:42px; height:42px; }
  }
  .page-coll .lb-suggest{
    flex:0 0 auto;
    display:flex; flex-direction:column; align-items:center;
    gap:.6rem;
    width:100%;
  }
  .page-coll .lb-suggest-label{
    text-align:center;
    color:var(--gold);
    font-size:.8rem;
    letter-spacing:.16em;
    text-transform:uppercase;
    line-height:1.3;
  }
  .page-coll .lb-suggest-set{ display:none; width:100%; }
  .page-coll .lb-suggest-set.is-active{ display:block; }
  .page-coll .lb-suggest-viewport{
    width:100%;
    overflow:hidden;
    -webkit-mask-image:linear-gradient(90deg, transparent, #000 4%, #000 96%, transparent);
    mask-image:linear-gradient(90deg, transparent, #000 4%, #000 96%, transparent);
    cursor:grab;
    touch-action:pan-y;
  }
  .page-coll .lb-suggest-viewport.dragging{ cursor:grabbing; }
  .page-coll .lb-suggest-track{
    display:flex; gap:.55rem;
    width:max-content;
    will-change:transform;
  }
  .page-coll .lb-thumb{
    flex:0 0 auto;
    width:132px; height:88px;
    overflow:hidden;
    border:1px solid var(--gold);
    display:block;
  }
  .page-coll .lb-thumb img{
    width:100%; height:100%;
    object-fit:cover; display:block;
    transition:transform .4s ease, opacity .3s ease;
    opacity:.85;
    pointer-events:none;
    -webkit-user-drag:none; user-select:none; -webkit-user-select:none; -webkit-touch-callout:none;
  }
  .page-coll .lb-thumb:hover img{ transform:scale(1.08); opacity:1; }
  @media(max-width:560px){
  .page-coll .lb-thumb{ width:130px; height:86px; }
  /* Le carrousel de suggestions s'étire jusqu'aux bords de l'écran malgré
     le padding horizontal de .lightbox (calc(50% - 50vw) = l'astuce
     classique pour « sortir » du conteneur centré). */
  .page-coll .lb-suggest{
    width:100vw;
    margin:0 calc(50% - 50vw);
  }
  .page-coll .lb-suggest-viewport{ -webkit-mask-image:none; mask-image:none; }
  .page-coll .lb-suggest-track{ padding:0 3vw; }
  .page-coll .lb-stage{ height:42vh; height:42dvh; }
  }
  .page-coll .lb-close{
    position:absolute; top:2.2vh; right:3vw;
    width:46px; height:46px; border-radius:50%;
    background:none; border:1px solid var(--line); color:var(--cream);
    font-size:1.7rem; line-height:1; cursor:pointer; z-index:3;
    display:flex; align-items:center; justify-content:center;
    transition:.3s;
  }
  .page-coll .lb-close:hover{ border-color:var(--gold); color:var(--gold); }
  @media(max-width:560px){
  .page-coll .lb-lens{ width:150px; height:150px; }
  }
  .page-coll .coll-cta{
    display:flex; flex-wrap:wrap; justify-content:center; gap:1rem;
    margin-top:2.6rem;
  }
  .page-coll .coll-final{ text-align:center; border-bottom:none; }
  .page-coll .coll-toggle{
    cursor:pointer;
    background:none;
    border:none;
    padding:0;
    color:var(--gold);
    font-family:'DM Sans',sans-serif;
    font-weight:300;
    font-size:.8rem;
    letter-spacing:.18em;
    text-transform:uppercase;
    transition:color .3s ease;
  }
  .page-coll .coll-toggle:hover{ color:var(--gold-light); }
  .page-coll .coll-toggle::after{
    content:'▾';
    margin-left:.5rem;
    display:inline-block;
    transition:transform .3s ease;
  }
  .page-coll .coll-toggle.is-open::after{ transform:rotate(180deg); }
  .page-coll .details-project-figure{
    position:relative;
    max-width:1400px;
    margin:0 auto;
    overflow:hidden;
    border:2px solid var(--gold);
    background:var(--black-soft);
  }
  .page-coll .details-project-figure > img{ display:block; width:100%; height:auto; }
  .page-coll .dp-carousel{ aspect-ratio:3 / 2; }
  .page-coll .dp-slides{ position:absolute; inset:0; }
  .page-coll .dp-slide{
    position:absolute; inset:0;
    width:100%; height:100%;
    object-fit:cover;
    opacity:0;
    pointer-events:none;
    transition:opacity .6s ease;
    -webkit-user-drag:none; user-select:none; -webkit-user-select:none; -webkit-touch-callout:none;
  }
  .page-coll .dp-slide.is-active{ opacity:1; pointer-events:auto; cursor:var(--zoom-cursor); }
  .page-coll .dp-nav{
    position:absolute; top:1rem;
    width:38px; height:38px; border-radius:50%;
    display:flex; align-items:center; justify-content:center;
    background:rgba(10,10,10,.55);
    border:1px solid var(--gold);
    color:var(--gold);
    cursor:pointer; z-index:3;
    transition:.3s ease;
  }
  .page-coll .dp-nav:hover{ background:var(--gold); color:var(--black); }
  .page-coll .dp-prev{ left:1rem; }
  .page-coll .dp-next{ right:1rem; }
  .page-coll .details-project-panel{
    position:absolute; left:0; right:0; bottom:0;
    z-index:2;
    display:flex; flex-direction:column;
    background:rgba(10,10,10,.86);   
  }
  .page-coll .details-project-panel::before{           
    content:'';
    position:absolute; left:0; right:0; bottom:100%;
    height:2.5rem;
    background:linear-gradient(0deg, rgba(10,10,10,.86), transparent);
    pointer-events:none;
  }
  .page-coll .details-project-text{
    max-height:3.4rem;                 
    overflow:hidden;
    transition:max-height .5s ease;
    scrollbar-width:none;              
    -ms-overflow-style:none;
    -webkit-mask-image:linear-gradient(180deg, #000 62%, transparent 100%);
    mask-image:linear-gradient(180deg, #000 62%, transparent 100%);
  }
  .page-coll .details-project-text.is-open{
    max-height:12rem;                  
    overflow-y:auto;
    
    -webkit-mask-image:linear-gradient(180deg, transparent 0%, #000 38%, #000 62%, transparent 100%);
    mask-image:linear-gradient(180deg, transparent 0%, #000 38%, #000 62%, transparent 100%);
  }
  .page-coll .details-project-text::-webkit-scrollbar{ display:none; }
  .page-coll .details-project-text-inner{ padding:1.1rem 1.8rem 0; }
  .page-coll .details-project-text-inner p{
    color:var(--cream);
    line-height:1.75;
    margin:0;
    font-size:1.05rem;
    text-align:justify;
  }
  .page-coll .details-project-text-inner p + p{ text-indent:1.6em; }
  .page-coll .details-project-cta{
    display:flex; justify-content:flex-end;
    padding:.35rem 1.4rem .8rem;
  }

  /* --- Trémel : le texte de l'œuvre n'est plus en overlay sur la photo ni
     en dessous — il vit maintenant dans .coll-locate-summary, à droite du
     bloc carte/titre, avec un résumé de 3 lignes et un bouton "En savoir
     plus" qui déplie le texte en entier. --- */
  #tremel-1 .details-project-text{
    max-height:none;
    overflow:visible;
    -webkit-mask-image:none;
    mask-image:none;
  }
  #tremel-1 .details-project-text:not(.is-open) .details-project-text-inner{
    display:-webkit-box;
    -webkit-line-clamp:3;
    -webkit-box-orient:vertical;
    overflow:hidden;
  }
  #tremel-1 .details-project-text.is-open{ max-height:none; overflow:visible; }
  #tremel-1 .details-project-cta{ justify-content:flex-start; padding:.8rem 0 0; }
  /* La marge héritée de .details-project-text-inner (pensée pour le panneau
     en overlay d'origine) décalait le texte des vrais bords du bloc — texte
     et bouton doivent aller jusqu'à la marge, comme le reste de la mise en
     page desktop/tablette. */
  #tremel-1 .details-project-text-inner{ padding:0; }
  /* text-align:justify (hérité du panneau d'origine, pensé pour une colonne
     étroite en overlay) étire les espaces entre les mots de façon inégale
     maintenant que le texte occupe toute la largeur de la page — d'où des
     "trous" visibles entre certains mots. Aligné à gauche à la place. */
  #tremel-1 .details-project-text-inner p{ text-align:left; }
  /* Le pin de localisation devant "Trémel" a été retiré : le sous-titre
     "Côtes-d'Armor · 22" avait une marge à gauche pour s'aligner avec le
     texte après ce pin (icône + gap ≈ 1.6rem) — sans le pin, ça décale
     le sous-titre par rapport au titre. */
  #tremel-1 .loc-sub{ margin-left:0; }
  #tremel-1 .coll-locate-divider{
    align-self:stretch;
    width:1px;
    background:var(--line);
    flex:0 0 auto;
  }
  #tremel-1 .coll-locate-summary{
    flex:1 1 auto;
    align-self:flex-start;
    min-width:0;
  }

  /* --- Cartes .tremel-nested (Trémel puis généralisé aux 5 autres cartes de
     "Mon métier") : retournement au SURVOL identique aux autres cartes
     (couverture ↔ carrousel), puis un second retournement imbriqué,
     déclenché au CLIC sur « En savoir plus », qui bascule uniquement à
     l'intérieur de la face arrière (carrousel ↔ texte complet). Scopé à la
     classe .tremel-nested, partagée par toutes les cartes concernées. --- */
  .tremel-nested .flip-back.tremel-back{ padding:0; overflow:hidden; }
  .tremel-nested .tremel-back-inner{
    position:absolute; inset:0;
  }
  .tremel-nested .tremel-back-face{
    position:absolute; inset:0;
    display:flex; flex-direction:column; justify-content:flex-end;
    padding:2rem;
    opacity:1; transition:opacity .5s ease;
  }
  .tremel-nested.showing-text .tremel-back-carousel{ opacity:0; pointer-events:none; }
  /* --- Cartes .coll-flip devenues aussi .tremel-nested (ex. cinéma de
     Plouescat) : leur propre croix .flip-close (retour à la couverture)
     resterait sinon visible par-dessus la croix .tremel-text-close (retour
     au carrousel) pendant l'affichage du texte — les deux se superposent au
     même coin. On efface la première tant que le texte est affiché. --- */
  .tremel-nested.showing-text .flip-close{ opacity:0; pointer-events:none; }
  .tremel-nested:not(.showing-text) .tremel-back-text{ opacity:0; pointer-events:none; }
  .tremel-nested .tremel-back-carousel{ padding:0; justify-content:flex-end; }
  /* --- Flèches précédent/suivant sur le ticker "Grandeur nature" (injectées
     en JS, voir script.js) : ordinateur uniquement — le tactile a déjà le
     glissement horizontal pour accélérer le défilement. --- */
  .page-coll .gn-nav-arrow{
    display:none;
    position:absolute; top:50%; z-index:3;
    width:42px; height:42px;
    align-items:center; justify-content:center;
    border-radius:50%;
    background:rgba(10,10,10,.55);
    border:1px solid var(--gold);
    color:var(--gold);
    cursor:pointer;
    transition:.3s ease;
    transform:translateY(-50%);
  }
  .page-coll .gn-nav-arrow:hover{ background:var(--gold); color:var(--black); }
  .page-coll .gn-nav-arrow.gn-nav-prev{ left:.9rem; }
  .page-coll .gn-nav-arrow.gn-nav-next{ right:.9rem; }
  @media(hover:hover) and (pointer:fine){
    .page-coll .gn-nav-arrow{ display:flex; }
  }
  /* --- Diaporama plein cadre (injecté en JS) : couche affichée au premier
     clic sur une flèche, une photo à la fois, à la place du ticker qui
     laisse toujours voir des bouts de photos voisines. --- */
  .page-coll .gn-slide{
    display:none;
    position:absolute; inset:0;
    z-index:2;
  }
  .page-coll .gn-slide.is-active{ display:block; }
  .page-coll .gn-slide img{
    width:100%; height:100%;
    object-fit:cover;
    display:block;
    cursor:var(--zoom-cursor);
  }
  .page-coll .carousel-viewport.gn-paused{ opacity:0; pointer-events:none; }
  /* --- Grande photo + petit carrousel carré : partagé par toutes les cartes
     de cette page qui utilisent ce système (Trémel, et les 5 autres cartes
     de la page collectivités une fois généralisé), pas seulement Trémel. --- */
  .page-coll .flip-back .carousel-hero{
    position:relative; width:100%; flex:1 1 auto; min-height:0; overflow:hidden;
  }
  .page-coll .flip-back .carousel-hero img{
    width:100%; height:100%; object-fit:cover; object-position:var(--bp-x,50%) center; display:block;
    cursor:var(--zoom-cursor);
    -webkit-user-drag:none; user-select:none; -webkit-user-select:none;
  }
  .page-coll .flip-back .simple-carousel{ flex:0 0 auto; padding:.6rem 1rem; }
  .tremel-nested .tremel-more-link{
    /* z-index:4, au-dessus des flèches gn-nav-arrow (3) et du diaporama
       gn-slide (2) : sans ça, une fois le diaporama manuel actif (photo
       figée après clic sur une flèche), il recouvre ce bouton — même
       z-index que gn-slide à l'origine, départagé par l'ordre du DOM (le
       diaporama, ajouté après en JS, passait dessus). */
    position:relative; z-index:4;
    align-self:flex-start;
    margin:.6rem 2rem 1.2rem;
    /* Cartouche plutôt qu'un simple soulignement : posé directement sur la
       photo (ou, pour le cinéma, sur un ticker noir et blanc très chargé),
       le texte doré seul devenait illisible sans un fond propre derrière. */
    background:rgba(10,10,10,.72);
    border:1px solid var(--gold); border-radius:6px;
    padding:.55rem 1.1rem;
    font-family:'DM Sans',sans-serif; font-weight:700; font-size:.8rem; letter-spacing:.1em; text-transform:uppercase;
    color:var(--gold);
    cursor:pointer;
    transition:background .3s ease, color .3s ease;
  }
  .tremel-nested .tremel-more-link:hover{ background:var(--gold); color:var(--black); }
  .tremel-nested .tremel-back-text{
    background:var(--black);
    justify-content:flex-start;
    overflow-y:auto;
    scrollbar-width:none;
    -ms-overflow-style:none;
    padding-bottom:0;
  }
  .tremel-nested .tremel-back-text::-webkit-scrollbar{ display:none; }
  /* --- Un texte court (en attendant le texte définitif d'une carte) laissait
     tout le bas du panneau en noir, l'air "cassé" à côté de Trémel qui
     remplit tout l'espace. margin:auto sur ce bloc le centre verticalement
     quand il tient dans la hauteur disponible ; dès qu'il déborde (texte
     long, comme Trémel), les marges auto retombent à 0 et il repart du haut,
     scrollable normalement — aucun changement pour les textes déjà longs. --- */
  .tremel-nested .tremel-back-text-inner{ margin:auto 0; width:100%; }
  .tremel-nested .tremel-back-text h3{
    color:var(--gold); font-family:'Playfair Display',serif; font-size:1.4rem; margin-bottom:1rem;
  }
  .tremel-nested .tremel-back-text p{
    color:var(--cream-dim); font-size:.85rem; line-height:1.6; margin-bottom:.9rem;
  }
  .tremel-nested .tremel-back-text p:last-child{ margin-bottom:2.4rem; }
  /* --- Croix pour revenir au carrousel sans attendre le mouseleave (utile
     au tactile, où il n'y a pas de "sortie de survol") : bulle ronde, même
     habillage visuel que .flip-close sur les cartes .coll-flip. --- */
  .tremel-nested .tremel-text-close{
    position:absolute; top:.8rem; right:.8rem; z-index:4;
    width:36px; height:36px; border-radius:50%;
    background:rgba(10,10,10,.6);
    border:1px solid var(--line);
    color:var(--cream);
    font-size:1.3rem; line-height:1;
    display:flex; align-items:center; justify-content:center;
    cursor:pointer;
    transition:.3s ease;
  }
  .tremel-nested .tremel-text-close:hover{ background:var(--gold); color:var(--black); }
  /* --- Indice de défilement (flèche bas) : la scrollbar est masquée sur ces
     panneaux (voir .tremel-back-text ci-dessus), donc sur mobile — où on ne
     voit pas non plus le curseur "grab" qu'on aurait au survol desktop —
     rien n'indique qu'il y a plus de texte en dessous. Collée en bas via
     position:sticky, elle suit le défilement et se range naturellement
     dans le flux une fois arrivé au bout du texte. Une fois le bas du texte
     réellement atteint (voir script.js), elle s'efface : sinon le dégradé
     recouvre en permanence les toutes dernières lignes, même quand il n'y a
     plus rien à faire défiler — illisible alors qu'il s'agit de la fin
     réelle du texte. --- */
  .tremel-nested .tremel-scroll-hint{ display:none; }
  @media(max-width:900px){
    .tremel-nested .tremel-scroll-hint{
      display:flex; justify-content:center; align-items:flex-end;
      position:sticky; bottom:0; flex-shrink:0;
      height:2.8rem; margin-top:-2.8rem; padding-bottom:.35rem;
      background:linear-gradient(180deg, transparent 0%, var(--black) 75%);
      color:var(--gold);
      pointer-events:none;
      opacity:1; transition:opacity .3s ease;
    }
    .tremel-nested .tremel-scroll-hint.is-hidden{ opacity:0; }
  }
  .tremel-nested .tremel-scroll-hint svg{ animation:tremelScrollHintBounce 1.6s ease-in-out infinite; }
  @keyframes tremelScrollHintBounce{
    0%,100%{ transform:translateY(0); }
    50%{ transform:translateY(4px); }
  }

  /* ============ OUTIL D'ÉDITION DIRECTE (edit-toolkit.js) ============ */
  .et-toolbar{
    position:fixed; right:1.3rem; bottom:1.3rem; z-index:99990;
    background:var(--black-soft); border:1px solid var(--line); border-radius:10px;
    box-shadow:0 8px 30px rgba(0,0,0,.55); user-select:none;
  }
  .et-toolbar-dragging{ opacity:.92; box-shadow:0 14px 44px rgba(0,0,0,.7); }
  .et-toolbar-handle{
    cursor:move; padding:.35rem .5rem .35rem .7rem; font-size:.62rem; letter-spacing:.1em; text-transform:uppercase;
    color:var(--cream-dim); border-bottom:1px solid var(--line); text-align:center;
    display:flex; align-items:center; justify-content:center; gap:.4rem;
  }
  .et-toolbar-handle:hover{ color:var(--gold); }
  .et-toolbar-handle-label{ flex:1 1 auto; }
  .et-toolbar-min-btn{
    cursor:pointer; flex:none; width:18px; height:18px; border-radius:4px;
    display:flex; align-items:center; justify-content:center;
    color:var(--cream-dim); border:1px solid transparent;
  }
  .et-toolbar-min-btn:hover{ color:var(--gold); border-color:var(--gold); }
  .et-toolbar-row{ display:flex; align-items:center; gap:.45rem; padding:.55rem .6rem; }
  /* Sur mobile, la rangée (image/texte/annoter/pages/recadrer + séparateur +
     sauvegarde + séparateur + 3 aperçus d'écran) dépasse la largeur de
     l'écran — la barre est en position:fixed sans limite de largeur ni
     retour à la ligne, donc une partie se retrouve hors-écran (à gauche ou
     à droite selon l'endroit où la barre a été déplacée) et reste
     inaccessible. On la limite à la largeur de l'écran et on la laisse
     passer sur deux lignes plutôt que déborder. */
  @media(max-width:560px){
    .et-toolbar{ max-width:calc(100vw - 1.6rem); }
    .et-toolbar-row{ flex-wrap:wrap; max-width:calc(100vw - 1.6rem); }
  }
  .et-toolbar-sep{ width:1px; align-self:stretch; background:var(--line); }
  .et-toolbar.et-toolbar-collapsed .et-toolbar-row{ display:none; }
  .et-toolbar.et-toolbar-collapsed .et-toolbar-handle{ border-bottom:none; }
  .et-toolbar.et-toolbar-collapsed .et-toolbar-min-btn svg{ transform:rotate(180deg); }

  .et-fab{
    width:42px; height:42px; border-radius:50%; border:1px solid var(--line);
    background:var(--black); color:var(--gold-light); display:flex; align-items:center; justify-content:center;
    cursor:pointer; transition:.2s; flex:none;
  }
  .et-fab:hover{ border-color:var(--gold); color:var(--gold); }
  .et-fab-active{ background:var(--gold); color:var(--black); border-color:var(--gold); }
  .et-fab-active:hover{ color:var(--black); }
  .et-fab-small{ width:34px; height:34px; }

  .et-library-panel{
    position:fixed; top:0; left:0; bottom:0; width:min(480px, 92vw); z-index:99988;
    background:var(--black-soft); border-right:1px solid var(--line); box-shadow:8px 0 30px rgba(0,0,0,.5);
    display:flex; flex-direction:column; padding:1rem; overflow:hidden;
    transform:translateX(-100%); transition:transform .25s;
  }
  .et-library-panel.et-visible{ transform:translateX(0); }
  /* Pendant "Tester la photo de fond", les boutons jaunes (Carrousels des
     cartes, Sliders, Avis, Logos, Mise en ligne) sont masqués : ils ne
     servent à rien dans ce mode et gênaient la vue d'ensemble des fichiers,
     demandé explicitement — le bouton de test lui-même et "+ Importer"
     restent visibles. */
  .et-library-panel.et-lib-quicktest-mode .et-lib-slots{ display:none; }
  .et-lib-head{ display:flex; align-items:center; justify-content:space-between; margin-bottom:.7rem; }
  .et-lib-head h3{ font-size:.95rem; color:var(--gold); margin:0; font-weight:600; }
  .et-lib-close{
    background:none; border:1px solid var(--line); color:var(--cream-dim); border-radius:6px;
    width:26px; height:26px; cursor:pointer; font-size:.8rem;
  }
  .et-lib-close:hover{ border-color:var(--gold); color:var(--gold); }
  .et-lib-search{
    width:100%; padding:.5rem .7rem; background:var(--black); border:1px solid var(--line); color:var(--cream);
    border-radius:6px; font-size:.83rem; margin-bottom:.6rem;
  }
  .et-lib-import{
    width:100%; padding:.55rem .7rem; background:transparent; border:1px dashed var(--gold); color:var(--gold);
    border-radius:6px; font-size:.78rem; cursor:pointer; margin-bottom:.6rem;
  }
  .et-lib-import:hover{ background:rgba(210,172,90,.08); }
  /* Bouton "tester la photo de fond du hero" : même style que l'import tant
     qu'inactif ; une fois activé, fond plein pour signaler clairement que
     les clics suivants sur la bibliothèque agissent différemment (pose
     directe sur le hero, pas de glisser nécessaire). */
  .et-lib-quicktest{
    width:100%; padding:.55rem .7rem; background:transparent; border:1px dashed var(--gold); color:var(--gold);
    border-radius:6px; font-size:.78rem; cursor:pointer; margin-bottom:.6rem;
  }
  .et-lib-quicktest:hover{ background:rgba(210,172,90,.08); }
  .et-lib-quicktest-active{
    background:var(--gold); color:var(--black); border-style:solid; font-weight:700;
  }
  .et-lib-quicktest-active:hover{ background:var(--gold-light); }
  .et-lib-slots{
    width:100%; padding:.55rem .7rem; background:var(--gold); color:var(--black); border:none;
    border-radius:6px; font-size:.78rem; font-weight:700; cursor:pointer; margin-bottom:.6rem;
  }
  .et-lib-slots:hover{ background:var(--gold-light); }
  .et-lib-hint{ font-size:.68rem; color:var(--cream-dim); margin-bottom:.7rem; line-height:1.5; }
  .et-lib-list{ flex:1; overflow-y:auto; }
  .et-lib-list details{ margin-bottom:.3rem; }
  .et-lib-list summary{
    cursor:pointer; font-size:.78rem; text-transform:uppercase; letter-spacing:.05em; color:var(--cream);
    padding:.5rem .4rem; margin:0 -0.4rem;
    background:rgba(210,172,90,.08); border:1px solid var(--line); border-radius:3px;
    display:flex; align-items:center; gap:.4rem;
  }
  .et-lib-list summary::marker{ color:var(--gold); }
  .et-lib-list summary::before{ content:'Cliquer pour afficher'; margin-left:auto; font-size:.62rem; letter-spacing:.03em; text-transform:none; color:var(--cream-dim); opacity:.7; }
  .et-lib-list details[open] summary::before{ content:''; }
  .et-lib-list summary:hover{ color:var(--gold); border-color:var(--gold); background:rgba(210,172,90,.16); }
  .et-lib-grid{ display:grid; grid-template-columns:repeat(auto-fill, minmax(90px,1fr)); gap:8px; padding:.2rem 0 .5rem; }
  .et-lib-thumb{
    aspect-ratio:1/1; border-radius:4px; overflow:hidden; border:1px solid var(--line); cursor:grab; background:#000;
  }
  .et-lib-thumb img{ width:100%; height:100%; object-fit:cover; display:block; pointer-events:none; }
  .et-lib-thumb:hover{ border-color:var(--gold); }
  .et-lib-thumb.et-dragging{ opacity:.4; }

  .et-drop-over{ outline:3px solid var(--gold) !important; outline-offset:-3px; }
  body.et-img-mode img, body.et-img-mode [style*="background-image"]{ cursor:copy; }

  /* Outil "Recadrer les photos (gauche/droite)" : glisser un .parallax-spacer
     (la zone cliquable en flux normal, le bandeau lui-même est en
     position:fixed derrière tout, donc jamais la cible directe des clics —
     voir edit-toolkit.js) déplace horizontalement la photo de fond associée
     via la variable --bp-x, consommée uniquement dans les media queries
     mobiles de styles.css : aucun effet sur le cadrage desktop/tablette. */
  body.et-repo-mode .parallax-spacer, body.et-repo-mode .hero{ cursor:ew-resize; }
  /* Pendant le recadrage, .hero-bg (une vraie balise <img>) et .hero-content
     (qui contient du texte sélectionnable) ne doivent jamais être la cible
     directe du clic : un <img> ou du texte sous le curseur perturbe le
     glisser (aperçu de drag natif de l'image, sélection de texte) — on
     force donc les clics à atteindre directement .hero pendant ce mode. */
  body.et-repo-mode .hero-bg, body.et-repo-mode .hero-content{ pointer-events:none; }
  /* Même principe pour les couvertures de flip-card : leurs enfants (num,
     h3, description) ne doivent jamais intercepter le clic de départ du
     glisser. */
  body.et-repo-mode .flip-front{ cursor:ew-resize; }
  /* :not(img) — certaines couvertures (cartes "Formats king size" : Pleyben,
     Plouescat cinéma...) utilisent une vraie balise <img> à l'intérieur de
     .flip-front plutôt qu'un fond CSS (voir .flip-front > img ci-dessus) :
     cette image doit rester la cible directe du glisser, seuls les autres
     enfants (num, h3, description, "Découvrir") passent en pointer-events:
     none. */
  body.et-repo-mode .flip-front *:not(img){ pointer-events:none; }
  body.et-repo-mode .flip-front > img{ cursor:ew-resize; }
  body.et-repo-mode .carousel-hero img, body.et-repo-mode .sq-preview img{ cursor:ew-resize; }
  /* .page-coll .flip-back .carousel-hero img (cartes Trémel/tremel-nested,
     3 classes) a une spécificité CSS supérieure à la règle générique
     ci-dessus (2 classes + 2 éléments < 3 classes + 1 élément dans l'ordre
     de comparaison ids/classes/éléments) : le curseur loupe (--zoom-cursor)
     restait donc affiché en mode recadrage au lieu de la double flèche,
     bien que le glisser fonctionne quand même (juste le curseur, visuel,
     qui ne suivait pas). Règle dédiée, à spécificité égale en classes mais
     un élément de plus, pour gagner le départage. */
  body.et-repo-mode .flip-back .carousel-hero img{ cursor:ew-resize; }
  body.et-repo-mode .parallax-spacer{ outline:1px dashed rgba(210,172,90,.4); outline-offset:-1px; }
  .parallax-spacer.et-repo-dragging, .hero.et-repo-dragging{ cursor:grabbing; }
  .et-repo-label{
    position:fixed; top:50%; left:50%; transform:translate(-50%,-50%);
    z-index:100000; pointer-events:none;
    background:var(--gold); color:var(--black);
    font-family:'DM Sans',sans-serif; font-weight:700; font-size:.85rem;
    padding:.35rem .7rem; border-radius:999px;
    opacity:0; transition:opacity .15s;
  }
  .et-repo-label.et-visible{ opacity:1; }

  .et-pages-panel{
    position:fixed; top:0; right:0; bottom:0; width:300px; z-index:99988;
    background:var(--black-soft); border-left:1px solid var(--line); box-shadow:-8px 0 30px rgba(0,0,0,.5);
    display:flex; flex-direction:column; padding:1rem; overflow:hidden;
    transform:translateX(100%); transition:transform .25s;
  }
  .et-pages-panel.et-visible{ transform:translateX(0); }
  .et-pages-list{ display:flex; flex-direction:column; gap:.4rem; margin-bottom:1rem; overflow-y:auto; }
  .et-page-item{
    text-align:left; padding:.6rem .8rem; background:var(--black); border:1px solid var(--line); color:var(--cream);
    border-radius:6px; font-size:.85rem; cursor:pointer;
  }
  .et-page-item:hover{ border-color:var(--gold); color:var(--gold); }
  .et-page-current{ border-color:var(--gold); color:var(--gold); background:rgba(210,172,90,.08); cursor:default; }
  .et-pages-dup{
    width:100%; padding:.6rem .7rem; background:var(--gold); color:var(--black); border:none;
    border-radius:6px; font-size:.8rem; font-weight:700; cursor:pointer; margin-bottom:1rem;
  }
  .et-pages-dup:hover{ background:var(--gold-light); }
  .et-pages-url-row{ display:flex; gap:.4rem; }
  .et-pages-url{
    flex:1; min-width:0; padding:.5rem .6rem; background:var(--black); border:1px solid var(--line); color:var(--cream);
    border-radius:6px; font-size:.78rem;
  }
  .et-pages-go{
    background:transparent; border:1px solid var(--gold); color:var(--gold); border-radius:6px;
    padding:.5rem .8rem; font-size:.78rem; cursor:pointer;
  }
  .et-pages-go:hover{ background:rgba(210,172,90,.1); }

  .et-editable{
    outline:1.5px dashed rgba(210,172,90,.55); outline-offset:3px; border-radius:2px; cursor:text;
  }
  .et-editable:hover{ outline-color:var(--gold); background:rgba(210,172,90,.06); }
  .et-editable:focus{ outline:1.5px solid var(--gold); background:rgba(210,172,90,.1); }

  .et-savebar{
    position:fixed; left:50%; bottom:1.3rem; transform:translateX(-50%) translateY(140%);
    z-index:99990; opacity:0; transition:transform .25s, opacity .25s; pointer-events:none;
  }
  .et-savebar.et-visible{ transform:translateX(-50%) translateY(0); opacity:1; pointer-events:auto; }
  .et-savebar-btn{
    background:var(--gold); color:var(--black); border:none; padding:.75rem 1.6rem; border-radius:30px;
    font-weight:700; font-size:.85rem; letter-spacing:.03em; cursor:pointer; box-shadow:0 6px 20px rgba(0,0,0,.5);
  }
  .et-savebar-btn:hover{ background:var(--gold-light); }
  .et-savebar-btn:disabled{ opacity:.6; cursor:default; }

  .et-textmode-banner{
    position:fixed; top:0; left:0; right:0; z-index:99991;
    display:none; align-items:center; justify-content:center;
    padding:.7rem 1rem; text-align:center;
    background:var(--gold); color:var(--black);
    font-size:.82rem; font-weight:700; letter-spacing:.02em;
    border:none; cursor:pointer;
    box-shadow:0 4px 16px rgba(0,0,0,.4);
  }
  .et-textmode-banner.et-visible{ display:flex; }
  .et-textmode-banner:hover{ background:var(--gold-light); }

  .et-toast{
    position:fixed; left:50%; bottom:5.2rem; transform:translateX(-50%) translateY(10px); z-index:99995;
    background:var(--black-soft); color:var(--cream); border:1px solid var(--gold); padding:.6rem 1.1rem; border-radius:6px;
    font-size:.82rem; opacity:0; transition:.25s; pointer-events:none;
  }
  .et-toast-show{ opacity:1; transform:translateX(-50%) translateY(0); }
  .et-toast-error{ border-color:#c96a5a; color:#f0b8ac; }

  .et-annotate-layer{
    position:absolute; top:0; left:0; z-index:99985; pointer-events:none;
  }
  .et-annotate-layer.et-annotate-active{ pointer-events:auto; cursor:crosshair; }
  .et-annotate-stroke{
    fill:none; stroke:#ff4d4f; stroke-width:4; stroke-linecap:round; stroke-linejoin:round; opacity:.85;
  }
  .et-clear-annotate{
    position:fixed; left:1.3rem; top:1.3rem; z-index:99990; display:none;
    background:var(--black-soft); color:var(--cream-dim); border:1px solid var(--line); border-radius:20px;
    padding:.5rem 1rem; font-size:.75rem; cursor:pointer; box-shadow:0 4px 16px rgba(0,0,0,.5);
  }

  .et-clear-annotate:hover{ border-color:var(--gold); color:var(--gold); }
  .et-clear-annotate.et-visible{ display:block; }

  .et-preview-overlay{
    position:fixed; inset:0; z-index:99999; background:rgba(6,6,6,.9);
    display:flex; flex-direction:column; align-items:center; justify-content:flex-start;
    padding:2vh 2vw; overflow:auto;
  }
  .et-preview-bar{
    width:100%; max-width:1360px; display:flex; align-items:center; justify-content:space-between;
    color:var(--cream-dim); font-size:.85rem; padding:.4rem .2rem 1rem;
  }
  .et-preview-close{
    background:transparent; border:1px solid var(--line); color:var(--cream); border-radius:6px;
    padding:.4rem .9rem; cursor:pointer; font-size:.8rem;
  }
  .et-preview-close:hover{ border-color:var(--gold); color:var(--gold); }
  .et-preview-frame-wrap{ display:flex; justify-content:center; }
  .et-preview-frame{
    border:8px solid #1c1a16; border-radius:14px; background:#fff; box-shadow:0 20px 60px rgba(0,0,0,.6);
  }

  .et-slots-overlay{ padding:1.4vh 1.4vw; }
  .et-slots-frame-wrap{ width:100%; height:100%; flex:1; display:flex; }
  .et-slots-frame{
    flex:1; width:100%; height:100%; border:1px solid var(--line); border-radius:10px;
    background:var(--black); box-shadow:0 20px 60px rgba(0,0,0,.6);
  }

  /* ============ CARTE BRETAGNE — PAGES VILLES (ex. Trémel) ============ */
  .chantier-hero .dept-map{ width:8.3rem; }
  .chantier-hero .dept-map svg{ width:100%; height:auto; display:block; overflow:visible; }
  @media(max-width:420px){
    .chantier-hero .dept-map{ width:clamp(70px, 30vw, 100px); }
  }
  .chantier-hero .dept-map .bzh-dept{
    fill:rgba(210,172,90,.12);
    stroke:var(--gold);
    stroke-width:1.4;
    stroke-linejoin:round;
  }
  .chantier-hero .dept-map .bzh-dept.is-active{ fill:var(--gold); }
  .chantier-hero .dept-pin .pin-ring{ fill:none; stroke:var(--cream); stroke-width:2.2; }
  .chantier-hero .dept-pin .pin-dot{ fill:var(--cream); }
  .chantier-hero .dept-pin .pin-pulse{
    fill:none;
    stroke:var(--cream);
    stroke-width:2;
    transform-box:fill-box;
    transform-origin:center;
    animation:deptPulse 2.4s ease-out infinite;
  }

  /* ============ PAGE "ANATOMIE D'UN CHANTIER" ============ */
  .chantier-hero .section-head{ margin-bottom:1rem; }
  .chantier-step{
    display:grid; grid-template-columns:1fr 1fr; gap:3.5rem; align-items:center;
    max-width:1200px; margin:0 auto; padding-top:4rem; padding-bottom:4rem;
  }
  .chantier-step-rev .chantier-step-media{ order:2; }
  .chantier-step-rev .chantier-step-text{ order:1; }
  /* Quand le carrousel (photo + vignettes) partage la ligne avec du texte
     (restaurant Breizh Odyssée), le texte doit s'aligner sur la photo
     seule, pas sur la colonne entière carrousel+vignettes, demandé
     explicitement. */
  .chantier-step-align-top{ align-items:start; }
  .chantier-step-media{
    aspect-ratio:4/3; border-radius:0; overflow:hidden; border:2px solid var(--gold);
  }
  .chantier-step-media img{ width:100%; height:100%; object-fit:cover; display:block; }
  /* .chantier-step-media-contain (photo de façade Warenghem) : photo entière
     visible sans rogner les côtés, demandé explicitement — au lieu du cover
     par défaut qui recadre pour remplir le cadre 4/3. */
  .chantier-step-media-contain{ aspect-ratio:auto; }
  .chantier-step-media-contain img{ height:auto; object-fit:contain; }
  /* .chantier-step-media-flip (cartes "Particuliers", flip-card conservée
     dans la mise en page photo+texte) : la carte gère déjà sa propre
     taille (500px) et sa propre bordure dorée (.flip-face) — on retire
     l'aspect-ratio/bordure/overflow par défaut de .chantier-step-media
     pour ne pas les dupliquer ou les faire entrer en conflit. Format de
     la photo de couverture volontairement laissé d'origine (cover),
     pas en plein format/contain. */
  .chantier-step-media-flip{ aspect-ratio:auto; overflow:visible; border:none; }
  /* .cs-photo-flip (photo "homard" Banque Populaire) : la photo se
     retourne pour révéler une seconde photo au dos, demandé explicitement
     — même mécanique 3D que .flip-card/.flip-inner (voir plus haut) mais
     portée séparément pour rester indépendante de ce composant plus lourd
     (modes toolkit et.text/repo, carrousel...) et pouvoir s'insérer dans
     n'importe quel .chantier-step-media. Cadre ajusté au format réel des
     photos (ratio de la photo de face, 2400x1349) plutôt que le 4/3 par
     défaut, et object-fit:cover sur les deux faces pour qu'elles remplissent
     exactement le même cadre sans bande vide, demandé explicitement. */
  .chantier-step-media.cs-photo-flip{ border:none; aspect-ratio:2400/1349; border-radius:0; overflow:visible; }
  /* .carantec-photo-flip (page hôtellerie, sterne de Dougall / plage
     Carantec) : cadre ajusté au ratio réel de ces deux photos (2400x1580),
     différent de celui de Banque Populaire ci-dessus, pour éviter un
     recadrage visible. */
  .chantier-step-media.cs-photo-flip.carantec-photo-flip{ aspect-ratio:2400/1580; }
  .cs-photo-flip{ perspective:1600px; position:relative; }
  .cs-photo-flip-inner{
    position:relative; width:100%; height:100%;
    transition:transform .8s cubic-bezier(.4,.2,.2,1);
    transform-style:preserve-3d;
  }
  /* Le survol CSS pur ne doit jouer que sur les appareils à souris : sur
     tactile, un tap peut laisser l'état :hover "collé" indéfiniment (bug
     connu de nombreux navigateurs mobiles), ce qui gardait visuellement la
     carte retournée même après que le script JS (voir script.js) ait retiré
     la classe .is-flipped au tap suivant — la carte semblait alors bloquée
     après un seul retournement, corrigé en scopant :hover à (hover:hover). */
  @media(hover:hover){
    .cs-photo-flip:hover .cs-photo-flip-inner{ transform:rotateY(180deg); }
  }
  .cs-photo-flip.is-flipped .cs-photo-flip-inner{ transform:rotateY(180deg); }
  .cs-photo-flip-face{
    position:absolute; inset:0; backface-visibility:hidden;
    background:var(--black-soft); display:flex; align-items:center; justify-content:center;
    border:2px solid var(--gold);
  }
  .chantier-step-media.cs-photo-flip .cs-photo-flip-face img{ width:100%; height:100%; object-fit:cover; }
  .cs-photo-flip-back{ transform:rotateY(180deg); }
  /* Indice visuel "photo retournable" sur écran tactile uniquement (pas de
     survol possible pour deviner l'interaction) : simple flèche blanche
     discrète en haut à droite, sans fond ni cadre, demandé explicitement.
     Élément réel (.cs-flip-hint), PAS un ::after sur .cs-photo-flip-front :
     ce dernier est à l'intérieur de .cs-photo-flip-inner (preserve-3d) et a
     lui-même backface-visibility:hidden — combinaison connue pour faire
     disparaître les pseudo-éléments sur Safari iOS. Positionné ici en
     enfant direct de .cs-photo-flip (hors du contexte 3D), il échappe à ce
     bug. hover:none exclut les écrans avec souris, où le survol suffit à
     comprendre l'interaction. Masqué une fois la carte retournée. */
  .cs-flip-hint{
    content:'';
    position:absolute; top:12px; right:12px; z-index:4;
    width:22px; height:22px;
    background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 12a9 9 0 1 1-3-6.7'/%3E%3Cpath d='M21 3v6h-6'/%3E%3C/svg%3E");
    background-repeat:no-repeat;
    background-position:center;
    background-size:22px 22px;
    filter:drop-shadow(0 1px 3px rgba(0,0,0,.7));
    display:none;
    pointer-events:none;
  }
  @media(hover:none){
    .cs-flip-hint{ display:block; }
  }
  .cs-photo-flip.is-flipped .cs-flip-hint{ display:none; }
  /* .chantier-step-media-fade ("La façade" Warenghem) : diaporama en fondu
     enchaîné entre plusieurs photos empilées dans le même cadre, demandé
     explicitement à la place d'une seule photo fixe. Contrairement à
     .chantier-step-media-contain, un ratio fixe (4/3, comme la valeur par
     défaut du site) est nécessaire ici : avec 4 photos de ratios différents
     qui se succèdent, le cadre ne peut pas suivre la taille naturelle de
     "l'image du moment" sans sauter à chaque fondu. object-fit:contain sur
     chaque calque évite toujours le recadrage (juste des bandes vides sur
     les côtés/haut-bas selon la photo, jamais de recadrage). */
  .chantier-step-media-fade{ aspect-ratio:auto; overflow:visible; border:none; }
  .cs-fade-stage{
    position:relative; aspect-ratio:2400/1349; background:var(--black-soft);
    border-radius:0; overflow:hidden; border:2px solid var(--gold);
  }
  .cs-fade-layer{
    position:absolute; inset:0; width:100%; height:100%; object-fit:contain;
    opacity:0; transition:opacity 1.8s ease; pointer-events:none;
  }
  .cs-fade-layer.is-active{ opacity:1; pointer-events:auto; }
  /* .cs-fade-nav : miniatures rondes cliquables sous la photo, pour sauter
     directement à une photo — portée en CSS/JS natif, sans framework, pour
     rester cohérente avec le reste du site (voir mémoire "no frameworks"). */
  .cs-fade-nav{
    display:flex; flex-wrap:wrap; justify-content:center; gap:.6rem; padding:.9rem .8rem;
  }
  /* Apparition en cascade gauche→droite au scroll (rejoue à chaque entrée
     dans l'écran, comme les pictos .surface-item et la carte de Bretagne —
     voir script.js), demandé explicitement. Le fondu clair/actif
     (.65 → 1 selon l'état de la photo) est porté par l'image à l'intérieur
     plutôt que par le bouton lui-même, pour laisser l'opacité du bouton
     entièrement dédiée à cette apparition au scroll, sans les mélanger. */
  .cs-fade-thumb{
    width:42px; height:42px; padding:0; border-radius:50%;
    border:none; cursor:pointer; background:none;
    flex:none; position:relative;
    opacity:0; transform:translateY(14px) scale(.8);
    transition:opacity .45s ease, transform .45s ease;
    transition-delay:var(--reveal-delay, 0s);
  }
  .cs-fade-nav.is-in .cs-fade-thumb{ opacity:1; transform:translateY(0) scale(1); }
  .cs-fade-thumb img{
    width:100%; height:100%; object-fit:cover; display:block; border-radius:50%;
    opacity:.65; transition:opacity .25s ease;
  }
  .cs-fade-thumb.is-active img{ opacity:1; }
  /* Le liseret du contour n'existe pas au repos (--ring-a:0deg, donc
     invisible via le mask conic-gradient) : il se dessine seulement au
     passage de la souris (comme .btn-ring sur la touche "Appeler" du
     header), demandé explicitement. La photo actuellement affichée garde
     son liseret doré fixe (indicateur d'état), les autres ne le montrent
     qu'au survol. Même technique que .surface-item::after. */
  .cs-fade-thumb::after{
    content:''; position:absolute; inset:-2px; border-radius:50%;
    border:2px solid var(--gold); pointer-events:none;
    --ring-a:0deg;
    transition:--ring-a .6s ease;
    -webkit-mask-image:conic-gradient(from 180deg, #000 var(--ring-a,0deg), transparent 0);
    mask-image:conic-gradient(from 180deg, #000 var(--ring-a,0deg), transparent 0);
  }
  .cs-fade-thumb:hover::after{ --ring-a:360deg; }
  .cs-fade-thumb.is-active::after{ --ring-a:360deg; }
  .chantier-step-num{
    display:block; font-family:'Playfair Display',serif; font-weight:700;
    font-size:1.1rem; color:var(--gold); letter-spacing:.08em; margin-bottom:.6rem;
  }
  .chantier-step-text h2{ font-size:1.5rem; color:var(--cream); margin-bottom:.9rem; }
  .chantier-step-text p{ color:var(--cream-dim); line-height:1.75; }
  @media(max-width:800px){
    .chantier-step{ grid-template-columns:1fr; gap:1.6rem; padding-top:2.6rem; padding-bottom:2.6rem; }
    .chantier-step-rev .chantier-step-media, .chantier-step-rev .chantier-step-text{ order:initial; }
  }
  /* .chantier-step-centered (Warenghem) : logo, titre et texte centrés au
     milieu de la page, sans colonne photo à côté — la photo du site reste
     visible juste au-dessus en fond fixe (.parallax-band), demandé
     explicitement. */
  .chantier-step-centered{
    grid-template-columns:1fr; justify-items:center; text-align:center;
  }
  .chantier-step-centered .chantier-step-text{ max-width:640px; }
  .chantier-step-centered .client-logo{ margin:0 auto 1.2rem; }
  /* .chantier-step-solo : même colonne unique que .chantier-step-centered,
     mais alignée à gauche comme le reste des blocs de la page (demandé
     explicitement pour les blocs "Espace bar & restaurant" / "Espace pub"
     de la page bars & restaurants, sans partenaire photo/texte en vis-à-vis). */
  .chantier-step-solo{ grid-template-columns:1fr; }
  .chantier-step-solo .chantier-step-text{ max-width:640px; }

  /* ============ PAGES "ENTREPRISES" — logo client au-dessus du texte ============ */
  .client-logo{ display:block; max-width:180px; max-height:64px; width:auto; height:auto; object-fit:contain; object-position:left center; margin-bottom:1.2rem; }
  /* Logo Awen agrandi de 20% par rapport à la taille standard des logos
     clients, demandé explicitement. */
  .client-logo-awen, .cinema-logo{ max-width:288px; max-height:103px; }
  .warenghem-logo, .banque-pop-logo{ max-width:240px; max-height:85px; }
  /* Logo A Fleur de Pot : fourni en noir sur fond transparent (pensé pour
     un fond clair), invisible sur le fond sombre du site — inversé en CSS
     pour repasser en blanc, demandé explicitement, sans retoucher le
     fichier d'origine. */
  .fleur-de-pot-logo{ filter:invert(1); max-width:360px; max-height:128px; }
  /* Logos A Fleur de Pot et L'Huîtrier doublés par rapport à la taille
     standard, demandé explicitement. */
  .huitrier-logo{ max-width:360px; max-height:128px; }
  /* Logo Breizh Odyssée doublé par rapport à la taille standard, demandé
     explicitement. */
  .breizh-odyssee-logo{ max-width:480px; max-height:171px; }
  /* Logo Histoire de Rondes agrandi 2,5x par rapport à la taille standard,
     demandé explicitement. */
  .histoire-rondes-logo{ max-width:450px; max-height:160px; }
  /* Logo Tom Café doublé par rapport à la taille standard, demandé
     explicitement. */
  .tom-cafe-logo{ max-width:360px; max-height:128px; }
  /* Logo Atelier 29 doublé par rapport à la taille standard, demandé
     explicitement. */
  .atelier29-logo{ max-width:360px; max-height:128px; }
  .glaz-sea-logo{ max-width:360px; max-height:128px; }
  .client-benefits{ margin-top:1.3rem; }
  .client-benefits .ma-item + .ma-item{ margin-top:1.1rem; }

  /* ============ VOUS AIMEREZ AUSSI (bas de page, entreprises/commerces) ============ */
  /* Espace entre le titre et les photos doublé par rapport au standard
     (3.5rem → 7rem), desktop et mobile, demandé explicitement. */
  .voir-aussi-section .section-head{ margin-bottom:7rem; }
  .voir-aussi-grid{
    display:flex; flex-wrap:nowrap; justify-content:center; align-items:flex-start;
    gap:clamp(1.2rem,3vw,3.5rem); max-width:1800px; margin:0 auto; padding:0 1.5rem;
  }
  .voir-aussi-item{
    display:flex; flex-direction:column; align-items:center; gap:1.2rem;
    text-decoration:none; flex:0 0 208px; max-width:208px; min-width:0;
    opacity:0; transform:translateY(14px) scale(.8);
    transition:opacity .45s ease, transform .45s ease;
    transition-delay:var(--reveal-delay, 0s);
  }
  .voir-aussi-item.is-in{ opacity:1; transform:translateY(0) scale(1); }
  .voir-aussi-circle{
    display:block; width:100%; aspect-ratio:1; border-radius:50%; overflow:hidden;
    border:2px solid var(--gold);
    transition:transform .4s cubic-bezier(.4,.2,.2,1), border-color .4s ease;
  }
  .voir-aussi-circle img{
    width:100%; height:100%; object-fit:cover; display:block;
    transition:transform .6s cubic-bezier(.4,.2,.2,1);
  }
  .voir-aussi-item:hover .voir-aussi-circle{ transform:translateY(-6px); border-color:var(--gold-light); }
  .voir-aussi-item:hover .voir-aussi-circle img{ transform:scale(1.08); }
  /* Libellé sous le rond, même style que celui des ronds-photo clients de la
     page d'accueil (.univers-client-circle span), pas du texte courbé sur le
     cercle — demandé explicitement. */
  .voir-aussi-label{
    font-family:'DM Sans',sans-serif; font-size:.75rem; letter-spacing:.28em;
    text-transform:uppercase; color:var(--gold); font-weight:600; text-align:center;
  }
  /* Même taille/breakpoint que les ronds-photo clients de la page d'accueil
     (.univers-picto-photo, 208px bureau / 23vw mobile) et toujours sur une
     seule ligne sur mobile (pas de retour à la ligne), demandé explicitement.
     gap élargi à 8vw et padding retiré (même correctif que
     #univers-jardin/#univers-maison, voir plus haut) : le padding:0 1rem
     de la rangée s'ajoutait à celui du conteneur de section, laissant les
     ronds serrés entre eux avec de la marge inutilisée de chaque côté. */
  @media(max-width:640px){
    /* justify-content:space-between + marge négative de 6px : les deux ronds
       extérieurs se poussent vers les bords de l'écran (taille des ronds
       inchangée, 23vw) et l'espace libre est réparti entre les trois. */
    .voir-aussi-grid{ flex-wrap:nowrap; gap:8vw; padding:0; justify-content:space-between; margin-left:-6px; margin-right:-6px; }
    .voir-aussi-item{ flex:0 0 auto; width:23vw; max-width:23vw; gap:.6rem; }
    .voir-aussi-label{ font-size:.62rem; letter-spacing:.08em; }
  }

  /* Bouton "Lire les témoignages complets" sous le carrousel d'avis */
  .avis-more{ display:flex; justify-content:center; margin-top:2.4rem; padding:0 1rem; }
  .avis-more .btn{ text-align:center; }

  /* Bloc d'appel à l'action des pages de communes (ex. Carnac) : titre,
     zone d'intervention, trois publics en liste, puis le bouton. */
  .cta-zone{ max-width:640px; margin:0 auto; }
  .cta-zone h2{ margin:0; }
  .cta-zone-intro{ color:var(--cream-dim); margin:1rem 0 1.6rem; }
  .cta-services{
    list-style:none; margin:0 0 2rem; padding:0;
    text-align:left;
    border-top:1px solid var(--line);
  }
  .cta-services li{
    display:flex; flex-direction:column; gap:.2rem;
    padding:1rem .2rem;
    border-bottom:1px solid var(--line);
  }
  .cta-services strong{
    color:var(--gold);
    font-family:'DM Sans',sans-serif;
    font-size:.78rem; font-weight:700;
    letter-spacing:.14em; text-transform:uppercase;
  }
  .cta-services span{ color:var(--cream); font-size:.98rem; line-height:1.5; }

  /* Maillage interne "À proximité" vers la commune voisine (pages de communes) */
  .cta-proche{
    max-width:640px; margin:0 auto 2.4rem;
    color:var(--cream-dim); font-size:.95rem; line-height:1.6;
  }
  .cta-proche a{
    color:var(--gold);
    text-decoration:underline; text-underline-offset:3px;
    text-decoration-color:rgba(210,172,90,.45);
    transition:text-decoration-color .2s ease;
  }
  .cta-proche a:hover{ text-decoration-color:var(--gold); }

  /* Avis client d'une page de chantier : carte à part, distincte du texte
     éditorial (fond, filet doré, étoiles, signature). */
  .chantier-avis-section{ display:flex; justify-content:center; }
  .chantier-avis{
    max-width:760px; width:100%; margin:0;
    padding:2rem 2.2rem 1.8rem;
    background:var(--black-soft);
    border:1px solid var(--line);
    border-top:2px solid var(--gold);
    border-radius:8px;
    display:flex; flex-direction:column; gap:1rem;
  }
  .chantier-avis-label{
    color:var(--gold);
    font-family:'DM Sans',sans-serif; font-size:.72rem; font-weight:700;
    letter-spacing:.16em; text-transform:uppercase;
  }
  .chantier-avis-stars{ color:var(--gold); letter-spacing:.2em; font-size:1rem; }
  .chantier-avis blockquote{ margin:0; }
  .chantier-avis blockquote p{
    margin:0 0 .9rem;
    font-family:'Playfair Display',serif; font-style:italic;
    color:var(--cream); font-size:1.05rem; line-height:1.75;
  }
  .chantier-avis blockquote p:last-child{ margin-bottom:0; }
  .chantier-avis figcaption{
    display:flex; flex-wrap:wrap; align-items:baseline; gap:.2rem .8rem;
    padding-top:1rem; border-top:1px solid var(--line);
  }
  .chantier-avis figcaption strong{
    font-family:'Playfair Display',serif; color:var(--gold); font-size:1rem;
  }
  .chantier-avis figcaption span{ color:var(--cream-dim); font-size:.88rem; }
  .chantier-avis figcaption em{ color:var(--cream-dim); font-size:.78rem; font-style:normal; letter-spacing:.06em; margin-left:auto; }
  @media(max-width:560px){ .chantier-avis{ padding:1.5rem 1.2rem 1.4rem; } }

  /* ============ BLOG — liste d'articles + mise en page d'article ============ */
  .chantier-step-text h3{
    font-family:'Playfair Display',serif; font-size:1.1rem; font-weight:700;
    color:var(--gold); margin:1.3rem 0 .4rem;
  }
  .chantier-step-text p a{
    color:var(--gold); text-decoration:underline; text-underline-offset:3px;
  }
  .blog-quote-section{ padding-top:3.4rem; padding-bottom:3.4rem; }
  .blog-quote{ max-width:760px; margin:0 auto; text-align:center; }
  .blog-quote blockquote{ margin:0; }
  .blog-quote p{
    font-family:'Playfair Display',serif; font-style:italic; font-weight:500;
    font-size:clamp(1.3rem,3.2vw,1.9rem); line-height:1.45; color:var(--cream); margin:0;
  }
  .blog-quote p::before{ content:"«\00a0"; color:var(--gold); }
  .blog-quote p::after{ content:"\00a0»"; color:var(--gold); }
  .blog-compare{
    max-width:760px; margin:2.4rem auto 0; padding:1.8rem 1.6rem;
    border:1px solid var(--line); text-align:center;
  }
  .blog-compare-title{
    display:block; margin-bottom:1.4rem;
    font-family:'DM Sans',sans-serif; font-size:.8rem; font-weight:700;
    letter-spacing:.16em; text-transform:uppercase; color:var(--gold);
  }
  .blog-compare-cols{ display:grid; grid-template-columns:1fr 1fr; gap:1.6rem; text-align:left; }
  .blog-compare-col{ border-top:1px solid var(--line); padding-top:1rem; }
  .blog-compare-col strong{
    display:block; margin-bottom:.6rem;
    font-family:'Playfair Display',serif; font-size:1.15rem; color:var(--cream);
  }
  .blog-compare-col ul{ list-style:none; margin:0; padding:0; }
  .blog-compare-col li{
    position:relative; padding:.35rem 0 .35rem 1.1rem;
    color:var(--cream-dim); line-height:1.5;
  }
  .blog-compare-col li::before{ content:"•"; position:absolute; left:0; color:var(--gold); }
  @media(max-width:560px){ .blog-compare-cols{ grid-template-columns:1fr; } }

  .blog-grid{
    display:grid; grid-template-columns:repeat(auto-fill,minmax(min(100%,320px),1fr));
    gap:2rem; max-width:1200px; margin:0 auto;
  }
  .blog-card{
    position:relative; display:flex; flex-direction:column;
    border:1px solid var(--line); background:rgba(255,255,255,.02);
    transition:border-color .25s;
  }
  .blog-card:hover{ border-color:var(--gold); }
  .blog-card-media{ aspect-ratio:4/3; overflow:hidden; }
  .blog-card-media img{ width:100%; height:100%; object-fit:cover; display:block; transition:transform .5s; }
  .blog-card:hover .blog-card-media img{ transform:scale(1.04); }
  .blog-card-body{ display:flex; flex-direction:column; flex:1; padding:1.4rem 1.4rem 1.6rem; }
  .blog-card-tag{
    font-family:'DM Sans',sans-serif; font-size:.74rem; font-weight:700;
    letter-spacing:.14em; text-transform:uppercase; color:var(--gold); margin-bottom:.6rem;
  }
  .blog-card h2{ margin:0 0 .7rem; }
  .blog-card h2 a{ color:var(--cream); text-decoration:none; }
  .blog-card h2 a::after{ content:""; position:absolute; inset:0; }
  .blog-card p{ color:var(--cream-dim); line-height:1.65; margin:0 0 1.2rem; }
  .blog-card-more{
    margin-top:auto; color:var(--gold);
    font-family:'DM Sans',sans-serif; font-size:.8rem; font-weight:700;
    letter-spacing:.12em; text-transform:uppercase;
  }
  .page-blog .chantier-step-text p + p{ margin-top:.9rem; }
  /* Titre (h1) des pages de villes, du blog (liste + article) et de la page fresques citoyennes :
     même taille que les titres de section (1.5rem), demandé explicitement (le h1
     responsive par défaut était trop grand). */
  body.page-ville .section-head h1{ font-size:1.5rem; }
  /* Pied de page "Blog" : liste repliable comme "Mes réalisations par ville", mais
     défilante pour rester gérable quand le nombre d'articles augmente. */
  .footer-col-list.footer-blog-list.is-open{ max-height:18em; overflow-y:auto; }
  /* #anatomieFooterBand (Marianne citoyenne de Trémel, 2400x1601, juste avant le
     pied de page de "Anatomie d'un chantier") : zoom réduit de 40% sur mobile par
     rapport au cover d'origine (~325% → 195%), centré sur le visage de la Marianne. */
  @media(max-width:560px){
    #anatomieFooterBand{ background-size:195% auto; background-position:var(--bp-x,72%) center; }
  }
  /* Le pied de page est opaque comme les .section : un bandeau photo fixe placé
     juste avant le pied de page ne transparaît plus derrière son texte. */
  footer{ background:var(--black); }
  /* Carte de blog : couverture avant/après figée (image coupée en deux avec la poignée),
     purement décorative — c'est toute la carte qui mène à la page où le curseur est actif.
     Pas de zoom au survol (il décalerait les deux images). */
  .blog-card-media.ba-static .ba-divider{ left:50%; margin-left:-1px; }
  .blog-card-media.ba-static .ba-handle{ pointer-events:none; cursor:inherit; }
  .blog-card-media.ba-static img,
  .blog-card:hover .blog-card-media.ba-static img{ transform:none; transition:none; }
  /* Revue de presse : mots d'ancre cliquables dans le texte des articles (voir
     linkifyArticle dans script.js) — or souligné, comme les liens des articles du blog. */
  .lightbox-article p a{
    color:var(--gold); text-decoration:underline; text-underline-offset:3px;
  }
  .lightbox-article p a:hover{ color:var(--gold-light); }
  .lightbox-article-title a{ color:inherit; text-decoration:underline; text-underline-offset:4px; }

  /* ============ PALETTE DE SAVOIR-FAIRE (accueil, bandeau "Studio et atelier") ============ */
  /* 6 ronds-photo NON cliquables (pas de lien, pas de liseret/survol) sous le
     titre : mêmes ronds bordés or et même apparition gauche→droite que
     .voir-aussi-item (délai --reveal-delay, voir script.js), sur une seule
     ligne sur ordinateur, 2 lignes de 3 sur mobile, demandé explicitement. */
  .palette-title{
    margin:2.4rem 0 0;
    font-size:1.5rem; color:var(--cream); line-height:1.25; text-align:center;
  }
  .palette-grid{
    list-style:none; margin:.6rem 0 0; padding:0; width:100%; max-width:1180px;
    display:flex; flex-wrap:nowrap; justify-content:center; align-items:flex-start;
    gap:clamp(1rem,2.4vw,2.6rem);
  }
  .palette-item{
    display:flex; flex-direction:column; align-items:center; gap:.9rem;
    flex:1 1 0; max-width:170px; min-width:0;
    opacity:0; transform:translateY(14px) scale(.8);
    transition:opacity .45s ease, transform .45s ease;
    transition-delay:var(--reveal-delay, 0s);
  }
  .palette-item.is-in{ opacity:1; transform:translateY(0) scale(1); }
  .palette-circle{
    display:block; width:100%; aspect-ratio:1; border-radius:50%; overflow:hidden;
    border:2px solid var(--gold);
  }
  .palette-circle img{
    width:100%; height:100%; object-fit:cover; object-position:var(--bp-x,50%) center; display:block;
  }
  .palette-label{
    font-family:'DM Sans',sans-serif; font-size:.7rem; letter-spacing:.2em;
    text-transform:uppercase; color:var(--gold); font-weight:600; text-align:center; line-height:1.5;
  }
  @media(max-width:640px){
    .palette-title{ margin-top:2rem; }
    /* 3 ronds par ligne sur 2 lignes : largeur fixe en vw avec de la marge
       réelle (3×24vw = 72vw dans les 90vw utiles), pas de calc() serré. */
    .palette-grid{
      display:grid; grid-template-columns:repeat(3,24vw); justify-content:space-between;
      row-gap:1.6rem; gap:1.6rem 0;
    }
    .palette-item{ max-width:none; width:24vw; gap:.6rem; }
    .palette-label{ font-size:.58rem; letter-spacing:.08em; }
  }

  /* Trio de photos "souvenirs" (page Mural Fest) : 3 photos côte à côte, cadres 4/3 fixes
     (object-fit:cover) pour que des formats différents ne décalent rien ; en colonne sur mobile. */
  .festival-trio-section{ padding:3rem 5vw; }
  .festival-trio{ display:grid; grid-template-columns:repeat(3,1fr); gap:.9rem; max-width:1100px; margin:0 auto; }
  .festival-trio-item{ margin:0; aspect-ratio:4/3; overflow:hidden; border:1px solid var(--gold); border-radius:6px; }
  .festival-trio-item img{ width:100%; height:100%; object-fit:cover; display:block; }
  @media(max-width:640px){
    .festival-trio{ grid-template-columns:1fr; gap:.8rem; }
  }

  /* Titre de l'œuvre mis en avant (page Mural Fest) : grand titre dans l'en-tête, pas un h2
     (les h2 restent à 1.5rem sur tout le site). */
  .section-head p.blog-work-title{
    margin:1.6rem auto 1.4rem;
    font-family:'Playfair Display',serif; font-style:italic; font-weight:700;
    font-size:clamp(1.9rem, 5.2vw, 3rem); line-height:1.15; color:var(--gold);
    max-width:24ch; text-wrap:balance;
  }

  /* Bloc "atouts" des pages blog destinées aux professionnels (piscinistes…) : 3 colonnes de
     .ma-item (titre ✓ + texte, styles existants), 1 colonne sur mobile. */
  .benefits-grid{
    display:grid; grid-template-columns:repeat(3,1fr); gap:1.8rem 2.6rem;
    max-width:1100px; margin:2.6rem auto 0; text-align:left;
  }
  @media(max-width:800px){
    .benefits-grid{ grid-template-columns:1fr; margin-top:1.8rem; }
  }

  /* Titres cliquables du bloc "atouts" (ex. secteur CHR sur la page architectes) : lien discret,
     soulignement doré, mêmes couleurs que le titre. */
  .benefits-grid .ma-item h4 a{
    color:inherit; text-decoration:underline; text-decoration-color:var(--gold);
    text-underline-offset:5px; text-decoration-thickness:1px; transition:color .3s ease;
  }
  .benefits-grid .ma-item h4 a:hover{ color:var(--gold-light); }

  /* Page contact : le surtitre "Contact" est le titre de niveau 1 de la page (h1) ; on lui garde
     exactement l'aspect du surtitre d'origine (petit texte doré en capitales, en ligne, sans marge). */
  .contact-info h1.contact-h1{ display:inline; margin:0; padding:0; line-height:normal; }
