/* =========================================================================
   Salle de classe FLE - Nos Réussites
   Tout est porté par .fle-app pour ne pas déborder sur le thème WordPress.
   Palette injectée par PHP dans :root (--fle-ink, --fle-primary, etc.).
   ====================================================================== */

.fle-app {
  /* Signature de la feuille. Le pied de page de l'application la lit et la
     compare à celle qu'attend le script : c'est le seul moyen sûr de savoir
     QUELLE feuille le navigateur utilise réellement. Un numéro de version
     affiché par le serveur ne prouve rien - il dit ce que PHP a envoyé, pas
     ce qu'un cache intermédiaire a servi. À incrémenter avec la palette. */
  --fle-css-rev: 35;

  /* ---------------------------------------------------------------------
     PALETTE - sarcelle et gris, et rien d'autre dans le décor

     Deux couleurs de marque, c'est peu. La tentation serait d'en ajouter
     une troisième pour faire ressortir les actions ; on s'en est passé.
     La hiérarchie vient ici de la VALEUR, pas de la teinte : sarcelle
     profonde pour la structure et le texte, sarcelle vive pour l'action,
     lavis de sarcelle pour les fonds, gris de marque pour les filets et
     ce qui dort. Trois matières, une seule voix chromatique.

     Les cinq premières variables restent réglables depuis l'administration
     (Réglages → Salle de classe FLE). Tout le reste en découle.
     ------------------------------------------------------------------ */
  --ink:     var(--fle-ink,     #22302F);   /* anthracite très légèrement sarcelle */
  --primary: var(--fle-primary, #0F5F60);   /* sarcelle profonde : structure, texte */
  --accent:  var(--fle-accent,  #1B8A8A);   /* la sarcelle de marque : l'action */
  --paper:   var(--fle-paper,   #F4F7F6);
  --line:    var(--fle-line,    #D7E0DF);
  --white:   #fff;
  --gris:    #8C8C8B;                       /* le gris de marque */

  /* ---------------------------------------------------------------------
     CONTRASTE - pourquoi les aplats ne sont pas exactement #1B8A8A

     #1B8A8A porte 4,16:1 sur blanc. C'est assez pour un aplat, un filet ou
     un grand titre - le seuil des composants d'interface est à 3:1 - mais
     pas pour un libellé blanc de 14 px, qui demande 4,5:1. Les
     remplissages qui portent du texte blanc sont donc assombris d'un cran
     (≈ 4,8:1). À l'échelle d'un bouton, l'œil n'y voit pas une autre
     couleur ; le lecteur malvoyant, si.

     Même raisonnement pour le gris : #8C8C8B plafonne à 3,37:1. Il tient
     les filets, les fonds inactifs et le décor ; le texte secondaire prend
     un gris plus dense, légèrement sarcelle, à 5,6:1.
     ------------------------------------------------------------------ */
  --accent-plein:  color-mix(in srgb, var(--accent) 90%, #06201F);
  --accent-sombre: color-mix(in srgb, var(--accent) 74%, #06201F);
  --muted:         #5C6A69;

  --lavis:      color-mix(in srgb, var(--accent)  7%, var(--white));
  --lavis-fort: color-mix(in srgb, var(--accent) 13%, var(--white));
  --lavis-gris: color-mix(in srgb, var(--gris)   10%, var(--white));

  /* ÉTATS. Ce ne sont pas des couleurs de marque mais des signaux, et ils
     n'apparaissent que dans les verdicts et les alertes - jamais dans le
     décor, jamais seuls : un glyphe les double toujours, pour qui ne
     distingue pas le vert du rouge. */
  --succes: #14705A;
  --alerte: #8A5300;
  --danger: #A32C22;
  --success: var(--succes);   /* alias hérités */
  --warn:    var(--alerte);

  /* PROFONDEUR. Trois niveaux, teintés sarcelle plutôt que noirs : une
     ombre grise sur un fond légèrement vert se voit comme une salissure. */
  --ombre-1: 0 1px 2px rgba(15,60,58,.07);
  --ombre-2: 0 1px 2px rgba(15,60,58,.05), 0 10px 24px -14px rgba(15,60,58,.28);
  --ombre-3: 0 2px 5px rgba(15,60,58,.07), 0 22px 44px -20px rgba(15,60,58,.36);
  --shadow:  var(--ombre-2);

  --radius:   12px;
  --radius-s:  9px;
  --radius-xs: 7px;

  /* TYPOGRAPHIE. Aucune police n'est téléchargée : une extension française
     qui appellerait un serveur de fontes étranger enverrait l'adresse IP de
     chaque apprenant avec elle. On se sert de ce qui est déjà sur l'appareil.
     Deux familles, deux fonctions, et la distinction est porteuse de sens :
     l'interface parle en linéale, la langue française se lit en romaine. */
  --ui:    "Inter", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --texte: "Charter", "Bitstream Charter", "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, "Times New Roman", serif;
  --data:  ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  /* ÉCHELLE FLUIDE. Le corps grandit avec la fenêtre entre le téléphone et
     l'ordinateur, puis s'arrête : au-delà, une ligne trop longue fatigue
     plus qu'un petit corps. */
  --t-corps: clamp(15px, 0.28vw + 14.1px, 16.5px);
  --t-lire:  clamp(16px, 0.42vw + 14.7px, 18px);

  font-family: var(--ui);
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: clip; /* clip, pas hidden : hidden ferait de la racine le conteneur de défilement et la barre collante ne collerait plus */
  line-height: 1.55;
  font-size: var(--t-corps);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

.fle-app *, .fle-app *::before, .fle-app *::after { box-sizing: border-box; }
.fle-app p, .fle-app h1, .fle-app h2, .fle-app h3, .fle-app h4, .fle-app ul, .fle-app ol, .fle-app figure { margin: 0; padding: 0; }
.fle-app ul, .fle-app ol { list-style: none; }
.fle-app button { font: inherit; color: inherit; cursor: pointer; }
/* La remise à plat ci-dessus protège les boutons du thème du site, mais
   elle pèse plus lourd que .fle-btn : tous les boutons pleins prenaient
   l'encre sombre sur leur aplat sarcelle ou rouge, 2:1 au lieu de 7:1.
   Le bouton reprend donc sa couleur de texte, au même poids qu'elle. */
.fle-app .fle-btn { color: var(--btn-texte); }
/* L'anneau de focus doit rester visible sur fond blanc ET sur un aplat
   sarcelle : un liseré blanc à l'intérieur, l'anneau sombre à l'extérieur.
   Il n'est jamais retiré nulle part, et le décalage de défilement évite
   que la barre collante ne recouvre l'élément qu'on vient d'atteindre. */
.fle-app :focus-visible {
  outline: 3px solid var(--accent-sombre);
  outline-offset: 2px;
  border-radius: var(--radius-xs);
  scroll-margin-top: 88px;
  scroll-margin-bottom: 24px;
}
.fle-app ::selection { background: color-mix(in srgb, var(--accent) 26%, var(--white)); color: var(--ink); }
.fle-app img, .fle-app svg { max-width: 100%; height: auto; }
.fle-noscript { padding: 24px; }

/* --- Signature : le filet Seyès, motif du cahier français ---------------- */
/* La seule audace du dessin, et elle est empruntée au sujet : le
   quadrillage du cahier français. Tout le reste de l'interface se tient
   tranquille pour que ce filet-là se remarque. */
.fle-seyes {
  height: 7px;
  background:
    repeating-linear-gradient(90deg, rgba(255,255,255,.55) 0 1px, transparent 1px 17px),
    linear-gradient(180deg, var(--accent), var(--primary));
}

/* --- Barre de séance ---------------------------------------------------- */
.fle-bar {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 10px clamp(11px, 1.8vw, 18px);
  background: var(--white);
  border-bottom: 1px solid var(--line);
  /* Collée en haut : les commandes de sortie restent atteignables même
     au milieu d'un long atelier, sans avoir à remonter la page. */
  position: sticky; top: 0; z-index: 30;
  box-shadow: 0 1px 0 var(--line), 0 8px 16px -14px rgba(15,60,58,.45);
}
.fle-bar__actions { display: inline-flex; align-items: center; gap: 8px; margin-left: 4px; }
.fle-bar__marque { font-weight: 700; letter-spacing: .01em; }
.fle-bar__marque small { display: block; font-weight: 400; font-size: 12.5px; color: var(--muted); letter-spacing: 0; text-transform: none; }
.fle-bar__espace { flex: 1 1 auto; }
.fle-app a.fle-bar__sortie, .fle-bar__sortie {
  appearance: none; background: var(--white); color: var(--primary);
  border: 1px solid var(--line); border-radius: 6px; cursor: pointer;
  padding: 4px 10px; font-size: 12.5px; font-weight: 600; font-family: inherit;
  display: inline-block; text-decoration: none; line-height: 1.5;
}
.fle-app a.fle-bar__sortie:hover { text-decoration: none; }
.fle-app a.fle-btn, .fle-app a.fle-btn:hover { text-decoration: none; display: inline-block; }
.fle-app a.fle-bar__sortie--vif, .fle-app a.fle-bar__sortie--vif:hover { color: var(--white); }
.fle-app a.fle-bar__sortie--quitter, .fle-app a.fle-bar__sortie--quitter:hover { color: var(--white); }
.fle-bar__sortie:hover { border-color: var(--primary); }
/* `hidden` doit l'emporter sur tout. Les règles de forme portées par
   `.fle-app a.fle-…` étaient plus spécifiques que `.fle-…[hidden]` : les
   commandes de sortie restaient affichées sur l'écran d'entrée, où il n'y a
   pourtant aucune salle à quitter. Une seule règle, sans appel possible. */
.fle-app [hidden] { display: none !important; }
.fle-bar__sortie[hidden] { display: none; }
.fle-bar__sortie--vif {
  background: var(--accent); color: var(--white);
  border-color: var(--accent);
}
.fle-bar__sortie--vif:hover { filter: brightness(1.08); border-color: var(--accent); }
/* Quitter la classe : la commande la plus à droite, et la plus lisible. */
.fle-bar__sortie--quitter {
  background: var(--primary); color: var(--white); border-color: var(--primary);
  font-weight: 700; padding: 6px 13px;
}
.fle-bar__sortie--quitter:hover { filter: brightness(1.1); border-color: var(--primary); }
/* Même défaut que les boutons pleins avant la 1.56 : la remise à plat
   « .fle-app button { color: inherit; font: inherit } » (0,1,1) l'emportait
   sur ces classes seules (0,1,0). « Entrer un autre code » et « Quitter la
   salle » s'écrivaient à l'encre sombre sur l'aplat, illisibles. */
.fle-app .fle-bar__sortie { color: var(--primary); font-size: 12.5px; font-weight: 600; line-height: 1.5; }
.fle-app .fle-bar__sortie--vif, .fle-app .fle-bar__sortie--quitter { color: var(--white); }
/* Le blanc sur la sarcelle de marque plafonne à 4,2:1 ; l'aplat plein,
   un ton plus sombre, passe 4,5:1 (comme .fle-btn--accent). */
.fle-app .fle-bar__sortie--vif { background: var(--accent-plein); border-color: var(--accent-plein); }
/* Au survol, l'aplat ne change plus de teinte : l'éclaircir faisait
   retomber le contraste sous 4,5:1, et le foncer ferait de même en thème
   sombre, où le texte est sombre. Le soulignement suffit à signaler. */
.fle-app .fle-bar__sortie--vif:hover { filter: none; text-decoration: underline; text-underline-offset: 2px; }
.fle-app .fle-bar__sortie--quitter { font-weight: 700; }

@media (max-width: 640px) {
  .fle-bar { gap: 9px; padding: 8px 11px; }
  .fle-bar__actions { margin-left: auto; }
  .fle-role { display: none; }
}
/* Le code de salle se dicte au téléphone et se recopie à la main : chiffres
   à chasse fixe, interlettrage large, et un cadre qui invite à le
   sélectionner d'un geste. */
.fle-code {
  font-family: var(--data); font-size: 17px; letter-spacing: .16em; font-weight: 700;
  background: var(--lavis); border: 1.5px dashed var(--accent); color: var(--primary);
  padding: 5px 12px; border-radius: var(--radius-xs);
  user-select: all; -webkit-user-select: all;
}
.fle-role { font-size: 12.5px; font-weight: 600; text-transform: none; letter-spacing: 0; color: var(--muted); }
.fle-presence { font-size: 13px; color: var(--muted); display: inline-flex; align-items: center; gap: 6px; }
.fle-pastille { width: 8px; height: 8px; border-radius: 50%; background: var(--success); display: inline-block; }
.fle-pastille--off { background: var(--danger); }
.fle-pastille--attente { background: var(--accent); }

/* --- Signature : le cachet de niveau CECRL ------------------------------ */
.fle-cachet {
  display: inline-flex; flex-direction: column; align-items: center; justify-content: center;
  min-width: 62px; padding: 5px 12px;
  border: 2.5px solid var(--accent); border-radius: 4px;
  color: var(--accent); background: color-mix(in srgb, var(--accent) 8%, var(--white));
  transform: rotate(-2.2deg);
  font-family: var(--data);
  transition: transform .18s ease;
}
.fle-cachet strong { font-size: 20px; line-height: 1; letter-spacing: .04em; }
.fle-cachet span { font-size: 9px; letter-spacing: .14em; text-transform: uppercase; opacity: .8; }
.fle-cachet--vide { border-color: var(--line); color: var(--muted); background: var(--white); }
.fle-cachet--anime { animation: fle-tampon .55s cubic-bezier(.2,1.6,.4,1); }
@keyframes fle-tampon {
  0% { transform: rotate(-14deg) scale(1.9); opacity: 0; }
  55% { transform: rotate(1deg) scale(.94); opacity: 1; }
  100% { transform: rotate(-2.2deg) scale(1); }
}
@media (prefers-reduced-motion: reduce) { .fle-cachet--anime { animation: none; } }

/* --- Chrono partagé ----------------------------------------------------- */
.fle-chrono {
  font-family: var(--data); font-size: 19px; font-weight: 700;
  padding: 3px 10px; border-radius: 6px; background: var(--ink); color: var(--white);
}
.fle-chrono--alerte { background: var(--danger); }
.fle-chrono--fini { background: var(--muted); }

/* --- Corps -------------------------------------------------------------- */
.fle-corps { padding: clamp(12px, 2.2vw, 22px); min-height: 420px; }
.fle-titre { font-size: 20px; font-weight: 700; letter-spacing: -.01em; }
.fle-soustitre { color: var(--muted); font-size: 14px; margin-top: 3px; }
.fle-section { margin-top: 18px; }
/* Les intitulés de section étaient en capitales espacées. C'est le tic le
   plus répandu des interfaces récentes, et c'est aussi ce qui se lit le plus
   mal : les capitales suppriment la silhouette du mot, sur laquelle repose
   la lecture rapide - et elles gênent particulièrement les lecteurs
   dyslexiques. Bas de casse, un cran de graisse, et la couleur de marque
   pour dire « ceci est un repère ». */
.fle-etiquette {
  display: block; margin-bottom: 6px;
  font-size: 12.5px; font-weight: 650; letter-spacing: 0; text-transform: none;
  color: var(--primary);
}

/* --- Accueil : la grille des modules ------------------------------------ */
.fle-grille { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 230px), 1fr)); gap: 14px; margin-top: 16px; }
.fle-tuile {
  display: flex; flex-direction: column; gap: 6px; text-align: left;
  background: var(--white); border: 1px solid var(--line); border-left: 4px solid var(--accent);
  border-radius: var(--radius); padding: 16px; box-shadow: var(--ombre-1);
  min-height: 104px;
  transition: transform .16s ease, border-color .16s ease, box-shadow .16s ease, background-color .16s ease;
}
.fle-tuile:hover { transform: translateY(-2px); box-shadow: var(--ombre-3); background: var(--lavis); }
.fle-tuile:focus-visible { transform: translateY(-2px); }
.fle-tuile__num { font-family: var(--data); font-size: 11.5px; color: var(--muted); letter-spacing: .06em; }
.fle-tuile__titre { font-weight: 680; font-size: 16px; letter-spacing: -.008em; }
.fle-tuile__texte { font-size: 13.5px; color: var(--muted); line-height: 1.45; }
/* L'atelier ouvert ne se signale pas seulement par un fond : il porte un
   filet plein sur toute sa hauteur, visible même en niveaux de gris. */
.fle-tuile--actif {
  border-left-width: 6px; border-left-color: var(--primary);
  background: var(--lavis-fort); box-shadow: var(--ombre-2);
}

/* --- Boutons -------------------------------------------------------------
   Quatre niveaux d'insistance, et un seul mécanisme : chaque variante ne
   fait que reposer trois variables. Ajouter une cinquième variante demande
   trois lignes, pas une nouvelle règle de mise en forme.

       accent    l'action principale - aplat sarcelle
       (défaut)  l'action ordinaire  - aplat sarcelle profonde
       fantôme   l'alternative       - contour sarcelle
       sourdine  le repli, l'annulation - contour gris

   Le relief ne vient pas d'un dégradé mais d'un liseré clair intérieur :
   un dégradé sur un aplat aussi saturé vire au sale dès qu'on le survole.
   ---------------------------------------------------------------------- */
.fle-btn {
  --btn-fond:  var(--primary);
  --btn-bord:  var(--primary);
  --btn-texte: var(--white);

  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 40px; padding: 9px 17px;
  border: 1.5px solid var(--btn-bord);
  background: var(--btn-fond);
  color: var(--btn-texte);
  border-radius: 10px;
  font-weight: 600; font-size: 14.5px; line-height: 1.25; letter-spacing: -.003em;
  text-align: center; text-decoration: none;
  box-shadow: var(--ombre-1), inset 0 1px 0 rgba(255,255,255,.15);
  transition: background-color .16s ease, border-color .16s ease,
              box-shadow .16s ease, transform .07s ease, color .16s ease;
}
.fle-btn:hover:not([disabled]) {
  background: color-mix(in srgb, var(--btn-fond) 87%, #06201F);
  border-color: color-mix(in srgb, var(--btn-bord) 87%, #06201F);
  box-shadow: var(--ombre-2), inset 0 1px 0 rgba(255,255,255,.15);
}
.fle-btn:active:not([disabled]) {
  transform: translateY(1px);
  box-shadow: inset 0 2px 5px rgba(6,32,31,.20);
}
/* Sur un aplat sarcelle, un anneau sombre posé au ras du bouton se
   perdrait : #166E6E sur #197F7F, c'est 1,26:1, autant dire rien. On
   intercale donc un liseré blanc de 3 px, exactement de l'épaisseur du
   décalage, si bien que l'anneau se détache toujours sur du blanc -
   6:1 - et le blanc sur le bouton - 4,8:1. Les deux frontières passent. */
.fle-btn:focus-visible {
  outline: 3px solid var(--accent-sombre);
  outline-offset: 3px;
  box-shadow: 0 0 0 3px var(--white), var(--ombre-2);
}

.fle-btn--accent   { --btn-fond: var(--accent-plein); --btn-bord: var(--accent-plein); }
.fle-btn--fantome  { --btn-fond: var(--white); --btn-bord: color-mix(in srgb, var(--primary) 45%, var(--white)); --btn-texte: var(--primary); }
.fle-btn--fantome:hover:not([disabled]) { background: var(--lavis); border-color: var(--primary); color: var(--primary); }
.fle-btn--sourdine { --btn-fond: var(--white); --btn-bord: var(--line); --btn-texte: var(--muted); box-shadow: none; }
.fle-btn--sourdine:hover:not([disabled]) { background: var(--lavis-gris); border-color: var(--gris); color: var(--ink); box-shadow: var(--ombre-1); }
.fle-btn--danger   { --btn-fond: var(--danger); --btn-bord: var(--danger); }

.fle-btn--petit { min-height: 34px; padding: 6px 12px; font-size: 13px; border-radius: 8px; gap: 6px; }
.fle-btn--grand { min-height: 46px; padding: 11px 20px; font-size: 15.5px; min-width: 58px; font-variant-numeric: tabular-nums; letter-spacing: .02em; }

/* Un bouton désactivé doit se lire comme désactivé, pas devenir illisible :
   on baisse le contraste de la SURFACE, jamais celui du libellé sur elle.
   Une opacité globale à .45 rendait le texte indéchiffrable. */
.fle-btn[disabled] {
  --btn-fond: var(--lavis-gris); --btn-bord: var(--line); --btn-texte: var(--muted);
  cursor: not-allowed; box-shadow: none; transform: none;
}

/* État sélectionné d'un groupe de bascules - les niveaux A1 … C1. Le
   marqueur n'est pas seulement la couleur : le bouton s'enfonce. */
.fle-btn[aria-pressed="true"] {
  --btn-fond: var(--accent-plein); --btn-bord: var(--accent-plein); --btn-texte: var(--white);
  box-shadow: inset 0 2px 4px rgba(6,32,31,.22);
}

.fle-barre-boutons { display: flex; flex-wrap: wrap; gap: 9px; align-items: center; }

/* --- Champs ------------------------------------------------------------- */
/* 16 px minimum : en dessous, iOS zoome tout seul à la mise au point et
   l'apprenant se retrouve avec une page décadrée qu'il ne sait pas remettre. */
.fle-champ, .fle-app select.fle-champ, .fle-app textarea.fle-champ {
  width: 100%; min-height: 42px; padding: 10px 13px;
  border: 1.5px solid var(--line); border-radius: var(--radius-xs);
  background: var(--white); color: var(--ink);
  font-family: inherit; font-size: max(16px, 1em); line-height: 1.5;
  transition: border-color .16s ease, box-shadow .16s ease;
}
.fle-champ::placeholder { color: var(--muted); opacity: 1; }
.fle-champ:hover:not(:disabled) { border-color: color-mix(in srgb, var(--gris) 70%, var(--line)); }
.fle-champ:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent);
}
/* L'anneau de focus global reste : le halo pâle ne suffit pas au soleil. */
.fle-champ:disabled { background: var(--lavis-gris); color: var(--muted); cursor: not-allowed; }
.fle-champ[aria-invalid="true"] { border-color: var(--danger); }
select.fle-champ { max-width: 260px; }
.fle-ligne { display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-end; }
.fle-ligne > * { flex: 0 0 auto; }
.fle-groupe { display: flex; flex-direction: column; gap: 4px; }
.fle-inline { display: inline-flex; align-items: center; gap: 6px; font-size: 13.5px; }

/* --- Cartes ------------------------------------------------------------- */
.fle-carte {
  background: var(--white); border: 1px solid var(--line);
  border-radius: var(--radius); padding: clamp(13px, 1.6vw, 18px);
  box-shadow: var(--ombre-1);
}
.fle-carte + .fle-carte { margin-top: 14px; }
/* Les colonnes se replient d'elles-mêmes : `auto-fit` évite d'avoir à
   deviner le point de rupture, et `min(100%, …)` empêche le débordement
   sur les très petits écrans, où une colonne de 260 px ne tient pas. */
.fle-deux  { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr)); gap: 16px; align-items: start; }
.fle-trois { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 230px), 1fr)); gap: 14px; }

/* --- Atelier d'écriture ------------------------------------------------- */
.fle-consigne {
  font-family: var(--texte); font-size: 16px; line-height: 1.62;
  background: color-mix(in srgb, var(--primary) 5%, var(--white));
  border-left: 3px solid var(--primary); padding: 12px 14px; border-radius: 0 7px 7px 0;
  white-space: pre-wrap; min-height: 90px;
}
.fle-production {
  width: 100%; min-height: 300px; resize: vertical;
  font-family: var(--texte); font-size: 16.5px; line-height: 1.85;
  padding: 14px 16px; border: 1px solid var(--line); border-radius: 7px; background: var(--white);
  background-image: repeating-linear-gradient(180deg, transparent 0 calc(1.85em - 1px), color-mix(in srgb, var(--line) 65%, transparent) calc(1.85em - 1px) 1.85em);
  background-position: 0 14px;
}
.fle-compteur { display: flex; gap: 16px; align-items: baseline; font-family: var(--data); font-size: 13px; color: var(--muted); margin-top: 8px; flex-wrap: wrap; }
.fle-compteur b { font-size: 22px; color: var(--ink); }
.fle-compteur--cible-ok b { color: var(--success); }
.fle-compteur--cible-court b { color: var(--warn); }
.fle-jauge { height: 5px; background: var(--line); border-radius: 3px; overflow: hidden; margin-top: 6px; }
.fle-jauge span { display: block; height: 100%; background: var(--accent); transition: width .25s ease; }

/* --- Tableau blanc ------------------------------------------------------ */
.fle-tbi { display: grid; grid-template-columns: 62px 1fr; gap: 10px; }
@media (max-width: 700px) { .fle-tbi { grid-template-columns: 1fr; } }
.fle-outils { display: flex; flex-direction: column; gap: 5px; background: var(--white); border: 1px solid var(--line); border-radius: var(--radius); padding: 6px; align-content: start; }
@media (max-width: 700px) { .fle-outils { flex-direction: row; flex-wrap: wrap; } }
/* Les outils du tableau. L'outil actif ne se signale pas seulement par un
   fond teinté - invisible pour qui ne perçoit pas la sarcelle : il porte un
   contour plein et un liseré, et il s'enfonce légèrement. */
.fle-outil {
  width: 48px; height: 44px; display: grid; place-items: center;
  border: 1.5px solid transparent; border-radius: var(--radius-xs);
  background: transparent; color: var(--ink);
  transition: background-color .15s ease, border-color .15s ease, color .15s ease;
}
.fle-outil:hover { background: var(--lavis); color: var(--primary); }
.fle-outil[aria-pressed="true"] {
  background: var(--lavis-fort); border-color: var(--accent); color: var(--primary);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 35%, var(--white));
}
.fle-outil svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.fle-toile-boite { position: relative; background: var(--white); border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }
.fle-toile { display: block; width: 100%; touch-action: none; cursor: crosshair; background: #fff; }
.fle-tbi-haut { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-bottom: 10px; }
.fle-couleurs { display: flex; gap: 4px; }
.fle-couleur {
  width: 28px; height: 28px; border-radius: 50%; border: 2px solid var(--white);
  box-shadow: 0 0 0 1px var(--line); transition: box-shadow .15s ease, transform .1s ease;
}
.fle-couleur:hover { transform: scale(1.06); }
/* La couleur retenue porte un anneau d'encre : sur une pastille, la couleur
   ne peut pas signaler la sélection puisqu'elle EST l'information. */
.fle-couleur[aria-pressed="true"] { box-shadow: 0 0 0 3px var(--ink); }
.fle-tbi-pages { font-family: var(--data); font-size: 13px; color: var(--muted); }

/* --- Conjugaison -------------------------------------------------------- */
.fle-drill { display: grid; gap: 10px; }
.fle-item { display: grid; grid-template-columns: 1fr 200px; gap: 10px; align-items: center; background: var(--white); border: 1px solid var(--line); border-radius: 8px; padding: 10px 12px; }
@media (max-width: 640px) { .fle-item { grid-template-columns: 1fr; } }
.fle-item__enonce { font-family: var(--texte); font-size: 16px; }
.fle-item__enonce em { color: var(--primary); font-style: normal; font-weight: 700; }
.fle-item--juste { border-color: var(--success); background: color-mix(in srgb, var(--success) 6%, var(--white)); }
.fle-item--faux { border-color: var(--danger); background: color-mix(in srgb, var(--danger) 5%, var(--white)); }
.fle-correction { font-size: 13px; color: var(--danger); margin-top: 4px; }
.fle-correction b { color: var(--success); }
.fle-score { font-family: var(--data); font-size: 26px; font-weight: 700; }

/* --- Listes de suivi ---------------------------------------------------- */
.fle-suivi { display: grid; gap: 8px; }
.fle-eleve { display: grid; grid-template-columns: 1fr auto; gap: 8px; align-items: center; background: var(--white); border: 1px solid var(--line); border-left: 3px solid var(--primary); border-radius: 8px; padding: 9px 12px; }
.fle-eleve--main { border-left-color: var(--accent); background: color-mix(in srgb, var(--accent) 7%, var(--white)); }
.fle-eleve--absent { border-left-color: var(--line); opacity: .72; }
.fle-eleve--revoque { border-left-color: var(--danger); background: color-mix(in srgb, var(--danger) 5%, var(--white)); }
.fle-eleve--gere { grid-template-columns: 1fr auto; }
/* Les commandes d'un inscrit (passe, libérer, révoquer, supprimer) passent
   sous le nom, sur toute la largeur : à côté, elles écrasaient le nom et le
   détail du travail en une colonne de quelques mots. */
.fle-eleve[tabindex="-1"]:focus { outline: 2px solid var(--primary); outline-offset: 2px; }
.fle-eleve--gere > .fle-eleve__actions { grid-column: 1 / -1; justify-content: flex-start; border-top: 1px dashed var(--line); padding-top: 8px; }
.fle-eleve__actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.fle-eleve__nom { font-weight: 600; }
.fle-eleve__detail { font-size: 12.5px; color: var(--muted); font-family: var(--data); }
/* Le passe de sept jours : la case et « Renouveler » restent ensemble. */
.fle-passe { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.fle-passe input[type="checkbox"] { width: 16px; height: 16px; margin: 0; accent-color: var(--primary); }
.fle-extrait { font-family: var(--texte); font-size: 14px; white-space: pre-wrap; max-height: 220px; overflow: auto; border-top: 1px dashed var(--line); margin-top: 8px; padding-top: 8px; grid-column: 1/-1; }

/* --- Journal / chat ----------------------------------------------------- */
.fle-journal { max-height: 340px; overflow: auto; display: flex; flex-direction: column; gap: 7px; padding-right: 4px; }
.fle-msg { border: 1px solid var(--line); border-radius: 8px; padding: 8px 11px; background: var(--white); }
.fle-msg--formateur { border-left: 3px solid var(--primary); }
.fle-msg--apprenant { border-left: 3px solid var(--accent); }
.fle-msg__meta { font-size: 11px; color: var(--muted); font-family: var(--data); }
.fle-msg__texte { white-space: pre-wrap; }

/* --- QCM ---------------------------------------------------------------- */
.fle-support { font-family: var(--texte); font-size: 16px; line-height: 1.7; white-space: pre-wrap; }
.fle-question { background: var(--white); border: 1px solid var(--line); border-radius: 8px; padding: 12px; }
.fle-question + .fle-question { margin-top: 10px; }
.fle-choix {
  display: block; padding: 10px 12px; border: 1.5px solid var(--line);
  border-radius: var(--radius-xs); margin-top: 7px; cursor: pointer;
  transition: background-color .15s ease, border-color .15s ease;
}
.fle-choix:hover { background: var(--lavis); border-color: var(--accent); }
/* Juste et faux se distinguent par un glyphe autant que par la couleur. */
.fle-choix--juste { border-color: var(--succes); border-left-width: 5px; background: color-mix(in srgb, var(--succes) 8%, var(--white)); }
.fle-choix--faux  { border-color: var(--danger); border-left-width: 5px; background: color-mix(in srgb, var(--danger) 6%, var(--white)); }
.fle-choix--juste::after { content: " \2713"; color: var(--succes); font-weight: 700; }
.fle-choix--faux::after  { content: " \2715"; color: var(--danger); font-weight: 700; }

/* --- Lexique / cartes --------------------------------------------------- */
.fle-carte-mot { background: var(--white); border: 1px solid var(--line); border-radius: var(--radius); padding: 22px; min-height: 190px; display: grid; place-content: center; text-align: center; box-shadow: var(--shadow); }
.fle-carte-mot__mot { font-family: var(--texte); font-size: 30px; font-weight: 700; }
.fle-carte-mot__cat { font-size: 13px; color: var(--muted); letter-spacing: 0; text-transform: none; }
.fle-carte-mot__def { font-family: var(--texte); font-size: 16px; margin-top: 12px; max-width: 46ch; }
.fle-carte-mot__ex { font-family: var(--texte); font-style: italic; color: var(--muted); margin-top: 8px; }

/* --- Divers ------------------------------------------------------------- */
/* Une alerte ne dit jamais son état par la seule couleur : un glyphe la
   double, et un filet épais à gauche la double encore. Huit pour cent des
   hommes ne distinguent pas le rouge du vert ; sur un écran de téléphone
   en plein soleil, personne ne les distingue. */
.fle-alerte {
  position: relative; border-radius: var(--radius-s);
  padding: 11px 14px 11px 40px; font-size: 14px;
  border: 1px solid; border-left-width: 4px; line-height: 1.5;
}
.fle-alerte::before {
  position: absolute; left: 13px; top: 11px;
  font-size: 15px; font-weight: 700; line-height: 1.35;
}
.fle-alerte--info {
  background: var(--lavis); border-color: color-mix(in srgb, var(--accent) 34%, var(--line));
  border-left-color: var(--accent);
}
.fle-alerte--info::before { content: "i"; font-style: italic; color: var(--primary); }
.fle-alerte--succes, .fle-alerte--success {
  background: color-mix(in srgb, var(--succes) 7%, var(--white));
  border-color: color-mix(in srgb, var(--succes) 34%, var(--line));
  border-left-color: var(--succes); color: var(--ink);
}
.fle-alerte--succes::before, .fle-alerte--success::before { content: "\2713"; color: var(--succes); }
.fle-alerte--attention {
  background: color-mix(in srgb, var(--alerte) 8%, var(--white));
  border-color: color-mix(in srgb, var(--alerte) 34%, var(--line));
  border-left-color: var(--alerte); color: var(--ink);
}
.fle-alerte--attention::before { content: "!"; color: var(--alerte); }
.fle-alerte--erreur {
  background: color-mix(in srgb, var(--danger) 6%, var(--white));
  border-color: color-mix(in srgb, var(--danger) 34%, var(--line));
  border-left-color: var(--danger); color: var(--danger);
}
.fle-alerte--erreur::before { content: "\2715"; color: var(--danger); }
.fle-vide { text-align: center; color: var(--muted); padding: 34px 16px; font-family: var(--texte); font-size: 16px; }
/* Les annonces vivent dans la racine de l'application : elles héritent de
   sa palette et de son thème, ce qui n'était pas le cas sur <body>. */
.fle-annonce { position: fixed; left: 50%; bottom: 22px; transform: translateX(-50%); z-index: 9999; background: var(--fle-ink, var(--ink, #22302F)); color: var(--white, #fff); padding: 11px 18px; border-radius: 999px; box-shadow: 0 12px 30px rgba(0,0,0,.28); font-size: 15px; line-height: 1.4; max-width: min(92vw, 640px); }
.fle-annonce[hidden] { display: none; }
.fle-annonce--erreur { background: var(--danger); color: #fff; cursor: pointer; padding-right: 30px; }
.fle-annonce--erreur::after { content: "\2715"; position: absolute; right: 12px; top: 50%; transform: translateY(-50%); opacity: .8; }
.fle-connexion { max-width: 480px; margin: 40px auto; }
.fle-connexion .fle-carte { padding: 26px; }
.fle-connexion h2 { font-size: 22px; font-weight: 700; }
.fle-connexion p { color: var(--muted); margin: 6px 0 16px; }
.fle-badge { display: inline-block; font-size: 12px; font-weight: 620; letter-spacing: 0; text-transform: none; padding: 3px 9px; border-radius: 999px; background: var(--paper); border: 1px solid var(--line); color: var(--muted); }
.fle-badge--vert { color: var(--success); border-color: color-mix(in srgb, var(--success) 40%, var(--line)); }
.fle-badge--orange { color: var(--alerte); border-color: color-mix(in srgb, var(--alerte) 45%, var(--line)); background: color-mix(in srgb, var(--alerte) 7%, var(--white)); }
.fle-badge--rouge { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 45%, var(--line)); }
.fle-retour { display: inline-flex; align-items: center; gap: 6px; background: none; border: none; color: var(--primary); font-weight: 600; padding: 0 0 10px; }
.fle-table { width: 100%; border-collapse: collapse; font-size: 14px; }
.fle-table th, .fle-table td { text-align: left; padding: 7px 9px; border-bottom: 1px solid var(--line); }
.fle-table th { font-size: 12.5px; font-weight: 650; text-transform: none; letter-spacing: 0; color: var(--primary); }
.fle-mono { font-family: var(--data); }
@media print { .fle-bar, .fle-outils, .fle-barre-boutons, .fle-retour { display: none !important; } .fle-app { border: none; } }

/* --- Salles indépendantes ----------------------------------------------
   Le formateur tient plusieurs sections de front. Chaque carte est une
   salle close sur elle-même : son code, ses inscrits, ses productions.
   ---------------------------------------------------------------------- */
.fle-salles { display: grid; gap: 12px; margin-top: 10px; }
.fle-salle {
  background: var(--white); border: 1px solid var(--line); border-radius: 10px;
  border-left: 4px solid var(--primary); padding: 13px 15px;
}
.fle-salle--close { border-left-color: var(--line); background: color-mix(in srgb, var(--paper) 60%, var(--white)); }
.fle-salle__haut { display: flex; flex-direction: column; gap: 6px; }
.fle-salle__id { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.fle-salle__titre { font-size: 16px; }
.fle-salle__meta { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; }
.fle-salle__bas {
  display: flex; flex-wrap: wrap; align-items: center; gap: 14px;
  margin-top: 11px; padding-top: 10px; border-top: 1px dashed var(--line);
}
.fle-code--petit { font-size: 14px; letter-spacing: .14em; padding: 3px 8px; }
.fle-lien {
  appearance: none; background: none; border: 0; padding: 0; cursor: pointer;
  font: inherit; font-size: 12.5px; color: var(--muted);
  text-decoration: underline; text-underline-offset: 3px;
}
.fle-lien:hover { color: var(--primary); }
/* Une commande autonome (hors phrase) doit offrir 24 px de haut. */
.fle-lien--cible { display: inline-block; min-height: 24px; padding: 3px 4px; }
.fle-lien--danger:hover { color: var(--danger); }

@media (max-width: 640px) {
  .fle-salle__meta { gap: 8px; font-size: 12px; }
  .fle-salle__bas { gap: 10px; }
}

@media print {
  .fle-salles, .fle-bar__sortie { display: none !important; }
}

/* --- Sortie de salle -----------------------------------------------------
   Quitter une section n'est ni une fermeture ni une perte : le pied de page
   le rappelle, à l'endroit où le regard finit sa course.
   ---------------------------------------------------------------------- */
.fle-pied {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
  margin-top: 22px; padding-top: 14px;
  border-top: 1px dashed var(--line);
}
.fle-carte--vif {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent), var(--shadow);
}

@media print { .fle-pied { display: none !important; } }

/* --- Bascule d'une salle à l'autre --------------------------------------
   Le formateur qui tient trois groupes en même temps ne doit pas repasser
   par la liste pour changer de salle : le menu est dans la barre.
   ---------------------------------------------------------------------- */
.fle-bar__bascule {
  appearance: auto; max-width: 260px;
  padding: 4px 8px; font-size: 13px; font-family: inherit;
  border: 1px solid var(--line); border-radius: 6px;
  background: var(--white); color: var(--ink); cursor: pointer;
}
.fle-bar__bascule:hover { border-color: var(--primary); }
.fle-bar__bascule[hidden] { display: none; }

@media (max-width: 720px) {
  .fle-eleve--gere { grid-template-columns: 1fr; }
  .fle-eleve__actions { justify-content: flex-start; }
  .fle-bar__bascule { max-width: 100%; flex: 1 1 100%; order: 9; }
}

@media print { .fle-bar__bascule, .fle-eleve__actions { display: none !important; } }

/* --- Barre de sortie ----------------------------------------------------
   Sur tous les écrans, dans les deux interfaces. Quitter une salle est un
   geste ordinaire : il ne se cherche pas, il se voit.
   ---------------------------------------------------------------------- */
.fle-sortie {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
  margin: 0 0 16px; padding: 9px 12px;
  background: color-mix(in srgb, var(--primary) 5%, var(--white));
  border: 1px solid var(--line); border-left: 4px solid var(--primary);
  border-radius: 9px;
}
.fle-sortie__quitter { font-weight: 700; }
.fle-sortie__code { display: inline-flex; align-items: center; gap: 7px; }
.fle-sortie__code .fle-etiquette { margin: 0; }
.fle-sortie__qui { display: inline-flex; align-items: center; gap: 7px; }
.fle-sortie__qui .fle-etiquette { margin: 0; }

@media (max-width: 640px) {
  .fle-sortie { gap: 8px; padding: 8px 10px; }
  .fle-sortie__quitter { flex: 1 1 100%; }
}

@media print { .fle-sortie { display: none !important; } }

/* --- Identification du formateur et lien sensible ------------------------ */
.fle-identite { border-left: 4px solid var(--accent); }
.fle-carte--sensible {
  border-left: 4px solid var(--danger);
  background: color-mix(in srgb, var(--danger) 4%, var(--white));
}

/* --- Pied technique ------------------------------------------------------
   La version réellement chargée, et de quoi repartir d'un navigateur propre.
   Discret, mais toujours là : c'est ce qui permet de diagnostiquer.
   ---------------------------------------------------------------------- */
.fle-technique {
  display: flex; flex-wrap: wrap; align-items: center; gap: 12px;
  margin-top: 26px; padding-top: 12px;
  border-top: 1px solid var(--line);
  font-size: 12px; color: var(--muted); font-family: var(--data);
}
@media print { .fle-technique { display: none !important; } }

/* ---------------------------------------------------------------------
   Parcours guidés - progression, tableaux de règle, retours de correction
   ------------------------------------------------------------------ */
.fle-app .fle-jauge__part { display: block; height: 100%; background: var(--accent); transition: width .25s ease; }

.fle-app .fle-liste { margin: 10px 0 0; padding-left: 20px; font-family: var(--texte); line-height: 1.55; }
.fle-app .fle-liste li { margin-bottom: 6px; }

.fle-app .fle-tableau-cadre { margin-top: 12px; overflow-x: auto; -webkit-overflow-scrolling: touch; }
.fle-app .fle-tableau { width: 100%; border-collapse: collapse; font-size: .94rem; min-width: 460px; }
.fle-app .fle-tableau th,
.fle-app .fle-tableau td { text-align: left; padding: 7px 10px; border-bottom: 1px solid var(--line); vertical-align: top; }
.fle-app .fle-tableau th { font-family: var(--ui); font-weight: 600; color: var(--primary); background: var(--paper); }
.fle-app .fle-tableau td { font-family: var(--texte); }
.fle-app .fle-tableau tr:last-child td { border-bottom: 0; }

.fle-app .fle-alerte--succes { border-color: var(--success); color: var(--success); background: color-mix(in srgb, var(--succes) 7%, var(--white)); }

.fle-app .fle-attente { padding: 22px; text-align: center; color: var(--muted);
  border: 1px dashed var(--line); border-radius: var(--radius); font-family: var(--texte); }

/* ---------------------------------------------------------------------
   Tableau blanc - saisie de texte à même la toile
   ------------------------------------------------------------------ */
.fle-app .fle-toile-boite { position: relative; }
.fle-app .fle-tbi-saisie {
  position: absolute; z-index: 5; margin: 0; padding: 2px 4px;
  border: 1.5px dashed var(--accent); border-radius: 4px;
  background: rgba(255,255,255,.94); box-shadow: 0 2px 10px rgba(15,60,58,.14);
  font-family: Georgia, "Iowan Old Style", "Times New Roman", serif;
  font-weight: 600; resize: none; overflow: hidden;
  min-width: 140px; max-width: 96%;
}
.fle-app .fle-tbi-saisie::placeholder { color: var(--muted); font-weight: 400; font-size: .68em; font-style: italic; }

/* ---------------------------------------------------------------------
   Cours de conversation - sommaire, étapes, mémo
   ------------------------------------------------------------------ */
.fle-app .fle-niveaux { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }

.fle-app .fle-etapes-rail { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
/* Le fil des sept étapes. Trois états, et chacun se distingue autrement
   que par la couleur : à venir (contour léger), franchie (fond teinté,
   contour plein), en cours (aplat plein et anneau extérieur). */
.fle-app .fle-etape-puce {
  flex: 0 0 auto;
  width: 38px; height: 38px; border-radius: 50%;
  border: 1.5px solid var(--line);
  background: var(--white); color: var(--muted); font-family: var(--ui);
  font-size: 14.5px; font-weight: 650; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background-color .18s ease, border-color .18s ease, color .18s ease, box-shadow .18s ease;
}
.fle-app .fle-etape-puce:hover:not(:disabled) { border-color: var(--accent); color: var(--primary); background: var(--lavis); }
.fle-app .fle-etape-puce--faite { background: var(--lavis-fort); color: var(--primary); border-color: var(--accent); }
.fle-app .fle-etape-puce--vive {
  background: var(--accent-plein); border-color: var(--accent-plein); color: #fff;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 24%, transparent);
}
.fle-app .fle-etape-puce:disabled { background: var(--lavis-gris); color: var(--muted); border-color: var(--line); cursor: not-allowed; }

.fle-app .fle-etiquettes { display: flex; flex-wrap: wrap; gap: 6px; }
.fle-app .fle-mot {
  display: inline-block; padding: 4px 10px; border-radius: 14px;
  background: var(--paper); border: 1px solid var(--line);
  font-family: var(--texte); font-size: .92rem;
}

.fle-app .fle-texte-support {
  margin-top: 12px; padding: 14px 16px; border-left: 3px solid var(--primary);
  background: var(--paper); border-radius: 0 var(--radius) var(--radius) 0;
  font-family: var(--texte); line-height: 1.7; white-space: pre-wrap;
}

.fle-app .fle-formules { margin-top: 10px; }
.fle-app .fle-formule {
  padding: 6px 12px; margin-bottom: 5px; border-radius: var(--radius);
  background: color-mix(in srgb, var(--accent) 6%, var(--white)); font-family: var(--texte); font-style: italic;
}

/* Le type de la question - littéral, inférence, critique - se lit d'un
   coup d'œil. Trois pastilles, bas de casse, et des teintes assez
   distinctes en VALEUR pour rester lisibles en noir et blanc. */
.fle-app .fle-marque {
  display: inline-block; padding: 2px 9px; border-radius: 999px; margin-left: 5px;
  font-family: var(--ui); font-size: .74rem; font-weight: 600;
  text-transform: none; letter-spacing: 0; white-space: nowrap;
  border: 1px solid transparent;
}
.fle-app .fle-marque--lit { background: color-mix(in srgb, var(--succes) 11%, var(--white)); border-color: color-mix(in srgb, var(--succes) 28%, var(--white)); color: var(--succes); }
.fle-app .fle-marque--inf { background: color-mix(in srgb, var(--alerte) 12%, var(--white)); border-color: color-mix(in srgb, var(--alerte) 30%, var(--white)); color: var(--alerte); }
.fle-app .fle-marque--cri { background: color-mix(in srgb, #6B3FA0 11%, var(--white)); border-color: color-mix(in srgb, #6B3FA0 28%, var(--white)); color: color-mix(in srgb, #5C3590 80%, var(--ink)); }

.fle-app .fle-memo {
  margin-top: 18px; padding: 18px 20px; border: 2px solid var(--accent);
  border-radius: var(--radius); background: color-mix(in srgb, var(--accent) 4%, var(--white));
}
.fle-app .fle-memo__titre { font-family: var(--ui); font-weight: 700; font-size: 1.05rem; color: var(--ink); }
.fle-app .fle-memo__section {
  margin-top: 16px; margin-bottom: 7px; font-family: var(--ui); font-size: .82rem;
  text-transform: none; letter-spacing: 0; color: var(--primary); font-weight: 650;
}

/* --- Conversation : types de questions, spirale, tâche finale --- */
.fle-app .fle-marque--ora { background: var(--lavis-fort); border-color: color-mix(in srgb, var(--accent) 32%, var(--white)); color: var(--primary); }
.fle-app .fle-question-orale { font-style: italic; color: var(--muted); }
.fle-app .fle-qcm-choix { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.fle-app .fle-spirale {
  display: flex; flex-wrap: wrap; gap: 8px; align-items: center;
  margin-top: 8px; padding: 8px 10px; border-radius: var(--radius); background: var(--paper);
}
.fle-app .fle-tache-finale {
  margin-top: 14px; padding: 12px 14px; border: 1px dashed var(--primary);
  border-radius: var(--radius); background: color-mix(in srgb, var(--accent) 4%, var(--white));
}
.fle-app .fle-tache-finale p { font-family: var(--texte); margin: 0; }

/* ---------------------------------------------------------------------
   Atelier « Les nombres » - item à lire, tour de parole, verdict
   ------------------------------------------------------------------ */
.fle-app .fle-nb-item {
  margin-top: 14px; padding: 22px 18px; text-align: center;
  border: 2px solid var(--primary); border-radius: var(--radius); background: var(--white);
  font-family: var(--ui); font-size: clamp(1.6rem, 5vw, 2.6rem);
  font-weight: 700; letter-spacing: .04em; color: var(--ink);
  word-break: break-word; line-height: 1.35;
}

.fle-app .fle-nb-tour {
  padding: 12px 16px; border-radius: var(--radius); margin-bottom: 12px;
  background: var(--paper); border: 1px solid var(--line);
  font-family: var(--ui); color: var(--muted); text-align: center;
}
.fle-app .fle-nb-tour--moi {
  background: var(--accent); border-color: var(--accent); color: #fff;
  font-weight: 700; font-size: 1.08rem;
  animation: fle-nb-pulse 1.6s ease-in-out infinite;
}
@keyframes fle-nb-pulse {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 45%, transparent); }
  50%      { box-shadow: 0 0 0 10px transparent; }
}

.fle-app .fle-verdict {
  position: relative; overflow: hidden; margin-top: 16px; padding: 24px 18px;
  text-align: center; border-radius: var(--radius); border: 2px solid;
  animation: fle-verdict-entree .32s cubic-bezier(.2,.9,.3,1.4);
}
@keyframes fle-verdict-entree {
  from { opacity: 0; transform: scale(.88) translateY(8px); }
  to   { opacity: 1; transform: none; }
}
.fle-app .fle-verdict--bravo  { border-color: var(--success); background: color-mix(in srgb, var(--succes) 8%, var(--white)); }
.fle-app .fle-verdict--encore { border-color: var(--warn); background: color-mix(in srgb, var(--accent) 7%, var(--white)); }
.fle-app .fle-verdict__signe { font-size: 2.6rem; line-height: 1; }
.fle-app .fle-verdict--bravo .fle-verdict__signe  { color: var(--success); animation: fle-verdict-signe .7s ease-out; }
.fle-app .fle-verdict--encore .fle-verdict__signe { color: var(--warn); }
@keyframes fle-verdict-signe {
  0%   { transform: scale(.3) rotate(-25deg); opacity: 0; }
  60%  { transform: scale(1.25) rotate(6deg); opacity: 1; }
  100% { transform: none; }
}
.fle-app .fle-verdict__mot {
  margin-top: 6px; font-family: var(--ui); font-weight: 700;
  font-size: clamp(1.3rem, 4vw, 1.9rem);
}
.fle-app .fle-verdict--bravo .fle-verdict__mot  { color: var(--success); }
.fle-app .fle-verdict--encore .fle-verdict__mot { color: var(--warn); }
.fle-app .fle-verdict__note { margin-top: 4px; font-family: var(--texte); color: var(--muted); }

.fle-app .fle-confettis { position: absolute; inset: 0; pointer-events: none; }
.fle-app .fle-confetti {
  position: absolute; top: -12px; width: 7px; height: 12px; border-radius: 2px;
  background: var(--accent); opacity: 0; animation: fle-confetti-chute 1.5s ease-in forwards;
}
.fle-app .fle-confetti:nth-child(3n)   { background: var(--success); }
.fle-app .fle-confetti:nth-child(3n+1) { background: var(--primary); }
@keyframes fle-confetti-chute {
  0%   { opacity: 0; transform: translateY(-10px) rotate(0); }
  12%  { opacity: 1; }
  100% { opacity: 0; transform: translateY(190px) rotate(420deg); }
}

@media (prefers-reduced-motion: reduce) {
  .fle-app .fle-nb-tour--moi,
  .fle-app .fle-verdict,
  .fle-app .fle-verdict__signe,
  .fle-app .fle-confetti { animation: none; }
  .fle-app .fle-confettis { display: none; }
}

/* ------------------------- atelier « Tableau de FLE » ------------------- */
.fle-tableau-fle-barre { display: flex; align-items: center; gap: 12px; margin-bottom: 10px; flex-wrap: wrap; }
.fle-tableau-fle-enveloppe {
  position: relative; width: 100%; border: 1px solid var(--line); border-radius: var(--radius);
  overflow: hidden; box-shadow: var(--shadow); background: var(--white);
  height: min(78vh, 900px); min-height: 460px;
}
.fle-tableau-fle-cadre { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

/* -------------------------- signe « parcours terminé » ------------------ */
.fle-app .fle-etiquette--succes {
  display: inline-block; text-transform: none; letter-spacing: 0; font-weight: 700;
  font-size: 12.5px; color: var(--success); background: color-mix(in srgb, var(--succes) 10%, var(--white));
  border: 1px solid color-mix(in srgb, var(--success) 40%, var(--line));
  border-radius: 999px; padding: 2px 10px; margin: 0 8px 0 0;
}

/* ---------------------------------------------------------------------
   Cours de conversation - la consigne actionnelle et ses appuis

   Hiérarchie visuelle voulue : ce qu'il faut FAIRE arrive en premier et
   se voit de loin ; l'objectif de langue, qui regarde d'abord le
   formateur, s'efface ; la situation jouée se détache comme un encadré
   d'énoncé d'examen, parce que c'en est un. Les béquilles - version
   simple, glose des verbes - restent repliées : à portée, jamais
   encombrantes.
   ------------------------------------------------------------------ */
/* Trois blocs se suivent à l'écran : ce qu'il faut FAIRE, la MATIÈRE sur
   laquelle le faire, et la SITUATION à jouer. Avec une seule couleur de
   marque, on ne peut pas les distinguer par la teinte. On les distingue
   donc par la matière : l'action est un aplat teinté à filet épais, la
   matière une page blanche cernée d'un filet fin, la situation une fiche
   posée, avec son ombre et son bandeau. Trois surfaces, une seule voix. */
.fle-app .fle-faire {
  margin-top: 14px; padding: 14px 16px;
  background: var(--lavis-fort);
  border: 1px solid color-mix(in srgb, var(--accent) 26%, var(--white));
  border-left: 5px solid var(--accent);
  border-radius: 0 var(--radius-s) var(--radius-s) 0;
}
.fle-app .fle-faire__texte {
  font-family: var(--texte); font-size: var(--t-lire); line-height: 1.64; margin: 0;
  max-width: 68ch;
}
.fle-app .fle-faire__outils { margin-top: 10px; }

.fle-app .fle-simple {
  margin-top: 10px; padding: 10px 12px; border-radius: 7px;
  background: var(--white); border: 1px dashed color-mix(in srgb, var(--accent) 45%, var(--line));
}
.fle-app .fle-simple p { font-family: var(--texte); font-size: 16px; line-height: 1.7; }

.fle-app .fle-gloses {
  margin-top: 10px; padding: 10px 12px; border-radius: 7px;
  background: var(--white); border: 1px solid var(--line);
}
.fle-app .fle-gloses dt {
  font-weight: 650; font-size: 14px; letter-spacing: 0;
  color: var(--primary); margin-top: 10px;
}
.fle-app .fle-gloses dt:first-child { margin-top: 0; }
.fle-app .fle-gloses dd { margin: 2px 0 0; font-family: var(--texte); font-size: 15px; }

.fle-app .fle-objectif { margin-top: 10px; }
.fle-app .fle-objectif p { font-size: 14px; color: var(--muted); font-style: italic; }

/* La question, l'opération lexicale : ce sur quoi porte l'activité.
   Classe distincte de .fle-consigne, dont la hauteur minimale est
   réglée pour l'atelier d'écriture et conviendrait mal ici. */
.fle-app .fle-question-vive {
  margin-top: 14px; padding: 15px 17px;
  font-family: var(--texte); font-size: var(--t-lire); line-height: 1.62;
  background: var(--white);
  border: 1px solid var(--line);
  border-top: 3px solid var(--primary);
  border-radius: 0 0 var(--radius-s) var(--radius-s);
  max-width: 70ch;
}

/* --- L'amorce visuelle ------------------------------------------------ */
.fle-app .fle-amorce {
  margin-top: 12px; padding: 12px 14px; border-radius: var(--radius);
  border: 1px solid var(--line); background: var(--paper);
}
.fle-app .fle-amorce__img {
  display: block; width: 100%; max-height: 340px; object-fit: contain;
  border-radius: 8px; background: var(--white); border: 1px solid var(--line);
  margin-bottom: 10px;
}
.fle-app .fle-amorce__protocole { counter-reset: amorce; margin-top: 4px; }
.fle-app .fle-amorce__protocole li {
  counter-increment: amorce; position: relative; padding-left: 30px; margin-top: 8px;
  font-family: var(--texte); font-size: 15.5px; line-height: 1.55;
}
.fle-app .fle-amorce__protocole li::before {
  content: counter(amorce); position: absolute; left: 0; top: 1px;
  width: 21px; height: 21px; border-radius: 50%; display: grid; place-content: center;
  font-family: var(--ui); font-size: 12px; font-weight: 700;
  color: var(--white); background: var(--primary);
}
.fle-app .fle-amorce .fle-champ { margin-top: 8px; }

/* --- La situation, au format des épreuves d'expression orale ---------- */
.fle-app .fle-tache {
  position: relative; margin-top: 16px; padding: 16px 18px;
  border-radius: var(--radius);
  background: var(--white);
  border: 1px solid color-mix(in srgb, var(--accent) 30%, var(--line));
  box-shadow: var(--ombre-2);
  overflow: hidden;
}
.fle-app .fle-tache::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 4px;
  background: linear-gradient(90deg, var(--accent), var(--primary));
}
.fle-app .fle-tache__ligne {
  font-family: var(--texte); font-size: 16.5px; line-height: 1.6; margin-top: 6px;
}
.fle-app .fle-tache__ligne:first-of-type { margin-top: 2px; }
.fle-app .fle-tache__ligne strong { font-family: var(--ui); font-size: 14px; font-weight: 680; color: var(--primary); }
.fle-app .fle-tache__elements { margin-top: 4px; }
.fle-app .fle-tache__elements li {
  position: relative; padding-left: 16px; margin-top: 3px; font-size: 14.5px;
}
.fle-app .fle-tache__elements li::before {
  content: ''; position: absolute; left: 3px; top: .62em;
  width: 6px; height: 6px; border-radius: 50%; background: var(--accent);
}
.fle-app .fle-tache__bascule {
  margin-top: 12px; padding: 10px 13px; border-radius: var(--radius-xs); font-size: 14.5px;
  background: color-mix(in srgb, var(--alerte) 8%, var(--white));
  border: 1px solid color-mix(in srgb, var(--alerte) 32%, var(--line));
  border-left: 4px solid var(--alerte);
}
.fle-app .fle-tache__bascule strong { color: var(--alerte); }

/* --- Le texte d'origine, écrit pour la classe entière ----------------- */
.fle-app .fle-origine {
  margin-top: 8px; padding: 9px 12px; border-radius: 7px;
  background: var(--paper); border: 1px solid var(--line);
  font-size: 13.5px; color: var(--muted);
}
.fle-app .fle-origine p { margin-top: 4px; }
.fle-app .fle-origine p:first-child { margin-top: 0; }

/* =========================================================================
   ADAPTATION À L'APPAREIL

   La salle se donne à deux, et les deux ne sont presque jamais sur le même
   matériel : le formateur prépare sur un ordinateur, l'apprenant suit sur
   le téléphone qu'il a dans la poche - souvent debout, souvent dans les
   transports, parfois d'une seule main. Ce n'est pas un cas dégradé de la
   version bureau, c'est le cas le plus fréquent. Les règles qui suivent
   sont donc écrites dans cet ordre : ce qui doit rester atteignable au
   pouce d'abord, le confort du grand écran ensuite.
   ====================================================================== */

/* --- Tablette et petit portable (≤ 900 px) ----------------------------- */
@media (max-width: 900px) {
  .fle-bar { gap: 10px; }
  .fle-corps { padding: 16px; }
  .fle-connexion { margin: 24px auto; }
  .fle-connexion .fle-carte { padding: 20px; }
}

/* --- Téléphone (≤ 640 px) ---------------------------------------------- */
@media (max-width: 640px) {
  .fle-bar { gap: 9px; padding: 9px 12px; }
  .fle-bar__actions { margin-left: auto; }
  .fle-bar__espace { flex-basis: 100%; height: 0; }   /* force le retour à la ligne */
  .fle-role { display: none; }                        /* le rôle se devine à l'écran */
  .fle-code { font-size: 15.5px; letter-spacing: .12em; padding: 4px 10px; }

  .fle-corps { padding: 13px; min-height: 320px; }
  .fle-titre { font-size: 18.5px; }

  /* Le fil des sept étapes ne se replie pas sur trois lignes : il défile,
     et l'étape en cours se cale au bord gauche quand on y arrive. */
  .fle-app .fle-etapes-rail {
    flex-wrap: nowrap; overflow-x: auto; scroll-snap-type: x proximity;
    padding-bottom: 4px; margin-inline: -2px; padding-inline: 2px;
    scrollbar-width: thin;
  }
  .fle-app .fle-etape-puce { scroll-snap-align: start; }

  /* Une fiche d'apprenant sur deux colonnes devient illisible sous 400 px :
     le nom passe au-dessus, les commandes en dessous, sur toute la largeur. */
  .fle-eleve, .fle-eleve--gere { grid-template-columns: 1fr; }
  .fle-eleve__actions { justify-content: flex-start; }

  .fle-carte-mot { min-height: 150px; padding: 18px; }
  .fle-carte-mot__mot { font-size: 25px; }
  .fle-production { min-height: 220px; }

  /* Les tableaux larges défilent au lieu de déborder de la page. */
  .fle-app .fle-table { display: block; overflow-x: auto; -webkit-overflow-scrolling: touch; }

  /* Le message de confirmation se colle au bas de l'écran, au-dessus de la
     barre de navigation du téléphone. */
  .fle-annonce {
    left: 12px; right: 12px; transform: none; text-align: center;
    bottom: calc(14px + env(safe-area-inset-bottom, 0px));
    border-radius: var(--radius);
  }

  .fle-app .fle-amorce__img { max-height: 240px; }
  .fle-app .fle-faire, .fle-app .fle-question-vive, .fle-app .fle-tache { padding: 13px 14px; }
}

/* --- Petit téléphone (≤ 430 px) ---------------------------------------- */
@media (max-width: 430px) {
  /* Bord à bord : sur un écran de 360 px, quatorze pixels de marge et de
     coins arrondis, c'est une colonne de texte en moins. */
  .fle-app { border-radius: 0; border-left: 0; border-right: 0; }
  .fle-corps { padding: 11px; }
  .fle-carte { padding: 12px; border-radius: var(--radius-s); }

  /* Les commandes d'une même barre prennent toute la largeur et s'empilent :
     sur un téléphone tenu d'une main, deux boutons côte à côte de 150 px
     s'atteignent mal, et se confondent. */
  .fle-barre-boutons > .fle-btn:not(.fle-btn--petit) { flex: 1 1 100%; }
  .fle-niveaux { display: grid; grid-template-columns: repeat(3, 1fr); }
  .fle-niveaux .fle-btn { width: 100%; min-width: 0; padding-inline: 8px; }
}

/* --- Téléphone couché, écran bas ---------------------------------------
   En paysage, la barre collante mangeait un tiers de la hauteur utile.
   Elle se décolle : on préfère devoir remonter que ne rien voir. */
@media (max-height: 500px) and (orientation: landscape) {
  .fle-bar { position: static; }
  .fle-corps { min-height: 0; }
}

/* --- Écran large (≥ 1200 px) -------------------------------------------
   On n'élargit pas les blocs de lecture indéfiniment : au-delà d'environ
   soixante-dix signes, l'œil perd le début de la ligne suivante. La place
   gagnée va aux colonnes, pas à la longueur de ligne. */
@media (min-width: 1200px) {
  .fle-corps { padding: 26px 30px; }
  .fle-app .fle-texte-support,
  .fle-app .fle-consigne,
  .fle-app .fle-simple p,
  .fle-app .fle-memo p { max-width: 72ch; }
}

/* --- Pointeur grossier : le doigt, pas la souris ------------------------
   Les recommandations d'accessibilité fixent la cible tactile à 44 px.
   Cette règle ne s'applique qu'aux appareils réellement tactiles : sur un
   ordinateur, des boutons de 44 px de haut donneraient une interface molle.
   ---------------------------------------------------------------------- */
@media (pointer: coarse) {
  .fle-btn { min-height: 46px; padding-inline: 19px; }
  .fle-btn--petit { min-height: 40px; padding: 9px 15px; font-size: 13.5px; }
  .fle-btn--grand { min-height: 52px; }
  .fle-app .fle-etape-puce { width: 44px; height: 44px; font-size: 15.5px; }
  .fle-champ, .fle-app select.fle-champ { min-height: 46px; }
  .fle-bar__sortie { min-height: 40px; padding: 8px 14px; display: inline-flex; align-items: center; }
  .fle-choix { padding: 12px 13px; }
  .fle-retour { min-height: 44px; padding-bottom: 0; }
  .fle-app .fle-qcm-choix .fle-btn { min-height: 46px; }
}

/* =========================================================================
   ACCESSIBILITÉ

   L'apprenant de FLE cumule souvent deux difficultés que l'interface peut
   aggraver ou soulager : il lit une langue qu'il ne maîtrise pas, et il la
   lit parfois sur un écran fatigué, en plein soleil, sans lunettes. Ce qui
   suit n'est pas une couche de conformité posée à la fin - c'est la même
   exigence que le reste, écrite au même endroit pour qu'on la retrouve.
   ====================================================================== */

/* --- Mouvement réduit ---------------------------------------------------
   Un tampon qui rebondit amuse la première fois et donne la nausée à qui
   souffre de troubles vestibulaires. Quand le système le demande, tout
   s'arrête - mais rien ne disparaît : les états restent lisibles. */
@media (prefers-reduced-motion: reduce) {
  .fle-app *, .fle-app *::before, .fle-app *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  .fle-tuile:hover, .fle-btn:active:not([disabled]) { transform: none; }
}

/* --- Contraste renforcé -------------------------------------------------
   Le système signale que les lavis et les ombres ne suffisent pas. On
   remplace la nuance par le trait : filets pleins, fonds blancs, texte
   d'encre. Le dessin y perd, la lecture y gagne, et c'est le bon échange. */
@media (prefers-contrast: more) {
  .fle-app {
    --line: #6E7B7A;
    --muted: #3D4A49;
    --lavis: var(--white);
    --lavis-fort: var(--white);
    --lavis-gris: var(--white);
  }
  .fle-carte, .fle-tuile, .fle-eleve, .fle-question, .fle-msg { border-width: 2px; }
  .fle-app .fle-faire, .fle-app .fle-question-vive, .fle-app .fle-tache,
  .fle-app .fle-texte-support, .fle-alerte { border-width: 2px; }
  .fle-app .fle-faire { border-left-width: 6px; }
  .fle-btn--fantome { --btn-bord: var(--primary); }
  .fle-app .fle-formule { background: var(--white); border: 1px solid var(--line); }
  .fle-carte, .fle-tuile { box-shadow: none; }
}

/* --- Couleurs imposées par le système (mode contrasté de Windows) -------
   Les navigateurs y remplacent toutes les couleurs. Les blocs dont la
   frontière n'était portée que par un fond deviendraient invisibles : on
   leur rend un filet, que le système, lui, conserve toujours. */
@media (forced-colors: active) {
  .fle-btn { border-width: 2px; }
  .fle-app .fle-faire, .fle-app .fle-question-vive, .fle-app .fle-tache,
  .fle-app .fle-simple, .fle-app .fle-gloses, .fle-app .fle-amorce,
  .fle-app .fle-formule, .fle-app .fle-spirale, .fle-app .fle-mot,
  .fle-alerte, .fle-badge, .fle-app .fle-marque { border: 1px solid; }
  .fle-app .fle-etape-puce--vive { outline: 2px solid; outline-offset: 1px; }
  .fle-seyes { border-bottom: 2px solid; }
}

/* --- Confort de lecture -------------------------------------------------
   Un code de salle ou une adresse d'image trop longue faisait déborder sa
   carte, et la page entière partait de travers. */
.fle-app { overflow-wrap: break-word; }
.fle-app .fle-champ, .fle-app .fle-extrait, .fle-app .fle-msg__texte { overflow-wrap: anywhere; }

/* Le lecteur d'écran a besoin d'un texte que l'œil n'a pas à voir : cette
   classe le lui réserve. Elle reste focalisable, contrairement à
   `display: none`, qui la retirerait aussi de la navigation au clavier. */
.fle-app .fle-invisible {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap; margin: -1px; padding: 0; border: 0;
}
.fle-app .fle-invisible:focus, .fle-app .fle-invisible:focus-within {
  position: static; width: auto; height: auto; clip-path: none;
  margin: 0; padding: 6px 10px; white-space: normal;
  background: var(--ink); color: var(--white); border-radius: var(--radius-xs);
}

/* --- Impression ---------------------------------------------------------
   Le mémo et la fiche de séance s'impriment : on retire la couleur de fond,
   qui vide les cartouches, et les commandes, qui ne servent à rien sur du
   papier. On garde les filets, qui portent la structure. */
@media print {
  .fle-app {
    border: none; box-shadow: none; background: #fff;
    font-size: 11.5pt; color: #000;
  }
  .fle-bar, .fle-outils, .fle-barre-boutons, .fle-retour, .fle-annonce,
  .fle-app .fle-etapes-rail, .fle-seyes { display: none !important; }
  .fle-carte, .fle-app .fle-tache, .fle-app .fle-faire, .fle-app .fle-memo {
    box-shadow: none; break-inside: avoid; background: #fff;
  }
  .fle-app .fle-tache::before { display: none; }
  .fle-app a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 9pt; color: #444; }
}

/* =========================================================================
   Atelier « DELF B2 - Production écrite »

   Deux principes de dessin, tenus partout dans cet atelier.

   Le premier : le SUJET se lit comme un sujet d'examen, pas comme une
   notification. Il occupe sa propre carte, en romaine, avec de l'air - un
   candidat qui survole la consigne perd des points au premier critère de la
   grille, et une mise en page pressée encourage à survoler.

   Le second : le STATUT d'un devoir se voit avant qu'on ait lu son titre.
   Un filet de couleur à gauche, une pastille, et l'affaire est réglée à un
   mètre de l'écran. Comme ailleurs dans l'application, la couleur ne porte
   jamais seule l'information : le mot est écrit à côté.
   ====================================================================== */

/* --- Le sujet ---------------------------------------------------------- */
.fle-app .fle-delf-sujet__titre {
  font-family: var(--texte); font-size: 20px; font-weight: 700;
  margin-top: 8px; letter-spacing: -.01em;
}
.fle-app .fle-delf-sujet__texte {
  font-family: var(--texte); font-size: var(--t-lire); line-height: 1.66;
  margin-top: 10px; white-space: pre-wrap; max-width: 68ch;
}
.fle-app .fle-delf-contraintes {
  display: flex; flex-wrap: wrap; gap: 8px 18px; margin-top: 14px;
  padding-top: 12px; border-top: 1px solid var(--line);
  font-size: 13.5px; color: var(--muted);
}
.fle-app .fle-delf-contraintes strong { color: var(--ink); }
.fle-app .fle-delf-strict {
  color: var(--alerte); font-weight: 600;
}

/* --- La liste des devoirs de l'apprenant ------------------------------- */
.fle-app .fle-delf-liste {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 280px), 1fr));
  gap: 14px; margin-top: 14px;
}
.fle-app .fle-delf-carte {
  display: flex; flex-direction: column; gap: 8px;
  background: var(--white); border: 1px solid var(--line);
  border-left: 5px solid var(--gris);
  border-radius: var(--radius); padding: 15px; box-shadow: var(--ombre-1);
}
.fle-app .fle-delf-carte__haut { display: flex; flex-wrap: wrap; gap: 6px; }
.fle-app .fle-delf-carte__titre { font-size: 16.5px; line-height: 1.35; letter-spacing: -.008em; }
/* À faire : le devoir attend, et cela se voit. En cours : la sarcelle vive.
   Remis : l'ambre de l'attente. Corrigé : le vert du verdict rendu. */
.fle-app .fle-delf-carte--neuf    { border-left-color: var(--accent); background: var(--lavis); }
.fle-app .fle-delf-carte--encours { border-left-color: var(--primary); }
.fle-app .fle-delf-carte--remis   { border-left-color: var(--alerte); }
.fle-app .fle-delf-carte--corrige { border-left-color: var(--succes); }

/* --- La barre de composition : intitulé à gauche, chronomètre à droite -- */
.fle-app .fle-delf-barre { align-items: center; gap: 10px; }

/* --- La note rendue ---------------------------------------------------- */
.fle-app .fle-delf-note__chiffre {
  display: inline-flex; align-items: baseline; gap: 4px;
  padding: 8px 16px; border-radius: var(--radius);
  background: var(--lavis-fort); border: 1px solid color-mix(in srgb, var(--accent) 30%, var(--white));
}
.fle-app .fle-delf-note__chiffre strong {
  font-size: 34px; line-height: 1; color: var(--primary); font-variant-numeric: tabular-nums;
}
.fle-app .fle-delf-note__chiffre span { font-size: 15px; color: var(--muted); }

.fle-app .fle-delf-points li {
  position: relative; padding-left: 20px; margin-top: 5px;
  font-family: var(--texte); font-size: 15.5px; line-height: 1.5;
}
.fle-app .fle-delf-points li::before {
  content: "\2192"; position: absolute; left: 0; color: var(--alerte); font-weight: 700;
}
.fle-app .fle-delf-points--ok li::before { content: "\2713"; color: var(--succes); }
.fle-app .fle-delf-commentaire {
  font-family: var(--texte); font-size: var(--t-lire); line-height: 1.62;
  white-space: pre-wrap; max-width: 68ch;
}

/* --- Côté formateur : aperçu, grille, copie ---------------------------- */
.fle-app .fle-delf-apercu:not(:empty) {
  margin-top: 14px; padding: 15px 17px; border-radius: var(--radius);
  background: var(--paper); border: 1px solid var(--line);
}
.fle-app .fle-delf-total {
  display: inline-flex; align-items: baseline; gap: 3px;
  padding: 5px 13px; border-radius: 999px;
  background: var(--primary); color: var(--white);
}
.fle-app .fle-delf-total strong { font-size: 21px; font-variant-numeric: tabular-nums; }
.fle-app .fle-delf-total span { font-size: 13px; opacity: .85; }

.fle-app .fle-delf-grille { display: grid; gap: 12px; }
.fle-app .fle-delf-critere {
  padding: 13px 15px; border-radius: var(--radius-s);
  background: var(--white); border: 1px solid var(--line);
}
.fle-app .fle-delf-critere .fle-soustitre { max-width: 62ch; }
/* La note effective : celle que la règle retient, une fois les plafonds du
   hors-sujet et la sanction de longueur appliqués. Quand elle diffère du
   clic du correcteur, elle le dit - sans quoi le formateur croirait à un
   bug là où il y a une règle. */
.fle-app .fle-delf-effectif {
  font-family: var(--data); font-size: 14px; font-weight: 700; color: var(--primary);
  padding: 2px 9px; border-radius: 999px; background: var(--lavis-fort);
}
.fle-app .fle-delf-effectif--force {
  color: var(--danger); background: color-mix(in srgb, var(--danger) 9%, var(--white));
}
.fle-app .fle-delf-desc__titre {
  margin-top: 10px; font-size: 12.5px; color: var(--muted);
}
.fle-app .fle-delf-desc { display: grid; gap: 3px; margin-top: 6px; }
.fle-app .fle-delf-desc__ligne {
  align-items: flex-start; gap: 8px; padding: 5px 7px; border-radius: var(--radius-xs);
  font-size: 14px; line-height: 1.45; cursor: pointer;
}
.fle-app .fle-delf-desc__ligne:hover { background: var(--lavis); }
.fle-app .fle-delf-desc__ligne input { margin-top: 2px; flex: 0 0 auto; width: 17px; height: 17px; accent-color: var(--accent); }

/* La copie du candidat : justifiée, aérée, avec les mêmes réglages qu'une
   feuille d'examen. On la lit, on ne la parcourt pas. */
.fle-app .fle-delf-copie {
  font-family: var(--texte); font-size: 16px; line-height: 1.8;
  white-space: pre-wrap; text-align: justify; hyphens: auto;
  background: var(--white); border: 1px solid var(--line);
  border-radius: var(--radius-s); padding: 16px 18px;
  max-height: 460px; overflow: auto;
}
.fle-app .fle-delf-rappel {
  font-family: var(--texte); font-size: 14.5px; line-height: 1.55; color: var(--muted);
  white-space: pre-wrap; padding: 11px 13px; border-radius: var(--radius-xs);
  background: var(--paper); border-left: 3px solid var(--line);
  max-height: 200px; overflow: auto;
}
.fle-app .fle-delf-correction { border-color: color-mix(in srgb, var(--accent) 30%, var(--line)); }

@media (max-width: 640px) {
  .fle-app .fle-delf-note__chiffre strong { font-size: 28px; }
  .fle-app .fle-delf-copie { max-height: 320px; padding: 13px; }
  .fle-app .fle-delf-sujet__titre { font-size: 18px; }
  /* Sur téléphone, le chronomètre reste visible pendant qu'on écrit :
     c'est la seule information dont on a besoin en permanence. */
  .fle-app .fle-delf-barre { position: sticky; top: 56px; z-index: 5;
    background: var(--white); padding: 6px 0; }
}

/* La grille consultée par l'apprenant avant d'écrire : mêmes critères que
   ceux du correcteur, présentés comme une liste de choses à faire et non
   comme un barème. Un candidat qui relit sa copie critère par critère avant
   de l'envoyer gagne plus de points que par n'importe quelle révision. */
.fle-app .fle-delf-grille-lue { display: grid; gap: 10px; margin-top: 12px; }
.fle-app .fle-delf-grille-lue .fle-delf-critere { background: var(--paper); }
.fle-app .fle-delf-grille-lue strong { font-size: 15.5px; }

/* L'avertissement de feuille périmée. Il ne s'affiche que si le navigateur
   sert une feuille plus ancienne que celle qu'attend le script - c'est-à-dire
   presque jamais, et exactement quand il le faut. */
.fle-app .fle-technique__alerte {
  color: var(--danger); font-weight: 600;
}

/* =========================================================================
   Atelier « DELF B2 - Production orale »
   ====================================================================== */

/* Le document declencheur se lit comme un extrait de presse : romaine,
   justifie, avec un filet qui le detache de la consigne. C'est un objet
   qu'on cite, pas un texte de l'application. */
.fle-app .fle-oral-document {
  margin-top: 12px; padding: 15px 17px;
  font-family: var(--texte); font-size: var(--t-lire); line-height: 1.72;
  text-align: justify; hyphens: auto;
  background: var(--paper); border-left: 4px solid var(--primary);
  border-radius: 0 var(--radius-s) var(--radius-s) 0;
  max-width: 66ch;
}

/* Le fil des trois temps de l'epreuve. */
.fle-app .fle-oral-fil {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px;
}
.fle-app .fle-oral-fil__etape {
  display: flex; flex-direction: column; gap: 2px;
  padding: 9px 11px; border-radius: var(--radius-xs);
  background: var(--white); border: 1.5px solid var(--line);
  font-size: 13.5px;
}
.fle-app .fle-oral-fil__etape--faite { background: var(--lavis); border-color: var(--accent); }
.fle-app .fle-oral-fil__etape--vive {
  background: var(--lavis-fort); border-color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent);
}
.fle-app .fle-oral-fil__etape strong { font-size: 14.5px; color: var(--primary); }

/* La duree conforme est le seul endroit de l'application ou le vert dit
   autre chose qu'un verdict : ici il dit « vous etes dans les clous », et
   c'est l'information dont l'apprenant a besoin en parlant. */
.fle-app .fle-chrono--ok {
  background: color-mix(in srgb, var(--succes) 12%, var(--white));
  color: var(--succes);
  border: 1px solid color-mix(in srgb, var(--succes) 35%, var(--white));
}

/* Le materiel de conduite du formateur. Il est lu en diagonale pendant que
   l'apprenant parle : gros interlignes, listes courtes, rien de dense. */
.fle-app .fle-oral-pistes li {
  position: relative; padding-left: 20px; margin-top: 6px;
  font-size: 14.5px; line-height: 1.5;
}
.fle-app .fle-oral-pistes li::before {
  content: ""; position: absolute; left: 3px; top: .6em;
  width: 7px; height: 7px; border-radius: 50%; background: var(--accent);
}
.fle-app .fle-oral-relances {
  counter-reset: rel; margin-top: 4px;
}
.fle-app .fle-oral-relances li {
  counter-increment: rel; position: relative; padding: 8px 10px 8px 38px;
  margin-top: 6px; border-radius: var(--radius-xs);
  background: var(--lavis); border: 1px solid color-mix(in srgb, var(--accent) 22%, var(--white));
  font-family: var(--texte); font-size: 15.5px; line-height: 1.45;
}
.fle-app .fle-oral-relances li::before {
  content: counter(rel); position: absolute; left: 10px; top: 9px;
  width: 20px; height: 20px; border-radius: 50%; display: grid; place-content: center;
  font-family: var(--ui); font-size: 11.5px; font-weight: 700;
  color: var(--white); background: var(--accent-plein);
}

/* Reponses probables et relances, dans le cours de conversation. */
.fle-app .fle-relances__registres {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 190px), 1fr)); gap: 10px;
}
.fle-app .fle-relances__registre {
  padding: 10px 12px; border-radius: var(--radius-xs);
  background: var(--white); border: 1px solid var(--line); border-top: 3px solid var(--gris);
  font-size: 14px; line-height: 1.5;
}
.fle-app .fle-relances__registre--court   { border-top-color: var(--alerte); }
.fle-app .fle-relances__registre--attendu { border-top-color: var(--accent); }
.fle-app .fle-relances__registre--riche   { border-top-color: var(--succes); }
.fle-app .fle-relances__groupe {
  margin-top: 12px; padding: 11px 13px; border-radius: var(--radius-xs);
  background: var(--paper); border: 1px solid var(--line);
}
.fle-app .fle-relances__phrases li {
  position: relative; padding-left: 18px; margin-top: 5px;
  font-family: var(--texte); font-size: 15.5px; line-height: 1.45;
}
.fle-app .fle-relances__phrases li::before {
  content: "\201C"; position: absolute; left: 0; top: .1em;
  color: var(--accent); font-size: 18px; font-weight: 700;
}

@media (max-width: 640px) {
  .fle-app .fle-oral-fil { grid-template-columns: 1fr; }
  .fle-app .fle-oral-document { padding: 13px 14px; }
}

/* L'attente entre la préparation et l'épreuve. Le document a disparu ;
   l'écran ne doit pas donner l'impression d'un bogue, mais d'un moment
   voulu. D'où le cartouche plein, la phrase brève, et le point qui bat -
   seul signe que quelque chose va se passer. */
.fle-app .fle-oral-attente {
  border-color: color-mix(in srgb, var(--alerte) 32%, var(--line));
  background: color-mix(in srgb, var(--alerte) 5%, var(--white));
}
.fle-app .fle-oral-attente__mot {
  font-family: var(--texte); font-size: 19px; font-weight: 700;
  margin: 6px 0 10px; color: var(--ink);
}
.fle-app .fle-oral-attente p { font-size: 15px; line-height: 1.6; max-width: 56ch; }
.fle-app .fle-oral-attente__pulse {
  width: 11px; height: 11px; border-radius: 50%; margin-top: 16px;
  background: var(--alerte); animation: fle-pouls 1.8s ease-in-out infinite;
}
@keyframes fle-pouls { 0%, 100% { opacity: .25; } 50% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .fle-app .fle-oral-attente__pulse { animation: none; opacity: 1; }
}

/* Le pupitre du formateur : c'est d'ici que part l'épreuve, et il doit se
   trouver sans être cherché, au milieu d'un panneau chargé. */
.fle-app .fle-oral-pupitre {
  margin-top: 12px; padding: 13px 15px; border-radius: var(--radius-s);
  background: var(--lavis-fort);
  border: 1px solid color-mix(in srgb, var(--accent) 32%, var(--white));
  border-left: 5px solid var(--accent);
}
.fle-app .fle-oral-pupitre .fle-barre-boutons { margin-top: 10px; }

/* Les séries de parcours. Trente cases à cocher d'affilée ne se lisent pas :
   il faut que l'œil voie d'abord trois blocs, et seulement ensuite leur
   contenu. D'où le cartouche, le titre en gras et le filet de gauche. */
.fle-app .fle-parcours-serie {
  margin-top: 14px; padding: 13px 15px; border-radius: var(--radius-s);
  background: var(--white); border: 1px solid var(--line);
  border-left: 4px solid var(--accent);
}
.fle-app .fle-parcours-serie:first-child { margin-top: 8px; }
.fle-app .fle-parcours-serie .fle-soustitre { margin-top: 4px; max-width: 70ch; }
.fle-app .fle-parcours-serie label { cursor: pointer; padding: 3px 4px; border-radius: var(--radius-xs); }
.fle-app .fle-parcours-serie label:hover { background: var(--lavis); }

/* =========================================================================
   NAVIGATION

   Reprise du dispositif du Système de design de l'État, tel qu'on le voit
   sur le site de l'AEFE : une barre de rubriques permanente, un panneau qui
   se déploie dessous, une recherche, un fil d'Ariane, des réglages
   d'affichage. Le vocabulaire visuel reste celui de l'application - la
   sarcelle, le gris, le filet de cahier.

   Un seul panneau sert aux trois usages. Trois panneaux auraient demandé
   trois gestes de fermeture et trois façons de se tromper.
   ====================================================================== */

/* Le lien d'évitement : premier élément focalisable, invisible tant qu'on
   ne l'atteint pas au clavier. */
.fle-app .fle-evitement {
  position: absolute; left: 8px; top: -60px; z-index: 60;
  padding: 10px 16px; border-radius: 0 0 var(--radius-s) var(--radius-s);
  background: var(--primary); color: var(--white);
  font-weight: 650; text-decoration: none;
  transition: top .14s ease;
}
.fle-app .fle-evitement:focus { top: 0; }
.fle-app .fle-corps:focus { outline: none; }

.fle-app .fle-nav {
  position: relative; z-index: 25;
  background: var(--white);
  border-bottom: 1px solid var(--line);
}
.fle-app .fle-nav[hidden] { display: none; }
.fle-app .fle-nav__barre {
  display: flex; align-items: stretch; gap: 4px;
  padding: 0 clamp(11px, 1.8vw, 18px);
  flex-wrap: wrap;
}
.fle-app .fle-nav__menu { display: flex; align-items: stretch; gap: 2px; flex-wrap: wrap; }

/* Les rubriques. Le repère de la rubrique courante est un filet épais sous
   le libellé - le même geste que sur les sites de l'État, et le seul qui se
   voie encore en noir et blanc. */
.fle-app .fle-nav__rubrique,
.fle-app .fle-nav__outil,
.fle-app .fle-nav__accueil {
  border: 0; background: transparent; color: var(--ink);
  font-family: var(--ui); font-size: 15px; font-weight: 600;
  padding: 14px 13px 12px; cursor: pointer;
  border-bottom: 3px solid transparent;
  transition: background-color .15s ease, color .15s ease, border-color .15s ease;
}
.fle-app .fle-nav__accueil { color: var(--primary); font-weight: 680; }
.fle-app .fle-nav__outil { color: var(--muted); font-weight: 550; }
.fle-app .fle-nav__rubrique:hover,
.fle-app .fle-nav__outil:hover,
.fle-app .fle-nav__accueil:hover { background: var(--lavis); color: var(--primary); }
.fle-app .fle-nav__rubrique[aria-expanded="true"],
.fle-app .fle-nav__outil[aria-expanded="true"] {
  background: var(--lavis-fort); color: var(--primary); border-bottom-color: var(--accent);
}
.fle-app .fle-nav__rubrique--actif { border-bottom-color: var(--accent); color: var(--primary); }
.fle-app .fle-nav__separateur {
  width: 1px; margin: 10px 6px; background: var(--line); align-self: stretch;
}
.fle-app .fle-nav__burger { display: none; }

/* Le panneau déployé. */
.fle-app .fle-nav__panneau {
  padding: 16px clamp(11px, 1.8vw, 18px) 20px;
  background: var(--paper);
  border-top: 1px solid var(--line);
  box-shadow: inset 0 6px 10px -10px rgba(15,60,58,.45);
}
.fle-app .fle-nav__panneau[hidden] { display: none; }
.fle-app .fle-nav__panneau-titre {
  font-size: 13px; font-weight: 650; color: var(--primary); margin-bottom: 10px;
}
.fle-app .fle-nav__liens {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 250px), 1fr)); gap: 8px;
}
.fle-app .fle-nav__lien {
  display: flex; flex-direction: column; gap: 3px; text-align: left;
  padding: 11px 13px; border-radius: var(--radius-xs);
  background: var(--white); border: 1px solid var(--line); border-left: 3px solid transparent;
  cursor: pointer;
  transition: border-color .15s ease, background-color .15s ease, transform .1s ease;
}
.fle-app .fle-nav__lien:hover { border-left-color: var(--accent); background: var(--lavis); transform: translateX(2px); }
.fle-app .fle-nav__lien strong { font-size: 15px; color: var(--ink); }
.fle-app .fle-nav__lien span { font-size: 13px; color: var(--muted); line-height: 1.45; }
.fle-app .fle-nav__lien--actif { border-left-color: var(--primary); background: var(--lavis-fort); }

.fle-app .fle-reglages { display: grid; gap: 14px; margin-top: 12px; }

/* --- Le fil d'Ariane --------------------------------------------------- */
.fle-app .fle-fil { margin-bottom: 10px; }
.fle-app .fle-fil ol { display: flex; flex-wrap: wrap; align-items: center; gap: 2px; }
.fle-app .fle-fil li { display: flex; align-items: center; font-size: 13.5px; }
.fle-app .fle-fil li + li::before {
  content: "›"; margin: 0 7px; color: var(--gris); font-size: 15px;
}
.fle-app .fle-fil__lien {
  border: 0; background: transparent; padding: 2px 0; cursor: pointer;
  color: var(--primary); font-family: var(--ui); font-size: 13.5px;
  text-decoration: underline; text-underline-offset: 2px;
}
.fle-app .fle-fil__lien:hover { text-decoration-thickness: 2px; }
.fle-app .fle-fil__ici { color: var(--muted); }

/* --- Les accès directs ------------------------------------------------- */
.fle-app .fle-acces {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 200px), 1fr)); gap: 10px;
}
.fle-app .fle-acces__carte {
  display: flex; flex-direction: column; gap: 3px; text-align: left;
  padding: 13px 15px; border-radius: var(--radius-s);
  background: var(--lavis); border: 1px solid color-mix(in srgb, var(--accent) 26%, var(--white));
  cursor: pointer; transition: background-color .15s ease, transform .1s ease;
}
.fle-app .fle-acces__carte:hover { background: var(--lavis-fort); transform: translateY(-2px); }
.fle-app .fle-acces__note { font-size: 12px; font-weight: 650; color: var(--primary); }
.fle-app .fle-acces__carte strong { font-size: 15.5px; }
.fle-app .fle-acces__fam { font-size: 12.5px; color: var(--muted); }

/* --- Retour en haut ---------------------------------------------------- */
.fle-app .fle-haut { margin-top: 22px; text-align: right; }
.fle-app .fle-haut__lien {
  border: 0; background: transparent; cursor: pointer;
  color: var(--primary); font-family: var(--ui); font-size: 13.5px; font-weight: 600;
  padding: 6px 2px; text-decoration: underline; text-underline-offset: 3px;
}

/* --- Téléphone : le menu devient un tiroir ----------------------------- */
@media (max-width: 780px) {
  .fle-app .fle-nav__barre { padding: 0 12px; align-items: center; }
  .fle-app .fle-nav__burger {
    display: inline-flex; align-items: center; gap: 8px;
    margin-left: auto; padding: 11px 14px;
    border: 1.5px solid var(--line); border-radius: var(--radius-xs);
    background: var(--white); color: var(--primary);
    font-family: var(--ui); font-size: 14.5px; font-weight: 650; cursor: pointer;
  }
  .fle-app .fle-nav__burger::before {
    content: ""; width: 16px; height: 12px; flex: 0 0 auto;
    background: linear-gradient(var(--primary) 0 2px, transparent 2px 5px,
                                var(--primary) 5px 7px, transparent 7px 10px,
                                var(--primary) 10px 12px);
  }
  .fle-app .fle-nav__burger[aria-expanded="true"] { background: var(--lavis-fort); }
  .fle-app .fle-nav__menu {
    display: none; flex-direction: column; align-items: stretch;
    flex-basis: 100%; padding-bottom: 8px;
  }
  .fle-app .fle-nav__menu--ouvert { display: flex; }
  .fle-app .fle-nav__rubrique,
  .fle-app .fle-nav__outil {
    text-align: left; padding: 13px 10px;
    border-bottom: 1px solid var(--line); border-left: 3px solid transparent;
  }
  .fle-app .fle-nav__rubrique--actif,
  .fle-app .fle-nav__rubrique[aria-expanded="true"],
  .fle-app .fle-nav__outil[aria-expanded="true"] {
    border-bottom-color: var(--line); border-left-color: var(--accent);
  }
  .fle-app .fle-nav__separateur { display: none; }
}

/* =========================================================================
   RÉGLAGES D'AFFICHAGE

   TAILLE DU TEXTE. On n'agrandit pas toute l'interface, seulement ce qu'on
   lit vraiment : le document d'examen, la consigne, le texte support, la
   copie. Gonfler aussi les boutons et les étiquettes ferait déborder la
   mise en page sans rien apporter à la lecture.
   ====================================================================== */
.fle-app[data-fle-taille="1"] { --t-lire: clamp(17.5px, .42vw + 16.2px, 19.5px); }
.fle-app[data-fle-taille="2"] { --t-lire: clamp(19px, .5vw + 17.5px, 21.5px); }
.fle-app[data-fle-taille="1"] .fle-texte-support,
.fle-app[data-fle-taille="2"] .fle-texte-support,
.fle-app[data-fle-taille="1"] .fle-delf-copie,
.fle-app[data-fle-taille="2"] .fle-delf-copie,
.fle-app[data-fle-taille="1"] .fle-production,
.fle-app[data-fle-taille="2"] .fle-production,
.fle-app[data-fle-taille="1"] .fle-consigne,
.fle-app[data-fle-taille="2"] .fle-consigne,
.fle-app[data-fle-taille="1"] .fle-formule,
.fle-app[data-fle-taille="2"] .fle-formule,
.fle-app[data-fle-taille="1"] .fle-relances__phrases li,
.fle-app[data-fle-taille="2"] .fle-relances__phrases li,
.fle-app[data-fle-taille="1"] .fle-oral-relances li,
.fle-app[data-fle-taille="2"] .fle-oral-relances li,
.fle-app[data-fle-taille="1"] .fle-liste li,
.fle-app[data-fle-taille="2"] .fle-liste li {
  font-size: var(--t-lire); line-height: 1.7;
}

/* =========================================================================
   THÈME SOMBRE

   Les jetons se redéfinissent, et tout le reste suit : les lavis, les
   bordures et les ombres sont calculés à partir d'eux par color-mix, donc
   ils basculent sans qu'on y touche.

   Deux ajustements ne se déduisent pas et méritent d'être dits. La sarcelle
   s'éclaircit - #1B8A8A sur un fond sombre tombe à 2,5:1, illisible - et le
   texte des boutons pleins passe du blanc à l'encre : blanc sur sarcelle
   claire ne ferait que 3,4:1, alors que l'encre y atteint 5,4:1.

   Conséquence à connaître : en thème sombre, la palette réglée dans
   l'administration n'est pas appliquée. Les couleurs y sont calculées pour
   le contraste, et une palette personnalisée les casserait sans prévenir.
   ====================================================================== */
.fle-app[data-fle-theme="sombre"] { color-scheme: dark; }
@media (prefers-color-scheme: dark) {
  .fle-app[data-fle-theme="systeme"] { color-scheme: dark; }
}

.fle-app[data-fle-theme="sombre"],
.fle-app[data-fle-theme="sombre"] .fle-bar,
.fle-app[data-fle-theme="sombre"] .fle-nav {
  --ink:     #E7EFEE;
  --primary: #5FC9C4;
  --accent:  #2FA8A6;
  --paper:   #0F1817;
  --line:    #2E3D3C;
  --white:   #182322;
  --muted:   #9CB0AE;
  --gris:    #7C8A89;
  --succes:  #5FD3A8;
  --alerte:  #E8B053;
  --danger:  #FF8A80;
  --ombre-1: 0 1px 2px rgba(0,0,0,.4);
  --ombre-2: 0 1px 2px rgba(0,0,0,.35), 0 10px 24px -14px rgba(0,0,0,.7);
  --ombre-3: 0 2px 5px rgba(0,0,0,.4), 0 22px 44px -20px rgba(0,0,0,.8);
}
.fle-app[data-fle-theme="sombre"] .fle-btn { --btn-texte: #0E1716; }
.fle-app[data-fle-theme="sombre"] .fle-btn--fantome { --btn-texte: var(--primary); }
.fle-app[data-fle-theme="sombre"] .fle-btn--sourdine { --btn-texte: var(--muted); }
.fle-app[data-fle-theme="sombre"] .fle-btn[disabled] { --btn-texte: var(--muted); }
.fle-app[data-fle-theme="sombre"] .fle-evitement,
.fle-app[data-fle-theme="sombre"] .fle-delf-total { color: #0E1716; }
.fle-app[data-fle-theme="sombre"] .fle-oral-relances li::before,
.fle-app[data-fle-theme="sombre"] .fle-etape-puce--vive { color: #0E1716; }
.fle-app[data-fle-theme="sombre"] .fle-seyes {
  background:
    repeating-linear-gradient(90deg, rgba(0,0,0,.35) 0 1px, transparent 1px 17px),
    linear-gradient(180deg, var(--accent), var(--primary));
}

@media (prefers-color-scheme: dark) {
  .fle-app[data-fle-theme="systeme"],
  .fle-app[data-fle-theme="systeme"] .fle-bar,
  .fle-app[data-fle-theme="systeme"] .fle-nav {
    --ink:     #E7EFEE;
    --primary: #5FC9C4;
    --accent:  #2FA8A6;
    --paper:   #0F1817;
    --line:    #2E3D3C;
    --white:   #182322;
    --muted:   #9CB0AE;
    --gris:    #7C8A89;
    --succes:  #5FD3A8;
    --alerte:  #E8B053;
    --danger:  #FF8A80;
    --ombre-1: 0 1px 2px rgba(0,0,0,.4);
    --ombre-2: 0 1px 2px rgba(0,0,0,.35), 0 10px 24px -14px rgba(0,0,0,.7);
    --ombre-3: 0 2px 5px rgba(0,0,0,.4), 0 22px 44px -20px rgba(0,0,0,.8);
  }
  .fle-app[data-fle-theme="systeme"] .fle-btn { --btn-texte: #0E1716; }
  .fle-app[data-fle-theme="systeme"] .fle-btn--fantome { --btn-texte: var(--primary); }
  .fle-app[data-fle-theme="systeme"] .fle-btn--sourdine { --btn-texte: var(--muted); }
  .fle-app[data-fle-theme="systeme"] .fle-btn[disabled] { --btn-texte: var(--muted); }
  .fle-app[data-fle-theme="systeme"] .fle-evitement,
  .fle-app[data-fle-theme="systeme"] .fle-delf-total { color: #0E1716; }
  .fle-app[data-fle-theme="systeme"] .fle-oral-relances li::before,
  .fle-app[data-fle-theme="systeme"] .fle-etape-puce--vive { color: #0E1716; }
  .fle-app[data-fle-theme="systeme"] .fle-seyes {
    background:
      repeating-linear-gradient(90deg, rgba(0,0,0,.35) 0 1px, transparent 1px 17px),
      linear-gradient(180deg, var(--accent), var(--primary));
  }
}

/* En thème clair, survoler un bouton l'assombrit. En thème sombre, cela
   rapprocherait l'aplat de la couleur du libellé - 4,4:1, sous le seuil. Le
   survol y éclaircit donc au lieu d'assombrir : le geste reste lisible, et
   le contraste remonte au lieu de descendre. */
.fle-app[data-fle-theme="sombre"] .fle-btn:hover:not([disabled]) {
  background: color-mix(in srgb, var(--btn-fond) 84%, #FFFFFF);
  border-color: color-mix(in srgb, var(--btn-bord) 84%, #FFFFFF);
}
@media (prefers-color-scheme: dark) {
  .fle-app[data-fle-theme="systeme"] .fle-btn:hover:not([disabled]) {
    background: color-mix(in srgb, var(--btn-fond) 84%, #FFFFFF);
    border-color: color-mix(in srgb, var(--btn-bord) 84%, #FFFFFF);
  }
}

/* La sentinelle d'amorçage. Elle n'est visible que si le script n'a pas
   construit l'interface : dans tous les autres cas, il a vidé le conteneur
   avant que quiconque ait pu la lire. Elle porte la version du serveur -
   seule information qui permette de trancher entre « cache » et « fichiers
   non déployés ». */
.fle-app .fle-amorcage {
  margin: 16px; padding: 16px 18px; border-radius: var(--radius-s);
  background: color-mix(in srgb, var(--alerte) 7%, var(--white));
  border: 1px solid color-mix(in srgb, var(--alerte) 35%, var(--line));
  border-left: 4px solid var(--alerte);
  font-family: var(--ui); font-size: 15px; line-height: 1.55; color: var(--ink);
}
.fle-app .fle-amorcage p { margin-top: 8px; }
.fle-app .fle-amorcage code,
.fle-app .fle-amorcage kbd {
  font-family: var(--data); font-size: 13px;
  background: var(--white); border: 1px solid var(--line);
  border-radius: 4px; padding: 1px 6px;
}

/* =========================================================================
   MATIÈRE

   Nouvelle direction visuelle, reprise d'une planche de référence : des
   volumes doux posés sur une surface claire quadrillée. Rien n'y est
   tranché au couteau - les angles sont largement arrondis, les frontières
   ne sont plus des filets d'un pixel mais des ombres diffuses, et chaque
   objet a l'air d'avoir une épaisseur.

   Trois principes, tenus partout à partir d'ici.

   1. L'ÉPAISSEUR REMPLACE LE FILET. Une carte ne se détache plus par un
      trait mais par une ombre basse et large, doublée d'un liseré clair sur
      son bord supérieur - la lumière vient du haut, comme dans la planche.
      Le filet ne disparaît pas pour autant : il subsiste, très pâle, parce
      qu'une ombre seule s'évanouit dès qu'on augmente le contraste système
      ou qu'on imprime.

   2. LES RAYONS AUGMENTENT. Dix-huit pixels sur les cartes, douze sur les
      petits blocs, et des pilules pour tout ce qui se presse. C'est ce qui
      donne la sensation de matière souple plutôt que de papier découpé.

   3. LA COULEUR NE BOUGE PAS. La sarcelle et le gris restent ce qu'ils
      étaient, et tous les calculs de contraste faits jusqu'ici tiennent
      encore : on change la matière, pas la palette.
   ====================================================================== */

.fle-app {
  --radius:    18px;
  --radius-s:  14px;
  --radius-xs: 11px;
  --radius-pilule: 999px;

  /* Ombres douces : très larges, très basses, très peu opaques. Une ombre
     serrée fait un objet découpé ; une ombre étalée fait un objet posé. */
  --ombre-1: 0 1px 2px rgba(15,60,58,.05), 0 4px 12px -6px rgba(15,60,58,.14);
  --ombre-2: 0 2px 4px rgba(15,60,58,.05), 0 12px 28px -12px rgba(15,60,58,.22);
  --ombre-3: 0 3px 6px rgba(15,60,58,.06), 0 26px 52px -20px rgba(15,60,58,.30);
  --shadow:  var(--ombre-2);

  /* Le liseré de lumière sur le bord haut, et le filet pâle qui garantit la
     frontière quand l'ombre ne suffit plus. */
  --relief: inset 0 1px 0 rgba(255,255,255,.85);
  --cerne:  color-mix(in srgb, var(--line) 55%, var(--white));
}

/* Le fond quadrillé de la planche : deux trames très pâles, à peine
   perceptibles, qui donnent une profondeur de champ sans attirer l'œil. */
.fle-app .fle-corps {
  background-image:
    repeating-linear-gradient(0deg, color-mix(in srgb, var(--gris) 9%, transparent) 0 1px, transparent 1px 64px),
    repeating-linear-gradient(90deg, color-mix(in srgb, var(--gris) 9%, transparent) 0 1px, transparent 1px 64px);
  background-position: -1px -1px;
}

/* --- Cartes ------------------------------------------------------------ */
.fle-app .fle-carte {
  border-color: var(--cerne);
  box-shadow: var(--ombre-1), var(--relief);
  padding: clamp(15px, 1.8vw, 21px);
}
.fle-app .fle-carte + .fle-carte { margin-top: 16px; }

/* Certains blocs portent une seconde carte derrière eux, légèrement
   décalée - le geste le plus reconnaissable de la planche. C'est purement
   décoratif, donc en pseudo-élément : rien à ajouter dans le balisage, et
   aucun lecteur d'écran ne le rencontre. */
.fle-app .fle-tache,
.fle-app .fle-memo,
.fle-app .fle-oral-document,
.fle-app .fle-texte-support { position: relative; }
.fle-app .fle-tache::after,
.fle-app .fle-memo::after {
  content: ""; position: absolute; z-index: -1;
  inset: 10px -9px -9px 10px;
  border-radius: inherit;
  background: color-mix(in srgb, var(--accent) 12%, var(--white));
  box-shadow: var(--ombre-1);
}

/* --- Boutons : des pilules --------------------------------------------- */
.fle-app .fle-btn {
  border-radius: var(--radius-pilule);
  padding: 10px 20px;
  box-shadow: var(--ombre-1), inset 0 1px 0 rgba(255,255,255,.18);
  border-width: 0;
  font-weight: 620;
}
.fle-app .fle-btn--petit { border-radius: var(--radius-pilule); padding: 7px 15px; }
.fle-app .fle-btn--grand { border-radius: var(--radius-pilule); padding: 12px 24px; }
.fle-app .fle-btn--fantome,
.fle-app .fle-btn--sourdine { border-width: 1.5px; }
.fle-app .fle-btn:hover:not([disabled]) { box-shadow: var(--ombre-2), inset 0 1px 0 rgba(255,255,255,.18); }
.fle-app .fle-btn:active:not([disabled]) { box-shadow: inset 0 3px 7px rgba(6,32,31,.22); }

/* --- Champs : creusés plutôt que cernés -------------------------------- */
.fle-app .fle-champ,
.fle-app select.fle-champ,
.fle-app textarea.fle-champ {
  border-radius: var(--radius-xs);
  border-color: var(--cerne);
  box-shadow: inset 0 2px 5px -3px rgba(15,60,58,.22);
}
.fle-app .fle-champ:focus {
  box-shadow: inset 0 2px 5px -3px rgba(15,60,58,.18),
              0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent);
}

/* =========================================================================
   LES TUILES D'ATELIER

   Quatre exigences, et elles se tiennent : fond sombre, texte blanc, toutes
   de la même taille, et un résumé qui ne déborde jamais.

   La taille identique ne s'obtient pas en espérant que les textes soient de
   longueur voisine - ils ne le sont pas. Elle s'obtient en imposant à la
   grille des rangées de hauteur égale, et au résumé un nombre de lignes
   fixe : au-delà, il est coupé net et le relais est pris par « Voir plus »,
   qui est le libellé de l'action, en pied de tuile.
   ====================================================================== */
.fle-app .fle-grille {
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 255px), 1fr));
  grid-auto-rows: 1fr;
  gap: 16px;
}
.fle-app .fle-tuile {
  display: flex; flex-direction: column; gap: 7px;
  min-height: 186px; height: 100%;
  padding: 18px 19px 16px;
  border: 0; border-radius: var(--radius);
  background: linear-gradient(165deg, #1C4A48 0%, #122625 100%);
  color: #fff;
  box-shadow: var(--ombre-2), inset 0 1px 0 rgba(255,255,255,.12);
  overflow: hidden;
  transition: transform .18s ease, box-shadow .18s ease;
}
/* Un halo sarcelle très pâle en haut à droite : c'est ce qui empêche
   l'aplat sombre de paraître plat, sans ajouter la moindre bordure. */
.fle-app .fle-tuile::before {
  content: ""; position: absolute; inset: auto -30% 40% auto;
  width: 170px; height: 170px; border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--accent) 42%, transparent) 0%, transparent 70%);
  pointer-events: none;
}
.fle-app .fle-tuile { position: relative; }
.fle-app .fle-tuile:hover { transform: translateY(-3px); box-shadow: var(--ombre-3), inset 0 1px 0 rgba(255,255,255,.14); }
.fle-app .fle-tuile:active { transform: translateY(-1px); }

.fle-app .fle-tuile__num {
  font-size: 12px; font-weight: 650; letter-spacing: .01em;
  color: color-mix(in srgb, var(--accent) 72%, #fff);
}
.fle-app .fle-tuile__titre {
  font-size: 17px; font-weight: 680; line-height: 1.25; letter-spacing: -.01em;
  color: #fff;
}
/* Le résumé : trois lignes, jamais plus. `line-clamp` coupe au mot et pose
   les points de suspension ; la hauteur maximale garantit le résultat même
   là où la propriété n'est pas appliquée. */
.fle-app .fle-tuile__texte {
  flex: 1 1 auto;
  font-size: 13.5px; line-height: 1.5; color: #BFD0CF;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3;
  line-clamp: 3; overflow: hidden;
  max-height: calc(1.5em * 3);
}
.fle-app .fle-tuile__plus {
  display: inline-flex; align-items: center; gap: 6px;
  margin-top: auto; padding-top: 10px;
  font-size: 13px; font-weight: 650;
  color: color-mix(in srgb, var(--accent) 65%, #fff);
  border-top: 1px solid rgba(255,255,255,.13);
}
.fle-app .fle-tuile__plus::after {
  content: ""; width: 14px; height: 8px; flex: 0 0 auto;
  background: currentColor;
  clip-path: polygon(0 3px, 9px 3px, 9px 0, 14px 4px, 9px 8px, 9px 5px, 0 5px);
  transition: transform .16s ease;
}
.fle-app .fle-tuile:hover .fle-tuile__plus::after { transform: translateX(3px); }

/* L'atelier ouvert : un anneau sarcelle plein, visible même en niveaux de
   gris parce qu'il change aussi la luminosité du fond. */
.fle-app .fle-tuile--actif {
  background: linear-gradient(165deg, #1E5D5A 0%, #143331 100%);
  box-shadow: var(--ombre-3), inset 0 0 0 2px var(--accent), inset 0 1px 0 rgba(255,255,255,.16);
}

/* --- Les mêmes règles pour les autres pavés cliquables ----------------- */
.fle-app .fle-nav__lien span {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  line-clamp: 2; overflow: hidden;
}
.fle-app .fle-nav__liens { grid-auto-rows: 1fr; }
.fle-app .fle-nav__lien {
  border-radius: var(--radius-s); border-color: var(--cerne);
  box-shadow: var(--ombre-1); min-height: 74px; justify-content: center;
}
.fle-app .fle-acces { grid-auto-rows: 1fr; }
.fle-app .fle-acces__carte {
  border-radius: var(--radius); border-color: transparent;
  box-shadow: var(--ombre-1), var(--relief); min-height: 92px; justify-content: center;
}

/* --- Pastilles, jetons, pilules ---------------------------------------- */
.fle-app .fle-etape-puce {
  border-width: 0;
  box-shadow: var(--ombre-1), inset 0 0 0 1.5px var(--cerne);
}
.fle-app .fle-etape-puce--faite { box-shadow: var(--ombre-1), inset 0 0 0 2px var(--accent); }
.fle-app .fle-etape-puce--vive {
  box-shadow: var(--ombre-2), 0 0 0 4px color-mix(in srgb, var(--accent) 20%, transparent);
}
.fle-app .fle-mot,
.fle-app .fle-badge,
.fle-app .fle-marque {
  border-radius: var(--radius-pilule);
  box-shadow: var(--ombre-1);
}
.fle-app .fle-code { border-radius: var(--radius-pilule); }

/* Le bouton qui sert d'interrupteur prend la forme d'une pilule enfoncée :
   c'est le geste de la planche, et il se lit sans couleur. */
.fle-app .fle-btn[aria-pressed="true"] {
  box-shadow: inset 0 2px 6px rgba(6,32,31,.28);
}

/* --- Navigation et alertes, mêmes matières ----------------------------- */
.fle-app .fle-nav__panneau { box-shadow: inset 0 8px 12px -12px rgba(15,60,58,.4); }
.fle-app .fle-alerte { border-radius: var(--radius-s); }
.fle-app .fle-eleve,
.fle-app .fle-delf-carte,
.fle-app .fle-parcours-serie,
.fle-app .fle-oral-pupitre,
.fle-app .fle-relances__groupe,
.fle-app .fle-delf-critere {
  border-radius: var(--radius-s);
  border-color: var(--cerne);
  box-shadow: var(--ombre-1);
}

/* --- Thème sombre : la matière suit ------------------------------------ */
.fle-app[data-fle-theme="sombre"] {
  --relief: inset 0 1px 0 rgba(255,255,255,.07);
  --cerne: color-mix(in srgb, var(--line) 80%, var(--white));
  --ombre-1: 0 1px 2px rgba(0,0,0,.35), 0 4px 12px -6px rgba(0,0,0,.55);
  --ombre-2: 0 2px 4px rgba(0,0,0,.35), 0 12px 28px -12px rgba(0,0,0,.7);
  --ombre-3: 0 3px 6px rgba(0,0,0,.4), 0 26px 52px -20px rgba(0,0,0,.8);
}
.fle-app[data-fle-theme="sombre"] .fle-corps {
  background-image:
    repeating-linear-gradient(0deg, rgba(255,255,255,.035) 0 1px, transparent 1px 64px),
    repeating-linear-gradient(90deg, rgba(255,255,255,.035) 0 1px, transparent 1px 64px);
}
/* En thème sombre, une tuile sombre sur fond sombre disparaîtrait : elle
   s'éclaircit d'un cran et prend un liseré sarcelle. */
.fle-app[data-fle-theme="sombre"] .fle-tuile {
  background: linear-gradient(165deg, #24413F 0%, #182B2A 100%);
  box-shadow: var(--ombre-2), inset 0 0 0 1px color-mix(in srgb, var(--accent) 30%, transparent);
}
.fle-app[data-fle-theme="sombre"] .fle-tuile--actif {
  background: linear-gradient(165deg, #2B5250 0%, #1C3836 100%);
  box-shadow: var(--ombre-3), inset 0 0 0 2px var(--accent);
}
.fle-app[data-fle-theme="sombre"] .fle-tache::after,
.fle-app[data-fle-theme="sombre"] .fle-memo::after {
  background: color-mix(in srgb, var(--accent) 18%, var(--white));
}

@media (prefers-color-scheme: dark) {
  .fle-app[data-fle-theme="systeme"] {
    --relief: inset 0 1px 0 rgba(255,255,255,.07);
    --cerne: color-mix(in srgb, var(--line) 80%, var(--white));
    --ombre-1: 0 1px 2px rgba(0,0,0,.35), 0 4px 12px -6px rgba(0,0,0,.55);
    --ombre-2: 0 2px 4px rgba(0,0,0,.35), 0 12px 28px -12px rgba(0,0,0,.7);
    --ombre-3: 0 3px 6px rgba(0,0,0,.4), 0 26px 52px -20px rgba(0,0,0,.8);
  }
  .fle-app[data-fle-theme="systeme"] .fle-corps {
    background-image:
      repeating-linear-gradient(0deg, rgba(255,255,255,.035) 0 1px, transparent 1px 64px),
      repeating-linear-gradient(90deg, rgba(255,255,255,.035) 0 1px, transparent 1px 64px);
  }
  .fle-app[data-fle-theme="systeme"] .fle-tuile {
    background: linear-gradient(165deg, #24413F 0%, #182B2A 100%);
    box-shadow: var(--ombre-2), inset 0 0 0 1px color-mix(in srgb, var(--accent) 30%, transparent);
  }
  .fle-app[data-fle-theme="systeme"] .fle-tuile--actif {
    background: linear-gradient(165deg, #2B5250 0%, #1C3836 100%);
    box-shadow: var(--ombre-3), inset 0 0 0 2px var(--accent);
  }
  .fle-app[data-fle-theme="systeme"] .fle-tache::after,
  .fle-app[data-fle-theme="systeme"] .fle-memo::after {
    background: color-mix(in srgb, var(--accent) 18%, var(--white));
  }
}

/* --- Contraste renforcé : la matière cède au trait ---------------------
   Quand le système demande plus de contraste, les ombres ne servent plus à
   rien - elles s'effacent et les filets reprennent la main. */
@media (prefers-contrast: more) {
  .fle-app .fle-carte, .fle-app .fle-tuile, .fle-app .fle-nav__lien,
  .fle-app .fle-acces__carte, .fle-app .fle-btn { box-shadow: none; }
  .fle-app .fle-carte, .fle-app .fle-nav__lien, .fle-app .fle-acces__carte { border: 2px solid var(--line); }
  .fle-app .fle-btn { border-width: 2px; }
  .fle-app .fle-tuile { background: var(--ink); border: 2px solid var(--accent); }
  .fle-app .fle-tuile::before, .fle-app .fle-tache::after, .fle-app .fle-memo::after { display: none; }
  .fle-app .fle-corps { background-image: none; }
}
@media (forced-colors: active) {
  .fle-app .fle-tuile { border: 2px solid; }
  .fle-app .fle-tuile::before { display: none; }
}
/* Le décalage des cartes empilées ne se voit pas à l'impression et brouille
   la mise en page : on le retire. */
@media print {
  .fle-app .fle-tache::after, .fle-app .fle-memo::after,
  .fle-app .fle-tuile::before { display: none !important; }
  .fle-app .fle-corps { background-image: none; }
}

/* La fiche de situation était détourée pour que son bandeau supérieur suive
   le rayon de la carte. Ce détourage empêchait la seconde carte de
   dépasser : on l'a retiré, et c'est le bandeau qui porte désormais son
   propre arrondi. */
.fle-app .fle-tache { overflow: visible; }
.fle-app .fle-tache::before { border-radius: var(--radius) var(--radius) 0 0; }

/* La famille et le « Voir plus » étaient une sarcelle à peine éclaircie :
   3,7:1 et 4,1:1 sur le fond de la tuile, sous le seuil. Ils sont désormais
   mélangés à soixante pour cent de blanc, ce qui les porte au-delà de 4,6:1 dans les deux
   thèmes sans les décolorer - on reconnaît encore la sarcelle. */
.fle-app .fle-tuile__num { color: color-mix(in srgb, var(--accent) 40%, #fff); }
.fle-app .fle-tuile__plus { color: color-mix(in srgb, var(--accent) 40%, #fff); }

/* Le lien d'évitement est retiré du balisage. La règle reste, et le masque :
   un navigateur qui servirait encore l'ancien script depuis son cache
   l'injecterait sinon de nouveau, et le lien reparaîtrait au milieu de la
   page - exactement ce qu'on vient de corriger. */
.fle-app .fle-evitement { display: none !important; }

/* =========================================================================
   L'écran de l'apprenant, vu par le formateur

   Un cadre qui ressemble à un écran : liseré net, fond de la couleur du
   contenu, et un bandeau qui rappelle où l'on en est. Il doit se distinguer
   du reste de la page sans prendre la vedette - ce n'est pas l'interface du
   formateur, c'est une fenêtre sur celle de l'autre.
   ====================================================================== */
.fle-app .fle-apercu {
  margin-top: 12px; border-radius: var(--radius);
  background: var(--white);
  border: 1.5px solid color-mix(in srgb, var(--accent) 30%, var(--line));
  box-shadow: var(--ombre-2);
  overflow: hidden;
}
.fle-app .fle-apercu__entete {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 10px 15px;
  background: var(--lavis-fort);
  border-bottom: 1px solid color-mix(in srgb, var(--accent) 24%, var(--line));
}
.fle-app .fle-apercu__corps { padding: 16px 18px; max-height: 460px; overflow: auto; }
.fle-app .fle-apercu__corps p { margin-top: 8px; }

.fle-app .fle-apercu__item {
  margin-top: 12px; padding: 11px 13px;
  border-radius: var(--radius-xs);
  background: var(--paper); border: 1px solid var(--cerne);
}
.fle-app .fle-apercu__q { font-family: var(--texte); font-size: 15.5px; line-height: 1.45; }
.fle-app .fle-apercu__reponse {
  margin-top: 6px; font-size: 14.5px; color: var(--primary);
}
.fle-app .fle-apercu__reponse strong { color: var(--primary); }
/* La bonne réponse : fond sarcelle plein et texte clair. Elle porte aussi
   une coche, pour rester repérable sans la couleur. */
.fle-app .fle-apercu__juste {
  background: var(--accent-plein); color: #fff;
  border-color: var(--accent-plein); font-weight: 650;
}
.fle-app .fle-apercu .fle-soustitre { margin-top: 6px; }

@media (max-width: 640px) {
  .fle-app .fle-apercu__corps { max-height: 320px; padding: 13px 14px; }
}

/* =========================================================================
   LE TABLEAU AU BAS DE LA SÉANCE

   Le bouton est rouge, à la demande. Une remarque s'impose, parce qu'elle
   engage la lisibilité de tout le reste : dans cette application, le rouge
   signale jusqu'ici l'erreur et l'action destructrice - « Retirer l'accès »,
   « Copie de moins de 125 mots ». Un bouton rouge pour un geste anodin crée
   donc une hésitation d'un quart de seconde.

   Deux précautions pour la réduire. Le rouge employé ici n'est PAS celui des
   alertes : il est plus chaud et plus soutenu, de sorte que les deux ne se
   confondent pas quand ils voisinent. Et il ne sert qu'à ce bouton-là, dont
   le libellé dit exactement ce qu'il fait : rien ne s'efface, rien ne se
   perd, le tableau s'ouvre.
   ====================================================================== */
.fle-app { --rouge-tableau: #B5342A; }

.fle-app .fle-btn--rouge {
  --btn-fond: var(--rouge-tableau);
  --btn-bord: var(--rouge-tableau);
  --btn-texte: #fff;
}
/* Le thème sombre fait passer les libellés des boutons pleins à l'encre et
   éclaircit au survol. Ni l'un ni l'autre ne convient ici : sur ce rouge,
   l'encre tombe à 3,4:1 et l'éclaircissement ferait descendre le blanc à
   4,5:1 tout juste. On garde donc le blanc, et on assombrit. */
.fle-app[data-fle-theme="sombre"] .fle-btn--rouge { --btn-texte: #fff; }
.fle-app[data-fle-theme="sombre"] .fle-btn--rouge:hover:not([disabled]) {
  background: color-mix(in srgb, var(--rouge-tableau) 87%, #06201F);
  border-color: color-mix(in srgb, var(--rouge-tableau) 87%, #06201F);
}
@media (prefers-color-scheme: dark) {
  .fle-app[data-fle-theme="systeme"] .fle-btn--rouge { --btn-texte: #fff; }
  .fle-app[data-fle-theme="systeme"] .fle-btn--rouge:hover:not([disabled]) {
    background: color-mix(in srgb, var(--rouge-tableau) 87%, #06201F);
    border-color: color-mix(in srgb, var(--rouge-tableau) 87%, #06201F);
  }
}

.fle-app .fle-tableau-appel {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  margin-top: 20px; padding: 15px 17px;
  border-radius: var(--radius);
  background: var(--white); border: 1px solid var(--cerne);
  box-shadow: var(--ombre-1), var(--relief);
}
.fle-app .fle-tableau-appel .fle-soustitre { flex: 1 1 260px; margin: 0; max-width: 62ch; }

.fle-app .fle-tableau-incruste {
  margin-top: 14px; padding: 14px;
  border-radius: var(--radius);
  background: var(--white);
  border: 1.5px solid color-mix(in srgb, var(--rouge-tableau) 28%, var(--line));
  box-shadow: var(--ombre-2);
}
.fle-app .fle-tableau-incruste[hidden] { display: none; }
/* Le cadre garde une hauteur confortable sans pousser la séance hors de
   l'écran : on en voit assez pour écrire, et l'on remonte d'un geste. */
.fle-app .fle-tableau-incruste .fle-tableau-fle-cadre { min-height: 62vh; }
@media (max-width: 640px) {
  .fle-app .fle-tableau-incruste { padding: 10px; }
  .fle-app .fle-tableau-incruste .fle-tableau-fle-cadre { min-height: 70vh; }
}

/* =========================================================================
   LA SENTINELLE NE DOIT PAS CLIGNOTER

   Le message « L'application ne s'est pas chargée » était affiché dès le
   premier octet de HTML, puis effacé par le script quelques dizaines de
   millisecondes plus tard. À chaque rafraîchissement, on le voyait donc
   passer - et un rafraîchissement ordinaire prenait l'allure d'un
   rechargement forcé, comme si tout était reparti de zéro.

   Il n'apparaît désormais qu'au bout de trois secondes. Si le script a fait
   son travail, personne ne le verra jamais ; s'il ne l'a pas fait, le
   message est là, et trois secondes d'attente ne changent rien à un
   diagnostic. Le délai passe par une animation, seul moyen de différer un
   affichage sans JavaScript - et c'est bien du cas où il n'y en a pas
   qu'il s'agit.
   ====================================================================== */
.fle-app .fle-amorcage {
  opacity: 0;
  animation: fle-amorcage-apparait 260ms ease-out 3s forwards;
}
@keyframes fle-amorcage-apparait { from { opacity: 0; } to { opacity: 1; } }
/* Le réglage « mouvement réduit » ramène toutes les durées à presque zéro ;
   le délai, lui, est conservé, et c'est le délai qui compte ici. */

/* =========================================================================
   L'ATTENTE ET LES DEMANDES D'ACCÈS
   ====================================================================== */

/* Côté apprenant : un point qui bat, et rien d'autre. L'écran doit dire
   « ça avance » sans donner l'impression qu'il s'est passé quelque chose. */
.fle-app .fle-attente-accord {
  display: flex; align-items: center; gap: 10px; margin-top: 16px;
  padding: 13px 15px; border-radius: var(--radius-s);
  background: var(--lavis); border: 1px solid color-mix(in srgb, var(--accent) 26%, var(--white));
  font-weight: 600; color: var(--primary);
}
.fle-app .fle-attente-accord__pouls {
  width: 10px; height: 10px; border-radius: 50%; background: var(--accent);
  animation: fle-pouls 1.6s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
  .fle-app .fle-attente-accord__pouls { animation: none; }
}

/* Côté formateur : une demande n'est pas une ligne de liste, c'est une
   interruption. Elle prend donc un cartouche à elle, en tête, et la couleur
   de l'attention - pas celle de l'erreur : personne n'a rien fait de mal. */
.fle-app .fle-demandes {
  margin-bottom: 18px; padding: 15px 17px; border-radius: var(--radius);
  background: color-mix(in srgb, var(--alerte) 7%, var(--white));
  border: 1.5px solid color-mix(in srgb, var(--alerte) 34%, var(--line));
  border-left: 5px solid var(--alerte);
  box-shadow: var(--ombre-1);
}
.fle-app .fle-demandes__titre {
  font-size: 16.5px; font-weight: 680; color: var(--ink);
}
.fle-app .fle-demandes .fle-eleve { margin-top: 10px; background: var(--white); }

/* La signature du document déclencheur : en bas à droite, en italique, comme
   sur les sujets officiels. C'est un repère de lecture autant qu'un
   ornement - un quotidien national et un magazine pour lycéens ne parlent
   pas du même endroit, et le candidat doit pouvoir en tenir compte. */
.fle-app .fle-oral-source {
  margin-top: 10px; text-align: right;
  font-family: var(--texte); font-style: italic; font-size: 14.5px;
  color: var(--muted);
}

/* =========================================================================
   LE SUJET AU FORMAT DE L'ÉPREUVE

   Trois phrases dans un cadre, comme sur la feuille que reçoit le candidat.
   Pas d'étiquette devant chaque ligne : le sujet officiel n'en a pas, et
   l'apprenant doit s'habituer à lire ce qu'il lira le jour venu.
   ====================================================================== */
.fle-app .fle-sujet-tcf { max-width: 62ch; }
/* Un paragraphe, d'un seul tenant, sans mise en gras d'aucune phrase : le
   sujet se lit comme sur la feuille d'épreuve. Trois lignes empilées dont la
   première en gras donnaient l'impression d'amorces à compléter. */
.fle-app .fle-sujet-tcf__texte {
  margin-top: 8px;
  font-family: var(--texte); font-size: var(--t-lire); line-height: 1.75;
  text-align: justify; hyphens: auto;
}

/* Le pendant du sujet, côté formateur : ce que le candidat ne voit pas. */
.fle-app .fle-conduite-tache {
  margin-top: 12px; padding: 13px 15px; border-radius: var(--radius-s);
  background: var(--paper); border: 1px solid var(--cerne);
  border-left: 4px solid var(--gris);
}
.fle-app .fle-conduite-tache p { font-size: 15px; line-height: 1.55; }

/* Les sections d'un niveau. Un niveau peut réunir un cours général et des
   ensembles de français sur objectifs spécifiques, un métier par
   sous-section : sans repère visuel, on parcourt quarante-trois séances
   pour en trouver trois. */
.fle-app .fle-section-titre {
  display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap;
  margin: 22px 0 4px; padding-bottom: 6px;
  border-bottom: 2px solid var(--accent);
}
.fle-app .fle-section-titre:first-child { margin-top: 6px; }
.fle-app .fle-section-titre strong { font-size: 17px; color: var(--primary); }
.fle-app .fle-soussection-titre {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  margin: 16px 0 2px; padding: 5px 11px;
  border-radius: var(--radius-pilule);
  background: var(--lavis); color: var(--ink);
  font-weight: 650; font-size: 14.5px; width: fit-content;
}

/* =========================================================================
   LE VOYANT « DIRECT »

   Emprunté au vocabulaire de la télévision : un point rouge qui bat, le mot,
   rien de plus. Il dit à l'apprenant que quelqu'un est aux commandes en ce
   moment même - information qui manquait, et qui change tout : on n'attend
   pas de la même façon devant une page pilotée et devant une page oubliée.
   ====================================================================== */
.fle-app .fle-direct {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 4px 11px 4px 9px;
  border-radius: var(--radius-pilule);
  background: color-mix(in srgb, #C0392B 12%, var(--white));
  border: 1px solid color-mix(in srgb, #C0392B 40%, var(--white));
  color: #8E2A20;
  font-family: var(--ui); font-size: 12px; font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase;
}
.fle-app .fle-direct__point {
  width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto;
  background: #C0392B;
  box-shadow: 0 0 0 0 color-mix(in srgb, #C0392B 55%, transparent);
  animation: fle-direct-bat 1.6s ease-out infinite;
}
@keyframes fle-direct-bat {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, #C0392B 55%, transparent); }
  70%  { box-shadow: 0 0 0 7px transparent; }
  100% { box-shadow: 0 0 0 0 transparent; }
}
/* Sans animation, le point plein suffit à distinguer le voyant. */
@media (prefers-reduced-motion: reduce) {
  .fle-app .fle-direct__point { animation: none; }
}
.fle-app[data-fle-theme="sombre"] .fle-direct {
  background: color-mix(in srgb, #FF8A80 14%, var(--white));
  border-color: color-mix(in srgb, #FF8A80 40%, var(--white));
  color: #FF9E95;
}
.fle-app[data-fle-theme="sombre"] .fle-direct__point { background: #FF8A80; }
@media (prefers-color-scheme: dark) {
  .fle-app[data-fle-theme="systeme"] .fle-direct {
    background: color-mix(in srgb, #FF8A80 14%, var(--white));
    border-color: color-mix(in srgb, #FF8A80 40%, var(--white));
    color: #FF9E95;
  }
  .fle-app[data-fle-theme="systeme"] .fle-direct__point { background: #FF8A80; }
}

/* =========================================================================
   TÉLÉPHONE DU FLE

   Le cadre n'est plus dessiné en CSS : c'est l'illustration fournie - un
   iPhone 12, en deux calques découpés du fichier d'origine.

   POURQUOI DEUX CALQUES
   ---------------------
   Le corps passe derrière la vidéo, l'encoche par-dessus. C'est ce qui fait
   qu'on regarde vraiment un téléphone et non une vidéo posée dans un cadre :
   sur l'appareil, l'image passe SOUS l'encoche, qui la mord. Un seul calque
   aurait obligé à laisser une bande vide en haut, et l'illusion tombait.

   LES PROPORTIONS VIENNENT DU DESSIN
   -----------------------------------
   Rien n'est estimé ici. L'écran de l'illustration mesure 189 sur 409,4
   unités, soit 19,495 pour 9 - les proportions d'un appareil réel, à cinq
   millièmes près. Les pourcentages ci-dessous sont mesurés sur le tracé de
   cet écran, dans le repère du fichier : la vidéo se pose donc exactement
   là où se pose l'image sur l'appareil, et non à peu près.
   ====================================================================== */
.fle-app .fle-tel-plan {
  display: grid; grid-template-columns: minmax(0, 360px) minmax(0, 1fr);
  gap: 22px; align-items: start; margin-top: 14px;
}

.fle-app .fle-tel {
  position: relative; width: 100%; max-width: 360px; margin: 0 auto;
  /* Le rapport du cadrage du dessin, pas un rapport choisi. */
  aspect-ratio: 212.40 / 432.61;
  background: url(../img/telephone-corps.svg) center / contain no-repeat;
  filter: drop-shadow(0 18px 26px rgba(14, 22, 21, .28));
}
/* L'encoche, au-dessus de la vidéo, et transparente au clic pour ne pas
   voler les commandes du lecteur. */
.fle-app .fle-tel::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: url(../img/telephone-encoche.svg) center / contain no-repeat;
}

.fle-app .fle-tel__ecran {
  position: absolute;
  left: 5.505%; top: 2.680%; width: 88.983%; height: 94.636%;
  overflow: hidden; background: #06100F;
  /* Le rayon des coins de l'écran, relevé sur le tracé : 24 unités, soit
     12,7 % de sa largeur et 5,9 % de sa hauteur. Deux valeurs, parce qu'un
     rayon unique donnerait des coins ovales sur un écran si allongé. */
  border-radius: 12.7% / 5.9%;
}
.fle-app .fle-tel__cadre {
  position: absolute; inset: 0; width: 100%; height: 100%; border: 0;
}
.fle-app .fle-tel__vide {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; justify-content: center; align-items: center;
  gap: 6px; padding: 22px; text-align: center; color: #BFD0CF;
}
.fle-app .fle-tel__vide .fle-soustitre { color: #93A7A5; }

/* Les questions occupent la place que le téléphone laisse. */
.fle-app .fle-tel__questions {
  padding: 16px 18px; border-radius: var(--radius);
  background: var(--white); border: 1px solid var(--cerne);
  box-shadow: var(--ombre-1), var(--relief);
  position: sticky; top: 12px;
}
.fle-app .fle-tel__question {
  display: flex; gap: 12px; align-items: flex-start;
  margin-top: 12px; padding: 12px 14px;
  border-radius: var(--radius-s); background: var(--lavis);
  border-left: 4px solid var(--accent);
}
.fle-app .fle-tel__question p {
  font-family: var(--texte); font-size: var(--t-lire); line-height: 1.6; margin: 0;
}
.fle-app .fle-tel__numero {
  flex: 0 0 auto; width: 24px; height: 24px; border-radius: 50%;
  display: grid; place-content: center;
  background: var(--accent-plein); color: #fff;
  font-family: var(--ui); font-size: 12.5px; font-weight: 700;
}

/* Côté formateur : l'aperçu et la banque de questions. */
.fle-app .fle-tel-apercu { margin-top: 14px; max-width: 360px; }
.fle-app .fle-tel-banque {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 320px), 1fr));
  gap: 4px; margin-top: 10px;
}
.fle-app .fle-tel-banque__ligne {
  padding: 7px 10px; border-radius: var(--radius-xs);
  font-size: 14.5px; line-height: 1.45; cursor: pointer;
}
.fle-app .fle-tel-banque__ligne:hover { background: var(--lavis); }
.fle-app .fle-tel-banque__ligne--eteinte { opacity: .45; cursor: not-allowed; }

/* Un appareil à sa vraie taille est haut : à 360 pixels de large, il en fait
   733. C'est la conséquence des proportions demandées, et elle est assumée -
   sur ordinateur les questions se lisent dans la colonne de droite, qui reste
   en vue pendant qu'on fait défiler. Sur petit écran, tout s'empile et l'on
   fait défiler comme on le ferait sur un téléphone. */
@media (max-width: 800px) {
  .fle-app .fle-tel-plan { grid-template-columns: 1fr; }
  .fle-app .fle-tel__questions { position: static; }
}

/* =========================================================================
   LA PASTILLE DE NOTIFICATION

   Un rond rouge, un chiffre blanc. C'est la convention universelle, et il
   n'y a aucune raison d'en inventer une autre : l'apprenant la reconnaît
   avant d'avoir lu quoi que ce soit.

   Deux précautions. Le chiffre plafonne à neuf, parce qu'au-delà il ne
   change plus la décision d'ouvrir l'atelier et que trois caractères
   déforment la vignette. Et la pastille porte une étiquette vocale qui dit
   le compte réel et ce qu'il désigne : un rond rouge muet ne dirait rien à
   qui ne le voit pas.
   ====================================================================== */
.fle-app .fle-pastille-porteur { display: inline-flex; }
.fle-app .fle-pastille-nb {
  display: inline-grid; place-content: center;
  min-width: 21px; height: 21px; padding: 0 6px; margin-left: 8px;
  border-radius: var(--radius-pilule);
  background: #C0392B; color: #fff;
  font-family: var(--ui); font-size: 12px; font-weight: 700;
  line-height: 1; letter-spacing: 0;
  box-shadow: 0 1px 3px rgba(0,0,0,.25);
}
/* Sur la vignette sombre, le rouge de la pastille ne se détache pas : 1,8:1
   contre le fond, sous le seuil exigé pour un élément d'interface. C'est un
   liseré clair qui porte la séparation - blanc sur la vignette, il dépasse
   largement le seuil, et il encercle la pastille sans la décolorer. */
.fle-app .fle-tuile .fle-pastille-nb { box-shadow: 0 0 0 2px rgba(255,255,255,.62); }
.fle-app .fle-tuile__num { display: flex; align-items: center; }
.fle-app .fle-nav__lien strong { display: flex; align-items: center; }
.fle-app .fle-nav__accueil { display: inline-flex; align-items: center; }

/* En contraste renforcé, l'aplat rouge cède au trait : la pastille garde son
   chiffre, encadré, et reste lisible sans dépendre de la couleur. */
@media (prefers-contrast: more) {
  .fle-app .fle-pastille-nb {
    background: transparent; color: var(--ink);
    box-shadow: none; border: 2px solid currentColor;
  }
}
@media (forced-colors: active) {
  .fle-app .fle-pastille-nb { border: 2px solid; }
}

/* =========================================================================
   LA BASCULE D'AFFICHAGE

   Le jaune est demandé, et il tombe bien : il ne sert nulle part ailleurs
   dans l'application, si bien qu'il ne peut être confondu ni avec la
   sarcelle des commandes ni avec le rouge des alertes. Il dit « attention,
   tu n'es pas dans l'état ordinaire », ce qui est exactement le propos.

   Deux précautions. Le jaune plein ne se détache pas du papier - 1,7 contre
   1, loin des trois exigés pour la limite d'un élément d'interface : c'est
   un liseré brun qui porte le contour. Et le bandeau reste collé en haut,
   parce qu'un formateur qui bascule puis fait défiler doit garder sous les
   yeux la raison pour laquelle ses commandes ont disparu.
   ====================================================================== */
.fle-app { --jaune: #EFB700; --jaune-bord: #8A6A00; }

.fle-app .fle-btn--jaune {
  --btn-fond: var(--jaune);
  --btn-bord: var(--jaune-bord);
  --btn-texte: #101010;
  font-weight: 680;
}
.fle-app .fle-btn--jaune:hover:not([disabled]) {
  background: color-mix(in srgb, var(--jaune) 87%, #06201F);
  border-color: var(--jaune-bord);
}
/* Le thème sombre fait passer les libellés des boutons pleins à l'encre et
   les éclaircit au survol. Sur un jaune, l'encre est déjà le bon choix ;
   seul l'éclaircissement est neutralisé, il délaverait le bouton. */
.fle-app[data-fle-theme="sombre"] .fle-btn--jaune:hover:not([disabled]) {
  background: color-mix(in srgb, var(--jaune) 87%, #06201F);
}

.fle-app .fle-bascule-vue {
  position: sticky; top: 8px; z-index: 5;
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  margin-bottom: 14px; padding: 11px 14px;
  border-radius: var(--radius);
  background: var(--white); border: 1px solid var(--cerne);
  box-shadow: var(--ombre-1), var(--relief);
}
.fle-app .fle-bascule-vue__mot {
  flex: 1 1 260px; max-width: 62ch;
  font-family: var(--ui); font-size: 13.5px; line-height: 1.45;
  color: var(--muted);
}
/* En aperçu, le bandeau prend la couleur de l'état : on ne peut pas
   travailler dix minutes sans s'en apercevoir. */
.fle-app .fle-bascule-vue--active {
  background: #FDF3D6;
  border-color: var(--jaune);
  border-left: 5px solid var(--jaune);
  box-shadow: var(--ombre-2);
}
.fle-app .fle-bascule-vue--active .fle-bascule-vue__mot { color: #4A3B00; }

@media print {
  .fle-app .fle-bascule-vue { display: none; }
}

/* =========================================================================
   MA CLASSE - le cadre de réunion
   =========================================================================
   Une boîte de visioconférence n'a pas de bonne hauteur en pixels. Elle a
   de bonnes proportions, et ce sont celles de l'appareil qui regarde.

   La boîte suit --fle-ecran, que le script pose sur la racine d'après le
   grand et le petit côté de l'écran, remis dans le sens où l'appareil est
   tenu. Un ordinateur donne du 16/9 ou du 21/9, une tablette du 3/4, un
   téléphone tenu droit une boîte verticale. Tourner l'appareil la retourne.

   POURQUOI UNE LARGEUR MAXIMALE, ET PAS SEULEMENT UNE HAUTEUR
   -----------------------------------------------------------
   Première tentative : proportions déclarées, plus un plafond de hauteur.
   Mesure au navigateur, sur une fenêtre de 1440 × 820 : on demandait
   1,778 et on obtenait 2,266. Le plafond mordait avant les proportions,
   partout, et la boîte n'avait donc jamais la forme annoncée - le défaut
   exact qu'on voulait corriger, reproduit autrement.

   La hauteur disponible est une contrainte réelle : la boîte ne doit pas
   pousser hors de vue le bouton qui ferme la réunion. Mais la faire
   respecter par un plafond de hauteur déforme, alors que la faire
   respecter par une largeur maximale rétrécit sans déformer. On calcule
   donc la largeur que cette hauteur autorise - hauteur × proportions - et
   la boîte se centre dans ce qui reste.

   SUR UN TÉLÉPHONE, LA LARGEUR PRIME
   ----------------------------------
   Même calcul sur un téléphone tenu droit : proportions 0,5, hauteur
   disponible 476 pixels, donc une boîte de 238 de large sur un écran qui
   en fait 390. Quarante pour cent de largeur perdus, sur l'appareil où
   chaque pixel de visage compte. Sous 640 pixels, la boîte reprend donc
   toute la largeur et sa hauteur se contente du plafond : elle reste
   verticale, sans se réduire à une colonne au milieu de deux marges.

   LA RÉSERVE DE 86 PIXELS
   -----------------------
   Le cadre n'est pas seul dans la scène : il y a les marges, et surtout
   la barre qui porte « Quitter la réunion ». Sans cette réserve, un
   téléphone couché - 390 pixels de haut - plaçait ce bouton à 399, donc
   hors de l'écran : on entrait dans une réunion qu'il fallait faire
   défiler pour quitter. Mesuré, pas supposé.

   svh plutôt que vh : sur un téléphone, vh compte la fenêtre barre
   d'adresse rétractée, c'est-à-dire une hauteur qu'on n'a pas encore. La
   ligne vh qui précède sert aux navigateurs qui ignorent svh.
   ====================================================================== */
.fle-app .fle-visio-scene {
  --fle-visio-h: min(900px, max(200px, calc(72vh - 86px)));
  --fle-visio-h: min(900px, max(200px, calc(72svh - 86px)));
  margin-top: 16px;
  padding: 12px;
  border-radius: var(--radius);
  background: var(--white);
  border: 1px solid var(--cerne);
  box-shadow: var(--ombre-2);
}
.fle-app .fle-visio-cadre,
.fle-app .fle-visio-zoom {
  display: block;
  width: 100%;
  max-width: calc(var(--fle-ecran-n, 1.778) * var(--fle-visio-h));
  margin-inline: auto;
  aspect-ratio: var(--fle-ecran, 16 / 9);
  max-height: var(--fle-visio-h);
  min-height: 180px;
  border: 0;
  border-radius: var(--radius-s);
  background: #0E1716;
  overflow: hidden;
}
/* La barre du cadre suit la même largeur : le bouton qui ferme la réunion
   doit rester sous la réunion, pas au bout d'une ligne vide. */
.fle-app .fle-visio-barre {
  max-width: calc(var(--fle-ecran-n, 1.778) * var(--fle-visio-h));
  margin-inline: auto;
}

/* Le SDK de Zoom place ses propres éléments : il lui faut un bloc qui se
   comporte en conteneur, pas une simple hauteur. */
.fle-app .fle-visio-zoom { position: relative; }
.fle-app .fle-visio-zoom > * { max-width: 100%; }

@media (max-width: 640px) {
  .fle-app .fle-visio-scene {
    padding: 6px;
    --fle-visio-h: min(900px, max(170px, calc(74vh - 70px)));
    --fle-visio-h: min(900px, max(170px, calc(74svh - 70px)));
  }
  .fle-app .fle-visio-cadre,
  .fle-app .fle-visio-zoom {
    max-width: none;
    min-height: 160px;
  }
  .fle-app .fle-visio-barre { max-width: none; }
}

/* Un navigateur qui ne connaît pas aspect-ratio - il en reste - doit
   quand même afficher une boîte utilisable, pas un filet de deux pixels. */
@supports not (aspect-ratio: 1 / 1) {
  .fle-app .fle-visio-cadre,
  .fle-app .fle-visio-zoom { height: 58vh; max-width: none; }
}

/* Une réunion n'a rien à faire sur une feuille imprimée. */
@media print {
  .fle-app .fle-visio-scene,
  .fle-app .fle-vsdk-scene { display: none; }
}

/* =========================================================================
   LA SALLE ZOOM DANS LA PAGE - la grille
   =========================================================================
   Le Video SDK ne donne aucune interface : la grille est à nous. Ses
   colonnes changent avec le nombre de caméras allumées, depuis le script,
   parce qu'une grille fixe donne des vignettes minuscules dès qu'il y a
   du monde et démesurées quand il n'y a personne.

   Le conteneur garde les proportions de l'écran, comme les autres cadres
   de réunion : une salle Zoom et une salle intégrée n'ont pas à se
   présenter différemment parce qu'elles reposent sur deux technologies.
   ====================================================================== */
.fle-app .fle-vsdk-scene {
  display: block;
  width: 100%;
  max-width: calc(var(--fle-ecran-n, 1.778) * var(--fle-visio-h));
  margin-inline: auto;
  aspect-ratio: var(--fle-ecran, 16 / 9);
  max-height: var(--fle-visio-h);
  min-height: 180px;
  border-radius: var(--radius-s);
  background: #0E1716;
  overflow: hidden;
  position: relative;
}
.fle-app .fle-vsdk-grille {
  display: grid;
  gap: 6px;
  padding: 6px;
  width: 100%;
  height: 100%;
  grid-auto-rows: minmax(0, 1fr);
}
.fle-app .fle-vsdk-case {
  position: relative;
  min-width: 0; min-height: 0;
  border-radius: var(--radius-xs);
  overflow: hidden;
  background: #16211F;
}
/* Le <video-player> est un élément du SDK : il n'a pas de dimensions
   propres tant qu'on ne lui en donne pas, et il reste invisible sans
   ceci - sans qu'aucune erreur ne le signale. */
.fle-app .fle-vsdk-case video-player,
.fle-app .fle-vsdk-case video {
  display: block;
  width: 100%; height: 100%;
  object-fit: cover;
}
.fle-app .fle-vsdk-nom {
  position: absolute; left: 6px; bottom: 6px;
  max-width: calc(100% - 12px);
  padding: 2px 8px;
  border-radius: 999px;
  background: rgba(6, 32, 31, .72);
  color: #fff;
  font-family: var(--ui); font-size: 12px; line-height: 1.5;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* Personne n'a allumé sa caméra : l'écran noir se justifie, en toutes
   lettres, plutôt que de laisser croire à une panne. */
.fle-app .fle-vsdk-grille[data-vide="oui"]::after {
  content: "Aucune caméra allumée pour l’instant.";
  grid-column: 1 / -1;
  align-self: center; justify-self: center;
  color: #9FB3B1;
  font-family: var(--ui); font-size: 14px;
  text-align: center; padding: 0 18px;
}
.fle-app .fle-vsdk-mot {
  font-family: var(--ui); font-size: 13.5px; line-height: 1.45;
  color: var(--muted);
  margin-bottom: 8px;
}
.fle-app .fle-vsdk-mot--vide { display: none; }
.fle-app .fle-vsdk-mot--erreur {
  color: #8C2F27;
  background: #FCEDEB;
  border-left: 4px solid #B5342A;
  border-radius: var(--radius-xs);
  padding: 8px 12px;
}
@media (max-width: 640px) {
  .fle-app .fle-vsdk-scene { max-width: none; min-height: 160px; }
}
@supports not (aspect-ratio: 1 / 1) {
  .fle-app .fle-vsdk-scene { height: 58vh; max-width: none; }
}

/* =========================================================================
   EXERCICES LEARNINGAPPS - le cadre
   =========================================================================
   Première écriture : trois hauteurs en pixels, 380, 560, 820, et une
   largeur qui suivait la page. Mesure au navigateur, sur une fenêtre de
   1440 par 820 : un cadre de 1416 sur 560, c'est-à-dire un bandeau où un
   appariement de six cartes flotte au milieu d'un grand vide. Et sur un
   téléphone couché, le plafond écrasait les trois crans à la même valeur
   - le réglage ne réglait plus rien.

   Le cadre prend donc les proportions de l'appareil, comme la boîte de
   réunion : --fle-ecran, que le script pose sur la racine d'après le
   grand et le petit côté de l'écran, remis dans le sens où l'appareil
   est tenu.

   CE QUE LES TROIS CRANS DEVIENNENT
   ---------------------------------
   Ils ne fixent plus une hauteur, ils partagent la place disponible :
   un peu plus de la moitié, les trois quarts, ou tout. C'est plus juste
   que des pixels, parce que la question n'a jamais été « combien de
   pixels fait ce mot croisé » mais « quelle part de l'écran je lui
   donne ». Et cela garde son sens sur tous les appareils : un cran reste
   un cran, même sur un téléphone couché.

   LA LARGEUR MAXIMALE, ENCORE
   ---------------------------
   Même raison qu'ailleurs : plafonner la hauteur déforme, borner la
   largeur rétrécit sans déformer. La largeur que la hauteur autorise se
   calcule - hauteur multipliée par les proportions - et le cadre se
   centre dans ce qui reste.

   SOUS 640 PIXELS, LA LARGEUR PRIME
   ---------------------------------
   Sur un téléphone, honorer des proportions de 0,5 donnerait un cadre
   de 238 de large sur un écran qui en fait 390. Un exercice écrit ne se
   lit pas dans une colonne. Le cadre reprend donc toute la largeur.

   LA RÉSERVE DE 92 PIXELS
   -----------------------
   Ce qui suit le cadre - le bouton « J'ai terminé » avant tout. Sans
   elle, un téléphone couché plaçait ce bouton à 412 dans une fenêtre de
   390 : l'apprenant finissait son exercice sans pouvoir le déclarer.
   Mesuré, pas supposé.
   ====================================================================== */
/* Le budget vit sur la racine : le cadre ET la ligne qui le suit doivent
   tous deux le lire, et une propriété posée sur le cadre resterait
   invisible à sa voisine. Le script pose --fle-la-part sur l'atelier. */
.fle-app {
  --fle-la-dispo: max(220px, calc(82vh - 92px));
  --fle-la-dispo: max(220px, calc(82svh - 92px));
  --fle-la-h: calc(var(--fle-la-dispo) * var(--fle-la-part, .76));
}
.fle-app .fle-la-scene {
  margin-top: 14px;
  padding: 10px;
  border-radius: var(--radius);
  background: var(--white);
  border: 1px solid var(--cerne);
  box-shadow: var(--ombre-2);
}
.fle-app .fle-la-cadre {
  display: block;
  width: 100%;
  max-width: calc(var(--fle-ecran-n, 1.778) * var(--fle-la-h));
  margin-inline: auto;
  aspect-ratio: var(--fle-ecran, 16 / 9);
  max-height: var(--fle-la-h);
  min-height: 200px;
  border: 0;
  border-radius: var(--radius-s);
  background: #F4F7F7;
}
.fle-app[data-fle-theme="sombre"] .fle-la-cadre { background: #16211F; }

/* Ce qui suit immédiatement le cadre garde sa largeur : le bouton qui
   ouvre l'exercice à part doit rester sous l'exercice, pas au bout d'une
   ligne vide. */
.fle-app .fle-la-barre {
  max-width: calc(var(--fle-ecran-n, 1.778) * var(--fle-la-h));
  margin-inline: auto;
}

@media (max-width: 640px) {
  .fle-app {
    --fle-la-dispo: max(200px, calc(84vh - 76px));
    --fle-la-dispo: max(200px, calc(84svh - 76px));
  }
  .fle-app .fle-la-scene { padding: 4px; }
  .fle-app .fle-la-cadre { max-width: none; min-height: 180px; }
  .fle-app .fle-la-barre { max-width: none; }
}

/* Un écran très bas - un téléphone couché, une fenêtre réduite en
   hauteur - n'a pas de quoi honorer des proportions : le plancher de
   hauteur l'emporte, et borner la largeur ne produit plus qu'un petit
   carré au milieu d'un écran large. Mesuré : 294 sur 200 dans une
   fenêtre de 756. Là, la largeur reprend la main, et l'exercice occupe
   la bande qu'on peut lui donner. */
@media (max-height: 520px) {
  .fle-app .fle-la-cadre,
  .fle-app .fle-la-barre { max-width: none; }
}

/* Un navigateur sans aspect-ratio doit quand même afficher un cadre
   utilisable, pas un filet de deux pixels. */
@supports not (aspect-ratio: 1 / 1) {
  .fle-app .fle-la-cadre { height: var(--fle-la-h); max-width: none; }
}

/* Un exercice interactif ne s'imprime pas. */
@media print {
  .fle-app .fle-la-scene { display: none; }
}

/* =========================================================================
   DELF B2 - COMPRÉHENSIONS : L'ÉPREUVE À L'ÉCRAN
   =========================================================================
   Une copie d'examen se lit longtemps et se parcourt du regard. Trois
   décisions en découlent.

   LA LARGEUR DE LECTURE. Un document de trois cents mots étalé sur seize
   cents pixels se lit mal : l'œil perd sa ligne au retour. Le texte est
   donc borné, comme sur le sujet papier.

   LE NUMÉRO DE QUESTION TIENT SA COLONNE. Sur le sujet officiel, les
   numéros forment une colonne que l'on descend pour vérifier qu'on n'a
   rien sauté. Un numéro noyé dans l'énoncé fait perdre ce balayage.

   LES RÉPONSES SONT DES CIBLES, PAS DES LIGNES DE TEXTE. On répond à
   quarante questions à la suite, souvent au doigt. La zone cliquable est
   la ligne entière, jamais le seul petit rond.
   ====================================================================== */
.fle-app .fle-ceco-consigne {
  font-family: var(--ui); font-size: 14px; line-height: 1.5;
  color: var(--ink); font-weight: 600;
  margin: 8px 0 4px;
}

.fle-app .fle-ceco-doc {
  margin: 12px 0;
  padding: 14px 18px;
  border-radius: var(--radius-s);
  background: var(--lavis-gris, #F4F7F7);
  border: 1px solid var(--cerne);
}
.fle-app .fle-ceco-doc__titre {
  margin: 0 0 8px;
  font-family: var(--titre, var(--ui)); font-size: 19px; line-height: 1.25;
  color: var(--ink);
}
.fle-app .fle-ceco-doc__texte {
  max-width: 68ch;
  font-size: 15.5px; line-height: 1.62;
  white-space: pre-wrap;
}
.fle-app .fle-ceco-doc__source {
  margin: 10px 0 0; text-align: right;
  font-size: 12.5px; font-style: italic; color: var(--muted);
}

.fle-app .fle-ceco-q { margin: 14px 0 0; padding-top: 12px; border-top: 1px solid var(--line); }
.fle-app .fle-ceco-q__tete { display: flex; align-items: baseline; gap: 10px; }
.fle-app .fle-ceco-q__num {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; border-radius: 50%;
  background: var(--ink); color: var(--white);
  font-family: var(--data, var(--ui)); font-size: 12px; font-weight: 700;
}
.fle-app .fle-ceco-q__enonce { flex: 1 1 auto; font-size: 15.5px; line-height: 1.5; }
.fle-app .fle-ceco-q__pts {
  flex: 0 0 auto; font-size: 12px; font-style: italic; color: var(--muted); white-space: nowrap;
}

.fle-app .fle-ceco-options { margin: 8px 0 0 32px; }
.fle-app .fle-ceco-option {
  display: flex; align-items: flex-start; gap: 9px;
  padding: 7px 10px; margin: 3px 0;
  border-radius: var(--radius-xs);
  border: 1px solid transparent;
  cursor: pointer;
}
.fle-app .fle-ceco-option:hover { background: var(--lavis-gris, #F4F7F7); }
.fle-app .fle-ceco-option__lettre {
  flex: 0 0 auto; width: 18px;
  font-family: var(--data, var(--ui)); font-weight: 700; color: var(--muted);
}
.fle-app .fle-ceco-option__texte { flex: 1 1 auto; line-height: 1.45; }
.fle-app .fle-ceco-option--choisie {
  background: color-mix(in srgb, var(--accent) 12%, var(--white));
  border-color: color-mix(in srgb, var(--accent) 45%, var(--white));
}
/* La correction : le vert et le rouge ne portent pas seuls la
   distinction. Un liseré épais à gauche et le mot de la réponse en gras
   la portent aussi, pour qui ne distingue pas ces deux teintes. */
.fle-app .fle-ceco-option--bonne {
  background: color-mix(in srgb, var(--succes) 14%, var(--white)); border-color: var(--succes); border-left-width: 5px;
}
.fle-app .fle-ceco-option--bonne .fle-ceco-option__texte { font-weight: 650; }
.fle-app .fle-ceco-option--fausse {
  background: color-mix(in srgb, var(--danger) 12%, var(--white)); border-color: var(--danger); border-left-width: 5px;
  text-decoration: line-through; text-decoration-thickness: 1px;
}

/* La forme à insertion : les réponses s'alignent, et la fin de phrase
   commune se place à leur droite - c'est la disposition du sujet
   officiel, et elle oblige à lire la phrase entière avant de choisir. */
.fle-app .fle-ceco-q__fin {
  margin: 4px 0 0 42px;
  font-size: 15.5px; line-height: 1.45; color: var(--ink);
}
/* Grille : les réponses à gauche, la fin de phrase à droite, alignées en
   haut ; le texte peut grossir ou passer à la ligne sans rien recouvrir. */
.fle-app .fle-ceco-insert { display: grid; grid-template-columns: minmax(0, 1fr); gap: 4px 18px; align-items: start; }
@media (min-width: 720px) {
  .fle-app .fle-ceco-insert { grid-template-columns: minmax(0, 32ch) minmax(12ch, 1fr); }
  .fle-app .fle-ceco-insert .fle-ceco-q__fin { margin: 10px 0 0; }
}

.fle-app .fle-ceco-note {
  font-family: var(--data, var(--ui));
  font-size: 34px; font-weight: 700; line-height: 1.2;
  margin: 6px 0 2px;
}
.fle-app .fle-ceco-copie {
  padding: 7px 0; border-bottom: 1px solid var(--line); gap: 12px;
}
.fle-app .fle-ceco-copie__detail { margin-top: 3px; }

/* Le chrono de la compréhension des écrits : une pastille fixe, en bas à
   droite, toujours visible quelle que soit la question qu'on lit. La barre
   du haut, collée elle aussi, change de hauteur selon l'écran : en bas, on
   ne se chevauche pas. */
.fle-app .fle-ceco-chrono {
  position: fixed; right: 16px; bottom: 16px; z-index: 40;
  display: flex; flex-direction: column; align-items: flex-end; gap: 0;
  padding: 8px 14px; border-radius: 12px;
  background: var(--white); border: 2px solid var(--primary);
  box-shadow: 0 6px 18px -8px rgba(15,60,58,.45);
}
.fle-app .fle-ceco-chrono__temps { font-family: var(--data, var(--ui)); font-size: 22px; line-height: 1.2; color: var(--ink); }
.fle-app .fle-ceco-chrono .fle-eleve__detail { font-size: 12.5px; }
.fle-app .fle-ceco-chrono--urgent { border-color: var(--danger); }
.fle-app .fle-ceco-chrono--urgent .fle-ceco-chrono__temps { color: var(--danger); }
@media (max-width: 480px) {
  .fle-app .fle-ceco-chrono { right: 8px; bottom: 8px; padding: 6px 10px; }
  .fle-app .fle-ceco-chrono .fle-eleve__detail { display: none; }
}
.fle-app .fle-ceco-depart { border-left: 4px solid var(--primary); }
/* Le bandeau « nouvelle version » du formateur. */
.fle-app .fle-maj { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin: 8px; }
/* La pastille ne doit pas couvrir la dernière question ni « Rendre ma copie ». */
.fle-app .fle-ceco-avec-chrono { padding-bottom: 96px; }

/* La copie rendue qui attend la validation du formateur. */
.fle-app .fle-ceco-attente { border-left: 4px solid var(--alerte); }
.fle-app .fle-ceco-attente__titre { font-size: 17px; margin: 6px 0 4px; line-height: 1.35; }

/* Le bilan de la correction : un mot accordé au résultat, trois conseils. */
.fle-app .fle-ceco-bilan__titre { font-size: 17px; margin: 10px 0 2px; }
.fle-app .fle-ceco-bilan__message { font-family: var(--texte); font-size: var(--t-lire); line-height: 1.55; margin: 2px 0 6px; }
.fle-app .fle-ceco-conseils { margin: 8px 0 0 22px; padding: 0; list-style: decimal; }
.fle-app .fle-ceco-conseils li { margin: 0 0 10px; padding-left: 4px; font-family: var(--texte); font-size: var(--t-lire); line-height: 1.55; }

/* Le choix d'une réponse se voit sans le bouton radio natif : la lettre
   devient une pastille pleine. Un thème WordPress qui masque ou redessine
   les boutons radio ne prive plus l'apprenant de ce retour. Le bouton
   natif reste, pour le clavier et les lecteurs d'écran, et ses règles
   d'affichage sont reposées ici, plus spécifiques que celles d'un thème. */
.fle-app .fle-ceco-option input[type="radio"] {
  /* !important, une fois n'est pas coutume : certains thèmes masquent les
     boutons radio par une règle qui l'emploie elle-même. */
  appearance: auto !important; -webkit-appearance: radio !important;
  display: inline-block !important; position: static !important; opacity: 1 !important; visibility: visible !important;
  width: 18px; height: 18px; min-width: 18px; margin: 2px 0 0; padding: 0;
  flex: 0 0 auto; accent-color: var(--accent); clip: auto !important; pointer-events: auto !important;
}
.fle-app .fle-ceco-option__lettre {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; border-radius: 50%;
  border: 1.5px solid var(--line);
}
.fle-app .fle-ceco-option--choisie .fle-ceco-option__lettre {
  background: var(--primary); border-color: var(--primary); color: var(--white);
}
/* Le contour au clavier seulement : un clic de souris n'en dessine pas. */
.fle-app .fle-ceco-option:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 1px; }
.fle-app .fle-ceco-alerte { color: var(--danger); font-weight: 650; }
.fle-app .fle-ceco-manques { margin: 6px 0 0 18px; list-style: disc; color: var(--danger); }
.fle-app .fle-ceco-manques li { margin: 3px 0; line-height: 1.45; }
.fle-app .fle-ceco-edit {
  margin: 12px 0 0; padding: 12px;
  border-radius: var(--radius-xs);
  background: var(--lavis-gris, #F4F7F7);
  border: 1px solid var(--line);
}
.fle-app .fle-ceco-bonne {
  display: inline-flex; align-items: center; gap: 5px;
  flex: 0 0 auto; padding: 0 8px 0 0;
  font-family: var(--data, var(--ui)); font-weight: 700; color: var(--muted);
}

/* Les trois documents de l'exercice 3, à l'oral : chacun son
   enregistrement, sa consigne et ses questions. Le filet à gauche
   rattache les questions au document, comme l'accolade du sujet papier. */
.fle-app .fle-ceco-piste {
  margin: 16px 0 0; padding: 2px 0 4px 14px;
  border-left: 3px solid var(--cerne);
}
.fle-app .fle-ceco-piste__titre {
  margin: 0 0 4px;
  font-family: var(--ui); font-size: 13px; font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase; color: var(--muted);
}
.fle-app .fle-ceco-piste .fle-ceco-q:first-of-type { border-top: 0; padding-top: 4px; }

/* La transcription, pour le formateur ou une fois la copie corrigée :
   repliée, parce qu'ouverte elle se lit avant d'écouter. */
.fle-app .fle-ceco-transcription {
  margin: 10px 0 0; padding: 8px 12px;
  border-radius: var(--radius-xs);
  border: 1px dashed var(--line);
}
.fle-app .fle-ceco-transcription summary {
  cursor: pointer; font-family: var(--ui); font-size: 13.5px; font-weight: 600; color: var(--ink);
}
.fle-app .fle-ceco-transcription[open] summary { margin-bottom: 8px; }

/* Les liens des enregistrements, en dehors de l'éditeur complet. */
.fle-app .fle-ceco-liens {
  margin: 10px 0 0; padding: 10px 12px;
  border-radius: var(--radius-xs);
  background: var(--lavis-gris, #F4F7F7);
  border: 1px solid var(--line);
}
.fle-app .fle-ceco-liens .fle-champ { width: 100%; max-width: 60ch; }

/* La banque : une ligne par épreuve, le bouton puis ce qui reste à faire. */
.fle-app .fle-ceco-banque { margin: 8px 0 0; }
.fle-app .fle-ceco-banque__ligne {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px;
  padding: 6px 0; border-bottom: 1px solid var(--line);
}
.fle-app .fle-ceco-banque__ligne:last-child { border-bottom: 0; }
.fle-app .fle-ceco-banque__ligne .fle-btn { text-align: left; white-space: normal; }

/* Les gestes du formateur sur une copie : une seconde écoute accordée,
   la copie rouverte. Ils passent à la ligne plutôt que de déborder. */
.fle-app .fle-ceco-copie__actions {
  display: flex; flex-wrap: wrap; gap: 6px; margin: 6px 0 0;
}
.fle-app .fle-ceco-copie__actions:empty { display: none; }

/* =========================================================================
   L'ÉCOUTE D'ÉPREUVE
   =========================================================================
   Une écoute qui ne peut pas être arrêtée doit dire ce qu'elle fait,
   sinon elle donne l'impression d'une panne. La jauge et le temps
   restant ne sont pas des commandes : on ne peut pas les saisir, et
   c'est volontaire - ils informent sans rien promettre.
   ====================================================================== */
.fle-app .fle-ecoute {
  margin: 10px 0 4px; padding: 12px 14px;
  border-radius: var(--radius-s);
  background: var(--white);
  border: 1px solid var(--cerne);
}
.fle-app .fle-ecoute--vive {
  border-color: var(--accent);
  border-left: 5px solid var(--accent);
  background: color-mix(in srgb, var(--accent) 6%, var(--white));
}
.fle-app .fle-ecoute__barre {
  margin-top: 10px; height: 8px; border-radius: 999px;
  background: var(--line); overflow: hidden;
}
.fle-app .fle-ecoute__jauge {
  height: 8px; width: 0;
  background: var(--accent);
  transition: width .25s linear;
}
.fle-app .fle-ecoute__temps {
  font-family: var(--data, var(--ui)); font-size: 13px; color: var(--muted);
  white-space: nowrap;
}
.fle-app .fle-ecoute__mot {
  font-family: var(--ui); font-size: 13px; line-height: 1.45; color: var(--muted);
  flex: 1 1 200px;
}
.fle-app .fle-ecoute__mot--erreur { color: var(--danger); font-weight: 600; }

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

/* Une épreuve ne s'imprime pas depuis ici : la copie appartient à
   l'apprenant, et un sujet imprimé circule. */
@media print {
  .fle-app .fle-ecoute { display: none; }
}


/* =========================================================================
   ACCESSIBILITÉ ET LISIBILITÉ (1.54)

   Ce qu'un audit RGAA a relevé, et qui se corrige sans refonte : des
   bordures de champs invisibles aux malvoyants, des étiquettes qui ne
   nommaient rien, des titres qui n'en étaient pas, des couleurs fixes
   pensées pour le thème clair et illisibles en sombre.
   ====================================================================== */

/* Les titres de l'application sont désormais de vrais titres (h2, h3),
   sans reprendre la taille ni les marges du thème hôte. */
.fle-app h2.fle-titre, .fle-app h3.fle-titre { margin: 0; padding: 0; line-height: 1.25; color: inherit; }
.fle-app h2.fle-titre:focus { outline: none; }
.fle-app h2.fle-titre:focus-visible { outline: 3px solid var(--accent); outline-offset: 4px; border-radius: var(--radius-xs); }
.fle-app h3.fle-etiquette, .fle-app h4.fle-etiquette { margin: 0 0 6px; padding: 0; line-height: 1.35; }

/* Lien d'évitement : invisible jusqu'au focus clavier, puis visible en tête. */
.fle-app .fle-evitement:focus, .fle-app .fle-evitement:focus-within {
  position: absolute; z-index: 10000; top: 8px; left: 8px;
  background: var(--accent-plein); color: #fff; text-decoration: none; font-weight: 650;
}

/* Champs : une frontière perceptible (au moins 3:1 sur le fond). */
.fle-app .fle-champ,
.fle-app select.fle-champ,
.fle-app textarea.fle-champ {
  border-color: color-mix(in srgb, var(--gris) 85%, var(--ink));
}
.fle-app .fle-champ:focus { border-color: var(--accent-plein); }
.fle-app .fle-btn--fantome { --btn-bord: color-mix(in srgb, var(--primary) 75%, var(--ink)); }
.fle-app .fle-btn--sourdine { --btn-bord: color-mix(in srgb, var(--gris) 85%, var(--ink)); }
.fle-app .fle-champ[aria-invalid="true"] { border-color: var(--danger); box-shadow: 0 0 0 2px color-mix(in srgb, var(--danger) 30%, transparent); }

/* Étiquettes liées, aide et mention obligatoire. */
.fle-app .fle-obligatoire { font-weight: 400; color: var(--muted); }
.fle-app .fle-aide { margin: 5px 0 0; font-size: 13px; line-height: 1.45; color: var(--muted); }

/* Confirmation en ligne, à côté du geste. */
.fle-app .fle-confirmation {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  margin-top: 8px; padding: 10px 12px;
  border: 1.5px solid var(--danger); border-radius: var(--radius-s);
  background: color-mix(in srgb, var(--danger) 8%, var(--white));
  flex-basis: 100%;
}
.fle-app .fle-confirmation__texte { flex: 1 1 240px; font-size: 14px; line-height: 1.45; }

/* L'apprenant sait qu'il est guidé. */
.fle-app .fle-sortie__suivi {
  font-size: 12.5px; font-weight: 650; color: var(--primary);
  padding: 4px 10px; border-radius: 999px;
  background: color-mix(in srgb, var(--primary) 12%, var(--white));
}

/* Le pied technique, replié pour l'apprenant. */
.fle-app .fle-technique__detail { display: flex; flex-wrap: wrap; gap: 10px 14px; align-items: center; margin-top: 6px; }
.fle-app .fle-technique__detail[hidden] { display: none; }

/* Le bouton-carte du lexique garde son apparence de carte. */
.fle-app button.fle-carte-mot {
  width: 100%; cursor: pointer; font: inherit; color: inherit; appearance: none;
}

/* Les textes lus par l'apprenant suivent le réglage de taille de lecture. */
.fle-app .fle-ceco-doc__texte, .fle-app .fle-ceco-q__enonce, .fle-app .fle-ceco-q__fin,
.fle-app .fle-ceco-option__texte,
.fle-app .fle-simple p, .fle-app .fle-amorce__protocole li, .fle-app .fle-tache__ligne {
  font-size: var(--t-lire);
}

/* Petits corps : 12,5 px est le plancher pour un public qui lit avec effort. */
.fle-app .fle-msg__meta, .fle-app .fle-badge, .fle-app .fle-technique, .fle-app .fle-marque { font-size: 12.5px; }
.fle-app .fle-cachet span { font-size: 11px; opacity: 1; }

/* Le focus ne change pas la forme des éléments ronds. */
.fle-app .fle-etape-puce:focus-visible, .fle-app .fle-couleur:focus-visible { border-radius: 50%; }

/* Zones défilantes atteignables au clavier : un liseré quand elles ont le focus. */
.fle-app .fle-extrait:focus-visible, .fle-app .fle-journal:focus-visible,
.fle-app .fle-delf-copie:focus-visible, .fle-app .fle-delf-rappel:focus-visible,
.fle-app .fle-apercu__corps:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }

/* Thème sombre : les libellés blancs sur l'accent passent à l'encre sombre,
   et les bordures de champs gardent leur contraste. */
.fle-app[data-fle-theme="sombre"] .fle-apercu__juste,
.fle-app[data-fle-theme="sombre"] .fle-tel__numero,
.fle-app[data-fle-theme="sombre"] .fle-oral-relances li::before,
.fle-app[data-fle-theme="sombre"] .fle-annonce--erreur { color: #0E1716; }
.fle-app[data-fle-theme="sombre"] .fle-champ,
.fle-app[data-fle-theme="sombre"] select.fle-champ,
.fle-app[data-fle-theme="sombre"] textarea.fle-champ { border-color: #6E7F7E; }
@media (prefers-color-scheme: dark) {
  .fle-app[data-fle-theme="systeme"] .fle-apercu__juste,
  .fle-app[data-fle-theme="systeme"] .fle-tel__numero,
  .fle-app[data-fle-theme="systeme"] .fle-oral-relances li::before,
  .fle-app[data-fle-theme="systeme"] .fle-annonce--erreur { color: #0E1716; }
  .fle-app[data-fle-theme="systeme"] .fle-champ,
  .fle-app[data-fle-theme="systeme"] select.fle-champ,
  .fle-app[data-fle-theme="systeme"] textarea.fle-champ { border-color: #6E7F7E; }
}

/* Sans color-mix() (navigateurs anciens des salles informatiques), les
   dérivés de la palette deviennent invalides : un repli en couleurs fixes
   évite les boutons sans fond et le texte blanc sur blanc. */
@supports not (color: color-mix(in srgb, red, blue)) {
  .fle-app { --accent-plein: #17807E; --cerne: #C9D3D2; --lavis-gris: #EEF2F1; }
  .fle-app .fle-champ, .fle-app select.fle-champ, .fle-app textarea.fle-champ { border-color: #7C7E7D; }
  .fle-app .fle-btn--accent { background: #17807E; border-color: #17807E; color: #fff; }
  .fle-app .fle-btn--fantome { border-color: #4A7C7A; }
  .fle-app .fle-ceco-option--bonne { background: #E8F6EC; border-color: #1E7A3C; }
  .fle-app .fle-ceco-option--fausse { background: #FCEDEB; border-color: #B5342A; }
  .fle-app .fle-confirmation { background: #FBEDEB; }
}


/* =========================================================================
   COURS DE CONVERSATION : LA DIDACTIQUE DE L'ORAL (1.55)

   Les blocs que toute séance reçoit : mot du jour, mots apportés, document
   déclencheur, ménagement, écoute, autres voix, temps de parole, carnet,
   retour de langue, observation.
   ====================================================================== */
.fle-app .fle-oral { margin-top: 12px; padding-top: 10px; border-top: 1px dashed var(--line); }
.fle-app .fle-oral > .fle-etiquette { margin-bottom: 4px; }
.fle-app .fle-question-vive--joker { margin-top: 8px; }
.fle-app .fle-oral__jokers { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.fle-app .fle-oral__jokers .fle-btn { text-align: left; white-space: normal; line-height: 1.35; }
.fle-app .fle-mot-du-jour { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; padding: 8px 12px; border-radius: var(--radius-s); background: color-mix(in srgb, var(--accent) 10%, var(--white)); border: 1px solid color-mix(in srgb, var(--accent) 40%, var(--white)); }
.fle-app .fle-mot-du-jour strong { font-size: 1.1em; }
.fle-app .fle-mot--mien { display: inline-flex; align-items: center; gap: 4px; }
.fle-app .fle-mot__retirer { appearance: none; border: 0; background: none; cursor: pointer; font: inherit; color: var(--muted); padding: 0 2px; min-width: 24px; min-height: 24px; }
.fle-app .fle-mot__retirer:hover { color: var(--danger); }
.fle-app .fle-doc-declencheur { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.fle-app .fle-menagement__acte { margin-top: 6px; }
.fle-app .fle-ecoute-avant { padding: 10px 12px; border-radius: var(--radius-s); background: color-mix(in srgb, var(--primary) 8%, var(--white)); }
.fle-app .fle-regards { margin-top: 10px; }
.fle-app .fle-parole__compte { font-family: var(--data, var(--ui)); }
.fle-app .fle-retour-langue { list-style: none; padding: 0; margin: 6px 0 0; }
.fle-app .fle-retour-langue li { display: grid; gap: 2px; padding: 8px 0; border-bottom: 1px solid var(--line); }
.fle-app .fle-retour-langue__dit { color: var(--muted); }
.fle-app .fle-retour-langue__mieux { font-weight: 650; }
.fle-app .fle-obs { margin-top: 10px; padding: 10px 12px; border: 1px solid var(--line); border-radius: var(--radius-s); background: var(--white); }
.fle-app .fle-obs__grille { display: grid; gap: 6px; margin-top: 6px; }
.fle-app .fle-obs__ligne { display: grid; grid-template-columns: minmax(140px, 1.4fr) repeat(3, minmax(0, 1fr)); gap: 6px; align-items: center; }
.fle-app .fle-obs__nom { font-size: 13.5px; }
.fle-app .fle-obs__deg { font-size: 13px; display: flex; align-items: center; gap: 4px; min-height: 24px; }
@media (max-width: 560px) {
  .fle-app .fle-obs__ligne { grid-template-columns: 1fr; }
  .fle-app .fle-obs__ligne .fle-obs__deg { display: inline-flex; margin-right: 10px; }
}
.fle-app .fle-outils-oral { margin-top: 10px; }


/* =========================================================================
   PARCOURS DE MÉTHODE : L'ÉCRIT DU DELF B2 (1.63)

   Des formes d'étape qui travaillent sur des textes entiers : une lettre
   à découper, des formules à classer, des paragraphes à remettre en ordre,
   une copie à relire, une production à écrire. Les textes s'affichent dans
   la police de lecture et sur un fond de page : l'apprenant doit y
   reconnaître une lettre, et non une suite de champs de formulaire.
   ====================================================================== */

/* Le ruban des phases */
.fle-app .fle-phases {
  list-style: none; margin: 10px 0 2px; padding: 0;
  display: flex; flex-wrap: wrap; gap: 6px;
}
.fle-app .fle-phases__item {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px 4px 5px; border-radius: 999px;
  font-size: 13px; color: var(--muted);
  background: var(--lavis-gris); border: 1px solid var(--line);
}
.fle-app .fle-phases__num {
  display: inline-grid; place-items: center; width: 20px; height: 20px; border-radius: 50%;
  font-size: 12px; font-weight: 700; background: var(--white); border: 1px solid var(--line);
}
.fle-app .fle-phases__item--faite { color: var(--primary); }
.fle-app .fle-phases__item--faite .fle-phases__num { border-color: var(--accent); }
.fle-app .fle-phases__item--courante {
  color: var(--ink); font-weight: 650;
  background: var(--lavis-fort); border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
}
.fle-app .fle-phases__item--courante .fle-phases__num { background: var(--accent-plein); border-color: var(--accent-plein); color: #fff; }
.fle-app .fle-methode__chapeau { margin: 4px 2px 8px; }

/* Fiche de méthode : un liseré la distingue d'une leçon de grammaire. */
.fle-app .fle-fiche-methode { border-top: 3px solid var(--accent); }

/* Verdicts : une teinte légère sur le bloc corrigé, doublée du verdict
   écrit en toutes lettres juste en dessous. */
.fle-app .fle-methode--juste { background: color-mix(in srgb, var(--succes) 7%, var(--white)); }
.fle-app .fle-methode--faux  { background: color-mix(in srgb, var(--alerte) 9%, var(--white)); }
.fle-app .fle-methode__retour:empty { display: none; }
.fle-app .fle-methode__bilan {
  margin-top: 12px; padding: 10px 13px; border-radius: var(--radius-s);
  background: var(--lavis-fort); color: var(--ink);
}
.fle-app .fle-methode__ligne { display: block; }
.fle-app .fle-methode__choix { max-width: 420px; margin-top: 6px; }

/* Étiquettes : extraits */
.fle-app .fle-methode__extrait {
  margin-top: 12px; padding: 12px 14px; border-radius: var(--radius-s);
  background: var(--white); border: 1px solid var(--cerne, var(--line));
}
.fle-app .fle-methode__citation {
  margin: 0; padding: 0 0 0 12px; border-left: 3px solid var(--line);
  font-family: var(--texte); font-size: 16px; line-height: 1.55; color: var(--ink);
}

/* Étiquettes : la lettre sur sa page */
.fle-app .fle-lettre {
  margin-top: 12px; padding: 22px 24px; border-radius: 4px;
  background: var(--white); border: 1px solid var(--line); box-shadow: var(--ombre-2);
  font-family: var(--texte); font-size: 15.5px; line-height: 1.5; color: var(--ink);
}
.fle-app .fle-lettre__bloc { margin-top: 14px; padding: 6px 8px; border-radius: var(--radius-xs); }
.fle-app .fle-lettre__bloc:first-child { margin-top: 0; }
.fle-app .fle-lettre__bloc--gauche { max-width: 62%; }
.fle-app .fle-lettre__bloc--droite { margin-left: auto; max-width: 62%; text-align: right; }
.fle-app .fle-lettre__bloc--droite .fle-lettre__choix { justify-content: flex-end; }
.fle-app .fle-lettre__bloc--retrait { padding-left: 2.2em; }
.fle-app .fle-lettre__choix { display: flex; align-items: center; gap: 8px; margin-top: 4px; font-family: var(--ui); }
.fle-app .fle-lettre__choix .fle-methode__choix { margin-top: 0; font-size: 14px; }
.fle-app .fle-lettre__num {
  display: inline-grid; place-items: center; flex: none; width: 22px; height: 22px; border-radius: 50%;
  font-size: 12px; font-weight: 700; color: var(--primary); background: var(--lavis-fort);
}
.fle-app .fle-lettre .fle-alerte { font-family: var(--ui); text-align: left; }

/* Étiquettes : tableau de méthode */
.fle-app .fle-methode__paires { margin-top: 12px; display: grid; gap: 8px; }
.fle-app .fle-methode__paire {
  display: grid; grid-template-columns: minmax(150px, .8fr) minmax(0, 2fr); gap: 12px; align-items: start;
  padding: 10px 12px; border-radius: var(--radius-s); background: var(--white); border: 1px solid var(--line);
}
.fle-app .fle-methode__paire--tete {
  background: none; border: 0; padding: 0 12px;
  font-size: 13px; font-weight: 650; color: var(--muted); text-transform: uppercase; letter-spacing: .03em;
}
.fle-app .fle-methode__paire .fle-methode__choix { max-width: none; width: 100%; margin-top: 0; }
@media (max-width: 640px) {
  .fle-app .fle-methode__paire { grid-template-columns: 1fr; gap: 6px; }
  .fle-app .fle-methode__paire--tete { display: none; }
  .fle-app .fle-lettre { padding: 16px 14px; }
  .fle-app .fle-lettre__bloc--gauche, .fle-app .fle-lettre__bloc--droite { max-width: none; }
}

/* Classement */
.fle-app .fle-tri { margin-top: 10px; display: grid; gap: 8px; }
.fle-app .fle-tri__ligne {
  margin: 0; padding: 10px 12px; min-width: 0;
  border: 1px solid var(--line); border-radius: var(--radius-s); background: var(--white);
}
.fle-app .fle-tri__formule {
  padding: 0; float: left; width: 100%;
  font-family: var(--texte); font-size: 15.5px; line-height: 1.45; color: var(--ink);
}
.fle-app .fle-tri__choix { clear: both; display: flex; flex-wrap: wrap; gap: 6px; padding-top: 8px; }
.fle-app .fle-tri__puce {
  display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
  min-height: 32px; padding: 4px 11px 4px 8px; border-radius: 999px;
  font-size: 14px; border: 1px solid var(--line); background: var(--paper);
}
.fle-app .fle-tri__puce input { margin: 0; accent-color: var(--accent-plein); }
.fle-app .fle-tri__puce:has(input:checked) {
  background: var(--lavis-fort); border-color: var(--accent); font-weight: 650;
}
.fle-app .fle-tri__puce:has(input:focus-visible) { outline: 3px solid var(--accent); outline-offset: 2px; }
.fle-app .fle-tri__puce--attendue { border-color: var(--succes); }
.fle-app .fle-tri__puce--attendue::after { content: "✓"; color: var(--succes); font-weight: 700; }
.fle-app .fle-tri__puce--fausse { border-color: var(--alerte); text-decoration: line-through; }
.fle-app .fle-tri__colonnes {
  margin-top: 10px; display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
}
.fle-app .fle-tri__colonne {
  padding: 10px 12px; border-radius: var(--radius-s);
  background: var(--paper); border: 1px solid var(--line);
}

/* Ordre */
.fle-app .fle-ordre { list-style: none; margin: 12px 0 0; padding: 0; display: grid; gap: 8px; }
.fle-app .fle-ordre__item {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 10px 12px; border-radius: var(--radius-s);
  background: var(--white); border: 1px solid var(--line);
}
.fle-app .fle-ordre__num {
  display: inline-grid; place-items: center; flex: none; width: 26px; height: 26px; border-radius: 50%;
  font-weight: 700; color: var(--primary); background: var(--lavis-fort);
}
.fle-app .fle-ordre__texte { flex: 1; min-width: 0; font-family: var(--texte); font-size: 15.5px; line-height: 1.5; }
.fle-app .fle-ordre__role { display: block; margin-top: 4px; font-family: var(--ui); font-size: 13.5px; color: var(--muted); }
.fle-app .fle-ordre__fleches { display: flex; flex-direction: column; gap: 4px; flex: none; }
.fle-app .fle-ordre__fleches .fle-btn { min-width: 40px; }
.fle-app .fle-ordre__corrige { margin-top: 8px; }
.fle-app .fle-ordre__corrige li { margin-top: 4px; }

/* Relecture */
.fle-app .fle-relecture {
  margin-top: 12px; padding: 20px 22px; border-radius: 4px;
  background: var(--white); border: 1px solid var(--line); box-shadow: var(--ombre-2);
  font-family: var(--texte); font-size: 16px; line-height: 1.7; color: var(--ink);
}
.fle-app .fle-relecture__par { margin: 0 0 10px; }
.fle-app .fle-relecture__par:last-child { margin-bottom: 0; }
.fle-app .fle-releve {
  appearance: none; display: inline; margin: 0; padding: 1px 2px; border: 0; border-radius: 3px;
  font: inherit; color: inherit; text-align: left; cursor: pointer;
  background: none; border-bottom: 2px dotted color-mix(in srgb, var(--accent) 60%, var(--line));
  -webkit-box-decoration-break: clone; box-decoration-break: clone;
}
.fle-app .fle-releve:hover:not([disabled]) { background: var(--lavis); }
.fle-app .fle-releve:focus-visible { outline: 3px solid var(--accent); outline-offset: 1px; }
.fle-app .fle-releve[aria-pressed="true"] {
  background: color-mix(in srgb, var(--alerte) 16%, var(--white));
  border-bottom: 2px solid var(--alerte);
}
.fle-app .fle-releve[disabled] { cursor: default; }
.fle-app .fle-releve.fle-releve--faute { border-bottom: 2px solid var(--danger); }
.fle-app .fle-releve.fle-releve--correct { border-bottom: 2px solid var(--succes); }
.fle-app .fle-releve.fle-methode--juste { background: color-mix(in srgb, var(--succes) 10%, var(--white)); }
.fle-app .fle-releve.fle-methode--faux { background: color-mix(in srgb, var(--alerte) 16%, var(--white)); }
.fle-app .fle-releve__num { margin-left: 2px; font-family: var(--ui); font-size: 11px; font-weight: 700; color: var(--primary); }
.fle-app .fle-relecture__notes { margin: 10px 0 0; padding-left: 22px; }
.fle-app .fle-relecture__notes li { margin-top: 6px; line-height: 1.45; }
.fle-app .fle-relecture__note--juste strong { color: var(--succes); }
.fle-app .fle-relecture__note--faux strong { color: var(--alerte); }

/* Rédaction */
.fle-app .fle-sujets { margin: 12px 0 0; padding: 0; border: 0; display: grid; gap: 8px; min-width: 0; }
.fle-app .fle-sujets legend { padding: 0; margin-bottom: 6px; font-weight: 650; }
.fle-app .fle-sujet {
  display: flex; gap: 10px; align-items: flex-start; cursor: pointer;
  padding: 12px 14px; border-radius: var(--radius-s); background: var(--white); border: 1px solid var(--line);
}
.fle-app .fle-sujet:hover { border-color: var(--accent); }
.fle-app .fle-sujet input { margin-top: 4px; accent-color: var(--accent-plein); }
.fle-app .fle-sujet__consigne { display: block; margin-top: 4px; font-family: var(--texte); font-size: 15px; line-height: 1.5; color: var(--ink); }
.fle-app .fle-sujet-choisi {
  margin-top: 12px; padding: 12px 14px; border-radius: var(--radius-s);
  background: var(--lavis); border: 1px solid color-mix(in srgb, var(--accent) 25%, var(--line));
}
.fle-app .fle-redaction__plan {
  margin-top: 12px; display: grid; gap: 14px; align-items: start;
  grid-template-columns: minmax(0, 1.75fr) minmax(230px, 1fr);
}
.fle-app .fle-redaction__libelle { display: block; font-weight: 650; margin-bottom: 6px; }
.fle-app textarea.fle-redaction__texte,
.fle-app .fle-redaction__texte {
  width: 100%; min-height: 380px; resize: vertical;
  font-family: var(--texte); font-size: 16px; line-height: 1.6;
}
.fle-app .fle-redaction__compte { margin-top: 4px; font-size: 14px; color: var(--muted); }
.fle-app .fle-redaction__compte--ok { color: var(--succes); font-weight: 650; }
.fle-app .fle-redaction .fle-jauge { margin-top: 8px; }
.fle-app .fle-boite {
  padding: 12px; border-radius: var(--radius-s);
  background: var(--paper); border: 1px solid var(--line);
  max-height: 560px; overflow: auto;
}
.fle-app .fle-boite .fle-soustitre { margin-top: 2px; font-size: 13px; }
.fle-app .fle-boite__groupe { margin-top: 8px; }
.fle-app .fle-boite__groupe summary { cursor: pointer; font-weight: 650; padding: 4px 0; }
.fle-app .fle-boite__formule {
  display: block; width: 100%; margin-top: 5px; padding: 7px 9px; cursor: pointer;
  text-align: left; font: inherit; font-size: 14px; line-height: 1.4; color: var(--ink);
  background: var(--white); border: 1px solid var(--line); border-radius: var(--radius-xs);
}
.fle-app .fle-boite__formule:hover { border-color: var(--accent); background: var(--lavis); }
.fle-app .fle-boite__formule:focus-visible { outline: 3px solid var(--accent); outline-offset: 1px; }
.fle-app .fle-boite__aide { font-style: italic; color: var(--muted); }
.fle-app .fle-redaction__relecture:empty { display: none; }
.fle-app .fle-redaction__relecture { margin-top: 12px; padding: 12px 14px; border-radius: var(--radius-s); background: var(--white); border: 1px solid var(--line); }
.fle-app .fle-controles { list-style: none; margin: 8px 0 0; padding: 0; display: grid; gap: 6px; }
.fle-app .fle-controles li { display: grid; grid-template-columns: 24px minmax(0, 1fr); gap: 8px; align-items: start; }
.fle-app .fle-controles li strong { display: block; }
.fle-app .fle-controles li span:not(.fle-controles__signe) { font-size: 14px; color: var(--muted); }
.fle-app .fle-controles__signe {
  display: inline-grid; place-items: center; width: 22px; height: 22px; border-radius: 50%;
  font-weight: 700; font-size: 13px; color: #fff;
}
.fle-app .fle-controles__ok .fle-controles__signe { background: var(--succes); }
.fle-app .fle-controles__non .fle-controles__signe { background: var(--alerte); }
.fle-app .fle-autoeval { display: block; margin: 12px 0 0; padding: 12px 14px; border: 1px solid var(--line); border-radius: var(--radius-s); min-width: 0; }
.fle-app .fle-autoeval legend { padding: 0 4px; font-weight: 650; }
.fle-app .fle-autoeval__ligne { display: flex; gap: 8px; margin-top: 6px; align-items: flex-start; cursor: pointer; line-height: 1.45; }
.fle-app .fle-autoeval__ligne input { margin-top: 3px; accent-color: var(--accent-plein); }
@media (max-width: 820px) {
  .fle-app .fle-redaction__plan { grid-template-columns: 1fr; }
  .fle-app .fle-boite { max-height: none; }
  .fle-app .fle-redaction__texte { min-height: 300px; }
}

/* La production, lue par le formateur */
.fle-app .fle-copie-lue {
  margin-top: 8px; padding: 12px 14px; border-radius: var(--radius-s);
  background: var(--paper); border: 1px solid var(--line);
}
.fle-app .fle-copie-lue__texte {
  margin-top: 10px; padding: 16px 18px; max-height: 460px; overflow: auto;
  white-space: pre-wrap; overflow-wrap: anywhere;
  font-family: var(--texte); font-size: 15.5px; line-height: 1.6; color: var(--ink);
  background: var(--white); border: 1px solid var(--line); border-radius: 4px;
}
.fle-app .fle-copie-lue__texte:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }
.fle-app .fle-apercu__item--neutre { background: var(--white); }

/* Thème sombre : les pastilles pleines gardent un libellé lisible. */
.fle-app[data-fle-theme="sombre"] .fle-controles__signe,
.fle-app[data-fle-theme="sombre"] .fle-phases__item--courante .fle-phases__num { color: #0E1716; }
@media (prefers-color-scheme: dark) {
  .fle-app[data-fle-theme="systeme"] .fle-controles__signe,
  .fle-app[data-fle-theme="systeme"] .fle-phases__item--courante .fle-phases__num { color: #0E1716; }
}
@media print {
  .fle-app .fle-boite, .fle-app .fle-ordre__fleches { display: none; }
}

/* =========================================================================
   TABLEAU DE BORD (1.64)

   L'accueil devient un tableau de bord, et l'application change de
   matière : un fond gris sarcelle très pâle, des panneaux à peine teintés,
   des cartes blanches posées dessus. La palette ne bouge pas - sarcelle,
   sarcelle profonde, gris - et la hiérarchie vient toujours de la valeur.

   La barre n'en fait plus qu'une : la marque, les rubriques en pilules et
   les initiales de la personne sur une carte blanche, la salle (code,
   présence, sortie) juste dessous. Les deux restent collées en haut.

   Les noms de classes anciens sont tous gardés ; les nouveaux portent le
   préfixe fle-tdb- (tableau de bord), fle-entete, ou un élément de bloc
   neuf (fle-nav__marque, fle-tuile__icone…).
   ====================================================================== */

.fle-app {
  --tdb-fond:    color-mix(in srgb, var(--paper) 72%, var(--line));
  --tdb-panneau: color-mix(in srgb, var(--white) 45%, var(--tdb-fond));
  --tdb-r-l: 26px;
  --tdb-r-m: 18px;
  background: var(--tdb-fond);
  border: 0;
  border-radius: var(--tdb-r-l);
  padding: clamp(6px, 1vw, 12px);
}
.fle-app[data-fle-theme="sombre"] { --tdb-fond: var(--paper); }
@media (prefers-color-scheme: dark) {
  .fle-app[data-fle-theme="systeme"] { --tdb-fond: var(--paper); }
}

/* Le filet Seyès et le quadrillage se retirent : le fond uni porte les
   cartes, et deux motifs sous des cartes arrondies se contrarient. */
.fle-app .fle-seyes { display: none; }
.fle-app .fle-corps,
.fle-app[data-fle-theme] .fle-corps { background-image: none; padding: 18px 6px 6px; }

/* --- L'en-tête --------------------------------------------------------- */
.fle-app .fle-entete {
  position: sticky; top: 0; z-index: 30;
  background: var(--tdb-fond);
  padding-bottom: 2px;
}
.fle-app .fle-entete .fle-nav {
  background: var(--white); border: 0;
  border-radius: 20px; box-shadow: var(--ombre-1);
}
.fle-app .fle-entete .fle-nav__barre {
  align-items: center; gap: 4px; flex-wrap: nowrap;
  padding: 8px 10px 8px 12px;
}
.fle-app .fle-nav__marque { display: flex; align-items: center; gap: 10px; margin-right: 12px; min-width: 0; flex: 0 1 auto; }
.fle-app .fle-nav__logo {
  width: 38px; height: 38px; border-radius: 12px; flex: 0 0 auto;
  display: grid; place-items: center;
  background: var(--accent-plein); color: #fff;
}
.fle-app .fle-nav__logo svg { width: 22px; height: 22px; display: block; }
.fle-app .fle-nav__marque-texte { min-width: 0; line-height: 1.2; }
.fle-app .fle-nav__marque-texte strong { display: block; font-size: 15.5px; font-weight: 700; color: var(--ink); white-space: nowrap; }
.fle-app .fle-nav__marque-texte small {
  display: block; max-width: 210px; font-size: 12.5px; color: var(--muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* Les rubriques : des pilules. La courante n'a plus de filet dessous mais
   un fond - sarcelle profonde pour l'accueil, lavis pour une rubrique. */
.fle-app .fle-entete .fle-nav__menu { flex: 1 1 auto; align-items: center; gap: 2px; flex-wrap: nowrap; min-width: 0; }
.fle-app .fle-entete .fle-nav__accueil,
.fle-app .fle-entete .fle-nav__rubrique,
.fle-app .fle-entete .fle-nav__outil {
  border: 0; border-radius: var(--radius-pilule);
  padding: 9px 15px; font-size: 14.5px; font-weight: 600; white-space: nowrap;
  display: inline-flex; align-items: center; gap: 6px;
}
.fle-app .fle-entete .fle-nav__accueil { color: var(--ink); }
.fle-app .fle-entete .fle-nav__accueil--actif,
.fle-app .fle-entete .fle-nav__accueil--actif:hover { background: var(--primary); color: var(--white); }
.fle-app .fle-entete .fle-nav__rubrique--actif { background: var(--lavis-fort); color: var(--primary); }
.fle-app .fle-entete .fle-nav__rubrique[aria-expanded="true"],
.fle-app .fle-entete .fle-nav__outil[aria-expanded="true"] { background: var(--lavis-fort); color: var(--primary); }
.fle-app .fle-entete .fle-nav__separateur { margin: 0 0 0 auto; width: 0; background: none; }
.fle-app .fle-nav__picto { display: inline-flex; }
.fle-app .fle-nav__picto svg { width: 18px; height: 18px; display: block; }
.fle-app .fle-entete .fle-nav__outil--recherche {
  min-width: 170px; color: var(--muted); font-weight: 500;
  background: color-mix(in srgb, var(--paper) 60%, var(--white));
  box-shadow: inset 0 0 0 1px var(--line);
}
.fle-app .fle-entete .fle-nav__outil--reglages {
  width: 40px; height: 40px; padding: 0; justify-content: center;
  box-shadow: inset 0 0 0 1px var(--line); color: var(--primary);
}
.fle-app .fle-nav__outil-libelle {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
.fle-app .fle-nav__moi {
  width: 40px; height: 40px; border-radius: 50%; flex: 0 0 auto; margin-left: 6px;
  display: grid; place-items: center;
  background: var(--lavis-fort); color: var(--primary);
  font-size: 14px; font-weight: 700; letter-spacing: .02em;
}
/* Sans salle : la marque seule. */
.fle-app .fle-nav--sans-salle .fle-nav__accueil,
.fle-app .fle-nav--sans-salle .fle-nav__burger,
.fle-app .fle-nav--sans-salle .fle-nav__menu { display: none !important; }

.fle-app .fle-entete .fle-nav__panneau {
  background: transparent; box-shadow: none;
  border-top: 1px solid var(--line);
  border-radius: 0 0 20px 20px;
  padding: 14px 14px 16px;
}

/* La barre de la salle, sous la navigation : plus une barre, une ligne. */
.fle-app .fle-entete .fle-bar {
  position: static; background: transparent; border: 0; box-shadow: none;
  padding: 10px 6px 4px; gap: 10px; font-size: 13.5px; color: var(--muted);
}
.fle-app .fle-bar__salle { display: inline-flex; align-items: center; gap: 8px; }
.fle-app .fle-bar--sans-salle .fle-bar__salle { display: none; }
.fle-app .fle-bar__qui strong { color: var(--ink); font-weight: 650; }
.fle-app .fle-bar__qui .fle-lien { margin-left: 6px; font-size: 13px; }
.fle-app .fle-entete .fle-bar .fle-bar__sortie,
.fle-app .fle-entete .fle-bar .fle-bar__sortie--vif,
.fle-app .fle-entete .fle-bar .fle-bar__sortie--quitter {
  background: var(--white); color: var(--primary);
  border: 0; border-radius: var(--radius-pilule);
  box-shadow: inset 0 0 0 1.5px var(--line);
  padding: 7px 15px; font-size: 13.5px; font-weight: 650;
}
.fle-app .fle-entete .fle-bar .fle-bar__sortie:hover { box-shadow: inset 0 0 0 1.5px var(--accent); text-decoration: none; filter: none; }
/* Le niveau CECRL : une pastille, plus un tampon. Le tampon garde son
   animation quand le niveau change. */
.fle-app .fle-entete .fle-cachet {
  display: inline-flex; flex-direction: row; align-items: baseline; gap: 5px;
  width: auto; height: auto; min-width: 0; padding: 5px 12px; transform: none;
  border: 0; border-radius: var(--radius-pilule);
  background: var(--lavis-fort); color: var(--primary); box-shadow: none;
}
.fle-app .fle-entete .fle-cachet strong { font-size: 14px; }
.fle-app .fle-entete .fle-cachet span { font-size: 10.5px; }
.fle-app .fle-entete .fle-cachet--vide { background: var(--white); color: var(--muted); box-shadow: inset 0 0 0 1px var(--line); }
@media (max-width: 1020px) { .fle-app .fle-entete .fle-role { display: none; } }

/* --- L'en-tête de l'accueil -------------------------------------------- */
.fle-app .fle-tdb-bonjour { margin: 2px 4px 18px; }
.fle-app .fle-tdb-bonjour .fle-tdb-bonjour__titre {
  font-size: clamp(26px, 3vw, 38px); font-weight: 560; letter-spacing: -.02em; line-height: 1.12;
  margin: 0;
}
.fle-app .fle-tdb-bonjour .fle-soustitre { margin-top: 6px; font-size: 15px; }
.fle-app .fle-tdb > .fle-alerte { margin: 0 0 14px; }

/* --- La grille du tableau ---------------------------------------------- */
.fle-app .fle-tdb-grille {
  display: grid; gap: 18px; align-items: stretch;
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
}
.fle-app .fle-tdb-grille--seule { grid-template-columns: minmax(0, 1fr); }
.fle-app .fle-tdb-colonne { display: grid; gap: 18px; align-content: start; min-width: 0; }
.fle-app .fle-tdb-colonne > .fle-carte + .fle-carte { margin-top: 0; }
@media (max-width: 900px) {
  .fle-app .fle-tdb-grille { grid-template-columns: minmax(0, 1fr); }
  /* Une seule colonne : les blocs se suivent dans l'ordre du balisage
     (ce qui attend, puis la carte à la une et les outils). Chez le
     formateur, seule la carte du code remonte en tête : c'est ce qu'on
     cherche en début de cours. */
  .fle-app .fle-tdb-colonne { display: contents; }
  .fle-app .fle-tdb-grille--une-dabord .fle-tdb-une { order: -1; }
}

.fle-app .fle-tdb-panneau {
  background: var(--tdb-panneau); border-radius: var(--tdb-r-l);
  padding: 18px; margin: 0;
}
.fle-app .fle-tdb-panneau__tete { display: flex; align-items: center; gap: 10px; margin: 0 4px 14px; }
.fle-app .fle-tdb-panneau__titre { margin: 0; font-size: 20px; font-weight: 600; letter-spacing: -.01em; color: var(--ink); }
.fle-app .fle-tdb-panneau__compte { margin-left: auto; font-size: 13px; color: var(--muted); }
.fle-app .fle-tdb-vide {
  margin: 0; padding: 16px; border-radius: var(--tdb-r-m);
  background: var(--white); color: var(--muted); font-size: 14.5px;
}

.fle-app .fle-tdb-ligne {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto auto; align-items: center; gap: 14px;
  width: 100%; text-align: left; color: var(--ink);
  background: var(--white); border: 0; border-radius: var(--tdb-r-m);
  padding: 14px 16px; box-shadow: var(--ombre-1);
  transition: box-shadow .15s ease;
}
.fle-app .fle-tdb-ligne + .fle-tdb-ligne { margin-top: 10px; }
.fle-app .fle-tdb-ligne:hover { box-shadow: var(--ombre-2); }
.fle-app .fle-tdb-ligne__titre { display: block; font-size: 15.5px; font-weight: 650; }
.fle-app .fle-tdb-ligne__sous { display: block; margin-top: 2px; font-size: 13px; color: var(--muted); }
.fle-app .fle-tdb-icone,
.fle-app .fle-tuile__icone {
  width: 46px; height: 46px; border-radius: 14px; flex: 0 0 auto;
  display: grid; place-items: center;
  background: var(--lavis-fort); color: var(--primary);
}
.fle-app .fle-tdb-icone svg { width: 24px; height: 24px; display: block; }
.fle-app .fle-tdb-pastille {
  border-radius: var(--radius-pilule); padding: 3px 10px; white-space: nowrap;
  font-size: 12.5px; font-weight: 650;
  background: var(--lavis-fort); color: var(--primary);
}
.fle-app .fle-tdb-fleche {
  width: 38px; height: 38px; border-radius: 50%; flex: 0 0 auto;
  display: grid; place-items: center; background: var(--lavis); color: var(--primary);
}
.fle-app .fle-tdb-fleche svg { width: 18px; height: 18px; display: block; }

/* --- La carte à la une : le seul aplat sombre de l'écran ---------------- */
.fle-app .fle-tdb-une {
  position: relative; overflow: hidden;
  display: flex; flex-direction: column; gap: 10px;
  min-height: 210px; padding: 22px;
  border-radius: var(--tdb-r-l); color: #fff;
  background: linear-gradient(150deg, #155F5F 0%, #0C3534 60%, #0A2928 100%);
}
.fle-app .fle-tdb-une::after {
  content: ""; position: absolute; right: -60px; top: -60px; width: 220px; height: 220px;
  border-radius: 50%; pointer-events: none;
  background: radial-gradient(circle, rgba(27,138,138,.55), transparent 70%);
}
.fle-app .fle-tdb-une__sur { position: relative; z-index: 1; font-size: 13px; font-weight: 600; color: #A9D3D2; padding-right: 52px; }
.fle-app .fle-tdb-une__titre { position: relative; z-index: 1; font-size: 26px; font-weight: 560; line-height: 1.15; letter-spacing: -.01em; max-width: 16ch; }
.fle-app .fle-tdb-une__code {
  position: relative; z-index: 1;
  font-size: clamp(32px, 3.4vw, 42px); font-weight: 700; letter-spacing: .16em; line-height: 1.1;
}
.fle-app .fle-tdb-une__note { position: relative; z-index: 1; font-size: 13.5px; color: #CFE6E5; }
.fle-app .fle-tdb-une__pied { position: relative; z-index: 1; margin-top: auto; display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.fle-app .fle-tdb-une__bouton {
  border: 0; border-radius: var(--radius-pilule); padding: 9px 18px;
  background: #fff; color: #0F5F60; font-size: 14px; font-weight: 650;
}
.fle-app .fle-tdb-une__bouton:hover { text-decoration: underline; text-underline-offset: 2px; }
.fle-app .fle-tdb-une__bouton--voile { background: rgba(255,255,255,.12); color: #fff; box-shadow: inset 0 0 0 1px rgba(255,255,255,.3); }
.fle-app .fle-tdb-une button:focus-visible { outline: 3px solid #fff; outline-offset: 2px; }
.fle-app .fle-tdb-une__coin {
  position: absolute; top: 18px; right: 18px; z-index: 1;
  width: 42px; height: 42px; border-radius: 50%;
  display: grid; place-items: center; background: #fff; color: #0F5F60;
}
.fle-app .fle-tdb-une__coin svg { width: 20px; height: 20px; display: block; }
.fle-app[data-fle-theme="sombre"] .fle-tdb-une { box-shadow: inset 0 0 0 1px rgba(95,201,196,.25); }

/* --- Niveau, outils du formateur, liens repliés ------------------------- */
.fle-app .fle-tdb-niveau {
  display: flex; align-items: center; gap: 16px;
  background: var(--white); border-radius: var(--tdb-r-m); padding: 16px; box-shadow: var(--ombre-1);
}
.fle-app .fle-tdb-niveau__lettre {
  width: 72px; height: 72px; border-radius: 20px; flex: 0 0 auto;
  display: grid; place-items: center;
  background: var(--lavis-fort); color: var(--primary); font-size: 28px; font-weight: 750;
}
.fle-app .fle-tdb-niveau p { margin: 4px 0 0; font-size: 14px; line-height: 1.45; color: var(--muted); }
.fle-app .fle-tdb-outil { margin: 0; border: 0; border-radius: var(--tdb-r-m); }
.fle-app .fle-tdb-replie {
  background: var(--white); border-radius: var(--tdb-r-m); box-shadow: var(--ombre-1);
  padding: 2px 16px;
}
.fle-app .fle-tdb-replie > summary { cursor: pointer; padding: 13px 0; font-weight: 650; color: var(--primary); }
.fle-app .fle-tdb-replie > .fle-carte { box-shadow: none; margin: 0 0 14px; }

/* La liste des apprenants, dans son panneau. */
.fle-app .fle-tdb-panneau--eleves > .fle-etiquette { display: block; margin: 0 4px 12px; font-size: 18px; font-weight: 600; color: var(--ink); letter-spacing: -.01em; }
.fle-app .fle-tdb-panneau--eleves .fle-eleve { background: var(--white); border-color: transparent; border-radius: var(--tdb-r-m); }

/* --- Les ateliers ------------------------------------------------------ */
.fle-app .fle-tdb-ateliers { margin-top: 28px; }
.fle-app .fle-tdb-ateliers__tete { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin: 0 4px 14px; }
.fle-app .fle-tdb-ateliers .fle-tdb-ateliers__titre {
  margin: 0; font-size: 20px; font-weight: 600; letter-spacing: -.01em; color: var(--ink); text-transform: none;
}
.fle-app .fle-tdb-filtres { margin-left: auto; display: flex; flex-wrap: wrap; gap: 6px; }
.fle-app .fle-tdb-filtre {
  border: 0; border-radius: var(--radius-pilule); padding: 6px 13px;
  font-size: 13px; font-weight: 600; background: var(--white); color: var(--muted); box-shadow: var(--ombre-1);
}
.fle-app .fle-tdb-filtre[aria-pressed="true"] { background: var(--ink); color: var(--white); }

/* Les tuiles : blanches, la famille en tête avec son pictogramme, la
   flèche en coin. Même hauteur pour toutes, comme avant : la grille
   impose des rangées égales et le résumé un nombre de lignes fixe. */
.fle-app .fle-grille { gap: 14px; }
.fle-app .fle-grille .fle-tuile {
  gap: 10px; min-height: 0; padding: 16px;
  background: var(--white); color: var(--ink);
  border: 0; border-radius: var(--tdb-r-m); text-align: left;
  box-shadow: var(--ombre-1);
}
.fle-app .fle-grille .fle-tuile::before { display: none; }
.fle-app .fle-grille .fle-tuile:hover { transform: translateY(-2px); box-shadow: var(--ombre-2); }
.fle-app .fle-grille .fle-tuile--actif { background: var(--white); box-shadow: inset 0 0 0 2px var(--accent), var(--ombre-2); }
.fle-app .fle-tuile__tete { display: flex; align-items: center; gap: 10px; padding-right: 42px; }
.fle-app .fle-tuile__icone { width: 40px; height: 40px; border-radius: 12px; }
.fle-app .fle-tuile__icone svg { width: 21px; height: 21px; display: block; }
.fle-app .fle-grille .fle-tuile__num { display: inline-flex; align-items: center; gap: 6px; color: var(--muted); font-family: var(--ui); font-size: 13px; font-weight: 600; letter-spacing: 0; }
.fle-app .fle-grille .fle-tuile__titre { color: var(--ink); font-size: 17px; font-weight: 650; }
.fle-app .fle-grille .fle-tuile__texte {
  color: var(--muted); -webkit-line-clamp: 2; line-clamp: 2; max-height: calc(1.5em * 2);
}
.fle-app .fle-grille .fle-tuile__plus { display: none; }
.fle-app .fle-tuile__coin {
  position: absolute; top: 14px; right: 14px;
  width: 34px; height: 34px; border-radius: 50%;
  display: grid; place-items: center; background: var(--lavis); color: var(--primary);
  transition: transform .16s ease;
}
.fle-app .fle-tuile__coin svg { width: 16px; height: 16px; display: block; }
.fle-app .fle-grille .fle-tuile:hover .fle-tuile__coin { transform: translate(2px, -2px); }

.fle-app .fle-tdb .fle-pied {
  margin-top: 24px; padding: 14px 4px 0; border-top: 1px solid var(--line);
  background: transparent; border-radius: 0;
}

/* --- Tablette et téléphone --------------------------------------------- */
@media (max-width: 1020px) {
  .fle-app .fle-entete .fle-nav__barre { flex-wrap: wrap; }
  .fle-app .fle-entete .fle-nav__burger {
    display: inline-flex; align-items: center; gap: 8px; margin-left: auto;
    border: 0; border-radius: var(--radius-pilule); box-shadow: inset 0 0 0 1px var(--line);
    padding: 9px 15px; background: var(--white); color: var(--primary); font-weight: 650;
  }
  .fle-app .fle-entete .fle-nav__menu {
    display: none; order: 10; flex: 1 1 100%;
    flex-direction: column; align-items: stretch; gap: 4px; padding: 8px 0 4px;
  }
  .fle-app .fle-entete .fle-nav__menu--ouvert { display: flex; }
  .fle-app .fle-entete .fle-nav__rubrique,
  .fle-app .fle-entete .fle-nav__outil { justify-content: flex-start; border-radius: 12px; border: 0; }
  .fle-app .fle-entete .fle-nav__outil--reglages { width: auto; height: auto; padding: 9px 15px; box-shadow: none; }
  .fle-app .fle-entete .fle-nav__outil--reglages .fle-nav__outil-libelle {
    position: static; width: auto; height: auto; overflow: visible; clip: auto; clip-path: none;
  }
  .fle-app .fle-entete .fle-nav__outil--recherche { min-width: 0; }
  .fle-app .fle-entete .fle-nav__separateur { display: none; }
}
@media (max-width: 640px) {
  /* Sur téléphone, l'en-tête ne colle plus : il prendrait un cinquième de
     l'écran. La pastille de chrono de l'écrit DELF prend sa place en haut. */
  .fle-app .fle-entete { position: static; }
  .fle-app .fle-delf-barre { top: 0; }
  .fle-app .fle-nav__marque-texte small { display: none; }
  .fle-app .fle-entete .fle-nav__accueil { padding: 8px 13px; }
  .fle-app .fle-entete .fle-nav__burger { padding: 8px 12px; }
  .fle-app .fle-nav__moi { width: 36px; height: 36px; }
  .fle-app .fle-tdb-panneau { padding: 12px; border-radius: 22px; }
  .fle-app .fle-tdb-ligne { grid-template-columns: auto minmax(0, 1fr) auto; gap: 12px; padding: 12px; }
  .fle-app .fle-tdb-ligne > .fle-tdb-fleche { display: none; }
  .fle-app .fle-tdb-icone { width: 40px; height: 40px; border-radius: 12px; }
  .fle-app .fle-tdb-une { min-height: 0; }
  .fle-app .fle-tdb-une__titre { font-size: 22px; }
  .fle-app .fle-entete .fle-bar { gap: 8px; row-gap: 6px; }
  .fle-app .fle-entete .fle-bar__libelle,
  .fle-app .fle-entete .fle-bar__espace { display: none; }
  .fle-app .fle-entete .fle-presence > span {
    position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
  }
  .fle-app .fle-entete .fle-bar__actions { margin-left: auto; }
  .fle-app .fle-entete .fle-code { font-size: 14px; padding: 3px 10px; letter-spacing: .12em; }
  .fle-app .fle-entete .fle-bar .fle-bar__sortie { padding: 6px 12px; font-size: 13px; }
  .fle-app .fle-entete .fle-bar__qui { order: 10; flex: 1 1 100%; font-size: 12.5px; }
  .fle-app .fle-entete .fle-sortie__suivi { order: 11; }
  .fle-app .fle-tdb-filtres { margin-left: 0; }
}
@media (max-width: 420px) {
  .fle-app .fle-nav__marque-texte { display: none; }
}

/* --- Contraste renforcé, impression ------------------------------------ */
@media (prefers-contrast: more) {
  .fle-app .fle-grille .fle-tuile, .fle-app .fle-tdb-ligne, .fle-app .fle-tdb-niveau,
  .fle-app .fle-tdb-replie, .fle-app .fle-entete .fle-nav { box-shadow: none; border: 2px solid var(--line); }
  .fle-app .fle-tdb-une { border: 2px solid var(--accent); }
  .fle-app .fle-tdb-une::after { display: none; }
}
@media print {
  .fle-app { background: none; padding: 0; }
  .fle-app .fle-entete { position: static; }
  .fle-app .fle-tdb-une { background: none; color: inherit; border: 1px solid #999; }
  .fle-app .fle-tdb-une__sur, .fle-app .fle-tdb-une__note { color: inherit; }
  .fle-app .fle-tdb-filtres, .fle-app .fle-tdb-une__coin, .fle-app .fle-tuile__coin { display: none; }
}

/* =========================================================================
   REPLI SANS COLOR-MIX (1.65)

   Les teintes dérivées de la palette se calculent avec color-mix(), que
   les téléphones anciens ne connaissent pas (Safari avant 16.2, Chrome
   avant 111). Une déclaration directe en color-mix y est ignorée, et la
   couleur précédente reste : rien de grave. Une VARIABLE en color-mix, en
   revanche, devient invalide là où on l’emploie, et le fond qui en dépend
   devient transparent : un bouton plein (--accent-plein) laissait alors
   son texte blanc sur le blanc de la page.

   Un premier repli, plus haut dans la feuille, couvrait trois de ces
   variables en thème clair. Il en manquait d’autres, dont celles du tableau
   de bord de la 1.64, et tout le thème sombre. Sur ces navigateurs
   seulement, les huit variables dérivées reçoivent ici leur valeur
   calculée d’avance, pour la palette par défaut, en thème
   clair et en thème sombre. Une palette personnalisée dans
   l’administration n’y est pas reprise : les boutons gardent alors la
   sarcelle par défaut, mais restent lisibles.
   ====================================================================== */
@supports not (color: color-mix(in srgb, red 50%, blue)) {
  .fle-app {
    --accent-plein: #197F7F; --accent-sombre: #166E6E;
    --lavis: #EFF7F7; --lavis-fort: #E1F0F0; --lavis-gris: #F4F4F3;
    --cerne: #E9EEED; --tdb-fond: #ECF1F0; --tdb-panneau: #F5F7F7;
  }
  .fle-app[data-fle-theme="sombre"] {
    --accent-plein: #2B9A99; --accent-sombre: #248583;
    --lavis: #1A2C2B; --lavis-fort: #1B3433; --lavis-gris: #222D2C;
    --cerne: #2A3837; --tdb-fond: #0F1817; --tdb-panneau: #131D1C;
  }
  @media (prefers-color-scheme: dark) {
    .fle-app[data-fle-theme="systeme"] {
      --accent-plein: #2B9A99; --accent-sombre: #248583;
      --lavis: #1A2C2B; --lavis-fort: #1B3433; --lavis-gris: #222D2C;
      --cerne: #2A3837; --tdb-fond: #0F1817; --tdb-panneau: #131D1C;
    }
  }
  .fle-app .fle-btn--sourdine { --btn-bord: #7C7E7D; }
}

/* =========================================================================
   COURS DE CONVERSATION : LE TABLEAU DE LANGUE (1.66)

   Une séance qui travaille un point de grammaire en donne le
   fonctionnement dans un tableau à deux colonnes (ce qu’on veut dire,
   des exemples) suivi de remarques encadrées. Les exercices de grammaire
   portent une étiquette à part, « grammaire ». Couleurs écrites en clair :
   aucune ne dépend de color-mix().
   ====================================================================== */
.fle-app .fle-conv-tableau-cadre { margin-top: 12px; overflow-x: auto; }
.fle-app .fle-conv-tableau { width: 100%; border-collapse: collapse; font-size: 14.5px; line-height: 1.5; }
.fle-app .fle-conv-tableau th {
  text-align: left; font-size: 12.5px; font-weight: 650; color: var(--muted);
  padding: 6px 10px; border-bottom: 2px solid var(--line);
}
.fle-app .fle-conv-tableau td { vertical-align: top; padding: 10px; border-bottom: 1px solid var(--line); }
.fle-app .fle-conv-tableau td:first-child { width: 42%; background: #EEF5F5; }
.fle-app .fle-conv-tableau td:first-child > strong { display: block; color: var(--ink); }
.fle-app .fle-conv-tableau__exemple strong, .fle-app .fle-conv-remarque strong,
.fle-app .fle-question-texte strong { font-weight: 700; color: var(--primary); }
.fle-app .fle-conv-tableau__formes { display: block; margin-top: 2px; font-style: italic; color: var(--muted); }
.fle-app .fle-conv-tableau__attention { display: block; margin-top: 6px; font-size: 13.5px; color: #8A5300; }
.fle-app .fle-conv-tableau__exemple { display: block; font-family: var(--texte); }
.fle-app .fle-conv-tableau__exemple + .fle-conv-tableau__exemple { margin-top: 4px; }
.fle-app .fle-conv-remarque {
  margin-top: 12px; padding: 12px 14px; border-radius: 14px;
  background: #FFFFFF; border: 1.5px solid #8FC3C3;
}
.fle-app .fle-conv-remarque__titre { display: block; margin-top: 4px; }
.fle-app .fle-conv-remarque p { margin-top: 4px; }
.fle-app .fle-conv-remarque .fle-liste { margin-top: 6px; font-family: var(--texte); }
.fle-app .fle-marque--gra { background: #E8EEF8; border-color: #B9C9E6; color: #2B4A7E; }
@media (max-width: 640px) {
  .fle-app .fle-conv-tableau, .fle-app .fle-conv-tableau tbody, .fle-app .fle-conv-tableau tr, .fle-app .fle-conv-tableau td { display: block; width: 100%; }
  .fle-app .fle-conv-tableau thead { display: none; }
  .fle-app .fle-conv-tableau td:first-child { width: 100%; border-bottom: 0; }
}
.fle-app[data-fle-theme="sombre"] .fle-conv-tableau td:first-child { background: #1A2C2B; }
.fle-app[data-fle-theme="sombre"] .fle-conv-tableau__attention { color: #E8B053; }
.fle-app[data-fle-theme="sombre"] .fle-conv-remarque { background: #182322; border-color: #2E6B6A; }
.fle-app[data-fle-theme="sombre"] .fle-marque--gra { background: #1C2638; border-color: #34476A; color: #A9C1EE; }
@media (prefers-color-scheme: dark) {
  .fle-app[data-fle-theme="systeme"] .fle-conv-tableau td:first-child { background: #1A2C2B; }
  .fle-app[data-fle-theme="systeme"] .fle-conv-tableau__attention { color: #E8B053; }
  .fle-app[data-fle-theme="systeme"] .fle-conv-remarque { background: #182322; border-color: #2E6B6A; }
  .fle-app[data-fle-theme="systeme"] .fle-marque--gra { background: #1C2638; border-color: #34476A; color: #A9C1EE; }
}
