/* =========================================================================
   Salle de classe FLE - Nos Réussites
   LA CLASSE VIRTUELLE (1.72.0)

   Feuille chargée après fle-classe.css. Elle en reprend les jetons (--ink,
   --primary, --accent, --paper, --line, --white, --muted, --danger, les
   ombres, les rayons, la police d'interface) et n'en redéfinit aucun : le
   thème sombre et la palette réglée dans l'administration s'appliquent
   donc ici sans qu'on y touche.

   La Classe virtuelle n'est pas un écran de plus mais un MODE de la
   racine. Quand .fle-app porte .fle-app--cv, elle sort du flux de la page
   et couvre toute la fenêtre ; le thème WordPress reste dessous, intact,
   et revient dès que la classe est retirée.

   Une contrainte commande toute la mise en page : .fle-corps ne bouge
   jamais dans le DOM, parce qu'un nœud déplacé recharge les iframes qu'il
   contient (visio, tableau, LearningApps). Les éléments neufs sont posés
   comme frères de .fle-corps, et une grille nommée les range. Changer la
   palette de côté revient à changer trois lignes de grid-template.

   Plan
     1. Jetons propres à la classe virtuelle (clair, sombre)
     2. L'atelier dans la liste : tuile et bouton rouges
     3. Le mode plein écran et sa grille
     4. Le bandeau du haut
     5. La palette des ateliers
     6. La languette et la bulle
     7. Les menus
     8. La discussion
     9. Écrans étroits
    10. Préférences du système : mouvement, contraste, impression

   Tout sélecteur part de .fle-app, sauf html.fle-cv-ouverte et
   body.fle-cv-ouverte, seules règles qui doivent atteindre la page.
   ====================================================================== */


/* =========================================================================
   1. JETONS

   Le décor reste sarcelle et gris. Le rouge ne sert qu'à l'accès à la
   classe virtuelle (tuile, bouton de navigation) et à la marque du
   bandeau. Il est voisin des deux rouges déjà présents (--danger #A32C22,
   le bouton du tableau #B5342A) ; on ne les distingue pas par la teinte
   mais par l'emploi : celui-ci n'apparaît jamais dans un message d'erreur
   et ne sert à aucun geste destructeur.

   Toutes les valeurs sont écrites en clair, sans color-mix() : une
   variable calculée devient invalide sur les navigateurs qui ignorent
   color-mix (voir « Repli sans color-mix », 1.65), et le fond qui en
   dépend disparaît.

   Rapports de contraste mesurés (WCAG 2, luminance relative)
     clair   #FFFFFF sur #B3261E ................ 6,54:1  libellés
             #FFE3E0 sur #B3261E ................ 5,39:1  texte secondaire
             #FFFFFF sur #96201A (survol) ........ 8,34:1  (#FFE3E0 : 6,88:1)
             #B3261E sur #FFFFFF ................ 6,54:1  flèche de la tuile
             #FFFFFF sur voile ≈ #BF4942 ......... 4,94:1  pictogramme (3:1 exigé)
             #B3261E contre le fond de page ...... 5,73:1  frontière de la tuile
     sombre  #FF8A80 sur #3A1614 ................ 7,05:1  libellés et bord
             #FFB4AB sur #3A1614 ................ 9,48:1  texte secondaire
             #FF8A80 sur #4A1D1A (survol) ........ 6,21:1  (#FFB4AB : 8,35:1)
             #3A1614 sur #FF8A80 (flèche) ........ 7,05:1
             #FF8A80 sur voile ≈ #562623 ......... 5,42:1  pictogramme
             #3A1614 contre #0F1817 ne fait que 1,12:1 : c'est le bord
             #FF8A80 (7,91:1 sur la page) qui porte la frontière.
     badges  #FFFFFF sur #C0392B ................ 5,44:1  (le rouge de .fle-pastille-nb)
     champs  #7C7E7D sur #FFFFFF ................ 4,09:1 ; #6E7F7E sur #182322 : 3,84:1
   ====================================================================== */
.fle-app {
  --cv-rouge:        #B3261E;
  --cv-rouge-texte:  #FFFFFF;
  --cv-rouge-doux:   #FFE3E0;
  --cv-rouge-bord:   #B3261E;
  --cv-rouge-survol: #96201A;
  --cv-rouge-voile:  rgba(255,255,255,.16);
  --cv-coin-fond:    #FFFFFF;
  --cv-coin-texte:   #B3261E;
  --cv-badge:        #C0392B;
  --cv-champ-bord:   #7C7E7D;
  --cv-moi-bord:     #AFD6D6;   /* filet de mes bulles : décor, le fond suffit à les distinguer */
}
.fle-app[data-fle-theme="sombre"] {
  --cv-rouge:        #3A1614; --cv-rouge-texte:  #FF8A80; --cv-rouge-doux:   #FFB4AB;
  --cv-rouge-bord:   #FF8A80; --cv-rouge-survol: #4A1D1A; --cv-rouge-voile:  rgba(255,138,128,.14);
  --cv-coin-fond:    #FF8A80; --cv-coin-texte:   #3A1614; --cv-champ-bord:   #6E7F7E;
  --cv-moi-bord:     #205250;
}
@media (prefers-color-scheme: dark) {
  .fle-app[data-fle-theme="systeme"] {
    --cv-rouge:        #3A1614; --cv-rouge-texte:  #FF8A80; --cv-rouge-doux:   #FFB4AB;
    --cv-rouge-bord:   #FF8A80; --cv-rouge-survol: #4A1D1A;
    --cv-rouge-voile:  rgba(255,138,128,.14); --cv-coin-fond:    #FF8A80;
    --cv-coin-texte:   #3A1614; --cv-champ-bord:   #6E7F7E; --cv-moi-bord:     #205250;
  }
}


/* =========================================================================
   2. L'ATELIER DANS LA LISTE

   La tuile et le bouton de navigation sont les deux seules portes. Ils
   prennent le rouge à pleine valeur en thème clair ; en thème sombre, un
   aplat rouge vif écraserait tout l'écran, et le rouge passe au bord et au
   texte sur un fond brun très sombre. Une fois dans la classe virtuelle,
   les deux disparaissent : on y est déjà.
   ====================================================================== */
.fle-app .fle-tuile.fle-tuile--cv {
  background: var(--cv-rouge); color: var(--cv-rouge-texte);
  box-shadow: var(--ombre-1), inset 0 0 0 1.5px var(--cv-rouge-bord);
}
.fle-app .fle-tuile.fle-tuile--cv:hover {
  background: var(--cv-rouge-survol);
  box-shadow: var(--ombre-2), inset 0 0 0 1.5px var(--cv-rouge-bord);
}
.fle-app .fle-tuile.fle-tuile--cv::before { display: none; }
.fle-app .fle-tuile.fle-tuile--cv .fle-tuile__titre { color: var(--cv-rouge-texte); }
.fle-app .fle-tuile.fle-tuile--cv .fle-tuile__num,
.fle-app .fle-tuile.fle-tuile--cv .fle-tuile__texte,
.fle-app .fle-tuile.fle-tuile--cv .fle-tuile__plus { color: var(--cv-rouge-doux); }
.fle-app .fle-tuile.fle-tuile--cv .fle-tuile__icone { background: var(--cv-rouge-voile); color: var(--cv-rouge-texte); }
.fle-app .fle-tuile.fle-tuile--cv .fle-tuile__coin { background: var(--cv-coin-fond); color: var(--cv-coin-texte); }

/* Le bouton direct de la barre de navigation : une pilule, comme les
   rubriques, mais pleine. Il peut porter aussi la classe d'une rubrique ;
   la double classe ci-dessous l'emporte sur leurs règles de survol. */
.fle-app .fle-nav .fle-nav__special {
  display: inline-flex; align-items: center; gap: 6px; flex: 0 0 auto;
  margin: 0 0 0 6px; padding: 7px 14px;
  border: 1.5px solid var(--cv-rouge-bord); border-radius: var(--radius-pilule, 999px);
  background: var(--cv-rouge); color: var(--cv-rouge-texte);
  font-family: var(--ui); font-size: 14.5px; font-weight: 650; line-height: 1.25;
  letter-spacing: 0; text-transform: none; text-decoration: none; white-space: nowrap;
  box-shadow: var(--ombre-1); cursor: pointer; transition: background-color .15s ease;
}
.fle-app .fle-nav .fle-nav__special:hover { background: var(--cv-rouge-survol); color: var(--cv-rouge-texte); }
.fle-app .fle-nav .fle-nav__special svg { display: block; width: 18px; height: 18px; flex: 0 0 auto; }
@media (max-width: 1020px) {
  /* Le menu déplié passe en colonne : le bouton s'y aligne comme une rubrique. */
  .fle-app .fle-entete .fle-nav__menu .fle-nav__special {
    justify-content: flex-start; margin: 4px 0 0; border-radius: 12px;
  }
}

.fle-app.fle-app--cv .fle-tuile--cv,
.fle-app.fle-app--cv .fle-nav__special { display: none !important; }


/* =========================================================================
   3. LE MODE PLEIN ÉCRAN

   La racine passe en position fixe sur toute la fenêtre. Son z-index
   (100000) la place au-dessus de la barre d'administration de WordPress
   (99999). La hauteur est donnée deux fois : 100vh pour les navigateurs
   anciens, puis 100dvh, qui suit l'apparition des barres d'adresse sur
   téléphone au lieu de laisser le bas de l'écran sous elles.

   Limite connue : si un conteneur du thème porte transform, filter ou
   contain, il devient la référence de position: fixed, et la classe
   virtuelle se cale sur lui au lieu de la fenêtre. Aucune feuille ne peut
   y remédier sans toucher au thème.

   La grille. Les colonnes et rangées de la palette et de la discussion
   sont en « auto » : quand l'une est masquée (display: none), sa piste
   tombe à zéro sans qu'il faille une autre grille.
   ====================================================================== */
html.fle-cv-ouverte,
body.fle-cv-ouverte { overflow: hidden; overscroll-behavior: none; }

.fle-app.fle-app--cv {
  --cv-chat-l: 320px;

  position: fixed;
  top: 0; right: 0; bottom: 0; left: 0;   /* inset: 0, en longues formes pour Safari < 14.1 */
  z-index: 100000;
  width: auto; max-width: none;
  height: 100vh; height: 100dvh; min-height: 0;
  margin: 0; padding: 0;
  border: 0; border-radius: 0; box-shadow: none;
  overflow: hidden;
  background: var(--tdb-fond, var(--paper));

  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  grid-template-rows: auto minmax(0, 1fr);
  grid-template-areas:
    "haut haut  haut"
    "dock scene chat";
}
/* La palette à gauche est la disposition par défaut (ci-dessus). */
.fle-app.fle-app--cv[data-cv-dock="droite"] {
  grid-template-areas:
    "haut haut  haut"
    "chat scene dock";
}
.fle-app.fle-app--cv[data-cv-dock="haut"] {
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-rows: auto auto minmax(0, 1fr);
  grid-template-areas:
    "haut  haut"
    "dock  dock"
    "scene chat";
}
.fle-app.fle-app--cv[data-cv-dock="bas"] {
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-rows: auto minmax(0, 1fr) auto;
  grid-template-areas:
    "haut  haut"
    "scene chat"
    "dock  dock";
}
.fle-app.fle-app--cv[data-cv-dock="flottant"] {
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-rows: auto minmax(0, 1fr);
  grid-template-areas:
    "haut  haut"
    "scene chat";
}

/* Ce que la classe virtuelle remplace. Le filet Seyès est déjà masqué par
   fle-classe.css ; on le redit pour ne pas dépendre de cette règle-là. */
.fle-app.fle-app--cv > .fle-seyes,
.fle-app.fle-app--cv > .fle-entete,
.fle-app.fle-app--cv > .fle-evitement { display: none !important; }
.fle-app.fle-app--cv .fle-fil { display: none; }

/* La scène : la zone de l'atelier, qui défile seule. min-width et
   min-height à zéro sont indispensables : sans eux, un élément de grille
   refuse de rétrécir sous la taille de son contenu, et un long atelier
   pousserait la discussion hors de l'écran au lieu de défiler. */
.fle-app.fle-app--cv > .fle-corps {
  grid-area: scene; min-width: 0; min-height: 0; overflow: auto; overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch; padding: 12px clamp(10px, 1.6vw, 20px) 28px;
}
/* Palette repliée : la languette est collée au bord de la scène. Une
   marge de plus de ce côté-là évite qu'elle couvre le début des lignes. */
.fle-app.fle-app--cv[data-cv-replie="1"] > .fle-corps { padding-left: 34px; }
.fle-app.fle-app--cv[data-cv-replie="1"][data-cv-dock="droite"] > .fle-corps { padding-left: clamp(10px, 1.6vw, 20px); padding-right: 34px; }
.fle-app.fle-app--cv[data-cv-replie="1"][data-cv-dock="haut"] > .fle-corps { padding-left: clamp(10px, 1.6vw, 20px); padding-top: 30px; }
.fle-app.fle-app--cv[data-cv-replie="1"][data-cv-dock="bas"] > .fle-corps { padding-left: clamp(10px, 1.6vw, 20px); padding-bottom: 34px; }
.fle-app.fle-app--cv[data-cv-replie="1"][data-cv-dock="flottant"] > .fle-corps { padding-left: clamp(10px, 1.6vw, 20px); }

/* Les annonces : leurs deux bulles sont en position fixe, mais leur
   conteneur deviendrait une cellule de la grille et ajouterait une rangée.
   On le sort du flux ; les bulles n'en dépendent pas. */
.fle-app.fle-app--cv > .fle-annonces { position: absolute; top: 0; left: 0; width: 0; height: 0; }
.fle-app.fle-app--cv[data-cv-dock="bas"]:not([data-cv-replie="1"]) .fle-annonce { bottom: 66px; }

/* Tout attribut hidden posé par le script l'emporte sur l'affichage
   choisi ici (sans cela, display: flex le rendrait inopérant). */
.fle-app [class*="fle-cv-"][hidden] { display: none !important; }

/* Hors du mode, les éléments de la classe virtuelle ne paraissent jamais,
   même si le script les laisse en place en la quittant. */
.fle-app:not(.fle-app--cv) .fle-cv-haut,
.fle-app:not(.fle-app--cv) .fle-cv-dock,
.fle-app:not(.fle-app--cv) .fle-cv-chat,
.fle-app:not(.fle-app--cv) .fle-cv-languette,
.fle-app:not(.fle-app--cv) .fle-cv-bulle,
.fle-app:not(.fle-app--cv) .fle-cv-menu { display: none !important; }

/* Remise à plat commune à tous les boutons neufs. Les thèmes WordPress
   habillent volontiers « button » (fond, majuscules, ombre, marge) ; la
   règle de fle-classe.css ne rétablit que la police et la couleur. */
.fle-app .fle-cv-haut__bouton, .fle-app .fle-cv-dock__bouton, .fle-app .fle-cv-dock__poignee,
.fle-app .fle-cv-dock__replier, .fle-app .fle-cv-languette, .fle-app .fle-cv-chat__menu-bouton,
.fle-app .fle-cv-chat__fermer, .fle-app .fle-cv-chat__anciens, .fle-app .fle-cv-chat__nouveaux,
.fle-app .fle-cv-msg__action {
  -webkit-appearance: none; appearance: none; margin: 0; border: 0; border-radius: 0;
  background: transparent; box-shadow: none;
  font-family: var(--ui); font-weight: 600; line-height: 1.2;
  letter-spacing: 0; text-transform: none; text-decoration: none; text-shadow: none;
  color: inherit; cursor: pointer; min-width: 0; min-height: 0;
  -webkit-tap-highlight-color: transparent;
}

/* Les pictogrammes. fle-classe.css donne aux SVG height: auto ; ici la
   taille est fixée, sinon un SVG sans attributs de dimension s'étire. */
.fle-app .fle-cv-haut__icone, .fle-app .fle-cv-dock__icone {
  display: inline-grid; place-items: center; flex: 0 0 auto; width: 18px; height: 18px;
  pointer-events: none;
}
.fle-app .fle-cv-haut__icone svg, .fle-app .fle-cv-dock__icone svg,
.fle-app .fle-cv-dock__replier svg, .fle-app .fle-cv-dock__poignee svg,
.fle-app .fle-cv-languette svg, .fle-app .fle-cv-chat__menu-bouton svg,
.fle-app .fle-cv-chat__fermer svg {
  display: block; flex: 0 0 auto; width: 18px; height: 18px; max-width: none; pointer-events: none;
}


/* =========================================================================
   4. LE BANDEAU DU HAUT

   Une carte blanche comme la barre de navigation, mais d'une seule ligne
   de 44 px : la classe virtuelle rend à l'atelier la hauteur que prenaient
   la navigation et la barre de salle. La marque rouge dit où l'on est ;
   tout le reste parle en sarcelle et gris.
   ====================================================================== */
.fle-app .fle-cv-haut {
  grid-area: haut; z-index: 30; display: flex; align-items: center; gap: 8px; flex-wrap: nowrap;
  min-width: 0; min-height: 44px; margin: 0; padding: 0 8px 0 10px;
  padding-left: max(10px, env(safe-area-inset-left));
  padding-right: max(8px, env(safe-area-inset-right)); background: var(--white);
  border-bottom: 1px solid var(--line); box-shadow: var(--ombre-1);
  font-size: 13.5px; line-height: 1.3;
}
.fle-app .fle-cv-haut__marque {
  flex: 0 0 auto; padding: 3px 10px;
  border: 1.5px solid var(--cv-rouge-bord); border-radius: var(--radius-pilule, 999px);
  background: var(--cv-rouge); color: var(--cv-rouge-texte);
  font-size: 13px; font-weight: 700; letter-spacing: .005em; white-space: nowrap;
}
.fle-app .fle-cv-haut__salle, .fle-app .fle-cv-haut__ici, .fle-app .fle-cv-haut__presence {
  flex: 0 1 auto; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.fle-app .fle-cv-haut__salle { font-weight: 650; color: var(--ink); }
/* Le nom de l'atelier, séparé de la salle par un filet plutôt que par un
   caractère : un « › » écrit en CSS serait lu par certains lecteurs d'écran. */
.fle-app .fle-cv-haut__ici { padding-left: 9px; border-left: 1px solid var(--line); color: var(--muted); }
.fle-app .fle-cv-haut__espace { flex: 1 1 auto; min-width: 0; }
.fle-app .fle-cv-haut__presence { font-size: 12.5px; color: var(--muted); }

/* Le minuteur de séance : la pastille sombre de .fle-chrono, à la taille
   du bandeau. Ses états changent de fond, mais les chiffres disent déjà
   tout : la couleur ne porte aucune information seule.
   Encre sur blanc 13,7:1 ; blanc sur --danger 7,14:1 ; blanc sur --muted
   5,64:1. En sombre, --white devient l'encre du fond : 7,06:1 et 7,09:1. */
.fle-app .fle-cv-haut__chrono {
  flex: 0 0 auto; padding: 2px 9px; border-radius: 7px; background: var(--ink); color: var(--white);
  font-family: var(--data); font-size: 14px; font-weight: 700; line-height: 1.5;
  font-variant-numeric: tabular-nums; letter-spacing: .02em;
}
.fle-app .fle-cv-haut__chrono--alerte { background: var(--danger); }
.fle-app .fle-cv-haut__chrono--fini { background: var(--muted); }

/* Les boutons : pilules sans fond, comme les rubriques de la navigation. */
.fle-app .fle-cv-haut__bouton {
  position: relative; display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  flex: 0 0 auto; height: 32px; padding: 0 11px; border-radius: var(--radius-pilule, 999px);
  color: var(--ink); font-size: 13.5px; white-space: nowrap;
  transition: background-color .15s ease, color .15s ease, box-shadow .15s ease;
}
.fle-app .fle-cv-haut__bouton:hover { background: var(--lavis-fort); color: var(--primary); }
/* Bouton dont le menu est ouvert, ou discussion affichée : le lavis plus
   un anneau, pour que l'état se lise aussi sans la couleur. */
.fle-app .fle-cv-haut__bouton[aria-expanded="true"],
.fle-app .fle-cv-haut__bouton[aria-pressed="true"],
.fle-app.fle-app--cv[data-cv-chat="ouvert"] .fle-cv-haut__bouton[data-action="chat"] {
  background: var(--lavis-fort); color: var(--primary); box-shadow: inset 0 0 0 1.5px var(--accent);
}
.fle-app .fle-cv-haut__bouton[data-action="inviter"] { color: var(--primary); box-shadow: inset 0 0 0 1.5px var(--accent); }
.fle-app .fle-cv-haut__bouton[data-action="quitter"] { color: var(--primary); box-shadow: inset 0 0 0 1.5px var(--line); }
.fle-app .fle-cv-haut__bouton[data-action="quitter"]:hover { box-shadow: inset 0 0 0 1.5px var(--accent); }
.fle-app .fle-cv-haut__bouton:focus-visible {
  outline: 3px solid var(--accent-sombre); outline-offset: 2px;
  border-radius: var(--radius-pilule, 999px);
}

/* Les messages non lus. Même rouge que les pastilles des tuiles : c'est le
   signal « quelque chose vous attend » de toute l'application. Le liseré
   de la couleur du bandeau le détache du bouton. */
.fle-app .fle-cv-badge {
  display: inline-grid; place-content: center; min-width: 18px; height: 18px; padding: 0 5px;
  border-radius: var(--radius-pilule, 999px); background: var(--cv-badge); color: #fff;
  font-family: var(--ui); font-size: 11px; font-weight: 700; line-height: 1;
  font-variant-numeric: tabular-nums; box-shadow: 0 0 0 2px var(--white); pointer-events: none;
}


/* =========================================================================
   5. LA PALETTE DES ATELIERS

   Des boutons de 32 × 32 px avec une icône de 18 px : petits, comme
   demandé, mais au-dessus du minimum tactile de 24 px des WCAG 2.2. Au
   repos, l'icône est grise (5,64:1 sur blanc, 7,09:1 en sombre) ; au
   survol elle prend le lavis ; l'atelier affiché prend l'aplat sarcelle
   profonde (blanc sur #0F5F60 : 7,43:1), le geste de l'accueil actif dans
   la navigation.

   La palette n'est jamais positionnée hors du mode flottant : le script y
   laisse peut-être les coordonnées de son dernier déplacement (style.left,
   style.top), et une palette en position relative les appliquerait.
   ====================================================================== */
.fle-app.fle-app--cv .fle-cv-dock {
  grid-area: dock; position: static; z-index: 20; display: flex; flex-direction: column;
  float: none; min-width: 0; min-height: 0; margin: 0; padding: 6px; background: var(--white);
  border-right: 1px solid var(--line); overflow-x: hidden; overflow-y: auto;
  overscroll-behavior: contain; scrollbar-width: thin;
}
.fle-app.fle-app--cv .fle-cv-dock__liste {
  display: flex; flex-direction: column; align-items: center; gap: 4px; flex: 1 0 auto;
  margin: 0; padding: 0;
}

.fle-app .fle-cv-dock__bouton, .fle-app .fle-cv-dock__replier {
  position: relative; display: inline-grid; place-items: center; flex: 0 0 auto;
  width: 32px; height: 32px; padding: 0; border-radius: 9px; color: var(--muted);
  transition: background-color .15s ease, color .15s ease;
}
.fle-app .fle-cv-dock__bouton:hover,
.fle-app .fle-cv-dock__replier:hover { background: var(--lavis-fort); color: var(--primary); }
.fle-app .fle-cv-dock__bouton[aria-current="true"],
.fle-app .fle-cv-dock__bouton[aria-current="true"]:hover {
  background: var(--primary); color: var(--white); box-shadow: var(--ombre-1);
}
/* L'anneau garde le rayon du bouton : la règle générale de fle-classe.css
   l'arrondirait à 11 px au moment du focus. */
.fle-app .fle-cv-dock__bouton:focus-visible, .fle-app .fle-cv-dock__replier:focus-visible,
.fle-app .fle-cv-dock__poignee:focus-visible {
  outline: 3px solid var(--accent-sombre); outline-offset: 2px; border-radius: 9px;
}

/* Le travail en attente : la pastille déborde du coin du bouton, dans la
   marge de 6 px de la palette, où le défilement ne la coupe pas. */
.fle-app .fle-cv-dock__pastille {
  position: absolute; top: -4px; right: -4px; display: inline-grid; place-content: center;
  min-width: 16px; height: 16px; padding: 0 4px; border-radius: var(--radius-pilule, 999px);
  background: var(--cv-badge); color: #fff;
  font-family: var(--ui); font-size: 10.5px; font-weight: 700; line-height: 1;
  font-variant-numeric: tabular-nums; box-shadow: 0 0 0 2px var(--white); pointer-events: none;
}

.fle-app .fle-cv-dock__separateur {
  display: block; flex: 0 0 auto; width: 20px; height: 1px; margin: 3px 0; background: var(--line);
}

/* Replier : en bas d'une palette verticale, au bout d'une horizontale. */
.fle-app.fle-app--cv .fle-cv-dock__replier { margin-top: auto; }

/* Les glyphes de repli. Si le script met un SVG dans le bouton, c'est lui
   qu'on voit ; sinon un chevron est tracé en bordures, qui restent
   visibles en couleurs forcées. Le texte éventuel du bouton est réduit à
   zéro : son nom accessible vient de aria-label. La rotation dit le sens
   (45deg vers la gauche, 225deg vers la droite, 135deg vers le haut,
   -45deg vers le bas). */
.fle-app .fle-cv-dock__replier,
.fle-app .fle-cv-languette,
.fle-app .fle-cv-chat__menu-bouton,
.fle-app .fle-cv-chat__fermer,
.fle-app .fle-cv-dock__poignee { font-size: 0; }
.fle-app .fle-cv-dock__replier:not(:has(svg))::before,
.fle-app .fle-cv-languette:not(:has(svg))::before {
  content: ""; display: block; width: 7px; height: 7px;
  border: solid currentColor; border-width: 0 0 2px 2px;
  transform: rotate(var(--cv-chevron, 45deg));
}
.fle-app.fle-app--cv .fle-cv-dock__replier { --cv-chevron: 45deg; }
.fle-app.fle-app--cv[data-cv-dock="droite"] .fle-cv-dock__replier { --cv-chevron: 225deg; }
.fle-app.fle-app--cv[data-cv-dock="haut"] .fle-cv-dock__replier { --cv-chevron: 135deg; }
.fle-app.fle-app--cv[data-cv-dock="bas"] .fle-cv-dock__replier { --cv-chevron: -45deg; }

/* La poignée : deux traits horizontaux, le signe « on peut tirer ». Elle
   n'existe qu'en mode flottant. touch-action: none laisse le glissé au
   doigt au script (pointer events) au lieu de faire défiler la page. */
.fle-app .fle-cv-dock__poignee {
  display: none; place-items: center; flex: 0 0 auto; width: 32px; height: 24px; padding: 0;
  border-radius: 7px; color: var(--muted); cursor: grab; touch-action: none;
}
.fle-app .fle-cv-dock__poignee:not(:has(svg))::before {
  content: ""; display: block; width: 14px; height: 6px;
  border-top: 2px solid currentColor; border-bottom: 2px solid currentColor;
}
.fle-app .fle-cv-dock__poignee:hover { background: var(--lavis-fort); color: var(--primary); }
.fle-app .fle-cv-dock__poignee:active { cursor: grabbing; }

/* --- Palette à droite --------------------------------------------------- */
.fle-app.fle-app--cv[data-cv-dock="droite"] .fle-cv-dock { border-right: 0; border-left: 1px solid var(--line); }

/* --- Palette en haut ou en bas : une rangée qui défile ----------------- */
.fle-app.fle-app--cv[data-cv-dock="haut"] .fle-cv-dock,
.fle-app.fle-app--cv[data-cv-dock="bas"] .fle-cv-dock {
  flex-direction: row; padding: 6px 8px; border-right: 0; overflow-x: auto; overflow-y: hidden;
}
.fle-app.fle-app--cv[data-cv-dock="haut"] .fle-cv-dock { border-bottom: 1px solid var(--line); }
.fle-app.fle-app--cv[data-cv-dock="bas"] .fle-cv-dock {
  border-top: 1px solid var(--line); padding-bottom: max(6px, env(safe-area-inset-bottom));
}
.fle-app.fle-app--cv[data-cv-dock="haut"] .fle-cv-dock__liste,
.fle-app.fle-app--cv[data-cv-dock="bas"] .fle-cv-dock__liste { flex-direction: row; }
.fle-app.fle-app--cv[data-cv-dock="haut"] .fle-cv-dock__separateur,
.fle-app.fle-app--cv[data-cv-dock="bas"] .fle-cv-dock__separateur { width: 1px; height: 20px; margin: 0 3px; }
.fle-app.fle-app--cv[data-cv-dock="haut"] .fle-cv-dock__replier,
.fle-app.fle-app--cv[data-cv-dock="bas"] .fle-cv-dock__replier { margin-top: 0; margin-left: auto; }

/* --- Palette flottante -------------------------------------------------
   Le script la place (style.left, style.top, en pixels de la fenêtre) et
   la déplace ; à défaut, elle se pose sous le bandeau, à gauche. Elle
   reste verticale : sa bulle s'ouvre à droite. */
.fle-app.fle-app--cv[data-cv-dock="flottant"] .fle-cv-dock {
  position: fixed; left: 12px; top: 56px; z-index: 40;
  max-height: calc(100vh - 24px); max-height: calc(100dvh - 24px); padding: 6px;
  border: 1px solid var(--line); border-radius: 14px; box-shadow: var(--ombre-3);
}
.fle-app.fle-app--cv[data-cv-dock="flottant"] .fle-cv-dock__liste { flex: 0 0 auto; }
.fle-app.fle-app--cv[data-cv-dock="flottant"] .fle-cv-dock__poignee { display: grid; }
.fle-app.fle-app--cv[data-cv-dock="flottant"] .fle-cv-dock__replier { margin-top: 2px; }

/* --- Palette masquée ---------------------------------------------------- */
.fle-app.fle-app--cv[data-cv-replie="1"] .fle-cv-dock { display: none; }


/* =========================================================================
   6. LA LANGUETTE ET LA BULLE

   La languette rouvre la palette masquée. Elle est placée en position
   absolue dans la zone « scene » de la grille : un élément absolu dont la
   grille est le bloc conteneur prend sa zone nommée pour repère. Elle se
   colle ainsi au bord de la scène, du côté où était la palette, sans
   qu'aucune hauteur de bandeau soit écrite en dur. Sarcelle profonde sur
   le fond de page : 6,51:1 en clair, 9,14:1 en sombre.
   ====================================================================== */
.fle-app .fle-cv-languette { display: none; }
.fle-app.fle-app--cv[data-cv-replie="1"] .fle-cv-languette {
  --cv-chevron: 225deg; position: absolute; grid-area: scene; z-index: 38;
  display: grid; place-items: center; top: 50%; right: auto; bottom: auto; left: 0;
  width: 24px; height: 64px; margin: -32px 0 0; padding: 0; border-radius: 0 12px 12px 0;
  background: var(--primary); color: var(--white); box-shadow: var(--ombre-2);
  transition: width .12s ease, height .12s ease;
}
.fle-app.fle-app--cv[data-cv-replie="1"] .fle-cv-languette:hover { width: 28px; }
.fle-app.fle-app--cv[data-cv-replie="1"][data-cv-dock="droite"] .fle-cv-languette {
  --cv-chevron: 45deg; left: auto; right: 0; border-radius: 12px 0 0 12px;
}
.fle-app.fle-app--cv[data-cv-replie="1"][data-cv-dock="haut"] .fle-cv-languette,
.fle-app.fle-app--cv[data-cv-replie="1"][data-cv-dock="bas"] .fle-cv-languette {
  left: 50%; width: 64px; height: 24px; margin: 0 0 0 -32px;
}
.fle-app.fle-app--cv[data-cv-replie="1"][data-cv-dock="haut"] .fle-cv-languette {
  --cv-chevron: -45deg; top: 0; border-radius: 0 0 12px 12px;
}
.fle-app.fle-app--cv[data-cv-replie="1"][data-cv-dock="bas"] .fle-cv-languette {
  --cv-chevron: 135deg; top: auto; bottom: 0; border-radius: 12px 12px 0 0;
}
.fle-app.fle-app--cv[data-cv-replie="1"][data-cv-dock="haut"] .fle-cv-languette:hover,
.fle-app.fle-app--cv[data-cv-replie="1"][data-cv-dock="bas"] .fle-cv-languette:hover { width: 64px; height: 28px; }
.fle-app.fle-app--cv[data-cv-replie="1"][data-cv-dock="flottant"] .fle-cv-languette {
  top: auto; bottom: 12px; left: 12px; width: 40px; height: 40px; margin: 0; border-radius: 12px;
  box-shadow: var(--ombre-3);
}
.fle-app.fle-app--cv[data-cv-replie="1"][data-cv-dock="flottant"] .fle-cv-languette:hover { width: 40px; }
.fle-app .fle-cv-languette:focus-visible { outline: 3px solid var(--accent-sombre); outline-offset: 2px; }

/* La bulle : le nom de l'atelier survolé ou atteint au clavier. Une seule
   pour toute la palette, posée par le script (style.left, style.top) à
   8 px du bouton et centrée sur lui, d'où la flèche au milieu du côté.
   Elle ne capte jamais la souris : sinon, en s'affichant sous le
   pointeur, elle lui ferait quitter le bouton et disparaîtrait aussitôt.
   Blanc sur encre : 13,7:1 (même rapport en sombre, couleurs inversées). */
.fle-app .fle-cv-bulle {
  position: fixed; left: 0; top: 0; z-index: 70;
  width: max-content; max-width: min(260px, calc(100vw - 16px)); margin: 0; padding: 5px 9px;
  border-radius: 7px; background: var(--ink); color: var(--white);
  font-family: var(--ui); font-size: 12.5px; font-weight: 600; line-height: 1.3;
  text-align: left; white-space: normal; box-shadow: var(--ombre-2); pointer-events: none;
  opacity: 0; visibility: hidden; transition: opacity .12s ease, visibility 0s linear .12s;
}
.fle-app .fle-cv-bulle--visible {
  opacity: 1; visibility: visible; transition: opacity .12s ease, visibility 0s linear 0s;
}
.fle-app .fle-cv-bulle::after {
  content: ""; position: absolute; width: 0; height: 0; border: 5px solid transparent;
}
.fle-app .fle-cv-bulle[data-cote="droite"]::after  { right: 100%; top: 50%; margin-top: -5px; border-right-color: var(--ink); }
.fle-app .fle-cv-bulle[data-cote="gauche"]::after  { left: 100%;  top: 50%; margin-top: -5px; border-left-color: var(--ink); }
.fle-app .fle-cv-bulle[data-cote="dessous"]::after { bottom: 100%; left: 50%; margin-left: -5px; border-bottom-color: var(--ink); }
.fle-app .fle-cv-bulle[data-cote="dessus"]::after  { top: 100%;    left: 50%; margin-left: -5px; border-top-color: var(--ink); }


/* =========================================================================
   7. LES MENUS

   Le menu de la palette et celui de la discussion. Position fixe : le
   script le pose sous son bouton (style.left, style.top, coordonnées de la
   fenêtre, tirées de getBoundingClientRect). À défaut, il tombe sous le
   bandeau, à droite. La largeur étant fixée (max-content), un left posé
   par le script annule le right ci-dessous au lieu d'étirer le menu.

   L'élément coché d'un groupe radio porte une coche tracée en bordures :
   elle reste visible sans couleur et en couleurs forcées.
   ====================================================================== */
.fle-app .fle-cv-menu {
  position: fixed; top: 48px; right: 8px; z-index: 60;
  width: max-content; min-width: 220px; max-width: min(320px, calc(100vw - 16px));
  max-height: calc(100vh - 64px); max-height: calc(100dvh - 64px);
  overflow-y: auto; overscroll-behavior: contain; margin: 0; padding: 6px; list-style: none;
  background: var(--white); color: var(--ink); border: 1px solid var(--line); border-radius: 14px;
  box-shadow: var(--ombre-3);
  font-family: var(--ui); font-size: 14px; line-height: 1.35; text-align: left;
}
.fle-app .fle-cv-menu li { margin: 0; padding: 0; list-style: none; }
.fle-app .fle-cv-menu [role^="menuitem"] {
  -webkit-appearance: none; appearance: none; position: relative;
  display: flex; align-items: center; gap: 8px; width: 100%; min-height: 34px;
  margin: 0; padding: 7px 12px 7px 32px; border: 0; border-radius: 9px;
  background: transparent; box-shadow: none; color: var(--ink);
  font-family: var(--ui); font-size: 14px; font-weight: 500; line-height: 1.3;
  letter-spacing: 0; text-transform: none; text-decoration: none; text-align: left;
  white-space: normal; cursor: pointer;
}
/* Le fond suit aussi le focus simple, pas seulement :focus-visible : le
   script déplace le focus dans le menu après un clic, et le navigateur
   peut alors ne pas afficher l'anneau. */
.fle-app .fle-cv-menu [role^="menuitem"]:hover,
.fle-app .fle-cv-menu [role^="menuitem"]:focus { background: var(--lavis-fort); color: var(--primary); }
.fle-app .fle-cv-menu [role^="menuitem"]:focus-visible { outline: 3px solid var(--accent-sombre); outline-offset: -3px; border-radius: 9px; }
.fle-app .fle-cv-menu [aria-checked="true"] { font-weight: 650; color: var(--primary); }
.fle-app .fle-cv-menu [aria-checked="true"]::before {
  content: ""; position: absolute; left: 13px; top: 50%; width: 5px; height: 10px; margin-top: -7px;
  border: solid currentColor; border-width: 0 2px 2px 0; transform: rotate(45deg);
}
.fle-app .fle-cv-menu [aria-disabled="true"],
.fle-app .fle-cv-menu [role^="menuitem"]:disabled { color: var(--muted); cursor: default; background: transparent; }
.fle-app .fle-cv-menu [role="separator"], .fle-app .fle-cv-menu hr {
  display: block; height: 0; margin: 5px 8px; padding: 0;
  border: 0; border-top: 1px solid var(--line); background: none;
}


/* =========================================================================
   8. LA DISCUSSION

   Une colonne de 320 px (--cv-chat-l, que le script peut changer sur la
   racine) en trois étages : la tête, le fil qui défile, la saisie. Le fil
   est sur le papier, les bulles des autres en blanc, les miennes en lavis
   de sarcelle et à droite. Le formateur se reconnaît à un filet sarcelle
   et à la mention « formateur » ; un message privé porte un liseré
   pointillé et sa mention ; un message effacé garde sa place, en italique
   gris. Aucune de ces distinctions ne repose sur la couleur seule.

   Rapports : gris sur papier 5,24:1, sur mes bulles 4,82:1, sur blanc
   5,64:1 ; sarcelle profonde sur mes bulles 6,34:1 ; --danger sur blanc
   7,14:1 ; blanc sur la mention « formateur » 7,43:1. En sombre, tous
   au-dessus de 5,8:1.
   ====================================================================== */
.fle-app.fle-app--cv .fle-cv-chat {
  grid-area: chat; position: relative; z-index: 20; display: flex; flex-direction: column;
  float: none; width: var(--cv-chat-l, 320px); max-width: 50vw; min-width: 0; min-height: 0;
  margin: 0; padding: 0; background: var(--white); color: var(--ink);
  border-left: 1px solid var(--line); font-size: var(--t-corps, 15px);
}
.fle-app.fle-app--cv:not([data-cv-chat="ouvert"]) .fle-cv-chat { display: none; }
.fle-app.fle-app--cv[data-cv-dock="droite"] .fle-cv-chat { border-left: 0; border-right: 1px solid var(--line); }

/* --- La tête ------------------------------------------------------------
   L'état « fermée aux apprenants » passe sur sa propre ligne : à 320 px,
   le titre, l'état et deux boutons ne tiennent pas ensemble. */
.fle-app .fle-cv-chat__tete {
  display: flex; flex-wrap: wrap; align-items: center; gap: 4px 6px; flex: 0 0 auto;
  min-height: 44px; padding: 6px 8px 6px 14px; border-bottom: 1px solid var(--line);
}
.fle-app .fle-cv-chat .fle-cv-chat__titre {
  margin: 0 auto 0 0; padding: 0;
  font-family: var(--ui); font-size: 15px; font-weight: 700; line-height: 1.3;
  letter-spacing: -.005em; text-transform: none; color: var(--ink);
}
.fle-app .fle-cv-chat__etat {
  order: 10; flex: 1 1 100%; margin: 0 0 2px; padding: 3px 9px;
  border-left: 3px solid var(--alerte); border-radius: 8px;
  background: var(--lavis-gris); color: var(--alerte);
  font-size: 12.5px; font-weight: 650; line-height: 1.4;
}
.fle-app .fle-cv-chat__menu-bouton, .fle-app .fle-cv-chat__fermer {
  position: relative; display: inline-grid; place-items: center; flex: 0 0 auto;
  width: 32px; height: 32px; padding: 0; border-radius: 9px; color: var(--muted);
  transition: background-color .15s ease, color .15s ease;
}
.fle-app .fle-cv-chat__menu-bouton:hover,
.fle-app .fle-cv-chat__fermer:hover,
.fle-app .fle-cv-chat__menu-bouton[aria-expanded="true"] { background: var(--lavis-fort); color: var(--primary); }
.fle-app .fle-cv-chat__menu-bouton:focus-visible,
.fle-app .fle-cv-chat__fermer:focus-visible { outline: 3px solid var(--accent-sombre); outline-offset: 2px; border-radius: 9px; }
/* Glyphes de secours, comme pour la palette : points de suspension
   verticaux et croix, en bordures. Le caractère des points n'est lu par
   aucun lecteur d'écran, le bouton ayant un aria-label. */
.fle-app .fle-cv-chat__menu-bouton:not(:has(svg))::before {
  content: "\22EE"; font-size: 20px; font-weight: 700; line-height: 1;
}
.fle-app .fle-cv-chat__fermer:not(:has(svg))::before,
.fle-app .fle-cv-chat__fermer:not(:has(svg))::after {
  content: ""; grid-area: 1 / 1; width: 14px; height: 0; border-top: 2px solid currentColor;
  transform: rotate(45deg);
}
.fle-app .fle-cv-chat__fermer:not(:has(svg))::after { transform: rotate(-45deg); }

/* --- Le fil ------------------------------------------------------------
   Une colonne flexible : la marge haute automatique de la liste pousse
   les messages en bas tant qu'ils sont peu nombreux, comme dans toute
   messagerie, sans le piège de justify-content: flex-end, qui rend le
   haut d'un contenu débordant inaccessible au défilement. */
.fle-app .fle-cv-chat__corps {
  display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0;
  overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain; padding: 10px 12px 14px;
  background: var(--paper); scrollbar-width: thin;
}
.fle-app .fle-cv-chat__anciens {
  align-self: center; flex: 0 0 auto; min-height: 30px; margin: 0 0 10px; padding: 5px 12px;
  border-radius: var(--radius-pilule, 999px); color: var(--primary); font-size: 13px;
  text-decoration: underline; text-underline-offset: 2px;
}
.fle-app .fle-cv-chat__anciens:hover { background: var(--lavis-fort); text-decoration-thickness: 2px; }
.fle-app .fle-cv-chat__fil {
  display: flex; flex-direction: column; gap: 6px; margin: auto 0 0; padding: 0; list-style: none;
}

/* Le séparateur de jour : le libellé entre deux filets. Les filets sont
   des pseudo-éléments vides, que personne n'entend. */
.fle-app .fle-cv-jour {
  display: flex; align-items: center; gap: 10px; align-self: stretch; margin: 8px 0 2px; padding: 0;
  font-size: 12px; font-weight: 650; line-height: 1.3; color: var(--muted); text-align: center;
}
.fle-app .fle-cv-jour::before,
.fle-app .fle-cv-jour::after { content: ""; flex: 1 1 auto; height: 0; border-top: 1px solid var(--line); }

/* Les bulles. La pointe (le coin peu arrondi) est du côté de l'auteur. */
.fle-app .fle-cv-msg {
  position: relative; align-self: flex-start; max-width: 86%; min-width: 0;
  margin: 0; padding: 6px 10px 7px; background: var(--white); border: 1px solid var(--line);
  border-radius: 14px 14px 14px 4px; box-shadow: var(--ombre-1); list-style: none;
}
.fle-app .fle-cv-msg--moi {
  align-self: flex-end; background: var(--lavis-fort); border-color: var(--cv-moi-bord);
  border-radius: 14px 14px 4px 14px;
}
.fle-app .fle-cv-msg--formateur { border-left: 3px solid var(--primary); }
.fle-app .fle-cv-msg--prive { border-style: dashed; border-color: var(--muted); }
.fle-app .fle-cv-msg--prive.fle-cv-msg--formateur { border-left-style: solid; border-left-color: var(--primary); }
.fle-app .fle-cv-msg--supprime { background: transparent; border-color: var(--line); box-shadow: none; }
.fle-app .fle-cv-msg--supprime .fle-cv-msg__texte { font-style: italic; color: var(--muted); }
.fle-app .fle-cv-msg--systeme {
  align-self: center; max-width: 100%; padding: 4px 12px; background: var(--lavis-gris);
  border: 0; border-radius: var(--radius-pilule, 999px); box-shadow: none; text-align: center;
}
.fle-app .fle-cv-msg--systeme .fle-cv-msg__tete { justify-content: center; }
.fle-app .fle-cv-msg--systeme .fle-cv-msg__texte { font-size: 12.5px; font-style: italic; color: var(--muted); }

.fle-app .fle-cv-msg__tete {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 6px; margin: 0 0 1px;
  font-size: 12px; line-height: 1.35; color: var(--muted);
}
.fle-app .fle-cv-msg__auteur { font-size: 12.5px; font-weight: 700; color: var(--ink); }
.fle-app .fle-cv-msg__role {
  align-self: center; padding: 0 6px; border-radius: var(--radius-pilule, 999px);
  background: var(--primary); color: var(--white);
  font-size: 11px; font-weight: 650; line-height: 1.6;
}
.fle-app .fle-cv-msg__prive { font-style: italic; color: var(--muted); }
.fle-app .fle-cv-msg__heure {
  margin-left: auto; padding-left: 6px; font-size: 11.5px; color: var(--muted);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.fle-app .fle-cv-msg__texte {
  margin: 0; font-size: 14.5px; line-height: 1.45; color: var(--ink); white-space: pre-wrap;
  overflow-wrap: break-word; overflow-wrap: anywhere;
}
.fle-app .fle-cv-msg__texte a {
  color: var(--primary); text-decoration: underline; text-underline-offset: 2px;
  overflow-wrap: anywhere;
}
.fle-app .fle-cv-msg__texte a:hover { text-decoration-thickness: 2px; }
.fle-app[data-fle-taille="1"] .fle-cv-msg__texte { font-size: 16px; }
.fle-app[data-fle-taille="2"] .fle-cv-msg__texte { font-size: 17.5px; line-height: 1.5; }

/* Les actions d'un message. À la souris, elles apparaissent au survol ou
   quand le focus entre dans le message, en barrette sous la bulle, du côté
   de son auteur, où la place ne manque jamais. Elles restent dans le flux
   du clavier pendant qu'elles sont invisibles (opacité nulle, pas
   display: none) : c'est le focus de la touche Tab qui les fait paraître.
   Sur écran tactile, il n'y a pas de survol : elles sont toujours là, dans
   la bulle (voir plus bas). */
.fle-app .fle-cv-msg__actions {
  position: absolute; z-index: 4; top: calc(100% - 6px); left: 6px; display: flex; gap: 2px;
  margin: 0; padding: 2px; background: var(--white); border-radius: var(--radius-pilule, 999px);
  box-shadow: var(--ombre-2), 0 0 0 1px var(--line); white-space: nowrap;
  opacity: 0; pointer-events: none; transition: opacity .12s ease;
}
.fle-app .fle-cv-msg--moi .fle-cv-msg__actions { left: auto; right: 6px; }
.fle-app .fle-cv-msg:hover .fle-cv-msg__actions,
.fle-app .fle-cv-msg:focus-within .fle-cv-msg__actions { opacity: 1; pointer-events: auto; }
.fle-app .fle-cv-msg__action {
  display: inline-flex; align-items: center; min-height: 26px; padding: 3px 10px;
  border-radius: var(--radius-pilule, 999px);
  color: var(--primary); font-size: 12px; white-space: nowrap;
}
.fle-app .fle-cv-msg__action:hover { background: var(--lavis-fort); }
.fle-app .fle-cv-msg__action--tous { color: var(--danger); }
.fle-app .fle-cv-msg__action--tous:hover {
  background: var(--lavis-gris); background: color-mix(in srgb, var(--danger) 10%, var(--white));
}
.fle-app .fle-cv-msg__action:focus-visible { outline: 3px solid var(--accent-sombre); outline-offset: 2px; border-radius: var(--radius-pilule, 999px); }

@media (hover: none), (pointer: coarse) {
  .fle-app .fle-cv-msg__actions, .fle-app .fle-cv-msg--moi .fle-cv-msg__actions {
    position: static; justify-content: flex-end; flex-wrap: wrap;
    margin: 6px -4px -2px 0; padding: 0; background: transparent; box-shadow: none;
    opacity: 1; pointer-events: auto;
  }
  .fle-app .fle-cv-msg__action { min-height: 32px; padding: 6px 10px; }
}

/* « Nouveaux messages » : collé au bas de la zone qui défile tant qu'on lit
   plus haut, à sa place naturelle quand on est en bas. */
.fle-app .fle-cv-chat__nouveaux {
  position: -webkit-sticky; position: sticky; bottom: 8px; z-index: 5;
  align-self: center; flex: 0 0 auto; display: inline-flex; align-items: center; gap: 7px;
  min-height: 32px; margin: 8px 0 0; padding: 6px 14px; border-radius: var(--radius-pilule, 999px);
  background: var(--primary); color: var(--white); font-size: 13px; box-shadow: var(--ombre-2);
}
.fle-app .fle-cv-chat__nouveaux::after {
  content: ""; display: block; width: 6px; height: 6px; margin-top: -3px;
  border: solid currentColor; border-width: 0 0 2px 2px; transform: rotate(-45deg);
}
.fle-app .fle-cv-chat__nouveaux:focus-visible { outline: 3px solid var(--accent-sombre); outline-offset: 2px; border-radius: var(--radius-pilule, 999px); }

/* --- La saisie ---------------------------------------------------------
   Une rangée flexible plutôt qu'une grille : l'avis masqué ne laisse
   aucun intervalle derrière lui. Le champ garde 16 px de corps (règle de
   fle-classe.css : en dessous, iOS zoome à la mise au point) ; il fait
   deux lignes au départ et grandit jusqu'à six, par field-sizing là où il
   est connu, par le script ailleurs, borné de toute façon par max-height. */
.fle-app .fle-cv-chat__saisie {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: 6px 8px; flex: 0 0 auto;
  margin: 0; padding: 8px 10px 10px; padding-bottom: max(10px, env(safe-area-inset-bottom));
  border-top: 1px solid var(--line); background: var(--white);
}
.fle-app .fle-cv-chat__avis {
  flex: 1 1 100%; margin: 0; padding: 6px 10px;
  border-left: 3px solid var(--alerte); border-radius: 9px;
  background: var(--lavis-gris); color: var(--ink); font-size: 13px; line-height: 1.4;
}
.fle-app .fle-cv-chat__ligne {
  display: flex; align-items: center; gap: 6px; flex: 1 1 100%; min-width: 0;
  font-size: 12.5px; color: var(--muted);
}
.fle-app .fle-cv-chat__ligne label {
  display: inline; float: none; margin: 0; padding: 0;
  font-size: 12.5px; font-weight: 650; line-height: 1.3; color: var(--muted);
  text-transform: none; letter-spacing: 0;
}
.fle-app .fle-cv-chat select.fle-cv-chat__dest {
  -webkit-appearance: menulist; appearance: auto;
  flex: 0 1 auto; width: auto; min-width: 0; max-width: 100%;
  height: 32px; margin: 0; padding: 2px 8px;
  border: 1.5px solid var(--cv-champ-bord); border-radius: 9px;
  background-color: var(--white); background-image: none; color: var(--ink);
  font-family: var(--ui); font-size: 14px; line-height: 1.2; box-shadow: none;
}
.fle-app .fle-cv-chat__compteur {
  flex: 0 0 auto; margin-left: auto; font-size: 12px; color: var(--muted);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.fle-app .fle-cv-chat textarea.fle-cv-chat__texte {
  display: block; flex: 1 1 0; width: auto; min-width: 0;
  min-height: calc(2.8em + 19px); max-height: calc(8.4em + 19px); margin: 0; padding: 8px 11px;
  border: 1.5px solid var(--cv-champ-bord); border-radius: 12px;
  background: var(--white); color: var(--ink);
  font-family: var(--ui); font-size: 16px; line-height: 1.4; resize: none; overflow-y: auto;
  box-shadow: none; field-sizing: content;
}
.fle-app .fle-cv-chat textarea.fle-cv-chat__texte::placeholder { color: var(--muted); opacity: 1; }
.fle-app .fle-cv-chat textarea.fle-cv-chat__texte:focus { border-color: var(--accent-plein); }
.fle-app .fle-cv-chat textarea.fle-cv-chat__texte:disabled,
.fle-app .fle-cv-chat select.fle-cv-chat__dest:disabled { background-color: var(--lavis-gris); color: var(--muted); cursor: not-allowed; }
.fle-app .fle-cv-chat .fle-cv-chat__envoyer {
  flex: 0 0 auto; min-height: 40px; margin: 0; padding: 8px 16px; font-size: 14px;
}
@media (pointer: coarse) {
  .fle-app .fle-cv-chat select.fle-cv-chat__dest { height: 38px; font-size: 16px; }
  .fle-app .fle-cv-chat .fle-cv-chat__envoyer { min-height: 44px; }
}


/* =========================================================================
   9. ÉCRANS ÉTROITS

   Sous 900 px, les libellés des boutons du bandeau s'effacent (leur
   aria-label reste) et la discussion ouverte se superpose à la scène au
   lieu de la rétrécir : à 320 px de large, elle en mangerait la moitié.
   Elle est placée, comme la languette, en position absolue dans la zone
   « scene », donc toujours à droite de la scène, quel que soit le côté de
   la palette.

   Sous 700 px, la palette passe en bas, en rangée qui défile, quelle que
   soit la préférence enregistrée ; le mode flottant n'y a plus de sens.
   Sous 600 px, la discussion prend toute la largeur.

   Le script doit tenir aria-orientation de la barre d'outils accordé à
   ces seuils : matchMedia("(max-width: 699.98px)").
   ====================================================================== */
@media (max-width: 899.98px) {
  .fle-app .fle-cv-haut__libelle { display: none; }
  .fle-app .fle-cv-haut__bouton { width: 32px; padding: 0; }
  .fle-app .fle-cv-badge { position: absolute; top: -3px; right: -4px; }

  .fle-app.fle-app--cv .fle-cv-chat, .fle-app.fle-app--cv[data-cv-dock="droite"] .fle-cv-chat {
    position: absolute; grid-area: scene; z-index: 35; top: 0; right: 0; bottom: 0; left: auto;
    width: min(var(--cv-chat-l, 320px), 100%); max-width: none;
    border-left: 1px solid var(--line); border-right: 0; box-shadow: var(--ombre-3);
  }
}

@media (max-width: 699.98px) {
  .fle-app.fle-app--cv, .fle-app.fle-app--cv[data-cv-dock] {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-rows: auto minmax(0, 1fr) auto;
    grid-template-areas:
      "haut  haut"
      "scene chat"
      "dock  dock";
  }
  /* Chaque règle est écrite deux fois, avec et sans [data-cv-dock] : la
     première l'emporte sur les règles propres à un côté, la seconde vaut
     si l'attribut manque. */
  .fle-app.fle-app--cv > .fle-corps { padding: 10px 10px 24px; }
  .fle-app.fle-app--cv .fle-cv-dock, .fle-app.fle-app--cv[data-cv-dock] .fle-cv-dock {
    position: static; z-index: 20; flex-direction: row; max-height: none; padding: 6px 8px;
    padding-bottom: max(6px, env(safe-area-inset-bottom));
    border: 0; border-top: 1px solid var(--line); border-radius: 0; box-shadow: none;
    overflow-x: auto; overflow-y: hidden;
  }
  .fle-app.fle-app--cv .fle-cv-dock__liste,
  .fle-app.fle-app--cv[data-cv-dock] .fle-cv-dock__liste { flex-direction: row; flex: 1 0 auto; }
  .fle-app.fle-app--cv .fle-cv-dock__separateur,
  .fle-app.fle-app--cv[data-cv-dock] .fle-cv-dock__separateur { width: 1px; height: 20px; margin: 0 3px; }
  .fle-app.fle-app--cv .fle-cv-dock__poignee,
  .fle-app.fle-app--cv[data-cv-dock] .fle-cv-dock__poignee { display: none; }
  .fle-app.fle-app--cv .fle-cv-dock__replier,
  .fle-app.fle-app--cv[data-cv-dock] .fle-cv-dock__replier { --cv-chevron: -45deg; margin: 0 0 0 auto; }

  .fle-app.fle-app--cv[data-cv-replie="1"] > .fle-corps,
  .fle-app.fle-app--cv[data-cv-replie="1"][data-cv-dock] > .fle-corps { padding: 10px 10px 34px; }
  .fle-app.fle-app--cv[data-cv-replie="1"] .fle-cv-languette,
  .fle-app.fle-app--cv[data-cv-replie="1"][data-cv-dock] .fle-cv-languette {
    --cv-chevron: 135deg; top: auto; right: auto; bottom: 0; left: 50%;
    width: 64px; height: 24px; margin: 0 0 0 -32px; border-radius: 12px 12px 0 0;
    box-shadow: var(--ombre-2);
  }
  .fle-app.fle-app--cv[data-cv-replie="1"] .fle-cv-languette:hover,
  .fle-app.fle-app--cv[data-cv-replie="1"][data-cv-dock] .fle-cv-languette:hover { width: 64px; height: 28px; }

  .fle-app.fle-app--cv:not([data-cv-replie="1"]) .fle-annonce { bottom: 66px; }
}

@media (max-width: 599.98px) {
  .fle-app.fle-app--cv .fle-cv-chat, .fle-app.fle-app--cv[data-cv-dock="droite"] .fle-cv-chat {
    left: 0; width: auto; border-left: 0; box-shadow: none;
  }
  .fle-app .fle-cv-haut { gap: 6px; }
  .fle-app .fle-cv-haut__ici { display: none; }
}

@media (max-width: 479.98px) {
  /* Sur un petit téléphone, la marque cède sa place au nom de la salle :
     la palette et la discussion disent assez où l'on est. */
  .fle-app .fle-cv-haut__marque { display: none; }
  .fle-app .fle-cv-haut { gap: 4px; padding-left: max(8px, env(safe-area-inset-left)); }
}


/* =========================================================================
   10. PRÉFÉRENCES DU SYSTÈME
   ====================================================================== */

/* Mouvement réduit : rien ne glisse, rien ne s'estompe. La bulle et les
   actions d'un message paraissent d'un coup. */
@media (prefers-reduced-motion: reduce) {
  .fle-app [class*="fle-cv-"],
  .fle-app [class*="fle-cv-"]::before,
  .fle-app [class*="fle-cv-"]::after,
  .fle-app .fle-nav__special { transition: none !important; }
  .fle-app .fle-tuile.fle-tuile--cv,
  .fle-app .fle-tuile.fle-tuile--cv:hover { transition: none; transform: none; }
}

/* Contraste renforcé : les ombres s'effacent et les filets épaississent,
   comme dans le reste de l'application. Badges et pastilles passent au
   trait, à la façon de .fle-pastille-nb. */
@media (prefers-contrast: more) {
  .fle-app .fle-cv-haut { border-bottom-width: 2px; box-shadow: none; }
  .fle-app.fle-app--cv .fle-cv-dock,
  .fle-app.fle-app--cv .fle-cv-chat { border-width: 2px; box-shadow: none; }
  .fle-app .fle-cv-msg { border-color: var(--muted); box-shadow: none; }
  .fle-app .fle-cv-dock__bouton[aria-current="true"] { box-shadow: 0 0 0 2px var(--ink); }
  .fle-app .fle-cv-menu,
  .fle-app .fle-cv-bulle { border: 2px solid var(--ink); box-shadow: none; }
  .fle-app .fle-cv-badge, .fle-app .fle-cv-dock__pastille {
    background: var(--white); color: var(--ink); box-shadow: inset 0 0 0 2px var(--ink);
  }
}

/* Couleurs forcées : les fonds et les ombres sont remplacés par le
   système. Ce qui ne tenait qu'à un fond (l'atelier courant, le bouton
   enfoncé, les pastilles) reçoit une bordure ; la flèche de la bulle,
   faite de bordures transparentes, est retirée. */
@media (forced-colors: active) {
  .fle-app .fle-cv-dock__bouton[aria-current="true"] { border: 2px solid Highlight; }
  .fle-app .fle-cv-haut__bouton[aria-expanded="true"],
  .fle-app .fle-cv-haut__bouton[aria-pressed="true"],
  .fle-app.fle-app--cv[data-cv-chat="ouvert"] .fle-cv-haut__bouton[data-action="chat"] { border: 2px solid Highlight; }
  .fle-app .fle-cv-bulle,
  .fle-app .fle-cv-badge,
  .fle-app .fle-cv-dock__pastille,
  .fle-app .fle-cv-haut__chrono,
  .fle-app .fle-cv-msg__role,
  .fle-app .fle-cv-msg__actions,
  .fle-app .fle-cv-languette,
  .fle-app .fle-cv-chat__nouveaux { border: 1px solid CanvasText; }
  .fle-app .fle-cv-bulle::after { display: none; }
}

/* Impression : la scène seule, à plat, dans le flux de la page. */
@media print {
  html.fle-cv-ouverte,
  body.fle-cv-ouverte { overflow: visible; }
  .fle-app.fle-app--cv { position: static; display: block; height: auto; overflow: visible; }
  .fle-app.fle-app--cv .fle-cv-haut,
  .fle-app.fle-app--cv .fle-cv-dock,
  .fle-app.fle-app--cv .fle-cv-chat,
  .fle-app.fle-app--cv .fle-cv-languette,
  .fle-app.fle-app--cv .fle-cv-bulle,
  .fle-app.fle-app--cv .fle-cv-menu { display: none !important; }
  .fle-app.fle-app--cv > .fle-corps { overflow: visible; padding: 0; }
}
