/* Composants VocaDial.
 *
 * Extrait tel quel des 47 maquettes de référence, qui inlinent cette feuille
 * pour être autonomes. C'était une commodité de maquette ; ici elle est
 * chargée une fois, normalement.
 *
 * Les valeurs viennent toutes de tokens.css, lui-même produit depuis DESIGN.md.
 * Aucune valeur en dur : modifier une couleur se fait dans DESIGN.md, jamais ici.
 */
/* Les polices sont déclarées dans fonts.css, servie depuis ce serveur. */

/* tokens générés depuis DESIGN.md */
/* VocaDial — jetons générés depuis DESIGN.md
   npx @google/design.md export --format css-tailwind DESIGN.md
   NE PAS ÉDITER À LA MAIN — régénérer depuis DESIGN.md */
/* composants */
/* VocaDial — composants
   Chaque classe correspond à une entrée du bloc `components` de DESIGN.md.
   Aucune valeur en dur : tout passe par les jetons de tokens.css. */



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

/* ── app-shell ── */
body {
  background: var(--color-surface);
  color: var(--color-ink);
  font-family: var(--font-body-md, Nunito), system-ui, sans-serif;
  font-size: var(--text-body-md, 15px);
  font-weight: 600;
  line-height: 1.5;
  min-height: 100vh;
}
body.projection {
  background: var(--color-proj-surface);
  color: var(--color-proj-ink);
}

button, input { font: inherit; color: inherit; }
button { background: none; border: none; cursor: pointer; }
:focus-visible { outline: 3px solid var(--color-primary); outline-offset: 3px; }

/* Un titre qui reçoit le focus par script — pour que le lecteur d'écran
 * annonce la page ou l'étape — n'est pas un contrôle : le cadre n'y dit rien à
 * qui voit, et il encadrait « Mon carnet » à l'ouverture. Les champs et les
 * boutons, eux, gardent leur anneau. */
[tabindex="-1"]:focus-visible { outline: none; }
body.projection :focus-visible { outline-color: var(--color-proj-accent); }

/* ── typographie ── */
.t-display-day    { font-family: Fredoka; font-size: 96px; font-weight: 700; line-height: .82; letter-spacing: -.03em; }
.t-display-month  { font-family: Fredoka; font-size: 30px; font-weight: 600; line-height: 1.1; }
.t-headline-lg    { font-family: Fredoka; font-size: 38px; font-weight: 700; line-height: 1.08; letter-spacing: -.02em; }
.t-headline-md    { font-family: Fredoka; font-size: 24px; font-weight: 600; line-height: 1.15; }
.t-title-module   { font-family: Fredoka; font-size: 18px; font-weight: 600; line-height: 1.15; }
.t-question       { font-family: Fredoka; font-size: 22px; font-weight: 600; line-height: 1.3; }
.t-answer-option  { font-family: Fredoka; font-size: 19px; font-weight: 600; line-height: 1.3; }
.t-label          { font-family: Fredoka; font-size: 14px; font-weight: 600; line-height: 1.3; }
.t-eyebrow        { font-family: Fredoka; font-size: 12px; font-weight: 500; line-height: 1.3; letter-spacing: .06em; text-transform: uppercase; font-kerning: none; }
.t-body-lg        { font-size: 17px; line-height: 1.55; }
.t-body-md        { font-size: 15px; line-height: 1.5; }
.t-body-sm        { font-size: 13px; line-height: 1.45; }
.t-code           { font-family: "Space Mono", monospace; font-size: 15px; font-weight: 700; letter-spacing: .06em; }
/* La projection se mesure en hauteur, pas en largeur.
 *
 * Calibrée en `vw`, la réponse plafonnait à 32 px : sur un vidéoprojecteur de
 * 1920 par 1080, cela fait un texte qui occupe trois pour cent de la hauteur et
 * que le fond de la classe ne lit pas. Un écran de projection est contraint par
 * sa hauteur — la largeur, il en a de reste, et c'est bien le reproche qu'on
 * lui fait : tout se tasse en haut à gauche.
 *
 * Les bornes basses restent en pixels pour les petits écrans, où la même règle
 * en `vh` donnerait un texte minuscule sur un téléphone en paysage. */
/*
 * Bornées en largeur autant qu'en hauteur, et dans la règle de base.
 *
 * Un plafond en `vw` existait déjà plus bas, sous `@media (max-width: 48rem)`.
 * Il n'a pas suffi : sur un téléphone, la phrase du mot du jour sortait encore
 * en capitales d'affiche sur quatre lignes. On n'a pas su dire laquelle des
 * conditions ne tenait pas — la cascade servie donne pourtant dix-huit pixels
 * sur un écran de trois cent quatre-vingt-dix.
 *
 * La borne est donc posée ici, dans la règle qui s'applique partout et ne
 * dépend d'aucune requête média : `min(vh, vw)` ne peut que réduire, et il ne
 * réduit qu'en portrait. Sur un vidéoprojecteur 1920 × 1080, `5vh` vaut 54 px
 * et `5.5vw` en vaut 105 : c'est la hauteur qui l'emporte, exactement comme
 * avant. C'est la forme que « El número » emploie depuis longtemps.
 */
.t-proj-q         { font-family: Fredoka; font-size: calc(clamp(30px, min(7.2vh, 7.5vw), 86px) * var(--proj-fit, 1)); font-weight: 700; line-height: 1.05; letter-spacing: -.02em; }
.t-proj-a         { font-family: Fredoka; font-size: calc(clamp(21px, min(5vh, 5.5vw), 58px) * var(--proj-fit, 1)); font-weight: 500; line-height: 1.25; }
/* Vingt pixels fixes : c'était la taille d'une étiquette de formulaire, sur
 * un écran de trois mètres. Comme le reste de la projection, elle se mesure
 * maintenant en hauteur. */
.t-proj-label     { font-family: Fredoka; font-size: calc(clamp(20px, 3vh, 34px) * var(--proj-fit, 1)); font-weight: 600; line-height: 1.3; letter-spacing: .04em; }

.text-secondary { color: var(--color-ink-muted); }
/* Le texte d'aide prend la teinte secondaire. `ink-faint` (2,3 : 1 sur le
 * fond crème) échouait au seuil de 4,5 : 1 des WCAG pour du texte ; il reste
 * aux éléments décoratifs — poignées, pastilles verrouillées. La hiérarchie
 * tient à la taille, plus à la pâleur. */
.text-hint      { color: var(--color-ink-muted); }
.text-points    { color: var(--color-gold-strong); }

/* ── relief : bordure + ombre pleine ── */
.depth-1 { border: 2.5px solid var(--color-ink); box-shadow: 0 4px 0 var(--color-ink); }
.depth-2 { border: 2.5px solid var(--color-ink); box-shadow: 0 5px 0 var(--color-ink); }
.pressable { transition: transform .12s, box-shadow .12s; }
.pressable:hover  { transform: translateY(-3px); box-shadow: 0 8px 0 var(--color-ink); }
.pressable:active { transform: translateY(5px);  box-shadow: 0 0 0 var(--color-ink); }

/* ── boutons ── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--spacing-2);
  font-family: Fredoka; font-size: 16px; font-weight: 600;
  border-radius: var(--radius-lg); padding: var(--spacing-4) var(--spacing-6);
  min-height: 52px; transition: transform .12s, box-shadow .12s;
}
.btn:active { transform: translateY(5px); box-shadow: 0 0 0 currentColor; }
.btn-primary  { background: var(--color-primary); color: var(--color-on-primary); box-shadow: 0 5px 0 var(--color-primary-active); }
.btn-primary:hover  { background: var(--color-primary-hover); }
.btn-primary:active { box-shadow: 0 0 0 var(--color-primary-active); }
.btn-ghost    { background: var(--color-surface-raised); color: var(--color-ink); border: 2.5px solid var(--color-ink); box-shadow: 0 5px 0 var(--color-ink); }
.btn-ghost:active { box-shadow: 0 0 0 var(--color-ink); }
.btn-validate { background: var(--color-success-strong); color: var(--color-on-success); box-shadow: 0 5px 0 #0d5a3d; }
.btn-validate:active { box-shadow: 0 0 0 #0d5a3d; }
.btn-danger   { background: var(--color-error-strong); color: var(--color-on-error); box-shadow: 0 5px 0 #8d2a24; }
.btn:disabled { background: var(--color-line); color: var(--color-ink-disabled); box-shadow: none; cursor: not-allowed; transform: none; }
.btn-lg { font-size: 19px; min-height: 62px; padding: var(--spacing-5) var(--spacing-8); }
.btn-block { width: 100%; }

/* ── surfaces ── */
.surface-card { background: var(--color-surface-raised); border-radius: var(--radius-xl); padding: var(--spacing-4); }
.divider { height: 2px; background: var(--color-line); border: none; }
.divider-strong { height: 2px; background: var(--color-line-strong); border: none; }

/* ── éphéméride ── */
.eph-stack { position: relative; padding-bottom: 14px; }
.eph-stack .layer { position: absolute; left: 9px; right: 9px; bottom: 6px; height: 26px;
  background: var(--color-surface-raised); border: 2.5px solid var(--color-line); border-radius: var(--radius-2xl); z-index: 0; }
.eph-stack .layer.b2 { left: 17px; right: 17px; bottom: 0; opacity: .6; }
.eph-sheet {
  position: relative; z-index: 2; background: var(--color-surface-raised);
  border: 2.5px solid var(--color-ink); border-radius: var(--radius-2xl);
  box-shadow: 0 5px 0 var(--color-ink); overflow: hidden;
}
.eph-rule { height: 6px; }
.eph-rule-es { background: var(--color-lang-es); }
.eph-rule-en { background: var(--color-lang-en); }
.eph-rule-fr { background: var(--color-lang-fr); }
.eph-rule-it { background: var(--color-lang-it); }
.eph-rule-de { background: var(--color-lang-de); }
.eph-band { padding: var(--spacing-2) var(--spacing-5); display: flex; justify-content: space-between;
  align-items: center; gap: var(--spacing-3); flex-wrap: wrap; color: var(--color-ink); }
.eph-band-es { background: var(--color-lang-es-soft); }
.eph-band-en { background: var(--color-lang-en-soft); }
.eph-band-fr { background: var(--color-lang-fr-soft); }
.eph-band-it { background: var(--color-lang-it-soft); }
.eph-band-de { background: var(--color-lang-de-soft); }
.eph-body { padding: var(--spacing-5); display: flex; align-items: center; gap: var(--spacing-5); flex-wrap: wrap; }
.eph-month { color: var(--color-ink-muted); }

/* ── progression ── */
.progress-track { height: 8px; background: var(--color-line); border-radius: var(--radius-full); overflow: hidden; flex: 1; }
.progress-fill  { height: 100%; background: var(--color-success); border-radius: var(--radius-full); }

/* ── tuiles de module ── */
.tile {
  background: var(--color-surface-raised); color: var(--color-ink);
  border: 2.5px solid var(--color-ink); border-radius: var(--radius-xl);
  box-shadow: 0 5px 0 var(--color-ink);
  padding: var(--spacing-4); text-align: left; position: relative;
  display: flex; flex-direction: column; gap: var(--spacing-1-5); min-height: 156px;
  transition: transform .12s, box-shadow .12s;
}
.tile:hover  { transform: translateY(-3px); box-shadow: 0 8px 0 var(--color-ink); }
.tile:active { transform: translateY(5px);  box-shadow: 0 0 0 var(--color-ink); }
.tile-done   { background: var(--color-success-soft); border-color: var(--color-success-strong); box-shadow: 0 5px 0 var(--color-success-strong); cursor: default; }
.tile-done:hover  { transform: none; box-shadow: 0 5px 0 var(--color-success-strong); }
.tile-locked { background: var(--color-surface-sunken); border-color: var(--color-line-strong); box-shadow: 0 5px 0 var(--color-line-strong); border-style: dashed; }
.tile-locked .t-title-module { color: var(--color-ink-muted); }

/* ── pastilles d'icône par famille ── */
.mod-icon { width: 44px; height: 44px; border-radius: var(--radius-md); display: grid; place-items: center; flex: none; }
.mod-icon svg { width: 24px; height: 24px; stroke: #fff; stroke-width: 2.1; fill: none; stroke-linecap: round; stroke-linejoin: round; }
.fam-temporal    { background: var(--color-family-temporal); }
.fam-lexico      { background: var(--color-family-lexico); }
.fam-fonologia   { background: var(--color-family-fonologia); }
.fam-gramatica   { background: var(--color-family-gramatica); }
.fam-comprension { background: var(--color-family-comprension); }
.fam-cultura     { background: var(--color-family-cultura); }
.fam-expresion   { background: var(--color-family-expresion); }
.fam-juegos      { background: var(--color-family-juegos); }
.fam-repaso      { background: var(--color-family-repaso); }
.fam-bienestar   { background: var(--color-family-bienestar); }
.fam-cierre      { background: var(--color-brand-band); }
.fam-locked      { background: var(--color-ink-faint); }

/* DESIGN.md nomme cette famille « repaso », le code l'appelle
 * « reactivacion » : deux noms pour la même chose, et la pastille restait
 * transparente faute que les deux se rencontrent. Trois modules s'affichaient
 * donc sans glyphe — le badge existait, il n'avait simplement pas de fond. */
.fam-reactivacion { background: var(--color-family-repaso); }

/* Deux familles que DESIGN.md ne nomme pas, parce qu'elles ne portent pas de
 * matière : « outils de classe » compte les absents et lance un chronomètre,
 * « production » n'a pas encore de module. Une teinte neutre plutôt qu'une
 * couleur inventée — le jour où la charte les nomme, ces deux lignes tombent. */
.fam-herramientas { background: var(--color-ink-muted); }
.fam-produccion   { background: var(--color-family-expresion); }

/* ── tampons ── */
.stamp {
  position: absolute; right: 10px; top: 12px; transform: rotate(-9deg);
  font-family: Fredoka; font-size: 12px; font-weight: 600; letter-spacing: .04em;
  border-radius: var(--radius-md); padding: var(--spacing-1) var(--spacing-2-5, 10px);
}
.stamp-done { background: var(--color-success-strong); color: var(--color-on-success); box-shadow: 0 3px 0 #0d5a3d; }
.stamp-gold { background: var(--color-gold); color: var(--color-ink); box-shadow: 0 3px 0 var(--color-gold-strong); }

/* ── pastilles ── */
.pill { display: inline-flex; align-items: center; gap: var(--spacing-1-5);
  background: var(--color-surface-sunken); color: var(--color-ink);
  border-radius: var(--radius-full); padding: var(--spacing-1) var(--spacing-3);
  font-size: 13px; font-weight: 700; }
.pill-license { background: var(--color-primary-soft); color: var(--color-primary-active); }
.pill-outline { background: transparent; border: 2px solid var(--color-line-strong); }
.code-class { display: inline-block; background: var(--color-primary-soft); color: var(--color-primary-active);
  border: 2.5px dashed var(--color-primary); border-radius: var(--radius-md); padding: var(--spacing-2) var(--spacing-3); }

/* ── options de réponse ── */
.option { display: flex; align-items: center; gap: var(--spacing-3); width: 100%; text-align: left;
  background: var(--color-surface-raised); color: var(--color-ink);
  border: 2.5px solid var(--color-line); border-radius: var(--radius-lg);
  box-shadow: 0 4px 0 var(--color-line); padding: var(--spacing-4); min-height: 58px;
  transition: transform .12s, box-shadow .12s; }
.option:hover  { transform: translateY(-2px); box-shadow: 0 6px 0 var(--color-line); }
.option-selected  { background: var(--color-primary-soft); color: var(--color-primary-active); border-color: var(--color-primary); box-shadow: 0 4px 0 var(--color-primary); }
.option-correct   { background: var(--color-success-soft); color: var(--color-success-strong); border-color: var(--color-success-strong); box-shadow: 0 4px 0 var(--color-success-strong); }
.option-incorrect { background: var(--color-error-soft); color: var(--color-error-strong); border-color: var(--color-error-strong); box-shadow: 0 4px 0 var(--color-error-strong); }

/* ── projection ── */
.proj-shell { min-height: 100vh; display: flex; flex-direction: column; padding: var(--spacing-8); }
.proj-eyebrow { color: var(--color-proj-ink-muted); }
.proj-highlight { color: var(--color-proj-accent); font-style: normal; }
.proj-answer { color: var(--color-proj-success); }
.proj-divider { height: 2px; background: var(--color-proj-line); border: none; }
.proj-btn { display: inline-flex; align-items: center; gap: var(--spacing-2);
  border: 2.5px solid var(--color-proj-ink); color: var(--color-proj-ink);
  border-radius: var(--radius-lg); padding: var(--spacing-3) var(--spacing-5);
  font-family: Fredoka; font-size: 18px; font-weight: 600; min-height: 56px; }
.proj-btn-solid { background: var(--color-proj-ink); color: var(--color-proj-surface); }
.proj-btn-accent { background: var(--color-proj-accent); border-color: var(--color-proj-accent); color: var(--color-proj-surface); }
/* Un bouton de scène éteint se voit éteint : la roue qui tourne, la partie de
 * pendu qui se joue. Allumé, il invite à appuyer sur un geste refusé. */
.proj-btn:disabled { opacity: .45; cursor: default; }
.proj-chip { border: 2px solid var(--color-proj-line); color: var(--color-proj-ink-muted);
  border-radius: var(--radius-md); padding: var(--spacing-2) var(--spacing-4);
  font-family: Fredoka; font-size: 17px; font-weight: 600; }
.proj-chip[aria-pressed="true"] { background: var(--color-proj-ink); color: var(--color-proj-surface); border-color: var(--color-proj-ink); }
.kbd { font-family: "Space Mono", monospace; font-size: 12px; border: 1.5px solid currentColor;
  border-radius: 5px; padding: 1px 6px; opacity: .75; }

/* ── mur d'archives ── */
/* Le mur garde `auto-fill` : ici la taille de la case est le sujet, et une
 * colonne vide en fin de ligne vaut mieux qu'un carré étiré. */
.wall { display: grid; grid-template-columns: repeat(auto-fill, minmax(22px, 1fr)); gap: 5px; }
.wall-cell { aspect-ratio: 3/4; border-radius: var(--radius-sm); background: var(--color-line); }
.wall-cell-done   { background: var(--color-success); }
.wall-cell-gold   { background: var(--color-gold); box-shadow: inset 0 0 0 2.5px var(--color-gold-strong); }
.wall-cell-missed { background: var(--color-surface); border: 2px dashed var(--color-line-strong); }

/* ── utilitaires de mise en page ── */
/* La largeur de l'application : celle de la page Start (84 rem), et non plus 1000 px,
 * qui laissait 300 px vides de chaque côté sur un écran de 1600. Une seule valeur
 * pour le contenu, le bandeau, les onglets, la barre de langues et le pied de page,
 * pour qu'ils restent alignés. */
:root { --page-w: 84rem; }
/* Un formulaire n'a rien à gagner à s'étendre sur 1300 px : les champs y deviennent des barres. */
.wrap.wrap-form { max-width: 52rem; }
.wrap { max-width: var(--page-w); margin: 0 auto; padding: 0 var(--spacing-4) var(--spacing-16); }
.row { display: flex; align-items: center; gap: var(--spacing-3); }
.row-wrap { flex-wrap: wrap; }
.spread { justify-content: space-between; }
.col { display: flex; flex-direction: column; }
/* `auto-fit`, et non `auto-fill`.
 *
 * Avec `auto-fill`, la grille réserve autant de colonnes que la largeur en
 * accepte — cinq sur mille pixels — et les trois cartes de l'accueil en
 * occupaient trois, laissant deux colonnes vides à droite. Les cartes
 * paraissaient étriquées sur un écran manifestement large, ce qui est
 * exactement ce qu'on lit : des colonnes fantômes.
 *
 * `auto-fit` réduit les colonnes vides à zéro et rend leur place aux autres.
 * Là où la grille est pleine — le sommaire, ses quinze modules — les deux mots
 * font strictement la même chose. La différence n'apparaît qu'au moment où
 * elle compte.
 *
 * Le défaut venait des maquettes et a été recopié tel quel : elles montraient
 * assez de tuiles pour que les colonnes vides ne se voient jamais.
 */
.grid-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(168px, 1fr)); gap: var(--spacing-3); }
.stack-1 > * + * { margin-top: var(--spacing-1); }
.stack-2 > * + * { margin-top: var(--spacing-2); }
.stack-3 > * + * { margin-top: var(--spacing-3); }
.stack-4 > * + * { margin-top: var(--spacing-4); }
.stack-5 > * + * { margin-top: var(--spacing-5); }
.stack-6 > * + * { margin-top: var(--spacing-6); }
/* `.mt-1`, `.mt-2` et `.mt-3` figuraient dans plus de cent balises sans avoir
 * jamais été définies : la remise à zéro générale l'emportait, et le texte
 * d'aide collait au champ qu'il commente. */
.mt-1 { margin-top: var(--spacing-1); } .mt-2 { margin-top: var(--spacing-2); }
.mt-3 { margin-top: var(--spacing-3); }
.mt-4 { margin-top: var(--spacing-4); } .mt-5 { margin-top: var(--spacing-5); } .mt-6 { margin-top: var(--spacing-6); }
.mt-8 { margin-top: var(--spacing-8); } .mt-12 { margin-top: var(--spacing-12); }
/* La marge basse n'existait pas : un `.mb-3` écrit dans un gabarit n'avait
 * aucun effet, et en silence. `tests/test-charte.php` le contrôle. */
.mb-2 { margin-bottom: var(--spacing-2); } .mb-3 { margin-bottom: var(--spacing-3); }
.mb-4 { margin-bottom: var(--spacing-4); }
.push { margin-left: auto; }
.grow { flex: 1; }

/* ── barre de maquette (hors produit) ── */

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

/*
 * Le réglage « Animations » a été retiré des préférences.
 *
 * Il ne servait qu'au professeur dont le système ne demande rien mais qui
 * trouve les dévoilements gênants — un cas rare, sur un écran de réglages qui
 * n'en comptait que trois. La ligne au-dessus, elle, reste et suffit : elle
 * obéit au choix de l'appareil, qui est l'endroit où ce choix se fait une fois
 * pour toutes et pour tous les sites.
 */


/* ══ chrome d'application ══ */
/* Le bandeau est blanc, comme celui de la page Start et comme la barre du bas sur
 * téléphone : il se détache du fond crème de la page au lieu de s'y fondre. */
.chrome { position: sticky; top: 0; z-index: 40; background: var(--color-surface-raised); border-bottom: 2px solid var(--color-line); }
.chrome-in { max-width: var(--page-w); margin: 0 auto; padding: var(--spacing-3) var(--spacing-4);
  display: flex; align-items: center; gap: var(--spacing-2-5, 10px); flex-wrap: wrap; }
/* La marque est un logotype, plus un mot composé. Le violet n'y a jamais eu sa
 * place : `primary` est la couleur de l'action dans l'interface, pas celle de
 * la marque — c'est une règle du dossier de marque, et elle explique pourquoi
 * l'ancien « Dial » violet jurait avec tout le reste. */
.brand { display: inline-flex; align-items: center; }
.langdots { display: flex; gap: var(--spacing-1-5); margin-left: var(--spacing-2); }
.langdot { width: 26px; height: 26px; border-radius: var(--radius-full); border: 3px solid transparent;
  box-shadow: 0 3px 0 rgba(46,38,80,.16); }
.langdot[aria-pressed="true"] { border-color: var(--color-ink); transform: translateY(1px); box-shadow: 0 2px 0 rgba(46,38,80,.28); }
.dot-es { background: var(--color-lang-es); } .dot-en { background: var(--color-lang-en); } .dot-fr { background: var(--color-lang-fr); } .dot-it { background: var(--color-lang-it); } .dot-de { background: var(--color-lang-de); }
.chip { display: inline-flex; align-items: center; gap: var(--spacing-1-5);
  background: var(--color-surface-raised); border: 2px solid var(--color-line);
  border-radius: var(--radius-full); padding: var(--spacing-1) var(--spacing-3);
  font-family: Fredoka; font-weight: 600; font-size: 15px; }
.chip svg { width: 17px; height: 17px; }
.seg { display: flex; gap: 3px; background: var(--color-line); padding: 3px; border-radius: var(--radius-full); }
.seg button { font-family: Fredoka; font-weight: 600; font-size: 14px; padding: var(--spacing-1) var(--spacing-3);
  border-radius: var(--radius-full); color: var(--color-ink-muted); }
.seg button[aria-pressed="true"] { background: var(--color-ink); color: var(--color-surface); }
/* `flex-wrap` par précaution : trois onglets tiennent en français sur un
 * téléphone, et « Mis clases · Ajustes · Descubrir » y tient moins bien. Un
 * onglet qui sort de l'écran ne se rattrape pas au doigt. */
.tabs { max-width: var(--page-w); margin: 0 auto; padding: 0 var(--spacing-4); display: flex; flex-wrap: wrap; gap: var(--spacing-2); }
.tabs a { font-family: Fredoka; font-weight: 600; font-size: 16px; padding: var(--spacing-2-5, 10px) var(--spacing-4);
  color: var(--color-ink-muted); border-radius: var(--radius-lg) var(--radius-lg) 0 0; text-decoration: none; }
.tabs a[aria-current="page"] { color: var(--color-ink); background: var(--color-surface-sunken); }

/* ══ le sous-menu d'une classe ══
 *
 * Sept destinations sur une ligne, sous le titre de la classe. Ce n'est pas
 * une seconde rangée d'onglets : les onglets disent où l'on est dans le
 * produit, celui-ci dit ce qu'on peut faire de la classe qu'on regarde. D'où
 * la boîte, qui l'attache visiblement au titre au lieu de le laisser flotter
 * sous le bandeau.
 *
 * Les liens portent une classe explicite. Un `a` nu hérite ici de la règle de
 * couleur des liens de texte, et sa spécificité égale celle d'un `.submenu a` —
 * à égalité c'est l'ordre du fichier qui tranche, ce qui est une façon de
 * décider par accident. */
.submenu { display: flex; flex-wrap: wrap; gap: var(--spacing-1);
  padding: var(--spacing-1); border: 2.5px solid var(--color-line);
  border-radius: var(--radius-lg); background: var(--color-surface-raised); }

a.submenu-link { font-family: Fredoka; font-weight: 600; font-size: 14px;
  padding: var(--spacing-2) var(--spacing-3); border-radius: var(--radius-md);
  color: var(--color-ink-muted); text-decoration: none; }

a.submenu-link:hover { background: var(--color-surface-sunken); color: var(--color-ink); }
a.submenu-link:focus-visible { outline: 3px solid var(--color-primary); outline-offset: 2px; }

/* ══ le code d'appairage ══
 *
 * Il est lu depuis le fond de la salle, sur un vidéoprojecteur qui délave, par
 * quelqu'un qui le recopie sur un téléphone tenu à bout de bras. D'où la
 * taille, l'interlettrage, et rien d'autre autour. */
/* Quatre caractères très espacés débordent d'un écran étroit si leur taille ne
 * se mesure qu'en hauteur : sur un téléphone en portrait, 14 vh valent plus de
 * cent pixels par signe, et la ligne dépasse. La largeur entre donc dans le
 * calcul — c'est elle qui manque. */
/* Le code en repli (étape 2) : quatre cases, lisibles à bout de bras mais
 * loin derrière le QR. */
.pair-code { display: flex; gap: 8px; margin: var(--spacing-4) 0 0; font-family: Fredoka; font-weight: 700; line-height: 1; }
.pair-code span { display: grid; place-items: center; width: clamp( 48px, 17vw, 72px ); height: clamp( 60px, 21vw, 88px );
  font-size: clamp( 34px, 11vw, 52px ); color: var(--color-primary); background: var(--color-primary-soft); border-radius: var(--radius-md); }

/* Le QR du même code : fond blanc franc et marge calme (ajoutée par le tracé),
 * sans quoi un reflet sur le tableau le rend illisible. Il est la pièce
 * principale de la carte : grand, mais borné par la hauteur de l'écran. */
.pair-qr { width: min( 250px, 100%, 36vh ); min-width: 180px; aspect-ratio: 1; background: #fff; border: 3px solid var(--color-ink); border-radius: var(--radius-lg); padding: var(--spacing-3); }
.pair-qr svg { display: block; width: 100%; height: 100%; }
.pair-qr[hidden] { display: none; }

/* La carte : étapes à gauche, QR à droite ; l'une sur l'autre en étroit, le QR
 * d'abord puisque c'est le geste le plus court. */
.pair-card { display: grid; grid-template-columns: minmax( 0, 1fr ) minmax( 220px, 260px ); gap: var(--spacing-8); align-items: center; padding: var(--spacing-6) var(--spacing-8); }
.pair-steps { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--spacing-8); }
.pair-step { display: grid; grid-template-columns: 36px 1fr; gap: var(--spacing-4); align-items: start; }
.pair-step h2 { margin: 4px 0; font-size: 22px; }
.pair-step p { font-size: 16px; }
.pair-step p { margin: 0; }
.pair-n { display: grid; place-items: center; width: 36px; height: 36px; border-radius: 50%; background: var(--color-primary-soft); color: var(--color-primary); font: 700 17px Fredoka; }
.pair-side { display: grid; justify-items: center; min-width: 0; }
.pair-wait, .pair-ok { align-items: center; text-align: center; gap: var(--spacing-3); }
.pair-wait[hidden], .pair-ok[hidden] { display: none; }
.pair-status { display: inline-flex; align-items: center; gap: 10px; margin: 0; }
.pair-dot { width: 10px; height: 10px; border-radius: 50%; background: var(--color-primary); animation: pair-pulse 1.6s ease-in-out infinite; }
@keyframes pair-pulse { 0%, 100% { opacity: .35; transform: scale( .8 ); } 50% { opacity: 1; transform: scale( 1.15 ); } }
@media ( prefers-reduced-motion: reduce ) { .pair-dot { animation: none; } }
.pair-tick { width: 84px; height: 84px; border-radius: 50%; background: var(--color-success-soft); position: relative; }
.pair-tick::after { content: ""; position: absolute; left: 31px; top: 21px; width: 16px; height: 30px; border: solid var(--color-success-strong); border-width: 0 5px 5px 0; transform: rotate( 40deg ); }
.pair-ok-title { color: var(--color-success-strong); margin: 0; }
.pair-ok p { margin: 0; max-width: 28ch; }
.pair-foot { display: flex; flex-wrap: wrap; align-items: center; gap: var(--spacing-3) var(--spacing-4); }
@media ( max-width: 640px ) {
  .pair-card { grid-template-columns: 1fr; gap: var(--spacing-6); padding: var(--spacing-5) var(--spacing-4); }
  .pair-side { order: -1; }
  .pair-foot { display: grid; }
  .pair-foot .btn { width: 100%; }
}

/* La saisie, elle, se fait au pouce : mêmes caractères, même espacement, pour
 * qu'on reconnaisse ce qu'on est en train de recopier. */
input.pair-input { font-family: Fredoka; font-weight: 700; font-size: 32px;
  letter-spacing: .3em; text-align: center; text-transform: uppercase; }

/* L'invitation à poser l'icône sur l'écran d'accueil. Elle vit sous le
 * formulaire, en retrait : c'est un confort, pas une étape. Le script la
 * découvre là où elle a un sens — un téléphone, et pas une application déjà
 * installée — et elle reste invisible partout ailleurs. */
.install-hint { border: 1px dashed var(--color-line-strong); border-radius: var(--radius-md);
  padding: var(--spacing-4); background: var(--color-surface-sunken); }

/* L'écran de saisie de la télécommande : reprendre, scanner, saisir. */
.pair-resume-card { display: flex; align-items: center; justify-content: space-between; gap: var(--spacing-3); width: 100%; text-align: left;
  min-height: 72px; padding: var(--spacing-3) var(--spacing-4); background: var(--color-surface-raised); color: inherit; font: inherit; text-decoration: none;
  border: 2.5px solid var(--color-ink); border-radius: var(--radius-xl); box-shadow: 0 5px 0 var(--color-ink); }
.pair-resume-card:active { transform: translateY(4px); box-shadow: 0 1px 0 var(--color-ink); }
.pair-resume-go { color: var(--color-primary); white-space: nowrap; }
.pair-scan svg { flex: none; }
.pair-or { display: flex; align-items: center; gap: var(--spacing-3); margin: 0; color: var(--color-ink-muted); font-family: Fredoka; font-weight: 500; font-size: var(--text-body-sm); }
.pair-or::before, .pair-or::after { content: ""; flex: 1; height: 2px; background: var(--color-line); }
input.pair-input::placeholder { color: var(--color-ink-faint); font-weight: 500; }
input.pair-input:disabled { background: var(--color-surface-sunken); color: var(--color-ink-disabled); }

/* L'invitation à installer, sur une ligne ; la note d'iPhone passe dessous. */
.pair-install { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--spacing-3); padding: var(--spacing-3) var(--spacing-4); }
.pair-install[hidden] { display: none; }
.pair-install p { margin: 0; flex: 1; min-width: 0; }
.pair-install .btn { flex: none; margin: 0; }
.pair-install .pair-install-note { flex-basis: 100%; }
.pair-install .pair-install-note[hidden] { display: none; }

/* La caméra du scan : plein écran, le temps de lire. */
.pair-cam { position: fixed; inset: 0; z-index: 100; background: #000; display: flex; flex-direction: column; align-items: center; justify-content: space-between; gap: var(--spacing-4);
  padding: var(--spacing-4) max( var(--spacing-4), env( safe-area-inset-right, 0px ) ) calc( var(--spacing-4) + env( safe-area-inset-bottom, 0px ) ) max( var(--spacing-4), env( safe-area-inset-left, 0px ) ); }
.pair-cam[hidden] { display: none; }
.pair-cam-video { flex: 1; min-height: 0; width: 100%; object-fit: cover; border-radius: var(--radius-xl); }
.pair-cam-hint { margin: 0; color: #fff; text-align: center; }
.pair-cam-cancel { width: 100%; max-width: 24rem; }
html.has-cam { overflow: hidden; }

/* ══ trois formes d'une même réponse ══
 *
 * « Falta … », « Faltan … y … », « No falta nadie. » : ce ne sont pas trois
 * étapes mais trois cas, et c'est leur alignement qui fait voir l'accord.
 * Empilées et centrées, la ligne du milieu se lit comme la variante de celle
 * du dessus. */
/*
 * Trois formes d'une même phrase se lisent l'une sous l'autre, alignées à
 * gauche. Centrées, leurs premiers mots — « Falta », « Faltan », « No falta » —
 * ne commençaient jamais au même endroit, alors que c'est précisément leur
 * début qui diffère et qu'il faut comparer.
 */
.proj-shapes { align-items: flex-start; gap: var(--spacing-4); text-align: left; }
/* « La última vez » : sous les amorces, les modules de la séance précédente. */
.proj-recall { align-items: flex-start; gap: var(--spacing-2); margin-top: var(--spacing-4); text-align: left; }
.proj-recall-chips { gap: var(--spacing-3); justify-content: flex-start; }
/* La date de la séance précédente se lit sous la question, pas à sa suite. */
[data-vd-module="la-ultima-vez"] .proj-ask { flex-direction: column; align-items: flex-start; gap: var(--spacing-2); }
[data-vd-module="la-ultima-vez"] .proj-hint { font-size: calc(clamp(17px, 2.8vh, 30px) * var(--proj-fit, 1)); }
.proj-recall .proj-chip { font-size: calc(clamp(15px, 2.4vh, 26px) * var(--proj-fit, 1)); }

/* ══ anneau de progression ══ */
.ring { position: relative; width: 88px; height: 88px; flex: none; }
.ring svg { transform: rotate(-90deg); }
.ring b { position: absolute; inset: 0; display: grid; place-items: center; align-content: center;
  font-family: Fredoka; font-weight: 700; font-size: 21px; line-height: 1; }
.ring b small { display: block; font-size: 10px; font-weight: 500; letter-spacing: .06em;
  color: var(--color-ink-muted); margin-top: 3px; }

/* ══ carte de série ══ */
.streak { display: flex; align-items: center; gap: var(--spacing-3); background: var(--color-surface-raised);
  border: 2.5px solid var(--color-line); border-radius: var(--radius-lg); padding: var(--spacing-3) var(--spacing-4); flex-wrap: wrap; }
.streak .flame { font-size: 24px; line-height: 1; }
.dots7 { display: flex; gap: var(--spacing-1-5); margin-left: auto; }
.dots7 i { width: 15px; height: 15px; border-radius: var(--radius-full); background: var(--color-line); }
.dots7 i.on { background: var(--color-lang-es); }
.dots7 i.now { background: transparent; border: 3px solid var(--color-lang-es); }

/*
 * `hidden` doit toujours gagner.
 *
 * L'attribut n'est qu'un `display: none` posé par la feuille du navigateur :
 * n'importe quelle règle d'auteur qui déclare un `display` le bat, et sans
 * qu'aucune erreur ne le signale. C'est ce qui laissait deux boutons
 * « Revenir au sommaire » côte à côte, et « Module suivant » visible là où il
 * n'y a pas de suivant — les deux étaient bien marqués `hidden`, mais
 * `.proj-btn` déclare `display: inline-flex`.
 *
 * `!important` se justifie ici et à peu près nulle part ailleurs : la règle ne
 * décrit pas une apparence mais une invariance, et le jour où quelqu'un pose
 * un `display` sur un composant, il ne doit pas avoir à y penser.
 */
[hidden] { display: none !important; }

/* ══ en-tête de section ══ */
.sec { display: flex; align-items: center; gap: var(--spacing-3); margin-top: var(--spacing-8); margin-bottom: var(--spacing-3); }
.sec h2 { font-family: Fredoka; font-weight: 600; font-size: 20px; }
.sec .count { background: var(--color-primary-soft); color: var(--color-primary-active);
  border-radius: var(--radius-full); padding: 2px var(--spacing-3); font-family: Fredoka; font-weight: 600; font-size: 14px; }

/* ══ bandeau de maquette, doux ══ */

/* ══ barre de progression du rituel en projection ══ */
.proj-steps { display: flex; gap: var(--spacing-1-5); flex: 1; }
.proj-steps i { height: 6px; flex: 1; border-radius: var(--radius-full); background: var(--color-proj-line); }
.proj-steps i.done { background: var(--color-proj-success); }
.proj-steps i.now  { background: var(--color-proj-accent); }

/* ── Projection ──────────────────────────────────────────────────────────
 * Composants employés uniquement par la scène projetée : carte, halo,
 * étiquettes de langue, roue de tirage, et les quatre animations. Les
 * maquettes de projection sont les seules à les charger.
 */
/* ══ projection : fond vivant ══ */
body.projection {
  background:
    radial-gradient(900px 520px at 12% -5%,  rgba(108,79,216,.42) 0%, transparent 62%),
    radial-gradient(760px 460px at 92% 108%, rgba(63,182,217,.30) 0%, transparent 60%),
    radial-gradient(620px 420px at 78% 8%,   rgba(245,162,61,.16) 0%, transparent 58%),
    var(--color-proj-surface);
  background-attachment: fixed;
}
.proj-card { background: rgba(255,255,255,.045); border: 3px solid var(--color-proj-line);
  border-radius: var(--radius-2xl); backdrop-filter: blur(2px); }
.proj-glow { box-shadow: 0 0 0 6px rgba(111,227,180,.10), 0 18px 60px -20px rgba(111,227,180,.55); }

/* apparitions */
@keyframes popIn { 0%{opacity:0;transform:scale(.72) translateY(10px);filter:blur(10px)}
  62%{opacity:1;transform:scale(1.06) translateY(0);filter:blur(0)} 100%{transform:scale(1)} }
@keyframes riseIn { from{opacity:0;transform:translateY(14px)} to{opacity:1;transform:none} }
@keyframes pulseRing { 0%{box-shadow:0 0 0 0 rgba(255,196,107,.55)} 70%{box-shadow:0 0 0 18px rgba(255,196,107,0)} 100%{box-shadow:0 0 0 0 rgba(255,196,107,0)} }
@keyframes floaty { 0%,100%{transform:translateY(0) rotate(0)} 50%{transform:translateY(-9px) rotate(2deg)} }
.revealed { animation: popIn .52s cubic-bezier(.34,1.5,.64,1) both; }
.rise { animation: riseIn .45s var(--bounce, cubic-bezier(.34,1.4,.64,1)) both; }
.floaty { animation: floaty 5.5s ease-in-out infinite; }
.pulse  { animation: pulseRing 2.2s ease-out infinite; }

/* pastilles de langue en projection */
/* L'étiquette de langue. Elle porte un code écrit, ou un drapeau tracé quand
 * la langue en a un — voir `Lang::flag()`. */
.lang-tag { display:inline-flex; align-items:center; justify-content:center;
  font-family: Fredoka; font-weight:700; font-size:19px; letter-spacing:.06em;
  width:66px; height:46px; border-radius: var(--radius-md); flex:none; }

/*
 * Avec un drapeau, la pastille disparaît.
 *
 * Elle avait d'abord gardé l'accent de langue en cadre autour du tracé. Trois
 * pixels d'orange autour d'un drapeau rouge et jaune ne se lisent pas comme
 * un accent : ils se lisent comme une bordure de tableau, et le drapeau a
 * l'air encadré au mur. L'accent servait à identifier la langue d'un coup
 * d'œil ; c'est précisément ce que le drapeau fait, et mieux. Il n'a besoin
 * de rien autour de lui.
 */
.lang-tag-flag {
  width: calc(clamp(46px, 5.4vh, 64px) * var(--proj-fit, 1));
  height: calc(clamp(31px, 3.6vh, 43px) * var(--proj-fit, 1));
  padding: 0;
  background: none;
  border: none;
  border-radius: 4px;
  overflow: hidden;
}

.lang-tag-flag svg {
  width: 100%;
  height: 100%;
  display: block;
  /* Un liseré, pas un cadre : un drapeau à bande blanche perdrait son bord
   * sur un fond clair, et le blanc de l'Union Jack touche les quatre côtés. */
  outline: 1px solid rgb(255 255 255 / .18);
  outline-offset: -1px;
}
.lang-tag-es { background: var(--color-lang-es); color: var(--color-ink); }
.lang-tag-en { background: var(--color-lang-en); color: var(--color-ink); }
.lang-tag-fr { background: var(--color-lang-fr); color: var(--color-ink); }
.lang-tag-it { background: var(--color-lang-it); color: var(--color-ink); }
.lang-tag-de { background: var(--color-lang-de); color: var(--color-ink); }
.lang-tag-off { background: transparent; border: 3px solid var(--color-proj-line); color: var(--color-proj-ink-muted); }

/* roue */
.wheel-wrap { position: relative; width: 100%; max-width: 340px; margin: 0 auto; }
.wheel { transition: transform 2.9s cubic-bezier(.12,.86,.16,1); transform-origin: 50% 50%; }
.wheel-hub { position:absolute; inset:0; display:grid; place-items:center; pointer-events:none; }
.wheel-hub b { font-family: Fredoka; font-weight:700; font-size:34px; color: var(--color-proj-ink); text-align:center; line-height:1.05; }
.wheel-hub small { display:block; font-family: Fredoka; font-weight:500; font-size:14px; color: var(--color-proj-ink-muted); margin-top:6px; }

/* confettis discrets */
.spark { position:absolute; width:12px; height:12px; border-radius:3px; opacity:.9; animation: floaty 6s ease-in-out infinite; }

/* ── Addendum de production ──────────────────────────────────────────────
 * Les maquettes portent en attribut `style` ce qui, dans le plugin, doit être
 * une classe : un balisage produit par PHP ne peut pas être ajusté à la main
 * écran par écran. Rien ici n'introduit de valeur nouvelle — tout vient de
 * tokens.css.
 */

/* Le dévoilement se fait par masquage, et non plus par floutage : la classe
 * voit qu'il reste quelque chose à découvrir — une barre pleine à la largeur
 * du mot —, ce qu'un élément absent ne dirait pas, et ce qu'un flou disait
 * mal. Voir plus bas, à `.proj-veiled`. */

/* C'est le contenu qui défile, jamais la page.
 *
 * `min-height: 100vh` laissait la coquille grandir avec le contenu : cinq
 * items d'« El acento » suffisaient à repousser le pied sous la ligne de
 * flottaison, et le professeur perdait « Découvrir », « Autre variante » et
 * « Revenir au sommaire » au moment précis où il en avait besoin — devant sa
 * classe, sans pouvoir chercher.
 *
 * La coquille tient donc exactement la hauteur de l'écran. L'en-tête et le
 * pied ne se compriment pas ; seul le corps défile. Le `min-height: 0` est
 * indispensable : un élément flex refuse par défaut de devenir plus petit que
 * son contenu, et sans lui le débordement ressort au lieu de défiler. */
/* `overflow: hidden` masque le débordement mais laisse le conteneur défiler
 * par programme : quand le navigateur amène un élément qui vient de recevoir le
 * focus dans la vue, la coquille entière glissait, et l'en-tête sortait de
 * l'écran sans que rien ne puisse le ramener. `clip` interdit ce défilement.
 * Le corps, lui, défile toujours — c'est son rôle. */
body.projection .proj-shell { height: 100vh; height: 100dvh; min-height: 100vh; min-height: 100dvh; overflow: hidden; overflow: clip; padding: var(--spacing-5) var(--spacing-6); }
body.projection .proj-head,
body.projection .proj-foot { flex: 0 0 auto; }
/*
 * Le corps défile verticalement, jamais horizontalement.
 *
 * `overflow-y: auto` seul ne suffit pas : quand un axe est réglé et l'autre
 * laissé à `visible`, le navigateur ramène le second à `auto`. Une barre
 * horizontale apparaissait donc au moindre dépassement — et il y en a un à
 * chaque dévoilement, parce qu'un voile peint bien au-delà de
 * sa boîte, d'environ trois fois son rayon de chaque côté. La réponse voilée
 * suivante poussait ainsi une quarantaine de pixels de halo hors du cadre.
 *
 * `clip` plutôt que `hidden` : `hidden` autoriserait encore un défilement
 * horizontal par programme, celui-là même qui avait fait glisser la scène
 * entière quand le menu de signalement prenait le focus.
 */
body.projection .proj-body {
	flex: 1 1 auto;
	min-height: 0;
	min-width: 0;
	overflow-y: auto;
	overflow-x: clip;
	overscroll-behavior: contain;
}
/* `min-width: 0` sans quoi un enfant large — une phrase d'exemple, une carte —
 * refuse de se réduire et pousse la colonne au-delà du cadre. C'est la règle
 * qu'on oublie une fois sur deux avec les boîtes flexibles. */
/*
 * La colonne principale s'étire sur toute la hauteur du corps et devient une
 * boîte flexible : sans cela, une carte réglée sur « toute la hauteur » n'a
 * aucune hauteur à quoi se référer, et retombe à zéro.
 */
body.projection .proj-main {
	min-height: 0;
	min-width: 0;
	align-self: stretch;
	display: flex;
	flex-direction: column;
}

/*
 * Une scène qui porte un planisphère lui donne toute la hauteur : la carte du
 * monde n'a de sens qu'en grand.
 *
 * La règle nommait « La hora ». Depuis que « El tiempo » pose ses villes sur
 * la même carte, elle ne le suivait pas : la carte réglée sur « toute la
 * hauteur » n'avait aucune hauteur à quoi se référer, retombait à zéro, et les
 * trois villes se superposaient en un point sur un fond vide. On désigne donc
 * ce qu'il y a dans la scène, et non le module qui l'a écrite — le prochain
 * module à villes marchera sans qu'on y revienne.
 */
body.projection .proj-body.has-map .proj-main > [data-vd-start],
body.projection .proj-body.has-map .proj-main > [data-vd-start] > .proj-row {
	flex: 1 1 auto;
	min-height: 0;
	display: flex;
}

/*
 * Sur un petit écran, la scène s'empile et chaque bloc prend la largeur.
 *
 * Elle est bâtie pour un écran large : une colonne média à gauche, la scène à
 * droite, un panneau d'aide dans le coin. Sur un téléphone tenu debout, cela
 * donnait une image par-dessus la phrase du mot du jour, un visage sur une
 * demi-largeur, une roue des verbes à côté d'un texte coupé. Les seuils
 * d'empilement étaient dispersés — quarante-huit rem ici, soixante là —, si
 * bien qu'entre les deux la scène restait en colonnes sans plus en avoir la
 * place.
 *
 * Un seul seuil désormais, celui de la carte : en dessous, la scène s'empile.
 * Les `!important` ne sont pas un aveu : ils reprennent la main sur les règles
 * de « phase 2 » du mot du jour, qui imposent une colonne média étroite et qui
 * sont elles-mêmes marquées ainsi.
 */
@media (max-width: 63.9375rem) {
	body.projection .proj-body { flex-direction: column; align-items: stretch; gap: var(--spacing-4); }

	body.projection .proj-media,
	body.projection .proj-shell[data-vd-phases].is-phase-2 .proj-media {
		flex: 0 0 auto !important;
		width: 100%;
		max-width: 100%;
		align-self: stretch !important;
	}

	body.projection .proj-main,
	body.projection .proj-shell[data-vd-phases].is-phase-2 .proj-main {
		flex: 1 1 auto !important;
		width: 100%;
		min-width: 0;
	}

	/* L'aide revient dans le flux, sous la scène, sur toute la largeur. */
	body.projection .proj-panel,
	body.projection .proj-shell[data-vd-phases].is-phase-2 .proj-panel {
		position: static;
		width: auto;
		max-height: none;
		overflow: visible;
	}

	body.projection .proj-main.has-panel > .t-proj-q,
	body.projection .proj-main.has-panel > [data-vd-start] { padding-right: 0; }

	/* Une zone par ligne : un visage ou une ville à demi-largeur ne se lit pas. */
	.proj-zones, .emo-zones, .col-zones { grid-template-columns: 1fr; }

	/*
	 * L'image du mot du jour ne prend pas tout l'écran : elle illustre, elle
	 * n'est pas le contenu — le mot et sa phrase le sont.
	 */
	body.projection .proj-media .proj-frame { max-height: 38vh; aspect-ratio: auto; }
	body.projection .proj-media .proj-frame img { max-height: 36vh; width: auto; margin-inline: auto; }

	/*
	 * La roue obéit au même plafond, par sa largeur.
	 *
	 * Le cadre plafonne à trente-huit pour cent de la hauteur et rogne ce qui
	 * dépasse — c'est ce qu'il faut pour une photo, qu'on préfère voir
	 * recadrée que minuscule. Mais la roue est un carré : sa hauteur vaut sa
	 * largeur, et rien ne lui disait de se réduire. Sur un écran large et
	 * court, elle gardait ses vingt-deux rem et se faisait couper au tiers
	 * inférieur — « visitar », « cerrar », « querer » disparaissaient sous le
	 * bord du cadre, et le verbe tiré pouvait être l'un d'eux.
	 *
	 * On la borne donc par la hauteur disponible. Le rapport d'un pour un
	 * fait le reste : contrainte en largeur, elle l'est en hauteur.
	 */
	body.projection .proj-media .wheel-wrap { max-width: min( 22rem, 34vh ); }

	/*
	 * Les commandes restent sous le pouce.
	 *
	 * Depuis que la scène se déroule au lieu de se rogner, elles partaient
	 * sous la ligne de flottaison : il fallait faire défiler tout le contenu
	 * pour atteindre « Découvrir », c'est-à-dire pour faire avancer le
	 * rituel. Elles se collent donc au bas de la fenêtre, sur un fond opaque
	 * — sans quoi le texte défilerait en transparence derrière elles.
	 */
	body.projection .proj-foot {
		position: sticky;
		bottom: 0;
		z-index: 5;
		margin-top: var(--spacing-5);
		padding-block: var(--spacing-3);
		padding-bottom: calc( var(--spacing-3) + env( safe-area-inset-bottom, 0px ) );
		background: var(--color-proj-surface);
		box-shadow: 0 -12px 18px -12px rgb(0 0 0 / .8);
	}

	/*
	 * Et la scène se termine au-dessus d'elle.
	 *
	 * Collée au bas de la fenêtre, la barre passe devant ce qui défile : la
	 * dernière ligne d'une phrase, les deux dernières formes d'une
	 * conjugaison, finissaient derrière les boutons.
	 *
	 * La réserve vaut la hauteur de la barre, pas une marge de confort : un
	 * bouton fait deux lignes de texte et ses marges, soit environ quatre
	 * rems, et l'encoche du téléphone s'y ajoute. Trop courte, elle ne
	 * corrige rien — c'est l'erreur du premier essai, à une seule mesure
	 * d'espacement.
	 */
	body.projection .proj-body {
		padding-bottom: calc( 5rem + env( safe-area-inset-bottom, 0px ) );
	}
}

/*
 * Sur un petit écran, la scène se déroule au lieu de se rogner.
 *
 * La scène tient dans la hauteur de l'écran et coupe ce qui dépasse : devant
 * une classe, ce qui déborde n'est jamais lu, et faire défiler ne se fait
 * pas. Mais la carte y devient une liste de villes, et la liste, le bandeau
 * des tournures et les commandes ne tiennent pas dans un téléphone tenu
 * debout : la liste débordait de sa case et venait se poser sur le bandeau.
 *
 * Un téléphone n'est pas un vidéoprojecteur. En dessous du seuil de la carte,
 * la scène reprend donc la hauteur de son contenu, et la page défile.
 */
@media (max-width: 63.9375rem) {
	body.projection .proj-shell {
		height: auto;
		min-height: 100vh;
		min-height: 100dvh;
		overflow: visible;
	}

	/*
	 * Et le corps cesse d'être un ascenseur dans l'ascenseur.
	 *
	 * La coquille reprenait bien la hauteur de son contenu, mais le corps
	 * gardait son `overflow-y: auto` et son `flex: 1` : il se calait sur la
	 * place restante et faisait défiler *à l'intérieur*, dans une coquille
	 * haute d'exactement un écran. Résultat, la page ne bougeait pas d'un
	 * pixel et le pouce glissait dans une boîte dont rien ne signalait le
	 * bord — c'est le défilement qu'on cherche sans le trouver.
	 *
	 * Sur un téléphone, il n'y a qu'un ascenseur et c'est la page. Le corps
	 * reprend donc sa hauteur naturelle et laisse passer.
	 */
	body.projection .proj-body {
		flex: 0 0 auto;
		min-height: 0;
		overflow: visible;
		overscroll-behavior: auto;
	}

	body.projection .proj-main,
	body.projection .proj-main > [data-vd-start] {
		flex: 0 0 auto;
		min-height: 0;
	}

	body.projection .proj-body.has-map .proj-main > [data-vd-start],
	body.projection .proj-body.has-map .proj-main > [data-vd-start] > .proj-row {
		flex: 0 0 auto;
		min-height: auto;
	}
}

/*
 * Mais un paysage de seize neuvièmes n'est pas un téléphone.
 *
 * Un cadre collé dans Canva, Genially ou un Padlet fait souvent 860 à 960
 * pixels de large : sous le seuil des soixante-quatre rem, donc empilé comme
 * sur un téléphone, avec une page qui défile sous des boutons restés en bas.
 * Dès que la fenêtre est couchée et assez haute, la scène reprend la
 * hauteur de l'écran et se réduit pour tenir, comme sur un grand écran. La
 * roue des verbes a son propre palier, plus bas, qui garde la main.
 */
@media (max-width: 63.9375rem) and (min-width: 40rem) and (min-height: 30rem) and (orientation: landscape) {
	body.projection .proj-shell:not([data-vd-module="rueda-verbos"]) {
		height: 100vh;
		height: 100dvh;
		min-height: 0;
		overflow: hidden;
		overflow: clip;
	}

	body.projection .proj-shell:not([data-vd-module="rueda-verbos"]) .proj-body {
		flex: 1 1 auto;
		min-height: 0;
		overflow-y: auto;
		overscroll-behavior: contain;
	}

	body.projection .proj-shell:not([data-vd-module="rueda-verbos"]) .proj-main > [data-vd-start] {
		flex: 1 1 auto;
		min-height: 0;
	}
}

/*
 * Partout ailleurs, la pile de lignes occupe la hauteur disponible et se
 * centre dedans — sans étirer les lignes elles-mêmes.
 *
 * La distinction est ce qui manquait. Étirer les lignes distribuerait la
 * hauteur entre les items et laisserait des trous entre des textes d'une
 * ligne ; centrer la pile ne change rien à leur taille et met le contenu là
 * où l'œil le cherche. Une scène d'un seul mot occupait le seizième supérieur
 * gauche d'un écran de trois mètres.
 */
body.projection .proj-main > [data-vd-start] {
	flex: 1 1 auto;
	min-height: 0;
	justify-content: center;
}

.proj-row { display: flex; align-items: center; gap: var(--spacing-4); }

.proj-row[data-row][aria-hidden="true"] { opacity: .4; }

/*
 * Ce qui reste à trouver se masque, il ne se floute plus.
 *
 * Le voile était un flou de quatorze pixels. Il disait bien qu'il y avait
 * quelque chose — mais une scène qui compte cinq lignes en attente était
 * floue aux cinq sixièmes, et un écran flou ne se lit pas comme un secret :
 * il se lit comme une panne de vidéoprojecteur. Un professeur ne sait pas si
 * la mise au point est mauvaise ou si c'est voulu.
 *
 * Le texte devient donc transparent sur une barre pleine, à la largeur exacte
 * du mot qu'elle cache. Rien ne bouge au dévoilement — la barre s'efface, le
 * mot paraît à sa place — et personne ne peut lire au travers, ce que le flou
 * ne garantissait pas sur les mots courts.
 */
.proj-row[data-row][aria-hidden="true"] .proj-answer,
.proj-row[data-row][aria-hidden="true"] .t-proj-a,
.proj-row[data-row][aria-hidden="true"] .word-chip,
.proj-veiled {
	color: transparent;
	user-select: none;
	/*
	 * Une barre posée sur la ligne, et non un pavé de la hauteur du texte.
	 *
	 * Le fond appliqué à toute la boîte donnait une dalle grise haute comme
	 * une réponse de quatre-vingts pixels — plus voyante que la question
	 * qu'elle accompagne. Le dégradé la ramène à la moitié de la hauteur de
	 * fonte, centrée sur la ligne : c'est un caviardage, et cela se lit
	 * comme tel.
	 *
	 * `box-decoration-break` la refait à chaque ligne quand la phrase se
	 * replie ; sans lui, une phrase sur deux lignes n'aurait qu'une barre à
	 * cheval sur les deux.
	 */
	background-image: linear-gradient(var(--color-proj-line), var(--color-proj-line));
	background-size: 100% .52em;
	background-position: 0 55%;
	background-repeat: no-repeat;
	box-decoration-break: clone;
	-webkit-box-decoration-break: clone;
}

.proj-row[data-row][aria-hidden="false"] { opacity: 1; }

.proj-row[data-row][aria-hidden="false"] .proj-answer,
.proj-row[data-row][aria-hidden="false"] .t-proj-a { filter: none; }

/* Un voile dévoilé perd son flou, où qu'il soit — et ses enfants avec lui.
 *
 * Le dévoilement retire d'ordinaire `proj-veiled` ; cette règle couvre les
 * chemins où les deux classes se croisent. Les enfants y sont nommés parce que
 * « sous un voile, rien ne parle » les éteint tous : sans cette ligne, un voile
 * levé resterait muet à l'intérieur. */
.proj-veiled.revealed,
.proj-row[data-row][aria-hidden="false"] .proj-answer,
.proj-row[data-row][aria-hidden="false"] .t-proj-a {
	color: inherit;
	background-image: none;
	user-select: auto;
}

/* Un voile qui garderait ses deux classes ne doit pas rester muet à
 * l'intérieur : l'invariant ne vaut que tant que le voile est fermé. */
.proj-veiled.revealed * { color: inherit !important; }

/*
 * La phrase, bornée en largeur autant qu'en hauteur.
 *
 * La projection se mesure en `vh`, et c'est juste : un vidéoprojecteur est
 * contraint par sa hauteur, jamais par sa largeur. Un téléphone tenu debout
 * est l'exact contraire — beaucoup de hauteur, très peu de largeur —, et la
 * même règle y donnait une typographie calibrée pour une hauteur dont l'écran
 * dispose, dans une largeur dont il ne dispose pas : « Mi hermano abre el
 * cuaderno en clase. » sortait sur quatre lignes de capitales d'affiche.
 *
 * Le professeur relit la scène sur son téléphone avant le cours — c'est déjà
 * la raison pour laquelle « El número » avait reçu le même traitement, et la
 * phrase du mot du jour n'avait jamais été bornée.
 *
 * Rien ne change sur un vidéoprojecteur : en 1920 × 1080, `6.4vh` vaut 69 px
 * et `9vw` en vaut 173 — c'est la hauteur qui l'emporte, comme avant. La
 * borne en largeur ne mord qu'en portrait.
 */
.proj-answer-lead { font-weight: 700; font-size: calc(clamp(26px, min(6.4vh, 9vw), 74px) * var(--proj-fit, 1)); }

/* Une réponse de quelques signes est tout le contenu de la scène : elle prend
 * l'écran. Le seuil qui décide est posé dans le module — douze caractères, au
 * -delà de quoi c'est une phrase et non un mot. */
.proj-answer-display { font-size: calc(clamp(48px, 16vh, 220px) * var(--proj-fit, 1)); line-height: 1; }

/*
 * « El número » : une seule colonne, au centre.
 *
 * Le nombre flottait au milieu et sa réponse partait sur le côté, plus
 * petite, sur une ligne décalée : l'œil ne savait pas où aller, et la moitié
 * de l'écran restait vide. Le nombre prend donc toute la place en haut, la
 * réponse se lit dessous, dans un cadre — flouté avant d'être dévoilé, comme
 * partout : la classe voit qu'il reste quelque chose à dire.
 */
body.projection .proj-shell[data-vd-module="numero"] .proj-row[data-row] {
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 3vh;
	text-align: center;
}

body.projection .proj-shell[data-vd-module="numero"] .proj-answer-display {
	font-size: calc(min(30vh, 24vw) * var(--proj-fit, 1));
	line-height: .9;
}

body.projection .proj-shell[data-vd-module="numero"] [data-vd-veil] {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 1vh;
	padding: 2.2vh 5vw;
	border: 2.5px solid var(--color-proj-line);
	border-radius: var(--radius-xl);
	background: color-mix(in oklab, var(--color-proj-ink) 6%, transparent);
}
@supports not (color: color-mix(in srgb, red, blue)) { body.projection .proj-shell[data-vd-module="numero"] [data-vd-veil] { background: rgba(255,246,233,0.06); } }

body.projection .proj-shell[data-vd-module="numero"] [data-vd-veil] .t-proj-a { font-size: calc(min(7.5vh, 5.5vw) * var(--proj-fit, 1)); font-weight: 600; }
/* « En letras » : un plancher en pixels, sinon l'étiquette disparaît sur un
 * téléphone tenu debout, où un centième de la largeur ne fait que neuf
 * pixels. Le professeur relit la scène sur son téléphone avant le cours. */
body.projection .proj-shell:is([data-vd-module="numero"], [data-vd-module="efemerides"]) [data-vd-veil] .t-eyebrow { font-size: calc(clamp(14px, 2.2vh, 26px) * var(--proj-fit, 1)); color: var(--color-proj-ink-muted); }

/*
 * Les morceaux du nombre s'écartent les uns des autres.
 *
 * Le dévoilement remet chacun de ses enfants en bloc — `[data-vd-veil] > *` —,
 * et cette règle-là, plus forte, annulait la disposition en ligne : les
 * morceaux se touchaient, « trescientossetenta y tres ». On la reprend donc
 * ici, sous le module, avec la force qu'il faut.
 *
 * « Un día como hoy » décompose l'année avec le même balisage, et attrape donc
 * le même défaut : les deux modules sont nommés ensemble plutôt que la règle
 * recopiée.
 */
body.projection .proj-shell:is([data-vd-module="numero"], [data-vd-module="efemerides"]) [data-vd-veil] .num-words {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	align-items: flex-start;
	gap: .1em .45em;
}

/*
 * Le nombre décomposé : chaque groupe de chiffres a la couleur des mots qui le
 * disent, et sa valeur s'écrit en petit sous les mots. « 373 » : 3 et
 * « trescientos » en or, 73 et « setenta y tres » en vert — la construction
 * du nombre se voit, là où les élèves se trompent.
 *
 * Quatre couleurs, du plus grand au plus petit, prises aux jetons de la scène
 * ou éclaircies vers l'encre pour tenir sur le fond sombre du vidéoprojecteur.
 */
.num-m { color: color-mix( in oklab, var(--color-family-fonologia) 55%, var(--color-proj-ink) ); }
@supports not (color: color-mix(in srgb, red, blue)) { /*
 * Le nombre décomposé : chaque groupe de chiffres a la couleur des mots qui le
 * disent, et sa valeur s'écrit en petit sous les mots. « 373 » : 3 et
 * « trescientos » en or, 73 et « setenta y tres » en vert — la construction
 * du nombre se voit, là où les élèves se trompent.
 *
 * Quatre couleurs, du plus grand au plus petit, prises aux jetons de la scène
 * ou éclaircies vers l'encre pour tenir sur le fond sombre du vidéoprojecteur.
 */
.num-m { color: rgb(231,158,184); } }
.num-k { color: color-mix( in oklab, var(--color-primary) 45%, var(--color-proj-ink) ); }
@supports not (color: color-mix(in srgb, red, blue)) { .num-k { color: rgb(189,171,225); } }
.num-h { color: var(--color-proj-accent); }
.num-u { color: var(--color-proj-success); }

.num-words { display: flex; flex-wrap: wrap; justify-content: center; align-items: flex-start; gap: .1em .45em; }
.num-part { display: inline-flex; flex-direction: column; align-items: center; }

/*
 * La valeur sous les mots se lit à trois mètres, ou ne sert à rien.
 *
 * Elle sortait à un tiers de la taille des mots, en gris pâle : sur un
 * vidéoprojecteur, « 1.000 » sous « mil » devenait une tache. Elle prend la
 * couleur de son morceau — c'est ce qui les relie — et presque la moitié de
 * sa taille.
 */
.num-part small { font-family: "Space Mono", ui-monospace, monospace; font-weight: 700;
  font-size: .46em; margin-top: .2em; letter-spacing: .02em; }
.num-link { color: var(--color-proj-ink-muted); }

/*
 * Un voile ne cache que ce qui n'a pas sa propre couleur.
 *
 * Le caviardage travaille en `color: transparent`. Les morceaux du nombre,
 * eux, posent leur couleur en clair — quatre règles plus spécifiques que
 * celle du voile. Résultat : la réponse restait lisible sous une barre qui
 * la traversait, et la scène donnait l'année avant qu'on l'ait demandée. Il
 * faut donc éteindre aussi les morceaux, et les rallumer au dévoilement.
 */
/*
 * Rien ne se lit sous un voile, quelle que soit sa couleur.
 *
 * `color: transparent` posé sur la boîte voilée ne tient que par héritage :
 * tout enfant qui déclare sa propre couleur passe devant, et son texte se lit
 * au travers du caviardage. C'est arrivé deux fois — les chiffres colorés de
 * l'année, puis « esta sobra » de l'intrus —, et cela arrivera à chaque module
 * qui donnera une couleur à ce qu'il cache.
 *
 * D'où le sélecteur universel, qui est ici le bon outil : la règle n'est pas
 * « ces classes-là se taisent » mais « sous un voile, rien ne parle ». Une
 * liste à tenir à jour est une liste qu'on oubliera d'allonger, et l'oubli ne
 * se verra qu'en classe, sur le mur, devant trente élèves.
 *
 * Les fonds et les bordures restent : ce qui doit disparaître est le texte,
 * pas la forme qui le contiendra.
 *
 * `!important`, et c'est l'un des rares endroits qui le méritent. La règle a
 * le poids d'une classe, comme celles des modules — `.intru-out`,
 * `.num-k` — qui sont écrites plus loin dans la feuille : à poids égal, la
 * dernière gagne, et c'était la couleur du module. La réponse se lisait donc
 * sous sa propre barre de caviardage. Ce n'est pas une préférence de style
 * qu'on surcharge ici, c'est un invariant : sous un voile, rien ne se lit, et
 * aucun module n'a le droit d'en décider autrement.
 */
.proj-veiled,
.proj-veiled * { color: transparent !important; }

/*
 * « Aujourd'hui dans l'histoire » : la phrase, et le bouton qui la dit.
 *
 * Le bouton est dans la scène et non dans le pied. À trois mètres, une barre
 * d'outils ne se lit pas ; et comme le navigateur refuse de parler tant que
 * rien n'a été cliqué, c'est ce bouton qui porte le premier geste.
 */
.efem-line { gap: var(--spacing-4); align-items: flex-start; }
.efem-line .listen-row .proj-btn { font-size: calc(clamp(15px, 2.4vh, 26px) * var(--proj-fit, 1)); }

/* « Un día como hoy » : l'année et ses mots, centrés l'un sous l'autre. */
.efem-year { align-items: center; gap: var(--spacing-2); width: 100%; }

/* La soustraction, en chiffres monospacés : les deux années s'alignent. */
.efem-sum { font-family: "Space Mono", ui-monospace, monospace; letter-spacing: .04em;
  color: var(--color-proj-ink-muted); }

/* Le compteur, en haut à droite de la scène, là où il ne dispute rien. */
/* Le compteur « 3 / 5 » est posé dans le coin de la scène : il lui faut un
   repère. Déclaré par le serveur, qui sait s'il l'a mis. */
.proj-main.has-count { position: relative; }
.proj-count { position: absolute; top: 0; right: 0; font-family: Fredoka; font-weight: 600; font-size: calc(clamp(16px, 3vh, 34px) * var(--proj-fit, 1)); color: var(--color-proj-ink-muted); font-variant-numeric: tabular-nums; }

/* Une réponse qui prend l'écran se centre dedans — quand elle est seule.
 *
 * Alignée à gauche, elle laissait les deux tiers droits vides, ce qu'on
 * reproche à juste titre à une scène de projection. Mais la règle s'appliquait
 * aussi aux scènes qui empilent plusieurs lignes, et là elle cassait tout :
 * sur « La fecha », « martes » se centrait pendant que le jour, le mois,
 * l'année et la phrase restaient calés à gauche. Une ligne au milieu, quatre
 * au bord — on ne voit plus que ça.
 *
 * Le centrage vaut donc là où il n'y a qu'une chose à l'écran : les modules
 * qui ne montrent qu'un item à la fois, et les scènes d'une seule ligne.
 * Partout ailleurs, toutes les lignes partagent le même bord. */
body.projection .proj-shell[data-vd-solo] .proj-row:has(.proj-answer-display),
body.projection .proj-shell[data-vd-steps="1"] .proj-row:has(.proj-answer-display) {
	justify-content: center;
}

/* Les étiquettes tiennent une colonne, et les réponses commencent toutes au
 * même endroit.
 *
 * « EL DÍA », « EL MES », « EL AÑO », « EL DÍA DE LA SEMANA » : quatre
 * étiquettes de largeurs différentes, posées à gauche, faisaient démarrer
 * leurs quatre réponses à quatre abscisses différentes. L'œil cherche
 * l'alignement qu'il attend d'une liste, ne le trouve pas, et l'écran paraît
 * bâclé sans qu'on sache dire pourquoi.
 *
 * Une largeur fixe en `ch` plutôt qu'une grille : la colonne doit être la même
 * d'une ligne à l'autre, or chaque ligne est sa propre boîte flexible et ne
 * sait rien de ses voisines. Vingt caractères logent la plus longue étiquette
 * des trois langues ; au-delà elle passe à la ligne dans sa colonne, et les
 * réponses restent alignées. */
body.projection .proj-shell:not([data-vd-solo]) .proj-row > .t-eyebrow:first-child {
	flex: 0 0 auto;
	width: 20ch;
	text-align: right;
	overflow-wrap: break-word;
}

/*
 * Une réponse en tête de liste n'est pas une réponse qui prend l'écran.
 *
 * « querer » fait six signes : la règle du mot court lui donnait cent
 * quarante-quatre pixels. Mais il n'est pas le contenu de la scène — les six
 * formes conjuguées le sont, et elles passaient sous la ligne de flottaison
 * pour lui laisser la place. Un mot ne prend l'écran que lorsqu'il n'y a rien
 * d'autre à montrer.
 */
.proj-row:has(.proj-group) .proj-answer-display {
	font-size: calc(clamp(26px, 6.4vh, 74px) * var(--proj-fit, 1));
}

body.projection .proj-row:has(.proj-group) { justify-content: flex-start; }

/* Le sourcil qui porte la règle — « sin tilde y termina en vocal » — est le
 * seul texte que la classe recopie. Il ne peut pas rester en corps
 * d'étiquette. */
body.projection .proj-row .t-eyebrow { font-size: calc(clamp(14px, 2.2vh, 24px) * var(--proj-fit, 1)); }

.proj-media { flex: 1 1 340px; min-width: 270px; position: relative; }

.proj-main { flex: 1 1 460px; min-width: 300px; gap: var(--spacing-6); }

/* L'espace entre la scène et son panneau était calibré pour une page qui
 * défile. Sur un écran d'une seule hauteur, il se prend sur le contenu — et le
 * contenu est ce qu'on projette. */
.proj-body { gap: var(--spacing-6); align-items: center; }

.proj-head { gap: var(--spacing-3); }

.proj-head .proj-eyebrow { width: 100%; }

.proj-steps-bar { max-width: 300px; }

.proj-levels { gap: var(--spacing-1); }

.proj-note { border: none; color: var(--color-proj-ink-muted); }

.proj-foot { gap: var(--spacing-3); }

.proj-panel { padding: var(--spacing-5); }

/* La mention de source : obligatoire, et discrète. Elle doit être lisible de
 * qui la cherche, invisible de qui regarde la réponse. */
.proj-credit {
	margin: var(--spacing-3) 0 0;
	font-size: calc(clamp(11px, 1.6vh, 16px) * var(--proj-fit, 1));
	color: var(--color-proj-ink-muted);
}

.proj-frame { padding: var(--spacing-4); overflow: hidden; }

/* ══ une illustration projetée ══
 *
 * L'image du mot du jour partait avec `width: 100%` et rien d'autre. Une
 * illustration carrée de mille pixels prenait donc toute la largeur de sa
 * colonne, puis toute la hauteur qui va avec — et la scène, qui tient en un
 * écran par principe, se mettait à défiler. Le professeur voyait un sac à dos
 * magnifique et la moitié du mot.
 *
 * La contrainte est en hauteur, parce que c'est la hauteur qui manque : un
 * vidéoprojecteur est large. `contain` garde les proportions, et la colonne
 * s'étire d'elle-même autour.
 *
 * Le plafond est doublé — la hauteur disponible dans la boîte, et une valeur
 * en `vh`. La première suffit quand toute la chaîne flexible se comporte ; la
 * seconde tient même si l'un des ancêtres perd sa hauteur définie, ce qui
 * arrive dès qu'un module intercale une boîte. Une image trop petite n'a
 * jamais fait défiler personne ; une image trop grande, si. */
body.projection .proj-body.has-illus .proj-media { align-self: stretch; min-height: 0; display: flex; }

body.projection .proj-body.has-illus .proj-media > .proj-frame {
	flex: 0 1 auto;
	min-height: 0;
	display: flex;
	align-items: center;
	justify-content: center;

	/*
	 * Un cadre carré, borné en hauteur d'écran, quelle que soit l'image.
	 *
	 * Les illustrations n'ont pas toutes la même forme : un stylo est
	 * nettement plus haut que large, et le cadre s'étirait avec lui jusqu'à
	 * pousser la scène sous le bord de l'écran — une barre de défilement
	 * apparaissait en pleine projection.
	 *
	 * `max-height: 100%` ne suffisait pas : un pourcentage de hauteur ne
	 * résout rien quand le parent n'a pas de hauteur définie, et le navigateur
	 * le traite alors comme absent. La borne est donc en unités d'écran, qui
	 * ne dépendent de personne, et le rapport carré fixe la largeur d'après
	 * elle. L'image se contient dedans : plus haute que large ou l'inverse,
	 * elle tient.
	 */
	aspect-ratio: 1 / 1;
	max-height: min( 62vh, 62vw );
	width: auto;

	/*
	 * Le cadre porte le papier de l'illustration.
	 *
	 * Les images sont dessinées sur un fond crème, et le cadre était
	 * transparent : une image plus étroite que son cadre laissait voir le
	 * violet de la scène de part et d'autre, et le carton clair flottait au
	 * milieu comme un rectangle rapporté. Le cadre prend donc la même teinte
	 * que le papier des illustrations — la frontière disparaît, et le tout se
	 * lit comme une seule carte posée sur la scène.
	 */
	background: var(--color-proj-paper);

	/*
	 * Et l'image touche les bords.
	 *
	 * Le cadre gardait sa marge intérieure : le papier du cadre formait donc
	 * un anneau autour du papier du dessin, deux crèmes voisins mais pas
	 * identiques, et la carte semblait doublée. Sans marge, l'image remplit le
	 * carré et le fond ne se voit plus que là où il sert — les bandes d'une
	 * image qui n'est pas au format.
	 */
	padding: 0;
	overflow: hidden;
}

/* ══ la carte d'une ville, dans « El tiempo » ══
 *
 * Le pictogramme d'abord, puis la ville, puis le degré : c'est l'ordre de
 * lecture d'une carte météo, et celui dans lequel la classe formule sa
 * réponse — « en Madrid hace sol, treinta y cinco grados ».
 *
 * Le degré est gros mais pas autant que la réponse dévoilée : il pose la
 * question, il ne la remplace pas. */
.sky-glyph { display: block; }

.sky-glyph svg {
	width: clamp( 34px, 7vh, 72px );
	height: clamp( 34px, 7vh, 72px );
	fill: none;
	stroke: var(--color-proj-accent);
	stroke-width: 1.8;
	stroke-linecap: round;
	stroke-linejoin: round;
}

.sky-degrees {
	font-family: Fredoka;
	font-weight: 700;
	font-size: calc(clamp(22px, 5vh, 52px) * var(--proj-fit, 1));
	line-height: 1.1;
	color: var(--color-proj-ink);
}

.proj-illus {
	display: block;
	width: 100%;
	height: 100%;
	/* Le cadre borne déjà : l'image n'a qu'à s'y contenir. */
	max-height: 100%;
	object-fit: contain;
	border-radius: var(--radius-lg);
}

.proj-missing {
	display: grid;
	place-items: center;
	min-height: 220px;
	font-family: Fredoka;
	font-size: clamp(48px, 9vw, 96px);
	color: var(--color-proj-line);
}

/* Zones cliquables : le schéma `zones` du § 4.3. */
.proj-zone {
	display: flex;
	flex-direction: column;
	gap: var(--spacing-1);
	padding: var(--spacing-4);
	text-align: left;
	background: rgba(255, 255, 255, .045);
	border: 3px solid var(--color-proj-line);
	border-radius: var(--radius-xl);
	color: inherit;
	font: inherit;
	cursor: pointer;
}

.proj-zone[aria-expanded="true"] { border-color: var(--color-proj-accent); }

.proj-zones {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
	gap: var(--spacing-4);
}

/* La syllabe tonique se distingue par la taille et le poids autant que par la
 * couleur : sur un vidéoprojecteur délavé, la nuance seule disparaît. */
.syll { color: var(--color-proj-ink-muted); }

.syll-stress {
	font-style: normal;
	font-size: 1.25em;
	font-weight: 700;
	color: var(--color-proj-accent);
	border-bottom: .08em solid currentColor;
}

.syll-sep { color: var(--color-proj-line); }

/* La découpe en syllabes est la réponse du module : elle se lit d'aussi loin
 * que le mot. Elle sortait à la taille d'une réponse ordinaire, moitié moins
 * grande que le mot qu'elle explique. */
.proj-answer:has(> .syll) { font-size: calc(clamp(30px, 9vh, 120px) * var(--proj-fit, 1)); }

/* Champs de saisie. Les maquettes n'en montrent pas — leurs valeurs sont
 * figées — mais un écran qui corrige en a besoin. Hauteur 52 px, comme
 * l'exige le § 11 des specs. */
.field { display: flex; flex-direction: column; gap: var(--spacing-1); }

.field-input {
	width: 100%;
	min-height: 52px;
	padding: var(--spacing-2) var(--spacing-3);
	background: var(--color-surface-raised);
	color: var(--color-ink);
	border: 2px solid var(--color-line-strong);
	border-radius: var(--radius-md);
	font-family: var(--font-body-md, Nunito), system-ui, sans-serif;
	font-size: var(--text-body-md);
}

/* ══ les groupes de champs ══
 *
 * Aucune règle ne portait sur `fieldset` ni sur `legend` : les formulaires
 * héritaient donc du style par défaut du navigateur — un cadre en relief
 * gravé, hérité de 1996, avec l'intitulé encoché dedans qui coupe le trait.
 * Sur l'écran de création d'une classe, cela donnait cinq boîtes grises aux
 * titres à moitié effacés, au milieu de champs qui, eux, suivaient la charte.
 *
 * Le `fieldset` reste pour ce qu'il vaut — il groupe des boutons radio, et les
 * lecteurs d'écran annoncent la légende avant chaque option —, mais il ne
 * dessine plus rien. La légende redevient une étiquette posée au-dessus de son
 * groupe, comme celle de n'importe quel champ.
 *
 * `min-width: 0` parce qu'un `fieldset` refuse de se réduire dans une boîte
 * flexible sans cela : c'est une particularité de l'élément, pas un oubli. */
fieldset {
	border: 0;
	margin: 0;
	padding: 0;
	min-width: 0;
}

legend {
	display: block;
	width: 100%;
	padding: 0;
	margin-bottom: var(--spacing-2);
}

.field-input:focus-visible {
	outline: 3px solid var(--color-primary);
	outline-offset: 1px;
	border-color: var(--color-primary);
}

/* Un champ touché mais non enregistré doit se voir : un relecteur qui perd
 * son travail à 23 h ne recommence pas. */
.field-input.is-dirty { border-color: var(--color-gold); }

/* ══ l'œil d'un champ de mot de passe ══
 *
 * Trois états, et le second est celui qui compte : `armed` avertit SANS
 * dévoiler. Le champ se borde alors de la couleur du bandeau, pour que le
 * professeur qui ne lit pas voie quand même que quelque chose attend sa
 * décision. Voir `includes/class-password-eye.php`.
 *
 * L'œil se centre sur `.pwd-box` plutôt que de se caler à `top: 0` : la
 * hauteur d'un champ appartient à `.field-input`, et un bouton qui la
 * recopierait se décalerait le jour où elle change. */
.pwd-field { display: flex; flex-direction: column; gap: var(--spacing-2); }
.pwd-box { position: relative; display: block; }

/* La place de l'œil, réservée dans le champ : sans cela le dernier caractère
 * tapé passe sous le bouton. */
.pwd-field .pwd-input { padding-right: 52px; }

.pwd-eye {
	position: absolute;
	right: var(--spacing-1);
	top: 50%;
	transform: translateY(-50%);
	width: 44px; height: 44px;
	display: grid; place-items: center;
	border-radius: var(--radius-md);
	color: var(--color-ink-muted);
}
.pwd-eye svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.pwd-eye:hover { background: var(--color-surface-sunken); color: var(--color-ink); }

/* Un seul des deux tracés est monté à la fois : l'œil ouvert dit « on peut
 * afficher », l'œil barré dit « on peut masquer ». */
.pwd-eye-shut { display: none; }
[data-vd-state="shown"] .pwd-eye-open { display: none; }
[data-vd-state="shown"] .pwd-eye-shut { display: block; }
[data-vd-state="shown"] .pwd-eye { color: var(--color-primary); }
[data-vd-state="armed"] .pwd-eye { color: var(--color-gold-strong); background: var(--color-surface-sunken); }
[data-vd-state="armed"] .pwd-input { border-color: var(--color-brand-band); }

.pwd-warn {
	background: var(--color-surface-sunken);
	border-left: 4px solid var(--color-gold);
	border-radius: var(--radius-md);
	padding: var(--spacing-3);
	color: var(--color-gold-strong);
	font-size: 14px;
	line-height: 1.45;
}
.pwd-warn-say { display: flex; gap: var(--spacing-2); align-items: flex-start; margin: 0; }
.pwd-warn-mark svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; display: block; margin-top: 2px; }
.pwd-warn-acts { display: flex; flex-wrap: wrap; gap: var(--spacing-2); margin: var(--spacing-3) 0 0; }

/* Les deux actions portent le même poids visuel que leur avertissement, et pas
 * celui de l'action principale du formulaire : dévoiler son mot de passe n'est
 * pas ce que le professeur est venu faire sur cet écran. */
.pwd-warn-go { background: var(--color-gold-strong); color: var(--color-surface-raised); box-shadow: 0 4px 0 #6b4906; }
.pwd-warn-go:active { box-shadow: 0 0 0 #6b4906; }
.pwd-warn-no { background: var(--color-surface-raised); color: var(--color-gold-strong); border: 2px solid var(--color-gold-strong); }

.pwd-left { display: flex; gap: var(--spacing-2); align-items: center; margin: 0; font-size: 13px; color: var(--color-ink-muted); }
.pwd-left-mark svg { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; display: block; }

.review-frame {
	display: block;
	width: 100%;
	aspect-ratio: 16 / 9;
	border: 3px solid var(--color-line-strong);
	border-radius: var(--radius-xl);
	background: var(--color-proj-surface);
}

/* Texte réservé aux technologies d'assistance. Les pastilles de langue n'ont
 * pas de libellé visible — c'est le parti pris des maquettes — mais elles
 * doivent en avoir un pour qui n'en voit pas la couleur. */
.sr-only {
	position: absolute;
	width: 1px; height: 1px;
	margin: -1px; padding: 0;
	overflow: hidden;
	clip: rect(0 0 0 0);
	white-space: nowrap;
	border: 0;
}

/* Signalement en projection. Discret : il sert deux fois par trimestre, pas
 * deux fois par séance. Mais atteignable en un geste quand il sert. */
/* Le contrôle n'est plus un <details> : plus de marqueur de divulgation à
 * masquer, et plus de position relative à tenir puisque le panneau a quitté
 * cet élément pour le corps du document. */
.proj-report { display: inline-flex; }

/*
 * Le menu est ancré à la fenêtre, et vit dans le corps du document.
 *
 * Le déplacer là est ce qui a fini par le rendre atteignable. En absolu ou en
 * fixe mais laissé dans le pied de scène, il dépendait de tous ses ancêtres :
 * la coquille de projection découpe ce qui la dépasse, et un élément en
 * position fixe se laisse quand même contenir par un ancêtre qui porte une
 * transformation ou un filtre — la scène en compte plusieurs.
 *
 * En bas à droite, au-dessus du pied : c'est là que se trouve son bouton, et
 * c'est le seul coin dont on soit sûr qu'il reste libre.
 */
.proj-report-menu {
	position: fixed;
	right: var(--spacing-8);
	bottom: calc(var(--spacing-8) + 4.5rem);
	z-index: 60;
	display: flex;
	flex-direction: column;
	gap: var(--spacing-1);
	min-width: 18rem;
	max-width: min(24rem, calc(100vw - 2 * var(--spacing-4)));
	padding: var(--spacing-3);
	background: var(--color-proj-surface);
	border: 3px solid var(--color-proj-line);
	border-radius: var(--radius-xl);
	color: var(--color-proj-ink);
}

/* `hidden` doit gagner : la règle ci-dessus pose un `display: flex` qui, sans
 * cela, l'emporterait sur le `display: none` du navigateur — et le panneau
 * resterait ouvert en permanence. */
.proj-report-menu[hidden] { display: none; }

.proj-report-menu .proj-chip { text-align: left; }
.proj-report-menu .t-eyebrow { color: var(--color-proj-ink-muted); margin: 0 0 var(--spacing-1); }

/* La provenance d'un contenu de remplacement s'annonce : un professeur doit
 * savoir qu'il projette un autre niveau ou une archive, pas le contenu du jour. */
.proj-origin {
	display: inline-block;
	padding: var(--spacing-1) var(--spacing-3);
	border-radius: var(--radius-full);
	background: var(--color-proj-line);
	color: var(--color-proj-ink);
	font-family: var(--font-label), Nunito, sans-serif;
	font-size: var(--text-label);
	letter-spacing: var(--tracking-eyebrow);
	text-transform: uppercase;
}

/* Une puce qui est un lien doit s'annoncer comme tel : le survol et le focus
 * répondent, et le soulignement par défaut disparaît. */
/* Une ancre déguisée en contrôle ne se souligne pas. Un vrai lien dans une
 * phrase, si : le soulignement est le seul repère qui ne dépende pas de la
 * couleur, et le supprimer partout d'un `a { text-decoration: none }` global
 * priverait de ce repère les daltoniens. D'où une liste — mais une liste dont
 * le sélecteur d'attribut attrape `btn`, `btn-ghost` et `proj-btn` du même
 * coup, ainsi que les variantes à venir. Corriger ce défaut une classe à la
 * fois l'a laissé revenir trois fois. */
/* Un lien de texte.
 *
 * Faute de règle, les quelques liens qui n'habillent pas un contrôle —
 * « Mot de passe oublié ? », « Essayer » — tombaient sur le bleu souligné du
 * navigateur, au milieu d'une page qui n'a pas une seule autre note de bleu.
 * Ils se voyaient, et c'est bien ce qu'on leur demande ; ils se voyaient comme
 * une pièce rapportée, ce qu'on ne leur demandait pas.
 *
 * Le soulignement reste, décalé sous la ligne de base : c'est ce qui distingue
 * un lien d'un mot en couleur, et le retirer coûterait à ceux qui distinguent
 * mal les couleurs. Les contrôles, eux, se déclarent juste en dessous et
 * gardent le leur.
 */
/* `a:not([class])` et non `a`.
 *
 * Écrite sur `a` nu, la règle de survol l'emportait sur celle des boutons :
 * `a:hover` pèse 0,1,1 quand `.btn-primary` pèse 0,1,0. Au survol, un bouton
 * primaire prenait donc le violet du lien pour couleur de texte — violet sur
 * violet, un rectangle vide. La couleur au repos, elle, passait inaperçue :
 * c'est le survol seul qui inversait la hiérarchie.
 *
 * Un contrôle porte toujours une classe, un lien de texte n'en porte jamais.
 * Le sélecteur dit exactement cela, et ne peut plus atteindre un bouton même
 * s'il pèse davantage. */
a:not([class]) {
  color: var(--color-primary);
  text-decoration-color: var(--color-line-strong);
  text-underline-offset: 3px;
}

a:not([class]):hover { color: var(--color-primary-hover); text-decoration-color: currentColor; }
a:not([class]):focus-visible { outline: 3px solid var(--color-primary); outline-offset: 2px; border-radius: var(--radius-sm); }

a[class*="btn"], a.chip, a.tile, a.tile-row, a.push, a.langdot, a.brand, a.class-card-band, a.class-head-back, a.icon-btn, .class-crumb a, a.ui-lang { text-decoration: none; }
a.chip { display: inline-flex; align-items: center; gap: var(--spacing-2); }
a.chip:hover { border-color: var(--color-primary); color: var(--color-primary); }
a.chip:focus-visible { outline: 3px solid var(--color-primary); outline-offset: 2px; }
a.chip .mod-icon { width: 22px; height: 22px; }

a.tile { color: inherit; }
a.tile:hover { border-color: var(--color-primary); }
a.tile:focus-visible { outline: 3px solid var(--color-primary); outline-offset: 2px; }

/* Un lien qui prend l'apparence d'un bouton ne garde pas son soulignement.
 * Oubli des maquettes, qui n'emploient que des <button>. */
a.btn:focus-visible { outline: 3px solid var(--color-primary); outline-offset: 3px; }

/* `.tile` est une carte carrée de grille : son `min-height: 156px` sert à
 * pousser le pied de tuile en bas. Employée en ligne pleine largeur — file de
 * relecture, état de la génération — elle laisse un vide de cent pixels.
 * `.tile-row` est la même carte, sans la hauteur plancher. */
.tile-row { min-height: 0; }
/* L'espace élève : une activité que le professeur vient d'ouvrir porte « Nouvelle », et un bandeau l'annonce. */
.act-new-badge { display: inline-block; margin-left: var(--spacing-2); padding: 0 var(--spacing-2); border-radius: var(--radius-full); background: var(--color-primary); color: var(--color-on-primary); font: 700 12px/20px var(--font-label), sans-serif; vertical-align: middle; }
.act-new-badge[hidden] { display: none; }
.act-new-banner { display: flex; flex-wrap: wrap; align-items: center; gap: var(--spacing-2) var(--spacing-3); padding: var(--spacing-3); border: 2px solid var(--color-primary); border-radius: var(--radius-md); background: var(--color-primary-soft); color: var(--color-ink); }
.act-new-banner[hidden] { display: none; }
.act-new-banner > span { flex: 1 1 200px; min-width: 0; overflow-wrap: anywhere; }
.act-new-banner .btn { min-height: 44px; min-width: 44px; }
.class-empty { display: grid; gap: var(--spacing-2); justify-items: start; padding: var(--spacing-5); }

/* ══ les classes archivées, repliées ══
 *
 * La section est un `<details>` : le navigateur ouvre et ferme, la recherche
 * dans la page déplie toute seule, et un professeur dont le JavaScript est
 * coupé voit ses archives comme les autres.
 *
 * Fermée, la ligne doit se lire comme un contrôle et non comme un titre de
 * section — d'où la bordure et le chevron. Les autres intertitres de l'écran
 * ne se cliquent pas ; celui-ci, si, et rien ne doit le laisser croire
 * décoratif.
 *
 * `.arch-when` porte l'échéance la plus proche. C'est ce qui rend le
 * repliement acceptable : voir `screen_classes()` pour le seuil. */
/* Le même écart que `.sec` au-dessus, et la même respiration en dessous : la
 * ligne remplace un intertitre de section, elle doit tenir sa place dans le
 * rythme de la page et non se coller à la carte qui la précède. */
.arch { margin-top: var(--spacing-8); }

.arch > summary {
	list-style: none;
	cursor: pointer;
	display: flex;
	align-items: center;
	gap: var(--spacing-2);
	padding: var(--spacing-3) var(--spacing-4);
	background: var(--color-surface-raised);
	border: 2px solid var(--color-line-strong);
	border-radius: var(--radius-lg);
}

/* Le marqueur de divulgation est retiré des deux façons qu'il faut : Safari et
 * les anciens WebKit n'écoutent que la pseudo-classe propriétaire. */
.arch > summary::-webkit-details-marker { display: none; }
.arch > summary::marker { content: ""; }
.arch > summary:hover { border-color: var(--color-ink-faint); }

.arch-chev {
	width: 18px; height: 18px; flex: none;
	fill: none; stroke: currentColor; stroke-width: 2.2;
	stroke-linecap: round; stroke-linejoin: round;
	color: var(--color-ink-muted);
	transition: transform .15s;
}
.arch[open] .arch-chev { transform: rotate(90deg); }

.arch-n {
	background: var(--color-surface-sunken);
	color: var(--color-ink-muted);
	border-radius: 99px;
	padding: 1px 9px;
	font-size: 13px;
	font-weight: 700;
}

/* L'échéance se pousse à droite tant qu'il y a la place, et passe à la ligne
 * sur un téléphone plutôt que d'écraser le nom de la section. */
.arch-when { margin-left: auto; font-size: 13.5px; color: var(--color-ink-muted); }
.arch-when.is-soon { color: var(--color-error-strong); font-weight: 700; }
.arch-body { padding-top: var(--spacing-3); }

@media (max-width: 34rem) {
	.arch > summary { flex-wrap: wrap; }
	.arch-when { margin-left: 0; flex-basis: 100%; }
}


/* Le pied d'une tuile de grille : collé en bas, quelle que soit la longueur
 * du titre au-dessus. C'est ce qui aligne les durées d'une rangée à l'autre. */
.tile-foot { margin-top: auto; padding-top: var(--spacing-2); }

.tile-cta { color: var(--color-primary); }

.proj-missing { gap: var(--spacing-2); text-align: center; }

/* ── Corrections de mise en page de la scène ───────────────────────────── */

/* Un tirage remplace le précédent : les autres doivent quitter le flux, pas
 * seulement s'estomper. Empilés et floutés, huit tirages occupaient l'écran
 * et noyaient celui qu'on projette. */
.proj-shell[data-vd-pattern="draw"] .proj-row[aria-hidden="true"] { display: none; }

/*
 * Un exercice à la fois, quand les lignes sont des exercices.
 *
 * Le schéma « dévoilement » sert deux choses différentes. « La palabra »
 * dévoile un mot en cinq temps, et garder les cinq à l'écran construit le
 * sens. « El acento » propose cinq mots sans rapport : les empiler remplit
 * l'écran, rapetisse chaque item et fait défiler la scène — alors qu'un seul
 * mot en grand est exactement ce qu'un vidéoprojecteur sait faire.
 *
 * La barre de progression continue de dire combien il en reste, ce qui remplace
 * avantageusement la pile : on voit qu'il y a une suite sans la lire d'avance.
 */
.proj-shell[data-vd-solo] .proj-row[data-row][aria-hidden="true"] { display: none; }

/* Sauf la première avant tout dévoilement : sans elle, la scène s'ouvrirait
 * vide et le professeur croirait la page en défaut. */
.proj-shell[data-vd-solo][data-vd-cursor="-1"] .proj-row[data-row]:first-child { display: flex; }

/* Une portion voilée est une étiquette au-dessus de sa réponse, pas une suite
 * de mots sur une ligne. Les fragments sont des <span>, donc en ligne par
 * nature : le conteneur les met en colonne, et `display: block` sur chacun les
 * sépare de toute façon si la colonne est mise en défaut. Sans quoi la
 * dernière syllabe se colle à la classification — « doLlana ». */
/*
 * On vise l'attribut, jamais la classe.
 *
 * Le dévoilement *retire* `proj-veiled` pour poser `revealed`. Toute règle
 * écrite pour `.proj-veiled` cessait donc de s'appliquer au moment précis où
 * le contenu devenait visible : la mise en colonne était juste tant qu'on ne
 * la voyait pas, et les fragments retombaient sur une ligne dès le premier
 * appui — « gatoga toLlanaSIN TILDE… ». J'ai corrigé trois fois le symptôme
 * avant de voir que la classe changeait sous la règle.
 *
 * `data-vd-veil`, lui, ne bouge pas. C'est ce qui en fait le bon point
 * d'accroche : il désigne ce qu'est l'élément, pas l'état dans lequel il se
 * trouve.
 */
[data-vd-veil], [data-vd-zone-body] {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: var(--spacing-2);
}

[data-vd-veil] > *, [data-vd-zone-body] > * { display: block; }

/* La question et sa réponse tiennent côte à côte tant qu'il y a la place, et
 * passent l'une sous l'autre sinon, plutôt que de déborder. */
.proj-row { flex-wrap: wrap; align-items: baseline; row-gap: var(--spacing-2); }

.proj-zone > [data-vd-zone-body] { width: 100%; }

/* Six formes verbales ne tiennent pas sur une ligne : elles débordaient de
 * l'écran par la droite, hors de vue et hors d'atteinte. */
.proj-group {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
	gap: var(--spacing-3) var(--spacing-5);
	width: 100%;
}

.proj-row-stack { flex-direction: column; align-items: flex-start; gap: var(--spacing-4); }

/* La roue : sans dimension, ses dix verbes se superposaient au centre. Le
 * rayon est une donnée géométrique, pas une valeur de charte — d'où la
 * variable locale plutôt qu'un jeton. */
/* ── La roue des verbes ──────────────────────────────────────────────────
 * Des secteurs, une aiguille fixe, du texte le long du rayon. Le texte radial
 * est ce qu'on lit sur toutes les roues de loterie : il reste lisible quelle
 * que soit la rotation, là où du texte horizontal posé sur un plateau tournant
 * finit penché — c'était le défaut de la version précédente.
 */

.wheel-wrap { aspect-ratio: 1; max-width: 22rem; }

.wheel { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }

.wheel-turn { transform-origin: 0 0; transition: transform 2.9s cubic-bezier(.12, .86, .16, 1); }

.wheel-slice > path {
	fill: var(--color-proj-line);
	stroke: var(--color-proj-surface);
	stroke-width: 1.5;
	transition: fill .3s ease;
}

/* Un secteur sur deux est plus sombre : sans cette alternance, seize parts de
 * la même couleur redeviennent un disque, et la roue cesse de se lire. */
.wheel-slice:nth-child(even) > path { fill: color-mix(in oklab, var(--color-proj-line) 62%, transparent); }
@supports not (color: color-mix(in srgb, red, blue)) { /* Un secteur sur deux est plus sombre : sans cette alternance, seize parts de
 * la même couleur redeviennent un disque, et la roue cesse de se lire. */
.wheel-slice:nth-child(even) > path { fill: rgba(125,106,136,0.62); } }

.wheel-slice > text {
	font-family: Fredoka;
	font-size: 11px;
	font-weight: 600;
	fill: var(--color-proj-ink);
	letter-spacing: .02em;
}

.wheel-slice.is-drawn > path { fill: var(--color-proj-accent); }

/*
 * Pendant que la roue tourne, le verbe n'est nulle part.
 *
 * Il s'écrivait en grand dans la colonne avant même le premier tour : la roue
 * tournait, et la classe avait déjà lu la réponse à côté. On le cache donc
 * pour la durée du tour — par la visibilité et non par l'affichage, pour que
 * rien ne saute quand il revient.
 *
 * Le moyeu et le secteur en jaune sont retirés par le script, qui les remet à
 * l'arrêt : ce sont des états, pas des styles.
 */
.proj-shell.is-spinning .proj-main .proj-answer-lead { visibility: hidden; }
.wheel-slice.is-drawn > text { fill: var(--color-proj-surface); font-weight: 700; }

.wheel-needle { fill: var(--color-proj-accent); }

.wheel-hub-disc { fill: var(--color-proj-surface); stroke: var(--color-proj-line); stroke-width: 3; }

.wheel-hub b {
	font-family: Fredoka;
	font-weight: 700;
	font-size: clamp(15px, 2.1vw, 21px);
	color: var(--color-proj-ink);
	text-align: center;
	line-height: 1.05;
	max-width: 8rem;
	overflow-wrap: anywhere;
}

/* ---------------------------------------------------------------------------
 * La hora — la carte du monde
 *
 * L'heure en chiffres reste lisible en permanence : c'est la question. Seule
 * la forme parlée se dévoile. Une bulle ouverte passe au-dessus des autres,
 * parce qu'elle grandit et que deux villes voisines se chevaucheraient.
 * ------------------------------------------------------------------------ */

/*
 * La carte se dimensionne sur la hauteur disponible, pas sur la largeur.
 *
 * Avec `width: 100%` et un plafond de hauteur, le plafond finissait par
 * tronquer la carte : la boîte gardait sa largeur, perdait de la hauteur, et
 * son rapport ne correspondait plus à celui du tracé. Les marqueurs, placés en
 * pourcentages de la boîte, s'en trouvaient décalés — Santiago sortait par le
 * bas.
 *
 * En partant de la hauteur, la largeur suit le rapport et le tracé reste
 * juste. Sur un écran étroit c'est l'inverse qui vaut, d'où la bascule plus
 * bas : là, c'est la largeur qui manque.
 */
/*
 * La carte est le conteneur de mesure de ses étiquettes.
 *
 * Elles étaient dimensionnées en pixels, et la carte se dimensionne à la
 * fenêtre : la même bulle occupait un dixième d'un planisphère projeté sur
 * trois mètres et un cinquième du même planisphère dans une fenêtre de bureau.
 * Le calcul qui les écarte, lui, raisonne en pourcentages de la carte — il ne
 * pouvait donc être juste qu'à une largeur d'écran, et il a été recalibré deux
 * fois sans jamais l'être partout.
 *
 * Déclarer la carte conteneur rend le rapport constant : tout ce qui est écrit
 * en `cqw` ci-dessous est une fraction de la largeur de la carte, à toutes les
 * tailles. La proportion écrite en PHP redevient vraie, et il n'y a plus de
 * largeur d'écran à supposer.
 */
.geo-map {
	position: relative;
	height: 100%;
	width: auto;
	aspect-ratio: var(--geo-ratio, 1000 / 395);
	margin-inline: auto;
	container-type: inline-size;
}

.geo-map-bg { position: absolute; inset: 0; width: 100%; height: 100%; }

/*
 * Les continents se lisent, ou la carte ne sert à rien.
 *
 * Le tracé était peint dans la couleur des filets, à 55 % d'opacité, sur un
 * fond violet sombre : deux valeurs à peine séparées, invisibles sur le
 * vidéoprojecteur d'une salle éclairée. Une carte qu'on ne distingue pas du
 * fond ne situe plus rien, et les bulles flottaient dans le noir.
 *
 * La terre se déduit donc de l'encre, pas du filet — elle doit se voir, comme
 * le texte — et le trait de côte monte encore d'un cran pour dessiner les
 * contours.
 */
.geo-land {
	fill: color-mix(in oklab, var(--color-proj-ink) 34%, var(--color-proj-surface));
	stroke: color-mix(in oklab, var(--color-proj-ink) 48%, var(--color-proj-surface));
	stroke-width: 1.5;
	stroke-linejoin: round;
}
@supports not (color: color-mix(in srgb, red, blue)) { /*
 * Les continents se lisent, ou la carte ne sert à rien.
 *
 * Le tracé était peint dans la couleur des filets, à 55 % d'opacité, sur un
 * fond violet sombre : deux valeurs à peine séparées, invisibles sur le
 * vidéoprojecteur d'une salle éclairée. Une carte qu'on ne distingue pas du
 * fond ne situe plus rien, et les bulles flottaient dans le noir.
 *
 * La terre se déduit donc de l'encre, pas du filet — elle doit se voir, comme
 * le texte — et le trait de côte monte encore d'un cran pour dessiner les
 * contours.
 */
.geo-land { fill: rgb(110,102,110); stroke: rgb(141,133,136); } }

/*
 * Toute la géométrie de la carte est calculée en PHP, en pourcentages, et
 * posée en attribut `style`. La feuille n'en connaît aucune valeur : la
 * hauteur de la carte découle d'un rapport d'aspect appliqué à une largeur
 * relative, et CSS ne sait pas la relire pour en prendre une fraction. Le
 * décalage des étiquettes qui se recouvrent doit pourtant se calculer dans les
 * mêmes unités que celles où on le dessine, sans quoi il écarte sur le papier
 * ce qui se chevauche à l'écran.
 *
 * L'étiquette est posée *au-dessus* du point, jamais centrée dessus : centrée,
 * elle recouvrait la pastille, qui venait se planter au milieu du nom de la
 * ville — « MA●RID ».
 */
.geo-pin { position: absolute; transform: translate(-50%, -100%); margin-top: -7px; }

/* Le trait de rappel et la pastille sont dans le SVG, donc derrière les
 * étiquettes et dans les unités de la carte. Sans le trait, une étiquette
 * déportée devient une heure flottante dont personne ne sait à quelle ville
 * elle appartient. */
/* Un filet net plutôt qu'une rayure : il relie deux objets, il n'ombre rien.
 * À moitié transparent et terminé au carré, il se lisait comme un accident du
 * fond de carte. */
.geo-leader { stroke: var(--color-proj-accent); stroke-width: 2.5; opacity: .72; stroke-linecap: round; }
.geo-dot { fill: var(--color-proj-accent); stroke: var(--color-proj-surface); stroke-width: 3; }

.geo-pin > .proj-zone {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 0;
	padding: var(--spacing-2) var(--spacing-3);
	min-height: 0;
	white-space: nowrap;
	border-radius: var(--radius-lg);
	/*
	 * Une bulle opaque, et bordée d'encre plutôt que de filet.
	 *
	 * Elle était translucide pour laisser voir la carte — ce qui allait tant
	 * que la carte était invisible. Maintenant qu'on la voit, un continent
	 * traversant « 12:15 » se lit comme un défaut d'affichage, et un cadre
	 * couleur filet disparaît par-dessus la terre.
	 */
	background: var(--color-proj-surface);
	border-width: max(2px, .15cqw);
	border-color: color-mix(in oklab, var(--color-proj-ink) 55%, var(--color-proj-surface));
	box-shadow: 0 3px 12px rgb(0 0 0 / .5);
	/*
	 * Le rembourrage entre dans la hauteur que PHP suppose : il se mesure donc
	 * dans la même unité que le reste.
	 *
	 * Il est large sur les côtés, et c'est la place de la pastille de rang.
	 * Rentrée dans la bulle pour ne plus déborder sur la voisine, elle se
	 * posait sur le premier chiffre : « 12:30 » se lisait « |2:30 ». Une marge
	 * latérale la loge sans rien déplacer — le contenu reste centré, et la
	 * hauteur, qui est ce qui compte pour l'écartement, ne bouge pas.
	 */
	padding: .55cqw 2cqw;
}
@supports not (color: color-mix(in srgb, red, blue)) { .geo-pin > .proj-zone { border-color: rgb(156,148,149); } }

/*
 * La réponse ne prend pas de place tant qu'elle n'est pas demandée.
 *
 * Une portion voilée reste dans le flux partout ailleurs, et c'est voulu : la
 * classe voit qu'il reste quelque chose à trouver. Sur une carte, ce bloc
 * flouté doublait la hauteur de chaque bulle, et huit bulles se recouvraient
 * au point de rendre la carte illisible. Elle est donc détachée du flux et
 * suspendue sous l'étiquette — toujours visible, toujours floutée, mais sans
 * pousser les autres villes.
 */
.geo-pin > .proj-zone > [data-vd-zone-body] {
	position: absolute;
	top: calc(100% + .6cqw);
	left: 50%;
	transform: translateX(-50%);
	align-items: center;
	width: max-content;
	max-width: 26cqw;
	padding: .6cqw 1.2cqw;
	background: var(--color-proj-surface);
	border: 2px solid color-mix(in oklab, var(--color-proj-ink) 55%, var(--color-proj-surface));
	border-radius: var(--radius-lg);
	box-shadow: 0 3px 12px rgb(0 0 0 / .5);
	white-space: normal;
	text-align: center;
}
@supports not (color: color-mix(in srgb, red, blue)) { /*
 * La réponse ne prend pas de place tant qu'elle n'est pas demandée.
 *
 * Une portion voilée reste dans le flux partout ailleurs, et c'est voulu : la
 * classe voit qu'il reste quelque chose à trouver. Sur une carte, ce bloc
 * flouté doublait la hauteur de chaque bulle, et huit bulles se recouvraient
 * au point de rendre la carte illisible. Elle est donc détachée du flux et
 * suspendue sous l'étiquette — toujours visible, toujours floutée, mais sans
 * pousser les autres villes.
 */
.geo-pin > .proj-zone > [data-vd-zone-body] { border: 2px solid rgb(156,148,149); } }

/*
 * La ligne de tête d'une étiquette : une heure pour « La hora », un ciel et un
 * degré pour « El tiempo ». Les deux se composent en ligne, centrées, parce
 * qu'un pictogramme posé au-dessus de son chiffre doublerait la hauteur de
 * l'étiquette — et la hauteur d'étiquette est ce qui décide combien de villes
 * tiennent sur la carte.
 */
.geo-lead {
	display: flex;
	align-items: center;
	justify-content: center;
	/* Entre la pastille de rang et le pictogramme : ils se touchaient, et le
	   chiffre paraissait faire partie du dessin du ciel. */
	gap: calc(.9cqw * var(--geo-scale, 1));
	font-family: Fredoka;
	/* Deux pour cent de la largeur de la carte. La bulle doit se lire du fond
	 * de la salle sans masquer le planisphère : au-delà, cinq étiquettes
	 * recouvrent l'Amérique et la carte ne situe plus rien. Les mesures que
	 * `World_Map` reprend — hauteur et largeur d'étiquette — suivent ce
	 * chiffre : les trois bougent ensemble. */
	font-size: calc(2.3cqw * var(--geo-scale, 1));
	font-weight: 700;
	line-height: 1;
	font-variant-numeric: tabular-nums;
	letter-spacing: .02em;
}

.geo-name {
	font-family: Fredoka;
	font-size: calc(1cqw * var(--geo-scale, 1));
	line-height: 1.25;
	font-weight: 500;
	letter-spacing: .06em;
	text-transform: uppercase;
	color: var(--color-proj-ink-muted);
}

.hora-said { font-size: calc(1.6cqw * var(--geo-scale, 1)); white-space: normal; line-height: 1.2; }

/* Le degré sur l'étiquette, et le pictogramme du ciel à côté de lui. */
.geo-degrees { font-family: Fredoka; font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums; }

.geo-lead .sky-glyph { display: flex; }

/*
 * Le pictogramme prend toute la ligne qu'il partage.
 *
 * Il était réduit à deux pour cent de la largeur de la carte quand le degré,
 * à côté de lui, en occupe deux virgule trois : il était donc plus petit que
 * le chiffre qu'il accompagne, alors que c'est lui qu'on lit en premier — « il
 * fait vingt-neuf » ne se demande qu'une fois qu'on a vu le nuage.
 *
 * Il monte à la hauteur du chiffre, et pas au-delà : la ligne du haut ne
 * grandit pas, la hauteur d'étiquette non plus, et c'est elle qui décide
 * combien de villes tiennent sur la carte. Quinze pour cent de plus, sans
 * rien coûter à personne — un vrai agrandissement demanderait de la place que
 * la carte n'a pas, et cela se discute ailleurs qu'ici.
 */
.geo-lead .sky-glyph svg {
	width: calc(2.3cqw * var(--geo-scale, 1));
	height: calc(2.3cqw * var(--geo-scale, 1));
}

/*
 * Une ville faite garde sa marque, la ville courante seule montre sa réponse.
 *
 * Les zones s'ouvrent en s'accumulant — la progression se compte à ce qui a
 * été trouvé. Mais huit cartons de réponse ouverts sur une mappemonde se
 * recouvraient au point qu'on ne savait plus lequel appartenait à quelle
 * ville. Les précédentes se contentent donc de leur heure en accent : la
 * classe a déjà dit la réponse à voix haute, et recliquer la redit.
 */
.geo-pin > .proj-zone[aria-expanded="true"] { border-color: var(--color-proj-accent); }
.geo-pin > .proj-zone[aria-expanded="true"] .geo-lead { color: var(--color-proj-accent); }

/*
 * Ailleurs, une réponse non trouvée reste affichée floutée : la classe voit
 * qu'il reste quelque chose à chercher, et c'est un principe du produit. Sur
 * une carte, huit cartons flous suspendus sous huit villes ne disent plus
 * rien — ils se recouvrent et masquent la carte. Ce qui reste à trouver se
 * lit ici sur la bulle : une ville dont l'heure est encore blanche n'a pas été
 * dite, une ville en accent l'a été.
 */
.geo-pin > .proj-zone:not(.is-current) > [data-vd-zone-body],
.geo-pin > .proj-zone[aria-expanded="false"] > [data-vd-zone-body] { display: none; }

.geo-pin:has( .is-current ) { z-index: 6; }

/*
 * La réponse d'une ville se mesure à la carte, comme l'étiquette.
 *
 * Ses lignes gardaient la taille des réponses ordinaires, calculée sur la
 * hauteur de l'écran : « poco nuboso » s'écrivait aussi gros qu'au centre
 * d'une scène vide, et le carton dépassait la carte d'un bon tiers. Mesurées
 * en fractions de la carte, elles restent en proportion d'elle à toutes les
 * tailles — plus grandes que l'étiquette, parce que c'est la réponse.
 *
 * Et en bas de la carte, le carton se déplie au-dessus de l'étiquette
 * (`is-low`, posé par `World_Map`) : dessous, il sortait du planisphère.
 */
@media (min-width: 64rem) {
	.geo-pin > .proj-zone > [data-vd-zone-body] .t-proj-a:not( .hora-said ) { font-size: 2.4cqw; line-height: 1.15; }
	.geo-pin > .proj-zone > [data-vd-zone-body] .proj-answer-lead { font-size: 3cqw; }
	.geo-pin > .proj-zone > [data-vd-zone-body] .t-eyebrow { font-size: 1.1cqw; }

	.geo-pin.is-low > .proj-zone > [data-vd-zone-body] {
		top: auto;
		bottom: calc(100% + .6cqw);
	}
}

/*
 * La date en chiffres de « La fecha ».
 *
 * Elle tient la place que la carte tient ailleurs : la colonne média, à
 * gauche, visible du début à la fin. C'est la question ; la phrase espagnole
 * est la réponse, et elle est à droite.
 */
.fecha-digits {
	margin: 0;
	font-family: Fredoka;
	font-weight: 700;
	font-variant-numeric: tabular-nums;
	/* La hauteur commande, mais la largeur a le dernier mot : « 22/09/2026 »
	 * fait dix signes, et sur un téléphone tenu debout il sortait de l'écran —
	 * l'ajustement automatique ne mesure que la hauteur. */
	font-size: calc(min(clamp(44px, 11vh, 112px), 12vw) * var(--proj-fit, 1));
	line-height: 1;
	letter-spacing: -.01em;
}

/* Les barres obliques séparent, elles ne se lisent pas : plus fines que les
 * chiffres, et en accent pour qu'on les voie sans les compter. */
.fecha-digits i {
	font-style: normal;
	font-weight: 500;
	color: var(--color-proj-accent);
	margin-inline: .04em;
}

/* L'année est la partie qu'on connaît déjà. */
.fecha-digits b { font-weight: 500; color: var(--color-proj-ink-muted); }

/*
 * L'étiquette de prix de « ¿Cuánto cuesta? ».
 *
 * Elle est la question : la classe la lit et doit la dire. Elle s'écrit donc
 * comme l'heure de « La hora » — gros, en chiffres tabulaires, à l'accent —
 * et non comme une réponse.
 */
.price-tag {
	display: block;
	font-family: Fredoka;
	font-weight: 700;
	font-variant-numeric: tabular-nums;
	font-size: calc(clamp(40px, 9vh, 104px) * var(--proj-fit, 1));
	line-height: 1;
	letter-spacing: -.01em;
	color: var(--color-proj-accent);
}

/* Le dessin de l'objet, au-dessus de son nom : la classe le voit avant de
 * le dire, comme pour les couleurs. */
.cc-pic { display: block; width: calc(clamp(80px, 24vh, 240px) * var(--proj-fit, 1)); height: auto;
	max-width: 100%; margin: 0 0 var(--spacing-3); }
.cc-obj { display: flex; align-items: center; gap: var(--spacing-6); }
.cc-obj .cc-pic { margin: 0; flex: none; }
.cc-what { min-width: 0; display: flex; flex-direction: column; gap: var(--spacing-2); }

.hora-clock-note { display: block; }
.hora-clock { margin-top: var(--spacing-2); }

/* Un bouton discret logé dans un en-tête de section. Posé entre le titre et la
 * grille, « Recommencer » se lisait comme la première tuile de cette grille. */
.btn-sm { font-size: 14px; min-height: 38px; padding: var(--spacing-2) var(--spacing-4); }
.sec-action { flex: 0 0 auto; }

/* Un module muet sans explication passe pour un module cassé — et se ferait
 * signaler à tort. L'avertissement reste discret : il s'adresse au professeur,
 * pas à la classe. */
.proj-novoice { color: var(--color-proj-ink-muted); max-width: 24rem; text-transform: none; letter-spacing: 0; }

/* ── Banque de mots ──────────────────────────────────────────────────────
 * Affichée en permanence, jamais cachée : dans ces modules, l'exercice est
 * d'associer une situation à la bonne formule, pas de deviner un mot qu'on
 * n'a pas. Sans elle, un débutant n'a rien à quoi se raccrocher et le
 * professeur finit par souffler la réponse. */
.word-bank { margin-top: var(--spacing-3); }
.bank-chips { display: flex; flex-wrap: wrap; gap: var(--spacing-2); margin-top: var(--spacing-2); }
.bank-chip {
	padding: var(--spacing-1) var(--spacing-3);
	border: 2px solid var(--color-proj-line);
	border-radius: var(--radius-full);
	font-family: Fredoka;
	font-size: 15px;
	color: var(--color-proj-ink-muted);
	white-space: nowrap;
	/*
	 * Une tournure plus longue que le panneau passe à la ligne plutôt que
	 * d'être coupée. « La temperatura máxima es de … grados » dépassait les
	 * dix-sept rem du panneau des scènes à carte, et se lisait « … gra ».
	 * Le `nowrap` reste la règle : il garde les formules courtes d'un seul
	 * tenant, et ne cède que lorsqu'il n'y a plus la place.
	 */
	max-width: 100%;
}

.proj-panel .bank-chip { white-space: normal; }

/* L'arc de progression se remplit d'un geste, pas d'un saut : le rituel se
 * termine sur cette rotation, c'est le seul moment où l'anneau est regardé. */
.ring-arc { transition: stroke-dashoffset .5s cubic-bezier(.22, .61, .36, 1); }

/* ── Les émotions ────────────────────────────────────────────────────────
 * Le visage est la question, et il se lit du fond de la classe : à la taille
 * d'un emoji ordinaire il n'était qu'une décoration en haut à gauche d'une
 * grande case vide. Les cases sont donc étroites et hautes, centrées sur lui. */
/*
 * Les visages tiennent sur une ligne, et les mots dans leur cadre.
 *
 * Deux fautes se cumulaient. La réponse était composée à la taille d'une
 * réponse de projection — jusqu'à quarante pixels — dans une case de neuf rem :
 * « Estoy orgulloso » débordait par les deux côtés et venait se poser sur la
 * case voisine. Et la case, faute de `min-width: 0`, refusait de se réduire :
 * une grille ne rétrécit pas ses colonnes en dessous de leur contenu tant
 * qu'on ne l'y autorise pas.
 *
 * La taille suit maintenant la largeur de la case plutôt que celle de l'écran,
 * et les mots longs se coupent au besoin. Un mot coupé se lit ; un mot posé
 * sur le voisin, non.
 */
/* La grille prend la largeur de sa ligne.
 *
 * Enfant d'une boîte flexible, elle ne recevait que sa largeur minimale et
 * repliait tout en une colonne. `flex: 1` le dit une fois pour toutes — c'est
 * la règle qu'on oublie chaque fois qu'une grille entre dans un flex. */
.proj-row > .proj-zones { flex: 1 1 auto; width: 100%; min-width: 0; }

.emo-zones { grid-template-columns: 1fr; }

/* Le mot est ce que la classe prononce : il se lit d'aussi loin que le visage
 * qu'il nomme. Il sortait à la taille d'une réponse ordinaire sous un émoji de
 * trois cents pixels. */
.emo-zones .proj-answer { font-size: calc(clamp(28px, 7vh, 88px) * var(--proj-fit, 1)); }

.emo-zones > .proj-zone {
	align-items: center;
	justify-content: center;
	text-align: center;
	gap: var(--spacing-3);
	min-width: 0;
	padding: var(--spacing-5) var(--spacing-4);
	/* La carte prend la hauteur de sa ligne : sans quoi elle reste un bandeau
	 * au milieu du vide, et le visage n'a pas où grandir. */
	min-height: 100%;
}

body.projection .proj-row:has(.emo-zones),
body.projection .proj-row:has(.col-zones) { flex: 1 1 auto; min-height: 0; align-items: stretch; }
body.projection .proj-row > .emo-zones,
body.projection .proj-row > .col-zones { align-content: stretch; }

/* Le visage se mesure en hauteur, comme tout ce qui se projette. Calibré en
 * largeur, il plafonnait à 60 px — un émoji de la taille d'un titre, dans un
 * module dont le sujet *est* le visage. */
/*
 * Il se mesure aussi en largeur, faute de quoi il sort de sa carte.
 *
 * La hauteur seule suffisait tant qu'on projetait : un écran de classe est
 * large et bas, et trente-quatre pour cent de sa hauteur tiennent dans
 * n'importe quelle carte. Sur un téléphone tenu debout, la même fraction fait
 * six cents pixels dans une carte qui en fait trois cent soixante-dix — le
 * visage débordait par le haut et par la droite, et la réponse se lisait
 * derrière lui.
 *
 * Le plafond en `vw` ne change rien à la projection, où c'est toujours la
 * hauteur qui contraint. Il ne se réveille qu'en portrait.
 */
.emo-face { font-size: calc(min(34vh, 30vw, 340px) * var(--proj-fit, 1)); line-height: 1; }

.emo-zones [data-vd-zone-body] { align-items: center; width: 100%; min-width: 0; }

.emo-zones .proj-answer,
.emo-zones .proj-answer-lead {
	font-size: clamp(14px, 1.5vw, 20px);
	line-height: 1.2;
	max-width: 100%;
	overflow-wrap: anywhere;
}

/* Quatre niveaux de même rang forment une grille, jamais une ligne qui se
 * replie : repliée, elle les distribuait au hasard de la largeur restante —
 * deux, puis un, puis un — et donnait à lire une hiérarchie qui n'existe pas.
 *
 * Quatre colonnes toujours, et `minmax(0, 1fr)` pour qu'elles se resserrent
 * plutôt que de déborder : les libellés font deux caractères, ils tiennent
 * partout. Une requête de conteneur aurait été plus fine, mais elle aurait
 * dépendu d'un conteneur que rien ne déclare — donc ne se serait jamais
 * appliquée, en silence. */
.level-picker { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--spacing-2); }
.level-picker > .btn { justify-content: center; padding-inline: var(--spacing-2); }

/* Une classe plutôt qu'un attribut `style` : un balisage produit par PHP ne
 * s'ajuste pas écran par écran. */
.gap-2 { gap: var(--spacing-2); }

/* Le cran manquant, employé à trois endroits depuis longtemps : la navigation
   d'un module isolé, l'en-tête de la vérification du poste, et les actions de
   réparation. Les trois collaient faute d'une règle de six lignes. */
.gap-3 { gap: var(--spacing-3); }

/* Une liste qui porte déjà sa marque — ✓, •, un chiffre — ne doit pas recevoir
   en plus la puce du navigateur. Sans cela chaque ligne s'ouvre sur « • ✓ »,
   et le signe qu'on a choisi se perd derrière celui qu'on n'a pas voulu. */
.list-marque { list-style: none; padding-left: 0; }

/* Les écrans de formulaire — connexion, inscription, rejoindre une classe — se
 * bornent en largeur. Une ligne de saisie qui traverse un écran de vingt-sept
 * pouces se lit mal, et un champ vide de cette largeur n'annonce pas ce qu'on
 * attend de lui. */
/* Centré, comme la colonne qui le contient.
 *
 * Il était bridé à 32 rem sans être recentré : sur un écran large, le
 * conteneur se centrait à mille pixels et le formulaire restait collé à son
 * bord gauche, à quatre cents pixels du milieu de l'écran. Une page de
 * connexion qui n'a que ce formulaire à montrer doit le mettre au centre — il
 * n'y a rien d'autre à regarder. */
.form-narrow { max-width: 32rem; margin-inline: auto; }

/* ═══ Le code d'accès, une case par caractère ═════════════════════════════
 *
 * Six cases plutôt qu'un champ. Le champ marchait — le tiret s'y écrivait
 * tout seul —, mais rien n'y disait combien de signes étaient attendus :
 * l'élève qui en avait tapé cinq ne l'apprenait qu'en appuyant sur « Entrer ».
 * Les cases le disent sans un mot, et la faute de frappe se corrige là où
 * elle est.
 *
 * Elles se partagent la largeur à parts égales et ne descendent jamais sous
 * la cible tactile : sur un téléphone de trois cent quatre-vingts pixels,
 * six cases et un tiret tiennent à quarante-six pixels chacune.
 */
.code-cells { display: flex; align-items: center; gap: 6px; }

.code-cell {
	flex: 1 1 0;
	min-width: 0;
	min-height: 60px;
	padding: 0;
	background: var(--color-surface-raised);
	color: var(--color-ink);
	border: 1.5px solid var(--color-line-strong);
	border-radius: var(--radius-md);
	font-size: 24px;
	text-align: center;
	text-transform: uppercase;
}

.code-cell:focus-visible {
	outline: 3px solid var(--color-primary);
	outline-offset: 1px;
	border-color: var(--color-primary);
}

/* La case remplie se marque : on voit d'un coup d'œil où l'on en est. */
.code-cell.is-full { border-color: var(--color-primary); }

/* Le tiret du coupon, dessiné et non saisi. */
.code-dash {
	flex: 0 0 auto;
	font-family: "Space Mono", monospace;
	font-weight: 700;
	color: var(--color-ink-faint);
}

/* ═══ Qui est connecté, et par où l'on sort ═══════════════════════════════
 *
 * Le bloc est à droite du bandeau : c'est là qu'on cherche son compte sur à
 * peu près tous les sites, et le professeur n'a pas à apprendre une
 * convention de plus. Le sélecteur de langue qui le poussait là a disparu ;
 * `margin-left: auto` le fait désormais seul.
 *
 * Le bouton reste discret :
 * se déconnecter n'est pas l'action de la page, et un bouton plein l'aurait
 * mise au même rang que « Projeter ». Il faut donc défaire ce que le
 * navigateur met d'office sur un <button>. */
.chrome-out { display: inline-flex; align-items: center; gap: var(--spacing-1);
  margin-left: auto; }

/* La sortie est un pictogramme : une porte et une flèche qui en part. Trente-
 * six pixels, ce qui reste touchable au pouce sans peser dans un bandeau. */
button.chrome-quit {
	display: grid;
	place-items: center;
	width: 36px;
	height: 36px;
	padding: 0;
	border: 0;
	border-radius: var(--radius-md);
	background: none;
	color: var(--color-ink-muted);
	cursor: pointer;
}

button.chrome-quit svg {
	width: 20px;
	height: 20px;
	fill: none;
	stroke: currentColor;
	stroke-width: 2;
	stroke-linecap: round;
	stroke-linejoin: round;
}

button.chrome-quit:hover { background: var(--color-surface-sunken); color: var(--color-primary); }
button.chrome-quit:focus-visible { outline: 3px solid var(--color-primary); outline-offset: 2px; }

/* L'aide : même pictogramme discret que la sortie, juste après elle. */
a.chrome-help { display: grid; place-items: center; width: 36px; height: 36px; margin-left: var(--spacing-1);
  border-radius: var(--radius-md); color: var(--color-ink-muted); text-decoration: none; }
a.chrome-help svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
a.chrome-help:hover { background: var(--color-surface-sunken); color: var(--color-primary); }
a.chrome-help:focus-visible { outline: 3px solid var(--color-primary); outline-offset: 2px; }
.chrome-in > .brand + a.chrome-help { margin-left: auto; }
/* L'aide pousse le groupe à droite ; ce qui la suit (langues, sortie) s'y
 * colle. Deux marges automatiques se partageaient l'espace libre, et l'aide
 * flottait au milieu du bandeau, loin de la sortie. */
.chrome-in > a.chrome-help ~ .chrome-out,
.chrome-in > a.chrome-help ~ .ui-langs { margin-left: 0; }

/* ═══ Le bandeau du professeur : onglets, libellés, menu du compte ═══════
 *
 * Les onglets n'avaient pas de couleur à eux : sans classe, leurs liens
 * recevaient celle de `a:not([class])`, le violet de l'action — la même que
 * celle d'un lien de paragraphe, et plus vive que l'onglet où l'on se trouve.
 * Le brun discret des onglets au repos, le brun foncé et un trait corail
 * (le « Dial » du logo) sous l'onglet courant : la marque dit où l'on est,
 * le violet reste aux actions. Le sélecteur monte d'un cran pour passer
 * devant la règle des liens, qui vient plus loin dans la feuille.
 */
@media (min-width: 40.0625rem) {
	/* Pas d'arrondi en haut : il dessinait un onglet de classeur dont le fond rejoignait la page, et
	 * l'onglet courant n'a plus de fond. Au survol, un aplat carré, posé sur le filet du bandeau. */
	.chrome .tabs a { position: relative; color: var(--color-ink-muted); background: none; padding-bottom: 12px; border-radius: 0; }
	.chrome .tabs { gap: var(--spacing-1); }
	/* Le texte du premier onglet s'aligne sur le bord gauche du logo : le rembourrage de
	 * l'onglet (16 px) plus le blanc du dessin faisaient flotter « Classes » à 11 px à droite. */
	.chrome .tabs a:first-child { margin-left: -11px; }
	.chrome .tabs a:hover { background: var(--color-surface-sunken); color: var(--color-ink); }
	.chrome .tabs a[aria-current="page"] { color: var(--color-ink); background: none; }
	.chrome .tabs a[aria-current="page"]::after {
		content: ""; position: absolute; left: 16px; right: 16px; bottom: -2px; height: 4px;
		border-radius: 4px 4px 0 0; background: var(--color-brand-corner);
	}
	.chrome .tabs a:focus-visible { outline: 3px solid var(--color-primary); outline-offset: -3px; }
}

/* Sur un grand écran, le bandeau du professeur tient sur une seule ligne : le logo, les
 * onglets, puis l'idée, l'aide et le compte. Deux lignes dont la seconde ne portait que
 * trois mots laissaient un tiers de la hauteur vide. `.chrome-in` devient transparent
 * (`display: contents`) pour que ses enfants rejoignent la ligne des onglets ; la largeur
 * de page passe alors dans le rembourrage du bandeau. Le trait corail descend jusqu'au
 * filet parce que les onglets occupent toute la hauteur. Élève et visiteur gardent leurs
 * deux lignes. */
@media (min-width: 64rem) {
	.chrome:has( > .tabs-app ) {
		display: flex; align-items: center; gap: var(--spacing-6); min-height: 68px;
		padding-inline: max( var(--spacing-4), calc( ( 100% - var(--page-w) ) / 2 + var(--spacing-4) ) );
	}
	.chrome:has( > .tabs-app ) .chrome-in { display: contents; }
	.chrome:has( > .tabs-app ) .chrome-in > :not( .brand ) { order: 2; }
	.chrome:has( > .tabs-app ) .tabs { order: 1; margin: 0; padding: 0; max-width: none; align-self: stretch; flex-wrap: nowrap; }
	.chrome:has( > .tabs-app ) .tabs a { display: flex; align-items: center; padding-bottom: 0; }
	.chrome:has( > .tabs-app ) .tabs a:first-child { margin-left: 0; }
}

/* Une ampoule seule ne dit rien : sur un écran large, le mot accompagne le dessin. */
.chrome-lbl { display: none; }
@media (min-width: 40.0625rem) {
	a.chrome-help.chrome-help-t { width: auto; display: inline-flex; align-items: center; gap: 6px; padding: 0 10px; font: 600 14px Fredoka, sans-serif; }
	.chrome-help-t .chrome-lbl { display: inline; }
}
/* Sur un téléphone, l'idée et l'aide quittent le bandeau pour le menu du compte. */
.acct-item.menu-mobile { display: none; }
@media (max-width: 40rem) {
	a.chrome-help.chrome-help-t { display: none; }
	.acct-item.menu-mobile { display: flex; }
	.chrome-in:has( .acct ) { justify-content: space-between; }
}

/* Le menu du compte : la même famille que celui de la page Start (contour
 * épais, ombre pleine violette, vignettes teintées). */
.chrome-in > a.chrome-help.chrome-idee { margin-left: auto; }
.acct { --acc: var(--color-primary); position: relative; margin-left: var(--spacing-1); }
.acct-btn { list-style: none; display: grid; place-items: center; width: 42px; height: 42px; border-radius: 50%; cursor: pointer;
	background: var(--color-primary-soft); border: 2.5px solid var(--color-ink); color: var(--color-ink);
	font: 700 18px Fredoka, sans-serif; letter-spacing: .02em; }
.acct-btn::-webkit-details-marker { display: none; }
.acct[open] .acct-btn { box-shadow: 0 3px 0 var(--acc); }
.acct-btn:focus-visible { outline: 3px solid var(--color-primary); outline-offset: 3px; }
.acct-menu { position: absolute; right: 0; top: calc(100% + 10px); z-index: 60; width: min(20.5rem, calc(100vw - 24px)); padding: 8px;
	background: var(--color-surface-raised); border: 2.5px solid var(--color-ink); border-radius: 20px;
	box-shadow: 0 6px 0 var(--acc); color: var(--color-ink); }
.acct-head { display: flex; align-items: center; gap: 12px; min-width: 0; padding: 8px 8px 12px; margin-bottom: 6px; border-bottom: 2px solid var(--color-line); }
.acct-av { flex: none; display: grid; place-items: center; width: 44px; height: 44px; border-radius: 50%;
	border: 2.5px solid var(--color-ink); background: var(--color-primary-soft); font: 700 18px Fredoka, sans-serif; }
.acct-mail { margin: 0; min-width: 0; font-weight: 800; font-size: 14.5px; line-height: 1.25; overflow-wrap: anywhere; }
.acct-item { display: flex; align-items: center; gap: 12px; min-height: 56px; padding: 6px 8px; border-radius: 14px; color: var(--color-ink); text-decoration: none; }
.acct-item:hover { background: var(--color-surface-sunken); }
.acct-item:focus-visible { outline: 3px solid var(--color-primary); outline-offset: -3px; }
.acct-item[aria-current="page"] { background: var(--color-primary-soft); }
.acct-ico { flex: none; display: grid; place-items: center; width: 40px; height: 40px; border-radius: 12px; background: var(--t, var(--color-surface-sunken)); }
.acct-ico svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.acct-tx { display: flex; flex-direction: column; min-width: 0; line-height: 1.25; }
.acct-tx b { font: 600 16px Fredoka, sans-serif; }
.acct-tx span { font-size: 13.5px; color: var(--color-ink-muted); }
.acct-ext { flex: none; margin-left: auto; width: 16px; height: 16px; fill: none; stroke: var(--color-ink-muted); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.acct-foot { margin: 6px 0 0; padding: 10px 6px 4px; border-top: 2px solid var(--color-line); }
.acct-out { display: flex; align-items: center; justify-content: center; gap: 8px; width: 100%; min-height: 48px; cursor: pointer;
	border: 2.5px solid var(--color-ink); border-radius: 99px; background: var(--color-surface-raised); color: var(--color-ink); font: 600 15px Fredoka, sans-serif; }
.acct-out svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.acct-out:hover { background: var(--color-surface-sunken); }
.acct-out:focus-visible { outline: 3px solid var(--color-primary); outline-offset: 2px; }
.acct-all { display: flex; align-items: center; justify-content: center; gap: 6px; width: 100%; min-height: 44px; margin-top: 6px; cursor: pointer;
	border: 0; background: none; color: var(--color-primary); font: 600 14px Nunito, system-ui, sans-serif; text-decoration: underline; text-underline-offset: 3px; }
.acct-all svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linejoin: round; }
.acct-all:focus-visible { outline: 3px solid var(--color-primary); outline-offset: 2px; border-radius: 8px; }
.acct-note { margin: 0; text-align: center; font-size: 13.5px; color: var(--color-ink-muted); }

/* ═══ La scène, sur un écran qui n'est pas un vidéoprojecteur ═══════════
 *
 * La projection est conçue pour un tableau : de très grands caractères, une
 * marge généreuse, cinq commandes alignées en pied. Rien de tout cela ne tient
 * sur la tablette avec laquelle un professeur prépare sa séance dans le train,
 * ni sur le portable qu'il sort en salle des profs — et ce sont pourtant les
 * deux moments où il regarde le rituel du lendemain.
 *
 * Deux seuils, pour deux gênes différentes. En largeur, ce qui déborde ; en
 * hauteur, ce qui chasse les commandes hors de l'écran.
 */

/*
 * Sous ce seuil, la carte cède la place à une liste.
 *
 * Strictement sous 1024 pixels. Le seuil valait 1024 compris, et tombait
 * exactement sur la définition la plus courante des vidéoprojecteurs de
 * salle de classe — 1024 × 768 : la carte disparaissait devant les élèves, là
 * précisément où elle sert. Or une image projetée se lit à sa taille sur le
 * mur, pas à son nombre de pixels ; ce qui est visé ici, c'est le téléphone
 * tenu à la main.
 *
 * Une bulle proportionnelle à la carte suit la carte partout — y compris là
 * où la carte devient minuscule. Sur un téléphone tenu debout, le planisphère
 * fait trois cents pixels de haut, et une heure dimensionnée à deux virgule
 * six pour cent de sa largeur s'écrirait à dix pixels : la géométrie serait
 * juste et le contenu illisible.
 *
 * Les villes s'empilent donc, et retrouvent des tailles en pixels — c'est une
 * liste, plus une carte, et une liste se mesure au texte qu'elle porte.
 *
 * Les villes s'empilent donc, dans l'ordre où elles se cliquent — le rang
 * qu'elles portent devient l'ordre de lecture, ce qu'il était déjà. On perd la
 * situation géographique, qui est un appui et non le contenu ; on garde ce qui
 * se dit. Le tracé disparaît plutôt que de servir de fond décoratif à une
 * liste.
 */
@media (max-width: 63.9375rem) {
	.geo-map {
		display: grid;
		gap: var(--spacing-3);
		width: 100%;
		height: auto;
		aspect-ratio: auto;
		max-height: none;
	}

	.geo-map-bg { display: none; }

	.geo-pin { position: static; transform: none; margin-top: 0; }

	.geo-pin > .proj-zone {
		width: 100%;
		flex-direction: row;
		align-items: center;
		justify-content: flex-start;
		gap: var(--spacing-4);
		white-space: normal;
	}

	/* Dépliée, la carte de ville n'a plus de raison de suspendre sa réponse
	 * sous elle : la place manque en largeur, pas en hauteur. */
	.geo-pin > .proj-zone > [data-vd-zone-body] {
		position: static;
		transform: none;
		width: auto;
		max-width: none;
		margin-left: auto;
		text-align: right;
	}

	.geo-rank {
		position: static;
		flex: none;
		width: 22px;
		height: 22px;
		font-size: 13px;
	}

	/*
	 * Les tailles reprennent le pixel.
	 *
	 * Elles sont écrites ici plutôt que sous quarante-huit rem, où elles se
	 * trouvaient : entre les deux seuils, la carte était déjà dépliée en liste
	 * et le texte encore mesuré sur elle — c'est-à-dire sur une largeur qui ne
	 * voulait plus rien dire.
	 */
	.geo-lead { font-size: clamp(20px, 3.4vw, 30px); gap: var(--spacing-2); }
	.geo-name { font-size: 11px; line-height: 1.3; }
	.hora-said { font-size: clamp(16px, 2.6vw, 22px); }
	.geo-lead .sky-glyph svg { width: 28px; height: 28px; }

	.geo-pin > .proj-zone { padding: var(--spacing-3) var(--spacing-4); border-width: 2px; }
}

@media (max-width: 48rem) {
	body.projection .proj-shell { padding: var(--spacing-4); }

	/* Le corps passe en colonne : côte à côte, la scène et son panneau
	 * d'aide se partageaient une largeur qu'aucun des deux n'avait. */
	body.projection .proj-body { flex-direction: column; align-items: stretch; gap: var(--spacing-5); }
	body.projection .proj-main { flex: 1 1 auto; min-width: 0; gap: var(--spacing-4); }

	/*
	 * Les tailles du téléphone ne se réduisent pas, et c'est voulu.
	 *
	 * `fit()` rapetisse tout ensemble quand la scène déborde : c'est ce qu'il
	 * faut devant un vidéoprojecteur, où l'on ne fait pas défiler et où ce qui
	 * dépasse n'est jamais lu. Un téléphone se fait défiler du pouce. Mieux
	 * vaut donc une scène qui se déroule à taille lisible qu'une scène entière
	 * mais rapetissée : ces tailles-là échappent au facteur, exprès.
	 */
	.t-proj-q { font-size: clamp(24px, 7.5vw, 38px); }
	.t-proj-a { font-size: clamp(19px, 5.5vw, 28px); }
	.proj-answer-lead { font-size: clamp(22px, 7vw, 34px); }

	/* Une seule colonne de zones : à deux, les villes et les visages
	 * n'avaient plus la place d'être lus de loin. */
	.proj-zones { grid-template-columns: 1fr; gap: var(--spacing-3); }
	.emo-zones { grid-template-columns: 1fr; }
	.proj-group { grid-template-columns: repeat(auto-fit, minmax(7rem, 1fr)); }

	/* Plus étroit encore : l'heure se resserre, le nom reste lisible. */
	.geo-lead { font-size: clamp(15px, 4.6vw, 22px); }
	.geo-name { font-size: 10px; }

	.wheel-wrap { max-width: 15rem; }

	/*
	 * Le pied s'enroule, et les boutons se partagent la largeur.
	 *
	 * Il défilait horizontalement, pour éviter qu'empilé sur quatre lignes il
	 * ne mange la moitié de l'écran. La crainte était juste, la réponse non :
	 * un défilement horizontal ne s'annonce pas sur un téléphone — pas de
	 * barre, pas d'ombre, rien. Le troisième bouton était coupé net au bord
	 * de l'écran, et « Revenir au sommaire » n'existait plus pour qui ne
	 * devinait pas le geste.
	 *
	 * En se partageant la largeur, trois boutons tiennent sur deux lignes et
	 * non sur quatre : c'est le compromis que l'enroulement seul ne donnait
	 * pas, parce qu'un bouton à sa largeur naturelle prend toute la ligne.
	 */
	body.projection .proj-foot {
		flex-wrap: wrap;
		gap: var(--spacing-2);
		overflow: visible;
	}

	body.projection .proj-foot > * {
		flex: 1 1 auto;
		min-width: 0;
		justify-content: center;
		text-align: center;
	}

	/*
	 * Toutes les tailles se mesurent en largeur, et aucune en hauteur.
	 *
	 * La scène est calibrée en `vh` parce qu'un vidéoprojecteur est contraint
	 * par sa hauteur. Un téléphone tenu debout, lui, est étroit et long : la
	 * même règle y donne des caractères énormes sur une colonne de quatre
	 * cents pixels, et une réponse de trois mots occupe l'écran entier.
	 *
	 * Le facteur de réduction ne rattrape rien ici : il ne se déclenche que
	 * lorsque la scène déborde de sa coquille, et sur un téléphone la
	 * coquille s'allonge au lieu de déborder. C'est donc à la feuille de
	 * style de poser des plafonds, exprimés en `vw`.
	 */
	.t-proj-q { font-size: clamp(20px, 6vw, 30px); }
	.t-proj-a { font-size: clamp(16px, 4.6vw, 24px); }
	.proj-answer-lead { font-size: clamp(19px, 5.6vw, 28px); }
	.proj-answer-display { font-size: clamp(38px, 13vw, 76px); }
	.proj-answer:has(> .syll) { font-size: clamp(24px, 8vw, 46px); }

	body.projection .proj-row .t-eyebrow { font-size: clamp(12px, 3.2vw, 16px); }
	body.projection .proj-count { font-size: clamp(14px, 3.6vw, 20px); }

	body.projection .proj-shell[data-vd-module="numero"] .proj-answer-display { font-size: clamp(40px, 15vw, 86px); }
	body.projection .proj-shell[data-vd-module="numero"] [data-vd-veil] .t-proj-a { font-size: clamp(16px, 4.6vw, 24px); }
	body.projection .proj-shell:is([data-vd-module="numero"], [data-vd-module="efemerides"]) [data-vd-veil] .t-eyebrow { font-size: clamp(12px, 3.2vw, 16px); }

	.emo-zones .proj-answer { font-size: clamp(20px, 5.6vw, 28px); }
	.emo-face { font-size: clamp(56px, 22vw, 120px); }

	/* Les trois derniers plafonds : le groupe de propositions, les degrés du
	 * bulletin, l'étiquette de prix. Ils étaient les seuls à rester en
	 * hauteur, et ce sont justement de gros caractères. */
	.proj-row:has(.proj-group) .proj-answer-display { font-size: clamp(26px, 8vw, 46px); }
	.sky-degrees { font-size: clamp(30px, 10vw, 56px); }
	.price-tag { font-size: clamp(30px, 10vw, 56px); }
	.cc-pic { width: clamp(64px, 24vw, 120px); }
	.cc-obj { gap: var(--spacing-4); }

	.proj-btn { padding: var(--spacing-3) var(--spacing-4); font-size: 15px; }

	/* Les raccourcis clavier ne servent à rien sans clavier, et prennent la
	 * place du libellé qu'ils accompagnent. */
	.kbd { display: none; }

	/* Ancré à la fenêtre, le menu de signalement doit rester dans le cadre. */
	.proj-report-menu {
		right: var(--spacing-4);
		left: var(--spacing-4);
		bottom: calc(var(--spacing-4) + 4rem);
		min-width: 0;
	}
}

/* Un écran bas — une tablette couchée, une fenêtre réduite — n'a pas de place
 * pour les très grands caractères, et c'est le pied de scène qui en pâtit le
 * premier puisqu'il est le dernier servi. */
@media (max-height: 34rem) {
	body.projection .proj-shell { padding: var(--spacing-3) var(--spacing-5); }
	body.projection .proj-body { gap: var(--spacing-4); }
	.t-proj-q { font-size: clamp(22px, 4.5vh, 34px); }
	/* Le plafond ne vaut que pour la carte dessinée : empilée, la liste des
	 * villes est le contenu, et la rogner cacherait la dernière. */
	@media (min-width: 64rem) {
		.geo-map { max-height: 46vh; width: 100%; height: auto; }
	}

	.proj-btn { padding: var(--spacing-2) var(--spacing-4); min-height: 0; }
}

/* ═══ Le lancement de la roue ══════════════════════════════════════════════
 *
 * La roue partait à l'arrivée sur le module. Le temps que la classe lève les
 * yeux du cahier, elle avait tourné et le verbe était tombé : le seul moment
 * de suspens du rituel passait pendant que personne ne regardait.
 *
 * Tant qu'on n'a pas lancé, elle attend sous un voile. Le flou n'est pas un
 * ornement — c'est lui qui fait le suspens. Une roue nette d'avance n'en a
 * aucun, puisqu'on a eu le temps de lire ses seize cases avant qu'elle parte.
 */
body.projection .proj-shell[data-vd-gate] .proj-media .proj-frame {
	filter: blur(9px) saturate(.55);
	opacity: .55;
	transition: filter .5s ease, opacity .5s ease;
}

/* Et rien à dévoiler tant que rien n'est tiré : les six personnes du premier
   verbe n'ont pas à occuper la scène derrière la question. */
body.projection .proj-shell[data-vd-gate] .proj-main > [data-vd-start] { display: none; }

/*
 * Le panneau d'aide cède la place : ce n'est plus une aide posée à côté, c'est
 * la seule chose à faire sur cet écran. Il reprend donc le flux, toute la
 * largeur de la scène, et perd son fond — un aplat derrière un bouton qu'on
 * cherche du fond de la salle ne fait que le rapetisser.
 */
body.projection .proj-shell[data-vd-gate] .proj-panel {
	position: static;
	width: auto;
	max-height: none;
	padding: 0;
	background: none;
	backdrop-filter: none;
	border: 0;
}

.spin-gate { display: flex; flex-direction: column; align-items: flex-start; gap: var(--spacing-5); }

/* La question du lancement est la question de la scène : elle est déjà écrite
   au-dessus par `stage()`. Sur écran étroit aussi : la scène passe en colonne
   (roue, puis question, puis choix), et la question de la scène tombe juste
   au-dessus des choix — la redire ici l'affichait deux fois de suite. */
.spin-gate .spin-ask { display: none; }

.spin-choices { display: flex; flex-wrap: wrap; gap: var(--spacing-3); }

.spin-choice {
	display: inline-flex;
	align-items: center;
	min-height: 3.2rem;
	padding: var(--spacing-3) var(--spacing-5);
	border: 2px solid var(--color-proj-line);
	border-radius: var(--radius-full);
	font-family: Fredoka;
	font-weight: 600;
	font-size: calc(clamp(17px, 2.6vh, 26px) * var(--proj-fit, 1));
	color: var(--color-proj-ink);
	text-decoration: none;
	transition: border-color .15s, color .15s, transform .15s;
}

.spin-choice:hover,
.spin-choice:focus-visible { border-color: var(--color-proj-accent); color: var(--color-proj-accent); transform: translateY(-2px); }

/*
 * Le bouton unique de l'A1. Il respire, et c'est le seul endroit du produit
 * où une animation dit quelque chose : rien d'autre n'attend sur cet écran,
 * et un bouton immobile au milieu d'un écran vide se confond avec un titre.
 */
.spin-go {
	display: inline-flex;
	align-items: center;
	padding: var(--spacing-4) var(--spacing-6);
	border-radius: var(--radius-full);
	background: var(--color-proj-accent);
	color: var(--color-proj-surface);
	font-family: Fredoka;
	font-weight: 700;
	font-size: calc(clamp(22px, 3.6vh, 38px) * var(--proj-fit, 1));
	text-decoration: none;
	animation: vd-call 2.2s ease-out infinite;
}

@keyframes vd-call {
	0%   { box-shadow: 0 0 0 0 rgba(255, 196, 107, .5); }
	70%  { box-shadow: 0 0 0 22px rgba(255, 196, 107, 0); }
	100% { box-shadow: 0 0 0 0 rgba(255, 196, 107, 0); }
}

@media (prefers-reduced-motion: reduce) {
	.spin-go { animation: none; }
	body.projection .proj-shell[data-vd-gate] .proj-media .proj-frame { transition: none; }
}

/* Sur un écran étroit, la scène passe en colonne : les choix prennent la
   largeur, pour se toucher au pouce. */
@media (max-width: 63.9375rem) {
	.spin-gate { align-items: stretch; }
	.spin-choice { flex: 1 1 12rem; justify-content: center; font-size: clamp(15px, 4vw, 20px); }
	.spin-go { justify-content: center; font-size: clamp(19px, 5.4vw, 26px); }
}

/* ═══ Le pendu ═════════════════════════════════════════════════════════════
 * La potence se dessine trait à trait plutôt que de compter les erreurs à
 * l'écrit : « 3 sur 6 » se lit, une potence à moitié construite se voit du
 * fond de la salle sans qu'on ait à la lire.
 */

.hang {
	display: grid;
	grid-template-columns: auto 1fr;
	grid-template-areas: "gallows word" "gallows keys" "verdict verdict";
	align-items: center;
	gap: var(--spacing-4) var(--spacing-6);
	width: 100%;
}

/* La potence occupait neuf rem — cent quarante-quatre pixels — au milieu d'un
 * écran de trois mètres. C'est le dessin qui dit combien d'erreurs restent :
 * il doit se lire du fond, pas se deviner. */
.hang-gallows { grid-area: gallows; width: calc(clamp(9rem, 34vh, 26rem) * var(--proj-fit, 1)); height: calc(clamp(9rem, 34vh, 26rem) * var(--proj-fit, 1)); flex: none; }
.hang-frame { fill: none; stroke: var(--color-proj-line); stroke-width: 5; stroke-linecap: round; }

/* Chaque trait attend son erreur. `visibility` plutôt que `display` pour que
 * le dessin ne se recompose pas à chaque trait. */
.hang-part {
	fill: none;
	stroke: var(--color-proj-accent);
	stroke-width: 5;
	stroke-linecap: round;
	visibility: hidden;
}

.hang-part.is-drawn { visibility: visible; }

.hang-word { grid-area: word; display: flex; flex-wrap: wrap; gap: var(--spacing-2); }

/* Une case vide montre sa place : la classe compte les lettres du mot avant
 * d'en proposer une, et c'est déjà de la réflexion. */
.hang-slot {
	display: inline-grid;
	place-items: center;
	min-width: clamp(2.4rem, 4.4vh, 4.4rem);
	padding-bottom: 6px;
	border-bottom: 5px solid var(--color-proj-line);
	font-family: Fredoka;
	font-size: clamp(26px, 6vh, 70px);
	font-weight: 700;
	line-height: 1.1;
}

/* La lettre est là dès le départ, simplement invisible : la révéler ne
 * déplace donc rien, et le mot ne sautille pas à chaque trouvaille. */
.hang-slot > .hang-letter { visibility: hidden; }
.hang-slot.is-open > .hang-letter { visibility: visible; }
.hang-slot.is-open { border-bottom-color: var(--color-proj-accent); }

.hang-keys {
	grid-area: keys;
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(clamp(2.6rem, 4.6vh, 4.6rem), 1fr));
	gap: var(--spacing-2);
}

.hang-key {
	min-height: clamp(2.8rem, 5vh, 5rem);
	border: 2px solid var(--color-proj-line);
	border-radius: var(--radius-md);
	background: none;
	color: var(--color-proj-ink);
	font-family: Fredoka;
	font-size: clamp(19px, 3vh, 34px);
	font-weight: 600;
	cursor: pointer;
}

.hang-key:hover:not(:disabled) { border-color: var(--color-proj-accent); }

/* Trouvée ou manquée, la lettre garde sa trace : la classe voit ce qu'elle a
 * déjà tenté, et le distingue par la forme autant que par la teinte. */
.hang-key:disabled { cursor: default; opacity: .75; }
.hang-key.is-hit { border-color: var(--color-proj-success); color: var(--color-proj-success); }
.hang-key.is-miss { border-style: dashed; text-decoration: line-through; opacity: .45; }

.hang-end { grid-area: verdict; display: flex; flex-wrap: wrap; align-items: center; gap: var(--spacing-3) var(--spacing-5); }
.hang-end:not(:has(> :not([hidden]))) { display: none; }
.hang-verdict { font-weight: 700; margin: 0; }
.hang-hear { margin: 0; }
.hang-verdict.is-lost { color: var(--color-proj-accent); }

/* ═══ Le pendu joué seul ══════════════════════════════════════════════════
 *
 * La même planche que la projection, sur fond clair. La géométrie se reprend
 * telle quelle ; les couleurs, non — celles de la projection sont faites pour
 * un fond sombre et disparaîtraient ici.
 *
 * On les redit donc une à une, plutôt que de redéfinir les jetons
 * `--color-proj-*` sur ce bloc. La tentation était grande : quatre lignes
 * auraient suffi. Mais un jeton redéfini sur un sélecteur ne vaut que pour ses
 * descendants, et la même variable est lue ailleurs dans la feuille sans
 * repli : le jour où une règle du pendu sortirait de `.hang-solo`, elle
 * perdrait sa couleur sans rien casser bruyamment. Un test du dépôt refuse
 * cette forme, et il a raison.
 *
 * Reste la taille. La potence est calibrée pour être lue du fond d'une salle,
 * ce qui n'a aucun sens à trente centimètres : elle passe à six rem, et la
 * planche se range en une colonne comme elle le fait déjà sur les écrans
 * étroits.
 */
.hang-solo .hang-frame { stroke: var(--color-line-strong); }
.hang-solo .hang-part { stroke: var(--color-primary); }
.hang-solo .hang-slot { border-bottom-color: var(--color-line-strong); color: var(--color-ink); }
.hang-solo .hang-slot.is-open { border-bottom-color: var(--color-primary); }
.hang-solo .hang-key { border-color: var(--color-line-strong); color: var(--color-ink); }
.hang-solo .hang-key:hover:not(:disabled) { border-color: var(--color-primary); }
.hang-solo .hang-key.is-hit { border-color: var(--color-success); color: var(--color-success-strong); }

.hang-solo .hang {
	grid-template-columns: 1fr;
	grid-template-areas: "gallows" "word" "keys";
	justify-items: center;
	gap: var(--spacing-4);
}

.hang-solo .hang-gallows { width: 6rem; height: 6rem; }
.hang-solo .hang-word { justify-content: center; }
.hang-solo .hang-slot { min-width: 1.8rem; font-size: 26px; border-bottom-width: 3px; }
.hang-solo .hang-keys { grid-template-columns: repeat(auto-fit, minmax(2.2rem, 1fr)); width: 100%; }
.hang-solo .hang-key { min-height: 2.6rem; font-size: 16px; }

/* L'image de la correction se pose comme une illustration, et non dans la
 * grille de la planche — il n'y a plus de planche à ce moment-là. */
.hang-sheet .hang-image { max-height: 12rem; }

@media (max-width: 48rem) {
	.hang { grid-template-columns: 1fr; grid-template-areas: "gallows" "word" "keys" "verdict"; justify-items: center; }
	.hang-gallows { width: 7rem; height: 7rem; }
	.hang-slot { min-width: 1.9rem; font-size: clamp(20px, 6vw, 30px); }
	.hang-keys { grid-template-columns: repeat(auto-fit, minmax(2.1rem, 1fr)); width: 100%; }
	.hang-key { min-height: 2.4rem; font-size: 16px; }
}

/* Un logo déposé remplace le logotype : on borne sa hauteur, pas sa largeur —
 * un logo est rarement carré, et le contraindre en largeur l'écrase. */
/* On borne la hauteur, jamais la largeur : un logotype n'est pas carré, et le
 * contraindre en largeur l'écrase. La zone de protection du dossier de marque
 * — la hauteur du bandeau tout autour — est tenue par la marge de l'en-tête. */
.brand-logo { display: block; height: 40px; width: auto; max-width: 15rem; }
/* Même taille que sur le site vitrine : 40 px de haut, 150 px de large sur téléphone. */
@media (max-width: 35rem) { .brand-logo { height: 34px; } }

/* L'étiquette d'une carte se dimensionne sur son texte, pas sur la carte : dans
 * une colonne flex, un enfant s'étire par défaut sur toute la largeur, et
 * « Gratuit » devenait une bande. */
.tile-pill { align-self: flex-start; }

/* Trois cartes côte à côte se lisent en colonnes : leurs titres partent du même
 * bord, et leurs conclusions se rejoignent en bas quelle que soit la longueur
 * du texte au-dessus. */
.grid-tiles > .tile { min-height: 100%; }

/* ══ la coche « fait » d'une tuile de rituel ══
 *
 * La boîte n'existe que pour tenir le bouton dans le coin de la tuile : la
 * tuile est un lien, et un bouton ne peut pas vivre dedans. Elle s'efface
 * autrement — même hauteur, même place dans la grille.
 *
 * Le bouton reste discret tant que rien n'est fait, et prend la couleur du
 * succès une fois posé. Il est petit, mais pas trop : quarante pixels, c'est
 * la cible tactile minimale, et on l'atteint sur une tablette posée à côté du
 * clavier au milieu d'un cours. */
.tile-slot { position: relative; display: flex; }
.tile-slot > .tile { flex: 1 1 auto; min-height: 100%; }

.tile-mark {
	position: absolute;
	top: var(--spacing-2);
	right: var(--spacing-2);
	width: 40px;
	height: 40px;
	display: grid;
	place-items: center;
	border: 2.5px solid var(--color-line);
	border-radius: var(--radius-full);
	background: var(--color-surface);
	color: var(--color-ink-faint);
	font-size: 18px;
	line-height: 1;
	cursor: pointer;
	padding: 0;
}

.tile-mark:hover { border-color: var(--color-primary); color: var(--color-primary); }
.tile-mark:focus-visible { outline: 3px solid var(--color-primary); outline-offset: 2px; }

.tile-mark[aria-pressed="true"] {
	background: var(--color-success-strong);
	border-color: var(--color-success-strong);
	color: var(--color-surface);
}

/* Le tampon « Hecho » et le cadenas occupaient déjà ce coin. Ils se décalent
 * de la largeur du bouton plutôt que de passer dessous : le tampon se lit du
 * fond de la salle, le bouton se touche, et aucun des deux ne remplace
 * l'autre. */
.tile-slot .stamp,
.tile-slot .stamp-locked { right: 58px; }

/* ═══ B8 — la télécommande ═════════════════════════════════════════════════
 *
 * Un écran de téléphone, tenu d'une main, consulté du coin de l'œil pendant
 * qu'on regarde ailleurs. Tout y est plus grand qu'ailleurs et plus espacé :
 * ce ne sont pas des commandes qu'on lit, ce sont des commandes qu'on touche.
 */

body.pilot { background: var(--color-surface); }

.pilot { max-width: 34rem; margin-inline: auto; padding-bottom: calc( 7rem + env( safe-area-inset-bottom, 0px ) ); }
.pilot-head { margin: var(--spacing-6) 0 var(--spacing-4); }
.pilot-head h1 { margin: var(--spacing-1) 0; }

/* Les touches secondaires : « Réécouter » et « Variante » côte à côte. Sans
 * « Réécouter » — un tableau sans son — il n'en reste qu'une, pleine largeur. */
.pilot-keys {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: var(--spacing-3);
}

.pilot-keys-quiet { grid-template-columns: minmax(0, 1fr); }
.pilot-key { min-height: 58px; justify-content: center; }

/* La barre du bas : « Retour » et « Suivant », fixes sous le pouce. « Suivant »
 * est deux fois plus large, c'est le geste qu'on fait quarante fois par séance
 * et le seul qu'on doit trouver sans regarder. */
.pilot-dock {
	position: fixed;
	inset: auto 0 0 0;
	z-index: 40;
	background: var(--color-surface);
	border-top: 2px solid var(--color-line);
	padding: var(--spacing-3) max( var(--spacing-4), env( safe-area-inset-right, 0px ) ) calc( var(--spacing-3) + env( safe-area-inset-bottom, 0px ) ) max( var(--spacing-4), env( safe-area-inset-left, 0px ) );
}

.pilot-dock-in {
	max-width: 34rem;
	margin-inline: auto;
	display: grid;
	grid-template-columns: 1fr 2.2fr;
	gap: var(--spacing-3);
}

.pilot-dock .pilot-key { min-height: 68px; font-size: 1.15rem; }

/* Un ordre parti se voit une demi-seconde. Sans ce retour, le professeur qui
 * regarde le tableau appuierait deux fois. */
.pilot-key.is-sent { transform: translateY(2px); }
.pilot-key.is-failed { outline: 3px solid var(--color-error); }

/* Le module que le tableau montre en ce moment. */
.pilot-module.is-current { border-color: var(--color-ink); box-shadow: 0 4px 0 var(--color-ink); }
.pilot-here { font-family: Fredoka; font-weight: 600; font-size: var(--text-body-sm); padding: 2px var(--spacing-3); border-radius: var(--radius-full); background: var(--color-gold); color: var(--color-ink); white-space: nowrap; }

/* La fiche de confirmation : au-dessus de la barre, collée en bas, à portée du
 * pouce. Fermée d'un geste en dehors d'elle. */
.pilot-veil {
	position: fixed;
	inset: 0;
	z-index: 90;
	display: flex;
	align-items: flex-end;
	justify-content: center;
	background: rgba( 46, 38, 80, .55 );
}

.pilot-veil[hidden] { display: none; }

.pilot-sheet {
	width: 100%;
	max-width: 34rem;
	background: var(--color-surface-raised);
	border: 2.5px solid var(--color-ink);
	border-bottom: 0;
	border-radius: var(--radius-2xl) var(--radius-2xl) 0 0;
	padding: var(--spacing-5) max( var(--spacing-4), env( safe-area-inset-right, 0px ) ) calc( var(--spacing-5) + env( safe-area-inset-bottom, 0px ) ) max( var(--spacing-4), env( safe-area-inset-left, 0px ) );
}

.pilot-levels { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--spacing-2); margin-top: var(--spacing-3); }
.pilot-levels > .btn { justify-content: center; }



/* Un élève qui a parlé se distingue du reste : c'est la liste de ceux qui
 * n'ont rien dit qu'on vient chercher ici, et elle doit sauter aux yeux. */




/* Retirer une tape est plus étroit qu'en ajouter une : c'est la correction
 * d'une erreur, pas un geste de la séance. */

.pilot-modules { list-style: none; margin: var(--spacing-3) 0 0; padding: 0; display: grid; gap: var(--spacing-2); }

.pilot-module {
	width: 100%;
	display: flex;
	align-items: center;
	gap: var(--spacing-3);
	min-height: 52px;
	padding: var(--spacing-2) var(--spacing-4);
	background: none;
	border: 2px solid var(--color-line);
	border-radius: var(--radius-lg);
	color: inherit;
	font: inherit;
	cursor: pointer;
	text-align: left;
}

.pilot-rank { font-family: Fredoka; font-weight: 700; color: var(--color-ink-muted); font-variant-numeric: tabular-nums; }
.pilot-module-name { flex: 1 1 auto; font-family: Fredoka; font-weight: 600; }
.pilot-go { color: var(--color-primary); }

.pilot-foot { display: grid; gap: var(--spacing-2); margin-top: var(--spacing-6); }

/* ═══ Le code d'une classe ═══════════════════════════════════════════════
 * On vient le chercher ici neuf fois sur dix : il se lit de loin, se dicte à
 * voix haute et se recopie sans hésiter sur la forme des caractères. */
.join-code {
	display: inline-block;
	padding: var(--spacing-1) var(--spacing-3);
	background: var(--color-surface-sunken);
	border-radius: var(--radius-md);
	font-family: "Space Mono", ui-monospace, monospace;
	font-size: 17px;
	font-weight: 700;
	letter-spacing: .08em;
	user-select: all;
}

/* ═══ Une pastille qui porte un choix ════════════════════════════════════
 * Le bouton radio reste visible. On pourrait le masquer et ne garder que la
 * pastille colorée, mais l'état ne tiendrait plus qu'à `:has(:checked)` : le
 * jour où un navigateur ne le comprend pas, le formulaire n'indique plus rien
 * de ce qui est coché. Le témoin natif dit toujours la vérité ; la pastille
 * ne fait que la rendre visible de loin. */
.chip:has( input:checked ) {
	border-color: var(--color-primary);
	background: var(--color-primary-soft);
	color: var(--color-primary-active);
}

.chip:has( input:focus-visible ) { outline: 3px solid var(--color-primary); outline-offset: 2px; }
.chip input { margin: 0; accent-color: var(--color-primary); }
.chip { cursor: pointer; }

.level-picker > .btn:has( input:checked ) {
	background: var(--color-primary);
	color: var(--color-on-primary);
	border-color: var(--color-primary);
}

.level-picker > .btn input { position: absolute; opacity: 0; pointer-events: none; }
.level-picker > .btn { position: relative; }

/* ═══ Cartes, et non tuiles ══════════════════════════════════════════════
 * `.grid-tiles` descend à 168 px de colonne : c'est fait pour les tuiles de
 * modules du sommaire, dont le libellé tient en deux mots. Une carte de classe
 * porte deux boutons côte à côte, et « Projeter → » plus « Télécommande » ne
 * tiennent pas dans 168 px — le second débordait par le bord. */
.grid-cards { grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr)); }

/* Et quand ils ne tiennent toujours pas — un écran étroit, une traduction
 * longue —, ils passent l'un sous l'autre plutôt que de sortir du cadre. */
.tile-foot.row { flex-wrap: wrap; row-gap: var(--spacing-2); }
.tile-foot .btn { flex: 1 1 auto; min-width: 0; }

/* ═══ C6 — la liste des élèves ═══════════════════════════════════════════ */

/* ═══ Les marges de ces listes sont les leurs ════════════════════════════
 * Sept listes portaient une classe utilitaire de marge dans le gabarit —
 * « roster mt-4 » — et ne l'ont jamais appliquée. Les utilitaires sont
 * déclarés ligne 276, les composants entre 2400 et 3900 : à spécificité
 * égale, c'est la dernière règle qui gagne, et `margin: 0` l'emportait
 * chaque fois.
 *
 * Ce `margin: 0` ne peut pas disparaître, il annule la marge que le
 * navigateur pose sur toute liste. La marge voulue entre donc dans la règle
 * du composant, à la valeur que l'utilitaire visait, et l'utilitaire quitte
 * le gabarit — le laisser laisserait croire qu'il fait quelque chose. */

.roster { list-style: none; margin: var(--spacing-4) 0 0; padding: 0; display: grid; gap: var(--spacing-2); }

.roster-row {
	display: flex;
	align-items: center;
	gap: var(--spacing-3);
	padding: var(--spacing-3) var(--spacing-4);
	background: var(--color-surface-raised);
	border: 2px solid var(--color-line);
	border-radius: var(--radius-lg);
	flex-wrap: wrap;
}

/* Une initiale plutôt qu'un portrait : il n'y a pas de photo à mettre, et il
 * n'y en aura jamais. Elle sert à retrouver une ligne du regard dans une liste
 * de trente, pas à identifier quelqu'un. */
.roster-mark {
	flex: 0 0 auto;
	width: 38px;
	height: 38px;
	display: grid;
	place-items: center;
	border-radius: var(--radius-full);
	background: var(--color-primary-soft);
	color: var(--color-primary-active);
	font-family: Fredoka;
	font-weight: 700;
	font-size: 17px;
}

.roster-who { flex: 1 1 12rem; display: flex; flex-direction: column; min-width: 0; }

/* ═══ Les codes fraîchement attribués ════════════════════════════════════
 * Ils ne s'affichent qu'une fois : ce bloc doit s'imprimer proprement, parce
 * que c'est la feuille qu'on découpe et qu'on distribue en début d'année. */
.pins-list { list-style: none; margin: var(--spacing-3) 0 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); gap: var(--spacing-2); }
.pins-list li { display: flex; align-items: center; justify-content: center; gap: var(--spacing-2); padding: var(--spacing-2) var(--spacing-3); border: 2px dashed var(--color-line-strong); border-radius: var(--radius-md); }
/* Le champ et son bouton sur une ligne, à la même hauteur.
 *
 * Le formulaire était posé dans l'en-tête de section sans mise en forme : les
 * deux contrôles s'alignaient sur la ligne de base du texte, à des hauteurs
 * différentes, avec l'espace d'un caractère entre eux. */
.pins-add { display: flex; align-items: center; gap: var(--spacing-2); }

/* Assez large pour deux chiffres et les flèches du navigateur, et à la hauteur
 * du bouton qui la suit — 38 pixels, comme tous les petits boutons. */
.pins-count { width: 5.5rem; min-height: 38px; text-align: center; font-family: Fredoka; font-weight: 600; }

@media print {
	/* Sur le papier, on ne garde que les codes. Le reste de l'écran —
	 * navigation, blocs d'explication, boutons — remplirait trois pages pour
	 * une liste qui en fait une. */
	.chrome, .sec, .roster, .surface-card:not( .pins ), .tabs, .chrome-out { display: none; }
	.pins { border: none; box-shadow: none; }
	.pins-list { grid-template-columns: repeat(2, 1fr); }
}

/* ═══ C4 — composer le rituel ════════════════════════════════════════════ */

/* La durée reste sous les yeux. C'est l'arbitrage qu'on vient faire ici, et le
 * reléguer au bas d'une page le ferait découvrir après coup. */
.compose-bar {
	position: sticky;
	top: 0;
	z-index: 20;
	display: flex;
	align-items: center;
	gap: var(--spacing-4);
	flex-wrap: wrap;
	margin-top: var(--spacing-6);
	padding: var(--spacing-3) var(--spacing-4);
	background: var(--color-surface-raised);
	border: 2.5px solid var(--color-ink);
	border-radius: var(--radius-lg);
	box-shadow: 0 5px 0 var(--color-ink);
}

.compose-total { display: flex; align-items: baseline; gap: var(--spacing-2); }
.compose-total strong { font-family: Fredoka; font-size: 26px; font-weight: 700; font-variant-numeric: tabular-nums; }
.compose-bar .btn { margin-left: auto; }

/* Le verdict change de couleur, mais il change surtout de mots : la teinte
 * seule ne dirait rien à qui ne la perçoit pas, et rien du tout à qui ne sait
 * pas qu'un rituel tient en huit minutes. */
[data-vd-state="long"] .compose-bar { border-color: var(--color-error-strong); }
[data-vd-state="long"] [data-vd-verdict] { color: var(--color-error-strong); }
[data-vd-state="empty"] .compose-bar { border-style: dashed; }

.compose-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--spacing-6); margin-top: var(--spacing-4); }

@media (min-width: 60rem) {
	/* Le rituel à gauche, le catalogue à droite : on lit ce qu'on a avant de
	 * regarder ce qu'on pourrait ajouter. */
	.compose-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: start; }
}

.compose-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--spacing-2); counter-reset: rituel; }

.compose-item {
	display: flex;
	align-items: center;
	gap: var(--spacing-3);
	padding: var(--spacing-3);
	background: var(--color-surface-raised);
	border: 2px solid var(--color-line);
	border-radius: var(--radius-lg);
}

/* Le rang se dessine plutôt que de s'écrire : l'ordre change à chaque geste, et
 * un numéro tapé en dur mentirait dès le premier déplacement. */
.compose-item::before {
	counter-increment: rituel;
	content: counter( rituel, decimal-leading-zero );
	font-family: Fredoka;
	font-weight: 700;
	color: var(--color-ink-muted);
	font-variant-numeric: tabular-nums;
}

.compose-item.is-dragging { opacity: .4; }
.compose-grip { cursor: grab; color: var(--color-ink-faint); }
.compose-name { flex: 1 1 auto; font-family: Fredoka; font-weight: 600; min-width: 0; }
.compose-time { color: var(--color-ink-muted); font-size: 14px; font-variant-numeric: tabular-nums; white-space: nowrap; }
.compose-moves { display: flex; gap: 2px; }

.compose-move {
	width: 34px;
	height: 34px;
	border: 2px solid var(--color-line);
	border-radius: var(--radius-md);
	background: none;
	color: var(--color-ink-muted);
	cursor: pointer;
	line-height: 1;
}

.compose-move:disabled { opacity: .3; cursor: default; }
.compose-drop:hover { border-color: var(--color-error-strong); color: var(--color-error-strong); }

.compose-offer { list-style: none; margin: var(--spacing-2) 0 0; padding: 0; display: grid; gap: var(--spacing-2); }

.compose-add {
	width: 100%;
	display: flex;
	align-items: center;
	gap: var(--spacing-3);
	padding: var(--spacing-3);
	background: none;
	border: 2px dashed var(--color-line-strong);
	border-radius: var(--radius-lg);
	color: inherit;
	font: inherit;
	cursor: pointer;
	text-align: left;
}

/* La ligne du catalogue tient sur deux rangs : le nom, la mention et la durée
 * d'abord ; le descriptif dessous, sur toute la largeur.
 *
 * `text-align: left` parce qu'un <button> centre son texte : sans cela, la
 * phrase de description se serait posée au milieu, sous un nom aligné à
 * gauche. */
.compose-add { flex-wrap: wrap; row-gap: var(--spacing-1); text-align: left; }

.compose-desc {
	flex: 1 1 100%;
	color: var(--color-ink-muted);
	font-size: 13px;
	line-height: 1.35;
	font-weight: 400;
}

.compose-add:hover:not( :disabled ) { border-style: solid; border-color: var(--color-primary); }
.compose-add:disabled { opacity: .45; cursor: default; }
.compose-plus { font-family: Fredoka; font-weight: 700; color: var(--color-primary); }

/* « outil » plutôt qu'un exercice : la mention est petite mais elle change ce
 * qu'on attend de la ligne. */
.compose-kind {
	padding: 1px var(--spacing-2);
	border-radius: var(--radius-full);
	background: var(--color-surface-sunken);
	color: var(--color-ink-muted);
	font-size: 12px;
	text-transform: uppercase;
	letter-spacing: .05em;
	white-space: nowrap;
}

/* ═══ Le panneau d'aide, dans un coin ════════════════════════════════════
 *
 * Il occupait un bandeau pleine largeur sous la scène, et prenait donc de la
 * hauteur à ce qu'on projette. Or ce qu'il porte est facultatif : une consigne
 * qu'on lit une fois — « clique sur une ville » —, parfois une banque de mots
 * qu'on consulte du coin de l'œil. Rien de tout cela ne mérite une bande.
 *
 * En haut à droite, à l'opposé du titre. C'est le coin que la scène laisse
 * libre le plus souvent : les lignes de dévoilement partent de la gauche, et
 * la carte y montre le Pacifique.
 */
@media (min-width: 64rem) {
	body.projection .proj-body { position: relative; }

	/* La largeur du panneau, nommée une fois : la scène doit lui réserver
	 * exactement cette place, et deux valeurs écrites séparément finissent
	 * toujours par diverger. */
	/*
	 * En rem, et non en pourcentage.
	 *
	 * Le panneau se place par rapport au corps ; le retrait qui lui réserve sa
	 * place se calcule sur la scène. Tant que la scène occupe tout le corps,
	 * `34 %` désigne la même chose des deux côtés — mais dès qu'un module
	 * porte une colonne média, la scène n'en fait plus que la moitié, et le
	 * retrait devient deux fois trop petit. La roue des verbes voyait donc sa
	 * question passer sous le panneau.
	 *
	 * Une largeur fixe n'a pas ce défaut : elle vaut la même chose où qu'on la
	 * lise. Vingt-deux rem sur les soixante que ce palier exige au minimum, ce
	 * qui laisse toujours les deux tiers à la scène.
	 */
	body.projection .proj-body { --proj-panel: 22rem; }

	body.projection .proj-panel {
		position: absolute;
		top: 0;
		right: 0;
		z-index: 4;
		width: var(--proj-panel);
		max-height: 100%;
		overflow-y: auto;
		/*
		 * La barre de défilement ne se dessine pas.
		 *
		 * `overflow-y: auto` est là par sécurité, pour une consigne qui
		 * déborderait. Mais le navigateur réserve sa gouttière dans la boîte
		 * bordée et arrondie, et le pouce s'y peignait en un court trait
		 * vertical au bord droit du panneau — projeté sur trois mètres, un
		 * trait qui n'appartient à rien et que la classe voit avant la
		 * consigne.
		 *
		 * Personne ne fait défiler une consigne au milieu d'un cours : le
		 * filet reste, sa poignée part.
		 */
		scrollbar-width: none;
		overscroll-behavior: contain;
		padding: var(--spacing-4);
		/* Assez opaque pour se lire par-dessus la carte, assez discret pour
		 * ne pas se disputer l'attention avec la réponse. */
		background: color-mix(in oklab, var(--color-proj-surface) 82%, transparent);
		backdrop-filter: blur(6px);
	}
@supports not (color: color-mix(in srgb, red, blue)) { body.projection .proj-panel { background: rgba(36,28,46,0.82); } }

	body.projection .proj-panel::-webkit-scrollbar { width: 0; height: 0; }

	/* La scène reprend la largeur que le panneau occupait — mais seulement
	 * quand elle est seule.
	 *
	 * Cette règle avait été posée pour récupérer la place du panneau d'aide,
	 * devenu flottant. Elle s'appliquait aussi aux modules qui portent une
	 * colonne média : la roue des verbes, la carte du monde, une image.
	 * `flex: 1 1 100%` chassait alors le média sur sa propre ligne, et la roue
	 * se retrouvait en bandeau au-dessus de la question au lieu d'être à côté
	 * d'elle — la moitié droite de l'écran vide, le reste à faire défiler.
	 *
	 * Le sélecteur de frère adjacent suffit à distinguer les deux cas : le
	 * média est toujours écrit avant la scène. */
	body.projection .proj-main { flex: 1 1 100%; }

	body.projection .proj-media + .proj-main { flex: 1 1 clamp(20rem, 52%, 40rem); }

	/*
	 * Une illustration ne prend pas la moitié de l'écran.
	 *
	 * La colonne média est dimensionnée pour la carte du monde et la roue des
	 * verbes, qui n'ont de sens qu'en grand. Une image de mot du jour, non :
	 * ce qu'on regarde ensuite est le mot, et c'est lui qui doit dominer.
	 * Sans ce plafond, l'image gardait sa moitié d'écran et le mot se
	 * retrouvait à l'étroit contre le panneau.
	 */
	body.projection .proj-body.has-illus .proj-media { flex: 0 1 clamp(16rem, 30%, 30rem); }

	/*
	 * La scène réserve la place du panneau plutôt que de passer dessous.
	 *
	 * Le panneau est sorti du flux pour rendre sa largeur à la scène ; la
	 * scène l'a prise entièrement, y compris la bande où il flotte. Une phrase
	 * un peu longue — un trabalenguas, précisément le module dont la phrase
	 * est longue par définition — filait donc sous le panneau et se
	 * terminait derrière lui.
	 *
	 * Le retrait ne porte que sur ce qui pourrait passer dessous. Posé sur
	 * `.proj-main`, il aurait aussi rétréci le panneau, qui est son enfant.
	 */
	body.projection .proj-main.has-panel > .t-proj-q,
	body.projection .proj-main.has-panel > [data-vd-start] {
		padding-right: calc(var(--proj-panel) + var(--spacing-6));
	}

	/*
	 * Le compteur aussi : posé en haut à droite de la scène, il passait sous
	 * le panneau qui flotte au même endroit — « 1 / 3 » d'« El intruso » ne
	 * se voyait plus. Il se range donc à gauche du panneau, dans la bande que
	 * la question lui laisse.
	 */
	body.projection .proj-main.has-panel.has-count > .proj-count {
		right: calc(var(--proj-panel) + var(--spacing-6));
	}

	/*
	 * Un module à colonne média garde son panneau dans le flux jusqu'à
	 * quatre-vingts rem.
	 *
	 * Le panneau flotte et la scène lui réserve vingt-deux rem de retrait.
	 * Quand un média occupe la gauche, la scène n'a plus que la moitié de la
	 * largeur : à mille pixels, elle fait vingt rem et se voyait imposer un
	 * retrait de vingt-trois. Une boîte plus étroite que son propre padding
	 * déborde nécessairement — la roue des verbes poussait donc sa question et
	 * son panneau hors de l'écran, et la page se faisait défiler
	 * latéralement.
	 *
	 * En dessous du seuil, le panneau reprend sa place sous la scène : il y
	 * tient, et rien ne dépasse.
	 */
	body.projection .proj-body.has-media .proj-panel {
		position: static;
		width: auto;
		max-height: none;
		backdrop-filter: none;
	}

	/*
	 * Et la scène récupère le retrait qui lui réservait sa place.
	 *
	 * Le retrait est posé au-dessus sur toute scène qui contient un panneau,
	 * sans regarder si ce panneau flotte encore. Remis dans le flux, le
	 * panneau n'occupe plus la bande de droite — mais les vingt-deux rem
	 * restaient réservés pour rien, et la question se retrouvait dans une
	 * colonne deux fois trop étroite, en caractères d'affiche. C'est la
	 * moitié de la panne du portable ; l'autre moitié était le seuil, plus
	 * bas.
	 */
	body.projection .proj-body.has-media .proj-main > .t-proj-q,
	body.projection .proj-body.has-media .proj-main > [data-vd-start] {
		padding-right: 0;
	}

	body.projection .proj-body.has-media .proj-main.has-panel.has-count > .proj-count { right: 0; }

	/*
	 * Une question posée dans une demi-colonne se dit plus petit.
	 *
	 * « ¿Cómo se conjuga? Presente » à soixante-dix-huit pixels dans une
	 * colonne de quatre cent cinquante prend trois lignes — deux cent
	 * cinquante pixels de haut, avant même la première réponse. La
	 * conjugaison passait sous la ligne de flottaison pour laisser la place à
	 * l'énoncé, ce qui est l'inverse de ce qu'on veut : la question se lit une
	 * fois, les réponses restent.
	 */
	body.projection .proj-media + .proj-main > .t-proj-q {
		font-size: calc(clamp(26px, 4.6vh, 52px) * var(--proj-fit, 1));
	}

	/* Le média prend le reste, sans dépasser la moitié : au-delà, la réponse
	 * — qui est le contenu — passerait au second plan derrière son décor. */
	body.projection .proj-media { flex: 1 1 clamp(16rem, 40%, 32rem); align-self: stretch; }
}

/* Assez large pour qu'une colonne média et un panneau flottant tiennent côte à
 * côte : la scène garde alors plus de trente rem une fois les deux servis. */
/*
 * Le panneau ne reprend son vol qu'une fois la place vraiment là.
 *
 * Il flottait dès quatre-vingts rem, et le compte n'y était pas pour un
 * module à colonne média. Sur un portable de mille trois cent soixante-six
 * pixels : la roue prend la moitié, la scène garde environ six cents pixels,
 * et le retrait qui réserve la place du panneau en vaut trois cent
 * cinquante-deux. Il reste deux cent vingt pixels pour une question écrite en
 * caractères d'affiche — elle débordait de sa boîte et filait sous le
 * panneau, qui la coupait en deux. C'est exactement la panne que le palier
 * précédent décrit à mille pixels : une boîte plus étroite que son propre
 * retrait déborde nécessairement.
 *
 * Le seuil passe donc à cent rem. En dessous, le panneau reste sous la scène
 * — il y tient, et rien ne dépasse. Un vidéoprojecteur de mille neuf cent
 * vingt, lui, le retrouve à droite, là où il ne gêne personne.
 */
@media (min-width: 100rem) {
	body.projection .proj-body.has-media .proj-panel {
		position: absolute;
		width: var(--proj-panel);
		max-height: 100%;
		backdrop-filter: blur(6px);
	}

	body.projection .proj-body.has-media .proj-main > .t-proj-q,
	body.projection .proj-body.has-media .proj-main > [data-vd-start] {
		padding-right: calc(var(--proj-panel) + var(--spacing-6));
	}
}

/* Sous ce seuil, le panneau reprend sa place dans le flux : superposé sur un
 * écran étroit, il couvrirait la moitié de la scène. */

/* Le rang d'une ville. Petit, en retrait : il dit dans quel ordre on avance,
 * pas ce qu'il faut trouver. L'heure reste la question. */
.geo-rank {
	position: absolute;
	/*
	 * Dans le coin, et non débordant du coin.
	 *
	 * La pastille dépassait de neuf pixels vers le haut et vers la gauche.
	 * Elle ajoutait donc à la hauteur de la bulle une part que le calcul
	 * d'écartement ignorait, et elle allait se poser sur la pastille d'une
	 * ville voisine — on lisait alors le trait de rappel d'une ville comme
	 * s'il désignait celle d'à côté.
	 */
	top: .3cqw;
	left: .3cqw;
	width: 1.9cqw;
	height: 1.9cqw;
	min-width: 15px;
	min-height: 15px;
	display: grid;
	place-items: center;
	border-radius: var(--radius-full);
	background: var(--color-proj-accent);
	color: var(--color-proj-surface);
	font-family: Fredoka;
	font-weight: 700;
	font-size: max(9px, 1.05cqw);
	line-height: 1;
}

.geo-pin > .proj-zone { position: relative; overflow: visible; }

/* ══════════════════════════════════════════════════════════════════════
 * Le rituel joué seul — écrans D1 à D7
 *
 * Un élève travaille sur le téléphone qu'il a en poche, pas sur le
 * vidéoprojecteur de la salle. Toute cette section part donc du petit écran
 * et s'élargit ensuite, à l'inverse de la projection qui fait le contraire.
 * ══════════════════════════════════════════════════════════════════════ */

.wrap-narrow {
	max-width: 44rem;
	margin: 0 auto;
	padding: 0 var(--spacing-4) var(--spacing-16);
}

.field-label {
	font-family: var(--font-label), system-ui, sans-serif;
	font-weight: 600;
	font-size: var(--text-label, 15px);
	color: var(--color-ink-muted);
}

/* La liste du jour. Une puce numérotée n'apporterait rien : chaque ligne
 * porte déjà son rang, et deux numérotations côte à côte se contredisent
 * dès qu'un module est retiré du rituel. */
/* `margin: 0` écrasait le `.mt-6` posé sur la liste : déclaré plus bas dans la
 * feuille, il l'emportait, et le bouton « Jugar » touchait la première carte.
 * On ne remet à zéro que ce que le navigateur ajoute sur les côtés et en bas. */
.solo-list { list-style: none; margin-inline: 0; margin-bottom: 0; padding: 0; }

.solo-step { width: 100%; text-decoration: none; color: inherit; gap: var(--spacing-3); }

/* Fait, mais toujours ouvert. Un module terminé se rejoue — sans rapporter
 * de points — et le griser aurait dit le contraire. */
.solo-step.is-done { background: var(--color-surface-sunken); }
.solo-step.is-done .t-title-module { color: var(--color-ink-muted); }

.solo-image {
	display: block;
	width: 100%;
	max-height: 44vh;
	object-fit: contain;
	border-radius: var(--radius-md);
}

.tile-media,
.tile-audio { min-height: auto; cursor: default; align-items: stretch; }

/*
 * L'espace élève fermé jusqu'à son heure.
 *
 * Une horloge, pas un cadenas : l'élève n'est pas puni, il est attendu. Et
 * l'heure se lit de loin, parce que c'est la seule information qu'il vient
 * chercher.
 */
.closed-card { text-align: center; padding: var(--spacing-8) var(--spacing-5); }
.closed-card .closed-lock { font-size: 40px; line-height: 1; }
.closed-clock { font-family: Fredoka; font-weight: 700; font-size: 54px; line-height: 1;
  margin: var(--spacing-2) 0; color: var(--color-primary); }

/* Les heures d'ouverture, dans les réglages de la classe. */
.when-grid { display: grid; grid-template-columns: 1fr auto auto; gap: var(--spacing-2) var(--spacing-4);
  align-items: center; margin-top: var(--spacing-4); }
.when-grid .when-day { font-family: Fredoka; font-weight: 600; }
.when-time { font-family: "Space Mono", ui-monospace, monospace; font-weight: 700;
  border: 2px solid var(--color-line); border-radius: var(--radius-md);
  padding: var(--spacing-1) var(--spacing-3); background: var(--color-surface); width: 7.5em; text-align: center; }
.when-time:disabled { opacity: .35; }

/* Une date complète ne tient pas dans la largeur d'une heure.
 *
 * `.when-time` fait 7,5 em, taillé pour « 16:00 » dans la grille des sept
 * jours. Le même champ portant « 31/08/2027 » et l'icône du calendrier s'y
 * coupait au milieu de l'année. Une variante, plutôt que d'élargir la grille
 * hebdomadaire qui, elle, n'a besoin de rien. */
.when-date { width: 13.5em; letter-spacing: -0.02em; text-align: left; padding-inline: var(--spacing-2); }
.onboard-card .when-date { width: 100%; max-width: 15em; }

/* L'échéance d'une classe : discrète en temps normal, ambre au dernier mois. */
.class-card-ends { color: var( --color-gold-strong ); font-weight: 600; }
.when-mode { display: none; }
.when-mode.is-shown { display: block; }

.tile-audio audio { width: 100%; }

.option-letter { width: 36px; justify-content: center; flex: none; }

/* La proposition est un `<label>` : c'est le bouton radio qu'il enveloppe
 * qui porte l'état, la sélection au clavier et l'envoi du formulaire. Le
 * dessiner nous-mêmes aurait demandé de réimplémenter les trois. */
.option:focus-within {
	outline: var(--focus-width, 3px) solid var(--color-primary);
	outline-offset: 2px;
}

.option:has(input:checked) {
	background: var(--color-primary-soft);
	color: var(--color-primary-active);
	border-color: var(--color-primary);
	box-shadow: 0 4px 0 var(--color-primary);
}

/*
 * Le verdict tient sur une ligne : l'appréciation à gauche, les points à
 * droite. Il occupait une carte haute et vide, où seul un mot s'écrivait.
 */
.solo-verdict {
	/* `.tile` impose 156 px de haut, faits pour les tuiles du sommaire : le
	 * verdict, qui tient sur une ligne, en gardait un grand vide. */
	min-height: 0;
	flex-direction: row;
	align-items: center;
	justify-content: space-between;
	gap: var(--spacing-3);
	padding: var(--spacing-4) var(--spacing-5);
}

/*
 * Le verdict s'est redressé : une figure, le mot, et ce qu'on gagne.
 *
 * Il tenait sur une ligne, à plat, les points repoussés à droite dans une
 * pastille grise. On lisait « ¡Correcto! » comme on lit un accusé de
 * réception. Trois secondes de satisfaction ne coûtent rien et sont tout ce
 * qui distingue un exercice d'un formulaire — après quoi on continue, et
 * c'est pourquoi rien ici ne demande de geste.
 */
.solo-verdict { flex-direction: column; justify-content: center; text-align: center; gap: var(--spacing-1); padding: var(--spacing-5); }
.solo-mark { font-size: 40px; line-height: 1.1; }
.solo-verdict .solo-title { margin: 0; }
.solo-verdict.is-correct { border-color: var(--color-success-strong); box-shadow: 0 4px 0 var(--color-success-strong); background: var(--color-success-soft); }
.solo-verdict.is-correct .solo-title { color: var(--color-success-strong); }
.solo-verdict.is-partial { border-color: var(--color-gold-strong); box-shadow: 0 4px 0 var(--color-gold-strong); }
.solo-verdict.is-partial .solo-title { color: var(--color-gold-strong); }
.solo-verdict.is-wrong   { border-color: var(--color-error-strong); box-shadow: 0 4px 0 var(--color-error-strong); }
.solo-verdict.is-wrong .solo-title { color: var(--color-error-strong); }

.solo-done { text-align: center; }
.solo-done .tile, .solo-done .btn { text-align: left; }
.solo-done .btn { text-align: center; }
.solo-trophy { font-size: 54px; line-height: 1; margin: var(--spacing-8) 0 var(--spacing-2); }
.solo-gain.is-clean { color: var(--color-success-strong); background: var(--color-success-soft); }

.solo-gains { display: flex; gap: var(--spacing-2); justify-content: center; margin: var(--spacing-2) 0 0; flex-wrap: wrap; }
.solo-gain { font-family: var(--font-title-module), system-ui, sans-serif; font-weight: 700; font-size: 14px;
	border-radius: var(--radius-full); padding: 4px 12px; background: var(--color-surface-raised); }
.solo-gain.is-points { color: var(--color-gold-strong); }
.solo-gain.is-points::before { content: "★ "; }
.solo-gain.is-streak { color: var(--color-ink); }

/*
 * La copie corrigée : une ligne par champ, séparées par un filet.
 *
 * Ce qui a été écrit d'abord, ce qu'il fallait écrire ensuite. Le filet à
 * gauche donne le verdict de la ligne sans qu'on ait à le lire — vert, doré,
 * rouge — et il tient tout seul, sans compter sur la couleur : la mention
 * « Ta réponse » puis « La réponse » dit la même chose en toutes lettres.
 */
.solo-sheet { gap: var(--spacing-4); }

.solo-line {
	padding-left: var(--spacing-4);
	border-left: 4px solid var(--color-line);
}

.solo-line + .solo-line { margin-top: var(--spacing-4); }
.solo-line.is-correct { border-left-color: var(--color-success-strong); }
.solo-line.is-near    { border-left-color: var(--color-gold-strong); }
.solo-line.is-wrong   { border-left-color: var(--color-error-strong); }

/* Ce que l'élève a écrit se lit tel quel, sans jugement typographique ; la
 * réponse attendue est ce qu'il doit retenir, et elle est en gras. */
.solo-wrote  { font-weight: 500; }
.solo-wanted { font-weight: 700; }

.solo-earned {
	background: var(--color-success-soft);
	border-color: var(--color-success-strong);
	color: var(--color-success-strong);
	font-weight: 700;
}

/* Remise en ordre. Les jetons restent des boutons : le glisser-déposer est
 * un confort, le clic est le mécanisme — sur un écran tactile de 5 pouces,
 * glisser un mot de trois lettres entre deux autres n'est pas une
 * interaction, c'est une épreuve d'adresse. */
.order-bank,
.order-line {
	display: flex;
	flex-wrap: wrap;
	gap: var(--spacing-2);
	align-items: center;
}

.order-line {
	min-height: 96px;
	background: var(--color-surface-sunken);
	border-style: dashed;
	cursor: default;
	padding: var(--spacing-4);
}

.order-token { cursor: pointer; }
.order-token[disabled] { opacity: .35; cursor: default; }

/* Le mur et le classement — D8 et D9 */

/* La pastille de légende. Même dessin que les cases du mur, taille fixe :
 * dans la grille elles s'étirent, ici elles doivent rester lisibles à côté
 * d'un mot. */
.wall-key {
	display: inline-block;
	width: 12px;
	height: 16px;
	vertical-align: -2px;
	margin-right: var(--spacing-1);
}

.rank-list { list-style: none; margin: var(--spacing-6) 0 0; padding: 0; }

.rank-row { gap: var(--spacing-3); }

/* Sa propre ligne se repère sans avoir à lire les pseudonymes un par un.
 * Un classement où l'on doit se chercher est un classement qu'on lit
 * d'abord pour savoir qui est devant soi. */
.rank-row.is-you {
	border-color: var(--color-primary);
	box-shadow: 0 4px 0 var(--color-primary);
	background: var(--color-primary-soft);
}

.rank-place {
	min-width: 44px;
	justify-content: center;
	flex: none;
	font-size: 18px;
}

/* Les écrans du professeur — C1, C5, C7 */

/* Un taux bas se signale par la couleur d'alerte, jamais par le rouge d'une
 * erreur : un module à 48 % n'est pas en panne, il est difficile. */
.text-warning { color: var(--color-gold-strong); }

/* Le code de classe se lit à voix haute, depuis le fond de la salle. */
.join-code {
	font-size: clamp(24px, 4vw, 34px);
	letter-spacing: .08em;
	color: var(--color-primary-active);
}

/* L'intégration — F1 à F3 */

/* Le cadre vit dans une page qui n'est pas la nôtre, souvent en 860 × 520.
 * Il ne défile pas de lui-même et ne réclame jamais la hauteur d'écran :
 * c'est l'hôte qui décide de sa taille. */
body.embed { min-height: 0; }

.embed-foot {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: var(--spacing-2);
	padding: var(--spacing-2) var(--spacing-4);
	background: var(--color-proj-surface);
	border-top: 1px solid var(--color-proj-line);
}

/* Le rappel de licence est discret par construction. C'est une relance, pas
 * un mur : un bandeau rouge dans le Genially d'un professeur ferait plus de
 * tort au réachat que l'oubli qu'il signale. */
.embed-note {
	font-family: var(--font-body-sm), system-ui, sans-serif;
	font-size: 13px;
	color: var(--color-proj-ink-muted);
}

a.embed-brand {
	margin-left: auto;
	font-family: var(--font-label), system-ui, sans-serif;
	font-weight: 600;
	font-size: 13px;
	color: var(--color-proj-ink-muted);
	text-decoration: none;
}

a.embed-brand:hover { color: var(--color-proj-accent); }

body.embed-notice { background: var(--color-surface); display: grid; grid-template-rows: 1fr auto; min-height: 100vh; }

/* Le message d'un cadre qui ne peut rien montrer : centré, sans autre décor. */
.embed-msg { align-self: center; max-width: 44rem; margin-inline: auto; padding: var(--spacing-4); text-align: center; display: grid; gap: var(--spacing-3); justify-items: center; }
.embed-msg .ico { font-size: 2.2rem; line-height: 1; }
.embed-msg h1 { font-family: var(--font-title-module), system-ui, sans-serif; font-size: clamp(20px, 3.2vh, 30px); margin: 0; }

/* El módulo del profe — C10 */

/* Une carte devient cliquable dans « Mes contenus ». Elle garde l'habit
 * d'une carte, donc elle en perd le soulignement — c'est le titre à
 * l'intérieur qui porte l'affordance, pas un trait sous toute la surface. */
a.surface-card { text-decoration: none; color: inherit; }

.format-hints { margin: var(--spacing-1) 0 0; padding-left: var(--spacing-4); }
.format-hints li { margin-top: 2px; }

/* L'aperçu porte le fond de projection, parce que c'est là que le contenu
 * vivra. Le montrer sur fond clair donnerait au professeur une idée fausse
 * du contraste, qui est la seule chose que la salle jugera. */
.authoring-preview {
	background: var(--color-proj-surface);
	/* Les couleurs de la salle, et non celles de l'écran autour : sans elles,
	 * le titre et les étiquettes héritaient de l'encre sombre de l'app, sur
	 * le fond sombre de la projection — invisibles (Killian, 6 oct. 2026). */
	color: var(--color-proj-ink);
	padding: 0;
	overflow: hidden;
}
/* L'aperçu tient dans la page : la hauteur d'un écran entier n'a pas de sens ici. */
.authoring-preview .proj-shell { min-height: 0; padding: var(--spacing-6); }

/* `width: 100%` avec un `max-height` déforme.
 *
 * La largeur est imposée, la hauteur est bornée : quand le rapport naturel de
 * l'image ne tient pas dans les deux, le navigateur l'écrase. Une photo prise
 * en portrait par un professeur arrivait aplatie sur trois mètres de mur.
 *
 * `object-fit: contain` rend le rapport : l'image tient dans la place qu'on
 * lui donne sans changer de forme. `height: auto` évite d'imposer la seconde
 * dimension tant qu'elle n'est pas nécessaire. */
.profe-image,
.profe-embed {
	display: block;
	width: 100%;
	height: auto;
	max-height: 46vh;
	object-fit: contain;
	border: 0;
	border-radius: var(--radius-md);
}

.profe-embed { aspect-ratio: 16 / 9; max-height: none; }
/* Une activité intégrée a besoin de place : sur téléphone, presque tout
 * l'écran ; et un bouton pour la passer en plein écran (Killian, 6 oct. 2026). */
.profe-embed-wrap { position: relative; width: 100%; }
.profe-plein { position: absolute; top: 8px; right: 8px; width: 40px; height: 40px; border-radius: 12px; display: grid; place-items: center; font-size: 22px; font-weight: 800; color: var(--color-proj-ink); background: color-mix( in srgb, var(--color-proj-surface) 80%, transparent ); border: 2px solid var(--color-proj-line); cursor: pointer; }
@supports not (color: color-mix(in srgb, red, blue)) { .profe-plein { background: rgba(36,28,46,0.80); } }
@media (max-width: 48rem) {
	.profe-embed { aspect-ratio: auto; height: 70vh; min-height: 420px; }
}

/* Le cadenas du sommaire — ce qui demande une licence se voit avant le clic */

.stamp-locked {
	position: absolute;
	top: var(--spacing-3);
	right: var(--spacing-3);
	font-size: 15px;
	line-height: 1;
}

/* La tuile reste cliquable et lisible : elle n'est pas désactivée, elle est
 * payante. La griser dirait « cassé » là où il faut dire « pas encore à vous ». */
.tile-gated { border-style: dashed; }
.tile-gated .tile-cta { color: var(--color-ink-muted); }

.chip-gated { border-style: dashed; }

/* La tilde, montrée du doigt.
 *
 * Ce qui s'oublie dans une copie n'est pas la syllabe tonique — elle
 * s'entend — mais le signe écrit, qui ne s'entend pas. Il est donc marqué
 * dans le mot lui-même, à la lettre près, et par deux moyens : la couleur
 * d'accent et un soulignement épais. À trois mètres et sur un
 * vidéoprojecteur délavé, la couleur seule ne dit rien. */
.tilde {
	font-style: normal;
	color: var(--color-proj-accent);
	text-decoration: underline;
	text-decoration-thickness: .12em;
	text-underline-offset: .12em;
}

/* L'accent tonique d'un mot qui n'en écrit pas.
 *
 * Le signe se pose au-dessus de la voyelle, comme un manuel de phonétique le
 * dessine, et non dans le texte : écrire « chocoláte » serait une faute
 * d'orthographe enseignée à trente élèves d'un coup. Ce mot ne porte pas de
 * tilde, il porte un accent tonique, et toute la leçon du module tient dans
 * cette différence.
 *
 * Le repère est décoratif — `aria-hidden` par construction, puisque produit
 * par la feuille : un lecteur d'écran lit le mot correctement orthographié,
 * ce qui est exactement ce qu'il doit lire. */
.tonic {
	font-style: normal;
	position: relative;
	color: var(--color-proj-accent);
}

.tonic::before {
	content: '´';
	position: absolute;
	left: 50%;
	top: -.42em;
	transform: translateX(-50%);
	font-size: 1.1em;
	line-height: 1;
	color: var(--color-proj-accent);
	pointer-events: none;
}

/* Le mot conserve sa place : sans marge haute, le signe déborderait sur la
 * ligne précédente — c'est-à-dire sur la découpe en syllabes. */
.acento-final { padding-top: .18em; }

/* La conclusion d'« El acento » : le mot réécrit avec sa tilde, en fin de
 * dévoilement. Plus grand qu'une ligne de réponse, plus petit que le mot du
 * haut — c'est un rappel, pas une seconde question. */
.acento-final { font-size: calc(clamp(34px, 10vh, 130px) * var(--proj-fit, 1)); line-height: 1; }

/* Le choix du temps, sous la roue. Des liens et non des boutons : le temps
 * fait partie de l'adresse, donc il se partage, se met en favori et revient
 * avec la flèche du navigateur. */
.tense-switch { gap: var(--spacing-2); margin-top: var(--spacing-3); }
.tense-switch .proj-btn { font-size: clamp(13px, 1.9vh, 20px); padding: var(--spacing-1) var(--spacing-3); }
.tense-switch .is-current { border-color: var(--color-proj-accent); color: var(--color-proj-accent); }

/* Les deux vitesses d'écoute du virelangue, sous la phrase. */
.listen-row { gap: var(--spacing-2); margin-top: var(--spacing-3); }
.listen-row .proj-btn { font-size: clamp(13px, 1.9vh, 20px); padding: var(--spacing-1) var(--spacing-3); }

/*
 * Días señalados — le nom de la fête, puis quand et comment on la vit.
 *
 * « Este domingo » passe devant le statut et prend l'accent : c'est ce qui
 * change d'un jour à l'autre, et ce que la classe doit lire en premier quand
 * la fête s'annonce avant d'arriver.
 */
.senalados-head { gap: var(--spacing-3); }
.senalados-chips { gap: var(--spacing-2); }
.senalados-chips .proj-chip { font-size: calc(clamp(14px, 2.2vh, 24px) * var(--proj-fit, 1)); }
.senalados-when { border-color: var(--color-proj-accent); color: var(--color-proj-accent); }
.senalados-word { display: flex; flex-direction: column; gap: var(--spacing-1); margin: var(--spacing-2) 0 0; }
.senalados-word .t-proj-a { font-size: calc(clamp(20px, 3.6vh, 40px) * var(--proj-fit, 1)); color: var(--color-proj-ink); }
.senalados-gloss { color: var(--color-proj-ink-muted); font-size: calc(clamp(14px, 2.2vh, 24px) * var(--proj-fit, 1)); }

/* L'illustration du pendu, révélée avec le verdict. Elle se range à sa suite,
 * dans la fin de partie, et se borne en hauteur : elle conclut, elle ne remplace pas la
 * potence que la classe vient de regarder se construire. */
.hang-image {
	max-height: clamp(6rem, 22vh, 16rem);
	width: auto;
	border-radius: var(--radius-md);
	justify-self: start;
}

/* ═══ La demande d'abonnement ════════════════════════════════════════════
 * Un mode de règlement porte une phrase d'explication : la pastille devient
 * une carte, bouton radio en tête, texte aligné à gauche sur deux lignes. */
.chip-choice {
	display: flex;
	align-items: flex-start;
	gap: var(--spacing-3);
	border-radius: var(--radius-md);
	padding: var(--spacing-3) var(--spacing-4);
	font-family: inherit;
	font-weight: 400;
}

.chip-choice input { margin-top: .3em; flex: none; }

/* Les champs d'une structure ne concernent pas un particulier. Masqués
 * seulement quand « à titre personnel » est coché : sans `:has()`, ils
 * restent visibles, et le formulaire reste juste. */
form:has( input[name="holder"][value="personal"]:checked ) :is( .subscription-org, .subscription-business ) { display: none; }
.subscription-postal { flex: 0 0 9rem; }

/* Ce qu'on demande à une structure dépend du pays, que le script pose en
 * `data-zone`. Le SIREN n'existe qu'en France ; le numéro de TVA n'a de sens
 * que dans l'Union ; hors de l'Union, on ne demande rien. Sans script, pas
 * d'attribut : tout s'affiche, et le serveur trie. */
form[data-zone="eu"] .subscription-ident,
form[data-zone="world"] :is( .subscription-ident, .subscription-vat ) { display: none; }
form:not( [data-zone="eu"] ) .subscription-vat-eu { display: none; }

/* Ce que contient le prix, sous la pastille : là où l'œil vient de lire le
 * montant. Un prix qui change de nature sans le dire ferait douter du reste. */
.price-note { font-size: 14px; color: var(--color-ink-muted); margin: 0; text-align: right; }

/* La porte vers le devis : une ligne sous le choix, pas une troisième
 * pastille. Ce n'est pas une autre façon d'être facturé, c'est un autre achat. */
.quote-door { font-size: 15px; margin: var(--spacing-1) 0 0; }
.quote-door a { font-weight: 700; color: var(--color-primary-active); }

.field-hint { font-size: 13px; color: var(--color-ink-muted); }
.field-req { color: var(--color-error-strong); text-transform: none; letter-spacing: 0; }

/* ═══ Créer une classe, une question à la fois ═══════════════════════════
 * Sans script, toutes les étapes s'affichent l'une sous l'autre et le
 * formulaire reste utilisable ; `.is-live` n'arrive qu'avec le script. */
.onboard-top { display: flex; align-items: center; gap: var(--spacing-3); margin-bottom: var(--spacing-6); }
.onboard-back { background: none; border: 0; padding: 0; color: var(--color-ink-muted); font: inherit; cursor: pointer; }
.onboard-back[hidden] { display: inline !important; visibility: hidden; }
.onboard-dots { display: flex; gap: 6px; flex: 1; }
.onboard-dots i { flex: 1; height: 6px; border-radius: var(--radius-full); background: var(--color-line); transition: background .2s; }
.onboard-dots i.is-on { background: var(--color-primary); }
.onboard:not( .is-live ) .onboard-top { display: none; }
.onboard.is-hero .onboard-top { visibility: hidden; }

.onboard-step { border: 0; margin: 0 0 var(--spacing-12); padding: 0; min-width: 0; }
.onboard.is-live .onboard-step { display: none; margin: 0; }
.onboard.is-live .onboard-step.is-current { display: block; }
.onboard-step legend { padding: 0; }

.onboard-hero { text-align: center; }
.onboard-emblem { display: inline-flex; align-items: center; justify-content: center; width: 88px; height: 88px;
	border-radius: 28px; background: var(--color-primary-soft); font-size: 44px; margin-bottom: var(--spacing-4); }
.onboard-hero .onboard-foot, .onboard-hero .onboard-pills { justify-content: center; }

.onboard-input { font-size: 20px; min-height: 56px; }
.onboard-foot { margin-top: var(--spacing-8); }

.onboard-card {
	display: flex; align-items: center; gap: var(--spacing-3);
	background: var(--color-surface-raised); border: 2px solid var(--color-line); border-radius: var(--radius-lg);
	padding: var(--spacing-3) var(--spacing-4); cursor: pointer; transition: border-color .15s;
}
.onboard-card:hover { border-color: var(--color-primary); }
/* Le bouton de la carte, et non n'importe quelle case qu'elle contient.
 *
 * `:has( input:checked )` descend dans tout le sous-arbre. Tant qu'une carte
 * ne portait qu'un bouton radio, cela revenait au même ; depuis que certaines
 * contiennent leurs propres réglages — les sept jours de la semaine, les sept
 * temps de la roue —, une seule case cochée à l'intérieur suffisait à allumer
 * la carte entière. Le professeur lisait donc deux choix sélectionnés là où il
 * n'en avait fait qu'un, et le vrai ne se distinguait plus du faux.
 *
 * `> input` n'accepte que l'enfant direct, qui est le bouton de la carte. */
.onboard-card:has( > input:checked ) { border-color: var(--color-primary); background: var(--color-primary-soft); }
.onboard-card:has( > input:focus-visible ) { outline: 3px solid var(--color-primary); outline-offset: 2px; }
.onboard-card input { accent-color: var(--color-primary); margin: 0; flex: none; }
.onboard-card.is-off { opacity: .5; cursor: default; }
.onboard-card.is-off:hover { border-color: var(--color-line); }
.onboard-grid { display: grid; grid-template-columns: repeat( auto-fit, minmax( 13rem, 1fr ) ); gap: var(--spacing-2); }

.onboard-code { display: inline-block; font-size: 30px; letter-spacing: .12em; padding: var(--spacing-3) var(--spacing-5);
	border: 2px dashed var(--color-primary); border-radius: var(--radius-lg); background: var(--color-surface-raised); }

/* ═══ Créer une classe : un panneau centré, une couleur par étape ═════════
 *
 * Le panneau reprend le langage de VocaDial Start : des halos de couleur dans
 * le fond, des pastilles pastel, une couleur par choix. Rien n'est en dur : les
 * couleurs viennent des jetons, et la couleur de l'étape (`--acc`) se pose sur
 * l'étape elle-même.
 *
 * `--acc-strong` est la couleur du bouton et des liens : l'accent mélangé à
 * l'encre, pour que le texte blanc reste lisible même sur l'orange ou le bleu
 * clair. La pastille garde, elle, la couleur franche.
 *
 * Les dérivées se déclarent sur chaque élément qui porte `--acc` : une
 * propriété personnalisée dérivée se calcule là où elle est écrite, pas là où
 * elle est lue. */
body.onboarding {
	background-repeat: no-repeat; background-attachment: fixed;
	background-image:
		radial-gradient( 56rem 26rem at 6% -4%, color-mix( in srgb, var(--color-primary) 16%, transparent ), transparent 72% ),
		radial-gradient( 46rem 24rem at 100% 2%, color-mix( in srgb, var(--color-lang-es) 14%, transparent ), transparent 72% ),
		radial-gradient( 60rem 30rem at 50% 104%, color-mix( in srgb, var(--color-family-expresion) 11%, transparent ), transparent 72% );
}
.onboard-stage { min-height: calc( 100dvh - 11rem ); display: flex; align-items: center; justify-content: center; padding-block: var(--spacing-6); }
.onboard-panel, .onboard-panel .onboard-step {
	--acc-strong: color-mix( in srgb, var(--acc, var(--color-primary)) 60%, var(--color-ink) );
	--acc-deep: color-mix( in srgb, var(--acc, var(--color-primary)) 40%, var(--color-ink) );
}
.onboard-panel {
	--acc: var(--color-primary);
	position: relative; width: 100%; max-width: 37rem; margin: 0; padding: clamp( 20px, 4.5vw, 36px ); text-align: center; overflow: hidden;
	background: var(--color-surface-raised); border: 2.5px solid var(--color-line); border-radius: 28px;
	box-shadow: 0 18px 44px -22px color-mix( in srgb, var(--acc, var(--color-primary)) 60%, transparent );
}
.onboard-panel::before {
	content: ""; position: absolute; inset: 0 0 auto 0; height: 11rem; pointer-events: none; transition: background .3s;
	background: radial-gradient( 26rem 10rem at 50% -35%, color-mix( in srgb, var(--acc, var(--color-primary)) 30%, transparent ), transparent 75% );
}
.onboard-panel > * { position: relative; }
.onboard-panel .onboard-top { margin-bottom: var(--spacing-5); text-align: left; }
.onboard-panel .onboard-dots i { height: 8px; }
.onboard-panel .onboard-dots i.is-on { background: var(--acc-strong, var(--color-primary)); }
.onboard-panel .onboard-dots i:nth-child( 1 ).is-on { background: var(--color-primary); }
.onboard-panel .onboard-dots i:nth-child( 2 ).is-on { background: var(--color-lang-en); }
.onboard-panel .onboard-dots i:nth-child( 3 ).is-on { background: var(--color-lang-es); }
.onboard-panel .onboard-dots i:nth-child( 4 ).is-on { background: var(--color-lang-fr); }
.onboard-panel .onboard-dots i:nth-child( 5 ).is-on { background: var(--color-family-expresion); }
.onboard-panel .btn-primary { background: var(--acc-strong, var(--color-primary)); box-shadow: 0 4px 0 var(--acc-deep, var(--color-primary-active)); color: var(--color-on-primary); }
.onboard-panel .onboard-foot { justify-content: center; }
.onboard-panel .onboard-input { text-align: center; }
.onboard-panel .row { justify-content: center; }
.onboard-panel .chip:hover { background: color-mix( in srgb, var(--acc, var(--color-primary)) 14%, var(--color-surface-raised) ); }
.onboard-panel .onboard-emblem, .onboard-tile {
	background: color-mix( in srgb, var(--acc, var(--color-primary)) 17%, var(--color-surface-raised) ); border: 2.5px solid color-mix( in srgb, var(--acc, var(--color-primary)) 35%, transparent );
}
.onboard-tile {
	display: grid; place-items: center; width: 68px; height: 68px; margin: 0 auto var(--spacing-3);
	border-radius: 24px; font-size: 34px; transform: rotate( -4deg );
}
.onboard-panel legend { display: block; width: 100%; }
.onboard-teaser { display: flex; flex-wrap: wrap; gap: var(--spacing-2); justify-content: center; margin-top: var(--spacing-4); }
.onboard-teaser span {
	display: inline-flex; gap: 6px; align-items: center; padding: 6px 14px; border-radius: var(--radius-full); font-weight: 800; font-size: 14.5px;
	background: color-mix( in srgb, var(--c, var(--color-primary)) 22%, var(--color-surface-raised) ); border: 2px solid color-mix( in srgb, var(--c, var(--color-primary)) 55%, transparent );
}

/* Cartes de choix : une couleur chacune, le rond de la case est remplacé par une pastille et un ✓. */
.onboard-panel .onboard-card { position: relative; text-align: left; border-width: 2.5px; border-radius: 18px; }
.onboard-panel .onboard-card:hover { border-color: var(--c, var(--acc, var(--color-primary))); }
.onboard-panel .onboard-card:has( > input:checked ) { border-color: var(--c, var(--acc, var(--color-primary))); background: color-mix( in srgb, var(--c, var(--acc, var(--color-primary)) ) 15%, var(--color-surface-raised) ); }
.onboard-panel .onboard-card.is-off:hover { border-color: var(--color-line); }
.onboard-pick > input { position: absolute; opacity: 0; pointer-events: none; }
.onboard-pick:has( > input:checked )::after {
	content: "✓"; position: absolute; right: 14px; top: 50%; transform: translateY( -50% ); display: grid; place-items: center;
	width: 26px; height: 26px; border-radius: 50%; background: var(--c, var(--acc, var(--color-primary))); color: var(--color-ink); font-weight: 800; font-size: 15px;
}
.onboard-pick .col { padding-right: 32px; min-width: 0; }
.onboard-badge {
	flex: none; display: grid; place-items: center; width: 46px; height: 46px; border-radius: 15px;
	background: var(--c, var(--color-primary)); color: var(--color-ink); font: 700 16px Fredoka, sans-serif;
}
.onboard-pick.is-off .onboard-badge { background: var(--color-line); }
.onboard-panel .onboard-grid { grid-template-columns: 1fr; }
.onboard-panel .niveau-repere { color: var(--color-ink-muted); font-weight: 700; }

/* Récapitulatif : deux lignes qui s'ouvrent. */
.onboard-recap { display: flex; flex-direction: column; gap: var(--spacing-2); margin-top: var(--spacing-5); text-align: left; }
.onboard-opt { border: 2.5px solid var(--color-line); border-radius: 18px; background: var(--color-surface-raised); }
.onboard-opt[open] { border-color: var(--acc, var(--color-primary)); }
.onboard-opt summary { display: flex; align-items: center; gap: var(--spacing-3); padding: var(--spacing-3) var(--spacing-4); cursor: pointer; list-style: none; }
.onboard-opt summary::-webkit-details-marker { display: none; }
.onboard-opt-ic {
	flex: none; display: grid; place-items: center; width: 40px; height: 40px; border-radius: 13px; font-size: 20px;
	background: color-mix( in srgb, var(--c, var(--color-primary)) 28%, var(--color-surface-raised) );
}
.onboard-opt-tx { flex: 1; min-width: 0; display: flex; flex-direction: column; line-height: 1.3; }
.onboard-opt-k { font-weight: 800; }
.onboard-opt-v { color: var(--color-ink-muted); font-weight: 700; font-size: 15px; }
.onboard-opt-go { flex: none; color: var(--acc-strong, var(--color-primary)); font-weight: 800; text-decoration: underline; text-underline-offset: 3px; }
.onboard-opt[open] .onboard-opt-go { display: none; }
.onboard-opt-body { display: flex; flex-direction: column; gap: var(--spacing-2); padding: 0 var(--spacing-4) var(--spacing-4); }

/* Classe prête. */
.onboard-panel .chip-color { background: color-mix( in srgb, var(--c, var(--color-primary)) 28%, var(--color-surface-raised) ); border-color: color-mix( in srgb, var(--c, var(--color-primary)) 60%, transparent ); font-weight: 800; }
.onboard-drive {
	margin: var(--spacing-6) auto 0; max-width: 30rem; padding: var(--spacing-3) var(--spacing-4); border-radius: 18px;
	background: var(--color-surface-sunken); border: 2px dashed var(--color-line-strong);
}
.onboard-drive a { color: var(--acc-strong, var(--color-primary)); font-weight: 800; text-decoration: underline; text-underline-offset: 3px; white-space: nowrap; }

/* ═══ Composer le rituel en quatre étapes ════════════════════════════════ */
.form-wide { max-width: 48rem; margin-inline: auto; }
/* La jauge est fixée en bas de l'écran, et non collante en haut : un parent
 * de la coquille coupe `position: sticky`, et c'est en bas que le pouce la
 * trouve sur un téléphone. Le formulaire garde de la place pour qu'elle ne
 * recouvre pas le dernier module. */
.compose-gauge {
	position: fixed; z-index: 20;
	left: 50%; transform: translateX( -50% );
	bottom: calc( env( safe-area-inset-bottom, 0px ) + var(--spacing-3) );
	width: min( 48rem, calc( 100% - 2 * var(--spacing-4) ) );
	display: flex; align-items: center; gap: var(--spacing-3);
	background: var(--color-surface-raised); border: 2px solid var(--color-ink); border-radius: var(--radius-lg);
	box-shadow: 0 4px 0 var(--color-ink);
	padding: var(--spacing-3) var(--spacing-4); font-size: 15px;
}
.compose-wizard.is-live { padding-bottom: calc( env( safe-area-inset-bottom, 0px ) + 6rem ); }
.onboard:not( .is-live ) .compose-gauge { display: none; }
/* La barre et son rouge sont partis avec la durée visée : il n'y a plus
 * d'objectif à dépasser, seulement un temps à lire. */
.compose-gauge-text { white-space: nowrap; font-weight: 600; }
.compose-module { align-items: flex-start; }
.compose-module input { margin-top: .3em; }
.compose-tag { font-size: 12px; border-radius: var(--radius-full); padding: 1px 9px; background: var(--color-surface-sunken); color: var(--color-ink-muted); }
/* L'état d'un module, que seul l'exploitant voit sur les cartes du catalogue. */
.compose-tag.is-etat { background: transparent; border: 1px dashed var(--color-line-strong); color: var(--color-ink-muted); }
.compose-tag.is-locked { background: #fdf0d6; color: #7a4f00; }
.compose-order { list-style: none; margin: var(--spacing-4) 0 0; padding: 0; }
.compose-row {
	display: flex; align-items: center; gap: var(--spacing-3); cursor: grab;
	background: var(--color-surface-raised); border: 2px solid var(--color-line); border-radius: var(--radius-md);
	padding: var(--spacing-2) var(--spacing-3); margin-bottom: var(--spacing-2);
}
.compose-row { user-select: none; }
.compose-row.is-dragging { cursor: grabbing; border-color: var(--color-primary); box-shadow: 0 6px 18px rgba( 59, 42, 36, .18 ); position: relative; z-index: 2; }
.compose-grip { flex: none; font-size: 20px; line-height: 1; color: var(--color-ink-faint); cursor: grab; touch-action: none; padding: 6px 2px; }
.compose-rank { width: 28px; height: 28px; flex: none; border-radius: var(--radius-sm); background: var(--color-primary-soft); color: var(--color-primary); display: flex; align-items: center; justify-content: center; font-weight: 600; }
.compose-row-name { flex: 1; font-weight: 600; }
.compose-row .compose-moves { display: flex; gap: 4px; }
.compose-row .compose-move { width: 36px; height: 36px; border: 1.5px solid var(--color-line); border-radius: var(--radius-sm); background: var(--color-surface-raised); color: var(--color-ink); cursor: pointer; }
/* Des pastilles qui passent à la ligne, et non une barre proportionnelle :
 * découpée en onze, la barre ne laissait à chaque module que quelques
 * lettres, rognées des deux côtés. */
.compose-timeline { display: flex; flex-wrap: wrap; gap: 6px; }
.compose-timeline span { display: inline-flex; align-items: baseline; gap: 6px; min-height: 32px; padding: 6px 10px; border-radius: var(--radius-sm);
	background: var(--color-primary-soft); color: var(--color-primary-active); font-size: 13px; line-height: 1.3; }
.compose-timeline small { font-size: 11px; opacity: .75; font-variant-numeric: tabular-nums; }

/* ═══ Mes classes ════════════════════════════════════════════════════════
 * Le bandeau du jour reprend la page d'éphéméride que projette le rituel. */
.today-hero {
	display: flex; align-items: center; gap: var(--spacing-4);
	background: var(--color-surface-raised); border: 2.5px solid var(--color-ink); border-radius: var(--radius-xl);
	box-shadow: 0 5px 0 var(--color-ink); padding: var(--spacing-4) var(--spacing-5);
}
.today-leaf {
	flex: none; width: 72px; height: 80px; border-radius: var(--radius-md); background: var(--color-lang-es); color: var(--color-ink);
	display: flex; flex-direction: column; align-items: center; justify-content: center; line-height: 1;
}
.today-leaf b { font-family: Fredoka; font-size: 32px; font-weight: 700; margin: 2px 0; }
.today-leaf small { font-size: 12px; font-weight: 600; letter-spacing: .02em; }
.today-ok { align-self: flex-start; font-size: 13px; border-radius: var(--radius-full); padding: 2px 10px;
	background: color-mix( in srgb, var(--color-success) 15%, transparent ); color: var(--color-success-strong); }
@supports not (color: color-mix(in srgb, red, blue)) { .today-ok { background: rgba(31,169,124,0.15); } }

.start-steps { list-style: none; margin: var(--spacing-3) 0 0; padding: 0; display: grid; gap: var(--spacing-2); }
.start-step {
	display: flex; align-items: center; gap: var(--spacing-3);
	background: var(--color-surface-raised); border: 2px solid var(--color-line); border-radius: var(--radius-lg);
	padding: var(--spacing-3) var(--spacing-4); opacity: .6;
}
.start-step.is-now { opacity: 1; border-color: var(--color-primary); }
.start-rank { flex: none; width: 36px; height: 36px; border-radius: var(--radius-md); background: var(--color-primary-soft); color: var(--color-primary);
	display: flex; align-items: center; justify-content: center; font-family: Fredoka; font-weight: 700; }

/* Des colonnes comptées, et non bornées. La borne de 22rem laissait deux cartes
 * et un grand vide à droite sur un ordinateur, et « + Nouvelle classe » au-delà
 * du bord des cartes (constaté le 5 octobre 2026). Trois colonnes qui
 * remplissent la largeur ; une classe seule garde la largeur d'une colonne. */
.class-cards { display: grid; grid-template-columns: repeat( 3, minmax( 0, 1fr ) ); gap: var(--spacing-4); margin-top: var(--spacing-3); }
@media (max-width: 60rem) { .class-cards { grid-template-columns: repeat( 2, minmax( 0, 1fr ) ); } }
@media (max-width: 35rem) { .class-cards { grid-template-columns: 1fr; } }
.class-card {
	background: var(--color-surface-raised); border: 2.5px solid var(--color-ink); border-radius: var(--radius-xl);
	box-shadow: 0 5px 0 var(--color-ink); overflow: hidden; display: flex; flex-direction: column;
}
.class-card-band { display: flex; justify-content: space-between; align-items: center; gap: var(--spacing-2);
	padding: var(--spacing-3) var(--spacing-4); color: var(--color-ink); text-decoration: none; }
.class-card-band .t-title-module { font-size: 20px; }
.class-tint-0 .class-card-band { background: #f7c9b8; }
.class-tint-1 .class-card-band { background: #cfe8d6; }
.class-tint-2 .class-card-band { background: #d9cffb; }
.class-tint-3 .class-card-band { background: #f8e2a6; }
.class-card-tag { flex: none; font-size: 12px; background: rgba( 255, 255, 255, .75 ); border-radius: var(--radius-full); padding: 2px 10px; }
.class-card-body { padding: var(--spacing-3) var(--spacing-4) var(--spacing-4); display: flex; flex-direction: column; gap: var(--spacing-2); flex: 1; }
.class-card-meta { display: flex; flex-wrap: wrap; gap: var(--spacing-3); }
.class-card-bars { display: flex; gap: 3px; }
.class-card-bars i { flex: 1; height: 6px; border-radius: var(--radius-full); background: var(--color-primary-soft); }
.class-card-actions { display: flex; gap: var(--spacing-2); margin-top: auto; padding-top: var(--spacing-2); }

.trial-note { display: flex; flex-wrap: wrap; align-items: center; gap: var(--spacing-2) var(--spacing-3);
	border: 1.5px dashed var(--color-line); border-radius: var(--radius-md); background: var(--color-surface-raised);
	padding: var(--spacing-2) var(--spacing-4); font-size: 14px; color: var(--color-ink-muted); }
.trial-note a { margin-left: auto; }
.items-end { align-items: flex-end; }

/* Un module de l'abonnement, en version d'essai : visible, pas cochable. */
.compose-module.is-locked { cursor: pointer; background: var(--color-surface); border-style: dashed; }
.compose-module.is-locked:hover { border-color: var(--color-gold); }
.compose-module.is-locked .t-title-module { color: var(--color-ink-muted); }

/* `margin: auto` rendu explicitement : la remise à zéro générale
 * (`* { margin: 0 }`) retirait au dialogue le centrage que le navigateur lui
 * donne, et la fenêtre se collait en haut à gauche. */
.upsell {
	margin: auto; max-height: calc( 100vh - 2 * var(--spacing-4) ); max-height: calc( 100dvh - 2 * var(--spacing-4) ); overflow: auto;
	width: min( 30rem, calc( 100% - 2 * var(--spacing-4) ) ); padding: var(--spacing-6);
	border: 2.5px solid var(--color-ink); border-radius: var(--radius-xl); box-shadow: 0 6px 0 var(--color-ink);
	background: var(--color-surface-raised); color: var(--color-ink); text-align: center;
}
.upsell::backdrop { background: rgba( 59, 42, 36, .45 ); }
.upsell-list { list-style: none; margin: var(--spacing-4) auto 0; padding: 0; display: inline-grid; gap: var(--spacing-1); text-align: left; }
.upsell .onboard-foot { justify-content: center; margin-top: var(--spacing-6); }

/* Le verrou de projection : la fenêtre « Projeter ici » posée sur la scène.
 * Elle reprend la carte de `.upsell` ; le fond s'assombrit davantage, pour
 * qu'on ne prenne pas la scène figée derrière pour une projection qui tourne. */
.stage-lock::backdrop { background: color-mix( in srgb, var(--color-proj-surface) 88%, transparent ); }
@supports not (color: color-mix(in srgb, red, blue)) { le fond s'assombrit davantage, pour
 * qu'on ne prenne pas la scène figée derrière pour une projection qui tourne. */
.stage-lock::backdrop { background: rgba(36,28,46,0.88); } }
.stage-lock .stage-lock-ico { margin: 0 0 var(--spacing-2); font-size: 40px; line-height: 1; }
.stage-lock .stage-lock-text { margin: var(--spacing-3) 0 0; font-weight: 600; }
.stage-lock .stage-lock-rule { margin: var(--spacing-2) 0 0; color: var(--color-ink-muted); }
.stage-lock .stage-lock-foot { display: grid; gap: var(--spacing-2); justify-items: center; margin-top: var(--spacing-6); }
.stage-lock .stage-lock-foot .btn-primary { width: 100%; }
.stage-lock .stage-lock-hint { margin: 0 0 var(--spacing-2); color: var(--color-ink-muted); }

/* Un rituel déjà composé : toutes les sections sur une page, un seul bouton. */
/* Dans une classe, le rituel suit la colonne de la page : il était dans une
 * colonne de 48rem centrée, décalée de l'intitulé « Réglages du rituel »
 * calé à gauche (Killian, 6 oct. 2026). Trois cartes par ligne au plus. */
/* La première composition, en étapes, se cale elle aussi à gauche, sous l'intitulé de la page. */
.compose-wizard { margin-inline: 0; max-width: none; }
/* Le bouton « Retour » est au-dessus de la barre, pas devant : la barre part du même bord que le titre. */
.compose-wizard .onboard-top { flex-direction: column; align-items: stretch; gap: var(--spacing-2); }
.compose-wizard .onboard-back { align-self: flex-start; }
/* La clôture suit la colonne de la page, comme la composition, au lieu de se centrer. */
.closure-col { max-width: 48rem; margin-inline: 0; }
.compose-wizard.is-page { max-width: none; margin-inline: 0; }
.compose-wizard.is-page .onboard-grid { grid-template-columns: repeat( auto-fit, minmax( max( 13rem, 30% ), 1fr ) ); }
.compose-wizard.is-page .compose-gauge { width: min( calc( 1000px - 2 * var(--spacing-4) ), calc( 100% - 2 * var(--spacing-4) ) ); }
.compose-wizard.is-page .onboard-step { display: block; margin-bottom: var(--spacing-10, 2.5rem); }
.compose-wizard.is-page .onboard-top,
.compose-wizard.is-page [data-vd-next],
.compose-wizard.is-page .onboard-step:not( :last-of-type ) .onboard-foot { display: none; }
.compose-wizard.is-page .onboard-step legend,
.compose-wizard.is-page .onboard-step > h2.t-headline-md { font-size: 20px; }

/* ═══ L'en-tête d'une classe, le même sur chacune de ses pages ═══════════ */
.class-head-back { font-size: 14px; color: var(--color-ink-muted); text-decoration: none; }
.class-head-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--spacing-4); margin-top: var(--spacing-4); }
.class-head-id { display: flex; flex-direction: column; gap: var(--spacing-3); }
.class-head-chips { display: flex; flex-wrap: wrap; gap: var(--spacing-2); }
.class-crumb { display: flex; flex-wrap: wrap; align-items: center; gap: var(--spacing-2); font-size: 14px; color: var(--color-ink-muted); }
.class-crumb a { color: inherit; text-decoration: none; }
.class-crumb a:hover { color: var(--color-primary); text-decoration: underline; }
.class-head-name { font-family: Fredoka; font-weight: 700; font-size: 30px; line-height: 1.15; margin: 0; }
.class-chip { padding: 4px 12px; }
.class-chip { font: inherit; font-size: 13px; background: var(--color-surface-raised); border: 1px solid var(--color-line); border-radius: var(--radius-full); padding: 2px 10px; color: var(--color-ink-muted); display: inline-flex; align-items: center; gap: 6px; }
.class-chip-code { font-family: "Space Mono", ui-monospace, monospace; color: var(--color-ink); cursor: pointer; }
.class-chip-code svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 2; }
.class-chip-code.is-copied { border-color: var(--color-success); color: var(--color-success-strong); }
.class-head-actions { display: flex; align-items: center; gap: var(--spacing-2); position: relative; }
.icon-btn {
	width: 46px; height: 46px; flex: none; display: inline-flex; align-items: center; justify-content: center; cursor: pointer;
	border: 2px solid var(--color-line); border-radius: var(--radius-md); background: var(--color-surface-raised); color: var(--color-ink);
	list-style: none;
}
.icon-btn::-webkit-details-marker { display: none; }
.icon-btn svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.icon-btn:hover, .icon-btn.is-current, .class-menu[open] > .icon-btn { border-color: var(--color-primary); color: var(--color-primary); }
.class-menu { position: relative; }
.class-menu-list {
	position: absolute; right: 0; top: calc( 100% + 8px ); z-index: 30; min-width: 16rem;
	background: var(--color-surface-raised); border: 2px solid var(--color-ink); border-radius: var(--radius-lg); box-shadow: 0 4px 0 var(--color-ink);
	padding: var(--spacing-1); display: flex; flex-direction: column;
}
.class-menu-list a { display: flex; align-items: center; gap: var(--spacing-3); padding: var(--spacing-2) var(--spacing-3); border-radius: var(--radius-md); color: var(--color-ink); text-decoration: none; }
.class-menu-icon { flex: none; width: 38px; height: 38px; border-radius: var(--radius-md); background: var(--color-primary-soft); color: var(--color-primary);
	display: inline-flex; align-items: center; justify-content: center; }
.class-menu-icon svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.class-menu-list a:hover, .class-menu-list a[aria-current="page"] { background: var(--color-primary-soft); }
.class-menu-list hr { border: 0; border-top: 1px solid var(--color-line); margin: var(--spacing-1) var(--spacing-2); }
/* « Passer en projection » : un bouton scindé. Le clic lance le cours ; le chevron déroule les accès directs. */
.split-btn { display: flex; }
.split-btn > .split-more { display: flex; position: static; }
.split-main { border-top-right-radius: 0; border-bottom-right-radius: 0; }
.split-chev {
	list-style: none; min-width: 46px; padding: 0 12px; display: inline-flex; align-items: center; justify-content: center;
	border-top-left-radius: 0; border-bottom-left-radius: 0; border-left: 2px solid rgba( 255, 255, 255, .45 );
}
.split-chev::-webkit-details-marker { display: none; }
.split-chev svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round; }
.split-list { min-width: 21rem; }
@media ( max-width: 47.99rem ) {
	.class-head .vd-plan-only { display: none; }
}
.page-head { margin-top: var(--spacing-8); padding-top: var(--spacing-6); border-top: 2px solid var(--color-line); }
/* ═══ Le bandeau de page : Modules, Mon Drive, Outils ══════════════════════
 *
 * Même bande que l'en-tête d'une classe — fond `surface-sunken`, filet pleine largeur
 * au bas — pour que les écrans d'une même entrée du bandeau se ressemblent. Dedans,
 * toujours dans cet ordre : le commutateur de vues (`.cat-seg`, s'il y en a un), le titre
 * et son introduction, puis la sous-navigation en onglets soulignés (`.band-nav`) avec,
 * à droite sur la même ligne, ce qui agit sur la liste (la recherche). Sous la bande,
 * sur le crème : les filtres et la liste.
 *
 * Les onglets de la sous-navigation naviguent ; les pastilles (`.lib-chip` hors de la
 * bande, `.cat-langs`) filtrent. Les deux se ressemblaient, on les confondait.
 *
 * Fond et filet sont des pseudo-éléments qui dépassent par un `box-shadow` rogné par
 * `clip-path` : aucun défilement horizontal, et rien n'est coupé sous la bande. */
.page-band { position: relative; isolation: isolate; z-index: 10; margin: 0 0 var(--spacing-6); padding: var(--spacing-6) 0 var(--spacing-6); }
.page-band:has( > .band-sub .band-nav ) { padding-bottom: 0; }
.page-band::before, .page-band::after { content: ""; position: absolute; left: 0; right: 0; clip-path: inset(0 -100vmax); }
.page-band::before { top: 0; bottom: 0; z-index: -1; background: var(--color-surface-sunken); box-shadow: 0 0 0 100vmax var(--color-surface-sunken); }
.page-band::after { bottom: 0; height: 2px; background: var(--color-line-strong); opacity: .55; box-shadow: 0 0 0 100vmax var(--color-line-strong); }
.page-band .cat-seg { margin: 0 0 var(--spacing-5); background: color-mix(in srgb, var(--color-ink) 7%, var(--color-surface-sunken)); }
.page-band .page-head, .page-band .mf-tete { margin: 0; padding: 0; border-top: 0; }
.band-sub { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 0 var(--spacing-5); margin-top: var(--spacing-4); }
.band-sub .dx-actions { flex: 0 1 28rem; min-width: min( 100%, 14rem ); margin: 0 0 var(--spacing-2); }
/* La recherche du Drive : à droite, centrée sur la hauteur de la bande (et non posée sur la ligne
 * des onglets, au bas). Le texte d'introduction lui laisse la place ; sur un téléphone elle reprend
 * sa place dans le flux, sous les onglets. */
.page-band .mf-intro { max-width: none; }
@media (min-width: 48rem) {
	.band-sub:not( .band-sub-recherche ) .dx-actions { position: absolute; right: 0; top: 50%; translate: 0 -50%; width: min( 26rem, 36% ); margin: 0; }
	.page-band:has( > .band-sub .dx-actions ) .mf-tete > div:first-child { max-width: min( 46rem, calc( 100% - min( 26rem, 36% ) - 4rem ) ); }
}
/* Les résultats d'une recherche : la barre est seule, au milieu de la bande, et plus large. */
.band-sub-recherche { justify-content: center; margin-top: var(--spacing-5); }
.band-sub-recherche .dx-actions { flex: 1 1 44rem; max-width: 44rem; margin: 0; }
.band-sub .dx-rech { flex: 1 1 auto; max-width: none; }
.page-band .band-nav { display: flex; flex-wrap: wrap; gap: 0 var(--spacing-5); margin: 0; padding: 0; border: 0; }
.page-band .band-nav .lib-chip {
	position: relative; z-index: 1; display: inline-flex; align-items: center; gap: 6px; min-height: 0; padding: 14px 2px 13px;
	border: 0; border-radius: 0; background: none; box-shadow: none; color: var(--color-ink-muted);
}
.page-band .band-nav .lib-chip:hover { color: var(--color-ink); }
.page-band .band-nav .lib-chip.is-on, .page-band .band-nav .lib-chip[aria-current="page"] { color: var(--color-ink); }
.page-band .band-nav .lib-chip.is-on::after, .page-band .band-nav .lib-chip[aria-current="page"]::after {
	content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 4px; border-radius: 4px 4px 0 0; background: var(--color-brand-corner);
}
.page-band .band-nav .lib-chip:focus-visible { outline: 3px solid var(--color-primary); outline-offset: 2px; }

/* L'en-tête d'une classe est une bande pleine largeur, teintée (`surface-sunken`) : les
 * pastilles et les boutons blancs y ressortent, et le contexte de la classe se lit comme un
 * bloc sous le bandeau blanc, au-dessus de la page crème. Le titre de la sous-page (`.page-head`)
 * repasse sur le fond crème, et le filet qui les sépare va d'un bord à l'autre ; sans titre, c'est
 * le bas de l'en-tête qui porte le filet.
 *
 * Le fond et le filet sont des pseudo-éléments qui dépassent par un `box-shadow` rogné
 * verticalement par `clip-path` : aucun défilement horizontal, ce que ferait `width: 100vw`.
 * Le rognage est sur le pseudo-élément et non sur l'en-tête, pour ne pas couper la roue des
 * réglages (`.class-menu-list`) qui s'ouvre en dessous. */
header.class-head.mt-6 { margin-top: 0; }
/* `z-index` : l'en-tête est un contexte d'empilement (`isolation`), et la roue des réglages qui s'y
 * ouvre (`.class-menu-list`, z-index 30) y est prisonnière. Sans `z-index` sur l'en-tête lui-même, les cartes
 * positionnées qui le suivent passaient par-dessus la roue. */
.class-head { position: relative; isolation: isolate; z-index: 30; padding-top: var(--spacing-6); margin-bottom: var(--spacing-6); }
.class-head::before, .class-head .page-head::before {
	content: ""; position: absolute; inset: 0; z-index: -1;
	background: var(--color-surface-sunken); box-shadow: 0 0 0 100vmax var(--color-surface-sunken); clip-path: inset(0 -100vmax);
}
.class-head .class-head-row { padding-bottom: var(--spacing-6); }
.class-head .page-head { position: relative; isolation: isolate; margin-top: 0; border-top: 0; }
.class-head .page-head::before { background: var(--color-surface); box-shadow: 0 0 0 100vmax var(--color-surface); }
.class-head .page-head::after,
.class-head:not( :has( .page-head ) )::after {
	content: ""; position: absolute; left: 0; right: 0; height: 2px; background: var(--color-line);
	box-shadow: 0 0 0 100vmax var(--color-line); clip-path: inset(0 -100vmax);
}
.class-head .page-head::after { top: 0; }
.class-head:not( :has( .page-head ) )::after { bottom: 0; }

/* Sur un téléphone, les commandes passent sous le nom, le bouton de
 * projection prend la largeur restante. */
@media ( max-width: 40rem ) {
	.class-head-actions { width: 100%; flex-wrap: wrap; }
	.class-head-actions .btn { flex: 1; }
	/* Le bouton porte une ombre pleine de 5 px : sans cet écart, la rangée d'icônes semble collée dessous. */
	.class-head-actions { row-gap: var(--spacing-4); }
	.class-head-actions .split-btn { flex: 1 1 100%; }
	.class-head-actions .split-chev { flex: none; }
	/* La roue des réglages est la dernière icône de la rangée, donc à gauche : un menu calé sur son bord
	 * droit sortait de l'écran. Il se cale sur la rangée entière, de bord à bord. */
	.class-head-actions { position: relative; }
	.class-head-actions > .class-menu:not( .split-btn ) { position: static; }
	.class-menu-list { left: 0; right: 0; min-width: 0; }
	.split-btn > .split-more > .split-list { left: 0; right: 0; min-width: 0; }
}

/* ═══ Les onglets du professeur, en bas de l'écran sur un téléphone ═════ */
.tabs .tab-icon { display: none; }

@media ( max-width: 40rem ) {
	body:has( .tabs-app ) { padding-bottom: calc( env( safe-area-inset-bottom, 0px ) + 72px ); }

	.tabs.tabs-app {
		position: fixed; left: 0; right: 0; bottom: 0; z-index: 40; max-width: none; margin: 0;
		display: flex; flex-wrap: nowrap; gap: 0;
		padding: var(--spacing-1) var(--spacing-2) calc( env( safe-area-inset-bottom, 0px ) + var(--spacing-2) );
		background: var(--color-surface-raised); border-top: 1.5px solid var(--color-line);
	}
	/*
	 * Un onglet tient sur une ligne, quoi qu'il arrive.
	 *
	 * Sans `nowrap`, le libellé le plus long passait à la ligne et la barre
	 * gagnait une ligne entière : les icônes des cinq onglets cessaient
	 * d'être à la même hauteur, sur la seule barre de l'application qu'on
	 * regarde sans la lire. La taille descend d'un point sur les appareils
	 * étroits plutôt que de couper un mot.
	 */
	.tabs.tabs-app a {
		flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 2px;
		padding: var(--spacing-1) 0; border-radius: var(--radius-md); font-size: 12px; background: none;
	}
	.tabs.tabs-app a > span:not( .tab-icon ):not( .tab-badge ) {
		max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
	}
	@media (max-width: 400px) { .tabs.tabs-app a { font-size: 11px; } }
	/*
	 * La pastille de l'onglet actif se dessine sur l'icône seule : un rembourrage
	 * de seize pixels la rendait plus large que le libellé qu'elle surmonte, et
	 * c'est lui qui décide de la largeur disponible.
	 */
	.tabs.tabs-app .tab-icon { display: inline-flex; padding: 3px 12px; border-radius: var(--radius-full); }
	.tabs.tabs-app .tab-icon svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
	.tabs.tabs-app a[aria-current="page"] { color: var(--color-primary); background: none; }
	.tabs.tabs-app a[aria-current="page"] .tab-icon { background: var(--color-primary-soft); }

	/* La jauge de composition remonte au-dessus de la barre. */
	body:has( .tabs-app ) .compose-gauge { bottom: calc( env( safe-area-inset-bottom, 0px ) + 80px ); }
	body:has( .tabs-app ) .compose-wizard.is-live { padding-bottom: calc( env( safe-area-inset-bottom, 0px ) + 10rem ); }
}

/* ═══ Le message d'un formulaire ═════════════════════════════════════════ */
.flash {
	display: flex; align-items: center; gap: var(--spacing-3);
	border: 2px solid; border-radius: var(--radius-lg); padding: var(--spacing-3) var(--spacing-4);
	font-size: 16px; font-weight: 600; line-height: 1.4;
}
.flash p { margin: 0; }
.flash-icon { flex: none; width: 30px; height: 30px; border-radius: var(--radius-full); display: inline-flex; align-items: center; justify-content: center; font-weight: 700; color: #fff; }
.flash.is-success { border-color: var(--color-success); background: color-mix( in srgb, var(--color-success) 12%, var(--color-surface-raised) ); color: var(--color-success-strong); }
@supports not (color: color-mix(in srgb, red, blue)) { .flash.is-success { background: rgb(228,245,239); } }
.flash.is-success .flash-icon { background: var(--color-success); }
.flash.is-warning { border-color: var(--color-gold); background: color-mix( in srgb, var(--color-gold) 14%, var(--color-surface-raised) ); color: var(--color-ink); }
@supports not (color: color-mix(in srgb, red, blue)) { .flash.is-warning { background: rgb(253,245,228); } }
.flash.is-warning .flash-icon { background: var(--color-gold); color: var(--color-ink); }

/* L'erreur avait ses jetons mais pas sa variante : un « adresse ou mot de
   passe incorrect » sortait donc sans couleur, dans un cadre neutre qu'on ne
   distingue pas d'une information. */
.flash.is-error { border-color: var(--color-error); background: color-mix( in srgb, var(--color-error) 12%, var(--color-surface-raised) ); color: var(--color-error-strong); }
@supports not (color: color-mix(in srgb, red, blue)) { /* L'erreur avait ses jetons mais pas sa variante : un « adresse ou mot de
   passe incorrect » sortait donc sans couleur, dans un cadre neutre qu'on ne
   distingue pas d'une information. */
.flash.is-error { background: rgb(253,236,235); } }
.flash.is-error .flash-icon { background: var(--color-error); }

/* Une information, pas un avertissement : quelque chose a été fait, et cela
 * marche. L'or est réservé à ce qui reste à faire — sans cette nuance, le
 * bandeau du réglage retenu se lirait comme une panne de plus. */
.flash.is-info { border-color: var(--color-primary); color: var(--color-ink);
  background: color-mix( in srgb, var(--color-primary) 9%, var(--color-surface-raised) ); }
@supports not (color: color-mix(in srgb, red, blue)) { /* Une information, pas un avertissement : quelque chose a été fait, et cela
 * marche. L'or est réservé à ce qui reste à faire — sans cette nuance, le
 * bandeau du réglage retenu se lirait comme une panne de plus. */
.flash.is-info { background: rgb(242,239,251); } }
.flash.is-info .flash-icon { background: var(--color-primary); color: var(--color-on-primary); }

/* Le lien qui fait passer d'un mode de connexion à l'autre. */
.login-switch { text-align: center; }
.login-switch a { color: var(--color-primary); font-weight: 600; }

/* Les écrans d'entrée — connexion, inscription.
 *
 * Ils ouvraient sur une colonne grise : titre, sous-titre gris, champs
 * empilés, bouton violet. C'est le reproche qu'avait reçu la première version
 * du centre d'aide, et le remède est le même — la bande que le produit porte
 * déjà, pas un ornement inventé pour l'occasion.
 *
 * L'aide est violette parce qu'on est dans l'application ; l'entrée est
 * orange parce qu'on n'y est pas encore. C'est la seule raison de la
 * différence, et elle vaut mieux qu'une variation décorative. */
.auth-hero { position: relative; overflow: hidden; text-align: center;
	padding: var(--spacing-8) var(--spacing-6) var(--spacing-6);
	border-radius: var(--radius-lg);
	background: linear-gradient( 165deg, var(--color-brand-paper) 0%, var(--color-surface-raised) 72% );
	border: 2px solid color-mix( in srgb, var(--color-brand-band) 34%, transparent ); }
@supports not (color: color-mix(in srgb, red, blue)) { l'entrée est
 * orange parce qu'on n'y est pas encore. C'est la seule raison de la
 * différence, et elle vaut mieux qu'une variation décorative. */
.auth-hero { border: 2px solid rgba(224,136,40,0.34); } }
.auth-band { position: absolute; inset: 0 0 auto; height: 7px;
	background: linear-gradient( 90deg, var(--color-brand-band), var(--color-brand-corner) ); }
.auth-hero h1 { margin: 0; }
.auth-hero p { margin: var(--spacing-2) auto 0; max-width: 28rem; color: var(--color-ink-muted); }

/* Les trois promesses, là où la décision se prend — et non en gris sous le
 * bouton, c'est-à-dire après le moment où elles servaient. */
.auth-pills { display: flex; flex-wrap: wrap; gap: var(--spacing-2);
	justify-content: center; margin-top: var(--spacing-4); }
.auth-pill { display: inline-flex; align-items: center; gap: 7px;
	font-size: 13.5px; font-weight: 700; color: var(--color-ink-muted);
	padding: 6px 13px; border-radius: 99px; background: var(--color-surface);
	border: 2px solid color-mix( in srgb, var(--color-brand-band) 30%, transparent ); }
@supports not (color: color-mix(in srgb, red, blue)) { .auth-pill { border: 2px solid rgba(224,136,40,0.30); } }
.auth-pill b { color: var(--color-success-strong); }

/* Les champs, coupés en cartes courtes. Même nombre de champs qu'avant :
 * une colonne de six se lit comme un dossier à remplir, deux cartes de deux
 * et trois se lisent comme deux gestes rapides. */
.auth-card { margin-top: var(--spacing-5); padding: var(--spacing-5);
	background: var(--color-surface-raised); border: 2px solid var(--color-line);
	border-radius: var(--radius-lg); }
.auth-step { display: flex; align-items: center; gap: var(--spacing-3);
	margin: 0 0 var(--spacing-4); font-family: var(--font-headline-md), inherit;
	font-weight: 700; font-size: 17px; color: var(--color-ink); }
.auth-n { flex: none; width: 26px; height: 26px; border-radius: 99px;
	display: grid; place-items: center; font-size: 14px;
	background: var(--color-primary); color: var(--color-on-primary); }

@media (max-width: 34rem) {
	.auth-hero { padding: var(--spacing-6) var(--spacing-4) var(--spacing-5); }
	.auth-card { padding: var(--spacing-4); }
}

/* Le sélecteur de langue du visiteur, à droite du bandeau. Discret : il se
 * cherche une fois, au premier passage. La langue courante se distingue par
 * un fond, pas par la seule couleur. */
.ui-langs { display: inline-flex; gap: 2px; margin-left: auto; }
.ui-lang { padding: var(--spacing-1) var(--spacing-2); border-radius: var(--radius-md); font-family: Fredoka; font-size: 13px; font-weight: 600; letter-spacing: .06em; color: var(--color-ink-muted); text-decoration: none; }
.ui-lang:hover { color: var(--color-primary); }
.ui-lang.is-current { background: var(--color-surface-sunken); color: var(--color-ink); }
.trial-note.is-active { border-style: solid; border-color: var(--color-success); }

/* ═══ L'échéancier de l'abonnement ═══════════════════════════════════════ */
.schedule { list-style: none; margin: var(--spacing-3) 0 0; padding: 0; display: grid; gap: var(--spacing-2); }
.schedule-row {
	display: flex; flex-wrap: wrap; align-items: center; gap: var(--spacing-2) var(--spacing-4);
	background: var(--color-surface-raised); border: 2px solid var(--color-line); border-radius: var(--radius-lg);
	padding: var(--spacing-3) var(--spacing-4);
}
.schedule-row.is-next { border-color: var(--color-primary); background: var(--color-primary-soft); }
.schedule-row.is-past { opacity: .75; }
.schedule-date { display: flex; flex-direction: column; min-width: 11rem; }
.schedule-period { flex: 1; }
.schedule-amount { font-family: Fredoka; font-weight: 700; white-space: nowrap; }

/* La pastille d'un onglet : ce qui attend. */
.tabs a { position: relative; }
.tab-badge {
	display: inline-flex; align-items: center; justify-content: center; min-width: 20px; height: 20px; padding: 0 6px; margin-left: 6px;
	border-radius: var(--radius-full); background: #d9442b; color: #fff; font-size: 12px; font-weight: 700; line-height: 1; vertical-align: 2px;
}
@media ( max-width: 40rem ) {
	.tabs.tabs-app .tab-badge { position: absolute; top: 0; left: calc( 50% + 8px ); margin: 0; }
}

/* ═══ Les caractères spéciaux, sous le champ de réponse ══════════════════
 * Des touches assez grandes pour le doigt (44 px), en rangée qui passe à la
 * ligne. Le focus reste dans le champ pendant la frappe. */
/* ═══ L'étagère à médailles ══════════════════════════════════════════════
 * Les grises restent visibles, avec leur avance : une collection dont on ne
 * voit que les cases pleines ne donne envie de rien. La barre dit où l'on en
 * est sans qu'on ait à lire le compte. */
.medal-grid { list-style: none; margin: var(--spacing-6) 0 0; padding: 0;
	display: grid; grid-template-columns: repeat( auto-fit, minmax( 9rem, 1fr ) ); gap: var(--spacing-3); }
.medal { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 2px;
	background: var(--color-surface-raised); border: 2px solid var(--color-line);
	border-radius: var(--radius-lg); padding: var(--spacing-4) var(--spacing-3); }
.medal-face { font-size: 34px; line-height: 1.1; filter: grayscale( 1 ); opacity: .45; }
.medal.is-earned { border-color: var(--color-gold); background: #fdf6e6; box-shadow: 0 3px 0 var(--color-gold-strong); }
.medal.is-earned .medal-face { filter: none; opacity: 1; }
.medal-name { font-family: var(--font-title-module), system-ui, sans-serif; font-size: 14px; line-height: 1.25; }
.medal.is-earned .medal-name { color: var(--color-gold-strong); }
.medal-note { font-size: 12px; color: var(--color-ink-muted); }
.medal-bar { width: 100%; height: 5px; border-radius: var(--radius-full); background: var(--color-surface-sunken);
	margin-top: var(--spacing-2); overflow: hidden; display: block; }
.medal-bar i { display: block; height: 100%; border-radius: var(--radius-full); background: var(--color-primary); }

/* ═══ Le calendrier de l'Avent ═══════════════════════════════════════════
 * Une case par jour du 1er au 24 décembre, dans l'espace élève : faite (son
 * dessin), à rattraper (pointillés), du jour (dorée), à venir (fermée). */
.avent { position: relative; overflow: hidden; border-radius: 22px; background: #173a2e; color: #fff7ea; padding: 30px 16px 16px;
	border: 2px solid #173a2e; box-shadow: 0 4px 0 #0e261d; }
.avent .guirlande { position: absolute; left: 0; right: 0; top: 0; height: 18px; display: flex; justify-content: space-around; }
.avent .guirlande::before { content: ""; position: absolute; left: 0; right: 0; top: 2px; height: 2px; background: #0e261d; }
.avent .guirlande i { width: 12px; height: 16px; border-radius: 0 0 50% 50%; margin-top: 2px; position: relative; }
.avent .guirlande i:nth-child(4n+1) { background: #e8724f; }
.avent .guirlande i:nth-child(4n+2) { background: #f5c26b; }
.avent .guirlande i:nth-child(4n+3) { background: #6ec3f0; }
.avent .guirlande i:nth-child(4n) { background: #f2f0e6; }
.avent-tete { display: flex; align-items: center; gap: 12px; }
.avent-tete img { width: 44px; height: 44px; flex: none; }
.avent-tag { font: 800 11px Nunito, sans-serif; letter-spacing: .1em; text-transform: uppercase; color: #f5c26b; }
.avent-titre { font: 700 21px/1.15 Fredoka, sans-serif; margin: 0; color: #fff7ea; }
.avent-sous { font: 600 13px Nunito, sans-serif; color: #bfe3d2; margin-top: 2px; }
.portes { display: grid; grid-template-columns: repeat( 6, minmax( 0, 1fr ) ); gap: 6px; margin-top: 14px; }
.porte { aspect-ratio: 1; border-radius: 10px; display: grid; place-items: center; font: 700 15px Fredoka, sans-serif; position: relative; text-decoration: none; }
.porte.is-faite { background: #fff7ea; color: #173a2e; }
.porte.is-faite img { width: 70%; height: 70%; }
.porte.is-ratee { background: #2a5a47; color: #fff7ea; border: 2px dashed #f5c26b; }
.porte.is-jour { background: #f5c26b; color: #173a2e; box-shadow: 0 3px 0 #c9902f; font-size: 18px; align-content: center; gap: 0; }
.porte.is-jour small { font: 800 8px Nunito, sans-serif; letter-spacing: .02em; text-transform: uppercase; white-space: nowrap; }
/* Cases étroites (téléphone) : le libellé « Aujourd'hui » ne tient pas ; la case jaune de la légende le dit, et le libellé reste lu par les lecteurs d'écran. */
.portes { container-type: inline-size; }
@container ( max-width: 440px ) {
	.porte.is-jour small { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset( 50% ); }
}
.porte.is-fermee { background: #22503f; color: #6f9c88; }
.avent-legende { display: flex; flex-wrap: wrap; gap: 6px 14px; margin-top: 12px; font: 700 12px Nunito, sans-serif; color: #bfe3d2; }
.avent-legende span::before { content: ""; display: inline-block; width: 10px; height: 10px; border-radius: 3px; margin-right: 6px; vertical-align: -1px; box-sizing: border-box; }
.avent-legende .l-jour::before { background: #f5c26b; }
.avent-legende .l-ratee::before { border: 2px dashed #f5c26b; }
.avent-legende .l-faite::before { background: #fff7ea; }
.avent-btn { display: block; margin-top: 14px; text-align: center; background: #f5c26b; color: #173a2e; border-radius: 14px; padding: 12px;
	font: 700 16px Fredoka, sans-serif; text-decoration: none; box-shadow: 0 3px 0 #c9902f; }
.avent-fini { margin: 14px 0 0; text-align: center; font: 700 14px Nunito, sans-serif; color: #bfe3d2; }
.carte-jour { border-radius: 22px; background: #fffaf2; border: 2px solid #173a2e; box-shadow: 0 4px 0 #173a2e; padding: 18px; text-align: center; }
.carte-jour .num { font: 800 12px Nunito, sans-serif; letter-spacing: .1em; text-transform: uppercase; color: #2e7d5b; }
.carte-jour > img { width: 120px; height: 120px; margin: 8px auto; display: block; }
.carte-q { font: 700 18px Fredoka, sans-serif; margin: 0; }
.carte-jour .choix { display: grid; gap: 8px; margin-top: 10px; }
.carte-jour .choix label { display: block; cursor: pointer; }
.carte-jour .choix input { position: absolute; opacity: 0; pointer-events: none; }
.carte-jour .choix span { display: block; border: 2px solid var(--color-line); border-radius: 14px; padding: 12px; font: 700 17px Nunito, sans-serif; background: #fff; }
.carte-jour .choix input:checked + span { border-color: var(--color-primary); background: #f0ecff; }
.carte-jour .choix input:focus-visible + span { outline: 3px solid var(--color-primary); outline-offset: 2px; }
.carte-jour .choix span.is-ok { border-color: #2e9e5b; background: #e8f6ee; }
.carte-verdict { margin: 12px 0 0; font: 700 16px Fredoka, sans-serif; color: #2e7d5b; }
.carte-jour .phrase { margin: 8px 0 0; font: 600 16px/1.45 Nunito, sans-serif; color: #3b2a24; }
.carte-jour .demain { margin: 12px 0 0; font: 700 13px Nunito, sans-serif; color: #7a6158; }

/* La médaille d'une édition limitée : pleine largeur, aux couleurs de la
 * fête. À gagner, son cercle est en pointillés ; gagnée, il est doré ; la
 * période passée, elle reste dans la collection, plus sobre. */
.medal-ed { grid-column: 1 / -1; position: relative; overflow: hidden; flex-direction: row; text-align: left; align-items: center; gap: 14px;
	background: #2b1d3a; border-color: #2b1d3a; color: #fff7ea; padding: 26px 16px 16px; }
.medal-ed .ed-picado { position: absolute; left: 8px; right: 8px; top: 0; display: flex; gap: 3px; }
.medal-ed .ed-picado i, .medal-toast .ed-picado i { height: 14px; }
.medal-ed .medal-face { filter: none; opacity: 1; width: 64px; height: 64px; flex: none; position: relative; }
.medal-ed .medal-face img { width: 64px; height: 64px; display: block; }
.medal-ed .medal-face::after { content: ""; position: absolute; inset: -6px; border-radius: 50%; border: 3px dashed rgba( 255, 247, 234, .35 ); }
.medal-ed-mots { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.medal-tag { font: 800 10.5px Nunito, sans-serif; letter-spacing: .1em; text-transform: uppercase; color: #f5c26b; }
.medal-ed .medal-name, .medal-ed.is-earned .medal-name { color: #fff7ea; font-size: 18px; }
.medal-ed .medal-note { color: #d8c7ea; font-size: 13px; }
.medal-ed.is-earned { background: #2b1d3a; border-color: var(--color-gold); box-shadow: 0 3px 0 var(--color-gold-strong); }
.medal-ed.is-earned .medal-face::after { border: 3px solid var(--color-gold); box-shadow: 0 0 0 3px rgba( 245, 194, 107, .25 ); }
.medal-ed.is-earned .medal-note { color: #f5c26b; font-weight: 800; }
.medal-ed.is-past { background: #fdf6e6; color: inherit; padding-top: 16px; }
.medal-ed.is-past .medal-name { color: var(--color-gold-strong); }
.medal-ed.is-past .medal-tag, .medal-ed.is-past .medal-note { color: var(--color-ink-muted); }
.medal-ed.is-past .medal-face::after { display: none; }
.medal-encore { padding: 12px 16px; border-radius: var(--radius-lg); border: 2px dashed var(--color-gold); background: var(--color-surface-raised); font-weight: 700; text-align: center; color: var(--color-ink); }
.medal-toast { display: flex; align-items: center; gap: 14px; padding: 26px 16px 16px; border-radius: var(--radius-lg); background: #2b1d3a; color: #fff7ea;
	position: relative; overflow: hidden; border: 2px solid var(--color-gold); box-shadow: 0 3px 0 var(--color-gold-strong); }
.medal-toast .ed-picado { position: absolute; left: 8px; right: 8px; top: 0; display: flex; gap: 3px; }
.medal-toast img { width: 56px; height: 56px; flex: none; }
.medal-toast div { display: flex; flex-direction: column; min-width: 0; }
.medal-toast span:not(.ed-picado) { color: #f5c26b; font-weight: 800; font-size: 13px; }
.medal-toast b { font: 700 18px Fredoka, sans-serif; }
.medal-toast small { color: #d8c7ea; font-weight: 700; font-size: 13px; }

/* ═══ Le mur, resserré ═══════════════════════════════════════════════════
 * Des carrés plutôt que des rectangles, et un filet doré plutôt qu'un fond :
 * une année entière tient ainsi sur un écran de téléphone sans que les
 * séances sans faute écrasent les autres. */
.wall { gap: 4px; grid-template-columns: repeat( auto-fill, minmax( 14px, 1fr ) ); }
.wall-cell { aspect-ratio: 1; }
.wall-key { width: 10px; height: 10px; border-radius: var(--radius-sm); flex: none; }

/* ═══ L'horloge de « La hora », en mode autonome ═════════════════════════
 * Les aiguilles sont tracées à leur place par le serveur : rien ici ne les
 * fait tourner, et l'horloge reste juste même sans cette feuille. */
.clock-face { display: block; width: min( 62vw, 13rem ); margin: 0 auto var(--spacing-2); }
.clock-face svg { display: block; width: 100%; height: auto; }
.clock-rim { fill: var(--color-surface-raised); stroke: var(--color-ink); stroke-width: 3.5; }
.clock-tick { stroke: var(--color-line-strong); stroke-width: 1.4; stroke-linecap: round; }
.clock-tick.is-quarter { stroke: var(--color-ink-muted); stroke-width: 2.6; }
.clock-hour { stroke: var(--color-ink); stroke-width: 5; stroke-linecap: round; }
.clock-minute { stroke: var(--color-primary); stroke-width: 3.4; stroke-linecap: round; }
.clock-pin { fill: var(--color-ink); }
.clock-city { text-align: center; margin: 0; }
/* Le filet, et il assume d'être discret : on retire la facilité de recopier
 * un nombre, pas la possibilité de vérifier ce qu'on lit. */
.clock-digital { text-align: center; margin: 0; font-family: "Space Mono", ui-monospace, monospace;
	font-weight: 700; font-size: 14px; color: var(--color-ink-faint); }

/* ═══ L'étiquette de « ¿Cuánto cuesta? », en mode autonome ═══════════════
 * Un prix hors contexte n'est qu'un nombre. Accroché à une étiquette, il
 * devient le prix de quelque chose — et c'est ce qu'on apprend à dire. */
.price-tag { position: relative; display: inline-flex; flex-direction: column; align-items: flex-start;
	background: var(--color-lang-es); color: var(--color-ink);
	border-radius: var(--radius-lg); padding: var(--spacing-3) var(--spacing-5) var(--spacing-3) var(--spacing-8);
	box-shadow: 0 4px 0 var(--color-brand-band); transform: rotate( -4deg ); margin: var(--spacing-2) 0 var(--spacing-4); }
.tile-media .cc-obj { gap: var(--spacing-3); flex-wrap: wrap; }
.tile-media .cc-pic { width: 96px; margin: 0; }
.tile-media .cc-obj .price-tag { margin: 0; }
.price-tag-eye { position: absolute; left: var(--spacing-3); top: 50%; transform: translateY( -50% );
	width: 14px; height: 14px; border-radius: var(--radius-full);
	background: var(--color-surface); box-shadow: inset 0 0 0 3px var(--color-brand-band); }
.price-tag-what { font-size: 11px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; opacity: .8; }
.price-tag-amount { font-family: Fredoka; font-weight: 700;
	font-size: 30px; line-height: 1.15; }

/* ═══ « Aujourd'hui dans l'histoire » ════════════════════════════════════
 * Le premier écran ne porte qu'un bouton, au milieu de rien : il n'y a
 * rien à lire par-dessus l'épaule du voisin, et toute la classe part du
 * même point. Le bouton est donc plus gros qu'ailleurs — c'est le seul
 * geste de l'écran. */
.efem-listen { align-items: center; justify-content: center; gap: var(--spacing-5); }
.proj-btn-lg { font-size: calc(clamp(18px, 2.6vh, 30px) * var(--proj-fit, 1));
	padding: .7em 1.4em; border-radius: var(--radius-full); }

/* Le texte sous la correction : entendu d'abord, lu ensuite. */
.efem-script { margin-top: var(--spacing-4); }

/* ═══ L'épingle du composeur ═════════════════════════════════════════════
 * Un module épinglé échappe au tirage. L'étoile est éteinte au repos et
 * pleine une fois posée : c'est un réglage qu'on relit d'un coup d'œil sur
 * une liste de huit lignes, pas une case à cocher qu'on déchiffre. */
.compose-pin { flex: none; background: none; border: 0; cursor: pointer; line-height: 1;
	font-size: 20px; padding: var(--spacing-2); border-radius: var(--radius-md);
	color: var(--color-line-strong); transition: color .15s ease, transform .15s ease; }
.compose-pin:hover { color: var(--color-ink-muted); }
.compose-pin[aria-pressed="true"] { color: var(--color-primary); transform: scale( 1.1 ); }
.compose-timeline .is-pinned { box-shadow: inset 0 0 0 2px var(--color-primary); }

/* ═══ Les propositions au tableau ════════════════════════════════════════
 * Le choix multiple appartient d'ordinaire au travail autonome. « La
 * especialidad del día » fait exception : devant une photo de plat, « d'où
 * vient-il ? » sans propositions n'est pas une question difficile, c'est une
 * question qu'on ne peut pas poser à une classe de quatrième.
 *
 * La lettre est ce qui compte le plus. À trois mètres, « la B » est ce
 * qu'une salle peut crier ensemble sans écorcher un mot qu'elle ne connaît
 * pas encore. */
.proj-choices { display: flex; flex-direction: column; gap: var(--spacing-2);
	margin: var(--spacing-3) 0; }
.proj-choice { display: flex; align-items: baseline; gap: var(--spacing-3);
	font-family: Fredoka; font-weight: 600;
	font-size: calc(clamp(18px, 3.4vh, 42px) * var(--proj-fit, 1)); line-height: 1.2;
	opacity: .85; transition: opacity .2s ease; }
.proj-choice b { flex: none; display: inline-flex; align-items: center; justify-content: center;
	width: 1.7em; height: 1.7em; border-radius: var(--radius-full);
	background: rgba(255,255,255,.12); font-size: .62em; }

/* La bonne réponse ne s'allume qu'une fois le voile levé : c'est le même
 * geste qui la dit, l'affiche et l'éclaire. */
.proj-main .col:has(.proj-veiled.revealed) .proj-choice { opacity: .35; }
.proj-main .col:has(.proj-veiled.revealed) .proj-choice.is-right { opacity: 1; }
.proj-main .col:has(.proj-veiled.revealed) .proj-choice.is-right b {
	background: var(--color-proj-accent); color: var(--color-proj-ink); }

/* ═══ « La especialidad del día » ════════════════════════════════════════
 * Le plat occupe le haut de l'écran, photo ou nom. Sans photo, le nom tient
 * la place qu'elle aurait prise : il est la question, il en a la taille. */
/* Le nom tient la place de la photo quand il n'y en a pas : au centre de sa
 * colonne en projection, au centre de la carte en autonome. */
.plate-name { text-align: center; margin: var(--spacing-4) 0; display: block; }
.plate-sheet { margin-top: var(--spacing-4); }

/* La liste d'ingrédients n'est pas une réponse d'affiche : c'est une
 * énumération de six mots. À la taille d'affiche elle tombait sur huit
 * lignes, avec une barre de défilement — sur un écran de projection, ce qui
 * passe sous la ligne de flottaison n'existe pas. */
.plate-with { max-width: 22ch; }

/* Le code de la liste ouvre la fiche de l'élève : il devient un lien, sans
 * en prendre l'apparence — une liste de codes soulignés se lirait mal. */
a.roster-who { text-decoration: none; color: inherit; border-radius: var(--radius-md); }
a.roster-who:hover .join-code { color: var(--color-primary); }

/* Les dix derniers jours, en petit, sous le code. Les cases sont plus
 * serrées que sur le mur de l'élève : elles servent à comparer trente lignes
 * d'un coup d'œil, pas à retrouver une date. */
.roster-wall { display: flex; gap: 3px; margin: var(--spacing-1) 0; }
.roster-wall .wall-cell { width: 11px; height: 11px; border-radius: 3px; }

/* ═══ Le questionnaire en plusieurs questions ════════════════════════════
 * Deux modules posent une suite de questions après un temps d'exposition :
 * les faits historiques après l'écoute, la spécialité du jour après la
 * photo. Trois groupes de propositions empilés sans repère se lisent comme
 * un seul long formulaire — l'élève perd le compte et valide en ayant sauté
 * la deuxième. D'où le numéro, et l'espace qui sépare les groupes.
 *
 * Les composants portent leur propre marge : une classe utilitaire posée
 * dans le PHP se ferait écraser par la première règle qui suit. */
.quiz-options { margin-top: var(--spacing-4); }
.quiz-ask { display: flex; align-items: baseline; gap: var(--spacing-3);
	margin-top: var(--spacing-6); }
.quiz-ask + .quiz-options { margin-top: var(--spacing-3); }
.quiz-rank { flex: none; display: inline-flex; align-items: center; justify-content: center;
	width: 1.6em; height: 1.6em; border-radius: var(--radius-full);
	background: var(--color-primary); color: var(--color-on-primary, #fff);
	font-size: .7em; font-weight: 700; }

/* ═══ « El tiempo » en mode autonome ═════════════════════════════════════
 * Deux variantes, deux allures. Celui qui entend reçoit un bouton et deux
 * champs ; celui qui n'entend pas reçoit l'icône et le degré, et reconnaît
 * le mot parmi quatre. L'icône est alors la question entière — elle a donc
 * la taille d'une question, pas celle d'une décoration de liste. */
.sky-card { display: flex; align-items: center; justify-content: center; gap: var(--spacing-4);
	padding: var(--spacing-4) 0; }
.sky-card svg { width: min( 34vw, 6.5rem ); height: auto; flex: none;
	fill: none; stroke: var(--color-primary); stroke-width: 1.6;
	stroke-linecap: round; stroke-linejoin: round; }
/* Portée à la carte, et non au mot-clé : `.sky-degrees` existe déjà, taillé
 * pour le tableau, en couleurs de projection. Une règle nue posée ici, huit
 * cents lignes plus bas et à specificité égale, l'aurait emporté partout. */
.sky-card .sky-degrees { font-family: Fredoka; font-weight: 700;
	font-size: 44px; line-height: 1; color: var(--color-ink); }

/* Le bouton qui fait parler la page. Il grossit un peu pendant qu'il parle :
 * une synthèse met parfois une seconde à démarrer, et sans ce signe l'élève
 * appuie une deuxième fois avant que la première phrase ne sorte. */
.say-button[data-vd-speaking] { transform: scale( 1.03 ); }
.say-button { transition: transform .18s ease; }

/* ═══ Le test de son ═════════════════════════════════════════════════════
 * Posé sous le parcours, et jamais au-dessus : ce qu'on vient faire ici,
 * c'est travailler. Les deux réponses ont le même poids visuel — « je
 * n'entends rien » n'est pas un aveu d'échec, c'est un réglage. */
.hear-card .row { gap: var(--spacing-3); margin-top: var(--spacing-4); }
.hear-card .btn { flex: 1 1 0; }

/* ═══ La bibliothèque du professeur ══════════════════════════════════════
 * Une liste dense, des filtres en pastilles, et une barre d'actions qui ne
 * paraît qu'une fois quelque chose coché : un bouton « Mettre à la
 * corbeille » toujours présent finit par être cliqué à vide. */
/* Le raccourci de l'accueil : un nom seul ne donne aucune raison d'y aller,
 * un compteur si. */
/* L'image déjà attachée à une fiche, en petit sous le champ. */
.authoring-thumb { max-width: 160px; max-height: 160px; border-radius: var(--radius-md);
	border: 2px solid var(--color-line); display: block; }

.lib-shortcut { display: flex; align-items: center; gap: var(--spacing-3); text-decoration: none; color: inherit;
	background: var(--color-surface-raised); border: 2px solid var(--color-line);
	border-radius: var(--radius-lg); padding: var(--spacing-3); }
.lib-shortcut:hover { border-color: var(--color-primary); }
.lib-shortcut-ico { flex: none; width: 44px; height: 44px; border-radius: var(--radius-md);
	background: var(--color-primary-soft); color: var(--color-primary-active); display: grid; place-items: center; }
.lib-shortcut-ico svg { width: 24px; height: 24px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.lib-shortcut-go { flex: none; font-family: var(--font-title-module), system-ui, sans-serif; font-weight: 600; font-size: 13px;
	color: var(--color-primary-active); border: 2px solid var(--color-line-strong); border-radius: var(--radius-full); padding: 5px 12px; }

.lib-filters { display: flex; flex-wrap: wrap; gap: var(--spacing-2); }
.lib-chip { display: inline-flex; align-items: center; gap: var(--spacing-2);
	font-family: var(--font-title-module), system-ui, sans-serif; font-weight: 600; font-size: 14px;
	border: 2px solid var(--color-line-strong); border-radius: var(--radius-full);
	padding: 5px 13px; background: var(--color-surface-raised); color: var(--color-ink); text-decoration: none; }
.lib-chip b { font-size: 12px; color: var(--color-ink-muted); font-weight: 600; }
.lib-chip.is-on { border-color: var(--color-primary); background: var(--color-primary-soft); color: var(--color-primary-active); }
.lib-chip.is-on b { color: var(--color-primary-active); }

.lib-bulk { position: sticky; top: var(--spacing-2); z-index: 20;
	display: flex; flex-wrap: wrap; align-items: center; gap: var(--spacing-2);
	background: var(--color-primary-soft); border: 2px solid var(--color-primary);
	border-radius: var(--radius-lg); padding: var(--spacing-2) var(--spacing-3); }
.lib-bulk-count { font-family: var(--font-title-module), system-ui, sans-serif; font-weight: 700;
	font-size: 14px; color: var(--color-primary-active); margin-right: auto; }
.lib-bulk-tag .field-input { width: 12rem; padding: 6px 10px; font-size: 14px; }
.btn.is-danger { color: var(--color-error-strong); }

.lib-list { list-style: none; margin: var(--spacing-4) 0 0; padding: 0; }
.lib-row { display: flex; align-items: flex-start; gap: var(--spacing-3);
	background: var(--color-surface-raised); border: 2px solid var(--color-line);
	border-radius: var(--radius-lg); padding: var(--spacing-3); margin-bottom: var(--spacing-2); }
.lib-row.is-pool { border-left: 6px solid var(--color-primary); }
.lib-row.is-dated { border-left: 6px solid var(--color-gold); }
.lib-row.is-draft { border-left: 6px solid var(--color-line-strong); }
.lib-row.is-trash { border-left: 6px solid var(--color-error); opacity: .72; }
.lib-pick { flex: none; padding-top: 2px; }
.lib-tags { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 5px; }
.lib-tags i { font-style: normal; font-size: 11px; background: var(--color-surface-sunken);
	border-radius: var(--radius-full); padding: 2px 8px; color: var(--color-ink-muted); }
.lib-state { flex: none; font-size: 12px; color: var(--color-ink-muted); white-space: nowrap; padding-top: 3px; }

/* ═══ Le rituel en chemin ════════════════════════════════════════════════
 * Un trait relie les pastilles, vert derrière soi, gris devant. C'est la
 * seule chose que la liste empilée ne savait pas dire : où l'on en est. */
/* La marge du haut est ici, et non sur une classe utilitaire.
 *
 * Le gabarit portait `mt-6`, mais `.mt-6` est déclaré huit cents lignes plus
 * haut : à spécificité égale, c'est le dernier qui gagne, et le `margin: 0`
 * de cette règle effaçait la marge sans rien dire. Le bouton « Jugar » se
 * retrouvait collé à la première pastille. Un composant qui remet ses marges
 * à zéro doit reposer les siennes, sans quoi il condamne silencieusement
 * l'utilitaire qu'on met dans son gabarit. */
.solo-path { list-style: none; margin: var(--spacing-6) 0 0; padding: 0; }
.solo-node { position: relative; }
.solo-node > a { display: flex; align-items: center; gap: var(--spacing-3);
	padding: var(--spacing-2) 0; text-decoration: none; color: inherit; }
.solo-node + .solo-node::before { content: ""; position: absolute; left: 25px; top: -10px;
	width: 4px; height: 20px; border-radius: 4px; background: var(--color-line-strong); }
.solo-node.is-done + .solo-node::before { background: var(--color-success); }

.solo-dot { position: relative; flex: none; width: 54px; height: 54px; border-radius: var(--radius-lg);
	display: grid; place-items: center; background: var(--color-surface-sunken);
	border: 2px solid var(--color-line-strong); }
.solo-dot svg, .solo-dot img { width: 28px; height: 28px; }
.solo-node.is-done .solo-dot { background: var(--color-success-soft); border-color: var(--color-success); }
.solo-node.is-now .solo-dot { background: var(--color-primary-soft); border-color: var(--color-primary);
	box-shadow: 0 0 0 5px var(--color-primary-soft); }
.solo-tick { position: absolute; right: -6px; bottom: -6px; width: 22px; height: 22px; border-radius: var(--radius-full);
	background: var(--color-success); color: var(--color-on-success); font-size: 12px; font-weight: 700;
	display: grid; place-items: center; border: 2px solid var(--color-surface); }

.solo-node b { display: block; }
.solo-score { flex: none; font-family: var(--font-title-module), system-ui, sans-serif; font-weight: 700;
	font-size: 13px; border-radius: var(--radius-full); padding: 4px 10px;
	background: var(--color-surface-sunken); color: var(--color-ink-muted); }
.solo-node.is-done .solo-score { background: var(--color-success-soft); color: var(--color-success-strong); }
.solo-node.is-now .solo-score { background: var(--color-primary-soft); color: var(--color-primary-active); }

/* ═══ Le bandeau et l'objectif de l'élève ════════════════════════════════
 * Trois nombres au plus, et une ligne d'arrivée visible avant l'effort.
 * L'anneau est un dégradé conique : il se redessine à toute taille et ne
 * coûte pas une requête. */
.solo-hud { display: flex; gap: var( --spacing-2 ); }
.solo-pill { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 1px;
	background: var( --color-surface-sunken ); border-radius: var( --radius-md ); padding: var( --spacing-2 ) var( --spacing-1 ); }
.solo-pill b { font-family: var( --font-title-module ), system-ui, sans-serif; font-weight: 700; font-size: 20px; line-height: 1.1; }
.solo-pill i { font-style: normal; font-size: 11px; color: var( --color-ink-muted ); text-transform: uppercase; letter-spacing: .04em; }
.solo-pill.is-flame b::before { content: "🔥 "; }
.solo-pill.is-coin b::before { content: "★ "; }
.solo-pill.is-coin b { color: var( --color-gold-strong ); }
.solo-pill.is-clean b { color: var( --color-success-strong ); }
.solo-pill.is-sheet b { color: var( --color-primary-active ); }
/* Quatre pastilles sur un téléphone : le libellé passe sur deux lignes
 * plutôt que de déborder. */
.solo-pill i { text-align: center; line-height: 1.25; }

.solo-goal { display: flex; align-items: center; gap: var( --spacing-4 );
	background: var( --color-surface-raised ); border: 1px solid var( --color-line );
	border-radius: var( --radius-lg ); padding: var( --spacing-3 ); }
.solo-goal.is-full { border-color: var( --color-success ); background: var( --color-success-soft ); }
.solo-ring { flex: none; width: 66px; height: 66px; border-radius: var( --radius-full ); display: grid; place-items: center;
	background: conic-gradient( var( --color-success ) 0 calc( var( --fill, 0% ) ), var( --color-surface-sunken ) calc( var( --fill, 0% ) ) 100% ); }
.solo-ring i { width: 52px; height: 52px; border-radius: var( --radius-full ); background: var( --color-surface-raised );
	display: grid; place-items: center; font-style: normal;
	font-family: var( --font-title-module ), system-ui, sans-serif; font-weight: 700; font-size: 15px; }
.solo-goal.is-full .solo-ring i { background: var( --color-success-soft ); }

/* ═══ Un champ à la fois ══════════════════════════════════════════════════
 * Les cartes sont toutes dans la page ; le script en replie huit sur neuf.
 * Sans lui, elles s'empilent — moins agréable, jamais bloquant. */
.solo-one-card + .solo-one-card { margin-top: var( --spacing-4 ); }
.solo-one-count { color: var( --color-ink-muted ); margin-bottom: var( --spacing-1 ); }
.solo-one-nav { align-items: center; }
.solo-one-nav [data-vd-one-back] { flex: none; }

/* La rangée porte son nom : sans lui, neuf touches de la taille d'un bouton
 * principal se lisaient comme un clavier incomplet, donc comme une consigne
 * — « tu n'as droit qu'à ces lettres ». Elle s'annonce, et s'efface. */
.keypad-strip > .t-eyebrow { color: var( --color-ink-muted ); margin-bottom: var( --spacing-2 ); }
.keypad { display: flex; flex-wrap: wrap; gap: var(--spacing-2); }
.keypad-key {
	min-width: 36px; height: 36px; padding: 0 var(--spacing-2);
	border: 1px solid var(--color-line); border-radius: var(--radius-md); background: var(--color-surface-sunken);
	font: inherit; font-size: 17px; font-weight: 500; color: var(--color-ink-muted); cursor: pointer;
}
.keypad-key:hover { border-color: var(--color-primary); color: var(--color-primary); }
.keypad-key:active { transform: translateY( 1px ); }

/* ═══ Vérifier ce poste ═══════════════════════════════════════════════════
 * Un voyant par essai. La couleur double un signe (✓ ! ✕) : l'état se lit
 * aussi sans distinguer les couleurs. */
.check-list { list-style: none; margin: var(--spacing-2) 0 0; padding: 0; }
.check-row { display: flex; gap: var(--spacing-3); align-items: flex-start; padding: var(--spacing-3) 0; border-top: 1px solid var(--color-line); }
.check-row:first-child { border-top: 0; }
.check-body { flex: 1; min-width: 0; }
.check-title { font-weight: 600; margin: 0; }
.check-body p + p { margin-top: 2px; }
.check-icon { flex: none; width: 28px; height: 28px; border-radius: var(--radius-full); display: inline-flex; align-items: center; justify-content: center;
	font-weight: 700; font-size: 15px; background: var(--color-surface-sunken); color: var(--color-ink-muted); }
.check-icon::before { content: "…"; }
[data-state="ok"] > .check-icon { background: var(--color-success); color: var(--color-on-success); }
[data-state="ok"] > .check-icon::before { content: "✓"; }
[data-state="warn"] > .check-icon { background: var(--color-gold); color: var(--color-ink); }
[data-state="warn"] > .check-icon::before { content: "!"; }
[data-state="fail"] > .check-icon { background: var(--color-error-strong); color: var(--color-on-error); }
[data-state="fail"] > .check-icon::before { content: "✕"; }
[data-state="ask"] > .check-icon { background: var(--color-primary-soft); color: var(--color-primary-active); }
[data-state="ask"] > .check-icon::before { content: "?"; }
[data-state="skip"] > .check-icon::before { content: "○"; }
[data-vd-heard][aria-pressed="true"] { border-color: var(--color-primary); background: var(--color-primary-soft); }
/* Le mode du son de ce poste, en tête de page : c'est la réponse que la page
 * donne, et tout le reste la justifie. Vert quand la synthèse vocale est là,
 * doré quand on se contente du mot du jour — une information, pas une panne. */
.sound-mode { display: flex; gap: var(--spacing-4); align-items: flex-start; padding: var(--spacing-5);
	border-radius: var(--radius-xl); background: var(--color-surface-raised); border: 2px solid var(--color-success); }
.sound-mode.is-fallback { border-color: var(--color-gold); }
.sound-mode-icon { flex: none; width: 44px; height: 44px; border-radius: var(--radius-full); display: grid; place-items: center; font-size: 22px;
	background: color-mix( in oklab, var(--color-success) 16%, var(--color-surface-raised) ); }
@supports not (color: color-mix(in srgb, red, blue)) { .sound-mode-icon { background: rgb(219,241,234); } }
.sound-mode.is-fallback .sound-mode-icon { background: color-mix( in oklab, var(--color-gold) 22%, var(--color-surface-raised) ); }
@supports not (color: color-mix(in srgb, red, blue)) { .sound-mode.is-fallback .sound-mode-icon { background: rgb(252,239,212); } }
.sound-mode p { margin: 0; }
.sound-mode-name { font-family: Fredoka; font-size: 22px; font-weight: 600; line-height: 1.2; }
.sound-mode-switch { background: none; border: 0; padding: 0; font: inherit; font-size: 14px; font-weight: 700;
	color: var(--color-primary-active); text-decoration: underline; cursor: pointer; text-align: left; }
.sound-mode-switch[hidden] { display: none; }

/* Le journal du poste : du texte brut, à copier tel quel dans un message. */
.device-journal-text { background: var(--color-surface-sunken); border-radius: var(--radius-lg); padding: var(--spacing-3) var(--spacing-4);
	font-family: "Space Mono", ui-monospace, monospace; font-size: 12.5px; line-height: 1.55; white-space: pre-wrap; overflow-wrap: anywhere; margin: var(--spacing-3) 0 0; }
.text-success { color: var(--color-success-strong); }
.text-error { color: var(--color-error-strong); }
/* La raison du réglage retenu, sous l'annonce : plus légère qu'elle, parce
 * qu'on la lit seulement si l'on se demande pourquoi. */
.device-hint-why { display: block; margin-top: 3px; font-size: 14px; font-weight: 500; color: var(--color-ink-muted); }

/* Le bandeau « Nouvel ordinateur ? » : une information, pas une alerte —
 * dans le contenu, sous les onglets, et d'un poids plus léger qu'une
 * notification d'action. */
.device-hint { display: flex; gap: var(--spacing-3); align-items: center; flex-wrap: wrap; font-size: 15px; font-weight: 500; border-width: 1.5px; }
.device-hint .flash-icon { width: 26px; height: 26px; font-size: 14px; }
.device-hint p { flex: 1 1 18rem; min-width: 0; }
.device-hint-later { background: none; border: 0; padding: var(--spacing-2); color: var(--color-ink-muted); font: inherit; font-size: 14px; text-decoration: underline; cursor: pointer; }
.device-hint-later:hover { color: var(--color-ink); }

/* La réparation d'une voix manquante.
 *
 * En pointillé, et non en carte pleine : ce n'est pas un huitième essai mais
 * ce qu'on fait du septième. Le trait discontinu dit « à faire », là où une
 * bordure pleine l'aurait rangé parmi les constats.
 *
 * Elle vit dans le corps de l'essai des voix, donc déjà en retrait : pas de
 * fond blanc, qui ferait une carte dans une carte. */
.fix-card { border: 1.5px dashed var(--color-line-strong); border-radius: var(--radius-lg);
  background: var(--color-surface); padding: var(--spacing-4); }
.fix-card[hidden] { display: none; }

/* Le système est deviné ; ces boutons servent à corriger la devinette.
 * Windows 10 et 11 sont indiscernables de l'extérieur. */
.fix-os { display: flex; flex-wrap: wrap; gap: 6px; }
.fix-tab { font: inherit; font-family: Fredoka; font-size: 13px; font-weight: 600; cursor: pointer;
  border: 1.5px solid var(--color-line-strong); border-radius: var(--radius-full);
  background: transparent; color: var(--color-ink-muted); padding: 4px 12px; }
.fix-tab[aria-selected="true"] { background: var(--color-ink); border-color: var(--color-ink); color: var(--color-surface); }

/* Numérotées, et la pastille plutôt que le chiffre nu : on suit ces cinq
 * lignes les yeux sur un autre écran, en revenant sans cesse à sa place. */
.fix-steps { list-style: none; counter-reset: fix-step; margin: var(--spacing-3) 0 0; padding: 0;
  display: flex; flex-direction: column; gap: 10px; }
.fix-steps li { counter-increment: fix-step; display: flex; gap: 10px; align-items: flex-start; font-size: 15px; }
.fix-steps li::before { content: counter(fix-step); flex: none; width: 22px; height: 22px; margin-top: 1px;
  border-radius: var(--radius-full); background: var(--color-ink); color: var(--color-surface);
  font-family: Fredoka; font-weight: 700; font-size: 13px;
  display: inline-flex; align-items: center; justify-content: center; }

/* L'avertissement qui compte plus que les cinq étapes : sans la case décochée,
 * Windows passe toute son interface en espagnol. */
.fix-warn { background: var(--color-surface-sunken); border-radius: var(--radius-md);
  padding: 10px 12px; font-size: 14px; margin-top: var(--spacing-3); }

/* « Reprenez ces étapes pour l'autre langue. » Elle se distingue de
 * l'avertissement : celui-ci met en garde, celle-là donne du travail en plus.
 * D'où le filet plutôt que l'aplat. */
.fix-more { border-left: 3px solid var(--color-ink); padding-left: var(--spacing-3);
  font-size: 15px; font-weight: 600; margin-top: var(--spacing-3); }
.fix-more[hidden] { display: none; }

.fix-handoff { display: flex; gap: var(--spacing-3); align-items: flex-start; font-size: 14px;
  background: var(--color-primary-soft); border-radius: var(--radius-md); padding: var(--spacing-3); }
.fix-handoff-icon { flex: none; width: 26px; height: 26px; border-radius: var(--radius-full);
  background: var(--color-primary); color: var(--color-on-primary);
  display: inline-flex; align-items: center; justify-content: center; font-size: 14px; }

@media print {
	/* La procédure seule, pour la déposer sur le bureau de la personne qui
	 * s'occupe de l'informatique. Le reste de la page — les autres essais, la
	 * recommandation, la navigation — ferait trois feuilles pour cinq lignes.
	 *
	 * La règle des coupons d'élèves cache toutes les cartes à l'impression :
	 * il faut la reprendre ici, sur la seule page où l'on imprime autre chose. */
	body.vd-print-fix .surface-card { display: block; }
	body.vd-print-fix { visibility: hidden; }
	body.vd-print-fix .fix-card, body.vd-print-fix .fix-card * { visibility: visible; }
	body.vd-print-fix .fix-card { position: absolute; left: 0; top: 0; width: 100%; border: 0; padding: 0; }
	body.vd-print-fix .fix-os, body.vd-print-fix .fix-actions { display: none; }
}

.voice-lines { list-style: none; margin: var(--spacing-2) 0 0; padding: 0; display: flex; flex-direction: column; gap: var(--spacing-2); }
.voice-line { display: flex; align-items: center; gap: var(--spacing-2); flex-wrap: wrap; font-size: 14px; }
.voice-text { flex: 1 1 16rem; min-width: 0; }
.voice-dot { flex: none; width: 12px; height: 12px; border-radius: var(--radius-full); background: var(--color-line-strong); }
.voice-line[data-state="ok"] .voice-dot { background: var(--color-success); }
.voice-line[data-state="warn"] .voice-dot { background: var(--color-gold); }
.voice-line[data-state="fail"] .voice-dot { background: var(--color-error-strong); }
.voice-line [hidden] { display: none; }

/* Le cadenas dans le flux, à côté du rang : il ne passe plus sous « Hecho ». */
.tile-rank { display: inline-flex; align-items: center; gap: var(--spacing-2); flex-wrap: wrap; }
.tile-lock { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; font-weight: 600; padding: 2px 8px; border-radius: var(--radius-full);
	background: var(--color-surface-sunken); color: var(--color-ink); }

/* Un lien discret en forme de bouton : visible, sans appeler au clic. */
.link-quiet { background: none; border: 0; padding: 0; font: inherit; font-size: 14px; color: var(--color-ink-muted); text-decoration: underline; cursor: pointer; }
.link-quiet:hover { color: var(--color-ink); }

/* ═══ Mot du jour : deuxième temps, les phrases ═══════════════════════════
 * Le mot s'efface, l'image devient vignette, les phrases prennent la largeur.
 * Les `!important` ne servent qu'à défaire le panneau flottant des paliers
 * de projection, sans en recopier chaque variante. */
.proj-shell[data-vd-phases].is-phase-2 .proj-main > .t-proj-q,
.proj-shell[data-vd-phases].is-phase-2 .proj-main > [data-vd-start] { display: none; }
.proj-shell[data-vd-phases].is-phase-2 .proj-media { flex: 0 0 clamp(7rem, 15%, 12rem) !important; align-self: flex-start !important; }
.proj-shell[data-vd-phases].is-phase-2 .proj-main { flex: 1 1 0 !important; min-width: 0; }
.proj-shell[data-vd-phases].is-phase-2 .proj-panel {
	position: static !important; width: auto !important; max-height: none !important; overflow: visible !important;
	background: none !important; backdrop-filter: none !important; border: 0 !important; box-shadow: none !important; padding: 0 !important;
	display: flex; flex-direction: column; gap: var(--spacing-4);
}
.proj-shell[data-vd-phases].is-phase-2 .proj-panel [data-row] .t-proj-a { font-size: calc(clamp(20px, 3.8vh, 42px) * var(--proj-fit, 1)); line-height: 1.25; }
/* La phrase dans la langue apprise, en tête et en grand ; les traductions dessous. */
.proj-shell[data-vd-phases].is-phase-2 .proj-panel > .t-eyebrow + [data-row] .t-proj-a { font-size: calc(clamp(28px, 6.2vh, 72px) * var(--proj-fit, 1)); font-weight: 600; }
.proj-shell[data-vd-phases].is-phase-2 .proj-panel > .t-eyebrow,
.proj-shell[data-vd-phases].is-phase-2 .proj-panel .proj-eyebrow-label { font-size: calc(clamp(14px, 2.2vh, 22px) * var(--proj-fit, 1)); }

/* Premier temps : le volet des phrases n'existe pas encore à l'écran, et la
 * scène reprend la place qu'il lui réservait. Ses lignes restent dans la
 * séquence de dévoilement : la première qui s'ouvre fait basculer la scène. */
.proj-shell[data-vd-phases]:not(.is-phase-2) .proj-panel { display: none !important; }
.proj-shell[data-vd-phases]:not(.is-phase-2) .proj-main > .t-proj-q,
.proj-shell[data-vd-phases]:not(.is-phase-2) .proj-main > [data-vd-start] { padding-right: 0 !important; }

/* Deuxième temps : chaque ligne part du bord gauche, « ¿Y tú? » comme les phrases. */
.proj-shell[data-vd-phases].is-phase-2 .proj-panel [data-row] { justify-content: flex-start; text-align: left; align-items: baseline; gap: var(--spacing-3); }
.proj-shell[data-vd-phases].is-phase-2 .proj-panel [data-row]:last-child { margin-top: var(--spacing-4); }
.proj-shell[data-vd-phases].is-phase-2 .proj-panel [data-row]:last-child .t-eyebrow { font-size: calc(clamp(14px, 2.2vh, 22px) * var(--proj-fit, 1)); flex: none; }

/* Deuxième temps, à la taille d'une salle : les phrases occupent la hauteur
 * libérée par le mot, centrées, et se lisent du fond. */
.proj-shell[data-vd-phases].is-phase-2 .proj-main { justify-content: center; align-self: stretch; }
.proj-shell[data-vd-phases].is-phase-2 .proj-media { flex-basis: clamp(9rem, 20%, 17rem) !important; align-self: center !important; }
.proj-shell[data-vd-phases].is-phase-2 .proj-panel { gap: clamp(12px, 2.6vh, 32px); }
.proj-shell[data-vd-phases].is-phase-2 .proj-panel [data-row] { justify-content: flex-start !important; margin-left: 0 !important; padding-left: 0 !important; }
.proj-shell[data-vd-phases].is-phase-2 .proj-panel > .t-eyebrow + [data-row] .t-proj-a { font-size: calc(clamp(40px, 9vh, 112px) * var(--proj-fit, 1)); line-height: 1.12; }
.proj-shell[data-vd-phases].is-phase-2 .proj-panel [data-row] .t-proj-a { font-size: calc(clamp(28px, 5.6vh, 66px) * var(--proj-fit, 1)); }
.proj-shell[data-vd-phases].is-phase-2 .proj-panel .lang-tag { transform: scale(1.35); transform-origin: left center; margin-right: var(--spacing-3); }
.proj-shell[data-vd-phases].is-phase-2 .proj-panel [data-row]:last-child { margin-top: clamp(12px, 3vh, 40px); }
.proj-shell[data-vd-phases].is-phase-2 .proj-panel [data-row]:last-child .t-eyebrow { font-size: calc(clamp(16px, 2.6vh, 28px) * var(--proj-fit, 1)); }
.proj-shell[data-vd-phases].is-phase-2 .proj-panel > .t-eyebrow { font-size: calc(clamp(16px, 2.6vh, 28px) * var(--proj-fit, 1)); }

/* Le bulletin complet du temps : sous la carte, pleine largeur, à une taille
 * qui tient en trois lignes sans faire défiler quoi que ce soit. */
.tiempo-bulletin { display: block; font-size: calc(clamp(18px, 3vh, 34px) * var(--proj-fit, 1)); line-height: 1.3; max-width: 60ch; }

/* ═══ Les scènes à carte ══════════════════════════════════════════════════
 * La carte se dimensionne sur la hauteur qui lui reste : tout ce qu'on prend
 * au-dessus d'elle, elle le perd en largeur — et les étiquettes, mesurées en
 * fractions de sa largeur, deviennent illisibles. La question passe donc au
 * second plan, les marges se resserrent, et le panneau d'aide se fait moins
 * large. C'est la carte qui doit occuper l'écran. */
body.projection .proj-body.has-map { --proj-panel: 17rem; margin-top: var(--spacing-3) !important; }
body.projection .proj-body.has-map .proj-main { gap: var(--spacing-2); }
body.projection .proj-body.has-map .proj-main > .t-proj-q,
body.projection .proj-body.has-map .proj-main > .proj-ask > .t-proj-q { font-size: calc(clamp(22px, 3.6vh, 44px) * var(--proj-fit, 1)); }

/* La consigne à côté de la question, plus petite et plus pâle : on la lit
 * quand on cherche quoi faire, et la classe regarde la question. */
.proj-ask { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--spacing-1) var(--spacing-4); }
.proj-ask > .t-proj-q { margin: 0; }
.proj-hint { margin: 0; font-family: Fredoka; font-weight: 500; font-size: calc(clamp(15px, 2.2vh, 22px) * var(--proj-fit, 1)); color: var(--color-proj-ink-muted); }
body.projection .proj-shell.has-map .proj-head { margin-bottom: 0; }

/*
 * La carte prend toute la largeur ; l'aide passe dessous.
 *
 * Le panneau d'aide flottait en haut à droite de la scène, et la carte ne
 * savait pas quoi en faire. Passer dessous cachait l'Europe et l'Afrique
 * derrière la liste des tournures ; se ranger à côté la réduisait à la
 * largeur restante, avec tout le bas de l'écran vide. Poser le panneau sur
 * une zone sans ville — la Russie, la Chine — ne tenait pas non plus : onze
 * tournures font près de quatre cent cinquante pixels de haut, et les villes
 * du jour changent.
 *
 * Dans une scène à carte, le panneau quitte donc le coin et s'aligne en
 * bandeau sous la carte, dans la place qui était vide. La carte ne partage
 * plus rien : aucune ville ne peut être couverte, quelles que soient celles
 * du jour, et les tournures se trouvent toujours au même endroit.
 */
@media (min-width: 60rem) {
	body.projection .proj-body.has-map .proj-main > [data-vd-start],
	body.projection .proj-body.has-map .proj-main > .t-proj-q {
		padding-right: 0;
	}

	body.projection .proj-body.has-map .proj-panel {
		position: static;
		width: auto;
		max-height: none;
		overflow: visible;
		background: none;
		backdrop-filter: none;
		border: 0;
		border-top: 2px solid var(--color-proj-line);
		border-radius: 0;
		padding: var(--spacing-2) 0 0;
		margin-top: var(--spacing-2);
		display: flex;
		flex-wrap: wrap;
		align-items: baseline;
		gap: var(--spacing-2) var(--spacing-4);
	}

	body.projection .proj-body.has-map .proj-panel .word-bank {
		margin: 0;
		display: flex;
		align-items: baseline;
		gap: var(--spacing-3);
		flex: 1 1 40rem;
	}

	body.projection .proj-body.has-map .proj-panel .bank-chips { margin: 0; }

	/* Le titre des tournures sur sa propre ligne, les tournures dessous :
	 * serré à côté d'elles, il se cassait en morceaux. */
	body.projection .proj-body.has-map .proj-panel .word-bank { display: block; }
	body.projection .proj-body.has-map .proj-panel .word-bank > .t-eyebrow { display: block; white-space: nowrap; margin-bottom: var(--spacing-2); }
	body.projection .proj-body.has-map .proj-panel .bank-chip { white-space: nowrap; }

	/* La source des données reste lisible, mais en bout de ligne. */
	body.projection .proj-body.has-map .proj-panel .proj-credit { margin: 0; flex-basis: 100%; text-align: right; }
}

/*
 * La carte tient dans sa place, sans jamais déborder.
 *
 * Elle se dimensionnait sur la hauteur seule, la largeur découlant du rapport
 * d'aspect : sur un écran peu large pour sa hauteur, elle dépassait à droite.
 * La ligne qui la porte devient un conteneur de taille, et la carte prend la
 * plus petite des deux mesures — toute la largeur, ou celle que permet toute
 * la hauteur. Le rapport d'aspect, dont dépend la place de chaque ville, est
 * tenu.
 *
 * Au-dessus du seuil de la carte seulement : en dessous, c'est une liste.
 */
@media (min-width: 64rem) {
	body.projection .proj-body.has-map .proj-main > [data-vd-start] > .proj-row {
		container-type: size;
		justify-content: center;
	}

	body.projection .proj-row > .geo-map {
		height: auto;
		width: min( 100cqw, calc( 100cqh * var( --geo-ratio, 1000 / 395 ) ) );
		flex: none;
		margin-inline: auto;
	}
}


/* ------------------------------------------------------------------
 * Los colores
 * ------------------------------------------------------------------
 *
 * La pastille *est* la question : elle occupe la place qu'occupe ailleurs le
 * texte de l'énoncé. Mesurée en hauteur de fenêtre comme tout ce qui se
 * projette — calibrée en largeur, elle plafonnerait sur un vidéoprojecteur
 * large et laisserait la moitié du mur vide.
 *
 * Le contour intérieur n'est pas décoratif. Le blanc du corpus est un blanc
 * cassé sur un fond clair, et le noir un noir sur fond sombre en projection :
 * sans liseré, deux des couleurs que le module doit enseigner deviennent
 * invisibles, et l'exercice devient « devine la couleur du papier ». */
.col-zones > .proj-zone {
	align-items: center;
	justify-content: center;
	text-align: center;
	gap: var(--spacing-4);
	min-width: 0;
	padding: var(--spacing-5) var(--spacing-4);
	min-height: 100%;
}

.col-swatch {
	display: block;
	background: var(--col-tint, var(--color-line));
	border-radius: var(--radius-xl);
	box-shadow: inset 0 0 0 2px rgb(0 0 0 / 20%);
	width: calc(min(46vw, 560px) * var(--proj-fit, 1));
	height: calc(min(30vh, 34vw, 340px) * var(--proj-fit, 1));
	max-width: 100%;
}

/* L'objet sous la pastille est une question, pas une réponse : il se lit à la
 * taille d'un énoncé, et non à celle de ce qu'on va dévoiler. */
/* L'objet à décrire portait la classe de la question de scène. C'est la
 * même taille, mais ce n'est pas la même intention : un style qui dit
 * « voici la question » ne doit pas dire aussi « voici un objet ». */
.col-subject {
	line-height: 1.15;
	max-width: 100%;
	overflow-wrap: anywhere;
	font-size: calc(clamp(18px, 3.6vh, 44px) * var(--proj-fit, 1));
	font-weight: var(--font-weight-projection-question, 700);
}

.col-zones .proj-answer { font-size: calc(clamp(24px, 5.2vh, 68px) * var(--proj-fit, 1)); }

/* Sur le téléphone, la pastille tient dans la carte de la question. Une bande
 * large et basse, et non un carré : c'est une surface colorée qu'on regarde,
 * pas une vignette à identifier. */
.col-swatch-solo {
	width: 100%;
	height: 7rem;
	border-radius: var(--radius-lg);
	box-shadow: inset 0 0 0 1px rgb(0 0 0 / 18%);
}

.col-swatch-chip {
	width: 1.5rem;
	height: 1.5rem;
	border-radius: var(--radius-sm);
	box-shadow: inset 0 0 0 1px rgb(0 0 0 / 18%);
}

/* L'objet remplace la pastille (0.102). Les parties `t` prennent la couleur
 * du jour ; le reste du dessin (vitres, roues, semelle) garde la sienne, pour
 * qu'on reconnaisse l'objet sans qu'il porte deux couleurs à nommer. Le halo
 * clair le détache du fond de scène, noir compris — sans lui, un livre noir
 * disparaissait dans la projection. */
.col-pic { display: flex; justify-content: center; align-items: flex-end; max-width: 100%; }
.col-obj {
	display: block;
	overflow: visible;
	width: calc(min(30vw, 400px) * var(--proj-fit, 1));
	height: calc(min(28vh, 30vw, 300px) * var(--proj-fit, 1));
	filter: drop-shadow(0 0 1.5px rgb(255 255 255 / 70%)) drop-shadow(0 6px 10px rgb(0 0 0 / 25%));
}
.col-pic.is-pl .col-obj { width: calc(min(17vw, 230px) * var(--proj-fit, 1)); height: calc(min(18vh, 20vw, 180px) * var(--proj-fit, 1)); margin: 0 -1.2%; }
.col-pic.is-pl .col-obj:nth-child(2) { transform: translateY(-8%) scale(1.06); }
.col-zones.is-duo { grid-template-columns: 1fr 1fr; }
.col-zones.is-duo .col-obj { width: calc(min(22vw, 300px) * var(--proj-fit, 1)); height: calc(min(24vh, 22vw, 240px) * var(--proj-fit, 1)); }
.col-zones.is-duo .col-pic.is-pl .col-obj { width: calc(min(10vw, 140px) * var(--proj-fit, 1)); height: calc(min(16vh, 14vw, 150px) * var(--proj-fit, 1)); }
.col-zones [data-vd-zone-body] { align-items: center; justify-content: center; text-align: center; max-width: 100%; box-sizing: border-box; }
.col-obj .t { fill: var(--col-tint, var(--color-line)); stroke: rgb(0 0 0 / 40%); stroke-width: 2.5; stroke-linejoin: round; }
.col-obj .s { fill: rgb(0 0 0 / 16%); }
.col-obj .u { fill: rgb(255 255 255 / 28%); }
.col-obj .w { fill: rgb(235 244 250 / 92%); stroke: rgb(0 0 0 / 30%); stroke-width: 1.5; }
.col-obj .p { fill: #f4f1ea; stroke: rgb(0 0 0 / 35%); stroke-width: 2; }
.col-obj .r { fill: #3a3640; }
.col-obj .h { fill: #c9c9cf; stroke: rgb(0 0 0 / 30%); stroke-width: 1.5; }
.col-obj .k { fill: #d9b54a; stroke: rgb(0 0 0 / 35%); stroke-width: 1.5; }
.col-obj .l { fill: none; stroke: rgb(0 0 0 / 45%); stroke-width: 3; stroke-linecap: round; }
.col-obj .f { fill: none; stroke: rgb(0 0 0 / 22%); stroke-width: 2; stroke-linecap: round; }
.col-obj .g { fill: none; stroke: #3a3640; stroke-width: 3; stroke-linecap: round; }
.col-obj .g1 { fill: none; stroke: rgb(0 0 0 / 55%); stroke-width: 1.6; }
.col-obj .ts { fill: none; stroke: var(--col-tint, var(--color-line)); stroke-linecap: round; stroke-linejoin: round; }
.col-obj .to { fill: none; stroke: rgb(0 0 0 / 40%); stroke-linecap: round; stroke-linejoin: round; }

/* Entre les deux phrases justes, « o » : petit, c'est un lien et non une réponse. */
.col-or { display: block; margin: var(--spacing-1) 0; font-size: calc(clamp(16px, 3vh, 36px) * var(--proj-fit, 1)); font-weight: 700; opacity: .7; }

/* La terminaison qui s'accorde : c'est elle que la séance enseigne. */
.col-fin { color: var(--color-gold); font-weight: inherit; text-decoration: underline; text-decoration-thickness: .08em; text-underline-offset: .12em; }

/* Sur le téléphone de l'élève : l'objet dans la carte de la question. */
.col-pic-solo { padding: var(--spacing-3) 0; border-radius: var(--radius-lg); background: var(--color-surface-sunken); }
.col-pic-solo .col-obj { width: 60%; height: 8.5rem; filter: drop-shadow(0 3px 6px rgb(0 0 0 / 18%)); }
.col-pic-solo.is-pl .col-obj { width: 30%; height: 6rem; margin: 0 -2%; }

@media (max-width: 48rem) {
	/* Sur un téléphone, le duo s'empile : deux colonnes de 170 px ne portent pas une phrase. */
	.col-zones.is-duo { grid-template-columns: 1fr; }
	.col-zones.is-duo .proj-answer { font-size: clamp(20px, 6.4vw, 28px); }
	.col-obj { width: 52vw; height: 30vw; }
	.col-pic.is-pl .col-obj { width: 24vw; height: 20vw; }
	.col-zones.is-duo .col-obj { width: 36vw; height: 22vw; }
	.col-zones.is-duo .col-pic.is-pl .col-obj { width: 20vw; height: 16vw; }
	.col-pic-solo .col-obj { width: 60%; height: 8.5rem; }
	.col-pic-solo.is-pl .col-obj { width: 30%; height: 6rem; }
}

/* Le tableau des formes, après la correction. Trois colonnes : la couleur, ce
 * qu'elle donne au singulier, ce qu'elle donne au pluriel. Les deux genres
 * partagent une case quand ils ne se distinguent pas — « verde · verde »
 * enseignerait une différence qui n'existe pas. */
.col-table { width: 100%; border-collapse: collapse; margin-top: var(--spacing-5); }
.col-table caption { text-align: left; padding-bottom: var(--spacing-2); color: var(--color-ink-muted); }
.col-table th,
.col-table td { text-align: left; padding: var(--spacing-2); border-bottom: 1px solid var(--color-line); }
.col-table th { color: var(--color-ink-muted); font-weight: 500; }
.col-table td:first-child { width: 2.5rem; }


/* ------------------------------------------------------------------
 * Saludos y cortesía
 * ------------------------------------------------------------------
 *
 * Deux écrans, une question et une réponse chacun : une écoute (qui parle à
 * qui, la réplique qui manque, deux saluts), puis « Ahora tú ».
 * La question de chaque écran est écrite dans l'écran lui-même, en grand :
 * celle de la scène, commune aux deux, ne s'affiche pas. */
.proj-shell[data-vd-module="saludos"] .proj-main > .t-proj-q { display: none; }

/* La consigne n'est qu'un repère d'arrivée : elle s'efface au premier
 * dévoilement, et l'écran, centré, ne lui garde pas de bande. Elle flotte en
 * haut à droite, loin de la scène, qui est au centre. */
body.projection .proj-shell[data-vd-module="saludos"] .proj-main.has-panel > [data-vd-start] { padding-right: 0; }

.proj-row > .sal-screen { flex: 1 1 auto; }
.sal-screen { display: flex; flex-direction: column; gap: var(--spacing-5); width: 100%; min-width: 0; }
/* La question de l'écran, à la taille de la question de scène. */
.sal-ask { margin: 0; font-family: Fredoka; font-size: calc(clamp(30px, min(7.2vh, 7.5vw), 86px) * var(--proj-fit, 1)); font-weight: 700; line-height: 1.05; letter-spacing: -.02em; }
@media (max-width: 63.9375rem) { .sal-ask { font-size: clamp(22px, 6vw, 34px); } }

.sal-stage {
	flex: 1 1 auto;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: var(--spacing-5);
	text-align: center;
	min-width: 0;
}

/* Le voile d'une réponse se centre sous ce qu'il complète. */
.sal-stage > [data-vd-veil] { align-items: center; text-align: center; }

/* « Ahora tú » : les pictogrammes de la situation, puis sa phrase. */
.sal-big {
	font-family: Fredoka, sans-serif;
	font-weight: 700;
	font-size: calc(clamp(56px, 16vh, 170px) * var(--proj-fit, 1));
	line-height: 1;
}
.sal-faces { font-size: calc(clamp(70px, 22vh, 230px) * var(--proj-fit, 1)); line-height: 1; white-space: nowrap; }
.sal-stage > .sal-big.sal-faces { font-size: calc(clamp(60px, 18vh, 190px) * var(--proj-fit, 1)); }
.sal-context {
	margin: 0;
	max-width: 60rem;
	font-family: Fredoka, sans-serif;
	font-weight: 600;
	font-size: calc(clamp(20px, 4vh, 46px) * var(--proj-fit, 1));
	line-height: 1.2;
	text-align: center;
}

/* Les formules justes : une carte par forme, son étiquette (registre ou
 * niveau) à droite. Sous le voile, elles n'existent pas encore : la place est
 * gardée, rien ne se devine. */
.sal-forms { display: flex; flex-direction: column; gap: var(--spacing-3); width: 100%; max-width: 60rem; }
.sal-form {
	display: flex;
	align-items: center;
	justify-content: space-between;
	flex-wrap: wrap;
	gap: var(--spacing-4);
	padding: var(--spacing-3) var(--spacing-5);
	border: 3px solid var(--color-proj-line);
	border-radius: var(--radius-xl);
	background: rgba(255, 255, 255, .045);
}
.sal-form-say {
	min-width: 0;
	font-family: Fredoka, sans-serif;
	font-weight: 700;
	font-size: calc(clamp(22px, 4.6vh, 54px) * var(--proj-fit, 1));
	line-height: 1.1;
	text-align: left;
	overflow-wrap: anywhere;
}
.sal-tag {
	padding: .3em .8em;
	border-radius: var(--radius-full);
	background: color-mix(in srgb, var(--color-proj-accent) 22%, transparent);
	color: var(--color-proj-accent);
	font: 800 calc(clamp(12px, 1.9vh, 20px) * var(--proj-fit, 1)) Nunito, sans-serif;
	letter-spacing: .04em;
	text-transform: uppercase;
	white-space: nowrap;
}
@supports not (color: color-mix(in srgb, red, blue)) { .sal-tag { background: rgba(255,196,107,0.22); } }
.sal-allok { display: block; margin: var(--spacing-3) 0 0; font-size: calc(clamp(14px, 2.4vh, 26px) * var(--proj-fit, 1)); color: var(--color-proj-ink-muted); text-align: center; }
/* La réplique qui manque : les formes se rangent en puces, côte à côte. */
.sal-forms.is-chips { flex-direction: row; flex-wrap: wrap; justify-content: center; }
.sal-forms.is-chips .sal-form { padding: var(--spacing-2) var(--spacing-4); }
.sal-forms.is-chips .sal-form-say { font-size: calc(clamp(18px, 3.4vh, 40px) * var(--proj-fit, 1)); }

/* L'écoute : le bouton, deux questions, puis le dialogue. */
.sal-player { display: flex; align-items: center; gap: var(--spacing-5); max-width: 100%; }
.sal-play {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: none;
	width: 2.2em;
	height: 2.2em;
	border: 0;
	border-radius: var(--radius-full);
	background: var(--color-proj-accent);
	color: var(--color-proj-surface);
	font-size: calc(clamp(34px, 8vh, 84px) * var(--proj-fit, 1));
	cursor: pointer;
}
.sal-play[hidden] + .sal-wave { display: none; }
.sal-play:focus-visible { outline: 3px solid var(--color-proj-ink); outline-offset: 3px; }
.sal-wave { display: flex; align-items: center; gap: 6px; height: 3.2em; min-width: 0; overflow: hidden; }
.sal-wave i { display: block; flex: none; width: 8px; border-radius: 4px; background: var(--color-proj-accent); opacity: .7; }

.sal-qs {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: var(--spacing-6);
	width: 100%;
	max-width: 60rem;
	text-align: left;
}
.sal-q { display: flex; flex-direction: column; gap: var(--spacing-2); min-width: 0; }
.sal-q b { font-family: Fredoka, sans-serif; font-size: calc(clamp(18px, 3.6vh, 40px) * var(--proj-fit, 1)); }
.sal-opts { display: flex; flex-wrap: wrap; gap: var(--spacing-2); }
.sal-opt {
	padding: .25em .7em;
	border: 2px solid var(--color-proj-line);
	border-radius: var(--radius-lg);
	font-family: Fredoka, sans-serif;
	font-weight: 600;
	font-size: calc(clamp(16px, 3.2vh, 34px) * var(--proj-fit, 1));
	transition: opacity .2s ease, border-color .2s ease;
}
/* Les bonnes réponses s'allument quand le dialogue se dévoile : le même geste
 * les dit, les montre et les éclaire (comme les propositions de la
 * spécialité). */
.sal-listen:has([data-vd-veil].revealed) .sal-opt { opacity: .55; }
.sal-listen:has([data-vd-veil].revealed) .sal-opt.is-right {
	opacity: 1;
	border-color: var(--color-proj-accent);
	background: color-mix(in srgb, var(--color-proj-accent) 20%, transparent);
}
@supports not (color: color-mix(in srgb, red, blue)) { .sal-listen:has([data-vd-veil].revealed) .sal-opt.is-right { background: rgba(255,196,107,0.20); } }
/* Le dialogue ne se devine pas sous une barre : il n'existe pas tant qu'il
 * n'est pas dévoilé, mais sa place est gardée. */
.sal-listen > [data-vd-veil].proj-veiled,
.sal-dos > [data-vd-veil].proj-veiled { visibility: hidden; }
.sal-listen > [data-vd-veil] { width: 100%; max-width: 60rem; }
.sal-script {
	display: flex;
	flex-direction: column;
	gap: .3em;
	width: 100%;
	padding-left: var(--spacing-4);
	border-left: 4px solid var(--color-proj-accent);
	text-align: left;
	font-family: Fredoka, sans-serif;
	font-weight: 600;
	font-size: calc(clamp(18px, 3.8vh, 42px) * var(--proj-fit, 1));
}
.sal-script mark,
.sal-take-txt mark {
	padding: 0 .15em;
	border-radius: var(--radius-sm);
	background: color-mix(in srgb, var(--color-gold) 45%, transparent);
	color: inherit;
}
@supports not (color: color-mix(in srgb, red, blue)) { .sal-script mark,
.sal-take-txt mark { background: rgba(242,182,60,0.45); } }

/* La réplique qui manque : un échange en bulles, la dernière vide, à droite. */
.sal-chat { display: flex; flex-direction: column; gap: var(--spacing-3); width: 100%; max-width: 36rem; margin-inline: auto; text-align: left; }
.sal-msg {
	align-self: flex-start;
	max-width: 85%;
	padding: .45em .9em;
	border: 3px solid var(--color-proj-line);
	border-radius: 22px 22px 22px 6px;
	background: rgba(255, 255, 255, .08);
	font-family: Fredoka, sans-serif;
	font-weight: 600;
	font-size: calc(clamp(22px, 4.4vh, 50px) * var(--proj-fit, 1));
	line-height: 1.2;
	text-align: left;
}
.sal-msg.b { align-self: flex-end; border-color: color-mix(in srgb, var(--color-proj-accent) 60%, transparent); border-radius: 22px 22px 6px 22px; }
@supports not (color: color-mix(in srgb, red, blue)) { .sal-msg.b { border-color: rgba(255,196,107,0.60); } }
.sal-msg .who { display: block; margin-bottom: .15em; font: 800 .45em Nunito, sans-serif; letter-spacing: .06em; text-transform: uppercase; color: var(--color-proj-ink-muted); }
.sal-msg.is-empty { min-width: 6em; border-style: dashed; color: var(--color-proj-accent); text-align: center; }

/* Deux saluts : deux enregistrements côte à côte ; le bon s'allume quand
 * le texte paraît. */
.sal-pair { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--spacing-5); width: 100%; max-width: 60rem; }
.sal-take {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: var(--spacing-3);
	min-width: 0;
	padding: var(--spacing-5);
	border: 3px solid var(--color-proj-line);
	border-radius: var(--radius-xl);
	background: rgba(255, 255, 255, .045);
	transition: opacity .2s ease, border-color .2s ease;
}
.sal-take-l { font-family: Fredoka, sans-serif; font-weight: 700; font-size: calc(clamp(30px, 6vh, 70px) * var(--proj-fit, 1)); line-height: 1; }
.sal-take .sal-wave { height: 2.4em; }
.sal-take .sal-wave i:nth-child(n+11) { display: none; }
.sal-take-txt { visibility: hidden; font-family: Fredoka, sans-serif; font-weight: 600; font-size: calc(clamp(16px, 3vh, 34px) * var(--proj-fit, 1)); text-align: center; }
.sal-dos:has(.revealed) .sal-take-txt { visibility: visible; }
.sal-dos:has(.revealed) .sal-take { opacity: .55; }
.sal-dos:has(.revealed) .sal-take.is-right { opacity: 1; border-color: var(--color-proj-accent); }

@media (max-width: 63.9375rem) {
	/* Sur un téléphone, la hauteur ne mesure plus rien : les tailles suivent
	 * la largeur, pour que la scène tienne sans défiler de côté. */
	.sal-big { font-size: clamp(48px, 18vw, 96px); }
	.sal-faces, .sal-stage > .sal-big.sal-faces { font-size: clamp(56px, 20vw, 110px); }
	.sal-context { font-size: clamp(18px, 5vw, 24px); }
	.sal-allok { font-size: clamp(14px, 4vw, 18px); }
	.sal-form-say { font-size: clamp(20px, 6vw, 30px); }
	.sal-forms.is-chips { flex-direction: column; align-items: stretch; }
	.sal-forms.is-chips .sal-form-say { font-size: clamp(18px, 5.4vw, 26px); }
	.sal-play { font-size: clamp(30px, 10vw, 48px); }
	.sal-q b, .sal-opt, .sal-script { font-size: clamp(16px, 4.6vw, 22px); }
	.sal-qs { grid-template-columns: minmax(0, 1fr); }
	.sal-wave i:nth-child(n+11) { display: none; }
	.sal-msg { max-width: 100%; font-size: clamp(16px, 4.6vw, 22px); }
	.sal-pair { grid-template-columns: minmax(0, 1fr); }
	.sal-take-l { font-size: 2.2rem; }
	.sal-take-txt { font-size: clamp(15px, 4.4vw, 20px); }
}

/* À la maison : les pictogrammes de la situation, en tête de la question. */
.sal-solo-media { margin: 0; text-align: center; font-size: 2.6rem; line-height: 1.2; }

/* ------------------------------------------------------------------
 * La duda
 * ------------------------------------------------------------------
 *
 * La phrase est la question : elle se lit d'un bout à l'autre de la salle, et
 * le trou doit se voir de là aussi. Un blanc typographique ne se voit pas —
 * c'est un trait plein qui le signale, à la couleur de ce qui va le remplir. */
.duda-sentence {
	margin: 0;
	line-height: 1.35;
	font-size: calc(clamp(20px, 4.4vh, 58px) * var(--proj-fit, 1));
	max-width: 30ch;
	overflow-wrap: anywhere;
}

.duda-gap {
	display: inline-block;
	min-width: 3.5em;
	border-bottom: .12em solid var(--color-proj-accent, var(--color-primary));
	vertical-align: baseline;
}

/* L'étiquette de la règle est le vrai contenu du module, mais elle n'est pas
 * la réponse : elle se pose sous elle, en petit, comme une note de marge. */
.duda-rule {
	display: inline-block;
	margin-top: var(--spacing-2);
	padding: var(--spacing-0-5) var(--spacing-3);
	border: 1px solid var(--color-proj-line, var(--color-line));
	border-radius: var(--radius-full);
	color: var(--color-proj-ink-muted, var(--color-ink-muted));
	font-size: calc(clamp(12px, 2vh, 26px) * var(--proj-fit, 1));
	line-height: 1.4;
}

/* La contre-phrase — le moment où la classe rit. Elle ne doit pas se lire
 * comme une seconde réponse : plus petite que la règle ne l'exigerait, et
 * dans la couleur de ce qui commente. */
.duda-but {
	margin: var(--spacing-3) 0 0;
	color: var(--color-proj-ink-muted, var(--color-ink-muted));
	font-size: calc(clamp(14px, 2.4vh, 30px) * var(--proj-fit, 1));
	line-height: 1.3;
	max-width: 36ch;
}

/* Sur le téléphone, la phrase tient dans la carte de la question. */
.duda-card .duda-sentence { font-size: var(--text-body-lg); }
.duda-card .duda-gap { border-bottom-color: var(--color-primary); min-width: 3em; }

.duda-table { width: 100%; border-collapse: collapse; margin-top: var(--spacing-5); }
.duda-table caption { text-align: left; padding-bottom: var(--spacing-2); color: var(--color-ink-muted); }
.duda-table th,
.duda-table td { text-align: left; padding: var(--spacing-2); border-bottom: 1px solid var(--color-line); }
.duda-table th { width: 55%; color: var(--color-ink-muted); font-weight: 500; }
.duda-table td { font-weight: 700; }
.duda-table .duda-note { font-weight: 400; color: var(--color-ink-muted); font-size: var(--text-body-sm); }

/* ------------------------------------------------------------------
 * Le compte de démonstration
 * ------------------------------------------------------------------
 *
 * Le bandeau tient toute la largeur, sous l'en-tête, et ne se referme pas. Un
 * avertissement qu'on peut faire disparaître finit par disparaître, et c'est
 * précisément celui-ci qu'il ne faut pas oublier : un professeur qui prendrait
 * ce compte pour un élève chercherait longtemps pourquoi son effectif ne
 * tombe pas juste.
 *
 * Les couleurs sont celles de la marque et non celles d'une alerte : ce n'est
 * pas une erreur, c'est un mode de travail. */
/* Le contenu se centre, comme tout ce que porte l'en-tête au-dessus.
 *
 * Collé à gauche sur un écran large, le bandeau partait vers un bord que rien
 * d'autre n'occupe : la barre de navigation est centrée, la page aussi, et lui
 * seul filait dans le coin. */
.demo-band {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	text-align: center;
	gap: var(--spacing-1) var(--spacing-2);
	align-items: baseline;
	padding: var(--spacing-2) var(--spacing-4);
	background: var(--color-brand-band);
	color: var(--color-on-primary, #fff);
	font-size: var(--text-body-sm);
	line-height: 1.35;
}

.demo-band strong { font-weight: 700; }
.demo-band span { opacity: .92; }

/* La carte du professeur, côté effectif. Le code s'y lit comme les autres
 * codes de l'écran — c'est le même objet, et le professeur va le recopier. */
.demo-card .join-code { font-size: var(--text-headline-md); }

/* Le module en test se signale dans la console, et nulle part ailleurs : un
 * professeur du programme voit le module, pas son étiquette — il n'a pas à
 * savoir qu'il essuie les plâtres pendant qu'il fait cours. */
.chip-beta { background: var(--color-brand-band); color: var(--color-on-primary, #fff); }

/* ------------------------------------------------------------------
 * L'annonce d'un module nouveau
 * ------------------------------------------------------------------
 *
 * Elle se pose sur l'écran des classes, au-dessus de la liste, et elle a la
 * couleur de la marque et non celle d'une alerte : ce n'est pas un incident,
 * c'est une bonne nouvelle. Le liseré la distingue des cartes d'information
 * qui l'entourent sans lui donner l'air d'un avertissement. */
.newish { border-left: 3px solid var(--color-brand-band); }
/* La marge est ici et non en classe utilitaire : la règle remet la marge à
 * zéro pour effacer celle du navigateur, et écraserait un `mt-3` posé dans le
 * balisage — le test des jetons attrape précisément ce genre de silence. */
.newish-list { list-style: none; margin: var(--spacing-3) 0 0; padding: 0; display: grid; gap: var(--spacing-3); }

/* L'icône garde sa taille de liste : c'est à elle qu'on reconnaîtra le module
 * dans la composition, parmi une vingtaine de pastilles. La réduire ici
 * reviendrait à annoncer un repère qu'on ne pourrait pas mémoriser. */
.newish-row {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--spacing-3);
	min-width: 0;
}

.newish-row > .col { min-width: 12rem; }

/* L'étiquette « en test », côté professeur.
 *
 * Elle avait été omise : un bêta-testeur, disais-je, n'a pas à savoir qu'il
 * essuie les plâtres pendant qu'il fait cours. C'était se tromper sur ce
 * qu'est un bêta-testeur — il a accepté d'essayer, il doit savoir sur quoi,
 * sans quoi il ne peut ni signaler ni se préparer.
 *
 * Elle se pose à deux endroits et à deux seulement : là où il choisit ses
 * modules, et là où il lance sa séance. Pas sur la scène projetée — trente
 * élèves n'ont pas à lire « bêta » sur le mur de la classe, et ce n'est pas à
 * eux que l'information s'adresse. */
.compose-tag.is-beta,
.tile-beta {
	background: var(--color-brand-band);
	color: var(--color-on-primary, #fff);
	border-radius: var(--radius-full);
	padding: var(--spacing-0-5) var(--spacing-2);
	font-size: var(--text-eyebrow);
	letter-spacing: var(--tracking-eyebrow, .04em);
	text-transform: uppercase;
	font-weight: 700;
	line-height: 1.4;
	white-space: nowrap;
}

.tile-beta { display: inline-block; margin-left: var(--spacing-2); }

/* « alpha · privé » : au même niveau de soin que « en test », mais d'une autre
 * couleur, pour qu'on ne confonde pas ce qu'on peut montrer à un collègue (la
 * bêta est ouverte à tous les professeurs) et ce qu'on garde pour soi. Le
 * liseré dit « réservé » sans dépendre de la couleur seule. */
.compose-tag.is-alpha {
	background: var(--color-primary-soft);
	color: var(--color-primary-active, var(--color-primary));
	border: 1px solid var(--color-primary);
	border-radius: var(--radius-full);
	padding: calc(var(--spacing-0-5) - 1px) calc(var(--spacing-2) - 1px);
	font-size: var(--text-eyebrow);
	letter-spacing: var(--tracking-eyebrow, .04em);
	text-transform: uppercase;
	font-weight: 700;
	line-height: 1.4;
	white-space: nowrap;
}

/* Le pense-bête des modules en alpha, en tête de la page des modules en test. */
.alpha-consigne {
	border-left: 4px solid var(--color-primary);
	background: var(--color-primary-soft);
}

/* Le fait du jour, en tête de « Hoy en la historia ».
 *
 * C'est une phrase et non une réponse : elle se mesure comme un énoncé, plus
 * grande qu'un texte de lecture et plus petite qu'un mot d'affiche. Et elle se
 * borne en largeur — une phrase qui traverse un écran de trois mètres se lit
 * en tournant la tête, ce qu'aucune classe ne fait. */
.efem-fact {
	margin: var(--spacing-3) 0 0;
	line-height: 1.3;
	font-size: calc(clamp(20px, 4.2vh, 52px) * var(--proj-fit, 1));
	max-width: 24ch;
	overflow-wrap: anywhere;
}

/* Une pastille qui se coche.
 *
 * Les temps de la roue sont courts et nombreux : une liste de cases à cocher
 * en colonne occuperait sept lignes pour sept mots. La case reste là pour le
 * clavier et le lecteur d'écran — elle est seulement invisible. */
.chip-pick { cursor: pointer; border: 1px solid var(--color-line-strong); }
.chip-pick:has(input:checked) { background: var(--color-primary-soft); border-color: var(--color-primary); color: var(--color-primary); font-weight: 600; }
.chip-pick:has(input:focus-visible) { outline: 2px solid var(--color-primary); outline-offset: 2px; }

/* ------------------------------------------------------------------
 * Les réglages d'une classe
 * ------------------------------------------------------------------
 *
 * Une ligne par réglage, sa valeur lisible sans ouvrir. L'écran était une
 * colonne de formulaires tous dépliés : tout y était visible en même temps,
 * donc rien n'y était visible — et les réglages qu'on touche une fois l'an
 * occupaient autant de place que ceux qu'on ajuste chaque mois. */
.set-ident { gap: var(--spacing-2); }

.pill {
	background: var(--color-surface-sunken);
	border-radius: var(--radius-full);
	padding: var(--spacing-1) var(--spacing-3);
	font-size: var(--text-body-sm);
	color: var(--color-ink-muted);
}

.pill b { color: var(--color-ink); }

.set-group { margin-top: var(--spacing-8); }
.set-group > p { margin-top: var(--spacing-1); }

.set-row {
	background: var(--color-surface-raised);
	border: 1px solid var(--color-line);
	border-radius: var(--radius-lg);
	margin-top: var(--spacing-2);
}

/* Le chevron tourne à l'ouverture, et la flèche native disparaît : deux
 * marqueurs pour un seul état se contredisent dès que l'un des deux se cache
 * derrière une feuille de style qui n'a pas chargé. */
.set-head {
	display: flex;
	align-items: center;
	gap: var(--spacing-3);
	padding: var(--spacing-4);
	cursor: pointer;
	list-style: none;
}

.set-head::-webkit-details-marker { display: none; }

.set-value {
	color: var(--color-primary);
	font-weight: 700;
	font-size: var(--text-body-sm);
	white-space: nowrap;
	text-align: right; /* une valeur sur deux lignes reste calée à droite */
}

.set-chev { color: var(--color-ink-faint); font-size: 1.2rem; line-height: 1; transition: transform .15s; }
.set-row[open] > .set-head > .set-chev { transform: rotate(90deg); }

/* Le détail se sépare du résumé par un filet, et les champs qu'il contient
 * perdent leur marge haute : ils en avaient une pour flotter dans une colonne,
 * ils n'en ont plus besoin dans une boîte. */
.set-body { padding: 0 var(--spacing-4) var(--spacing-4); border-top: 1px solid var(--color-line); }
.set-body > .field:first-child,
.set-body > fieldset:first-child { margin-top: var(--spacing-4); }

.set-link { display: flex; align-items: center; gap: var(--spacing-3); padding: var(--spacing-4); text-decoration: none; color: inherit; }
.set-link:hover { border-color: var(--color-line-strong); }

/* ------------------------------------------------------------------
 * La télécommande : ce qui vient, et l'état de la liaison
 * ------------------------------------------------------------------
 *
 * « À suivre » se lit d'un coup d'œil, la main basse, sans quitter la classe
 * des yeux. D'où la taille : c'est la seule chose de l'écran qu'on lit
 * vraiment pendant un cours, le reste se touche. */
.pilot-ahead {
	background: var(--color-surface-sunken);
	border-radius: var(--radius-lg);
	padding: var(--spacing-3) var(--spacing-4);
	margin-bottom: var(--spacing-4);
}

.pilot-ahead > p { margin: var(--spacing-1) 0 0; line-height: 1.3; }

/* L'état de la liaison est une note de bas de page, pas une alerte : il
 * prévient, il n'interrompt pas. Il ne monte en couleur que lorsque le
 * professeur risque d'appuyer deux fois. */
.pilot-link {
	display: flex;
	align-items: flex-start;
	gap: var(--spacing-2);
	margin: var(--spacing-4) 0;
	font-size: var(--text-body-sm);
	color: var(--color-ink-muted);
}

.pilot-dot { width: .6rem; height: .6rem; border-radius: 50%; background: var(--color-line-strong); flex: none; margin-top: .4rem; }
.pilot-link-text { display: flex; flex-direction: column; min-width: 0; }
.pilot-link-hint { font-weight: 400; }
.pilot-link-hint[hidden] { display: none; }
.pilot-dot.is-ok { background: var(--color-success); }
.pilot-dot.is-slow { background: var(--color-brand-band); }
.pilot-dot.is-bad,
.pilot-dot.is-down { background: var(--color-error); }
.pilot-link[data-vd-state="bad"],
.pilot-link[data-vd-state="down"] { color: var(--color-error-strong); font-weight: 600; }

/* ------------------------------------------------------------------
 * El intruso
 * ------------------------------------------------------------------
 *
 * Les quatre mots se regardent ensemble, en grille et non en colonne : mis les
 * uns sous les autres, ils se lisent dans l'ordre, et l'ordre suggère une
 * progression qui n'existe pas. Côte à côte, ils se comparent. */
.intru-zones { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--spacing-3); }

.intru-zones > .proj-zone {
	align-items: center;
	/* En haut, et non au centre : la carte de l'intrus, qui cache sa raison,
	 * est plus haute que ses voisines ; centrés, les mots d'une même rangée
	 * ne seraient plus alignés. */
	justify-content: flex-start;
	text-align: center;
	gap: var(--spacing-2);
	min-width: 0;
	padding: var(--spacing-5) var(--spacing-3);
}

.intru-zone { font-size: calc(clamp(20px, 4.4vh, 54px) * var(--proj-fit, 1)); line-height: 1.15; }

/* Ce qui sort du lot, et ce qui y reste. La famille partagée est une note — on
 * la lit trois fois sur quatre —, la raison de l'intrus est la réponse. */
.intru-in {
	font-size: calc(clamp(12px, 2vh, 24px) * var(--proj-fit, 1));
	color: var(--color-proj-ink-muted);
	letter-spacing: var(--tracking-eyebrow, .04em);
	text-transform: uppercase;
}

.intru-out {
	display: inline-block;
	font-size: calc(clamp(12px, 2vh, 24px) * var(--proj-fit, 1));
	font-weight: 700;
	letter-spacing: var(--tracking-eyebrow, .04em);
	text-transform: uppercase;
	color: var(--color-proj-accent);
}

/*
 * Fermée, la carte de l'intrus a la taille des autres. Sa raison, une phrase
 * entière, la rendait plus haute et descendait sa barre : la classe voyait
 * l'intrus avant d'avoir cherché. Elle ne prend sa place qu'à l'ouverture de
 * la carte — `aria-expanded`, que le script tient à jour, et non le voile,
 * qu'une règle de disposition ne doit pas viser (test-tokens).
 */
.intru-zones > .proj-zone[aria-expanded="false"] .intru-why { display: none; }

/* Dévoilée, la carte garde l'axe de son mot : famille, verdict et raison centrés dessous. */
.intru-zones > .proj-zone > [data-vd-zone-body] { align-items: center; }

.intru-why {
	margin: var(--spacing-2) 0 0;
	font-size: calc(clamp(13px, 2.2vh, 28px) * var(--proj-fit, 1));
	line-height: 1.3;
	max-width: 24ch;
}

/* Sur le téléphone, la grille tient dans la carte de la question. */
.intru-words { display: grid; grid-template-columns: 1fr 1fr; gap: var(--spacing-2); }
.intru-word {
	background: var(--color-surface-sunken);
	border-radius: var(--radius-md);
	padding: var(--spacing-2) var(--spacing-3);
	text-align: center;
	font-size: var(--text-body-lg);
}

.intru-table { width: 100%; border-collapse: collapse; margin-top: var(--spacing-5); }
.intru-table caption { text-align: left; padding-bottom: var(--spacing-2); color: var(--color-ink-muted); }
.intru-table th,
.intru-table td { text-align: left; padding: var(--spacing-2); border-bottom: 1px solid var(--color-line); }
.intru-table th { width: 40%; font-weight: 700; }
.intru-table td { color: var(--color-ink-muted); }

/* Le drapeau d'une pastille de langue : la hauteur d'une capitale, aligné sur
 * la ligne de base du mot qu'il accompagne. */
.pill-lang { display: inline-flex; align-items: center; gap: var(--spacing-2); }
.pill-lang svg { width: 1.1em; height: auto; border-radius: 2px; display: block; }

/* Le bandeau de bascule : « vous êtes connecté en tant que », et la porte de
 * sortie.
 *
 * Même place et même rôle que le bandeau du compte de démonstration — sous
 * l'en-tête, sur toute la largeur, sans croix pour le fermer. Une couleur
 * différente parce que ce n'est pas le même état : la démonstration est un
 * mode de travail, la bascule est une situation dont il faut sortir. */
.switch-band {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	text-align: center;
	gap: var(--spacing-1) var(--spacing-3);
	align-items: baseline;
	padding: var(--spacing-2) var(--spacing-4);
	background: var(--color-primary);
	color: var(--color-on-primary, #fff);
	font-size: var(--text-body-sm);
	line-height: 1.35;
}

.switch-back { color: inherit; font-weight: 700; text-decoration: underline; }
.switch-back:hover { text-decoration: none; }

/* Une classe déjà servie par le module : présente, éteinte, non cliquable.
 * La masquer laisserait croire qu'on l'a oubliée. */
.chip-in { border: 1px solid var(--color-line); background: var(--color-surface-sunken); color: var(--color-ink-muted); }
.newish-pick { width: 100%; }

/* La consigne seule (un encadré qui ne porte que son libellé, marqué `is-cue`
 * par le serveur) s'efface dès la première réponse dévoilée — voir paint()
 * dans projection.js. */
body.projection .proj-shell.is-started .proj-panel.is-cue { display: none; }

/* Rendre la télécommande : centré, détaché du pied, discret.
   Le geste est rare et sans retour en arrière — il ne doit pas se trouver sous
   le pouce au milieu d'une séance. */
.pilot-give { align-items: center; text-align: center; }

/* Ce que l'adresse d'inscription décide, dit au champ et non sous le bouton.
   Trois états, et aucun n'est une erreur : on informe, on ne refuse pas. */
.field-ac {
	display: block;
	margin-top: var(--spacing-2);
	padding: var(--spacing-2) var(--spacing-3);
	font-size: 14px;
	line-height: 1.45;
	border-radius: var(--radius-md);
	background: var(--color-surface-sunken);
	color: var(--color-ink-muted);
}
.field-ac.is-ac {
	background: var(--color-success-soft, var(--color-surface-sunken));
	color: var(--color-success-strong);
	font-weight: 700;
}
.field-ac.is-autre { background: var(--color-surface-sunken); color: var(--color-ink-muted); }

/* Le programme des modules en test. */
.chip-beta {
	flex: none; font-size: 12px; font-weight: 800; letter-spacing: .04em;
	padding: 2px 10px; border-radius: 99px;
	background: var(--color-primary); color: #fff;
}
.beta-fait { font-size: 13.5px; font-weight: 700; color: var(--color-success-strong); align-self: center; }

/* Le verdict : trois pastilles, une seule cochée. Le bouton radio lui-même est
   caché, mais il reste le contrôle — c'est lui que le clavier atteint et que
   les lecteurs d'écran annoncent. */
.beta-choix {
	display: inline-flex; align-items: center; gap: var(--spacing-2);
	border: 2px solid var(--color-line-strong); background: var(--color-surface);
	color: var(--color-ink); border-radius: var(--radius-md);
	padding: var(--spacing-2) var(--spacing-4); cursor: pointer;
	font-size: 15px; font-weight: 700;
}
.beta-choix input { position: absolute; opacity: 0; width: 0; height: 0; }
.beta-choix:has(input:checked), .beta-choix.is-on {
	border-color: var(--color-primary); background: var(--color-primary); color: #fff;
}
.beta-choix:has(input:focus-visible) { outline: 3px solid var(--color-primary); outline-offset: 2px; }

.beta-invite {
	display: flex; gap: var(--spacing-4); align-items: flex-start;
	padding: var(--spacing-5);
	background: var(--color-surface-raised);
	border: 2px dashed var(--color-primary);
	border-radius: var(--radius-lg);
}
.beta-ico {
	flex: none; width: 40px; height: 40px; border-radius: 99px;
	display: grid; place-items: center;
	background: var(--color-surface-sunken); font-size: 19px;
}

/* Le centre d'aide. */
.hc-search {
	display: flex; align-items: center; gap: var(--spacing-3);
	margin-top: var(--spacing-5);
	padding: var(--spacing-4) var(--spacing-5);
	background: var(--color-surface-raised);
	border: 2px solid var(--color-line-strong);
	border-radius: var(--radius-lg);
}
.hc-search:focus-within { border-color: var(--color-primary); }
.hc-search svg { width: 22px; height: 22px; flex: none; fill: none; stroke: var(--color-ink-muted); stroke-width: 2.2; stroke-linecap: round; }
.hc-search input { flex: 1; border: 0; background: none; outline: none; font: inherit; font-size: 17px; color: var(--color-ink); min-width: 0; }
.hc-search input::-webkit-search-cancel-button { display: none; }
.hc-clear { border: 0; background: var(--color-surface-sunken); color: var(--color-ink-muted); width: 26px; height: 26px; border-radius: 99px; cursor: pointer; font-size: 17px; line-height: 1; flex: none; }
.hc-res { margin-top: var(--spacing-3); }
.hc-none { padding: var(--spacing-3) var(--spacing-4); }

.hc-eyebrow { font-size: 11.5px; letter-spacing: .1em; text-transform: uppercase; font-weight: 800; color: var(--color-ink-faint); margin: var(--spacing-8) 0 var(--spacing-3); }

.hc-row { display: flex; align-items: baseline; gap: var(--spacing-3); padding: var(--spacing-3) var(--spacing-4); border-radius: var(--radius-md); }
.hc-row:hover { background: var(--color-surface-raised); }
.hc-row a { color: var(--color-ink); text-decoration: none; }
.hc-row a:hover { color: var(--color-primary); text-decoration: underline; }
.hc-top .hc-row { background: var(--color-surface-raised); }
.hc-dur { flex: none; font-size: 13px; font-weight: 700; color: var(--color-ink-muted); background: var(--color-surface-sunken); border-radius: 99px; padding: 2px 10px; }

.hc-next { display: flex; gap: var(--spacing-4); padding: var(--spacing-5); background: var(--color-surface-raised); border: 2px solid var(--color-primary); border-radius: var(--radius-lg); }
.hc-next.is-quiet { border-color: var(--color-line-strong); }
.hc-next-ico { flex: none; width: 38px; height: 38px; border-radius: 99px; display: grid; place-items: center; background: var(--color-primary); color: #fff; font-size: 15px; }
.hc-next.is-quiet .hc-next-ico { background: var(--color-surface-sunken); color: var(--color-ink-muted); }
.hc-next-links { margin-top: var(--spacing-1); font-size: 14.5px; font-weight: 700; }
.hc-dot { color: var(--color-ink-faint); margin: 0 6px; }

.hc-videos { display: flex; align-items: center; gap: var(--spacing-4); margin-top: var(--spacing-8); padding: var(--spacing-5); background: var(--color-surface-raised); border: 2px solid var(--color-line-strong); border-radius: var(--radius-lg); text-decoration: none; color: inherit; }
.hc-videos:hover { border-color: var(--color-ink-faint); }
.hc-videos-ico { flex: none; width: 44px; height: 44px; border-radius: 99px; display: grid; place-items: center; background: var(--color-primary); color: #fff; font-size: 17px; }

.hc-sec { margin-top: var(--spacing-2); }
.hc-sec .arch-when { font-weight: 400; }

/* Le cadre n'arrive qu'au clic : il remplace la façade, en seize neuvièmes. */
.hc-frame { width: 100%; aspect-ratio: 16 / 9; border: 0; border-radius: var(--radius-md); display: block; }

/* Le corps d'un article vient de la vitrine : on lui donne le rythme de
   l'application sans toucher à son balisage. */
.hc-article { max-width: 44rem; line-height: 1.6; }
.hc-article p { margin: 0 0 var(--spacing-4); }
.hc-article ol, .hc-article ul { margin: 0 0 var(--spacing-4); padding-left: var(--spacing-6); }
.hc-article li { margin-bottom: var(--spacing-2); }
.hc-article h2, .hc-article h3 { margin: var(--spacing-6) 0 var(--spacing-3); font-family: Fredoka, system-ui, sans-serif; }
.hc-article .note {
	background: var(--color-surface-raised);
	border-left: 4px solid var(--color-primary);
	border-radius: var(--radius-md);
	padding: var(--spacing-4) var(--spacing-5);
	color: var(--color-ink-muted);
}
.hc-article img { max-width: 100%; height: auto; border-radius: var(--radius-md); }
/* Un message à transmettre tel quel (au service informatique, à la
 * direction) : encadré pour qu'on le repère, et sélectionné d'un geste pour
 * qu'on le copie sans en oublier la fin. */
.hc-article blockquote {
	margin: 0 0 var(--spacing-4);
	padding: var(--spacing-3) var(--spacing-4);
	border: 2px dashed var(--color-line-strong);
	border-radius: var(--radius-md);
	background: var(--color-surface-raised);
	user-select: all;
	-webkit-user-select: all;
}
.hc-article blockquote p:last-child { margin-bottom: 0; }

@media (max-width: 34rem) {
	.hc-sec .arch-when { display: none; }
	.hc-next { padding: var(--spacing-4); gap: var(--spacing-3); }
}

/* Le centre d'aide : le bandeau de page (titre, question à Vera, ses trois étapes), puis les sujets en cartes. */
.aide-band { text-align: center; }
.aide-hero h1 { margin: 0; }
.aide-hero p { margin: var(--spacing-2) auto 0; max-width: 40rem; color: var(--color-ink-muted); }
.aide-hero p b { color: var(--color-ink); }

.aide-ask { max-width: 46rem; margin: var(--spacing-5) auto 0; padding: 0; text-align: left; }
.aide-ask-bar { display: flex; align-items: center; gap: var(--spacing-3);
	padding: 8px 8px 8px var(--spacing-4);
	background: var(--color-surface-raised); border: 2.5px solid var(--color-ink);
	border-radius: 99px; box-shadow: 0 4px 0 var(--color-primary); }
.aide-ask-bar .vera { flex: none; }
.aide-ask-champ { flex: 1; border: 0; background: none; outline: none; font: inherit;
	font-size: 17px; color: var(--color-ink); min-width: 0; padding: 8px 0; }
.aide-ask-go { flex: none; width: 44px; height: 44px; border: 0; border-radius: 99px;
	background: var(--color-primary); color: #fff; font-size: 20px; cursor: pointer; }

/* Le fil de la conversation. */
.aide-fil { display: flex; flex-direction: column; gap: var(--spacing-4);
	margin: var(--spacing-6) 0 var(--spacing-5); }
.aide-tour { display: flex; gap: var(--spacing-3); align-items: flex-start; }
.aide-tour.is-moi { flex-direction: row-reverse; }
.aide-ico { flex: none; width: 36px; height: 36px; border-radius: 99px; display: grid;
	place-items: center; background: var(--color-surface-sunken); overflow: hidden; font-size: 17px; }
.aide-bulle { max-width: 38rem; padding: var(--spacing-4) var(--spacing-5);
	background: var(--color-surface-raised); border: 2px solid var(--color-line-strong);
	border-radius: var(--radius-lg); }
.is-moi .aide-bulle { background: var(--color-primary); border-color: var(--color-primary); color: #fff; }
.is-moi .aide-bulle .text-hint { color: rgba( 255, 255, 255, .78 ); }

.aide-src { display: flex; align-items: center; gap: var(--spacing-3); margin-top: var(--spacing-3);
	padding: var(--spacing-2) var(--spacing-3); background: var(--color-surface-sunken);
	border-radius: var(--radius-md); font-size: 13.5px; }
.aide-suite { display: flex; flex-wrap: wrap; gap: var(--spacing-2); margin-top: var(--spacing-3); }

.aide-pts { display: inline-flex; gap: 4px; padding: 4px 0; }
.aide-pts i { width: 7px; height: 7px; border-radius: 99px; background: var(--color-ink-faint); animation: aide-pt 1s infinite; }
.aide-pts i:nth-child(2) { animation-delay: .15s; }
.aide-pts i:nth-child(3) { animation-delay: .3s; }
@keyframes aide-pt { 0%, 60%, 100% { opacity: .25 } 30% { opacity: 1 } }

.aide-retour { margin-top: var(--spacing-3); text-align: center; }
.aide-retour-b { border: 0; background: none; color: var(--color-ink-muted); font: inherit;
	font-size: 13.5px; font-weight: 700; cursor: pointer; }

/* Le brouillon est un document, pas un message : toute la largeur, hors du
   fil des bulles. Emboîté dans une bulle il se retrouvait à trois cadres de
   profondeur sur un téléphone, et sa zone de texte coupait ses lignes. */
.aide-doc { border: 2px solid var(--color-primary); border-radius: var(--radius-lg);
	background: var(--color-surface); padding: var(--spacing-5); }
.aide-doc-titre { margin: 0 0 var(--spacing-4); font-size: 11.5px; letter-spacing: .1em;
	text-transform: uppercase; font-weight: 800; color: var(--color-ink-faint); }
.aide-doc-err { margin: var(--spacing-3) 0 0; color: var(--color-error-strong); font-size: 14px; font-weight: 700; }
.aide-joint { background: var(--color-surface-sunken); border-radius: var(--radius-md);
	padding: var(--spacing-4); font-size: 13.5px; line-height: 1.7; }
.aide-corps { display: block; box-sizing: border-box; width: 100%; resize: vertical; overflow: hidden;
	min-height: 7rem; margin-top: var(--spacing-4); padding: var(--spacing-4);
	font: inherit; font-size: 15px; line-height: 1.55;
	border: 2px solid var(--color-line-strong); border-radius: var(--radius-md);
	background: var(--color-surface); color: var(--color-ink); }
.aide-doc .aide-suite { margin-top: var(--spacing-4); }
.aide-doc.is-plie { display: flex; align-items: center; gap: var(--spacing-3);
	padding: var(--spacing-3) var(--spacing-4); border-style: dashed; }

/* La bascule : les rubriques s'effacent, le champ ne bouge pas. */
.is-chat [data-vera-repos], .is-chat [data-vera-browse] { display: none; }

/* La marge négative n'existe que pour chevaucher l'en-tête coloré. En
   conversation l'en-tête disparaît, mais la marge restait : elle annulait
   exactement la marge basse du fil, et le brouillon venait coller la barre de
   question. Une valeur posée pour un état doit être annulée dans l'autre. */
.is-chat .aide-ask { margin-top: var(--spacing-6); }

.aide-rep { margin-top: var(--spacing-5); }
.aide-rep-bulle { padding: var(--spacing-5); background: var(--color-surface-raised);
	border: 2px solid var(--color-line-strong); border-radius: var(--radius-lg); }
.aide-rep-source { display: flex; align-items: center; gap: var(--spacing-3);
	margin-top: var(--spacing-4); padding: var(--spacing-3) var(--spacing-4);
	background: var(--color-surface-sunken); border-radius: var(--radius-md); font-size: 14px; }
.aide-rep-pistes { margin-top: var(--spacing-2); }
.aide-rep-pistes li { padding: var(--spacing-1) 0; }
.aide-rep-aveu { margin-top: var(--spacing-3); font-size: 13px; color: var(--color-ink-muted); text-align: center; }

.aide-grille { display: grid; grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
	gap: var(--spacing-4); list-style: none; padding: 0; }
.aide-carte { height: 100%; background: var(--color-surface-raised);
	border: 2px solid var(--color-line-strong); border-top: 5px solid var(--c, var(--color-primary));
	border-radius: var(--radius-lg); }
.aide-carte > summary { list-style: none; cursor: pointer; display: flex; flex-direction: column;
	gap: var(--spacing-2); padding: var(--spacing-5); }
.aide-carte > summary::-webkit-details-marker { display: none; }
.aide-carte > summary::marker { content: ""; }
.aide-carte:hover { border-color: var(--c, var(--color-primary)); }
.aide-carte-ico { width: 46px; height: 46px; border-radius: var(--radius-md); display: grid;
	place-items: center; font-size: 23px; background: color-mix( in srgb, var(--c, var(--color-primary)) 18%, transparent ); }
.aide-carte-n { font-size: 13px; font-weight: 700; color: var(--c, var(--color-primary)); }
.aide-carte-liste { padding: 0 var(--spacing-5) var(--spacing-5); }

/* La dernière carte des sujets n'est pas un dépliant mais un lien : elle mène
   à la boîte à idées. Mêmes bordures, même bande colorée — ce n'est pas une
   pièce rapportée, c'est le sixième sujet. */
.aide-carte-lien { display: flex; flex-direction: column; gap: var(--spacing-2);
	padding: var(--spacing-5); text-decoration: none; color: inherit; }

/* La boîte à idées : les pastilles d'état, les voix, la bascule. */
.idee-etat { flex: none; font-size: 12.5px; font-weight: 800; border-radius: 99px; padding: 3px 11px;
	background: var(--color-surface-sunken); color: var(--color-ink-muted); }
/* Le chemin, sous la barre de l'aide.
 *
 * Il ne décrit pas une fonction, il décrit ce qui va arriver à la personne —
 * et la dernière ligne est la seule qui compte : quelqu'un lui répond. Sans
 * elle, l'écran n'était qu'un champ de recherche, et celui qui avait besoin
 * d'un humain repartait sur le site vitrine. */
.aide-chemin { list-style: none; margin: var(--spacing-5) 0 0; padding: 0;
	display: flex; flex-wrap: wrap; justify-content: center; gap: var(--spacing-2) var(--spacing-5); }
.aide-chemin li { display: flex; align-items: center; gap: var(--spacing-2); text-align: left;
	font-size: 14px; color: var(--color-ink-muted); line-height: 1.4; }
.aide-chemin li b { color: var(--color-ink); }
.aide-chemin-n { flex: none; width: 22px; height: 22px; border-radius: 99px;
	display: grid; place-items: center; font-size: 12px; font-weight: 800;
	background: var(--color-surface-raised);
	color: var(--color-primary); }
/* Sur un téléphone les trois étapes s'empilent, alignées à gauche. */
@media (max-width: 40rem) { .aide-chemin { flex-direction: column; align-items: flex-start; width: fit-content; max-width: 100%; margin-inline: auto; } }

/* Les sujets : des cartes, trois par ligne. Une carte ouverte prend toute la ligne et montre ses articles. */
.reg-pile.aide-sujets { display: grid; grid-template-columns: repeat( auto-fill, minmax( min( 100%, 380px ), 1fr ) ); gap: 14px; align-items: start; }
.aide-sujets > details.reg-plie[open] { grid-column: 1 / -1; }
.aide-sujets > details.reg-plie > summary.reg-ligne { display: grid; grid-template-columns: auto 1fr; grid-template-areas: "ico fl" "txt txt" "val val"; align-items: center; gap: 6px var(--spacing-3); padding: 16px; }
.aide-sujets .reg-ico { grid-area: ico; width: 44px; height: 44px; border-radius: 12px; margin-bottom: 4px; }
.aide-sujets .reg-fl { grid-area: fl; justify-self: end; }
.aide-sujets .reg-txt { grid-area: txt; }
.aide-sujets .reg-ligne > .reg-val { grid-area: val; max-width: none; margin: 0; order: 0; flex: none; text-align: left; font-size: 13px; }
.aide-sujets .reg-corps { padding: 0 16px 12px; }
.aide-sujets .aide-liste .hc-row + .hc-row { border-top: 0; }
.aide-sujets .aide-liste { display: grid; grid-template-columns: repeat( auto-fill, minmax( min( 100%, 22rem ), 1fr ) ); gap: 0 var(--spacing-6); }
.aide-deux { display: grid; grid-template-columns: repeat( auto-fit, minmax( min( 100%, 290px ), 1fr ) ); gap: 14px; margin-top: var(--spacing-6); }
.aide-deux > * { margin: 0; }

/* L'article : le bandeau, le texte, et à droite la rubrique et Vera. */
.aide-meta { display: flex; flex-wrap: wrap; gap: 8px; margin: var(--spacing-3) 0 0; }
.aide-pill { display: inline-flex; align-items: center; gap: 6px; padding: 4px 12px; border-radius: 99px;
	background: var(--color-surface-raised); border: 1.5px solid var(--color-line);
	font: 600 13px Nunito, sans-serif; color: var(--color-ink-muted); }
.aide-art { display: grid; grid-template-columns: minmax( 0, 1fr ) 22rem; gap: var(--spacing-8); align-items: start; }
@media (max-width: 60rem) { .aide-art { grid-template-columns: minmax( 0, 1fr ); gap: var(--spacing-6); } }
.aide-art-main .hc-video { max-width: 44rem; }
.aide-side { position: sticky; top: 84px; display: flex; flex-direction: column; gap: 14px; }
@media (max-width: 60rem) { .aide-side { position: static; } }
.aide-box { padding: 16px; background: var(--color-surface-raised); border: 2px solid var(--color-line); border-radius: var(--radius-lg); }
.aide-box h2 { margin: 0 0 8px; font: 600 13px Fredoka, sans-serif; text-transform: uppercase; letter-spacing: .06em; color: var(--color-ink-muted); }
.aide-box ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.aide-box li a { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 10px; border-radius: 12px;
	color: var(--color-ink); text-decoration: none; font-weight: 700; font-size: 15px; }
.aide-box li a:hover { background: var(--color-surface-sunken); }
.aide-box li a.on { background: var(--color-primary-soft); color: var(--color-primary-active); }
.aide-box li a em { flex: none; font-style: normal; font-size: 12px; font-weight: 700; color: var(--color-ink-muted); white-space: nowrap; }
.aide-vera { display: flex; flex-direction: column; gap: 10px; background: var(--color-primary-soft); border-color: color-mix( in srgb, var(--color-primary) 35%, transparent ); }
.aide-vera p { margin: 0; font-size: 14px; color: var(--color-ink-muted); }
.aide-vera .aide-vera-t { display: flex; align-items: center; gap: 10px; font-size: 16px; color: var(--color-ink); }
.aide-vera .btn { align-self: flex-start; }


/* Une ligne, pas une carte : elle se pose au bas d'un écran de travail, où une
   carte deviendrait du mobilier au bout de trois passages. */
.idee-ligne { display: flex; align-items: center; gap: var(--spacing-4);
	padding: var(--spacing-4); text-decoration: none; color: inherit;
	background: var(--color-surface-raised); border: 2px solid var(--color-line);
	border-radius: var(--radius-lg); }
.idee-ligne:hover { border-color: var(--color-brand-band); }
.idee-ligne-ico { flex: none; width: 38px; height: 38px; border-radius: var(--radius-md);
	display: grid; place-items: center; font-size: 19px;
	background: color-mix( in srgb, var(--color-brand-band) 18%, transparent ); }
@supports not (color: color-mix(in srgb, red, blue)) { .idee-ligne-ico { background: rgba(224,136,40,0.18); } }

/* L'ampoule de l'en-tête : au trait, jamais en aplat — elle doit se lire
   comme secondaire à côté du « ? », qui est le geste pressé. */
.chrome-idee svg { fill: none; }

.idee-etat.is-attente { background: var(--color-surface-sunken); color: var(--color-ink-muted);
	border: 2px dashed var(--color-line-strong); padding: 1px 9px; }
.idee-etat.is-etude { background: color-mix( in srgb, var(--color-brand-band) 20%, var(--color-surface) );
	color: #8a5208; }
@supports not (color: color-mix(in srgb, red, blue)) { .idee-etat.is-etude { background: rgb(249,224,194); } }
.idee-etat.is-pub,
.idee-etat.is-plan { background: color-mix( in srgb, var(--color-success) 16%, var(--color-surface) );
	color: var(--color-success-strong); }
@supports not (color: color-mix(in srgb, red, blue)) { .idee-etat.is-pub, .idee-etat.is-plan { background: rgb(219,234,216); } }
.idee-etat.is-cours { background: color-mix( in srgb, var(--color-primary) 16%, var(--color-surface) );
	color: var(--color-primary); }
@supports not (color: color-mix(in srgb, red, blue)) { .idee-etat.is-cours { background: rgb(229,223,248); } }
/* Le mois de livraison, sous le titre : une indication, pas une promesse — il disparaît une fois passé. */
.idee-etat-nb { margin-left: 4px; padding: 0 6px; border-radius: 99px; background: color-mix( in srgb, currentColor 14%, transparent ); font-variant-numeric: tabular-nums; }
@supports not (color: color-mix(in srgb, red, blue)) { .idee-etat-nb { background: rgba(0,0,0,.08); } }
.idee-livraison { flex: none; font-size: 12.5px; font-weight: 700; border-radius: 99px; padding: 2px 10px;
	border: 1.5px solid var(--color-line-strong, var(--color-line)); color: var(--color-ink); background: transparent; white-space: nowrap; }
/* Les quatre étapes, dites une fois au-dessus de la liste. */
.idee-etapes { display: flex; flex-wrap: wrap; gap: var(--spacing-2); }
.idee-etat.is-fait { background: var(--color-primary); color: var(--color-on-primary); }
.idee-etat.is-non { background: var(--color-surface-sunken); color: var(--color-ink-faint); }

/* L'idée vers laquelle Vera envoie : la carte se signale à l'arrivée, et ne
   se cache pas sous l'en-tête collant. */
.idee-ligne-cible { scroll-margin-top: 96px; }
.idee-ligne-cible:target,
.idee-ligne-cible.is-cible { outline: 3px solid var(--color-primary); outline-offset: 2px; }

/* Le motif d'un refus se détache du reste : c'est une parole tenue, pas une
   mention légale. */
.idee-motif { margin: 0; padding-left: var(--spacing-4); color: var(--color-ink-muted);
	border-left: 3px solid var(--color-line-strong); }

.idee-moi { display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
	font: inherit; font-size: 13.5px; font-weight: 700; color: var(--color-ink-muted);
	padding: 5px 12px; border-radius: 99px; background: var(--color-surface-sunken);
	border: 2px solid transparent; }
.idee-moi b { color: var(--color-ink); }
.idee-moi.is-on { background: color-mix( in srgb, var(--color-primary) 10%, var(--color-surface) );
	border-color: var(--color-primary); color: var(--color-primary); }
@supports not (color: color-mix(in srgb, red, blue)) { .idee-moi.is-on { background: rgb(240,229,231); } }
.idee-moi.is-on b { color: var(--color-primary); }
.idee-moi[disabled] { cursor: default; opacity: .75; }

.idee-bascule { display: flex; justify-content: center; gap: var(--spacing-5); margin-top: var(--spacing-4); }
.idee-bascule button { position: relative; z-index: 1; display: inline-flex; align-items: center; gap: 6px; cursor: pointer; font: inherit; font-size: 15px; font-weight: 700;
	padding: 14px 2px 13px; border: 0; border-radius: 0; background: none; color: var(--color-ink-muted); }
.idee-bascule button:hover { color: var(--color-ink); }
.idee-bascule button b { font-size: 13px; color: var(--color-primary); }
.idee-bascule button.is-on { color: var(--color-ink); }
.idee-bascule button.is-on::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 4px; border-radius: 4px 4px 0 0; background: var(--color-brand-corner); }
.idee-bascule button:focus-visible { outline: 3px solid var(--color-primary); outline-offset: 2px; }
.page-band:has( > .idee-bascule ) { padding-bottom: 0; }

/* La liste : des cartes sur deux colonnes, le vote à gauche, et une page à la fois (idees-filtre.js). */
.idee-grille { display: grid; grid-template-columns: repeat( auto-fill, minmax( min( 100%, 34rem ), 1fr ) ); gap: 12px; margin-top: var(--spacing-4); }
.idee-grille > li[hidden] { display: none; }
.idee-ligne-cible { display: flex; align-items: stretch; gap: 14px; padding: 12px 16px 12px 12px; }
.idee-main { display: flex; flex-direction: column; justify-content: center; gap: var(--spacing-2); min-width: 0; flex: 1; }
.idee-ligne-cible .idee-moi { flex: none; flex-direction: column; justify-content: center; align-self: stretch; gap: 0; width: 64px; padding: 6px 0;
	border: 2px solid var(--color-line); border-radius: 14px; background: var(--color-surface); color: var(--color-ink); }
.idee-ligne-cible .idee-moi:hover:not( [disabled] ) { border-color: var(--color-primary); }
.idee-ligne-cible .idee-moi > span { font-size: 15px; color: var(--color-primary); line-height: 1; }
.idee-ligne-cible .idee-moi b { font: 700 20px Fredoka, sans-serif; line-height: 1.1; }
.idee-ligne-cible .idee-moi small { font-size: 11px; font-weight: 700; color: var(--color-ink-muted); }
.idee-ligne-cible .idee-moi.is-on { border-color: var(--color-primary); }
.idee-plus { display: flex; justify-content: center; margin: var(--spacing-6) 0; }
/* Sur un téléphone le titre garde toute la ligne, l'étape et le mois passent dessous. */
@media (max-width: 40rem) { .idee-ligne-cible .idee-acc > summary > b { flex: 1 1 100%; } }
.idee-etapes { margin-top: 0; }

/* Le texte d'origine et la mise au propre, côte à côte. Jamais l'un à la
   place de l'autre : c'est ce qui rend la reformulation vérifiable. */
/* L'avis préparé par Vera : le profil déjà rempli tient en une ligne. */
.aide-connexion { margin-top: 12px; padding: 12px 14px; border-radius: 14px; background: color-mix( in srgb, var(--color-primary) 8%, var(--color-surface) );
	border: 1px solid color-mix( in srgb, var(--color-primary) 30%, transparent ); font: 600 14px/1.5 Nunito, sans-serif; }
@supports not (color: color-mix(in srgb, red, blue)) { /* Le texte d'origine et la mise au propre, côte à côte. Jamais l'un à la
   place de l'autre : c'est ce qui rend la reformulation vérifiable. */
/* L'avis préparé par Vera : le profil déjà rempli tient en une ligne. */
.aide-connexion { background: rgb(243,233,232); border: 1px solid rgba(108,79,216,0.30); } }
.te-profil { border: 1px solid var(--color-line); border-radius: 12px; padding: 10px 12px; background: var(--color-surface); }
.te-profil > summary { cursor: pointer; list-style: none; display: flex; justify-content: space-between; gap: 8px; align-items: baseline; }
.te-profil > summary::-webkit-details-marker { display: none; }
.te-profil[open] > summary .te-lien { visibility: hidden; }
.aide-bulle form[data-te-form] { margin-top: 8px; }
/* La boîte à idées en accordéon : le titre, et la description qu'on ouvre. */
.idee-acc > summary { cursor: pointer; list-style: none; }
.idee-acc > summary::-webkit-details-marker { display: none; }
.idee-acc:not([data-vide]) > summary b::after { content: " ▾"; font-size: .8em; color: var(--color-ink-muted); }
.idee-acc[open]:not([data-vide]) > summary b::after { content: " ▴"; }
.idee-acc[data-vide] > summary { cursor: default; }
.idee-desc { margin: var(--spacing-2) 0 0; color: var(--color-ink-muted); }
/* Les idées dégagées par Vera : une carte par demande, à cocher. */
.idee-liste { display: grid; gap: 10px; margin-top: 12px; }
.idee-une { display: flex; gap: 10px; align-items: flex-start; background: color-mix( in srgb, var(--color-primary) 7%, var(--color-surface) );
	border: 2px solid color-mix( in srgb, var(--color-primary) 30%, transparent ); border-radius: 14px; padding: 12px 14px; cursor: pointer; }
@supports not (color: color-mix(in srgb, red, blue)) { .idee-une { background: rgb(245,234,232); border: 2px solid rgba(108,79,216,0.30); } }
.idee-une input { margin-top: 4px; width: 18px; height: 18px; accent-color: var(--color-primary); flex: none; }
.idee-une > span { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.idee-une i { font-style: normal; font-weight: 800; font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: var(--color-ink-muted); margin-right: 4px; }
.idee-avis { display: flex; gap: 10px; align-items: flex-start; margin-top: 12px; padding: 10px 12px; border-radius: 12px; background: #fdf6e6; border: 1px solid var(--color-gold); cursor: pointer; }
.idee-avis input { margin-top: 4px; width: 18px; height: 18px; accent-color: var(--color-primary); flex: none; }
.idee-avis > span { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.idee-merci { margin-top: 12px; padding: 10px 12px; border-radius: 12px; background: #fdf6e6; border: 1px solid var(--color-gold); }
.idee-deux { display: grid; grid-template-columns: 1fr 1fr; gap: var(--spacing-4);
	margin-top: var(--spacing-4); }
.idee-col { padding: var(--spacing-4); background: var(--color-surface-sunken);
	border-radius: var(--radius-md); }
.idee-col.is-prop { background: color-mix( in srgb, var(--color-primary) 8%, var(--color-surface) );
	border: 2px solid color-mix( in srgb, var(--color-primary) 35%, transparent ); }
@supports not (color: color-mix(in srgb, red, blue)) { .idee-col.is-prop { background: rgb(243,233,232); border: 2px solid rgba(108,79,216,0.35); } }
.idee-col p { margin: 0 0 var(--spacing-2); }
.idee-col p:last-child { margin-bottom: 0; }
.idee-brut { color: var(--color-ink-muted); font-style: italic; }

@media (max-width: 46rem) { .idee-deux { grid-template-columns: 1fr; } }

/* La série entière en une ligne : qui la cherche est en mode « apprendre »,
   pas en mode « bloqué ». Elle est donc après les sujets, et discrète. */
.aide-serie { display: flex; align-items: center; gap: var(--spacing-4);
	padding: var(--spacing-4) var(--spacing-5);
	background: var(--color-surface-raised); border: 2px solid var(--color-line-strong);
	border-radius: var(--radius-lg); text-decoration: none; color: inherit; }
.aide-serie:hover { border-color: var(--color-ink-faint); }
.aide-serie-ico { flex: none; width: 38px; height: 38px; border-radius: 99px;
	display: grid; place-items: center; background: var(--color-primary); color: #fff; font-size: 15px; }

/* Le visage de Vera : les points de la bande battent quand elle cherche. */
.vera { display: block; }
.vera-cherche .vp { animation: vera-pt 1.1s infinite; }
.vera-cherche .vp2 { animation-delay: .18s; }
.vera-cherche .vp3 { animation-delay: .36s; }
@keyframes vera-pt { 0%,60%,100% { opacity:.2 } 30% { opacity:1 } }

@media (prefers-reduced-motion: reduce) { .vera-cherche .vp { animation: none; } }
@media (max-width: 34rem) { .aide-hero { padding: var(--spacing-6) var(--spacing-4); } .aide-ask { padding: 0; } }


/* ═══ La bulle de Vera ════════════════════════════════════════════════
 * En bas à droite, sur les écrans de travail du professeur. Sur téléphone,
 * au-dessus de la barre d'onglets ; sur l'écran de composition, au-dessus de
 * la jauge. Elle s'efface quand on descend pour lire. */
.vera-bulle { position: fixed; z-index: 45; right: var(--spacing-6);
	bottom: calc( env( safe-area-inset-bottom, 0px ) + var(--spacing-6) );
	width: 60px; height: 60px; border-radius: var(--radius-full); border: 2px solid var(--color-ink); cursor: pointer;
	display: grid; place-items: center; padding: 0; background: var(--color-surface-raised);
	box-shadow: 0 4px 0 var(--color-ink), 0 10px 24px color-mix( in srgb, var(--color-ink) 18%, transparent );
	transition: transform .22s ease, opacity .22s ease; }
@supports not (color: color-mix(in srgb, red, blue)) { sur l'écran de composition, au-dessus de
 * la jauge. Elle s'efface quand on descend pour lire. */
.vera-bulle { box-shadow: 0 4px 0 var(--color-ink), 0 10px 24px rgba(59,42,36,0.18); } }
.vera-bulle:focus-visible { outline: 3px solid var(--color-primary); outline-offset: 3px; }
.vera-bulle.is-cachee { transform: translateY( 24px ) scale( .85 ); opacity: 0; pointer-events: none; }
.vera-bulle .vb-fermer { display: none; font-size: 30px; line-height: 1; color: var(--color-ink); }
.vera-bulle[aria-expanded="true"] .vb-visage { display: none; }
.vera-bulle[aria-expanded="true"] .vb-fermer { display: block; }
.vb-visage { display: grid; place-items: center; }

/* La pastille : combien de choses neuves vous attendent. Le chiffre est à
   l'encre, cerclé d'encre : il se lit sans la couleur, y compris pour une
   personne daltonienne. Au repos, elle ne bouge pas. */
.vb-pastille { position: absolute; z-index: 1; top: -6px; right: -8px; min-width: 24px; height: 24px; padding: 0 6px; box-sizing: border-box;
	display: grid; place-items: center; border-radius: var(--radius-full);
	font: 700 13px/1 var(--font-label), Nunito, sans-serif; font-variant-numeric: tabular-nums;
	color: var(--color-ink); background: var(--color-brand-corner);
	border: 2px solid var(--color-ink); box-shadow: 0 0 0 2px var(--color-surface-raised); }
.vera-bulle[aria-expanded="true"] .vb-pastille { display: none; }

/* À l'arrivée d'une nouveauté, une seule fois : une onde (deux passages) et
   un sautillement de Vera. Rien du tout si le mouvement est réduit. */
.vb.is-signal .vera-bulle::after { content: ""; position: absolute; inset: -2px; border-radius: inherit;
	border: 3px solid var(--color-brand-corner); opacity: 0; pointer-events: none;
	animation: vb-onde .8s ease-out .3s 2; }
@keyframes vb-onde { from { transform: scale( 1 ); opacity: .9; } to { transform: scale( 1.55 ); opacity: 0; } }
.vb.is-signal .vb-visage { animation: vb-saut .6s ease-in-out .3s 1; }
@keyframes vb-saut { 0%, 100% { transform: none; } 30% { transform: translateY( -5px ) rotate( -8deg ); } 60% { transform: translateY( 1px ) rotate( 5deg ); } }
@media ( prefers-reduced-motion: reduce ) { .vb.is-signal .vera-bulle::after, .vb.is-signal .vb-visage { animation: none; } }

.vm-scrim { position: fixed; inset: 0; z-index: 44; background: color-mix( in srgb, var(--color-ink) 30%, transparent ); }
@supports not (color: color-mix(in srgb, red, blue)) { .vm-scrim { background: rgba(59,42,36,0.30); } }
.vera-menu { position: fixed; z-index: 46; right: var(--spacing-6); width: min( 360px, calc( 100vw - 2 * var(--spacing-4) ) );
	bottom: calc( env( safe-area-inset-bottom, 0px ) + var(--spacing-6) + 72px );
	padding: 14px; border-radius: var(--radius-lg); background: var(--color-surface);
	border: 2px solid var(--color-ink); box-shadow: 0 4px 0 var(--color-ink), 0 16px 40px color-mix( in srgb, var(--color-ink) 22%, transparent );
	display: flex; flex-direction: column; gap: 8px; animation: vm-in .18s ease; }
@supports not (color: color-mix(in srgb, red, blue)) { .vera-menu { box-shadow: 0 4px 0 var(--color-ink), 0 16px 40px rgba(59,42,36,0.22); } }
.vera-menu[hidden], .vm-scrim[hidden] { display: none; }
@keyframes vm-in { from { opacity: 0; transform: translateY( 10px ) scale( .96 ); } to { opacity: 1; transform: none; } }
.vera-menu-tete { margin: 2px 4px 4px; font: 700 15px Fredoka, Nunito, sans-serif; color: var(--color-ink); }
.vm-choix { display: flex; align-items: center; gap: 12px; text-decoration: none;
	padding: 12px; border-radius: var(--radius-md); color: var(--color-ink);
	background: var(--color-surface-raised); border: 2px solid var(--color-line); }
.vm-choix:hover, .vm-choix:focus-visible { border-color: var(--color-primary); outline: none; }
.vm-mots { display: flex; flex-direction: column; gap: 1px; flex: 1; min-width: 0; }
.vm-mots b { font-size: 15.5px; }
.vm-mots span:not( .vm-compte ) { font-size: 13.5px; color: var(--color-ink-muted); }
.vm-ico { flex: none; width: 40px; height: 40px; border-radius: 12px; display: grid; place-items: center;
	font: 800 20px Fredoka, Nunito, sans-serif; color: var(--c, var(--color-primary)); background: color-mix( in srgb, var(--c, var(--color-primary)) 16%, transparent ); }
.vm-fleche { flex: none; font: 700 24px Fredoka, Nunito, sans-serif; color: var(--color-ink-faint); }
.vm-compte { display: inline-grid; place-items: center; min-width: 22px; height: 22px; padding: 0 6px; margin-left: 4px;
	border-radius: var(--radius-full); font-size: 12.5px; font-weight: 800; color: var(--color-ink); background: var(--color-brand-corner);
	box-shadow: inset 0 0 0 1.5px var(--color-ink); vertical-align: 2px; }

/* Au-dessus de la jauge de composition, où qu'elle soit. */
body:has( .compose-wizard.is-live ) .vera-bulle { bottom: calc( env( safe-area-inset-bottom, 0px ) + var(--spacing-3) + 80px ); }
body:has( .compose-wizard.is-live ) .vera-menu { bottom: calc( env( safe-area-inset-bottom, 0px ) + var(--spacing-3) + 152px ); }

@media ( max-width: 40rem ) {
	.vera-bulle { right: var(--spacing-4); bottom: calc( env( safe-area-inset-bottom, 0px ) + 88px ); }
	.vera-menu { right: var(--spacing-4); bottom: calc( env( safe-area-inset-bottom, 0px ) + 160px ); }
	body:has( .compose-wizard.is-live ) .vera-bulle { bottom: calc( env( safe-area-inset-bottom, 0px ) + 150px ); }
	body:has( .compose-wizard.is-live ) .vera-menu { bottom: calc( env( safe-area-inset-bottom, 0px ) + 222px ); }
}

/* Le bas des pages garde la place de la bulle : la dernière carte ne doit
   jamais finir dessous. */
body:has( .vera-bulle ) .wrap { padding-bottom: 96px; }

@media ( prefers-reduced-motion: reduce ) {
	.vera-menu { animation: none; }
	.vera-bulle { transition: none; }
}

/* « Quoi de neuf » : ce qui est arrivé depuis la dernière visite se signale
   par son bord et un mot, sans clignoter. */
.vn-carte { border: 2px solid transparent; }
.vn-carte.is-nouveau { border-color: color-mix( in srgb, var(--color-brand-corner) 50%, transparent ); }
@supports not (color: color-mix(in srgb, red, blue)) { .vn-carte.is-nouveau { border-color: rgba(232,114,79,0.50); } }
.vn-neuf { font-weight: 800; color: var(--color-brand-corner); }
.vn-lien { color: var(--color-primary); font-weight: 700; text-decoration: none; margin-top: 2px; }
.vn-lien:hover { text-decoration: underline; }

/* « Quoi de neuf » : nouveautés et idées en lignes qui se déplient. */
.nv-sec{display:flex;align-items:center;gap:var(--spacing-3);margin-top:var(--spacing-8);margin-bottom:var(--spacing-3)}
.nv-sec h2{margin:0}
.nv-sec .nv-nb{font:700 12px/1 Nunito,sans-serif;padding:4px 9px;border-radius:99px;background:var(--color-surface-sunken);color:var(--color-ink-muted)}
.nv-sec hr{flex:1;border:0;border-top:2px solid var(--color-line);margin:0}
.nv-badge{flex:none;width:48px;height:48px;border-radius:var(--radius-md);background:var(--color-primary-soft);display:grid;place-items:center;font-size:24px}
.nv-date{font-size:13px;font-weight:700;color:var(--color-ink-faint)}
.nv-pastille{font:800 12px/1 Nunito,sans-serif;padding:4px 10px;border-radius:99px;background:var(--color-brand-corner);color:#fff;letter-spacing:.02em}
.nv-cta{color:var(--color-primary);font-weight:700;text-decoration:none;display:inline-block;margin-top:var(--spacing-2)}
.nv-cta:hover{text-decoration:underline}
/* Vos idées : la progression se voit */
.nv-idees{list-style:none;margin:var(--spacing-4) 0 0;padding:0;display:grid;gap:var(--spacing-4);grid-template-columns:repeat(auto-fit,minmax(min(100%,320px),1fr))}
.nv-idee{background:var(--color-surface-raised);border:2px solid color-mix(in srgb,var(--color-brand-corner) 50%,transparent);border-radius:var(--radius-xl);padding:var(--spacing-4);display:flex;flex-direction:column;gap:var(--spacing-2)}
.nv-idee-t{display:flex;flex-direction:column;gap:2px}.nv-idee-t b{font:600 17px/1.3 Fredoka,sans-serif}
.nv-role{font-size:13px;font-weight:700;color:var(--color-ink-faint)}
.nv-idee p{margin:0;font-size:14px;font-weight:600;color:var(--color-ink-muted)}
.nv-etapes{list-style:none;margin:var(--spacing-2) 0;padding:0;display:grid;grid-template-columns:repeat(4,1fr);position:relative}
.nv-etapes li{display:flex;flex-direction:column;align-items:center;gap:6px;position:relative;font-size:12px;font-weight:700;color:var(--color-ink-faint);text-align:center}
.nv-etapes li::before{content:"";position:absolute;top:8px;left:-50%;width:100%;height:4px;background:var(--color-line);z-index:0}
.nv-etapes li:first-child::before{display:none}
.nv-etapes li.is-fait::before,.nv-etapes li.is-ici::before{background:var(--color-primary)}
.nv-etapes i{position:relative;z-index:1;width:20px;height:20px;border-radius:50%;background:var(--color-surface-raised);border:3px solid var(--color-line)}
.nv-etapes li.is-fait i{background:var(--color-primary);border-color:var(--color-primary)}
.nv-etapes li.is-ici i{border-color:var(--color-primary);box-shadow:0 0 0 4px var(--color-primary-soft);background:var(--color-surface-raised)}
.nv-etapes li.is-ici{color:var(--color-primary-active)}
.nv-sec-premier{margin-top:0}
.nv-vide{margin-top:var(--spacing-3);color:var(--color-ink-muted);font-weight:600}
/* Le reste : une ligne par nouveauté, qui se déplie */
.nv-mois{margin:var(--spacing-5) 0 var(--spacing-2);font:500 12px/1.3 Fredoka,sans-serif;letter-spacing:.06em;text-transform:uppercase;color:var(--color-ink-faint)}
.nv-liste{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:var(--spacing-2)}
.nv-ligne{background:var(--color-surface-raised);border-radius:var(--radius-lg)}
.nv-ligne summary{list-style:none;cursor:pointer;display:flex;align-items:center;gap:var(--spacing-3);padding:var(--spacing-3) var(--spacing-4);min-height:56px}
.nv-ligne summary::-webkit-details-marker{display:none}
.nv-ligne .nv-badge{width:36px;height:36px;font-size:18px;border-radius:var(--radius-sm)}
.nv-titre{flex:1;min-width:0;font:600 16px/1.3 Fredoka,sans-serif;color:var(--color-ink)}
.nv-plus{flex:none;width:12px;height:12px;border-right:3px solid var(--color-ink-faint);border-bottom:3px solid var(--color-ink-faint);transform:rotate(45deg);margin:0 4px 4px 4px;transition:transform .15s}
.nv-ligne[open] .nv-plus{transform:rotate(-135deg);margin-top:6px}
.nv-ligne.is-nouveau{border:2px solid color-mix(in srgb,var(--color-brand-corner) 50%,transparent)}
.nv-ligne.is-nouveau .nv-badge{background:var(--color-lang-es-soft)}
.nv-ligne summary:hover .nv-titre{color:var(--color-primary-active)}
.nv-ligne summary:focus-visible{outline:3px solid var(--color-primary);outline-offset:2px;border-radius:var(--radius-lg)}
.nv-corps{padding:0 var(--spacing-4) var(--spacing-4) calc(var(--spacing-4) + 36px + var(--spacing-3))}
.nv-corps p{margin:0;font-size:15px;line-height:1.5;color:var(--color-ink-muted);font-weight:600}
@media (max-width:32rem){.nv-date{display:none}.nv-ligne summary{flex-wrap:wrap}.nv-pastille{order:3}.nv-corps{padding-left:var(--spacing-4)}.nv-ligne summary{padding:var(--spacing-3)}}

/* ═══ Mot du jour, deuxième temps, sur téléphone ══════════════════════════
 * Les tailles des phrases ci-dessus se mesurent en hauteur (`vh`), pour un
 * vidéoprojecteur. Sur un téléphone tenu debout, 6,2vh font une cinquantaine
 * de pixels : la phrase occupait l'écran. Et ces règles, plus précises que
 * les plafonds du téléphone, passaient par-dessus. Mêmes sélecteurs, plus
 * loin dans la feuille, mesurés en largeur. */
@media (max-width: 48rem) {
	.proj-shell[data-vd-phases].is-phase-2 .proj-panel [data-row] .t-proj-a { font-size: clamp(16px, 4.6vw, 22px); }
	.proj-shell[data-vd-phases].is-phase-2 .proj-panel > .t-eyebrow + [data-row] .t-proj-a { font-size: clamp(19px, 5.6vw, 26px); }
	.proj-shell[data-vd-phases].is-phase-2 .proj-panel > .t-eyebrow,
	.proj-shell[data-vd-phases].is-phase-2 .proj-panel .proj-eyebrow-label { font-size: clamp(12px, 3.4vw, 14px); }
}

/* ═══ Les modules en test de 0.100.0 ═══════════════════════════════════════
 * Des étiquettes de mots, côte à côte : les mots mélangés d'une phrase, les
 * deux mots d'une paire, les mots utiles d'une question. Au trait clair sur
 * le fond sombre de la scène, et à la taille d'une réponse : on les lit du
 * fond de la salle. */
.word-chips { display: flex; flex-wrap: wrap; gap: 12px; }
.word-chip {
	display: inline-flex; align-items: center; padding: .25em .7em; border-radius: 16px;
	border: 2px solid color-mix( in srgb, var(--color-proj-ink) 40%, transparent );
	background: color-mix( in srgb, var(--color-proj-ink) 10%, transparent );
	color: var(--color-proj-ink); font-family: Fredoka, sans-serif; font-weight: 600;
	font-size: calc( clamp( 22px, 4.6vh, 52px ) * var(--proj-fit, 1) ); line-height: 1.15;
}
@supports not (color: color-mix(in srgb, red, blue)) { .word-chip { border: 2px solid rgba(255,246,233,0.40); background: rgba(255,246,233,0.10); } }
.word-chip b { color: var(--color-gold); margin-right: .15em; }

/* Une ligne pas encore dévoilée cache ses étiquettes comme ses réponses :
 * lisibles en grisé, les « mots utiles » se donnaient avant leur tour. */
.proj-row[data-row][aria-hidden="true"] .word-chip b { color: transparent; }

/* Une étiquette au-dessus de sa ligne, et non dans la colonne des étiquettes :
 * quand la ligne s'empile, la colonne de vingt caractères n'a plus de voisine
 * à aligner, et poussait l'étiquette au milieu de nulle part. */
body.projection .proj-shell:not([data-vd-solo]) .proj-row.proj-row-stack > .t-eyebrow:first-child { width: auto; text-align: left; }

@media ( max-width: 48rem ) {
	.word-chips { gap: 8px; }
	.word-chip { font-size: clamp( 17px, 5vw, 24px ); border-radius: 12px; }
}

/* ═══ La Bibliothèque : le catalogue des modules (0.101.0) ════════════════ */
.cat-seg { display: inline-flex; gap: 4px; padding: 4px; border-radius: var(--radius-full); background: var(--color-surface-sunken); }
.cat-seg a { font: 700 15px Nunito, sans-serif; border-radius: var(--radius-full); padding: 8px 18px; text-decoration: none; color: var(--color-ink-muted); }
.cat-seg a[aria-current="page"] { background: var(--color-surface-raised); color: var(--color-ink); box-shadow: 0 1px 0 var(--color-line-strong); }
.cat-filtres { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px; }
.cat-filtres .cat-langs { flex: 1 1 auto; min-width: 0; }
.cat-langs, .cat-fams { display: flex; gap: 8px; overflow-x: auto; padding-bottom: 4px; scrollbar-width: none; }
/* Les langues en pastilles ; tout le reste (familles, niveau, durée, statut, tri) derrière une icône « Filtres et tri ». */
.cat-fbtn { position: relative; display: inline-flex; align-items: center; gap: 8px; min-height: 44px; padding: 0 16px 0 12px; border: 2px solid var(--color-line-strong); border-radius: var(--radius-full); background: var(--color-surface-raised); color: var(--color-ink); font: 700 14px Nunito, sans-serif; cursor: pointer; }
.cat-fbtn[hidden], .cat-actifs[hidden], .cat-fvoile[hidden], .cat-panneau[hidden], .cat-fbadge[hidden], .cat-fsec .nb[hidden] { display: none; }
.cat-fbtn svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; }
.cat-fbtn[aria-expanded="true"] { border-color: var(--color-ink); box-shadow: 0 3px 0 var(--color-ink); }
.cat-fbtn:focus-visible { outline: 3px solid var(--color-primary); outline-offset: 2px; }
.cat-fbadge { display: inline-grid; place-items: center; min-width: 22px; height: 22px; padding: 0 6px; border-radius: var(--radius-full); background: var(--color-primary); color: #fff; font: 800 12px Nunito, sans-serif; }
.cat-actifs { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 12px; }
.cat-puce { display: inline-flex; align-items: center; gap: 6px; min-height: 36px; padding: 0 6px 0 12px; border: 2px solid var(--color-primary); border-radius: var(--radius-full); background: var(--color-primary-soft); color: var(--color-primary-active); font: 800 13px Nunito, sans-serif; }
.cat-puce button { display: grid; place-items: center; width: 28px; height: 28px; border: 0; border-radius: var(--radius-full); background: transparent; color: inherit; font: 800 16px/1 Nunito, sans-serif; cursor: pointer; }
.cat-puce button:hover { background: var(--color-primary-soft); }
.cat-puce button:focus-visible, .cat-raz:focus-visible { outline: 3px solid var(--color-primary); outline-offset: 1px; }
.cat-raz { min-height: 36px; padding: 0; border: 0; background: transparent; color: var(--color-primary-active); font: 800 13px Nunito, sans-serif; text-decoration: underline; cursor: pointer; }

/* Le panneau : à droite sur un grand écran, en feuille sur un téléphone. */
.cat-fvoile { position: fixed; inset: 0; z-index: 60; background: rgba( 59, 42, 36, .45 ); }
.cat-panneau { position: fixed; top: 0; right: 0; bottom: 0; z-index: 61; width: min( 400px, 100vw ); display: flex; flex-direction: column; background: var(--color-surface-raised); border-left: 2px solid var(--color-ink); padding-top: env( safe-area-inset-top, 0px ); }
.cat-panneau header { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 16px 16px 12px; border-bottom: 2px solid var(--color-line); }
.cat-panneau header h2 { font: 600 20px var(--font-title-module), sans-serif; margin: 0; }
.cat-fx { display: grid; place-items: center; width: 44px; height: 44px; border: 0; border-radius: var(--radius-full); background: transparent; color: var(--color-ink); font: 800 22px/1 Nunito, sans-serif; cursor: pointer; }
.cat-fx:hover { background: var(--color-surface-sunken); }
.cat-fx:focus-visible { outline: 3px solid var(--color-primary); outline-offset: 2px; }
.cat-fcorps { flex: 1 1 auto; overflow: auto; padding: 8px 16px; }
.cat-panneau footer { display: flex; gap: 8px; padding: 12px 16px calc( 12px + env( safe-area-inset-bottom, 0px ) ); border-top: 2px solid var(--color-line); }
.cat-panneau footer .btn-primary { flex: 1 1 auto; }
.cat-faide { margin: 0; padding: 6px 4px; color: var(--color-ink-muted); font: 600 12px Nunito, sans-serif; }
.cat-fsec { padding: 8px 0; border-bottom: 2px solid var(--color-line); }
.cat-fsec:last-child { border-bottom: 0; }
.cat-fsec > summary { display: flex; align-items: center; gap: 8px; min-height: 44px; list-style: none; cursor: pointer; color: var(--color-ink-muted); font: 800 13px Nunito, sans-serif; letter-spacing: .06em; text-transform: uppercase; }
.cat-fsec > summary::-webkit-details-marker { display: none; }
.cat-fsec > summary::after { content: "▾"; margin-left: auto; font-size: 14px; transition: rotate .15s; }
.cat-fsec:not([open]) > summary::after { rotate: -90deg; }
.cat-fsec > summary:focus-visible { outline: 3px solid var(--color-primary); outline-offset: 2px; border-radius: var(--radius-md); }
.cat-fsec .nb { display: inline-grid; place-items: center; min-width: 20px; height: 20px; padding: 0 6px; border-radius: var(--radius-full); background: var(--color-primary); color: #fff; font: 800 12px Nunito, sans-serif; letter-spacing: 0; }
.cat-fsec .val { color: var(--color-primary-active); font: 700 13px Nunito, sans-serif; letter-spacing: 0; text-transform: none; }
.cat-fliste { display: flex; flex-direction: column; gap: 2px; margin-top: 4px; }
.cat-fopt { display: flex; align-items: center; gap: 10px; min-height: 44px; padding: 0 10px; border-radius: var(--radius-md); cursor: pointer; font: 700 15px Nunito, sans-serif; }
.cat-fopt:hover { background: var(--color-primary-soft); }
.cat-fopt input { flex: none; width: 20px; height: 20px; margin: 0; accent-color: var(--color-primary); }
.cat-fopt:has( input:checked ) { background: var(--color-primary-soft); color: var(--color-primary-active); }
.cat-fopt:has( input:focus-visible ) { outline: 3px solid var(--color-primary); outline-offset: -3px; }
.cat-fopt .n { margin-left: auto; color: var(--color-ink-muted); font: 700 13px Nunito, sans-serif; }
.cat-fopt.is-zero:not( :has( input:checked ) ) { opacity: .55; }
.cat-fpuces { display: flex; flex-wrap: wrap; gap: 8px; padding: 4px 0 8px; }
.cat-fpuces label { position: relative; display: inline-flex; align-items: center; gap: 6px; min-height: 40px; padding: 0 14px; border: 2px solid var(--color-line-strong); border-radius: var(--radius-full); background: var(--color-surface-raised); font: 700 14px Nunito, sans-serif; cursor: pointer; }
.cat-fpuces label input { position: absolute; opacity: 0; inset: 0; margin: 0; cursor: pointer; }
.cat-fpuces label:has( input:checked ) { background: var(--color-primary-soft); border-color: var(--color-primary); color: var(--color-primary-active); }
.cat-fpuces label:has( input:checked )::before { content: "✓"; font-weight: 800; }
.cat-fpuces label:has( input:focus-visible ) { outline: 3px solid var(--color-primary); outline-offset: 2px; }
.cat-fpuces label .n { color: var(--color-ink-muted); font: 700 12px Nunito, sans-serif; }
.cat-fpuces label.is-zero:not( :has( input:checked ) ) { opacity: .45; }
@media ( max-width: 560px ) {
	.cat-panneau { top: auto; left: 0; right: 0; width: auto; max-height: 86vh; border-left: 0; border-top: 2px solid var(--color-ink); border-radius: var(--radius-lg) var(--radius-lg) 0 0; }
}
@media ( prefers-reduced-motion: reduce ) { .cat-fsec > summary::after { transition: none; } }
.cat-langs button, .cat-fams button { flex: none; font: 700 14px Nunito, sans-serif; padding: 7px 14px; border-radius: var(--radius-full); cursor: pointer;
	border: 2px solid var(--color-line-strong); background: var(--color-surface-raised); color: var(--color-ink); }
.cat-langs button[aria-pressed="true"] { background: var(--color-ink); border-color: var(--color-ink); color: var(--color-surface); }
.cat-fams button[aria-pressed="true"] { background: var(--color-primary-soft); border-color: var(--color-primary); color: var(--color-primary); }
.cat-langs button:focus-visible, .cat-fams button:focus-visible, .cat-choix button:focus-visible { outline: 3px solid var(--color-primary); outline-offset: 2px; }
.cat-grille { display: grid; gap: 14px; grid-template-columns: repeat( auto-fit, minmax( 290px, 1fr ) ); padding: 0; }
.cat-carte { display: flex; flex-direction: column; gap: 10px; padding: 16px; border-radius: var(--radius-lg); background: var(--color-surface-raised); border: 2px solid var(--color-line); min-width: 0; }
.cat-tete { display: flex; gap: 12px; align-items: center; }
.cat-tete > :first-child { flex: none; }
.cat-nom { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; }
.cat-meta { font-size: 13px; color: var(--color-ink-muted); }
.cat-dans { font-size: 13px; color: var(--color-success-strong); font-weight: 700; }
.cat-actions { display: flex; flex-wrap: wrap; gap: 10px 6px; margin-top: auto; }
/* Les boutons d'une carte (Essayer / Gérer / Fiche) tiennent sur une ligne :
 * marges latérales resserrées, libellé jamais coupé ; le retour à la ligne
 * reste le secours des écrans très étroits et des libellés les plus longs. */
.cat-actions .btn-sm { padding-inline: var(--spacing-3); white-space: nowrap; }
.cat-lock { font-size: 12px; border-radius: var(--radius-full); padding: 1px 9px; background: var(--color-surface-sunken); color: var(--color-ink-muted); }
.cat-voile { position: fixed; inset: 0; z-index: 90; background: color-mix( in srgb, var(--color-ink) 40%, transparent ); }
@supports not (color: color-mix(in srgb, red, blue)) { .cat-voile { background: rgba(59,42,36,0.40); } }
.cat-voile[hidden] { display: none; }
.cat-volet { position: fixed; z-index: 91; left: 0; right: 0; bottom: 0; max-height: 88vh; overflow-y: auto; padding: 10px 20px calc( 20px + env( safe-area-inset-bottom, 0px ) );
	background: var(--color-surface); border-radius: 22px 22px 0 0; box-shadow: 0 -10px 40px color-mix( in srgb, var(--color-ink) 22%, transparent );
	transform: translateY( 105% ); transition: transform .24s ease; visibility: hidden; }
@supports not (color: color-mix(in srgb, red, blue)) { .cat-volet { box-shadow: 0 -10px 40px rgba(59,42,36,0.22); } }
.cat-volet.is-open { transform: none; visibility: visible; }
@media ( min-width: 48rem ) {
	.cat-volet { left: 50%; right: auto; width: 460px; margin-left: -230px; bottom: auto; top: 6vh; max-height: 88vh; border-radius: 22px; transform: translateY( 20px ); opacity: 0; transition: opacity .2s, transform .2s; }
	.cat-volet.is-open { transform: none; opacity: 1; }
}
@media ( prefers-reduced-motion: reduce ) { .cat-volet { transition: none; } }
.cat-grip { width: 44px; height: 5px; border-radius: var(--radius-full); background: var(--color-line-strong); margin: 0 auto 12px; }
.cat-fermer { flex: none; width: 40px; height: 40px; border-radius: var(--radius-full); border: 0; background: var(--color-surface-sunken); font-size: 22px; cursor: pointer; color: var(--color-ink); }
.cat-choix { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.cat-choix button { font: 700 15px Nunito, sans-serif; min-width: 64px; padding: 9px 14px; border-radius: 12px; cursor: pointer; border: 2px solid var(--color-line-strong); background: var(--color-surface-raised); color: var(--color-ink); }
.cat-choix button[aria-pressed="true"] { border-color: var(--color-primary); background: var(--color-primary-soft); color: var(--color-primary); }
.cat-choix button:disabled { opacity: .4; cursor: not-allowed; }
.cat-classes { display: flex; flex-direction: column; gap: 8px; margin-top: 8px; }
.cat-classe { display: flex; align-items: center; gap: 10px; min-height: 48px; padding: 10px 14px; border-radius: 12px;
	background: var(--color-surface-sunken); color: var(--color-ink); text-decoration: none; font-weight: 700; font-size: 15px; }
.cat-classe > span:last-child { margin-left: auto; color: var(--color-primary); font-size: 14px; }
.cat-classe:focus-visible { outline: 3px solid var(--color-primary); outline-offset: 2px; }

/* La barre de défilement des volets : fine, aux couleurs du produit, et
 * tenue à l'écart des coins arrondis. La barre système, grise et carrée,
 * débordait sur l'arrondi du volet (signalé le 6 octobre 2026). */
.cat-volet, .vera-menu {
	scrollbar-width: thin;
	scrollbar-color: color-mix( in srgb, var(--color-ink) 28%, transparent ) transparent;
}
@supports not (color: color-mix(in srgb, red, blue)) { /* La barre de défilement des volets : fine, aux couleurs du produit, et
 * tenue à l'écart des coins arrondis. La barre système, grise et carrée,
 * débordait sur l'arrondi du volet (signalé le 6 octobre 2026). */
.cat-volet, .vera-menu { scrollbar-color: rgba(59,42,36,0.28) transparent; } }
.cat-volet::-webkit-scrollbar, .vera-menu::-webkit-scrollbar { width: 10px; }
.cat-volet::-webkit-scrollbar-track, .vera-menu::-webkit-scrollbar-track { background: transparent; margin-block: 22px; }
.cat-volet::-webkit-scrollbar-thumb, .vera-menu::-webkit-scrollbar-thumb {
	background: color-mix( in srgb, var(--color-ink) 28%, transparent );
	border-radius: var(--radius-full);
	border: 3px solid transparent;
	background-clip: padding-box;
}
@supports not (color: color-mix(in srgb, red, blue)) { .cat-volet::-webkit-scrollbar-thumb, .vera-menu::-webkit-scrollbar-thumb { background: rgba(59,42,36,0.28); } }
.cat-volet::-webkit-scrollbar-thumb:hover, .vera-menu::-webkit-scrollbar-thumb:hover { background-color: color-mix( in srgb, var(--color-ink) 45%, transparent ); }
@supports not (color: color-mix(in srgb, red, blue)) { .cat-volet::-webkit-scrollbar-thumb:hover, .vera-menu::-webkit-scrollbar-thumb:hover { background-color: rgba(59,42,36,0.45); } }
.cat-volet::-webkit-scrollbar-button, .vera-menu::-webkit-scrollbar-button { display: none; height: 0; }

/* La question d'avis à la fin d'un essai : trois boutons, en ligne puis empilés. */
.proj-avis { display: grid; gap: var(--spacing-3); padding-top: var(--spacing-4); border-top: 1px solid color-mix( in srgb, var(--color-proj-ink) 20%, transparent ); }
@supports not (color: color-mix(in srgb, red, blue)) { /* La question d'avis à la fin d'un essai : trois boutons, en ligne puis empilés. */
.proj-avis { border-top: 1px solid rgba(255,246,233,0.20); } }
.proj-avis-choix { display: flex; flex-wrap: wrap; gap: var(--spacing-3); }
.proj-avis-choix .proj-btn { font-size: clamp( 16px, 2.2vh, 24px ); }

/* Le volet d'avis sur un module en test : trois choix francs, deux lignes
 * facultatives. Le choix suffit pour envoyer. */
.av-choix { display: grid; gap: 8px; margin-top: 12px; }
.av-choix label { display: flex; align-items: center; gap: 12px; font: 700 16px Nunito, sans-serif; padding: 12px 14px; border-radius: 14px; cursor: pointer;
	border: 2px solid var(--color-line-strong); background: var(--color-surface-raised); color: var(--color-ink); min-height: 56px; }
.av-choix label small { display: block; font-weight: 500; font-size: 13px; color: var(--color-ink-muted); }
.av-choix .av-e { font-size: 22px; width: 28px; text-align: center; flex: none; }
.av-choix label:has(input:checked) { border-color: var(--color-primary); background: var(--color-primary-soft); }
.av-choix label:has(input:focus-visible) { outline: 3px solid var(--color-primary); outline-offset: 2px; }
.av-plus summary { cursor: pointer; font-weight: 700; color: var(--color-primary); margin-top: 14px; list-style: none; }
.av-plus summary::-webkit-details-marker { display: none; }

/* L'annonce des nouveautés : un module en entier, les autres en une ligne. */
.newish-try { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; margin-top: 10px; }
.newish-more { display: flex; align-items: center; gap: 10px; margin-top: 14px; padding: 10px 12px; border-radius: 12px;
	background: var(--color-surface-sunken); color: var(--color-ink); text-decoration: none; font-weight: 700; font-size: 15px; }
.newish-more-icons { display: flex; flex: none; }
.newish-more-icons > * { transform: scale( .7 ); margin-right: -10px; }

/* L'accueil (première visite) : un carnet de six pages, posé sur Mes classes.
 * Volet en bas sur téléphone, fenêtre au centre sur un écran large. */
body.ob-ouvert { overflow: hidden; }
.ob-voile { position: fixed; inset: 0; z-index: 90; background: color-mix( in srgb, var(--color-ink) 45%, transparent ); }
@supports not (color: color-mix(in srgb, red, blue)) { .ob-voile { background: rgba(59,42,36,0.45); } }
.ob { position: fixed; z-index: 91; left: 0; right: 0; bottom: 0; max-height: 92vh; overflow-y: auto; display: flex; flex-direction: column; gap: 14px; margin: 0;
	padding: 14px 20px calc( 18px + env( safe-area-inset-bottom, 0px ) ); background: var(--color-surface); border-radius: 24px 24px 0 0;
	box-shadow: 0 -10px 40px color-mix( in srgb, var(--color-ink) 22%, transparent );
	scrollbar-width: thin; scrollbar-color: color-mix( in srgb, var(--color-ink) 28%, transparent ) transparent; }
@supports not (color: color-mix(in srgb, red, blue)) { .ob { box-shadow: 0 -10px 40px rgba(59,42,36,0.22); scrollbar-color: rgba(59,42,36,0.28) transparent; } }
@media ( min-width: 48rem ) { .ob { left: 50%; right: auto; bottom: auto; top: 6vh; width: 480px; margin-left: -240px; border-radius: 24px; max-height: 88vh; } }
.ob-tete { display: flex; align-items: center; gap: 12px; }
.ob-points { display: flex; gap: 6px; flex: 1; }
.ob-point { height: 6px; flex: 1; max-width: 40px; border-radius: var(--radius-full); background: var(--color-line-strong); }
.ob-point.is-on { background: var(--color-primary); }
.ob-passer { border: 0; background: none; font: 700 14px Nunito, sans-serif; color: var(--color-ink-muted); cursor: pointer; padding: 8px; min-height: 40px; }
.ob-passer:focus-visible { outline: 3px solid var(--color-primary); outline-offset: 2px; border-radius: 8px; }
.ob-etape { display: flex; flex-direction: column; gap: 10px; text-align: center; }
.ob-etape[hidden] { display: none; }
.ob-etape .field { text-align: left; margin-top: 4px; }
.ob-illu { min-height: 150px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; padding: 16px; border-radius: 18px; background: var(--color-surface-sunken); }
.ob-titre { margin: 4px 0 0; text-wrap: balance; }
.ob-vera { display: flex; align-items: center; gap: 10px; }
.ob-bulle { font: 700 16px Nunito, sans-serif; background: var(--color-surface-raised); border: 2px solid var(--color-line-strong); border-radius: 16px 16px 16px 4px; padding: 8px 14px; }
.ob-mini { width: 100%; margin: 0; text-align: left; }
.ob-badges { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; }
.ob-chip { font: 700 14px Nunito, sans-serif; color: #fff; background: var(--color-primary); padding: 6px 14px; border-radius: var(--radius-full); }
.ob-tutos { list-style: none; margin: 0; padding: 0; width: 100%; display: grid; gap: 8px; text-align: left; }
.ob-tuto { display: flex; align-items: center; gap: 10px; background: var(--color-surface-raised); border-radius: 12px; padding: 8px 10px; }
.ob-tuto b { font-size: 14.5px; display: block; }
.ob-tuto .col > span { font-size: 13px; color: var(--color-ink-muted); }
.ob-play { flex: none; width: 34px; height: 34px; border-radius: 10px; display: grid; place-items: center; background: #e62117; color: #fff; font-size: 13px; }
.ob-choix { display: grid; gap: 8px; width: 100%; text-align: left; }
.ob-reseaux { display: grid; gap: 8px; width: 100%; }
.ob-reseau { display: flex; justify-content: space-between; align-items: center; min-height: 44px; padding: 10px 14px; border-radius: 12px; font: 700 15px Nunito, sans-serif;
	color: #fff; background: var(--c, var(--color-ink)); text-decoration: none; }
.ob-reseau span { font-weight: 600; opacity: .9; }
.ob-reseau:focus-visible { outline: 3px solid var(--color-primary); outline-offset: 2px; }
.ob-pied { display: flex; gap: 10px; }
.ob-pied [hidden] { display: none; }
/* La demande du pays : sur petit écran, en haut et sans illustration, pour que la liste des pays ait de la place sous le champ. */
@media ( max-width: 47.99rem ) { .ob-pays { top: 0; bottom: auto; min-height: 62vh; border-radius: 0 0 24px 24px; padding-top: calc( 18px + env( safe-area-inset-top, 0px ) ); } .ob-pays .ob-illu { display: none; } }


/* Les modules en test, expliqués là où on les voit (0.103.15).
 * L'encart du catalogue se replie en deux lignes ; le rappel, lui, se pose
 * dans le volet d'un module et en tête de la composition. */
.cat-test {
	border: 2px solid var(--color-brand-band);
	border-radius: var(--radius-lg);
	background: var(--color-brand-paper);
	padding: var(--spacing-3) var(--spacing-4);
}
.cat-test summary { list-style: none; cursor: pointer; display: flex; gap: var(--spacing-3); align-items: flex-start; }
.cat-test summary::-webkit-details-marker { display: none; }
.cat-test-ico { font-size: 24px; line-height: 1; }
.cat-test-plus { color: var(--color-primary); font-weight: 800; }
.cat-test[open] .cat-test-plus { display: none; }
.cat-test ul { margin: var(--spacing-3) 0 0; padding: 0; list-style: none; display: grid; gap: var(--spacing-2); }
.cat-test li { display: flex; gap: var(--spacing-2); }
.cat-test li > span:first-child { flex: none; width: 1.4em; text-align: center; }
.avert-test {
	border-left: 4px solid var(--color-brand-band);
	background: var(--color-brand-paper);
	border-radius: 0 var(--radius-md) var(--radius-md) 0;
	padding: var(--spacing-2) var(--spacing-3);
}
.avert-test a { font-weight: 800; }
.compose-beta-note { display: none; margin-top: var(--spacing-1); color: var(--color-ink); font-weight: 700; }
.compose-module:has(input:checked) .compose-beta-note { display: block; }

/* Le témoignage (0.104) : un volet sur « Mes classes », les mêmes pièces que
 * l'avis sur un module en test. Les étoiles sont des boutons radio : elles
 * se choisissent au clavier, et le formulaire marche sans script. */
.te-volet .te-ico { font-size: 30px; line-height: 1; }
.te-bloc { border: 0; margin: 0; padding: 0; min-width: 0; }
.te-bloc legend { padding: 0; }
.te-reseaux { display: flex; gap: var(--spacing-3); align-items: flex-start; padding: var(--spacing-3); border: 2px solid var(--color-line); border-radius: var(--radius-md); background: var(--color-surface-raised); cursor: pointer; }
.te-reseaux input { margin-top: 3px; }
.te-reseaux small { display: block; color: var(--color-ink-muted); font-weight: 600; margin-top: 2px; }
.te-etoiles { display: flex; gap: var(--spacing-1); margin-top: var(--spacing-2); }
.te-etoiles label { font-size: 34px; line-height: 1; padding: var(--spacing-1); cursor: pointer; color: var(--color-line-strong); border-radius: var(--radius-md); }
.te-etoiles label.on { color: var(--color-gold-strong); }
.te-etoiles label:has(input:focus-visible) { outline: 3px solid var(--color-primary); outline-offset: 2px; }
.te-puces { display: flex; flex-wrap: wrap; gap: var(--spacing-2); margin-top: var(--spacing-2); }
.te-puces[hidden] { display: none; }
.te-puces label { display: inline-flex; align-items: center; gap: 6px; padding: var(--spacing-2) var(--spacing-3); min-height: 40px; border: 2px solid var(--color-line-strong); border-radius: var(--radius-full); font: 700 15px Nunito, sans-serif; cursor: pointer; background: var(--color-surface-raised); color: var(--color-ink); }
.te-puces input { accent-color: var(--color-primary); }
.te-puces label:has(input:checked) { border-color: var(--color-primary); background: var(--color-primary-soft); color: var(--color-primary); }
.te-puces small { font-weight: 500; font-size: 12px; color: var(--color-ink-muted); }
.te-puces small:empty { display: none; }
.te-apercu { margin-top: var(--spacing-3); padding: var(--spacing-3) var(--spacing-4); border-radius: var(--radius-md); background: var(--color-brand-paper); border: 1px solid var(--color-line); }
.te-apercu q { display: block; margin-top: var(--spacing-1); quotes: "« " " »"; }
.te-apercu .te-note { color: var(--color-gold-strong); letter-spacing: 2px; }
.te-apercu .te-qui { display: block; margin-top: var(--spacing-2); font-weight: 800; font-size: 14px; color: var(--color-ink-muted); }
.te-sorties { display: flex; justify-content: center; flex-wrap: wrap; gap: var(--spacing-2); }
.te-lien { background: none; border: 0; padding: 0; font: inherit; font-weight: 700; color: var(--color-primary); text-decoration: underline; cursor: pointer; }
.te-merci { text-align: center; padding: var(--spacing-6) 0; }
.te-merci-ico { font-size: 48px; line-height: 1; }
.te-volet .te-bloc + .te-bloc,
.te-volet .field + .te-bloc { margin-top: var(--spacing-5); }
.te-volet .te-bloc legend { margin-bottom: var(--spacing-1); }

/* ── Les éditions limitées (0.105) ───────────────────────────────────
 * Une carte de nuit sur « Mes classes », une guirlande de papel picado, et
 * au tableau quatre dessins, un texte, un vrai ou faux. Les couleurs de la
 * guirlande sont celles d'une fête, pas de la charte : elles restent
 * littérales, et cantonnées à ce décor. */
.ed-carte { position: relative; overflow: hidden; border-radius: 22px; padding: 18px 18px 16px; background: #2b1d3a; color: #fff7ea; border: 3px solid var(--color-ink); box-shadow: 0 5px 0 var(--color-ink); }
.ed-picado { position: absolute; left: 10px; right: 10px; top: 0; display: flex; gap: 4px; }
.ed-picado i, .ed-decor i { flex: 1; height: 22px; clip-path: polygon( 0 0, 100% 0, 100% 70%, 85% 100%, 70% 70%, 50% 100%, 30% 70%, 15% 100%, 0 70% ); }
.ed-picado i:nth-child(6n+1), .ed-decor-papel-picado i:nth-child(6n+1) { background: #e8724f; }
.ed-picado i:nth-child(6n+2), .ed-decor-papel-picado i:nth-child(6n+2) { background: #f5a23d; }
.ed-picado i:nth-child(6n+3), .ed-decor-papel-picado i:nth-child(6n+3) { background: #d6249f; }
.ed-picado i:nth-child(6n+4), .ed-decor-papel-picado i:nth-child(6n+4) { background: #2e9e5b; }
.ed-picado i:nth-child(6n+5), .ed-decor-papel-picado i:nth-child(6n+5) { background: #6a4fd8; }
.ed-picado i:nth-child(6n), .ed-decor-papel-picado i:nth-child(6n) { background: #1fa97c; }
.ed-decor-chauves-souris i:nth-child(odd) { background: #f07f1e; }
.ed-decor-chauves-souris i:nth-child(even) { background: #2b1d3a; }
/* Noël : une guirlande d'ampoules sur un fil, et non des fanions. */
.ed-decor-guirlande { justify-content: space-around; gap: 0; }
.ed-decor-guirlande::before { content: ""; position: absolute; left: 0; right: 0; top: 3px; height: 2px; background: #1b4d3a; }
.ed-decor.ed-decor-guirlande i { flex: none; width: 14px; height: 20px; margin-top: 4px; clip-path: none; border-radius: 3px 3px 50% 50%; }
.ed-decor-guirlande i:nth-child(4n+1) { background: #e8724f; }
.ed-decor-guirlande i:nth-child(4n+2) { background: #f5c26b; }
.ed-decor-guirlande i:nth-child(4n+3) { background: #6ec3f0; }
.ed-decor-guirlande i:nth-child(4n) { background: #2e9e5b; }
/* Les fanions des éditions du printemps et de l'été (0.115.0). */
.ed-decor-fuego i:nth-child(3n+1) { background: #e8472f; }
.ed-decor-fuego i:nth-child(3n+2) { background: #f5a23d; }
.ed-decor-fuego i:nth-child(3n) { background: #f7d046; }
.ed-decor-rosas i:nth-child(odd) { background: #d6334a; }
.ed-decor-rosas i:nth-child(even) { background: #f3e2c7; }
.ed-decor-trefles i:nth-child(3n+1) { background: #169b62; }
.ed-decor-trefles i:nth-child(3n+2) { background: #f7f2e7; }
.ed-decor-trefles i:nth-child(3n) { background: #ff883e; }
.ed-decor-crepes i:nth-child(odd) { background: #e9b96e; }
.ed-decor-crepes i:nth-child(even) { background: #8a5a2b; }
.ed-decor-poissons i:nth-child(3n+1) { background: #3fb6d9; }
.ed-decor-poissons i:nth-child(3n+2) { background: #f5a23d; }
.ed-decor-poissons i:nth-child(3n) { background: #6a4fd8; }
.ed-decor-tricolore i:nth-child(3n+1) { background: #0055a4; }
.ed-decor-tricolore i:nth-child(3n+2) { background: #f7f2e7; }
.ed-decor-tricolore i:nth-child(3n) { background: #ef4135; }
.ed-tete { display: flex; gap: 14px; align-items: center; margin-top: 16px; }
.ed-ico { font-size: 40px; line-height: 1; }
.ed-eyebrow { font: 800 12px Nunito, sans-serif; letter-spacing: .08em; text-transform: uppercase; color: #f5c26b; }
.ed-titre { font: 700 22px Fredoka, sans-serif; margin: 2px 0 0; }
.ed-ligne { display: flex; align-items: center; gap: 12px; margin-top: 12px; padding: 10px 12px; border-radius: 14px; background: rgba( 255, 247, 234, .08 ); }
.ed-mini { width: 34px; height: 34px; flex: none; }
.ed-boutons { display: flex; gap: 8px; flex: none; }
.ed-ligne.is-ajoutee { box-shadow: inset 4px 0 0 #f5c26b; }
.ed-ajoutee { font: 800 11px Nunito, sans-serif; font-style: normal; letter-spacing: .04em; text-transform: uppercase; color: #2b1d3a;
	background: #f5c26b; border-radius: 999px; padding: 2px 8px; align-self: flex-start; margin: 2px 0; }
.ed-boutons .btn-ghost { background: #fff7ea; color: var(--color-ink); }
@media (max-width: 480px) {
	.ed-ligne:has(.btn-ghost) { flex-wrap: wrap; }
	.ed-ligne:has(.btn-ghost) .ed-boutons { width: 100%; justify-content: flex-end; }
}
.ed-mots { display: flex; flex-direction: column; flex: 1; min-width: 0; }
.ed-mots b { font: 700 17px Fredoka, sans-serif; }
.ed-mots span { font: 600 13px Nunito, sans-serif; color: #d8c7ea; }
.ed-texte { margin: 12px 0 0; font: 600 15px/1.45 Nunito, sans-serif; color: #eadcf5; }
.ed-fiches { margin: 10px 0 0; font: 700 14px Nunito, sans-serif; color: #eadcf5; }
.ed-fiches a { color: #f5c26b; }
.ed-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 14px; align-items: center; }
.ed-actions .btn-ghost { background: #fff7ea; color: var(--color-ink); }
.ed-non-form { margin: 0; }
.ed-non { background: none; border: 0; padding: 0; color: #d8c7ea; font: 700 14px Nunito, sans-serif; text-decoration: underline; cursor: pointer; }
a.ed-voile { display: block; }
.ed-volet-ico { width: 40px; height: 40px; }
.aide-doc.is-envoye { border-color: var(--color-success-strong); }
.aide-doc.is-envoye .aide-doc-titre { color: var(--color-success-strong); }
.niveau-repere { margin-top: 4px; font-weight: 700; color: var(--color-primary); }
.tile-cible { font: 600 12.5px Nunito, sans-serif; color: var(--color-ink-muted); font-style: italic; margin-top: 1px; }
.ed-compteur { align-self: flex-start; margin: 4px 0 2px; padding: 2px 10px; border-radius: 999px; background: #2b1d3a; color: #f5c26b;
	font: 800 12px Nunito, sans-serif; letter-spacing: .04em; text-transform: uppercase; }
.ed-classes .av-e i { font-style: normal; }
.ed-classes .ed-coche, .ed-classes input:checked + .av-e .ed-plus { display: none; }
.ed-classes input:checked + .av-e .ed-coche { display: inline; color: var(--color-primary); font-weight: 900; }
.ed-seances { margin: 8px 0 0; padding: 0; list-style: none; display: grid; gap: 8px; counter-reset: ed; }
.ed-seances li { counter-increment: ed; position: relative; display: flex; flex-direction: column; padding: 10px 12px 10px 44px; border-radius: 14px; background: var(--color-surface-raised); border: 2px solid var(--color-line-strong); }
.ed-seances li::before { content: counter(ed); position: absolute; left: 12px; top: 10px; width: 22px; height: 22px; border-radius: 50%; background: #2b1d3a; color: #f5c26b; font: 800 13px/22px Nunito, sans-serif; text-align: center; }
.ed-seances b { font: 700 16px Fredoka, sans-serif; }
.ed-seances span { font: 600 13px Nunito, sans-serif; color: var(--color-ink-muted); }
.mod-icon.fam-edition { background: #2b1d3a; display: grid; place-items: center; }
.mod-icon.fam-edition img { width: 70%; height: 70%; }

/* Au tableau. */
.ed-decor { position: fixed; left: 0; right: 0; top: 0; z-index: 5; display: flex; gap: 6px; padding: 0 24px; pointer-events: none; }
.ed-decor i { height: 26px; }
.ed-zones { grid-template-columns: repeat( 4, minmax( 0, 1fr ) ); }
/* Sur un téléphone, deux par deux : à quatre de front, chaque dessin n'avait
 * plus que la largeur d'un pouce (Killian, 6 oct. 2026). */
@media (max-width: 48rem) {
	.ed-zones { grid-template-columns: repeat( 2, minmax( 0, 1fr ) ); }
}
.ed-zones > .proj-zone { align-items: center; justify-content: center; text-align: center; gap: var(--spacing-3); padding: var(--spacing-5) var(--spacing-3); }
.ed-pic { width: calc( clamp( 70px, 20vh, 220px ) * var(--proj-fit, 1) ); height: auto; max-width: 100%; }
.ed-zone-texte > .proj-zone { align-items: flex-start; text-align: left; gap: var(--spacing-3); padding: var(--spacing-5); }
.ed-theme { font: 700 calc( clamp( 22px, 4.4vh, 52px ) * var(--proj-fit, 1 ) ) Fredoka, sans-serif; }
.ed-culture, .ed-pourquoi { display: block; font: 600 calc( clamp( 17px, 3.2vh, 38px ) * var(--proj-fit, 1) )/1.4 Nunito, sans-serif; max-width: 72ch; }
/* Le texte culturel tient à l'écran : plus large, moins de lignes ; le bouton
 * d'écoute et l'encadré « ¿Sabías…? » se resserrent avec le reste. */
.ed-zone-texte > .proj-zone { padding: calc( var(--spacing-5) * var(--proj-fit, 1) ); gap: calc( var(--spacing-3) * var(--proj-fit, 1) ); }
.ed-ecoute { margin-bottom: calc( var(--spacing-3) * var(--proj-fit, 1) ); }
.ed-sabias { display: block; margin-top: calc( var(--spacing-3) * var(--proj-fit, 1) ); padding: var(--spacing-2) var(--spacing-3); border-radius: var(--radius-md); border: 2px dashed var(--color-brand-band); font: 600 calc( clamp( 15px, 2.6vh, 30px ) * var(--proj-fit, 1) ) Nunito, sans-serif; }
.ed-dit { display: block; font: 700 calc( clamp( 22px, 4.6vh, 54px ) * var(--proj-fit, 1) ) Fredoka, sans-serif; }
.ed-oral { display: block; margin-top: var(--spacing-3); font: 700 calc( clamp( 16px, 2.8vh, 32px ) * var(--proj-fit, 1) ) Nunito, sans-serif; color: var(--color-brand-sheet); }

/* À la maison. */
.ed-solo-pic { display: grid; place-items: center; padding: var(--spacing-4); }
.ed-solo-img { width: 120px; height: 120px; }
.ed-solo-culture .ed-sabias { font-size: 15px; }
.ed-solo-oral { padding: 12px 14px; border-radius: 14px; background: #2b1d3a; color: #fff7ea; font: 700 16px Nunito, sans-serif; }
.ed-solo-oral small { display: block; margin-top: 4px; color: #d8c7ea; font-weight: 600; }
/* Au catalogue. */
.cat-carte.cat-edition { background: #2b1d3a; border-color: #2b1d3a; color: #fff7ea; box-shadow: 0 4px 0 var(--color-ink); }
.cat-edition .cat-meta, .cat-edition .text-secondary { color: #d8c7ea !important; }
.cat-ed-badge { display: inline-block; width: fit-content; font: 800 11px Nunito, sans-serif; letter-spacing: .06em; text-transform: uppercase; padding: 2px 9px; border-radius: var(--radius-full); background: #f5c26b; color: #2b1d3a; }
.cat-ed-dates { margin: 0; padding: 8px 10px; border-radius: 12px; background: rgba( 255, 255, 255, .08 ); font: 700 14px Nunito, sans-serif; color: #f5c26b; }
.cat-ed-off { margin: 0; font: 700 13px Nunito, sans-serif; color: #f5c26b; }
.cat-edition .btn-ghost { background: #fff7ea; color: var(--color-ink); }
/* La place des fanions se prend dans l'écran, pas au-dessus : la coquille
 * fait déjà toute la hauteur, et 26 px de plus la faisaient défiler. */
body.projection:has(.ed-decor) .proj-shell { padding-top: calc( var(--spacing-5) + 26px ); }
a.cat-fermer { display: grid; place-items: center; text-decoration: none; color: inherit; }

/* ═══ Créer une fiche (bibliothèque) ═════════════════════════════════════
 * Trois étapes : le format en cartes, avec un exemple au tableau sous chacune ;
 * la saisie à côté de son aperçu ; le moment de passage. L'écran ne dépend
 * d'aucune classe : une langue, un niveau (0.113.0). */
.fiche-pour { display: flex; flex-wrap: wrap; align-items: center; gap: var(--spacing-2); }
.fiche-pour-choix { box-sizing: border-box; display: inline-flex; align-items: center; min-height: 44px; padding: 0 18px; border-radius: var(--radius-full); border: 2px solid var(--color-line); background: var(--color-surface-raised);
	font: 600 15px var(--font-title-module), Fredoka, sans-serif; color: var(--color-ink); text-decoration: none; }
.fiche-pour-choix.is-on { border-color: var(--color-primary); background: var(--color-primary-soft); color: var(--color-primary); }
.fiche-etape { display: flex; align-items: center; gap: 10px; margin: var(--spacing-8) 0 var(--spacing-3);
	font: 600 20px/1.2 Fredoka, sans-serif; color: var(--color-ink); }
.fiche-n { display: inline-grid; place-items: center; flex: none; width: 30px; height: 30px; border-radius: 50%;
	background: var(--color-ink); color: var(--color-surface-raised); font: 700 15px Fredoka, sans-serif; }
.fiche-formats { border: 0; margin: 0; padding: 0; min-width: 0; display: grid; gap: var(--spacing-3);
	grid-template-columns: repeat( auto-fit, minmax( max( 13rem, 30% ), 1fr ) ); }
.fiche-format { position: relative; display: flex; flex-direction: column; gap: 6px; padding: var(--spacing-4); min-width: 0;
	border: 2px solid var(--color-line); border-radius: var(--radius-lg); background: var(--color-surface-raised); cursor: pointer; }
.fiche-format:has( input:checked ) { border-color: var(--color-primary); background: var(--color-primary-soft); box-shadow: 0 4px 0 var(--color-primary); }
.fiche-format:has( input:checked )::after { content: "✓"; position: absolute; top: 10px; right: 12px; width: 22px; height: 22px; border-radius: 50%;
	background: var(--color-primary); color: var(--color-on-primary); display: grid; place-items: center; font: 700 13px Nunito, sans-serif; }
.fiche-format:has( input:focus-visible ) { outline: 3px solid var(--color-primary); outline-offset: 2px; }
.fiche-format b { font: 600 16px/1.25 Fredoka, sans-serif; padding-right: 26px; }
.fiche-format small { color: var(--color-ink-muted); font-weight: 600; font-size: 13px; line-height: 1.4; }
.fiche-mini { margin-top: auto; padding: 8px 10px; border-radius: var(--radius-md); background: var(--color-proj-surface); color: var(--color-proj-ink);
	font: 600 13px/1.35 Fredoka, sans-serif; overflow-wrap: anywhere; }
.fiche-mini i { font-style: normal; color: var(--color-proj-accent); }
.fiche-mini em { font-style: normal; color: var(--color-proj-success); }
.fiche-grille { display: grid; grid-template-columns: minmax( 0, 1.15fr ) minmax( 0, 1fr ); gap: var(--spacing-6); align-items: start; }
.fiche-carte { background: var(--color-surface-raised); border: 2px solid var(--color-line); border-radius: var(--radius-xl);
	padding: var(--spacing-5); display: flex; flex-direction: column; gap: var(--spacing-4); min-width: 0; }
.fiche-exemple { display: flex; gap: var(--spacing-3); align-items: center; justify-content: space-between; flex-wrap: wrap;
	padding: 12px 14px; border-radius: var(--radius-md); background: var(--color-brand-paper); font-weight: 700; }
.fiche-bonne { border-color: var(--color-success-strong); background: var(--color-success-soft); }
.fiche-trois { display: grid; grid-template-columns: repeat( 3, minmax( 0, 1fr ) ); gap: var(--spacing-2); }
.fiche-depot { display: flex; gap: var(--spacing-4); align-items: center; padding: var(--spacing-4); cursor: pointer;
	border: 2px dashed var(--color-line-strong); border-radius: var(--radius-md); background: var(--color-surface-sunken);
	font-weight: 700; font-size: 14px; color: var(--color-ink-muted); }
.fiche-depot.is-survol { border-color: var(--color-primary); background: var(--color-primary-soft); }
.fiche-depot:has( input:focus-visible ) { outline: 3px solid var(--color-primary); outline-offset: 2px; }
.fiche-depot u { color: var(--color-primary); }
.fiche-depot img, .fiche-depot-ico { flex: none; width: 56px; height: 56px; object-fit: contain; padding: 6px; box-sizing: border-box;
	border-radius: var(--radius-md); background: var(--color-surface-raised); border: 2px solid var(--color-line); display: grid; place-items: center; font-size: 26px; }
.fiche-adresse summary { cursor: pointer; color: var(--color-primary); font-weight: 700; }
.fiche-apercu { position: sticky; top: var(--spacing-4); display: flex; flex-direction: column; gap: var(--spacing-2); min-width: 0; }
.fiche-apercu-t { font: 600 14px Fredoka, sans-serif; color: var(--color-ink-muted); text-transform: uppercase; letter-spacing: .06em; }
.fiche-tableau { background: var(--color-proj-surface); color: var(--color-proj-ink); border-radius: var(--radius-xl); padding: var(--spacing-5);
	min-height: 15rem; display: flex; flex-direction: column; gap: var(--spacing-3); justify-content: center; box-shadow: 0 6px 0 var(--color-ink); }
.fiche-tableau .q { margin: 0; font: 600 26px/1.2 Fredoka, sans-serif; text-align: center; overflow-wrap: anywhere; }
.fiche-tableau .q.is-vide { color: var(--color-proj-ink-muted); font-size: 18px; }
.fiche-tableau .img { display: grid; place-items: center; }
.fiche-tableau .img img { width: auto; height: 96px; max-width: 100%; object-fit: contain; }
.fiche-choix { display: grid; grid-template-columns: repeat( 2, minmax( 0, 1fr ) ); gap: var(--spacing-2); }
.fiche-choix span { border: 2px solid var(--color-proj-line); border-radius: var(--radius-md); padding: 8px; text-align: center;
	font: 600 16px Fredoka, sans-serif; overflow-wrap: anywhere; }
.fiche-choix span.bon { border-color: var(--color-proj-success); color: var(--color-proj-success); }
/* Au tableau, une seule réponse : la bonne, voilée jusqu'au dévoilement (aperçu aligné, 0.13x). */
.fiche-choix span:only-child { grid-column: 1 / -1; }
.fiche-voile { margin: 0; text-align: center; color: var(--color-proj-ink-muted); }
.fiche-integre { margin: 0; padding: var(--spacing-6) var(--spacing-4); border: 2px dashed var(--color-proj-line); border-radius: var(--radius-md);
	text-align: center; color: var(--color-proj-ink-muted); font-weight: 700; }
.fiche-quand { border: 0; margin: 0; padding: 0; min-width: 0; display: grid; grid-template-columns: repeat( 2, minmax( 0, 1fr ) ); gap: var(--spacing-3); }
.fiche-q { display: flex; gap: var(--spacing-3); align-items: flex-start; padding: var(--spacing-4); cursor: pointer;
	border: 2px solid var(--color-line); border-radius: var(--radius-lg); background: var(--color-surface-raised); }
.fiche-q:has( > input:checked ) { border-color: var(--color-primary); background: var(--color-primary-soft); }
.fiche-q > input { margin-top: 4px; }
.fiche-q-ico { font-size: 24px; line-height: 1; }
.fiche-q b { font: 600 16px Fredoka, sans-serif; }
.fiche-bas { display: grid; grid-template-columns: repeat( auto-fit, minmax( min( 100%, 20rem ), 1fr ) ); gap: var(--spacing-4); }
.fiche-barre { margin-top: var(--spacing-6); padding-top: var(--spacing-4); border-top: 2px solid var(--color-line);
	display: flex; gap: var(--spacing-2); align-items: center; flex-wrap: wrap; }
.fiche-barre .grow { flex: 1; min-width: 12rem; }
@media (max-width: 48rem) {
	.fiche-grille, .fiche-quand { grid-template-columns: 1fr; }
	.fiche-apercu { position: static; order: -1; }
	.fiche-formats { grid-template-columns: repeat( 2, minmax( 0, 1fr ) ); }
	.fiche-tableau .q { font-size: 22px; }
}
@media (max-width: 26rem) {
	.fiche-trois { grid-template-columns: 1fr; }
	.fiche-formats { grid-template-columns: 1fr; }
}

/* ═══ Mentions légales : pied de page hors connexion, bas des réglages ═══ */
.pied-legal { border-top: 2px solid var(--color-line); margin-top: var(--spacing-12); }
.pied-legal-in { max-width: var(--page-w); margin: 0 auto; padding: var(--spacing-5) var(--spacing-4) calc( env( safe-area-inset-bottom, 0px ) + var(--spacing-5) );
	display: flex; flex-wrap: wrap; gap: var(--spacing-2) var(--spacing-5); align-items: center; justify-content: space-between;
	font-size: 13px; font-weight: 600; color: var(--color-ink-muted); }
.pied-legal-liens { display: flex; flex-wrap: wrap; gap: var(--spacing-2) var(--spacing-4); }
.pied-legal-liens a { color: inherit; }
.pied-legal-liens a:hover { color: var(--color-primary); }
.reglages-legal { padding-top: var(--spacing-4); border-top: 2px solid var(--color-line); font-size: 13px; font-weight: 600; color: var(--color-ink-muted); }

/* ═══ Réglages : une seule forme de boîte, la ligne (0.116.0) ═══════════════
 * Icône, titre, phrase ; à droite un bouton (le geste se fait ici) ou une
 * flèche (on va ailleurs, toute la ligne est le lien). */
.reg-pile { display: flex; flex-direction: column; gap: var(--spacing-2); }
.reg-ligne { display: flex; align-items: center; gap: var(--spacing-4); padding: var(--spacing-4) 18px;
	background: var(--color-surface-raised); border: 2px solid var(--color-line); border-radius: var(--radius-lg);
	color: inherit; text-decoration: none; }
.reg-ligne.is-lien:hover { border-color: var(--color-brand-band); }
.reg-ico { flex: none; width: 42px; height: 42px; border-radius: var(--radius-md); display: grid; place-items: center;
	font-size: 20px; font-weight: 800; color: var(--t, var(--color-primary)); background: color-mix( in srgb, var(--t, var(--color-primary)) 16%, transparent ); }
.reg-txt { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.reg-txt > b { font: 600 17px/1.25 Fredoka, sans-serif; color: var(--color-ink); }
.reg-txt > span { font-size: 14px; line-height: 1.45; color: var(--color-ink-muted); font-weight: 600; }
.reg-txt .reg-ok { color: var(--color-success-strong); font-weight: 800; }
.reg-txt .reg-attente { color: var(--color-gold-strong); font-weight: 800; }
.reg-fl { flex: none; font-size: 20px; color: var(--color-ink-faint); }
.reg-ligne > .btn, .reg-form { flex: none; margin: 0; }
.reg-fixe { flex: none; font-weight: 700; font-size: 13px; color: var(--color-ink-faint); }
.reg-inter { position: relative; display: block; width: 46px; height: 26px; cursor: pointer; }
.reg-inter input { position: absolute; inset: 0; opacity: 0; margin: 0; cursor: pointer; }
.reg-inter span { position: absolute; inset: 0; border-radius: var(--radius-full); background: var(--color-line-strong); transition: background .2s; }
.reg-inter span::after { content: ""; position: absolute; top: 3px; left: 3px; width: 20px; height: 20px; border-radius: 50%; background: var(--color-surface-raised); transition: left .2s; }
.reg-inter input:checked + span { background: var(--color-success-strong); }
.reg-inter input:checked + span::after { left: 23px; }
.reg-inter input:focus-visible + span { outline: 3px solid var(--color-primary); outline-offset: 2px; }
form > .surface-card { border: 2px solid var(--color-line); }
@media (max-width: 32rem) {
	.reg-ligne { flex-wrap: wrap; align-items: flex-start; }
	.reg-ligne:not( .is-lien ) .reg-txt { flex: 1 1 calc( 100% - 58px ); }
	.reg-ligne > .btn, .reg-ligne > .reg-form { margin-left: 58px; }
	.reg-ligne:has( .reg-inter ), .reg-ligne:has( > .reg-fixe ) { flex-wrap: nowrap; align-items: center; }
	.reg-ligne:has( .reg-inter ) .reg-txt, .reg-ligne:has( > .reg-fixe ) .reg-txt { flex: 1 1 auto; }
	.reg-ligne:has( .reg-inter ) > .reg-form { margin-left: 0; }
}

/* ═══ Réglages : les fenêtres (0.117.0) ═══════════════════════════════════
 * Une fenêtre sur la page, pour ce qui demande plus qu'un clic : la lettre,
 * l'export, l'import, l'avis. */
button.reg-ligne { width: 100%; font: inherit; text-align: left; cursor: pointer; }
.reg-form-ligne { margin: 0; }
dialog.avm { margin: auto; inset: 0; width: min( 680px, calc( 100% - 32px ) ); max-height: calc( 100% - 40px ); overflow: auto; padding: 20px 22px;
	background: var(--color-surface); color: var(--color-ink); border: 2px solid var(--color-ink); border-radius: var(--radius-xl);
	box-shadow: 0 8px 0 var(--color-ink); }
dialog.avm[open] { display: flex; flex-direction: column; gap: 14px; }
dialog.avm::backdrop { background: color-mix( in srgb, var(--color-ink) 45%, transparent ); }
@supports not (color: color-mix(in srgb, red, blue)) { dialog.avm::backdrop { background: rgba(59,42,36,0.45); } }
.avm-tete { display: flex; align-items: center; gap: 12px; }
.avm-tete > b { flex: 1; font: 600 21px Fredoka, sans-serif; }
.avm-tete form { margin: 0; }
.avm-ico { width: 42px; height: 42px; border-radius: var(--radius-md); display: grid; place-items: center; font-size: 20px;
	background: color-mix( in srgb, var(--color-family-repaso) 16%, transparent ); }
@supports not (color: color-mix(in srgb, red, blue)) { .avm-ico { background: rgba(160,112,78,0.16); } }
.avm-x { border: 0; background: none; font-size: 26px; line-height: 1; cursor: pointer; color: var(--color-ink-muted); }
.avm-bulle { margin: 0; padding: 12px 14px; border: 2px solid var(--color-line); border-radius: 16px; border-top-left-radius: 4px;
	background: var(--color-surface-raised); font-weight: 600; font-size: 15px; line-height: 1.45; }
.avm-astuce { margin: 0; padding: 12px 14px; border-radius: 14px; background: var(--color-brand-paper); font-weight: 600; font-size: 14px; line-height: 1.45; }
.avm-texte { margin: 0; font-weight: 600; }
.avm-form { display: flex; flex-direction: column; gap: 12px; margin: 0; }
.avm-bas { display: flex; align-items: center; justify-content: flex-end; gap: 10px; flex-wrap: wrap; border-top: 2px solid var(--color-line); padding-top: 12px; }
.avm-bas .grow { flex: 1; font-size: 13px; font-weight: 700; color: var(--color-ink-muted); }
.xp-usage { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.xp-u { border: 2px solid var(--color-line); border-radius: 14px; padding: 12px 14px; background: var(--color-surface-raised); display: flex; gap: 10px; align-items: flex-start; cursor: pointer; }
.xp-u:has( input:checked ) { border-color: var(--color-primary); background: var(--color-primary-soft); }
.xp-u b { display: block; font: 600 16px Fredoka, sans-serif; }
.xp-u span span { font-size: 13px; font-weight: 600; color: var(--color-ink-muted); }
.xp-sec { margin: 0; border: 2px solid var(--color-line); border-radius: 14px; background: var(--color-surface-raised); padding: 6px 14px; min-width: 0; }
.xp-sec legend { padding: 0 4px; font: 600 13px Fredoka, sans-serif; text-transform: uppercase; letter-spacing: .06em; color: var(--color-ink-muted); }
.xp-l { display: flex; align-items: center; gap: 12px; padding: 9px 0; border-top: 1px solid var(--color-line); font-weight: 700; }
.xp-l:first-of-type { border-top: 0; }
.xp-l .meta { margin-left: auto; font-size: 13px; color: var(--color-ink-muted); font-weight: 600; text-align: right; }
.xp-l .sub, .xp-depot .sub { display: block; font-size: 13px; color: var(--color-ink-muted); font-weight: 600; }
.xp-l input { width: 18px; height: 18px; accent-color: var(--color-primary); flex: none; }
.xp-l.off { opacity: .55; }
.xp-note { font-size: 13px; color: var(--color-ink-muted); font-weight: 600; margin: 4px 0 8px; }
.xp-depot { display: flex; gap: 12px; align-items: center; margin: 0; padding: 14px; border: 2px dashed var(--color-line-strong); border-radius: 14px;
	background: var(--color-surface-sunken); font-weight: 700; font-size: 14px; }
.xp-depot .f { font-size: 26px; }
.xp-depot.ok { border-style: solid; border-color: var(--color-success-strong); background: var(--color-success-soft); }
.xp-tag { display: inline-block; font-size: 12px; font-weight: 800; padding: 2px 8px; border-radius: var(--radius-full); background: var(--color-surface-sunken); color: var(--color-ink-muted); }
.xp-tag.neuf { background: var(--color-success-soft); color: var(--color-success-strong); }
.xp-tag.att { background: color-mix( in srgb, var(--color-gold) 25%, transparent ); color: var(--color-gold-strong); }
@supports not (color: color-mix(in srgb, red, blue)) { .xp-tag.att { background: rgba(242,182,60,0.25); } }
.av-corr { border: 2px solid var(--color-primary); background: var(--color-primary-soft); border-radius: var(--radius-lg); padding: 12px 14px; display: flex; flex-direction: column; gap: 8px; }
.av-corr p { margin: 0; }
.av-corr-t { font-weight: 800; }
.av-corr-texte { background: var(--color-surface-raised); border-radius: var(--radius-md); padding: 10px 12px; font-size: 15px; line-height: 1.5; }
.av-corr-texte del { color: var(--color-error-strong); text-decoration: line-through; }
.av-corr-texte ins { text-decoration: none; background: var(--color-success-soft); color: var(--color-success-strong); font-weight: 800; border-radius: 4px; padding: 0 2px; }
.av-corr-boutons { display: flex; gap: 8px; flex-wrap: wrap; }
@media (max-width: 35rem) { .xp-usage { grid-template-columns: 1fr; } }
.avm-form input[type="file"] { font: inherit; font-size: 14px; color: var(--color-ink-muted); }
.avm-form input[type="file"]::file-selector-button { margin-right: 12px; padding: 8px 16px; border: 2px solid var(--color-ink); border-radius: var(--radius-full);
	background: var(--color-surface-raised); color: var(--color-ink); font: 700 14px Fredoka, sans-serif; cursor: pointer; }

/* ── Mes fiches : le stock, les séquences, et les rituels (0.118.0) ───── */
.mf-tete { display: flex; align-items: center; justify-content: space-between; gap: var(--spacing-3); flex-wrap: wrap; margin-top: var(--spacing-6); }
.mf-tete p { margin: 6px 0 0; max-width: 62ch; }
.mf-tete-bts { display: flex; gap: var(--spacing-2); flex-wrap: wrap; }
.mf-intro { margin: 6px 0 0; max-width: 62ch; }
.mf-outils { display: flex; gap: var(--spacing-2); margin-top: var(--spacing-4); }
.mf-outils .field-input { padding: 8px 12px; font-size: 15px; }
.mf-paire { flex: 0 1 13rem; min-width: 0; }
.mf-q { flex: 1 1 10rem; min-width: 0; }
.mf-filtres { display: flex; gap: var(--spacing-2); margin-top: var(--spacing-3); overflow-x: auto; scrollbar-width: none; padding-bottom: 2px; }
.mf-filtres::-webkit-scrollbar { display: none; }
.mf-filtres .lib-chip { flex: none; }
a.lib-chip { text-decoration: none; }
.mf-sel { display: flex; justify-content: flex-end; margin: 0; }
.mf-sel-b { font-weight: 800; color: var(--color-primary); padding: 4px 0; }
[data-vd-bulk]:not(.is-sel) .mf-pick { display: none; }
[data-vd-bulk]:not(.is-sel) .mf-l { padding-left: var(--spacing-4); }
.mf-barre { position: sticky; top: var(--spacing-2); z-index: 20; display: flex; align-items: center; gap: var(--spacing-2); margin-top: var(--spacing-2); padding: 8px 10px; border-radius: var(--radius-full); background: var(--color-surface-raised); border: 2px solid var(--color-primary); box-shadow: 0 8px 24px -12px color-mix( in srgb, var(--color-ink) 40%, transparent ); }
@supports not (color: color-mix(in srgb, red, blue)) { .mf-barre { box-shadow: 0 8px 24px -12px rgba(59,42,36,0.40); } }
.mf-barre-n { flex: none; font-weight: 800; color: var(--color-primary); padding-left: 6px; }
.mf-barre select { flex: 1; min-width: 0; padding: 6px 10px; font-size: 14px; }
.mf-barre-x { flex: none; width: 32px; height: 32px; border-radius: 50%; font-weight: 800; color: var(--color-ink-muted); }
.mf-groupe { margin: var(--spacing-6) 0 0; font: 600 13px var(--font-title-module), system-ui, sans-serif; text-transform: uppercase; letter-spacing: .06em; color: var(--color-ink-muted); }
.mf-pile { list-style: none; margin: var(--spacing-3) 0 0; padding: 0; display: flex; flex-direction: column; gap: var(--spacing-2); }
.mf-l { display: flex; align-items: center; gap: var(--spacing-3); padding: 0 var(--spacing-4) 0 var(--spacing-3); background: var(--color-surface-raised); border: 2px solid var(--color-line); border-radius: var(--radius-lg); }
.mf-l:hover { border-color: var(--color-primary); }
.mf-l.neuve { border-color: var(--color-success-strong); box-shadow: 0 0 0 4px var(--color-success-soft); }
.mf-pick { flex: none; display: grid; place-items: center; padding: var(--spacing-2); }
.mf-pick input { width: 20px; height: 20px; accent-color: var(--color-primary); }
.mf-lien { flex: 1; min-width: 0; display: flex; align-items: center; gap: var(--spacing-3); padding: 12px 0; color: inherit; text-decoration: none; }
.mf-ico { flex: none; width: 40px; height: 40px; border-radius: 12px; display: grid; place-items: center; font-size: 19px; background: var(--color-primary-soft); }
.mf-txt { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.mf-txt b { font: 600 16px var(--font-title-module), system-ui, sans-serif; overflow-wrap: anywhere; }
.mf-txt span { font-size: 13px; font-weight: 600; color: var(--color-ink-muted); overflow-wrap: anywhere; }
.mf-etats { flex: none; display: flex; flex-wrap: wrap; gap: 4px; justify-content: flex-end; max-width: 50%; }
.mf-fl { flex: none; font-size: 18px; color: var(--color-ink-faint); }
@media (max-width: 560px) {
	.mf-lien { flex-wrap: wrap; }
	.mf-etats { max-width: none; justify-content: flex-start; order: 3; width: 100%; padding-left: 52px; }
	.mf-fl { display: none; }
}
.pf-c { display: inline-block; font-size: 12px; font-weight: 800; padding: 3px 9px; border-radius: var(--radius-full); white-space: nowrap; }
.pf-c.cours { background: var(--color-success-soft); color: var(--color-success-strong); }
.pf-c.venir { background: var(--color-primary-soft); color: var(--color-primary-active); }
.pf-c.finie, .pf-c.stock { background: var(--color-surface-sunken); color: var(--color-ink-muted); }
.pf-c.tir { background: color-mix( in srgb, var(--color-gold) 24%, transparent ); color: var(--color-ink); }
@supports not (color: color-mix(in srgb, red, blue)) { .pf-c.tir { background: rgba(242,182,60,0.24); } }
.pf-c.brou { border: 1.5px dashed var(--color-line-strong); color: var(--color-ink-muted); }

.mf-ok, .mf-err, .mf-statut { display: flex; gap: var(--spacing-3); align-items: flex-start; flex-wrap: wrap; padding: 14px 16px; border-radius: var(--radius-lg); border: 2px solid var(--color-line); background: var(--color-surface-raised); }
.mf-ok { border-color: var(--color-success-strong); background: var(--color-success-soft); }
.mf-statut.is-rappel { border-color: var(--color-primary); background: var(--color-primary-soft); }
.mf-err { border-color: var(--color-error); background: color-mix( in srgb, var(--color-error) 10%, var(--color-surface-raised) ); }
@supports not (color: color-mix(in srgb, red, blue)) { .mf-err { background: rgb(253,239,238); } }
.mf-ok > span, .mf-err > span, .mf-statut > span { font-size: 22px; line-height: 1.2; }
.mf-ok > div, .mf-err > div, .mf-statut .t { flex: 1; min-width: 14rem; display: flex; flex-direction: column; gap: 4px; }
.mf-ok b, .mf-err b, .mf-statut b { font: 600 17px var(--font-title-module), system-ui, sans-serif; }
.mf-ok p, .mf-err p { margin: 0; font-weight: 600; color: var(--color-ink-muted); }
.mf-statut .t > span { font-size: 14px; font-weight: 600; color: var(--color-ink-muted); }
.mf-statut .mf-etats { max-width: none; justify-content: flex-start; }
.mf-ok .bts, .mf-statut .bts { display: flex; gap: var(--spacing-2); flex-wrap: wrap; margin-top: 6px; }
.field-input.ko, .fiche-depot.ko { border-color: var(--color-error) !important; box-shadow: 0 0 0 3px color-mix( in srgb, var(--color-error) 18%, transparent ); }
@supports not (color: color-mix(in srgb, red, blue)) { .field-input.ko, .fiche-depot.ko { box-shadow: 0 0 0 3px rgba(239,95,85,0.18); } }
.mf-msg { margin: 6px 0 0; font-size: 14px; font-weight: 700; color: var(--color-error-strong); }

.sq-grille { display: grid; grid-template-columns: repeat( auto-fit, minmax( 240px, 1fr ) ); gap: var(--spacing-3); margin-top: var(--spacing-4); }
.sq { position: relative; display: flex; flex-direction: column; gap: 8px; padding: 14px 16px; border: 2px solid var(--color-line); border-radius: var(--radius-lg); background: var(--color-surface-raised); color: inherit; text-decoration: none; text-align: left; font: inherit; cursor: pointer; }
.sq::before { content: ""; position: absolute; left: 14px; top: -10px; width: 64px; height: 12px; border: 2px solid var(--color-line); border-bottom: 0; border-radius: 10px 10px 0 0; background: inherit; }
.sq:hover { border-color: var(--color-primary); }
.sq-h { display: flex; justify-content: space-between; gap: 8px; align-items: flex-start; flex-wrap: wrap; }
.sq-h b { font: 600 16px var(--font-title-module), system-ui, sans-serif; overflow-wrap: anywhere; }
.sq-m { font-size: 13px; font-weight: 700; color: var(--color-ink-muted); }
.sq-p { display: flex; gap: 4px; flex-wrap: wrap; }
.sq-p span { width: 28px; height: 28px; border-radius: 8px; display: grid; place-items: center; font-size: 14px; background: var(--color-primary-soft); }
.sq-nv { border-style: dashed; align-items: center; justify-content: center; color: var(--color-primary); font-weight: 800; min-height: 0; padding: 12px; }
@media (max-width: 560px) { .sq-grille { gap: var(--spacing-4); } }
.sq-nv::before { border-style: dashed; }
.sq-ordre .mf-l { padding-left: var(--spacing-4); }
.sq-n { flex: none; width: 26px; text-align: center; font: 700 15px var(--font-title-module), system-ui, sans-serif; color: var(--color-ink-muted); }
.sq-act { flex: none; display: flex; gap: 2px; margin: 0; }
.sq-b { width: 32px; height: 32px; border: 0; border-radius: 8px; background: none; font-weight: 800; color: var(--color-ink-muted); cursor: pointer; }
.sq-b:hover:not(:disabled) { background: var(--color-surface-sunken); color: var(--color-ink); }
.sq-b:disabled { opacity: .3; cursor: default; }

/* Le volet de la composition, et la fenêtre « Ajouter au rituel ». */
.pf { padding: 18px 20px; border: 2px solid var(--color-primary); border-radius: var(--radius-lg); background: var(--color-surface-raised); display: flex; flex-direction: column; gap: var(--spacing-4); }
.pf-h { display: flex; gap: var(--spacing-3); align-items: flex-start; }
.pf-h > span { font-size: 24px; }
.pf-h b { display: block; font: 600 18px var(--font-title-module), system-ui, sans-serif; }
.pf-h div span { font-size: 14px; font-weight: 600; color: var(--color-ink-muted); }
.pf-g { display: flex; flex-direction: column; gap: var(--spacing-2); border: 0; margin: 0; padding: 0; min-width: 0; }
.pf-gt { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; padding: 0; }
.pf-gt b { font: 600 16px var(--font-title-module), system-ui, sans-serif; }
.pf-gt span { font-size: 13px; font-weight: 600; color: var(--color-ink-muted); }
.pf-r { display: flex; align-items: center; gap: var(--spacing-3); padding: 10px 14px; border: 2px solid var(--color-line); border-radius: 14px; background: var(--color-surface); }
label.pf-r { cursor: pointer; }
label.pf-r:has( input:checked ) { border-color: var(--color-primary); background: var(--color-primary-soft); }
.pf-r input { flex: none; width: 20px; height: 20px; accent-color: var(--color-primary); }
.pf-r .i { flex: none; width: 36px; height: 36px; border-radius: 10px; display: grid; place-items: center; background: var(--color-primary-soft); }
.pf-r .t { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.pf-r .t b { font-weight: 800; overflow-wrap: anywhere; }
.pf-r .t span { font-size: 13px; font-weight: 700; color: var(--color-ink-muted); overflow-wrap: anywhere; }
.pf-r.is-off { opacity: .55; cursor: default; }
.pf-r.is-finie { opacity: .6; }
.pf-r.is-cache { display: none; }
.pf-a { flex: none; display: flex; gap: 2px; }
.pf-a button { width: 32px; height: 32px; border: 0; border-radius: 8px; background: none; color: var(--color-ink-muted); font-weight: 800; cursor: pointer; }
.pf-a button:hover { background: var(--color-surface-sunken); color: var(--color-ink); }
.pf-vide { margin: 0; padding: 10px 14px; border: 2px dashed var(--color-line); border-radius: 14px; font-size: 14px; font-weight: 600; color: var(--color-ink-muted); }
.pf-bas { display: flex; gap: var(--spacing-2); flex-wrap: wrap; align-items: center; }
.pf-note { font-size: 13px; font-weight: 600; color: var(--color-ink-faint); }
.pf-dlg .pf-liste { max-height: 40vh; overflow: auto; padding: 2px; }
.pf-tabs { display: flex; gap: 6px; padding: 4px; border-radius: var(--radius-full); background: var(--color-surface-sunken); width: max-content; max-width: 100%; }
.pf-tabs button { padding: 6px 16px; border: 0; border-radius: var(--radius-full); background: none; font: inherit; font-weight: 800; font-size: 14px; color: var(--color-ink-muted); cursor: pointer; }
.pf-tabs button[aria-selected="true"] { background: var(--color-surface-raised); color: var(--color-ink); }
.pf-modes { display: flex; flex-wrap: wrap; gap: 8px; }
.pf-m { display: inline-flex; align-items: center; gap: 8px; padding: 8px 14px; border: 2px solid var(--color-line); border-radius: var(--radius-full); font-weight: 800; cursor: pointer; }
.pf-m input { accent-color: var(--color-primary); }
.pf-aide { margin: 0; font-size: 13px; font-weight: 600; color: var(--color-ink-muted); }
.pf-quand summary { cursor: pointer; font-weight: 800; color: var(--color-primary); }
.pf-quand[open] summary { margin-bottom: 8px; }
.pf-quand .pf-dates label { display: inline-flex; align-items: center; gap: 6px; }
.pf-quand .pf-aide { margin-top: 6px; }
.pf-m.on { border-color: var(--color-primary); background: var(--color-primary-soft); }
.pf-dates { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; font-weight: 700; font-size: 14px; }
.pf-dates input { padding: 6px 8px; border: 2px solid var(--color-line); border-radius: 10px; background: var(--color-surface-raised); font: inherit; font-size: 14px; color: var(--color-ink); max-width: 100%; }
.pf-cl { display: inline-flex; align-items: center; gap: 6px; padding: 6px 12px; border: 2px solid var(--color-line); border-radius: var(--radius-full); font-weight: 700; cursor: pointer; }
.pf-cl:has( input:checked ) { border-color: var(--color-primary); background: var(--color-primary-soft); }
.pf-titre { margin: 0; padding: 10px 14px; border-radius: 14px; background: var(--color-surface-sunken); font-weight: 800; }
.pf-err { margin: 0; padding: 10px 14px; border-radius: 14px; background: color-mix( in srgb, var(--color-error) 12%, var(--color-surface-raised) ); color: var(--color-error-strong); font-weight: 700; }
@supports not (color: color-mix(in srgb, red, blue)) { .pf-err { background: rgb(253,236,235); } }

/* La liste « Autre langue ou niveau » a la hauteur, la police et le contour des pastilles qui la précèdent. */
.fiche-pour-autre { box-sizing: border-box; width: auto; max-width: 100%; min-height: 44px; height: 44px; padding: 0 38px 0 18px; border: 2px solid var(--color-line);
	border-radius: var(--radius-full); font: 600 15px var(--font-title-module), Fredoka, sans-serif; color: var(--color-ink); cursor: pointer; }
/* Dans le bandeau : sous l'introduction, et le fil d'Ariane sans marge haute (la bande a la sienne). */
.page-band > p.mt-6 { margin-top: 0; }
.page-band .fiche-tete { margin-top: var(--spacing-2); }
.page-band .fiche-pour { margin-top: var(--spacing-5); }

/* Le petit rituel des fiches : l'étoile, le nombre en plus, la séance (0.119.0). */
.pf-star { flex: none; width: 34px; height: 34px; border-radius: 10px; display: grid; place-items: center; font-size: 17px; border: 2px solid var(--color-line); background: var(--color-surface-raised); filter: grayscale( 1 ); opacity: .5; cursor: pointer; }
.pf-star:hover { opacity: .8; }
.pf-star.on { filter: none; opacity: 1; border-color: var(--color-gold); background: color-mix( in srgb, var(--color-gold) 18%, transparent ); }
@supports not (color: color-mix(in srgb, red, blue)) { .pf-star.on { background: rgba(242,182,60,0.18); } }
.pf-a button:disabled { opacity: .3; cursor: default; }
.pf-plus { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.pf-plus > b { font: 600 16px var(--font-title-module), system-ui, sans-serif; }
.pf-plus-choix { display: flex; gap: 6px; }
.pf-plus-choix .pf-m { padding: 6px 14px; background: var(--color-surface-raised); font: inherit; font-weight: 800; }
.pf-plus .pf-aide { flex-basis: 100%; }
.pf-frise { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; padding: 10px 12px; border-radius: 14px; background: var(--color-surface-sunken); font-size: 14px; font-weight: 700; }
.pf-frise i { font-style: normal; padding: 4px 10px; border-radius: var(--radius-full); background: var(--color-surface-raised); border: 2px solid var(--color-line); }
.pf-frise em { font-style: normal; color: var(--color-ink-muted); }
.quiz-media { margin-top: var(--spacing-4); }
.quiz-media img { max-height: 30vh; width: auto; max-width: 100%; border-radius: var(--radius-md); }
/* Sur téléphone, deux étages : l'étoile, l'icône et le titre ; puis l'état et les gestes. */
@media (max-width: 560px) {
	.pf { padding: 14px; }
	.pf-r { flex-wrap: wrap; gap: 8px 10px; padding: 10px 12px; }
	.pf-r .t { flex: 1 1 calc( 100% - 110px ); min-width: 0; }
	.pf-r .pf-c { order: 5; margin-left: 44px; }
	.pf-r .pf-a { order: 6; margin-left: auto; }
	.pf-dlg .pf-r .t { flex-basis: auto; }
}
.pf-plus-choix .pf-m.on { background: var(--color-primary-soft); border-color: var(--color-primary); color: var(--color-primary-active); }
.pf-cl { flex-wrap: wrap; }
.pf-cl-deja { flex-basis: 100%; font-size: 12px; font-weight: 800; color: var(--color-success-strong); padding-left: 24px; }
.pf-cl.is-deja { border-color: var(--color-success-strong); background: var(--color-success-soft); }
label.pf-r > .pf-c { flex: none; }
.pf-c-x { display: inline; margin: 0 0 0 6px; }
.pf-c-x button { font-weight: 800; color: inherit; opacity: .65; padding: 0 2px; cursor: pointer; }
.pf-c-x button:hover { opacity: 1; }

/* L'onglet « Éditions limitées ». */
.ed-l { display: flex; align-items: center; gap: var(--spacing-3); flex-wrap: wrap; padding: 12px var(--spacing-4); background: var(--color-surface-raised); border: 2px solid var(--color-line); border-radius: var(--radius-lg); }
.ed-l.is-tard { opacity: .75; }
.ed-l-ico { flex: none; width: 40px; height: 40px; }
.ed-l .mf-txt { flex: 1 1 12rem; }
.ed-l-bts { display: flex; gap: var(--spacing-2); flex-wrap: wrap; flex-basis: 100%; padding-left: 52px; }
@media (max-width: 560px) { .ed-l-bts { padding-left: 0; } }
/* Les éditions en cartes, sur la même grille que les modules : quatre par ligne sur un grand écran
 * (cartes de 290 px et plus), une seule sur un téléphone. `auto-fill` et non `auto-fit` : deux ou
 * trois éditions gardent la largeur d'une carte de module au lieu de s'étirer sur la ligne. */
.mf-pile:has( > .ed-l ) { display: grid; grid-template-columns: repeat( auto-fill, minmax( 290px, 1fr ) ); gap: 14px; }
.mf-pile > .ed-l { flex-direction: column; align-items: stretch; flex-wrap: nowrap; gap: var(--spacing-3); padding: 16px; }
.mf-pile > .ed-l .ed-l-ico { width: 52px; height: 52px; }
.mf-pile > .ed-l .mf-txt { flex: 1 1 auto; }
.mf-pile > .ed-l .pf-c { align-self: flex-start; }
.mf-pile > .ed-l .ed-l-bts { flex-basis: auto; padding-left: 0; margin-top: auto; }

/* ═══ La ligne partout (0.121.0) ═════════════════════════════════════════
 * La ligne des réglages devient la seule boîte de l'application, hors objets
 * qu'on manipule (classe, rituel du jour, modules, éditions). À droite, une
 * seule chose : → on va ailleurs, › ça se déplie (avec la valeur actuelle),
 * un interrupteur, un bouton, ou ⋯ pour les gestes secondaires. */
.reg-val { flex: none; max-width: 44%; text-align: right; color: var(--color-primary); font-weight: 800; font-size: 14px; line-height: 1.3; }
.reg-val.join-code { font-size: 13px; }
.reg-fl { transition: transform .15s; }
details.reg-plie { background: var(--color-surface-raised); border: 2px solid var(--color-line); border-radius: var(--radius-lg); }
details.reg-plie:hover { border-color: var(--color-brand-band); }
details.reg-plie > summary.reg-ligne { border: 0; background: none; list-style: none; cursor: pointer; }
details.reg-plie > summary::-webkit-details-marker { display: none; }
details.reg-plie[open] > summary .reg-fl { transform: rotate(90deg); }
.reg-corps { padding: var(--spacing-4) 18px 18px; border-top: 1px solid var(--color-line); }
.reg-corps > .field:first-child, .reg-corps > fieldset:first-child { margin-top: 0; }
.reg-corps > ul { list-style: none; margin: 0; padding: 0; }
.reg-ico.is-num { --t: var(--color-ink-muted); font: 600 16px/1 Fredoka, sans-serif; }
.reg-ico .mod-icon, .reg-ligne > .mod-icon { flex: none; }
.reg-code { font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace !important; letter-spacing: .08em; }
.reg-ok-t { color: var(--color-success-strong) !important; }
.reg-voir { display: inline-block; margin-top: 4px; font-size: 13px; font-weight: 800; color: var(--color-primary); }
.reg-intro { margin-top: calc( -1 * var(--spacing-1) ); margin-bottom: var(--spacing-3); }
.reg-note { margin-top: var(--spacing-3); font-size: 14px; line-height: 1.5; color: var(--color-ink-muted); font-weight: 600; }
/* La page des élèves : les trois étapes d'une classe sans codes, la carte qui les ouvre, les groupes de lignes. */
.reg-groupe + .reg-groupe { margin-top: var(--spacing-8); }
.etapes { list-style: none; margin: var(--spacing-4) 0 var(--spacing-5); padding: 0; display: flex; flex-wrap: wrap; gap: var(--spacing-2); }
.et { display: flex; align-items: center; gap: 8px; padding: 6px 12px 6px 6px; border: 2px solid var(--color-line); border-radius: var(--radius-full); background: var(--color-surface-raised); color: var(--color-ink-muted); font-size: 14px; }
.et-n { width: 26px; height: 26px; border-radius: 50%; background: var(--color-line); display: inline-flex; align-items: center; justify-content: center; font-weight: 800; font-size: 13px; }
.et.is-now { border-color: var(--color-primary); color: var(--color-ink); font-weight: 700; }
.et.is-now .et-n { background: var(--color-primary); color: var(--color-on-primary); }
.cree { padding: var(--spacing-6); }
.cree-titre { font-size: 22px; margin: 4px 0 6px; }
.cree-actions { gap: var(--spacing-3); align-items: center; margin-top: var(--spacing-4); }
.cree-n { width: 5rem; min-height: 44px; text-align: center; }
.ratt { margin: var(--spacing-6) 0 var(--spacing-4); }
.ratt-actions { gap: var(--spacing-3); }
@media ( max-width: 32rem ) { .cree { padding: var(--spacing-4); } }
.reg-pile.is-serree { gap: 6px; }
ul.reg-pile { list-style: none; padding: 0; margin-bottom: 0; }
a.reg-txt { color: inherit; text-decoration: none; }
a.reg-txt:hover > b { color: var(--color-primary); }
.reg-txt .roster-wall { margin: 4px 0 0; }
.reg-pile.is-serree .reg-ligne { padding: 10px 14px; gap: 12px; }
.reg-pile.is-serree .reg-ico { width: 34px; height: 34px; font-size: 15px; }
.reg-plus { flex: none; display: flex; gap: 6px; align-items: center; margin: 0; }
.reg-plus input[type=number] { width: 60px; padding: 6px 8px; border: 2px solid var(--color-line); border-radius: var(--radius-md); font: inherit; font-weight: 800; text-align: center; background: var(--color-surface-raised); color: var(--color-ink); }
.reg-menu { position: relative; flex: none; }
.reg-menu > summary { list-style: none; width: 38px; height: 38px; display: grid; place-items: center; border-radius: var(--radius-md);
	border: 2px solid var(--color-line); font-weight: 900; cursor: pointer; color: var(--color-ink); }
.reg-menu > summary::-webkit-details-marker { display: none; }
.reg-menu > summary:focus-visible { outline: 3px solid var(--color-primary); outline-offset: 2px; }
.reg-menu[open] > summary { border-color: var(--color-ink); }
.reg-menu-liste { position: absolute; right: 0; top: calc( 100% + 6px ); z-index: 5; min-width: 200px; padding: 6px; display: flex; flex-direction: column;
	background: var(--color-surface-raised); border: 2px solid var(--color-ink); border-radius: var(--radius-md); box-shadow: 0 4px 0 var(--color-ink); }
.reg-menu-liste form { margin: 0; }
.reg-menu-liste button, .reg-menu-liste a { display: block; width: 100%; padding: 10px 12px; border: 0; border-radius: var(--radius-sm); background: none;
	font: inherit; font-weight: 800; text-align: left; color: var(--color-ink); text-decoration: none; cursor: pointer; }
.reg-menu-liste button:hover, .reg-menu-liste a:hover { background: var(--color-surface-sunken); }
.reg-menu-liste .is-danger { color: var(--color-error-strong); }
@media (max-width: 32rem) {
	.reg-ligne:has( > .reg-menu ), .reg-ligne:has( > .reg-fl ):not( :has( > .reg-val ) ), .reg-pile.is-serree .reg-ligne { flex-wrap: nowrap; align-items: center; }
	.reg-ligne:has( > .reg-menu ) .reg-txt, .reg-ligne:has( > .reg-fl ) .reg-txt, .reg-pile.is-serree .reg-ligne .reg-txt { flex: 1 1 auto; }
	.reg-pile.is-serree .reg-ligne > .btn, .reg-pile.is-serree .reg-ligne > .reg-form { margin-left: 0; }
	.reg-ligne:has( > .reg-val ) { flex-wrap: wrap; }
	.reg-ligne > .reg-val { order: 3; flex: 1 0 calc( 100% - 58px ); max-width: none; margin-left: 58px; margin-top: -8px; text-align: left; }
	.reg-ligne:has( > .reg-val ) > .reg-fl { order: 2; align-self: center; }
	.reg-ligne.reg-ligne:has( > .reg-val ) > .reg-txt { flex: 1 1 0; }
	.reg-ligne > .reg-plus { margin-left: 58px; }
}
.aide-liste { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.aide-liste .hc-row { padding: var(--spacing-2) 0; border-radius: 0; }
.aide-liste .hc-row + .hc-row { border-top: 1px solid var(--color-line); }
.aide-liste .hc-row:hover { background: none; }

/* ═══ Travail à la maison : périodes et comparaison (0.121.0) ═══ */
.sv-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.sv-chips label { cursor: pointer; }
.sv-chips input { position: absolute; opacity: 0; pointer-events: none; }
.sv-chips span { display: inline-block; padding: 8px 14px; border-radius: var(--radius-full); border: 2px solid var(--color-line-strong); background: var(--color-surface-raised); font-weight: 800; font-size: 14px; }
.sv-chips input:checked + span { background: var(--color-ink); border-color: var(--color-ink); color: var(--color-surface-raised); }
.sv-chips input:focus-visible + span { outline: 3px solid var(--color-primary); outline-offset: 2px; }
.sv-chips.is-comp input:checked + span { background: var(--color-gold); border-color: var(--color-gold-strong); color: var(--color-ink); }
.sv-dates { display: flex; flex-wrap: wrap; gap: 10px; align-items: end; margin-top: 10px; }
.sv-dates label { display: flex; flex-direction: column; gap: 4px; font-weight: 800; font-size: 13px; color: var(--color-ink-muted); }
.sv-dates input { padding: 8px 10px; border: 2px solid var(--color-line-strong); border-radius: var(--radius-md); font: inherit; font-weight: 700; background: var(--color-surface-raised); color: var(--color-ink); }
.sv-resume { margin-top: 12px; font-weight: 700; font-size: 14px; color: var(--color-ink-muted); line-height: 1.5; }
.sv-resume b { color: var(--color-ink); }
.sv-resume i { font-style: normal; background: color-mix( in srgb, var(--color-gold) 35%, transparent ); padding: 1px 6px; border-radius: 6px; color: var(--color-ink); }
@supports not (color: color-mix(in srgb, red, blue)) { .sv-resume i { background: rgba(242,182,60,0.35); } }
.sv-kpis { display: grid; grid-template-columns: repeat( 3, 1fr ); gap: 8px; }
.sv-kpi { background: var(--color-surface-raised); border: 2px solid var(--color-line); border-radius: var(--radius-lg); padding: 12px 12px 10px; min-width: 0; }
.sv-kpi b { display: block; font: 600 26px/1.1 Fredoka, sans-serif; }
.sv-kpi span { display: block; font-size: 13px; font-weight: 700; color: var(--color-ink-muted); line-height: 1.3; margin-top: 2px; }
.sv-kpi .sv-d { margin-top: 6px; }
.sv-d { display: block; font-size: 13px; font-weight: 800; }
.sv-up { color: var(--color-success-strong) !important; }
.sv-down { color: var(--color-gold-strong) !important; }
.sv-eq { color: var(--color-ink-faint) !important; }
.sv-graph { background: var(--color-surface-raised); border: 2px solid var(--color-line); border-radius: var(--radius-lg); padding: 12px 10px 8px; }
.sv-graph svg { display: block; width: 100%; max-width: 620px; height: auto; margin: 0 auto; }
.sv-leg { display: flex; flex-wrap: wrap; gap: 14px; font-size: 13px; font-weight: 700; color: var(--color-ink-muted); margin: 8px 4px 2px; }
.sv-leg i { display: inline-block; width: 12px; height: 12px; border-radius: 3px; margin-right: 6px; vertical-align: -1px; }
.sv-barres { display: flex; flex-direction: column; gap: 3px; margin-top: 6px; }
.sv-barre { display: block; height: 7px; border-radius: 4px; background: var(--color-surface-sunken); overflow: hidden; }
.sv-barre i { display: block; height: 100%; border-radius: 4px; background: var(--color-primary); }
.sv-barre.is-comp i { background: var(--color-gold); }
.sv-taux { flex: none; text-align: right; min-width: 62px; }
.sv-taux b { display: block; font: 600 22px/1 Fredoka, sans-serif; }
.sv-taux b.is-bas { color: var(--color-gold-strong); }
.sv-taux small { display: block; margin-top: 4px; font-size: 12px; font-weight: 800; }

/* ═══ Le bouche-à-oreille : invitation et séquence partagée (0.123.0) ═══ */
.inv-qui { display: flex; gap: 12px; align-items: center; margin-bottom: 6px; }
.inv-av { width: 44px; height: 44px; border-radius: 50%; display: grid; place-items: center; font: 700 18px Fredoka, sans-serif; background: var(--color-primary); color: var(--color-surface-raised); flex: none; }
.inv-carte { background: var(--color-surface-raised); border: 2px solid var(--color-ink); border-radius: var(--radius-xl); box-shadow: 0 6px 0 var(--color-ink); padding: 20px; margin-top: 20px; }
.inv-eye { display: block; font: 700 12px/1.3 Fredoka, sans-serif; text-transform: uppercase; letter-spacing: .08em; color: var(--color-ink-muted); }
.inv-mods { display: flex; flex-wrap: wrap; gap: 8px; margin: 14px 0 18px; }
.inv-mods > span { display: inline-flex; align-items: center; gap: 8px; padding: 4px 12px 4px 4px; border-radius: var(--radius-full); border: 2px solid var(--color-line); font-weight: 800; font-size: 13px; }
.inv-mods .mod-icon { width: 26px; height: 26px; border-radius: 8px; }
.inv-mods .mod-icon svg { width: 16px; height: 16px; }
.inv-fiches { list-style: none; margin: 14px 0 18px; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.inv-fiches li { display: flex; gap: 10px; align-items: center; padding: 10px 12px; border: 2px solid var(--color-line); border-radius: var(--radius-md); font-weight: 700; min-width: 0; overflow-wrap: anywhere; }
.inv-large { width: 100%; justify-content: center; text-align: center; }
.inv-centre { text-align: center; }
.inv-lien { display: flex; gap: 8px; align-items: stretch; margin-top: 6px; }
.inv-lien input { flex: 1; min-width: 0; font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace; font-weight: 700; }
.inv-msg { width: 100%; font: inherit; font-size: 14px; line-height: 1.5; padding: 10px 12px; border: 2px solid var(--color-line); border-radius: var(--radius-md); background: var(--color-surface-raised); color: var(--color-ink); resize: vertical; }
.inv-partage { display: flex; flex-wrap: wrap; gap: 8px; }
.inv-partage .inv-sms { display: none; }
@media (pointer: coarse) { .inv-partage .inv-sms { display: inline-flex; } }

/* Les fenêtres : une barre de défilement fine, qui ne mord pas les coins arrondis. */
dialog.avm { scrollbar-width: thin; scrollbar-color: var(--color-line-strong) transparent; }
dialog.avm::-webkit-scrollbar { width: 10px; }
dialog.avm::-webkit-scrollbar-track { background: transparent; margin: 18px 0; }
dialog.avm::-webkit-scrollbar-thumb { background: var(--color-line-strong); border-radius: 10px; border: 3px solid transparent; background-clip: padding-box; }
.inv-reglage > summary { cursor: pointer; font-weight: 800; font-size: 14px; color: var(--color-primary); list-style: none; }
.inv-reglage > summary::-webkit-details-marker { display: none; }
.inv-reglage > summary::after { content: " ›"; }
.inv-reglage[open] > summary::after { content: " ⌄"; }
.inv-reglage > form { margin-top: var(--spacing-3); }
.inv-oui, .inv-non { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; font-weight: 700; font-size: 14px; }
.inv-oui li::before { content: "✓ "; color: var(--color-success-strong); font-weight: 900; }
.inv-non li::before { content: "✕ "; color: var(--color-ink-faint); font-weight: 900; }
.inv-etapes { list-style: none; margin: 22px 0 0; padding: 0; display: flex; flex-direction: column; gap: 10px; counter-reset: etape; }
.inv-etapes li { display: flex; gap: 12px; align-items: flex-start; font-weight: 700; line-height: 1.45; }
.inv-etapes li::before { counter-increment: etape; content: counter(etape); flex: none; width: 28px; height: 28px; border-radius: 50%; display: grid; place-items: center; background: var(--color-primary); color: var(--color-surface-raised); font: 700 14px Fredoka, sans-serif; }
.inv-code { font: 700 30px/1 ui-monospace, Menlo, Consolas, monospace; letter-spacing: .12em; text-align: center; padding: 14px; border: 2px solid var(--color-ink); border-radius: var(--radius-lg); background: var(--color-surface-raised); }
.inv-saisie { font-family: ui-monospace, Menlo, Consolas, monospace; font-weight: 800; letter-spacing: .1em; text-transform: uppercase; }

/* ------------------------------------------------------------------
 * L'écran d'attente : prouver qu'on enseigne (0.131.0).
 * Les cartes de choix sont des liens : sans script, choisir une voie
 * est une navigation ordinaire.
 * ------------------------------------------------------------------ */
a.onboard-card { color: inherit; text-decoration: none; }
.pending-proof .onboard-hero { text-align: center; }
.proof-emoji { font-size: 26px; flex: none; width: 40px; text-align: center; }
.proof-drop {
	position: relative; display: flex; flex-direction: column; align-items: center; gap: var(--spacing-1);
	padding: var(--spacing-5) var(--spacing-4); border: 2px dashed var(--color-line-strong); border-radius: var(--radius-lg);
	background: var(--color-surface-raised); text-align: center; cursor: pointer;
}
.proof-drop:hover, .proof-drop:focus-within { border-color: var(--color-primary); }
.proof-drop input[type="file"] { position: absolute; inset: 0; opacity: 0; cursor: pointer; }
.proof-drop-icon { font-size: 30px; }
.proof-or { display: flex; align-items: center; gap: var(--spacing-3); margin: var(--spacing-3) 0; color: var(--color-ink-muted); font-weight: 700; font-size: 13px; }
.proof-or::before, .proof-or::after { content: ""; flex: 1; border-top: 1px solid var(--color-line); }
.pending-again .link-button { background: none; border: 0; padding: 0; font: inherit; color: var(--color-primary); text-decoration: underline; cursor: pointer; }
.pending-proof a.onboard-back { text-decoration: none; }

/* ═══ Les offres ═════════════════════════════════════════════════════════
 * Une offre se lit dans un cadre violet plein — la couleur de l'action —,
 * jamais dans l'or, réservé à ce qui reste à faire. Le prix de référence est
 * barré à côté du nouveau : le sens ne tient pas à la seule couleur. */
.offre { border: 2px solid var(--color-primary); border-radius: var(--radius-lg); background: var(--color-primary-soft); padding: var(--spacing-3) var(--spacing-4); }
.offre-titre { display: block; font: 600 16px/1.3 Fredoka, sans-serif; color: var(--color-primary-active); }
.offre p { margin: var(--spacing-1) 0 0; font-size: 14px; line-height: 1.45; }
.offre .offre-mention { margin-top: var(--spacing-2); font-size: 12px; color: var(--color-ink-muted); }
.prix-barre { text-decoration: line-through; font-weight: 600; color: var(--color-ink-muted); margin-right: var(--spacing-1); }
.offre-accept { align-items: flex-start; text-align: left; }
.offre-accept input { margin-top: .25em; flex: none; }

/* Dans l'échéancier : ce qu'est chaque période, et ce qui est offert. */
.schedule-row.is-offered { border-style: dashed; background: var(--color-surface); }
.schedule-what { display: block; font-weight: 700; color: var(--color-ink); }

/* Le rappel d'une offre, sur « Mes classes » : la ligne de la formule, en violet. */
.trial-note.is-offre { border-style: solid; border-color: var(--color-primary); color: var(--color-ink); }
.trial-note.is-offre a { font-weight: 700; color: var(--color-primary-active); }

/* ═══ Pares mínimos : une paire par écran ═══════════════════════════════════
 * Deux cartes A et B côte à côte, une illustration par mot. À l'écoute, rien
 * ne dit laquelle est la bonne ; à la réponse (`.pp.is-open`, la ligne
 * suivante montre les mêmes cartes), la bonne s'encadre et prend sa coche,
 * l'autre s'estompe, et le sens du mot paraît sous chacune. Tout est en
 * classes : la page ne dépend pas de `:has()`.
 *
 * Les dessins sont décoratifs (`aria-hidden`, le mot et son sens sont écrits).
 * Un mot sans dessin garde son cadre, en pointillés. */
.pp { display: flex; flex-direction: column; gap: var(--spacing-4); width: 100%; }
.pp-cards { display: grid; grid-template-columns: repeat(2, minmax(0, 22rem)); gap: var(--spacing-6); }
.pp-card {
	position: relative; display: flex; flex-direction: column; align-items: center; gap: .2em;
	min-width: 0; padding: .6em .8em .7em;
	border: 3px solid var(--color-proj-line); border-radius: var(--radius-xl);
	background: rgba(255, 255, 255, .045); transition: opacity .2s ease;
}
.pp-pic {
	display: grid; place-items: center; width: 100%; padding: .4em;
	border-radius: calc(var(--radius-xl) - 6px); background: rgba(255, 255, 255, .07);
}
.pp-pic.is-none { border: 3px dashed var(--color-proj-line); background: transparent; padding: calc(.4em - 3px); }
/* La hauteur de la carte vient du dessin, mesuré sur la hauteur de la
 * projection comme les autres images ; le dessin est carré. */
.pp-img,
.pp-pic.is-none::before { content: ""; display: block; width: 100%; max-width: calc(clamp(96px, 24vh, 260px) * var(--proj-fit, 1)); aspect-ratio: 1; object-fit: contain; }
.pp-w {
	font-family: Fredoka, sans-serif; font-weight: 700; line-height: 1.05; text-align: center;
	font-size: calc(clamp(30px, 7vh, 76px) * var(--proj-fit, 1)); overflow-wrap: anywhere;
}
.pp-w b { color: var(--color-gold); margin-right: .35em; }
.pp-sens {
	font-weight: 700; color: var(--color-proj-ink-muted); text-align: center; min-height: 1.3em;
	font-size: calc(clamp(16px, 3vh, 34px) * var(--proj-fit, 1)); visibility: hidden;
}
.pp-ok {
	position: absolute; top: -.7em; right: -.6em; display: none; place-items: center;
	width: 1.7em; height: 1.7em; border-radius: 50%;
	background: var(--color-proj-accent); color: var(--color-proj-surface); font-weight: 900;
	font-size: calc(clamp(16px, 3vh, 32px) * var(--proj-fit, 1));
}
.pp.is-open .pp-sens { visibility: visible; }
.pp.is-open .pp-card { opacity: .5; }
.pp.is-open .pp-card.is-right {
	opacity: 1; border-color: var(--color-proj-accent);
	box-shadow: 0 0 0 4px color-mix(in srgb, var(--color-proj-accent) 25%, transparent);
}
@supports not (color: color-mix(in srgb, red, blue)) { .pp.is-open .pp-card.is-right { box-shadow: 0 0 0 4px rgba(255,196,107,0.25); } }
.pp.is-open .pp-card.is-right .pp-ok { display: grid; }

/* La réponse remplace l'écoute au même endroit : pas de nouvelle arrivée. */
.proj-shell[data-vd-module="pares-minimos"] .proj-row.revealed { animation: none; }

@media (max-width: 63.9375rem) {
	.pp-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--spacing-3); }
	.pp-img,
	.pp-pic.is-none::before { max-width: clamp(64px, 24vw, 140px); }
	.pp-w { font-size: clamp(22px, 7vw, 34px); }
	.pp-sens { font-size: clamp(14px, 4vw, 18px); }
}

/* ═══ ¿Dónde está? : un dessin et une question par écran ═══════════════════
 * Les cinq dessins et les cinq questions de la séance sont tous dans la scène ;
 * un seul se montre, celui de la ligne ouverte (`data-vd-cursor`, tenu par le
 * script). Avant le premier geste, ou sans curseur, c'est le premier. Tout est
 * en sélecteurs d'attribut : rien ne dépend de `:has()`.
 *
 * Le dessin est décoratif au sens où le nom du dessin (`alt`) dit ce qu'il montre
 * sans dire où : la réponse est écrite sous la question, voilée. */
.prep-pic,
.prep-q { display: none; }
.proj-shell[data-vd-cursor="0"] .prep-pic[data-at="0"],
.proj-shell[data-vd-cursor="1"] .prep-pic[data-at="1"],
.proj-shell[data-vd-cursor="2"] .prep-pic[data-at="2"],
.proj-shell[data-vd-cursor="3"] .prep-pic[data-at="3"],
.proj-shell[data-vd-cursor="4"] .prep-pic[data-at="4"],
.proj-shell[data-vd-cursor="5"] .prep-pic[data-at="5"],
.proj-shell[data-vd-cursor="6"] .prep-pic[data-at="6"],
.proj-shell[data-vd-cursor="7"] .prep-pic[data-at="7"],
.proj-shell[data-vd-cursor="-1"] .prep-pic[data-at="0"],
.proj-shell:not([data-vd-cursor]) .prep-pic[data-at="0"] { display: block; }
.proj-shell[data-vd-cursor="0"] .prep-q[data-at="0"],
.proj-shell[data-vd-cursor="1"] .prep-q[data-at="1"],
.proj-shell[data-vd-cursor="2"] .prep-q[data-at="2"],
.proj-shell[data-vd-cursor="3"] .prep-q[data-at="3"],
.proj-shell[data-vd-cursor="4"] .prep-q[data-at="4"],
.proj-shell[data-vd-cursor="5"] .prep-q[data-at="5"],
.proj-shell[data-vd-cursor="6"] .prep-q[data-at="6"],
.proj-shell[data-vd-cursor="7"] .prep-q[data-at="7"],
.proj-shell[data-vd-cursor="-1"] .prep-q[data-at="0"],
.proj-shell:not([data-vd-cursor]) .prep-q[data-at="0"] { display: block; }
.prep-img { display: block; width: 100%; height: auto; max-height: calc(58vh * var(--proj-fit, 1)); object-fit: contain; border-radius: calc(var(--radius-xl) - 8px); }
/* Le cadre de la scène plafonne les images à 36 vh sur un écran étroit : le dessin
 * suit ici la largeur du cadre, il a ses proportions (560 × 340). */
body.projection .proj-media .proj-frame .prep-img { width: 100%; max-height: none; margin-inline: 0; }
.prep-ans { display: block; }
/* La préposition : soulignée, dans la couleur d'accent de la scène. */
.prep-hl {
	color: var(--color-proj-accent);
	text-decoration: underline; text-decoration-thickness: .09em; text-underline-offset: .2em; text-decoration-skip-ink: none;
	text-decoration-color: var(--color-proj-accent);
}
/* La traduction, en petit, sous la phrase. */
.prep-gloss { display: block; margin-top: var(--spacing-2); font-weight: 700; color: var(--color-proj-ink-muted); font-size: calc(clamp(16px, min(2.8vh, 4.6vw), 30px) * var(--proj-fit, 1)); }
/* La réponse se lit juste sous sa question, pas au milieu de la colonne. */
body.projection .proj-shell[data-vd-module="donde-esta"] .proj-main > [data-vd-start] { justify-content: flex-start; flex: 0 0 auto; }
/* Le dessin remplace le précédent au même endroit : pas de nouvelle arrivée. */
.proj-shell[data-vd-module="donde-esta"] .proj-row.revealed { animation: none; }

/* Une fenêtre couchée plus étroite que soixante-quatre rem (un cadre de 960 sur
 * 540, un moniteur zoomé) garde le dessin à gauche et la scène à droite : la
 * scène y a la hauteur de l'écran, et un empilement ferait passer la réponse
 * dans une seconde colonne, hors de la fenêtre. */
@media (max-width: 63.9375rem) and (min-width: 40rem) and (min-height: 30rem) and (orientation: landscape) {
	body.projection .proj-shell[data-vd-module="donde-esta"] .proj-body { flex-direction: row !important; flex-wrap: nowrap; align-items: center !important; gap: var(--spacing-4); }
	body.projection .proj-shell[data-vd-module="donde-esta"] .proj-media { flex: 0 0 46% !important; width: auto !important; max-width: 46% !important; align-self: center !important; }
	body.projection .proj-shell[data-vd-module="donde-esta"] .proj-main { flex: 1 1 0 !important; width: auto !important; min-width: 0; }
	body.projection .proj-shell[data-vd-module="donde-esta"] .proj-media .proj-frame { max-height: none; }
	body.projection .proj-shell[data-vd-module="donde-esta"] .prep-img { max-height: calc(54vh * var(--proj-fit, 1)); }
	body.projection .proj-shell[data-vd-module="donde-esta"] .proj-media + .proj-main > .t-proj-q { font-size: calc(clamp(22px, 4.4vh, 40px) * var(--proj-fit, 1)); }
}

/* ═══ Me gusta : qui aime, quoi, et la phrase en trois couleurs ═══════════════
 * Les six scènes de la séance (la question, ou la phrase d'un autre, puis la
 * carte de la personne, le symbole et la carte de la chose) sont toutes dans la
 * page ; une seule se montre, celle de la ligne ouverte (`data-vd-cursor`, tenu
 * par le script). Tout est en sélecteurs d'attribut : rien ne dépend de `:has()`.
 *
 * Le pronom est or, le verbe vert et souligné, la chose violette, « no » rouge
 * clair : la règle se lit à la couleur. Les cartes sont des conteneurs — les mots
 * y suivent la largeur de la carte (`cqw`), comme les zones des éditions, pour
 * qu'aucun ne sorte de sa case ; sans les unités de conteneur, la taille de repli
 * (en hauteur de fenêtre) reste. */
.proj-shell[data-vd-module="me-gusta"] {
	--gus-p: var(--color-proj-accent);
	--gus-v: var(--color-proj-success);
	--gus-n: #b7a4ff;
	--gus-no: #ff9a9a;
}
.gus-item { display: none; }
.proj-shell[data-vd-cursor="0"] .gus-item[data-at="0"],
.proj-shell[data-vd-cursor="1"] .gus-item[data-at="1"],
.proj-shell[data-vd-cursor="2"] .gus-item[data-at="2"],
.proj-shell[data-vd-cursor="3"] .gus-item[data-at="3"],
.proj-shell[data-vd-cursor="4"] .gus-item[data-at="4"],
.proj-shell[data-vd-cursor="5"] .gus-item[data-at="5"],
.proj-shell[data-vd-cursor="6"] .gus-item[data-at="6"],
.proj-shell[data-vd-cursor="7"] .gus-item[data-at="7"],
.proj-shell[data-vd-cursor="-1"] .gus-item[data-at="0"],
.proj-shell:not([data-vd-cursor]) .gus-item[data-at="0"] { display: block; }
.gus-q .t-proj-q { margin: 0; }
.gus-by { display: block; font-family: Nunito; font-weight: 800; letter-spacing: .02em; color: var(--color-proj-ink-muted); font-size: calc(clamp(15px, min(2.6vh, 4.2vw), 26px) * var(--proj-fit, 1)); }
.gus-said { display: block; font-size: calc(clamp(24px, min(5.4vh, 6.4vw), 60px) * var(--proj-fit, 1)); overflow-wrap: anywhere; }
.gus-said::before { content: "\00ab\00a0"; color: var(--color-proj-ink-muted); }
.gus-said::after { content: "\00a0\00bb"; color: var(--color-proj-ink-muted); }

.gus-scene {
	container-type: inline-size;
	display: grid;
	grid-template-columns: minmax(0, 1fr) auto minmax(0, 1.3fr);
	align-items: stretch;
	gap: var(--spacing-4);
	max-width: 36rem;
	margin: var(--spacing-4) 0 var(--spacing-5);
}
.gus-card {
	container-type: inline-size;
	display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--spacing-2);
	min-width: 0; padding: var(--spacing-3) var(--spacing-3);
	text-align: center; background: var(--color-proj-surface);
	border-radius: var(--radius-xl);
}
.gus-avs { display: flex; justify-content: center; }
.gus-avatar { display: block; width: calc(clamp(44px, 9.5vh, 96px) * var(--proj-fit, 1)); height: auto; }
.gus-avs .gus-avatar + .gus-avatar { margin-left: -.9em; }
.gus-img { display: block; width: auto; max-width: 100%; height: calc(clamp(56px, 13vh, 120px) * var(--proj-fit, 1)); object-fit: contain; }
.gus-lab {
	font-family: Fredoka; font-weight: 700; line-height: 1.12; overflow-wrap: anywhere; max-width: 100%;
	font-size: calc(clamp(18px, 3.2vh, 34px) * var(--proj-fit, 1));
	font-size: min(calc(clamp(18px, 3.2vh, 34px) * var(--proj-fit, 1)), 13cqw);
}
.gus-who[data-kind="tonic"] .gus-lab {
	font-size: calc(clamp(24px, 5vh, 52px) * var(--proj-fit, 1));
	font-size: min(calc(clamp(24px, 5vh, 52px) * var(--proj-fit, 1)), 17cqw);
}
.gus-sym { display: flex; align-items: center; justify-content: center; }
.gus-symbol { display: block; width: calc(clamp(30px, 6vh, 64px) * var(--proj-fit, 1)); height: auto; }

body.projection .proj-shell[data-vd-module="me-gusta"] [data-vd-veil] { display: block; }
.gus-ans { display: block; }
.gus-sent { display: block; color: var(--color-proj-ink); line-height: 1.2; overflow-wrap: anywhere; }
.gus-a, .gus-t, .gus-x, .gus-dot { color: var(--color-proj-ink); }
.gus-no { color: var(--gus-no); }
.gus-p { color: var(--gus-p); }
.gus-v { color: var(--gus-v); text-decoration: underline; text-decoration-thickness: .09em; text-underline-offset: .2em; text-decoration-skip-ink: none; }
.gus-n { color: var(--gus-n); }
/* Dévoilée, la phrase garde ses couleurs : la règle générale d'un voile levé les
 * ramènerait toutes à celle du texte. */
.proj-shell[data-vd-module="me-gusta"] .proj-veiled.revealed .gus-a,
.proj-shell[data-vd-module="me-gusta"] .proj-veiled.revealed .gus-t,
.proj-shell[data-vd-module="me-gusta"] .proj-veiled.revealed .gus-x,
.proj-shell[data-vd-module="me-gusta"] .proj-veiled.revealed .gus-dot { color: var(--color-proj-ink) !important; }
.proj-shell[data-vd-module="me-gusta"] .proj-veiled.revealed .gus-no { color: var(--gus-no) !important; }
.proj-shell[data-vd-module="me-gusta"] .proj-veiled.revealed .gus-p { color: var(--gus-p) !important; }
.proj-shell[data-vd-module="me-gusta"] .proj-veiled.revealed .gus-v { color: var(--gus-v) !important; }
.proj-shell[data-vd-module="me-gusta"] .proj-veiled.revealed .gus-n { color: var(--gus-n) !important; }
.proj-shell[data-vd-module="me-gusta"] .proj-veiled.revealed .gus-why { color: var(--color-proj-ink-muted) !important; }

.gus-why { display: flex; flex-direction: column; gap: var(--spacing-1); margin-top: var(--spacing-3); font-family: Nunito; font-weight: 700; color: var(--color-proj-ink-muted); font-size: calc(clamp(16px, min(2.8vh, 4.4vw), 28px) * var(--proj-fit, 1)); }
.gus-why-line { display: block; overflow-wrap: anywhere; }
.gus-why i { font-style: italic; }

/* La réponse se lit juste sous la scène, pas au milieu de la colonne. */
body.projection .proj-shell[data-vd-module="me-gusta"] .proj-main > [data-vd-start] { justify-content: flex-start; flex: 0 0 auto; }
/* La phrase remplace la précédente au même endroit : pas de nouvelle arrivée. */
.proj-shell[data-vd-module="me-gusta"] .proj-row.revealed { animation: none; }

/* Sous la largeur de la scène à deux colonnes, la scène garde sa grille et la
 * carte de la personne passe au-dessus du symbole seulement quand le téléphone
 * est vraiment étroit. */
@media (min-width: 64rem) {
	body.projection .proj-main.has-panel > .gus-item { padding-right: calc(var(--proj-panel) + var(--spacing-6)); }
}
@media (max-width: 63.9375rem) {
	.gus-scene { gap: var(--spacing-2); margin: var(--spacing-3) 0; }
	.gus-card { padding: var(--spacing-2); }
	.gus-avatar { width: clamp(40px, 12vw, 64px); }
	.gus-img { height: clamp(48px, 16vw, 84px); }
	.gus-symbol { width: clamp(24px, 7vw, 36px); }
}
@media (max-width: 63.9375rem) and (min-width: 40rem) and (min-height: 30rem) and (orientation: landscape) {
	.gus-avatar { width: calc(clamp(36px, 8vh, 64px) * var(--proj-fit, 1)); }
	.gus-img { height: calc(clamp(44px, 11vh, 84px) * var(--proj-fit, 1)); }
	.gus-scene { margin: var(--spacing-2) 0 var(--spacing-3); }
	.gus-why { margin-top: var(--spacing-2); }
}

/* ═══ La roue des verbes sur un écran qui n'est pas un 1080 ═════════════════
 *
 * Retour d'une salle de classe : « l'affichage de la roue ne rentre pas dans
 * l'écran ». Un vieux moniteur 5:4 (1280 × 1024), un navigateur avec ses
 * barres d'onglets et d'outils, parfois un zoom Windows de 125 ou 150 % : la
 * fenêtre utile n'est plus un 1280 × 720 mais un 1024 × 560, voire un
 * 853 × 600. Les captures du projet ne se faisaient qu'à 1280 × 720.
 *
 * Trois pannes distinctes, que le facteur `--proj-fit` ne corrige pas :
 *   - la roue gardait ses vingt-deux rem quelle que soit la hauteur, alors
 *     que `fit()` ne réduit que les caractères — la scène la plus haute
 *     rognait donc son panneau, et le texte tombait à 8 px ;
 *   - sur une fenêtre haute et étroite, les formes verbales grandissaient avec
 *     la hauteur (`vh`) dans une colonne étroite — « podemos » devenait
 *     « podem » ;
 *   - sous soixante-quatre rem, la scène s'empile « comme sur un téléphone »,
 *     alors qu'un moniteur zoomé à 150 % est un paysage de 853 pixels.
 *
 * Tout est donc exprimé en fonction de la fenêtre : la roue dépend de la
 * hauteur qui lui reste, les formes de la largeur de leur colonne (`cqi`,
 * avec le `vw` pour repli), et les marges se resserrent sur une fenêtre basse.
 * Les tailles de texte gardent un plancher de 22 px pour les formes — c'est
 * ce qu'on lit à cinq mètres —, de 14 px pour les étiquettes de personne. */
body.projection .proj-shell[data-vd-module="rueda-verbos"] {
	--rv-roue: max(11rem, min(22rem, calc(100vh - 14rem)));
}

/* Une propriété personnalisée n'a pas de repli de déclaration : sur un navigateur
 * d'avant l'unité `dvh` (Chrome 107 d'un poste de collège), la seconde ligne
 * aurait rendu `var(--rv-roue)` invalide et la roue serait tombée à 0 × 0. On ne
 * la pose donc que là où l'unité existe. */
@supports (height: 100dvh) {
	body.projection .proj-shell[data-vd-module="rueda-verbos"] {
		--rv-roue: max(11rem, min(22rem, calc(100dvh - 14rem)));
	}
}

/* Les formes : trois par ligne, la taille suivant la colonne et la hauteur. */
body.projection .proj-shell[data-vd-module="rueda-verbos"] .proj-group {
	container-type: inline-size;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: var(--spacing-2) var(--spacing-4);
}

body.projection .proj-shell[data-vd-module="rueda-verbos"] .proj-group .proj-answer {
	font-size: calc(clamp(22px, min(5vh, 2.1vw), 60px) * var(--proj-fit, 1));
	font-size: calc(clamp(22px, min(5vh, 4.4cqi), 60px) * var(--proj-fit, 1));
	line-height: 1.15;
	overflow-wrap: break-word;
}

body.projection .proj-shell[data-vd-module="rueda-verbos"] .proj-group .t-eyebrow {
	font-size: calc(clamp(14px, 2.2vh, 22px) * var(--proj-fit, 1));
}

/* Une grande fenêtre haute (le 5:4 de 1280 × 1024) a la place de mettre les
 * formes sur trois lignes de deux, donc plus grandes. */
@media (min-height: 56rem) {
	body.projection .proj-shell[data-vd-module="rueda-verbos"] .proj-group { grid-template-columns: repeat(2, minmax(0, 1fr)); }
	body.projection .proj-shell[data-vd-module="rueda-verbos"] .proj-group .proj-answer {
		font-size: calc(clamp(22px, min(5.4vh, 3vw), 64px) * var(--proj-fit, 1));
		font-size: calc(clamp(22px, min(5.4vh, 5.6cqi), 64px) * var(--proj-fit, 1));
	}
}

/* Une fenêtre basse : marges resserrées, roue bornée par la hauteur, panneau
 * du temps réduit à ses puces. */
@media (max-height: 46rem) {
	body.projection .proj-shell[data-vd-module="rueda-verbos"] { padding-block: var(--spacing-3); }
	body.projection .proj-shell[data-vd-module="rueda-verbos"] .proj-head { gap: var(--spacing-2); }
	body.projection .proj-shell[data-vd-module="rueda-verbos"] .proj-body { margin-top: var(--spacing-3); gap: var(--spacing-4); }
	body.projection .proj-shell[data-vd-module="rueda-verbos"] .proj-foot { margin-top: var(--spacing-3); }
	body.projection .proj-shell[data-vd-module="rueda-verbos"] .proj-foot .proj-btn { padding-block: var(--spacing-2); min-height: 0; }

	/* La colonne de la roue épouse la roue : sans cela, le cadre gardait une
	 * largeur de 40 % et la scène n'avait plus la place de ses formes. */
	body.projection .proj-shell[data-vd-module="rueda-verbos"] .proj-media { flex: 0 0 auto; min-width: 0; width: calc(var(--rv-roue) + 2 * var(--spacing-3) + 6px); }
	body.projection .proj-shell[data-vd-module="rueda-verbos"] .proj-media .proj-frame { padding: var(--spacing-3); }
	body.projection .proj-shell[data-vd-module="rueda-verbos"] .proj-media .wheel-wrap { max-width: var(--rv-roue); }
	body.projection .proj-shell[data-vd-module="rueda-verbos"] .proj-main { min-width: 0; gap: var(--spacing-3); }

	body.projection .proj-shell[data-vd-module="rueda-verbos"] .proj-media + .proj-main > .t-proj-q { font-size: calc(clamp(22px, 4vh, 52px) * var(--proj-fit, 1)); }
	body.projection .proj-shell[data-vd-module="rueda-verbos"] .proj-row:has(.proj-group) .proj-answer-display { font-size: calc(clamp(26px, 6vh, 64px) * var(--proj-fit, 1)); }
	body.projection .proj-shell[data-vd-module="rueda-verbos"] .proj-row-stack { gap: var(--spacing-2); }

	/* Le temps courant est déjà dans la question : l'étiquette du panneau
	 * redit la même chose, et coûte une ligne. */
	body.projection .proj-shell[data-vd-module="rueda-verbos"] .proj-panel { padding: var(--spacing-2) var(--spacing-3); }
	body.projection .proj-shell[data-vd-module="rueda-verbos"] .proj-panel > .t-eyebrow:first-child:not(:only-child) { display: none; }
	body.projection .proj-shell[data-vd-module="rueda-verbos"] .tense-switch { margin-top: 0; gap: var(--spacing-1) var(--spacing-2); }
	body.projection .proj-shell[data-vd-module="rueda-verbos"] .tense-switch .proj-btn { font-size: clamp(14px, 2.4vh, 18px); padding: 2px var(--spacing-3); min-height: 0; }
}

/* Un paysage plus étroit que soixante-quatre rem — un moniteur zoomé à 125 ou
 * 150 % — garde la roue à gauche et la scène à droite : la roue tient dans la
 * hauteur, et il lui reste de la largeur. Les `!important` reprennent la main
 * sur ceux du palier d'empilement. */
@media (max-width: 63.9375rem) and (min-width: 40rem) and (min-height: 30rem) and (orientation: landscape) {
	body.projection .proj-shell[data-vd-module="rueda-verbos"] { height: 100vh; height: 100dvh; min-height: 0; overflow: hidden; overflow: clip; }
	body.projection .proj-shell[data-vd-module="rueda-verbos"] .proj-body { flex: 1 1 auto; min-height: 0; overflow: auto; padding-bottom: 0; }
	body.projection .proj-shell[data-vd-module="rueda-verbos"] .proj-main { flex: 1 1 0; }
	/* La porte du lancement : des puces côte à côte, comme sur un écran large,
	 * et non un empilement de boutons pleine largeur qui sort de la fenêtre. */
	body.projection .proj-shell[data-vd-module="rueda-verbos"] .spin-gate { align-items: flex-start; gap: var(--spacing-3); }
	body.projection .proj-shell[data-vd-module="rueda-verbos"] .spin-choice { flex: 0 1 auto; justify-content: flex-start; min-height: 0; padding: var(--spacing-2) var(--spacing-4); font-size: calc(clamp(17px, 2.6vh, 26px) * var(--proj-fit, 1)); }
	body.projection .proj-shell[data-vd-module="rueda-verbos"] .spin-go { justify-content: flex-start; font-size: calc(clamp(22px, 3.6vh, 38px) * var(--proj-fit, 1)); }
	body.projection .proj-shell[data-vd-module="rueda-verbos"] .proj-media + .proj-main > .t-proj-q { font-size: calc(clamp(22px, 4vh, 52px) * var(--proj-fit, 1)); }
	body.projection .proj-shell[data-vd-module="rueda-verbos"] .proj-body { flex-direction: row !important; flex-wrap: nowrap; align-items: center !important; gap: var(--spacing-4); }
	body.projection .proj-shell[data-vd-module="rueda-verbos"] .proj-media { flex: 0 0 auto !important; align-self: center !important; width: calc(var(--rv-roue) + 2 * var(--spacing-3) + 6px) !important; max-width: 46% !important; }
	body.projection .proj-shell[data-vd-module="rueda-verbos"] .proj-media .proj-frame { max-height: none; aspect-ratio: auto; }
	body.projection .proj-shell[data-vd-module="rueda-verbos"] .proj-media .wheel-wrap { max-width: var(--rv-roue); }
	body.projection .proj-shell[data-vd-module="rueda-verbos"] .proj-main { flex: 1 1 0 !important; width: auto !important; min-width: 0; }
	body.projection .proj-shell[data-vd-module="rueda-verbos"] .proj-foot { position: static; margin-top: var(--spacing-3); box-shadow: none; background: none; padding-block: 0; }
}

/* La roue d'une grande fenêtre haute grandit avec elle : le 5:4 de la salle
 * laissait un tiers de la colonne vide sous une roue de 22 rem. */
@media (min-height: 56rem) {
	body.projection .proj-shell[data-vd-module="rueda-verbos"] .proj-media .wheel-wrap { max-width: min(30rem, 100%); }
}

/* Días señalados : la date, en grand, avant le nom de la fête. */
.dia-date { font-family: Fredoka, sans-serif; font-weight: 700; font-size: calc(clamp(40px, 11vh, 130px) * var(--proj-fit, 1)); line-height: 1; margin: 0; color: var(--color-gold); }
.dia-date small { display: block; font-size: .38em; font-weight: 600; color: var(--color-proj-ink-muted); letter-spacing: .02em; margin-bottom: .15em; text-transform: capitalize; }

/* Le son refusé à l'arrivée : un bandeau au pied de la scène, et le ♪ qui bat. */
.proj-sound-live { flex: 1 0 100%; min-width: 0; }
.proj-sound-live:empty { display: none; }
.proj-sound-note {
	display: flex; align-items: center; gap: var(--spacing-3);
	padding: var(--spacing-2) var(--spacing-4);
	border: 2px solid var(--color-proj-accent);
	border-radius: var(--radius-xl, 18px);
	background: color-mix(in srgb, var(--color-proj-accent) 16%, var(--color-proj-surface));
	color: var(--color-proj-ink);
	font-family: Nunito, sans-serif; font-weight: 700; line-height: 1.3;
	font-size: calc(clamp(16px, 2.7vh, 28px) * var(--proj-fit, 1));
	text-align: left;
}
@supports not (color: color-mix(in srgb, red, blue)) { .proj-sound-note { background: rgb(71,55,56); } }
.proj-sound-txt { margin: 0; flex: 1 1 auto; min-width: 0; }
.proj-sound-txt strong { color: var(--color-proj-accent); font-weight: 800; }
.proj-sound-key { display: inline-block; padding: 0 .4em; border: 2px solid currentColor; border-radius: .4em; font-family: Fredoka, sans-serif; font-weight: 600; line-height: 1.25; }
[data-vd-hear].is-needs-click, [data-vd-speak].is-needs-click { outline: 4px solid var(--color-proj-ink); outline-offset: 4px; animation: pulseRing 2.2s ease-out infinite; }
@media (prefers-reduced-motion: reduce) { [data-vd-hear].is-needs-click, [data-vd-speak].is-needs-click { animation: none; } }
@media (max-width: 63.9375rem) {
	.proj-sound-note { padding: var(--spacing-2) var(--spacing-3); font-size: 15px; }
}

/* « Pares mínimos » sur une fenêtre basse : les deux cartes (image carrée +
 * mot) dépassaient de quelques pixels sous 36 rem de haut, et la scène
 * se réduisait à 80 % sous 40 rem, le bandeau du son
 * bloqué et les boutons ayant déjà pris leur place. */
@media (max-height: 40rem) {
	.pp-img,
	.pp-pic.is-none::before { max-width: calc(clamp(72px, 18vh, 260px) * var(--proj-fit, 1)); }
}

/* Intégrations : le lien pour Canva, et les deux boutons (code, lien) d'une ligne. */
.canva-link { display: flex; gap: var(--spacing-3); align-items: center; flex-wrap: wrap; margin-top: var(--spacing-3); }
.canva-link .field-input { flex: 1 1 18rem; min-width: 0; }
.canva-steps { margin: var(--spacing-3) 0 0; padding-left: 1.4em; display: grid; gap: var(--spacing-2); font-size: 15px; line-height: 1.45; }
.canva-steps li::marker { font-weight: 800; color: var(--color-primary); }
@media (max-width: 40rem) {
	.reg-ligne:has(.reg-form .btn + input) { flex-wrap: wrap; }
	.reg-ligne:has(.reg-form .btn + input) .reg-txt { flex: 1 1 0; min-width: 0; }
	.reg-ligne:has(.reg-form .btn + input) .reg-form { flex: 1 1 100%; display: flex; gap: var(--spacing-2); }
	.reg-ligne:has(.reg-form .btn + input) .reg-form .btn { flex: 1 1 0; }
	.canva-link .btn { flex: 1 1 100%; }
}

/* L'intégration sert à projeter en classe : la règle d'usage, et l'engagement à cocher. */
.vd-regle-usage { border: 2px solid var(--color-gold-strong); }
.vd-regle-liste { margin: var(--spacing-3) 0 0; padding-left: 1.2em; display: grid; gap: var(--spacing-2); }
.vd-engagement { display: flex; gap: var(--spacing-3); align-items: flex-start; cursor: pointer; }
.vd-engagement input { flex: none; width: 1.3rem; height: 1.3rem; margin: 0; accent-color: var(--color-primary); }
.vd-engagement span { line-height: 1.3rem; }

/* Intégrations : les deux usages en onglets, et la règle côté élèves. */
.vd-usages { display: flex; flex-wrap: wrap; gap: var(--spacing-2); margin-top: var(--spacing-4); }
.vd-regle-eleves { border: 2px solid var(--color-family-comprension); }

/* Le cadre intégré : le pied (note, marque) prend sa place dans la hauteur de
 * l'hôte, au lieu de s'ajouter sous une scène qui, elle, mesure déjà tout
 * l'écran. Sans cela, la page défilait de la hauteur du pied dans chaque
 * cadre Canva ou Genially. Le téléphone en portrait garde sa page qui défile. */
@media (min-width: 40rem) and (orientation: landscape) {
	body.projection:has(> .embed-foot) { display: flex; flex-direction: column; height: 100vh; height: 100dvh; min-height: 0; overflow: hidden; overflow: clip; }
	body.projection:has(> .embed-foot) > main { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
	body.projection:has(> .embed-foot) > main > * { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
	body.projection:has(> .embed-foot) .proj-shell { flex: 1 1 auto; height: auto !important; min-height: 0 !important; }
	body.projection:has(> .embed-foot) > .embed-foot { flex: none; }
}

/* Les mots d'une carte d'édition (Día de Muertos…) ne sortent plus de leur
 * carte : la taille suit la largeur de la carte, et un mot trop long se coupe
 * plutôt que de déborder. */
.ed-zones > .proj-zone { container-type: inline-size; }
.ed-zones .proj-answer-lead {
	font-size: min(calc(clamp(26px, min(6.4vh, 9vw), 74px) * var(--proj-fit, 1)), 15cqw);
	overflow-wrap: anywhere;
}

/* « Varier d'un jour à l'autre ? » : la règle des étoiles, dite avant le choix. */
.vd-pick-regle { border: 2px solid var(--color-primary); }
.vd-pick-liste { margin: var(--spacing-2) 0 0; padding-left: 1.2em; display: grid; gap: var(--spacing-1); }
.vd-pick-note { font-weight: 700; color: var(--color-ink); }
.vd-pick-note:empty { display: none; }

/* ═══ La rutina : trois cartes, une horloge, un dessin, un verbe ═══════════════
 * Trois cartes (schéma `zones`) : l'horloge à aiguilles et le dessin de l'action en haut,
 * le verbe à l'infinitif dessous, la phrase modèle voilée jusqu'au clic. Au-dessus des
 * cartes, un bandeau en lecture seule dit à quelle personne on conjugue (« Persona de la
 * sesión: tú ») : il n'est pas cliquable, la personne est tirée au sort.
 *
 * Chaque carte est un conteneur : les mots y suivent la largeur de la carte (`cqw`), comme les
 * zones des éditions, pour qu'aucun ne sorte de sa case. Sans les unités de conteneur, la taille
 * de repli (en hauteur de fenêtre) reste. Rien ici ne dépend de `:has()` ni de `color-mix`. */
.rut-who {
	display: inline-flex; align-items: baseline; gap: .4em; flex: 0 0 auto;
	margin: 0 0 var(--spacing-3); padding: var(--spacing-1) var(--spacing-5);
	background: var(--color-proj-accent); color: var(--color-proj-surface); border-radius: 999px;
	font-family: Nunito; font-weight: 700; line-height: 1.3;
	font-size: calc(clamp(15px, min(2.8vh, 4.4vw), 28px) * var(--proj-fit, 1));
}
.rut-who-val { font-weight: 900; }
.proj-zones.rut-zones { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--spacing-4); align-items: stretch; }
.rut-zones > .proj-zone {
	container-type: inline-size;
	align-items: center; justify-content: flex-start; text-align: center;
	gap: var(--spacing-2); min-width: 0; padding: var(--spacing-4) var(--spacing-3);
}
.rut-top { display: flex; align-items: center; justify-content: center; gap: var(--spacing-3); width: 100%; }
.rut-clock { display: block; flex: 0 1 auto; width: 36%; height: auto; max-height: calc(24vh * var(--proj-fit, 1)); }
.rut-pic { display: block; flex: 0 1 auto; width: 46%; height: auto; max-height: calc(24vh * var(--proj-fit, 1)); object-fit: contain; }
.rut-verb {
	display: block; max-width: 100%; font-family: Nunito; font-weight: 800; letter-spacing: .02em; line-height: 1.15; overflow-wrap: anywhere;
	font-size: calc(clamp(16px, 2.8vh, 30px) * var(--proj-fit, 1));
	font-size: min(calc(clamp(16px, 2.8vh, 30px) * var(--proj-fit, 1)), 8cqw);
}
.rut-ans { display: block; width: 100%; }
.rut-zones .proj-answer-lead {
	font-size: calc(clamp(18px, 3.6vh, 40px) * var(--proj-fit, 1)); line-height: 1.18; overflow-wrap: anywhere;
	font-size: min(calc(clamp(18px, 3.6vh, 40px) * var(--proj-fit, 1)), 7.4cqw);
}
.rut-gloss {
	display: block; margin-top: var(--spacing-2); font-family: Nunito; font-weight: 700; color: var(--color-proj-ink-muted); overflow-wrap: anywhere;
	font-size: calc(clamp(13px, 2.2vh, 24px) * var(--proj-fit, 1));
	font-size: min(calc(clamp(13px, 2.2vh, 24px) * var(--proj-fit, 1)), 5.6cqw);
}
/* Dévoilée, la glose garde sa couleur : la règle générale d'un voile levé la ramènerait à celle du texte. */
.proj-shell[data-vd-module="la-rutina"] .proj-veiled.revealed .rut-gloss { color: var(--color-proj-ink-muted) !important; }
body.projection .proj-shell[data-vd-module="la-rutina"] .proj-main > [data-vd-start] { padding-right: 0; justify-content: flex-start; flex: 0 0 auto; }
/* Le bandeau et les cartes se lisent juste sous la question, pas au milieu de la colonne : centrés,
 * ils remontaient sous le titre dès que la fenêtre était basse. */
body.projection .proj-shell[data-vd-module="la-rutina"] [data-vd-start] > .proj-row { align-items: flex-start; }

/* Téléphone, ou fenêtre étroite en portrait : les cartes s'empilent, l'horloge et le dessin à gauche. */
@media (max-width: 39.9375rem), (max-width: 63.9375rem) and (orientation: portrait) {
	.proj-zones.rut-zones { grid-template-columns: 1fr; gap: var(--spacing-3); }
	.rut-zones > .proj-zone {
		display: grid; grid-template-columns: auto minmax(0, 1fr); grid-template-areas: "top verb" "top body";
		align-items: center; column-gap: var(--spacing-3); row-gap: var(--spacing-1); text-align: left; padding: var(--spacing-3);
	}
	.rut-zones > .proj-zone > .rut-top { grid-area: top; width: auto; flex-direction: column; gap: var(--spacing-2); }
	.rut-zones > .proj-zone > .rut-verb { grid-area: verb; font-size: clamp(16px, 4.6vw, 24px); }
	.rut-zones > .proj-zone > [data-vd-zone-body] { grid-area: body; }
	.rut-clock, .rut-pic { width: clamp(64px, 22vw, 96px); max-height: none; }
	.rut-zones .proj-answer-lead { font-size: clamp(18px, 5.2vw, 28px); }
	.rut-gloss { font-size: clamp(13px, 3.6vw, 18px); }
}
/* Une fenêtre basse (un 960 × 540 : un petit projecteur, un navigateur avec ses barres) : l'horloge et
 * le dessin se resserrent pour que les trois cartes, la consigne et le pied tiennent sans défilement. */
@media (min-width: 40rem) and (max-height: 40rem) {
	.rut-clock, .rut-pic { max-height: calc(15vh * var(--proj-fit, 1)); }
	.rut-zones > .proj-zone { padding: var(--spacing-2) var(--spacing-2); gap: var(--spacing-1); }
	.rut-who { margin-bottom: var(--spacing-1); }
	.proj-zones.rut-zones { gap: var(--spacing-3); }
	body.projection .proj-shell[data-vd-module="la-rutina"] .proj-main { gap: var(--spacing-3); }
	body.projection .proj-shell[data-vd-module="la-rutina"] .proj-panel { padding: var(--spacing-3) var(--spacing-5); }
	.rut-zones .proj-answer-lead {
		font-size: calc(clamp(16px, 3.2vh, 34px) * var(--proj-fit, 1));
		font-size: min(calc(clamp(16px, 3.2vh, 34px) * var(--proj-fit, 1)), 6.8cqw);
	}
}

/* L'invitation à installer l'espace élève : une carte, toujours là tant que l'application n'est pas installée. */
.install-card { padding: var(--spacing-4); border: 2px solid var(--color-primary); border-radius: var(--radius-xl); background: var(--color-surface); display: grid; gap: var(--spacing-3); }
.install-card[hidden] { display: none; }
.install-card-head { display: flex; gap: var(--spacing-3); align-items: center; }
.install-card-head img { flex: none; width: 52px; height: 52px; border-radius: 12px; }
.install-card-title { font-family: var(--font-title-module), system-ui, sans-serif; font-size: 18px; line-height: 1.2; }
.install-card p { margin: 0; }
.install-card-go { width: 100%; }
.install-card-steps { margin: 0; padding: 0; list-style: none; display: grid; gap: var(--spacing-2); }
.install-card-steps li { display: flex; gap: var(--spacing-3); align-items: center; font-weight: 700; }
.install-card-n { flex: none; width: 28px; height: 28px; border-radius: 50%; background: var(--color-primary); color: var(--color-on-primary); display: grid; place-items: center; font-weight: 800; font-size: 14px; }
.install-card-share { display: inline-block; vertical-align: -3px; width: 20px; height: 20px; }
.install-card-go[hidden], .install-card-steps[hidden] { display: none; }

/* Les langues d'un même élève, sur son appareil : une bande sous l'en-tête, calée sur les onglets. */
.langs { background: var(--color-surface); }
.langs-in { max-width: var(--page-w); margin: 0 auto; padding: var(--spacing-3) var(--spacing-4); display: grid; gap: var(--spacing-3); }
.langs-toggle { position: absolute; opacity: 0; width: 1px; height: 1px; pointer-events: none; }
.langs-in:has( .langs-toggle:focus-visible ) .langs-plus { outline: 3px solid var(--color-primary); outline-offset: 2px; }
.langs-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--spacing-2); }
.langs-bar { display: contents; }
.langs-pill { flex: none; display: inline-flex; align-items: center; gap: 6px; min-height: 44px; padding: 6px 14px; border-radius: 999px; border: 2px solid var(--color-line-strong); background: var(--color-surface-raised); color: var(--color-ink); font: 800 14px Nunito, sans-serif; cursor: pointer; }
.langs-pill.is-on { background: var(--color-primary); border-color: var(--color-primary); color: var(--color-on-primary); cursor: default; }
.langs-plus { font-size: 18px; border-style: dashed; background: transparent; color: var(--color-primary); }
.langs-toggle:checked ~ .langs-row .langs-plus { background: var(--color-primary-soft); }
.langs-flag { display: inline-flex; width: 24px; }
.langs-flag svg { width: 100%; height: auto; border-radius: 3px; }
.langs-panel { display: none; max-width: 34rem; padding: var(--spacing-4); border-radius: var(--radius-lg, 16px); border: 1px solid var(--color-line); background: var(--color-surface-raised); }
.langs-toggle:checked ~ .langs-panel { display: block; }
.langs-manage-title { margin-top: var(--spacing-6); padding-top: var(--spacing-4); border-top: 1px solid var(--color-line); }
.langs-list { list-style: none; margin: var(--spacing-3) 0 0; padding: 0; display: grid; gap: var(--spacing-3); }
.langs-list > li { display: grid; grid-template-columns: auto 1fr; align-items: center; column-gap: var(--spacing-2); }
.langs-list > li > .langs-remove { grid-column: 1 / -1; }
.langs-remove > summary { cursor: pointer; font: 800 14px Nunito, sans-serif; color: var(--color-primary); min-height: 44px; display: inline-flex; align-items: center; }
.langs-remove > form { padding: var(--spacing-2) 0; }
.langs-notice { margin: 0; padding: var(--spacing-3) var(--spacing-4); border-radius: var(--radius-md, 12px); font-weight: 700; }
.langs-notice.is-ok { background: var(--color-success-soft); color: var(--color-success-strong); }
.langs-notice.is-warn { background: var(--color-error-soft); color: var(--color-error-strong); }

/* Sur un écran large, les onglets de l'élève et la bande des langues suivent la colonne du contenu. */
@media ( min-width: 40.0625rem ) {
	.tabs.tabs-student, .langs-in { max-width: 44rem; }
}

/* La clôture du cours : chronomètre, ticket, dé. */
.proj-head .cierre-chrono { margin-left: auto; order: 2; display: inline-flex; gap: 10px; align-items: center; padding: 8px 22px; border: 2px solid var(--color-gold); border-radius: 999px; color: var(--color-gold); font-family: Fredoka; font-weight: 700; font-size: 30px; font-variant-numeric: tabular-nums; }
.proj-head .cierre-chrono.is-late { border-color: var(--color-error); color: var(--color-error); }
.cierre-ticket { display: grid; gap: 14px; max-width: 52rem; padding: 28px 36px; border: 3px dashed var(--color-gold); border-radius: 28px; }
.cierre-ticket .t-proj-a { font-size: 44px; line-height: 1.1; }
.cierre-dado { display: grid; gap: var(--spacing-5); justify-items: start; }
.cierre-face { min-height: 3.5em; max-width: 52rem; }
@media ( prefers-reduced-motion: no-preference ) {
	.cierre-face:not(:empty) { animation: cierre-pop .35s ease-out; }
}
@keyframes cierre-pop { from { transform: scale(.94); opacity: 0; } to { transform: scale(1); opacity: 1; } }
.closure-narrow { max-width: 40rem; margin-inline: auto; }
.closure-notes { margin-top: var(--spacing-3); border: 2px dashed var(--color-line-strong); border-radius: var(--radius-lg); }
.closure-notes[open] { border-style: solid; background: var(--color-surface-raised); }
.closure-notes > summary { cursor: pointer; min-height: 52px; padding: 12px 18px; display: flex; flex-wrap: wrap; align-items: center; gap: var(--spacing-2); font-weight: 800; color: var(--color-primary); list-style: none; border-radius: var(--radius-lg); }
.closure-notes > summary::-webkit-details-marker { display: none; }
.closure-notes > summary:focus-visible { outline: 3px solid var(--color-primary); outline-offset: 2px; }
.closure-notes > div { padding: var(--spacing-1) 18px 18px; }

/* Le compte à rebours : un seul nombre à la fois, en grand, au milieu de l'écran. */
[data-vd-module="cuenta-atras"] .proj-main { justify-content: center; align-items: center; text-align: center; }
[data-vd-module="cuenta-atras"] .proj-row { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0; }
[data-vd-module="cuenta-atras"] .proj-row[aria-hidden="true"] { display: none; }
[data-vd-module="cuenta-atras"] .proj-row[aria-hidden="false"]:has( ~ .proj-row[aria-hidden="false"] ) { display: none; }
.cierre-num { font-family: Fredoka; font-weight: 700; font-size: clamp(120px, 42vh, 400px); line-height: .9; letter-spacing: -.02em; }
.cierre-word { font-family: Fredoka; font-weight: 600; font-size: clamp(32px, 9vh, 96px); line-height: 1.1; }
.cierre-word-end { font-size: clamp(48px, 16vh, 180px); font-weight: 700; }

/* Les diapositives de la clôture : débuts de phrase, idées, adieu. */
.cierre-starters { display: flex; flex-wrap: wrap; gap: 16px; }
.cierre-chip { padding: 14px 26px; border: 2px solid var(--color-proj-line); border-radius: 20px; font-family: Fredoka; font-weight: 600; font-size: clamp(24px, 5.2vh, 46px); line-height: 1.1; }
.cierre-idea { display: flex; gap: 14px; align-items: baseline; font-family: Fredoka; font-weight: 600; font-size: clamp(26px, 6vh, 54px); line-height: 1.2; }
.cierre-idea b { color: var(--color-gold); }
.cierre-idea-box { display: block; max-width: 70rem; padding: 18px 30px; border: 3px solid var(--color-gold); border-radius: 22px; }
[data-vd-module="cierre-adios"] .proj-main { justify-content: center; align-items: center; text-align: center; gap: var(--spacing-5); }
[data-vd-module="cierre-adios"] .t-proj-q { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
[data-vd-module="cierre-adios"] .proj-row { justify-content: center; }
.cierre-adios { display: grid; gap: var(--spacing-3); justify-items: center; }
.cierre-adios-big { font-family: Fredoka; font-weight: 700; font-size: clamp(48px, 12vh, 150px); line-height: 1.05; letter-spacing: -.02em; white-space: nowrap; }
.cierre-adios-sub { font-family: Fredoka; font-weight: 500; font-size: clamp(26px, 6vh, 56px); opacity: .9; }
.cierre-rdv { display: inline-flex; gap: 14px; align-items: center; padding: 14px 32px; border: 2px solid var(--color-gold); border-radius: 999px; color: var(--color-gold); font-family: Fredoka; font-weight: 700; font-size: clamp(26px, 6vh, 52px); }
[data-closure-words][hidden] { display: none; }
.cierre-wave { display: inline-block; font-size: clamp(72px, 20vh, 200px); line-height: 1; transform-origin: 70% 75%; }
@media ( prefers-reduced-motion: no-preference ) {
	.cierre-wave { animation: cierre-wave 1.8s ease-in-out 2; }
}
@keyframes cierre-wave { 0%, 100% { transform: rotate(0); } 15% { transform: rotate(16deg); } 30% { transform: rotate(-10deg); } 45% { transform: rotate(16deg); } 60% { transform: rotate(-8deg); } 75% { transform: rotate(10deg); } }

/* Les idées saisies par le professeur ne se devinent pas : masquées jusqu'à leur dévoilement, pas seulement floutées. */
[data-vd-module="cierre-aprendido"] .proj-row[aria-hidden="true"],
[data-vd-module="cierre-proxima"] .proj-row[aria-hidden="true"],
[data-vd-module="cierre-adios"] .proj-row[aria-hidden="true"] { display: none; }

/* Les pastilles d'étape de la boîte à idées filtrent la liste. */
button.idee-filtre { border: 0; font-family: inherit; cursor: pointer; }
button.idee-filtre[aria-pressed="true"] { outline: 3px solid var(--color-primary); outline-offset: 2px; }
button.idee-filtre:focus-visible { outline: 3px solid var(--color-primary); outline-offset: 2px; }

/* Clôture : choisir sa date, et retrouver l'historique dans « Rituels passés ». */
.closure-days { display: flex; flex-wrap: wrap; align-items: center; gap: var(--spacing-2); }
.closure-day { display: inline-flex; align-items: center; gap: var(--spacing-1); min-height: 44px; padding: 8px 14px; border: 2px solid var(--color-line-strong); border-radius: var(--radius-full); font-weight: 700; color: var(--color-ink); text-decoration: none; }
.closure-day.is-on { border-color: var(--color-primary); background: var(--color-primary-soft); color: var(--color-primary); }
.closure-day-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--color-success); }
.closure-day-other { width: auto; max-width: 11rem; }
.closure-planned ul { margin: var(--spacing-1) 0 0; padding-left: var(--spacing-5); }
.closure-histo { border: 2px dashed var(--color-line-strong); border-radius: var(--radius-lg); }
.closure-histo[open] { border-style: solid; background: var(--color-surface-raised); }
.closure-histo > summary { cursor: pointer; list-style: none; border-radius: var(--radius-lg); }
.closure-histo > summary::-webkit-details-marker { display: none; }
.closure-histo > summary:focus-visible { outline: 3px solid var(--color-primary); outline-offset: 2px; }
.closure-histo .reg-ligne { border: 0; background: transparent; box-shadow: none; }
.closure-chevron { flex: none; color: var(--color-primary); font-weight: 800; transition: transform .15s; }
.closure-histo[open] .closure-chevron { transform: rotate(180deg); }
.closure-histo-body { display: grid; gap: var(--spacing-3); padding: 0 18px 16px; }
.closure-histo-body ul { margin: var(--spacing-1) 0 0; padding-left: var(--spacing-5); }

/* ══ le sélecteur de pays (assets/js/pays.js, Pays::selecteur()) ══
 *
 * Sans script, c'est un <select> natif et `.field-input` suffit. Avec lui, le
 * <select> est remplacé par un champ de saisie qui filtre une liste : le champ
 * garde l'allure d'un champ (même hauteur, même bordure), un chevron remplace
 * la flèche du menu natif, et la liste s'ouvre sous lui, dans son cadre, avec
 * ses propres barres de défilement.
 *
 * La liste a la hauteur de ce que l'écran laisse : 20 rem au plus, la moitié de
 * l'écran sur un téléphone dont le clavier est ouvert (`dvh` suit le clavier,
 * `vh` en repli). Chaque ligne fait 48 px au moins : on la tape au pouce. */
.pays { position: relative; }
.pays-boite { position: relative; scroll-margin-top: 88px; }
.pays-saisie { padding-right: 52px; text-overflow: ellipsis; }
.pays-bascule {
	position: absolute; top: 0; right: 0; bottom: 0;
	width: 52px; padding: 0; border: 0; background: transparent; cursor: pointer;
	color: var(--color-ink-muted);
	display: flex; align-items: center; justify-content: center;
	border-radius: 0 var(--radius-md) var(--radius-md) 0;
}
.pays-bascule::before {
	content: ""; width: 9px; height: 9px;
	border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
	transform: translateY(-3px) rotate(45deg); transition: transform .15s;
}
.pays.is-ouvert .pays-bascule::before { transform: translateY(2px) rotate(-135deg); }
.pays-liste {
	position: absolute; z-index: 30; left: 0; right: 0; top: calc(100% + var(--spacing-1));
	max-height: 20rem; max-height: min(20rem, 50vh); max-height: min(20rem, 50dvh);
	overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch;
	background: var(--color-surface-raised);
	border: 2px solid var(--color-line-strong);
	border-radius: var(--radius-md);
	box-shadow: 0 6px 0 var(--color-line);
	padding: var(--spacing-1) 0;
}
.pays-liste[hidden] { display: none; }
.pays-groupe {
	padding: var(--spacing-2) var(--spacing-3) var(--spacing-1);
	font-size: var(--text-body-sm); font-weight: 800; letter-spacing: .04em; text-transform: uppercase;
	color: var(--color-ink-muted);
}
.pays-option {
	display: flex; align-items: baseline; flex-wrap: wrap; column-gap: var(--spacing-2);
	min-height: 48px; padding: var(--spacing-3);
	box-sizing: border-box; align-content: center;
	font-size: var(--text-body-md); color: var(--color-ink); cursor: pointer;
}
.pays-option.is-actif { background: var(--color-primary-soft); }
.pays-option[aria-selected="true"] { font-weight: 800; color: var(--color-primary-active); }
.pays-option[aria-selected="true"]::after { content: "✓"; margin-left: auto; color: var(--color-primary); }
.pays-alias { font-size: var(--text-body-sm); color: var(--color-ink-muted); }
.pays-vide { padding: var(--spacing-4) var(--spacing-3); font-size: var(--text-body-md); color: var(--color-ink-muted); }

/* ── Catalogue : présentation en sections (sélecteur, titres, pastilles) ── */
.cat-vue { display: flex; align-items: center; gap: var(--spacing-2); }
.cat-vue[hidden] { display: none; }
.cat-vue label { font: 700 14px Nunito, sans-serif; color: var(--color-ink-muted); }
.cat-vue select { font: 700 14px Nunito, sans-serif; min-height: 38px; max-width: 100%; padding: 6px 12px; border-radius: var(--radius-full); border: 2px solid var(--color-line-strong); background: var(--color-surface-raised); color: var(--color-ink); cursor: pointer; }
.cat-vue select:focus-visible { outline: 3px solid var(--color-primary); outline-offset: 2px; }
.cat-sections { display: grid; gap: var(--spacing-6); }
.cat-section { min-width: 0; }
.cat-section-titre { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px var(--spacing-3); margin: 0 0 var(--spacing-3); font: 600 20px/1.2 Fredoka, sans-serif; color: var(--color-ink); }
.cat-section-nb { font: 700 13px Nunito, sans-serif; color: var(--color-ink-muted); }
.cat-note { margin-bottom: 0; }
.cat-pastille { font: 800 11px Nunito, sans-serif; letter-spacing: .04em; text-transform: uppercase; border-radius: var(--radius-full); padding: 2px 9px; }
.cat-pastille.is-neuf { background: var(--color-success-soft); color: var(--color-success-strong); }
.cat-pastille.is-pop { background: var(--color-gold); color: var(--color-ink); }
@media ( max-width: 30rem ) { .cat-vue { flex-wrap: wrap; } .cat-vue select { flex: 1 1 auto; } }

/* ═══ Paiement en ligne : l'écran Abonnement (maquette « Abonnement et stockage ») ═══ */
.pay-wrap { display: grid; gap: var(--spacing-4); padding-top: var(--spacing-6); }
.pay-wrap > .mt-8:first-child { margin-top: 0; }
.pay-wrap > * + * { margin-top: 0; }
.pay-panel { display: grid; gap: var(--spacing-3); border: 2px solid var(--color-line); }
.pay-form { margin: 0; }
.pay-code > summary { list-style: none; cursor: pointer; width: fit-content; }
.pay-code > summary::-webkit-details-marker { display: none; }
.pay-code > summary::marker { content: ""; }
.pay-code > summary:hover { color: var(--color-ink); }
/* Un champ et son bouton sur une même ligne : même hauteur, même bord haut (le bouton ne dépasse que de son ombre). */
.pay-inline { display: flex; align-items: flex-start; gap: var(--spacing-3); }
.pay-inline .field { flex: 1 1 auto; min-width: 0; }
.pay-inline .field-input { min-height: 44px; }
.pay-inline .btn { flex: none; min-height: 44px; padding-top: 0; padding-bottom: 0; }
.pay-aside { margin-left: auto; }
.pay-plan { display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr); gap: var(--spacing-5); align-items: center; }
.pay-cta { display: grid; gap: var(--spacing-3); justify-items: start; }
.pay-price { font: 700 44px/1 Fredoka, sans-serif; }
.pay-price small { font: 600 15px Nunito, sans-serif; color: var(--color-ink-muted); }
.pay-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--spacing-1); }
.pay-list li { position: relative; padding-left: 1.5em; }
.pay-list li::before { content: "✓"; position: absolute; left: 0; color: var(--color-success-strong); font-weight: 800; }
.pay-banner { --c: var(--color-gold-strong); --bg: var(--color-brand-paper);
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: var(--spacing-1) var(--spacing-4); align-items: center;
  border: 2px solid var(--c, var(--color-gold-strong)); border-radius: var(--radius-lg); background: var(--bg, var(--color-brand-paper)); padding: var(--spacing-3) var(--spacing-4); }
.pay-banner.is-bad { --c: var(--color-error-strong); --bg: var(--color-error-soft); }
.pay-banner.is-ok { --c: var(--color-success-strong); --bg: var(--color-success-soft); }
.pay-banner.is-info { --c: var(--color-primary); --bg: var(--color-primary-soft); }
.pay-banner-ic { grid-row: 1 / span 2; align-self: start; width: 36px; height: 36px; border-radius: 50%; display: grid; place-items: center;
  background: var(--c, var(--color-gold-strong)); color: var(--color-on-primary); font: 700 20px Fredoka, sans-serif; }
.pay-banner-tx { display: grid; gap: 2px; min-width: 0; }
.pay-banner-tx b { font: 600 17px Fredoka, sans-serif; color: var(--color-ink); }
.pay-banner-tx span { font-size: 14px; color: var(--color-ink-muted); }
.pay-banner .pay-form { grid-column: 3; grid-row: 1 / span 2; }
.pay-tiers { display: grid; grid-template-columns: repeat( auto-fit, minmax(210px, 1fr) ); gap: var(--spacing-3); align-items: stretch; margin-top: var(--spacing-3); }
.pay-tier { position: relative; display: grid; gap: var(--spacing-1); align-content: start; text-align: center; padding: var(--spacing-4) var(--spacing-3);
  background: var(--color-surface-raised); border: 3px solid var(--color-line-strong); border-radius: var(--radius-xl); color: var(--color-ink); text-decoration: none; }
.pay-tier.is-link:hover { border-color: var(--color-primary); }
.pay-tier.is-chosen { border-color: var(--color-primary); background: var(--color-primary-soft); }
.pay-tier.is-current { border-color: var(--color-success-strong); }
.pay-go { font: 700 32px/1 Fredoka, sans-serif; }
.pay-pr { font: 700 22px Fredoka, sans-serif; }
.pay-pr small { font: 600 13px Nunito, sans-serif; color: var(--color-ink-muted); }
.pay-pr s { font-weight: 600; color: var(--color-ink-muted); }
.pay-first { display: block; justify-self: center; font: 700 12px Fredoka, sans-serif; background: var(--color-gold); color: var(--color-ink); border-radius: var(--radius-full); padding: 1px 10px; margin-bottom: var(--spacing-1); }
.pay-sub b { color: var(--color-ink); }
.pay-badge { position: absolute; top: -12px; left: 50%; transform: translateX(-50%); background: var(--color-gold); color: var(--color-ink); font: 700 12px Fredoka, sans-serif; padding: 1px 12px; border-radius: var(--radius-full); white-space: nowrap; }
.pay-badge.is-current { background: var(--color-success-strong); color: var(--color-on-success); }
.pay-due { font: 700 22px Fredoka, sans-serif; }
.pay-order { border-color: var(--color-primary); margin-top: var(--spacing-3); }
.pay-gauge { height: 14px; border-radius: var(--radius-full); background: var(--color-surface-sunken); overflow: hidden; border: 2px solid var(--color-line-strong); }
.pay-gauge i { display: block; height: 100%; background: var(--color-primary); }
@media (max-width: 720px) { .pay-plan { grid-template-columns: 1fr; } .pay-aside { margin-left: 0; } }
@media (max-width: 640px) { .pay-banner { grid-template-columns: auto minmax(0, 1fr); } .pay-banner .pay-form { grid-column: 1 / -1; grid-row: auto; } .pay-banner .pay-form .btn { width: 100%; } }

/* La suite du cours, sur l'écran de fin de l'ouverture : le plan de travail est une fonction d'ordinateur. */
body.projection [data-vd-phone-only] { display: none; }
@media (max-width: 767px) and (pointer: coarse) {
	body.projection [data-vd-desktop-only] { display: none; }
	body.projection [data-vd-phone-only] { display: inline-flex; }
}

/* ── Refonte de la page Abonnement  ── */
.ab-wrap { display: grid; gap: var(--spacing-8); padding-bottom: var(--spacing-10); }
.ab-hero { position: relative; overflow: hidden; border-radius: var(--radius-2xl); border: 2px solid var(--color-line-strong);
  background: radial-gradient(circle at 88% 18%, #ffd89a 0, transparent 38%), linear-gradient(135deg, var(--color-brand-paper), #fff4e1 60%, #ffe6c4);
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--spacing-6); align-items: center; padding: var(--spacing-8); }
.ab-hero-tx { display: grid; gap: var(--spacing-3); max-width: 40rem; min-width: 0; }
.ab-hero-tx > * { margin: 0; }
.ab-hero h1 { font-size: clamp(30px, 4.4vw, 44px); line-height: 1.1; }
.ab-mark { background: linear-gradient(transparent 62%, var(--color-gold) 62% 92%, transparent 92%); padding: 0 .1em; }
.ab-status { justify-self: start; }
.ab-art { width: clamp(150px, 22vw, 240px); height: auto; }
.ab-trust { display: flex; flex-wrap: wrap; gap: var(--spacing-2) var(--spacing-3); list-style: none; margin: 0; padding: 0; }
.ab-trust li { display: inline-flex; align-items: center; gap: var(--spacing-2); background: #fff; border: 2px solid var(--color-line); border-radius: var(--radius-full); padding: var(--spacing-1-5) var(--spacing-3) var(--spacing-1-5) var(--spacing-2); font-size: 14px; font-weight: 600; }
.ab-trust svg { width: 24px; height: 24px; flex: none; }
.ab-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(300px, 380px); gap: var(--spacing-8); align-items: start; }
.ab-main { display: grid; gap: var(--spacing-10); min-width: 0; }
.ab-sec > h2 { margin: 0 0 var(--spacing-4); font-size: 26px; }
.ab-ico { width: 48px; height: 48px; flex: none; }
.ab-buy { position: static; padding: 0; overflow: hidden; border: 2px solid var(--color-brand-band); box-shadow: 0 8px 0 var(--color-brand-paper); }
.ab-buy-head { display: flex; align-items: center; justify-content: space-between; gap: var(--spacing-3); flex-wrap: wrap; padding: var(--spacing-3) var(--spacing-6); background: linear-gradient(135deg, var(--color-brand-sheet), var(--color-brand-corner)); color: #fff; }
.ab-buy-head h2 { margin: 0; font: 600 19px Fredoka, sans-serif; color: var(--color-ink); }
.ab-buy-head .pill { background: #fff; color: var(--color-ink); }
.ab-buy-body { display: grid; gap: var(--spacing-4); padding: var(--spacing-6); }
@media (min-width: 861px) and (min-height: 760px) { .ab-buy { position: sticky; top: calc(var(--chrome-h, 84px) + var(--spacing-4)); } }
.ab-buy .pay-price { margin: 0; font-size: 52px; color: var(--color-ink); }
/* Avec une remise : l'ancien prix s'efface, le nouveau domine, « TVA incluse » garde sa ligne (jamais coupé en deux). */
.ab-buy .pay-price.is-promo { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 var(--spacing-2); }
.ab-buy .pay-price.is-promo .pay-first { flex: 0 0 100%; margin-bottom: var(--spacing-1); justify-self: start; width: fit-content; }
.ab-buy .pay-price.is-promo s { font-size: 28px; color: var(--color-ink-muted); }
.ab-buy .pay-price.is-promo small { flex: 0 0 100%; margin-top: var(--spacing-1); white-space: nowrap; }
.ab-per { margin: 0; font-size: 14px; color: var(--color-ink-muted); }
.ab-buy .btn-lg { width: 100%; justify-content: center; text-align: center; }
.ab-keep { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--spacing-2); font-size: 14px; }
.ab-keep li { display: flex; gap: var(--spacing-2); align-items: flex-start; }
.ab-keep li::before { content: "✓"; flex: none; width: 20px; height: 20px; border-radius: 50%; display: grid; place-items: center; background: var(--color-success-soft); color: var(--color-success-strong); font-weight: 800; font-size: 12px; }
.ab-benefits { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--spacing-4); }
.ab-benefit { --tone: var(--color-primary-active); --tint: var(--color-primary-soft); display: grid; gap: var(--spacing-2); align-content: start; background: var(--tint, var(--color-primary-soft)); padding: var(--spacing-5); border-radius: var(--radius-xl); }
.ab-benefit.is-contenus { --tone: #8f4a00; --tint: var(--color-lang-es-soft); }
.ab-benefit.is-integrations { --tone: #0d6a80; --tint: var(--color-lang-en-soft); }
.ab-benefit.is-stockage { --tone: var(--color-success-strong); --tint: var(--color-success-soft); }
.ab-benefit .ab-badge { width: 68px; height: 68px; border-radius: var(--radius-lg); background: #fff; display: grid; place-items: center; box-shadow: 0 3px 0 rgba(59, 42, 36, .12); }
.ab-benefit .ab-badge svg { width: 46px; height: 46px; }
.ab-benefit .t-eyebrow { color: var(--tone, var(--color-primary-active)); margin-top: var(--spacing-2); }
.ab-benefit h3 { margin: 0; }
.ab-benefit p { margin: 0; }
.ab-scroll { overflow-x: auto; border-radius: var(--radius-xl); }
.ab-compare { width: 100%; border-collapse: separate; border-spacing: 0; background: var(--color-surface-raised); border: 2px solid var(--color-line); border-radius: var(--radius-xl); overflow: hidden; }
.ab-compare th, .ab-compare td { padding: var(--spacing-3) var(--spacing-4); text-align: left; border-bottom: 2px solid var(--color-line); vertical-align: middle; }
.ab-compare thead th { font: 600 16px Fredoka, sans-serif; background: var(--color-surface-sunken); }
.ab-compare thead th.is-pro { background: var(--color-primary); color: #fff; }
.ab-compare tbody th { font-weight: 600; width: 44%; }
.ab-compare td { width: 28%; }
.ab-compare td.is-pro { background: var(--color-primary-soft); font-weight: 600; color: var(--color-primary-active); }
.ab-compare tbody tr:last-child > * { border-bottom: 0; }
.ab-yes { display: inline-grid; place-items: center; width: 26px; height: 26px; border-radius: 50%; background: var(--color-success); color: #fff; font-weight: 800; font-size: 14px; }
.ab-no { color: var(--color-ink-faint); font-weight: 700; }
.ab-steps { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--spacing-4); counter-reset: ab; }
.ab-steps li { counter-increment: ab; position: relative; display: grid; gap: var(--spacing-2); align-content: start; background: #fff; border: 2px solid var(--color-line); border-radius: var(--radius-xl); padding: var(--spacing-5); }
.ab-steps li::before { content: counter(ab); position: absolute; top: var(--spacing-3); right: var(--spacing-3); width: 28px; height: 28px; border-radius: 50%; display: grid; place-items: center; background: var(--color-brand-paper); color: var(--color-ink); font: 700 14px Fredoka, sans-serif; }
.ab-steps .ab-ico { width: 52px; height: 52px; }
.ab-steps b { font: 600 18px Fredoka, sans-serif; }
.ab-steps span { font-size: 14px; color: var(--color-ink-muted); }
.ab-faq { display: grid; gap: var(--spacing-2); }
.ab-faq details { background: var(--color-surface-raised); border: 2px solid var(--color-line); border-radius: var(--radius-lg); padding: 0 var(--spacing-4); }
.ab-faq details[open] { border-color: var(--color-primary); }
.ab-faq summary { list-style: none; cursor: pointer; padding: var(--spacing-3) 0; font: 600 16px Fredoka, sans-serif; display: flex; align-items: center; gap: var(--spacing-3); }
.ab-faq summary::-webkit-details-marker { display: none; }
.ab-faq summary::marker { content: ""; }
.ab-faq summary::before { content: "?"; flex: none; width: 28px; height: 28px; border-radius: 50%; display: grid; place-items: center; background: var(--color-primary-soft); color: var(--color-primary-active); font: 700 15px Fredoka, sans-serif; }
.ab-faq summary::after { content: "+"; margin-left: auto; color: var(--color-primary); font-size: 24px; line-height: 1; }
.ab-faq details[open] summary::after { content: "−"; }
.ab-faq details p { margin: 0 0 var(--spacing-3); padding-left: calc(28px + var(--spacing-3)); font-size: 15px; color: var(--color-ink-muted); }
.ab-school { display: grid; grid-template-columns: 56px minmax(0, 1fr); gap: var(--spacing-3) var(--spacing-4); align-items: start; background: var(--color-lang-en-soft); border-radius: var(--radius-xl); padding: var(--spacing-5); }
.ab-school .ab-ico { width: 56px; height: 56px; }
.ab-school-tx { display: grid; gap: var(--spacing-1-5); min-width: 0; }
.ab-school-tx h3, .ab-school-tx p { margin: 0; }
.ab-school-act { grid-column: 2; display: flex; flex-wrap: wrap; align-items: center; gap: var(--spacing-3) var(--spacing-4); }
.ab-lede { margin: calc(var(--spacing-2) * -1) 0 var(--spacing-4); max-width: 46rem; }
.ab-times { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--spacing-6); }
.ab-time { position: relative; display: grid; gap: var(--spacing-2); align-content: start; justify-items: start; background: #fff; border: 2px solid var(--color-line); border-radius: var(--radius-xl); padding: var(--spacing-5); }
.ab-time h3, .ab-time p { margin: 0; }
.ab-time .ab-ico { width: 56px; height: 56px; }
.ab-time.is-pro { background: var(--color-primary-soft); border-color: var(--color-primary); box-shadow: 0 6px 0 rgba(108, 79, 216, .18); }
.ab-time:not(:last-child)::after { content: "→"; position: absolute; right: calc(var(--spacing-6) / -2 - 9px); top: 50%; transform: translateY(-50%); color: var(--color-ink-faint); font: 700 20px Fredoka, sans-serif; background: var(--color-surface); border-radius: 50%; width: 22px; text-align: center; z-index: 1; }
.ab-time .pill.is-free { background: var(--color-success-soft); color: var(--color-success-strong); }
.ab-time .pill.is-pro { background: var(--color-primary); color: #fff; }
.ab-compare th small { display: block; margin-top: 2px; font: 400 13px Nunito, sans-serif; color: var(--color-ink-muted); }
.ab-compare tr.ab-group th { background: var(--color-surface-sunken); font: 600 13px Fredoka, sans-serif; letter-spacing: .06em; text-transform: uppercase; padding-top: var(--spacing-2); padding-bottom: var(--spacing-2); width: auto; }
@media (max-width: 860px) {
  .ab-times { grid-template-columns: minmax(0, 1fr); gap: var(--spacing-5); }
  .ab-time:not(:last-child)::after { content: "↓"; right: auto; left: 50%; top: auto; bottom: calc(var(--spacing-5) / -2 - 12px); transform: translateX(-50%); }
  .ab-hero { grid-template-columns: minmax(0, 1fr); padding: var(--spacing-6); }
  .ab-art { display: none; }
  .ab-grid { grid-template-columns: minmax(0, 1fr); gap: var(--spacing-6); }
  .ab-buy { position: static; order: -1; }
  .ab-steps { grid-template-columns: minmax(0, 1fr); }
  .ab-steps li { grid-template-columns: 52px minmax(0, 1fr); column-gap: var(--spacing-4); align-items: center; padding-right: var(--spacing-12); }
  .ab-steps .ab-ico { grid-row: 1 / span 2; }
}
@media (max-width: 560px) {
  .ab-benefits { grid-template-columns: minmax(0, 1fr); }
  .ab-school { grid-template-columns: minmax(0, 1fr); }
  .ab-school-act { grid-column: 1; }
  .ab-compare th, .ab-compare td { padding: var(--spacing-2) var(--spacing-3); }
  .ab-compare tbody th { width: auto; }
  .ab-buy-head, .ab-buy-body { padding-left: var(--spacing-4); padding-right: var(--spacing-4); }
  .ab-buy .pay-price { font-size: 44px; }
}

/* Choix de l'espace Drive à la souscription */
.ab-sizes { border: 0; margin: 0; padding: 0; display: grid; gap: var(--spacing-2); min-width: 0; }
.ab-sizes legend { padding: 0; margin-bottom: var(--spacing-2); }
.ab-chips { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--spacing-2); }
.ab-chip { position: relative; display: grid; gap: 2px; justify-items: center; align-content: center; text-align: center; cursor: pointer; min-height: 62px; padding: var(--spacing-2) var(--spacing-1); background: var(--color-surface-raised); border: 2px solid var(--color-line); border-radius: var(--radius-lg); }
.ab-chip:hover { border-color: var(--color-line-strong); }
.ab-chip input { position: absolute; opacity: 0; inset: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; }
.ab-chip:has(input:checked) { border-color: var(--color-primary); background: var(--color-primary-soft); }
.ab-chip:has(input:checked) .ab-chip-n { color: var(--color-primary-active); }
.ab-chip:has(input:focus-visible) { outline: 3px solid var(--color-primary); outline-offset: 2px; }
.ab-chip-n { font: 600 16px Fredoka, sans-serif; }
.ab-chip-p { font-size: 12px; color: var(--color-ink-muted); white-space: nowrap; }
.ab-form { display: grid; gap: var(--spacing-4); }
.ab-size-note { margin: 0; }

/* Mon abonnement (VocaDial+ actif, résilié, à régulariser) */
.me-hero { display: grid; gap: var(--spacing-2); }
.me-hero h1 { margin: 0; }
.me-hero p { margin: 0; }
.me-pill { display: inline-flex; align-items: center; gap: var(--spacing-1-5); font: 700 13px Fredoka, sans-serif; border-radius: var(--radius-full); padding: 3px 12px; background: var(--color-success-soft); color: var(--color-success-strong); }
.me-pill.is-end { background: var(--color-brand-paper); color: var(--color-gold-strong); }
.me-pill.is-bad { background: var(--color-error-soft); color: var(--color-error-strong); }
.me-pill::before { content: "●"; font-size: 10px; }
.me-card { position: static; }
@media (min-width: 861px) and (min-height: 700px) { .me-card { position: sticky; top: calc(var(--chrome-h, 84px) + var(--spacing-4)); } }
.me-when { display: grid; gap: 2px; }
.me-when small { color: var(--color-ink-muted); font-size: 14px; }
.me-when b { font: 700 28px/1.1 Fredoka, sans-serif; color: var(--color-ink); }
.me-banner { border-radius: var(--radius-lg); padding: var(--spacing-3) var(--spacing-4); font-size: 14px; }
.me-banner.is-end { background: var(--color-brand-paper); }
.me-banner.is-bad { background: var(--color-error-soft); }
.me-banner b { display: block; font: 600 16px Fredoka, sans-serif; margin-bottom: 2px; }
.me-open { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--spacing-2) var(--spacing-3); }
.me-open li { display: inline-flex; align-items: center; gap: var(--spacing-2); background: #fff; border: 2px solid var(--color-line); border-radius: var(--radius-full); padding: var(--spacing-1-5) var(--spacing-3) var(--spacing-1-5) var(--spacing-2); font-size: 14px; font-weight: 600; }
.me-open li::before { content: "✓"; width: 22px; height: 22px; border-radius: 50%; display: grid; place-items: center; background: var(--color-success); color: #fff; font-size: 12px; font-weight: 800; }
.ab-time .pill.is-in { background: var(--color-success-soft); color: var(--color-success-strong); }
.me-drive { display: grid; gap: var(--spacing-3); background: var(--color-success-soft); border-radius: var(--radius-xl); padding: var(--spacing-5); }
.me-drive-top { display: flex; align-items: center; gap: var(--spacing-4); flex-wrap: wrap; justify-content: space-between; }
.me-drive-top .t-title-module, .me-drive-top p { margin: 0; }
.me-gauge { height: 14px; border-radius: var(--radius-full); background: #fff; border: 2px solid var(--color-ink); overflow: hidden; }
.me-gauge > span { display: block; height: 100%; background: var(--color-success); }
.me-drive-info { display: flex; justify-content: space-between; gap: var(--spacing-3); flex-wrap: wrap; font-size: 14px; color: var(--color-ink-muted); }
.me-drive-tiers { display: flex; flex-wrap: wrap; gap: var(--spacing-2); }
.me-tier { border: 2px solid var(--color-line); background: #fff; border-radius: var(--radius-lg); padding: var(--spacing-1-5) var(--spacing-3); font: 600 15px Fredoka, sans-serif; }
.me-tier.is-now { border-color: var(--color-success-strong); color: var(--color-success-strong); }

/* Changer d'espace */
.st-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--spacing-3); }
.st-tier { position: relative; display: grid; gap: var(--spacing-1); align-content: start; justify-items: center; text-align: center; min-width: 0; color: inherit; text-decoration: none; background: var(--color-surface-raised); border: 2px solid var(--color-line); border-radius: var(--radius-xl); padding: var(--spacing-5) var(--spacing-3) var(--spacing-4); }
a.st-tier { cursor: pointer; }
a.st-tier:hover { border-color: var(--color-line-strong); }
a.st-tier:focus-visible { outline: 3px solid var(--color-primary); outline-offset: 2px; }
.st-tier.is-chosen { border-color: var(--color-primary); background: var(--color-primary-soft); box-shadow: 0 6px 0 color-mix( in srgb, var(--color-primary) 18%, transparent ); }
.st-tier.is-now { border-color: var(--color-success-strong); }
.st-tier.is-small { opacity: .55; }
.st-tier .pay-badge { position: absolute; top: -12px; left: 50%; transform: translateX(-50%); white-space: nowrap; }
.st-go { font: 700 34px/1 Fredoka, sans-serif; color: var(--color-ink); }
.st-name { font: 600 14px Fredoka, sans-serif; color: var(--color-ink-muted); }
.st-price { margin-top: var(--spacing-2); display: grid; gap: 2px; justify-items: center; }
.st-price s { color: var(--color-ink-muted); font-size: 14px; }
.st-price b { font: 700 20px Fredoka, sans-serif; }
.st-price small { font-size: 13px; color: var(--color-ink-muted); }
.st-cl { font: 600 13px Nunito, sans-serif; color: var(--color-primary-active); }
.st-note { font-size: 13px; color: var(--color-ink-muted); margin-top: var(--spacing-1); }
.st-now { margin-top: var(--spacing-1); font: 600 13px Fredoka, sans-serif; color: var(--color-success-strong); }
.st-suggest { margin: var(--spacing-3) 0 0; font-size: 14px; color: var(--color-ink-muted); }
.me-drive-flat { background: var(--color-surface-raised); border: 2px solid var(--color-line); }
.st-sum { display: grid; gap: var(--spacing-3); margin: 0; }
.st-sum > div { display: flex; justify-content: space-between; gap: var(--spacing-3); align-items: baseline; border-bottom: 2px solid var(--color-line); padding-bottom: var(--spacing-2); }
.st-sum > div:last-child { border-bottom: 0; padding-bottom: 0; }
.st-sum dt { color: var(--color-ink-muted); font-size: 14px; }
.st-sum dd { margin: 0; font-weight: 700; text-align: right; }
.st-sum dd small { display: block; font-weight: 400; color: var(--color-ink-muted); }
.st-sum .big dd { font: 700 24px Fredoka, sans-serif; }
@media (max-width: 860px) { .st-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); row-gap: var(--spacing-5); } }

/* ═══ Mes classes, version du matin ══════════════════════════════════════
 * Le langage de VocaDial Start : une ombre dure colorée, une pastille d'icône
 * inclinée, un bloc = une couleur. Aucune couleur en dur : tout vient des
 * jetons. Pas de color-mix() — les dégradés partent des pastels du thème. */
.hero-m { position: relative; display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 19rem); gap: var(--spacing-4) var(--spacing-8); align-items: center;
	background: linear-gradient(135deg, var(--color-primary-soft) 0%, var(--color-surface-raised) 62%);
	border: 2.5px solid var(--color-ink); border-radius: var(--radius-2xl); box-shadow: 0 7px 0 var(--color-primary); padding: var(--spacing-6) var(--spacing-8); }
.hero-m-txt { display: flex; flex-direction: column; align-items: flex-start; gap: var(--spacing-1); min-width: 0; }
.hero-m-eb { font: 500 14px Fredoka; letter-spacing: .04em; color: var(--color-ink-muted); }
.hero-m-titre { font-family: Fredoka; font-weight: 700; letter-spacing: -.02em; line-height: 1.08; font-size: clamp(28px, 4.6vw, 42px); text-wrap: balance; }
.hero-m-sum { margin-top: var(--spacing-1); color: var(--color-ink-muted); font-size: 16px; }
.hero-m .today-ok { margin-top: var(--spacing-2); }
.hero-art { width: 100%; height: auto; max-height: 9.5rem; stroke: var(--color-ink); stroke-width: 3; stroke-linejoin: round; stroke-linecap: round; justify-self: end; }
.hero-art .m { fill: var(--color-lang-es); } .hero-art .n { fill: var(--color-lang-en); } .hero-art .f { fill: var(--color-lang-fr); } .hero-art .t { fill: var(--color-success); }
.hero-art .i { fill: var(--color-ink); stroke: none; } .hero-art .l { stroke: var(--color-surface-raised); } .hero-art .w { fill: none; stroke: var(--color-primary); stroke-width: 5; }

.blk { --bc: var(--color-primary); --bp: var(--color-primary-soft); background: var(--color-surface-raised); border: 2.5px solid var(--color-ink); border-radius: 28px; box-shadow: 0 6px 0 var(--bc); min-width: 0; }
.blk-h { display: flex; flex-wrap: wrap; align-items: center; gap: var(--spacing-2) var(--spacing-3); padding: var(--spacing-4) var(--spacing-5) var(--spacing-2); border-radius: 25px 25px 0 0;
	background: linear-gradient(180deg, var(--bp), var(--color-surface-raised)); }
.blk-ico { display: grid; place-items: center; width: 46px; height: 46px; border-radius: 15px; border: 2.5px solid var(--color-ink); background: var(--bp); transform: rotate(-4deg); flex: none; font-size: 22px; }
.blk-h h2 { font: 600 23px/1.1 Fredoka; flex: 1 1 8rem; min-width: 0; }
.blk-b { padding: var(--spacing-2) var(--spacing-5) var(--spacing-5); }
/* Quatre cartes par rangée : une carte dit la classe, la durée et la dernière projection, jamais le contenu du rituel. */
.blk .class-cards { margin-top: var(--spacing-2); grid-template-columns: repeat( 4, minmax( 0, 1fr ) ); }
@media (max-width: 75rem) { .blk .class-cards { grid-template-columns: repeat( 3, minmax( 0, 1fr ) ); } }
@media (max-width: 56rem) { .blk .class-cards { grid-template-columns: repeat( 2, minmax( 0, 1fr ) ); } }
@media (max-width: 35rem) { .blk .class-cards { grid-template-columns: 1fr; } }
/* Une carte de classe ne rogne plus son menu « ⋯ » : le bandeau arrondit lui-même ses coins. */
.blk .class-card { overflow: visible; }
.blk .class-card-band { border-radius: 17px 17px 0 0; }
.class-card-actions .reg-menu > summary { height: 38px; border-radius: var(--radius-md); }

.b-green { --bc: var(--color-success); --bp: var(--color-success-soft); }
.b-violet { --bc: var(--color-primary); --bp: var(--color-primary-soft); }
.b-blue { --bc: var(--color-lang-en); --bp: var(--color-lang-en-soft); }
.b-pink { --bc: var(--color-lang-fr); --bp: var(--color-lang-fr-soft); }
.b-orange { --bc: var(--color-lang-es); --bp: var(--color-lang-es-soft); }
.minis { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 21rem), 1fr)); gap: var(--spacing-6); margin-top: var(--spacing-4); }
.mini { position: relative; display: grid; grid-template-columns: auto minmax(0, 1fr); grid-template-rows: auto auto 1fr; gap: var(--spacing-2) var(--spacing-4); align-items: start; padding: var(--spacing-5) var(--spacing-6);
	background: linear-gradient(135deg, var(--bp) 0%, var(--color-surface-raised) 100%); box-shadow: 0 7px 0 var(--bc); }
.mini .blk-ico { width: 60px; height: 60px; border-radius: 18px; font-size: 30px; grid-row: 1 / span 3; background: var(--color-surface-raised); }
.mini-top { display: contents; }
/* Le titre occupe toujours la hauteur de la pastille : une ligne ou deux, le texte part du même point d'une tuile à l'autre. */
.mini h3 { grid-column: 2; grid-row: 1; display: flex; align-items: flex-end; align-self: end; min-height: 0; margin: 0; font: 600 21px/1.15 Fredoka; padding-right: var(--spacing-6); }
.mini p { grid-column: 2; grid-row: 2; margin: 0; font-size: 15px; color: var(--color-ink-muted); }
.mini .btn { grid-column: 2; grid-row: 3; align-self: end; justify-self: start; margin-top: var(--spacing-2); background: var(--bc); color: var(--color-ink); border-color: var(--color-ink); box-shadow: 0 3px 0 var(--color-ink); }
.b-violet .btn, .b-pink .btn { color: var(--color-on-primary); }
.mini-x-form { display: contents; }
.mini-x { position: absolute; top: 10px; right: 12px; width: 32px; height: 32px; border-radius: var(--radius-full); color: var(--color-ink-muted); font-size: 20px; line-height: 1; cursor: pointer; }
.mini-x:hover { background: var(--color-surface-raised); }
.mini-x:focus-visible { outline: 3px solid var(--color-primary); outline-offset: 2px; }
@media (max-width: 40rem) {
	.hero-m { grid-template-columns: 1fr; padding: var(--spacing-5) var(--spacing-4); }
	.hero-art { max-height: 6.5rem; justify-self: center; }
	.blk-h { padding: var(--spacing-4) var(--spacing-4) var(--spacing-2); }
	.blk-b { padding: var(--spacing-2) var(--spacing-4) var(--spacing-4); }
	.mini { padding: var(--spacing-4); }
	.mini .blk-ico { width: 50px; height: 50px; font-size: 25px; }
}

/* ═══ Réglages : le bandeau de l'abonnement et le sommaire ════════
 * Le bandeau reprend celui de la page de l'abonnement (`.ab-hero`), avec les
 * quatre avantages en tuiles. Le sommaire du haut est la sous-navigation du
 * `.page-band` : des ancres, qui soulignent la section en vue. */
.sec[id] { scroll-margin-top: calc( var(--chrome-h, 64px) + var(--spacing-4) ); }
.abo-hero { display: block; margin-top: var(--spacing-4); padding: var(--spacing-6); }
.abo-hero h2 { margin: 0; font-size: clamp(26px, 4vw, 34px); line-height: 1.1; }
.abo-hero .ab-hero-tx { max-width: none; gap: var(--spacing-3); }
.abo-avs { list-style: none; margin: var(--spacing-1) 0 0; padding: 0; display: grid; grid-template-columns: repeat( 2, minmax( 0, 1fr ) ); gap: var(--spacing-3); }
.abo-av { --tint: var(--color-primary-soft); --tone: var(--color-primary-active); display: flex; align-items: center; gap: var(--spacing-3); min-width: 0;
	background: var(--tint); border-radius: var(--radius-lg); padding: var(--spacing-3) var(--spacing-4); }
.abo-av.is-contenus { --tint: var(--color-lang-es-soft); --tone: #8f4a00; }
.abo-av.is-integrations { --tint: var(--color-lang-en-soft); --tone: #0d6a80; }
.abo-av.is-stockage { --tint: var(--color-success-soft); --tone: var(--color-success-strong); }
.abo-av .ab-badge { flex: none; width: 44px; height: 44px; border-radius: var(--radius-md); background: #fff; display: grid; place-items: center; font-size: 22px; box-shadow: 0 2px 0 rgba( 59, 42, 36, .12 ); }
.abo-avt { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.abo-avt b { font: 600 16px/1.25 Fredoka, sans-serif; color: var(--color-ink); }
.abo-avt span { font-size: 13px; line-height: 1.4; font-weight: 600; color: var(--color-ink-muted); }
.abo-ok { flex: none; font-weight: 800; color: var(--tone); }
.abo-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--spacing-3); }
.abo-discret { font-size: 14px; font-weight: 700; color: var(--color-ink-muted); }
.abo-note { margin: 0; font-size: 13px; line-height: 1.45; font-weight: 600; color: var(--color-ink-muted); }
@media (max-width: 40rem) {
	.abo-avs { grid-template-columns: 1fr; }
	.abo-hero { padding: var(--spacing-4); }
	.abo-actions .btn { flex: 1 1 100%; }
}
/* Le cadre du focus sur une fenêtre (`dialog.avm`) doublait son trait : il n'a pas à s'afficher. */
dialog.avm:focus, dialog.avm:focus-visible { outline: none; }
/* Le fil d'Ariane dans le bandeau : au-dessus du titre, sans marge de plus. */
.page-head > .class-crumb { margin: 0 0 var(--spacing-1); }


/* ═══ Réglages d'un rituel déjà composé ══════════════════════════════════
 * Une page, non plus des étapes. La séance est une carte fixe à gauche, le catalogue s'étale à droite
 * en grille et c'est la page qui défile : le catalogue n'a pas de cadre qui défile à part, et ajouter
 * un module ne fait rien parcourir. Chaque module porte sa pastille de famille et un bouton « Ajouter »
 * écrit ; les quatre moments de la séance ont chacun leur couleur. Sur téléphone, deux onglets. */
.compose-wizard.is-page .rg-sec { margin-top: var(--spacing-8); }
.rg-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--spacing-3); flex-wrap: wrap; }
.rg-cols { display: grid; grid-template-columns: minmax( 0, 1fr ); gap: var(--spacing-5); align-items: start; }
@media ( min-width: 900px ) { .rg-cols { grid-template-columns: minmax( 18rem, 22rem ) minmax( 0, 1fr ); } }
/* L'en-tête de l'application (`.chrome`) est collant : tout ce qui se colle ici se colle SOUS lui. `--chrome-h` en donne la hauteur (compose.js la mesure) ; 84 px à défaut. */
.rg-tabs { display: none; gap: 4px; background: var(--color-surface-sunken); border-radius: var(--radius-full); padding: 4px; position: sticky; top: calc( var(--chrome-h, 84px) + var(--spacing-1) ); z-index: 6; margin-top: var(--spacing-3); }
.rg-tabs button { flex: 1; font: inherit; font-weight: 700; border: 0; background: transparent; border-radius: var(--radius-full); padding: 9px 10px; color: var(--color-ink-muted); cursor: pointer; font-variant-numeric: tabular-nums; }
.rg-tabs button[aria-selected="true"] { background: var(--color-surface-raised); color: var(--color-ink); box-shadow: 0 2px 0 var(--color-line-strong); }
.rg-tabs button:focus-visible { outline: 3px solid var(--color-primary); outline-offset: 2px; }

/* Le bandeau d'un compte dont l'essai ou l'abonnement est fini. */
.rg-trial { display: flex; align-items: center; gap: var(--spacing-3); flex-wrap: wrap; background: var(--color-surface-raised); border: 2px solid var(--color-gold); border-radius: 20px; padding: var(--spacing-3) var(--spacing-4); }
.rg-trial-i { font-size: 26px; }
.rg-trial .col { min-width: 12rem; }

/* La séance : une carte, le temps en grand. */
.rg-mine { background: var(--color-surface-raised); border: 2.5px solid var(--color-ink); border-radius: var(--radius-xl); box-shadow: 0 5px 0 var(--color-ink); overflow: hidden; display: flex; flex-direction: column; min-width: 0; }
/* La carte défile d'un bloc : la liste des modules garde sa hauteur, le volet « Vos fiches » vient dessous, et le temps de la séance reste en haut. */
@media ( min-width: 900px ) { .rg-mine { position: sticky; top: calc( var(--chrome-h, 84px) + var(--spacing-3) ); max-height: calc( 100vh - var(--chrome-h, 84px) - 7rem ); overflow-y: auto; } .rg-mine > .rg-hero { position: sticky; top: 0; z-index: 2; } }
.rg-mine > :not( .rg-hero ) { margin-inline: 14px; }
.rg-mine > .rg-head { margin-top: 12px; }
.rg-mine > .rg-head h2 { font-size: 18px; }
.rg-mine > .compose-order { margin-top: var(--spacing-2); margin-bottom: 14px; flex: none; }
.rg-mine > .rg-gocat { margin-bottom: 14px; align-self: flex-start; }
@media ( min-width: 900px ) { .rg-mine > .rg-gocat { display: none; } }
.rg-hero { display: flex; align-items: baseline; flex-wrap: wrap; gap: 2px 10px; background: var(--color-brand-sheet); padding: 14px 18px 12px; flex: none; }
.rg-hero-k { font-weight: 800; font-size: 14px; color: var(--color-ink); width: 100%; }
.rg-hero b { font-family: Fredoka; font-weight: 700; font-size: 34px; line-height: 1; color: var(--color-ink); font-variant-numeric: tabular-nums; }
.rg-hero-sub { font-size: 14px; font-weight: 700; color: var(--color-ink); }
.rg-hero-sub:not( :empty )::before { content: "· "; }
.rg-bar [data-vd-gauge-sub] { color: var(--color-ink-muted); font-size: 14px; }
.rg-empty { display: flex; flex-direction: column; align-items: center; gap: 6px; text-align: center; background: var(--color-surface); border-radius: 18px; padding: var(--spacing-5) var(--spacing-4); margin-block: 12px; color: var(--color-ink-muted); font-size: 14px; }
.rg-empty[hidden] { display: none; }
.rg-empty-i { font-size: 28px; }
.rg-gone { font-size: 13px; color: var(--color-ink-muted); background: #fdf0d6; border-radius: 14px; padding: 8px 12px; line-height: 1.4; margin-bottom: 12px; }
.rg-gone b { color: #7a4f00; }
.rg-gone a { white-space: nowrap; font-weight: 700; }

/* Les lignes du rituel : la pastille, le nom et sa durée dessous, les gestes à droite. */
.compose-wizard.is-page .rg-row { display: grid; grid-template-columns: auto auto minmax( 0, 1fr ) auto; align-items: center; column-gap: 8px; background: transparent; border: 0; border-bottom: 2px dashed var(--color-line); border-radius: 0; padding: 9px 2px; margin: 0; }
.compose-wizard.is-page .rg-row:last-child { border-bottom: 0; }
.compose-wizard.is-page .rg-row.is-pinned { border-bottom-color: var(--color-gold); }
.compose-wizard.is-page .rg-row.is-dragging { background: var(--color-surface-raised); border: 2px solid var(--color-primary); border-radius: var(--radius-md); }
.rg-rname { display: flex; flex-direction: column; min-width: 0; line-height: 1.25; }
.rg-rname .compose-row-name { font-size: 15px; }
.rg-rname .compose-time { font-size: 12px; }
/* Un module de VocaDial+ que le rituel contenait : gris, à sa place, avec le nom de ce qui le rendra. */
.compose-wizard.is-page .rg-row.is-ghost { opacity: .75; }
.rg-row.is-ghost .compose-row-name { color: var(--color-ink-muted); }
.rg-row.is-ghost .compose-time { color: #7a4f00; font-weight: 700; font-style: italic; }
.rg-row.is-ghost .rg-badge .mod-icon { filter: grayscale( 1 ); }
.rg-row.is-ghost .compose-grip { visibility: hidden; }
.rg-row.is-ghost .rg-acts { opacity: 1; }
.rg-badge { flex: none; display: block; }
.rg-badge .mod-icon { width: 36px; height: 36px; border-radius: 12px; }
.rg-badge .mod-icon svg { width: 20px; height: 20px; }
.rg-acts { display: flex; align-items: center; gap: 2px; opacity: .4; transition: opacity .15s; }
.rg-row:hover .rg-acts, .rg-row:focus-within .rg-acts, .rg-row.is-pinned .rg-acts { opacity: 1; }
.compose-wizard.is-page .rg-row .compose-pin { width: 30px; height: 30px; display: grid; place-items: center; }
.compose-wizard.is-page .rg-row .compose-moves { gap: 2px; }
.compose-wizard.is-page .rg-row .compose-move { width: 30px; height: 30px; border-color: transparent; background: transparent; font-size: 14px; }
.compose-wizard.is-page .rg-row .compose-move:hover:not( :disabled ) { background: var(--color-surface-sunken); }
@media ( prefers-reduced-motion: no-preference ) { .rg-row.is-new { animation: rg-pop 1.2s ease-out; } }
@keyframes rg-pop { 0% { background: var(--color-gold); } 60% { background: #fff4d6; } 100% { background: transparent; } }

/* Le catalogue : un fond sable, une barre de recherche qui reste en haut, une grille. */
.rg-cat { background: var(--color-surface-sunken); border-radius: 26px; padding: var(--spacing-4); min-width: 0; }
.rg-cat-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 10px; padding: 0 0 var(--spacing-2); }
.rg-cat-head b { font-family: Fredoka; font-size: 24px; }
.rg-cat-head .rg-count { font-size: 14px; color: var(--color-ink-muted); }
.rg-cat-sub { flex: 1 0 100%; font-size: 14px; color: var(--color-ink-muted); font-weight: 600; }
.rg-cat-bar { position: sticky; top: var(--chrome-h, 84px); z-index: 4; background: var(--color-surface-sunken); padding: 0 0 var(--spacing-2); }
.rg-search { font: inherit; font-weight: 600; font-size: 15px; width: 100%; padding: 11px 18px; border: 2px solid var(--color-line-strong); border-radius: var(--radius-full); background: var(--color-surface-raised); color: var(--color-ink); }
.rg-search:focus-visible { outline: 3px solid var(--color-primary); outline-offset: 1px; border-color: var(--color-primary); }
.rg-chips { display: flex; gap: 6px; flex-wrap: wrap; margin: var(--spacing-2) 0 0; }
.rg-chips button { font: inherit; font-size: 14px; font-weight: 700; border: 2px solid var(--color-line-strong); background: var(--color-surface-raised); color: var(--color-ink-muted); border-radius: var(--radius-full); padding: 6px 14px; cursor: pointer; display: inline-flex; align-items: center; gap: 7px; }
.rg-chips button[aria-pressed="true"] { background: var(--color-primary); border-color: var(--color-primary); color: var(--color-on-primary); }
.rg-chips button:focus-visible { outline: 3px solid var(--color-primary); outline-offset: 2px; }
.rg-chips button[data-m]::before, .rg-mh::before { content: ""; border-radius: 50%; background: var(--mc); flex: none; }
.rg-chips button[data-m]::before { width: 10px; height: 10px; }
.rg-chips button[aria-pressed="true"][data-m]::before { background: #fff; box-shadow: 0 0 0 2px var(--mc); }
[data-m="start"] { --mc: var(--color-gold); }
[data-m="warm"] { --mc: var(--color-brand-sheet); }
[data-m="learn"] { --mc: var(--color-primary); }
[data-m="review"] { --mc: var(--color-family-expresion); }
.rg-warn-d { margin: 0 0 var(--spacing-2); font-size: 13px; }
.rg-warn-d summary { cursor: pointer; color: var(--color-primary-active); background: var(--color-primary-soft); font-weight: 700; padding: 6px 14px; border-radius: var(--radius-full); display: inline-block; }
.rg-warn-d summary:focus-visible { outline: 3px solid var(--color-primary); outline-offset: 2px; }
.rg-warn-d[open] { background: var(--color-surface-raised); border-left: 4px solid var(--color-primary); border-radius: var(--radius-md); padding: 6px 8px; }
.rg-warn-d p { margin: 6px 0 0; color: var(--color-ink); }
.rg-items { display: grid; grid-template-columns: repeat( auto-fill, minmax( 16rem, 1fr ) ); gap: var(--spacing-2); margin-top: var(--spacing-3); }
.rg-items [hidden] { display: none; }
.rg-mh { grid-column: 1 / -1; display: flex; align-items: center; gap: 10px; margin-top: var(--spacing-2); }
.rg-mh::before { width: 14px; height: 14px; }
.rg-mh h3 { margin: 0; font-family: Fredoka; font-size: 19px; font-weight: 600; color: var(--color-ink); }
.rg-mh-n { font-size: 12px; font-weight: 700; color: var(--color-ink-muted); background: var(--color-surface-raised); border-radius: var(--radius-full); padding: 1px 9px; }
.rg-item { position: relative; background: var(--color-surface-raised); border: 2px solid var(--color-line); border-radius: 20px; padding: 14px; display: grid; grid-template-columns: auto minmax( 0, 1fr ); grid-template-areas: "b t" "b p"; column-gap: 12px; row-gap: 8px; cursor: pointer; transition: transform .12s, box-shadow .12s, border-color .12s; }
.rg-item > input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.rg-item .rg-badge { grid-area: b; align-self: start; }
.rg-item .rg-badge .mod-icon { width: 42px; height: 42px; border-radius: 14px; }
.rg-item .rg-badge .mod-icon svg { width: 24px; height: 24px; }
.rg-item .rg-txt { grid-area: t; min-width: 0; display: flex; flex-direction: column; }
.rg-l1 { display: flex; flex-direction: column; }
.rg-item .t-title-module { font-size: 17px; }
.rg-item .compose-time { font-size: 12px; }
.rg-d { font-size: 13.5px; color: var(--color-ink-muted); line-height: 1.35; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.rg-item .compose-beta-note { display: none; margin-top: 4px; }
.rg-item:has( > input:checked ) .compose-beta-note { display: block; }
.rg-item:hover { transform: translateY( -2px ); box-shadow: 0 5px 0 var(--color-line-strong); }
.rg-item:has( > input:checked ) { border-color: var(--color-success); }
.rg-item:has( > input:focus-visible ) { outline: 3px solid var(--color-primary); outline-offset: 3px; }
.rg-item.is-locked { border-style: dashed; background: var(--color-surface); }
.rg-item.is-locked:hover { border-color: var(--color-gold); }
.rg-plus { grid-area: p; justify-self: end; height: 36px; border-radius: var(--radius-full); padding: 0 16px 0 12px; display: inline-flex; align-items: center; gap: 7px; font-weight: 700; font-size: 14px; background: var(--color-primary); color: var(--color-on-primary); border: 2px solid var(--color-primary); box-shadow: 0 3px 0 var(--color-primary-active); }
.rg-plus-i { font-size: 18px; line-height: 1; }
.rg-plus-i::before { content: "+"; }
.rg-t-in, .rg-t-lock { display: none; }
.rg-item:hover .rg-plus { background: var(--color-primary-hover); }
.rg-item > input:checked ~ .rg-plus { background: var(--color-success-soft); border-color: var(--color-success); color: var(--color-success-strong); box-shadow: none; }
.rg-item > input:checked ~ .rg-plus .rg-plus-i::before { content: "✓"; }
.rg-item > input:checked ~ .rg-plus .rg-t-add, .rg-item.is-locked .rg-t-add { display: none; }
.rg-item > input:checked ~ .rg-plus .rg-t-in { display: inline; }
.rg-item.is-locked .rg-plus { background: #fdf0d6; border-color: var(--color-gold); color: #7a4f00; box-shadow: none; }
.rg-item.is-locked .rg-plus-i::before { content: "🔒"; font-size: 14px; }
.rg-item.is-locked .rg-t-lock { display: inline; }
@media ( prefers-reduced-motion: no-preference ) { .rg-item > input:checked ~ .rg-plus { animation: rg-bump .35s ease-out; } }
@keyframes rg-bump { 0% { transform: scale( .9 ); } 60% { transform: scale( 1.08 ); } 100% { transform: none; } }
.rg-none { grid-column: 1 / -1; padding: var(--spacing-4); text-align: center; color: var(--color-ink-muted); font-size: 14px; }
.rg-idea { margin-top: var(--spacing-4); background: var(--color-surface-raised); border-radius: 20px; }

/* Le tirage : une phrase, et trois séances possibles. */
.rg-box { background: var(--color-surface-raised); border: 2px solid var(--color-line); border-radius: var(--radius-lg); padding: var(--spacing-4); }
.rg-lab { display: block; font-weight: 700; margin-bottom: var(--spacing-2); }
.rg-select, .rg-num { font: inherit; font-weight: 700; padding: 10px 14px; border: 2px solid var(--color-ink); border-radius: var(--radius-md); background: var(--color-surface-raised); color: var(--color-ink); max-width: 100%; }
.rg-num { width: 6rem; }
.rg-select:disabled { opacity: .5; border-color: var(--color-line-strong); }
.rg-select:focus-visible, .rg-num:focus-visible { outline: 3px solid var(--color-primary); outline-offset: 2px; }
.rg-samples-h { display: flex; justify-content: space-between; align-items: baseline; gap: var(--spacing-3); margin-top: var(--spacing-4); flex-wrap: wrap; }
.rg-samples-h b { font-family: Fredoka; font-size: 16px; }
.rg-link-btn { font: inherit; font-weight: 700; font-size: 14px; color: var(--color-primary); background: none; border: 0; cursor: pointer; padding: 4px 2px; }
.rg-link-btn:hover { text-decoration: underline; }
.rg-link-btn:focus-visible { outline: 3px solid var(--color-primary); outline-offset: 2px; }
.rg-link-btn[hidden] { display: none; }
.rg-samples { display: grid; gap: var(--spacing-2); margin-top: var(--spacing-2); }
.rg-sample { display: grid; grid-template-columns: 5.5rem minmax( 0, 1fr ) auto; gap: var(--spacing-3); align-items: center; background: var(--color-surface); border-radius: 16px; padding: 10px 14px; }
.rg-sample-l { font-family: Fredoka; font-weight: 600; font-size: 14px; }
.rg-sample-t { font-size: 13px; color: var(--color-ink-muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
.rg-sample .compose-timeline { gap: 6px; margin: 0; }
.rg-sample .compose-timeline span.is-fix { background: #fff4d6; color: #6b4a00; }
.rg-hint { margin: var(--spacing-3) 0 0; font-size: 13px; color: var(--color-ink-muted); }
@media ( max-width: 640px ) { .rg-sample { grid-template-columns: 1fr; gap: 4px; } }

/* Le cours en trois temps. */
.rg-arc { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--spacing-3); }
.rg-arc > li { display: grid; grid-template-columns: auto minmax( 0, 1fr ); column-gap: var(--spacing-3); position: relative; }
.rg-arc > li:not( :last-child )::before { content: ""; position: absolute; left: 17px; top: 38px; bottom: calc( -1 * var(--spacing-3) ); width: 2px; background: var(--color-line-strong); }
.rg-dot { width: 36px; height: 36px; border-radius: 50%; background: var(--color-primary-soft); color: var(--color-primary); font-family: Fredoka; font-weight: 700; display: flex; align-items: center; justify-content: center; z-index: 1; }
.rg-arc .rg-box { padding: var(--spacing-3) var(--spacing-4); }
.rg-t { display: flex; justify-content: space-between; gap: var(--spacing-2); align-items: baseline; flex-wrap: wrap; }
.rg-t b { font-family: Fredoka; font-size: 17px; }
.rg-clo-steps { list-style: none; margin: var(--spacing-2) 0 0; padding: 0; display: grid; gap: 4px; font-size: 14px; }
.rg-clo-steps li { display: flex; justify-content: space-between; gap: var(--spacing-3); }
.rg-clo-steps li span:last-child { color: var(--color-ink-muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
.rg-clo-set { margin-top: var(--spacing-3); padding-top: var(--spacing-3); border-top: 2px solid var(--color-line); display: grid; gap: var(--spacing-3); }
.rg-clo-set [hidden] { display: none; }
.rg-plan.is-off { border-style: dashed; background: var(--color-surface); cursor: default; }
.rg-plan.is-off .t-title-module { color: var(--color-ink-muted); }
.rg-plan-cta { margin-top: 6px; font-weight: 700; font-size: 14px; }

/* La barre du bas : la durée, l'état, et l'enregistrement. Elle reprend la place de la jauge. */
.compose-gauge.rg-bar { flex-wrap: wrap; justify-content: space-between; }
.compose-wizard.is-page .compose-gauge { display: flex; }
.rg-bar .rg-sum { display: flex; flex-direction: column; line-height: 1.25; min-width: 0; flex: 1 1 12rem; }
.rg-bar .compose-gauge-text { font-family: Fredoka; font-size: 18px; font-variant-numeric: tabular-nums; }
.rg-bar .rg-dirty { font-size: 13px; color: var(--color-ink-muted); }
.rg-bar .rg-dirty.is-on { color: #7a4f00; font-weight: 700; }
.rg-bar .rg-btns { display: flex; gap: var(--spacing-2); align-items: center; margin-left: auto; }
.rg-bar .btn { padding-block: 10px; }
.compose-wizard.is-page.is-live { padding-bottom: calc( env( safe-area-inset-bottom, 0px ) + 9rem ); }

/* Téléphone : deux onglets. La séance garde sa carte ; le catalogue passe en une colonne, ses filtres
 * défilent sur une ligne et sa recherche reste sous les onglets. */
@media ( max-width: 899px ) {
	.rg-tabs { display: flex; }
	.rg-cols[data-tab="rituel"] .rg-cat { display: none; }
	.rg-cols[data-tab="cat"] .rg-mine { display: none; }
	.rg-hero { padding: 12px 16px 10px; }
	.rg-hero b { font-size: 28px; }
	.rg-mine > .compose-order { overflow: visible; }
	.rg-cat { padding: 12px; border-radius: 22px; }
	.rg-cat-head b { font-size: 21px; }
	.rg-cat-bar { top: calc( var(--chrome-h, 84px) + 56px ); padding: 8px 0 6px; }
	.rg-chips { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; margin: 8px -12px 0; padding: 0 12px 4px; }
	.rg-chips::-webkit-scrollbar { display: none; }
	.rg-chips button { flex: none; white-space: nowrap; }
	.rg-items { grid-template-columns: 1fr; }
	.rg-item { padding: 12px; }
	/* Une ligne par module : la poignée, la pastille, le nom et sa durée, puis ★ ↑ ↓ × serrés à droite. */
	.compose-wizard.is-page .rg-row { column-gap: 6px; padding: 6px 0; }
	.compose-wizard.is-page .rg-row .rg-acts { opacity: 1; gap: 0; }
	.compose-wizard.is-page .rg-row .compose-pin,
	.compose-wizard.is-page .rg-row .compose-move { width: 32px; height: 32px; }
	.compose-wizard.is-page .rg-row .compose-moves { gap: 0; }
	.rg-badge .mod-icon { width: 34px; height: 34px; }
}
@media ( max-width: 560px ) {
	.rg-bar .rg-btns { width: 100%; }
	.rg-bar .rg-btns .btn-primary { flex: 1; }
}
