/* ==========================================================================
   FEUILLE DE STYLE UNIQUE — réutilisable sur toutes les verticales
   Pour changer de verticale : modifier uniquement les 2 variables --brand
   et --accent ci-dessous. Tout le reste est générique.
   ========================================================================== */

:root{
  /* --- À PERSONNALISER PAR VERTICALE --------------------------------- */
  --brand:        #0f2c47;   /* couleur principale (titres, header, footer) */
  --brand-hover:  #18405f;
  /* RÈGLE DE CONTRASTE — relire avant de changer ces trois valeurs.
     --accent ne sert QUE de couleur de trait : flèches, puces, filets,
     bordures, le « .fr » du logo, le surtitre du hero. Du blanc posé
     dessus ne donne que 3,41:1, sous le minimum AA de 4,5:1.
     Dès qu'une surface pleine porte du texte blanc — bouton, pastille
     numérotée — c'est --accent-hover (5,00:1), et --accent-shadow pour
     son survol (7,49:1). Corrigé le 07/11/2026 : le bouton principal du
     site et les pastilles des étapes échouaient tous les deux. */
  --accent:       #c8781a;   /* TRAIT seulement, jamais sous du blanc */
  --accent-hover: #a35f0d;   /* surfaces pleines à texte blanc */
  --accent-shadow:#7d4809;   /* survol de ces surfaces, et ombre portée */
  --accent-soft:  #fdf6ec;   /* fond des encadrés d'alerte */
  --accent-line:  #f0dcc0;

  /* --- GÉNÉRIQUE : ne pas toucher ------------------------------------ */
  --ink:    #16202b;
  --muted:  #5b6b7c;
  --line:   #e2e8ee;
  --bg:     #fbfcfd;
  --soft:   #f2f6fa;
  --white:  #ffffff;

  --radius: 9px;
  --maxw:   760px;
}

/* ---------- RESET ---------- */
*{box-sizing:border-box;margin:0;padding:0}
img{max-width:100%;height:auto;display:block}

html{scroll-behavior:smooth}
body{
  font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Inter,Roboto,Helvetica,sans-serif;
  color:var(--ink);
  background:var(--bg);
  line-height:1.65;
  font-size:17px;
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
}

.wrap{max-width:var(--maxw);margin:0 auto;padding:0 22px}

/* ==========================================================================
   BLOC : HEADER
   ========================================================================== */
.site-header{
  background:var(--white);
  border-bottom:1px solid var(--line);
  position:sticky;top:0;z-index:50;
}
.site-header .wrap{
  display:flex;align-items:center;justify-content:space-between;height:62px;
}
.logo{
  font-weight:700;font-size:17px;color:var(--brand);
  letter-spacing:-.3px;text-decoration:none;
}
/* Le « .fr » du logo reste en --accent (3,41:1 sur blanc) et c'est VOULU :
   les WCAG exemptent explicitement le texte qui fait partie d'un logo ou
   d'une marque. Un balayage de contraste le signalera à chaque fois — c'est
   le seul point du site à ignorer, et la seule exception. */
.logo span{color:var(--accent)}
.header-cta{
  background:var(--brand);color:var(--white);text-decoration:none;
  font-size:13.5px;font-weight:600;padding:9px 16px;border-radius:6px;
  transition:background .15s;
}
.header-cta:hover{background:var(--brand-hover)}

/* ==========================================================================
   BLOC : FIL D'ARIANE
   ========================================================================== */
.breadcrumb{
  font-size:13px;color:var(--muted);padding:14px 0 0;
}
.breadcrumb a{color:var(--muted);text-decoration:none}
.breadcrumb a:hover{text-decoration:underline}
.breadcrumb span{margin:0 7px;opacity:.5}

/* ==========================================================================
   BLOC : HERO (haut de page)
   ========================================================================== */
/* --- Fond photographique du hero -----------------------------------------
   Une caméra de local professionnel, sous charpente métallique : la photo est
   dans les gris froids de la charte, donc le voile n'a presque rien à
   corriger. Deux poids seulement (800 px / 1600 px) : au-delà, le voile
   masque de toute façon le détail. Le contraste du texte est tenu par le
   dégradé ::before, jamais par la photo — c'est lui qu'on règle si le
   recadrage change. */
.hero,
.hero-home{
  position:relative;
  color:var(--white);
  border:0;
  background:var(--brand)
    url(/assets/img/camera-surveillance-local-professionnel-800.webp)
    center/cover no-repeat;
}
@media(min-width:700px){
  .hero,
  .hero-home{
    background-image:url(/assets/img/camera-surveillance-local-professionnel-1600.webp);
  }
}
.hero::before,
.hero-home::before{
  content:"";position:absolute;inset:0;
  background:linear-gradient(90deg,
    rgba(15,44,71,.90) 0%,
    rgba(15,44,71,.82) 46%,
    rgba(15,44,71,.52) 100%);
}
/* Sur les pages sans carte de formulaire, le texte occupe toute la largeur :
   il passe donc devant le sujet de la photo et le voile doit rester dense
   jusqu'au bord droit. */
.hero:not(:has(.hero-grid))::before{
  background:linear-gradient(90deg,
    rgba(15,44,71,.93) 0%,
    rgba(15,44,71,.90) 55%,
    rgba(15,44,71,.76) 100%);
}
/* Le contenu repasse au-dessus du voile. */
.hero>.wrap,
.hero-home>.wrap{position:relative}

.hero{padding:30px 0 40px}

/* Déclinaisons claires des éléments du hero, qui sont sur fond sombre. */
.hero h1{color:var(--white)}
.hero .lede{color:#cfdded}
.hero .kicker{color:#e0a964}
.hero .breadcrumb,
.hero .breadcrumb a{color:#a9bfd2}
.hero .breadcrumb{padding:16px 0 10px}
.hero .page-meta{color:#9fb5c8;border-top-color:rgba(255,255,255,.24)}
.hero .author{color:#a9bfd2}
.hero .author b{color:var(--white)}
/* Le lien de ce bloc sortait en #0000EE — le bleu par défaut du navigateur —
   sur le fond bleu nuit, soit 1,52:1. Illisible, sur 25 pages, depuis
   toujours. La cause : la seule règle de couleur des liens est `main a`, et
   le bloc auteur est dans le hero, pas dans main. Personne ne le voyait
   parce qu'un bleu sur un bleu ne saute pas aux yeux — il disparaît. */
.hero .author a{color:var(--white);text-decoration:underline;text-underline-offset:2px}
.hero .author .avatar{border-color:rgba(255,255,255,.34);background-color:rgba(255,255,255,.12)}
/* La carte du formulaire est le seul élément clair : l'ombre portée la
   décolle du fond au lieu de la poser dessus. */
.hero .embed-hero,
.hero-home .embed-hero{
  background:var(--white);border-color:#cfd9e3;
  box-shadow:0 18px 44px -22px rgba(0,0,0,.65);
}
.kicker{
  font-size:12px;font-weight:700;letter-spacing:.9px;text-transform:uppercase;
  color:var(--accent);margin-bottom:14px;
}
h1{
  font-size:35px;line-height:1.22;letter-spacing:-.8px;
  color:var(--brand);margin-bottom:16px;font-weight:720;
}
.lede{font-size:18.5px;color:var(--muted);margin-bottom:26px}

/* --- Hero à deux colonnes : article à gauche, formulaire à droite ---------
   Le formulaire doit être visible sans défiler : c'est ce qui sépare une page
   qui informe d'une page qui capte. En dessous de 1000 px il repasse sous le
   texte, car une colonne de 380 px ne tient pas à côté d'un h1. */
.hero-grid{display:grid;gap:30px;align-items:start}
@media(min-width:1000px){
  /* Le hero sort de la largeur de lecture de l'article : il faut la place
     du formulaire sans écraser le h1. L'article, lui, reste étroit. */
  .hero .wrap,
  .hero-home .wrap,
  .site-header .wrap,
  .site-footer .wrap{max-width:1100px}
  .hero-grid{grid-template-columns:minmax(0,1fr) 384px;gap:52px}
  .hero-main{min-width:0}
}
.hero-form{min-width:0}
/* Variante compacte du bloc .embed quand il est dans le hero. */
.embed.embed-hero{margin:0;padding:20px}
.embed.embed-hero h3{font-size:17px}
.embed.embed-hero .embed-s{font-size:13.5px;margin-bottom:14px}
.embed.embed-hero .embed-frame,
.embed.embed-hero .embed-frame iframe{min-height:430px;height:430px}
.embed.embed-hero .embed-legal{font-size:12px}
/* Le formulaire du partenaire empile ses champs sur un téléphone : il lui
   faut plus de hauteur, pas moins. La maquette, elle, est déjà empilée — lui
   réserver la même place la ferait occuper un écran entier sans rien montrer
   de plus. La réserve ne vise donc que l'iframe réellement chargée. */
@media(max-width:700px){
  .embed.embed-hero .embed-frame:has(iframe[src]),
  .embed.embed-hero .embed-frame iframe[src]{min-height:470px;height:470px}
}
.page-meta{
  font-size:13px;color:var(--muted);
  padding-top:18px;border-top:1px solid var(--line);
}

/* ==========================================================================
   TYPOGRAPHIE DE CONTENU
   ========================================================================== */
main{padding:38px 0 10px}
h2{
  font-size:25px;color:var(--brand);margin:46px 0 14px;
  letter-spacing:-.5px;font-weight:700;line-height:1.3;
}
h3{font-size:18.5px;color:var(--brand);margin:28px 0 10px;font-weight:650}
p{margin-bottom:16px}
ul,ol{margin:0 0 18px 20px}
li{margin-bottom:9px}
strong{font-weight:650;color:var(--ink)}
main a{color:var(--brand);text-decoration:underline;text-underline-offset:2px}
.note{font-size:14.5px;color:var(--muted)}

/* ==========================================================================
   BLOC : ENCADRÉ RÉPONSE  (« L'essentiel »)
   Toujours placé juste après le hero. Capte les featured snippets.
   ========================================================================== */
.answer-box{
  background:var(--soft);border-left:3px solid var(--brand);
  padding:20px 24px;border-radius:0 var(--radius) var(--radius) 0;margin:28px 0;
}
.answer-box .label{
  font-size:12px;font-weight:700;letter-spacing:.8px;text-transform:uppercase;
  color:var(--brand);margin-bottom:9px;
}
.answer-box p:last-child{margin-bottom:0}

/* L'essentiel était un paragraphe de cinq lignes : la forme contredisait le
   titre, puisqu'il fallait tout lire pour savoir ce qu'il contenait. En liste,
   chaque point se saisit seul et le lecteur s'arrête dès qu'il a sa réponse.
   Le gras en tête de puce porte l'information ; ce qui suit la justifie, et
   peut être sauté. */
.answer-box ul{list-style:none;margin:0;padding:0}
.answer-box li{
  position:relative;padding-left:18px;margin-bottom:10px;
  font-size:15.5px;line-height:1.55;
}
.answer-box li:last-child{margin-bottom:0}
.answer-box li::before{
  content:"";position:absolute;left:0;top:.62em;
  width:6px;height:6px;border-radius:50%;background:var(--brand);
}
.answer-box li b{font-weight:650}

/* Le chiffre vérifié vient après les puces, pas avant : il appuie le propos,
   il ne le remplace pas — une page qui ouvre sur une statistique nationale
   répond à une question que le lecteur ne s'est pas posée. La source est dans
   le bloc et non en note : un chiffre dont il faut chercher l'origine ne se
   vérifie pas, donc ne vaut rien. */
.answer-box .chiffre{
  margin:14px 0 0;padding-top:13px;border-top:1px solid var(--line);
  font-size:15px;line-height:1.5;
}
.answer-box .chiffre b{
  font-size:19px;font-weight:700;color:var(--brand);
  margin-right:2px;white-space:nowrap;
}
.answer-box .chiffre span{
  display:block;margin-top:5px;
  font-size:13px;line-height:1.45;color:var(--muted);
}

/* ==========================================================================
   BLOC : ENCADRÉ D'ALERTE  (argument de conversion fort)
   ========================================================================== */
.callout{
  background:var(--accent-soft);border:1px solid var(--accent-line);
  border-radius:var(--radius);padding:20px 24px;margin:26px 0;
}
.callout .label{font-weight:700;color:var(--accent-hover);margin-bottom:8px;font-size:15.5px}
.callout p{font-size:15.5px}
.callout p:last-child{margin-bottom:0}

/* Variante neutre */
.callout.neutral{background:var(--soft);border-color:var(--line)}
.callout.neutral .label{color:var(--brand)}

/* ==========================================================================
   BLOC : TABLEAU
   ========================================================================== */
.table-wrap{overflow-x:auto;margin:22px 0;-webkit-overflow-scrolling:touch}
table{
  width:100%;border-collapse:collapse;font-size:15px;background:var(--white);
  border:1px solid var(--line);border-radius:var(--radius);overflow:hidden;
}
th{
  background:var(--brand);color:var(--white);text-align:left;padding:12px 14px;
  font-weight:600;font-size:13.5px;letter-spacing:.2px;
}
td{padding:12px 14px;border-top:1px solid var(--line);vertical-align:top}
tbody tr:nth-child(even){background:#fafcfd}
td .sub{color:var(--muted);font-size:13.5px;display:block}
.price{font-weight:650;color:var(--brand);white-space:nowrap}

/* --- Les tableaux sur un téléphone ---------------------------------------
   .table-wrap sait défiler horizontalement, mais rien ne dit au lecteur
   qu'il le peut : sur un écran de 375 px, le tableau des sanctions sortait
   du cadre à « jusqu'à 5 ans et 300 000 » — le montant coupé net, sans la
   moindre ombre ni flèche pour l'annoncer. Un chiffre à moitié affiché sur
   une page de droit est pire qu'un chiffre absent.
   La cause tenait surtout à .price : white-space:nowrap protège bien un
   montant (« 2 500 € » ne doit pas se couper entre le nombre et l'unité),
   mais il est posé ici sur des phrases entières — « jusqu'à 20 M€ ou 4 % du
   CA mondial » — qu'il rendait insécables sur 293 px. On le relâche sur
   mobile, on resserre la typographie, et on autorise la coupure des mots que
   la colonne ne peut pas contenir.
   La coupure est confiée à hyphens:auto, qui suit les règles françaises
   grâce au lang="fr" de la page, et non à overflow-wrap:anywhere — essayé
   d'abord, il coupait « sous conditions » en « conditi / ons » et « en
   principe » en « princip / e », parce qu'il autorise la rupture après
   n'importe quelle lettre. break-word ne coupe que le mot qui, seul, ne
   tient pas dans sa colonne.
   Mesuré après coup : les 50 tableaux du site tiennent entièrement à 320 px
   comme à 375 px. Le défilement reste possible, il n'est simplement plus
   nécessaire — c'est pourquoi aucun indicateur de défilement n'est ajouté. */
@media(max-width:700px){
  .table-wrap table{font-size:13.5px}
  .table-wrap th,
  .table-wrap td{padding:9px 10px;overflow-wrap:break-word;hyphens:auto}
  .table-wrap .price{white-space:normal}
}

/* ==========================================================================
   BLOC : LISTE À COCHES  (checklist, critères, questions à poser)
   ========================================================================== */
.checklist{list-style:none;margin-left:0}
.checklist li{padding-left:34px;position:relative;margin-bottom:16px}
.checklist li::before{
  content:"";position:absolute;left:0;top:4px;width:21px;height:21px;
  background:var(--brand);border-radius:50%;
}
.checklist li::after{
  content:"";position:absolute;left:7px;top:11px;width:7px;height:3.5px;
  border-left:2px solid var(--white);border-bottom:2px solid var(--white);
  transform:rotate(-45deg);
}
.checklist li b{display:block;color:var(--brand);margin-bottom:2px}

/* ==========================================================================
   BLOC : ÉTAPES NUMÉROTÉES
   ========================================================================== */
.steps{list-style:none;margin-left:0;counter-reset:step}
/* Tolère les deux écritures : <ol class="steps"> ou <div class="steps"><ol> */
.steps ol,.steps ul{list-style:none;margin:0;padding-left:0}
.steps li{padding-left:44px;position:relative;margin-bottom:20px}
.steps li::before{
  counter-increment:step;content:counter(step);
  position:absolute;left:0;top:1px;width:28px;height:28px;
  background:var(--brand);color:var(--white);border-radius:50%;
  font-size:14px;font-weight:700;display:flex;align-items:center;justify-content:center;
}
.steps li b{display:block;color:var(--brand);margin-bottom:2px}

/* ==========================================================================
   BLOC : APPEL À L'ACTION
   Le href pointe vers le formulaire du partenaire. JAMAIS de formulaire ici.
   ========================================================================== */
.cta{
  background:linear-gradient(180deg,var(--white) 0%,var(--soft) 100%);
  border:1px solid var(--line);border-radius:var(--radius);
  padding:26px;margin:34px 0;text-align:center;
  box-shadow:0 1px 3px rgba(15,44,71,.05);
}
.cta h3{font-size:19px;color:var(--brand);margin:0 0 8px;letter-spacing:-.3px}

/* ==========================================================================
   BLOC : RENVOI VERS LE FORMULAIRE DU PARTENAIRE
   Ce bloc ne contient AUCUN champ de saisie et n'en contiendra pas : le
   contrat l'interdit sur ce site. Il décrit le parcours et renvoie, par un
   lien interne, à /demande-de-devis/ — la seule page où le script du
   partenaire construit son questionnaire. Ne jamais le remplacer par un
   formulaire local, même provisoire.

   Il n'y a plus d'iframe ici depuis le 07/11/2026 : les 29 qui attendaient
   une URL d'intégration ont été retirées, cette URL n'ayant plus d'objet.
   Les sélecteurs `:not(:has(iframe[src]))` plus bas sont donc toujours
   vrais. Ils sont CONSERVÉS À DESSEIN : leur `:has()` pèse dans la
   spécificité, et les simplifier changerait l'ordre du cascade pour gagner
   deux cents octets. Ne pas « nettoyer » sans revérifier le rendu.
   ========================================================================== */
.embed{
  border:1px solid var(--line);border-radius:var(--radius);
  background:linear-gradient(180deg,var(--white) 0%,var(--soft) 100%);
  padding:26px;margin:34px 0;box-shadow:0 1px 3px rgba(15,44,71,.05);
}
.embed h3{font-size:19px;color:var(--brand);margin:0 0 8px;letter-spacing:-.3px}
.embed .embed-s{font-size:14.5px;color:var(--muted);margin:0 0 18px}
.embed-frame{
  position:relative;min-height:560px;border-radius:7px;overflow:hidden;
  background:var(--white);border:1px dashed var(--line);
}
/* Libellé de réservation : visible seulement tant que l'iframe est vide. */
.embed-frame::before{
  content:"Emplacement réservé au formulaire du partenaire";
  position:absolute;inset:0;display:flex;align-items:center;
  justify-content:center;text-align:center;padding:0 24px;
  font-size:14px;color:var(--muted);
}
.embed-frame iframe{
  position:relative;display:block;width:100%;height:560px;border:0;
  background:var(--white);
}
/* Tant que l'URL du partenaire n'est pas renseignée, l'attribut reste
   data-src : le navigateur ne charge rien et le libellé de réservation
   reste lisible. À réception du kit : renommer data-src en src. */
.embed-frame iframe:not([src]){display:none}

/* --- Maquette du formulaire ----------------------------------------------
   Aperçu de ce que l'emplacement contiendra. Dessinée en <div> : l'article
   6.1 interdit <form>, <input>, <select> et <textarea> sur ce domaine, et
   l'interdiction ne connaît pas d'exception « provisoire » — un validateur
   qui passe pendant la recette ne fait pas la différence entre une maquette
   et un vrai formulaire. Rien n'est donc saisissable ici : aucun champ ne
   prend le focus, aucune donnée ne peut partir.
   À réception du kit : renommer data-src en src, la maquette disparaît
   d'elle-même (règle :has ci-dessous), puis supprimer le bloc .mock. */
.embed-frame:has(.mock)::before{content:none}

/* Le cadre ne réserve plus 430 px (560 hors hero) quand il contient le bloc
   d'étapes : cette hauteur était une place gardée pour l'iframe, et l'iframe
   a disparu le 07/11/2026. Mesuré sur grand écran : le contenu occupait
   372 px dans 430, soit 58 px de vide qui repoussaient le bouton d'autant,
   sur 29 pages. Le `.mock` repasse donc en flux normal et le cadre prend
   exactement la taille de ce qu'il contient.

   La règle est volontairement conditionnée à `:has(.mock)`. Sur
   /demande-de-devis/, le cadre est vide au chargement et sa réserve sert à
   autre chose : empêcher la page de sauter quand le questionnaire du
   partenaire s'y insère. Elle doit y rester. */
.embed-frame:has(.mock),
.embed.embed-hero .embed-frame:has(.mock){min-height:0;height:auto}
.embed-frame:has(.mock) .mock{position:static}
.embed-frame:has(iframe[src]) .mock{display:none}
.mock{
  position:absolute;inset:0;display:flex;flex-direction:column;
  justify-content:center;padding:20px;gap:11px;
}
.mock-step{
  font-size:11.5px;font-weight:700;letter-spacing:.6px;text-transform:uppercase;
  /* --accent-hover, pas --accent : 11,5 px d'orange clair sur le fond blanc
     du cadre ne donnaient que 3,41:1. C'est la même règle que pour les
     boutons — l'orange clair ne sert que de trait. */
  color:var(--accent-hover);margin:0;
}
.mock-step span{color:var(--muted);font-weight:600;letter-spacing:0;text-transform:none}
/* Les faux champs (.mock-field, .mock-box, .mock-cta) ont été retirés le
   07/11/2026. Aucune page, aucun gabarit et aucun script ne les produisait
   plus : un champ qui ressemble à un champ mais n'accepte rien est une
   impasse, et le bloc décrit désormais le parcours en clair. */
.mock-note{font-size:11.5px;color:var(--muted);text-align:center;margin:0}/* --muted, pas #9aa8b5 : ce gris-la tombait a 2,43:1 sur le fond blanc du
   cadre, sous le minimum AA de 4,5:1 — pour la seule ligne qui promet au
   visiteur qu'on ne revend pas ses donnees. --muted donne 5,47:1. */

/* Les trois étapes du parcours, à la place de la maquette de formulaire.
   Un faux champ promet une saisie qui n'aboutit pas ; une liste numérotée
   dit la même chose sans mentir, et un moteur peut la citer. */
.etapes{
  margin:0;padding:0;list-style:none;counter-reset:etape;
  display:flex;flex-direction:column;gap:11px;
}
.etapes li{
  position:relative;padding-left:30px;font-size:13.5px;line-height:1.45;
  color:var(--muted);
}
.etapes li::before{
  counter-increment:etape;content:counter(etape);
  position:absolute;left:0;top:1px;width:20px;height:20px;border-radius:50%;
  background:var(--accent-hover);color:var(--white);
  font-size:11.5px;font-weight:700;line-height:20px;text-align:center;
}
.etapes b{color:var(--brand);font-weight:650}

/* --- Le parcours de devis, en mode essai ---------------------------------
   Le fichier `_mode-essai` à la racine suspend l'article 6.1 le temps
   d'éprouver l'ergonomie de la saisie — ce que la maquette ci-dessus, par
   construction, ne permet pas : on ne mesure pas un formulaire qu'on ne peut
   pas remplir. `python3 _formulaire.py --retirer` remet l'état contractuel.

   Toutes les règles qui suivent sont conditionnées par :has(form.parcours) ou
   descendent de .parcours. Le jour où le formulaire cède la place à l'iframe
   du partenaire, aucune ne s'applique plus : il n'y a rien à se souvenir de
   retirer, et le style de la maquette reprend seul. C'est le même principe
   que les règles mobiles plus bas, et pour la même raison — ce qui dépend
   d'un nettoyage manuel finit par ne pas être nettoyé. */
.embed.embed-hero .embed-frame:has(form.parcours),
.embed-frame:has(form.parcours){min-height:0;height:auto;border-style:solid}
/* Le cadre n'est plus « réservé » : il est occupé. */
.embed-frame:has(form.parcours)::before{content:none}
/* Le bouton de repli doublait le bouton du formulaire : deux appels à
   l'action pour la même demande, à trois centimètres l'un de l'autre. Tant
   qu'un vrai formulaire est là, c'est lui le chemin ; le repli reparaît de
   lui-même quand l'iframe prendra la place. */
.embed-frame:has(form.parcours) ~ .embed-fallback{display:none}

.parcours{display:flex;flex-direction:column;padding:18px}
.parcours fieldset{border:0;padding:0;margin:0;display:flex;flex-direction:column;gap:11px}
/* Le display:flex ci-dessus écrase le display:none que le navigateur applique
   à [hidden] : sans cette règle, les trois étapes s'empilent à l'écran. */
.parcours fieldset[hidden]{display:none}
.parcours label{display:flex;flex-direction:column;gap:5px}
.parcours label>b{font-size:13px;font-weight:650;color:var(--brand)}
.parcours input,
.parcours select{
  font-weight:400;font-size:15px;line-height:1.3;font-family:inherit;color:var(--ink);
  border:1px solid var(--line);border-radius:6px;
  background:var(--white);padding:11px 13px;width:100%;
  -webkit-appearance:none;appearance:none;
}
.parcours select{
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'><path d='M1 1l5 5 5-5' fill='none' stroke='%239aa8b5' stroke-width='2'/></svg>");
  background-repeat:no-repeat;background-position:right 13px center;background-size:11px;
  padding-right:34px;
}
.parcours input:focus,
.parcours select:focus{outline:2px solid var(--accent);outline-offset:1px;border-color:var(--accent)}
/* Le formulaire porte novalidate, et le rouge est posé par aria-invalid et
   non par :user-invalid. Les trois étapes coexistent dans le document, et une
   étape masquée reste soumise à la validation native : le navigateur refusait
   d'envoyer l'étape 1 à cause d'un champ requis de l'étape 2, qu'il ne
   pouvait ni afficher ni mettre en focus — refus silencieux, donc bouton mort
   sans explication. La validation est faite en JavaScript, étape par étape. */
.parcours [aria-invalid="true"]{border-color:#b91c1c}
.parcours .cases{display:flex;flex-direction:column;gap:7px}
.parcours .cases>b{font-size:13px;font-weight:650;color:var(--brand)}
.parcours .cases span{display:flex;align-items:center;gap:9px;font-size:14px;color:var(--ink)}
.parcours .cases label{display:inline;font-size:14px}
.parcours .cases input{width:auto;margin:0;-webkit-appearance:checkbox;appearance:checkbox}
.parcours button[type=submit],
.parcours .retour{
  font-weight:650;font-size:15px;line-height:1;font-family:inherit;cursor:pointer;border-radius:7px;padding:13px;
  border:1px solid transparent;width:100%;
}
.parcours button[type=submit]{background:var(--accent-hover);color:var(--white);margin-top:3px}
.parcours button[type=submit]:hover{filter:brightness(1.07)}
.parcours .retour{background:none;color:var(--muted);border:0;padding:4px;font-weight:600}
.parcours .erreur{
  background:#fef2f2;border:1px solid #fecaca;color:#991b1b;
  border-radius:6px;padding:9px 11px;font-size:13px;margin:0;
}
.parcours .fin{text-align:center}
.parcours .fin .coche{
  width:46px;height:46px;border-radius:50%;background:#dcfce7;color:#15803d;
  display:flex;align-items:center;justify-content:center;font-size:24px;
  margin:0 auto 14px;
}
.parcours .fin h4{font-size:17px;color:var(--brand);margin:0 0 8px}
.parcours .fin p{font-size:14px;color:var(--muted);margin:0 0 6px}
.parcours .fin dl{
  text-align:left;background:var(--soft);border:1px solid var(--line);
  border-radius:6px;padding:12px;margin:14px 0 0;font-size:13px;
}
/* dt flottant plutôt qu'une grille : le libellé et sa valeur restent sur la
   même ligne, et une valeur longue passe à la ligne sous elle-même au lieu
   de décaler la colonne de gauche. */
.parcours .fin dt{color:var(--muted);float:left;clear:left;width:46%}
.parcours .fin dd{color:var(--ink);margin:0 0 4px;font-weight:600;overflow:hidden}

.embed-fallback{text-align:center;margin:18px 0 0}
/* .reassurance n'a pas de couleur à elle : elle hérite. Dans le hero elle
   héritait du blanc prévu pour le fond sombre — et se retrouvait donc en
   blanc sur la carte blanche du bloc .embed, invisible, laissant 54 px de
   vide sous le bouton. Elle est ici recolorée comme dans un bloc .cta, qui
   est le même fond clair. */
.embed-fallback .reassurance{font-size:12.5px;color:var(--muted);margin:13px 0 0}
.embed-legal{font-size:12.5px;color:var(--muted);margin:14px 0 0;text-align:center}
@media(max-width:700px){
  .embed{padding:20px 16px}
  .embed-frame:has(iframe[src]),
  .embed-frame iframe[src]{min-height:640px;height:640px}
}

/* --- La maquette sur un téléphone ----------------------------------------
   Mesuré sur un écran de 375 × 812 : le bloc .embed du hero faisait 915 px
   de haut — plus d'un écran entier — dont 470 px de maquette. Le lecteur
   ouvrait donc la page sur un formulaire grisé qu'il ne peut pas remplir,
   le seul bouton qui marche restant sous la ligne de flottaison.
   La maquette ne sert qu'à montrer la forme de ce qui viendra ; elle n'a pas
   besoin de la taille d'un vrai formulaire pour le faire. Elle est donc
   resserrée ici, et seulement ici : au-dessus de 700 px l'écran est assez
   haut pour qu'elle ne coûte rien.
   Les sélecteurs portent sur :not(:has(iframe[src])) et non sur .mock : le
   jour où l'URL du partenaire arrive, la règle cesse d'elle-même de
   s'appliquer, sans qu'on ait à se souvenir de la retirer.
   La hauteur est laissée au contenu plutôt que fixée en pixels : la maquette
   sort de son calque absolu et le cadre fait exactement sa taille. Un cadre
   chiffré se règle à deux pixels près, puis se dérègle à la première police
   qui rend autrement — celui-ci n'a rien à régler. */
@media(max-width:700px){
  .embed-frame:not(:has(iframe[src])),
  .embed.embed-hero .embed-frame:not(:has(iframe[src])){
    min-height:0;height:auto;
  }
  .embed-frame:not(:has(iframe[src])) .mock{position:static}
  .mock{padding:14px;gap:8px}
  .mock-step{font-size:10.5px;letter-spacing:.5px}
  .mock-note{font-size:11px;line-height:1.35}

  /* --- Le bouton avant l'explication, sur petit écran seulement ---------
     Mesuré sur l'accueil à 390 px : la carte de devis occupait 830 px et
     son bouton commençait à 1 000 px du haut. Sur un téléphone dont la
     zone visible fait 650 à 700 px, il fallait donc défiler plus d'un
     écran entier — passé le titre, la phrase d'accroche et les trois
     étapes — avant de pouvoir agir. Celui qui était déjà décidé devait
     lire pour trouver le bouton.

     On inverse donc deux blocs : le bouton remonte juste sous la phrase
     d'accroche, les trois étapes passent dessous. Rien n'est retiré ni
     masqué, et l'ordre du document ne bouge pas — c'est de l'ordre
     visuel. Le texte y gagne même en logique : « ce qui se passe quand
     vous cliquez » se lit mieux après le bouton qu'avant.

     Sur grand écran la carte tient dans la colonne de droite sans défiler
     du tout : la règle ne s'y applique pas, et l'ordre de lecture normal
     — on explique, puis on propose — y est conservé. */
  .embed.embed-hero{display:flex;flex-direction:column}
  .embed.embed-hero .embed-frame{order:1}
  .embed.embed-hero .embed-legal{order:2}

  /* Le parcours, lui, se resserre sans se rétrécir : la taille des champs ne
     descend pas sous 15 px. En dessous, iOS zoome de lui-même sur le champ
     au moment du focus, décale la page et ne la remet pas — on gagnerait
     quelques pixels de hauteur pour perdre le fil de la saisie. */
  .parcours{padding:14px}
  .parcours fieldset{gap:9px}
  .parcours label>b{font-size:12.5px}
  .parcours input,
  .parcours select{padding:10px 12px}
  .parcours button[type=submit]{padding:12px}
  .parcours .fin dt{float:none;width:auto;margin-top:6px}
  .parcours .fin dd{margin:0}
}

.cta p{font-size:14.5px;color:var(--muted);margin-bottom:18px}
.btn{
  display:inline-block;background:var(--accent-hover);color:var(--white);
  text-decoration:none;font-weight:650;font-size:16px;padding:14px 30px;
  border-radius:7px;box-shadow:0 2px 0 var(--accent-shadow);
  transition:background .15s,transform .08s;
}
.btn:hover{background:var(--accent-shadow)}
.btn:active{transform:translateY(1px);box-shadow:0 1px 0 var(--accent-shadow)}

/* Barre de devis fixe en bas d'écran, sur téléphone et tablette (09/11/2026,
   demandée par Alexandre, comme celle de prestalgo.fr). Sans JavaScript :
   les pages de contenu n'en exécutent aucun. Elle reste donc affichée en
   permanence sous 1000 px, et le pied de page reçoit la marge qui l'empêche
   de cacher ses derniers liens. Classe « barre-devis » et non « cta-… » :
   le contrôle 11 de _audit.py compte les class="cta, elle fausserait le
   compte. Absente de /demande-de-devis/, où elle renverrait sur elle-même. */
.barre-devis{display:none}
@media(max-width:999.98px){
  .barre-devis{
    position:fixed;left:12px;right:12px;bottom:12px;z-index:40;
    display:flex;align-items:center;justify-content:center;min-height:52px;
    padding:8px 16px;border-radius:10px;
    background:var(--accent-hover);color:var(--white);
    font-weight:650;font-size:16px;line-height:1.25;text-align:center;text-decoration:none;
    box-shadow:0 14px 30px -12px rgba(15,44,71,.55);
  }
  .barre-devis:hover{background:var(--accent-shadow)}
  .site-footer:has(~ .barre-devis){padding-bottom:88px}
}
.cta .reassurance{font-size:12.5px;color:var(--muted);margin:13px 0 0}

/* Variante compacte, alignée à gauche, pour le milieu de page */
.cta.inline{text-align:left;padding:20px 24px}
.cta.inline h3{font-size:16.5px}

/* ==========================================================================
   BLOC : FAQ  (associer le JSON-LD FAQPage dans le <head>)
   ========================================================================== */
.faq-item{border-bottom:1px solid var(--line);padding:18px 0}
.faq-item:last-child{border-bottom:none}
.faq-q{font-weight:650;color:var(--brand);font-size:17px;margin-bottom:7px}
.faq-a{margin-bottom:0}

/* ==========================================================================
   BLOC : MAILLAGE INTERNE  (essentiel au SEO — ne jamais l'omettre)
   ========================================================================== */
/* Les sources sont une trace de ce qui a servi à écrire la page, pas un
   argument de vente : bord discret, pas de fond, pas de couleur d'accent.
   Qui les lit les cherche ; qui ne les lit pas ne doit pas buter dessus. */
/* Prévenir avant le clic plutôt que surprendre après : le lecteur quitte le
   domaine, autant le lui dire. Dit aussi que nous ne collectons rien, ce qui
   est vrai et vaut mieux dit que tu. Discret, sous le bouton, jamais en
   concurrence avec lui. */
.redirect-note{
  margin:9px 0 0;font-size:12.5px;line-height:1.45;color:var(--muted);
  opacity:.85;
}

.sources{
  margin:34px 0;padding:18px 0 0;border-top:1px solid var(--line);
  font-size:14px;color:var(--muted);line-height:1.6;
}
.sources .label{
  font-size:12px;font-weight:700;letter-spacing:.8px;text-transform:uppercase;
  color:var(--muted);margin-bottom:10px;
}
.sources ul{list-style:none;margin:0;display:grid;gap:7px}
.sources li{margin:0;padding-left:15px;position:relative}
.sources li::before{
  content:"";position:absolute;left:0;top:9px;
  width:5px;height:5px;border-radius:50%;background:var(--line);
}
.sources a{color:var(--muted);text-decoration:underline}
.sources a:hover{color:var(--text)}

.related{
  background:var(--white);border:1px solid var(--line);
  border-radius:var(--radius);padding:22px 24px;margin:36px 0;
}
.related .label{
  font-size:12px;font-weight:700;letter-spacing:.8px;text-transform:uppercase;
  color:var(--muted);margin-bottom:12px;
}
.related ul{list-style:none;margin:0;display:grid;gap:9px}
.related li{margin:0}
.related a{
  color:var(--brand);text-decoration:none;font-weight:600;font-size:15.5px;
}
.related a:hover{text-decoration:underline}
.related a::before{content:"→ ";color:var(--accent);font-weight:700}

/* ==========================================================================
   BLOC : AUTEUR / CRÉDIBILITÉ  (signal E-E-A-T)
   ========================================================================== */
/* En tête d'article, pas en pied : le lecteur doit savoir qui parle avant de
   lire, pas après. C'est aussi l'ordre que les moteurs et les modèles
   rattachent à l'auteur. */
.author{
  display:flex;gap:13px;align-items:center;
  margin:14px 0 0;
  font-size:14px;color:var(--muted);line-height:1.5;
}
.author .avatar{
  width:44px;height:44px;border-radius:50%;flex:0 0 44px;
  background:var(--soft) url("/assets/img/auteur.svg") center/cover no-repeat;
  border:1px solid var(--line);
}
.author b{color:var(--brand);display:block;font-size:15px;margin-bottom:1px}

/* ==========================================================================
   BLOC : PIED DE PAGE  (la mention de rémunération est obligatoire)
   ========================================================================== */
.site-footer{
  background:var(--brand);color:#b9c9d8;margin-top:56px;
  padding:34px 0 30px;font-size:13.5px;
}
.site-footer a{color:var(--white)}
.disclosure{
  background:rgba(255,255,255,.07);border-radius:7px;
  padding:15px 18px;margin-bottom:22px;line-height:1.6;
}
.disclosure strong{color:var(--white)}
.footer-nav{display:flex;gap:20px;flex-wrap:wrap;margin-bottom:14px}
.footer-nav a{text-decoration:none;color:#d6e3ee}
.footer-nav a:hover{text-decoration:underline}

/* ==========================================================================
   MOBILE
   ========================================================================== */
@media(max-width:600px){
  body{font-size:16.5px}
  h1{font-size:27px}
  h2{font-size:21px}
  h3{font-size:17.5px}
  .lede{font-size:16.5px}
  .hero{padding:22px 0 28px}
  .header-cta{display:none}
  .cta{padding:22px 18px}
  .btn{width:100%;padding:15px 20px}
  .author{flex-direction:column;align-items:flex-start;gap:10px}
}

/* ==========================================================================
   IMPRESSION
   ========================================================================== */
@media print{
  .site-header,.cta,.site-footer,.related,.barre-devis{display:none}
  body{background:#fff;font-size:12pt}
}

/* ==========================================================================
   BLOCS SPÉCIFIQUES À LA PAGE D'ACCUEIL
   ========================================================================== */

/* La page d'accueil partage le fond photographique de .hero (voir plus haut)
   et n'ajoute qu'une respiration plus large et des tailles de titre. */
.hero-home{padding:58px 0 54px}
.hero-home h1{color:var(--white);font-size:39px;margin-bottom:18px}
.hero-home .lede{color:#c5d6e5;font-size:19px;margin-bottom:28px}
/* ATTENTION, piège vérifié le 07/11/2026 : l'accueil porte `hero-home` et
   PAS `hero`. Les règles `.hero *` ne l'atteignent donc jamais, et tout ce
   qui doit valoir sur fond sombre doit être redit ici. Supprimer cette
   ligne en croyant qu'elle est redondante fait retomber le surtitre sur le
   `.kicker` générique, en --accent : 4,18:1 sur le bleu nuit, sous le seuil.
   #e0a964 est l'orange clair du hero, 6,81:1. */
.hero-home .kicker{color:#e0a964}
/* `.hero-home .reassurance` a été SUPPRIMÉE le 07/11/2026. Elle posait
   #9fb5c8 — un gris-bleu clair calculé pour le fond bleu nuit, où il donne
   6,74:1. Mais la carte de devis est blanche et vit DANS le hero : la règle
   y descendait et y imposait 2,12:1, le pire contraste du site, sur la
   phrase placée juste sous le bouton principal de l'accueil.

   Elle avait une cible légitime tant qu'une phrase de réassurance existait
   sur le fond sombre. Cette phrase a été retirée le même jour (elle était
   restée seule après la suppression de son bouton) : la règle ne touchait
   donc plus que la carte, où elle avait tort. La carte reprend la couleur
   des 33 autres pages, --muted à 5,47:1.

   À retenir pour la suite : une couleur pensée pour un fond sombre ne doit
   pas être posée par une règle descendante d'une zone sombre, parce qu'une
   zone sombre peut contenir une carte claire. Le contrôle 18 de _audit.py
   vérifie désormais ce cas précis. */

/* Grille de rubriques */
.cards{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));
  gap:16px;margin:26px 0;
}
.card{
  background:var(--white);border:1px solid var(--line);border-radius:var(--radius);
  padding:20px 22px;text-decoration:none;display:block;
  transition:border-color .15s,box-shadow .15s;
}
.card:hover{border-color:var(--brand);box-shadow:0 2px 10px rgba(15,44,71,.07)}
.card b{display:block;color:var(--brand);font-size:16.5px;margin-bottom:5px}
.card span{color:var(--muted);font-size:14.5px;display:block;line-height:1.5}

/* Liste de liens compacte (annuaire de pages métier) */
.linklist{
  columns:2;column-gap:28px;list-style:none;margin:18px 0 0;
}
/* La classe se pose tantôt sur le <ul>, tantôt sur un <div> qui l'enveloppe.
   Dans ce second cas le list-style ci-dessus vise le conteneur et rate la
   liste : la puce par défaut réapparaît en plus de la flèche de .linklist a. */
.linklist ul{list-style:none;margin:0;padding:0}
.linklist li{margin:0 0 10px;break-inside:avoid}
.linklist a{color:var(--brand);text-decoration:none;font-size:15.5px;font-weight:600}
.linklist a:hover{text-decoration:underline}
.linklist a::before{content:"→ ";color:var(--accent)}

/* Bloc méthodologie / confiance */
.trust{
  background:var(--soft);border:1px solid var(--line);border-radius:var(--radius);
  padding:26px 28px;margin:36px 0;
}
.trust h3{margin-top:0}
.trust ul{margin-bottom:0}

@media(max-width:600px){
  .hero-home{padding:38px 0 36px}
  .hero-home h1{font-size:28px}
  .hero-home .lede{font-size:17px}
  .linklist{columns:1}
}

/* ==========================================================================
   SOMMAIRE À ANCRES
   Sur une page de 2 500 mots, c'est lui qui évite le rebond immédiat.
   Google s'en sert aussi pour afficher des sous-liens dans les résultats.
   ========================================================================== */
.toc{background:var(--soft);border:1px solid var(--line);border-radius:var(--radius);
  padding:20px 24px;margin:30px 0;}
.toc .label{font-size:12px;font-weight:700;letter-spacing:.07em;text-transform:uppercase;
  color:var(--muted);margin-bottom:12px}
.toc ol{margin:0;padding-left:20px}
.toc li{margin:0 0 7px;font-size:15.5px}
.toc a{color:var(--brand);text-decoration:none;font-weight:600}
.toc a:hover{text-decoration:underline}

/* Décale l'ancre pour qu'un titre cliqué ne colle pas au haut de l'écran */
main h2[id]{scroll-margin-top:22px}

/* ==========================================================================
   ICÔNES DE CARTE
   Les fichiers sont dans /assets/img/icons/. Ils sont appliqués en
   mask-image et non en background-image : le tracé sert de pochoir et la
   couleur vient de var(--brand). Conséquence utile — en dupliquant le site
   pour une autre verticale, les icônes suivent la nouvelle couleur sans
   qu'on touche aux SVG.
   Usage : <a class="card i-garage" …>
   ========================================================================== */
/* Le @supports n'est pas une précaution décorative : sans masque, le
   pseudo-élément s'afficherait en carré plein de couleur sur chaque carte.
   Enfermé ici, il n'apparaît tout simplement pas et la carte reste correcte. */
@supports ((-webkit-mask-image:url("")) or (mask-image:url(""))){
  .card[class*="i-"]::before{
    content:"";display:block;width:26px;height:26px;margin-bottom:12px;
    background:var(--brand);opacity:.85;
    -webkit-mask:var(--ico) center/contain no-repeat;
            mask:var(--ico) center/contain no-repeat;
  }
  .card:hover::before{opacity:1}
}

.i-garage          {--ico:url("/assets/img/icons/garage.svg")}
.i-entrepot        {--ico:url("/assets/img/icons/entrepot.svg")}
.i-pharmacie       {--ico:url("/assets/img/icons/pharmacie.svg")}
.i-commerce        {--ico:url("/assets/img/icons/commerce.svg")}
.i-bureaux         {--ico:url("/assets/img/icons/bureaux.svg")}
.i-restaurant      {--ico:url("/assets/img/icons/restaurant.svg")}
.i-atelier         {--ico:url("/assets/img/icons/atelier.svg")}
.i-chantier        {--ico:url("/assets/img/icons/chantier.svg")}
.i-agricole        {--ico:url("/assets/img/icons/agricole.svg")}
.i-medical         {--ico:url("/assets/img/icons/medical.svg")}
.i-bijouterie      {--ico:url("/assets/img/icons/bijouterie.svg")}
.i-sport           {--ico:url("/assets/img/icons/sport.svg")}
.i-alarme          {--ico:url("/assets/img/icons/alarme.svg")}
.i-telesurveillance{--ico:url("/assets/img/icons/telesurveillance.svg")}
.i-video           {--ico:url("/assets/img/icons/video.svg")}
.i-acces           {--ico:url("/assets/img/icons/acces.svg")}
.i-incendie        {--ico:url("/assets/img/icons/incendie.svg")}
.i-prix            {--ico:url("/assets/img/icons/prix.svg")}
.i-assurance       {--ico:url("/assets/img/icons/assurance.svg")}
.i-grille          {--ico:url("/assets/img/icons/grille.svg")}

/* Puces de la liste des 12 métiers : même pochoir, format réduit */
@supports ((-webkit-mask-image:url("")) or (mask-image:url(""))){
  .linklist a[class*="i-"]{display:flex;align-items:center;gap:9px}
  .linklist a[class*="i-"]::before{
    content:"";flex:0 0 17px;height:17px;background:var(--brand);opacity:.6;
    -webkit-mask:var(--ico) center/contain no-repeat;
            mask:var(--ico) center/contain no-repeat;
  }
}

/* ==========================================================================
   FIGURES ET SCHÉMAS
   Règle : on n'illustre pas pour décorer. Une figure doit porter une
   information que le texte ne donne pas aussi vite — un plan d'implantation,
   un enchaînement, une décomposition de prix. Toujours un alt descriptif et
   une légende : c'est ce qui la rend indexable dans Google Images.
   width/height sont obligatoires dans le HTML pour éviter le saut de mise
   en page au chargement (Cumulative Layout Shift).
   ========================================================================== */
figure.schema{
  margin:30px 0;padding:22px 22px 16px;
  background:var(--white);border:1px solid var(--line);border-radius:var(--radius);
}
figure.schema img,figure.schema svg{display:block;width:100%;height:auto}
figure.schema figcaption{
  margin-top:14px;padding-top:13px;border-top:1px solid var(--line);
  font-size:13.5px;color:var(--muted);line-height:1.55;
}
figure.schema figcaption b{color:var(--ink);font-weight:650}

/* Bandeau illustré de haut de page, pour une photo réelle le jour où il y en a */
figure.cover{margin:0 0 26px}
figure.cover img{
  display:block;width:100%;height:auto;border-radius:var(--radius);
  border:1px solid var(--line);
}
figure.cover figcaption{margin-top:9px;font-size:13px;color:var(--muted)}
