/* Composants des pages de contenu.
 *
 * Le langage visuel est celui de style.css : bordures de 2px a l'encre, ombres
 * dures sans flou, pastilles en monospace, cartes blanches sur papier creme.
 * Rien n'est invente ici — le monde est etendu, pas remplace.
 *
 * Difference assumee avec la source : toutes les tailles sont relatives, comme
 * l'exige la spec (§ 11). Le reglage « grande police » du systeme doit agir.
 *
 * Le contrat de direction demande des crans et des marques gravees : le rail de
 * progression les porte, et la bande du calcul les portera au plan suivant.
 */

/* ------------------------------------------------------------ Navigation */

/* La barre reste COLLANTE, y compris sur petit ecran ou elle prend deux lignes
   et 114 px de haut, soit 15 % d'un ecran de telephone en permanence. C'est un
   arbitrage rendu par l'utilisateur : l'alternative etait une barre qui defile
   avec la page, rendant la navigation absente pendant toute la lecture. Sur un
   site ou l'on va et vient entre une regle, la machine et les exercices, la
   navigation vaut ces pixels. Mesure : elle colle bien a 360, 414, 768, 1024 et
   1200 px, et aucun contenu ne lui passe par-dessus. */
.nav {
  position: sticky;
  top: 0;
  z-index: 60;
  background: rgba(239, 242, 236, 0.94);
  backdrop-filter: blur(8px);
  border-bottom: 2px solid var(--line);
}

/* Hauteur de la barre, declaree ici parce qu'elle en decoule : une ligne
   au-dessus du seuil, deux en dessous. Elle sert a compenser le defilement. */
:root {
  --barre: 4rem;
}

@media (max-width: 70rem) {
  :root {
    --barre: 7.25rem;
  }
}

/* La contrepartie d'une barre collante, qui manquait.

   Sans elle, tout ce que le navigateur amene en haut du cadre arrive DERRIERE la
   barre : une ancre suivie depuis un sommaire, et surtout la case courante que
   bande.js ramene dans le champ a chaque cran. On avancerait alors dans le
   calcul en regardant une case cachee. */
html {
  scroll-padding-top: calc(var(--barre) + var(--pas) * 2);
}

.nav-in {
  /* Plus large que la colonne de texte : la barre porte neuf elements, la
     colonne n'en porte qu'un. Les contraindre a la meme largeur coupait le
     dernier lien. */
  max-width: 78rem;
  margin: 0 auto;
  padding: calc(var(--pas) * 2) calc(var(--pas) * 5);
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: calc(var(--pas) * 1.5);
  align-items: center;
}

/* Seuls les liens de contenu defilent. L'etat de session, lui, reste toujours
   visible : le mettre dans la meme zone defilante faisait couper le dernier
   lien en deux sur un ecran large. */
.nav-liens {
  display: flex;
  gap: calc(var(--pas) * 1.5);
  align-items: center;
  overflow-x: auto;
  scrollbar-width: none;
  /* La barre de defilement est masquee juste en dessous, a dessein. Sans elle,
     rien ne disait qu'il restait des liens hors du cadre — et il en restait
     beaucoup : 708 px a 320 px de large, mesures au navigateur. Deux couvercles
     couleur papier, cales sur le CONTENU, recouvrent deux ombres calees sur le
     CADRE. Tant qu'on est au bord, le couvercle masque l'ombre ; des qu'on
     defile, il s'en va avec le contenu et l'ombre apparait — du seul cote ou il
     reste a lire. Aucun script ne mesure quoi que ce soit. */
  background:
    linear-gradient(to right, var(--paper) 45%, transparent) left center / 1.5rem 100% no-repeat,
    linear-gradient(to left, var(--paper) 45%, transparent) right center / 1.5rem 100% no-repeat,
    radial-gradient(farthest-side at 0 50%,
      color-mix(in srgb, var(--line) 26%, transparent), transparent)
      left center / 0.75rem 100% no-repeat,
    radial-gradient(farthest-side at 100% 50%,
      color-mix(in srgb, var(--line) 26%, transparent), transparent)
      right center / 0.75rem 100% no-repeat;
  background-attachment: local, local, scroll, scroll;
}

.nav-liens::-webkit-scrollbar {
  display: none;
}

.nav-etat {
  display: flex;
  gap: calc(var(--pas) * 1.5);
  align-items: center;
  white-space: nowrap;
}

.nav-marque {
  font-family: var(--display);
  font-weight: 800;
  font-size: var(--t-petit);
  margin-right: calc(var(--pas) * 2);
  white-space: nowrap;
  text-decoration: none;
  color: var(--ink);
  /* Elle mesurait 21 px de haut : c'est un lien de la barre, pas un mot dans
     une phrase, et il lui faut la cible tactile. La hauteur de ligne fait le
     centrage sans flex, qui aurait empeche l'ellipsis ci-dessous. */
  min-height: var(--cible);
  line-height: var(--cible);
  /* Dernier recours contre le debordement : l'etat de session s'elargit quand
     on est connecte, et la police du systeme peut etre agrandie. Plutot que de
     pousser hors du cadre, le nom se coupe. */
  overflow: hidden;
  text-overflow: ellipsis;
}

.nav a:not(.nav-marque) {
  font-family: var(--mono);
  font-size: var(--t-petit);
  text-decoration: none;
  color: var(--ink2);
  border: 1.5px solid transparent;
  border-radius: 99px;
  padding: calc(var(--pas) * 1.5) calc(var(--pas) * 2.5);
  white-space: nowrap;
  /* Cible tactile : la barre est le premier element touche sur mobile. */
  min-height: var(--cible);
  display: inline-flex;
  align-items: center;
}

.nav a:not(.nav-marque):hover,
.nav a:not(.nav-marque):focus-visible {
  border-color: var(--line);
  color: var(--ink);
  background: var(--card);
}

/* OU SUIS-JE. Le lien de la page courante garde en permanence le contour que
   les autres ne montrent qu au survol : sans lui, la barre ne dit pas ou l on
   est, et c est la premiere chose qu on y cherche.

   Il est plus marque que le survol — bordure a l encre, fond de carte, texte
   sombre — pour qu on le distingue du lien qu on est simplement en train de
   pointer. Sans cet ecart, deplacer la souris ferait clignoter deux reperes
   identiques et on ne saurait plus lequel dit la page.

   Le selecteur porte sur aria-current et non sur une classe : le meme attribut
   sert au lecteur d ecran, qui annonce « page actuelle ». Un seul marqueur pour
   les deux, donc aucun risque qu ils divergent. C est deja la convention du
   rail des onze regles. */
/* La marque du site, quand on est sur l accueil. Elle n a pas la forme d un
   bouton et n a pas a en prendre une : un souligne suffit a dire ou l on est,
   et la mettre en gras ne servirait a rien puisqu elle l est deja. */
.nav-marque[aria-current="page"] {
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 4px;
}

.nav a:not(.nav-marque)[aria-current="page"] {
  border-color: var(--ink2);
  color: var(--ink);
  background: var(--card);
  font-weight: 700;
}

/* Au survol du lien courant, rien ne bouge : il est deja a son maximum, et un
   changement donnerait a croire qu on peut aller ailleurs en cliquant. */
.nav a:not(.nav-marque)[aria-current="page"]:hover {
  border-color: var(--ink2);
}

/* Deux des trois colonnes de .nav-in ne cedent jamais : la marque et l'etat de
   session sont en nowrap et gardent leur largeur. A 320 px elles reclamaient
   330 px pour 320 disponibles — d'ou trois pixels de debordement de la page, et
   surtout une zone de liens ecrasee a une trentaine de pixels, ou l'on ne
   lisait qu'un fragment de mot.

   Sous le seuil, la barre prend deux lignes : la marque et l'etat gardent la
   premiere, les liens ont la seconde pour eux seuls et retrouvent toute la
   largeur. Le seuil n'est pas choisi, il est mesure : il faut 1101 px pour que
   les neuf liens tiennent sur une ligne, donc la barre coupait encore du
   contenu a 1024 px. 70rem couvre toute la plage ou elle coupait. */
@media (max-width: 70rem) {
  .nav-in {
    grid-template-columns: minmax(0, 1fr) auto;
    row-gap: calc(var(--pas) * 2);
  }

  .nav-liens {
    grid-row: 2;
    grid-column: 1 / -1;
  }

  /* Sans quoi un element de grille refuse de descendre sous la largeur de son
     contenu, et l'ellipsis de la marque ne se declenche jamais. */
  .nav-marque {
    min-width: 0;
  }
}

/* Sur les tres petites largeurs, le remplissage lateral de la barre coute plus
   qu'il ne rapporte : ces seize pixels sont du texte lisible en moins. */
@media (max-width: 30rem) {
  .nav-in {
    padding: calc(var(--pas) * 2) calc(var(--pas) * 3);
  }
}

/* ------------------------------------------------------------ Accueil */

.hero {
  padding: calc(var(--pas) * 10) 0 calc(var(--pas) * 6);
}

.eyebrow {
  font-family: var(--mono);
  font-size: var(--t-petit);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink2);
  margin: 0;
}

.hero h1 {
  font-weight: 800;
  margin: 0.18em 0 0.3em;
}

.lede {
  font-size: clamp(1.0625rem, 1rem + 0.4vw, 1.25rem);
  max-width: 62ch;
}

.entree {
  display: flex;
  flex-wrap: wrap;
  gap: calc(var(--pas) * 3);
  margin-top: calc(var(--pas) * 6);
}

.btn-premier,
.btn-second {
  font-family: var(--mono);
  font-size: var(--t-corps);
  font-weight: 700;
  text-decoration: none;
  border: 2px solid var(--line);
  border-radius: 9px;
  padding: calc(var(--pas) * 3) calc(var(--pas) * 5);
  box-shadow: var(--shadow-sm);
  min-height: var(--cible);
  display: inline-flex;
  align-items: center;
  transition: transform 0.08s, box-shadow 0.08s;
}

.btn-premier {
  background: var(--ink);
  color: var(--paper);
}

.btn-second {
  background: var(--card);
  color: var(--ink);
}

.btn-premier:hover,
.btn-second:hover,
.btn-premier:focus-visible,
.btn-second:focus-visible {
  transform: translate(1px, 1px);
  box-shadow: 2px 2px 0 var(--line);
}

@media (prefers-reduced-motion: reduce) {
  .btn-premier,
  .btn-second {
    transition: none;
  }
}

.carte {
  background: var(--card);
  border: 2px solid var(--line);
  border-radius: var(--r);
  box-shadow: var(--shadow);
  padding: calc(var(--pas) * 5) calc(var(--pas) * 6);
  margin: 0 0 calc(var(--pas) * 6);
}

.carte h2 {
  margin-top: 0;
}

/* Apercu des gestes : pastilles, comme les tags de la source. */
.gestes-apercu {
  list-style: none;
  padding: 0;
  margin: calc(var(--pas) * 4) 0 0;
  display: flex;
  flex-wrap: wrap;
  gap: calc(var(--pas) * 2);
}

.gestes-apercu a {
  font-family: var(--mono);
  font-size: var(--t-petit);
  border: 1.5px solid var(--line);
  border-radius: 99px;
  padding: calc(var(--pas) * 2) calc(var(--pas) * 3.5);
  background: var(--paper);
  text-decoration: none;
  color: var(--ink);
  min-height: var(--cible);
  display: inline-flex;
  align-items: center;
}

.gestes-apercu a:hover,
.gestes-apercu a:focus-visible {
  background: var(--card);
  box-shadow: var(--shadow-sm);
}

/* Apercu des regles : une ligne par regle, badge, titre, cout. */
.regles-apercu {
  list-style: none;
  padding: 0;
  margin: calc(var(--pas) * 4) 0 0;
  counter-reset: lecon;
}

.regles-apercu > li {
  counter-increment: lecon;
  border-top: 1.5px solid color-mix(in srgb, var(--line) 22%, transparent);
}

.regles-apercu > li:last-child {
  border-bottom: 1.5px solid color-mix(in srgb, var(--line) 22%, transparent);
}

.regles-apercu a {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: calc(var(--pas) * 4);
  padding: calc(var(--pas) * 3) calc(var(--pas) * 2);
  min-height: var(--cible);
  text-decoration: none;
  color: var(--ink);
}

.regles-apercu a:hover,
.regles-apercu a:focus-visible {
  background: var(--paper);
}

.ra-badge {
  font-family: var(--mono);
  font-weight: 700;
  font-size: var(--t-corps);
  border: 2px solid var(--line);
  border-radius: 8px;
  padding: calc(var(--pas)) calc(var(--pas) * 2);
  background: var(--paper);
  white-space: nowrap;
}

.ra-titre {
  font-family: var(--body);
}

.ra-cout {
  font-family: var(--mono);
  font-size: var(--t-petit);
  color: var(--ink2);
  white-space: nowrap;
}

@media (max-width: 34rem) {
  .regles-apercu a {
    grid-template-columns: auto 1fr;
  }

  .ra-cout {
    grid-column: 2;
  }
}

/* ------------------------------------------------------------ Page des gestes */

.intro {
  max-width: 62ch;
}

.gestes {
  list-style: none;
  padding: 0;
  margin: calc(var(--pas) * 6) 0 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
  gap: calc(var(--pas) * 4);
}

.gestes > li {
  background: var(--card);
  border: 2px solid var(--line);
  border-radius: var(--r);
  box-shadow: var(--shadow-sm);
  padding: calc(var(--pas) * 4) calc(var(--pas) * 5);
}

.gestes h2 {
  margin: 0 0 calc(var(--pas) * 2);
  font-size: var(--t-h3);
}

.gestes h2 a {
  text-decoration: none;
  color: var(--ink);
}

.gestes h2 a:hover,
.gestes h2 a:focus-visible {
  color: var(--chiffre);
}

.usages {
  font-family: var(--mono);
  font-size: var(--t-petit);
  color: var(--ink2);
  margin-bottom: 0;
}

/* ------------------------------------------------------------ Page d'une règle */

/* Le rail : une bande a crans. Chaque regle est un cran, celui ou l'on se
   trouve est marque par un cadre epais — une forme, jamais une couleur seule. */
.rail {
  border-bottom: 2px solid var(--line);
  margin: 0 0 calc(var(--pas) * 6);
  overflow-x: auto;
  scrollbar-width: none;
  /* Meme dispositif que la barre de navigation, meme raison : la barre de
     defilement est masquee et le rail cachait 195 px a 320 px de large. L'ombre
     n'apparait que du cote ou il reste des regles. */
  background:
    linear-gradient(to right, var(--paper) 45%, transparent) left center / 1.5rem 100% no-repeat,
    linear-gradient(to left, var(--paper) 45%, transparent) right center / 1.5rem 100% no-repeat,
    radial-gradient(farthest-side at 0 50%,
      color-mix(in srgb, var(--line) 26%, transparent), transparent)
      left center / 0.75rem 100% no-repeat,
    radial-gradient(farthest-side at 100% 50%,
      color-mix(in srgb, var(--line) 26%, transparent), transparent)
      right center / 0.75rem 100% no-repeat;
  background-attachment: local, local, scroll, scroll;
}

.rail::-webkit-scrollbar {
  display: none;
}

.rail ol {
  list-style: none;
  display: flex;
  gap: 0;
  padding: 0;
  margin: 0;
}

.rail li {
  border-right: 1.5px solid color-mix(in srgb, var(--line) 30%, transparent);
}

.rail li:first-child {
  border-left: 1.5px solid color-mix(in srgb, var(--line) 30%, transparent);
}

.rail a {
  font-family: var(--mono);
  font-size: var(--t-petit);
  text-decoration: none;
  color: var(--ink2);
  padding: calc(var(--pas) * 2.5) calc(var(--pas) * 3);
  min-height: var(--cible);
  /* Les onglets a un chiffre, de x2 a x9, mesuraient 40 px de large pour 44 de
     haut : la cible etait atteinte dans un sens seulement. Ce sont huit des
     onze regles. */
  min-width: var(--cible);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  white-space: nowrap;
}

.rail a:hover,
.rail a:focus-visible {
  background: var(--card);
  color: var(--ink);
}

.rail-ici a {
  font-weight: 700;
  color: var(--ink);
  background: var(--card);
  box-shadow: inset 0 -4px 0 var(--ink);
}

.accroche {
  font-size: clamp(1.0625rem, 1rem + 0.3vw, 1.1875rem);
  color: var(--ink2);
  max-width: 62ch;
}

/* La formule de gestes : la promesse centrale du site rendue visible. */
.formule {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: calc(var(--pas) * 2);
  margin: calc(var(--pas) * 5) 0;
  padding: calc(var(--pas) * 4);
  background: var(--card);
  border: 2px solid var(--line);
  border-radius: var(--r);
  box-shadow: var(--shadow-sm);
}

.badge-geste {
  font-family: var(--mono);
  font-size: var(--t-petit);
  font-weight: 700;
  text-decoration: none;
  color: var(--ink);
  border: 2px solid var(--line);
  border-radius: 8px;
  padding: calc(var(--pas) * 2) calc(var(--pas) * 3);
  background: var(--paper);
  min-height: var(--cible);
  display: inline-flex;
  align-items: center;
}

.badge-geste:hover,
.badge-geste:focus-visible {
  background: var(--chiffre-bg);
  border-color: var(--chiffre);
  color: var(--chiffre);
}

.formule-plus {
  font-family: var(--mono);
  font-weight: 700;
  color: var(--ink3);
}

.recette {
  max-width: 62ch;
  padding-left: calc(var(--pas) * 6);
}

.recette li {
  margin-bottom: calc(var(--pas) * 2);
}

.bande {
  background: var(--card);
  border: 2px solid var(--line);
  border-radius: var(--r);
  box-shadow: var(--shadow);
  padding: calc(var(--pas) * 5);
  margin: calc(var(--pas) * 4) 0;
  min-height: 6rem;
}

.sans-js {
  font-family: var(--mono);
  font-size: var(--t-petit);
  color: var(--ink2);
  margin: 0;
}

/* Encadre complet, comme .box.why et .box.warn de la source : la couleur est
   portee par toute la bordure. Une bordure laterale epaisse est un motif que le
   detecteur signale a juste titre, et le monde etabli ne l'emploie nulle part. */
.pourquoi {
  max-width: 66ch;
  padding: calc(var(--pas) * 4) calc(var(--pas) * 5);
  background: var(--voisin-bg);
  border: 2px solid var(--voisin);
  border-radius: 12px;
}

.piege {
  max-width: 66ch;
  padding: calc(var(--pas) * 4) calc(var(--pas) * 5);
  background: var(--retenue-bg);
  border: 2px solid var(--retenue);
  border-radius: 12px;
}

.suite {
  margin-top: calc(var(--pas) * 8);
  padding-top: calc(var(--pas) * 4);
  border-top: 2px solid var(--line);
  font-family: var(--mono);
}

/* ------------------------------------------------------------ Fiche d'un geste */

.fil {
  font-family: var(--mono);
  font-size: var(--t-petit);
  margin: 0 0 calc(var(--pas) * 4);
}

.correspondances {
  list-style: none;
  padding: 0;
  margin: calc(var(--pas) * 4) 0 0;
}

.correspondances li {
  display: flex;
  align-items: center;
  gap: calc(var(--pas) * 4);
  padding: calc(var(--pas) * 2) 0;
  border-top: 1.5px solid color-mix(in srgb, var(--line) 22%, transparent);
}

.correspondances li:last-child {
  border-bottom: 1.5px solid color-mix(in srgb, var(--line) 22%, transparent);
}

.correspondances a {
  font-family: var(--mono);
  font-weight: 700;
  text-decoration: none;
  color: var(--ink);
  border: 2px solid var(--line);
  border-radius: 8px;
  padding: calc(var(--pas)) calc(var(--pas) * 2.5);
  background: var(--paper);
  min-height: var(--cible);
  display: inline-flex;
  align-items: center;
  white-space: nowrap;
}

.corr-titre {
  color: var(--ink2);
}

/* ------------------------------------------------------------ États du site */

.deja-la {
  max-width: 62ch;
}

.deja-la li {
  margin-bottom: calc(var(--pas) * 2);
}

/* ------------------------------------------------------------ Impression */

@media print {
  .nav,
  .rail,
  .suite,
  .annonce,
  .degrade {
    display: none !important;
  }

  /* Les ombres et les fonds colores ne survivent pas a la photocopie :
     seules les bordures portent l'information sur papier. */
  .carte,
  .formule,
  .bande,
  .gestes > li {
    box-shadow: none;
    border: 1.5px solid #000;
  }

  .pourquoi,
  .piege {
    background: transparent;
    border: 1.5px solid #000;
  }

  a {
    color: #000;
  }
}

/* ------------------------------------------------------------ Formule, cohésion */

/* Le signe « + » voyage avec le badge qui le suit : sans cela, une formule a
   cinq gestes laissait un « + » orphelin en fin de ligne. */
.formule-terme {
  display: inline-flex;
  align-items: center;
  gap: calc(var(--pas) * 2);
}

/* ------------------------------------------------------------ Pied de page */

.pied {
  border-top: 2px solid var(--line);
  margin-top: calc(var(--pas) * 12);
  background: var(--card);
}

.pied-in {
  max-width: 62rem;
  margin: 0 auto;
  padding: calc(var(--pas) * 6) calc(var(--pas) * 5);
}

.pied nav {
  display: flex;
  flex-wrap: wrap;
  gap: calc(var(--pas) * 2);
  margin-bottom: calc(var(--pas) * 4);
}

.pied nav a {
  font-family: var(--mono);
  font-size: var(--t-petit);
  text-decoration: none;
  color: var(--ink2);
  border: 1.5px solid var(--line);
  border-radius: 99px;
  padding: calc(var(--pas) * 1.5) calc(var(--pas) * 3);
  min-height: var(--cible);
  display: inline-flex;
  align-items: center;
}

.pied nav a:hover,
.pied nav a:focus-visible {
  color: var(--ink);
  background: var(--paper);
}

.pied p {
  font-size: var(--t-petit);
  color: var(--ink3);
  margin: 0;
  max-width: 62ch;
}

@media print {
  .pied nav {
    display: none;
  }

  .pied {
    background: transparent;
    border-top: 1.5px solid #000;
  }
}

/* ------------------------------------------------------------ Formulaires */

.formulaire {
  max-width: 34rem;
  margin: calc(var(--pas) * 6) 0;
}

/* Les pages de l'espace — mon profil, l'espace, l'administration — sont des
   pages de contenu dont le corps se trouve etre un formulaire. Leur colonne
   suit donc celle du texte, et non la largeur d'une boite de connexion : un
   cadre de 34rem au milieu d'une page de 62rem se lit comme un decrochage, pas
   comme une intention, d'autant que le titre et les liens de bas de page, eux,
   prennent la pleine largeur.
   Les formulaires courts d'authentification gardent 34rem : pour deux champs,
   une boite etroite est un choix juste, et l'etirer ferait traverser toute la
   page a l'oeil entre l'etiquette et la saisie.
   Les champs ne s'etirent pas pour autant : ils sont bornes ailleurs a 24rem,
   et a 10rem pour les nombres. Ce sont les cadres qui s'alignent, pas les
   saisies. */
.formulaire.formulaire-espace {
  max-width: 62rem;
}

.formulaire fieldset {
  border: 2px solid var(--line);
  border-radius: var(--r);
  background: var(--card);
  padding: calc(var(--pas) * 4) calc(var(--pas) * 5);
  margin: 0 0 calc(var(--pas) * 5);
}

.formulaire legend {
  font-family: var(--display);
  font-weight: 700;
  padding: 0 calc(var(--pas) * 2);
}

.champ {
  margin: 0 0 calc(var(--pas) * 5);
}

.champ label {
  display: block;
  font-weight: 700;
  margin-bottom: calc(var(--pas) * 1.5);
}

.champ small {
  display: block;
  margin-top: calc(var(--pas) * 1.5);
  font-size: var(--t-petit);
  color: var(--ink2);
  max-width: 52ch;
}

.facultatif {
  font-family: var(--mono);
  font-size: var(--t-petit);
  font-weight: 400;
  color: var(--ink3);
}

input[type="text"],
input[type="password"],
input[type="number"],
input[type="email"],
select {
  font-family: var(--body);
  font-size: var(--t-corps);
  width: 100%;
  max-width: 24rem;
  min-height: var(--cible);
  padding: calc(var(--pas) * 2) calc(var(--pas) * 3);
  border: 2px solid var(--line);
  border-radius: 8px;
  background: var(--paper);
  color: var(--ink);
}

/* Les nombres et les codes en chiffres tabulaires : c'est le sujet du site. */
input[type="number"],
input[inputmode="numeric"] {
  font-family: var(--mono);
  max-width: 10rem;
}

button {
  font-family: var(--mono);
  font-size: var(--t-corps);
  cursor: pointer;
}

/* Choix de type d'espace : des cartes cliquables, pas des puces serrées. */
.choix {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: calc(var(--pas) * 2) calc(var(--pas) * 3);
  align-items: center;
  padding: calc(var(--pas) * 3);
  border: 2px solid transparent;
  border-radius: 8px;
  min-height: var(--cible);
  cursor: pointer;
}

.choix:hover {
  background: var(--paper);
}

.choix:has(input:checked) {
  border-color: var(--line);
  background: var(--paper);
}

.choix input {
  min-width: 1.25rem;
  min-height: 1.25rem;
}

.choix small {
  grid-column: 2;
  font-family: var(--mono);
  font-size: var(--t-petit);
  color: var(--ink2);
}

/* ------------------------------------------------------------ Qui es-tu ? */

.qui {
  list-style: none;
  padding: 0;
  margin: calc(var(--pas) * 6) 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
  gap: calc(var(--pas) * 4);
}

/* Cibles larges : un enfant de six ans doit cliquer la sienne sans aide. */
.qui-carte {
  width: 100%;
  min-height: 7rem;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: calc(var(--pas));
  padding: calc(var(--pas) * 4);
  background: var(--card);
  border: 2px solid var(--line);
  border-radius: var(--r);
  box-shadow: var(--shadow-sm);
  color: var(--ink);
  transition: transform 0.08s, box-shadow 0.08s;
}

.qui-carte:hover,
.qui-carte:focus-visible {
  transform: translate(1px, 1px);
  box-shadow: 2px 2px 0 var(--line);
}

@media (prefers-reduced-motion: reduce) {
  .qui-carte {
    transition: none;
  }
}

.qui-prenom {
  font-family: var(--display);
  font-size: var(--t-h3);
  font-weight: 700;
}

.qui-role {
  font-family: var(--mono);
  font-size: var(--t-petit);
  color: var(--ink2);
}

.qui-code {
  display: block;
  margin-bottom: calc(var(--pas) * 2);
}

.qui-serie {
  font-family: var(--mono);
  font-size: var(--t-petit);
  color: var(--ink2);
}

.qui-verrou {
  font-size: var(--t-petit);
}

.qui-protege {
  font-size: var(--t-petit);
  color: var(--ink2);
}

.qui-oubli {
  font-size: var(--t-petit);
  color: var(--ink2);
  border-top: 1px solid var(--line);
  padding-top: calc(var(--pas) * 2);
  margin-top: calc(var(--pas) * 2);
}

/* ------------------------------------------------------------ Liste des profils */

.liste-profils {
  list-style: none;
  padding: 0;
  margin: calc(var(--pas) * 4) 0;
}

.liste-profils li {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: calc(var(--pas) * 3);
  padding: calc(var(--pas) * 3) 0;
  border-top: 1.5px solid color-mix(in srgb, var(--line) 22%, transparent);
}

.liste-profils li:last-child {
  border-bottom: 1.5px solid color-mix(in srgb, var(--line) 22%, transparent);
}

.lp-prenom {
  font-weight: 700;
  min-width: 8rem;
}

.lp-role,
.lp-age,
.lp-verrou {
  font-family: var(--mono);
  font-size: var(--t-petit);
  color: var(--ink2);
}

/* Le role se lit comme une etiquette, l'age comme une donnee : les coller dans
   le meme gris (defaut 18 de l'audit) faisait lire « parent, 9 ans » d'un bloc.
   --trait n'existe pas dans ce depot (verifie sur assets/css/*.css) : --line est
   la variable de bordure reellement employee, deja vue sur .ra-badge. */
.lp-role {
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 0 .5em;
}

.lp-verrou {
  color: var(--retenue);
}

.lp-action {
  margin-left: auto;
}

/* Cette classe habille un <button> ET un <a> : « Supprimer » est un bouton de
   formulaire, « Modifier » est un lien vers une page, et les deux sont voisins
   dans la liste des profils. Ils doivent donc se ressembler.
   Les trois dernieres declarations sont ce qui manquait au lien. Sans elles il
   gardait son soulignement, heritait de la police du corps de texte — la regle
   generique button donnait le mono a son voisin, pas a lui — et son min-height
   restait sans effet, un element en ligne ne prenant pas de hauteur. Il se
   lisait comme un lien souligne dans un cadre, pas comme un bouton. */
.btn-discret {
  background: transparent;
  border: 1.5px solid var(--ink3);
  border-radius: 99px;
  color: var(--ink2);
  font-family: var(--mono);
  font-size: var(--t-petit);
  min-height: var(--cible);
  padding: 0 calc(var(--pas) * 4);
  display: inline-flex;
  align-items: center;
  text-decoration: none;
}

.btn-discret:hover,
.btn-discret:focus-visible {
  border-color: var(--chiffre);
  color: var(--chiffre);
}

/* ------------------------------------------------------------ Message d'action */

.message {
  max-width: 62rem;
  margin: calc(var(--pas) * 4) auto 0;
  padding: calc(var(--pas) * 3) calc(var(--pas) * 5);
  border: 2px solid var(--line);
  border-radius: 8px;
  background: var(--card);
}

.message-erreur {
  background: var(--chiffre-bg);
  border-color: var(--chiffre);
  color: var(--chiffre);
}

/* Alerte en surimpression de l'ecran des voix (tache 5) : eprouver un moteur
   ou ecouter un essai en ajax pose ce toast au lieu de recharger la page et
   de faire perdre le defilement. Meme gabarit visuel que .message ci-dessus,
   position: fixed pour rester a l'ecran quel que soit le defilement. z-index
   au-dessus du plus haut du fichier, .nav-panneau a 70 : un toast qui
   apparaitrait sous le panneau du menu serait illisible. */
.toast {
  position: fixed;
  left: 50%;
  bottom: calc(var(--pas) * 4);
  transform: translateX(-50%);
  z-index: 80;
  max-width: 34rem;
  margin: 0;
  padding: calc(var(--pas) * 3) calc(var(--pas) * 5);
  border: 2px solid var(--line);
  border-radius: 8px;
  background: var(--card);
  box-shadow: var(--shadow-sm);
}

.toast-erreur {
  background: var(--chiffre-bg);
  border-color: var(--chiffre);
  color: var(--chiffre);
}

.nav-espace {
  font-family: var(--mono);
  font-size: var(--t-petit);
  font-weight: 700;
  white-space: nowrap;
}

@media print {
  .formulaire,
  .message,
  .lp-action {
    display: none;
  }
}

/* ------------------------------------------------------------ Administration */

.alerte {
  border: 2px solid var(--chiffre);
  background: var(--chiffre-bg);
  border-radius: var(--r);
  padding: calc(var(--pas) * 4) calc(var(--pas) * 5);
  margin: calc(var(--pas) * 5) 0;
  max-width: 62ch;
}

.alerte h2 {
  margin-top: 0;
  color: var(--chiffre);
  font-size: var(--t-h3);
}

.alerte p:last-child {
  margin-bottom: 0;
}

/* Trace SMTP : elle doit défiler dans son cadre, jamais élargir la page. */
.trace {
  font-family: var(--mono);
  font-size: var(--t-petit);
  line-height: 1.5;
  background: var(--card);
  border: 2px solid var(--line);
  border-radius: 8px;
  padding: calc(var(--pas) * 4);
  max-height: 22rem;
  overflow: auto;
  white-space: pre-wrap;
  word-break: break-word;
}

.etat {
  list-style: none;
  padding: 0;
  font-family: var(--mono);
  font-size: var(--t-petit);
}

.etat li {
  padding: calc(var(--pas) * 1.5) 0;
  border-top: 1.5px solid color-mix(in srgb, var(--line) 22%, transparent);
}

/* Pastilles d'etat des moteurs (tache 7) : un rond de la taille du texte,
   purement decoratif (aria-hidden cote HTML) — le detail textuel juste a
   cote porte toujours l'information, la couleur ne la porte jamais seule. */
.pastille {
  display: inline-block;
  width: 0.75em;
  height: 0.75em;
  border-radius: 50%;
  border: 1.5px solid var(--line);
  margin-right: var(--pas);
  vertical-align: middle;
}

/* --resultat / --resultat-bg est le SEUL vert du site (voir tokens.css,
   pense pour le resultat d'un exercice) : on etend ici son usage au succes
   d'une epreuve de connexion — meme couleur, meme sens, "ca a marche". */
.pastille-ok {
  background: var(--resultat-bg);
  border-color: var(--resultat);
}

.pastille-echec {
  background: var(--chiffre-bg);
  border-color: var(--chiffre);
}

/* Etat transitoire pendant la sequence "Tout eprouver" : ni succes ni echec
   encore constate, une pastille neutre plutot qu'une couleur qui mentirait
   le temps d'une reponse. */
.pastille-neutre {
  background: var(--card);
}

/* ------------------------------------------------------------ Avatars */

.avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  border-radius: 14px;
  background: var(--card);
  object-fit: cover;
}

/* Barre de navigation : 30 px au plus, jamais davantage. Le min() garde
   l'échelle relative en deçà — l'avatar suit donc le réglage de police du
   système jusqu'à cette limite, puis plafonne. */
.avatar-mini {
  width: min(1.75rem, 30px);
  height: min(1.75rem, 30px);
  border-radius: 7px;
}

.avatar-normal {
  width: 3rem;
  height: 3rem;
}

.avatar-grand {
  width: 4.5rem;
  height: 4.5rem;
  border-radius: 18px;
}

/* Sans image, l'initiale : une case vide serait moins reconnaissable qu'une
   lettre, et c'est la reconnaissance qui compte sur « Qui es-tu ? ». */
.avatar-lettre {
  font-family: var(--display);
  font-weight: 800;
  color: var(--ink);
  border: 3px solid var(--line);
  background: var(--paper);
}

.avatar-mini.avatar-lettre {
  font-size: 0.875rem;
  border-width: 2px;
}

.avatar-normal.avatar-lettre {
  font-size: 1.375rem;
}

.avatar-grand.avatar-lettre {
  font-size: 2rem;
}

/* ------------------------------------------------- Menu de l'utilisateur */

/* La barre ne garde que l'image et le prenom ; tout le reste est dans le
   panneau. Cette section est en nowrap et ne cede jamais : quand elle portait
   quatre elements, elle ecrasait la zone des liens de contenu. */
.nav-menu {
  position: relative;
}

.nav-moi {
  display: inline-flex;
  align-items: center;
  gap: calc(var(--pas) * 2);
  text-decoration: none;
  color: var(--ink);
  /* La cible tactile, comme les autres commandes de la barre. */
  min-height: var(--cible);
  padding: 0 calc(var(--pas) * 2);
  border: 1.5px solid transparent;
  border-radius: 99px;
  cursor: pointer;
  /* Le triangle par defaut du navigateur est remplace par le chevron ci-dessous,
     qui suit l'etat du menu et s'accorde au reste. */
  list-style: none;
}

.nav-moi::-webkit-details-marker {
  display: none;
}

/* Un chevron dessine, et non un caractere : il tourne quand le menu s'ouvre, ce
   qui dit l'etat sans le nommer. */
.nav-moi::after {
  content: '';
  width: 0.4rem;
  height: 0.4rem;
  border-right: 2px solid var(--ink2);
  border-bottom: 2px solid var(--ink2);
  transform: rotate(45deg) translateY(-0.1rem);
  transition: transform 120ms ease;
}

.nav-menu[open] > .nav-moi::after {
  transform: rotate(-135deg) translateY(-0.1rem);
}

.nav-moi:hover,
.nav-menu[open] > .nav-moi,
.nav-moi:focus-visible {
  border-color: var(--line);
  background: var(--card);
}

.nav-panneau {
  position: absolute;
  top: calc(100% + var(--pas));
  right: 0;
  z-index: 70;
  min-width: 14rem;
  display: flex;
  flex-direction: column;
  background: var(--card);
  border: 2px solid var(--line);
  border-radius: var(--r);
  box-shadow: var(--shadow-sm);
  padding: calc(var(--pas) * 2);
}

/* Qui l'on est, et sous quel role : utile, mais pas au point d'occuper la barre
   en permanence. */
.np-qui {
  margin: 0 0 calc(var(--pas) * 2);
  padding: 0 calc(var(--pas) * 2) calc(var(--pas) * 2);
  border-bottom: 1.5px solid color-mix(in srgb, var(--line) 25%, transparent);
  font-family: var(--display);
  font-weight: 700;
  font-size: var(--t-petit);
  display: flex;
  flex-direction: column;
  gap: calc(var(--pas) * 0.5);
}

.np-role {
  font-family: var(--mono);
  font-weight: 400;
  color: var(--ink3);
}

/* Les entrees du menu retrouvent une mise en page de liste : dans la barre,
   elles heritaient de la pilule des liens de navigation. */
.nav .nav-panneau a,
.nav-panneau button {
  display: flex;
  align-items: center;
  min-height: var(--cible);
  padding: 0 calc(var(--pas) * 2);
  border: 0;
  border-radius: calc(var(--r) / 2);
  background: none;
  font-family: var(--mono);
  font-size: var(--t-petit);
  color: var(--ink2);
  text-decoration: none;
  text-align: left;
  white-space: nowrap;
  cursor: pointer;
}

.nav .nav-panneau a:hover,
.nav .nav-panneau a:focus-visible,
.nav-panneau button:hover,
.nav-panneau button:focus-visible {
  background: var(--paper);
  color: var(--ink);
}

.np-sortie {
  margin: calc(var(--pas) * 2) 0 0;
  padding: calc(var(--pas) * 2) 0 0;
  border-top: 1.5px solid color-mix(in srgb, var(--line) 25%, transparent);
}

.np-sortie button {
  width: 100%;
  color: var(--chiffre);
}

/* Sous le seuil, la barre passe sur deux lignes et la section utilisateur se
   retrouve pres du bord droit : le panneau ancre a droite y reste dans le cadre,
   ce qu'un panneau ancre a gauche ne ferait pas. */
@media (max-width: 30rem) {
  .nav-panneau {
    min-width: 12rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  .nav-moi::after {
    transition: none;
  }
}

/* Galerie de choix : la vignette occupe toute la case.
   Depuis que les figures n'ont plus de legende, la hauteur que le texte
   occupait ne sert plus a rien. Une image de 3rem perdue au milieu d'une case
   de 6rem se choisissait mal, et pour une main de six ans la cible compte
   autant que le dessin. */
.galerie {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(6rem, 1fr));
  gap: calc(var(--pas) * 3);
  margin: calc(var(--pas) * 4) 0;
}

/* C'est la CASE qui est carree, et non l'image : la vignette « Mon initiale »
   porte une legende sous sa lettre, et si le carre etait porte par l'image
   cette case-la depasserait, rendant la premiere rangee plus haute que les
   autres. Ici la legende prend sa part de la hauteur, la figure prend le
   reste, et toutes les cases restent alignees.
   overflow cache : c'est le cadre arrondi de la case qui rogne l'image, ce qui
   evite d'avoir a accorder deux rayons entre eux. */
.galerie-item {
  position: relative;
  display: flex;
  flex-direction: column;
  aspect-ratio: 1;
  padding: 0;
  border: 3px solid transparent;
  border-radius: var(--r);
  overflow: hidden;
  cursor: pointer;
}

/* display bloc, et non le inline-flex par defaut de la vignette : un element
   en ligne se pose sur la ligne de base et laisse sous lui la place du
   jambage, un lisere clair de quelques pixels sous chaque image. */
.galerie-item .avatar {
  display: flex;
  flex: 1 1 auto;
  width: 100%;
  height: auto;
  min-height: 0;
  border-radius: 0;
}

.galerie-item:hover {
  border-color: var(--line);
}

/* Le choix se marque par un cadre colore et non par un fond : sous une image
   pleine case, un changement de fond ne se verrait pas. */
.galerie-item:has(input:checked) {
  border-color: var(--chiffre);
  box-shadow: var(--shadow-sm);
}

.galerie-item input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
}

/* Le focus doit rester visible : la case radio est masquée, pas absente. */
.galerie-item:has(input:focus-visible) {
  outline: 3px solid var(--chiffre);
  outline-offset: 3px;
}

/* Une seule case de la galerie garde une legende : « Mon initiale ». Les seize
   figures s'en passent — l'enfant reconnait un renard — mais une lettre ne se
   devine pas. Elle prend sa part de la hauteur de la case, en bas. */
.galerie-nom {
  flex: none;
  padding: calc(var(--pas) * 1) calc(var(--pas) * 1);
  background: var(--card);
  font-family: var(--mono);
  font-size: var(--t-petit);
  line-height: 1.15;
  color: var(--ink2);
  text-align: center;
}

/* La lettre occupe maintenant presque toute la case : a 1.375rem elle y
   flotterait. La bordure part, celle de la case la remplace. */
.galerie-item .avatar-lettre {
  font-size: 2.25rem;
  border: 0;
}

.apercu-avatar {
  display: flex;
  align-items: center;
  gap: calc(var(--pas) * 3);
  font-family: var(--mono);
  font-size: var(--t-petit);
  color: var(--ink2);
}

input[type="file"] {
  font-family: var(--mono);
  font-size: var(--t-petit);
  max-width: 100%;
}

/* ------------------------------------------------------------ La machine */

/* Les trois commandes tiennent sur une ligne des qu'il y a la place : la
   saisie, le multiplicateur et le bouton forment un seul geste, et les separer
   sur trois lignes eloignerait le bouton de ce qu'il declenche. En dessous,
   elles s'empilent d'elles-memes. */
.machine-saisie {
  max-width: 46rem;
  display: flex;
  flex-wrap: wrap;
  gap: calc(var(--pas) * 4);
  align-items: flex-end;
}

.machine-saisie .champ {
  margin: 0;
}

/* Le nombre prend la place restante, le multiplicateur juste la sienne : c'est
   le nombre que l'on relit et corrige, pas la liste. */
.machine-saisie .champ:first-child {
  flex: 1 1 12rem;
}

.machine-saisie input[type="text"] {
  font-family: var(--mono);
  /* Les chiffres saisis sont lus un a un, comme ceux de la bande. */
  letter-spacing: 0.08em;
}

/* Le formulaire est en flex : sans cela le message se glisserait a cote du
   bouton au lieu de prendre sa propre ligne sous le champ qu'il concerne. */
.machine-saisie .machine-alerte {
  flex: 1 1 100%;
  margin: 0;
}

/* Meme forme que .message du gabarit — bordure pleine de 2 px et rayon de 8 px —
   avec les couleurs de la retenue, exactement comme .message-erreur reprend
   cette forme avec celles du chiffre. Une bordure laterale epaisse aurait fait
   une troisieme forme de message dans un monde visuel qui n'en a que deux. */
.machine-alerte {
  margin: 0;
  padding: calc(var(--pas) * 2) calc(var(--pas) * 3);
  border: 2px solid var(--retenue);
  border-radius: 8px;
  background: var(--retenue-bg);
  color: var(--ink);
  font-size: var(--t-petit);
  max-width: 46rem;
}

/* hidden ne suffit pas : un element en flex ou en grid le contredit. Ici le
   parent est en flux normal, mais la regle protege contre un changement de
   contexte ulterieur. */
.machine-alerte[hidden],
.machine-saisie .machine-alerte[hidden] {
  display: none;
}

.machine-vers-regle {
  margin: calc(var(--pas) * 5) 0 0;
  font-family: var(--mono);
  font-size: var(--t-petit);
}

/* ============================================================== EXERCICES
   La feuille vit a l'ecran ET sur le papier. Les deux rendus partagent la
   meme structure : ce qui disparait a l'impression porte no-print, ce qui
   n'apparait qu'a l'impression porte print-seul. Rien n'est invente ici,
   le monde est etendu, pas remplace. */

.exo-reglages {
  display: flex;
  flex-wrap: wrap;
  gap: calc(var(--pas) * 4);
  align-items: flex-end;
}

.exo-anonyme {
  border-bottom: 2px solid var(--voisin);
  padding: calc(var(--pas) * 2) 0;
  margin: calc(var(--pas) * 4) 0;
}

/* Compteur explicite, et non le marqueur natif de la liste : display:flex sur
   un li supprime son ::marker, et la feuille imprimee se corrige a haute voix
   — « numero trois » — donc elle DOIT etre numerotee. Constate a l'ecran, les
   dix lignes s'affichaient sans aucun numero. */
.exo-liste {
  counter-reset: exo;
  list-style: none;
  margin: calc(var(--pas) * 6) 0;
  padding-left: 0;
}

.exo-item::before {
  counter-increment: exo;
  content: counter(exo) ".";
  font-family: var(--mono);
  font-size: var(--t-petit);
  color: var(--ink2);
  min-width: 2.25ch;
  text-align: right;
}

.exo-item {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: calc(var(--pas) * 2);
  /* Cible tactile large : un enfant de six ans vise mal, et la ligne entiere
     doit rester confortable au doigt. */
  min-height: var(--cible);
  padding: var(--pas) 0;
}

.exo-enonce {
  font-family: var(--mono);
  font-size: var(--t-corps);
}

.exo-nombre { font-weight: 700; }
.exo-signe,
.exo-egal { color: var(--ink2); }

.exo-saisie {
  font-family: var(--mono);
  font-size: var(--t-corps);
  width: 7rem;
  min-height: var(--cible);
  padding: var(--pas) calc(var(--pas) * 2);
  border: 2px solid var(--line);
  border-radius: 9px;
  background: var(--card);
  color: var(--ink);
}

/* Le verdict porte d'abord une FORME — coche ou croix — puis une couleur, et
   son aria-label porte le mot. Retirer la couleur n'enleve rien : la feuille
   finit photocopiee. */
.exo-verdict {
  font-weight: 700;
  min-width: 1.5rem;
}

.exo-juste .exo-verdict { color: var(--resultat); }
.exo-faux .exo-verdict { color: var(--chiffre); }
.exo-faux .exo-saisie { border-style: dashed; }

.exo-attendu {
  font-family: var(--mono);
  font-size: var(--t-corps);
  font-weight: 700;
  color: var(--resultat);
}

.exo-actions {
  display: flex;
  gap: calc(var(--pas) * 4);
  flex-wrap: wrap;
  margin-top: calc(var(--pas) * 6);
}

.exo-entete { margin-bottom: calc(var(--pas) * 6); }

.exo-trait {
  display: inline-block;
  width: 12rem;
  border-bottom: 1px solid var(--line);
}

.print-seul { display: none; }

@media print {
  /* La feuille distribuee ne porte que la feuille : ni navigation, ni pied de
     page, ni boutons, ni reponses. */
  .no-print,
  .accroche,
  .exo-anonyme {
    display: none !important;
  }

  .print-seul { display: block; }

  .exo-saisie {
    border: none;
    border-bottom: 1px solid #000;
    border-radius: 0;
    box-shadow: none;
  }

  .exo-item { break-inside: avoid; }
}

/* =============================================================== CONTROLE */

.controle-limite {
  border-bottom: 2px solid var(--chiffre);
  padding: calc(var(--pas) * 2) 0;
  margin: calc(var(--pas) * 6) 0;
}

.controle-exemple {
  font-family: var(--mono);
  font-size: var(--t-petit);
}

.controle-verdict {
  display: flex;
  align-items: baseline;
  gap: calc(var(--pas) * 3);
  flex-wrap: wrap;
  margin-top: calc(var(--pas) * 4);
  padding: calc(var(--pas) * 3) calc(var(--pas) * 4);
  border: 2px solid var(--line);
  border-radius: 9px;
  background: var(--card);
}

/* La marque de forme d'abord, la couleur ensuite : en photocopie, seule la
   forme survit. Le trait plein et le trait tirete distinguent les deux etats
   meme sans elle. */
.controle-passe { border-style: solid; }
.controle-echoue { border-style: dashed; }

.controle-marque { font-weight: 700; }
.controle-passe .controle-marque { color: var(--resultat); }
.controle-echoue .controle-marque { color: var(--chiffre); }

/* LE BILAN DE FIN DE SERIE : ni un succes ni un echec, une LECON.
   Donc ni le trait plein du verdict qui passe, ni le trait tirete de celui qui
   echoue : une barre laterale, la forme qu'aucun des deux etats n'emploie. En
   photocopie elle se distingue encore, comme le reste de cette page. */
.controle-bilan {
  margin-top: calc(var(--pas) * 6);
  padding: calc(var(--pas) * 3) calc(var(--pas) * 4);
  border-left: 4px solid var(--ink2);
  background: var(--card);
}

.controle-bilan-amorce { font-weight: 700; }

/* Les deux lignes piegees sont de la DONNEE, pas du texte : meme fonte que les
   autres nombres de la page, et pas de puce — elles se lisent comme un releve. */
.controle-bilan-lignes {
  list-style: none;
  padding: 0;
  margin: calc(var(--pas) * 3) 0;
  font-family: var(--mono);
  font-size: var(--t-petit);
}

.controle-bilan-lignes li { margin: calc(var(--pas) * 2) 0; }

.controle-bilan-lecon { margin-bottom: 0; }

.controle-detail {
  font-family: var(--mono);
  font-size: var(--t-petit);
  color: var(--ink2);
}

/* Meme raison que la liste d'exercices : le marqueur natif disparait sous
   display:flex. */
.controle-liste {
  counter-reset: ctrl;
  list-style: none;
  margin: calc(var(--pas) * 5) 0;
  padding-left: 0;
}

.controle-ligne::before {
  counter-increment: ctrl;
  content: counter(ctrl) ".";
  font-family: var(--mono);
  font-size: var(--t-petit);
  color: var(--ink2);
  min-width: 2.25ch;
  text-align: right;
}

.controle-ligne {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: calc(var(--pas) * 3);
  min-height: var(--cible);
  padding: var(--pas) 0;
}

.controle-enonce {
  font-family: var(--mono);
  font-size: var(--t-corps);
}

.controle-choix {
  display: flex;
  gap: calc(var(--pas) * 2);
  flex-wrap: wrap;
}

.controle-retour { font-weight: 700; }

@media print {
  /* On imprime la recette et la limite ; le testeur et l'entrainement n'ont
     aucun sens sur du papier. */
  .controle-jeu,
  .controle-testeur {
    display: none;
  }
}

/* ============================================================ AIDE-MEMOIRE
   La page qu'on decoupe et qu'on punaise : elle doit rester lisible en noir
   et blanc, et tenir sur une feuille. */

.memo-defilant {
  /* Douze lignes de formules ne tiennent pas sur 360 px : la table defile
     dans son propre conteneur plutot que de pousser la page entiere. */
  overflow-x: auto;
  margin: calc(var(--pas) * 6) 0;
}

.memo {
  border-collapse: collapse;
  width: 100%;
  font-size: var(--t-petit);
}

.memo th,
.memo td {
  border: 1px solid var(--line);
  padding: calc(var(--pas) * 2) calc(var(--pas) * 3);
  text-align: left;
  vertical-align: top;
}

.memo thead th {
  font-family: var(--display);
  background: var(--card);
}

.memo-m {
  font-family: var(--mono);
  font-weight: 700;
  text-align: center;
  white-space: nowrap;
}

.memo tbody td { font-family: var(--mono); }

.memo-notes {
  margin: calc(var(--pas) * 6) 0;
  border-bottom: 2px solid var(--voisin);
  padding-bottom: calc(var(--pas) * 3);
}

.memo-actions { margin-top: calc(var(--pas) * 6); }

@media print {
  /* La fiche est faite pour etre decoupee : elle tient sur une page, sans
     conteneur defilant qui couperait une colonne a l'impression. */
  .memo-defilant { overflow: visible; }
  .memo { font-size: 10pt; }
  .memo tr { break-inside: avoid; }
}

/* ================================================================ RITUEL */

.rituel-etapes {
  margin: calc(var(--pas) * 5) 0;
  padding-left: calc(var(--pas) * 6);
}

.rituel-etapes li { margin-bottom: calc(var(--pas) * 3); }

.rituel-or {
  border: 2px solid var(--line);
  border-radius: 9px;
  background: var(--card);
  padding: calc(var(--pas) * 4);
  margin: calc(var(--pas) * 6) 0;
}

.rituel-or h3 { margin-top: 0; }

/* Six semaines, chacune une carte. Pas de grille a colonnes fixes : une
   progression se lit dans l'ordre, et deux colonnes invitent a lire de
   travers. */
.semaines {
  list-style: none;
  counter-reset: semaine;
  padding-left: 0;
  margin: calc(var(--pas) * 5) 0;
  position: relative;
}

/* Le fil de la frise, porte par la LISTE et non par chaque semaine.
   Une bordure epaisse repetee sur six elements aurait donne six cartes a
   onglet lateral — un motif que ce projet a deja refuse ailleurs. Ici le trait
   est ce qu'il pretend etre : une ligne continue qui relie les six crans, et
   sur laquelle les pastilles numerotees viennent se poser. Fin et a l'encre
   attenuee : c'est un support, pas un accent. */
.semaines::before {
  content: "";
  position: absolute;
  left: 0;
  top: calc(var(--pas) * 4);
  bottom: calc(var(--pas) * 6);
  width: 1px;
  background: color-mix(in srgb, var(--line) 28%, transparent);
}

.semaine {
  padding: calc(var(--pas) * 2) 0 calc(var(--pas) * 4) calc(var(--pas) * 5);
  margin-bottom: calc(var(--pas) * 5);
  position: relative;
}

.semaine h3 { margin: 0 0 calc(var(--pas) * 2); }

/* Le numero de semaine est porte par le cran lui-meme : c'est la marque
   gravee du contrat de direction, pas une puce decorative. */
.semaine::before {
  counter-increment: semaine;
  content: counter(semaine);
  position: absolute;
  left: calc(var(--pas) * -3);
  top: calc(var(--pas) * 2);
  width: calc(var(--pas) * 6);
  height: calc(var(--pas) * 6);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--mono);
  font-weight: 700;
  font-size: var(--t-petit);
  background: var(--paper);
  border: 2px solid var(--line);
  border-radius: 99px;
}

.semaine-regles {
  display: flex;
  flex-wrap: wrap;
  gap: calc(var(--pas) * 2);
  align-items: center;
  margin: 0 0 calc(var(--pas) * 2);
}

.semaine-badge {
  font-family: var(--mono);
  font-weight: 700;
  text-decoration: none;
  color: var(--ink);
  border: 2px solid var(--line);
  border-radius: 9px;
  padding: calc(var(--pas)) calc(var(--pas) * 2.5);
  min-height: var(--cible);
  display: inline-flex;
  align-items: center;
  background: var(--card);
}

.semaine-badge:hover,
.semaine-badge:focus-visible {
  background: var(--ink);
  color: var(--paper);
}

.semaine-gestes {
  font-family: var(--mono);
  font-size: var(--t-petit);
  color: var(--ink2);
}

.rituel-limites {
  border-bottom: 2px solid var(--voisin);
  padding-bottom: calc(var(--pas) * 3);
  margin-top: calc(var(--pas) * 8);
}

@media print {
  .semaine { break-inside: avoid; }
}

/* ================================================================== JEUX
   Public de six ans : cibles larges, une question par ligne, un verdict
   immediat et court. */

.jeu {
  border: 2px solid var(--line);
  border-radius: var(--r);
  background: var(--card);
  padding: calc(var(--pas) * 5);
  margin-bottom: calc(var(--pas) * 6);
}

.jeu h2 {
  display: flex;
  align-items: center;
  gap: calc(var(--pas) * 3);
  margin-top: 0;
}

.jeu-numero {
  font-family: var(--mono);
  font-size: var(--t-petit);
  width: calc(var(--pas) * 7);
  height: calc(var(--pas) * 7);
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 2px solid var(--line);
  border-radius: 99px;
}

.jeu-consigne { color: var(--ink2); }

.jeu-questions {
  list-style: none;
  padding-left: 0;
  margin: calc(var(--pas) * 4) 0 0;
}

.jeu-question {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: calc(var(--pas) * 3);
  padding: calc(var(--pas) * 2) 0;
  border-top: 1px solid color-mix(in srgb, var(--line) 20%, transparent);
}

.jeu-enonce {
  font-family: var(--mono);
  font-size: 1.15em;
  font-weight: 700;
  min-width: 6ch;
}

/* Le chiffre vise porte un encadre plein, comme la case courante de la bande :
   c'est la meme marque pour la meme idee — « c'est celui-ci qu'on traite ». */
.jeu-chiffre {
  display: inline-block;
  padding: 0 calc(var(--pas));
}

.jeu-vise {
  border: 2px solid var(--chiffre);
  border-radius: 6px;
  color: var(--chiffre);
}

.jeu-choix {
  display: flex;
  flex-wrap: wrap;
  gap: calc(var(--pas) * 2);
}

/* Cible elargie au-dela du minimum usuel : PRODUCT.md l'exige pour les jeunes
   enfants, et c'est ici que le public est le plus jeune. */
.jeu-choix button {
  min-height: 3.25rem;
  min-width: 3.25rem;
  justify-content: center;
}

.jeu-choisi-juste {
  background: var(--resultat);
  color: var(--paper);
  border-color: var(--resultat);
}

.jeu-choisi-faux {
  background: var(--chiffre-bg);
  border-style: dashed;
}

.jeu-retour {
  font-family: var(--mono);
  font-weight: 700;
}

.jeu-juste .jeu-retour { color: var(--resultat); }
.jeu-faux .jeu-retour { color: var(--chiffre); }

.jeux-repere {
  border-bottom: 2px solid var(--voisin);
  padding-bottom: calc(var(--pas) * 3);
  margin-top: calc(var(--pas) * 8);
}

@media print {
  /* Les jeux ne s'impriment pas : ils n'existent que joues. */
  .jeux { display: none; }
}

/* ============================================================ AIDE VOCALE
   Le bouton n'existe dans le HTML que si son enregistrement a ete depose :
   c'est le PHP qui tranche, pas ce fichier. Ce qui suit ne decrit donc qu'un
   bouton qu'on sait present. */

.son {
  /* Aligne sur la ligne de base du titre qu'il accompagne, sans le pousser :
     il vient APRES le texte, comme une note, et ne doit jamais devenir le
     premier element que l'oeil rencontre. */
  margin-left: calc(var(--pas) * 2);
  vertical-align: middle;

  /* Cible elargie au-dela du minimum usuel. PRODUCT.md l'exige pour les jeunes
     enfants, et ce bouton n'existe justement que pour eux. */
  min-width: 2.75rem;
  min-height: 2.75rem;

  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;

  border: 2px solid var(--line);
  border-radius: 99px;
  background: var(--card);
  color: var(--ink);
  cursor: pointer;
  transition: transform 0.08s, box-shadow 0.08s;
}

.son-marque {
  /* Le triangle de lecture, en taille fixe : il ne suit pas l'echelle du titre,
     sans quoi le bouton d'un h1 ecraserait celui d'un h2. */
  font-size: 1rem;
  line-height: 1;
}

.son:hover,
.son:focus-visible {
  background: var(--ink);
  color: var(--paper);
}

/* En lecture : le bouton s'enfonce et s'inverse. La forme change autant que la
   couleur — un enfant daltonien doit voir lequel parle. */
.son-joue {
  background: var(--ink);
  color: var(--paper);
  box-shadow: inset 2px 2px 0 color-mix(in srgb, var(--paper) 30%, transparent);
}

@media (prefers-reduced-motion: reduce) {
  .son { transition: none; }
}

@media print {
  /* Un bouton d'ecoute sur du papier ne veut rien dire. */
  .son { display: none; }
}

/* Le bouton d'ecoute de la colonne se pose dans le flux de l'explication,
   apres elle, et non en surimpression : la bande est deja dense, et un
   pictogramme flottant y devient un obstacle plutot qu'une aide. */
.son-colonne {
    margin-top: 0.5rem;
}

/* ============================================================ Accueil, lot B2a

   Les couches de l'accueil, la table des onze decompositions et l'addition posee.
   ============================================================================ */

.couche {
  margin: calc(var(--pas) * 8) 0;
}

.couche h2 {
  margin-bottom: calc(var(--pas) * 3);
}

.couche p {
  margin: 0 0 calc(var(--pas) * 3);
}

/* L'ADDITION POSEE.

   Un tableau, et non un bloc preformate : l'alignement des colonnes est la seule
   chose que cette figure doit garantir — c'est lui qui rend visible que chaque
   colonne porte un chiffre et son voisin de droite. Un <pre> a espaces
   dependrait d'une police a chasse fixe et se casserait au zoom.

   Elle est aria-hidden : la phrase du corpus, juste apres, dit ce qu'elle
   montre. */
.pose {
  border-collapse: collapse;
  margin: calc(var(--pas) * 4) 0;
  font-family: var(--mono);
  font-size: var(--t-grand, 1.4rem);
  font-variant-numeric: tabular-nums;
}

.pose td {
  width: 2ch;
  padding: calc(var(--pas)) calc(var(--pas) * 1.5);
  text-align: center;
}

.pose-signe {
  width: 1.5ch;
  color: var(--ink3);
}

/* PAS DE BARRE. Une addition posee porte sa barre SOUS le dernier operande, juste
   avant le total — jamais entre les deux operandes, ou elle se lit comme un
   trait de separation. Et cette figure n'affiche pas de total : le mettre
   reviendrait a donner le resultat avant que la page ne l'ait explique.
   La matiere n'en met pas non plus. Un premier essai posait un border-top sur la
   seconde ligne, ce qui dessinait exactement la barre fautive — et cela ne s'est
   vu qu'en ouvrant la page. */
.pose-somme td {
  padding-top: calc(var(--pas) * 1.5);
}

/* LA TABLE DES ONZE DECOMPOSITIONS.

   Onze lignes de trois colonnes tiennent sur un ecran de bureau, pas sur un
   telephone. Le defilement est celui du BLOC, jamais celui de la page : une page
   qui defile horizontalement fait perdre la colonne de texte. */
.table-defilante {
  overflow-x: auto;
  margin: calc(var(--pas) * 4) 0;
}

.decompositions {
  border-collapse: collapse;
  width: 100%;
  min-width: 32rem;
  font-size: var(--t-petit);
}

.decompositions th,
.decompositions td {
  padding: calc(var(--pas) * 2);
  text-align: left;
  border-bottom: 1px solid var(--line);
}

.decompositions th {
  font-family: var(--mono);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink2);
  border-bottom-width: 2px;
}

/* La colonne des regles, en chasse fixe : « x10 » et « x3 » doivent s'aligner
   pour se lire comme une liste, pas comme une phrase. */
.decompositions td:first-child {
  font-family: var(--mono);
  font-weight: 700;
  white-space: nowrap;
}


/* ============================================================ Histoire

   La vie de Jakow Trachtenberg : le recit en sections, la carte du parcours
   (partiel SVG, sans fond de carte) et l'encart pour l'adulte, petit seul.
   ============================================================================ */

/* Le portrait flotte a droite et le recit coule autour de lui — c'est la
   demande de l'auteur. Sur un ecran etroit il garde le flottement mais cede la
   place au texte : 42 % de la colonne, jamais plus de 300 px. */
.histoire-portrait {
  float: right;
  width: min(300px, 42%);
  height: auto;
  margin: calc(var(--pas) * 2) 0 calc(var(--pas) * 4) calc(var(--pas) * 5);
  border: 2px solid var(--line);
  border-radius: 9px;
  box-shadow: var(--shadow-sm);
}

.histoire-part {
  margin: calc(var(--pas) * 8) 0;
}

.histoire-part h2 {
  margin-bottom: calc(var(--pas) * 3);
}

/* Pas de max-width ici, et c'est une demande de l'auteur (2026-09-03) : les
   lignes a hauteur du portrait le contournent, puis le texte reprend TOUTE la
   largeur disponible des qu'il passe sous la photo. */
.histoire-part p {
  margin: 0 0 calc(var(--pas) * 3);
}

/* En petit, le recit est ecrit en phrases courtes a lire a voix haute : les
   lignes se suivent comme des vers, pas comme des paragraphes. */
body[data-registre="petit"] .histoire-part p {
  margin-bottom: calc(var(--pas) * 1.5);
}

/* L'encart pour l'adulte : un cadre a part du recit, meme facture que la regle
   d'or du rituel. */
.histoire-encart {
  border: 2px solid var(--line);
  border-radius: 9px;
  background: var(--card);
  padding: calc(var(--pas) * 4);
  margin: calc(var(--pas) * 8) 0;
}

.histoire-encart h2 {
  margin-top: 0;
  font-size: var(--t-h3);
}

.histoire-encart p {
  margin: 0;
  max-width: 62ch;
}

/* La carte du parcours. Le SVG garde ses proportions et ne depasse jamais la
   colonne de lecture : la page ne defile pas horizontalement. */
.histoire-carte {
  margin: calc(var(--pas) * 8) 0;
}

.histoire-carte svg {
  display: block;
  width: 100%;
  max-width: 620px;
  height: auto;
  margin: calc(var(--pas) * 4) auto 0;
}

.hc-route {
  fill: none;
  stroke: var(--voisin);
  stroke-width: 3;
  stroke-linejoin: round;
  stroke-linecap: round;
  opacity: 0.75;
}

.hc-ville { fill: var(--ink); }

/* Le depart et l'arrivee, en couleur d'accent : c'est le sens de la ligne. */
.hc-bord { fill: var(--chiffre); }

.hc-nom {
  font-family: var(--body);
  font-size: 22px;
  fill: var(--ink);
}
