/* ============================================================================
   BASE — le craft appliqué. À copier tel quel, à NE PAS réécrire par site.

   Ce fichier ne contient AUCUN choix esthétique : il ne fait qu'appliquer
   mécaniquement les règles de 09-bible-web/01-fondamentaux-ui.md (grille,
   échelle, proximité, lisibilité, états) et de 09-bible-web/07 (les inviolables).

   Il ne lit que des tokens. Toute l'identité vit dans tokens.css.

   Pourquoi il existe : l'audit du 07/08/2026 a montré que chaque site
   reconstruisait sa grille, son échelle et ses états à la main — d'où des
   valeurs au hasard, des contrastes ratés et des cibles trop petites. Ici,
   le plancher de qualité est posé une fois pour toutes.
   ============================================================================ */

/* ---------------------------------------------------- 1. Remise à plat ---- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body, h1, h2, h3, h4, p, figure, blockquote, dl, dd { margin: 0; }
ul[class], ol[class] { list-style: none; padding: 0; margin: 0; }
img, picture, video, canvas, svg { display: block; max-width: 100%; }
input, button, textarea, select { font: inherit; color: inherit; }
button { background: none; border: 0; cursor: pointer; }

/* ⛔ INVIOLABLE I05 — le garde-fou mouvement. Toujours en haut, jamais retiré. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
  html { scroll-behavior: auto; }
}

/* ------------------------------------------------------- 2. Le corps ------ */
body {
  background: var(--fond);
  color: var(--encre);
  font-family: var(--f-texte);
  font-size: var(--fs-body);          /* ⛔ I01 — plancher 19px                */
  line-height: var(--lh-body);
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
}

/* ------------------------------------------------- 3. La grille ----------- */
/* 4 colonnes mobile · 8 tablette · 12 desktop. Rien ne sort de là sans
   décision écrite (09-bible-web/07, règle F01).                              */
.wrap {
  width: 100%;
  max-width: var(--w-max);
  margin-inline: auto;
  padding-inline: var(--e-5);                       /* 24px : la marge mobile  */
}
@media (min-width: 768px)  { .wrap { padding-inline: var(--e-6); } }
@media (min-width: 1024px) { .wrap { padding-inline: var(--e-8); } }

/* ⚠️ `minmax(0, 1fr)` et PAS `1fr`. C'est LE piège de CSS Grid : `1fr` vaut
   `minmax(auto, 1fr)`, donc une colonne ne descend jamais sous la largeur de son
   contenu — un mot long, une carte dense, et les colonnes se chevauchent au lieu
   de se partager la largeur. Constaté sur le premier site généré par le socle
   (07/08/2026) : les 3 cartes de services sortaient à des largeurs différentes.
   Le `min-width: 0` sur les enfants couvre le même problème en flex. */
.grid { display: grid; gap: var(--gap-grille-m); grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (min-width: 768px)  { .grid { grid-template-columns: repeat(8, minmax(0, 1fr));  gap: var(--gap-grille); } }
@media (min-width: 1024px) { .grid { grid-template-columns: repeat(12, minmax(0, 1fr)); gap: var(--gap-grille); } }
.grid > * { min-width: 0; }

.col-2 { grid-column: span 2; } .col-3 { grid-column: span 3; }
.col-4 { grid-column: span 4; } .col-5 { grid-column: span 5; }
.col-6 { grid-column: span 6; } .col-7 { grid-column: span 7; }
.col-8 { grid-column: span 8; } .col-12{ grid-column: 1 / -1; }
@media (max-width: 767px) { [class*="col-"] { grid-column: 1 / -1; } }

/* Sortir de la grille : un choix assumé, jamais un accident. */
.full-bleed { width: 100vw; margin-left: 50%; transform: translateX(-50%); }

/* ------------------------------------------------- 4. Les sections -------- */
.section { padding-block: var(--pad-section); }
.section--sombre { background: var(--sombre); color: #fff; }
.section--sombre .lead,
.section--sombre p { color: rgb(255 255 255 / .82); }
.section--surface { background: var(--surface); }
.section + .section { border-top: 1px solid var(--ligne); }
.section--sombre + .section,
.section--sombre { border-top-color: var(--ligne-nuit); }

/* ------------------------------------------------- 5. La typographie ------ */
h1, h2, h3 { font-family: var(--f-titre); font-weight: 700; text-wrap: balance; }
h1 { font-size: var(--fs-h1); line-height: var(--lh-titre); letter-spacing: var(--ls-titre); }
h2 { font-size: var(--fs-h2); line-height: 1.12; letter-spacing: -.015em; }
h3 { font-size: var(--fs-h3); line-height: 1.2;  letter-spacing: -.01em; }

/* La règle de proximité : beaucoup avant un titre, peu après.
   Un titre appartient à ce qui le SUIT (09-bible-web/01 §2.2).               */
h2 { margin-block: var(--e-9) var(--e-4); }
h3 { margin-block: var(--e-6) var(--e-2); }
h2:first-child, h3:first-child { margin-top: 0; }

p, li { max-width: var(--w-texte); text-wrap: pretty; }
p + p { margin-top: var(--e-4); }
.lead { font-size: clamp(18px, 2vw, 21px); color: var(--encre-2); }

/* Le label en capitales : letter-spacing OBLIGATOIRE, sinon c'est illisible. */
.label {
  font-size: var(--fs-label); font-weight: 600;
  text-transform: uppercase; letter-spacing: var(--ls-label);
  color: var(--encre-2);
}

a { color: inherit; text-underline-offset: 3px; text-decoration-thickness: 1px; }
strong, b { font-weight: 700; }

/* Les listes à puce du contenu (celles qui n'ont pas de classe) */
:where(ul:not([class]), ol:not([class])) { padding-left: 1.2em; margin-block: 0 var(--e-4); }
:where(ul:not([class]), ol:not([class])) li + li { margin-top: var(--e-2); }

/* ------------------------------------------------- 6. L'accessibilité ----- */
/* ⛔ I06 — un focus VISIBLE sur tout ce qui se navigue au clavier.           */
:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 3px;
  border-radius: 3px;
}
:focus:not(:focus-visible) { outline: none; }

/* Le lien d'évitement : première chose dans le <body>, invisible jusqu'au Tab */
.skip {
  position: absolute; left: -9999px; top: 0; z-index: 999;
  padding: var(--e-3) var(--e-5); background: var(--marque); color: #fff;
}
.skip:focus { left: var(--e-3); top: var(--e-3); }

/* Masquer visuellement sans masquer pour un lecteur d'écran */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

/* ------------------------------------------------- 7. Les boutons --------- */
/* ⛔ I03 — 48px de haut minimum. Les 6 états sont tous définis : sans ça,
   un composant n'est pas livrable (09-bible-web/02 §7.3).                    */
.btn {
  position: relative; overflow: hidden;
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--e-2);
  min-height: var(--min-cible);
  padding: var(--e-3) var(--e-6);
  border-radius: var(--r-cta);
  font-weight: 650; text-decoration: none; text-align: center;
  transition: transform var(--d-micro) var(--ease-sortie),
              box-shadow var(--d-micro) var(--ease-sortie),
              background  var(--d-micro),
              border-color var(--d-micro);
}
.btn:hover  { transform: translateY(-2px); box-shadow: var(--sh-2); }
.btn:active { transform: translateY(0);    box-shadow: var(--sh-1); transition-duration: 60ms; }
.btn[disabled], .btn[aria-disabled="true"] { opacity: .5; pointer-events: none; }
.btn[data-loading] { pointer-events: none; }
.btn[data-loading]::after {
  content: ""; width: 15px; height: 15px; border-radius: 50%;
  border: 2px solid currentColor; border-top-color: transparent;
  animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

.btn--primaire  { background: var(--marque); color: #fff; }
.btn--secondaire{ background: transparent; color: var(--encre);
                  border: 2px solid var(--encre); }
.btn--sombre    { background: #fff; color: var(--sombre); }

/* La flèche qui avance : le détail qui coûte 2 lignes et se voit. */
.btn svg { transition: transform var(--d-etat) var(--ease-retour); }
.btn:hover svg { transform: translateX(4px); }

/* ------------------------------------------------- 8. Les cartes ---------- */
.card {
  position: relative;                       /* pour un badge en absolu       */
  display: flex; flex-direction: column; gap: var(--e-4);
  padding: var(--e-5);
  background: var(--surface);
  border: 1px solid var(--ligne);
  border-radius: var(--r-bloc);
  overflow: hidden;                         /* le rayon s'applique à l'image */
}
@media (min-width: 768px) { .card { padding: var(--e-6); } }
.card__media { width: 100%; aspect-ratio: 4/3; object-fit: cover; }
.card__body  { flex: 1 1 auto; }            /* pousse le CTA en bas          */
.card__badge { position: absolute; top: var(--e-3); right: var(--e-3); }
.card--lien:hover { border-color: var(--marque); }

/* ------------------------------------------------- 9. Les formulaires ----- */
.field { display: flex; flex-direction: column; gap: var(--e-2); margin-bottom: var(--e-5); }
.field > label { font-weight: 600; font-size: var(--fs-small); }
.field input, .field textarea, .field select {
  min-height: var(--min-cible);
  padding: var(--e-3) var(--e-4);
  background: #fff; color: var(--encre);
  border: 2px solid var(--ligne); border-radius: var(--r-cta);
  transition: border-color var(--d-micro);
}
.field input:focus, .field textarea:focus { border-color: var(--marque); }
.field .aide { font-size: var(--fs-small); color: var(--encre-2); }

/* ⛔ I07 — l'erreur ne passe JAMAIS par la couleur seule : icône + texte.    */
.field.is-error input, .field.is-error textarea { border-color: var(--danger); }
.field.is-error .msg { color: var(--danger); font-size: var(--fs-small); font-weight: 600; }
.field.is-error .msg::before { content: "⚠ "; }
.field.is-error { animation: shake .35s both; }
@keyframes shake {
  10%,90% { transform: translateX(-2px) } 30%,70% { transform: translateX(4px) }
  50%     { transform: translateX(-4px) }
}

/* ------------------------------------------------- 10. La barre d'appel --- */
/* Le patron le plus efficace du web local : UN CTA, épinglé, visible pendant
   tout le scroll. 64 % du trafic est mobile (09-bible-web/04 §9).            */
@media (max-width: 767px) {
  .callbar {
    position: fixed; inset: auto 0 0 0; z-index: 60;
    display: flex; gap: var(--e-2);
    padding: 10px var(--e-4) calc(10px + env(safe-area-inset-bottom));
    background: var(--marque);
    box-shadow: 0 -6px 20px rgb(0 0 0 / .16);
  }
  .callbar .btn { flex: 1; min-height: 46px; }
  body { padding-bottom: 84px; }
}
@media (min-width: 768px) { .callbar { display: none; } }

/* ------------------------------------------------- 11. Le reveal ---------- */
/* ⛔ I04 — la classe n'est JAMAIS dans le markup : c'est reveal.js qui pose
   `.js` sur <html>. Sans JS, rien n'est masqué. Failsafe à 1400 ms.          */
.js [data-reveal-item] {
  opacity: 0; transform: translateY(18px);
  transition: opacity var(--d-entree) var(--ease-expo),
              transform var(--d-entree) var(--ease-expo);
  transition-delay: var(--d, 0ms);
}
.js [data-reveal].is-in [data-reveal-item] { opacity: 1; transform: none; }

/* Variantes — 09-bible-web/02 §4. Une seule par section.                     */
.js [data-reveal-item].rv-scale  { transform: scale(.94); }
.js [data-reveal-item].rv-gauche { transform: translateX(-28px); }
.js [data-reveal-item].rv-droite { transform: translateX(28px); }
.js [data-reveal-item].rv-rideau { opacity: 1; clip-path: inset(0 0 100% 0);
                                   transition: clip-path .9s var(--ease-expo); }
.js [data-reveal].is-in [data-reveal-item].rv-rideau { clip-path: inset(0); }
.js [data-reveal-item].rv-trait  { opacity: 1; transform: scaleX(0); transform-origin: left; }
.js [data-reveal].is-in [data-reveal-item].rv-trait { transform: scaleX(1); }

/* ------------------------------- 11 bis. Les composants du catalogue ------ */
/* Tout ce qu'utilise sections/catalogue.html doit être stylé ICI. Un bloc du
   catalogue qui s'appuie sur une classe absente produit un site bancal dès la
   première génération — constaté au premier essai (nav sans espacement,
   paragraphes collés). */

/* Nav */
.nav { position: sticky; top: 0; z-index: 50; padding-block: var(--e-3);
       background: color-mix(in srgb, var(--fond) 88%, transparent);
       backdrop-filter: blur(10px); border-bottom: 1px solid var(--ligne); }
.marque { display: inline-flex; align-items: center; gap: var(--e-2);
          font-family: var(--f-titre); font-weight: 700; font-size: 20px;
          text-decoration: none; }
.nav__liens { display: flex; align-items: center; gap: var(--e-5); flex-wrap: wrap; }
.nav__liens a { text-decoration: none; font-weight: 600; font-size: var(--fs-small);
                padding-block: var(--e-2); }
.nav__liens a:hover { color: var(--marque); }
@media (max-width: 900px) { .nav { position: static; } .nav__liens { display: none; } }

/* Hero */
.hero { padding-bottom: var(--pad-section); }
.hero .label { display: block; margin-bottom: var(--e-3); }
.hero h1 { margin-bottom: var(--e-4); }

/* Espacements de texte courants — le « lead » respire, la mention légère aussi */
.lead { margin-bottom: var(--e-5); }
.aide { font-size: var(--fs-small); color: var(--encre-2); margin-top: var(--e-3); }
.section--sombre .aide { color: rgb(255 255 255 / .7); }

/* Citation */
blockquote { margin: 0 0 var(--e-4); padding: var(--e-4) var(--e-5);
             background: var(--surface); color: var(--encre);
             border-left: 4px solid var(--accent); border-radius: 0 var(--r-bloc) var(--r-bloc) 0; }

/* Figure / vidéo */
figure { margin: 0; }
figure video, figure img { width: 100%; border-radius: var(--r-img); background: #000; }
figcaption { margin-top: var(--e-3); font-size: var(--fs-small); color: var(--encre-2); }
.section--sombre figcaption { color: rgb(255 255 255 / .7); }

/* FAQ — <details> natif : accessible, indexable, zéro JS */
.faq__item { border-bottom: 1px solid var(--ligne); }
.faq__item summary { display: flex; align-items: center; justify-content: space-between;
                     gap: var(--e-4); min-height: var(--min-cible);
                     padding-block: var(--e-3); cursor: pointer;
                     font-weight: 650; list-style: none; }
.faq__item summary::-webkit-details-marker { display: none; }
.faq__item summary::after { content: "+"; font-size: 26px; line-height: 1;
                            transition: transform var(--d-etat) var(--ease-sortie); }
.faq__item[open] summary::after { transform: rotate(45deg); }
.faq__body { padding-bottom: var(--e-4); }

/* Process — la liste ordonnée sans puces */
ol.grid { list-style: none; padding: 0; counter-reset: etape; }
ol.grid > li { max-width: none; }

/* Zone d'intervention — la liste de villes EST ce qui référence */
.section ul.row { list-style: none; padding: 0; }
.section ul.row li { max-width: none; padding: var(--e-2) var(--e-4);
                     border: 1px solid var(--ligne); border-radius: var(--r-cta);
                     font-size: var(--fs-small); font-weight: 600; }

/* Tableaux (pages légales) */
table { width: 100%; border-collapse: collapse; margin-bottom: var(--e-5);
        font-size: var(--fs-small); font-variant-numeric: tabular-nums; }
th, td { text-align: left; padding: var(--e-3); border-bottom: 1px solid var(--ligne);
         vertical-align: top; }
th { font-weight: 700; }

/* Le bloc de contenu propre à la page : ses paragraphes gardent la largeur de lecture */
.section > .wrap > div > p { margin-bottom: var(--e-4); }

/* ------------------------------------------------- 12. Utilitaires -------- */
.stack > * + * { margin-top: var(--e-4); }
.stack-l > * + * { margin-top: var(--e-6); }
.row { display: flex; align-items: center; gap: var(--e-4); flex-wrap: wrap; }
.between { display: flex; align-items: center; justify-content: space-between;
           gap: var(--e-4); flex-wrap: wrap; }
.center { text-align: center; margin-inline: auto; }
.nums { font-variant-numeric: tabular-nums; font-family: var(--f-chiffre); }
.hr { border: 0; border-top: 1px solid var(--ligne); margin-block: var(--e-8); }

/* Impression : on retire le décor, on garde le contenu et les URL. */
@media print {
  .callbar, .nav, nav, video, canvas { display: none !important; }
  body { font-size: 12pt; color: #000; background: #fff; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 10pt; }
}
