/* =============================================================================
   Décompression — feuille de style
   Site statique, aucune dépendance externe.
   ========================================================================== */

/* --- 1. Jetons de couleur ------------------------------------------------- */

:root {
  color-scheme: light dark;

  /* ---------------------------------------------------------------------
     Palette « océan », reprise de BioGuesser (static/css/style.css).

     Les teintes sont les siennes ; seule la CLARTÉ a été ajustée là où sa
     valeur ne franchissait pas le seuil WCAG AA une fois posée en texte. Chez
     lui ces couleurs servent de pastilles bordées ; ici elles deviennent des
     liens et des étiquettes de courbes, donc du texte, soumis à 4,5:1.
     Les neuf écarts sont notés en commentaire, avec le rapport obtenu.
     --------------------------------------------------------------------- */
  --bg:          #faf9f5;   /* ocean-deep  : le papier chaud, tel quel        */
  --bg-soft:     #f1ede3;   /* ocean-mid                                      */
  --bg-panel:    #ffffff;   /* card-bg                                        */
  --bg-inset:    #f4f0e5;
  --border:      #e3ddcd;
  --border-soft: #efe9db;

  --text:        #22201b;   /* text        · 15,45:1                          */
  --text-muted:  #6f6657;   /* text-muted  ·  5,37:1                          */
  --text-faint:  #736a5b;   /* éclairci au maximum encore lisible ·  4,69:1   */

  --accent:      #256fa9;   /* ocean-bright #2878b5 assombri ·  4,67:1        */
  --accent-soft: #e8f1f8;
  --accent-line: #9cc4e0;
  --on-accent:   #ffffff;   /* texte posé SUR l'accent ·  5,35:1              */

  --warn:        #8f6604;   /* gold #cf9b1f assombri ·  4,66:1                */
  --warn-soft:   #fbf3e0;
  --danger:      #c22b2b;   /* coral #d64545 assombri ·  4,66:1               */
  --danger-soft: #fbe3df;   /* error-bg, tel quel                             */
  --ok:          #1b7942;   /* success #1f8a4c assombri ·  4,71:1             */
  --ok-soft:     #dff3e6;   /* success-bg, tel quel                           */

  /* Les sept courbes. Jetons dédiés : une couleur de graphique n'emprunte pas
     un jeton de texte, sans quoi assombrir une légende déplace une courbe.
     ΔE minimal entre deux d'entre elles : 23,5 — largement au-dessus du seuil
     de discrimination. Toutes ≥ 4,5:1 sur le fond. */
  --c1: #1c7e6f;   /* teal    #1f8a7a assombri */
  --c2: #268137;   /* vert    #2f9e44 assombri */
  --c3: #936904;   /* ambre   #e0a006 assombri */
  --c4: #c14a0a;   /* orange  #e8590c assombri */
  --c5: #dc2121;   /* rouge   #e03131 assombri */
  --c6: #2775b1;   /* bleu    ocean-bright     */
  --c7: #6b6b6b;   /* neutre                   */

  --font-sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
  --font-serif: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua", Georgia, serif;
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  /* Largeur de lecture. Ramenée de 42 à 38 rem en passant la prose en
     sans-serif : à taille égale, la sans est plus étroite et tenait 79
     caractères par ligne, au-delà de la plage confortable. À 38 rem la
     médiane retombe à 72. */
  --measure: 38rem;
  --radius: 6px;
  --shadow: 0 1px 2px rgba(20, 30, 40, .06), 0 4px 16px rgba(20, 30, 40, .05);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    /* Palette sombre de BioGuesser, reprise SANS retouche : elle franchit
       déjà le seuil AA partout. Seul l'accent a été éclairci, sa valeur
       d'origine (#2878b5) ne donnant que 4,01:1 sur ce fond et 3,56:1 sur
       une carte. */
    --bg:          #07111f;   /* ocean-deep                                   */
    --bg-soft:     #0d2137;   /* ocean-mid                                    */
    --bg-panel:    #0f1e30;   /* card-bg                                      */
    --bg-inset:    #0d2137;
    --border:      #1e3a55;
    --border-soft: #16293d;

    --text:        #e8f4f8;   /* text        · 16,89:1                        */
    --text-muted:  #8ab0c8;   /* text-muted  ·  8,23:1                        */
    --text-faint:  #578db0;   /* assombri au maximum encore lisible · 4,67:1  */

    --accent:      #4898d7;   /* ocean-bright éclairci · 5,25:1, carte 4,66:1 */
    --accent-soft: #0d2b42;
    --accent-line: #2878b5;
    /* Sur cet accent clair, le blanc ne donne que 3,11:1 : le texte posé sur
       l'accent reprend le fond de page · 6,08:1. */
    --on-accent:   #07111f;

    --warn:        #ffc832;   /* ambre de leur échelle · 12,23:1              */
    --warn-soft:   #2a2410;
    --danger:      #ff6b6b;   /* coral, tel quel ·  6,82:1                    */
    --danger-soft: #3d1a1a;   /* error-bg, tel quel                           */
    --ok:          #4ecd8a;
    --ok-soft:     #1a3d2a;   /* success-bg, tel quel                         */

    --c1: #2dd4bf;   /* turquoise      */
    --c2: #a0e68c;   /* vert clair     */
    --c3: #ffc832;   /* ambre          */
    --c4: #ff9664;   /* orange         */
    --c5: #ff6b6b;   /* coral          */
    --c6: #4898d7;   /* bleu           */
    --c7: #9fb3bf;   /* neutre         */

    --shadow: 0 8px 32px rgba(0, 0, 0, .5);
  }
}

:root[data-theme="dark"] {
  /* Palette sombre de BioGuesser, reprise SANS retouche : elle franchit
     déjà le seuil AA partout. Seul l'accent a été éclairci, sa valeur
     d'origine (#2878b5) ne donnant que 4,01:1 sur ce fond et 3,56:1 sur
     une carte. */
  --bg:          #07111f;   /* ocean-deep                                   */
  --bg-soft:     #0d2137;   /* ocean-mid                                    */
  --bg-panel:    #0f1e30;   /* card-bg                                      */
  --bg-inset:    #0d2137;
  --border:      #1e3a55;
  --border-soft: #16293d;

  --text:        #e8f4f8;   /* text        · 16,89:1                        */
  --text-muted:  #8ab0c8;   /* text-muted  ·  8,23:1                        */
  --text-faint:  #578db0;   /* assombri au maximum encore lisible · 4,67:1  */

  --accent:      #4898d7;   /* ocean-bright éclairci · 5,25:1, carte 4,66:1 */
  --accent-soft: #0d2b42;
  --accent-line: #2878b5;
  /* Sur cet accent clair, le blanc ne donne que 3,11:1 : le texte posé sur
     l'accent reprend le fond de page · 6,08:1. */
  --on-accent:   #07111f;

  --warn:        #ffc832;   /* ambre de leur échelle · 12,23:1              */
  --warn-soft:   #2a2410;
  --danger:      #ff6b6b;   /* coral, tel quel ·  6,82:1                    */
  --danger-soft: #3d1a1a;   /* error-bg, tel quel                           */
  --ok:          #4ecd8a;
  --ok-soft:     #1a3d2a;   /* success-bg, tel quel                         */

  --c1: #2dd4bf;   /* turquoise      */
  --c2: #a0e68c;   /* vert clair     */
  --c3: #ffc832;   /* ambre          */
  --c4: #ff9664;   /* orange         */
  --c5: #ff6b6b;   /* coral          */
  --c6: #4898d7;   /* bleu           */
  --c7: #9fb3bf;   /* neutre         */

  --shadow: 0 8px 32px rgba(0, 0, 0, .5);
}

/* --- 2. Base -------------------------------------------------------------- */

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

/* L'attribut `hidden` doit gagner sur les règles d'affichage de cette feuille.
   Le navigateur le pose avec la plus faible priorité qui soit : la moindre
   déclaration `display` portée par une classe le rend inopérant, et l'élément
   reste affiché. Le cas s'est produit sur .legend, où les deux légendes du
   profil du simulateur, celle des gradient factors et celle de VPM-B,
   s'affichaient ensemble. */
[hidden] { display: none !important; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; scroll-padding-top: 5rem; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  /* Sans-serif, comme le site de référence. Les titres, la navigation, les
     légendes et les tableaux l'employaient déjà : seule la prose était en
     Iowan Old Style. Le jeton --font-serif reste défini, un seul mot suffit
     donc à revenir en arrière. */
  font-family: var(--font-sans);
  font-size: 1.0625rem;
  line-height: 1.72;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4, h5, .sans { font-family: var(--font-sans); }

h1 { font-size: clamp(1.9rem, 1.3rem + 2.4vw, 2.8rem); line-height: 1.15; letter-spacing: -.02em; margin: 0 0 .6rem; font-weight: 700; }
h2 { font-size: clamp(1.4rem, 1.1rem + 1.1vw, 1.85rem); line-height: 1.22; letter-spacing: -.015em; margin: 3.2rem 0 1rem; font-weight: 650; }
h3 { font-size: 1.22rem; line-height: 1.3; margin: 2.2rem 0 .7rem; font-weight: 650; }
h4 { font-size: 1.05rem; margin: 1.6rem 0 .5rem; font-weight: 650; color: var(--text-muted); }

h2 + h3 { margin-top: 1.4rem; }

p { margin: 0 0 1.15rem; }
ul, ol { margin: 0 0 1.15rem; padding-left: 1.3rem; }
li { margin-bottom: .45rem; }
li > ul, li > ol { margin-top: .45rem; margin-bottom: .3rem; }

a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { text-decoration-thickness: 2px; }

strong { font-weight: 650; }
em { font-style: italic; }

code, .mono { font-family: var(--font-mono); font-size: .875em; }
p code, li code, td code {
  background: var(--bg-inset); padding: .1em .35em; border-radius: 3px;
  border: 1px solid var(--border-soft);
}

hr { border: 0; border-top: 1px solid var(--border); margin: 2.5rem 0; }

/* Plus aucun <abbr title> sur le site : il se soulignait en pointillés
   exactement comme un terme de glossaire, promettant une bulle qui ne venait
   jamais. Même signal, comportement différent — le lecteur ne peut pas deviner
   lequel des deux il a sous le curseur. La convention est le glossaire ; cette
   règle est conservée sans soulignement, pour qu'un <abbr> égaré n'imite plus
   un terme glosé. */
abbr[title] { text-decoration: none; cursor: inherit; }

/* --- 3. Structure --------------------------------------------------------- */

.layout { display: flex; align-items: flex-start; }

.sidebar {
  position: sticky; top: 0; flex: 0 0 16.5rem; height: 100vh;
  overflow-y: auto; padding: 1.5rem 1rem 3rem 1.5rem;
  border-right: 1px solid var(--border); background: var(--bg-soft);
}

.brand { display: block; text-decoration: none; color: var(--text); margin-bottom: 1.6rem; }
.brand-mark {
  font-family: var(--font-sans); font-weight: 700; font-size: 1.02rem;
  letter-spacing: -.01em; display: flex; align-items: center; gap: .5rem;
}
.brand-mark svg { flex: 0 0 auto; }
.brand-sub { font-family: var(--font-sans); font-size: .74rem; color: var(--text-faint); letter-spacing: .04em; text-transform: uppercase; margin-top: .25rem; padding-left: 1.75rem; }

.nav { font-family: var(--font-sans); font-size: .875rem; }
.nav-group { margin-bottom: 1.35rem; }
.nav-title {
  font-size: .68rem; text-transform: uppercase; letter-spacing: .09em;
  color: var(--text-faint); font-weight: 650; margin-bottom: .5rem; padding-left: .55rem;
}
.nav a {
  display: block; padding: .32rem .55rem; border-radius: 4px;
  color: var(--text-muted); text-decoration: none; line-height: 1.35;
  border-left: 2px solid transparent;
}
.nav a:hover { background: var(--bg-inset); color: var(--text); }
.nav a[aria-current="page"] {
  color: var(--accent); background: var(--accent-soft);
  border-left-color: var(--accent); font-weight: 600;
}

/* Le sommaire de page recopié dans le tiroir, sous le lien du chapitre courant,
   ne sert que sur téléphone, où la boîte « Sur cette page » est hors de portée
   une fois qu'on a défilé. */
.nav-toc { display: none; }

.main { flex: 1 1 auto; min-width: 0; padding: 0 clamp(1.1rem, 4vw, 3.5rem) 6rem; }

/* Le conteneur occupe toute la largeur libre ; à l'intérieur, le texte courant
   reste à une largeur lisible tandis que les tableaux, figures et cartes
   s'étalent sur toute la place disponible. */
.wrap { max-width: 80rem; margin: 0 auto; }
.wrap-wide { max-width: 80rem; margin: 0 auto; }

.wrap > p,
.wrap > ul,
.wrap > ol,
.wrap > h1, .wrap > h2, .wrap > h3, .wrap > h4,
.wrap > .quote,
.wrap > .formula,
.wrap > .table-note,
.wrap > .footnote,
.wrap > .toc,
.wrap > .disclaimer,
.wrap > .pager,
.wrap > .site-footer,
.page-head > * {
  max-width: var(--measure);
}

/* Un encadré contient du texte : un peu plus large que la prose, pas davantage. */
.wrap > .callout { max-width: 52rem; }

/* Éléments de données : toute la largeur disponible. */
.wrap > .table-scroll,
.wrap > figure,
.wrap > .figure-frame,
.wrap > .cards,
.wrap > .stats,
.wrap > .comp-list,
.wrap > .legend,
.wrap > .preset-row,
.wrap > [data-table],
.wrap > [data-models],
.wrap > [data-manuels],
.wrap > .sim-layout {
  max-width: 100%;
}

/* Les tableaux imbriqués dans un encadré suivent la largeur de l'encadré. */
.callout .table-scroll { margin-left: 0; margin-right: 0; }

/* Sur grand écran, le sommaire quitte le fil du texte pour occuper la marge
   droite et devenir un rail de navigation qui suit le défilement. Ne s'applique
   qu'aux pages qui possèdent effectivement un sommaire. */
@media (min-width: 1500px) {
  .wrap:has(> .toc) {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 17rem;
    column-gap: 3.5rem;
    align-items: start;
  }
  /* Le texte reste à sa largeur lisible à l'intérieur de la colonne. */
  .wrap:has(> .toc) > * { grid-column: 1; max-width: var(--measure); }
  .wrap:has(> .toc) > .callout { max-width: 52rem; }

  .wrap:has(> .toc) > .toc {
    grid-column: 2;
    grid-row: 2 / 1000;
    position: sticky;
    top: 1.5rem;
    margin: 0;
    align-self: start;
    max-height: calc(100vh - 3rem);
    overflow-y: auto;
  }

  /* Les éléments larges remplissent toute la colonne de contenu — sans jamais
     passer sous le rail, qui serait alors recouvert. */
  .wrap:has(> .toc) > .table-scroll,
  .wrap:has(> .toc) > figure,
  .wrap:has(> .toc) > .figure-frame,
  .wrap:has(> .toc) > .cards,
  .wrap:has(> .toc) > .stats,
  .wrap:has(> .toc) > .comp-list,
  .wrap:has(> .toc) > .preset-row,
  .wrap:has(> .toc) > [data-table],
  .wrap:has(> .toc) > [data-models],
  .wrap:has(> .toc) > [data-manuels] {
    max-width: 100%;
  }
}

.page-head { padding: clamp(2.5rem, 6vw, 4.5rem) 0 1.2rem; }
.eyebrow {
  font-family: var(--font-sans); font-size: .74rem; font-weight: 650;
  letter-spacing: .1em; text-transform: uppercase; color: var(--accent);
  margin: 0 0 .7rem;
}
.lead { font-size: 1.19rem; line-height: 1.6; color: var(--text-muted); margin-bottom: 0; }

/* --- 4. Barre supérieure mobile ------------------------------------------- */

.topbar {
  display: none; position: sticky; top: 0; z-index: 40;
  align-items: center; justify-content: space-between; gap: .75rem;
  padding: .6rem clamp(1.1rem, 4vw, 2rem);
  background: color-mix(in srgb, var(--bg) 92%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border);
}

.icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2.1rem; height: 2.1rem; padding: 0;
  background: transparent; border: 1px solid var(--border); border-radius: var(--radius);
  color: var(--text-muted); cursor: pointer;
}
.icon-btn:hover { background: var(--bg-inset); color: var(--text); }

/* En haut à droite, hors du fil de lecture. Sur téléphone, il vient occuper
   l'emplacement que la topbar lui réserve à droite du titre. */
.theme-toggle { position: fixed; top: 1rem; right: 1rem; z-index: 50; background: var(--bg-panel); box-shadow: var(--shadow); }

@media (max-width: 900px) {
  .topbar { display: flex; }
  .layout { display: block; }
  .sidebar {
    position: fixed; inset: 0 auto 0 0; z-index: 45; width: min(20rem, 84vw);
    height: 100vh; transform: translateX(-102%); transition: transform .22s ease;
    box-shadow: var(--shadow);
  }
  .sidebar.open { transform: none; }
  .theme-toggle { top: .6rem; right: clamp(1.1rem, 4vw, 2rem); box-shadow: none; }
  .nav-toc {
    display: block; margin: .15rem 0 .5rem .55rem;
    padding-left: .6rem; border-left: 2px solid var(--border);
  }
  .nav-toc a { font-size: .82rem; padding: .26rem .5rem; }
  .scrim { position: fixed; inset: 0; z-index: 44; background: rgba(10, 18, 24, .45); }
  .main { padding-top: .5rem; }
}

/* --- 5. Encadrés ---------------------------------------------------------- */

.callout {
  margin: 1.8rem 0; padding: 1rem 1.15rem; border-radius: var(--radius);
  border: 1px solid var(--border); border-left-width: 3px;
  background: var(--bg-panel); font-size: .98rem;
}
.callout > :last-child { margin-bottom: 0; }
.callout-title {
  font-family: var(--font-sans); font-weight: 650; font-size: .82rem;
  letter-spacing: .05em; text-transform: uppercase; margin: 0 0 .45rem;
  display: flex; align-items: center; gap: .4rem;
}
.callout.info    { border-left-color: var(--accent); background: var(--accent-soft); }
.callout.info    .callout-title { color: var(--accent); }
.callout.key     { border-left-color: var(--ok); background: var(--ok-soft); }
.callout.key     .callout-title { color: var(--ok); }
.callout.warn    { border-left-color: var(--warn); background: var(--warn-soft); }
.callout.warn    .callout-title { color: var(--warn); }
.callout.danger  { border-left-color: var(--danger); background: var(--danger-soft); }
.callout.danger  .callout-title { color: var(--danger); }

/* --- 6. Citations et sources ---------------------------------------------- */

a.src {
  font-family: var(--font-sans); font-size: .68em; font-weight: 600;
  vertical-align: .35em; line-height: 1; white-space: nowrap;
  padding: .12em .38em; margin-left: .12em;
  background: var(--accent-soft); color: var(--accent);
  border-radius: 3px; text-decoration: none;
  border: 1px solid transparent;
}
a.src:hover { border-color: var(--accent-line); }

.quote {
  margin: 1.6rem 0; padding: .2rem 0 .2rem 1.1rem;
  border-left: 3px solid var(--accent-line);
  font-style: italic; color: var(--text-muted);
}
.quote > :last-child { margin-bottom: 0; }
.quote cite {
  display: block; margin-top: .5rem; font-style: normal;
  font-family: var(--font-sans); font-size: .82rem; color: var(--text-faint);
}

/* --- 7. Tableaux ---------------------------------------------------------- */

.table-scroll {
  overflow-x: auto; margin: 1.8rem 0;
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--bg-panel);
}
table { border-collapse: collapse; width: 100%; font-family: var(--font-sans); font-size: .875rem; }
caption {
  caption-side: top; text-align: left; padding: .8rem 1rem .1rem;
  font-family: var(--font-sans); font-size: .82rem; color: var(--text-muted);
}
th, td { padding: .5rem .75rem; text-align: left; border-bottom: 1px solid var(--border-soft); vertical-align: top; }
thead th {
  font-size: .74rem; text-transform: uppercase; letter-spacing: .05em;
  color: var(--text-muted); font-weight: 650; white-space: nowrap;
  background: var(--bg-inset);
}
tbody tr:last-child td { border-bottom: 0; }
tbody tr:hover { background: var(--bg-inset); }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; font-family: var(--font-mono); font-size: .82rem; }
/* Séparateur vertical entre deux blocs de colonnes d'un même tableau : la classe
   se pose sur la première cellule de chaque bloc, en-tête comprise. */
th.bloc, td.bloc { border-left: 1px solid var(--border); }
/* Extrêmes d'une colonne chiffrée. La couleur double le gras, jamais l'inverse :
   l'information reste lisible sans elle. */
td.plus-long  { color: var(--ok); }
td.plus-court { color: var(--warn); }
/* Colonne pilotée par un curseur : elle ne classe rien, elle suit une saisie.
   Même accent que les valeurs réglables des figures, jamais le vert ni
   l'orange, qui disent ici « le plus long » et « le plus court ». */
th.col-reglee, td.col-reglee { color: var(--accent); }

.table-note { font-size: .82rem; color: var(--text-faint); margin: -1.2rem 0 1.8rem; font-family: var(--font-sans); }

/* --- 8. Badges et puces --------------------------------------------------- */

.badge {
  display: inline-block; font-family: var(--font-sans); font-size: .7rem;
  font-weight: 650; letter-spacing: .03em; padding: .16em .5em;
  border-radius: 3px; border: 1px solid var(--border); white-space: nowrap;
  background: var(--bg-inset); color: var(--text-muted);
}
.badge.buhlmann { background: var(--accent-soft); color: var(--accent); border-color: var(--accent-line); }
.badge.bubble   { background: var(--warn-soft); color: var(--warn); border-color: currentColor; }
.badge.haldane  { background: var(--ok-soft); color: var(--ok); border-color: currentColor; }
.badge.propre   { background: var(--bg-inset); color: var(--text-faint); }
.badge.ok       { background: var(--ok-soft); color: var(--ok); border-color: currentColor; }
.badge.warn     { background: var(--warn-soft); color: var(--warn); border-color: currentColor; }
.badge.danger   { background: var(--danger-soft); color: var(--danger); border-color: currentColor; }

.dot { display: inline-block; width: .6rem; height: .6rem; border-radius: 50%; margin-right: .35rem; vertical-align: baseline; }

/* --- 9. Figures ----------------------------------------------------------- */

figure { margin: 2rem 0; }
figure svg { display: block; width: 100%; height: auto; }
figcaption {
  font-family: var(--font-sans); font-size: .82rem; color: var(--text-muted);
  margin-top: .7rem; line-height: 1.5;
}
.figure-frame {
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--bg-panel); padding: 1rem;
}

/* --- 9b. SVG des figures calculées ---------------------------------------- */

.fig-axis  { stroke: var(--text-faint); stroke-width: 1; }
.fig-grid  { stroke: var(--border-soft); stroke-width: 1; }
.fig-tick  { fill: var(--text-faint); font-family: var(--font-sans); font-size: 10px; }
.fig-axis-label { fill: var(--text-muted); font-family: var(--font-sans); font-size: 11px; font-weight: 600; }
.fig-label { font-family: var(--font-sans); font-size: 10.5px; font-weight: 650; fill: var(--text-muted); }
.fig-titre { font-family: var(--font-sans); font-size: 13px; font-weight: 650; fill: var(--text); }
.fig-note  { font-family: var(--font-sans); font-size: 10.5px; fill: var(--text-faint); font-style: italic; }
/* La valeur exacte, entre parenthèses derrière la valeur ronde du raisonnement :
   même couleur et même taille, l'italique disant seul que c'est un aparté.
   Sert au repère des périodes, où l'on raisonne sur 100 % d'un compartiment qui
   n'en est jamais qu'à 98,4. */
.fig-label .exact, .fig-note .exact { font-style: italic; }
.fig-curve { stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; fill: none; }
.fig-marker { stroke: var(--text-faint); stroke-width: 1; stroke-dasharray: 3 3; }
.fig-dot   { fill: currentColor; }

/* palette ordonnée : du plus permissif au plus pénalisant */
/* Une courbe reçoit UNIQUEMENT stroke. Toute déclaration `fill` ici écraserait
   le fill="none" porté par la balise — un attribut de présentation a la plus
   faible priorité qui soit, et la courbe se remplirait en aplat. Les
   étiquettes et les points, eux, ne reçoivent que fill. */
.fig-curve.c0, .fig-rappel.c0 { stroke: var(--c1); }
.fig-curve.c1, .fig-rappel.c1 { stroke: var(--c2); }
.fig-curve.c2, .fig-rappel.c2 { stroke: var(--c3); }
.fig-curve.c3, .fig-rappel.c3 { stroke: var(--c4); }
.fig-curve.c4, .fig-rappel.c4 { stroke: var(--c5); }
.fig-curve.c5, .fig-rappel.c5 { stroke: var(--c6); }
.fig-curve.c6, .fig-rappel.c6 { stroke: var(--c7); }

/* Une note peut porter la couleur d'une courbe pour s'y rattacher visuellement.
   Comme les étiquettes, elle ne reçoit que fill — jamais stroke. */
.fig-note.c0, .fig-label.c0, .fig-dot.c0 { fill: var(--c1); color: var(--c1); stroke: none; }
.fig-note.c1, .fig-label.c1, .fig-dot.c1 { fill: var(--c2); color: var(--c2); stroke: none; }
.fig-note.c2, .fig-label.c2, .fig-dot.c2 { fill: var(--c3); color: var(--c3); stroke: none; }
.fig-note.c3, .fig-label.c3, .fig-dot.c3 { fill: var(--c4); color: var(--c4); stroke: none; }
.fig-note.c4, .fig-label.c4, .fig-dot.c4 { fill: var(--c5); color: var(--c5); stroke: none; }
.fig-note.c5, .fig-label.c5, .fig-dot.c5 { fill: var(--c6); color: var(--c6); stroke: none; }
.fig-note.c6, .fig-label.c6, .fig-dot.c6 { fill: var(--c7); color: var(--c7); stroke: none; }

.fig-curve.ambient  { stroke: var(--text-faint); stroke-dasharray: 5 4; }
.fig-label.ambient  { fill: var(--text-faint); stroke: none; }
.fig-curve.mvalue   { stroke: var(--danger); }
.fig-label.mvalue, .fig-note.mvalue { fill: var(--danger); stroke: none; }
.fig-dot.mvalue     { fill: var(--danger); }
.fig-curve.gfline   { stroke: var(--accent); stroke-dasharray: 6 3; }
.fig-label.gfline, .fig-note.gfline { fill: var(--accent); stroke: none; }
.fig-curve.rapport  { stroke: var(--c4); stroke-dasharray: 6 3; }
.fig-curve.marche   { stroke: var(--c1); stroke-dasharray: 4 3; stroke-width: 1.5; }
.fig-rappel.marche  { stroke: var(--c1); }
.fig-label.marche   { fill: var(--c1); stroke: none; }
.fig-note.rapport, .fig-label.rapport { fill: var(--c4); stroke: none; }
.fig-dot.rapport    { fill: var(--c4); }
.fig-zone           { fill: var(--accent); opacity: .10; }
.fig-zone.danger    { fill: var(--danger); }
/* Bande intermédiaire : refusée par la droite la plus stricte, tolérée par la
   plus permissive. Un rouge à mi-opacité, entre le bleu du toléré et le rouge
   du refusé, évite le trou blanc qui se lisait comme un oubli. */
.fig-zone.danger-partiel { fill: var(--danger); opacity: .09; }
/* Commandes d'une figure réglable : deux curseurs sous le graphique, dans la
   même grille que les champs du simulateur. */
.fig-controls { display: grid; grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
                gap: .3rem 1.4rem; margin: .9rem 0 0; }
.fig-controls .field { margin-bottom: .4rem; }
.fig-readout { margin: .1rem 0 0; font-family: var(--font-mono); font-size: .8rem; }
/* Au calibre des étiquettes qu'elle remplace dans le graphe : celles-ci sont
   posées à 10,5 px dans un SVG rendu à peine agrandi, soit 11,4 px à l'écran.
   Héritée de .footnote, la légende s'affichait à 14,1 px et pesait plus lourd
   que la figure. */
.fig-legende { display: flex; flex-wrap: wrap; gap: .2rem 1.1rem; margin: .4rem 0 0; }
p.fig-legende.footnote { font-size: .7rem; }
.fig-legende-item { white-space: nowrap; }
.fig-jauge-box      { fill: none; stroke: var(--text-muted); stroke-width: 1.5; }
.fig-flux           { stroke-width: 2; fill: none; }
.fig-niveau         { stroke: var(--accent); stroke-width: 1.5; }
.fig-robinet        { fill: none; stroke: var(--text-muted); stroke-width: 3; stroke-linejoin: round; }
.fig-flux-tete      { stroke: none; }
.fig-flux.entree    { stroke: var(--danger); }
.fig-flux-tete.entree { fill: var(--danger); }
.fig-flux.sortie    { stroke: var(--c1); }
.fig-flux-tete.sortie { fill: var(--c1); }
.fig-jauge-fill     { fill: var(--accent); opacity: .30; }

/* Figure interactive du chapitre 5 : la population de germes et son curseur.
   Un germe inerte reste discret ; celui qui grossit prend l'accent, parce que
   c'est son entrée en croissance que la figure donne à voir. */
.fig-germe          { fill: var(--text-faint); opacity: .30; }
.fig-germe.grossi   { fill: var(--c1); opacity: .70; }
.fig-germe.actif    { fill: var(--accent); opacity: .85; }
.fig-curseur        { margin: .5rem 0 0; }
.fig-curseur input[type="range"] { width: 100%; accent-color: var(--accent); }
.fig-lecture        { font-family: var(--font-sans); font-size: .78rem;
                      color: var(--text-muted); margin: .4rem 0 0;
                      font-variant-numeric: tabular-nums; }
.fig-jauge-exces    { fill: var(--danger); opacity: .45; }
.fig-jauge-max      { stroke: var(--danger); stroke-width: 2; stroke-dasharray: 6 3; }
/* Le second trait d'un récipient : l'ancien critère, à comparer au nouveau.
   Même orange que le rapport fixe des figures de droites. */
.fig-jauge-max.rapport { stroke: var(--c4); stroke-width: 1.5; stroke-dasharray: 3 3; }
.fig-jauge-max.c1      { stroke: var(--c2); stroke-width: 1.5; stroke-dasharray: 5 3; }
/* Le trait du gradient factor sur un récipient, et le plancher de la bande où
   il se place. Même bleu et même gris que sur les figures de droites, pour
   qu'un trait garde le même sens d'une figure à l'autre. */
.fig-jauge-max.gfline  { stroke: var(--accent); stroke-width: 2; stroke-dasharray: 6 3; }
.fig-jauge-max.ambient { stroke: var(--text-faint); stroke-width: 1.2; stroke-dasharray: 3 3; }
.fig-bar            { opacity: .85; }
.fig-bar.c1         { fill: var(--c2); }
.fig-bar.c3         { fill: var(--c4); }
.fig-note.zone      { fill: var(--accent); font-style: normal; font-weight: 600; }
.fig-curve.deepstop    { stroke: var(--c5); }
.fig-label.deepstop    { fill: var(--c5); stroke: none; }
.fig-curve.shallowstop { stroke: var(--c1); }
.fig-label.shallowstop { fill: var(--c1); stroke: none; }

/* --- 10. Cartes ----------------------------------------------------------- */

.cards { display: grid; gap: 1rem; margin: 1.8rem 0; }
.cards.two { grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); }
.cards.three { grid-template-columns: repeat(auto-fit, minmax(12.5rem, 1fr)); }

.card {
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--bg-panel); padding: 1.1rem 1.2rem;
  font-size: .95rem;
}
.card > :last-child { margin-bottom: 0; }
.card h3, .card h4 { margin-top: 0; }
a.card { text-decoration: none; color: inherit; display: block; transition: border-color .15s, transform .15s; }
a.card:hover { border-color: var(--accent); transform: translateY(-1px); }
a.card .card-title { font-family: var(--font-sans); font-weight: 650; color: var(--accent); margin-bottom: .3rem; }
.card-meta { font-family: var(--font-sans); font-size: .78rem; color: var(--text-faint); }

/* --- 11. Formulaires (simulateur) ----------------------------------------- */

.panel {
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--bg-panel); padding: 1.2rem;
}

.field { margin-bottom: .95rem; font-family: var(--font-sans); }
.field label {
  display: flex; justify-content: space-between; align-items: baseline; gap: .5rem;
  font-size: .8rem; font-weight: 600; color: var(--text-muted); margin-bottom: .3rem;
}
.field label .val { font-family: var(--font-mono); font-size: .85rem; color: var(--accent); font-weight: 600; }

input[type="range"] { width: 100%; accent-color: var(--accent); }
input[type="number"], select {
  width: 100%; padding: .42rem .6rem; font-family: var(--font-sans); font-size: .9rem;
  color: var(--text); background: var(--bg); border: 1px solid var(--border);
  border-radius: 4px;
}
input[type="number"]:focus, select:focus { outline: 2px solid var(--accent); outline-offset: -1px; }

.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: .7rem; }

.btn {
  font-family: var(--font-sans); font-size: .85rem; font-weight: 600;
  padding: .45rem .85rem; border-radius: 4px; cursor: pointer;
  background: var(--bg-inset); color: var(--text); border: 1px solid var(--border);
}
.btn:hover { border-color: var(--accent); color: var(--accent); }
.btn.primary { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.btn.primary:hover { filter: brightness(1.08); color: var(--on-accent); }
.btn-row { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: .9rem; }

.preset-row { display: flex; flex-wrap: wrap; gap: .4rem; margin-bottom: .3rem; }
.preset {
  font-family: var(--font-sans); font-size: .75rem; font-weight: 600;
  padding: .25rem .55rem; border-radius: 999px; cursor: pointer;
  background: var(--bg-inset); color: var(--text-muted); border: 1px solid var(--border);
}
.preset:hover { border-color: var(--accent); color: var(--accent); }
.preset[aria-pressed="true"] { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.preset:disabled { opacity: .4; cursor: default; }
.preset:disabled:hover { border-color: var(--border); color: var(--text-muted); }

/* Barre de filtre marque/modèle des tableaux d'ordinateurs.
   Les listes déroulantes portent leur intitulé au-dessus : sans alignement
   explicite sur le bas, le flex étire le bouton et le compte sur toute la
   hauteur du bloc, et le bouton devient une pastille géante. */
.filtre-barre { align-items: flex-end; gap: .5rem .8rem; margin-bottom: .7rem; }
.filtre-barre label { display: flex; flex-direction: column; gap: .2rem; margin: 0; }
.filtre-barre select { width: auto; min-width: 9rem; max-width: 16rem; }
.filtre-barre .preset { padding: .42rem .7rem; }
.filtre-barre .filtre-compte { padding-bottom: .5rem; white-space: nowrap; }

/* Choix des colonnes. « Modèle » est verrouillée : son bouton reste allumé et
   garde son infobulle, mais il ne se clique pas. L'atténuer le ferait passer
   pour indisponible, ce qu'il n'est pas : il est acquis. */
.colonnes-barre { margin-bottom: .8rem; }
.colonnes-barre .preset[aria-disabled="true"] { cursor: default; }
.colonnes-barre .preset[aria-disabled="true"]:hover { border-color: var(--accent); }

/* « Toutes les colonnes » agit, il ne bascule pas une colonne : un écart le
   sépare des pastilles, sans quoi il se lit comme une dixième colonne. */
.colonnes-barre .preset-action { margin-left: .8rem; font-style: italic; }

/* Tableau à une ligne par algorithme.
   Le survol par ligne, qui suffit ailleurs, casse ici le groupe : la cellule
   fusionnée appartient à la première sous-ligne et reste dans son fond quand on
   pointe la seconde, ce qui dessine une marche d'escalier. Le survol porte donc
   sur toute la machine, posé par table-manuels.js. */
.par-algo tbody tr:hover { background: none; }
.par-algo tbody tr.groupe-survol,
.par-algo tbody tr.groupe-survol > td.fusionnee { background: var(--bg-inset); }

/* Les colonnes sont séparées d'un filet, de la même valeur que les filets
   horizontaux. Une version précédente ne le posait que sur les cellules
   fusionnées : les machines à plusieurs algorithmes se retrouvaient encadrées
   et les autres non, si bien que les colonnes n'existaient qu'une ligne sur
   trois. Le filet appartient à la grille, pas au groupe.
   Pas de filet à gauche de la première colonne, il tomberait sur le bord du
   tableau ; en border-collapse deux bords voisins n'en dessinent qu'un.
   Les lignes gardent toutes leur filet horizontal. Une version encore
   antérieure les effaçait à l'intérieur d'un groupe pour le « souder », avec un
   garde-fou en :last-of-type qui ne pouvait pas marcher : ce sélecteur désigne
   le dernier <tr> du tableau, pas le dernier de chaque groupe. Résultat, aucune
   ligne entre deux algorithmes et aucune entre deux machines. C'est la cellule
   fusionnée, sans filet horizontal en son milieu, qui dit le groupe. */
.par-algo th:not(:first-child),
.par-algo td:not(:first-child) { border-left: 1px solid var(--border-soft); }

/* Une cellule fusionnée se lit de haut en bas : son contenu se cale en haut. */
.par-algo td.fusionnee { vertical-align: top; }

/* --- 12. Sorties chiffrées ------------------------------------------------ */

/* La colonne minimale est celle qui fait tenir le plus long libellé sur une
   ligne, mesurée et non devinée : « En déco pendant » demande 117 px, plus le
   rembourrage. En dessous, un libellé passait sur deux lignes et la tuile en
   prenait quatre au lieu de trois. */
.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(8.7rem, 1fr)); gap: .1rem; margin: 1.2rem 0; }
/* Les trois lignes d'une tuile — libellé, nombre, unité — tiennent sur les
   mêmes rangées que celles de ses voisines. Sans cela, un libellé qui passe sur
   deux lignes descend son nombre et son unité, et toute la rangée perd son
   peigne ; ce qui arrivait dès qu'on repliait les réglages et que les tuiles
   changeaient de largeur. */
.stat {
  display: grid; grid-template-rows: subgrid; grid-row: span 3;
  align-content: start;
  padding: .7rem; background: var(--bg-inset);
  border: 1px solid var(--border-soft); font-family: var(--font-sans);
  /* Chaque tuile porte son explication en infobulle : le curseur l'annonce. */
  cursor: help;
}
/* Une ligne, jamais deux : c'est ce qui garantit trois lignes par tuile, donc
   des rangées de même hauteur. Le corps et l'interlettrage sont resserrés juste
   assez pour que le plus long tienne dans la colonne minimale ci-dessus. */
.stat-label { font-size: .62rem; text-transform: uppercase; letter-spacing: .04em; color: var(--text-faint); font-weight: 650; white-space: nowrap; }
.stat-value { font-size: 1.5rem; font-weight: 700; font-variant-numeric: tabular-nums; line-height: 1.2; margin-top: .15rem; }
.stat-unit { font-size: .8rem; font-weight: 500; color: var(--text-muted); margin-left: .15rem; }
.stat.accent .stat-value { color: var(--accent); }
.stat.warn .stat-value { color: var(--warn); }
.stat.danger .stat-value { color: var(--danger); }

/* --- 13. Barres de compartiments ------------------------------------------ */

.comp-list { font-family: var(--font-sans); font-size: .75rem; margin: 1rem 0; }
/* Deux colonnes de nombres à droite : « 2,92 / 2,69 bar », puis le plafond que
   ce compartiment impose à lui seul. Le plus bas des seize désigne le
   directeur, sans qu'il faille ouvrir une bulle pour le savoir. */
.comp-row, .comp-entete { display: grid; grid-template-columns: 2.4rem 3.1rem 1fr 6.6rem 3.1rem; gap: .5rem; align-items: center; margin-bottom: .22rem; }
/* L'en-tête des colonnes. Il porte lui-même sa bulle, d'où le curseur d'aide. */
.comp-entete {
  font-family: var(--font-sans); font-size: .6rem; font-weight: 650;
  text-transform: uppercase; letter-spacing: .04em; color: var(--text-faint);
  margin-bottom: .45rem; cursor: help;
}
.comp-entete span:nth-child(4), .comp-entete span:nth-child(5) { text-align: right; }
.comp-entete span:nth-child(2) { text-align: right; }
.comp-row .comp-plafond {
  text-align: right; font-variant-numeric: tabular-nums;
  font-family: var(--font-mono); font-size: .7rem; color: var(--text-muted);
  white-space: nowrap;
}
.comp-row.leading .comp-plafond { color: var(--danger); font-weight: 700; }
.comp-row .idx { color: var(--text-faint); font-variant-numeric: tabular-nums; }
.comp-row .ht { color: var(--text-muted); font-family: var(--font-mono); font-size: .7rem; text-align: right; }
.comp-bar { position: relative; height: .95rem; background: var(--bg-inset); border-radius: 2px; overflow: hidden; border: 1px solid var(--border-soft); }
.comp-bar i { position: absolute; inset: 0 auto 0 0; display: block; border-radius: 1px; }
/* Le repère de la limite : fixe sur l'échelle, il ne bouge pas d'un instant à
   l'autre de la plongée, seulement quand on change le réglage. */
.comp-bar .mline { position: absolute; top: -2px; bottom: -2px; width: 2px; background: var(--danger); }
/* VPM-B donne deux barres au même compartiment : la charge, puis le volume de
   phase. La seconde est plus basse et d'une autre couleur pour qu'aucune ne se
   lise à la place de l'autre, et les deux se serrent l'une contre l'autre pour
   se lire comme une paire. Son bord droit est V_crit : la barre ne va pas
   au-delà, elle finit dessus. */
.comp-row.a-volume { margin-bottom: .06rem; }
.comp-row-vol { margin-bottom: .5rem; }
.comp-row-vol .comp-bar { height: .62rem; border-right: 2px solid var(--danger); }
.comp-row-vol .comp-bar i { background: var(--c1); }
.comp-row-vol .comp-bar .mline { background: var(--text); }
.comp-row-vol .ht { grid-column: 1 / 3; color: var(--text-faint); font-style: italic; }
.comp-row-vol .pct { grid-column: 4 / 6; }

.comp-row .pct { text-align: right; font-variant-numeric: tabular-nums; font-family: var(--font-mono); font-size: .7rem; white-space: nowrap; }
/* Le maximum toléré, à droite de la charge : c'est le nombre que porte le trait
   rouge de la barre, et celui qui rend « 111 % » lisible au fond. */
.comp-row .pct-max { color: var(--text-faint); font-weight: 400; }
.comp-row.leading .pct { color: var(--danger); font-weight: 700; }
.comp-row.leading .idx { color: var(--text); font-weight: 700; }

/* --- 13b. Simulateur ------------------------------------------------------ */

.sim-layout { display: grid; grid-template-columns: 17rem 1fr; gap: 1.4rem; align-items: start; margin: 2rem 0; }
@media (max-width: 780px) { .sim-layout { grid-template-columns: 1fr; } }

.sim-controls { position: sticky; top: 1rem; }
@media (max-width: 780px) { .sim-controls { position: static; } }

.sim-profile svg, .sim-out svg { width: 100%; height: auto; display: block; }

.sim-ceil-zone { fill: var(--danger); opacity: .09; }
/* Le franchissement de la courbe de sécurité, et la bande de temps passée
   au-delà. En jaune et non en rouge : le rouge dit déjà le plafond, qui est un
   interdit, alors que dépasser la courbe est seulement entrer en décompression
   obligatoire. */
.sim-zone-depassement { fill: var(--warn); opacity: .10; }
.sim-trait-courbe { stroke: var(--warn); stroke-width: 1.4; stroke-dasharray: 4 3; }
.sim-ceil      { stroke: var(--danger); stroke-width: 1.8; stroke-dasharray: 5 3; }
.sim-ceil100   { stroke: var(--text-faint); stroke-width: 1.2; stroke-dasharray: 2 3; }
.sim-profile-line, .sim-profile polyline.sim-profile { stroke: var(--accent); }
polyline.sim-profile { stroke: var(--accent); stroke-width: 2.4; stroke-linejoin: round; }
.sim-stop-dot  { fill: var(--accent); }

/* Le curseur temporel du profil, posé sous le graphe comme un curseur ordinaire
   plutôt que piloté au survol : la lecture doit tenir pendant qu'on descend
   regarder les barres qu'elle décrit. */
.sim-curseur-ligne { stroke: var(--text-muted); stroke-width: 1; stroke-dasharray: 3 3; }
.sim-curseur-point { fill: var(--accent); stroke: var(--bg-panel); stroke-width: 1.5; }
.sim-instant { margin: .8rem 0 .2rem; }
.sim-lecture {
  font-family: var(--font-mono); font-size: .8rem; color: var(--text);
  font-weight: 600; margin: 0; min-height: 1.4em;
}

/* --- Le profil multi-niveaux : poignées sur le graphe, table dans le panneau.
   La poignée est large à dessein — cible de doigt autant que de souris — et
   son contour reprend le fond du panneau pour se détacher du trait qu'elle
   chevauche. Le survol l'éclaircit sans virer au rouge ni au jaune, déjà pris
   par le plafond et la courbe de sécurité. */
.sim-poignee { fill: var(--accent); stroke: var(--bg-panel); stroke-width: 2; cursor: grab; }
.sim-poignee:hover { stroke: var(--accent); fill: var(--bg-panel); }
.sim-poignee:active { cursor: grabbing; }

.sim-profil-multi, .sim-points-bouton {
  font-family: var(--font-sans); font-size: .76rem; font-weight: 600;
  padding: .38rem .65rem; border-radius: 7px;
  border: 1px dashed var(--border); background: transparent; color: var(--text-muted);
  cursor: pointer;
}
.sim-profil-multi { margin: -.3rem 0 1rem; }
.sim-profil-multi:hover, .sim-points-bouton:hover {
  border-color: var(--accent); color: var(--accent); border-style: solid;
}

.sim-points { margin-bottom: 1.1rem; font-family: var(--font-sans); }
.sim-points-titre {
  display: flex; align-items: center;
  font-size: .78rem; font-weight: 600; color: var(--text-muted);
  margin-bottom: .5rem;
}
.sim-point-row {
  display: grid; grid-template-columns: 1.7rem 1fr auto 1fr auto 1.6rem;
  gap: .4rem; align-items: center; margin-bottom: .35rem;
}
.sim-point-row input { width: 100%; min-width: 0; }
.sim-point-nom { font-family: var(--font-mono); font-size: .74rem; color: var(--text-faint); }
.sim-point-unite { font-size: .72rem; color: var(--text-faint); }
.sim-point-retirer {
  border: 1px solid var(--border); background: transparent; color: var(--text-muted);
  border-radius: 6px; width: 1.55rem; height: 1.55rem; line-height: 1;
  font-size: .9rem; cursor: pointer; padding: 0;
}
.sim-point-retirer:hover:not(:disabled) { border-color: var(--danger); color: var(--danger); }
.sim-point-retirer:disabled { opacity: .35; cursor: default; }
.sim-points-actions { display: flex; gap: .5rem; margin-top: .55rem; flex-wrap: wrap; }

/* --- 13c. Le banc : plusieurs configurations sur une même page -------------
   Une configuration est une instance complète du simulateur. Elle porte une
   pastille de couleur qui la relie à sa courbe dans le graphe superposé et à sa
   ligne dans le tableau des écarts : c'est le seul fil qui permette de savoir,
   d'un coup d'œil, quelle courbe appartient à quels réglages. */

/* Le verrou de la plongée, posé sur le titre de sa section. Fermé, il est
   discret : c'est l'état normal, et une configuration détachée est le cas
   remarquable, donc le seul à s'annoncer par la couleur. */
/* Les deux gradient factors, chacun dans sa couleur, du curseur jusqu'au nombre
   qu'il commande. Vert pour GF Low, bleu pour GF High. Ni orange ni rouge : sur
   une page qui compare des décompressions, ces teintes se liraient comme un
   jugement porté sur le réglage. Le bleu est celui de tous les autres curseurs
   de la page, et le vert n'est employé par aucune configuration, donc rien ne
   les confond avec les pastilles de couleur du banc. */
input[type="range"].sim-gf-bas  { accent-color: var(--c2); }
input[type="range"].sim-gf-haut { accent-color: var(--accent); }
.field label .val .gf-bas  { color: var(--c2); }
.field label .val .gf-haut { color: var(--accent); }
.field label .val .gf-sep  { color: var(--text-faint); font-weight: 400; }

/* Le point d'aide d'un champ : discret à côté de son libellé, mais atteignable
   au clavier, parce que la bulle qu'il porte est parfois la seule explication
   d'un réglage à trois options. */
.sim-aide {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.05rem; height: 1.05rem; margin-left: .35rem; padding: 0;
  vertical-align: middle;
  border: 1px solid var(--border); border-radius: 50%;
  background: transparent; color: var(--text-faint);
  font-family: var(--font-sans); font-size: .62rem; font-weight: 700; line-height: 1;
  cursor: help;
}
.sim-aide:hover, .sim-aide:focus-visible { border-color: var(--accent); color: var(--accent); }
.sim-bulle strong { color: var(--accent); }

.sim-section-title.avec-verrou { display: flex; align-items: center; gap: .4rem; }
.sim-verrou {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.4rem; height: 1.4rem; padding: 0;
  border: 1px solid transparent; border-radius: 5px;
  background: transparent; color: var(--text-faint); cursor: pointer;
}
.sim-verrou:hover { border-color: var(--border); color: var(--text-muted); }
.sim-verrou[aria-pressed="false"] { color: var(--accent); }
.sim-verrou[aria-pressed="false"]:hover { border-color: var(--accent); }

.sim-config {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: .2rem 1.1rem 1.1rem;
  margin-bottom: 1.6rem;
  background: var(--bg-panel, transparent);
}
.sim-config .sim-layout { margin: .8rem 0 0; }

.sim-config-tete {
  display: flex; align-items: baseline; gap: .6rem;
  padding: .8rem 0 .55rem;
  border-bottom: 1px solid var(--border-soft);
}
.sim-config-titre { margin: 0; font-size: .95rem; white-space: nowrap; flex: none; }
/* Sur mobile, le résumé passe sous le titre plutôt que de le couper en deux :
   « Configuration B » sur deux lignes se lit comme deux configurations. */
@media (max-width: 620px) {
  .sim-config-tete { flex-wrap: wrap; }
  .sim-config-resume { order: 3; flex-basis: 100%; white-space: normal; }
}
.sim-config-resume {
  flex: 1 1 auto; min-width: 0;
  font-family: var(--font-mono); font-size: .74rem; color: var(--text-muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Replier les réglages : la grille passe à une colonne et les résultats
   prennent toute la largeur. Le bouton est posé au-dessus du panneau qu'il
   commande, et son chevron pointe vers là où va le panneau. */
.sim-layout.sans-commandes { grid-template-columns: 1fr; }
.sim-config-barre { margin: .9rem 0 -.5rem; }
.sim-config-replier {
  display: inline-flex; align-items: center; gap: .4rem;
  font-family: var(--font-sans); font-size: .78rem; font-weight: 600;
  padding: .34rem .7rem; border-radius: 7px;
  border: 1px solid var(--border); background: transparent; color: var(--text-muted);
  cursor: pointer;
}
.sim-config-replier:hover { border-color: var(--accent); color: var(--accent); }
.sim-config-replier svg { transition: transform .15s ease; }
.sim-config-replier[aria-expanded="false"] { color: var(--accent); border-color: var(--accent); }
.sim-config-replier[aria-expanded="false"] svg { transform: rotate(180deg); }

.sim-config-retirer {
  flex: none;
  border: 1px solid var(--border); background: transparent; color: var(--text-muted);
  border-radius: 6px; width: 1.7rem; height: 1.7rem; line-height: 1;
  font-size: 1rem; cursor: pointer;
}
.sim-config-retirer:hover { border-color: var(--danger); color: var(--danger); }

.sim-config-pastille, .sim-pastille {
  display: inline-block; flex: none;
  width: .62rem; height: .62rem; border-radius: 50%;
}
.sim-config-pastille.c0, .sim-pastille.c0, .sim-legend-trait.c0 { background: var(--c1); }
.sim-config-pastille.c1, .sim-pastille.c1, .sim-legend-trait.c1 { background: var(--c2); }
.sim-config-pastille.c2, .sim-pastille.c2, .sim-legend-trait.c2 { background: var(--c3); }
.sim-config-pastille.c3, .sim-pastille.c3, .sim-legend-trait.c3 { background: var(--c4); }
.sim-config-pastille.c4, .sim-pastille.c4, .sim-legend-trait.c4 { background: var(--c5); }
.sim-config-pastille.c5, .sim-pastille.c5, .sim-legend-trait.c5 { background: var(--c6); }

.sim-banc-pied { display: flex; align-items: center; gap: .8rem; margin: 0 0 2rem; }
.sim-ajouter {
  font-family: var(--font-sans); font-size: .85rem; font-weight: 600;
  padding: .5rem .9rem; border-radius: 7px;
  border: 1px dashed var(--border); background: transparent; color: var(--text-muted);
  cursor: pointer;
}
.sim-ajouter:hover { border-color: var(--accent); color: var(--accent); border-style: solid; }

/* Une note posée dans le panneau de commandes, à la place d'un contrôle qui
   n'existe pas pour ce moteur. Elle suit le rythme des champs, pas celui de la
   prose du chapitre. */
.sim-note-champ { margin: -.5rem 0 1rem; font-size: .75rem; }

.sim-comparaison { margin: 2.4rem 0; }

/* La légende du graphe superposé, qui est aussi sa commande. Elle ne reprend pas
   .preset : cette classe remplit le bouton d'accent une fois enfoncé, et la
   couleur de la configuration, seule chose à lire ici, disparaîtrait dedans. */
.profils-barre { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; margin: .9rem 0 .5rem; }
.profils-barre > .footnote { margin: 0 .3rem 0 0; }
.profil-bascule {
  display: inline-flex; align-items: center; gap: .45rem;
  font-family: var(--font-sans); font-size: .78rem;
  padding: .32rem .75rem; border-radius: 999px;
  border: 1px solid var(--border); background: transparent; color: var(--text);
  cursor: pointer;
}
.profil-bascule:hover { border-color: var(--accent); }
.profil-bascule .sim-legend-trait { flex: none; }
.profil-bascule[aria-pressed="false"] { opacity: .45; }
.profil-bascule[aria-disabled="true"] { cursor: default; }
.profil-bascule[aria-disabled="true"]:hover { border-color: var(--border); }
.sim-resume-cell { font-family: var(--font-mono); font-size: .72rem; color: var(--text-muted); }
/* L'écart se pose sous la valeur, jamais à côté : à côté, il passe à la ligne
   sur certaines cellules et pas sur d'autres, et la colonne perd son peigne. */
.sim-ecart { display: block; font-size: .72rem; color: var(--text-muted); white-space: nowrap; }
.sim-ecart.nul { color: var(--text-faint); }

/* Les traits du graphe superposé. La couleur vient de .fig-curve.cN, déjà
   définie pour les figures : une seule palette pour tout le site. */
.sim-multi-profil { stroke-width: 2.2; stroke-linejoin: round; }
.sim-multi-ceil   { stroke-width: 1.4; stroke-dasharray: 5 3; }
.sim-legend-trait { display: inline-block; width: 1.1rem; height: 3px; border-radius: 2px; }

.sim-section-title {
  font-family: var(--font-sans); font-size: .72rem; font-weight: 650;
  text-transform: uppercase; letter-spacing: .07em; color: var(--text-faint);
  margin: 1.4rem 0 .5rem;
}
/* La marge haute sépare une section de la précédente. En tête du panneau elle
   ne sépare rien et ne fait qu'ouvrir un vide sous la bordure. */
.sim-section-title:first-child { margin-top: 0; }

.check-row { display: flex; align-items: center; gap: .5rem; font-family: var(--font-sans); font-size: .85rem; margin-bottom: .6rem; }
.check-row input { accent-color: var(--accent); }

/* --- 14. Divers ----------------------------------------------------------- */

.toc {
  font-family: var(--font-sans); font-size: .88rem;
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--bg-soft); padding: 1rem 1.2rem; margin: 2rem 0;
}
.toc-title { font-size: .7rem; text-transform: uppercase; letter-spacing: .08em; color: var(--text-faint); font-weight: 650; margin-bottom: .5rem; }
.toc ol { margin: 0; padding-left: 1.1rem; }
.toc li { margin-bottom: .25rem; }
.toc a { text-decoration: none; }
.toc a:hover { text-decoration: underline; }

.footnote { font-size: .88rem; color: var(--text-muted); }

/* Portrait de la page À propos : photo ronde, texte à côté. */
.auteur { display: flex; align-items: center; gap: 1.6rem; margin: 1.5rem 0; }
.auteur-ligne { margin-bottom: 0; }
.auteur-citation { font-family: var(--font-serif); margin: .8rem 0 0; }
.auteur-citation p { margin-bottom: .8rem; }
.auteur-photo {
  width: 200px; height: 200px; flex-shrink: 0;
  border-radius: 50%; object-fit: cover;
  border: 3px solid var(--bg-panel);
  box-shadow: 0 0 0 2px var(--accent-line);
}
/* Sous 540 px, le texte n'a plus la place à côté de la photo. */
@media (max-width: 540px) {
  .auteur { flex-direction: column; align-items: flex-start; gap: 1rem; }
}

/* ============================================================================
   Boîte « Me contacter » de la page À propos.

   Repliée au chargement : le lecteur vient pour le contenu, et un formulaire
   déplié prendrait la place d'un texte que personne n'a demandé à quitter.

   Le formulaire poste vers le service de contact du VPS, qui remet le message
   au serveur de courrier du domaine. L'adresse mailto ne reparaît que si cet
   envoi échoue : elle devient le secours, dans la ligne d'état.
   ========================================================================= */

.contact {
  max-width: 42rem;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--bg-inset);
  margin: 1.6rem 0 2.4rem;
}

.contact > summary {
  display: flex; align-items: center; gap: .6rem;
  padding: .8rem 1rem; cursor: pointer; border-radius: 10px;
  font-family: var(--font-sans); color: var(--text);
  list-style: none;   /* Firefox affiche un triangle natif ; le chevron le remplace. */
}
.contact > summary::-webkit-details-marker { display: none; }
.contact > summary:hover { background: var(--accent-soft); }
.contact > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.contact[open] > summary {
  border-bottom: 1px solid var(--border);
  border-radius: 10px 10px 0 0;
}

.contact-icone  { flex: 0 0 auto; color: var(--accent); }
.contact-titre  { font-weight: 650; font-size: .92rem; }
.contact-sous   { font-size: .8rem; color: var(--text-muted); }
/* Sous 560 px, titre et sous-titre passeraient à la ligne et le chevron
   perdrait son alignement : le sous-titre s'efface, le titre suffit. */
@media (max-width: 560px) { .contact-sous { display: none; } }

.contact-chevron {
  flex: 0 0 auto; margin-left: auto; color: var(--text-faint);
  transition: transform .18s ease;
}
.contact[open] .contact-chevron { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) { .contact-chevron { transition: none; } }

.contact-corps { padding: 1rem 1rem 1.1rem; }
.contact .field { margin-bottom: .85rem; }

/* Les champs texte du site se limitaient au nombre et à la liste déroulante.
   Ces deux règles restent bornées à la boîte : elles ne repeignent aucun
   contrôle des autres pages. */
.contact input[type="text"], .contact input[type="email"], .contact textarea {
  width: 100%; padding: .5rem .65rem;
  font-family: var(--font-sans); font-size: .92rem; line-height: 1.5;
  color: var(--text); background: var(--bg);
  border: 1px solid var(--border); border-radius: 4px;
}
.contact textarea { resize: vertical; min-height: 7.5rem; }
.contact input[type="text"]:focus,
.contact input[type="email"]:focus,
.contact textarea:focus { outline: 2px solid var(--accent); outline-offset: -1px; }
.contact [aria-invalid="true"] { border-color: var(--danger); }

.contact-erreur {
  font-family: var(--font-sans); font-size: .78rem;
  color: var(--danger); margin: .3rem 0 0;
}
.contact-compteur {
  font-family: var(--font-mono); font-size: .74rem;
  color: var(--text-faint); font-weight: 400;
}
.contact-compteur.court { color: var(--warn); }

.contact-note { margin: .9rem 0 0; }
/* La hauteur est réservée d'avance : sans elle, le premier message d'état
   pousse le bas de la boîte au moment où le lecteur y porte les yeux. */
.contact-etat {
  margin: .6rem 0 0; min-height: 1.15rem;
  font-family: var(--font-sans); font-size: .82rem; color: var(--text-muted);
}
.contact-etat.fait { color: var(--ok); }
.contact-etat.rate { color: var(--danger); }
.contact-etat a { color: inherit; }

/* Le champ-piège quitte l'écran sans quitter le formulaire : `display: none`
   se repère au premier coup d'œil dans le code de la page, et les robots qui
   le lisent sautent le champ. */
.contact-piege {
  position: absolute; left: -9999px;
  width: 1px; height: 1px; overflow: hidden;
}

/* Pendant l'envoi, le bouton dit ce qu'il fait et refuse un second clic. */
.contact .btn:disabled { opacity: .6; cursor: default; }
.contact .btn:disabled:hover { border-color: var(--accent); color: var(--on-accent); }

/* Sur papier, un formulaire vide n'est que du bruit ; l'adresse reste dans le
   texte de la note. */
@media print { .contact { display: none; } }

.site-footer {
  border-top: 1px solid var(--border); margin-top: 4rem; padding: 2rem 0 1rem;
  font-family: var(--font-sans); font-size: .82rem; color: var(--text-faint);
}
.site-footer a { color: var(--text-muted); }

.pager { display: flex; justify-content: space-between; gap: 1rem; margin-top: 3.5rem; padding-top: 1.5rem; border-top: 1px solid var(--border); font-family: var(--font-sans); font-size: .9rem; }
.pager a { text-decoration: none; display: block; max-width: 48%; }
.pager .dir { font-size: .7rem; text-transform: uppercase; letter-spacing: .07em; color: var(--text-faint); font-weight: 650; }
.pager .to-next { text-align: right; margin-left: auto; }

.formula {
  font-family: var(--font-mono); font-size: .92rem; text-align: center;
  background: var(--bg-inset); border: 1px solid var(--border-soft);
  border-radius: var(--radius); padding: .9rem 1rem; margin: 1.5rem 0;
  overflow-x: auto; line-height: 1.9;
}
/* Titre d'un bloc de formule.
   Une formule posée sans titre n'est annonçable ni à l'œil, ni par un lecteur
   d'écran : le lecteur tombe sur des symboles sans savoir ce qu'ils calculent.
   En petites capitales, dans la police du texte et non celle du code, pour se
   distinguer nettement de l'équation qu'il annonce. */
.formula-titre {
  font-family: var(--font-sans); font-size: .72rem; font-weight: 700;
  letter-spacing: .06em; text-transform: uppercase;
  color: var(--text-muted); text-align: left;
  margin: 0 0 .85rem; padding-bottom: .5rem;
  border-bottom: 1px solid var(--border-soft);
}
.formula .note { display: block; font-family: var(--font-sans); font-size: .78rem; color: var(--text-faint); margin-top: .5rem; }
/* Rassurance posée entre le titre et les symboles : le lecteur qui fuit les
   mathématiques doit la lire AVANT l'équation, pas la découvrir après avoir
   décroché. En vert (--ok) : c'est une permission, ni une alerte ni un titre. */
.formula-rassure {
  font-family: var(--font-sans); font-size: .8rem; font-weight: 650;
  color: var(--ok); text-align: left;
  margin: 0 0 .75rem;
}

.legend { display: flex; flex-wrap: wrap; gap: .3rem 1.1rem; font-family: var(--font-sans); font-size: .78rem; color: var(--text-muted); margin: .7rem 0; }
.legend span { display: flex; align-items: center; gap: .35rem; }
.legend i { width: 1.1rem; height: 3px; border-radius: 2px; display: block; }
/* La légende des compartiments ne décrit pas des courbes mais des barres : ses
   pastilles prennent la hauteur d'un remplissage, et le repère garde la forme
   du trait vertical qu'il désigne dans la barre. Les trois couleurs s'empilent
   pour se lire comme l'échelle qu'elles sont ; l'écart plus large les sépare du
   repère, qui n'est pas de même nature. */
.legend-comps { flex-direction: column; align-items: flex-start; gap: .5rem; }
.legend-comps .legend-groupe { flex-direction: column; align-items: flex-start; gap: .25rem; }
.legend-comps i { height: .6rem; border-radius: 1px; flex: none; }
/* Le trait ne fait que deux pixels de large : on lui rend l'empreinte des
   autres pastilles pour que les quatre libellés partent du même bord. */
.legend i.trait { width: 2px; height: .85rem; border-radius: 0; margin: 0 calc((1.1rem - 2px) / 2); }

.disclaimer {
  border: 2px solid var(--danger); border-radius: var(--radius);
  background: var(--danger-soft); padding: 1rem 1.15rem; margin: 2rem 0;
  font-family: var(--font-sans); font-size: .9rem;
}
.disclaimer strong { color: var(--danger); }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* Lien d'évitement : la barre latérale et ses quatorze liens précèdent le
   contenu dans le DOM ; au clavier, ce lien est le premier arrêt de chaque
   page. Invisible tant qu'il n'a pas le focus. */
.skip-link {
  position: absolute; left: -100vw; top: 0; z-index: 100;
  padding: .6rem 1rem; background: var(--accent); color: var(--on-accent);
  font-family: var(--font-sans); font-size: .9rem; font-weight: 600;
  border-radius: 0 0 var(--radius) 0; text-decoration: none;
}
.skip-link:focus { left: 0; }

/* Le seul mouvement non trivial du site est le défilement animé des ancres
   (sommaires, notes) : sur une page longue il dure près d'une seconde. Les
   deux transitions restantes sont neutralisées par cohérence. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .sidebar { transition: none; }
  a.card { transition: none; }
  a.card:hover { transform: none; }
}

/* Écrans tactiles : les commandes montent à 44 px (recommandation WCAG AAA /
   Apple HIG) sans toucher aux proportions sur écran pointé à la souris. */
@media (pointer: coarse) {
  .icon-btn { width: 2.75rem; height: 2.75rem; }
  .preset { min-height: 2.75rem; display: inline-flex; align-items: center; }
  .btn { min-height: 2.75rem; }
  .nav a { padding-top: .6rem; padding-bottom: .6rem; }
}

@media print {
  .sidebar, .topbar, .theme-toggle, .pager { display: none !important; }
  body { background: #fff; color: #000; font-size: 11pt; }
}

/* Note secondaire sous une valeur de tuile statistique. */
.stat-note { font-size: .72rem; color: var(--text-muted); margin-top: .2rem; line-height: 1.3; }


/* ============================================================================
   Glossaire — terme marqué et bulle de rappel.
   La bulle est un confort : sans JavaScript et à l'impression, le terme reste
   du texte ordinaire et le lecteur passe par glossaire.html.
   ========================================================================= */

.gloss {
  border-bottom: 1px dotted var(--accent-line);
  cursor: help;
}
.gloss:hover,
.gloss:focus-visible {
  border-bottom-style: solid;
  background: var(--accent-soft);
  border-radius: 2px;
}
.gloss:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* La bulle des tuiles du simulateur partage l'aspect de celle du glossaire :
   deux bulles d'aide sur la même page qui ne se ressembleraient pas se liraient
   comme deux mécanismes différents. */
.gloss-bulle, .sim-bulle {
  position: absolute;
  z-index: 60;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 6px 24px rgba(0, 0, 0, .13);
  padding: .6rem .7rem;
  font-family: var(--sans, system-ui, sans-serif);
  font-size: .82rem;
  line-height: 1.45;
  color: var(--text);
}
.gloss-bulle[hidden], .sim-bulle[hidden] { display: none; }
/* Passerelle invisible par-dessus les six pixels qui séparent le terme de sa
   bulle : sans elle, le pointeur traverse une zone qui n'appartient à aucun des
   deux, et le survol se rompt avant d'avoir atteint « En savoir plus ». */
.gloss-bulle::before {
  content: ''; position: absolute; left: 0; right: 0; top: -8px; height: 8px;
}
.gloss-bulle.au-dessus::before { top: auto; bottom: -8px; }
.gloss-terme { display: block; color: var(--accent); margin-bottom: .2rem; }
.gloss-def   { display: block; color: var(--text); }
.gloss-lien  { display: inline-block; margin-top: .4rem; font-size: .78rem; }

/* Index alphabétique de glossaire.html */
.gloss-index { display: grid; gap: .5rem; margin: 1rem 0 2rem; }
.gloss-entree {
  border-left: 3px solid var(--accent-line);
  background: var(--bg-inset);
  border-radius: 0 6px 6px 0;
  padding: .55rem .8rem;
}
.gloss-entree dt { font-weight: 700; color: var(--text); }
.gloss-entree dd { margin: .15rem 0 0; color: var(--text-muted); }
.gloss-lettre {
  font-family: var(--sans, system-ui, sans-serif);
  font-size: .78rem; font-weight: 700; letter-spacing: .08em;
  color: var(--text-faint); text-transform: uppercase;
  margin: 1.4rem 0 .3rem;
}

@media print {
  .gloss { border-bottom: none; }
  .gloss-bulle, .sim-bulle { display: none !important; }
}

/* ============================================================================
   Boîte de spécification du simulateur — dépliable à la demande.
   ========================================================================= */

.spec-box {
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--bg-inset);
  margin: 1.2rem 0 1.6rem;
  max-width: 100%;
}
.spec-box > summary {
  cursor: pointer;
  padding: .8rem 1rem;
  font-family: var(--sans, system-ui, sans-serif);
  font-size: .88rem;
  line-height: 1.45;
  color: var(--text);
  border-radius: 10px;
}
.spec-box > summary:hover { background: var(--accent-soft); }
.spec-box > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.spec-box[open] > summary {
  border-bottom: 1px solid var(--border);
  border-radius: 10px 10px 0 0;
}
.spec-body { padding: .4rem 1rem 1.1rem; }
.spec-body h3 {
  font-family: var(--sans, system-ui, sans-serif);
  font-size: .9rem;
  letter-spacing: .01em;
  margin: 1.5rem 0 .5rem;
  color: var(--accent);
}
.spec-body h3:first-of-type { margin-top: .8rem; }
.spec-body table { font-size: .82rem; }
.spec-body ol { padding-left: 1.2rem; }
.spec-body ol li { margin-bottom: .35rem; }

@media print {
  .spec-box > summary { display: none; }
  .spec-body { padding: 0; }
}

/* Ligne de rappel entre une étiquette écartée et le bout de sa courbe. */
.fig-rappel { stroke-width: 1; opacity: .55; fill: none; }

/* -----------------------------------------------------------------------------
 * Rail chronologique.
 *
 * Le chapitre 1 mêlait des sections datées (« 1908 : Haldane… ») et des sections
 * sans date. Un lecteur en concluait que l'équation de Schreiner était
 * contemporaine de Haldane — elle est de 1971. Or l'ordre du chapitre est
 * thématique et non chronologique : la section Schreiner s'ouvre sur « l'équation
 * ci-dessus », et doit rester où elle est.
 *
 * On distingue donc deux natures, au lieu de forcer une chronologie fausse :
 *   · un JALON porte son millésime dans la marge — 1908, 1965, 1983, 1990,
 *     dans l'ordre, ce qui forme une vraie ligne du temps ;
 *   · un ROUAGE porte un simple point creux : c'est une explication, pas une
 *     étape de l'histoire.
 * Le trait qui les relie court d'un titre à l'autre.
 * -------------------------------------------------------------------------- */
/* La gouttière est creusée pour toute la colonne, et non pour les seuls
   titres : sinon le trait traverse les paragraphes et le bord gauche du texte
   devient irrégulier. */
[data-chrono] .wrap { padding-left: 4.6rem; }
[data-chrono] h2[data-annee], [data-chrono] h2[data-rouage] { position: relative; }
/* le trait, tracé vers le haut depuis chaque repère : bout à bout, il forme
   une ligne continue sans exiger de conteneur autour du chapitre */
.main h2[data-annee]::after, .main h2[data-rouage]::after {
  content: ''; position: absolute; left: -1.05rem; width: 1px;
  top: -100vh; height: 100vh;
  background: var(--border-soft);
}
.main h2:first-of-type::after { display: none; }

/* La pastille est calée par son bord DROIT, pas par sa largeur : un millésime
   simple garde la largeur commune, une mention de durée (« dès 1908 ») s'étend
   vers la gauche sans désaligner la colonne. */
.main h2[data-annee]::before {
  content: attr(data-annee);
  position: absolute; right: 100%; margin-right: 1.45rem; top: .34em;
  font-family: var(--font-sans); font-size: .7rem; font-weight: 700;
  letter-spacing: .04em;
  color: var(--bg); background: var(--accent);
  padding: .15rem .4rem; border-radius: 3px;
  min-width: 3.15rem; text-align: center; box-sizing: border-box;
  white-space: nowrap;
}
.main h2[data-rouage]::before {
  content: ''; position: absolute; left: -1.4rem; top: .78em;
  width: .48rem; height: .48rem; border-radius: 50%;
  background: var(--bg); border: 1px solid var(--border);
}

/* Sur mobile la marge n'existe pas : le millésime revient dans le fil. */
@media (max-width: 860px) {
  [data-chrono] .wrap { padding-left: 0; }
  .main h2[data-annee]::after, .main h2[data-rouage]::after,
  .main h2[data-rouage]::before { display: none; }
  .main h2[data-annee]::before {
    position: static; display: inline-block; margin-right: .5rem;
    vertical-align: .18em; width: auto;
  }
}

/* -----------------------------------------------------------------------------
 * Écrans d'ordinateurs redessinés (voir assets/ecrans.js).
 * Schémas, pas captures : l'aspect est délibérément celui du site, non celui
 * d'un appareil — un rendu trop réaliste laisserait croire à une reproduction.
 * -------------------------------------------------------------------------- */
.ecran { width: 100%; max-width: 300px; height: auto; display: block; margin: 0 auto .8rem; }
.ecran-boitier { fill: var(--bg-soft); stroke: var(--border); stroke-width: 1; }
.ecran-verre   { fill: var(--bg-panel); stroke: var(--border-soft); stroke-width: 1; }
.ecran-alerte .ecran-boitier { stroke: var(--danger); }
.ecran-mode { font-family: var(--font-sans); font-size: 9px; font-weight: 700;
              letter-spacing: .09em; fill: var(--text-faint); }
.ecran-alerte .ecran-mode { fill: var(--danger); }
.ecran-valeur-xl { font-family: var(--font-mono); font-size: 34px; font-weight: 700; fill: var(--text); }
.ecran-valeur    { font-family: var(--font-mono); font-size: 16px; font-weight: 700; fill: var(--text); }
.ecran-valeur.alerte { fill: var(--danger); }
.ecran-unite     { font-family: var(--font-sans); font-size: 9px; fill: var(--text-muted); }
.ecran-libelle   { font-family: var(--font-sans); font-size: 8px; letter-spacing: .05em;
                   text-transform: uppercase; fill: var(--text-faint); }
.ecran-renvoi    { fill: var(--accent); }
.ecran-renvoi-n  { font-family: var(--font-sans); font-size: 9px; font-weight: 700; fill: var(--bg-panel); }

.ecran-legende { margin: .2rem 0 .6rem 1.1rem; padding: 0; font-size: .78rem;
                 color: var(--text-muted); line-height: 1.5; }
.ecran-legende li { margin-bottom: .22rem; }
.ecran-legende strong { color: var(--text); }

/* Rendu fidèle (Suunto EON Core) — couleurs relevées sur l'affichage réel. */
.eon { width: 100%; max-width: 320px; height: auto; display: block; margin: 0 auto .8rem;
       border-radius: 9px; }
.eon text { font-family: var(--font-sans); }
.eon-lab   { font-size: 13px; fill: #9aa7ad; }
.eon-xl    { font-size: 54px; font-weight: 300; fill: #fff; letter-spacing: -1px; }
.eon-md    { font-size: 30px; font-weight: 300; fill: #fff; }
.eon-vert  { fill: #92c83e; }
.eon-orange{ fill: #ff9944; }
.eon-teal  { fill: #4cc4cf; }
.eon-batt  { font-size: 11px; fill: #9aa7ad; }
.eon-temp  { font-size: 15px; fill: #fff; }
.eon-cap   { font-size: 22px; fill: #4cc4cf; }
.eon-rose  { font-size: 10px; fill: #4cc4cf; }
.eon-badge { font-size: 11px; font-weight: 700; fill: #1a1200; letter-spacing: .06em; }
.eon-deepstop-v { font-size: 13px; fill: #fff; }
.eon-deepstop-l { font-size: 11px; fill: #9aa7ad; letter-spacing: .06em; }

/* --- Inventaire des écrans (page d'évaluation interne) --------------------- */
.inv-barre { margin: 1.2rem 0 1.6rem; }
.inv-filtres { display: flex; flex-wrap: wrap; gap: .35rem; align-items: center; margin-bottom: .5rem; }
.inv-lab { font-family: var(--font-sans); font-size: .74rem; font-weight: 700;
           letter-spacing: .06em; text-transform: uppercase; color: var(--text-faint);
           margin-right: .3rem; }
.inv-btn { font-family: var(--font-sans); font-size: .78rem; padding: .28rem .6rem;
           border: 1px solid var(--border); border-radius: 4px; background: var(--bg-panel);
           color: var(--text-muted); cursor: pointer; }
.inv-btn:hover { border-color: var(--accent-line); color: var(--text); }
.inv-btn[aria-pressed="true"] { background: var(--accent); border-color: var(--accent);
                                color: var(--bg-panel); font-weight: 700; }
.inv-modele { border: 1px solid var(--border-soft); border-radius: var(--radius);
              margin-bottom: .7rem; background: var(--bg-panel); }
.inv-modele > summary { padding: .55rem .8rem; cursor: pointer; font-size: .9rem; }
.inv-meta { font-family: var(--font-sans); font-size: .76rem; color: var(--text-faint); }
.inv-grille { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
              gap: .7rem; padding: .3rem .8rem .9rem; }
.inv-vig { margin: 0; }
.inv-vig img { width: 100%; height: auto; display: block; border: 1px solid var(--border);
               border-radius: 4px; background: #000; image-rendering: pixelated; }
.inv-vig figcaption { font-family: var(--font-sans); font-size: .7rem; color: var(--text-faint);
                      margin-top: .25rem; display: flex; flex-wrap: wrap; gap: .25rem; align-items: center; }
.inv-tag { border: 1px solid var(--accent-line); color: var(--accent); border-radius: 3px;
           padding: 0 .3rem; font-size: .65rem; letter-spacing: .03em; }
.inv-douteux img { opacity: .45; }
.inv-tag.inv-warn { border-color: var(--warn); color: var(--warn); }

/* LCD à segments (Mares Quad et apparentés) — pas de couleur, la hiérarchie
   vient de la place dans la grille. */
.lcd { width: 100%; max-width: 340px; height: auto; display: block; margin: 0 auto .8rem;
       border-radius: 6px; }
.lcd-fond  { fill: #cfd6cd; stroke: #9aa39a; }
.lcd-trait { stroke: #9aa39a; stroke-width: 1.2; }
.lcd text  { font-family: var(--font-mono); fill: #161a16; }
.seg       { fill: #161a16; }
.seg-off   { fill: #c2c9c0; }        /* segment éteint : visible, c'est la trame */
.lcd-lab   { font-family: var(--font-sans); font-size: 11px; font-weight: 700;
             letter-spacing: .08em; fill: #161a16; }
.lcd-u     { font-family: var(--font-sans); font-size: 11px; fill: #3d443d; }
/* Sélecteur descendant obligatoire : `.lcd text` (0,1,1) bat `.lcd-off` (0,1,0),
   et les libellés éteints s'affichaient allumés. Troisième occurrence du même
   piège de spécificité dans ce projet — après les courbes des figures et les
   couleurs de l'EON Core. */
.lcd .lcd-off { font-family: var(--font-sans); font-size: 11px; font-weight: 700;
                letter-spacing: .08em; fill: #b3bbb2; }
/* Les bandeaux gravés du Quad 2 portent jusqu'à cinq libellés sur une rangée :
   il leur faut leur propre taille. Classe de TAILLE seulement, posée à côté de
   .lcd-lab ou .lcd-off — elle ne touche pas au remplissage, donc elle ne peut
   pas rallumer un libellé éteint. */
.lcd .lcd-mini { font-size: 8.5px; letter-spacing: .04em; }

/* Mares M2 : le boîtier fait partie de l'écran. Sa barre de menu gravée — dive,
   surf, set, time, plan, sim, log, pc — est ce qu'un moniteur reconnaît avant
   d'avoir lu un chiffre, et elle n'existe sur aucun autre modèle du fonds. */
.m2-boitier { fill: #7c8079; stroke: #5c6058; }
.m2 .m2-menu { font-family: var(--font-sans); font-size: 9.5px; fill: #edefe9;
               letter-spacing: .02em; }

/* Scubapro Luna 2.0 — le premier écran NÉGATIF du fonds : segments et points
   clairs sur fond noir, quand les neuf vitres précédentes sont toutes
   positives. Couleurs échantillonnées sur la notice, pas choisies : fond
   #000000 (bruit JPEG jusqu'à #030303), segment allumé #ededed, point de
   matrice #e3e3e3, grille interpoints dans un bloc inversé #989898…#b6b6b6.

   POURQUOI C'EST ICI ET PAS DANS LE FICHIER DU MODÈLE. `segments()` et
   `digit()` ne posent que `class:` sur leurs polygones, jamais `style` : un
   modèle ne peut donc pas repeindre ses propres chiffres, et le contournement
   habituel du style en ligne n'existe pas.

   ET POURQUOI CE BLOC EST ÉCRIT APRÈS CELUI DE .lcd — quatrième occurrence du
   même piège. `.lcd text` et `.luna text` sont à spécificité ÉGALE (0,1,1),
   comme `.lcd .lcd-off` et `.luna .lcd-off` (0,2,0) : à égalité, c'est l'ordre
   source qui tranche. Une vitre qui porte les deux classes pour réutiliser les
   libellés gravés verrait, si ce bloc passait avant, ses libellés repeints en
   sombre sur fond noir — donc disparaître. Défaut invisible dans le code,
   visible au seul rendu, exactement comme les libellés éteints du Quad
   affichés allumés. Ne pas remonter ce bloc. */
.luna { width: 100%; max-width: 340px; height: auto; display: block;
        margin: 0 auto .8rem; border-radius: 6px; }
.luna-fond { fill: #000000; stroke: #2a2a2a; }
.luna .seg { fill: #ededed; }
.luna .seg-off { fill: #0b0b0b; }
.luna .mat { fill: #e3e3e3; }
.luna .mat-off { fill: #101010; }
/* Le pavé de vidéo inverse, et les points DEDANS : allumé = sombre. C'est lui
   qui groupe « DECO 5m 1: » et laisse « TAT 12: » dehors — sur cet écran, rien
   d'autre ne sépare ces trois nombres. */
.luna .inv-bloc { fill: #e3e3e3; }
.luna .mat-inv { fill: #000000; }
.luna .mat-inv-off { fill: #b6b6b6; }
.luna text, .luna .lcd-lab, .luna .lcd-off { fill: #ededed; }
