/* =====================================================
   CIVIKA — site vitrine
   Feuille AUTONOME : aucun partage avec site.css (sites de communes) ni
   prospect.css (fiches). Préfixe `v-` sur toutes les classes pour qu'un
   futur mélange accidentel se voie immédiatement.
   ===================================================== */

:root {
    --v-bleu:        #2563eb;
    --v-bleu-clair:  #60a5fa;
    --v-violet:      #7c3aed;
    --v-encre:       #0b1220;
    --v-encre-doux:  #1e293b;
    --v-gris:        #5b6879;
    --v-gris-clair:  #94a3b8;
    --v-fond:        #ffffff;
    --v-fond-alt:    #f6f8fc;
    --v-bordure:     #e4e9f2;
    --v-rayon:       18px;
    --v-rayon-sm:    12px;
    --v-ombre:       0 1px 2px rgba(11, 18, 32, .04), 0 8px 24px -8px rgba(11, 18, 32, .10);
    --v-ombre-forte: 0 20px 50px -18px rgba(11, 18, 32, .28);
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
    margin: 0;
    font-family: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
    font-size: 17px; line-height: 1.65; font-weight: 400;
    color: var(--v-encre-doux); background: var(--v-fond);
    -webkit-font-smoothing: antialiased;
    /* Pied de page toujours en bas, meme sur une page courte */
    min-height: 100dvh; display: flex; flex-direction: column;
}
main { flex: 1 0 auto; }
img { max-width: 100%; height: auto; display: block; }

h1, h2, h3 {
    margin: 0 0 16px; color: var(--v-encre);
    letter-spacing: -.03em; line-height: 1.1; font-weight: 800;
    text-wrap: balance;
}
/* max-width 730 = ~2 lignes maxi sur un H1 colossal, garde l'accroche
   compacte au lieu de s'étaler sur toute la largeur du hero. `text-wrap:
   balance` (hérité de h1,h2,h3) équilibre les lignes automatiquement.
   `line-height: 1` (au lieu de 1.1 hérité) : titres colossaux plus
   ramassés verticalement, l'interligne suffit sans respiration excessive. */
h1 { font-size: clamp(38px, 5.6vw, 68px); max-width: 730px; line-height: 1; }
h2 { font-size: clamp(28px, 3.6vw, 44px); }
h3 { font-size: 20px; letter-spacing: -.015em; font-weight: 700; }
p  { margin: 0 0 18px; }
a  { color: var(--v-bleu); }

.v-conteneur { max-width: 1280px; margin: 0 auto; padding: 0 28px; }
/* .v-mesure limite la longueur de ligne d'un bloc de texte. C'est un ENFANT de
   .v-conteneur, jamais la meme balise : pose sur le conteneur, il en remplace la
   mesure et retrecit toute la section — meme piege que .v-prose. Aligne a gauche
   par defaut, sur le meme fer que le reste de la page ; ajouter .v-centre quand
   le bloc doit vraiment etre centre. */
.v-mesure    { max-width: 860px; margin-right: auto; }
.v-centre    { text-align: center; margin-left: auto; margin-right: auto; }
/* text-align: center centre le CONTENU inline. Mais nos h1/h2/h3 portent
   leur propre max-width (730/900 px) et deviennent des blocs plus
   étroits que le parent — ils se calent alors à gauche par défaut.
   Un margin-inline: auto restaure le centrage effectif du bloc lui-même. */
.v-centre h1,
.v-centre h2,
.v-centre h3,
.v-centre p { margin-left: auto; margin-right: auto; }

.v-skip {
    position: absolute; left: -9999px; top: 8px; z-index: 200;
    background: var(--v-encre); color: #fff; padding: 10px 18px; border-radius: 8px;
}
.v-skip:focus { left: 12px; }
:focus-visible { outline: 2px solid var(--v-bleu); outline-offset: 3px; border-radius: 6px; }

/* ---------- En-tete ---------- */
.v-entete {
    position: sticky; top: 0; z-index: 100;
    background: rgba(255, 255, 255, .82);
    backdrop-filter: saturate(180%) blur(14px);
    border-bottom: 1px solid transparent;
    transition: background .25s ease, border-color .2s ease, box-shadow .2s ease;
}
/* Au scroll : opacité montée à .94 (plus opaque = meilleure séparation avec
   le contenu qui défile dessous), bordure + ombre plus marquées. */
.v-entete.est-decolle {
    background: rgba(255, 255, 255, .94);
    border-bottom-color: var(--v-bordure);
    box-shadow: 0 4px 20px -12px rgba(11, 18, 32, .3);
}

/* Sur l'ACCUEIL uniquement : en-tête transparente par-dessus le hero sombre
   jusqu'au premier scroll. Dès `.est-decolle` (>8px de scroll, ajouté par
   vitrine.js), on retombe sur le fond blanc translucide standard.
   Toutes les couleurs de contenu bascule via des sélecteurs `body.v-page-accueil
   .v-entete:not(.est-decolle)` — quand on scrolle, ils cèdent la place aux
   couleurs par défaut sans jamais dupliquer les règles. */
body.v-page-accueil .v-entete[data-entete-transparent]:not(.est-decolle) {
    background: transparent;
    backdrop-filter: none;
    border-bottom-color: transparent;
    box-shadow: none;
}
/* Le logo est dessiné SOMBRE (fichier logo.svg). Sur fond transparent (hero
   sombre) on l'inverse via filter pour l'afficher en BLANC — aucune variante
   d'image à maintenir, un seul fichier pour tout le site. */
body.v-page-accueil .v-entete[data-entete-transparent]:not(.est-decolle) .v-marque img {
    filter: brightness(0) invert(1);
}
/* Nav en couleurs claires UNIQUEMENT en desktop — en mobile le menu s'ouvre
   sur un panneau blanc, il doit conserver ses couleurs sombres pour rester
   lisible. Le burger, lui, reste blanc (voir plus bas). */
@media (min-width: 941px) {
    body.v-page-accueil .v-entete[data-entete-transparent]:not(.est-decolle) .v-nav-lien {
        color: rgba(255, 255, 255, .78);
    }
    body.v-page-accueil .v-entete[data-entete-transparent]:not(.est-decolle) .v-nav-lien:hover,
    body.v-page-accueil .v-entete[data-entete-transparent]:not(.est-decolle) .v-nav-lien.est-actif {
        color: #fff; background: rgba(255, 255, 255, .1);
    }
}
/* Bouton « Se connecter » en variante fantôme claire : bordure blanche
   translucide, fond transparent. Sur scroll, revient au style standard. */
body.v-page-accueil .v-entete[data-entete-transparent]:not(.est-decolle) .v-btn-fantome {
    color: #fff; border-color: rgba(255, 255, 255, .22); background: transparent;
}
body.v-page-accueil .v-entete[data-entete-transparent]:not(.est-decolle) .v-btn-fantome:hover {
    border-color: rgba(255, 255, 255, .5); background: rgba(255, 255, 255, .06);
}
body.v-page-accueil .v-entete[data-entete-transparent]:not(.est-decolle) .v-burger span {
    background: #fff;
}
.v-entete-grille {
    display: flex; align-items: center; gap: 28px; min-height: 88px;
}
.v-marque img { height: 54px; }
.v-nav { display: flex; gap: 4px; margin-left: 8px; flex: 1; }
.v-nav-lien {
    padding: 8px 14px; border-radius: 999px; text-decoration: none;
    color: var(--v-gris); font-weight: 550; font-size: 15.5px;
    transition: background .15s ease, color .15s ease;
}
.v-nav-lien:hover { background: var(--v-fond-alt); color: var(--v-encre); }
.v-nav-lien.est-actif, .v-nav-lien.est-actif:hover { color: var(--v-encre); background: var(--v-fond-alt); }
.v-entete-actions { display: flex; gap: 10px; align-items: center; }

/* ---------- Mega-panneau « Fonctionnalités » (desktop) ----------
   Panneau plein largeur qui s'ouvre sous l'en-tête au survol du lien
   « Fonctionnalités ». Position absolute sur .v-entete (ancre naturelle),
   `:has()` pour déclencher l'ouverture sans JS. Masqué en mobile où le
   menu burger prend le relais. */
.v-nav-item { display: inline-flex; align-items: center; }
.v-nav-item-menu {
    position: relative;
    /* Pont invisible entre le lien et le panneau — comble le « trou »
       créé par le padding vertical du header (88 px de haut vs ~32 px du
       lien). Sans ce ::after, la souris qui traverse vers le panneau
       sortait momentanément de tout hover et le panneau se refermait. */
}
.v-nav-item-menu::after {
    content: ""; position: absolute; left: -8px; right: -8px;
    top: 100%; height: 40px;
    /* Invisible ET non-interactif par défaut : sans pointer-events: none,
       la zone-pont interceptait les clics/hover sur les éléments visuels
       situés en-dessous (typiquement le hero ou une accroche) même quand
       personne n'était sur le lien parent. On ne l'active que pendant
       le hover réel du lien — juste le temps de traverser vers le panneau. */
    pointer-events: none;
}
.v-nav-item-menu:hover::after { pointer-events: auto; }

.v-entete-panneau {
    position: absolute; top: 100%;
    /* Panneau CENTRÉ et BORNÉ à la mesure du conteneur (1280 px), plutôt
       que collé aux bords du viewport. `left/right: 0 + margin: 0 auto`
       fonctionne sur un élément absolute quand max-width est défini.
       Petit `margin-top` pour détacher le panneau du bas du header — le
       panneau devient une CARTE flottante arrondie sur tous les coins. */
    left: 15px; right: 15px; max-width: 1260px; margin: 8px auto 0;
    background: #ffffff;
    border: 1px solid var(--v-bordure); border-radius: 16px;
    box-shadow: 0 20px 40px -20px rgba(11, 18, 32, .2);
    /* Overflow hidden pour clipper l'encart « À la carte » qui déborde
       jusqu'aux bords via margin négatif — les coins arrondis du panneau
       parent découpent proprement les angles de l'encart de droite. */
    overflow: hidden;
    /* Caché par défaut : `opacity` + `pointer-events` (pas de display:none
       pour préserver la transition d'ouverture/fermeture). `visibility` +
       `pointer-events` évite tout clic fantôme quand fermé. */
    opacity: 0; visibility: hidden; pointer-events: none;
    transform: translateY(-8px);
    transition: opacity .2s ease, transform .2s ease, visibility 0s linear .2s;
    z-index: 90;
}
/* Ouverture sur hover du trigger OU focus clavier dedans, OU hover du
   panneau lui-même (permet à la souris de traverser du lien au panneau
   sans fermeture accidentelle). Nécessite :has() — supporté par tous les
   navigateurs modernes depuis 2023. */
.v-entete:has([data-nav-menu]:hover) .v-entete-panneau,
.v-entete:has([data-nav-menu]:focus-within) .v-entete-panneau,
.v-entete:has([data-panneau]:hover) .v-entete-panneau,
.v-entete:has([data-panneau]:focus-within) .v-entete-panneau {
    opacity: 1; visibility: visible; pointer-events: auto;
    transform: translateY(0);
    transition: opacity .2s ease, transform .2s ease, visibility 0s linear;
}

.v-entete-panneau-grille {
    display: grid;
    grid-template-columns: 1.8fr 1fr;
    gap: 44px;
    /* Padding égal sur les 4 côtés (visuellement) — le padding vertical
       48 px de la grille matche les 48 px effectifs à gauche/droite
       (20 grille + 28 conteneur). Respiration homogène en encart carré. */
    padding: 48px 20px;
}
.v-entete-panneau-titre {
    margin: 0 0 10px; font-size: 23px; font-weight: 700;
    letter-spacing: -.015em; color: var(--v-encre);
}
/* Léger décalage à gauche de la colonne inclus — l'eyebrow et le titre
   étaient collés au padding de la grille, un peu de respiration guide
   mieux l'œil vers la grille de modules dessous. */
.v-entete-panneau-inclus { padding-left: 12px; }
/* Eyebrow plus resserrée du titre dans le panneau — le .v-eyebrow global
   met 18 px sous, trop d'espace pour cet encart compact. */
.v-entete-panneau .v-eyebrow { margin-bottom: 8px; }
/* Grille des 6 modules inclus — 3 colonnes desktop, chaque module est un
   lien vers sa fiche `/fonctionnalites/{slug}`. Picto + nom sur une ligne. */
.v-entete-panneau-modules {
    display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px;
}
.v-entete-panneau-module {
    display: flex; align-items: center; gap: 12px;
    padding: 10px 12px; border-radius: 10px;
    text-decoration: none; color: var(--v-encre);
    transition: background .15s ease;
}
.v-entete-panneau-module:hover {
    background: var(--v-fond-alt);
}
.v-entete-panneau-module .v-picto {
    margin-bottom: 0; width: 36px; height: 36px; border-radius: 10px; flex: 0 0 auto;
}
.v-entete-panneau-module-nom { font-size: 14.5px; font-weight: 600; }

/* Colonne droite « À la carte » — bloc BORD À BORD qui occupe toute la
   hauteur du panneau (extension via marges négatives au-delà du padding
   du grille). Filet gauche + fond dégradé le distinguent du bloc blanc. */
.v-entete-panneau-plus {
    /* Négatif top/right/bottom = collé aux 3 bords du panneau parent
       (au-delà du padding 48/20 du grille). Le gauche reste à 0 pour
       préserver le gap avec la colonne inclus. */
    margin: -48px -20px -48px 0;
    padding: 48px 40px;
    background: linear-gradient(135deg, rgba(37, 99, 235, .06), rgba(124, 58, 237, .06));
    /* Coins arrondis DROITE UNIQUEMENT — matchent les angles du panneau
       parent, coins gauche à zéro pour se coller au bloc blanc voisin. */
    border-radius: 0;
    /* Filet gauche discret pour séparer visuellement du contenu blanc. */
    border-left: 1px solid var(--v-bordure);
    display: flex; flex-direction: column; gap: 10px;
    align-items: flex-start;
    /* Pas de `justify-content: center` : les titres des 2 colonnes doivent
       s'aligner en HAUT, comme le fait naturellement la colonne inclus. */
    justify-content: flex-start;
}
.v-entete-panneau-plus-txt {
    margin: 0 0 8px; font-size: 14px; color: var(--v-gris); line-height: 1.55;
}

/* Mobile : mega-panneau masqué, on garde la nav simple + burger. */
@media (max-width: 940px) {
    .v-entete-panneau { display: none; }
}
/* Pas de mega-panneau sur la page /fonctionnalites elle-même — l'utilisateur
   y est déjà, le sous-menu serait redondant. Le lien reste actif dans la nav
   (clic possible), seul le déroulé au hover est neutralisé. */
body.v-page-fonctionnalites .v-entete-panneau { display: none; }
/* Adaptation quand l'en-tête est TRANSPARENTE (accueil, pas encore scrollé) :
   les liens sont en clair sur fond sombre, mais le panneau lui reste blanc
   (contenu classique) — pas d'ajustement de couleur nécessaire. */

.v-btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 9px;
    padding: 12px 22px; border-radius: 999px; text-decoration: none;
    font-weight: 650; font-size: 15.5px; border: 1.5px solid transparent;
    transition: transform .14s ease, box-shadow .18s ease, background .15s ease;
    white-space: nowrap; cursor: pointer;
}
.v-btn-primaire {
    background: linear-gradient(135deg, var(--v-bleu), var(--v-violet));
    color: #fff; box-shadow: 0 8px 22px -10px rgba(37, 99, 235, .8);
}
.v-btn-primaire:hover { transform: translateY(-2px); box-shadow: 0 16px 34px -12px rgba(37, 99, 235, .9); }
.v-btn-fantome { color: var(--v-encre); border-color: var(--v-bordure); background: #fff; }
.v-btn-fantome:hover { border-color: var(--v-gris-clair); }
.v-btn-clair { background: #fff; color: var(--v-encre); }
.v-btn-clair:hover { transform: translateY(-2px); box-shadow: 0 16px 34px -14px rgba(0, 0, 0, .5); }
.v-btn-lg { padding: 15px 30px; font-size: 16.5px; }

.v-burger {
    display: none; background: none; border: 0; padding: 10px; cursor: pointer;
    /* La zone de clic est cadrée pour que la transformation en croix soit
       centrée et symétrique — sans dimensions fixes, `rotate` + `translateY`
       se calculeraient par rapport à des offsets qui bougeraient d'un span
       à l'autre. */
    position: relative;
    width: 42px; height: 42px;
}
.v-burger span {
    display: block;
    position: absolute;
    left: 10px; /* padding container */
    width: 22px; height: 2px;
    background: var(--v-encre); border-radius: 2px;
    /* Origine centrée pour rotate autour du milieu du trait. */
    transform-origin: center;
    transition: transform .28s cubic-bezier(.6,.05,.36,1), opacity .18s ease, top .28s ease;
}
.v-burger span:nth-child(1) { top: 13px; }
.v-burger span:nth-child(2) { top: 20px; }
.v-burger span:nth-child(3) { top: 27px; }
/* Ouvert : les 3 barres se transforment en croix — barre 1 descend et
   pivote de 45°, barre 2 devient invisible, barre 3 monte et pivote
   de -45°. La transition est fluide (.28s), même durée que le menu. */
.v-burger.est-actif span:nth-child(1) { top: 20px; transform: rotate(45deg); }
.v-burger.est-actif span:nth-child(2) { opacity: 0; }
.v-burger.est-actif span:nth-child(3) { top: 20px; transform: rotate(-45deg); }

/* Bloque le scroll du corps quand le menu occupe l'écran. */
body.v-nav-verrouille { overflow: hidden; }

/* Sur l'accueil, quand le menu est OUVERT, l'entête retombe sur son fond
   blanc quel que soit l'état de scroll — sinon les liens du menu
   apparaîtraient sur fond transparent illisible. */
body.v-page-accueil .v-entete[data-entete-transparent].menu-ouvert {
    background: rgba(255, 255, 255, .94);
    backdrop-filter: saturate(180%) blur(14px);
    border-bottom-color: var(--v-bordure);
}
body.v-page-accueil .v-entete[data-entete-transparent].menu-ouvert .v-marque img {
    filter: none;
}
body.v-page-accueil .v-entete[data-entete-transparent].menu-ouvert .v-burger span {
    background: var(--v-encre);
}
/* Les CTA du menu mobile sur la home doivent aussi retrouver leur style
   standard quand le menu est ouvert — sinon `.v-btn-fantome` hérite du
   mode transparent (texte + bordure blanches) et se retrouve blanc sur
   blanc dans le panneau ouvert. */
body.v-page-accueil .v-entete[data-entete-transparent].menu-ouvert .v-nav-actions .v-btn-fantome {
    color: var(--v-encre);
    border-color: var(--v-bordure);
    background: #fff;
}
body.v-page-accueil .v-entete[data-entete-transparent].menu-ouvert .v-nav-actions .v-btn-fantome:hover {
    border-color: var(--v-gris-clair);
    background: #fff;
}

@media (max-width: 940px) {
    .v-nav {
        /* Panneau pleine hauteur — propriétés explicites (top / left /
           right / height) plus fiables qu'`inset` selon les navigateurs.
           `100dvh` prend en compte la barre d'adresse mobile qui se
           replie au scroll (100vh laisserait une bande sous le pli). */
        position: fixed;
        top: 88px; left: 0; right: 0;
        height: calc(100dvh - 88px);
        flex-direction: column; gap: 4px;
        background: #fff; border-top: 1px solid var(--v-bordure);
        padding: 24px 28px 40px; margin: 0; display: none;
        overflow-y: auto;
    }
    .v-nav.est-ouvert { display: flex; }
    .v-nav-lien { padding: 14px 14px; font-size: 18px; }
    /* Les actions (Se connecter, Essai gratuit) sont dupliquées dans le
       menu mobile via .v-nav-actions (rendue par le layout PHP), poussée
       en bas du panneau par `margin-top: auto`. Ça remplit visuellement
       le menu ET offre les 2 CTA à portée de pouce sans revenir à l'en-tête. */
    .v-nav-actions {
        margin-top: auto;
        display: flex; flex-direction: column; gap: 10px;
        padding-top: 24px; border-top: 1px solid var(--v-bordure);
    }
    .v-nav-actions .v-btn { width: 100%; text-align: center; padding: 14px 20px; font-size: 16px; }
    .v-entete-grille { justify-content: space-between; }
    /* On masque les 2 CTA en-tête sur mobile : ils sont dans le menu. */
    .v-entete-actions { display: none; }
    .v-burger { display: block; }
}
/* Sur desktop, `.v-nav-actions` (menu mobile) reste caché — les CTA
   sont déjà présents dans `.v-entete-actions` en haut à droite. */
@media (min-width: 941px) { .v-nav-actions { display: none; } }

/* ---------- Sections ---------- */
.v-section { padding: clamp(64px, 9vw, 116px) 0; }
.v-section-alt { background: var(--v-fond-alt); }
.v-section-entete { max-width: 760px; margin: 0 auto clamp(38px, 5vw, 62px); text-align: center; }
.v-section-entete p { font-size: 19px; color: var(--v-gris); margin: 0; }

.v-eyebrow {
    display: inline-block; margin-bottom: 18px;
    font-size: 12.5px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase;
    color: var(--v-bleu);
}

/* ---------- Hero ---------- */
.v-hero {
    position: relative; overflow: hidden;
    background: var(--v-encre);
    padding: clamp(80px, 11vw, 150px) 0 clamp(72px, 10vw, 130px);
    color: #fff;
}
/* Sur l'ACCUEIL uniquement : le hero passe SOUS l'en-tête transparente.
   Marge négative = hauteur du header, compensée par le padding-top pour que
   le contenu ne bouge pas visuellement. Sur les autres pages, hero reste
   en-dessous du header standard. */
body.v-page-accueil .v-hero {
    margin-top: -88px;
    /* Padding-top réduit : 88 (header) + 40-90px pour rapprocher le contenu
       du haut de page. Le titre est colossal, il n'a pas besoin d'une grosse
       zone de respiration au-dessus pour prendre sa place. */
    padding-top: calc(88px + clamp(40px, 5vw, 90px));
}

/* Halos animés — 3 spots colorés qui dérivent lentement (32-40s cycle),
   effet « aurore » discret. Placés dans un div dédié (.v-hero-halos) plutôt
   que sur pseudo-éléments, pour pouvoir positionner 3 halos indépendamment
   sans coller les animations. `will-change: transform` = compositor GPU. */
.v-hero-halos {
    position: absolute; inset: 0; overflow: hidden; pointer-events: none;
}
.v-halo {
    position: absolute; border-radius: 50%; filter: blur(4px);
    will-change: transform, opacity;
}
.v-halo-bleu {
    top: -340px; left: -180px; width: 900px; height: 900px;
    background: radial-gradient(circle, rgba(37, 99, 235, .55), transparent 62%);
    animation: v-halo-derive-a 34s ease-in-out infinite;
}
.v-halo-violet {
    top: -220px; right: -220px; width: 780px; height: 780px;
    background: radial-gradient(circle, rgba(124, 58, 237, .48), transparent 62%);
    animation: v-halo-derive-b 40s ease-in-out infinite;
}
.v-halo-cyan {
    bottom: -280px; left: 45%; width: 620px; height: 620px;
    background: radial-gradient(circle, rgba(14, 165, 233, .28), transparent 62%);
    animation: v-halo-derive-c 46s ease-in-out infinite;
}
@keyframes v-halo-derive-a {
    0%, 100% { transform: translate(0, 0) scale(1); opacity: 1; }
    50%      { transform: translate(80px, 50px) scale(1.08); opacity: .85; }
}
@keyframes v-halo-derive-b {
    0%, 100% { transform: translate(0, 0) scale(1); opacity: .9; }
    50%      { transform: translate(-70px, 60px) scale(1.12); opacity: 1; }
}
@keyframes v-halo-derive-c {
    0%, 100% { transform: translate(0, 0) scale(1); opacity: .7; }
    50%      { transform: translate(60px, -40px) scale(1.15); opacity: .95; }
}
@media (prefers-reduced-motion: reduce) {
    .v-halo { animation: none; }
}

/* ---------- Ruban 3D animé (Three.js / WebGL) ----------
   Conteneur du canvas généré dynamiquement par hero_twist.js. Absolu sur
   toute la surface du hero, pointer-events désactivés pour laisser passer
   les clics vers le texte/CTAs, z-index modéré : au-dessus des halos, sous
   le contenu texte (.v-conteneur z-index: 1). Masqué sous 700 px (le JS
   n'initialise même pas WebGL dans ce cas — cf. hero_twist.js). */
.v-hero-twist {
    position: absolute; inset: 0;
    pointer-events: none; overflow: hidden;
    z-index: 0;
    /* Screen : les couleurs de la torsade s'AJOUTENT au fond sombre du hero
       (formule 1-(1-a)(1-b)) → rendu lumineux, la torsade brille au-dessus
       du fond navy sans jamais tomber en noir même dans ses zones sombres. */
    mix-blend-mode: screen;
    /* Opacité réduite pour l'intégrer plus discrètement au hero — le mesh
       reste net (pas de flou/composant supplémentaire), c'est juste sa
       présence visuelle qui est atténuée. */
    opacity: .55;
}
.v-hero-twist canvas { display: block; width: 100%; height: 100%; }


.v-hero > .v-conteneur { position: relative; z-index: 1; }
.v-hero h1 { color: #fff; }

/* Grille 2 colonnes (texte + mockup) sur desktop. Le texte est légèrement
   privilégié (1.35fr vs 1fr) car c'est là qu'est le message ; le mockup
   compense en poussant vers la droite (translateX sur .v-hero-mockup) et
   peut PARTIR HORS CHAMP — clippé par `overflow: hidden` du hero, pas de
   scrollbar horizontale. */
.v-hero-grille {
    display: grid;
    grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr);
    gap: 56px;
    align-items: center;
}
.v-hero-mockup {
    /* Décalage à droite : le cadre déborde partiellement de sa colonne, la
       moitié droite peut sortir du viewport pour un effet « aperçu qui
       glisse dans la page » — donne du dynamisme sans coût de composition. */
    transform: translateX(20%);
}
@media (max-width: 1080px) {
    /* On garde la grille 2 colonnes mais on rétrécit la colonne mockup et
       on pousse davantage le cadre à droite — il ne dépasse plus qu'à
       moitié dans le viewport (clippé par `overflow: hidden` du hero) ;
       le texte reprend l'essentiel de la largeur pour rester lisible. */
    .v-hero-grille {
        grid-template-columns: minmax(0, 1.9fr) minmax(0, 1fr);
        gap: 32px;
    }
    .v-hero-mockup { transform: translateX(50%); }
    /* Cartes flottantes retirées à ce breakpoint : elles collent au bord du
       viewport et débordent visuellement, sans apporter de plus-value. */
    .v-hero-mockup .v-mockup-flottante { display: none; }
}
@media (max-width: 700px) {
    /* Sous 700px, le mockup est trop englouti (moins d'un tiers visible) —
       retiré pour laisser respirer le texte. */
    .v-hero-grille { grid-template-columns: 1fr; gap: 60px; }
    .v-hero-mockup { display: none; }
}

.v-hero-intro {
    font-size: clamp(18px, 2vw, 21px); color: rgba(255, 255, 255, .78);
    margin: 0 0 34px;
}
.v-hero-actions { display: flex; flex-wrap: wrap; gap: 14px; align-items: center; }
.v-hero-note {
    margin: 22px 0 0; font-size: 14.5px; line-height: 1.6;
    color: rgba(255, 255, 255, .55);
}
/* La ligne prix (dans un <b>) ressort — blanc quasi plein, la seconde ligne
   « tarif unique » reste en secondaire. */
.v-hero-note b { color: rgba(255, 255, 255, .95); font-weight: 700; font-size: 15.5px; }
/* Variante fantôme claire — bouton outline blanc sur fond sombre. Remplace le
   `style="color:#fff;border-color:rgba(255,255,255,.25)"` inline précédent. */
.v-btn-fantome-clair {
    color: #fff; border-color: rgba(255, 255, 255, .28); background: transparent;
}
.v-btn-fantome-clair:hover {
    border-color: rgba(255, 255, 255, .55); background: rgba(255, 255, 255, .06);
}

/* ---------- Mockup hero (100 % HTML/CSS) ----------
   Cadre navigateur macOS + capture minimaliste d'un site de commune.
   Aucune image chargée (net à toute résolution, léger). Cartes flottantes
   autour = sensation de produit vivant sans surcharger. */
.v-hero-mockup {
    position: relative;
    perspective: 1400px;
}
.v-mockup-cadre {
    position: relative;
    background: #ffffff;
    border-radius: 14px;
    overflow: hidden;
    box-shadow:
        0 40px 80px -30px rgba(0, 0, 0, .55),
        0 20px 40px -20px rgba(37, 99, 235, .35),
        0 0 0 1px rgba(255, 255, 255, .06);
    /* Bascule 3D de repos ; vitrine.js remplace ce `transform` en continu
       quand la souris bouge (effet tilt). `will-change` demande au compositor
       de promouvoir en couche GPU, évite le hoquet à la 1re frame. */
    transform: rotateY(-6deg) rotateX(3deg);
    transform-style: preserve-3d;
    will-change: transform;
    transition: transform .3s ease-out;   /* fallback quand JS ne tourne pas */
    /* Désaturation globale de la capture : donne un rendu « présentation
       produit » plus posé, moins criard, sans réécrire chaque couleur.
       Les notifications flottantes autour restent à saturation pleine
       (elles sont hors du cadre). */
    filter: saturate(.75);
}
.v-mockup-barre {
    display: flex; align-items: center; gap: 8px;
    padding: 11px 14px;
    background: #f1f3f7;
    border-bottom: 1px solid #e3e7ee;
}
.v-mockup-pt { width: 11px; height: 11px; border-radius: 50%; flex: 0 0 auto; }
.v-mockup-pt-r { background: #ff5f57; }
.v-mockup-pt-o { background: #febc2e; }
.v-mockup-pt-v { background: #28c840; }
.v-mockup-url {
    margin-left: 14px; padding: 4px 12px;
    background: #ffffff; border: 1px solid #e3e7ee; border-radius: 6px;
    font-size: 11.5px; color: #6b7280; font-family: -apple-system, system-ui, sans-serif;
    flex: 1; max-width: 240px;
}
.v-mockup-ecran { padding: 18px 20px 22px; background: #ffffff; }
.v-mockup-entete {
    display: flex; align-items: center; justify-content: space-between;
}
/* Blason municipal — SVG dessiné dans le HTML. Écu simplifié + gradient
   primaire (bleu → violet, cohérent avec l'identité Civika). Aucune image
   à charger, net à toute résolution. */
.v-mockup-blason { width: 28px; height: 30px; display: block; }
.v-mockup-nav { display: flex; gap: 14px; }
.v-mockup-nav span {
    display: block; width: 28px; height: 5px; border-radius: 3px;
    background: #dfe4ec;
}

.v-mockup-hero {
    position: relative; overflow: hidden;
    margin: 16px -20px 18px; padding: 24px 20px 22px;
    color: #fff;
    /* Camaïeu bleu-violet : dégradé principal bleu nuit → violet + halos
       DANS la même famille (bleu clair et violet clair), aucun contraste
       de teinte. Sensation « posée, cohérente », plus institutionnelle. */
    background:
        radial-gradient(circle at 85% 15%, rgba(139, 92, 246, .3), transparent 55%),
        radial-gradient(circle at 15% 90%, rgba(59, 130, 246, .32), transparent 55%),
        linear-gradient(135deg, #0f172a 0%, #4338ca 55%, #7c3aed 100%);
}
.v-mockup-hero h4 { margin: 0 0 4px; font-size: 15px; font-weight: 700; }
.v-mockup-hero p  { margin: 0; font-size: 11.5px; opacity: .85; }
/* Chip météo (coin sup. droit du hero) — glass morphism léger + icône soleil. */
.v-mockup-chip {
    position: absolute; top: 12px; right: 14px;
    display: inline-flex; align-items: center; gap: 5px;
    padding: 3px 8px 3px 6px;
    background: rgba(255, 255, 255, .18); border: 1px solid rgba(255, 255, 255, .25);
    border-radius: 999px;
    color: #fff; backdrop-filter: blur(6px);
}
.v-mockup-chip svg { width: 10px; height: 10px; }
.v-mockup-chip-l { display: block; width: 24px; height: 4px; border-radius: 2px; background: rgba(255, 255, 255, .8); }
/* Barre de recherche à l'intérieur du hero — glass morphism, icône loupe.
   Largeur ~50 % du hero pour ne pas s'étaler comme un champ formulaire. */
.v-mockup-recherche {
    display: inline-flex; align-items: center; gap: 8px;
    margin-top: 12px; padding: 8px 14px;
    width: 50%; max-width: 200px;
    background: rgba(255, 255, 255, .16); border: 1px solid rgba(255, 255, 255, .22);
    border-radius: 999px; color: rgba(255, 255, 255, .85);
    backdrop-filter: blur(6px);
}
.v-mockup-recherche svg { width: 12px; height: 12px; flex: 0 0 auto; }
.v-mockup-recherche-l { display: block; height: 5px; width: 60%; border-radius: 3px; background: rgba(255, 255, 255, .5); }

.v-mockup-raccourcis {
    display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px;
    margin-bottom: 16px;
}
.v-mockup-racc {
    aspect-ratio: 1; background: #f4f6fa; border-radius: 10px;
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px;
    padding: 6px;
    /* Léger dégradé pour éviter l'aplat plat — donne de la texture. */
    background: linear-gradient(180deg, #f8fafc 0%, #eef2f8 100%);
    border: 1px solid rgba(228, 233, 240, .8);
}
.v-mockup-racc svg { width: 18px; height: 18px; color: var(--v-bleu); }
.v-mockup-racc-l { display: block; width: 60%; height: 4px; border-radius: 2px; background: #cfd6e3; }

/* Bandeau de section (« Dernières actualités » + lien « Tout voir ») — barres
   simulées, gauche large, droite courte. */
.v-mockup-section-tete {
    display: flex; align-items: center; justify-content: space-between;
    margin-bottom: 10px; padding: 0 2px;
}
.v-mockup-section-l    { display: block; width: 45%; height: 8px; border-radius: 4px; background: var(--v-encre); }
.v-mockup-section-lien { display: block; width: 42px; height: 5px; border-radius: 3px; background: var(--v-bleu); }

.v-mockup-cartes {
    display: grid; grid-template-columns: 1fr 1fr; gap: 10px;
}
.v-mockup-carte {
    background: #ffffff; border: 1px solid #eef1f6; border-radius: 10px;
    overflow: hidden;
    box-shadow: 0 1px 3px rgba(0, 0, 0, .04);
}
.v-mockup-img {
    aspect-ratio: 16/9;
    /* Dégradés distincts pour les 2 cards → suggérer 2 sujets différents
       (nature/festif) sans afficher de vraie photo. */
}
/* Aplat unique pour les deux cartes — même fond que le hero pour maintenir
   l'unité visuelle du camaïeu bleu-violet dans toute la maquette. */
.v-mockup-img-1 {
    background:
        radial-gradient(circle at 85% 15%, rgba(139, 92, 246, .3), transparent 55%),
        radial-gradient(circle at 15% 90%, rgba(59, 130, 246, .32), transparent 55%),
        linear-gradient(135deg, #0f172a 0%, #4338ca 55%, #7c3aed 100%);
}
.v-mockup-carte-corps { padding: 10px 10px 12px; }
.v-mockup-carte-meta {
    display: flex; align-items: center; gap: 6px; margin-bottom: 8px;
}
.v-mockup-tag {
    display: inline-block; padding: 2px 7px;
    border-radius: 999px; height: 8px; min-width: 40px;
}
/* Chips catégories dans la même famille bleu/violet, tonalités différentes. */
.v-mockup-tag-1 { background: rgba(37, 99, 235, .16); box-shadow: inset 0 0 0 1px rgba(37, 99, 235, .3); }
.v-mockup-tag-2 { background: rgba(124, 58, 237, .16); box-shadow: inset 0 0 0 1px rgba(124, 58, 237, .3); }
.v-mockup-date { display: block; width: 34px; height: 4px; border-radius: 2px; background: #cfd6e3; }
.v-mockup-l { height: 6px; border-radius: 3px; background: #dfe4ec; }
.v-mockup-l.l1 { width: 92%; margin-bottom: 5px; }
.v-mockup-l.l2 { width: 58%; }

/* Cartes flottantes autour du mockup — notifications qui donnent une vie
   au produit. Petit float subtil (4s), décalées pour ne pas se chevaucher. */
.v-mockup-flottante {
    position: absolute; z-index: 2;
    display: flex; align-items: center; gap: 12px;
    padding: 12px 16px;
    background: rgba(255, 255, 255, .96);
    border: 1px solid rgba(255, 255, 255, .3);
    border-radius: 12px;
    box-shadow: 0 20px 40px -15px rgba(0, 0, 0, .35);
    color: var(--v-encre); font-size: 13px;
    backdrop-filter: blur(10px);
    animation: v-mockup-flotte 4.5s ease-in-out infinite;
}
.v-mockup-flottante strong { display: block; font-weight: 700; font-size: 13px; }
.v-mockup-flottante small  { display: block; color: var(--v-gris); font-size: 11.5px; margin-top: 2px; }
.v-mockup-fl-pt { width: 10px; height: 10px; border-radius: 50%; flex: 0 0 auto; }
.v-mockup-fl-pt-v { background: #22c55e; box-shadow: 0 0 0 4px rgba(34, 197, 94, .18); }
.v-mockup-fl-pt-b { background: var(--v-bleu); box-shadow: 0 0 0 4px rgba(37, 99, 235, .18); }
.v-mockup-flottante-1 { top: 12%; left: -8%; animation-delay: 0s; }
.v-mockup-flottante-2 { bottom: 15%; right: -6%; animation-delay: 2s; }
@keyframes v-mockup-flotte {
    0%, 100% { transform: translateY(0); }
    50%      { transform: translateY(-8px); }
}
@media (prefers-reduced-motion: reduce) {
    .v-mockup-flottante { animation: none; }
}
@media (max-width: 640px) {
    /* Cartes flottantes retirées en mobile — trop de charge visuelle sur
       un écran étroit, et elles débordent hors du cadre. */
    .v-mockup-flottante { display: none; }
    .v-mockup-cadre { transform: none; }
}

.v-puce {
    display: inline-flex; align-items: center; gap: 9px; margin-bottom: 26px;
    padding: 7px 16px 7px 12px; border-radius: 999px;
    background: rgba(255, 255, 255, .08); border: 1px solid rgba(255, 255, 255, .14);
    font-size: 14px; font-weight: 550; color: rgba(255, 255, 255, .9);
}
.v-puce b { color: #fff; font-weight: 700; }
.v-point { width: 7px; height: 7px; border-radius: 50%; background: #4ade80; flex: 0 0 auto; }

/* ---------- Cartes ---------- */
.v-grille { display: grid; gap: 22px; }
.v-grille-3 { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
.v-grille-2 { grid-template-columns: repeat(auto-fit, minmax(380px, 1fr)); }
.v-grille-4 { grid-template-columns: repeat(auto-fit, minmax(232px, 1fr)); }

.v-carte {
    background: #fff; border: 1px solid var(--v-bordure); border-radius: var(--v-rayon);
    padding: 30px 28px; box-shadow: var(--v-ombre);
    transition: transform .18s ease, box-shadow .22s ease, border-color .18s ease;
}
.v-carte h3 { margin-bottom: 10px; max-width: 23ch; }

/* Apparition des cartes au scroll — ajouté par vitrine.js via
   IntersectionObserver. La classe .va-apparaitre est POSÉE PAR JS uniquement,
   ce qui garantit que si JS échoue/désactivé, les cartes s'affichent
   normalement (dégradation gracieuse). */
.va-apparaitre {
    opacity: 0;
    transform: translateY(24px);
    transition: opacity .55s cubic-bezier(.22, .61, .36, 1),
                transform .55s cubic-bezier(.22, .61, .36, 1);
}
.va-apparaitre.est-visible {
    opacity: 1;
    transform: translateY(0);
}
.v-carte p  { margin: 0; color: var(--v-gris); font-size: 15.5px; }
a.v-carte { display: block; text-decoration: none; color: inherit; }
a.v-carte:hover { transform: translateY(-3px); box-shadow: var(--v-ombre-forte); border-color: #cfd9ea; }

.v-picto {
    width: 46px; height: 46px; border-radius: 13px; flex: 0 0 auto;
    display: grid; place-items: center; margin-bottom: 18px;
    background: linear-gradient(135deg, rgba(37, 99, 235, .12), rgba(124, 58, 237, .12));
    color: var(--v-bleu); font-size: 21px;
}
/* Dans une tête de carte, l'espacement est porté par le conteneur flex :
   la marge du picto y ferait un décalage vertical avec l'étiquette. */
.v-carte-tete .v-picto, .v-module-tete .v-picto { margin-bottom: 0; }
.v-picto svg { width: 22px; height: 22px; stroke-width: 1.9; }
.v-picto-lg { width: 60px; height: 60px; border-radius: 17px; }
.v-picto-lg svg { width: 28px; height: 28px; }
/* Picto et étiquette sur la même ligne : le regard prend le type de module et
   son prix d'un seul coup d'œil, avant même de lire le titre. */
.v-carte-tete, .v-module-tete {
    display: flex; align-items: center; gap: 14px; margin-bottom: 18px;
}
.v-carte-tete .v-etiquette, .v-module-tete .v-etiquette { margin-left: auto; }

.v-etiquette {
    display: inline-block; padding: 4px 11px; border-radius: 999px;
    font-size: 12.5px; font-weight: 650;
    background: var(--v-fond-alt); color: var(--v-gris);
}
.v-etiquette-incluse { background: rgba(74, 222, 128, .16); color: #15803d; }

/* ---------- Tarifs ---------- */
.v-prix-bloc {
    max-width: 480px; margin: 0 auto; text-align: center;
    background: var(--v-encre); color: #fff; border-radius: 26px;
    padding: 44px 38px; box-shadow: var(--v-ombre-forte);
    position: relative; overflow: hidden;
}
.v-prix-bloc::before {
    content: ""; position: absolute; top: -160px; left: -80px; width: 420px; height: 420px;
    border-radius: 50%; background: radial-gradient(circle, rgba(124, 58, 237, .5), transparent 65%);
}
.v-prix-bloc > * { position: relative; z-index: 1; }
.v-prix-bloc h2, .v-prix-bloc h3 { color: #fff; font-size: 22px; margin-bottom: 6px; }
/* Pas de letter-spacing négatif : les chiffres à graisse forte se collent
   mal avec un tracking serré, on garde l'espacement naturel de la police. */
.v-prix-montant { font-size: 72px; font-weight: 800; line-height: 1; }
.v-prix-unite { color: rgba(255, 255, 255, .7); font-size: 16px; margin: 8px 0 26px; }
.v-prix-liste { list-style: none; margin: 0 0 28px; padding: 0; text-align: left; }
.v-prix-liste li {
    display: flex; gap: 11px; align-items: flex-start;
    padding: 9px 0; font-size: 15.5px; color: rgba(255, 255, 255, .88);
}
.v-check { color: #4ade80; flex: 0 0 auto; font-weight: 700; }

/* ---------- Carrousel ----------
   Defilement natif avec accroche (scroll-snap) : le geste tactile, l'inertie
   et la molette sont ceux du systeme, sans bibliotheque a embarquer — ce que
   la politique de securite du contenu interdirait de charger depuis un CDN.
   Sans JavaScript, le bloc reste utilisable : il defile a la main. */
.v-carrousel { position: relative; }
.v-carrousel-piste {
    display: grid; grid-auto-flow: column; grid-auto-columns: minmax(320px, 1fr);
    gap: 22px; overflow-x: auto; overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory; scroll-padding: 0 2px;
    padding: 4px 2px 10px; margin: -4px -2px 0;
    scrollbar-width: none;
}
.v-carrousel-piste::-webkit-scrollbar { display: none; }
.v-carte-slide { scroll-snap-align: start; display: flex; flex-direction: column; }
.v-carte-slide p { flex: 1; }
.v-carte-lien {
    display: inline-flex; align-items: center; gap: 7px; margin-top: 18px;
    color: var(--v-bleu); font-weight: 650; font-size: 14.5px;
}
.v-carte-slide:hover .v-carte-lien svg { transform: translateX(3px); }
.v-carte-lien svg { transition: transform .16s ease; }

/* Au-dela de 4 cartes visibles, la piste ne defile plus : on la centre. */
@media (min-width: 1400px) { .v-carrousel-piste { grid-auto-columns: minmax(300px, 1fr); } }

.v-carrousel-cmd {
    display: flex; align-items: center; justify-content: center; gap: 16px; margin-top: 22px;
}
.v-carrousel-fleche {
    width: 44px; height: 44px; border-radius: 50%; flex: 0 0 auto; cursor: pointer;
    display: grid; place-items: center;
    background: #fff; border: 1.5px solid var(--v-bordure); color: var(--v-encre);
    transition: border-color .15s ease, transform .15s ease, opacity .15s ease;
}
.v-carrousel-fleche:hover:not(:disabled) { border-color: var(--v-bleu); color: var(--v-bleu); transform: translateY(-2px); }
.v-carrousel-fleche:disabled { opacity: .35; cursor: default; }
.v-carrousel-points { display: flex; gap: 7px; }
.v-carrousel-point {
    width: 7px; height: 7px; border-radius: 50%; background: #cfd9ea; border: 0; padding: 0;
    transition: width .2s ease, background .2s ease;
}
.v-carrousel-point.est-actif { width: 24px; border-radius: 999px; background: var(--v-bleu); }

/* ---------- Simulateur de tarif ---------- */
.v-simulateur { display: grid; grid-template-columns: 400px 1fr; gap: 28px; align-items: start; }
.v-prix-colonne { position: sticky; top: 100px; }
@media (max-width: 1000px) {
    .v-simulateur { grid-template-columns: 1fr; }
    .v-prix-colonne { position: static; }
}
.v-prix-detail {
    margin: 22px 0 4px; padding: 14px 0;
    border-top: 1px solid rgba(255, 255, 255, .14);
    border-bottom: 1px solid rgba(255, 255, 255, .14);
}
.v-prix-ligne {
    display: flex; justify-content: space-between; gap: 14px;
    font-size: 14.5px; color: rgba(255, 255, 255, .8); padding: 3px 0;
}
.v-prix-note { margin: 14px 0 0; font-size: 13px; color: rgba(255, 255, 255, .55); }

/* Accueil : le prix a gauche, ce qu'il comprend a droite. La colonne de gauche
   est fixe et etroite — un prix n'a pas besoin de place, une liste si. */
.v-offre {
    display: grid; grid-template-columns: minmax(0, 380px) minmax(0, 1fr);
    gap: 44px; align-items: start;
}
/* La carte remplit sa colonne : la mesure de 480 px et le centrage automatique
   n'ont de sens que lorsqu'elle est seule au milieu de la page. */
.v-prix-bloc-compact { max-width: none; margin: 0; padding: 38px 32px; }
.v-offre-detail h3 { font-size: 22px; margin-bottom: 14px; }
.v-offre-detail .v-aide { margin-top: 18px; }
@media (max-width: 900px) {
    .v-offre { grid-template-columns: 1fr; gap: 32px; }
    .v-prix-bloc-compact { max-width: 480px; margin: 0 auto; }
}

.v-carte-modules { padding: 28px 26px; }
/* Bandeau titre + bouton « Tout décocher » : bouton poussé à DROITE via
   `margin-left: auto` et centré vertical avec le titre H2 (align-items: center).
   Le bouton reste sur sa ligne (white-space: nowrap) même quand le titre
   déborde sur 2 lignes en mobile. */
.v-modules-entete {
    display: flex; align-items: center; gap: 18px; margin-bottom: 22px;
    user-select: none;
}
.v-modules-entete > div { flex: 1; min-width: 0; }
.v-modules-entete h2 { font-size: 22px; margin-bottom: 4px; }
.v-modules-entete p { margin: 0; font-size: 14.5px; color: var(--v-gris); }
.v-modules-entete .v-lien-bouton {
    margin-left: auto; align-self: center;
    /* Léger décalage vers le haut pour aligner l'axe optique du lien avec
       l'axe du H2 (le libellé du bouton étant plus court, l'oeil le voyait
       centré sur le paragraphe descriptif plutôt que sur le titre). */
    margin-top: -8px;
}
.v-lien-bouton {
    background: none; border: 0; padding: 4px 2px; cursor: pointer; white-space: nowrap;
    color: var(--v-bleu); font: inherit; font-size: 12.5px; font-weight: 500;
    text-decoration: underline; text-underline-offset: 3px;
}

.v-modules-grille { display: grid; grid-template-columns: 1fr 1fr; gap: 4px 22px; }
@media (max-width: 700px) { .v-modules-grille { grid-template-columns: 1fr; } }

.v-module-choix {
    display: flex; align-items: center; gap: 12px; padding: 8px 4px; cursor: pointer;
    border-radius: 10px; transition: background .13s ease;
    /* Évite la sélection accidentelle du libellé au double-clic ou au glisser
       sur la ligne — l'élément est cliquable comme un bouton, pas destiné
       à être copié. */
    user-select: none;
}
.v-module-choix:hover { background: var(--v-fond-alt); }
.v-module-choix input { position: absolute; opacity: 0; width: 0; height: 0; }

/* Interrupteur : le seul element vraiment dessine du simulateur. */
.v-interrupteur {
    width: 38px; height: 22px; border-radius: 999px; flex: 0 0 auto; position: relative;
    background: #d3dbe8; transition: background .18s ease;
}
.v-interrupteur::after {
    content: ""; position: absolute; top: 3px; left: 3px; width: 16px; height: 16px;
    border-radius: 50%; background: #fff; box-shadow: 0 1px 3px rgba(11, 18, 32, .3);
    transition: transform .18s ease;
}
.v-module-choix input:checked + .v-interrupteur { background: var(--v-bleu); }
.v-module-choix input:checked + .v-interrupteur::after { transform: translateX(16px); }
.v-module-choix input:focus-visible + .v-interrupteur { outline: 2px solid var(--v-bleu); outline-offset: 3px; }

/* Module inclus : coche et verrouille. Le vert dit « acquis », le curseur
   « non modifiable » — l'utilisateur comprend sans qu'on l'ecrive. */
.v-module-choix.est-inclus { cursor: default; }
.v-module-choix.est-inclus:hover { background: transparent; }
.v-module-choix input:disabled + .v-interrupteur { background: #4ade80; opacity: .85; }

.v-module-texte { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.v-module-choix .v-module-nom { font-size: 15px; font-weight: 600; color: var(--v-encre); }
.v-module-tarif { font-size: 13px; color: var(--v-gris); }
.est-inclus .v-module-tarif { color: #15803d; font-weight: 600; }
.v-module-info {
    color: var(--v-gris-clair); display: grid; place-items: center; padding: 4px; flex: 0 0 auto;
}
.v-module-info:hover { color: var(--v-bleu); }

/* ---------- Recherche de commune (essai) ---------- */
/* Au fer a gauche comme le titre qui la precede, pas centree : le champ est le
   point de depart du parcours, il doit tomber sous le debut du texte. */
.v-recherche { max-width: 660px; margin: 0 auto 56px 0; position: relative; }
.v-recherche label { display: block; font-weight: 700; margin-bottom: 12px; font-size: 17px; }
.v-recherche-champ { position: relative; }
/* Picto en flex : garantit un centrage vertical PARFAIT de l'icône SVG
   dans le span (sans `inline-flex`, la ligne de base du texte décalait
   l'icône de 1-2 px). `line-height: 0` évite tout ajout d'espace vertical. */
.v-recherche-picto {
    position: absolute; left: 20px; top: 50%; transform: translateY(-50%);
    display: inline-flex; align-items: center; justify-content: center;
    line-height: 0; color: var(--v-gris-clair);
}
.v-recherche-champ input {
    width: 100%; padding: 16px 56px 16px 56px; font: inherit; font-size: 17px;
    border: 1.5px solid var(--v-bordure); border-radius: 14px; background: #fff;
    /* Halo violet permanent (repos) : le champ se distingue du fond blanc
       de la page sans avoir besoin d'être encadré ou éclairé — la teinte
       reprend --v-violet, identité produit. Renforcé au focus. */
    box-shadow: 0 8px 26px -14px rgba(124, 58, 237, .35);
    transition: border-color .15s ease, box-shadow .18s ease;
}
.v-recherche-champ input::placeholder { color: var(--v-gris-clair); font-weight: 500; }
.v-recherche-champ input:hover {
    border-color: var(--v-gris-clair);
    box-shadow: 0 12px 32px -14px rgba(124, 58, 237, .45);
}
.v-recherche-champ input:focus {
    outline: none; border-color: var(--v-violet);
    box-shadow: 0 0 0 4px rgba(124, 58, 237, .16), 0 14px 36px -14px rgba(124, 58, 237, .5);
}
.v-recherche-etat {
    position: absolute; right: 18px; top: 50%; transform: translateY(-50%);
    font-size: 13px; color: var(--v-gris-clair);
}
.v-recherche-liste {
    list-style: none; margin: 8px 0 0; padding: 6px; position: absolute; left: 0; right: 0; z-index: 20;
    background: #fff; border: 1px solid var(--v-bordure); border-radius: 14px; box-shadow: var(--v-ombre-forte);
    max-height: 340px; overflow-y: auto;
}
.v-recherche-liste li { border-radius: 10px; }
.v-recherche-liste a {
    display: flex; justify-content: space-between; gap: 14px; align-items: baseline;
    padding: 12px 14px; text-decoration: none; color: inherit;
}
.v-recherche-liste li:hover, .v-recherche-liste li.est-survol { background: var(--v-fond-alt); }
.v-recherche-nom { font-weight: 600; }
.v-recherche-lieu { font-size: 13.5px; color: var(--v-gris-clair); white-space: nowrap; }
.v-recherche-vide { padding: 16px; color: var(--v-gris); font-size: 15px; }

.v-retour {
    padding: 14px 18px; border-radius: var(--v-rayon-sm); margin-bottom: 22px;
    font-size: 15.5px; border: 1px solid transparent;
}
.v-retour-ok { background: rgba(74, 222, 128, .14); border-color: rgba(22, 163, 74, .3); color: #15803d; }
.v-retour-erreur { background: rgba(239, 68, 68, .1); border-color: rgba(220, 38, 38, .3); color: #b91c1c; }

/* Contact : le formulaire garde la largeur utile, la colonne de droite se
   contente de ce que ses trois encarts demandent. */
.v-contact-grille {
    display: grid; grid-template-columns: minmax(0, 1fr) 340px;
    gap: 40px; align-items: start;
}
@media (max-width: 940px) { .v-contact-grille { grid-template-columns: 1fr; } }

/* ---------- Modale d'essai ---------- */
.v-modale {
    width: min(620px, calc(100vw - 32px)); padding: 34px 32px 30px;
    border: 0; border-radius: 22px; box-shadow: var(--v-ombre-forte);
    color: var(--v-encre-doux); background: #fff;
}
.v-modale::backdrop { background: rgba(11, 18, 32, .55); backdrop-filter: blur(3px); }
.v-modale-fermer-forme { position: absolute; top: 14px; right: 14px; margin: 0; }
.v-modale-fermer {
    width: 36px; height: 36px; border-radius: 50%; cursor: pointer;
    background: var(--v-fond-alt); border: 0; color: var(--v-gris); font-size: 15px;
}
.v-modale-fermer:hover { background: #e8edf6; color: var(--v-encre); }
.v-modale-titre { font-size: 26px; margin-bottom: 8px; padding-right: 40px; }
.v-modale-intro { color: var(--v-gris); font-size: 15.5px; margin-bottom: 24px; }

/* Pieges a robots : invisibles sans aria-hidden ni tabindex, qui seraient des
   signaux trop evidents pour un robot un peu soigne. */
.v-piege { position: absolute; width: 1px; height: 1px; overflow: hidden; opacity: 0; }

.v-engagement {
    display: flex; gap: 11px; align-items: flex-start;
    font-size: 14px; line-height: 1.5; color: var(--v-gris); font-weight: 400;
}
.v-engagement input { width: auto; margin-top: 3px; flex: 0 0 auto; }

/* ---------- Etapes ----------
   Bloc graphique : grand numéro en dégradé + icône dans une pastille.
   Ligne pointillée horizontale reliant les 3 étapes — construite via
   ::after sur chaque étape (sauf la dernière) pour être robuste quelle
   que soit la largeur du conteneur (pas de calcul en % fragile). */
.v-etapes {
    list-style: none; padding: 0; margin: 0;
    display: grid; grid-template-columns: repeat(3, 1fr); gap: 40px;
}
.v-etape { position: relative; }
.v-etape h3 { margin: 22px 0 8px; }
.v-etape p  { margin: 0; color: var(--v-gris); font-size: 15.5px; }

/* Tête de chaque étape : grand chiffre + pastille icône alignés
   horizontalement, centrés verticalement sur la ligne pointillée. */
.v-etape-tete {
    display: flex; align-items: center; gap: 16px;
    /* Hauteur explicite = celle de la pastille (60 px) — sinon le grand
       chiffre en font-size 64 augmente la hauteur du tete et décale la
       ligne dashed qu'on aligne à mi-hauteur. */
    height: 60px;
}

/* Ligne pointillée : ::after sur chaque étape SAUF la dernière. Part
   juste après la pastille et va jusqu'au bord droit de la colonne, puis
   traverse le gap et se prolonge jusqu'à la moitié de la colonne suivante.
   La pastille du next étape (avec son halo blanc de 5 px) masquera la fin
   du trait — effet « chemin qui atterrit ». */
.v-etape:not(:last-child)::after {
    content: "";
    position: absolute;
    top: 30px;                    /* centre vertical du tete 60 px */
    /* Décalage à partir du bord DROIT de la pastille — on part de la
       pastille (à droite du numéro), pas du bord de l'étape. */
    left: calc(100% + 12px);      /* fin de l'étape + un peu de marge */
    /* Longueur : la moitié du gap (20 px) + une bonne partie de la
       prochaine étape (jusqu'aux ~2/3), la pastille suivante clippera. */
    width: 80%;
    height: 0;
    border-top: 2px dashed var(--v-bordure);
    /* Derrière la pastille suivante — le halo blanc de la pastille masque
       proprement la fin du trait. */
    z-index: -1;
    /* Correction pour le layout flex de tete : le décalage doit partir
       du bord droit de la pastille, PAS du bord droit de l'étape (qui
       est plus loin puisque le tete ne remplit pas toute la colonne). */
}
/* On repose le ::after sur la pastille elle-même — plus fiable pour
   l'ancrage à sa droite. Reset du ::after précédent. */
.v-etape:not(:last-child)::after { display: none; }
.v-etape:not(:last-child) .v-etape-picto::after {
    content: "";
    position: absolute;
    top: 50%; left: 100%;
    /* Marge = espace entre la pastille et le début du trait. */
    margin-left: 10px;
    /* Longueur : traverse le gap 40 px + une grande partie de la colonne
       suivante (~250 px) — la pastille suivante avec son halo blanc masquera
       le trait qui arrive dessus, donnant un rendu « chemin connecté ». */
    width: 280px;
    height: 0;
    border-top: 2px dashed var(--v-bordure);
    z-index: -1;
}

/* Pastille icône ronde 60 px, gradient primaire, ombre projetée pour
   la détacher du fond alt de la section. Border 5 px en anneau qui
   « masque » la ligne pointillée qui traverse derrière. */
.v-etape-picto {
    position: relative;   /* ancre pour ::after de la ligne */
    flex: 0 0 auto;
    display: grid; place-items: center;
    width: 60px; height: 60px; border-radius: 50%;
    background: linear-gradient(135deg, var(--v-bleu), var(--v-violet));
    color: #fff;
    box-shadow: 0 10px 24px -12px rgba(37, 99, 235, .55);
    /* Halo de la couleur du fond de section — découpe la ligne dashed
       qui passe derrière, effet « chemin » qui atterrit sur la pastille. */
    border: 5px solid var(--v-fond-alt);
    z-index: 1;
}
.v-etape-picto svg { width: 22px; height: 22px; }
/* Grand chiffre en dégradé — outline effect via `background-clip: text`.
   Font-size costaude ; padding-right 0.15em pour compenser le
   letter-spacing serré (sans ça, le dernier chiffre est coupé). */
.v-etape-num {
    font-size: 64px; font-weight: 800; line-height: 1;
    letter-spacing: -.04em;
    padding-right: .1em;
    background: linear-gradient(135deg, var(--v-bleu), var(--v-violet));
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    /* Anti-clip : pad vertical pour que les descendants (rares en chiffres
       mais possibles avec certains numériques) ne soient jamais tronqués. */
    padding-block: 4px;
}

/* Mobile : étapes empilées verticalement, ligne pointillée masquée
   (elle ne relierait rien de visible dans un empilement vertical). */
@media (max-width: 780px) {
    .v-etapes { grid-template-columns: 1fr; gap: 32px; }
    .v-etape .v-etape-picto::after { display: none; }
}

/* ---------- Liste a puces cochees ---------- */
.v-liste-points { list-style: none; margin: 0; padding: 0; }
.v-liste-points li {
    display: flex; gap: 12px; align-items: flex-start; padding: 9px 0;
    font-size: 16.5px; color: var(--v-encre-doux);
}
.v-liste-points .v-check { color: #16a34a; }

/* Listing concis des modules : une ligne par module, prix aligne a droite. */
.v-modules-liste { border: 1px solid var(--v-bordure); border-radius: var(--v-rayon); overflow: hidden; background: #fff; }
.v-module-ligne {
    display: grid; grid-template-columns: 1fr auto; gap: 16px; align-items: center;
    padding: 15px 22px; text-decoration: none; color: inherit;
    border-top: 1px solid var(--v-bordure);
    transition: background .14s ease;
}
.v-module-ligne:first-child { border-top: 0; }
.v-module-ligne:hover { background: var(--v-fond-alt); }
.v-module-nom { font-weight: 600; font-size: 16px; color: var(--v-encre); }
.v-module-prix { font-weight: 700; font-size: 15.5px; color: var(--v-encre); white-space: nowrap; }
.v-module-prix small { display: block; font-weight: 500; font-size: 12.5px; color: var(--v-gris-clair); }

/* ---------- Bandeau d'appel ---------- */
.v-cta {
    background: linear-gradient(135deg, var(--v-bleu), var(--v-violet));
    color: #fff; border-radius: 26px; padding: clamp(44px, 6vw, 72px) 32px; text-align: center;
    /* Tilt au hover : le JS applique inline `transform: perspective(1200px)
       rotateX(±rx) rotateY(±ry)` selon la position souris. `will-change`
       pré-promeut sur le GPU, `transition` gère le retour doux à l'horizontale
       quand la souris quitte le bloc. Pas de perspective en CSS : elle est
       intégrée directement dans le transform inline (plus simple, autonome). */
    will-change: transform;
    transition: transform .35s cubic-bezier(.22, .61, .36, 1);
}
.v-cta h2 { color: #fff; }
.v-cta p { color: rgba(255, 255, 255, .86); font-size: 18px; max-width: 52ch; margin: 0 auto 30px; }
/* Note bas de CTA (astérisque, précisions légales, exceptions) — plus
   petite et plus discrète que le paragraphe principal. Placée SOUS le
   bouton, elle ne parasite pas la lecture du message principal. */
.v-cta-note {
    font-size: 12.5px !important; color: rgba(255, 255, 255, .55) !important;
    max-width: 68ch !important; margin: 22px auto 0 !important; line-height: 1.5;
}
/* Sup en (1) plutôt qu'astérisque : le chiffre est plus lisible en petit,
   la parenthèse guide l'oeil. `line-height: 0` empêche le sup d'écarter
   la ligne où il est posé (comportement par défaut du <sup>). */
.v-cta-note sup, .v-cta sup { font-size: 60%; line-height: 0; }
/* Ligne de réassurances sous le CTA : trois arguments séparés par des
   points médians, plus discrète que le paragraphe principal — enlève
   les dernières hésitations sans ajouter de bruit visuel. */
.v-cta-reassurances {
    font-size: 13.5px !important; color: rgba(255, 255, 255, .7) !important;
    margin: 22px auto 0 !important; letter-spacing: .01em; font-weight: 500;
}
/* « /mois » collé au montant, plus petit — hiérarchie visuelle claire :
   le nombre porte l'accroche, l'unité reste secondaire. */
.v-prix-unite-inline {
    font-size: .34em; font-weight: 600; opacity: .7; margin-left: 4px;
    letter-spacing: 0;
}

/* ---------- Contenu editorial (pages legales, a propos) ----------
   `.v-prose` est ENFANT de `.v-conteneur` (jamais la meme balise — voir
   CLAUDE.md §11 : sur le meme element ca ecraserait la mesure du conteneur).
   Largeur bornee a 1024 px (mesure de lecture confortable, ~85 caracteres
   par ligne) et ALIGNE A GAUCHE dans son conteneur pour que le texte suivi
   demarre au fer de la maquette, pas centre au milieu. */
.v-prose {
    max-width: 1024px;
    margin-right: auto;   /* margin-left par defaut 0 → alignement gauche */
}
/* Le premier élément d'un .v-prose ne doit jamais avoir de marge haute —
   la section parente porte déjà son propre padding vertical, une marge en
   plus créerait un vide inutile en tête de bloc. */
.v-prose > :first-child { margin-top: 0; }
.v-prose h2 { font-size: 26px; margin: 44px 0 14px; }
.v-prose h3 { margin: 30px 0 10px; }
/* Tirets plutot que pastilles : la puce ronde fait « liste a puces de
   presentation », le tiret cadratin reste dans le registre du texte suivi. */
.v-prose ul { list-style: none; padding-left: 0; margin: 0 0 18px; }
.v-prose li { margin-bottom: 8px; padding-left: 26px; position: relative; }
.v-prose li::before {
    content: "—"; position: absolute; left: 0; top: 0;
    color: var(--v-gris-clair); font-weight: 500;
}
.v-prose a { text-decoration-thickness: 1px; text-underline-offset: 3px; }

/* ---------- Lien texte en dégradé bleu → violet ----------
   Alternative aux boutons pleins pour les liens secondaires qui doivent
   quand même attirer l'œil. Texte en gras + gradient text + flèche solide.
   `background-clip: text` + `color: transparent` = la couleur du texte
   suit le dégradé. La flèche SVG utilise `currentColor` par défaut, on
   force sa `color` à --v-violet (fin du gradient) pour qu'elle reste
   visible (sinon `color: transparent` du parent la rendrait invisible). */
.v-lien-degrade {
    display: inline-flex; align-items: center; gap: 6px;
    text-decoration: none;
    font-weight: 700; font-size: 15.5px;
    /* Petit hover gap qui pousse la flèche vers la droite (~2px), rappel
       du pattern « lien-plus » côté site tenant. */
    transition: gap .18s ease;
}
.v-lien-degrade span {
    background: linear-gradient(90deg, var(--v-bleu), var(--v-violet));
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}
.v-lien-degrade svg {
    color: var(--v-violet);
    transition: transform .18s ease;
}
.v-lien-degrade:hover { gap: 10px; }
.v-lien-degrade:hover svg { transform: translateX(2px); }

/* ---------- FAQ (accordéon natif <details>) ----------
   Aucune dépendance JS : le comportement ouvrir/fermer est fourni par le
   navigateur, l'accessibilité clavier (Tab + Enter/Space) l'est aussi.
   Le chevron ▸ pivote à 90° via `[open]` — état déclaratif du <details>.
   La flèche par défaut du <summary> est masquée pour un rendu propre. */
.v-faq { margin: 0 auto 0 0; }
.v-faq-groupe {
    font-size: 12.5px; font-weight: 700; letter-spacing: .12em;
    text-transform: uppercase; color: var(--v-bleu);
    margin: 44px 0 14px; padding: 0;
}
.v-faq-groupe:first-child { margin-top: 0; }
.v-faq-item {
    border-bottom: 1px solid var(--v-bordure);
}
.v-faq-item:first-of-type { border-top: 1px solid var(--v-bordure); }
.v-faq-item summary {
    /* Retire le marker natif — style manuel via ::after ci-dessous. */
    list-style: none;
    cursor: pointer;
    padding: 22px 40px 22px 0;
    font-size: 17px; font-weight: 650; color: var(--v-encre);
    position: relative;
    line-height: 1.4;
    user-select: none;
    transition: color .15s ease;
}
.v-faq-item summary::-webkit-details-marker { display: none; }
.v-faq-item summary:hover { color: var(--v-bleu); }
.v-faq-item summary::after {
    /* Chevron dessiné en pur CSS (2 traits pivotés en +/-45°). Pivote de */
    /* -90° en état fermé à 0° (pointe vers le bas) en état ouvert. */
    content: "";
    position: absolute; right: 4px; top: 50%;
    width: 10px; height: 10px;
    border-right: 2px solid var(--v-gris);
    border-bottom: 2px solid var(--v-gris);
    transform: translateY(-70%) rotate(-45deg);
    transition: transform .2s ease, border-color .15s ease;
}
.v-faq-item[open] summary::after {
    transform: translateY(-50%) rotate(45deg);
    border-color: var(--v-bleu);
}
.v-faq-item[open] summary { color: var(--v-bleu); }
.v-faq-corps {
    padding: 0 40px 22px 0;
    font-size: 15.5px; color: var(--v-gris); line-height: 1.65;
}
.v-faq-corps p { margin: 0 0 12px; }
.v-faq-corps p:last-child { margin-bottom: 0; }
.v-faq-corps a { color: var(--v-bleu); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px; }
.v-faq-corps code {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 90%; background: var(--v-fond-alt); padding: 2px 6px;
    border-radius: 4px;
}

/* ---------- Page À propos : grille texte + encart ----------
   Grille asymétrique 2fr / 1fr : le texte long à gauche, un encart plus
   étroit à droite (chiffres clés, identité éditeur). Passe en 1 colonne
   sous 900 px pour rester lisible sur tablette et mobile. */
.v-grille-a-propos {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
    gap: 56px;
    align-items: start;
}
@media (max-width: 900px) {
    .v-grille-a-propos { grid-template-columns: 1fr; gap: 40px; }
}

/* Encart latéral — carte discrète, un ton en dessous des .v-carte
   principales pour ne pas concurrencer le contenu. `position: sticky`
   suit le scroll tant qu'on est dans sa section. */
.v-encart {
    background: var(--v-fond-alt);
    border: 1px solid var(--v-bordure);
    border-radius: var(--v-rayon);
    padding: 26px 26px 22px;
    position: sticky; top: 108px;   /* header 88 + marge 20 */
}
.v-encart-titre {
    margin: 0 0 18px; font-size: 12.5px; font-weight: 700;
    letter-spacing: .12em; text-transform: uppercase; color: var(--v-bleu);
}
.v-encart-note {
    margin: 18px 0 0; padding-top: 16px;
    border-top: 1px solid var(--v-bordure);
    font-size: 13.5px; color: var(--v-gris);
}

/* Liste de chiffres clés — chaque item = un gros nombre + son libellé
   court. Le nombre sert d'ancre visuelle, le libellé en petit dessous. */
.v-encart-chiffres { list-style: none; margin: 0; padding: 0; }
.v-encart-chiffres li {
    padding: 14px 0;
    border-bottom: 1px solid var(--v-bordure);
}
.v-encart-chiffres li:first-child { padding-top: 0; }
.v-encart-chiffres li:last-child  { padding-bottom: 0; border-bottom: 0; }
.v-encart-chiffres strong {
    display: block; font-size: 22px; font-weight: 800; color: var(--v-encre);
    letter-spacing: -.02em; margin-bottom: 3px;
}
.v-encart-chiffres span { font-size: 14px; color: var(--v-gris); line-height: 1.45; }

/* Liste ordonnée d'étapes pour un encart — chaque item porte un chiffre
   en gras et une brève description. Utilisé sur /essai/envoye. */
.v-encart-etapes { list-style: none; margin: 0; padding: 0; }
.v-encart-etapes li {
    padding: 10px 0; border-bottom: 1px solid var(--v-bordure);
    font-size: 14.5px; color: var(--v-encre); line-height: 1.5;
}
.v-encart-etapes li:first-child { padding-top: 0; }
.v-encart-etapes li:last-child  { padding-bottom: 0; border-bottom: 0; }
.v-encart-etapes li strong { display: inline-block; margin-right: 6px; color: var(--v-bleu); }

/* Liste de définition pour l'identité éditeur — 2 colonnes internes
   dt/dd, libellés à gauche en gris, valeurs à droite en encre. */
.v-encart-dl {
    display: grid;
    grid-template-columns: minmax(90px, auto) 1fr;
    row-gap: 10px; column-gap: 16px;
    margin: 0;
}
.v-encart-dl dt {
    font-size: 12.5px; color: var(--v-gris); font-weight: 600;
    text-transform: uppercase; letter-spacing: .06em;
    align-self: center;
}
.v-encart-dl dd {
    margin: 0; font-size: 14.5px; color: var(--v-encre); font-weight: 500;
    align-self: center; word-break: break-word;
}
.v-encart-dl dd a { color: var(--v-bleu); text-decoration: none; }
.v-encart-dl dd a:hover { text-decoration: underline; }

/* Liste à check ou à croix — utilisée dans les cartes « nos partis pris »
   et « nos non-choix ». Pastille colorée + icône Lucide (check ou x) dessinée
   via SVG data-URI en background composite. Même viewBox, même stroke-width,
   même taille pour les 2 variantes — cohérence visuelle garantie. */
.v-liste-check { list-style: none; margin: 6px 0 0; padding: 0; }
.v-liste-check li {
    /* Le texte s'aligne verticalement avec le TITRE de la carte au-dessus :
       46 px (picto titre) + 14 px (gap titre) = 60 px d'offset gauche.
       La pastille de la liste (22 px) est décalée pour être centrée sous
       le picto du titre (46 px / 2 = 23 px, pastille placée à left: 12 px
       pour un centre à 23 px). Le gap entre pastille et texte est donc
       plus généreux (~26 px), ce qui aère la lecture. */
    position: relative; padding: 0 0 16px 60px;
    font-size: 15.5px; color: var(--v-gris); line-height: 1.55;
}
.v-liste-check li:last-child { padding-bottom: 0; }
.v-liste-check li strong { display: block; color: var(--v-encre); margin-bottom: 4px; }
/* Pastille + icône combinées : le SVG (icône) est en background PREMIER
   (dessus), la couleur de fond DERRIÈRE. `top: 4px` cale visuellement la
   pastille sur la baseline de la première ligne du <strong>. */
.v-liste-check li::before {
    content: "";
    position: absolute; left: 12px; top: 4px;
    width: 22px; height: 22px; border-radius: 999px;
    background:
        url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2316a34a' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E")
        center / 12px no-repeat,
        rgba(34, 197, 94, .16);
}
/* Variante « non-choix » : pastille rouge + croix Lucide (même stroke-width
   que le check pour une identité visuelle homogène). */
.v-liste-check-non li::before {
    background:
        url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23dc2626' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'/%3E%3Cline x1='6' y1='6' x2='18' y2='18'/%3E%3C/svg%3E")
        center / 12px no-repeat,
        rgba(239, 68, 68, .14);
}

.v-page-entete { padding: clamp(56px, 7vw, 92px) 0 clamp(30px, 4vw, 46px); }
.v-page-entete p {
    font-size: 19px; color: var(--v-gris); margin: 0;
    max-width: 940px; text-wrap: balance;
}

.v-fil { display: flex; gap: 8px; align-items: center; margin-bottom: 18px; font-size: 14px; color: var(--v-gris-clair); }
.v-fil a { color: var(--v-gris); text-decoration: none; }
.v-fil a:hover { color: var(--v-bleu); }

/* ---------- Formulaire ---------- */
/* Aucune largeur propre : le formulaire remplit ce qui le contient — la colonne
   de gauche sur la page contact, la boite de dialogue dans la modale. Les deux
   sont deja bornes, une mesure ici ne ferait que les retrecir davantage. */
.v-form { display: grid; gap: 16px; }
.v-form-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.v-form label { display: block; font-weight: 600; font-size: 14.5px; margin-bottom: 7px; color: var(--v-encre); }
.v-form input, .v-form select, .v-form textarea {
    width: 100%; padding: 13px 15px; border: 1.5px solid var(--v-bordure);
    border-radius: var(--v-rayon-sm); font: inherit; font-size: 16px; background: #fff;
    color: var(--v-encre); transition: border-color .15s ease, box-shadow .15s ease;
}
.v-form input:focus, .v-form select:focus, .v-form textarea:focus {
    outline: none; border-color: var(--v-bleu); box-shadow: 0 0 0 4px rgba(37, 99, 235, .12);
}
/* Pas de poignee de redimensionnement : elle laisse l'utilisateur casser la
   mise en page du formulaire, pour un gain nul — le champ est deja assez haut. */
.v-form textarea { resize: none; min-height: 130px; }

/* La case a cocher doit rester SUR la ligne de son texte. Sans ces deux regles,
   `.v-form label` (0,1,1) l'emporte sur `.v-engagement` (0,1,0) et repasse le
   bloc en `display: block` — case empilee au-dessus du texte — pendant que
   `.v-form input`, declare plus bas a specificite egale, etire la case a
   100 % de large. Les deux corrections doivent donc vivre ici, apres le bloc. */
.v-form label.v-engagement {
    display: flex; gap: 11px; align-items: flex-start; margin-bottom: 0;
    font-size: 14px; line-height: 1.5; font-weight: 400; color: var(--v-gris);
}
.v-form .v-engagement input[type="checkbox"] {
    width: 17px; height: 17px; padding: 0; margin: 2px 0 0; flex: 0 0 auto;
    accent-color: var(--v-bleu);
}
.v-aide { font-size: 13.5px; color: var(--v-gris); margin: 6px 0 0; }
@media (max-width: 620px) { .v-form-2 { grid-template-columns: 1fr; } }

/* ---------- Pied de page ---------- */
.v-pied { background: var(--v-encre); color: rgba(255, 255, 255, .68); padding: 68px 0 34px; flex: 0 0 auto; }
.v-pied-grille { display: grid; grid-template-columns: 2fr 1fr 1fr 1fr; gap: 40px; }
.v-pied-marque img {
    height: 52px; filter: brightness(0) invert(1);
    /* Margin-top négatif = compense l'espace blanc intrinsèque au fichier
       SVG au-dessus du glyphe, pour aligner visuellement l'axe optique du
       logo avec les titres de colonnes du footer. */
    margin: -20px 0 12px;
}
.v-pied-marque p { font-size: 15px; margin: 0; text-wrap: balance; }
.v-pied h2 { font-size: 13px; text-transform: uppercase; letter-spacing: .1em; color: #fff; margin-bottom: 14px; }
.v-pied a { display: block; color: rgba(255, 255, 255, .68); text-decoration: none; font-size: 15px; padding: 5px 0; }
.v-pied a:hover { color: #fff; }
.v-pied-bas {
    display: flex; justify-content: space-between; flex-wrap: wrap; gap: 12px;
    margin-top: 48px; padding-top: 24px; font-size: 13.5px; color: rgba(255, 255, 255, .45);
    border-top: 1px solid rgba(255, 255, 255, .1);
}
@media (max-width: 860px) { .v-pied-grille { grid-template-columns: 1fr 1fr; } }
@media (max-width: 520px) { .v-pied-grille { grid-template-columns: 1fr; gap: 28px; } }

@media (prefers-reduced-motion: reduce) {
    * { animation: none !important; transition: none !important; scroll-behavior: auto !important; }
}

/* ==================================================================
   Bloc démo — cadre navigateur + preview 16/9 avec léger tilt.
   Placé sur la home vitrine juste avant le CTA final. L'inclinaison
   au repos donne une sensation « objet 3D » à peu de frais (aucun
   JS, aucune image transformée). Au hover, retour à plat + très
   légère mise à l'échelle : le visiteur sent que c'est interactif.
   `prefers-reduced-motion` neutralise l'ensemble.
   ================================================================== */
.v-demo-lien {
    display: block;
    max-width: 1080px;
    margin: 40px auto 0;
    text-decoration: none;
    color: inherit;
}
/* Le tilt est INTERACTIF (JS `appliquerTiltInverse` dans vitrine.js) — pas
   d'inclinaison au repos. Au repos, l'objet est à plat, propre, lisible ;
   au survol, il suit doucement la souris (mouvement inverse amorti par
   lerp). Approche identique au bloc `.v-cta`. Le `will-change` +
   `transition` sont posés pour que le retour à l'horizontale au
   mouseleave soit fluide. */
.v-demo-cadre {
    position: relative;
    background: #ffffff;
    border-radius: 14px;
    overflow: hidden;
    box-shadow:
        0 24px 50px -20px rgba(15, 23, 42, .28),
        0 10px 24px -10px rgba(15, 23, 42, .16),
        0 0 0 1px rgba(15, 23, 42, .06);
    will-change: transform;
    transition: transform .35s cubic-bezier(.22, .61, .36, 1),
                box-shadow .35s ease;
}
.v-demo-lien:hover .v-demo-cadre,
.v-demo-lien:focus-visible .v-demo-cadre {
    box-shadow:
        0 32px 70px -20px rgba(15, 23, 42, .34),
        0 14px 34px -10px rgba(15, 23, 42, .20),
        0 0 0 1px rgba(15, 23, 42, .08);
}

/* Barre navigateur imitant Safari/Chrome : 3 pastilles + URL centrée
   + petit indicateur de lien externe qui rappelle le CTA plus bas. */
.v-demo-barre {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 12px 16px;
    background: linear-gradient(to bottom, #f8fafc, #eef1f6);
    border-bottom: 1px solid rgba(15, 23, 42, .07);
    font-size: 13px;
    color: #64748b;
}
.v-demo-pt {
    width: 12px; height: 12px; border-radius: 50%;
    box-shadow: inset 0 -1px 1px rgba(0,0,0,.15);
    flex-shrink: 0;
}
.v-demo-pt-r { background: #ff5f57; }
.v-demo-pt-o { background: #febc2e; }
.v-demo-pt-v { background: #28c840; }
.v-demo-url {
    flex: 1;
    text-align: center;
    font-family: ui-monospace, "SF Mono", "Roboto Mono", monospace;
    font-size: 12.5px;
    letter-spacing: .01em;
    color: #475569;
}
.v-demo-lien-ico {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px; height: 22px;
    border-radius: 6px;
    color: #64748b;
    background: rgba(15, 23, 42, .05);
    transition: background .2s ease, color .2s ease;
}
.v-demo-lien:hover .v-demo-lien-ico,
.v-demo-lien:focus-visible .v-demo-lien-ico {
    background: rgba(37, 99, 235, .12);
    color: #2563eb;
}

/* Zone image : l'image conserve son ratio naturel — le container prend
   la hauteur qu'il faut. Aucun crop, aucune bande. Le dégradé de repli
   n'apparaît que si l'image est absente (404) : il est posé sur le
   container mais recouvert dès que l'image est chargée. */
.v-demo-visuel {
    background: linear-gradient(135deg, #eef2ff 0%, #e0e7ff 45%, #c7d2fe 100%);
    display: block;
    line-height: 0; /* évite l'espace baseline sous <img> inline-block */
}
.v-demo-visuel img {
    display: block;
    width: 100%;
    height: auto;   /* respecte le ratio de l'image source */
}
/* Message affiché si l'image est cassée — les navigateurs modernes
   affichent l'alt-text sur fond gris. On adoucit avec un peu de
   padding pour que ça reste lisible. */
.v-demo-visuel img[alt] { color: #64748b; padding: 16px; }

/* Responsive : réduit la marge haute et l'URL en petit. Le tilt JS est
   automatiquement désactivé sur pointeur imprécis (mobile) via la
   media query `(hover: hover) and (pointer: fine)` dans vitrine.js. */
@media (max-width: 640px) {
    .v-demo-lien { margin-top: 24px; }
    .v-demo-url { font-size: 11.5px; }
}
