/* ============================================================================
   BTS CIEL — design system « Crème & Douceur »
   Vanilla, zéro dépendance. Chaque fiche déclare sa matière via
   <body data-matiere="reseau"> pour hériter de son accent chromatique.
   ========================================================================= */

:root {
  /* Surfaces */
  --papier:        #FDF5E6;   /* fond de page — jamais de blanc pur */
  --carte:         #FFFFFF;
  --carte-creuse:  #FBF6EE;
  --bord:          #E6DCCE;
  --bord-fort:     #D8CBB8;

  /* Texte */
  --encre:         #2F2F2F;
  --encre-douce:   #6B6257;
  --encre-tenue:   #8A8175;

  /* Accent par défaut (réseau) — surchargé par [data-matiere].
     --accent sert aux SURFACES (fonds, bordures, filets) ;
     --accent-sombre sert au TEXTE. Un accent clair posé en texte sur un
     fond clair tombait à 3:1 — mesuré, pas supposé. */
  --accent:        #005B96;
  --accent-pale:   #E8F1F8;
  --accent-sombre: #00426C;

  /* Texte renforcé et couleur posée SUR un fond d'accent.
     Elles étaient écrites en dur : un « color:#1F1F1F » devenait illisible
     dès qu'on passait le fond en sombre. */
  --encre-forte:  #1F1F1F;
  --sur-accent:   #FFFFFF;

  /* Sémantique */
  --vert:   #2D5A27;  --vert-pale:   #EAF2E8;  --vert-bord:  #D3E2CE;
  --ambre:  #B8860B;  --ambre-pale:  #FBF2DC;  --ambre-bord: #EBDCB4;
  --ambre-sombre: #7A5807;
  --corrige-fond: #FFF9E8;  --corrige-bord: #EBD9A8;
  --rouge:  #A32E2E;  --rouge-pale:  #FBEDEC;  --rouge-bord: #EFD2CF;
  --violet: #6A0DAD;  --violet-pale: #F3EBFA;  --violet-bord: #DFCDEF;

  /* Rythme */
  --r:   10px;
  --r-l: 16px;
  --ombre:      0 1px 2px rgba(60,45,25,.04), 0 4px 16px rgba(60,45,25,.05);
  --ombre-haut: 0 2px 6px rgba(60,45,25,.06), 0 12px 32px rgba(60,45,25,.07);

  --sans:  -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  /* La famille d'ACCENT d'un titre. Un seul mot change de famille et le
     titre entier change de ton — c'est le plus vieux procédé de la presse,
     et il ne coûte rien puisque la police est déjà sur la machine.
     Les neuf thèmes qui imposent leur propre police la ramènent sur
     « --sans » : un romain à empattements ne veut rien dire au milieu
     d'un terminal, et une police d'écriture n'a pas d'accent à donner. */
  --titre-accent: ui-serif, Georgia, "Iowan Old Style", "Times New Roman", serif;
  --mono:  ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Consolas, monospace;
}

[data-matiere="dev"]     { --accent:#2D5A27; --accent-pale:#EAF2E8; --accent-sombre:#1E3D1A; }
[data-matiere="reseau"]  { --accent:#005B96; --accent-pale:#E8F1F8; --accent-sombre:#00426C; }
[data-matiere="maths"]   { --accent:#8B0000; --accent-pale:#F8EBEB; --accent-sombre:#630000; }
[data-matiere="anglais"] { --accent:#C05621; --accent-pale:#FCEFE6; --accent-sombre:#8C3D14; }
[data-matiere="culture"] { --accent:#6A0DAD; --accent-pale:#F3EBFA; --accent-sombre:#4C097C; }
/* Pour ce pôle seulement, le violet sémantique est aussi la couleur d'accent :
   « méthode » (violet) et « boîte à outils » (accent) tombaient sur le même
   fond #F3EBFA, deux encarts distincts rendus identiques. On décale le violet
   sémantique vers l'indigo — l'accent de la matière reste inchangé. */
[data-matiere="culture"] { --violet:#2F4A7C; --violet-pale:#EBF0F8; --violet-bord:#CBD8EC; }
[data-matiere="projets"] { --accent:#B8860B; --accent-pale:#FBF2DC; --accent-sombre:#7A5807; }

/* ══════════════════ le changement de thème se FOND ════════════════════
   Quarante et un thèmes, et jusqu'ici passer de l'un à l'autre CLAQUAIT :
   toutes les couleurs changeaient dans la même image.

   Une variable CSS ordinaire n'est pas animable — le navigateur ne sait
   pas qu'elle contient une couleur, donc il ne sait pas interpoler entre
   deux. En la DÉCLARANT avec « @property » et « syntax: "<color>" », on
   le lui apprend, et la transition devient possible. C'est le seul moyen
   d'animer un thème sans dupliquer chaque règle qui s'en sert.

   VINGT-HUIT jetons, et pas un de plus. Trois critères, vérifiés sur les
   quatre feuilles avant d'écrire une ligne :

     · la valeur est TOUJOURS une couleur dans les 41 thèmes. « --ombre »
       est une liste d'ombres, « --mesure » une largeur, « --interligne »
       un nombre : les déclarer en « <color> » les ferait REJETER, et le
       thème repartirait en silence sur la valeur initiale ;
     · le jeton est TOUJOURS posé sur « :root ». En déclarer un qui ne
       l'est pas lui donnerait une valeur là où il n'en avait aucune, et
       ferait taire les replis « var(--x, défaut) » ;
     · aucun repli de ce genre ne s'appuie dessus — vérifié, il n'y en a
       pas sur ces vingt-huit.

   « --or », « --pierre », « --pierre-survol » et « --ressort » sont bien
   des couleurs, mais seuls quelques thèmes les posent : ils restent
   dehors, et c'est la deuxième règle qui les exclut.

   La valeur initiale est celle du thème clair. Elle n'est jamais
   observée, puisque « :root » pose les vingt-huit : c'est un filet, pas
   un réglage. */
@property --accent { syntax: "<color>"; inherits: true; initial-value: #005B96; }
@property --accent-pale { syntax: "<color>"; inherits: true; initial-value: #E8F1F8; }
@property --accent-sombre { syntax: "<color>"; inherits: true; initial-value: #00426C; }
@property --ambre { syntax: "<color>"; inherits: true; initial-value: #B8860B; }
@property --ambre-bord { syntax: "<color>"; inherits: true; initial-value: #EBDCB4; }
@property --ambre-pale { syntax: "<color>"; inherits: true; initial-value: #FBF2DC; }
@property --ambre-sombre { syntax: "<color>"; inherits: true; initial-value: #7A5807; }
@property --bord { syntax: "<color>"; inherits: true; initial-value: #E6DCCE; }
@property --bord-fort { syntax: "<color>"; inherits: true; initial-value: #D8CBB8; }
@property --carte { syntax: "<color>"; inherits: true; initial-value: #FFFFFF; }
@property --carte-creuse { syntax: "<color>"; inherits: true; initial-value: #FBF6EE; }
@property --corrige-bord { syntax: "<color>"; inherits: true; initial-value: #EBD9A8; }
@property --corrige-fond { syntax: "<color>"; inherits: true; initial-value: #FFF9E8; }
@property --encre { syntax: "<color>"; inherits: true; initial-value: #2F2F2F; }
@property --encre-douce { syntax: "<color>"; inherits: true; initial-value: #6B6257; }
@property --encre-forte { syntax: "<color>"; inherits: true; initial-value: #1F1F1F; }
@property --encre-tenue { syntax: "<color>"; inherits: true; initial-value: #8A8175; }
@property --papier { syntax: "<color>"; inherits: true; initial-value: #FDF5E6; }
@property --rouge { syntax: "<color>"; inherits: true; initial-value: #A32E2E; }
@property --rouge-bord { syntax: "<color>"; inherits: true; initial-value: #EFD2CF; }
@property --rouge-pale { syntax: "<color>"; inherits: true; initial-value: #FBEDEC; }
@property --sur-accent { syntax: "<color>"; inherits: true; initial-value: #FFFFFF; }
@property --vert { syntax: "<color>"; inherits: true; initial-value: #2D5A27; }
@property --vert-bord { syntax: "<color>"; inherits: true; initial-value: #D3E2CE; }
@property --vert-pale { syntax: "<color>"; inherits: true; initial-value: #EAF2E8; }
@property --violet { syntax: "<color>"; inherits: true; initial-value: #6A0DAD; }
@property --violet-bord { syntax: "<color>"; inherits: true; initial-value: #DFCDEF; }
@property --violet-pale { syntax: "<color>"; inherits: true; initial-value: #F3EBFA; }

:root { --fondu-duree: .32s; --fondu-courbe: ease; }

/* Le fondu ne s'arme qu'APRÈS le premier rendu. « data-fondu » est posé
   par app.js à la première image ; sans lui, la page s'ouvrirait en
   fondu DEPUIS les valeurs initiales — un éclair crème avant le thème
   choisi, c'est-à-dire exactement ce que l'ANTIFLASH existe pour
   empêcher.

   Et « data-anim="0" » l'éteint, pour deux raisons qui n'en font qu'une :
   celui qui coupe les animations ne veut pas non plus de celle-ci, et
   les deux bancs d'essai posent déjà ce réglage avant de mesurer. Sans
   cette clause, ils lisaient les couleurs EN PLEINE TRANSITION : 3 192
   éléments annoncés sous le seuil, tous au rapport 1,0 — le symptôme
   d'un fond et d'un texte relevés à deux instants différents du même
   fondu. L'instrument doit figer ce qu'il mesure. */
:root[data-fondu="1"]:not([data-anim="0"]) {
  transition:
    --accent var(--fondu-duree) var(--fondu-courbe),
    --accent-pale var(--fondu-duree) var(--fondu-courbe),
    --accent-sombre var(--fondu-duree) var(--fondu-courbe),
    --ambre var(--fondu-duree) var(--fondu-courbe),
    --ambre-bord var(--fondu-duree) var(--fondu-courbe),
    --ambre-pale var(--fondu-duree) var(--fondu-courbe),
    --ambre-sombre var(--fondu-duree) var(--fondu-courbe),
    --bord var(--fondu-duree) var(--fondu-courbe),
    --bord-fort var(--fondu-duree) var(--fondu-courbe),
    --carte var(--fondu-duree) var(--fondu-courbe),
    --carte-creuse var(--fondu-duree) var(--fondu-courbe),
    --corrige-bord var(--fondu-duree) var(--fondu-courbe),
    --corrige-fond var(--fondu-duree) var(--fondu-courbe),
    --encre var(--fondu-duree) var(--fondu-courbe),
    --encre-douce var(--fondu-duree) var(--fondu-courbe),
    --encre-forte var(--fondu-duree) var(--fondu-courbe),
    --encre-tenue var(--fondu-duree) var(--fondu-courbe),
    --papier var(--fondu-duree) var(--fondu-courbe),
    --rouge var(--fondu-duree) var(--fondu-courbe),
    --rouge-bord var(--fondu-duree) var(--fondu-courbe),
    --rouge-pale var(--fondu-duree) var(--fondu-courbe),
    --sur-accent var(--fondu-duree) var(--fondu-courbe),
    --vert var(--fondu-duree) var(--fondu-courbe),
    --vert-bord var(--fondu-duree) var(--fondu-courbe),
    --vert-pale var(--fondu-duree) var(--fondu-courbe),
    --violet var(--fondu-duree) var(--fondu-courbe),
    --violet-bord var(--fondu-duree) var(--fondu-courbe),
    --violet-pale var(--fondu-duree) var(--fondu-courbe);
}

/* Un fondu de couleurs reste un mouvement : qui en demande moins n'en
   reçoit aucun. */
@media (prefers-reduced-motion: reduce) {
  :root[data-fondu="1"]:not([data-anim="0"]) { transition: none; }
}

/* ------------------------------------------------------------------ base */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; scroll-padding-top: 1.5rem; -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: var(--sans);
  /* 1rem, et non 16.5px : sinon le réglage « Taille du texte », qui agit sur
     la racine, ne touchait que les rem — le texte des fiches, lui, ne
     bougeait pas d'un pixel. */
  font-size: 1rem;
  line-height: var(--interligne, 1.72);
  color: var(--encre);
  background: var(--papier);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4 { line-height: 1.22; letter-spacing: -.018em; margin: 0; font-weight: 700; }
p { margin: 0 0 1.05em; }
a { color: var(--accent-sombre); text-underline-offset: .18em; text-decoration-thickness: 1px; }
a:hover { color: var(--accent-sombre); }
strong { font-weight: 650; color: var(--encre-forte); }
img, svg, video { max-width: 100%; height: auto; }
:focus-visible { outline: 2.5px solid var(--accent); outline-offset: 3px; border-radius: 4px; }

/* --------------------------------------------------------------- charpente */
.page { display: grid; grid-template-columns: 268px minmax(0, 1fr); gap: 3rem;
        max-width: var(--large-page, 1220px); margin: 0 auto; padding: 0 2rem 6rem; }
.corps { min-width: 0; padding-top: 2.6rem; max-width: var(--mesure, 76ch); }

/* ---------------------------------------------------------------- sommaire */
.sommaire { position: sticky; top: 0; align-self: start; max-height: 100vh;
            overflow-y: auto; padding: 2.6rem 0 3rem; font-size: 0.8485rem; }
/* Le seul chemin de retour depuis une fiche : il doit s'attraper au pouce,
   donc au moins 36 px de haut. Mesuré, il en faisait 22. */
.sommaire .retour { display: inline-flex; align-items: center; gap: .45rem;
  color: var(--encre-douce); text-decoration: none; font-size: 0.7576rem; font-weight: 600;
  letter-spacing: .02em; margin-bottom: 1.3rem; padding: .45rem .55rem .45rem 0;
  min-height: 36px; box-sizing: border-box; }
.sommaire .retour:hover { color: var(--accent-sombre); }
.sommaire .retour::before { content: "\2190"; }
.sommaire h2 { font-size: 0.6364rem; text-transform: uppercase; letter-spacing: .13em;
  color: var(--encre-tenue); font-weight: 700; margin-bottom: .9rem; }
.sommaire ol { list-style: none; margin: 0; padding: 0; border-left: 2px solid var(--bord); }
.sommaire li { margin: 0; }
.sommaire li a { display: block; padding: .38rem 0 .38rem 1rem; margin-left: -2px;
  border-left: 2px solid transparent; color: var(--encre-douce);
  text-decoration: none; transition: color .15s, border-color .15s; }
.sommaire li a:hover { color: var(--encre); }
.sommaire li a.actif { color: var(--accent-sombre); border-left-color: var(--accent-sombre); font-weight: 600; }
.sommaire li.sous a { padding-left: 1.9rem; font-size: 0.8rem; }

/* ----------------------------------------------------------------- en-tête */
.fiche-tete { margin-bottom: 2.8rem; }
.fil { display: flex; flex-wrap: wrap; align-items: center; gap: .2rem .5rem;
  font-size: 0.697rem; font-weight: 650; letter-spacing: .05em; text-transform: uppercase;
  color: var(--encre-tenue); margin-bottom: 1.15rem; }
/* Le fil d'Ariane est de la navigation : au doigt, 22 px de haut se ratent.
   Un peu de remplissage vertical suffit à le rendre atteignable sans changer
   son allure. */
.fil a { color: inherit; text-decoration: none;
         display: inline-flex; align-items: center; min-height: 36px; padding: 0 .12rem; }
.fil a:hover { color: var(--accent-sombre); }
.fil .matiere { color: var(--accent-sombre); }
.fil .sep { color: var(--bord-fort); }
.badge { display: inline-block; background: var(--accent-pale); color: var(--accent-sombre);
  border-radius: 999px; padding: .22rem .7rem; font-size: 0.6364rem; letter-spacing: .07em; }

.fiche-tete h1 { font-size: clamp(2rem, 5.4vw, 3.05rem); font-weight: 780; letter-spacing: -.032em; }
.chapeau { font-size: 1.12rem; color: var(--encre-douce); margin-top: .85rem; max-width: 62ch; }

.flash { display: flex; gap: 1rem; background: var(--carte); border: 1px solid var(--bord);
  border-left: 4px solid var(--accent); border-radius: var(--r); padding: 1.15rem 1.35rem;
  margin: 2rem 0 1.2rem; box-shadow: var(--ombre); }
.flash .pastille { font-size: 1.15rem; line-height: 1.5; }
.flash h2 { font-size: 0.6364rem; text-transform: uppercase; letter-spacing: .12em;
  color: var(--accent-sombre); margin-bottom: .4rem; }
.flash p { margin: 0; font-size: 0.9394rem; }

.motscles { display: flex; flex-wrap: wrap; gap: .45rem; align-items: center;
  font-size: 0.7576rem; color: var(--encre-tenue); }
.motscles code { background: var(--carte); border: 1px solid var(--bord); border-radius: 6px;
  padding: .18rem .55rem; font-family: var(--mono); font-size: 0.7152rem; color: var(--encre-douce); }

/* ---------------------------------------------------------------- sections */
section { margin-top: 3.4rem; scroll-margin-top: 1.5rem; }
section > h2 { font-size: 1.62rem; font-weight: 740; padding-bottom: .55rem;
  border-bottom: 2px solid var(--bord); margin-bottom: 1.35rem; }
section > h2 .num { color: var(--accent-sombre); font-family: var(--mono); font-size: .78em;
  font-weight: 600; margin-right: .55rem; }
h3 { font-size: 1.16rem; font-weight: 690; margin: 2.1rem 0 .7rem; color: var(--accent-sombre); }
h4 { font-size: .98rem; font-weight: 680; margin: 1.5rem 0 .5rem; }

ul, ol { padding-left: 1.35rem; margin: 0 0 1.1em; }
li { margin-bottom: .42em; }
li::marker { color: var(--accent-sombre); }

/* ----------------------------------------------------------------- encarts */
.encart { border: 1px solid var(--bord); border-radius: var(--r); padding: 1.05rem 1.25rem;
  margin: 1.6rem 0; background: var(--carte); box-shadow: var(--ombre); font-size: 0.9333rem; }
.encart > :last-child { margin-bottom: 0; }
/* Surtout pas « display:flex » ici : un titre d'encart mêle du texte libre et
   parfois un <code>, et un conteneur flex en fait des éléments insécables — le
   titre ne peut plus se couper et pousse la page au-delà de 375 px. Flux inline
   normal, donc, qui revient à la ligne tout seul. */
.encart .titre { font-weight: 700;
  font-size: 0.7273rem; text-transform: uppercase; letter-spacing: .08em; margin-bottom: .6rem; }

.encart.analogie { background: var(--ambre-pale); border-color: var(--ambre-bord); }
.encart.analogie .titre { color: var(--ambre-sombre); }
.encart.outils   { background: var(--accent-pale); border-color: var(--bord); }
.encart.outils   .titre { color: var(--accent-sombre); }
.encart.piege    { background: var(--rouge-pale); border-color: var(--rouge-bord); }
.encart.piege    .titre { color: var(--rouge); }
.encart.savoir   { background: var(--vert-pale); border-color: var(--vert-bord); }
.encart.savoir   .titre { color: var(--vert); }
.encart.corrige  { background: var(--corrige-fond); border-color: var(--corrige-bord); border-left: 4px solid var(--ambre); }
.encart.corrige  .titre { color: var(--ambre-sombre); }
.encart.methode  { background: var(--violet-pale); border-color: var(--violet-bord); }
.encart.methode  .titre { color: var(--violet); }

/* La phrase de clôture d'un encart — le « à retenir » qui referme la
   démonstration. Un filet la détache du corps, un trait à gauche reprend
   l'accent du bloc. Employée 420 fois dans le dépôt, elle n'avait aucune
   règle : elle se rendait exactement comme un paragraphe ordinaire. */
.rap { margin-top: .95rem; padding: .62rem 0 0 .85rem;
  border-top: 1px solid var(--bord-fort); border-left: 3px solid var(--accent);
  font-size: 0.8848rem; }
/* Glose brève accolée à une valeur — « 126 (2⁷ − 2) ». Employée dans les
   tableaux, elle doit s'effacer devant le chiffre qu'elle explique. */
.sub { font-size: .86em; color: var(--encre-tenue); }

.encart.analogie .rap, .encart.corrige .rap { border-left-color: var(--ambre); }
.encart.piege    .rap { border-left-color: var(--rouge);  }
.encart.savoir   .rap { border-left-color: var(--vert);   }
.encart.methode  .rap { border-left-color: var(--violet); }

/* -------------------------------------------------------------------- quiz */
.quiz { border: 1px solid var(--bord); border-left: 4px solid var(--accent);
  border-radius: var(--r); background: var(--carte); padding: 1.05rem 1.25rem;
  margin: 1.6rem 0; box-shadow: var(--ombre); }
.quiz .titre { font-size: 0.7273rem; text-transform: uppercase; letter-spacing: .08em;
  font-weight: 700; color: var(--accent-sombre); margin-bottom: .55rem; }
.quiz .question { font-weight: 560; margin-bottom: .85rem; }
.quiz button { font: inherit; font-size: 0.8121rem; font-weight: 620; cursor: pointer;
  background: var(--accent); color: var(--sur-accent); border: 0; border-radius: 7px;
  padding: .48rem 1.05rem; transition: background .15s, transform .08s; }
.quiz button:hover { background: var(--accent-sombre); }
.quiz button:active { transform: translateY(1px); }
.quiz .reponse { margin-top: .95rem; padding-top: .95rem; border-top: 1px dashed var(--bord-fort);
  font-size: 0.9212rem; animation: apparait .22s ease; }
.quiz .reponse > :last-child { margin-bottom: 0; }
@keyframes apparait { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; } }

/* --------------------------------------------------------------- exercices */
.exo { background: var(--carte); border: 1px solid var(--bord); border-radius: var(--r-l);
  padding: 1.5rem 1.7rem; margin: 1.8rem 0; box-shadow: var(--ombre); }
/* Pas de flex : un titre d'exercice contient du texte libre et souvent un
   <code>, que le mode flex rend insécable — la ligne pousse alors la page
   hors de l'écran. Les deux pastilles s'alignent très bien en flux inline. */
.exo > h3 { margin-top: 0;
  color: var(--encre); font-size: 1.08rem; }
.exo > h3 .no { display: inline-block; margin-right: .55rem;
  font-family: var(--mono); font-size: .8em; font-weight: 700;
  color: var(--sur-accent); background: var(--accent); border-radius: 6px; padding: .1rem .45rem; }
.exo .enonce { font-size: 0.9333rem; }
.exo .quiz { margin-bottom: 0; background: var(--carte-creuse); }
.exo .tableau { background: var(--carte-creuse); }
.niveau { margin-left: .5rem; font-size: 0.6364rem; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  border-radius: 999px; padding: .16rem .6rem; }   /* « margin-left:auto » servait au flex, retiré avec lui */
.niveau.n1 { background: var(--vert-pale);  color: var(--vert); }
.niveau.n2 { background: var(--ambre-pale); color: var(--ambre-sombre); }
.niveau.n3 { background: var(--rouge-pale); color: var(--rouge); }
.rep-ok { color: var(--vert); font-weight: 650; }
.rep-non { color: var(--rouge); font-weight: 650; }

/* -------------------------------------------------------------------- code */
.bloc-code { position: relative; margin: 1.5rem 0; }
.bloc-code .langue { position: absolute; top: 0; left: 1rem; transform: translateY(-50%);
  background: var(--accent); color: var(--sur-accent); font-family: var(--mono); font-size: 0.6061rem;
  font-weight: 600; letter-spacing: .08em; text-transform: uppercase;
  padding: .16rem .55rem; border-radius: 5px; z-index: 2; }
.bloc-code .copier, .bloc-code .essayer { position: absolute; top: .55rem; right: .55rem; z-index: 2;
  font: inherit; font-size: 0.697rem; font-weight: 600; cursor: pointer;
  /* Fond OPAQUE, et c'est une mesure qui l'exige. En rgba(255,255,255,.09)
     le rendu était le même à l'œil — le bouton flotte au-dessus d'un <pre>
     sombre — mais un contrôle de contraste compose les fonds en remontant
     le DOM, pas la pile visuelle : le parent de ce bouton est .bloc-code,
     qui n'a pas de fond, donc la mesure aboutissait au papier du thème.
     Sur « Androïde (jour) », elle relevait 1,18:1. Le rendu ne change pas :
     #373532 est exactement rgba(255,255,255,.09) posé sur #23211E. Le texte
     y tient 6,91:1, et 8,97:1 au survol. */
  background: #373532; color: #C9C2B6; border: 1px solid #464542;
  border-radius: 6px; padding: .45rem .7rem; transition: all .15s;
  min-height: 34px; }   /* 30 px se rataient au doigt sur un bloc de code */
.bloc-code .copier:hover, .bloc-code .essayer:hover { background: #4B4946; color: #fff; }
.bloc-code .copier.fait { background: #2D5A27; border-color: #2D5A27; color: #fff; }
/* « Essayer » se range à gauche de « Copier », et PARTAGE ses règles au lieu
   de les recopier : deux commandes du même bloc n'ont aucune raison de se
   ressembler à moitié. Écrit d'abord en double, le bouton faisait 43 px de
   haut contre 37, pour un simple « display » différent. Ne restent ici que
   les deux écarts réels — le décalage de 4,9 rem est la largeur de
   « Copier » plus la gouttière. */
.bloc-code .essayer { right: 4.9rem; text-decoration: none; }

/* ── l'atelier par-dessus le cours ───────────────────────────────────────
   « ça m'amène à l'outil, du coup ça me sort du cours. » Un onglet neuf
   fait perdre sa place dans la page. L'atelier s'ouvre donc ici même, dans
   un <dialog> natif : le fond assombri, le piège à tabulation et la
   fermeture par Échap viennent du navigateur, pas d'un script.

   La fenêtre est GRANDE — un atelier de programmation a besoin de place, et
   une boîte de dialogue étriquée serait pire que l'onglet qu'elle remplace.
   Sur téléphone elle prend tout l'écran : il n'y a pas d'autre choix
   raisonnable à 375 px. */
.modale-atelier {
  width: min(1200px, 96vw); max-width: 96vw;
  height: min(92vh, 980px); max-height: 92vh;
  padding: 0; border: 1px solid var(--bord-fort); border-radius: var(--r);
  background: var(--carte); color: var(--encre);
  box-shadow: 0 24px 60px rgba(0,0,0,.34);
  overflow: hidden;
}
.modale-atelier::backdrop { background: rgba(18,16,14,.62); }
/* Le fond ne défile plus : sans cela la molette passe au travers et le
   cours glisse derrière pendant qu'on tape du code. */
html.modale-ouverte { overflow: hidden; }

.modale-atelier .modale-barre {
  display: flex; align-items: center; gap: .75rem;
  padding: .5rem .55rem .5rem .95rem;
  border-bottom: 1px solid var(--bord);
  background: var(--carte-creuse);
}
.modale-atelier .modale-titre {
  flex: 1; min-width: 0; font-size: .92rem; color: var(--encre);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.modale-atelier .modale-onglet {
  font-size: .76rem; color: var(--accent-sombre); text-decoration: none;
  border: 1px solid var(--bord-fort); border-radius: 6px;
  padding: .4rem .6rem; min-height: 34px; display: inline-flex;
  align-items: center; white-space: nowrap;
}
.modale-atelier .modale-onglet:hover { background: var(--accent-pale); }
/* 38 px : au-dessus du seuil de 34 que le banc mesure, et la croix est la
   commande qu'on vise le plus vite — elle doit pardonner un doigt pressé. */
.modale-atelier .modale-croix {
  flex: none; width: 38px; height: 38px; line-height: 1;
  font: inherit; font-size: 1.5rem; cursor: pointer;
  background: none; color: var(--encre-douce);
  border: 1px solid transparent; border-radius: 8px;
}
.modale-atelier .modale-croix:hover {
  background: var(--rouge-pale); color: var(--rouge); border-color: var(--rouge-bord);
}
/* Le cadre prend TOUT ce qui reste sous la barre. Écrit d'abord
   « height: calc(100% - 51px) », il rognait cinq pixels d'atelier : la
   barre en fait 56, et un nombre posé à la main se trompe dès que la
   police ou l'interligne du thème bouge. Une colonne flexible n'a pas
   ce défaut — elle mesure au lieu de deviner. */
.modale-atelier[open] { display: flex; flex-direction: column; }
.modale-atelier .modale-barre { flex: none; }
.modale-atelier .modale-cadre {
  flex: 1; min-height: 0; width: 100%;
  border: 0; background: var(--papier);
}

@media (max-width: 640px) {
  .modale-atelier {
    width: 100vw; max-width: 100vw; height: 100dvh; max-height: 100dvh;
    border-radius: 0; border: 0;
  }
  /* Le lien vers l'onglet disparaît : sur téléphone, l'écran entier est
     déjà pris, et un second contexte n'aide personne. */
  .modale-atelier .modale-onglet { display: none; }
}
pre { margin: 0; background: #23211E; color: #EDE7DC; border-radius: var(--r);
  padding: 1.15rem 1.25rem; overflow-x: auto; font-family: var(--mono);
  font-size: 0.8061rem; line-height: 1.66; }
pre code { font: inherit; color: inherit; background: none; padding: 0; border: 0; }

/* ------------------------------------------- coloration du code publié
   Demandé : colorer chaque élément et chaque attribut, comme le fait
   l'éditeur — c'est ce qui rend un bloc lisible d'un coup d'œil.

   Ces classes sont posées à la PUBLICATION par coloration.py : aucune
   bibliothèque, aucun script, rien à charger. La page arrive déjà colorée.

   Une seule palette suffit pour les quarante thèmes, et c'est une mesure qui
   le dit : dans toute la feuille, « pre » n'a que DEUX fonds — #23211E à
   l'écran, #F4F1EC à l'impression. Aucun thème ne les redéfinit. Les vingt
   couleurs ci-dessous ont donc été mesurées contre ces deux fonds-là :
   toutes passent le seuil AA, la plus juste à 4,78:1.

   Le commentaire est volontairement le plus terne — c'est sa fonction — mais
   pas en dessous du seuil : le premier gris essayé (#8C8578) tombait à
   4,39:1. */
.j-com { color: #948D80; font-style: italic; }
/* Sauf dans un bloc de calcul : les colonnes y sont alignées à l'espace près,
   et l'italique qu'un navigateur SYNTHÉTISE faute de monospace penché suffit
   à les faire glisser. La couleur reste, la pente part. */
.bloc-code[data-fam="calcul"] .j-com { font-style: normal; }
.j-mc  { color: #E58AC9; }
.j-typ { color: #6FC3DF; }
.j-txt { color: #C3E88D; }
.j-num { color: #F7A66B; }
.j-fn  { color: #82AAFF; }
.j-bal { color: #E5C07B; }
.j-att { color: #8FD4C1; }
.j-var { color: #F09E9E; }
/* Les opérateurs. Comptés sur les 90 blocs de C publiés, ils forment le plus
   gros trou de la coloration : 130 « = », 80 « < », 57 « > », 40 « ++ » — près
   de cinq cents signes sans couleur, au milieu d'un code qui en a partout
   ailleurs. Teinte choisie par mesure, pas à l'œil : 7,78:1 sur le #23211E des
   blocs de code, et la plus ÉLOIGNÉE de l'encre courante parmi cinq candidates
   — un opérateur doit se distinguer du texte sans crier plus fort qu'un
   mot-clé. Désaturée exprès, pour ne pas se confondre avec le bleu franc des
   appels de fonction. */
.j-op  { color: #A9B6C4; }
.j-pre { color: #C8A2E8; }
/* « overflow-wrap » ne coupe qu'en dernier recours — un mot qui ne tient pas
   seul sur sa ligne. Sans lui, un chemin comme
   « http://localhost/monprojet/index.php » n'offre aucune césure et pousse la
   page hors de l'écran à 375 px. */
:not(pre) > code { font-family: var(--mono); font-size: .885em; background: var(--carte-creuse);
  border: 1px solid var(--bord); border-radius: 5px; padding: .1em .38em; color: var(--accent-sombre);
  overflow-wrap: break-word; }

/* Le code ne se met JAMAIS en petites capitales, quel que soit son contexte.
   Titres d'encart, en-têtes de tableau et intertitres de fiche sont en
   majuscules : sans ce garde-fou, « adduser » s'affiche ADDUSER et
   « enable secret » ENABLE SECRET — des commandes qu'aucun terminal n'accepte.
   Une déclaration sur l'élément lui-même bat toujours un héritage : la règle
   couvre donc aussi les contextes en majuscules qui seront écrits plus tard. */
code, kbd, samp { text-transform: none; letter-spacing: normal; }

/* ------------------------------------------------- coloration syntaxique */
/* Palette chaude, lisible sur le fond #23211E des blocs de code.           */

/* ------------------------------------ démonstration : code | résultat */
.demo { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem;
  margin: 1.7rem 0; align-items: start; }
.demo > .bloc-code { margin: 0; min-width: 0; }
.demo .apercu { min-width: 0; }
.demo .apercu { border: 1px solid var(--bord); border-radius: var(--r);
  background: var(--carte); overflow: hidden; box-shadow: var(--ombre); }
.demo .apercu .etiquette { font-family: var(--mono); font-size: 0.6061rem; font-weight: 600;
  letter-spacing: .07em; text-transform: uppercase; color: var(--encre-tenue);
  background: var(--carte-creuse); border-bottom: 1px solid var(--bord);
  padding: .34rem .7rem; }
.demo .apercu iframe { display: block; width: 100%; border: 0; background: #fff; }

/* Certaines démonstrations ont besoin de toute la largeur pour dire quelque
   chose : une grille responsive tassée dans une colonne de 300 px ne montre
   qu'une seule colonne, c'est-à-dire exactement ce qu'on veut éviter.
   « .demo.large » empile alors le code au-dessus du résultat, pleine largeur. */
.demo.large { grid-template-columns: 1fr; }

@media (max-width: 900px) { .demo { grid-template-columns: 1fr; } }

/* ----------------------------------------------------------------- tableau */
.tableau { overflow-x: auto; margin: 1.6rem 0; border: 1px solid var(--bord);
  border-radius: var(--r); background: var(--carte); box-shadow: var(--ombre);
  -webkit-overflow-scrolling: touch; }
table { border-collapse: collapse; width: 100%; font-size: 0.8848rem; }
th, td { padding: .62rem .9rem; text-align: left; border-bottom: 1px solid var(--bord); }
th { background: var(--carte-creuse); font-size: 0.697rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .05em; color: var(--encre-douce);
  white-space: nowrap; }
tbody tr:last-child td { border-bottom: 0; }
tbody tr:hover { background: var(--carte-creuse); }
td code { white-space: nowrap; }
td .sub, th .sub { display: block; font-size: 0.697rem; color: var(--encre-tenue);
  font-weight: 400; text-transform: none; letter-spacing: 0; }

/* ------------------------------------------------------------------ schéma */
.schema { margin: 1.9rem 0; padding: 1.4rem; background: var(--carte);
  border: 1px solid var(--bord); border-radius: var(--r-l); box-shadow: var(--ombre);
  text-align: center; overflow-x: auto; }
.schema svg { display: block; margin: 0 auto; max-width: 100%; height: auto; }
.schema figcaption { margin-top: .9rem; font-size: 0.7879rem; color: var(--encre-tenue);
  font-style: italic; }

/* ------------------------------------------------------------------- récap */
.recap { margin-top: 4rem; background: var(--carte); border: 1px solid var(--bord);
  border-top: 4px solid var(--accent); border-radius: var(--r-l);
  padding: 1.7rem 1.9rem; box-shadow: var(--ombre-haut); }
.recap h2 { font-size: 1.15rem; margin-bottom: 1rem; }
.recap ul { list-style: none; padding: 0; }
.recap li { position: relative; padding-left: 1.6rem; margin-bottom: .6rem; }
.recap li::before { content: "\25B8"; position: absolute; left: .2rem; color: var(--accent-sombre);
  font-weight: 700; }
/* Un chapitre qui couvre deux séances a deux récapitulatifs. Plutôt qu'un seul
   bloc de vingt lignes où l'on ne retrouve rien, un intertitre par moitié — même
   graphie que le titre des sources, pour qu'il se lise comme une étiquette et
   non comme un titre de section. */
.recap-part { margin: 1.4rem 0 .7rem; font-size: 0.6364rem; text-transform: uppercase;
  letter-spacing: .12em; color: var(--encre-tenue); }
.recap-part:first-of-type { margin-top: 0; }

.sources { margin-top: 2rem; font-size: 0.7879rem; color: var(--encre-tenue); }
.sources h2 { font-size: 0.6364rem; text-transform: uppercase; letter-spacing: .12em;
  color: var(--encre-tenue); margin-bottom: .7rem; }
.sources ul { list-style: none; padding: 0; display: flex; flex-wrap: wrap; gap: .4rem; }
.sources li { background: var(--carte); border: 1px solid var(--bord); border-radius: 6px;
  padding: .2rem .6rem; font-family: var(--mono); font-size: 0.6909rem; margin: 0; }

/* ------------------------------------------ fiche de révision (imprimable) */
.page.revision { grid-template-columns: minmax(0, 1fr); max-width: var(--large-page, 1000px); }
.page.revision .corps { max-width: none; }
.grille { display: grid; grid-template-columns: repeat(auto-fit, minmax(290px, 1fr));
  gap: 1rem; margin: 1.4rem 0; }
.memo { background: var(--carte); border: 1px solid var(--bord); border-radius: var(--r);
  border-top: 3px solid var(--accent); padding: .95rem 1.1rem; box-shadow: var(--ombre);
  font-size: 0.8727rem; break-inside: avoid; }
.memo h2, .memo h3 { margin: 0 0 .55rem; font-size: 0.7273rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .07em; color: var(--accent-sombre);
  border: 0; padding: 0; }
.memo > :last-child { margin-bottom: 0; }
.memo ul, .memo ol { margin-bottom: 0; padding-left: 1.1rem; }
.memo li { margin-bottom: .28em; }
.memo table { font-size: 0.7879rem; }
.memo th, .memo td { padding: .34rem .5rem; }
.memo .tableau { margin: .5rem 0 0; box-shadow: none; }
.memo.large { grid-column: 1 / -1; }
.memo.cle, .memo.alerte { border-top-color: var(--rouge); }
.memo.cle h2, .memo.cle h3,
.memo.alerte h2, .memo.alerte h3 { color: var(--rouge); }
/* Une formule doit être lisible avant d'être jolie : son texte prend l'encre
   pleine, l'accent ne sert plus qu'au fond et au filet. Mesuré sur les 216
   combinaisons d'ambiance et d'accent, le texte à l'accent tombait à 3,9:1. */
.formule { font-family: var(--mono); font-size: 0.9091rem; font-weight: 600; text-align: center;
  background: var(--accent-pale); border-radius: 7px; padding: .55rem; margin: .55rem 0;
  border-left: 3px solid var(--accent); color: var(--encre); }
.section-revision { margin-top: 2.2rem; }
.section-revision > h2 { font-size: 1.28rem; }

/* ------------------------------------------------------------- responsive */
@media (max-width: 900px) {
  .page { grid-template-columns: 1fr; gap: 0; padding: 0 1.15rem 4rem; }
  .corps { padding-top: 1.6rem; }
  .sommaire { position: static; max-height: none; padding: 1.4rem 0 0; }
  .sommaire ol { display: none; }
  .sommaire.ouvert ol { display: block; }
  .sommaire h2 { cursor: pointer; display: flex; align-items: center; justify-content: space-between;
    background: var(--carte); border: 1px solid var(--bord); border-radius: var(--r);
    padding: .75rem 1rem; margin: 0 0 .7rem; font-size: 0.697rem; }
  .sommaire h2::after { content: "\25BE"; font-size: 0.7879rem; transition: transform .2s; }
  .sommaire.ouvert h2::after { transform: rotate(180deg); }
  body { font-size: 0.9697rem; }
}

/* ------------------------------------------------------------- impression */
@media print {
  :root { --papier: #fff; }
  body { font-size: 10.5pt; line-height: 1.45; }
  .page { display: block; max-width: none; padding: 0; }
  .sommaire, .bloc-code .copier, .bloc-code .essayer, .quiz button,
  .modale-atelier { display: none !important; }
  .quiz .reponse { display: block !important; }
  .encart, .quiz, .recap, .tableau, .schema { box-shadow: none; break-inside: avoid; }
  section > h2, h3 { break-after: avoid; }
  pre { background: #F4F1EC; color: #23211E; border: 1px solid #DDD; }
  /* Sur papier le fond s'inverse : la palette d'écran y passerait sous le
     seuil. Mêmes rôles, mêmes teintes, assombries pour le blanc. */
  .j-com { color: #6E6A62; }
  .j-mc  { color: #A3246E; }
  .j-typ { color: #0B6E86; }
  .j-txt { color: #2F6B1E; }
  .j-num { color: #9A4A00; }
  .j-fn  { color: #1D4FA8; }
  .j-bal { color: #7A5A00; }
  .j-att { color: #0D6B57; }
  .j-var { color: #A32020; }
  .j-op  { color: #4A5560; }
  .j-pre { color: #6B3FA0; }
  .demo { grid-template-columns: 1fr; }
  .demo .apercu { break-inside: avoid; }
  a { color: inherit; text-decoration: none; }
  .grille { grid-template-columns: 1fr 1fr; gap: .55rem; }
  .memo { padding: .55rem .7rem; font-size: 9pt; box-shadow: none; }
  .fiche-tete h1 { font-size: 20pt; }
  .chapeau, .motscles { display: none; }
  .section-revision { margin-top: 1rem; }
  @page { margin: 12mm; }
}

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

/* ============================================================================
   PORTAIL ET INDEX DE MATIÈRE
   ========================================================================= */

.portail-tete { padding: 1rem 0 2.6rem; border-bottom: 1px solid var(--bord); margin-bottom: 2.6rem; }
.portail-tete h1 { font-size: clamp(2.4rem, 7vw, 4.2rem); font-weight: 800; letter-spacing: -.04em; }
.portail-tete h1 span { color: var(--encre-tenue); font-weight: 300; letter-spacing: -.02em; }
.portail-tete .chapeau { max-width: 56ch; }

.compteurs { display: flex; flex-wrap: wrap; gap: 2.4rem; margin-top: 2rem; }
.compteurs div { display: flex; flex-direction: column; }
.compteurs strong { font-size: 2rem; font-weight: 780; line-height: 1; letter-spacing: -.03em; }
.compteurs span { font-size: 0.6667rem; text-transform: uppercase; letter-spacing: .09em;
  color: var(--encre-tenue); font-weight: 650; margin-top: .35rem; }

.grille-poles { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 1.1rem; }
.pole { display: block; text-decoration: none; color: inherit; background: var(--carte);
  border: 1px solid var(--bord); border-radius: var(--r-l); padding: 1.5rem 1.6rem;
  box-shadow: var(--ombre); position: relative; overflow: hidden;
  transition: transform .18s, box-shadow .18s, border-color .18s; }
.pole::before { content: ""; position: absolute; inset: 0 auto 0 0; width: 4px; background: var(--accent); }
.pole:hover { transform: translateY(-3px); box-shadow: var(--ombre-haut); border-color: var(--bord-fort); }
.pole-ic { font-family: var(--mono); font-size: 0.9091rem; font-weight: 700; color: var(--accent-sombre);
  background: var(--accent-pale); border-radius: 9px; width: 42px; height: 42px;
  display: flex; align-items: center; justify-content: center; margin-bottom: 1rem; }
.pole h2 { font-size: 1.18rem; font-weight: 720; margin-bottom: .45rem; }
.pole p { font-size: 0.8606rem; color: var(--encre-douce); margin-bottom: 1.1rem; }

.jauge { margin-top: 1.4rem; }
.jauge-barre { height: 5px; background: var(--carte-creuse); border: 1px solid var(--bord);
  border-radius: 999px; overflow: hidden; }
.jauge-barre span { display: block; height: 100%; background: var(--accent); border-radius: 999px;
  transition: width .4s ease; }
.jauge-txt { margin-top: .5rem; font-size: 0.697rem; font-weight: 620; letter-spacing: .04em;
  text-transform: uppercase; color: var(--encre-tenue); }

.portail-pied { margin-top: 3.4rem; padding-top: 1.6rem; border-top: 1px solid var(--bord);
  font-size: 0.8485rem; color: var(--encre-douce); }
.pied-liens { font-size: 0.7576rem; color: var(--encre-tenue); }

/* ---------------------------------------------------- liste des chapitres */
.liste-chap { display: flex; flex-direction: column; gap: .55rem; }

/* Marque un chapitre de 2e année dans la liste d'un pôle. Les deux années
   cohabitent dans le même index : l'épreuve E4 porte sur les deux, et un
   chapitre de 1re année reste une révision utile. */
/* Chapitre « bonus » : un complément procuré en dehors de la formation
   (CNED), et non un cours donné en classe. Listé, mais hors décompte. */
.bonus { display: inline-block; margin-left: .45rem; padding: .08rem .42rem;
  border: 1px dashed var(--bord-fort); border-radius: 999px;
  background: var(--carte-creuse); color: var(--encre-tenue);
  font-size: 0.5818rem; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; vertical-align: .12em; }

/* « systeme de numeration n'est pas au progrmme donc met un petit tag en
   rouge clair qui dit que ça n'est pas dans le programme ».

   Distinct de « bonus », qui est gris : un chapitre bonus est un complément
   qu'il est allé chercher lui-même ; celui-ci a bien été ENSEIGNÉ, il n'est
   simplement pas au programme de l'épreuve. Deux situations, deux étiquettes.

   Le rouge vient des jetons du site — --rouge, --rouge-pale, --rouge-bord —
   et non d'une couleur écrite en dur : ce sont les mêmes que les encarts
   « piège » et les mauvaises réponses de QCM, donc déjà déclinés sur les
   41 thèmes et déjà mesurés par le banc de contraste.

   Il reste COMPTÉ dans l'avancement, contrairement à « bonus » : le chapitre
   est écrit, et il sert de révision. C'est l'épreuve qui l'ignore, pas lui. */
.hors-prog { display: inline-block; margin-left: .45rem; padding: .08rem .42rem;
  border: 1px solid var(--rouge-bord); border-radius: 999px;
  background: var(--rouge-pale); color: var(--rouge);
  font-size: 0.5818rem; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; vertical-align: .12em; white-space: nowrap; }

.an2 { display: inline-block; margin-left: .45rem; padding: .08rem .42rem;
  border: 1px solid var(--accent); border-radius: 999px; background: var(--accent-pale);
  color: var(--accent-sombre); font-size: 0.5818rem; font-weight: 700;
  letter-spacing: .06em; text-transform: uppercase; vertical-align: .12em; }
.chap { display: grid; grid-template-columns: 44px minmax(0, 1fr) auto;
  grid-template-areas: "num txt liens" "num src liens";
  align-items: center; gap: .2rem 1rem;
  background: var(--carte); border: 1px solid var(--bord); border-radius: var(--r);
  padding: .95rem 1.15rem; box-shadow: var(--ombre); transition: border-color .15s; }
.chap:hover { border-color: var(--bord-fort); }
.chap-num { grid-area: num; font-family: var(--mono); font-size: 0.9091rem; font-weight: 700;
  color: var(--accent-sombre); background: var(--accent-pale); border-radius: 8px;
  width: 38px; height: 38px; display: flex; align-items: center; justify-content: center; }
.chap-txt { grid-area: txt; }
.chap-txt h3 { margin: 0; font-size: 0.9394rem; font-weight: 660; color: var(--encre); }
.chap-txt p { margin: .1rem 0 0; font-size: 0.8rem; color: var(--encre-douce); }
.chap-src { grid-area: src; font-size: 0.6667rem; color: var(--encre-tenue);
  font-family: var(--mono); margin-top: .3rem; }
.chap-liens { grid-area: liens; display: flex; gap: .35rem; flex-wrap: wrap; }
.lien-fiche { font-size: 0.697rem; font-weight: 650; letter-spacing: .03em; border-radius: 6px;
  padding: .3rem .65rem; text-decoration: none; white-space: nowrap;
  background: var(--accent-pale); color: var(--accent-sombre);
  border: 1px solid transparent; transition: background .15s; }
.lien-fiche:hover { background: var(--accent); color: var(--sur-accent); }
.lien-fiche.vide { background: transparent; color: var(--encre-tenue);
  border: 1px dashed var(--bord-fort); cursor: default; }
.chap.attente { opacity: .72; }
.chap.pret .chap-num { background: var(--accent); color: var(--sur-accent); }

@media (max-width: 620px) {
  .chap { grid-template-columns: 38px minmax(0, 1fr);
          grid-template-areas: "num txt" "num src" "liens liens"; }
  .chap-liens { margin-top: .7rem; }
  .compteurs { gap: 1.4rem; }
}

/* ---------------------------------------------------------------------- QCM
   La quatrième fiche : on répond, on voit tout de suite si c'est juste, et on
   lit POURQUOI. Un QCM qui dit seulement « faux » n'apprend rien.
   Les couples de couleurs sont ceux des encarts — vert sur vert pâle, rouge
   sur rouge pâle — dont le contraste est déjà mesuré sur les quarante thèmes. */
.qcm { max-width: 62ch; margin: 0 auto; }
.qcm-q { background: var(--carte); border: 1px solid var(--bord);
  border-left: 3px solid var(--accent); border-radius: var(--r);
  padding: 1.15rem 1.3rem 1.25rem; margin: 1.1rem 0; box-shadow: var(--ombre);
  break-inside: avoid; }
.qcm-q > p { margin: 0 0 .9rem; font-size: 1.0303rem; font-weight: 650;
  color: var(--encre); line-height: 1.5; }
.qcm-n { display: inline-grid; place-items: center; width: 24px; height: 24px;
  margin-right: .5rem; vertical-align: 1px; border-radius: 999px;
  background: var(--accent-pale); color: var(--accent-sombre);
  font-family: var(--mono); font-size: 0.6667rem; font-weight: 700; }
.qcm-opts { display: grid; gap: .45rem; }
.qcm-opt { display: flex; align-items: flex-start; gap: .6rem; width: 100%;
  text-align: left; cursor: pointer; font: inherit; font-size: 0.9394rem;
  line-height: 1.5; color: var(--encre); background: var(--carte-creuse);
  border: 1px solid var(--bord-fort); border-radius: var(--r);
  padding: .6rem .8rem; min-height: 40px;
  transition: border-color .14s, background .14s, transform .1s var(--ease); }
.qcm-opt:hover:not(:disabled) { border-color: var(--accent); }
.qcm-opt:active:not(:disabled) { transform: scale(.995); }
.qcm-opt:disabled { cursor: default; }
.qcm-lt { flex: none; width: 20px; height: 20px; margin-top: .1rem;
  display: grid; place-items: center; border-radius: 5px;
  background: var(--carte); border: 1px solid var(--bord-fort);
  font-family: var(--mono); font-size: 0.6667rem; font-weight: 700;
  color: var(--encre-douce); }
.qcm-opt.bon  { background: var(--vert-pale);  border-color: var(--vert);  color: var(--vert); }
.qcm-opt.faux { background: var(--rouge-pale); border-color: var(--rouge); color: var(--rouge); }
.qcm-opt.bon .qcm-lt  { background: var(--vert);  border-color: var(--vert);  color: #FFFFFF; }
.qcm-opt.faux .qcm-lt { background: var(--rouge); border-color: var(--rouge); color: #FFFFFF; }
.qcm-opt.pale { opacity: .55; }
.qcm-why { margin: .8rem 0 0; padding: .7rem .85rem; border-radius: var(--r);
  background: var(--accent-pale); border-left: 3px solid var(--accent);
  font-size: 0.8788rem; line-height: 1.6; color: var(--encre); }
.qcm-why[hidden] { display: none; }
.qcm-why b { color: var(--accent-sombre); }

.qcm-tete { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem 1rem;
  margin: 1.6rem 0 .4rem; padding: .75rem 1rem; border-radius: var(--r);
  background: var(--carte-creuse); border: 1px solid var(--bord); }
.qcm-tete .av { flex: 1 1 10rem; height: 8px; border-radius: 999px;
  background: var(--carte); border: 1px solid var(--bord-fort); overflow: hidden; }
.qcm-tete .av span { display: block; height: 100%; width: 0;
  background: var(--accent); transition: width .28s var(--ease); }
.qcm-tete .sc { font-family: var(--mono); font-size: 0.8788rem; font-weight: 700;
  color: var(--encre); white-space: nowrap; }

.qcm-fin { margin-top: 1.6rem; padding: 1.3rem 1.4rem; border-radius: var(--r-l);
  background: var(--carte); border: 1px solid var(--bord);
  border-top: 3px solid var(--accent); box-shadow: var(--ombre); text-align: center; }
.qcm-fin[hidden] { display: none; }
.qcm-fin h2 { margin: 0 0 .3rem; font-size: 1.12rem; color: var(--encre); }
.qcm-fin .gros { font-family: var(--mono); font-size: 2.1rem; font-weight: 800;
  line-height: 1.1; color: var(--accent-sombre); }
.qcm-fin p { margin: .5rem 0 0; font-size: 0.9091rem; color: var(--encre-douce); }
.qcm-fin button { margin-top: 1rem; min-height: 40px; padding: .5rem 1.1rem;
  cursor: pointer; font: inherit; font-size: 0.8788rem; font-weight: 650;
  background: var(--accent); color: var(--sur-accent);
  border: 1px solid var(--accent); border-radius: var(--r); }
.qcm-fin button:hover { opacity: .88; }

@media print {
  .qcm-tete, .qcm-fin, .qcm-opt:disabled { display: none !important; }
  .qcm-why { display: block !important; }
}
/* Le QCM se distingue des trois fiches de cours : c'est un contrôle, pas une
   lecture. Un filet suffit — la couleur d'accent reste celle de la matière. */
.lien-fiche.qcm { background: transparent; color: var(--accent-sombre);
  border: 1px solid var(--accent); }
.lien-fiche.qcm:hover { background: var(--accent); color: var(--sur-accent); }

/* ═══════════════════════════════ le choix du système ═══════════════════
   Demandé sur le chapitre Docker : un tutoriel complet en tête de page,
   avec trois boutons pour choisir la configuration — Mac, Windows ou
   Linux.

   Trois raisons de le faire SANS JavaScript, avec des boutons radio :

     · une fiche doit s'ouvrir hors ligne et sans script — c'est la règle du
       dépôt, et un tutoriel d'installation est précisément ce qu'on lit sur
       un téléphone pendant que l'ordinateur télécharge ;
     · le clavier fonctionne tout seul : les flèches passent d'un système à
       l'autre, parce que ce sont de vrais boutons radio d'un même groupe ;
     · à l'impression, les quatre volets s'ouvrent d'un coup : sur papier,
       la barre d'onglets ne sert plus à rien et cacher trois systèmes sur
       quatre serait une perte sèche.

   Les entrées ne sont pas « display:none » mais rendues transparentes et
   sorties du flux : masquées pour de bon, elles ne seraient plus focusables,
   et le composant deviendrait inatteignable au clavier. */
.choix-os { margin: 1.4rem 0; }
.choix-os > input {
  position: absolute;
  width: 1px; height: 1px;
  opacity: 0;
  pointer-events: none;
}
.choix-os-barre {
  display: flex;
  flex-wrap: wrap;                  /* quatre systèmes à 320 px : on passe à la ligne */
  gap: .4rem;
  margin-bottom: -1px;
}
.choix-os-barre label {
  padding: .55rem 1.1rem;
  min-height: 34px;                 /* le plancher de cible tactile du banc */
  border: 1px solid var(--bord);
  border-radius: 10px 10px 0 0;
  background: var(--papier);
  color: var(--encre-douce);
  font-weight: 600;
  font-size: .95rem;
  cursor: pointer;
  user-select: none;
}
.choix-os-barre label:hover { color: var(--encre); }
.choix-os .volet {
  display: none;
  padding: 1.1rem 1.2rem .4rem;
  border: 1px solid var(--bord);
  border-radius: 0 10px 10px 10px;
  background: var(--carte);
}
/* Le volet affiché suit la valeur cochée — par la valeur, jamais par un
   identifiant : le composant doit pouvoir resservir ailleurs. */
.choix-os > input[value="mac"]:checked    ~ .volet[data-os="mac"],
.choix-os > input[value="windows"]:checked ~ .volet[data-os="windows"],
.choix-os > input[value="linux"]:checked  ~ .volet[data-os="linux"],
.choix-os > input[value="autre"]:checked  ~ .volet[data-os="autre"] { display: block; }

/* L'onglet actif. Les quatre étiquettes sont dans l'ordre des quatre
   entrées : c'est ce qui permet de les désigner par leur rang. */
.choix-os > input[value="mac"]:checked     ~ .choix-os-barre label:nth-child(1),
.choix-os > input[value="windows"]:checked ~ .choix-os-barre label:nth-child(2),
.choix-os > input[value="linux"]:checked   ~ .choix-os-barre label:nth-child(3),
.choix-os > input[value="autre"]:checked   ~ .choix-os-barre label:nth-child(4) {
  background: var(--carte);
  color: var(--accent-sombre);      /* --accent est une couleur de surface */
  border-bottom-color: var(--carte);
}
/* Le focus clavier doit se voir sur l'ÉTIQUETTE, puisque l'entrée est
   invisible. Sans cette règle, on tabule dans le vide. */
.choix-os > input:focus-visible ~ .choix-os-barre label { outline: 2px solid var(--accent); }
@media print {
  .choix-os-barre { display: none; }
  .choix-os .volet { display: block; border-radius: 10px; }
}

/* ═══════════════════════════ l'appui sur un TP ═════════════════════════
   Demandé : que le cours se tienne seul. Renvoyer au TP ne suffit pas —
   quelqu'un qui n'a pas le TP sous la main doit pouvoir suivre quand
   même. Et la règle vaut pour tous les cours, pas pour un seul.

   Il a raison, et l'audit lui donne raison deux fois : douze cours sur
   cinquante-huit portaient des phrases du type « c'est la question 3.2 du
   TP », où le renvoi ne complétait pas l'explication — il la REMPLAÇAIT. Un
   lecteur sans le sujet lisait une référence à un document qu'il n'a pas, à
   l'endroit précis où il attendait la notion.

   La règle est donc posée, et elle vaut pour tout cours à venir :

     · un cours s'explique ENTIÈREMENT sans le TP. La notion, l'exemple et la
       conséquence sont dans le cours ;
     · un renvoi au TP est un BONUS, jamais un porteur de sens. Il se place
       APRÈS l'explication complète, et la page reste juste si on le masque ;
     · il porte cette classe, qui le donne à voir comme ce qu'il est — une
       note de marge pour qui a le sujet sous les yeux.

   Les exercices, eux, gardent leurs renvois : une page de correction PARLE
   du sujet, c'est son objet. La règle ne concerne que `cours.html`. */
.appui-tp {
  margin: .9rem 0 0;
  padding: .5rem .85rem;
  border-left: 3px solid var(--bord-fort);
  background: var(--carte-creuse);
  border-radius: 0 8px 8px 0;
  color: var(--encre-douce);
  font-size: 0.8667rem;
}
.appui-tp strong { color: var(--encre); }
.appui-tp::before {
  content: "Si vous avez le sujet";
  display: block;
  margin-bottom: .15rem;
  font-size: 0.7333rem; font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase;
  /* Pas --encre-tenue : mesurée entre 3,71 et 4,17:1 sur Midgar, et ce
     libellé fait 11,7 px. La règle de la section 10 s'applique telle quelle. */
  color: var(--encre-douce);
}
/* À l'impression d'une fiche de révision, la note de marge ne sert plus :
   on révise avec ce qu'on a sous la main, pas avec un sujet resté en cours. */
@media print { .appui-tp { display: none; } }

/* ═══════════════════════════════════════════════════════════════════════
   AMBIANCES — 24 thèmes
   Repris du projet Sakina et transposés sur les variables de ces fiches.
   Chaque thème ne redéfinit que les surfaces et le texte : les accents
   restent sémantiques (une couleur par matière), sauf si l'on en choisit
   un dans les réglages.
   ═══════════════════════════════════════════════════════════════════════ */
/* Le thème sombre de base. Dans Sakina il vivait dans « :root » ; ici les
   fiches sont claires par défaut, il lui faut donc son propre bloc. */
html[data-theme="dark"] {  /* Sombre */
  --papier: #0E1013;
  --carte: #16181C;
  --carte-creuse: #1C1F24;
  --bord: rgba(255,255,255,.10);
  --encre: #E9E6E1;
  --encre-douce: #A8A39B;
  --encre-tenue: #7C776F;
  --ambiance-sombre: 1;
}
html[data-theme="emerald"] {  /* Émeraude */
  --papier: #04120C;
  --carte: #0A1F15;
  --carte-creuse: #11291D;
  --bord: rgba(180,255,215,0.12);
  --encre: #EAF6EF;
  --encre-douce: #8FAF9D;
  --encre-tenue: #527060;
  --ambiance-sombre: 1;
}
html[data-theme="ocean"] {  /* Océan */
  --papier: #050B16;
  --carte: #0B1628;
  --carte-creuse: #122036;
  --bord: rgba(170,210,255,0.12);
  --encre: #EAF1F8;
  --encre-douce: #8FA5BD;
  --encre-tenue: #516580;
  --ambiance-sombre: 1;
}
html[data-theme="mocha"] {  /* Moka */
  --papier: #120C08;
  --carte: #1F1611;
  --carte-creuse: #2A1E17;
  --bord: rgba(255,220,190,0.12);
  --encre: #F6EEE7;
  --encre-douce: #B39C8A;
  --encre-tenue: #6E5B4C;
  --ambiance-sombre: 1;
}
html[data-theme="amoled"] {  /* AMOLED */
  --papier: #000000;
  --carte: #0A0A0A;
  --carte-creuse: #111111;
  --bord: rgba(255,255,255,0.08);
  --encre: #F5F5F5;
  --encre-douce: #9A9A9A;
  --encre-tenue: #525252;
  --ambiance-sombre: 1;
}
html[data-theme="nordic"] {  /* Nordique */
  --papier: #1B2430;
  --carte: #232D3B;
  --carte-creuse: #2C3849;
  --bord: rgba(180,210,240,0.10);
  --encre: #E7EDF5;
  --encre-douce: #95A3B8;
  --encre-tenue: #5C6A80;
  --ambiance-sombre: 1;
}
html[data-theme="rosewood"] {  /* Rosewood */
  --papier: #1A0B10;
  --carte: #25121A;
  --carte-creuse: #301923;
  --bord: rgba(255,190,210,0.12);
  --encre: #F7EBEF;
  --encre-douce: #B99AA4;
  --encre-tenue: #7A5D66;
  --ambiance-sombre: 1;
}
html[data-theme="starry"] {  /* Nuit étoilée */
  --papier: #060814;
  --carte: #0C1024;
  --carte-creuse: #131938;
  --bord: rgba(180,200,255,0.14);
  --encre: #EEF1FA;
  --encre-douce: #93A0C4;
  --encre-tenue: #5A6488;
  --ambiance-sombre: 1;
}
html[data-theme="sunset"] {  /* Coucher */
  --papier: #2A0F1E;
  --carte: #3B142B;
  --carte-creuse: #4A1B37;
  --bord: rgba(255,180,150,0.12);
  --encre: #FBE9E0;
  --encre-douce: #C99B94;
  --encre-tenue: #8A6A66;
  --ambiance-sombre: 1;
}
html[data-theme="aurora"] {  /* Aurore */
  --papier: #071018;
  --carte: #0D1B24;
  --carte-creuse: #122732;
  --bord: rgba(170,255,220,0.14);
  --encre: #E8F6F1;
  --encre-douce: #8FBFAE;
  --encre-tenue: #527F72;
  --ambiance-sombre: 1;
}
html[data-theme="midnight"] {  /* Minuit */
  --papier: #050716;
  --carte: #161826;
  --carte-creuse: #232431;
  --bord: rgba(255,255,255,0.10);
  --encre: #EBEBEC;
  --encre-douce: #8E8F96;
  --encre-tenue: #555660;
  --ambiance-sombre: 1;
}
html[data-theme="carbon"] {  /* Carbone */
  --papier: #14181D;
  --carte: #24282C;
  --carte-creuse: #303338;
  --bord: rgba(255,255,255,0.10);
  --encre: #ECECEC;
  --encre-douce: #959799;
  --encre-tenue: #5F6165;
  --ambiance-sombre: 1;
}
html[data-theme="light"] {  /* Clair */
  --papier: #F5F4F0;
  --carte: #FFFFFF;
  --carte-creuse: #EEECEA;
  --bord: rgba(0,0,0,0.09);
  --encre: #1A1814;
  --encre-douce: #6B6760;
  --encre-tenue: #ADA9A4;
  --ambiance-sombre: 0;
}
html[data-theme="sand"] {  /* Sable */
  --papier: #F3EBDD;
  --carte: #FCF7EC;
  --carte-creuse: #EDE3D0;
  --bord: rgba(90,60,20,0.12);
  --encre: #2B2013;
  --encre-douce: #7A6A52;
  --encre-tenue: #B3A48A;
  --ambiance-sombre: 0;
}
html[data-theme="cream"] {  /* Crème */
  --papier: #EBE1CD;
  --carte: #F7F0E0;
  --carte-creuse: #E3D7BE;
  --bord: rgba(80,55,15,0.14);
  --encre: #2E2413;
  --encre-douce: #75654A;
  --encre-tenue: #AC9C7E;
  --ambiance-sombre: 0;
}
html[data-theme="dawn"] {  /* Aube */
  --papier: #F7F0F2;
  --carte: #FFFAFB;
  --carte-creuse: #F1E4E8;
  --bord: rgba(120,40,70,0.10);
  --encre: #2A1A20;
  --encre-douce: #7E6570;
  --encre-tenue: #B7A0AA;
  --ambiance-sombre: 0;
}
html[data-theme="sakura"] {  /* Sakura */
  --papier: #FFF0F3;
  --carte: #FFFFFF;
  --carte-creuse: #FCE4EA;
  --bord: rgba(190,90,120,0.14);
  --encre: #3A1425;
  --encre-douce: #7A4A5D;
  --encre-tenue: #B48A98;
  --ambiance-sombre: 0;
}
html[data-theme="porcelain"] {  /* Porcelaine */
  --papier: #F8F5F0;
  --carte: #FBFAF8;
  --carte-creuse: #EBE8E4;
  --bord: rgba(74,73,72,0.12);
  --encre: #222221;
  --encre-douce: #6F6E6C;
  --encre-tenue: #ADABA8;
  --ambiance-sombre: 0;
}
html[data-theme="linen"] {  /* Lin */
  --papier: #EFE7D8;
  --carte: #F7F4ED;
  --carte-creuse: #E3DBCD;
  --bord: rgba(71,69,64,0.12);
  --encre: #21201E;
  --encre-douce: #6B6761;
  --encre-tenue: #A7A197;
  --ambiance-sombre: 0;
}
html[data-theme="mist"] {  /* Brume */
  --papier: #E8ECEF;
  --carte: #F4F6F7;
  --carte-creuse: #DCE0E3;
  --bord: rgba(69,70,71,0.12);
  --encre: #202121;
  --encre-douce: #686A6B;
  --encre-tenue: #A2A5A7;
  --ambiance-sombre: 0;
}
html[data-theme="frost"] {  /* Givre */
  --papier: #E8F1F5;
  --carte: #F4F8FA;
  --carte-creuse: #DCE4E8;
  --bord: rgba(69,72,73,0.12);
  --encre: #202122;
  --encre-douce: #686C6E;
  --encre-tenue: #A2A8AB;
  --ambiance-sombre: 0;
}
html[data-theme="peachlight"] {  /* Pêche pâle */
  --papier: #FFE9DA;
  --carte: #FFF5EE;
  --carte-creuse: #F2DDCF;
  --bord: rgba(76,69,65,0.12);
  --encre: #23201E;
  --encre-douce: #726862;
  --encre-tenue: #B2A398;
  --ambiance-sombre: 0;
}
html[data-theme="mintlight"] {  /* Menthe pâle */
  --papier: #E7F5EE;
  --carte: #F4FAF7;
  --carte-creuse: #DBE8E2;
  --bord: rgba(69,73,71,0.12);
  --encre: #202221;
  --encre-douce: #676E6B;
  --encre-tenue: #A1ABA6;
  --ambiance-sombre: 0;
}
html[data-theme="marble"] {  /* Marbre */
  --papier: #F2EFE9;
  --carte: #FBF9F4;
  --carte-creuse: #E8E3D8;
  --bord: rgba(60,50,30,0.10);
  --encre: #1E1A12;
  --encre-douce: #6E6552;
  --encre-tenue: #A69C84;
  --ambiance-sombre: 0;
}

/* Deux ambiances claires reprises de Sakina passaient le texte à 4,42:1 —
   juste sous le seuil AA de 4,5. Leur encre est assombrie d'un cran. */
html[data-theme="sand"]  { --encre: #241E14; }
html[data-theme="cream"] { --encre: #241C0E; }

/* ── Ce qui se déduit, pour toutes les ambiances ─────────────────────────
   Plutôt que de redéfinir sept variables de plus dans chacun des 24 blocs,
   on les calcule à partir de celles qui viennent d'être posées. Un thème
   ajouté demain héritera de ces règles sans rien écrire. */
html[data-theme] {
  --bord-fort:  color-mix(in srgb, var(--encre) 20%, var(--carte));
  --carte-creuse: color-mix(in srgb, var(--encre) 4%, var(--carte));

  /* Les deux gris de texte sont DÉRIVÉS de l'encre et du papier, au lieu
     d'être fixés par ambiance. Mesurés sur le thème clair d'origine, les
     libellés en « encre tenue » tombaient à 2,1:1 — sous le seuil AA de
     4,5. Un mélange garanti suffit, et il vaut pour les 24 ambiances. */
  --encre-douce: color-mix(in srgb, var(--encre) 84%, var(--papier));
  --encre-tenue: color-mix(in srgb, var(--encre) 70%, var(--papier));
}
html[data-theme="light"] { --carte-creuse: #FBF6EE; }

/* ── Les ambiances sombres partagent tout ce qui suit ─────────────────── */
html[data-sombre="1"] {
  /* Le texte renforcé et la couleur posée sur un fond d'accent s'inversent. */
  --encre-forte: #FFFFFF;
  --sur-accent:  #0E1013;

  /* Les teintes sémantiques sont plus claires et les fonds plus discrets
     qu'en version claire : mesuré, un rouge #F08A84 sur un fond teinté à
     13 % tombait à 4,17:1 sur l'ambiance « nordic ». */
  --vert:   #A7E8A5;  --vert-pale:   rgba(127,199,126,.09);  --vert-bord:  rgba(127,199,126,.28);
  --ambre:  #F2D384;  --ambre-pale:  rgba(224,181,74,.09);   --ambre-bord: rgba(224,181,74,.28);
  --ambre-sombre: #F2D384;
  --corrige-fond: rgba(224,181,74,.07); --corrige-bord: rgba(224,181,74,.26);
  --rouge:  #F7B0AB;  --rouge-pale:  rgba(240,138,132,.09);  --rouge-bord: rgba(240,138,132,.28);
  --violet: #CDB6F1;  --violet-pale: rgba(179,146,232,.09);
  --violet-bord: rgba(179,146,232,.30);
  --ombre:      0 1px 2px rgba(0,0,0,.45), 0 8px 26px rgba(0,0,0,.38);
  --ombre-haut: 0 2px 8px rgba(0,0,0,.5),  0 18px 44px rgba(0,0,0,.45);
  color-scheme: dark;
}
html[data-sombre="0"] { color-scheme: light; }

/* Les accents de matière, éclaircis : un vert #2D5A27 sur fond sombre est
   illisible ; un #7FC77E passe le contraste AA. */
html[data-sombre="1"] [data-matiere="dev"]     { --accent:#7FC77E; --accent-pale:rgba(127,199,126,.13); --accent-sombre:#A7DCA5; }
html[data-sombre="1"] [data-matiere="reseau"]  { --accent:#63B3ED; --accent-pale:rgba(99,179,237,.13);  --accent-sombre:#9ECBF5; }
html[data-sombre="1"] [data-matiere="maths"]   { --accent:#F08A84; --accent-pale:rgba(240,138,132,.13); --accent-sombre:#F6B3AE; }
html[data-sombre="1"] [data-matiere="anglais"] { --accent:#F0A868; --accent-pale:rgba(240,168,104,.13); --accent-sombre:#F6C79B; }
html[data-sombre="1"] [data-matiere="culture"] { --accent:#B392E8; --accent-pale:rgba(179,146,232,.13); --accent-sombre:#CDB6F1;
                                                 --violet:#8FB2E8; --violet-pale:rgba(143,178,232,.13); --violet-bord:rgba(143,178,232,.32); }
html[data-sombre="1"] [data-matiere="projets"] { --accent:#E0B54A; --accent-pale:rgba(224,181,74,.13);  --accent-sombre:#EDD08A; }

html[data-sombre="1"] .tok-str { color:#B6E3A0; }

/* ── Confort de lecture ─────────────────────────────────────────────── */
html[data-taille="petit"]      { font-size: 15px; }
html[data-taille="normal"]     { font-size: 16.5px; }
html[data-taille="grand"]      { font-size: 18.5px; }
html[data-taille="tres-grand"] { font-size: 20.5px; }

/* Largeur de lecture — une ligne trop longue se relit mal, un écran 27" laissé
   à 76ch gaspille les deux tiers de la surface. Quatre crans, au choix. */
html[data-largeur="etroit"] { --mesure: 62ch;  --large-page: 980px;  --large-app: 980px;  }
html[data-largeur="normal"] { --mesure: 76ch;  --large-page: 1220px; --large-app: 1120px; }
html[data-largeur="large"]  { --mesure: 92ch;  --large-page: 1480px; --large-app: 1400px; }
html[data-largeur="pleine"] { --mesure: none;  --large-page: 100%;   --large-app: 100%;   }

/* Police du texte — trois familles natives, aucune police téléchargée. */
html[data-police="serif"] { --sans: ui-serif, Georgia, "Iowan Old Style", "Times New Roman", serif; }
html[data-police="mono"]  { --sans: var(--mono); }

/* Interligne */
html[data-interligne="serre"]  { --interligne: 1.55; }
html[data-interligne="normal"] { --interligne: 1.72; }
html[data-interligne="aere"]   { --interligne: 1.95; }

html[data-anim="0"] *, html[data-anim="0"] *::before, html[data-anim="0"] *::after {
  animation-duration: .001ms !important; animation-iteration-count: 1 !important;
  transition-duration: .001ms !important; scroll-behavior: auto !important;
}

/* ── Pourquoi « [data-sombre="0"] » sur les règles de FOND ───────────────
   Signalé le 27/09/2026 : le mode sombre de « console blanche » était à
   revoir.

   Mesuré : les cartes d'un index restaient BLANCHES de nuit, sous un texte
   passé en blanc cassé — 1,08:1, illisible. La cause n'était pas la palette
   sombre, qui est juste : c'était une règle écrite pour la face claire, sans
   garde de face, et qui peignait par-dessus. Une image de fond se pose SUR la
   couleur de fond ; le « --carte » sombre était là, recouvert.

   Le banc, lui, ne lisait que « backgroundColor » : il voyait le sombre et
   déclarait le contraste bon. Deux aveuglements superposés, dont un dans
   l'outil chargé de les voir.

   Quatre univers étaient touchés — cahier-rose, console-blanche, grand-large,
   liquid — pour 854 textes sous le seuil. Seules les règles qui PEIGNENT sont
   scopées : la forme (arrondis, biseaux, inclinaisons) reste commune aux deux
   faces, puisque c'est elle qui fait l'univers. */

/* ═══════════════════════════════════════════════════════════════════════
   STYLES — les thèmes « à univers », repris de Sakina avec leurs noms.
   Chacun vient d'un jeu ou d'un écran : Voxel, Terminal, Matrix, Retro CRT,
   Midgar, Détermination, Androïde, Velours, Grand Large, Cahier rose,
   Console blanche, Bloc-notes, Neon Lime, Liquid Glass, Zellige.

   Principe : un style agit d'abord PAR LES VARIABLES (papier, encre, accent,
   rayon, ombre, police). Il n'a donc pas besoin de connaître les ~90 classes
   des fiches — il les repeint toutes d'un coup. Seules les textures
   (trame de pixels, lignes de balayage, papier réglé) ajoutent des règles.

   Deux contraintes tenues :
   • aucune police ni image extérieure — tout est natif ou dessiné en CSS ;
   • chaque style redéclare l'accent pour [data-matiere], sinon la couleur
     de matière reprend le dessus (elle est plus spécifique).
   ═══════════════════════════════════════════════════════════════════════ */

/* ══════════════════════════════════════════════════════════════════════
   VOXEL — dans l'esprit des menus du jeu de cubes.
   La texture de terre du jeu en fond, voile noir par-dessus, panneaux
   opaques, et surtout le bouton de pierre à biseau : clair en haut à gauche,
   sombre en bas à droite, cerné de noir. Le texte porte son ombre dure d'un
   pixel. Les couleurs sont mesurées, pas choisies à l'œil : le gris d'origine
   du jeu ne tenait pas le seuil de lisibilité.
   ══════════════════════════════════════════════════════════════════════ */
html[data-theme="voxel"], html[data-theme="voxel"] [data-matiere] {
  /* --papier vaut la zone LA PLUS CLAIRE de la texture de terre (#503928,
     mesurée sur l'image elle-même). Le fond rendu est plus sombre encore,
     voilé à 28 % : le contraste annoncé est donc toujours pessimiste, jamais
     optimiste. Un fond moyen aurait laissé passer des textes illisibles
     au-dessus des blocs clairs. */
  --papier:#503928; --carte:#1B1B1B; --carte-creuse:#151515;
  --bord:#000000; --bord-fort:#000000;
  --encre:#F0F0F0; --encre-douce:#D8D8D8; --encre-tenue:#B9B9B9;
  --accent:#45792C; --accent-pale:rgba(143,212,107,.16); --accent-sombre:#8FD46B;
  --sur-accent:#FFFFFF;
  --vert:#8FD46B;  --ambre:#F5C842;  --rouge:#F49A9A;  --violet:#C2A3F0;
}
html[data-theme="voxel"] {
  --sans: var(--mono); --titre-accent: var(--sans);
  --r:0px; --r-l:0px;
  --ombre:none; --ombre-haut:none;
  --pierre:#6E6E6E;          /* blanc dessus : 5,1:1 */
  --pierre-survol:#5B679C;   /* blanc dessus : 5,43:1 */
}

/* Le fond du menu : la texture de terre du jeu, posée une fois pour toutes
   et fixe au défilement, comme dans l'écran d'options. « pixelated » empêche
   le lissage : les blocs restent des blocs quand l'image est agrandie. */
html[data-theme="voxel"] body {
  background-color:#2E2116;
  background-image:
    linear-gradient(rgba(0,0,0,.28), rgba(0,0,0,.28)),
    url("fond-voxel.webp");
  background-size: auto, cover;
  background-position: center;
  background-repeat: no-repeat;
  background-attachment: fixed;
  image-rendering: pixelated;
}

/* Les panneaux : noirs, opaques, cernés d'un trait clair — les cadres
   d'inventaire. Aucun arrondi nulle part. */
html[data-theme="voxel"] .carte-matiere,
html[data-theme="voxel"] .chapitre,
html[data-theme="voxel"] .encart,
html[data-theme="voxel"] .feuille,
html[data-theme="voxel"] .resultats,
html[data-theme="voxel"] .app-tete,
html[data-theme="voxel"] .bloc-code,
html[data-theme="voxel"] .sommaire,
html[data-theme="voxel"] table {
  background-color:#1B1B1B;
  border: 2px solid #000000;
  box-shadow: inset 2px 2px 0 rgba(255,255,255,.14), inset -2px -2px 0 rgba(0,0,0,.55);
  backdrop-filter: none; -webkit-backdrop-filter: none;
}

/* LE bouton du jeu : pierre grise, biseau clair en haut à gauche, sombre en
   bas à droite, contour noir. Au survol il vire au bleu-violet et se borde de
   blanc ; à l'appui le biseau s'inverse et le bouton « s'enfonce ».
   Le gris est descendu de #8B8B8B à #6E6E6E : le gris d'origine ne tenait le
   blanc qu'à 3,41:1, sous le seuil de lisibilité. */
html[data-theme="voxel"] .app-tete nav a,
html[data-theme="voxel"] .pastilles button,
html[data-theme="voxel"] .quiz button,
html[data-theme="voxel"] .bouton-hasard,
html[data-theme="voxel"] .mini,
html[data-theme="voxel"] .danger,
html[data-theme="voxel"] .bouton-rond,
html[data-theme="voxel"] .flottant,
html[data-theme="voxel"] .coche,
html[data-theme="voxel"] .chapitre .liens a,
html[data-theme="voxel"] .champ-select select,
html[data-theme="voxel"] .sommaire .retour,
html[data-theme="voxel"] .bloc-code .copier {
  background: var(--pierre); color: #FFFFFF;
  border: 2px solid #000000; border-radius: 0;
  box-shadow: inset 2px 2px 0 rgba(255,255,255,.34), inset -2px -2px 0 rgba(0,0,0,.42);
  text-shadow: 2px 2px 0 rgba(0,0,0,.6);
  letter-spacing: .02em; font-weight: 400;
  transition: background .08s linear, border-color .08s linear;
}
html[data-theme="voxel"] .app-tete nav a:hover,
html[data-theme="voxel"] .pastilles button:hover,
html[data-theme="voxel"] .quiz button:hover,
html[data-theme="voxel"] .bouton-hasard:hover,
html[data-theme="voxel"] .mini:hover,
html[data-theme="voxel"] .danger:hover,
html[data-theme="voxel"] .bouton-rond:hover,
html[data-theme="voxel"] .flottant:hover,
html[data-theme="voxel"] .coche:hover,
html[data-theme="voxel"] .chapitre .liens a:hover,
html[data-theme="voxel"] .sommaire .retour:hover,
html[data-theme="voxel"] .champ-select select:hover {
  background: var(--pierre-survol); border-color: #FFFFFF; color: #FFFFFF; transform: none;
}
html[data-theme="voxel"] .pastilles button:active,
html[data-theme="voxel"] .quiz button:active,
html[data-theme="voxel"] .bouton-hasard:active,
html[data-theme="voxel"] .mini:active,
html[data-theme="voxel"] .flottant:active,
html[data-theme="voxel"] .coche:active {
  box-shadow: inset -2px -2px 0 rgba(255,255,255,.22), inset 2px 2px 0 rgba(0,0,0,.5);
  transform: none;
}
/* La page où l'on est, et le cran choisi : vert d'herbe. */
html[data-theme="voxel"] .app-tete nav a[aria-current="page"],
html[data-theme="voxel"] .pastilles button[aria-pressed="true"],
html[data-theme="voxel"] .coche[aria-pressed="true"] {
  background:#45792C; border-color:#000000; color:#FFFFFF;
}

/* Le champ de saisie du jeu : noir, cerné de gris clair, texte blanc. */
html[data-theme="voxel"] .recherche input {
  background:#0A0A0A; color:#FFFFFF; border:2px solid #A0A0A0; border-radius:0;
  box-shadow:none;
}
html[data-theme="voxel"] .recherche input:focus { border-color:#FFFFFF; box-shadow:none; }
html[data-theme="voxel"] .recherche input::placeholder { color:#9A9A9A; }

/* Cadres nets partout : pas une pilule arrondie dans un menu de blocs. */
html[data-theme="voxel"] .heros .promo,
html[data-theme="voxel"] .carte-matiere .pastille,
html[data-theme="voxel"] .carte-matiere .ic,
html[data-theme="voxel"] .chapitre .num,
html[data-theme="voxel"] .jauge-matiere,
html[data-theme="voxel"] .app-marque .sigle {
  border-radius:0; border:2px solid #000000; background:#1B1B1B; color:#F0F0F0;
}

/* Le texte du jeu porte toujours son ombre d'un pixel. */
html[data-theme="voxel"] h1,
html[data-theme="voxel"] h2,
html[data-theme="voxel"] h3,
html[data-theme="voxel"] .app-marque,
html[data-theme="voxel"] .heros p,
html[data-theme="voxel"] .chiffres strong,
html[data-theme="voxel"] .chiffres span { text-shadow: 2px 2px 0 rgba(0,0,0,.6); }
html[data-theme="voxel"] h1, html[data-theme="voxel"] h2 { letter-spacing:.01em; font-weight:400; }
html[data-theme="voxel"] .heros h1 span { color:#FCFC54; }   /* le jaune du titre */
html[data-theme="voxel"] .heros::before { background:none; }
html[data-theme="voxel"] img, html[data-theme="voxel"] svg { image-rendering: pixelated; }

/* ──────────────────────────── PIXEL (trame de points, accent cyan) */
html[data-theme="pixel"], html[data-theme="pixel"] [data-matiere] {
  --papier:#0F1216; --carte:#1B2228; --carte-creuse:#151B20;
  --bord:#000000; --bord-fort:#000000;
  --encre:#EAF7FB; --encre-douce:#A9C4CE; --encre-tenue:#7D98A3;
  --accent:#5FE4F5; --accent-pale:rgba(95,228,245,.13); --accent-sombre:#9BEFFA;
  --sur-accent:#0A1216;
}
html[data-theme="pixel"] {
  --sans: var(--mono); --titre-accent: var(--sans);
  --r:0px; --r-l:0px;
  --ombre:4px 4px 0 rgba(0,0,0,.6);
  --ombre-haut:6px 6px 0 rgba(0,0,0,.7);
}
html[data-theme="pixel"] body {
  background-image:
    linear-gradient(rgba(255,255,255,.028) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,.028) 1px, transparent 1px);
  background-size: 16px 16px;
}
html[data-theme="pixel"] .carte-matiere,
html[data-theme="pixel"] .chapitre,
html[data-theme="pixel"] .encart,
html[data-theme="pixel"] .feuille,
html[data-theme="pixel"] .resultats { border-width:2px; border-style:solid; }
html[data-theme="pixel"] img,
html[data-theme="pixel"] svg { image-rendering: pixelated; }
html[data-theme="pixel"] h1,
html[data-theme="pixel"] h2 { letter-spacing:.02em; text-transform:uppercase; font-size:.92em; }

/* ────────────────────────────────────────────────────── TERMINAL (shell) */
html[data-theme="terminal"], html[data-theme="terminal"] [data-matiere] {
  --papier:#07090A; --carte:#0C1113; --carte-creuse:#0A0E10;
  --bord:rgba(59,224,122,.22); --bord-fort:rgba(59,224,122,.42);
  --encre:#CFF8DA; --encre-douce:#8FD9A4; --encre-tenue:#5E9E72;
  --accent:#3BE07A; --accent-pale:rgba(59,224,122,.12); --accent-sombre:#7DEDA6;
  --sur-accent:#04140A;
}
html[data-theme="terminal"] {
  --sans: var(--mono); --titre-accent: var(--sans);
  --r:2px; --r-l:3px;
  --ombre:0 0 0 1px rgba(59,224,122,.10);
  --ombre-haut:0 0 24px rgba(59,224,122,.14);
}
html[data-theme="terminal"] h2::before,
html[data-theme="terminal"] .carte-matiere h2::before {
  content:"$ "; color:var(--accent); font-weight:400;
}
html[data-theme="terminal"] .app-marque .sigle { border-radius:2px; }

/* ──────────────────────────────────────────────────────── MATRIX (pluie) */
html[data-theme="matrix"], html[data-theme="matrix"] [data-matiere] {
  --papier:#000803; --carte:#04160B; --carte-creuse:#031009;
  --bord:rgba(34,197,94,.26); --bord-fort:rgba(34,197,94,.5);
  --encre:#B6FFC8; --encre-douce:#76D68E; --encre-tenue:#4E9A62;
  --accent:#22C55E; --accent-pale:rgba(34,197,94,.12); --accent-sombre:#6EE7A0;
  --sur-accent:#001406;
}
html[data-theme="matrix"] {
  --sans: var(--mono); --titre-accent: var(--sans);
  --r:0px; --r-l:0px;
  --ombre:0 0 0 1px rgba(34,197,94,.14);
  --ombre-haut:0 0 30px rgba(34,197,94,.2);
}
html[data-theme="matrix"] body {
  background-image: repeating-linear-gradient(90deg,
    rgba(34,197,94,.045) 0 1px, transparent 1px 22px);
}
html[data-theme="matrix"] h1,
html[data-theme="matrix"] h2,
html[data-theme="matrix"] .heros h1 span { text-shadow:0 0 12px rgba(34,197,94,.5); }

/* ─────────────────────────────────────────────── RETRO CRT (phosphore ambre) */
html[data-theme="crt"], html[data-theme="crt"] [data-matiere] {
  --papier:#140D03; --carte:#1F1506; --carte-creuse:#191004;
  --bord:rgba(255,165,31,.24); --bord-fort:rgba(255,165,31,.46);
  --encre:#FFD79A; --encre-douce:#D9A85E; --encre-tenue:#A87F42;
  --accent:#FFA51F; --accent-pale:rgba(255,165,31,.12); --accent-sombre:#FFC978;
  --sur-accent:#1A0F02;
}
html[data-theme="crt"] {
  --sans: var(--mono); --titre-accent: var(--sans);
  --r:4px; --r-l:6px;
  --ombre:0 0 0 1px rgba(255,165,31,.12);
  --ombre-haut:0 0 34px rgba(255,165,31,.18);
}
/* Les lignes de balayage sont posées en superposition fixe, sans intercepter
   le pointeur, et disparaissent si l'utilisateur coupe les animations. */
html[data-theme="crt"] body::after {
  content:""; position:fixed; inset:0; z-index:9999; pointer-events:none;
  background: repeating-linear-gradient(rgba(0,0,0,.22) 0 1px, transparent 1px 3px);
  mix-blend-mode: multiply;
}
html[data-theme="crt"][data-anim="0"] body::after { display:none; }
html[data-theme="crt"] h1, html[data-theme="crt"] h2 { text-shadow:0 0 10px rgba(255,165,31,.45); }

/* ───────────────────────────────────────────────── MIDGAR (néon sur nuit) */
html[data-theme="midgar"], html[data-theme="midgar"] [data-matiere] {
  --papier:#070C14; --carte:#101B2B; --carte-creuse:#0B1420;
  --bord:rgba(53,199,216,.2); --bord-fort:rgba(53,199,216,.42);
  --encre:#E2EEF8; --encre-douce:#9FB8CC; --encre-tenue:#71899E;
  --accent:#35C7D8; --accent-pale:rgba(53,199,216,.13); --accent-sombre:#7EDFEA;
  --sur-accent:#04121A;
}
html[data-theme="midgar"] {
  --r:2px; --r-l:2px;
  --ombre:0 2px 0 rgba(53,199,216,.18);
  --ombre-haut:0 0 28px rgba(53,199,216,.22);
}
html[data-theme="midgar"] .carte-matiere,
html[data-theme="midgar"] .encart {
  clip-path: polygon(0 0, calc(100% - 14px) 0, 100% 14px, 100% 100%, 14px 100%, 0 calc(100% - 14px));
}
html[data-theme="midgar"] h2 { letter-spacing:.06em; text-transform:uppercase; font-size:.95em; }

/* ────────────────────────────────────── DÉTERMINATION (noir, cœur rouge) */
html[data-theme="determination"], html[data-theme="determination"] [data-matiere] {
  --papier:#000000; --carte:#0B0B0B; --carte-creuse:#060606;
  --bord:#FFFFFF; --bord-fort:#FFFFFF;
  --encre:#FFFFFF; --encre-douce:#D6D6D6; --encre-tenue:#A8A8A8;
  --accent:#FF3B3B; --accent-pale:rgba(255,59,59,.14); --accent-sombre:#FF8A8A;
  --sur-accent:#000000;   /* 5,94:1 — le blanc n'y tenait qu'à 3,53:1 */
}
html[data-theme="determination"] {
  --sans: var(--mono); --titre-accent: var(--sans);
  --r:0px; --r-l:0px;
  --ombre:none; --ombre-haut:none;
}
html[data-theme="determination"] .carte-matiere,
html[data-theme="determination"] .chapitre,
html[data-theme="determination"] .encart,
html[data-theme="determination"] .feuille,
html[data-theme="determination"] .resultats { border:2px solid #FFFFFF; }
/* Le cœur est une DÉCORATION, pas un second glyphe. .ic est une grille de
   38 px de côté : un ::after y crée une deuxième rangée, qui déborde sous la
   pastille et vient se poser sur la première lettre du titre. On le sort du
   flux et on le pose dans l'angle. */
html[data-theme="determination"] .carte-matiere .ic { position:relative; }
html[data-theme="determination"] .carte-matiere .ic::after {
  content:"\2665"; position:absolute; top:-5px; right:-5px;
  font-size:.58em; line-height:1; pointer-events:none;
}

/* ───────────────────────────────────────────── ANDROÏDE (sable, HUD fin) */
html[data-theme="androide"], html[data-theme="androide"] [data-matiere] {
  --papier:#CBC7B6; --carte:#DCD9CB; --carte-creuse:#D3CFC0;
  --bord:rgba(58,54,45,.34); --bord-fort:rgba(58,54,45,.6);
  --encre:#33302A; --encre-douce:#474338; --encre-tenue:#555046;  /* 4,72:1 sur le papier */
  --accent:#3A362D; --accent-pale:rgba(58,54,45,.12); --accent-sombre:#26231D;
  --sur-accent:#DCD9CB;
}
html[data-theme="androide"] {
  --r:0px; --r-l:0px;
  --ombre:0 1px 0 rgba(58,54,45,.25);
  --ombre-haut:0 2px 0 rgba(58,54,45,.35);
}
html[data-theme="androide"] .carte-matiere,
html[data-theme="androide"] .chapitre,
html[data-theme="androide"] .encart { border-width:1px; border-style:solid; }
html[data-theme="androide"] h1, html[data-theme="androide"] h2 { letter-spacing:.08em; font-weight:600; }

/* ──────────────────────────────────────────── VELOURS (noir et carmin) */
html[data-theme="velours"], html[data-theme="velours"] [data-matiere] {
  --papier:#0A0507; --carte:#15090D; --carte-creuse:#100708;
  --bord:rgba(228,35,74,.26); --bord-fort:rgba(228,35,74,.5);
  --encre:#F7EAEE; --encre-douce:#C8A3AD; --encre-tenue:#9C7D86;
  --accent:#E4234A; --accent-pale:rgba(228,35,74,.14); --accent-sombre:#FF8DA1;
  --sur-accent:#FFFFFF;
}
html[data-theme="velours"] {
  --r:0px; --r-l:0px;
  --ombre:3px 3px 0 rgba(228,35,74,.28);
  --ombre-haut:6px 6px 0 rgba(228,35,74,.35);
}
html[data-theme="velours"] h1, html[data-theme="velours"] h2 {
  font-style: italic; letter-spacing:-.02em;
}
html[data-theme="velours"] .carte-matiere { transform: skewY(-.4deg); }

/* ──────────────────────────────────────── GRAND LARGE (mer et parchemin) */
html[data-theme="grand-large"], html[data-theme="grand-large"] [data-matiere] {
  --papier:#E3F3EF; --carte:#FFFDF4; --carte-creuse:#F6F1E2;
  --bord:#CFE0D8; --bord-fort:#A9C7BB;
  --encre:#24413D; --encre-douce:#3C5A54; --encre-tenue:#3A524A;
  /* #456057 mesuré à 4,23:1 sur le fond turquoise de la page — sous le seuil.
     Le défaut n'était pas neuf : il ne se voyait pas parce que « Vu
     récemment » n'existe que si le lecteur a un historique, et que le banc
     n'en sème pas. Il est apparu le jour où j'ai simplement navigué sur le
     site avant de mesurer. Un contrôle ne voit que ce que la page affiche :
     un composant conditionnel doit être provoqué, sinon il n'est jamais
     mesuré. Nouvelle valeur : 4,94:1 sur la page, 6,9:1 sur le parchemin. */
  /* Mesuré contre le PARCHEMIN, pas contre --carte. L'ancienne valeur
     (#547069) annonçait « 4,70:1 » — vrai sur #FFFDF4, faux sur le fond
     réel : les cartes de Grand Large sont peintes d'un dégradé qui
     descend à #F6E7C1, où elle tombait à 4,39:1. Le banc ne lisait alors
     que « backgroundColor » et ne voyait pas le dégradé.
     Nouvelle valeur : 5,59:1 sur le parchemin, 6,73:1 sur la carte. */
  --accent:#0C7A76; --accent-pale:rgba(12,122,118,.11); --accent-sombre:#075C59;
  --sur-accent:#FFFFFF;
}
html[data-theme="grand-large"] {
  --sans: ui-rounded, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; --titre-accent: var(--sans);
  --r:16px; --r-l:26px;
  --ombre:0 2px 10px rgba(12,74,70,.1);
  --ombre-haut:0 10px 34px rgba(12,74,70,.16);
}
html[data-theme="grand-large"][data-sombre="0"] body {
  background-image: radial-gradient(ellipse 120% 60% at 50% 0%, rgba(255,255,255,.7), transparent 70%);
}

/* ────────────────────────────────────────── CAHIER ROSE (papier réglé) */
html[data-theme="cahier-rose"], html[data-theme="cahier-rose"] [data-matiere] {
  --papier:#FFF0F6; --carte:#FFFFFF; --carte-creuse:#FFF6FA;
  --bord:#F3CFDF; --bord-fort:#E4A8C4;
  --encre:#4A2A38; --encre-douce:#6B4354; --encre-tenue:#836070;
  --accent:#C2185B; --accent-pale:rgba(194,24,91,.1); --accent-sombre:#9C1249;
  --sur-accent:#FFFFFF;
}
html[data-theme="cahier-rose"] {
  --r:14px; --r-l:20px;
  --ombre:0 2px 8px rgba(160,60,105,.09);
  --ombre-haut:0 10px 30px rgba(160,60,105,.14);
}
html[data-theme="cahier-rose"][data-sombre="0"] .carte-matiere,
html[data-theme="cahier-rose"][data-sombre="0"] .encart {
  background-image: repeating-linear-gradient(transparent 0 27px, rgba(226,168,196,.28) 27px 28px);
}

/* ───────────────────────────────────── CONSOLE BLANCHE (blanc laqué) */
html[data-theme="console-blanche"], html[data-theme="console-blanche"] [data-matiere] {
  --papier:#EBF0F4; --carte:#FFFFFF; --carte-creuse:#F4F7F9;
  --bord:#D3DDE4; --bord-fort:#A9B9C4;
  --encre:#26333C; --encre-douce:#3F5060; --encre-tenue:#4E6675;
  /* Même correction que Grand Large, et même cause. « 4,68:1 mesuré »
     valait contre --carte (#FFFFFF) ; le fond réel de la page descend à
     #E4EBF1, où l'ancienne valeur tombait à 4,19:1. Nouvelle valeur :
     6,03 / 5,71 / 5,01 sur les trois surfaces du thème. */
  --accent:#0679A0; --accent-pale:rgba(6,121,160,.1); --accent-sombre:#045C7A;
  --sur-accent:#FFFFFF;
}
html[data-theme="console-blanche"] {
  --r:6px; --r-l:8px;
  --ombre:0 1px 0 #FFFFFF inset, 0 1px 3px rgba(38,51,60,.1);
  --ombre-haut:0 8px 26px rgba(38,51,60,.14);
}
html[data-theme="console-blanche"][data-sombre="0"] .carte-matiere,
html[data-theme="console-blanche"][data-sombre="0"] .chapitre {
  background-image: linear-gradient(#FFFFFF, #F6F9FB);
}

/* ────────────────────────────────────────── BLOC-NOTES (cahier à marge) */
html[data-theme="bloc-notes"], html[data-theme="bloc-notes"] [data-matiere] {
  --papier:#FAF7EC; --carte:#FFFEF7; --carte-creuse:#F5F1E3;
  --bord:#DED7C2; --bord-fort:#BFB59A;
  --encre:#2A2E38; --encre-douce:#474D5A; --encre-tenue:#666C7D;  /* 4,64:1 mesuré */
  --accent:#17509B; --accent-pale:rgba(23,80,155,.09); --accent-sombre:#103C76;
  --sur-accent:#FFFFFF;
}
html[data-theme="bloc-notes"] {
  --sans: ui-serif, Georgia, "Iowan Old Style", "Times New Roman", serif; --titre-accent: var(--sans);
  --r:3px; --r-l:4px;
  --ombre:0 1px 2px rgba(60,50,25,.09);
  --ombre-haut:0 8px 22px rgba(60,50,25,.13);
}
html[data-theme="bloc-notes"][data-sombre="0"] body {
  background-image: repeating-linear-gradient(transparent 0 25px, rgba(23,80,155,.09) 25px 26px);
}
html[data-theme="bloc-notes"] .carte-matiere,
html[data-theme="bloc-notes"] .encart { border-style: dashed; }

/* ───────────────────────────────────────────────── NEON LIME (nuit vive) */
html[data-theme="neon-lime"], html[data-theme="neon-lime"] [data-matiere] {
  --papier:#0A0C06; --carte:#141A0D; --carte-creuse:#0F1409;
  --bord:rgba(163,230,53,.2); --bord-fort:rgba(163,230,53,.44);
  --encre:#ECFFD4; --encre-douce:#B9D98C; --encre-tenue:#8DA966;
  --accent:#A3E635; --accent-pale:rgba(163,230,53,.12); --accent-sombre:#C6F27A;
  --sur-accent:#0A1300;
}
html[data-theme="neon-lime"] {
  --r:8px; --r-l:12px;
  --ombre:0 0 0 1px rgba(163,230,53,.12);
  --ombre-haut:0 0 32px rgba(163,230,53,.22);
}
html[data-theme="neon-lime"] .heros h1 span { text-shadow:0 0 18px rgba(163,230,53,.45); }

/* ────────────────────────────────────────── LIQUID GLASS (verre dépoli) */
html[data-theme="liquid"], html[data-theme="liquid"] [data-matiere] {
  --papier:#E8EEF6; --carte:rgba(255,255,255,.62); --carte-creuse:rgba(255,255,255,.4);
  --bord:rgba(255,255,255,.7); --bord-fort:rgba(120,140,170,.35);
  --encre:#16202C; --encre-douce:#35465A; --encre-tenue:#425566;
  /* Liquid Glass pose un voile bleu radial sur la page. Au point le plus
     dense (55 % de #78BEFF), l'ancienne valeur tombait à 3,70:1 — un
     texte ténu posé pile sur la tache lumineuse. Mesurée contre ce
     point-là et non contre --papier : 4,95:1 sur le voile, 6,61 ailleurs. */
  --accent:#1D4ED8; --accent-pale:rgba(29,78,216,.1); --accent-sombre:#1A3FA8;
  --sur-accent:#FFFFFF;
}
html[data-theme="liquid"] {
  --r:16px; --r-l:24px;
  --ombre:0 1px 1px rgba(255,255,255,.7) inset, 0 6px 22px rgba(30,50,80,.12);
  --ombre-haut:0 1px 1px rgba(255,255,255,.8) inset, 0 18px 50px rgba(30,50,80,.2);
}
html[data-theme="liquid"][data-sombre="0"] body {
  background-image:
    radial-gradient(ellipse 70% 50% at 12% 6%,  rgba(120,190,255,.55), transparent 62%),
    radial-gradient(ellipse 60% 45% at 88% 12%, rgba(190,160,255,.45), transparent 60%),
    radial-gradient(ellipse 80% 50% at 50% 98%, rgba(150,255,225,.4),  transparent 64%);
  background-attachment: fixed;
}
html[data-theme="liquid"] .carte-matiere,
html[data-theme="liquid"] .chapitre,
html[data-theme="liquid"] .encart,
html[data-theme="liquid"] .feuille,
html[data-theme="liquid"] .resultats {
  backdrop-filter: blur(18px) saturate(170%);
  -webkit-backdrop-filter: blur(18px) saturate(170%);
}

/* ─────────────────────────────────────────────── ZELLIGE (mosaïque) */
html[data-theme="zellige"], html[data-theme="zellige"] [data-matiere] {
  --papier:#F2EDE0; --carte:#FFFDF6; --carte-creuse:#F7F2E7;
  --bord:#DED3BC; --bord-fort:#C0B092;
  --encre:#24352F; --encre-douce:#3E534B; --encre-tenue:#596D63;  /* 4,74:1 mesuré */
  --accent:#0C6357; --accent-pale:rgba(12,99,87,.1); --accent-sombre:#084A41;
  --sur-accent:#FFFFFF;
}
html[data-theme="zellige"] {
  --r:4px; --r-l:6px;
  --ombre:0 1px 2px rgba(40,60,50,.08);
  --ombre-haut:0 10px 28px rgba(40,60,50,.14);
}
html[data-theme="zellige"][data-sombre="0"] body {
  background-image:
    repeating-linear-gradient( 45deg, rgba(12,99,87,.05) 0 2px, transparent 2px 18px),
    repeating-linear-gradient(-45deg, rgba(180,140,60,.05) 0 2px, transparent 2px 18px);
}

/* ═══════════════════════════════════════════════════════════════════════
   SECONDE COUCHE — la direction artistique, pas seulement la palette.
   Chaque style ci-dessus posait ses variables ; un menu ne se reconnaît pas
   à ses couleurs seules mais à la FORME de ses panneaux, à ce que fait la
   sélection, et à la façon dont le texte est posé. C'est ce que cette
   couche ajoute, sans toucher aux couleurs déjà mesurées au contraste.
   ═══════════════════════════════════════════════════════════════════════ */

/* ══════════════════════════ DÉTERMINATION — la boîte de dialogue noire */
/* Le jeu n'a qu'un seul objet d'interface : un rectangle noir cerné de blanc
   épais, du texte blanc à chasse fixe, et un cœur rouge qui désigne le choix
   courant. Le jaune ne sert qu'à une chose : l'option sélectionnée. */
html[data-theme="determination"] .app-tete,
html[data-theme="determination"] .bandeau-plan,
html[data-theme="determination"] .sommaire,
html[data-theme="determination"] .bloc-code,
html[data-theme="determination"] table { border:2px solid #FFFFFF; background:#000000; }

html[data-theme="determination"] .app-tete nav a,
html[data-theme="determination"] .pastilles button,
html[data-theme="determination"] .quiz button,
html[data-theme="determination"] .bouton-hasard,
html[data-theme="determination"] .bouton-rond,
html[data-theme="determination"] .mini,
html[data-theme="determination"] .coche,
html[data-theme="determination"] .bloc-code .copier {
  position: relative; background:#000000; color:#FFFFFF;
  border:2px solid #FFFFFF; border-radius:0; box-shadow:none;
}
/* Le cœur : il n'apparaît pas, il se DÉPLACE — c'est le curseur du jeu.
   Réservé en largeur pour que rien ne bouge quand il arrive. */
html[data-theme="determination"] .app-tete nav a::before,
html[data-theme="determination"] .pastilles button::before,
html[data-theme="determination"] .bouton-hasard::before,
html[data-theme="determination"] .coche::before {
  content:"\2665"; display:inline-block; width:1em; margin-right:.15em;
  color:transparent; transition:none;
}
html[data-theme="determination"] .app-tete nav a:hover::before,
html[data-theme="determination"] .pastilles button:hover::before,
html[data-theme="determination"] .bouton-hasard:hover::before,
html[data-theme="determination"] .coche:hover::before,
html[data-theme="determination"] .app-tete nav a[aria-current="page"]::before,
html[data-theme="determination"] .pastilles button[aria-pressed="true"]::before,
html[data-theme="determination"] .coche[aria-pressed="true"]::before { color:#FF3B3B; }
/* Le jaune ne désigne QUE le choix courant : c'est sa seule fonction dans
   le jeu, et lui en donner une autre la lui ferait perdre. */
html[data-theme="determination"] .app-tete nav a[aria-current="page"],
html[data-theme="determination"] .pastilles button[aria-pressed="true"],
html[data-theme="determination"] .coche[aria-pressed="true"] { color:#FFFF00; border-color:#FFFF00; }
html[data-theme="determination"] .heros h1 span { color:#FFFF00; }
html[data-theme="determination"] .recherche input {
  background:#000000; color:#FFFFFF; border:2px solid #FFFFFF; border-radius:0;
}
html[data-theme="determination"] h1,
html[data-theme="determination"] h2 { letter-spacing:.04em; font-weight:400; }

/* ═══════════════════════ MIDGAR — le menu de Final Fantasy VII Remake */
/* Panneaux bleu nuit translucides, liseré cyan en haut, coins coupés, et une
   barre verticale qui marque l'entrée active. Les titres sont en capitales
   très espacées : c'est la signature typographique de ces menus. */
/* « .feuille » reçoit bien le fond et le liseré — mais PAS le
   « position: relative » : elle est en « fixed », ancrée à l'écran, et la
   repasser en relative la renvoie dans le flux, à moitié dehors. La même
   faute avait été faite sur Androïde ; celle-ci, le banc l'a trouvée seul,
   le jour où on lui a appris à ouvrir les réglages. */
html[data-theme="midgar"] .carte-matiere,
html[data-theme="midgar"] .chapitre,
html[data-theme="midgar"] .encart,
html[data-theme="midgar"] .bandeau-plan,
html[data-theme="midgar"] .sommaire { position: relative; }
html[data-theme="midgar"] .carte-matiere,
html[data-theme="midgar"] .chapitre,
html[data-theme="midgar"] .encart,
html[data-theme="midgar"] .feuille,
html[data-theme="midgar"] .bandeau-plan,
html[data-theme="midgar"] .sommaire {
  background: linear-gradient(160deg, rgba(20,42,66,.92), rgba(9,18,30,.92));
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  border:1px solid rgba(53,199,216,.28);
}
/* Le filet lumineux du haut : dans le jeu, chaque panneau s'ouvre par là. */
html[data-theme="midgar"] .carte-matiere::after,
html[data-theme="midgar"] .encart::after,
html[data-theme="midgar"] .bandeau-plan::after {
  content:""; position:absolute; left:0; right:0; top:0; height:1px;
  background: linear-gradient(90deg, transparent, rgba(126,223,234,.9), transparent);
}
html[data-theme="midgar"] .app-tete {
  background: linear-gradient(180deg, rgba(10,22,36,.96), rgba(7,14,24,.92));
  border-bottom:1px solid rgba(53,199,216,.3);
}
html[data-theme="midgar"] .app-tete nav a { position:relative; border-radius:0; }
html[data-theme="midgar"] .app-tete nav a[aria-current="page"] {
  background: rgba(53,199,216,.1); box-shadow: inset 2px 0 0 #35C7D8;
  text-shadow: 0 0 10px rgba(53,199,216,.6);
}
html[data-theme="midgar"] h1,
html[data-theme="midgar"] h3 { letter-spacing:.07em; text-transform:uppercase; }
html[data-theme="midgar"] .heros h1 span { text-shadow:0 0 22px rgba(53,199,216,.55); }

/* ═════════════════════════════ VELOURS — Persona 5 Royal, rouge et noir */
/* Tout y est de travers et rien n'y est droit : les panneaux penchent, les
   angles sont coupés en biais, les titres sont en italique lourd. Le rouge
   ne décore pas, il découpe. L'or est la touche « Royal ». */
html[data-theme="velours"] { --or:#E8C25A; }
html[data-theme="velours"] body {
  background-image:
    radial-gradient(circle at 18% 12%, rgba(228,35,74,.14), transparent 44%),
    repeating-linear-gradient(115deg, rgba(228,35,74,.05) 0 2px, transparent 2px 9px);
  background-attachment: fixed;
}
html[data-theme="velours"] .carte-matiere,
html[data-theme="velours"] .encart,
html[data-theme="velours"] .bandeau-plan {
  transform: skewY(-1deg);
  clip-path: polygon(0 10px, 14px 0, 100% 0, 100% calc(100% - 10px), calc(100% - 14px) 100%, 0 100%);
  border-left:3px solid #E4234A;
}
/* Le contenu se redresse : seul le CADRE penche, sinon le texte devient
   illisible et la page entière gîte. */
html[data-theme="velours"] .carte-matiere > *,
html[data-theme="velours"] .encart > *,
html[data-theme="velours"] .bandeau-plan > * { transform: skewY(1deg); }
html[data-theme="velours"] .app-tete {
  background:#0A0507; border-bottom:3px solid #E4234A;
}
html[data-theme="velours"] .app-tete nav a,
html[data-theme="velours"] .pastilles button,
html[data-theme="velours"] .bouton-hasard,
html[data-theme="velours"] .mini {
  transform: skew(-9deg); border-radius:0;
}
html[data-theme="velours"] .app-tete nav a > *,
html[data-theme="velours"] .bouton-hasard > * { display:inline-block; transform: skew(9deg); }
html[data-theme="velours"] .app-tete nav a[aria-current="page"] {
  background:#E4234A; color:#FFFFFF;
}
html[data-theme="velours"] h1,
html[data-theme="velours"] h2,
html[data-theme="velours"] h3 {
  font-style: italic; font-weight:800; letter-spacing:-.025em; text-transform:uppercase;
}
html[data-theme="velours"] .heros h1 span { color:#E8C25A; }
html[data-theme="velours"] .carte-matiere .pastille,
html[data-theme="velours"] .heros .promo {
  border-radius:0; transform: skew(-9deg); border-color:#E8C25A; color:#E8C25A;
}

/* ═══════════════════════════════ ANDROÏDE — NieR:Automata, austère */
/* Beige sale, filets d'un pixel, capitales espacées, et la sélection qui
   INVERSE le bloc au lieu de le colorer. Les petits repères d'angle sont la
   marque de ses menus : quatre traits, jamais un cadre fermé. */
html[data-theme="androide"][data-sombre="0"] body::after {
  content:""; position:fixed; inset:0; z-index:9998; pointer-events:none;
  background: repeating-linear-gradient(rgba(58,54,45,.045) 0 1px, transparent 1px 4px);
}
html[data-theme="androide"][data-anim="0"] body::after { display:none; }
/* « .feuille » NE doit pas figurer ici : la feuille de réglages est en
   « position: fixed », ancrée en bas à droite de l'écran. La repasser en
   « relative » la renvoie dans le flux, à moitié hors de l'écran — le
   panneau s'ouvrait coupé à gauche. Les repères d'angle ne concernent que
   les panneaux de contenu, de toute façon. */
html[data-theme="androide"] .carte-matiere,
html[data-theme="androide"] .encart,
html[data-theme="androide"] .bandeau-plan { position:relative; }
/* Les repères d'angle, dessinés en dégradés : deux traits en haut à gauche,
   deux en bas à droite. Rien au milieu — le cadre reste ouvert. */
html[data-theme="androide"][data-sombre="0"] .carte-matiere::before,
html[data-theme="androide"][data-sombre="0"] .encart::before,
html[data-theme="androide"][data-sombre="0"] .bandeau-plan::before {
  content:""; position:absolute; inset:-1px; pointer-events:none;
  background:
    linear-gradient(#3A362D,#3A362D) left  top    / 12px 2px no-repeat,
    linear-gradient(#3A362D,#3A362D) left  top    / 2px 12px no-repeat,
    linear-gradient(#3A362D,#3A362D) right bottom / 12px 2px no-repeat,
    linear-gradient(#3A362D,#3A362D) right bottom / 2px 12px no-repeat;
}
html[data-theme="androide"][data-sombre="0"] .app-tete { background:#C2BEAC; border-bottom:1px solid #3A362D; }
html[data-theme="androide"] .app-tete nav a,
html[data-theme="androide"] .pastilles button,
html[data-theme="androide"] .mini,
html[data-theme="androide"] .coche { border-radius:0; letter-spacing:.06em; }
/* La sélection inverse : fond sombre, texte sable. C'est exactement ce que
   fait le curseur du jeu, et ça se lit sans couleur. */
html[data-theme="androide"][data-sombre="0"] .app-tete nav a[aria-current="page"],
html[data-theme="androide"][data-sombre="0"] .pastilles button[aria-pressed="true"],
html[data-theme="androide"][data-sombre="0"] .coche[aria-pressed="true"] {
  background:#3A362D; color:#DCD9CB; box-shadow:none;
}
html[data-theme="androide"][data-sombre="0"] .app-tete nav a:hover { background:rgba(58,54,45,.12); }
/* Les capitales très espacées sont la signature typographique du jeu — mais
   un titre long, mis en capitales et écarté de .14em, ne tient plus dans
   375 px : il poussait la page à 389 et la décalait entière. L'interlettrage
   se resserre sur petit écran, et le mot peut se couper si vraiment il le
   faut. Le signe reste, le débordement part. */
html[data-theme="androide"] h1,
html[data-theme="androide"] h3 {
  text-transform:uppercase; letter-spacing:.14em; overflow-wrap:anywhere;
}
@media (max-width: 560px) {
  html[data-theme="androide"] h1,
  html[data-theme="androide"] h3 { letter-spacing:.06em; }
}
html[data-theme="androide"] .heros .promo { border-radius:0; letter-spacing:.14em; }

/* ═════════════════════════ CAHIER ROSE — Doki Doki, le carnet à poèmes */
/* Des boîtes blanches très arrondies posées sur un rose pâle, un liseré rose
   soutenu, et une ombre douce : c'est la fenêtre de dialogue du jeu. Le
   papier réglé est réservé aux encarts — c'est la feuille de poème. */
html[data-theme="cahier-rose"][data-sombre="0"] body {
  background-image:
    radial-gradient(circle at 12% 8%,  rgba(255,182,213,.5), transparent 42%),
    radial-gradient(circle at 88% 4%,  rgba(255,214,232,.6), transparent 40%);
  background-attachment: fixed;
}
html[data-theme="cahier-rose"] .carte-matiere,
html[data-theme="cahier-rose"] .chapitre,
html[data-theme="cahier-rose"] .bandeau-plan,
html[data-theme="cahier-rose"] .feuille,
html[data-theme="cahier-rose"] .app-tete {
  border:2px solid #E4A8C4;
  box-shadow: 0 4px 0 rgba(228,168,196,.45), 0 10px 26px rgba(160,60,105,.12);
}
html[data-theme="cahier-rose"] .app-tete nav a,
html[data-theme="cahier-rose"] .pastilles button,
html[data-theme="cahier-rose"] .bouton-hasard,
html[data-theme="cahier-rose"] .mini,
html[data-theme="cahier-rose"] .coche {
  border-radius:999px; border:1.5px solid #E4A8C4; background:#FFFFFF;
}
html[data-theme="cahier-rose"][data-sombre="0"] .app-tete nav a[aria-current="page"],
html[data-theme="cahier-rose"][data-sombre="0"] .pastilles button[aria-pressed="true"],
html[data-theme="cahier-rose"][data-sombre="0"] .coche[aria-pressed="true"] {
  background:#C2185B; color:#FFFFFF; border-color:#C2185B;
}
html[data-theme="cahier-rose"] .carte-matiere .ic { position:relative; }
html[data-theme="cahier-rose"] .carte-matiere .ic::after {
  content:"\273F"; position:absolute; top:-5px; right:-5px;
  font-size:.58em; line-height:1; pointer-events:none;
}
html[data-theme="cahier-rose"] h1,
html[data-theme="cahier-rose"] h2 { letter-spacing:-.01em; }

/* ═════════════════════ GRAND LARGE — Wind Waker, parchemin sur la mer */
/* Le fond est la mer, les panneaux sont du parchemin cerné de brun chaud et
   très arrondi — le HUD du jeu. Le bleu reste dehors, le texte reste sur
   fond clair : c'est ce qui rend l'ensemble lisible en plein soleil. */
html[data-theme="grand-large"][data-sombre="0"] body {
  background-image:
    radial-gradient(ellipse 140% 70% at 50% -10%, rgba(255,247,214,.85), transparent 58%),
    linear-gradient(180deg, #CDEDE6 0%, #9FD8D0 45%, #7CC4BE 100%);
  background-attachment: fixed;
}
html[data-theme="grand-large"][data-sombre="0"] .carte-matiere,
html[data-theme="grand-large"][data-sombre="0"] .chapitre,
html[data-theme="grand-large"][data-sombre="0"] .encart,
html[data-theme="grand-large"][data-sombre="0"] .bandeau-plan,
html[data-theme="grand-large"][data-sombre="0"] .feuille,
html[data-theme="grand-large"][data-sombre="0"] .sommaire {
  background: linear-gradient(180deg, #FFF8E4, #F6E7C1);
  border:2px solid #A9793F;
  box-shadow: 0 3px 0 rgba(122,84,40,.35), 0 12px 30px rgba(12,74,70,.18);
}
html[data-theme="grand-large"][data-sombre="0"] .app-tete {
  background: linear-gradient(180deg, #FFF8E4, #F2DFB6);
  border-bottom:2px solid #A9793F;
}
html[data-theme="grand-large"] .app-tete nav a,
html[data-theme="grand-large"] .pastilles button,
html[data-theme="grand-large"] .bouton-hasard,
html[data-theme="grand-large"] .mini,
html[data-theme="grand-large"] .coche {
  border:2px solid #A9793F; background:#FFF8E4; border-radius:999px;
}
html[data-theme="grand-large"][data-sombre="0"] .app-tete nav a[aria-current="page"],
html[data-theme="grand-large"][data-sombre="0"] .pastilles button[aria-pressed="true"],
html[data-theme="grand-large"][data-sombre="0"] .coche[aria-pressed="true"] {
  background:#0C7A76; color:#FFF8E4; border-color:#075C59;
}
html[data-theme="grand-large"] h1,
html[data-theme="grand-large"] h2 { letter-spacing:-.005em; }

/* ═══════════════════════ CONSOLE BLANCHE — le menu de la Wii */
/* Des tuiles blanches très arrondies, un liseré bleu clair, une lueur bleue
   au survol, et la séparation grise horizontale du bas d'écran. Tout est
   laqué : les dégradés vont du blanc pur au gris-bleu le plus léger. */
html[data-theme="console-blanche"][data-sombre="0"] body {
  background-image: linear-gradient(180deg, #F7FAFC 0%, #E4EBF1 100%);
  background-attachment: fixed;
}
html[data-theme="console-blanche"] .carte-matiere,
html[data-theme="console-blanche"] .chapitre,
html[data-theme="console-blanche"] .bandeau-plan,
html[data-theme="console-blanche"] .feuille {
  border:2px solid #C9DCE8; border-radius:14px;
  box-shadow: inset 0 1px 0 #FFFFFF, 0 2px 6px rgba(38,51,60,.09);
  transition: box-shadow .18s, border-color .18s;
}
html[data-theme="console-blanche"] .carte-matiere:hover {
  border-color:#5FB8E0;
  box-shadow: inset 0 1px 0 #FFFFFF, 0 0 0 3px rgba(95,184,224,.28), 0 8px 22px rgba(38,51,60,.14);
}
html[data-theme="console-blanche"][data-sombre="0"] .app-tete {
  background: linear-gradient(180deg, #FFFFFF, #EDF3F7);
  border-bottom:1px solid #C9DCE8;
}
html[data-theme="console-blanche"][data-sombre="0"] .app-tete nav a,
html[data-theme="console-blanche"][data-sombre="0"] .pastilles button,
html[data-theme="console-blanche"][data-sombre="0"] .bouton-hasard,
html[data-theme="console-blanche"][data-sombre="0"] .mini,
html[data-theme="console-blanche"][data-sombre="0"] .bouton-rond,
html[data-theme="console-blanche"][data-sombre="0"] .coche {
  border-radius:999px; border:1px solid #C9DCE8;
  background: linear-gradient(180deg, #FFFFFF, #F1F6F9);
  box-shadow: inset 0 1px 0 #FFFFFF;
}
html[data-theme="console-blanche"][data-sombre="0"] .app-tete nav a[aria-current="page"],
html[data-theme="console-blanche"][data-sombre="0"] .pastilles button[aria-pressed="true"],
html[data-theme="console-blanche"][data-sombre="0"] .coche[aria-pressed="true"] {
  background: linear-gradient(180deg, #2FA6DC, #0679A0); color:#FFFFFF; border-color:#045C7A;
}

/* ══════════════════════ BLOC-NOTES — Doodle Jump, le cahier griffonné */
/* Page quadrillée, trait de crayon, et le vert des plateformes. Les panneaux
   sont légèrement de travers, comme collés à la main — mais très légèrement :
   au-delà d'un degré, une page entière devient pénible à lire. */
html[data-theme="bloc-notes"] {
  --sans: "Chalkboard SE", "Comic Sans MS", "Marker Felt", ui-rounded, sans-serif; --titre-accent: var(--sans);
  --ressort:#7DB93F;
}
html[data-theme="bloc-notes"][data-sombre="0"] body {
  background-image:
    repeating-linear-gradient(rgba(23,80,155,.10) 0 1px, transparent 1px 26px),
    repeating-linear-gradient(90deg, rgba(23,80,155,.06) 0 1px, transparent 1px 26px);
}
html[data-theme="bloc-notes"] .carte-matiere,
html[data-theme="bloc-notes"] .encart,
html[data-theme="bloc-notes"] .bandeau-plan {
  border:2px solid #2A2E38; border-style:solid;
  box-shadow: 2px 2px 0 rgba(42,46,56,.75);
}
html[data-theme="bloc-notes"] .carte-matiere:nth-child(odd)  { transform: rotate(-.5deg); }
html[data-theme="bloc-notes"] .carte-matiere:nth-child(even) { transform: rotate(.5deg); }
html[data-theme="bloc-notes"] .app-tete {
  border-bottom:2px solid #2A2E38; background:#FFFEF7;
}
html[data-theme="bloc-notes"] .app-tete nav a,
html[data-theme="bloc-notes"] .pastilles button,
html[data-theme="bloc-notes"] .bouton-hasard,
html[data-theme="bloc-notes"] .mini,
html[data-theme="bloc-notes"] .coche {
  border:2px solid #2A2E38; border-radius:10px; background:#FFFEF7;
  box-shadow: 2px 2px 0 rgba(42,46,56,.6);
}
/* Le vert du ressort : c'est la seule couleur vive du jeu, réservée à ce
   qui est actif — on saute dessus. */
html[data-theme="bloc-notes"][data-sombre="0"] .app-tete nav a[aria-current="page"],
html[data-theme="bloc-notes"][data-sombre="0"] .pastilles button[aria-pressed="true"],
html[data-theme="bloc-notes"][data-sombre="0"] .coche[aria-pressed="true"] {
  background: var(--ressort); color:#14240A; border-color:#2A2E38;
}
html[data-theme="bloc-notes"] .heros h1 span { color:#4B7D22; }

/* ═════════════════════════ LIQUID GLASS — le verre des iOS récents */
/* Le verre ne se voit pas à sa transparence mais à son BORD : un liseré clair
   en haut, sombre en bas, et un léger grossissement de ce qu'il y a derrière.
   Les formes sont des « squircles » — arrondis larges et continus. */
html[data-theme="liquid"][data-sombre="0"] .carte-matiere,
html[data-theme="liquid"][data-sombre="0"] .chapitre,
html[data-theme="liquid"][data-sombre="0"] .encart,
html[data-theme="liquid"][data-sombre="0"] .bandeau-plan,
html[data-theme="liquid"][data-sombre="0"] .feuille,
html[data-theme="liquid"][data-sombre="0"] .app-tete {
  border-radius:22px; border:.5px solid rgba(255,255,255,.55);
  background: linear-gradient(180deg, rgba(255,255,255,.72), rgba(255,255,255,.46));
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.95),
    inset 0 -1px 0 rgba(120,140,170,.18),
    0 8px 30px rgba(30,50,80,.14);
  backdrop-filter: blur(24px) saturate(180%);
  -webkit-backdrop-filter: blur(24px) saturate(180%);
}
html[data-theme="liquid"] .app-tete { border-radius:0; }
html[data-theme="liquid"][data-sombre="0"] .app-tete nav a,
html[data-theme="liquid"][data-sombre="0"] .pastilles button,
html[data-theme="liquid"][data-sombre="0"] .bouton-hasard,
html[data-theme="liquid"][data-sombre="0"] .mini,
html[data-theme="liquid"][data-sombre="0"] .bouton-rond,
html[data-theme="liquid"][data-sombre="0"] .coche {
  border-radius:999px; border:.5px solid rgba(255,255,255,.7);
  background: linear-gradient(180deg, rgba(255,255,255,.8), rgba(255,255,255,.5));
  box-shadow: inset 0 1px 0 rgba(255,255,255,.95), 0 2px 10px rgba(30,50,80,.1);
  backdrop-filter: blur(14px) saturate(170%);
  -webkit-backdrop-filter: blur(14px) saturate(170%);
}
html[data-theme="liquid"][data-sombre="0"] .app-tete nav a[aria-current="page"],
html[data-theme="liquid"][data-sombre="0"] .pastilles button[aria-pressed="true"],
html[data-theme="liquid"][data-sombre="0"] .coche[aria-pressed="true"] {
  background: linear-gradient(180deg, #3B6BEA, #1D4ED8); color:#FFFFFF;
  border-color: rgba(255,255,255,.4);
}
html[data-theme="liquid"][data-sombre="0"] .recherche input {
  border-radius:999px; border:.5px solid rgba(255,255,255,.7);
  background: rgba(255,255,255,.6);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
}

/* ═══════════════════════════════════════════════════════════════════════
   LES DEUX FACES DE CHAQUE UNIVERS
   Un univers n'est pas « un thème sombre » ou « un thème clair » : c'est une
   forme, une typographie, une façon de désigner la sélection. Tout cela vaut
   de jour comme de nuit. Le bouton jour/nuit ne quitte donc plus l'univers,
   il en change la face — « data-sombre » vaut 1 ou 0, et c'est tout.

   Les blocs plus haut restent la face NATIVE de chaque univers (celle du jeu).
   Ci-dessous, la face manquante. Deux sélecteurs d'attribut sur « html »
   l'emportent sur un seul : rien n'a besoin d'être réécrit au-dessus.

   Les couleurs sont conservatrices par construction — encre foncée sur papier
   clair, encre claire sur papier foncé — et vérifiées ensuite par
   verification/contraste.html, qui croise désormais les deux faces.
   ═══════════════════════════════════════════════════════════════════════ */

/* ──────────────────────────────── VOXEL en plein jour (sable et herbe) */
html[data-theme="voxel"][data-sombre="0"],
html[data-theme="voxel"][data-sombre="0"] [data-matiere] {
  /* --papier vaut la zone LA PLUS SOMBRE du rendu — l'inverse exact de la
     face de nuit, et pour la même raison. De nuit, le fond est voilé de noir :
     la zone la plus CLAIRE donne la mesure la plus dure. De jour, le voile est
     blanc : c'est la zone la plus SOMBRE qui contraint.

     Depuis le 28/09/2026, la face de jour a SA PROPRE image — la texture de
     pierre, fournie avec la demande — au lieu de la terre de nuit
     blanchie à 62 %.
     #AEAEAF est le pixel le plus sombre des 559 000 de l'image, voilé de
     blanc à 50 % : mesuré sur l'image elle-même, pas sur une moyenne. Une
     moyenne de bloc donnait #7C7C7C et aurait laissé passer des textes
     illisibles au-dessus des joints sombres de la pierre.
     Les trois encres y tiennent 8,45 · 6,08 · 5,22:1, et --accent-sombre
     5,47:1. La valeur est très légèrement PLUS CLAIRE que l'ancienne
     (#B0ABA6) : aucun texte déjà validé ne peut donc régresser. */
  --papier:#AEAEAF; --carte:#EFE8D8; --carte-creuse:#E3DAC6;
  --bord:#2B2115; --bord-fort:#2B2115;
  --encre:#17110B; --encre-douce:#3A2C1C; --encre-tenue:#463625;
  --accent:#35631F; --accent-pale:rgba(53,99,31,.15); --accent-sombre:#1E3D11;
  --sur-accent:#FFFFFF;
  --vert:#2E6B1E; --ambre:#8A5F00; --rouge:#9E2B25; --violet:#5B3E8F;
}
html[data-theme="voxel"][data-sombre="0"] {
  --pierre:#DCD6C8; --pierre-survol:#B9C3E2;
}
/* Le plein jour a sa propre image : la texture de PIERRE, quand la nuit a
   celle de la terre. Le voile blanc tombe de 62 % à 50 % — il n'a plus à
   éclaircir une image sombre, seulement à poser le soleil dessus, et la
   pierre reste lisible comme pierre. #C0C0C0 est le pixel médian de l'image
   voilé de la même façon : c'est ce qu'on voit le temps que l'image arrive,
   et pendant l'impression. */
html[data-theme="voxel"][data-sombre="0"] body {
  background-color:#C0C0C0;
  background-image:
    linear-gradient(rgba(255,255,255,.5), rgba(255,255,255,.5)),
    url("fond-voxel-clair.webp");
}
html[data-theme="voxel"][data-sombre="0"] .carte-matiere,
html[data-theme="voxel"][data-sombre="0"] .chapitre,
html[data-theme="voxel"][data-sombre="0"] .encart,
html[data-theme="voxel"][data-sombre="0"] .feuille,
html[data-theme="voxel"][data-sombre="0"] .resultats,
html[data-theme="voxel"][data-sombre="0"] .app-tete,
html[data-theme="voxel"][data-sombre="0"] .bloc-code,
html[data-theme="voxel"][data-sombre="0"] .sommaire,
html[data-theme="voxel"][data-sombre="0"] table {
  background-color:#EFE8D8; border:2px solid #2B2115;
  box-shadow: inset 2px 2px 0 rgba(255,255,255,.8), inset -2px -2px 0 rgba(43,33,21,.28);
}
html[data-theme="voxel"][data-sombre="0"] .app-tete nav a,
html[data-theme="voxel"][data-sombre="0"] .pastilles button,
html[data-theme="voxel"][data-sombre="0"] .quiz button,
html[data-theme="voxel"][data-sombre="0"] .bouton-hasard,
html[data-theme="voxel"][data-sombre="0"] .mini,
html[data-theme="voxel"][data-sombre="0"] .danger,
html[data-theme="voxel"][data-sombre="0"] .bouton-rond,
html[data-theme="voxel"][data-sombre="0"] .flottant,
html[data-theme="voxel"][data-sombre="0"] .coche,
html[data-theme="voxel"][data-sombre="0"] .chapitre .liens a,
html[data-theme="voxel"][data-sombre="0"] .champ-select select,
html[data-theme="voxel"][data-sombre="0"] .sommaire .retour,
html[data-theme="voxel"][data-sombre="0"] .bloc-code .copier {
  background: var(--pierre); color:#1F1710; text-shadow:none;
  box-shadow: inset 2px 2px 0 rgba(255,255,255,.85), inset -2px -2px 0 rgba(43,33,21,.3);
}
html[data-theme="voxel"][data-sombre="0"] .app-tete nav a[aria-current="page"],
html[data-theme="voxel"][data-sombre="0"] .pastilles button[aria-pressed="true"],
html[data-theme="voxel"][data-sombre="0"] .coche[aria-pressed="true"] {
  background:#3A6B22; color:#FFFFFF;
}
html[data-theme="voxel"][data-sombre="0"] .recherche input {
  background:#FFFDF5; color:#1F1710; border:2px solid #2B2115;
}
html[data-theme="voxel"][data-sombre="0"] .recherche input::placeholder { color:#5B4A34; }
html[data-theme="voxel"][data-sombre="0"] .heros .promo,
html[data-theme="voxel"][data-sombre="0"] .carte-matiere .pastille,
html[data-theme="voxel"][data-sombre="0"] .carte-matiere .ic,
html[data-theme="voxel"][data-sombre="0"] .chapitre .num,
html[data-theme="voxel"][data-sombre="0"] .jauge-matiere,
html[data-theme="voxel"][data-sombre="0"] .app-marque .sigle {
  background:#EFE8D8; border:2px solid #2B2115; color:#1F1710;
}
/* Une ombre dure noire sous un texte noir ne se voit pas : elle l'épaissit
   et le rend sale. En plein jour, le texte n'en porte pas. */
html[data-theme="voxel"][data-sombre="0"] h1,
html[data-theme="voxel"][data-sombre="0"] h2,
html[data-theme="voxel"][data-sombre="0"] h3,
html[data-theme="voxel"][data-sombre="0"] .app-marque,
html[data-theme="voxel"][data-sombre="0"] .heros p,
html[data-theme="voxel"][data-sombre="0"] .chiffres strong,
html[data-theme="voxel"][data-sombre="0"] .chiffres span { text-shadow:none; }
html[data-theme="voxel"][data-sombre="0"] .heros h1 span { color:#8A5F00; }

/* ─────────────────────────────────────────────────────── PIXEL en clair */
html[data-theme="pixel"][data-sombre="0"],
html[data-theme="pixel"][data-sombre="0"] [data-matiere] {
  --papier:#DCE7EC; --carte:#FFFFFF; --carte-creuse:#F0F5F8;
  --bord:#10181D; --bord-fort:#10181D;
  --encre:#0D1418; --encre-douce:#39505C; --encre-tenue:#4C6672;
  --accent:#0B6E85; --accent-pale:rgba(11,110,133,.12); --accent-sombre:#08505F;
  --sur-accent:#FFFFFF;
}
html[data-theme="pixel"][data-sombre="0"] {
  --ombre:4px 4px 0 rgba(16,24,29,.25); --ombre-haut:6px 6px 0 rgba(16,24,29,.3);
}
html[data-theme="pixel"][data-sombre="0"] body {
  background-image:
    linear-gradient(rgba(16,24,29,.05) 1px, transparent 1px),
    linear-gradient(90deg, rgba(16,24,29,.05) 1px, transparent 1px);
}

/* ────────────────────────────────── TERMINAL en clair (fond de papier) */
html[data-theme="terminal"][data-sombre="0"],
html[data-theme="terminal"][data-sombre="0"] [data-matiere] {
  --papier:#EEF5EF; --carte:#FFFFFF; --carte-creuse:#F5FAF6;
  --bord:rgba(11,106,56,.24); --bord-fort:rgba(11,106,56,.46);
  --encre:#0E2A18; --encre-douce:#2F5840; --encre-tenue:#3F6B50;
  --accent:#0B6A38; --accent-pale:rgba(11,106,56,.1); --accent-sombre:#084E29;
  --sur-accent:#FFFFFF;
}
html[data-theme="terminal"][data-sombre="0"] { --ombre:0 0 0 1px rgba(11,106,56,.12); }

/* ────────────────────────────────────── MATRIX en clair (vert sur blanc) */
html[data-theme="matrix"][data-sombre="0"],
html[data-theme="matrix"][data-sombre="0"] [data-matiere] {
  --papier:#EDF6EF; --carte:#FFFFFF; --carte-creuse:#F4FAF5;
  --bord:rgba(13,110,55,.24); --bord-fort:rgba(13,110,55,.46);
  --encre:#0A2A15; --encre-douce:#2C563B; --encre-tenue:#3C6A4B;
  --accent:#0D6E37; --accent-pale:rgba(13,110,55,.1); --accent-sombre:#095228;
  --sur-accent:#FFFFFF;
}
html[data-theme="matrix"][data-sombre="0"] body {
  background-image: repeating-linear-gradient(90deg,
    rgba(13,110,55,.05) 0 1px, transparent 1px 22px);
}
html[data-theme="matrix"][data-sombre="0"] h1,
html[data-theme="matrix"][data-sombre="0"] h2,
html[data-theme="matrix"][data-sombre="0"] .heros h1 span { text-shadow:none; }

/* ──────────────────────────── RETRO CRT en clair (papier thermique ambre) */
html[data-theme="crt"][data-sombre="0"],
html[data-theme="crt"][data-sombre="0"] [data-matiere] {
  --papier:#F5EAD6; --carte:#FFFCF4; --carte-creuse:#F9F2E4;
  --bord:rgba(122,80,0,.26); --bord-fort:rgba(122,80,0,.48);
  --encre:#33230A; --encre-douce:#5A4111; --encre-tenue:#6B4F18;
  --accent:#8A5A00; --accent-pale:rgba(138,90,0,.11); --accent-sombre:#6A4400;
  --sur-accent:#FFFFFF;
}
html[data-theme="crt"][data-sombre="0"] body::after {
  background: repeating-linear-gradient(rgba(122,80,0,.08) 0 1px, transparent 1px 3px);
  mix-blend-mode: normal;
}
html[data-theme="crt"][data-sombre="0"] h1,
html[data-theme="crt"][data-sombre="0"] h2 { text-shadow:none; }

/* ───────────────────────── MIDGAR en clair (les écrans de jour de Shinra) */
html[data-theme="midgar"][data-sombre="0"],
html[data-theme="midgar"][data-sombre="0"] [data-matiere] {
  --papier:#E4EDF4; --carte:#FFFFFF; --carte-creuse:#F1F6FA;
  --bord:rgba(8,105,119,.24); --bord-fort:rgba(8,105,119,.46);
  --encre:#0B2231; --encre-douce:#2F4C5F; --encre-tenue:#3F5E72;
  --accent:#086977; --accent-pale:rgba(8,105,119,.1); --accent-sombre:#064E58;
  --sur-accent:#FFFFFF;
}
html[data-theme="midgar"][data-sombre="0"] .carte-matiere,
html[data-theme="midgar"][data-sombre="0"] .chapitre,
html[data-theme="midgar"][data-sombre="0"] .encart,
html[data-theme="midgar"][data-sombre="0"] .feuille,
html[data-theme="midgar"][data-sombre="0"] .bandeau-plan,
html[data-theme="midgar"][data-sombre="0"] .sommaire {
  background: linear-gradient(160deg, rgba(255,255,255,.96), rgba(233,242,248,.96));
  border:1px solid rgba(8,105,119,.3);
}
html[data-theme="midgar"][data-sombre="0"] .carte-matiere::after,
html[data-theme="midgar"][data-sombre="0"] .encart::after,
html[data-theme="midgar"][data-sombre="0"] .bandeau-plan::after {
  background: linear-gradient(90deg, transparent, rgba(8,105,119,.7), transparent);
}
html[data-theme="midgar"][data-sombre="0"] .app-tete {
  background: linear-gradient(180deg, #FFFFFF, #EAF2F7);
  border-bottom:1px solid rgba(8,105,119,.3);
}
html[data-theme="midgar"][data-sombre="0"] .app-tete nav a[aria-current="page"] {
  background: rgba(8,105,119,.1); box-shadow: inset 2px 0 0 #086977; text-shadow:none;
}
html[data-theme="midgar"][data-sombre="0"] .heros h1 span { text-shadow:none; }

/* ───────────────────── DÉTERMINATION en clair (la boîte blanche inversée) */
html[data-theme="determination"][data-sombre="0"],
html[data-theme="determination"][data-sombre="0"] [data-matiere] {
  --papier:#FFFFFF; --carte:#FFFFFF; --carte-creuse:#F4F4F4;
  --bord:#000000; --bord-fort:#000000;
  --encre:#000000; --encre-douce:#2E2E2E; --encre-tenue:#454545;
  --accent:#C40000; --accent-pale:rgba(196,0,0,.1); --accent-sombre:#8E0000;
  --sur-accent:#FFFFFF;
}
html[data-theme="determination"][data-sombre="0"] .app-tete,
html[data-theme="determination"][data-sombre="0"] .bandeau-plan,
html[data-theme="determination"][data-sombre="0"] .sommaire,
html[data-theme="determination"][data-sombre="0"] .bloc-code,
html[data-theme="determination"][data-sombre="0"] table { border:2px solid #000000; background:#FFFFFF; }
html[data-theme="determination"][data-sombre="0"] .carte-matiere,
html[data-theme="determination"][data-sombre="0"] .chapitre,
html[data-theme="determination"][data-sombre="0"] .encart,
html[data-theme="determination"][data-sombre="0"] .feuille,
html[data-theme="determination"][data-sombre="0"] .resultats { border:2px solid #000000; }
html[data-theme="determination"][data-sombre="0"] .app-tete nav a,
html[data-theme="determination"][data-sombre="0"] .pastilles button,
html[data-theme="determination"][data-sombre="0"] .quiz button,
html[data-theme="determination"][data-sombre="0"] .bouton-hasard,
html[data-theme="determination"][data-sombre="0"] .bouton-rond,
html[data-theme="determination"][data-sombre="0"] .mini,
html[data-theme="determination"][data-sombre="0"] .coche,
html[data-theme="determination"][data-sombre="0"] .bloc-code .copier,
html[data-theme="determination"][data-sombre="0"] .recherche input {
  background:#FFFFFF; color:#000000; border:2px solid #000000;
}
/* Le jaune du jeu sur du blanc serait illisible : il devient un aplat,
   texte noir dessus. Même signal, contraste tenu. */
html[data-theme="determination"][data-sombre="0"] .app-tete nav a[aria-current="page"],
html[data-theme="determination"][data-sombre="0"] .pastilles button[aria-pressed="true"],
html[data-theme="determination"][data-sombre="0"] .coche[aria-pressed="true"] {
  background:#FFD400; color:#000000; border-color:#000000;
}
html[data-theme="determination"][data-sombre="0"] .heros h1 span { color:#8A6A00; }

/* ────────────────────── VELOURS en clair (le blanc « Royal » de Persona) */
html[data-theme="velours"][data-sombre="0"],
html[data-theme="velours"][data-sombre="0"] [data-matiere] {
  --papier:#F2EFEC; --carte:#FFFFFF; --carte-creuse:#F7F4F1;
  --bord:rgba(180,17,44,.24); --bord-fort:rgba(180,17,44,.5);
  --encre:#1A0A0E; --encre-douce:#4A2E35; --encre-tenue:#5C3D45;
  --accent:#B4112C; --accent-pale:rgba(180,17,44,.1); --accent-sombre:#8A0C21;
  --sur-accent:#FFFFFF;
  /* L'or « Royal » de jour : #6F540D tombait à 4,24:1 sur la pastille,
     mesuré par le banc dès l'instant où il a croisé la face claire — il
     ne l'avait jamais vue. #6F540D tient 6,22:1 sur le papier. */
  --or:#6F540D;
}
html[data-theme="velours"][data-sombre="0"] {
  --ombre:3px 3px 0 rgba(180,17,44,.22); --ombre-haut:6px 6px 0 rgba(180,17,44,.28);
}
html[data-theme="velours"][data-sombre="0"] body {
  background-image:
    radial-gradient(circle at 18% 12%, rgba(180,17,44,.1), transparent 44%),
    repeating-linear-gradient(115deg, rgba(180,17,44,.045) 0 2px, transparent 2px 9px);
}
html[data-theme="velours"][data-sombre="0"] .app-tete {
  background:#FFFFFF; border-bottom:3px solid #B4112C;
}
html[data-theme="velours"][data-sombre="0"] .carte-matiere,
html[data-theme="velours"][data-sombre="0"] .encart,
html[data-theme="velours"][data-sombre="0"] .bandeau-plan { border-left:3px solid #B4112C; }
html[data-theme="velours"][data-sombre="0"] .app-tete nav a[aria-current="page"] {
  background:#B4112C; color:#FFFFFF;
}
html[data-theme="velours"][data-sombre="0"] .heros h1 span { color:#6F540D; }
html[data-theme="velours"][data-sombre="0"] .carte-matiere .pastille,
html[data-theme="velours"][data-sombre="0"] .heros .promo { border-color:#6F540D; color:#6F540D; }

/* ───────────────────────────── NEON LIME en clair (citron sur papier) */
html[data-theme="neon-lime"][data-sombre="0"],
html[data-theme="neon-lime"][data-sombre="0"] [data-matiere] {
  --papier:#F3F8E8; --carte:#FFFFFF; --carte-creuse:#F8FBF0;
  --bord:rgba(77,124,15,.22); --bord-fort:rgba(77,124,15,.45);
  --encre:#1B2608; --encre-douce:#3E5216; --encre-tenue:#4E651E;
  --accent:#4D7C0F; --accent-pale:rgba(77,124,15,.1); --accent-sombre:#3A5E0B;
  --sur-accent:#FFFFFF;
}
html[data-theme="neon-lime"][data-sombre="0"] { --ombre-haut:0 8px 26px rgba(77,124,15,.16); }
html[data-theme="neon-lime"][data-sombre="0"] .heros h1 span { text-shadow:none; }

/* ══════════════════ Et la face SOMBRE des univers nés en clair ══════════ */

/* ────────────────────────────── ANDROÏDE de nuit (le mode « piratage ») */
html[data-theme="androide"][data-sombre="1"],
html[data-theme="androide"][data-sombre="1"] [data-matiere] {
  --papier:#2A2822; --carte:#35322B; --carte-creuse:#2F2C26;
  --bord:rgba(203,199,182,.3); --bord-fort:rgba(203,199,182,.55);
  --encre:#E4E0D2; --encre-douce:#C2BEAC; --encre-tenue:#AAA695;
  --accent:#CBC7B6; --accent-pale:rgba(203,199,182,.12); --accent-sombre:#E4E0D2;
  --sur-accent:#2A2822;
}
html[data-theme="androide"][data-sombre="1"] body::after {
  background: repeating-linear-gradient(rgba(203,199,182,.05) 0 1px, transparent 1px 4px);
}
html[data-theme="androide"][data-sombre="1"] .carte-matiere::before,
html[data-theme="androide"][data-sombre="1"] .encart::before,
html[data-theme="androide"][data-sombre="1"] .bandeau-plan::before {
  background:
    linear-gradient(#CBC7B6,#CBC7B6) left  top    / 12px 2px no-repeat,
    linear-gradient(#CBC7B6,#CBC7B6) left  top    / 2px 12px no-repeat,
    linear-gradient(#CBC7B6,#CBC7B6) right bottom / 12px 2px no-repeat,
    linear-gradient(#CBC7B6,#CBC7B6) right bottom / 2px 12px no-repeat;
}
html[data-theme="androide"][data-sombre="1"] .app-tete {
  background:#242219; border-bottom:1px solid rgba(203,199,182,.4);
}
html[data-theme="androide"][data-sombre="1"] .app-tete nav a[aria-current="page"],
html[data-theme="androide"][data-sombre="1"] .pastilles button[aria-pressed="true"],
html[data-theme="androide"][data-sombre="1"] .coche[aria-pressed="true"] {
  background:#CBC7B6; color:#2A2822;
}
html[data-theme="androide"][data-sombre="1"] .app-tete nav a:hover { background:rgba(203,199,182,.14); }

/* ───────────────────── GRAND LARGE de nuit (la mer sous la lune) */
html[data-theme="grand-large"][data-sombre="1"],
html[data-theme="grand-large"][data-sombre="1"] [data-matiere] {
  --papier:#0D2A32; --carte:#16333A; --carte-creuse:#122C33;
  --bord:rgba(216,178,120,.3); --bord-fort:rgba(216,178,120,.55);
  --encre:#EAF6F2; --encre-douce:#B8D6CF; --encre-tenue:#9CC0B9;
  --accent:#63C9BD; --accent-pale:rgba(99,201,189,.14); --accent-sombre:#96E0D6;
  --sur-accent:#062024;
}
html[data-theme="grand-large"][data-sombre="1"] body {
  background-image:
    radial-gradient(ellipse 140% 70% at 50% -10%, rgba(120,190,200,.22), transparent 58%),
    linear-gradient(180deg, #14414B 0%, #0D2A32 55%, #081E24 100%);
}
/* Le parchemin devient une lanterne : sombre, mais toujours cerné de brun. */
html[data-theme="grand-large"][data-sombre="1"] .carte-matiere,
html[data-theme="grand-large"][data-sombre="1"] .chapitre,
html[data-theme="grand-large"][data-sombre="1"] .encart,
html[data-theme="grand-large"][data-sombre="1"] .bandeau-plan,
html[data-theme="grand-large"][data-sombre="1"] .feuille,
html[data-theme="grand-large"][data-sombre="1"] .sommaire {
  background: linear-gradient(180deg, #1B3B42, #16333A);
  border:2px solid #A9793F;
  box-shadow: 0 3px 0 rgba(0,0,0,.35), 0 12px 30px rgba(0,0,0,.4);
}
html[data-theme="grand-large"][data-sombre="1"] .app-tete {
  background: linear-gradient(180deg, #1B3B42, #122C33); border-bottom:2px solid #A9793F;
}
html[data-theme="grand-large"][data-sombre="1"] .app-tete nav a,
html[data-theme="grand-large"][data-sombre="1"] .pastilles button,
html[data-theme="grand-large"][data-sombre="1"] .bouton-hasard,
html[data-theme="grand-large"][data-sombre="1"] .mini,
html[data-theme="grand-large"][data-sombre="1"] .coche {
  background:#1B3B42; border:2px solid #A9793F; color:#EAF6F2;
}
html[data-theme="grand-large"][data-sombre="1"] .app-tete nav a[aria-current="page"],
html[data-theme="grand-large"][data-sombre="1"] .pastilles button[aria-pressed="true"],
html[data-theme="grand-large"][data-sombre="1"] .coche[aria-pressed="true"] {
  background:#63C9BD; color:#062024; border-color:#D8B278;
}

/* ─────────────────── CAHIER ROSE de nuit (la face sombre du carnet) */
html[data-theme="cahier-rose"][data-sombre="1"],
html[data-theme="cahier-rose"][data-sombre="1"] [data-matiere] {
  --papier:#180C14; --carte:#24121E; --carte-creuse:#1E0F19;
  --bord:rgba(255,124,171,.3); --bord-fort:rgba(255,124,171,.55);
  --encre:#FBEAF2; --encre-douce:#DDB3C8; --encre-tenue:#C296AD;
  --accent:#FF7CAB; --accent-pale:rgba(255,124,171,.14); --accent-sombre:#FFAECB;
  --sur-accent:#2A0F1D;
}
html[data-theme="cahier-rose"][data-sombre="1"] body {
  background-image:
    radial-gradient(circle at 12% 8%, rgba(120,30,70,.4), transparent 42%),
    radial-gradient(circle at 88% 4%, rgba(70,20,50,.45), transparent 40%);
}
html[data-theme="cahier-rose"][data-sombre="1"] .carte-matiere,
html[data-theme="cahier-rose"][data-sombre="1"] .chapitre,
html[data-theme="cahier-rose"][data-sombre="1"] .bandeau-plan,
html[data-theme="cahier-rose"][data-sombre="1"] .feuille,
html[data-theme="cahier-rose"][data-sombre="1"] .app-tete {
  border:2px solid rgba(255,124,171,.45);
  box-shadow: 0 4px 0 rgba(255,124,171,.18), 0 10px 26px rgba(0,0,0,.5);
}
html[data-theme="cahier-rose"][data-sombre="1"] .app-tete nav a,
html[data-theme="cahier-rose"][data-sombre="1"] .pastilles button,
html[data-theme="cahier-rose"][data-sombre="1"] .bouton-hasard,
html[data-theme="cahier-rose"][data-sombre="1"] .mini,
html[data-theme="cahier-rose"][data-sombre="1"] .coche {
  background:#24121E; border:1.5px solid rgba(255,124,171,.45); color:#FBEAF2;
}
html[data-theme="cahier-rose"][data-sombre="1"] .app-tete nav a[aria-current="page"],
html[data-theme="cahier-rose"][data-sombre="1"] .pastilles button[aria-pressed="true"],
html[data-theme="cahier-rose"][data-sombre="1"] .coche[aria-pressed="true"] {
  background:#FF7CAB; color:#2A0F1D; border-color:#FF7CAB;
}
html[data-theme="cahier-rose"][data-sombre="1"] .carte-matiere,
html[data-theme="cahier-rose"][data-sombre="1"] .encart {
  background-image: repeating-linear-gradient(transparent 0 27px, rgba(255,124,171,.14) 27px 28px);
}

/* ──────────────────────── CONSOLE BLANCHE de nuit (la console éteinte) */
html[data-theme="console-blanche"][data-sombre="1"],
html[data-theme="console-blanche"][data-sombre="1"] [data-matiere] {
  --papier:#0E141A; --carte:#19222B; --carte-creuse:#141C24;
  --bord:#2C3A46; --bord-fort:#44586A;
  --encre:#E9F1F7; --encre-douce:#B7C7D4; --encre-tenue:#9AAEBD;
  --accent:#4FC3F0; --accent-pale:rgba(79,195,240,.14); --accent-sombre:#8CD9F6;
  --sur-accent:#05131B;
}
html[data-theme="console-blanche"][data-sombre="1"] body {
  background-image: linear-gradient(180deg, #131C24 0%, #0B1116 100%);
}
html[data-theme="console-blanche"][data-sombre="1"] .carte-matiere,
html[data-theme="console-blanche"][data-sombre="1"] .chapitre,
html[data-theme="console-blanche"][data-sombre="1"] .bandeau-plan,
html[data-theme="console-blanche"][data-sombre="1"] .feuille {
  border:2px solid #2C3A46;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.06), 0 2px 6px rgba(0,0,0,.5);
}
html[data-theme="console-blanche"][data-sombre="1"] .carte-matiere:hover {
  border-color:#4FC3F0;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.08), 0 0 0 3px rgba(79,195,240,.25), 0 8px 22px rgba(0,0,0,.55);
}
html[data-theme="console-blanche"][data-sombre="1"] .app-tete {
  background: linear-gradient(180deg, #1A242E, #131A21); border-bottom:1px solid #2C3A46;
}
html[data-theme="console-blanche"][data-sombre="1"] .app-tete nav a,
html[data-theme="console-blanche"][data-sombre="1"] .pastilles button,
html[data-theme="console-blanche"][data-sombre="1"] .bouton-hasard,
html[data-theme="console-blanche"][data-sombre="1"] .mini,
html[data-theme="console-blanche"][data-sombre="1"] .bouton-rond,
html[data-theme="console-blanche"][data-sombre="1"] .coche {
  background: linear-gradient(180deg, #1F2A34, #172029); border:1px solid #2C3A46;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.06); color:#E9F1F7;
}
html[data-theme="console-blanche"][data-sombre="1"] .app-tete nav a[aria-current="page"],
html[data-theme="console-blanche"][data-sombre="1"] .pastilles button[aria-pressed="true"],
html[data-theme="console-blanche"][data-sombre="1"] .coche[aria-pressed="true"] {
  background: linear-gradient(180deg, #4FC3F0, #1E93C4); color:#05131B; border-color:#8CD9F6;
}

/* ──────────────────────────── BLOC-NOTES de nuit (le tableau noir) */
html[data-theme="bloc-notes"][data-sombre="1"],
html[data-theme="bloc-notes"][data-sombre="1"] [data-matiere] {
  --papier:#16201B; --carte:#1E2A24; --carte-creuse:#1A241F;
  --bord:#3C4C43; --bord-fort:#5A6F63;
  --encre:#EDF4EF; --encre-douce:#C2D2C8; --encre-tenue:#A7BAAF;
  --accent:#9BD95C; --accent-pale:rgba(155,217,92,.14); --accent-sombre:#C2EC96;
  --sur-accent:#132009;
  --ressort:#9BD95C;
}
html[data-theme="bloc-notes"][data-sombre="1"] body {
  background-image:
    repeating-linear-gradient(rgba(237,244,239,.07) 0 1px, transparent 1px 26px),
    repeating-linear-gradient(90deg, rgba(237,244,239,.045) 0 1px, transparent 1px 26px);
}
html[data-theme="bloc-notes"][data-sombre="1"] .carte-matiere,
html[data-theme="bloc-notes"][data-sombre="1"] .encart,
html[data-theme="bloc-notes"][data-sombre="1"] .bandeau-plan {
  border:2px solid #EDF4EF; box-shadow: 2px 2px 0 rgba(237,244,239,.28);
}
html[data-theme="bloc-notes"][data-sombre="1"] .app-tete {
  background:#1E2A24; border-bottom:2px solid #EDF4EF;
}
html[data-theme="bloc-notes"][data-sombre="1"] .app-tete nav a,
html[data-theme="bloc-notes"][data-sombre="1"] .pastilles button,
html[data-theme="bloc-notes"][data-sombre="1"] .bouton-hasard,
html[data-theme="bloc-notes"][data-sombre="1"] .mini,
html[data-theme="bloc-notes"][data-sombre="1"] .coche {
  background:#1E2A24; border:2px solid #EDF4EF; color:#EDF4EF;
  box-shadow: 2px 2px 0 rgba(237,244,239,.22);
}
html[data-theme="bloc-notes"][data-sombre="1"] .app-tete nav a[aria-current="page"],
html[data-theme="bloc-notes"][data-sombre="1"] .pastilles button[aria-pressed="true"],
html[data-theme="bloc-notes"][data-sombre="1"] .coche[aria-pressed="true"] {
  background:#9BD95C; color:#132009; border-color:#EDF4EF;
}
html[data-theme="bloc-notes"][data-sombre="1"] .heros h1 span { color:#C2EC96; }

/* ─────────────────────── LIQUID GLASS de nuit (le verre fumé d'iOS) */
html[data-theme="liquid"][data-sombre="1"],
html[data-theme="liquid"][data-sombre="1"] [data-matiere] {
  --papier:#0B1220; --carte:rgba(40,52,74,.6); --carte-creuse:rgba(30,40,58,.5);
  --bord:rgba(255,255,255,.16); --bord-fort:rgba(255,255,255,.28);
  --encre:#EDF2FA; --encre-douce:#BCC8DC; --encre-tenue:#A2B0C8;
  --accent:#7CA3FF; --accent-pale:rgba(124,163,255,.16); --accent-sombre:#A8C2FF;
  --sur-accent:#08101F;
}
html[data-theme="liquid"][data-sombre="1"] body {
  background-image:
    radial-gradient(ellipse 70% 50% at 12% 6%,  rgba(40,90,190,.5), transparent 62%),
    radial-gradient(ellipse 60% 45% at 88% 12%, rgba(95,60,170,.45), transparent 60%),
    radial-gradient(ellipse 80% 50% at 50% 98%, rgba(20,110,110,.4), transparent 64%);
}
html[data-theme="liquid"][data-sombre="1"] .carte-matiere,
html[data-theme="liquid"][data-sombre="1"] .chapitre,
html[data-theme="liquid"][data-sombre="1"] .encart,
html[data-theme="liquid"][data-sombre="1"] .bandeau-plan,
html[data-theme="liquid"][data-sombre="1"] .feuille,
html[data-theme="liquid"][data-sombre="1"] .app-tete {
  border:.5px solid rgba(255,255,255,.18);
  background: linear-gradient(180deg, rgba(56,70,96,.66), rgba(30,40,58,.54));
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.22),
    inset 0 -1px 0 rgba(0,0,0,.3),
    0 8px 30px rgba(0,0,0,.45);
}
html[data-theme="liquid"][data-sombre="1"] .app-tete nav a,
html[data-theme="liquid"][data-sombre="1"] .pastilles button,
html[data-theme="liquid"][data-sombre="1"] .bouton-hasard,
html[data-theme="liquid"][data-sombre="1"] .mini,
html[data-theme="liquid"][data-sombre="1"] .bouton-rond,
html[data-theme="liquid"][data-sombre="1"] .coche {
  border:.5px solid rgba(255,255,255,.2); color:#EDF2FA;
  background: linear-gradient(180deg, rgba(64,80,108,.72), rgba(36,48,68,.6));
  box-shadow: inset 0 1px 0 rgba(255,255,255,.24), 0 2px 10px rgba(0,0,0,.4);
}
html[data-theme="liquid"][data-sombre="1"] .app-tete nav a[aria-current="page"],
html[data-theme="liquid"][data-sombre="1"] .pastilles button[aria-pressed="true"],
html[data-theme="liquid"][data-sombre="1"] .coche[aria-pressed="true"] {
  background: linear-gradient(180deg, #6E97FF, #3F6BE0); color:#08101F;
}
html[data-theme="liquid"][data-sombre="1"] .recherche input {
  background: rgba(30,40,58,.6); color:#EDF2FA; border:.5px solid rgba(255,255,255,.2);
}

/* ───────────────────────────── ZELLIGE de nuit (mosaïque à la lampe) */
html[data-theme="zellige"][data-sombre="1"],
html[data-theme="zellige"][data-sombre="1"] [data-matiere] {
  --papier:#111F1B; --carte:#1A2B26; --carte-creuse:#152420;
  --bord:#32463F; --bord-fort:#4C665C;
  --encre:#E9F2EE; --encre-douce:#BCD2C9; --encre-tenue:#A2BBB1;
  --accent:#49BCA6; --accent-pale:rgba(73,188,166,.14); --accent-sombre:#7FD6C5;
  --sur-accent:#04150F;
}
html[data-theme="zellige"][data-sombre="1"] body {
  background-image:
    repeating-linear-gradient( 45deg, rgba(73,188,166,.06) 0 2px, transparent 2px 18px),
    repeating-linear-gradient(-45deg, rgba(216,178,120,.05) 0 2px, transparent 2px 18px);
}

/* ═══════════════════════ Les titres des univers, rendus incassables ════
   Trois ingrédients qui s'additionnent : une police à chasse fixe, des
   capitales, et un interlettrage. Chacun élargit le titre ; ensemble, un
   intitulé long de chapitre ne tient plus dans un téléphone étroit et pousse
   la page entière — mesuré à 320 px : +10 sur Voxel, +25 sur Détermination,
   +41 sur Midgar. La signature typographique est conservée ; c'est le droit
   de se couper qui manquait, et l'interlettrage qui se resserre en dessous
   de 560 px. Androïde avait déjà reçu ce traitement, pour la même raison. */
html[data-theme="voxel"] h1,        html[data-theme="voxel"] h2,
html[data-theme="pixel"] h1,        html[data-theme="pixel"] h2,
html[data-theme="terminal"] h1,     html[data-theme="terminal"] h2,
html[data-theme="matrix"] h1,       html[data-theme="matrix"] h2,
html[data-theme="crt"] h1,          html[data-theme="crt"] h2,
html[data-theme="midgar"] h1,       html[data-theme="midgar"] h2,
html[data-theme="midgar"] h3,
html[data-theme="determination"] h1, html[data-theme="determination"] h2,
html[data-theme="velours"] h1,      html[data-theme="velours"] h2,
html[data-theme="velours"] h3 { overflow-wrap: anywhere; }

@media (max-width: 560px) {
  html[data-theme="midgar"] h1,        html[data-theme="midgar"] h3,
  html[data-theme="pixel"] h1,         html[data-theme="pixel"] h2,
  html[data-theme="determination"] h1, html[data-theme="determination"] h2,
  html[data-theme="velours"] h1,       html[data-theme="velours"] h2,
  html[data-theme="velours"] h3 { letter-spacing:.01em; }
}

/* ═══════════════════════ CONSOLE BLEUE — le menu d'une console de salon ══
   Demandé : un thème PS4. Ce qu'on reconnaît de ce menu-là tient en
   cinq traits, et aucun n'est une couleur :

     · UNE VAGUE. Le fond n'est pas un bleu uni mais une onde très douce qui
       traverse l'écran en diagonale, plus claire en haut à gauche. C'est elle
       qu'on voit avant tout le reste ;
     · DES TUILES CARRÉES posées sur une seule ligne, sans cadre au repos.
       La sélection ne colore pas la tuile : elle l'entoure d'un filet blanc
       fin et la soulève ;
     · UNE TYPOGRAPHIE MAIGRE, très espacée sur les petites étiquettes, et
       toujours en capitales pour les libellés de service ;
     · AUCUNE BORDURE au repos. Les séparations sont des changements de
       luminosité, pas des traits ;
     · LES QUATRE GLYPHES — croix, rond, carré, triangle — en bas, comme
       légende des commandes.

   Les couleurs sont mesurées, pas choisies : --papier vaut la teinte la plus
   CLAIRE de la vague (#0E3A6B), parce que sur une face sombre c'est elle qui
   met l'encre le plus en danger. Mesuré sur ce fond : encre-tenue 6,04:1,
   accent 5,95:1. */
html[data-theme="console-bleue"], html[data-theme="console-bleue"] [data-matiere] {
  --papier:#0E3A6B; --carte:#12315A; --carte-creuse:#0D2748;
  --bord:rgba(160,205,255,.16); --bord-fort:rgba(160,205,255,.38);
  --encre:#F2F7FF; --encre-douce:#C6DCF4; --encre-tenue:#9FC0E0;
  --accent:#6FC3FF; --accent-pale:rgba(111,195,255,.13); --accent-sombre:#A9DCFF;
  --sur-accent:#04203D;
}
/* LA FACE JOUR. Elle manquait, et le banc a relevé quatre cent cinquante
   textes blancs sur fond blanc : les jetons étaient écrits sans garde de
   face, donc l'encre claire de la nuit servait aussi le jour. C'est la même
   faute que sur Velours et Midgar, commise dans le même quart d'heure — la
   preuve qu'une règle apprise ne se retient pas, et qu'il faut la mesurer.

   Les valeurs sont calculées contre --papier, qui vaut ici la teinte la plus
   SOMBRE de la vague claire (#C9DDF3) : sur une face claire c'est elle qui
   met l'encre le plus en danger. Mesuré : encre-tenue 5,17:1, accent 4,73:1. */
html[data-theme="console-bleue"][data-sombre="0"],
html[data-theme="console-bleue"][data-sombre="0"] [data-matiere] {
  --papier:#C9DDF3; --carte:#FFFFFF; --carte-creuse:#F2F7FD;
  --bord:rgba(11,95,165,.18); --bord-fort:rgba(11,95,165,.40);
  --encre:#0A1E38; --encre-douce:#244463; --encre-tenue:#395A7B;
  --accent:#0B5FA5; --accent-pale:rgba(11,95,165,.10); --accent-sombre:#074B85;
  --sur-accent:#FFFFFF;
}
html[data-theme="console-bleue"][data-sombre="0"] body {
  background-image:
    radial-gradient(ellipse 120% 80% at 12% -20%, rgba(255,255,255,.85), transparent 62%),
    radial-gradient(ellipse 90% 60% at 88% 8%, rgba(160,205,245,.55), transparent 60%),
    linear-gradient(160deg, #EAF3FD 0%, #D8E8F8 55%, #C9DDF3 100%);
  background-attachment: fixed;
}
html[data-theme="console-bleue"][data-sombre="0"] .carte-matiere,
html[data-theme="console-bleue"][data-sombre="0"] .chapitre,
html[data-theme="console-bleue"][data-sombre="0"] .encart,
html[data-theme="console-bleue"][data-sombre="0"] .bandeau-plan,
html[data-theme="console-bleue"][data-sombre="0"] .feuille,
html[data-theme="console-bleue"][data-sombre="0"] .sommaire {
  background: linear-gradient(170deg, rgba(255,255,255,.92), rgba(255,255,255,.68));
}
html[data-theme="console-bleue"][data-sombre="0"] .carte-matiere:hover,
html[data-theme="console-bleue"][data-sombre="0"] .carte-matiere:focus-visible,
html[data-theme="console-bleue"][data-sombre="0"] .chapitre:hover,
html[data-theme="console-bleue"][data-sombre="0"] .chapitre:focus-visible {
  border-color:rgba(11,95,165,.85);
  box-shadow: 0 16px 34px rgba(20,60,110,.18), 0 0 0 1px rgba(11,95,165,.45);
}
html[data-theme="console-bleue"][data-sombre="0"] .app-tete {
  background: linear-gradient(180deg, rgba(255,255,255,.92), rgba(255,255,255,.6));
  border-bottom:1px solid rgba(11,95,165,.16);
}
html[data-theme="console-bleue"][data-sombre="0"] .app-tete nav a,
html[data-theme="console-bleue"][data-sombre="0"] .pastilles button,
html[data-theme="console-bleue"][data-sombre="0"] .bouton-hasard,
html[data-theme="console-bleue"][data-sombre="0"] .mini,
html[data-theme="console-bleue"][data-sombre="0"] .coche {
  background:rgba(11,95,165,.07);
}
html[data-theme="console-bleue"][data-sombre="0"] .app-tete nav a[aria-current="page"],
html[data-theme="console-bleue"][data-sombre="0"] .pastilles button[aria-pressed="true"],
html[data-theme="console-bleue"][data-sombre="0"] .coche[aria-pressed="true"] {
  background:rgba(11,95,165,.16); border-color:rgba(11,95,165,.7);
}

html[data-theme="console-bleue"] {
  --r:4px; --r-l:6px;
  --ombre:0 1px 0 rgba(255,255,255,.06) inset;
  --ombre-haut:0 18px 48px rgba(0,12,30,.55);
}
/* La vague : deux ellipses très étalées et un dégradé de fond. Trois couches
   valent mieux qu'une image — elles suivent la taille de l'écran, ne coûtent
   aucune requête, et restent nettes sur un téléphone comme sur un moniteur. */
html[data-theme="console-bleue"][data-sombre="1"] body {
  background-image:
    radial-gradient(ellipse 120% 80% at 12% -20%, rgba(120,190,255,.30), transparent 62%),
    radial-gradient(ellipse 90% 60% at 88% 8%, rgba(60,130,215,.22), transparent 60%),
    linear-gradient(160deg, #0B2B54 0%, #071B36 55%, #050F22 100%);
  background-attachment: fixed;
}
/* Les tuiles : pas de cadre au repos, un filet blanc et un soulèvement à la
   sélection. C'est le geste exact du menu — la tuile ne change pas de
   couleur, elle SORT. */
html[data-theme="console-bleue"] .carte-matiere,
html[data-theme="console-bleue"] .chapitre,
html[data-theme="console-bleue"] .encart,
html[data-theme="console-bleue"] .bandeau-plan,
html[data-theme="console-bleue"] .feuille,
html[data-theme="console-bleue"] .sommaire {
  border:1px solid transparent;
  background: linear-gradient(170deg, rgba(255,255,255,.07), rgba(255,255,255,.02));
  box-shadow:none;
  transition: transform .18s cubic-bezier(.2,.7,.3,1), box-shadow .18s, border-color .18s;
}
html[data-theme="console-bleue"] .carte-matiere:hover,
html[data-theme="console-bleue"] .carte-matiere:focus-visible,
html[data-theme="console-bleue"] .chapitre:hover,
html[data-theme="console-bleue"] .chapitre:focus-visible {
  border-color:rgba(255,255,255,.85);
  transform: translateY(-4px);
  box-shadow: 0 16px 34px rgba(0,10,28,.6), 0 0 0 1px rgba(255,255,255,.35);
}
html[data-theme="console-bleue"] .app-tete {
  background: linear-gradient(180deg, rgba(8,26,52,.92), rgba(8,26,52,.55));
  border-bottom:1px solid rgba(160,205,255,.14);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
}
/* Les libellés de service en capitales très espacées : c'est la signature
   typographique de ce menu, et elle ne coûte pas une police de plus. */
html[data-theme="console-bleue"] .app-tete nav a,
html[data-theme="console-bleue"] .pastilles button,
html[data-theme="console-bleue"] .niveau,
html[data-theme="console-bleue"] .encart .titre {
  text-transform: uppercase; letter-spacing:.14em; font-weight:600;
  overflow-wrap: anywhere;
}
html[data-theme="console-bleue"] .app-tete nav a,
html[data-theme="console-bleue"] .pastilles button,
html[data-theme="console-bleue"] .bouton-hasard,
html[data-theme="console-bleue"] .mini,
html[data-theme="console-bleue"] .coche {
  border:1px solid transparent; background:rgba(255,255,255,.06);
  border-radius:4px;
}
html[data-theme="console-bleue"] .app-tete nav a[aria-current="page"],
html[data-theme="console-bleue"] .pastilles button[aria-pressed="true"],
html[data-theme="console-bleue"] .coche[aria-pressed="true"] {
  background:rgba(255,255,255,.14); border-color:rgba(255,255,255,.8);
  color:var(--encre);
}
/* Le titre de page : maigre et large, posé sur un filet lumineux vertical —
   le « MAIN MENU » écrit dans la marge. */
html[data-theme="console-bleue"] .tete-matiere,
html[data-theme="console-bleue"] .fiche-tete {
  border-left:2px solid var(--accent); padding-left:1rem;
}
html[data-theme="console-bleue"] h1 { font-weight:300; letter-spacing:.01em; }
html[data-theme="console-bleue"] h2 { font-weight:400; }
/* Les quatre glyphes de manette, en pied de page : la légende des commandes.
   Ils ne servent à rien et c'est leur rôle — ils disent de quel monde vient
   ce thème, comme la réglure du cahier ou les créneaux du château. */
html[data-theme="console-bleue"] .app-pied::after {
  content:"✕  ◯  ▢  △"; display:block; margin-top:.8rem;
  font-family:var(--mono); font-size:.78rem; letter-spacing:.5em;
  color:var(--encre-tenue); text-align:center;
}

/* ══════════════════ CONSOLE BLANCHE — le menu de la Wii, à l'identique ══
   Demandé : pour « console blanche », un style entièrement différent des
   autres — reproduire le menu de la Wii à l'identique, avec ses
   paramètres et ses chaînes.

   Ce menu-là ne se reconnaît pas à sa couleur — il est presque blanc, comme
   dix autres thèmes. Il se reconnaît à SA GRILLE et à SA BARRE :

     · des CHAÎNES carrées, toutes de la même taille, rangées en grille
       régulière avec un écart généreux. Jamais une carte plus large qu'une
       autre : c'est la régularité qui fait le menu ;
     · chaque chaîne est une tuile laquée — liseré gris très clair, angle à
       peine arrondi, reflet blanc en haut, ombre courte en bas ;
     · au survol, un HALO BLEU CLAIR qui déborde de la tuile, et rien
       d'autre : ni couleur de fond, ni déplacement brusque ;
     · une BARRE GRISE en bas d'écran, séparée du reste par un trait, qui
       porte les boutons ronds — c'est elle qui donne l'échelle de tout le
       reste ;
     · une typographie petite, grise, et l'heure en gros au milieu.

   Ces règles ne touchent PAS les couleurs mesurées plus haut : elles ne
   posent que des formes. C'est la condition pour que les quarante thèmes
   restent contrôlables par un seul banc. */
html[data-theme="console-blanche"][data-sombre="0"] body {
  background-image:
    linear-gradient(180deg, #FDFEFF 0%, #EFF4F8 62%, #E3EAF0 100%);
  background-attachment: fixed;
}
/* La grille des chaînes : des carrés, tous égaux. « auto-fit » avec un
   minimum ET un maximum identiques force la régularité — sans le maximum,
   la dernière rangée s'étire et la grille cesse d'être une grille. */
html[data-theme="console-blanche"] .grille-matieres,
html[data-theme="console-blanche"] .grille-chapitres {
  grid-template-columns: repeat(auto-fit, minmax(min(210px, 100%), 210px));
  justify-content: center; gap: 1.15rem;
}
html[data-theme="console-blanche"] .carte-matiere,
html[data-theme="console-blanche"] .chapitre {
  border-radius:10px;
  transition: box-shadow .2s ease, border-color .2s ease;
}
html[data-theme="console-blanche"][data-sombre="0"] .carte-matiere,
html[data-theme="console-blanche"][data-sombre="0"] .chapitre {
  border:1px solid #CFDCE6;
  background: linear-gradient(180deg, #FFFFFF 0%, #FFFFFF 52%, #F3F7FA 100%);
  box-shadow: inset 0 1px 0 #FFFFFF, inset 0 -14px 20px -14px rgba(120,150,175,.28),
              0 2px 3px rgba(40,60,80,.10);
}
/* La face nuit garde la laque, mais retournée : le même reflet en haut, la
   même ombre en bas, sur un gris d'ardoise. C'est la console éteinte. */
html[data-theme="console-blanche"][data-sombre="1"] .carte-matiere,
html[data-theme="console-blanche"][data-sombre="1"] .chapitre {
  border:1px solid rgba(160,190,210,.22);
  background: linear-gradient(180deg, rgba(255,255,255,.07) 0%,
                              rgba(255,255,255,.04) 52%, rgba(0,0,0,.10) 100%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.14), 0 2px 3px rgba(0,0,0,.24);
}
/* Le halo. Il DÉBORDE — c'est ce qui le distingue d'une bordure épaissie, et
   c'est exactement ce que fait le pointeur de la manette sur une chaîne. */
html[data-theme="console-blanche"] .carte-matiere:hover,
html[data-theme="console-blanche"] .carte-matiere:focus-visible,
html[data-theme="console-blanche"] .chapitre:hover,
html[data-theme="console-blanche"] .chapitre:focus-visible {
  border-color:#8ECCE8;
  box-shadow: inset 0 1px 0 #FFFFFF,
              0 0 0 4px rgba(120,200,232,.38), 0 0 22px 6px rgba(95,184,224,.30),
              0 4px 10px rgba(40,60,80,.14);
}
/* La barre du bas : un bandeau gris séparé par un trait net, avec ses deux
   boutons ronds aux extrémités. C'est l'élément qui « fait Wii » plus que
   tout le reste, et le pied de page en tient lieu. */
html[data-theme="console-blanche"][data-sombre="0"] .app-pied {
  position:relative; margin-top:3rem; padding:1.5rem 4.6rem 1.7rem;
  background: linear-gradient(180deg, #E7EDF2, #DAE3EA);
  border-top:2px solid #C3D2DD;
  box-shadow: inset 0 2px 0 #FFFFFF;
}
html[data-theme="console-blanche"][data-sombre="0"] .app-pied::before,
html[data-theme="console-blanche"][data-sombre="0"] .app-pied::after {
  content:""; position:absolute; bottom:50%; width:46px; height:46px;
  margin-bottom:-23px; border-radius:50%;
  background: radial-gradient(circle at 36% 30%, #FFFFFF, #E4EBF1 70%, #CBD7E0);
  border:1px solid #BCCBD6;
  box-shadow: inset 0 1px 0 #FFFFFF, 0 1px 3px rgba(40,60,80,.18);
}
html[data-theme="console-blanche"][data-sombre="0"] .app-pied::before { left:1.1rem; }
html[data-theme="console-blanche"][data-sombre="0"] .app-pied::after  { right:1.1rem; }
/* La typographie du menu : petite, grise, sans emphase. Les titres de chaîne
   y sont posés comme des étiquettes, pas comme des titres de presse. */
html[data-theme="console-blanche"] .carte-matiere h2,
html[data-theme="console-blanche"] .chapitre h3 {
  font-size:.96rem; font-weight:600; letter-spacing:-.005em;
}
html[data-theme="console-blanche"] .app-tete nav a,
html[data-theme="console-blanche"] .pastilles button {
  border-radius:999px;
}

/* ═════════════════ GRAND LARGE — le menu d'objets de Wind Waker ═════════
   Demandé : la même chose pour « Grand Large » — le menu d'objets de
   Zelda Wind Waker, à l'identique.

   Ce menu-là est une TOILE VERTE tendue, sur laquelle on a cousu des cases.
   Quatre traits le font reconnaître :

     · le fond est un vert d'herbe mat, légèrement moucheté — pas un dégradé
       lisse, une étoffe ;
     · les objets sont dans des CASES CARRÉES cernées d'un filet doré fin,
       séparées par des cloisons plus claires. La grille est visible, et
       c'est elle qui organise tout ;
     · la sélection n'est pas une couleur : ce sont QUATRE ÉQUERRES blanches
       aux angles de la case ;
     · les titres sont sur des plaques de bois sombre à liseré doré, et le
       nom de l'objet s'affiche en bas sur une plaque verte plus claire.

   Le thème gardait déjà le parchemin et le brun chaud ; ce qui manquait,
   c'est la grille cousue et les équerres. */
/* ── Le vert est le PANNEAU, pas la page ────────────────────────────────
   Première version : j'avais peint tout le fond en herbe. Le banc a relevé
   125 textes sous le seuil, et « Vu récemment » est tombé de 2,94 à 2,38 —
   ma « correction » avait empiré les choses. Deux erreurs, et la seconde
   était la plus grossière :

     · j'avais calculé la lisibilité contre la mauvaise encre. L'intitulé
       fautif est un gris clair qui ne tenait que sur le fond très pâle du
       thème : il lui faut un fond de luminance 0,9, c'est-à-dire presque
       blanc. Aucun vert d'herbe ne peut convenir ;
     · « --papier » n'est pas seulement la couleur du fond de page : c'est un
       JETON, lu par tout ce qui a besoin de la teinte du papier. Le passer en
       vert saturé a déplacé des dizaines de surfaces d'un coup.

   Or, en regardant la capture fournie plutôt que mon souvenir : dans le jeu,
   le vert n'est pas le fond de l'écran, c'est l'ÉTOFFE DU PANNEAU d'objets,
   posée sur le monde. Ici, la page reste le parchemin clair, et la grille des
   matières devient la toile verte cousue. C'est à la fois plus fidèle et
   lisible — les deux allaient ensemble depuis le début. */
html[data-theme="grand-large"][data-sombre="0"] .grille-matieres,
html[data-theme="grand-large"][data-sombre="0"] .grille-chapitres {
  gap:.55rem; padding:.8rem; border-radius:12px;
  background-image:
    radial-gradient(circle at 20% 15%, rgba(255,255,255,.16) 0 2px, transparent 3px),
    radial-gradient(circle at 70% 60%, rgba(0,0,0,.06) 0 2px, transparent 3px),
    linear-gradient(180deg, #8FBE64, #6E9F4C);
  background-size: 26px 26px, 34px 34px, auto;
  border:3px solid #8A6A32;
  box-shadow: inset 0 0 0 2px rgba(255,247,214,.45),
              0 4px 0 rgba(90,64,28,.3);
}
html[data-theme="grand-large"][data-sombre="0"] .carte-matiere,
html[data-theme="grand-large"][data-sombre="0"] .chapitre {
  position:relative; border-radius:6px;
  border:2px solid #A9793F;
  background: linear-gradient(180deg, rgba(255,248,228,.96), rgba(240,226,190,.96));
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.7), 0 2px 0 rgba(90,64,28,.35);
}
/* Les quatre équerres de la sélection. Deux pseudo-éléments suffisent : le
   premier porte les angles du haut, le second ceux du bas, chacun avec deux
   bordures. C'est ainsi que le jeu dessine son curseur — et c'est beaucoup
   plus lisible qu'un cadre plein, parce que l'objet reste entièrement
   visible dessous. */
html[data-theme="grand-large"] .carte-matiere::before,
html[data-theme="grand-large"] .carte-matiere::after,
html[data-theme="grand-large"] .chapitre::before,
html[data-theme="grand-large"] .chapitre::after {
  content:""; position:absolute; width:16px; height:16px;
  opacity:0; transition:opacity .14s ease;
  border-color:#FFFFFF; border-style:solid;
  filter: drop-shadow(0 1px 1px rgba(40,28,8,.5));
  pointer-events:none;
}
html[data-theme="grand-large"] .carte-matiere::before,
html[data-theme="grand-large"] .chapitre::before {
  left:-5px; top:-5px; border-width:3px 0 0 3px;
  box-shadow: 226px 0 0 -3px #FFF;   /* l'angle haut-droit, par l'ombre */
}
html[data-theme="grand-large"] .carte-matiere::after,
html[data-theme="grand-large"] .chapitre::after {
  left:-5px; bottom:-5px; border-width:0 0 3px 3px;
}
html[data-theme="grand-large"] .carte-matiere:hover::before,
html[data-theme="grand-large"] .carte-matiere:hover::after,
html[data-theme="grand-large"] .carte-matiere:focus-visible::before,
html[data-theme="grand-large"] .carte-matiere:focus-visible::after,
html[data-theme="grand-large"] .chapitre:hover::before,
html[data-theme="grand-large"] .chapitre:hover::after,
html[data-theme="grand-large"] .chapitre:focus-visible::before,
html[data-theme="grand-large"] .chapitre:focus-visible::after { opacity:1; }
/* Les plaques de bois : les titres de section du menu. */
html[data-theme="grand-large"][data-sombre="0"] .tete-matiere h1,
html[data-theme="grand-large"][data-sombre="0"] .fiche-tete h1 {
  display:inline-block; padding:.45rem 1.4rem; border-radius:8px;
  color:#FFF6DC; background: linear-gradient(180deg, #6B4A24, #4E351A);
  border:3px solid #C89B4E;
  box-shadow: inset 0 1px 0 rgba(255,246,220,.35), 0 3px 0 rgba(40,28,8,.4);
}

/* ══════════════════ MIDGAR — le menu de Final Fantasy VII Remake ════════
   Les captures du menu principal du Remake ont été fournies. Ce qui le fait
   reconnaître n'est pas le bleu — c'est la CHARPENTE :

     · un cadre lumineux fin qui court tout autour de l'écran, avec un petit
       LOSANGE à chaque angle. C'est la première chose qu'on voit ;
     · une liste à gauche, dont la ligne choisie est barrée d'un DÉGRADÉ
       horizontal clair qui s'éteint vers la droite — jamais un aplat ;
     · une étiquette VERTICALE dans la marge (« MAIN MENU ») ;
     · des capitales maigres très espacées, et des chiffres deux fois plus
       gros que leur libellé ;
     · aucun angle arrondi : tout est coupé à 90°, et les séparations sont
       des filets d'un pixel.

   Le thème avait déjà les panneaux bleu nuit et le filet cyan. On ajoute la
   charpente, les losanges et le dégradé de sélection. */
html[data-theme="midgar"] .page,
html[data-theme="midgar"] .contenu { position:relative; }
html[data-theme="midgar"] .contenu::before {
  content:""; position:fixed; inset:12px; pointer-events:none; z-index:2;
  border:1px solid rgba(126,206,255,.34);
}
/* Les quatre losanges des angles. Un seul pseudo-élément, quatre copies par
   « box-shadow » : le losange est un carré tourné de 45°, et les trois
   autres sont ses ombres portées — aucun nœud supplémentaire dans le HTML. */
html[data-theme="midgar"] .contenu::after {
  content:""; position:fixed; left:12px; top:12px; width:9px; height:9px;
  margin:-4px 0 0 -4px; pointer-events:none; z-index:3;
  background:#9FDCFF; transform:rotate(45deg);
  box-shadow: 0 0 6px 1px rgba(126,206,255,.8);
}
html[data-theme="midgar"] .carte-matiere,
html[data-theme="midgar"] .chapitre,
html[data-theme="midgar"] .encart,
html[data-theme="midgar"] .bandeau-plan {
  border-radius:0; border-left:2px solid rgba(126,206,255,.5);
}
html[data-theme="midgar"][data-sombre="1"] .carte-matiere,
html[data-theme="midgar"][data-sombre="1"] .chapitre,
html[data-theme="midgar"][data-sombre="1"] .encart,
html[data-theme="midgar"][data-sombre="1"] .bandeau-plan {
  background: linear-gradient(100deg, rgba(20,46,82,.86), rgba(12,28,54,.62) 72%);
}
html[data-theme="midgar"][data-sombre="0"] .carte-matiere,
html[data-theme="midgar"][data-sombre="0"] .chapitre,
html[data-theme="midgar"][data-sombre="0"] .encart,
html[data-theme="midgar"][data-sombre="0"] .bandeau-plan {
  background: linear-gradient(100deg, rgba(232,243,253,.94), rgba(248,251,255,.7) 72%);
}
/* La sélection : un dégradé qui s'éteint vers la droite, et un trait blanc à
   gauche. C'est le geste exact du menu — la ligne s'allume par la gauche. */
html[data-theme="midgar"] .carte-matiere:hover,
html[data-theme="midgar"] .carte-matiere:focus-visible,
html[data-theme="midgar"] .chapitre:hover,
html[data-theme="midgar"] .chapitre:focus-visible {
  border-left-color: var(--encre);
  box-shadow: inset 0 0 0 1px rgba(159,220,255,.38);
}
html[data-theme="midgar"][data-sombre="1"] .carte-matiere:hover,
html[data-theme="midgar"][data-sombre="1"] .chapitre:hover {
  background: linear-gradient(100deg, rgba(150,215,255,.34), rgba(20,46,82,.5) 68%);
}
html[data-theme="midgar"][data-sombre="0"] .carte-matiere:hover,
html[data-theme="midgar"][data-sombre="0"] .chapitre:hover {
  background: linear-gradient(100deg, rgba(120,185,240,.30), rgba(248,251,255,.8) 68%);
}
/* L'étiquette verticale de la marge. Elle n'existe que sur grand écran :
   sous mille pixels, elle mordrait sur le texte, et une signature qui gêne
   la lecture n'est plus une signature. */
@media (min-width: 1100px) {
  html[data-theme="midgar"] .tete-matiere { position:relative; }
  html[data-theme="midgar"] .tete-matiere::before {
    content:"MAIN MENU"; position:absolute; left:-2.6rem; top:0;
    writing-mode:vertical-rl; font-family:var(--mono); font-size:.66rem;
    letter-spacing:.42em; color:rgba(159,220,255,.6);
  }
}
html[data-theme="midgar"] .app-tete nav a,
html[data-theme="midgar"] .pastilles button,
html[data-theme="midgar"] .mini, html[data-theme="midgar"] .coche {
  border-radius:0; text-transform:uppercase; letter-spacing:.16em;
  font-weight:500; overflow-wrap:anywhere;
}

/* ═══════════════════════ VELOURS — le menu de Persona 5 ════════════════
   Les captures du menu et des commandes ont été fournies. Ce style-là est le
   plus bruyant des quarante, et c'est voulu : il n'a pas de règle douce.

     · TOUT EST DE TRAVERS. Les panneaux penchent, les boutons penchent, et
       ils penchent dans des sens différents ;
     · les angles sont COUPÉS en pointe, jamais arrondis — un polygone, pas
       un rectangle ;
     · le rouge n'est pas un accent, c'est le FOND ; le noir découpe ;
     · la sélection ne surligne pas : elle SORT du cadre, projetée, avec un
       liseré blanc épais ;
     · les titres sont en capitales lourdes et légèrement inclinées.

   Le cadre penche, jamais le contenu : chaque panneau incliné redresse ses
   enfants d'autant. Sans ce redressement, la page entière gîte et le texte
   devient pénible — c'est la règle déjà posée pour ce thème, on l'étend. */
/* LA FORME est commune aux deux faces — c'est elle, le thème. LA COULEUR ne
   l'est pas : un panneau noir sur la face claire, dont l'encre est sombre,
   donne 1,01:1. Le banc a relevé 509 textes d'un coup, tous pour cette seule
   faute, répétée sur trois thèmes. C'est la leçon déjà écrite au chapitre 18
   du journal — « un thème sombre ne se juge pas à l'œil » — et je l'ai
   refaite en peignant une face avec la palette de l'autre. */
html[data-theme="velours"] .carte-matiere,
html[data-theme="velours"] .chapitre {
  border-radius:0;
  clip-path: polygon(0 0, calc(100% - 18px) 0, 100% 18px, 100% 100%, 18px 100%, 0 calc(100% - 18px));
  border:2px solid #0B0B0B;
  transform: skewY(-.8deg);
  transition: transform .16s cubic-bezier(.2,.8,.3,1.2), box-shadow .16s;
}
html[data-theme="velours"] .carte-matiere > *,
html[data-theme="velours"] .chapitre > * { transform: skewY(.8deg); }
html[data-theme="velours"][data-sombre="1"] .carte-matiere,
html[data-theme="velours"][data-sombre="1"] .chapitre {
  background: linear-gradient(135deg, #16090B 0%, #2A0C10 60%, #3A0E14 100%);
}
/* De jour, Persona reste Persona : le rouge et le noir découpent une page
   BLANCHE. C'est d'ailleurs la moitié du style du jeu — ses menus alternent
   les deux, ils ne sont pas noirs en permanence. */
html[data-theme="velours"][data-sombre="0"] .carte-matiere,
html[data-theme="velours"][data-sombre="0"] .chapitre {
  background: linear-gradient(135deg, #FFFFFF 0%, #FBF3F3 60%, #F6E7E8 100%);
}
html[data-theme="velours"] .carte-matiere:hover,
html[data-theme="velours"] .carte-matiere:focus-visible,
html[data-theme="velours"] .chapitre:hover,
html[data-theme="velours"] .chapitre:focus-visible {
  transform: skewY(-.8deg) translate(-5px, -5px) scale(1.02);
  box-shadow: 8px 8px 0 #E60012, 0 0 0 3px #FFFFFF;
}
html[data-theme="velours"] .tete-matiere h1,
html[data-theme="velours"] .fiche-tete h1 {
  display:inline-block; transform: skewX(-6deg);
  text-transform:uppercase; font-weight:900; letter-spacing:.01em;
  padding:.3rem .9rem; color:#FFFFFF; background:#0B0B0B;
  box-shadow: 6px 6px 0 #E60012;
}
/* Les étoiles du fond : le motif de découpe du jeu, en très discret. Elles
   ne doivent pas passer derrière le texte au point de le gêner — 4 % suffit
   à ce que l'œil sente le motif sans le lire. */
html[data-theme="velours"][data-sombre="1"] body {
  background-image:
    repeating-conic-gradient(from 18deg at 12% 8%,
      rgba(255,255,255,.045) 0 6deg, transparent 6deg 24deg),
    repeating-conic-gradient(from 42deg at 88% 72%,
      rgba(230,0,18,.06) 0 5deg, transparent 5deg 22deg),
    linear-gradient(160deg, #120507 0%, #1C0709 60%, #0B0405 100%);
  background-attachment: fixed;
}
html[data-theme="velours"] .app-tete nav a,
html[data-theme="velours"] .pastilles button {
  clip-path: polygon(0 0, calc(100% - 9px) 0, 100% 9px, 100% 100%, 9px 100%, 0 calc(100% - 9px));
  border-radius:0; text-transform:uppercase; font-weight:800;
  overflow-wrap:anywhere;
}

/* ══════════════════════════════════════════════════════════════════════════
   LES DISPOSITIONS — quand un thème déplace le HTML
   ══════════════════════════════════════════════════════════════════════════
   Demandé : le menu de la Wii comme thème à part entière — donc revoir
   le CSS, le style, et jusqu'au HTML.

   Ce qui avait été livré était une peinture : les bonnes couleurs sur la
   disposition du site. Un menu de console ne se reconnaît pas à ses couleurs
   mais à sa DISPOSITION — des cases toutes égales, une barre en bas, l'heure
   au centre de cette barre.

   Le thème se choisit dans le navigateur, APRÈS la génération des pages : il
   ne peut donc pas réécrire leur balisage. Il peut ranger autrement ce qui
   existe — c'est ici — et recevoir le décor que le CSS ne sait pas produire,
   une horloge qui avance et des flèches qui tournent des pages, que app.js
   bâtit. Aucune des 244 pages n'a changé d'une ligne.

   ── 1. la Wii ──────────────────────────────────────────────────────────── */

/* La barre du bas couvre 4,6 rem : le contenu lui cède la place, sinon le
   dernier rang de chaînes se retrouve dessous et devient inatteignable. */
html[data-dispo="wii"] body { padding-bottom: 5.4rem; }

/* LE FOND. Mesuré avant d'être choisi : le thème « Console blanche » posait
   un papier à #EBF0F4 et mes chaînes un blanc dégradé vers #EFF4F8 — à l'œil
   comme à la mesure, des cases blanches sur un fond blanc. Elles étaient bien
   là, à 242 px de côté, simplement invisibles.
   Sur la console, les chaînes blanches se détachent sur un BLEU-GRIS. C'est
   donc le fond qui devait changer, pas les cases. La valeur basse du dégradé
   devient « --papier » : pour une face claire, c'est la zone la plus SOMBRE
   qui donne la mesure la plus dure, et le banc de contraste doit mesurer
   celle-là. L'encre #26333C y tient 8,2:1. */
/* ── Le papier bleu coûte une encre ─────────────────────────────────────
   Le banc de contraste a rendu **65 éléments sous le seuil, tous à 3,91 : 1,
   tous sur « console-blanche (jour) »**. Une seule valeur répétée soixante-
   cinq fois, ce n'est pas soixante-cinq problèmes : c'est une paire.
   Vérification faite, c'est « --encre-tenue » (#4E6675) : elle avait été
   choisie contre le papier du thème (#EBF0F4), où elle vaut 5,26. Sur le
   papier de la disposition Wii (#BFD3E0), elle tombe à 3,91 — exactement la
   valeur du banc.

   Changer le papier d'un thème, c'est changer le fond de TOUTES ses encres.
   Celle-ci redescend donc d'un ton — teinte et saturation gardées, seule la
   luminosité baisse — et elle repasse partout : 4,88 sur le bas du dégradé,
   6,05 sur le haut, 7,54 sur une chaîne blanche. Elle reste plus claire que
   « --encre-douce » (5,38), donc elle dit toujours la même chose dans la
   hiérarchie : une encre retenue. */
/* ── Et il faut le dire DEUX FOIS, comme le thème le dit ────────────────
   Deuxième mesure, et elle a rendu le même 3,91 : la correction ci-dessus
   n'était posée que sur « html ». Or le thème déclare sa palette sur DEUX
   sélecteurs — « html[data-theme=…] » **et** « html[data-theme=…]
   [data-matiere] » —, et le « body » porte « data-matiere ». Tout ce qui est
   dans le corps relisait donc la palette d'origine : l'encre, mais aussi le
   papier, qui valait encore #EBF0F4 à l'intérieur du body pendant que html
   portait #BFD3E0. La disposition n'était appliquée qu'à moitié, et seul le
   dégradé posé sur « body » faisait croire le contraire.

   Une surcharge doit couvrir tous les sélecteurs que la chose surchargée
   emploie, sinon elle ne surcharge que le plus visible d'entre eux. */
html[data-dispo="wii"][data-dispo-menu][data-sombre="0"],
html[data-dispo="wii"][data-dispo-menu][data-sombre="0"] [data-matiere] {
  --papier: #BFD3E0; --encre-tenue: #435764; --accent-sombre: #045570; }
/* Troisième passage du banc, dernier élément : « span.cat-ic » sur la page
   des outils, à 4,34 : 1. Son fond propre est « --accent-pale », une teinte
   à 10 % — donc le papier le TRAVERSE, et sur le bleu de la disposition le
   composé descend à rgb(173,202,218). L'encre, « --accent-sombre », avait été
   choisie contre du blanc. Elle descend d'un ton elle aussi : 4,82 sur le pire
   composé, 5,88 sur le plus clair, 8,27 sur blanc.
   Un fond translucide n'est pas un fond : c'est une fenêtre sur ce qu'il y a
   dessous, et changer ce qu'il y a dessous change sa couleur. */
html[data-dispo="wii"][data-dispo-menu][data-sombre="0"] body {
  background: linear-gradient(#DCE8F0 0%, #BFD3E0 100%) fixed;
}
html[data-dispo="wii"][data-dispo-menu][data-sombre="1"],
html[data-dispo="wii"][data-dispo-menu][data-sombre="1"] [data-matiere] { --papier: #1B2730; }
html[data-dispo="wii"][data-dispo-menu][data-sombre="1"] body {
  background: linear-gradient(#263642 0%, #1B2730 100%) fixed;
}
/* De nuit, les chaînes ne peuvent pas rester blanc laqué : elles brûleraient.
   Elles prennent l'ardoise, et c'est le liseré bleu qui porte la lumière. */
html[data-dispo="wii"][data-sombre="1"] .contenu .carte-matiere,
html[data-dispo="wii"][data-sombre="1"] .liste-chapitres .chapitre {
  background: linear-gradient(#2E3E4B 0%, #2E3E4B 62%, #263642 100%);
  border-color: #3E525F;
  box-shadow: 0 1px 0 rgba(255,255,255,.06) inset, 0 3px 10px rgba(0,0,0,.3);
}
html[data-dispo="wii"] .app-pied { display: none; }

/* L'en-tête se fait oublier : sur le menu d'une console, rien ne précède les
   chaînes. On la garde — c'est la seule navigation du site — mais réduite. */
html[data-dispo="wii"] .app-tete { box-shadow: none; background: transparent; }
html[data-dispo="wii"] .heros, html[data-dispo="wii"] .chiffres,
html[data-dispo="wii"] .bandeau-plan { opacity: .92; }

/* LES CHAÎNES. Des carrés tous égaux, blanc laqué, coins très arrondis,
   gouttières larges et régulières. « aspect-ratio: 1 » fait le carré sans
   hauteur écrite en dur — donc le réglage de taille du lecteur le conserve. */
/* ── Le plancher de colonne décide de tout ──────────────────────────────
   Il valait 190 px, et une chaîne de chapitre était COUPÉE : à 240 px de
   côté, son contenu — le titre, la phrase, et les quatre boutons Cours /
   Exercices / Fiche / QCM — en demande 279. « overflow: hidden » faisait le
   reste sans rien dire, et le titre « Assemblage d'un PC » s'affichait
   « d'un PC ».

   La cause est dans « auto-fill » : plus l'écran est large, plus il ajoute de
   colonnes, et chacune retombe près du minimum. La largeur d'une colonne ne
   dépend donc pas de l'écran — elle dépend du PLANCHER. Et comme le carré
   fait la hauteur égale à la largeur, c'est le plancher, et lui seul, qui
   doit être assez haut pour le contenu.

   Mesuré de 640 à 1760 px de grille : à 270 px, le carré tient partout, le
   plus serré gardant 26 px de rab. */
html[data-dispo="wii"] .contenu .grille-matieres,
html[data-dispo="wii"] .liste-chapitres {
  display: grid; gap: 1.5rem;
  grid-template-columns: repeat(auto-fill, minmax(min(270px, 100%), 1fr));
}
html[data-dispo="wii"] .contenu .carte-matiere,
html[data-dispo="wii"] .liste-chapitres .chapitre {
  aspect-ratio: 1; display: flex; flex-direction: column;
  justify-content: center; align-items: center; text-align: center;
  padding: 1rem .9rem; gap: .45rem; overflow: hidden;
  border-radius: 20px; border: 1px solid #D5DEE6;
  background: linear-gradient(#FFFFFF 0%, #FFFFFF 62%, #EFF4F8 100%);
  box-shadow: 0 2px 0 #FFF inset, 0 4px 12px rgba(30,60,90,.22);
  transition: box-shadow .18s, transform .18s;
}
/* La case choisie prend le cadre bleu lumineux de la console. Le focus REÇOIT
   le même traitement que le survol : au clavier aussi, on doit voir où l'on
   est — et c'est la seule façon de rendre la grille utilisable sans souris. */
html[data-dispo="wii"] .contenu .carte-matiere:hover,
html[data-dispo="wii"] .contenu .carte-matiere:focus-visible,
html[data-dispo="wii"] .liste-chapitres .chapitre:hover,
html[data-dispo="wii"] .liste-chapitres .chapitre:focus-within {
  transform: translateY(-2px);
  box-shadow: 0 0 0 3px #4FC3F7, 0 0 16px 2px rgba(79,195,247,.65),
              0 6px 16px rgba(40,70,100,.2);
}
html[data-dispo="wii"] .contenu .carte-matiere p,
html[data-dispo="wii"] .liste-chapitres .chapitre p {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; font-size: .76rem; line-height: 1.4;
}
/* ── Ce qui traverse la rangée n'est pas une chaîne ─────────────────────
   La carte « Reprendre » porte « grid-column: 1 / -1 » : elle traverse toute
   la grille. Mise au carré, elle mesurait **1245 × 1245** — un carré plus
   haut que l'écran, qui poussait les six matières hors de vue. Le carré n'a
   de sens que pour une case de grille ; dès qu'un élément prend la rangée
   entière, il redevient une bande. Même raison pour « .recents ». */
html[data-dispo="wii"] .contenu .carte-matiere.reprise {
  aspect-ratio: auto; flex-direction: row; justify-content: flex-start;
  text-align: left; gap: .6rem; padding: .9rem 1.1rem; border-radius: 16px;
}
html[data-dispo="wii"] .contenu .carte-matiere.reprise > * { width: auto; }
html[data-dispo="wii"] .contenu .carte-matiere .ic { font-size: 1.9rem; }
html[data-dispo="wii"] .contenu .carte-matiere::after { display: none; }
html[data-dispo="wii"] .liste-chapitres .chapitre > * { width: 100%; }

/* « display: flex » écrase « [hidden] », qui n'est qu'un « display: none » de
   la feuille du navigateur. Sans cette règle, la pagination marquait bien les
   cases en trop — et elles restaient à l'écran. Toute règle d'affichage posée
   sur un élément paginé doit rendre son « hidden » à nouveau. */
html[data-dispo] .contenu .carte-matiere[hidden],
html[data-dispo] .liste-chapitres .chapitre[hidden] { display: none !important; }

/* ════════════════════════════════════════════════════════════════════════
   LA DISPOSITION PS4
   ════════════════════════════════════════════════════════════════════════
   Demandé ensuite pour le menu PS4, avec la même exigence que pour la
   Wii : une expérience réellement immersive.

   Une décision prise d'avance, et c'est la leçon du matin : **cette
   disposition ne touche pas à « --papier »**. Celle de la Wii l'a fait, et
   il a fallu quatre passages du banc pour rattraper les encres qui se
   posaient dessus — y compris celles qui vivent sur un fond translucide,
   qu'on ne voit pas en lisant la feuille. Or Console bleue a DÉJÀ son bleu,
   calculé et mesuré sur ses deux faces. La disposition n'ajoute donc que ce
   qui lui manque : la vague, le rangement, et les deux bandes.

   Ce qui est repris de la console, et ce qui ne l'est pas :
     · la barre de fonctions en haut, étiquette sous le seul élément visé ✔
     · les tuiles rectangulaires collées, sans gouttière ✔
     · la grande vague claire en diagonale ✔
     · l'heure en haut à droite ✔
     · la bande d'aide en bas ✔ — mais avec les VRAIES touches du clavier.
       « ⊗ Précédent · ◎ Valider » décrit une manette que personne n'a ici.
     · la rangée UNIQUE qui défile au stick ✘ — une page web n'a pas de
       stick, et une rangée qui déborde fait défiler la page de travers.
       Les tuiles restent collées, mais elles reviennent à la ligne.
   ──────────────────────────────────────────────────────────────────────── */

/* La vague : une grande diagonale claire qui traverse l'écran, posée SOUS le
   contenu et par-dessus le dégradé du thème. « fixed » pour qu'elle reste
   une lumière de la pièce, pas un motif qui défile avec le texte. */
/* Le creux du bas n'existe que si la bande du bas existe : une fiche garde
   sa barre flottante et n'a rien à dégager de plus. « :has » est déjà employé
   ailleurs dans le projet pour ce genre de question — la feuille sait
   reconnaître ce qu'elle contient. */
html[data-dispo="ps4"] body { position: relative; }
html[data-dispo="ps4"] body:has(.dispo-aide) { padding-bottom: 3.6rem; }
html[data-dispo="ps4"] body::before {
  content: ""; position: fixed; inset: 0; z-index: 0; pointer-events: none;
  background:
    linear-gradient(118deg, transparent 32%,
      rgba(255,255,255,.14) 44%, rgba(255,255,255,.22) 50%,
      rgba(255,255,255,.10) 57%, transparent 69%);
}
html[data-dispo="ps4"][data-sombre="0"] body::before {
  background:
    linear-gradient(118deg, transparent 32%,
      rgba(255,255,255,.55) 44%, rgba(255,255,255,.78) 50%,
      rgba(255,255,255,.45) 57%, transparent 69%);
}
/* Le contenu passe DEVANT la vague, sinon elle le laverait. */
html[data-dispo="ps4"] .app-tete,
html[data-dispo="ps4"] .contenu,
html[data-dispo="ps4"] .corps,
html[data-dispo="ps4"] .app-pied { position: relative; z-index: 1; }

/* ── La barre de fonctions ───────────────────────────────────────────────
   Elle existe déjà : c'est la navigation du site, et elle porte exactement
   ce qu'il faut — un pictogramme et une étiquette par entrée, et
   « aria-current » sur la page où l'on est. On ne bâtit rien, on range.

   L'étiquette ne se montre que sous l'élément VISÉ. Sur la console, viser
   c'est déplacer le curseur ; ici c'est le survol, le focus clavier, ou la
   page courante. Les trois sont traités pareil : une barre dont l'étiquette
   n'apparaîtrait qu'au survol serait muette pour qui navigue au clavier. */
html[data-dispo="ps4"] .app-tete {
  background: transparent; box-shadow: none; border-bottom: 0;
}
html[data-dispo="ps4"] .app-tete nav { gap: clamp(.5rem, 2.2vw, 1.6rem); }
html[data-dispo="ps4"] .app-tete nav > a:not(.bouton-3d) {
  flex-direction: column; align-items: center; justify-content: flex-start;
  gap: .25rem; padding: .4rem .35rem .2rem; background: transparent;
  border: 0; border-radius: 10px; color: var(--encre-tenue);
  transition: color .16s ease, transform .16s ease;
}
html[data-dispo="ps4"] .app-tete nav > a:not(.bouton-3d) .ico {
  width: 26px; height: 26px; filter: drop-shadow(0 1px 2px rgba(0,0,0,.25));
}
/* ── L'étiquette ne doit RIEN coûter à la rangée ─────────────────────────
   Première version : « opacity: 0 » sur toutes les étiquettes, 1 sur celle
   qu'on vise. Mesurée, elle ne montrait rien du tout — le site masque déjà
   les étiquettes de sa navigation en dessous d'une certaine largeur, avec
   « display: none », et une opacité ne ramène pas ce qui n'est pas affiché.
   Une surcharge qui ne parle pas la même propriété que la règle d'origine ne
   la surcharge pas.

   Deuxième version, et c'est la bonne pour une autre raison : l'étiquette est
   SORTIE DU FLUX, posée sous son pictogramme. Elle ne prend donc aucune
   largeur dans la rangée — ni quand elle se montre, ni quand elle se cache —
   et la barre ne bouge pas d'un pixel quand le curseur passe. C'est ce que
   fait la console : les icônes sont fixes, seule l'étiquette apparaît. */
html[data-dispo="ps4"] .app-tete nav > a:not(.bouton-3d) { position: relative; }
html[data-dispo="ps4"] .app-tete nav > a:not(.bouton-3d) > span {
  display: block; position: absolute; top: calc(100% - .1rem); left: 50%;
  transform: translateX(-50%); white-space: nowrap; pointer-events: none;
  font-size: .62rem; letter-spacing: .06em; text-transform: uppercase;
  opacity: 0; transition: opacity .16s ease;
}
html[data-dispo="ps4"] .app-tete nav > a:not(.bouton-3d):hover,
html[data-dispo="ps4"] .app-tete nav > a:not(.bouton-3d):focus-visible,
html[data-dispo="ps4"] .app-tete nav > a:not(.bouton-3d)[aria-current="page"] {
  color: var(--encre); transform: translateY(-2px);
}
html[data-dispo="ps4"] .app-tete nav > a:not(.bouton-3d):hover > span,
html[data-dispo="ps4"] .app-tete nav > a:not(.bouton-3d):focus-visible > span,
html[data-dispo="ps4"] .app-tete nav > a:not(.bouton-3d)[aria-current="page"] > span { opacity: 1; }
html[data-dispo="ps4"] .app-tete nav > a:not(.bouton-3d)[aria-current="page"] .ico {
  filter: drop-shadow(0 0 7px color-mix(in srgb, var(--accent) 75%, transparent));
}

/* ── L'heure, en haut à droite ───────────────────────────────────────────
   Posée au-dessus de tout, hors du flux : elle ne doit décaler ni l'en-tête
   ni le contenu. Son creux à droite tient compte de l'encoche d'un
   téléphone, et sa taille reste celle d'une horloge qu'on lit de loin. */
/* ── L'heure tient sur une PLAQUE, pas sur une ombre ─────────────────────
   Elle est « fixed » : la page défile dessous, et elle passe donc sur ce qui
   vient — une carte, un schéma clair, une image. Mesuré avant de livrer :
   sur la face nuit, son encre quasi blanche sur un fond blanc donne
   **1,08 : 1**. Invisible. Une ombre portée ne rattrape pas ça ; elle ne
   fait que salir les lettres.

   C'est la leçon du titre du village 3D, et la réponse est la même : on ne
   devine pas un fond, on en pose un. Sur une plaque, le pire cas remonte à
   6,51 : 1 la nuit et 10,41 : 1 le jour. Le flou n'est pas décoratif — il
   écrase l'écart de ce qu'il y a dessous avant de le recouvrir, ce qu'une
   couleur seule ne sait pas faire. */
.dispo-horloge[data-dispo-barre="ps4"] {
  position: fixed; z-index: 40; pointer-events: none;
  top: max(.55rem, env(safe-area-inset-top));
  right: max(.9rem, env(safe-area-inset-right));
  display: flex; align-items: baseline; gap: .1rem;
  padding: .3rem .6rem; border-radius: 9px;
  font: 600 1.02rem/1 var(--sans); color: var(--encre);
  background: rgba(10, 26, 46, .72);
  border: 1px solid rgba(190, 215, 245, .22);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
}
html[data-dispo="ps4"][data-sombre="0"] .dispo-horloge {
  background: rgba(255, 255, 255, .80);
  border-color: rgba(11, 95, 165, .22);
}
.dispo-horloge .dispo-deux { font-style: normal; opacity: .6; }
.dispo-horloge .dispo-date {
  margin-left: .5rem; font-size: .72rem; font-weight: 500; opacity: .78;
}

/* ── La bande d'aide ─────────────────────────────────────────────────────
   Noire, fine, en bas, et VRAIE : chaque touche écrite ici fait quelque
   chose (voir AIDES_PS4 dans app.js). Elle ne reçoit pas le clic — ce n'est
   pas un menu, c'est un rappel. */
.dispo-aide[data-dispo-barre="ps4"] {
  position: fixed; z-index: 40; left: 0; right: 0;
  bottom: 0; pointer-events: none;
  display: flex; align-items: center; justify-content: center;
  flex-wrap: wrap; gap: .25rem 1.4rem;
  padding: .5rem 1rem calc(.5rem + env(safe-area-inset-bottom));
  background: rgba(3, 10, 22, .92);
  color: #DCE9F8;
}
/* ── Le fondu passe AU-DESSUS des lettres, pas à travers ─────────────────
   La bande avait pour fond « linear-gradient(transparent, .86 à 38 %) ».
   Joli de loin, et faux : le haut des lettres tombait dans la partie encore
   claire du dégradé. Mesuré par le banc — qui voit enfin ce décor — et
   recalculé à la main : **1,13 : 1** à l'extrémité transparente, contre
   12,13 une fois la plaque pleine. Un fond en dégradé n'est pas un fond,
   c'est une suite de fonds, et le texte est jugé sur le pire.

   La plaque devient donc pleine, et le fondu — qui servait à ne pas couper
   la page net — se range juste au-dessus d'elle, où il ne porte aucun texte. */
.dispo-aide[data-dispo-barre="ps4"]::before {
  content: ""; position: absolute; left: 0; right: 0; bottom: 100%; height: 2.2rem;
  background: linear-gradient(rgba(3, 10, 22, 0), rgba(3, 10, 22, .92));
  pointer-events: none;
}
.dispo-aide-item { display: inline-flex; align-items: center; gap: .4rem; }
.dispo-aide-item kbd {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 1.5rem; height: 1.5rem; padding: 0 .4rem;
  border-radius: 5px; border: 1px solid rgba(220,233,248,.42);
  background: rgba(220,233,248,.10);
  font: 600 .72rem/1 var(--mono, ui-monospace, monospace); color: #FFFFFF;
}
.dispo-aide-item em { font-style: normal; font-size: .74rem; color: #DCE9F8; }

/* ── Les tuiles, collées ─────────────────────────────────────────────────
   Pas de gouttière : c'est la rangée de la console. Ce qui sépare deux
   tuiles n'est donc pas du vide mais un FILET — un bord d'un pixel, repris
   des deux côtés pour que la grille n'ait pas de liseré extérieur.

   Le plancher de colonne vaut 230 px et non 270 comme sur la Wii : la tuile
   n'est pas un carré ici, sa hauteur ne suit pas sa largeur, donc une
   colonne étroite ne coupe rien — elle rallonge. */
html[data-dispo="ps4"] .contenu .grille-matieres,
html[data-dispo="ps4"] .liste-chapitres {
  display: grid; gap: 0;
  grid-template-columns: repeat(auto-fill, minmax(min(230px, 100%), 1fr));
  border-radius: 10px; overflow: hidden;
  box-shadow: 0 10px 30px rgba(2,12,28,.28);
}
html[data-dispo="ps4"] .contenu .carte-matiere,
html[data-dispo="ps4"] .liste-chapitres .chapitre {
  margin: 0; border-radius: 0; border: 0;
  box-shadow: inset -1px -1px 0 var(--bord), inset 1px 1px 0 var(--bord);
  background: color-mix(in srgb, var(--carte) 78%, transparent);
  transition: background .16s ease, box-shadow .16s ease, transform .16s ease;
}
/* ── Une rangée n'est pas une tuile ──────────────────────────────────────
   Vu à l'écran avant de le croire : les quatre boutons Cours / Exercices /
   Fiche / QCM passaient PAR-DESSUS le titre et la phrase. La cause n'est pas
   dans cette feuille, elle est dans la nature de « .chapitre » : c'est une
   grille de trois colonnes — « 44px 1fr auto », numéro | texte | liens —
   dessinée pour une ligne qui traverse la page. Serrée dans une tuile de
   239 px, elle n'a plus la place de les mettre côte à côte, et les colonnes
   se recouvrent.

   Une disposition qui ne fait que repeindre une grille de rangées obtient
   des rangées peintes, pas des tuiles. Celle-ci reporte donc les liens sur
   leur propre ligne : le numéro reste à côté du titre, où il se lit, et les
   quatre boutons passent dessous. */
html[data-dispo="ps4"] .liste-chapitres .chapitre {
  grid-template-columns: 38px 1fr;
  grid-template-areas: "num txt" "liens liens";
  align-items: start; gap: .55rem .7rem; padding: .95rem 1rem 1rem;
}
html[data-dispo="ps4"] .liste-chapitres .chapitre .num { align-self: start; }
/* Les quatre liens en DEUX COLONNES plutôt qu'en flux qui retombe : à 239 px
   de large, le flux donnait « Cours » seul, puis « Exercices Fiche », puis
   « QCM » — trois lignes bancales pour quatre boutons du même rang. En
   grille, ils forment un carré régulier, et chacun garde sa cible tactile. */
html[data-dispo="ps4"] .liste-chapitres .chapitre .liens {
  margin-top: .15rem; display: grid; grid-template-columns: 1fr 1fr; gap: .35rem;
}
html[data-dispo="ps4"] .liste-chapitres .chapitre .liens a {
  text-align: center; padding: .4rem .5rem;
}
/* La coche de révision est posée par app.js SANS zone de grille : elle
   tombait donc dans une troisième rangée implicite, seule, tout en bas à
   droite, et elle allongeait la tuile pour rien. On lui donne sa place — au
   bout du titre, là où elle dit « ce chapitre est su ». */
html[data-dispo="ps4"] .liste-chapitres .chapitre {
  grid-template-areas: "num txt" "liens liens";
}
html[data-dispo="ps4"] .liste-chapitres .chapitre .coche {
  grid-area: num; align-self: end; justify-self: center; margin-top: .4rem;
}
/* « translateX » déplaçait la rangée vers la droite au survol : dans une
   grille collée, cela ouvrirait une fente. La tuile monte, elle ne glisse
   pas. */
html[data-dispo="ps4"] .liste-chapitres .chapitre:hover { transform: none; }

/* La tuile visée SORT, elle ne change pas de couleur : filet blanc fin et
   léger soulèvement. C'est le geste du menu, et « z-index » l'empêche de
   passer sous ses voisines collées. */
html[data-dispo="ps4"] .contenu .carte-matiere:hover,
html[data-dispo="ps4"] .contenu .carte-matiere:focus-visible,
html[data-dispo="ps4"] .liste-chapitres .chapitre:hover,
html[data-dispo="ps4"] .liste-chapitres .chapitre:focus-within {
  position: relative; z-index: 2; transform: translateY(-3px);
  background: color-mix(in srgb, var(--carte) 96%, transparent);
  box-shadow: 0 0 0 2px rgba(255,255,255,.9), 0 10px 22px rgba(2,12,28,.4);
}

/* ── La grande tuile sélectionnée de l'accueil ───────────────────────────
   Sur le menu de la console, l'accueil montre une grande tuile visée, cernée
   d'un filet blanc, avec une flèche vers le bas, et son titre écrit À DROITE.
   Ici cette tuile existe déjà et elle a un sens : « Reprendre » est la seule
   chose qu'on vise vraiment en arrivant. On ne fabrique donc pas une fausse
   sélection — on habille la vraie. */
html[data-dispo="ps4"] .contenu .carte-matiere.reprise {
  display: flex; flex-direction: row; align-items: center; gap: 1rem;
  padding: 1rem 1.2rem; border-radius: 12px; margin-bottom: 1.1rem;
  background: color-mix(in srgb, var(--carte) 92%, transparent);
  box-shadow: 0 0 0 1px rgba(255,255,255,.85), 0 12px 28px rgba(2,12,28,.34);
}
html[data-dispo="ps4"] .contenu .carte-matiere.reprise::before {
  content: "\2193"; flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  width: 54px; height: 54px; border-radius: 8px;
  border: 1px solid rgba(255,255,255,.9);
  background: color-mix(in srgb, var(--accent) 22%, transparent);
  font-size: 1.3rem; color: var(--encre);
}
html[data-dispo="ps4"] .contenu .carte-matiere.reprise > * {
  width: auto; text-align: left;
}

/* ── Les flèches de page ─────────────────────────────────────────────────
   Mêmes règles que partout : elles PAGINENT pour de bon, et elles se grisent
   aux bords au lieu de mentir. */
html[data-dispo="ps4"] .dispo-pages { margin-top: 1rem; }
html[data-dispo="ps4"] .dispo-pages .dispo-fleche {
  border-color: rgba(255,255,255,.34);
  background: rgba(255,255,255,.08); color: var(--encre);
}
html[data-dispo="ps4"] .dispo-pages .dispo-fleche:not(:disabled):hover {
  background: rgba(255,255,255,.18); border-color: rgba(255,255,255,.7);
}
html[data-dispo="ps4"] .dispo-pages .dispo-compte { color: var(--encre-douce); }

/* Le pied de page du site répète ce que la bande d'aide dit mieux. */
html[data-dispo="ps4"] .app-pied { display: none; }

@media (max-width: 640px) {
  /* On avait écrit ici que sur un téléphone les étiquettes devaient TOUTES
     s'afficher, puisqu'un pictogramme seul ne dit rien. Vu à l'écran : elles
     se chevauchaient toutes — « ACCUEILPLANNINGDEVOIRSOUTILSÀ PROPOS ». La
     raison est dans la règle qui précède : depuis qu'elles sont hors du flux,
     elles ne se poussent plus, elles se superposent. Cinq étiquettes de 43 à
     60 px centrées sous des icônes espacées de 55 px ne peuvent pas tenir.

     Donc la même règle que sur grand écran : une seule à la fois, celle de la
     page où l'on est. C'est d'ailleurs ce que fait la console. */
  .dispo-horloge[data-dispo-barre="ps4"] { font-size: .9rem; }
  .dispo-horloge .dispo-date { display: none; }
  .dispo-aide[data-dispo-barre="ps4"] { gap: .2rem .8rem; padding: .4rem .6rem
    calc(.4rem + env(safe-area-inset-bottom)); }
  .dispo-aide-item em { display: none; }
  html[data-dispo="ps4"] body:has(.dispo-aide) { padding-bottom: 3rem; }
  html[data-dispo="ps4"] .contenu .grille-matieres,
  html[data-dispo="ps4"] .liste-chapitres {
    grid-template-columns: repeat(auto-fill, minmax(min(240px, 100%), 1fr));
  }
}


/* ── la barre du bas, et l'horloge ─────────────────────────────────────── */
.dispo-barre[data-dispo-barre="wii"] {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem; padding: .5rem 1rem;
  background: linear-gradient(#E9EDF0, #C9D2D9);
  border-top: 1px solid #AFBAC4;
  border-radius: 26px 26px 0 0;
  box-shadow: 0 -2px 10px rgba(30,50,70,.16);
}
.dispo-barre .dispo-rond {
  flex: none; width: 56px; height: 56px; border-radius: 50%;
  font: 700 .78rem/1 var(--sans); letter-spacing: .04em; cursor: pointer;
  color: #2B5E85; background: radial-gradient(circle at 50% 32%, #FFFFFF, #DCE4EA);
  border: 1px solid #A9B6C1;
  box-shadow: 0 2px 0 #FFF inset, 0 2px 6px rgba(30,50,70,.22);
}
.dispo-barre .dispo-rond:hover,
.dispo-barre .dispo-rond:focus-visible {
  color: #10405F; box-shadow: 0 0 0 3px #4FC3F7, 0 2px 8px rgba(30,50,70,.3);
}
.dispo-barre .dispo-droite { font-size: 1.3rem; }
.dispo-heure {
  display: flex; align-items: baseline; gap: .12rem;
  font-family: var(--sans); color: #41525E;
}
.dispo-heure b { font-size: 1.9rem; font-weight: 300; letter-spacing: .02em; }
/* Les deux points clignotent, comme sur la console. L'animation se coupe avec
   le réglage « animations » : une pulsation permanente dans le champ de vision
   fatigue, et certains ne la supportent pas du tout. */
.dispo-heure .dispo-deux { font-style: normal; font-size: 1.5rem; opacity: .85; }
html[data-anim="1"] .dispo-heure .dispo-deux { animation: dispo-clin 2s steps(1) infinite; }
@keyframes dispo-clin { 0%, 49% { opacity: .85; } 50%, 100% { opacity: .2; } }
/* La date valait #5E6E7A : **3,44 : 1** sur le bas de la plaque grise, et
   4,47 sur le haut — c'est-à-dire sous le seuil des deux côtés. Elle n'a
   jamais été conforme ; simplement, aucun banc ne regardait cette barre.
   Nouvelle valeur : 4,85 en bas, 6,31 en haut. */
.dispo-heure .dispo-date {
  margin-left: .7rem; font-size: .82rem; color: #4A5761; align-self: center;
}

/* ── les flèches de page ───────────────────────────────────────────────── */
.dispo-pages {
  display: flex; align-items: center; justify-content: center; gap: 1.1rem;
  margin: 1.6rem 0 .4rem;
}
.dispo-pages .dispo-fleche {
  width: 46px; height: 46px; border-radius: 50%; cursor: pointer;
  font: 400 1.6rem/1 var(--sans); color: #2B5E85;
  background: radial-gradient(circle at 50% 32%, #FFFFFF, #DEE6EC);
  border: 1px solid #A9B6C1;
  box-shadow: 0 2px 0 #FFF inset, 0 2px 6px rgba(30,50,70,.18);
}
.dispo-pages .dispo-fleche:hover:not(:disabled),
.dispo-pages .dispo-fleche:focus-visible:not(:disabled) {
  box-shadow: 0 0 0 3px #4FC3F7, 0 2px 8px rgba(30,50,70,.26);
}
/* Désactivée, pas cachée : sur la console les flèches restent là. Mais elles
   DISENT qu'elles sont inertes — un bouton grisé ne ment pas, un bouton
   identique qui ne répond pas, si. */
.dispo-pages .dispo-fleche:disabled { opacity: .38; cursor: default; }
.dispo-pages .dispo-compte {
  min-width: 3.4rem; text-align: center;
  font: 600 .84rem var(--sans); color: var(--encre-douce);
}
/* Une seule page : la rangée s'efface pour qui regarde, mais reste dans le
   flux — sinon la grille sauterait d'un écran à l'autre. */
.dispo-pages[data-seule="1"] { opacity: .3; }

@media (max-width: 640px) {
  .dispo-barre[data-dispo-barre="wii"] { padding: .4rem .7rem; }
  .dispo-barre .dispo-rond { width: 46px; height: 46px; font-size: .7rem; }
  .dispo-heure b { font-size: 1.5rem; }
  .dispo-heure .dispo-date { font-size: .74rem; margin-left: .45rem; }
  html[data-dispo="wii"] body { padding-bottom: 4.6rem; }
  html[data-dispo="wii"] .contenu .grille-matieres,
  html[data-dispo="wii"] .liste-chapitres {
    grid-template-columns: repeat(auto-fill, minmax(min(240px, 100%), 1fr));
    gap: 1rem;
  }
  /* Sur un téléphone, le carré est abandonné, et ce n'est pas un renoncement :
     une colonne de 160 px de côté ne peut pas porter quatre boutons, et
     deux colonnes étroites valent moins qu'une chaîne entière qu'on lit.
     La chaîne prend donc la hauteur de ce qu'elle contient. */
  html[data-dispo="wii"] .contenu .carte-matiere,
  html[data-dispo="wii"] .liste-chapitres .chapitre { aspect-ratio: auto; }
}

/* À l'impression, rien de tout cela n'a de sens. */
@media print {
  .dispo-barre, .dispo-pages { display: none !important; }
  html[data-dispo] .contenu .carte-matiere,
  html[data-dispo] .liste-chapitres .chapitre { aspect-ratio: auto; }
}

/* ═══════════════════════════════════════════════════════════════════════
   COQUILLE — accueil, pages de matière, recherche
   Ne concerne que les pages de navigation. Les fiches gardent theme.css.
   ═══════════════════════════════════════════════════════════════════════ */

/* ───────────────────────────────────────────────── en-tête de l'application */
.app-tete {
  position: sticky; top: 0; z-index: 40;
  display: flex; align-items: center; gap: .9rem;
  padding: .7rem clamp(1rem, 4vw, 2.4rem);
  background: color-mix(in srgb, var(--papier) 86%, transparent);
  backdrop-filter: blur(14px) saturate(150%);
  -webkit-backdrop-filter: blur(14px) saturate(150%);
  border-bottom: 1px solid var(--bord);
}
/* Sans « nowrap », « BTS CIEL — révisions » et « À propos » se cassaient en
   deux lignes dès 430 px, et l'en-tête doublait de hauteur. Le titre se
   tronque plutôt que de replier la barre. */
.app-marque {
  /* « flex: none » : le porte-logo ne se comprime JAMAIS. Sans lui, l'arrivée
     d'un troisième lien dans la barre l'a écrasé à 15 px de large — le badge
     de la classe se retrouvait tranché sur téléphone. Si la place manque,
     c'est à la navigation de céder, pas à l'identité du site. */
  display: flex; align-items: center; gap: .55rem; flex: none; padding: .25rem 0;
  font-weight: 700; font-size: 0.9091rem; color: var(--encre);
  text-decoration: none; letter-spacing: -.01em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* Porte-logo : le badge de la classe, dessiné en SVG, reste net de 27 px
   (téléphone) à 34 px (grand écran) et à l'impression. */
.app-marque .sigle {
  width: 30px; height: 30px; flex: none;
  display: grid; place-items: center; border-radius: 50%;
  overflow: hidden; box-shadow: 0 0 0 1px var(--bord-fort);
}
.app-marque .sigle svg,
.app-marque .sigle img { width: 100%; height: 100%; display: block;
                        object-fit: cover; }
.app-tete nav { margin-left: auto; display: flex; gap: .2rem; align-items: center; flex: none; }
.app-tete nav a {
  padding: .42rem .7rem; border-radius: 8px; text-decoration: none;
  color: var(--encre-douce); font-size: 0.8121rem; font-weight: 600;
  white-space: nowrap;
}
.app-tete nav a { display: inline-flex; align-items: center; gap: .38rem; }
.app-tete nav a .ico { width: 17px; height: 17px; flex: 0 0 auto; opacity: .78; }
.app-tete nav a[aria-current="page"] .ico { opacity: 1; }
.app-tete nav a:hover { background: var(--carte-creuse); color: var(--encre); }
.app-tete nav a[aria-current="page"] { color: var(--accent-sombre); background: var(--accent-pale); }

/* ───────────────────────────────────────────────────────────────── héros */
/* « overflow:hidden » servait à contenir le halo décoratif. Il rognait aussi
   la liste de résultats, qui déborde volontairement du héros : la recherche
   renvoyait des lignes invisibles, coupées au ras du champ. Le halo est
   maintenant tenu dans ses propres bornes, et le héros ne rogne plus rien. */
.heros {
  position: relative;
  padding: clamp(2.6rem, 8vw, 5rem) clamp(1rem, 4vw, 2.4rem) clamp(1.8rem, 4vw, 3rem);
  text-align: center;
}
/* Un seul voile, et d'une seule teinte. Il y en avait deux — un bleu à gauche,
   un ambre à droite — qui se rejoignaient au milieu de l'écran : sur un large
   écran la bande virait du bleu au jaune, et comme les deux étaient au plus
   fort en haut du bloc, elle commençait par un trait net sous l'en-tête.
   Le voile est maintenant centré et nul sur les quatre bords : aucune arête,
   aucune rencontre de teintes. */
.heros::before {
  content: ""; position: absolute; inset: 0; overflow: hidden;
  background: radial-gradient(ellipse 78% 68% at 50% 46%,
              color-mix(in srgb, var(--accent) 7%, transparent) 0%, transparent 70%);
  pointer-events: none; z-index: -1;
}
.heros .promo {
  display: inline-block; margin-bottom: 1rem; padding: .3rem .8rem;
  border: 1px solid var(--bord-fort); border-radius: 999px;
  background: var(--carte); color: var(--encre-douce);
  font-size: 0.697rem; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
}
.heros h1 {
  margin: 0 0 .7rem; font-size: clamp(2rem, 6.5vw, 3.4rem); line-height: 1.06;
  letter-spacing: -.028em; font-weight: 800; color: var(--encre);
}
.heros h1 span { color: var(--accent-sombre); }
/* L'accent du titre : même corps, même approche, UNE famille de
   différence et une graisse ordinaire. Le contraste vient de la forme des
   lettres, pas d'une couleur de plus — et il tient donc sur les quarante
   et un thèmes sans rien mesurer. */
.heros h1 em {
  font-family: var(--titre-accent); font-style: italic; font-weight: 400;
}
.heros p {
  margin: 0 auto; max-width: 42ch; font-size: clamp(15px, 2.4vw, 17.5px);
  line-height: 1.6; color: var(--encre-douce);
}

/* ─────────────────────────────────────────────────────────────── recherche */
.recherche { max-width: 620px; margin: 1.8rem auto 0; position: relative; z-index: 45; }
.recherche input {
  width: 100%; box-sizing: border-box;
  padding: .82rem 1rem .82rem 2.7rem;
  font: inherit; font-size: 0.9394rem; color: var(--encre);
  background: var(--carte); border: 1px solid var(--bord-fort);
  border-radius: 12px; box-shadow: var(--ombre);
  transition: border-color .15s, box-shadow .15s;
}
.recherche input:focus {
  outline: none; border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-pale), var(--ombre);
}
.recherche svg {
  position: absolute; left: .95rem; top: 50%; transform: translateY(-50%);
  width: 17px; height: 17px; color: var(--encre-tenue); pointer-events: none;
}
.resultats {
  position: absolute; left: 0; right: 0; top: calc(100% + .5rem); z-index: 46;
  max-height: min(58vh, 430px); overflow-y: auto; text-align: left;
  background: var(--carte); border: 1px solid var(--bord-fort);
  border-radius: 12px; box-shadow: var(--ombre-haut); padding: .35rem;
}
.resultats:empty { display: none; }
.resultats a {
  display: block; padding: .55rem .7rem; border-radius: 8px;
  text-decoration: none; color: var(--encre);
}
.resultats a:hover, .resultats a:focus { background: var(--accent-pale); outline: none; }
/* Deux <span> : sans « display:block » ils se chevauchent sur une seule ligne. */
.resultats .r-titre { display: block; font-weight: 640; font-size: 0.8606rem; line-height: 1.35; }
.resultats .r-chemin { display: block; font-size: 0.7273rem; color: var(--encre-tenue); margin-top: .12rem; }
.resultats .r-vide { padding: .8rem .7rem; color: var(--encre-tenue); font-size: 0.8182rem; }

/* ───────────────────────────────────────────────────── grille des matières */
.contenu { max-width: var(--large-app, 1120px); margin: 0 auto; padding: 0 clamp(1rem, 4vw, 2.4rem) 4rem; }
.grille-matieres {
  display: grid; gap: 1rem; margin-top: 2.2rem;
  grid-template-columns: repeat(auto-fit, minmax(270px, 1fr));
}
.carte-matiere {
  position: relative; display: flex; flex-direction: column; gap: .5rem;
  padding: 1.35rem 1.4rem 1.25rem; text-decoration: none;
  background: var(--carte); border: 1px solid var(--bord);
  border-radius: var(--r-l); box-shadow: var(--ombre);
  transition: transform .16s var(--ease, ease), box-shadow .16s, border-color .16s;
  overflow: hidden;
}
.carte-matiere::after {
  content: ""; position: absolute; inset: 0 auto 0 0; width: 3px;
  background: var(--accent);
}
.carte-matiere:hover {
  transform: translateY(-3px); box-shadow: var(--ombre-haut);
  border-color: var(--bord-fort);
}
.carte-matiere .ic {
  width: 38px; height: 38px; border-radius: 11px; display: grid; place-items: center;
  background: var(--accent-pale); color: var(--accent-sombre); font-size: 1.0909rem;
}
.carte-matiere h2, .carte-matiere h3 {
  margin: .2rem 0 0; font-size: 1.12rem; font-weight: 720; color: var(--encre);
  letter-spacing: -.012em;
}
.carte-matiere p { margin: 0; font-size: 0.8364rem; line-height: 1.55; color: var(--encre-douce); }
.carte-matiere .pied {
  margin-top: auto; padding-top: .8rem; display: flex; align-items: center; gap: .5rem;
  font-size: 0.7576rem; color: var(--encre-tenue);
}
.carte-matiere .pastille {
  padding: .12rem .5rem; border-radius: 999px;
  background: var(--accent-pale); color: var(--accent-sombre);
  font-weight: 700; font-size: 0.697rem;
}

/* ─────────────────────────────────────────────────── liste des chapitres */
.liste-chapitres { display: flex; flex-direction: column; gap: .6rem; margin-top: 1.8rem; }
.chapitre {
  display: grid; align-items: center; gap: .3rem 1rem;
  grid-template-columns: 44px 1fr auto;
  grid-template-areas: "num txt liens";
  padding: .9rem 1.1rem;
  background: var(--carte); border: 1px solid var(--bord);
  border-radius: var(--r); box-shadow: var(--ombre);
  transition: border-color .15s, transform .15s;
}
.chapitre:hover { border-color: var(--bord-fort); transform: translateX(2px); }
.chapitre .num {
  grid-area: num; width: 38px; height: 38px; border-radius: 10px;
  display: grid; place-items: center;
  background: var(--accent-pale); color: var(--accent-sombre);
  font-weight: 800; font-size: 0.8485rem;
}
.chapitre .txt { grid-area: txt; min-width: 0; }
.chapitre .txt h3 {
  margin: 0; font-size: 1rem; font-weight: 680; color: var(--encre);
  letter-spacing: -.008em;
}
.chapitre .txt p { margin: .15rem 0 0; font-size: 0.8rem; color: var(--encre-douce); }
.chapitre .liens { grid-area: liens; display: flex; gap: .35rem; flex-wrap: wrap; }
.chapitre .liens a {
  padding: .34rem .7rem; border-radius: 8px; text-decoration: none;
  border: 1px solid var(--bord); background: var(--carte-creuse);
  color: var(--encre-douce); font-size: 0.7576rem; font-weight: 650;
  white-space: nowrap;
}
.chapitre .liens a:hover { background: var(--accent-pale); color: var(--accent-sombre); border-color: var(--accent); }

@media (max-width: 620px) {
  .chapitre { grid-template-columns: 38px 1fr; grid-template-areas: "num txt" ". liens"; }
  .chapitre .liens { margin-top: .5rem; }
}

/* ───────────────────────────────────────────────────────────── chiffres */
.chiffres {
  display: flex; flex-wrap: wrap; gap: 1.6rem 2.6rem; justify-content: center;
  margin-top: 2.2rem;
}
.chiffres div { text-align: center; }
.chiffres strong {
  display: block; font-size: 1.9rem; font-weight: 800; color: var(--encre);
  letter-spacing: -.02em; line-height: 1;
}
.chiffres span {
  display: block; margin-top: .25rem; font-size: 0.697rem; color: var(--encre-tenue);
  text-transform: uppercase; letter-spacing: .08em; font-weight: 700;
}

/* ─────────────────────────────────────────────────────────────── pied */
.app-pied {
  border-top: 1px solid var(--bord); margin-top: 3rem;
  padding: 2rem clamp(1rem, 4vw, 2.4rem) 2.6rem;
  text-align: center; color: var(--encre-tenue); font-size: 0.8rem; line-height: 1.7;
}
.app-pied a { color: var(--encre-douce); display: inline-flex; align-items: center;
              min-height: 36px; padding: 0 .3rem; }
.app-pied .liens { margin-top: .6rem; display: flex; gap: .9rem; justify-content: center; flex-wrap: wrap; }

/* ──────────────────────────────────────────── fil d'Ariane des matières */
.fil-app {
  display: flex; align-items: center; gap: .45rem; flex-wrap: wrap;
  padding-top: 1.8rem; font-size: 0.7879rem; color: var(--encre-tenue);
}
.fil-app a { color: var(--encre-douce); text-decoration: none; font-weight: 600;
             display: inline-flex; align-items: center; min-height: 36px; padding: 0 .1rem; }
.fil-app a:hover { color: var(--accent-sombre); }

.tete-matiere { padding-top: .8rem; }
.tete-matiere h1 {
  margin: .5rem 0 .4rem; font-size: clamp(1.7rem, 5vw, 2.5rem);
  letter-spacing: -.024em; font-weight: 800; color: var(--encre);
}
.tete-matiere p { margin: 0; max-width: 58ch; color: var(--encre-douce); font-size: 0.9394rem; line-height: 1.6; }

/* ═══════════════════════════════════════════════════════════════════════
   RÉGLAGES — feuille coulissante, dans l'esprit de Sakina
   ═══════════════════════════════════════════════════════════════════════ */
.bouton-rond {
  width: 36px; height: 36px; flex: none; border-radius: 10px; cursor: pointer;
  display: grid; place-items: center; padding: 0;
  background: transparent; color: var(--encre-douce);
  border: 1px solid transparent; font-size: 0.9091rem; line-height: 1;
  transition: background .15s, color .15s, border-color .15s;
}
.bouton-rond:hover { background: var(--carte-creuse); color: var(--accent-sombre); border-color: var(--bord); }
.bouton-rond svg { width: 18px; height: 18px; }

/* ── le bouton du monde 3D ───────────────────────────────────────────────
   Demandé : plutôt qu'un bouton « Monde 3D », une pastille « 3D » posée
   à droite des paramètres, qui prend du relief au survol.

   Il est donc tout à droite, écrit « 3D », et il se comporte comme un objet :
   il s'incline vers le pointeur, sa face se détache du fond, et le relief du
   texte se creuse du même côté. Les deux rotations viennent du script
   (--rx / --ry) ; ici on ne décrit que la matière.

   Aucune couleur écrite en dur : l'accent de la page fait le relief, donc le
   bouton se repeint avec les quarante thèmes comme le reste. */
.bouton-3d {
  /* La MÊME boîte que la loupe, la lune et l'engrenage : 36 × 36, fond
     transparent, bordure invisible. Demandé : la même taille pour les
     trois. Il était le seul à montrer sa boîte en permanence, et c'est ce
     qui le faisait paraître plus gros — ce n'était pas sa taille, c'était
     son fond. Trois boutons côte à côte doivent être trois fois le même
     objet, sans quoi l'œil cherche pourquoi l'un est différent. */
  position: relative; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; padding: 0;
  border-radius: 10px; text-decoration: none;
  font-family: var(--mono); font-weight: 800; font-size: 0.7727rem;
  letter-spacing: .03em; color: var(--encre-douce);
  background: transparent; border: 1px solid transparent;
  transform-style: preserve-3d;
  transform: perspective(240px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg));
  transition: transform .26s cubic-bezier(.22,.7,.3,1), color .18s,
              background .18s, border-color .18s, box-shadow .26s;
}
.bouton-3d:hover, .bouton-3d:focus-visible {
  color: var(--accent-sombre); background: var(--carte-creuse);
  border-color: var(--accent);
  box-shadow: 0 10px 22px var(--accent-pale);
}
/* L'ÉPAISSEUR. Demandé : que le bouton lui-même soit en 3D, et prenne du
   relief quand le curseur arrive. Une inclinaison seule ne fait
   pas un volume : il faut voir la TRANCHE. C'est une seconde face, posée
   six unités en arrière et décalée de trois pixels — l'épaisseur du bouton,
   littéralement. Elle n'existe qu'au survol : au repos, le bouton est plat
   comme ses deux voisins. */
.bouton-3d::before {
  content: ""; position: absolute; inset: 0; border-radius: inherit;
  background: var(--accent-pale); border: 1px solid var(--bord);
  transform: translateZ(-6px) translate(3px, 4px);
  opacity: 0; transition: opacity .26s;
}
.bouton-3d:hover::before, .bouton-3d:focus-visible::before { opacity: 1; }
/* La face avance vers le lecteur : c'est ce translateZ qui fait que
   l'inclinaison se lit comme un volume et non comme un cisaillement. */
.b3d-face { position: relative; z-index: 1; transform: translateZ(7px);
  transition: text-shadow .26s; }
.bouton-3d:hover .b3d-face, .bouton-3d:focus-visible .b3d-face {
  text-shadow: 1px 1px 0 var(--accent-pale), 2px 2px 0 var(--accent-pale),
               3px 3px 0 var(--accent-pale), 4px 4px 0 var(--accent-pale),
               5px 6px 10px rgba(60, 45, 25, .22);
}
.b3d-lueur {
  position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  background: radial-gradient(56px circle at var(--mx, 50%) var(--my, 50%),
              var(--accent-pale), transparent 72%);
  opacity: 0; transition: opacity .26s;
}
.bouton-3d:hover .b3d-lueur, .bouton-3d:focus-visible .b3d-lueur { opacity: 1; }
/* Un objet qui bouge sous la souris est précisément ce qui gêne quand on a
   demandé moins d'animation. Le bouton reste, l'effet part. */
@media (prefers-reduced-motion: reduce) {
  .bouton-3d { transform: none; transition: color .18s, border-color .18s; }
  .b3d-face { transform: none; }
  .bouton-3d::before { display: none; }
}
html[data-anim="0"] .bouton-3d { transform: none; }
html[data-anim="0"] .b3d-face { transform: none; }
html[data-anim="0"] .bouton-3d::before { display: none; }

.voile {
  position: fixed; inset: 0; z-index: 90; opacity: 0;
  background: rgba(0,0,0,.45); backdrop-filter: blur(3px);
  transition: opacity .22s ease; pointer-events: none;
}
.voile.ouvert { opacity: 1; pointer-events: auto; }

.feuille {
  position: fixed; z-index: 91; left: 0; right: 0; bottom: 0;
  max-height: 86vh; overflow-y: auto; overscroll-behavior: contain;
  background: var(--carte); color: var(--encre);
  border-top: 1px solid var(--bord-fort);
  border-radius: 20px 20px 0 0; box-shadow: var(--ombre-haut);
  transform: translateY(101%); transition: transform .28s cubic-bezier(.32,.72,0,1);
  padding-bottom: max(1.2rem, env(safe-area-inset-bottom));
}
.feuille.ouverte { transform: translateY(0); }
@media (min-width: 720px) {
  .feuille {
    left: auto; right: 18px; bottom: 18px; width: 420px;
    max-height: min(82vh, 720px); border-radius: 18px;
    border: 1px solid var(--bord-fort);
    transform: translateY(calc(100% + 24px));
  }
}
.feuille-tete {
  position: sticky; top: 0; z-index: 2;
  display: flex; align-items: center; gap: .6rem;
  padding: 1rem 1.2rem .8rem;
  background: var(--carte); border-bottom: 1px solid var(--bord);
}
.feuille-tete h2 { margin: 0; font-size: 1.05rem; font-weight: 720; letter-spacing: -.01em; }
.feuille-tete .bouton-rond { margin-left: auto; }
.feuille-corps { padding: .4rem 1.2rem 1.2rem; }

.reglage { padding: 1rem 0; border-bottom: 1px solid var(--bord); }
.reglage:last-child { border-bottom: 0; }
.reglage > h3 {
  margin: 0 0 .1rem; font-size: 0.697rem; font-weight: 750;
  letter-spacing: .09em; text-transform: uppercase; color: var(--encre-tenue);
}
.reglage > p { margin: 0 0 .7rem; font-size: 0.7758rem; color: var(--encre-tenue); line-height: 1.5; }

.pastilles { display: flex; flex-wrap: wrap; gap: .45rem; }
.pastilles button {
  padding: .4rem .72rem; border-radius: 999px; cursor: pointer;
  background: var(--carte-creuse); color: var(--encre-douce);
  border: 1px solid var(--bord); font: inherit; font-size: 0.7758rem; font-weight: 620;
  transition: background .13s, color .13s, border-color .13s;
}
.pastilles button:hover { border-color: var(--bord-fort); color: var(--encre); }
.pastilles button[aria-pressed="true"] {
  background: var(--accent-pale); color: var(--accent-sombre); border-color: var(--accent);
}

.nuanciers { display: grid; grid-template-columns: repeat(auto-fill, minmax(84px, 1fr)); gap: .5rem; }
.nuancier {
  display: flex; flex-direction: column; align-items: center; gap: .35rem;
  padding: .5rem .3rem .45rem; border-radius: 11px; cursor: pointer;
  background: transparent; border: 1px solid transparent; font: inherit;
  color: var(--encre-douce); font-size: 0.697rem; font-weight: 620; text-align: center;
}
.nuancier:hover { background: var(--carte-creuse); }
.nuancier[aria-pressed="true"] { border-color: var(--accent); background: var(--accent-pale); color: var(--accent-sombre); }
.nuancier .rond {
  width: 30px; height: 30px; border-radius: 999px;
  border: 1px solid var(--bord-fort); box-shadow: inset 0 1px 2px rgba(0,0,0,.18);
}

.bascule {
  display: flex; align-items: center; gap: .8rem; width: 100%;
  padding: .55rem 0; background: none; border: 0; cursor: pointer;
  font: inherit; color: var(--encre); text-align: left;
}
.bascule .txt { flex: 1; min-width: 0; }
.bascule .txt b { display: block; font-size: 0.8485rem; font-weight: 640; }
.bascule .txt span { display: block; font-size: 0.7515rem; color: var(--encre-tenue); margin-top: .1rem; }
.bascule .interrupteur {
  flex: none; width: 42px; height: 25px; border-radius: 999px; position: relative;
  background: var(--bord-fort); transition: background .18s;
}
.bascule .interrupteur::after {
  content: ""; position: absolute; top: 3px; left: 3px;
  width: 19px; height: 19px; border-radius: 999px; background: #fff;
  box-shadow: 0 1px 3px rgba(0,0,0,.3); transition: transform .18s;
}
.bascule[aria-pressed="true"] .interrupteur { background: var(--accent); }
.bascule[aria-pressed="true"] .interrupteur::after { transform: translateX(17px); }

.danger {
  width: 100%; padding: .6rem; border-radius: 9px; cursor: pointer;
  background: var(--rouge-pale); color: var(--rouge);
  border: 1px solid color-mix(in srgb, var(--rouge) 35%, transparent);
  font: inherit; font-size: 0.8rem; font-weight: 650;
}
.danger:hover { background: color-mix(in srgb, var(--rouge) 18%, transparent); }

.toast {
  position: fixed; left: 50%; bottom: 22px; transform: translate(-50%, 14px);
  z-index: 95; padding: .6rem 1.1rem; border-radius: 999px;
  background: var(--encre); color: var(--papier);
  font-size: 0.8121rem; font-weight: 620; box-shadow: var(--ombre-haut);
  opacity: 0; pointer-events: none; transition: opacity .2s, transform .2s;
}
.toast.visible { opacity: 1; transform: translate(-50%, 0); }

/* ── Progression : cocher un chapitre comme révisé ───────────────────── */
.chapitre.fait { border-color: color-mix(in srgb, var(--vert) 45%, var(--bord)); }
.chapitre.fait .num { background: var(--vert-pale); color: var(--vert); }
/* 34 px, et non 26 : c'est la commande la plus utilisée de la page de
   matière, et 26 px se ratent au pouce. */
.coche {
  grid-area: coche; width: 34px; height: 34px; border-radius: 9px; cursor: pointer;
  display: grid; place-items: center; padding: 0; font-size: 0.7879rem; line-height: 1;
  background: var(--carte-creuse); color: var(--encre-tenue);
  border: 1px solid var(--bord); transition: background .14s, color .14s, border-color .14s;
}
.coche:hover { border-color: var(--bord-fort); color: var(--encre-douce); }
.coche[aria-pressed="true"] { background: var(--vert-pale); color: var(--vert); border-color: var(--vert); }
.chapitre { grid-template-areas: "num txt liens coche"; grid-template-columns: 44px 1fr auto auto; }
@media (max-width: 620px) {
  .chapitre { grid-template-columns: 38px 1fr auto; grid-template-areas: "num txt coche" ". liens liens"; }
}

.jauge-matiere {
  margin-top: 1.1rem; height: 6px; border-radius: 999px; overflow: hidden;
  background: var(--carte-creuse); border: 1px solid var(--bord);
}
.jauge-matiere i { display: block; height: 100%; width: 0; background: var(--vert); transition: width .3s; }
.jauge-txt { margin-top: .45rem; font-size: 0.7576rem; color: var(--encre-tenue); }

/* ═══════════════════════════════════════════════════════════════════════
   RÉGLAGES — sélecteur de thème, aperçu, boutons flottants
   ═══════════════════════════════════════════════════════════════════════ */

/* Quarante thèmes en pastilles occupaient tout l'écran des réglages ; en
   sélecteur natif ils tiennent sur une ligne, et le menu déroulant du système
   sait faire défiler, chercher au clavier et rester lisible sur mobile. */
.champ-select { display: flex; gap: .5rem; align-items: center; }
.champ-select select {
  flex: 1; min-width: 0; appearance: none; -webkit-appearance: none;
  padding: .6rem 2.2rem .6rem .8rem; cursor: pointer;
  font: inherit; font-size: .8485rem; font-weight: 620; color: var(--encre);
  background: var(--carte-creuse); border: 1px solid var(--bord-fort);
  border-radius: var(--r);
  background-image:
    linear-gradient(45deg, transparent 50%, currentColor 50%),
    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: right 1rem top 55%, right .7rem top 55%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  transition: border-color .15s, box-shadow .15s;
}
.champ-select select:focus-visible {
  outline: none; border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-pale);
}
.mini {
  flex: none; width: 38px; height: 38px; border-radius: var(--r); cursor: pointer;
  display: grid; place-items: center; padding: 0; font-size: .9697rem; line-height: 1;
  background: var(--carte-creuse); color: var(--encre-douce);
  border: 1px solid var(--bord-fort);
  transition: transform .18s var(--ease, cubic-bezier(.34,1.3,.64,1)), border-color .15s;
}
.mini:hover { border-color: var(--accent); transform: rotate(-18deg) scale(1.08); }
.mini:active { transform: rotate(-18deg) scale(.94); }

/* Aperçu : trois bandes qui prennent les couleurs du thème sélectionné. Le
   choix se voit avant de refermer la feuille. */
.apercu-theme {
  display: flex; align-items: center; gap: .6rem; margin-top: .7rem;
  padding: .55rem .65rem; border-radius: var(--r);
  background: var(--papier); border: 1px solid var(--bord);
}
.apercu-theme .ap-carte {
  flex: none; display: flex; gap: .25rem; align-items: center;
  padding: .35rem .45rem; border-radius: calc(var(--r) - 3px);
  background: var(--carte); border: 1px solid var(--bord-fort);
}
.apercu-theme .ap-carte i { width: 22px; height: 8px; border-radius: 3px; background: var(--accent); }
.apercu-theme .ap-carte b { width: 34px; height: 8px; border-radius: 3px; background: var(--encre-tenue); }
.apercu-theme .ap-txt { font-size: .7576rem; color: var(--encre-tenue); font-weight: 620; }

/* ── La barre d'outils d'une fiche ────────────────────────────────────
   Écrite en partant du téléphone : la barre du bas est le cas PAR DÉFAUT,
   et elle ne remonte sur le côté que là où il y a vraiment la place. Trois
   situations, chacune énoncée une seule fois :

   • par défaut            → barre horizontale en bas, qui s'efface en lisant ;
   • fiche avec sommaire   → rangée dans la colonne de gauche, dès 901 px ;
   • fiche de révision     → pas de colonne (elle s'imprime sur une seule) :
                             elle passe dans la marge droite, mais seulement
                             au-delà de 1380 px, où cette marge existe.

   Empilée au bord droit comme au départ, elle se posait en plein sur le
   texte : 170 px de commandes par-dessus la colonne de lecture. */
.barre-outils {
  position: fixed; z-index: 60;
  left: 0; right: 0; bottom: 0;
  display: flex; flex-direction: row; justify-content: space-evenly; gap: 2px;
  padding: 7px 8px calc(7px + env(safe-area-inset-bottom));
  background: color-mix(in srgb, var(--carte) 92%, transparent);
  backdrop-filter: blur(16px) saturate(170%);
  -webkit-backdrop-filter: blur(16px) saturate(170%);
  border-top: 1px solid var(--bord);
  transition: transform .26s var(--ease, cubic-bezier(.32,.72,0,1));
}
.barre-outils.effacee { transform: translateY(105%); }

.flottant {
  width: 46px; height: 46px; border-radius: 12px; cursor: pointer; flex: none;
  display: grid; place-items: center; padding: 0; text-decoration: none;
  background: transparent; border: 1px solid transparent; box-shadow: none;
  color: var(--encre-douce);
  transition: transform .18s var(--ease, cubic-bezier(.34,1.3,.64,1)), color .15s,
              border-color .15s, background .15s;
}
.flottant:active { background: var(--carte-creuse); transform: scale(.92); }
.flottant svg { width: 20px; height: 20px; }
/* La barre ne doit pas recouvrir la fin du texte. */
.page { padding-bottom: 5.5rem; }

/* ── Fiche avec sommaire : la barre se range dans la colonne de gauche ── */
@media (min-width: 901px) {
  .barre-outils:not(.sans-colonne) {
    left: calc(max(0px, (100vw - var(--large-page, 1220px)) / 2) + 2rem);
    right: auto; bottom: 22px; width: 268px;
    justify-content: flex-start; gap: 8px;
    padding: 0; background: none; border-top: 0;
    backdrop-filter: none; -webkit-backdrop-filter: none;
    transform: none;
  }
  /* Le sommaire s'arrête au-dessus : sur un chapitre à quinze sections, la
     liste descendait jusqu'en bas et passait dessous. */
  .sommaire { padding-bottom: 6rem; }
  .page { padding-bottom: 6rem; }
  /* Posé seul au-dessus de la page, un bouton porte son propre verre dépoli ;
     dans la barre du bas, c'est la barre qui le porte — pas lui. */
  .barre-outils:not(.sans-colonne) .flottant {
    background: color-mix(in srgb, var(--carte) 88%, transparent);
    backdrop-filter: blur(12px) saturate(150%);
    -webkit-backdrop-filter: blur(12px) saturate(150%);
    border-color: var(--bord-fort); border-radius: 14px;
    box-shadow: var(--ombre-haut); width: 44px; height: 44px;
  }
  .barre-outils:not(.sans-colonne) .flottant:hover {
    color: var(--accent-sombre); border-color: var(--accent); transform: translateY(-2px);
  }
}

/* ── Fiche de révision : marge droite, mais seulement si elle existe ──── */
@media (min-width: 1380px) {
  .barre-outils.sans-colonne {
    left: auto; right: 16px; bottom: 22px;
    flex-direction: column; justify-content: flex-start; gap: 10px;
    padding: 0; background: none; border-top: 0;
    backdrop-filter: none; -webkit-backdrop-filter: none;
    transition: opacity .22s var(--ease), transform .26s var(--ease);
  }
  .barre-outils.sans-colonne.effacee {
    opacity: 0; transform: translateX(120%); pointer-events: none;
  }
  /* Posé seul au-dessus de la page, un bouton porte son propre verre dépoli ;
     dans la barre du bas, c'est la barre qui le porte — pas lui. */
  .barre-outils.sans-colonne .flottant {
    background: color-mix(in srgb, var(--carte) 88%, transparent);
    backdrop-filter: blur(12px) saturate(150%);
    -webkit-backdrop-filter: blur(12px) saturate(150%);
    border-color: var(--bord-fort); border-radius: 14px;
    box-shadow: var(--ombre-haut); width: 44px; height: 44px;
  }
  .barre-outils.sans-colonne .flottant:hover {
    color: var(--accent-sombre); border-color: var(--accent); transform: translateY(-2px);
  }
}
@media print { .barre-outils, .toast { display: none !important; } }

/* ═══════════════════════════════════════════════════════════════════════
   MOUVEMENT — discret, utile, et toujours désactivable
   « Emotional Design » : l'animation confirme une action ou explique une
   apparition. Elle ne décore jamais pour décorer, et elle cède devant
   « prefers-reduced-motion » comme devant le réglage de la feuille.
   ═══════════════════════════════════════════════════════════════════════ */
:root { --ease: cubic-bezier(.32,.72,0,1); }

@keyframes monter { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
@keyframes pop    { 0% { transform: scale(1); } 45% { transform: scale(1.28); } 100% { transform: scale(1); } }
@keyframes glisse { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }

.apparait { opacity: 0; }
.apparait.vu { animation: monter .5s var(--ease) both; animation-delay: var(--retard, 0ms); }
.coche.pulse { animation: pop .42s var(--ease); }
.resultats { animation: glisse .16s var(--ease) both; }
.toast { transition: opacity .2s var(--ease), transform .26s var(--ease); }

/* La carte se soulève, et son filet de couleur s'épaissit : deux signaux pour
   la même information, l'un de forme, l'autre de couleur. */
.carte-matiere::after { transition: width .18s var(--ease); }
.carte-matiere:hover::after { width: 5px; }
.carte-matiere .ic { transition: transform .22s var(--ease); }
.carte-matiere:hover .ic { transform: scale(1.08) rotate(-4deg); }
.carte-matiere:active { transform: translateY(-1px) scale(.995); }

.chapitre .liens a { transition: background .14s, color .14s, border-color .14s, transform .14s; }
.chapitre .liens a:active { transform: scale(.96); }

/* La reprise se distingue de la grille : elle traverse toute la largeur. */
.carte-matiere.reprise { grid-column: 1 / -1; }

/* Un anneau de focus visible partout — au clavier, on doit savoir où l'on est. */
a:focus-visible, button:focus-visible, select:focus-visible, input:focus-visible,
summary:focus-visible, [tabindex]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px; border-radius: 4px;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important; animation-iteration-count: 1 !important;
    transition-duration: .001ms !important; scroll-behavior: auto !important;
  }
  .apparait { opacity: 1; }
}
html[data-anim="0"] .apparait { opacity: 1; }

/* ═══════════════════════════════════════════════════════════════════════
   ADAPTATION — du téléphone au très grand écran
   Mesuré aux largeurs réelles : 375 (iPhone SE/13 mini), 390 (iPhone 15),
   768 (iPad portrait), 1024 (iPad paysage), 1440 (MacBook), 1920 et 2560.
   ═══════════════════════════════════════════════════════════════════════ */

/* — Téléphone ——————————————————————————————————————————————————————— */
/* Sous 420 px, le titre perdait ses trois derniers pixels : le logo, deux
   liens et deux boutons ne tiennent qu'en resserrant les écarts. */
/* Sous 420 px, le logo, deux liens et deux boutons ne tiennent pas avec le
   titre : c'est le titre qui cède. Le badge de la classe identifie le site à
   lui seul, et le lien reste étiqueté pour les lecteurs d'écran. */
@media (max-width: 420px) {
  /* Quatre destinations au lieu de trois : sous 420 px la barre ne tient
     plus sur une ligne, il lui manque une quarantaine de pixels. On a essayé
     de les prendre sur les pastilles — le banc du site refuse toute cible
     tactile sous 34 px, et il a raison : un bouton qu'on rate deux fois sur
     trois ne vaut pas la ligne qu'il économise. La barre passe donc à deux
     rangées, et on l'assume : le badge seul en haut, la navigation étalée
     en dessous. Les écarts sont resserrés, les cibles gardent leur taille. */
  .app-tete { gap: .25rem; padding: .55rem .35rem; }
  /* « flex: 1 1 auto » et non « 1 0 100% » : imposer la pleine largeur
     envoyait la barre sur une deuxième ligne même à 420 px, où elle tenait
     encore à côté du badge. Là, elle reste sur la ligne tant qu'elle y entre,
     et quand elle n'y entre plus elle occupe toute la sienne. */
  .app-tete nav { gap: .1rem; flex: 1 1 auto; }
  .app-marque .nom { display: none; }
  /* Le titre parti, le lien d'accueil se réduisait au badge : 27 px de large,
     sous le seuil de 34 px que le banc du site refuse. C'est le lien le plus
     souvent visé sur un téléphone. Il reprend une taille qu'on atteint. */
  .app-marque .sigle { width: 34px; height: 34px; }
}
/* La barre d'application, mesurée plutôt que devinée.
   Avec ses cinq liens et le titre entier, elle réclame 841 px — mesuré dans
   le navigateur, pas estimé. Le seuil des liens secondaires était fixé à
   620 px : entre 620 et 841 px, la barre débordait et décalait TOUTE la page
   de plusieurs dizaines de pixels. Le défaut existait déjà à quatre liens ;
   l'arrivée de « Planning » n'a fait qu'élargir la bande.
   « Accueil » est déjà le logo, « À propos » est repris dans le pied : ce
   sont eux qui cèdent, puis la queue du titre — le badge de la classe
   identifie le site à lui seul. */
@media (max-width: 900px) {
  /* Le pictogramme remplace le mot au lieu de supprimer le lien. Avant,
     « Accueil » et « À propos » disparaissaient purement et simplement sous
     620 px — sur le seul appareil où l'on navigue vraiment. */
  /* Sous ce seuil, les libellés des liens cèdent la place au seul picto.
     Le bouton 3D, lui, N'A que son libellé — il n'a pas de picto à montrer
     à sa place, et sans cette exception il devenait une case vide. */
  .app-tete nav a:not(.bouton-3d) span { display: none; }
  /* 19 px de dessin + 2 × 8 px = 35 px : au-dessus du plancher de 34 px que
     le banc tactile exige. Mesuré, pas estimé — la première valeur essayée
     (.42rem) donnait 32 px, et serait passée inaperçue à l'œil. */
  .app-tete nav a { padding: .5rem .56rem; }
  .app-tete nav a .ico { width: 19px; height: 19px; }
  .app-marque .nom-long { display: none; }
}
/* Le filet. Un seuil est toujours calculé pour une police, une langue et un
   nombre de liens donnés ; le jour où l'un des trois change, il ment. Ici la
   barre passe à la ligne au lieu de pousser la page : elle peut devenir
   haute, elle ne peut plus déborder. */
/* Entre 481 et 620 px, la barre reprenait d'un coup son pas large : les
   trois liens passaient de 236 à 260 px et elle repartait sur deux rangées
   à 520 et 560 px — mesuré. Le pas compact tient jusqu'à ce que la place
   soit vraiment là. */
@media (min-width: 481px) and (max-width: 620px) {
  .app-tete { gap: .45rem; padding: .6rem .7rem; }
  .app-tete nav a { font-size: .7879rem; }
  .app-marque { font-size: .8485rem; }
  .app-marque .sigle { width: 27px; height: 27px; }
}

.app-tete { flex-wrap: wrap; }
/* « flex: none » interdisait à la barre de rétrécir : sans ce remplacement,
   les deux règles ci-dessous ne serviraient à rien. */
.app-tete nav { flex: 0 1 auto; min-width: 0; flex-wrap: wrap; justify-content: flex-end; }
/* ── La barre serrée : une seule rangée, le badge seul ───────────────────
   Signalé : « le menu est moche, il est gros, il prend beaucoup de place —
   tu peux peut-être mettre l'icône sur la même ligne et retirer le texte
   BTS CIEL quand l'écran est serré ».

   Mesuré avant de corriger, et ce n'est pas le texte qui débordait : à
   390 px il était DÉJÀ tronqué à rien, et la barre faisait quand même
   112 px de haut sur deux rangées. Le compte : 390 − 26 de rembourrage
   − 34 de porte-logo − 8 d'écart = 322 px disponibles pour une rangée de
   liens qui en réclame 327. Il manquait CINQ pixels.

   On les prend donc là où ils ne coûtent rien — l'écart entre les liens et
   le rembourrage de la barre — et pas sur les liens eux-mêmes, qui sont des
   cibles tactiles et doivent rester à 34 px. Et le mot disparaît pour de
   bon sous 480 px au lieu de s'effilocher en « … » : un titre tronqué à
   deux lettres n'informe personne et occupe quand même sa place. */
@media (max-width: 480px) {
  .app-tete nav a { font-size: .7879rem; }
  .app-marque { font-size: .8485rem; }
  .app-marque .sigle { width: 27px; height: 27px; }
  .app-marque .nom-long { display: none; }
  .heros { padding-top: 2rem; }
  .heros .promo { font-size: .6667rem; }
  .recherche { margin-top: 1.3rem; }
  .resultats { max-height: 52vh; }
  .grille-matieres { grid-template-columns: 1fr; gap: .7rem; margin-top: 1.6rem; }
  .carte-matiere { padding: 1.1rem 1.1rem 1rem; }
  .chiffres { gap: 1.1rem 1.6rem; }
  .chiffres strong { font-size: 1.55rem; }
  .feuille-corps { padding: .4rem .95rem 1.2rem; }
  .pastilles button { padding: .44rem .7rem; }   /* ≥ 38 px de haut : cible tactile */
}

/* — Tablette portrait ————————————————————————————————————————————— */
@media (min-width: 481px) and (max-width: 900px) {
  .grille-matieres { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* — Écran large : la feuille de réglages devient un panneau latéral ——— */
@media (min-width: 1100px) {
  .grille-matieres { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
}

/* — Très grand écran : on remplit sans étirer le texte ————————————— */
@media (min-width: 1600px) {
  .grille-matieres { grid-template-columns: repeat(auto-fit, minmax(330px, 1fr)); gap: 1.2rem; }
  .heros h1 { font-size: clamp(3rem, 3.4vw, 4.2rem); }
  .chapitre { padding: 1.05rem 1.3rem; }
}

/* — Pointeur grossier : toutes les cibles à 44 px, pas d'effet de survol —— */
@media (hover: none) and (pointer: coarse) {
  .carte-matiere:hover { transform: none; box-shadow: var(--ombre); }
  .chapitre:hover { transform: none; }
  .chapitre .liens a { padding: .5rem .85rem; }
  .coche { width: 38px; height: 38px; }
}

/* — Écran court et large (portable posé, fenêtre réduite) ———————————— */
@media (max-height: 560px) and (min-width: 720px) {
  .heros { padding-top: 1.6rem; padding-bottom: 1.2rem; }
  .feuille { max-height: 94vh; }
}

/* Bouton « au hasard » — tirer une fiche quand on ne sait pas par où
   commencer. Repris de Sakina, où il ouvre une invocation au hasard. */
.bouton-hasard {
  display: inline-flex; align-items: center; gap: .45rem; cursor: pointer;
  margin-top: 1rem; padding: .5rem 1rem; border-radius: 999px;
  font: inherit; font-size: .8182rem; font-weight: 650;
  background: var(--carte); color: var(--encre-douce);
  border: 1px solid var(--bord-fort); box-shadow: var(--ombre);
  transition: transform .16s var(--ease), border-color .15s, color .15s;
}
.bouton-hasard:hover { border-color: var(--accent); color: var(--accent-sombre); transform: translateY(-2px); }
.bouton-hasard:active { transform: translateY(0) scale(.97); }
.bouton-hasard .de { display: inline-block; transition: transform .3s var(--ease); }
.bouton-hasard:hover .de { transform: rotate(180deg); }

/* ═══════════════════════════════════════════════════════════════════════
   NAVIGATION ENTRE CHAPITRES
   Enchaîner deux chapitres demandait de remonter à l'index de la matière :
   deux clics et un aller-retour pour avancer d'une page.
   ═══════════════════════════════════════════════════════════════════════ */
/* La pile de trois boutons flottants occupe 168 px en bas à droite. Sans ce
   dégagement, elle recouvrait la carte « chapitre suivant » — le dernier bloc
   de la page, et le seul qu'on cherche à atteindre en bas. */
.voisins {
  display: grid; grid-template-columns: 1fr 1fr; gap: .8rem;
  margin: 3.2rem 0 5rem; padding-top: 1.8rem; border-top: 1px solid var(--bord);
}
.voisins a {
  display: flex; flex-direction: column; gap: .18rem;
  padding: .9rem 1.1rem; border-radius: var(--r);
  background: var(--carte); border: 1px solid var(--bord);
  text-decoration: none; box-shadow: var(--ombre); min-width: 0;
  transition: border-color .15s, transform .15s var(--ease), box-shadow .15s;
}
.voisins a span {
  font-size: .7273rem; font-weight: 650; color: var(--encre-tenue);
  text-transform: uppercase; letter-spacing: .07em;
}
.voisins a b {
  font-size: .9394rem; font-weight: 660; color: var(--encre); line-height: 1.35;
  overflow-wrap: anywhere;
}
.voisins a:hover {
  border-color: var(--accent); transform: translateY(-2px); box-shadow: var(--ombre-haut);
}
.voisins a:hover b { color: var(--accent-sombre); }
.voisins .suiv { text-align: right; align-items: flex-end; }
.voisins .prec span::before { content: "\2190\00a0"; }
.voisins .suiv span::after  { content: "\00a0\2192"; }
/* La case vide garde sa colonne : sans elle, « suivant » remonterait à
   gauche sur le premier chapitre, et la flèche pointerait vers l'arrière. */
.voisins .vide { display: block; }
@media (max-width: 620px) {
  .voisins { grid-template-columns: 1fr; margin: 2.4rem 0 1.5rem; }
  .voisins .vide { display: none; }
  .voisins .suiv { text-align: left; align-items: flex-start; }
}
@media print { .voisins { display: none; } }

/* ═══════════════════════════════════════════════════════════════════════
   PALETTE DE RECHERCHE — ouvrable depuis n'importe quelle page
   C'est depuis une fiche qu'on cherche le plus, en plein TP. Le champ de
   l'accueil ne servait plus dès qu'un cours était ouvert.
   ═══════════════════════════════════════════════════════════════════════ */
.palette {
  position: fixed; z-index: 92;
  left: 50%; top: max(14px, 9vh);
  width: min(680px, calc(100vw - 1.6rem));
  transform: translate(-50%, -10px);
  background: var(--carte); color: var(--encre);
  border: 1px solid var(--bord-fort); border-radius: var(--r-l);
  box-shadow: var(--ombre-haut); overflow: hidden;
  opacity: 0; pointer-events: none;
  transition: opacity .16s var(--ease), transform .18s var(--ease);
}
.palette.ouverte { opacity: 1; pointer-events: auto; transform: translate(-50%, 0); }
.palette-champ {
  display: flex; align-items: center; gap: .6rem;
  padding: .55rem .6rem .55rem 1rem; border-bottom: 1px solid var(--bord);
}
.palette-champ svg { width: 18px; height: 18px; flex: none; color: var(--encre-tenue); }
.palette-champ input {
  flex: 1; min-width: 0; border: 0; background: transparent; outline: none;
  font: inherit; font-size: 1.03rem; color: var(--encre); padding: .4rem 0;
}
.palette-champ input::placeholder { color: var(--encre-tenue); }
/* La liste partagée avec l'accueil s'y pose à plat : elle n'a plus à flotter. */
.palette .resultats {
  position: static; transform: none; animation: none;
  border: 0; border-radius: 0; box-shadow: none;
  max-height: min(52vh, 420px); padding: .35rem;
}
.palette-aide {
  margin: 0; padding: .5rem .9rem; border-top: 1px solid var(--bord);
  font-size: .7273rem; color: var(--encre-tenue);
}
.palette-aide b { color: var(--encre-douce); }
@media (hover: none) and (pointer: coarse) { .palette-aide { display: none; } }
@media print { .palette, .voile { display: none !important; } }

/* Troisième bouton flottant : la loupe, au-dessus des deux autres. */
.flottant-3 { bottom: max(124px, calc(env(safe-area-inset-bottom) + 108px)); }

/* ═══════════════════════════════════════════════════════════════════════
   VU RÉCEMMENT — réviser, c'est faire des allers-retours
   ═══════════════════════════════════════════════════════════════════════ */
.recents { grid-column: 1 / -1; }
.recents h3 {
  margin: 0 0 .55rem; font-size: .697rem; font-weight: 750;
  letter-spacing: .09em; text-transform: uppercase; color: var(--encre-tenue);
}
.recents ul { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: .4rem; }
.recents li { min-width: 0; max-width: 100%; }
.recents a {
  display: inline-flex; align-items: center; min-height: 36px;
  padding: .3rem .85rem; border-radius: 999px; max-width: 100%;
  background: var(--carte); border: 1px solid var(--bord);
  color: var(--encre-douce); font-size: .7879rem; font-weight: 620;
  text-decoration: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  transition: border-color .14s, color .14s, transform .14s var(--ease);
}
/* Un point dans la couleur de la matière : on lit d'un coup d'œil si la fiche
   était du réseau ou des maths, sans avoir à relire le titre. */
.recents a::before {
  content: ""; flex: none; width: 7px; height: 7px; border-radius: 999px;
  background: var(--accent); margin-right: .5rem;
}
.recents a:hover { border-color: var(--accent); color: var(--accent-sombre); transform: translateY(-1px); }

/* ═══════════════════════════════════════════════════════════════════════
   OUTILS — convertisseur et table des masques

   La couleur y fait un travail, elle ne décore pas : elle dit à quel octet
   appartient un groupe de huit bits, et où s'arrête le réseau dans un masque.
   Les quatre teintes sont celles que le design system définit DÉJÀ pour les
   quarante thèmes — accent, vert, violet, ambre. Aucune couleur nouvelle
   n'est écrite en dur : elles suivent le thème comme le reste.
   ═══════════════════════════════════════════════════════════════════════ */
.outil {
  --o1: var(--accent-sombre); --o2: var(--vert);
  --o3: var(--violet);        --o4: var(--ambre-sombre);
  --o1-fond: var(--accent-pale); --o2-fond: var(--vert-pale);
  --o3-fond: var(--violet-pale); --o4-fond: var(--ambre-pale);

  margin-top: 2.2rem; padding: 1.5rem 1.6rem 1.7rem;
  background: var(--carte); border: 1px solid var(--bord);
  border-top: 3px solid var(--accent); border-radius: var(--r-l);
  box-shadow: var(--ombre);
}
.outil > h2 {
  display: flex; align-items: center; gap: .6rem;
  margin: 0 0 .5rem; font-size: 1.24rem; font-weight: 740;
  letter-spacing: -.018em; color: var(--encre);
}
.num-outil {
  flex: none; width: 26px; height: 26px; border-radius: 999px;
  display: grid; place-items: center;
  background: var(--accent); color: var(--sur-accent);
  font-family: var(--mono); font-size: .7576rem; font-weight: 700;
}
.outil .intro { margin: 0 0 1.2rem; color: var(--encre-douce); font-size: .9394rem; line-height: 1.6; }
.outil .note  { margin: .9rem 0 0; font-size: .8182rem; color: var(--encre-tenue); line-height: 1.6; }

/* ── Les huit bits d'un octet ───────────────────────────────────────── */
.bits { display: grid; grid-template-columns: repeat(8, minmax(0, 1fr)); gap: .3rem; }
.bit { display: flex; flex-direction: column; align-items: center; gap: .3rem; min-width: 0; }
.bit .poids {
  font-family: var(--mono); font-size: .697rem; font-weight: 600;
  color: var(--encre-tenue); letter-spacing: -.02em;
}
.bit button {
  width: 100%; min-height: 48px; cursor: pointer; padding: 0;
  font-family: var(--mono); font-size: 1.15rem; font-weight: 700;
  background: var(--carte-creuse); color: var(--encre-tenue);
  border: 1px solid var(--bord-fort); border-radius: var(--r);
  transition: background .12s, color .12s, border-color .12s, transform .1s var(--ease);
}
.bit button:hover { border-color: var(--accent); color: var(--encre); }
.bit button:active { transform: scale(.94); }
/* Un bit allumé prend l'accent : fond d'accent, texte « sur-accent » — le
   seul couple dont le contraste est garanti sur les quarante thèmes. */
.bit button[aria-pressed="true"] {
  background: var(--accent); color: var(--sur-accent); border-color: var(--accent);
}

/* On montre l'addition, pas seulement le résultat : c'est l'opération qu'on
   pose au tableau, et c'est elle qu'il faut retenir. */
.calcul {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: .1rem;
  margin: 1rem 0 1.2rem; padding: .75rem .95rem; border-radius: var(--r);
  background: var(--accent-pale); border-left: 3px solid var(--accent);
  font-family: var(--mono); font-size: .9394rem; color: var(--encre);
}
.calcul .plus, .calcul .egal { color: var(--accent-sombre); padding: 0 .45rem; font-weight: 700; }
.calcul b { font-size: 1.24em; font-weight: 800; color: var(--accent-sombre); }

/* ── Champs ─────────────────────────────────────────────────────────── */
.rangee { display: flex; flex-wrap: wrap; gap: .75rem; }
.rangee label {
  display: flex; flex-direction: column; gap: .3rem; flex: 1 1 9rem; min-width: 0;
  font-size: .697rem; font-weight: 700; letter-spacing: .09em;
  text-transform: uppercase; color: var(--encre-tenue);
}
.rangee input {
  width: 100%; box-sizing: border-box; min-height: 46px;
  padding: .55rem .75rem; font-family: var(--mono); font-size: 1.03rem;
  color: var(--encre); background: var(--carte-creuse);
  border: 1px solid var(--bord-fort); border-radius: var(--r);
  transition: border-color .15s, box-shadow .15s;
}
.rangee input:focus {
  outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-pale);
}
/* Chaque base a son repère de couleur, repris du bloc des bits. */
.ch-dec input { border-left: 3px solid var(--o1); }
.ch-bin input { border-left: 3px solid var(--o2); }
.ch-hex input { border-left: 3px solid var(--o3); }

/* ── L'adresse IPv4, un octet par colonne ───────────────────────────── */
.ipv4 {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: .5rem;
  margin-top: 1.1rem;
}
.oct {
  display: flex; flex-direction: column; gap: .25rem; min-width: 0;
  padding: .7rem .5rem .6rem; border-radius: var(--r); text-align: center;
  border: 1px solid var(--bord);
}
.oct .rang {
  font-size: .6667rem; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; opacity: .9;
}
.oct .val { font-family: var(--mono); font-size: 1.36rem; font-weight: 800; line-height: 1.1; }
.oct .b8  { font-family: var(--mono); font-size: .7576rem; letter-spacing: .04em; color: var(--encre-douce); }
/* « encre tenue » tombait à 3,73:1 sur le fond teinté du thème Midgar —
   mesuré, pas supposé. « encre douce » y tient 6,59:1, et la ligne
   hexadécimale reste discrète face au décimal qui la surplombe. */
.oct .hx  { font-family: var(--mono); font-size: .697rem; color: var(--encre-douce); }
.oct.o1 { background: var(--o1-fond); border-color: color-mix(in srgb, var(--o1) 30%, transparent); }
.oct.o2 { background: var(--o2-fond); border-color: color-mix(in srgb, var(--o2) 30%, transparent); }
.oct.o3 { background: var(--o3-fond); border-color: color-mix(in srgb, var(--o3) 30%, transparent); }
.oct.o4 { background: var(--o4-fond); border-color: color-mix(in srgb, var(--o4) 30%, transparent); }
.oct.o1 .rang, .oct.o1 .val { color: var(--o1); }
.oct.o2 .rang, .oct.o2 .val { color: var(--o2); }
.oct.o3 .rang, .oct.o3 .val { color: var(--o3); }
.oct.o4 .rang, .oct.o4 .val { color: var(--o4); }
.ipv4 .invalide { grid-column: 1 / -1; margin: 0; color: var(--rouge); font-size: .8788rem; }
@media (max-width: 560px) { .ipv4 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* ── Table des masques ──────────────────────────────────────────────── */
.filtre { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; margin-bottom: .9rem; }
.filtre label {
  font-size: .697rem; font-weight: 700; letter-spacing: .09em;
  text-transform: uppercase; color: var(--encre-tenue);
}
.filtre input {
  flex: 1 1 15rem; min-width: 0; box-sizing: border-box; min-height: 46px;
  padding: .5rem .8rem; font: inherit; font-size: .9091rem; color: var(--encre);
  background: var(--carte-creuse); border: 1px solid var(--bord-fort); border-radius: var(--r);
}
.filtre input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-pale); }
.filtre button {
  min-height: 46px; padding: .5rem .9rem; cursor: pointer; flex: none;
  font: inherit; font-size: .8182rem; font-weight: 650;
  background: var(--carte-creuse); color: var(--encre-douce);
  border: 1px solid var(--bord-fort); border-radius: var(--r);
  transition: border-color .14s, color .14s;
}
.filtre button:hover { border-color: var(--accent); color: var(--accent-sombre); }

.legende {
  display: flex; flex-wrap: wrap; align-items: center; gap: .4rem 1.1rem;
  margin: 0 0 1rem; font-size: .8182rem; color: var(--encre-douce);
}
.legende .pl { width: 14px; height: 14px; border-radius: 4px; display: inline-block; }
.legende .pl-res  { background: var(--accent); }
.legende .pl-hote { background: var(--carte-creuse); border: 1px solid var(--bord-fort); }

/* Le masque en binaire, sous sa forme décimale : les 1 sont les bits de
   réseau, les 0 ceux d'hôte. C'est tout ce qu'un masque veut dire, et
   « 255.255.255.192 » ne le montre pas. */
.mb {
  display: block; margin-top: .25rem;
  font-family: var(--mono); font-size: .6667rem; letter-spacing: .02em; white-space: nowrap;
}
.mb b { background: var(--accent-pale); color: var(--accent-sombre); font-weight: 700; padding: .05em 0; }
.mb i { background: var(--carte-creuse); color: var(--encre-tenue); font-style: normal; padding: .05em 0; }
.mb .sep { color: var(--bord-fort); padding: 0 .1em; }

#table-masques th[scope="row"] {
  font-family: var(--mono); font-size: .9394rem; font-weight: 700;
  color: var(--accent-sombre); background: var(--accent-pale); white-space: nowrap;
}
#table-masques .nb { font-family: var(--mono); white-space: nowrap; }
#table-masques .rq { color: var(--encre-tenue); font-size: .92em; }
#table-masques tr[hidden] { display: none; }

/* ── Les cartes du sommaire des outils ──────────────────────────────── */
.carte-outil .ic, .carte-outils .ic { font-size: 19px; }

/* ═══════════════════════════════════════════════════════════════════════
   LE SOMMAIRE DES OUTILS, PAR CATÉGORIE

   Six outils alignés se lisaient comme une liste de courses. Groupés, ils
   répondent à une question différente chacun : « je calcule », « je suis en
   TP », « je rends une copie ». Le titre de catégorie porte la question.
   ═══════════════════════════════════════════════════════════════════════ */
.cat-outils { margin-top: 2.6rem; }
.cat-outils:first-of-type { margin-top: 1.4rem; }
.cat-tete {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: .2rem .9rem;
  padding-bottom: .7rem; border-bottom: 1px solid var(--bord);
}
.cat-tete h2 {
  margin: 0; font-size: 1.06rem; font-weight: 760; color: var(--encre);
  letter-spacing: -.014em;
}
.cat-tete p { margin: 0; font-size: .8182rem; color: var(--encre-douce); }
.cat-outils .grille-matieres { margin-top: 1rem; }

/* ═══════════════════════════════════════════════════════════════════════
   CALCULATEUR DE SOUS-RÉSEAU

   Huit résultats à lire d'un coup d'œil : la clé en petites capitales, la
   valeur en chiffres larges, et la raison en dessous. Les quatre teintes
   sont celles du bloc « .outil » — accent, vert, violet, ambre — déjà
   mesurées sur les quarante thèmes.
   ═══════════════════════════════════════════════════════════════════════ */
.res {
  display: grid; gap: .5rem; margin-top: 1.2rem;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
.res .r {
  display: flex; flex-direction: column; gap: .12rem; min-width: 0;
  padding: .7rem .85rem .75rem; border-radius: var(--r);
  background: var(--carte-creuse); border: 1px solid var(--bord);
  border-left: 3px solid var(--bord-fort);
}
/* « encre tenue » tombait entre 3,71 et 4,17:1 sur les fonds teintés du
   thème Midgar — mesuré, comme pour « .oct .hx ». « encre douce » y tient. */
.res .k {
  font-size: .6667rem; font-weight: 700; letter-spacing: .07em;
  text-transform: uppercase; color: var(--encre-douce);
}
.res .v {
  font-family: var(--mono); font-size: 1.12rem; font-weight: 800;
  color: var(--encre); letter-spacing: -.015em; overflow-wrap: anywhere;
}
.res .s { font-size: .7273rem; color: var(--encre-douce); line-height: 1.45; }
.res .o1 { border-left-color: var(--o1); background: var(--o1-fond); }
.res .o2 { border-left-color: var(--o2); background: var(--o2-fond); }
.res .o3 { border-left-color: var(--o3); background: var(--o3-fond); }
.res .o4 { border-left-color: var(--o4); background: var(--o4-fond); }
.res .o1 .v { color: var(--o1); }
.res .o2 .v { color: var(--o2); }
.res .o3 .v { color: var(--o3); }
.res .o4 .v { color: var(--o4); }

/* L'opération posée : adresse, masque, et le résultat du ET logique. C'est
   la seule partie de l'outil qu'on recopie sur une feuille d'examen. */
.mb-pose {
  margin-top: 1.4rem; padding: .9rem 1rem; border-radius: var(--r);
  background: var(--carte-creuse); border: 1px solid var(--bord); overflow-x: auto;
}
.mbl {
  display: flex; align-items: center; gap: .7rem; white-space: nowrap;
  padding: .22rem 0; font-size: .8182rem;
}
.mbl > span:first-child {
  flex: none; width: 5.4rem; text-align: right;
  font-size: .6667rem; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--encre-douce);
}
.mbl .d { font-family: var(--mono); font-size: .7576rem; color: var(--encre-douce); font-weight: 700; }
.mbl.et { border-top: 1px solid var(--bord-fort); margin-top: .2rem; padding-top: .45rem; }
.mbl.et > span:first-child, .mbl.et .d { color: var(--accent-sombre); }

.sr-erreur {
  margin: .9rem 0 0; padding: .6rem .8rem; border-radius: var(--r);
  background: var(--rouge-pale); border-left: 3px solid var(--rouge);
  color: var(--rouge); font-size: .8485rem; font-weight: 600;
}
.sr-legende {
  caption-side: bottom; padding-top: .6rem; text-align: left;
  font-size: .7576rem; color: var(--encre-douce);
}
/* Un « select » du système ne suit pas la carte : sur un thème sombre il
   reste blanc. On le rhabille comme les champs voisins. */
.rangee select {
  width: 100%; box-sizing: border-box; min-height: 46px;
  padding: .55rem .6rem; font: inherit; font-size: .9091rem; color: var(--encre);
  background: var(--carte-creuse); border: 1px solid var(--bord-fort);
  border-radius: var(--r); cursor: pointer;
}
.rangee select:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-pale); }
#dc-table th[scope="row"], #table-ports th[scope="row"] {
  font-family: var(--mono); font-size: .8788rem; font-weight: 700;
  color: var(--accent-sombre); background: var(--accent-pale); white-space: nowrap;
}
#dc-table .nb, #table-ports .nb { font-family: var(--mono); white-space: nowrap; }
#table-ports tr[hidden] { display: none; }

/* La colonne « sur le câble » : deux mots et une pastille. C'est la seule
   différence entre 23 et 22, entre 80 et 443 — elle doit se voir. */
.legende .pl-clair { background: var(--rouge); }
.legende .pl-sur   { background: var(--vert); }
td.etat { white-space: nowrap; font-size: .8182rem; font-weight: 650; }
td.etat .pl { margin-right: .35rem; vertical-align: -1px; }
td.etat.clair { color: var(--rouge); }
td.etat.sur   { color: var(--vert); }

/* ═══════════════════════════════════════════════════════════════════════
   COMMANDES PACKET TRACER

   Un bloc = une intention, et il se copie d'un seul geste. La barre du haut
   filtre par mot ou par catégorie : dix-neuf blocs empilés ne se parcourent
   pas au pouce.
   ═══════════════════════════════════════════════════════════════════════ */
.pt-barre {
  position: sticky; top: 0; z-index: 5;
  margin: 1.8rem 0 .4rem; padding: .9rem 0 .7rem;
  background: var(--papier);
  border-bottom: 1px solid var(--bord);
}
.pt-barre .filtre { margin-bottom: .6rem; }
.pt-chips { display: flex; flex-wrap: wrap; gap: .35rem; }
.pt-chip {
  cursor: pointer; font: inherit; font-size: .7576rem; font-weight: 650;
  min-height: 34px; padding: .3rem .7rem; border-radius: 999px;
  background: var(--carte-creuse); color: var(--encre-douce);
  border: 1px solid var(--bord-fort);
  transition: background .14s, color .14s, border-color .14s;
}
.pt-chip:hover { border-color: var(--accent); color: var(--accent-sombre); }
.pt-chip.on { background: var(--accent); color: var(--sur-accent); border-color: var(--accent); }
.pt-rien { margin: .8rem 0 0; font-size: .8485rem; color: var(--encre-douce); }

.pt-cat { margin-top: 1.6rem; }
.pt-cat[hidden] { display: none; }
.pt-bloc {
  margin-top: 1.3rem; padding-top: 1.2rem; border-top: 1px solid var(--bord);
}
.pt-bloc:first-of-type { margin-top: 1rem; padding-top: 0; border-top: 0; }
.pt-bloc[hidden] { display: none; }
.pt-tete { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem .7rem; }
.pt-tete h3 {
  margin: 0; font-size: 1rem; font-weight: 740; color: var(--encre);
  letter-spacing: -.012em;
}
.pt-eq {
  flex: none; padding: .14rem .55rem; border-radius: 999px;
  background: var(--accent-pale); color: var(--accent-sombre);
  font-size: .6667rem; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
}
.pt-quoi { margin: .4rem 0 0; font-size: .8788rem; color: var(--encre-douce); line-height: 1.55; }
.pt-bloc .bloc-code { margin: .9rem 0 0; }
.pt-bloc .note { margin-top: .75rem; }

/* ═══════════════════════════════════════════════════════════════════════
   COMPTEUR DU COMPTE RENDU

   Trois blocs, trois cibles, et un état par bloc : trop court, dans la
   cible, trop long. Les trois teintes sont celles des encarts — ambre,
   vert, rouge — dont les contrastes sont déjà mesurés.
   ═══════════════════════════════════════════════════════════════════════ */
.cr-blocs { display: grid; gap: 1rem; }
.cr-bloc {
  padding: .9rem 1rem 1rem; border-radius: var(--r);
  background: var(--carte-creuse); border: 1px solid var(--bord);
  border-left: 3px solid var(--bord-fort);
}
.cr-tete { display: flex; flex-wrap: wrap; align-items: baseline; gap: .2rem .7rem; }
.cr-tete h3 { margin: 0; font-size: .9394rem; font-weight: 740; color: var(--encre); }
.cr-cible {
  font-size: .6667rem; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--encre-douce);
}
.cr-bloc textarea {
  display: block; width: 100%; box-sizing: border-box; margin-top: .6rem;
  padding: .7rem .8rem; font: inherit; font-size: .9091rem; line-height: 1.6;
  color: var(--encre); background: var(--carte);
  border: 1px solid var(--bord-fort); border-radius: var(--r);
  resize: vertical; min-height: 5.5rem;
}
.cr-bloc textarea:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-pale); }
.cr-verdict { margin: .5rem 0 0; font-size: .8182rem; font-weight: 650; min-height: 1.2em; }
/* Chaque état reprend le fond teinté de l'encart de la même couleur : c'est
   le couple fond/texte dont le contraste est déjà mesuré sur les 40 thèmes.
   Posé sur le fond neutre du bloc, l'ambre tombait à 4,17:1 sur Androïde. */
.cr-bloc.court { border-left-color: var(--ambre); background: var(--ambre-pale); }
.cr-bloc.court .cr-verdict { color: var(--ambre-sombre); }
.cr-bloc.juste { border-left-color: var(--vert); background: var(--vert-pale); }
.cr-bloc.juste .cr-verdict { color: var(--vert); }
.cr-bloc.long  { border-left-color: var(--rouge); background: var(--rouge-pale); }
.cr-bloc.long  .cr-verdict { color: var(--rouge); }

.cr-total {
  margin-top: 1.4rem; padding: 1.1rem 1.2rem; border-radius: var(--r);
  background: var(--carte-creuse); border: 1px solid var(--bord);
  border-top: 3px solid var(--bord-fort);
}
.cr-chiffre { display: flex; align-items: baseline; gap: .55rem; }
.cr-chiffre b {
  font-family: var(--mono); font-size: 2rem; font-weight: 800; line-height: 1;
  letter-spacing: -.03em; color: var(--encre);
}
.cr-chiffre span { font-size: .7576rem; font-weight: 700; letter-spacing: .07em;
  text-transform: uppercase; color: var(--encre-douce); }
.cr-jauge { margin: .9rem 0 .5rem; }
.cr-piste {
  position: relative; height: 10px; border-radius: 999px;
  background: var(--carte); border: 1px solid var(--bord-fort); overflow: hidden;
}
/* La fourchette acceptée, 180 à 220 sur une échelle de 0 à 260 : de 69,2 %
   à 84,6 % de la piste. Les deux bornes sont calculées, pas estimées. */
.cr-zone {
  position: absolute; top: 0; bottom: 0; left: 69.23%; width: 15.38%;
  background: var(--vert-pale); border-left: 1px solid var(--vert);
  border-right: 1px solid var(--vert);
}
.cr-curseur {
  position: absolute; top: -3px; bottom: -3px; width: 3px; left: 0;
  background: var(--encre); border-radius: 2px;
  transition: left .18s var(--ease);
}
.cr-graduations {
  display: flex; justify-content: space-between; margin-top: .3rem;
  font-family: var(--mono); font-size: .6667rem; color: var(--encre-douce);
}
.cr-etat { margin: 0; font-size: .8485rem; font-weight: 650; color: var(--encre-douce); }
.cr-total.court { border-top-color: var(--ambre); background: var(--ambre-pale); }
.cr-total.court .cr-etat { color: var(--ambre-sombre); }
.cr-total.juste { border-top-color: var(--vert); background: var(--vert-pale); }
.cr-total.juste .cr-etat { color: var(--vert); }
.cr-total.long  { border-top-color: var(--rouge); background: var(--rouge-pale); }
.cr-total.long  .cr-etat { color: var(--rouge); }

.cr-rendu {
  margin-top: 1.3rem; padding: 1rem 1.1rem; border-radius: var(--r);
  background: var(--accent-pale); border-left: 3px solid var(--accent);
}
.cr-rappel { margin: 0 0 .7rem; font-size: .8485rem; color: var(--encre); line-height: 1.55; }
.cr-ligne { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem; }
.cr-ligne code {
  font-family: var(--mono); font-size: 1.03rem; font-weight: 700;
  padding: .45rem .8rem; border-radius: var(--r);
  background: var(--carte); color: var(--accent-sombre);
  border: 1px solid var(--bord-fort);
}
#cr-copier {
  min-height: 40px; padding: .45rem .9rem; cursor: pointer; flex: none;
  font: inherit; font-size: .8182rem; font-weight: 650;
  background: var(--accent); color: var(--sur-accent);
  border: 1px solid var(--accent); border-radius: var(--r);
  transition: opacity .14s;
}
#cr-copier:hover { opacity: .88; }
#cr-copier.fait { background: var(--vert); border-color: var(--vert); color: #FFFFFF; }

@media (max-width: 560px) {
  .mbl > span:first-child { width: 4.2rem; }
  .res { grid-template-columns: 1fr; }
}
/* À l'impression, une barre collante se répète en haut de chaque page. */
@media print {
  .pt-barre, .pt-chips, .cr-rendu button { display: none !important; }
  .pt-bloc, .cr-bloc, .res .r { break-inside: avoid; }
}

/* Ce qui a été retiré d'une valeur saisie, dit sous le champ : un caractère
   effacé en silence ferait coller un mot de passe différent de celui qu'on
   lit à l'écran. */
.pt-avis {
  display: block; margin-top: .3rem; font-size: .7273rem; font-weight: 600;
  letter-spacing: 0; text-transform: none; color: var(--ambre-sombre);
}
.pt-avis[hidden] { display: none; }

/* L'icône de la matière devant son titre de section, comme sur l'accueil :
   c'est le même repère visuel, donc la même lecture. */
.cat-ic {
  display: inline-grid; place-items: center; width: 26px; height: 26px;
  margin-right: .5rem; vertical-align: -6px; border-radius: 8px;
  background: var(--accent-pale); color: var(--accent-sombre); font-size: .8182rem;
}

/* ═══════════════════════════════════════════════════════════════════════
   DEVOIRS — ce qui tombe, quand, et quoi relire

   La couleur vient de la matière du devoir, pas d'un code de gravité : on
   reconnaît « maths » ou « dev » d'un coup d'œil, comme partout ailleurs.
   Seule l'imminence ajoute un signal, et elle est calculée dans le
   navigateur — une échéance écrite en dur vieillit mal.
   ═══════════════════════════════════════════════════════════════════════ */
.dev-liste { display: grid; gap: 1.1rem; margin-top: 2rem; }
.devoir {
  position: relative; padding: 1.3rem 1.5rem 1.4rem;
  background: var(--carte); border: 1px solid var(--bord);
  border-left: 4px solid var(--accent); border-radius: var(--r-l);
  box-shadow: var(--ombre);
}
.devoir.imminent { border-color: var(--accent); box-shadow: var(--ombre-haut); }
.devoir.passe { opacity: .5; border-left-color: var(--bord-fort); }

.dev-tete {
  display: flex; flex-wrap: wrap; align-items: center; gap: .45rem .8rem;
  margin-bottom: .55rem;
}
.dev-pole {
  padding: .16rem .6rem; border-radius: 999px;
  background: var(--accent-pale); color: var(--accent-sombre);
  font-size: .6667rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
}
.dev-date { font-size: .8182rem; font-weight: 650; color: var(--encre-douce); }
.dev-compte {
  font-family: var(--mono); font-size: .7576rem; font-weight: 700;
  color: var(--accent-sombre); padding: .12rem .5rem; border-radius: 999px;
  background: var(--accent-pale);
}
.devoir.imminent .dev-compte { background: var(--rouge-pale); color: var(--rouge); }
.devoir.passe .dev-compte { background: var(--carte-creuse); color: var(--encre-douce); }
.dev-bareme {
  margin-left: auto; font-size: .7576rem; font-weight: 700;
  color: var(--encre-douce); white-space: nowrap;
}
.devoir h2 {
  margin: 0 0 .4rem; font-size: 1.15rem; font-weight: 740;
  letter-spacing: -.014em; color: var(--encre);
}
.dev-quoi { margin: 0; font-size: .9091rem; line-height: 1.6; color: var(--encre-douce); }
.dev-confirmer {
  margin: .8rem 0 0; padding: .55rem .8rem; border-radius: var(--r);
  background: var(--ambre-pale); border-left: 3px solid var(--ambre);
  font-size: .8485rem; color: var(--ambre-sombre); font-weight: 600;
}
.dev-attendu { margin-top: 1.1rem; }
.dev-attendu h3, .dev-reviser h3 {
  margin: 0 0 .5rem; font-size: .6667rem; font-weight: 700;
  letter-spacing: .09em; text-transform: uppercase; color: var(--encre-douce);
}
.dev-attendu ol { margin: 0; padding-left: 1.3rem; }
.dev-attendu li { margin-bottom: .35rem; font-size: .8788rem; line-height: 1.55; color: var(--encre); }
.dev-attendu li b { color: var(--accent-sombre); }

.dev-reviser { margin-top: 1.1rem; display: grid; gap: .4rem; }
.dev-reviser a {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: .1rem .6rem;
  padding: .55rem .8rem; border-radius: var(--r); text-decoration: none;
  background: var(--carte-creuse); border: 1px solid var(--bord);
  border-left: 3px solid var(--accent); min-height: 40px;
  transition: border-color .14s, transform .1s var(--ease);
}
.dev-reviser a:hover { border-color: var(--accent); transform: translateX(2px); }
.dev-reviser a b { font-size: .8788rem; font-weight: 700; color: var(--encre); }
.dev-reviser a span { font-size: .7879rem; color: var(--encre-douce); }
.dev-conseil {
  margin: 1.1rem 0 0; padding: .7rem .9rem; border-radius: var(--r);
  background: var(--accent-pale); border-left: 3px solid var(--accent);
  font-size: .8485rem; line-height: 1.6; color: var(--encre);
}

/* ══════════════════════════════════════════════════════════ le planning */
/* Le bandeau du prochain cours. Il n'apparaît que si le JavaScript a trouvé
   quelque chose à y mettre : écrit vide, il laisserait un trait sans objet. */
.plan-prochain {
  margin: 1.4rem 0 0; padding: .7rem 1rem; border-radius: var(--r);
  background: var(--accent-pale); border-left: 3px solid var(--accent);
  font-size: .8788rem; font-weight: 600; color: var(--encre); line-height: 1.5;
}
.plan-barre {
  display: flex; align-items: center; justify-content: space-between;
  gap: .8rem; margin: 1.6rem 0 1rem; padding: .35rem;
  background: var(--carte-creuse); border: 1px solid var(--bord);
  border-radius: var(--r);
}
.plan-barre strong {
  flex: 1; text-align: center; font-size: .8485rem; font-weight: 700;
  color: var(--encre);
}
.plan-barre button {
  min-width: 40px; min-height: 40px; padding: 0 .7rem;
  font-size: 1rem; font-family: inherit; cursor: pointer;
  color: var(--encre); background: var(--carte);
  border: 1px solid var(--bord); border-radius: var(--r);
  transition: border-color .14s, background .14s;
}
.plan-barre button:hover:not(:disabled) { border-color: var(--accent); }
/* Un bouton désactivé reste lisible : on éteint le geste, pas le texte. */
.plan-barre button:disabled { opacity: .45; cursor: default; }

.plan-jour { margin-bottom: 1.4rem; }
.plan-jour h3 {
  margin: 0 0 .6rem; font-size: .7273rem; font-weight: 700;
  letter-spacing: .07em; text-transform: uppercase; color: var(--encre-douce);
}
.plan-jour ol { margin: 0; padding: 0; list-style: none; display: grid; gap: .5rem; }
.plan-creneau {
  display: grid; grid-template-columns: 5.4rem 1fr; gap: .2rem .9rem;
  align-items: baseline; padding: .7rem .9rem; border-radius: var(--r);
  background: var(--carte); border: 1px solid var(--bord);
  border-left: 3px solid var(--bord-fort);
}
.plan-creneau.prochain { border-left-color: var(--accent); }
.plan-creneau.encours {
  border-color: var(--accent); border-left-color: var(--accent);
  background: var(--accent-pale); box-shadow: var(--ombre);
}
/* L'heure : le début porte l'information, la fin la complète. Les deux dans
   la même colonne, l'une sous l'autre, pour que les lignes s'alignent. */
.plan-h { grid-row: span 2; font-family: var(--mono); line-height: 1.35; }
.plan-h b { display: block; font-size: .9091rem; font-weight: 700; color: var(--encre); }
.plan-h i { display: block; font-style: normal; font-size: .7576rem; color: var(--encre-douce); }
/* Empilées sans marque, « 09:30 » et « 12:30 » se lisent comme deux débuts.
   Le tiret dit que la seconde est une borne de fin. Et c'est un tiret, pas
   une flèche : une flèche lie une grandeur à sa valeur, jamais deux bornes
   d'un même intervalle. */
.plan-h i::before { content: "\2013\00a0"; }
.plan-cours { font-size: .8788rem; font-weight: 600; color: var(--encre); line-height: 1.45; }
.plan-salle { font-size: .7879rem; color: var(--encre-douce); line-height: 1.45; }

.plan-abo {
  margin-top: 2.4rem; padding: 1.1rem 1.2rem; border-radius: var(--r-l);
  background: var(--carte-creuse); border: 1px solid var(--bord);
}
.plan-abo h2 { margin: 0 0 .5rem; font-size: 1rem; color: var(--encre); }
.plan-abo p { margin: 0 0 .8rem; font-size: .8485rem; line-height: 1.65; color: var(--encre); }
.plan-url { display: flex; flex-wrap: wrap; gap: .5rem; align-items: stretch; }
.plan-url code {
  flex: 1 1 14rem; min-width: 0; padding: .6rem .7rem;
  font-family: var(--mono); font-size: .7576rem; color: var(--encre);
  background: var(--papier); border: 1px solid var(--bord);
  border-radius: var(--r);
  /* Une URL ne contient pas d'espace : sans cela elle élargit la page. */
  overflow-wrap: anywhere; word-break: break-all; line-height: 1.5;
}
.plan-url button {
  min-height: 40px; padding: 0 1rem; cursor: pointer;
  font-family: inherit; font-size: .7879rem; font-weight: 700;
  color: var(--sur-accent); background: var(--accent);
  border: 1px solid var(--accent); border-radius: var(--r);
}
.plan-url button:hover { background: var(--accent-sombre); border-color: var(--accent-sombre); }
.plan-note { margin: .8rem 0 0 !important; font-size: .7879rem; color: var(--encre-douce); }

/* ── La même semaine, lue à trois tailles ────────────────────────────── */
/* Téléphone : l'heure se resserre, le reste prend la place. */
@media (max-width: 30rem) {
  .plan-creneau { grid-template-columns: 4.4rem 1fr; padding: .6rem .7rem; }
  .plan-jour h3 { font-size: .6970rem; }
  .plan-barre strong { font-size: .7879rem; }
  .plan-abo { padding: .9rem .8rem; }
}
/* À partir de 60 rem, les jours se rangent côte à côte, comme sur l'écran
   du hall : une semaine se lit d'un coup d'œil au lieu de se dérouler.
   « auto-fit » suit le nombre réel de jours — deux jours donnent deux
   colonnes, pas deux colonnes et un trou.
   Le « :not([hidden]) » n'est pas un ornement : « display: grid » l'emporte
   sur le « display: none » de l'attribut hidden, et les huit semaines
   s'afficheraient toutes à la fois. */
@media (min-width: 60rem) {
  .plan-semaine:not([hidden]) {
    display: grid; align-items: start; gap: 0 1.6rem;
    grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr));
  }
  .plan-jour { margin-bottom: .6rem; }
  /* Une colonne par jour : la ligne devient large, l'intitulé et la salle
     peuvent se ranger l'un à côté de l'autre plutôt que l'un sous l'autre. */
  .plan-creneau { grid-template-columns: 5.4rem 1fr; padding: .8rem 1rem; }
}

/* ════════════════════════════════ le bandeau du planning, sur l'accueil */
/* Trois boîtes identiques ne disent pas quoi regarder. Ici UN cours domine —
   celui qui vient, ou celui qui se déroule — et le reste de la journée tient
   sur une ligne. Le bandeau prend la couleur de la matière du cours en
   vedette : « data-matiere » redéfinit --accent sur n'importe quel élément,
   et les quarante thèmes le suivent sans une couleur écrite en dur. */
.bandeau-plan {
  position: relative; overflow: hidden;
  padding: .85rem 1.1rem .95rem 1.35rem; border-radius: var(--r-l);
  background: var(--carte); border: 1px solid var(--bord);
  box-shadow: var(--ombre);
}
/* Le liseré de matière, posé en ::before pour qu'il épouse les coins. */
.bandeau-plan::before {
  content: ""; position: absolute; inset: 0 auto 0 0; width: 4px;
  background: var(--accent);
}

.bp-tete {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: .35rem .7rem;
  margin-bottom: .6rem;
}
.bp-jour {
  font-size: .7273rem; font-weight: 700; letter-spacing: .09em;
  text-transform: uppercase; color: var(--accent-sombre);
}
.bp-delai {
  padding: .1rem .45rem; border-radius: 999px;
  background: var(--carte-creuse); color: var(--encre-douce);
  font-size: .6970rem; font-weight: 600; white-space: nowrap;
}
/* Imminent ou en cours : le délai cesse d'être une mention et devient l'info. */
.bp-delai.vif { background: var(--accent-pale); color: var(--accent-sombre); }
.bp-tout {
  margin-left: auto; font-size: .7576rem; font-weight: 600;
  color: var(--encre-douce); text-decoration: none; white-space: nowrap;
}
.bp-tout::after { content: " \2192"; }
.bp-tout:hover { color: var(--accent-sombre); }

/* ── Le cours qui domine ─────────────────────────────────────────────── */
.bp-vedette {
  display: grid; grid-template-columns: auto 1fr; gap: 0 1rem;
  align-items: center;
}
.bp-h { line-height: 1.1; text-align: right; font-variant-numeric: tabular-nums; }
.bp-h b {
  display: block; font-size: 1.4545rem; font-weight: 700; color: var(--encre);
  letter-spacing: -.01em;
}
.bp-h i {
  display: block; margin-top: .1rem; font-style: normal;
  font-size: .7273rem; color: var(--encre-douce);
}
.bp-txt { min-width: 0; }
.bp-titre {
  display: block; font-size: 1.0303rem; font-weight: 700; line-height: 1.3;
  color: var(--encre);
}
.bp-lieu {
  display: block; margin-top: .15rem; font-size: .7879rem; color: var(--encre-douce);
}
/* La jauge n'apparaît que pendant le cours : elle dit d'un coup d'œil s'il
   reste dix minutes ou deux heures. */
.bp-jauge {
  grid-column: 1 / -1; margin-top: .7rem; height: 3px; border-radius: 999px;
  background: var(--carte-creuse); overflow: hidden;
}
.bp-jauge i { display: block; height: 100%; background: var(--accent); }

/* ── Le reste de la journée ──────────────────────────────────────────── */
/* Chaque cours porte son horaire complet et sa salle : c'est ce qu'on vient
   chercher un matin, et l'abréger obligeait à ouvrir le planning pour rien.
   Une ligne par cours, pas des pastilles en enfilade : trois informations
   ne tiennent pas côte à côte sans qu'on ait à les démêler. */
.bp-suite {
  display: grid; gap: .1rem;
  margin: .85rem 0 0; padding: .7rem 0 0; list-style: none;
  border-top: 1px solid var(--bord);
}
.bp-suite li {
  display: grid; grid-template-columns: auto 1fr auto; gap: .1rem .55rem;
  align-items: baseline; padding: .32rem .3rem; border-radius: var(--r);
  font-size: .7879rem; color: var(--encre-douce);
}
.bp-suite li:hover { background: var(--carte-creuse); }
/* La pastille porte la matière du cours : on repère « maths » sans lire. */
.bp-suite li b {
  position: relative; padding-left: .85rem; font-weight: 700;
  color: var(--encre); font-variant-numeric: tabular-nums; white-space: nowrap;
}
.bp-suite li b::before {
  content: ""; position: absolute; left: 0; top: .42em;
  width: 7px; height: 7px; border-radius: 50%; background: var(--accent);
}
.bp-suite li span { color: var(--encre); font-weight: 600; min-width: 0; }
/* L'horaire complet en bout de ligne, aligné à droite : on lit la colonne
   des débuts d'un trait, et la durée reste disponible sans la chercher. */
.bp-suite li u {
  grid-column: 3; text-decoration: none; font-size: .7273rem;
  color: var(--encre-douce); font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.bp-suite li i {
  grid-column: 2 / -1; font-style: normal; font-size: .7273rem;
  color: var(--encre-douce);
}
.bp-suite li.passe { opacity: .45; }

/* Téléphone : la vedette garde sa hiérarchie, l'heure passe au-dessus pour
   laisser l'intitulé occuper toute la largeur au lieu de se couper en trois. */
@media (max-width: 26rem) {
  .bandeau-plan { padding: .8rem .85rem .85rem 1.1rem; }
  .bp-vedette { grid-template-columns: 1fr; gap: .25rem; }
  .bp-h { display: flex; align-items: baseline; gap: .4rem; text-align: left; }
  .bp-h b { font-size: 1.2727rem; }
  .bp-h i { margin-top: 0; }
  .bp-suite li { grid-template-columns: auto 1fr; }
  .bp-suite li u { grid-column: 2; justify-self: start; }
  .bp-suite li i { grid-column: 1 / -1; padding-left: .85rem; }
}

/* Le bandeau se pose juste sous la barre du haut, avant le titre : c'est la
   première question qu'on se pose en ouvrant le site un matin de cours, et
   elle ne mérite pas qu'on fasse défiler. Il n'est pas dans « .contenu », il
   reprend donc lui-même sa largeur et ses marges. */
.bandeau-hote {
  max-width: var(--large-app, 1120px); margin: 0 auto;
  padding: 1.1rem clamp(1rem, 4vw, 2.4rem) 0;
}
.bandeau-hote:empty { display: none; }
.bandeau-hote .bandeau-plan { margin-bottom: 0; }

/* ── Trois cibles tactiles remises au-dessus du seuil ────────────────── */
/* Le banc du site refuse toute cible sous 34 px. Ces trois-là y passaient
   encore, et la première pour une raison instructive : la règle qui remonte
   le badge à 34 px vivait dans le bloc « max-width: 420px », mais le bloc
   « max-width: 480px » — plus bas dans le fichier, donc prioritaire à
   égalité de spécificité — le ramenait à 27. Deux media queries qui se
   recouvrent se départagent par l'ORDRE, pas par la largeur. D'où cette
   reprise, placée après toutes les autres. */
@media (max-width: 480px) {
  .app-marque .sigle { width: 34px; height: 34px; }
}
/* « Tout le planning » : un lien qu'on vise au pouce, pas une note de bas de
   page. Il garde sa ligne de texte et gagne sa hauteur en rembourrage. */
.bp-tout {
  display: inline-flex; align-items: center; min-height: 34px;
  padding: 0 .1rem;
}
/* Le téléchargement de l'agenda devient un bouton discret : c'est une action,
   et une action se vise. */
.plan-note a {
  display: inline-flex; align-items: center; min-height: 34px;
  padding: 0 .7rem; border-radius: var(--r); text-decoration: none;
  border: 1px solid var(--bord); background: var(--carte);
  font-weight: 600; color: var(--encre);
}
.plan-note a:hover { border-color: var(--accent); color: var(--accent-sombre); }

/* ── La grille des matières, et ce qui ne peut pas se couper ─────────── */
/* « minmax(270px, 1fr) » impose 270 px de large au minimum : dès que la
   colonne disponible descend en dessous, la carte dépasse au lieu de
   rétrécir. Le « min(270px, 100%) » lui rend le droit de se réduire.
   Et un intitulé long rendu à chasse fixe — « Probabilités conditionnelles
   — exercices » sur le thème Voxel — ne se coupe pas tout seul : il poussait
   la page de 8 px à 375. Défaut invisible pour le banc, qui n'a pas
   d'historique et n'affichait donc jamais la carte « Vu récemment ». */
.grille-matieres { grid-template-columns: repeat(auto-fit, minmax(min(270px, 100%), 1fr)); }
.grille-matieres > * { min-width: 0; }
.recents li a, .carte-matiere.reprise b, .carte-matiere.reprise span {
  overflow-wrap: anywhere;
}

/* ═══════════════════════════════════════════════════════════════════════
   L'ATELIER C / C++

   Une contrainte a dicté presque tout le reste : dans cette feuille, « pre »
   n'a que DEUX fonds — #23211E à l'écran, #F4F1EC à l'impression — et aucun
   des quarante thèmes ne les redéfinit. Les dix teintes de code (.j-*) ont
   été mesurées contre ces deux fonds-là et passent toutes AA.

   L'éditeur et la console se posent donc sur CETTE surface, et pas sur une
   surface neuve : le code qu'on y écrit prend exactement les couleurs qu'il
   a dans les fiches, sur les quarante thèmes, sans une mesure de plus. Tout
   ce qui entoure — barre, cartes de diagnostic, tiroir — vit au contraire
   dans les variables du thème et se repeint avec lui.

   Aucune couleur n'est écrite en dur hors de cette surface héritée.
   ═══════════════════════════════════════════════════════════════════════ */
#atelier {
  /* Le panneau des commandes se place « absolute » par rapport à l'atelier :
     sans ancêtre positionné, il remonterait jusqu'à la page et irait se
     coller dans un coin, très loin de la barre qui l'a ouvert. C'est la même
     raison que pour le tiroir des exemples, plus bas. */
  position: relative;
  padding-bottom: 1.3rem;

  /* La hauteur des deux cadres se compte EN LIGNES, pas en pourcentage
     d'écran. Signalé : seulement seize lignes affichées, là où l'on
     pourrait en montrer une trentaine. Une hauteur en « vh » donne un
     nombre de lignes
     différent sur chaque machine — 16 chez lui, 23 ici — et personne ne peut
     dire combien on en verra. Ici le calcul part de l'interligne réel, donc
     30 lignes sont 30 lignes partout. Et comme tout est en rem, le réglage
     de taille du lecteur les conserve : agrandir le texte n'enlève pas de
     lignes, ça agrandit le cadre.

     Le « min(…, 86vh) » empêche le cadre de dépasser un écran court, et le
     « max(22rem, …) » l'empêche de devenir inutilisable sur un écran très
     court. Les 3,85rem couvrent l'onglet du haut, le rembourrage ET les deux
     bordures d'un pixel : mesuré, parce que 3,6rem donnait 29 lignes — à deux
     pixels près, et deux pixels coûtent une ligne entière. */
  --edi-police: .8061rem;
  --edi-inter: 1.66;
  --edi-lignes: 30;
  --h-volet: calc(var(--edi-lignes) * var(--edi-police) * var(--edi-inter) + 3.85rem);
}
/* « hidden » perd contre une règle de display, et toutes celles d'ici en
   posent une. Sans ce rappel, « Arrêter » s'affiche en permanence — ce qui
   invite à cliquer sur une commande sans objet. */
#atelier [hidden] { display: none !important; }

/* ── la barre de commandes ───────────────────────────────────────────
   Quatre groupes, pas davantage (Miller) : lancer · langage · réglage ·
   ressources. L'état est à droite, seul, pour qu'on sache toujours où le
   chercher sans le confondre avec une commande. */
.at-barre {
  display: flex; flex-wrap: wrap; align-items: center; gap: .5rem;
  margin-bottom: 1rem;
}
.at-barre button { font: inherit; cursor: pointer; }

.at-lancer {
  display: inline-flex; align-items: center; gap: .5rem;
  min-height: 42px; padding: 0 1.1rem;
  background: var(--accent); color: var(--sur-accent);
  border: 1px solid var(--accent); border-radius: 7px;
  font-size: .9394rem; font-weight: 700;
  transition: background .14s, transform .08s;
}
.at-lancer:hover:not(:disabled) { background: var(--accent-sombre); border-color: var(--accent-sombre); }
.at-lancer:active:not(:disabled) { transform: translateY(1px); }
.at-lancer:disabled { opacity: .55; cursor: default; }
.at-lancer .at-triangle { font-size: .82em; }
.at-lancer kbd {
  font-family: var(--mono); font-size: .72em; opacity: .78;
  border: 1px solid currentColor; border-radius: 4px; padding: .05em .35em;
  background: none; color: inherit;
}
.at-stop {
  display: inline-flex; align-items: center; gap: .45rem;
  min-height: 42px; padding: 0 .9rem; border-radius: 7px;
  background: var(--rouge-pale); color: var(--rouge);
  border: 1px solid var(--rouge-bord); font-weight: 650; font-size: .8788rem;
}
.at-stop:hover { border-color: var(--rouge); }

/* Segments : un seul état allumé, et c'est le couple accent / sur-accent —
   le seul dont le contraste est garanti sur les quarante thèmes. */
.at-segments {
  display: inline-flex; border: 1px solid var(--bord-fort);
  border-radius: 7px; overflow: hidden; background: var(--carte-creuse);
}
.at-segments button {
  min-height: 42px; padding: 0 .95rem; border: 0; background: none;
  color: var(--encre-douce); font-weight: 650; font-size: .8788rem;
  font-family: var(--mono); letter-spacing: -.01em;
}
.at-segments button + button { border-left: 1px solid var(--bord-fort); }
.at-segments button:hover { color: var(--encre); background: var(--carte); }
.at-segments button[aria-pressed="true"] { background: var(--accent); color: var(--sur-accent); }

.at-bascule, .at-creux {
  display: inline-flex; align-items: center; gap: .45rem;
  min-height: 42px; padding: 0 .85rem; border-radius: 7px;
  background: var(--carte-creuse); color: var(--encre-douce);
  border: 1px solid var(--bord-fort); font-weight: 600; font-size: .8485rem;
}
.at-bascule:hover, .at-creux:hover { border-color: var(--accent); color: var(--encre); }
.at-coche {
  width: 15px; height: 15px; border-radius: 4px; flex: none;
  border: 1.5px solid var(--bord-fort); background: var(--carte);
  position: relative;
}
.at-bascule[aria-pressed="true"] { color: var(--encre); border-color: var(--accent); }
.at-bascule[aria-pressed="true"] .at-coche { background: var(--accent); border-color: var(--accent); }
.at-bascule[aria-pressed="true"] .at-coche::after {
  content: ""; position: absolute; left: 4px; top: 1px; width: 4px; height: 8px;
  border: solid var(--sur-accent); border-width: 0 2px 2px 0; transform: rotate(42deg);
}

/* L'état et sa jauge. Loi de Doherty : passé 400 ms sans signe de vie, on
   croit que c'est cassé. Le téléchargement du compilateur dure bien plus,
   donc il se montre — en mégaoctets, pas en pourcentage abstrait. */
.at-jauge-boite { margin-left: auto; min-width: 0; text-align: right; }
.at-etat {
  margin: 0; font-size: .7879rem; font-weight: 600; color: var(--encre-douce);
  line-height: 1.35; overflow-wrap: anywhere;
}
.at-etat.e-ok { color: var(--vert); }
.at-etat.e-avert { color: var(--ambre-sombre); }
.at-etat.e-erreur { color: var(--rouge); }
.at-jauge {
  margin-top: .3rem; height: 5px; width: min(220px, 40vw); margin-left: auto;
  border-radius: 999px; background: var(--carte-creuse);
  border: 1px solid var(--bord); overflow: hidden;
}
.at-jauge::before {
  content: ""; display: block; height: 100%; width: var(--part, 0%);
  background: var(--accent); transition: width .2s linear;
}

/* ── le tiroir des exemples ──────────────────────────────────────────── */
.at-tiroir {
  /* « position: relative » n'est pas décoratif : c'est lui qui donne au
     panneau de dossier un repère. Sans ancêtre positionné, une boîte en
     « position: absolute » remonte jusqu'à la page et va se coller dans un
     coin de l'écran, très loin du dossier qu'on vient d'ouvrir. */
  position: relative;
  margin: 0 0 1rem; padding: 1rem 1.1rem 1.1rem;
  background: var(--carte-creuse); border: 1px solid var(--bord);
  border-radius: var(--r);
}
.at-tiroir-tete { display: flex; align-items: center; justify-content: space-between; gap: .6rem; }
.at-tiroir-tete h3 { margin: 0; font-size: .97rem; font-weight: 700; color: var(--encre); }
.at-tiroir-tete button {
  min-width: 34px; min-height: 34px; border-radius: 7px; cursor: pointer;
  background: var(--carte); border: 1px solid var(--bord-fort); color: var(--encre-douce);
  font: inherit;
}
.at-tiroir-tete button:hover { border-color: var(--accent); color: var(--encre); }
.at-liste-ex { margin-top: .8rem; display: grid; gap: 1rem; }
.at-ex-groupe h4 {
  margin: 0 0 .45rem; font-size: .697rem; font-weight: 700; letter-spacing: .09em;
  text-transform: uppercase; color: var(--encre-tenue);
}
.at-ex-groupe { display: grid; gap: .4rem;
  grid-template-columns: repeat(auto-fit, minmax(min(250px, 100%), 1fr)); }
.at-ex-groupe h4 { grid-column: 1 / -1; }
.at-ex {
  display: flex; flex-direction: column; gap: .15rem; text-align: left;
  min-height: 44px; padding: .55rem .75rem; border-radius: var(--r);
  background: var(--carte); border: 1px solid var(--bord); color: var(--encre);
  font: inherit; min-width: 0;
}
.at-ex:hover { border-color: var(--accent); }
.at-ex b { font-size: .8485rem; font-weight: 650; overflow-wrap: anywhere; }
.at-ex span { font-size: .7576rem; color: var(--encre-douce); line-height: 1.45; overflow-wrap: anywhere; }
.at-vide { margin: 0; font-size: .8182rem; color: var(--encre-tenue); }

/* ── les deux volets ─────────────────────────────────────────────────
   « auto-fit » avec un minimum en « min(…, 100%) » : sous 340 px la colonne
   a le droit de rétrécir au lieu de pousser la page hors de l'écran. C'est
   la correction déjà faite sur la grille des matières, pour la même raison. */
.at-grille {
  display: grid; gap: .9rem;
  grid-template-columns: repeat(auto-fit, minmax(min(340px, 100%), 1fr));
}
/* ── Le thème de l'atelier pilote TOUT le chrome, pas seulement le code ──
   Il ne pilotait que deux éléments — le <pre> peint et le flux de la
   console. Le volet, la barre d'onglet, la marge, les numéros de ligne,
   le curseur, la sélection et les teintes de la console restaient câblés
   sur « nuit ». Sur les trois autres thèmes sombres la couture se voyait ;
   sur « papier » le thème devenait inutilisable : encre 1,09 · numéros
   2,91 · onglet 1,71 · notes 2,32 — mesuré, pas estimé.

   Une variable par rôle, redéclarée par thème : une pièce de chrome
   ajoutée plus tard lit la variable et suit les cinq thèmes sans qu'on
   ait à y penser. Les valeurs par défaut sont celles de « nuit », donc
   ce thème ne bouge pas d'un pixel. */
#atelier {
  --edi-fond:   #23211E;
  --edi-encre:  #EDE7DC;
  --edi-barre:  rgba(255,255,255,.055);
  --edi-trait:  rgba(255,255,255,.09);
  --edi-filet:  rgba(255,255,255,.07);
  --edi-voile:  rgba(0,0,0,.18);
  --edi-num:    #938E86;
  --edi-onglet: #B8B0A2;
  --edi-note:   #A79F92;
  --edi-douce:  #D8D1C4;
  --edi-ambre:  #F7C46B;
  --edi-vert:   #9CD67F;
  --edi-rouge:  #FF9E93;
  --edi-bleu:   #82AAFF;
  --edi-caret:  #FFD79A;
  --edi-select: rgba(130,170,255,.32);
  --edi-champ:  #1D1B19;
  --edi-plein-encre: #23211E;   /* encre sur un bouton plein ambre */
}
/* Les trois autres thèmes sombres ne changent que le fond : les teintes
   ci-dessus ont été mesurées sur #23211E, le plus clair des quatre, et
   elles ne font que gagner sur un fond plus sombre (pire cas : ardoise,
   numéros de ligne 5,14). */
#atelier[data-edi-theme="ardoise"]   { --edi-fond: #1E2430; }
#atelier[data-edi-theme="encre"]     { --edi-fond: #14161A; }
#atelier[data-edi-theme="contraste"] { --edi-fond: #000000; --edi-encre: #FFFFFF; }

/* « papier » inverse tout : chaque teinte est reprise de la palette
   d'impression, déjà mesurée, et revérifiée contre SON fond réel — la
   marge et la barre portent un voile noir, pas blanc.
     fond #F4F1EC · marge #E8E5E0 · barre #E7E4DF
     encre 14,25 · numéros 5,44 · onglet 6,29 · notes 6,56 · boutons 7,40
     ambre 6,04 · vert 5,75 · rouge 6,69 · bleu 6,81 · curseur 4,82 */
#atelier[data-edi-theme="papier"] {
  --edi-fond:   #F4F1EC;
  --edi-encre:  #23211E;
  --edi-barre:  rgba(0,0,0,.055);
  --edi-trait:  rgba(0,0,0,.12);
  --edi-filet:  rgba(0,0,0,.10);
  --edi-voile:  rgba(0,0,0,.05);
  --edi-num:    #5F5A52;
  --edi-onglet: #55504A;
  --edi-note:   #5A554D;
  --edi-douce:  #4A463F;
  --edi-ambre:  #8A4B00;
  --edi-vert:   #2F6B1E;
  --edi-rouge:  #A32020;
  --edi-bleu:   #1D4FA8;
  --edi-caret:  #9A5B00;
  --edi-select: rgba(76,125,240,.32);
  --edi-champ:  #FFFFFF;
  --edi-plein-encre: #2A1800;
}

.at-volet {
  display: flex; flex-direction: column; min-width: 0;
  border: 1px solid var(--bord-fort); border-radius: var(--r); overflow: hidden;
  background: var(--edi-fond);
  /* « resize » du navigateur plutôt qu'une poignée en JavaScript : c'est la
     même que celle d'un textarea, elle existe déjà dans la tête de tout le
     monde, elle marche au clavier des lecteurs d'écran, et elle ne coûte pas
     une ligne. Elle exige seulement « overflow » différent de visible. */
  resize: vertical;
}
.at-volet-code   { height: max(22rem, min(var(--h-volet), 86vh)); min-height: 220px; }
/* ── La console a sa hauteur, pas celle de l'éditeur ─────────────────────
   « ça fait beaucoup quand la page de gauche est longue, la console l'est
   aussi ; mettre une taille définie en fonction de la taille de la page et
   mettre un truc pour scroller. »

   Elle recevait « --h-volet », c'est-à-dire la hauteur de l'ÉDITEUR, elle-même
   calculée pour trente lignes de code. Un programme de trente lignes qui
   affiche « Bonjour » donnait donc trente lignes de noir pour une ligne de
   texte. Les deux cadres n'ont pourtant pas le même métier : l'un est l'endroit
   où l'on travaille, l'autre rend compte. VS Code ne fait pas autrement — un
   grand éditeur, un terminal bas.

   La console se mesure donc sur la PAGE : jamais moins de onze rem, jamais plus
   de vingt-six, et 38 % de la fenêtre entre les deux. Elle défilait déjà
   (« .con-flux » est en overflow:auto) ; ce qui manquait, c'est qu'elle cesse
   de s'étirer. */
/* Deux réglages successifs, et les deux étaient de lui : « la console est
   hyper grosse », puis « allonge un peu la console là maintenant c'est trop
   petit ». 38 vh plafonnés à 26 rem étaient trop courts dès que la barre de
   saisie apparaît — elle mange 140 px, et il ne restait que 200 px de sortie.
   52 vh plafonnés à 34 rem, et un plancher de 9 rem pour le flux lui-même :
   la zone de saisie ne peut plus l'écraser. */
.at-volet-sortie { height: clamp(14rem, 52vh, 34rem); min-height: 200px; }
/* Sans cela, la grille étire le plus court sur la hauteur du plus long et le
   réglage ci-dessus ne servirait à rien. En plein écran, au contraire, on veut
   que les deux remplissent — c'est tout l'objet du plein écran. */
.at-grille { align-items: start; }
.at-volet::-webkit-resizer { background: none; }
.at-poignee-note {
  margin: .45rem 0 0; font-size: .7273rem; color: var(--encre-tenue); text-align: right;
}
.at-volet-tete {
  display: flex; align-items: center; gap: .5rem; padding: .4rem .7rem;
  background: var(--edi-barre); border-bottom: 1px solid var(--edi-trait);
}
/* Les teintes posées sur ce fond sombre, mesurées contre #23211E — et
   contre #1D1B19 pour la marge, qui porte un voile noir de 18 %.
   Aucune ne descend sous 4,5:1 :
     #EDE7DC 13,05  texte de l'éditeur et sortie du programme
     #D8D1C4 10,58  bouton « Fin de saisie »
     #F7C46B  9,99  stderr, gardes, « attend une saisie »
     #9CD67F  9,44  ce que l'étudiant a tapé
     #FF9E93  8,08  arrêt et marge d'erreur
     #B8B0A2  7,47  libellé d'onglet
     #82AAFF  6,99  note d'information
     #A79F92  6,13  notes de la console
     #938E86  5,28  numéros de ligne (sur la marge)
   Elles s'ajoutent aux dix teintes de code (.j-*), déjà mesurées contre le
   même fond : c'est tout l'intérêt de poser l'atelier sur la surface des
   blocs de code plutôt que d'en inventer une. */
.at-onglet {
  font-family: var(--mono); font-size: .7273rem; font-weight: 600;
  color: var(--edi-onglet); letter-spacing: -.01em;
}

/* ── l'éditeur ───────────────────────────────────────────────────────
   Un textarea transparent posé sur un <pre> peint. Les deux doivent avoir
   EXACTEMENT la même police, la même taille, le même interligne et le même
   rembourrage : un dixième de pixel d'écart et le curseur dérive en bout de
   ligne. D'où les valeurs partagées par une variable. */
.edi {
  --edi-pad: .8rem;   /* les deux autres mesures sont posées sur #atelier */
  display: grid; grid-template-columns: auto 1fr;
  flex: 1; min-height: 0;
}
.edi-marge {
  overflow: hidden; padding: var(--edi-pad) 0;
  background: var(--edi-voile); border-right: 1px solid var(--edi-filet);
  text-align: right; user-select: none;
}
.edi-num {
  display: block; width: 100%; box-sizing: border-box; border: 0; background: none;
  padding: 0 .55rem 0 .7rem; cursor: default;
  font-family: var(--mono); font-size: var(--edi-police); line-height: var(--edi-inter);
  /* Mesuré, pas choisi. #6F6A62 — la première valeur essayée — tombait à
     3,20:1 sur le fond de la marge : sous le seuil AA, sur un texte qu'on
     lit pour se rendre à une ligne d'erreur. #938E86 tient 5,28:1 sur la
     marge et 4,94:1 sur le volet. */
  color: var(--edi-num); text-align: right;
}
.edi-num.a-erreur, .edi-num.a-avert { font-weight: 700; }
.edi-num.a-erreur { color: var(--edi-rouge); background: rgba(255,120,110,.16); }
.edi-num.a-avert  { color: var(--edi-ambre); background: rgba(247,180,90,.14); }

.edi-champ { position: relative; min-width: 0; overflow: hidden; }
.edi-peint, .edi-saisie {
  margin: 0; padding: var(--edi-pad) .9rem;
  font-family: var(--mono); font-size: var(--edi-police); line-height: var(--edi-inter);
  white-space: pre; tab-size: 4; letter-spacing: normal; word-spacing: normal;
  border: 0; box-sizing: border-box;
}
.edi-peint {
  position: absolute; inset: 0; overflow: visible; pointer-events: none;
  /* Le fond des blocs de code, répété tel quel. Poser « background: none »
     ici cassait un invariant que le banc de contraste vérifie : sur tout le
     site, un <pre> n'a que DEUX fonds, #23211E à l'écran et #F4F1EC à
     l'impression. C'est cet invariant qui autorise UNE seule palette de
     coloration pour les quarante thèmes. Le rendu est identique — le volet
     porte déjà la même couleur — mais la règle redevient vraie. */
  background: var(--edi-fond); color: var(--edi-encre); border-radius: 0;
  will-change: transform;
}
.edi-saisie {
  position: relative; width: 100%; height: 100%; display: block;
  overflow: auto; resize: none; outline: none;
  background: transparent; color: transparent; caret-color: var(--edi-caret);
}
.edi-saisie::selection {
  background: var(--edi-select);
  /* WebKit ignore « color » dans ::selection quand le texte porte un
     « -webkit-text-fill-color » : sans cette seconde ligne, la sélection
     révèle le texte transparent du textarea PAR-DESSUS la couche peinte. */
  color: transparent; -webkit-text-fill-color: transparent;
}
.edi-saisie:focus { outline: none; }
.edi-champ:focus-within { box-shadow: inset 0 0 0 2px var(--accent); }

/* ── la console ──────────────────────────────────────────────────────── */
.con { flex: 1; display: flex; min-height: 0; }
.con-flux {
  min-height: 9rem;
  flex: 1; margin: 0; padding: .8rem .9rem; overflow: auto;
  background: var(--edi-fond); border-radius: 0;   /* même invariant que .edi-peint */
  font-family: var(--mono); font-size: .8061rem; line-height: 1.6;
  color: var(--edi-encre); white-space: pre-wrap; overflow-wrap: anywhere;
}
.con-prog { color: var(--edi-encre); }
.con-prog.con-err { color: var(--edi-ambre); }
.con-saisie { color: var(--edi-vert); font-weight: 700; }
.con-saisie::before { content: "› "; opacity: .65; }
.con-note { color: var(--edi-note); font-style: italic; }
.con-note.con-stop { color: var(--edi-rouge); font-style: normal; font-weight: 650; }
.con-note.con-garde { color: var(--edi-ambre); font-style: normal; font-weight: 650; }
.con-note.con-info { color: var(--edi-bleu); font-style: normal; }

.at-entree {
  padding: .55rem .7rem .65rem;
  background: rgba(255,255,255,.055); border-top: 1px solid rgba(255,255,255,.09);
}
.at-entree label {
  display: block; margin-bottom: .35rem;
  font-size: .7273rem; font-weight: 650; color: var(--edi-ambre);
}
.at-entree-rangee { display: flex; gap: .4rem; }
.at-entree input {
  flex: 1; min-width: 0; min-height: 38px; box-sizing: border-box;
  padding: .4rem .6rem; border-radius: 6px;
  font-family: var(--mono); font-size: .8061rem;
  background: var(--edi-voile); color: var(--edi-encre);
  border: 1px solid rgba(255,255,255,.2);
}
.at-entree input:focus { outline: none; border-color: #9CD67F; box-shadow: 0 0 0 2px rgba(156,214,127,.25); }
.at-entree button {
  min-height: 38px; padding: 0 .85rem; border-radius: 6px; cursor: pointer;
  font: inherit; font-size: .8182rem; font-weight: 650;
  background: var(--accent); color: var(--sur-accent); border: 1px solid var(--accent);
}
.at-entree button:hover { background: var(--accent-sombre); }
.at-entree .at-eof {
  background: var(--edi-barre); color: var(--edi-douce);
  border-color: rgba(255,255,255,.22); font-weight: 600;
}
.at-entree .at-eof:hover { background: rgba(255,255,255,.18); color: #fff; }
@media (max-width: 480px) {
  .at-entree-rangee { flex-wrap: wrap; }
  .at-entree input { flex: 1 1 100%; }
}

/* ── plein écran ─────────────────────────────────────────────────────
   Un éditeur se juge à la quantité de code qu'on voit d'un coup. Sur une
   fiche de cours on garde le contexte autour ; quand on code pour de bon,
   on veut l'écran. Le geste est réversible d'une touche (Échap), ce qui est
   la condition pour qu'il soit sans risque. */
#atelier.at-grand {
  position: fixed; inset: 0; z-index: 90; margin: 0; border-radius: 0;
  border: 0; box-shadow: none; overflow: auto;
  padding: .8rem clamp(.8rem, 2vw, 1.4rem) 1.4rem;
  background: var(--papier);
}
/* « La console est hyper grosse c'est grave reduit la et met un scroll ».
   En plein écran, la grille étirait ses deux volets à la même hauteur : sur
   un grand écran, la console héritait des 900 px de l'éditeur pour afficher
   une ligne. « Jour 1, serveur 1 : » dans 900 px de noir.

   La hauteur bornée du mode normal avait déjà réglé le problème — mais
   seulement dans le mode normal. Le plein écran la remettait à « auto » et
   laissait l'étirement faire le reste. Deux endroits à corriger, et je n'en
   avais vu qu'un.

   Désormais : l'ÉDITEUR prend la hauteur de l'écran, c'est à cela que sert
   le plein écran ; la console garde la sienne, un peu plus généreuse qu'en
   mode normal, et défile. Elle reste redimensionnable à la main pour qui
   veut la voir plus grande. */
#atelier.at-grand .at-grille { align-items: start; }
/* « Je t'ai pas demandé de réduire le programme.c » — et il a raison : en
   bornant la console j'avais rogné l'éditeur de 2 rem au passage. Il garde
   exactement la hauteur qu'il avait, celle de la grille en plein écran. */
#atelier.at-grand .at-volet-code { height: calc(100vh - 7.5rem); }
#atelier.at-grand .at-volet-sortie {
  height: clamp(14rem, 55vh, 40rem);
  resize: vertical; overflow: hidden;
}
/* 7,5 rem : la barre de commandes et le rembourrage, mesurés. Le reste de
   la hauteur va aux deux cadres, ce qui est tout l'objet du plein écran. */
#atelier.at-grand .at-grille { min-height: calc(100vh - 7.5rem); }
#atelier.at-grand .at-volet-code { resize: none; }
#atelier.at-grand .at-poignee-note { display: none; }
body.at-fige { overflow: hidden; }

.at-icone { gap: .4rem; }
/* Deux coins opposés plutôt qu'un carré plein : c'est le signe d'« agrandir »
   qu'on reconnaît sans le lire, et il tient en deux pseudo-éléments. */
.at-ic-plein { position: relative; width: 14px; height: 14px; flex: none; }
.at-ic-plein::before, .at-ic-plein::after {
  content: ""; position: absolute; width: 7px; height: 7px;
  border: 1.6px solid currentColor;
}
.at-ic-plein::before { top: 0; left: 0; border-width: 1.6px 0 0 1.6px; }
.at-ic-plein::after { bottom: 0; right: 0; border-width: 0 1.6px 1.6px 0; }
#at-plein[aria-pressed="true"] { border-color: var(--accent); color: var(--encre); }
#at-plein[aria-pressed="true"] .at-ic-plein { background: var(--accent-pale); }

/* ── la notice repliée ───────────────────────────────────────────────
   Demandé : cette note d'information peut rester discrète, et ne
   s'ouvrir qu'au clic. Elle sert une fois, quand on découvre l'outil ; elle
   ne doit pas occuper la moitié de l'écran à chaque visite. */
.at-notice {
  margin-top: 1.6rem; border-top: 1px solid var(--bord); padding-top: .9rem;
}
.at-notice > summary {
  cursor: pointer; list-style: none; display: flex; align-items: center; gap: .5rem;
  min-height: 34px; font-size: .8485rem; font-weight: 650; color: var(--encre-douce);
}
.at-notice > summary::-webkit-details-marker { display: none; }
.at-notice > summary::before {
  content: "›"; display: inline-block; flex: none;
  width: 20px; height: 20px; border-radius: 999px; text-align: center;
  line-height: 19px; font-weight: 800;
  background: var(--carte-creuse); border: 1px solid var(--bord-fort);
  transition: transform .18s var(--ease, ease);
}
.at-notice[open] > summary::before { transform: rotate(90deg); }
.at-notice > summary:hover { color: var(--encre); }
.at-notice-corps { padding-top: .7rem; }
.at-notice-corps p { font-size: .8485rem; line-height: 1.6; color: var(--encre-douce); }
.at-notice-corps > p:first-child { margin-top: 0; }

/* ── les cartes de diagnostic ────────────────────────────────────────
   Norman : un message d'erreur nomme la cause ET l'action. Trois niveaux,
   et chacun reprend un couple fond/texte déjà mesuré sur les quarante
   thèmes — jamais une teinte inventée pour l'occasion. */
.at-diag-tete {
  margin: 1.4rem 0 .6rem; font-size: .7273rem; font-weight: 700;
  letter-spacing: .09em; text-transform: uppercase; color: var(--encre-tenue);
}
.at-diags { display: grid; gap: .6rem; }
.at-diag {
  padding: .8rem .95rem .85rem; border-radius: var(--r);
  border: 1px solid var(--bord); background: var(--carte-creuse);
  border-left: 4px solid var(--bord-fort);
}
.at-diag.d-erreur { background: var(--rouge-pale); border-color: var(--rouge-bord); border-left-color: var(--rouge); }
.at-diag.d-avert  { background: var(--ambre-pale); border-color: var(--ambre-bord); border-left-color: var(--ambre-sombre); }
.at-diag.d-garde  { background: var(--violet-pale); border-color: var(--violet-bord); border-left-color: var(--violet); }
.at-diag.d-fichier { background: var(--vert-pale); border-color: var(--vert-bord); border-left-color: var(--vert); }

.at-diag-tete, .at-diag h4 { overflow-wrap: anywhere; }
.at-diag .at-diag-tete {
  display: flex; flex-wrap: wrap; align-items: center; gap: .5rem;
  margin: 0 0 .5rem; text-transform: none; letter-spacing: normal;
}
.at-diag h4 { margin: 0; font-size: .9091rem; font-weight: 700; color: var(--encre); flex: 1 1 12rem; }
.at-puce {
  flex: none; width: 22px; height: 22px; border-radius: 999px;
  display: grid; place-items: center; font-size: .7273rem; font-weight: 800;
}
.d-erreur .at-puce { background: var(--rouge); color: #fff; }
.d-avert .at-puce  { background: var(--ambre-sombre); color: #fff; }
.d-garde .at-puce  { background: var(--violet); color: #fff; }
.d-fichier .at-puce { background: var(--vert); color: #fff; }

.at-aller {
  flex: none; min-height: 34px; padding: 0 .65rem; border-radius: 7px; cursor: pointer;
  font: inherit; font-size: .7576rem; font-weight: 650; font-family: var(--mono);
  background: var(--carte); border: 1px solid var(--bord-fort); color: var(--encre-douce);
}
.at-aller:hover { border-color: var(--accent); color: var(--accent-sombre); }

.at-extrait { margin: .35rem 0 .55rem; padding: .6rem .75rem; font-size: .7576rem; }
.at-extrait mark {
  background: rgba(255,160,90,.26); color: inherit;
  border-bottom: 2px solid #F7A66B; border-radius: 2px; padding: 0 1px;
}
.at-pourquoi { margin: 0 0 .35rem; font-size: .8485rem; line-height: 1.55; color: var(--encre); }
.at-remede { margin: 0; font-size: .8485rem; line-height: 1.55; color: var(--encre); }
.at-remede b { font-weight: 700; }
.at-notes { margin: .45rem 0 0; padding-left: 1.1rem; }
.at-notes li { font-size: .7879rem; color: var(--encre-douce); line-height: 1.5; margin-bottom: .2rem; }
.at-source { margin: .5rem 0 0; font-size: .7273rem; color: var(--encre-douce); }
.at-nomfic { margin: .4rem 0 .1rem; font-family: var(--mono); font-size: .7879rem; font-weight: 650; color: var(--encre); }
.at-vo { margin-top: .5rem; }
.at-vo summary {
  cursor: pointer; font-size: .7273rem; color: var(--encre-tenue);
  min-height: 24px; display: inline-flex; align-items: center;
}
.at-vo code { display: block; margin-top: .3rem; font-size: .7576rem; }
.at-relancer {
  min-height: 34px; padding: 0 .75rem; border-radius: 7px; cursor: pointer; font: inherit;
  font-size: .7879rem; font-weight: 650;
  background: var(--carte); border: 1px solid var(--bord-fort); color: var(--encre);
}
.at-relancer:hover { border-color: var(--violet); color: var(--violet); }

/* Le conteneur existait dans le balisage depuis le début — il n'avait jamais
   reçu sa règle. Un tableau de trois colonnes de texte ne descend pas sous
   374 px : il refusait donc de tenir dans les 287 px disponibles sur un
   téléphone, et poussait la PAGE ENTIÈRE à 418 px de large. Ce qui doit
   céder, c'est le tableau — pas la page. */
.tableau-conteneur { overflow-x: auto; overscroll-behavior-x: contain; }
.at-tableau { font-size: .8182rem; }
.at-tableau td { vertical-align: top; }

/* ── téléphone ───────────────────────────────────────────────────────
   Sous 720 px les deux volets s'empilent : deux colonnes de 170 px ne
   servent ni à écrire ni à lire. Les hauteurs se resserrent pour que
   l'éditeur ET le début de la console tiennent dans un écran. */
@media (max-width: 720px) {
  #atelier { --edi-lignes: 20; }
  .at-volet-code   { height: max(18rem, min(var(--h-volet), 62vh)); }
  .at-volet-sortie { height: max(12rem, min(calc(var(--h-volet) * .62), 38vh)); }
  .at-poignee-note { display: none; }
  .at-jauge-boite { margin-left: 0; text-align: left; width: 100%; }
  .at-jauge { margin-left: 0; width: 100%; }
  .at-lancer { flex: 1 1 auto; justify-content: center; }
}
@media (max-width: 420px) {
  .at-lancer kbd { display: none; }
  .at-bascule { font-size: .7879rem; }
}

/* ═══════════════ une page vue dans un cadre ═══════════════════════════════
   Quand une échoppe du village ouvre un outil, elle le charge dans un
   « iframe ». L'outil arrivait avec toute la coquille du site : en-tête,
   navigation, et le bouton « 3D » — donc on relançait le village DANS le
   village. « je t'avais dit que chaque monde est indépendant de l'autre. »

   Deux choses disparaissent, et pas une de plus :

   — la coquille (en-tête, fil d'Ariane, pied de page), parce qu'elle n'a
     aucun sens à l'intérieur d'une fenêtre qui porte déjà son propre titre,
     et parce que c'est elle qui offrait la porte de sortie vers le village ;
   — le paragraphe de présentation. Signalé : à l'ouverture d'un outil,
     ce message prend de la place pour rien. C'est juste : ce texte
     explique l'outil à quelqu'un qui arrive par le site. Dans une boutique,
     le tenancier vient de le dire, et l'outil fait vingt lignes de haut.

   Le titre reste, en plus petit : sans lui on ne sait plus ce qu'on manipule
   si l'on a fait défiler. */
[data-encadre] .app-tete,
[data-encadre] .app-pied,
[data-encadre] .fil-app { display: none !important; }
[data-encadre] .tete-matiere > p { display: none; }
[data-encadre] .tete-matiere { margin-bottom: .6rem; }
[data-encadre] .tete-matiere h1 { font-size: 1.06rem; margin: 0; }
/* Et la page encadrée cesse de se centrer : sa colonne de lecture de 1120 px
   était juste à l'intérieur du site, où elle borde un paragraphe. Dans un
   cadre de boutique, elle laissait deux bandes vides et faisait déborder le
   tableau des masques par la droite. Un outil n'est pas un article. */
[data-encadre] .contenu { padding: .9rem 1rem; max-width: none; }
/* Une page encadrée ne redemande jamais l'installation ni le mode hors
   ligne : elle n'est pas une destination, elle est un morceau d'une autre. */
[data-encadre] .app-installer, [data-encadre] .bandeau-maj { display: none !important; }

/* ═══════════════ s'entraîner, depuis la page des devoirs ══════════════════
   Les fiches de révision disaient QUOI relire ; elles ne donnaient rien à
   FAIRE. Or on ne révise pas une étude de fonction en la relisant — on la
   refait, et on compare. Les exercices vivent donc à côté de la date du
   contrôle, là où l'on vient voir ce qui tombe.

   Aucune couleur nouvelle : « .quiz » est déjà dessiné et mesuré sur les
   41 thèmes, et l'encadré reprend les jetons du design system. */
.dev-revisions { margin-top: 1.2rem; padding-top: 1rem;
  border-top: 1px solid var(--bord); }
.dev-revisions h3 { font-size: .82rem; letter-spacing: .06em;
  text-transform: uppercase; color: var(--encre-douce); margin: 0 0 .7rem; }

/* Le repli. <summary> est une COMMANDE : 34 px de haut comme toutes les
   autres du site, un chevron qui dit dans quel sens ça va, et la flèche
   native retirée — elle ne suit aucun thème. */
.dev-revisions > summary {
  display: flex; align-items: center; gap: .6rem;
  min-height: 34px; padding: .2rem 0; cursor: pointer;
  list-style: none; user-select: none;
}
.dev-revisions > summary::-webkit-details-marker { display: none; }
.dev-rev-titre {
  font-size: .82rem; letter-spacing: .06em; text-transform: uppercase;
  color: var(--encre-douce); font-weight: 650;
}
.dev-rev-compte {
  font-size: .76rem; color: var(--encre-douce); opacity: .8;
  padding: .1rem .45rem; border-radius: 999px;
  border: 1px solid var(--bord);
}
.dev-rev-chevron {
  margin-left: auto; width: .55rem; height: .55rem; flex: none;
  border-right: 2px solid var(--encre-douce);
  border-bottom: 2px solid var(--encre-douce);
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform .18s ease;
}
.dev-revisions[open] > summary .dev-rev-chevron {
  transform: rotate(-135deg) translate(-2px, -2px);
}
.dev-revisions > summary:hover .dev-rev-titre,
.dev-revisions > summary:focus-visible .dev-rev-titre { color: var(--encre); }
.dev-rev-corps { margin-top: .8rem; }

/* L'aire sous la courbe, dessinée plutôt que décrite. « currentColor »
   partout : la figure suit l'encre du thème, quels que soient les 41. */
.fig-aire { margin: .8rem 0 .2rem; }
.fig-aire svg { display: block; width: 100%; height: auto; color: var(--encre); }
.fig-aire figcaption {
  margin-top: .3rem; font-size: .78rem; color: var(--encre-douce);
}
.dev-revisions .quiz { margin: 0 0 .9rem; }
.dev-revisions .quiz:last-child { margin-bottom: 0; }
/* Les énoncés numérotés : la liste vit DANS le quiz, au-dessus du bouton. */
.dev-revisions .quiz ol, .dev-revisions .quiz ul { margin: .5rem 0 .9rem;
  padding-left: 1.3rem; }
.dev-revisions .quiz li { margin: .25rem 0; }
.dev-revisions .reponse p { margin: .55rem 0; }

/* ═════════════════════ le TP de révision ════════════════════════════════
   Demandé : « comme les tp […] ca ameene au complitaeur avec les enoncer ».

   Un exercice de TP n'est pas un quiz : on ne déplie pas une réponse, on
   PART ailleurs — dans l'atelier, avec le sujet déjà chargé. Les deux
   commandes sont donc des liens, et l'un des deux l'emporte visiblement sur
   l'autre : on vient ici pour chercher. Le corrigé reste à côté, en clair,
   parce que cacher le corrigé derrière un repli n'empêche personne de
   l'ouvrir et donne seulement l'impression d'être surveillé. */
.dev-tp .tp-mode {
  margin: 0 0 1rem; font-size: .88rem; color: var(--encre-douce);
  padding-left: .8rem; border-left: 2px solid var(--bord);
}
.dev-tp .tp-exo {
  margin: 0 0 .95rem; padding: .85rem .95rem;
  border: 1px solid var(--bord); border-radius: 12px;
  background: var(--carte-creuse);
}
.dev-tp .tp-exo:last-child { margin-bottom: 0; }
.dev-tp .tp-exo .titre {
  font-weight: 700; font-size: .95rem; color: var(--encre);
  margin-bottom: .2rem;
}
.dev-tp .tp-quoi {
  margin: 0 0 .55rem; font-size: .84rem; color: var(--encre-douce);
}
/* La ligne d'identité du sujet : durée, barème, nombre d'exercices. C'est
   ce qu'un vrai sujet porte en en-tête, et c'est ce qui permet de choisir
   avant de cliquer — on sait combien de temps ça prend. */
.dev-tp .tp-meta {
  display: flex; flex-wrap: wrap; gap: .3rem .4rem;
  margin: .1rem 0 .5rem;
}
.dev-tp .tp-meta span {
  font-size: .74rem; color: var(--encre-douce);
  padding: .08rem .5rem; border-radius: 999px;
  border: 1px solid var(--bord); background: var(--carte);
}
/* Le sommaire du sujet : un exercice par ligne, son barème au bout. */
.dev-tp .tp-liste {
  margin: .5rem 0 .2rem; padding-left: 1.25rem;
  font-size: .87rem; line-height: 1.55;
}
.dev-tp .tp-liste li { margin: .35rem 0; color: var(--encre-douce); }
.dev-tp .tp-liste li b { color: var(--encre); }
.dev-tp .tp-bareme {
  font-size: .74rem; color: var(--encre-douce);
  padding: .05rem .42rem; margin-left: .35rem; border-radius: 999px;
  border: 1px solid var(--bord); white-space: nowrap;
}
.dev-tp .tp-exo p { margin: .5rem 0; }
.dev-tp .tp-exo .rap {
  font-size: .85rem; color: var(--encre-douce);
  border-left: 2px solid var(--accent); padding-left: .7rem;
}
/* La sortie attendue : un énoncé de TP la donne toujours, et c'est ce qui
   permet de savoir qu'on a fini. Elle est repliée pour ne pas allonger la
   carte, pas pour la cacher. */
.dev-tp .tp-sortie { margin: .6rem 0; }
/* Sans marqueur, cette ligne se lisait comme une légende : rien ne disait
   qu'on pouvait cliquer. Un chevron qui tourne, et la commande se voit. */
.dev-tp .tp-sortie > summary {
  cursor: pointer; font-size: .82rem; color: var(--encre-douce);
  min-height: 34px; display: flex; align-items: center; gap: .45rem;
  list-style: none;
}
.dev-tp .tp-sortie > summary::-webkit-details-marker { display: none; }
.dev-tp .tp-sortie > summary::before {
  content: ""; flex: none; width: .4rem; height: .4rem;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: rotate(-45deg); transition: transform .18s ease;
}
.dev-tp .tp-sortie[open] > summary::before { transform: rotate(45deg); }
.dev-tp .tp-sortie > summary:hover { color: var(--encre); }
.dev-tp .tp-sortie pre {
  margin: .3rem 0 0; padding: .6rem .75rem; overflow-x: auto;
  font-family: var(--mono); font-size: .82rem; line-height: 1.5;
  color: var(--encre); background: var(--carte);
  border: 1px solid var(--bord); border-radius: 8px;
}
/* Les deux commandes. 44 px de haut : c'est la mesure d'un doigt, et cette
   page se lit autant sur un téléphone que sur un écran. */
.dev-tp .tp-boutons {
  display: flex; flex-wrap: wrap; gap: .5rem; margin: .8rem 0 0;
}
.dev-tp .tp-boutons a {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 44px; padding: .4rem 1rem; border-radius: 999px;
  font-size: .88rem; font-weight: 650; text-decoration: none;
  border: 1px solid transparent; transition: transform .12s ease;
}
.dev-tp .tp-boutons a:active { transform: translateY(1px); }
.dev-tp .tp-sujet {
  background: var(--accent); color: var(--sur-accent);
  border-color: var(--accent-sombre);
}
.dev-tp .tp-sujet:hover { filter: brightness(1.06); }
.dev-tp .tp-corrige {
  background: var(--carte); color: var(--encre-douce);
  border-color: var(--bord-fort);
}
.dev-tp .tp-corrige:hover { color: var(--encre); }
@media (max-width: 420px) {
  .dev-tp .tp-boutons a { flex: 1 1 100%; }
}

/* ═══════════════ les gestes de VS Code dans l'atelier ═════════════════════
   Trois comportements repris à la main, sans rien charger : Ctrl/Cmd+D pour
   parcourir les occurrences d'un mot, Alt+Z pour le retour à la ligne, et le
   surlignage de toutes les occurrences du mot sous le curseur.

   La couleur du surlignage n'est pas choisie à l'œil, et c'est heureux :
   j'avais d'abord écrit ici qu'un voile CLAIR « ne peut que monter le rapport
   de contraste ». C'est faux, exactement à l'envers, et le calcul l'a dit en
   une seconde. Le fond d'un bloc de code est #23211E et l'encre y est CLAIRE ;
   éclaircir le fond rapproche donc les deux. Mesuré sur les dix teintes de
   coloration, un voile bleu clair à 26 % fait tomber les commentaires à
   2,92:1 — très en dessous de AA — et même à 14 % ils restent à 3,78:1.

   Il faut donc ASSOMBRIR. Quatre voiles ont été calculés ; celui retenu, un
   bleu très sombre à 50 %, donne un fond composé de (22, 28, 47) où la teinte
   la plus juste tient 5,14:1 — mieux que les 4,88:1 du fond nu. Le surlignage
   rend donc le code un peu PLUS lisible, pas moins.

   Le liseré, lui, peut être clair : une bordure ne porte aucun texte, elle ne
   change aucun rapport. C'est elle qui rend la marque visible ; le fond, lui,
   se contente de ne pas nuire.

   ── Et puis le geste a été essayé ─────────────────────────────────────────
   Signalé : Ctrl+D semblait sélectionner tous les mots identiques d'un
   coup. C'est juste, et le défaut n'était pas dans Ctrl+D : c'était ce
   surlignage-ci. Poser le curseur dans un mot encadrait DÉJÀ toutes ses
   occurrences, d'une boîte identique pour chacune. Ctrl+D déplaçait bien la
   sélection de l'une à la suivante — mesuré : 39 → 86 → 94 → 119 → 134 → 39 —
   mais rien ne le montrait, puisque les sept paraissaient élues d'avance.

   Deux marques pour deux choses différentes, donc :
     · passive — « le même mot est aussi ici » : un simple trait sous le mot ;
     · active  — « c'est ici que vous êtes » : le trait devient ambre, la
       couleur du curseur du champ, et la sélection native l'habille.

   Bénéfice qu'on n'avait pas cherché : plus aucun fond n'est posé sur le
   texte. Les 5,14:1 calculés plus haut deviennent les 4,88:1 du fond nu —
   le surlignage ne touche plus au contraste du tout, ni en bien ni en mal. */
/* ── le curseur de volume du fond sonore ──────────────────────────────────
   Une piste de 34 px de haut : la règle du site veut qu'une commande se vise
   au doigt, et un curseur se vise plus mal qu'un bouton. */
.curseur-reglage {
  display: flex; align-items: center; gap: .7rem;
  margin: .7rem 0 .2rem; font-size: .88rem;
}
.curseur-reglage > span { color: var(--encre-2); white-space: nowrap; }
.curseur-reglage input[type="range"] { flex: 1; min-width: 6rem; height: 34px; }
.curseur-reglage output {
  font-variant-numeric: tabular-nums; min-width: 3ch; text-align: right;
  color: var(--encre-2); font-size: .85rem;
}
.note-son { font-size: .82rem; color: var(--encre-2); margin: .5rem 0 0; }

/* Dans un bloc de calcul, les colonnes sont alignées à l'espace près et
   l'italique du commentaire — que le navigateur SYNTHÉTISE, faute d'italique
   dans une police à chasse fixe — suffit à les faire glisser. La couleur
   reste, la pente part. */
.bloc-code[data-fam="calcul"] .j-com { font-style: normal; }

/* ── et puis : « on voit pas asser bien » ─────────────────────────────────
   Le trait fin était trop discret. Le fond sombre mesuré plus haut revient
   donc — rgba(10,24,64,.5), qui donne un composé de (22,28,47) où la teinte
   la plus juste tient 5,14:1 contre 4,88:1 sur le fond nu. Il rend le code
   un peu PLUS lisible, pas moins : c'est le seul voile qui ait ce droit.

   Trois marques, trois choses différentes, et aucune ne ressemble aux deux
   autres :
     · .edi-occ       — le même mot ailleurs : fond sombre, liseré bleu ;
     · .edi-occ.actif — celle où est le curseur : le liseré passe en ambre ;
     · .edi-paire     — l'accolade, le crochet ou la parenthèse qui ferme :
                        un liseré ambre SANS fond, parce que ce n'est pas
                        « le même mot », c'est la structure. */
.edi-occ {
  background: rgba(10, 24, 64, .5);
  border-radius: 2px;
  box-shadow: 0 0 0 1px rgba(130, 170, 255, .55);
}
.edi-paire {
  border-radius: 2px;
  box-shadow: 0 0 0 1.5px rgba(255, 215, 154, .9);
}
/* Une ouvrante que rien ne ferme : c'est une faute de compilation qui
   s'annonce, et elle mérite sa couleur. */
.edi-paire.orpheline {
  box-shadow: 0 0 0 1.5px #FF9E93;
  background: rgba(120, 20, 16, .35);
}

/* ── les sélections multiples ──────────────────────────────────────────────
   Demandé : sélectionner « int », appuyer sur Ctrl+D, et obtenir la
   sélection de départ plus la suivante. Le champ natif n'en a qu'une ; les autres
   sont dessinées dans la couche peinte, qui est à nous.

   Exactement la couleur de la sélection native — rgba(130,170,255,.3), celle
   de .edi-saisie::selection — et c'est un choix, pas une facilité : deux
   sélections qui font la même chose doivent se ressembler, sinon on croit
   qu'elles ne font pas la même chose. Le contraste n'en souffre ni plus ni
   moins que celui de la sélection que le navigateur pose déjà.

   Le trait ambre à droite est le curseur : il y en a un par sélection, comme
   dans VS Code, et c'est lui qui dit où la frappe va atterrir. */
.edi-sel {
  background: rgba(130, 170, 255, .3);
  border-right: 2px solid var(--edi-caret);
  border-radius: 1px;
}
/* Une sélection réduite à un curseur — après avoir tapé — ne doit pas
   peindre le caractère suivant : seul le trait reste. */
.edi-sel.vide { background: none; border-radius: 0; }
.edi-occ.actif {
  box-shadow: 0 0 0 1.5px #FFD79A;
}

/* L'état se lit, il ne se devine pas : « compteur · 3 sur 7 ». Sans ce
   compteur, rien ne distingue « Ctrl+D a bougé » de « Ctrl+D n'a rien fait ».
   Il tient dans l'en-tête du volet, à droite du nom du fichier. */
.edi-etat {
  margin-left: auto;
  font: 600 .7273rem/1.2 var(--mono); letter-spacing: -.01em;
  color: var(--edi-onglet);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  max-width: 55%;
}

/* Le renommage (F2). Il prend la place de l'état, dans le même en-tête :
   on ne déplace pas le regard pour une action qui parle du mot qu'on vient
   de désigner. */
.edi-renommer {
  margin-left: auto;
  display: flex; align-items: center; gap: .4rem; flex-wrap: nowrap;
}
.edi-renommer[hidden] { display: none; }
.edi-renommer label {
  font-size: .7273rem; color: var(--edi-onglet); white-space: nowrap;
}
.edi-renommer input {
  font: 500 .7273rem/1 var(--mono);
  padding: .3rem .45rem; width: 9rem; min-width: 5rem;
  border: 1px solid rgba(255,255,255,.22); border-radius: 4px;
  background: var(--edi-champ); color: var(--edi-encre);
}
.edi-renommer input:focus { outline: 2px solid var(--edi-caret); outline-offset: 1px; }
.edi-renommer input[aria-invalid="true"] { border-color: var(--edi-rouge); }
/* 34 px : la hauteur minimale d'une commande, règle du site. */
.edi-renommer button {
  font-size: .7273rem; padding: .34rem .6rem; min-height: 34px;
  border-radius: 4px; border: 1px solid rgba(255,255,255,.22);
  background: transparent; color: var(--edi-douce); cursor: pointer;
}
.edi-renommer button[type="submit"] {
  background: var(--edi-ambre); border-color: transparent;
  color: var(--edi-plein-encre); font-weight: 600;
}
/* Le retour à la ligne : les DEUX couches basculent ensemble. Si le champ
   enroule et que sa peinture ne le fait pas, le texte coloré se décale d'une
   ligne à chaque enroulement et tout glisse — le défaut se voit tout de suite,
   mais seulement sur une ligne assez longue pour enrouler. */
.edi.enroule .edi-saisie,
.edi.enroule .edi-peint { white-space: pre-wrap; overflow-wrap: anywhere; }
.edi.enroule .edi-saisie { overflow-x: hidden; }
/* L'onglet dit l'état, au lieu de le laisser deviner. */
.at-volet[data-enroule="1"] .at-onglet::after {
  content: " ⏎"; opacity: .75; font-size: .9em;
}
/* La note des raccourcis : elle vit sur la même ligne que celle des poignées,
   et elle passe dessous dès que la place manque. */
.at-raccourcis { display: inline-block; margin-left: .5rem; }

/* ═══════════════ les TP en dossiers, comme sur un téléphone ═══════════════
   « Comme les dossiers d'applications sur iPhone : quand tu cliques, ça ouvre
   une sorte de bulle carrée avec toutes les apps dedans. »

   Quinze corrigés à la file, c'est une liste qu'on parcourt des yeux sans la
   lire. Regroupés, ce sont deux objets — et « celui de quel TP ? » est la
   seule question qu'on se pose en ouvrant ce tiroir.

   La vignette reprend le signe que tout le monde connaît déjà : un carré
   arrondi, une grille de petites pastilles dedans, le nom dessous. On
   n'apprend rien à personne, et c'est tout l'intérêt. */
/* « C'est pas sur la même ligne » : à 7,5 rem de large minimum, deux
   dossiers seulement tenaient dans le tiroir, et le troisième passait seul à
   la ligne. Mesuré sur son tiroir : 300 px utiles, 0,6 rem de gouttière —
   il faut descendre sous 5,8 rem pour en loger trois. À 5,6 rem, trois
   colonnes font 93 px chacune ; quatre n'en feraient que 68 et ne tiennent
   donc pas. La vignette fait 3,1 rem, « 7 exercices » environ 4,4 rem : la
   tuile ne perd rien. */
.at-dossiers {
  display: grid; gap: .6rem; margin-top: .5rem;
  grid-template-columns: repeat(auto-fill, minmax(min(5.6rem, 100%), 1fr));
}
.at-dossier {
  display: flex; flex-direction: column; align-items: center; gap: .35rem;
  padding: .7rem .5rem .6rem; border-radius: 14px; cursor: pointer;
  background: var(--carte-creuse); border: 1px solid var(--bord);
  color: var(--encre); font: inherit; text-align: center;
  transition: border-color .18s ease, transform .18s ease;
}
.at-dossier:hover, .at-dossier:focus-visible {
  border-color: var(--accent); transform: translateY(-2px); }
.at-dossier b { font-size: .86rem; }
.at-dossier > span:last-child { font-size: .74rem; color: var(--encre-douce); }
/* La grille 3×3 du dossier — et les RANGÉES comptent autant que les
   colonnes. Sans « grid-template-rows », trois exercices formaient une seule
   rangée qui s'étirait sur toute la hauteur : trois gros barreaux au lieu de
   trois pastilles. « le TP 4 il est moche », et il l'était.
   Trois rangées d'un tiers chacune, alignées en haut : à trois exercices on
   remplit la première rangée, à neuf la grille entière — exactement ce que
   fait un dossier d'applications sur un téléphone. */
.at-dossier-grille {
  display: grid; grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, 1fr); grid-auto-rows: 1fr;
  align-content: start; justify-content: start; gap: 3px;
  width: 3.1rem; height: 3.1rem; padding: 5px; border-radius: 11px;
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 26%, transparent);
}
.at-vignette {
  border-radius: 3px; min-height: 0;
  background: color-mix(in srgb, var(--accent) 62%, transparent);
}

/* La bulle carrée. Elle se pose PAR-DESSUS la liste, dans le tiroir, et ne
   déplace rien : ouvrir un dossier ne doit pas faire sauter ce qu'on était en
   train de lire. */
.at-sac {
  position: absolute; inset: auto .6rem .6rem; z-index: 3;
  max-height: 72%; overflow: auto;
  padding: .7rem; border-radius: 16px;
  background: var(--carte); border: 1px solid var(--bord-fort);
  box-shadow: 0 18px 44px rgba(0, 6, 20, .34);
}
.at-sac-tete { display: flex; align-items: center; justify-content: space-between;
  gap: .5rem; margin-bottom: .55rem; }
.at-sac-tete h5 { margin: 0; font-size: .9rem; letter-spacing: .04em; }
.at-sac-fermer {
  width: 34px; height: 34px; border-radius: 50%; cursor: pointer;
  border: 1px solid var(--bord); background: var(--carte-creuse);
  color: var(--encre); font: inherit; line-height: 1;
}
.at-sac-fermer:hover { border-color: var(--accent); }
.at-sac-grille { display: grid; gap: .45rem; }
/* Le numéro est celui de la LISTE, pas celui du sujet : les corrigés publiés
   ne reprennent pas la numérotation de la feuille de la professeure, et
   l'inventer serait affirmer quelque chose de faux à la veille d'un TP. Il
   sert à se repérer dans le dossier, et le titre dit le reste. */
.at-ex-sac { position: relative; padding-left: 2.4rem; }
.at-ex-sac > i {
  position: absolute; left: .7rem; top: .62rem; font-style: normal;
  width: 1.3rem; height: 1.3rem; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: .72rem; font-weight: 700;
  background: color-mix(in srgb, var(--accent) 18%, transparent);
  color: var(--accent);
}

/* ═══════════════════════ la liste des commandes ═══════════════════════
   « Le Alt+Z il fonctionne mais sur Mac je le trouve pas. Fais une commande
   pour que je puisse voir les commandes. »

   Le panneau se pose DANS l'atelier, pas au milieu de l'écran : on le
   consulte en gardant son programme sous les yeux, et on le referme d'un
   Échap. Ce n'est pas une boîte de dialogue qui prend la main — c'est une
   antisèche qu'on déplie. D'où « aria-modal="false" » : rien n'est bloqué
   derrière. */
.at-palette {
  position: absolute; z-index: 6;
  top: 56px; right: 10px; left: 10px;
  max-width: 460px; margin-left: auto;
  max-height: min(60vh, 460px); overflow: auto;
  padding: .9rem 1rem 1rem;
  border: 1px solid var(--bord-fort); border-radius: 12px;
  background: var(--carte); box-shadow: 0 14px 40px rgba(0, 0, 0, .18);
}
.at-palette-tete { display: flex; align-items: center; justify-content: space-between; gap: .6rem; }
.at-palette-tete h3 { margin: 0; font-size: .97rem; font-weight: 700; color: var(--encre); }
.at-palette-filtre {
  width: 100%; margin: .7rem 0 .5rem; min-height: 38px;
  padding: 0 .7rem; border-radius: 8px;
  border: 1px solid var(--bord-fort); background: var(--carte-creuse);
  color: var(--encre); font: inherit; font-size: .88rem;
}
.at-palette-filtre:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
.at-palette-liste { margin: 0; padding: 0; list-style: none; }
.at-palette-liste li {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding: .42rem .1rem;
  border-bottom: 1px solid var(--bord);
  font-size: .865rem; color: var(--encre);
}
.at-palette-liste li:last-child { border-bottom: 0; }
.at-palette-rien { color: var(--encre-douce); font-style: italic; }
.at-palette-touches { display: inline-flex; gap: .25rem; flex: none; align-items: center; }
.at-palette-touches em { color: var(--encre-douce); font-size: .8rem; }
/* Les touches gardent la taille d'un vrai clavier : un ⌥ de 9 px ne se
   reconnaît pas, et c'est précisément le symbole qu'on venait chercher. */
.at-palette-touches kbd, .at-barre kbd {
  min-width: 1.5em; padding: .12rem .34rem;
  border: 1px solid var(--bord-fort); border-bottom-width: 2px; border-radius: 5px;
  background: var(--carte-creuse); color: var(--encre);
  font-family: var(--mono); font-size: .78rem; text-align: center;
}
.at-palette-pied {
  margin: .7rem 0 0; padding-top: .55rem; border-top: 1px solid var(--bord);
  color: var(--encre-douce); font-size: .78rem;
}
@media (max-width: 560px) {
  .at-palette { top: 8px; left: 8px; right: 8px; max-width: none; max-height: 76vh; }
  .at-palette-liste li { flex-direction: column; align-items: flex-start; gap: .25rem; }
}

/* ═══════════════════════ les contrôles déjà passés ════════════════════
   « Range les devoirs passés dans un menu déroulant, et range les devoirs en
   terme de chronologie. »

   Un <details>, pas un bouton : il s'ouvre sans JavaScript, il s'imprime
   ouvert, et le navigateur sait déjà y chercher du texte — c'est le même
   choix que pour les sujets d'entraînement, et pour les mêmes raisons.

   Replié par défaut, parce que ce qui compte en haut d'une page de devoirs
   est ce qui ARRIVE. Mais pas caché : un contrôle passé reste le meilleur
   sujet de révision pour le suivant. */
.dev-passes {
  margin: 1.6rem 0 0;
  border: 1px solid var(--bord);
  border-radius: var(--r);
  background: var(--carte-creuse);
}
.dev-passes > summary {
  display: flex; align-items: center; gap: .6rem;
  min-height: 46px; padding: .55rem 1rem;
  cursor: pointer; list-style: none;
  font-weight: 700; color: var(--encre);
}
.dev-passes > summary::-webkit-details-marker { display: none; }
.dev-passes > summary:hover { color: var(--accent-sombre); }
.dev-passes > summary .dev-rev-compte { margin-left: auto; }
.dev-passes[open] > summary { border-bottom: 1px solid var(--bord); }
.dev-passes > .dev-liste { padding: 1rem; }
/* Une carte passée se lit, mais ne réclame plus rien : l'accent tombe. */
.dev-passes .devoir { opacity: .88; }
.dev-passes .devoir:hover { opacity: 1; }
.dev-apres h3::before { content: "✓ "; color: var(--vert); }
.dev-rien { color: var(--encre-douce); font-style: italic; }

/* ═══════════════════════════ la calculatrice ══════════════════════════
   « Upsilon NumWorks à intégrer comme outils, et améliore-le pour qu'il
   ressemble aux fonctionnalités récentes d'une calculatrice NumWorks
   d'aujourd'hui. » Puis, l'outil une fois debout : « la calculatrice est
   ultra moche, améliore-moi ça et rends-la ergonomique ».

   Le reproche était juste, et il se mesurait. Les touches s'étiraient sur
   toute la largeur du volet : à 800 px, trente rectangles pâles de 110 px
   portant un glyphe de 14 px au milieu. Ce n'était pas un clavier, c'était
   un formulaire. La croix directionnelle, étalée sur six colonnes, avait
   ses flèches à 180 px les unes des autres — une croix dont les branches
   ne se touchent pas n'est plus une croix. Et le coffre à outils, écrit
   « 🧰 », sortait en rouge et brun au milieu d'un clavier d'encre.

   Trois règles ont guidé la reprise :

   · UN APPAREIL A UNE TAILLE. Le clavier est plafonné et centré : ses
     touches font la taille d'une touche, pas celle d'une colonne.
   · LE RELIEF EST DE L'INFORMATION, pas de la décoration. Une touche
     bombée se voit enfonçable avant d'être enfoncée ; c'est l'affordance
     de Norman, et elle coûte deux ombres.
   · CE QUI EST IMPRIMÉ SUR UNE TOUCHE DOIT Y RESTER. Voir plus bas les
     deux légendes.

   Deux mondes dans une page, et il faut les séparer nettement :

   · LE CHÂSSIS — la barre, le clavier, la boîte à outils, le catalogue —
     appartient au site. Il prend les jetons du design system et change
     avec les quarante thèmes, comme tout le reste.
   · L'ÉCRAN appartient à l'appareil. Un écran de calculatrice ne devient
     pas violet parce qu'on a choisi le thème Midgar : ce qu'on y lit doit
     ressembler à ce qu'on lira le jour de l'épreuve. Sa palette est donc
     déclarée ICI, une seule fois, sur « .nw-ecran », et nulle part
     ailleurs. Ce n'est pas une entorse à la règle « aucune couleur
     nouvelle en dur » : c'est un appareil représenté, au même titre
     qu'une classe Bootstrap citée dans un <pre> est du contenu enseigné.

   Les deux palettes de l'écran — clair et sombre, comme le thème que la
   version communautaire a popularisé — sont mesurées : le texte doux
   tient 7:1 sur le fond, le jaune de sélection porte de l'encre noire. */

/* Le relief des touches, déclaré une fois pour les deux faces. Sur un
   thème sombre, un filet blanc à 75 % ne fait pas « bombé », il fait
   « néon » : la lumière vient toujours d'en haut, mais elle est plus
   faible quand la pièce est sombre. */
#calculatrice {
  --nw-relief: inset 0 1px 0 rgba(255, 255, 255, .72),
               0 1.5px 0 var(--bord-fort), 0 2px 3px rgba(60, 45, 25, .10);
  --nw-relief-bas: inset 0 2px 3px rgba(60, 45, 25, .20);
  --nw-grain: rgba(60, 45, 25, .028);
}
:root[data-sombre="1"] #calculatrice {
  --nw-relief: inset 0 1px 0 rgba(255, 255, 255, .13),
               0 1.5px 0 rgba(0, 0, 0, .35), 0 2px 4px rgba(0, 0, 0, .28);
  --nw-relief-bas: inset 0 2px 4px rgba(0, 0, 0, .45);
  --nw-grain: rgba(255, 255, 255, .022);
}

.nw-barre {
  display: flex; flex-wrap: wrap; align-items: center; gap: .45rem;
  margin-bottom: .9rem;
}
.nw-barre button { font: inherit; cursor: pointer; }
.nw-creux {
  display: inline-flex; align-items: center; gap: .4rem;
  min-height: 40px; padding: 0 .9rem; border-radius: 999px;
  background: var(--carte-creuse); color: var(--encre-douce);
  border: 1px solid var(--bord-fort); font-weight: 600; font-size: .8182rem;
  box-shadow: var(--nw-relief);
}
.nw-creux:hover { border-color: var(--accent); color: var(--encre); }
.nw-creux:active { transform: translateY(1.5px); box-shadow: var(--nw-relief-bas); }
.nw-creux[aria-expanded="true"], .nw-creux[aria-pressed="true"] {
  border-color: var(--accent); color: var(--accent-sombre); background: var(--accent-pale);
}
.nw-creux kbd {
  font-family: var(--mono); font-size: .72em; border: 1px solid currentColor;
  border-radius: 4px; padding: .05em .35em; opacity: .75;
}
.nw-icone { gap: .4rem; }
.nw-etat {
  margin: 0 0 0 auto; font-size: .7879rem; font-weight: 600;
  color: var(--encre-douce); text-align: right; line-height: 1.35;
}
.nw-etat.e-ok { color: var(--vert); }
.nw-etat.e-erreur { color: var(--rouge); }

/* ── l'appareil ───────────────────────────────────────────────────────
   Sur un écran large, l'écran et le clavier sont côte à côte : le tracé
   d'une fonction a besoin de place, et personne ne tient une page web
   comme une calculatrice. En dessous de 900 px ils s'empilent, écran en
   haut — c'est la disposition de la machine.

   Les deux sont maintenant posés dans un MÊME châssis. Avant, c'étaient
   deux boîtes blanches voisines, sans rien pour dire qu'elles formaient
   un objet ; la loi de proximité dit qu'on lit alors deux choses, et
   c'est bien ce qu'on lisait. Le grain — une rayure d'un pixel toutes
   les quatre, à moins de 3 % — se devine sans se voir : il suffit à
   enlever au châssis son air de papier. */
.nw-corps {
  display: grid; gap: clamp(.65rem, 2vw, 1rem); align-items: start;
  grid-template-columns: minmax(0, 1fr) minmax(252px, 330px);
  padding: clamp(.6rem, 1.8vw, .95rem);
  border: 1px solid var(--bord-fort); border-radius: 22px;
  background:
    repeating-linear-gradient(0deg, var(--nw-grain) 0 1px, transparent 1px 4px),
    linear-gradient(180deg, var(--carte) 0%, var(--carte-creuse) 100%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .7),
              0 1px 2px rgba(60, 45, 25, .05), 0 10px 28px rgba(60, 45, 25, .10);
}
@media (max-width: 900px) { .nw-corps { grid-template-columns: minmax(0, 1fr); } }

.nw-ecran {
  --nw-fond: #FFFFFF;
  --nw-encre: #1A1A1A;
  --nw-encre-douce: #565656;
  --nw-bande: #2B2B2B;
  --nw-sur-bande: #FFFFFF;
  --nw-choix: #FFB734;
  --nw-sur-choix: #1A1A1A;
  --nw-filet: #CFCFCF;
  --nw-grille: #EDEDED;
  --nw-creuse: #F4F4F4;
  --nw-rouge: #C0392B;
  --nw-c1: #0B6CB8; --nw-c2: #C0392B; --nw-c3: #1E7B33; --nw-c4: #7A3FA8;
  display: flex; flex-direction: column;
  min-height: 400px;
  /* Un cadre, pas une bordure : les cinq pixels de « carte creuse »
     autour de la dalle sont le plastique de l'appareil, et l'ombre
     interne la pose en creux dedans. */
  border: 5px solid var(--carte-creuse); border-radius: 14px;
  background: var(--nw-fond); color: var(--nw-encre);
  overflow: hidden;
  box-shadow: 0 0 0 1px var(--bord-fort), inset 0 2px 5px rgba(20, 14, 5, .16);
}
.nw-ecran[data-ecran="sombre"] {
  --nw-fond: #15171B;
  --nw-encre: #F3F4F6;
  --nw-encre-douce: #B6BAC2;
  --nw-bande: #0C0E11;
  --nw-sur-bande: #F3F4F6;
  --nw-filet: #3A3F47;
  --nw-grille: #262B31;
  --nw-creuse: #1E2127;
  --nw-rouge: #FF8A80;
  --nw-c1: #5FB8F5; --nw-c2: #FF8A80; --nw-c3: #7FD08A; --nw-c4: #C9A3F0;
}
.nw-bandeau {
  display: flex; align-items: center; gap: .6rem;
  padding: .3rem .6rem; min-height: 26px;
  background: var(--nw-bande); color: var(--nw-sur-bande);
  font-size: .7576rem; font-weight: 700; letter-spacing: .01em;
}
/* Un titre d'application peut être long (« Régression linéaire ») et le
   bandeau ne doit jamais pousser l'angle ni l'heure hors de l'écran :
   c'est le titre qui se coupe, parce que c'est lui qu'on devine. */
.nw-bandeau-titre {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.nw-bandeau-droite { margin-left: auto; display: flex; align-items: center; gap: .55rem; }
.nw-angle, .nw-heure { font-family: var(--mono); font-weight: 600; opacity: .9; }
.nw-examen {
  background: var(--nw-choix); color: var(--nw-sur-choix);
  border-radius: 4px; padding: .05rem .4rem; font-size: .9em;
}
/* L'état du modificateur, dans le bandeau. Une touche qui change le sens
   de trente autres sans le dire est un mode caché ; Norman en fait la
   première cause d'erreur, et l'appareil l'affiche pour cette raison. */
.nw-mod {
  background: var(--nw-choix); color: var(--nw-sur-choix);
  border-radius: 4px; padding: .05rem .4rem; font-size: .9em;
  font-family: var(--mono);
}
.nw-page {
  flex: 1; min-height: 0; padding: .7rem .8rem 1rem;
  font-size: .8788rem; line-height: 1.5; overflow: auto;
}
.nw-sans-js { margin: 0; color: var(--nw-encre-douce); }

/* ── l'accueil : la grille d'applications ────────────────────────────
   Trois colonnes, des tuiles égales, et UNE seule tuile choisie à la
   fois. La marque du choix est posée sur le NOM, pas sur la tuile :
   c'est ce que fait la machine, et c'est plus lisible qu'un liseré —
   une pastille pleine se voit du coin de l'œil, un trait de deux pixels
   demande qu'on le cherche. Le liseré reste quand même, parce que deux
   indices valent mieux qu'un et que le second ne coûte rien.

   Les flèches du clavier déplacent la sélection, Entrée ouvre — c'est le
   seul geste de l'accueil, il doit marcher sans la souris. */
.nw-accueil { display: grid; grid-template-columns: repeat(3, 1fr); gap: .55rem; }
@media (max-width: 420px) { .nw-accueil { grid-template-columns: repeat(2, 1fr); } }
.nw-tuile {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: .42rem; min-height: 84px; padding: .5rem .3rem;
  border: 1px solid var(--nw-filet); border-radius: 12px;
  background: var(--nw-creuse); color: var(--nw-encre);
  font: inherit; font-weight: 650; font-size: .8182rem; cursor: pointer;
  text-align: center;
}
.nw-tuile:hover { border-color: var(--nw-choix); }
.nw-tuile:focus-visible { outline: 2px solid var(--nw-choix); outline-offset: 2px; }
.nw-tuile[aria-current="true"] { border-color: var(--nw-choix); }
.nw-tuile-ic {
  width: 30px; height: 30px; display: grid; place-items: center; color: var(--nw-encre);
}
.nw-tuile-ic svg { width: 100%; height: 100%; display: block; }
.nw-tuile-ic .f { color: var(--nw-filet); }
.nw-tuile-ic .a { color: var(--nw-choix); }
.nw-tuile-nom {
  padding: .08rem .42rem; border-radius: 5px; line-height: 1.3;
}
.nw-tuile[aria-current="true"] .nw-tuile-nom {
  background: var(--nw-choix); color: var(--nw-sur-choix);
}
.nw-accueil-note { margin: .9rem 0 0; font-size: .7879rem; color: var(--nw-encre-douce); }

/* ── le fil des calculs ──────────────────────────────────────────────
   L'entrée en petit et en gris, le résultat EXACT en gros, la valeur
   approchée dessous. C'est la hiérarchie de l'appareil, et elle dit la
   bonne chose : ce qu'on recopie sur la copie, c'est la forme exacte.

   L'entrée est un BOUTON : un clic la remet dans la ligne de saisie.
   Une faute de frappe dans « binomialeCdf(10;0.3;4) » se corrigeait en
   la retapant en entier ; elle se corrige maintenant en la reprenant. */
.nw-flux { display: flex; flex-direction: column; gap: .5rem; }
.nw-ligne {
  border-bottom: 1px solid var(--nw-grille); padding-bottom: .45rem;
  display: flex; flex-direction: column; gap: .1rem;
}
.nw-ligne:last-child { border-bottom: 0; }
.nw-saisie {
  display: block; width: calc(100% + .4rem); margin: 0 0 0 -.2rem;
  padding: .1rem .2rem; text-align: left; border: 0; border-radius: 5px;
  background: none; cursor: pointer; font: inherit;
  font-family: var(--mono); font-size: .7879rem; color: var(--nw-encre-douce);
  overflow-wrap: anywhere; font-variant-numeric: tabular-nums;
}
.nw-saisie:hover { color: var(--nw-encre); background: var(--nw-creuse); }
.nw-saisie:focus-visible { outline: 2px solid var(--nw-choix); outline-offset: 0; }
.nw-resultat {
  font-family: var(--mono); font-size: 1.12rem; font-weight: 700;
  text-align: right; overflow-wrap: anywhere; font-variant-numeric: tabular-nums;
}
.nw-approche {
  font-family: var(--mono); font-size: .8182rem; color: var(--nw-encre-douce);
  text-align: right; font-variant-numeric: tabular-nums;
}
.nw-erreur {
  color: var(--nw-rouge); font-size: .8182rem; font-weight: 600;
  background: none; text-align: left;
}
.nw-vide { color: var(--nw-encre-douce); font-style: italic; margin: 0; line-height: 2; }
/* Les essais de l'écran vide : des cibles, pas des citations. Encre de
   l'écran sur sa surface creuse — le couple le plus sûr qu'il ait. */
.nw-essai {
  font-family: var(--mono); font-size: .8182rem; font-style: normal;
  color: var(--nw-encre); background: var(--nw-creuse);
  border: 1px solid var(--nw-filet); border-radius: 999px;
  padding: .2rem .6rem; min-height: 30px; cursor: pointer;
  font-variant-numeric: tabular-nums;
}
.nw-essai:hover { border-color: var(--nw-choix); }
.nw-essai:focus-visible { outline: 2px solid var(--nw-choix); outline-offset: 1px; }

/* Le champ de saisie de l'écran : c'est l'élément le plus utilisé de
   l'outil, il a donc la plus grande cible et le plus gros caractère. */
.nw-saisie-boite {
  display: flex; gap: .4rem; align-items: stretch;
  /* La boîte est passée EN TÊTE de l'écran : l'air qu'elle avait au-dessus
     lui sert maintenant en dessous, pour la détacher du premier calcul. */
  margin: 0 0 .8rem;
}
.nw-champ {
  flex: 1; min-width: 0; min-height: 42px; padding: .35rem .55rem;
  font-family: var(--mono); font-size: 1rem; color: var(--nw-encre);
  background: var(--nw-creuse); font-variant-numeric: tabular-nums;
  border: 1.5px solid var(--nw-filet); border-radius: 9px;
}
.nw-champ:focus { outline: 2px solid var(--nw-choix); outline-offset: 1px; border-color: var(--nw-choix); }
.nw-valider {
  min-height: 42px; padding: 0 .9rem; border-radius: 9px; cursor: pointer;
  background: var(--nw-bande); color: var(--nw-sur-bande); border: 0;
  font: inherit; font-weight: 700; font-size: .8182rem; letter-spacing: .04em;
}

/* ── les panneaux d'application ────────────────────────────────────────
   Les onglets forment un SEGMENT : un seul bloc creux, dans lequel la
   pastille choisie glisse. Trois boutons voisins demandent qu'on lise
   lequel est allumé ; un segment se lit d'un coup, parce que le fond
   dit déjà qu'ils vont ensemble. */
.nw-onglets {
  display: inline-flex; flex-wrap: wrap; gap: 2px; margin: 0 0 .6rem;
  max-width: 100%; padding: 2px; border-radius: 999px;
  border: 1px solid var(--nw-filet); background: var(--nw-creuse);
}
.nw-onglet {
  min-height: 32px; padding: .2rem .78rem; cursor: pointer; font: inherit;
  font-size: .7879rem; font-weight: 650; border-radius: 999px;
  border: 0; background: none; color: var(--nw-encre-douce);
}
.nw-onglet:hover { color: var(--nw-encre); }
.nw-onglet:focus-visible { outline: 2px solid var(--nw-choix); outline-offset: 1px; }
.nw-onglet[aria-selected="true"] {
  background: var(--nw-choix); color: var(--nw-sur-choix);
}
.nw-rangee { display: flex; flex-wrap: wrap; gap: .4rem; align-items: center; margin-bottom: .5rem; }
.nw-rangee label { font-size: .7879rem; font-weight: 600; color: var(--nw-encre-douce); }
.nw-petit {
  min-height: 34px; padding: .2rem .4rem; width: 6.5rem; max-width: 40vw;
  font-family: var(--mono); font-size: .8182rem; font-variant-numeric: tabular-nums;
  color: var(--nw-encre); background: var(--nw-creuse);
  border: 1px solid var(--nw-filet); border-radius: 7px;
}
.nw-petit.nw-large { width: 100%; max-width: none; flex: 1; }
.nw-petit:focus { outline: 2px solid var(--nw-choix); outline-offset: 1px; }
select.nw-petit { width: auto; min-width: 7rem; }
.nw-bouton {
  min-height: 34px; padding: .25rem .7rem; cursor: pointer; font: inherit;
  font-size: .7879rem; font-weight: 650; border-radius: 999px;
  border: 1px solid var(--nw-filet); background: var(--nw-creuse); color: var(--nw-encre);
}
.nw-bouton:hover { border-color: var(--nw-choix); }
.nw-bouton.nw-primaire { background: var(--nw-bande); color: var(--nw-sur-bande); border-color: var(--nw-bande); }

/* Les résultats : une liste de couples « nom → valeur », alignés sur la
   valeur. Un tableau de bord qu'on lit en diagonale. Les chiffres sont
   tabulaires : sans cela, les colonnes de « 0.1234 » et « 1.0000 » ne
   tombent pas l'une sous l'autre, et c'est précisément ce qu'on cherche
   à comparer. */
.nw-valeurs { display: grid; grid-template-columns: auto 1fr; gap: .15rem .7rem; margin: .5rem 0 0; }
.nw-valeurs dt { font-size: .7879rem; color: var(--nw-encre-douce); font-weight: 600; }
.nw-valeurs dd {
  margin: 0; font-family: var(--mono); font-size: .8485rem; font-weight: 650;
  overflow-wrap: anywhere; font-variant-numeric: tabular-nums;
}
.nw-valeurs dd b { color: var(--nw-encre); }
.nw-sous { font-size: .7576rem; color: var(--nw-encre-douce); margin: .5rem 0 0; line-height: 1.5; }
.nw-sous a { color: inherit; text-decoration: underline; }
.nw-chapitre {
  display: inline-flex; align-items: center; gap: .3rem; min-height: 34px;
  margin-top: .6rem; padding: .2rem .7rem;
  border: 1px solid var(--nw-filet); border-radius: 999px;
  background: var(--nw-creuse); color: var(--nw-encre);
  font-size: .7879rem; font-weight: 650; text-decoration: none;
}
.nw-chapitre:hover { border-color: var(--nw-choix); text-decoration: underline; }

/* Les tableaux de l'écran (valeurs, statistiques, régressions). */
.nw-table { width: 100%; border-collapse: collapse; font-size: .7879rem; }
.nw-table th, .nw-table td {
  border: 1px solid var(--nw-grille); padding: .2rem .4rem; text-align: right;
  font-family: var(--mono); font-variant-numeric: tabular-nums;
}
.nw-table th { background: var(--nw-creuse); font-weight: 700; color: var(--nw-encre-douce); }
.nw-table td:first-child, .nw-table th:first-child { text-align: left; }
.nw-defile { overflow: auto; max-height: 260px; }
.nw-cellule {
  width: 100%; min-height: 34px; padding: .15rem .3rem; border: 0; background: none;
  font-family: var(--mono); font-size: .7879rem; color: var(--nw-encre); text-align: right;
  font-variant-numeric: tabular-nums;
}
.nw-cellule:focus { outline: 2px solid var(--nw-choix); outline-offset: -2px; }

/* ── le tracé ─────────────────────────────────────────────────────────
   En SVG et non sur une toile : il reste net quand on l'agrandit, il
   s'imprime, et le banc de rendu peut le lire. La courbe est coupée dès
   qu'elle sort du cadre — sans cela une asymptote dessine un trait
   vertical qui n'existe pas, et c'est l'erreur de lecture la plus
   fréquente sur un écran de calculatrice. */
.nw-trace { display: block; width: 100%; height: auto; background: var(--nw-fond); }
.nw-trace .axe { stroke: var(--nw-encre-douce); stroke-width: 1; }
.nw-trace .grille { stroke: var(--nw-grille); stroke-width: 1; }
.nw-trace .courbe { fill: none; stroke-width: 1.8; stroke-linejoin: round; stroke-linecap: round; }
.nw-trace .c1 { stroke: var(--nw-c1); } .nw-trace .c2 { stroke: var(--nw-c2); }
.nw-trace .c3 { stroke: var(--nw-c3); } .nw-trace .c4 { stroke: var(--nw-c4); }
.nw-trace .aire { fill: var(--nw-c1); opacity: .18; stroke: none; }
.nw-trace .point { fill: var(--nw-c1); }
/* Un nuage par série, chacun de la couleur de SA courbe : sans ça, trois
   séries donnent trois courbes distinctes au-dessus d'un seul tas de
   points bleus, et on ne sait plus quel point appartient à quoi. */
.nw-trace .point.c2 { fill: var(--nw-c2); }
.nw-trace .point.c3 { fill: var(--nw-c3); }
.nw-trace .point.c4 { fill: var(--nw-c4); }
/* Les en-têtes du tableau des régressions portent la même couleur : la
   colonne X2 et la courbe X2 se reconnaissent sans légende. */
.nw-col-c2 { color: var(--nw-c2); }
.nw-col-c3 { color: var(--nw-c3); }
.nw-col-c4 { color: var(--nw-c4); }
.nw-table-reg th[scope="row"] {
  text-align: left; font-weight: 500; color: var(--nw-encre-douce);
  white-space: nowrap;
}
/* Le point moyen se distingue des points de mesure : un anneau, pas un
   disque. La machine fait pareil — il n'appartient pas aux données. */
.nw-trace .point.nw-moyen { fill: none; stroke-width: 2.5; r: 4.5; }
.nw-trace .point.nw-moyen.c2 { stroke: var(--nw-c2); }
.nw-trace .point.nw-moyen.c3 { stroke: var(--nw-c3); }
.nw-trace .point.nw-moyen.c4 { stroke: var(--nw-c4); }
.nw-moyenne {
  margin: .35rem 0 0; padding: .35rem .6rem;
  background: var(--nw-creuse); border-radius: 6px;
  font-family: var(--mono); font-size: .7576rem; color: var(--nw-encre);
}
.nw-case { display: inline-flex; align-items: center; gap: .3rem; }
/* La barre de l'onglet Graphique, comme sur la machine : des entrées
   posées à plat, séparées par rien d'autre que l'espace. Pas des
   boutons en relief — ce sont des rubriques, et la machine les montre
   ainsi. */
.nw-barre-outils {
  display: flex; flex-wrap: wrap; align-items: center; gap: .15rem;
  margin: 0 0 .5rem; padding: .25rem 0;
  border-bottom: 1px solid var(--nw-filet);
}
.nw-outil {
  display: inline-flex; align-items: center; gap: .35rem;
  padding: .3rem .6rem; min-height: 32px;
  border: 0; border-radius: 7px; background: none; cursor: pointer;
  font: inherit; font-size: .7879rem; color: var(--nw-encre);
}
.nw-outil:hover { background: var(--nw-creuse); }
.nw-outil:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.nw-outil.nw-ouvert {
  background: var(--nw-choix); color: var(--nw-sur-choix); font-weight: 600;
}
/* La pastille d'« Auto » : allumée ou éteinte. Un cercle vide dit
   « éteint » plus clairement qu'un cercle absent, qui dit « rien ». */
.nw-pastille {
  width: 10px; height: 10px; border-radius: 50%;
  border: 1.5px solid var(--nw-encre-douce);
}
.nw-pastille.nw-allumee { background: var(--nw-choix); border-color: var(--nw-choix); }
.nw-panneau {
  margin: 0 0 .5rem; padding: .5rem .6rem;
  background: var(--nw-creuse); border-radius: 8px;
}
.nw-court { width: 5.5ch; }
.nw-equation {
  margin: .5rem 0 0; font-family: var(--mono); font-size: .8061rem;
  color: var(--nw-encre);
}
.nw-trace .barre { fill: var(--nw-c1); }
.nw-trace .barre-choisie { fill: var(--nw-choix); stroke: var(--nw-encre); stroke-width: .8; }
.nw-trace .curseur { stroke: var(--nw-encre); stroke-width: 1; stroke-dasharray: 3 2; }
.nw-trace text { fill: var(--nw-encre-douce); font-size: 9px; font-family: var(--mono); }
.nw-trace .etiq { fill: var(--nw-encre); font-weight: 700; }
.nw-curseur-info {
  font-family: var(--mono); font-size: .8182rem; font-weight: 650;
  margin: .35rem 0 0; display: flex; flex-wrap: wrap; gap: .1rem .9rem;
  font-variant-numeric: tabular-nums;
}
.nw-legende { display: flex; flex-wrap: wrap; gap: .1rem .8rem; margin: .4rem 0 0; font-size: .7576rem; }
.nw-legende span { display: inline-flex; align-items: center; gap: .3rem; color: var(--nw-encre-douce); }
.nw-legende i { width: 14px; height: 3px; border-radius: 2px; display: inline-block; }

/* ── le clavier ───────────────────────────────────────────────────────
   La disposition de l'appareil : le bloc de navigation, le bloc des
   fonctions sur six colonnes, le pavé numérique sur cinq.

   PLAFONNÉ À 352 px, et c'est la correction principale. Une touche de
   calculatrice mesure un pouce de large ; étirée à 110 px elle ne se
   vise plus, elle se survole. Chaque touche fait au moins 40 px de haut
   — en dessous, on en tape deux à la fois, et c'est la seule raison de
   ce chiffre. */
.nw-clavier {
  display: flex; flex-direction: column; gap: .45rem;
  width: 100%; max-width: 352px; margin-inline: auto;
  padding: .6rem .55rem .5rem;
  border: 1px solid var(--bord); border-radius: 18px;
  background: var(--carte-creuse);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .55);
}
.nw-bloc { display: grid; gap: .3rem; }
.nw-bloc-fn { grid-template-columns: repeat(6, 1fr); }
.nw-bloc-num { grid-template-columns: repeat(5, 1fr); }
.nw-vide-case { display: none; }

/* La rangée de navigation n'est pas une grille : la croix doit rester
   d'un seul tenant, et les deux touches de sortie se posent à côté
   d'elle. En grille à six colonnes, les flèches finissaient à 180 px
   les unes des autres. */
.nw-bloc-nav {
  display: flex; align-items: center; justify-content: center; gap: .45rem;
}
.nw-bloc-nav > .nw-touche { min-width: 50px; }
.nw-croix {
  order: -1; flex: 0 0 auto; width: 126px;
  display: grid; gap: .22rem; grid-template-columns: repeat(3, 1fr);
  grid-template-areas: ". haut ." "gauche ok droite" ". bas .";
}
.nw-croix .nw-touche { min-height: 34px; min-width: 0; padding: 0; border-radius: 9px; }
.nw-croix .k-haut { grid-area: haut; } .nw-croix .k-bas { grid-area: bas; }
.nw-croix .k-gauche { grid-area: gauche; } .nw-croix .k-droite { grid-area: droite; }
.nw-croix .k-ok { grid-area: ok; font-size: .6818rem; border-radius: 999px; }

.nw-touche {
  position: relative; display: flex; align-items: center; justify-content: center;
  min-height: 42px; padding: .62rem .22rem .2rem; cursor: pointer;
  border: 1px solid var(--bord-fort); border-radius: 999px;
  background: linear-gradient(180deg, var(--carte), var(--carte-creuse));
  color: var(--encre); box-shadow: var(--nw-relief);
  font: inherit; font-size: .8182rem; font-weight: 650; line-height: 1.05;
  font-family: var(--mono); font-variant-numeric: tabular-nums;
  transition: transform .06s ease, box-shadow .06s ease;
}
.nw-touche:hover { border-color: var(--accent); }
.nw-touche:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.nw-touche:active { transform: translateY(1.5px); box-shadow: var(--nw-relief-bas); }
.nw-ico { width: 1.15em; height: 1.15em; display: block; }
.nw-touche-nav .nw-ico, .nw-croix .nw-ico { width: 1.3em; height: 1.3em; }

/* ── les deux légendes ────────────────────────────────────────────────
   La table des touches porte depuis toujours DEUX sens par touche : ce
   qu'elle écrit sous Maj, et la lettre de mémoire qu'elle écrit sous
   alpha. L'ancien rendu n'en montrait qu'un, et toujours le même : sur
   les douze touches qui ont les deux, la lettre n'était imprimée nulle
   part. Pour taper « A » il fallait l'avoir deviné.

   La place dit laquelle : à gauche ce que donne Maj, à droite ce que
   donne alpha. La couleur le redit, pour ceux qui ne connaissent pas
   encore la convention — et les deux légendes sont toujours là, même
   quand un modificateur est allumé, parce qu'une touche imprimée ne
   change pas de gravure quand on appuie dessus. */
.nw-leg {
  position: absolute; top: 3px; left: 7px; right: 7px;
  display: flex; justify-content: space-between; align-items: baseline;
  font-family: var(--sans); font-size: .625rem; font-weight: 700;
  line-height: 1; letter-spacing: -.02em; pointer-events: none;
}
.nw-leg i { font-style: normal; white-space: nowrap; }
/* LA LÉGENDE DE MAJ EST UNE PASTILLE, PAS UNE COULEUR D'ENCRE — et c'est
   une mesure qui l'a imposée, après une correction ratée.

   Premier état : « --ambre-sombre » sur la touche. Le banc a rendu
   4,17:1 sur le thème androïde de jour, pour un seuil de 4,5.
   Deuxième état : arrêter le dégradé de la touche à 58 %, pour que la
   légende trouve « --carte » pur sous elle. Le banc a rendu 4,17 de
   nouveau. Il avait raison et j'avais tort : il garde les DEUX extrêmes
   d'un dégradé opaque et retient le pire, parce que le lecteur voit
   vraiment les deux couleurs. Un arrêt déplacé ne change rien à ça.

   Mesuré sur ce thème : « --ambre-sombre » vaut 4,60 sur « --carte »,
   4,17 sur « --carte-creuse », et l'encre pleine vaut 11,79 sur
   « --ambre-pale ». L'ambre passe donc du texte au FOND, où elle dit
   exactement la même chose — c'est à quoi servent les couleurs
   d'accent, et c'est écrit depuis toujours dans « theme.css » : les
   surfaces d'un côté, le texte de l'autre. Une marge de 0,1 sur un
   thème sur quarante et un n'est pas une marge. */
.nw-l-maj {
  color: var(--encre); background: var(--ambre-pale);
  border-radius: 3px; padding: 0 .22em;
}
.nw-l-alp { color: var(--encre-douce); }

/* Modificateur allumé : les touches qu'il atteint se teignent, et leur
   légende s'éteint — son sens est passé dans le grand libellé. */
/* Les trois teintes suivantes sont PLATES, pour la même raison qu'EXE :
   le libellé s'écrit au milieu de la touche, et un dégradé y pose un
   fond composé dont aucun couple ne répond. « --ambre-sombre sur
   --ambre-pale » et « --accent-sombre sur --accent-pale » sont des
   couples de la maison ; « sur le milieu d'un dégradé » n'en est pas un. */
.nw-clavier[data-mod="maj"] .nw-touche[data-maj] {
  color: var(--ambre-sombre); border-color: var(--ambre-bord);
  background: var(--ambre-pale);
}
.nw-clavier[data-mod="maj"] .nw-l-maj { visibility: hidden; }
.nw-clavier[data-mod="alpha"] .nw-touche[data-alpha] {
  color: var(--accent-sombre); border-color: var(--accent);
  background: var(--accent-pale);
}
.nw-clavier[data-mod="alpha"] .nw-l-alp { visibility: hidden; }

.nw-touche-fn { font-size: .7576rem; }
.nw-touche-nav { font-size: .7879rem; }
/* EXE reste PLAT, et c'est une mesure qui l'a imposé. Le dégradé
   « accent → accent-sombre » paraissait plus profond ; il écrivait
   « --sur-accent » sur « --accent-sombre », deux jetons qui ne forment
   pas un couple. Mesuré sur le thème voxel de nuit : 1,78:1. Le couple
   garanti est « --sur-accent sur --accent », et il n'existe que si le
   fond est bien « --accent ». Le relief vient des ombres, qui ne
   changent aucune couleur. */
.nw-touche-exe {
  background: var(--accent);
  color: var(--sur-accent); border-color: var(--accent-sombre);
  letter-spacing: .04em;
}
.nw-touche-exe:hover { border-color: var(--accent-sombre); }
/* La touche d'accueil est ambrée comme sur l'appareil : c'est la seule
   touche qui ramène quelque part, elle ne se cherche pas. */
.nw-touche[data-act="accueil"] {
  background: var(--ambre-pale);
  border-color: var(--ambre-bord); color: var(--ambre-sombre);
}
.nw-touche[data-act="maj"][aria-pressed="true"] {
  background: var(--ambre-pale); border-color: var(--ambre); color: var(--ambre-sombre);
  box-shadow: var(--nw-relief-bas);
}
.nw-touche[data-act="alpha"][aria-pressed="true"] {
  background: var(--accent-pale); border-color: var(--accent); color: var(--accent-sombre);
  box-shadow: var(--nw-relief-bas);
}
.nw-clavier-note { margin: .1rem 0 0; font-size: .6818rem; color: var(--encre-douce); text-align: center; }

/* ── la boîte à outils ───────────────────────────────────────────────── */
.nw-boite {
  margin-top: 1rem; border: 1px solid var(--bord-fort); border-radius: var(--r);
  background: var(--carte); box-shadow: var(--ombre);
}
.nw-boite-tete {
  display: flex; gap: .5rem; align-items: center; flex-wrap: wrap;
  padding: .6rem .8rem; border-bottom: 1px solid var(--bord);
}
.nw-boite-tete h3 { margin: 0; font-size: .9394rem; }
.nw-boite-tete input {
  flex: 1; min-width: 10rem; min-height: 38px; padding: .2rem .5rem;
  border: 1px solid var(--bord-fort); border-radius: 999px;
  background: var(--carte-creuse); color: var(--encre); font: inherit; font-size: .8485rem;
}
.nw-boite-tete button {
  min-height: 38px; min-width: 38px; cursor: pointer; font: inherit; font-size: 1rem;
  border: 1px solid var(--bord-fort); border-radius: 999px;
  background: var(--carte-creuse); color: var(--encre-douce);
}
.nw-boite-liste { max-height: 340px; overflow: auto; padding: .4rem; }
.nw-boite-cat {
  margin: .5rem 0 .25rem; padding: 0 .4rem; font-size: .7576rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .04em; color: var(--encre-douce);
}
.nw-boite-item {
  display: block; width: 100%; text-align: left; cursor: pointer; font: inherit;
  min-height: 38px; padding: .35rem .5rem; border: 1px solid transparent;
  border-radius: 9px; background: none; color: var(--encre);
}
.nw-boite-item:hover, .nw-boite-item:focus-visible {
  background: var(--accent-pale); border-color: var(--accent);
}
.nw-boite-item b { font-family: var(--mono); font-size: .8485rem; }
.nw-boite-item i { display: block; font-style: normal; font-size: .7879rem; color: var(--encre-douce); }
.nw-boite-rien { padding: .8rem; margin: 0; color: var(--encre-douce); font-style: italic; }

.nw-aide-clavier {
  margin: .9rem 0 0; font-size: .8182rem; color: var(--encre-douce); line-height: 1.6;
}
.nw-aide-clavier kbd {
  font-family: var(--mono); font-size: .9em; border: 1px solid var(--bord-fort);
  border-radius: 4px; padding: .05em .3em; background: var(--carte-creuse);
}
.nw-notice { margin-top: 1.2rem; }
.nw-notice > summary {
  cursor: pointer; min-height: 44px; display: flex; align-items: center;
  font-weight: 700; color: var(--encre);
}
.nw-notice > summary:hover { color: var(--accent-sombre); }
.nw-notice-corps { padding: .3rem 0 0; }
.nw-notice-corps h4 { margin: 1.1rem 0 .4rem; font-size: .9394rem; }
.nw-notice-corps p { margin: 0 0 .7rem; line-height: 1.65; font-size: .8788rem; }
.nw-note-forte {
  border-left: 3px solid var(--accent); padding-left: .8rem;
  background: var(--accent-pale); border-radius: 0 8px 8px 0; padding: .5rem .8rem;
}
.nw-conventions { margin: 0 0 .8rem; padding-left: 1.1rem; }
.nw-conventions li { margin-bottom: .45rem; line-height: 1.6; font-size: .8788rem; }
.nw-cat-tete { margin: 1.6rem 0 .4rem; }
.nw-cat-intro { margin: 0 0 .9rem; color: var(--encre-douce); font-size: .8788rem; line-height: 1.6; }
.nw-cat-groupe { margin-bottom: 1.1rem; }
.nw-cat-groupe h4 { margin: 0 0 .4rem; font-size: .9091rem; }
.nw-cat-table { width: 100%; border-collapse: collapse; font-size: .8182rem; }
.nw-cat-table th, .nw-cat-table td {
  border: 1px solid var(--bord); padding: .3rem .5rem; text-align: left; vertical-align: top;
}
.nw-cat-table th { background: var(--carte-creuse); font-weight: 700; }
.nw-cat-table code { font-size: .95em; }
.nw-cat-table .ex { font-family: var(--mono); white-space: nowrap; }

/* ── agrandi ──────────────────────────────────────────────────────────
   Même geste que l'atelier C, et pour la même raison : un tracé se juge
   à ce qu'on en voit d'un coup. Réversible par Échap. */
#calculatrice.nw-grand {
  position: fixed; inset: 0; z-index: 90; margin: 0; border: 0; border-radius: 0;
  box-shadow: none; overflow: auto; background: var(--papier);
  padding: .8rem clamp(.8rem, 2vw, 1.4rem) 1.4rem;
}
#calculatrice.nw-grand .nw-ecran { min-height: calc(100vh - 11rem); }
#calculatrice.nw-grand .nw-notice,
#calculatrice.nw-grand .nw-cat-tete,
#calculatrice.nw-grand .nw-cat-intro,
#calculatrice.nw-grand .nw-catalogue,
#calculatrice.nw-grand .nw-aide-clavier { display: none; }
body.nw-fige { overflow: hidden; }

@media print {
  .nw-clavier, .nw-barre, .nw-boite, .nw-aide-clavier { display: none; }
  .nw-corps { grid-template-columns: 1fr; background: none; box-shadow: none; border: 0; padding: 0; }
  .nw-ecran { box-shadow: none; border-width: 1px; }
}

/* ── la marge de l'éditeur est cliquable ──────────────────────────────
   Demandé : le geste de VS Code — un clic sur le numéro sélectionne la
   ligne entière.
   L'affordance doit se voir avant le clic (Norman) : le curseur change sur
   toute la bande, et le numéro survolé reprend sa pleine encre. Ce sont les
   deux seuls signes disponibles — on ne peut ni agrandir un numéro de ligne
   ni l'encadrer sans décaler le code qu'il numérote. */
.edi-marge { cursor: pointer; }
.edi-marge .edi-num:hover { color: var(--encre); }
.edi-marge:active .edi-num { user-select: none; }

/* ── le séparateur des deux volets ───────────────────────────────────
   « met la possibilité de pouvoir agrandir la fenêtre de programme.c vers
   la droite, si on le fait du coup ça prend sur la fenêtre de la console ».

   La colonne du séparateur fait 34 px, et ce n'est pas une coquetterie :
   c'est une COMMANDE, donc la règle du site lui impose la même cible
   tactile qu'à un bouton. Le trait visible, lui, fait 2 px — le reste est
   de la place pour le doigt, exactement comme dans un éditeur de bureau.
   Il remplace la gouttière de 0,9 rem qui séparait déjà les deux cadres,
   donc l'écran ne perd que vingt pixels.

   Les deux colonnes sont pilotées par une seule variable. Sous 760 px les
   volets s'empilent : un séparateur vertical n'a alors plus de sens, il
   disparaît et la gouttière revient. */
@media (min-width: 760px) {
  .at-grille {
    grid-template-columns: minmax(260px, var(--at-part, 1fr)) 34px minmax(260px, 1fr);
    gap: 0;
  }
}
.at-separateur {
  align-self: stretch; cursor: col-resize; position: relative;
  display: flex; align-items: center; justify-content: center;
  background: none; border: 0; padding: 0;
  touch-action: none;
}
/* APRÈS la règle de base, et pas avant : à spécificité égale c'est le
   dernier qui gagne. Écrite au-dessus, cette ligne ne masquait rien — le
   séparateur restait visible sur téléphone, où il n'a aucun sens
   puisque les deux cadres sont l'un sous l'autre. */
@media (max-width: 759px) { .at-separateur { display: none; } }
.at-separateur > span {
  display: block; width: 2px; height: 100%; border-radius: 2px;
  background: var(--bord-fort); transition: background .12s, width .12s;
}
.at-separateur:hover > span,
.at-separateur:focus-visible > span,
.at-separateur[data-tire="1"] > span { background: var(--accent); width: 4px; }
.at-separateur:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
/* Pendant le glissement, le pointeur traverse l'éditeur : sans cela il
   sélectionnerait du texte à chaque mouvement, et le geste serait
   inutilisable. */
body.at-tire, body.at-tire * { cursor: col-resize !important; user-select: none !important; }

/* Le pavé de six lignes sous les cadres a disparu : il était jugé laid,
   et il l'était. Ce qui reste est une ligne, et tout ce que le
   pavé disait vit maintenant dans la palette des commandes. */
.at-lien {
  font: inherit; color: var(--accent-sombre); background: none; border: 0;
  padding: 0; cursor: pointer; text-decoration: underline;
  min-height: 34px;
}
.at-lien:hover { color: var(--encre); }

/* ── Le menu Réglages, le surligneur et les cinq jeux de couleurs ─────────
   Demandé : « ranger Contrôles d'exécution, Exemples, Indenter, Partager,
   Commandes F1 dans un bouton réglage », « pouvoir surligner avec une
   couleur un truc qu'on sélectionne », et « changer la couleur du thème de
   la console et du compilateur […] j'en veux plusieurs sélectionnables ».

   La barre ne garde donc que ce qui sert PENDANT qu'on programme :
   Exécuter, le langage, les cinq pastilles de surlignage, Réglages,
   Agrandir. Le reste est à un clic, et n'encombre plus. */
.at-reglages-boite { position: relative; }
.at-menu {
  position: absolute; top: calc(100% + .35rem); right: 0; z-index: 40;
  min-width: 15rem; padding: .35rem; display: flex; flex-direction: column; gap: .15rem;
  background: var(--carte); border: 1px solid var(--filet); border-radius: 11px;
  box-shadow: 0 10px 28px rgba(0,0,0,.18);
}
.at-menu[hidden] { display: none; }
.at-menu-item {
  display: flex; align-items: center; gap: .5rem; width: 100%;
  min-height: 36px; padding: .3rem .55rem; text-align: left;
  background: none; border: 0; border-radius: 7px; cursor: pointer;
  font: inherit; font-size: .8182rem; color: var(--encre);
}
.at-menu-item:hover, .at-menu-item:focus-visible { background: var(--creuse); }
.at-menu-item kbd { margin-left: auto; }
.at-menu-titre {
  margin: .4rem .55rem .15rem; font-size: .7273rem; letter-spacing: .04em;
  text-transform: uppercase; color: var(--encre-douce);
}
.at-themes { display: flex; flex-wrap: wrap; gap: .25rem; padding: 0 .35rem .25rem; }
.at-themes button {
  min-height: 30px; padding: .2rem .5rem; cursor: pointer; font: inherit;
  font-size: .7727rem; color: var(--encre-douce);
  background: var(--creuse); border: 1px solid var(--filet); border-radius: 7px;
}
.at-themes button[aria-pressed="true"] {
  color: var(--encre); border-color: var(--accent); background: var(--carte);
}

/* Les pastilles de surlignage : des cibles de 34 px, comme tout le reste. */
.at-surligneur { display: flex; gap: .25rem; align-items: center; }
.at-couleur {
  width: 34px; height: 34px; padding: 0; cursor: pointer; border-radius: 9px;
  border: 1px solid var(--filet); font: inherit; font-size: .8182rem;
  color: var(--encre-douce); background: var(--creuse);
}
.at-couleur:hover, .at-couleur:focus-visible { border-color: var(--accent); }
.at-c-rouge  { background: #D63031; }
.at-c-ambre  { background: #D68C00; }
.at-c-vert   { background: #2EA043; }
.at-c-bleu   { background: #1F6FEB; }
.at-c-effacer { background: var(--creuse); }

/* ── Les cinq jeux de couleurs de l'éditeur et de la console ─────────────
   L'invariant « tout pre du site a le fond #23211E » (§ 23) vaut toujours
   pour les FICHES : il n'est levé qu'ici, dans l'atelier, et chaque jeu a
   été mesuré avant d'être écrit — la pire des onze teintes de code contre
   son fond, et les quatre surlignages contre ces mêmes teintes.

       nuit      fond #23211E   pire teinte 4,88
       ardoise   fond #1E2430   pire teinte 4,73
       encre     fond #14161A   pire teinte 5,50
       contraste fond #000000   pire teinte 6,38
       papier    fond #F4F1EC   pire teinte 4,78  (la palette d'impression) */

/* Papier inverse le fond : la palette d'écran y passerait sous le seuil.
   Ce sont les teintes déjà mesurées pour l'impression. */
#atelier[data-edi-theme="papier"] .j-com { color: #6E6A62; }
#atelier[data-edi-theme="papier"] .j-mc  { color: #A3246E; }
#atelier[data-edi-theme="papier"] .j-typ { color: #0B6E86; }
#atelier[data-edi-theme="papier"] .j-txt { color: #2F6B1E; }
#atelier[data-edi-theme="papier"] .j-num { color: #9A4A00; }
#atelier[data-edi-theme="papier"] .j-fn  { color: #1D4FA8; }
#atelier[data-edi-theme="papier"] .j-bal { color: #7A5A00; }
#atelier[data-edi-theme="papier"] .j-att { color: #0D6B57; }
#atelier[data-edi-theme="papier"] .j-var { color: #A32020; }
#atelier[data-edi-theme="papier"] .j-op  { color: #4A5560; }
#atelier[data-edi-theme="papier"] .j-pre { color: #6B3FA0; }

/* ── Le surlignage lui-même ──────────────────────────────────────────────
   Un fond OPAQUE, pas un voile : un voile se compose avec le fond du thème,
   et aucune opacité ne tenait le seuil sur les cinq à la fois — mesuré. */
.edi-surligne { border-radius: 3px; }
.edi-surligne-rouge { background: #4D1112; }
.edi-surligne-ambre { background: #362300; }
.edi-surligne-vert  { background: #0D2D13; }
.edi-surligne-bleu  { background: #0B2650; }
#atelier[data-edi-theme="papier"] .edi-surligne-rouge { background: #FAE8E8; }
#atelier[data-edi-theme="papier"] .edi-surligne-ambre { background: #F8EAD1; }
#atelier[data-edi-theme="papier"] .edi-surligne-vert  { background: #DEF0E1; }
#atelier[data-edi-theme="papier"] .edi-surligne-bleu  { background: #E2ECFC; }

@media (max-width: 760px) {
  .at-surligneur { order: 9; }
  .at-menu { right: auto; left: 0; }
}

/* ── La barre serrée : une seule rangée, et le badge seul ────────────────
   Écrite À LA FIN de la feuille, et c'est la moitié du correctif : la même
   règle placée plus haut ne s'appliquait pas — à spécificité égale, c'est la
   dernière qui gagne (§ 34), et une autre reprenait le rembourrage large.
   Mesuré : le rembourrage calculé restait à 13,2 px alors que la règle en
   demandait 8.

   Le compte, à 390 px : la rangée réclame 315 px de liens plus 7 écarts, le
   badge en prend 34 et la barre 26 de rembourrage — il manquait CINQ pixels.
   On les prend sur le rembourrage et les écarts, jamais sur les liens :
   « min-width/min-height: 34px » les tient au plancher tactile du banc,
   quoi qu'il arrive ensuite au reste de la feuille.

   Et le mot « BTS CIEL » disparaît pour de bon plutôt que de s'effilocher
   en « … » : un titre tronqué à deux lettres n'informe personne et occupe
   quand même sa place. Le badge, lui, reste — c'est l'identité du site. */
@media (max-width: 480px) {
  .app-marque .nom { display: none; }
  .app-tete { gap: .35rem; padding: .55rem .45rem; }
  .app-tete nav { gap: 2px; }
  .app-tete nav a,
  .app-tete nav button {
    min-width: 34px; min-height: 34px; padding: .38rem;
    justify-content: center;
  }
}

/* ── Le kit de survie ────────────────────────────────────────────────────
   Un guide tenu par la promotion, pas un cours : il a donc ses cartes à
   lui, plus aérées qu'un chapitre, et aucune couleur qui ne vienne du
   design system — ces blocs se lisent sur les 41 thèmes comme le reste. */
.kit-partie { margin-top: 2.4rem; }
.kit-partie > h2 {
  margin: 0 0 .9rem; font-size: 1.1818rem; color: var(--encre);
  padding-bottom: .5rem; border-bottom: 2px solid var(--accent-pale);
}
.kit-intro { margin: 0 0 .9rem; color: var(--encre-douce); }
.kit-carte {
  margin-top: .9rem; padding: 1rem 1.1rem;
  background: var(--carte); border: 1px solid var(--bord); border-radius: 13px;
}
.kit-carte h3 { margin: 0 0 .35rem; font-size: 1rem; color: var(--encre); }
.kit-carte ul { margin: .5rem 0 0; padding-left: 1.1rem; }
.kit-carte li { margin: .25rem 0; }
.kit-quoi { margin: 0; color: var(--encre-douce); }
.kit-os {
  margin-left: .4rem; padding: .1rem .45rem; border-radius: 999px;
  font-size: .7273rem; font-weight: 600; letter-spacing: .03em;
  color: var(--sur-accent); background: var(--accent-sombre);
}
.kit-lien { margin: .6rem 0 0; font-size: .8485rem; }
.kit-encart {
  margin-top: 1rem; padding: .9rem 1.1rem;
  background: var(--accent-pale); border-radius: 13px;
  border-left: 4px solid var(--accent-sombre);
}
.kit-encart h3 { margin: 0 0 .4rem; font-size: .9394rem; color: var(--encre); }
.kit-encart p { margin: .35rem 0 0; }
.kit-rap { margin: .7rem 0 0; font-size: .8485rem; color: var(--encre-douce); }
@media (max-width: 480px) {
  .kit-carte, .kit-encart { padding: .85rem .9rem; }
}


/* ── Le rail de section ──────────────────────────────────────────────────
   Repris de getartcraft.com : là-bas chaque chapitre porte sa barre
   collante, et elles se chassent l'une l'autre. Ici une seule barre dont
   le texte change — répéter trente-sept fois le titre dans le document
   l'alourdirait pour rien, et le ferait lire deux fois.

   Le fond reprend la recette de « .app-tete » : elle est déjà éprouvée sur
   les quarante thèmes, y compris ceux qui posent une image de fond, où un
   aplat opaque ferait une bande. */
.rail {
  position: sticky; top: 0; z-index: 30;
  display: flex; align-items: baseline; gap: .6rem;
  margin: 0 0 1.1rem; padding: .45rem .7rem;
  background: color-mix(in srgb, var(--papier) 88%, transparent);
  backdrop-filter: blur(14px) saturate(150%);
  -webkit-backdrop-filter: blur(14px) saturate(150%);
  border-bottom: 1px solid var(--bord); border-radius: 0 0 8px 8px;
  font-family: var(--mono); font-size: .7273rem; letter-spacing: .04em;
  color: var(--encre-douce); line-height: 1.5;
}
.rail[hidden] { display: none; }
.rail .r-num { font-weight: 700; color: var(--accent-sombre); flex: none; }
.rail .r-titre {
  flex: 1; min-width: 0; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; color: var(--encre);
}
/* « tabular-nums » : sans lui, le compteur saute d'un pixel à chaque
   changement de section — un mouvement qu'on ne regarde pas mais qu'on
   voit. */
.rail .r-tot { flex: none; font-variant-numeric: tabular-nums; }
@media print { .rail { display: none; } }


/* ── Curseurs de thème — engendré par publier.py ────────────
   Source : les jeux déposés dans Truc /Curseur/_zips/, convertis en
   PNG 32 px par _pilotage/scripts/curseurs.py. Un « .ani » ne peut
   pas servir de curseur en CSS et Safari ne lit pas les « .cur » :
   tout est ramené au PNG, seul format que tous les navigateurs
   acceptent. */
html[data-curseur="1"][data-theme="androide"] { cursor: url("curseurs/androide-defaut.png") 0 1, auto; }
html[data-curseur="1"][data-theme="androide"] :is(a,button,summary,label,select,[role="button"],.coche,.pastilles button) { cursor: url("curseurs/androide-lien.png") 0 1, pointer; }
html[data-curseur="1"][data-theme="androide"] :is(p,li,td,th,dd,blockquote,pre,code,input,textarea,h1,h2,h3,h4) { cursor: url("curseurs/androide-texte.png") 15 15, text; }
html[data-curseur="1"][data-theme="console-blanche"] { cursor: url("curseurs/console-blanche-defaut.png") 8 2, auto; }
html[data-curseur="1"][data-theme="console-blanche"] :is(a,button,summary,label,select,[role="button"],.coche,.pastilles button) { cursor: url("curseurs/console-blanche-lien.png") 8 2, pointer; }
html[data-curseur="1"][data-theme="console-blanche"] :is(p,li,td,th,dd,blockquote,pre,code,input,textarea,h1,h2,h3,h4) { cursor: url("curseurs/console-blanche-texte.png") 15 15, text; }
html[data-curseur="1"][data-theme="console-blanche"] :is(button:disabled,input:disabled,[aria-disabled="true"]) { cursor: url("curseurs/console-blanche-interdit.png") 7 2, not-allowed; }
html[data-curseur="1"][data-theme="console-blanche"] :is(a,button,summary,label,[role="button"],.coche):active { cursor: url("curseurs/console-blanche-actif.png") 9 11, pointer; }
html[data-curseur="1"][data-theme="determination"] { cursor: url("curseurs/determination-defaut.png") 0 0, auto; }
html[data-curseur="1"][data-theme="determination"] :is(a,button,summary,label,select,[role="button"],.coche,.pastilles button) { cursor: url("curseurs/determination-lien.png") 0 0, pointer; }
html[data-curseur="1"][data-theme="determination"] :is(p,li,td,th,dd,blockquote,pre,code,input,textarea,h1,h2,h3,h4) { cursor: url("curseurs/determination-texte.png") 5 9, text; }
html[data-curseur="1"][data-theme="determination"] :is(button:disabled,input:disabled,[aria-disabled="true"]) { cursor: url("curseurs/determination-interdit.png") 0 0, not-allowed; }
html[data-curseur="1"][data-theme="grand-large"] { cursor: url("curseurs/grand-large-defaut.png") 0 0, auto; }
html[data-curseur="1"][data-theme="grand-large"] :is(a,button,summary,label,select,[role="button"],.coche,.pastilles button) { cursor: url("curseurs/grand-large-lien.png") 1 1, pointer; }
html[data-curseur="1"][data-theme="grand-large"] :is(p,li,td,th,dd,blockquote,pre,code,input,textarea,h1,h2,h3,h4) { cursor: url("curseurs/grand-large-texte.png") 4 4, text; }
html[data-curseur="1"][data-theme="grand-large"] :is(button:disabled,input:disabled,[aria-disabled="true"]) { cursor: url("curseurs/grand-large-interdit.png") 7 7, not-allowed; }
html[data-curseur="1"][data-theme="velours"] { cursor: url("curseurs/velours-defaut.png") 3 2, auto; }
html[data-curseur="1"][data-theme="velours"] :is(a,button,summary,label,select,[role="button"],.coche,.pastilles button) { cursor: url("curseurs/velours-lien.png") 4 4, pointer; }
html[data-curseur="1"][data-theme="velours"] :is(p,li,td,th,dd,blockquote,pre,code,input,textarea,h1,h2,h3,h4) { cursor: url("curseurs/velours-texte.png") 16 16, text; }
html[data-curseur="1"][data-theme="velours"] :is(button:disabled,input:disabled,[aria-disabled="true"]) { cursor: url("curseurs/velours-interdit.png") 13 2, not-allowed; }
html[data-curseur="1"][data-theme="voxel"] { cursor: url("curseurs/voxel-defaut.png") 1 1, auto; }
html[data-curseur="1"][data-theme="voxel"] :is(a,button,summary,label,select,[role="button"],.coche,.pastilles button) { cursor: url("curseurs/voxel-lien.png") 1 1, pointer; }
html[data-curseur="1"][data-theme="voxel"] :is(p,li,td,th,dd,blockquote,pre,code,input,textarea,h1,h2,h3,h4) { cursor: url("curseurs/voxel-texte.png") 15 15, text; }
html[data-curseur="1"][data-theme="voxel"] :is(button:disabled,input:disabled,[aria-disabled="true"]) { cursor: url("curseurs/voxel-interdit.png") 15 15, not-allowed; }
