/* Feuille unique de Whatafter — GENERE par tools/build_css.py.
   Ne pas editer ce fichier : modifier les sources (fonts.css, whatafter.css, utilitaires.css, animations.css)
   puis relancer le script. Les sources restent separees pour la maintenance ;
   c'est la livraison qui est groupee (une seule requete avant le premier rendu). */

/* ===== fonts.css ===== */
/* Polices auto-hébergées (aucune requête externe).

   UNE SEULE déclaration, et une seule graisse de fichier : Inter est une police VARIABLE,
   son axe `wght` va de 100 à 900. La déclarer `font-weight:100 900` sur ce fichier fait
   dessiner chaque graisse pour de vrai — titres en 600, chiffres en 650, tout est juste.

   Avant, deux fichiers IDENTIQUES étaient déclarés en 400 et 600 : le navigateur ne trouvait
   pas le dessin du 600 et l'épaississait artificiellement (faux gras). 94 ko pour deux
   requêtes, et un gras imité, sur un site qui vend la précision visuelle.

   Le fichier est sous-ensemblé au latin utile : accents français, guillemets, tirets,
   apostrophe courbe, euro, symboles de mesure. Ce qui ne sert pas n'est pas téléchargé. */
@font-face{
  font-family:'Inter';
  font-style:normal;
  font-weight:100 900;
  font-display:swap;
  src:url('/static/fonts/inter-variable-latin.woff2') format('woff2-variations');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}


/* ===== whatafter.css ===== */
/* ===========================================================
   Whatafter — identité « précision »
   Encre froide, un seul accent bleu signal, angles nets, grille
   stricte, chiffres alignés en tabulaire. Aucune fioriture.
   Objectif : contemporain et carré, lisible au premier regard.

   Les noms de variables sont conservés volontairement : les styles
   en ligne des gabarits s'y réfèrent, et un renommage silencieux
   ferait perdre bordures et couleurs sans erreur visible.
   =========================================================== */
:root{
  /* surfaces : gris froids, très clairs */
  --cream:#f6f7f9;        /* fond général */
  --cream-2:#eceff3;      /* zones alternées */
  --paper:#ffffff;        /* cartes, surfaces */

  /* encres : froides, franc contrastées */
  --ink:#0b1220;          /* titres, chiffres */
  --ink-2:#39424e;        /* texte courant */
  --mute:#5b6572;         /* texte secondaire (contraste AA garanti) */

  /* filets */
  --line:#dde2e8;
  --line-2:#eaeef2;

  /* Plus de variable « nuit » : le theme est clair partout. Les surfaces sombres (bandeau,
     pied, heros) sont devenues claires, et le seul aplat encre qui reste est le bouton
     d'action principale. Une variable morte fait croire a une intention disparue. */

  /* un seul accent : bleu signal */
  --brick:#2563eb;
  --brick-2:#1d4ed8;
  --brick-ink:#1d4ed8;

  /* états */
  --sage:#15803d;
  --amber:#b45309;
  --verm:#dc2626;
  --verm-ink:#b91c1c;

  /* typographie : une seule famille, géométrique */
  --sans:"Inter",system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
  --serif:var(--sans);                    /* plus de sérif : la hiérarchie vient de la graisse */
  --mono:ui-monospace,SFMono-Regular,"DejaVu Sans Mono",Menlo,monospace;

  /* grille : échelle de 8px */
  --r:6px;
  --r-sm:4px;
  --shadow:0 1px 2px rgba(11,18,32,.04),0 1px 1px rgba(11,18,32,.03);
  --shadow-lift:0 4px 12px -4px rgba(11,18,32,.12);
  --s1:8px; --s2:16px; --s3:24px; --s4:32px; --s5:48px; --s6:64px;
}

*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{margin:0;background:var(--cream);color:var(--ink-2);
  font-family:var(--sans);font-size:16.5px;line-height:1.65;
  font-feature-settings:"cv11","ss01";letter-spacing:-.002em}

/* ------------------------------------------------------------------ texte */
a{color:var(--ink);text-decoration:none;border-bottom:1px solid var(--line);transition:color .12s}
a:hover{border-color:var(--brick);color:var(--brick-ink)}
/* La marge haute compte : sans elle, un titre qui suit un paragraphe (ou une liste) colle
   au bloc précédent — c'est le défaut le plus visible sur une page de texte long. */
h1,h2,h3,h4{color:var(--ink);margin:0 0 var(--s2);line-height:1.16;
  font-family:var(--sans);font-weight:650;letter-spacing:-.022em}
h1{font-size:clamp(1.95rem,3.6vw,2.75rem);letter-spacing:-.03em}
h2{font-size:clamp(1.3rem,2.1vw,1.7rem)}
h2:not(:first-child),h3:not(:first-child){margin-top:var(--s6)}
/* dans une colonne de texte, on aere davantage : la mesure est plus longue à l'œil */
.colonne-texte h2:not(:first-child),.colonne-texte h3:not(:first-child){margin-top:var(--s6)}
.colonne-texte p,.colonne-texte li{max-width:68ch}
h3{font-size:1.06rem;font-weight:600;letter-spacing:-.012em}
h4{font-size:.95rem;font-weight:600}
p{margin:0 0 var(--s2);max-width:64ch}
b,strong{font-weight:600;color:var(--ink)}
.lead{font-size:1.08rem;color:var(--ink-2);max-width:60ch}
.hint{font-size:.85rem;color:var(--mute);margin:var(--s1) 0 0;max-width:70ch}
.dim{color:var(--mute)}
.mono{font-family:var(--mono);font-size:.82rem;color:var(--mute);letter-spacing:-.01em}
.center{text-align:center}

/* ------------------------------------------------------------------ grille */
.wrap{max-width:1180px;margin:0 auto;padding:0 var(--s3);position:relative;z-index:1}
.narrow{max-width:800px}
.grid{display:grid;gap:var(--s2)}
.g2{grid-template-columns:repeat(auto-fit,minmax(300px,1fr))}
.g3{grid-template-columns:repeat(auto-fit,minmax(230px,1fr))}
.g4{grid-template-columns:repeat(auto-fit,minmax(200px,1fr))}
section{padding:var(--s6) 0;position:relative;z-index:1}
section.tight{padding:var(--s5) 0}
section.alt{background:var(--cream-2);border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
/* Plus de section « nuit » : le theme est clair partout. Une section d'appel se distingue
   par le creux et un filet épais, pas par un aplat sombre — c'est la meme grammaire que le
   reste du site, et le contraste y est meilleur qu'un blanc sur un bleu presque noir. */
section.dark{background:var(--cream-2);color:var(--ink-2)}
section.dark h1,section.dark h2,section.dark h3{color:var(--ink)}
section.dark .lead{color:var(--ink-2)}

/* étiquette de section : petit carré d'accent + capitales espacées */
.tagline{display:flex;align-items:center;gap:9px;font-size:.76rem;font-weight:600;
  color:var(--brick-ink);text-transform:uppercase;letter-spacing:.1em}
.tagline::before{content:"";width:9px;height:9px;background:var(--brick);border-radius:1px;flex:0 0 9px}

/* ------------------------------------------------------------------ bandeau */
.rail{background:rgba(255,255,255,.92);color:var(--ink-2);position:sticky;top:0;z-index:20;
  border-bottom:1px solid var(--line);backdrop-filter:blur(8px)}
.rail-in{max-width:1180px;margin:0 auto;padding:0 var(--s3);height:62px;
  display:flex;align-items:center;gap:var(--s3)}
.brand{display:flex;align-items:center;gap:0;color:var(--ink);border:0;
  font-weight:650;letter-spacing:-.022em;font-size:1.12rem}
.brand:hover{color:var(--ink);border:0}
.brand em{font-style:normal;font-weight:400;color:var(--mute)}
.brand .marque{width:26px;height:26px;display:block;flex:0 0 26px;margin-right:9px}
.rail nav{margin-left:auto;display:flex;gap:var(--s3);align-items:center;font-size:.9rem}
.rail nav a{color:var(--ink-2);border:0;font-weight:500}
.rail nav a:hover{color:var(--brick-ink)}
.rail .tag{font-size:.82rem;color:var(--mute)}
@media(max-width:860px){.rail nav .hide{display:none}.rail-in{gap:var(--s2)}}

/* ------------------------------------------------------------------ boutons */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:7px;
  font-family:var(--sans);font-weight:600;font-size:.93rem;letter-spacing:-.006em;
  padding:11px 18px;border:1px solid var(--line);border-radius:var(--r);
  background:var(--paper);color:var(--ink);cursor:pointer;transition:all .12s;
  border-bottom:1px solid var(--line)}
.btn:hover{border-color:#c3ccd6;background:#fbfcfd}
.btn.primary{background:var(--brick);border-color:var(--brick);color:#fff}
.btn.primary:hover{background:var(--brick-2);border-color:var(--brick-2);color:#fff}
/* `.btn.dark` etait le bouton sur fond nuit. Il devient le bouton en encre pleine : sur
   papier, c'est lui qui ressort le plus. Le nom de classe est conserve — il est utilise dans
   cinq gabarits — mais son sens est « action principale sur fond clair ». */
.btn.dark{background:var(--ink);border-color:var(--ink);color:#fff}
.btn.dark:hover{background:var(--ink-2);border-color:var(--ink-2)}
.btn.sm{padding:8px 13px;font-size:.85rem}
.btn.block{display:flex;width:100%}
.btn:focus-visible{outline:2px solid var(--brick);outline-offset:2px}

/* ------------------------------------------------------------------ cartes */
.metric{border:1px solid var(--line);background:var(--paper);padding:var(--s2) 18px;
  border-radius:var(--r);box-shadow:var(--shadow)}
.metric .k{font-size:.79rem;letter-spacing:.02em;color:var(--mute);font-weight:500;
  text-transform:uppercase}
.metric .v{font-size:2.05rem;font-weight:650;color:var(--ink);line-height:1.1;
  margin-top:5px;letter-spacing:-.035em;font-variant-numeric:tabular-nums}
.metric .v .u{font-size:.85rem;color:var(--mute);font-weight:500;letter-spacing:0;margin-left:2px}
/* cartes de formule : même hauteur, bouton poussé en bas — c'est ce qui fait « carré » */
.metric.plan{display:flex;flex-direction:column}
.metric.plan .btn{margin-top:auto}
.metric.warn{border-color:#e8cdb4;background:#fdf8f2}
.metric.warn .v{color:var(--verm-ink)}
.metric.good{border-color:#c3dcc9;background:#f5fbf6}
.metric.good .v{color:var(--sage)}
.metric.plat{border-color:#c9d6f5;background:#f5f8ff}
.metric.plat .v{color:var(--brick-ink)}

.gauge{height:6px;background:var(--line-2);border-radius:3px;overflow:hidden;margin-top:12px}
.gauge i{display:block;height:100%;background:var(--sage);border-radius:3px}
.gauge.danger i{background:var(--verm)}
.gauge.mid i{background:var(--amber)}

/* ------------------------------------------------------------------ relevés */
.releve{border:1px solid var(--line);background:var(--paper);border-radius:var(--r);overflow:hidden}
.releve .row{display:flex;justify-content:space-between;align-items:baseline;gap:var(--s2);
  padding:11px 15px;border-bottom:1px solid var(--line-2)}
.releve .row:last-child{border-bottom:0}
.releve .k{color:var(--mute);font-size:.9rem;flex:1 1 auto;min-width:0}
.releve .v{font-size:.96rem;font-weight:600;color:var(--ink);text-align:right;
  font-variant-numeric:tabular-nums;white-space:nowrap;flex:0 0 auto}
.releve .v.sig{color:var(--brick-ink)}
.releve .v a{border-bottom:1px solid transparent}
.releve .v a:hover{border-bottom-color:var(--brick)}

/* ------------------------------------------------------------------ saisie */
.scan{border:1px solid var(--line);background:var(--paper);padding:var(--s3);
  border-radius:var(--r);box-shadow:var(--shadow-lift)}
.scan .row{display:flex;gap:9px;flex-wrap:wrap}
.scan input[type=text],.scan input[type=email],.scan input[type=tel],.scan input[type=url],
.champ{flex:1 1 220px;width:100%;padding:12px 14px;border:1px solid var(--line);
  border-radius:var(--r);background:#fff;font-family:var(--sans);font-size:1rem;color:var(--ink)}
.scan input:focus,.champ:focus{outline:2px solid var(--brick);outline-offset:0;border-color:var(--brick)}
.champ{display:block;margin-bottom:9px}
textarea.champ{min-height:120px;resize:vertical}
.champ.inline{display:inline-block;width:auto;flex:1 1 220px;margin-bottom:0}
.champ.note{min-height:64px;font-size:.95rem}
label.champ-label{display:block;font-size:.85rem;font-weight:600;color:var(--ink);margin:0 0 5px;
  letter-spacing:-.006em}
.hp{position:absolute;left:-9999px;height:0;overflow:hidden}

/* ------------------------------------------------------------------ listes */
.facts{margin:0;padding:0;list-style:none;border-top:1px solid var(--line)}
.facts li{border-bottom:1px solid var(--line);padding:12px 2px;display:flex;gap:13px;
  font-size:.95rem;align-items:baseline}
.facts .n{color:var(--brick-ink);font-weight:600;flex:0 0 36px;font-variant-numeric:tabular-nums;
  font-size:.85rem;white-space:nowrap}

/* ------------------------------------------------------------------ constats */
.find{border-top:1px solid var(--line);padding:var(--s3) 0}
.find:first-of-type{border-top:0}
.find h3{margin-bottom:var(--s1)}
.sev{display:inline-flex;align-items:center;gap:6px;font-size:.75rem;font-weight:600;
  padding:3px 9px;border-radius:var(--r-sm);border:1px solid;margin-bottom:10px;
  text-transform:uppercase;letter-spacing:.05em}
.sev::before{content:"";width:6px;height:6px;border-radius:1px;background:currentColor}
.sev.critique{color:var(--verm-ink);border-color:#f0c4be;background:#fdf2f0}
.sev.majeur{color:#8a5308;border-color:#ecd2a8;background:#fdf7ed}
.sev.mineur{color:var(--mute);border-color:var(--line);background:var(--cream-2)}
.sev.info{color:#166534;border-color:#c3dcc9;background:#f5fbf6}
.find .f{font-size:.95rem;margin:.32rem 0;max-width:78ch}
.find .f b{color:var(--ink)}
.blur{filter:blur(5px);user-select:none;pointer-events:none}
.gate{border:1px solid #c9d6f5;background:#f5f8ff;padding:var(--s3);margin:var(--s3) 0;
  border-radius:var(--r)}
.gate h3{margin-bottom:var(--s1)}

/* ------------------------------------------------------------------ tableaux */
table{width:100%;border-collapse:collapse;font-size:.92rem}
th,td{text-align:left;padding:11px 12px;border-bottom:1px solid var(--line);vertical-align:top}
th{font-size:.75rem;color:var(--mute);font-weight:600;letter-spacing:.06em;
  text-transform:uppercase;background:var(--cream-2);border-bottom:1px solid var(--line)}
td.num{font-variant-numeric:tabular-nums;white-space:nowrap}

/* ------------------------------------------------------------------ pliage */
details{border-bottom:1px solid var(--line);padding:15px 0}
details summary{cursor:pointer;font-weight:600;color:var(--ink);list-style:none;
  font-size:1rem;display:flex;justify-content:space-between;gap:var(--s2);align-items:baseline;
  letter-spacing:-.008em}
details summary::-webkit-details-marker{display:none}
details summary::after{content:"+";color:var(--brick);font-weight:600;font-size:1.15rem;flex:0 0 auto}
details[open] summary::after{content:"–"}
details p{margin:.65rem 0 0;font-size:.95rem;color:var(--ink-2)}

/* ------------------------------------------------------------------ pied */
footer{background:var(--cream-2);color:var(--mute);padding:var(--s5) 0 var(--s4);font-size:.9rem;
  border-top:1px solid var(--line)}
footer a{color:var(--ink-2);border:0}
footer a:hover{color:var(--brick-ink);text-decoration:underline}
.foot{display:grid;grid-template-columns:1.6fr 1fr 1fr 1fr;gap:var(--s4)}
@media(max-width:860px){.foot{grid-template-columns:1fr 1fr}}
@media(max-width:560px){.foot{grid-template-columns:1fr}}
footer .tag{color:var(--mute);font-weight:600;margin-bottom:9px;font-size:.75rem;
  text-transform:uppercase;letter-spacing:.08em}
footer p{max-width:none}

/* ------------------------------------------------------------------ messages */
.alert{border:1px solid #f0c4be;background:#fdf2f0;color:var(--verm-ink);
  padding:12px 15px;font-size:.92rem;margin-bottom:var(--s2);border-radius:var(--r)}
.note{border:1px solid var(--line);border-left:3px solid var(--brick);background:#f8fafc;
  padding:14px 16px;font-size:.94rem;border-radius:var(--r)}
.chip{display:inline-block;font-size:.78rem;border:1px solid var(--line);padding:3px 9px;
  border-radius:var(--r-sm);color:var(--mute);margin:0 5px 5px 0;background:var(--paper);
  font-weight:500;letter-spacing:-.004em}
.chip.on{border-color:#c3dcc9;color:#166534;background:#f5fbf6}
.chip.late{border-color:#f0c4be;color:var(--verm-ink);background:#fdf2f0}
.spark{display:block;width:100%;height:48px}
.plan-bar{height:8px;border-radius:3px;background:var(--line-2);overflow:hidden}
.plan-bar i{display:block;height:100%;background:var(--brick)}
.mt1{margin-top:var(--s2)}.mt2{margin-top:var(--s4)}.mb0{margin-bottom:0}

/* une mire graduée n'apportait rien : elle est retirée volontairement. */

/* ---------------------------------------------------------------- paires etiquette + champ
   Un formulaire horizontal ou l'etiquette est un simple <label> de bloc produit des
   libelles qui flottent entre deux champs : on ne sait plus lequel ils decrivent, et la
   lecture au clavier devient devinette. Une paire « etiquette au-dessus, champ en dessous »
   reglee en grille reste juste a toutes les largeurs, et l'ordre du code suit l'ordre de
   lecture — rien a annoncer en plus a un lecteur d'ecran. */
.paire{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));
  gap:var(--s3);align-items:end}
.paire .duo{display:flex;flex-direction:column;gap:5px;min-width:0}
/* `flex:1 1 220px` decrit une LARGEUR de base — sans effet utile dans une colonne, ou il
   gonfle la hauteur du champ a ~200px. On annule : la largeur vient du duo, la hauteur du
   padding. */
.paire .duo .champ{flex:none;width:100%;height:auto;display:block;margin-bottom:0}
.paire button,.paire .btn{justify-self:start}
@media (max-width:560px){.paire{grid-template-columns:1fr}}

/* Lien d'evitement : invisible jusqu'au focus clavier. Ne JAMAIS le masquer avec
   `display:none` ou `visibility:hidden` — un lien non focusable ne sert a rien, et c'est
   l'erreur classique sur ce composant. On le sort de l'ecran, on le ramene au focus. */
.evitement{position:absolute;left:-9999px;top:0;z-index:100;padding:10px 16px;
  background:var(--brick);color:#fff;font-weight:600;border-radius:0 0 var(--r) 0}
.evitement:focus{left:0;outline:2px solid #fff;outline-offset:-4px}


/* ===== utilitaires.css ===== */
/* ===========================================================
   Whatafter — utilitaires extraits des attributs style="".

   Le CSP du site (`style-src 'self'`) bloque les styles en ligne : ils étaient
   donc purement ignorés par le navigateur, sans aucune erreur visible. Ces classes
   portent les mêmes déclarations, mais dans une feuille que le navigateur applique.
   Ce fichier est produit par /tmp/migrer_styles.py : ne pas l'éditer à la main.
   =========================================================== */

/* largeurs du plan de correction et des jauges (100 classes) */
.w0{width:0%}
.w1{width:1%}
.w2{width:2%}
.w3{width:3%}
.w4{width:4%}
.w5{width:5%}
.w6{width:6%}
.w7{width:7%}
.w8{width:8%}
.w9{width:9%}
.w10{width:10%}
.w11{width:11%}
.w12{width:12%}
.w13{width:13%}
.w14{width:14%}
.w15{width:15%}
.w16{width:16%}
.w17{width:17%}
.w18{width:18%}
.w19{width:19%}
.w20{width:20%}
.w21{width:21%}
.w22{width:22%}
.w23{width:23%}
.w24{width:24%}
.w25{width:25%}
.w26{width:26%}
.w27{width:27%}
.w28{width:28%}
.w29{width:29%}
.w30{width:30%}
.w31{width:31%}
.w32{width:32%}
.w33{width:33%}
.w34{width:34%}
.w35{width:35%}
.w36{width:36%}
.w37{width:37%}
.w38{width:38%}
.w39{width:39%}
.w40{width:40%}
.w41{width:41%}
.w42{width:42%}
.w43{width:43%}
.w44{width:44%}
.w45{width:45%}
.w46{width:46%}
.w47{width:47%}
.w48{width:48%}
.w49{width:49%}
.w50{width:50%}
.w51{width:51%}
.w52{width:52%}
.w53{width:53%}
.w54{width:54%}
.w55{width:55%}
.w56{width:56%}
.w57{width:57%}
.w58{width:58%}
.w59{width:59%}
.w60{width:60%}
.w61{width:61%}
.w62{width:62%}
.w63{width:63%}
.w64{width:64%}
.w65{width:65%}
.w66{width:66%}
.w67{width:67%}
.w68{width:68%}
.w69{width:69%}
.w70{width:70%}
.w71{width:71%}
.w72{width:72%}
.w73{width:73%}
.w74{width:74%}
.w75{width:75%}
.w76{width:76%}
.w77{width:77%}
.w78{width:78%}
.w79{width:79%}
.w80{width:80%}
.w81{width:81%}
.w82{width:82%}
.w83{width:83%}
.w84{width:84%}
.w85{width:85%}
.w86{width:86%}
.w87{width:87%}
.w88{width:88%}
.w89{width:89%}
.w90{width:90%}
.w91{width:91%}
.w92{width:92%}
.w93{width:93%}
.w94{width:94%}
.w95{width:95%}
.w96{width:96%}
.w97{width:97%}
.w98{width:98%}
.w99{width:99%}
.w100{width:100%}

/* déclarations nommées */
.check-accent{margin-top:4px;accent-color:var(--brick)}
.check-ligne{display:flex;gap:10px;align-items:flex-start;margin-top:14px;font-size:.9rem;color:var(--mute)}
.d-inline{display:inline}
.d-inline-ml-6{display:inline;margin-left:6px}
.foot-mentions{font-size:.82rem;margin:28px 0 0;color:var(--mute)}
.foot-pitch{font-size:.88rem;margin-top:12px;max-width:34ch;color:var(--mute)}
.fs-135{font-size:1.35rem}
.fs-140{font-size:1.4rem}
.fs-170{font-size:1.7rem}
.fs-78{font-size:.78rem}
.fs-80{font-size:.8rem}
.fs-90{font-size:.9rem}
.fs-92{font-size:.92rem}
.fs-92-m-041{font-size:.92rem;margin:.4rem 0 1rem}
.fs-92-m-06{font-size:.92rem;margin:.6rem 0 0}
.fs-95{font-size:.95rem}
.fs-95-mb-14{font-size:.95rem;margin-bottom:14px}
.fs-97-m-0{font-size:.97rem;margin:0}
.fs-97-m-07{font-size:.97rem;margin:.7rem 0 0}
.fs-97-mb-14{font-size:.97rem;margin-bottom:14px}
/* `.u45` marque un champ legal NON PUBLIE (« pas encore attribue ») : il doit se lire comme une
   absence, pas comme une valeur. Sans ce style, « pas encore attribué » s'affichait en gras noir,
   identique a un vrai SIREN — sur la page des mentions legales, exactement la ou la distinction
   compte. */
.u45{font-weight:400;color:var(--mute);font-style:normal}
.gap-44{gap:44px}
.grid-top-44{align-items:start;gap:44px}
.m-0-fs-90{margin:0;font-size:.9rem}
.m-10-0-6{margin:10px 0 6px}
.m-8-0-2{margin:8px 0 2px}
.mb-03{margin-bottom:.3rem}
.mb-04{margin-bottom:.4rem}
.mb-10{margin-bottom:10px}
.mb-14{margin-bottom:14px}
/* Deux boutons cote a cote se collent si rien ne les separe : le second parait attache au premier.
   `guides.html` reclame `ml-1` depuis sa creation et la classe n'existait pas — un ecart visible
   a l'oeil, invisible a la lecture du gabarit. */
.ml-1{margin-left:10px}
.mb-6{margin-bottom:6px}
.mb-8{margin-bottom:8px}
.mt-6-d-inline{margin-top:6px;display:inline}
.pad-18{padding:18px}
.pad-20{padding:20px}
.pad-24{padding:24px}
.sp-10{margin-top:10px}
.sp-12{margin-top:12px}
.sp-14{margin-top:14px}
.sp-2{margin-top:2px}
.sp-26{margin-top:26px}
.t-danger{color:var(--verm-ink)}
.u11{font-size:.82rem}
.u21{font-size:.97rem;margin:.6rem 0 0}
.u28{font-size:12px}
.u29{gap:12px}
.u35{margin-bottom:18px}
.u39{margin-top:10px;border-top:1px solid var(--line-2)}
.u4{display:block;max-width:100%}
.u42{margin-top:18px;max-width:70ch}
.u47{margin-top:6px;font-size:.95rem}
.u48{margin:.4rem 0 0}
.u49{margin:.5rem 0 0}
.u51{margin:10px 0 4px}
.u54{max-width:100%}
.u55{max-width:70ch}
.u56{padding:16px}
.u6{display:flex;gap:26px;flex-wrap:wrap}
.u60{width:100%;height:140px;margin-top:10px}
.u61{width:11%}
.u62{width:12%}
.u63{width:13%}
.u64{width:14%}
.u65{width:16%}
.u66{width:18%}
.u67{width:20%}
.u68{width:22%}
.u69{width:26%}
.u7{display:flex;gap:26px;flex-wrap:wrap;align-items:center;justify-content:space-between}
.u70{width:34%}
.u71{width:7%}
.u72{width:8%}

/* déclarations isolées (une occurrence) */
.u4{display:block;max-width:100%}  /* display:block;max-width:100% */
.u6{display:flex;gap:26px;flex-wrap:wrap}  /* display:flex;gap:26px;flex-wrap:wrap */
.u7{display:flex;gap:26px;flex-wrap:wrap;align-items:center;justify-content:space-between}  /* display:flex;gap:26px;flex-wrap:wrap;align-items:center;justify-content:space-between */
.u11{font-size:.82rem}  /* font-size:.82rem */
.u21{font-size:.97rem;margin:.6rem 0 0}  /* font-size:.97rem;margin:.6rem 0 0 */
.u28{font-size:12px}  /* font-size:12px */
.u29{gap:12px}  /* gap:12px */
.u35{margin-bottom:18px}  /* margin-bottom:18px */
.u39{margin-top:10px;border-top:1px solid var(--line-2)}  /* margin-top:10px;border-top:1px solid var(--line-2) */
.u42{margin-top:18px;max-width:70ch}  /* margin-top:18px;max-width:70ch */
.u47{margin-top:6px;font-size:.95rem}  /* margin-top:6px;font-size:.95rem */
.u48{margin:.4rem 0 0}  /* margin:.4rem 0 0 */
.u49{margin:.5rem 0 0}  /* margin:.5rem 0 0 */
.u51{margin:10px 0 4px}  /* margin:10px 0 4px */
.u54{max-width:100%}  /* max-width:100% */
.u55{max-width:70ch}  /* max-width:70ch */
.u56{padding:16px}  /* padding:16px */
.u60{width:100%;height:140px;margin-top:10px}  /* width:100%;height:140px;margin-top:10px */
.u61{width:11%}  /* width:11% */
.u62{width:12%}  /* width:12% */
.u63{width:13%}  /* width:13% */
.u64{width:14%}  /* width:14% */
.u65{width:16%}  /* width:16% */
.u66{width:18%}  /* width:18% */
.u67{width:20%}  /* width:20% */
.u68{width:22%}  /* width:22% */
.u69{width:26%}  /* width:26% */
.u70{width:34%}  /* width:34% */
.u71{width:7%}  /* width:7% */
.u72{width:8%}  /* width:8% */


/* ===== animations.css ===== */
/* ===========================================================
   Whatafter — animations CSS : défilement, survol, entrées.

   Règle tenue partout : on n'anime que `transform` et `opacity`.
   Ces deux propriétés sont composées par le GPU ; animer `width`,
   `top` ou `filter` déclencherait un recalcul de mise en page à
   chaque image, ce qu'un site qui vend la vitesse ne peut pas
   se permettre.

   Deux familles :
     · @keyframes + animation-timeline: view()  → piloté par le défilement
     · transition sur .rev / .revu              → piloté par l'observateur
   =========================================================== */

/* ------------------------------------------------------------------ entrées
   Révélation **en CSS pur**, sans une ligne de JavaScript.

   Le tout est enfermé dans `@supports (animation-timeline: view())` : si le moteur
   ne gère pas les animations pilotées par le défilement, AUCUNE de ces règles ne
   s'applique et le contenu est visible d'emblée. C'est la seule construction qui
   garantit qu'un effet ne peut jamais cacher du contenu — un masquage posé en
   JavaScript laisse toujours la porte ouverte à un script qui ne se charge pas.

   Conséquence assumée : sur un moteur sans `animation-timeline` (Firefox à ce
   jour), la page s'affiche sans effet d'entrée. Elle reste complète et lisible.  */
@keyframes entree {
  from { opacity: .25; transform: translate3d(0, 26px, 0) scale(.985); }
  to   { opacity: 1;   transform: translate3d(0, 0, 0) scale(1); }
}

@keyframes entree-op { from { opacity: .2; } to { opacity: 1; } }

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .rev {
      animation: entree linear both;
      animation-timeline: view();
      animation-range: entry 0% cover 32%;
    }
    /* Certains blocs portent déjà un `transform` écrit par le script (la carte de mesure
       qui suit le pointeur). Pour eux, l'entrée n'anime que l'opacité : deux effets ne
       doivent jamais écrire la même propriété, sinon le dernier gagne et l'autre disparaît. */
    .rev-op {
      animation: entree-op linear both;
      animation-timeline: view();
      animation-range: entry 0% cover 30%;
    }
  }
}

/* ------------------------------------------------------------------ scène 3D */
.scene {
  position: relative;
  perspective: 1400px;          /* la perspective est portée par le parent, jamais par la carte */
  perspective-origin: 50% 40%;
}
.carte3d {
  transform-style: preserve-3d;
  transform: rotateX(0) rotateY(0) translateZ(0);
  transition: box-shadow .4s ease;
  box-shadow: 0 1px 2px rgba(11,18,32,.04), 0 18px 40px -24px rgba(11,18,32,.35);
  backface-visibility: hidden;
}
/* Éléments soulevés dans la profondeur : c'est ce qui se voit au pivotement. */
.carte3d .relief { transform: translateZ(34px); }
.carte3d .relief-2 { transform: translateZ(18px); }

@media (max-width: 899px) {
  .scene { perspective: none; }
  .carte3d { transform: none !important; box-shadow: 0 1px 2px rgba(11,18,32,.04); }
  .carte3d .relief, .carte3d .relief-2 { transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .carte3d { transform: none !important; }
}

/* ------------------------------------------------------------------ champ 3D */
.champ {
  position: relative;
  overflow: hidden;
  background: #f6f7f9;          /* le fond existe sans le canvas : jamais de trou */
  isolation: isolate;
}
.champ canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  opacity: .92;
}
/* voile : garantit le contraste du texte posé sur le champ, en toutes circonstances.
   En theme clair il ECLAIRCIT (le texte est en encre) au lieu d'assombrir, et il est plus
   dense qu'avant : sur fond sombre une courbe passait sous le texte sans gene, sur fond clair
   la meme courbe traverse la ligne de base et fait baisser le contraste. */
.champ::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(105deg, rgba(246,247,249,.97) 0%, rgba(246,247,249,.93) 44%,
                              rgba(246,247,249,.86) 100%);
  pointer-events: none;
}
.champ > .wrap { position: relative; z-index: 2; }
/* Texte du champ : encre froide sur papier. Meme hierarchie qu'ailleurs — les titres en
   pleine encre, le texte courant en encre adoucie, les indications en gris moyen. */
.champ h1, .champ h2, .champ h3 { color: var(--ink); }
.champ .lead { color: var(--ink-2); }
.champ .hint { color: var(--mute); }
.champ .tagline { color: var(--brick-ink); }
/* la carte de saisie reste BLANCHE : c'est elle qui doit ressortir, pas le fond */
.champ .scan { background: #fff; border-color: var(--line); }
.champ .scan input { background: #fff; color: var(--ink); border-color: var(--line); }
.champ .scan input::placeholder { color: var(--mute); }
.champ .check-ligne { color: var(--ink-2); }
.champ .scan .hint { color: var(--mute); }
.champ .scan .hint b { color: var(--ink); }
/* les cartes de chiffres : papier translucide, filet franc */
.champ .metric { background: rgba(255,255,255,.86); border-color: var(--line);
  backdrop-filter: blur(3px); }
.champ .metric .k { color: var(--mute); }
.champ .metric .v { color: var(--ink); }
.champ .metric .v .u { color: var(--mute); }
.champ .metric h3, .champ .metric p { color: var(--ink-2); }
.champ .metric h3 { color: var(--ink); }
/* le vert « revele » etait choisi pour un fond nuit (#7ee2a8, tres clair). Sur papier il
   devient illisible : on prend le vert d'etat du site, celui des constats « info ». */
.champ .metric .v.revele { color: #166534; }
.champ .metric .releve { background: #fff; border-color: var(--line); }
.champ .metric .releve .row { border-color: var(--line-2); }
.champ .metric .releve .k { color: var(--mute); }
.champ .metric .releve .v { color: var(--ink); }
.champ .metric .releve .v.sig { color: var(--brick-ink); }
/* Le rouge d'alerte : #f28b82 etait un corail clair, lisible sur bleu nuit et delave sur
   papier. On prend le rouge d'erreur du site, celui des constats critiques. */
.champ .metric .t-danger { color: var(--verm-ink); }
.champ .metric .hint { color: var(--mute); }
/* Listes a filets : sur fond clair les filets redeviennent des filets, pas des traits qui
   barrent le texte. Meme grammaire que le reste du site. */
.champ .metric .facts { border-top-color: var(--line); }
.champ .metric .facts li { border-bottom-color: var(--line); color: var(--ink-2); }
.champ .metric .facts .n { color: var(--brick-ink); }
/* L'encart : blanc, comme les autres cartes du champ. Un aplat sombre au milieu d'une page
   claire attirerait l'oeil pour rien. */
.champ .metric .note { background: #fff; border-color: var(--line); color: var(--ink-2); }
.champ .metric .note b { color: var(--ink); }

/* ------------------------------------------------------------------ défilement */
@keyframes remplissage { from { transform: scaleX(0); } to { transform: scaleX(1); } }

/* la section des prix se redresse un peu plus tôt : c'est la section de décision */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    #prix .rev { animation-range: entry 0% cover 24%; }
  }
}

/* ------------------------------------------------------------------ repli Firefox
   Firefox ne gère pas encore `animation-timeline` : les blocs s'afficheraient sans effet.
   On offre alors une révélation par transition, pilotée par un observateur de défilement
   placé dans `3d-repli.js`. Ce fichier ne se charge QUE dans ce cas de figure
   (`@supports not`), et il retire tout masquage s'il tombe en panne.

   Pourquoi un second mécanisme plutôt qu'un seul : les animations pilotées par le
   défilement sont composées par le GPU et ne coûtent rien, on ne veut pas s'en priver là
   où elles existent. Le repli est un ajout, pas un remplacement.                    */
@keyframes repli { to { opacity: 1; transform: none; } }

@supports not (animation-timeline: view()) {
  html.repli .rev, html.repli .rev-op {
    opacity: 0;
    transform: translate3d(0, 24px, 0);
    transition: opacity .7s cubic-bezier(.16,1,.3,1), transform .8s cubic-bezier(.16,1,.3,1);
  }
  html.repli .rev-vu, html.repli .rev-vu, html.repli .rev.rev-vu, html.repli .rev-op.rev-vu {
    opacity: 1;
    transform: none;
  }
  /* filet de sécurité : quoi qu'il arrive, tout est visible au bout de 2,5 s */
  html.repli .rev, html.repli .rev-op { animation: repli .6s ease 2.5s forwards; }
}

@media (prefers-reduced-motion: reduce) {
  html.repli .rev, html.repli .rev-op { opacity: 1 !important; transform: none !important;
    transition: none !important; animation: none !important; }
}

/* barre de progression de lecture : transform only */
.progression {
  position: fixed;
  top: 0; left: 0; right: 0;
  height: 2px;
  transform: scaleX(0);
  transform-origin: 0 50%;
  background: var(--brick);
  z-index: 30;
  pointer-events: none;
}
@supports (animation-timeline: scroll()) {
  .progression {
    animation: remplissage linear;
    animation-timeline: scroll(root block);
  }
}
@media (prefers-reduced-motion: reduce) {
  .progression { display: none; }
}

/* ------------------------------------------------------------------ barres 3D
   La comparaison qui vend le produit : « ce que Google peut lire » face à « ce que voit
   un visiteur ». Deux barres en volume, à l'échelle réelle des mots comptés.

   Construites en CSS 3D pur — pas de canvas, pas de bibliothèque : un prisme est fait
   de trois faces (avant, dessus, côté droit), assemblées avec `preserve-3d`. Chaque
   niveau de l'imbrication doit porter `preserve-3d`, sinon les faces sont aplaties.  */
.barres3d {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: 96px;
  height: 300px;
  margin: 0 auto;
  width: fit-content;
  transform-style: preserve-3d;
  /* Deux axes obligatoires : `rotateY` seul met la face du dessus de profil (invisible)
     et le prisme paraît plat. C'est l'inclinaison verticale qui révèle le volume. */
  transform: rotateX(12deg) rotateY(-22deg);
}
/* La chaîne des hauteurs doit être complète : `.barres3d` (300 px) → `.barre-col` (100 %)
   → `.barre3d` (le pourcentage). Sans le 100 % intermédiaire, le pourcentage se résout
   contre une hauteur automatique et les barres tombent à zéro. */
.barre-col { position: relative; transform-style: preserve-3d; height: 100%;
  display: flex; align-items: flex-end; }

.barre3d {
  position: relative;
  width: 84px;
  height: 100%;
  transform-style: preserve-3d;
  background: linear-gradient(180deg, #39424e 0%, #1b2431 100%);
  border-radius: 2px 2px 0 0;
}
.barre3d.google { background: linear-gradient(180deg, #e0596a 0%, #b91c1c 100%); }

/* face du dessus */
.barre3d::before {
  content: "";
  position: absolute;
  left: 0; right: 0; top: 0;
  height: 16px;                       /* la profondeur du prisme */
  background: #6f7d90;
  transform-origin: 50% 0;
  transform: rotateX(90deg);
}
/* face de droite */
.barre3d::after {
  content: "";
  position: absolute;
  top: 0; bottom: 0; right: 0;
  width: 16px;
  background: rgba(11,18,32,.42);
  transform-origin: 100% 50%;
  transform: rotateY(90deg);
}
.barre3d.google { background: linear-gradient(180deg, #e0596a 0%, #b91c1c 100%); }
.barre3d.google::before { background: #f08a95; }
.barre3d.google::after { background: rgba(120,20,20,.45); }

/* le sol, pour que les barres reposent sur quelque chose */
.barres3d .sol {
  position: absolute;
  left: -30px; right: -30px; bottom: -14px;
  height: 14px;
  background: rgba(11,18,32,.10);
  transform-origin: 50% 0;
  transform: rotateX(90deg);
}

.barre-tete {
  position: absolute;
  left: 0; right: 0;
  bottom: 100%;
  margin-bottom: 18px;
  text-align: center;
}
/* Un rapport de 1 à 137 donne une barre de quelques pixels : sans plancher elle se lit
   comme un élément cassé. Le plancher est de 12 px, la proportion reste vraie et le
   rapport est écrit en clair sous le graphique — la disproportion est le message. */
.h12, .h1, .h0 { min-height: 12px; }
.barre-nombre {
  font-size: 1.75rem; font-weight: 650; letter-spacing: -.035em;
  font-variant-numeric: tabular-nums; color: var(--ink); line-height: 1;
}
.barre-nombre.petit { color: var(--verm-ink); }
.barre-nombre .u { font-size: .78rem; font-weight: 500; color: var(--mute); letter-spacing: 0; }
/* Les légendes vivent dans le flux, sous le graphique : en position absolue elles
   recouvraient le paragraphe qui suit. */
.legendes3d {
  display: flex;
  justify-content: center;
  gap: 96px;
  margin-top: 34px;
  text-align: center;
}
.legendes3d > div { width: 170px; font-size: .84rem; color: var(--mute); line-height: 1.4; }
.legendes3d b { display: block; color: var(--ink); font-weight: 600; }

@media (max-width: 700px) {
  .barres3d { height: 220px; gap: 46px; transform: rotateY(-12deg) scale(.92); padding-left: 20px; }
  .barre3d { width: 66px; }
  .barre-nombre { font-size: 1.4rem; }
}

/* ------------------------------------------------------------------ survols */
.metric, .releve { transition: border-color .16s ease, box-shadow .2s ease, transform .2s ease; }
.metric:hover { border-color: #c3ccd6; box-shadow: var(--shadow-lift); }
.btn { transition: background-color .12s, border-color .12s, color .12s, transform .12s; }
.btn.primary:hover { transform: translate3d(0, -1px, 0); }
.sev { transition: transform .16s ease; }
details[open] summary::after { transform: rotate(180deg); }

/* hauteurs en pourcentage — le CSP interdit les styles en ligne */
.h0{height:0%}
.h1{height:1%}
.h2{height:2%}
.h3{height:3%}
.h4{height:4%}
.h5{height:5%}
.h6{height:6%}
.h7{height:7%}
.h8{height:8%}
.h9{height:9%}
.h10{height:10%}
.h11{height:11%}
.h12{height:12%}
.h13{height:13%}
.h14{height:14%}
.h15{height:15%}
.h16{height:16%}
.h17{height:17%}
.h18{height:18%}
.h19{height:19%}
.h20{height:20%}
.h21{height:21%}
.h22{height:22%}
.h23{height:23%}
.h24{height:24%}
.h25{height:25%}
.h26{height:26%}
.h27{height:27%}
.h28{height:28%}
.h29{height:29%}
.h30{height:30%}
.h31{height:31%}
.h32{height:32%}
.h33{height:33%}
.h34{height:34%}
.h35{height:35%}
.h36{height:36%}
.h37{height:37%}
.h38{height:38%}
.h39{height:39%}
.h40{height:40%}
.h41{height:41%}
.h42{height:42%}
.h43{height:43%}
.h44{height:44%}
.h45{height:45%}
.h46{height:46%}
.h47{height:47%}
.h48{height:48%}
.h49{height:49%}
.h50{height:50%}
.h51{height:51%}
.h52{height:52%}
.h53{height:53%}
.h54{height:54%}
.h55{height:55%}
.h56{height:56%}
.h57{height:57%}
.h58{height:58%}
.h59{height:59%}
.h60{height:60%}
.h61{height:61%}
.h62{height:62%}
.h63{height:63%}
.h64{height:64%}
.h65{height:65%}
.h66{height:66%}
.h67{height:67%}
.h68{height:68%}
.h69{height:69%}
.h70{height:70%}
.h71{height:71%}
.h72{height:72%}
.h73{height:73%}
.h74{height:74%}
.h75{height:75%}
.h76{height:76%}
.h77{height:77%}
.h78{height:78%}
.h79{height:79%}
.h80{height:80%}
.h81{height:81%}
.h82{height:82%}
.h83{height:83%}
.h84{height:84%}
.h85{height:85%}
.h86{height:86%}
.h87{height:87%}
.h88{height:88%}
.h89{height:89%}
.h90{height:90%}
.h91{height:91%}
.h92{height:92%}
.h93{height:93%}
.h94{height:94%}
.h95{height:95%}
.h96{height:96%}
.h97{height:97%}
.h98{height:98%}
.h99{height:99%}
.h100{height:100%}

/* ------------------------------------------------------------------ révélation générale
   Les effets ne doivent pas vivre seulement sur l'accueil : chaque page entre de la même
   façon. Plutôt que de semer une classe dans six gabarits — et d'en oublier un — on
   cible la structure, qui est la même partout (`.wrap` est le conteneur de chaque section).

   `:has()` sert à écarter les grilles dont les enfants portent déjà `.rev` : sans cela,
   l'entrée du parent et celle de l'enfant se multiplieraient, et l'opacité finale ne
   serait plus celle écrite.                                                        */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .wrap > h1, .wrap > h2, .wrap > .tagline, .wrap > .lead,
    .wrap > .note, .wrap > .releve, .wrap > .metric, .wrap > .barres3d,
    .wrap > .grid:not(:has(.rev)) {
      animation: entree linear both;
      animation-timeline: view();
      animation-range: entry 0% cover 30%;
    }
    /* le héros de l'accueil gère ses propres blocs : on ne double pas la cascade */
    .champ > .wrap > h1, .champ > .wrap > .grid { animation: none; }
  }
}

/* ------------------------------------------------------------------ colonne latérale
   Sur une page de texte long, une colonne latérale qui reste en haut laisse un vide de
   plusieurs centaines de pixels. Elle suit donc la lecture, avec une limite : elle ne colle
   que si elle tient dans la fenêtre, sinon elle déborderait par le bas. */
.colonne-cote { position: sticky; top: 84px; align-self: start; }
@media (max-width: 899px) {
  .colonne-cote { position: static; }
}
