/* Gestion École — design system : doux, rond, un peu ludique. */
:root {
    --primary: #6d5efc;
    --primary-dark: #5747e0;
    --primary-soft: #efecff;
    /* Second arrêt du dégradé des boutons + teinte de leur ombre. Déclinés par
       thème (cf. html[data-theme="itschool"]) pour que le dégradé suive --primary. */
    --primary-lift: #8b7dff;
    --primary-shadow: rgba(109, 94, 252, .30);
    --accent: #ff8a5c;
    /* Couleur de marque iT.SCHOOL (éditeur) — utilisée en ACCENT (logo, liens,
       petits détails). Le violet reste la couleur PRINCIPALE du produit. */
    --brand: #0189d9;
    --brand-dark: #0171b5;
    --brand-soft: #e6f4fc;
    --ink: #1f2440;
    --muted: #8a90a8;
    --line: #ecedf4;
    --bg: #f6f7fb;
    --card: #ffffff;
    --ok: #1a9f63;
    --shadow: 0 10px 30px -12px rgba(45, 40, 90, .18);
    --radius: 18px;
    --radius-sm: 12px;
    --danger: #e5484d;
    --danger-soft: #fdecec;
    --warn: #f5a524;
    /* Couleurs sémantiques des icônes d'action (au repos) */
    --c-edit: #6d5efc; --c-view: #0189d9; --c-add: #1f9d63; --c-fav: #f2b705;
    --c-flag: #ef6c3b; --c-pin: #7c5cff; --c-reply: #0ea5a5; --c-set: #64748b;
}

/* === Thème iT.SCHOOL (bleu) — activé via <html data-theme="itschool"> ===========
   Réglable par le super-admin (console ▸ Apparence). Le thème « standard » (violet)
   = valeurs :root par défaut. On ne surcharge que le « mauve » : la couleur
   principale (--primary*) + les dégradés violets codés en dur. */
html[data-theme="itschool"] {
    --primary: #0189d9;
    --primary-dark: #0171b5;
    --primary-soft: #e6f4fc;
    --primary-lift: #22c1d6;
    --primary-shadow: rgba(1, 137, 217, .30);
}
html[data-theme="itschool"] .space-ecole,
html[data-theme="itschool"] .space-head.is-ecole .sh-ico {
    background: linear-gradient(135deg, #0189d9 0%, #38aae6 55%, #8fd2f3 100%);
}
html[data-theme="itschool"] .ap-hello {
    background: linear-gradient(135deg, #0189d9 0%, #3aabe7 100%);
    box-shadow: 0 14px 30px -16px rgba(28, 157, 215, .7);
}
html[data-theme="itschool"] .auth {
    background:
        radial-gradient(1200px 600px at 10% -10%, #d2ecfa 0%, transparent 55%),
        radial-gradient(900px 500px at 110% 110%, #e1f3fc 0%, transparent 50%),
        var(--bg);
}

* { box-sizing: border-box; }

body {
    margin: 0;
    font-family: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
    color: var(--ink);
    background: var(--bg);
    line-height: 1.55;
    -webkit-font-smoothing: antialiased;
}

/* Convention : toute page connectée tient dans la fenêtre — pas de scroll de PAGE,
   le défilement vit DANS la zone de travail (.content) ou la zone interne d'un module.
   (sauf avis contraire ; mobile <900px : on relâche pour rester confortable.) */
body.app-fit { height: 100dvh; display: flex; flex-direction: column; overflow: hidden; }
body.app-fit > .topbar { flex: none; }
@media (max-width: 900px) { body.app-fit { height: auto; overflow: visible; } }

h1, h2, h3, .brand { font-family: "Baloo 2", "Inter", system-ui, sans-serif; }
a { color: inherit; }

/* ---------- Auth / login ---------- */
.auth {
    /* ⚠️ `dvh` et non `vh` : sur mobile, `100vh` vaut la hauteur écran BARRE D'URL RÉTRACTÉE, donc
       plus que le visible. Combiné au clavier virtuel, le bas du formulaire passe sous le pli. */
    min-height: 100dvh;
    display: grid;
    /* ⚠️⚠️ `minmax(0, 1fr)` EST LE CORRECTIF, et il n'est pas décoratif. Sans lui, la colonne
       implicite est en `auto`, donc dimensionnée sur le MAX-CONTENT de la carte : mesuré à 376 px
       là où le conteneur n'en offre que 342 (390 d'écran − 2 × 24 de marge). La page devenait plus
       large que le téléphone (400 px pour 390), la carte était rognée à droite — dates, pastilles,
       case à cocher — et le doigt qui voulait faire défiler partait de travers. `minmax(0, 1fr)`
       borne la piste à l'espace réel : la carte suit, et `max-width` ne joue plus que sur grand
       écran. Débordement classique de CSS Grid ; mesuré au navigateur, pas déduit. */
    grid-template-columns: minmax(0, 1fr);
    padding: 1.5rem;
    background:
        radial-gradient(1200px 600px at 10% -10%, #d8d2ff 0%, transparent 55%),
        radial-gradient(900px 500px at 110% 110%, #ffd9c7 0%, transparent 50%),
        var(--bg);
}
/* ⚠️⚠️ Centrage par marges AUTO, jamais par `place-items: center`. Une marge `auto` ne peut pas
   devenir négative : dès que l'enfant est plus haut que le conteneur, elle retombe à zéro et
   l'élément se cale au DÉBUT — son haut reste donc atteignable, dans TOUS les moteurs. Un
   `align-items: center`, lui, déborde des deux côtés, et ce qui passe au-dessus de l'origine de
   défilement n'est plus joignable sur certains moteurs. Même rendu quand il y a de la place. */
.auth > * { margin: auto; }
.auth-card {
    width: 100%;
    max-width: 400px;
    background: var(--card);
    border-radius: 24px;
    box-shadow: var(--shadow);
    padding: 2.4rem 2.2rem;
}
.auth-logo {
    width: 64px; height: 64px;
    display: grid; place-items: center;
    font-size: 2rem;
    border-radius: 20px;
    background: var(--primary-soft);
    margin-bottom: 1.1rem;
}
/* Logo officiel iT.SCHOOL Educa+ sur la page de connexion. */
.auth-logo-img { display: block; width: 100%; max-width: 360px; height: auto; margin: -.4rem auto 1.2rem; }
.auth-card h1 { margin: 0 0 .2rem; font-size: 1.6rem; }

/* Sélecteur de mode de connexion (iT.SCHOOL / compte local). Réutilise le contrôle segmenté
   du projet ; ses éléments sont ici des LIENS — d'où le retrait du soulignement et le
   centrage, que `.seg-btn` ne prévoit pas puisqu'il est écrit pour des <button>. */
.auth-seg { display: flex; width: 100%; margin: 0 0 1.4rem; }
.auth-seg .seg-btn { flex: 1; text-align: center; text-decoration: none; padding: .45rem .75rem; }
.auth-aparte { margin: 1rem 0 0; text-align: center; font-size: .85rem; }

.auth-card .sub { color: var(--muted); margin: 0 0 1.6rem; }

.field { margin-bottom: 1rem; }
.field label { display: block; font-size: .85rem; font-weight: 600; color: var(--muted); margin-bottom: .35rem; }
.input {
    width: 100%;
    padding: .8rem 1rem;
    border: 1.5px solid var(--line);
    border-radius: var(--radius-sm);
    font-size: 1rem;
    background: #fcfcff;
    transition: border-color .15s, box-shadow .15s;
}
.input:focus {
    outline: none;
    border-color: var(--primary);
    box-shadow: 0 0 0 4px var(--primary-soft);
}
/* Champ visible flatpickr (altInput) : compact, aligné sur les champs de formulaire. */
.fp-input {
    width: 100%;
    box-sizing: border-box;
    padding: .4rem .55rem;
    font-size: .9rem;
    line-height: 1.3;
    border: 1px solid var(--line, #e2e8f0);
    border-radius: 8px;
    background: #fff;
}
.fp-input:focus {
    outline: none;
    border-color: var(--primary);
    box-shadow: 0 0 0 3px var(--primary-soft);
}

/* ── LE CALENDRIER DE L'APPLICATION ──────────────────────────────────────────
   flatpickr arrive avec son propre style, bleu et anguleux, qui ne ressemble à aucun autre écran
   d'ici. On l'habille : la couleur du produit (qui change avec l'environnement — prod bleu, staging
   violet), les arrondis et l'ombre des cartes, la police du reste.
   ⚠️ `--primary` est une variable de thème : le calendrier suit l'environnement sans le savoir. */
.flatpickr-calendar {
    font-family: inherit;
    border-radius: var(--radius, 14px);
    border: 1px solid var(--line);
    box-shadow: 0 12px 32px rgba(20, 20, 60, .16);
    padding-bottom: .25rem;
}
.flatpickr-calendar.arrowTop::before, .flatpickr-calendar.arrowTop::after,
.flatpickr-calendar.arrowBottom::before, .flatpickr-calendar.arrowBottom::after { display: none; }
.flatpickr-months { padding: .35rem 0 .1rem; }
.flatpickr-months .flatpickr-month { color: var(--ink); }
.flatpickr-current-month { font-size: .98rem; font-weight: 700; }
.flatpickr-current-month .flatpickr-monthDropdown-months { font-weight: 700; border-radius: 8px; }
.flatpickr-months .flatpickr-prev-month:hover svg,
.flatpickr-months .flatpickr-next-month:hover svg { fill: var(--primary); }
.flatpickr-weekday { font-size: .78rem; font-weight: 700; color: var(--muted); text-transform: lowercase; }
.flatpickr-day { border-radius: 10px; font-size: .9rem; color: var(--ink); }
.flatpickr-day:hover { background: var(--primary-soft); border-color: transparent; }
/* ⚠️ Le jour CHOISI porte la couleur pleine, celui d'AUJOURD'HUI un simple cerclage : deux repères
   différents, qu'un même aplat rendrait impossibles à distinguer. */
.flatpickr-day.selected, .flatpickr-day.selected:hover {
    background: var(--primary); border-color: var(--primary); color: #fff; font-weight: 700;
}
.flatpickr-day.today { border-color: var(--primary); }
.flatpickr-day.today:hover { background: var(--primary-soft); color: var(--ink); }
.flatpickr-day.flatpickr-disabled, .flatpickr-day.prevMonthDay, .flatpickr-day.nextMonthDay { color: var(--muted); opacity: .55; }
.flatpickr-day.flatpickr-disabled { text-decoration: line-through; }

/* ── Boutons d'action ────────────────────────────────────────────────────────
   Système unique, calqué sur .jv-verif (« Vérifier et valider ») : dégradé à 135°,
   ombre TEINTÉE de la couleur du bouton, 700 à .85rem, rayon 10, léger soulèvement
   au survol. La couleur est SÉMANTIQUE — elle dit ce que fait le bouton :
     .btn            violet  action principale (Ajouter, Créer, Lancer)
     .btn-ok         vert    confirmer (Valider, Enregistrer)
     .btn-info       bleu    consulter / naviguer (Ouvrir, Entrer)
     .btn-danger     rouge   détruire (Supprimer, Retirer, Purger)
     .btn-ghost      pâle    action secondaire, sans dégradé
   Tailles : .sm (ligne de tableau) · défaut · .lg (barre d'enregistrement).
   Largeur : `auto` — un bouton fait la taille de son libellé. Le pleine-largeur
   est désormais EXPLICITE via .btn-block (formulaires de connexion, où le bouton
   est l'action unique d'une carte étroite). L'ancien défaut `width:100%` obligeait
   à l'annuler dans 27 règles CSS et 32 attributs style= : tous supprimés. */
.btn {
    display: inline-flex; align-items: center; justify-content: center; gap: .4rem;
    width: auto;
    padding: .52rem 1rem;
    border: 0;
    border-radius: 10px;
    background: linear-gradient(135deg, var(--btn-a), var(--btn-b));
    color: #fff;
    font-family: inherit;
    font-size: .88rem;
    font-weight: 700;
    line-height: 1.3;
    text-decoration: none;
    cursor: pointer;
    box-shadow: 0 2px 6px var(--btn-sh);
    transition: transform .12s, box-shadow .12s, filter .12s;
    --btn-a: var(--primary); --btn-b: var(--primary-lift); --btn-sh: var(--primary-shadow);
}
.btn:hover { transform: translateY(-1px); box-shadow: 0 5px 14px var(--btn-sh); color: #fff; filter: saturate(1.06); }
.btn:active { transform: translateY(0); }
.btn:focus-visible { outline: 2px solid var(--primary-dark); outline-offset: 2px; }
.btn[disabled], .btn.is-disabled { opacity: .5; cursor: not-allowed; transform: none; box-shadow: none; filter: grayscale(.4); }
.btn svg { width: 1.05em; height: 1.05em; }
/* Variantes sémantiques */
.btn-ok     { --btn-a: #16a34a; --btn-b: #0ea5a4; --btn-sh: rgba(16, 163, 74, .30); }
.btn-info   { --btn-a: #0189d9; --btn-b: #22c1d6; --btn-sh: rgba(1, 137, 217, .30); }
/* Neutre : action tertiaire type « Annuler », qui ne doit rien revendiquer.
   Comble un vrai manque — trois classes locales (pj-btn-cancel, pj-btn-ann,
   btn-light) le réinventaient chacune à leur façon. */
.btn-quiet  { background: var(--card); color: var(--ink); border: 1px solid var(--line); box-shadow: none; }
.btn-quiet:hover { background: var(--bg); border-color: var(--primary); color: var(--primary-dark); box-shadow: none; filter: none; }
/* Tailles */
.btn.lg { padding: .72rem 1.5rem; font-size: 1rem; border-radius: 12px; }
/* Pleine largeur EXPLICITE : action unique d'une carte étroite (connexion,
   définition de mot de passe). Remplace l'ancien width:100% implicite. */
.btn-block { width: 100%; }
.btn:active { transform: scale(.98); }
/* Bouton compact (ex. Enregistrer d'une fiche) : petit, largeur au contenu. */
.btn.sm { padding: .36rem .78rem; font-size: .8rem; border-radius: 8px; gap: .3rem; }
/* Secondaire : pas de dégradé ni d'ombre portée au repos — il ne doit jamais
   rivaliser avec l'action principale posée à côté. */
.btn-ghost { background: var(--primary-soft); color: var(--primary-dark); box-shadow: none; }
.btn-ghost:hover { background: #e4e0ff; color: var(--primary-dark); box-shadow: 0 3px 10px var(--primary-shadow); filter: none; }

.alert {
    background: #fff0ec;
    color: #c0431f;
    border: 1px solid #ffd9cd;
    padding: .7rem .9rem;
    border-radius: var(--radius-sm);
    font-size: .9rem;
    margin-bottom: 1rem;
}

/* Bannière d'information/attention INLINE : persistante et pleine largeur du
   conteneur (à NE PAS confondre avec les toasts .flash, fixes et éphémères). */
.banner {
    display: flex; align-items: flex-start; gap: .5rem;
    width: 100%; padding: .8rem 1.1rem; margin-bottom: 1.1rem;
    border-radius: var(--radius-sm);
    font-size: .9rem; font-weight: 500; line-height: 1.45;
}
.banner-warn { background: #fefce8; color: #854d0e; border: 1px solid #fde68a; }
.banner-info { background: #eff6ff; color: #1e40af; border: 1px solid #bfdbfe; }
.banner-ok   { background: #e6f7ee; color: #157a4b; border: 1px solid #b7ebcd; }
.banner a { color: inherit; text-decoration: underline; font-weight: 600; }

/* Navigation de jour compacte (pill) : ‹ [date] › + Aujourd'hui. */
.pr-daynav { display: inline-flex; align-items: center; gap: .1rem; background: var(--card, #fff); border: 1px solid var(--line, #e2e8f0); border-radius: 999px; padding: .15rem .3rem; }
.pr-daynav .dn-arrow { width: 30px; height: 30px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; color: var(--muted); text-decoration: none; font-size: 1.25rem; line-height: 1; font-weight: 700; }
.pr-daynav .dn-arrow:hover { background: var(--bg, #f1f5f9); color: var(--ink, #0f172a); }
.pr-daynav .dn-date { border: none; background: transparent; font-weight: 600; font-size: .88rem; color: var(--ink, #0f172a); padding: .2rem .25rem; cursor: pointer; width: auto; }
.pr-daynav .dn-date::-webkit-calendar-picker-indicator { opacity: .5; cursor: pointer; }
.pr-daynav .dn-today { font-size: .8rem; color: var(--brand, #0189d9); text-decoration: none; font-weight: 600; padding: 0 .4rem 0 .2rem; }
.pr-daynav .dn-today:hover { text-decoration: underline; }

/* ---------- App shell ---------- */
.app { display: flex; height: 100vh; overflow: hidden; }

.sidebar {
    width: 250px;
    flex-shrink: 0;
    background: var(--card);
    border-right: 1px solid var(--line);
    padding: 1.3rem 1rem;
    display: flex;
    flex-direction: column;
    gap: .3rem;
    position: relative;
}

/* Onglet flèche : épingle / replie la barre (toujours visible). */
.sidebar-pin {
    position: absolute; top: 64px; right: -13px; z-index: 5;
    width: 26px; height: 44px; padding: 0; cursor: pointer;
    border: 1px solid var(--line); border-left: none;
    background: var(--card); color: var(--primary-dark);
    border-radius: 0 12px 12px 0; box-shadow: 2px 0 6px rgba(0,0,0,.06);
    display: flex; align-items: center; justify-content: center;
}
.sidebar-pin:hover { background: var(--primary-soft); }
.sidebar-pin-ico { font-size: 1.3rem; line-height: 1; font-weight: 700; transition: transform .18s ease; }
.app.sidebar-pinned .sidebar-pin-ico { transform: rotate(180deg); }
.brand {
    display: flex; align-items: center; gap: .6rem;
    font-size: 1.25rem; font-weight: 700;
    padding: .3rem .5rem 1.1rem;
}
.brand .logo {
    width: 38px; height: 38px; border-radius: 12px;
    display: grid; place-items: center; font-size: 1.2rem;
    background: var(--primary-soft);
}
/* Logo iT.SCHOOL Educa+ (fichier officiel) dans la topbar. */
.topbar .brand { padding: 0; }
.brand-logo { height: 64px; width: auto; display: block; }

.nav-group-label {
    font-size: .72rem; text-transform: uppercase; letter-spacing: .06em;
    color: var(--muted); font-weight: 700;
    padding: .9rem .8rem .3rem;
}
.nav-item {
    display: flex; align-items: center; gap: .7rem;
    padding: .65rem .8rem;
    border-radius: var(--radius-sm);
    text-decoration: none;
    color: var(--ink);
    font-weight: 600;
    font-size: .95rem;
    transition: background .12s;
}
.nav-item .ico { font-size: 1.1rem; width: 1.4rem; text-align: center; }
.nav-item:hover { background: var(--bg); }
.nav-item.active { background: var(--primary-soft); color: var(--primary-dark); }
.nav-sub { margin-left: .6rem; padding-left: .6rem; border-left: 2px solid var(--line); }

.sidebar-footer { margin-top: auto; }

/* ---------- Main ---------- */
.main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.topbar {
    display: flex; align-items: center; justify-content: space-between;
    padding: .55rem 1.6rem;
    background: var(--card);
    border-bottom: 2px solid var(--brand);   /* fine signature de marque iT.SCHOOL */
}
.topbar .hello { font-weight: 600; }
.topbar .hello span { color: var(--muted); font-weight: 500; }

/* Bouton de retour rapide à l'accueil, présent en haut de chaque page. */
.home-pill {
    display: inline-flex; align-items: center; gap: .4rem;
    padding: .5rem .9rem; border-radius: 999px;
    background: var(--primary-soft); color: var(--primary-dark);
    font-weight: 700; font-size: .9rem; text-decoration: none;
    white-space: nowrap; flex-shrink: 0;
    transition: background .15s ease, color .15s ease, transform .15s ease;
}
.home-pill:hover { background: var(--primary); color: #fff; transform: translateY(-1px); }

/* L'agenda en un clic (topbar) : une mini page de calendrier à la date du jour, sur le dégradé des
   boutons du thème — elle suit donc la couleur de l'environnement. */
.agenda-pill {
    display: inline-flex; align-items: center; gap: .5rem; flex-shrink: 0;
    padding: .28rem .9rem .28rem .32rem; border-radius: 999px;
    background: linear-gradient(135deg, var(--primary), var(--primary-lift)); color: #fff;
    font-weight: 800; font-size: .9rem; text-decoration: none; white-space: nowrap;
    box-shadow: 0 4px 12px var(--primary-shadow);
    transition: transform .15s ease, box-shadow .15s ease;
}
.agenda-pill:hover { transform: translateY(-1px); box-shadow: 0 6px 18px var(--primary-shadow); }
.agenda-pill:focus-visible { outline: 3px solid var(--primary-soft); outline-offset: 2px; }
.agenda-pill.is-active { box-shadow: 0 0 0 3px var(--primary-soft), 0 4px 12px var(--primary-shadow); }
.agenda-pill-cal {
    display: grid; grid-template-rows: auto 1fr; width: 2rem; height: 2.05rem; overflow: hidden;
    border-radius: 7px; background: #fff; box-shadow: 0 1px 3px rgba(0, 0, 0, .18); text-align: center;
}
.agenda-pill-mois { background: var(--accent); color: #fff; font-size: .52rem; font-weight: 800; letter-spacing: .06em;
    text-transform: uppercase; line-height: 1.5; }
.agenda-pill-jour { display: grid; place-items: center; color: var(--primary-dark); font-size: .98rem; font-weight: 900; line-height: 1; }
@media (max-width: 640px) {
    .agenda-pill { padding: .28rem; }
    .agenda-pill-lib { display: none; }
}

/* Sélecteur d'année scolaire (topbar) = contexte de navigation global.
   Pilule cohérente avec .home-pill ; l'option sélectionnée = l'année active. */
/* Sélecteur d'année (topbar) : menu maison façon <details>, comme le menu utilisateur. */
.annee-menu { position: relative; flex-shrink: 0; }
.annee-menu > summary { list-style: none; }
.annee-menu > summary::-webkit-details-marker { display: none; }
.annee-pill {
    display: inline-flex; align-items: center; gap: .4rem;
    padding: .35rem .7rem; border-radius: 999px; cursor: pointer;
    background: var(--primary-soft); color: var(--primary-dark);
    font-weight: 700; font-size: .9rem; white-space: nowrap;
    transition: background .13s;
}
.annee-pill:hover { background: #e4e0ff; }
.annee-menu > summary:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; border-radius: 999px; }
.annee-caret { width: 15px; height: 15px; opacity: .7; transition: transform .15s; }
.annee-menu[open] .annee-caret { transform: rotate(180deg); }
.annee-list {
    position: absolute; right: 0; top: calc(100% + .5rem); z-index: 80;
    min-width: 200px; background: var(--card); border: 1px solid var(--line);
    border-radius: 14px; box-shadow: 0 16px 42px rgba(20, 20, 60, .18); overflow: hidden; padding: .3rem;
}
.annee-item {
    display: flex; align-items: center; justify-content: space-between; gap: .8rem;
    padding: .5rem .7rem; border-radius: 9px; color: var(--ink); text-decoration: none; font-weight: 600;
}
.annee-item:hover, .annee-item.is-active { background: var(--primary-soft); color: var(--primary-dark); }
.annee-star { width: 15px; height: 15px; color: var(--c-fav); flex-shrink: 0; }

/* Sélecteur de PÉRIMÈTRE (école ▸ implantations) — calqué sur .annee-menu.
   Radios = bascule d'école (contexte) ; cases = filtre implantations (dans l'école active). */
.scope-menu { position: relative; flex-shrink: 0; }
.scope-menu > summary { list-style: none; }
.scope-menu > summary::-webkit-details-marker { display: none; }
.scope-pill {
    display: inline-flex; align-items: center; gap: .4rem;
    padding: .3rem .6rem .3rem .55rem; border-radius: 999px; cursor: pointer;
    background: var(--primary-soft); color: var(--primary-dark);
    font-weight: 700; font-size: .9rem; white-space: nowrap; transition: background .13s;
}
.scope-pill:hover { background: #e4e0ff; }
.scope-menu > summary:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; border-radius: 999px; }
.scope-ecole-cur { max-width: 13rem; overflow: hidden; text-overflow: ellipsis; }
.scope-sep { opacity: .5; }
.scope-caret { width: 15px; height: 15px; opacity: .7; transition: transform .15s; }
.scope-menu[open] .scope-caret { transform: rotate(180deg); }
.scope-pop {
    position: absolute; right: 0; top: calc(100% + .5rem); z-index: 80;
    min-width: 260px; background: var(--card); border: 1px solid var(--line);
    border-radius: 14px; box-shadow: 0 16px 42px rgba(20, 20, 60, .18); padding: .4rem;
}
.scope-ecoles { display: flex; flex-direction: column; gap: .1rem; }
.scope-centre { margin: .3rem .5rem .1rem; font-size: .72rem; font-weight: 700; letter-spacing: .03em; text-transform: uppercase; color: var(--muted); }
.scope-ecole {
    display: flex; align-items: center; gap: .55rem;
    padding: .5rem .6rem; border-radius: 9px; color: var(--ink); text-decoration: none; font-weight: 600;
}
.scope-ecole:hover { background: var(--primary-soft); }
.scope-ecole.is-active { background: var(--primary-soft); color: var(--primary-dark); }
.scope-radio { width: 16px; height: 16px; border-radius: 50%; border: 2px solid var(--muted); flex-shrink: 0; position: relative; }
.scope-ecole.is-active .scope-radio, .scope-radio.on { border-color: var(--primary); }
.scope-radio.on::after { content: ""; position: absolute; inset: 3px; border-radius: 50%; background: var(--primary); }
.scope-ecole-lib { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.scope-div { height: 1px; background: var(--line); margin: .4rem .2rem; }

/* Filtre implantations (dans le menu périmètre) : cases + Appliquer. */
.impl-list { display: flex; flex-direction: column; gap: .15rem; }
.impl-item {
    display: flex; align-items: center; gap: .6rem;
    padding: .45rem .55rem; border-radius: 9px; color: var(--ink); font-weight: 600; cursor: pointer;
}
.impl-item:hover { background: var(--primary-soft); }
.impl-item input { accent-color: var(--primary); width: 16px; height: 16px; flex-shrink: 0; }
.impl-item-lib { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.impl-apply { width: auto; margin-top: .35rem; align-self: stretch; }

/* Bandeau « brouillon retrouvé » (filet de sécurité de saisie). */
.draft-bar {
    display: flex; align-items: center; gap: .6rem; flex-wrap: wrap;
    background: #fff7ed; border: 1px solid #fed7aa; color: #9a3412;
    padding: .6rem .9rem; border-radius: 12px; margin-bottom: 1rem; font-size: .9rem;
}
.draft-bar button {
    border: none; border-radius: 8px; padding: .35rem .8rem; font-weight: 700;
    cursor: pointer; background: var(--primary); color: #fff; font-size: .85rem;
}
.draft-bar button.ghost { background: transparent; color: #9a3412; text-decoration: underline; padding: .35rem .4rem; }
.userchip { display: flex; align-items: center; gap: .6rem; }

.avatar {
    width: 38px; height: 38px; border-radius: 50%;
    display: grid; place-items: center;
    font-weight: 700; font-size: .85rem; color: #fff;
    flex-shrink: 0;
}
.avatar.sm { width: 32px; height: 32px; font-size: .75rem; }

/* Pastille d'implantation (convention) : acronyme sur la couleur choisie.
   Léger ombrage du texte pour rester lisible même sur une couleur claire. */
.avatar.pastille-impl { font-size: .72rem; letter-spacing: .02em; text-shadow: 0 1px 2px rgba(0, 0, 0, .28); }
.avatar.pastille-impl.sm { font-size: .62rem; }
/* Chip d'implantation « bouton » (moins rond que la pastille) — colonnes Implantation des grids. */
.pastille-btn {
    display: inline-flex; align-items: center; justify-content: center;
    padding: .22rem .5rem; border-radius: 8px;
    background: var(--primary); color: #fff;
    font-weight: 700; font-size: .72rem; letter-spacing: .02em; line-height: 1;
    text-shadow: 0 1px 2px rgba(0, 0, 0, .28); white-space: nowrap;
}
.pastille-btn.sm { padding: .16rem .42rem; font-size: .66rem; border-radius: 7px; }

/* Avatar SVG génératif : occupe le même gabarit que la pastille d'initiales. */
.avatar.avatar-svg { padding: 0; background: transparent; overflow: hidden; }
.avatar.avatar-svg svg { display: block; width: 100%; height: 100%; }

/* Nom de membre = pastille d'initiales + nom (dans le tableau du personnel). */
.member-name { display: inline-flex; align-items: center; gap: .6rem; }

/* Menu utilisateur de la topbar (clic sur les initiales → déconnexion…). */
.user-menu { position: relative; }
.user-menu > summary { list-style: none; cursor: pointer; display: inline-flex; }
.user-menu > summary::-webkit-details-marker { display: none; }
.user-menu > summary .avatar { transition: transform .12s ease, box-shadow .12s ease; }
.user-menu > summary:hover .avatar { transform: translateY(-1px); box-shadow: 0 4px 14px rgba(20, 20, 60, .22); }
.user-menu[open] > summary .avatar { box-shadow: 0 0 0 3px var(--primary-soft); }
.user-menu-pop {
    position: absolute; right: 0; top: calc(100% + .55rem); z-index: 80;
    min-width: 230px; background: var(--card); border: 1px solid var(--line);
    border-radius: var(--radius); box-shadow: 0 16px 42px rgba(20, 20, 60, .18); overflow: hidden;
}
.ump-head { display: flex; align-items: center; gap: .6rem; padding: .9rem 1rem; border-bottom: 1px solid var(--line); }
.ump-head .ump-id { min-width: 0; }
.ump-head strong { display: block; line-height: 1.2; }
.ump-head .ump-mail { display: block; font-size: .8rem; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ump-version { margin: .4rem .9rem 0; padding-top: .5rem; border-top: 1px solid var(--line); font-size: .72rem; color: var(--muted); }
.ump-item { display: flex; align-items: center; gap: .55rem; padding: .7rem 1rem; color: var(--ink); text-decoration: none; font-weight: 600; }
.ump-item:hover { background: var(--primary-soft); color: var(--primary-dark); }

/* CONVENTION largeur de base : la zone de travail d'une page SANS menu occupe
   la largeur de la COLONNE DE GAUCHE de la liste du personnel = largeur totale
   moins la colonne menu (300px) et le gap (1.6rem). Calée à gauche.
   Les pages AVEC menu/colonnes (liste perso `.page-with-aside`, console `/admin`,
   dashboard `.is-home`) repassent en pleine largeur (cf. règles ci-dessous). */
.content { padding: 1.8rem; max-width: calc(100% - 300px - 1.6rem); width: 100%; flex: 1; min-height: 0; overflow-y: auto; }
.content.is-home,
.content:has(.page-with-aside),
.admin-main .content { max-width: none; }
@media (max-width: 900px) { .content { max-width: none; } }
.page-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 1.4rem; gap: 1rem; flex-wrap: wrap; }
.page-head h1 { margin: 0; font-size: 1.7rem; }
.page-head .lead { color: var(--muted); margin: .2rem 0 0; }
.page-head-link { text-decoration: none; color: inherit; display: block; border-radius: var(--radius-sm); transition: opacity .12s; }
.page-head-link:hover { opacity: .75; }
.page-head-link:hover h1 { color: var(--primary-dark); }

/* Citation de session : elle occupe le blanc de la topbar, entre la marque et les pastilles.
   `min-width: 0` est ce qui autorise l'ellipsis — sans lui un élément flex refuse de passer
   sous la largeur de son contenu et POUSSE les pastilles hors de l'écran. Deux lignes au
   maximum : la topbar ne doit pas changer de hauteur selon la citation tirée. */
.citation-accueil {
    flex: 1 1 auto; min-width: 0;
    margin: 0 1.4rem; padding: .1rem 0 .1rem .9rem;
    border-left: 3px solid var(--primary-soft);
}
.citation-accueil blockquote {
    margin: 0; font-style: italic; font-size: .9rem; line-height: 1.35; color: var(--ink);
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
    overflow: hidden;
}
.citation-accueil figcaption {
    margin-top: .15rem; font-size: .78rem; color: var(--muted);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* Sous cette largeur, le bandeau n'a plus de blanc à offrir : marque et pastilles d'abord. */
@media (max-width: 1100px) { .citation-accueil { display: none; } }

.mi-identity { display: flex; align-items: center; gap: 1rem; }

/* Fiche élève — tuile droit à l'image (en-tête) */
.eleve-photo-tile {
    display: flex; flex-direction: column; align-items: center; gap: .1rem;
    border-radius: 12px; padding: .45rem .9rem; line-height: 1;
}
.eleve-photo-tile .ept-pic { font-size: 1.45rem; }
.eleve-photo-tile .ept-lbl { font-size: .66rem; font-weight: 700; letter-spacing: .03em; }
.eleve-photo-tile.ok { background: #d3f9d8; color: #178037; }
.eleve-photo-tile.ko { background: #ffe3e3; color: #c92a2a; }

/* ---------- Cards / stats ---------- */
.card {
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 1.3rem 1.4rem;
}
.stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 1rem; margin-bottom: 1.6rem; }
.stat { display: flex; align-items: center; gap: 1rem; }
.stat .emoji { font-size: 2rem; width: 58px; height: 58px; border-radius: 16px; display: grid; place-items: center; background: var(--primary-soft); }
.stat .num { font-size: 1.8rem; font-weight: 800; font-family: "Baloo 2", sans-serif; line-height: 1; }
.stat .lbl { color: var(--muted); font-size: .9rem; }

/* ---------- Table ---------- */
.toolbar { display: flex; gap: .8rem; align-items: center; margin-bottom: 1rem; flex-wrap: wrap; }
/* Repère « cette absence vient d'une RÈGLE récurrente », sur la cellule d'appel.
   ⚠️ Une classe à lui, et surtout PAS `.pr-code` : chaque repère a la sienne, et
   `presence_appel_controller.js` les nettoie NOMMÉMENT au changement de statut. Tant qu'il ne
   visait que `.pr-code`, un 🔁 déguisé en `.pr-code` survivait au clic « Présent ».
   Gris neutre : il informe, il ne signale rien — l'état, lui, est dit par le segment. */
.pr-recur { font-size: .8em; white-space: nowrap; color: var(--muted); cursor: help; }
/* Une PIÈCE couvre déjà cette demi-journée — posé au pointage, sans attendre la validation. */
.pr-piece { font-size: .8em; white-space: nowrap; color: var(--c-add); cursor: help; }
/* Le 🔖 motif de l'absence. ⚠️ La classe existait depuis toujours SANS règle : chaque gabarit
   portait sa taille en `style=` inline, et le badge peint par le JS au pointage sortait 25 % plus
   grand que celui du rechargement. Une forme, un seul endroit. */
.pr-code { font-size: .8em; white-space: nowrap; }

/* Contrôles de formulaire de MÊME hauteur dans une grille — une HAUTEUR, pas un minimum.
   Mesuré dans Chrome sur le formulaire des récurrences : `select` 47px, `input[type=date]` 49px
   (son indicateur de calendrier), `input[type=file]` 52px (son bouton natif). Trois hauteurs
   dans une même colonne, et l'œil lit un formulaire bricolé — c'est le reproche exact de
   Philippe (« drop-list motif de la même hauteur que les autres », 2026-09-08). Même leçon que
   `.me-period .me-input` (plus bas), sortie de son seul écran. */
.form-grid .field-edit > .input:not(textarea):not([type="checkbox"]) { height: 48px; }
/* Un champ désactivé DOIT se voir : sans cela on clique dedans et rien ne se passe. */
.input:disabled { background: var(--bg); color: var(--muted); cursor: not-allowed; opacity: .75; }

/* Barre de FILTRES d'une liste (`<form method="get">`). Elle existe parce que `.toolbar` seule ne
   suffisait pas : ses contrôles s'alignent au CENTRE et prennent chacun la largeur de leur contenu,
   si bien que deux listes déroulantes voisines n'avaient jamais la même taille — ce que l'œil lit
   immédiatement comme du bricolage. Ici : alignées par le BAS (les libellés n'ont pas tous la même
   hauteur) et toutes à la même largeur minimale. */
.filters { display: flex; flex-wrap: wrap; gap: .8rem; align-items: flex-end; margin-bottom: 1rem; }
.filters .field-edit { margin: 0; min-width: 13rem; }
.filters .input { width: 100%; }
@media (max-width: 640px) { .filters .field-edit { min-width: 100%; } }
.search { flex: 1; min-width: 220px; max-width: 380px; }
.table-wrap { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }
/* Enregistrements DNS (auth de domaine) : les valeurs CNAME et les motifs d'erreur sont longs.
   On lève le overflow:hidden hérité → scroll horizontal si besoin, ET on autorise le retour à la
   ligne des valeurs/erreurs pour qu'elles soient TOUJOURS lisibles (jamais coupées). */
.dns-records { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.dns-records code { word-break: break-all; overflow-wrap: anywhere; white-space: normal; }
.dns-records .dns-reason { display: inline-block; word-break: break-word; }
.dns-records td { vertical-align: top; }
.dns-records .icon-btn { vertical-align: middle; margin-left: .3rem; }
.dns-records .dns-fqdn { font-size: .78rem; word-break: break-all; }
.dns-aide { margin: .5rem 0 0; font-size: .85rem; }
/* Confirmation de copie : le bouton passe au vert le temps de la lire. */
.icon-btn.est-copie { color: var(--ok, #157347); border-color: currentColor; }
table { width: 100%; border-collapse: collapse; }
th { text-align: left; font-size: .78rem; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); padding: .9rem 1.1rem; border-bottom: 1px solid var(--line); }

/* Liste plein écran : page-head + recherche figés, tableau scrollable, pagination toujours visible. */
.list-page { display: flex; flex-direction: column; height: 100%; min-height: 0; }
.list-page .page-head, .list-page .toolbar, .list-page .pagination { flex-shrink: 0; }
.list-page .pagination { margin-bottom: .2rem; }
.list-page .table-wrap { flex: 1; min-height: 0; overflow-y: auto; }
/* En-têtes de colonnes figés pendant le scroll du tableau. */
.list-page thead th { position: sticky; top: 0; background: var(--card); z-index: 1; }
td { padding: .85rem 1.1rem; border-bottom: 1px solid var(--line); }
tr:last-child td { border-bottom: none; }
tbody tr:hover { background: #fbfbfe; }
.cell-name { display: flex; align-items: center; gap: .7rem; font-weight: 600; }

.badge {
    display: inline-flex; align-items: center; gap: .3rem;
    padding: .25rem .6rem; border-radius: 999px;
    font-size: .8rem; font-weight: 600;
    background: var(--brand-soft); color: var(--brand-dark);   /* accent iT.SCHOOL */
}
.badge.muted { background: var(--bg); color: var(--muted); }
/* Badge de classe coloré à la couleur de son implantation (option par implantation) :
   fond + couleur posés en inline ; ombre légère pour rester lisible sur couleur claire. */
.badge-classe { text-shadow: 0 1px 2px rgba(0, 0, 0, .25); }

/* Liste des groupes virtuels : nom coloré à la couleur de l'implantation (dégradé si
   plusieurs) + pastilles d'implantation dans la colonne Implantation. */
.grp-name { display: inline-flex; align-items: center; gap: .35rem; text-decoration: none; color: inherit; }
.grp-name-col {
    padding: .28rem .6rem; border-radius: 9px; color: #fff;
    text-shadow: 0 1px 2px rgba(0, 0, 0, .3);
}
.grp-name-col strong { color: #fff; }
.grp-name-ac { color: var(--muted); font-weight: 500; font-size: .9em; }
.grp-name-col .grp-name-ac { color: rgba(255, 255, 255, .85); }
.grp-pastilles { display: inline-flex; align-items: center; gap: .3rem; flex-wrap: wrap; }
/* Grille des groupes : centrer verticalement le contenu (icônes 34px vs pastille de nom plus haute). */
.grp-grid td { vertical-align: middle; }
/* Modale « membres d'un groupe système ». */
.grp-mem-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .1rem; max-height: 55vh; overflow-y: auto; }
.grp-mem-list li { display: flex; align-items: center; gap: .6rem; padding: .35rem .3rem; border-radius: 8px; }
.grp-mem-list li:hover { background: var(--bg); }
.grp-mem-nom { font-weight: 500; }

/* ---------- Empty state ---------- */
.empty { text-align: center; padding: 3.5rem 1.5rem; color: var(--muted); }
.empty .big { font-size: 3rem; }
.empty h3 { color: var(--ink); margin: .6rem 0 .3rem; }

/* ---------- Dropzone (import) ---------- */
.dropzone {
    border: 2px dashed #d6d8e6;
    border-radius: var(--radius);
    background: var(--card);
    padding: 2.6rem 1.5rem;
    text-align: center;
    transition: border-color .15s, background .15s;
    cursor: pointer;
}
.dropzone.dragover { border-color: var(--primary); background: var(--primary-soft); }
.dropzone .big { font-size: 2.6rem; }
.dropzone h3 { margin: .6rem 0 .2rem; }
.dropzone p { color: var(--muted); margin: 0; }
.dropzone .fname { margin-top: .8rem; font-weight: 600; color: var(--primary-dark); }

.note { background: #f0f7ff; border: 1px solid #d8e8ff; color: #2456a6; border-radius: var(--radius-sm); padding: .9rem 1.1rem; font-size: .9rem; }

@media (max-width: 760px) {
    .sidebar { position: fixed; inset: 0 auto 0 0; transform: translateX(-100%); transition: transform .2s; z-index: 30; box-shadow: var(--shadow); }
    .sidebar.open { transform: none; }
    .content { padding: 1.1rem; }
    .menu-toggle { display: inline-flex !important; }
    .sidebar-pin { display: none; }
}
.menu-toggle { display: none; background: var(--primary-soft); color: var(--primary-dark); border: none; width: 40px; height: 40px; border-radius: 12px; font-size: 1.2rem; cursor: pointer; }

/* ---------- Barre latérale auto-masquée (desktop) ----------
   Par défaut (non épinglée) la barre se réduit à un fin rail et se déploie
   en survol, par-dessus le contenu (sans le pousser). La flèche l'épingle. */
@media (min-width: 761px) {
    .app:not(.sidebar-pinned) .sidebar {
        position: fixed; top: 0; bottom: 0; left: 0; width: 250px;
        transform: translateX(-237px);
        transition: transform .2s ease;
        z-index: 40; box-shadow: var(--shadow);
    }
    .app:not(.sidebar-pinned) .sidebar:hover,
    .app:not(.sidebar-pinned) .sidebar:focus-within {
        transform: translateX(0);
    }
    /* Le contenu occupe presque toute la largeur ; on réserve juste le rail. */
    .app:not(.sidebar-pinned) .main { margin-left: 13px; }
    /* Indice visuel du rail (bande dégradée le long du bord). */
    .app:not(.sidebar-pinned) .sidebar::before {
        content: ''; position: absolute; top: 0; bottom: 0; right: 0; width: 3px;
        background: linear-gradient(var(--primary), var(--primary-dark)); opacity: .35;
    }
}

/* Pagination (liste des élèves) */
.pagination { display: flex; align-items: center; justify-content: center; gap: .4rem; margin-top: 1.6rem; flex-wrap: wrap; }
.page-btn {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 40px; height: 40px; padding: 0 .65rem;
    border-radius: 12px;
    background: var(--card); color: var(--ink);
    border: 1px solid var(--line);
    font-weight: 700; font-size: .95rem; text-decoration: none;
    transition: background .15s, color .15s, border-color .15s, transform .08s;
}
.page-btn:hover { background: var(--primary-soft); color: var(--primary-dark); border-color: var(--primary-soft); }
.page-btn:active { transform: scale(.95); }
.page-btn.current {
    background: var(--primary); color: #fff; border-color: var(--primary);
    box-shadow: var(--shadow); cursor: default;
}
.page-btn.nav { font-size: 1.15rem; }
.page-btn.disabled { background: var(--bg); color: var(--muted); border-color: var(--line); cursor: default; }
.page-btn.disabled:hover { background: var(--bg); color: var(--muted); }
.page-gap { display: inline-flex; align-items: center; justify-content: center; min-width: 24px; height: 40px; color: var(--muted); font-weight: 700; }

/* ---------- Action en fin de ligne (liste élèves) ---------- */
.col-action { width: 1%; white-space: nowrap; text-align: right; }
.btn-row {
    display: inline-flex; align-items: center; gap: .4rem;
    padding: .45rem .8rem; border-radius: 999px;
    background: var(--primary-soft); color: var(--primary-dark);
    border: 1px solid transparent;
    font-size: .85rem; font-weight: 700; text-decoration: none;
    transition: background .15s, border-color .15s, transform .08s;
}
.btn-row:hover { background: #e4e0ff; border-color: var(--primary); }
.btn-row:active { transform: scale(.96); }

/* ---------- Fiche élève (détail) ---------- */
.detail-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 1.1rem; align-items: start; }
.card-title { margin: 0 0 1rem; font-size: 1.05rem; }
.fields { margin: 0; display: grid; gap: .8rem; }
.fields > div { display: flex; justify-content: space-between; gap: 1rem; align-items: baseline; }
.fields dt { color: var(--muted); font-size: .85rem; margin: 0; }
.fields dd { margin: 0; font-weight: 600; text-align: right; }
.muted { color: var(--muted); font-weight: 400; }

/* Les responsables CÔTE À CÔTE (choix Philippe, 2026-09-20) : père et mère se lisent d'un coup
   d'œil au lieu de s'empiler. La grille se remplit d'elle-même et repasse à une colonne dès que
   310px ne tiennent plus — sur téléphone, comme dans un tiroir étroit. */
.parents { display: grid; grid-template-columns: repeat(auto-fit, minmax(310px, 1fr)); gap: 1rem; }
/* Une personne = un bloc ENCADRÉ (choix Philippe, 2026-08-22) : sans cadre, plusieurs
   responsables côte à côte se lisaient comme des zones flottantes sans frontière. */
.parent {
    display: flex; gap: .8rem; align-items: flex-start;
    border: 1px solid var(--line); border-radius: var(--radius-sm);
    padding: .7rem .8rem; background: var(--card);
}
.parent-body { min-width: 0; flex: 1; }
.parent-head { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; }
/* Badges de relation (père/mère/responsable) sur une carte responsable groupée. */
.parent-rels { display: inline-flex; align-items: center; gap: .35rem; flex-wrap: wrap; }
.resp-rel { display: inline-flex; align-items: center; gap: .3rem; }
.resp-rel-x {
    border: none; background: none; cursor: pointer; padding: 0; line-height: 1;
    font-size: .8rem; color: var(--danger, #c0431f); opacity: .55; transition: opacity .12s;
}
.resp-rel:hover .resp-rel-x { opacity: 1; }
/* Coordonnées en DEUX COLONNES (<dl>) : gouttière de largeur fixe pour les pictos,
   valeurs alignées entre elles. En flex-column, chaque ligne démarrait après un emoji
   de largeur différente (✉️ 📞 📍) — rien ne pouvait s'aligner. Ordre : adresse
   d'abord (rue, puis code postal + localité, comme sur une enveloppe), téléphone,
   e-mail. Une donnée absente ne laisse pas de trou : la grille se referme. */
.parent-meta {
    display: grid; grid-template-columns: 1.05rem 1fr;
    column-gap: .5rem; row-gap: .28rem;
    margin: .4rem 0 0; font-size: .88rem; color: var(--muted);
}
.parent-meta dt { text-align: center; font-size: .82rem; line-height: 1.4; opacity: .75; }
/* overflow-wrap : un e-mail long déborderait sinon de sa carte. */
.parent-meta dd { margin: 0; min-width: 0; line-height: 1.4; overflow-wrap: anywhere; }
.parent-meta a { color: var(--primary-dark); text-decoration: none; }
.parent-meta a:hover { text-decoration: underline; }

/* ---------- Dossier élève : onglets ---------- */
.flash { display: flex; align-items: center; gap: .5rem; padding: .8rem 1.1rem; border-radius: var(--radius-sm); margin-bottom: 1.1rem; font-weight: 600; }
.flash-ok { background: #e6f7ee; color: #157a4b; }
.flash-error { background: #fdecec; color: #c0392b; }

/* Onglets du DOSSIER élève — boutons à pastille, une couleur par domaine.
   `.tabs`/`.tab` n'est utilisé QUE par la fiche élève (`eleve/show.html.twig`).
   Ce ne sont pas des onglets soulignés mais des BOUTONS : la cible est plus grande,
   l'emoji est détaché du libellé dans sa pastille, et la couleur identifie la section
   avant même qu'on la lise. Elle vient de `data-dom` (ci-dessous), jamais d'un
   `style=` inline. Chaque bouton dérive tout son décor du jeton `--c`. */
.tabs { display: flex; flex-wrap: wrap; gap: .5rem; margin-bottom: 1.2rem; }
.tab {
    --c: var(--primary);
    display: inline-flex; align-items: center; gap: .55rem;
    padding: .4rem .9rem .4rem .4rem;
    background: var(--card, #fff); border: 1px solid var(--line); border-radius: 12px;
    color: var(--ink); text-decoration: none; cursor: pointer;
    font-family: inherit; font-size: .9rem; font-weight: 700; line-height: 1.3;
    transition: transform .12s, box-shadow .15s, border-color .15s, background .15s, color .15s;
}
.tab .tab-ico {
    width: 30px; height: 30px; flex: none; border-radius: 9px;
    display: grid; place-items: center; font-size: 1rem; line-height: 1;
    background: color-mix(in srgb, var(--c) 15%, #fff);
    transition: background .15s;
}
.tab:hover {
    color: var(--ink); border-color: var(--c); transform: translateY(-1px);
    box-shadow: 0 4px 12px color-mix(in srgb, var(--c) 22%, transparent);
}
.tab.active, .tab.is-active {
    background: color-mix(in srgb, var(--c) 10%, #fff);
    border-color: var(--c);
    color: color-mix(in srgb, var(--c) 85%, #000);
    box-shadow: 0 3px 10px color-mix(in srgb, var(--c) 28%, transparent);
}
.tab.active .tab-ico, .tab.is-active .tab-ico { background: var(--c); color: #fff; }
.tab:focus-visible { outline: 2px solid var(--c); outline-offset: 2px; }
.tab .count {
    background: color-mix(in srgb, var(--c) 15%, #fff);
    color: color-mix(in srgb, var(--c) 85%, #000);
    border-radius: 999px; padding: 0 .45rem; font-size: .78rem;
}
.tab.active .count, .tab.is-active .count { background: #fff; }
/* Une couleur par domaine du dossier (l'ordre suit celui des onglets). */
.tab[data-dom="identite"]      { --c: #6d5efc; }
.tab[data-dom="pedagogie"]     { --c: #0189d9; }
.tab[data-dom="bulletins"]     { --c: #b45309; }
.tab[data-dom="discipline"]    { --c: #e11d48; }
.tab[data-dom="autorisations"] { --c: #15803d; }

/* Le cadre du dossier à transmettre au centre PMS, sous le fil, quand le relais est décidé. */
.pms-cadre { margin: 1rem 0 0; padding: 1rem 1.1rem; background: var(--primary-soft); border-radius: 12px; }
.pms-cadre h4 { margin: 0 0 .3rem; font-size: 1rem; }
.pms-cadre .muted { margin: 0; font-size: .88rem; }
.pms-gestes { display: flex; flex-wrap: wrap; gap: .6rem; align-items: center; margin-top: .7rem; }
.pms-gestes form { margin: 0; }
.pms-traces { margin: .7rem 0 0; padding-left: 1.1rem; font-size: .86rem; }

/* La décision DÉJÀ PRISE, sous le fil : discrète, mais écrite — c'est ce qu'on vient vérifier. */
.decision-prise { margin: 1rem 0 0; padding: .7rem .9rem; background: var(--bg); border-radius: 10px; font-size: .9rem; }
.decision-prise .badge { margin-right: .4rem; }

/* AUTOCOMPLÉTION : le champ, sa liste flottante et ses lignes à pastille.
   ⚠️ Ces règles vivaient en DOUBLE, inline, dans `presence/correction.html.twig` et
   `presence/historique.html.twig`. Elles montent ici parce qu'un troisième écran s'en sert (le
   pilote du suivi) : trois copies d'un même composant finissent par diverger. */
.es-wrap { position: relative; }
.es-results { position: absolute; z-index: 30; left: 0; right: 0; top: 100%; margin-top: .25rem;
    background: var(--card); border: 1px solid var(--line); border-radius: 10px;
    box-shadow: 0 8px 24px rgba(15, 23, 42, .12); max-height: 320px; overflow: auto; }
.es-item { display: flex; align-items: center; gap: .5rem; width: 100%; padding: .45rem .7rem;
    text-align: left; text-decoration: none; color: inherit; background: none; border: 0;
    border-top: 1px solid var(--line); cursor: pointer; font: inherit; }
.es-item:first-child { border-top: 0; }
.es-item:hover, .es-item:focus-visible, .es-item.est-actif { background: var(--primary-soft); }
/* ⚠️ La ligne parcourue au clavier doit se voir AUTANT que celle survolée : sans repère, les flèches
   déplacent quelque chose d'invisible. */
.es-item.est-actif { box-shadow: inset 2px 0 0 var(--primary); }
.es-reste { margin: 0; padding: .4rem .7rem; font-size: .8rem; color: var(--muted); border-top: 1px solid var(--line); }
.es-nom { min-width: 0; }
.es-empty { padding: .5rem .7rem; color: var(--muted); }

/* Les quatre volets d'un même axe dans UNE carte : un nom, un état, ses gestes. Quatre cartes
   séparées donnaient quatre fois l'ombre, le padding et le titre pour une phrase grise et un bouton
   verrouillé — la fiche du suivi faisait deux écrans de vide (20/09).
   ⚠️ Aucun dépliant : les gestes portent des tiroirs, et sur Safari un champ dans un `<details>`
   part VIDE. Une ligne fermée reste donc lisible, avec son bouton verrouillé qui dit son seuil. */
.fiche-lignes { display: grid; }
.fiche-ligne { display: grid; grid-template-columns: 14rem minmax(0, 1fr) auto; gap: .9rem;
    align-items: start; padding: .9rem 0; border-top: 1px solid var(--line); }
.fiche-ligne:first-child { border-top: 0; padding-top: .2rem; }
.fiche-ligne-nom { font-weight: 700; display: flex; align-items: baseline; gap: .45rem; }
/* La pastille de la checklist : ✅ quand la démarche est engagée, ○ tant qu'elle ne l'est pas. */
.fiche-coche { flex: none; font-size: .95rem; line-height: 1.2; }
.axe1-compte { margin: -.5rem 0 .9rem; color: var(--muted); font-size: .9rem; }
.fiche-ligne-etat > :first-child { margin-top: 0; }
.fiche-ligne-etat > :last-child { margin-bottom: 0; }
.fiche-ligne-etat ul { margin: 0; padding-left: 1.1rem; }
.fiche-ligne-gestes { display: flex; flex-wrap: wrap; gap: .5rem; justify-content: flex-end; }
@media (max-width: 720px) {
    .fiche-ligne { grid-template-columns: 1fr; gap: .5rem; }
    .fiche-ligne-gestes { justify-content: flex-start; }
}

/* La table des matières d'une FICHE (suivi d'un élève) compte plus d'entrées que les onglets d'un
   dossier : elle se resserre pour tenir sur une seule ligne jusqu'à 1280px, largeur d'un portable
   avec le menu de module déplié. Ciblé sur l'enfant direct de `.page-main` : les onglets du dossier
   de l'élève, eux, vivent dans `.dossier` et gardent leur taille.
   ⚠️ `.5rem` est le maximum qui tienne sur une ligne à 1280px — mesuré au navigateur le 20/09 :
   à .55rem les sept entrées passent sur deux lignes. */
.page-main > .tabs { gap: .5rem; }
.page-main > .tabs .tab { padding: .3rem .65rem .3rem .28rem; font-size: .84rem; gap: .45rem; }
.page-main > .tabs .tab .tab-ico { width: 26px; height: 26px; font-size: .9rem; }

.tab-panel { display: none; }
.tab-panel.active { display: block; }

/* ---------- Formulaires du dossier ---------- */
.form .card-title { margin-bottom: 1.2rem; }
.form-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1rem; }
.field-edit { display: flex; flex-direction: column; gap: .35rem; }
.field-edit.full { grid-column: 1 / -1; }
.field-edit > span { font-size: .85rem; font-weight: 600; color: var(--muted); }
.field-edit.check { flex-direction: row; align-items: center; gap: .5rem; }
.field-edit.check > span { color: var(--ink); }
.field-edit textarea.input { resize: vertical; font-family: inherit; line-height: 1.5; }
/* ⚠️ `gap` : sans lui, deux boutons voisins se TOUCHENT — constaté sur « Action de l'école » et
   « Actions antérieures » (20/09). Un template s'en était sorti en posant son propre `gap` inline ;
   la règle est ici, une fois, pour les 32 usages. `wrap` : trois boutons ne débordent pas. */
.form-actions { margin-top: 1.2rem; display: flex; flex-wrap: wrap; gap: .6rem; justify-content: flex-end; }

/* ---------- Entretiens : historique ---------- */
.timeline { list-style: none; margin: 1.2rem 0 0; padding: 0; display: grid; gap: .9rem; }
.entry { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 1rem 1.2rem; }
.entry-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
.entry-head > div { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.entry-body { margin: .6rem 0 0; white-space: pre-line; }
.link-danger { background: none; border: none; cursor: pointer; font-size: 1rem; opacity: .6; padding: .2rem; line-height: 1; }
.link-danger:hover { opacity: 1; }

@media (max-width: 640px) { .form-grid { grid-template-columns: 1fr; } }

/* ---------- Bulletins (grille officielle) ---------- */
.badge-ok { background: #e6f7ee; color: #157a4b; }
.badge-blue { background: #e3f2fd; color: #0b6aa2; }
.bulletin { margin-top: 1.2rem; }
.bulletin-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; }

.bulletin-grid { width: 100%; border-collapse: collapse; font-size: .9rem; }
.bulletin-grid th, .bulletin-grid td { border: 1px solid var(--line); padding: .35rem .5rem; }
.bulletin-grid thead th { background: var(--bg); font-size: .72rem; text-transform: uppercase; letter-spacing: .03em; color: var(--muted); text-align: left; position: static; }
.bulletin-grid thead th.num, .bulletin-grid td.num { text-align: center; }
.bulletin-grid td.lib { font-weight: 500; }
.bulletin-grid td.max { color: var(--muted); white-space: nowrap; width: 3rem; }
.branche-cell { background: var(--primary-soft); color: var(--primary-dark); font-weight: 700; font-family: "Baloo 2", sans-serif; text-align: center; vertical-align: middle; width: 7rem; }
.pct-row { background: #fafaff; font-weight: 700; }
.pct-row .lib { font-style: italic; }
.row-appreciation td.lib, .row-absence td.lib { color: var(--ink); }

/* Cellules de saisie compactes, intégrées au tableau. */
.cell-input { width: 100%; min-width: 3rem; border: 1px solid transparent; background: transparent; border-radius: 6px; padding: .3rem .35rem; text-align: center; font: inherit; color: inherit; }
.cell-input:hover { border-color: var(--line); }
.cell-input:focus { outline: none; border-color: var(--primary); background: #fff; box-shadow: 0 0 0 2px var(--primary-soft); }

.legend { font-size: .8rem; margin: .6rem 0 0; }
.legend strong { color: var(--ink); }

/* Cadres séparés sous le tableau. Comportement : pleine largeur, plus grand.
   Absences / Retards : deux tableaux séparés côte à côte en dessous. */
.bulletin-extras { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: .9rem; margin-top: .9rem; }

.comportement-cadre { margin-top: 1rem; }
.comportement-cadre .mini-grid { font-size: .92rem; }
.comportement-cadre .mini-grid th, .comportement-cadre .mini-grid td { padding: .55rem .7rem; }
.comportement-cadre .mini-grid td.lib { width: 42%; }
.comportement-cadre .pastilles { gap: .55rem; }
.comportement-cadre .pastille { width: 26px; height: 26px; }
.mini-title { margin: 0 0 .5rem; font-size: .95rem; font-family: "Baloo 2", sans-serif; color: var(--primary-dark); }
.mini-grid { width: 100%; border-collapse: collapse; font-size: .85rem; }
.mini-grid th, .mini-grid td { border: 1px solid var(--line); padding: .3rem .4rem; }
.mini-grid thead th { background: var(--bg); font-size: .68rem; text-transform: uppercase; letter-spacing: .03em; color: var(--muted); text-align: center; }
.mini-grid td.lib { font-weight: 500; }
.mini-grid td.num { text-align: center; }

/* Comportement : sélecteur à 3 pastilles de couleur (rouge / orange / vert). */
.pastilles { display: inline-flex; gap: .35rem; justify-content: center; }
.pastille { position: relative; width: 20px; height: 20px; border-radius: 50%; cursor: pointer; opacity: .3; transition: opacity .12s, box-shadow .12s, transform .08s; }
.pastille:hover { opacity: .65; }
.pastille input { position: absolute; inset: 0; opacity: 0; margin: 0; cursor: pointer; }
.p-vert { background: #2ec27e; }
.p-orange { background: #f5a524; }
.p-rouge { background: #f0463f; }
.pastille.on, .pastille:has(input:checked) { opacity: 1; transform: scale(1.08); box-shadow: 0 0 0 2px var(--card), 0 0 0 3px var(--ink); }

@media (max-width: 760px) {
    .table-wrap:has(.bulletin-grid) { overflow-x: auto; }
    .bulletin-grid { min-width: 620px; }
}

/* ---------- Administration des comptes ---------- */
.invite-box { border: 1px solid var(--primary); background: var(--primary-soft); margin-bottom: 1.1rem; }
.invite-link { font-family: ui-monospace, monospace; font-size: .85rem; cursor: pointer; }
/* Actions de ligne : TOUJOURS sur une ligne (jamais d'icônes empilées verticalement). */
.row-actions { display: inline-flex; gap: .15rem; justify-content: flex-end; flex-wrap: nowrap; align-items: center; }
.row-actions form { display: inline; }
.btn-row.danger { background: #fdecec; color: #c0392b; }
.btn-row.danger:hover { background: #f9d9d9; border-color: #c0392b; }

/* ---------- Espace parent ---------- */
.enfant-card { text-decoration: none; transition: transform .08s, box-shadow .15s; }
.enfant-card:hover { transform: translateY(-2px); box-shadow: var(--shadow); }
.pastille-static {
    display: inline-flex; align-items: center; justify-content: center;
    width: 24px; height: 24px; border-radius: 50%;
    color: #fff; font-weight: 800; font-size: .8rem;
}

/* ---------- Éditeur de structure de modèle ---------- */
.struct-row { display: grid; grid-template-columns: 1fr auto; gap: .5rem 1rem; align-items: center; padding: .6rem 0; border-bottom: 1px solid var(--line); }
.struct-row:last-of-type { border-bottom: none; }
.struct-main { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.struct-edit, .struct-add { grid-column: 1 / -1; }
.struct-edit > summary, .struct-add > summary { cursor: pointer; font-weight: 600; color: var(--primary-dark); font-size: .9rem; }

/* Ligne d'en-tête de catégorie dans le bulletin basé sur un modèle. */
.bulletin-grid .cat-row td { background: var(--primary-soft); color: var(--primary-dark); font-weight: 700; font-family: "Baloo 2", sans-serif; }
.bulletin-grid .gen-row td { background: #fff7ec; }

/* ---------- Apparence du modèle (éditeur) ---------- */
.apparence-layout { display: grid; grid-template-columns: 1fr 260px; gap: 1.2rem; align-items: start; }
.seuils { margin-top: .8rem; display: flex; flex-direction: column; gap: .4rem; }
.seuil-row { display: flex; align-items: center; gap: .4rem; }
.apercu-style { position: sticky; top: 0; }
.apercu-label { font-size: .8rem; margin-bottom: .35rem; }
.apercu-sheet { border: 1px solid var(--line); border-radius: var(--radius-sm); overflow: hidden; }
.apercu-cat { padding: .4rem .7rem; font-weight: 700; font-family: "Baloo 2", sans-serif; }
.apercu-line { display: flex; justify-content: space-between; padding: .4rem .7rem; border-top: 1px solid var(--line); }
.apercu-pct { font-variant-numeric: tabular-nums; }
@media (max-width: 720px) { .apparence-layout { grid-template-columns: 1fr; } }

/* ---------- Thème appliqué au bulletin (modèle) ---------- */
.bull-themed { font-family: var(--bull-font); font-size: var(--bull-size); }
.bull-themed .bulletin-grid .cat-row td { background: var(--bull-cat-bg); color: var(--bull-cat-fg); }

/* ---------- Agencement des blocs (rendu du bulletin) ---------- */
.bull-layout { display: grid; grid-template-columns: repeat(12, 1fr); gap: 1rem; align-items: start; }
.bull-block { grid-column: span var(--bw, 12); min-width: 0; }
.bull-block .table-wrap, .bull-block .mini-cadre { margin-top: 0; }
.bull-texte { border: 1px solid var(--line); border-radius: var(--radius-sm); padding: .8rem 1rem; white-space: pre-line; }
@media (max-width: 720px) { .bull-block { grid-column: span 12; } }

/* ---------- Constructeur d'agencement (Gridstack) ---------- */
.agencement-toolbar { display: flex; gap: .6rem; margin-bottom: 1rem; flex-wrap: wrap; }
.grid-stack { background: var(--bg); border-radius: var(--radius); min-height: 320px; }
.grid-stack-item-content.blk { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius-sm); padding: .7rem .9rem; overflow: hidden; display: flex; flex-direction: column; gap: .5rem; }
.blk-title { font-weight: 700; font-family: "Baloo 2", sans-serif; color: var(--primary-dark); cursor: move; display: flex; align-items: center; justify-content: space-between; gap: .5rem; }
.blk-remove { background: none; border: none; cursor: pointer; color: var(--muted); font-weight: 700; }
.blk-remove:hover { color: #c0392b; }
.blk-text { resize: none; flex: 1; }

/* Cellule de cote verrouillée (utilisateur non affecté à la discipline). */
.cell-locked { display: inline-flex; align-items: center; gap: .25rem; color: var(--muted); }
.cell-locked .lock { font-size: .85rem; opacity: .8; }

/* ---------- Plan de pilotage (hiérarchie) ---------- */
.objectif { margin-top: 1.1rem; }
.strategie { border-left: 3px solid var(--primary-soft); margin: .8rem 0 .8rem .4rem; padding-left: .9rem; }
.pp-bar { display: inline-block; width: 90px; height: 8px; border-radius: 999px; background: var(--line); overflow: hidden; vertical-align: middle; margin-right: .4rem; }
.pp-bar span { display: block; height: 100%; background: var(--primary); }
/* Grille de l'arbre (educaplus, lot 1) : l'objectif est la ligne dépliante, stratégies et actions ses
   sous-lignes, décalées d'un cran par niveau. Les intitulés passent à la ligne (la grille ne défile pas). */
.pp-arbre td { vertical-align: top; }
.pp-arbre > thead > tr > th:first-child { min-width: 13rem; }
.pp-titre { white-space: normal; overflow-wrap: break-word; }
.pp-niv-strategie > td:first-child { padding-left: 2.2rem; font-weight: 600; color: var(--primary-dark); }
.pp-niv-action > td:first-child { padding-left: 3.6rem; }
.pp-niv-ajout > td { padding-left: 3.6rem; }
.pp-niv-ajout.pp-sous-objectif > td { padding-left: 2.2rem; }
.pp-arbre .badge, .pp-avancement { white-space: nowrap; }
/* Étroit (menu latéral ouvert, tablette) : six colonnes ne tiennent pas. La grille DÉFILE au lieu d'être
   coupée par `.table-wrap` (même parade que `.bulletin-grid`), et la barre cède sa place au pourcentage. */
.table-wrap:has(.pp-arbre) { overflow-x: auto; }
@media (max-width: 1100px) { .pp-arbre .pp-bar { display: none; } }
.pp-raisons { margin: .3rem 0 0; padding-left: 1.1rem; }
/* Lot 3 : la portée du panneau d'indicateurs (tout le plan / un objectif), au-dessus de `.pp-dash`. */
.pp-portee { display: flex; align-items: center; justify-content: space-between; gap: .8rem; flex-wrap: wrap; margin-bottom: .7rem; }
.pp-portee h3 { margin: 0; }
.pp-alert p { margin: 0; }
.pp-alert .pp-plus { margin-top: .3rem; font-size: .82rem; }
.pp-num { text-align: center; }
/* Dans un module à menu latéral, quatre cartes côte à côte écrasent l'anneau : il prend sa ligne, les
   trois alertes se rangent dessous. */
.page-with-aside .pp-dash { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.page-with-aside .pp-dash .pp-indic { grid-column: 1 / -1; }
@media (max-width: 760px) { .page-with-aside .pp-dash { grid-template-columns: minmax(0, 1fr); } }
/* Le disque intérieur de l'anneau (::after, peint après) masquait le taux : le texte repasse dessus. */
.pp-donut-center { z-index: 1; }
.pp-voir-indic { text-decoration: none; margin-left: .35rem; font-size: .9rem; opacity: .75; }
.pp-voir-indic:hover { opacity: 1; }
.pp-rubrique + .pp-rubrique { margin-top: 1.1rem; }
.pp-rubrique h3 { margin: 0 0 .3rem; font-size: 1rem; }
.pp-rubrique p { margin: 0; white-space: pre-line; }

/* ---------- Suivi d'une action / fiches de réunion ---------- */
.suivi-group { margin: 1.1rem 0 .4rem; font-size: .95rem; font-family: "Baloo 2", sans-serif; color: var(--primary-dark); }
.suivi-champ { display: flex; flex-direction: column; gap: .15rem; padding: .4rem 0; border-bottom: 1px solid var(--line); }
.suivi-champ:last-child { border-bottom: none; }
.suivi-champ dt { font-size: .8rem; font-weight: 600; color: var(--muted); }
.suivi-champ dd { margin: 0; }
.suivi-suite { background: var(--primary-soft); border-radius: var(--radius-sm); padding: .6rem .8rem; border-bottom: none; }
.reunion { margin-top: 1rem; }

/* Réunion clôturée + pied de fiche + historique. */
.reunion-cloturee { border-color: #d9d9e3; background: #fbfbfe; }
.reunion-footer { display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin-top: .8rem; padding-top: .6rem; border-top: 1px solid var(--line); flex-wrap: wrap; }
.reunion-hist { margin-top: .6rem; }
.reunion-hist > summary { cursor: pointer; font-size: .85rem; }
.reunion-hist ul { margin: .5rem 0 0; padding-left: 1.1rem; font-size: .85rem; color: var(--muted); }

/* ---------- Tableau de bord intelligent (pilotage) ---------- */
.pp-dash { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 1rem; margin-bottom: 1.2rem; }
.pp-indic { display: flex; align-items: center; gap: 1.3rem; }
.pp-donut {
    --taux: 0; --col: var(--ok);
    width: 108px; height: 108px; border-radius: 50%; flex-shrink: 0;
    background: conic-gradient(var(--col) calc(var(--taux) * 1%), var(--line) 0);
    display: grid; place-items: center; position: relative;
    transition: background .4s ease;
}
.pp-donut::after { content: ""; position: absolute; width: 80px; height: 80px; border-radius: 50%; background: var(--card); box-shadow: inset 0 0 0 1px var(--line); }
.pp-donut-center { position: relative; text-align: center; line-height: 1; }
.pp-donut-center strong { display: block; font-family: "Baloo 2", sans-serif; font-size: 1.6rem; }
.pp-donut-center span { font-size: .66rem; color: var(--muted); text-transform: uppercase; letter-spacing: .05em; }
.pp-indic-body { flex: 1; min-width: 0; }
.pp-indic-titre { font-weight: 700; }
.pp-legend { display: flex; flex-wrap: wrap; gap: .3rem 1rem; margin: .45rem 0 .85rem; font-size: .85rem; color: var(--muted); }
.pp-legend .dot { display: inline-block; width: 9px; height: 9px; border-radius: 50%; margin-right: .35rem; vertical-align: middle; }
.dot-green { background: #2ec27e; } .dot-blue { background: var(--primary); } .dot-grey { background: #d6d8e6; }
.pp-avg-head { display: flex; justify-content: space-between; align-items: baseline; font-size: .85rem; color: var(--muted); margin-bottom: .3rem; }
.pp-avg-head strong { color: var(--ink); font-family: "Baloo 2", sans-serif; }
.pp-bar-full { width: 100%; height: 10px; }
.pp-indic-titre { font-weight: 700; }
.pp-alert h4 { margin: 0 0 .5rem; font-size: .95rem; display: flex; align-items: center; gap: .4rem; }
.pp-alert { border-left: 4px solid var(--line); }
.pp-alert-red { border-left-color: #f0463f; }
.pp-alert-orange { border-left-color: var(--warn); }
.pp-alert-blue { border-left-color: var(--primary); }
.pp-list { list-style: none; margin: 0; padding: 0; font-size: .88rem; display: flex; flex-direction: column; gap: .3rem; }
.pp-list a { color: var(--primary-dark); text-decoration: none; font-weight: 600; }
.pp-list a:hover { text-decoration: underline; }
.pp-filter { display: flex; gap: .6rem; flex-wrap: wrap; padding: .8rem 1rem; }
.pp-filter .input { width: auto; }
.pp-filter #pp-search { flex: 1; min-width: 220px; }

/* ---------- Boîtes d'objectifs (grille 2 par ligne) ---------- */
.pp-boxes { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1rem; }
.pp-box {
    position: relative; overflow: hidden;
    display: flex; flex-direction: column; gap: .35rem; justify-content: center;
    min-height: 120px; padding: 1.3rem 1.4rem;
    background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
    text-decoration: none; color: var(--ink);
    transition: transform .1s, box-shadow .15s, border-color .15s;
}
.pp-box:hover { transform: translateY(-3px); box-shadow: var(--shadow); border-color: var(--primary); }
.pp-box-num { font-family: "Baloo 2", sans-serif; font-weight: 800; font-size: 1.25rem; }
.pp-box-meta { color: var(--muted); font-size: .85rem; }
/* Le nom de l'objectif n'apparaît qu'au survol. */
.pp-box-reveal {
    position: absolute; inset: 0;
    display: flex; align-items: center; justify-content: center; text-align: center;
    padding: 1.2rem; background: var(--primary); color: #fff;
    font-weight: 700; font-family: "Baloo 2", sans-serif; font-size: 1.05rem;
    opacity: 0; transform: scale(1.02); transition: opacity .15s, transform .15s;
}
.pp-box:hover .pp-box-reveal, .pp-box:focus-visible .pp-box-reveal { opacity: 1; transform: scale(1); }
@media (max-width: 640px) { .pp-boxes { grid-template-columns: 1fr; } }

/* ---------- Cartes cliquables (stratégies / actions) ---------- */
.pp-cards { display: flex; flex-direction: column; gap: .6rem; }
.pp-card {
    display: flex; align-items: center; justify-content: space-between; gap: 1rem;
    padding: .9rem 1.1rem; background: var(--card);
    border: 1px solid var(--line); border-radius: var(--radius-sm);
    text-decoration: none; color: var(--ink);
    transition: transform .08s, box-shadow .15s, border-color .15s;
}
.pp-card:hover { transform: translateX(3px); border-color: var(--primary); box-shadow: var(--shadow); }
.pp-card-main { min-width: 0; }
.pp-card-edit { display: flex; align-items: flex-start; gap: .5rem; padding: 0 0 .4rem 1.1rem; }
.pp-card-edit .struct-add { flex: 1; }
.pp-card .pp-bar { width: 90px; }

/* ---------- Icône Action (doigt + bouton, onde de pression) ---------- */
.icon-action { width: 1em; height: 1em; display: inline-block; vertical-align: -0.18em; color: var(--ink); }
.icon-action .ia-btn,
.icon-action .ia-ripple { transform-box: fill-box; transform-origin: center; }
.icon-action .ia-btn { transition: transform .12s ease; }
.icon-action .ia-ripple { animation: ia-pulse 2.1s ease-out infinite; }
@keyframes ia-pulse {
    0%   { transform: scale(.5);  opacity: .65; }
    70%  { transform: scale(1.2); opacity: 0; }
    100% { transform: scale(1.2); opacity: 0; }
}
/* Léger enfoncement quand on survole l'élément contenant l'icône. */
.pp-card:hover .icon-action .ia-btn,
.stat:hover .icon-action .ia-btn,
.btn-row:hover .icon-action .ia-btn { transform: scale(.8); }
.emoji .icon-action { width: 1.4rem; height: 1.4rem; }

/* ---------- Fiche santé : cases à cocher imagées ---------- */
.sante-pics { display: flex; flex-wrap: wrap; gap: .6rem; margin-bottom: 1rem; }
.sante-pic { position: relative; cursor: pointer; }
/* On masque LA CASE À COCHER (la tuile lui sert de rendu), surtout pas tout input :
   les tuiles de repère personnalisé contiennent un champ texte visible. */
.sante-pic input[type="checkbox"] { position: absolute; opacity: 0; width: 0; height: 0; }
.sante-pic .pic {
    display: grid; place-items: center;
    width: 70px; height: 64px; border-radius: var(--radius-sm);
    border: 2px solid var(--line); background: var(--card);
    font-size: 1.9rem; transition: border-color .12s, background .12s, transform .08s;
}
.sante-pic .lbl { display: block; text-align: center; font-size: .78rem; color: var(--muted); margin-top: .25rem; }
.sante-pic:hover .pic { border-color: var(--primary); }
.sante-pic input:checked + .pic { border-color: var(--primary); background: var(--primary-soft); transform: translateY(-2px); }
.sante-pic input:checked ~ .lbl { color: var(--primary-dark); font-weight: 700; }
.sante-soutien { display: flex; flex-wrap: wrap; gap: .4rem 1.2rem; margin-top: .25rem; }

/* Cadres Santé compacts : contenu sur une seule colonne, icônes plus petites.
   .sante-card est porté par le <form> qui enveloppe les DEUX cartes (🩺 Santé,
   🤝 Soutien) + le drawer — un seul formulaire, cf. eleve/_onglet_sante.html.twig.
   Le drawer, lui, garde la grille à 2 colonnes du reste de l'app. */
.sante-card .card .form-grid { grid-template-columns: 1fr; }
/* Tuiles de même largeur et libellé sur UNE ligne : sans quoi « Appareil auditif »
   passe à la ligne et sa tuile se désaligne des quatre autres. */
.sante-card .sante-pic { width: 108px; }
.sante-card .sante-pic .pic { width: 100%; height: 54px; font-size: 1.6rem; line-height: 1; }
.sante-card .sante-pic .lbl { white-space: nowrap; }
/* Repères personnalisés : tuile en pointillés tant qu'elle n'est pas nommée
   (affordance « emplacement libre »), pleine dès qu'elle l'est. Le nom se saisit
   JUSTE SOUS la tuile, dans un champ qui prend la place du libellé — même gabarit
   que les autres tuiles, donc la rangée reste alignée. */
.sante-pic-autre { position: relative; }
.sante-pic-autre .pic { border-style: dashed; }
.sante-pic-autre.is-on .pic { border-style: solid; border-color: var(--primary); background: var(--primary-soft); }
/* `position` et `opacity` explicites : filet contre la règle de masquage voisine,
   qui a déjà rendu ce champ invisible une fois. */
.sante-card .sante-pic-nom { position: static; opacity: 1; height: auto;
    display: block; width: 100%; margin-top: .25rem; padding: .1rem .2rem;
    border: 0; border-bottom: 1px dashed var(--line); border-radius: 0; background: transparent;
    font-family: inherit; font-size: .78rem; line-height: 1.3; text-align: center; color: var(--muted); }
.sante-card .sante-pic-nom::placeholder { color: var(--muted); opacity: .75; }
.sante-card .sante-pic-nom:focus { outline: none; border-bottom-color: var(--primary); color: var(--ink); }
.sante-pic-autre.is-on .sante-pic-nom { color: var(--primary-dark); font-weight: 700; border-bottom-color: transparent; }
/* Croix de suppression, au coin de la tuile. Discrète au repos pour ne pas
   encombrer la rangée, franche au survol/focus clavier. Absente de la tuile
   vierge : il n'y a rien à y supprimer. */
.sante-pic-x { position: absolute; top: -6px; right: -6px; z-index: 1;
    display: grid; place-items: center; width: 20px; height: 20px; padding: 0;
    border: 1px solid var(--line); border-radius: 999px; background: var(--card);
    color: var(--muted); font-size: .68rem; line-height: 1; cursor: pointer;
    opacity: 0; transition: opacity .12s, color .12s, border-color .12s; }
.sante-pic-autre:hover .sante-pic-x,
.sante-pic-x:focus-visible { opacity: 1; }
.sante-pic-x:hover { color: var(--danger); border-color: var(--danger); }
.sante-pic-autre[data-picto-vierge] .sante-pic-x { display: none; }
/* Sans survol (tactile), la croix reste visible : sinon la suppression serait
   inatteignable au doigt. */
@media (hover: none) { .sante-pic-autre.is-on .sante-pic-x { opacity: 1; } }
.sante-soutien-card { margin-top: 1.1rem; }

/* Action « Détails médicaux » : en bas à gauche du cadre Santé. Son compteur
   réutilise la pastille .pedago-n du dossier élève (rien de nouveau à définir). */
.sante-plus { margin-top: .9rem; }

/* Détails médicaux remplis : une boîte par donnée, au format du champ Allergies
   (.field-edit + .input), EMPILÉES sous lui. Pas de donnée ⇒ pas de boîte.
   La boîte est en lecture — les champs de saisie vivent dans le drawer. */
.sante-resume-item { margin-bottom: .7rem; }
.sante-box { font: inherit; font-weight: 500; color: var(--ink); text-align: left;
    white-space: pre-line; overflow-wrap: anywhere; }
button.sante-box { cursor: pointer; }
button.sante-box:hover { border-color: var(--primary); background: var(--primary-soft); }
button.sante-box:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }

/* ============================================================
   Navigation par espaces : École → Classe → Individu
   ============================================================ */
[data-screen] { display: none; }
[data-screen].active { display: block; animation: screen-in .25s ease; }
@keyframes screen-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

/* --- Accueil : 3 grandes cases --- */
.spaces-hero { margin: 0 0 1.2rem; }
.spaces-hero h1 { margin: 0 0 .3rem; font-size: 1.5rem; }
.spaces-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 1.3rem;
    margin-bottom: 1.8rem;
}
@media (max-width: 900px) { .spaces-grid { grid-template-columns: 1fr; } }

.space-card {
    position: relative;
    display: flex;
    flex-direction: column;
    border: none;
    border-radius: var(--radius);
    padding: 0;
    overflow: hidden;
    cursor: pointer;
    text-align: left;
    color: #fff;
    min-height: 230px;
    box-shadow: var(--shadow);
    transition: transform .18s ease, box-shadow .18s ease;
    text-decoration: none;
}
.space-card:hover { transform: translateY(-6px); box-shadow: 0 22px 40px -16px rgba(45, 40, 90, .4); }
.space-card:active { transform: translateY(-2px); }
.space-card .sc-art {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 4.6rem;
    line-height: 1;
    filter: drop-shadow(0 8px 14px rgba(0, 0, 0, .18));
}
.space-card .sc-body { padding: 1rem 1.25rem 1.3rem; background: rgba(0, 0, 0, .14); }
.space-card .sc-title { font-family: "Baloo 2", sans-serif; font-weight: 800; font-size: 1.45rem; margin: 0; }
.space-card .sc-desc { margin: .15rem 0 0; font-size: .9rem; opacity: .92; line-height: 1.35; }
.space-card .sc-go { margin-top: .55rem; font-size: .82rem; font-weight: 700; opacity: .95; }
.space-ecole    { background: linear-gradient(135deg, #6d5efc 0%, #8b7bff 55%, #b8acff 100%); }
.space-classe   { background: linear-gradient(135deg, #ff8a5c 0%, #ff6f91 60%, #ffa36c 100%); }
.space-cartable { background: linear-gradient(135deg, #18b6a4 0%, #2bd4b0 55%, #7ee8c4 100%); }

/* ============================================================
   Accueil 2 colonnes : contenu principal + panneau « assistant »
   (repris du dashboard de Pauline — mêmes tokens de design)
   ============================================================ */
/* Le tableau de bord exploite toute la largeur de l'écran (les autres pages
   restent plafonnées à 1100px via .content). */
.content.is-home { max-width: none; padding-top: 1rem; }
/* Accueil : titre remonté + écart resserré titre ↔ hero (gain de place). */
.content.is-home .page-head { margin-bottom: .5rem; }

.home-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 360px;
    gap: 2rem;
    align-items: start;
}
.home-main { min-width: 0; }
/* Les 3 espaces : grandes cartes côte à côte, étirées sur toute la largeur. */
.home-main .spaces-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1.6rem; margin-bottom: 1.4rem; }
.home-main .space-card { min-height: 280px; }
.home-main .space-card .sc-art { font-size: 5.6rem; }
.home-main .space-card .sc-title { font-size: 1.7rem; }
.home-main .space-card .sc-desc { font-size: .98rem; }
@media (max-width: 900px) { .home-main .spaces-grid { grid-template-columns: 1fr; } }

@media (max-width: 1100px) {
    .home-grid { grid-template-columns: 1fr; }
    .assistant-panel { position: static !important; }
}

/* ===== Dashboard plein écran : zones gauche/droite à scroll indépendant =====
   Scopé à <body class="dash-split"> (seulement le tableau de bord). La topbar
   reste figée ; la zone de contenu occupe le reste de la hauteur et délègue le
   défilement aux deux colonnes (et aux écrans de tuiles). */
/* Défilement de PAGE classique (un seul scroll vertical, pas de scroll horizontal) :
   on neutralise la mise en page « plein écran » (app-fit) sur le dashboard. */
body.dash-split { height: auto; display: block; overflow: visible; }
body.dash-split .topbar { position: sticky; top: 0; z-index: 50; }   /* reste visible au défilement */
body.dash-split > .content { flex: none; min-height: 0; overflow: visible; }
body.dash-split .content.is-home { display: block; overflow: visible; }
body.dash-split [data-spaces] { display: block; }
body.dash-split [data-screen].active { display: block; overflow: visible; }
body.dash-split [data-screen="accueil"].active .home-grid { align-items: start; }
body.dash-split [data-screen="accueil"].active .home-main,
body.dash-split [data-screen="accueil"].active .assistant-panel {
    min-height: 0; max-height: none; overflow: visible; padding-right: 0;
}
/* Le panneau « assistant » reste visible pendant le défilement de la page. */
body.dash-split [data-screen="accueil"].active .assistant-panel { position: sticky; top: 4.5rem; }
body.dash-split [data-screen].active > .tiles { overflow: visible; padding-right: 0; }

/* Sous 1100px (1 colonne) : on revient à un défilement de page classique. */
@media (max-width: 1100px) {
    body.dash-split { height: auto; display: block; overflow: visible; }
    body.dash-split > .content,
    body.dash-split .content.is-home,
    body.dash-split [data-spaces],
    body.dash-split [data-screen].active,
    body.dash-split [data-screen="accueil"].active,
    body.dash-split [data-screen="accueil"].active .home-main,
    body.dash-split [data-screen="accueil"].active .assistant-panel {
        display: block;
        overflow: visible;
        min-height: 0;
        max-height: none;
        padding-right: 0;
    }
}

/* --- Placeholder « vie scolaire » (chat à intégrer plus tard) --- */
.vs-placeholder {
    display: flex;
    align-items: center;
    gap: .9rem;
    padding: 1.1rem 1.25rem;
    background: var(--card);
    border: 1px dashed var(--line);
    border-radius: var(--radius);
    color: var(--muted);
}
.vs-ph-ico { font-size: 1.8rem; flex: none; }
.vs-ph-title { margin: 0; font-weight: 700; color: var(--ink); display: flex; align-items: center; gap: .5rem; }
.vs-ph-desc { margin: .15rem 0 0; font-size: .88rem; }

/* --- Module « Mes équipes » embarqué dans le dashboard (sélecteur | chat) --- */
/* Titre de section « Vie scolaire » : au-dessus du hub, séparé du chat (façon Pauline). */
.vs-section-head { margin: .4rem 0 .8rem; }
.vs-section-head h2 { margin: 0; font-size: 1.4rem; }
.vs-section-head p { margin: .15rem 0 0; color: var(--muted); font-size: .92rem; }
/* Ligne de titre : « Vie scolaire » à gauche, raccourci Chat à droite (même ligne). */
.vs-sh-row { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
.vs-chat-link {
    display: inline-flex; align-items: center; gap: .4rem;
    padding: .35rem .85rem; border-radius: 999px;
    background: var(--card); color: var(--primary-dark);
    border: 1px solid var(--line);
    font-weight: 700; font-size: .92rem; text-decoration: none; white-space: nowrap;
    transition: background .15s ease, color .15s ease, border-color .15s ease, transform .15s ease;
}
.vs-chat-link:hover { background: var(--primary); color: #fff; border-color: var(--primary); transform: translateY(-1px); }
.vs-chat-ico { font-size: 1.05rem; line-height: 1; }
.vs-chat-badge {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 1.35rem; height: 1.35rem; padding: 0 .35rem; margin-left: .1rem;
    border-radius: 999px; background: #dc2626; color: #fff; font-size: .75rem; font-weight: 800;
}

/* Le Turbo Frame autour de la section messagerie est transparent au layout. */
#dash-msg-frame { display: contents; }
.dash-msg {
    display: grid;
    grid-template-columns: 76px minmax(0, 1fr);   /* rail étroit façon Teams + fil */
    gap: 1rem;
    align-items: start;     /* hauteur auto : le fil vit sur la PAGE (pas de cadre qui scrolle) */
    margin-top: 1.2rem;
    width: 100%;            /* s'aligne à droite avec la rangée de cartes (carte verte) */
}
/* La colonne de gauche ne porte plus de carte : c'est le rail .vs-rail-mini qui
   est la carte (et qui gère son propre sticky). */
.dash-msg-nav { min-width: 0; }
/* Dans le dashboard, c'est la colonne entière qui scrolle (pas chaque liste). */
.dash-msg-nav .msg-nav-list { max-height: none; }
/* Pastille avatar (façon Teams) dans les sélecteurs de canaux/conversations. */
.msg-nav-ico { display: inline-flex; align-items: center; justify-content: center; flex: none; }
.msg-nav-ico .avatar { width: 26px; height: 26px; font-size: .7rem; }
.dash-msg-chat {
    min-width: 0;
    min-height: 0;
    /* Pas de panneau autour ; pas de scroll interne : le fil vit sur la page. */
    background: transparent;
    border: none;
    border-radius: 0;
    overflow: visible;
}
.dash-msg-chat .chat { height: auto; min-height: 0; }
/* Vie Scolaire : le fil défile avec la PAGE (pas de zone scrollable interne). */
.dash-msg-chat .chat.vs-hub { overflow: visible; }
.chat.vs-hub .chat-feed { flex: none; overflow: visible; max-height: none; padding: 0; background: none; }

@media (max-width: 1100px) {
    .dash-msg { grid-template-columns: 1fr; height: auto; }
    .dash-msg-nav { max-height: 40vh; }
    .dash-msg-chat { height: 70vh; }
}

/* --- Panneau assistant (sticky) --- */
.assistant-panel {
    position: sticky;
    top: 1rem;
    display: flex;
    flex-direction: column;
    gap: .9rem;
}

/* En-tête : salutation + date */
.ap-hello {
    border-radius: var(--radius);
    padding: 1.1rem 1.25rem;
    color: #fff;
    background: linear-gradient(135deg, #6d5efc 0%, #8b7bff 100%);
    box-shadow: 0 14px 30px -16px rgba(109, 94, 252, .7);
}
.ap-hello-greet { margin: 0; font-family: "Baloo 2", sans-serif; font-weight: 800; font-size: 1.3rem; }
.ap-hello-date { margin: .15rem 0 0; font-size: .85rem; opacity: .9; text-transform: capitalize; }

/* Carte générique de widget */
.ap-card {
    display: block;
    background: var(--card);
    border: 1px solid var(--line);
    border-left: 3px solid var(--line);
    border-radius: var(--radius-sm);
    padding: .95rem 1.05rem;
    text-decoration: none;
    color: var(--ink);
    box-shadow: 0 6px 18px -14px rgba(31, 36, 64, .5);
    transition: transform .15s ease, box-shadow .15s ease, border-color .15s ease;
}
a.ap-card:hover { transform: translateY(-2px); box-shadow: 0 12px 26px -14px rgba(31, 36, 64, .55); }

.ap-card-h {
    display: flex;
    align-items: center;
    gap: .45rem;
    margin: 0 0 .7rem;
    font-size: .82rem;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--muted);
}
.ap-card-h .ap-ico { font-size: 1rem; }

.ap-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .65rem; }
.ap-empty { margin: 0; color: var(--muted); font-size: .9rem; }
.ap-more { display: inline-block; margin-top: .8rem; font-size: .82rem; font-weight: 700; color: var(--primary-dark); }

/* Agenda */
.ap-agenda { border-left-color: #6d5efc; }
.ap-event { display: grid; grid-template-columns: auto 3.4rem 1fr; align-items: baseline; gap: .55rem; color: inherit; text-decoration: none; }
a.ap-event:hover .ap-event-title { text-decoration: underline; }
.ap-dot { width: 9px; height: 9px; border-radius: 50%; align-self: center; flex: none; }
.ap-event-time { font-variant-numeric: tabular-nums; font-weight: 700; font-size: .82rem; color: var(--muted); white-space: nowrap; }
.ap-event-body { min-width: 0; display: flex; flex-direction: column; }
.ap-event-title { font-weight: 600; font-size: .92rem; line-height: 1.3; }
.ap-event-sub { font-size: .78rem; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* À faire */
.ap-tasks { border-left-color: #f59e0b; }
.ap-task { display: grid; grid-template-columns: auto 1fr; align-items: baseline; gap: .55rem; }
.ap-task-check { color: var(--muted); font-size: .9rem; line-height: 1.3; }
.ap-task-body { min-width: 0; display: flex; flex-direction: column; }
.ap-task-title { font-weight: 600; font-size: .92rem; line-height: 1.3; color: inherit; text-decoration: none; }
.ap-task-due { font-size: .76rem; font-weight: 700; color: var(--muted); }
.ap-task.is-late .ap-task-due, .ap-task.is-late .ap-task-check { color: #dc2626; }
.ap-task.is-today .ap-task-due, .ap-task.is-today .ap-task-check { color: #ea580c; }

/* Présences : les deux gestes du jour (appels à faire, pièces à encoder). */
.ap-presences { border-left-color: #16a34a; }
.pw-stats { gap: .45rem; }
/* Sépare les deux gestes du jour de la ligne de veille « cohérence », qui n'est pas un geste
   du jour mais un voyant. `<li>` et non `<div>` : un enfant direct de `<ul>` doit en être un. */
.pw-sep { height: 1px; margin: .15rem .55rem; background: var(--line, #e5e7eb); }
.pw-stat {
    display: flex;
    align-items: center;
    gap: .7rem;
    padding: .5rem .55rem;
    border-radius: 10px;
    color: inherit;
    text-decoration: none;
    transition: background .15s;
}
.pw-stat:hover { background: var(--primary-soft); }
.pw-n {
    flex: none;
    min-width: 2.1rem;
    text-align: center;
    font-family: "Baloo 2", sans-serif;
    font-weight: 800;
    font-size: 1.5rem;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    color: var(--muted);
}
.pw-stat.is-todo .pw-n { color: #dc2626; }
.pw-stat.is-wait .pw-n { color: #ea580c; }
.pw-stat.is-ok .pw-n { color: #16a34a; }
/* Arriéré d'appels : le seul voyant de la carte qui parle du PASSÉ, et le plus urgent — il
   doit se voir SANS lire, d'où le rouge plein, le filet vertical et le liseré de la carte. */
.pw-stat.is-arriere {
    background: #fee2e2;
    border: 1px solid #fca5a5;
    border-left: 4px solid #dc2626;
}
.pw-stat.is-arriere:hover { background: #fecaca; }
.pw-stat.is-arriere .pw-n, .pw-stat.is-arriere .pw-t { color: #b91c1c; }
.pw-stat.is-arriere .pw-s { color: #b91c1c; }
.ap-presences.has-arriere { border-left-color: #dc2626; }

/* Alerte « registre FWB » : mêmes rouges que le KPI « En échec » de l'écran d'envoi APP100. */
.pw-stat.is-err { background: #fee2e2; }
.pw-stat.is-err:hover { background: #fecaca; }
.pw-stat.is-err .pw-n { color: #b91c1c; }
.pw-stat.is-err .pw-t { color: #b91c1c; }
.pw-body { min-width: 0; display: flex; flex-direction: column; }
.pw-t { font-weight: 600; font-size: .92rem; line-height: 1.3; }
.pw-s { font-size: .78rem; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Carte « Dernière activité » (liseré) */
.ap-message { border-left-color: #18b6a4; }

/* Boîte « Dernière activité » (mini-fil des derniers messages reçus). */
.ap-feed { list-style: none; margin: .2rem 0 0; padding: 0; display: flex; flex-direction: column; gap: .15rem; }
.ap-feed-empty { margin: .3rem 0 0; font-size: .9rem; color: var(--muted); }
.ap-feed-item { border-radius: 10px; }
.ap-feed-link { display: flex; gap: .55rem; align-items: flex-start; padding: .5rem .55rem; border-radius: 10px; color: inherit; text-decoration: none; transition: background .15s; }
.ap-feed-link:hover { background: var(--primary-soft); }
.ap-feed-av { flex: none; margin-top: .1rem; }
.ap-feed-body { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: .05rem; }
.ap-feed-head { display: flex; align-items: baseline; justify-content: space-between; gap: .5rem; }
.ap-feed-source { font-size: .72rem; font-weight: 700; color: var(--brand); text-transform: uppercase; letter-spacing: .02em; white-space: nowrap; }
.ap-feed-time { font-size: .72rem; color: var(--muted); white-space: nowrap; flex: none; }
.ap-feed-title { font-size: .85rem; font-weight: 600; color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ap-feed-preview { font-size: .85rem; line-height: 1.35; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ap-feed-item.is-unread .ap-feed-link { background: color-mix(in srgb, var(--primary-soft) 70%, transparent); }
.ap-feed-item.is-unread .ap-feed-title { font-weight: 800; }
.ap-feed-item.is-unread .ap-feed-source::before { content: "● "; color: var(--primary); font-size: .7em; }

/* En-tête de la colonne : salutation + bouton réglages. */
.ap-hello { display: flex; align-items: flex-start; justify-content: space-between; gap: .5rem; }
.ap-prefs { position: relative; flex: none; }
.ap-prefs-btn { border: 0; background: transparent; cursor: pointer; font-size: 1.05rem; line-height: 1; padding: .25rem; border-radius: 8px; opacity: .6; transition: opacity .15s, background .15s; }
.ap-prefs-btn:hover { opacity: 1; background: var(--primary-soft); }

/* Modale de personnalisation (hérite de dialog.modal). */
.prefs-dialog form { display: flex; flex-direction: column; gap: .8rem; padding: 1.4rem; min-width: 320px; }
.prefs-dialog h3 { margin: 0; font-family: "Baloo 2", sans-serif; }
.prefs-dialog .muted { margin: 0; }
.prefs-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .4rem; }
.prefs-item { display: flex; align-items: center; gap: .55rem; padding: .55rem .6rem; border: 1px solid rgba(31,36,64,.12); border-radius: 10px; background: #fff; cursor: grab; user-select: none; }
.prefs-item:active { cursor: grabbing; }
.prefs-item.dragging { opacity: .4; }
.prefs-grip { color: var(--muted); font-size: 1.15rem; line-height: 1; }
.prefs-ico { font-size: 1.05rem; }
.prefs-label { font-weight: 600; }
.prefs-count { display: flex; align-items: center; justify-content: space-between; gap: .6rem; font-weight: 600; }
.prefs-count input { width: 4rem; padding: .35rem .5rem; border: 1px solid rgba(31,36,64,.18); border-radius: 8px; font: inherit; }
/* Le 4rem ci-dessus vise le compteur (un nombre à un chiffre) : un nom de ville n'y tient pas,
   et une case à cocher étirée sur 4rem est un rectangle bizarre. */
.prefs-count input[type="text"] { width: 11rem; }
.prefs-check input[type="checkbox"] { width: auto; padding: 0; }
.prefs-dialog menu { display: flex; justify-content: flex-end; gap: .6rem; margin: 0; padding: 0; list-style: none; }

/* Alerte « assistant directeur » */
.ad-alert-row { display: flex; flex-wrap: wrap; gap: .4rem; margin-bottom: .6rem; }
.ad-alert-pill { font-size: .76rem; font-weight: 700; border-radius: 999px; padding: .15rem .55rem; }
.ad-alert-pill.is-retard { background: #fee2e2; color: #dc2626; }
.ad-alert-pill.is-urgent { background: #ffedd5; color: #ea580c; }
.ad-alert-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .4rem; }
.ad-alert-list li { display: flex; align-items: baseline; gap: .45rem; font-size: .86rem; line-height: 1.3; }
.ad-alert-dot { width: 8px; height: 8px; border-radius: 50%; flex: none; align-self: center; }

/* Stat d'encouragement */
.ap-streak {
    display: flex;
    align-items: center;
    gap: .6rem;
    padding: .85rem 1rem;
    border-radius: var(--radius-sm);
    background: var(--primary-soft);
    color: var(--primary-dark);
    font-size: .88rem;
    line-height: 1.35;
}
.ap-streak-ico { font-size: 1.3rem; flex: none; }

/* Apparition en cascade des widgets */
.ap-anim { opacity: 0; animation: ap-in .5s cubic-bezier(.22, 1, .36, 1) forwards; animation-delay: calc(var(--i, 0) * .07s); }
@keyframes ap-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .ap-anim { animation: none; opacity: 1; } }

/* --- Fil d'Ariane --- */
.crumbs { display: flex; align-items: center; flex-wrap: wrap; gap: .35rem; margin: 0 0 1.2rem; font-size: .9rem; }
.crumbs a { color: var(--muted); text-decoration: none; font-weight: 600; border: none; background: none; cursor: pointer; font: inherit; font-weight: 600; padding: 0; }
.crumbs a:hover { color: var(--brand-dark); }
.crumbs .sep { color: var(--line); }
.crumbs .here { color: var(--ink); font-weight: 700; }

/* --- En-tête d'espace --- */
.space-head { display: flex; align-items: center; gap: .85rem; margin: 0 0 1.3rem; }
.space-head .sh-ico {
    width: 56px; height: 56px; border-radius: 16px;
    display: grid; place-items: center; font-size: 1.9rem; color: #fff; flex: none;
}
/* Même dégradé que les grandes cartes du dashboard (.space-ecole/classe/cartable). */
.space-head.is-ecole .sh-ico    { background: linear-gradient(135deg, #6d5efc 0%, #8b7bff 55%, #b8acff 100%); }
.space-head.is-classe .sh-ico   { background: linear-gradient(135deg, #ff8a5c 0%, #ff6f91 60%, #ffa36c 100%); }
.space-head.is-cartable .sh-ico { background: linear-gradient(135deg, #18b6a4 0%, #2bd4b0 55%, #7ee8c4 100%); }
.space-head h2 { margin: 0; font-size: 1.5rem; }
.space-head p { margin: .1rem 0 0; color: var(--muted); font-size: .92rem; }

/* --- Grille de tuiles de modules --- */
.tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 1rem; }
/* En-tête de rubrique : occupe toute la largeur → les tuiles d'un même thème
   démarrent sur une nouvelle ligne (séparateur logique + filet). */
.tiles-group {
    grid-column: 1 / -1;
    display: flex;
    align-items: center;
    gap: .6rem;
    margin: .6rem 0 -.3rem;
    font-size: .78rem;
    font-weight: 700;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--muted);
}
.tiles-group:first-child { margin-top: 0; }
.tiles-group::after { content: ""; flex: 1; height: 1px; background: var(--line); }
.tile {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: .35rem;
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    padding: 1.05rem 1.1rem;
    text-decoration: none;
    color: var(--ink);
    cursor: pointer;
    transition: transform .15s ease, box-shadow .15s ease, border-color .15s ease;
}
.tile:hover { transform: translateY(-3px); box-shadow: var(--shadow); border-color: var(--primary); }
.tile .tile-ico { font-size: 1.9rem; line-height: 1; }
.tile .tile-name { font-weight: 700; font-size: 1rem; }
.tile .tile-desc { font-size: .82rem; color: var(--muted); line-height: 1.3; }
/* Module non développé, vu par la DIRECTION : case normale + badge « Bientôt » (repère roadmap). */
.tile.is-soon { cursor: default; box-shadow: none; }
.tile.is-soon:hover { transform: none; box-shadow: none; border-color: var(--line); }
/* Module non accessible, vu par un NON-gestionnaire (prof) : case entièrement grisée, sans badge. */
.tile.is-soon.is-locked { background: var(--bg); border-color: var(--line); }
.tile.is-soon.is-locked .tile-ico { filter: grayscale(1); opacity: .45; }
.tile.is-soon.is-locked .tile-name { color: var(--muted); }
.tile.is-soon.is-locked .tile-desc { opacity: .8; }
.tile .tile-badge {
    position: absolute; top: .7rem; right: .7rem;
    font-size: .68rem; font-weight: 700; letter-spacing: .02em;
    background: var(--primary-soft); color: var(--primary-dark);
    border-radius: 999px; padding: .12rem .5rem;
}
.tile.is-soon .tile-badge { background: #eef0f6; color: var(--muted); }

/* ===== Messagerie (Mes équipes & Vie scolaire) ===== */

/* Rail vertical d'icônes (bande gauche façon Teams). */
.vs-hub { display: grid; grid-template-columns: 76px minmax(0, 1fr); gap: 1.2rem; align-items: start; }
.vs-rail-mini {
    position: sticky; top: 0; align-self: start;
    max-height: calc(100vh - 2rem);
    display: flex; flex-direction: column; align-items: center; gap: .5rem;
    background: var(--card); border: 1px solid var(--line); border-radius: 18px;
    padding: .7rem .5rem;
}
.vs-rail-mini .vs-rail-list {
    display: flex; flex-direction: column; align-items: center; gap: .5rem;
    overflow-y: auto; flex: 1; min-height: 0; width: 100%; padding: .25rem 0;
}
.vs-mini-sep {
    width: 100%; font-size: .62rem; font-weight: 800; letter-spacing: .05em;
    color: var(--muted); text-align: center; padding: .3rem 0 .1rem;
    border-top: 1px solid var(--line); margin-top: .2rem;
}
.vs-mini-label {
    display: block; font-size: .65rem; font-weight: 600; color: var(--muted);
    text-align: center; max-width: 64px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    margin-top: .2rem; line-height: 1.2;
}
.vs-mini-item {
    position: relative; display: flex; flex-direction: column; align-items: center;
    text-decoration: none; gap: 0; flex: none; border: none; background: none; cursor: pointer;
    padding: 0; font-family: inherit;
}
.vs-mini-av {
    width: 46px; height: 46px; border-radius: 16px;
    display: grid; place-items: center; font-weight: 800; font-size: 1.2rem;
    /* Couleurs personnalisables par canal (cf. modale de création) ; défaut violet. */
    background: var(--tile-bg, var(--primary-soft)); color: var(--tile-fg, var(--primary-dark));
    user-select: none; transition: border-radius .15s ease, transform .12s ease, box-shadow .15s ease;
}
.vs-mini-item:hover .vs-mini-av { border-radius: 12px; transform: translateY(-1px); box-shadow: var(--shadow, 0 4px 14px rgba(31,36,64,.12)); }
/* Tuile active : on GARDE sa couleur (cf. couleur choisie) ; l'état actif est une
   barre latérale (façon Teams), pas un écrasement de couleur. */
/* Conversation sélectionnée : la tuile garde sa couleur et est ENTOURÉE proprement. */
.vs-mini-item.is-active .vs-mini-av { border-radius: 13px; outline: 2px solid var(--primary); outline-offset: 2px; }
.vs-mini-badge {
    position: absolute; top: -4px; right: -4px;
    min-width: 18px; height: 18px; padding: 0 4px; border-radius: 999px;
    background: #dc2626; color: #fff; font-size: .68rem; font-weight: 800;
    display: inline-flex; align-items: center; justify-content: center;
    box-shadow: 0 0 0 2px var(--card);
}
.vs-mini-add {
    width: 46px; height: 46px; border-radius: 16px; flex: none;
    display: grid; place-items: center; font-size: 1.4rem; text-decoration: none;
    color: var(--primary-dark); background: var(--primary-soft);
    border: none; cursor: pointer; font-family: inherit;   /* reset bordure native du <button> */
    transition: background .12s, color .12s;
}
.vs-mini-add:hover { background: var(--primary); color: #fff; }
.vs-mini-add:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
/* Séparateur (trait) entre les conversations et le bouton ＋. */
.vs-mini-div { width: 56%; height: 1px; border: none; background: var(--line); margin: .35rem 0; flex: none; }

/* Modale de création Vie Scolaire : libellés de champ + choix des couleurs. */
.vs-field-label { display: block; font-weight: 700; color: var(--ink); margin: .7rem 0 .25rem; font-size: .92rem; }
.vs-field-label .muted { font-weight: 500; }
.vs-color-row { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; }
.vs-color { display: inline-flex; align-items: center; gap: .4rem; font-size: .88rem; color: var(--muted); cursor: pointer; }
.vs-color input[type="color"] { width: 38px; height: 30px; border: 1px solid var(--line); border-radius: 8px; background: none; cursor: pointer; padding: 2px; }
.vs-color-preview {
    margin-left: auto; width: 46px; height: 46px; border-radius: 14px;
    display: grid; place-items: center; font-weight: 800; font-size: 1.15rem;
}
/* Sélection des implantations (cases à cocher) — filtre les membres. */
.vs-impl-pick { display: flex; flex-wrap: wrap; gap: .4rem; }
.vs-impl-chip {
    display: inline-flex; align-items: center; gap: .35rem; cursor: pointer;
    border: 1px solid var(--line); border-radius: 999px; padding: .25rem .65rem; font-size: .85rem;
}
.vs-impl-chip:hover { border-color: var(--primary); background: var(--primary-soft); }
.vs-impl-chip input { margin: 0; }
/* Titre de section : « Vie scolaire — <nom> » + engrenage de modification. */
.vs-section-head .vs-sh-sep { color: var(--muted); font-weight: 400; }
.vs-section-head .vs-sh-canal { color: var(--primary); }
/* Pastille « somme » des non-lus, à côté du titre Vie scolaire. */
.vs-sh-badge {
    display: inline-flex; align-items: center; justify-content: center; vertical-align: middle;
    min-width: 1.5rem; height: 1.5rem; padding: 0 .4rem; margin-left: .4rem;
    border-radius: 999px; background: #dc2626; color: #fff; font-size: .8rem; font-weight: 800;
}
.vs-pane { min-width: 0; }
@media (max-width: 860px) {
    .vs-hub { grid-template-columns: 64px minmax(0, 1fr); gap: .7rem; }
    .vs-rail-mini { position: static; max-height: none; }
}

/* Volet principal (pane) */
.vs-pane .vs { margin-top: 1.2rem; padding-top: 1.2rem; }

/* ============================================================
   Vie scolaire : fil de discussion partagé (style Teams léger)
   ============================================================ */
.vs { margin-top: 2.2rem; padding-top: 1.6rem; border-top: 1px solid var(--line); }
.vs-head { margin-bottom: 1rem; }
.vs-head h2 { margin: 0; font-size: 1.4rem; }
.vs-head p { margin: .15rem 0 0; color: var(--muted); font-size: .92rem; }

.vs-composer { padding: 1rem; margin-bottom: 1.3rem; }
.vs-input { resize: vertical; min-height: 2.6rem; }
.vs-composer-bar { display: flex; align-items: center; gap: .7rem; margin-top: .7rem; flex-wrap: wrap; }
.vs-attach {
    display: inline-flex; align-items: center; gap: .35rem;
    padding: .5rem .8rem; border-radius: var(--radius-sm);
    cursor: pointer; font-weight: 600; font-size: .9rem; width: auto;
}
.vs-files-hint { font-size: .82rem; flex: 1; min-width: 120px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vs-send { width: auto; }

.vs-feed { display: flex; flex-direction: column; gap: .8rem; }
.vs-msg { display: flex; gap: .85rem; padding: .9rem 1rem; align-items: flex-start; }
.vs-msg-avatar {
    width: 42px; height: 42px; border-radius: 50%; flex: none;
    display: grid; place-items: center; color: #fff; font-weight: 700; font-size: .95rem;
}
.vs-msg-main { flex: 1; min-width: 0; }
.vs-msg-head { display: flex; align-items: center; gap: .55rem; min-height: 1.75rem; }
.vs-msg-author { font-weight: 700; }
.vs-msg-time { color: var(--muted); font-size: .8rem; }
.vs-msg-del { margin-left: auto; }
.vs-msg-del button { background: none; border: none; cursor: pointer; font-size: .95rem; padding: 0; line-height: 1; }
.vs-msg-body { margin-top: .3rem; line-height: 1.45; white-space: pre-line; word-wrap: break-word; }
.vs-attachments { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: .6rem; }
.vs-chip {
    display: inline-flex; align-items: center; gap: .45rem; max-width: 100%;
    background: var(--bg); border: 1px solid var(--line); border-radius: 999px;
    padding: .35rem .7rem; text-decoration: none; color: var(--ink);
    font-size: .85rem; transition: border-color .15s ease, background .15s ease;
}
.vs-chip:hover { border-color: var(--primary); background: var(--primary-soft); }
.vs-chip-ico { font-size: 1.05rem; line-height: 1; }
.vs-chip-name { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 18ch; }
.vs-chip-size { color: var(--muted); font-size: .78rem; flex: none; }

/* Aperçu des images jointes (façon Teams) */
.vs-img-wrap {
    position: relative; display: inline-block; border-radius: 12px; overflow: hidden;
    border: 1px solid var(--line); line-height: 0; max-width: 100%;
}
.vs-img { display: block; max-width: 260px; max-height: 220px; width: auto; height: auto; object-fit: cover; }
.vs-img-dl {
    position: absolute; top: .4rem; right: .4rem; background: rgba(0,0,0,.55); color: #fff;
    border-radius: 999px; width: 1.7rem; height: 1.7rem; display: flex; align-items: center;
    justify-content: center; font-size: .9rem; opacity: 0; transition: opacity .15s ease;
}
.vs-img-wrap:hover .vs-img-dl { opacity: 1; }

/* Barre d'actions d'un message : j'aime + répondre */
.vs-msg-actions { display: flex; align-items: center; gap: .4rem; margin-top: .55rem; flex-wrap: wrap; }
.vs-like { margin: 0; }
.vs-like-btn, .vs-act-btn {
    display: inline-flex; align-items: center; gap: .35rem; cursor: pointer;
    background: none; border: 1px solid transparent; border-radius: 999px;
    padding: .25rem .6rem; font-size: .82rem; font-weight: 600; color: var(--muted);
    transition: background .15s ease, color .15s ease, border-color .15s ease;
}
.vs-like-btn:hover, .vs-act-btn:hover { background: var(--primary-soft); color: var(--primary); }
.vs-like-btn.on { color: var(--primary); background: var(--primary-soft); }
.vs-like-ico { font-size: 1rem; line-height: 1; }
.vs-like-count { font-variant-numeric: tabular-nums; }
.vs-rep-count { color: var(--muted); font-size: .8rem; margin-left: .3rem; }

/* Réponses en fil */
.vs-replies {
    margin: .6rem 0 0;
    display: flex; flex-direction: column; gap: .55rem;
}
.vs-reply {
    display: flex; gap: .6rem; align-items: flex-start;
    background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius-sm);
    padding: .6rem .7rem;
}
.vs-reply-avatar {
    flex: none; width: 1.9rem; height: 1.9rem; border-radius: 50%; color: #fff;
    display: flex; align-items: center; justify-content: center; font-size: .72rem; font-weight: 700;
}
.vs-reply-main { flex: 1; min-width: 0; }
/* Corbeille « supprimer ma réponse » : poussée à droite, discrète, nette au survol. */
.vs-reply-del { margin-left: auto; }
.vs-reply-del .vs-act-btn { padding: 0 .25rem; opacity: .45; transition: opacity .12s; }
.vs-reply:hover .vs-reply-del .vs-act-btn,
.vs-reply-del .vs-act-btn:focus-visible { opacity: 1; }
.vs-reply-form { margin-top: .6rem; }
.vs-reply-form .vs-input { width: 100%; }
/* Champ de réponse rattaché au fil (dashboard) : masqué, révélé par ↩︎ via la bascule,
   s'ouvre EN BAS du message (après ses réponses). */
.vs-reply-area { display: none; margin-top: .6rem; }
.vs-reply-toggle:checked ~ .vs-reply-area { display: block; }
.vs-edit-form { margin-top: .5rem; }
.vs-edit-form .vs-input { width: 100%; }
.vs-inline-form { display: inline; margin: 0; }
.vs-edited { color: var(--muted); font-size: .78rem; font-style: italic; }
.vs-subject { font-weight: 800; font-size: 1.02rem; margin: .15rem 0 .25rem; color: var(--ink); }
.vs-subject-toggle {
    align-self: flex-start; background: none; border: none; cursor: pointer; padding: .1rem 0;
    color: var(--primary); font-weight: 600; font-size: .85rem;
}
.vs-subject-input { margin-bottom: .5rem; font-weight: 700; }
.vs-pin-badge { margin-left: .2rem; }
.vs-msg.is-pinned { border-color: var(--primary); box-shadow: inset 3px 0 0 var(--primary); }
.vs-act-danger { color: var(--danger, #f0463f); }

/* Mentions */
.vs-mention { color: var(--primary); background: var(--primary-soft); border-radius: 5px; padding: 0 .25rem; font-weight: 600; }
.vs-mention-box {
    position: absolute; z-index: 1000; background: var(--card, #fff); border: 1px solid var(--line);
    border-radius: 10px; box-shadow: 0 8px 24px rgba(0,0,0,.14); overflow: hidden; max-height: 240px; overflow-y: auto;
}
.vs-mention-item { padding: .45rem .7rem; cursor: pointer; font-size: .9rem; }
.vs-mention-item.on, .vs-mention-item:hover { background: var(--primary-soft); color: var(--primary); }

/* Réactions emoji */
.vs-reacts { display: inline-flex; align-items: center; gap: .3rem; flex-wrap: wrap; }
.vs-react {
    display: inline-flex; align-items: center; gap: .25rem; cursor: pointer;
    border: 1px solid var(--line); background: var(--bg); border-radius: 999px;
    padding: .12rem .5rem; font-size: .85rem; line-height: 1.3; transition: border-color .15s, background .15s;
}
.vs-react:hover { border-color: var(--primary); }
.vs-react.on { border-color: var(--primary); background: var(--primary-soft); color: var(--primary); font-weight: 700; }
.vs-react-n { font-variant-numeric: tabular-nums; font-size: .8rem; }
.vs-react-add { position: relative; display: inline-flex; }
.vs-react-add-btn {
    cursor: pointer; border: 1px dashed var(--line); background: none; border-radius: 999px;
    padding: .12rem .5rem; font-size: .85rem; color: var(--muted); line-height: 1.3;
}
.vs-react-add-btn:hover { border-color: var(--primary); color: var(--primary); }
.vs-react-pop {
    display: none; position: absolute; bottom: 130%; left: 0; z-index: 50;
    background: var(--card, #fff); border: 1px solid var(--line); border-radius: 999px;
    padding: .25rem .35rem; gap: .15rem; box-shadow: 0 8px 24px rgba(0,0,0,.16);
}
.vs-react-pop.open { display: inline-flex; }
.vs-react-pick { cursor: pointer; border: none; background: none; font-size: 1.25rem; padding: .15rem .25rem; border-radius: 8px; line-height: 1; }
.vs-react-pick:hover { background: var(--primary-soft); transform: scale(1.15); }

/* Barre d'outils : recherche + épinglés */
.vs-toolbar { display: flex; gap: .6rem; margin: 0 0 .8rem; }
.vs-search { position: relative; flex: 1; }
.vs-search-input { width: 100%; }
.vs-search-clear {
    position: absolute; right: .5rem; top: 50%; transform: translateY(-50%);
    border: none; background: none; cursor: pointer; color: var(--muted); font-size: 1rem;
}
.vs-pinned { margin-bottom: .9rem; border: 1px solid var(--line); border-radius: 12px; padding: .5rem .8rem; background: var(--bg); }
.vs-pinned > summary { cursor: pointer; font-weight: 700; color: var(--primary); }
.vs-pinned-feed { margin-top: .7rem; }
.vs-search-results { padding: .6rem; }
.vs-search-head { font-weight: 700; margin-bottom: .6rem; color: var(--muted); }

/* Équipes / canaux : membres et sélecteur de personnel */
.vs-members { margin-bottom: 1.3rem; }
.vs-members > summary { cursor: pointer; font-weight: 700; }
.vs-member-list { display: flex; flex-wrap: wrap; gap: .5rem; margin: .8rem 0; }
.vs-member-chip {
    display: inline-flex; align-items: center; gap: .35rem;
    background: var(--bg); border: 1px solid var(--line); border-radius: 999px;
    padding: .25rem .7rem; font-size: .85rem; font-weight: 600;
}
.vs-member-chip .link-danger { font-size: .85rem; line-height: 1; }
.vs-roster {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: .3rem .8rem; max-height: 240px; overflow-y: auto;
    border: 1px solid var(--line); border-radius: var(--radius-sm);
    padding: .7rem .8rem; margin-top: .3rem; background: var(--bg);
}
.vs-roster-item { display: flex; align-items: center; gap: .45rem; font-size: .9rem; cursor: pointer; }
.vs-roster-item input { width: auto; }
.vs-add-members { margin-top: .6rem; }
.vs-member-actions { margin-top: 1rem; padding-top: .8rem; border-top: 1px solid var(--line); }

/* Barre d'actions du composer (pièce jointe + envoi). */
.vs-composer-actions { display: flex; align-items: center; gap: .7rem; margin-top: .7rem; flex-wrap: wrap; }

/* Sujet d'un message (fil général / équipe). */
.vs-msg-sujet { font-weight: 800; font-size: 1.02rem; margin: .2rem 0 .3rem; color: var(--ink); }

/* Formulaires d'action inline sur un message (supprimer / épingler / éditer). */
.vs-act-delete, .vs-act-pin, .vs-act-edit { display: inline; margin: 0; }
.vs-act-delete button, .vs-act-pin button {
    background: none; border: none; cursor: pointer; font-size: 1rem; padding: .15rem .3rem;
    border-radius: 6px; line-height: 1; color: var(--muted); transition: background .12s, color .12s;
}
.vs-act-delete button:hover { background: #fee2e2; color: #dc2626; }
.vs-act-pin button:hover { background: var(--primary-soft); color: var(--primary); }
.vs-act-edit { display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; }
.vs-act-edit input { flex: 1; min-width: 120px; }
.vs-act-edit button { background: none; border: none; cursor: pointer; font-size: 1rem; padding: .15rem .3rem; border-radius: 6px; line-height: 1; }
.vs-act-edit button:hover { background: var(--primary-soft); color: var(--primary); }

/* Pièces jointes en pastilles. */
.vs-files { display: flex; flex-wrap: wrap; gap: .4rem; margin-top: .5rem; }
.vs-file {
    display: inline-flex; align-items: center; gap: .35rem;
    background: var(--bg); border: 1px solid var(--line); border-radius: 999px;
    padding: .25rem .65rem; font-size: .84rem; text-decoration: none; color: var(--ink);
    transition: border-color .12s, background .12s;
}
.vs-file:hover { border-color: var(--primary); background: var(--primary-soft); }

/* Zone réactions d'un message. */
.vs-msg-react { margin-top: .45rem; }
.vs-reactions-bar { display: flex; flex-wrap: wrap; gap: .3rem; margin-bottom: .2rem; }
.vs-reaction {
    display: inline-flex; align-items: center; gap: .2rem; cursor: pointer;
    border: 1px solid var(--line); background: var(--bg); border-radius: 999px;
    padding: .1rem .45rem; font-size: .85rem; line-height: 1.3;
    transition: border-color .12s, background .12s;
}
.vs-reaction:hover { border-color: var(--primary); background: var(--primary-soft); }
.vs-reaction.is-mine { border-color: var(--primary); background: var(--primary-soft); color: var(--primary); font-weight: 700; }
.vs-react-picker { display: flex; gap: .15rem; flex-wrap: wrap; }
.vs-react-btn {
    cursor: pointer; border: none; background: none; font-size: 1.15rem; padding: .1rem .2rem;
    border-radius: 7px; line-height: 1; transition: background .1s, transform .1s;
}
.vs-react-btn:hover { background: var(--primary-soft); transform: scale(1.18); }

/* Épinglés : élément dans le <details> (pas la bulle principale). */
.vs-pin-item {
    padding: .35rem .5rem; border-radius: 8px; font-size: .88rem; line-height: 1.4;
    border-left: 3px solid var(--primary); background: var(--primary-soft); margin-bottom: .3rem;
}

/* Modale « Nouvelle équipe » (native <dialog>). */
dialog.vs-new {
    border: none; padding: 0; border-radius: var(--radius);
    max-width: 480px; width: calc(100% - 2rem);
    box-shadow: 0 30px 80px rgba(31,36,64,.3);
    color: var(--ink); background: var(--card);
}
dialog.vs-new::backdrop { background: rgba(31,36,64,.45); }
dialog.vs-new form { display: flex; flex-direction: column; gap: .8rem; padding: 1.4rem; }
dialog.vs-new h3 { margin: 0 0 .4rem; font-family: "Baloo 2", sans-serif; }
dialog.vs-new menu { display: flex; justify-content: flex-end; gap: .6rem; margin: 0; padding: 0; list-style: none; }

/* ===================== Module Développement professionnel ===================== */
.stat-card { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 1rem 1.1rem; }
.stat-ico { font-size: 1.5rem; }
.stat-val { font-size: 1.8rem; font-weight: 800; line-height: 1.1; }
.stat-lbl { color: var(--muted); font-size: .85rem; font-weight: 600; }
.badge-danger { background: #fdecec; color: #c0392b; }

.dp-tabs { display: flex; gap: .4rem; flex-wrap: wrap; margin-bottom: 1rem; border-bottom: 1px solid var(--line); }
.dp-tab { text-decoration: none; color: var(--ink); font-weight: 600; padding: .55rem .9rem; border-radius: 10px 10px 0 0; }
.dp-tab:hover { background: var(--bg); }
.dp-tab.active { background: var(--primary-soft); color: var(--primary-dark); }
.dp-intro { background: var(--primary-soft); border: none; margin-bottom: 1.2rem; }
.dp-filters { display: flex; gap: .6rem; align-items: center; flex-wrap: wrap; }
.dp-add { margin: .8rem 0 1.2rem; }
.dp-add > summary { cursor: pointer; font-weight: 600; }
.dp-checks { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: .35rem .8rem; margin: .5rem 0 1rem; }
.dp-check { display: flex; align-items: center; gap: .45rem; font-size: .92rem; }
.dp-alertes { display: flex; flex-direction: column; gap: .5rem; }
.dp-alerte { padding: .6rem .9rem; border-radius: 10px; font-weight: 600; font-size: .92rem; }
.dp-al-info { background: #eef4ff; color: #1d4ed8; }
.dp-al-warn { background: #fff5e6; color: #b9770e; }
.dp-al-danger { background: #fdecec; color: #c0392b; }
.dp-histo { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: .35rem; font-size: .9rem; }
.dp-objs { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 1rem; }
.dp-obj-head { display: flex; justify-content: space-between; align-items: center; gap: .5rem; margin-bottom: .3rem; }
.dp-inline { display: inline; margin: 0; }
.dp-inline .input { margin-top: .4rem; }
.dp-signs { display: flex; gap: 1.5rem; flex-wrap: wrap; margin-bottom: .6rem; font-weight: 600; }
.dp-pdcp-list { display: flex; flex-direction: column; gap: .5rem; }
.dp-pdcp-row { display: flex; justify-content: space-between; align-items: center; text-decoration: none; color: var(--ink); padding: .8rem 1rem; }
.dp-pdcp-row:hover { border-color: var(--primary); }
.dp-locked { text-align: center; padding: 2.4rem 1.5rem; }
.dp-locked .big { font-size: 2.6rem; }
.dp-locked p { max-width: 60ch; margin: .6rem auto 0; color: var(--muted); }
.dp-propose { display: flex; justify-content: space-between; align-items: center; gap: 1rem; flex-wrap: wrap;
    background: #fff7e6; border: 1px solid #f0c060; }
.dp-propose-txt { min-width: 0; }
a.dp-propose:hover { border-color: var(--primary); }

/* ============================================================
   Doc du projet (dashboard super-admin)
   ============================================================ */
.doc-nav {
    position: sticky;
    top: 0;
    z-index: 5;
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    padding: .6rem 0;
    margin-bottom: 1rem;
    background: var(--bg);
    border-bottom: 1px solid var(--line);
}
.doc-nav a {
    text-decoration: none;
    font-size: .85rem;
    font-weight: 600;
    color: var(--muted);
    padding: .35rem .8rem;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: var(--card);
}
.doc-nav a:hover { color: var(--primary-dark); border-color: var(--primary); }

.doc-section { margin: 1.8rem 0 2.4rem; scroll-margin-top: 4rem; }
.doc-section > h2 { margin: 0 0 .6rem; }

.doc-card {
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    padding: 1rem 1.1rem;
    margin: 1rem 0;
    box-shadow: 0 6px 18px -14px rgba(31, 36, 64, .5);
}
.doc-card-head { display: flex; align-items: center; flex-wrap: wrap; gap: .6rem; margin-bottom: .6rem; }
.doc-card-head h3 { margin: 0; font-size: 1.05rem; }
.doc-card-head code { font-size: 1rem; }
.doc-entity { font-size: .8rem; font-weight: 700; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }

table.doc-fields { width: 100%; border-collapse: collapse; font-size: .86rem; }
table.doc-fields th {
    text-align: left;
    font-size: .72rem;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--muted);
    border-bottom: 1px solid var(--line);
    padding: .35rem .5rem;
}
table.doc-fields td { padding: .4rem .5rem; border-bottom: 1px solid var(--line); vertical-align: top; }
table.doc-fields tr:last-child td { border-bottom: none; }
table.doc-fields tr.doc-rel { background: rgba(109, 94, 252, .035); }
table.doc-fields code { font-size: .82rem; background: var(--primary-soft); padding: .05rem .35rem; border-radius: 5px; }

.doc-constraints { margin-top: .7rem; display: flex; flex-wrap: wrap; gap: .4rem; }

.doc-badge {
    display: inline-block;
    font-size: .7rem;
    font-weight: 700;
    border-radius: 999px;
    padding: .1rem .5rem;
    background: var(--line);
    color: var(--muted);
    margin-right: .25rem;
}
.doc-badge.is-pk { background: #ede9fe; color: #6d28d9; }
.doc-badge.is-fk { background: #e0f2fe; color: #0369a1; }
.doc-badge.is-tenant { background: #fef3c7; color: #b45309; }
.doc-badge.is-req { background: #fee2e2; color: #b91c1c; }
.doc-badge.is-ok { background: #dcfce7; color: #15803d; }

.doc-prose { line-height: 1.6; }
.doc-prose ul { margin: .5rem 0; padding-left: 1.2rem; }
.doc-prose li { margin: .35rem 0; }
.doc-prose code { font-size: .85rem; background: var(--primary-soft); padding: .05rem .35rem; border-radius: 5px; }
.doc-prose a { color: var(--brand-dark); font-weight: 600; }   /* liens en accent iT.SCHOOL */

/* ============================================================
   Console super-admin : menu à gauche + contenu
   ============================================================ */
.admin-shell { display: flex; align-items: flex-start; min-height: calc(100vh - 66px); }
/* Plein écran (body.app-fit) : borner le shell à la fenêtre pour que le
   défilement vive dans .content (sinon le bas de page est rogné sans scroll,
   le body étant overflow:hidden — cf. convention « pas de scroll de page »). */
body.app-fit .admin-shell { flex: 1; min-height: 0; align-items: stretch; }
.admin-side {
    flex: none;
    width: 232px;
    align-self: stretch;
    background: var(--card);
    border-right: 1px solid var(--line);
    padding: 1.2rem .8rem;
    position: sticky;
    top: 0;
}
.admin-side-title { margin: 0 .4rem 1rem; font-family: "Baloo 2", sans-serif; font-weight: 800; font-size: 1.05rem; }
.admin-side nav { display: flex; flex-direction: column; gap: .25rem; }
.admin-side nav a {
    display: block;
    padding: .6rem .8rem;
    border-radius: var(--radius-sm);
    text-decoration: none;
    color: var(--ink);
    font-weight: 600;
    font-size: .92rem;
    transition: background .12s ease, color .12s ease;
}
.admin-side nav a:hover { background: var(--primary-soft); color: var(--primary-dark); }
.admin-side nav a.is-active { background: var(--primary); color: #fff; }
.admin-side-foot { margin: 1.2rem .4rem 0; padding-top: 1rem; border-top: 1px solid var(--line); font-size: .85rem; }
.admin-side-foot a { color: var(--muted); text-decoration: none; }
.admin-side-foot a:hover { color: var(--brand-dark); }

.admin-main { flex: 1; min-width: 0; display: flex; flex-direction: column; min-height: 0; }
/* (convention largeur de base : pas de plafond spécifique, même la console admin) */

.adm-membership { padding: .2rem 0; line-height: 1.5; }
.adm-membership + .adm-membership { border-top: 1px dashed var(--line); }

@media (max-width: 820px) {
    .admin-shell { flex-direction: column; }
    .admin-side { width: 100%; position: static; border-right: none; border-bottom: 1px solid var(--line); }
    .admin-side nav { flex-direction: row; flex-wrap: wrap; }
}

/* ============================================================
   Sélecteur de thème (console super-admin ▸ Apparence)
   ============================================================ */
.theme-options { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 1rem; max-width: 620px; }
.theme-opt {
    display: grid;
    grid-template-columns: auto 1fr;
    grid-template-areas: "swatch name" "swatch desc";
    align-items: center;
    column-gap: .9rem;
    padding: 1rem 1.1rem;
    border: 2px solid var(--line);
    border-radius: var(--radius-sm);
    background: var(--card);
    cursor: pointer;
    transition: border-color .15s ease, box-shadow .15s ease;
}
.theme-opt:hover { border-color: var(--primary); }
.theme-opt.is-active { border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-soft); }
.theme-opt input { grid-area: swatch / swatch / swatch / swatch; position: absolute; opacity: 0; }
.theme-swatch { grid-area: swatch; display: inline-flex; }
.theme-swatch i { width: 16px; height: 28px; display: block; }
.theme-swatch i:first-child { border-radius: 6px 0 0 6px; }
.theme-swatch i:last-child { border-radius: 0 6px 6px 0; }
/* Aperçu de la position du menu (contenu clair large + menu foncé étroit). */
.menu-pos-preview { grid-area: swatch; display: inline-flex; gap: 3px; width: 46px; height: 30px; }
.menu-pos-preview i { display: block; border-radius: 3px; }
.menu-pos-preview .mp-main { flex: 1; background: var(--primary-soft); }
.menu-pos-preview .mp-side { width: 12px; background: var(--primary); }
.theme-name { grid-area: name; font-weight: 800; font-family: "Baloo 2", sans-serif; }
.theme-desc { grid-area: desc; font-size: .85rem; color: var(--muted); line-height: 1.3; }

/* ===========================================================================
   Page avec menu latéral contextuel (à droite) — 1er usage : Équipe éducative.
   Plein écran (comme le dashboard) + menu repliable.
   =========================================================================== */
.page-with-aside { display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: 1.6rem; align-items: start; }
@media (max-width: 900px) { .page-with-aside { grid-template-columns: 1fr; } }

.side-menu { position: sticky; top: 1.2rem; }
@media (max-width: 900px) { .side-menu { position: static; order: -1; } }

/* La colonne principale ne déborde pas de sa cellule de grille (tableaux larges). */
.page-with-aside .page-main { min-width: 0; }

/* Le cadre du tableau (liste du personnel) défile EN INTERNE, en-tête figé, au
   lieu d'allonger la page. max-height (pas height) → il épouse encore son contenu
   quand il y a peu de lignes. On laisse de la place SOUS le cadre pour que la
   pagination reste visible sans scroller la page. */
.page-with-aside .table-wrap { max-height: calc(100vh - 21rem); overflow-y: auto; }
.page-with-aside .table-wrap thead th { position: sticky; top: 0; background: var(--card); z-index: 1; }
.page-with-aside .pagination { margin-top: .9rem; }
@media (max-width: 900px) { .page-with-aside .table-wrap { max-height: none; } }

/* Tableau plus serré (lignes plus denses) pour la liste du personnel. */
.page-with-aside table th { padding: .55rem 1.1rem; }
.page-with-aside table td { padding: .45rem 1.1rem; }

/* ---------- Bouton d'action ICÔNE SEULE unifié (macro _partials/actions.html.twig) ---------- */
.icon-btn {
    display: inline-flex; align-items: center; justify-content: center;
    width: 34px; height: 34px; padding: 0;
    border: none; border-radius: 10px;
    background: transparent; color: var(--muted);
    cursor: pointer; text-decoration: none;
    transition: background .14s, color .14s, transform .07s;
}
.icon-btn svg { width: 19px; height: 19px; display: block; }
/* Couleur AU REPOS par action (légèrement adoucie via l'opacité) ; halo teinté au survol. */
.icon-btn { opacity: .88; }
.icon-btn.ic-edit { color: var(--c-edit); }
.icon-btn.ic-view, .icon-btn.ic-classer { color: var(--c-view); }
.icon-btn.ic-delete, .icon-btn.ic-purge, .icon-btn.ic-cancelSend, .icon-btn.is-danger { color: var(--danger); }
/* `download` prend le vert de `add`/`save` : c'est une action qui APPORTE quelque chose
   (le fichier arrive chez vous), à distinguer du bleu de `view` qui ne fait que montrer. */
.icon-btn.ic-add, .icon-btn.ic-save, .icon-btn.ic-restore, .icon-btn.ic-download { color: var(--c-add); }
.icon-btn.ic-favorite, .icon-btn.ic-react, .icon-btn.is-fav { color: var(--c-fav); }
.icon-btn.ic-flag { color: var(--c-flag); }
.icon-btn.ic-pin { color: var(--c-pin); }
.icon-btn.ic-reply, .icon-btn.ic-replyAll, .icon-btn.ic-forward { color: var(--c-reply); }
.icon-btn.ic-settings, .icon-btn.ic-pause, .icon-btn.ic-stop { color: var(--c-set); }
/* `play` reprend le vert des actions qui REMETTENT en marche (restore, add). */
.icon-btn.ic-play { color: var(--c-add); }
.icon-btn:hover { opacity: 1; background: color-mix(in srgb, currentColor 14%, transparent); }
.icon-btn:active { transform: scale(.9); }
.icon-btn:focus-visible { outline: 2px solid currentColor; outline-offset: 1px; opacity: 1; }
.icon-btn[disabled] { opacity: .4; cursor: default; }
/* État actif (épinglé/favori/suivi) : fond teinté persistant, couleur de l'icône conservée. */
.icon-btn.is-on { opacity: 1; background: color-mix(in srgb, currentColor 15%, transparent); }
.icon-btn.sm { width: 28px; height: 28px; border-radius: 8px; }
.icon-btn.sm svg { width: 16px; height: 16px; }

/* Sélecteur « Afficher N par page ». */
.pagesize-pick { display: inline-flex; align-items: center; gap: .4rem; font-size: .85rem; white-space: nowrap; }
.pagesize-pick select { width: auto; padding-top: .4rem; padding-bottom: .4rem; }

/* --- Repli du menu : laisse une icône pour le rouvrir --- */
.page-with-aside.is-collapsed { grid-template-columns: minmax(0, 1fr) auto; }
.page-with-aside.is-collapsed .side-menu { display: none; }
.menu-reopen { display: none; }
.page-with-aside.is-collapsed .menu-reopen {
    display: inline-flex; align-items: center; justify-content: center;
    position: sticky; top: 0;
    width: 46px; height: 46px; border-radius: 14px;
    border: 1px solid var(--line); background: var(--card); cursor: pointer;
    font-size: 1.25rem; color: var(--primary);
    box-shadow: 0 6px 18px rgba(31, 36, 64, .06);
    transition: background .15s ease;
}
.page-with-aside.is-collapsed .menu-reopen:hover { background: var(--primary-soft); }

/* Position du menu de module = réglage GLOBAL super-admin (<html data-menu-position>).
   Par défaut à droite ; « left » le passe à gauche (desktop uniquement — sous 900px le
   menu reste empilé en haut). Couvre toutes les pages avec module_layout d'un seul coup. */
@media (min-width: 901px) {
    [data-menu-position="left"] .page-with-aside { grid-template-columns: 300px minmax(0, 1fr); }
    [data-menu-position="left"] .page-with-aside > .page-main { order: 2; }
    [data-menu-position="left"] .page-with-aside > .side-menu { order: 1; }
    [data-menu-position="left"] .page-with-aside.is-collapsed { grid-template-columns: auto minmax(0, 1fr); }
    [data-menu-position="left"] .page-with-aside.is-collapsed > .menu-reopen { order: 1; }
}

.menu-card {
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    overflow: hidden;
    box-shadow: 0 6px 18px rgba(31, 36, 64, .06);
}

/* Mini-barre : juste le bouton « replier » aligné à droite (pas d'en-tête inutile). */
.menu-toolbar { display: flex; justify-content: flex-end; padding: .3rem .5rem 0; }
.menu-collapse {
    border: none; background: transparent; cursor: pointer;
    width: 30px; height: 30px; border-radius: 9px; color: var(--muted); font-size: 1.1rem;
    transition: background .12s ease, color .12s ease;
}
.menu-collapse:hover { background: var(--bg); color: var(--ink); }

.menu-list { display: flex; flex-direction: column; gap: .2rem; padding: .15rem .5rem .5rem; }

.menu-item {
    display: flex; align-items: center; gap: .7rem;
    width: 100%; padding: .48rem .6rem;
    border: none; background: transparent;
    border-radius: 14px;
    font-family: inherit; font-size: .95rem; font-weight: 600; text-align: left;
    color: var(--ink); text-decoration: none; cursor: pointer;
    transition: background .15s ease, transform .15s ease;
}
.menu-item:hover { background: var(--primary-soft); transform: translateX(3px); }
.menu-item .mi-ico {
    display: inline-flex; align-items: center; justify-content: center;
    width: 38px; height: 38px; flex-shrink: 0;
    border-radius: 12px; background: var(--primary-soft); color: var(--primary);
    font-size: 1.1rem; transition: background .15s ease, color .15s ease;
}
.menu-item:hover .mi-ico { background: #fff; }
.menu-item .mi-body { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.menu-item .mi-label { line-height: 1.15; }
.menu-item .mi-hint { font-size: .76rem; font-weight: 500; color: var(--muted); }

/* Item de SOUS-NIVEAU (retour vers l'accueil du module, sous « Tableau de bord »)
   : en retrait + connecteur ↳ + pastille plus petite → hiérarchie visible. */
.menu-item.is-sub { margin-left: 1.4rem; position: relative; }
.menu-item.is-sub::before {
    content: "↳"; position: absolute; left: -1rem; top: 50%; transform: translateY(-58%);
    color: var(--muted); font-size: 1rem; line-height: 1;
}
.menu-item.is-sub .mi-ico { width: 30px; height: 30px; font-size: .95rem; }
.menu-item.is-sub .mi-label { font-size: .9rem; }
.menu-item .mi-chevron { color: var(--muted); font-size: 1.05rem; opacity: 0; transition: opacity .15s ease; }
.menu-item:hover .mi-chevron { opacity: 1; }

/* Item « principal » (Nouveau) : pastille couleur du thème (violet ou bleu). */
.menu-item.is-primary .mi-ico { background: var(--primary); color: #fff; }
.menu-item.is-primary:hover .mi-ico { background: var(--primary-dark); color: #fff; }

/* Item « à venir » : désactivé visuellement + badge Bientôt. */
.menu-item.is-soon { cursor: default; opacity: .65; }
.menu-item.is-soon:hover { background: transparent; transform: none; }
.menu-item.is-soon:hover .mi-ico { background: var(--primary-soft); }
.menu-item.is-soon .mi-ico { background: #f1f2f7; color: var(--muted); }
.mi-soon-tag {
    align-self: center; font-size: .64rem; font-weight: 800; letter-spacing: .04em;
    text-transform: uppercase; color: var(--muted);
    background: #f1f2f7; border-radius: 999px; padding: .15rem .5rem;
}

.menu-sep { height: 1px; background: var(--line); margin: .35rem .65rem; }

/* Entrée de navigation ACTIVE (menus de module refondus 2026-07). */
.menu-item.is-current {
    background: var(--primary-soft);
    box-shadow: inset 3px 0 0 var(--primary);
    font-weight: 700;
    color: var(--primary-dark);
}
.menu-item.is-current .mi-ico { background: #fff; }

/* En-tête de section repliable du menu (type 'titre') — bien visible (retour Philippe). */
.menu-title {
    display: flex; align-items: center; gap: .4rem;
    width: 100%; border: none; cursor: pointer;
    margin-top: .5rem; padding: .5rem .6rem;
    background: var(--primary-soft); border-radius: 9px;
    color: var(--primary-dark);
    font-size: .78rem; font-weight: 800; letter-spacing: .07em; text-transform: uppercase;
}
.menu-title:hover { filter: brightness(.97); }
/* Variante FIXE (`fixe: true`) : un intitulé, pas un bouton — rien à replier, donc ni
   curseur main ni survol. */
.menu-title.is-fixe { cursor: default; }
.menu-title.is-fixe:hover { filter: none; }
.menu-title .mt-chevron { margin-left: auto; transition: transform .15s ease; font-size: .7rem; }
.menu-title.is-closed .mt-chevron { transform: rotate(-90deg); }
.menu-sect-hidden { display: none; }

/* Sous-groupe repliable sous un item-parent (lien `collapsible: true`) : chevron ▾
   TOUJOURS visible (indique le repli), rotatif quand fermé. Cf. module_layout.html.twig. */
.menu-item .mi-subchevron {
    color: var(--muted); font-size: .8rem; cursor: pointer;
    padding: .1rem .3rem; border-radius: 6px; line-height: 1;
    transition: transform .15s ease, background .15s ease, color .15s ease;
}
.menu-item .mi-subchevron:hover { background: var(--primary-soft); color: var(--primary-dark); }
.menu-item.is-parent.is-closed .mi-subchevron { transform: rotate(-90deg); }
.submenu-hidden { display: none; }

/* ── Grids Présences (look UNIFIÉ : justificatifs à valider / à fournir / liste des
   absences). Classes jadis dupliquées en <style> inline, centralisées ici. ── */
.jv-grid td { vertical-align: middle; }
.jv-name { display: inline-flex; align-items: center; gap: .5rem; font-weight: 600; white-space: nowrap; }

/* Nom d'élève CLIQUABLE (macro _partials/eleve.html.twig) : ouvre son dossier. Discret par
   défaut — un grid de 200 lignes ne doit pas virer au bleu — la cliquabilité se révèle au
   survol (souligné + couleur de marque), comme .rf-ecart-nom. */
.eleve-lien { color: inherit; text-decoration: none; }
.eleve-lien:hover, .eleve-lien:focus-visible { text-decoration: underline; color: var(--brand, #0189d9); }
.jv-num { font-weight: 700; white-space: nowrap; color: var(--ink); }
.jv-per { display: inline-flex; align-items: center; gap: .4rem; flex-wrap: wrap; font-weight: 600; font-size: .9rem; }

/* Sous la période DÉCLARÉE, ce que la pièce justifie vraiment. Les deux vivaient sous un même
   intitulé et rien ne disait qu'elles pouvaient différer (design 2026-09-06). */
.jv-couv { display: block; margin-top: .15rem; font-size: .76rem; font-weight: 600; color: var(--muted, #64748b); }
.jv-couv-large { color: #9a3412; cursor: help; }
.jv-day { display: inline-flex; align-items: center; gap: .25rem; white-space: nowrap; }
.jv-picto { font-size: .95rem; }
.jv-arrow { color: var(--muted); }
.jv-verif { display: inline-flex; align-items: center; gap: .4rem; padding: .45rem .85rem; border-radius: 10px;
    background: linear-gradient(135deg, #16a34a, #0ea5a4); color: #fff; font-weight: 700; font-size: .85rem;
    text-decoration: none; border: 0; box-shadow: 0 2px 6px rgba(16, 163, 74, .28); transition: transform .12s, box-shadow .12s; }
.jv-verif:hover { transform: translateY(-1px); box-shadow: 0 5px 14px rgba(16, 163, 74, .38); color: #fff; }
.jv-verif svg { width: 1.05em; height: 1.05em; }
/* Variante « info complémentaire » : même bouton, dégradé BLEU (iT.SCHOOL) + icône info. */
.jv-verif.is-info { background: linear-gradient(135deg, #0189d9, #22c1d6); box-shadow: 0 2px 6px rgba(1, 137, 217, .28); }
.jv-verif.is-info:hover { box-shadow: 0 5px 14px rgba(1, 137, 217, .38); }
/* Variante COMPACTE (Vue d'ensemble, colonne étroite) : picto SEUL, même couleur sémantique. */
.jv-verif.is-icon { padding: .42rem; gap: 0; }
.jv-verif.is-icon svg { width: 1.2em; height: 1.2em; }

/* ── Modale « Encoder une absence » — contrôles façon app mobile (chips + cartes) ───────── */
.me-modale { width: min(680px, 95vw); max-height: 94vh; display: flex; flex-direction: column; overflow: hidden; padding: 0; }
/* Le form remplit la modale en colonne : en-tête + pied figés, corps défilant entre les deux. */
.me-modale > form { display: flex; flex-direction: column; min-height: 0; flex: 1 1 auto; }
.me-head { display: flex; align-items: center; gap: .7rem; padding: .9rem 1.2rem; border-bottom: 1px solid var(--line); flex: none; }
.me-head-actions { margin-left: auto; display: flex; align-items: center; gap: .5rem; flex: none; }
.me-x { border: 0; background: transparent; color: var(--muted); font-size: 1.15rem; line-height: 1; cursor: pointer;
    width: 34px; height: 34px; border-radius: 9px; display: grid; place-items: center; transition: background .12s, color .12s; }
.me-x:hover { background: var(--line); color: var(--ink); }
.me-ava { width: 40px; height: 40px; border-radius: 50%; flex: none; display: grid; place-items: center;
    font-weight: 800; color: #fff; font-size: .92rem; background: linear-gradient(135deg, var(--brand), #22c1d6); }
.me-who { min-width: 0; }
.me-who .me-nm { font-weight: 800; font-size: 1.05rem; letter-spacing: -.01em; line-height: 1.15; }
.me-who .me-sb { font-size: .82rem; color: var(--muted); }
.me-body { display: flex; flex-direction: column; gap: .8rem; padding: 1rem 1.2rem 1.2rem; flex: 1 1 auto; overflow-y: auto; }
.me-lbl { display: block; font-size: .72rem; font-weight: 800; letter-spacing: .05em; text-transform: uppercase;
    color: var(--muted); margin-bottom: .45rem; }
/* Période sur UNE ligne (4 colonnes) pour limiter la hauteur → pas de scroll. */
.me-period { display: grid; grid-template-columns: 1.3fr 1fr 1.3fr 1fr; gap: .55rem; }
/* Date et demi-journée côte à côte doivent faire la MÊME hauteur.
   ⚠️ `min-height` NE SUFFIT PAS, et c'est l'erreur du 2026-09-03 au matin : un plancher relève
   le plus court à une valeur fixe, mais laisse l'input date au-dessus dès qu'un navigateur le
   rend plus haut que ce plancher — l'écart survit, simplement ailleurs. Seule une hauteur
   IMPOSÉE aux deux les rend égaux par construction, quel que soit le moteur.
   43 px = ce que Chrome donne à l'input date, dont l'indicateur de calendrier natif l'épaissit
   (le select, lui, s'en tenait à 38). `box-sizing: border-box` est global : la valeur inclut
   padding et bordures, le contenu garde 24 px pour une police de 14,7 px. */
.me-period .me-input { height: 43px; }
.me-period .field-lbl { font-size: .72rem; font-weight: 700; color: var(--muted); margin-bottom: .2rem; display: block; }

/* L'écho de la période saisie : ce que « du 5 au 9 » désigne vraiment, en demi-journées de
   classe. Deux champs de dates ne le montrent pas, et la faute ne se voyait qu'après
   l'enregistrement — parfois seulement au registre légal (design 2026-09-06).
   ⚠️ `[hidden]` explicite : le contrôleur bascule l'attribut, et une règle `display:` le
   rendrait visible malgré lui (docs/conventions/frontend.md, piège n° 2). */
.me-echo {
  margin: .5rem 0 0;
  padding: .4rem .6rem;
  border-radius: 8px;
  background: var(--surface-2, #f8fafc);
  border-left: 3px solid #94a3b8;
  font-size: .82rem;
  font-weight: 600;
  line-height: 1.4;
  color: var(--muted, #64748b);
}

.me-echo.is-alerte {
  background: #fffbeb;
  border-left-color: #f59e0b;
  color: #92400e;
}

.me-echo[hidden] { display: none; }
.me-input { width: 100%; padding: .5rem .6rem; border: 1.5px solid var(--line); border-radius: var(--radius-sm);
    background: var(--bg, #fff); color: var(--ink); font: inherit; font-size: .92rem; }
.me-input:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-soft); }
/* Champ éteint parce que le motif choisi ne l'autorise pas — même grammaire que
   `.me-photo.is-disabled`, qui verrouille le dépôt de pièce pour la raison symétrique. */
.me-input:disabled { background: var(--bg-soft, #f6f7f9); color: var(--muted); cursor: not-allowed; opacity: .7; }
.me-chip:disabled { border-color: var(--line); color: var(--muted); cursor: not-allowed; opacity: .55; }
.me-chip:disabled:hover { border-color: var(--line); color: var(--muted); }
/* Champ mis en évidence parce que le motif choisi le rend obligatoire (« Circonstances
   exceptionnelles » exige sa précision : la FWB refuse de la recevoir vide). Même ambre que
   `.me-photo-msg`, qui porte le message juste en dessous. */
.me-input.is-requis { border-color: #f59e0b; background: #fffbeb; }
.me-input.is-requis:focus { border-color: #f59e0b; box-shadow: 0 0 0 3px #fde68a; }

/* Motif = chips (au lieu d'un menu déroulant). */
.me-chipgroup + .me-chipgroup { margin-top: .6rem; }
.me-chipgroup-lbl { font-size: .68rem; font-weight: 700; color: var(--muted); margin-bottom: .35rem; }
.me-chips { display: flex; flex-wrap: wrap; gap: .5rem; }
.me-chip { font: inherit; font-weight: 700; font-size: .85rem; border: 1.5px solid var(--line); background: var(--bg, #fff);
    color: var(--ink); padding: .44rem .75rem; border-radius: 999px; cursor: pointer; transition: border-color .12s, background .12s, color .12s; }
.me-chip:hover { border-color: var(--primary); color: var(--primary); }
.me-chip.on { border-color: var(--primary); background: var(--primary-soft); color: var(--primary); }

/* Gros bouton photo/fichier (le vrai <input file> est masqué, ce label le déclenche). */
.me-photo { display: flex; align-items: center; justify-content: center; gap: .5rem; width: 100%; padding: .75rem;
    border-radius: var(--radius-sm); border: 1.7px dashed var(--brand); background: var(--brand-soft); color: var(--brand);
    font: inherit; font-weight: 800; cursor: pointer; }
.me-photo:hover { background: var(--brand); color: #fff; }
/* Verrouillée tant qu'aucun motif justifié n'est choisi. */
.me-photo.is-disabled { border-color: var(--line); background: var(--bg, #fff); color: var(--muted); cursor: not-allowed; opacity: .6; }
.me-photo.is-disabled:hover { background: var(--bg, #fff); color: var(--muted); }
.me-photo-msg { font-size: .82rem; color: #b45309; background: #fffbeb; border: 1px solid #fde68a;
    border-radius: 8px; padding: .4rem .6rem; margin-top: .4rem; }
.me-file { position: absolute; width: 1px; height: 1px; opacity: 0; overflow: hidden; }
.me-filename { font-size: .82rem; color: var(--muted); margin-top: .4rem; }
.me-filename:empty { display: none; }
.me-hint { font-size: .78rem; color: var(--muted); margin: .35rem 0 0; line-height: 1.4; }

/* Bandeau contextuel de la modale d'encodage : ce que l'absence EST aujourd'hui, et le geste
   qui la défait. Il a remplacé le bouton « Annuler l'absence » du pied de page, dont le libellé
   entrait en collision avec la fermeture du dialogue (2026-09-03). */
.me-bandeau { display: flex; align-items: center; gap: .6rem; padding: .6rem .75rem;
    border-radius: var(--radius-sm); background: var(--brand-soft); border: 1px solid var(--brand);
    font-size: .88rem; color: var(--ink); }
.me-bandeau[hidden] { display: none; }
.me-bandeau-btn { margin-left: auto; white-space: nowrap; }

/* Confirmation « maison » de la modale d'encodage : `window.confirm()` sortait du thème, ne sait
   porter ni gras ni compte, et impose « OK / Annuler » — deux mots qui disaient le contraire de
   l'action sur un bouton nommé « Annuler l'absence ». Posée DANS l'overlay, au-dessus de la carte. */
.me-confirm { position: absolute; inset: 0; z-index: 1; display: flex; align-items: center;
    justify-content: center; padding: 1rem; background: rgba(6, 24, 38, .55); }
.me-confirm[hidden] { display: none; }
.me-confirm-card { width: min(460px, 92vw); padding: 0; overflow: hidden; }
.me-confirm-txt { margin: 0; font-size: .95rem; line-height: 1.5; }

/* ── Justification par un parent (pages PUBLIQUES, sans compte) ─────────────────────────────
   Réutilise `.auth`/`.auth-card` (écran de connexion) et les contrôles `.me-*` (modale
   d'encodage). Ce qui suit n'est que ce que ni l'un ni l'autre ne fournit. */
.jp-card { max-width: 520px; }
.jp-card h1 { text-align: center; }
.jp-card .sub { text-align: center; }
.jp-etat { font-size: 2.6rem; line-height: 1; text-align: center; margin: 0 0 .6rem; }
.jp-etat-ok { filter: none; }
.jp-etat-ko { opacity: .85; }
.jp-bloc { margin: 0 0 1.3rem; }
.jp-bloc[hidden] { display: none; }

/* Identité de l'élève : nom, prénom et classe — la seule chose du dossier que la page montre.
   Elle est là pour lever le doute quand une fratrie partage la même adresse. */
.jp-eleve { display: flex; align-items: center; justify-content: center; gap: .55rem; flex-wrap: wrap;
    margin: 0 0 1.5rem; }
.jp-eleve-nom { font-weight: 800; font-size: 1.05rem; }
.jp-eleve-classe { font-weight: 800; font-size: .76rem; letter-spacing: .03em; padding: .2rem .55rem;
    border-radius: 999px; background: var(--primary-soft); color: var(--primary); }

/* « Du … au … » : deux champs à égalité. */
.jp-dates { display: flex; gap: .6rem; }
.jp-date { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; gap: .25rem; }
.jp-date > span { font-size: .76rem; font-weight: 700; color: var(--muted); }
/* ⚠️ iOS impose sa propre hauteur à un <input type="date"> : sans minimum explicite, les deux
   champs ne s'alignent plus avec les autres `.me-input` de la page. */
.jp-date .me-input { min-height: 40px; }
/* Ce que l'ÉCOLE a constaté, énoncé AVANT les champs de dates. Le formulaire se contentait de
   pré-remplir : rien ne disait d'où venaient ces dates, ni qu'en changer était une déclaration
   du parent et non une correction de l'appel (design 2026-09-06). */
.jp-constat {
  margin: 0 0 .6rem;
  padding: .55rem .75rem;
  background: #fffbeb;
  border: 1px solid #fde68a;
  border-radius: 10px;
  font-size: .88rem;
  line-height: 1.45;
  color: #78350f;
}

.jp-duree { margin: .45rem 0 0; font-size: .82rem; font-weight: 700; color: var(--muted); }
.jp-duree:empty { display: none; }

/* Motifs : quatre lignes pleine largeur plutôt que des pastilles qui se répartissent — sur un
   téléphone, chaque motif devient une cible franche, et sa précision tient sous son libellé. */
.jp-card .me-chips { flex-direction: column; gap: .45rem; }
.jp-card .me-chip { display: flex; align-items: center; gap: .55rem; width: 100%; text-align: left;
    padding: .6rem .8rem; border-radius: var(--radius-sm); }
/* Motif hors durée : ÉTEINT, jamais retiré — et sa raison s'affiche juste dessous. */
.jp-card .me-chip:disabled { cursor: not-allowed; opacity: .55; background: var(--bg, #fff);
    border-color: var(--line); color: var(--muted); }
.jp-card .me-chip:disabled:hover { border-color: var(--line); color: var(--muted); }
.jp-raison { margin: -.15rem 0 .35rem; padding: .4rem .6rem; border-radius: var(--radius-sm);
    background: #fffbeb; border: 1px solid #fde68a; color: #92400e; font-size: .78rem; line-height: 1.4; }
.jp-raison[hidden] { display: none; }
.jp-chip-txt { display: flex; flex-direction: column; line-height: 1.25; }
.jp-chip-txt small { font-weight: 500; font-size: .72rem; opacity: .8; }

.jp-envoyer { margin-top: 1.3rem; }

/* ⚠️⚠️ RÉSERVE DE DÉFILEMENT SOUS LE FORMULAIRE — ce n'est pas de l'espacement.

   Le problème : un contrôle peut se retrouver hors d'atteinte alors que la page « défile ». Sur
   mobile, le clavier réduit le viewport VISUEL sans réduire celui de MISE EN PAGE, donc la course
   de défilement ne grandit pas d'un pixel : mesuré le 2026-08-27, après « Autre motif », le bouton
   « Envoyer » restait à 640 px alors que le clavier ne laissait voir que les 380 premiers, page
   déjà tout en bas. Le parent scrolle, et rien ne bouge.

   ⚠️ La réserve est posée POUR TOUS LES POINTEURS, pas seulement le tactile. La cause exacte varie
   d'un moteur à l'autre — clavier virtuel, barre d'outils escamotable, zoom, fenêtre courte — et
   les diagnostiquer un par un a déjà coûté trois correctifs. De la course en trop rend le défaut
   IMPOSSIBLE quelle qu'en soit la cause. Elle est plus généreuse au tactile, où le clavier mange
   la moitié de l'écran.

   ⚠️ Invisible : elle vit sous la carte, sur le dégradé de `.auth`, et n'est portée que par
   l'écran de saisie — les écrans d'état tiennent dans une hauteur d'écran. */
.auth-saisie { padding-bottom: 30vh; }

/* ⚠️⚠️ SUR GRAND ÉCRAN, LE FORMULAIRE TIENT SANS DÉFILER — deux colonnes.
   Empilé, il fait ~1050 px : sur un portable il dépasse toujours, et il faut donc défiler pour
   atteindre le bouton. Or le défilement est exactement ce qui a résisté à quatre correctifs sur le
   Mac de l'utilisateur. Plutôt que de continuer à réparer le défilement, on retire le besoin d'en
   faire : à partir de 780 px de large, la carte s'élargit et le formulaire se répartit en deux
   colonnes — période et motifs à gauche, pièce/texte, déclaration et envoi à droite. Le tout
   redescend sous les 700 px et tient dans n'importe quelle fenêtre de bureau.
   ⚠️ `pointer: fine` seulement : le téléphone garde sa colonne unique, qui lui va, et où le
   problème est réglé. */


/* ⚠️⚠️ SUR ÉCRAN NON TACTILE, C'EST LA CARTE QUI DÉFILE, PAS LA PAGE.

   Cinq correctifs ont réparé le défilement du DOCUMENT — débordement horizontal, centrage,
   réserve pour le clavier — et le bas du formulaire restait inatteignable sur le Mac de
   l'utilisateur, sans que rien de mesurable ne l'explique de ce côté-ci. On change donc de
   MÉCANISME : la carte est bornée à la hauteur de la fenêtre et défile en interne. Un conteneur
   qui déborde et qui porte `overflow-y: auto` défile par construction, indépendamment de tout ce
   qui peut clocher sur le défilement de la page.

   ⚠️ L'ascenseur est stylé, donc CLASSIQUE et toujours visible : macOS masque les ascenseurs
   flottants par défaut, et c'est probablement pour ça que la page semblait bloquée.

   ⚠️ `overscroll-behavior: contain` : arrivé en bout de course, le geste ne se propage pas à la
   page derrière — sinon on croit que « ça saute ».

   ⚠️ TACTILE EXCLU. Le téléphone fonctionne depuis ce matin avec le défilement de page et la
   réserve pour le clavier ; un conteneur défilant imbriqué y réintroduirait exactement les
   ennuis qu'on vient de régler. */
@media (pointer: fine) {
    .auth-saisie .auth-card {
        /* ⚠️ 4rem et non 3 : `.auth` porte déjà 1,5rem de marge en haut ET en bas. À 3rem la carte
           faisait exactement la hauteur de la fenêtre, et l'arrondi rendait la PAGE défilante d'un
           pixel par-dessus la carte défilante — deux défilements imbriqués pour rien. */
        max-height: calc(100dvh - 4rem);
        overflow-y: auto;
        overscroll-behavior: contain;
        scrollbar-width: auto;
        scrollbar-color: var(--primary) var(--primary-soft);
    }
    .auth-saisie .auth-card::-webkit-scrollbar { width: 14px; }
    .auth-saisie .auth-card::-webkit-scrollbar-track { background: var(--primary-soft); border-radius: 8px; }
    .auth-saisie .auth-card::-webkit-scrollbar-thumb {
        background: var(--primary); border-radius: 8px; border: 3px solid var(--primary-soft);
    }
    .auth-saisie .auth-card::-webkit-scrollbar-thumb:hover { background: var(--ink); }

    /* La page, elle, n'a plus rien à faire défiler : la réserve n'aurait plus de sens. */
    .auth-saisie { padding-bottom: 1.5rem; }
}

@media (pointer: coarse) {
    .auth-saisie { padding-bottom: 65vh; }
}
.jp-mention { font-weight: 400; color: var(--muted); text-transform: none; letter-spacing: 0; }
.jp-zone { min-height: 84px; resize: vertical; font-family: inherit; }
/* Case à cocher de déclaration : la cible tactile est TOUTE la ligne, pas la seule case. */
.jp-signature { display: flex; align-items: flex-start; gap: .6rem; margin: .7rem 0 0;
    font-size: .88rem; line-height: 1.35; cursor: pointer; }
.jp-signature input { margin-top: .15rem; width: 20px; height: 20px; flex: none; accent-color: var(--primary); }
/* Second bouton fichier : présent mais discret — la photo reste le geste principal. */
.jp-photo-alt { margin-top: .5rem; background: var(--bg, #fff); color: var(--muted); border-style: dashed; }
.jp-photo-alt:hover { background: var(--primary-soft); color: var(--primary); }
.jp-apercu { display: block; width: 100%; max-height: 220px; object-fit: contain; margin: .6rem 0 0;
    border-radius: var(--radius-sm); border: 1px solid var(--line); background: var(--bg, #fff); }
.jp-apercu[hidden] { display: none; }
.jp-erreur { margin: 0 0 1.1rem; padding: .7rem .9rem; border-radius: var(--radius-sm);
    background: #fffbeb; border: 1px solid #fde68a; color: #92400e; font-size: .88rem; line-height: 1.4; }
.jp-note { margin: 1.2rem 0 0; text-align: center; font-size: .82rem; color: var(--muted); }
.jp-pied { margin: 1.6rem 0 0; text-align: center; font-size: .8rem; color: var(--muted); }
.me-foot { display: flex; gap: .6rem; justify-content: center; padding: 1rem 1.3rem 1.3rem;
    border-top: 1px solid var(--line); flex: none; }
@media (max-width: 560px) {
    .me-period { grid-template-columns: 1fr 1fr; }
}
.jv-more { color: var(--primary); font-weight: 600; font-size: .88rem; text-decoration: none; }
.jv-more:hover { text-decoration: underline; }
.ve-gauge { display: inline-flex; align-items: center; gap: .5rem; }
.ve-gauge svg { width: 38px; height: 38px; flex: none; }
.ve-gauge-sub { font-size: .78rem; color: var(--muted); white-space: nowrap; }
.ve-gauge-sub.is-late { color: #b91c1c; font-weight: 600; }

/* Interrupteur de vue (toggle-view : à plat / par jour) — centralisé (jadis inline). */
.tv-switch { display: inline-flex; align-items: center; gap: .5rem; cursor: pointer; font-size: .9rem; user-select: none; }
.tv-switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.tv-track { width: 42px; height: 24px; border-radius: 999px; background: #cbd5e1; position: relative; transition: background .2s; flex: none; }
.tv-thumb { position: absolute; top: 2px; left: 2px; width: 20px; height: 20px; border-radius: 50%; background: #fff; box-shadow: 0 1px 3px rgba(0, 0, 0, .35); transition: transform .2s; }
.tv-switch input:checked + .tv-track { background: var(--primary, #6d5efc); }
.tv-switch input:checked + .tv-track .tv-thumb { transform: translateX(18px); }
.tv-switch input:focus-visible + .tv-track { box-shadow: 0 0 0 3px var(--primary-soft, #e0e7ff); }
/* Barre d'affichage (toggle au-dessus du grid) + en-tête de jour (« Vue par jour »). */
.jf-toolbar { display: flex; justify-content: flex-end; margin-bottom: .8rem; }
/* Ligne-séparateur de jour (« Vue par jour » : une seule table → colonnes alignées). */
.jf-jour td { background: var(--primary-soft); color: var(--primary-dark); font-weight: 700; padding: .45rem .75rem; font-size: .9rem; }
.jf-jour-n { font-weight: 400; color: var(--muted); font-size: .85rem; }
/* Pastille de compteur à côté d'un titre de cadre (Vue d'ensemble, grids « à … »). */
.ve-badge { display: inline-flex; align-items: center; justify-content: center; min-width: 1.4rem; height: 1.4rem; padding: 0 .45rem; border-radius: 999px; background: var(--primary-soft, #eef2ff); color: var(--primary-dark, #4338ca); font-weight: 800; font-size: .82rem; margin-left: .5rem; vertical-align: middle; }
.ve-badge.is-alert { background: #fee2e2; color: #991b1b; }

/* Bouton relance grisé au niveau « Dernier ». (La jauge de niveau réutilise .ve-gauge.) */
.rl-btn[disabled] { opacity: .45; cursor: default; }
/* Contrôle segmenté (bascule à N vues : Liste / Par jour / Par épisode). */
.seg { display: inline-flex; background: var(--bg); border: 1px solid var(--line); border-radius: 10px; padding: 2px; gap: 2px; }
.seg-btn { border: 0; background: transparent; padding: .3rem .75rem; border-radius: 8px; font-family: inherit; font-size: .85rem; font-weight: 600; color: var(--muted); cursor: pointer; transition: background .15s ease, color .15s ease; }
.seg-btn:hover { color: var(--ink); }
.seg-btn.is-active { background: #fff; color: var(--primary-dark); box-shadow: 0 1px 3px rgba(0, 0, 0, .12); }

/* Actions de page dans le page-head (droite du titre). */
.page-actions { display: flex; gap: .5rem; align-items: center; flex-wrap: wrap; }

/* Barre d'enregistrement en bas de page (flux normal, centrée) : le bouton
   « Enregistrer » d'une page d'édition vit EN BAS AU MILIEU (choix Philippe,
   facilite l'usage), plus dans le page-head. À placer à la fin du contenu. */
.page-save-bar { display: flex; justify-content: center; flex-wrap: wrap; gap: .6rem; margin-top: 1.8rem; }
.page-save-bar .btn, .page-save-bar .btn-ghost { padding-inline: 2.2rem; }

/* Zone « danger » (retrait d'un membre) : bordure rouge discrète. */
.danger-box { border-color: #f3c9c9; }
.danger-box[open] { box-shadow: 0 0 0 3px #fdecec; }

/* ---------- Tableau triable (clic sur l'en-tête) ---------- */
table.sortable th { cursor: pointer; user-select: none; white-space: nowrap; transition: color .12s; }
table.sortable th:hover { color: var(--primary); }
table.sortable th .th-label { display: inline-flex; align-items: center; gap: .4rem; }
table.sortable th .th-caret { font-size: .72rem; opacity: .3; transition: opacity .12s; }
table.sortable th:hover .th-caret { opacity: .65; }
table.sortable th[aria-sort="ascending"],
table.sortable th[aria-sort="descending"] { color: var(--primary); }
table.sortable th[aria-sort="ascending"] .th-caret,
table.sortable th[aria-sort="descending"] .th-caret { opacity: 1; }
.no-result td { text-align: center; color: var(--muted); padding: 1.6rem; }
/* Décalage Nom ↔ autres colonnes : .cell-name est en display:flex, ce qui
   sort la cellule du modèle de tableau et la désaligne des td voisins (baseline
   décalée par les badges plus hauts). Ici la cellule Nom n'a pas d'avatar → on
   la remet en cellule de tableau normale + tout aligné au milieu. */
table.sortable td { vertical-align: middle; }
table.sortable td.cell-name { display: table-cell; }

/* ===========================================================================
   Assistant d'import du personnel (multi-step).
   =========================================================================== */
.section-sub { font-family: "Baloo 2", sans-serif; font-size: 1.15rem; margin: 1.6rem 0 .8rem; }

/* Indicateur d'étapes */
.stepper { display: flex; gap: .5rem; list-style: none; padding: 0; margin: .4rem 0 1.4rem; flex-wrap: wrap; }
.stepper .step { display: inline-flex; align-items: center; gap: .5rem; padding: .45rem .9rem; border-radius: 999px; background: var(--card); border: 1px solid var(--line); color: var(--muted); font-weight: 600; font-size: .9rem; }
.stepper .step-num { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; border-radius: 50%; background: var(--bg); color: var(--muted); font-size: .8rem; font-weight: 800; }
.stepper .step.is-current { border-color: var(--primary); color: var(--primary); background: var(--primary-soft); }
.stepper .step.is-current .step-num { background: var(--primary); color: #fff; }
.stepper .step.is-done { color: var(--ink); }
.stepper .step.is-done .step-num { background: var(--primary); color: #fff; }

/* Cartes de type de source (radio) */
.src-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 1rem; }
.src-card { position: relative; display: flex; flex-direction: column; align-items: center; text-align: center; gap: .25rem; padding: 1.3rem 1rem; background: var(--card); border: 2px solid var(--line); border-radius: var(--radius); cursor: pointer; transition: border-color .15s, box-shadow .15s, transform .08s; }
.src-card:hover { border-color: var(--primary-soft); transform: translateY(-2px); }
.src-card input { position: absolute; opacity: 0; pointer-events: none; }
.src-card:has(input:checked) { border-color: var(--primary); box-shadow: 0 0 0 4px var(--primary-soft); }
.src-emoji { font-size: 2rem; }
/* Import verrouillé par la synchro iT.SCHOOL : la carte reste lisible — on doit voir ce que
   l'import savait faire — mais elle n'est plus une affordance. */
.src-card.is-disabled { cursor: not-allowed; opacity: .55; filter: grayscale(1); }
.src-card.is-disabled:hover { border-color: var(--line); transform: none; }

.src-name { font-weight: 800; font-family: "Baloo 2", sans-serif; }
.src-hint { font-size: .8rem; color: var(--muted); }

/* Mappage colonnes */
.map-grid { display: flex; flex-direction: column; gap: .6rem; }
.map-row { display: grid; grid-template-columns: 140px 24px 1fr; align-items: center; gap: .6rem; }
.map-target { font-weight: 600; }
.map-target .req { color: #c0392b; }
.map-arrow { text-align: center; color: var(--muted); }
@media (max-width: 560px) { .map-row { grid-template-columns: 1fr; } .map-arrow { display: none; } }

/* Options */
.opt-list { display: flex; flex-direction: column; gap: .8rem; }
.opt { display: flex; align-items: flex-start; gap: .7rem; cursor: pointer; line-height: 1.35; }
.opt input { margin-top: .25rem; }
.opt.is-disabled { opacity: .6; cursor: default; }

/* Rapport */
.report-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 1rem; margin-top: .4rem; }
.rstat { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 1.1rem; text-align: center; }
.rstat-num { display: block; font-size: 1.9rem; font-weight: 800; font-family: "Baloo 2", sans-serif; line-height: 1; }
.rstat-lbl { display: block; margin-top: .35rem; font-size: .82rem; color: var(--muted); }
.rstat.ok .rstat-num { color: #1d9a6c; }
.rstat.warn .rstat-num { color: #b8860b; }
.rstat.err { border-color: #f3c9c9; }
.rstat.err .rstat-num { color: #c0392b; }
.err-list { margin: .6rem 0 0; padding-left: 1.2rem; font-size: .88rem; color: var(--muted); display: flex; flex-direction: column; gap: .25rem; }
.job-state { font-size: 2rem; line-height: 1; }
.job-state.job-running { display: inline-block; animation: job-spin 1.6s linear infinite; }
@keyframes job-spin { to { transform: rotate(360deg); } }

/* Badges de statut de job (et import, alias historiques) */
.badge.import-pending, .badge.job-pending { background: #fff7ed; color: #9a3412; }
.badge.import-running, .badge.job-running { background: var(--primary-soft); color: var(--primary-dark); }
.badge.import-done, .badge.job-done { background: #e7f7ef; color: #1d9a6c; }
.badge.import-failed, .badge.job-failed { background: #fdecec; color: #c0392b; }
.badge.job-canceled { background: var(--bg); color: var(--muted); }

/* Console admin — supervision des tâches */
.worker-state { display: inline-flex; align-items: center; gap: .5rem; font-weight: 600; font-size: .9rem; padding: .4rem .8rem; border-radius: 999px; border: 1px solid var(--line); background: var(--card); }
.worker-state .worker-dot { width: 10px; height: 10px; border-radius: 50%; background: var(--muted); flex-shrink: 0; }
.worker-state.is-on .worker-dot { background: #1d9a6c; box-shadow: 0 0 0 3px rgba(29, 154, 108, .2); }
.worker-state.is-off { color: #c0392b; }
.worker-state.is-off .worker-dot { background: #c0392b; }
.job-counters { display: flex; flex-wrap: wrap; gap: .5rem; margin: 1rem 0 .2rem; }
.job-counter { display: inline-flex; align-items: center; gap: .4rem; padding: .35rem .7rem; border-radius: 12px; border: 1px solid var(--line); background: var(--card); color: var(--ink); text-decoration: none; font-size: .85rem; transition: border-color .12s, background .12s; }
.job-counter:hover { background: var(--primary-soft); }
.job-counter.is-active { border-color: var(--primary); background: var(--primary-soft); }
.job-counter strong { font-family: "Baloo 2", sans-serif; }

/* ----- Écran de correspondance (mapping) ----- */
.map-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; margin: 1.6rem 0 .2rem; }
.map-loader { display: inline-flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.map-loader .input { width: auto; }

.map2-card { padding: 1.3rem 1.4rem; }
.map2-group-title { font-family: "Baloo 2", sans-serif; font-weight: 800; font-size: .98rem; color: var(--ink); margin-bottom: .6rem; }
.map2 { display: flex; flex-direction: column; gap: .45rem; }
.map2-row {
    display: grid; grid-template-columns: minmax(190px, 240px) minmax(0, 1fr) minmax(110px, 200px);
    align-items: center; gap: 1rem;
    padding: .5rem .7rem; border-radius: 12px; border: 1px solid var(--line); background: var(--card);
    transition: border-color .12s, box-shadow .12s;
}
.map2-row:hover { border-color: var(--primary-soft); box-shadow: 0 2px 10px rgba(31, 36, 64, .05); }
.map2-row.is-required { background: var(--primary-soft); border-color: transparent; }
.map2-target { display: flex; align-items: center; gap: .6rem; min-width: 0; }
.map2-ico {
    display: inline-flex; align-items: center; justify-content: center;
    width: 34px; height: 34px; flex-shrink: 0; border-radius: 10px;
    background: #fff; border: 1px solid var(--line); font-size: 1.05rem;
}
.map2-label { font-weight: 600; line-height: 1.2; min-width: 0; }
.map2-label .req { color: #c0392b; }
.map2-keytag {
    display: inline-block; margin-left: .3rem; font-size: .6rem; font-weight: 800;
    letter-spacing: .04em; text-transform: uppercase; color: var(--primary-dark);
    background: #fff; border: 1px solid var(--primary-soft); border-radius: 999px;
    padding: .05rem .42rem; vertical-align: middle;
}
.map2-anon { font-size: .76rem; color: var(--muted); }
.map2-row select { width: 100%; }
.map2-ex { font-size: .82rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.map2-ex b { color: var(--ink); font-weight: 700; }
@media (max-width: 720px) {
    .map2-row { grid-template-columns: 1fr; gap: .45rem; }
    .map2-ex { display: none; }
}

/* ---------- Fenêtre modale (native <dialog>) ---------- */
dialog.modal {
    border: none; padding: 0; border-radius: var(--radius);
    max-width: 560px; width: calc(100% - 2rem);
    box-shadow: 0 30px 80px rgba(31, 36, 64, .3);
    color: var(--ink); background: var(--card);
}
dialog.modal::backdrop { background: rgba(31, 36, 64, .45); }
.modal-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 1.1rem 1.3rem; border-bottom: 1px solid var(--line); }
.modal-head h2 { margin: 0; font-size: 1.15rem; font-family: "Baloo 2", sans-serif; }
.modal-close { border: none; background: transparent; font-size: 1.5rem; line-height: 1; cursor: pointer; color: var(--muted); border-radius: 8px; width: 34px; height: 34px; flex-shrink: 0; }
.modal-close:hover { background: var(--bg); color: var(--ink); }
.modal-body { padding: 1.2rem 1.3rem 1.4rem; }
/* Une modale de LECTURE (une aide, une procédure) : la largeur est celle de `modal-lg`, déjà dans la
   charte ; on n'ajoute que la borne de hauteur, pour que le fond ne défile jamais derrière elle. */
dialog.modal.modal-lg .modal-body { max-height: min(70vh, 640px); overflow-y: auto; }
/* La liste des paliers dans l'aide : chaque palier respire, et son acteur se lit d'un coup d'œil. */
.procedure-liste { margin: 0; padding-left: 1.2rem; }
.procedure-liste li { margin-bottom: .7rem; }
.procedure-liste li > div { color: var(--muted); font-size: .92rem; margin-top: .15rem; }

/* Page « Mes infos » — pages du module (menu latéral contextuel). */
/* Convention : la colonne de contenu (gauche) scrolle indépendamment ; le menu (droite) reste fixe.
   Même principe que la liste du personnel (.page-with-aside .table-wrap) : la zone interne est bornée
   au viewport avec son propre overflow ; le menu latéral reste sticky en haut (cf. .side-menu). */
[id^="aside-mes-infos"] .page-main { max-height: calc(100vh - 11rem); overflow-y: auto; padding-right: .7rem; }
@media (max-width: 900px) {
    [id^="aside-mes-infos"] .page-main { max-height: none; overflow: visible; padding-right: 0; }
}
.mi-banner { display: flex; align-items: center; gap: 1rem; margin-bottom: 1.4rem; }
.mi-banner-av { width: 72px; height: 72px; border-radius: 50%; overflow: hidden; box-shadow: 0 4px 16px rgba(20,20,60,.12); background: #fff; flex: 0 0 auto; }
.mi-banner-av svg { display: block; width: 100%; height: 100%; }
.avatar.mi-ini { width: 72px; height: 72px; font-size: 1.6rem; border-radius: 50%; }
.mi-card-block { margin-bottom: 1.4rem; }
/* Grille d'informations lisible : libellé au-dessus, valeur pleine largeur (pas de troncature). */
.mi-info { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .9rem 1.6rem; }
.mi-field { display: flex; flex-direction: column; gap: .15rem; min-width: 0; }
.mi-field-k { font-size: .78rem; font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: .03em; }
.mi-field-v { font-weight: 600; color: #2b2f44; word-break: break-word; }
.mi-attach { display: flex; flex-direction: column; gap: .6rem; }
.mi-attach-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .5rem; border-top: 1px solid var(--line); padding-top: .6rem; }
.mi-attach-row:first-child { border-top: 0; padding-top: 0; }
.mi-attach-ecole { font-weight: 600; }
.mi-attach-roles { display: flex; flex-wrap: wrap; gap: .35rem; }
@media (max-width: 640px) { .mi-info { grid-template-columns: 1fr; } }

/* Éditeur d'avatar (page « Mon avatar »). */
.av-editor { display: grid; grid-template-columns: 200px 1fr; gap: 1.5rem; align-items: start; }
.av-preview { position: sticky; top: 1rem; }
.av-preview img { width: 180px; height: 180px; border-radius: 50%; box-shadow: 0 6px 20px rgba(26,26,64,.12); }
.av-group { margin-bottom: 1rem; }
.av-group h3 { font-size: .85rem; margin: 0 0 .4rem; }
.av-chips, .av-swatches, .av-emoji-grid { display: flex; flex-wrap: wrap; gap: .4rem; }
.av-chip { border: 1px solid #d9dde8; border-radius: 999px; padding: .25rem .7rem; cursor: pointer; font-size: .85rem; }
.av-chip input, .av-swatch input, .av-emoji input { position: absolute; opacity: 0; pointer-events: none; }
.av-chip:has(input:checked) { border-color: var(--primary, #6d5efc); background: var(--primary, #6d5efc); color: #fff; }
.av-swatch span { display: block; width: 26px; height: 26px; border-radius: 50%; border: 2px solid #fff; box-shadow: 0 0 0 1px #d9dde8; cursor: pointer; }
.av-swatch:has(input:checked) span { box-shadow: 0 0 0 2px var(--primary, #6d5efc); }
.av-emoji span { display: block; width: 34px; height: 34px; line-height: 34px; text-align: center; font-size: 22px; border-radius: 8px; cursor: pointer; }
.av-emoji:has(input:checked) span { background: #eef1ff; outline: 2px solid var(--primary, #6d5efc); }
.av-check { display: inline-flex; align-items: center; gap: .4rem; cursor: pointer; }
@media (max-width: 700px) { .av-editor { grid-template-columns: 1fr; } .av-preview { position: static; text-align: center; } }

/* --- Badge messagerie global (topbar) --- */
.msg-pill, .mail-pill { position: relative; }
.msg-badge, .mail-badge {
    position: absolute; top: -2px; right: -2px;
    min-width: 17px; height: 17px; padding: 0 3px; border-radius: 999px;
    background: #dc2626; color: #fff; font-size: .65rem; font-weight: 800;
    display: inline-flex; align-items: center; justify-content: center;
    box-shadow: 0 0 0 2px var(--card, #fff);
    pointer-events: none;
}
.msg-badge[hidden], .mail-badge[hidden] { display: none !important; }

/* ============================================================================
   Messagerie — refonte « chat » (bulles + menu droit navigateur)
   ========================================================================== */

/* --- Menu droit : badges non-lus + canal actif --- */
.menu-item .mi-badge {
    margin-left: .35rem;
    min-width: 20px; height: 20px; padding: 0 6px;
    display: inline-flex; align-items: center; justify-content: center;
    background: #dc2626; color: #fff;
    font-size: .72rem; font-weight: 800; line-height: 1;
    border-radius: 999px;
}
.menu-item.is-current {
    background: var(--primary-soft);
    box-shadow: inset 3px 0 0 var(--primary);
}
.menu-item.is-current .mi-label { color: var(--primary-dark); font-weight: 700; }

/* --- Conteneur chat : header fixe / feed scrollable / composer fixe --- */
/* La messagerie remplit la hauteur dispo : le .content ne scrolle pas, c'est le
   FIL (.chat-feed) qui défile. La chaîne content → page-with-aside → page-main → chat
   propage la hauteur (cf. body.app-fit). */
.content:has(.chat) { display: flex; flex-direction: column; overflow: hidden; min-height: 0; }
.content:has(.chat) > .crumbs { flex: none; }
.content:has(.chat) .page-with-aside { flex: 1; min-height: 0; align-items: stretch; }
.content:has(.chat) .page-main { min-height: 0; }
.content:has(.chat) .side-menu { position: static; align-self: start; max-height: 100%; }
.content:has(.chat) .menu-card { max-height: 100%; display: flex; flex-direction: column; }
.content:has(.chat) .menu-list { overflow-y: auto; }

.chat {
    display: flex; flex-direction: column;
    height: 100%; min-height: 0;
    background: var(--card);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    overflow: hidden;
}
/* Module « Mes équipes » : cadre de conversation plus étroit et centré (façon Teams).
   Le hub Vie Scolaire (.vs-hub, dashboard) garde sa pleine largeur. */
.chat:not(.vs-hub) { width: 100%; max-width: 940px; margin-inline: auto; }

/* En-tête */
.chat-head {
    display: flex; align-items: center; gap: .85rem;
    padding: .85rem 1.1rem;
    border-bottom: 1px solid var(--line);
    background: linear-gradient(180deg, #fff, #fcfcff);
}
.chat-head-ico {
    width: 46px; height: 46px; flex: 0 0 auto;
    display: grid; place-items: center;
    border-radius: 14px; font-size: 1.4rem;
    background: var(--primary-soft);
}
.chat-head-ico.is-general { background: linear-gradient(135deg, #fde68a, #fca5a5); }
.chat-head-ico.is-team    { background: linear-gradient(135deg, var(--primary-soft), #dcd7ff); }
.chat-head-ico.is-dm      { background: linear-gradient(135deg, var(--brand-soft), #cfe9fb); }
.chat-head-info { min-width: 0; }
.chat-head-info h2 { margin: 0; font-size: 1.12rem; line-height: 1.2; }
.chat-head-info p { margin: .1rem 0 0; font-size: .85rem; }
.chat-head-leave { margin-left: auto; }
.chat-head-btn {
    border: 1px solid var(--line); background: #fff; color: var(--muted);
    padding: .4rem .8rem; border-radius: 999px; cursor: pointer; font-weight: 600; font-size: .82rem;
}
.chat-head-btn:hover { color: #dc2626; border-color: #f3c7c7; background: #fff5f5; }
.chat-head-btn.is-danger { color: #dc2626; border-color: #f3c7c7; }

/* Épinglés */
.chat-pinned { border-bottom: 1px solid var(--line); background: #fffdf5; }
.chat-pinned > summary { cursor: pointer; padding: .55rem 1.1rem; font-weight: 600; font-size: .85rem; color: #b45309; }
.chat-pin-item { display: block; padding: .35rem 1.1rem .35rem 2rem; font-size: .85rem; color: var(--ink); text-decoration: none; border-top: 1px dashed #f1e4c4; }
.chat-pin-item:hover { background: #fff8e8; }

/* Fil de discussion */
.chat-feed {
    flex: 1 1 auto; overflow-y: auto;
    padding: 1.1rem 1.1rem 1.4rem;
    display: flex; flex-direction: column; gap: .35rem;
    background:
        radial-gradient(1200px 400px at 100% -5%, rgba(109,94,252,.05), transparent 60%),
        var(--bg);
    scroll-behavior: smooth;
}
.chat-empty { margin: auto; text-align: center; color: var(--muted); }
.chat-empty-emoji { font-size: 2.6rem; }

/* Écran d'accueil du module (aucun canal sélectionné) */
.chat--empty-module { align-items: center; justify-content: center; }
.chat-welcome { text-align: center; max-width: 420px; padding: 2rem; }
.chat-welcome h2 { margin: .4rem 0 .3rem; }
.chat-welcome-actions { display: flex; gap: .6rem; justify-content: center; flex-wrap: wrap; margin-top: 1.2rem; }

/* Séparateur de jour (façon Teams) : pastille centrée. */
.chat-day { align-self: center; margin: .7rem 0 .25rem; }
.chat-day span {
    display: inline-block; padding: .15rem .75rem; border-radius: 999px;
    font-size: .72rem; font-weight: 700; letter-spacing: .01em;
    background: var(--primary-soft); color: var(--primary-dark);
}

/* Un message — TOUT aligné à gauche (style canal) : pastille + en-tête (nom + heure)
   AU-DESSUS de la bulle, pour soi comme pour les autres. */
.chat-msg { display: flex; align-items: flex-start; gap: .55rem; max-width: 100%; margin-top: .35rem; }
/* Pastille toujours alignée sur la ligne du nom (en haut du message). */
.chat-msg-av { flex: 0 0 auto; align-self: flex-start; margin-top: .1rem; }
.chat-msg-main { min-width: 0; max-width: 80%; display: flex; flex-direction: column; }

/* En-tête au-dessus du cadre */
.chat-msg-head { display: flex; align-items: center; gap: .45rem; margin: 0 .4rem .15rem; min-height: 1.45rem; align-self: flex-start; }
.chat-msg-author { font-size: .82rem; font-weight: 800; color: var(--primary-dark); }
.chat-msg-time { font-size: .72rem; color: var(--muted); white-space: nowrap; }

/* Barre d'actions : on RÉUTILISE la barre de Vie Scolaire (.vs-msg-tools / .vs-tool-btn /
   .vs-pop + éditeur Tiptap _cps). Sur la PAGE « Mes équipes » : révélée au survol ; les
   panneaux s'ouvrent vers la DROITE (tout aligné à gauche). */
.chat-msg .vs-msg-tools { margin-left: .25rem; }
.chat-msg:hover .vs-msg-tools,
.chat-msg-main:focus-within > .chat-msg-head > .vs-msg-tools,
.chat-msg .vs-msg-tools:has(.vs-pop[open]) { opacity: 1; transform: none; pointer-events: auto; }
/* Sur le DASHBOARD (chat embarqué « vie scolaire ») : barre TOUJOURS visible, quel que
   soit le type de message (.vs-msg vie scolaire OU .chat-msg équipe/conversation). */
.dash-msg .vs-msg-tools { opacity: 1; transform: none; pointer-events: auto; }
.chat-msg .vs-msg-tools .vs-pop[open] > .vs-react-picker,
.chat-msg .vs-msg-tools .vs-pop[open] > .vs-reply-form,
.chat-msg .vs-msg-tools .vs-pop[open] > .vs-edit-form { left: 0; right: auto; }

.chat-bubble {
    position: relative;
    padding: .5rem .75rem;
    border-radius: 12px;
    background: var(--card); border: 1px solid var(--line);
    box-shadow: 0 1px 2px rgba(31,36,64,.05);
    display: flex; flex-direction: column; gap: .15rem;
}
/* Mes messages : même teinte légère que mes réponses (pas de violet plein). */
.chat-msg.is-mine .chat-bubble {
    background: var(--primary-soft); border-color: #ded8fc;
}
.chat-msg-subject { font-size: .82rem; font-weight: 700; color: var(--ink); opacity: .85; }
.chat-msg-text { word-break: break-word; line-height: 1.4; }
/* Sortie Tiptap = des <p> : on neutralise marges + paragraphes vides qui
   rendaient les bulles trop hautes pour un message court. */
.chat-msg-text p { margin: 0 0 .3rem; }
.chat-msg-text p:last-child { margin-bottom: 0; }
.chat-msg-text p:empty { display: none; }

/* Pièces jointes */
.chat-files { display: flex; flex-wrap: wrap; gap: .35rem; margin-top: .25rem; }
.chat-file {
    display: inline-flex; align-items: center; gap: .3rem;
    background: rgba(0,0,0,.04); border: 1px solid var(--line);
    padding: .25rem .55rem; border-radius: 10px; font-size: .8rem;
    color: var(--ink); text-decoration: none;
}
.chat-file em { opacity: .65; font-style: normal; font-size: .75rem; }

/* Réactions posées sous la bulle (barre visible si réactions ; picker = outil 🙂). */
.vs-reactions-bar { display: flex; flex-wrap: wrap; gap: .25rem; margin: .25rem .15rem 0; }
.vs-reactions-bar:empty { display: none; }
.vs-reaction {
    display: inline-flex; align-items: center; gap: .2rem;
    background: #fff; border: 1px solid var(--line); border-radius: 999px;
    padding: .1rem .45rem; font-size: .78rem; line-height: 1.4; box-shadow: 0 1px 2px rgba(31,36,64,.05);
}
.vs-reaction.is-mine { background: var(--primary-soft); border-color: #d6cffc; color: var(--primary-dark); font-weight: 700; }
.vs-react-btn { border: 0; background: transparent; cursor: pointer; font-size: 1.25rem; padding: .15rem .3rem; border-radius: 10px; transition: transform .1s ease; }
.vs-react-btn:hover { background: var(--primary-soft); transform: scale(1.25); }

/* Réponses en fil */
.chat-replies {
    margin: .35rem 0 .2rem; padding-left: .9rem;
    border-left: 2px solid var(--line); display: flex; flex-direction: column; gap: .35rem;
}
.chat-msg.is-mine .chat-replies { align-self: stretch; }
.chat-reply { display: flex; align-items: flex-start; gap: .4rem; }
.chat-reply-av { flex: 0 0 auto; align-self: flex-start; margin-top: .1rem; }
.chat-reply-main { min-width: 0; display: flex; flex-direction: column; max-width: 80%; }
.chat-reply-head { display: flex; align-items: center; gap: .4rem; margin: 0 .3rem .08rem; }
.chat-reply-author { font-size: .74rem; font-weight: 800; color: var(--primary-dark); }
.chat-reply-time { font-size: .68rem; color: var(--muted); white-space: nowrap; }
.chat-reply-bubble {
    background: var(--card); border: 1px solid var(--line); border-radius: 12px;
    padding: .35rem .6rem; font-size: .9rem;
    display: flex; flex-direction: column; gap: .1rem;
}
.chat-reply.is-mine .chat-reply-bubble { background: var(--primary-soft); border-color: #ded8fc; }
.chat-reply-text { white-space: pre-wrap; word-break: break-word; }
/* Neutraliser les marges des <p> Tiptap (sinon la bulle de réponse est trop haute). */
.chat-reply-text p { margin: 0 0 .3rem; }
.chat-reply-text p:last-child { margin-bottom: 0; }
.chat-reply-text p:empty { display: none; }

/* Composer */
/* Composer façon Teams : une seule barre arrondie, icônes inline à droite */
.chat-composer { border-top: 1px solid var(--line); padding: .7rem .9rem .8rem; background: #fff; }
/* Bannière « réponse » : message cité au-dessus du composer (façon Teams). */
.cps-reply {
    display: flex; align-items: flex-start; gap: .5rem;
    margin-bottom: .5rem; padding: .4rem .55rem;
    background: var(--primary-soft); border-left: 3px solid var(--primary);
    border-radius: 8px;
}
.cps-reply[hidden] { display: none; } /* sinon display:flex masque l'attribut hidden */
.cps-reply-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: .05rem; }
.cps-reply-head { font-size: .78rem; font-weight: 700; color: var(--primary-dark); }
.cps-reply-extract { font-size: .8rem; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cps-reply-cancel {
    flex: none; border: 0; background: transparent; cursor: pointer; color: var(--muted);
    font-size: .85rem; line-height: 1; padding: .15rem .35rem; border-radius: 6px;
}
.cps-reply-cancel:hover { background: rgba(0,0,0,.06); color: var(--ink); }
.cps {
    display: flex; align-items: flex-end; gap: .4rem;
    border: 1.5px solid var(--line); border-radius: 14px;
    padding: .25rem .35rem .25rem .9rem; background: #fff;
    transition: border-color .12s ease, box-shadow .12s ease;
}
.cps:focus-within { border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-soft); }
/* Zone d'édition Tiptap : .cps-editor = conteneur (flex), .cps-input = .ProseMirror. */
.cps-editor { flex: 1 1 auto; min-width: 0; }
.cps-input {
    min-height: 22px; max-height: 180px; overflow-y: auto;
    outline: none; font: inherit; line-height: 1.5; padding: .5rem 0; color: var(--ink);
    overflow-wrap: anywhere;
}
.cps-input p { margin: 0; }
.cps-input p + p { margin-top: .15rem; }
/* Placeholder Tiptap (extension Placeholder). */
.cps-input p.is-editor-empty:first-child::before {
    content: attr(data-placeholder); color: var(--muted); float: left; height: 0; pointer-events: none;
}
/* Mode rédaction (barre de mise en forme ouverte) : éditeur plus spacieux, comme Teams. */
.chat-composer.is-rich .cps-input { min-height: 90px; }
.chat-composer.is-rich .cps { align-items: stretch; }
.chat-composer.is-rich .cps-tools { align-items: flex-end; }
/* Composer Vie Scolaire : sujet optionnel (style annonce de Pauline). */
.vs-composer { display: flex; flex-direction: column; gap: .5rem; }
/* Rangée du haut du composer : « Ajoutez un sujet » à gauche, ⚙️ modifier à droite. */
.vs-composer-top { display: flex; align-items: center; justify-content: space-between; gap: .5rem; }
.vs-subject-toggle {
    align-self: flex-start; background: none; border: none; cursor: pointer;
    padding: .1rem 0; color: var(--primary); font-weight: 600; font-size: .85rem;
}
.vs-subject-input { font-weight: 700; }
.vs-send { width: auto; margin-left: auto; }

/* Dashboard Vie Scolaire (façon Pauline) : pas de panneau autour. Chaque bloc
   (composer, recherche, message) est sa propre carte, dans une colonne. */
.dash-msg-chat .chat.vs-hub {
    /* display/align forcés : la classe vs-hub porte aussi une règle legacy
       (grid + align-items:start) qui empêchait le composer de s'étirer en largeur. */
    display: flex; flex-direction: column; align-items: stretch;
    background: transparent; border: none; box-shadow: none; border-radius: 0;
    padding: 0; gap: .8rem;
}
/* Zone de saisie : éditeur Tiptap qui remplit la carte composer. */
.vs-composer .cps-editor.vs-input {
    width: 100%; box-sizing: border-box;
    border: 1px solid var(--line); border-radius: 12px; background: #fff;
    padding: .55rem .8rem; cursor: text;
}
.vs-composer .cps-editor.vs-input .cps-input { padding: 0; min-height: 4.5rem; max-height: 240px; }
.vs-composer:focus-within .cps-editor.vs-input { border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-soft); }
.vs-composer-bar { align-items: center; }
/* Bouton « Publier » : texte blanc (.cps-send du module le peignait en violet). */
.vs-send.cps-send { color: #fff; }
.vs-send.cps-send:hover { color: #fff; }

/* Corps de message en HTML (Tiptap) dans le cadre .vs-msg. */
.vs-msg-body--html { white-space: normal; }
.vs-msg-body--html p { margin: 0; }
.vs-msg-body--html p + p { margin-top: .25rem; }
.vs-msg-body--html ul, .vs-msg-body--html ol { margin: .2rem 0; padding-left: 1.25rem; }
.vs-msg-body--html mark { background: #fff3a3; padding: 0 .15rem; border-radius: 3px; }
.vs-msg-body--html a { color: var(--brand); text-decoration: underline; }

/* Actions d'un message (réagir / répondre / modifier) via <details>. */
.vs-pop { position: relative; }
.vs-pop > summary { list-style: none; }
.vs-pop > summary::-webkit-details-marker { display: none; }
.vs-pop[open] > summary.vs-act-btn { background: var(--primary-soft); color: var(--primary); }
/* Réagir / Répondre / Modifier s'ouvrent DANS la carte du message (en flux, pleine
   largeur sous la barre d'actions) — plus de boîte flottante. */
.vs-msg-actions .vs-pop[open] { flex: 1 0 100%; }
.vs-pop--pick > .vs-react-picker {
    margin-top: .4rem; display: flex; flex-wrap: wrap; gap: .15rem;
    background: var(--card, #fff); border: 1px solid var(--line); border-radius: 999px;
    padding: .25rem .35rem; width: max-content; max-width: 100%;
}
.vs-pop > .vs-reply-form, .vs-pop > .vs-edit-form {
    width: 100%; margin-top: .5rem;
    background: var(--bg); border: 1px solid var(--line); border-radius: 12px; padding: .8rem;
}
.vs-pop > .vs-reply-form .vs-input, .vs-pop > .vs-edit-form .vs-input { width: 100%; }

/* ── Barre d'actions d'un message Vie Scolaire : pilule d'icônes, révélée au survol ──
   Placée sur la ligne nom + heure (margin-left:auto). Les popovers (réagir / répondre /
   modifier) s'ouvrent en panneaux flottants : le fil du dashboard scrolle avec la PAGE
   (pas de cadre interne) et ni .card ni .vs-msg n'ont d'overflow → aucun rognage. */
.vs-msg-tools {
    position: relative; margin-left: auto; flex: none;
    display: inline-flex; align-items: center; gap: .1rem;
    padding: .14rem; border-radius: 11px;
    background: var(--card, #fff); border: 1px solid var(--line);
    box-shadow: 0 4px 14px rgba(20, 20, 50, .10);
    opacity: 0; transform: translateY(-3px); pointer-events: none;
    transition: opacity .14s ease, transform .14s ease;
}
.vs-msg:hover > .vs-msg-main > .vs-msg-head > .vs-msg-tools,
.vs-reply:hover .vs-msg-tools,
.vs-msg-main:focus-within > .vs-msg-head > .vs-msg-tools,
.vs-msg-tools:has(.vs-pop[open]) {
    opacity: 1; transform: none; pointer-events: auto;
}
/* Boutons d'action Messagerie/VS migrés en .icon-btn : masquer le marqueur du
   <summary> (popover réagir/modifier) + reproduire l'état actif du popover ouvert. */
.vs-msg-tools summary.icon-btn { list-style: none; }
.vs-msg-tools summary.icon-btn::-webkit-details-marker { display: none; }
.vs-pop[open] > summary.icon-btn { opacity: 1; background: color-mix(in srgb, currentColor 15%, transparent); }

/* Popovers ouverts DEPUIS la barre = panneaux flottants ancrés sous la pilule. */
.vs-msg-tools .vs-pop { position: static; }
.vs-msg-tools .vs-pop[open] > .vs-react-picker {
    position: absolute; top: calc(100% + .4rem); right: 0; z-index: 40; margin: 0;
    background: var(--card, #fff); border: 1px solid var(--line); border-radius: 999px;
    box-shadow: 0 8px 24px rgba(20, 20, 50, .14); padding: .28rem .4rem; width: max-content; max-width: 80vw;
}
.vs-msg-tools .vs-pop[open] > .vs-reply-form,
.vs-msg-tools .vs-pop[open] > .vs-edit-form {
    position: absolute; top: calc(100% + .4rem); right: 0; z-index: 40; margin: 0;
    width: min(440px, 82vw); text-align: left;
    background: var(--card, #fff); border: 1px solid var(--line); border-radius: 14px;
    box-shadow: 0 12px 32px rgba(20, 20, 50, .16); padding: .8rem;
}
.cps-input code { background: rgba(0,0,0,.06); padding: .05rem .3rem; border-radius: 5px; font-size: .9em; }
.cps-input a { color: var(--brand); text-decoration: underline; }
.cps-input ul, .cps-input ol { margin: .25rem 0; padding-left: 1.3rem; }
.cps-input blockquote { margin: .3rem 0; padding: .1rem .7rem; border-left: 3px solid var(--primary); }
.cps-input mark { background: #fff3a3; padding: 0 .15rem; border-radius: 3px; }
.cps-tools { flex: 0 0 auto; display: flex; align-items: center; gap: .1rem; padding-bottom: .15rem; }
.cps-wrap { position: relative; display: inline-flex; }
.cps-btn {
    border: 0; background: transparent; cursor: pointer; color: var(--muted);
    width: 34px; height: 34px; border-radius: 9px;
    display: inline-flex; align-items: center; justify-content: center;
}
.cps-btn svg { width: 20px; height: 20px; }
.cps-aa { font-weight: 700; font-size: .92rem; letter-spacing: -.02em; }
.cps-btn:hover, .cps-btn.is-on { background: var(--primary-soft); color: var(--primary); }
.cps-send { color: var(--primary); }
.cps-send:hover { background: var(--primary); color: #fff; }
.cps-sep { width: 1px; align-self: stretch; margin: .35rem .2rem; background: var(--line); }
.cps-files { display: block; font-size: .76rem; color: var(--muted); margin: .4rem 0 0 .3rem; }

/* Popovers du composer (format / émoji) */
.cps-pop {
    position: absolute; bottom: calc(100% + 8px); right: 0; z-index: 40;
    background: #fff; border: 1px solid var(--line); border-radius: 12px; box-shadow: var(--shadow);
    padding: .35rem;
}
/* L'attribut hidden doit l'emporter sur les display:flex/grid ci-dessous. */
.cps-pop[hidden] { display: none; }
.cps-format { display: flex; align-items: center; gap: .1rem; }
.cps-fmt-sep { width: 1px; height: 20px; background: var(--line); margin: 0 .2rem; }
.cps-format mark { background: #fff3a3; padding: 0 .15rem; border-radius: 3px; }
.cps-format button {
    border: 0; background: transparent; cursor: pointer; min-width: 30px; height: 30px;
    border-radius: 8px; font-size: .9rem; color: var(--ink);
}
.cps-format button:hover { background: var(--primary-soft); color: var(--primary); }
.cps-format button.is-on { background: var(--primary); color: #fff; }
.cps-emoji { display: grid; grid-template-columns: repeat(5, 1fr); gap: .1rem; width: max-content; }
.cps-emoji button { border: 0; background: transparent; cursor: pointer; font-size: 1.25rem; padding: .15rem .3rem; border-radius: 8px; }
.cps-emoji button:hover { background: var(--primary-soft); transform: scale(1.15); }

/* Mentions : puce dans l'éditeur + menu d'autocomplétion */
.cps-mention {
    background: var(--primary-soft); color: var(--primary-dark); font-weight: 600;
    padding: 0 .3rem; border-radius: 6px; white-space: nowrap;
}
.chat-composer { position: relative; }
.cps-mention-menu {
    position: absolute; z-index: 50; min-width: 200px; max-width: 280px;
    background: #fff; border: 1px solid var(--line); border-radius: 12px; box-shadow: var(--shadow);
    padding: .25rem; display: flex; flex-direction: column; gap: 1px;
}
.cps-mention-item {
    text-align: left; border: 0; background: transparent; cursor: pointer;
    padding: .4rem .55rem; border-radius: 8px; font-size: .88rem; color: var(--ink);
}
.cps-mention-item:hover, .cps-mention-item.is-active { background: var(--primary-soft); color: var(--primary-dark); }

/* Mise en forme rendue dans les messages (et dans l'éditeur WYSIWYG) */
.chat-msg-text code, .chat-reply-text code, .cps-input code { background: rgba(0,0,0,.06); padding: .05rem .3rem; border-radius: 5px; font-size: .9em; }
.chat-msg.is-mine .chat-msg-text code { background: rgba(255,255,255,.2); }
.chat-msg-text a, .chat-reply-text a { color: var(--brand); text-decoration: underline; }
.chat-msg.is-mine .chat-msg-text a { color: #fff; }
.chat-msg-text mark, .cps-input mark { background: #fff3a3; padding: 0 .15rem; border-radius: 3px; }
.chat-msg.is-mine .chat-msg-text mark { color: var(--ink); }
.chat-msg-text ul, .chat-msg-text ol, .cps-input ul, .cps-input ol { margin: .25rem 0; padding-left: 1.3rem; }
.chat-msg-text li, .cps-input li { margin: .1rem 0; }
.chat-msg-text blockquote, .cps-input blockquote {
    margin: .3rem 0; padding: .15rem .7rem; border-left: 3px solid var(--primary); color: inherit; opacity: .9;
}
.chat-msg.is-mine .chat-msg-text blockquote { border-left-color: rgba(255,255,255,.6); }

/* Modales création */
.msg-dialog {
    border: 0; border-radius: var(--radius); padding: 1.4rem; width: min(460px, 92vw);
    max-height: 90vh; overflow-y: auto;
    box-shadow: var(--shadow); color: var(--ink);
}
.msg-dialog::backdrop { background: rgba(31,36,64,.45); backdrop-filter: blur(2px); }
.msg-dialog h3 { margin: 0 0 .2rem; }
.msg-dialog .input { width: 100%; border: 1.5px solid var(--line); border-radius: 10px; padding: .55rem .75rem; margin-top: .6rem; }
/* Outils de sélection de membres : recherche + « Tout sélectionner », au-dessus de la liste. */
.msg-roster-tools { display: flex; align-items: center; gap: .6rem; margin: .8rem 0 .35rem; }
.msg-roster-tools .input { margin-top: 0; }
.msg-roster-search { flex: 1 1 auto; }
.msg-roster-all { display: inline-flex; align-items: center; gap: .35rem; white-space: nowrap; font-size: .85rem; color: var(--muted); cursor: pointer; }
.msg-roster-all input { width: 1rem; height: 1rem; accent-color: var(--primary); cursor: pointer; }
.msg-roster-tools + .msg-roster { margin-top: 0; }
.msg-roster { border: 1px solid var(--line); border-radius: 12px; margin: .8rem 0 0; padding: .5rem; max-height: 190px; overflow-y: auto; }
.msg-roster legend { font-size: .8rem; color: var(--muted); padding: 0 .3rem; }
.msg-roster-item {
    display: flex; align-items: center; gap: .6rem;
    padding: .4rem .55rem; border-radius: 10px; cursor: pointer;
    border: 1px solid transparent;
}
.msg-roster-item:hover { background: var(--primary-soft); }
.msg-roster-item input { position: absolute; opacity: 0; pointer-events: none; }
.msg-roster-name { flex: 1 1 auto; }
.msg-roster-check {
    flex: 0 0 auto; width: 22px; height: 22px; border-radius: 999px;
    display: grid; place-items: center; color: #fff; font-size: .8rem; font-weight: 800;
    background: var(--line); transition: background .12s ease;
}
.msg-roster-item:has(input:checked) { background: var(--primary-soft); border-color: #d6cffc; }
.msg-roster-item:has(input:checked) .msg-roster-check { background: var(--primary); }
.msg-roster-item:not(:has(input:checked)) .msg-roster-check { color: transparent; }
.msg-dialog-actions { display: flex; justify-content: flex-end; gap: .5rem; margin: 1rem 0 0; padding: 0; }
/* Zone sensible du dialogue de paramétrage VS : suppression du groupe, séparée des actions. */
.vs-danger-zone { display: flex; align-items: center; gap: .7rem; flex-wrap: wrap; margin-top: .9rem; padding-top: .9rem; border-top: 1px solid var(--line); }
.vs-danger-hint { font-size: .8rem; }
/* (Ancienne définition de .btn-danger retirée : elle était écrasée par celle du
   bloc « boutons d'action », même spécificité mais déclarée plus bas — elle
   n'avait donc jamais d'effet. La variante rouge vit désormais avec les autres.) */

@media (max-width: 900px) {
    /* app-fit relâché sur mobile → on borne le chat au viewport explicitement. */
    .content:has(.chat) { display: block; overflow: visible; }
    .chat { height: calc(100dvh - 7rem); min-height: 420px; }
    .chat-msg-main { max-width: 86%; }
}

/* Menu droit « Mes équipes » — allégé, sections à scroll vertical indépendant */
.msg-nav { display: flex; flex-direction: column; gap: .7rem; margin-top: .5rem; }
.msg-nav-section { display: flex; flex-direction: column; min-height: 0; }
.msg-nav-head { display: flex; align-items: center; justify-content: space-between; padding: .15rem .45rem; }
.msg-nav-head > span { font-size: .7rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); }
.msg-nav-add {
    width: 22px; height: 22px; border-radius: 999px; border: 1px solid var(--line);
    background: #fff; color: var(--primary); cursor: pointer;
    font-size: 1.05rem; font-weight: 700; line-height: 0; padding: 0;
    display: inline-flex; align-items: center; justify-content: center;
}
.msg-nav-add:hover { background: var(--primary-soft); border-color: #d6cffc; }
.msg-nav-search {
    width: 100%; border: 1px solid var(--line); border-radius: 8px;
    padding: .35rem .55rem; font: inherit; font-size: .82rem; margin: .15rem 0 .4rem;
}
.msg-nav-search:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-soft); }
.msg-nav-list { max-height: 34vh; overflow-y: auto; display: flex; flex-direction: column; gap: 1px; }
.msg-nav-item {
    display: flex; align-items: center; gap: .5rem;
    padding: .35rem .5rem; border-radius: 8px; text-decoration: none; color: var(--ink);
    font-size: .88rem;
}
.msg-nav-item:hover { background: var(--primary-soft); }
.msg-nav-item.is-current { background: var(--primary-soft); box-shadow: inset 3px 0 0 var(--primary); }
.msg-nav-item.is-current .msg-nav-name { color: var(--primary-dark); font-weight: 600; }
.msg-nav-ico { flex: 0 0 auto; font-size: .9rem; opacity: .75; }
.msg-nav-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 400; }
.msg-nav-badge {
    flex: 0 0 auto; min-width: 18px; height: 18px; padding: 0 5px; border-radius: 999px;
    background: #dc2626; color: #fff; font-size: .68rem; font-weight: 800; display: grid; place-items: center;
}
.msg-nav-empty { font-size: .8rem; color: var(--muted); padding: .3rem .5rem; margin: 0; }

/* Messages flash (feedback global, ex. erreurs/confirmations) */
.flash {
    position: fixed; top: 4.2rem; left: 50%; transform: translateX(-50%);
    z-index: 200; max-width: min(560px, 92vw);
    padding: .7rem 1.1rem; border-radius: 12px; box-shadow: var(--shadow);
    font-weight: 600; font-size: .9rem; color: #fff;
    animation: flash-in .2s ease, flash-out .4s ease 4.6s forwards;
}
.flash + .flash { top: 7.3rem; }
.flash-success { background: var(--ok); }
.flash-error { background: #dc2626; }
.flash-info, .flash-notice { background: var(--primary); }
@keyframes flash-in { from { opacity: 0; transform: translate(-50%, -8px); } to { opacity: 1; transform: translate(-50%, 0); } }
@keyframes flash-out { to { opacity: 0; transform: translate(-50%, -8px); visibility: hidden; } }

/* === Boîte mail (module Messagerie ✉️) — disposition façon Outlook === */
/* Coquille maître-détail plein écran : la page ne scrolle pas, chaque volet a son overflow. */
/* .mailx-page = classe explicite (en plus de :has(.mailx)) pour garantir le scroll
   par volet même sur navigateurs sans :has(). */
.content:has(.mailx), .content.mailx-page { display:flex; flex-direction:column; overflow:hidden; min-height:0; max-width:none; }
.content:has(.mailx) > .crumbs, .content:has(.mailx) > .flash,
.content.mailx-page > .crumbs, .content.mailx-page > .flash { flex:none; }
.mailx {
    display:flex; flex:1; min-height:0;
    border:1px solid var(--border, #eee); border-radius:12px; overflow:hidden; background:#fff;
}
/* (a) Colonne dossiers — cachée en 2 volets (défaut), visible en 3 volets. */
.mailx-folders { display:none; }
.mailx.is-3pane .mailx-folders {
    display:flex; flex-direction:column; gap:.15rem; width:230px; flex:none;
    padding:.7rem; border-right:1px solid var(--border, #eee); overflow-y:auto;
}
.mailx-folder {
    display:flex; align-items:center; gap:.55rem; padding:.5rem .6rem; border-radius:8px;
    text-decoration:none; color:inherit; font-weight:600;
}
.mailx-folder:hover { background:var(--primary-soft, #f3f1ff); }
.mailx-folder.is-active { background:var(--primary-soft, #f3f1ff); color:var(--primary, #6d5efc); }
.mailx-folder.is-new { background:var(--primary, #6d5efc); color:#fff; justify-content:center; margin-bottom:.4rem; }
.mailx-folder.is-new:hover { filter:brightness(1.05); }
.mailx-folder-label { flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.mailx-folder-badge { background:var(--primary, #6d5efc); color:#fff; border-radius:10px; padding:0 .4rem; font-size:.72rem; font-weight:700; }
.mailx-folder.is-new .mailx-folder-badge,
.mailx-folder.is-active .mailx-folder-badge { background:#fff; color:var(--primary, #6d5efc); }

/* (b) Volet liste */
.mailx-list { width:360px; flex:none; display:flex; flex-direction:column; min-height:0; border-right:1px solid var(--border, #eee); }
.mailx-list-head { display:flex; align-items:center; justify-content:space-between; gap:.5rem; padding:.6rem .7rem; border-bottom:1px solid var(--border, #eee); flex:none; }
.mailx-folder-menu { position:relative; }
.mailx-folder-menu > summary { list-style:none; cursor:pointer; font-weight:800; font-size:1.05rem; display:inline-flex; align-items:center; gap:.3rem; }
.mailx-folder-menu > summary::-webkit-details-marker { display:none; }
.mailx-caret { font-size:.7rem; color:var(--muted, #888); }
.mailx-folder-dd { position:absolute; z-index:40; top:100%; left:0; margin-top:.3rem; min-width:220px; background:#fff; border:1px solid var(--border, #ddd); border-radius:10px; box-shadow:0 8px 24px rgba(0,0,0,.12); padding:.3rem; display:flex; flex-direction:column; }
.mailx-folder-dd a { padding:.45rem .6rem; border-radius:7px; text-decoration:none; color:inherit; }
.mailx-folder-dd a:hover { background:var(--primary-soft, #f3f1ff); }
.mailx-folder-dd a.is-active { color:var(--primary, #6d5efc); font-weight:700; }
.mailx-list-tools { display:flex; align-items:center; gap:.15rem; }
.mailx-tool-form { display:contents; }
.mailx-tool { display:inline-flex; align-items:center; gap:.25rem; background:none; border:1px solid transparent; border-radius:7px; cursor:pointer; color:var(--muted, #666); font-size:.8rem; padding:.25rem .45rem; text-decoration:none; }
.mailx-tool:hover { background:var(--primary-soft, #f3f1ff); }
.mailx-tool.is-on { color:var(--primary, #6d5efc); border-color:var(--primary, #6d5efc); font-weight:600; }
/* Menu filtre/tri/affichage façon Outlook : 1 icône → 1 menu qui regroupe tout. */
.mailx-filter-menu { position:relative; flex:none; }
.mailx-filter-btn { list-style:none; cursor:pointer; display:inline-flex; align-items:center; justify-content:center; width:32px; height:32px; border-radius:8px; color:var(--muted, #666); border:1px solid transparent; }
.mailx-filter-btn::-webkit-details-marker { display:none; }
.mailx-filter-btn:hover, .mailx-filter-menu[open] > .mailx-filter-btn { background:var(--primary-soft, #f3f1ff); color:var(--primary, #6d5efc); }
.mailx-filter-dd { position:absolute; z-index:40; top:100%; right:0; margin-top:.3rem; min-width:262px; background:#fff; border:1px solid var(--border, #ddd); border-radius:12px; box-shadow:0 10px 30px rgba(0,0,0,.14); padding:.4rem; display:flex; flex-direction:column; }
.mailx-filter-dd form { display:block; }
.mailx-filter-head { font-weight:800; font-size:.95rem; padding:.4rem .6rem .3rem; }
.mailx-filter-group { font-size:.72rem; text-transform:uppercase; letter-spacing:.03em; color:var(--muted, #999); padding:.5rem .6rem .15rem; }
.mailx-filter-opt { display:flex; align-items:center; gap:.25rem; width:100%; text-align:left; background:none; border:none; cursor:pointer; padding:.45rem .6rem; border-radius:8px; font-size:.9rem; font-family:inherit; color:inherit; text-decoration:none; }
.mailx-filter-opt:hover { background:var(--primary-soft, #f3f1ff); }
.mailx-filter-opt.is-on { color:var(--primary, #6d5efc); font-weight:600; }
.mailx-filter-check { width:1.1rem; flex:none; text-align:center; color:var(--primary, #6d5efc); font-weight:700; }
.mailx-filter-sep { height:1px; background:var(--border, #eee); margin:.3rem .35rem; }

.mail-list { display:flex; flex-direction:column; flex:1; min-height:0; overflow-y:auto; }
.mail-day { position:sticky; top:0; z-index:1; background:#fff; padding:.4rem .7rem .2rem; font-size:.76rem; font-weight:700; text-transform:uppercase; letter-spacing:.03em; color:var(--muted, #999); }
.mail-row { display:flex; align-items:center; gap:.3rem; border-bottom:1px solid var(--border, #f0f0f0); position:relative; }
.mail-row-link { display:flex; align-items:flex-start; gap:.6rem; padding:.55rem .6rem; flex:1; min-width:0; text-decoration:none; color:inherit; }
.mail-row:hover { background:var(--primary-soft, #f3f1ff); }
.mail-row.is-selected { background:var(--primary-soft, #ece9ff); box-shadow:inset 3px 0 0 var(--primary, #6d5efc); }
/* Gras UNIQUEMENT si non lu : expéditeur en gras noir, titre en gras bleu. */
.mail-row.is-unread .mail-from { font-weight:800; color:#171717; }
.mail-row.is-unread .mail-subject { font-weight:800; color:var(--brand, #0189d9); }
.mail-row.is-unread::before { content:''; position:absolute; left:.18rem; top:50%; transform:translateY(-50%); width:7px; height:7px; border-radius:50%; background:var(--primary, #6d5efc); }
.mail-row-main { min-width:0; flex:1; display:flex; flex-direction:column; gap:.05rem; }
.mail-row-top { display:flex; justify-content:space-between; gap:.5rem; }
.mail-from { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-weight:400; }
.mail-when { color:var(--muted, #888); font-size:.78rem; flex:none; margin-top:1.25rem; }
.mail-subject { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.mail-preview { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; color:var(--muted, #888); font-size:.82rem; }
.mail-count { background:var(--primary, #6d5efc); color:#fff; border-radius:10px; padding:0 .4rem; font-size:.72rem; }
.mail-clip { flex:none; align-self:center; font-size:.85rem; }
/* Indicateur de suivi (drapeau) persistant sur la ligne quand le mail est marqué. */
.mail-flag { flex:none; align-self:center; font-size:.85rem; }
.mail-star-form { flex:none; padding-right:.35rem; }
.mail-star { background:none; border:none; cursor:pointer; font-size:1.05rem; padding:.2rem; color:var(--muted, #bbb); line-height:1; }
.mail-star:hover { color:#f2b705; }
.mail-star.is-on { color:#f2b705; }
/* Colonne de droite façon Outlook : barre d'outils TRANSPARENTE en ligne 1 (révélée au
   survol ; une bascule activée — drapeau/favori/épingle — reste affichée), date en LIGNE 2. */
.mail-row-aside { position:relative; flex:none; align-self:flex-start; display:flex; flex-direction:column; align-items:flex-end; padding:.55rem .55rem .35rem 0; min-width:46px; }
.mail-row-actions { position:absolute; top:.4rem; right:.5rem; display:flex; align-items:center; gap:.05rem; background:transparent; }
/* Actions de ligne mail : icône seule révélée au survol de la ligne */
.mail-row-actions .icon-btn { display: none; }
.mail-row:hover .mail-row-actions .icon-btn,
.mail-row-actions:has(details[open]) .icon-btn,
.mail-row-actions .icon-btn.is-on { display: inline-flex; }
.mail-row.is-pinned { background:color-mix(in srgb, var(--brand, #0189d9) 6%, transparent); }

/* (c) Volet détail */
.mailx-detail { flex:1; min-width:0; display:flex; flex-direction:column; min-height:0; overflow-y:auto; }
/* Mode rédaction (nouveau message / répondre / transférer) : écran dédié — on masque
   la liste pour ne pas donner l'impression de « répondre dans la boîte ». Composer centré. */
.mailx.is-composing .mail-compose { max-width:820px; margin-inline:auto; width:100%; }
.mail-compose-title { font-size:1.05rem; font-weight:700; margin:.7rem .9rem .2rem; }
.mailx-detail-bar { display:flex; align-items:center; flex-wrap:wrap; gap:.4rem; padding:.7rem .9rem; border-bottom:1px solid var(--border, #eee); position:sticky; top:0; background:#fff; z-index:2; }
.mailx-detail-bar form { display:inline; }
.mailx-bar-spacer { flex:1; }
.mailx-empty { margin:auto; text-align:center; color:var(--muted, #888); padding:2rem; }
.mailx-empty .big { font-size:3rem; }
.mailx-empty h3 { margin:.4rem 0 .2rem; }
.mailx-empty .btn { margin-top:.8rem; }
.mail-thread { padding:0 0 1.4rem; }
/* Sujet (petit) seul en haut — peu d'espace avant l'expéditeur, pas de séparateur ici. */
.mail-thread-head { display:flex; align-items:flex-start; gap:.6rem; padding:.8rem 1.1rem .2rem; position:sticky; top:0; background:#fff; z-index:2; }
.mail-thread-head + .mail-msg { padding-top:.3rem; }
.mail-thread-subject { margin:0; font-size:1.15rem; font-weight:700; line-height:1.3; min-width:0; overflow-wrap:anywhere; }
.mail-thread-tools { display:flex; align-items:center; gap:.15rem; flex:none; }
/* Message : plus de carte bordée — zone de lecture aérée, pleine largeur. */
.mail-msg { padding:.95rem 1.1rem; }
.mail-msg + .mail-msg { border-top:1px solid var(--border, #f0f0f0); }
/* Séparateur APRÈS l'en-tête (nom + « à … » + icônes), avant le corps. */
.mail-msg-head { display:flex; align-items:center; gap:.6rem; padding-bottom:.7rem; margin-bottom:.85rem; border-bottom:1px solid var(--border, #eee); }
.mail-msg-who { display:flex; flex-direction:column; min-width:0; flex:1; gap:.05rem; }
.mail-msg-name { color:#171717; font-weight:700; font-size:.98rem; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.mail-msg-meta { color:var(--muted, #888); font-size:.82rem; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
/* Actions du message : uniquement des icônes, toutes sur une seule ligne. */
.mail-msg-actions { display:flex; align-items:center; gap:.15rem; flex:none; }
.mail-msg-body { line-height:1.6; }
.mail-pj { display:inline-block; margin-top:.5rem; margin-right:.5rem; font-size:.9rem; }
.mail-actions { display:flex; flex-wrap:wrap; gap:.5rem; margin-top:.8rem; }
/* ---- Composer (rédaction) façon Outlook/Gmail ---- */
.mail-compose { display:flex; flex-direction:column; flex:1; min-height:0; }

/* Boutons du module mail : compacts, largeur auto (annule le .btn width:100%) */
.mail-compose-bar .btn,
.mailx-detail-bar .btn,
.mail-schedule-menu .btn,
.mail-schedule-submit { width: auto; }

/* Barre d'action : 1 bouton primaire compact + actions icônes discrètes */
.mail-compose-bar { display:flex; align-items:center; gap:.35rem; padding:.55rem .9rem; border-bottom:1px solid var(--border, #eee); background:#fafafe; }
.mail-send-btn {
    width: auto;
    padding: .3rem .72rem;
    font-size: .85rem;
    font-weight: 600;
    border-radius: 7px 0 0 7px;
    line-height: 1.15;
    display: inline-flex;
    align-items: center;
    gap: .3rem;
}
/* Lorsqu'il n'y a pas de caret accolé (ex : lien Répondre), arrondi plein */
a.mail-send-btn, a.btn.mail-send-btn { border-radius: 7px; }
.mail-send-caret {
    width: auto;
    padding: .3rem .5rem;
    border-radius: 0 7px 7px 0;
    border-left: 1px solid rgba(255,255,255,.3);
    font-size: .8rem;
    font-weight: 700;
    line-height: 1.15;
    display: inline-flex;
    align-items: center;
}
/* Menu split-button envoi différé */
[data-controller~="mail-schedule"] { position: relative; display: inline-flex; align-items: center; }
.mail-schedule-menu {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    z-index: 20;
    background: #fff;
    border: 1px solid var(--border, #e6e6ef);
    border-radius: 10px;
    box-shadow: 0 8px 24px rgba(0,0,0,.12);
    padding: .3rem;
    min-width: 230px;
}
.mail-schedule-menu[hidden] { display: none; }
.mail-schedule-item {
    display: block;
    width: 100%;
    text-align: left;
    padding: .45rem .7rem;
    border: none;
    background: none;
    border-radius: 7px;
    cursor: pointer;
    font-size: .9rem;
    color: var(--text, #1a1a2e);
}
.mail-schedule-item:hover { background: var(--primary-soft, #f3f1ff); }
.mail-schedule-sep { border: none; border-top: 1px solid var(--border, #e6e6ef); margin: .2rem 0; }
.mail-schedule-custom { display: flex; align-items: center; flex-wrap: wrap; gap: .4rem; padding: .3rem .5rem .4rem; }
.mail-schedule-dt { flex: 1; border: 1px solid var(--border, #e6e6ef); border-radius: 7px; padding: .25rem .5rem; font-size: .88rem; }
.mail-schedule-submit { padding: .25rem .6rem; font-size: .82rem; font-weight: 600; border-radius: 7px; }
/* Bandeau mail programmé (vue lecture) */
.mail-prog-banner {
    background: var(--primary-soft, #f3f1ff);
    color: var(--primary, #6d5efc);
    padding: .5rem .8rem;
    border-radius: 8px;
    font-weight: 600;
    margin: .6rem .9rem;
}
/* Badge « Programmé » dans la liste */
.mail-badge-prog {
    display: inline-block;
    font-size: .68rem;
    font-weight: 700;
    background: var(--primary-soft, #f3f1ff);
    color: var(--primary, #6d5efc);
    border-radius: 6px;
    padding: .05rem .35rem;
    margin-left: .3rem;
    vertical-align: middle;
    white-space: nowrap;
}
.mail-when-prog { font-size: .78rem; color: var(--muted, #888); }
.tile-ico.mail-at { font-weight: 800; }
.mail-pill { font-weight: 800; }
.mail-bar-sep { width:1px; align-self:stretch; background:var(--border,#e6e6ef); margin:.1rem .5rem; }

/* ── Dossiers personnalisés ─────────────────────────────────────── */
.mailx-folders-group { padding:.6rem .7rem .2rem; font-size:.72rem; font-weight:700; text-transform:uppercase; letter-spacing:.06em; color:var(--muted,#999); }
.mailx-folder-perso { font-size:.9rem; }
/* Zone de drop : contour pointillé + fond doux */
.mailx-folder.is-drop { outline:2px dashed var(--primary,#6d5efc); background:var(--primary-soft,#f3f1ff); }
/* Glisser-déposer par événements pointer (cf. mail_classer_controller) */
.mailx[data-dragging] { user-select:none; cursor:grabbing; }
.mailx[data-dragging] .mail-row-link { pointer-events:none; } /* le clic n'ouvre pas pendant le glisser */
.mail-classer-ghost { position:fixed; z-index:1000; pointer-events:none; background:var(--primary,#6d5efc); color:#fff; padding:.25rem .6rem; border-radius:8px; font-size:.82rem; font-weight:600; box-shadow:0 8px 24px rgba(0,0,0,.28); white-space:nowrap; max-width:280px; overflow:hidden; text-overflow:ellipsis; }
/* Nouveau dossier */
.mailx-folder-new-wrap { padding:.5rem .5rem .4rem; }
.mailx-folder-new-btn { width:100%; background:none; border:1px dashed var(--border,#ddd); border-radius:8px; cursor:pointer; color:var(--muted,#888); font-size:.82rem; padding:.3rem .5rem; text-align:left; }
.mailx-folder-new-btn:hover { border-color:var(--primary,#6d5efc); color:var(--primary,#6d5efc); }
.mailx-folder-new-form { display:flex; gap:.3rem; align-items:center; }
.mailx-folder-new-input { flex:1; min-width:0; border:1px solid var(--border,#ddd); border-radius:7px; padding:.25rem .45rem; font-size:.85rem; font-family:inherit; outline:none; }
.mailx-folder-new-input:focus { border-color:var(--primary,#6d5efc); }
.mailx-folder-new-ok { flex:none; background:var(--primary,#6d5efc); color:#fff; border:none; border-radius:7px; padding:.25rem .5rem; cursor:pointer; font-size:.9rem; }
/* En-tête du dossier perso courant */
.mailx-dossier-perso-head { display:flex; align-items:center; gap:.4rem; padding:.5rem .7rem; border-bottom:1px solid var(--border,#eee); background:#fafafe; flex:none; }
.mailx-dossier-perso-titre { font-weight:700; flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.mailx-dossier-rename-form { display:flex; align-items:center; gap:.2rem; }
.mailx-dossier-rename-input { border:1px solid var(--border,#ddd); border-radius:6px; padding:.18rem .35rem; font-size:.82rem; font-family:inherit; outline:none; max-width:110px; }
.mailx-dossier-rename-input:focus { border-color:var(--primary,#6d5efc); }
/* Séparateur dans le dropdown du header */
.mailx-folder-dd-sep { height:1px; background:var(--border,#eee); margin:.2rem 0; }
/* Menu « Classer » par ligne */
.mail-row-classer { position:relative; flex:none; }
.mail-row-classer > summary { list-style:none; cursor:pointer; }
.mail-row-classer > summary::-webkit-details-marker { display:none; }
.mail-row-classer[open] > summary { background:var(--primary-soft,#f3f1ff); border-radius:8px; }
.mail-row-classer-dd { position:absolute; z-index:50; right:0; top:100%; min-width:180px; background:#fff; border:1px solid var(--border,#ddd); border-radius:10px; box-shadow:0 8px 24px rgba(0,0,0,.12); padding:.3rem; display:flex; flex-direction:column; }
.mail-row-classer-dd form { display:block; }
.mail-row-classer-opt { width:100%; text-align:left; background:none; border:none; cursor:pointer; padding:.4rem .6rem; border-radius:7px; font-size:.88rem; font-family:inherit; color:inherit; }
.mail-row-classer-opt:hover { background:var(--primary-soft,#f3f1ff); }
.mail-row-classer-opt.is-active { color:var(--primary,#6d5efc); font-weight:700; }

/* En-têtes serrés : libellé gris à gauche, champ pleine largeur, fin séparateur */
.mail-heads { display:flex; flex-direction:column; flex:none; }
.mail-head { display:flex; align-items:center; gap:.5rem; padding:.3rem .9rem; border-bottom:1px solid var(--border,#eee); font-weight:400; }
.mail-head-label { flex:none; width:42px; color:var(--muted,#888); font-size:.85rem; font-weight:600; }
.mail-head-field { position:relative; flex:1; min-width:0; display:flex; flex-wrap:wrap; align-items:center; gap:.3rem; }
.mail-head-field .mail-suggest-list { top:calc(100% + 2px); left:0; }
.mail-head-input { flex:1; min-width:120px; border:none; outline:none; background:none; padding:.2rem 0; font-size:.95rem; font-family:inherit; }
.mail-subject { font-weight:400; }
.mail-cc-toggle { flex:none; border:none; background:none; color:var(--brand,#0189d9); cursor:pointer; font-size:.82rem; font-weight:600; padding:.1rem .3rem; border-radius:6px; }
.mail-cc-toggle:hover { background:var(--primary-soft,#f3f1ff); }

/* Zone d'écriture : prend tout l'espace restant, scroll interne propre */
.mail-pieces-info { flex:none; padding:.4rem .9rem; color:var(--muted,#777); font-size:.85rem; border-top:1px solid var(--border,#eee); }

/* Responsive : sous 900px, on empile (liste au-dessus, détail dessous). */
@media (max-width: 900px) {
    .content:has(.mailx), .content.mailx-page { display:block; overflow:visible; }
    .mailx { flex-direction:column; border-radius:0; }
    .mailx.is-3pane .mailx-folders { width:auto; flex-direction:row; flex-wrap:wrap; border-right:none; border-bottom:1px solid var(--border, #eee); }
    .mailx-list { width:auto; border-right:none; border-bottom:1px solid var(--border, #eee); max-height:45vh; }
    .mailx-detail { min-height:50vh; }
}
.mail-recipients { display:flex; flex-wrap:wrap; gap:.3rem; }
.mail-chip { display:inline-flex; align-items:center; gap:.35rem; background:var(--primary-soft,#f3f1ff); border-radius:14px; padding:.1rem .2rem .1rem .2rem; font-weight:500; font-size:.85rem; }
.mail-chip button { background:none; border:none; cursor:pointer; color:var(--muted,#888); line-height:1; padding:0 .2rem; }
.mail-chip button:hover { color:#c92a2a; }

/* Zone d'écriture : prend l'espace restant ; la barre de format colle en haut */
.mail-editor { flex:1; min-height:0; overflow-y:auto; margin:.7rem .9rem 0; padding:0; border:1px solid var(--border,#e3e3ee); border-radius:12px; background:#fff; display:flex; flex-direction:column; }
.mail-editor:focus-within { border-color:var(--primary,#6d5efc); box-shadow:0 0 0 3px var(--primary-soft,#f3f1ff); }

/* Barre de formatage collante en haut de la zone */
.mail-format-bar { position:sticky; top:0; z-index:2; display:flex; align-items:center; gap:.15rem; flex-wrap:wrap; padding:.4rem .55rem; background:#fafafe; border-bottom:1px solid var(--border,#eee); border-radius:12px 12px 0 0; }
.mail-fb-btn { display:inline-flex; align-items:center; justify-content:center; min-width:30px; height:30px; padding:0 .35rem; background:none; border:1px solid transparent; border-radius:7px; cursor:pointer; font-size:.95rem; font-weight:600; line-height:1; color:#333; }
.mail-fb-btn:hover { background:var(--primary-soft,#f3f1ff); }
.mail-fb-btn.is-active { background:var(--primary-soft,#ece9ff); border-color:var(--primary,#6d5efc); color:var(--primary,#6d5efc); }
.mail-fb-btn b, .mail-fb-btn i, .mail-fb-btn u, .mail-fb-btn s { font-style:inherit; }
.mail-fb-select { height:30px; border:1px solid var(--border,#ddd); border-radius:7px; background:#fff; cursor:pointer; font-size:.85rem; padding:0 .3rem; font-family:inherit; }
.mail-fb-sep { width:1px; height:20px; background:var(--border,#e6e6ef); margin:0 .2rem; }
.mail-fb-color { position:relative; display:inline-flex; }
.mail-fb-color-menu { position:absolute; top:calc(100% + 4px); left:0; z-index:10; display:flex; flex-wrap:wrap; gap:.3rem; width:128px; padding:.5rem; background:#fff; border:1px solid var(--border,#ddd); border-radius:10px; box-shadow:0 8px 24px rgba(0,0,0,.14); }
.mail-fb-color-menu[hidden] { display:none; }
.mail-fb-swatch { width:22px; height:22px; border:1px solid rgba(0,0,0,.12); border-radius:50%; cursor:pointer; padding:0; }
.mail-fb-swatch:hover { transform:scale(1.12); }
.mail-fb-swatch-clear { width:22px; height:22px; border:1px solid var(--border,#ddd); border-radius:50%; background:#fff; cursor:pointer; color:var(--muted,#888); font-size:.7rem; line-height:1; padding:0; }

/* Contenu éditable : rendu propre, AUCUN cadre par phrase/paragraphe (fix focus) */
.mail-editor .ProseMirror { flex:1; min-height:180px; outline:none; padding:.8rem 1rem; line-height:1.55; font-size:.97rem; }
.mail-editor .ProseMirror:focus, .mail-editor .ProseMirror:focus-visible { outline:none; box-shadow:none; border:none; }
.mail-editor .ProseMirror p { margin:.2em 0; }
.mail-editor .ProseMirror h2 { font-size:1.3rem; margin:.5em 0 .25em; }
.mail-editor .ProseMirror h3 { font-size:1.1rem; margin:.5em 0 .2em; }
.mail-editor .ProseMirror ul, .mail-editor .ProseMirror ol { padding-left:1.3em; margin:.3em 0; }
.mail-editor .ProseMirror blockquote { border-left:3px solid var(--primary,#6d5efc); margin:.4em 0; padding:.1em 0 .1em .8em; color:#555; }
.mail-editor .ProseMirror code { background:#f1f0fb; border-radius:4px; padding:.05em .35em; font-size:.9em; }
.mail-editor .ProseMirror hr { border:none; border-top:1px solid var(--border,#ddd); margin:.8em 0; }
.mail-editor .ProseMirror a { color:var(--brand,#0189d9); }
.mail-editor .ProseMirror:focus-visible, .mail-editor .ProseMirror *:focus, .mail-editor .ProseMirror-selectednode { outline:none; }
.mail-editor .ProseMirror p.is-editor-empty:first-child::before { content:attr(data-placeholder); color:var(--muted,#aaa); float:left; height:0; pointer-events:none; }
.mail-suggest { position:relative; }
.mail-suggest-list { position:absolute; z-index:30; background:#fff; border:1px solid var(--border,#ddd); border-radius:8px; box-shadow:0 6px 20px rgba(0,0,0,.12); max-height:240px; overflow:auto; min-width:260px; }
.mail-suggest-item { display:flex; align-items:center; gap:.5rem; padding:.4rem .6rem; cursor:pointer; }

/* Éditeur réutilisable de modèles d'e-mail (App\Controller\Email\AbstractModeleEmailController). */
.me-edit { display:flex; flex-direction:column; gap:1rem; }
.me-vars { display:flex; flex-wrap:wrap; gap:.4rem; margin:.3rem 0; }
.me-var { cursor:pointer; font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:.8rem; }

/* ---------- Constructeur d'e-mail v2 — deux volets (templates/email/modele/builder.html.twig,
   assets/controllers/email_builder_controller.js, assets/editor/email-builder.js). Rendu
   INCRÉMENTAL : un bloc = un nœud DOM créé une seule fois par `reconcilier()`, déplacé par
   `insertBefore`, jamais recréé par `innerHTML` (cf. spec 2026-07-26, garantie caret/undo). ---------- */
.ebx-tabs { display: none; }

.ebx-split { display: grid; grid-template-columns: minmax(0,1fr) minmax(0,1fr); gap: 1.2rem; align-items: start; }

/* Volet de composition = carte blanche (même esprit que l'aperçu à droite, .ebx-frame-wrap).
   En-tête STICKY (actions : Ajouter un bloc / Insérer un champ / Réinitialiser — ne bougent pas au
   scroll) + corps défilant. « Enregistrer » vit dans le page-head (haut-droite). */
.ebx-editor {
    display: flex; flex-direction: column; min-width: 0;
    background: var(--card); border: 1px solid var(--line); border-radius: var(--radius-sm);
    box-shadow: 0 1px 2px rgba(31,27,46,.04);
}
.ebx-editor-head {
    display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
    padding: .55rem .7rem; border-bottom: 1px solid var(--line);
    position: sticky; top: 0; z-index: 16; background: var(--card);
    border-radius: var(--radius-sm) var(--radius-sm) 0 0;
}
.ebx-head-reset { margin-left: auto; }
/* Outils de mise en forme du texte, dans le popover de réglages d'un bloc Titre/Texte (à côté de
   l'alignement) : rangée d'icônes ; état actif .is-on = marque/liste appliquée à la sélection. */
.ebx-format { display: flex; flex-wrap: wrap; align-items: center; gap: .15rem; }
.ebx-format .icon-btn.is-on { background: var(--primary-soft); color: var(--primary-dark); }
.ebx-editor-body { display: flex; flex-direction: column; gap: .9rem; padding: .85rem .8rem; min-width: 0; }
/* Boutons du builder (en-tête composition + actions de page) : icône + libellé alignés, largeur auto. */
.eb .page-actions .btn, .eb .ebx-editor-head .btn { display: inline-flex; align-items: center; gap: .4rem; }
.eb .page-actions .btn svg, .eb .ebx-editor-head .btn svg { width: 1.05em; height: 1.05em; }
/* Ancre du menu « Insérer un champ » : wrapper étroit position:relative → le menu (.eb-champ-menu,
   inséré en SIBLING du bouton par _ouvrirMenuChamps) se positionne SOUS le bouton, et non contre la
   barre sticky (qui serait sinon le bloc conteneur). Utilisé par le bouton de la barre ET du sujet. */
.eb-champ-anchor { position: relative; display: inline-flex; }
/* Sélecteur composé `.eb-inserter.ebx-toolbar-inserter` (spécificité 0,2,0) — le générique
   `.eb-inserter` (0,1,0) est déclaré PLUS LOIN dans la feuille (inserteurs « + » entre blocs) ;
   sans ce renfort de spécificité, l'ordre source le ferait gagner et écraserait ce override. */
.eb-inserter.ebx-toolbar-inserter { display: inline-flex; height: auto; }

.ebx-subject-wrap { display: flex; align-items: flex-end; gap: .5rem; }
.ebx-subject { display: flex; flex-direction: column; gap: .3rem; flex: 1; min-width: 0; }
/* Sujet = éditeur Tiptap mono-ligne à pastilles (hôte .ebx-subject-host, aspect input). */
.ebx-subject-host { min-height: 2.5rem; display: flex; align-items: center; cursor: text; overflow-x: auto; white-space: nowrap; }
.ebx-subject-host .ProseMirror { flex: 1; min-width: 0; outline: none; white-space: nowrap; }
.ebx-subject-host .ProseMirror p { margin: 0; }
.ebx-subject-host .tpl-var { vertical-align: baseline; }

.ebx-canvas { display: flex; flex-direction: column; gap: .8rem; min-height: 60px; }
.ebx-empty {
    padding: 1.4rem; text-align: center; border: 1px dashed var(--line); border-radius: var(--radius-sm);
    display: flex; flex-direction: column; gap: .8rem; align-items: center;
}

.ebx-block {
    display: flex; gap: .4rem; background: var(--card); border: 1px solid var(--line);
    border-radius: var(--radius-sm); padding: .6rem .9rem .8rem .35rem;
}
.ebx-block.is-selected { border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-soft); }
.ebx-block.dragging { opacity: .4; }

/* Rail latéral (spec affordances 2026-07-26) : poignée + « + » d'ajout. */
.ebx-rail { flex: 0 0 auto; display: flex; flex-direction: column; align-items: center; gap: .3rem; padding-top: .1rem; }
.ebx-block-body { flex: 1 1 auto; min-width: 0; }

.ebx-block-tools { display: flex; align-items: center; gap: .15rem; margin-bottom: .4rem; }
/* Barre d'actions révélée au survol/focus/sélection (le libellé du bloc reste toujours visible). */
.ebx-block-tools .icon-btn { opacity: 0; transition: opacity .12s ease; }
.ebx-block:hover .ebx-block-tools .icon-btn,
.ebx-block:focus-within .ebx-block-tools .icon-btn,
.ebx-block.is-selected .ebx-block-tools .icon-btn { opacity: 1; }

/* Poignée : TOUJOURS visible (discrète au repos → pleine au survol) = signal « bloc déplaçable ». */
.ebx-handle { cursor: grab; opacity: .5; transition: opacity .12s ease; }
.ebx-handle:active { cursor: grabbing; }
.ebx-block:hover .ebx-rail .ebx-handle,
.ebx-block:focus-within .ebx-rail .ebx-handle,
.ebx-block.is-selected .ebx-rail .ebx-handle { opacity: 1; }

/* « + » d'ajout du rail : révélé au survol du bloc (insère avant ce bloc). */
.ebx-rail .eb-inserter { height: auto; }
.ebx-rail .eb-inserter-btn { opacity: 0; }
.ebx-block:hover .ebx-rail .eb-inserter-btn,
.ebx-block:focus-within .ebx-rail .eb-inserter-btn,
.ebx-rail .eb-inserter.is-open .eb-inserter-btn { opacity: 1; transform: scale(1); }
/* Menu de palette ouvert depuis le rail étroit : aligné au rail (pas centré). */
.ebx-rail .eb-inserter-menu { left: 0; transform: none; }

.ebx-block-label { font-size: .78rem; font-weight: 700; color: var(--muted); flex: 1; }
.ebx-spacer-flex { flex: 1; }

.ebx-block-content { min-width: 0; cursor: text; }

/* Popover de réglages UNIQUE, réutilisé : déplacé (appendChild) dans la carte sélectionnée —
   rendu comme un panneau inline sous le contenu, pas de positionnement absolu (fondation ;
   l'ancrage flottant précis est un raffinement ultérieur). */
.ebx-popover {
    margin-top: .7rem; padding: .8rem .9rem; border: 1px dashed var(--line); border-radius: 8px;
    background: var(--bg); display: flex; flex-direction: column; gap: .7rem;
}
.ebx-popover[hidden] { display: none; }
.ebx-insp-row { display: flex; flex-direction: column; gap: .3rem; font-size: .85rem; }
.ebx-insp-row label { display: flex; flex-direction: column; gap: .3rem; }
.ebx-insp-row select, .ebx-insp-row input[type="text"] {
    font-family: inherit; font-size: .9rem; padding: .4rem .55rem; border: 1px solid var(--line);
    border-radius: 8px; background: #fff; color: var(--ink);
}
.ebx-insp-label { font-weight: 600; color: var(--muted); }
.ebx-insp-note { margin: 0; font-size: .85rem; }

.eb-align { display: flex; gap: .2rem; }
.eb-align .icon-btn.is-on { background: var(--primary-soft); color: var(--primary); opacity: 1; }
.eb-align .btn.is-on { background: var(--primary-soft); border-color: var(--primary); color: var(--primary-dark); }

.eb-swatches { display: flex; gap: .4rem; }
.eb-swatch { width: 24px; height: 24px; border-radius: 50%; border: 2px solid transparent; cursor: pointer; padding: 0; }
.eb-swatch.is-on { border-color: var(--ink); box-shadow: 0 0 0 2px #fff inset; }

/* Hôte d'édition riche (Titre/Texte, monté par email-builder.js) : aperçu statique stylé
   jusqu'au montage de l'éditeur, puis ProseMirror vivant — même nœud DOM dans les deux cas. */
.ebx-richhost .eb-text { border: 1px solid transparent; border-radius: 8px; padding: .3rem .4rem; min-height: 40px; }
.ebx-richhost .eb-text:focus-within { border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-soft); background: #fff; }
.ebx-texte-titre { font-family: Arial, Helvetica, sans-serif; font-weight: 700; color: #1f2937; font-size: 1.25rem; }
.ebx-texte-titre[data-niveau="h3"] { font-size: 1.05rem; }
.ebx-texte-texte { font-family: Arial, Helvetica, sans-serif; color: #1f2937; line-height: 1.5; }

.ebx-btn-wrap { padding: .3rem 0; }
.ebx-btn-fake {
    display: inline-block; padding: 10px 20px; border-radius: 8px; font-weight: 700;
    font-family: Arial, Helvetica, sans-serif; cursor: default; user-select: none;
}
.ebx-hr { border: none; border-top: 1px solid #e5e7eb; margin: 8px 0; }
.ebx-spacer {
    border-radius: 6px;
    background: repeating-linear-gradient(45deg, var(--bg), var(--bg) 6px, var(--line) 6px, var(--line) 7px);
}
.ebx-legacy-preview {
    margin: .4rem 0 0; padding: .6rem .7rem; background: var(--bg); border-radius: 8px; font-size: .78rem;
    max-height: 140px; overflow: auto; white-space: pre-wrap; word-break: break-word;
}

/* Menu palette d'ajout de bloc (template `data-eb-palette`) — cloné dans DEUX contextes :
   l'état canevas vide (`.ebx-empty`) et le menu d'ajout (barre sticky du haut + inserteurs
   « + » entre blocs, `.eb-inserter-menu`). TOUJOURS une LISTE VERTICALE (icône + libellé par
   ligne, jamais une rangée/grille de boutons — cf. Task #2). Plus de palette en fin de
   canevas (`.ebx-end-palette`, retirée — Task #1). */
.eb-palette-menu { display: flex; flex-direction: column; gap: .1rem; min-width: 200px; }
.eb-palette-item {
    display: flex; align-items: center; gap: .5rem; width: 100%; text-align: left;
    padding: .5rem .7rem; border: 0; border-radius: 8px; background: none; cursor: pointer;
    font: inherit; font-size: .88rem; color: var(--ink); white-space: nowrap;
}
.eb-palette-item:hover, .eb-palette-item:focus-visible { background: var(--primary-soft); color: var(--primary-dark); outline: none; }

/* Sélecteur d'élève pour « Envoyer un test » (Task #4, `.page-actions`) — recherche débouncée,
   résultats en liste déroulante ; sélection = pastille retirable (chip) ; sans sélection =
   indice « données d'exemple ». Purement visuel, la logique vit dans
   email_builder_controller.js (eleveSaisir/eleveClear/_eleveChoisir…). */
.ebx-eleve-picker { display: flex; align-items: center; gap: .5rem; }
.ebx-eleve-search-box { position: relative; }
.ebx-eleve-input {
    width: 210px; font-family: inherit; font-size: .85rem; padding: .45rem .7rem;
    border: 1.5px solid var(--line); border-radius: var(--radius-sm); background: #fcfcff; color: var(--ink);
}
.ebx-eleve-input:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-soft); }
.ebx-eleve-results {
    position: absolute; z-index: 30; left: 0; right: 0; top: 100%; margin-top: .3rem;
    background: var(--card); border: 1px solid var(--line); border-radius: 8px;
    box-shadow: 0 8px 24px rgba(0,0,0,.14); max-height: 260px; overflow-y: auto;
}
.ebx-eleve-item {
    display: block; width: 100%; text-align: left; padding: .45rem .7rem; border: 0;
    border-top: 1px solid var(--line); background: none; cursor: pointer;
    font: inherit; font-size: .85rem; color: var(--ink);
}
.ebx-eleve-item:first-child { border-top: 0; }
.ebx-eleve-item:hover, .ebx-eleve-item:focus-visible { background: var(--primary-soft); color: var(--primary-dark); outline: none; }
.ebx-eleve-empty { margin: .5rem .7rem; font-size: .82rem; }
.ebx-eleve-chip {
    display: flex; align-items: center; gap: .3rem; padding: .3rem .3rem .3rem .75rem;
    background: var(--primary-soft); color: var(--primary-dark); border-radius: 999px;
    font-size: .85rem; font-weight: 600;
}
.ebx-eleve-hint { font-size: .8rem; }

.ebx-preview { position: sticky; top: 0; display: flex; flex-direction: column; gap: .6rem; min-width: 0; }
.ebx-preview-bar { display: flex; align-items: center; gap: .8rem; }
.ebx-device-toggle { display: flex; gap: .2rem; }
.ebx-device-toggle .icon-btn[aria-pressed="true"] { background: var(--primary-soft); color: var(--primary); opacity: 1; }
.ebx-status { font-size: .8rem; color: var(--muted); margin-left: auto; }
.ebx-frame-wrap { border: 1px solid var(--line); border-radius: var(--radius-sm); background: #f3f4f6; padding: .8rem; overflow: auto; }
.ebx-frame { width: 100%; height: 560px; border: 0; background: #fff; border-radius: 8px; display: block; margin-inline: auto; transition: width .15s ease; }
.ebx-preview[data-device="mobile"] .ebx-frame { width: 375px; }

@media (max-width: 900px) {
    .ebx-tabs { display: flex; gap: .4rem; margin-bottom: .8rem; }
    .ebx-tab { padding: .4rem .8rem; border-radius: 999px; border: 1px solid var(--line); background: #fff; font-weight: 600; font-size: .85rem; cursor: pointer; }
    .ebx-tab.is-active { background: var(--primary); color: #fff; border-color: var(--primary); }
    .ebx-split { grid-template-columns: 1fr; }
    .ebx-split .ebx-editor, .ebx-split .ebx-preview { display: none; }
    .ebx-split[data-tab="editor"] .ebx-editor { display: flex; }
    .ebx-split[data-tab="preview"] .ebx-preview { display: flex; }
    .ebx-preview { position: static; }
}

/* ---------- Inserteur « + » (bouton rond, ouvre la palette d'ajout) — classes RÉUTILISÉES par le
   « + » du rail de chaque bloc (insère avant ce bloc) ET la barre d'ajout sticky du haut (ajoute en
   fin). Plus d'inserteurs flottants ENTRE les blocs (retirés avec _regenererInserters, spec
   affordances 2026-07-26). Aucun éditeur à l'intérieur. */
.eb-inserter { display: flex; align-items: center; justify-content: center; height: 18px; position: relative; }
.eb-inserter-btn {
    width: 24px; height: 24px; border-radius: 50%; padding: 0;
    border: 1px solid var(--line); background: var(--card); color: var(--muted);
    display: flex; align-items: center; justify-content: center; cursor: pointer;
    opacity: 0; transform: scale(.8);
    transition: opacity .12s ease, transform .12s ease, background .12s ease, color .12s ease, border-color .12s ease;
}
.eb-inserter-btn svg { width: 14px; height: 14px; display: block; }
.eb-inserter:hover .eb-inserter-btn,
.eb-inserter:focus-within .eb-inserter-btn,
.eb-inserter.is-open .eb-inserter-btn { opacity: 1; transform: scale(1); }
.eb-inserter-btn:hover, .eb-inserter-btn:focus-visible { background: var(--primary); border-color: var(--primary); color: #fff; }
.eb-inserter-menu {
    position: absolute; top: 100%; left: 50%; transform: translateX(-50%); margin-top: .3rem; z-index: 20;
    background: var(--card); border: 1px solid var(--line); border-radius: var(--radius-sm);
    box-shadow: 0 8px 24px rgba(0,0,0,.14); padding: .6rem; width: max-content; max-width: min(360px, 85vw);
}

/* Menus « Insérer un champ » (toolbar bloc Titre/Texte + sujet) — même déclencheur
   `.ebx-champ-btn` dans les deux contextes (cf. _ouvrirMenuChamps). */
.ebx-champ-btn { position: relative; }
.eb-champ-menu {
    position: absolute; top: 100%; right: 0; margin-top: .3rem; z-index: 20;
    background: var(--card); border: 1px solid var(--line); border-radius: var(--radius-sm);
    box-shadow: 0 8px 24px rgba(0,0,0,.14);
    padding: .3rem; min-width: 190px; max-width: min(280px, 85vw); max-height: 260px; overflow-y: auto;
    display: flex; flex-direction: column;
}
.eb-champ-item {
    display: block; width: 100%; text-align: left; padding: .4rem .6rem; border-radius: 6px;
    border: none; background: transparent; cursor: pointer; font-size: .85rem; color: var(--ink);
}
.eb-champ-item:hover, .eb-champ-item:focus-visible { background: var(--primary-soft); color: var(--primary-dark); }
.eb-champ-empty { margin: .2rem .4rem; font-size: .82rem; }

/* Région d'annonces a11y (aria-live) — texte visuellement masqué. Jamais posé sur `.ebx-canvas`
   lui-même (cf. gabarit) : ce conteneur mute à chaque frappe Tiptap, ce qui spammerait le
   lecteur d'écran à chaque caractère saisi. */
.ebx-sr-only {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}

/* Zone d'édition riche d'un bloc Titre/Texte (mont Tiptap par email-builder.js) — classes
   RÉUTILISÉES telles quelles par le builder v2 (host .eb-text à l'intérieur de .ebx-richhost). */
.eb-text { border: 1px solid var(--line); border-radius: 8px; padding: .6rem .75rem; background: #fff; min-height: 70px; }
.eb-text:focus-within { border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-soft); }
.eb-text .ProseMirror { outline: none; line-height: 1.5; }
.eb-text .ProseMirror p { margin: .2em 0; }

/* Pastille de variable (Tiptap Mention détournée) : jamais le jeton `{{ … }}` brut à l'écran. */
.tpl-var {
    display: inline-block; background: var(--primary-soft); color: var(--primary-dark);
    border-radius: 999px; padding: .05rem .5rem; font-size: .85em; font-weight: 600;
    white-space: nowrap; user-select: none; cursor: pointer;
}
/* Pastille SÉLECTIONNÉE (clic → NodeSelection) : anneau net → l'utilisateur voit le champ ciblé
   par la mise en forme (classe posée par ProseMirror sur le node view node-sélectionné). */
.tpl-var.ProseMirror-selectednode { outline: 2px solid var(--primary); outline-offset: 1px; background: var(--primary); color: #fff; }

/* Module Dossiers élèves — liste des élèves dans une fiche de classe. */
.eleve-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.eleve-list-row { display: flex; align-items: center; gap: .6rem; padding: .5rem 0; border-bottom: 1px solid var(--line); font-weight: 600; }
.eleve-list-row:last-child { border-bottom: 0; }

/* ============================================================
   Fiche élève — CSS porté 1:1 du legacy gestion-ecole
   ============================================================ */

/* Conteneur principal de la fiche (onglets + panneaux) */
.dossier { display: flex; flex-direction: column; }

/* .tabs, .tab.active et l'alias .tab.is-active sont définis plus haut, en un seul
   endroit : rien à redéfinir ici (une surcharge locale ferait diverger les deux). */

/* ── Onglet Identité : disposition grille 2 colonnes, cards égales (legacy inline #tab-infos) ─ */
.dossier .detail-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: stretch; }
.dossier .detail-grid > .card { height: 100%; }
/* .parents est déjà défini (grid gap:1rem) ; on force auto-fill ici pour compatibilité */
/* 300 et non 250 : en dessous, une adresse ou un e-mail un peu long se casse en trois. */
.dossier .parents { grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); }
@media (max-width: 760px) { .dossier .detail-grid { grid-template-columns: 1fr; } }

/* ── Onglet Santé : cases à cocher imagées (legacy app.css, identiques) ─────────────────── */
/* .sante-pics, .sante-pic, .sante-card, .sante-plus déjà définis plus haut ; on ne redéfinit pas */

/* Soutiens cochables (case + coordonnées dépliables) — porté du legacy inline #tab-infos */
.sante-soutien-list { display: flex; flex-direction: column; gap: .5rem; }
/* Une ligne par soutien, REPLIÉE par défaut : on ne voit que la case, le libellé et
   un aperçu de ce qu'elle contient. Le chevron n'apparaît que si la case est cochée. */
.soutien-item { border: 1px solid var(--border, #e5e7eb); border-radius: .45rem; padding: .45rem .6rem; }
.soutien-item.is-on { border-color: var(--primary); background: var(--primary-soft); }
.soutien-head { display: flex; align-items: center; gap: .6rem; }
.soutien-head > .field-edit.check { flex: none; }
/* Coordonnées de la ligne repliée, en pastilles typées (nom, téléphone, e-mail).
   Téléphone et e-mail sont des liens tel:/mailto: — joindre l'intervenant sans
   déplier. Masquées si la ligne n'est pas active : leur contenu vient du serveur
   et n'aurait plus de sens sur une case qu'on vient de décocher. */
.soutien-chips { flex: 1; min-width: 0; display: flex; flex-wrap: wrap; gap: .3rem; align-items: center; }
.soutien-item:not(.is-on) .soutien-chips { display: none; }
.soutien-chip { display: inline-flex; align-items: center; gap: .3rem; max-width: 100%;
    padding: .14rem .5rem; border-radius: 999px; background: var(--card);
    border: 1px solid var(--line); font-size: .78rem; color: var(--muted);
    text-decoration: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.soutien-chip b { color: var(--ink); font-weight: 650; }
.soutien-chip.is-lien:hover { border-color: var(--primary); color: var(--primary-dark); }
.soutien-chip.is-lien:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.soutien-vide { color: var(--muted); font-size: .8rem; font-style: italic; }

/* Champ de coordonnée : libellé au-dessus, comme les autres formulaires de l'app. */
.coord-f { display: flex; flex-direction: column; gap: .22rem; min-width: 0; }
.coord-f > span { font-size: .72rem; font-weight: 700; color: var(--muted);
    text-transform: uppercase; letter-spacing: .04em; }
.coord-f .input { padding: .38rem .55rem; font-size: .9rem; }
.coord-f-full { margin-bottom: .55rem; }
.soutien-chevron { margin-left: auto; flex: none; display: inline-grid; place-items: center;
    width: 26px; height: 26px; border: 0; border-radius: 7px; background: transparent;
    color: var(--muted); cursor: pointer; font-size: .95rem; line-height: 1;
    transition: transform .15s, background .12s, color .12s; }
.soutien-chevron[hidden] { display: none; }
.soutien-chevron:hover { background: var(--card); color: var(--primary-dark); }
.soutien-chevron:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.soutien-item.is-open .soutien-chevron { transform: rotate(180deg); }
.soutien-coord { margin-top: .5rem; }
.soutien-coord[hidden] { display: none; }
.coord-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .4rem; }
@media (max-width: 520px) { .coord-grid { grid-template-columns: 1fr; } }

/* ── Onglet Autorisations : lignes de personnes — porté du legacy inline #tab-autorisations ─ */
.personnes { display: flex; flex-direction: column; gap: .4rem; margin: .3rem 0 .5rem; }
.personne-row { display: grid; grid-template-columns: 1fr 1fr .9fr 1fr auto; gap: .4rem; align-items: center; }
.personne-row .link-danger { font-size: 1rem; }
@media (max-width: 900px) { .personne-row { grid-template-columns: 1fr 1fr; } }
/* ⚠️ `.field-edit` est un flex COLONNE : son `align-items: stretch` par défaut étire tout
   enfant direct sur la largeur de la carte — un `.btn` s'y retrouve pleine largeur alors
   que `.btn` est en `width:auto`. D'où le `align-self` explicite. Piège à connaître pour
   tout bouton posé directement dans un `.field-edit`. */
.personnes-add { align-self: flex-start; margin-top: .4rem; }
/* « Tous les jours » pilote les cinq cases : on la sépare visuellement du groupe. */
.jours-tous { margin-right: .5rem; padding-right: .8rem; border-right: 1px solid var(--line); }
@media (max-width: 600px) { .jours-tous { margin-right: 0; padding-right: 0; border-right: 0; } }

/* Zone dangereuse (retrait élève) */
details.danger-zone { margin-top: 1.2rem; border: 1px solid #fca5a5; border-radius: var(--radius); background: #fff5f5; }
details.danger-zone > summary { cursor: pointer; padding: .6rem .9rem; font-weight: 600; color: #c0392b; list-style: none; }
details.danger-zone > summary::-webkit-details-marker { display: none; }
details.danger-zone > p { margin: 0 .9rem .5rem; font-size: .88rem; }
details.danger-zone > form { padding: .5rem .9rem .9rem; display: flex; flex-direction: column; gap: .6rem; }
/* Variante destructrice — déclarée ici pour rester avec la zone dangereuse, mais
   elle suit la même formule que les autres (dégradé + ombre teintée). */
.btn-danger { --btn-a: #c0392b; --btn-b: #e5484d; --btn-sh: rgba(192, 57, 43, .30); }

/* Carte parent / responsable : avatar + corps (porté 1:1 du legacy) */
/* .parent, .parent-body, .parent-head, .parent-meta déjà définis plus haut ; identiques */

/* Section « Ajouter un responsable » : bouton simple + panneau révélé au clic
   (plus de <details> — un champ dans <details> est soumis vide sur Safari). */
.resp-add { margin-top: 1rem; }
.resp-add > form { margin-top: .7rem; padding: .6rem .8rem .8rem; display: flex; flex-direction: column;
    gap: .6rem; border: 1px solid var(--line); border-radius: var(--radius-sm); }
.resp-add > form[hidden] { display: none; }   /* sinon display:flex l'emporterait */

/* Suggestions de responsables existants */
.resp-results { display: flex; flex-direction: column; gap: .3rem; margin: .3rem 0; }
.resp-hit { display: block; width: 100%; text-align: left; padding: .4rem .6rem;
    border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--card);
    cursor: pointer; font-size: .9rem; transition: background .12s, border-color .12s; }
.resp-hit:hover { background: var(--primary-soft); border-color: var(--primary); color: var(--primary-dark); }
.mail-suggest-item.is-active, .mail-suggest-item:hover { background:var(--primary-soft,#f3f1ff); }

/* Variantes mineures du wizard d'import (relevées en revue finale menus). */
.flash.flash-warn { background: #fff4e5; color: #8a5300; border-color: #ffd9a8; }
.map-groupe > summary { cursor: pointer; padding: .5rem .2rem; }

/* ── Grille des années scolaires (Établissement) — lignes dépliables (fermetures) ── */
.asg-grid th.num, .asg-grid td.num { text-align: right; white-space: nowrap; }
.asg-grid .asg-row td { transition: background .12s; }
.asg-grid .asg-row:hover td { background: var(--primary-soft, #f3f1ff); }
.asg-grid .asg-row.is-open td { background: var(--primary-soft, #f3f1ff); }
.asg-lib { cursor: pointer; }
.asg-caret { cursor: pointer; }
.asg-caret svg { transform: rotate(-90deg); transition: transform .15s; }
.asg-row.is-open .asg-caret svg { transform: rotate(0); }
.asg-actions { display: flex; align-items: center; justify-content: flex-end; gap: .6rem; white-space: nowrap; }
.asg-actions form { display: inline-flex; margin: 0; }
/* « Définir courante » aligné : le bloc d'icônes (✏️/🗑️) a une largeur constante, quel que soit
   le nombre d'icônes présentes → le bouton courante démarre toujours au même endroit. */
.asg-act-courante { display: inline-flex; justify-content: flex-end; }
.asg-act-icons { display: inline-flex; align-items: center; justify-content: flex-end; gap: .35rem; }
.asg-act-placeholder { display: inline-block; width: 28px; height: 28px; }
.asg-detail > td { padding: 0; background: color-mix(in srgb, var(--primary-soft, #f3f1ff) 55%, #fff); }
.asg-panel { padding: 1rem 1.2rem 1.3rem; border-left: 3px solid var(--primary); }
.asg-dates { display: flex; gap: 1rem; align-items: flex-end; flex-wrap: wrap; margin-bottom: 1rem; padding-bottom: 1rem; border-bottom: 1px solid var(--border, #e6e3f0); }
.asg-dates .field-edit { gap: .3rem; }
.asg-panel-head { display: flex; justify-content: space-between; align-items: center; gap: 1rem; flex-wrap: wrap; margin-bottom: .5rem; }
.asg-panel-head h3 { margin: 0; font-size: .98rem; }
.asg-add > summary { cursor: pointer; color: var(--primary); font-weight: 600; padding: .35rem 0; list-style: none; }
.asg-add > summary::-webkit-details-marker { display: none; }
.asg-add-form { margin-top: .7rem; max-width: 680px; }
.ferm-portee { display: flex; flex-wrap: wrap; gap: .4rem; align-items: center; }
.ferm-scope { margin-top: .4rem; }
.dp-label { margin: 1rem 0 .3rem; font-size: .85rem; font-weight: 600; color: var(--muted); }
.dp-check[hidden] { display: none; }

/* Sélecteur d'implantation en pastilles cliquables (radios). */
.ferm-impl { display: flex; flex-wrap: wrap; gap: .5rem; }
.ferm-impl-opt { display: inline-flex; align-items: center; gap: .4rem; padding: .28rem .6rem .28rem .35rem; border: 1.5px solid var(--line); border-radius: 999px; cursor: pointer; font-size: .9rem; transition: border-color .12s, background .12s; }
.ferm-impl-opt input { position: absolute; opacity: 0; width: 0; height: 0; }
.ferm-impl-opt:hover { border-color: var(--primary); }
.ferm-impl-opt:has(input:checked) { border-color: var(--primary); background: var(--primary-soft); font-weight: 600; }
/* Niveaux / classes en 3 colonnes (niveaux : M1-M3 · P1-P3 · P4-P6). */
.ferm-cols { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: .15rem 1rem; max-width: 560px; margin: .3rem 0 .4rem; }
.ferm-cols-col { display: flex; flex-direction: column; gap: .15rem; }
.ferm-cols-classes { max-width: 640px; }

/* Chip multi-implantations (dégradé + acronymes en tirets), comme le nom des groupes virtuels. */
.pastille-acr { display: inline-flex; align-items: center; padding: .2rem .6rem; border-radius: 999px; color: #fff; font-weight: 700; font-size: .78rem; letter-spacing: .02em; }

dialog.modal.modal-lg { max-width: 720px; }
.asg-add-form fieldset { border: 1px solid var(--border, #e6e3f0); border-radius: 10px; padding: .6rem .9rem; }
.asg-add-form legend { font-size: .82rem; font-weight: 600; color: var(--muted); padding: 0 .4rem; }

/* ── Statut de justification d'absence — vocabulaire UNIQUE ──────────────────
   Cf. App\Presence\Enum\EtatMetier. Classe .etat-{value} ; le libellé vient du PHP.
   Rendu partout où un statut d'absence est affiché (grids, tuiles, fiche élève). */
.etat-justif { display: inline-flex; align-items: center; gap: .28rem; border-radius: 8px; padding: .1rem .5rem; font-size: .8rem; font-weight: 600; white-space: nowrap; }
.etat-justif .etat-ic { width: .95em; height: .95em; flex: none; opacity: .85; }
/* Palette « une couleur par statut » (proposition B validée) : plus aucun doublon rouge. */
.etat-non_fourni          { background: #fef3c7; color: #92400e; } /* ambre     — pièce attendue, délai ouvert */
.etat-a_valider           { background: #eae7ff; color: #5b3fd6; } /* violet    — attend la validation direction */
.etat-valide              { background: #dcfce7; color: #166534; } /* vert      — validé */
.etat-non_justifie        { background: #fee2e2; color: #b91c1c; } /* rouge     — injustifiée (délai dépassé / actée) */
.etat-refuse              { background: #fce7f3; color: #9d174d; } /* framboise — refusé par la direction */
.etat-info_complementaire { background: #e0f2fe; color: #0369a1; } /* bleu ciel — infos complémentaires attendues */
.etat-annule              { background: #f1f5f9; color: #94a3b8; text-decoration: line-through; } /* gris barré — annulé */
.etat-non_requis          { background: #eef1f5; color: #64748b; } /* gris neutre — non requis (M1/M2 dispensés) */

/* ── Présence FWB (axe ② de la refonte 2 axes) — écusson 🛡️ affiché DÈS que l'issue est résolue.
   Binaire : justifiée (vert) ⟺ justificatif validé ; injustifiée (rouge) sinon. Cf. Absence::presenceFwb(). */
.pfwb { display: inline-flex; align-items: center; gap: .28rem; border-radius: 8px; padding: .1rem .5rem; font-size: .8rem; font-weight: 600; white-space: nowrap; }
.pfwb .pfwb-ic { width: .95em; height: .95em; flex: none; }
.pfwb-justifiee   { background: #dcfce7; color: #166534; } /* vert  — présence justifiée (pièce validée) */
.pfwb-injustifiee { background: #fee2e2; color: #b91c1c; } /* rouge — présence injustifiée (défaut FWB) */

/* ── Statut d'e-mail sortant — supervision (Lot 2) ───────────────────────────
   Cf. App\Email\Enum\StatutEmail::couleur(). Classe .email-statut-{token} ; libellé via ::label(). */
.email-statut { display: inline-block; border-radius: 8px; padding: .1rem .5rem; font-size: .8rem; font-weight: 600; white-space: nowrap; }
.email-statut-gris   { background: #f1f5f9; color: #64748b; }
.email-statut-bleu   { background: #dbeafe; color: #1e40af; }
.email-statut-vert   { background: #dcfce7; color: #166534; }
.email-statut-orange { background: #fef3c7; color: #92400e; }
.email-statut-rouge  { background: #fee2e2; color: #991b1b; }

/* Bandeau de compteurs du journal e-mails */
.email-kpis { display: flex; gap: .5rem; flex-wrap: wrap; align-items: center; margin: .2rem 0; }
.email-kpi { display: inline-block; border-radius: 8px; padding: .25rem .6rem; font-size: .85rem; background: #f1f5f9; color: #475569; }

/* ── Fiche élève — édition en place (cadres Identité / Scolarité) ───────────
   Le cadre est un <form> ; le crayon (data-eleve-edit-target="crayon") bascule .is-editing
   qui échange .ee-read (lecture) contre .ee-edit (champ) — cf. contrôleur Stimulus eleve-edit. */
.eleve-edit .ee-edit { display: none; }
.eleve-edit.is-editing .ee-edit { display: block; width: 100%; }
.eleve-edit.is-editing .ee-read { display: none; }
/* En édition, la valeur (dd) prend la place restante — sans quoi l'input resterait
   à sa largeur intrinsèque (dd shrink-to-fit) avec le texte hérité aligné à droite. */
.eleve-edit.is-editing .fields dd { flex: 1; text-align: left; margin-left: 1rem; }
/* Champ vide : la LIGNE ENTIÈRE disparaît en lecture (pas de « — » décoratif) et
   revient en édition pour rester complétable. La classe est posée au rendu Twig puis
   entretenue par le contrôleur eleve-edit (_miroir) quand on vide/remplit un champ.
   L'input reste dans le DOM (juste masqué) : le form continue de tout soumettre. */
.eleve-edit .fields > div.is-vide { display: none; }
.eleve-edit.is-editing .fields > div.is-vide { display: flex; }
.eleve-edit .card-title { display: flex; align-items: center; gap: .5rem; }
.eleve-edit .card-title .icon-btn { margin-left: auto; }
/* Pied d'onglet du dossier élève : « dernière mise à jour … par … », SOUS le bouton
   d'enregistrement et centré comme lui. Discret — c'est de la traçabilité, pas du
   contenu. Rendu UNE SEULE FOIS par onglet (eleve/_derniere_maj.html.twig) : la
   carte Santé avait sa propre ligne, d'où un doublon désormais supprimé. */
.maj-pied { margin: .6rem 0 0; font-size: .82rem; color: var(--muted); text-align: center; }

.ee-statut { font-size: .8rem; font-weight: 600; color: #16a34a; }
.ee-statut.is-err { color: var(--danger, #dc2626); }

/* Fiche élève — frise du parcours scolaire */
.sco-tl-titre { margin: .9rem 0 .3rem; font-size: .8rem; text-transform: uppercase; letter-spacing: .04em; }
.sco-tl { list-style: none; margin: .2rem 0 0 .5rem; padding: 0 0 0 1.1rem; border-left: 2px solid var(--line); }
.sco-tl-item { position: relative; padding: .35rem 0 .55rem; }
.sco-tl-item::before {
    content: ''; position: absolute; left: calc(-1.1rem - 7px); top: .72rem;
    width: 11px; height: 11px; border-radius: 50%;
    background: var(--line); border: 2px solid var(--card, #fff);
}
.sco-tl-item.is-cur::before { background: var(--primary); }
.sco-tl-main { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.sco-tl-tit { display: inline-flex; align-items: center; gap: .3rem; font-size: .88rem; }
.sco-tl-meta { font-size: .8rem; margin-top: .15rem; }
.email-kpi strong { font-weight: 700; }

/* ===================== Modules du dossier élève — système commun (Discipline + Pédagogie) ===================== */
/* Les classes `disc-*` ci-dessous sont le système COMMUN aux modules du dossier élève qui
   partagent le même habillage (Discipline ⚖️, Pédagogie 📚 à venir) : cartes à ombre douce,
   tuiles KPI à icône teintée, badges fins, zones de texte sur fond doux. PAS de renommage —
   « disc- » reste le préfixe historique/commun, les modules le RÉUTILISENT. Les classes propres
   à la Pédagogie (accordéon d'aménagements, grille de zones, pastille compteur, carte d'année
   passée…) sont préfixées `pedago-*` et vivent en fin de bloc. Valeurs portées TELLES QUELLES de
   la maquette validée (`docs/charte/maquettes/2026-08-08-onglet-pedagogie.html`,
   § Engagement de fidélité visuelle) en harmonisant avec les tokens du projet (--line, --muted,
   --primary, --radius-sm) quand ils rendent la même chose à l'œil — jamais au prix du rendu. */

/* Carte de module : rayon 14px + ombre douce mauve (ni --radius 18px ni --radius-sm 12px ne
   correspond → valeur maquette figée en dur), titre en violet foncé dédié (#40378f, sans token
   existant assez proche). Titre en flex pour pousser le bouton d'action à droite (margin-left:auto
   ne résout pas hors flex — cf. revue Task 6). */
.disc-card { border-radius: 14px; border-color: var(--line); box-shadow: 0 1px 3px rgba(80, 70, 150, .07); }
/* Espacement des cadres d'un onglet du dossier (Pédagogie, Discipline). `.card` n'a AUCUNE
   marge : les cartes se touchaient. On ne peut pas se contenter de `+` (sélecteur de
   frère adjacent) — un <script> sépare Entretiens de Documents et casserait l'adjacence.
   La marge du haut se recouvre avec le `margin-bottom` des KPIs (fusion des marges), donc
   pas de double espace sous eux. Portée aux enfants DIRECTS de l'onglet : les cartes
   posées dans une grille (fiche incident) gardent le `gap` de leur grille. */
.tab-panel > .disc-card { margin-top: 1.1rem; }
.disc-card .card-title { display: flex; align-items: center; gap: .5rem; color: #40378f; font-size: .95rem; letter-spacing: .01em; }
.disc-head-btn { margin-left: auto; }

/* Tuiles KPI : icône dans un carré teinté (défaut violet = var(--primary-soft), variantes
   .is-bad rouge / .is-warn orange selon la gravité du signal — 3ᵉ variante « violet » = défaut,
   pas de classe à poser). */
.disc-kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 1rem; margin-bottom: 1.1rem; }
.disc-kpi { display: flex; align-items: center; gap: 12px; border: 1px solid var(--line); border-radius: var(--radius-sm, 12px); padding: 10px 14px; background: var(--card); box-shadow: 0 1px 2px rgba(80, 70, 150, .06); }
.disc-kpi-ico { display: flex; align-items: center; justify-content: center; width: 34px; height: 34px; flex: none; border-radius: 10px; font-size: 16px; background: var(--primary-soft); }
.disc-kpi-ico.is-bad { background: #ffe9e9; }
.disc-kpi-ico.is-warn { background: #fff2e3; }
.disc-kpi-n { font-size: 19px; font-weight: 800; line-height: 1.1; font-family: "Baloo 2", sans-serif; }
.disc-kpi-l { color: var(--muted); font-size: 10.5px; letter-spacing: .02em; text-transform: uppercase; }

/* Badge fin (catégorie / gravité / lieu d'un incident, dispositif pédagogique…) : rayon 7px,
   10.5px/700 — remplace l'ancienne pill toute ronde (999px), fidèle à la maquette. */
.disc-b { display: inline-flex; align-items: center; padding: 2px 8px; border-radius: 7px; font-size: 10.5px; font-weight: 700; letter-spacing: .01em; background: var(--bg); color: var(--muted); }
.disc-b.disc-g1 { background: #fff6d6; color: #93780a; }
.disc-b.disc-g2 { background: #ffedd8; color: #c1560a; }
.disc-b.disc-g3 { background: #ffe3e3; color: #c92a2a; }
/* Badge de dispositif (Pédagogie) : ✓ actif (vert) / inactif barré-atténué (gris). */
.disc-b.is-on { background: #e7f5ec; color: #1f7a3d; }
.disc-b.is-off { background: #f4f2fa; color: #9b97b3; text-decoration: line-through; opacity: .7; }
/* Ambre : mise en avant douce — « année en cours », « Maintien P2 » (maquette .b.warn). */
.disc-b.is-warn { background: #fff3bf; color: #997404; }

/* Zone de texte (difficultés, points forts, objectifs, remarques…) : fond doux + libellé
   uppercase gris — classe commune, consommée par la grille .pedago-zones de la Pédagogie. */
.disc-zone { border: 1px solid var(--line); border-radius: 10px; padding: 8px 10px; background: #fbfaff; white-space: pre-line; }
.disc-zone > b { display: block; margin-bottom: 3px; font-size: 10.5px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--muted); white-space: normal; }

/* Pastille « statut » d'un incident (point coloré + libellé). */
.disc-dot { display: inline-flex; align-items: center; gap: .35rem; font-size: .82rem; font-weight: 700; }
.disc-dot::before { content: ''; width: 9px; height: 9px; border-radius: 50%; background: currentColor; flex: none; }
.disc-dot.disc-st-ouvert { color: #f08c00; }
.disc-dot.disc-st-suivi { color: #1971c2; }
.disc-dot.disc-st-clos { color: #2f9e44; }

/* Menu DU DOSSIER : le nom de l'élève coiffe la table des matières, pour savoir de qui
   est le dossier même après avoir défilé (proposition 2 : le nom seul, sans carte). */
.dossier-menu-nom { padding: .1rem .2rem .55rem; font-family: 'Baloo 2', sans-serif;
    font-weight: 800; font-size: 1rem; line-height: 1.15; color: var(--ink); }
/* Cibles des entrées « Identité / Scolarité / … » : elles vivent sur la même page, on y va
   par ancre. Ancres DÉDIÉES et non `id` posé sur les cartes : les formulaires portent déjà
   `identite-form`/`scolarite-form`, référencés par les tests — on ne les renomme pas.
   ⚠️ L'ancre est PREMIER ENFANT DE LA CARTE, jamais posée avant elle : `.detail-grid` est
   une grille, et un élément placé entre deux cartes y occuperait une CELLULE — ce qui
   cassait la mise côte à côte d'Identité et Scolarité.
   `scroll-margin-top` évite que la topbar collante recouvre le titre visé. */
.sec-ancre { display: block; height: 0; scroll-margin-top: 1rem; }

/* Cadres « 🛡️ Absences » et « ⏰ Retards » (lecture seule, données de Présences).
   La ligne de chiffres sert de résumé au-dessus de la liste ; les deux cartes sont
   posées côte à côte par `.disc-detail-grid`, réutilisé de la fiche incident. */
.disc-pres-chiffres { margin: -.2rem 0 .6rem; font-size: .88rem; color: var(--muted); }
.disc-pres-chiffres strong { color: var(--ink); }
/* Barre ‹ › + œil dans le TITRE de la carte (motif des cartes de la Vue d'ensemble).
   `.pg-nav` est déclarée plus bas avec `margin-top:.7rem` et `justify-content:flex-end`,
   pensés pour un pied de grid : on les annule ici, la barre est en ligne dans l'en-tête. */
.disc-card-nav { display: inline-flex; align-items: center; gap: .5rem; }
.disc-card-nav .pg-nav { margin: 0; }

/* Grids Incidents / Devoirs — single-line, largeurs fixes. */
.disc-table { table-layout: fixed; }
.disc-table td, .disc-table th { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.disc-num { font-size: .76rem; color: var(--muted); font-weight: 600; }

/* Barre de pagination des grids (vues école Incidents/Devoirs, 50 lignes/page) — mêmes
   classes que le bloc <style> local de presence/vue_ensemble.html.twig, mutualisées ici
   pour ne pas dupliquer un <style> par template. */
.pg-nav { display: flex; align-items: center; justify-content: flex-end; gap: .5rem; margin-top: .7rem; }
/* ⚠️ `display:flex` l'emporte sur l'attribut `hidden` : sans cette règle, le contrôleur
   `paginate` a beau poser `navTarget.hidden = true` quand il n'y a qu'une page, la barre
   reste affichée — un « 1 / 1 » avec deux flèches grisées. Vaut pour TOUTES les cartes
   paginées (Vue d'ensemble Présences comprise). Même piège que `.cps-reply[hidden]` : sur
   ce projet, un élément masqué par `hidden` ET stylé en `display:flex`/`grid` exige sa
   règle explicite. */
.pg-nav[hidden] { display: none; }
.pg-nav .pg-info { color: var(--muted); font-size: .85rem; min-width: 3.2rem; text-align: center; }
.pg-btn { border: 1px solid var(--line, #e2e8f0); background: #fff; border-radius: 8px; padding: .28rem .6rem; cursor: pointer; font-size: .9rem; line-height: 1; }
.pg-btn:disabled { opacity: .4; cursor: default; }
.pg-btn:not(:disabled):hover { border-color: var(--primary); color: var(--primary); }
.pg-hide { display: none !important; }
/* Sélecteur « lignes par page » de la barre de pagination (cible `taille` du contrôleur). */
.pg-taille { display: inline-flex; align-items: center; gap: .35rem; color: var(--muted); font-size: .85rem; margin-right: .4rem; }
.pg-taille select { border: 1px solid var(--line, #e2e8f0); background: #fff; border-radius: 8px; padding: .24rem .4rem; font-size: .85rem; color: var(--ink); cursor: pointer; }
.pg-taille select:hover { border-color: var(--primary); }

/* Drawer latéral « Nouvel incident » (Task 7) : overlay + panneau glissant depuis la droite. */
/* ---------- Tiroir d'encodage (panneau latéral droit) ----------
   ⚠️ FORME DE RÉFÉRENCE POUR TOUT ENCODAGE (décision Philippe, 2026-09-08 : « il FAUT que ce soit
   toujours comme cela partout ») : on n'ouvre plus une PAGE de formulaire, on ouvre un tiroir à
   droite pendant que la liste reste à l'écran. Le contexte ne disparaît pas, et revenir ne coûte
   pas un aller-retour serveur.

   Deux familles de noms, LES MÊMES RÈGLES : `.drawer-*` est le nom générique à employer désormais ;
   `.disc-drawer-*` est le nom d'origine (onglet ⚖️ Discipline), gardé pour ne pas réécrire un
   écran qui marche. Ne pas dupliquer ces règles ailleurs — ajouter son nom ici. */
.disc-drawer-overlay, .drawer-overlay { position: fixed; inset: 0; background: rgba(31, 36, 64, .45); opacity: 0; pointer-events: none; transition: opacity .15s ease; z-index: 60; }
.disc-drawer-overlay.is-open, .drawer-overlay.is-open { opacity: 1; pointer-events: auto; }
.disc-drawer-panel, .drawer-panel { position: fixed; top: 0; right: 0; bottom: 0; width: min(680px, 92vw); background: var(--card); box-shadow: -8px 0 24px rgba(0, 0, 0, .12); transform: translateX(100%); transition: transform .2s ease; z-index: 61; display: flex; flex-direction: column; }
.disc-drawer-panel.is-open, .drawer-panel.is-open { transform: translateX(0); }
.disc-drawer-panel form, .drawer-panel form { display: flex; flex-direction: column; height: 100%; min-height: 0; }
.disc-drawer-head, .drawer-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 1.1rem 1.3rem; border-bottom: 1px solid var(--line); flex: none; }
.disc-drawer-head h2, .drawer-head h2 { margin: 0; font-size: 1.15rem; font-family: "Baloo 2", sans-serif; }
.disc-drawer-body, .drawer-body { padding: 1.2rem 1.3rem; overflow-y: auto; flex: 1; min-height: 0; display: flex; flex-direction: column; gap: .9rem; }
.disc-drawer-foot, .drawer-foot { padding: 1rem 1.3rem; border-top: 1px solid var(--line); flex: none; display: flex; gap: .6rem; align-items: center; }
/* ⚠️ `.btn` est en `width:100%` dans ce projet : sans cela, deux boutons de pied de tiroir
   s'empilent sur deux lignes pleine largeur au lieu de se ranger côte à côte. */
.drawer-foot .btn { width: auto; }

/* ---------- Grid à lignes dépliantes ----------
   ⚠️ FORME DE RÉFÉRENCE POUR TOUTE LISTE (même décision) : une ligne par objet, et son détail
   DESCEND dans le grid au clic — pas une page, pas une modale. Motif né des certificats couvrant
   plusieurs jours (« Liste des absences »), repris tel quel par les absences récurrentes.
   Piloté par `toggle-view#deplier` : la ligne principale porte `.epi-main` + `data-epi="<clé>"`,
   les sous-lignes `.epi-sub` + `data-epi-sub="<clé>"`. Ces règles étaient dans un `<style>` de
   `presence/_toutes_absences.html.twig` — invisibles depuis tout autre écran. */
.epi-clic { cursor: pointer; }
.epi-clic:hover td { background: #eef2ff; }
.epi-chev { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; border-radius: 7px; background: var(--primary-soft, #eef2ff); color: var(--primary, #6d5efc); font-weight: 800; }
.epi-chev::before { content: '▸'; display: inline-block; transition: transform .15s; }
.epi-main.is-open .epi-chev { background: var(--primary, #6d5efc); color: #fff; }
.epi-main.is-open .epi-chev::before { transform: rotate(90deg); }
.epi-sub td { background: #f4f6fb; font-size: .88rem; }
.epi-sub-jour { color: #475569; font-weight: 600; white-space: nowrap; }
/* Épisode aux statuts hétérogènes : icône d'alerte sur la ligne principale (déplié par défaut). */
.epi-mixte { cursor: help; margin-right: .15rem; }
/* Colonne N° : chevron « déplier » quand les justificatifs diffèrent selon les jours. */
.epi-numchev { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; border-radius: 6px; background: var(--primary-soft, #eef2ff); color: var(--primary, #6d5efc); font-weight: 800; line-height: 1; transition: transform .15s; }
.epi-main.is-open .epi-numchev { transform: rotate(180deg); }

/* Première colonne des absences récurrentes : la règle tient en une cellule — période, ce qui la
   justifie, quand elle a été encodée. Trois lignes, deux tailles : la période porte, le reste
   accompagne. Même intention que `.disc-num` sous la date d'un incident. */
.rec-periode { display: flex; align-items: center; gap: .5rem; white-space: nowrap; }
/* ⚠️ Les deux lignes d'appoint sont TRONQUÉES, jamais renvoyées à la ligne : un nom de fichier un
   peu long faisait passer la cellule de trois à cinq lignes et désalignait tout le tableau. Ce qui
   ne tient pas est dans l'infobulle. */
.rec-meta { display: block; font-size: .82rem; color: #475569; margin-top: .15rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 330px; }
/* Statut d'une récurrence : UN voyant, vert si elle tourne, rouge sinon (Philippe, 2026-09-08).
   Le libellé exact reste en infobulle — la pastille l'écrivait en dix fois plus large, pour une
   information qui se lit d'un coup d'œil. */
.rec-voyant { display: inline-block; width: 12px; height: 12px; border-radius: 999px; cursor: help; }
.rec-voyant.is-ok { background: #16a34a; box-shadow: 0 0 0 3px rgba(22, 163, 74, .15); }
.rec-voyant.is-ko { background: #dc2626; box-shadow: 0 0 0 3px rgba(220, 38, 38, .15); }
/* Règle héritée sans justificatif : le signal se pose à côté de la date d'encodage, sans coûter
   une colonne — le justificatif est obligatoire depuis le 2026-09-08, ces règles sont antérieures. */
.rec-alerte { cursor: help; font-size: .95rem; }
/* ⚠️ `max-width` sur `.rec-meta`, PAS sur la cellule : en `table-layout: auto`, une largeur posée
   sur un `<td>` n'est qu'un vœu — la colonne se dimensionne sur le contenu le plus large, et un nom
   de fichier un peu long faisait grossir la colonne à 406 px (mesuré). Borner le CONTENU est ce qui
   déclenche vraiment l'ellipse. */
.rec-col1 { min-width: 280px; }
.rec-col-eleve { white-space: nowrap; }
/* Emplacement du chevron réservé sur les lignes sans occurrence — l'alignement prime. */
.epi-chev.is-vide { background: none; }
.epi-chev.is-vide::before { content: ''; }
/* Aperçu des dates à venir, dans le tiroir : une liste, pas un tableau — ce ne sont pas des faits. */
.rec-apercu { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: .4rem .9rem; font-size: .88rem; }
.rec-apercu li { display: flex; align-items: center; gap: .35rem; }

/* Gravité en 3 segments cliquables (radios masqués, sélection via :has). */
.disc-grav { display: flex; gap: .5rem; }
.disc-grav-opt { position: relative; flex: 1; display: flex; align-items: center; justify-content: center; padding: .5rem .6rem; border: 1.5px solid var(--line); border-radius: var(--radius-sm, 10px); cursor: pointer; font-weight: 700; font-size: .88rem; text-align: center; }
.disc-grav-opt input { position: absolute; opacity: 0; pointer-events: none; }
.disc-grav-mineur:has(input:checked) { border-color: #93780a; background: #fff6d6; color: #93780a; }
.disc-grav-majeur:has(input:checked) { border-color: #c1560a; background: #ffedd8; color: #c1560a; }
.disc-grav-grave:has(input:checked) { border-color: #c92a2a; background: #ffe3e3; color: #c92a2a; }

/* Recherche d'élèves (drawer) : suggestions cliquables + pastilles retirables. */
.disc-eleve-results { display: flex; flex-direction: column; gap: .3rem; margin-top: .4rem; }
.disc-eleve-hit { text-align: left; border: 1px solid var(--line); background: var(--bg); border-radius: 8px; padding: .4rem .6rem; font: inherit; cursor: pointer; }
.disc-eleve-hit:hover { border-color: var(--primary); color: var(--primary); }
.disc-chips { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: .5rem; }
.disc-chip { display: inline-flex; align-items: center; gap: .4rem; border: 1.5px solid var(--line); background: var(--primary-soft); color: var(--primary); border-radius: 999px; padding: .3rem .5rem .3rem .8rem; font-weight: 700; font-size: .85rem; }
.disc-chip button { border: none; background: transparent; color: inherit; cursor: pointer; font-size: 1rem; line-height: 1; padding: 0 .2rem; }

/* Fiche incident (Task 8) : en-tête badges, corps 2 colonnes, chronologie des suites, barre de statut. */
.disc-detail-badges { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; margin-top: .5rem; }
.disc-detail-grid { display: grid; grid-template-columns: 1.4fr 1fr; gap: 1rem; margin-bottom: 1rem; align-items: start; }
/* ⚠️ `white-space: normal` et PAS `pre-line` : depuis le passage à l'éditeur riche, ces
   blocs contiennent du HTML (les sauts de ligne y sont des balises). En `pre-line`, ce
   sont les retours d'INDENTATION DU TEMPLATE qui deviendraient visibles — un grand vide
   sous le titre. Même piège que `.disc-zone` en pédagogie. */
.disc-detail-desc { white-space: normal; }
.disc-eleves-impliques { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .6rem; }
.disc-eleves-impliques li { display: flex; align-items: center; gap: .5rem; }

.disc-timeline { list-style: none; margin: 0; padding: 0; border-left: 2px solid var(--line); }
.disc-timeline-item { position: relative; padding: 0 0 1rem 1.1rem; }
.disc-timeline-item::before { content: ''; position: absolute; left: -6px; top: .3rem; width: 10px; height: 10px; border-radius: 50%; background: var(--primary); }
.disc-timeline-date { font-size: .78rem; font-weight: 700; color: var(--muted); }
.disc-timeline-body p { margin: .3rem 0; }
.disc-timeline-auteur { font-size: .8rem; }

.disc-statusbar-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .8rem; }
.disc-statusbar-actions { display: flex; flex-wrap: wrap; gap: .6rem; }

/* ---------- Pédagogie (`pedago-*`) : classes propres au module, posées sur le système commun
   ci-dessus (.disc-card/.disc-kpi/.disc-b/.disc-zone/.disc-timeline). ---------- */

/* Grille des 4 zones de texte de la fiche annuelle : 2 colonnes, 1 seule sous 900px. */
.pedago-zones { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }

/* Accordéon « Aménagements raisonnables » : fond doux, résumé en gras violet foncé (même teinte
   que .disc-card .card-title), catégories en ligne avec leur pastille compteur .pedago-n. */
.pedago-amg { border: 1px solid var(--line); border-radius: 10px; padding: 8px 10px; margin: 10px 0; background: #fbfaff; }
.pedago-amg summary { cursor: pointer; font-weight: 700; font-size: .8rem; color: #40378f; }
.pedago-cat { display: inline-flex; align-items: center; gap: 4px; margin: 4px 8px 0 0; font-size: .72rem; color: var(--muted); }

/* Pastille compteur ronde (nombre d'items cochés dans une catégorie d'aménagements). */
.pedago-n { display: inline-block; background: var(--primary); color: #fff; border-radius: 999px; padding: 0 6px; font-size: 10px; font-weight: 700; line-height: 1.5; }

/* Panneau d'une ANNÉE scolaire : l'en-tête se lit sans ouvrir (année, état, dispositifs,
   titulaire). L'année courante est ouverte ; les révolues sont repliées et en lecture
   seule — cf. FichePedagogique::estModifiable(). */
.pedago-annee > summary { cursor: pointer; list-style: none; display: flex; flex-wrap: wrap;
    align-items: center; gap: .45rem; padding: .1rem 0; }
.pedago-annee > summary::-webkit-details-marker { display: none; }
.pedago-annee > summary::before { content: '▸'; color: var(--muted); font-size: .8rem;
    transition: transform .15s; flex: none; }
.pedago-annee[open] > summary::before { transform: rotate(90deg); }
.pedago-annee-lib { font-weight: 800; letter-spacing: -.01em; }
.pedago-annee-etat { font-size: .66rem; font-weight: 700; text-transform: uppercase;
    letter-spacing: .07em; padding: .05rem .45rem; border-radius: 999px; white-space: nowrap; }
.pedago-annee-etat.is-cur { background: linear-gradient(135deg, var(--primary), var(--primary-lift)); color: #fff; }
.pedago-annee-etat.is-lock { background: #64748b; color: #fff; }
.pedago-annee-etat.is-futur { background: #94a3b8; color: #fff; }
.pedago-annee-etat.is-open { background: #b45309; color: #fff; }
.pedago-annee-tit { margin-left: auto; font-size: .8rem; color: var(--muted); }
/* Une année clôturée s'affiche en retrait : c'est une archive, pas la fiche vivante. */
.pedago-annee.is-cloturee { background: #fbfbfd; }
.pedago-verrou { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem;
    margin: .6rem 0 .2rem; padding: .5rem .7rem; border-radius: 9px;
    background: var(--bg); border: 1px dashed var(--line); color: #475569; font-size: .82rem; }
.pedago-verrou.is-open { background: #fffbeb; border-color: #fde68a; color: #78350f; }

/* ── Onglet Pédagogie : respiration entre les cadres ──────────────────────────
   `.card` n'a AUCUNE marge par défaut : sans ces règles, les panneaux d'année,
   la carte Entretiens et la carte Documents se touchent. */
.pedago-annee { margin-bottom: 1rem; }
.pedago-barre + .pedago-annee { margin-top: .2rem; }
.pedago-annee + .card,
.pedago-annee ~ .card + .card { margin-top: 1.6rem; }

/* ── Disposition des données de suivi, reprise de l'app de Pauline ───────────
   Ligne 1 = les dispositifs ; ligne 2 = maintien et avancement, chacun dans son
   bloc bordé. Même structure en lecture et dans le drawer d'édition. */
.pedago-l1 { display: flex; flex-wrap: wrap; gap: .4rem; margin-bottom: .6rem; }
.maintien-avancement { display: flex; flex-wrap: wrap; gap: 1rem; margin-bottom: .9rem; }
.disp-bloc { flex: 1 1 260px; min-width: 0; border: 1px solid var(--line); border-radius: 10px;
    padding: .6rem .8rem; }
.disp-bloc.is-on { border-color: var(--primary); background: var(--primary-soft); }
.disp-bloc-lib { font-weight: 700; font-size: .88rem; }
.disp-bloc-detail { display: block; margin-top: .15rem; font-size: .8rem; color: var(--muted); }
.disp-menus { display: flex; flex-wrap: wrap; gap: .6rem; align-items: flex-end; margin-top: .5rem; }
.disp-menus[hidden] { display: none; }
.disp-menus .field-edit { flex: 1 1 130px; min-width: 0; }

/* Aménagements : une catégorie repliable, compteur en pastille à droite (motif PL). */
.amenagements { display: flex; flex-direction: column; gap: .35rem; }
.amen-cat { border: 1px solid var(--line); border-radius: .45rem; overflow: hidden; }
.amen-cat > summary { cursor: pointer; padding: .4rem .6rem; font-weight: 600; font-size: .85rem;
    list-style: none; display: flex; align-items: center; gap: .45rem; }
.amen-cat > summary::-webkit-details-marker { display: none; }
.amen-cat > summary::before { content: '▸'; font-size: .75rem; color: var(--muted); transition: transform .15s; }
.amen-cat[open] > summary::before { transform: rotate(90deg); }
.amen-cat[open] > summary { background: var(--primary-soft); }
.amen-cat .pill { margin-left: auto; font-size: .72rem; font-weight: 700; background: var(--primary);
    color: #fff; border-radius: 1rem; padding: .05rem .45rem; }
.amen-items { display: flex; flex-direction: column; gap: .3rem; padding: .4rem .7rem .6rem 1.5rem; }
.amen-check { display: flex; align-items: flex-start; gap: .5rem; font-weight: 400; font-size: .85rem;
    line-height: 1.25; cursor: pointer; }
.amen-check input { margin: .15rem 0 0; flex: none; }
.amen-lu { font-size: .84rem; color: var(--ink); }
.amen-block[hidden] { display: none; }
.pedago-amg-lecture { margin-bottom: .9rem; }

/* Zones de texte du suivi : WYSIWYG dans le drawer, HTML rendu en lecture.
   Plus HAUTES que les anciens textarea (rows=3) — on y écrit de vrais paragraphes. */
.pedago-zone-edit { margin-bottom: .2rem; }
/* Barre d'outils FLOTTANTE : elle suit le défilement du panneau au lieu de filer
   vers le haut. `.mail-format-bar` est déjà en `position:sticky`, mais dans le
   composer mail elle se cale sur `.mail-editor`, qui est lui-même la zone de
   défilement. Ici c'est le DRAWER qui défile : on retire donc le défilement de
   l'éditeur pour que le sticky se résolve contre `.disc-drawer-body`. */
.pedago-editeur { margin: .25rem 0 0; overflow: visible; }
.pedago-editeur .mail-format-bar { z-index: 5; box-shadow: 0 2px 6px rgba(20, 26, 46, .07); }
/* Outils REPLIABLES : la barre est masquée, une petite pastille « Aa » la déplie.
   Sur une page qui empile 4 zones, une barre permanente au-dessus de chacune
   saturait l'écran. Le composer mail n'est pas concerné (opt-in par data-outils). */
.mail-fb-toggle { position: absolute; top: .3rem; right: .4rem; z-index: 6;
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 28px; height: 24px; padding: 0 .4rem;
    border: 1px solid var(--line); border-radius: 7px; background: var(--card);
    color: var(--muted); font: 700 .78rem/1 var(--sans, inherit); cursor: pointer;
    opacity: .55; transition: opacity .12s, color .12s, border-color .12s; }
.pedago-zone-edit { position: relative; }
.pedago-zone-edit:hover .mail-fb-toggle, .mail-fb-toggle:focus-visible { opacity: 1; }
.mail-fb-toggle:hover { color: var(--primary-dark); border-color: var(--primary); opacity: 1; }
.mail-fb-toggle.is-on { opacity: 1; color: #fff; background: var(--primary); border-color: var(--primary); }
.mail-format-bar[hidden] { display: none; }
.pedago-editeur .ProseMirror { min-height: 150px; font-size: .92rem; }
/* Compte-rendu d'entretien : un vrai texte, pas une note — zone nettement plus haute. */
.pedago-zone-haute .pedago-editeur .ProseMirror { min-height: 320px; }
/* ⚠️ `.disc-zone` est en `white-space: pre-line`, hérité du temps où ces champs
   étaient du texte brut. Le contenu étant devenu du HTML, les retours à la ligne
   d'INDENTATION du gabarit se voyaient — d'où le grand blanc entre le titre et le
   texte. On repasse en `normal` : les sauts viennent désormais du balisage. */
.pedago-zone { white-space: normal; padding: 10px 12px; }
/* Titre mis en évidence, même traitement que « Aménagements raisonnables »
   (.pedago-cat-titre) : violet foncé et lisible, au lieu du gris minuscule en
   capitales. Le picto est DÉCORATIF — aria-hidden côté gabarit.
   ⚠️ Sélecteur porté à `.disc-zone > b…` : `.disc-zone > b` (0,1,1) l'emportait sur
   la simple classe (0,1,0) et le titre restait gris. */
.disc-zone > b.pedago-zone-titre { display: flex; align-items: center; gap: .35rem;
    margin: 0 0 .55rem; font-size: .84rem; font-weight: 700; letter-spacing: 0;
    text-transform: none; color: #40378f; }
.disc-zone > b.pedago-zone-titre span { font-size: .95em; opacity: .9; }
.pedago-zone-lu { font-size: .88rem; line-height: 1.5; }
/* Les marges du premier/dernier bloc doubleraient l'espace du cadre. */
.pedago-zone-lu > :first-child { margin-top: 0; }
.pedago-zone-lu > :last-child { margin-bottom: 0; }
.pedago-zone-lu p { margin: .2em 0; }
.pedago-zone-lu ul, .pedago-zone-lu ol { margin: .2em 0; padding-left: 1.2rem; }
.pedago-zone-lu blockquote { margin: .3em 0; padding-left: .6rem; border-left: 3px solid var(--line); color: var(--muted); }

/* ─── Notes signées des rubriques (difficultés, points forts, objectifs, remarques) ───
   Un dossier s'écrit à plusieurs mains. Le fil conducteur du bloc est LA COULEUR DE
   L'AUTEUR : `--note-teinte`, posée par le gabarit, est la même que celle de sa pastille
   d'initiales (jeton `avatar_color`, déterministe). Le filet gauche de chaque note la
   reprend — on lit d'un coup d'œil vertical combien de mains ont écrit, et lesquelles,
   sans lire un seul nom. Aucun composant inventé : une variable et une bordure. */
.pedago-rubrique { display: flex; flex-direction: column; }
.pedago-rubrique-compte {
    margin-left: auto; font-size: .72rem; font-weight: 700; color: var(--muted);
    flex: none;
    background: var(--line); border-radius: 999px; padding: 0 .45rem; line-height: 1.5;
}
.pedago-rubrique-vide { margin: 0; font-size: .84rem; color: var(--muted); font-style: italic; }

.pedago-notes { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .5rem; }
.pedago-note {
    border-left: 3px solid var(--note-teinte, var(--line));
    padding: .1rem 0 .1rem .6rem;
}
/* Sa propre note : un fond à peine teinté de SA couleur. Pas de cadre supplémentaire —
   ce qui distingue doit rester plus discret que ce qui informe. */
.pedago-note.is-mienne { background: color-mix(in srgb, var(--note-teinte) 7%, transparent); border-radius: 0 8px 8px 0; padding-right: .5rem; }

.pedago-note-sign { display: flex; align-items: center; gap: .4rem; margin-bottom: .2rem; }
.pedago-note-qui { font-size: .8rem; font-weight: 700; color: var(--ink); }
.pedago-note-quand { font-size: .74rem; color: var(--muted); }
.pedago-note-corr { font-style: italic; }
/* Les actions n'apparaissent qu'au survol de LA note : quatre rubriques peuplées
   mettraient sinon une rangée d'icônes partout, et la page se lirait comme une barre
   d'outils. Toujours visibles au clavier (focus-within), sans quoi elles seraient
   inatteignables sans souris. */
.pedago-note-actions { margin-left: auto; display: flex; gap: .1rem; opacity: 0; transition: opacity .12s; }
.pedago-note:hover .pedago-note-actions,
.pedago-note:focus-within .pedago-note-actions { opacity: 1; }
.pedago-note-texte { font-size: .88rem; line-height: 1.5; }
.pedago-note-texte > :first-child { margin-top: 0; }
.pedago-note-texte > :last-child { margin-bottom: 0; }
.pedago-note-texte p { margin: .2em 0; }
.pedago-note-texte ul, .pedago-note-texte ol { margin: .2em 0; padding-left: 1.2rem; }

/* Le « + » d'une rubrique : discret au repos, il ne doit pas concurrencer le titre. */
.pedago-rubrique-ajout { margin-left: auto; opacity: .45; transition: opacity .12s; }
.pedago-rubrique:hover .pedago-rubrique-ajout,
.pedago-rubrique-ajout:focus-visible { opacity: 1; }
.pedago-rubrique-compte + .pedago-rubrique-ajout { margin-left: .35rem; }

/* « ma note du 02/09 » / « nouvelle note » : dit à qui appartient le cadre qu'on édite,
   sans quoi on croirait corriger celui du collègue affiché juste à côté. */
.pedago-zone-edit-qui { font-weight: 500; color: var(--muted); text-transform: none;
    letter-spacing: 0; margin-left: .35rem; }

/* Qui signe, dans le panneau d'écriture — annoncé AVANT d'écrire. */
.pedago-note-signature { display: flex; align-items: center; gap: .4rem;
    margin: .6rem 0 0; font-size: .8rem; color: var(--muted); }
.pedago-note-signature strong { color: var(--ink); }

/* Convention des formulaires du dossier élève : UN SEUL bouton d'enregistrement,
   vert, aligné à GAUCHE. Pas d'« Annuler » — la croix, l'Échap et le clic hors du
   panneau ferment déjà, et un second bouton concurrence l'action réelle.
   (.disc-drawer-foot aligne déjà à gauche : rien à y ajouter.) */
.pedago-form-actions { display: flex; justify-content: flex-start; margin-top: 1rem; }

/* Phrase d'orientation de la carte Documents (formats acceptés, taille max). */
.pedago-doc-aide { margin: -.4rem 0 .7rem; font-size: .82rem; color: var(--muted); }

/* ── Entretiens : une LIGNE par entretien, le fil conducteur conservé ────────
   Date · objet · auteur · actions. Le compte-rendu ne s'étale plus dans la liste :
   il s'ouvre dans le panneau latéral, en lecture. */
/* GRILLE INVISIBLE : colonnes de largeur fixe, alignées d'une ligne à l'autre, et
   `justify-content: start` — l'espace restant va TOUT À DROITE au lieu d'écarter la
   date de l'œil aux deux bouts de la carte. */
/* ⚠️ `padding` REDÉCLARÉ en entier : la valeur héritée de `.disc-timeline-item`
   (`0 0 1rem 1.1rem`) porte le retrait qui écarte la ligne du trait vertical —
   l'écraser par un `padding: .4rem 0` collait le texte sur le fil. */
.pedago-ent-item { display: grid; justify-content: start; align-items: center;
    grid-template-columns: 6.5rem minmax(0, 26rem) minmax(0, 13rem) auto;
    gap: .25rem 1.1rem; padding: .35rem 0 .35rem 1.1rem; }
/* La pastille du fil était calée sur `top: .3rem`, pensé pour l'ancien bloc
   multi-lignes dont la date était la 1re ligne. La ligne étant désormais une grille
   centrée, on centre la pastille : elle s'aligne alors sur la date. */
.pedago-ent-item::before { top: 50%; transform: translateY(-50%); }
.pedago-ent-date { font-size: .82rem; font-weight: 700; color: var(--muted);
    font-variant-numeric: tabular-nums; }
.pedago-ent-objet { min-width: 0; font-weight: 650; font-size: .9rem;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pedago-ent-auteur { display: inline-flex; align-items: center; gap: .35rem; min-width: 0;
    font-size: .82rem; color: var(--muted); }
.pedago-ent-auteur > span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pedago-ent-actions { display: inline-flex; align-items: center; gap: .2rem; }
/* Écran étroit : la grille se resserre, l'objet garde la priorité. */
@media (max-width: 760px) {
    .pedago-ent-item { grid-template-columns: 5.6rem minmax(0, 1fr) auto; }
    .pedago-ent-auteur { display: none; }
}

/* Détail d'un entretien : VERROUILLÉ à l'ouverture, l'édition est un geste
   explicite. La bascule est visuelle ; la garde réelle est côté serveur. */
.pedago-ent-detail .ent-ed { display: none; }
.pedago-ent-detail.is-edit .ent-ed { display: revert; }
.pedago-ent-detail.is-edit .ent-ro { display: none; }
.pedago-ent-verrou { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem;
    margin: 0 0 .9rem; padding: .5rem .7rem; border-radius: 9px; background: var(--bg);
    border: 1px dashed var(--line); color: #475569; font-size: .82rem; }
.ent-meta { display: grid; gap: .5rem 1.2rem; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    margin: 0 0 .9rem; }
.ent-meta dt { font-size: .72rem; font-weight: 700; text-transform: uppercase;
    letter-spacing: .04em; color: var(--muted); }
.ent-meta dd { margin: .1rem 0 0; font-weight: 600; font-size: .88rem;
    display: flex; align-items: center; gap: .35rem; }

/* Documents (bilans, rapports…) : GRID INVISIBLE calqué sur la liste des entretiens —
   colonnes alignées, aucune bordure. La régularité suffit à faire lire la liste ; les
   filets de l'ancienne version hachaient la carte sans rien ajouter. */
.pedago-doc-liste { list-style: none; margin: .2rem 0 0; padding: 0; }
.pedago-doc-item { display: grid; justify-content: start; align-items: center;
    grid-template-columns: 6.5rem minmax(0, 26rem) minmax(0, 13rem) auto;
    gap: .25rem 1.1rem; padding: .35rem 0; }
.pedago-doc-item + .pedago-doc-item { border-top: 1px solid color-mix(in srgb, var(--line) 45%, transparent); }
.pedago-doc-date { font-size: .82rem; font-weight: 700; color: var(--muted);
    font-variant-numeric: tabular-nums; }
.pedago-doc-nom { display: inline-flex; align-items: center; gap: .4rem; min-width: 0; font-size: .9rem; }
.pedago-doc-ico { flex: none; line-height: 1; }
/* Seul le LIBELLÉ se tronque : la catégorie et la taille sont courtes et doivent rester
   entières (une taille coupée ne veut plus rien dire). */
.pedago-doc-lib { min-width: 0; font-weight: 650; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pedago-doc-taille { flex: none; font-size: .78rem; font-variant-numeric: tabular-nums; }
.pedago-doc-auteur { display: inline-flex; align-items: center; gap: .35rem; min-width: 0;
    font-size: .82rem; color: var(--muted); }
.pedago-doc-auteur > span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pedago-doc-actions { display: inline-flex; align-items: center; gap: .2rem; }
@media (max-width: 760px) {
    .pedago-doc-item { grid-template-columns: 5.6rem minmax(0, 1fr) auto; }
    .pedago-doc-auteur, .pedago-doc-taille { display: none; }
}

/* ---------- Édition en place (crayon) : réutilise TEL QUEL le système générique
   .eleve-edit/.ee-read/.ee-edit/.ee-statut du bloc « Fiche élève — édition en place »
   ci-dessus (aucune classe inventée pour le read/edit toggle lui-même) — uniquement la
   mise en page propre aux champs de la fiche pédagogique. ---------- */

/* Cases dispositifs + sous-blocs maintien/avancement : ligne flex qui wrap. Spécificité
   à 3 classes, IDENTIQUE à `.eleve-edit.is-editing .ee-edit` (display:block générique) —
   gagne par ordre de cascade (cette règle est plus bas dans le fichier). */
.eleve-edit.is-editing .pedago-disp-edit { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem 1.2rem; margin: 10px 0; }
.pedago-sub-select { flex-basis: 100%; display: flex; gap: .5rem; margin: -.3rem 0 .4rem 1.7rem; }
.pedago-sub-select select { max-width: 220px; }
.pedago-sub-select[hidden] { display: none; } /* sinon display:flex masque l'attribut hidden (motif .cps-reply) */

/* Bloc « Aménagements raisonnables » en édition (.pedago-amg.ee-edit) : même piège que
   .cps-reply/.pedago-sub-select ci-dessus — la règle auteur `.eleve-edit.is-editing .ee-edit
   { display: block }` (générique, ci-dessus) bat la règle user-agent [hidden]{display:none}
   à spécificité égale/inférieure quel que soit l'attribut `hidden` posé par le template
   quand `fiche.ar` est faux. Sans ce correctif, le catalogue des 28 aménagements s'affiche
   dès qu'on entre en édition même sur une fiche sans AR (et les cases cochées y sont
   silencieusement jetées par PedagogieService::majFiche, qui vide amenagements si ar=false). */
.eleve-edit.is-editing .ee-edit[hidden] { display: none; }

/* Catalogue d'aménagements en édition : accordéon de cases par catégorie (le violet/gras
   du résumé vient de la règle héritée `.pedago-amg summary` ci-dessus). */
.pedago-cat-titre { margin: 0 0 6px; font-weight: 700; font-size: .8rem; color: #40378f; }
.pedago-cat-group { margin: 2px 0; }
.pedago-amg-item { padding: 2px 0 2px 14px; font-size: .78rem; }

@media (max-width: 900px) {
    .disc-detail-grid { grid-template-columns: 1fr; }
    .pedago-zones { grid-template-columns: 1fr; }
}

/* ---------------------------------------------------------------------------
   Aide des modules (App\Aide) — documents empilés et centrés, puis la FAQ.
   Les classes vivent ICI et jamais dans un <style> de gabarit : la page peut
   être rendue pour plusieurs modules, le style serait dupliqué.
   --------------------------------------------------------------------------- */
.aide-doc, .aide-faq { max-width: 900px; margin-inline: auto; }

/* `.card` n'a AUCUNE marge dans ce projet : sans ça les cartes se touchent. */
.aide-doc { margin-bottom: 1.1rem; }

/* Même en-tête de carte que la Discipline : titre à gauche, actions repoussées
   à droite. On ne réutilise pas les classes `disc-*`, réservées au dossier élève. */
.aide-doc .card-title,
.aide-faq .card-title { display: flex; align-items: center; gap: .5rem; color: #40378f; font-size: .95rem; }
.aide-doc-actions { margin-left: auto; display: flex; gap: .4rem; }

/* CONSULTATION SEULE : les pages du PDF sont dessinées par PDF.js et empilées. Aucune
   hauteur imposée — on déroule les pages, c'est `.content` qui défile (body.app-fit).
   Pas de cadre sombre, pas de barre d'outils : il n'y a plus de visualiseur natif. */
.aide-doc-pages { display: flex; flex-direction: column; gap: .8rem; }

.aide-doc-page {
    display: block;
    width: 100%;
    height: auto;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: #fff;
    box-shadow: 0 1px 3px rgba(31, 36, 64, .06);
}

.aide-doc-pages.is-chargement { min-height: 120px; }
.aide-doc-pages.is-chargement::after {
    content: "Chargement du document…";
    color: var(--muted);
    font-size: .9rem;
}
.aide-doc-pages.is-erreur { color: var(--muted); font-size: .9rem; }

/* Document déposé en IMAGE (capture d'écran PNG…) : même présentation qu'une page de PDF,
   pleine largeur de la carte. `height:auto` préserve les proportions sur mobile. */
.aide-doc-image {
    display: block;
    width: 100%;
    height: auto;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: #fff;
    box-shadow: 0 1px 3px rgba(31, 36, 64, .06);
}

.aide-faq-item { border-top: 1px solid var(--line); padding: .55rem 0; }
.aide-faq-item:first-of-type { border-top: 0; }
.aide-faq-item > summary { cursor: pointer; font-weight: 600; }
.aide-faq-reponse { padding: .45rem 0 .2rem; }
.aide-faq-reponse p:last-child { margin-bottom: 0; }

/* Titre de la section FAQ, HORS de la carte : les utilisateurs doivent voir d'un coup
   d'œil que ce qui suit les documents est une foire aux questions. */
.aide-faq-titre {
    max-width: 900px;
    margin: 1.6rem auto .6rem;
    font-size: 1.25rem;
}

/* Rien à masquer sur téléphone : les pages sont des images, elles s'y affichent
   exactement comme sur grand écran (c'était tout l'intérêt d'abandonner l'<iframe>). */

/* Import d'une FAQ par collage : la zone reçoit un document entier, pas une réponse —
   elle a donc besoin de bien plus de hauteur qu'un champ ordinaire. */
.aide-import-zone { min-height: 220px; }
.aide-import-liste { margin: .4rem 0 .8rem; padding-left: 1.2rem; }
.aide-import-liste li { margin-bottom: .3rem; }

/* Intertitre de la FAQ : sépare les sections d'un document d'aide (« Faire l'appel »,
   « Absences »…). Sans lui, soixante questions s'empilent sans repère. */
.aide-faq-section {
    margin: 1.1rem 0 .3rem;
    font-family: "Baloo 2", sans-serif;
    font-size: 1rem;
    color: #40378f;
}
.aide-faq-section:first-of-type { margin-top: .2rem; }

/* ═══ Export APP100 — écran de pilotage « À traiter / Le registre » (préfixe a1-) ════════════
   Refonte 2026-08-14 : l'écran s'était empilé par itérations (5 KPIs, file par élève de ~2 000
   lignes, section hors-fenêtre, liste des lots) et deux tableaux jumeaux décrivaient le même
   jour avec deux vocabulaires. Il porte désormais DEUX temps : « À traiter » = un mur de CAS
   (une carte = un geste, écrite en français) ; « Le registre » = la consultation exhaustive.
   Template + CSS seulement : assembleurs, jetons, routes et endpoint live sont inchangés. */

/* Palette : sous cette racine, les badges du module parlent la langue de Présences (.etat-*)
   au lieu de celle des jobs d'import. On cible `data-etat` (posé par le gabarit) et NON les
   classes rendues par PHP — le repeint live efface l'attribut, la classe du serveur reprend
   alors la main : jamais un badge « Transmis » peint aux couleurs de « À envoyer ». */
.a1-app100 .badge[data-etat="appel_non_termine"] { background: #eef1f5; color: #64748b; }
.a1-app100 .badge[data-etat="a_envoyer"],
.a1-app100 .badge[data-etat="susp_a_transmettre"] { background: #fef3c7; color: #92400e; }
.a1-app100 .badge[data-etat="en_cours"]           { background: #eae7ff; color: #5b3fd6; }
.a1-app100 .badge[data-etat="transmis"],
.a1-app100 .badge[data-etat="susp_transmise"],
.a1-app100 .badge[data-etat="suppr_transmise"]    { background: #dcfce7; color: #166534; }
.a1-app100 .badge[data-etat="correction"]         { background: #e0f2fe; color: #0369a1; }
.a1-app100 .badge[data-etat="echec"]              { background: #fee2e2; color: #b91c1c; }
.a1-app100 .badge[data-etat="bloquee"]            { background: #fce7f3; color: #9d174d; }

/* Les deux temps de l'écran. Ce sont des LIENS (?vue=) : l'onglet survit au rechargement
   qui suit chaque envoi, et le registre reste partageable par son URL. */
   Le contrôle est le SEGMENTÉ de l'app (`.seg` / `.seg-btn`) : l'ancien jeu `.a1-tab` en était
   un double, d'où sa dérive de couleurs. Il ne reste ici que la marge du bloc, le fait que les
   segments sont des liens (donc sans soulignement) et la pastille de comptage. */
.a1-segment { margin: 0 0 1.1rem; }
.a1-segment .seg-btn { display: inline-flex; align-items: center; gap: .4rem; text-decoration: none; }
.a1-tab-n {
    display: inline-grid; place-items: center; min-width: 22px; height: 22px; padding: 0 .3rem;
    border-radius: 999px; background: var(--primary); color: #fff; font-size: .78rem;
}
.seg-btn:not(.is-active) .a1-tab-n { background: var(--muted); }

/* Rien à faire : l'écran doit le DIRE, sinon il a l'air aussi chargé qu'un jour de panne. */
.a1-ok {
    display: flex; align-items: center; gap: 1rem;
    background: var(--card); border: 1px solid var(--line); border-left: 5px solid var(--ok);
    border-radius: var(--radius); padding: 1.1rem 1.3rem;
}
.a1-ok-ic { font-size: 2rem; line-height: 1; }

/* Filtres du mur de cartes : radios masquées + règles ~ . Aucun JS, aucun aller-retour, et
   l'état se voit dans la tuile allumée. Une tuile à zéro n'est pas un label (rien à filtrer). */
.a1-f { position: absolute; opacity: 0; pointer-events: none; }
.a1-kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: .8rem; margin-bottom: 1.1rem; }
.a1-kpi {
    display: block; border: 1px solid var(--line); border-radius: 14px; padding: .75rem .9rem;
    background: var(--card); cursor: pointer; transition: border-color .14s, box-shadow .14s;
}
.a1-kpi.is-vide { cursor: default; opacity: .6; }
.a1-kpi:not(.is-vide):hover { border-color: var(--primary); }
.a1-n { display: block; font-family: "Baloo 2", sans-serif; font-size: 1.7rem; font-weight: 800; line-height: 1; font-variant-numeric: tabular-nums; }
.a1-l { display: block; color: var(--muted); font-size: .82rem; }
.a1-kpi.is-echec .a1-n { color: #b91c1c; }
.a1-kpi.is-bloque .a1-n { color: #9d174d; }
/* La tuile n'est qu'un label : c'est la case radio, invisible, qui reçoit le focus clavier —
   on reporte donc l'anneau sur SA tuile (une règle par filtre, comme pour :checked). */
#a1f-tout:focus-visible   ~ .a1-kpis [for="a1f-tout"],
#a1f-envoi:focus-visible  ~ .a1-kpis [for="a1f-envoi"],
#a1f-renvoi:focus-visible ~ .a1-kpis [for="a1f-renvoi"],
#a1f-echec:focus-visible  ~ .a1-kpis [for="a1f-echec"],
#a1f-bloque:focus-visible ~ .a1-kpis [for="a1f-bloque"] { outline: 2px solid var(--primary); outline-offset: 2px; }
#a1f-tout:checked   ~ .a1-kpis [for="a1f-tout"],
#a1f-envoi:checked  ~ .a1-kpis [for="a1f-envoi"],
#a1f-renvoi:checked ~ .a1-kpis [for="a1f-renvoi"],
#a1f-echec:checked  ~ .a1-kpis [for="a1f-echec"],
#a1f-bloque:checked ~ .a1-kpis [for="a1f-bloque"] { border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-soft); }
#a1f-envoi:checked  ~ .a1-cards .a1-cas:not([data-cat="envoi"]),
#a1f-renvoi:checked ~ .a1-cards .a1-cas:not([data-cat="renvoi"]),
#a1f-echec:checked  ~ .a1-cards .a1-cas:not([data-cat="echec"]),
#a1f-bloque:checked ~ .a1-cards .a1-cas:not([data-cat="bloque"]) { display: none; }

/* Le mur de cas. Une carte = un problème + sa phrase + son bouton ; la couleur du liseré
   redit la famille déjà donnée par le picto du titre (jamais la couleur seule). */
.a1-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(330px, 1fr)); gap: .9rem; align-items: start; }
.a1-cas {
    display: flex; flex-direction: column; gap: .5rem;
    background: var(--card); border: 1px solid var(--line); border-left: 4px solid var(--muted);
    border-radius: var(--radius-sm); padding: .95rem 1.05rem;
}
.a1-cas.is-echec  { border-left-color: #b91c1c; }
.a1-cas.is-bloque { border-left-color: #9d174d; }
.a1-cas.is-renvoi { border-left-color: #0369a1; }
.a1-cas.is-envoi  { border-left-color: #f59e0b; }
.a1-cas-head { display: flex; align-items: flex-start; justify-content: space-between; gap: .6rem; flex-wrap: wrap; }
.a1-cas-head h3 { margin: 0; font-size: .98rem; font-weight: 800; line-height: 1.3; text-wrap: balance; }
.a1-badge-lien { text-decoration: none; }
.a1-cas-ou { display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; color: var(--muted); font-size: .82rem; }
.a1-delai { font-weight: 600; }
.a1-cas-dit { font-size: .88rem; }
.a1-cas-dit p { margin: 0 0 .4rem; }
.a1-cas-dit p:last-child { margin-bottom: 0; }
.a1-warn { color: #92400e; }
.a1-eleves { margin: .2rem 0 0; padding-left: 1.1rem; font-size: .86rem; }
.a1-eleves li { margin-bottom: .2rem; }
.a1-cas-act { display: flex; align-items: center; gap: .45rem; flex-wrap: wrap; margin-top: auto; padding-top: .2rem; }
.a1-cas-oeil { margin-left: auto; }
.a1-hint { font-size: .78rem; }
/* Aboutissement en direct : la carte ne disparaît pas toute seule (on ne retire jamais un
   nœud sous la souris) — elle se grise et invite à actualiser. */
.a1-cas.is-fini { opacity: .6; }
.a1-fini { display: inline-flex; align-items: center; gap: .4rem; font-size: .8rem; color: var(--muted); }
.a1-fini[hidden] { display: none; }

/* Pied : ce qui vit sans nous (appels pas encore validés, envois en vol). */
.a1-pied { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; margin-top: 1rem; color: var(--muted); font-size: .85rem; }

/* Hors fenêtre : c'est du droit FWB, pas du pilotage. */
.a1-hf { margin-top: 1rem; background: var(--card); border: 1px solid var(--line); border-radius: var(--radius-sm); padding: .7rem 1rem; }
.a1-hf-titre { margin: 0; font-weight: 700; font-size: .9rem; }
.a1-hf-classer { display: flex; flex-wrap: wrap; gap: .4rem; align-items: center; }
.a1-hf p { font-size: .85rem; }
.a1-hf-jour { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; margin: .6rem 0 .2rem; }

/* Le registre. `a1-raison` sert AUSSI aux pages de communication (suspensions, justificatifs) :
   sa place est ici, pas dans un <style> de gabarit. */
.a1-reg-note { font-size: .85rem; margin: 0 0 .7rem; }
.a1-num { white-space: nowrap; font-variant-numeric: tabular-nums; }
.a1-raison { display: block; color: var(--muted); font-size: .82rem; }
/* Registre : signal d'anomalie réduit à un pictogramme, pour que la ligne tienne sur UNE
   hauteur. Ce qu'il annonce se lit derrière l'œil (et en infobulle au survol). */
.a1-flag { margin-left: .3rem; cursor: help; }
/* Colonnes d'ACTION du registre : une par picto (œil, puis rejouer/envoyer). Deux colonnes et
   non une seule — c'est ce qui aligne les œils d'une ligne à l'autre, même quand il n'y a rien
   à rejouer. `table-layout:fixed` (disc-table) fige la largeur, le centrage fait le reste. */
.a1-col-ic { text-align: center; white-space: nowrap; overflow: visible; }
.a1-col-ic form { display: inline; margin: 0; }
/* Grille des tentatives (page de détail) : la ligne dont on lit le contenu plus bas. Le
   liseré porte l'information — une simple teinte se confondrait avec le survol. */
.a1-tent-grid tr.is-vue > td { background: var(--primary-soft); }
.a1-tent-grid tr.is-vue > td:first-child { box-shadow: inset 3px 0 0 var(--primary); }
/* Unité APP100 au fil du texte, à côté de la pastille d'implantation : ce n'est PAS un badge
   (elle ne porte aucun état), juste la précision « unité 1 (primaire) » sur la même ligne.
   Le conteneur est `.cell-name` (flex) — cf. gabarit. */
.a1-unite { color: var(--muted); font-size: .85rem; font-weight: 600; overflow: hidden; text-overflow: ellipsis; }

/* ── Détail d'une transmission : méta à gauche, élèves à droite (même partition que la fiche
   justificatif). Les blocs « Communication » avaient leurs styles en `style=` inline dans le
   gabarit : ramenés ici. ── */
.a1-detail { display: grid; grid-template-columns: minmax(300px, 400px) 1fr; gap: 1.2rem; align-items: start; }
@media (max-width: 900px) { .a1-detail { grid-template-columns: 1fr; } }
.a1-req { font-size: .82rem; font-weight: 500; color: var(--muted); word-break: break-all; }
.a1-rapport { margin-top: .8rem; }
.a1-rapport summary { cursor: pointer; }
.a1-tent { border: 1px solid var(--line); border-radius: 10px; padding: .7rem .9rem; margin-bottom: .6rem; }
.a1-tent-head { display: flex; gap: .6rem; align-items: center; flex-wrap: wrap; }
.a1-tent-err { margin-top: .4rem; }
.a1-tent-err summary { cursor: pointer; }
.a1-tent-json { max-height: 320px; overflow: auto; font-size: .78rem; }

/* Liste clé/valeur d'une page de détail. Née dans la fiche justificatif (où elle vivait en
   <style> local), PARTAGÉE depuis avec le détail d'une transmission APP100 → promue ici pour
   qu'il n'y ait qu'une définition. Les surcharges d'ÉDITION EN PLACE restent locales à la
   fiche justificatif (son <style> est rendu après cette feuille, il gagne). */
.pj-dl { display: flex; flex-direction: column; gap: 0; }
.pj-dl > div { display: flex; gap: .8rem; padding: .55rem 0; border-top: 1px solid #eef2f7; }
.pj-dl > div:first-child { border-top: 0; }
.pj-dl dt { flex: 0 0 42%; font-size: .82rem; color: var(--muted); text-transform: uppercase; letter-spacing: .02em; margin: 0; }
.pj-dl dd { flex: 1; margin: 0; font-weight: 600; }

/* Responsable légal — second axe, posé à côté du badge de relation dans la fiche élève.
   Un écusson discret, pas un badge de plus : la relation reste l'information principale. */
.resp-legal {
  font-size: .72rem;
  font-weight: 700;
  color: #40378f;
  white-space: nowrap;
}

/* ── Grille 🔐 Rôles & permissions — sélecteur de portée par domaine ────────────
   Un cran = niveau + portée (voir/modifier × tous/ses élèves). Le select remplace
   les 3 radios ∅/👁/✏️ : à 6 crans, des radios déborderaient en largeur. */
/* Rôle sans classes réglé sur « ses élèves » : il ne verrait aucun élève. */
.perm-alerte { margin-left: .25rem; font-size: .9rem; }

/* ── Nettoyage de rentrée (super-admin) ──────────────────────────────────────
   Écran /admin/nettoyage : suppression en masse des élèves fantômes, ouverte
   jusqu'au premier jour de l'année scolaire seulement. */
.nett-confirm {
    display: flex;
    align-items: flex-start;
    gap: .6rem;
    margin: 1rem 0 .2rem;
    font-weight: 600;
    line-height: 1.4;
    cursor: pointer;
}
.nett-confirm input { margin-top: .18rem; flex: none; }
/* Une ligne épargnée reste lisible mais s'efface visuellement : l'œil doit tomber
   sur ce qui va être détruit, pas sur ce qui reste. */
.disc-table tr.is-epargne { opacity: .62; }
.disc-table tr.is-epargne .a1-raison { display: block; }

/* ─── Compte à rebours de la fenêtre FWB (file d'envoi APP100) ───────────────────────────
   Sur une ligne « ⏳ Appel non terminé » : combien de jours OUVRABLES il reste avant que la
   FWB ne fige la journée. Ce n'est pas un ornement — passé la fenêtre, l'appel manquant est
   perdu, et rien d'autre à l'écran ne le disait. */
.a1-jr {
    margin-left: .35rem; padding: .05rem .4rem; border-radius: 999px;
    background: #eef1f5; color: #64748b; font-size: .76rem; font-weight: 700;
    font-variant-numeric: tabular-nums; cursor: help;
}
.a1-jr.is-urgent { background: #fef3c7; color: #92400e; }
.a1-jr.is-close  { background: #fee2e2; color: #b91c1c; }
/* La tuile « Appel non terminé » COMPTE dans « À traiter » (la direction est comptable du
   registre, pas seulement l'enseignant), mais son chiffre reste neutre : ni refus, ni blocage. */
.a1-kpi.is-attente .a1-n { color: #64748b; }

/* Détail d'une correction APP100 : le code transmis → celui qu'on va envoyer. */
.a1-diff { font-variant-numeric: tabular-nums; font-weight: 600; }
.a1-diff-fleche { color: var(--muted); margin: 0 .15rem; }

/* ===========================================================================
   Contrôle de cohérence (/etablissement/coherence).
   Une ligne = un contrôle, dépliable sur ses lignes nommées.
   =========================================================================== */

.ck-verdict { display: flex; align-items: center; gap: 1.1rem; padding: 1.15rem 1.4rem; border-radius: var(--radius); margin-bottom: 1.3rem; border: 1px solid; }
.ck-verdict.is-ko { background: linear-gradient(135deg, #fff5f5, #fff9f5); border-color: #fbd5d5; }
.ck-verdict.is-ok { background: linear-gradient(135deg, #effaf3, #f0fbf7); border-color: #b7ebcd; }
.ck-verdict-ico { width: 56px; height: 56px; flex: none; border-radius: 16px; display: grid; place-items: center; font-size: 1.7rem; }
.ck-verdict.is-ko .ck-verdict-ico { background: #fee2e2; }
.ck-verdict.is-ok .ck-verdict-ico { background: #dcfce7; }
.ck-verdict-txt { flex: 1; min-width: 0; }
.ck-verdict-h { margin: 0; font-size: 1.22rem; line-height: 1.25; }
.ck-verdict.is-ko .ck-verdict-h { color: #b91c1c; }
.ck-verdict.is-ok .ck-verdict-h { color: #157a4b; }
.ck-verdict-s { margin: .2rem 0 0; font-size: .88rem; color: var(--muted); }

.ck-groupe { margin-bottom: 1.1rem; padding: 0; overflow: hidden; }
.ck-groupe-h { display: flex; align-items: center; gap: .55rem; margin: 0; padding: .85rem 1.2rem; font-size: .76rem; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); border-bottom: 1px solid var(--line); background: #fcfcfe; }
.ck-groupe-h .ck-gn { margin-left: auto; font-family: "Baloo 2", sans-serif; font-size: 1rem; color: var(--ink); letter-spacing: 0; }

.ck-item { border-bottom: 1px solid var(--line); }
.ck-item:last-child { border-bottom: none; }
.ck-row { display: grid; grid-template-columns: 10px minmax(0, 1fr) auto auto; align-items: center; gap: .9rem; padding: .85rem 1.2rem; cursor: pointer; list-style: none; }
.ck-row::-webkit-details-marker { display: none; }
.ck-item[open] .ck-row { background: #fcfbff; }
.ck-item[open] .ck-chev { transform: rotate(90deg); }
.ck-dot { width: 10px; height: 10px; border-radius: 50%; }
.ck-dot.ko { background: #dc2626; }
.ck-dot.warn { background: #ea580c; }
.ck-dot.ok { background: #16a34a; }
/* ⚠️ Sans flex-direction:column, le titre et la conséquence — deux <span> — se
   suivent sur la MÊME ligne et se collent sans espace. */
.ck-row-body { min-width: 0; display: flex; flex-direction: column; }
.ck-row-t { font-weight: 600; font-size: .95rem; line-height: 1.3; }
.ck-row-c { font-size: .81rem; color: var(--muted); line-height: 1.35; margin-top: .1rem; }
.ck-n { font-family: "Baloo 2", sans-serif; font-weight: 800; font-size: 1.45rem; line-height: 1; font-variant-numeric: tabular-nums; min-width: 2.2rem; text-align: right; }
.ck-n.ko { color: #dc2626; }
.ck-n.warn { color: #ea580c; }
.ck-chev { color: var(--muted); font-size: 1.05rem; width: 1.2rem; text-align: center; transition: transform .15s ease; }

.ck-sub { background: #fbfaff; padding: .3rem .6rem .7rem 2.15rem; }
.ck-fix { display: flex; align-items: flex-start; gap: .5rem; margin: .35rem .6rem .55rem; padding: .55rem .75rem; border-radius: 10px; background: var(--brand-soft); color: var(--brand-dark); font-size: .84rem; line-height: 1.4; }
.ck-line { display: flex; align-items: center; gap: .65rem; padding: .4rem .6rem; border-radius: 9px; text-decoration: none; color: inherit; font-size: .9rem; }
.ck-line:hover { background: var(--primary-soft); }
.ck-line-nom { font-weight: 600; }
.ck-line-meta { color: var(--muted); font-size: .82rem; }
.ck-line-sp { flex: 1; }
.ck-more { padding: .45rem .6rem; font-size: .83rem; color: var(--muted); font-style: italic; }

/* La ligne verte est un <summary> repliable : elle déplie la liste de CE QU'ON A REGARDÉ.
   Comme .ck-row, elle doit perdre le marqueur natif du <details>. */
.ck-sains { border: 1px solid #cdeedd; border-radius: var(--radius); overflow: hidden; }
.ck-vert { display: flex; align-items: center; gap: .7rem; padding: .8rem 1.2rem; background: #f2fbf6; color: #157a4b; font-size: .9rem; font-weight: 600; cursor: pointer; list-style: none; }
.ck-vert::-webkit-details-marker { display: none; }
.ck-vert .ck-vert-n { font-family: "Baloo 2", sans-serif; font-weight: 800; font-size: 1.15rem; }
.ck-vert .ck-vert-sp { flex: 1; }
.ck-vert .ck-chev { color: #3f9a6d; }
.ck-sains[open] .ck-chev { transform: rotate(90deg); }
.ck-sains-liste { margin: 0; padding: .6rem 1.2rem .9rem 2.6rem; list-style: none; background: #fafefb; column-width: 20rem; column-gap: 1.6rem; }
.ck-sains-liste li { font-size: .87rem; color: var(--muted); padding: .12rem 0; break-inside: avoid; }

/* ═══════════════════════════════════════════════════════════════════════════════════════════
   📡 REGISTRE FWB — la confrontation au registre de la Fédération (préfixe `rf-`)

   Rien de générique ici : le bandeau de verdict réutilise `.ck-verdict`, les cartes `.card`,
   les badges `.badge-*`. Ce bloc ne pose que ce qui n'existait pas — la grille du registre et
   la ligne d'écart.
   ═══════════════════════════════════════════════════════════════════════════════════════════ */

/* ── Le sélecteur mois × implantation × unité ── */
.rf-filtres { display: flex; flex-wrap: wrap; align-items: flex-end; gap: .9rem; margin-bottom: .8rem; }
.rf-filtre { display: flex; flex-direction: column; gap: .25rem; min-width: 0; }
.rf-filtre > span { font-size: .72rem; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--muted); }
.rf-filtre select { min-width: 12rem; max-width: 100%; }
.rf-filtres-sp { flex: 1; }

.rf-relire { display: flex; align-items: center; flex-wrap: wrap; gap: .7rem; margin-bottom: .55rem; }
.rf-relire-note { font-size: .82rem; color: var(--muted); max-width: 46rem; line-height: 1.45; }

/* La synchronisation manuelle : deux dates et un bouton, alignés sur la ligne du dessus. */
.rf-synchro { display: flex; align-items: flex-end; flex-wrap: wrap; gap: .7rem; margin-bottom: 1.2rem; }
.rf-synchro input[type="date"] { min-width: 9.5rem; }
.rf-synchro .rf-relire-note { align-self: center; }

.rf-bloc { margin-bottom: 1.1rem; padding: 0; overflow: hidden; }
.rf-legende { margin: .8rem 1.2rem .2rem; font-size: .84rem; color: var(--muted); line-height: 1.5; }

/* ── La grille : le registre reconstitué ──
   ⚠️ Le défilement horizontal vit DANS ce conteneur. La page ne défile jamais latéralement. */
.rf-scroll { overflow-x: auto; padding: .8rem 1.2rem 1.2rem; }
.rf-grille { border-collapse: separate; border-spacing: 0; margin-bottom: 1.4rem; font-size: .82rem; }
.rf-grille:last-child { margin-bottom: 0; }
.rf-grille caption { text-align: left; font-weight: 700; font-size: .9rem; padding-bottom: .4rem; color: var(--ink); }

/* ⚠️ Sélecteurs préfixés par `.rf-scroll` — pas par coquetterie : `.page-with-aside table td`
   (0,2,1) bat `.rf-grille td` (0,1,1) et rendait 1,1 rem de padding horizontal sur chaque
   case. Un mois demandait alors 1 280 px de large là où 700 suffisent. Mesuré, pas supposé. */
.rf-scroll .rf-grille th,
.rf-scroll .rf-grille td { padding: .22rem .16rem; border-bottom: 1px solid var(--line); }

/* La colonne des noms reste visible pendant le défilement : sans elle, on lit une grille de
   codes sans savoir de qui l'on parle. */
.rf-scroll .rf-col-nom {
    position: sticky; left: 0; z-index: 1;
    background: var(--card);
    text-align: left; font-weight: 600; font-size: .8rem; text-transform: none; letter-spacing: 0;
    color: var(--ink); white-space: nowrap;
    padding-right: .7rem; min-width: 9.5rem;
    box-shadow: 1px 0 0 var(--line);
}
.rf-col-nom a { color: inherit; text-decoration: none; }
.rf-col-nom a:hover { text-decoration: underline; }

.rf-scroll .rf-col-jour { text-align: center; font-variant-numeric: tabular-nums; }
.rf-scroll thead .rf-col-jour { font-size: .74rem; color: var(--muted); font-weight: 700; padding-bottom: .45rem; letter-spacing: 0; }
.rf-scroll thead .rf-col-jour.is-nonlu { color: #c2410c; }
.rf-scroll thead .rf-col-jour.is-nonlu::after { content: '•'; display: block; line-height: .4; }

.rf-duo { display: inline-flex; gap: 1px; }
/* ⚠️ Dimensions serrées à dessein : un mois complet (20 jours ouvrés × 2 demis) doit tenir sans
   défilement sur un écran de bureau. Au-delà, `.rf-scroll` prend le relais — mais le cas
   COURANT ne doit pas obliger à faire glisser le tableau pour lire son propre registre. */
.rf-case {
    display: inline-grid; place-items: center;
    min-width: 1.12rem; height: 1.25rem; padding: 0 .1rem;
    border-radius: 4px; font-size: .68rem; font-weight: 700; font-family: "Baloo 2", sans-serif;
    text-decoration: none;
}
.rf-case.is-present { background: #f1f5f9; color: #64748b; }
.rf-case.is-absent  { background: #fff4e6; color: #b45309; }
.rf-case.is-vide    { background: transparent; color: #cbd5e1; font-weight: 400; }
.rf-case.is-ecart   { background: #fee2e2; color: #b91c1c; box-shadow: inset 0 0 0 1.5px #f87171; }
a.rf-case.is-ecart:hover { background: #fca5a5; color: #7f1d1d; }
.rf-case.is-fwb     { background: #ede9fe; color: #5b21b6; }
.rf-case.is-local   { background: var(--brand-soft); color: var(--brand-dark, #0369a1); }

/* ── Une ligne d'écart ── */
.rf-ecart { display: flex; flex-wrap: wrap; align-items: center; gap: .9rem 1.2rem; padding: .9rem 1.2rem; border-bottom: 1px solid var(--line); }
.rf-ecart:last-child { border-bottom: none; }
.rf-ecart-jour { display: flex; flex-direction: column; gap: .2rem; min-width: 9rem; font-size: .82rem; color: var(--muted); }
.rf-ecart-jour b { font-size: .92rem; color: var(--ink); }
.rf-ecart-jour .badge { align-self: flex-start; }

.rf-ecart-corps { flex: 1; min-width: 16rem; display: flex; flex-direction: column; gap: .45rem; }
.rf-ecart-qui { display: flex; align-items: baseline; gap: .5rem; flex-wrap: wrap; }
.rf-ecart-nom { font-weight: 700; font-size: .95rem; color: inherit; text-decoration: none; }
a.rf-ecart-nom:hover { text-decoration: underline; }
.rf-ecart-classe { font-size: .8rem; color: var(--muted); }

/* Le face-à-face : c'est LUI qui fait comprendre l'écart en une seconde. Les deux versions
   côte à côte, jamais l'une sous l'autre en petit. */
.rf-faceaface { display: flex; flex-wrap: wrap; gap: .4rem 1.4rem; }
.rf-cote { display: flex; align-items: center; gap: .45rem; font-size: .85rem; }
.rf-cote-qui { font-size: .7rem; font-weight: 800; letter-spacing: .05em; text-transform: uppercase; color: var(--muted); min-width: 5.2rem; }
.rf-cote-lib { color: var(--ink); }
.rf-cote-rien { color: var(--muted); font-style: italic; }

.rf-ecart-actions { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; }
.rf-ecart-sortie { font-size: .82rem; color: var(--muted); font-style: italic; max-width: 26rem; }

/* ── Ce qui n'a pas pu être comparé — jamais silencieux ── */
.rf-angles { background: #fffdf7; }
.rf-angle { padding: .8rem 1.2rem; border-bottom: 1px solid var(--line); }
.rf-angle:last-child { border-bottom: none; }
.rf-angle-note { margin: .25rem 0 .4rem; font-size: .82rem; color: var(--muted); line-height: 1.5; }
.rf-angle-liste { margin: .35rem 0 0; padding: 0; list-style: none; column-width: 22rem; column-gap: 1.6rem; }
.rf-angle-liste li { font-size: .85rem; color: var(--muted); padding: .12rem 0; break-inside: avoid; }
.rf-angle-cle { font-weight: 600; color: var(--ink); }
.rf-angle-cle a { color: inherit; text-decoration: none; }
.rf-angle-cle a:hover { text-decoration: underline; }

@media (max-width: 720px) {
    .rf-ecart-actions { width: 100%; }
    .rf-filtre select { min-width: 100%; }
    .rf-filtre { width: 100%; }
}

/* ── Page légale PUBLIQUE (politique de confidentialité) ────────────────────────────────────
   Même coque que l'écran de connexion et que les pages parents. Ce qui suit n'est que ce que
   `.auth-card` ne prévoit pas : une carte taillée pour un formulaire de 400px rend un texte
   long illisible, et `.auth-card` centre son titre — un document se lit aligné à gauche. */
.legal-card { max-width: 720px; text-align: left; }
.legal-card h1 { margin-bottom: .4rem; }
.legal-card h2 { margin: 2rem 0 .5rem; font-size: 1.05rem; color: var(--ink); }
.legal-card p { margin: 0 0 .9rem; line-height: 1.65; color: var(--ink); }
.legal-card .sub { margin-bottom: 1.8rem; }
.legal-liste { margin: 0 0 .9rem; padding: 0; line-height: 1.65; }
.legal-liste dt { font-weight: 600; margin-top: .7rem; }
.legal-liste dd { margin: 0; color: var(--muted); }
.legal-liste li { margin: 0 0 .5rem 1.1rem; color: var(--muted); }
.legal-liste li strong, .legal-liste dt { color: var(--ink); }
/* <address> arrive en italique et resserré par défaut du navigateur : ici c'est une
   identité légale, elle se lit comme le reste du document. */
.legal-editeur { font-style: normal; line-height: 1.8; color: var(--ink); }

/* ---------- Journal d'accès (super-admin) ----------
   Rien d'inventé : le grid dépliant (.epi-*), les badges, .mi-info, .pagination, .filters viennent
   du catalogue. Ici seulement ce qui manquait au catalogue, et qui sert ailleurs :
   - .badge-warn : la teinte orange qui manquait entre badge-ok et badge-danger (un 4xx, un verrou) ;
   - .cell-trunc : borner un contenu long SUR LE CONTENU (jamais sur le <td> : en table-layout auto,
     une largeur de cellule n'est qu'un vœu) — .table-wrap est en overflow:hidden et COUPE sinon ;
   - le focus clavier d'une ligne dépliante, absent jusqu'ici (Tab sur 200 lignes sans repère) ;
   - la barre de volume par jour en trois segments. */
.badge-warn { background: #fff4e5; color: #b45309; }
.cell-trunc { display: inline-block; max-width: 320px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom; }
.cell-trunc.is-court { max-width: 200px; }
.cell-trunc.is-long { max-width: 360px; }
/* Console ▸ Citations : le texte EST la colonne principale de cet écran — il prend la place que
   la table lui laisse, au lieu des 360 px génériques qui coupaient toutes les citations. */
.table-citations .cell-trunc { max-width: min(56vw, 760px); }
.epi-clic:focus-visible { outline: none; }
.epi-clic:focus-visible td { background: #eef2ff; box-shadow: inset 3px 0 0 var(--primary); }
table.sortable th a.th-label { color: inherit; text-decoration: none; }
table.sortable th a.th-label:hover { color: var(--primary); }
.ja-table td { vertical-align: top; }
.ja-table .ja-ip { font-variant-numeric: tabular-nums; white-space: nowrap; }
.ja-table .ja-origine, .ja-table .ja-route { display: block; font-size: .72rem; max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ja-table code { font-size: .82rem; }
.ja-row-serveur td { box-shadow: inset 3px 0 0 #c0392b; }
.ja-total { font-size: 1rem; font-weight: 600; }
.ja-detail { display: flex; flex-direction: column; gap: .9rem; padding: .3rem .2rem; }
.ja-detail-grille { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.ja-detail .mi-field-v { font-weight: 500; font-size: .85rem; }
.ja-erreur { border-left: 3px solid #c0392b; padding-left: .8rem; display: flex; flex-direction: column; gap: .6rem; }
.ja-trace { margin: 0; font-size: .74rem; line-height: 1.4; white-space: pre-wrap; word-break: break-word; background: #fff; border: 1px solid var(--line); border-radius: 8px; padding: .6rem .8rem; max-height: 18rem; overflow: auto; }
.ja-raccourcis { margin: 0; display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; }
.ja-raccourcis .btn-ghost { width: auto; }
.ja-actifs { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; margin: -.2rem 0 1rem; font-size: .85rem; }
.ja-actifs .badge a, .ja-actifs .muted a { margin-left: .3rem; text-decoration: none; }
.ja-actifs .btn-ghost { width: auto; }
.ja-check .dp-check { display: inline-flex; align-items: center; gap: .4rem; height: 2.6rem; }
.ja-pg-info { margin-left: .6rem; font-size: .85rem; }
.ja-stat { text-decoration: none; color: inherit; display: block; }
.ja-stat:hover { border-color: var(--primary); }
.ja-deux-colonnes { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.2rem; }
.ja-deux-colonnes .card, .content > .card[data-role] { margin-bottom: 1.2rem; }
.ja-fiche-grille { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.ja-fiche .card-title { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
.ja-fiche .btn-ghost { width: auto; }
.ja-jour { display: flex; align-items: center; gap: .6rem; margin: .25rem 0; font-size: .8rem; }
.ja-jour a { text-decoration: none; }
.barre-jour { display: flex; flex: 1; height: 1.1rem; border-radius: 4px; overflow: hidden; background: var(--bg); }
.barre-jour > span { display: block; height: 100%; }
.barre-jour .is-ok, .ja-leg.is-ok { background: var(--primary); }
.barre-jour .is-err, .ja-leg.is-err { background: #f59e0b; }
.barre-jour .is-echec, .ja-leg.is-echec { background: #c0392b; }
.ja-leg { display: inline-block; width: .8rem; height: .8rem; border-radius: 3px; vertical-align: middle; }
.ja-signaux tr.is-danger td { background: #fff5f5; }
.ja-signaux tr.is-warn td { background: #fffaf0; }
@media (max-width: 1100px) {
    .ja-deux-colonnes, .ja-detail-grille, .ja-fiche-grille { grid-template-columns: 1fr; }
}
/* Le journal d'accès est DENSE : cellules plus serrées que le tableau standard, et chaque contenu
   long borné (mesuré à 1 440 px : sans cela, Compte et Durée sortaient du cadre, coupés). */
.ja-table th, .ja-table td { padding: .55rem .7rem; }
.ja-table .badge { font-size: .74rem; padding: .2rem .5rem; }
.cell-trunc.is-moyen { max-width: 240px; }
.ja-table .ja-origine, .ja-table .ja-route { max-width: 170px; }
.ja-table-journal .cell-trunc.is-court { max-width: 170px; }
.ja-table-connexions .cell-trunc { max-width: 280px; }
/* Une IPv6 fait 39 caractères : en `nowrap` elle seule imposait 365 px à la colonne. Elle se coupe. */
.ja-table .ja-ip, .ja-table strong.ja-ip { white-space: normal; word-break: break-all; display: inline-block; max-width: 180px; }
.ja-table-blocages tr.is-inactif td { color: var(--muted); }
.ja-fiche-actions { display: inline-flex; gap: .4rem; }
.ja-bloquer { margin-left: .2rem; }

/* ── Tuile de classe du sélecteur d'appel (Présences ▸ Faire l'appel) ────────
   Sortie du gabarit pour vivre ici ; le CAHIER de classe (ci-dessous) est l'autre forme du
   même choix, pour les écrans qui ouvrent un dossier plutôt qu'un appel.                  */
.pr-tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 1rem; }
.pr-tile {
    display: flex; flex-direction: column; gap: .3rem;
    border: 1px solid #e2e8f0; border-radius: 14px; padding: 1rem; background: #fff;
    text-decoration: none; color: inherit;
    transition: transform .08s, box-shadow .08s, border-color .08s;
}
a.pr-tile:hover { border-color: #2563eb; box-shadow: 0 6px 18px rgba(37, 99, 235, .13); transform: translateY(-2px); }
a.pr-tile:focus-visible { outline: 3px solid #93c5fd; outline-offset: 2px; }
.pr-tile-nom { font-size: 1.6rem; font-weight: 800; line-height: 1.1; color: #0f172a; }
.pr-tile-eff { color: #64748b; font-size: .85rem; margin-bottom: .45rem; }
.pr-tile-go { margin-top: .5rem; font-weight: 700; color: #2563eb; font-size: .85rem; }

/* ── CAHIER de classe — le choix d'une classe, façon école ───────────────────
   Couverture colorée à spirale, étiquette blanche collée dessus : l'objet que l'enfant a
   dans son cartable. Employé par Présences ▸ Liste des justificatifs (`.jl-cahier`, qui y
   pose son compteur de pièces) et par Dossiers élèves (`.cahier`, qui y pose le titulaire).
   Un seul jeu de règles pour les deux — deux définitions auraient dérivé.                 */
/* `align-content: start` : la zone de travail est une colonne flex, la grille y reçoit donc
   toute la hauteur restante — et `stretch`, le défaut de la grille, étirerait ses rangées pour
   la remplir. Les cahiers gardent ainsi leur hauteur (mesurée : 220 px, toutes rangées). */
.jl-tiles, .cahiers { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
                      gap: 1.2rem; align-content: start; }
.jl-cahier, .cahier {
    position: relative; display: flex; flex-direction: column; align-items: center; gap: .4rem;
    min-height: 220px; border-radius: 8px 16px 16px 8px; padding: 1.3rem 1rem 1rem 2.1rem;
    text-decoration: none;
    background-image: linear-gradient(160deg, rgba(255, 255, 255, .18), rgba(0, 0, 0, .10));
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .15), 0 4px 10px rgba(15, 23, 42, .18);
    transition: transform .09s, box-shadow .09s;
}
a.jl-cahier:hover, a.cahier:hover { transform: translateY(-3px) rotate(-.5deg); box-shadow: 0 10px 22px rgba(15, 23, 42, .26); }
a.jl-cahier:focus-visible, a.cahier:focus-visible { outline: 3px solid #93c5fd; outline-offset: 2px; }
/* La spirale : une reliure dessinée en dégradé radial, répétée sur la hauteur. */
.jl-cahier::before, .cahier::before {
    content: ""; position: absolute; left: .5rem; top: .9rem; bottom: .9rem; width: 12px;
    background-image: radial-gradient(circle at 6px 7px, #f8fafc 2.2px, #334155 2.6px 4px, transparent 4.5px);
    background-size: 12px 15px; background-repeat: repeat-y;
}
/* L'étiquette blanche collée sur la couverture : le nom de la classe. */
.jl-etiq, .cahier-etiq {
    background: #fff; border-radius: 9px; padding: .55rem 1rem .5rem; text-align: center; min-width: 68%;
    border: 1px solid rgba(15, 23, 42, .10); box-shadow: 0 1px 3px rgba(15, 23, 42, .28);
}
.jl-etiq .jl-nom, .cahier-etiq .cahier-nom {
    display: block; font-family: "Baloo 2", sans-serif; font-size: 1.5rem; font-weight: 800;
    color: #0f172a; line-height: 1.05;
}
.jl-etiq .jl-eff, .cahier-etiq .cahier-sous { display: block; font-size: .76rem; color: #64748b; margin-top: .1rem; }
.jl-count { margin-top: auto; display: flex; flex-direction: column; align-items: center; gap: .15rem; }
.jl-count .jl-n {
    display: flex; align-items: center; justify-content: center; width: 50px; height: 50px; border-radius: 50%;
    background: #fff; color: #0f172a; font-weight: 800; font-size: 1.3rem; box-shadow: 0 2px 6px rgba(15, 23, 42, .30);
}
.jl-count .jl-lab { font-size: .7rem; font-weight: 700; color: rgba(255, 255, 255, .95); text-transform: uppercase; letter-spacing: .05em; }
.jl-pastille, .cahier-ruban {
    position: absolute; top: .55rem; right: .55rem; background: #fef9c3; color: #854d0e; border-radius: 999px;
    padding: .2rem .55rem; font-size: .72rem; font-weight: 800; box-shadow: 0 1px 3px rgba(15, 23, 42, .30);
}

/* ── CAHIER-REGISTRE — la variante « dos toilé, étiquette d'écolier » ────────
   L'autre cahier du produit : bande de toile à la place de la spirale, étiquette crème à
   double filet portant « Classe de Madame Vinciane », pastille du code, et un mot en pied
   qui dit ce qu'on ouvre (« Registre », « Dossiers »). Employé par Présences ▸ Registres et
   par Dossiers élèves — un seul jeu de règles pour les deux.                              */
.rd-tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 1.2rem;
            margin-top: .9rem; align-content: start; }
.rd-cahier {
    position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: .55rem; min-height: 220px; border-radius: 6px 14px 14px 6px; padding: 1.2rem 1rem 1.1rem 2.2rem;
    text-decoration: none;
    background-image: linear-gradient(160deg, rgba(255, 255, 255, .16), rgba(0, 0, 0, .12));
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .14), 0 4px 10px rgba(15, 23, 42, .18);
    transition: transform .09s, box-shadow .09s;
}
a.rd-cahier:hover { transform: translateY(-3px) rotate(.5deg); box-shadow: 0 10px 22px rgba(15, 23, 42, .26); }
a.rd-cahier:focus-visible { outline: 3px solid #93c5fd; outline-offset: 2px; }
/* Dos toilé : bande sombre continue + filet clair, à la place de la spirale. */
.rd-cahier::before {
    content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 16px;
    background: rgba(15, 23, 42, .30); border-radius: 6px 0 0 6px;
    box-shadow: inset -2px 0 0 rgba(255, 255, 255, .25);
}
.rd-etiq {
    background: #fffdf5; border-radius: 8px; padding: .7rem .9rem .6rem; text-align: center; width: 82%;
    border: 1px solid rgba(15, 23, 42, .14);
    box-shadow: 0 1px 3px rgba(15, 23, 42, .28), inset 0 0 0 3px #fffdf5, inset 0 0 0 4px rgba(15, 23, 42, .14);
}
.rd-etiq .rd-titu { display: block; font-family: "Baloo 2", sans-serif; font-size: 1.05rem; font-weight: 800; color: #0f172a; line-height: 1.15; }
.rd-etiq .rd-eff { display: block; font-size: .76rem; color: #64748b; margin-top: .15rem; }
.rd-code {
    display: inline-flex; align-items: center; justify-content: center; min-width: 56px; padding: .25rem .6rem;
    border-radius: 999px; background: #fff; color: #0f172a; font-family: "Baloo 2", sans-serif;
    font-weight: 800; font-size: 1.05rem; box-shadow: 0 2px 6px rgba(15, 23, 42, .30);
}
.rd-lab { font-size: .7rem; font-weight: 700; color: rgba(255, 255, 255, .95); text-transform: uppercase; letter-spacing: .05em; }
/* MON cahier : cerclé de blanc et de la couleur du produit, posé en avant. */
.rd-cahier.is-mienne {
    box-shadow: inset 0 0 0 3px rgba(255, 255, 255, .95), 0 0 0 3px var(--primary), 0 10px 22px rgba(15, 23, 42, .30);
    transform: translateY(-3px);
}
.rd-cahier.is-vide .rd-code { color: #64748b; }

/* Le titulaire, écrit sur la couverture — en blanc, la couverture étant colorée. */
.cahier-tit {
    margin-top: auto; display: flex; align-items: center; gap: .35rem; max-width: 100%;
    font-size: .82rem; font-weight: 700; color: rgba(255, 255, 255, .97);
    text-shadow: 0 1px 2px rgba(15, 23, 42, .35);
    overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
}
.cahier-tit .avatar { box-shadow: 0 1px 3px rgba(15, 23, 42, .35); flex: none; }
/* ⚠️ L'ellipsis doit vivre sur le SPAN du nom, pas sur le conteneur flex : un nom long
   (« Mme Remouchamps ») était sinon coupé net, sans les points de suspension. */
.cahier-tit > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* MON cahier : cerclé de blanc, halo de la couleur du produit, posé en avant. */
.cahier.is-mienne {
    box-shadow: inset 0 0 0 3px rgba(255, 255, 255, .95), 0 0 0 3px var(--primary), 0 10px 22px rgba(15, 23, 42, .30);
    transform: translateY(-3px);
}
/* « Ma classe » prend la place du nom du titulaire — c'est la même ligne, pas un ajout. */
.cahier-tit.is-moi { font-size: .9rem; font-weight: 800; letter-spacing: .01em; }
/* Le cahier « sans classe » : une couverture grise, volontairement en retrait. */
.cahier.is-vide { opacity: .92; }

/* ── Barre de compteurs du dossier élève ─────────────────────────────────────
   Les cartes qui MÈNENT quelque part (absences → registre annuel, incidents → onglet ⚖️)
   sont des liens : elles n'en prennent ni la couleur ni le soulignement, sinon la barre vire
   au bleu souligné et ne se lit plus comme une rangée de chiffres.                        */
a.disc-kpi { text-decoration: none; color: inherit; }
a.disc-kpi:hover { border-color: var(--primary); box-shadow: 0 4px 12px rgba(109, 94, 252, .12); }
a.disc-kpi:hover .disc-kpi-l { text-decoration: underline; }
/* Tuiles qui FILTRENT une liste (Présences ▸ Suivi) : la tuile active se voit — bordure, fond ET mention
   « filtre actif » écrite —, et une tuile à zéro n'est pas un lien : il n'y a rien à filtrer. */
a.disc-kpi.is-active { border-color: var(--primary); background: var(--primary-soft); box-shadow: inset 0 0 0 1px var(--primary); }
.disc-kpi.is-vide { opacity: .6; }
/* ── Fil d'actions (Présences ▸ Suivi) ───────────────────────────────────────
   Une étape par palier, de haut en bas, et un geste par étape. La pastille de gauche REDIT ce que
   le badge écrit déjà ; elle ne porte jamais l'information seule.
   ⚠️ Classes PROPRES au fil : ne pas repeindre `.stepper`, partagé avec l'assistant d'import. */
.fil { list-style: none; margin: .4rem 0 0; padding: 0; border-left: 2px solid var(--line); }
.fil-etape { position: relative; padding: 0 0 1.4rem 1.4rem; }
.fil-etape::before {
    content: ''; position: absolute; left: -8px; top: .35rem; width: 14px; height: 14px;
    border-radius: 50%; background: var(--line); border: 2px solid var(--card);
}
.fil-etape.is-faite::before, .fil-etape.is-rien-a-faire::before { background: #157a4b; }
.fil-etape.is-a-faire::before { background: #c0392b; }
.fil-etape.is-depassee::before { background: #b45309; }
.fil-etape.is-en-attente::before { background: var(--muted); }
.fil-seuil { font-size: .78rem; font-weight: 800; color: var(--muted); text-transform: uppercase; letter-spacing: .02em; }
.fil-titre { font-weight: 700; margin: .1rem 0 .2rem; }
.fil-quoi { margin: 0; font-size: .9rem; }
.fil-etat { margin-top: .45rem; display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.fil-preuve { font-size: .85rem; margin-top: .35rem; }
.fil-etape.is-pas-atteinte .fil-titre, .fil-etape.is-pas-atteinte .fil-seuil { color: var(--muted); }
/* ── LE TIROIR DU COURRIER : la lettre d'abord ────────────────────────────────
   ⚠️⚠️ La LETTRE occupe toute la modale (demande de Philippe, 20/09) : c'est elle qu'on vient lire
   avant d'envoyer, pas les réglages. Panneau large, PDF à gauche sur toute la hauteur, destinataires
   et sorties dans la colonne de droite. */
.drawer-panel.drawer-large { width: min(1180px, 96vw); }
.drawer-large .drawer-body { display: grid; grid-template-columns: 1.6fr 1fr; gap: 1.2rem;
    align-items: stretch; padding: 1rem 1.2rem; }
@media (max-width: 900px) {
    .drawer-panel.drawer-large { width: 96vw; }
    .drawer-large .drawer-body { grid-template-columns: 1fr; }
}
/* L'aperçu occupe la colonne de gauche, sur toute la hauteur du tiroir. */
.apercu-lettre { margin: 0; display: flex; flex-direction: column; min-height: 0; }
.apercu-lettre iframe { display: block; width: 100%; flex: 1 1 auto; min-height: min(70vh, 760px);
    border: 1px solid var(--line); border-radius: 10px; background: var(--bg); }
.apercu-lettre p { margin: .35rem 0 0; font-size: .82rem; flex: none; }
/* Les trois sorties : c'est le clic qui clôt l'étape, il doit se voir. */
.sorties-boutons { display: flex; gap: .5rem; flex-wrap: wrap; }
.drawer-large .sorties-boutons { flex-direction: column; }
.drawer-large .sorties-boutons .btn { width: 100%; }

/* ── LE PARCOURS GUIDÉ de la fiche (Présences ▸ Suivi) ───────────────────────
   Deux cartes : l'étape actuelle à gauche, la suivante à droite. La ligne du temps se voyage.
   ⚠️⚠️ ROUGE = à faire · VERT = fait · GRIS = pas atteint. Le fond porte la couleur, mais l'état est
   toujours ÉCRIT : la couleur seule ne dit rien (demande de Philippe, 20/09). */
.parcours { margin-bottom: 1.4rem; }

/* La ligne du temps : quatre étapes cliquables, colorées par leur état. */
.rail { list-style: none; margin: .2rem 0 1.4rem; padding: 0; display: grid;
    grid-auto-flow: column; grid-auto-columns: 1fr; align-items: start; }
.rail-etape { position: relative; min-width: 0; overflow: hidden; text-align: center; }
.rail-etape > a { display: block; padding: .35rem .4rem .5rem; text-decoration: none; color: inherit;
    border-radius: 10px; }
.rail-etape > a:hover { background: var(--bg); }
.rail-etape > a:focus-visible { outline: 2px solid var(--primary); outline-offset: -3px; }
/* Les trois tons, et rien d'autre. */
.rail-etape.est-fait { --ton: #157a4b; --ton-doux: #e6f7ee; }
.rail-etape.est-du { --ton: #c0392b; --ton-doux: #fdecea; }
.rail-etape.est-gris { --ton: var(--muted); --ton-doux: var(--bg); }
/* Fait, et derrière nous : le vert reste — c'est en ordre — mais il s'efface pour ne pas peser
   autant que l'étape où l'on en est. */
.rail-etape.est-fait-passe { --ton: #6f9e89; --ton-doux: #f2f8f5; }
.rail-etape.est-fait-passe .rail-nom { font-weight: 600; }
.rail-pastille { position: relative; display: inline-grid; place-items: center; width: 30px; height: 30px;
    border-radius: 50%; background: var(--ton-doux); border: 2px solid var(--ton); color: var(--ton);
    font-size: .78rem; font-weight: 800; }
/* Le trait part du BORD de la pastille, à 50 % de sa hauteur : il passe par son centre quoi qu'il arrive. */
.rail-pastille::before, .rail-pastille::after { content: ''; position: absolute; top: 50%; margin-top: -1px;
    height: 2px; width: 100vw; background: var(--line); }
.rail-pastille::before { right: calc(50% + 17px); }
.rail-pastille::after { left: calc(50% + 17px); }
.rail-etape:first-child .rail-pastille::before, .rail-etape:last-child .rail-pastille::after { display: none; }
.rail-nom { display: block; margin-top: .3rem; font-size: .84rem; font-weight: 700; color: var(--ton);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rail-etat { display: block; font-size: .72rem; color: var(--muted);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rail-etape.est-vue > a { background: var(--ton-doux); box-shadow: inset 0 0 0 1px var(--ton); }

/* Les deux cartes. */
.parcours-corps { display: grid; grid-template-columns: 1.25fr 1fr; gap: 1rem; align-items: start; }
@media (max-width: 860px) { .parcours-corps { grid-template-columns: 1fr; } }
.etape { border: 1px solid var(--line); border-radius: 12px; padding: .9rem 1rem; min-width: 0; }
.etape.est-du { border-color: #f0c0bc; background: #fff7f6; }
.etape.est-fait { border-color: #bfe3d2; background: #f2fbf7; }
.etape.est-fait-passe { border-color: #d8e8e0; background: #f7fbf9; }
.etape.est-fait-passe .etape-nom { color: #37544a; }
.etape.est-gris { background: var(--bg); }
.etape-tete { display: flex; align-items: center; justify-content: space-between; gap: .5rem;
    flex-wrap: wrap; margin-bottom: .4rem; }
.etape-role { font-size: .74rem; text-transform: uppercase; letter-spacing: .05em; color: var(--muted); font-weight: 700; }
.etape-nom { margin: 0 0 .15rem; font-size: 1.02rem; }
.etape-seuil { margin: 0 0 .5rem; font-size: .8rem; color: var(--muted); }
.etape-etat { margin: 0 0 .5rem; display: flex; align-items: center; gap: .45rem; flex-wrap: wrap; font-size: .9rem; }
.etape-quoi { margin: 0 0 .7rem; font-size: .9rem; color: var(--ink); }
.etape-preuve { margin: .3rem 0 .6rem; font-size: .85rem; }
/* Ce qui se fait SANS le directeur, dans le cadre de son étape : un fait, pas une tâche. */
.etape-info { margin: 0 0 .7rem; padding: .5rem .65rem; border-radius: 8px; background: var(--card);
    border: 1px dashed var(--line); font-size: .85rem; }
.etape-info .acteur { margin-right: .35rem; }
.etape .btn { margin-top: .2rem; }

/* Les six démarches, DANS la carte de l'axe 1. */
/* ⚠️ Le parcours ne LISTE plus les six démarches (20/09) : il en donne le compte et renvoie à la
   carte de l'axe 1, seule à les écrire. Les règles de liste sont parties avec elle. */
.etape-demarches { border-top: 1px solid var(--line); padding-top: .6rem; margin-bottom: .7rem; }
.etape-demarches-n { margin: 0 0 .35rem; font-size: .88rem; }
.etape-demarches-n strong { font-size: 1.2rem; font-weight: 800; color: #c2410c; }
/* ⚠️ La barre ACCOMPAGNE le compte, elle ne le remplace pas : « 3 sur 7 » reste écrit au-dessus.
   Un suivi peut être bien mené avec deux démarches — une barre seule se lirait comme une note. */
.etape-barre { height: 6px; border-radius: 999px; background: var(--line); overflow: hidden; margin-bottom: .55rem; }
.etape-barre > span { display: block; height: 100%; background: #c2410c; border-radius: 999px; }
/* La checklist de l'étape : une coche, le libellé qui mène AU GESTE, ce qu'il a donné à côté. */
.etape-liste { list-style: none; margin: 0; padding: 0; display: grid; gap: .3rem; font-size: .9rem; }
.etape-liste li { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: .45rem; align-items: baseline; }
/* ⚠️ La ligne répondue s'estompe, mais son LIEN garde l'encre du texte : il reste cliquable, donc il
   doit rester lisible — c'est par lui qu'on ajoute une deuxième convocation ou qu'on revient sur un
   point écarté (demande du 23/09). */
.etape-liste li.est-faite { color: var(--muted); }
.etape-liste li.est-faite a { color: var(--ink); }
/* ⚠️ Le libellé d'une démarche FAITE n'est pas barré : elle reste une information qu'on vient lire
   (qui est le pilote, quand la convocation est partie), pas une ligne à rayer. */
.etape-coche { font-size: .9rem; line-height: 1.4; }
.etape-liste a { color: inherit; text-decoration-color: var(--muted); text-underline-offset: 2px; }
.etape-liste a:hover { color: var(--primary); text-decoration-color: currentColor; }
/* La signature d'une ligne du journal : qui, quand, et ce qui a été corrigé depuis. Le rôle et la
   correction se lisent sans peser autant que le nom — mais ils restent lisibles, pas décoratifs. */
/* ⚠️ La signature s'aligne sur sa pastille : `inline-flex` et `align-items: center`, sinon l'avatar
   dépasse de la ligne de texte et la ligne saute d'un demi-caractère. */
.sig { display: inline-flex; align-items: center; gap: .35rem; font-size: .82rem; }
.sig-nom { font-weight: 600; color: var(--ink); }
.sig-role { opacity: .8; }
/* ⚠️ La correction ne se cache pas : elle dit au lecteur qu'il ne lit pas le premier jet. */
.sig-corrige { font-style: italic; }
/* ⚠️ « Pas nécessaire » vit DANS la modale du geste (29/09) : une zone à part, sous les champs, pour
   qu'on ne la confonde pas avec ce qu'on remplit — et son bouton est dans le pied, après « Enregistrer ». */
/* ── L'APERÇU DE LA LETTRE, DANS LA MODALE ───────────────────────────────────
   ⚠️ Une hauteur FIXE et un cadre qui défile : la lettre fait une page A4, et la laisser s'étendre
   repousserait les champs et le bouton d'envoi hors de l'écran — on ne verrait plus quoi faire. */
.lettre-apercu { margin-bottom: .9rem; }
.lettre-apercu-tete { display: flex; align-items: baseline; gap: .6rem; flex-wrap: wrap; margin-bottom: .5rem; }
.lettre-apercu-tete .muted { flex: 1; min-width: 12rem; font-size: .82rem; }
.lettre-apercu-cadre {
    display: block; width: 100%; height: 340px; border: 1px solid var(--line);
    border-radius: var(--radius-sm, 10px); background: #fff;
}
/* ── Le choix d'un créneau, côté PARENT ──────────────────────────────────────
   ⚠️ La ligne ENTIÈRE est cliquable (`<label>` autour de l'`<input>`) : sur un téléphone, viser un
   rond de 16 px échoue une fois sur trois. Hauteur confortable, et l'état choisi se voit. */
.cr-choix { display: grid; gap: .5rem; margin: 1rem 0; }
.cr-option { display: flex; align-items: center; gap: .7rem; min-height: 52px; padding: .7rem .9rem;
    border: 1px solid var(--line); border-radius: 12px; background: #fff; cursor: pointer; }
.cr-option:hover { border-color: var(--primary); }
.cr-option.est-choisi { border-color: var(--primary); background: var(--primary-soft); }
.cr-option input { width: 20px; height: 20px; flex: none; accent-color: var(--primary); }
.cr-quand { font-weight: 600; }
.cr-note { margin-top: .9rem; font-size: .85rem; }
/* ⚠️ Le bouton porte la MÊME hauteur de cible que les cartes au-dessus (mesuré à 390 px : il
   tombait à 35 px, contre 74 px pour un créneau). C'est le seul geste de la page, et il se fait
   au pouce sur un téléphone, souvent d'une main. */
.cr-valider { min-height: 52px; font-size: 1rem; }

/* Les trois créneaux : un rang, une date, une heure — alignés pour se comparer d'un coup d'œil. */
.creneaux-zone > .muted { margin: .15rem 0 .5rem; font-size: .82rem; }
.creneau-ligne { display: grid; grid-template-columns: 1.4rem minmax(0, 1fr) 7.5rem; gap: .45rem; align-items: center; margin-bottom: .4rem; }
.creneau-rang { color: var(--muted); font-size: .82rem; font-weight: 700; text-align: center; }
@media (max-width: 720px) { .creneau-ligne { grid-template-columns: 1.4rem minmax(0, 1fr); } }
.ecart-zone { border-top: 1px dashed var(--line); padding-top: .8rem; margin-top: .3rem; }
.ecart-zone > .muted { margin: .2rem 0 .6rem; font-size: .82rem; }

/* La pastille d'ACTEUR : qui agit, écrit noir sur blanc. */
.acteur { display: inline-block; padding: .08rem .5rem; border-radius: 999px; font-size: .74rem;
    font-weight: 700; border: 1px solid var(--line); background: var(--card); color: var(--muted); }
.acteur-ecole { border-color: #cbd5e1; color: #334155; }
.acteur-administration { border-color: #bfd4ea; background: #eef5fc; color: #1d4e79; }
.acteur-cpms { border-color: #cdbde8; background: #f4effb; color: #5b3a96; }

/* Ce qui reste à faire ou à savoir, sous les deux cartes : des lignes, pas des cartes. */
.aussi { list-style: none; margin: 1rem 0 0; padding: 0; display: grid; gap: .4rem; font-size: .9rem; }
.aussi li { display: grid; grid-template-columns: auto 1fr; gap: .5rem; align-items: baseline; }

/* ⚠️ Les cartes du dossier respirent : empilées sans écart, elles formaient un mur (20/09). */
.content > .page-with-aside .page-main > .card,
.page-main > section.card { margin-bottom: 1.1rem; }

/* ── L'ESCALIER du suivi (Présences ▸ Suivi) ─────────────────────────────────
   Une marche par étape du fil, dans l'ordre, avec son seuil ; à gauche, détaché, ce qui est dû
   maintenant. Il remplace les tuiles, qui mélangeaient deux grammaires (19/09).
   ⚠️ La couleur ne porte rien seule : le seuil, le nombre et le nom restent écrits. */
.suivi-tete { display: flex; gap: 1rem; align-items: stretch; margin-bottom: 1rem; flex-wrap: wrap; }
.suivi-du {
    display: flex; align-items: center; gap: .9rem; text-decoration: none; color: inherit;
    background: #fff5f5; border: 1px solid #f3c6c6; border-left: 4px solid #c0392b;
    border-radius: var(--radius); padding: .85rem 1.1rem; min-width: 210px;
}
.suivi-du.is-vide { background: var(--card); border-color: var(--line); border-left-color: var(--line); }
.suivi-du.is-vide .suivi-du-n, .suivi-du.is-vide .suivi-du-l { color: var(--muted); }
.suivi-du-n { font-size: 1.9rem; font-weight: 800; line-height: 1; color: #c0392b; }
.suivi-du-l { display: block; font-size: .82rem; font-weight: 700; color: #8f2f24; text-transform: uppercase; letter-spacing: .02em; }
.suivi-du-s { display: block; font-size: .78rem; color: var(--muted); }

/*
  ⚠️⚠️ **DES COLONNES STRICTEMENT ÉGALES.** En flex, `flex: 1` ne suffit pas : un élément flex ne
  descend jamais sous la largeur de son contenu (`min-width: auto`), si bien que « Relais CPMS »
  prenait plus de place que « Alerte » et que les pastilles n'étaient plus équidistantes. La grille,
  elle, découpe la largeur en parts égales quoi qu'il y ait dedans.
*/
.suivi-echelle {
    list-style: none; margin: 0; padding: .55rem 0 .6rem; display: grid; flex: 1;
    grid-auto-flow: column; grid-auto-columns: 1fr; align-items: start;
    background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
}
/* `min-width: 0` : sans lui, un libellé long rendrait sa colonne plus large que les autres.
   `overflow: hidden` coupe les segments du trait au bord exact de la colonne. */
.suivi-marche { position: relative; min-width: 0; overflow: hidden; }
.suivi-marche > a, .suivi-marche > span { display: block; text-decoration: none; color: inherit; padding: .1rem .5rem .1rem; text-align: center; border-radius: 10px; }
.suivi-marche[data-ton="alerte"], .suivi-palier[data-ton="alerte"] { --ton: #157a4b; --ton-doux: #e6f7ee; }
.suivi-marche[data-ton="courrier"], .suivi-palier[data-ton="courrier"] { --ton: #b45309; --ton-doux: #fff4e5; }
.suivi-marche[data-ton="axe1"], .suivi-palier[data-ton="axe1"] { --ton: #c2410c; --ton-doux: #fff1e8; }
.suivi-marche[data-ton="evaluation"], .suivi-palier[data-ton="evaluation"] { --ton: #b91c1c; --ton-doux: #fdecec; }
.suivi-marche[data-ton="relais_cpms"], .suivi-palier[data-ton="relais_cpms"] { --ton: #8f1414; --ton-doux: #fbe6e6; }
.suivi-seuil {
    position: relative; display: inline-grid; place-items: center; width: 26px; height: 26px; margin-bottom: .3rem;
    border-radius: 50%; background: var(--ton-doux); border: 2px solid var(--ton);
    font-size: .74rem; font-weight: 800; color: var(--ton);
}
/*
  ⚠️ Le trait part du BORD de la pastille, à `top: 50%` de la pastille elle-même : il passe donc
  exactement par son centre quelle que soit la hauteur du contenu au-dessus. Posé sur la marche, il
  dépendait d'un décalage en dur — et passait au-dessus des pastilles.
  `100vw` déborde volontairement : `overflow: hidden` sur la marche le coupe au bord de la colonne.
*/
.suivi-seuil::before, .suivi-seuil::after {
    content: ''; position: absolute; top: 50%; margin-top: -1px; height: 2px; width: 100vw; background: var(--line);
}
.suivi-seuil::before { right: calc(50% + 15px); }
.suivi-seuil::after { left: calc(50% + 15px); }
.suivi-marche:first-child .suivi-seuil::before, .suivi-marche:last-child .suivi-seuil::after { display: none; }
.suivi-n { display: block; font-size: 1.25rem; font-weight: 800; line-height: 1.1; color: var(--ton); }
.suivi-n.is-zero { color: var(--muted); font-weight: 600; }
/* Une seule ligne : un libellé replié décalerait le bas des marches les unes par rapport aux autres. */
.suivi-l { display: block; font-size: .78rem; color: var(--muted); line-height: 1.25; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.suivi-marche > a:hover { background: var(--ton-doux); }
.suivi-marche.is-active > a { background: var(--ton-doux); box-shadow: inset 0 0 0 1px var(--ton); }
/* ⚠️ `overflow: hidden` sur la marche (il coupe les segments du trait) rognait l'anneau de focus, qui se
   dessine À L'EXTÉRIEUR de l'ancre : on le ramène à l'intérieur. */
.suivi-marche > a:focus-visible { outline: 2px solid var(--ton); outline-offset: -3px; border-radius: 10px; }

/* Les deux filtres qui ne sont pas des marches : des puces, dans la barre. */
.suivi-puces { display: flex; gap: .5rem; align-items: center; margin-left: auto; }
.puce {
    display: inline-flex; align-items: center; gap: .35rem; text-decoration: none; font-size: .85rem; font-weight: 600;
    border: 1px solid var(--line); border-radius: 999px; padding: .25rem .7rem; color: var(--ink); background: var(--card);
}
.puce:hover { border-color: var(--primary); }
.puce.is-active { border-color: var(--primary); background: var(--primary-soft); }
.puce.is-vide { color: var(--muted); }

/* ── Le BANDEAU FIXE du suivi (demande de Philippe, 22/09) ───────────────────
   L'escalier compte les paliers, la barre les filtre : les deux restent sous la main pendant que les
   grids défilent.
   ⚠️ C'est `.content` qui défile (`overflow-y: auto`), pas le document : le sticky s'accroche à LUI,
   et `top: 0` colle donc au haut de la zone de contenu, sous la barre de l'application.
   ⚠️ Fond OPAQUE obligatoire — les lignes des grids passent derrière. */
.suivi-fixe {
    position: sticky; top: 0; z-index: 12;
    background: var(--bg); padding: .25rem 0 2.1rem;
}
.suivi-fixe .suivi-tete { margin-bottom: .7rem; }
/*
  ⚠️⚠️ **L'AIR SOUS LES FILTRES EST UN PADDING, JAMAIS UNE MARGE.** Une marge n'est pas peinte : les
  lignes des grids défilaient DEDANS, réapparaissant entre la barre de filtres et le premier cadre. Et
  la marge du dernier enfant fusionnait avec celle du bandeau, si bien que l'écart n'augmentait pas
  quand on l'augmentait. Tout l'écart est donc dans la boîte, couvert par son fond.
*/
.suivi-fixe .filters { margin-bottom: 0; }
/* ⚠️ Des champs plus étroits QUE PARTOUT AILLEURS, et pour une raison mesurée : à 13rem, la barre se
   replie sur deux lignes dès 1340 px de large et le bandeau passe de 182 à 225 px — 43 px pris aux
   grids, sur l'écran le plus répandu. Trois listes courtes n'en ont pas besoin. */
.suivi-fixe .filters .field-edit { min-width: 10rem; }
/*
  ⚠️⚠️ **LE PADDING DU CONTENEUR N'EST PAS UNE ZONE MORTE.** `.content` a 1.8rem de padding, et le
  contenu DÉFILE DEDANS : collé à `top: 0`, le bandeau laissait passer au-dessus de lui une bande de
  29 px où l'on voyait en permanence la moitié d'une ligne de grid flotter par-dessus l'escalier
  (mesuré : `elementFromPoint` y rendait un `<td>`). Ce prolongement la couvre, du même fond.
*/
.suivi-fixe::before {
    content: ''; position: absolute; left: 0; right: 0; bottom: 100%; height: 2rem;
    background: var(--bg);
}
/* ⚠️ Ce prolongement déborde VERS LE HAUT, et il est opaque : il mordait de 10 px sur le bas du
   sous-titre de la page (« … selon notre registre », lettres coupées net, mesuré). L'en-tête de cet
   écran-là lui laisse donc la place — elle défile de toute façon dès qu'on descend. */
.content:has(.suivi-fixe) .page-head { padding-bottom: 1rem; }
/* Une ombre courte SOUS le bandeau : elle dit que du contenu passe dessous, sans trait ni cadre. */
.suivi-fixe::after {
    content: ''; position: absolute; left: 0; right: 0; top: 100%; height: 12px; pointer-events: none;
    background: linear-gradient(rgba(15, 23, 42, .08), rgba(15, 23, 42, 0));
}
/*
  ⚠️ **SOUS 900 px, LE BANDEAU NE COLLE PAS** — et c'est voulu : `body.app-fit` relâche la hauteur,
  `.content` ne défile plus, c'est le document. `position: sticky` reste déclaré mais ne s'accroche à
  rien. Sur un écran étroit, un bandeau de 268 px mangerait de toute façon la moitié de la page.
*/

/* ── UN GRID PAR PALIER ──────────────────────────────────────────────────────
   L'en-tête porte le seuil (même pastille que la marche de l'escalier), le nom de l'étape et le
   nombre d'élèves. Le ton vient de `data-ton`, partagé avec l'escalier. */
.suivi-palier-tete { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; margin-bottom: .7rem; }
.suivi-palier-tete h2 { margin: 0; font-size: 1.02rem; color: var(--ton, var(--ink)); }
.suivi-palier-seuil {
    display: inline-flex; align-items: center; justify-content: center; min-width: 2rem; height: 2rem;
    border-radius: 999px; background: var(--ton-doux, var(--bg)); color: var(--ton, var(--ink));
    border: 1px solid var(--ton, var(--line)); font-weight: 800; font-size: .95rem; padding-inline: .4rem;
}
.suivi-palier-s { color: var(--muted); font-size: .82rem; }
.suivi-palier-tete .badge { margin-left: auto; }
/* ⚠️ Dix lignes par grid : le cadre n'a plus à défiler EN INTERNE (`.page-with-aside .table-wrap`
   plafonne à `100vh - 21rem`), et son en-tête n'a plus à être figé — collé au haut de `.content`, il
   irait se glisser DERRIÈRE le bandeau fixe. C'est la page qui descend, le bandeau qui reste. */
.suivi-palier .table-wrap { max-height: none; }
.suivi-palier .table-wrap thead th { position: static; }
/* ⚠️ Un filet, pas un confort : `.table-wrap` coupe en X sans prévenir (la colonne d'action, donc le
   lien vers la fiche, disparaît sous 1150 px). Une barre vaut mieux qu'une colonne effacée en silence. */
.suivi-palier .table-wrap { overflow-x: auto; }
/*
  ⚠️ **LE FOCUS CLAVIER PASSE DERRIÈRE LE BANDEAU.** Chrome sait ajuster son défilement au collant,
  pas les autres : sans cette marge, une ligne atteinte au clavier atterrit jusqu'à 254 px sous le
  bandeau, anneau de focus compris. 17rem couvre la hauteur maximale mesurée du bandeau (268 px, à
  920 px de large), en Chrome comme avec un défilement naïf.
*/
.suivi-palier tr.epi-main, .suivi-palier .eleve-lien { scroll-margin-top: 17rem; }
/* La façon de lire un grid, sous le dernier : une seule fois pour tout l'écran. */
.suivi-aide { margin: .2rem 0 1.1rem; font-size: .85rem; }

/* ── Le grid du suivi : RIEN SUR DEUX LIGNES (demande de Philippe, 19/09) ─────
   ⚠️ `min-width: 0` sur le nom : sans lui, un enfant flex refuse de descendre sous la largeur de son
   texte — il se REPLIE au lieu de s'abréger, et l'ellipse ne sert à rien. */
/* ⚠️ Les lignes PRINCIPALES seulement : les sous-lignes dépliées portent des phrases entières
   (« Seuil de 9 demi-jours atteint : le rappel de la loi est envoyé par… ») qui doivent se replier,
   sinon elles élargissent la table de plusieurs centaines de pixels — et `.table-wrap` les coupe. */
.suivi-grid tr.epi-main td { white-space: nowrap; }
/* ⚠️⚠️ Six colonnes qui ne se replient pas, sur un portable de 1280 : c'est LA COLONNE DU NOM qui
   absorbe tout l'espace restant (`width: 100%` + `max-width: 0`, la recette des tableaux élastiques)
   et qui s'abrège quand il en manque. Sans elle, un état long — « Non faite, dépassée depuis le
   12/01 » — pousserait la colonne d'action hors du cadre, que `.table-wrap` coupe sans prévenir. */
.suivi-grid { width: 100%; }
.suivi-grid th, .suivi-grid td { padding-inline: .55rem; }
.suivi-grid th:first-child, .suivi-grid td.col-elv { width: 100%; max-width: 0; }
.suivi-grid td.col-elv .cell-name { flex-wrap: nowrap; min-width: 0; }
/* ⚠️ Un PLANCHER sous la colonne élastique : sans lui, elle se comprime jusqu'à ZÉRO (mesuré à
   1150 px avec un nom composé et un code de classe long) et le lien vers la fiche disparaît, alors
   que rien ne déborde — donc aucune barre de défilement pour aller le chercher. Le plancher force
   la table à déborder, et `overflow-x: auto` rend enfin la colonne atteignable. */
.suivi-grid td.col-elv .cell-name, .suivi-grid th:first-child { min-width: 10rem; }
.suivi-grid td.col-elv .eleve-lien { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Le compteur commence où commence son titre. */
.suivi-grid th.col-compteur, .suivi-grid td.col-compteur { text-align: left; }
.suivi-grid td.col-compteur .ve-gauge { margin-left: 0; vertical-align: middle; }
/* « Nouveau » se pose à côté du COMPTEUR : c'est le palier qui est neuf, pas l'élève. */
.suivi-grid .neuf {
    display: inline-block; vertical-align: middle; margin-left: .45rem;
    background: #fff4e5; color: #b45309; border: 1px solid #f0c98a; border-radius: 999px;
    padding: .05rem .45rem; font-size: .7rem; font-weight: 700; white-space: nowrap;
}
/* L'état tient dans UNE pastille qui porte sa date, calée à droite : les dates s'alignent. */
.suivi-grid th.col-etat, .suivi-grid td.col-etat { text-align: right; }
.suivi-grid td.col-etat .badge { white-space: nowrap; }
.suivi-grid td.col-etat .quand { font-variant-numeric: tabular-nums; font-weight: 400; opacity: .85; margin-left: .25rem; }
/* Une tuile qui porte du TEXTE et non un nombre : deux lignes au plus, le reste au survol — sinon une
   phrase de quatre lignes déséquilibre toute la rangée d'indicateurs. */
.disc-kpi-texte {
    font-size: 1rem; line-height: 1.25;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.dossier-kpis { margin-bottom: 1rem; }
/* Le droit à l'image : un mot, pas un nombre — même gabarit, taille de texte adaptée. */
.kpi-image .kpi-mot { font-size: 1.15rem; }
.kpi-image.is-non .disc-kpi-ico { filter: grayscale(.15); }

/* ── Carte Météo du tableau de bord ──────────────────────────────────────────
   Un chiffre qu'on lit de loin, le ciel en un mot, et le reste en gris : c'est une carte
   d'agrément, elle ne doit pas peser plus lourd que les cartes de travail voisines. */
.meteo-corps { min-height: 3.4rem; }
.meteo-ligne { display: flex; align-items: center; gap: .8rem; }
.meteo-emoji { font-size: 2.1rem; line-height: 1; }
.meteo-temp { font-size: 1.6rem; font-weight: 800; line-height: 1.05; color: var(--ink, #0f172a); }
.meteo-ciel { font-size: .9rem; color: #475569; }
.meteo-detail { margin: .5rem 0 0; font-size: .82rem; }
.meteo-attente { margin: 0; font-size: .85rem; }

/* En-tête : le titre, et le ⚙️ des réglages poussé à droite (révélé au survol de la carte,
   comme les barres d'action ailleurs — il ne doit pas concurrencer le contenu). */
.meteo-tete { display: flex; align-items: center; justify-content: space-between; gap: .5rem; }
.meteo-tete .card-title { margin: 0; }
/* ⚠️ Discret, mais JAMAIS invisible : caché jusqu'au survol, il serait inatteignable au doigt
   (une tablette n'a pas de survol) et la personne ne saurait pas que la carte se règle. */
.meteo-reglages-btn { border: 0; background: none; padding: .1rem .25rem; border-radius: 6px;
    font-size: .95rem; line-height: 1; cursor: pointer; opacity: .45; transition: opacity .15s; }
.meteo-card:hover .meteo-reglages-btn,
.meteo-reglages-btn:focus-visible,
.meteo-reglages-btn[aria-expanded="true"] { opacity: .8; }
.meteo-reglages-btn:hover { opacity: 1; background: rgba(31,36,64,.06); }

/* Panneau de réglages, sur la carte.
   ⚠️ La règle [hidden] est OBLIGATOIRE et doit rester APRÈS le display:flex : sans elle, le
   display l'emporterait et le panneau resterait visible en permanence. */
.meteo-reglages { display: flex; flex-direction: column; gap: .35rem; margin: .5rem 0 .7rem;
    padding: .6rem .7rem; border: 1px solid rgba(31,36,64,.12); border-radius: 10px;
    background: rgba(31,36,64,.03); font-size: .82rem; }
.meteo-reglages[hidden] { display: none; }
.meteo-reglage-ville { display: flex; align-items: center; gap: .5rem; font-weight: 600; }
.meteo-reglage-ville input { flex: 1; min-width: 0; padding: .3rem .45rem; font: inherit;
    border: 1px solid rgba(31,36,64,.18); border-radius: 8px; }
.meteo-reglage-aide { margin: 0 0 .2rem; font-size: .76rem; }
.meteo-reglage-blocs { display: flex; flex-direction: column; gap: .2rem; }
.meteo-reglage-bloc { display: flex; align-items: center; gap: .45rem; cursor: pointer; }

/* La ligne qu'on regarde le matin : récréation dehors ou pas. */
.meteo-pluie { margin: .45rem 0 0; font-size: .85rem; font-weight: 600; color: var(--ink, #0f172a); }
.meteo-pluie.is-sec { font-weight: 500; color: #475569; }
/* « (80 %) » ne se coupe pas : dans une colonne étroite, le « % » se retrouvait seul à la ligne. */
.meteo-pluie .muted { white-space: nowrap; }

/* Les trois prochains jours : une grille à trois colonnes pour que les températures s'alignent. */
.meteo-jours { list-style: none; margin: .55rem 0 0; padding: 0; display: flex;
    flex-direction: column; gap: .18rem; font-size: .82rem; }
.meteo-jours li { display: grid; grid-template-columns: 1fr auto auto; align-items: center; gap: .5rem; }
.meteo-jour-nom { text-transform: capitalize; }
.meteo-jour-ico { font-size: .95rem; }
.meteo-jour-t { font-variant-numeric: tabular-nums; }

/* Air et pollens. ⚠️ Repère, pas avis médical : couleurs sobres, aucun ton d'alerte médicale. */
.meteo-air { margin: .55rem 0 0; font-size: .8rem; display: flex; flex-wrap: wrap; gap: .3rem; align-items: center; }
.meteo-aqi, .meteo-pollen { padding: .08rem .4rem; border-radius: 999px; font-weight: 600; }
.meteo-aqi.is-bon { background: rgba(22,163,74,.12); color: #15803d; }
.meteo-aqi.is-moyen { background: rgba(217,119,6,.14); color: #b45309; }
.meteo-aqi.is-mauvais { background: rgba(220,38,38,.12); color: #b91c1c; }
.meteo-pollen { background: rgba(31,36,64,.07); color: #475569; }
.meteo-pollen.is-cran3 { background: rgba(217,119,6,.14); color: #b45309; }
.meteo-pollen.is-cran4 { background: rgba(220,38,38,.12); color: #b91c1c; }

/* ── Icône de FORMAT dans un bouton d'export ─────────────────────────────────
   La couleur dit le format sans qu'on lise l'étiquette : rouge = PDF, vert = tableur.
   (Les icônes Tabler sont vendorisées dans assets/icons/ — jamais de CDN.) */
.ico-fmt { width: 1.05rem; height: 1.05rem; vertical-align: -.2em; }
.ico-fmt.is-pdf { color: #dc2626; }
.ico-fmt.is-xls { color: #15803d; }

/* Recherche d'élève de l'accueil Dossiers élèves : plus large que la recherche d'une liste —
   elle porte une phrase (« Rechercher un élève de l'école »), pas un mot-clé. */
.search-eleve { max-width: 34rem; }

/* ── PUPITRE D'ÉLÈVE — la classe telle qu'on l'ouvre ─────────────────────────
   La maquette validée (Philippe, 2026-09-14) : un vrai banc d'écolier par enfant — dossier,
   plateau de bois, pieds d'acier, ombre au sol —, la pastille et le NOM posés sur le plateau,
   le ⚠ d'une allergie sur le coin (information de sécurité : jamais derrière un survol), et le
   détail dans une fiche qui se lève AU-DESSUS du banc.

   ⚠️ Le banc EST celui de la maquette : `assets/images/pupitre.webp` en est découpé (un banc de la
   deuxième rangée, son nom effacé par une colonne de bois voisine), pas une reconstitution — deux
   tentatives de le redessiner ont été refusées, et à raison. Il porte son propre fond, d'où la
   couleur de `.pup-salle` : c'est celle de l'image, et c'est ce qui rend le raccord invisible.
   Gabarit : templates/_partials/pupitre.html.twig.                                            */

/* Ce qu'on dit au lecteur d'écran sans le montrer à l'œil. (`.ebx-sr-only` est la même
   technique, réservée à l'éditeur de la boîte mail — celle-ci est l'utilitaire général.) */
.sr-only {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* La salle : fond très clair, et le coin de bureau posé en bas à gauche. */
.pup-salle {
    position: relative; margin-top: .4rem; padding: 1rem 2.2rem .5rem;
    background: #f2eeea; border-radius: var(--radius); box-shadow: inset 0 0 0 1px rgba(160, 140, 120, .12);
}

/* La barre d'outils de la maquette : recherche, filtre, et la bascule bancs / liste. */
.pup-barre { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; }
.pup-barre .pup-compte { margin-right: auto; font-size: .85rem; color: var(--muted); }
.pup-cherche { position: relative; display: flex; align-items: center; flex: 1 1 16rem; max-width: 24rem; }
.pup-cherche svg { position: absolute; left: .7rem; width: 1.05rem; height: 1.05rem; color: var(--muted); pointer-events: none; }
.pup-cherche .input { width: 100%; padding-left: 2.3rem; border-radius: 999px; }
.pup-filtre .input { border-radius: 999px; min-width: 9rem; }
.pup-vues { display: inline-flex; gap: .15rem; padding: .15rem; border-radius: 12px; background: var(--bg); }
.pup-vue.is-on { background: var(--primary-soft); color: var(--primary-dark); }
.pup-tiles {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
    gap: 1.8rem 1.2rem; margin-top: .9rem; align-content: start;
}
.pupitre { position: relative; }
/* L'en-tête de colonnes n'existe que sur la feuille imprimée. */
.pup-entetes { display: none; }

/* Le banc. Le SVG suit la boîte (`preserveAspectRatio="none"`), donc on lui tient son rapport :
   un meuble qui s'étire n'est plus un meuble. Le contenu se pose sur le plateau, dont le SVG
   occupe la bande 13 %–70 % — d'où les marges internes en pourcentage. */
.pup-banc {
    position: relative; z-index: 1; aspect-ratio: 268 / 300;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: .4rem; padding: 29% 12% 22%;
    background: url("../images/pupitre-AxcI721.webp") no-repeat center / 100% 100%;
    /* Le banc AVANCE vers qui le regarde — il ne fait pas que se soulever (demande Philippe). */
    transition: transform .22s cubic-bezier(.22, .61, .36, 1), filter .22s ease;
}
.pup-nom {
    display: flex; align-items: center; justify-content: center; text-align: center;
    font-family: "Baloo 2", sans-serif; font-size: .95rem; font-weight: 700; line-height: 1.15;
    color: var(--ink); min-height: 2.3em;
}
.pup-nom strong { font-weight: 800; }
.pupitre .avatar { box-shadow: 0 2px 5px rgba(31, 36, 64, .28); }

/* Le banc ENTIER ouvre le dossier : c'est le lien du nom qu'on étire dessus, et donc sa garde
   `eleve.view` — sans le droit, la macro ne rend pas de lien et rien n'est cliquable. */
.pupitre .eleve-lien::after { content: ""; position: absolute; inset: 0; z-index: 2; }
.pupitre .eleve-lien:hover, .pupitre .eleve-lien:focus-visible { text-decoration: none; color: inherit; }

/* Le repère d'allergie, sur le coin du plateau. Transparent au clic : il ne troue pas le banc. */
.pup-tag {
    position: absolute; top: 31%; right: 9%; z-index: 3; pointer-events: none;
    display: inline-flex; align-items: center; gap: .22rem; padding: .1rem .42rem;
    border-radius: 999px; background: #fdecec; color: #c0392b; font-size: .68rem; font-weight: 700;
    box-shadow: inset 0 0 0 1px rgba(192, 57, 43, .25), 0 1px 2px rgba(31, 36, 64, .12);
}
.pup-tag svg { width: .9em; height: .9em; }

/* Le bouton « Informations » existe PARTOUT : un portable ou un Chromebook à dalle tactile
   répond `hover: hover` (son pointeur principal est le trackpad) et n'aurait alors aucun chemin
   vers l'allergie — le tap sur le banc ouvrant, lui, le dossier. */
.pup-plus { position: absolute; top: 29%; left: 7%; z-index: 7; color: #64748b; opacity: .38;
             transition: opacity .18s ease; }
.pupitre:hover .pup-plus, .pupitre:focus-within .pup-plus, .pupitre.is-ouvert .pup-plus,
.pup-plus:focus-visible { opacity: 1; }
.pup-plus:hover, .pup-plus:focus-visible { color: var(--ink); background: rgba(15, 23, 42, .07); }

/* La fiche se lève AU-DESSUS du banc, comme sur la maquette, et pointe vers lui. Elle ne s'ouvre
   PAS dessous par défaut : ancrée là, elle recouvrait 100 % du plateau du rang suivant — un
   élève effaçé de la liste, et le bouton « Voir le dossier » d'un autre enfant à 9 px de là où
   l'on croyait cliquer. Le contrôleur la bascule sous le banc (`is-bas`) quand la place manque
   au-dessus, sur la première rangée ou en haut du cadre de défilement. */
.pup-fiche {
    position: absolute; left: -34px; right: -34px; min-width: 264px; bottom: calc(100% - 34%); z-index: 6;
    padding: .8rem .9rem .85rem; border-radius: 16px;
    background: var(--card); border: 1px solid var(--line);
    box-shadow: 0 2px 4px rgba(31, 36, 64, .06), 0 22px 40px -16px rgba(31, 36, 64, .55);
    opacity: 0; visibility: hidden; transform: translateY(6px);
    transition: opacity .18s ease, transform .18s ease, visibility .18s;
}
.pup-fiche::after {
    content: ""; position: absolute; bottom: -6px; left: 50%; width: 11px; height: 11px;
    margin-left: -5px; background: var(--card);
    border-right: 1px solid var(--line); border-bottom: 1px solid var(--line);
    transform: rotate(45deg);
}
.pupitre.is-bas .pup-fiche { bottom: auto; top: calc(100% - 40%); }
.pupitre.is-bas .pup-fiche::after {
    bottom: auto; top: -6px; border: 0; border-left: 1px solid var(--line); border-top: 1px solid var(--line);
}

/* Le banc survolé se soulève et se cercle de bleu — le reste de la salle reste au repos. */
@media (hover: hover) {
    .pupitre:hover .pup-banc { transform: translateY(-8px) scale(1.06); filter: drop-shadow(0 14px 18px rgba(31, 36, 64, .22)); }
    .pupitre:hover { outline: 2px solid rgba(1, 137, 217, .5); outline-offset: -4px; border-radius: 18px; }
    .pupitre:hover .pup-fiche { opacity: 1; visibility: visible; transform: translateY(0); }
}
/* Le focus clavier fait exactement ce que fait le survol — sinon la fiche serait inatteignable
   sans souris. `.is-ouvert` est le même état, posé au doigt par le contrôleur `pupitre`. */
.pupitre:focus-within .pup-banc, .pupitre.is-ouvert .pup-banc {
    transform: translateY(-8px) scale(1.06); filter: drop-shadow(0 14px 18px rgba(31, 36, 64, .22));
}
.pupitre:focus-within, .pupitre.is-ouvert { outline: 2px solid rgba(1, 137, 217, .5); outline-offset: -4px; border-radius: 18px; }
.pupitre:focus-within .pup-fiche, .pupitre.is-ouvert .pup-fiche { opacity: 1; visibility: visible; transform: translateY(0); }

/* Le titre laisse sa place au bouton « Informations », qui reste au-dessus de la fiche : c'est
   lui qui la referme au doigt, il ne peut donc pas passer dessous. */
.pup-fiche-nom {
    display: flex; align-items: center; gap: .5rem; margin: 0 0 .55rem; padding-left: 1.6rem;
    font-family: "Baloo 2", sans-serif; font-weight: 800; font-size: .95rem; line-height: 1.2;
    color: var(--ink);
}
.pup-lignes { list-style: none; margin: 0; padding: 0; display: grid; gap: .36rem; }
.pup-ligne { display: grid; grid-template-columns: 1.1rem auto 1fr; align-items: center; gap: .45rem; font-size: .8rem; }
.pup-ico { display: inline-flex; align-items: center; justify-content: center; color: #64748b; font-size: 1rem; line-height: 1; }
.pup-ico svg { width: 1em; height: 1em; }
.pup-cle { color: #5b6478; }
.pup-val { justify-self: end; text-align: right; font-weight: 600; color: var(--ink); }
.pup-val.muted { font-weight: 500; color: var(--muted); }
.pup-ligne .badge { justify-self: end; font-size: .72rem; padding: .12rem .5rem; }
.pup-allergies { display: flex; flex-wrap: wrap; gap: .25rem; justify-content: flex-end; }
.pup-ouvrir { margin-top: .7rem; width: 100%; }

/* Le coin de bureau et les deux mots écrits à la main, au pied de la classe. Décor pur : il
   disparaît à l'impression, en vue liste et sur les écrans étroits, où la place se compte. */
.pup-pied { position: relative; margin-top: 1.4rem; min-height: 130px; }
.pup-decor {
    position: absolute; left: -1.4rem; bottom: -.5rem; width: 250px; height: 168px;
    background: url("../images/classe-decor-G_mYW4m.webp") no-repeat left bottom / contain;
    pointer-events: none;
}
.pup-mot {
    position: absolute; bottom: 1.1rem; font-family: "Caveat", "Snell Roundhand", cursive;
    font-size: 1.5rem; line-height: 1.15; color: #7b849c; white-space: pre-line;
}
.pup-mot.est-gauche { left: 250px; }
.pup-mot.est-droite { right: .5rem; text-align: right; }
@media (max-width: 900px) { .pup-pied { display: none; } }
/* Sur une colonne étroite, la fiche tient dans le banc : débordée, elle élargissait la page. */
@media (max-width: 640px) { .pup-fiche { left: 0; right: 0; min-width: 0; } }

/* ── Vue LISTE ───────────────────────────────────────────────────────────────
   Le même DOM, mis à plat : un banc par ligne, fiche dépliée. C'est exactement ce que fait
   l'impression, d'où les sélecteurs communs — et c'est ce qui rend la bascule gratuite. */
.pup-tiles.est-liste { display: block; }
.pup-tiles.est-liste .pupitre { border-bottom: 1px solid var(--line); }
.pup-tiles.est-liste .pupitre { display: flex; align-items: center; gap: .8rem; }
.pup-tiles.est-liste .pup-banc {
    flex: 0 0 40%; aspect-ratio: auto; flex-direction: row; justify-content: flex-start;
    gap: .5rem; padding: .45rem 0; background: none; transform: none !important; filter: none !important;
}
.pup-tiles.est-liste .pup-nom { min-height: 0; justify-content: flex-start; text-align: left; }
.pup-tiles.est-liste .pup-tag { position: static; }
.pup-tiles.est-liste .pup-plus { display: none; }
.pup-tiles.est-liste .pup-fiche {
    position: static; flex: 1; opacity: 1; visibility: visible; transform: none;
    padding: 0; border: 0; box-shadow: none; background: none;
}
.pup-tiles.est-liste .pup-fiche::after, .pup-tiles.est-liste .pup-fiche-nom, .pup-tiles.est-liste .pup-ouvrir { display: none; }
.pup-tiles.est-liste .pup-lignes { display: flex; flex-wrap: wrap; gap: .2rem 1.2rem; }
.pup-tiles.est-liste .pup-ligne { display: inline-flex; gap: .3rem; }

/* Rien ne correspond à la recherche ou au filtre. */
.pup-vide { display: none; padding: 1.4rem; color: var(--muted); }
.pup-tiles.est-vide + .pup-vide { display: block; }

/* Sur papier, il n'y a ni survol ni clavier : la classe redevient une LISTE À COLONNES, fiche
   dépliée — la feuille que l'école affiche, emporte en sortie et lit à la verticale. Les colonnes
   s'alignent d'une ligne à l'autre parce que `display: contents` fait remonter le nom et les
   quatre valeurs dans UNE seule grille : sans lui, chaque élève avait sa propre mise en page et
   rien ne tombait en face de rien.                                                             */
@media print {
    .pup-tiles {
        /* Deux colonnes souples (le nom, les allergies) encadrent trois colonnes serrées : sans
           `minmax(0, …)`, une liste d'allergies un peu longue sortait de la feuille. */
        display: grid; grid-template-columns: minmax(0, 1fr) auto auto auto minmax(0, 1.15fr);
        align-items: stretch;
        /* Pas de `column-gap` : le filet de séparation doit courir d'un bord à l'autre, sans
           trous entre les colonnes. L'air se met DANS les cellules. */
        /* ⚠️ `gap`, pas seulement `column-gap` : l'espace entre RANGÉES vient de la grille
           d'écran (1.8rem), et il coûtait cinq élèves de page. */
        gap: 0; padding: 0; margin: 0;
    }
    /* Les boîtes intermédiaires s'effacent : leurs enfants deviennent les cellules de la grille. */
    .pupitre, .pup-fiche, .pup-lignes, .pup-entetes { display: contents; }
    /* ⚠️ Piège n°2 de docs/conventions/frontend.md : `display` bat l'attribut `hidden`. Sans
       cette règle, un élève écarté par le filtre revenait sur la feuille imprimée. */
    .pupitre[hidden] { display: none !important; }
    /* ⚠️ `display: contents` supprime la boîte, PAS l'héritage : sans ces trois-là, la fiche
       reste celle d'un survol fermé et la feuille sort avec la seule colonne des noms. */
    .pup-fiche { opacity: 1 !important; visibility: visible !important; transform: none !important; }

    .pup-barre, .pup-plus, .pup-fiche-nom, .pup-ouvrir, .pup-fiche::after, .pup-tag, .pup-pied,
    .pup-ico, .pup-cle { display: none !important; }
    /* Le papier est blanc : ni fond de salle, ni cadre. */
    .pup-salle { background: none !important; box-shadow: none !important; padding: 0 !important; margin: 0 !important; }
    /* Ni plateau, ni relief, ni état de survol resté collé au moment d'imprimer. */
    .pup-banc, .pupitre:hover .pup-banc, .pupitre:focus-within .pup-banc, .pupitre.is-ouvert .pup-banc {
        background: none !important; transform: none !important; filter: none !important;
    }

    /* L'en-tête de colonnes, sur la première page. */
    .pup-entetes span {
        padding: 0 5mm .12rem 0; font-size: .66rem; font-weight: 700; text-transform: uppercase;
        letter-spacing: .04em; color: #475569; border-bottom: 1.5px solid #334155;
    }
    .pup-entetes span:last-child { padding-right: 0; }

    /* Une cellule par colonne, toutes à la même ligne de base, séparées d'un filet. */
    /* Cellules étirées à la hauteur de leur rangée : sans ça, le filet sous le nom ne tombait
       pas en face de celui des valeurs, et la feuille partait en marches d'escalier. */
    .pup-banc, .pup-ligne {
        display: flex; align-items: center; padding: .17rem 5mm .17rem 0;
        border-bottom: 1px solid #dde4ec; break-inside: avoid; font-size: .78rem;
    }
    .pup-ligne:last-child { padding-right: 0; }
    /* `justify-content: center` vient de l'écran, où le nom est posé au milieu du plateau : sur
       la feuille, la colonne se lit au fer à gauche. */
    .pup-banc { flex: none; aspect-ratio: auto; min-height: 0; justify-content: flex-start; }
    /* `margin-right: auto` pousse le nom au fer à gauche quoi qu'il arrive : le plateau le
       centrait, et sur une colonne de feuille un nom centré se lit mal. */
    .pup-nom { display: block; min-height: 0; margin-right: auto; text-align: left; font-size: .82rem; }
    .pup-val { display: inline; text-align: left; font-weight: 600; }
    .pup-ligne .badge {
        display: inline; justify-self: start; padding: 0; background: none !important;
        font-size: .78rem; font-weight: 600;
    }
    .pup-allergies { display: inline; }
    .pup-allergies .badge::after { content: " · "; color: #64748b; }
    .pup-allergies .badge:last-child::after { content: ""; }
    /* Sans allergie, la CELLULE reste — la vider décalerait toute la colonne. */
    .pup-ligne.is-sans-allergie > * { visibility: hidden; }
}

/* ============================================================
   PEAU « CONSOLE » DE LA SUPER-ADMIN
   ============================================================
   Décision Philippe, 2026-09-19 : « fais-moi un truc pro pour informaticien ».
   L'application est dessinée pour des directeurs et des enseignants — ronde,
   colorée, Baloo 2. La console d'exploitation s'adresse à trois personnes qui
   la BALAIENT : elle prend ici sa propre densité et sa propre typographie.

   ⚠️ Tout ce bloc est scopé à `.admin-shell`. Aucune règle ne sort de la
   console : l'app garde son identité, ses 48 px et ses polices.
   Documentée dans docs/charte/charte-graphique.md § « La console super-admin a sa propre peau ».
   ============================================================ */
.admin-shell {
    --adm-sans: "IBM Plex Sans", "Inter", system-ui, -apple-system, sans-serif;
    --adm-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
    /* Gris tirés vers le bleu de marque : posés à côté du logo, ils tiennent ensemble. */
    --adm-ink: #111721;
    --adm-muted: #5f6b80;
    --adm-faint: #8590a4;
    --adm-line: #dfe5ee;
    --adm-line-2: #eaeef5;
    --adm-bg: #eef1f6;
    --adm-ok: #0f7a56;      --adm-ok-soft: #e2f4ed;
    --adm-warn: #a8620a;    --adm-warn-soft: #fcf0dd;
    --adm-dang: #b5372c;    --adm-dang-soft: #fbeae8;

    font-family: var(--adm-sans);
    color: var(--adm-ink);
    /* Les colonnes de chiffres s'alignent : c'est la moitié de la lisibilité d'une console. */
    font-variant-numeric: tabular-nums;
}
.admin-shell .content { background: var(--adm-bg); }

/* — Typographie : Baloo 2 sort de la console — */
.admin-shell h1, .admin-shell h2, .admin-shell h3,
.admin-shell .card-title, .admin-shell .drawer-head h2 {
    font-family: var(--adm-sans);
    letter-spacing: -.012em;
}
.admin-shell h1 { font-size: 1.35rem; font-weight: 600; }
.admin-shell h2 { font-size: 1.05rem; font-weight: 600; }
.admin-shell h3, .admin-shell .card-title { font-size: .95rem; font-weight: 600; }
.admin-shell .page-head .lead { font-size: .88rem; }
/* Toute donnée technique — adresse, identifiant, chemin, horodatage — en chasse fixe. */
.admin-shell code { font-family: var(--adm-mono); }

/* — Rail : cinq familles au lieu de dix-huit entrées à la file — */
.admin-side { width: 216px; padding: .9rem .65rem 1.1rem; }
.admin-side-title {
    display: flex; align-items: center; gap: .55rem;
    margin: 0 .5rem .8rem; padding-bottom: .8rem;
    border-bottom: 1px solid var(--adm-line-2);
    font-family: var(--adm-sans); font-size: .85rem; font-weight: 600; letter-spacing: -.01em;
}
.admin-side-sa {
    flex: none; width: 26px; height: 26px; border-radius: 6px;
    background: var(--adm-ink); color: #fff;
    display: grid; place-items: center;
    font-size: .64rem; font-weight: 600; letter-spacing: .04em;
}
.admin-side-grp {
    margin: .85rem .5rem .3rem; font-family: var(--adm-mono);
    font-size: .63rem; font-weight: 600; letter-spacing: .11em; text-transform: uppercase;
    color: var(--adm-faint);
}
.admin-side-grp:first-of-type { margin-top: .1rem; }
.admin-side nav a {
    display: flex; align-items: center; gap: .55rem;
    padding: 0 .5rem; height: 29px;
    border-radius: 6px; font-size: .79rem; font-weight: 450;
}
.admin-side nav a svg { width: 16px; height: 16px; flex: none; color: var(--adm-faint); }
.admin-side nav a:hover { background: var(--adm-line-2); color: var(--adm-ink); }
.admin-side nav a:hover svg { color: var(--adm-muted); }
/* L'entrée courante ne s'aplatit plus sous un aplat plein : fond doux + texte de marque. */
.admin-side nav a.is-active { background: var(--brand-soft); color: var(--brand-dark); font-weight: 600; }
.admin-side nav a.is-active svg { color: var(--brand); }
.admin-side-foot { margin-top: .9rem; padding-top: .8rem; font-size: .76rem; }

/* — Densité des grilles : 36 px la ligne au lieu de 48 — */
/* ⚠️ `.table-wrap` est en `overflow: hidden` dans l'app : un tableau trop large est COUPÉ, pas
   défilé. Mesuré sur le grid Centres & écoles (7 colonnes, 607 px de min-content) : à 840 px de
   fenêtre, 43 px disparaissent ; à 400 px, 244 px — Élèves, Comptes, État et la colonne d'action
   deviennent invisibles ET inatteignables. La console rétablit donc le défilement horizontal,
   comme le fait déjà `.dns-records`. */
.admin-shell .table-wrap { border-radius: 8px; overflow-x: auto; -webkit-overflow-scrolling: touch; }
.admin-shell table th {
    height: 30px; padding: 0 .65rem;
    background: #f7f9fc; font-size: .66rem; letter-spacing: .07em;
}
.admin-shell table td { height: 36px; padding: .25rem .65rem; font-size: .8rem; }
.admin-shell .epi-sub td { font-size: .78rem; }
/* Le chevron de dépliage : discret, il ne doit pas peser autant que la donnée. */
.admin-shell .epi-chev { width: 18px; height: 18px; border-radius: 5px; font-size: .7rem; }
.admin-shell .epi-clic:hover td { background: #f8fafd; }
.admin-shell .epi-main.is-open td { background: var(--brand-soft); }
.admin-shell .epi-main.is-open td:first-child { box-shadow: inset 3px 0 0 var(--brand); }

/* — Contrôles : une seule hauteur, 34 px, listes déroulantes et dates comprises — */
.admin-shell .input,
.admin-shell select.input,
.admin-shell input[type="date"].input,
.admin-shell input[type="datetime-local"].input {
    height: 34px; padding: 0 .55rem; border-radius: 6px; font-size: .82rem;
}
.admin-shell textarea.input { height: auto; padding: .45rem .55rem; }
.admin-shell .field-edit > span { font-size: .66rem; letter-spacing: .05em; text-transform: uppercase; color: var(--adm-faint); }
.admin-shell .filters { gap: .55rem; align-items: flex-end; }
.admin-shell .filters .field-edit { min-width: 9.5rem; }
.admin-shell .btn { height: 34px; padding: 0 .75rem; border-radius: 6px; font-size: .82rem; font-weight: 500; box-shadow: none; }
.admin-shell .btn.sm { height: 28px; padding: 0 .6rem; font-size: .75rem; }
.admin-shell .btn-row { border-radius: 6px; font-size: .75rem; font-weight: 600; padding: .28rem .6rem; }

/* — Badges : la couleur ne dit plus qu'un état — */
.admin-shell .badge {
    border-radius: 5px; padding: .1rem .4rem;
    font-family: var(--adm-mono); font-size: .68rem; font-weight: 500;
}
.admin-shell .badge-ok      { background: var(--adm-ok-soft);   color: var(--adm-ok); }
.admin-shell .badge-warn    { background: var(--adm-warn-soft); color: var(--adm-warn); }
.admin-shell .badge-danger  { background: var(--adm-dang-soft); color: var(--adm-dang); }
/* Pastille d'état à point : lit l'état sans lire le mot. */
.admin-shell .badge.adm-dot::before {
    content: ""; width: 5px; height: 5px; border-radius: 50%; background: currentColor; flex: none;
}

/* — En-tête d'écran : titre · compte · action, puis filtres, puis grille — */
.admin-shell .page-head { margin-bottom: .8rem; align-items: flex-start; }
.adm-count { font-family: var(--adm-mono); font-size: .72rem; color: var(--adm-faint); }
/* Pastilles de filtre actif : ce qui est actif, et combien ça retire. */
.adm-actifs { display: flex; flex-wrap: wrap; gap: .4rem; align-items: center; margin: 0 0 .8rem; font-size: .75rem; }
/* ⚠️ `display` bat `hidden` : sans cette ligne, le résumé des filtres reste à l'écran même
   quand le gabarit le pose caché (piège n°2 de conventions/frontend.md). */
.adm-actifs[hidden] { display: none; }
.adm-actifs .adm-actifs-lab {
    font-family: var(--adm-mono); font-size: .63rem; letter-spacing: .07em;
    text-transform: uppercase; color: var(--adm-faint);
}
.adm-actifs .adm-reste { color: var(--adm-faint); }

/* — Tuiles : compactes, l'écart d'abord —
   Neuf pavés à gros chiffre poussaient la grille sous la ligne de flottaison. Ils deviennent une
   bande d'un seul tenant : l'œil compare des voisins, il ne saute pas d'une carte à l'autre. */
.admin-shell .stat-grid {
    grid-template-columns: repeat(auto-fit, minmax(118px, 1fr));
    gap: 1px; margin-bottom: 1rem;
    background: var(--adm-line); border: 1px solid var(--adm-line); border-radius: 8px; overflow: hidden;
}
.admin-shell .stat-grid .stat-card { border: 0; border-radius: 0; padding: .5rem .65rem .6rem; }
.admin-shell .stat-card .stat { display: flex; align-items: center; gap: .45rem; }
.admin-shell .stat-ico { font-size: .95rem; opacity: .75; }
.admin-shell .stat-val { font-family: var(--adm-mono); font-size: 1.15rem; font-weight: 600; letter-spacing: -.02em; }
.admin-shell .stat-lbl { font-size: .68rem; font-weight: 400; line-height: 1.25; color: var(--adm-muted); }
/* Un zéro n'est PAS une information : il s'efface pour laisser voir les écarts, et seuls les
   compteurs qui comptent vraiment (erreurs, échecs, blocages) s'allument en rouge. */
.admin-shell .stat-card.est-vide .stat-val { color: #b6c0d0; }
.admin-shell .stat-card.est-vide .stat-ico { opacity: .3; }
.admin-shell .stat-card.est-chaud .stat-val { color: var(--adm-dang); }

/* — Onglets et pilules de fenêtre : des repères, pas des boutons d'action — */
.admin-shell .tabs { gap: .3rem; margin-bottom: .9rem; }
.admin-shell .tab { padding: .3rem .65rem; border-radius: 6px; font-size: .78rem; font-weight: 500; }
.admin-shell .tab .tab-ico { font-size: .85rem; }
.admin-shell .page-actions.btn-row { gap: .25rem; }

/* — Cartes et tiroir — */
.admin-shell .card { border-radius: 10px; box-shadow: none; padding: 1rem 1.1rem; }
.admin-shell .drawer-panel { width: min(420px, 94vw); }
.admin-shell .drawer-head { padding: .8rem 1rem; }
.admin-shell .drawer-head h2 { font-size: .95rem; }
.admin-shell .drawer-body { padding: .9rem 1rem; gap: .7rem; }
.admin-shell .drawer-foot { padding: .75rem 1rem; }
/* Zone dangereuse d'un tiroir : ce qu'une suppression emporte, écrit avant le bouton. */
.adm-danger { margin-top: auto; padding: .7rem .8rem; border: 1px solid #f0d8d4; border-radius: 7px; background: #fdf6f5; }
.adm-danger .adm-danger-t { font-size: .8rem; font-weight: 600; color: var(--adm-dang); margin-bottom: .2rem; }
.adm-danger p { margin: 0 0 .5rem; font-size: .75rem; color: var(--adm-muted); line-height: 1.45; }

/* — Faits d'une fiche : trois chiffres côte à côte, en tiroir ou en ligne dépliée — */
.adm-faits { display: flex; flex-wrap: wrap; gap: 1rem; padding: .55rem .7rem; background: #f7f9fc; border-radius: 6px; }
.adm-faits > span { display: flex; flex-direction: column; }
.adm-faits .adm-faits-l { font-size: .63rem; letter-spacing: .06em; text-transform: uppercase; color: var(--adm-faint); }
.adm-faits .adm-faits-v { font-family: var(--adm-mono); font-size: .85rem; font-weight: 500; }

@media (max-width: 820px) {
    .admin-side { width: 100%; }
    /* Sous 820 px le rail se met à plat et ses entrées s'enroulent. Les cinq intertitres, eux,
       prennent chacun toute une ligne : mesuré à 400 px, ils coûtent 211 px de haut et repoussent
       le contenu à y = 687. Le groupement sert à BALAYER une colonne ; à plat il ne sert plus. */
    .admin-side-grp { display: none; }
}

/* — Centres & écoles : une école dépliée sous son centre —
   La sous-ligne n'est pas un second tableau : une bande par école, ses implantations en
   pastilles cliquables (chacune ouvre le tiroir sur ELLE), ses chiffres et ses actions à
   droite. Le tout dans le <td colspan> de la `.epi-sub`. */
.adm-ecole {
    display: flex; align-items: center; gap: .55rem; flex-wrap: wrap;
    padding: .45rem .6rem; margin-top: .35rem;
    background: var(--card); border: 1px solid var(--adm-line); border-radius: 6px;
}
.adm-ecole-nom { font-size: .82rem; min-width: 11rem; }
.adm-impls { display: flex; gap: .3rem; flex-wrap: wrap; align-items: center; }
.adm-ecole-fin { margin-left: auto; display: flex; align-items: center; gap: .5rem; }
.adm-ecole-fin .muted { font-family: var(--adm-mono); font-size: .68rem; }
.adm-ecole-actions { display: flex; gap: .4rem; margin-top: .5rem; }
.admin-shell .btn-ghost.is-danger { background: var(--u-card, #fff); color: var(--adm-dang); border: 1px solid #e8c4bf; }
.admin-shell .btn-ghost.is-danger:hover { background: var(--adm-dang-soft); }

/* Pastille d'implantation : c'est un LIEN d'encodage, pas une étiquette — il ouvre le tiroir. */
.adm-chip {
    display: inline-flex; align-items: center; gap: .3rem; height: 21px; padding: 0 .4rem;
    border: 1px solid var(--adm-line); border-radius: 5px; background: #fbfcfe;
    font-family: var(--adm-mono); font-size: .68rem; color: var(--adm-muted);
    text-decoration: none; cursor: pointer;
}
.adm-chip:hover { border-color: var(--brand); color: var(--brand-dark); background: var(--brand-soft); }
.adm-chip-n { color: var(--adm-ink); font-weight: 500; }
.adm-chip:hover .adm-chip-n { color: var(--brand-dark); }
.adm-chip-a { color: var(--adm-faint); }
.adm-chip.is-add { border-style: dashed; color: var(--brand); background: transparent; }

/* Sous-titre d'un en-tête de tiroir de la console : de QUOI on parle, sous le nom.
   ⚠️ Préfixé `adm-` : `.drawer-*` est le namespace PARTAGÉ avec toute l'application. */
.adm-drawer-sous { display: block; font-family: var(--adm-mono); font-size: .68rem; color: var(--adm-faint); }
.admin-shell .drawer-head h2 + .adm-drawer-sous { margin-top: .1rem; }

/* La citation de session accompagne l'espace d'une école ; sur la console d'exploitation, c'est
   du bruit au-dessus de la donnée. Masquée ICI et pas retirée du gabarit : la topbar est
   partagée, et les tests de la citation d'accueil s'appuient sur son balisage. */
body.adm .citation-accueil { display: none; }

/* — Utilisateurs : l'adresse est une donnée technique, pas un lien souligné en bleu — */
.adm-lien-mono { font-family: var(--adm-mono); font-size: .78rem; color: var(--adm-ink); text-decoration: none; }
.adm-lien-mono:hover { color: var(--brand-dark); text-decoration: underline; }
/* Cases de rôles du tiroir : une grille, pas une file de cases de largeurs inégales. */
.adm-roles { display: grid; grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr)); gap: .3rem .8rem; }
.adm-role-case { display: flex; align-items: center; gap: .4rem; font-size: .8rem; font-weight: 400; color: var(--adm-ink); }
.adm-role-case input { margin: 0; }

/* — Largeur de lecture : une explication technique tient en lignes lisibles —
   Les écrans de réglage (Apparence, Nettoyage, Reprise) portent de vrais paragraphes ; en pleine
   largeur de console ils font 150 caractères, et l'œil perd la ligne suivante. On les borne SANS
   toucher aux tableaux ni aux grilles, qui doivent, eux, prendre toute la place. */
.admin-shell .content > p,
.admin-shell .page-head .lead,
.admin-shell .card > p:not([class]),
.admin-shell .note { max-width: 82ch; }

/* — Le champ FICHIER : le bouton natif ne ressemble à rien de la console —
   Sans cette règle, « Choisir un fichier » sort en gris système, d'une autre hauteur que les
   champs voisins (Calendrier FWB, imports d'aide et de citations). */
.admin-shell input[type="file"].input { padding: .3rem .5rem; line-height: 1.6; cursor: pointer; }
.admin-shell input[type="file"].input::file-selector-button {
    margin-right: .6rem; padding: .18rem .6rem;
    border: 1px solid var(--adm-line); border-radius: 5px;
    background: #f7f9fc; color: var(--adm-ink);
    font: inherit; font-size: .78rem; font-weight: 500; cursor: pointer;
}
.admin-shell input[type="file"].input::file-selector-button:hover { background: var(--brand-soft); color: var(--brand-dark); }

/* Un nom de variable d'environnement au milieu d'une phrase : il ne doit ni s'étirer ni
   disloquer la ligne (vu sur Sauvegardes, où BACKUP_ALERTE_EMAIL cassait le bandeau). */
.admin-shell .banner code, .admin-shell .note code, .admin-shell p code {
    padding: .05rem .3rem; border-radius: 4px; background: #eef1f6;
    font-size: .92em; white-space: nowrap;
}

/* — Un bandeau est une PHRASE, pas une rangée —
   `.banner` est en `display: flex` : chaque nœud de son contenu devient un item, si bien qu'un
   `<code>` ou un `<strong>` au milieu d'une phrase la disloque. Mesuré sur Sauvegardes, où
   « Aucune adresse dédiée (BACKUP_ALERTE_EMAIL) : … » sortait dans le désordre. Les bandeaux
   qui enveloppent déjà leur texte dans un bloc rendent pareil en `block`. */
.admin-shell .banner { display: block; }

/* ── Journal d'accès : la synthèse (design du 2026-09-22) ─────────────────────────────────────
   Un verdict en une ligne, puis des points lisibles en français. La couleur ne dit que le niveau :
   liseré à gauche + badge ; le texte reste noir sur blanc, lisible au premier coup d'œil. */
.admin-shell .ja-synthese { margin-bottom: 1.2rem; }
.admin-shell .ja-verdict {
    display: block; padding: .8rem 1rem; margin-bottom: .8rem; border-radius: var(--radius-sm);
    border: 1px solid var(--line); border-left: 4px solid var(--adm-ok); background: var(--card); font-size: .92rem;
}
.admin-shell .ja-verdict.is-surveiller { border-left-color: var(--adm-warn); }
.admin-shell .ja-verdict.is-attention { border-left-color: var(--adm-dang); }
.admin-shell .ja-verdict-note { display: block; margin-top: .25rem; font-size: .78rem; color: var(--adm-muted); }
.admin-shell .ja-point {
    background: var(--card); border: 1px solid var(--line); border-left: 4px solid var(--line);
    border-radius: var(--radius-sm); padding: .7rem 1rem .6rem; margin-bottom: .6rem;
}
.admin-shell .ja-point.is-attention { border-left-color: var(--adm-dang); }
.admin-shell .ja-point.is-surveiller { border-left-color: var(--adm-warn); }
.admin-shell .ja-point.is-savoir { padding: .5rem 1rem .45rem; }
.admin-shell .ja-point-tete { display: flex; flex-wrap: wrap; align-items: baseline; gap: .35rem .6rem; }
.admin-shell .ja-point-titre { font-size: .9rem; }
.admin-shell .ja-quand { font-size: .74rem; margin-left: auto; color: var(--adm-muted); }
.admin-shell .ja-point-detail { margin: .3rem 0 .35rem; font-size: .84rem; line-height: 1.45; max-width: 90ch; }
.admin-shell .ja-point.is-savoir .ja-point-detail,
.admin-shell .ja-point .muted,
.admin-shell .ja-point .badge.muted { color: var(--adm-muted); }
.admin-shell .ja-cibles { list-style: none; margin: 0 0 .3rem; padding: 0; }
.admin-shell .ja-cibles li { display: flex; flex-wrap: wrap; align-items: center; gap: .2rem .6rem; padding: .22rem 0; border-top: 1px dashed var(--line); font-size: .82rem; }
.admin-shell .ja-cible { font-family: var(--adm-mono); font-weight: 600; overflow-wrap: anywhere; }
.admin-shell .ja-precision { font-size: .78rem; overflow-wrap: anywhere; min-width: 0; }
.admin-shell .ja-cibles .row-actions { margin-left: auto; }
.admin-shell .ja-point-pied { margin: .2rem 0 0; font-size: .78rem; }
.admin-shell .ja-sous-titre { margin: 1rem 0 .4rem; font-size: .72rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--adm-muted); }
/* L'anneau de focus d'une tuile était rogné par l'overflow de la grille : on le rentre dans la tuile. */
.admin-shell .stat-grid .stat-card:focus-visible { outline-offset: -3px; }
.admin-shell .ja-origine { font-size: .72rem; }
.admin-shell details.ja-techniques > summary { cursor: pointer; margin: 0; }
.admin-shell details.ja-techniques[open] > summary { margin-bottom: .8rem; }

/* ── État des écoles (veille super-admin) ─────────────────────────────────────────────────────
   Le détail d'une école dépliée : quatre blocs côte à côte, qui passent les uns sous les autres
   quand la place manque. La couleur reste portée par les badges des cases, jamais par ces blocs. */
.admin-shell .ee-detail { display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); gap: .8rem 1.6rem; padding: .3rem .2rem .5rem; }
.admin-shell .ee-titre { font-weight: 600; font-size: .78rem; margin: 0 0 .3rem; }
.admin-shell .ee-detail p { margin: .2rem 0; font-size: .78rem; }
.admin-shell .ee-liste { margin: 0 0 .35rem; padding-left: 1.1rem; font-size: .78rem; }
.admin-shell .ee-liste li { margin: .15rem 0; }
.admin-shell td[data-case] .muted { font-size: .7rem; margin-top: .15rem; }

/* ── AGENDA ──────────────────────────────────────────────────────────────────────────────────────
   Le calendrier de l'école (`templates/agenda/`). Trois vues, un tiroir.
   ⚠️ La couleur d'un événement est celle de sa CATÉGORIE, une donnée de l'école : elle arrive par la
   variable `--ag-c` posée sur l'élément, jamais en dur ici.
   ⚠️ Le quadrillage est peint par le `gap` sur un fond `--line` : aucune bordure de cellule.
   ⚠️ Tout `[hidden]` du formulaire est forcé : `.field-edit` est en `display:flex`, qui l'emporterait. */
.ag-barre { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem 1rem; margin-bottom: .9rem; }
.ag-seg .seg-btn { display: inline-flex; align-items: center; text-decoration: none; }
.ag-nav { gap: .25rem; }
.ag-titre { margin: 0; padding: 0 .35rem; font-size: 1.05rem; min-width: 11ch; text-align: center; }
.ag-filtre { margin-left: auto; }
.ag-filtre .input { min-width: 13rem; }

.ag-grille { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 1px; background: var(--line);
    border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }
.ag-dow { background: var(--bg); padding: .35rem .5rem; font-size: .75rem; font-weight: 700; color: var(--muted); text-transform: uppercase; }
.ag-case { position: relative; min-width: 0; min-height: 6.4rem; padding: 1.7rem .3rem .35rem; background: var(--card);
    display: flex; flex-direction: column; gap: .2rem; }
.ag-case.is-weekend { background: color-mix(in srgb, var(--bg) 45%, var(--card)); }
.ag-case.is-hors { background: var(--bg); }
.ag-case.is-hors .ag-num { color: var(--muted); }
.ag-num { position: absolute; top: .3rem; left: .45rem; z-index: 1; pointer-events: none; font-size: .82rem; font-weight: 700;
    color: var(--ink); font-variant-numeric: tabular-nums; }
.ag-case.is-today .ag-num { background: var(--primary); color: #fff; border-radius: 999px; padding: 0 .45rem; }
/* Toute la case pose un événement : le lien la couvre, pastilles et « +N » passent au-dessus. */
.ag-add { position: absolute; inset: 0; z-index: 0; display: flex; justify-content: flex-end; align-items: flex-start;
    padding: .25rem .45rem; color: var(--primary); font-weight: 700; text-decoration: none; }
.ag-add span { opacity: 0; transition: opacity .12s; }
.ag-add:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
.ag-add:focus-visible span { opacity: 1; }
@media (hover: hover) { .ag-add:hover { background: var(--primary-soft); } .ag-add:hover span { opacity: 1; } }
@media (hover: none) { .ag-add span { opacity: .45; } }
.ag-chip, .ag-plus { position: relative; z-index: 1; }
.ag-chip { display: flex; align-items: baseline; gap: .3rem; min-width: 0; padding: .12rem .4rem; border-radius: 6px;
    border-left: 3px solid var(--ag-c); background: color-mix(in srgb, var(--ag-c) 13%, var(--card));
    font-size: .78rem; line-height: 1.3; color: var(--ink); text-decoration: none; }
.ag-chip:hover { background: color-mix(in srgb, var(--ag-c) 24%, var(--card)); color: var(--ink); }
/* Assombrie : du blanc sur un vert ou un orange clairs passe sous le contraste lisible (4,5:1). */
.ag-chip.is-journee { background: color-mix(in srgb, var(--ag-c) 72%, #000); color: #fff; }
.ag-chip.is-journee:hover { filter: brightness(1.08); color: #fff; }
.ag-chip-h { flex-shrink: 0; font-weight: 700; font-variant-numeric: tabular-nums; }
.ag-chip-t { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ag-case:not(.is-deplie) .ag-chip.is-cache { display: none; }
/* Dans le mois, un titre garde deux lignes avant de se couper : « Permane… » ne dit rien. */
.ag-mois .ag-chip { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.ag-mois .ag-chip-h { margin-right: .25rem; }
.ag-mois .ag-chip-t { display: inline; white-space: normal; }
/* Dans le mois, la couleur dit la catégorie : l'emoji mangerait la première ligne du titre. */
.ag-mois .ag-chip-e { display: none; }
.ag-plus { align-self: flex-start; padding: .05rem .4rem; border: 0; background: none; cursor: pointer;
    font: inherit; font-size: .75rem; font-weight: 600; color: var(--primary-dark); }
.ag-plus[hidden] { display: none; }

.ag-semaine .ag-case { min-height: 15rem; padding-top: 1.9rem; }
.ag-semaine .ag-chip { flex-direction: column; align-items: stretch; gap: 0; }
.ag-semaine .ag-chip-t { white-space: normal; }
.ag-jour-nom { margin-right: .15rem; color: var(--muted); font-weight: 600; }
.ag-vide { position: relative; z-index: 1; pointer-events: none; color: var(--muted); font-size: .8rem; }

.ag-jour { display: grid; gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }
.ag-hrow { display: grid; grid-template-columns: 5rem minmax(0, 1fr); min-height: 3rem; background: var(--card); }
.ag-hh { padding: .45rem .6rem; background: var(--bg); color: var(--muted); font-size: .8rem; font-weight: 700; font-variant-numeric: tabular-nums; }
.ag-hrow-journee .ag-hh { color: var(--ink); }
.ag-hin { position: relative; min-width: 0; padding: .35rem .45rem; display: flex; flex-wrap: wrap; align-content: flex-start; gap: .3rem; }
.ag-hin .ag-chip { max-width: 100%; }

@media (max-width: 640px) {
    .ag-filtre { margin-left: 0; width: 100%; }
    .ag-filtre .input { min-width: 0; width: 100%; }
    .ag-mois .ag-case { min-height: 4.4rem; padding: 1.5rem .15rem .2rem; }
    .ag-mois .ag-chip { padding: .05rem .2rem; font-size: .66rem; }
    .ag-mois .ag-chip-h { display: none; }
    .ag-dow { padding: .3rem .2rem; font-size: .66rem; }
    .ag-semaine { grid-template-columns: minmax(0, 1fr); }
    .ag-semaine .ag-case { min-height: 3.5rem; }
    .ag-hrow { grid-template-columns: 3.6rem minmax(0, 1fr); }
}

/* Le tiroir de consultation. */
.ag-fiche-cat { display: flex; align-items: center; gap: .45rem; margin: 0; font-weight: 600; }
.ag-pastille { width: .8rem; height: .8rem; flex-shrink: 0; border-radius: 50%; background: var(--ag-c); }
.ag-fiche { display: grid; grid-template-columns: minmax(8rem, max-content) minmax(0, 1fr); gap: .5rem 1rem; margin: 0; }
.ag-fiche dt { color: var(--muted); font-size: .85rem; font-weight: 600; }
.ag-fiche dd { margin: 0; overflow-wrap: anywhere; }
.ag-auteur { margin: 0; font-size: .8rem; }
.ag-supprimer { margin-left: auto; }
@media (max-width: 640px) { .ag-fiche { grid-template-columns: minmax(0, 1fr); gap: .15rem; } .ag-fiche dd { margin-bottom: .45rem; } }

/* Le tiroir de saisie : le tiroir large pose déjà ses deux colonnes. */
.drawer-large .ag-plein { grid-column: 1 / -1; }
.ag-col { display: flex; flex-direction: column; gap: .7rem; min-width: 0; }
.ag-col .card-title { margin: .5rem 0 0; }
.ag-aide { margin: 0; font-size: .82rem; }
/* Le <label for> d'un champ de fiche prend l'allure des intitulés `.field-edit > span`. */
.field-edit > .ag-libelle { font-size: .85rem; font-weight: 600; color: var(--muted); }
.ag-raisons { margin: .3rem 0 0; padding-left: 1.1rem; }
.ag-fiche-champs { min-width: 0; margin: 0; padding: 0; border: 0; }
/* La saisie : deux cadres de même largeur. À gauche, la fiche dans un panneau à la couleur de sa
   catégorie (liseré à gauche, fond à peine teinté) ; sans catégorie, le panneau reste neutre. */
.drawer-large.ag-saisie .drawer-body { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: stretch; }
@media (max-width: 900px) { .drawer-large.ag-saisie .drawer-body { grid-template-columns: minmax(0, 1fr); } }
.ag-cadre { background: var(--card); border: 1px solid var(--line); border-radius: 14px; padding: 1rem 1.1rem 1.1rem; }
.ag-sec { display: flex; align-items: center; gap: .6rem; margin: .6rem 0 0; font-size: .74rem; font-weight: 800;
    letter-spacing: .07em; text-transform: uppercase; color: var(--muted); }
.ag-sec::after { content: ""; flex: 1; height: 1px; background: var(--line); }
.ag-cadre > .ag-sec:first-child { margin-top: 0; }
.ag-panneau { --ag-c: var(--line); display: flex; flex-direction: column; gap: .9rem; min-width: 0; padding: .9rem 1rem 1rem;
    border: 1px solid color-mix(in srgb, var(--ag-c) 30%, var(--line)); border-left: 4px solid var(--ag-c); border-radius: 12px;
    background: color-mix(in srgb, var(--ag-c) 5%, var(--card)); }
.ag-panneau-tete { display: flex; align-items: center; gap: .65rem; margin-bottom: .85rem; }
.ag-panneau-tete strong { display: block; font-size: .95rem; }
.ag-panneau-tete small { display: block; color: var(--muted); font-size: .8rem; }
.ag-panneau-ic { display: grid; place-items: center; flex: none; width: 2.1rem; height: 2.1rem; border-radius: 10px;
    background: color-mix(in srgb, var(--ag-c) 16%, var(--card)); font-size: 1.1rem; }
.ag-panneau-lien { padding-top: .8rem; border-top: 1px dashed color-mix(in srgb, var(--ag-c) 35%, var(--line)); }
.ag-attente { margin: 0; padding: .7rem .8rem; border: 1px dashed var(--line); border-radius: 10px; background: var(--card); color: var(--muted); font-size: .9rem; }
.ag-parametrer { align-self: flex-end; font-size: .8rem; font-weight: 600; color: var(--muted); text-decoration: none; }
.ag-parametrer:hover { color: var(--primary-dark); }
/* Une case « oui / non » n'a pas d'intitulé au-dessus : on la centre face à son voisin de ligne. */
.ag-champ:has(> .opt) { justify-content: center; }
.ag-tiroir form [hidden] { display: none !important; }
/* La palette d'emojis d'une catégorie : les suggestions du nom, puis les thèmes ; l'emoji choisi est cerclé. */
.ag-emoji { gap: .35rem; }
.ag-emoji-champ { font-size: 1.3rem; text-align: center; }
.ag-emoji-suggestions { display: flex; flex-direction: column; gap: .25rem; padding: .5rem .6rem; border: 1px solid var(--line); border-radius: 10px;
    background: color-mix(in srgb, var(--primary-soft) 60%, var(--card)); }
.ag-emoji-palette { display: flex; flex-direction: column; gap: .25rem; max-height: 15rem; overflow-y: auto; padding: .5rem .6rem;
    border: 1px solid var(--line); border-radius: 10px; background: var(--card); }
.ag-emoji-theme { font-size: .72rem; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--muted); margin-top: .2rem; }
.ag-emoji-grille { display: flex; flex-wrap: wrap; gap: .2rem; }
.ag-emoji-btn { width: 2.2rem; height: 2.2rem; display: grid; place-items: center; font-size: 1.25rem; line-height: 1;
    border: 1.5px solid transparent; border-radius: 8px; background: none; cursor: pointer; }
.ag-emoji-btn:hover { background: var(--bg); }
.ag-emoji-btn[aria-pressed="true"] { border-color: var(--primary); background: var(--primary-soft); }
/* Un congé scolaire ou un férié, lu dans les fermetures des Présences : une bande en lecture seule, et la
   case à peine grisée. Ni lien ni couleur de catégorie : ce n'est pas un événement de l'agenda. */
.ag-case.is-conge { background: color-mix(in srgb, var(--muted) 7%, var(--card)); }
.ag-conge { display: block; position: relative; z-index: 1; padding: .1rem .4rem; border: 1px dashed var(--line); border-radius: 6px;
    color: var(--muted); font-size: .76rem; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ag-opts { display: flex; flex-wrap: wrap; gap: .35rem; }
.ag-opts-liste { max-height: 14rem; overflow-y: auto; padding: .15rem; }
.ag-opt { display: inline-flex; align-items: center; gap: .35rem; padding: .28rem .65rem; border: 1.5px solid var(--line);
    border-radius: 999px; cursor: pointer; font-size: .88rem; transition: border-color .12s, background .12s; }
.ag-opt input { position: absolute; opacity: 0; width: 0; height: 0; }
.ag-opt .avatar { margin-left: -.2rem; }
.ag-opt:hover { border-color: var(--primary); }
.ag-opt:has(input:checked) { border-color: var(--primary); background: var(--primary-soft); font-weight: 600; }
.ag-opt:has(input:focus-visible) { outline: 2px solid var(--primary); outline-offset: 1px; }
.ag-heure { display: flex; gap: .4rem; }
.ag-heure .input { flex: 1 1 0; min-width: 0; height: 48px; }
.ag-lignes { display: flex; flex-direction: column; gap: .35rem; }
.ag-ligne { display: flex; flex-wrap: wrap; align-items: center; gap: .35rem; }
.ag-ligne > select, .ag-ligne > input:not(.ag-nom-libre) { flex: 1 1 0; min-width: 0; }
.ag-nom-libre { flex: 1 1 100%; order: 2; }
.ag-ajout { align-self: flex-start; }
.ag-ajouts { display: flex; flex-wrap: wrap; gap: .35rem; }
/* La répartition des élèves : une carte par classe d'accueil, ses élèves en pastilles à cocher. */
.ag-repartition { display: flex; flex-direction: column; gap: .5rem; }
.ag-rep-ligne { display: flex; flex-direction: column; gap: .4rem; padding: .55rem .6rem; border: 1px solid var(--line); border-radius: 10px; background: var(--card); }
.ag-rep-tete { display: flex; align-items: center; gap: .35rem; }
.ag-rep-tete > select { flex: 1 1 0; min-width: 0; }
.ag-rep-eleves:empty { display: none; }

/* Paramétrage de l'agenda : une catégorie ou un champ masqué se lit en retrait. */
.ag-masquee td { opacity: .6; }
.ag-param .epi-sub-jour { white-space: normal; }
/* Un nom de 120 caractères ne pousse pas la colonne d'actions hors du tableau (`.table-wrap` coupe). */
.ag-nom-categorie { display: inline-block; max-width: 22rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom; }

/* La liste des événements : les cartes par catégorie, puis la liste d'une catégorie. */
.ag-cartes { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 16rem), 1fr)); gap: .8rem; }
.ag-carte { display: flex; flex-direction: column; gap: .35rem; border-top: 4px solid var(--ag-c); color: var(--ink); text-decoration: none; transition: box-shadow .12s, transform .12s; }
.ag-carte:hover { box-shadow: var(--shadow); transform: translateY(-1px); color: var(--ink); }
.ag-carte-titre { display: flex; align-items: center; gap: .45rem; font-weight: 700; }
.ag-carte-comptes { font-size: .9rem; }
.ag-carte-prochain { font-size: .82rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ag-pastille-titre { display: inline-block; margin-right: .5rem; vertical-align: middle; }
.ag-liste .ag-mois-titre th { background: var(--bg); text-align: left; font-size: .8rem; text-transform: uppercase; letter-spacing: .03em; color: var(--muted); }
.ag-liste-cadre { overflow-x: auto; }
.ag-liste-cadre[hidden] { display: none; }
.ag-quand { white-space: nowrap; }
.ag-quand > span { display: block; font-size: .8rem; }
.ag-resume { font-size: .85rem; overflow-wrap: anywhere; }
@media (max-width: 640px) { .ag-places { display: none; } }
@media (max-width: 640px) { .ag-liste th:nth-child(3), .ag-liste td:nth-child(3) { display: none; } }
.ag-resume > span { display: block; }

/* « Qui a participé ? » sur la fiche d'une activité avec élèves. */
.ag-participation { display: flex; flex-direction: column; gap: .6rem; border-top: 1px solid var(--line); padding-top: .8rem; }
.ag-participation .card-title { margin: 0; }
.ag-seances { display: flex; flex-wrap: wrap; align-items: center; gap: .3rem; margin: 0; font-size: .85rem; }
.ag-seances a { text-decoration: none; }
.ag-participation-classe h4 { margin: 0 0 .25rem; font-size: .95rem; }
.ag-participation-classe p { margin: .15rem 0; font-size: .88rem; }
.ag-participation-classe .ag-alerte { display: block; margin: .2rem 0; padding: .35rem .6rem; font-size: .85rem; }
