/* Système visuel Soskool (DESIGN.md), repris du prototype `prototype/gabarit.html`.
   Clair ; un seul accent (indigo lagon) pour l'actif ; l'argile pour ce qui attend ;
   couleurs vives réservées aux prestations. Police système, chiffres tabulaires. */

/* ------------------------------------------------------------------ jetons -- */
:root {
  --rayon: 8px;
  --police: "Segoe UI Variable Text", "Segoe UI", -apple-system, BlinkMacSystemFont, Roboto, "Helvetica Neue", Arial, sans-serif;
  --fond: #f4f5f7; --rail: #f9fafb; --paper: #ffffff; --surface: #f6f7f9; --survol: #eef0f3;
  --line: #e3e5ea; --line-forte: #cfd3da; --filet-doux: #eef0f3; --ligne-paire: #f8f9fb; --bord-champ: #868c97;
  --ink: #121417; --ink2: #464c57; --ink3: #626977;
  --lagoon: #4f55d6; --lagoon-soft: #eff0fd; --lagoon-line: #c9cbf5;
  --clay: #a84b1c; --clay-soft: #fdf3ec; --clay-line: #f1cdb4;
  --vert: #1d7a4e; --rouge: #c2352b;
  /* Les teintes des tuteurs, au planning des cours particuliers (28/09). */
  --t0: #4f55d6; --t1: #1d7a4e; --t2: #a84b1c; --t3: #8a3ea8; --t4: #0e7490;
  --t5: #b45309; --t6: #be185d; --t7: #4d7c0f;
  /* Ce qui s'écrit SUR un aplat : accent (lagon, argile), bouton principal, message. */
  --sur-accent: #ffffff;
  --puce-active-fond: #4f55d6; --puce-active-texte: #ffffff; --puce-active-bord: #4f55d6;
  --primaire-fond: #121417; --primaire-texte: #ffffff; --primaire-survol: #2b2f36; --primaire-appui: #000000;
  --pole-actif-sous: #cfd3da;
  /* Les cartes de « Toute l'équipe », écran des tuteurs du jour (28/09). */
  --carte-equipe-fond: #ffffff; --carte-equipe-bord: #d3d7de;
  --message-fond: #121417; --message-texte: #ffffff; --message-refus: #7a2d12; --message-bon: #17402c;
  /* Pastilles de prestation : la teinte est posée en ligne, la clarté vient d'ici. */
  --presta-fond-l: 0.94; --presta-fond-c: 0.05;
  --presta-texte-l: 0.42; --presta-texte-c: 0.12;
  --presta-ligne-l: 0.84; --presta-ligne-c: 0.08;
  --erreur: #7a2d12;
  --barre-haut: rgb(244 245 247 / 0.92); --voile: rgb(18 20 23 / 0.38); --voile-photo: rgb(12 14 17 / 0.86); --anneau: rgb(79 85 214 / 0.18);
  --logo-fond: transparent; --logo-melange: multiply;
  --ombre: 0 1px 2px rgb(18 20 23 / 0.05), 0 2px 8px rgb(18 20 23 / 0.04);
  --ombre-survol: 0 2px 4px rgb(18 20 23 / 0.06), 0 6px 16px rgb(18 20 23 / 0.06);
  --ombre-haute: 0 12px 32px rgb(18 20 23 / 0.16), 0 2px 6px rgb(18 20 23 / 0.08);
  color-scheme: light;
}

/* ------------------------------------------------------------ mode sombre --
   Suit la préférence du système, sauf choix manuel mémorisé sur l'appareil
   (`theme.js` pose data-theme="light" ou "dark" sur <html> avant l'affichage).
   Les deux blocs sont identiques : une préférence de système, un choix forcé.
   Contrastes vérifiés par ecrans/tests/test_mode_sombre.py (WCAG AA, 4,5:1). */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
  --fond: #111317; --rail: #15181d; --paper: #1b1e24; --surface: #22262d; --survol: #2a2f37;
  --line: #30353e; --line-forte: #4a505b; --filet-doux: #262a31; --ligne-paire: #1f2228; --bord-champ: #6f7684;
  --ink: #eef0f3; --ink2: #c3c8d1; --ink3: #9ba2ae;
  --lagoon: #a4a8ff; --lagoon-soft: #252946; --lagoon-line: #474e9c;
  --clay: #f2a676; --clay-soft: #33241b; --clay-line: #6b4128;
  --vert: #62d29a; --rouge: #ff8f85;
  --t0: #a4a8ff; --t1: #62d29a; --t2: #f2a676; --t3: #d6a4f0; --t4: #67d4ea;
  --t5: #f5c16c; --t6: #f59ac5; --t7: #a8d86b;
  --sur-accent: #111317;
  --puce-active-fond: #252946; --puce-active-texte: #a4a8ff; --puce-active-bord: #474e9c;
  --primaire-fond: #4f55d6; --primaire-texte: #ffffff; --primaire-survol: #5f65e0; --primaire-appui: #454bc4;
  --pole-actif-sous: #e4e6ff;
  /* Les cartes de « Toute l'équipe » : un cran au-dessus du fond, filet visible. */
  --carte-equipe-fond: #1d2027; --carte-equipe-bord: #3f4550;
  --message-fond: #2d323b; --message-texte: #ffffff; --message-refus: #7a2d12; --message-bon: #17402c;
  /* Pastilles de prestation : aplat sombre, texte clair — même teinte. */
  --presta-fond-l: 0.30; --presta-fond-c: 0.06;
  --presta-texte-l: 0.90; --presta-texte-c: 0.09;
  --presta-ligne-l: 0.46; --presta-ligne-c: 0.09;
  --erreur: #ff9f80;
  --barre-haut: rgb(17 19 23 / 0.9); --voile: rgb(0 0 0 / 0.6); --voile-photo: rgb(0 0 0 / 0.9); --anneau: rgb(164 168 255 / 0.3);
  --logo-fond: #f4f5f7; --logo-melange: normal;
  --ombre: 0 1px 2px rgb(0 0 0 / 0.4), 0 2px 8px rgb(0 0 0 / 0.25);
  --ombre-survol: 0 2px 4px rgb(0 0 0 / 0.45), 0 6px 16px rgb(0 0 0 / 0.35);
  --ombre-haute: 0 12px 32px rgb(0 0 0 / 0.6), 0 2px 6px rgb(0 0 0 / 0.4);
  color-scheme: dark;
  }
}
:root[data-theme="dark"] {
  --fond: #111317; --rail: #15181d; --paper: #1b1e24; --surface: #22262d; --survol: #2a2f37;
  --line: #30353e; --line-forte: #4a505b; --filet-doux: #262a31; --ligne-paire: #1f2228; --bord-champ: #6f7684;
  --ink: #eef0f3; --ink2: #c3c8d1; --ink3: #9ba2ae;
  --lagoon: #a4a8ff; --lagoon-soft: #252946; --lagoon-line: #474e9c;
  --clay: #f2a676; --clay-soft: #33241b; --clay-line: #6b4128;
  --vert: #62d29a; --rouge: #ff8f85;
  --t0: #a4a8ff; --t1: #62d29a; --t2: #f2a676; --t3: #d6a4f0; --t4: #67d4ea;
  --t5: #f5c16c; --t6: #f59ac5; --t7: #a8d86b;
  --sur-accent: #111317;
  --puce-active-fond: #252946; --puce-active-texte: #a4a8ff; --puce-active-bord: #474e9c;
  --primaire-fond: #4f55d6; --primaire-texte: #ffffff; --primaire-survol: #5f65e0; --primaire-appui: #454bc4;
  --pole-actif-sous: #e4e6ff;
  /* Les cartes de « Toute l'équipe » : un cran au-dessus du fond, filet visible. */
  --carte-equipe-fond: #1d2027; --carte-equipe-bord: #3f4550;
  --message-fond: #2d323b; --message-texte: #ffffff; --message-refus: #7a2d12; --message-bon: #17402c;
  /* Pastilles de prestation : aplat sombre, texte clair — même teinte. */
  --presta-fond-l: 0.30; --presta-fond-c: 0.06;
  --presta-texte-l: 0.90; --presta-texte-c: 0.09;
  --presta-ligne-l: 0.46; --presta-ligne-c: 0.09;
  --erreur: #ff9f80;
  --barre-haut: rgb(17 19 23 / 0.9); --voile: rgb(0 0 0 / 0.6); --voile-photo: rgb(0 0 0 / 0.9); --anneau: rgb(164 168 255 / 0.3);
  --logo-fond: #f4f5f7; --logo-melange: normal;
  --ombre: 0 1px 2px rgb(0 0 0 / 0.4), 0 2px 8px rgb(0 0 0 / 0.25);
  --ombre-survol: 0 2px 4px rgb(0 0 0 / 0.45), 0 6px 16px rgb(0 0 0 / 0.35);
  --ombre-haute: 0 12px 32px rgb(0 0 0 / 0.6), 0 2px 6px rgb(0 0 0 / 0.4);
  color-scheme: dark;
}
* { box-sizing: border-box; }
html { scrollbar-color: var(--line-forte) transparent; }
body {
  margin: 0; font-family: var(--police); font-size: 14px; line-height: 1.45;
  color: var(--ink); background: var(--fond);
  font-variant-numeric: tabular-nums; -webkit-font-smoothing: antialiased;
  caret-color: var(--lagoon); accent-color: var(--lagoon);
}
::selection { background: var(--lagoon-line); color: var(--ink); }
h1, h2, h3 { font-family: var(--police); margin: 0; letter-spacing: -0.01em; text-wrap: balance; }
button { font: inherit; color: inherit; cursor: pointer; border: none; background: none; padding: 0; }
button:disabled { cursor: not-allowed; opacity: .5; }
select, input, textarea { font: inherit; color: inherit; }
a { color: var(--lagoon); text-underline-offset: 3px; }
:focus-visible { outline: 2px solid var(--lagoon); outline-offset: 2px; border-radius: 6px; }
.icone { width: 16px; height: 16px; flex-shrink: 0; stroke: currentColor; fill: none; stroke-width: 1.75;
         stroke-linecap: round; stroke-linejoin: round; vertical-align: -3px; }
[hidden], .masque { display: none !important; }

/* ---------------------------------------------------------------- coquille -- */
.app { display: grid; grid-template-columns: 232px minmax(0, 1fr); min-height: 100vh; }
.rail { background: var(--rail); border-right: 1px solid var(--line); display: flex; flex-direction: column;
        gap: 18px; padding: 16px 12px; position: sticky; top: 0; height: 100vh; overflow-y: auto; }
.marque { display: flex; justify-content: center; padding: 6px 4px 2px; }
.marque img { max-width: 160px; width: 100%; height: auto; display: block; mix-blend-mode: var(--logo-melange);
              background: var(--logo-fond); border-radius: 8px; }
.onglets { display: flex; flex-direction: column; gap: 2px; }
.onglet { display: flex; align-items: center; gap: 10px; padding: 7px 10px; border-radius: 6px; font-size: 14px;
          color: var(--ink2); text-decoration: none; white-space: nowrap; transition: background .15s, color .15s; }
.onglet:hover { background: var(--survol); color: var(--ink); }
.onglet[aria-current="page"] { background: var(--paper); color: var(--ink); font-weight: 600; box-shadow: var(--ombre); }
.onglet[aria-current="page"] .icone { color: var(--lagoon); }
/* Le menu de la direction en deux groupes (27/09) : « Supervision », ce qu'elle
   partage avec les superviseurs, puis « Direction », ce qu'elle seule voit. Réduit ou
   en rangée, les titres s'effacent et un trait sépare les deux familles. */
.groupe-onglets { display: flex; flex-direction: column; gap: 2px; }
.groupe-onglets + .groupe-onglets { margin-top: 14px; }
.titre-groupe { margin: 0 0 4px; padding: 0 10px; font-size: 12px; font-weight: 600; color: var(--ink3); }
.rail-reduit .titre-groupe { display: none; }
.rail-reduit .groupe-onglets + .groupe-onglets { margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--line); }
/* En rangée (tablette), chaque groupe est une bande : le premier remplit déjà la
   largeur, un trait vertical en tête de la seconde ne séparait rien. */
@media (max-width: 900px) {
  .groupe-onglets { flex-direction: row; flex-wrap: wrap; flex-basis: 100%; }
  .titre-groupe { display: none; }
  .groupe-onglets + .groupe-onglets { margin-top: 6px; padding-top: 6px; border-top: 1px solid var(--line); }
}
/* Pastille de l'onglet « À remplir » (lot 3, point 6) : en argile, parce qu'elle
   attend un geste ; absente quand il n'y a rien — elle est vide, donc sans boîte
   (`:empty`), et rien ne s'affiche. Le rail réduit n'a plus la place d'un nombre
   à côté de l'icône : la pastille se réduit alors à un point, au coin de la case. */
.pastille-onglet { margin-left: auto; min-width: 18px; padding: 0 6px; border-radius: 20px;
                   background: var(--clay); color: var(--sur-accent);
                   font-size: 12px; font-weight: 650; line-height: 17px; text-align: center; }
.pastille-onglet:empty { display: none; }
/* Lu par un lecteur d'écran, invisible à l'œil : « 3 à traiter » (27/09). */
.lecteur-ecran { position: absolute; width: 1px; height: 1px; overflow: hidden;
                 clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }
/* Le lien d'évitement (A12) : masqué comme `.lecteur-ecran`, montré dès qu'il a le
   focus, au-dessus de tout (la barre du haut est collée, le calque est à 50). */
.lien-evitement { position: absolute; width: 1px; height: 1px; overflow: hidden;
                  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }
.lien-evitement:focus { position: fixed; top: 8px; left: 8px; z-index: 80; width: auto; height: auto;
                        clip: auto; clip-path: none; padding: 10px 14px; border-radius: 8px;
                        background: var(--paper); color: var(--ink); font-weight: 650;
                        box-shadow: var(--ombre-haute); outline: 2px solid var(--lagoon); }
/* Le titre des pages d'erreur (A20) : un vrai `<h1>`, à la taille du texte gras
   qu'il remplace. */
.titre-erreur { font-size: 15px; font-weight: 700; margin: 0 0 8px; }
/* L'ancre « à traiter » ne tombe pas sous la barre du haut. */
.ancre-a-traiter { display: block; scroll-margin-top: 90px; }
.rail-reduit .onglet { position: relative; }
.rail-reduit .pastille-onglet { position: absolute; top: 3px; right: 3px; margin: 0;
                                min-width: 8px; height: 8px; padding: 0; overflow: hidden;
                                color: transparent; line-height: 8px; }
.rail-bas { margin-top: auto; display: flex; flex-direction: column; gap: 10px; }
.qui { display: flex; gap: 9px; align-items: flex-start; font-size: 13px; color: var(--ink2); padding: 0 10px; }
.qui .point, .role .point { width: 8px; height: 8px; border-radius: 50%; border: 1.5px solid currentColor; flex-shrink: 0; margin-top: 4px; }
.role { display: flex; align-items: center; gap: 9px; padding: 7px 10px; border-radius: 6px; font-size: 13px;
        color: var(--ink2); width: 100%; text-align: left; }
.role .point { margin-top: 0; }
/* Les icônes du menu (cadenas, porte) s'alignent sur celle du thème : pas de marge en
   plus du `gap` (relecture de la revue d'affichage du 26/09). */
.role .icone-bouton { margin-right: 0; }
.role:hover { background: var(--survol); color: var(--ink); }
.bascule-rail { display: flex; align-items: center; gap: 10px; width: 100%; min-height: 36px; padding: 7px 10px;
                border-radius: 6px; border-top: 1px solid var(--line); font-size: 13px; color: var(--ink2); text-align: left; }
.bascule-rail:hover { background: var(--survol); color: var(--ink); }
.bascule-rail .texte { flex-grow: 1; }
/* La touche « [ » : une boîte fixe de 18 px où le crochet, un tracé SVG de 10 × 14
   centré dans son cadre, se centre par construction (retours de Kealohi, 26 et 27/09).
   Écrit comme un caractère, il se plaçait selon les mesures de la police : réglé au
   pixel dans un navigateur, il restait décalé dans un autre. */
.bascule-rail kbd { color: var(--ink3); border: 1px solid var(--line-forte);
                    border-radius: 5px; background: var(--paper);
                    display: inline-flex; align-items: center; justify-content: center;
                    box-sizing: border-box; width: 18px; height: 18px; padding: 0;
                    flex-shrink: 0; }
.bascule-rail kbd svg { display: block; }
/* Sur <html> et non plus sur `.app` (lot 4) : `theme.js` la pose avant l'affichage,
   le menu ne s'ouvre plus à 232 px pour se refermer aussitôt. */
.rail-reduit .app { grid-template-columns: 64px minmax(0, 1fr); }
.rail-reduit .rail { padding: 12px 8px; align-items: center; }
.rail-reduit .marque, .rail-reduit .bascule-rail kbd, .rail-reduit .qui { display: none; }
/* Réduit, le libellé est masqué à l'œil mais reste lu (vérification du 28/09, A5) :
   en `display: none`, le nom d'un onglet à pastille se calculait sur la pastille
   seule, et « Tableau de bord » s'annonçait « 3 à traiter ». */
.rail-reduit .texte { position: absolute; width: 1px; height: 1px; overflow: hidden;
                      clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }
/* Le libellé court, sous l'icône, n'existe qu'au doigt dans le menu réduit (E6) :
   caché ailleurs, et jamais lu (`aria-hidden`) — le libellé entier l'est déjà. */
.texte-court { display: none; }
@media (pointer: coarse) and (min-width: 901px) {
  /* Réduit par défaut sur la tablette en paysage : neuf icônes sans nom, un `title`
     qu'un doigt ne fait jamais paraître, des pastilles réduites à un point (E6).
     Libellé à 12 px, le plus petit pas de DESIGN.md (29/09) : à 76 px d'onglet, moins
     2 × 2 px de marge, « Signalements » (71 px mesurés) tient sur une ligne. */
  .rail-reduit .app { grid-template-columns: 84px minmax(0, 1fr); }
  .rail-reduit .rail { padding: 12px 4px; }
  /* `.onglets .onglet` : le plancher de 44 × 44 px, écrit plus bas, ne l'écrase pas. */
  .rail-reduit .onglets .onglet { flex-direction: column; gap: 2px; width: 76px; height: auto; min-height: 52px;
                         padding: 6px 2px; white-space: normal; }
  .rail-reduit .texte-court { display: block; font-size: 12px; line-height: 1.15; text-align: center;
                              max-width: 100%; overflow-wrap: anywhere; }
  .rail-reduit .pastille-onglet { top: 2px; right: 4px; min-width: 16px; height: 16px; padding: 0 4px;
                                  color: var(--sur-accent); font-size: 11px; line-height: 16px; }
}
.rail-reduit .onglet, .rail-reduit .role, .rail-reduit .bascule-rail { width: 40px; height: 36px; justify-content: center; padding: 0; min-height: 0; }
.rail-reduit .bascule-rail .icone { transform: scaleX(-1); }

.zone { min-width: 0; display: flex; flex-direction: column; }
.barre-haut { position: sticky; top: 0; z-index: 20; display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
              padding: 10px 24px; min-height: 58px; background: var(--barre-haut);
              backdrop-filter: saturate(1.4) blur(10px); border-bottom: 1px solid var(--line); }
.titre-page { display: flex; align-items: baseline; gap: 10px; margin-right: auto; min-width: 0; }
.titre-page h1 { font-size: 17px; font-weight: 650; }
.titre-page span { font-size: 13px; color: var(--ink3); white-space: nowrap; }
/* Vérification du 27/09 (U1) : un formulaire `.commandes` dans l'en-tête y gardait
   sa marge basse de 16 px, et les boutons de période flottaient 8 px au-dessus du
   titre et de l'horloge (Séances, Pilotage, Assiduité, Registre, Fiche élève). */
.barre-haut > .commandes { margin-bottom: 0; }
/* U3 : sur téléphone, le sous-titre passe à la ligne au lieu d'être rogné au bord. */
@media (max-width: 600px) {
  .titre-page { flex-wrap: wrap; row-gap: 2px; }
  .titre-page span { white-space: normal; }
}
.horloge-reelle { font-weight: 650; font-size: 15px; padding: 5px 10px; border: 1px solid var(--line);
                  border-radius: var(--rayon); background: var(--paper); box-shadow: var(--ombre); }
.principal { padding: 22px 24px 64px; max-width: 1680px; width: 100%; }
.titre-vue { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; margin: 4px 0 12px; }
.titre-vue h2 { font-size: 15px; font-weight: 650; }
.titre-vue span { font-size: 13px; color: var(--ink3); }
.titre-vue .attend { color: var(--clay); }
.espace { flex-grow: 1; }

/* ----------------------------------------------------------------- boutons -- */
.puce, .mini, .primaire, .secondaire {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px; white-space: nowrap;
  border-radius: var(--rayon); font-weight: 550; text-decoration: none;
  transition: background .15s, border-color .15s, color .15s, box-shadow .15s;
}
.puce { border: 1px solid var(--line); background: var(--paper); padding: 5px 10px; font-size: 13px; color: var(--ink2); }
.puce:hover { background: var(--surface); color: var(--ink); }
/* En sombre, un aplat lavande était la tache la plus claire de l'écran (E19) : les
   jetons `--puce-active-*` le rendent en fond pâle, comme un repli ouvert. */
.puce.actif { background: var(--puce-active-fond); color: var(--puce-active-texte);
              border-color: var(--puce-active-bord); }
.primaire { background: var(--primaire-fond); color: var(--primaire-texte); padding: 8px 14px; font-size: 14px; box-shadow: var(--ombre); }
.primaire:hover { background: var(--primaire-survol); }
.primaire:active { background: var(--primaire-appui); box-shadow: none; }
.primaire.argile { background: var(--clay); color: var(--sur-accent); }
.secondaire { background: var(--paper); border: 1px solid var(--line); padding: 7px 13px; font-size: 14px;
              color: var(--ink); box-shadow: var(--ombre); }
.secondaire:hover { background: var(--surface); border-color: var(--line-forte); }
.mini { border: 1px solid var(--line); background: var(--paper); padding: 3px 8px; font-size: 12px; color: var(--ink2); }
.mini:hover { background: var(--lagoon-soft); border-color: var(--lagoon-line); color: var(--lagoon); }
.lien-discret { font-size: 12px; color: var(--ink3); text-decoration: underline; align-self: flex-start; padding: 2px 0; }
.htmx-request.primaire, .htmx-request.secondaire, .htmx-request.choix { opacity: .6; cursor: progress; }
/* Plan « ergonomie-5 » (inventaire du 07/10, § 1) : TOUT bouton qui envoie — « Arrivé »,
   « Vu », « Rappel », « Clore »… — s'atténue le temps de l'aller-retour, comme les gros ;
   `soskool.js` pose `aria-busy` et arrête le second toucher. Le bouton d'envoi d'un
   formulaire suit son formulaire. */
button[aria-busy="true"], form[aria-busy="true"] button:not([type="button"]) {
  opacity: .6; cursor: progress; }

/* ------------------------------------------------------------ compteurs -- */
.compteurs { display: flex; flex-wrap: wrap; background: var(--paper); border: 1px solid var(--line);
             border-radius: 10px; box-shadow: var(--ombre); margin-bottom: 20px; overflow: hidden; }
.compteur { flex: 1 1 128px; padding: 11px 16px; display: flex; flex-direction: column; gap: 3px;
            border-right: 1px solid var(--line); }
.compteur:last-child { border-right: none; }
.compteur .etiquette { font-size: 13px; color: var(--ink3); }
.compteur .nombre { font-size: 22px; font-weight: 650; line-height: 1.1; letter-spacing: -0.02em; }
.compteur.alerte .nombre, .compteur.alerte .etiquette { color: var(--clay); }
.compteur.alerte .etiquette::before { content: ""; display: inline-block; width: 6px; height: 6px; border-radius: 50%;
                                      background: var(--clay); margin-right: 6px; vertical-align: 2px; }

/* ------------------------------------------------------ cartes et pôles -- */
.grille { display: grid; grid-template-columns: repeat(auto-fill, minmax(262px, 1fr)); gap: 12px; align-items: start; }
.carte { background: var(--paper); border: 1px solid var(--line); border-radius: 10px; padding: 12px 14px;
         display: flex; flex-direction: column; gap: 6px; box-shadow: var(--ombre); transition: border-color .15s, box-shadow .15s; }
.carte header { display: flex; align-items: center; gap: 8px; padding-bottom: 6px; border-bottom: 1px solid var(--line); margin-bottom: 2px; }
.carte header b { font-size: 14px; font-weight: 650; flex-grow: 1; }
.jeton { font-size: 12px; font-weight: 650; border-radius: 20px; padding: 1px 8px; min-width: 24px; text-align: center; border: 1px solid; }
.jeton.libre { background: var(--lagoon-soft); color: var(--lagoon); }
.jeton.disponible { background: var(--surface); color: var(--ink2); }
.jeton.charge { background: var(--surface); color: var(--ink); }
.jeton.sature { background: var(--clay-soft); color: var(--clay); }
.carte .charge-mot { font-size: 12px; color: var(--ink3); }
.carte .libre-mot { font-size: 12px; color: var(--lagoon); font-weight: 600; }
.rang { display: flex; align-items: center; gap: 8px; padding: 3px 0; min-height: 26px; }
.rang.vise { background: var(--lagoon-soft); border-radius: 6px; padding: 3px 5px; }
/* `break-word`, pas `anywhere` : celui-ci laissait rétrécir un nom sous la largeur d'un
   mot, et « Tamatoa D. » se cassait en « Tamato / a D. » (revue d'affichage du 26/09). */
.nom { flex-grow: 1; min-width: 0; overflow-wrap: break-word; font-size: 14px; font-weight: 550; line-height: 1.3; text-align: left; }
.nom:hover { color: var(--lagoon); }
.rang .bloc-nom { flex-grow: 1; min-width: 0; display: flex; flex-direction: column; }
.rang .bloc-nom .sous { font-size: 12px; color: var(--ink3); line-height: 1.3; }
.rang .dur { color: var(--ink2); font-size: 12px; white-space: nowrap; min-width: 42px; text-align: right; }
/* `.cl` porte deux choses : une étiquette courte (« 3ème », « 13:25 ») et une ligne
   de détail en texte libre (« avec vous depuis 13:14 · Anglais, Physique-chimie »,
   « session fermée : second facteur exigé par le rôle… »). `nowrap` par défaut
   convenait à la première et faisait déborder la page entière pour la seconde : à
   390 px, la vue tuteur réclamait 476 px. La règle est donc renversée — le texte
   passe à la ligne — et `.serre` demande explicitement la ligne unique là où une
   colonne doit tenir. Deux exceptions avaient déjà été ajoutées avant ce
   renversement ; une troisième aurait suivi. */
.cl { color: var(--ink3); font-size: 12px; }
/* Un paragraphe explicatif ne s'étire pas sur toute la largeur d'un grand écran
   (critique du 25/09). Dans la page seulement : les pages étroites (connexion,
   activation) centrent les leurs, qu'un plafond décentrerait. */
.principal p.cl:not(.pied-legal) { max-inline-size: 75ch; }
.cl.serre { white-space: nowrap; }

.attente { background: var(--paper); border: 1px solid var(--clay-line); border-radius: 10px; padding: 12px 14px;
           display: flex; flex-direction: column; gap: 8px; box-shadow: var(--ombre); }
.attente.recente { border-color: var(--line); }
.attente.longue { background: var(--clay-soft); border-color: var(--clay); border-width: 2px; }
.attente .nom { font-size: 15px; font-weight: 700; letter-spacing: -0.01em; }
.attente .detail { font-size: 12px; color: var(--ink2); }
.attente.longue .detail { color: var(--clay); font-weight: 600; }
.attente:not(.longue) .a-placer { display: none; }
.attente .boutons { display: flex; gap: 6px; }
.attente .boutons .primaire { flex-grow: 1; }

.poles { display: grid; grid-template-columns: repeat(auto-fit, minmax(330px, 1fr)); gap: 24px; align-items: start; }
.pole { min-width: 0; }
.pole-tete { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 12px; padding: 10px 14px;
             border-radius: 10px; background: var(--surface); border: 1px solid var(--line); }
.pole-tete h2 { font-size: 17px; font-weight: 650; }
.pole-tete .classes { font-size: 12px; color: var(--ink3); }
.pole.actif .pole-tete { background: var(--primaire-fond); border-color: var(--primaire-fond); color: var(--primaire-texte); }
.pole.actif .pole-tete .classes { color: var(--pole-actif-sous); }
.pole.lecture .carte, .pole.lecture .attente { box-shadow: none; }
.pole .grille { grid-template-columns: repeat(auto-fill, minmax(228px, 1fr)); }
.pole .compteurs { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
.pole .compteur { padding: 9px 12px; min-width: 0; }
.pole .compteur:nth-child(3n) { border-right: none; }
.pole .compteur .nombre { font-size: 17px; }
.badge { font-size: 12px; font-weight: 600; padding: 2px 9px; border-radius: 20px; background: var(--primaire-fond); color: var(--primaire-texte); white-space: nowrap; }
.pole.actif .badge { background: var(--primaire-texte); color: var(--primaire-fond); }
.badge.lecture { background: var(--paper); color: var(--ink2); border: 1px solid var(--line); }
/* Plan « main-direction » (10/10) : le bouton de la direction, à la place du badge.
   Une cible d'au moins 44 px ; pressé, il prend les couleurs du bloc actif. */
.bouton-main { min-height: 44px; padding: 6px 12px; border-radius: 20px; font-size: 13px;
               font-weight: 600; text-align: left; white-space: normal; cursor: pointer;
               background: var(--paper); color: var(--ink2); border: 1px solid var(--line); }
.bouton-main .geste { text-decoration: underline; text-underline-offset: 2px; }
.bouton-main:hover { border-color: var(--ink3); }
.bouton-main.prise { background: var(--primaire-texte); color: var(--primaire-fond);
                     border-color: var(--primaire-texte); }
.bouton-main:focus-visible { outline: 2px solid var(--lagoon); outline-offset: 2px; }
/* « Absent aujourd'hui » (vérification du 28/09, E16) : sans cette règle, le badge
   prenait l'aplat noir du bouton principal. */
.badge.alerte { background: var(--clay-soft); color: var(--clay); border: 1px solid var(--clay-line); }
.bloc-pole { margin-bottom: 18px; }

.recherche { display: flex; align-items: center; gap: 7px; flex-grow: 1; min-width: 220px; max-width: 420px;
             border: 1px solid var(--bord-champ); border-radius: 8px; padding: 0 11px; background: var(--paper); }
.recherche input { flex-grow: 1; border: none; background: none; padding: 10px 0; font-size: 13px; outline: none; }
/* Le champ n'avait aucun indicateur de focus (critique du 23/09, WCAG 2.4.7) :
   c'est le cadre entier qui le porte, comme `.champ:focus`. */
.recherche:focus-within { border-color: var(--lagoon); box-shadow: 0 0 0 3px var(--anneau); }
.commandes { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; margin-bottom: 16px; }
.commandes .note { font-size: 12px; color: var(--ink2); }
/* Un formulaire de commandes dans une rangée de commandes (onglet Élèves, M1) : sa marge est celle de la rangée. */
.commandes > .commandes { margin-bottom: 0; }

/* Le cartouche ne sert qu'à l'impression. */
.cartouche { display: none; }

/* Pastille de prestation. La TEINTE (`--h`) et les trois couleurs sont posées en
   ligne par `pastille_prestation` : une pastille vit dans des conteneurs qui posent
   leur propre `color`, et une règle de feuille de style y perdrait. Ce qui a changé,
   c'est que ces couleurs composent maintenant la teinte imposée par la direction
   avec les jetons `--presta-*` du thème, au lieu de nombres écrits en dur — les
   pastilles étaient la seule couleur du site à ne pas basculer, et « Stage BAC »
   faisait une tache quasi blanche sur une ligne sombre. */
.presta { display: inline-block; border-radius: 20px; padding: 1px 8px; font-size: 12px; font-weight: 650;
          white-space: nowrap; line-height: 1.5; vertical-align: 1px; flex-shrink: 0; }

.encart { border: 1px solid var(--line); border-radius: 10px; padding: 12px 14px; background: var(--paper);
          font-size: 13px; color: var(--ink2); line-height: 1.55; }
.encart b { color: var(--ink); font-weight: 600; }
.encart.info { border-color: var(--lagoon-line); background: var(--lagoon-soft); }
.encart.alerte { border-color: var(--clay-line); background: var(--clay-soft); }
.encart + .encart, .bloc-encart { margin-bottom: 12px; }

/* ---------------------------------------------------------------- champs -- */
.champ { width: 100%; border: 1px solid var(--bord-champ); border-radius: var(--rayon); padding: 8px 11px; font-size: 14px;
         background: var(--paper); transition: border-color .15s, box-shadow .15s; }
.champ::placeholder { color: var(--ink3); }
.champ:hover { border-color: var(--ink3); }
.champ:focus { outline: none; border-color: var(--lagoon); box-shadow: 0 0 0 3px var(--anneau); }
.champ:disabled { background: var(--surface); color: var(--ink3); }
/* `soskool.js` porte la hauteur d'une zone de texte à celle de son contenu ; elle
   reste redimensionnable à la main, et le plafond évite qu'elle chasse le pied de
   la fenêtre. */
textarea.champ { resize: vertical; max-height: 50vh; }
.champ.court { width: 110px; text-align: center; }
.champ.auto { width: auto; }
.ligne-champ { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.ligne-champ > label:first-child { font-size: 13px; width: 84px; }
.ligne-champ .note { font-size: 12px; color: var(--ink3); }
/* Fenêtre d'un compte de direction : où se prend la main (plan « main-direction »). */
.note-main-direction { margin-top: 12px; white-space: normal; max-width: 40em; }
.categorie { display: flex; flex-wrap: wrap; gap: 6px; }
.categorie label { border: 1px solid var(--line); border-radius: 20px; padding: 6px 12px; font-size: 13px;
                   font-weight: 550; cursor: pointer; background: var(--paper); }
.categorie input { position: absolute; opacity: 0; pointer-events: none; }
.categorie label:has(input:checked) { background: var(--lagoon); border-color: var(--lagoon); color: var(--sur-accent); }

/* -------------------------------------------------------------- fenêtres -- */
.voile { position: fixed; inset: 0; background: var(--voile); display: flex; align-items: center;
         justify-content: center; padding: 20px; z-index: 40; animation: voile .16s ease-out; }
.boite { background: var(--paper); border-radius: 12px; box-shadow: var(--ombre-haute); width: min(640px, 100%);
         max-height: 86vh; display: flex; flex-direction: column; overflow: hidden;
         animation: boite .2s cubic-bezier(.16, 1, .3, 1); }
.voile.stable, .voile.stable .boite { animation: none; }
@keyframes voile { from { opacity: 0; } }
@keyframes boite { from { opacity: 0; transform: translateY(6px) scale(.985); } }
.boite > header { padding: 16px 20px 14px; border-bottom: 1px solid var(--line); display: flex; align-items: flex-start; gap: 12px; }
.boite > header h2 { font-size: 17px; font-weight: 650; }
.boite > header p { margin: 4px 0 0; font-size: 13px; color: var(--ink2); }
.boite .corps { padding: 16px 20px; overflow-y: auto; display: flex; flex-direction: column; gap: 8px; }
.boite > footer { padding: 12px 20px; border-top: 1px solid var(--line); display: flex; gap: 8px; justify-content: flex-end;
                  flex-wrap: wrap; background: var(--surface); }
.boite > footer .note { font-size: 12px; color: var(--ink3); margin-right: auto; align-self: center; }
/* Un pied dont le seul bouton était la sortie se retire avec elle : la croix
   « Fermer » de l'en-tête suffit, une bande vide ne dirait rien (critique du 25/09). */
.boite > footer:not(:has(> :not([hidden]))),
.pied-formulaire:not(:has(> :not([hidden]))) { display: none; }
.choix { display: flex; align-items: center; gap: 11px; padding: 9px 12px; border: 1px solid var(--line); border-radius: var(--rayon);
         background: var(--paper); text-align: left; width: 100%; transition: border-color .12s, background .12s; }
.choix:hover:not(:disabled) { border-color: var(--lagoon-line); background: var(--lagoon-soft); }
.choix .rond { width: 30px; height: 30px; border-radius: 50%; background: var(--surface); border: 1px solid var(--line);
               display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 650; flex-shrink: 0; color: var(--ink2); }
.choix .bloc { flex-grow: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.choix .bloc b { font-size: 14px; font-weight: 600; }
.choix .bloc span { font-size: 12px; color: var(--ink3); }
.choix .etat { font-size: 12px; font-weight: 700; color: var(--ink2); }
.choix .etat.libre { color: var(--lagoon); }
.liste-choix { display: flex; flex-direction: column; gap: 6px; }
.etape { font-size: 12px; color: var(--ink2); font-weight: 600; }
/* Le tuteur retenu, en tête de la seconde étape (lot B, 21/09) : la même ligne que
   dans la liste qu'on vient de quitter, pour qu'on reconnaisse son choix sans le
   relire — mais posée en surface, sans bordure cliquable : ce n'est plus un bouton. */
.tuteur-retenu { display: flex; align-items: center; gap: 11px; padding: 9px 12px;
                 background: var(--surface); border-radius: var(--rayon); margin-bottom: 14px; }
.tuteur-retenu .rond { width: 30px; height: 30px; border-radius: 50%; background: var(--paper);
                       border: 1px solid var(--line); display: flex; align-items: center;
                       justify-content: center; font-size: 12px; font-weight: 650; flex-shrink: 0; }
.tuteur-retenu .bloc { flex-grow: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.tuteur-retenu .bloc b { font-size: 14px; font-weight: 600; }
.tuteur-retenu .bloc span { font-size: 12px; color: var(--ink3); }
/* Ce qui sépare les matières du tuteur du reste du catalogue. En toutes lettres et
   sans filet : le lot B range, il ne contraint pas — les autres matières ne sont pas
   derrière une porte, elles sont simplement plus loin. */
.separateur-matieres { margin: 12px 0 6px; }
.seance { display: flex; flex-direction: column; gap: 4px; padding: 11px 13px; border: 1px solid var(--line);
          border-radius: 8px; background: var(--surface); }
.seance.en-cours { border-color: var(--lagoon); background: var(--lagoon-soft); }
.seance .haut { display: flex; align-items: baseline; gap: 9px; }
.seance .haut b { font-size: 13px; }
.seance .haut span { font-size: 12px; color: var(--ink2); flex-grow: 1; }
.ligne-journal { display: flex; gap: 14px; padding: 10px 14px; border: 1px solid var(--line); border-radius: 8px;
                 background: var(--surface); }
.ligne-journal .quand { flex-shrink: 0; width: 88px; font-weight: 700; font-size: 13px; }
/* E8 (28/09) : « pour le 28/09 », puis, dessous, le jour et l'heure de l'écriture. */
.ligne-journal .quand small { display: block; font-weight: 400; font-size: 11px; color: var(--ink3); }
.ligne-journal .quoi { flex-grow: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.ligne-journal .quoi b { font-size: 13px; }
.ligne-journal .quoi span { font-size: 12px; color: var(--ink2); }
.ligne-journal .quoi small { font-size: 12px; color: var(--ink3); }
.pile-journal { display: flex; flex-direction: column; gap: 8px; }
/* La barre de période du Journal (plan journal-periode) : Jour / Semaine / Mois,
   puis ‹ la période en clair ›. Le libellé garde une largeur minimale pour que les
   flèches ne sautent pas d'un mois court à un mois long ; sur tablette, les cibles
   passent à 44 px par le bloc « au doigt » en fin de fichier. */
.barre-journal { margin-bottom: 10px; }
.barre-journal .groupe { display: inline-flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.barre-journal .periode-libelle { min-width: 16ch; text-align: center; font-size: 14px; }
.fleche-periode[aria-disabled="true"] { opacity: 0.45; cursor: default; }
.fleche-periode[aria-disabled="true"]:hover { background: var(--paper); color: var(--ink2); }
.liste-cloture { margin: 0; padding-left: 18px; font-size: 13px; }

.message { position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%); z-index: 60; background: var(--message-fond);
           color: var(--message-texte); border-radius: 10px; padding: 11px 16px; font-size: 14px; font-weight: 500;
           box-shadow: var(--ombre-haute); max-width: min(560px, calc(100vw - 32px)); animation: message .22s cubic-bezier(.16, 1, .3, 1);
           /* Il recouvrait les boutons « Rappel » des cartes pendant cinq secondes
              (critique du 23/09) : un toucher le traverse désormais. */
           pointer-events: none; }
@keyframes message { from { opacity: 0; transform: translate(-50%, 8px); } }
/* Le message garde ses boutons cliquables — lui seul laisse passer le toucher. */
.message { display: flex; align-items: center; gap: 12px; }
.message .texte-message { flex: 1 1 auto; }
.message button { pointer-events: auto; font: inherit; cursor: pointer; color: inherit;
                  background: transparent; border: 1px solid color-mix(in srgb, currentColor 45%, transparent); border-radius: 8px; }
.message .message-geste { padding: 6px 12px; min-height: 36px; font-weight: 600; flex: none; }
.message .message-fermer { border: 0; padding: 4px 8px; font-size: 17px; line-height: 1; min-height: 36px; opacity: .8; flex: none; }
.message button:hover, .message button:focus-visible { background: color-mix(in srgb, currentColor 14%, transparent); }
.message.refus { background: var(--message-refus); }
.message.bon { background: var(--message-bon); }
@media (prefers-reduced-motion: reduce) { .voile, .boite, .message { animation: none; } }
.hors-ligne { position: fixed; top: 0; left: 50%; transform: translateX(-50%); z-index: 70; background: var(--message-refus);
              color: var(--message-texte); font-size: 13px; font-weight: 550; padding: 6px 14px; border-radius: 0 0 8px 8px; }
.hors-ligne:empty { display: none; }

/* -------------------------------------------------------- photo agrandie --
   Retours de Kealohi du 20/09 : une seule façon d'agrandir une photo partout — la
   pastille d'un élève, la photo en tête de fiche, la photo d'un devoir. Un calque
   de plus, AU-DESSUS des fenêtres (50 contre 40) et sous le bandeau de message
   (60), qui doit rester lisible. La fenêtre de dessous n'est pas touchée : on la
   retrouve telle quelle à la fermeture.

   `[hidden]` doit être écrit : `display: flex` l'emporterait sinon sur le
   `display: none` que le navigateur donne d'office à un élément caché. */
.voile-photo { position: fixed; inset: 0; z-index: 50; background: var(--voile-photo);
               display: flex; align-items: center; justify-content: center; padding: 16px;
               animation: voile .16s ease-out; }
.voile-photo[hidden] { display: none; }
.photo-plein { margin: 0; display: flex; flex-direction: column; align-items: center; gap: 12px;
               max-width: 100%; }
/* Une photo de 3 000 px doit tenir dans un téléphone sans déborder ni faire défiler.
   `dvh` et non `vh` : sur mobile, `vh` compte la barre d'adresse rétractée, et le bas
   de l'image passait dessous. */
.photo-plein img { display: block; max-width: 94vw; max-height: 86dvh; object-fit: contain;
                   border-radius: 10px; background: var(--paper); }
/* Photo absente, effacée ou refusée (403 après une déconnexion, 404, fichier
   disparu) : une phrase qui dit quoi faire, pas un rectangle vide muet. */
/* Même forme qu'une alerte du site (`.encart.alerte`, `.rappel`) : filet d'argile
   et fond pâle, sans bandeau latéral. Le trait épais sur un seul côté était une
   forme que ce projet n'emploie nulle part ailleurs (détecteur, 2026-09-21). */
.note-photo { max-width: 34em; background: var(--clay-soft); color: var(--ink); text-align: left;
              border: 1px solid var(--clay-line);
              border-radius: 10px; padding: 12px 14px; font-size: 14px; }
.note-photo[hidden] { display: none; }
/* La même zone sert à dire l'attente, qui n'est pas un incident : filet neutre
   plutôt que le trait argile du refus. */
.note-photo.attente-photo { border-color: var(--line); border-left-color: var(--ink3);
                            color: var(--ink2); }
/* La seule sortie visible : 44 px au doigt, promesse de DESIGN.md. */
.fermer-photo { position: absolute; top: 12px; right: 12px; min-width: 44px; min-height: 44px;
                display: inline-flex; align-items: center; justify-content: center; gap: 6px;
                padding: 0 14px; border: 1px solid var(--line); border-radius: 8px;
                background: var(--paper); color: var(--ink); font-size: 14px; font-weight: 550;
                cursor: pointer; box-shadow: var(--ombre-haute); }
.fermer-photo:hover { background: var(--survol); }
@media (prefers-reduced-motion: reduce) { .voile-photo { animation: none; } }

/* ------------------------------------------------------- feuille du jour -- */
.feuille-defile { overflow-x: auto; background: var(--paper); border: 1px solid var(--line); border-radius: 10px; box-shadow: var(--ombre); }
.feuille-grille { min-width: 760px; padding: 6px 0; }
/* U4 : sur une tablette tenue en portrait (768 px), la grille dépassait de 57 px son
   cadre et la colonne « Total » ne se voyait qu'en faisant glisser. Plus étroite,
   la piste garde une cinquantaine de pixels par heure. */
@media (max-width: 800px) {
  .feuille-grille { min-width: 680px; }
  .barre-nom { width: 160px; }
}
.barre-ligne { display: flex; align-items: center; padding: 6px 14px; border-top: 1px solid var(--filet-doux); gap: 10px; }
.barre-ligne.entete { border-top: none; border-bottom: 1px solid var(--line); align-items: flex-end;
                      font-size: 12px; letter-spacing: .04em; text-transform: uppercase; color: var(--ink3); font-weight: 600; }
.feuille-lignes .barre-ligne:nth-child(even of :not(.masque)) { background: var(--ligne-paire); }
.feuille-lignes .barre-ligne:hover { background: var(--lagoon-soft); }
.barre-nom { width: 196px; flex-shrink: 0; display: flex; flex-direction: column; gap: 1px; }
.barre-nom .nom { font-size: 14px; font-weight: 600; }
.barre-nom span { font-size: 12px; color: var(--ink3); }
.barre-piste { flex-grow: 1; height: 28px; position: relative; min-width: 0;
               background-image: repeating-linear-gradient(to right, var(--line) 0 1px, transparent 1px calc(100% / 6)); }
.graduations { flex-grow: 1; display: flex; position: relative; text-transform: none; letter-spacing: 0; font-weight: 400; }
.graduations div { flex: 1 1 0; border-left: 1px solid var(--line); padding-left: 4px; }
/* La dernière heure marque la fin de la piste : largeur nulle, texte qui déborde. */
.graduations div:last-of-type { flex: 0 0 0; width: 0; white-space: nowrap; }
.barre-seance { position: absolute; top: 3px; height: 22px; background: var(--lagoon-soft); border: 1px solid var(--lagoon-line);
                border-radius: 5px; display: flex; align-items: center; padding: 0 6px; overflow: hidden; }
.barre-seance.en-cours { background: var(--lagoon); border-color: var(--lagoon); }
.barre-seance b { font-size: 12px; font-weight: 600; color: var(--lagoon); white-space: nowrap; }
.barre-seance.en-cours b { color: var(--sur-accent); }
.barre-heure { width: 52px; flex-shrink: 0; text-align: center; font-size: 13px; font-weight: 550; }
.barre-heure.vide { color: var(--ink3); font-weight: 400; font-size: 12px; }
.barre-total { width: 66px; flex-shrink: 0; text-align: right; font-size: 13px; font-weight: 600; }
.repere { position: absolute; top: -6px; bottom: -6px; width: 2px; background: var(--rouge); opacity: .7; pointer-events: none; }
.repere-etiquette { position: absolute; top: -2px; transform: translateX(-50%); background: var(--clay); color: var(--sur-accent);
                    font-size: 12px; font-weight: 700; border-radius: 5px; padding: 1px 5px; white-space: nowrap; }
/* Le parcours papier est le tableau du bloc d'impression, plus bas ; à l'écran,
   c'est la frise qui dit la même chose à l'œil. Il reste lu (vérification du 28/09,
   A9) : la frise ne dit l'heure de début d'une séance que par sa position, et elle
   est `aria-hidden`. Masqué à l'œil seulement, comme `.lecteur-ecran`. */
.papier-parcours, .papier-titre { position: absolute; width: 1px; height: 1px; overflow: hidden;
                                  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }
/* Les attendus pas encore arrivés (E4) : une rangée de noms qui ouvrent la fiche. */
.liste-non-venus { display: flex; flex-wrap: wrap; gap: 2px 14px; list-style: none; margin: 4px 0 0; padding: 0; }
.ventilation { font-size: 12px; color: var(--ink2); margin-bottom: 12px; line-height: 1.7; }

/* ------------------------------------------------------------ vue tuteur -- */
.doc { background: var(--paper); border: 1px solid var(--line); border-radius: 10px; padding: 13px 14px; display: flex;
       flex-direction: column; gap: 9px; box-shadow: var(--ombre); }
.doc .haut { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.doc .haut b { font-size: 17px; flex-grow: 1; letter-spacing: -0.01em; }
.doc .haut span { font-size: 12px; color: var(--ink2); }
.doc .haut .dur { font-weight: 600; color: var(--lagoon); }
/* Le bloc de boutons d'une carte (lot 3, point 4). Il n'avait aucune mise en
   page : ses boutons restaient des éléments EN LIGNE, séparés par la seule
   espace du texte. Mesuré avant correction à 390, 768, 1024 et 1440 px, dans
   les deux thèmes : 3,8 px entre deux boutons d'une même ligne et **0 px**
   entre deux lignes — « Compte rendu » touchait donc « Départ du Centre » dès
   que le bloc passait à la ligne, c'est-à-dire toujours à trois boutons.
   6 px : le plus petit pas du rythme d'espacement, comme `.demande .boutons`. */
.doc .boutons { display: flex; flex-wrap: wrap; gap: 6px; }

/* ------------------------------------------------------------- connexion -- */
.connexion { min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 16px; }
.connexion form { width: min(380px, 100%); background: var(--paper); border: 1px solid var(--line); border-radius: 12px;
                  box-shadow: var(--ombre); padding: 24px; display: flex; flex-direction: column; gap: 12px; }
.connexion img { max-width: 160px; margin: 0 auto 6px; display: block; mix-blend-mode: var(--logo-melange);
                  background: var(--logo-fond); border-radius: 8px; }
.connexion label { font-size: 13px; font-weight: 550; display: flex; flex-direction: column; gap: 4px; }
.erreur { color: var(--erreur); font-size: 13px; }

/* --------------------------------------------------------- points de rupture -- */
@media (max-width: 1100px), (pointer: coarse) {
  .poles { gap: 16px; }
  /* (La grille des cartes n'est plus forcée à une colonne : elle en prend autant
     que la largeur du pôle le permet — deux à 1024 px, lot 4.) */
  .mini { padding: 9px 11px; font-size: 13px; }
  .puce { padding: 9px 11px; }
  .primaire, .secondaire { padding: 10px 14px; }
  .barre-nom { width: 150px; }
}
@media (max-width: 900px) {
  /* `auto 1fr` : sans lignes déclarées, une page courte étirait la barre du haut
     jusqu'à 318 px (revue d'ergonomie du 25/09). */
  .app, .rail-reduit .app { grid-template-columns: 1fr; grid-template-rows: auto 1fr; }
  .rail-bas { position: relative; }
  /* `.rail-bas >` : la règle générale du menu est écrite plus bas dans la feuille ;
     sans ce surcroît de précision, elle l'emportait sur celle-ci. */
  .rail-bas > .bouton-compte { display: inline-flex; align-items: center; gap: 6px; min-height: 44px;
                   padding: 8px 12px; border: 1px solid var(--line); border-radius: var(--r-controle, 8px);
                   background: var(--paper); color: var(--ink2); font: inherit; font-size: 13px; cursor: pointer; }
  .bouton-compte[aria-expanded="true"] { border-color: var(--lagoon-line); color: var(--ink); }
  .rail-bas > .menu-compte { display: none; }
  .rail-bas.ouvert > .menu-compte {
    display: flex; flex-direction: column; gap: 4px; position: absolute; right: 0; top: calc(100% + 6px);
    z-index: 30; min-width: 240px; padding: 10px; background: var(--paper); border: 1px solid var(--line);
    border-radius: 10px; box-shadow: var(--ombre-haute); }
  .rail-bas.ouvert .menu-compte .qui { display: flex; padding: 4px 10px 8px; }
  .bascule-rail { display: none !important; }
  /* `overflow: visible` : le menu du compte déborde sous la barre ; l'ascenseur de
     la barre latérale n'a plus lieu d'être quand elle est une bande en haut. */
  .rail { position: relative; z-index: 25; height: auto; flex-direction: row; flex-wrap: wrap; align-items: center; gap: 10px;
          border-right: none; border-bottom: 1px solid var(--line); padding: 10px 12px; overflow: visible; }
  .marque img { max-width: 110px; }
  .onglets { flex-direction: row; overflow-x: auto; max-width: 100%; }
  .rail-bas { margin-top: 0; flex-direction: row; align-items: center; margin-left: auto; }
  .role { width: auto; }
}
@media (max-width: 720px) {
  .principal { padding: 14px 12px 60px; }
  .barre-haut { padding: 8px 12px; position: static; }
  .barre-nom { width: 116px; }
}
@media (max-width: 700px) { .poles { grid-template-columns: 1fr; } }
@media (max-width: 520px) {
  /* Vérification du 28/09, E11 : sur le téléphone du tuteur, l'horloge tombait seule
     sur sa ligne, sous le titre — l'en-tête prenait 40 % du premier écran. Le titre
     part d'une base nulle : il se replie sur lui-même, et l'horloge reste à côté. */
  .titre-page { flex: 1 1 0; }
  .horloge-reelle { font-size: 13px; padding: 3px 7px; }
  .vue-tuteur .grille { grid-template-columns: minmax(0, 1fr); }
  .qui { display: none; }
  /* Promesse de DESIGN.md, longtemps écrite et jamais tenue (relecture du lot 3).
     À cette largeur une carte occupe déjà toute la ligne : deux boutons côte à
     côte y font deux cibles étroites, sous les 44 px visés dès 1100 px. Ils
     s'empilent, pleine largeur, au padding annoncé. */
  .vue-tuteur .doc .boutons { flex-direction: column; align-items: stretch; }
  .vue-tuteur .doc .boutons > button { width: 100%; padding: 13px 14px; }
}

/* ------------------------------------------------------------- impression --
   La feuille du jour seule, en aplats clairs cernés : une photocopie d'aplats
   sombres est illisible. Tout ce qui sert à agir disparaît. */
@media print {
  :root, :root[data-theme], :root:not([data-theme="light"]) {
    --fond: #f4f5f7; --rail: #f9fafb; --paper: #ffffff; --surface: #f6f7f9; --survol: #eef0f3;
    --line: #e3e5ea; --line-forte: #cfd3da; --filet-doux: #eef0f3; --ligne-paire: #f8f9fb; --bord-champ: #868c97;
    --ink: #121417; --ink2: #464c57; --ink3: #626977;
    --lagoon: #4f55d6; --lagoon-soft: #eff0fd; --lagoon-line: #c9cbf5;
    --clay: #a84b1c; --clay-soft: #fdf3ec; --clay-line: #f1cdb4;
    --vert: #1d7a4e; --rouge: #c2352b;
    /* Les teintes des tuteurs, au planning des cours particuliers (28/09). */
    --t0: #4f55d6; --t1: #1d7a4e; --t2: #a84b1c; --t3: #8a3ea8; --t4: #0e7490;
    --t5: #b45309; --t6: #be185d; --t7: #4d7c0f;
    /* Ce qui s'écrit SUR un aplat : accent (lagon, argile), bouton principal, message. */
    --sur-accent: #ffffff;
  --puce-active-fond: #4f55d6; --puce-active-texte: #ffffff; --puce-active-bord: #4f55d6;
    --primaire-fond: #121417; --primaire-texte: #ffffff; --primaire-survol: #2b2f36; --primaire-appui: #000000;
    --pole-actif-sous: #cfd3da;
    /* Les cartes de « Toute l'équipe », écran des tuteurs du jour (28/09). */
    --carte-equipe-fond: #ffffff; --carte-equipe-bord: #d3d7de;
    --message-fond: #121417; --message-texte: #ffffff; --message-refus: #7a2d12; --message-bon: #17402c;
    /* Pastilles de prestation : la série claire, comme le reste. Le bloc
       ci-dessous les neutralise de toute façon en blanc cerné. */
    --presta-fond-l: 0.94; --presta-fond-c: 0.05;
    --presta-texte-l: 0.42; --presta-texte-c: 0.12;
    --presta-ligne-l: 0.84; --presta-ligne-c: 0.08;
    --erreur: #7a2d12;
    --barre-haut: rgb(244 245 247 / 0.92); --voile: rgb(18 20 23 / 0.38); --voile-photo: rgb(12 14 17 / 0.86); --anneau: rgb(79 85 214 / 0.18);
    --logo-fond: transparent; --logo-melange: multiply;
    --ombre: 0 1px 2px rgb(18 20 23 / 0.05), 0 2px 8px rgb(18 20 23 / 0.04);
    --ombre-survol: 0 2px 4px rgb(18 20 23 / 0.06), 0 6px 16px rgb(18 20 23 / 0.06);
    --ombre-haute: 0 12px 32px rgb(18 20 23 / 0.16), 0 2px 6px rgb(18 20 23 / 0.08);
    color-scheme: light;
  }

  /* ---- marges de page : une décision de portée SITE, assumée ----------------
     `@page` ne se limite à aucun sélecteur : ces marges s'appliquent à TOUTE
     impression du site, pas à la seule feuille du jour — l'écran « Séances »
     compris. Il n'y en avait aucune avant le 20/09, et la règle était rangée
     sous « la feuille de papier », ce qui laissait croire le contraire
     (relecture du 20/09, M5).

     Choix fait ici : les assumer partout, et les écrire à cet endroit, avec les
     autres règles de portée site. CSS n'offre pas de `@page` par sélecteur ; la
     seule façon de la restreindre serait une page nommée (`@page feuille` +
     `page: feuille`), que Firefox ne met pas en œuvre — la feuille du jour y
     retomberait silencieusement sur les marges par défaut, et deux postes
     imprimeraient deux mises en page différentes sans que personne le voie.
     Mieux vaut des marges uniformes et dites qu'une portée qui dépend du
     navigateur. 11/9/13 mm contre ~12,7 mm par défaut : tous les écrans
     imprimables du site sont des tableaux denses, ils y gagnent.

     À rouvrir si Kealohi veut des marges différentes par écran. */
  @page { margin: 11mm 9mm 13mm; }
  /* Une exception, et une seule (plan « planning-cp », 29/09) : la semaine des cours
     particuliers s'imprime en PAYSAGE, sur une page nommée que seul cet écran
     demande. Le sens et les marges des autres écrans ne changent pas. Chrome, Edge
     et Firefox 110+ honorent `page:` ; un navigateur plus ancien imprime ce planning
     en portrait, la semaine serrée dans la largeur, sans rien couper. */
  @page planning-cp { size: A4 landscape; margin: 8mm 8mm 9mm; }
  body[data-ecran="cours_particuliers"] .principal { page: planning-cp; }

  /* `#hors-ligne` : le bandeau rouge « Serveur injoignable » n'était pas masqué —
     imprimer pendant une coupure le posait en travers de la feuille (vu au
     rendu de la page d'impression, 20/09). */
  .rail, .barre-haut, #calque, #calque-photo, #zone-message, #hors-ligne,
  .encart:not(.a-imprimer), .compteurs,
  .commandes, .ventilation,
  .primaire, .secondaire, .mini, .puce, .champ, .repere, .repere-etiquette { display: none !important; }
  /* Catalogues (plan du 28/09) : chaque catégorie s'imprime dépliée, ses champs lus
     comme du texte, sans les lignes d'ajout vides ni le chevron. `::details-content`
     (Chrome et Edge 131+, Safari 18.4+) ; un navigateur plus ancien n'imprime que
     les catégories ouvertes à l'écran. */
  .catalogue::details-content { content-visibility: visible; display: block; }
  .catalogue > summary::before { display: none; }
  .catalogue { box-shadow: none; break-inside: auto; }
  .table-catalogue .champ { display: inline-block !important; border: 0; padding: 0; min-height: 0;
                            background: none; width: auto; }
  .table-catalogue form:not(:has(input[type="hidden"])) { display: none; }
  /* Seul le titre que le cartouche remplace disparaît. Masquer `.titre-vue` en
     général faisait aussi tomber les titres de section des autres écrans — « À
     renseigner par tuteur » sur « Séances » (relecture du 19/09, M6). */
  .titre-vue.remplace-par-cartouche { display: none !important; }
  /* Le cartouche remplace le titre d'écran : il dit le pôle et l'année, que la
     feuille imprimée passait sous silence — deux feuilles de superviseurs
     différents étaient indiscernables, et une feuille classée ne se datait pas. */
  .cartouche { display: block !important; font-size: 12pt; margin: 0 0 10pt; }
  .encart.a-imprimer { border: 0.5pt solid var(--ink3); font-size: 8.5pt;
                       padding: 5pt 7pt; margin-bottom: 8pt; break-inside: avoid; }
  .app { display: block; }
  body { background: var(--paper); }
  .principal { padding: 0; }
  .titre-vue h2 { font-size: 16pt; margin-bottom: 8pt; }
  .feuille-defile { overflow: visible; border: none; box-shadow: none; }
  /* Les pastilles de prestation étaient les seules couleurs à survivre à la
     photocopie, où elles deviennent des gris indiscernables. */
  .presta { background: #fff !important; color: var(--ink) !important;
            border: 0.5pt solid var(--ink2) !important; }

  /* ---- la feuille de papier (20/09) ----------------------------------------
     « Débarrasse-toi de la frise, affiche seulement les séances réalisées avec
     leurs horaires et peut-être une petite flèche qui indique l'ordre des
     séances (gauche à droite). Il faut que la feuille soit plus dense en
     information aussi. L'affichage doit être clair, simple et dense. » (Kealohi.)

     Ni frise ni graduations : un vrai tableau à cinq colonnes. `display: table`
     n'est pas un détail de goût — c'est lui qui aligne les colonnes d'une page à
     l'autre et qui permet à `table-header-group` de répéter l'en-tête en tête de
     chaque feuille. Le parcours papier est le quatrième enfant de la même
     `.barre-ligne` que la frise : les filtres et le tri de `feuille.js` le
     suivent sans rien savoir de lui.

     (Les marges de page ne sont PAS ici : `@page` vaut pour tout le site, elle
     est plus haut, avec les autres règles de cette portée.) */
  .barre-piste, .graduations { display: none !important; }
  .papier-parcours, .papier-titre { display: table-cell !important; position: static; width: auto;
                                    height: auto; overflow: visible; clip: auto; clip-path: none;
                                    white-space: normal; }
  .feuille-grille { min-width: 0; display: table; width: 100%; padding: 0;
                    table-layout: fixed; }
  .barre-ligne.entete { display: table-header-group; }
  .feuille-lignes { display: table-row-group; }
  /* `:not(.masque)`, et la règle explicite qui suit, ne sont pas décoratifs.
     « Une feuille filtrée s'imprime filtrée » est LE point décisif de la feuille
     de papier, et il ne tenait qu'au `!important` de `[hidden], .masque` (ligne
     103) : une règle générique, très loin d'ici, typiquement ce qu'on nettoie en
     passant. Sans lui, `.masque` (0,1,0) perdait contre `.feuille-lignes
     .barre-ligne` (0,2,0) et le superviseur du collège qui filtre son pôle
     imprimait les élèves du lycée — noms, horaires et tuteurs —, sans que rien
     ne change à l'écran (relecture du 20/09, M2). L'invariant tient désormais
     par la spécificité seule : 0,3,0 pour le masquage contre 0,2,0 pour
     l'affichage, et la règle est ici, sous les yeux de qui touche au papier. */
  .feuille-lignes .barre-ligne:not(.masque) { display: table-row; background: #fff !important;
                                              break-inside: avoid; }
  .feuille-lignes .barre-ligne.masque { display: none; }
  .barre-ligne > div { display: table-cell; vertical-align: top;
                       padding: 3pt 5pt 3pt 0; border-bottom: 0.4pt solid var(--line-forte); }
  .barre-ligne.entete > div { border-bottom: 0.9pt solid var(--ink2); padding-bottom: 2.5pt;
                              font-size: 7.5pt; letter-spacing: .03em; color: var(--ink2); }
  /* La taille se pose sur la CELLULE, pas seulement sur ses enfants : une ligne
     de texte de 7 pt dans une cellule restée à 14 px garde le montant de sa
     police héritée, soit 20 px de boîte pour 13 px de texte — 8 px perdus par
     ligne d'élève, invisibles à la lecture du code. */
  .barre-nom { width: 24%; font-size: 7pt; line-height: 1.3; }
  .barre-heure { width: 8%; text-align: left; font-size: 8.5pt; font-weight: 550; line-height: 1.3; }
  .barre-total { width: 8%; text-align: right; padding-right: 0; font-size: 8.5pt; line-height: 1.3; }
  /* Une page A4 fait 794 px de large : la règle des cibles tactiles (≤ 1100 px,
     `min-height: 44px` sur `.nom`) s'appliquait donc au PAPIER et gonflait chaque
     ligne d'élève de 54 px alors que son texte en demande 25. C'est à elle que la
     feuille imprimée devait sa moitié de page perdue. */
  .barre-nom .nom { font-size: 8.5pt; font-weight: 700; text-align: left; padding: 0;
                    display: block; min-height: 0; line-height: 1.2; }
  .barre-nom span { font-size: 7pt; color: var(--ink2); }
  /* Densité : la matière de chaque séance est déjà dans le parcours, à sa place. */
  .barre-nom .nom-matieres { display: none; }
  .papier-parcours { font-size: 8pt; line-height: 1.35; color: var(--ink); }
  .papier-seance { white-space: nowrap; }
  .papier-seance b { font-weight: 700; font-variant-numeric: tabular-nums; }
  .papier-fleche { color: var(--ink3); padding: 0 3pt; font-weight: 700; }
  .papier-matiere, .papier-vide { color: var(--ink2); }
  /* En noir et blanc, un aplat pâle n'est plus qu'un gris : le mot reste. */
  .papier-manque { font-weight: 700; text-transform: uppercase; font-size: 6.5pt;
                   letter-spacing: .04em; border: 0.5pt solid var(--ink2); padding: 0 2pt; }
  #vue::after { content: "Feuille du jour — Soskool"; display: block; margin-top: 10pt; font-size: 7.5pt; color: var(--ink3); }

  /* ---- feuille de secours (lot « mise en ligne ») : sans le bouton, une page
     par pôle, sans marge intérieure. */
  .feuille-secours { padding: 0; }
  .feuille-secours .ne-pas-imprimer { display: none; }
  .page-secours { break-after: page; }
  .page-secours + .page-secours { margin-top: 0; }
}

/* ------------------------------------------------ pastille photo et panneaux --
   La photo reste une vignette ronde à côté du nom ; sans photo, les initiales sur
   fond neutre. Aucune adresse publique : la source passe par « ecrans:photo ». */
.pastille { width: 28px; height: 28px; flex-shrink: 0; border-radius: 50%; object-fit: cover;
            background: var(--surface); border: 1px solid var(--line); display: inline-flex;
            align-items: center; justify-content: center; font-size: 11px; font-weight: 700;
            color: var(--ink3); letter-spacing: .02em; vertical-align: middle; }
/* Le bouton qui agrandit (pastille d'un élève, photo d'un devoir) : aucune boîte
   à lui, seulement une cible cliquable autour de l'image. */
.loupe-photo { display: inline-flex; flex-shrink: 0; padding: 0; border: 0; background: none;
               line-height: 0; border-radius: 50%; cursor: zoom-in; align-items: center; }
/* La pastille fait 28 px, sous la promesse des 44 px de DESIGN.md. L'horizontale
   est prise : `.ligne-eleve` a `gap: 10px`, une cible de 44 px de large mordrait
   sur le bouton du nom et volerait des clics destinés à la fiche. La verticale,
   elle, est libre là où la rangée fait DÉJÀ 44 px — la liste dense des élèves —,
   et la cible y passe à 28 × 44 sans déplacer un seul pixel de rendu (relecture
   du 20/09, m4).

   Attention : pas de `min-height` sur `.loupe-photo` en général. Un rang de
   carte de tuteur fait 26 px sur grand écran (`.rang`) et un attendu guère plus :
   la majoration y gonflerait chaque ligne du tableau de bord. Sous 1100 px, où
   `.rang` et `.ligne-attendu` sont déjà portés à 44 px, la règle vaut partout — c'est
   le bloc « cibles tactiles » en fin de fichier qui s'en charge. */
.ligne-eleve .loupe-photo { min-height: 44px; }

/* Panneaux repliables de la fiche : soskool.js garde leur état au rafraîchissement. */
.repli > .corps-repli { display: none; }
.repli.ouvert > .corps-repli { display: block; margin-top: 8px; }
/* `flex-wrap` et l'alignement à gauche (E17) : un titre de matière long se cassait
   en deux colonnes centrées sur le téléphone. */
.bascule { display: inline-flex; flex-wrap: wrap; justify-content: flex-start; text-align: left;
           align-items: center; gap: 6px; background: var(--paper);
           border: 1px solid var(--line); border-radius: 8px; padding: 6px 11px; cursor: pointer;
           font-size: 13px; font-weight: 550; color: var(--ink2); }
.bascule:hover { background: var(--surface); }
.repli.ouvert > .bascule { border-color: var(--lagoon-line); background: var(--lagoon-soft); color: var(--lagoon); }
.bascule.medical { border-color: var(--clay-line); background: var(--clay-soft); color: var(--clay); }
.bascule.important { border-color: var(--clay); background: var(--clay-soft); color: var(--clay); font-weight: 700; }
.panneaux { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 12px; }
.panneaux .repli { flex: 1 1 100%; }
/* Dans la rangée des boutons de la fiche, la pastille se centre sur eux : son
   `align-self: flex-start`, utile dans une carte en colonne, la montait de 5 px ici
   (revue d'affichage du 26/09). */
.panneaux .mention-sortie { align-self: center; }
.texte-libre { white-space: pre-wrap; font-size: 13px; line-height: 1.55; }

/* Dossier : une ligne par pièce, une par responsable. */
.lignes-dossier { display: flex; flex-direction: column; gap: 5px; font-size: 13px; }
.lignes-dossier > div { display: flex; gap: 10px; align-items: baseline; }
/* La colonne d'étiquettes est la PREMIÈRE de la ligne (nature de la pièce, lien du
   responsable, date d'un accès). Un `.cl` placé plus loin est du texte libre : lui
   imposer 150 px infrangibles poussait la page à 765 px sur un téléphone (écran
   « Comptes », liste des derniers accès). Il prend maintenant la place qui reste. */
.lignes-dossier .cl { color: var(--ink3); font-size: 12px; min-width: 0; }
.lignes-dossier > * > .cl:first-child { width: 150px; flex-shrink: 0; }
@media (max-width: 520px) {
  /* Sur un téléphone, 150 px d'étiquette ne laissent plus rien : la ligne s'empile. */
  .lignes-dossier > * > .cl:first-child { width: auto; }
  .lignes-dossier > div { flex-wrap: wrap; }
}
.etat-piece { font-weight: 650; }
.etat-piece.fourni { color: var(--vert); }
.etat-piece.manquant { color: var(--clay); }
.etat-piece.refuse { color: var(--rouge); }

/* Élèves attendus, demandes et signalements : ce qui appelle un geste. */
/* --------------------------------------------------- élèves attendus --
   Une LIGNE par élève, plus une carte (retour de Kealohi du 2026-09-21). En
   cartes, 53 attendus noyaient le tableau de bord, et leurs trois boutons —
   incompressibles — volaient au nom toute la largeur d'une colonne de 228 px :
   il s'écrivait lettre par lettre (commit b9f6fc4). Même remède que la liste
   des élèves : une ligne pleine largeur, où chaque part a sa place déclarée. */
.liste-attendus { background: var(--paper); border: 1px solid var(--line); border-radius: 10px;
                  box-shadow: var(--ombre); overflow: hidden; }
.bloc-attendus { margin-bottom: 20px; }
.attendus-vide { padding: 14px; font-size: 13px; color: var(--ink3); }
.ligne-attendu { display: flex; align-items: center; gap: 10px; padding: 7px 14px; min-height: 44px;
                 border-top: 1px solid var(--filet-doux); flex-wrap: wrap; font-size: 13px; }
.ligne-attendu:first-child { border-top: none; }
.ligne-attendu:hover { background: var(--lagoon-soft); }
/* Un retard attend un geste : règle de l'attente orange, rien d'autre ne l'emprunte. */
.ligne-attendu.retard { background: var(--clay-soft); box-shadow: inset 3px 0 0 var(--clay); }
.ligne-attendu.retard:hover { background: var(--clay-soft); }
/* `min-width` plutôt que `flex-basis` : le nom réclame de quoi s'écrire avant
   que les boutons ne prennent le reste, et passe à la ligne s'il est long. */
/* Seul le nom s'étire : les autres colonnes gardent une largeur fixe, sans quoi
   une ligne en retard — qui porte un texte de plus — décalerait ses voisines et
   la liste cesserait de se lire en colonnes. La colonne « retard » reste réservée
   même vide, pour la même raison. */
.ligne-attendu .nom { flex: 1 1 180px; min-width: 12ch; font-weight: 600; }
.ligne-attendu .cl { flex: 0 0 92px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ligne-attendu .quand { flex: 0 0 180px; font-variant-numeric: tabular-nums; color: var(--ink3); font-size: 12px; }
.ligne-attendu > .retard { flex: 0 0 104px; font-size: 12px; font-weight: 650; color: var(--clay); }
.ligne-attendu .badge { font-size: 12px; }
.ligne-attendu .boutons { display: flex; gap: 6px; flex-wrap: wrap; margin-left: auto; }
/* Dans un pôle du tableau de bord, la colonne est étroite : les largeurs fixes y
   deviendraient un carcan, et les trois boutons passent sous le nom. Même chose
   sur tablette, où les cibles tactiles de 44 px mangent toute la ligne : les
   colonnes cèdent la place avant que le nom ne se comprime. */
.pole .ligne-attendu .quand, .pole .ligne-attendu .cl,
.pole .ligne-attendu > .retard { flex: 0 1 auto; }
@media (max-width: 1100px) {
  .ligne-attendu .quand, .ligne-attendu .cl, .ligne-attendu > .retard { flex: 0 1 auto; }
  .ligne-attendu { gap: 8px; padding: 6px 12px; }
}
.carte .a-documenter { font-size: 12px; font-weight: 650; color: var(--clay); }
.depart-demande { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; padding: 7px 10px;
  border-radius: 8px; background: var(--clay-soft); color: var(--clay); font-size: 12px; font-weight: 600; }
.depart-demande span { flex-grow: 1; }
.demande, .signalement { display: flex; flex-direction: column; gap: 7px; padding: 11px 13px;
                         border: 1px solid var(--clay-line); border-radius: 10px; background: var(--clay-soft); }
.demande.traite, .signalement.traite { border-color: var(--line); background: var(--paper); }
.demande .haut, .signalement .haut { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.demande .haut b, .signalement .haut b,
.demande .haut .nom, .signalement .haut .nom { font-size: 14px; flex-grow: 1; font-weight: 700; }
.demande .boutons, .signalement .boutons { display: flex; gap: 6px; flex-wrap: wrap; }
/* Autorisation de sortie (demande 2, 21/09). Deux états seulement s'écrivent :
   « autorisee » n'affiche rien — norme incolore. L'argile dit ce qui pèse et
   appelle un geste ; l'encre tertiaire dit la question encore ouverte. */
/* Un refus de la famille se porte en **pastille argile pleine**, pas en texte argile.
   Vu au navigateur le 21/09 : la carte d'un élève en attente est déjà tout entière en
   argile, si bien qu'un simple texte argile se lisait comme la suite de la ligne de
   détail — « ne repart pas sans un adulte » avait exactement le poids de « accueil
   hors de son pôle ». L'inversion est celle des badges du système (pilule pleine,
   texte sur accent), pas une couleur de plus. */
.mention-sortie { display: inline-flex; align-items: center; gap: 6px; flex-wrap: wrap;
                  font-size: 12px; font-weight: 650; border-radius: 20px;
                  padding: 3px 10px; background: var(--clay); color: var(--sur-accent);
                  /* La pastille épouse son texte : dans une carte en colonne, un
                     élément souple s'étirerait sur toute la largeur et cesserait
                     d'être une pastille. */
                  align-self: flex-start; width: fit-content; }
/* Sans réponse : rien de plein. Ce n'est pas une décision, c'est une question — elle
   se pose sans peser, et le bouton qui la tranche suffit à la faire voir. */
.mention-sortie.sans-reponse { color: var(--ink3); font-weight: 400;
                               background: none; padding: 0; }
/* Le titre seul passe en argile : les noms de la liste sont dans des <b> eux
   aussi, et tout colorer faisait de l'encart un bloc orange — l'attente orange
   marque ce qui appelle un geste, pas chaque mot. */
.encart-sortie > b { color: var(--clay); }

.marque-signal { display: inline-flex; width: 16px; height: 16px; border-radius: 50%; background: var(--clay);
                 color: var(--sur-accent); font-size: 11px; font-weight: 700; align-items: center; justify-content: center; }
.rappel { border: 1px solid var(--clay-line); background: var(--clay-soft); border-radius: 10px;
          padding: 11px 13px; display: flex; gap: 10px; align-items: baseline; flex-wrap: wrap; }
.rappel b { font-size: 13px; color: var(--clay); }
/* Colonne « aujourd'hui » de l'onglet Élèves (décision du 2026-09-20). Aucune
   pastille de couleur (retour de la direction du 17/09) : c'est le mot qui porte
   l'information, et seul l'état actif est appuyé. « Pas attendu » est le cas
   courant sur une longue liste : il reste en gris pâle pour ne pas crier. */
.etat-du-jour { font-size: 12px; white-space: nowrap; color: var(--ink3);
                margin-left: auto; text-align: right; }
.etat-du-jour.en_seance, .etat-du-jour.en_attente { color: var(--ink); font-weight: 600; }
.etat-du-jour.attendu { color: var(--ink2); }
/* Écran « Tuteurs du jour », enrichi (décision du 2026-09-20) : chaque tuteur porte
   une seconde ligne — matières possibles, comptes rendus manquants, absences à
   venir. Elle est en retrait et plus petite : on lit d'abord le nom. */
.ligne-tuteur { display: flex; flex-direction: column; gap: 2px; padding: 6px 0; }
.ligne-tuteur + .ligne-tuteur { border-top: 1px solid var(--filet-doux); }
.ligne-tuteur .details-tuteur { padding-left: 2px; font-size: 12px; }
.ligne-tuteur.absent .nom-lien { color: var(--ink3); }
/* Même effet dans les colonnes des pôles : « HinanoDEMO » au doigt (vu le 28/09). */
.ligne-tuteur .nom-lien { gap: 0 .3em; }
/* « Toute l'équipe » en cartes (demande de Kealohi, 28/09) : un cadre par tuteur,
   pour les distinguer d'un coup d'œil. Le nom en titre, l'état du jour dessous,
   puis les matières et les rappels. Couleurs : jetons `--carte-equipe-*` seulement.
   `min(260px, 100%)` : jamais plus large que la colonne, donc aucun défilement
   horizontal, même à 768 px menu ouvert. */
.cartes-equipe { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px;
                 grid-template-columns: repeat(auto-fill, minmax(min(260px, 100%), 1fr)); }
.carte-tuteur { display: flex; flex-direction: column; gap: 6px; min-width: 0;
                padding: 12px 14px; border: 1px solid var(--carte-equipe-bord);
                border-radius: var(--rayon); background: var(--carte-equipe-fond);
                box-shadow: var(--ombre); font-size: 13px; }
.carte-tuteur .carte-tete { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.carte-tuteur .nom-carte { font-size: 15px; font-weight: 600; line-height: 1.25; min-width: 0;
                           overflow-wrap: anywhere; }
/* `gap` : au doigt, `.nom-lien` passe en inline-flex, qui avale l'espace entre le
   prénom et le nom (vu au navigateur le 28/09 : « HinanoDEMO »). */
.carte-tuteur .nom-carte .nom-lien { color: var(--ink); text-decoration: none; gap: 0 .3em;
                                     flex-wrap: wrap; }
.carte-tuteur .nom-carte .nom-lien:hover { color: var(--lagoon); text-decoration: underline; }
.carte-tuteur .nom-carte .cl { font-weight: 400; color: var(--ink2); }
.carte-tuteur .etat-carte { font-size: 12px; color: var(--ink3); }
.carte-tuteur .etat-carte.present { color: var(--ink2); font-weight: 600; }
.carte-tuteur .matieres-carte { margin: 0; color: var(--ink2); overflow-wrap: anywhere; }
.carte-tuteur .rappels-carte { margin: 0; font-size: 12px; color: var(--ink3); }
.carte-tuteur .gestes-carte { display: flex; gap: 6px; margin-top: auto; padding-top: 2px; }
.carte-tuteur.absent { border-style: dashed; }
.carte-tuteur.absent .nom-carte .nom-lien { color: var(--ink3); }
/* Écran « Séances » (décision du 2026-09-20) : un tableau dense sur une période
   qui peut couvrir un mois. Colonnes fixes, pas de pastille de couleur — le
   statut est un mot, et seul « à renseigner » est appuyé. */
/* DESIGN.md annonce « largeur min. 880 px, défilement horizontal dans son cadre en
   dessous » : ni l'un ni l'autre n'était posé, et la bascule en cartes n'arrivait
   qu'à 900 px. Entre 901 et 1150 px — la tablette en paysage, poste de travail
   annoncé — les colonnes souples étaient comprimées sans plancher : à 1024 px,
   `46 | 110 | 96 | 48 | 66 | 62 | 104 | 96`, le nom de l'élève réclamant 168 px et
   la colonne tuteur 48 px. La bascule remonte à 1100 px et le cadre défile. */
.ligne-seance { display: grid; align-items: baseline; gap: 10px; padding: 8px 14px;
                border-top: 1px solid var(--filet-doux); font-size: 13px; min-width: 880px;
                grid-template-columns: 46px 110px minmax(0, 1.6fr) minmax(0, 0.8fr)
                                       minmax(0, 1.1fr) 62px 104px 96px; }
.liste-eleves.table-seances { overflow-x: auto; }
.ligne-seance:first-child { border-top: none; }
.ligne-seance.entete { font-size: 12px; color: var(--ink3); font-weight: 600;
                       background: var(--surface); }
.ligne-seance > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
/* U2 : la ligne « aucune séance » occupe toute la largeur de la grille, au lieu de
   tenir dans la colonne Date, un mot par ligne. */
.ligne-seance.ligne-vide > span { grid-column: 1 / -1; white-space: normal; color: var(--ink3); }
.ligne-seance .nom { display: block; text-align: left; }
.ligne-seance.a-faire { background: var(--lagoon-soft); }
.statut-seance { font-size: 12px; white-space: nowrap; color: var(--ink2); }
.statut-seance.afaire { color: var(--ink); font-weight: 600; }
.statut-seance.encours { color: var(--ink3); }
.barre-periode { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
@media (max-width: 1100px) {
  /* Le tableau ne tient plus : chaque séance devient un bloc, en-tête masquée. */
  .ligne-seance { grid-template-columns: 1fr 1fr; min-width: 0; }
  .ligne-seance.entete { display: none; }
}
.rappel .texte-libre { flex-grow: 1; }
/* La suite donnée à un signalement, lue par le tuteur qui l'a émis (décision du
   2026-09-20) : détachée du texte du signalement, pour qu'on ne confonde pas ce
   qu'il a écrit et ce qu'on lui répond. */
/* Filet de **citation**, pas un onglet d'accent sur une carte : il détache ce qu'on
   répond au tuteur de ce qu'il a lui-même écrit. 2 px et non 3 — le détecteur ne
   voit pas la balise depuis la feuille de style, et sa version navigateur exempte
   justement les bornes de texte sur un <span>. Plutôt que d'aveugler la règle sur
   toute la feuille par une exception, on prend la largeur la plus discrète : elle
   cite aussi bien. */
.suite-signalement { border-left: 2px solid var(--lagoon-line); padding-left: 9px; color: var(--ink2); }

/* --------------------------------------------------------- onglet Élèves --
   Une ligne par fiche, rangées par classe : nom en graisse, le reste en encre
   tertiaire (règle du nom en graisse). Aucune couleur : les prestations
   s'écrivent en toutes lettres. */
.groupe-classe { margin-bottom: 20px; }
.liste-eleves { background: var(--paper); border: 1px solid var(--line); border-radius: 10px; box-shadow: var(--ombre); overflow: hidden; }
.ligne-eleve { display: flex; align-items: center; gap: 10px; padding: 7px 14px; min-height: 44px; border-top: 1px solid var(--filet-doux); flex-wrap: wrap; }
.ligne-eleve:first-child { border-top: none; }
.ligne-eleve:hover { background: var(--lagoon-soft); }
.ligne-eleve .nom { flex: 0 1 220px; }
/* Colonne « classe » de la liste : elle se coupe par des points de suspension, ce
   qui exige une ligne unique. Le libellé y est court par nature. */
.ligne-eleve .cl { flex: 0 1 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ligne-eleve .prestations { flex: 1 1 160px; font-size: 12px; color: var(--ink2); }
.ligne-eleve.inactif .nom { color: var(--ink3); }

/* --------------------------------------------------- bornes d'une venue --
   Fenêtre « Corriger la journée » (lot A, retour du 2026-09-21). Elle montre la
   journée avant de demander une heure : c'est tout son propos, et c'est ce que la
   fenêtre d'horaire — deux champs nus — ne faisait pas.

   **Aucune couleur d'accent sur ce qui est.** La suite des tranches, la liste des
   frontières et l'aperçu sont de l'information : encre, papier, filet. Le lagon ne
   sert qu'à désigner la frontière VISÉE — la seule chose qui attend une décision —
   et l'argile qu'aux écarts de l'aperçu, qui sont ce que la correction change.
   Règle de la norme incolore, règle de l'attente orange. */
.boite.large { width: min(760px, 100%); }

/* La journée telle qu'elle est : arrivée, tranches, départ, en une bande. */
.suite-bornes { display: flex; flex-wrap: wrap; align-items: stretch; gap: 6px;
                background: var(--paper); border: 1px solid var(--line); border-radius: 10px;
                padding: 10px; }
.suite-bornes .borne-fixe, .suite-bornes .tranche {
  display: flex; flex-direction: column; gap: 2px; padding: 6px 10px; border-radius: 8px;
  min-height: 44px; justify-content: center; }
.suite-bornes .borne-fixe { background: var(--ligne-paire); flex: 0 0 auto; }
.suite-bornes .tranche { background: var(--surface); border: 1px solid var(--filet-doux);
                         flex: 1 1 140px; min-width: 0; }
.suite-bornes .tranche.visee { border-color: var(--lagoon-line); background: var(--lagoon-soft); }
.suite-bornes b { font-size: 14px; font-weight: 600; }
.suite-bornes .cl { font-size: 12px; }

/* Les frontières : ce qu'on clique. Une par changement de tuteur, jamais pour la
   première séance — sa borne est l'arrivée, et un bouton qui renvoie ailleurs vaut
   moins qu'une absence de bouton. */
.liste-frontieres { display: flex; flex-direction: column; gap: 6px; }
.frontiere { display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
             background: var(--paper); border: 1px solid var(--line); border-radius: 8px;
             padding: 8px 12px; min-height: 44px; font: inherit; color: inherit; cursor: pointer; }
.frontiere:hover { background: var(--lagoon-soft); }
.frontiere[aria-pressed="true"] { border-color: var(--lagoon); background: var(--lagoon-soft); }
.frontiere .bloc { display: flex; flex-direction: column; gap: 2px; flex: 1 1 auto; min-width: 0; }
.frontiere .heure { font-size: 15px; font-weight: 650; font-variant-numeric: tabular-nums; }

/* Les pas. Au centre on corrige de cinq à quinze minutes, debout, sur tablette :
   taper « 15:45 » pour gagner cinq minutes est la mauvaise réponse. Le champ reste
   pour les écarts francs. */
/* Le nom de la frontière tient sa ligne : serré entre les pas et le champ, il se
   cassait en « Hinano → / Poehere » dans un coin (vu au navigateur le 21/09). */
.nom-frontiere { flex: 1 1 100%; font-weight: 600; }
.pas-heure { display: flex; gap: 4px; flex: none; }
.pas-heure .mini { min-width: 44px; justify-content: center; font-variant-numeric: tabular-nums; }

/* Corriger les séances (retour de la direction, 25/09) : une ligne par séance —
   début, tuteur, gestes. Une séance retirée reste visible, grisée, avec le choix de
   qui reprend son temps : c'est la décision du geste, elle doit se voir.
   `ligne-correction`, pas `ligne-seance` : ce nom est celui du tableau de « Séances »,
   dont la ligne héritait la grille et le `> span { overflow: hidden }` — « Retirer la
   séance » coupé, 140 px hors de la fenêtre (revue d'affichage du 26/09). */
.lignes-seances { display: flex; flex-direction: column; gap: 8px; }
.ligne-correction { display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
                padding: 6px 8px; border: 1px solid var(--filet-doux); border-radius: 8px;
                background: var(--paper); }
.ligne-correction select.champ { flex: 1 1 160px; min-width: 0; }
.ligne-correction .gestes-ligne { display: flex; gap: 4px; flex: none; }
.ligne-correction.retiree { background: var(--ligne-paire); }
/* A24 : à 55 % d'opacité, l'heure retirée tombait à 4,02:1 ; la liste, hors de la
   tabulation, restait modifiable à la souris. */
.ligne-correction.retiree .champ { opacity: .7; }
.ligne-correction.retiree select.champ { pointer-events: none; }
.ligne-correction .temps-retire { flex: 1 1 100%; display: flex; flex-wrap: wrap; gap: 4px 14px;
                              border: 0; margin: 0; padding: 0; }
.ligne-correction .temps-retire legend { padding: 0; margin-right: 6px; float: left; }
.ligne-correction .temps-retire label { display: inline-flex; align-items: center; gap: 6px;
                                    min-height: 44px; }

.bloc-frontiere, .bloc-rouvrir { display: flex; flex-direction: column; gap: 8px;
                                 border-top: 1px solid var(--filet-doux); padding-top: 10px; }

/* L'aperçu : la conséquence en toutes lettres, avant de valider. Les lignes qui ne
   changent pas restent grises — seul l'écart porte de la couleur, parce que seul
   l'écart est la décision. */
.apercu-bornes { background: var(--surface); border: 1px solid var(--line); border-radius: 8px;
                 padding: 8px 12px; display: flex; flex-direction: column; gap: 2px; }
.ligne-apercu { display: flex; align-items: baseline; gap: 10px; font-size: 13px;
                color: var(--ink2); min-height: 26px; }
.ligne-apercu b { flex: 0 1 120px; font-size: 13px; color: var(--ink); }
.ligne-apercu span { font-variant-numeric: tabular-nums; }
.ligne-apercu.change { color: var(--ink); }
.ligne-apercu .ecart { margin-left: auto; color: var(--clay); font-weight: 600; }

.autre-tuteur > summary { display: flex; align-items: center; gap: 8px; cursor: pointer;
                          font-size: 13px; color: var(--ink2); padding: 8px 0; min-height: 44px; }
.autre-tuteur > summary:hover { color: var(--ink); }
.autre-tuteur .liste-choix { margin-top: 4px; }

@media (max-width: 720px) {
  /* Debout au comptoir : les tranches passent en colonne plutôt que de se réduire
     à une largeur où le prénom du tuteur se coupe. */
  .suite-bornes .tranche { flex: 1 1 100%; }
  .pas-heure { flex: 1 1 100%; }
  .pas-heure .mini { flex: 1 1 auto; }
}

/* ------------------------------------------------------------ camarades --
   Écran « Camarades » et ligne « Travaille avec … » de la fiche (retour du
   2026-09-21). Même surface dense que la liste des élèves — papier, filet, rangée
   de 44 px, survol lagon pâle : c'est la même matière, il n'y a pas de raison
   qu'elle se présente autrement.

   **Aucune couleur d'accent.** Un groupe de camarades ne demande aucun geste et
   n'est jamais « actif » : ni lagon, ni argile (règle de la norme incolore,
   règle de l'attente orange). Seul le survol de rangée, commun à toutes les
   listes, emprunte le lagon pâle. */
.liste-camarades { background: var(--paper); border: 1px solid var(--line); border-radius: 10px;
                   box-shadow: var(--ombre); overflow: hidden; }
.ligne-camarades { display: flex; align-items: center; gap: 10px; padding: 7px 14px;
                   min-height: 44px; border-top: 1px solid var(--filet-doux); flex-wrap: wrap; }
.ligne-camarades:first-child { border-top: none; }
.ligne-camarades:hover { background: var(--lagoon-soft); }
.ligne-camarades .nom-groupe { flex: 0 1 200px; font-size: 14px; font-weight: 550; line-height: 1.3; }
/* Du texte qui coule, pas une grille : les prénoms se lisent en une phrase, et
   les virgules restent collées au nom qui précède. Surtout, `display: flex` ici
   réveillait le `flex-grow: 1` du `.nom` global et étalait deux prénoms sur toute
   la largeur de la rangée (vu au navigateur le 21/09). */
.ligne-camarades .membres { flex: 1 1 260px; font-size: 13px; color: var(--ink2); }
.ligne-camarades form { margin-left: auto; }

/* Un nom qui n'est pas cliquable ne doit pas ressembler à un nom cliquable : pas
   de survol lagon, pas de curseur de main. C'est ce qui distingue, à l'œil, le
   camarade dont le tuteur peut ouvrir la fiche de celui dont il ne lit que le nom
   (correction de Kealohi du 2026-09-21). */
.nom-plat { font-size: 13px; color: var(--ink2); }
.nom-lien { background: none; border: 0; padding: 0; font: inherit; color: inherit;
            cursor: pointer; text-align: left; }
.nom-lien:hover { color: var(--lagoon); text-decoration: underline; }
.nom-lien:focus-visible { outline: 2px solid var(--lagoon); outline-offset: 2px; border-radius: 6px; }
.travaille-avec { white-space: normal; }

/* Fenêtre de gestion : les groupes de l'élève, puis les camarades à cocher. */
.liste-groupes { display: flex; flex-direction: column; gap: 6px; margin-bottom: 4px; }
.ligne-groupe { display: flex; align-items: center; gap: 10px; border: 1px solid var(--line);
                border-radius: 8px; padding: 8px 11px; background: var(--paper); }
.ligne-groupe .bloc { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1 1 auto; }
.ligne-groupe .bloc .cl { white-space: normal; }
.ligne-groupe .mini { margin-left: auto; flex: none; }
.choix-camarades { margin-top: 2px; }

/* Rappel de la fenêtre d'affectation : un camarade est déjà chez un tuteur. C'est
   une phrase, pas un encart — un encart se lirait comme un avertissement, et rien
   ici n'attend de décision. */
.rappel-camarades { white-space: normal; margin: 0 0 10px; }

/* Sous 1100 px, les cibles tactiles passent à 44 px comme partout ailleurs : la
   rangée les porte déjà, le bouton du nom prend la hauteur. */
@media (max-width: 1100px), (pointer: coarse) {
  .ligne-camarades .nom-lien { display: inline-block; min-height: 44px; line-height: 44px; }
}

/* ------------------------------------------------------- types de travail --
   Cases à cocher du compte rendu : mêmes pilules que les catégories, sans couleur
   tant qu'elles ne sont pas cochées. */
.cases-types { border: none; padding: 0; margin: 0; display: flex; flex-wrap: wrap; gap: 6px; }
.cases-types legend { padding: 0; margin-bottom: 4px; }
.cases-types label { display: inline-flex; align-items: center; gap: 6px; border: 1px solid var(--line);
                     border-radius: 20px; padding: 5px 11px; font-size: 13px; cursor: pointer; background: var(--paper); }
.cases-types label:has(input:checked) { border-color: var(--lagoon-line); background: var(--lagoon-soft); color: var(--lagoon); font-weight: 600; }
.types-travail { font-weight: 600; color: var(--ink2); }
.table-catalogue { display: flex; flex-direction: column; gap: 6px; max-width: 720px; }
.table-catalogue form { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; padding: 8px 12px;
                        border: 1px solid var(--line); border-radius: 8px; background: var(--paper); }
.table-catalogue form.retire { background: var(--surface); }
.table-catalogue .champ[name="rang"] { width: 70px; }

/* ------------------------------------------------ catalogues dépliants --
   Plan du 28/09 : chaque catégorie de « Catalogues » est un `<details>` natif,
   replié à l'ouverture, sans script. Le titre porte le nom et le compte ; toute la
   rangée est la cible, 44 px au moins partout — l'écran se tient aussi au doigt.
   Après une action, seul l'intérieur est remplacé : l'état ouvert reste. */
.catalogues { display: flex; flex-direction: column; gap: 10px; max-width: 760px; }
.catalogue { background: var(--paper); border: 1px solid var(--line); border-radius: 10px; box-shadow: var(--ombre); }
.catalogue > summary { display: flex; align-items: center; gap: 12px; min-height: 44px; padding: 8px 14px;
                       cursor: pointer; list-style: none; border-radius: 10px; }
.catalogue > summary::-webkit-details-marker { display: none; }
.catalogue > summary::before {
  content: ""; flex: none; width: 7px; height: 7px; margin: 0 2px 2px 2px;
  border-right: 2px solid var(--ink3); border-bottom: 2px solid var(--ink3);
  transform: rotate(-45deg); transition: transform .15s;
}
.catalogue[open] > summary::before { transform: rotate(45deg); margin-bottom: 4px; }
.catalogue[open] > summary { border-bottom: 1px solid var(--line); border-radius: 10px 10px 0 0; }
.catalogue > summary:hover .titre-catalogue { color: var(--lagoon); }
.titre-catalogue { flex: 1 1 auto; min-width: 0; font-size: 15px; font-weight: 650; overflow-wrap: anywhere; }
.compte-catalogue { flex: none; min-width: 28px; padding: 1px 9px; border-radius: 20px; text-align: center;
                    font-size: 13px; font-weight: 600; color: var(--ink2); background: var(--surface); }
.corps-catalogue { padding: 12px 14px 14px; }
.corps-catalogue > p.cl { margin: 0 0 10px; }
.corps-catalogue .table-catalogue { max-width: none; }
/* La grille tarifaire (plan « tarifs », 01/10) : une année par bloc, ses dates de
   début en tête, puis le soutien et les cours particuliers comme sur l'affiche. Le
   libellé prend la place qui reste ; le prix, aligné à droite, se lit en colonne. */
.grille-tarifs { display: flex; flex-direction: column; gap: 8px; padding: 10px 0 14px;
                 border-top: 1px solid var(--line); }
.grille-tarifs:first-of-type { border-top: 0; padding-top: 0; }
.titre-grille { margin: 0; font-size: 14px; font-weight: 650; }
.titre-grille .note { margin-left: 6px; font-weight: 400; }
.grille-tarifs .etape { margin: 6px 0 0; }
.dates-grille { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; }
.preparer-grille { margin-top: 12px; padding: 10px 12px; border: 1px dashed var(--line-forte);
                   border-radius: 8px; }
.table-catalogue form.ligne-tarif { display: grid; grid-template-columns: minmax(0, 1fr) 215px auto auto;
                                    gap: 8px; align-items: center; }
.ligne-tarif .libelle-tarif { min-width: 0; }
.ligne-tarif .detail-tarif { display: block; }
.prix-tarif { display: inline-flex; align-items: center; gap: 6px; }
@media (max-width: 600px) {
  .table-catalogue form.ligne-tarif { grid-template-columns: 1fr auto; }
  .ligne-tarif .libelle-tarif { grid-column: 1 / -1; }
}
.champ.prix { width: 112px; text-align: right; font-variant-numeric: tabular-nums; }
.ligne-ajout-tarif { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 4px; }
.ligne-ajout-tarif .champ.court { width: 70px; }
/* La période d'une prestation et son bouton restent ensemble, poussés à droite. */
.groupe-vacances { display: inline-flex; align-items: center; gap: 8px; margin-left: auto; flex-wrap: wrap; }
@media (prefers-reduced-motion: reduce) { .catalogue > summary::before { transition: none; } }
/* fin des catalogues dépliants */
/* Pied d'un formulaire dans une fenêtre : le bouton principal à droite. */
.pied-formulaire { display: flex; gap: 10px; align-items: center; justify-content: flex-end; flex-wrap: wrap;
                   padding-top: 10px; border-top: 1px solid var(--line); margin-top: 6px; }
.jours-prevus { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 6px 14px; }
.jours-prevus label { width: 96px; font-size: 13px; }
.choix .primaire { flex-shrink: 0; }

/* ---------------------------------------------------------------- devoirs --
   Dans la fiche, avant les séances : ce que l'élève a à faire. La photo est une
   vignette cadrée ; au clic, elle s'ouvre en grand (même adresse, même contrôle). */
.devoirs { display: flex; flex-direction: column; gap: 6px; margin-bottom: 12px; }
.devoirs .etape { display: flex; align-items: center; gap: 10px; }
.devoir { display: flex; flex-direction: column; gap: 5px; padding: 10px 12px; border: 1px solid var(--line);
          border-radius: 8px; background: var(--paper); }
.devoir .haut { display: flex; align-items: baseline; gap: 9px; flex-wrap: wrap; }
.devoir .haut b { font-size: 13px; }
.devoir .haut span { font-size: 12px; color: var(--ink3); flex-grow: 1; }
/* « Modifier » et « Retirer » vont ensemble : sur téléphone, la ligne passe à la
   ligne et ils doivent rester côte à côte plutôt que de tomber l'un sous l'autre. */
.devoir .haut .gestes { display: flex; gap: 6px; flex-shrink: 0; }
.photo-devoir { align-self: flex-start; border-radius: 6px; }
.photo-devoir img { display: block; max-width: 100%; max-height: 160px; border-radius: 6px; border: 1px solid var(--line); }

/* ----------------------------------------------------------- fiche tuteur --
   Une carte par section : la fiche s'allonge quand une catégorie s'ajoute. */
.sections-tuteur { display: grid; grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); gap: 16px; align-items: start; }
.section-tuteur { background: var(--paper); border: 1px solid var(--line); border-radius: 10px; box-shadow: var(--ombre);
                  padding: 14px 16px; display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.section-tuteur[data-section="activite"] { grid-column: 1 / -1; }
.section-tuteur h2 { font-size: 15px; font-weight: 650; }
.section-tuteur .compteurs { margin-bottom: 4px; box-shadow: none; }
.nom-lien { color: inherit; text-decoration: none; }
.carte header .nom-lien { flex-grow: 1; }
.nom-lien:hover { color: var(--lagoon); text-decoration: underline; }

/* ------------------------------------------------ correction orthographique -- */
.resultat-orthographe:empty { display: none; }
.orthographe { display: flex; flex-direction: column; gap: 6px; padding: 8px 10px; border: 1px solid var(--line);
               border-radius: 8px; background: var(--surface); }
.mot-inconnu { text-decoration: underline wavy var(--clay); text-underline-offset: 3px; }

/* « Mes dernières actions » (annulation, 18/09) : l'heure alignée, la raison en retrait. */
.actions-recentes > div { padding: 6px 0; border-bottom: 1px solid var(--line); }
.actions-recentes .heure { width: 44px; flex-shrink: 0; font-variant-numeric: tabular-nums; }
.actions-recentes .raison, .actions-recentes .cl-date { color: var(--ink3); font-size: 12px; max-width: 46ch; }
.actions-recentes .annulee .libelle { text-decoration: line-through; color: var(--ink3); }

/* ------------------------------------------------ plan « révision » -- */
/* Arrivée : une ligne par élève, sa prestation proposée ; l'autre en second bouton. */
.ligne-arrivee { display: flex; align-items: center; gap: 6px; }
.ligne-arrivee .choix { flex: 1 1 auto; min-width: 0; }
.ligne-arrivee.masque { display: none; }
/* Sous la ligne d'un élève dont une venue a été annulée aujourd'hui : de quoi la
   rétablir, ou la raison de ne pas pouvoir (plan du 22/09). Décalé sous le nom, en
   encre seconde et sans fond : pointer une arrivée neuve reste le geste principal,
   et celui-ci ne doit pas lui disputer le regard. */
.venue-annulee { display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
                 padding: 4px 0 8px 41px; font-size: 12px; color: var(--ink2); }
.venue-annulee.masque { display: none; }
.autre-prestation, .prestations-vacances { font-size: 13px; }
.autre-prestation > summary, .prestations-vacances > summary { cursor: pointer; padding: 6px 0; color: var(--ink2); }
.autre-prestation .categorie { margin: 4px 0 6px; }
.prestations-vacances { margin-left: 2px; }
/* Icônes des boutons : au trait, dans la couleur du texte, jamais seules. */
.icone-bouton { width: 16px; height: 16px; flex: none; vertical-align: -3px; }
button .icone-bouton, a .icone-bouton { margin-right: 5px; }
.icone-alerte { color: var(--rouge); }
.poignee .icone-bouton { margin: 0; }
/* Affectation : matières d'abord, tuteurs ensuite, l'autre pôle replié. */
.choix-matieres { border: none; padding: 0; margin: 0 0 6px; display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.choix-matieres legend { padding: 0; margin-bottom: 8px; }
.ajout-matiere { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.ajout-matiere .champ { flex: 1 1 200px; width: auto; }
.choix.propose { border-color: var(--lagoon); background: var(--lagoon-soft); }
.envoi-autre-pole { margin-top: 10px; border-top: 1px solid var(--line); padding-top: 8px; }
.envoi-autre-pole > summary { cursor: pointer; font-size: 14px; font-weight: 550; color: var(--ink2); padding: 6px 0; }
.envoi-autre-pole[open] > summary { color: var(--ink); }
.envoi-autre-pole .liste-choix { margin-top: 8px; }
/* Les pilules cachent leur case : le focus au clavier se voit sur la pilule. */
.categorie label:has(input:focus-visible) { outline: 2px solid var(--lagoon); outline-offset: 2px; }
/* Feuille du jour : la barre dit la durée, l'étiquette dit le reste, SOUS elle.
   Le texte était dans la barre, donc borné par la durée : 37 px de barre pour 94 px
   de texte sur une séance de moins d'une heure, et « Hinano » devenait « Hinan ».
   L'étiquette prend maintenant la largeur de son texte, alignée sur le début de la
   barre (`--gauche`) et bornée par `--suivante` — les deux posés par le gabarit.
   (Depuis l'essai du 20/09, voir le bloc « deux niveaux » plus bas, `--suivante`
   est la barre d'après DE MÊME NIVEAU et non plus la barre d'après tout court.)
   La borner par la seule fin de la piste empilait les étiquettes de deux séances
   consécutives au même `top`, complètes mais illisibles (relecture du 19/09, G1) :
   la place réellement libre est presque toujours plus large que la barre, et c'est
   tout le gain recherché. Les 4 px retirés laissent respirer les deux textes.
   Une séance minuscule garde une barre visible : `min-width` de 4 px.
   L'étiquette a désormais le sien, 3 ch : trois affectations en quelques secondes
   (mauvais tuteur, correction immédiate) mettent les rangs 0 et 2 au même endroit,
   `--suivante` vaut alors `--gauche` et le `max-width` tombe à ZÉRO — l'étiquette
   du premier tuteur disparaissait, infobulle comprise (relecture du 20/09, m2).
   Un `min-width` l'emporte toujours sur un `max-width` plus petit : il reste de
   quoi lire le début du prénom et attraper l'infobulle. */
.barre-piste { height: 60px; }
.barre-seance { min-width: 4px; }
.barre-etiquette { position: absolute; top: 26px; height: 16px; left: var(--gauche);
                   max-width: calc(var(--suivante) - var(--gauche) - 4px); min-width: 3ch;
                   display: flex; align-items: center; gap: 5px;
                   font-size: 12px; line-height: 16px; color: var(--ink2);
                   white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.barre-etiquette b { font-weight: 600; color: var(--ink); }
.barre-etiquette .barre-fin { font-variant-numeric: tabular-nums; }
/* Le compte rendu manquant, en toutes lettres (A9) : un « · » après le prénom ne se
   remarquait pas, et ne se lisait pas. */
.barre-etiquette .barre-cr { color: var(--clay); font-weight: 650; }
.barre-matiere { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
/* ---- deux niveaux d'étiquette (essai du 2026-09-20, « option 3, on essaie ») ----
   Un seul niveau bornait chaque étiquette au début de la barre SUIVANTE : une
   séance courte tronquait son texte (4 cas sur 60 relevés à la main). En alternant
   les étiquettes de 16 px, une barre sur deux seulement fait obstacle : la borne
   `--suivante` devient la barre d'après de même niveau (posée par
   `presentation.poser_les_etiquettes`), donc presque toujours toute la place
   restante. Coût : la piste passe de 44 à 60 px, soit 16 px par ligne d'élève.
   POUR DÉFAIRE : `NIVEAUX_ETIQUETTE = 1` dans `ecrans/presentation.py`, rendre
   `height: 44px` à `.barre-piste` ci-dessus, et supprimer ce bloc. */
.barre-etiquette.niveau-bas { top: 42px; }
/* L'autre pôle, en lecture seule : plus discret, et repliable (point 7). Les textes
   gardent leurs couleurs — leur contraste est vérifié — ; c'est la surface qui
   s'efface : cartes à plat sur le fond, colonne plus étroite. */
/* Dès 901 px et non plus 1101 (lot 4) : à 1024 px en paysage, les deux pôles
   avaient des colonnes égales, et les cartes du sien commençaient à 1 733 px. */
@media (min-width: 901px) {
  /* `:not(.un-replie)` n'est pas un détail : `:has()` prend la spécificité de son
     argument, donc `.poles:has(.pole.actif)` (0,3,0) battait la règle du repli
     (0,2,0) quel que soit l'ordre des règles, et la largeur n'était jamais rendue.
     Les deux mises en page sont désormais exclusives. */
  /* 240 px au moins pour l'autre pôle : entre 901 et 960 px, menu déplié, il
     tombait sous la largeur d'une carte (228 px) — relecture du lot 4, m1. */
  .poles:has(.pole.actif):not(.un-replie) { grid-template-columns: minmax(0, 1.65fr) minmax(240px, 1fr); }
}
.pole.lecture .carte, .pole.lecture .attente, .pole.lecture .compteurs, .pole.lecture .demande,
.pole.lecture .signalement, .pole.lecture .liste-attendus { background: transparent; box-shadow: none; }
.pole.lecture .pole-tete { background: transparent; }
.pole.lecture .compteur .nombre { font-size: 15px; }
/* La file et les tuteurs côte à côte (revue d'ergonomie du 25/09) : seulement quand
   le pôle a de la place — l'autre replié, ou un grand écran. En dessous, l'ordre
   reste celui de la page : la file d'abord, les tuteurs ensuite. */
@media (min-width: 901px) {
  .poles.un-replie .travail-pole.deux-colonnes {
    display: grid; grid-template-columns: minmax(260px, 1fr) minmax(0, 2fr); gap: 16px; align-items: start; }
  .poles.un-replie .travail-pole.deux-colonnes .colonne-file .grille { grid-template-columns: 1fr; }
  /* Côte à côte, la colonne des tuteurs posait trois cartes de 240 px : trop peu pour
     l'avatar, le nom, la classe et la durée (revue d'affichage du 26/09). */
  .poles.un-replie .travail-pole.deux-colonnes .colonne-tuteurs .grille { grid-template-columns: repeat(auto-fill, minmax(min(280px, 100%), 1fr)); }
}
@media (min-width: 1500px) {
  .pole.actif .travail-pole.deux-colonnes {
    display: grid; grid-template-columns: minmax(260px, 1fr) minmax(0, 2fr); gap: 16px; align-items: start; }
  .pole.actif .travail-pole.deux-colonnes .colonne-file .grille { grid-template-columns: 1fr; }
  .pole.actif .travail-pole.deux-colonnes .colonne-tuteurs .grille { grid-template-columns: repeat(auto-fill, minmax(min(280px, 100%), 1fr)); }
}
/* Un menu d'actions secondaires (revue d'ergonomie du 25/09) : « Exporter ou
   imprimer » sur la feuille du jour. */
/* Une étiquette et sa liste passent à la ligne ensemble : « Trier par : » restait
   seul en bout de ligne (revue d'affichage du 26/09). */
.etiquette-liste { display: inline-flex; align-items: center; gap: 8px; }
.menu-actions { position: relative; }
.menu-actions > summary { list-style: none; cursor: pointer; display: inline-flex; align-items: center; gap: 6px; }
.menu-actions > summary::-webkit-details-marker { display: none; }
.menu-actions > summary::after { content: "▾"; font-size: 11px; color: var(--ink3); }
.menu-actions-corps { position: absolute; right: 0; top: calc(100% + 6px); z-index: 15; min-width: 220px;
  display: flex; flex-direction: column; gap: 4px; padding: 8px; background: var(--paper);
  border: 1px solid var(--line); border-radius: 10px; box-shadow: var(--ombre-haute); }
.menu-actions-corps > .secondaire { justify-content: flex-start; text-align: left; }
/* Dans les listes de la clôture, un nom ouvre la fiche : il se lit comme un lien. */
.liste-cloture .nom-lien { text-decoration: underline; text-decoration-style: dotted; text-underline-offset: 3px; }
.liste-cloture .mini { margin-left: 6px; }
.indice-present { color: var(--ink3); font-weight: 400; }
/* Les trois corrections sous une étiquette (revue d'ergonomie du 25/09). */
.groupe-corriger { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.groupe-corriger .etiquette-groupe { font-size: 13px; color: var(--ink3); margin-right: 2px; }
/* « Départ » à l'autre bout de la carte, loin d'« Affecter » (revue du 25/09). */
.boutons .bouton-depart { margin-left: auto; }
/* Comptes (plan « ergonomie-5 ») : le pôle ne sert pas quand le rôle choisi est
   « Direction » — replié ici, désactivé par `soskool.js` (`data-replie-si`). */
form:has(select[name="role"] option[value="direction"]:checked) .zone-pole { display: none; }
/* Le « Départ » d'un rang de carte (plan « ergonomie-5 ») : au bout du rang, après la
   durée ; il ne rétrécit pas, c'est le nom qui passe à la ligne. */
.rang .depart-rang { flex-shrink: 0; white-space: nowrap; }
/* Vérification finale du 09/10, G2 : à 768 px en portrait, la carte d'un tuteur
   fait ~320 px. Poignée, photo, classe, durée et « Départ » (44 px au doigt) n'y
   laissaient que 38 px au nom : « Mathématiques · Remise à niveau » se brisait mot
   par mot et « Mathématiques », plus large que sa boîte, recouvrait « 4ème ». Dans
   une carte étroite, le rang passe donc sur deux lignes : le nom et ses matières
   et la classe en haut, puis durée et « Départ », serrés à droite dessous. La
   requête porte sur la CARTE, pas sur l'écran : la même carte est étroite à 768 px
   et large à 1280 px. */
.colonne-tuteurs .grille > .carte { container-type: inline-size; }
@container (max-width: 400px) {
  .rang { flex-wrap: wrap; row-gap: 2px; }
  .rang .bloc-nom { flex: 1 1 55%; }
  .rang > .dur { margin-left: auto; }
}
.replier-pole { display: inline-flex; align-items: center; }
.replier-pole .icone-bouton { transition: transform .15s; }
/* Replié SUR LE CÔTÉ (demande de Kealohi du 2026-09-20) : l'autre pôle devient une
   bande verticale étroite, et toute la largeur revient au sien. La bande entière est
   le bouton : c'est une cible de 40 px de large sur toute la hauteur de la colonne,
   confortable au doigt comme à la souris. Le texte tourne avec `writing-mode`, qui
   garde de vraies lettres — sélectionnables, lues par un lecteur d'écran, et
   traduisibles — là où une image ne le serait pas. */
.pole.replie { width: 40px; }
.pole.replie .corps-pole, .pole.replie .pole-tete .classes,
.pole.replie .pole-tete .badge, .pole.replie .pole-tete .bouton-main,
.pole.replie .pole-tete .espace { display: none; }
.pole.replie .pole-tete { flex-direction: column; flex-wrap: nowrap; justify-content: flex-start;
                          gap: 12px; margin-bottom: 0; padding: 12px 6px; width: 40px;
                          min-height: 220px; }
.pole.replie .pole-tete h2 { writing-mode: vertical-rl; font-size: 14px; white-space: nowrap;
                             color: var(--ink2); }
.pole.replie .replier-pole { writing-mode: vertical-rl; padding: 6px 2px; border: 0;
                             background: none; flex-grow: 1; align-items: flex-start; }
.pole.replie .replier-pole .icone-bouton { transform: rotate(90deg); }
/* La mise en page du repli n'est plus déduite d'une classe : `tableau.js` écrit la
   suite exacte des colonnes dans `--colonnes-poles` — 40px pour un pôle replié, une
   part égale pour chacun des autres — quels que soient leur nombre et leur ordre.
   Replier le PREMIER pôle écrasait sinon le second dans 40 px. La valeur de repli
   ne sert que si le script n'a pas tourné. */
.poles.un-replie { grid-template-columns: var(--colonnes-poles, minmax(0, 1fr) 40px); }
@media (max-width: 700px) {
  /* Sur un téléphone, les colonnes s'empilent : une bande verticale n'aurait aucun
     sens en pleine largeur. Le pôle replié redevient un simple bandeau. */
  .poles.un-replie { grid-template-columns: 1fr; }
  .pole.replie, .pole.replie .pole-tete { width: auto; min-height: 0; }
  .pole.replie .pole-tete { flex-direction: row; padding: 10px 14px; }
  .pole.replie .pole-tete h2, .pole.replie .replier-pole { writing-mode: horizontal-tb; }
  .pole.replie .replier-pole .icone-bouton { transform: rotate(-90deg); }
}
@media (prefers-reduced-motion: reduce) { .replier-pole .icone-bouton { transition: none; } }
/* Glisser-déposer (point 5) : la poignée démarre le geste au doigt, sans faire
   défiler la page ; le reste de la carte garde le défilement tactile. */
.poignee { touch-action: none; cursor: grab; color: var(--ink3); display: inline-flex; align-items: center; }
[data-glisser="venue"] { cursor: grab; }
[data-glisser="venue"] .poignee { padding: 6px 2px; margin: -6px 0; }
.glisse-en-cours, .glisse-en-cours * { cursor: grabbing !important; user-select: none; -webkit-user-select: none; }
.en-glisse { opacity: .45; }
.fantome-glisse { position: fixed; top: 0; left: 0; z-index: 60; pointer-events: none; margin: 0;
                  box-shadow: var(--ombre-haute); }
.survol-depot { outline: 2px solid var(--lagoon); outline-offset: 2px; background: var(--lagoon-soft) !important; }
.a-inscrire { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 14px; }
.puce-tuteur { border: 1px solid var(--line); border-radius: 20px; padding: 6px 12px; font-size: 13px;
               background: var(--paper); color: var(--ink); gap: 4px; }
/* Un tuteur annoncé absent reste proposé — c'est au superviseur de trancher, et
   `inscrire_tuteur` refusera — mais il se voit **avant** le clic (retour du 22/09).
   Rouge et non argile : l'argile dit « ceci attend un geste », or une absence
   n'attend rien, elle empêche. Le mot « absent » double la couleur : une liste
   qui ne tiendrait que par la teinte ne se lirait pas en daltonisme. */
.puce-tuteur.absent { border-color: var(--rouge); color: var(--rouge); }
.puce-tuteur.absent .cl, .mot-absent { color: var(--rouge); }
.mot-absent { font-size: 12px; font-weight: 600; }
/* Ce qu'une annulation d'arrivée emporte : une ligne par séance, le temps en
   graisse. Liste simple et sans couleur — l'encart d'alerte au-dessus porte déjà
   l'avertissement, et répéter l'argile ici en ferait un bloc orange. */
.temps-emporte { margin: 0 0 12px; padding-left: 18px; font-size: 13px; color: var(--ink2); }
.temps-emporte li { margin-bottom: 3px; }
/* La consigne d'un élève qui attend, quand elle porte une heure (22/09). Elle se
   lit au moment du départ, et c'est le seul endroit où elle serve — un quatrième
   état d'autorisation de sortie aurait coûté aux 145 familles pour un seul élève.
   Sans couleur d'accent : ce n'est pas une alerte, c'est un fait à connaître. */
.consigne-horaire { display: block; margin-top: 4px; font-size: 12px; color: var(--ink2);
                    white-space: normal; }
/* Les navigateurs ne stylent qu'un `color` sur une `option`, et seulement quand la
   liste est déroulée : le libellé porte donc « — absent aujourd'hui » en clair. */
option.absent { color: var(--rouge); }
.fantome-glisse { background: var(--paper); border: 1px solid var(--line-forte); border-radius: 10px; padding: 8px 10px; }
/* Fiches entièrement modifiables (point 11) : libellé à gauche, champ à droite. */
.grille-champs { display: grid; grid-template-columns: minmax(120px, 170px) minmax(0, 1fr); gap: 8px 12px; align-items: center; }
.grille-champs > label { font-size: 13px; color: var(--ink2); }
@media (max-width: 520px) { .grille-champs { grid-template-columns: 1fr; } }
/* (Les deux exceptions qui remettaient un paragraphe ou une légende en texte
   ordinaire ont disparu : le renversement de `.cl` les rend inutiles.) */

/* ------------------------------------------ garde du texte non enregistré --
   Critique d'ergonomie du 23/09 : fermer une fenêtre qui porte du texte modifié
   demande d'abord, par ce bandeau posé EN TÊTE de la fenêtre (`soskool.js`,
   `garder`). Même forme qu'une alerte du site : il attend un geste, donc argile. */
.garde-saisie { display: flex; flex-wrap: wrap; align-items: center;
                justify-content: space-between; gap: 8px 12px; margin-bottom: 12px; }
.garde-saisie .boutons { display: flex; flex-wrap: wrap; gap: 8px; }

/* Le renvoi vers une venue d'un autre jour jamais refermée : il remplace le bouton
   de pointage (ligne d'attendu, fiche), avec la même taille que lui. */
.lien-suspens { color: var(--clay); border-color: var(--clay-line); text-decoration: none; }
.lien-suspens:hover { background: var(--clay-soft); }
/* Hors de la fenêtre de pointage — ligne d'attendu, pied de la fiche —, le
   rétablissement suit le bouton de pointage sur la même rangée : le décalage sous
   le nom, propre à la liste de la fenêtre, n'a plus de sens. */
.ligne-attendu .venue-annulee, .boite footer .venue-annulee { padding: 0; }

/* --------------------------------------------- confirmer un geste qui perd --
   La fenêtre du site qui remplace la boîte du navigateur (`soskool.js`,
   `htmx:confirm`). Au-dessus des fenêtres et de la photo agrandie, sous les
   messages : elle interroge sur un geste parti d'une fenêtre, sans la remplacer. */
.voile-confirmation { position: fixed; inset: 0; z-index: 55; background: var(--voile);
                      display: flex; align-items: center; justify-content: center;
                      padding: 20px; animation: voile .12s ease-out; }
.boite.petite { width: min(440px, 100%); }
.boite.petite .corps p { margin: 0; white-space: normal; line-height: 1.5; }
.boite.petite footer { justify-content: flex-end; }

/* ---------------------------------------------- pointer un groupe d'un geste --
   Onglet « Attendus » (critique du 23/09) : une case par élève pointable, un bouton
   par bloc. La case est grande et précède « Arrivé » : c'est la même rangée de
   gestes, le choix groupé avant le choix unitaire. */
.lot-arrivees, .lot-absents { display: flex; justify-content: flex-end; align-items: center;
                gap: 10px; flex-wrap: wrap; margin: 0 0 8px; }
/* Absence non prévenue (plan du 05/10). « non prévenue » en graisse ordinaire : le
   mot « Absence » se lit d'abord, la mention le distingue de « Justifier
   l'absence ». La colonne « attendu à » passe de 210 à 180 px — son texte le plus
   long, « attendu à 17:00 (heure du jour) », mesure 165 px au navigateur — pour
   qu'une ligne en retard et ses quatre gestes tiennent sur un rang à 1 440 px.
   Une ligne déjà notée n'attend plus de geste : elle
   quitte l'argile (règle de l'attente orange) et reste à plat, comme un justifié. */
.absent-non-prevenu .mention { font-weight: 400; }
.ligne-attendu.absent .nom { font-weight: 550; color: var(--ink2); }
.case-lot { inline-size: 20px; block-size: 20px; margin: 0; accent-color: var(--lagoon);
            cursor: pointer; flex-shrink: 0; }
/* La case seule n'offrait au doigt que sa surface (26 px) : le label qui l'entoure
   porte la cible à 44 px sans grossir la case (critique du 25/09). */
.zone-case-lot { display: inline-flex; align-items: center; justify-content: center;
                 min-inline-size: 44px; min-block-size: 44px; margin: -12px 0 -12px -10px;
                 cursor: pointer; flex-shrink: 0; }

/* La fenêtre de pointage : la recherche et « Enchaîner » sur une rangée. */
.recherche-arrivee { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; }
.recherche-arrivee .champ { flex: 1 1 260px; }
.enchainer { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; }

/* ------------------------------------------------ la clôture recomposée --
   Critique du 23/09. « Clôturer » a quitté la rangée de « présence oubliée » et
   passe à droite, à part ; dans la fenêtre, la case « Journée sans attendus » se
   lit avec son libellé, qui l'entoure. */
.commandes-cloture { display: flex; justify-content: flex-end; margin: -4px 0 12px; }
.case-libelle { display: flex; align-items: flex-start; gap: 10px; margin: 0 0 12px;
                font-size: 13px; line-height: 1.45; color: var(--ink2); cursor: pointer; }
.case-libelle input { margin-top: 3px; flex-shrink: 0; }
/* Les noms qui ouvrent une fiche réutilisent `.nom-lien` (camarades de la fiche). */

/* ------------------------------------------- lot 3 : erreurs et raisons --
   L'erreur sous le champ fautif (critique du 23/09) : même argile que les
   encarts d'alerte, le champ cerné de la même couleur. Et le motif « grisé avec
   sa raison », qui vivait en style en ligne : un bouton qu'on ne peut pas encore
   presser dit pourquoi, à côté, en texte courant. */
.erreur-champ { margin: 6px 0 0; color: var(--erreur); font-size: 13px; font-weight: 600; }
.champ[aria-invalid="true"] { border-color: var(--clay); box-shadow: 0 0 0 3px var(--clay-soft); }
.raison-grise { color: var(--ink3); font-size: 12px; max-width: 46ch; align-self: center; }

/* --------------------------------------------- zoom 200 % et petits écrans --
   Lot 4 (critique du 23/09) : à 200 % (640 px utiles), le menu en tête prenait
   193 px sur trois rangées et trois onglets sortaient de l'écran, cachés dans un
   défilement horizontal. Le logo se réduit, le compte et ses boutons montent sur
   sa rangée, et les onglets passent à la ligne : tous restent visibles. */
@media (max-width: 900px) {
  .marque { padding: 0; }
  .marque img { max-height: 30px; width: auto; }
  .onglets { order: 3; flex-basis: 100%; flex-wrap: wrap; overflow-x: visible; }
  /* Chaque bouton reste d'un seul tenant, mais la rangée passe à la ligne : sur
     un téléphone, « Se déconnecter » sortait de l'écran. */
  .rail-bas { gap: 6px; flex-wrap: wrap; justify-content: flex-end; }
  .rail-bas .role { white-space: nowrap; }
}
@media (max-width: 720px) {
  /* Le nom du compte cède la place : il est dans « Se déconnecter » et au journal. */
  .qui { display: none; }
}

/* ------------------------------------------------------ pages légales --
   Mentions légales et confidentialité (lot « mise en ligne ») : pages publiques,
   sans menu, en colonne de lecture. */
.page-legale { max-width: 720px; margin: 32px auto 48px; padding: 0 16px; line-height: 1.55; }
.page-legale h1 { font-size: 17px; margin: 8px 0 12px; }
.page-legale h2 { font-size: 15px; margin: 22px 0 6px; }
.page-legale ul { padding-left: 20px; }
.pied-legal { margin-top: 28px; text-align: center; }
.connexion + .pied-legal, .connexion .pied-legal { margin-top: 12px; }
.lien-legal { font-size: 12px; padding: 0 10px; }
/* Le menu du compte (revue d'ergonomie du 25/09) : ouvert dans la barre latérale,
   derrière un bouton sur tablette et téléphone. */
.bouton-compte { display: none; }
.menu-compte { display: contents; }
.rail-reduit .lien-legal { display: none; }

/* ---------------------------------------------------- feuille de secours --
   À imprimer avant l'ouverture (lot « mise en ligne ») : colonnes à remplir à la
   main, une page par pôle. Couleurs par les jetons, que le bloc d'impression remet
   en clair ; ses règles d'impression propres sont dans ce bloc (marges de page
   comprises : aucune page nommée, voir plus haut). */
.feuille-secours { background: var(--paper); color: var(--ink); padding: 16px; }
.feuille-secours h1 { font-size: 17px; margin: 0 0 6px; }
.feuille-secours table { width: 100%; border-collapse: collapse; font-size: 12px; margin-top: 8px; }
.feuille-secours th, .feuille-secours td { border: 1px solid var(--line-forte); padding: 5px 6px;
                                           text-align: left; vertical-align: top; }
.feuille-secours th { background: var(--surface); }
.feuille-secours .a-remplir { width: 11%; }
.feuille-secours .ligne-vide td { height: 26px; }
.feuille-secours .avec-adulte td:nth-child(5) { font-weight: 700; }
.page-secours + .page-secours { margin-top: 32px; }

/* -------------------------------------------------------------- pilotage --
   Lot du 2026-09-24, direction seule. Des blocs papier ; dans chaque bloc, une
   rangée par indicateur : le libellé, le chiffre, sa précision. La rangée est un
   `<details>` natif dont le dépliant porte la liste que le chiffre résume — aucun
   script. Les barres sont du CSS (`--part`, posée en ligne), sans bibliothèque, et
   restent en encre tertiaire : le lagon dit « actif », pas « beaucoup ». L'argile
   ne marque que ce qui attend une décision. */
.pilotage-contexte { font-size: 13px; color: var(--ink3); margin: 0 0 12px; }
.dates-libres label { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; color: var(--ink2); }
.dates-libres .champ { width: auto; }
.pilotage-grille { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(440px, 100%), 1fr));
                   gap: 16px; align-items: start; }
.pilotage-bloc { background: var(--paper); border: 1px solid var(--line); border-radius: 10px;
                 box-shadow: var(--ombre); padding: 12px 14px; min-width: 0; }
.pilotage-bloc h2 { font-size: 15px; font-weight: 650; padding-bottom: 8px; border-bottom: 1px solid var(--line); }
.pilotage-bloc > .cl { margin: 10px 0 2px; }
.indicateur { border-bottom: 1px solid var(--filet-doux); }
div.indicateur, .indicateur > summary {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 12px; row-gap: 2px;
  align-items: baseline; padding: 10px 0;
}
.indicateur > summary { cursor: pointer; list-style: none; border-radius: 6px; }
.indicateur > summary::-webkit-details-marker { display: none; }
.indicateur .libelle { font-size: 14px; font-weight: 550; min-width: 0; overflow-wrap: anywhere; }
.indicateur > summary .libelle::before {
  content: ""; display: inline-block; width: 6px; height: 6px; margin: 0 10px 0 2px; vertical-align: 2px;
  border-right: 1.75px solid var(--ink3); border-bottom: 1.75px solid var(--ink3);
  transform: rotate(-45deg); transition: transform .15s;
}
.indicateur[open] > summary .libelle::before { transform: rotate(45deg); }
div.indicateur .libelle { padding-left: 18px; }
.indicateur > summary:hover .libelle { color: var(--lagoon); }
.indicateur .valeur { font-size: 22px; font-weight: 650; line-height: 1.1; letter-spacing: -0.02em; text-align: right; }
.indicateur .valeur.attend { color: var(--clay); }
.indicateur .precision { grid-column: 1 / -1; font-size: 12px; color: var(--ink3); padding-left: 18px; }
.indicateur > :not(summary) { margin: 0 0 12px; }
.indicateur > p.cl { margin-top: -4px; }
.table-pilotage { width: 100%; border-collapse: collapse; font-size: 13px; }
.table-pilotage th { text-align: left; font-weight: 550; font-size: 12px; color: var(--ink3); padding: 6px 8px;
                     background: var(--surface); }
.table-pilotage td { padding: 6px 8px; border-top: 1px solid var(--filet-doux); vertical-align: middle; }
.table-pilotage .nombre { text-align: right; white-space: nowrap; }
.table-pilotage + .table-pilotage { margin-top: 10px; }
.barre-cellule { width: 38%; }
.barre-pilotage { display: block; height: 8px; border-radius: 5px; background: var(--surface); overflow: hidden; }
.barre-pilotage > span { display: block; height: 100%; width: var(--part, 0%); background: var(--ink3); border-radius: 5px; }
.liste-pilotage { list-style: none; margin: 0; padding: 0; columns: 2 220px; column-gap: 16px; font-size: 13px; }
.liste-pilotage li { break-inside: avoid; padding: 4px 0; display: flex; flex-wrap: wrap; gap: 0 8px; align-items: baseline; }
@media (max-width: 520px) { .barre-cellule { width: 28%; } }
@media (prefers-reduced-motion: reduce) { .indicateur > summary .libelle::before { transition: none; } }
@media (max-width: 1100px), (pointer: coarse) {
  .indicateur > summary { min-height: 44px; }
  .pilotage-bloc .cl a, .dates-libres a { display: inline-flex; align-items: center; min-height: 44px; }
}

/* ----------------------------------------------- listes de la direction --
   Dossiers à compléter, Assiduité, Signalements, Registre (27/09). Les tableaux
   du Pilotage dans un bloc papier ; des puces de filtre qui portent leur compte.
   Sous 760 px, chaque rangée devient une petite carte : le libellé de chaque
   cellule s'affiche au-dessus de sa valeur (`data-libelle`), sans défilement latéral. */
.filtres-liste { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 12px; }
.filtres-liste .puce { display: inline-flex; align-items: center; gap: 6px; text-decoration: none; border-radius: 20px; }
.filtres-liste .compte { font-variant-numeric: tabular-nums; font-weight: 650; }
.liste-direction { padding: 4px 6px; margin-bottom: 10px; }
.table-direction td { vertical-align: top; }
.table-direction .nombre .cl { white-space: nowrap; }
.texte-signalement { max-width: 60ch; margin: 2px 0; }
.etiquette-ecart { display: inline-block; padding: 1px 8px; border-radius: 10px; font-size: 12px; font-weight: 600;
                   border: 1px solid var(--line); color: var(--ink2); white-space: nowrap; }
.etiquette-ecart.en_dessous, .etiquette-ecart.decale { color: var(--clay); background: var(--clay-soft); border-color: var(--clay-line); }
.etiquette-ecart.au_dessus { color: var(--lagoon); background: var(--lagoon-soft); border-color: var(--lagoon-line); }
@media (max-width: 760px) {
  .table-direction thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .table-direction, .table-direction tbody, .table-direction tr, .table-direction td { display: block; width: 100%; }
  .table-direction tr { padding: 8px 2px; border-top: 1px solid var(--line); }
  .table-direction tr:first-child { border-top: 0; }
  .table-direction td { border: 0; padding: 3px 6px; text-align: left; }
  .table-direction td.nombre { text-align: left; white-space: normal; }
  .table-direction td::before { content: attr(data-libelle); display: block; color: var(--ink3); font-size: 12px; }
}

/* ------------------------------------------ fiches élèves : la liste (28/09) --
   Quatre rangées de pastilles (pôle, classe, prestation, statut), chacune avec son
   titre à gauche ; elles passent à la ligne plutôt que de faire défiler la page.
   Les élèves, sous leur pôle puis leur classe, dans les tableaux de la direction. */
.filtres-fiches { display: grid; gap: 4px; margin: 0 0 8px; }
.rangee-filtre { display: grid; grid-template-columns: 96px minmax(0, 1fr); align-items: start; gap: 8px; }
.rangee-filtre .filtres-liste { margin: 0; }
.titre-filtre { padding-top: 7px; font-size: 12px; font-weight: 650; color: var(--ink3);
                text-transform: uppercase; letter-spacing: .04em; }
.compte-fiches { margin: 4px 0 10px; }
.pole-fiches + .pole-fiches { margin-top: 18px; }
.titre-classe { font-size: 14px; font-weight: 650; margin: 6px 6px 2px; }
.titre-classe .cl, .pole-fiches .titre-partie .cl { font-weight: 400; font-size: 13px; }
.table-fiches { width: 100%; }
.table-fiches td { overflow-wrap: anywhere; vertical-align: middle; }
.table-fiches tr.inactif .nom-lien { color: var(--ink2); }
@media (min-width: 761px) {
  .table-fiches th:first-child { width: 38%; }
  .table-fiches th:nth-child(2) { width: 27%; }
}
@media (max-width: 1100px), (pointer: coarse) { .titre-filtre { padding-top: 14px; } }
@media (max-width: 520px) {
  .rangee-filtre { grid-template-columns: minmax(0, 1fr); gap: 2px; }
  .titre-filtre { padding-top: 6px; }
}

/* ------------------------------------------------- cours particuliers (28/09) --
   La grille du classeur « Planning Cours Particuliers » : un jour par bloc, une
   colonne par salle, une ligne par demi-heure. Chaque tuteur garde sa teinte d'une
   semaine à l'autre (le classeur colorait les cases par tuteur) ; la teinte est mêlée
   au papier, donc lisible en clair comme en sombre. Un cours fait porte ✓, un cours
   à replacer est hachuré.

   Plan « planning-cp » (29/09) :
   - E1 : chaque jour est sa propre grille, à lignes de hauteur FIXE (`--haut-jour`,
     `--haut-salle`) : l'en-tête du jour colle à `top: 0`, celui des salles juste
     dessous, la colonne des heures à gauche. Le cadre défile seul, à toutes les
     largeurs — sous 760 px il perdait sa hauteur maximale, et un cadre
     `overflow: auto` qui ne défile pas en hauteur empêche tout collage en haut.
   - E5 : `.vue-jour` montre le jour choisi seul ; `.vue-auto` fait de même sous
     1 200 px, et montre la semaine en colonnes étroites au-dessus.
   - A7, O3 : les cases vides n'ont pas d'arrêt de tabulation ; `soskool.js` ouvre
     « planifier ici » d'après `data-*`.

   Plan « cours-particuliers-2 » (01/10) :
   - six salles sur deux niveaux : une ligne des niveaux entre le jour et les salles ;
   - le jour par salle (`--col`), la semaine par couloirs (`--piste`, décision 12) :
     six salles × six jours ne tiennent sur aucun écran ni sur le papier ;
   - plus aucun élément par demi-heure : le fond de la colonne dessine les lignes, le
     toucher se lit à sa hauteur (`soskool.js`), un seul fantôme suit la souris ;
   - textes de 12 px au moins, cibles de 44 px au doigt, repère de l'heure courante,
     légende des statuts, état vide. */
.planning-defile { overflow: auto; max-height: calc(100vh - 180px); min-height: 320px; background: var(--paper);
                   isolation: isolate;
                   border: 1px solid var(--line); border-radius: 10px; box-shadow: var(--ombre);
                   margin-bottom: 16px; }
.planning-defile:focus-visible { outline: 2px solid var(--lagoon); outline-offset: 2px; }
/* Une demi-heure : 28 px à la souris, 44 px au doigt (cibles tactiles, lot 4 : une
   case d'une demi-heure y est un bouton). */
.grille-cp { --ligne-cp: 28px; --haut-jour: 48px; --haut-niveau: 20px; --haut-salle: 22px; --col-min: 96px;
             display: flex; min-width: min-content; position: relative; }
@media (pointer: coarse) { .grille-cp { --ligne-cp: 44px; --haut-jour: 60px; } }
.heures-cp, .jour-bloc { display: grid; min-width: 0;
                         grid-template-rows: var(--haut-jour) var(--haut-niveau) var(--haut-salle) repeat(var(--lignes), var(--ligne-cp)); }
.heures-cp { flex: 0 0 52px; position: sticky; left: 0; z-index: 4; background: var(--paper); }
.coin-cp { grid-row: 1 / span 3; position: sticky; top: 0; z-index: 1; background: var(--paper);
           border-bottom: 1px solid var(--line); }
.heure-cp { font-size: 12px; color: var(--ink3); text-align: right; padding: 2px 6px 0 0; line-height: 1; }
.heure-cp.pleine { font-weight: 600; color: var(--ink2); }
/* Le jour par salle : `--salles` colonnes, chaque cours dans la sienne (`--col`). */
.jour-bloc { flex: 1 1 0; min-width: calc(var(--salles) * var(--col-min)); position: relative;
             grid-template-columns: repeat(var(--salles), minmax(0, 1fr)); border-left: 2px solid var(--line); }
.jour-bloc.p-1 { --pistes: 1; } .jour-bloc.p-2 { --pistes: 2; } .jour-bloc.p-3 { --pistes: 3; }
.jour-bloc.p-4 { --pistes: 4; } .jour-bloc.p-5 { --pistes: 5; } .jour-bloc.p-6 { --pistes: 6; }
.jour-bloc.p-7 { --pistes: 7; } .jour-bloc.p-8 { --pistes: 8; }
.jour-cp { grid-column: 1 / -1; grid-row: 1; position: sticky; top: 0; z-index: 3; min-width: 0; overflow: hidden;
           background: var(--paper); padding: 5px 8px 3px; border-bottom: 1px solid var(--filet-doux); }
.jour-bloc.aujourdhui .jour-cp { background: var(--lagoon-soft); }
.nom-jour { display: flex; align-items: center; gap: 6px; white-space: nowrap; }
.nom-jour h3 { font-size: 13px; font-weight: 650; margin: 0; }
.date-jour { color: var(--ink3); font-weight: 400; }
.jour-court { display: none; }
.nom-jour .lien-discret { font-size: 12px; padding: 4px 4px; }
.nom-jour .ajout-jour { margin-left: auto; color: var(--lagoon); font-weight: 600; }
/* Au doigt : « + Cours » et « Infos » ont 44 px de haut (critique du 01/10). */
@media (pointer: coarse), (max-width: 1100px) {
  .nom-jour .lien-discret { min-height: 44px; padding: 0 8px; display: inline-flex; align-items: center; }
  .grille-cp { --haut-jour: 60px; }
}
/* La supervision lit sans planifier : pas de boutons dans l'en-tête du jour, il
   reprend sa hauteur d'avant (le nom, puis la ligne des infos). */
.grille-cp.lecture { --haut-jour: 44px; }
.infos-jour { margin: 1px 0 0; font-size: 12px; color: var(--clay); line-height: 1.35;
              white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.absents-jour { color: var(--rouge); font-weight: 600; }
/* Six salles sur deux niveaux (01/10) : la ligne des niveaux colle sous le jour,
   celle des salles sous les niveaux. */
.niveau-cp { grid-row: 2; position: sticky; top: var(--haut-jour); z-index: 3; background: var(--surface);
             padding: 2px 6px; font-size: 12px; font-weight: 600; color: var(--ink2); white-space: nowrap;
             overflow: hidden; text-overflow: ellipsis; border-left: 1px solid var(--line); }
.salle-cp { grid-row: 3; position: sticky; top: calc(var(--haut-jour) + var(--haut-niveau)); z-index: 3; background: var(--paper);
            padding: 3px 6px; font-size: 12px; font-weight: 600; color: var(--ink2);
            border-left: 1px solid var(--filet-doux);
            border-bottom: 1px solid var(--line); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Les demi-heures sont dessinées par le fond : un filet en haut de chaque ligne. */
.colonne-cp, .colonne-jour-cp { grid-row: 4 / -1; position: relative; border-left: 1px solid var(--filet-doux);
              background: repeating-linear-gradient(to bottom, var(--filet-doux) 0 1px, transparent 1px var(--ligne-cp)); }
.colonne-jour-cp { grid-column: 1 / -1; display: none; }
[data-nouveau] :is(.colonne-cp, .colonne-jour-cp) { cursor: pointer; }
/* Le fantôme « + » qui suit la souris (soskool.js pose `--rang`) : la case libre
   qu'un clic planifierait. Aucun au doigt, où il n'y a pas de survol. */
.survol-cp { position: absolute; left: 0; right: 0; top: calc(var(--rang, 0) * var(--ligne-cp)); height: var(--ligne-cp);
             background: var(--lagoon-soft); color: var(--lagoon); font-weight: 650; display: flex;
             align-items: center; justify-content: center; pointer-events: none; }
.vide-jour-cp { grid-row: 4 / -1; grid-column: 1 / -1; align-self: start; justify-self: center; margin: 24px 0 0;
                font-size: 12px; color: var(--ink3); pointer-events: none; z-index: 1; }
/* Le repère de l'heure courante (décision 14) : un trait rouge sur le jour
   d'aujourd'hui, posé et avancé chaque minute par soskool.js (`--minute-cp`). Sans
   script, ou hors des heures de la grille, il ne se montre pas. */
.maintenant-cp { grid-row: 4 / -1; grid-column: 1 / -1; position: relative; pointer-events: none; z-index: 2;
                 display: none; }
.maintenant-cp.pose { display: block; }
.maintenant-cp::before { content: ""; position: absolute; left: 0; right: 0; height: 2px; margin-top: -1px;
                         top: calc(var(--minute-cp, 0) * var(--ligne-cp) / 30); background: var(--rouge); opacity: .7; }
.maintenant-cp::after { content: ""; position: absolute; left: -4px; width: 8px; height: 8px; border-radius: 50%;
                        margin-top: -4px; top: calc(var(--minute-cp, 0) * var(--ligne-cp) / 30); background: var(--rouge); }
.cours-cp { --t: var(--ink3); grid-column: var(--col); margin: 1px 2px; padding: 3px 6px;
            border: 1px solid color-mix(in srgb, var(--t) 45%, var(--paper));
            border-left: 4px solid var(--t);
            border-radius: 6px; background: color-mix(in srgb, var(--t) 12%, var(--paper));
            color: var(--ink); text-align: left; font: inherit; line-height: 1.25; display: flex;
            flex-direction: column; gap: 1px; overflow: hidden; z-index: 1; min-width: 0; }
button.cours-cp { cursor: pointer; }
button.cours-cp:hover, button.cours-cp:focus-visible { background: color-mix(in srgb, var(--t) 22%, var(--paper));
                                                        outline: 2px solid var(--t); outline-offset: -1px; }
.teinte-0 { --t: var(--t0); } .teinte-1 { --t: var(--t1); } .teinte-2 { --t: var(--t2); }
.teinte-3 { --t: var(--t3); } .teinte-4 { --t: var(--t4); } .teinte-5 { --t: var(--t5); }
.teinte-6 { --t: var(--t6); } .teinte-7 { --t: var(--t7); } .teinte-sans { --t: var(--ink3); }
/* La case : le nom en graisse, puis matière et tuteur, puis classe, heures du
   forfait et statut — 12 px au moins (règle du nom en graisse, DESIGN.md). */
.eleve-cp { font-size: 13px; font-weight: 650; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.detail-cp { font-size: 12px; color: var(--ink2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.salle-case-cp { display: none; font-weight: 600; }
.bas-cp { display: flex; gap: 6px; align-items: center; margin-top: auto; font-size: 12px; color: var(--ink2);
          white-space: nowrap; overflow: hidden; }
.classe-cp { overflow: hidden; text-overflow: ellipsis; }
.rang-cp { font-weight: 600; color: var(--ink2); font-variant-numeric: tabular-nums; }
.fait-cp { margin-left: auto; color: var(--vert); font-weight: 700; }
.replacer-cp { margin-left: auto; color: var(--clay); font-weight: 600; }
/* Relecture de « planning-cp », M2 : le tuteur est annoncé absent ce jour-là. Un
   filet rouge en tirets, et le mot : la couleur seule ne se lit ni en gris ni au
   lecteur d'écran (qui lit « tuteur absent »). */
.cours-cp.tuteur-absent { border: 1.5px dashed var(--rouge); border-left-width: 4px; }
.absent-cp { margin-left: auto; color: var(--rouge); font-weight: 650; }
.absent-cp + .fait-cp { margin-left: 0; }
.cours-cp.fait { background: color-mix(in srgb, var(--t) 5%, var(--paper)); border-left-style: double; }
.cours-cp.fait .eleve-cp { color: var(--ink2); }
.cours-cp.a_replacer { background: repeating-linear-gradient(135deg, color-mix(in srgb, var(--clay) 12%, var(--paper)) 0 6px,
                                                              var(--paper) 6px 12px);
                       border-left-color: var(--clay); }
/* La légende (décision 15) : une ligne de 12 px sous les commandes. */
.outils-cp { display: flex; gap: 8px 16px; align-items: center; justify-content: space-between; margin: 0 0 8px; }
.outils-cp .groupe { display: flex; gap: 6px; align-items: center; flex: none; }
.legende-cp { display: flex; flex-wrap: wrap; gap: 2px 14px; align-items: center; margin: 0; padding: 0; flex: 1 1 auto;
              list-style: none; font-size: 12px; color: var(--ink3); }
@media (max-width: 520px) { .outils-cp { flex-wrap: wrap; } }
.legende-cp li { display: inline-flex; align-items: center; gap: 5px; }
.legende-cp .consigne-cp { color: var(--ink2); }
.pastille-cp { width: 16px; height: 12px; border-radius: 3px; border: 1px solid color-mix(in srgb, var(--t0) 45%, var(--paper));
               border-left: 3px solid var(--t0); background: color-mix(in srgb, var(--t0) 12%, var(--paper));
               font-size: 9px; line-height: 10px; text-align: center; color: var(--vert); font-weight: 700; }
.pastille-cp.fait { background: color-mix(in srgb, var(--t0) 5%, var(--paper)); border-left-style: double; }
.pastille-cp.pastille-absent { border: 1.5px dashed var(--rouge); border-left-width: 3px; }
.vide-semaine-cp { margin: 0 0 8px; }
/* Les vues (E5). Les puces : « Semaine », puis un jour chacune ; en vue
   automatique, la puce allumée suit la largeur, comme la grille. */
.aller-jour { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin: 0 0 8px; }
.aller-jour .groupe { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.aller-jour .espace { flex-grow: 1; }
.aller-jour .puce { text-decoration: none; }
.aller-jour .puce-semaine { margin-right: 6px; }
.aller-jour .puce-jour.aujourdhui:not(.actif) { border-color: var(--lagoon-line); }
.vue-jour .jour-bloc:not(.choisi) { display: none; }
.vue-jour .jour-bloc { min-width: calc(var(--salles) * var(--col-min)); }
/* La vue automatique (relecture m6 de « planning-cp ») : la semaine seulement à
   partir de 1 200 px ET si elle TIENT dans la région. Depuis le 01/10 (décision 12),
   la semaine se range en couloirs : il lui faut 52 + 6 × couloirs × 56 + 16 px, où
   « couloirs » est le plus grand nombre de cours simultanés d'un jour (classe
   `pistes-N`, posée par le serveur). La région vaut l'écran moins 295 px (menu
   déplié) ou 127 px (menu réduit). Au-delà de quatre couloirs, un jour. Des requêtes
   d'écran et non de conteneur : le projet n'en a aucune (test du lot 3). Sinon, le
   jour choisi seul, par salle. */
.vue-auto .jour-bloc:not(.choisi) { display: none; }
.aller-jour.vue-auto .puce-jour.choisi { background: var(--lagoon); color: var(--sur-accent); border-color: var(--lagoon); }
/* La vue semaine forcée : en couloirs, à toutes les largeurs ; le cadre défile en
   largeur quand elle ne tient pas. */
.vue-semaine .grille-cp { --col-min: 56px; --haut-niveau: 0px; --haut-salle: 0px; }
.vue-semaine .jour-bloc { grid-template-columns: repeat(var(--pistes), minmax(0, 1fr));
    min-width: calc(var(--pistes) * var(--col-min)); }
.vue-semaine :is(.niveau-cp, .salle-cp, .colonne-cp) { display: none; }
.vue-semaine .colonne-jour-cp { display: block; }
.vue-semaine .cours-cp { grid-column: var(--piste); padding: 2px 4px; }
.vue-semaine .salle-case-cp { display: inline; }
.vue-semaine .jour-long { position: absolute; width: 1px; height: 1px; overflow: hidden;
    clip-path: inset(50%); white-space: nowrap; }
.vue-semaine .jour-court { display: inline; }
.vue-semaine .jour-cp { padding: 5px 6px 3px; }
@media (min-width: 1200px) {
  .pistes-1.vue-auto .jour-bloc:not(.choisi) { display: grid; }
  .aller-jour.pistes-1.vue-auto .puce-jour.choisi { background: var(--paper); color: var(--ink2); border-color: var(--line); }
  .aller-jour.pistes-1.vue-auto .puce-semaine { background: var(--lagoon); color: var(--sur-accent); border-color: var(--lagoon); }
  .pistes-1.vue-auto .grille-cp { --col-min: 56px; --haut-niveau: 0px; --haut-salle: 0px; }
  .pistes-1.vue-auto .jour-bloc { grid-template-columns: repeat(var(--pistes), minmax(0, 1fr));
      min-width: calc(var(--pistes) * var(--col-min)); }
  .pistes-1.vue-auto :is(.niveau-cp, .salle-cp, .colonne-cp) { display: none; }
  .pistes-1.vue-auto .colonne-jour-cp { display: block; }
  .pistes-1.vue-auto .cours-cp { grid-column: var(--piste); padding: 2px 4px; }
  .pistes-1.vue-auto .salle-case-cp { display: inline; }
  .pistes-1.vue-auto .jour-long { position: absolute; width: 1px; height: 1px; overflow: hidden;
      clip-path: inset(50%); white-space: nowrap; }
  .pistes-1.vue-auto .jour-court { display: inline; }
  .pistes-1.vue-auto .jour-cp { padding: 5px 6px 3px; }
}
@media (min-width: 1200px) {
  .pistes-2.vue-auto .jour-bloc:not(.choisi) { display: grid; }
  .aller-jour.pistes-2.vue-auto .puce-jour.choisi { background: var(--paper); color: var(--ink2); border-color: var(--line); }
  .aller-jour.pistes-2.vue-auto .puce-semaine { background: var(--lagoon); color: var(--sur-accent); border-color: var(--lagoon); }
  .pistes-2.vue-auto .grille-cp { --col-min: 56px; --haut-niveau: 0px; --haut-salle: 0px; }
  .pistes-2.vue-auto .jour-bloc { grid-template-columns: repeat(var(--pistes), minmax(0, 1fr));
      min-width: calc(var(--pistes) * var(--col-min)); }
  .pistes-2.vue-auto :is(.niveau-cp, .salle-cp, .colonne-cp) { display: none; }
  .pistes-2.vue-auto .colonne-jour-cp { display: block; }
  .pistes-2.vue-auto .cours-cp { grid-column: var(--piste); padding: 2px 4px; }
  .pistes-2.vue-auto .salle-case-cp { display: inline; }
  .pistes-2.vue-auto .jour-long { position: absolute; width: 1px; height: 1px; overflow: hidden;
      clip-path: inset(50%); white-space: nowrap; }
  .pistes-2.vue-auto .jour-court { display: inline; }
  .pistes-2.vue-auto .jour-cp { padding: 5px 6px 3px; }
}
@media (min-width: 1371px) {
  .pistes-3.vue-auto .jour-bloc:not(.choisi) { display: grid; }
  .aller-jour.pistes-3.vue-auto .puce-jour.choisi { background: var(--paper); color: var(--ink2); border-color: var(--line); }
  .aller-jour.pistes-3.vue-auto .puce-semaine { background: var(--lagoon); color: var(--sur-accent); border-color: var(--lagoon); }
  .pistes-3.vue-auto .grille-cp { --col-min: 56px; --haut-niveau: 0px; --haut-salle: 0px; }
  .pistes-3.vue-auto .jour-bloc { grid-template-columns: repeat(var(--pistes), minmax(0, 1fr));
      min-width: calc(var(--pistes) * var(--col-min)); }
  .pistes-3.vue-auto :is(.niveau-cp, .salle-cp, .colonne-cp) { display: none; }
  .pistes-3.vue-auto .colonne-jour-cp { display: block; }
  .pistes-3.vue-auto .cours-cp { grid-column: var(--piste); padding: 2px 4px; }
  .pistes-3.vue-auto .salle-case-cp { display: inline; }
  .pistes-3.vue-auto .jour-long { position: absolute; width: 1px; height: 1px; overflow: hidden;
      clip-path: inset(50%); white-space: nowrap; }
  .pistes-3.vue-auto .jour-court { display: inline; }
  .pistes-3.vue-auto .jour-cp { padding: 5px 6px 3px; }
}
@media (min-width: 1203px) and (max-width: 1370.98px) {
  .rail-reduit .pistes-3.vue-auto .jour-bloc:not(.choisi) { display: grid; }
  .rail-reduit .aller-jour.pistes-3.vue-auto .puce-jour.choisi { background: var(--paper); color: var(--ink2); border-color: var(--line); }
  .rail-reduit .aller-jour.pistes-3.vue-auto .puce-semaine { background: var(--lagoon); color: var(--sur-accent); border-color: var(--lagoon); }
  .rail-reduit .pistes-3.vue-auto .grille-cp { --col-min: 56px; --haut-niveau: 0px; --haut-salle: 0px; }
  .rail-reduit .pistes-3.vue-auto .jour-bloc { grid-template-columns: repeat(var(--pistes), minmax(0, 1fr));
      min-width: calc(var(--pistes) * var(--col-min)); }
  .rail-reduit .pistes-3.vue-auto :is(.niveau-cp, .salle-cp, .colonne-cp) { display: none; }
  .rail-reduit .pistes-3.vue-auto .colonne-jour-cp { display: block; }
  .rail-reduit .pistes-3.vue-auto .cours-cp { grid-column: var(--piste); padding: 2px 4px; }
  .rail-reduit .pistes-3.vue-auto .salle-case-cp { display: inline; }
  .rail-reduit .pistes-3.vue-auto .jour-long { position: absolute; width: 1px; height: 1px; overflow: hidden;
      clip-path: inset(50%); white-space: nowrap; }
  .rail-reduit .pistes-3.vue-auto .jour-court { display: inline; }
  .rail-reduit .pistes-3.vue-auto .jour-cp { padding: 5px 6px 3px; }
}
@media (min-width: 1707px) {
  .pistes-4.vue-auto .jour-bloc:not(.choisi) { display: grid; }
  .aller-jour.pistes-4.vue-auto .puce-jour.choisi { background: var(--paper); color: var(--ink2); border-color: var(--line); }
  .aller-jour.pistes-4.vue-auto .puce-semaine { background: var(--lagoon); color: var(--sur-accent); border-color: var(--lagoon); }
  .pistes-4.vue-auto .grille-cp { --col-min: 56px; --haut-niveau: 0px; --haut-salle: 0px; }
  .pistes-4.vue-auto .jour-bloc { grid-template-columns: repeat(var(--pistes), minmax(0, 1fr));
      min-width: calc(var(--pistes) * var(--col-min)); }
  .pistes-4.vue-auto :is(.niveau-cp, .salle-cp, .colonne-cp) { display: none; }
  .pistes-4.vue-auto .colonne-jour-cp { display: block; }
  .pistes-4.vue-auto .cours-cp { grid-column: var(--piste); padding: 2px 4px; }
  .pistes-4.vue-auto .salle-case-cp { display: inline; }
  .pistes-4.vue-auto .jour-long { position: absolute; width: 1px; height: 1px; overflow: hidden;
      clip-path: inset(50%); white-space: nowrap; }
  .pistes-4.vue-auto .jour-court { display: inline; }
  .pistes-4.vue-auto .jour-cp { padding: 5px 6px 3px; }
}
@media (min-width: 1539px) and (max-width: 1706.98px) {
  .rail-reduit .pistes-4.vue-auto .jour-bloc:not(.choisi) { display: grid; }
  .rail-reduit .aller-jour.pistes-4.vue-auto .puce-jour.choisi { background: var(--paper); color: var(--ink2); border-color: var(--line); }
  .rail-reduit .aller-jour.pistes-4.vue-auto .puce-semaine { background: var(--lagoon); color: var(--sur-accent); border-color: var(--lagoon); }
  .rail-reduit .pistes-4.vue-auto .grille-cp { --col-min: 56px; --haut-niveau: 0px; --haut-salle: 0px; }
  .rail-reduit .pistes-4.vue-auto .jour-bloc { grid-template-columns: repeat(var(--pistes), minmax(0, 1fr));
      min-width: calc(var(--pistes) * var(--col-min)); }
  .rail-reduit .pistes-4.vue-auto :is(.niveau-cp, .salle-cp, .colonne-cp) { display: none; }
  .rail-reduit .pistes-4.vue-auto .colonne-jour-cp { display: block; }
  .rail-reduit .pistes-4.vue-auto .cours-cp { grid-column: var(--piste); padding: 2px 4px; }
  .rail-reduit .pistes-4.vue-auto .salle-case-cp { display: inline; }
  .rail-reduit .pistes-4.vue-auto .jour-long { position: absolute; width: 1px; height: 1px; overflow: hidden;
      clip-path: inset(50%); white-space: nowrap; }
  .rail-reduit .pistes-4.vue-auto .jour-court { display: inline; }
  .rail-reduit .pistes-4.vue-auto .jour-cp { padding: 5px 6px 3px; }
}
.panneaux-cp { display: grid; gap: 16px; grid-template-columns: repeat(auto-fit, minmax(min(420px, 100%), 1fr)); align-items: start; }
/* Vérification finale du 09/10, G3 : le tableau des forfaits a sept colonnes. Dans
   une demi-grille (420 px à 1024) il débordait de sa carte et de la page, « Clore »
   coupé au bord de l'écran. Il prend toute la largeur des panneaux. */
.panneaux-cp .forfaits-cp { grid-column: 1 / -1; }
.liste-replacer-cp, .liste-cours-tuteur { list-style: none; margin: 8px 0 0; padding: 0; font-size: 13px; }
.liste-replacer-cp li, .liste-cours-tuteur li { display: flex; flex-wrap: wrap; gap: 2px 8px; align-items: baseline;
                                                 padding: 6px 0; border-top: 1px solid var(--filet-doux); }
.liste-replacer-cp li:first-child, .liste-cours-tuteur li:first-child { border-top: 0; }
.liste-cours-tuteur { background: var(--paper); border: 1px solid var(--line); border-radius: 10px; padding: 4px 12px;
                      margin-bottom: 22px; }
.quand-cp { font-weight: 600; min-width: 170px; }
.etats-cours { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 14px; padding-bottom: 14px;
               border-bottom: 1px solid var(--line); }
.secondaire.danger { color: var(--rouge); }
/* E9 (plan « planning-cp ») : « jusqu'au » n'apparaît que si « Répéter » est coché.
   Sans script : la CSP refuse le JS en ligne, et `:has` suffit. Un navigateur sans
   `:has` montre tout, comme avant. */
.ligne-repeter .champ-jusqu { display: contents; }
.ligne-repeter:not(:has(input[name="repeter"]:checked)) .champ-jusqu { display: none; }
/* Les cinq formules (01/10) : des choix rapides en pilules, deux lignes chacune (la
   formule, puis ce qu'il reste ou « à ouvrir »). Le nom du forfait ne se montre que
   pour un forfait à ouvrir ; il est facultatif, donc jamais bloquant s'il est caché. */
.formules-cp { border: 0; margin: 0 0 12px; padding: 0; min-width: 0; }
.formules-cp legend, .choix-dispo legend { font-size: 13px; font-weight: 600; color: var(--ink2); padding: 0;
                                          margin-bottom: 6px; }
.pilules-cp { display: flex; flex-wrap: wrap; gap: 6px; }
.pilule-cp { position: relative; display: inline-flex; }
.pilule-cp input { position: absolute; opacity: 0; inset: 0; margin: 0; cursor: pointer; }
.pilule-cp > span { display: flex; flex-direction: column; gap: 1px; min-height: 44px; justify-content: center;
                    padding: 5px 12px; border: 1px solid var(--line-forte); border-radius: 10px;
                    background: var(--paper); color: var(--ink); font-size: 13px; font-weight: 550;
                    line-height: 1.25; cursor: pointer; }
.pilule-cp small { font-size: 12px; font-weight: 400; color: var(--ink3); }
.pilule-cp:hover > span { border-color: var(--lagoon-line); background: var(--lagoon-soft); }
/* Cochée : fond lagon, texte blanc, comme les catégories en pilules (DESIGN.md). */
.pilule-cp input:checked + span { border-color: var(--lagoon); background: var(--lagoon); color: var(--sur-accent); }
.pilule-cp input:checked + span small { color: color-mix(in srgb, var(--sur-accent) 86%, var(--lagoon)); }
.pilule-cp input:focus-visible + span { outline: 2px solid var(--lagoon); outline-offset: 2px; }
.pilule-cp.complet > span { color: var(--ink3); }
.formules-cp .nom-forfait { margin-top: 8px; }
.formules-cp:not(:has(input[value^="nouveau"]:checked)) .nom-forfait { display: none; }
/* La fenêtre « Nouveau cours » (01/10) : qui est libre, en pilules ; les occupés
   grisés, avec leur raison en toutes lettres (« Grisé avec sa raison », DESIGN.md).
   Ils restent choisissables : le serveur juge (décision 7). */
.boite-cours .corps { display: flex; flex-direction: column; gap: 4px; }
.dispos-cp { display: flex; flex-direction: column; gap: 12px; margin: 4px 0 12px; }
.choix-dispo { border: 0; margin: 0; padding: 0; min-width: 0; }
.pilule-cp.occupe > span { background: var(--surface); border-style: dashed; color: var(--ink2); }
.pilule-cp.occupe small { color: var(--ink3); }
.pilule-cp.occupe input:checked + span { background: var(--surface); color: var(--ink);
                                         border: 2px solid var(--clay); }
.pilule-cp.occupe input:checked + span small { color: var(--clay); }
.niveau-dispo + .niveau-dispo { margin-top: 8px; }
.titre-niveau { display: block; font-size: 12px; color: var(--ink3); margin-bottom: 4px; }
.creneaux-cp { margin: 8px 0 0; font-size: 13px; color: var(--ink2); }
.creneaux-cp:empty, .creneaux-cp:has(> span:empty) { display: none; }
.alerte-eleve { border-color: var(--clay-line); background: var(--clay-soft); }
.plus-options { border-top: 1px solid var(--line); margin-top: 4px; }
.plus-options > summary { display: flex; align-items: center; gap: 8px; min-height: 44px; cursor: pointer;
                          font-size: 13.5px; font-weight: 550; color: var(--ink2); list-style: none; }
.plus-options > summary::-webkit-details-marker { display: none; }
.plus-options > summary::before { content: "›"; display: inline-block; width: 12px; color: var(--ink3);
                                  transition: transform .15s; }
.plus-options[open] > summary::before { transform: rotate(90deg); }
.plus-options > summary .cl { font-weight: 400; }
.plus-options .contenu-options { padding: 4px 0 8px; }
.pied-cours { display: flex; justify-content: space-between; gap: 8px; }
.icone-recherche { color: var(--ink3); }
.aide-recherche { margin: 6px 0 0; font-size: 12px; color: var(--ink3); }
@media (prefers-reduced-motion: reduce) { .plus-options > summary::before { transition: none; } }
.resultats-cours { margin-top: 10px; max-height: 50vh; overflow: auto; }
.resultats-cours .ligne-resultat { width: 100%; text-align: left; background: none; border: 0; font: inherit; cursor: pointer; }
@media (max-width: 760px) {
  .quand-cp { min-width: 0; width: 100%; }
}
/* L'impression (E5) : la semaine entière, quelle que soit la vue, sur une page A4
   paysage — la page nommée « planning-cp », déclarée avec les marges du site, dans
   le bloc d'impression commun. La hauteur d'une demi-heure se déduit du nombre de
   lignes, pour que la grille tienne sur une page même étendue de 7 h à 20 h. Depuis
   le 01/10, la semaine imprimée est rangée en couloirs (décision 12) : six salles
   × six jours feraient 36 colonnes de 7 mm. */
@media print {
  .aller-jour, .ajout-jour, .nom-jour .lien-discret, .consigne-cp, .maintenant-cp, .survol-cp,
  .vide-jour-cp { display: none !important; }
  .legende-cp { font-size: 7pt; margin: 0 0 2pt; gap: 0 8pt; }
  .planning-defile { overflow: visible; max-height: none; min-height: 0; box-shadow: none; border-radius: 0;
                     border: 0.5pt solid var(--line-forte); break-inside: avoid; margin-bottom: 0; }
  .grille-cp, .grille-cp.lecture { --ligne-cp: calc(140mm / var(--lignes)); --haut-jour: 10.5mm; --haut-niveau: 0mm; --haut-salle: 0mm;
               --col-min: 0px; min-width: 0; width: 100%; }
  .planning-defile .jour-bloc { display: grid !important; min-width: 0;
                                grid-template-columns: repeat(var(--pistes), minmax(0, 1fr)); }
  .planning-defile :is(.niveau-cp, .salle-cp, .colonne-cp) { display: none !important; }
  .planning-defile .colonne-jour-cp { display: block !important; }
  .planning-defile .cours-cp { grid-column: var(--piste); }
  .planning-defile .salle-case-cp { display: inline !important; }
  .heures-cp { flex-basis: 9mm; position: static; }
  .coin-cp, .jour-cp { position: static; }
  .jour-cp { padding: 1mm 1.5mm 0.5mm; }
  .nom-jour h3 { font-size: 9pt; }
  .infos-jour { font-size: 7pt; margin-top: 0.5mm; }
  .heure-cp { font-size: 7pt; padding-right: 1mm; }
  .jour-long { position: static !important; width: auto !important; height: auto !important; clip-path: none !important; }
  .jour-court { display: none !important; }
  .cours-cp { padding: 0.5mm 1mm; margin: 0.3mm 0.5mm; border-radius: 1mm; gap: 0; border-left-width: 1.5mm; }
  .eleve-cp { font-size: 7.5pt; }
  .detail-cp, .bas-cp { font-size: 6.5pt; }
  .panneaux-cp { break-before: page; }
  /* Les requêtes de largeur se lisent sur la page PAR DÉFAUT (portrait, 192 mm, soit
     moins de 760 px) : le tableau des forfaits passait en cartes, sur trois pages.
     Sur la page paysage, il redevient un tableau. */
  .panneaux-cp .table-direction { display: table; width: 100%; }
  .panneaux-cp .table-direction thead { position: static; width: auto; height: auto; overflow: visible;
                                        clip: auto; display: table-header-group; }
  .panneaux-cp .table-direction tbody { display: table-row-group; width: auto; }
  .panneaux-cp .table-direction tr { display: table-row; width: auto; padding: 0; }
  .panneaux-cp .table-direction td { display: table-cell; width: auto; padding: 1.5pt 4pt;
                                     border-top: 0.5pt solid var(--line); }
  .panneaux-cp .table-direction td.nombre { text-align: right; }
  .panneaux-cp .table-direction td::before { content: none; }
}

/* ---------------------------------------------------- fiche élève complète --
   L'onglet de la direction (27/09) : le dossier en cartes, sur deux colonnes quand
   la place le permet ; l'historique en une colonne, ses longues listes repliées. */
.titre-partie { font-size: 15px; font-weight: 650; margin: 18px 0 8px; }
.sections-fiche { display: grid; gap: 12px; grid-template-columns: minmax(0, 1fr); align-items: start; }
@media (min-width: 1100px) { .sections-fiche:not(.historique) { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.section-fiche { background: var(--paper); border: 1px solid var(--line); border-radius: 10px;
                 padding: 12px 14px; box-shadow: var(--ombre); min-width: 0; }
.section-fiche > header { display: flex; align-items: center; gap: 8px; padding-bottom: 6px; margin-bottom: 8px;
                          border-bottom: 1px solid var(--line); }
.section-fiche > header h2 { font-size: 14px; font-weight: 650; margin: 0; flex-grow: 1; }
.section-fiche p { margin: 0 0 6px; }
.donnees { display: grid; grid-template-columns: minmax(120px, 170px) minmax(0, 1fr); gap: 4px 12px;
           margin: 0; font-size: 13px; }
.donnees dt { color: var(--ink3); }
.donnees dd { margin: 0; min-width: 0; overflow-wrap: break-word; }
.repli-liste { margin-top: 8px; }
.repli-liste > summary { cursor: pointer; font-size: 13px; font-weight: 550; color: var(--ink2); padding: 4px 0; }
.repli-liste > .lignes-dossier, .repli-liste > .compte-rendu-lu { margin-top: 6px; }
.deux-listes { display: grid; gap: 12px; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
.alerte-texte { color: var(--clay); font-weight: 600; }
.compte-rendu-lu { padding: 8px 0; border-top: 1px solid var(--line); font-size: 13px; }
/* Le formulaire d'une fenêtre, affiché dans sa section : mêmes champs, sans boîte. */
.edition-en-place { display: flex; flex-direction: column; gap: 8px; }
.edition-en-place > .corps { display: flex; flex-direction: column; gap: 8px; }
.edition-en-place > p.cl:empty { display: none; }
.edition-en-place > footer { display: flex; justify-content: flex-end; gap: 8px; flex-wrap: wrap;
                             padding-top: 8px; border-top: 1px solid var(--line); }
/* Les pièces : le nom en colonne fixe, comme les autres lignes du dossier — le champ
   caché placé avant lui empêchait la règle `:first-child` de s'appliquer. */
.section-fiche .lignes-dossier > form > .cl { width: 150px; flex-shrink: 0; }
.resultats-fiche { gap: 2px; }
.ligne-resultat { display: flex; gap: 12px; align-items: baseline; padding: 8px 10px; border-radius: 8px;
                  color: var(--ink); text-decoration: none; }
.ligne-resultat:hover { background: var(--survol); }

/* ------------------------------------------------- absences des tuteurs --
   Plan « absences-tuteur » (28/09). L'onglet « Mes absences » se remplit au
   téléphone : une colonne, des champs pleine largeur, rien qui déborde. */
.mes-absences { max-width: 640px; display: flex; flex-direction: column; gap: 22px; }
.formulaire-absence { display: flex; flex-direction: column; gap: 12px; background: var(--paper);
                      border: 1px solid var(--line); border-radius: 10px; padding: 14px; box-shadow: var(--ombre); }
.periode-absence { display: grid; gap: 12px; grid-template-columns: repeat(auto-fit, minmax(min(200px, 100%), 1fr)); }
.champ-absence { display: flex; flex-direction: column; gap: 4px; font-size: 13px; font-weight: 550; color: var(--ink2); min-width: 0; }
.champ-absence .cl { font-weight: 400; }
.formulaire-absence .note { margin: 0; }
.formulaire-absence .boutons { display: flex; justify-content: flex-end; }
.liste-absences { list-style: none; margin: 0; padding: 4px 14px; background: var(--paper);
                  border: 1px solid var(--line); border-radius: 10px; }
.absence-annoncee { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; padding: 10px 0;
                    border-top: 1px solid var(--filet-doux); }
.absence-annoncee:first-child { border-top: 0; }
.quand-absence { display: flex; flex-direction: column; gap: 2px; flex: 1 1 220px; min-width: 0; }
.motif-absence { font-size: 13px; color: var(--ink2); overflow-wrap: anywhere; }
.etat-absence { font-size: 12px; color: var(--clay); }
.etat-absence.vue { color: var(--vert); }
/* L'encart du tableau de bord : une ligne par absence, « Vu » au bout. */
.absences-tuteurs .titre-vue { margin: 0 0 6px; }
.absences-tuteurs ul { list-style: none; margin: 0; padding: 0; }
.absences-tuteurs li { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; padding: 6px 0;
                       border-top: 1px solid var(--filet-doux); font-size: 13px; }
.absences-tuteurs li:first-child { border-top: 0; }
.absences-tuteurs .qui-absent { flex: 1 1 240px; min-width: 0; overflow-wrap: anywhere; }
.absences-tuteurs .a-voir b { color: var(--clay); }

/* Le bandeau des prêts de tuteurs (plan « prêt-de-tuteur », 09/10) : en tête du
   tableau, une ligne par demande, ses gestes au bout. Cibles de 44 px partout, pas
   seulement au doigt : on y décide vite, entre deux élèves. */
.bandeau-prets ul { list-style: none; margin: 0; padding: 0; }
.bandeau-prets li { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; padding: 6px 0;
                    border-top: 1px solid var(--filet-doux); }
.bandeau-prets li:first-child { border-top: 0; }
.bandeau-prets .pret-texte { flex: 1 1 260px; min-width: 0; overflow-wrap: anywhere; }
.bandeau-prets .pret-gestes { display: flex; flex-wrap: wrap; gap: 8px; }
.bandeau-prets button, .gestes-pret button { min-height: 44px; min-width: 44px; }
.gestes-pret { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px;
               margin-top: 6px; font-size: 13px; }

/* Le raccourci « A » du pointage (critique du 25/09) : montré seulement là où un
   clavier est probable — souris et grand écran. Au doigt, il ne dirait rien. */
.raccourci { display: none; margin-left: 8px; padding: 0 5px; border-radius: 5px;
             border: 1px solid color-mix(in srgb, currentColor 45%, transparent);
             font-family: inherit; font-size: 12px; font-weight: 600; line-height: 16px; opacity: .8; }
@media (hover: hover) and (pointer: fine) and (min-width: 1101px) {
  .raccourci { display: inline-block; }
}

/* ------------------------------------------ tablette (plan « ergonomie-5 ») --
   Inventaire du 07/10, § 13 : lu debout, à bout de bras, tout ce qui qualifie un
   élève — classe, heure prévue, retard, matière en cours, durée — était à 12 px.
   Au doigt, un plancher de 13 px. Les sélecteurs reprennent ceux qui posent les
   12 px (même spécificité, plus loin dans le fichier). La grille des cours
   particuliers garde les siens : ses cases sont comptées à la demi-heure. */
@media (pointer: coarse) {
  .cl, .lignes-dossier .cl, .suite-bornes .cl, .raison-grise,
  .rang .bloc-nom .sous, .rang .dur, .attente .detail,
  .ligne-attendu .quand, .ligne-attendu > .retard { font-size: 13px; }
}
/* § 1 : à 768 px en portrait, le pôle du superviseur n'avait que la moitié de
   l'écran — la pondération 1,65 / 1 ne vaut qu'au-dessus de 900 px. Entre 701 et
   900 px, le sien prend toute la largeur et passe en premier ; l'autre, en lecture,
   vient dessous (et se replie sur le côté, comme ailleurs, si on le demande). */
@media (min-width: 701px) and (max-width: 900px) {
  .poles:has(.pole.actif):not(.un-replie) { grid-template-columns: minmax(0, 1fr); }
  .poles:has(.pole.actif):not(.un-replie) .pole.actif { order: -1; }
}

/* ------------------------------------------------------- cibles tactiles --
   DESIGN.md s'engage : « Do porter les cibles tactiles vers 44 px sous 1100 px. »
   Seules quatre classes de boutons étaient majorées, aucune n'atteignait 44 px, et
   les cibles les PLUS utilisées ne l'étaient pas du tout : le nom de l'élève, qui
   est le chemin normal vers sa fiche, faisait 18 px de haut sur une tablette, et
   les dépliants du compte rendu — la tâche principale du tuteur sur son téléphone —
   32 px. Ce bloc est le dernier du fichier : il passe donc après les règles de
   détail qui, à spécificité égale, gagnaient auparavant.

   Lot 4 (critique du 23/09) : le bloc s'applique aussi à tout écran tenu au
   doigt (`pointer: coarse`), quelle que soit sa largeur — une tablette de 1180
   ou 1366 px n'avait aucune cible majorée. La largeur reste : une fenêtre
   étroite à la souris n'y perd rien. */
@media (max-width: 1100px), (pointer: coarse) {
  .mini, .puce, .primaire, .secondaire, .puce-tuteur, .bascule, .bascule-rail,
  .role, .onglet, .choix, .champ, select.champ, .recherche, .recherche input,
  .cases-types label, .categorie label { min-height: 44px; }
  /* Les cibles en ligne dans un texte : la hauteur seule ne suffit pas, il faut
     que la zone cliquable la remplisse. */
  .nom, .nom-lien, .lien-discret, .bascule {
    min-height: 44px; display: inline-flex; align-items: center;
  }
  /* La photo d'un élève ouvre son agrandissement : c'est une cible comme une
     autre, et elle ne fait que 28 px. Ici la rangée qui la porte est déjà
     majorée (`.rang`, `.ligne-attendu`, `.ligne-eleve`, et `.nom` à côté d'elle), donc
     28 × 44 ne déplace rien (relecture du 20/09, m4). */
  .loupe-photo { min-height: 44px; }
  /* Le nom d'un élève peut tenir sur trois lignes : la boîte grandit avec lui. */
  .nom { align-items: center; }
  .ligne-seance .nom { display: inline-flex; }
  /* Un rang dense reste lisible, mais chaque ligne devient atteignable au doigt. */
  .rang, .ligne-tuteur, .ligne-attendu { min-height: 44px; }
  /* Les cartes de « Toute l'équipe » (28/09) : un peu plus d'air entre elles, pour
     qu'un doigt vise la bonne ; le nom et « Absences » sont déjà majorés ci-dessus. */
  .cartes-equipe { gap: 14px; }
  .carte-tuteur { padding: 12px 14px 14px; }
  /* `summary` garde son triangle : on l'épaissit par le remplissage, pas par
     `display`, qui l'effacerait. */
  summary,
  .autre-prestation > summary, .prestations-vacances > summary,
  .envoi-autre-pole > summary { padding: 12px 0; }
  /* Les cases du pointage en lot (critique du 23/09). */
  .case-lot { inline-size: 26px; block-size: 26px; }
  /* Les trois cibles restées sous 44 px (critique du 23/09) : les flèches de
     période de « Séances » (28 px de large) et le lien « Inscrire un tuteur du
     jour » (37 px de haut). */
  .fleche-periode { min-width: 44px; justify-content: center; }
  /* Un lien dans un encart (« Inscrire un tuteur du jour », « Ouvrir sa feuille ») :
     cible majorée, allure inchangée (relecture du lot 4, m4). */
  .encart a { display: inline-flex; align-items: center; min-height: 44px; }
  /* Le menu réduit (par défaut sur tablette) fixait 40 × 36 px à ses cibles, et sa
     spécificité battait le plancher ci-dessus (relecture du lot 4, M1). */
  .rail-reduit .onglet, .rail-reduit .role, .rail-reduit .bascule-rail { width: 44px; height: 44px; }
  /* La poignée du glisser et les puces de tuteur, déjà majorées à la largeur. */
  [data-glisser="venue"] .poignee { padding: 10px 6px; margin: -10px -4px; }
  .puce-tuteur { padding: 10px 14px; }
  /* Le message reste jusqu'au geste suivant : sa croix et son « Annuler » se
     touchent au doigt (relecture du 25/09, m9). */
  .message .message-geste, .message .message-fermer { min-height: 44px; min-width: 44px; }
  /* La case « Proposée » d'une ligne de Catalogues (plan du 28/09) : l'étiquette qui
     l'entoure devient la cible, la case seule faisait 13 px. */
  .table-catalogue label.note { min-height: 44px; display: inline-flex; align-items: center; gap: 6px; }
}

/* ---------------------------------------------- le mode sélection (09/10) --
   Déplacement groupé : « Sélectionner » fait de chaque élève de son pôle une case.
   L'état choisi se lit sans la couleur : la coche apparaît dans la case, la carte
   est cernée, et `aria-pressed` le dit au lecteur d'écran. Cibles de 44 px : la
   tablette, debout. Les boutons de la carte (Départ, Affecter, Annuler l'arrivée)
   et la poignée se retirent le temps du mode : aucun toucher n'y écrit par surprise. */
.coche-selection { display: none; }
.bouton-selection[aria-pressed="true"] { background: var(--puce-active-fond); color: var(--puce-active-texte);
                                         border-color: var(--puce-active-bord); }
.mode-selection [data-selectionnable] { cursor: pointer; }
.mode-selection .coche-selection { display: inline-flex; align-items: center; justify-content: center; flex: none;
                                   width: 44px; height: 44px; padding: 0; border: 2px solid var(--bord-champ);
                                   border-radius: 10px; background: var(--paper); color: transparent; cursor: pointer; }
.mode-selection .coche-selection .icone-bouton { width: 24px; height: 24px; stroke-width: 2.5; }
.mode-selection .coche-selection[aria-pressed="true"] { background: var(--lagoon); border-color: var(--lagoon);
                                                        color: var(--sur-accent); }
.mode-selection .coche-selection:focus-visible { outline: 2px solid var(--lagoon); outline-offset: 2px; }
.mode-selection [data-selectionnable].choisi { box-shadow: 0 0 0 2px var(--lagoon); background: var(--lagoon-soft); }
.mode-selection .rang[data-selectionnable] { min-height: 48px; border-radius: 8px; padding: 2px 4px; }
.mode-selection [data-selectionnable] .poignee, .mode-selection [data-selectionnable] .boutons,
.mode-selection [data-selectionnable] .depart-rang, .mode-selection [data-selectionnable] .lien-discret { display: none; }
.barre-selection { position: fixed; left: 50%; bottom: 0; transform: translateX(-50%); z-index: 55;
                   width: min(640px, 100vw); display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
                   background: var(--paper); border: 1px solid var(--line-forte); border-bottom: 0;
                   border-radius: 12px 12px 0 0; box-shadow: var(--ombre-haute);
                   padding: 10px 16px calc(10px + env(safe-area-inset-bottom, 0px)); }
.barre-selection[hidden] { display: none; }
.barre-selection .compte-selection { flex: 1 1 12em; font-weight: 650; font-variant-numeric: tabular-nums; }
.barre-selection button { min-height: 44px; }
/* La barre ne couvre ni le message, ni les dernières cartes. */
.mode-selection .message { bottom: 96px; }
.mode-selection .app { padding-bottom: 96px; }
/* La fenêtre groupée : une ligne par élève, ses matières dessous. */
.groupe-choisi { list-style: none; margin: 0 0 12px; padding: 0; display: grid; gap: 4px; }
.eleve-groupe { border: 1px solid var(--line); border-radius: 10px; padding: 10px 12px; margin: 10px 0 0; }
.eleve-groupe legend { padding: 0 4px; }
.rectification-groupe { display: grid; gap: 4px; margin-bottom: 8px; }
.rectification-groupe label { display: flex; align-items: center; gap: 8px; min-height: 44px; }
.autres-matieres-groupe summary { cursor: pointer; min-height: 44px; display: flex; align-items: center; color: var(--ink2); }
