/* =========================================================================
   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: 16;

  /* ---------------------------------------------------------------------
     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: hidden;
  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; }
/* 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); }

@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);
  outline: none;
}
.fle-champ:focus-visible { outline: none; }
.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 auto; }
.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); }
.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; }
.fle-annonce { position: fixed; left: 50%; bottom: 22px; transform: translateX(-50%); z-index: 9999; background: var(--ink); color: #fff; padding: 11px 18px; border-radius: 999px; box-shadow: 0 12px 30px rgba(0,0,0,.28); font-size: 14px; }
.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); }
.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; outline: none;
  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: #5C3590; }

.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; }
}
