/* =========================================================================
   ColorLearn — css/app.css
   Composants ajoutés à la v1 : pied de page global, modal de génération,
   skeletons, panneau de configuration (wizard), filtres du sommaire,
   bibliothèque, tableau de bord, notifications.

   Règle absolue : tout ce qui est ici est de l'INTERFACE. Rien de tout cela
   ne s'imprime (bloc @media print en fin de fichier).
   ========================================================================= */

/* ---------- Utilitaires ---------- */

/* L'attribut `hidden` doit gagner. Sans cela, toute classe portant un
   `display` (.pile, .setup__grille…) le neutralise silencieusement — et un
   bloc censé être masqué, comme le champ de clé en mode serveur, reste
   affiché. */
[hidden] {
  display: none !important;
}

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

/* Le lien d'évitement : invisible tant qu'il n'a pas le focus, puis
   franchement visible. On le sort de l'écran plutôt que de le masquer
   avec `display:none`, qui le retirerait aussi de l'ordre de tabulation
   et le rendrait donc parfaitement inutile. */
.lien-evitement {
  position: fixed;
  top: 0;
  left: 50%;
  transform: translate(-50%, -120%);
  z-index: 1000;
  padding: 10px 22px;
  border: 3px solid var(--encre);
  border-top: 0;
  border-radius: 0 0 14px 14px;
  background: var(--papier);
  color: var(--encre);
  font: 800 15px/1 var(--police-texte);
  text-decoration: none;
  transition: transform 140ms ease-out;
}

.lien-evitement:focus {
  transform: translate(-50%, 0);
}

/* La cible du saut ne doit jamais afficher de contour au clic — seul le
   parcours clavier a besoin du repère. */
main:focus {
  outline: none;
}

main:focus-visible {
  outline: 3px solid #1a73e8;
  outline-offset: 4px;
}

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

.pile {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}

/* =========================================================================
   1. PIED DE PAGE GLOBAL (E1 · US1.1)
   ========================================================================= */
.pied-global {
  max-width: 210mm;
  margin: 28px auto 40px;
  padding: 18px 20px 20px;
  background: var(--papier);
  border: var(--trait-fin) solid var(--encre);
  border-radius: var(--rayon);
  box-shadow: 0 2px 14px rgb(0 0 0 / 0.1);
  font-size: 13px;
}

.pied-global__haut {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px 18px;
  padding-bottom: 10px;
  margin-bottom: 10px;
  border-bottom: 2px dashed var(--encre);
}

.pied-global__marque {
  margin: 0;
  font-family: var(--police-titre);
  font-size: 19px;
  text-transform: uppercase;
  letter-spacing: 0.02em;
}

.pied-global__marque span {
  display: block;
  font-family: var(--police-texte);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.pied-global nav {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 20px;
}

.pied-global a {
  color: var(--encre);
  font-weight: 700;
  text-decoration: none;
  padding-bottom: 2px;
}

.pied-global__bas {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px 16px;
  font-size: 12px;
}

.pied-global__bas p {
  margin: 0;
  max-width: 62ch;
}

.selecteur-langue {
  display: flex;
  gap: 6px;
  align-items: center;
}

.selecteur-langue > span {
  font-weight: 800;
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

/* =========================================================================
   2. MODAL DE GÉNÉRATION (E1 · US1.2)
   ========================================================================= */
.modal-gen {
  width: min(560px, calc(100vw - 32px));
  padding: 0;
  border: var(--trait-epais) solid var(--encre);
  border-radius: var(--rayon);
  background: var(--papier);
  color: var(--encre);
}

.modal-gen::backdrop {
  background: rgb(0 0 0 / 0.55);
}

.modal-gen__corps {
  padding: 18px 20px 20px;
}

.modal-gen h2 {
  margin: 0 0 2px;
  font-family: var(--police-titre);
  font-size: 21px;
  text-transform: uppercase;
}

.modal-gen__sous {
  margin: 0 0 14px;
  font-size: 13px;
}

.modal-gen__ligne {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-bottom: 12px;
}

/* Vignette de la dernière image produite */
.modal-gen__vignette {
  flex: none;
  width: 88px;
  height: 88px;
  border: var(--trait-fin) dashed var(--encre);
  border-radius: 8px;
  overflow: hidden;
  display: grid;
  place-items: center;
  background: var(--papier);
}

.modal-gen__vignette img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: grayscale(1) contrast(1.15);
}

.modal-gen__vignette--pleine {
  border-style: solid;
}

.modal-gen__infos {
  flex: 1;
  min-width: 0;
}

.modal-gen__cadre {
  margin: 0 0 6px;
  font-weight: 800;
  font-size: 14px;
  overflow-wrap: anywhere;
}

/* Barre de progression n/N, dessinée à l'encre */
.modal-gen__barre {
  height: 16px;
  border: var(--trait-fin) solid var(--encre);
  border-radius: 999px;
  overflow: hidden;
  background: var(--papier);
}

.modal-gen__barre i {
  display: block;
  height: 100%;
  width: 0%;
  background-image: repeating-linear-gradient(
    45deg,
    var(--encre) 0 3px,
    transparent 3px 7px
  );
  border-right: 2px solid var(--encre);
  transition: width 220ms var(--crayon-courbe, ease);
}

.modal-gen__compte {
  margin: 6px 0 0;
  font-size: 12.5px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.modal-gen__erreur {
  margin: 0 0 12px;
  padding: 8px 12px;
  border: var(--trait-fin) solid var(--encre);
  border-left-width: 6px;
  border-radius: 8px;
  font-size: 13px;
  font-weight: 700;
}

.modal-gen__erreur[hidden] {
  display: none;
}

.modal-gen__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: flex-end;
}

.modal-gen .btn {
  border-color: var(--encre);
}

.modal-gen .btn--ghost {
  color: var(--encre);
}

/* =========================================================================
   3. SKELETONS (E1 · US1.3) — shimmer noir & blanc, zéro layout shift
   ========================================================================= */
.image-coloriage.est-en-attente .image-coloriage__zone,
.skeleton {
  position: relative;
  overflow: hidden;
  background: repeating-linear-gradient(
    45deg,
    rgb(0 0 0 / 0.045) 0 6px,
    transparent 6px 12px
  );
}

.image-coloriage.est-en-attente .image-coloriage__zone::after,
.skeleton::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    100deg,
    transparent 24%,
    rgb(0 0 0 / 0.09) 46%,
    rgb(0 0 0 / 0.09) 54%,
    transparent 76%
  );
  transform: translateX(-100%);
  animation: chatoiement 1.5s ease-in-out infinite;
}

@keyframes chatoiement {
  to { transform: translateX(100%); }
}

/* La zone garde son ratio : l'image remplace le skeleton sans décalage. */
.image-coloriage__img {
  animation: apparition 140ms ease-out;
}

@keyframes apparition {
  from { opacity: 0; }
  to { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .image-coloriage.est-en-attente .image-coloriage__zone::after,
  .skeleton::after {
    animation: none;
    opacity: 0.5;
    transform: none;
  }
  .image-coloriage__img {
    animation: none;
  }
}

/* =========================================================================
   4. PANNEAU DE CONFIGURATION — le « setup » devient un wizard (E2)
   ========================================================================= */
.setup {
  max-width: 210mm;
  /* La barre d'outils est fixe : on dégage sa hauteur réelle, mesurée par
     js/ui.js dans --toolbar-hauteur (elle change en s'empilant sur mobile). */
  margin: calc(var(--toolbar-hauteur, 44px) + 22px) auto 18px;
  padding: 16px 20px 18px;
  background: var(--papier);
  border: var(--trait-epais) solid var(--encre);
  border-radius: var(--rayon);
  box-shadow: 0 4px 24px rgb(0 0 0 / 0.14);
}

/* La feuille garde ses 72 px de dégagement quand elle est seule sous la
   barre d'outils ; le panneau les a déjà pris, on resserre.
   @media screen est INDISPENSABLE : ce sélecteur (0-2-0) l'emporte sinon sur
   le `.feuille { margin: 0 }` (0-1-0) de styles.css et repousse le contenu
   d'une page à l'impression. */
@media screen {
  .setup + .feuille {
    margin-top: 26px;
  }
}

/* Sur fond blanc, un bouton « fantôme » doit s'écrire à l'encre : hérité
   de la v1, où .btn--ghost vit sur le noir de la barre d'outils. */
.setup .btn--ghost,
.modal-gen .btn--ghost,
.biblio .btn--ghost,
.pied-global .btn--ghost {
  color: var(--encre);
  border-color: var(--encre);
}

.setup__entete {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px 16px;
  margin-bottom: 10px;
}

.setup h2 {
  margin: 0;
  font-family: var(--police-titre);
  font-size: 20px;
  text-transform: uppercase;
}

.setup__intro {
  margin: 0 0 12px;
  font-size: 13.5px;
  max-width: 78ch;
}

/* ---------- Le champ unique : « écris, l'IA fait le reste » ---------- */
.setup__demande {
  display: flex;
  gap: 10px;
  align-items: stretch;
  margin-bottom: 6px;
}

.setup__demande input {
  flex: 1;
  min-width: 0;
  font: 700 17px/1.2 var(--police-texte);
  padding: 14px 20px;
  border: var(--trait-epais) solid var(--encre);
  border-radius: 999px;
  background: var(--papier);
  color: var(--encre);
}

.setup__demande input::placeholder {
  font-weight: 400;
  font-style: italic;
  opacity: 0.55;
}

.setup__demande input:focus-visible {
  outline: 3px solid #1a73e8;
  outline-offset: 2px;
}

.setup__go {
  flex: none;
  font: 800 15px/1 var(--police-texte);
  padding: 0 26px;
  border: var(--trait-epais) solid var(--encre);
  border-radius: 999px;
  background: var(--encre);
  color: var(--papier);
  cursor: pointer;
  white-space: nowrap;
}

.setup__go:hover {
  transform: translateY(-1px);
}

.setup__aide {
  margin: 0 0 8px;
  padding-left: 20px;
  font-size: 12.5px;
  font-style: italic;
  opacity: 0.75;
}

.setup__secondaire {
  margin: 0 0 4px;
  padding-left: 18px;
}

/* La ligne de statut ne réserve de la place que lorsqu'elle a quelque
   chose à dire — sinon elle creuse un vide au bas du panneau. */
.setup .panneau-ia__statut:empty {
  display: none;
}

/* ---------- Le reste, replié ---------- */
.setup__avance {
  margin-top: 12px;
  padding-top: 10px;
  border-top: 2px dashed var(--encre);
}

.setup__avance > summary {
  font-weight: 800;
  font-size: 13px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  cursor: pointer;
  padding: 4px 0;
}

.setup__avance > summary:focus-visible {
  outline: 3px solid #1a73e8;
  outline-offset: 3px;
}

.setup__avance[open] > summary {
  margin-bottom: 10px;
}

@media (max-width: 560px) {
  .setup__demande {
    flex-direction: column;
  }
  .setup__go {
    padding: 14px 26px;
  }
}

.setup__grille {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 10px 14px;
  margin-bottom: 12px;
}

.setup__champ {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}

.setup__champ > span {
  font-weight: 800;
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.setup__champ input,
.setup__champ select {
  font: 700 14px/1.2 var(--police-texte);
  padding: 9px 12px;
  border: 2px solid var(--encre);
  border-radius: 999px;
  background: var(--papier);
  color: var(--encre);
  min-width: 0;
}

.setup__champ input:focus-visible,
.setup__champ select:focus-visible {
  outline: 3px solid #1a73e8;
  outline-offset: 2px;
}

.setup__champ--case {
  flex-direction: row;
  align-items: center;
  gap: 8px;
}

.setup__champ--case input {
  width: 20px;
  height: 20px;
  flex: none;
  accent-color: var(--encre);
}

.setup__prereglages {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  padding-top: 10px;
  margin-top: 4px;
  border-top: 2px dashed var(--encre);
}

.setup__prereglages > span {
  font-weight: 800;
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.setup__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  margin-top: 12px;
}

.setup__actions .btn {
  border-color: var(--encre);
}

.setup__actions .btn--ghost {
  color: var(--encre);
}

.setup__note {
  margin: 8px 0 0;
  font-size: 11.5px;
  font-style: italic;
}

.setup__graine {
  font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
  font-weight: 700;
  letter-spacing: 0.04em;
}

/* Squelette de fiche affiché avant qu'une notion ait été choisie (E2 · US2.1).
   On n'estompe QUE les zones réellement en attente : la planche de
   référence et l'en-tête, eux, sont utilisables tout de suite — les
   griser laisserait croire que la page ne sert à rien sans clé API. */
.fiche-en-attente #gen-cartes,
.fiche-en-attente #gen-seconde {
  opacity: 0.5;
}

.fiche-en-attente #gen-cartes::after {
  content: attr(data-attente);
  display: block;
  grid-column: 1 / -1;
  padding: 10px;
  border: var(--trait-fin) dashed var(--encre);
  border-radius: var(--rayon);
  text-align: center;
  font-weight: 800;
  font-size: 13px;
}

@media print {
  /* Sur le papier, une fiche vierge s'assume : elle se remplit au crayon. */
  .fiche-en-attente #gen-cartes,
  .fiche-en-attente #gen-seconde {
    opacity: 1;
  }
  .fiche-en-attente #gen-cartes::after {
    display: none;
  }
}

/* -------------------------------------------------------------------------
   UNE PAGE DE MATIÈRE EST UNE CATÉGORIE, PAS UNE FICHE

   Elle montrait le squelette d'une fiche vierge — six cadres d'images
   vides, une planche, un bouton « Imprimer la fiche » — avant même qu'on
   ait choisi un sujet. On croyait être tombé sur une fiche ratée.

   Tant qu'aucun sujet n'est choisi, le squelette n'est pas affiché : il
   n'a rien à montrer. Il réapparaît entier dès que le modèle a écrit
   quelque chose — script.js retire alors « fiche-en-attente », et la
   page redevient la fiche qu'on est venu chercher.
   ------------------------------------------------------------------------- */
body[data-categorie].fiche-en-attente .entete__identite,
body[data-categorie].fiche-en-attente #gen-cartes,
body[data-categorie].fiche-en-attente #gen-seconde,
body[data-categorie].fiche-en-attente .planche,
body[data-categorie].fiche-en-attente .feuille > .pied,
body[data-categorie].fiche-en-attente #btn-print,
body[data-categorie].fiche-en-attente #btn-reset {
  display: none;
}

/* La galerie occupe alors toute la page : elle EST le contenu. */
body[data-categorie].fiche-en-attente .galerie {
  margin-bottom: 0;
}

/* =========================================================================
   4 bis. LA PLANCHE DE RÉFÉRENCE
   -------------------------------------------------------------------------
   Table de Pythagore, planisphère, tableau périodique… C'est l'affiche de
   la fiche : elle occupe toute la largeur et ne se coupe jamais.
   ========================================================================= */
.planche {
  margin-top: 7mm;
}

.planche__cadre {
  margin: 0;
  border: var(--trait-epais) solid var(--encre);
  border-radius: var(--rayon);
  padding: 6px 8px 8px;
  break-inside: avoid;
  page-break-inside: avoid;
}

.planche__cadre svg {
  display: block;
  width: 100%;
  height: auto;
  /* Une planche large et basse (frise, système solaire) ne doit pas
     s'étirer sur toute la hauteur d'une page. */
  max-height: 155mm;
}

.planche__cadre figcaption {
  margin-top: 5px;
  text-align: center;
}

/* =========================================================================
   5. SOMMAIRE — filtres par niveau, badges (E11)
   ========================================================================= */
/* ---------- Le sommaire, rangé par matière ----------
   Une discipline se voit d'un coup d'œil : trois notions de
   mathématiques ne se confondent plus avec quatre de sciences. */
.hub-matiere {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin: 6mm 0 2.5mm;
  padding-bottom: 3px;
  border-bottom: var(--trait-epais) solid var(--encre);
  font-family: var(--police-titre);
  font-size: 19px;
  line-height: 1.1;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  break-after: avoid;
  page-break-after: avoid;
}

.hub-matiere:first-of-type {
  margin-top: 2mm;
}

.hub-matiere > span {
  font-size: 22px;
}

/* Le titre d'une matière mène à sa page de catégorie. Le soulignement
   n'apparaît qu'au survol : sur papier, un titre souligné sous une barre
   déjà épaisse ne se lit plus. */
.hub-matiere a {
  color: inherit;
  text-decoration: none;
}

.hub-matiere a:hover,
.hub-matiere a:focus-visible {
  text-decoration: underline;
  text-underline-offset: 3px;
}

.hub-matiere small {
  margin-left: auto;
  font-family: var(--police-texte);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.1em;
  opacity: 0.65;
}

/* Une matière et ses notions restent ensemble sur la même page. */
.hub-matiere + .hub {
  break-inside: avoid;
  page-break-inside: avoid;
}

/* La porte d'entrée d'une matière : une carte en pointillés, visiblement
   « à remplir », qui dit que les notions livrées ne sont pas une limite. */
.hub-carte--creer {
  border-style: dashed;
}

.hub-carte--creer h2 {
  font-style: italic;
}

@media print {
  /* Sur le papier, on ne crée rien : la carte n'a plus de sens. */
  .hub-carte--creer {
    display: none !important;
  }
}

.hub-filtres {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 0 0 5mm;
  padding: 10px 12px;
  border: var(--trait-fin) dashed var(--encre);
  border-radius: var(--rayon);
}

.hub-filtres__titre {
  margin: 0 6px 0 0;
  font-weight: 800;
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.hub-carte__meta {
  display: flex;
  gap: 6px;
  align-items: center;
  margin-top: 2px;
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.hub-carte__niveau {
  border: 1.5px solid var(--encre);
  border-radius: 999px;
  padding: 1px 7px;
}

.hub-carte__nouveau {
  border: 1.5px solid var(--encre);
  border-radius: 999px;
  padding: 1px 7px;
  background: var(--encre);
  color: var(--papier);
}

.hub-carte[hidden] {
  display: none !important;
}

/* La matière d'une fiche, sur sa carte du sommaire : c'est ce qui
   empêche « Le corps humain & le vivant » de flotter sans discipline. */
.hub-carte__matiere {
  opacity: 0.7;
}

/* Les cartes de MATIÈRE ouvrent le sommaire. Leur emblème est l'emoji de
   la discipline, plus gros qu'une icône de fiche : on doit voir d'un coup
   d'œil que ces cartes-là ne sont pas des fiches. */
.hub-carte__emoji {
  font-size: 34px;
  line-height: 1.1;
}

.hub-carte--matiere {
  border-width: var(--trait-epais);
}

.hub-carte--matiere h2 {
  font-size: 17px;
}

/* Compteur d'étoiles par carte, rempli par le script */
.hub-carte__etoiles {
  font-size: 10.5px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}

/* =========================================================================
   5 bis. LA GALERIE D'UNE CATÉGORIE

   Une matière est une catégorie : sa page montre ses sujets en cartes,
   filtrables par niveau, plutôt que d'ouvrir directement une fiche unique.

   Elle réutilise .hub et .hub-carte — mêmes cartes, même trait, même
   comportement au survol. Seuls l'état du sujet et le titre en h3
   demandent quelque chose de neuf.
   ========================================================================= */
.galerie {
  margin: 0 0 7mm;
}

.galerie__intro {
  margin: 0 0 4mm;
  font-size: 13px;
  max-width: 70ch;
}

.galerie__compte {
  margin: 0 0 3mm;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.galerie__vide {
  margin: 0 0 4mm;
  padding: 10px 12px;
  border: var(--trait-fin) dashed var(--encre);
  border-radius: var(--rayon);
  font-size: 12.5px;
}

/* Le titre d'une carte de galerie est un h3 : la page a déjà son h1, et
   la galerie son h2. La hiérarchie ne saute pas un niveau. */
.galerie-carte h3 {
  margin: 0;
  font-family: var(--police-titre);
  font-size: 15px;
  line-height: 1.1;
  text-transform: uppercase;
  /* Un intitulé du programme officiel peut être long : on le laisse
     respirer sur trois lignes plutôt que de le couper. */
  overflow-wrap: anywhere;
}

.galerie-carte p {
  font-size: 11px;
}

.galerie-carte__etat {
  border: 1.5px solid var(--encre);
  border-radius: 999px;
  padding: 1px 7px;
  border-style: dashed;
}

/* Ce qui est déjà écrit se voit d'un coup d'œil : plein contre pointillé. */
.galerie-carte__etat--prete {
  border-style: solid;
  background: var(--encre);
  color: var(--papier);
}

.galerie-carte--sujet svg {
  width: 50px;
  height: 50px;
}

/* La barre de niveaux est une NAVIGATION, pas un filtre : chaque niveau
   a son adresse. Trois états doivent se distinguer sans lire —
   accessible, ici, et vide. */
.crayon-pastille--ici {
  background: var(--encre);
  color: var(--papier);
  cursor: default;
}

/* Un niveau que la matière ne couvre pas reste visible mais éteint : le
   masquer laisserait croire à un oubli, et un lien qui déçoit est pire
   qu'un lien absent. */
.crayon-pastille--vide {
  opacity: 0.35;
  cursor: not-allowed;
}

a.crayon-pastille {
  text-decoration: none;
}

/* =========================================================================
   6. BIBLIOTHÈQUE (E10) — liste des fiches enregistrées
   ========================================================================= */
.biblio {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 3mm;
  margin: 0;
  padding: 0;
  list-style: none;
}

.biblio__item {
  border: var(--trait-fin) solid var(--encre);
  border-radius: var(--rayon);
  padding: 10px 12px 12px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.biblio__item h3 {
  margin: 0;
  font-family: var(--police-titre);
  font-size: 16px;
  line-height: 1.15;
}

.biblio__meta {
  margin: 0;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.biblio__sujet {
  margin: 0;
  font-size: 12.5px;
}

.biblio__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: auto;
  padding-top: 6px;
}

.biblio__actions .btn {
  border-color: var(--encre);
  padding: 6px 12px;
  font-size: 12px;
}

.biblio__actions .btn--ghost {
  color: var(--encre);
}

.biblio__vide {
  border: var(--trait-fin) dashed var(--encre);
  border-radius: var(--rayon);
  padding: 18px;
  text-align: center;
  font-size: 13.5px;
}

/* =========================================================================
   7. TABLEAU DE BORD (E11)
   ========================================================================= */
.tdb-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 3mm;
  margin-bottom: 5mm;
}

.tdb-stat {
  border: var(--trait-epais) solid var(--encre);
  border-radius: var(--rayon);
  padding: 10px 14px 12px;
  text-align: center;
}

.tdb-stat b {
  display: block;
  font-family: var(--police-titre);
  font-size: 34px;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.tdb-stat span {
  display: block;
  margin-top: 3px;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

/* Barres de progression par thème */
.tdb-themes {
  list-style: none;
  margin: 0 0 5mm;
  padding: 0;
  display: grid;
  gap: 6px;
}

.tdb-theme {
  display: grid;
  grid-template-columns: minmax(120px, 1.3fr) 3fr auto;
  align-items: center;
  gap: 10px;
  border: var(--trait-fin) solid var(--encre);
  border-radius: 10px;
  padding: 5px 10px;
  font-size: 13px;
}

.tdb-theme a {
  color: var(--encre);
  font-weight: 800;
  text-decoration: none;
}

.tdb-theme__jauge {
  height: 12px;
  border: 1.5px solid var(--encre);
  border-radius: 999px;
  overflow: hidden;
}

.tdb-theme__jauge i {
  display: block;
  height: 100%;
  background-image: repeating-linear-gradient(45deg, var(--encre) 0 2.5px, transparent 2.5px 6px);
  border-right: 2px solid var(--encre);
}

.tdb-theme__n {
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  font-size: 12px;
}

/* Régularité : une case par jour, 12 dernières semaines */
.tdb-heatmap {
  display: grid;
  grid-template-rows: repeat(7, 14px);
  grid-auto-flow: column;
  grid-auto-columns: 14px;
  gap: 3px;
  overflow-x: auto;
  padding-bottom: 4px;
}

.tdb-heatmap i {
  border: 1.2px solid var(--encre);
  border-radius: 3px;
  background: var(--papier);
}

.tdb-heatmap i[data-n="1"] { background-image: repeating-linear-gradient(45deg, var(--encre) 0 1px, transparent 1px 5px); }
.tdb-heatmap i[data-n="2"] { background-image: repeating-linear-gradient(45deg, var(--encre) 0 1.5px, transparent 1.5px 4px); }
.tdb-heatmap i[data-n="3"] { background-image: repeating-linear-gradient(45deg, var(--encre) 0 2px, transparent 2px 3px); }
.tdb-heatmap i[data-n="4"] { background: var(--encre); }

/* Badges à colorier */
.tdb-badges {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: 3mm;
}

.tdb-badge {
  border: var(--trait-fin) solid var(--encre);
  border-radius: var(--rayon);
  padding: 10px;
  text-align: center;
}

.tdb-badge__rond {
  width: 54px;
  height: 54px;
  margin: 0 auto 6px;
  border: var(--trait-epais) solid var(--encre);
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-family: var(--police-titre);
  font-size: 20px;
}

.tdb-badge.est-gagne .tdb-badge__rond {
  background-image: repeating-linear-gradient(45deg, var(--encre) 0 2.2px, transparent 2.2px 7px);
}

.tdb-badge:not(.est-gagne) {
  opacity: 0.5;
}

.tdb-badge h3 {
  margin: 0 0 2px;
  font-family: var(--police-titre);
  font-size: 14px;
}

.tdb-badge p {
  margin: 0;
  font-size: 11px;
}

/* =========================================================================
   8. NOTIFICATIONS (écran uniquement)
   ========================================================================= */
.toasts {
  position: fixed;
  left: 50%;
  bottom: 18px;
  transform: translateX(-50%);
  z-index: 60;
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: center;
  pointer-events: none;
}

.toast {
  max-width: min(92vw, 520px);
  padding: 10px 16px;
  border: var(--trait-fin) solid var(--papier);
  border-radius: 999px;
  background: var(--encre);
  color: var(--papier);
  font-weight: 700;
  font-size: 13px;
  box-shadow: 0 4px 18px rgb(0 0 0 / 0.3);
  animation: toast-entree 200ms ease-out;
}

.toast--alerte {
  background: var(--papier);
  color: var(--encre);
  border-color: var(--encre);
  border-width: var(--trait-epais);
}

@keyframes toast-entree {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .toast { animation: none; }
}

/* =========================================================================
   9. SÉCURITÉ DE LA CLÉ (E5) — bandeau BYOK
   ========================================================================= */
.byok {
  margin: 8px 0 0;
  padding: 8px 12px;
  border: var(--trait-fin) solid var(--encre);
  border-left-width: 6px;
  border-radius: 8px;
  font-size: 12px;
}

.byok b {
  font-family: var(--police-titre);
}

.byok__etat {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-weight: 800;
}

.byok__etat::before {
  content: "";
  width: 10px;
  height: 10px;
  border-radius: 50%;
  border: 2px solid var(--encre);
}

.byok__etat[data-etat="chiffree"]::before {
  background: var(--encre);
}

/* =========================================================================
   10. RESPONSIVE
   ========================================================================= */
@media (max-width: 760px) {
  .setup,
  .pied-global {
    margin-left: 10px;
    margin-right: 10px;
  }

  .tdb-theme {
    grid-template-columns: 1fr;
    gap: 4px;
  }

  .modal-gen__ligne {
    flex-direction: column;
    align-items: stretch;
  }

  .modal-gen__vignette {
    width: 100%;
    height: 120px;
  }
}

/* =========================================================================
   11. IMPRESSION — rien de tout cela n'existe sur le papier.
   ========================================================================= */
@media print {
  .pied-global,
  .modal-gen,
  .setup,
  .hub-filtres,
  .toasts,
  .byok,
  .biblio__actions,
  .fil-crayons,
  [data-ecran-seulement] {
    display: none !important;
  }

  .image-coloriage.est-en-attente .image-coloriage__zone::after,
  .skeleton::after {
    display: none !important;
  }

  .image-coloriage.est-en-attente .image-coloriage__zone,
  .skeleton {
    background: var(--papier) !important;
  }

  .hub-carte__meta {
    font-size: 8px;
  }

  .hub-carte__nouveau {
    background: none;
    color: var(--encre);
  }

  .tdb-stats,
  .tdb-themes,
  .tdb-badges,
  .tdb-heatmap {
    break-inside: avoid;
    page-break-inside: avoid;
  }
}

/* =========================================================================
   PROGRAMME OFFICIEL — pages de niveau et générateur de leçon
   -------------------------------------------------------------------------
   Deux documents très différents partagent ce bloc :

     · niveau-<x>.html  un catalogue à parcourir à l'écran, dont chaque
                        entrée est un lien vers la génération ;
     · professeur.html  une fiche de préparation qui doit tenir sur du
                        papier, parce qu'un enseignant la pose sur son
                        bureau et non sur un deuxième écran.

   D'où la règle qui gouverne tout ce fichier : le formulaire est marqué
   `data-ecran-seulement`, la leçon s'imprime seule.
   ========================================================================= */

.feuille--large {
  max-width: 232mm;
}

/* ------------------------------------------------------- pages de niveau */
.niveau-barre {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  justify-content: center;
  margin: 0 0 8mm;
}

.niveau-barre a {
  border: 2px solid var(--encre);
  border-radius: 999px;
  padding: 3px 12px;
  font-weight: 800;
  font-size: 13px;
  text-decoration: none;
  color: inherit;
}

.niveau-barre a:hover,
.niveau-barre a:focus-visible {
  background: var(--encre);
  color: var(--papier);
}

.niveau-grille {
  display: grid;
  gap: 6mm;
  grid-template-columns: repeat(auto-fill, minmax(78mm, 1fr));
  align-items: start;
}

/* Au cycle 4, une matière porte jusqu'à quinze attendus : le bloc
   dépasse alors la page A4, et « ne jamais couper » devient impossible à
   tenir. L'unité insécable est donc le DOMAINE avec ses attendus — c'est
   lui qui perd son sens si on le sépare, pas la matière. */
.niveau-matiere {
  border: var(--trait-epais) solid var(--encre);
  border-radius: 12px;
  padding: 4mm 4mm 3mm;
}

.niveau-sujet {
  break-inside: avoid;
  page-break-inside: avoid;
}

.niveau-matiere__titre {
  margin: 0 0 3mm;
  font-family: var(--titre, inherit);
  font-size: 16px;
  border-bottom: 2px solid var(--crayon, var(--encre));
  padding-bottom: 2mm;
}

.niveau-matiere__absent {
  margin: 0;
  font-size: 12px;
  font-style: italic;
}

.niveau-sujets {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 3mm;
}

.niveau-sujet > a {
  font-weight: 800;
  font-size: 13.5px;
  color: inherit;
  text-decoration-color: var(--crayon, var(--encre));
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
}

.niveau-sujet--theme > a::before {
  content: "▸ ";
  color: var(--crayon, var(--encre));
}

.niveau-sujet__origine {
  display: block;
  font-size: 10.5px;
  opacity: 0.72;
}

/* Les attendus officiels : cités, donc jamais reformulés ni tronqués par
   la mise en page. Ils restent lisibles mais discrets — c'est la preuve,
   pas le titre. */
.niveau-attendus {
  margin: 1.5mm 0 0;
  padding-left: 4mm;
  font-size: 11px;
  line-height: 1.35;
}

.niveau-attendus li {
  margin-bottom: 0.8mm;
}

/* ------------------------------------------------- générateur de leçon */
.lecon-form {
  border: var(--trait-epais) solid var(--encre);
  border-radius: 14px;
  padding: 5mm;
  margin-bottom: 6mm;
  display: grid;
  gap: 4mm;
}

.lecon-form__ligne {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

.lecon-form__ligne label {
  font-weight: 800;
  font-size: 12.5px;
}

.lecon-form select,
.lecon-form input {
  font: inherit;
  font-size: 14px;
  padding: 5px 8px;
  border: 2px solid var(--encre);
  border-radius: 8px;
  background: var(--papier);
  color: inherit;
}

.lecon-form__ligne--principale input {
  flex: 1 1 260px;
}

/* .btn est dessiné pour la barre d'outils sombre : bordure et fond en
   couleur « papier ». Posé sur du papier, il devient invisible. Sur cette
   page l'action principale est sur fond blanc, elle s'inverse donc. */
.lecon-form .btn {
  background: var(--encre);
  color: var(--papier);
  border-color: var(--encre);
}

.lecon-form .btn:disabled {
  opacity: 0.45;
  cursor: progress;
}

.lecon-form__ligne--cle input {
  flex: 1 1 200px;
}

.lecon-ancrage {
  margin: 0;
  font-size: 12px;
}

.lecon-ancrage--absent {
  font-weight: 700;
}

.lecon-ancrage--absent::before {
  content: "⚠ ";
}

.lecon-ancrage--ok::before {
  content: "✓ ";
}

/* ------------------------------------------------------ la leçon rendue */
.lecon__tete {
  border-bottom: var(--trait-epais) solid var(--encre);
  padding-bottom: 3mm;
  margin-bottom: 4mm;
}

.lecon__meta {
  margin: 0;
  font-size: 12px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.lecon__titre {
  margin: 1mm 0 2mm;
  font-family: var(--titre, inherit);
  font-size: 26px;
  line-height: 1.1;
}

.lecon__objectif {
  margin: 0;
  font-size: 14px;
}

.lecon__bloc {
  margin-bottom: 4mm;
  break-inside: avoid;
  page-break-inside: avoid;
}

.lecon__bloc h3 {
  margin: 0 0 2mm;
  font-family: var(--titre, inherit);
  font-size: 15px;
  border-bottom: 2px solid var(--encre);
  padding-bottom: 1mm;
}

.lecon__bloc ul {
  margin: 0;
  padding-left: 5mm;
  font-size: 12.5px;
}

.lecon__bloc p {
  margin: 0 0 1.5mm;
  font-size: 12.5px;
}

.lecon__colonnes {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 5mm;
}

.lecon__programme {
  border: 2px dashed var(--encre);
  border-radius: 10px;
  padding: 3mm 4mm;
}

.lecon__source {
  font-size: 10.5px;
  font-style: italic;
  opacity: 0.75;
}

.lecon__phases {
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: phase;
}

.lecon-phase {
  border-left: 4px solid var(--encre);
  padding: 0 0 2mm 4mm;
  margin-bottom: 3mm;
  break-inside: avoid;
  page-break-inside: avoid;
}

.lecon-phase__tete {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 8px;
}

.lecon-phase__nom {
  font-family: var(--titre, inherit);
  font-size: 14px;
}

.lecon-phase__min {
  font-weight: 800;
  font-size: 12px;
  border: 2px solid var(--encre);
  border-radius: 999px;
  padding: 0 8px;
  white-space: nowrap;
}

/* La consigne est ce que le professeur PRONONCE : elle doit se retrouver
   d'un coup d'œil au milieu d'une séance, d'où le fond tramé. */
.lecon-phase__consigne {
  margin: 1mm 0;
  padding: 1.5mm 3mm;
  border-left: 3px solid var(--encre);
  background: rgba(0, 0, 0, 0.045);
  font-style: italic;
  font-size: 12.5px;
}

.lecon-phase__role {
  margin: 0.8mm 0 0;
  font-size: 12px;
}

.lecon__table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12px;
}

.lecon__table th,
.lecon__table td {
  border: 1.5px solid var(--encre);
  padding: 2mm;
  text-align: left;
  vertical-align: top;
}

.lecon__table th {
  width: 42%;
  font-weight: 800;
}

.lecon__trace {
  border: var(--trait-epais) solid var(--encre);
  border-radius: 10px;
  padding: 3mm 4mm;
}

.lecon__pont {
  border-top: var(--trait-epais) dashed var(--encre);
  padding-top: 3mm;
}

.lecon__prolongements {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.lecon__prolongements span {
  border: 2px solid var(--encre);
  border-radius: 999px;
  padding: 1px 9px;
  font-size: 11.5px;
}

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

@media print {
  /* Le formulaire et la barre de niveaux ne servent qu'à l'écran : les
     imprimer gâcherait une page et brouillerait la préparation. */
  .lecon-form,
  .niveau-barre {
    display: none !important;
  }

  .lecon__bloc h3,
  .lecon-phase__min,
  .lecon__table th,
  .lecon__table td,
  .niveau-barre a {
    border-color: #000;
  }

  .lecon-phase__consigne {
    background: none;
    border-left-width: 4px;
  }

  .niveau-grille {
    grid-template-columns: 1fr 1fr;
  }
}

/* =========================================================================
   CIBLES DE POINTAGE (WCAG 2.5.8 — 24 × 24 px)
   -------------------------------------------------------------------------
   La règle exempte les liens « dans une phrase ou un bloc de texte », et on
   s'appuie sur cette exemption : agrandir « Obtenir une clé Gemini » au
   milieu d'un paragraphe casserait l'interligne pour rien.

   Elle ne couvre en revanche PAS les listes de commandes — navigation de
   pied de page, liste des domaines d'une page de niveau, liste des notions
   d'une matière. Ce sont les liens qu'on vise au doigt sur une tablette,
   souvent debout devant une classe. Ils gagnent donc de la hauteur, sans
   bouger d'un pixel à l'écran puisque le remplissage remplace un espacement
   qui existait déjà.
   ========================================================================= */
.pied-global nav a,
.tdb-theme a,
.niveau-sujet > a,
.hub-mode-emploi li a {
  display: inline-block;
  padding-block: 4px;
}

/* La case à cocher du panneau : 20 px de côté, sous le seuil, et c'est la
   seule commande du wizard qu'on manque régulièrement. */
.setup__champ input[type="checkbox"] {
  width: 24px;
  height: 24px;
  flex: 0 0 auto;
}

@media print {
  /* Le remplissage ajouté ci-dessus ne sert qu'au doigt : sur papier il
     ne ferait qu'allonger les listes. */
  .pied-global nav a,
  .niveau-sujet > a,
  .hub-mode-emploi li a {
    padding-block: 0;
  }
}

/* =========================================================================
   PAGES D'ACCUEIL PAR USAGE
   -------------------------------------------------------------------------
   Aucun composant nouveau : on réemploie `.hub-carte`, `.section-titre` et
   `.entete` du design d'origine, pour qu'un visiteur qui arrive par une de
   ces pages soit déjà chez lui quand il ouvre une fiche.
   ========================================================================= */
.persona-etapes__liste {
  list-style: none;
  margin: 0 0 8mm;
  padding: 0;
  display: grid;
  gap: 5mm;
  grid-template-columns: repeat(auto-fit, minmax(62mm, 1fr));
  counter-reset: etape;
}

.persona-etape {
  position: relative;
  border: var(--trait-epais) solid var(--encre);
  border-radius: 14px;
  padding: 5mm 4mm 4mm;
  break-inside: avoid;
  page-break-inside: avoid;
}

/* Le numéro est un repère visuel, pas une information : il est déjà porté
   par la structure <ol>, d'où aria-hidden côté HTML. */
.persona-etape__n {
  position: absolute;
  top: -14px;
  left: 4mm;
  width: 28px;
  height: 28px;
  display: grid;
  place-items: center;
  border: var(--trait-epais) solid var(--encre);
  border-radius: 999px;
  background: var(--papier);
  font: 800 15px/1 var(--police-titre, var(--police-texte));
}

.persona-etape h3 {
  margin: 0 0 2mm;
  font-family: var(--police-titre, inherit);
  font-size: 17px;
  line-height: 1.15;
}

.persona-etape p {
  margin: 0;
  font-size: 13px;
  line-height: 1.45;
}

.hub--portes {
  grid-template-columns: repeat(auto-fit, minmax(64mm, 1fr));
}

.hub-carte--porte {
  min-height: 0;
  padding: 5mm 4mm;
}

.hub-carte--porte h3 {
  margin: 0 0 2mm;
  font-family: var(--police-titre, inherit);
  font-size: 17px;
}

.persona-faq {
  margin-top: 8mm;
}

.persona-faq__item {
  border-bottom: 2px solid var(--encre);
  padding: 3mm 0;
  break-inside: avoid;
  page-break-inside: avoid;
}

/* Les questions restent dépliées. Un <details> replié ne s'imprime pas de
   façon fiable — les navigateurs masquent son contenu autrement qu'avec
   « display », et l'impression doit fonctionner sans JavaScript. Avec trois
   questions courtes, l'accordéon n'économisait aucune place utile. */
.persona-faq__item h3 {
  margin: 0;
  font-family: var(--police-titre, inherit);
  font-size: 15px;
  line-height: 1.2;
}

.persona-faq__item p {
  margin: 2mm 0 0;
  font-size: 13px;
  line-height: 1.5;
  max-width: 74ch;
}

.persona-autres {
  margin-top: 8mm;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  font-size: 13px;
}

.persona-autres p {
  margin: 0;
  font-weight: 800;
}

.persona-autres a {
  display: inline-block;
  border: 2px solid var(--encre);
  border-radius: 999px;
  padding: 4px 14px;
  text-decoration: none;
  color: inherit;
  font-weight: 700;
}

.persona-autres a:hover,
.persona-autres a:focus-visible {
  background: var(--encre);
  color: var(--papier);
}

@media print {
  /* Les liens « vous n'êtes pas au bon endroit ? » n'ont aucun sens une
     fois imprimés : sur du papier, ils ne mènent nulle part. */
  .persona-autres {
    display: none !important;
  }
}

/* Le bandeau « Vous venez pour… » en tête du sommaire : quatre portes,
   avant la grille des notions. C'est la première question qu'un visiteur
   se pose, et la grille ne pouvait pas y répondre. */
.personas__liste {
  display: grid;
  gap: 4mm;
  grid-template-columns: repeat(auto-fit, minmax(44mm, 1fr));
  margin-bottom: 8mm;
}

.persona-pastille {
  position: relative;
  display: grid;
  grid-template-columns: 34px 1fr;
  grid-template-areas: "ico nom" "ico txt";
  column-gap: 10px;
  align-items: center;
  border: var(--trait-epais) solid var(--encre);
  border-radius: 14px;
  padding: 4mm;
  text-decoration: none;
  color: inherit;
  background: var(--papier);
}

.persona-pastille svg {
  grid-area: ico;
  width: 34px;
  height: 34px;
}

.persona-pastille b {
  grid-area: nom;
  font-family: var(--police-titre, inherit);
  font-size: 16px;
}

.persona-pastille span {
  grid-area: txt;
  font-size: 12px;
  line-height: 1.35;
}

@media print {
  /* Ces portes ne servent qu'à naviguer : imprimées, elles occupent le
     haut de la première page du sommaire pour rien. */
  .personas {
    display: none !important;
  }
}

/* =========================================================================
   COMPTE ET CRÉDITS
   -------------------------------------------------------------------------
   Ce bloc remplace l'ancienne interface de saisie de clé. Il n'affiche
   plus un champ à remplir mais un ÉTAT : qui je suis, combien il me
   reste. Tout ce qui décide vraiment — l'identité, le solde, le débit —
   vit sur le serveur ; ces règles ne font que le montrer.
   ========================================================================= */
.compte-bandeau {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 12px;
  margin-top: 10px;
  padding: 8px 12px;
  border: var(--trait-fin) solid var(--encre);
  border-radius: 12px;
  font-size: 13px;
}

.compte-bandeau__etat {
  font-weight: 800;
}

.compte-bandeau__solde {
  border: 2px solid var(--encre);
  border-radius: 999px;
  padding: 2px 10px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}

/* Un solde à zéro n'est pas une information neutre : c'est ce qui bloque
   la prochaine génération. */
.compte-bandeau[data-etat="deconnecte"] .compte-bandeau__etat::before { content: "○ "; }
.compte-bandeau[data-etat="connecte"] .compte-bandeau__etat::before { content: "● "; }
.compte-bandeau[data-etat="hors-service"] { border-style: dashed; }

.compte-bloc {
  margin-bottom: 8mm;
}

.compte-methodes {
  display: grid;
  gap: 5mm;
  grid-template-columns: repeat(auto-fit, minmax(62mm, 1fr));
  margin-top: 4mm;
}

.compte-methode {
  border: var(--trait-epais) solid var(--encre);
  border-radius: 14px;
  padding: 5mm 4mm;
  display: grid;
  gap: 3mm;
  align-content: start;
}

.compte-methode h3 {
  margin: 0;
  font-family: var(--police-titre, inherit);
  font-size: 17px;
}

.compte-methode p {
  margin: 0;
  font-size: 13px;
}

.compte-methode input {
  font: inherit;
  font-size: 14px;
  padding: 7px 12px;
  border: 2px solid var(--encre);
  border-radius: 999px;
  background: var(--papier);
  color: inherit;
  width: 100%;
}

.compte-methode .btn,
.compte-bloc .btn {
  background: var(--encre);
  color: var(--papier);
  border-color: var(--encre);
}

.compte-note {
  margin-top: 5mm;
  font-size: 12px;
  max-width: 78ch;
}

.compte-solde-carte {
  border: var(--trait-epais) solid var(--encre);
  border-radius: 14px;
  padding: 5mm;
  text-align: center;
  margin-bottom: 6mm;
}

.compte-solde-carte__n {
  margin: 0;
  font-family: var(--police-titre, inherit);
  font-size: 46px;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.compte-solde-carte__l {
  margin: 1mm 0 0;
  font-size: 13px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.compte-solde-carte__id {
  margin: 2mm 0 0;
  font-size: 12px;
  opacity: 0.75;
}

.compte-packs {
  display: grid;
  gap: 4mm;
  grid-template-columns: repeat(auto-fit, minmax(52mm, 1fr));
  margin-bottom: 6mm;
}

.compte-pack {
  border: var(--trait-fin) solid var(--encre);
  border-radius: 12px;
  padding: 4mm;
  display: grid;
  gap: 2mm;
  align-content: start;
}

.compte-pack h3 {
  margin: 0;
  font-family: var(--police-titre, inherit);
  font-size: 16px;
}

.compte-pack__credits {
  margin: 0;
  font-weight: 800;
  font-size: 15px;
}

.compte-pack__detail {
  margin: 0;
  font-size: 12px;
}

.compte-pack__prix {
  margin: 0;
  font-family: var(--police-titre, inherit);
  font-size: 22px;
}

.compte-hist {
  width: 100%;
  border-collapse: collapse;
  font-size: 12.5px;
}

.compte-hist th,
.compte-hist td {
  border: 1.5px solid var(--encre);
  padding: 2mm 3mm;
  text-align: left;
}

.compte-hist__delta {
  text-align: right;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}

.compte-indispo-texte {
  font-style: italic;
}

.lecon-form__compte {
  margin: 0;
  font-size: 12.5px;
}

/* Le reCAPTCHA de Firebase se dimensionne seul ; on l'empêche seulement
   de déborder d'une carte étroite. */
#compte-recaptcha {
  max-width: 100%;
  overflow-x: auto;
}

@media print {
  /* Un compte ne s'imprime pas : ni les moyens de connexion, ni les
     packs, ni le bandeau d'état sur une fiche. */
  .compte-bandeau,
  .compte-methodes,
  .compte-packs,
  #compte-recaptcha {
    display: none !important;
  }
}

/* =========================================================================
   RAYONS ET ADMINISTRATION
   ========================================================================= */
.tdb-rayon {
  margin-bottom: 4mm;
}

.tdb-rayon h3 {
  margin: 0 0 2mm;
  font-family: var(--police-titre, inherit);
  font-size: 14px;
}

.tdb-rayon__puces {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

/* Une puce active doit se voir SANS couleur : le produit s'imprime en
   noir et blanc, et le contraste ne peut donc pas reposer sur la teinte. */
.tdb-puce {
  border: 2px solid var(--encre);
  border-radius: 999px;
  padding: 4px 12px;
  background: var(--papier);
  color: inherit;
  font: 700 12.5px var(--police-texte);
  cursor: pointer;
}

.tdb-puce b {
  font-variant-numeric: tabular-nums;
  opacity: 0.7;
}

.tdb-puce[aria-pressed="true"] {
  background: var(--encre);
  color: var(--papier);
}

.tdb-puce[aria-pressed="true"] b {
  opacity: 0.85;
}

.admin-rayons {
  display: grid;
  gap: 4mm;
  grid-template-columns: repeat(auto-fit, minmax(52mm, 1fr));
}

.admin-rayon {
  border: var(--trait-fin) solid var(--encre);
  border-radius: 12px;
  padding: 3mm 4mm;
}

.admin-rayon h3 {
  margin: 0 0 2mm;
  font-family: var(--police-titre, inherit);
  font-size: 14px;
}

.admin-rayon ul {
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: 12.5px;
}

.admin-rayon li {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  padding: 1px 0;
}

.admin-rayon li b {
  font-variant-numeric: tabular-nums;
}

.admin-drapeaux {
  list-style: none;
  margin: 0 0 2mm;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 6px 14px;
  font-size: 13px;
  font-weight: 700;
}

/* Un manque doit sauter aux yeux : c'est la seule information vraiment
   actionnable de cette liste. */
.admin-drapeaux li[data-ok="false"] {
  border: 2px solid var(--encre);
  border-radius: 999px;
  padding: 1px 10px;
}

.admin-meta {
  margin: 0 0 2mm;
  font-size: 12px;
}

.admin-table {
  font-size: 12px;
}

.admin-table small {
  opacity: 0.7;
  font-size: 10.5px;
}

.admin-actions {
  white-space: nowrap;
}

.admin-actions button {
  border: 2px solid var(--encre);
  border-radius: 999px;
  background: var(--papier);
  color: inherit;
  font: 700 11.5px var(--police-texte);
  padding: 2px 8px;
  margin-right: 3px;
  cursor: pointer;
}

.admin-actions button:disabled {
  opacity: 0.4;
  cursor: progress;
}

@media print {
  /* L'administration ne s'imprime pas, et les puces de filtre non plus :
     un filtre est une commande, pas une information. */
  .tdb-rayon__puces,
  .admin-actions,
  .admin-rayons {
    display: none !important;
  }
}

/* Les rayons partagent la mise en forme de la bibliothèque sans partager
   sa classe : même aspect, deux composants distincts. */
.rayon__item {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  align-items: center;
  border: var(--trait-fin) solid var(--encre);
  border-radius: 10px;
  padding: 2mm 3mm;
  margin-bottom: 2mm;
  font-size: 12.5px;
}

.rayon__item small {
  display: block;
  opacity: 0.75;
  font-size: 11px;
}

/* L'avertissement de mise en service : visible sans être alarmant, et
   surtout impossible à confondre avec le reste de la page. */
.compte-avertissement {
  border: var(--trait-epais) dashed var(--encre);
  border-radius: 12px;
  padding: 4mm;
  margin-bottom: 6mm;
  font-size: 13px;
  line-height: 1.45;
  max-width: 80ch;
}

/* =========================================================================
   5 ter. LA PAGE MODÈLE

   Le gabarit d'une matière, rendu lisible pour être relu avant toute
   production en série. Elle s'imprime : un modèle se valide sur papier,
   crayon en main.
   ========================================================================= */
.modele-bloc {
  border: var(--trait-fin) solid var(--encre);
  border-radius: var(--rayon);
  padding: 10px 14px;
  margin: 0 0 5mm;
  break-inside: avoid;
  page-break-inside: avoid;
}

.modele-liste {
  margin: 0;
  padding-left: 20px;
  font-size: 13px;
}

.modele-liste li {
  margin-bottom: 4px;
}

.modele__etiquette {
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  opacity: 0.75;
}

/* L'état saute aux yeux : c'est la seule information de la page qui
   décide si l'on peut lancer quatre-vingts générations. */
.modele-etat {
  border: var(--trait-epais) solid var(--encre);
  border-radius: var(--rayon);
  padding: 10px 14px;
  margin: 0 0 5mm;
}

.modele-etat--valide {
  background: var(--encre);
  color: var(--papier);
}

.modele-etat--valide code {
  color: inherit;
}

.modele-etat--attente {
  border-style: dashed;
}
