/* =============================================
   BIZZPLAN — Master Stylesheet
   Système de design v1 — verrouillé le 2026-08-05 après revue de Gauthier.
   Origine : reference/moodboard-identite-visuelle.html (palette + typo) et
   reference/simulation-elements-ui.html (composants) — toute modification de fond
   (nouvelle couleur, nouveau composant) doit d'abord être validée sur ces pages de
   référence avant d'atterrir ici, jamais l'inverse.
   ============================================= */

/* Plus Jakarta Sans / Inter — auto-hébergées (RGPD : zéro tracker externe, cf. convention
   Tikkoun). font-display:fallback : bloque un court instant puis bascule sur le fallback
   système si la police tarde — réduit FOUT/CLS par rapport à 'swap'. */
@font-face { font-family:'BP-Jakarta'; font-style:normal; font-weight:400; font-display:fallback; src:url('fonts/plus-jakarta-sans-400-latin.woff2') format('woff2'); }
@font-face { font-family:'BP-Jakarta'; font-style:normal; font-weight:500; font-display:fallback; src:url('fonts/plus-jakarta-sans-500-latin.woff2') format('woff2'); }
@font-face { font-family:'BP-Jakarta'; font-style:normal; font-weight:600; font-display:fallback; src:url('fonts/plus-jakarta-sans-600-latin.woff2') format('woff2'); }
@font-face { font-family:'BP-Jakarta'; font-style:normal; font-weight:700; font-display:fallback; src:url('fonts/plus-jakarta-sans-700-latin.woff2') format('woff2'); }
@font-face { font-family:'BP-Inter'; font-style:normal; font-weight:400; font-display:fallback; src:url('fonts/inter-400-latin.woff2') format('woff2'); }
@font-face { font-family:'BP-Inter'; font-style:normal; font-weight:500; font-display:fallback; src:url('fonts/inter-500-latin.woff2') format('woff2'); }
@font-face { font-family:'BP-Inter'; font-style:normal; font-weight:600; font-display:fallback; src:url('fonts/inter-600-latin.woff2') format('woff2'); }

/* ── Palette de marque — fixe, ne change pas avec le thème ─────────────────── */
:root {
  --navy: #1E3A8A;
  --anthracite: #333333;
  --indigo: #4C1D95;
  --indigo-light: #B49CF2; /* repère sur fond anthracite fixe (nav) — jamais un accent général */
  --sage: #0F766E;
  --sage-soft: #64748B; /* "gris vert" */
  --ivoire: #F8FAFC;
}

/* ── Usage sémantique — duo "Autorité" (clair) / "Confiance sombre" (sombre) ── */
:root {
  --bg: #F8FAFC;
  --surface: #FFFFFF;
  --text: #333333;
  --text-soft: #5B6069;
  --accent: #4C1D95;
  --accent-contrast: #F8FAFC;
  --secondary: #1E3A8A; /* second niveau d'action, pas un état "cliqué" de l'accent */
  --success: #0F766E;
  --success-contrast: #F8FAFC;
  --danger: #B91C1C;
  --danger-contrast: #F8FAFC;
  --line: rgba(51, 51, 51, 0.14);
  --line-strong: rgba(51, 51, 51, 0.26);
  --focus-ring: #4C1D95;
  --select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235B6069' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");

  /* Triad "feu tricolore" — réservée aux stress-tests / validation de KPI financiers
     (cf. .kpi-*), jamais à un message d'interface générique. --kpi-caution (jaune) ajouté
     2026-08-20 (retour Gauthier — gradient à 4 paliers rouge/orange/jaune/vert pour
     niveau_couverture_tresorerie, cf. engine/stress_tests.py bizzplan-api) : orange et jaune
     sont désormais 2 paliers distincts d'alerte non bloquante, entre --kpi-warn (orange,
     coussin < 50 % du cash-burn) et --kpi-go (vert, coussin confortable). */
  --kpi-go: #16A34A;
  --kpi-warn: #F97316;
  --kpi-caution: #EAB308;
  --kpi-stop: #B91C1C;
  --kpi-contrast: #F8FAFC;

  /* La palette des graphiques empilés (js/charts.js § 14.5) est passée d'un jeu de 6
     couleurs dédiées ici (--chart-2..6, insuffisant dès qu'une sélection dépassait 6
     lignes, retour Gauthier 2026-08-14) à 22 teintes générées en HSL directement côté JS
     (couleurEmpilee()) — un jeu de 22×2 thèmes aurait été disproportionné à maintenir ici. */

  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2.5rem;
  --radius-sm: 2px;
  --radius: 4px; /* anguleux et net par défaut — registre "document financier" ; la seule
                     exception assumée est .icon-tile (voir plus bas) */
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #1E3A8A;
    --surface: #16295E;
    --text: #F8FAFC;
    --text-soft: #C3CCE8;
    --accent: #B49CF2;
    --accent-contrast: #1A1032;
    --secondary: #7C93E0;
    --success: #2DD4BF;
    --success-contrast: #0B1220;
    --danger: #F87171;
    --danger-contrast: #2A0A0A;
    --line: rgba(248, 250, 252, 0.16);
    --line-strong: rgba(248, 250, 252, 0.3);
    --focus-ring: #B49CF2;
    --select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23C3CCE8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
    --kpi-go: #4ADE80;
    --kpi-warn: #FB923C;
    --kpi-caution: #FACC15;
    --kpi-stop: #F87171;
    --kpi-contrast: #1A1300;
  }
}
/* Le toggle de thème (si ajouté un jour côté BizzPlan) stampe data-theme sur <html> —
   doit gagner dans les deux sens sur la préférence système, cf. règles Artifact déjà
   appliquées sur les pages de référence. */
:root[data-theme="dark"] {
  --bg: #1E3A8A;
  --surface: #16295E;
  --text: #F8FAFC;
  --text-soft: #C3CCE8;
  --accent: #B49CF2;
  --accent-contrast: #1A1032;
  --secondary: #7C93E0;
  --success: #2DD4BF;
  --success-contrast: #0B1220;
  --danger: #F87171;
  --danger-contrast: #2A0A0A;
  --line: rgba(248, 250, 252, 0.16);
  --line-strong: rgba(248, 250, 252, 0.3);
  --focus-ring: #B49CF2;
  --select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23C3CCE8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  --kpi-go: #4ADE80;
  --kpi-warn: #FB923C;
  --kpi-caution: #FACC15;
  --kpi-stop: #F87171;
  --kpi-contrast: #1A1300;
}
:root[data-theme="light"] {
  --bg: #F8FAFC;
  --surface: #FFFFFF;
  --text: #333333;
  --text-soft: #5B6069;
  --accent: #4C1D95;
  --accent-contrast: #F8FAFC;
  --secondary: #1E3A8A;
  --success: #0F766E;
  --success-contrast: #F8FAFC;
  --danger: #B91C1C;
  --danger-contrast: #F8FAFC;
  --line: rgba(51, 51, 51, 0.14);
  --line-strong: rgba(51, 51, 51, 0.26);
  --focus-ring: #4C1D95;
  --select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235B6069' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  --kpi-go: #16A34A;
  --kpi-warn: #F97316;
  --kpi-caution: #EAB308;
  --kpi-stop: #B91C1C;
  --kpi-contrast: #F8FAFC;
}

/* ── Reset & base ────────────────────────────────────────────────────────── */

*, *::before, *::after { box-sizing: border-box; }

html { font-size: 16px; }
/* Défilement animé vers les ancres (2026-08-19, retour Gauthier § Récapitulatif — sommaire
   de navigation ancrée) — bénéficie aussi au scrollspy existant de js/stepper.js sur les
   écrans du wizard, jamais scindé par écran. Respecte prefers-reduced-motion. */
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: 'BP-Jakarta', -apple-system, sans-serif;
  font-size: 1rem;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  /* Menu principal fixe (2026-08-11, retour Gauthier — "reste visible en toutes
     circonstances") : --nav-h a une valeur de repli statique ici, réécrite par js/nav.js
     avec la hauteur réellement mesurée dès l'injection du menu (robuste au retour à la
     ligne des liens sur mobile, jamais un nombre en dur qui pourrait dériver). */
  padding-top: var(--nav-h, 60px);
}

/* Inter réservé aux données denses (saisie, chiffres tabulaires) — Plus Jakarta Sans porte
   tout le reste, y compris les paragraphes d'intro/aide (.lead/.section-intro/.alert-msg/
   .hint/.error-msg) : c'est la police retenue, elle doit se voir partout, pas seulement sur
   les titres. Portée resserrée le 2026-08-19 (retour Gauthier — Inter apparaissait "hors des
   tableaux PF", ex. le paragraphe d'intro de récapitulatif.html) : cette règle couvrait
   auparavant aussi les paragraphes de texte, jamais l'intention documentée ci-dessus. */
.field input, .field select,
td, th.num {
  font-family: 'BP-Inter', -apple-system, sans-serif;
}

code {
  font-family: ui-monospace, 'SF Mono', Menlo, monospace;
  font-size: 0.85em;
}

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

/* ── Typographie de base ─────────────────────────────────────────────────── */

.eyebrow {
  font-family: 'BP-Inter', sans-serif;
  font-weight: 600;
  font-size: 0.78rem;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 0.4rem;
}
/* Nom du projet — un 3e niveau distinct de l'eyebrow (toujours "PROJET", court et fixe)
   et du h1 (titre de l'écran) : une majuscule/espacé large convient à un mot-clé fixe,
   pas à un nom de longueur variable. Casse normale, taille intermédiaire, tronqué proprement
   plutôt que de risquer un nom d'entreprise long sur 2 lignes en petites capitales. */
.project-context {
  font-family: 'BP-Inter', sans-serif;
  font-size: 1.2rem;
  font-weight: 600;
  color: var(--accent);
  margin: 0 0 0.6rem;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

h1 {
  font-family: 'BP-Jakarta', sans-serif;
  font-weight: 700;
  font-size: clamp(1.75rem, 4vw, 2.4rem);
  line-height: 1.1;
  letter-spacing: -0.01em;
  margin: 0 0 1rem;
  text-wrap: balance;
}

h2 {
  font-family: 'BP-Jakarta', sans-serif;
  font-weight: 700;
  font-size: clamp(1.3rem, 3vw, 1.6rem);
  letter-spacing: -0.005em;
  margin: 0 0 0.5rem;
}

.lead {
  max-width: 44em;
  font-size: 1.05rem;
  color: var(--text-soft);
  margin: 0;
}

/* .lead-large (2026-08-24, retour Gauthier — "la largeur du bloc d'intro est figée sur celle
   du menu... adapter à la largeur active de la vue") : le plafond de 44em ci-dessus (pensé
   pour le confort de lecture) laissait le lead visiblement plus étroit que le contenu qu'il
   introduit. D'abord posée sur synthese.html/business-plan.html (.cockpit-shell large), puis
   étendue le même jour (2e retour Gauthier — "toutes sous-vue du Wizard") aux 10 écrans de
   configuration (formulaire + tableau des lignes déjà saisies, souvent plus large que 44em) —
   Additive, jamais posée sur .lead directement. Seules mon-compte.html (page de connexion,
   contenu volontairement étroit) et recapitulatif.html (pas de .cockpit-shell, cf. son propre
   commentaire de fichier) gardent le plafond de lecture 44em. */
.lead-large { max-width: 100%; }

.section-intro {
  max-width: 42em;
  color: var(--text-soft);
  font-size: 0.94rem;
  margin: 0 0 1.6rem;
}

/* ── Layout ──────────────────────────────────────────────────────────────── */

.wrap {
  max-width: 1040px;
  margin: 0 auto;
  padding: clamp(2rem, 5vw, 4rem) clamp(1.25rem, 4vw, 2rem) 5rem;
}
/* Pages wizard : stepper sticky present → padding-top reduit (clamp trop grand sur grand ecran) */
body:has(.stepper-sticky) .wrap { padding-top: 1.25rem; }

/* ── Icônes ──────────────────────────────────────────────────────────────── */
/* Sprite chargé par js/icons.js (symbols Lucide-style, ligne claire) — jamais d'emoji. */

.icon {
  width: 1em;
  height: 1em;
  stroke: currentColor;
  fill: none;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  flex-shrink: 0;
  vertical-align: -0.15em;
}

/* Contenant carré à coins arrondis pour un picto isolé (empty states, mise en avant
   de fonctionnalité...) — SEULE exception documentée au registre anguleux de la page :
   composants structurels (cartes, tableaux, nav, boutons) restent nets. */
.icon-tile {
  width: 3.25rem;
  height: 3.25rem;
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.icon-tile .icon { width: 1.5rem; height: 1.5rem; }
.icon-tile-navy { background: var(--navy); color: var(--ivoire); }
.icon-tile-indigo { background: var(--indigo); color: var(--ivoire); }
.icon-tile-sage { background: var(--sage); color: var(--ivoire); }
.icon-tile-anthracite { background: var(--anthracite); color: var(--ivoire); }
.icon-tile-sagesoft { background: var(--sage-soft); color: var(--ivoire); }
.icon-tile-ivoire { background: var(--ivoire); color: var(--anthracite); border: 1px solid var(--line-strong); }
/* Indigo clair (2026-08-25, retour Gauthier — comment-ca-marche.html : "indigo clair... et
   d'alterner avec l'indigo foncé un pictogramme sur deux") — .icon-tile-indigo (déjà
   existante) sert de variante foncée, jamais dupliquée. */
.icon-tile-indigo-clair { background: var(--indigo-light); color: var(--indigo); }

/* Photo de profil — même exception que .icon-tile (un visage se lit mieux adouci). */
.founder-photo {
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 50%;
  object-fit: cover;
  flex-shrink: 0;
  border: 1px solid var(--line);
}

/* ── Navigation ──────────────────────────────────────────────────────────── */
/* Fusion vitrine + app (2026-08-25, retour Gauthier — "menu full-white, on
   abandonne l'anthracite") : un seul nav-bar, servi par js/nav.js sur TOUTES
   les pages (marketing et app). Suit désormais les tokens sémantiques
   (--surface/--text/--accent), donc le même comportement clair/sombre que le
   reste du site — l'ancienne exception "fixe quel que soit le thème" est
   abandonnée avec l'anthracite. .nav-links sert aux deux contextes (liens
   marketing centrés OU Tableau de bord/Nouveau projet/Mon compte à droite) ;
   .nav-links-center porte en plus le repli mobile (masqué <720px), réservé
   aux liens marketing pour ne pas faire disparaître le menu app sur mobile. */

.nav-bar {
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  padding: var(--space-3) var(--space-5);
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 50;
  box-sizing: border-box;
}
/* nav-inner : reproduit EXACTEMENT le même modèle de boîte que .mkt-hero > .mkt-inner
   (padding sur le parent pleine largeur, max-width:1040px non paddé et centré à
   l'intérieur) pour que le logo/menu démarrent à l'aplomb pixel-parfait du texte des pages
   (retour Gauthier 2026-08-25 — l'ancien padding fixe de .nav-bar, non centré, décalait le
   menu par rapport à la marge réelle du contenu dès que le viewport dépassait 1040px ; une
   1ère tentative avec padding+box-sizing:border-box directement sur .nav-inner restait
   décalée de 24px, un modèle de boîte différent de .mkt-inner). */
.nav-inner {
  max-width: 1040px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* gap (2026-08-26, retour Gauthier — le picto de mode "étouffe" contre le CTA) : les
     marges auto (.nav-links / .nav-links-center) n'absorbent l'espace libre QUE du côté où
     elles sont posées — rien ne séparait le picto du CTA juste après lui (0px mesuré). gap
     garantit un espacement minimal entre CHAQUE paire d'éléments adjacents, sans perturber
     les marges auto existantes (les deux mécanismes se cumulent plutôt que s'annuler). */
  gap: var(--space-4);
}
/* Filet de sécurité (2026-08-27, audit mobile) : si le contenu de la barre dépasse malgré
   tout la largeur disponible sur un très petit écran, le dernier élément (le CTA côté
   marketing, le dropdown "Mon compte" côté app) redescend proprement à la ligne plutôt que
   de déborder hors du viewport et forcer un scroll horizontal sur toute la page. */
@media (max-width: 400px) {
  .nav-inner { flex-wrap: wrap; row-gap: var(--space-2); }
}
.nav-brand {
  font-family: 'BP-Jakarta', sans-serif;
  font-weight: 700;
  font-size: 1.05rem;
  letter-spacing: -0.01em;
  color: var(--text);
  text-decoration: none;
}
/* margin-left:auto (2026-08-26, ajout du toggle 3 modes) : pousse .nav-links — et tout ce
   qui le suit dans .nav-inner, désormais le toggle — contre le bord droit côté nav app (2
   items avant : brand + nav-links, déjà positionnés par justify-content:space-between,
   inchangé visuellement ; en ajouter un 3e sans cette marge les aurait répartis en 3 tiers
   égaux). Sans effet côté marketing : .nav-links-center définit son propre margin-left
   (var(--space-6)) qui prévaut, cf. commentaire juste en dessous. */
.nav-links { display: flex; align-items: center; gap: var(--space-5); list-style: none; margin: 0; padding: 0; margin-left: auto; }
/* nav-links-center (marketing) : malgré son nom hérité, elle doit border immédiatement le
   logo à gauche (retour Gauthier 2026-08-25 — "on aligne le menu à gauche"), jamais centrée
   dans .nav-bar. La marge auto absorbe l'espace libre à sa droite avant que justify-content
   ne s'applique, ce qui pousse .nav-cta seul vers la droite sans toucher au nav app (2
   éléments, pas de .nav-links-center, donc inchangé par cette règle). */
.nav-links-center { margin-right: auto; margin-left: var(--space-6); }
.nav-links a {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-family: 'BP-Jakarta', sans-serif;
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--text-soft);
  text-decoration: none;
  padding-bottom: 2px;
  border-bottom: 2px solid transparent;
}
.nav-links a:hover { color: var(--accent); }
.nav-links a.active { color: var(--accent); border-bottom-color: var(--accent); font-weight: 600; }
.nav-links a:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
/* Bouton hamburger (2026-08-27, audit mobile) — masqué par défaut, visible seulement sous
   720px (breakpoint inverse de .nav-links-center juste en dessous) : sans lui, les liens
   marketing (Fonctionnalités/Comment ça marche/Tarifs/Obligations légales) devenaient
   totalement inaccessibles sous 720px, sans AUCUN accès alternatif — jamais remarqué
   jusqu'ici car l'audit portait sur les pages app, pas la vitrine (retour Gauthier, capture
   DevTools accueil). Même registre visuel que .nav-icon-btn (picto circulaire), mais
   rectangulaire pour se distinguer visuellement du bouton engrenage à côté duquel il vit. */
.nav-menu-toggle {
  display: none;
  align-items: center; justify-content: center;
  width: 2.1rem; height: 2.1rem;
  border: 1px solid var(--line); border-radius: 8px;
  background: var(--ivoire); color: var(--anthracite);
  cursor: pointer; flex-shrink: 0;
}
.nav-menu-toggle .icon { width: 1.15rem; height: 1.15rem; }
.nav-menu-toggle:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
/* Respiration Hamburger→Engrenage (2026-09-02, retour Gauthier — "espace de respiration
   entre les deux") — au-delà du gap:0.3rem déjà posé par .nav-actions, jamais suffisant
   entre 2 pictos aussi proches visuellement. Scopé à .nav-actions (nav vitrine uniquement,
   seul contexte où .nav-menu-toggle vit à côté de l'engrenage). */
.nav-actions .nav-menu-toggle { margin-right: 0.35rem; }
html[data-nav="indigo"] .nav-menu-toggle { background: transparent; border-color: rgba(255,255,255,0.35); color: var(--accent-contrast, #fff); }
@media (max-width: 720px) {
  .nav-menu-toggle { display: flex; }
  /* .nav-bar (position:fixed) sert de bloc conteneur pour ce panneau, même s'il est niché
     dans .nav-inner — un ancêtre position:fixed est un conteneur positionné valide au sens
     CSS, aucun position:relative supplémentaire à poser. Panneau plein-largeur ouvert/fermé
     via la classe .open (posée en JS au clic, cf. js/nav.js::wireMarketingMenuToggle) —
     jamais en :hover/:focus-within seul (motif de .dropdown-panel, inutilisable au clic
     tactile qui ne déclenche pas :hover de façon fiable sur mobile). */
  .nav-links.nav-links-center {
    display: none; flex-direction: column; align-items: stretch; gap: 0;
    position: absolute; top: 100%; left: 0; right: 0;
    background: var(--surface); border-bottom: 1px solid var(--line);
    box-shadow: 0 10px 28px rgba(10, 8, 20, 0.14);
    padding: var(--space-2) var(--space-5); margin: 0;
  }
  .nav-links.nav-links-center.open { display: flex; }
  .nav-links.nav-links-center a { padding: var(--space-3) 0; border-bottom: 1px solid var(--line); }
  .nav-links.nav-links-center li:last-child a { border-bottom: none; }
  /* Mode Indigo (retour Gauthier — "dans le mode Goutte, le drop-down est invisible") :
     html[data-nav="indigo"] .nav-links > li > a (plus haut dans ce fichier) colore le texte
     en quasi-blanc (--accent-contrast), pensé pour la nav du haut sur fond indigo plein —
     ce panneau, lui, s'ouvre sur fond clair (var(--surface)) même en mode Indigo, jamais
     teinté indigo lui-même (mêmes couleurs de contenu qu'en mode clair). Texte blanc sur
     fond blanc = invisible. Spécificité de sélecteur suffisante (2 classes ici contre 1 sur
     la règle du haut) pour l'emporter sans !important. */
  html[data-nav="indigo"] .nav-links.nav-links-center > li > a { color: var(--text-soft); border-bottom-color: var(--line); }
  html[data-nav="indigo"] .nav-links.nav-links-center > li > a:hover,
  html[data-nav="indigo"] .nav-links.nav-links-center > li > a.active { color: var(--accent); border-bottom-color: var(--accent); }
}

/* Nav app sous 480px (2026-08-27, audit mobile) — "Tableau de bord"/"Nouveau projet" en
   texte plein débordaient largement le viewport (aucun traitement responsive jusqu'ici,
   contrairement à .nav-links-center ci-dessus). Icônes seules + nom accessible via
   aria-label (posé sur navLink(), jamais un aria-label différent du texte masqué) — jamais
   de perte fonctionnelle, juste une densité visuelle réduite.
   Scopé à :not(.nav-links-center) (2026-08-27, correctif same-day) — navLink() est
   PARTAGÉE entre nav app et nav marketing (js/nav.js), .nav-link-label enveloppe donc aussi
   les liens du menu hamburger marketing ; contrairement au nav app, ces liens n'ont AUCUNE
   icône (iconId=null dans buildMarketingLinks()) — un simple display:none non scopé
   vidait tout le panneau ouvert de son texte, ne laissant que des lignes vides (retour
   Gauthier, capture accueil "menu disparu" — root cause exacte du panneau blanc). */
@media (max-width: 480px) {
  .nav-links:not(.nav-links-center) .nav-link-label { display: none; }
  .nav-links:not(.nav-links-center) { gap: var(--space-3); }
}

/* Groupe des icônes droite de la nav (2026-09-01, retour Gauthier — "regrouper les 3 icônes
   droite dans un seul bouton engrenage" ; anciennement .nav-toggles avec 3 pictos
   langue/mode/accessibilité, cf. git history). WRAPPER OBLIGATOIRE : sans ce div flex, le
   justify-content:space-between de .nav-inner éparpillerait les icônes sur toute la largeur
   au lieu de les coller ensemble contre le bord droit — gap:0.3rem (pas var(--space-3)) pour
   rester au ras des pictos, même pattern que tikkoun-website/css/style.css::.nav-actions.
   margin-left:auto propre au groupe (nav app, sans .nav-links-center à côté). */
.nav-actions { display: flex; align-items: center; gap: 0.3rem; margin-left: auto; flex-shrink: 0; }
.nav-cta { display: flex; align-items: center; gap: var(--space-4); }

/* CTA marketing sous 480px : texte raccourci (même lien, même intention) plutôt qu'icône
   seule — contrairement aux liens de nav ci-dessus, cette action a besoin de rester
   explicite (c'est LE bouton d'action principal des 5 pages marketing).
   flex-basis:100% sous 720px (2026-08-27, retour Gauthier — capture fonctionnalites.html,
   CTA débordant à droite du cluster .nav-actions) : même leçon que le fil d'Ariane des
   pages Projet (commit ada4567) — compter sur le calcul naturel de flex-wrap ("est-ce que
   ça tient sur cette ligne") est fragile au pixel près. Passage déterministe à la ligne,
   comme "Imprimer/PDF"/"Compiler le PDF final" sur les pages Projet. */
@media (max-width: 720px) {
  #nav-marketing-cta { flex-basis: 100%; }
}
@media (max-width: 480px) {
  #nav-marketing-cta .btn { padding: 0.55rem 0.85rem; font-size: 0.82rem; }
}

/* ── Bouton d'icône générique de la nav (engrenage) — même gabarit que l'ancien .ui-mode-btn
   (2.1rem, cercle var(--ivoire)/var(--anthracite)) — badge toujours clair, jamais théorisé
   par le thème actif, pour rester lisible quel que soit le mode en cours (y compris sur une
   nav déjà indigo ou déjà sombre). */
.nav-icon-btn {
  display: flex; align-items: center; justify-content: center; width: 2.1rem; height: 2.1rem;
  border: 1px solid var(--line); border-radius: 50%; background: var(--ivoire); color: var(--anthracite);
  cursor: pointer; flex-shrink: 0; transition: transform 0.15s ease, border-color 0.15s ease;
}
.nav-icon-btn .icon { width: 1.05rem; height: 1.05rem; }
.nav-icon-btn:hover { transform: scale(1.08); border-color: var(--indigo); }
.nav-icon-btn:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }

/* ── Variante "Connexion" (2026-09-27) — bouton-icône teinté en --accent plutôt que le cercle
   ivoire/anthracite neutre de l'engrenage, pour rester distinguable (une action de navigation
   directe, pas un panneau de préférences). Remplace l'ancien lien texte "Connexion" en
   btn-outline, illisible sur la nav en mode Indigo (--line-strong quasi invisible sur fond
   indigo — même retour Gauthier que le CTA .btn-primary ci-dessous, déjà inversé pour ce mode).
   Même inversion accent/accent-contrast en mode Indigo pour rester lisible dans ce thème. */
.nav-icon-btn-accent { background: var(--accent); color: var(--accent-contrast); border-color: transparent; }
.nav-icon-btn-accent:hover { border-color: var(--accent-contrast); }
html[data-nav="indigo"] .nav-icon-btn-accent { background: var(--accent-contrast); color: var(--accent); }

/* ── Panneau de préférences (2026-09-01) — regroupe Langue/Mode/Accessibilité, remplace les
   3 boutons circulaires précédents (.lang-switch-btn/.ui-mode-btn/.a11y-toggle). Port du
   pattern gear-panel de tikkoun-website/css/style.css (.nav-gear-wrap/.nav-gear-panel/
   .gp-*), adapté aux tokens BizzPlan — panneau toujours sur fond clair (var(--surface)),
   même en mode Indigo, jamais teinté lui-même (même convention que .dropdown-panel/
   .nav-links-center mobile, cf. commentaires plus haut dans ce fichier). */
.nav-gear-wrap { position: relative; display: inline-flex; align-items: center; }
/* Pont invisible (2026-09-27, retour Gauthier — le panneau se referme si la souris traverse
   trop lentement l'espace entre l'icône et le panneau) : top:calc(100% + 8px) ci-dessous laisse
   un espace mort qui n'appartient ni au déclencheur ni au panneau — :hover se perd pendant la
   traversée. Ce pseudo-élément (position:absolute, donc jamais dans le flux — n'agrandit pas la
   boîte du wrapper ni ne décale l'icône) couvre exactement cet espace ; comme il reste un
   descendant de .nav-gear-wrap, le survoler maintient :hover sur tout le wrapper. */
.nav-gear-wrap::after { content: ''; position: absolute; left: 0; right: 0; top: 100%; height: 8px; }
.nav-gear-panel {
  position: absolute; top: calc(100% + 8px); right: 0; width: 220px;
  /* max-width borné au viewport (2026-09-02, audit responsive 275px) — right:0 ancre déjà le
     bord DROIT du panneau à l'intérieur de .nav-bar (jamais de débordement à droite), mais
     rien ne bornait le bord GAUCHE : sous ~270px, les 220px fixes pouvaient dépasser le bord
     gauche du viewport. calc(100vw - 2rem) garantit une marge de 1rem de chaque côté quelle
     que soit la largeur — no-op sur desktop (toujours très supérieur à 220px). */
  max-width: calc(100vw - 2rem);
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 0.65rem 0.8rem; box-shadow: 0 10px 28px rgba(10, 8, 20, 0.14);
  opacity: 0; pointer-events: none; transform: translateY(-6px);
  transition: opacity 0.16s ease, transform 0.16s ease; z-index: 200;
}
/* Survol pur (2026-09-27, retour Gauthier) — un essai de clic-épinglage (.open, ajouté/retiré en
   JS) a été retiré le même jour : ambigu à l'usage, il fallait re-cliquer pour refermer sinon le
   menu restait ouvert. Même logique simple que .nav-item-dropdown ci-dessous : :hover/:focus-
   within scopés au wrapper (.nav-gear-wrap), aucun état géré en JS. */
.nav-gear-wrap:hover .nav-gear-panel,
.nav-gear-wrap:focus-within .nav-gear-panel { opacity: 1; pointer-events: auto; transform: translateY(0); }
.gp-row { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; padding: 0.4rem 0; }
.gp-row + .gp-row { border-top: 1px solid var(--line); }
.gp-lbl { font-size: 0.68rem; font-weight: 600; color: var(--text-soft); letter-spacing: .04em; text-transform: uppercase; flex-shrink: 0; }
/* Segmented (Langue FR/NL/EN texte, Mode Clair/Indigo/Sombre en icônes) — l'option active
   reçoit pointer-events:none EN CSS (via .gp-on), jamais géré côté JS, pour ne jamais
   naviguer sur soi-même (Langue = vrais liens <a>) ni redéclencher inutilement le mode déjà
   actif. */
.gp-seg { display: flex; border: 1px solid var(--line); border-radius: 20px; overflow: hidden; }
.gp-seg-opt {
  font-family: 'BP-Jakarta', sans-serif; font-size: 0.68rem; font-weight: 700; letter-spacing: .02em;
  padding: 0.22rem 0.55rem; color: var(--text-soft); text-decoration: none;
  background: none; border: none; cursor: pointer; transition: background 0.15s ease, color 0.15s ease;
}
.gp-seg-opt:hover { color: var(--indigo); }
.gp-seg-opt.gp-on { background: var(--indigo-light); color: var(--indigo); pointer-events: none; cursor: default; }
/* Mode — mêmes icônes que l'ancien .ui-mode-btn cyclique (i-sun/i-droplet/i-moon), jamais de
   texte : reprend le vocabulaire visuel déjà connu des utilisateurs (retour Gauthier). */
.gp-seg-icons .gp-seg-opt { display: flex; align-items: center; justify-content: center; padding: 0.32rem 0.6rem; }
.gp-seg-icons .gp-seg-opt .icon { width: 0.95rem; height: 0.95rem; }
/* Accessibilité — binaire −/+, seul vrai toggle du panneau (contrairement à Langue/Mode,
   segmented à 3 options). SÉLECTEUR ~ (frère général) OBLIGATOIRE — jamais + (frère
   adjacent) : les 2 <span class="gp-tgl-side"> intercalés entre l'input et .gp-track
   casseraient le mouvement du curseur avec un +. */
.gp-tgl { display: flex; align-items: center; gap: 0.4rem; cursor: pointer; }
.gp-tgl input { position: absolute; opacity: 0; width: 0; height: 0; }
.gp-track { width: 30px; height: 14px; border-radius: 7px; background: var(--line); border: 1px solid var(--line); position: relative; transition: background 0.15s ease; flex-shrink: 0; }
.gp-track::after { content: ''; position: absolute; top: 1px; left: 1px; width: 10px; height: 10px; border-radius: 50%; background: var(--text-soft); transition: transform 0.15s ease, background 0.15s ease; }
.gp-tgl input:checked ~ .gp-track { background: var(--indigo-light); border-color: var(--indigo); }
.gp-tgl input:checked ~ .gp-track::after { transform: translateX(16px); background: var(--indigo); }
.gp-tgl-side { color: var(--text-soft); display: flex; align-items: center; flex-shrink: 0; line-height: 1; font-size: 0.8rem; font-weight: 700; }

html[data-nav="indigo"] .nav-bar { background: var(--accent); border-bottom-color: transparent; }
html[data-nav="indigo"] .nav-brand { color: var(--accent-contrast); }
/* Combinateur enfant direct ">"  — jamais ".nav-links a" (bug réel trouvé le 2026-08-27,
   retour Gauthier : dropdown illisible en mode Indigo). ".dropdown-panel a" (Profil/
   Abonnement/Déconnexion) est un DESCENDANT de .nav-links (imbriqué dans le <li> "Mon
   compte") mais reste sur un fond clair (--surface) même en mode Indigo — un sélecteur
   descendant lui appliquait par erreur le texte quasi blanc de la nav, illisible sur son
   propre fond blanc. ">" ne cible que le lien direct de chaque <li> (liens de nav + le
   déclencheur "Mon compte"), jamais les liens du panneau qui s'ouvre en dessous. */
html[data-nav="indigo"] .nav-links > li > a { color: color-mix(in srgb, var(--accent-contrast) 78%, transparent); }
html[data-nav="indigo"] .nav-links > li > a:hover,
html[data-nav="indigo"] .nav-links > li > a.active { color: var(--accent-contrast); border-bottom-color: var(--accent-contrast); }
html[data-nav="indigo"] .nav-cta .btn-primary { background: var(--accent-contrast); color: var(--accent); }
html[data-nav="indigo"] .nav-cta .btn-primary:hover { filter: brightness(0.95); }

html[data-nav="indigo"] .footer { background: var(--accent); border-top-color: transparent; }
html[data-nav="indigo"] .footer-brand .nav-brand { color: var(--accent-contrast); }
html[data-nav="indigo"] .footer-brand p { color: color-mix(in srgb, var(--accent-contrast) 76%, transparent); }
html[data-nav="indigo"] .footer-col h4 { color: var(--accent-contrast); }
html[data-nav="indigo"] .footer-links a { color: color-mix(in srgb, var(--accent-contrast) 78%, transparent); }
html[data-nav="indigo"] .footer-links a:hover { color: var(--accent-contrast); }
html[data-nav="indigo"] .footer-bottom { border-top-color: color-mix(in srgb, var(--accent-contrast) 25%, transparent); }
html[data-nav="indigo"] .footer-bottom p { color: color-mix(in srgb, var(--accent-contrast) 76%, transparent); }
html[data-nav="indigo"] .footer-bottom a { color: color-mix(in srgb, var(--accent-contrast) 88%, transparent); }
html[data-nav="indigo"] .footer-bottom a:hover { color: var(--accent-contrast); }

.nav-item-dropdown { position: relative; }
/* Pont invisible — même correctif que .nav-gear-wrap::after ci-dessus, taille ajustée au
   margin-top: 0.6rem de .dropdown-panel plus bas. */
.nav-item-dropdown::after { content: ''; position: absolute; left: 0; right: 0; top: 100%; height: 0.6rem; }
.dropdown-panel {
  position: absolute;
  top: 100%;
  right: 0;
  margin-top: 0.6rem;
  min-width: 190px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  display: none;
  flex-direction: column;
  box-shadow: 0 10px 28px rgba(10, 8, 20, 0.14);
  z-index: 10;
}
.nav-item-dropdown:hover .dropdown-panel,
.nav-item-dropdown:focus-within .dropdown-panel { display: flex; }
.dropdown-panel a {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.65rem 1rem;
  font-size: 0.86rem;
  font-weight: 500;
  color: var(--text-soft);
  border-bottom: none;
}
.dropdown-panel a:hover, .dropdown-panel a:focus-visible {
  background: var(--bg);
  color: var(--accent);
  outline: none;
}

/* ── Boutons ─────────────────────────────────────────────────────────────── */

.btn {
  font-family: 'BP-Jakarta', sans-serif;
  font-weight: 600;
  font-size: 0.9rem;
  border: 1px solid transparent;
  padding: 0.65rem 1.15rem;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  text-decoration: none;
  transition: background 0.12s ease, border-color 0.12s ease, color 0.12s ease;
}
.btn:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.btn-sm { padding: 0.4rem 0.8rem; font-size: 0.82rem; }

.btn-primary { background: var(--accent); color: var(--accent-contrast); }
.btn-primary:hover { filter: brightness(1.1); }
.btn-primary:active { filter: brightness(0.92); }
.btn-primary:disabled { opacity: 0.4; cursor: not-allowed; filter: none; }

/* Secondaire = navy (--secondary), délibérément une couleur distincte plutôt qu'un
   indigo assombri : un second niveau d'action (ex. "enregistrer" à côté de "payer"),
   pas un état "cliqué" du primaire — changer de teinte au clic brouillerait identité
   et état. --secondary s'éclaircit en thème sombre (le fond de page y est déjà navy). */
.btn-secondary { background: transparent; color: var(--secondary); border-color: var(--secondary); }
.btn-secondary:hover { background: var(--secondary); color: var(--bg); }
.btn-secondary:disabled { opacity: 0.4; cursor: not-allowed; }

.btn-ghost { background: transparent; color: var(--text-soft); }
.btn-ghost:hover { color: var(--text); background: var(--line); }
.btn-ghost:disabled { opacity: 0.4; cursor: not-allowed; }

/* .btn-outline — variante neutre (bordure --line-strong) pour une action utilitaire à
   côté d'une action primaire (ex. "Reproduire" à côté de "Arrêter"). N'avait jamais été
   définie (bug réel trouvé le 2026-08-12, retour Gauthier) : le bouton n'héritait que du
   style de base .btn, sans couleur ni état :disabled — d'où son unique apparence, cliqué
   ou non, chargement ou non. */
.btn-outline { background: transparent; color: var(--text); border-color: var(--line-strong); }
.btn-outline:hover { border-color: var(--accent); color: var(--accent); }
.btn-outline:disabled { opacity: 0.4; cursor: not-allowed; }

/* Icône animée pour signaler un traitement en cours dans un bouton (ex. #btn-reproduire
   pendant le recalcul) — remplace le libellé le temps de l'appel réseau. */
.icon.spin { animation: spin 0.9s linear infinite; }
@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }

/* ── Barre collante des 11 écrans de paramétrage (2026-08-11, retour Gauthier § UX) ────
   Injectée par BizzStepper (js/stepper.js) au premier enfant de <body>, empilée sous le
   menu principal (--nav-h, cf. js/nav.js), toujours visible dès le chargement de l'écran.
   Seule ligne de progression désormais — l'ancienne version pleine taille du hero
   (.stepper/.step-circle/.step-line/.stepper-current, supprimées le même jour) faisait
   doublon avec elle : même "Étape X/11", 2 barres de progression dont une non interactive.
   `top` chaîné sur --cockpit-topbar-bottom (Chantier 4 ter, 2026-08-18) — nécessaire
   UNIQUEMENT sur recapitulatif.html, qui cumule désormais .cockpit-topbar (3 onglets) ET ce
   stepper (empilement, sinon superposition) ; sur les 10 autres écrans de configuration
   (jamais de .cockpit-topbar, variable jamais publiée), retombe exactement sur --nav-h via
   le repli CSS — AUCUN changement visuel là où rien n'a été demandé. */
.stepper-sticky { position: fixed; top: var(--cockpit-topbar-bottom, var(--nav-h, 60px)); left: 0; right: 0; z-index: 30; background: var(--surface); border-bottom: 1px solid var(--line); box-shadow: 0 2px 10px rgba(0,0,0,0.08); }
/* Grille plutôt que flex (retour Gauthier 2026-08-17 — "Précédent"/"Suivant" doivent être
   alignés CENTRE À CENTRE sur la barre de progression, pas sur tout le bloc label+barre).
   Avant ce correctif : .stepper-sticky-main empilait label PUIS barre de points dans un seul
   bloc flex, centré comme un tout — "Précédent"/"Suivant" se retrouvaient donc centrés entre
   les deux lignes, visiblement plus haut que le centre réel des points. Grid area "prev
   dots next" isole la barre de points sur sa PROPRE ligne, avec prev/next comme voisins
   directs de cette ligne — align-items:center les centre alors exactement sur SA hauteur à
   elle, jamais sur le label au-dessus. */
.stepper-sticky-inner {
  max-width: 960px; margin: 0 auto; padding: var(--space-2) var(--space-4);
  display: grid; grid-template-columns: auto 1fr auto;
  grid-template-areas: "label label label" "prev dots next" "ancres ancres ancres";
  column-gap: var(--space-3); row-gap: var(--space-2); align-items: center;
}
/* Wizard Complet : barre épurée sans Précédent/Suivant, avec barre de progression + labels */
.stepper-sticky .stepper-sticky-inner {
  grid-template-columns: 1fr;
  grid-template-areas: "header" "dots" "ancres";
  row-gap: var(--space-2);
}
.stepper-sticky-label { grid-area: label; display: block; font-family: 'BP-Jakarta', sans-serif; font-weight: 700; font-size: 0.8rem; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.stepper-sticky-count { font-weight: 500; color: var(--text-soft); }
/* Barre de progression + compteur N/11 (remplace le libellé textuel "Étape N/11 — label") */
.stepper-sticky-header { grid-area: header; display: flex; align-items: center; gap: 0.75rem; }
.stepper-sticky-progress-bar { flex: 1; height: 5px; background: var(--line-strong); border-radius: 3px; overflow: hidden; }
.stepper-sticky-progress-bar > div { height: 100%; background: var(--accent); border-radius: 3px; transition: width 0.35s ease; }
.stepper-sticky-progress-count { font-family: 'BP-Inter', sans-serif; font-size: 0.76rem; color: var(--text-soft); white-space: nowrap; font-variant-numeric: tabular-nums; }

/* Jalons interactifs (2026-08-11, retour Gauthier — fusionne la barre de progression non
   interactive de la barre collante avec les cercles cliquables du hero, jusque-là
   dupliqués et le 2e disparaissant au scroll) — même palette/états que .step-circle, en
   version compacte (point plein, pas de numéro à l'intérieur — le numéro/libellé reste
   accessible via l'attribut title au survol, même pattern que .step-circle). */
/* Agrandis le 2026-08-11 (retour Gauthier — "pas très lisibles", numéro à nouveau visible
   à l'intérieur) : 22px avec numéro, entre les 8px nus de la 1ère version et les 30px du
   hero d'origine — l'équilibre lisibilité/économie d'espace demandé. */
.stepper-sticky-dots { grid-area: dots; display: flex; align-items: flex-start; overflow-x: auto; -webkit-overflow-scrolling: touch; }
/* Colonne dot + label — la ligne de connexion est un sibling avec margin-top = moitié de la hauteur du dot (11px = 22px/2) pour rester centrée sur le cercle */
.stepper-sticky-dot-col { display: inline-flex; flex-direction: column; align-items: center; flex: 1 0 3.5rem; text-decoration: none; }
.stepper-sticky-dot-label { font-family: 'BP-Inter', sans-serif; font-size: 0.62rem; white-space: nowrap; text-align: center; line-height: 1.1; margin-top: 3px; opacity: 0; transition: opacity 0.15s; }
.stepper-sticky-dot-col:hover .stepper-sticky-dot-label { opacity: 1; }
.stepper-sticky-dot-col:has(.stepper-sticky-dot.active) .stepper-sticky-dot-label { opacity: 1; }
.stepper-sticky .stepper-sticky-dot-line { display: none; }
.stepper-sticky-dot {
  display: flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; border-radius: 50%; flex-shrink: 0; box-sizing: border-box;
  font-family: 'BP-Jakarta', sans-serif; font-weight: 700; font-size: 0.64rem;
  font-variant-numeric: tabular-nums;
  border: 1.5px solid var(--line-strong); color: var(--text-soft); background: var(--surface);
}
.stepper-sticky-dot.completed { background: var(--accent); color: var(--accent-contrast); border-color: var(--accent); }
.stepper-sticky-dot.active { background: var(--surface); color: var(--accent); border-color: var(--accent); border-width: 2.5px; }
.stepper-sticky-dot.disabled { opacity: 0.6; }
.stepper-sticky-dot-line { flex: 1 1 auto; height: 2px; background: var(--line-strong); min-width: 6px; }
.stepper-sticky-dot-line.completed { background: var(--accent); }
a.stepper-sticky-dot-link { display: inline-flex; align-items: center; cursor: pointer; }
a.stepper-sticky-dot-link:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; border-radius: 50%; }

/* padding-bottom (2026-08-11, retour Gauthier) : la scrollbar horizontale native de ce
   conteneur (overflow-x:auto, nécessaire dès que trop d'ancres pour la largeur dispo)
   s'affichait collée au bas des pills, les chevauchant visuellement sur les systèmes qui
   affichent des scrollbars classiques (non-overlay) — cet espace lui donne sa propre place. */
/* Indicateur visuel de défilement (2026-08-19, retour Gauthier) — overflow-x:auto existait
   déjà (2026-08-11) et fonctionne, mais rien ne signalait qu'il y avait plus d'onglets
   hors écran (surtout macOS, barres de défilement masquées par défaut) : les onglets en
   fin de liste (ex. "Matériel informat…", "Analyse de marché et c…") semblaient coupés et
   inaccessibles alors qu'ils étaient déjà atteignables au scroll. Technique "scroll
   shadows" tout CSS (4 dégradés superposés, 2 qui défilent AVEC le contenu — masquent le
   dégradé d'ombre tant qu'on est au bord — et 2 fixes qui portent l'ombre elle-même) :
   l'ombre n'apparaît que du côté où il reste effectivement du contenu à faire défiler,
   disparaît automatiquement une fois arrivé au bout. Zéro JS, robuste au redimensionnement.
*/
.stepper-sticky-anchors {
  grid-area: ancres;
  display: flex; gap: var(--space-2); padding-bottom: 8px; overflow-x: auto;
  background:
    linear-gradient(to right, var(--surface) 50%, transparent) left / 40px 100% no-repeat local,
    linear-gradient(to left, var(--surface) 50%, transparent) right / 40px 100% no-repeat local,
    linear-gradient(to right, color-mix(in srgb, var(--text) 20%, transparent), transparent) left / 14px 100% no-repeat scroll,
    linear-gradient(to left, color-mix(in srgb, var(--text) 20%, transparent), transparent) right / 14px 100% no-repeat scroll,
    var(--surface);
}
.stepper-sticky-anchors a { flex-shrink: 0; font-size: 0.76rem; font-weight: 600; color: var(--text-soft); text-decoration: none; padding: 2px 10px; border-radius: 999px; background: color-mix(in srgb, var(--text) 5%, transparent); white-space: nowrap; }
.stepper-sticky-anchors a.active { background: var(--accent); color: var(--accent-contrast); }
.stepper-sticky-nav { grid-area: prev; font-family: 'BP-Inter', sans-serif; font-size: 0.8rem; font-weight: 700; color: var(--accent); text-decoration: none; white-space: nowrap; }
.stepper-sticky-nav-next { grid-area: next; }
.stepper-sticky-nav-vide { width: 1px; }
@media (max-width: 640px) {
  .stepper-sticky-nav:not(.stepper-sticky-nav-vide) { font-size: 0; }
  .stepper-sticky-nav:not(.stepper-sticky-nav-vide)::before { content: '←'; font-size: 1rem; }
  .stepper-sticky-nav-next:not(.stepper-sticky-nav-vide)::before { content: '→'; }
}

/* ── Onglets ─────────────────────────────────────────────────────────────── */

.tabs { display: flex; gap: var(--space-4); border-bottom: 1px solid var(--line); margin-bottom: var(--space-5); }
.tab {
  background: none;
  border: none;
  cursor: pointer;
  font-family: 'BP-Jakarta', sans-serif;
  font-weight: 600;
  font-size: 0.92rem;
  color: var(--text-soft);
  padding: 0.6rem 0;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.tab.active { color: var(--accent); border-bottom-color: var(--accent); }
.tab:hover { color: var(--text); }
.tab:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }

.link-btn {
  background: none;
  border: none;
  cursor: pointer;
  font-family: 'BP-Inter', sans-serif;
  font-size: 0.8rem;
  font-weight: 500;
  color: var(--accent);
  padding: 0;
  text-decoration: underline;
}
.link-btn:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
/* Navigation retour/suivant partagée (écrans 1-9, cf. BizzStepper.renderNav) — le lien
   retour reste toujours au même endroit (premier enfant flex) que le lien suivant existe
   ou non ; flex-wrap évite tout débordement horizontal sur mobile. */
.screen-nav { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; margin-top: 2.5rem; }

/* Bulle d'info contextuelle au survol/focus — pour expliquer une règle non-évidente (ex.
   régime fiscal d'un taux de compte courant) sans alourdir le libellé du champ. Fond
   indigo/texte blanc, même langage que .pill-indigo (cf. retour Gauthier 2026-08-06). */
.info-tip { position: relative; display: inline-flex; align-items: center; vertical-align: middle; margin-left: 0.35rem; cursor: help; color: var(--text-soft); }
.info-tip .icon { width: 1rem; height: 1rem; }
.info-tip-bubble {
  position: absolute; bottom: calc(100% + 0.6rem); left: 50%; transform: translateX(-50%);
  width: 280px; max-width: 80vw;
  background: var(--accent); color: var(--accent-contrast);
  font-size: 0.78rem; font-weight: 400; line-height: 1.45;
  padding: 0.75rem 0.9rem; border-radius: 0.6rem;
  opacity: 0; visibility: hidden; transition: opacity 0.15s ease;
  z-index: 20; pointer-events: none;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
}
.info-tip-bubble::after {
  content: ''; position: absolute; top: 100%; left: 50%; transform: translateX(-50%);
  border: 6px solid transparent; border-top-color: var(--accent);
}
/* Sous 480px (2026-08-28, corrigé le même jour — 1re tentative insuffisante) : centrer la
   bulle sur son icône (left:50%/translateX(-50%) ci-dessus) la fait déborder du viewport dès
   que l'icône siège près du bord droit — visibility:hidden CONSERVE sa géométrie même
   invisible, donc ce débordement était réel au niveau du document (root cause d'un scroll
   horizontal accidentel de toute la page, confirmé : bodyScrollWidth retombe exactement à
   innerWidth une fois .info-tip-bubble retirée du DOM).
   1re tentative (left/right:1rem + width:auto, en gardant position:absolute) INSUFFISANTE :
   left/right sur un élément position:absolute sont relatifs à son bloc englobant, ici
   .info-tip (position:relative) — un simple <span> inline-flex qui ne fait que la largeur de
   la petite icône (~20px). left:1rem/right:1rem à l'intérieur d'une boîte de 20px ne laisse
   aucune place : le navigateur retombe sur une largeur "shrink-to-fit" (mesuré 28px), pas la
   pleine largeur espérée — la bulle débordait donc TOUJOURS (confirmé sur financement.html,
   retour Gauthier "le menu ne se fixe pas... sur l'écran-étape Financement").
   Fix réel : position:fixed sous ce seuil — le bloc englobant devient alors le VIEWPORT
   lui-même, où left/right délimitent une vraie plage utilisable et width:auto s'étire
   correctement entre les deux. Perd la pointe exactement alignée sur l'icône (bulle ancrée
   en bas d'écran façon bandeau plutôt que juste au-dessus de l'icône) — compromis délibéré,
   la garantie de ne jamais dépasser l'écran prime sur le positionnement précis ici. */
@media (max-width: 480px) {
  .info-tip-bubble {
    position: fixed; left: 1rem; right: 1rem; bottom: 1rem; top: auto;
    transform: none; width: auto; max-width: none;
  }
  .info-tip-bubble::after { display: none; }
}
.info-tip:hover .info-tip-bubble, .info-tip:focus .info-tip-bubble, .info-tip:focus-within .info-tip-bubble {
  opacity: 1; visibility: visible;
}

/* ── Formulaire ──────────────────────────────────────────────────────────── */

.form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--space-4);
  max-width: 640px;
}
.field { display: flex; flex-direction: column; gap: var(--space-2); }
.field label { font-size: 0.85rem; font-weight: 600; }
.field .hint { font-size: 0.78rem; color: var(--text-soft); margin: 0; }
.field .error-msg { font-size: 0.78rem; color: var(--danger); margin: 0; }
.essentiel-form .field + .field { margin-top: 1.5rem; }

/* "Statut du projet : [badge]" (recapitulatif.html, 2026-08-19, retour Gauthier QA passe 3)
   — ligne flex dédiée plutôt qu'un texte + badge en flux inline normal : align-items:center
   aligne le texte et le badge sur un centre commun, indépendamment de leurs tailles de
   police différentes (le badge est plus petit que le texte). */
.statut-projet-ligne { display: flex; align-items: center; gap: 0.4rem; font-size: 0.85rem; color: var(--text-soft); margin: 0 0 0.25rem; }

/* ── Saisonnalité graphique (ventes.html, 2026-08-11, retour Gauthier) ─────────────────
   12 barres modulables à la souris/au doigt (Pointer Events) — échelle 0-200, 100 =
   normal (repère pointillé au milieu), dégradé continu rouge (bas) → orange (100) → vert
   (haut), jamais 3 couleurs franches. Cliquer le chiffre = saisie précise en secours. */
#saisonnalite-grid { display: flex; align-items: flex-end; gap: var(--space-2); height: 200px; padding-top: var(--space-5); }
.saison-bar-col { display: flex; flex-direction: column; align-items: center; flex: 1 1 0; min-width: 0; height: 100%; }
.saison-bar-valeur { font-family: 'BP-Jakarta', sans-serif; font-size: 0.76rem; font-weight: 700; margin-bottom: var(--space-1); cursor: pointer; line-height: 1.2; }
.saison-bar-valeur:hover, .saison-bar-valeur:focus-visible { text-decoration: underline; outline: none; }
.saison-bar-valeur-input { width: 3.4rem; font-size: 0.76rem; text-align: center; padding: 1px 2px; }
.saison-bar-track { position: relative; width: 100%; max-width: 30px; flex: 1 1 auto; background: color-mix(in srgb, var(--text) 6%, transparent); border-radius: var(--radius); cursor: ns-resize; touch-action: none; overflow: hidden; }
.saison-bar-track:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.saison-bar-repere { position: absolute; left: 0; right: 0; bottom: 50%; border-top: 1px dashed color-mix(in srgb, var(--text) 30%, transparent); pointer-events: none; }
.saison-bar-fill { position: absolute; left: 0; right: 0; bottom: 0; border-radius: var(--radius); transition: background-color 0.1s ease; }
.saison-bar-mois { font-size: 0.72rem; color: var(--text-soft); margin-top: var(--space-1); }
@media (max-width: 640px) {
  #saisonnalite-grid { height: 160px; gap: 3px; }
  .saison-bar-valeur { font-size: 0.68rem; }
  .saison-bar-mois { font-size: 0.62rem; }
}

/* ── Cockpit financement (synthese.html, 2026-08-21, retour Gauthier § point 4, POC
   "Chantier 5") — même mécanique que la saisonnalité ci-dessus (Pointer Events, track/fill),
   adaptée à un montant EUR sans borne fixe (pas de repère à 100, pas de dégradé de couleur
   sémantique — une couleur fixe par catégorie, cohérente avec la palette catégorielle déjà
   utilisée par BizzCharts.barreEmpileeHorizontale sur la carte Financement de la Vue
   d'ensemble, jamais la palette rouge/orange/vert réservée aux verdicts de KPI). */
/* .cockpit-slider-groupe (2026-08-21) : un slider par POSTE, plus par catégorie agrégée —
   nombre de colonnes désormais variable par groupe (0, 1, ou plusieurs emprunts...), d'où
   .cockpit-slider-col en largeur FIXE + .cockpit-slider-grid qui wrap, plutôt que le
   flex:1 1 0 d'origine (pensé pour exactement 3 colonnes pleine largeur — un groupe à 1 seul
   poste s'y serait retrouvé absurdement étiré sur toute la largeur disponible). */
/* .cockpit-groupes-rangee (2026-08-21, retour Gauthier — "l'idéal est d'avoir les curseurs
   sur un seul pupitre horizontal") : les groupes (Capital/Avances en CC./Emprunts/Subsides)
   tiennent désormais à la largeur de leur contenu (flex: 0 0 auto), plus une largeur minimale
   fixe de 240px chacun (qui forçait 2 groupes par ligne puis un saut à la ligne pour le 3e) —
   tous s'alignent sur UNE seule rangée tant que la place le permet, séparateur vertical entre
   groupes (border-right) plutôt qu'un encadré complet par groupe. flex-wrap conservé comme
   seul filet de sécurité sur un écran trop étroit pour tout aligner. */
.cockpit-groupes-rangee { display: flex; flex-wrap: wrap; gap: var(--space-5); align-items: flex-start; }
/* max-width:100% (2026-08-28, audit mobile — retour Gauthier, capture : "Site web /
   plateforme e-commerce (développement)" déborde du cadre) : flex:0 0 auto seul (flex-
   basis:auto) laisse ce groupe se dimensionner sur son contenu naturel, sans jamais de
   plafond — son titre (.cockpit-slider-groupe-titre, un <h4> normal, wrap sur les espaces
   sans problème) ne débordait que parce que LE GROUPE LUI-MÊME n'avait aucune largeur
   maximale l'empêchant d'être plus large que l'écran sur sa propre ligne (flex-wrap sur le
   parent .cockpit-groupes-rangee pousse bien un groupe trop large sur sa propre ligne, mais
   ne le force jamais À RÉTRÉCIR lui-même). */
.cockpit-slider-groupe { flex: 0 0 auto; max-width: 100%; }
.cockpit-slider-groupe:not(:last-child) { border-right: 1px solid var(--line); padding-right: var(--space-5); }
.cockpit-slider-groupe-titre { font-size: 0.85rem; font-weight: 700; color: var(--text-soft); margin: 0 0 var(--space-2); cursor: default; }
.cockpit-structure-financement { max-width: 420px; }

/* .cockpit-tabs (chantier 2/5, 2026-08-21) — Financement/Revenus aujourd'hui, extensible aux
   prochains groupes Cockpit (Charges/Investissements) sans nouveau style : chaque onglet
   n'est qu'un bouton de plus dans cette rangée. Pills sobres, même esprit que .btn-outline
   mais sans bordure individuelle (juste la ligne de séparation basse commune), pour rester
   discret au-dessus d'un contenu déjà chargé (sliders + panneau KPI). */
/* overflow-x:auto + scroll shadows (2026-08-28, audit mobile — retour Gauthier, mesure
   Web Inspector réelle sur iPhone : bodyScrollWidth=496 vs innerWidth=375, .cockpit-tabs en
   tête des éléments fautifs) — pensée à l'origine pour 2 onglets (Financement/Revenus),
   jamais revue lors de l'extension à 4 (Charges/Investissements ajoutés depuis) : ni
   flex-wrap ni overflow-x, la rangée débordait donc du viewport sans AUCUNE contention —
   contrairement à .table-wrap/.stepper-sticky-anchors qui ont ce traitement depuis le
   début. Root cause du débordement en cascade sur .cockpit-content/.recap-section
   (conteneurs bloc simples, sans flex/grid — ils s'élargissent pour accueillir un enfant en
   overflow visible, exactement comme .info-tip-bubble faisait déborder tout le document).
   Même motif exact que .stepper-sticky-anchors/.table-wrap, jamais un 3e système inventé. */
.cockpit-tabs {
  display: flex; gap: var(--space-2); border-bottom: 1px solid var(--line);
  margin-bottom: var(--space-4); padding-bottom: var(--space-2);
  overflow-x: auto;
  background:
    linear-gradient(to right, var(--surface) 50%, transparent) left / 40px 100% no-repeat local,
    linear-gradient(to left, var(--surface) 50%, transparent) right / 40px 100% no-repeat local,
    linear-gradient(to right, color-mix(in srgb, var(--text) 20%, transparent), transparent) left / 14px 100% no-repeat scroll,
    linear-gradient(to left, color-mix(in srgb, var(--text) 20%, transparent), transparent) right / 14px 100% no-repeat scroll,
    var(--surface);
}
.cockpit-tab { border: none; background: transparent; color: var(--text-soft); font-family: 'BP-Jakarta', sans-serif; font-size: 0.85rem; font-weight: 600; padding: 0.4rem 0.9rem; border-radius: var(--radius); cursor: pointer; transition: background 0.12s ease, color 0.12s ease; flex-shrink: 0; white-space: nowrap; }
.cockpit-tab:hover { color: var(--text); background: color-mix(in srgb, var(--text) 6%, transparent); }
.cockpit-tab.active { background: var(--accent); color: var(--accent-contrast); }
.cockpit-tab:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }

/* .cockpit-charges-categorie (2026-08-22, retour Gauthier — regroupement du Cockpit Charges
   par catégorie du compte de résultat, titre affiché UNE SEULE FOIS par groupement) — chaque
   catégorie empile ses propres .cockpit-groupes-rangee (déjà défini ci-dessus, inchangé),
   séparées verticalement plutôt que mêlées dans une seule rangée horizontale continue. */
.cockpit-charges-categorie:not(:last-child) { margin-bottom: var(--space-5); padding-bottom: var(--space-4); border-bottom: 1px solid var(--line); }
.cockpit-charges-categorie-titre { font-size: 0.95rem; font-weight: 700; margin: 0 0 var(--space-3); }
/* min-height (pas height) sur la grille + hauteur EXPLICITE sur chaque colonne, plutôt que
   height:100% (2026-08-28, audit mobile — retour Gauthier, captures iPhone réelles : groupes
   de curseurs qui se chevauchent avec le titre du groupe suivant, notamment sur "Effectifs"
   qui peut compter de nombreux postes). height:180px fixe sur la grille contredisait
   flex-wrap:wrap dès qu'une rangée de curseurs devait vraiment passer à la ligne (jamais
   exercé sur desktop, où la grille est assez large pour que la plupart des groupes tiennent
   sur une seule ligne — devient fréquent en colonne étroite mobile, surtout avec plusieurs
   postes "Effectifs" à 2 curseurs chacun) : la grille NE POUVAIT PAS grandir pour la 2e
   rangée, dont le contenu débordait alors visuellement par-dessus ce qui suit dans la page.
   .cockpit-slider-col avait height:100% (relatif à la grille) — nécessite maintenant sa
   propre valeur explicite, un height:100% ne se résout plus une fois le parent en
   min-height (hauteur intrinsèque, un pourcentage dessus devient invalide). */
.cockpit-slider-grid { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--space-4); min-height: 180px; padding-top: var(--space-5); }
.cockpit-slider-col { display: flex; flex-direction: column; align-items: center; flex: 0 0 128px; min-width: 0; height: 180px; }
.cockpit-slider-valeur { font-family: 'BP-Jakarta', sans-serif; font-size: 0.85rem; font-weight: 700; margin-bottom: var(--space-1); cursor: pointer; line-height: 1.2; }
.cockpit-slider-valeur:hover, .cockpit-slider-valeur:focus-visible { text-decoration: underline; outline: none; }
.cockpit-slider-valeur-input { width: 5.5rem; font-size: 0.85rem; text-align: center; padding: 1px 2px; }
.cockpit-slider-track { position: relative; width: 100%; max-width: 64px; flex: 1 1 auto; background: color-mix(in srgb, var(--text) 6%, transparent); border-radius: var(--radius); cursor: ns-resize; touch-action: none; overflow: hidden; }
.cockpit-slider-track:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.cockpit-slider-track-inerte { cursor: not-allowed; }
.cockpit-slider-track.en-cours { opacity: 0.5; }
.cockpit-slider-fill { position: absolute; left: 0; right: 0; bottom: 0; border-radius: var(--radius); transition: height 0.1s ease; }
/* Libellé sur 2 lignes MAX avec ellipse (2026-08-21, retour Gauthier — capture montrant des
   libellés réels ("Capital souscrit (apport personnel en société)", "Compte courant associé/
   administrateur"...) qui débordaient sur 3-4 lignes, gonflant chaque bloc bien au-delà de la
   hauteur du slider lui-même — la fixture de test utilisée pendant le dev n'avait que des
   libellés courts, jamais repérée avant un vrai test). Même mécanique de troncature que
   .stepper-sticky-label (js/stepper.js) mais sur 2 lignes plutôt qu'1 (un libellé de poste,
   contrairement au titre d'étape, doit rester distinguable d'un autre poste du même groupe).
   Texte complet toujours accessible via data-tooltip (mécanisme déjà générique sur
   #synthese-content, cf. l'écouteur mouseover plus bas dans ce fichier). */
.cockpit-slider-label {
  font-size: 0.8rem; color: var(--text-soft); margin-top: var(--space-1); text-align: center;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  line-height: 1.3; max-height: 2.6em; cursor: default;
}
@media (max-width: 640px) {
  .cockpit-slider-grid { min-height: 140px; gap: var(--space-2); }
  .cockpit-slider-col { flex-basis: 96px; height: 140px; }
  .cockpit-slider-valeur { font-size: 0.72rem; }
  .cockpit-slider-label { font-size: 0.68rem; }
}

.field input[type="text"],
.field input[type="email"],
.field input[type="password"],
.field input[type="number"],
.field input[type="date"],
.field select {
  font-family: 'BP-Inter', sans-serif;
  font-size: 0.95rem;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--line-strong);
  padding: 0.6rem 0.7rem;
  border-radius: var(--radius-sm);
  width: 100%;
}
.field input[type="text"]::placeholder,
.field input[type="email"]::placeholder,
.field input[type="password"]::placeholder { color: var(--text-soft); }

/* Champs de montant (2026-08-19, retour Gauthier) — masque les flèches natives
   d'incrément/décrément du input[type=number] : pensées pour une valeur unitaire à
   ajuster pas à pas (ex. durée, nombre d'échéances), pas pour la saisie directe d'un
   montant en euros. Champs identifiés .input-montant dans chaque écran du wizard
   (investissements.html, financement.html, ventes.html, achats-charges.html,
   equipe-remuneration.html) — jamais un blanket sur tout input[type=number] : les
   compteurs/durées/taux gardent leurs flèches, toujours utiles pour ces valeurs-là. */
.input-montant::-webkit-outer-spin-button,
.input-montant::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.input-montant { -moz-appearance: textfield; }

.field textarea {
  font-family: 'BP-Inter', sans-serif;
  font-size: 0.95rem;
  line-height: 1.5;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--line-strong);
  padding: 0.6rem 0.7rem;
  border-radius: var(--radius-sm);
  width: 100%;
  resize: vertical;
}
.field textarea::placeholder { color: var(--text-soft); }
.field textarea:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 1px;
  border-color: var(--focus-ring);
}

/* Chevron custom : le rendu natif du navigateur colle la flèche contre le bord droit du
   cadre, sans marge — corrigé une fois ici pour tous les <select> du site (même défaut
   déjà repéré sur tikkoun-website, corrigé là-bas en parallèle). */
.field select {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  background-image: var(--select-chevron);
  background-repeat: no-repeat;
  background-position: right 0.75rem center;
  background-size: 1.1rem;
  padding-right: 2.5rem;
}
.field input:focus-visible, .field select:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 1px;
  border-color: var(--focus-ring);
}
.field.has-error input { border-color: var(--danger); }

/* Flèches d'incrémentation toujours visibles (jamais masquées par appearance:none) —
   l'utilisateur doit voir au premier coup d'œil qu'un nombre libre est possible en plus
   des boutons de préremplissage rapide ci-dessous. */
.field input[type="number"] { -moz-appearance: textfield; appearance: auto; }
.field input[type="number"]::-webkit-inner-spin-button,
.field input[type="number"]::-webkit-outer-spin-button { opacity: 1; }

/* Boutons de préremplissage rapide — lisibles comme des options sélectionnables, pas
   comme des actions : état actif rempli, reflète toujours la valeur réelle du champ. */
.preset-btn {
  font-family: 'BP-Jakarta', sans-serif;
  font-weight: 600;
  font-size: 0.82rem;
  padding: 0.4rem 0.8rem;
  border: 1px solid var(--line-strong);
  background: var(--surface);
  color: var(--text-soft);
  cursor: pointer;
}
.preset-btn:hover { border-color: var(--accent); color: var(--accent); }
.preset-btn.active { background: var(--accent); border-color: var(--accent); color: var(--accent-contrast); }
.preset-btn:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }

.password-wrap { position: relative; display: flex; }
.password-wrap input { flex: 1; padding-right: 2.4rem; }
.password-toggle {
  position: absolute;
  right: 0.4rem;
  top: 50%;
  transform: translateY(-50%);
  background: none;
  border: none;
  cursor: pointer;
  color: var(--text-soft);
  display: flex;
  padding: 0.3rem;
}
.password-toggle:hover { color: var(--text); }
.password-toggle:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }

.checkbox-row { display: flex; align-items: center; gap: var(--space-2); }
.checkbox-row label { font-size: 0.88rem; font-weight: 500; flex: 1 1 auto; }
.checkbox-row input[type="checkbox"], .checkbox-row input[type="radio"] { width: 1.05rem; height: 1.05rem; accent-color: var(--accent); }
/* Catégorie verrouillée (achats-charges.html, contient déjà des charges) — jamais
   l'attribut natif disabled : son rendu réduit/pâli varie selon l'OS/navigateur (macOS
   Chrome le rend visiblement plus petit que les checkboxes actives, bug de taille signalé
   par Gauthier le 2026-08-13), donc même poids visuel ici, verrouillage porté par le
   curseur + la couleur du label uniquement. */
.checkbox-row.verrouille { cursor: not-allowed; }
.checkbox-row.verrouille label { color: var(--text-soft); cursor: not-allowed; }
/* Badge secondaire "Contient déjà des charges" (2026-08-19, retour Gauthier) — sibling du
   label plutôt que concaténé à son texte : label en flex:1 (ci-dessus) pousse ce badge à
   l'extrémité droite de la ligne, quelle que soit la longueur du libellé principal —
   restaure un alignement de lecture propre sur toute la liste de catégories. */
.checkbox-row-badge { flex-shrink: 0; font-size: 0.7rem; color: var(--text-soft); background: color-mix(in srgb, var(--text) 6%, transparent); padding: 0.15rem 0.55rem; border-radius: 999px; white-space: nowrap; }

/* ── Cartes projet ───────────────────────────────────────────────────────── */

.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--space-4);
}
.project-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-top: 3px solid var(--line-strong);
  padding: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.project-card-top { display: flex; justify-content: space-between; align-items: flex-start; gap: var(--space-2); }
.project-name { font-family: 'BP-Jakarta', sans-serif; font-weight: 700; font-size: 1.02rem; }
.project-meta { font-size: 0.82rem; color: var(--text-soft); display: flex; flex-direction: column; gap: 0.2rem; }
.project-date { font-size: 0.78rem; color: var(--text-soft); font-variant-numeric: tabular-nums; }

/* ── Cartes ToolBox (2026-08-26) — réutilise .project-card telle quelle (même boîte),
   ajoute juste l'affordance de lien pour l'outil disponible et l'état atténué pour les
   outils annoncés mais pas encore construits. */
a.tool-card { transition: border-color 0.15s ease, transform 0.15s ease; }
a.tool-card:hover { border-color: var(--accent); transform: translateY(-2px); }
.tool-card-soon { opacity: 0.6; }
.tool-card-soon .project-card-top { width: 100%; justify-content: space-between; }

/* Suppression d'un projet (2026-08-20, tableau de bord, retour Gauthier — nettoyer la masse
   de projets de test). Icône seule, discrète tant qu'on ne survole pas — même registre que
   .btn-fermer-volet (reset transparent + couleur au survol), teinte danger plutôt que text
   pour signaler le caractère destructif de l'action. */
.btn-supprimer-projet { background: none; border: none; cursor: pointer; color: var(--text-soft); padding: var(--space-1); flex-shrink: 0; border-radius: var(--radius-sm); }
.btn-supprimer-projet:hover { color: var(--danger); background: color-mix(in srgb, var(--danger) 10%, transparent); }
.btn-supprimer-projet:disabled { opacity: 0.5; cursor: not-allowed; }
.btn-supprimer-projet .icon { width: 1.05rem; height: 1.05rem; }

/* Sélecteur de scénario du tableau de bord (2026-08-20) — réutilise .scenario-nav-select-*
   tel quel (même composant que le fil d'Ariane, css/style.css § Coquille de navigation),
   mais dans un conteneur bien plus étroit qu'une topbar pleine largeur : une carte projet
   peut descendre jusqu'à 260px (cf. .card-grid, minmax(260px,1fr)). Sans ce correctif, le
   bouton-pilule (max-width:260px côté topbar, jamais pensé pour rétrécir) dépassait le cadre
   de la carte — bug réel signalé par Gauthier avant même que je ne le voie. min-width:0 sur
   la chaîne flex qui doit rétrécir (le défaut flex "min-width:auto" empêche un enfant de
   rétrécir sous sa largeur intrinsèque, cause exacte du débordement) ; l'ellipsis déjà posée
   sur .scenario-nav-select-value (css/style.css) n'a alors enfin quelque chose de borné
   contre quoi tronquer. Scopé à ce conteneur uniquement — jamais touché .scenario-nav-select-*
   en dehors d'ici, la topbar reste inchangée.
   ⚠ 2e bug trouvé et signalé par Gauthier dans la foulée : un premier jet appliquait
   min-width:0 à TOUS les descendants (sélecteur universel `*`) — appliqué par erreur aussi à
   .scenario-nav-select-label ("Scénario"), un texte court à largeur fixe qui n'a jamais
   besoin de rétrécir. Une fois comprimé à 0, son texte (jamais recadré, aucun overflow:hidden
   dessus) débordait de sa propre boîte et se superposait visuellement à la pilule juste à
   côté ("ScénariPrix challengé..."). Liste explicite ci-dessous — jamais le sélecteur
   universel — qui exclut délibérément le label. */
.dash-scenario-selector { display: flex; align-items: center; flex-wrap: wrap; gap: 0.5rem; margin: 0.25rem 0 0.5rem; max-width: 100%; }
.dash-scenario-selector .scenario-nav-select-label { flex-shrink: 0; }
.dash-scenario-selector .scenario-nav-select-group,
.dash-scenario-selector .scenario-nav-select-pill,
.dash-scenario-selector .scenario-nav-select-btn,
.dash-scenario-selector .scenario-nav-select-value {
  min-width: 0; max-width: 100%;
}
/* Le popup DÉROULÉ n'est jamais contraint à la largeur (étroite) de la pilule qui l'ouvre —
   contrairement au bouton fermé, il flotte au-dessus du reste (position:absolute déjà posée
   par la règle .scenario-nav-select-list de base) et ne pousse jamais le layout de la page :
   bug réel trouvé et signalé par Gauthier juste après le fix ci-dessus — un max-width:100%
   ici tronquait les libellés de scénario ("Positionnen...", "Prix challen...") au lieu de les
   afficher en entier, jamais l'intention. min-width:100% (déjà dans la règle de base) suffit
   à garantir qu'il ne soit jamais plus étroit que le bouton ; une largeur mini de confort en
   plus pour qu'un libellé court n'y semble pas perdu. */
.dash-scenario-selector .scenario-nav-select-list { min-width: 220px; }

/* Mini-cartes Configuration/Plan Financier/Business Plan (2026-08-19, retour Gauthier §
   Tableau de bord) — remplacent l'ancien statut unique par projet (une seule pill, dérivée
   d'une colonne projects.statut jamais écrite en base, cf. js/dashboard.js). Toute la
   mini-carte est cliquable (<a>, jamais interceptée en JS) sauf la variante .is-disabled
   (Business Plan hors formule — rien à ouvrir). */
.project-substeps { display: flex; flex-direction: column; gap: var(--space-2); }
.project-substep {
  display: flex; align-items: flex-start; gap: var(--space-3);
  padding: var(--space-2) var(--space-3); border: 1px solid var(--line); border-radius: var(--radius);
  text-decoration: none; color: inherit; transition: border-color 0.15s ease;
}
a.project-substep:hover { border-color: var(--accent); }
.project-substep.is-disabled { opacity: 0.55; }
.project-substep-icon {
  width: 1.75rem; height: 1.75rem; border-radius: 6px; flex-shrink: 0; margin-top: 0.1rem;
  display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--accent) 12%, transparent); color: var(--accent);
}
.project-substep-icon .icon { width: 1rem; height: 1rem; }
.project-substep-body { flex: 1 1 auto; min-width: 0; }
.project-substep-label { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); font-family: 'BP-Jakarta', sans-serif; font-weight: 700; font-size: 0.85rem; }
.project-substep-bar { height: 5px; border-radius: 999px; background: color-mix(in srgb, var(--text) 8%, transparent); overflow: hidden; margin-top: 0.4rem; }
.project-substep-bar-fill { height: 100%; background: var(--accent); border-radius: 999px; }
.project-substep-detail { font-family: 'BP-Inter', sans-serif; font-size: 0.76rem; color: var(--text-soft); margin-top: 0.3rem; }

/* ── Sections narratives (narratif-bp.html) ─────────────────────────────── */

.narrative-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-top: 3px solid var(--line-strong);
  padding: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.narrative-card h3 { font-family: 'BP-Jakarta', sans-serif; font-weight: 700; font-size: 1.02rem; margin: 0; }
.narrative-card .hint { font-size: 0.82rem; color: var(--text-soft); margin: 0; }
.narrative-card .hint ul { margin: 0.3rem 0 0; padding-left: 1.2rem; }
.narrative-card .hint li { margin: 0.15rem 0; }
.narrative-save-state { font-size: 0.76rem; color: var(--text-soft); min-height: 1.1em; }
.narrative-save-state.is-saved { color: var(--success); }

/* ── Badges de statut ────────────────────────────────────────────────────── */

.badge-group { margin-bottom: var(--space-4); }
.badge-group-label { font-size: 0.78rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-soft); margin: 0 0 var(--space-2); }
.badge-row { display: flex; gap: var(--space-2); flex-wrap: wrap; }

.pill {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.76rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  padding: 0.28rem 0.65rem;
  border-radius: 999px;
  border: 1px solid transparent;
}
.pill-dot { width: 0.4rem; height: 0.4rem; border-radius: 50%; background: currentColor; }
.pill .icon { width: 0.85em; height: 0.85em; }

.pill-neutral { color: var(--text-soft); border-color: var(--line-strong); }
.pill-success { color: var(--success); border-color: var(--success); background: color-mix(in srgb, var(--success) 16%, transparent); }
/* .pill-warning (2026-08-20, retour Gauthier — niveaux d'alerte progressifs sur les stress-
   tests, jamais un simple binaire succès/danger) : réutilise --kpi-warn, déjà défini pour la
   triad "feu tricolore" go/warn/stop (cf. § usage sémantique plus haut, jusqu'ici seulement
   consommée par .kpi-go/.kpi-warn/.kpi-stop, un style de bordure différent) — même variable,
   même langage de pill que .pill-success/.pill-danger. */
.pill-warning { color: var(--kpi-warn); border-color: var(--kpi-warn); background: color-mix(in srgb, var(--kpi-warn) 16%, transparent); }
/* .pill-caution (jaune, 2026-08-20) : 2e palier d'alerte non bloquante, entre .pill-warning
   (orange) et .pill-success (vert) — cf. niveau_couverture_tresorerie, engine/stress_tests.py
   bizzplan-api, gradient rouge/orange/jaune/vert. */
.pill-caution { color: var(--kpi-caution); border-color: var(--kpi-caution); background: color-mix(in srgb, var(--kpi-caution) 16%, transparent); }
.pill-danger { color: var(--danger); border-color: var(--danger); background: color-mix(in srgb, var(--danger) 16%, transparent); }
.pill-accent { color: var(--accent); border-color: var(--accent); background: color-mix(in srgb, var(--accent) 16%, transparent); }
/* Fond plein + texte blanc (var(--accent-contrast), pas blanc en dur — s'inverse
   correctement en thème sombre) : bulle d'info contextuelle dans une carte (durée
   d'amortissement, taux/échéancier, date de départ...) — le fond transparent de
   .pill-neutral se lisait mal sur le blanc de la carte, cf. retour Gauthier 2026-08-06. */
.pill-indigo { color: var(--accent-contrast); border-color: var(--accent); background: var(--accent); }
.pill-sagesoft { color: var(--sage-soft); border-color: var(--sage-soft); background: color-mix(in srgb, var(--sage-soft) 16%, transparent); }
.pill-muted { color: var(--text-soft); border-color: var(--line); opacity: 0.7; }

/* ── Alertes ─────────────────────────────────────────────────────────────── */
/* Info / succès / danger uniquement — le triad feu tricolore (orange + vert) n'apparaît
   jamais ici, cf. section Validation KPI ci-dessous. */

.alert {
  border: 1px solid var(--line);
  border-left: 3px solid var(--text-soft);
  padding: var(--space-3) var(--space-4);
  font-size: 0.9rem;
  display: flex;
  gap: var(--space-3);
}
.alert .icon { width: 1.15rem; height: 1.15rem; margin-top: 0.15rem; }
.alert-body { display: flex; flex-direction: column; gap: 0.2rem; }
.alert-label { font-family: 'BP-Jakarta', sans-serif; font-size: 0.72rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; }
.alert-info {
  border-left-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 8%, var(--surface));
}
.alert-info .alert-label, .alert-info .icon { color: var(--accent); }
.alert-success {
  border-left-color: var(--success);
  background: color-mix(in srgb, var(--success) 8%, var(--surface));
}
.alert-success .alert-label, .alert-success .icon { color: var(--success); }
.alert-danger {
  border-left-color: var(--danger);
  background: color-mix(in srgb, var(--danger) 8%, var(--surface));
}
.alert-danger .alert-label, .alert-danger .icon { color: var(--danger); }

/* ── Validation KPI — triad feu tricolore, usage exclusif ───────────────────── */
/* Rouge / orange / vert réservés aux stress-tests et à la validation de KPI
   financiers (cf. bizzplan-api/engine/anomalies.py) — jamais pour un message
   d'interface générique. Ne pas réutiliser --kpi-* ailleurs. */

.kpi-list { display: flex; flex-direction: column; gap: var(--space-2); }
.kpi-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  background: var(--surface);
  border: 1px solid var(--line);
  border-left-width: 4px;
  padding: var(--space-3) var(--space-4);
}
.kpi-main { display: flex; align-items: flex-start; gap: var(--space-3); }
.kpi-main .icon { width: 1.25rem; height: 1.25rem; margin-top: 0.15rem; }
.kpi-text { display: flex; flex-direction: column; gap: 0.15rem; }
.kpi-title { font-family: 'BP-Jakarta', sans-serif; font-weight: 600; font-size: 0.92rem; }
.kpi-detail { font-family: 'BP-Inter', sans-serif; font-size: 0.84rem; color: var(--text-soft); }
.kpi-tag {
  font-family: 'BP-Jakarta', sans-serif;
  font-weight: 700;
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: 0.25rem 0.55rem;
  color: var(--kpi-contrast);
  flex-shrink: 0;
}
.kpi-go { border-left-color: var(--kpi-go); }
.kpi-go .icon { color: var(--kpi-go); }
.kpi-go .kpi-tag { background: var(--kpi-go); }
.kpi-warn { border-left-color: var(--kpi-warn); }
.kpi-warn .icon { color: var(--kpi-warn); }
.kpi-warn .kpi-tag { background: var(--kpi-warn); }
.kpi-stop { border-left-color: var(--kpi-stop); }
.kpi-stop .icon { color: var(--kpi-stop); }
.kpi-stop .kpi-tag { background: var(--kpi-stop); }

/* ── Tableaux de chiffres ────────────────────────────────────────────────── */
/* En-tête indigo (combo "Sagesse"), ligne de total teintée gris vert. */

/* Scroll shadows (2026-08-27, audit mobile) — même motif exact que .stepper-sticky-anchors
   ci-dessus (2026-08-19) : overflow-x:auto existait déjà (table min-width:480px ci-dessous,
   par nature plus large qu'un viewport mobile) mais rien ne signalait qu'il restait des
   colonnes hors écran — un tableau tronqué à droite ressemblait à un débordement cassé
   plutôt qu'à "fais glisser pour voir la suite" (retour Gauthier, captures DevTools 375px).
   Même trick zéro-JS : 2 dégradés qui défilent AVEC le contenu (masquent l'ombre tant qu'on
   est au bord) + 2 dégradés fixes qui portent l'ombre, visible uniquement du côté où il
   reste du contenu à faire défiler. */
.table-wrap {
  overflow-x: auto;
  border: 1px solid var(--line);
  background:
    linear-gradient(to right, var(--surface) 50%, transparent) left / 40px 100% no-repeat local,
    linear-gradient(to left, var(--surface) 50%, transparent) right / 40px 100% no-repeat local,
    linear-gradient(to right, color-mix(in srgb, var(--text) 20%, transparent), transparent) left / 14px 100% no-repeat scroll,
    linear-gradient(to left, color-mix(in srgb, var(--text) 20%, transparent), transparent) right / 14px 100% no-repeat scroll,
    var(--surface);
  cursor: grab;
  /* touch-action:pan-y (2026-08-27, audit mobile) — root cause réelle du "toujours pas
     scrollable" malgré wireTableDragScroll (js/nav.js) déjà étendu au tactile : sans cette
     propriété, touch-action reste à sa valeur par défaut (auto) et le moteur de rendu tente
     de reconnaître le geste comme un scroll NATIF dès les premiers pixels de mouvement,
     AVANT que le JS n'ait eu la main — la séquence pointermove peut alors être interrompue
     (pointercancel) sans jamais laisser au dx/dy de wireTableDragScroll le temps de
     s'exécuter, quel que soit le preventDefault() posé plus tard dans le geste (trop tard).
     pan-y déclare explicitement : le défilement VERTICAL natif de la page reste intact (un
     doigt qui scrolle la page en passant sur un tableau n'est jamais bloqué), mais
     l'horizontal n'est PAS pré-capturé par le navigateur — laisse la main entière et
     immédiate au JS pour ce seul axe. Correctif standard pour un drag horizontal personnalisé
     sur un élément niché dans une page qui défile verticalement. */
  touch-action: pan-y;
}
/* Défilement au clic-glissé souris (js/nav.js::wireTableDragScroll) — cursor:grab par
   défaut (poser un grab sur un tableau non scrollable est inoffensif, rien à saisir) ;
   .table-wrap-dragging posée en JS pendant le drag actif : curseur "en cours de saisie" +
   user-select:none (sans ça, glisser sur des cellules sélectionne leur texte au lieu de
   faire défiler — comportement natif du navigateur à désactiver explicitement ici). */
.table-wrap-dragging { cursor: grabbing; user-select: none; }
table { width: 100%; border-collapse: collapse; font-size: 0.92rem; min-width: 480px; background: var(--surface); }
thead th {
  text-align: left;
  font-family: 'BP-Jakarta', sans-serif;
  font-size: 0.74rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ivoire);
  background: var(--indigo);
  /* Padding horizontal augmenté (var(--space-4)→var(--space-5)) + line-height explicite
     (2026-08-19, retour Gauthier QA passe 2 § D4) — les tableaux à colonnes nombreuses/
     libellés longs (ex. "Volume (départ → croisière)", ventes.html) forcent le navigateur à
     rétrécir ces colonnes au plus près du texte (table sans layout:fixed), le padding fixe
     devenant visuellement négligeable une fois le libellé passé sur 2 lignes — vaut pour
     tout tableau du site, pas seulement Flux de revenus. */
  padding: var(--space-3) var(--space-5);
  line-height: 1.35;
  border-right: 1px solid color-mix(in srgb, var(--ivoire) 20%, transparent);
}
thead th:last-child { border-right: none; }
thead th.num, td.num { text-align: right; font-variant-numeric: tabular-nums; }
/* white-space:nowrap (2026-08-18, retour Gauthier) : un montant ne doit jamais se couper
   entre le chiffre et le €, ni entre les groupes de milliers. Porté par des spans dédiés
   (.montant-nowrap, .montant-negatif — formatMontant()/formatMontantSigne(), js/synthese.js)
   plutôt que par td.num globalement : un td.num peut aussi contenir le badge d'évolution
   (.kpi-evolution, "↑ X %") juste après le montant, qui LUI a le droit de repasser à la
   ligne (exception explicite de Gauthier — seul le montant est protégé, jamais le badge).
   Un nowrap sur tout le td forçait donc montant+badge sur une seule ligne, élargissant
   toute la colonne au lieu de laisser le badge redescendre. Le débordement résiduel
   (colonnes très nombreuses) reste absorbé par .table-wrap { overflow-x: auto } existant. */
.montant-nowrap, .montant-negatif, .kpi-evolution { white-space: nowrap; }
tbody td { padding: var(--space-2) var(--space-4); border-bottom: 1px solid var(--line); border-right: 1px solid var(--line); }
tbody td:last-child { border-right: none; }
tbody tr:last-child td { border-bottom: none; }
/* tfoot (lignes "Total"/"TCAM (période totale)", 2026-08-19, retour Gauthier QA passe 2 § C)
   — même padding que tbody td, sinon le libellé colle au bord gauche et les valeurs
   numériques (déjà text-align:right via td.num) se retrouvent flush contre le bord de
   cellule au lieu d'être insérées comme les lignes de données au-dessus, donc visuellement
   décalées d'une colonne malgré le même alignement à droite. */
tfoot td { padding: var(--space-2) var(--space-4); border-right: 1px solid var(--line); }
tfoot td:last-child { border-right: none; }
tr.total td {
  border-top: 1px solid var(--line-strong);
  background: color-mix(in srgb, var(--sage-soft) 16%, transparent);
  font-weight: 700;
  padding-top: var(--space-3);
  padding-bottom: var(--space-3);
}
tr.total td:first-child { font-family: 'BP-Jakarta', sans-serif; }

/* Hiérarchie de totaux à 3 niveaux (2026-08-10, retour Gauthier § UI/UX) — un tableau
   financier long (compte de résultat, bilan) a besoin de plus qu'un seul niveau de "total" :
   niveau 1 = sous-total sous-jacent (discret, juste une démarcation typographique) ; niveau
   2 = sous-total intermédiaire structurant (= .total existant, inchangé, réutilisé partout
   ailleurs) ; niveau 3 = grand total (le chiffre qui compte le plus dans le tableau, fond
   plein indigo comme l'en-tête — jamais confondu avec un sous-total). Ne jamais utiliser
   rouge/orange/vert ici — cette triade reste réservée aux stress-tests/KPI (CLAUDE.md).
   `.total`/`tr.total` reste l'alias niveau 2 le plus courant, non renommé pour ne rien
   casser sur les pages existantes (recapitulatif.html, tableaux ajoutés le 2026-08-10). */
tr.total-1 td { border-top: 1px solid var(--line); font-weight: 600; font-style: italic; }
tr.total-2 td { border-top: 1px solid var(--line-strong); background: color-mix(in srgb, var(--sage-soft) 16%, transparent); font-weight: 700; padding-top: var(--space-3); padding-bottom: var(--space-3); }
tr.total-2 td:first-child { font-family: 'BP-Jakarta', sans-serif; }
/* border-top ivoire semi-transparent (2026-08-19, retour Gauthier QA passe 3) — tr.total-3
   partage le même fond indigo que thead th ; quand une ligne total-3 est la toute première
   du tbody (ex. "Chiffre d'affaires" en tête de Revenus/Compte de résultat), elle se
   fondait visuellement avec l'en-tête juste au-dessus, aucune séparation perceptible entre
   les deux blocs indigo. Même teinte que la bordure déjà utilisée entre colonnes de
   thead th (color-mix ivoire/transparent) — cohérent avec le langage visuel existant sur
   fond indigo, pas une nouvelle couleur inventée pour l'occasion. */
tr.total-3 td { background: var(--indigo); color: var(--ivoire); font-weight: 700; font-size: 1.02em; padding-top: var(--space-3); padding-bottom: var(--space-3); border-top: 1px solid color-mix(in srgb, var(--ivoire) 30%, transparent); border-right: 1px solid color-mix(in srgb, var(--ivoire) 30%, transparent); }
tr.total-3 td:first-child { font-family: 'BP-Jakarta', sans-serif; }
/* Séparateur vertical (2026-08-19, retour Gauthier QA passe 4) — tr.total-3 hérite bien
   border-right de tbody td, mais dans sa couleur var(--line) : un gris clair conçu pour un
   fond blanc, quasi invisible sur le fond indigo de cette ligne. Même correctif que le
   border-top ci-dessus (ivoire semi-transparent), généralisé à TOUTES les lignes total-3 du
   site (Chiffre d'affaires, Résultat net, Total des charges, TOTAL ACTIF/PASSIF, Solde
   final...) — une seule règle par sélecteur de classe, jamais un correctif par tableau. */
tr.total-3 td:last-child { border-right: none; }

/* Lignes qui se soustraient dans une cascade (ex. Achats, Frais généraux) — parenthèses,
   convention financière universelle, jamais une couleur (rouge réservé aux anomalies). */
td.montant-negatif { font-variant-numeric: tabular-nums; }

/* Détail repliable sous sa ligne de sous-total (2026-08-10) — un <tbody> par groupe de
   détail, juste après la ligne qui le porte ; caché/affiché via l'attribut [hidden], jamais
   une table séparée plus bas dans la page (bien moins lisible, retour Gauthier). */
.btn-toggle-detail { display: inline-flex; align-items: center; gap: 0.4rem; background: none; border: none; padding: 0; margin: 0; font: inherit; color: inherit; cursor: pointer; text-align: left; }
.btn-toggle-detail .icon { width: 0.85rem; height: 0.85rem; flex-shrink: 0; transition: transform 0.15s ease; }
.btn-toggle-detail[aria-expanded="true"] .icon { transform: rotate(180deg); }
tbody.detail-group td:first-child { padding-left: calc(var(--space-4) + 1.15rem); color: var(--text-soft); font-weight: 400; font-style: normal; }
tbody.detail-group td { background: color-mix(in srgb, var(--text) 3%, var(--surface)); font-size: 0.94em; }

/* ── Coquille Cockpit (synthese.html, 2026-08-10) — sidebar persistante + panneau de
   contenu qui bascule sans recharger la page (navigation douce, historique du navigateur
   respecté via history.pushState). Squelette du futur Cockpit (Chantier 5) : l'édition des
   hypothèses et les recommandations IA viendront se greffer sur cette même coquille,
   jamais une reconstruction séparée. ─────────────────────────────────────────────────── */

.cockpit-shell { display: flex; align-items: flex-start; gap: var(--space-5); margin-top: 1.5rem; }
/* top calé sur --cockpit-topbar-bottom (mesuré en JS, reserverEspaceTopbar() dans
   js/synthese.js) — jamais var(--space-4) seul : ça collait le sidebar sticky sous le SEUL
   menu principal (--nav-h), pas sous la barre collante du Cockpit par-dessus, qui le
   recouvrait dès qu'on scrollait (bug constaté 2026-08-17, retour Gauthier — "Vue
   d'ensemble" disparaissait sous la sticky nav bar). */
/* Fond distinct du reste de la zone de contenu (2026-08-19, retour Gauthier § revue UI/UX
   banque/investisseur) — var(--surface), jamais var(--bg) : la page (.wrap) est en --bg
   (gris très clair / bleu marine selon le thème), la sidebar prend le blanc/surface des
   cartes pour marquer clairement la séparation nav/contenu, cohérent avec la carte
   Vue d'ensemble déjà sur --surface. */
.cockpit-sidebar { flex: 0 0 208px; display: flex; flex-direction: column; gap: var(--space-2); position: sticky; top: var(--cockpit-topbar-bottom, 84px); background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: var(--space-3); }
/* Mini-blocs de la sidebar Cockpit (2026-08-25, retour Gauthier — capture d'écran, "on crée
   visuellement des mini-blocs... fond de couleur distincte de celle du fond du menu") : 3
   groupes (Vue d'ensemble seule / KPI-Stress-tests-Cockpit / le reste des tableaux) — jamais
   un changement des liens eux-mêmes, purement une présentation groupée construite côté JS
   (js/synthese.js::renderSidebarLiens()). Fond --bg (le gris/marine de la PAGE, jamais
   --surface — la sidebar elle-même est déjà en --surface, un fond identique ne créerait
   aucune distinction visuelle). .cockpit-sidebar-groupe-accent (KPI/Stress-tests/Cockpit,
   le trio diagnostic/interactif) reprend l'indigo de marque en lavis léger — jamais la
   couleur pleine, réservée à l'état actif d'un lien. */
.cockpit-sidebar-groupe { display: flex; flex-direction: column; gap: var(--space-1); background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius); padding: var(--space-2); }
.cockpit-sidebar-groupe-accent { background: color-mix(in srgb, var(--accent) 9%, var(--bg)); border-color: color-mix(in srgb, var(--accent) 35%, var(--line)); }
/* Récapitulatif n'a PAS de 2e barre collante au-dessus (contrairement à synthese.js et son
   .cockpit-topbar) — le fallback générique 84px ci-dessus est une estimation pour CE cas-là,
   pas pour celui-ci : si --nav-h (menu principal, mesuré en JS par nav.js) dépasse
   réellement 84px sur un affichage donné, la sidebar collait sous le menu fixe au lieu de le
   dégager, invisible/inatteignable pendant le scroll (même famille de bug que celui déjà
   corrigé le 2026-08-17 sur synthese.js — cf. commentaire au-dessus). Sélecteur d'ID, plus
   spécifique que .cockpit-sidebar seul : gagne sans !important. */
/* max-height + overflow-y (2026-08-19, retour Gauthier — le décalage top seul n'a pas
   suffi : 11 liens + padding peuvent dépasser la hauteur du viewport sur un écran bas ;
   une fois "collée" en haut, une position:sticky ne révèle jamais plus de son propre
   contenu au scroll de la PAGE — ses derniers liens (ex. "Narratif BP") restaient donc
   sous le bord de l'écran, inatteignables, exactement le symptôme d'origine malgré le
   `top` déjà corrigé. Scoped à #recap-sidebar uniquement (jamais .cockpit-sidebar
   générique) — la sidebar de la Vue d'ensemble (10 sections) est déjà "sticky et
   fonctionnelle", explicitement exclue de toute modification. */
#recap-sidebar { top: var(--nav-h, 60px); max-height: calc(100vh - var(--nav-h, 60px) - 1.5rem); overflow-y: auto; }
.cockpit-sidebar a { display: block; padding: var(--space-2) var(--space-3); border-radius: var(--radius); color: var(--text); text-decoration: none; font-size: 0.92rem; }
.cockpit-sidebar a:hover { background: color-mix(in srgb, var(--accent) 10%, transparent); }
.cockpit-sidebar a.active { background: var(--accent); color: var(--accent-contrast); font-weight: 700; }
.cockpit-content { flex: 1 1 auto; min-width: 0; }
.cockpit-content .recap-section:first-child { margin-top: 0; }

.cockpit-card-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: var(--space-4); }
/* Cartes du cockpit (2026-08-12, retour Gauthier § 4) — la tuile d'icône pleine couleur
   (icon-tile-*, seule exception au registre anguleux du site) donne à chaque carte une
   identité visuelle immédiate au lieu d'un simple encadré monochrome ; ombre portée légère
   + lift au survol pour sortir du plat. Couleurs cyclées côté JS (carteCockpit()), jamais
   sage/sage-soft ici — cette teinte est réservée aux verdicts de KPI. */
a.cockpit-card {
  display: flex; flex-direction: column; gap: var(--space-2);
  border: 1px solid var(--line); background: var(--surface); border-radius: var(--radius);
  padding: var(--space-4); text-decoration: none; color: inherit;
  box-shadow: 0 1px 2px color-mix(in srgb, var(--text) 6%, transparent);
  transition: border-color 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease;
  /* min-width:0 (2026-08-27, audit mobile — retour Gauthier, capture Vue d'ensemble réelle,
     "6,5k€ → 314,7k€" tronqué au bord de l'écran) : piège CSS Grid classique — un item de
     grille garde par défaut une largeur minimale = la largeur intrinsèque de son contenu
     (min-content), qui PASSE OUTRE le 1fr de grid-template-columns si le contenu est plus
     large. .cockpit-card-kpi-paire a pourtant déjà flex-wrap:wrap (2026-08-19, pensé
     exactement pour ce cas) — sans effet tant que la carte elle-même, item de grille,
     refuse de rétrécir en dessous de ce contenu non wrappé pour calculer sa propre largeur.
     Même famille de bug que le fil d'Ariane des pages Projet (ada4567), ici sur une grille
     plutôt qu'un flex imbriqué. */
  min-width: 0;
}
/* Micro-interaction hover un peu plus marquée que le lift existant (2026-08-19, retour
   Gauthier — "renforcer le sentiment de cockpit interactif") : légère montée en échelle en
   plus du translateY déjà en place, jamais l'un sans l'autre. */
a.cockpit-card:hover { border-color: var(--accent); transform: translateY(-2px) scale(1.01); box-shadow: 0 6px 16px color-mix(in srgb, var(--text) 10%, transparent); }
a.cockpit-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Tuile réduite par rapport à la taille .icon-tile par défaut (3.25rem, pensée pour un
   picto isolé de mise en avant) — sur une grille dense de 6-9 cartes, elle prenait trop de
   place à l'écran (retour Gauthier 2026-08-13 § 13). Override local, jamais sur .icon-tile
   lui-même : les autres usages (empty states...) gardent leur taille normale. */
/* min-width:0 (2026-08-27, audit mobile, suite du fix a.cockpit-card ci-dessus) — le fix
   parent empêche la CARTE de déborder de sa colonne de grille, mais .cockpit-card-head est
   elle-même un flex row imbriquée (icône + titre) : sans son propre min-width:0, elle hérite
   du même piège à son niveau, laissant le TEXTE du titre déborder visuellement (retour
   Gauthier — "textes trop longs comme Trésorerie ou Investissements", capture réelle). */
.cockpit-card-head { display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
a.cockpit-card .icon-tile { width: 2.25rem; height: 2.25rem; border-radius: 9px; flex-shrink: 0; }
a.cockpit-card .icon-tile .icon { width: 1.1rem; height: 1.1rem; }
/* overflow-wrap:anywhere — un titre en un seul mot ("INVESTISSEMENTS") n'a aucun espace où
   wrapper naturellement ; sans ça, min-width:0 seul laisse le mot déborder tel quel plutôt
   que de le couper en dernier recours. N'affecte jamais les titres à plusieurs mots
   ("COMPTE DE RÉSULTAT"), qui continuent de wrapper sur les espaces normalement. */
a.cockpit-card h3 { margin: 0; font-size: 0.85rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.03em; color: var(--text-soft); overflow-wrap: anywhere; }
a.cockpit-card .cockpit-card-kpi { font-family: 'BP-Jakarta', sans-serif; font-size: 1.35rem; font-weight: 700; font-variant-numeric: tabular-nums; }
/* Chiffre principal en paire "départ → arrivée" (2026-08-19, retour Gauthier QA passe 2 § A)
   — remplace un chiffre isolé sur les cartes où une comparaison dans le temps est le vrai
   repère de lecture (Revenus/Charges/Compte de résultat/Trésorerie/Bilan/Emprunts). Le
   départ reste en retrait (taille/poids réduits, couleur --text-soft) pour ne jamais
   concurrencer l'arrivée, qui hérite de la taille normale de .cockpit-card-kpi (aucune règle
   de taille sur .cockpit-card-kpi-fin — elle prend celle du parent). flex-wrap : sur les
   cartes les plus étroites (grille à 2 colonnes mobile), la paire redescend plutôt que de
   forcer un débordement horizontal. */
a.cockpit-card .cockpit-card-kpi-paire { display: flex; align-items: baseline; gap: 0.4rem; flex-wrap: wrap; }
a.cockpit-card .cockpit-card-kpi-debut { font-size: 0.85rem; font-weight: 600; color: var(--text-soft); font-variant-numeric: tabular-nums; }
a.cockpit-card .cockpit-card-kpi-fleche { font-size: 0.85rem; color: var(--text-soft); }
a.cockpit-card .cockpit-card-sub { font-size: 0.82rem; color: var(--text-soft); }
/* Mini-graphique de tendance (2026-08-13, retour Gauthier § 13, option B ; généralisé
   2026-08-19 à un contenu par carte — barres = flux annuel, courbe = valeur cumulée/stock,
   barre empilée horizontale = composition instantanée pour Financement). Le total de la
   dernière année reste la donnée mise en avant (cockpit-card-kpi), le mini-graphique ajoute
   le contexte d'évolution sans reproduire le tableau annuel complet déjà présent dans la vue
   détaillée en un clic. Hauteur fixe : toutes les cartes gardent la même hauteur qu'elles
   affichent un graphique ou non (cohérence stricte de la grille, retour Gauthier). */
/* flex-direction: column (2026-08-25, retour Gauthier — capture d'écran "Vue d'ensemble
   synthétique", carte Financement) : en row (défaut précédent), le SVG (width:100%) et
   .chart-legende se disputaient la même ligne — la légende se retrouvait compressée contre le
   bord droit de la barre, chaque item repassant à la ligne faute de place. Colonne + gap :
   graphique et légende empilés proprement, quel que soit le nombre de segments. */
a.cockpit-card .cockpit-card-chart { min-height: 2.25rem; display: flex; flex-direction: column; align-items: stretch; gap: 0.3rem; margin: 0.1rem 0; }
a.cockpit-card .bizz-chart-sparkline { height: 2.25rem; width: 100%; }
a.cockpit-card .bizz-chart-barre-horizontale { height: 0.9rem; width: 100%; }
a.cockpit-card .chart-legende { font-size: 0.68rem; gap: 0.5rem; margin-top: 0.15rem; }
/* Indicateur secondaire + badge de statut (2026-08-19) — même ligne, badge à droite si les
   deux sont présents ; sinon l'un ou l'autre seul occupe toute la ligne. */
.cockpit-card-meta { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); flex-wrap: wrap; min-height: 1.4rem; }
.cockpit-card-indicateur { font-size: 0.78rem; color: var(--text-soft); }
.cockpit-card-meta .pill { font-size: 0.7rem; padding: 0.2rem 0.55rem; }
/* Carte d'action "Hypothèses" (2026-08-19) — structure volontairement différente des 8
   autres (pas de graphique/indicateur/badge), gardée sobre : centrée verticalement pour ne
   pas paraître "cassée" à côté des cartes de données bien remplies. */
a.cockpit-card.cockpit-card-action { justify-content: center; }

@media (max-width: 760px) {
  /* align-items:stretch (2026-08-28, audit mobile — retour Gauthier, mesure Web Inspector
     reelle : .cockpit-content lui-meme a 608px de large sur un ecran de 375px, alors qu'il
     porte deja flex:1 1 auto + min-width:0). Root cause de TOUTE la cascade de debordement
     restante sur les pages PF (KPI de synthese, tableaux, boutons d'action...) — jamais un
     bug local a un composant precis. .cockpit-shell { align-items:flex-start } (plus haut,
     pensee pour le layout desktop en ligne : sidebar/contenu gardent chacun leur propre
     hauteur, jamais etires l'un sur l'autre) prend un sens TOTALEMENT DIFFERENT une fois
     flex-direction passee en column ci-dessous : l'axe transversal devient alors horizontal
     (la largeur), et flex-start fait alors RETRECIR chaque enfant a la largeur de SON PROPRE
     CONTENU plutot que de l'etirer sur toute la largeur disponible — .cockpit-sidebar avait
     deja son propre correctif manuel (width:100% ci-dessous), jamais applique a
     .cockpit-content, qui heritait donc silencieusement de la largeur de son plus large
     enfant (table, texte...) au lieu d'etre borne par l'ecran. */
  .cockpit-shell { flex-direction: column; align-items: stretch; }
  .cockpit-sidebar { flex-direction: row; flex-wrap: wrap; position: static; width: 100%; padding: var(--space-2); }
  .cockpit-sidebar-groupe { flex-direction: row; flex-wrap: wrap; }
  /* Grille de cartes à 2 colonnes préservée sur mobile/tablette (retour Gauthier, contrainte
     transversale) — jamais 1 seule colonne, même sur un iPhone SE 375px. Fallback lisible
     pour les mini-graphiques : la légende texte (liste des segments) est le premier élément
     sacrifié à cette largeur, le graphique lui-même (+ son tooltip au tap) reste. */
  .cockpit-card-grid { grid-template-columns: repeat(2, 1fr); gap: var(--space-3); }
  a.cockpit-card { padding: var(--space-3); }
  a.cockpit-card .chart-legende { display: none; }
  .cockpit-card-indicateur { font-size: 0.72rem; }
}

/* Barre collante du Cockpit (2026-08-14, retour Gauthier — restructuration nav de
   synthese.html) : Récapitulatif toujours accessible dès le chargement + statut de l'Arrêt
   du PF, empilée sous le menu principal comme .stepper-sticky (même z-index). `.wrap` reçoit
   un margin-top compensatoire égal à la hauteur réelle mesurée en JS (reserverEspaceTopbar,
   js/synthese.js) — jamais un nombre en dur, même pattern que js/stepper.js. Le badge de
   statut est un simple lien (data-section="arret") qui renvoie vers la section correspondante
   de la sidebar plutôt qu'un bouton actionnable — une seule source de vérité pour l'action
   d'arrêt, cf. retour Gauthier § navigation. */
.cockpit-topbar { position: fixed; top: var(--nav-h, 60px); left: 0; right: 0; z-index: 30; background: var(--surface); border-bottom: 1px solid var(--line); box-shadow: 0 2px 10px rgba(0,0,0,0.08); }
.cockpit-topbar-inner { max-width: 960px; margin: 0 auto; display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); padding: var(--space-2) var(--space-4); flex-wrap: wrap; }
/* Sous 480px, .cockpit-topbar-statut (Imprimer/PDF, Compiler le PDF final…) redescend sur sa
   propre ligne pleine largeur plutôt que de flotter à côté d'une ligne du fil d'Ariane
   (2026-08-27, audit mobile) — cohérent avec le fil d'Ariane empilé en colonne juste
   au-dessus (.scenario-nav-breadcrumb). */
@media (max-width: 480px) {
  .cockpit-topbar-inner { align-items: flex-start; }
  .cockpit-topbar-statut { flex-basis: 100%; padding-left: 0; border-left: none; margin-top: var(--space-2); }
}
/* Regroupe Récapitulatif + Imprimer/PDF (2026-08-19) — sans ce conteneur, justify-content:
   space-between de .cockpit-topbar-inner écarterait le bouton Imprimer au centre au lieu de
   le coller à côté du lien Récapitulatif. */
/* min-width:0 (2026-08-27, audit mobile) : sans ça, un conteneur flex qui est LUI-MÊME un
   item d'un flex parent garde par défaut min-width:auto — il refuse alors de rétrécir en
   dessous de la largeur naturelle de son contenu, ce qui peut empêcher le flex-wrap du
   parent de s'enclencher correctement même quand flex-wrap:wrap est posé partout dans la
   chaîne (piège flexbox classique sur les layouts imbriqués). Root cause du débordement
   latéral de la barre Projet/Scénario/Mode sur synthese.html/business-plan.html à 375px
   (retour Gauthier, captures DevTools) — recapitulatif.html, qui utilise la même coquille
   scenario-nav.js, s'en sortait car son contenu de page en dessous imposait déjà une
   largeur différente. Posé sur toute la chaîne de conteneurs imbriqués ci-dessous, jamais
   seulement au niveau le plus haut. */
.cockpit-topbar-gauche { display: flex; align-items: center; gap: var(--space-4); flex-wrap: wrap; min-width: 0; }
.cockpit-topbar-recap { font-family: 'BP-Inter', sans-serif; font-size: 0.85rem; font-weight: 700; color: var(--accent); text-decoration: none; white-space: nowrap; }
.cockpit-topbar-recap:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
/* Séparateur visuel (retour Gauthier 2026-08-17 — "pas de menu secondaire distinctement
   visible") : avant ce correctif, .cockpit-topbar-statut n'avait aucun habillage propre — ses
   boutons/badge flottaient au même niveau visuel que .cockpit-topbar-gauche (onglets +
   sélecteur), sans repère marquant où finit la nav principale et où commence la zone d'action
   contextuelle de la page. Un simple filet vertical + respiration à gauche suffit à les
   distinguer, sans surcharger un CTA qui porte déjà son propre style (.btn/.pill) — jamais un
   second fond/pilule autour de boutons déjà habillés, qui alourdirait plus qu'il ne clarifierait. */
.cockpit-topbar-statut { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; padding-left: var(--space-4); border-left: 1px solid var(--line); min-width: 0; }
.cockpit-topbar-statut:empty { padding-left: 0; border-left: none; }
.cockpit-topbar-statut a.pill { text-decoration: none; cursor: pointer; }

/* Coquille de navigation persistante (js/scenario-nav.js) — injectée dans
   .cockpit-topbar-gauche sur synthese.html/business-plan.html/recapitulatif.html, remplace
   l'ancien lien "← Retour" unique et incohérent d'une page à l'autre (retour Gauthier : "un
   dédale"). Fil d'Ariane à 3 pilules (Projet / Module / Scénario), adopté le 2026-08-19
   après comparaison avec l'ancien duo "3 onglets + sélecteur de scénario en dessous" — cf.
   commentaire de fichier de js/scenario-nav.js. Toutes les pilules partagent le même langage
   visuel .scenario-nav-select-* (étiquette + pilule teintée), aucun 2e style introduit ici. */
.scenario-nav-breadcrumb { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; min-width: 0; }
.scenario-nav-breadcrumb-sep { color: var(--text-soft); font-size: 0.9rem; }

/* Sous 480px, empilement déterministe d'une pilule par ligne plutôt que de compter sur le
   calcul naturel de flex-wrap (2026-08-27, retour Gauthier — captures DevTools réelles sur
   synthese.html/business-plan.html/recapitulatif.html+Wizard, MÊME composant partagé) : le
   correctif min-width:0 ci-dessus corrige bien le blocage du wrap, mais "combien de pilules
   tiennent sur la ligne 1" reste ensuite un calcul au pixel près (police BP-Inter chargée ou
   non au moment du rendu, arrondis sous-pixel) — business-plan.html/recapitulatif.html
   atterrissaient sur 1 pilule/ligne par chance, synthese.html sur "2 pilules puis ça déborde"
   avec le MÊME code. flex-direction:column supprime cette ambiguïté : jamais de calcul de
   tenue à la ligne, comportement identique quelle que soit la page. Le séparateur "/" perd
   son sens en colonne (chaque ligne est déjà auto-portée par son étiquette Projet/Scénario/
   Mode) — masqué plutôt que ré-empilé bizarrement entre deux lignes. */
@media (max-width: 480px) {
  .scenario-nav-breadcrumb { flex-direction: column; align-items: flex-start; gap: var(--space-2); }
  .scenario-nav-breadcrumb-sep { display: none; }
}

/* Chaque pilule (Projet/Module/Scénario) sur la même ligne, jamais l'une sous l'autre —
   contrairement à l'ancien groupe Scénario isolé (qui portait flex-basis:100%/margin-top/
   border-left, pensés pour une pilule seule posée sous la rangée d'onglets). Masquée tant
   qu'un seul scénario existe pour la pilule Scénario elle-même
   (js/scenario-nav.js::buildPiluleScenario) — jamais un choix affiché quand il n'y en a pas. */
.scenario-nav-select-group { display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
.scenario-nav-select-label {
  font-family: 'BP-Inter', sans-serif; font-size: 0.78rem; font-weight: 600;
  color: var(--text-muted, var(--text)); letter-spacing: 0.01em;
  white-space: nowrap;
}
/* Compteur "(N/3)" (2026-08-23, js/scenario-nav.js::buildPiluleScenario) — poids normal
   (jamais 600 comme le libellé "Scénario" qu'il complète) pour rester visuellement
   secondaire, même couleur muted que le libellé pour ne pas créer un 3e niveau de contraste
   dans le fil d'Ariane. */
.scenario-nav-compteur { font-weight: 400; opacity: 0.75; }
/* Bouton + liste maison plutôt qu'un <select> natif (retour Gauthier 2026-08-17, 3 défauts
   constatés sur le <select> : anneau de focus natif "ovale indigo superposé" que
   `outline`/`border-radius` ne parvient pas à faire correspondre à notre pilule dans tous
   les navigateurs, popup natif qui s'ouvrait parfois vers le HAUT (positionnement 100%
   hors de notre contrôle, ce composant vit dans .cockpit-topbar en position:fixed près du
   haut de la fenêtre — heuristique du navigateur imprévisible dans ce contexte), et surbrillance
   d'option dans la couleur d'accent DU SYSTÈME D'EXPLOITATION, jamais la nôtre. Un <select>
   natif ne se laisse pas intégralement styler cross-browser sur ces 3 points — remplacé par
   un bouton (valeur + chevron) + une <ul role="listbox"> positionnée nous-mêmes juste
   en-dessous (jamais au-dessus, jamais laissée au navigateur), câblé en JS
   (js/scenario-nav.js::inject()). */
.scenario-nav-select-pill {
  position: relative; display: inline-flex; align-items: center;
  background: var(--accent-tint, rgba(76, 29, 149, 0.08)); border: 1px solid var(--line-strong);
  border-radius: 999px; padding: 0 var(--space-3);
}
/* font-size aligné sur .scenario-nav-select-label ci-dessus (0.78rem, retour Gauthier
   2026-08-18 — "taille de texte identique à celle du mot Scénario") : les deux affichaient
   des tailles différentes (0.85rem ici auparavant), rompant la cohérence graphique du
   groupe étiquette+valeur. */
.scenario-nav-select-btn {
  display: inline-flex; align-items: center; gap: var(--space-2); max-width: 260px;
  appearance: none; -webkit-appearance: none; border: none; background: transparent;
  font-family: 'BP-Inter', sans-serif; font-size: 0.78rem; font-weight: 600; color: var(--accent);
  padding: 0.4rem 0; cursor: pointer; outline: none;
}
/* 260px est un plafond pensé pour desktop (n'entre jamais en jeu tant qu'un nom de
   projet/scénario reste court) — sous 480px, resserré nettement pour que l'ellipsis
   s'enclenche systématiquement même sur un nom court comme "Tikkoun Extended Search 9" :
   avec min-width:0 posé sur toute la chaîne de conteneurs ci-dessus (2026-08-27, audit
   mobile), les 3 pilules Projet/Scénario/Mode réunies dépassaient encore la largeur d'un
   iPhone SE avant ce resserrement, même une fois le wrap réparé. */
@media (max-width: 480px) {
  .scenario-nav-select-btn { max-width: 108px; }
}
/* box-shadow sur le CONTENEUR .scenario-nav-select-pill, jamais sur .scenario-nav-select-btn
   lui-même (bug réel trouvé le 2026-08-19, retour Gauthier — "cercle indigo sur la zone
   cliquable du sélecteur") : le bouton a un padding horizontal nul (0.4rem 0, cf. règle
   ci-dessus), donc un anneau posé dessus est plus étroit que la pilule teintée réellement
   perçue comme zone cliquable — il "flotte" à l'intérieur au lieu d'épouser son contour.
   Posé sur le conteneur via :focus-within, l'anneau épouse exactement la pilule (même
   border-radius:999px que .scenario-nav-select-pill) — ironique, puisque ce composant a été
   construit à l'origine pour éliminer précisément ce défaut sur le <select> natif remplacé
   (cf. commentaire plus haut). */
.scenario-nav-select-pill:focus-within { box-shadow: 0 0 0 2px var(--focus-ring); }
/* Empêche un long nom de scénario (renommage libre, cf. dashboard.js) de pousser le chevron
   hors champ (retour Gauthier 2026-08-17, "scénario n°3 déborde") — ellipsis sur la valeur
   seule, jamais sur le chevron (flex-shrink:0, toujours visible). */
.scenario-nav-select-value { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.scenario-nav-select-chevron { width: 0.85em; height: 0.85em; color: var(--accent); flex-shrink: 0; transition: transform 0.15s; }
.scenario-nav-select-btn[aria-expanded="true"] .scenario-nav-select-chevron { transform: rotate(180deg); }
/* top:100% fixe la liste TOUJOURS sous le bouton, jamais au-dessus — plus de dépendance à
   une heuristique de navigateur qui décidait mal dans ce contexte position:fixed. */
.scenario-nav-select-list {
  position: absolute; top: 100%; left: 0; margin-top: var(--space-2); list-style: none;
  min-width: 100%; max-height: 240px; overflow-y: auto; z-index: 40;
  background: var(--surface); border: 1px solid var(--line-strong); border-radius: var(--radius);
  box-shadow: 0 8px 24px rgba(0,0,0,0.16); padding: var(--space-2);
}
.scenario-nav-select-option {
  padding: 0.45rem var(--space-3); border-radius: var(--radius);
  font-family: 'BP-Inter', sans-serif; font-size: 0.85rem; font-weight: 600;
  color: var(--text); white-space: nowrap; cursor: pointer;
}
/* Notre propre teinte d'accent, jamais la surbrillance native du système d'exploitation
   (retour Gauthier — 2e défaut du <select> natif). */
.scenario-nav-select-option:hover { background: var(--accent-tint, rgba(76, 29, 149, 0.08)); }
.scenario-nav-select-option.selected { color: var(--accent); background: var(--accent-tint, rgba(76, 29, 149, 0.08)); }

/* ── Récapitulatif (recapitulatif.html) — sections lecture seule ───────────── */

/* 2026-08-12, retour Gauthier § 2 : ces blocs (recap-section) n'étaient qu'une <dl> nue,
   sans séparateur ni fond ni hiérarchie — "invisible table". Traitement carte + bandeau
   d'en-tête teinté, repris à l'identique par .bloc-action-secondaire et par les cartes du
   cockpit (même bloc, même fichier) pour une cohérence unique. Le bandeau bleede jusqu'aux
   bords de la carte (padding porté par lui, pas par .recap-section) ; le corps reçoit son
   inset horizontal via une marge sur les enfants directs plutôt qu'un padding général —
   .table-wrap et .kv-grid restent ainsi de simples enfants, sans wrapper supplémentaire. */
.recap-section { margin-top: 2.5rem; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); padding-bottom: var(--space-4); }
.recap-section-head {
  display: flex; justify-content: space-between; align-items: baseline; gap: var(--space-3); flex-wrap: wrap;
  margin: 0 0 var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: color-mix(in srgb, var(--accent) 6%, var(--surface));
  border-bottom: 1px solid var(--line);
  border-radius: var(--radius) var(--radius) 0 0;
}
.recap-section-head h2 { margin: 0; font-size: 1rem; }
.recap-section > *:not(.recap-section-head) { margin-left: var(--space-4); margin-right: var(--space-4); }

/* Sépare visuellement une action principale (ex. "Arrêter mon Plan Financier") d'une
   action secondaire/utilitaire à côté (ex. "Reproduire") — la bordure en pointillés
   signale un chemin alternatif, pas une simple variante de la même action (retour
   Gauthier 2026-08-12 : les deux boutons côte à côte laissaient planer un doute). */
.bloc-action-secondaire { margin-top: var(--space-4); padding-top: var(--space-4); border-top: 1px dashed var(--line); }

.kv-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--space-3) var(--space-4);
}
/* 2026-08-13, retour Gauthier § 11.1 : dt/dd même taille + même poids de gris que le reste
   du texte rendaient le champ et sa valeur difficiles à distinguer d'un coup d'œil (surtout
   en grille dense, ex. Modèle d'affaires). Distinction portée par la couleur (dt en indigo)
   plutôt que par un écart de taille — cohérent avec la hiérarchie typographique restreinte
   du reste du site. */
.kv-item dt { font-size: 0.95rem; font-weight: 600; color: var(--accent); margin: 0; }
.kv-item dd { font-size: 0.95rem; margin: 0.15rem 0 0; }

/* Affordance de survol (2026-08-24, chantier UI/UX Cockpit) — [data-tooltip] n'avait jusqu'ici
   AUCUN indice visuel qu'un élément est survolable (mécanisme déjà en place, cf.
   js/synthese.js § "Infobulle personnalisée pour les graphiques SVG", jamais stylé). Bordure
   pointillée UNIQUEMENT sur un <dt> (les libellés de Stress-tests/KPI, texte déjà souligné
   visuellement par la couleur accent ci-dessus) — jamais sur les autres usages existants
   (titres/libellés de sliders Cockpit, cellules TCAM) pour ne pas alourdir des éléments déjà
   denses visuellement ; le curseur "help" reste, lui, appliqué à TOUT élément [data-tooltip]. */
[data-tooltip] { cursor: help; }
dt[data-tooltip] { border-bottom: 1px dotted currentColor; }

/* .kv-grid-framed (2026-08-20, retour Gauthier — fiche de Stress-tests, densité de KPI plus
   forte que les autres usages de kv-grid) : cadre visible par item, la distinction purement
   typographique de .kv-item (dt en indigo, dd en gris) ne suffisait plus à délimiter chaque
   paire label/valeur d'un coup d'œil. Classe additive scopée (jamais sur .kv-item directement)
   pour ne changer aucun des autres usages existants (récapitulatif, KPI de synthèse,
   échéancier d'emprunt...). */
.kv-grid-framed .kv-item {
  border: 1px solid var(--line); border-radius: var(--radius);
  padding: var(--space-3); background: var(--bg);
}

/* Cards profil "Responsable(s)" (recapitulatif.html, 2026-08-19, retour Gauthier) — remplace
   le tableau Nom/Statut/Bio, illisible dès qu'une bio dépassait une ligne. auto-fit (jamais
   auto-fill) : une seule card ne s'étire pas en pleine largeur disgracieuse — elle prend sa
   largeur naturelle plafonnée à 1fr, reste lisible à 1 comme à plusieurs responsables. */
.profil-card-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: var(--space-3); margin-top: 1rem; }
.profil-card { border: 1px solid var(--line); border-radius: var(--radius); padding: var(--space-3); background: var(--bg); }
.profil-card-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); }
.profil-card-nom { font-weight: 700; font-size: 1rem; }
.profil-card-badge { font-size: 0.68rem; padding: 0.2rem 0.55rem; }
.profil-card-statut { margin-top: 0.4rem; font-size: 0.72rem; }
.profil-card-bio { font-size: 0.88rem; margin: 0.6rem 0 0.2rem; white-space: pre-line; }
.profil-card-bio.clamped { display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden; }
.profil-card .btn-lire-plus { font-size: 0.78rem; }

/* ── Graphiques SVG faits maison (js/charts.js) — 2026-08-12, retour Gauthier § 3/5 ──── */

.kpi-charts { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: var(--space-4); margin-top: 1rem; }
/* .kpi-charts est aussi utilisé, replié, pour le panneau "Graphify this!" (attribut
   hidden) — sans cette règle, le display:grid ci-dessus l'emporte sur [hidden] (même
   spécificité CSS qu'un sélecteur de classe, mais après lui dans la cascade de l'agent
   utilisateur) et le panneau reste visible malgré hidden. Bug réel trouvé le 2026-08-12 en
   testant visuellement l'état replié. */
.kpi-charts[hidden] { display: none; }
.kpi-chart-bloc { border: 1px solid var(--line); border-radius: var(--radius); padding: var(--space-3); background: var(--bg); }
.kpi-chart-bloc h3 { margin: 0 0 var(--space-2); font-size: 0.8rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.03em; color: var(--text-soft); }
.bizz-chart { width: 100%; height: auto; display: block; }
.bizz-chart .chart-valeur { font-family: 'BP-Jakarta', sans-serif; font-size: 9px; font-weight: 700; fill: var(--text); }
.bizz-chart .chart-label { font-family: 'BP-Inter', sans-serif; font-size: 8px; fill: var(--text-soft); }
/* Pourcentage affiché DANS un segment de barre empilée (2026-08-22, opt-in via
   opts.pourcentageVisibleSegments, cf. js/charts.js) — blanc plutôt que var(--text) : les
   teintes de couleurEmpilee() sont toutes assez saturées/sombres pour un texte clair,
   contrairement au fond neutre derrière .chart-valeur. */
.bizz-chart .chart-valeur-segment { font-family: 'BP-Jakarta', sans-serif; font-size: 9px; font-weight: 700; fill: #fff; pointer-events: none; }

/* Légende du graphique empilé (js/charts.js::barresEmpilees, § 14.5) — rendue en HTML à
   côté du SVG plutôt qu'à l'intérieur : texte net à toute taille, pas de recalcul de
   position par série. */
.chart-legende { display: flex; flex-wrap: wrap; gap: var(--space-3); margin-top: var(--space-2); }
.chart-legende-item { display: inline-flex; align-items: center; gap: 0.35rem; font-size: 0.78rem; color: var(--text-soft); }
.chart-legende-puce { width: 0.65rem; height: 0.65rem; border-radius: 2px; display: inline-block; flex-shrink: 0; }

/* Case "Graphify" par ligne de détail (§ 14.5) — coche une sous-catégorie pour l'ajouter
   au graphique empilé du poste parent, cf. ligneDetailPostesGraphify()/écouteur 'change'
   dans synthese.js. */
.detail-graphify-check { display: flex; align-items: center; gap: 0.4rem; cursor: pointer; font-weight: 400; }
.detail-graphify-check input { width: 0.9rem; height: 0.9rem; accent-color: var(--accent); flex-shrink: 0; }

/* "Combify this!" (2026-08-15, retour Gauthier § UX graphiques) — combine plusieurs
   graphiques KPI par défaut en un seul graphique à barres groupées (BizzCharts.
   barresGroupees), même mécanique de case à cocher que .detail-graphify-check ci-dessus
   mais hors tableau, d'où sa propre rangée plutôt qu'une cellule de <tr>. */
.combify-checks { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4); margin: var(--space-2) 0 var(--space-3); }
.graphify-panel { margin-top: 1rem; }

/* En-tête de section à plusieurs boutons (Graphify + Combify, 2026-08-16) — un seul wrapper
   flex plutôt que deux boutons concaténés en enfants directs de .recap-section-head, sinon
   son justify-content:space-between les écarterait du titre au lieu de les regrouper à
   droite. */
.recap-section-actions { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }

/* Infobulle personnalisée pour les graphiques SVG (2026-08-16, retour Gauthier) — remplace
   <title> natif (lent à apparaître, texte minuscule) sur les segments empilés/groupés,
   cf. écouteur mouseover/mousemove/mouseout délégué sur #synthese-content (js/synthese.js).
   Un seul élément partagé, ajouté une fois à <body>. */
/* max-width + white-space:normal (2026-08-18, retour Gauthier) : nowrap convenait aux
   infobulles courtes de graphique ("label : montant (%)") mais les phrases plus longues des
   boutons Graphify/Combify débordaient de l'écran en une seule ligne continue. Le
   positionnement (écouteur mousemove, js/synthese.js) borne aussi la position pour ne
   jamais dépasser le bord droit du viewport. */
.bizz-chart-tooltip {
  position: fixed; z-index: 60; pointer-events: none;
  background: var(--text); color: var(--bg);
  font-family: 'BP-Inter', sans-serif; font-size: 0.76rem; font-weight: 600;
  padding: 0.3rem 0.55rem; border-radius: var(--radius);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
  white-space: normal; max-width: 260px;
}
.bizz-chart-tooltip[hidden] { display: none; }

/* Volet latéral de détail mensuel (2026-08-17, retour Gauthier § mensualisation, Trésorerie
   uniquement pour l'instant) — un seul ouvert à la fois, cf. écouteur délégué sur contentEl
   (js/synthese.js) qui ferme systématiquement tout .volet-lateral déjà ouvert avant d'en
   afficher un autre. z-index au-dessus de .cockpit-topbar/.stepper-sticky (30) ET de
   .bizz-chart-tooltip (60) — un volet ouvert doit primer sur tout le reste de l'écran. */
/* --ivoire (jamais --accent) : le bouton vit DANS thead th, qui est en permanence fond
   --indigo/texte --ivoire (jamais adapté au thème clair/sombre, cf. règle thead th plus
   haut) — --accent/--accent-contrast changent avec le thème et s'étaient retrouvés
   identiques au fond indigo, bouton invisible (retour Gauthier 2026-08-17). */
/* Fond ivoire plein + texte indigo (2026-08-19, retour Gauthier QA passe 4 — "je te laisse
   choisir" entre fond blanc/texte indigo ou fond indigo clair/texte indigo) : contour seul
   se distinguait mal du fond indigo de thead th à distance/faible contraste écran ; un fond
   plein donne un vrai repère de bouton, cohérent avec .pill-indigo ailleurs dans l'appli
   (même logique inversée : fill+contraste plutôt qu'un simple contour). */
.btn-lien-mensuel {
  display: inline-block; margin-left: var(--space-2); font-family: 'BP-Inter', sans-serif;
  font-size: 0.7rem; font-weight: 700; color: var(--indigo); background: var(--ivoire);
  border: 1px solid var(--ivoire); border-radius: 999px; padding: 0.15rem 0.6rem;
  cursor: pointer; vertical-align: middle;
}
.btn-lien-mensuel:hover { background: color-mix(in srgb, var(--ivoire) 85%, transparent); }
.volet-backdrop { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.35); z-index: 70; }
/* Largeur fixée en JS (renderCashFlow, js/synthese.js) selon le nombre de colonnes réel —
   moins de bornes si la 1ère année est un exercice court (démarrage en cours d'année) — la
   valeur ici n'est qu'un repli si jamais le style inline n'est pas appliqué. */
.volet-lateral {
  position: fixed; top: 0; right: 0; bottom: 0; width: min(900px, 96vw); z-index: 71;
  background: var(--surface); box-shadow: -8px 0 24px rgba(0, 0, 0, 0.2);
  overflow-y: auto; padding: var(--space-4); display: flex; flex-direction: column; gap: var(--space-3);
}
.volet-backdrop[hidden], .volet-lateral[hidden] { display: none; }
.volet-lateral-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); }
.volet-lateral-head h2 { margin: 0; font-size: 1rem; }
.btn-fermer-volet { background: none; border: none; cursor: pointer; color: var(--text-soft); padding: var(--space-1); flex-shrink: 0; }
.btn-fermer-volet:hover { color: var(--text); }
.btn-fermer-volet .icon { width: 1.1rem; height: 1.1rem; }
@media (max-width: 620px) {
  .volet-lateral { width: 100vw; }
}

/* Modal centré (2026-08-17, retour Gauthier — confirmation avant production définitive du
   BP, "sobre et professionnel", jamais un window.confirm() natif) — réutilise
   .volet-backdrop tel quel (générique, déjà en place) et .volet-lateral-head/
   .btn-fermer-volet (pas spécifiques au positionnement latéral, réutilisables tels quels
   pour l'en-tête) ; seule cette classe-ci est nouvelle, le panneau latéral lui-même
   (.volet-lateral) n'est pas adapté à un dialogue centré (plein-hauteur, ancré à droite). */
.modal-centre {
  position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);
  width: min(480px, 92vw); z-index: 71;
  background: var(--surface); border-radius: var(--radius); box-shadow: 0 20px 60px rgba(0, 0, 0, 0.25);
  padding: var(--space-4); display: flex; flex-direction: column; gap: var(--space-3);
}
.modal-centre[hidden] { display: none; }
.modal-centre-actions { display: flex; justify-content: flex-end; gap: var(--space-2); margin-top: var(--space-2); }

/* Modal de coaching (2026-08-22) — liste des alertes déterministes, réutilise .pill tel quel
   (sévérité) devant chaque texte, pas de nouvelle palette. */
.coaching-alertes-liste { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); font-size: 0.9rem; }
.coaching-alertes-liste .pill { margin-right: 0.4rem; }

/* Évolution d'une année sur l'autre (§ 3) — flèche + %. Indigo (2026-08-13, retour
   Gauthier § 12, remplace --text-soft) pour distinguer le chiffre de référence (montant,
   couleur texte normale) de l'indice associé d'un coup d'œil — reste hors de la palette
   rouge/orange/vert, réservée aux verdicts de KPI (cf. CLAUDE.md). */
.kpi-evolution { font-size: 0.78rem; color: var(--accent); font-weight: 600; margin-left: 0.35rem; }

/* Coloration conditionnelle des valeurs brutes du tableau KPI (2026-08-19, retour Gauthier)
   — rouge/vert réservés à CET écran de verdict (jamais les cascades comptables, cf.
   formatMontantSigne/.montant-negatif plus haut, qui restent en parenthèses non colorées).
   kpi-valeur-positive reste en couleur de texte normale plutôt que --success plein : un CA
   positif (l'immense majorité des cellules) n'a pas besoin d'être criant de vert, seul le
   négatif doit sauter aux yeux. */
.kpi-valeur-positive { color: var(--text); }
.kpi-valeur-negative { color: var(--danger); font-weight: 600; }

/* ── Footer ──────────────────────────────────────────────────────────────── */

footer {
  margin-top: clamp(3rem, 7vw, 4rem);
  padding-top: 1.5rem;
  border-top: 1px solid var(--line);
  font-size: 0.82rem;
  color: var(--text-soft);
}

/* ── Impression PDF du Plan Financier (synthese.html, 2026-08-19) ──────────
   window.print() + CSS @media print plutôt qu'un rendu serveur (Chrome headless) — aucune
   nouvelle dépendance, cohérent avec le vanilla JS du site ; les données sont déjà
   entièrement dans le DOM aujourd'hui (Cockpit), donc aucune perte de protection du
   know-how par rapport à l'existant (CLAUDE.md § protection du know-how). Deux "modes"
   (auto/manuel) unifiés en UNE seule liste à cocher (js/synthese.js::ouvrirSelectionImpression) —
   tout coché par défaut = auto, décocher des sections = manuel, jamais deux interfaces
   séparées pour ce qui est fondamentalement le même filtre. */
.liste-impression-checks { display: flex; flex-direction: column; gap: var(--space-2); margin: var(--space-2) 0 var(--space-3); }
.liste-impression-actions { display: flex; gap: var(--space-2); flex-wrap: wrap; margin-top: auto; padding-top: var(--space-3); border-top: 1px solid var(--line); }

/* Champs du formulaire "Page de garde" dans le panneau d'impression (2026-08-19) — label +
   input/textarea empilés, même esprit que les autres formulaires du site (jamais un composant
   dédié pour 6 champs). */
.champ-impression { display: flex; flex-direction: column; gap: 0.25rem; font-size: 0.85rem; margin-bottom: var(--space-2); }
.champ-impression input, .champ-impression textarea { font: inherit; padding: 0.4rem 0.5rem; border: 1px solid var(--line); border-radius: 6px; background: var(--surface); color: var(--text); resize: vertical; }

/* Invisible à l'écran, seul contenu visible à l'impression (cf. @media print ci-dessous) —
   reconstruit à chaque impression depuis dernierParType (js/synthese.js), jamais un doublon
   synchronisé en continu avec le Cockpit. */
.zone-impression { display: none; }

@media print {
  /* Numéro de page (2026-08-17, retour Gauthier) — sur la règle @page GÉNÉRIQUE, jamais une
     page nommée séparée : une page nommée appliquée au document du BP produisait
     systématiquement une 1re page blanche, même posée sur l'élément le plus extérieur du
     contenu imprimé (comportement du moteur d'impression de Chrome plus fiable à éviter
     qu'à corriger). S'applique donc aussi à l'impression du PF (bénéfice secondaire assumé,
     jamais demandé séparément mais cohérent — un document imprimé sans numéro de page est
     rarement voulu). counter(page) seul, jamais "N / Total" : counter(pages) (total) n'est
     pas fiable cross-navigateur dans les moteurs d'impression actuels. */
  @page { size: A4 portrait; margin: 1.5cm; @bottom-center { content: counter(page); font-size: 8pt; color: #666; } }
  @page paysage { size: A4 landscape; margin: 1cm; }
  /* Bug réel trouvé le 2026-08-20 (retour Gauthier — "la plupart des chiffres est désormais
     invisible" sur un PDF exporté depuis un navigateur en mode sombre) : body.background
     était bien forcé en blanc ci-dessous, mais --text/--text-soft (et le reste des variables
     thématiques) ne l'étaient jamais — un système/navigateur en dark mode fournit --text:
     #F8FAFC (quasi blanc) via @media(prefers-color-scheme:dark) ou :root[data-theme="dark"]
     (css/style.css, tout en haut), qui continue de s'appliquer À L'INTÉRIEUR de ce
     @media print. Texte quasi blanc sur fond forcé blanc = invisible, sauf les rares
     éléments à couleur FIXE (ex. tr.total-3 : background:var(--indigo)/color:var(--ivoire),
     --indigo/--ivoire ne variant jamais avec le thème, cf. palette de marque en tête de
     fichier) — d'où des tableaux où seuls les totaux semblaient visibles. :root ET
     :root[data-theme="dark"] ciblés explicitement (la 2e règle a une spécificité plus
     élevée que le simple :root ci-dessous et gagnerait sinon) — !important nécessaire, la
     règle @media(prefers-color-scheme:dark) n'en porte pas mais son ordre de cascade la
     ferait sinon gagner sur un print non marqué. Un document imprimé doit TOUJOURS rester
     lisible clair-sur-blanc, quel que soit le thème choisi à l'écran. */
  :root, :root[data-theme="dark"] {
    --bg: #F8FAFC !important; --surface: #FFFFFF !important;
    --text: #333333 !important; --text-soft: #5B6069 !important;
    --line: rgba(51, 51, 51, 0.14) !important; --line-strong: rgba(51, 51, 51, 0.26) !important;
  }
  body { padding-top: 0 !important; background: #fff; }
  body > *:not(.zone-impression) { display: none !important; }
  .zone-impression { display: block !important; }

  .zone-impression h1 { font-size: 1.4rem; margin-bottom: 0.3rem; }
  .zone-impression .impression-sous-titre { color: #555; font-size: 0.85rem; margin: 0 0 1.5rem; }

  /* Page de garde (2026-08-19) — sur sa propre page, jamais mêlée au premier tableau qui
     suit (break-after systématique, quel que soit le nombre de sections cochées). */
  .zone-impression .page-garde { text-align: center; padding: 4cm 1cm 1cm; break-after: page; page-break-after: always; }
  .zone-impression .page-garde-type { text-transform: uppercase; letter-spacing: 0.15em; font-size: 0.8rem; color: #555; margin: 0 0 2rem; }
  .zone-impression .page-garde h1 { font-size: 2rem; margin: 0 0 0.5rem; }
  .zone-impression .page-garde-forme { font-size: 1rem; color: #333; margin: 0 0 1.5rem; }
  .zone-impression .page-garde-description { max-width: 30rem; margin: 0 auto 3rem; font-size: 0.95rem; color: #333; }
  .zone-impression .page-garde-porteur { margin-top: 4rem; font-size: 0.9rem; color: #333; }
  .zone-impression .page-garde-porteur p { margin: 0.15rem 0; }
  .zone-impression .page-garde-nom { font-weight: 600; }
  .zone-impression .page-garde-date { margin-top: 1.5rem; font-size: 0.85rem; color: #555; }

  .zone-impression .recap-section {
    border: 1px solid #ccc; box-shadow: none; break-inside: avoid; page-break-inside: avoid;
    margin-bottom: var(--space-4);
  }
  .zone-impression .recap-section-head { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  .zone-impression .bp-synthese-chapitre { -webkit-print-color-adjust: exact; print-color-adjust: exact; break-inside: avoid; page-break-inside: avoid; }
  .zone-impression table { break-inside: auto; }
  .zone-impression tr { break-inside: avoid; }
  .zone-impression .table-wrap { overflow: visible; border: none; }

  /* Détail mensuel en pages séparées, format paysage (2026-08-19) — une section par année,
     toujours sur une page dédiée (break-before systématique, y compris pour la première :
     jamais mêlée au tableau annuel qui précède), ajustée à la largeur de la page (table-layout
     fixed + police réduite pour tenir jusqu'à ~13 colonnes mensuelles). */
  .zone-impression .zone-impression-paysage { page: paysage; break-before: page; page-break-before: always; }
  .zone-impression .zone-impression-paysage table { table-layout: fixed; width: 100%; font-size: 0.72rem; }
  .zone-impression .zone-impression-paysage th, .zone-impression .zone-impression-paysage td { padding: 0.3rem 0.4rem; overflow-wrap: break-word; word-break: break-word; }
  .zone-impression .zone-impression-paysage th:first-child, .zone-impression .zone-impression-paysage td:first-child { width: 130px; }

  /* Aucun contrôle interactif n'a de sens sur papier — jamais un bouton ou une case à cocher
     imprimés, seul leur résultat (panneau déplié ou non) compte. Uniquement l'<input> pour
     .detail-graphify-check (pas tout le <label>, qui porte aussi le libellé du poste — le
     cacher entièrement effacerait le nom de la ligne, cf. ligneDetailPostesGraphify(),
     js/synthese.js). .btn-toggle-detail : seul le chevron (interactif) disparaît, jamais le
     bouton entier — il porte aussi le libellé de la ligne de cascade (ex. "Chiffre d'affaires"),
     le cacher entièrement viderait la première colonne du tableau. */
  .zone-impression .recap-section-actions,
  .zone-impression .detail-graphify-check input,
  .zone-impression .combify-checks { display: none !important; }
  /* display:block plutôt que le display:flex/inline-flex habituel — un flex-item ne
     rétrécit jamais sous la largeur intrinsèque de son contenu par défaut, donc le
     libellé déborde de la colonne au lieu de passer à la ligne (bug constaté sur le
     détail mensuel paysage, colonnes étroites, retour Gauthier 2026-08-19). Le
     chevron/la case étant déjà cachés en impression, plus besoin du flex ici. */
  .zone-impression .btn-toggle-detail { cursor: default; display: block; }
  .zone-impression .btn-toggle-detail .icon { display: none; }
  .zone-impression .detail-graphify-check { display: block; }
  .zone-impression .cockpit-card-grid { grid-template-columns: repeat(2, 1fr); }

  /* .cockpit-intro-didactique (2026-08-24, retour Gauthier — "tous les textes didactiques et
     informatifs sont ajoutés au PDF du PF... c'est une anomalie, ils n'intéressent pas le
     lecteur du livrable") : les paragraphes d'intro/aide ajoutés au chantier UI/UX Cockpit
     (js/synthese.js) sont rendus par les MÊMES fonctions à l'écran et dans #zone-impression
     (renderContenuSection(..., true) réutilise renderCompteResultat()/renderBilan()/etc. sans
     distinction) — jamais séparés à l'écriture, seulement masqués ICI à l'impression. Le lead
     principal de synthese.html/business-plan.html (#synthese-lead/#bp-lead) n'a PAS besoin de
     cette classe : `body > *:not(.zone-impression) { display:none !important }` ci-dessus
     l'exclut déjà, il vit hors de .zone-impression. */
  .cockpit-intro-didactique { display: none !important; }
}

/* ── Document final du Business Plan (2026-08-17, js/business-plan-final.js) ──────────
   Visualisation à l'écran + impression, même contenu assemblé une seule fois (jamais
   reconstruit séparément pour les deux). Réutilise .page-garde/.recap-section/.table-wrap
   déjà stylés pour l'impression PF (règles ci-dessus, section "Impression PDF du Plan
   Financier") — seuls les éléments réellement nouveaux (pagination numérotée, TOC, cadre
   de lecture à l'écran) reçoivent une règle ici. */

/* Pagination : cf. règle @page générique tout en haut de ce fichier (section "Impression
   PDF du Plan Financier") — plus de page nommée dédiée ici (retirée le 2026-08-17, cf. son
   commentaire : provoquait systématiquement une 1re page blanche, même posée sur l'élément
   le plus extérieur du contenu imprimé). bp-document-final reste sur #zone-impression dans
   business-plan.html à titre de marqueur sémantique ("ce contenu EST le document final"),
   mais ne porte plus aucune règle CSS propre. */
@media print {
  .zone-impression .bp-toc { break-after: page; page-break-after: always; }
}

/* Table des matières — ancres cliquables, jamais de numéro de page (limite technique
   ci-dessus) : utile à l'écran (viewer) et en PDF-avec-liens (Enregistrer en PDF conserve
   les liens internes), moins au papier où seule la numérotation des sections guide. */
.bp-toc { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: var(--space-2); }
.bp-toc a { display: block; text-decoration: none; color: var(--text); padding: 0.3rem 0; border-bottom: 1px dotted var(--line); }
.bp-toc a:hover { color: var(--accent); }
.bp-section-numero, .bp-toc-numero { color: var(--accent); font-weight: 700; margin-right: 0.4em; }

/* Sous-titres des tableaux/graphiques financiers intégrés (2026-08-17,
   js/business-plan-final.js::tableauAnnuel()/graphiquesFinanciers()) — bug réel trouvé le
   2026-08-17 (retour Gauthier, "alignement des titres") : un style INLINE posé
   directement en JS (`style="margin:1.5rem 0 0.5rem"`) gagne TOUJOURS sur la règle externe
   `.recap-section > *:not(.recap-section-head) { margin-left/right: var(--space-4) }`
   ci-dessus (l'inline l'emporte quelle que soit la spécificité du sélecteur externe) —
   ces titres perdaient donc leur inset horizontal, flush contre la bordure de la carte,
   pendant que le texte environnant (jamais stylé en inline) le conservait. Classe dédiée à
   la place : ne fixe QUE margin-top/bottom, laisse margin-left/right à la règle externe.
   Cette classe est un ENFANT DIRECT de .recap-section (jamais nichée plus profond), sinon
   la règle externe ne s'appliquerait pas non plus. */
.bp-soustitre { font-size: 0.95rem; margin-top: 1.5rem; margin-bottom: 0.5rem; }

/* Puces (2026-08-17, retour Gauthier) — classe dédiée plutôt qu'un sélecteur `ul` nu, pour
   ne jamais affecter d'autres listes du site (ex. .bp-toc, déjà stylée séparément) — rendu
   par js/business-plan.js et js/business-plan-final.js::renderBlocListe(). margin-left/
   right, eux, sont de toute façon repris par la règle externe .recap-section > * ci-dessus
   (plus spécifique que cette classe seule) — seuls margin-top/bottom viennent d'ici.
   Bug réel trouvé le 2026-08-17 (retour Gauthier, "alignement des points bulles") :
   `padding: 0` supprimait l'espace que `list-style-position: outside` (comportement par
   défaut du navigateur) réserve pour la puce elle-même — elle se dessinait donc HORS de la
   boîte de la liste, empiétant sur la bordure de la carte au lieu de s'aligner avec le
   texte. `padding-left` réserve maintenant cet espace explicitement. */
.bp-liste { margin-top: 0.5rem; margin-bottom: 1rem; padding-left: 1.25rem; }
.bp-liste li { margin-bottom: 0.35rem; }

/* Encadré "Synthèse" de fin de chapitre (2026-08-23, retour Gauthier — "on la met en forme
   dans un encadré, c'est visuellement attrayant et donne intuitivement la connotation de
   commentaire ou de résumé"). Même teinte que --accent-tint (déjà utilisée pour la pilule du
   fil d'Ariane) plutôt qu'un nouveau ton — un seul vocabulaire de "zone accentuée" dans tout
   le site. Bordure gauche plus marquée (jamais un cadre complet) : lecture immédiate "ceci
   est un aparté", sans isoler visuellement le bloc du reste du chapitre comme le ferait un
   encadré à 4 bords. Rendu par js/business-plan.js ET js/business-plan-final.js::
   renderTexteSection (même classe, même marqueur "**Synthèse :**", jamais un rendu divergent
   entre la vue section-par-section et le document final compilé). */
.bp-synthese-chapitre {
  background: var(--accent-tint, rgba(76, 29, 149, 0.08));
  border-left: 3px solid var(--accent, #4c1d95);
  border-radius: var(--radius, 8px);
  padding: var(--space-3) var(--space-4);
  margin: var(--space-3) 0;
}

/* Écran de visualisation (2026-08-17) — conteneur "page" en lecture seule, mise en page
   proche de l'impression même à l'écran (fond distinct + bordure + ombre, effet "feuille
   posée") — jamais littéralement paginé à l'écran (seule l'impression réelle pagine, via
   @page ci-dessus) : juste une lecture confortable avant d'imprimer. .page-garde à
   l'intérieur reprend EXACTEMENT les classes de la couverture déjà utilisée pour
   l'impression PF (js/synthese.js::construireCouvertureImpression) — jamais une 2e famille
   de classes, seule cette règle-ci (portée écran) et son équivalent impression
   (.zone-impression .page-garde, section "Impression PDF du Plan Financier" ci-dessus)
   diffèrent, chacun scopé à son propre contexte de rendu. */
.bp-document-viewer { max-width: 760px; margin: 0 auto; }
/* Alignement à gauche scopé au carrousel marketing (2026-08-25, retour Gauthier — "aligne les
   blocs à gauche également") — jamais sur .bp-document-viewer directement, partagée avec le
   vrai visualiseur de document compilé (js/business-plan-final.js), qui doit rester centré
   tel quel. */
#sim-bp-document .bp-document-viewer { margin: 0; }
.bp-document-page {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: 0 4px 24px rgba(0, 0, 0, 0.08); padding: 3rem 3.5rem; margin-bottom: var(--space-4);
}
.bp-document-page .page-garde { text-align: center; padding: 2rem 1rem 1rem; }
.bp-document-page .page-garde-type { text-transform: uppercase; letter-spacing: 0.15em; font-size: 0.8rem; color: var(--text-soft); margin: 0 0 2rem; }
.bp-document-page .page-garde h1 { font-size: 2rem; margin: 0 0 0.5rem; }
.bp-document-page .page-garde-forme { font-size: 1rem; color: var(--text-soft); margin: 0 0 1.5rem; }
.bp-document-page .page-garde-description { max-width: 30rem; margin: 0 auto 3rem; font-size: 0.95rem; color: var(--text-soft); }
.bp-document-page .page-garde-porteur { margin-top: 4rem; font-size: 0.9rem; color: var(--text-soft); }
.bp-document-page .page-garde-porteur p { margin: 0.15rem 0; }
.bp-document-page .page-garde-nom { font-weight: 600; color: var(--text); }
.bp-document-page .page-garde-date { margin-top: 1.5rem; font-size: 0.85rem; color: var(--text-soft); }

/* ══════════════════════════════════════════════════════════════════════════
   PAGES MARKETING (2026-08-24) — index.html/fonctionnalites.html/
   comment-ca-marche.html/tarifs.html. Préfixe .mkt- partout, jamais un nom
   générique qui pourrait entrer en collision avec l'app (.card/.section
   n'existent pas encore ici mais pourraient un jour). Réutilise EXCLUSIVEMENT
   les tokens déjà posés plus haut (--accent/--bg/--surface/--text/--radius…)
   — jamais une 2e palette, jamais un rayon de bordure arrondi qui trahirait
   le registre "document financier" déjà établi (--radius: 4px, cf. plus haut).
   ══════════════════════════════════════════════════════════════════════════ */

/* Nav marketing fusionnée dans .nav-bar/js/nav.js (2026-08-25, cf. § Navigation
   plus haut) — .mkt-nav retiré, une seule implémentation pour tout le site. */

/* ── Structure de page : sections pleine largeur alternées (--bg/--surface),
   contenu recentré à l'intérieur — même gabarit que .wrap (1040px) mais
   jamais .wrap lui-même (qui porte un padding-top pensé pour l'app, pas pour
   une page qui commence par un hero). */
.mkt-section { padding: var(--space-6) var(--space-5); }
.mkt-section-alt { background: var(--surface); }
.mkt-inner { max-width: 1040px; margin: 0 auto; }
.mkt-inner-narrow { max-width: 700px; margin: 0 auto; }

.mkt-eyebrow {
  font-size: 0.78rem; font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--accent); margin: 0 0 0.75rem;
}
/* Plafonné à 2.5rem, pas 3rem (2026-08-25, retour Gauthier — "mets la phrase d'intro sur 2
   lignes, rejet à la ligne d'office sur la deuxième phrase") : au-delà de 2.5rem/40px, la
   2e phrase du H1 de l'Accueil (57 caractères) dépasse la largeur de .mkt-inner (1040px) et
   se scinde sur une 3e ligne malgré le <br> placé entre les deux phrases — vérifié à
   960/1280/1440/1920/2560px, 2 lignes garanties à partir de 1280px. max-width:none (jamais
   de plafond en ch ici) : seul le <br> explicite contrôle le point de coupure voulu. */
.mkt-h1 { font-size: clamp(2rem, 5vw, 2.5rem); line-height: 1.12; letter-spacing: -0.015em; margin: 0 0 1.1rem; max-width: none; }
.mkt-h2 { font-size: clamp(1.5rem, 3.2vw, 1.9rem); line-height: 1.2; letter-spacing: -0.01em; margin: 0 0 0.9rem; }
.mkt-lead { font-size: 1.1rem; color: var(--text-soft); max-width: none; margin: 0 0 1.75rem; }
.mkt-section > .mkt-inner > p, .mkt-prose p { max-width: 62ch; }
/* .mkt-prose-large (2026-08-25, retour Gauthier — même principe que .lead-large, appliqué
   "de façon systématique" à tout texte d'intro qui précède un bloc pleine largeur) : sur
   fonctionnalites.html, chaque .mkt-prose introduit une reconstruction (ou rien) qui occupe
   toute la largeur de .wrap — le plafond de 62ch, pensé pour un paragraphe de lecture isolé,
   laissait le texte visiblement plus étroit que ce bloc. Additive, jamais posée sur
   .mkt-prose p directement (qui reste la valeur par défaut si un futur usage de .mkt-prose
   n'a rien de large en dessous). */
.mkt-prose-large p { max-width: 100%; }

/* ── Hero (Accueil) ───────────────────────────────────────────────────── */
/* Alignement latéral aligné sur les autres pages marketing (2026-08-25, retour Gauthier —
   "on adopte la même règle d'alignement latéral que sur les autres pages") : le hero était
   seul à centrer son texte dans une colonne étroite (.mkt-inner-narrow, 700px) alors que
   fonctionnalites.html/comment-ca-marche.html/tarifs.html restent en texte aligné à gauche
   dans .wrap (1040px) — bord gauche décalé en descendant vers les sections suivantes
   (.mkt-inner, déjà 1040px). Hero repassé en .mkt-inner dans index.html, texte aligné à
   gauche par défaut (plus de text-align:center ni de colonne flex centrée). */
/* padding-inline ajouté (2026-08-25, bug auto-détecté en vérifiant l'alignement de la nav) :
   .mkt-hero n'avait aucun padding horizontal propre, et .mkt-inner (max-width:1040px sans
   padding à lui) touchait donc directement les bords du viewport en dessous de ~1040px —
   texte du H1 collé à l'écran sur mobile/tablette. Même valeur que .mkt-section pour rester
   au même gabarit. */
/* padding-top SANS var(--nav-h) (2026-09-28, correctif sitewide — retour Gauthier, capture
   accueil mobile "espace de respiration disproportionné") : `body { padding-top: var(--nav-h) }`
   (plus haut dans ce fichier) compense déjà le nav fixe pour TOUT le contenu de la page —
   .mkt-hero, enfant direct de body juste après #nav-placeholder, héritait ce décalage
   gratuitement. Ajouter var(--nav-h) une 2e fois ici le comptait deux fois (nav-h non
   négligeable en mobile où le bandeau marketing passe sur 2 lignes, ~140px) — même bug que
   celui trouvé et corrigé en style inline sur 28 pages HTML (.wrap) le même jour, ici via
   cette classe CSS plutôt qu'un style inline. */
.mkt-hero { padding-top: var(--space-6); padding-inline: var(--space-5); }

/* ── Preuves (3 cartes) ───────────────────────────────────────────────── */
.mkt-proof-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-5); margin-top: var(--space-5); }
.mkt-proof-card {
  background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius);
  padding: var(--space-5);
}
.mkt-proof-card .icon { color: var(--accent); width: 1.4rem; height: 1.4rem; margin-bottom: var(--space-3); }
.mkt-proof-card h3 { font-size: 1rem; margin: 0 0 0.5rem; }
.mkt-proof-card p { margin: 0; font-size: 0.92rem; color: var(--text-soft); }
@media (max-width: 820px) { .mkt-proof-grid { grid-template-columns: 1fr; } }

/* ── ToolBox sur la vitrine (2026-08-26) — section Accueil + feature 08 de
   fonctionnalites.html. Les 4 cartes d'outils réutilisent .project-card.tool-card telle
   quelle (même composant que toolbox.html lui-même) ; ces deux classes sont propres à cette
   section : la ligne de statuts ("changez de perspective") et l'encadré d'unicité n'ont pas
   d'équivalent ailleurs sur le site. */
.mkt-toolbox-stances { display: flex; flex-wrap: wrap; gap: var(--space-2); margin: var(--space-4) 0 var(--space-5); }
.mkt-toolbox-stance {
  display: inline-flex; align-items: center; gap: 0.45rem;
  font-size: 0.82rem; font-weight: 600; letter-spacing: 0.01em;
  padding: 0.4rem 0.85rem 0.4rem 0.6rem; border-radius: 999px;
  background: var(--indigo-light); color: var(--indigo);
}
.mkt-toolbox-stance .icon { width: 1rem; height: 1rem; }
.mkt-toolbox-differentiator {
  margin-top: var(--space-5); padding: var(--space-4) 1.4rem; border-radius: var(--radius);
  background: var(--indigo-light); display: flex; gap: var(--space-3); align-items: flex-start;
}
.mkt-toolbox-differentiator .icon { width: 1.3rem; height: 1.3rem; color: var(--indigo); flex-shrink: 0; margin-top: 0.15rem; }
.mkt-toolbox-differentiator p { margin: 0; font-size: 0.92rem; color: var(--indigo); font-weight: 500; line-height: 1.5; }

/* ── Stepper 4 étapes, en encadré (Accueil, 2026-08-25 — retour Gauthier : l'ancien
   bandeau texte+flèches "était peu attrayant") ───────────────────────────────────
   Même langage visuel que .stepper-sticky-dot (barre collante du menu de configuration,
   js/stepper.js) — cercle numéroté rempli en --accent (indigo), ligne de connexion pleine
   --accent — jamais une 2e palette, juste une version plus grande/lisible pour un contexte
   de page d'accueil (40px vs 22px, numéro + libellé toujours visible, pas seulement au
   survol comme la version compacte de l'app). .mkt-flow-line en flex:1 sur un sibling FIXE
   (.mkt-flow-step) avec align-items:flex-start + margin-top calé sur le centre du cercle —
   reste correctement centré quelle que soit la hauteur du libellé voisin (1 ou 2 lignes). */
.mkt-flow-steps { display: flex; align-items: flex-start; justify-content: flex-start; padding: var(--space-2) 0; }
.mkt-flow-step { display: flex; flex-direction: column; align-items: center; width: 210px; flex-shrink: 0; text-align: center; }
.mkt-flow-circle {
  width: 40px; height: 40px; border-radius: 50%; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: var(--accent); color: var(--accent-contrast);
  font-family: 'BP-Jakarta', sans-serif; font-weight: 700; font-size: 1.05rem;
  font-variant-numeric: tabular-nums; margin-bottom: var(--space-2);
}
.mkt-flow-label { margin: 0; font-weight: 700; font-size: 0.9rem; color: var(--text); line-height: 1.3; padding: 0 var(--space-1); }
.mkt-flow-desc { margin: 0.3rem 0 0; font-size: 0.8rem; color: var(--text-soft); line-height: 1.4; padding: 0 var(--space-1); }
.mkt-flow-line { flex: 1 1 40px; min-width: 16px; max-width: 64px; height: 2px; background: var(--accent); margin-top: 19px; }
.mkt-steps-banner-link { display: block; font-size: 0.9rem; margin-top: var(--space-3); }
@media (max-width: 640px) {
  .mkt-flow-steps { flex-direction: column; align-items: center; gap: var(--space-4); }
  .mkt-flow-line { display: none; }
}

/* ── Liste numérotée (Comment ça marche) — numéroté à raison : vraie
   séquence temporelle, pas une décoration. ─────────────────────────────── */
/* max-width retiré, margin:auto → 0 (2026-08-25, retour Gauthier — alignement à gauche
   généralisé) : la liste flottait centrée dans une colonne étroite, seule page marketing
   encore concernée. Colonne icône ajoutée à droite de chaque étape ("infographique évocateur
   et élégant pour chaque étape", .icon-tile déjà établi ailleurs sur le site — jamais un
   nouveau composant visuel). */
.mkt-steps-list { display: flex; flex-direction: column; gap: 0; max-width: 760px; margin: var(--space-5) 0 0; }
.mkt-step { display: grid; grid-template-columns: 2.4rem 1fr 3.25rem; align-items: start; gap: 0 var(--space-4); padding: var(--space-4) 0; border-top: 1px solid var(--line); }
.mkt-step:first-child { border-top: none; }
.mkt-step-num {
  font-weight: 700; color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent);
  width: 2rem; height: 2rem; border-radius: var(--radius); display: flex; align-items: center; justify-content: center;
  font-size: 0.9rem;
}
.mkt-step h3 { font-size: 1rem; margin: 0.1rem 0 0.35rem; }
.mkt-step p { margin: 0; color: var(--text-soft); font-size: 0.94rem; }
.mkt-step .icon-tile { width: 3.25rem; height: 3.25rem; border-radius: var(--radius); }
.mkt-step .icon-tile .icon { width: 1.6rem; height: 1.6rem; }

/* ── Blocs fonctionnalité (Fonctionnalités) ──────────────────────────── */
.mkt-feature { padding: var(--space-6) 0; border-top: 1px solid var(--line); }
.mkt-feature:first-child { border-top: none; padding-top: var(--space-4); }
/* Badge numéroté (2026-08-25, retour Gauthier — "utilisons le même format pour les étapes
   que sur [comment-ca-marche.html], plus lisible et plus élégant") : mêmes valeurs que
   .mkt-step-num (carré indigo clair, jamais un cercle ni une couleur différente), déclarées
   ici séparément plutôt que fusionnées en un seul sélecteur partagé — les deux pages restent
   libres d'évoluer indépendamment si un jour l'une a besoin d'un ajustement propre. */
.mkt-feature-head { display: grid; grid-template-columns: 2.4rem 1fr; gap: 0 var(--space-4); align-items: start; margin-bottom: 0.9rem; }
.mkt-feature-num {
  font-weight: 700; color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent);
  width: 2rem; height: 2rem; border-radius: var(--radius); display: flex; align-items: center; justify-content: center;
  font-size: 0.9rem; margin-top: 0.15rem;
}
.mkt-feature-head h2 { margin: 0 0 0.2rem; color: var(--accent); }
.mkt-feature-tag { margin: 0; font-size: 0.82rem; color: var(--text-soft); }
.mkt-feature .mkt-prose { margin-bottom: var(--space-4); }

/* ── Placeholder visuel (capture d'écran à venir) — jamais une fausse
   capture bricolée : un encadré honnête qui dit exactement ce qui doit
   remplacer cet espace. */
.mkt-visual-placeholder {
  border: 1px dashed var(--line-strong); border-radius: var(--radius);
  background: var(--bg); padding: var(--space-5); text-align: center;
  color: var(--text-soft); font-size: 0.86rem; margin: var(--space-4) 0;
}
.mkt-visual-placeholder .icon { width: 1.3rem; height: 1.3rem; margin-bottom: var(--space-2); color: var(--text-soft); }

/* ── Widgets de simulation (js/simulations-marketing.js) ─────────────── */
.mkt-sim {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  padding: var(--space-5); margin: var(--space-4) 0;
}
/* Indigo généralisé à TOUS les titres de widget (2026-08-25) — l'essai du 1er jet (2 titres
   sur l'Accueil seulement, classe .mkt-sim-title-accent) est confirmé et étendu à tous les
   .mkt-sim-title du site, fonctionnalites.html compris ("tu as oublié de mettre les titres
   des sections en captures en indigo") — .mkt-sim-title-accent devient un alias inutile mais
   inoffensif, gardé pour ne pas casser les usages déjà posés dans le HTML/JS. */
.mkt-sim-title { font-weight: 700; font-size: 1.02rem; margin: 0 0 0.3rem; color: var(--accent); }
.mkt-sim-title-accent { color: var(--accent); }
.mkt-sim-caption { font-size: 0.86rem; color: var(--text-soft); margin: 0 0 var(--space-4); }
/* .mkt-sim .cockpit-slider-grid (2026-08-27, audit mobile ; généralisé le même jour de
   .mkt-sim-cockpit à .mkt-sim — 2e occurrence trouvée sur fonctionnalites.html §
   "Impact sur les stress-tests", initCockpitFinancementDemo(), qui n'a pas le wrapper interne
   .mkt-sim-cockpit mais vit dans la même coquille .mkt-sim du gabarit HTML) — ces démos
   comptent TOUJOURS exactement 3 curseurs, contrairement au vrai Cockpit app qui a un nombre
   variable de postes par groupe (d'où .cockpit-slider-grid en flex-wrap + height fixe, cf.
   plus haut — jamais retouché ici, risque de casser l'alignement vertical des vrais curseurs
   de l'app). Sous 375px, flex-wrap faisait passer le 3e curseur à la ligne SANS que la
   hauteur fixe (140px sur ce breakpoint) ne s'adapte — le curseur débordait, chevauchant le
   texte du bloc suivant ("Saisonnalité mensuelle" / "Impact sur les stress-tests", retour
   Gauthier, captures accueil ET fonctionnalites.html). Un nombre de colonnes connu et fixe
   permet une grille à 3 colonnes qui rétrécit plutôt que de passer à la ligne — plus jamais
   de dépassement possible, quelle que soit la largeur. Scopé à .mkt-sim (marketing
   uniquement, jamais utilisée par le vrai Cockpit app, cf. grep js/synthese.js), jamais au
   sélecteur nu .cockpit-slider-grid.
   .cockpit-slider-valeur : text-align:center ajouté (retour Gauthier — "l'alignement du
   texte au-dessus du 3ème bloc n'est pas centré") — la valeur la plus longue de la démo
   ("140 unités/mois") passe sur 2 lignes tandis que les 2 autres tiennent sur 1, or la
   règle de base (plus haut) ne centrait QUE le bloc dans son conteneur (align-items:center
   sur .cockpit-slider-col), jamais le texte lui-même une fois qu'il wrap sur plusieurs
   lignes de largeurs différentes — les 2 lignes du libellé le plus long apparaissaient donc
   décalées l'une par rapport à l'autre. min-height + flex column + justify-content:flex-end
   réserve la même hauteur (jusqu'à 2 lignes) pour TOUS les curseurs, valeur alignée en bas
   dans cet espace réservé : le haut du curseur (track) démarre ainsi à la même hauteur
   partout, qu'un libellé wrap sur 1 ou 2 lignes ("le 3ème bloc est de hauteur différente que
   les 2 autres", même retour). */
.mkt-sim .cockpit-slider-grid { display: grid; grid-template-columns: repeat(3, 1fr); height: 180px; }
.mkt-sim .cockpit-slider-col { flex-basis: auto; width: 100%; }
.mkt-sim .cockpit-slider-valeur { text-align: center; min-height: 2.4em; display: flex; flex-direction: column; justify-content: flex-end; }
@media (max-width: 640px) {
  .mkt-sim .cockpit-slider-grid { height: 140px; gap: var(--space-2); }
  .mkt-sim .cockpit-slider-valeur { min-height: 2.1em; }
}
.mkt-sim-disclaimer { font-size: 0.8rem; color: var(--text-soft); margin-top: var(--space-3); font-style: italic; }

.mkt-sim-field { margin-bottom: var(--space-3); }
.mkt-sim-field label { display: block; font-size: 0.84rem; color: var(--text-soft); margin-bottom: 0.3rem; }
.mkt-sim-field input[type="number"] {
  width: 100%; font: inherit; font-family: 'BP-Inter', sans-serif; padding: 0.5rem 0.65rem;
  border: 1px solid var(--line-strong); border-radius: var(--radius); background: var(--bg); color: var(--text);
}
.mkt-sim-result { display: flex; flex-direction: column; gap: 0.4rem; margin-top: var(--space-4); padding-top: var(--space-4); border-top: 1px solid var(--line); }
.mkt-sim-result-row { display: flex; justify-content: space-between; font-size: 0.94rem; }
.mkt-sim-result-row.total { font-weight: 700; border-top: 1px solid var(--line); padding-top: 0.4rem; margin-top: 0.2rem; }
.mkt-sim-result-row .num { font-family: 'BP-Inter', sans-serif; font-variant-numeric: tabular-nums; }
.mkt-sim-result-row .num.negative { color: var(--danger); }
.mkt-sim-result-row .num.positive { color: var(--success); }

/* Simulation 2 — le curseur Cockpit, la démo phare : un chiffre KPI massif
   qui réagit au glissement, même esprit visuel qu'une carte KPI réelle du
   Cockpit (cf. .kpi-valeur-positive/-negative plus haut dans ce fichier).
   text-align:center retiré (2026-08-25, retour Gauthier — alignement latéral) : le titre/
   la légende/le KPI de ce widget s'alignent désormais à gauche comme le reste de la page et
   comme son équivalent sur fonctionnalites.html ("Testez un aperçu de votre Plan
   Financier", jamais centré) — seuls les CLUSTERS visuels (grille de curseurs, grille de
   saisonnalité) restent en flex-start naturel, inchangés. .prix-affiche/input[type="range"]
   retirés : vestiges du 1er jet à curseur natif unique, remplacé depuis par les curseurs
   .cockpit-slider-* drag réels — plus aucun appelant. */
.mkt-sim-kpi { margin-top: var(--space-4); }
/* Mise en évidence du CA estimé (2026-08-25, retour Gauthier) : label agrandi + indigo,
   valeur réduite et recadrée dans un encadré indigo clair — même paire de tons que
   .icon-tile-indigo-clair (fond var(--indigo-light), texte var(--indigo)), jamais les
   couleurs sémantiques success/danger ici : ce n'est pas un diagnostic bon/mauvais, juste un
   résultat de simulation. */
.mkt-sim-kpi-label { font-size: 1.05rem; font-weight: 600; color: var(--accent); text-transform: uppercase; letter-spacing: 0.06em; }
.mkt-sim-kpi-valeur {
  font-family: 'BP-Inter', sans-serif; font-size: 1.05rem; font-weight: 700; line-height: 1.1;
  font-variant-numeric: tabular-nums; transition: color 0.15s ease;
  display: inline-block; margin-top: 0.6rem; padding: 0.6rem 1.1rem; border-radius: var(--radius);
  background: var(--indigo-light); color: var(--indigo);
}

/* Simulation 3 — extrait de Business Plan : table des matières + extrait
   texte + encadré de clôture, mêmes conventions visuelles que le vrai
   document (.bp-synthese-chapitre, cf. plus haut dans ce fichier). */
/* Grid, jamais `columns` multi-colonnes (2026-08-25, retour Gauthier — bulles d'infobulle mal
   positionnées/coupées) : un layout `columns` crée un contexte de fragmentation qui piège les
   enfants `position:absolute` (les bulles `.info-tip-bubble`) de façon imprévisible — corrigé
   en 2 vraies colonnes de grille, flux par colonne (`grid-auto-flow:column`) pour conserver
   exactement la même répartition visuelle (1-9 à gauche, 10-18 à droite). 9 lignes en dur —
   suppose 18 chapitres (BP_CHAPITRES), à ajuster si ce total change un jour. */
.mkt-sim-bp-toc { display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: repeat(9, auto); grid-auto-flow: column; column-gap: var(--space-5); font-size: 0.86rem; color: var(--text-soft); margin: 0 0 var(--space-4); list-style: none; padding: 0; }
.mkt-sim-bp-toc li { padding: 0.2rem 0; }
.mkt-sim-bp-excerpt { font-size: 0.96rem; line-height: 1.6; }
.mkt-sim-bp-excerpt p { margin: 0 0 0.9rem; }
@media (max-width: 600px) { .mkt-sim-bp-toc { grid-template-columns: 1fr; grid-template-rows: none; grid-auto-flow: row; } }
/* Variante annotée fixe/variable ("Structure modulaire du Business Plan", 2026-08-25) — même
   liste, chaque ligne devient une rangée flex (numéro/libellé à gauche, badge .pill à
   droite) pour porter le badge sans casser le rendu 2 colonnes. */
.mkt-sim-bp-toc-annotee li { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); }
.mkt-sim-bp-toc-annotee .pill { font-size: 0.68rem; padding: 0.18rem 0.5rem; flex-shrink: 0; }

/* Simulation 1 — écart trésorerie/résultat lié à l'investissement (2026-08-25) : encadré
   ton neutre (jamais success/danger — ce n'est pas un verdict, juste un fait pédagogique). */
.mkt-sim-ecart {
  margin-top: var(--space-3); padding: var(--space-3);
  background: var(--bg); border-left: 3px solid var(--accent); border-radius: var(--radius);
  font-size: 0.86rem; color: var(--text-soft); line-height: 1.5;
}
.mkt-sim-ecart strong { color: var(--text); }

/* Reconstruction "Menu de configuration" (fonctionnalites.html § 01, 2026-08-25) — barre de
   progression réutilisant .stepper-sticky-inner SANS le wrapper .stepper-sticky (position:
   fixed) : ici, elle vit à l'intérieur d'une carte, jamais collée au viewport. Marges
   négatives = même effet "bord à bord" que la vraie barre, à l'intérieur du padding de la
   carte plutôt qu'à l'échelle de la page. */
.mkt-sim-wizard-bar {
  margin: calc(-1 * var(--space-5)) calc(-1 * var(--space-5)) var(--space-4);
  background: var(--surface); border-bottom: 1px solid var(--line); border-radius: var(--radius) var(--radius) 0 0;
  overflow-x: auto;
}
.mkt-sim-wizard-bar .stepper-sticky-nav { color: var(--text-soft); cursor: default; }
.mkt-sim-wizard-title { margin: 0 0 var(--space-4); }

/* Carrousel du Business Plan compilé (fonctionnalites.html § 05, 2026-08-25) — navigation
   sobre, jamais de flèches superposées à même la "page" (.bp-document-page reste une
   reproduction fidèle du vrai document, la navigation vit clairement en dehors). */
.mkt-sim-bp-selector { display: flex; flex-wrap: wrap; gap: var(--space-2); justify-content: flex-start; }
.mkt-sim-bp-selector button {
  font-family: 'BP-Jakarta', sans-serif; font-size: 0.84rem; font-weight: 600;
  padding: 0.45rem 0.9rem; border-radius: var(--radius); border: 1px solid var(--line-strong);
  background: var(--surface); color: var(--text-soft); cursor: pointer;
}
.mkt-sim-bp-selector button:hover { border-color: var(--accent); color: var(--accent); }
.mkt-sim-bp-selector button.active { background: var(--accent); color: var(--accent-contrast); border-color: var(--accent); }
/* Restructuré (2026-08-27, audit mobile) — .mkt-sim-carousel-compte vivait DANS la rangée
   flex des boutons (min-width:14rem + 2 boutons, sans flex-wrap) : à 375px ça ne tenait
   jamais sur une ligne, "Suivant →" sortait du cadre (retour Gauthier, capture
   fonctionnalites.html). Sorti en <p> autonome au-dessus, la rangée ne contient plus que les
   2 boutons — tient large sur tout viewport, plus besoin de wrap défensif. */
.mkt-sim-carousel-compte { font-size: 0.86rem; color: var(--text-soft); text-align: center; margin: var(--space-3) 0 0; }
.mkt-sim-carousel-nav { display: flex; align-items: center; justify-content: center; gap: var(--space-4); margin-top: var(--space-2); }
.mkt-sim-bp-carousel-toc { list-style: none; margin: 0; padding: 0; }
.mkt-sim-bp-carousel-toc li { display: flex; justify-content: space-between; gap: var(--space-3); padding: 0.4rem 0; border-bottom: 1px dotted var(--line); font-size: 0.94rem; }

/* ── Tarifs (page publique) ───────────────────────────────────────────── */
.mkt-pricing-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-5); margin: var(--space-5) 0; align-items: stretch; }
.mkt-price-card { background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius); padding: var(--space-5); display: flex; flex-direction: column; }
.mkt-price-card h3 { font-size: 1.05rem; margin: 0 0 0.3rem; }
.mkt-price-card .prix { font-family: 'BP-Inter', sans-serif; font-size: 2.2rem; font-weight: 700; margin: var(--space-3) 0 0.2rem; }
.mkt-price-card .prix small { font-size: 1rem; font-weight: 500; color: var(--text-soft); }
.mkt-price-card ul { margin: var(--space-3) 0 0; padding-left: 1.1rem; font-size: 0.92rem; color: var(--text-soft); }
.mkt-price-card ul li { margin-bottom: 0.4rem; }
@media (max-width: 720px) { .mkt-pricing-grid { grid-template-columns: 1fr; } }

/* Grille Essentiel/Complet (fonctionnalites.html, encart "À chaque projet, son Business
   Plan") — propriétés posées ICI plutôt qu'en style inline sur l'élément (2026-09-28,
   correctif same-day) : un style inline gagne TOUJOURS contre une règle de feuille externe,
   media query ou pas — @media (max-width:640px) ci-dessous ne pouvait donc jamais s'appliquer
   tant que grid-template-columns restait posé en inline sur la balise (retour Gauthier,
   capture mobile montrant les 2 cartes toujours juxtaposées, très étroites, illisibles). */
.mkt-parcours-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
@media (max-width: 640px) { .mkt-parcours-grid { grid-template-columns: 1fr; } }

/* Table "Région / Exigences spécifiques" (plan-financier-obligatoire.html) — vrai correctif
   2026-09-28 (le premier essai, retirer le nowrap de la 1re colonne, n'était pas la cause
   réelle et n'a rien changé, retour Gauthier) : la règle GLOBALE `table { min-width:480px }`
   ci-dessus (§ Tableaux de chiffres) s'applique à TOUT <table>, y compris celui-ci — sans
   rapport avec son contenu, elle impose déjà 480px avant même de considérer le texte des
   cellules, garantissant le débordement à 375px (iPhone SE). Cette règle est pensée pour les
   tableaux de chiffres de l'app, toujours nichés dans .table-wrap (défilement horizontal
   volontaire, beaucoup de colonnes) — ce tableau-ci est un simple contenu texte à 2 colonnes,
   jamais voulu comme scrollable. min-width:0 neutralise spécifiquement ce plancher hérité par
   accident ; combiné au retour à la ligne du label sous 480px (déjà posé, gardé — utile une
   fois le vrai plancher levé), le tableau peut enfin se redimensionner à la largeur réelle du
   viewport au lieu de forcer 480px. */
.mkt-legal-table { min-width: 0; }
.mkt-legal-table-label { white-space: nowrap; }
@media (max-width: 480px) {
  .mkt-legal-table-label { white-space: normal; }
}

/* Dominantes indigo (2026-08-25, retour Gauthier — "dominante indigo foncé pour le PF et
   indigo clair pour le BP") — mêmes tokens que le reste du site, jamais une nouvelle
   couleur : --accent (indigo foncé, pleine teinte) pour le Plan Financier seul,
   color-mix() indigo clair (lavis) pour Plan Financier + Business Plan. Icon-tile de chaque
   carte en ton INVERSÉ (clair sur fond foncé, foncé sur fond clair) pour un accent qui
   ressort, jamais la même teinte que le fond. */
.mkt-price-card-dark { background: var(--accent); border-color: var(--accent); color: var(--accent-contrast); }
.mkt-price-card-dark h3, .mkt-price-card-dark .prix { color: var(--accent-contrast); }
.mkt-price-card-dark .prix small { color: color-mix(in srgb, var(--accent-contrast) 70%, transparent); }
.mkt-price-card-dark ul { color: color-mix(in srgb, var(--accent-contrast) 85%, transparent); }
.mkt-price-card-dark .icon-tile { background: var(--accent-contrast); color: var(--accent); }

.mkt-price-card-light { background: color-mix(in srgb, var(--accent) 8%, var(--surface)); border-color: color-mix(in srgb, var(--accent) 30%, var(--line)); }
.mkt-price-card-light .icon-tile { background: var(--accent); color: var(--accent-contrast); }

.mkt-price-card-icons { display: flex; gap: 0.4rem; margin-bottom: var(--space-3); }
.mkt-price-card .icon-tile { width: 2.5rem; height: 2.5rem; border-radius: var(--radius); display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.mkt-price-card .icon-tile .icon { width: 1.3rem; height: 1.3rem; }

/* Encart option Recherche approfondie (2026-08-25) — même langage visuel que son équivalent
   réel sur choix-formule.html (bordure + fond teintés --accent), jamais un style ad hoc. */
.mkt-price-card-option {
  margin-top: var(--space-3); padding: 0.7rem 0.9rem; border: 1px solid var(--accent);
  border-radius: var(--radius); background: color-mix(in srgb, var(--accent) 8%, transparent);
  font-size: 0.86rem; color: var(--text);
}
.mkt-price-card-dark .mkt-price-card-option {
  border-color: color-mix(in srgb, var(--accent-contrast) 40%, transparent);
  background: color-mix(in srgb, var(--accent-contrast) 12%, transparent);
  color: var(--accent-contrast);
}
.mkt-price-card-option strong { color: var(--accent); }
.mkt-price-card-dark .mkt-price-card-option strong { color: var(--accent-contrast); }

.mkt-price-card-cta { justify-content: center; align-self: stretch; margin-top: var(--space-4); }
.mkt-price-card-dark .mkt-price-card-cta { background: var(--accent-contrast); color: var(--accent); }
.mkt-price-card-dark .mkt-price-card-cta:hover { filter: brightness(0.95); }

/* ── FAQ (accordion léger, sans JS requis — <details>/<summary> natifs) ─── */
/* max-width/margin:auto retirés (2026-08-25, retour Gauthier — "on aligne les FAQ comme
   partout ailleurs") : dernier bloc encore centré dans une colonne étroite du site
   marketing. */
.mkt-faq { margin: var(--space-5) 0 0; }
.mkt-faq details { border-top: 1px solid var(--line); padding: var(--space-3) 0; }
.mkt-faq details:last-child { border-bottom: 1px solid var(--line); }
.mkt-faq summary { cursor: pointer; font-weight: 600; font-size: 0.98rem; list-style: none; display: flex; justify-content: space-between; align-items: center; gap: var(--space-3); }
.mkt-faq summary::-webkit-details-marker { display: none; }
.mkt-faq summary .icon { flex-shrink: 0; color: var(--text-soft); transition: transform 0.15s ease; }
.mkt-faq details[open] summary .icon { transform: rotate(180deg); }
.mkt-faq p { margin: var(--space-2) 0 0; color: var(--text-soft); font-size: 0.94rem; }

/* ── Bandes CTA + footer ──────────────────────────────────────────────── */
/* text-align:center retiré (2026-08-25, retour Gauthier — "reste à aligner à gauche" même sur
   ce bandeau) : dernier bloc encore centré sur l'Accueil, désormais cohérent avec le reste de
   la page. Phrase forcée sur 2 lignes comme le H1 (<br> entre les 2 phrases, cf. index.html)
   — vérifier empiriquement si .mkt-h2 a besoin du même ajustement de plafond de police que
   .mkt-h1 avant de considérer ce point clos. */
.mkt-cta-band h2 { margin-bottom: var(--space-4); font-size: 26px; }

/* ── Footer structuré (2026-08-25) ────────────────────────────────────────
   Remplace l'ancien .mkt-footer (une ligne de liens centrée) — inspiré du footer
   Tikkoun (js/nav.js::getFooterHTML(), 4 colonnes + bas de page légal), variables
   adaptées : jamais de fond anthracite fixe ici (le footer app Tikkoun est délibérément
   sombre en toute circonstance ; BizzPlan suit ses tokens sémantiques comme le reste du
   site, cf. la fusion nav déjà faite le même jour — clair/sombre selon le thème). Injecté
   par js/nav.js::getFooterHTML() dans #footer-placeholder, présent uniquement sur les 4
   pages marketing (comme l'ancien .mkt-footer — jamais sur les pages app, qui n'ont pas de
   pied de page). */
.footer { background: var(--surface); border-top: 1px solid var(--line); padding: var(--space-6) 0 var(--space-5); }
.footer-inner { max-width: 1040px; margin: 0 auto; padding-inline: var(--space-5); box-sizing: border-box; }
/* footer-grid à 2 pistes (marque | groupe de liens), pas 4 côte à côte (2026-08-26,
   retour Gauthier — "le 3ème bloc est renvoyé à la ligne trop vite") : avec les 4 colonnes
   comme pistes indépendantes d'une seule grille, le seul palier réactif prévu (860px)
   faisait basculer d'un coup de "tout sur une ligne" à "2 colonnes, la 3ème colonne de
   liens rejetée sur sa propre ligne" — un saut brutal dès une largeur d'écran modérément
   réduite. .footer-links-group isole les 3 colonnes de liens dans leur propre grille,
   avec ses paliers à elle, indépendants de la largeur du bloc marque. */
.footer-grid { display: grid; grid-template-columns: 2fr 3fr; gap: var(--space-6); margin-bottom: var(--space-6); }
.footer-links-group { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-6); }
.footer-brand .nav-brand { display: inline-block; margin-bottom: var(--space-3); }
.footer-brand p { font-size: 0.86rem; color: var(--text-soft); line-height: 1.7; max-width: 34ch; }
.footer-col h4 {
  font-family: 'BP-Jakarta', sans-serif; font-size: 0.76rem; font-weight: 700;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--text); margin: 0 0 var(--space-3);
}
.footer-links { list-style: none; margin: 0; padding: 0; }
.footer-links li { margin-bottom: 0.55rem; }
.footer-links a { font-size: 0.88rem; color: var(--text-soft); text-decoration: none; }
.footer-links a:hover { color: var(--accent); }
.footer-bottom {
  border-top: 1px solid var(--line); padding-top: var(--space-4);
  display: flex; justify-content: space-between; align-items: flex-start; gap: var(--space-4); flex-wrap: wrap;
}
.footer-bottom p { font-size: 0.78rem; color: var(--text-soft); margin: 0; line-height: 1.6; }
.footer-bottom a { color: var(--text-soft); }
.footer-bottom a:hover { color: var(--accent); }
@media (max-width: 860px) {
  .footer-grid { grid-template-columns: 1fr; }
}
@media (max-width: 560px) {
  .footer-links-group { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 380px) {
  .footer-links-group { grid-template-columns: 1fr; }
  .footer-bottom { flex-direction: column; }
}

/* ── Pages légales (Mentions légales / CGV / Confidentialité) ───────────── */
.legal-content { max-width: 760px; }
.legal-content h2 {
  font-size: 1.1rem; color: var(--accent); margin: var(--space-6) 0 var(--space-2);
  padding-bottom: 0.3rem; border-bottom: 1px solid var(--line);
}
.legal-content h2:first-of-type { margin-top: var(--space-5); }
.legal-content h3 { font-size: 0.98rem; color: var(--text); margin: var(--space-4) 0 0.4rem; }
.legal-content p, .legal-content li { font-size: 0.92rem; line-height: 1.7; color: var(--text-soft); }
.legal-content ul { padding-left: 1.3rem; margin: 0.4rem 0 0.8rem; }
.legal-content li { margin-bottom: 0.3rem; }
.legal-content strong { color: var(--text); }
.legal-content a { color: var(--accent); }
.legal-content .table-wrap { margin: var(--space-3) 0 var(--space-4); }
.legal-block {
  background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius);
  padding: var(--space-4) var(--space-5); margin: var(--space-3) 0 var(--space-4);
}
.legal-block p { margin: 0.25rem 0; }
.legal-updated {
  display: inline-block; background: color-mix(in srgb, var(--accent) 8%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--accent) 25%, var(--line)); border-radius: var(--radius);
  padding: 0.35rem 0.8rem; font-size: 0.8rem; color: var(--text-soft); margin-bottom: var(--space-4);
}

/* Disclaimer permanent des outils ToolBox (2026-08-26) — délibérément discret : même
   registre visuel que .legal-block (fond neutre, jamais une bannière d'alerte rouge), texte
   réduit et atténué pour rester "non agressif, ni intrusif" (retour Gauthier) tout en étant
   lisible sans effort. */
.toolbox-disclaimer { max-width: 640px; margin-top: var(--space-6); }
.toolbox-disclaimer-title {
  display: flex; align-items: center; gap: 0.4rem; font-weight: 600; font-size: 0.85rem;
  color: var(--text); margin: 0 0 0.4rem !important;
}
.toolbox-disclaimer-title .icon { width: 1rem; height: 1rem; color: var(--text-soft); flex-shrink: 0; }
.toolbox-disclaimer p:not(.toolbox-disclaimer-title) { font-size: 0.8rem; line-height: 1.6; color: var(--text-soft); }
