/*
  FICHIER RECOPIE : NE PAS MODIFIER ICI.

  Original : kmoove-memory/src/styles.css
  Copie produite par : npm run exporter-editeur (depot du jeu)

  L'editeur de seance existe en UN SEUL exemplaire, pour que l'animateur
  retrouve les MEMES mots et les MEMES blocs sur le mur et sur le site.
  Une retouche faite ici serait perdue au prochain export, et le controle
  des deux depots la signalerait avant.
*/
/* ══════════════════════════════════════════════════════════════════════
   EDITEUR (F1) — une colonne de templates a gauche, un centre qui montre le
   template choisi, et une barre de reglages toujours visible en bas
   (2026-09-07, T4 ; remplace le centre a deux etats du 2026-09-06, etape 3
   tache 3). Utilise a la SOURIS par l'animateur : elements plus compacts
   que les ecrans de jeu.
   ══════════════════════════════════════════════════════════════════════ */
/* ⚠️ PADDING ET GAP RESSERRÉS PAR `clamp()` (2026-09-07, T1) : sur une
   fenêtre courte, chaque pixel de marge se prend sur la grille des paires
   (mesure : « DOUZE PAIRES… » manquait 33px après le seul resserrement de
   l'en-tête). `clamp()` ne mord QUE sous ~1067px de haut (16px de `vh` y
   vaut moins que le plafond) ; au-delà (le mur en Full HD, 1920x1080), les
   valeurs restent celles d'origine. */
.ecran--editeur {
  justify-content: flex-start;
  /* Coefficients affinés (2026-09-07) : mesurés pour atteindre pile ce qu'il
     fallait à 900px de haut (« DOUZE PAIRES… », qui ne tolère AUCUN
     défilement, quelle que soit la fenêtre) sans écraser un mur en Full HD
     -- voir la mesure complète juste après `.bloc, .bloc--contenu` un peu
     plus bas, ET la note de `.barre-reglages` (T4) qui a repris une part de
     ces coefficients pour lui faire de la place. */
  gap: clamp(0px, 0.15vh, 4px);
  padding: clamp(6px, 1vh, 16px) 28px clamp(0px, 0.15vh, 4px);
  overflow: hidden;
}
.editeur__entete { flex-shrink: 0; display: flex; align-items: center; justify-content: space-between; gap: 24px; width: 100%; min-width: 0; }
/* `min-width: 0` (2026-09-07) : sans lui, un enfant flex refuse de descendre
   sous sa taille de CONTENU (celle d'un champ de 380px inclus), et le
   groupe entier passait à la ligne du dessous plutôt que de rétrécir --
   138px pour un en-tête qui n'a besoin que d'une ligne. Voir la mesure sur
   `.editeur__nom input`, juste en dessous. */
.editeur__identite { display: flex; align-items: baseline; gap: 22px; min-width: 0; }
/* `.editeur__titre` (« K-Moove éditeur » en dégradé) a été RETIRÉ le
   2026-09-08 (T1.2) : le nom du produit prenait le coin le plus lu de
   l'écran au seul texte que l'animateur écrit lui-même. La règle reste ici,
   sans emploi dans l'éditeur, parce que le dégradé du logo sur un titre est
   la marque du produit et resservira : la retirer ferait rechercher ses six
   lignes le jour où un écran en aura besoin. */
.editeur__titre {
  font-size: var(--km-texte-xl);
  font-weight: 800;
  background: var(--km-degrade);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  flex-shrink: 0;
}
/* ⚠️ L'INTITULÉ RESTE SUR LA MÊME LIGNE QUE LE CHAMP (2026-09-08, T1.2).
   Il a été empilé au-dessus pendant une heure, et MESURÉ : à 1130x915 (la
   fenêtre de Mounassib), l'en-tête gagnait une ligne, cette ligne se prenait
   sur la grille des paires, et « DOUZE PAIRES ET LA TUILE + TIENNENT SANS QUE
   LA GRILLE DÉFILE » tombait. La hauteur de cet en-tête est un BUDGET, pas un
   goût (§ 6 bis du CLAUDE.md) : ce que T1.2 rend au titre de la séance est le
   coin qu'occupait le nom du produit, et un cran de taille de police, pas une
   ligne de plus.
   `flex-shrink: 0` sur l'intitulé : sans lui, le texte se fait rogner par le
   champ à mesure que la fenêtre rétrécit, et « Titre de ce K-Moove » devenait
   « Titre de ce K-M… » -- mesuré au même endroit, le même jour. */
.editeur__nom {
  font-size: var(--km-texte-s);
  color: var(--texte-doux);
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
  white-space: nowrap;
}
.editeur__nom input {
  /* ⚠️ 380px FIXES forçaient l'en-tête à 138px de haut (mesuré à 1400x900,
     2026-09-07) : le champ ne pouvait pas rétrécir, l'en-tête passait sur
     plusieurs lignes plutôt que de lui laisser moins de place. `clamp()`
     lui laisse jusqu'à 320px quand la fenêtre est large, jamais moins de
     160px (un titre de séance reste lisible pendant la frappe). */
  width: clamp(160px, 20vw, 320px);
  min-width: 0;
  margin-left: 0;
  padding: 6px 12px;
  font: inherit;
  /* Le titre du K-Moove est le SEUL texte que l'animateur écrit dans cet
     en-tête : il se lit d'un cran au-dessus du reste (T1.2). */
  font-size: var(--km-texte-l);
  color: var(--texte);
  background: var(--fond);
  border: 2px solid var(--bordure);
  border-radius: 10px;
}
/* ─── DEUX GROUPES, PAS SIX BOUTONS DE MEME POIDS (2026-09-08, T1.1) ─────
   L'action principale (essayer, faite vingt fois par séance) était noyée
   parmi cinq gestes rares (importer, exporter, communauté, IA, fermer, faits
   une fois par mois). Elle passe seule sur la ligne du haut, en grand ; les
   gestes rares descendent en dessous, en LIENS DISCRETS. Rien n'est replié
   derrière un menu (règle 37) et aucun libellé ne prend de « … » (règle 36) :
   ce qui change est le poids visuel, jamais l'accès. */
.editeur__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 18px;
}
/* ⚠️ UNE SEULE LIGNE, ET LA HIÉRARCHIE SE PORTE PAR LE STYLE (2026-09-08).
   Les gestes rares ont d'abord été mis SOUS l'essai, sur une seconde ligne.
   Mesuré : l'en-tête gagnait une ligne, et cette ligne se prenait sur la
   grille des paires -- « DOUZE PAIRES ET LA TUILE + TIENNENT » annonçait
   « il manque 28 px ». La hauteur de cet en-tête est un BUDGET (§ 6 bis du
   CLAUDE.md), et T1.1 ne demande pas une ligne de plus : elle demande que
   l'action principale cesse d'avoir le même poids que cinq gestes rares.
   Ce poids-là se porte très bien par le STYLE : les gestes sont des LIENS
   (sans cadre, sans fond, en `--km-texte-xs`), l'essai garde de vrais
   boutons. Rien n'est replié derrière un menu (règle 37), aucun libellé ne
   prend de « … » (règle 36), et la grille garde ses pixels. */
.editeur__gestes {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 14px;
}
/* Un geste rare se lit comme un LIEN : pas de cadre, pas de fond, le texte
   souligné au survol. Il reste un vrai bouton (règle 37 : il se voit, il se
   clique, il a son `data-cible`), il ne se dispute simplement plus l'oeil
   avec l'action principale. */
.choix--lien {
  min-width: 0;
  padding: 2px 4px;
  font-size: var(--km-texte-xs);
  font-weight: 600;
  color: var(--texte-doux);
  background: none;
  border: none;
  border-radius: 6px;
  text-decoration: none;
}
.choix--lien:hover { color: var(--accent); text-decoration: underline; }
.choix--lien:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }
.editeur__message { font-size: var(--km-texte-l); color: var(--accent-doux); }
/* L'essai, a cote du bouton « Tester » : 1, 2 ou 3 joueurs (paragraphe 1.5).
   La reduction de zones et sa note (regle 42) sont celles du mur, puisque
   c'est le meme demarrer() qui recoit `joueurs`. */
.essai { display: inline-flex; align-items: center; gap: 10px; }
.essai__intitule { font-size: var(--km-texte-s); color: var(--texte-doux); }
.essai__joueurs { display: inline-flex; gap: 6px; }
/* « 2 joueurs » plutôt que « 2 » (T1.4) : le bouton est donc plus large, et
   son texte remonte de `xs` à `s`. C'est l'action principale de l'écran. */
.essai__joueurs .choix { min-width: 0; padding: 6px 14px; font-size: var(--km-texte-s); }

/* « Séance enregistrée » — l'enregistrement est automatique, encore faut-il le
   DIRE. Sans cette ligne, un travail sauvegardé en silence ressemble
   exactement à un travail perdu, et l'animateur n'ose pas quitter la page. */
.editeur__enregistrement {
  margin-top: 8px;
  font-size: var(--km-texte-m);
  font-weight: 600;
  color: var(--succes);
}
.editeur__enregistrement--echec { color: var(--accent-doux); }

/* ─── LA COLONNE ET LE CENTRE (2026-09-06) ───
   Le meme principe qu'une colonne d'outils a gauche et une page centrale,
   reconnu chez les concurrents du secteur : c'est ce que l'animateur
   reconnait deja. La colonne est un seul aplat sombre, meme dans le theme
   clair -- ce n'est pas un oubli, c'est LA maquette retenue avec le
   designer. */
.editeur__corps { display: flex; gap: 16px; width: 100%; flex: 1 1 auto; min-height: 0; }

/* ═══ LA BARRE DES RÉGLAGES : TOUJOURS VISIBLE, EN BAS (2026-09-07, T4) ═══
   Mounassib : « l'option Réglages de la séance doit être toujours visible
   pour que les clients puissent régler directement. Là, on doit cliquer
   dessus à chaque fois. » Remplace l'ancien second état du centre
   (2026-09-06, etape 3 tache 3), qui cachait les réglages derrière un clic
   sur la colonne de gauche.

   ─── CE QUE ÇA COÛTE, ET COMMENT C'EST PAYÉ ─────────────────────────────
   `.barre-reglages` est un troisième enfant de `.ecran--editeur` (colonne
   flex), `flex-shrink: 0` : son entête (~52px mesurés, montre en pied de
   page l'exigence « environ 60 px repliée ») retire ce mont de hauteur à
   `.editeur__corps`, qui ne l'avait jamais cédée avant -- l'ancien bloc des
   réglages ne coûtait RIEN replié (`hidden`, 0px) puisqu'il remplaçait tout
   le centre plutôt que de s'y ajouter. Ce coût est repris par un
   resserrement de `.ecran--editeur` et de `.bloc, .bloc--contenu` (voir
   leurs notes) : mesuré ensemble à 1400×900 (« DOUZE PAIRES ET LA TUILE + »)
   pour rester à zéro défilement, plafond absolu.

   ─── DÉPLIÉE, ELLE GRANDIT VERS LE HAUT, JAMAIS EN REPOUSSANT LA GRILLE ──
   `.barre-reglages__corps` est en `position: absolute`, `bottom: 100%` de
   `.barre-reglages` (donc juste au-dessus de l'entête) : elle recouvre le
   bas du centre en SURIMPRESSION plutôt que de repousser `.editeur__corps`
   une seconde fois. Sans cela, chaque dépliage aurait fait REFLUER la grille
   des paires d'autant de pixels que le bloc des réglages en demande (plus de
   150px, mesure du 2026-08-19) : la douzième paire et la tuile « + »
   auraient disparu du défilement à CHAQUE consultation des réglages, pas
   seulement au premier rendu. */
.barre-reglages {
  position: relative;
  flex-shrink: 0;
  z-index: 5;
}
.barre-reglages__entete {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  /* Resserre comme le reste de l'editeur sous les fenetres courtes (voir
     `.ecran--editeur` et `.bloc, .bloc--contenu`) : mesure faite ensemble
     pour que « DOUZE PAIRES ET LA TUILE + » repasse a zero deficit apres
     l'arrivee de cette barre (2026-09-07, T4). */
  padding: clamp(2px, 0.35vh, 6px) 18px;
  font: inherit;
  font-size: var(--km-texte-xs);
  line-height: 1.15;
  color: var(--texte);
  background: var(--fond-carte);
  border: 1px solid var(--bordure);
  border-radius: 14px;
  cursor: pointer;
  text-align: left;
}
.barre-reglages--ouverte .barre-reglages__entete { border-color: var(--accent); }
.barre-reglages__icone { flex: 0 0 auto; font-size: var(--km-texte-s); line-height: 1.2; }
/* Le résumé PREND la place : sur une fenêtre étroite, il s'arrête plutôt
   que de casser la ligne et de faire grandir la barre (elle doit garder sa
   hauteur, repliée comme dépliée). */
.barre-reglages__resume {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 600;
}
.barre-reglages__fleche { flex: 0 0 auto; font-size: var(--km-texte-xs); color: var(--texte-doux); }
.barre-reglages__corps {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 100%;
  z-index: 10;
  margin-bottom: 8px;
  max-height: min(58vh, 560px);
  overflow-y: auto;
  padding: 16px 18px;
  background: var(--fond-carte);
  border: 2px solid var(--bordure);
  border-radius: 18px;
  box-shadow: 0 -16px 36px rgba(0, 0, 0, 0.28);
}
.lateral {
  display: flex;
  flex-direction: column;
  gap: 8px;
  /* ⚠️ LARGEUR RELATIVE, PLUS FIXE (2026-09-07). L'éditeur ne se met plus à
     l'échelle : il occupe la vraie fenêtre, qui va de 1280 à 2560 px de
     large. Une colonne figée à 300 px y était trop large sur un petit
     portable et ridicule sur un grand écran. `clamp()` la borne des deux
     côtés : jamais moins de 260 px (en dessous, un nom de template se coupe),
     jamais plus de 360 px (au delà, elle vole de la place au contenu). */
  width: clamp(260px, 18vw, 360px);
  flex-shrink: 0;
  padding: 14px;
  color: #fff;
  background: var(--km-encre);
  border-radius: 18px;
  min-height: 0;
}
.lateral__titre { font-size: var(--km-texte-m); font-weight: 700; }
.lateral__liste { display: flex; flex-direction: column; gap: 6px; overflow-y: auto; flex: 1; min-height: 0; }
.manche {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  font-size: var(--km-texte-s);
  color: #fff;
  background: rgba(255, 255, 255, 0.06);
  border: 2px solid transparent;
  border-radius: 12px;
  cursor: pointer;
}
/* Ce qui est choisi passe au degrade du logo, ici aussi. */
.manche.choisie { background: var(--km-degrade); border-color: transparent; }
.manche__nom { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
/* Plus d'ellipse : deux lignes valent mieux qu'un titre coupe (« Un me... »). */
.manche__titre { font-weight: 700; overflow-wrap: anywhere; }
/* Le titre choisi se renomme AU CLIC, sur place (etape 3, tache 3). */
.manche__titre-saisie {
  width: 100%;
  font: inherit;
  font-size: var(--km-texte-s);
  padding: 2px 6px;
  border-radius: 6px;
  border: 2px solid var(--km-cyan);
  color: var(--km-encre);
}
/* L'icône de la variante : d'un coup d'œil, on voit qu'une séance mélange un
   memory d'images et un jeu « image et mot ». */
/* line-height 1.4, pas 1 (2026-09-06) : certains emoji colores rendent une
   boite plus haute que leur em carre, et debordaient de leur span (mesure du
   garde-fou des debordements). */
.manche__icone { flex: 0 0 auto; font-size: var(--km-texte-s); line-height: 1.4; }
/* ─── Le nom du jeu, sous le titre de la manche (2026-08-22) ───
   « ☀️ Manche 1 » ne dit pas quel jeu sera joue : il faudrait connaitre les
   onze icones. Le nom s ecrit donc en toutes lettres, discret sous le titre —
   l information est la, sans voler la vedette au nom que l animateur a choisi. */
.manche__jeu { font-size: var(--km-texte-xs); opacity: 0.85; overflow-wrap: anywhere; }
/* Les gestes d'une manche : monter, descendre, retirer -- en colonne, a
   droite de son nom. */
.manche__gestes { display: flex; flex-direction: column; gap: 2px; }
.manche__fleche, .manche__retirer {
  width: 26px;
  height: 22px;
  padding: 0;
  font: inherit;
  font-size: var(--km-texte-xs);
  line-height: 1;
  color: #fff;
  background: rgba(255, 255, 255, 0.12);
  border: 0;
  border-radius: 6px;
  cursor: pointer;
}
.manche__fleche:hover, .manche__retirer:hover { background: rgba(255, 255, 255, 0.28); }
.lateral__ajouter { width: 100%; }
/* « + Ajouter un template » : l'entree existait, elle ne se voyait pas
   (regle 37, 2026-08-22). */
/* ⚠️ « Réglages de la séance » A QUITTÉ LA COLONNE (2026-09-07, T4) : voir
   `.barre-reglages` plus bas, qui les rend TOUJOURS visibles en bas de
   l'écran plutôt que derrière un clic. `.lateral__reglages` n'a plus de
   raison d'exister ici : ne pas le recréer. */

/* ─── « Changer de jeu » : visible, jamais dominant ───
   Sur toute la largeur, il ressemblait a un en-tete de section et volait le
   regard au contenu. C'est une action secondaire : on la trouve quand on la
   cherche, elle ne s'impose pas.

   ─── DANS LE TITRE, PLUS SUR SA PROPRE LIGNE (2026-09-07) ────────────────
   Il vivait sous le titre, en `display:block` aligne a droite : une ligne
   entiere (bouton ~48px + 8px de gouttiere) pour un seul bouton secondaire.
   Mesure a 1400x900, la grille des paires manquait alors 105px pour poser
   douze paires et la tuile « + » sans defiler (« DOUZE PAIRES ET LA TUILE
   + TIENNENT SANS QUE LA GRILLE DEFILE »). `.bloc__titre` est deja une
   ligne flex (titre + nom de la manche) : le bouton y prend sa place a
   droite via `margin-left:auto`, sans ligne a lui -- ni plus dominant
   qu'avant (il reste petit, `choix--petit`), ni moins trouvable (meme
   texte, meme position visuelle a droite du titre). */
.bouton-changer-jeu {
  flex-shrink: 0;
  margin-left: auto;
}

/* ─── Ce que le contenu perdrait en changeant de jeu ───
   Dit AVANT le clic, sur la tuile du jeu envisage. Le decouvrir apres serait
   un regret, et il n y a pas d annulation dans cet editeur. */
.option__perte {
  display: block;
  margin-top: 8px;
  font-size: var(--km-texte-xs);
  line-height: 1.45;
  color: var(--corail);
}

/* Le centre : le template choisi. Il ne montre plus les reglages de la
   seance depuis le 2026-09-07 (T4, voir `.barre-reglages` plus bas) : le
   modificateur `.bloc--reglages` a disparu avec eux. `.bloc--contenu` reste
   pour les tests et un futur habillage propre. */
.centre { flex: 1; min-width: 0; min-height: 0; display: flex; }
.bloc, .bloc--contenu {
  flex: 1;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  /* Coefficients affinés (2026-09-07, T1 puis T4) : même resserrement qu'
     `.ecran--editeur` ci-dessus, mesurés ensemble pour que « DOUZE PAIRES ET
     LA TUILE + TIENNENT SANS QUE LA GRILLE DÉFILE » (1400×900, plafond
     absolu : jamais de défilement, à AUCUNE hauteur) passe pile. Mesuré
     avant ce réglage fin : il manquait 23px à la grille avec un premier
     coefficient trop timide (`1vh` sur ce gap restait, par construction,
     TOUJOURS plafonné à son maximum dès que la fenêtre dépasse 800px de
     haut -- 1vh y vaut déjà plus que 8px -- donc n'apportait STRICTEMENT
     RIEN à 900px). Repris à `0.67vh`/`1vh` : 20px de plus libérés, à 3px
     du compte -- ce gap se répète QUATRE fois dans `.bloc--contenu`
     (titre, aide, tirage, grille), donc chaque dixième de `vh` grignoté ici
     vaut QUATRE fois plus qu'ailleurs. Redescendu à `0.55vh` : les 3px
     manquants, et une marge.
     ─── T4 : LA BARRE DES RÉGLAGES A REPRIS CETTE PLACE (2026-09-07) ───────
     La barre du bas (~52px repliée, voir sa note) mange maintenant une part
     de la hauteur qu'`.ecran--editeur` offrait à `.editeur__corps`. Regagné
     ici : le gap redescend à `0.45vh` (4 répétitions dans `.bloc--contenu`,
     donc chaque `vh` grignoté ici vaut quatre fois plus), le padding
     vertical à `0.75vh`. Mesuré ensemble avec la barre : voir sa note pour
     le total. */
  gap: clamp(2px, 0.3vh, 6px);
  padding: clamp(3px, 0.5vh, 10px) 18px;
  background: var(--fond);
  border: 2px solid var(--bordure);
  border-radius: 18px;
}
.bloc__titre { display: flex; align-items: center; gap: 12px; font-size: var(--km-texte-m); }
.bloc__aide { font-size: var(--km-texte-xs); color: var(--texte-doux); }

/* ─── LE CHOIX DE LA VARIANTE DE JEU ────────────────────────────────────────
   La liste vient du catalogue (schemas/options/), jamais du HTML. Chaque
   tuile dit le nom du jeu, sa règle en une phrase, et pour qui il est fait :
   un animateur ne choisit pas un jeu sur son seul titre. */
/* `align-self` : la boîte de modale centre ses enfants ; sans cela la liste
   ne prendrait pas la largeur et les phrases se casseraient inutilement. */
/* ═══ LE CATALOGUE EN TUILES, COMME NETFLIX (2026-09-07, T5) ═══════════════
   Mounassib : « quand on met ajouter un template, il y a des textes assez
   petits, faits sous forme de tuiles... comme un grand catalogue... un peu
   plus ludique, comme un catalogue Netflix. » Decide avec lui : une carte
   VERTICALE par variante (photo en 16:9, puis le texte), rangee par famille
   dans une ligne SOUPLE qui pose autant de cartes que la largeur permet
   (2026-09-07 : une rangee par famille, jamais une grille partagee -- voir
   `.options__rangee` juste apres, et pourquoi). La recherche et les filtres
   ne changent pas de comportement -- seule la PRESENTATION change, d'une
   liste plate a des cartes. */
/* ═══ LE CATALOGUE PREND TOUT L'ECRAN (2026-09-08, lot 1, T1) ══════════════
   Mounassib : « les templates sont sur tout l'ecran, la recherche et les
   filtres plutot sur le cote gauche, les templates par trois ou quatre, et
   on descend avec la barre de defilement de l'ecran, pas une autre. »

   Trois regions, et UNE SEULE defile :
     1. `.catalogue__entete` : le titre, l'aide et la sortie. Fixe.
     2. `.options-chercher`  : chercher puis filtrer. Fixe (voir plus bas).
     3. `.options`           : les tuiles. LA SEULE ZONE QUI DEFILE.

   ⚠️ POURQUOI PAS LE DEFILEMENT DE LA PAGE. Mounassib decrit « la barre de
   l'ecran » : ce qu'il ne veut pas, c'est une petite barre au milieu d'une
   boite au milieu de la page. La regle 62 interdit par ailleurs a la page de
   l'editeur de defiler, et une mesure la tient (`page qui defile`). La
   reponse est donc une boite qui occupe TOUT l'ecran, dont la zone de tuiles
   descend jusqu'au bord bas : sa barre EST la barre de l'ecran, a l'oeil
   comme au geste, sans qu'aucune page ne defile. */
/* L'en-tete : ce qu'on lit, et la sortie, sur la meme ligne. La sortie est a
   DROITE et non en bas (regle 25 vaut pour le mur ; ici l'animateur est a la
   souris) : une barre de boutons en bas volerait a la liste la hauteur meme
   qui manque au catalogue. */
.catalogue__entete {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 24px;
  flex: 0 0 auto;
}
.catalogue__intitule { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1 1 auto; }
/* La recherche vit dans l'en-tete, pas dans la colonne (2026-09-08) : elle y
   est deux fois plus large qu'en colonne, et c'est ce qui a permis aux
   filtres de tenir sans defiler (680 px de contenu pour 512 de hauteur,
   mesures a 1366x768 avant ce deplacement). Elle grandit jusqu'a 480 px et
   retrecit avant le titre, jamais l'inverse. */
.catalogue__recherche { flex: 0 1 480px; min-width: 220px; align-self: center; }
/* A gauche, jamais centre : l'aide suit le titre, et une ligne centree sous
   un titre cale a gauche donne l'impression de deux blocs sans rapport. */
.catalogue__intitule .modale__aide { text-align: left; max-width: none; }
/* Le corps : la colonne des filtres, puis les tuiles. `min-height: 0` est ce
   qui rend le defilement possible : sans lui, un enfant flex refuse de
   descendre sous la taille de son contenu et c'est la BOITE qui deborde. */
.catalogue__corps {
  display: flex;
  align-items: stretch;
  gap: 24px;
  flex: 1 1 auto;
  min-height: 0;
}

.options {
  /* ─── UNE COLONNE DE RANGEES, PAS UNE GRILLE UNIQUE (2026-09-07) ────────
     Une seule grille CSS partagee par TOUTES les familles reserve le MEME
     nombre de colonnes sur chaque rangee, familles courtes comprises : une
     famille de deux variantes (« Memoire ») ou d'une seule (« Ce qui va
     ensemble ») laissait un grand vide a droite a 1920px -- releve sur une
     vraie capture. `.options` n'est donc plus qu'un conteneur VERTICAL :
     chaque famille pose sa PROPRE rangee (`.options__rangee`, juste apres),
     qui ne reserve que ce qu'elle utilise. */
  display: flex;
  flex-direction: column;
  gap: 18px;
  align-self: stretch;
  /* ⚠️ La liste PREND la place qui reste, elle ne s'arrete pas a une hauteur
     devinee (capture du 2026-08-31). Avec la barre de recherche au-dessus, un
     `max-height` fixe coupait la derniere tuile en deux, sans rien qui dise
     qu'il y avait une suite : l'animateur croyait le catalogue termine. */
  flex: 1 1 auto;
  min-height: 0;
  /* Enfant d'une RANGEE depuis le 2026-09-08 (la colonne des filtres est a
     sa gauche) : sans `min-width: 0`, les tuiles pousseraient la rangee au
     lieu de passer a la ligne, et la colonne de gauche serait comprimee. */
  min-width: 0;
  overflow-y: auto;
  padding-right: 4px;
  /* Un degrade en bas : il DIT qu'il reste des jeux dessous, ce qu'une tuile
     coupee net ne dit pas. Il ne prend aucun clic. */
  mask-image: linear-gradient(to bottom, var(--km-encre) calc(100% - 28px), transparent);
}
/* La rangee d'UNE famille : `flex-wrap` pose autant de cartes que la largeur
   permet (cinq a six a 1920px, mesure reelle), puis passe a la ligne -- une
   famille courte ne montre QUE ses cartes, jamais de colonnes fantomes. Une
   grille CSS avec `auto-fit`/`1fr` a ete essayee et ecartee : elle etire
   les rares cartes d'une famille courte jusqu'a occuper toute la largeur
   (une image de 480px de large affichee sur pres de 900px, floue), la ou
   `flex` avec un `max-width` sur `.option` (juste apres) laisse la place
   inutilisee EN BLOC a la fin de la rangee, jamais entre deux cartes. */
.options__rangee { display: flex; flex-wrap: wrap; gap: 18px; }
.option {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding-bottom: 14px;
  text-align: left;
  cursor: pointer;
  /* `flex: 1 1 300px` : la carte grandit pour remplir sa rangee (jusqu'a
     380px, la photo restant nette) et peut retrecir a 280px quand une
     famille chargee (sept variantes ou plus) demande plus de cartes que la
     largeur n'en offre a 300px pile -- avant de passer a la ligne. */
  /* ─── TROIS PAR RANGEE A 1366, CINQ A 1920 (2026-09-08, lot 1, T1) ────
     Mounassib : « les templates par trois ou quatre ». Mesure dans la vraie
     page : la colonne des filtres prise, il reste 1030 px au centre a 1366.
     A 300 px de base, trois tuiles tenaient deja, mais elles s'etiraient
     jusqu'a 380 px et la carte montait alors a 410 px de haut, pour 484 px
     offerts : la premiere rangee remplissait l'ecran a elle seule et la
     suivante n'apparaissait pas. A 280 px de base et 340 au plus, la carte
     descend a environ 340 px : une rangee entiere ET le haut de la suivante,
     ce qui DIT qu'il y en a d'autres (regle 37 : ce qui ne se voit pas
     n'existe pas). */
  flex: 1 1 280px;
  min-width: 260px;
  max-width: 340px;
  /* ⚠️ PAS de `overflow: hidden` ICI (2026-09-07, corrige apres capture) :
     pose sur `.option`, cette regle ecrasait sa hauteur a 18px dans la
     grille -- un ELEMENT GRID dont l'overflow n'est pas `visible` perd son
     minimum de taille base sur son CONTENU (la regle CSS du minimum
     automatique), et la carte entiere s'effondrait derriere un rectangle
     sombre, texte et photo caches. Voir `.option__vignette` : c'est ELLE
     qui rogne les coins hauts de la photo, sans toucher a la hauteur de
     toute la carte. */
  background: var(--fond-carte);
  border: 2px solid var(--bordure);
  border-radius: 14px;
}
.option:focus-visible, .option:active { border-color: var(--accent); }
/* ─── LA VIGNETTE : LA PHOTO DU JEU, OU L'ICONE EN GRAND ─────────────────
   `aspect-ratio: 16 / 9` colle exactement au format des vignettes produites
   par `scripts/capturer-ecrans.js` (480x270) : aucune deformation. Le fond
   coloré par famille (`data-famille`, plus bas) comble l'instant de
   `loading="lazy"` -- sans lui, un rectangle blanc ferait sauter l'oeil
   d'une tuile a l'autre a mesure qu'elles se chargent (Mounassib : « garder
   la vitesse du site »). Une fiche SANS vignette (ou dont le fichier ne
   charge pas) garde ce meme fond, avec l'icone a la place de la photo :
   jamais de cadre vide (regle 59). */
.option__vignette {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--fond-profond);
  flex-shrink: 0;
  /* Les coins HAUTS seulement (ceux du BAS sont ceux de `.option`, qui n'a
     plus besoin de rogner : voir sa note). `overflow: hidden` porte ICI
     desormais, sur un element dont la hauteur ne depend QUE de son propre
     `aspect-ratio` -- jamais du contenu d'un parent grid, donc sans risque
     pour le calcul de hauteur de la carte. */
  overflow: hidden;
  border-radius: 12px 12px 0 0;
}
.option__photo { width: 100%; height: 100%; object-fit: cover; display: block; }
/* L'icone n'est plus un repere DE TEXTE a cote du titre (2026-09-06 et
   avant) : c'est desormais l'ILLUSTRATION de la carte quand aucune photo ne
   s'affiche, donc bien plus grande -- « l'emoji en tres grand » (le plan,
   T5). L'interligne de 1,4 reste : un emoji colore deborde de la boite que
   lui donnerait une interligne de 1,1 (voir l'historique de cette regle,
   verifie par le controle des debordements). */
.option__vignette .option__icone { font-size: 56px; line-height: 1.4; }

/* Sept familles, sept couleurs -- un remplissage decoratif, jamais un texte
   (les jetons `--km-*` qui portent du texte gardent 4,5:1 de contraste ;
   `--km-cyan` en particulier n'en porte JAMAIS, voir CLAUDE.md § 4 bis). Une
   famille peut reprendre la couleur d'une autre : ce n'est qu'un repli de
   chargement, pas un code couleur a apprendre. */
.option__vignette[data-famille="memoire"] { background: var(--km-cyan); }
.option__vignette[data-famille="langage"] { background: var(--km-bleu); }
.option__vignette[data-famille="ordre"] { background: var(--km-indigo); }
.option__vignette[data-famille="reperage"] { background: var(--km-violet); }
.option__vignette[data-famille="logique"] { background: var(--km-magenta); }
.option__vignette[data-famille="questions"] { background: var(--km-cyan); }
.option__vignette[data-famille="ecoute"] { background: var(--km-indigo); }
/* Le repli (aucune photo, ou une photo qui n'a pas charge) : un degrade
   discret donne du relief a la couleur de famille, plutot qu'un aplat plat
   qui ferait paraitre la tuile inachevee a cote de ses voisines illustrees. */
.option__vignette--repli {
  background-image: radial-gradient(circle at 50% 40%, rgba(255, 255, 255, 0.16), rgba(0, 0, 0, 0.08));
}

/* ─── LE CATALOGUE, QUAND IL Y EN A CENT (2026-08-31) ──────────────────────
   Une liste plate de cent modeles est inutilisable, et c'est le vrai cout de
   la fabrique : pas le poids du paquet (environ 3 % pour cent modeles), mais
   le CHOIX. Les concurrents ne vendent pas un moteur, ils vendent un
   catalogue navigable.

   Les familles, la recherche et les filtres restent DANS la modale : ouvrir
   un second ecran pour choisir un jeu ferait perdre le fil a un animateur qui
   prepare sa seance devant un groupe qui attend. */
/* ─── LA COLONNE DES FILTRES, A GAUCHE (2026-09-08, lot 1, T1) ───────────
   Elle etait une bande horizontale au-dessus des tuiles : elle mangeait
   trois lignes de hauteur, celle-la meme qui manque a un catalogue. A
   gauche, elle ne coute que de la largeur, dont un ecran 16:9 a de reste.

   ⚠️ ELLE NE DOIT PAS DEFILER : c'est tout l'objet de la demande (« pas une
   autre barre »). `overflow-y: auto` n'est la que comme dernier filet, pour
   qu'un contenu plus long qu'aujourd'hui reste ATTEIGNABLE plutot que rogne.
   Un cas de navigateur exige qu'il ne serve jamais a 1366x768, la plus
   petite taille servie (« LA COLONNE DES FILTRES NE DEFILE PAS »). */
.options-chercher {
  display: flex;
  flex-direction: column;
  gap: 14px;
  flex: 0 0 clamp(240px, 17vw, 320px);
  width: clamp(240px, 17vw, 320px);
  min-height: 0;
  overflow-y: auto;
  padding-right: 16px;
  border-right: 2px solid var(--bordure);
}
/* Un groupe de filtres : son intitule, puis ses boutons. Sans intitule, une
   grappe de boutons ne dit pas ce qu'elle fait, et les deux grappes de cette
   colonne ne font PAS la meme chose (l'une aide a choisir, l'autre ecarte). */
.options__groupe { display: flex; flex-direction: column; gap: 6px; }
/* ─── DANS LA COLONNE, DES RANGEES, PAS UNE GRAPPE DE PASTILLES ──────────
   Mesure a 1366x768, la plus petite taille servie (regle 49). Une grappe de
   pastilles de 42 px dans une colonne de 222 px demandait 536 px de contenu
   pour 484 px offerts : chaque pastille prenait sa propre ligne DE TOUTE
   FACON (« memorisation » fait 105 px a elle seule), en payant en plus les
   bordures et les coins de tous les cotes.

   La forme juste pour un filtre a choix unique dans une colonne etroite est
   celle qu'emploie n'importe quel catalogue : une LISTE de rangees pleine
   largeur, sans cadre, celle qui est choisie portant un trait de couleur a
   gauche. On y gagne 110 px, et on y lit mieux : les intitules s'alignent.

   ⚠️ Le texte ne maigrit JAMAIS : il reste a `--km-texte-s`. Ce qui part est
   le rembourrage et le cadre, jamais la lettre (regle des jetons de texte). */
.options-chercher .recherche__competences,
.options-chercher .options__filtres {
  flex-direction: column;
  flex-wrap: nowrap;
  align-items: stretch;
  gap: 2px;
}
.options-chercher .choix--petit {
  width: 100%;
  padding: 5px 10px;
  text-align: left;
  background: transparent;
  border: 0;
  /* Un trait a gauche, transparent tant que rien n'est choisi : la rangee ne
     bouge donc pas d'un pixel quand on la choisit. */
  border-left: 4px solid transparent;
  border-radius: 6px;
}
/* ⚠️ `.choix:hover` (plus bas) pose `border-color: var(--accent)` sur les
   QUATRE cotes. Sur une rangee dont le bord gauche EST le marqueur de
   selection, le survol allumait donc le meme trait que le choix : sur la
   capture du 2026-09-08, « Il faut entendre un son » paraissait coche alors
   que la souris ne faisait que passer dessus. Le survol se contente du fond. */
.options-chercher .choix--petit:hover {
  background: var(--fond-profond);
  border-left-color: transparent;
}
.options-chercher .choix--petit.choisi:hover { border-left-color: var(--accent); }
.options-chercher .choix--petit.choisi {
  color: var(--texte);
  background: var(--fond-profond);
  border-left-color: var(--accent);
}
.options__requete {
  width: 100%;
  padding: 10px 14px;
  font: inherit;
  font-size: var(--km-texte-s);
  color: var(--texte);
  background: var(--fond-profond);
  border: 2px solid var(--bordure);
  border-radius: 10px;
}
.options__requete:focus { outline: none; border-color: var(--accent); }

/* Le filtre par competence (2026-09-05) : au-dessus des exigences. Meme
   agencement que .options__filtres, sous un autre nom -- il n'ecarte pas,
   il aide a choisir. */
.recherche__competences {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}

.options__filtres {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}
.options__filtres-titre { font-size: var(--km-texte-xs); color: var(--texte-doux); }

/* L'en-tete d'une famille : un titre, et la phrase qui dit a qui elle
   s'adresse. Sans la phrase, « Reperage dans l'espace » ne dit rien a un
   animateur qui decouvre le produit. `.options` est une colonne verticale
   (2026-09-07) : plus besoin de `grid-column: 1 / -1`, l'entete est un
   enfant de plein droit qui prend naturellement toute la largeur. Le
   `gap` de `.options` espace deja les entetes de leur rangee -- plus de
   marge a la main ici. */
.options__famille { display: flex; flex-direction: column; gap: 2px; }
.options__famille-titre {
  font-size: var(--km-texte-xs);
  font-weight: 800;
  color: var(--accent-doux);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.options__famille-aide { font-size: var(--km-texte-xs); line-height: 1.35; color: var(--texte-doux); }

/* ─── LES PASTILLES : FAMILLE ET COMPETENCES (2026-09-07, T5) ────────────
   Une carte Netflix montre son genre d'un coup d'oeil, en petite pastille --
   pas en phrase pleine largeur. */
.option__pastilles { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.option__famille {
  padding: 3px 10px;
  font-size: var(--km-texte-xs);
  font-weight: 800;
  color: #fff;
  background: var(--km-degrade);
  border-radius: 999px;
  white-space: nowrap;
}
/* Ce que la variante travaille (2026-09-05) : le filtre par competence n'est
   pas la seule facon de le savoir, la tuile le dit aussi. Devenue une
   pastille au lieu d'une ligne de texte (T5) : elle vit desormais DANS
   `.option__pastilles`, a cote de la famille. */
.option__competences {
  padding: 3px 10px;
  font-size: var(--km-texte-xs);
  color: var(--texte-doux);
  background: var(--fond-profond);
  border: 1px solid var(--bordure);
  border-radius: 999px;
}

/* Ce que le jeu demande au joueur, dit sur la tuile : l'animateur le voit
   AVANT de choisir, pas devant le groupe. Reste une ligne A PART des
   pastilles : c'est un frein, pas une information decorative. */
.option__exige {
  margin-top: 2px;
  font-size: var(--km-texte-xs);
  font-weight: 700;
  color: var(--accent-doux);
}

/* ⚠️ Une liste vide n'est JAMAIS muette : un ecran vide passe pour une panne,
   et l'animateur ne saurait pas que ce sont SES filtres qui l'ont videe.
   `.options` est une colonne (2026-09-07) : ce message prend deja toute sa
   largeur sans rien de plus a poser. */
.options__rien {
  padding: 18px 4px;
  font-size: var(--km-texte-xs);
  line-height: 1.45;
  color: var(--texte-doux);
}
.option__corps { display: flex; flex-direction: column; gap: 6px; min-width: 0; padding: 0 16px; }
/* Tailles retenues avec Mounassib pour le catalogue en tuiles (T5) : le
   titre et l'explication montent d'un cran par rapport a l'ancienne liste
   plate, une carte plus large que haute a la place pour les porter. */
.option__titre { font-weight: 800; font-size: var(--km-texte-m); }
.option__explication { font-size: var(--km-texte-s); line-height: 1.35; }
/* `.option__pour-qui` a QUITTE la carte (2026-09-07, revue du coordinateur) :
   un conseil d'usage de trois a cinq lignes ne tient jamais sans trancher
   une phrase. Il vit desormais en infobulle du titre (`titre.title`,
   voir `_poserLaTuile()`) -- rien a habiller ici. */
/* `flex-shrink: 0` : le compte ne bouge pas, mais il ne prend pas non plus la
   place du titre — c'est le titre qui doit rester lisible en entier. */
/* Le compte vit sur la SECONDE ligne, aupres du nom du jeu, dans la colonne
   sombre : il herite du blanc de .manche__jeu (etape 3, tache 3). Il ne
   redefinit plus sa couleur -- var(--texte-doux) y devenait illisible, un
   bleu sombre sur le meme aplat sombre. */
.manche__compte { opacity: 0.9; }

/* Grille des paires */
/* ─── UNE GRILLE, PAS UN FLEX (2026-09-07) ──────────────────────────────
   Mesure AVANT correction (regle 49), en pixels de DESIGN (voir la mise en
   garde plus bas) : la grille offre 1508 px de large, une tuile fait
   naturellement 184 px, et DOUZE paires en occupent sept par rangee, sur
   DEUX rangees, sans deborder (« manque: 0 » : la hauteur disponible est
   remplie a zero pres, donc une troisieme rangee ferait deborder). A DEUX
   paires en revanche, les tuiles gardaient ce meme 184 px : le centre de
   l editeur restait vide aux trois quarts au lieu de profiter de la
   largeur offerte.

   ⚠️ LE PIEGE DE MESURE (a ne pas refaire) : `getBoundingClientRect()`
   rend des pixels d ECRAN, apres le `transform: scale()` que
   `editeur-seance.html` pose sur `#scene` pour adapter le canevas
   1920x1080 a la fenetre reelle (`ajusterEchelle()`). Le mesurer ainsi
   puis l ecrire tel quel dans le CSS revient a m elanger deux echelles :
   un premier essai avait ainsi RETRECI les tuiles au lieu de les
   agrandir. `offsetWidth` (ou `getComputedStyle().width`), qui ignore ce
   transform, donne le vrai pixel de conception, celui dans lequel TOUT
   le reste de cette feuille de style est deja ecrit (`.vignette` a 64px,
   `.paire--ajout` a 118px...).

   ⚠️ LE COUPLAGE A EVITER : `repeat(auto-fit, minmax(min, max))` calcule
   le NOMBRE de colonnes sur le plus grand des deux bornes qui soit une
   longueur definie, donc sur `max` des qu il en est une. Fixer un `max`
   en pixels assez haut pour agrandir vraiment les tuiles (par exemple
   260px) aurait donc RECALCULE le nombre de colonnes a la baisse (5 au
   lieu de 7 a 1508px) et fait passer DOUZE paires a TROIS rangees, la
   meme regression que la retouche doit eviter. La sortie : poser `max` a
   `1fr` (indefini, donc le calcul retombe sur `min` : sept colonnes,
   inchange), et borner la tuile elle-meme par un vrai `max-width` : la
   COLONNE peut s elargir librement, la TUILE qui vit dedans, non.

   ⚠️ `margin-inline: auto` SEUL DESACTIVE L ETIREMENT, IL NE CENTRE RIEN
   (eprouve dans une page isolee, 2026-09-07) : un item de grille dont la
   largeur reste `auto` et qui porte des marges horizontales `auto` n est
   PAS etire par la grille : la specification l exempte justement de
   l etirement pour lui laisser sa taille de contenu. Pose seul, il gardait
   donc les tuiles a 184px, aussi vide qu avant la correction. Il faut
   d abord rendre la largeur DEFINIE (`width: 100%`, resolue contre la
   colonne, puis plafonnee par `max-width`) : alors la largeur n est plus
   `auto`, l etirement ne joue plus aucun role, et `margin-inline: auto`
   absorbe correctement ce que `max-width` a refuse de remplir, centrant la
   tuile dans le surplus de sa colonne.

   ⚠️ CE QUI DEBORDAIT VRAIMENT N ETAIT PAS UN ARRONDI (piste suivie et
   abandonnee, 2026-09-07 : forcer une division entiere par tuile, via
   `gap`, n avait rien change, la preuve que ce n etait pas la cause).
   `tests/navigateur/editeur-web.js` mesure `scrollWidth`, insensible a
   `overflow-x`, et localiser precisement l element dont le bord DEPASSE
   celui de `.grille-paires` a designe `.paire__croix` : son `right: -8px`
   la fait deborder de 8px HORS de sa propre tuile, EXPRES (le bouton doit
   se voir en entier, meme dans le coin). En `flex-wrap`, la derniere tuile
   d une rangee laissait toujours une marge non consommee a sa droite (le
   flex ne s etirait jamais pour remplir la rangee), et ce debordement s y
   logeait sans jamais atteindre le bord du conteneur. La grille, qui etire
   les tuiles jusqu au bord, amene desormais la derniere croix d une
   rangee COMPLETE jusqu au bord reel, d ou le `padding-right` de
   `.grille-paires`, qui lui rend la place qu elle a toujours eue.
   `overflow-x: hidden` reste pose en filet : `.grille-paires` ne s agrandit
   qu en HAUTEUR, jamais en largeur, un debordement horizontal serait donc
   toujours un defaut, jamais un defilement voulu. */
.grille-paires {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(184px, 1fr));
  align-content: start;
  /* 10px, pas 14px (2026-09-07, T4) : quatre points repris pour faire de la
     place a la barre des reglages, sans se voir a l'oeil sur une grille de
     cette densite. */
  gap: 10px;
  overflow-x: hidden;
  overflow-y: auto;
  flex: 1;
  /* `padding-right: 12px` rend a `.paire__croix` la place qu elle a
     toujours eue pour deborder de sa tuile (8px d aplomb, 4px de reserve) :
     voir la note au-dessus de ce bloc pour le raisonnement complet. */
  padding: 2px 12px 2px 2px;
  /* ─── LE DERNIER FILET, ET IL DOIT SE VOIR (2026-09-07, T1) ─────────────
     `overflow-y: auto` ci-dessus ne sert JAMAIS a 900px de haut ou plus
     (« DOUZE PAIRES ET LA TUILE + TIENNENT SANS QUE LA GRILLE DEFILE » le
     garantit : plafond ABSOLU, aucun defilement). Sous 800px
     (tests/navigateur/editeur-web.js,
     HAUTEUR_SOUS_LAQUELLE_LA_GRILLE_PEUT_DEFILER), meme resserree au
     plancher de lisibilite, la grille peut manquer quelques pixels pour
     DOUZE paires : le filet sert alors, et Mounassib a choisi la lisibilite
     plutot que de rogner les marges plus loin. Le meme fondu que `.options`
     (le catalogue de templates, juste au-dessus dans ce fichier) : sans
     lui, une tuile a moitie visible en bas semblerait coupee net plutot que
     dire qu'il y en a d'autres dessous. */
  mask-image: linear-gradient(to bottom, var(--fond) calc(100% - 20px), transparent);
}
.paire {
  /* `relative` : le rang de la suite se pose dans le coin de la tuile. */
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 10px;
  background: var(--fond-profond);
  border: 3px solid var(--bordure);
  border-radius: 16px;
  cursor: pointer;
  /* Le plafond de croissance (voir la note de `.grille-paires`) : une
     colonne isolee peut s elargir jusqu a occuper toute la grille, mais la
     tuile qui la remplit s arrete a 260px (environ 1,4 fois son format
     d origine) : au-dela, une carte de 130px de haut s etire en bandeau
     plutot que de paraitre agrandie. `width: 100%` rend la largeur
     DEFINIE (necessaire pour que `margin-inline: auto` centre au lieu de
     desactiver l etirement, voir la note ci-dessus) ; `max-width` la
     plafonne ensuite. */
  width: 100%;
  max-width: 260px;
  margin-inline: auto;
}
.paire:hover { border-color: var(--accent); }
/* Une paire qui en répète une autre. Le liseré rouge se voit d'un coup d'œil ;
   le bandeau au-dessus de la grille dit ce que ça signifie et le répare. */
.paire--doublon { border-color: var(--corail); background: var(--km-alerte-fond); }
.paire--ajout {
  /* `justify-self`/`align-self` : la tuile « + » garde une taille FIXE
     (118x96, le pictogramme ne grandit pas avec la grille), elle se
     centre donc dans sa case au lieu de rester collee au coin quand la
     case grandit autour d elle (voir la note de `.grille-paires`). Une
     largeur EXPLICITE ignore de toute facon `max-width` et
     `margin-inline: auto` herites de `.paire` : ce sont ces deux regles,
     et non celles-ci, qui bornent et centrent la tuile « + ». */
  justify-content: center;
  justify-self: center;
  align-self: center;
  width: 118px;
  height: 96px;
  font-size: var(--km-texte-2xl);
  color: var(--accent);
  border-style: dashed;
}
/* Au plafond de paires : la tuile RESTE, en retrait. Un bouton qui s'evapore
   passe pour une panne — celui-ci explique pourquoi il ne repond plus. */
.paire--ajout-max { opacity: 0.4; color: var(--texte-doux); cursor: default; }
.paire__cartes { display: flex; align-items: center; gap: 6px; }
/* Le bouton « Modifier », sous chaque paire : la tuile entiere reste
   cliquable, mais une zone cliquable qui ne se voit pas n'existe pas. */
.paire__modifier {
  padding: 4px 14px;
  font-family: inherit;
  font-size: var(--km-texte-s);
  font-weight: 600;
  color: var(--texte-doux);
  background: transparent;
  border: 2px solid var(--bordure);
  border-radius: 10px;
  cursor: pointer;
}
.paire:hover .paire__modifier { color: var(--texte); border-color: var(--accent); }
/* La croix et le dupliquer : en PERMANENCE visibles dans les coins de la
   tuile (regle 37, 2026-09-06) — un ballon ne peut pas « survoler », une
   zone cliquable qui ne se voit qu'au survol n'existe pas pour lui. */
.paire__croix, .paire__dupliquer {
  position: absolute;
  top: -8px;
  width: 26px;
  height: 26px;
  padding: 0;
  font-family: inherit;
  font-size: var(--km-texte-xs);
  line-height: 1;
  color: var(--texte-doux);
  background: var(--fond-carte);
  border: 2px solid var(--bordure);
  border-radius: 50%;
  cursor: pointer;
}
.paire__croix { right: -8px; }
.paire__dupliquer { left: -8px; }
.paire__croix:hover, .paire__dupliquer:hover { color: var(--texte); border-color: var(--accent); }
.paire__signe { font-size: var(--km-texte-m); color: var(--texte-doux); }
/* 64 px et non 74 : avec la tuile « + », douze paires font alors 7 par rangée
   et tiennent en DEUX rangées, sans défiler (mesure du 2026-08-19). */
.vignette {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 64px;
  height: 64px;
  background: var(--creme);
  border-radius: 10px;
  overflow: hidden;
}
/* Regle 54 : la vignette montre la carte comme le mur la montrera, image en
   plein cadre. */
.vignette img { width: 100%; height: 100%; object-fit: cover; }
.vignette--vide { background: var(--fond-carte); border: 2px dashed var(--bordure); }
/* Une carte de MOT se montre telle qu'elle sera au mur : le texte lui-même.
   Une vignette vide à sa place ferait croire à une carte manquante. */
.vignette--mot {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 4px;
  font-weight: 800;
  font-size: var(--km-texte-xs);
  line-height: 1.05;
  text-align: center;
  overflow-wrap: break-word;
  hyphens: none;
  background: var(--fond-carte);
  border: 2px solid var(--bordure);
}
/* Une carte de COULEUR (jeu de suite) : le meme aplat que le mur, mais en
   plein cadre — regle 54, appliquee a une couleur comme a une image
   (2026-09-06, plan directeur § 8, 3.4). `.carte__couleur` porte 84 % / 14 px
   dans le CSS du mur : trop petit pour une vignette de 64 px, ou l'aplat
   devait se voir en entier. */
.vignette--couleur { background: var(--fond-carte); border: 2px solid var(--bordure); }
.vignette--couleur .carte__couleur { display: block; width: 100%; height: 100%; border-radius: 8px; }

/* Le bandeau des paires en double, au-dessus de la grille du bloc ②. */
.editeur__doublons {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 10px 16px;
  font-size: var(--km-texte-m);
  color: var(--corail);
  background: var(--km-alerte-fond);
  border: 2px solid var(--corail);
  border-radius: 12px;
}

/* ③ Réglages
   ─── POURQUOI UNE GRILLE, ET PAS UNE LIGNE QUI S'ENROULE ───
   Mesuré le 2026-08-19 : en flex-wrap, chaque phrase d'aide (largeur 100 %)
   cassait la ligne et renvoyait les réglages suivants au-dessous. Le bloc ③
   occupait 369 px pour 283 px de contenu, et il ne restait que 190 px aux
   paires — qui en réclamaient 298. En colonnes de largeur fixe, les aides
   restent dans leur cellule : 7 réglages tiennent en 2 rangées. */
.reglages { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 20px; }
/* ─── LE BLOC ③ SE MESURE AU PIXEL, ET IL A GRANDI (2026-09-05) ───
   Les réglages universels (logo, deux sons, phrase d'après l'erreur) ont porté
   le bloc ③ de 157 à 314 px, et ces 157 px se prenaient sur la grille des
   paires : douze paires et la tuile « + » ne tenaient plus. Mesuré, pas
   estimé (règle 49). Les boutons de CE bloc sont donc plus compacts que ceux
   des modales : l'éditeur se tient à la souris, sur le PC de
   l'établissement, et non au ballon. */
.reglages .choix { min-width: 0; padding: 6px 14px; font-size: var(--km-texte-s); border-width: 2px; }
/* Les réglages qui appartiennent à la MANCHE (le tirage au sort) : même
   apparence, mais rangés dans le bloc ② à côté de ce qu'ils concernent. */
/* Le tirage vit seul dans le bloc ② : sa ligne et son aide, l'une sous l'autre. */
.reglages--manche { flex-direction: column; align-items: flex-start; gap: 4px; }
.reglage { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; }
.reglage__nom { font-size: var(--km-texte-s); color: var(--texte-doux); min-width: 0; }
.reglage__choix { display: flex; align-items: center; gap: 8px; }
/* La phrase qui explique un réglage — et surtout pourquoi un choix est grisé.
   Un bouton grisé sans explication passe pour une panne (constaté le
   2026-08-17 : « j'ai l'impression qu'ils ne proposent plus deux équipes »). */
.reglage__aide {
  /* En DERNIER, quel que soit le réglage qui l'a produite : une aide glissée
     entre deux réglages casse la ligne et vole 149 px à la grille des paires. */
  order: 99;
  width: 100%;
  margin-top: -2px;
  /* 16 px : le plancher de tout l'éditeur (2026-09-06, tâche 6, famille 4 du
     garde-fou des débordements). Vaut pour l'aide du puzzle comme pour
     toutes les autres — un seul réglage, jamais un cas particulier. */
  font-size: var(--km-texte-xs);
  line-height: 1.3;
  color: var(--texte-doux);
}
/* L'aperçu du fond d'écran choisi. « Changer le fond » dit qu'un fond existe ;
   il ne dit pas LEQUEL — et l'animateur devait lancer une partie pour le voir. */
.reglage__apercu {
  display: block;
  width: 96px;
  height: 54px;                 /* 16:9, comme le mur */
  overflow: hidden;
  background: var(--fond-profond);
  border: 2px solid var(--bordure);
  border-radius: 8px;
  flex: 0 0 auto;
}
.reglage__apercu img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* « Aucun fond » : l'etat vide se voit, au lieu de laisser deviner. */
.reglage__apercu--vide {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--km-texte-xs);
  color: var(--texte-doux);
}
/* Une phrase que l'animateur ÉCRIT : le texte affiché après une erreur, le
   mot à lire ou le bruitage à chercher. La règle 38 (ne rien faire taper qui
   puisse être choisi) ne s'applique pas ici : une liste toute faite
   laisserait toujours dehors « Pas grave ! », un prénom, ou la phrase que
   cette maison-là emploie. */
.reglage__texte {
  flex: 0 0 230px;
  padding: 6px 12px;
  font-family: inherit;
  font-size: var(--km-texte-s);
  color: var(--texte);
  background: var(--fond-carte);
  border: 2px solid var(--bordure);
  border-radius: 10px;
}
/* Le champ des sons partage sa ligne avec quatre boutons : il est donc plus
   court encore, sinon la ligne déborderait sur la suivante. */
.reglage__texte--court { flex: 0 0 170px; }
/* Le son posé se NOMME : « son-1a2b3c.mp3 » ne dit rien de ce qu'on entendra
   (règle 35, transposée au son). */
.reglage__son { font-size: var(--km-texte-s); color: var(--texte-doux); }
/* Second appui attendu : le bouton dit qu'il attend une confirmation. */
.choix--confirmer {
  background: var(--corail);
  color: #fff;
  border-color: transparent;
}
/* L'image actuellement posee en fond, marquee dans la banque. */
.banque__element--actuel .vignette { outline: 4px solid var(--accent); }

.choix {
  min-width: 96px;
  padding: 10px 20px;
  font-family: inherit;
  font-size: var(--km-texte-m);
  font-weight: 600;
  color: var(--texte);
  background: var(--fond-profond);
  border: 3px solid var(--bordure);
  border-radius: 12px;
  cursor: pointer;
  transition: border-color var(--transition), background var(--transition);
}
.choix--petit { min-width: 0; padding: 8px 16px; font-size: var(--km-texte-s); }
/* Le dégradé du logo, sur le bouton d'action principale (2026-09-06). */
.choix--valider { background: var(--km-degrade); border-color: transparent; color: #fff; }
.choix:hover { border-color: var(--accent); }
/* Ce qui est choisi passe au magenta : la couleur du bas des lettres du logo,
   jamais confondue avec l'accent (le bleu de l'action). */
.choix.choisi {
  border-color: var(--km-magenta);
  color: var(--km-magenta);
  background: rgba(187, 12, 165, 0.12);
}
.choix:disabled { opacity: 0.4; cursor: default; }

/* ─── Modales de l'editeur ─── */
.modale {
  position: absolute;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(27, 31, 58, 0.55);
}
.modale__boite {
  padding: 32px 40px;
  background: var(--fond-carte);
  border: 3px solid var(--bordure);
  border-radius: 24px;
  display: flex;
  flex-direction: column;
  gap: 20px;
  /* ─── LE DEFAUT S'INVERSE : ON S'ETIRE (2026-09-08, T1.8) ──────────────
     ⚠️ C'EST UN PIEGE QUI A DEJA COUTE DEUX FOIS, LE MEME JOUR. Cette boite
     est une COLONNE flex : avec `align-items: center`, tout enfant se reduit
     a la largeur de son CONTENU au lieu d'occuper la boite. Une grille en
     `repeat(auto-fill, minmax(120px, 1fr))` n'a alors qu'UNE colonne a
     remplir : elle SAIT faire quatre colonnes, et elle n'en montre qu'une.
     C'est arrive a `.options` (le catalogue de templates) le matin du
     2026-09-07, puis a `.banque` (la bibliotheque d'images) : une recherche
     qui rend onze images n'en montrait qu'UNE, dans une colonne etroite au
     milieu d'une modale large et vide (capture de Mounassib, 2026-09-08).
     Chacune a d'abord ete corrigee chez elle, par un `align-self: stretch`.
     Deux exceptions ecrites l'une apres l'autre pour le meme defaut, c'est le
     signal du § 3 bis 0 du CLAUDE.md : la decision vivait au mauvais endroit.
     Le defaut devient donc « je m'etire », qui est ce que veut tout enfant
     porteur de contenu, et les rares elements qui doivent rester au milieu le
     DISENT (juste en dessous : le titre, l'aide, les rangees de boutons).
     Ce sens-la ne se defait pas en silence : un enfant qui s'etire trop se
     VOIT, un enfant qui se reduit a une colonne passe pour un manque de
     resultats. */
  align-items: stretch;
  /* ─── EN PART DE LA SCÈNE, PLUS DE LA FENÊTRE (2026-09-07) ─────────────
     `vw`/`vh` mesurent la fenêtre RÉELLE du navigateur, barre du site et
     pied de page légal compris. `.modale` (le fond assombri, juste
     au-dessus) occupe toute la scène disponible (`inset: 0`), qui est plus
     COURTE que la fenêtre : `92vh` pouvait donc dépasser la scène et
     déborder de la page (constaté le 2026-09-07, `page qui defile`, à
     1366×768). Une part de `.modale` s'adapte toujours, quelle que soit la
     hauteur que la barre et le pied de page laissent réellement. */
  max-width: 92%;
  max-height: 92%;
}
/* ─── LE CATALOGUE : TOUTE LA SCENE (2026-09-08, lot 1, T1) ──────────────
   ⚠️ CETTE REGLE DOIT RESTER APRES `.modale__boite`, dont elle annule le
   `max-width: 92%`. Les deux ont la MEME specificite : c'est l'ORDRE seul
   qui decide, et posee plus haut dans le fichier (avec le reste de la mise
   en page du catalogue) elle etait ignoree en silence -- 1257 px sur 1366
   mesures. La mise en page proprement dite vit plus haut, avec `.options`. */
.modale__boite--catalogue {
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  /* Aucun rayon ni bordure : une boite qui touche les quatre bords n'a plus
     de dehors a montrer, et un coin arrondi y laisserait voir l'editeur
     assombri, ce qui ferait croire a une fenetre posee de travers. */
  border-radius: 0;
  border-width: 0;
  padding: 16px 24px 0;
  gap: 12px;
  align-items: stretch;
}
/* La modale du catalogue occupe toute la hauteur disponible : a dix-neuf jeux
   la liste debordait deja, a cent elle deborderait bien plus.
   `92%` de `.modale` (donc de la scene), plus `92vh` de la fenetre
   (2026-09-07) : meme raison qu'au-dessus de `.modale__boite`. */
.modale__boite--large { width: 1100px; height: 92%; }
/* ─── CE QUI RESTE AU MILIEU LE DIT (2026-09-08, T1.8) ────────────────────
   Depuis que `.modale__boite` s'etire par defaut (voir sa note), ces
   elements-ci demandent explicitement le centrage. Ils ont un point commun :
   ce sont des LIGNES COURTES (un titre, une phrase, une rangee de boutons).
   Tout ce qui porte du contenu -- une grille, un formulaire, une photo --
   s'etire, et c'est le bon defaut. */
.modale__titre { font-size: var(--km-texte-xl); font-weight: 800; text-align: center; }
.modale__aide {
  font-size: var(--km-texte-m);
  color: var(--texte-doux);
  text-align: center;
  max-width: 620px;
  margin-inline: auto;
}
/* Le refus d'une paire en double : la fenêtre reste ouverte, l'animateur voit
   pourquoi et corrige sans perdre ce qu'il avait commencé. */
.modale__alerte {
  max-width: 620px;
  padding: 10px 16px;
  font-size: var(--km-texte-m);
  text-align: center;
  color: var(--corail);
  background: var(--km-alerte-fond);
  border: 2px solid var(--corail);
  border-radius: 12px;
}
.modale__boutons { display: flex; gap: 20px; justify-content: center; }

.paire-edition { display: flex; align-items: center; justify-content: center; gap: 26px; }
/* ─── LE BLOC DU SON SE COMPREND SANS MODE D'EMPLOI (2026-09-08, T1.12) ───
   Il portait trois boutons, un champ et deux boutons de plus, sans un seul
   intitule. Le titre et sa phrase prennent toute la largeur du groupe pour
   que les boutons restent alignes en dessous. */
.paire-edition__sons-titre {
  flex-basis: 100%;
  font-size: var(--km-texte-m);
  font-weight: 700;
  color: var(--texte);
}
/* L'en-tete de la liste des bruitages proposes (2026-09-08, T1.12) : sans
   elle, on lisait « freesound » et « lion » sans savoir de quoi il
   s'agissait. */
.sons-trouves__titre {
  margin: 0 0 6px;
  font-size: var(--km-texte-s);
  font-weight: 700;
  color: var(--texte);
}
.paire-edition__sons-aide {
  flex-basis: 100%;
  margin: 0;
  font-size: var(--km-texte-xs);
  color: var(--texte-doux);
}
.paire-edition__cote { display: flex; flex-direction: column; align-items: center; gap: 10px; }
.paire-edition__cote figcaption { font-size: var(--km-texte-m); color: var(--texte-doux); }
.paire-edition__lien { font-size: var(--km-texte-2xl); color: var(--accent); }
.paire-edition__vignette {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 190px;
  height: 190px;
  background: var(--creme);
  border-radius: 16px;
  overflow: hidden;
}
/* Regle 54 : meme plein cadre que la carte du mur. */
.paire-edition__vignette img { width: 100%; height: 100%; object-fit: cover; }
/* La face d'une carte, EXACTEMENT comme le mur la dessine (image, mot ou
   couleur), posee DANS `.paire-edition__vignette` (2026-09-06, plan
   directeur § 8, 3.4). ⚠️ PAS la classe `.carte__face` du mur : elle porte
   `transform: rotateY(180deg)` et `position: absolute` (le retournement 3D
   de la carte au mur) — appliques ici, ils miroiteraient le contenu et le
   sortiraient du flux, puisque cet apercu ne fait jamais partie d'un
   retournement. `.apercu-carte` fournit donc son propre cadre. */
.apercu-carte {
  width: 190px;
  height: 190px;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  border-radius: 16px;
  background: var(--creme);
}
.apercu-carte img { width: 100%; height: 100%; object-fit: cover; }
/* L'apercu herite lui aussi de `.carte__mot` depuis le 2026-09-08 :
   son exception n'a plus lieu d'etre. */
/* L'aperçu montre le mot comme le mur le montrera : gros, centré, en gras. */
.apercu-mot {
  width: 88%;
  font-weight: 800;
  font-size: var(--km-texte-xl);
  line-height: 1.05;
  text-align: center;
  overflow-wrap: break-word;
  hyphens: none;
}
/* « ou écrivez un mot » : le champ qui remplace l'image par du texte. */
.paire-edition__mot {
  width: 100%;
  margin-top: 8px;
  padding: 8px 10px;
  font: inherit;
  font-size: var(--km-texte-xs);
  text-align: center;
  color: var(--texte);
  background: var(--fond-carte);
  border: 2px solid var(--bordure);
  border-radius: 10px;
}
.paire-edition__mot:focus { outline: none; border-color: var(--accent); }

/* ─── LA PALETTE : une carte peut n'être qu'une couleur ─────────────────────
   Ni lecture, ni image — c'est ce qui rend le jeu de suite accessible à un
   groupe où le langage manque. Chaque pastille porte le nom de sa couleur,
   pour que l'animateur puisse la dire à voix haute. */
.palette { display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; margin-top: 8px; }
.palette__pastille {
  width: 30px;
  height: 30px;
  padding: 0;
  cursor: pointer;
  border: 2px solid var(--bordure);
  border-radius: 8px;
}
.palette__pastille--choisie { border-color: var(--texte); border-width: 3px; }

/* ─── L'ORDRE, QUAND IL EST LA SUITE ELLE-MÊME ──────────────────────────────
   « Retrouver votre suite » : l'animateur compose l'ordre, il doit donc le
   VOIR. Le rang se lit d'un coup d'œil, et deux flèches suffisent à changer
   une carte de place — un glisser-déposer serait moins clair et marcherait
   mal au doigt. */
.paire__rang {
  position: absolute;
  top: 4px;
  left: 6px;
  min-width: 20px;
  padding: 1px 5px;
  font-size: var(--km-texte-xs);
  font-weight: 800;
  text-align: center;
  color: var(--km-encre);
  background: var(--km-cyan);
  border-radius: 999px;
}
.paire__ordre { display: flex; gap: 4px; justify-content: center; margin-top: 4px; }
.paire__fleche {
  min-width: 30px;
  padding: 2px 6px;
  font-size: var(--km-texte-xs);
  color: var(--texte);
  cursor: pointer;
  background: var(--fond-profond);
  border: 2px solid var(--bordure);
  border-radius: 8px;
}
.paire-edition__meme { display: flex; align-items: center; gap: 8px; font-size: var(--km-texte-m); }

/* Le cote SON des variantes sonores (2026-08-25) : micro, voix lue,
   bruitage, ecoute. Quatre petits gestes en colonne serree. */
.paire-edition__sons {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: center;
}
.paire-edition__meme input { width: 22px; height: 22px; }

/* ─── LES BRUITAGES TROUVES, UNE LISTE A ECOUTER (2026-09-06, tache 8) ────
   « Bruitage » ne pose plus le premier resultat tout seul : chaque piste
   proposee s'ecoute (▶) avant d'etre choisie, comme un catalogue plutot
   qu'un pari. */
.sons-trouves {
  display: flex;
  flex-direction: column;
  gap: 6px;
  width: 100%;
  max-height: 220px;
  overflow-y: auto;
  margin-top: 8px;
  font-size: var(--km-texte-xs);
}
.son-trouve {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px;
  background: var(--fond-profond);
  border-radius: 10px;
}
.son-trouve span { flex: 1; min-width: 0; overflow-wrap: anywhere; }

.images-actions { display: flex; gap: 12px; justify-content: center; }
/* Les trois sections de la modale d'images : les motifs livrés, ce que
   l'établissement possède, et la bibliothèque libre de droits (2026-09-06,
   plan directeur § 8, 3.5 — remplace les deux onglets qui mélangeaient les
   soixante motifs avec les quelques photos de la maison). Les boutons
   reprennent `.choix.choix--petit` et `.choisi` : le même patron que partout
   ailleurs dans l'éditeur, pas un second système d'onglets à entretenir. */
.images-sections { display: flex; gap: 10px; justify-content: flex-start; }
.images-recherche { display: flex; gap: 10px; width: 100%; }
.images-recherche input {
  flex: 1;
  padding: 10px 14px;
  font-family: inherit;
  font-size: var(--km-texte-m);
  color: var(--texte);
  background: var(--fond-profond);
  border: 2px solid var(--bordure);
  border-radius: 10px;
}
/* Ce que la bibliothèque a répondu — y compris « pas de connexion », qui est
   un état NORMAL sur une borne d'établissement et se dit sans alarmer. */
.images-note { font-size: var(--km-texte-s); color: var(--texte-doux); text-align: center; }

/* Plus de `max-height` deviné (2026-09-06) : la boîte de la modale
   (`.modale__boite--large`) a une hauteur FIXE (92% de la scène depuis le
   2026-09-07, flex-direction: column), et la banque prend ce qui reste sous
   le titre, les sections et les
   actions — comme `.options` du catalogue de templates. Une grille plutôt
   qu'une ligne qui s'enroule : chaque vignette garde sa largeur, quel que
   soit le nombre de colonnes que la fenêtre laisse tenir. */
.banque {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  gap: 12px;
  align-content: flex-start;
  overflow-y: auto;
  flex: 1 1 auto;
  min-height: 0;
  padding: 4px;
}
/* Des vignettes plus grandes dans la banque (96 px) que dans la grille des
   paires (64 px) : on choisit ici, on ne fait qu'y jeter un oeil là-bas. */
.banque .vignette { width: 96px; height: 96px; }
.banque__element {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 8px;
  background: var(--fond-profond);
  border: 3px solid var(--bordure);
  border-radius: 14px;
  cursor: pointer;
}
.banque__element:hover { border-color: var(--accent); }
/* ─── « Choisir » SE VOIT SUR CHAQUE VIGNETTE (2026-09-08, T1.10) ─────────
   Regle 37 : une zone cliquable qui ne se voit pas n'existe pas. La vignette
   ETAIT le bouton, et rien ne le disait.
   ⚠️ `pointer-events: none` : la pastille n'est pas une cible, c'est un
   PANNEAU. Le clic traverse et va a la figure, qui porte le `data-cible` --
   sinon le filtre a ballon compterait deux zones pour un seul geste, et le
   bord entre les deux ne repondrait a rien.
   ⚠️ Elle est visible EN PERMANENCE, pas au survol : la borne se pilote au
   ballon et un mur n'a pas de survol ; et sur le site, une pastille qui
   n'apparait qu'au survol ne se voit pas AVANT qu'on cherche. */
.banque__choisir {
  pointer-events: none;
  padding: 2px 12px;
  font-size: var(--km-texte-xs);
  font-weight: 700;
  color: var(--fond);
  background: var(--accent);
  border-radius: 9999px;
}
.banque__element:hover .banque__choisir,
.banque__element:focus-within .banque__choisir { background: var(--succes); }
/* Plus d'ellipse (2026-09-06) : un titre long se lit en entier, sur
   plusieurs lignes, plutôt que d'être coupé au milieu d'un mot (règle 62). */
.banque__element figcaption {
  max-width: 120px;
  font-size: var(--km-texte-xs);
  color: var(--texte-doux);
  overflow-wrap: anywhere;
  white-space: normal;
  text-align: center;
}
.banque__separateur {
  /* `.banque` est une GRILLE depuis le 2026-09-06 : un simple `width: 100%`
     ne remplirait qu'UNE cellule, pas la ligne entière (c'était le cas en
     `flex-wrap`, ou une largeur de 100 % force le retour à la ligne). */
  grid-column: 1 / -1;
  margin: 6px 0 2px;
  font-size: var(--km-texte-m);
  font-weight: 700;
  color: var(--texte-doux);
}

/* ─── LE BLOC ② QUAND LA MANCHE EST UN PUZZLE (2026-08-31) ─────────────────
   Un puzzle n'a pas de paires : il a UNE image et une decoupe. Le bloc montre
   donc l'image en grand (regle 35 : on montre l'image, jamais son nom), et la
   decoupe juste dessous, avec les memes boutons de reglage que partout
   ailleurs. */
/* ⚠️ LE BOUTON NE SE FAIT PAS ECRASER PAR L'APERCU (2026-09-08, T1.9).
   Mesure a 1130x915 : « Choisir l'image » recevait 32 px pour les 75 qu'il
   demande, et son texte etait coupe (regle 62). La cause n'est pas la
   largeur de la fenetre mais l'apercu, dont la taille est fixe et qui ne
   cede rien : le bouton etait le seul enfant retrecissable de la rangee.
   `flex-shrink: 0` sur le bouton, et `flex-wrap` sur la rangee : si un jour
   les deux ne tiennent plus cote a cote, le bouton passe DESSOUS, entier.
   Un texte qui passe a la ligne se lit ; un texte coupe, non. */
.puzzle-choix {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 18px;
  width: 100%;
  padding: 14px;
  background: var(--fond-carte);
  border: 1px solid var(--bordure);
  border-radius: var(--rayon);
}
.puzzle-choix .choix { flex-shrink: 0; }
/* L'apercu est GRAND : c'est cette image que le groupe verra sur tout le mur,
   et une vignette de 64 px ne dit pas si elle est reconnaissable. */
.vignette--puzzle {
  width: 168px;
  height: 168px;
  flex: 0 0 auto;
  border-radius: 14px;
}
.puzzle-decoupe { width: 100%; }
/* « + Un autre puzzle » : un peu d'air au-dessus, pour ne pas coller au
   dernier bouton de découpe (2026-09-06, tache 6). */
.puzzle-autre { margin-top: 6px; align-self: flex-start; }

/* ═══════════ LE QUIZ, CÔTÉ ÉDITEUR (2026-09-02) ═══════════
   Une manche de quiz est une LISTE de questions, pas une grille de paires :
   on lit une ligne par question, avec son énoncé et sa bonne réponse. Sans ce
   résumé, l'animateur devrait ouvrir chaque question pour relire son travail. */

.question {
  /* `relative` : la croix de suppression se pose dans son coin, comme sur
     une paire (`.paire`). `flex-start` (2026-09-06) : un enonce de plusieurs
     lignes grandit la ligne, et le rang comme « Modifier » doivent rester en
     haut plutot que de se retrouver ecrases au milieu. */
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 14px;
  padding: 12px 16px;
  border-radius: 14px;
  background: var(--fond-carte);
  border: 2px solid var(--bordure);
  cursor: pointer;
}
.question:hover { border-color: var(--accent); }
.question__corps {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
}
.question__vignette { width: 56px; height: 56px; flex-shrink: 0; }
/* Plus d'ellipse (2026-09-06, tache 6, regle 62) : un enonce long se lit en
   entier, sur plusieurs lignes, plutot que d'etre coupe au milieu d'un mot.
   L'animateur doit pouvoir verifier sa question sans l'ouvrir. */
.question__enonce {
  flex: 1;
  min-width: 0;
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
  overflow-wrap: anywhere;
  font-size: var(--km-texte-s);
  line-height: 1.3;
}
.question__reponse {
  flex-shrink: 0;
  max-width: 40%;
  white-space: normal;
  overflow-wrap: anywhere;
  color: var(--succes);
  font-weight: 700;
}

/* La modale d'une question. */
.question-edition { display: flex; flex-direction: column; gap: 12px; }
.question-edition__champ { display: flex; flex-direction: column; gap: 6px; }
.question-edition__champ textarea {
  width: 100%;
  box-sizing: border-box;
  resize: vertical;
  font: inherit;
  padding: 10px 12px;
  border-radius: 10px;
  border: 2px solid var(--bordure);
  background: var(--fond-carte);
  color: var(--texte);
}
.question-edition__compteur { margin: 0; font-size: var(--km-texte-xs); opacity: 0.7; }
/* Au-delà de trois lignes, la manche ne tiendra plus à trois zones : on le dit
   AVANT, plutôt que de laisser le mur l'annoncer devant le groupe. */
.question-edition__compteur--serre { color: var(--or); opacity: 1; }
/* Le pavé de symboles du calcul : une rangée qui se replie, comme les gestes
   du son juste en dessous (`.question-edition__gestes`). */
.question-calcul-pad { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 2px; }
.question-calcul-pad button { min-width: 0; padding: 6px 16px; font-size: var(--km-texte-m); }
.question-edition__image { display: flex; align-items: center; gap: 10px; }

.question-reponses { display: flex; flex-direction: column; gap: 10px; }
/* ─── LA SUITE D'UN ÉNONCÉ LOGIQUE, CÔTÉ ÉDITEUR (2026-09-09, lot C) ───
   Deux à cinq cases, puis la case « ? » que le mur posera. Elle vit dans le
   bloc de l'ÉNONCÉ, au-dessus des réponses candidates : ce que le groupe
   regarde d'abord se compose d'abord.
   ⚠️ La case « ? » n'est PAS modifiable : elle montre à l'animateur ce que le
   mur ajoutera, pour qu'il ne cherche pas où écrire la question. */
.question-suite { display: flex; flex-direction: column; gap: 8px; }
.question-suite__titre {
  font-size: var(--km-texte-m);
  font-weight: 700;
  color: var(--texte);
}
.question-suite__rangee { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; }
.question-suite__case {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 8px;
  background: var(--fond-profond);
  border: 2px solid var(--bordure);
  border-radius: 12px;
}
.question-suite__case--demande {
  justify-content: center;
  min-width: 64px;
  min-height: 96px;
  font-size: var(--km-texte-2xl);
  font-weight: 800;
  color: var(--or);
  border-style: dashed;
  border-color: var(--or);
}
.question-reponse { display: flex; align-items: center; gap: 10px; }
/* Trois champs de texte de la meme forme, et TROIS noms distincts : le mot
   d'une reponse, l'unite d'une echelle, le libelle d'un endroit a toucher.
   Ils ont porte le meme nom jusqu'au 2026-09-03, pour partager ce style, et
   « .question-reponse__mot » designait alors quatre champs dont un seul sur
   quatre n'etait pas une reponse. Le cas d'interface « LE QUIZ SE COMPOSE ET
   S ESSAIE SUR LE WEB » remplissait donc un champ CACHE et echouait, sans que
   rien ne dise pourquoi. Un nom de classe qui ment coute plus cher qu'un
   selecteur de plus. */
.question-reponse__mot,
.question-echelle__unite,
.question-zone__libelle {
  flex: 1;
  font: inherit;
  padding: 8px 12px;
  border-radius: 10px;
  border: 2px solid var(--bordure);
  background: var(--fond-carte);
  color: var(--texte);
}
.question-reponse__vignette { width: 64px; height: 64px; flex-shrink: 0; }
/* Le ✓ de la bonne réponse : une case à cocher qui se VOIT de loin, et qui dit
   ce qu'elle est sans qu'on ait à la survoler (règle 37). */
.question-reponse__juste {
  width: 44px;
  height: 44px;
  flex-shrink: 0;
  border-radius: 50%;
  border: 3px solid var(--bordure);
  background: transparent;
  color: var(--fond);
  font-size: var(--km-texte-m);
  font-weight: 800;
  cursor: pointer;
}
.question-reponse__juste.choisi { background: var(--succes); border-color: var(--succes); }
.question-vf { min-width: 160px; }

/* Le SON d une question : un champ, puis les trois gestes. Ils tiennent sur
   une ligne qui se replie, pour que la modale ne grandisse pas quand l hote
   ne sait pas preparer de sons (le mur ne fait que les jouer). */
.question-edition__son { display: flex; flex-direction: column; gap: 8px; }
.question-edition__gestes { display: flex; flex-wrap: wrap; gap: 8px; }

/* ─── L'ÉCHELLE, CÔTÉ ÉDITEUR ───
   Six champs de nombres ne disent pas à quoi ressemblera la règle. L'aperçu
   sous eux montre les graduations telles que le mur les posera, avec la vraie
   valeur en vert et la plage tolérée en doré : l'animateur voit son échelle,
   il ne l'imagine pas. */
.question-echelle {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 16px;
  align-items: flex-end;
}
.question-echelle__champ {
  display: flex;
  flex-direction: column;
  gap: 4px;
  /* 16 px : le plancher de tout l'éditeur (2026-09-06, tâche 6). Les six
     libellés sont désormais des PHRASES (« Première graduation », plus
     « De ») : à 13 px, elles se lisaient déjà en se penchant. */
  font-size: var(--km-texte-xs);
  opacity: 0.85;
}
.question-echelle__nombre {
  width: 96px;
  padding: 8px 10px;
  border-radius: 10px;
  border: 1px solid var(--bordure);
  background: var(--fond-carte);
  color: var(--texte);
  font-size: var(--km-texte-xs);
  font-weight: 700;
}
.question-echelle__apercu {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-top: 12px;
  padding: 12px;
  border-radius: 12px;
  background: var(--km-surface);
  font-size: var(--km-texte-xs);
}
.question-echelle__graduation {
  padding: 8px 14px;
  border-radius: 10px;
  background: var(--bordure);
  font-weight: 700;
}
.question-echelle__graduation--juste {
  background: var(--succes);
  color: var(--km-encre);
}
.question-echelle__graduation--tolere {
  background: var(--or);
  color: var(--km-encre);
}
.question-echelle__alerte { color: var(--corail); font-weight: 700; }

/* ─── LA MODALE PLEIN ÉCRAN DE LA PHOTO À PINS (2026-09-06, tâche 7) ───────
   « Touchez sur l'image » n'a rien à voir avec une question ordinaire : la
   photo EST le terrain de jeu, et une boîte de modale de taille courante
   l'écrasait (capture 30 du plan directeur). `_rendreModaleQuestion()` pose
   cette classe sur `.modale__boite` dès que le format est `zones`.

   ─── EN PART DE LA SCÈNE, PLUS EN PIXELS FIGÉS (2026-09-07) ─────────────
   Ces 1840×1050 étaient des « pixels de scène » : justes tant que l'éditeur
   vivait dans une scène FIXE de 1920×1080 réduite par `transform: scale()`
   (voir la note sur `#scene` dans `editeur-seance.html`). L'éditeur ne se
   met plus à l'échelle : ces pixels devenaient des pixels RÉELS, plus
   grands que la fenêtre elle-même dès qu'elle faisait moins de 1840 de
   large ou 1050 de haut -- et la modale débordait de la page (constaté le
   2026-09-07, `page qui defile`). `.modale` (le fond assombri) occupe déjà
   TOUTE la scène disponible (`inset: 0`) : une part de sa propre largeur et
   hauteur s'y adapte, quelle que soit la fenêtre, sans jamais dépendre de
   `vw`/`vh` (qui ignorent la barre du site et son pied de page légal). */
.modale__boite--plein {
  /* 98%, pas 96% (2026-09-07) : la photo prend ce qui reste sous le titre et
     l'enonce, et chaque pixel de la boite compte a une fenetre courte. */
  width: 98%;
  height: 98%;
  max-width: none;
  max-height: none;
  padding: 10px 24px;
  gap: 10px;
  align-items: stretch;
}
.modale__boite--plein .question-edition { flex: 1 1 auto; min-height: 0; }
/* L'aide de la modale plein ecran a toute la largeur de la boite (1840 px de
   scene) : la borner a 620 px (la largeur qui convient a une boite etroite)
   la faisait passer sur quatre lignes, au detriment de la photo (mesure en
   vrai, 2026-09-06 : 81 px au lieu de 40). */
.modale__boite--plein .modale__aide { max-width: none; }
/* ─── LE DECOR CEDE SA HAUTEUR A LA PHOTO (2026-09-08, T1.9) ─────────────
   Mesure a 1130x915 (la fenetre de Mounassib) : sur 715 px de scene, la
   photo n'en recevait que 329. Le reste partait dans le decor, ligne par
   ligne. Ce titre-ci passe donc d'un cran (`xl` -> `l`) : dans une modale
   qui occupe TOUT l'ecran, il n'a plus a crier pour se distinguer de ce qui
   l'entoure, il n'y a rien autour. Gain mesure : 13 px, et l'aide qui
   l'accompagne en rend 66 de plus en passant en infobulle (voir
   `_rendreModaleQuestion`). */
.modale__boite--plein .modale__titre { font-size: var(--km-texte-l); }
/* ⚠️ TOUTE LA CHAÎNE DOIT PORTER UNE HAUTEUR DÉFINIE (2026-09-06) : sans
   `flex: 1 1 auto; min-height: 0` sur CE conteneur aussi, sa hauteur reste
   `auto` (dictée par son contenu), et le `max-height: 100%` de
   `.question-photo__image` ne trouve alors rien à quoi se comparer : la
   photo (un SVG carré, sans largeur/hauteur propres) grandit alors selon SA
   largeur seule et déborde par-dessus les boutons « Enregistrer » et
   « Supprimer la question », mesuré en vrai (Playwright refusait le clic
   sur « Enregistrer » : l'image interceptait le pointeur à sa place). */
.modale__boite--plein .question-reponses { flex: 1 1 auto; min-height: 0; }

/* ─── LA PHOTO ET SES ENDROITS, CÔTÉ ÉDITEUR ───
   On clique SUR la photo pour poser un endroit. Elle est donc affichée à ses
   propres proportions : la part de l'élément que le filtre à clics rend est
   alors exactement la coordonnée de l'endroit, sans qu'aucune échelle n'ait à
   être devinée. */
.question-photo {
  position: relative;
  display: inline-block;
  max-width: 100%;
  margin-top: 8px;
  border-radius: 12px;
  overflow: hidden;
  cursor: crosshair;
}
.question-photo__image {
  display: block;
  max-width: 100%;
  max-height: 320px;
}
/* ─── L'OBJET POSÉ, VU DANS L'ÉDITEUR (2026-09-09, lot D) ───
   L'animateur doit VOIR ce qu'il pose, à sa place, pendant qu'il compose :
   sinon il découvrirait au mur qu'il a couvert le visage de quelqu'un
   (règle 35, montrer l'image et jamais son nom). Le repère numéroté reste
   par-dessus, en plus discret, pour qu'on puisse encore le saisir et le
   déplacer. */
.question-photo__objet {
  position: absolute;
  transform: translate(-50%, -50%);
  object-fit: contain;
  pointer-events: none;
  filter: drop-shadow(0 4px 10px rgba(0, 0, 0, 0.5));
}
.question-photo__cible--objet {
  background: rgba(12, 10, 22, 0.35);
  border-style: dashed;
}

/* Un endroit posé : un cercle numéroté, à sa taille réelle. L'animateur voit
   la zone que le groupe devra atteindre, pas un point sans épaisseur. */
.question-photo__cible {
  position: absolute;
  transform: translate(-50%, -50%);
  height: 0;
  border-radius: 50%;
  border: 3px solid var(--or);
  background: rgba(184, 134, 11, 0.28);
  color: var(--creme);
  font-weight: 800;
  font-size: var(--km-texte-xs);
  display: flex;
  align-items: center;
  justify-content: center;
  text-shadow: 0 2px 6px rgba(0, 0, 0, 0.9);
  pointer-events: none;
}
.question-photo__liste { display: grid; gap: 8px; margin-top: 12px; }

/* ─── LE PLEIN ÉCRAN : PHOTO À GAUCHE, LISTE ENTIÈRE À DROITE ─────────────
   (2026-09-06, tâche 7). Deux colonnes plutôt qu'une photo étroite au-dessus
   d'une liste tassée : à six endroits, la liste a besoin de sa propre
   colonne pour ne jamais couper un nom (règle 62). */
.question-photo--plein {
  display: grid;
  grid-template-columns: 1fr 380px;
  /* Une seule ligne, qui PREND toute la hauteur du conteneur (`1fr`) plutot
     que de se limiter au contenu (`auto`, la valeur par defaut d'une ligne
     de grille) : sans elle, la ligne se calait sur son contenu le plus haut
     (la photo ou la liste), laissait un vide sous elle, et surtout ne
     donnait a `.question-photo` (ci-dessous, `height: 100%`) aucune hauteur
     definie a quoi se comparer, mesure en vrai le 2026-09-06 (photo tombee a
     180 px au lieu des 630 px attendus). */
  grid-template-rows: 1fr;
  gap: 18px;
  flex: 1 1 auto;
  min-height: 0;
}
/* ⚠️ LA TAILLE EST POSÉE EN JAVASCRIPT, PAS DEVINÉE PAR `object-fit`
   (corrige le 2026-09-06, mesure en vrai). Les ronds `.question-photo__cible`
   se positionnent en POURCENTAGE de CE conteneur (`position: relative`
   ci-dessous, en base.css), exactement comme la coordonnée `impact.fx/fy` du
   clic : le conteneur doit donc être la photo, au pixel près, jamais plus
   LARGE qu'elle (`object-fit: contain` centre l'image dans une boîte plus
   grande, mais ne réduit PAS la boîte : les pourcentages seraient alors
   décalés du LETTERBOXING). Un motif est de plus un SVG sans `width` ni
   `height` propres, seulement un `viewBox` : `object-fit` ne peut même pas
   calculer de taille avec `width: auto` des deux côtés (mesuré en vrai :
   boîte ET image tombées à 0×0). `_rendreCiblesDeLaQuestion()` mesure donc
   la place disponible puis pose sur `.question-photo` la largeur et la
   hauteur EXACTES que `rectangleContenu()` calculerait au mur pour ce
   rapport (`geometrie.js`) : la boîte EST la photo. */
.question-photo--plein .question-photo {
  display: block;
  min-height: 0;
  max-width: 100%;
  max-height: 100%;
  margin-top: 0;
}
/* La photo REMPLIT sa boîte, puisque la boîte a déjà la bonne forme (posée en
   pixels par `_rendreCiblesDeLaQuestion()`). Jamais de recadrage (règle 54,
   seule exception du produit, voir CLAUDE.md § 6 ter, point 11 : un repère
   posé HORS cadre déplacerait l'endroit sous les yeux du groupe) : la boîte
   a le bon RAPPORT, `object-fit: contain` ne fait donc plus rien ici, il
   reste en garde-fou si jamais la boîte n'a pas pu être mesurée (fenêtre
   masquée, script coupé).
   ⚠️ `max-height: none` EST OBLIGATOIRE (corrige le 2026-09-06, mesuré en
   vrai). La règle de base `.question-photo__image` (question ORDINAIRE, pas
   plein écran) pose `max-height: 320px` : sans l'écraser ici, ce plafond
   restait actif malgré `height: 100%` (`max-height` l'emporte toujours sur
   `height`) et coupait la photo à 320 px de scène, quelle que soit la boîte
   calculée en JavaScript. */
.question-photo--plein .question-photo__image {
  display: block;
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  object-fit: contain;
}
/* Le rond REÇOIT le pointeur (contrairement à la règle générale ci-dessus,
   sans quoi rien ne pourrait le glisser) : il se saisit et se déplace à la
   souris, en plus des flèches de la liste qui restent. `touch-action: none`
   empêche la tablette d'un animateur de faire défiler la page pendant le
   geste. */
.question-photo--plein .question-photo__cible {
  pointer-events: auto;
  cursor: grab;
  touch-action: none;
}
.question-photo--plein .question-photo__cible:active { cursor: grabbing; }
.question-photo__aside {
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-height: 0;
}
.question-photo__compteur { margin: 0; font-size: var(--km-texte-s); font-weight: 700; }
/* Déclarée PAR DESSEIN (tests/navigateur/editeur-web.js,
   CONTENEURS_QUI_DEFILENT_PAR_DESSEIN) : six endroits nommés ne tiennent pas
   toujours sans défiler, et c'est le filet voulu, jamais un texte coupé. */
.question-photo--plein .question-photo__liste {
  overflow-y: auto;
  flex: 1 1 auto;
  min-height: 0;
  font-size: var(--km-texte-xs);
}
