/* ============================================================
   style.css — AFM Stiring — Design V2
   Sidebar sombre + palette ambre/vert — Notion/Slack inspired
   ============================================================ */

/* ═══════════════════════════════════════════════════════════════
   SOMMAIRE — l'ordre des sections est voulu (étape H de
   docs/REMISE-EN-ORDRE.md), il décide de qui l'emporte à poids égal.
   ═══════════════════════════════════════════════════════════════
     1. Polices, variables, palettes
     2. Base et mise en page
     3. Navigation
     4. Socle commun (en-têtes, champs, boutons, cartes, tableaux…)
     5. Écrans — portail, accueils, secrétariat
     6. Écrans — administration
     7. Mode sombre des anciens écrans (« Inline style overrides »)
     8. Écrans — trésorerie
     9. Écrans — école arabe
    10. Le moule commun — APRÈS les écrans : écrit pour l'emporter
        sur leurs anciennes règles (barres de filtres, replis, menus,
        bulle ⓘ, listes, glisser).
    11. Téléphone et écran tactile (règles globales), animations,
        impression — en dernier : elles s'appliquent à tout.
   ⛔ Une règle d'un écran va dans sa section (5, 6, 8, 9) ; un
   élément commun nouveau va dans le moule (10). Déplacer une règle change la
   cascade : contrôle « 0 écart » (styles calculés) après coup.

   SEUILS D'ÉCRAN (étape L) — un seul seuil téléphone : 768 px.
     · « @media (max-width: 768px) » : le téléphone. Une règle du
       téléphone ne prend pas 480 / 600 / 640 px : entre deux seuils,
       l'écran avait moitié une présentation, moitié l'autre.
     · « @media (min-width: 769px) » : l'ordinateur seul.
     · 400 / 360 px : retouches des petits téléphones (iPhone SE…),
       en plus de la règle à 768, jamais à sa place.
     · 1100 px (et 1099) : la barre du haut et les grilles larges.
     · 900 / 1000 / 1160 / 1360 px : grilles d'un écran précis
       (nombre de colonnes) — exceptions voulues, ne pas multiplier.
   ═══════════════════════════════════════════════════════════════ */

/* ███████████████████████████████████████████████████████████████
   1. POLICES, VARIABLES, PALETTES
   ███████████████████████████████████████████████████████████████ */

/* ============================================================
   DM Sans — hébergée en local (assets/fonts/)
   SIL Open Font License 1.1 — voir assets/fonts/OFL.txt

   Remplace l'ancien @import vers fonts.googleapis.com, qui était
   silencieusement BLOQUÉ par la Content-Security-Policy définie dans
   .htaccess (style-src 'self' / font-src 'self') : le site tournait
   en réalité sur la police de repli.

   Fichier variable unique (wght 400→700) au lieu de 4 graisses
   séparées : une seule requête, et plus aucun aller-retour vers Google.
   ============================================================ */

@font-face {
    font-family: 'DM Sans';
    font-style: normal;
    font-weight: 400 700;          /* plage variable */
    font-display: swap;
    src: url('../fonts/DMSans-var.woff2') format('woff2-variations'),
         url('../fonts/DMSans-var.woff2') format('woff2');
}

@font-face {
    font-family: 'DM Sans';
    font-style: italic;
    font-weight: 400;
    font-display: swap;
    src: url('../fonts/DMSans-Italic.woff2') format('woff2');
}

/* ============================================================
   Refonte B2·3 (étape 1, 06/10/2026) — deux polices, en local
   pour la même raison que DM Sans (CSP font-src 'self').
   Atkinson Hyperlegible Next : le texte. Dessinée pour les
   malvoyants (lettres qu'on ne confond pas : l / I / 1, 0 / O),
   choisie parce qu'une partie des utilisateurs sont âgés.
   Lexend : titres et chiffres.
   Fichiers variables découpés par alphabet (Fontsource) : le
   navigateur ne charge « latin-ext » que si une page contient
   une lettre qui en a besoin (Ş, Ğ… dans un nom). Licence OFL.
   DM Sans reste déclarée : plus aucun écran ne la demande (les PDF
   la nomment, mais mPDF ne lit pas cette feuille) ; la retirer se
   fera au ménage de fin de refonte.
   ============================================================ */
@font-face {
    font-family: 'Atkinson Hyperlegible Next';
    font-style: normal; font-weight: 200 800; font-display: swap;
    src: url('../fonts/atkinson-hyperlegible-next-latin-ext-wght-normal.woff2') format('woff2');
    unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
@font-face {
    font-family: 'Atkinson Hyperlegible Next';
    font-style: normal; font-weight: 200 800; font-display: swap;
    src: url('../fonts/atkinson-hyperlegible-next-latin-wght-normal.woff2') format('woff2');
    unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
    font-family: 'Atkinson Hyperlegible Next';
    font-style: italic; font-weight: 200 800; font-display: swap;
    src: url('../fonts/atkinson-hyperlegible-next-latin-wght-italic.woff2') format('woff2');
}
@font-face {
    font-family: 'Lexend';
    font-style: normal; font-weight: 100 900; font-display: swap;
    src: url('../fonts/lexend-latin-ext-wght-normal.woff2') format('woff2');
    unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}
@font-face {
    font-family: 'Lexend';
    font-style: normal; font-weight: 100 900; font-display: swap;
    src: url('../fonts/lexend-latin-wght-normal.woff2') format('woff2');
    unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

/* ═══════════════════════════════════════════════════
   DESIGN TOKENS — Light
   ═══════════════════════════════════════════════════ */
:root {

    /*  Largeur de la colonne de page, partagée par le contenu
        (.main-content) ET l'intérieur de la barre du haut et des onglets :
        sur un grand écran, logo, pilules et onglets commencent au bord
        gauche du contenu, recherche et compte s'arrêtent à son bord droit
        (demande de l'utilisateur, 07/10/2026 : la barre allait d'un bord à
        l'autre de l'écran, le contenu restait une colonne au milieu).
        --page-pad = marge intérieure, la même des deux côtés. */
    --page-max: 1440px;
    --page-pad: 40px;

    /*  Une couleur par enseignant dans la Semaine type (08/10/2026) :
        huit teintes bien distinctes, assez foncées pour un nom écrit
        dessus sur fond clair. Le rang de l'enseignant (ordre de création)
        choisit la teinte, modulo 8. */
    --prof-1: #2563eb; --prof-2: #c2410c; --prof-3: #15803d; --prof-4: #854d0e;
    --prof-5: #be123c; --prof-6: #0e7490; --prof-7: #db2777; --prof-8: #4d7c0f;

    /*  Fond bleu nuit de la page de connexion (le nom vient de l’ancienne
        barre latérale, retirée à l’étape 2 de la refonte). */
    --sidebar-bg: #1b2030;

    /* Surfaces */
    /*  Refonte B2·3 « Lumière » (étape 1, 06/10/2026) : fond gris bleuté,
        cartes blanches, texte bleu nuit. Valeurs et raisons dans
        docs/REFONTE-INTERFACE.md, section 4. Les NOMS ne changent pas :
        les ~4 000 règles du fichier lisent ces variables. */
    --color-bg:         #f4f6fa;
    --color-surface:    #ffffff;
    --color-surface-alt:#f7f8fb;
    --color-border:     #e3e7ef;
    --color-border-strong: #c8cfdb;

    /* Text */
    --color-text:       #1b2030;
    --color-muted:      #5a6275;
    --color-text-tertiary: #676e80;

    /* Accents — trésorerie doré (accent par défaut, aussi portail et
       Administration), secrétariat vert, école violet. -lt = fond très
       pâle, -mid = la pastille du module. */
    /*  Doré B (07/10/2026, l'utilisateur voyait de l'orange dans #8a6400) :
        un doré foncé plus jaune pour le texte (5,8:1 sur blanc), et un vrai
        or clair pour les aplats (--color-primary-fond), texte foncé dessus. */
    --color-primary:    #76640a;
    --color-primary-dk: #5e5008;
    --color-primary-lt: #fcf8e6;
    --color-primary-mid:#f6e7a6;
    /*  Les aplats d'accent (bouton principal, pagination, pastilles…) et le
        texte posé dessus. Distincts de --color-primary pour la seule
        Trésorerie : un or lisible en texte serait trop foncé en aplat.
        Les autres modules les ramènent à leur couleur (bloc « ACCENT PAR
        MODULE »). */
    --color-primary-fond:    #d9b23c;
    --color-primary-fond-dk: #c9a227;
    --color-on-fond:         #1b2030;
    --color-accent:     #0b7450;
    --color-accent-dk:  #085a3e;
    --color-accent-lt:  #eef9f3;
    --color-accent-mid: #ddf4e8;
    /* Module école arabe — violet, distinct du doré (tréso),
       du vert (secrétariat) et du bleu --color-info (badge bureau) */
    --color-ecole:      #5a3fd6;
    /*  Pilule du module Trésorerie dans la barre du haut : --color-primary
        prend la couleur du module de la page, celle-ci jamais. */
    --color-treso:      #76640a;
    --color-treso-mid:  #f6e7a6;
    --color-treso-fond: #d9b23c;
    --color-ecole-dk:   #4630b0;
    --color-ecole-lt:   #f6f4ff;
    --color-ecole-mid:  #efebff;

    /* Semantic */
    --color-danger:     #be2d35;
    --color-danger-lt:  #fce8e9;
    --color-success:    #1a7340;
    --color-success-lt: #e1f4e8;
    --color-warning:    #a8480b;
    --color-warning-lt: #ffeedd;
    --color-info:       #2563c4;
    --color-info-lt:    #e6eefc;

    /* Shapes — coins plus ronds (champ 12, carte 18, feuille 24) et
       ombre douce bleu nuit. */
    --radius:           12px;
    --radius-lg:        18px;
    --radius-xl:        24px;
    --shadow:           0 1px 2px var(--pal-encre-bleu-a05), 0 6px 20px var(--pal-encre-bleu-a06);
    --shadow-md:        0 6px 20px var(--pal-encre-bleu-a10);
    --shadow-lg:        0 16px 40px var(--pal-encre-bleu-a22);
    --transition:       .15s ease;

    /* Font — texte en Atkinson Hyperlegible Next, titres et chiffres
       en Lexend (voir les @font-face en tête du fichier). */
    --font: 'Atkinson Hyperlegible Next', system-ui, -apple-system, sans-serif;
    --font-title: 'Lexend', 'Atkinson Hyperlegible Next', system-ui, sans-serif;
    /*  Teintes des états (alertes, badges, boutons colorés) — 06/10/2026.
        Elles étaient écrites en dur, recopiées d'écran en écran ; chacune
        a désormais un nom et une valeur par thème (bloc sombre plus bas).
        -soft = fond pâle, -text = texte, -border = bordure.
        ⛔ Une couleur d'état ajoutée demain prend l'une de ces variables
        plutôt qu'un code couleur, sinon le thème sombre l'oubliera. */
    /*  L'orange d'avertissement, à part de l'accent : l'accent prend la
        couleur du module (indigo à l'école, vert au secrétariat), une
        alerte « en attente » doit rester orange partout. Mêmes valeurs
        que l'ancien accent : rien ne bouge en trésorerie. */
    --color-warning-vif: #d4650f;
    --color-warning-dk:  #9a430a;
    --color-warning-mid: #ffe2c2;
    /*  Anneau des champs actifs et voile d'un onglet choisi : suivent
        l'accent, donc le module. */
    --color-primary-ring: var(--pal-dore-a16);
    /*  Texte posé sur une couleur vive — accent du module (boutons
        principaux, pastilles, onglet actif) ou couleur d'alerte (pastille
        de notification, rouge, vert, orange) : blanc en clair ; foncé en
        sombre, où ces couleurs s'éclaircissent et un texte blanc ne se
        lisait plus. */
    --color-on-accent: var(--pal-blanc);
    --color-primary-wash: var(--pal-dore-a06);
    --color-danger-soft: #fce8e9;
    --color-danger-border: #f3c0c3;
    --color-warning-soft: #ffeedd;
    --color-warning-text: #8f3f08;
    --color-warning-border: #f8cfa6;
    --color-success-soft: #e1f4e8;
    --color-success-text: #17643a;
    --color-success-border: #b3e0c3;
    --color-info-soft: #e6eefc;
    --color-info-text: #1d4e9e;
    --color-gold-soft: #fff3cc;
    --color-gold-text: #7a5800;
    --color-gold-border: #e3c46a;
    /*  Fonds, traits et textes neutres, et les deux teintes des types de
        réunion (rose : AG extraordinaire, violet : commission). Écrits
        en dur, ils restaient clairs en mode sombre (texte illisible). */
    --color-subtle: #f7f8fb;
    --color-line: #e3e7ef;
    --color-neutral-soft: #eceff5;
    --color-neutral-text: #5a6275;
    --color-success-mid: #d2eedc;
    --color-pink-soft: #fce7f3;
    --color-pink-text: #9d174d;
    --color-purple-soft: #f3e8ff;
    --color-purple-text: #6b21a8;
    /*  Constantes de couleur (06/10/2026) : la même valeur dans les deux
        thèmes — barre latérale toujours sombre, pastilles vives à texte
        blanc, aperçus « papier » (CERFA, courriers), bandeaux test / local,
        nuances propres au thème sombre, voiles et ombres (-aNN = opacité).
        Rangées ici pour qu'un changement d'esthétique se fasse à UN seul
        endroit. ⛔ Une couleur ajoutée demain prend une variable, jamais un
        code couleur : une couleur qui doit changer avec le thème va dans
        les variables --color-* (clair ici, sombre dans le bloc sombre). */
    --pal-vert-100: #dcfce7;
    --pal-vert-sapin: #0f6e56;
    --pal-indigo-400: #818cf8;
    --pal-indigo-800: #3730a3;
    --pal-ardoise-bleue: #5a7184;
    --pal-gris-neutre: #888888;
    --pal-bleu-petrole-a13: rgba(26,82,118,.1333);
    --pal-or-brun-a13: rgba(133,79,11,.1333);
    --pal-vert-sapin-a13: rgba(15,110,86,.1333);
    --pal-ambre-300: #fcd34d;
    --pal-ambre-400: #fbbf24;
    --pal-ambre-50: #fffbeb;
    --pal-ambre-500: #f59e0b;
    --pal-ambre-600: #d97706;
    --pal-ambre-800: #92400e;
    --pal-ambre-sombre-survol: #3a3520;
    --pal-ardoise-700: #334155;
    --pal-blanc: #ffffff;
    --pal-bleu-200: #bfdbfe;
    --pal-bleu-300: #93c5fd;
    --pal-bleu-600: #2563eb;
    --pal-bleu-700: #1d4ed8;
    --pal-bleu-800: #1e40af;
    --pal-bleu-marine: #1a3a5c;
    --pal-bleu-nuit: #1e3a5f;
    --pal-bleu-petrole: #1a5276;
    --pal-brique: #c0392b;
    --pal-brique-fonce: #7b241c;
    --pal-ciel-100: #e0f2fe;
    --pal-ciel-200: #bae6fd;
    --pal-ciel-700: #0369a1;
    --pal-ciel-800: #075985;
    --pal-ciel-900: #0c4a6e;
    --pal-ciel-nuit: #2a4a5e;
    --pal-code-sombre: #222222;
    --pal-code-sombre-2: #2a2a2a;
    --pal-cyan-300: #67e8f9;
    --pal-cyan-50: #ecfeff;
    --pal-cyan-700: #0e7490;
    --pal-cyan-nuit: #2a4a50;
    --pal-emeraude-200: #a7f3d0;
    --pal-emeraude-300: #6ee7b7;
    --pal-emeraude-400: #34d399;
    --pal-emeraude-600: #059669;
    --pal-emeraude-800: #065f46;
    --pal-encre: #1a1a1a;
    --pal-gris-100: #f3f4f6;
    --pal-gris-700: #374151;
    --pal-gris-clair: #bbbbbb;
    --pal-gris-fonce: #555555;
    --pal-gris-fond: #f0f0f0;
    --pal-gris-fond-froid: #f4f5f7;
    --pal-gris-moyen: #666666;
    --pal-gris-pale: #e5e5e5;
    --pal-gris-sombre: #333333;
    --pal-gris-trait: #cccccc;
    --pal-indigo-200: #c7d2fe;
    --pal-indigo-300: #a5b4fc;
    --pal-indigo-500: #6366f1;
    --pal-indigo-600: #4f46e5;
    --pal-indigo-700: #4338ca;
    --pal-jaune-100: #fef9c3;
    --pal-jaune-800: #854d0e;
    --pal-lavande-pale: #eeedf5;
    --pal-noir: #000000;
    --pal-nuit: #1a1a2e;
    --pal-or: #c9a84c;
    --pal-or-100: #fdf3d7;
    --pal-or-25: #fffdf5;
    --pal-or-50: #fef9ec;
    --pal-or-brun: #854f0b;
    --pal-or-clair: #e5c94c;
    --pal-or-nuit: #2a2515;
    --pal-or-nuit-2: #1f1a0d;
    --pal-or-sombre: #b8860b;
    --pal-or-texte: #7a5c00;
    --pal-orange-600: #ea580c;
    --pal-orange-700: #c2410c;
    --pal-pourpre-700: #7e22ce;
    --pal-rose-800: #9d174d;
    --pal-rose-pale: #f5c6cb;
    --pal-rouge-100: #fee2e2;
    --pal-rouge-200: #fecaca;
    --pal-rouge-300: #fca5a5;
    --pal-rouge-400: #f87171;
    --pal-rouge-500: #ef4444;
    --pal-rouge-600: #dc2626;
    --pal-rouge-900: #7f1d1d;
    --pal-rouge-sombre-survol: #3a2020;
    --pal-turquoise: #3bb8c4;
    --pal-vert-200: #bbf7d0;
    --pal-vert-300: #86efac;
    --pal-vert-600: #16a34a;
    --pal-vert-800: #166534;
    --pal-violet-100: #ede9fe;
    --pal-violet-300: #c4b5fd;
    --pal-violet-400: #a78bfa;
    --pal-violet-600: #7c3aed;
    --pal-violet-800: #5b21b6;
    --pal-violet-950: #2e1065;
    --pal-violet-nuit: #1e1a30;
    --pal-ambre-400-a12: rgba(251,191,36,.12);
    --pal-ambre-400-a20: rgba(251,191,36,.2);
    --pal-ambre-400-a30: rgba(251,191,36,.3);
    --pal-ambre-500-a06: rgba(245,158,11,.06);
    --pal-ambre-500-a15: rgba(245,158,11,.15);
    --pal-ambre-600-a06: rgba(217,119,6,.06);
    --pal-ambre-600-a10: rgba(217,119,6,.1);
    --pal-ambre-600-a12: rgba(217,119,6,.12);
    --pal-ambre-600-a18: rgba(217,119,6,.18);
    --pal-ambre-600-a20: rgba(217,119,6,.2);
    --pal-blanc-a02: rgba(255,255,255,.02);
    --pal-blanc-a04: rgba(255,255,255,.04);
    --pal-blanc-a05: rgba(255,255,255,.05);
    --pal-blanc-a06: rgba(255,255,255,.06);
    --pal-blanc-a08: rgba(255,255,255,.08);
    --pal-blanc-a10: rgba(255,255,255,.1);
    --pal-blanc-a12: rgba(255,255,255,.12);
    --pal-blanc-a25: rgba(255,255,255,.25);
    --pal-blanc-a35: rgba(255,255,255,.35);
    --pal-blanc-a40: rgba(255,255,255,.4);
    --pal-blanc-a50: rgba(255,255,255,.5);
    --pal-blanc-a55: rgba(255,255,255,.55);
    --pal-blanc-a70: rgba(255,255,255,.7);
    --pal-blanc-a80: rgba(255,255,255,.8);
    --pal-blanc-a88: rgba(255,255,255,.88);
    --pal-bleu-400-a06: rgba(96,165,250,.06);
    --pal-bleu-500-a12: rgba(59,130,246,.12);
    --pal-bleu-500-a20: rgba(59,130,246,.2);
    --pal-bleu-500-a30: rgba(59,130,246,.3);
    --pal-bleu-600-a08: rgba(37,99,235,.08);
    --pal-bleu-600-a10: rgba(37,99,235,.1);
    --pal-bleu-600-a15: rgba(37,99,235,.15);
    --pal-bleu-600-a25: rgba(37,99,235,.25);
    --pal-bleu-600-a35: rgba(37,99,235,.35);
    --pal-bleu-700-a02: rgba(29,78,216,.02);
    --pal-bleu-700-a03: rgba(29,78,216,.03);
    --pal-bleu-700-a04: rgba(29,78,216,.04);
    --pal-bleu-700-a06: rgba(29,78,216,.06);
    --pal-bleu-700-a08: rgba(29,78,216,.08);
    --pal-bleu-petrole-a12: rgba(26,82,118,.12);
    --pal-emeraude-600-a06: rgba(5,150,105,.06);
    --pal-emeraude-600-a12: rgba(5,150,105,.12);
    --pal-emeraude-600-a15: rgba(5,150,105,.15);
    --pal-emeraude-600-a18: rgba(5,150,105,.18);
    --pal-emeraude-600-a20: rgba(5,150,105,.2);
    --pal-indigo-600-a06: rgba(79,70,229,.06);
    --pal-indigo-600-a14: rgba(79,70,229,.14);
    --pal-indigo-600-a15: rgba(79,70,229,.15);
    --pal-indigo-600-a22: rgba(79,70,229,.22);
    --pal-indigo-600-a24: rgba(79,70,229,.24);
    --pal-noir-a02: rgba(0,0,0,.02);
    --pal-noir-a03: rgba(0,0,0,.03);
    --pal-noir-a04: rgba(0,0,0,.04);
    --pal-noir-a05: rgba(0,0,0,.05);
    --pal-noir-a06: rgba(0,0,0,.06);
    --pal-noir-a08: rgba(0,0,0,.08);
    --pal-noir-a10: rgba(0,0,0,.1);
    --pal-noir-a12: rgba(0,0,0,.12);
    --pal-noir-a15: rgba(0,0,0,.15);
    --pal-noir-a20: rgba(0,0,0,.2);
    --pal-noir-a25: rgba(0,0,0,.25);
    --pal-noir-a30: rgba(0,0,0,.3);
    --pal-noir-a40: rgba(0,0,0,.4);
    --pal-noir-a45: rgba(0,0,0,.45);
    --pal-noir-a50: rgba(0,0,0,.5);
    --pal-noir-a55: rgba(0,0,0,.55);
    --pal-noir-a60: rgba(0,0,0,.6);
    --pal-or-a08: rgba(201,168,76,.08);
    --pal-or-a12: rgba(201,168,76,.12);
    --pal-or-a20: rgba(201,168,76,.2);
    --pal-or-a30: rgba(201,168,76,.3);
    --pal-rouge-500-a08: rgba(239,68,68,.08);
    --pal-rouge-500-a20: rgba(239,68,68,.2);
    --pal-rouge-600-a06: rgba(220,38,38,.06);
    --pal-rouge-600-a12: rgba(220,38,38,.12);
    --pal-rouge-600-a15: rgba(220,38,38,.15);
    --pal-rouge-600-a20: rgba(220,38,38,.2);
    --pal-rouge-600-a30: rgba(220,38,38,.3);
    --pal-rouge-600-a35: rgba(220,38,38,.35);
    --pal-vert-500-a06: rgba(34,197,94,.06);
    --pal-vert-500-a08: rgba(34,197,94,.08);
    --pal-vert-500-a12: rgba(34,197,94,.12);
    --pal-vert-500-a20: rgba(34,197,94,.2);
    --pal-vert-500-a30: rgba(34,197,94,.3);
    --pal-vert-500-a35: rgba(34,197,94,.35);
    --pal-vert-600-a03: rgba(22,163,74,.03);
    --pal-vert-600-a05: rgba(22,163,74,.05);
    --pal-vert-600-a06: rgba(22,163,74,.06);
    --pal-violet-600-a04: rgba(124,58,237,.04);
    --pal-violet-600-a08: rgba(124,58,237,.08);
    /*  Refonte B2·3 : voiles des trois couleurs de module (anneau d'un
        champ actif, onglet choisi), ombres bleu nuit, filet des cartes
        en sombre. */
    --pal-dore-a06: rgba(138,100,0,.06);
    --pal-dore-a16: rgba(138,100,0,.16);
    --pal-vert-module-a06: rgba(11,116,80,.06);
    --pal-vert-module-a16: rgba(11,116,80,.16);
    --pal-violet-module-a06: rgba(90,63,214,.06);
    --pal-violet-module-a16: rgba(90,63,214,.16);
    --pal-encre-bleu-a05: rgba(20,25,40,.05);
    --pal-encre-bleu-a06: rgba(20,25,40,.06);
    --pal-encre-bleu-a10: rgba(20,25,40,.10);
    --pal-encre-bleu-a22: rgba(20,25,40,.22);
    --pal-lilas-filet: #2c2e42;
}

/* ═══════════════════════════════════════════════════
   DESIGN TOKENS — Dark
   ═══════════════════════════════════════════════════ */
[data-theme="dark"] {
    /*  Les mêmes huit teintes, éclaircies pour se lire sur fond sombre. */
    --prof-1: #7aa7ff; --prof-2: #fb9a5b; --prof-3: #5fd38a; --prof-4: #cdb58a;
    --prof-5: #fb7f9b; --prof-6: #4fd0e6; --prof-7: #f9a8d4; --prof-8: #a8d65a;
    --sidebar-bg: #0e0f18;
    /*  « Nuit lilas » (refonte B2·3, étape 1) : fonds bleu-violet très
        sombres, couleurs de module éclaircies, ombre remplacée par un
        filet d'un pixel (une ombre ne se voit pas sur du sombre). */
    --color-bg:         #131420;
    --color-surface:    #1c1d2c;
    --color-surface-alt:#202234;
    --color-border:     #2c2e42;
    --color-border-strong: #45485f;
    --color-text:       #edebf7;
    --color-muted:      #aba8c2;
    --color-text-tertiary: #8b88a3;
    --color-primary:    #f0be4a;
    --color-primary-dk: #f5cd6e;
    --color-primary-lt: #2d2512;
    --color-primary-mid:#3d321a;
    --color-accent:     #45d19c;
    --color-accent-dk:  #6cdcb1;
    --color-accent-lt:  #11291f;
    --color-accent-mid: #173a2c;
    --color-ecole:      #c2b4ff;
    --color-treso:      #f0be4a;
    --color-treso-mid:  #2d2512;
    --color-treso-fond: #f0be4a;
    --color-primary-fond:    #f0be4a;
    --color-primary-fond-dk: #f5cd6e;
    --color-on-fond:         #131420;
    --color-ecole-dk:   #d4caff;
    --color-ecole-lt:   #2a2350;
    --color-ecole-mid:  #352c66;
    --color-danger:     #f47a7f;
    --color-danger-lt:  #371a1d;
    --color-success:    #54c985;
    --color-success-lt: #13291c;
    --color-warning:    #f59e5a;
    --color-warning-lt: #36240f;
    --color-info:       #7eb0f6;
    --color-info-lt:    #16243a;
    --shadow:           0 0 0 1px var(--pal-lilas-filet);
    --shadow-md:        0 0 0 1px var(--pal-lilas-filet), 0 6px 20px var(--pal-noir-a40);
    --shadow-lg:        0 16px 40px var(--pal-noir-a55);
    /*  Teintes des états : voir le bloc clair. */
    --color-warning-vif: #f59e5a;
    --color-warning-dk:  #f7b57c;
    --color-warning-mid: #4a3015;
    --color-primary-ring: var(--pal-ambre-400-a20);
    --color-on-accent: #131420;
    --color-danger-soft: #371a1d;
    --color-danger-border: #5e2a2e;
    --color-warning-soft: #36240f;
    --color-warning-text: #f7b57c;
    --color-warning-border: #634014;
    --color-success-soft: #13291c;
    --color-success-text: #6fd69a;
    --color-success-border: #24492f;
    --color-info-soft: #16243a;
    --color-info-text: #9cc3f8;
    --color-gold-soft: #2d2512;
    --color-gold-text: #f0be4a;
    --color-gold-border: #6b5520;
    /*  Neutres et types de réunion : voir le bloc clair. */
    --color-subtle: #1a1b28;
    --color-line: #2c2e42;
    --color-neutral-soft: #262839;
    --color-neutral-text: #aba8c2;
    --color-success-mid: #1a3826;
    --color-pink-soft: #3b1229;
    --color-pink-text: #f9a8d4;
    --color-purple-soft: #2a1840;
    --color-purple-text: #d8b4fe;
}

/* ═══════════════════════════════════════════════════
   ACCENT PAR MODULE (06/10/2026, demande de l'utilisateur)
   Chaque module prend sa couleur dans ses pages — celle de son bouton
   dans la barre latérale et de sa carte au portail : ambre pour la
   trésorerie, vert pour le secrétariat, indigo pour l'école. Seul
   l'ACCENT change (boutons, liens, filets, élément actif, anneau des
   champs) ; les alertes gardent leurs couleurs (--color-warning-*,
   --color-danger…). La classe vient de header.php ; une page commune
   (cloche, Mon compte) prend le module d'où l'on vient, une page hors
   module (portail, Administration) garde l'ambre. Les valeurs sombres
   suivent seules : --color-ecole / --color-accent changent avec le thème.
   ═══════════════════════════════════════════════════ */
body.module-secret {
    --color-primary:      var(--color-accent);
    --color-primary-dk:   var(--color-accent-dk);
    --color-primary-lt:   var(--color-accent-lt);
    --color-primary-mid:  var(--color-accent-mid);
    --color-primary-ring: var(--pal-vert-module-a16);
    --color-primary-wash: var(--pal-vert-module-a06);
    --color-primary-fond:    var(--color-accent);
    --color-primary-fond-dk: var(--color-accent-dk);
    --color-on-fond:         var(--color-on-accent);
}
body.module-ecole {
    --color-primary:      var(--color-ecole);
    --color-primary-dk:   var(--color-ecole-dk);
    --color-primary-lt:   var(--color-ecole-lt);
    --color-primary-mid:  var(--color-ecole-mid);
    --color-primary-ring: var(--pal-violet-module-a16);
    --color-primary-wash: var(--pal-violet-module-a06);
    --color-primary-fond:    var(--color-ecole);
    --color-primary-fond-dk: var(--color-ecole-dk);
    --color-on-fond:         var(--color-on-accent);
}

/* ═══════════════════════════════════════════════════
   PALETTES (docs/REFONTE-INTERFACE.md, section 7 ; catalogue PALETTES
   dans helpers.php). Une palette ne redéfinit que le fond, les filets,
   le texte et les couleurs des modules : le reste du site suit. Toutes
   en clair ; le sombre est « Nuit lilas » (data-theme="dark"). La
   Trésorerie garde partout le doré B (:root). Écrites après :root : à
   précision égale, la dernière règle l'emporte. Chaque palette a été
   vérifiée (contraste ≥ 4,5:1, modules distincts, orange d'alerte à part).
   ═══════════════════════════════════════════════════ */
[data-palette="cedre"] {
    --color-bg: #f6f2eb; --color-surface-alt: #faf7f2; --color-border: #e5ddcf; --color-border-strong: #cdc2b0;
    --color-text: #2a2420; --color-muted: #6b6157; --color-text-tertiary: #756a5f;
    --color-accent: #2e6b4a; --color-accent-dk: #22543a; --color-accent-lt: #eef5f0; --color-accent-mid: #dcebe1;
    --color-ecole: #2f5ba8; --color-ecole-dk: #244789; --color-ecole-lt: #f1f5fb; --color-ecole-mid: #e1eaf7;
    --color-barre: #efe5d3; --color-barre-filet: #ddd0b8;
}
/*  Cèdre et sable : la barre du haut et les onglets en sable aussi
    (demande de l'utilisateur : une barre blanche y faisait « hors sujet »). */
[data-palette="cedre"] .mobile-topbar,
[data-palette="cedre"] .subnav { background: var(--color-barre); border-color: var(--color-barre-filet); }
[data-palette="mosaique"] {
    --color-bg: #f2f5f5; --color-surface-alt: #f7f9f9; --color-border: #dfe6e6; --color-border-strong: #c2cdcd;
    --color-text: #14262a; --color-muted: #55656c; --color-text-tertiary: #5e6e74;
    --color-accent: #4c6a10; --color-accent-dk: #3b530c; --color-accent-lt: #f3f7e8; --color-accent-mid: #e5efcd;
    --color-ecole: #0b6f78; --color-ecole-dk: #08575e; --color-ecole-lt: #eef8f8; --color-ecole-mid: #d8f0f1;
}
[data-palette="prune"] {
    --color-bg: #f6f3f6; --color-surface-alt: #faf8fa; --color-border: #e7e0e7; --color-border-strong: #cfc4cf;
    --color-text: #231b27; --color-muted: #64596b; --color-text-tertiary: #6d6274;
    --color-accent: #1b6f43; --color-accent-dk: #155535; --color-accent-lt: #eef8f2; --color-accent-mid: #dcf0e3;
    --color-ecole: #7a3e9d; --color-ecole-dk: #61307d; --color-ecole-lt: #f9f3fc; --color-ecole-mid: #f1e5f8;
}
[data-palette="lavande"] {
    --color-bg: #f5f3fc; --color-surface-alt: #f9f8fe; --color-border: #e4dff4; --color-border-strong: #c9c1e6;
    --color-text: #1d1a33; --color-muted: #5b5675; --color-text-tertiary: #655f7e;
}

/* ███████████████████████████████████████████████████████████████
   2. BASE ET MISE EN PAGE
   ███████████████████████████████████████████████████████████████ */

/* ═══════════════════════════════════════════════════
   BASE
   ═══════════════════════════════════════════════════ */
html {
    max-width: 100%;
    overflow-x: hidden;
    /*  clip et non hidden (refonte B2·3, étape 2) : « hidden » sur html ET
        body fait de body un conteneur de défilement, et l’en-tête collant
        ne collait plus (il partait avec la page, décalé du bandeau).
        « clip » coupe pareil sans cet effet ; un navigateur trop ancien
        garde la ligne du dessus. */
    overflow-x: clip;
    /*  Refonte B2·3 : tout le site un cran plus grand (17 px au lieu de
        16 par défaut). En pourcentage et non en px, pour respecter un
        navigateur réglé plus grand par quelqu'un qui voit mal. Presque
        toutes les tailles du fichier sont en rem : texte, marges et
        boutons grandissent ensemble (+6 %), rien ne se décale. Les
        @media en rem ne bougent pas (ils lisent la taille du navigateur). */
    font-size: 106.25%;
}
body {
    font-family: var(--font);
    /*  14 px fixes avant : le texte sans taille propre (cellules,
        paragraphes) suit désormais la même échelle que le reste. */
    font-size: .9375rem;
    line-height: 1.55;
    color: var(--color-text);
    background: var(--color-bg);
    -webkit-font-smoothing: antialiased;
    transition: background var(--transition), color var(--transition);
    max-width: 100%;
    overflow-x: hidden;
    overflow-x: clip;   /* voir html */
}
/*  ⚠ [hidden] cache TOUJOURS, quel que soit le composant.
    Le navigateur masque [hidden] par une règle faible : n'importe quelle
    classe qui pose son display (flex, grid, inline-flex…) l'écrasait, et
    un élément que le script voulait cacher restait affiché. Le piège est
    tombé au moins trois fois (bouton « Filtrer », options retirées,
    mensualités de l'encaissement) et avait donné 25 rustines
    « .x[hidden] { display: none } », retirées depuis. Audit du 28/09/2026 :
    522 types d'éléments sur 64 écrans ne se seraient pas cachés. ⛔ Ne pas
    réécrire de rustine par composant : cette règle couvre tout. Une seule règle,
    en !important : c'est ici le sens voulu de l'attribut, partout.
    ⛔ Pour montrer un élément caché, retirer l'attribut (el.hidden =
    false), jamais poser style.display — il resterait caché.
    « html » devant : un cran de précision de plus que les utilitaires
    en !important d'une seule classe (.d-block, écrit plus bas), qui
    l'auraient sinon emporté. */
html [hidden] { display: none !important; }
/*  Refonte B2·3 : titres et grands chiffres en Lexend, chiffres de même
    largeur (une colonne de montants s'aligne d'elle-même). Seule la
    police change ici : tailles et graisses restent celles de chaque
    écran, retouchées aux étapes suivantes. */
h1, h2, h3, .stat-value {
    font-family: var(--font-title);
    letter-spacing: -.01em;
}
.stat-value, td.text-right,
.montant, .table td { font-variant-numeric: tabular-nums; }
/*  Icône au trait (icone(), helpers.php) : couleur du texte voisin. */
.icone { display: inline-block; vertical-align: middle; flex-shrink: 0; }
/* Dans un menu « ⋯ », l'icône est en gris discret, comme dans la feuille
   du téléphone ; une ligne qui supprime la garde rouge (couleur du texte). */
.menu-plus-list .icone { color: var(--color-muted); }
.menu-plus-list .menu-plus-danger .icone,
.menu-plus-list .usr-menu-danger .icone { color: inherit; }
img { max-width: 100%; height: auto; }
a { color: var(--color-primary); text-decoration: none; }
a:hover { text-decoration: underline; }

/* ═══════════════════════════════════════════════════
   LAYOUT — Sidebar + main
   ═══════════════════════════════════════════════════ */
.app-layout {
    display: flex;
    min-height: 100vh;
}
.main-area {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}
.main-content {
    /* ⚠ width: 100% est indispensable, ce n'est pas une redondance.
       .main-area est un conteneur flex en colonne, et en flexbox une marge
       automatique sur l'axe transversal — ici « margin: 0 auto » — annule
       l'étirement : sans largeur explicite, ce bloc se réduit à la largeur
       de son contenu au lieu d'occuper les 960 px prévus.
       Invisible sur une page qui porte un grand tableau, qui remplit la
       largeur toute seule. Très visible sur une page de cartes étroites :
       l'écran Rapports se repliait sur une colonne de 400 px au milieu
       d'une fenêtre de 1900, et ses quatre cartes s'empilaient — dans un
       conteneur de largeur indéfinie, repeat(auto-fit, …) ne compte qu'une
       seule colonne.
       La règle mobile plus bas posait déjà width: 100% pour la même raison,
       sur le seul petit écran. */
    width: 100%;
    /*  Refonte B2·3, étape 3 : sans barre latérale, le contenu prend la
        place (maquette : pleine largeur, marges de 40 à 48 px) — borné à
        1180 px pour que les lignes ne deviennent pas illisibles sur un
        très grand écran. « wide » ne change plus rien, « large » garde
        ses 1440 px.
        Puis (07/10/2026) : une seule largeur pour toutes les pages,
        --page-max (1440 px), la même que l'intérieur de la barre du haut. */
    max-width: var(--page-max);
    margin: 0 auto;
    padding: 28px var(--page-pad) 100px;
}
.main-content.main-content--wide {
    max-width: var(--page-max);
}
/* Écran dont un tableau a vraiment besoin de place ($pageWide = 'large') :
   la fiche famille, dont la colonne Classe porte cours, enseignants et
   horaires (demande de l'utilisateur, grand écran). */
.main-content.main-content--large {
    max-width: var(--page-max);
}

@media (max-width: 768px) {
    .main-area { margin-left: 0; max-width: 100vw; min-width: 0; overflow-x: hidden; }
    .main-content { padding: 16px 12px 110px; width: 100%; max-width: 100%; min-width: 0; overflow-x: hidden; box-sizing: border-box; }
    /* Filet de sécurité : aucun enfant direct de main-content ne peut dépasser */
    .main-content > * { max-width: 100%; min-width: 0; }
}

/* ███████████████████████████████████████████████████████████████
   3. NAVIGATION (barre du haut, onglets, connexion, recherche, barre du bas)
   ███████████████████████████████████████████████████████████████ */

/* ═══════════════════════════════════════════════════
   NAVIGATION EN HAUT — refonte B2·3, étape 2 (06/10/2026)
   ═══════════════════════════════════════════════════
   Remplace la barre latérale (et ses 480 lignes de CSS). Maquette :
   docs/maquettes/ecrans/1-navigation.html.

   .entete = la barre du haut (.mobile-topbar : logo, modules en pilules,
   recherche, alertes, compte) + les onglets du module (.subnav). Deux
   rangées d'onglets sont dans la page, tirées de includes/navigation.php :
   .nav-ordi (rubriques en menus « ▾ », grand écran) et .nav-tel (cinq
   destinations au plus). Le basculement se fait à 1100 px, et NON à
   768 px comme le reste du site : en dessous, les huit rubriques de la
   trésorerie et les trois pilules ne tiennent plus sur une ligne.

   Téléphone et tablette : les menus « ▾ » et le menu du compte
   s'ouvrent en FEUILLE DU BAS (poignée, titres de rubrique, « Fermer »),
   sur un voile qui ferme au toucher. */

.app-layout { display: block; min-height: 100vh; }
.main-area { margin-left: 0; }

/*  Sur ordinateur et tablette l'en-tête reste en haut de l'écran (il
    remplace une barre latérale qui, elle, ne partait jamais). Sur
    téléphone .main-area coupe le débordement horizontal, ce qui empêche
    de coller : l'en-tête défile avec la page, comme avant. */
.entete { position: sticky; top: var(--env-h); z-index: 200; }
/*  Un menu ouvert passe au-dessus de tout, barre du bas comprise (900). */
.entete:has(.tn-dd.tn-open) { z-index: 1001; }

/* ── Barre du haut ── */
.mobile-topbar {
    display: flex; align-items: center; gap: 12px;
    height: 64px;
    /*  Le fond va d'un bord à l'autre ; le contenu de la barre s'aligne
        sur la colonne de page (--page-max) : même calcul que le centrage
        de .main-content, plus sa marge intérieure. */
    padding: 0 max(var(--page-pad), calc((100% - var(--page-max)) / 2 + var(--page-pad)));
    background: var(--color-surface);
    border-bottom: 1px solid var(--color-border);
    box-sizing: border-box; max-width: 100vw;
}
.top-marque {
    display: flex; align-items: center; gap: 10px; flex-shrink: 0;
    color: var(--color-text); text-decoration: none; margin-right: 8px;
}
.top-marque:hover { text-decoration: none; }
.sb-logo {
    width: 38px; height: 38px; border-radius: 12px;
    display: flex; align-items: center; justify-content: center;
    font-size: 14px; font-weight: 700; flex-shrink: 0;
    background: var(--color-ecole); color: var(--color-on-accent);
}
.sb-logo img { width: 100%; height: 100%; object-fit: contain; border-radius: 10px; }
/*  Un logo en image a son propre fond : pas de carré violet derrière. */
.sb-logo:has(img) { background: none; }
.sb-org {
    font-family: var(--font-title); font-weight: 600; font-size: 16px;
    color: var(--color-text); white-space: nowrap;
}

/*  Les modules : pastille pâle de leur couleur, texte de leur couleur,
    point devant ; celui où l'on est porte un contour de 2 px. Couleurs
    lues sur --color-treso / -accent / -ecole, qui ne changent pas avec
    le module de la page (contrairement à --color-primary). */
.mob-tabs { display: flex; align-items: center; gap: 8px; min-width: 0; }
.mod-pill {
    --t: var(--color-treso-mid); --d: var(--color-treso);
    display: inline-flex; align-items: center; gap: 8px; flex-shrink: 0;
    height: 40px; padding: 0 16px; border-radius: 999px;
    background: var(--t); color: var(--d);
    border: 2px solid transparent;
    font-size: 15px; font-weight: 700; white-space: nowrap;
    text-decoration: none;
}
.mod-pill::before {
    content: ''; width: 10px; height: 10px; border-radius: 50%;
    background: var(--point, var(--d)); flex-shrink: 0;
}
.mod-pill:not(.mod-pill--secret):not(.mod-pill--ecole) { --point: var(--color-treso-fond); }
.mod-pill:hover { text-decoration: none; color: var(--d); border-color: var(--d); }
.mod-pill--secret { --t: var(--color-accent-mid); --d: var(--color-accent); }
.mod-pill--ecole  { --t: var(--color-ecole-mid);  --d: var(--color-ecole); }
.mod-pill--on { border-color: var(--d); }
.mob-tab-court { display: none; }

.mob-actions { display: flex; align-items: center; gap: 8px; margin-left: auto; flex-shrink: 0; }
.mob-icon-btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 8px;
    min-width: 40px; height: 40px; padding: 0 10px; border-radius: 12px;
    border: none; background: transparent; cursor: pointer;
    color: var(--color-text); font-family: var(--font);
    font-size: 15px; font-weight: 600; text-decoration: none; white-space: nowrap;
}
.mob-icon-btn:hover { background: var(--color-neutral-soft); text-decoration: none; color: var(--color-text); }
.mob-icon-pos { position: relative; }
/*  Ordinateur : la recherche a l'allure d'un champ (elle ouvre la même
    fenêtre que Ctrl+K), les alertes et le compte sont écrits. */
.top-recherche {
    width: 240px; justify-content: flex-start; padding: 0 16px;
    border: 1px solid var(--color-border-strong); border-radius: 21px;
    background: var(--color-bg); color: var(--color-muted); font-weight: 400;
}
.top-recherche:hover { color: var(--color-text); }
.top-avatar {
    width: 38px; height: 38px; border-radius: 50%;
    display: grid; place-items: center;
    background: var(--color-primary-mid); color: var(--color-primary);
    font-size: 13px; font-weight: 700;
}
.top-compte { padding: 0; border-radius: 50%; }
.top-tel { display: none; }

/* ── Onglets du module ── */
.subnav {
    display: flex; align-items: stretch;
    background: var(--color-surface);
    border-bottom: 1px solid var(--color-border);
    padding: 0 max(var(--page-pad), calc((100% - var(--page-max)) / 2 + var(--page-pad)));
}
.nav-tel { display: none; }
.tn-bar { display: flex; align-items: stretch; gap: 26px; width: 100%; }
.tn-link, .tn-btn {
    display: flex; align-items: center; gap: 4px;
    height: 52px; padding: 0 4px;
    background: none; border: none; cursor: pointer;
    font-family: var(--font); font-size: 16px; font-weight: 600;
    color: var(--color-muted); text-decoration: none; white-space: nowrap;
}
.tn-link:hover, .tn-btn:hover { color: var(--color-text); text-decoration: none; }
/*  Onglet de la page (ou menu qui la contient) : souligné de 3 px, de la
    couleur du module. */
.tn-link.tn-on, .tn-btn.tn-on { color: var(--color-primary); box-shadow: inset 0 -3px 0 var(--color-primary); }
.tn-dd.tn-open > .tn-btn { color: var(--color-text); }
.tn-arr { font-size: .7em; transition: transform .2s; }
.tn-dd.tn-open .tn-arr { transform: rotate(180deg); }
.tn-dd { position: relative; display: flex; align-items: stretch; }

/*  Panneau d'un menu (ordinateur) : carte blanche arrondie sous l'onglet. */
.tn-panel {
    display: none;
    position: absolute; top: calc(100% + 6px); left: -8px;
    min-width: 260px; padding: 8px;
    background: var(--color-surface);
    border-radius: 16px; box-shadow: var(--shadow-lg);
    z-index: 9999;
}
.tn-dd.tn-open .tn-panel { display: block; }
/*  En sombre l’ombre ne se voit pas : un filet détache le panneau. */
[data-theme="dark"] .tn-panel { border: 1px solid var(--color-border-strong); }
.tn-item {
    display: flex; align-items: center; gap: 8px;
    min-height: 46px; padding: 0 14px; border-radius: 10px;
    font-size: 16px; color: var(--color-text); text-decoration: none;
    white-space: nowrap;
}
.tn-item:hover { background: var(--color-neutral-soft); color: var(--color-text); text-decoration: none; }
.tn-item.tn-on { color: var(--color-primary); font-weight: 700; }
.tn-titre { font-size: 13px; font-weight: 700; color: var(--color-muted); padding: 10px 14px 4px; }
.tn-sep { height: 1px; margin: 6px; background: var(--color-border); }
.tn-panel .tn-fermer { display: none; }   /* .btn, écrit plus bas, le montrerait */

/*  Menu du compte : calé à droite, sous les initiales. */
.mob-menu { align-items: center; }
.mob-menu .tn-panel--compte { left: auto; right: 0; top: calc(100% + 10px); }
.tn-compte-qui { display: flex; flex-direction: column; padding: 8px 14px 6px; }
.tn-compte-qui strong { font-size: 16px; }
.tn-compte-qui span { font-size: 14px; color: var(--color-muted); }
.tn-panel--compte .tn-item--danger,
.tn-panel--compte .tn-item--danger:hover { color: var(--color-danger); font-weight: 700; }
.tn-panel--compte .tn-item--danger:hover { background: var(--color-danger-lt); }

.tn-voile { display: none; }
.tn-panel--compte .tn-item--portail { display: none; }   /* le logo y mène déjà */

/*  Écran moyen d'ordinateur : on resserre avant de basculer. */
@media (max-width: 1360px) {
    /*  Marge un peu réduite, pour le contenu comme pour la barre : ils
        restent alignés et les huit rubriques tiennent sur la ligne. */
    :root { --page-pad: 28px; }
    .tn-bar { gap: 18px; }
    .top-recherche { width: 200px; }
}

/* ── Tablette et téléphone (< 1100 px) ── */
@media (max-width: 1099px) {
    .nav-ordi { display: none; }
    .nav-tel { display: flex; }
    .mobile-topbar { height: 56px; padding: 0 10px; gap: 8px; }
    .top-ordi { display: none; }
    .top-tel { display: inline; }
    .top-recherche { width: auto; border: none; background: none; padding: 0 8px; color: var(--color-text); }
    .top-compte { border-radius: 12px; font-size: 20px; line-height: 1; }
    .sb-logo { width: 32px; height: 32px; border-radius: 10px; }
    .mod-pill { height: 36px; padding: 0 12px; font-size: 14px; }

    /*  Cinq destinations à parts égales, le nom seul (maquette). */
    .subnav { padding: 0 6px; }
    .tn-bar { gap: 0; }
    .tn-bar > .tn-link, .tn-bar > .tn-dd { flex: 1 1 0; min-width: 0; justify-content: center; }
    .tn-link, .tn-btn {
        height: 46px; padding: 0 2px; width: 100%; justify-content: center;
        font-size: 14px;
    }
    .tn-label { overflow: hidden; text-overflow: ellipsis; min-width: 0; }

    /*  Feuille du bas : en position fixe, elle n'est rognée par aucun
        conteneur (contrainte iOS des menus dans un bloc qui défile). */
    .tn-panel, .mob-menu .tn-panel--compte {
        position: fixed; top: auto; left: 0; right: 0; bottom: 0;
        min-width: 0; max-height: 80vh; overflow-y: auto;
        padding: 10px 10px max(12px, env(safe-area-inset-bottom, 0px));
        border-radius: 24px 24px 0 0;
        box-shadow: 0 -10px 30px var(--pal-noir-a20);
        z-index: 1001;
    }
    .tn-panel::before {
        content: ''; display: block; width: 44px; height: 5px; border-radius: 3px;
        background: var(--color-border-strong); margin: 2px auto 6px;
    }
    .tn-item { white-space: normal; }
    .tn-panel .tn-fermer { display: flex; width: 100%; margin-top: 6px; }
    body:has(.tn-dd.tn-open) .tn-voile {
        display: block; position: fixed; inset: 0; z-index: 1000;
        background: var(--pal-noir-a45);
    }
}
/*  Téléphone : les modules à leur nom abrégé, le nom de l'association
    s'efface (le logo reste, il ramène au portail). */
/*  Téléphone : .main-area coupe le débordement horizontal et devient le
    conteneur de défilement — un « top » y décalerait l’en-tête au lieu
    de le coller. L’en-tête défile avec la page, comme avant. */
@media (max-width: 768px) {
    .entete { position: relative; top: 0; }
}
@media (max-width: 768px) {
    .sb-org { display: none; }
    .mob-tab-label { display: none; }
    .mob-tab-court { display: inline; }
    .mob-tabs { gap: 6px; }
    .mod-pill { padding: 0 10px; gap: 6px; font-size: 13.5px; }
    .mod-pill::before { width: 8px; height: 8px; }
    .mob-actions { gap: 0; }
    .mob-icon-btn { min-width: 36px; padding: 0 6px; }
}
/*  Petit téléphone : le logo cède sa place aux trois modules (le portail
    reste dans le menu du compte, « Tous les modules »), le point des
    pilules aussi, et les onglets passent à 13 px pour que « Membres ▾ »
    ne soit pas coupé. */
@media (max-width: 768px) {
    .top-marque { display: none; }
    .tn-panel--compte .tn-item--portail { display: flex; }
    .mod-pill::before { display: none; }
    .mod-pill { padding: 0 10px; }
    .tn-link, .tn-btn { font-size: 13px; gap: 2px; }
    .tn-arr { font-size: 9px; }
}
@media (max-width: 340px) {
    .subnav { padding: 0 2px; }
    .tn-link, .tn-btn { font-size: 11.5px; padding: 0 1px; }
}

/* ═══════════════════════════════════════════════════
   LOGIN PAGE
   ═══════════════════════════════════════════════════ */
/*  Style B2·3 (07/10/2026) : le fond des pages du site (clair, ou Nuit
    lilas en sombre) et une carte blanche posée dessus. Le fond bleu nuit
    venait de l'ancienne barre latérale, qui n'existe plus. */
.login-page {
    display: flex; align-items: center; justify-content: center;
    min-height: 100dvh; padding: 1rem;
    background: var(--color-bg);
}
.login-container {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-xl);
    box-shadow: var(--shadow-md);
    padding: 2.5rem 2rem; width: 100%; max-width: 420px;
    transition: background var(--transition);
}
.login-logo { text-align: center; margin-bottom: 1.75rem; }
.login-logo img {
    width: 88px; height: 88px; object-fit: contain;
    margin-bottom: .9rem; border-radius: 18px;
    background: var(--pal-blanc); padding: 6px;
    box-shadow: 0 0 0 1px var(--color-border);
}
.login-logo h1 { font-family: var(--font-title); font-size: 1.5rem; font-weight: 700; color: var(--color-text); }
.login-logo p { color: var(--color-muted); font-size: .85rem; margin-top: .35rem; }
.login-help { text-align: center; margin-top: 1.25rem; font-size: .85rem; color: var(--color-muted); }
/*  Un lien simple prend l'accent ; un bouton garde ses couleurs (un « btn-primary »
    posé ici écrivait de l'or sur l'or — page « lien expiré »). */
.login-help a:not(.btn) { color: var(--color-primary); }
/*  Le bouton principal des pages de connexion à l'encre, pas à l'ambre :
    la page n'est dans aucun module, et l'utilisateur n'aimait pas l'orange
    (07/10/2026). En sombre, encre claire et texte foncé. */
.login-page .btn-primary { background: var(--color-text); border-color: var(--color-text); color: var(--color-surface); }
.login-page .btn-primary:hover { background: var(--color-text); opacity: .88; }
.login-rester { margin: .1rem 0 1rem; font-size: .88rem; color: var(--color-text); cursor: pointer; }
.login-rester input[type="checkbox"] { width: auto; }

/*  Téléphone : la carte reste une carte posée sur le fond, sans remplir
    l'écran — pleine hauteur, elle laissait une fine bordure sombre
    autour (« une boîte dans une boîte »). */
@media (max-width: 768px) {
    .login-container { padding: 2rem 1.25rem; border-radius: var(--radius-lg); }
}

/* ═══════════════════════════════════════════════════
   NOTIFICATION BELL
   ═══════════════════════════════════════════════════ */
.notif-badge {
    position: absolute; top: -6px; right: -8px;
    background: var(--color-danger); color: var(--color-on-accent);
    font-size: .6rem; font-weight: 700;
    min-width: 15px; height: 15px; border-radius: 999px;
    display: flex; align-items: center; justify-content: center; padding: 0 3px;
}
.notif-badge.hidden { display: none; }

/* ═══════════════════════════════════════════════════
   SEARCH OVERLAY
   ═══════════════════════════════════════════════════ */
.search-overlay {
    display: none; position: fixed; inset: 0;
    background: var(--pal-noir-a45); z-index: 10000;
    align-items: flex-start; justify-content: center;
    padding: 80px 16px 16px;
}
.search-overlay.open { display: flex; }
.search-box {
    background: var(--color-surface);
    border-radius: var(--radius-lg);
    max-width: 560px; width: 100%;
    box-shadow: var(--shadow-lg);
    overflow: hidden;
}
.search-input-wrap {
    display: flex; align-items: center; gap: 10px;
    padding: 14px 18px;
    border-bottom: 1px solid var(--color-border);
}
.search-input-wrap input {
    flex: 1; min-width: 0; border: none; outline: none; font-size: .9rem;
    background: transparent; color: var(--color-text);
    font-family: var(--font);
}
.search-input-wrap input::placeholder { color: var(--color-muted); }
.search-fermer {
    flex: 0 0 auto; width: 2.25rem; height: 2.25rem; margin-right: -.4rem;
    display: inline-flex; align-items: center; justify-content: center;
    border: none; border-radius: 50%; cursor: pointer;
    background: transparent; color: var(--color-muted);
    font-size: 1.1rem; line-height: 1;
}
.search-fermer:hover, .search-fermer:focus-visible { background: var(--color-surface-alt); color: var(--color-text); }
.search-results { max-height: 420px; overflow-y: auto; }
.search-section {
    font-size: .9rem; font-weight: 700;
    color: var(--color-muted);
    padding: 10px 18px 4px;
}
.search-item {
    display: flex; align-items: center; gap: 12px;
    padding: 9px 18px; cursor: pointer;
    text-decoration: none; color: var(--color-text);
    transition: background .08s;
}
.search-item:hover, .search-item.active { background: var(--color-surface-alt); }
.search-item-icon { font-size: 1rem; flex-shrink: 0; width: 22px; text-align: center; }
.search-item-text { flex: 1; min-width: 0; }
.search-item-title {
    font-size: .82rem; font-weight: 600;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.search-item-sub {
    font-size: .7rem; color: var(--color-muted);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.search-empty { padding: 24px; text-align: center; color: var(--color-muted); font-size: .82rem; }
/*  Ordinateur (bandeau large, même seuil que lui) : la recherche se tape
    DANS le bandeau (demande de l'utilisateur, 11/10/2026) — plus de
    fenêtre au milieu de l'écran. C'est la même boîte, posée à la place
    exacte du bouton « Rechercher… » (navigation.js mesure le bouton et
    écrit --rg-haut / --rg-droite), un peu plus large que lui, les
    résultats dessous. Le voile reste, invisible : toucher ailleurs ferme.
    Rien à lire tant qu'on n'a pas tapé deux lettres : pas de panneau. */
@media (min-width: 1100px) {
    .search-overlay { background: transparent; padding: 0; }
    .search-overlay.open { display: block; }
    .search-box {
        position: fixed; top: var(--rg-haut, 12px); right: var(--rg-droite, 16px);
        width: 460px; max-width: calc(100vw - 32px);
        border: 1px solid var(--color-border-strong); border-radius: 21px;
    }
    .search-input-wrap { height: 38px; padding: 0 6px 0 16px; border-bottom: none; }
    .search-input-wrap input { font-size: 15px; }
    .search-fermer { width: 1.9rem; height: 1.9rem; margin-right: 0; font-size: .95rem; }
    .search-results { border-top: 1px solid var(--color-border); }
    .search-results:has(> [data-attente]) { display: none; }
}

/* ═══════════════════════════════════════════════════
   BOTTOM BAR (mobile)
   ═══════════════════════════════════════════════════ */
.bottom-bar {
    display: none;
    position: fixed; bottom: 0; left: 0; right: 0;
    background: var(--color-surface);
    border-top: 1px solid var(--color-border);
    z-index: 900;
    padding: 6px 6px max(6px, env(safe-area-inset-bottom, 0px));
    justify-content: space-around;
}
/*  Refonte B2·3 : chaque geste prend une part égale de la barre, le mot
    sous l'icône passe de 10 à 13 px (maquette : barre de 68 px). */
.bb-item {
    display: flex; flex-direction: column; align-items: center; gap: 3px;
    flex: 1 1 0; min-width: 0;
    text-decoration: none; color: var(--color-muted);
    font-size: .76rem; font-weight: 600;
    padding: 6px 2px; border-radius: var(--radius);
    transition: color .15s;
    -webkit-tap-highlight-color: transparent;
}
.bb-item .bb-icon { font-size: 1.35rem; line-height: 1; }
.bb-item .bb-label { font-size: .76rem; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bb-item--btn { background: none; border: none; font-family: var(--font); cursor: pointer; }
.bb-item.active { color: var(--color-primary); }
.bb-item:hover { color: var(--color-primary); text-decoration: none; }

@media (max-width: 768px) {
    .bottom-bar { display: flex; }
}

/* ═══════════════════════════════════════════════════
   FOOTER
   ═══════════════════════════════════════════════════ */
.app-footer {
    margin-top: auto; padding: 1rem 1.5rem;
    border-top: 1px solid var(--color-border);
    font-size: .72rem; color: var(--color-muted);
    display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
}
.app-footer a { color: var(--color-muted); text-decoration: none; }
.app-footer a:hover { color: var(--color-primary); }

@media (max-width: 768px) {
    .app-footer { display: none; }
}

/* ============================================================
   SITE DE TEST / LOCAL — le repère d'environnement
   ============================================================
   Posé par bandeauEnvironnement() / classeEnvironnement() (helpers.php).
   Rien en production.

   Le bandeau est FIXE en haut de l'écran (demande de l'utilisateur) :
   il ne doit jamais défiler hors de vue. Tout ce qui se colle en haut
   de l'écran descend donc de sa hauteur, --env-h (0 en production) :
   barre latérale, panneaux des menus du téléphone, blocs collants
   (Permissions, Catégories, Paramètres). ⚠ Un élément collé en haut ajouté demain doit ajouter
   var(--env-h) à son « top », sinon il glissera sous le bandeau. */
:root { --env-h: 0px; }
body.env-test, body.env-local { --env-h: 26px; padding-top: var(--env-h); }
body.env-test .app-layout, body.env-local .app-layout { min-height: calc(100vh - var(--env-h)); }

.env-bandeau {
    position: fixed; top: 0; left: 0; right: 0; z-index: 950;
    height: var(--env-h); box-sizing: border-box;
    display: flex; align-items: center; justify-content: center; gap: .3rem;
    padding: 0 .75rem; font-size: .78rem; line-height: 1;
    white-space: nowrap; overflow: hidden;
    color: var(--pal-blanc); font-weight: 500;
}
.env-bandeau--test  { background: repeating-linear-gradient(135deg, var(--pal-orange-700) 0 14px, var(--pal-orange-600) 14px 28px); }
.env-bandeau--local { background: repeating-linear-gradient(135deg, var(--pal-bleu-700) 0 14px, var(--pal-bleu-600) 14px 28px); }

/*  Ce qui se colle en haut de l'écran descend de la hauteur du bandeau. */
/*  PAS le bandeau ni la sous-barre du téléphone : collés dans .main-area,
    qui commence déjà sous le bandeau, ils descendaient deux fois (mesuré).
    Le décalage ne vaut que pour ce qui se cale sur l'ÉCRAN (position fixe). */
body.env-test .perms-sidebar,  body.env-local .perms-sidebar,
body.env-test .perms-barre,    body.env-local .perms-barre    { top: calc(1rem + var(--env-h)); }
body.env-test .cat-form-sticky, body.env-local .cat-form-sticky { top: calc(110px + var(--env-h)); }
body.env-test .params-toc,     body.env-local .params-toc     { top: calc(var(--header-h, 56px) + 8px + var(--env-h)); }
/*  Refonte B2·3 (étape 2) : l’en-tête (barre du haut + onglets) reste
    collé en haut de l’écran sur ordinateur et tablette — 117 px, 103 px
    sous 1100 px, rien sur téléphone où il défile avec la page. Ce qui se
    colle en haut d’une page descend d’autant, en plus du bandeau. */
:root { --nav-h: 117px; }
@media (max-width: 1099px) { :root { --nav-h: 103px; } }
@media (max-width: 768px)  { :root { --nav-h: 0px; } }
html body .perms-sidebar, html body .perms-barre { top: calc(1rem + var(--env-h) + var(--nav-h)); }
html body .perms-sidebar { max-height: min(calc(100vh - 2rem - var(--env-h) - var(--nav-h)), 40rem); }
html body .cat-form-sticky { top: calc(1rem + var(--env-h) + var(--nav-h)); }
html body .params-toc { top: calc(var(--header-h, 56px) + 8px + var(--env-h) + var(--nav-h)); }
/*  Page de connexion : son propre retrait d'1rem reste sous le bandeau. */
body.login-page.env-test, body.login-page.env-local { padding-top: calc(1rem + var(--env-h)); }

/*  La pastille sur le logo : reste visible même bandeau hors champ
    (fenêtre plein écran d'une modale, par exemple). */
body.env-test .sb-logo, body.env-local .sb-logo { position: relative; }
body.env-test .sb-logo::after, body.env-local .sb-logo::after {
    position: absolute; left: 50%; bottom: -5px; transform: translateX(-50%);
    font-size: 8px; font-weight: 800; letter-spacing: .04em; line-height: 1;
    padding: 2px 3px; border-radius: 3px; white-space: nowrap;
    color: var(--pal-blanc); box-shadow: 0 0 0 1.5px var(--sidebar-bg);
}
body.env-test  .sb-logo::after { content: 'TEST';  background: var(--pal-orange-600); }
body.env-local .sb-logo::after { content: 'LOCAL'; background: var(--pal-bleu-600); }

@media (max-width: 768px) {
    /*  Sur un téléphone la phrase ne tient pas : le mot suffit. */
    .env-bandeau-suite { display: none; }
}
/*  Une section visée par une ancre (#…) s'arrête sous le bandeau, pas
    dessous. S'ajoute aux scroll-margin-top déjà posés. */
html:has(body.env-test), html:has(body.env-local) { scroll-padding-top: 26px; }
/*  À l'impression (Ctrl+P), ni bandeau ni retrait. */
@media print {
    .env-bandeau { display: none !important; }
    body.env-test, body.env-local { padding-top: 0; }
}

/* ███████████████████████████████████████████████████████████████
   4. SOCLE COMMUN — en-têtes, champs, boutons, alertes, cartes, tableaux, tuiles, badges, pagination, utilitaires
   ███████████████████████████████████████████████████████████████ */

/* ═══════════════════════════════════════════════════
   PAGE HEADER
   ═══════════════════════════════════════════════════ */
.page-header {
    display: flex; align-items: center; gap: 1rem;
    margin-bottom: 1.5rem; flex-wrap: wrap;
}
.page-header h1 {
    font-size: 1.4rem; font-weight: 700;
    letter-spacing: -.02em; flex: 1; min-width: 200px;
}
.page-header .text-muted { width: 100%; margin-top: -.5rem; font-size: .85rem; }
/* Boutons d'action d'un titre de page. Ils étaient posés dans un <div>
   nu : sur ordinateur ils s'alignent d'eux-mêmes, mais dès qu'une
   largeur d'écran les oblige à passer à la ligne, chacun garde la
   largeur de son texte et la rangée finit en escalier. */
.page-actions { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; }
/* Retour à la liste d'où l'on vient, en petit au-dessus du titre (comme
   le retour d'un iPhone) : un bouton de plus dans la rangée se lisait
   comme un outil de la page (fiche famille, 04/10/2026). */
.lien-retour {
    display: inline-block; padding: .25rem 0; margin-bottom: .25rem;
    font-size: .85rem; font-weight: 500; color: var(--color-muted); text-decoration: none;
}
.lien-retour:hover, .lien-retour:focus-visible { color: var(--color-primary); }

@media (max-width: 768px) {
    .page-header h1 { font-size: 1.15rem; min-width: 0; }
    .page-header { margin-bottom: 1rem; }
}
/* Sur téléphone, ces boutons prennent toute la largeur du titre et se
   la partagent : deux courts tiennent une ligne, un long occupe la
   sienne en entier — plutôt que trois largeurs différentes décalées à
   gauche. */
@media (max-width: 768px) {
    .page-actions { width: 100%; }
    .page-actions > .btn { flex: 1 1 auto; justify-content: center; }
    /* Un menu « ▾ » de la rangée peut tomber en début de ligne : son
       panneau, calé sur le bord droit du bouton, sortait alors de l'écran
       par la gauche (« 📧 Envoyer ▾ » du rapport d'AG). Il s'ouvre sous la
       rangée entière, calé à droite. */
    .page-actions:has(> .menu-plus) { position: relative; }
    .page-actions > .menu-plus { position: static; }
}

/* ═══════════════════════════════════════════════════
   FORMS
   ═══════════════════════════════════════════════════ */
.form-group { margin-bottom: 1.15rem; }
.form-group label {
    display: block; font-size: .88rem; font-weight: 700;
    margin-bottom: .35rem; color: var(--color-text);
}
/* Une case à cocher n'est pas un champ de saisie : la largeur pleine
   ci-dessous la fait dériver au milieu de sa ligne, loin de son
   libellé. Le sélecteur d'attribut passe devant la règle générique
   sans avoir à la réécrire. */
.form-group input[type="checkbox"],
.form-group input[type="radio"] { width: auto; min-height: 0; padding: 0; }

/*  Refonte B2·3 : champs de 44 px (la maquette en demande 48), texte à
    la taille du site. */
.form-group input, .form-group select, .form-group textarea {
    width: 100%; padding: .55rem .85rem; min-height: 2.6rem;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius);
    font-size: .95rem; color: var(--color-text);
    background: var(--color-surface);
    font-family: var(--font);
    transition: border-color var(--transition), box-shadow var(--transition);
}
.form-group input:focus, .form-group select:focus, .form-group textarea:focus {
    outline: none; border-color: var(--color-primary);
    box-shadow: 0 0 0 3px var(--color-primary-ring);
}
[data-theme="dark"] .form-group input:focus,
[data-theme="dark"] .form-group select:focus,
[data-theme="dark"] .form-group textarea:focus {
    box-shadow: 0 0 0 3px var(--color-primary-ring);
}
.form-group small { display: block; margin-top: .25rem; font-size: .78rem; color: var(--color-muted); }

/* ═══════════════════════════════════════════════════
   BUTTONS
   ═══════════════════════════════════════════════════ */
/*  Aucune règle n'existait pour cet état : « Envoyer à 0 membre(s) »,
    désactivé par le mécanisme des fenêtres d'envoi, gardait l'allure d'un
    bouton qui attend un clic. Vaut pour toutes les fenêtres d'envoi
    (convocation, diffusion du PV, reprise d'actions). */
.btn:disabled, .btn[disabled] { opacity: .5; cursor: not-allowed; box-shadow: none; }

/*  Refonte B2·3, étape 3 : boutons plus hauts (42 px, 36 en petit, 30 en
    très petit — la maquette demande 46 / 40, ramenés pour les tableaux
    denses), texte en gras léger. La hauteur passe par min-height : un
    écran qui règle son propre rembourrage garde la sienne au-dessus. */
.btn {
    display: inline-flex; align-items: center; justify-content: center; gap: .4rem;
    padding: .55rem 1.1rem; border-radius: var(--radius);
    min-height: 2.5rem; box-sizing: border-box;
    font-size: .9rem; font-weight: 600; cursor: pointer;
    border: 1px solid var(--color-border-strong);
    background: var(--color-surface); color: var(--color-text);
    text-decoration: none; white-space: nowrap;
    font-family: var(--font);
    /* Un lien <a class="btn"> hérite de la hauteur de ligne de la page
       (1,55), un <button class="btn"> non : le navigateur lui impose la
       sienne, plus serrée. Deux boutons côte à côte — « Modifier » (un
       lien) et « Autres actions » (un bouton) — n'avaient donc pas la
       même hauteur. On aligne les liens sur les boutons, et non
       l'inverse : les boutons sont de loin les plus nombreux, c'est
       l'apparence que le site a déjà presque partout. */
    line-height: normal;
    transition: all var(--transition);
}
.btn:hover { background: var(--color-surface-alt); text-decoration: none; }
.btn:active { transform: scale(.97); }
.btn-primary { background: var(--color-primary-fond); color: var(--color-on-fond); border-color: var(--color-primary-fond); }
.btn-primary:hover { background: var(--color-primary-fond-dk); }
.btn-secondary { background: var(--color-surface); color: var(--color-text); border-color: var(--color-border-strong); }
.btn-secondary:hover { background: var(--color-surface-alt); }
.btn-danger { background: var(--color-danger); color: var(--color-surface); border-color: var(--color-danger); }
.btn-danger:hover { opacity: .9; }
.btn-sm { padding: .35rem .8rem; font-size: .82rem; min-height: 2.15rem; }
.btn-xs { padding: .2rem .55rem; font-size: .76rem; min-height: 1.8rem; }
.btn-full { width: 100%; }
.btn-group { display: flex; gap: .5rem; flex-wrap: wrap; }

/* ═══════════════════════════════════════════════════
   ALERTS
   ═══════════════════════════════════════════════════ */
.alert {
    padding: .75rem 1rem; border-radius: var(--radius);
    font-size: .85rem; margin-bottom: 1rem;
    border: 1px solid transparent;
    display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
    /* flex-wrap: un texte qui dépasse une ligne se compose de plusieurs
       items flex anonymes (le texte avant un lien, le lien, le texte
       après) : sans ce flex-wrap, ils se serrent chacun sur une seule
       ligne au lieu de s'enchaîner normalement, et le texte se
       fragmente en colonnes étroites illisibles. */
}
.alert-error, .alert-danger { background: var(--color-danger-lt); color: var(--color-danger); border-color: var(--color-danger-border); }
.alert-success { background: var(--color-success-lt); color: var(--color-success); border-color: var(--color-success-border); }
.alert-info { background: var(--color-info-lt); color: var(--color-info); border-color: var(--pal-bleu-200); }
.alert-warning { background: var(--color-warning-lt); color: var(--color-warning); border-color: var(--color-warning-mid); }

[data-theme="dark"] .alert-error, [data-theme="dark"] .alert-danger { border-color: var(--color-danger-border); }
[data-theme="dark"] .alert-success { border-color: var(--color-success-border); }
[data-theme="dark"] .alert-info { border-color: var(--pal-bleu-nuit); }
[data-theme="dark"] .alert-warning { border-color: var(--color-warning-border); }

/* ═══════════════════════════════════════════════════
   CARDS
   ═══════════════════════════════════════════════════ */
.card {
    background: var(--color-surface);
    /*  Refonte B2·3 : bordure transparente (et non retirée) — les tailles
        ne bougent pas d'un pixel, l'ombre dessine le bord. */
    border: 1px solid transparent;
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow);
    overflow: hidden;
    transition: background var(--transition), border-color var(--transition);
}
/* Deux cartes empilées ne se touchent pas : un petit écart laisse
   respirer les sections (demande de l'utilisateur, après l'accueil de
   l'école). Mesuré sur les 62 écrans : 12 empilaient des cartes collées.
   Dans le flux ordinaire, la marge fusionne avec celle déjà posée par un
   écran — un écart plus grand reste le sien.
   ⚠ Les conteneurs en grille ou en flex, eux, ont leur propre « gap » et
   n'additionnent pas les marges comme le flux : la règle y décalerait une
   carte posée à côté d'une autre, ou doublerait l'écart. Ils sont exclus
   par nom — un conteneur de cartes ajouté demain en grille ou en flex
   s'ajoute à la liste. */
.card + .card { margin-top: .6rem; }
:is(.pwd-grille, .ecole-accueil-cartes, .cour-rediger-sidebar, .cour-tpl-grid,
    .dashboard-grid, .cat-layout, .cerfa-main-grid) > .card + .card { margin-top: 0; }
.card-body { padding: 1.25rem; }
.card-header {
    display: flex; align-items: center; justify-content: space-between;
    padding: .85rem 1.25rem;
    border-bottom: 1px solid var(--color-border);
}
.card-header h2 { font-size: 1.05rem; font-weight: 600; margin: 0; }
.card-header h2 small { font-weight: 400; color: var(--color-muted); font-size: .78rem; }

/* ═══════════════════════════════════════════════════
   TABLES
   ═══════════════════════════════════════════════════ */
.table { width: 100%; border-collapse: collapse; font-size: .85rem; }
/*  Refonte B2·3 : en-têtes écrits normalement (les capitales se lisent
    mal, surtout pour les personnes âgées), en gras gris sur le fond
    gris bleuté des bandeaux de la maquette. */
.table th {
    text-align: left; padding: .6rem .85rem;
    font-weight: 700; font-size: .8rem;
    color: var(--color-muted);
    text-transform: none; letter-spacing: 0;
    border-bottom: 1px solid var(--color-border);
    background: var(--color-neutral-soft);
}
.table td {
    padding: .7rem .85rem;
    border-bottom: 1px solid var(--color-border);
    vertical-align: middle;
}
.table tr:last-child td { border-bottom: none; }
.table tr:hover td { background: var(--color-surface-alt); }
.table td a { color: var(--color-primary); text-decoration: none; font-weight: 500; }
/* Un bouton plein posé en lien dans une cellule : la règle ci-dessus, plus
   précise que .btn-primary, lui donnait un texte orange sur fond orange —
   le « 📧 Convoquer » de la liste des réunions était un pavé muet. */
.table td a.btn-primary { color: var(--color-on-fond); }
.table td a.btn-danger { color: var(--color-danger); }
.table td small { display: block; color: var(--color-muted); font-size: .72rem; }
.table-responsive { overflow-x: auto; -webkit-overflow-scrolling: touch; }
/* Un tableau en width: 100% ne déborde jamais tant que son texte peut
   se couper : les en-têtes se replient sur plusieurs lignes au lieu de
   déclencher le défilement de .table-responsive, qui ne sert alors à
   rien. Les en-têtes restent sur une ligne, quitte à élargir le
   tableau au-delà du conteneur — c'est justement ce qui fait défiler. */
.table-responsive .table th { white-space: nowrap; }

/* Bouton « Tout déplier / Tout replier » d'un tableau repliable
   (voir .table-mobile--repliable ci-dessous) : posé par le JS de
   footer.php, il n'a de sens que dans la vue carte du mobile — sur
   ordinateur le tableau est déjà entièrement visible. */
.table-mobile-toggle-all { display: none; }

/* Mobile table → cards */
@media (max-width: 768px) {
    /* Seul un tableau passé en cartes (.table-mobile) a besoin de ce
       débordement visible, pour que ses menus déroulants ne soient pas
       rognés. Un tableau resté classique dans un .table-responsive doit
       au contraire continuer à défiler, pas déborder de sa carte. */
    .table-responsive:has(.table-mobile) { overflow-x: visible; }
    .card { overflow: visible; }
    .table-mobile { min-width: 0 !important; border-collapse: separate; border-spacing: 0; }
    .table-mobile thead { display: none; }
    .table-mobile tbody { display: block; }
    .table-mobile tbody tr {
        display: block; background: var(--color-surface);
        border: 1px solid var(--color-border);
        border-radius: var(--radius);
        padding: .85rem; margin-bottom: .6rem;
        box-shadow: var(--shadow);
    }
    .table-mobile tbody td {
        display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center;
        padding: .25rem 0; border-bottom: none; font-size: .85rem; width: 100% !important;
        gap: .1rem .5rem; min-width: 0; overflow-wrap: anywhere; word-break: break-word;
    }
    .table-mobile tbody td::before {
        content: attr(data-label); font-weight: 600; font-size: .8rem;
        color: var(--color-text-tertiary); margin-right: .75rem; flex-shrink: 0;
    }
    .table-mobile tbody td > * { min-width: 0; overflow-wrap: anywhere; word-break: break-word; }
    /* Une valeur courte (date, code...) reste à côté de son étiquette ;
       une sous-ligne de détail (âge, enseignant, créneaux...) — toujours
       posée dans un <div> — passe systématiquement à la ligne plutôt que
       de se coincer à côté et de se couper lettre par lettre. */
    .table-mobile tbody td > div { flex-basis: 100%; }
    /* La sous-ligne (téléphone, âge, enseignant...) doit rester rattachée
       visuellement à la valeur au-dessus, qui est poussée à droite par
       justify-content: space-between — sinon elle retombe à gauche et
       semble appartenir à la ligne précédente. Le premier <td> fait
       exception : il agit comme un titre de carte, aligné à gauche. */
    .table-mobile tbody td:not(:first-child) > div { text-align: right; }
    .table-mobile tbody td:first-child {
        font-weight: 600; margin-bottom: .3rem;
        padding-bottom: .35rem; border-bottom: 1px solid var(--color-border);
        display: block;
    }
    .table-mobile tbody td:first-child::before { display: none; }
    .table-mobile tr:hover td { background: transparent; }
    /* Colonne présente dans le tableau desktop (et sur la fiche
       complète) mais superflue dans le coup d'œil rapide d'une carte
       mobile — typiquement une valeur dont une autre ligne visible est
       déjà la différence ou le résultat. */
    .table-mobile tbody td.table-mobile-secondary { display: none; }
    /* En-tête de carte avec nom + badge d'alerte + case à cocher : trois
       éléments qui se serrent sinon sur une seule ligne. Scopé à cette
       classe plutôt qu'à .card-header en général, pour ne pas changer
       les en-têtes des autres modules. */
    .ecole-header-wrap { flex-wrap: wrap; }

    /* Tableaux repliables (.table-mobile--repliable) : sur une liste
       de plusieurs dizaines d'élèves ou de familles, afficher chaque
       ligne en entier impose un défilement interminable. Seul le
       premier <td> (et ceux marqués .table-mobile-glance) reste visible
       par défaut ; un clic dessus déplie le reste. Le clic est branché
       dans app.js, mutualisé comme details.pliable — toute liste qui
       ajoute cette classe en hérite sans JS à écrire.
       Scopé à --repliable : les autres tableaux .table-mobile restent
       entièrement visibles comme avant. */
    .table-mobile-toggle-all { display: inline-flex; margin: .75rem .85rem .1rem; }
    .table-mobile--repliable tbody td:first-child {
        position: relative; padding-right: 1.5rem;
        cursor: pointer; user-select: none;
    }
    .table-mobile--repliable tbody td:first-child::after {
        content: ''; position: absolute; right: .15rem; top: .5rem;
        width: 7px; height: 7px;
        border-right: 2px solid var(--color-muted);
        border-bottom: 2px solid var(--color-muted);
        transform: rotate(45deg) translate(-1px, -2px);
        transition: transform .15s;
    }
    .table-mobile--repliable tbody tr.tr--ouverte td:first-child::after {
        transform: rotate(-45deg) translate(-1px, 1px);
    }
    .table-mobile--repliable tbody tr:not(.tr--ouverte) td:not(:first-child):not(.table-mobile-glance) {
        display: none;
    }
    /* Détail porté par le premier <td> lui-même — l'email et
       l'identifiant sous un nom de compte. Utile une fois la ligne
       ouverte, mais il triple la hauteur de l'en-tête de carte, qui est
       justement la seule chose censée rester visible quand tout est
       replié. Posé ici plutôt que dans la feuille d'un écran : toute
       liste repliable finit par avoir une sous-ligne de ce genre. */
    .table-mobile--repliable tbody tr:not(.tr--ouverte) .table-mobile-detail {
        display: none;
    }
}

/* ═══════════════════════════════════════════════════
   STAT CARDS
   ═══════════════════════════════════════════════════ */
.stat-card {
    background: var(--color-surface);
    border: 1px solid transparent;
    border-radius: var(--radius-lg);
    padding: 1.05rem 1.2rem;
    box-shadow: var(--shadow);
    position: relative; overflow: hidden;
    transition: all .15s;
}
/*  Refonte B2·3 : plus de bandeau coloré en haut de la tuile (la maquette
    n'en a pas) ; seule la tuile d'alerte garde un repère, son chiffre en
    rouge (règle plus bas). */
.stat-card::before { content: none; }
.stat-card:hover { box-shadow: var(--shadow-md); border-color: var(--color-border-strong); }
.stat-card--link { text-decoration: none; display: block; cursor: pointer; color: inherit; }
.stat-card--link:hover { transform: translateY(-1px); }
.stat-card .stat-value {
    font-size: 1.65rem; font-weight: 600;
    letter-spacing: -.02em; color: var(--color-text);
    line-height: 1.1;
}
.stat-card .stat-label {
    font-size: .85rem; font-weight: 600;
    color: var(--color-muted);
    margin-bottom: 4px;
    text-transform: none; letter-spacing: 0;
}
.stat-card .stat-sub { font-size: .8rem; color: var(--color-muted); margin-top: 4px; }

@media (max-width: 768px) {
    .stat-card { padding: .75rem .65rem; }
    .stat-card .stat-value { font-size: 1.25rem; }
    .stat-card .stat-label { font-size: .65rem; }
}

/* ═══════════════════════════════════════════════════
   BADGES
   ═══════════════════════════════════════════════════ */
.badge {
    display: inline-block; padding: .2rem .65rem;
    border-radius: 999px; font-size: .78rem; font-weight: 700;
}
/*  Le catalogue : CINQ tons, posés par badge($texte, $ton) (helpers.php)
    — neutre, info, ok, attention, danger. Les trois statuts d'un PV
    (brouillon, relecture, approuvé) gardent leur nom, lu dans la base
    (« badge-<?= statut ?> ») : brouillon et approuvé SONT les tons
    neutre et ok ; relecture garde son orange plus soutenu. ⛔ Pas de
    nouvelle couleur de badge : un ton de plus s'ajoute ici et dans
    badge(), nulle part ailleurs. */
.badge-secondary, .badge-brouillon { background: var(--color-surface-alt); color: var(--color-muted); }
.badge-info      { background: var(--color-info-lt);    color: var(--color-info); }
.badge-success, .badge-approuve { background: var(--color-success-lt); color: var(--color-accent-dk); }
.badge-warning   { background: var(--color-warning-soft); color: var(--color-warning-text); }
.badge-relecture { background: var(--color-warning-lt); color: var(--color-warning-dk); }
.badge-danger    { background: var(--color-danger-lt); color: var(--color-danger); }

/* Plus de text-transform: capitalize — ces badges portent maintenant le
   libellé du rôle (« École arabe », « Enseignant ») et non sa clé en
   base (« ecole », « prof ») : capitaliser chaque mot en faisait
   « École Arabe ». */
.role-badge {
    display: inline-block; padding: .1rem .4rem;
    border-radius: 999px; font-size: .65rem; font-weight: 600;
}
.role-admin      { background: var(--color-primary-fond); color: var(--color-on-fond); }
.role-secretaire { background: var(--color-accent); color: var(--color-on-accent); }
.role-tresorier  { background: var(--color-primary-fond); color: var(--color-on-fond); }
.role-bureau     { background: var(--color-info); color: var(--color-on-accent); }
.role-cotisations{ background: var(--color-accent); color: var(--color-on-accent); }
.role-ecole      { background: var(--color-ecole); color: var(--color-on-accent); }
/* Responsable pédagogique : l'indigo de l'école, un cran plus sombre
   pour qu'on le distingue du rôle École complet dans une liste. */
.role-ecole_pedago { background: var(--color-ecole-dk); color: var(--color-on-accent); }
.role-ecole_lecture { background: var(--color-ecole-lt); color: var(--color-ecole-dk); border: 1px dashed var(--color-ecole); }
/* Enseignant : dans la famille indigo de l'école, mais en teinte claire
   — il vient à l'école sans en être le responsable. C'était le seul rôle
   sans règle ici, son badge s'affichait donc sans fond du tout. Les deux
   variables s'inversent en thème sombre (fond foncé, texte clair), le
   contraste tient des deux côtés sans règle supplémentaire. */
.role-prof       { background: var(--color-ecole-mid); color: var(--color-ecole-dk); }
.role-membre     { background: var(--color-surface-alt); color: var(--color-muted); }
/*  Un badge de rôle posé en <small> dans un tableau (statistiques de
    présence) prenait le gris de « .table td small », plus précis : texte
    gris sur fond de couleur, illisible. Il garde la couleur de son rôle. */
.table td small.role-badge:not(.role-membre, .role-prof, .role-ecole_lecture) { color: var(--color-on-accent); }
.table td small.role-badge:is(.role-admin, .role-tresorier) { color: var(--color-on-fond); }

[data-theme="dark"] :is(.badge-secondary, .badge-brouillon) { background: var(--pal-blanc-a08); }
[data-theme="dark"] .badge-relecture { background: var(--color-warning-lt); }
[data-theme="dark"] :is(.badge-success, .badge-approuve) { background: var(--color-accent-lt); }
[data-theme="dark"] .badge-warning { background: var(--color-warning-lt); color: var(--color-warning-text); }

/* ═══════════════════════════════════════════════════
   PAGINATION
   ═══════════════════════════════════════════════════ */
.pagination {
    display: flex; align-items: center; justify-content: center;
    gap: .3rem; margin-top: 1.5rem; flex-wrap: wrap;
}
/* Enfants DIRECTS seulement : les libellés « Précédente / Préc. » sont des
   <span> DANS le bouton — visés par « .pagination span », ils prenaient un
   cadre et leur display l'emportait sur .pagination-court (les deux
   libellés s'affichaient, chacun dans sa case). */
.pagination > a, .pagination > span {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 34px; height: 34px; padding: 0 .5rem;
    border-radius: var(--radius); font-size: .82rem; font-weight: 500;
    text-decoration: none; border: 1px solid var(--color-border);
    background: var(--color-surface); color: var(--color-text);
    transition: all var(--transition);
}
.pagination a:hover { background: var(--color-surface-alt); border-color: var(--color-primary); }
.pagination .active { background: var(--color-primary-fond); color: var(--color-on-fond); border-color: var(--color-primary-fond); }
.pagination .disabled { opacity: .4; pointer-events: none; }
.pagination-info { text-align: center; font-size: .78rem; color: var(--color-muted); margin-top: .4rem; }
/* Libellés de « Précédente / Suivante » : complets, abrégés sur un petit
   écran — jamais une flèche seule. */
.pagination .pagination-court { display: none; }
@media (max-width: 768px) {
    .pagination .pagination-long { display: none; }
    .pagination .pagination-court { display: inline; }
}

/* ═══════════════════════════════════════════════════
   FILTERS
   ═══════════════════════════════════════════════════ */
/* .filters n'avait AUCUNE règle : les sélecteurs d'année de l'école
   tombaient sur l'apparence native du navigateur. Les anciennes barres
   .filters-bar (réunions, journal) ont rejoint le moule .liste-filtres. */
.filters { display: flex; gap: .6rem; flex-wrap: wrap; align-items: center; }
.filters select, .filters input {
    padding: .45rem .9rem; font-size: .88rem; min-height: 2.5rem;
    border: 1px solid var(--color-border-strong); border-radius: 999px;
    background: var(--color-surface); color: var(--color-text);
    font-family: var(--font);
}
.filters .btn { padding: .4rem .9rem; font-size: .88rem; border-radius: 999px; }

/* ═══════════════════════════════════════════════════
   UTILITIES
   ═══════════════════════════════════════════════════ */
.text-muted { color: var(--color-muted); }
.text-center { text-align: center; }
/* Texte aligné sur ses deux bords, pour un paragraphe d'explication.
   La césure automatique l'accompagne toujours : sur une colonne étroite
   de téléphone, justifier sans couper les mots creuse de larges trous
   entre eux — le français a des mots longs. -webkit- reste nécessaire
   pour Safari iOS. Sans effet sur la dernière ligne d'un paragraphe,
   donc inoffensif sur un texte d'une seule ligne. */
.text-justify,
/* Les familles de paragraphes qui portent de la prose explicative, pour
   n'avoir pas à répéter la classe sur chacun des soixante et quelques
   du site. Toutes visent un <p> ou un <details>, jamais une cellule de
   tableau : .ecole-sub habille aussi des <td>, où justifier deux mots
   dans une colonne étroite ne ferait que creuser des trous — d'où le
   « p. » devant. Un paragraphe centré garde sa règle, déclarée après. */
p.ecole-sub,
details > p,
.tps-desc,
.bcp-annex-text,
.bil-transit-note {
    text-align: justify;
    -webkit-hyphens: auto;
            hyphens: auto;
}
/* Garde-fou : un paragraphe explicitement centré le reste, même s'il
   porte par ailleurs une des classes justifiées ci-dessus. */
p.text-center { text-align: center; }
/* Un numéro de téléphone qu'on touche pour appeler (afficherTelephone).
   Il garde la couleur du texte qui l'entoure — il se lit d'abord comme
   un numéro — et ne se signale que par un soulignement discret. Jamais
   coupé en fin de ligne : « 06 12 34 » / « 56 78 » ne se relit pas. */
.lien-tel {
    color: inherit;
    white-space: nowrap;
    text-decoration: underline dotted;
    text-underline-offset: 3px;
}
.lien-tel:hover { color: var(--color-primary); }
/* Le bouton WhatsApp qui le suit : écarté du numéro, et resserré pour
   tenir sur la même ligne dans une case de tableau. */
.btn.lien-tel-wa { margin-left: .35rem; padding: .1rem .45rem; vertical-align: baseline; }
.text-danger { color: var(--color-danger); }
.text-success { color: var(--color-success); }
/* Un message « rien ici » — liste vide, aucun résultat. Une seule classe
   pour tout le site : il y en avait vingt-cinq, chacune avec sa marge.
   - de base : sous un titre de carte ou à la place d'une liste ;
   - --compact : dans une petite colonne (accueil, bilan, détail d'un point) ;
   - --grand : une page entière vide, avec son icône (.vide-liste-icone).
   Posée sur un .card-body, elle remplace son rembourrage (écrite après lui).
   Un message d'ÉTAT reste en clair ; une explication va dans une bulle ⓘ. */
.vide-liste { margin: 0; padding: 2rem; text-align: center; color: var(--color-muted); }
.vide-liste--compact { padding: .75rem 1rem; font-size: .85rem; }
.vide-liste--grand { padding: 3rem 1rem; }
.vide-liste-icone { margin: 0 0 1rem; font-size: 2.5rem; line-height: 1; }
.hide-mobile { }
@media (max-width: 768px) { .hide-mobile { display: none !important; } }

/* Page header — titre + boutons */
.page-actions { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; margin-bottom: 1.5rem; }
.page-actions h1 { flex: 1; font-size: 1.5rem; font-weight: 600; }
/* Posée DANS un .page-header, la rangée de boutons est à côté du titre :
   sa marge du bas (prévue quand elle porte elle-même le titre) la faisait
   remonter au-dessus de la ligne du titre, centrée avec sa marge. */
.page-header > .page-actions { margin-bottom: 0; }
/* Quand .page-actions porte aussi le titre (secrétariat, Utilisateurs),
   le titre prend sa ligne sur téléphone. Sans cela, les boutons — que
   la règle des petits écrans fait grandir pour se partager la largeur —
   lui disputaient la même ligne : « 📋 Réunions » se cassait en deux,
   l'emoji au-dessus du mot. Écrite après la règle de base ci-dessus, qui
   l'écraserait sinon à égalité de précision. */
@media (max-width: 768px) {
    .page-actions > h1 { flex: 1 1 100%; font-size: 1.3rem; }
    /* Sous un titre, les boutons se partagent la ligne à parts égales :
       grandir depuis la longueur de leur texte (règle des rangées de
       boutons de l'école) donnait deux boutons voisins de largeurs
       différentes. Les rangées sans titre gardent leur comportement. */
    .page-actions > h1 ~ .btn { flex: 1 1 0; min-width: 0; justify-content: center; }
}

/* Un titre et UN SEUL bouton (« Export CSV », « ← Retour », « + Nouveau
   compte »…) restent sur la même ligne sur téléphone : empilé, le bouton
   gâchait une ligne entière pour un geste souvent rare (16 écrans).
   Dès qu'il y a deux boutons ou plus, la rangée à part reprend ses droits.
   Sélecteurs en :has(), plus précis que les règles d'empilement
   (.page-header en colonne, .page-actions > h1 sur sa ligne) : ils les
   emportent où qu'ils soient écrits. */
@media (max-width: 768px) {
    .page-header:has(> h1 + :is(a, button).btn:last-child),
    .page-header:has(> h1 + :is(div, span):last-child > .btn:only-child) {
        flex-direction: row; flex-wrap: nowrap; align-items: center !important;
    }
    .page-header:has(> h1 + :is(a, button).btn:last-child) > h1,
    .page-header:has(> h1 + :is(div, span):last-child > .btn:only-child) > h1,
    .page-actions:has(> h1 + .btn:last-child) > h1 { flex: 1 1 auto; min-width: 0; }
    /* Même taille de titre que les autres écrans (.page-header h1) : à 1,3rem,
       « Mandatures ⓘ » ne tenait pas à côté de son bouton. */
    .page-actions:has(> h1 + .btn:last-child) > h1 { font-size: 1.15rem; }
    .page-header:has(> h1 + :is(a, button).btn:last-child) > .btn,
    .page-header:has(> h1 + :is(div, span):last-child > .btn:only-child) > :last-child,
    .page-actions:has(> h1 + .btn:last-child) > .btn { flex: 0 0 auto; white-space: nowrap; }
    /* Titre trop long pour garder le bouton à côté : passé dessous, le
       bouton reste calé à droite, comme sur les autres écrans. */
    .page-actions:has(> h1 + .btn:last-child) > .btn { margin-left: auto; font-size: .85rem; padding: .45rem .8rem; }
    .page-actions:has(> h1 + .btn:last-child) { gap: .5rem; flex-wrap: nowrap; }   /* comme .page-header : le titre cède, le bouton reste à côté */
    /* Même chose quand le seul bouton est un menu « ⋯ Plus » (Cotisations) :
       il restait seul sur sa ligne, à gauche. */
    .page-header:has(> h1 + .menu-plus:last-child) { flex-direction: row; flex-wrap: nowrap; align-items: center !important; }
    .page-header:has(> h1 + .menu-plus:last-child) > h1 { flex: 1 1 auto; min-width: 0; }
    .page-header:has(> h1 + .menu-plus:last-child) > .menu-plus { flex: 0 0 auto; }
    /* En-tête d'une carte : quand le titre pousse le bouton à la ligne,
       il reste à droite (accueils : « Tous les comptes », « Caisses et
       arrêtés » tombaient à gauche, leurs voisins à droite). */
    .card-header > .btn:last-child { margin-left: auto; }
    /* Le bouton enveloppé (Appel, Assiduité, Paramètres) : son conteneur
       garde la largeur de la rangée (.page-actions { width: 100% }), il
       écrasait le titre sur deux lignes. */
    .page-header:has(> h1 + :is(div, span):last-child > .btn:only-child) > :last-child { width: auto; }
    /* Un menu « ▾ » d'un .page-header, qui passe en colonne jusqu'à 768 px,
       tombe à gauche : son panneau, calé à droite du bouton, sortait de
       l'écran (« 🖨 Imprimer ▾ » des Classes). Il s'ouvre sous l'en-tête,
       calé à droite. */
    .page-header:has(> .menu-plus) { position: relative; }
    .page-header > .menu-plus { position: static; }
}

/* Card sans padding interne */
.card-body--flush { padding: 0; }
/* Zone de carte qui prolonge la précédente au lieu d'ouvrir un nouveau
   sujet : sans cela, les deux rembourrages s'additionnent et creusent
   quarante pixels de vide au milieu d'un même groupe de commandes. */
.card-body--suite { padding-top: 0; }
/* Spacers */
.mt-sm { margin-top: .75rem; }
.mt-1  { margin-top: 1rem; }
.d-inline { display: inline; }
.d-none { display: none !important; }
.d-block { display: block !important; }
.ml-auto { margin-left: auto; }

/* Grilles formulaire */
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
@media (max-width: 768px) { .grid-2 { grid-template-columns: 1fr; } }

/* Boutons formulaire */
.form-buttons { display: flex; gap: .75rem; margin-top: 1.5rem; }

/* Card formulaire (panneau blanc bordé) */
.form-card {
    background: var(--color-surface); border: 1px solid var(--color-border);
    border-radius: var(--radius); padding: 1.5rem; max-width: 700px;
}

/* Section séparée par un trait */

/* ═══════════════════════════════════════════════════
   UTILITAIRES TRÉSORERIE
   ═══════════════════════════════════════════════════ */

.mb-0 { margin-bottom: 0; }
.mb-1 { margin-bottom: 1rem; }
.ml-05 { margin-left: .5rem; }
.p-0 { padding: 0; }
.p-1-5 { padding: 1.5rem; }
.w-full { width: 100%; }
/*  Sorties des style="…" des pages (10/10/2026). Largeur d'une colonne
    étroite (case à cocher, bouton), en rem ; liste posée dans une alerte. */
.table th.larg-2   { width: 2rem; }
.table th.larg-2-5 { width: 2.5rem; }
.table th.larg-3   { width: 3rem; }
.table th.larg-6   { width: 6rem; }
.table th.larg-9   { width: 9rem; }
.liste-alerte { margin: .5rem 0 0 1.2rem; }
.nowrap { white-space: nowrap; }
.d-inline { display: inline; }
.text-sm { font-size: .85rem; }
.text-right { text-align: right; }
.text-center { text-align: center; }
.text-uppercase { text-transform: uppercase; }

/* ═══════════════════════════════════════════════════════════════
   UTILITAIRES — ajoutés par lot 2B
   ═══════════════════════════════════════════════════════════════ */
.text-xs { font-size: .75rem; }

/* ── Utility text colors ── */
.text-info    { color: var(--color-info); }
.text-warning { color: var(--color-warning); }

/* ── Résidus header/permissions/secretariat ── */
.mob-icon-pos           { position:relative; }
.notif-badge-pos        { position:absolute; top:2px; right:2px; font-size:.55rem; min-width:12px; height:12px; }
.search-icon            { font-size:1rem; opacity:.5; }

/* ============================================================
   ── Nouveautés session paramètres + courriers ──────────────
   ============================================================ */

/* ── Groupe de boutons dans l'en-tête de page (harmonisation) ── */
.page-actions-btns {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    align-items: center;
}
/*  640 px et non 600 : c'est le seuil auquel .page-actions fait déjà
    passer ses boutons en pleine largeur. Deux seuils pour le même geste
    laissaient, entre les deux, une bande de quarante pixels où les
    boutons reprenaient leur largeur naturelle et finissaient en
    escalier — le défaut que les deux règles cherchent à éviter. */
@media (max-width: 768px) {
    .page-actions-btns {
        width: 100%;          /* occupe toute la largeur sous le h1 */
        gap: .4rem;
    }
    /* Un menu « ⋯ » en bout de rangée garde sa largeur : posé seul sur
       une ligne, il en gâchait une entière pour trois points, et son
       panneau (calé à droite) sortait de l'écran par la gauche. Les
       boutons qui l'accompagnent se partagent le reste de la ligne. */
    .page-actions-btns > .menu-plus { flex: 0 0 auto; }
    .page-actions-btns > .menu-plus > .btn { flex: none; width: auto; }
    .page-actions-btns:has(> .menu-plus) > .btn { flex: 1 1 0; }
    .page-actions-btns .btn {
        flex: 1 1 calc(50% - .2rem);  /* 2 boutons par ligne en mobile */
        min-width: 0;
        padding: .5rem .6rem;
        font-size: .82rem;
        justify-content: center;
        white-space: nowrap;
    }
    /* Si un seul bouton : pleine largeur */
    .page-actions-btns .btn:only-child {
        flex: 1 1 100%;
    }
}

/* ── Boutons d'action dans l'en-tête de page ── */
.params-header-actions {
    display: flex;
    gap: .5rem;
    flex-wrap: wrap;
}
@media (max-width: 768px) {
    /* Même motif que .page-actions-btns : 2 boutons par ligne plutôt
       qu'empilés en pleine largeur, pour ne pas repousser le contenu. */
    .params-header-actions { width: 100%; gap: .4rem; }
    .params-header-actions .btn {
        flex: 1 1 calc(50% - .2rem);
        min-width: 0;
        padding: .5rem .6rem;
        font-size: .78rem;
        justify-content: center;
        text-align: center;
        white-space: normal;
        line-height: 1.25;
    }
    .params-header-actions .btn:only-child { flex: 1 1 100%; }
}

/* ── Case à cocher avec petit texte sous le label ── */
.checkbox-label {
    display: flex;
    align-items: flex-start;
    gap: .5rem;
    cursor: pointer;
    font-weight: normal;
}
.checkbox-label input[type="checkbox"] {
    margin-top: .25rem;
    flex-shrink: 0;
}
/* Dans un .form-group, la règle des libellés (display: block, plus
   précise) repoussait le texte sous la case, seule sur sa ligne. */
.form-group .checkbox-label { display: flex; font-weight: normal; }
.checkbox-label strong { display: block; }
.checkbox-label small {
    display: block;
    font-size: .78rem;
    font-weight: normal;
    margin-top: .1rem;
}

/* Boutons de couleur en mode sombre : fond teinté, texte de la couleur. */
[data-theme="dark"] .btn-warning { background: var(--pal-ambre-400-a12); color: var(--color-warning); border-color: var(--pal-ambre-400-a30); }
[data-theme="dark"] .btn-warning:hover { background: var(--pal-ambre-400-a20); }
[data-theme="dark"] .btn-danger  { background: var(--pal-rouge-600-a12); color: var(--color-danger); border-color: var(--pal-rouge-600-a30); }
[data-theme="dark"] .btn-danger:hover  { background: var(--pal-rouge-600-a20); }
[data-theme="dark"] .btn-success { background: var(--pal-vert-500-a12); color: var(--color-success-text); border-color: var(--pal-vert-500-a30); }
[data-theme="dark"] .btn-success:hover { background: var(--pal-vert-500-a20); }

/* ███████████████████████████████████████████████████████████████
   5. ÉCRANS — PORTAIL, ACCUEILS, SECRÉTARIAT
   ███████████████████████████████████████████████████████████████ */

/* ═══════════════════════════════════════════════════
   PORTAIL — index.php (refonte B2·3, étape 4 ; maquette
   docs/maquettes/ecrans/5-portail.html)
   ═══════════════════════════════════════════════════ */
.portal-page { margin: 0 auto; }
.portal-hello { display: flex; align-items: baseline; flex-wrap: wrap; gap: .3rem .9rem; margin-bottom: 1.1rem; }
.portal-hello h1 { font-size: 1.75rem; font-weight: 600; margin: 0; }
.portal-date { color: var(--color-muted); }

/* « Aujourd'hui » : ce qui concerne la personne connectée, en pastilles
   blanches à bord fin, icône grise devant. */
.portal-jour-bloc { margin-bottom: 1.25rem; }
.portal-jour-titre { font-family: var(--font); font-size: .85rem; font-weight: 600; color: var(--color-muted); margin: 0 0 .5rem; }
.portal-jour { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem; }
.portal-jour__item {
    display: inline-flex; align-items: center; gap: .6rem;
    min-height: 2.6rem; padding: .5rem 1rem; box-sizing: border-box;
    border: 1px solid var(--color-border); border-radius: 14px;
    background: var(--color-surface); color: var(--color-text);
    font-size: .9rem; text-decoration: none;
}
.portal-jour__item .icone { color: var(--color-muted); flex-shrink: 0; }
.portal-jour__item strong { font-weight: 700; }
a.portal-jour__item:hover { border-color: var(--color-border-strong); text-decoration: none; color: var(--color-text); }
.portal-jour__etat { font-size: .85rem; color: var(--color-warning); font-weight: 600; }

/* Les cartes des modules : en-tête pastel de la couleur du module, filet
   de 4 px de cette couleur en haut, icône dans un carré blanc arrondi.
   Couleurs lues sur --color-treso / -accent / -ecole, qui ne suivent pas
   l'accent du module de la page (le portail n'en a pas). */
.module-card--treso  { --mod: var(--color-treso);  --mod-t: var(--color-treso-mid); --mod-filet: var(--color-treso-fond); }
.module-card--secret { --mod: var(--color-accent); --mod-t: var(--color-accent-mid); }
.module-card--ecole  { --mod: var(--color-ecole);  --mod-t: var(--color-ecole-mid); }
.modules-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1.25rem; align-items: start; margin-bottom: 1.25rem; }
@media (max-width: 1000px) { .modules-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 768px)  { .modules-grid { grid-template-columns: 1fr; gap: .8rem; } }
.module-card {
    display: flex; flex-direction: column; overflow: hidden;
    background: var(--color-surface); border-radius: var(--radius-lg);
    box-shadow: var(--shadow);
}
.module-card__top {
    display: flex; align-items: center; gap: .8rem;
    padding: 1rem 1.2rem; text-decoration: none;
    background: var(--mod-t); color: var(--mod);
    box-shadow: inset 0 4px 0 var(--mod-filet, var(--mod));
}
.module-card__top:hover { text-decoration: none; color: var(--mod); }
@media (hover: hover) { .module-card__top:hover { filter: brightness(.97); } }
.module-card__icon {
    width: 2.6rem; height: 2.6rem; border-radius: 12px; flex-shrink: 0;
    display: grid; place-items: center; background: var(--color-surface);
}
.module-card__body { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.module-card__title { font-family: var(--font-title); font-size: 1.2rem; font-weight: 600; }
.module-card__desc { font-size: .85rem; font-weight: 600; opacity: .85; }
.module-card__cta { font-weight: 700; font-size: .9rem; white-space: nowrap; }

.module-card__atraiter-titre { padding: .75rem 1.2rem .25rem; font-size: .85rem; font-weight: 700; color: var(--color-muted); }
.module-card__atraiter .atraiter-ligne { padding-left: 1.2rem; padding-right: 1.2rem; }
.module-card__atraiter .atraiter-liste li:first-child { border-top: 1px solid var(--color-border); }
.module-card__plus {
    display: block; padding: .7rem 1.2rem; font-size: .88rem;
    color: var(--color-muted); text-decoration: none; border-top: 1px solid var(--color-border);
}
.module-card__plus:hover { color: var(--color-text); text-decoration: underline; }
.module-card__plus--tel { display: none; }
.module-card__ok { padding: .8rem 1.2rem; font-size: .9rem; color: var(--color-success); font-weight: 600; }

/* « Créer : » sous les cartes. */
.portal-creer { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem; }
.portal-creer__titre { font-size: .85rem; font-weight: 600; color: var(--color-muted); }

/* Téléphone : pastilles « Aujourd'hui » deux par ligne (Reprendre sur
   toute la largeur), en-tête de carte sur une ligne sans sous-titre, et
   deux lignes « À traiter » par carte. */
@media (max-width: 768px) {
    .portal-hello h1 { font-size: 1.45rem; }
    .portal-date { display: none; }
    .portal-jour-titre { display: none; }
    .portal-jour { display: grid; grid-template-columns: 1fr 1fr; gap: .5rem; }
    .portal-jour__item { font-size: .85rem; padding: .5rem .75rem; }
    .portal-jour__item--reprendre, .portal-jour__geste, .portal-jour__etat { grid-column: 1 / -1; }
    .module-card__top { padding: .75rem .9rem; }
    .module-card__icon { width: 2.2rem; height: 2.2rem; }
    .module-card__title { font-size: 1.05rem; }
    .module-card__desc, .module-card__atraiter-titre { display: none; }
    .module-card__atraiter .atraiter-ligne { padding-left: .9rem; padding-right: .9rem; }
    .module-card__atraiter .atraiter-liste li:nth-child(n+3) { display: none; }
    .module-card__plus--ordi { display: none; }
    .module-card__plus--tel { display: block; padding-left: .9rem; }
    .portal-creer__titre { flex-basis: 100%; }
    .portal-creer .btn { flex: 1 1 0; }
}

/* ═══════════════════════════════════════════════════
   RECHERCHE — search/index.php
   ═══════════════════════════════════════════════════ */
.search-title { font-size: 1.5rem; font-weight: 600; margin-bottom: 1.5rem; }
.search-bar { display: flex; gap: .5rem; margin-bottom: 2rem; position: relative; }
.search-bar input[type="text"] {
    flex: 1; min-width: 0; padding: .6rem 1rem; border: 2px solid var(--color-border);
    border-radius: var(--radius); font-size: 1rem; color: var(--color-text);
    background: var(--color-surface); transition: border-color .15s;
}
.search-bar input[type="text"]:focus { outline: none; border-color: var(--color-primary); box-shadow: 0 0 0 3px var(--pal-bleu-600-a10); }
.search-bar button { padding: .6rem 1.25rem; }
.search-dropdown {
    display: none; position: absolute; top: 100%; left: 0; right: 0; z-index: 50;
    background: var(--color-surface); border: 1px solid var(--color-border);
    border-radius: var(--radius); box-shadow: 0 8px 24px var(--pal-noir-a12);
    margin-top: .35rem; max-height: 350px; overflow-y: auto;
}
.search-dropdown-item {
    display: flex; gap: .6rem; padding: .6rem .85rem; text-decoration: none;
    color: var(--color-text); border-bottom: 1px solid var(--color-border);
    align-items: center; font-size: .85rem; transition: background .1s;
}
.search-dropdown-item:hover { background: var(--color-surface-alt); }
.search-dropdown-icon { font-size: 1.1rem; }
.search-dropdown-body { flex: 1; min-width: 0; }
.search-dropdown-label { font-weight: 500; display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.search-dropdown-sub { font-size: .75rem; color: var(--color-muted); }
.search-stats { font-size: .85rem; color: var(--color-muted); margin-bottom: 1.5rem; }
.result-group-title {
    font-size: .9rem; font-weight: 600; color: var(--color-muted);
    margin-bottom: .75rem; margin-top: 1.5rem;
    padding-bottom: .5rem; border-bottom: 1px solid var(--color-border);
}
.result-item {
    background: var(--color-surface); border: 1px solid var(--color-border);
    border-radius: var(--radius); padding: 1rem 1.25rem;
    margin-bottom: .75rem; transition: border-color .15s;
}
.result-item:hover { border-color: var(--color-primary); }
.result-title a { font-weight: 600; font-size: .95rem; color: var(--color-primary); text-decoration: none; }
.result-title a:hover { text-decoration: underline; }
.result-meta { display: flex; gap: 1rem; flex-wrap: wrap; margin-top: .3rem; font-size: .78rem; color: var(--color-muted); }
.result-snippet { margin-top: .5rem; font-size: .85rem; line-height: 1.6; color: var(--color-text); }
.result-snippet mark { background: var(--color-warning-soft); color: var(--color-warning-text); padding: .05rem .2rem; border-radius: 2px; }
.result-point-label {
    display: inline-block; padding: .15rem .5rem; border-radius: 999px;
    font-size: .7rem; font-weight: 500; background: var(--color-info-lt); color: var(--color-primary);
}
.search-hint { margin-top: .5rem; font-size: .85rem; }

/* ═══════════════════════════════════════════════════
   NOTIFICATIONS — notifications/index.php
   ═══════════════════════════════════════════════════ */
.notif-header { display: flex; align-items: center; gap: 1rem; margin-bottom: 1.5rem; flex-wrap: wrap; }
.notif-header h1 { flex: 1; font-size: 1.5rem; font-weight: 600; }
.notif-actions { display: flex; gap: .5rem; }
.notif-item {
    display: flex; gap: .75rem; align-items: flex-start;
    padding: .75rem 1rem; border-bottom: 1px solid var(--color-border); transition: background .15s;
}
.notif-item:last-child { border-bottom: none; }
.notif-item:hover { background: var(--color-subtle); }
.notif-item.unread { background: var(--color-info-lt); }
.notif-icon {
    width: 36px; height: 36px; border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    font-size: 1rem; flex-shrink: 0;
}
.notif-icon.type-COMMENTAIRE_ADDED    { background: var(--color-info-soft); }
.notif-icon.type-REUNION_RELECTURE    { background: var(--color-warning-soft); }
.notif-icon.type-REUNION_APPROUVEE    { background: var(--color-success-mid); }
.notif-icon.type-ECHEANCE_J3          { background: var(--color-danger-soft); }
.notif-icon.type-ACTION_ASSIGNEE      { background: var(--pal-violet-100); }
.notif-icon.type-ACTION_COMMENT       { background: var(--color-info-soft); }
.notif-icon.type-ACTION_MARKED_DONE   { background: var(--color-success-mid); }
.notif-icon.type-default              { background: var(--color-neutral-soft); }
[data-theme="dark"] .notif-item:hover { background: var(--color-surface-alt); }
[data-theme="dark"] .notif-item.unread { background: var(--color-info-soft); }
[data-theme="dark"] .notif-icon.type-COMMENTAIRE_ADDED { background: var(--color-info-soft); }
[data-theme="dark"] .notif-icon.type-REUNION_RELECTURE { background: var(--color-warning-soft); }
[data-theme="dark"] .notif-icon.type-REUNION_APPROUVEE { background: var(--color-success-soft); }
[data-theme="dark"] .notif-icon.type-ECHEANCE_J3       { background: var(--color-danger-soft); }
[data-theme="dark"] .notif-icon.type-ACTION_ASSIGNEE   { background: var(--pal-violet-nuit); }
[data-theme="dark"] .notif-icon.type-ACTION_COMMENT    { background: var(--color-info-soft); }
[data-theme="dark"] .notif-icon.type-ACTION_MARKED_DONE { background: var(--color-success-soft); }
[data-theme="dark"] .notif-icon.type-default            { background: var(--color-surface-alt); }
.notif-body { flex: 1; min-width: 0; }
.notif-message { font-size: .875rem; line-height: 1.4; }
/*  Le message est le lien : il garde l'allure du texte. */
.notif-message a, .notif-message a:hover { color: inherit; text-decoration: none; }
.notif-item.unread .notif-message { font-weight: 500; }
.notif-date { font-size: .75rem; color: var(--color-muted); margin-top: .2rem; }
.notif-read-btn {
    background: none; border: none; cursor: pointer;
    font-size: .8rem; color: var(--color-muted); padding: .2rem .4rem; border-radius: 4px; flex-shrink: 0;
}
.notif-read-btn:hover { background: var(--color-border); color: var(--color-text); }
.notif-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--color-primary-fond); flex-shrink: 0; margin-top: .4rem; }
.notif-dot.read { background: transparent; }

/* ═══════════════════════════════════════════════════
   ACCUEILS DES MODULES — includes/accueil.php (refonte B2·3, étape 4)
   ═══════════════════════════════════════════════════
   « Bonjour » + date, gestes de création à droite ; quatre tuiles ;
   « À faire maintenant » à côté d'un second bloc propre au module. */
.accueil-entete {
    display: flex; align-items: center; justify-content: space-between;
    flex-wrap: wrap; gap: .75rem 1rem; margin-bottom: 1.1rem;
}
.accueil-bonjour { display: flex; align-items: baseline; flex-wrap: wrap; gap: .25rem .9rem; }
.accueil-bonjour h1 { font-size: 1.75rem; font-weight: 600; margin: 0; }
.accueil-date, .accueil-complement { color: var(--color-muted); }
.accueil-complement::before { content: "· "; }
.accueil-gestes { display: flex; flex-wrap: wrap; gap: .6rem; }

/*  Quatre tuiles : rond pastel de la couleur du module, libellé « … › »,
    chiffre en Lexend, une ligne dessous. */
.accueil-tuiles { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 1rem; margin-bottom: 1.25rem; }
.accueil-tuile { display: flex; flex-direction: column; align-items: flex-start; gap: .15rem; text-decoration: none; color: inherit; }
.accueil-tuile:hover { text-decoration: none; color: inherit; }
.accueil-tuile-ico {
    width: 2.4rem; height: 2.4rem; border-radius: 50%; margin-bottom: .45rem;
    display: grid; place-items: center;
    background: var(--color-primary-mid); color: var(--color-primary);
}
.accueil-tuile .stat-label { margin: 0; color: var(--color-muted); }
.accueil-tuile .stat-value { font-size: 1.6rem; }
.accueil-tuile .stat-sub { margin-top: .1rem; line-height: 1.4; }
.accueil-tuile--danger .stat-value { color: var(--color-danger); }
.accueil-tuile--danger .accueil-tuile-ico { background: var(--color-danger-lt); color: var(--color-danger); }
.accueil-tuile--warn .accueil-tuile-ico { background: var(--color-warning-lt); color: var(--color-warning); }
@media (hover: hover) { .accueil-tuile.stat-card--link:hover { box-shadow: var(--shadow-md); transform: translateY(-1px); } }

/*  Deux colonnes : « À faire » à gauche (le travail du jour), le bloc du
    module à droite, plus large. Une seule présente : elle prend tout. */
.accueil-colonnes { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: 1.25rem; align-items: start; margin-bottom: 1.25rem; }
.accueil-colonnes > :only-child { grid-column: 1 / -1; }
.accueil-pile { display: flex; flex-direction: column; gap: 1.25rem; min-width: 0; }
.accueil-pile > .card + .card { margin-top: 0; }
/*  Ligne grise sous une action ou une réunion (réunion d’origine, date, rédacteur). */
.sec-action-sous { display: block; font-size: .82rem; color: var(--color-muted); margin-top: .1rem; }
.accueil-reunions .badge { flex-shrink: 0; }
.accueil-colonnes > .card + .card { margin-top: 0; }
.accueil-afaire .card-header h2 { display: flex; align-items: center; gap: .5rem; }
.accueil-afaire-nb {
    min-width: 1.6rem; height: 1.6rem; padding: 0 .45rem; border-radius: 999px;
    display: inline-grid; place-items: center;
    background: var(--color-neutral-soft); color: var(--color-muted); font-size: .8rem; font-weight: 700;
}
.accueil-rien { margin: 0; padding: 1rem 1.25rem; color: var(--color-success); font-weight: 600; }
.accueil-afaire .atraiter-ligne { flex-wrap: wrap; row-gap: .25rem; }
/*  La gravité écrite en mots, pas seulement en couleur. */
.accueil-pilule {
    flex-shrink: 0; display: inline-flex; align-items: center;
    height: 1.55rem; padding: 0 .6rem; border-radius: 999px;
    font-size: .75rem; font-weight: 700; white-space: nowrap;
}
.accueil-pilule--danger { background: var(--color-danger-lt); color: var(--color-danger); }
.accueil-pilule--warn   { background: var(--color-warning-lt); color: var(--color-warning); }
.accueil-pilule--info   { background: var(--color-info-lt); color: var(--color-info); }

/*  « En caisse » (École) : une ligne par compte, libellé à gauche,
    montant à droite — ce qu’on compare se range en colonnes. */
.accueil-total { font-family: var(--font); font-size: .9rem; font-weight: 600; color: var(--color-muted); margin-left: .35rem; white-space: nowrap; }
.accueil-second .card-header { flex-wrap: wrap; gap: .5rem; }
.accueil-caisses { list-style: none; margin: 0; padding: 0; }
.accueil-caisses li + li { border-top: 1px solid var(--color-border); }
.accueil-caisses a {
    display: flex; align-items: center; gap: .75rem; min-height: 52px;
    padding: .6rem 1.25rem; color: var(--color-text); text-decoration: none;
}
.accueil-caisses a:hover { background: var(--color-surface-alt); text-decoration: none; color: var(--color-text); }
.accueil-caisses-ico {
    width: 2.1rem; height: 2.1rem; border-radius: 50%; flex-shrink: 0;
    display: grid; place-items: center; background: var(--color-primary-mid); color: var(--color-primary);
}
.accueil-caisses-lib { flex: 1; min-width: 0; display: flex; flex-direction: column; font-weight: 600; }
.accueil-caisses-lib > :not(:first-child), .accueil-caisses-note { font-weight: 400; font-size: .82rem; color: var(--color-muted); }
.accueil-caisses-val { font-family: var(--font-title); font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
.accueil-tuile .ecole-jauge { display: block; width: 100%; margin: .3rem 0 .35rem; }

/*  École : « Dernières opérations » à gauche d'« En caisse », à la même
    hauteur. Symétrie (demande de l'utilisateur) : à parts égales, pas le
    5 / 7 des autres accueils.
    ⚠ La hauteur est posée par un petit script de ecole/index.php, pas par
    le CSS : la liste vit dans un <details>, dont le contenu est rangé dans
    une boîte à part (::details-content) que tous les navigateurs ne savent
    pas étirer — la carte restait courte, ou laissait une bande blanche
    (deux captures de l'utilisateur). Ici, le cas sans script : la liste à
    sa hauteur, bornée, les cartes non étirées. */
.accueil-colonnes--egales { align-items: start; grid-template-columns: repeat(2, minmax(0, 1fr)); }
details.accueil-registre { min-width: 0; }
.accueil-registre-liste {
    list-style: none; margin: 0; padding: 0;
    max-height: 22rem; overflow-y: auto;
}
/*  Les deux cartes se replient : l'en-tête de carte devient le <summary>. */
details.accueil-repli > summary { list-style: none; cursor: pointer; }
details.accueil-repli > summary::-webkit-details-marker { display: none; }
details.accueil-repli > summary h2 { display: flex; align-items: center; gap: .4rem; }
details.accueil-repli:not([open]) > summary { border-bottom: 0; }
.accueil-registre-jour {
    padding: .3rem 1.25rem; font-size: .78rem; font-weight: 700;
    color: var(--color-primary); background: var(--color-surface-alt);
    border-top: 1px solid var(--color-border);
}
.accueil-registre-liste > .accueil-registre-jour:first-child { border-top: 0; }
.accueil-registre-ligne {
    display: flex; align-items: center; gap: .75rem;
    padding: .5rem 1.25rem; border-top: 1px solid var(--color-border);
}
.accueil-registre-jour + .accueil-registre-ligne { border-top: 0; }
/*  Le filet suit le genre, comme dans le Registre : vert ce qui entre,
    rouge ce qui sort, gris un transfert. */
.accueil-registre--famille, .accueil-registre--sortie { box-shadow: inset 4px 0 0 var(--color-success); }
.accueil-registre--depense   { box-shadow: inset 4px 0 0 var(--color-danger); }
.accueil-registre--transfert { box-shadow: inset 4px 0 0 var(--color-border-strong); }
.accueil-registre-lib { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.accueil-registre-lib > strong, .accueil-registre-lib > a {
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.accueil-registre-meta { font-size: .8rem; color: var(--color-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.accueil-registre-val { font-family: var(--font-title); font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
.accueil-registre-val--entree { color: var(--color-success); }
.accueil-registre-val--sortie { color: var(--color-danger); }
.accueil-registre-val--transfert { color: var(--color-muted); }
@media (max-width: 1000px) {
    .accueil-colonnes--egales { grid-template-columns: 1fr; }
}
/*  Trésorerie : « Opérations de caisse » et « Opérations bancaires » côte
    à côte. À nombre de lignes égal, la carte qui compte le plus de
    bandeaux de jour dépassait l'autre : même hauteur bornée pour les
    deux, la suite défile dans la carte (comme le registre de l'école).
    Ordinateur seulement — sur téléphone les cartes s'empilent, et une
    liste qui défile dans une page qui défile se manie mal au doigt :
    les lignes de la suite n'y sont pas affichées (règle plus bas). */
@media (min-width: 769px) {
    .accueil-ops-defile { max-height: 28rem; overflow-y: auto; }
}

@media (max-width: 1000px) {
    .accueil-tuiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .accueil-colonnes { grid-template-columns: 1fr; }
}
/*  Téléphone : la date s'efface, les gestes se partagent la ligne, les
    tuiles restent deux par ligne, plus serrées. */
@media (max-width: 768px) {
    .accueil-bonjour h1 { font-size: 1.45rem; }
    .accueil-date { display: none; }
    .accueil-complement::before { content: none; }
    .accueil-gestes { width: 100%; }
    .accueil-gestes .btn { flex: 1 1 0; min-width: 0; white-space: normal; text-align: center; }
    /*  Gestes que la barre du bas porte déjà (Trésorerie : Saisie,
        Collecte) : pas deux fois sur le même écran. */
    .accueil-gestes--ordi { display: none; }
    /*  Trésorerie : la suite des deux listes d'opérations (au-delà de
        six) ne s'affiche que sur ordinateur, où la carte défile. Sélecteur
        long exprès : les règles des cartes .ops-table, plus bas, rendent
        chaque ligne en bloc. */
    .accueil-ops-defile .ops-table tbody tr.accueil-ops-suite { display: none; }
    /*  « À faire » : la pilule au-dessus, la phrase et le chiffre dessous
        — côte à côte, la phrase se coupait au deuxième mot. */
    .accueil-afaire .atraiter-ligne { display: grid; grid-template-columns: minmax(0, 1fr) auto auto; column-gap: .6rem; }
    .accueil-afaire .accueil-pilule { grid-column: 1 / -1; justify-self: start; }
    /*  Lignes longues (actions) : l’échéance passe sous la phrase. */
    .atraiter-liste--longue .atraiter-ligne { flex-wrap: wrap; }
    .atraiter-liste--longue .atraiter-lib { flex-basis: calc(100% - 2.5rem); }
    .atraiter-liste--longue .atraiter-val { margin-left: calc(10px + .75rem); font-size: .85rem; }
    .accueil-tuiles { gap: .6rem; }
    .accueil-tuile { padding: .8rem .9rem; }
    .accueil-tuile-ico { width: 2rem; height: 2rem; margin-bottom: .3rem; }
    .accueil-tuile .stat-value { font-size: 1.25rem; }
    .accueil-tuile .stat-label { font-size: .8rem; }
}

/* Stat sub-info */
.stat-sub { font-size: .75rem; color: var(--color-muted); margin-top: 4px; }

/* Carte dashboard */
.dash-card { margin-bottom: 1.25rem; }

/* Stats du mois */

.treso-sub-count { font-size: .82rem; color: var(--color-muted); }

/* ═══════════════════════════════════════════════════
   RÉUNIONS — Composants spécifiques
   ═══════════════════════════════════════════════════ */
.type-comite             { background: var(--color-info-soft); color: var(--color-info-text); }
.type-AG_ordinaire       { background: var(--color-warning-soft); color: var(--color-warning-text); }
.type-AG_extraordinaire  { background: var(--color-pink-soft); color: var(--color-pink-text); }
.type-commission         { background: var(--color-purple-soft); color: var(--color-purple-text); }
.reunion-statut-badges { display: inline-flex; flex-wrap: wrap; gap: .25rem; align-items: center; }
/* Liste des réunions : type et nombre de points sous la date sur
   ordinateur ; sur téléphone ils passent dans la ligne dépliée, et les
   deux pastilles (statut, convocation) s'empilent à droite — côte à côte
   elles écrasaient la date sur trois lignes. */
.reunion-type-mobile { display: none; }
@media (max-width: 768px) {
    .reunion-sous-type { display: none; }
    .reunion-type-mobile { display: inline; }
    .reunion-statut-badges { flex-direction: column; align-items: flex-end; }
}

/* Date et heure d'une réunion (create.php, edit.php) : deux champs dans
   la colonne que le champ « date + heure » occupait seul. L'heure garde
   une largeur fixe — elle ne porte que cinq caractères, la date prend le
   reste. Sous 600 px la grille passe déjà en une colonne, et les deux
   tiennent encore côte à côte sur la largeur d'un téléphone. */
/*  margin-bottom : ses deux champs n'ont pas le leur (ci-dessous) ; sans lui,
    « Titre de la réunion » se collait sous la date. */
.reunion-datetime { display: flex; gap: .6rem; align-items: flex-start; margin-bottom: 1rem; }
.reunion-datetime > .form-group { flex: 1 1 auto; min-width: 0; margin-bottom: 0; }
.reunion-datetime > .reunion-datetime-heure { flex: 0 0 7rem; }

/* Le rattachement calculé (mandature), écrit sous les champs : une
   information, pas un champ — d'où le ton discret et le filet à gauche
   qui la détache de la saisie. */
.reunion-mandature-info {
    margin: 0 0 1.15rem; padding: .5rem .75rem;
    border-left: 3px solid var(--color-border-strong);
    background: var(--color-surface-alt);
    border-radius: 0 var(--radius) var(--radius) 0;
    font-size: .82rem; color: var(--color-muted);
}
.reunion-mandature-info strong { color: var(--color-text); }

/* La ligne « Reprendre une action ouverte », sous le formulaire d'ajout
   d'action d'un point : un geste occasionnel, discret à côté du geste
   courant, mais nommé en toutes lettres. */
.point-reprise {
    display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
    margin: .5rem 0 0; font-size: .8rem;
}

/*  « Qui s'en occupe ? » : le panneau de cases à cocher d'une action
    (champResponsables()). Il emprunte .menu-plus, déjà mutualisé ; ne
    restent que la largeur, la hauteur plafonnée — vingt-trois comptes
    dépasseraient l'écran — et le filet qui sépare la liste de la mention
    libre. */
.act-resp-panneau { min-width: 260px; max-width: 320px; padding: .5rem; }
.act-resp-liste { max-height: 14rem; overflow-y: auto; display: grid; gap: .25rem; }
.act-resp-liste .checkbox-label { font-size: .85rem; padding: .15rem .1rem; }
.act-resp-libre { border-top: 1px solid var(--color-border); margin-top: .5rem; padding-top: .5rem; }
.act-resp-libre label { display: block; font-size: .78rem; color: var(--color-muted); margin-bottom: .25rem; }
.act-resp-libre input { width: 100%; padding: .35rem .5rem; font-size: .85rem;
    border: 1px solid var(--color-border-strong); border-radius: var(--radius);
    background: var(--color-surface); color: var(--color-text); font-family: var(--font); }
/*  Le bouton dit qui a été choisi : son libellé s'allonge, il ne doit pas
    pousser la date et « + Action » hors de la ligne. */
.act-resp-btn { max-width: 16rem; }
.act-resp-resume { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/*  La ligne « Prévenir les responsables », au-dessus du récapitulatif des
    actions : un bouton et le compte de ce qui n'a jamais été annoncé. */
.pv-annonce-ligne {
    display: flex; align-items: center; gap: .6rem; flex-wrap: wrap;
    margin: 0 0 .75rem; font-size: .82rem;
}

/*  « À venir », sous la grille du calendrier : ce qu'il reste à préparer,
    même dans un autre mois. Une ligne par réunion, son état de convocation
    en coup d'œil et ses deux gestes à droite. */
.cal-avenir { margin-top: 1.25rem; }
.cal-avenir-liste { list-style: none; margin: 0; padding: 0; }
.cal-avenir-item {
    display: flex; align-items: center; gap: .5rem .75rem; flex-wrap: wrap;
    padding: .6rem 1.25rem; border-bottom: 1px solid var(--color-border);
    font-size: .85rem;
}
.cal-avenir-item:last-child { border-bottom: none; }
.cal-avenir-quand { color: var(--color-muted); font-size: .8rem; }
.cal-avenir-titre { font-weight: 600; color: var(--color-text); text-decoration: none; }
.cal-avenir-titre:hover { color: var(--color-primary); }
.cal-avenir-actions { display: flex; gap: .35rem; margin-left: auto; }
/*  Un jour se clique pour y préparer une réunion : le curseur doit le dire,
    y compris sur un jour vide. */
.cal-cell--clic { cursor: pointer; }
/*  Le lien d'ajout, en bas de la fenêtre d'un jour. */
.cal-modal-ajout { display: inline-flex; margin-top: .5rem; }
/*  La mention « Convoquée le … » d'une réunion passée : une information,
    pas une section — la carte d'envoi, elle, a disparu avec la date. */
.pv-convoc-rappel { margin: -.5rem 0 1.5rem; font-size: .82rem; }
@media (max-width: 768px) {
    .cal-avenir-item { align-items: flex-start; }
    .cal-avenir-quand, .cal-avenir-titre { flex: 1 0 100%; }
    .cal-avenir-actions { flex: 1 0 100%; margin-left: 0; }
    .cal-avenir-actions > * { flex: 1 1 0; justify-content: center; }
}

/* Calendrier (calendar.php) */
.cal-header {
    display: flex; align-items: center; justify-content: space-between;
    margin-bottom: 1.5rem; flex-wrap: wrap; gap: .75rem;
}
.cal-header h1 { font-size: 1.5rem; font-weight: 600; }
.cal-nav { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.cal-nav a:not(.cal-today-btn) {
    display: inline-flex; align-items: center; justify-content: center;
    width: 36px; height: 36px; border-radius: var(--radius);
    border: 1px solid var(--color-border); background: var(--color-surface);
    color: var(--color-text); text-decoration: none; font-size: 1rem;
    flex-shrink: 0;
    transition: background .15s, border-color .15s;
}
.cal-nav a:not(.cal-today-btn):hover { background: var(--color-surface-alt); border-color: var(--color-primary); }
.cal-month-label { font-size: 1.1rem; font-weight: 600; min-width: 160px; text-align: center; }
.cal-today-btn {
    height: 36px; padding: 0 .75rem; font-size: .82rem;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: var(--radius); border: 1px solid var(--color-border);
    background: var(--color-surface); color: var(--color-text);
    text-decoration: none; cursor: pointer; font-family: var(--font);
    transition: background .15s, border-color .15s;
}
.cal-today-btn:hover { background: var(--color-surface-alt); border-color: var(--color-primary); }

.cal-grid {
    display: grid; grid-template-columns: repeat(7, 1fr);
    border: 1px solid var(--color-border); border-radius: var(--radius);
    overflow: hidden; background: var(--color-border); gap: 1px;
}
.cal-dow {
    background: var(--color-primary-fond); color: var(--color-on-fond);
    text-align: center; padding: .5rem .25rem;
    font-size: .8rem; font-weight: 600;
}
.cal-cell {
    background: var(--color-surface); min-height: 90px;
    padding: .35rem; display: flex; flex-direction: column;
    position: relative; transition: background .15s;
}
.cal-cell:hover { background: var(--color-surface-alt); }
.cal-cell.empty { background: var(--color-bg); }
.cal-cell.today { background: var(--color-accent-lt); }
.cal-day-num {
    font-size: .8rem; font-weight: 600; color: var(--color-muted);
    margin-bottom: .25rem; line-height: 1;
}
.cal-cell.today .cal-day-num { color: var(--color-primary); font-size: .85rem; }

.cal-event {
    display: block; padding: .15rem .35rem; margin-bottom: .2rem;
    border-radius: 4px; font-size: .68rem; font-weight: 500;
    text-decoration: none; color: var(--pal-blanc);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    transition: opacity .15s; line-height: 1.3;
}
.cal-event:hover { opacity: .85; }
.cal-event.type-comite            { background: var(--pal-bleu-800); }
.cal-event.type-commission        { background: var(--pal-pourpre-700); }
.cal-event.type-AG_ordinaire      { background: var(--pal-ambre-800); }
.cal-event.type-AG_extraordinaire { background: var(--pal-rose-800); }
.cal-event.statut-brouillon { opacity: .5; }
.cal-event.statut-relecture { border: 1px dashed var(--pal-blanc-a50); }

.cal-more {
    font-size: .65rem; color: var(--color-muted); font-weight: 500;
    padding: .1rem .25rem; cursor: pointer;
}

.cal-summary { margin-top: 1rem; font-size: .82rem; color: var(--color-muted); }

/* Modal détails jour */
.cal-modal {
    display: none; position: fixed; top: 0; left: 0; right: 0; bottom: 0;
    background: var(--pal-noir-a40); z-index: 200;
    align-items: center; justify-content: center; padding: 1rem;
}
.cal-modal.active { display: flex; }
.cal-modal-content {
    background: var(--color-surface); border-radius: var(--radius);
    padding: 1.25rem; width: 100%; max-width: 400px;
    box-shadow: 0 10px 30px var(--pal-noir-a20); max-height: 80vh; overflow-y: auto;
}
.cal-modal-content h3 { font-size: 1rem; font-weight: 600; margin-bottom: .75rem; }
.cal-modal-event {
    display: flex; align-items: center; gap: .6rem;
    padding: .5rem; border: 1px solid var(--color-border); border-radius: var(--radius);
    margin-bottom: .5rem; text-decoration: none; color: var(--color-text);
    transition: border-color .15s;
}
.cal-modal-event:hover { border-color: var(--color-primary); }
.cal-modal-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }
.cal-modal-dot.type-comite { background: var(--pal-bleu-800); }
.cal-modal-dot.type-commission { background: var(--pal-pourpre-700); }
.cal-modal-dot.type-AG_ordinaire { background: var(--pal-ambre-800); }
.cal-modal-dot.type-AG_extraordinaire { background: var(--pal-rose-800); }
.cal-modal-ev-body { flex: 1; min-width: 0; }
.cal-modal-ev-title { font-weight: 500; display: block; }
.cal-modal-ev-meta { font-size: .78rem; color: var(--color-muted); }
.cal-modal-close { margin-top: .75rem; width: 100%; }

@media (max-width: 768px) {
    .cal-cell { min-height: 60px; padding: .25rem; }
    .cal-day-num { font-size: .7rem; }
    .cal-event { font-size: .6rem; padding: .1rem .2rem; }
    .cal-dow { font-size: .65rem; padding: .35rem .15rem; }
    .cal-month-label { font-size: .95rem; min-width: 120px; }
}
@media (max-width: 768px) {
    .cal-cell { min-height: 45px; }
    .cal-event { display: none; }
    .cal-cell.has-events::after {
        content: ''; width: 6px; height: 6px; border-radius: 50%;
        background: var(--color-primary-fond); margin: .15rem auto 0;
    }
    .cal-cell.has-events { cursor: pointer; }
}

/* Vue PV (view.php) */
.pv-header {
    background: var(--color-surface); border: 1px solid var(--color-border);
    border-radius: var(--radius); padding: 1.5rem; margin-bottom: 1.5rem;
}
.pv-title { font-size: 1.4rem; font-weight: 600; margin-bottom: .5rem; }
.pv-meta { display: flex; gap: 1.5rem; flex-wrap: wrap; font-size: .85rem; color: var(--color-muted); }
.pv-meta span { display: flex; align-items: center; gap: .3rem; }

.pv-participants-list { display: flex; flex-wrap: wrap; gap: .5rem; }
.pv-participant {
    padding: .25rem .6rem; border-radius: 999px;
    font-size: .8rem; font-weight: 500;
}

/* Pastilles de présence (lecture du PV) sur les variables du thème : les
   fonds clairs écrits en dur restaient clairs en mode sombre. Classe
   construite en PHP (`pres-<?= presence ?>`, reunions/view.php). */
.pres-present { background: var(--color-success-lt); color: var(--color-success); }
.pres-excuse  { background: var(--color-warning-lt); color: var(--color-warning); }
.pres-absent  { background: var(--color-danger-lt);  color: var(--color-danger); }
.pv-point {
    background: var(--color-surface); border: 1px solid var(--color-border);
    border-radius: var(--radius); margin-bottom: 1rem; overflow: hidden;
}
/* Fond et filet pris dans le thème : #f8fafc en dur restait blanc en
   mode sombre. Le filet passe sur le corps ouvert — posé sous l'en-tête,
   il doublait le bord de la carte sur chaque point replié. */
.pv-point-header {
    display: flex; align-items: center; gap: .75rem;
    padding: .75rem 1rem; background: var(--color-surface-alt);
    transition: background .15s; cursor: pointer;
}
.pv-point-header:hover { background: var(--color-primary-lt); }
.pv-point-header:focus-visible { outline: 2px solid var(--color-primary); outline-offset: -2px; }
.pv-toggle { font-size: .8rem; color: var(--color-muted); transition: transform .2s; flex-shrink: 0; }
.pv-toggle.collapsed { transform: rotate(-90deg); }
.pv-point-body { display: none; padding: 1rem 1.25rem; }
.pv-point-body.pv-point-open { display: block; border-top: 1px solid var(--color-border); }
.pv-point-intitule { display: block; }
/* Ce qu'on lit sans déplier. Flex plutôt qu'un séparateur écrit : les
   éléments absents ([hidden]) ne laissent ni trou ni « · » orphelin. */
.pv-point-resume { display: flex; flex-wrap: wrap; gap: 0 .75rem; font-size: .75rem; font-weight: 400; color: var(--color-muted); }
.pv-point-resume > span { margin-top: .15rem; }
@media (max-width: 768px) {
    .pv-point-header { padding: .7rem .85rem; gap: .6rem; }
    .pv-point-body { padding: .85rem .9rem; }
}
.pv-point-num {
    background: var(--color-primary-fond); color: var(--color-on-fond);
    width: 28px; height: 28px; border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    font-size: .8rem; font-weight: 700; flex-shrink: 0;
}
.pv-point-title { font-weight: 600; font-size: .95rem; flex: 1; }
.pv-contenu { font-size: .9rem; line-height: 1.7; margin-bottom: 1rem; }
.pv-contenu p { margin-bottom: .5rem; }
.pv-contenu ul, .pv-contenu ol { margin-left: 1.5rem; margin-bottom: .5rem; }
.pv-decisions {
    background: var(--color-info-lt); border-left: 3px solid var(--color-primary);
    padding: .75rem 1rem; border-radius: 0 var(--radius) var(--radius) 0;
    margin-bottom: 1rem;
}
.pv-decisions strong { font-size: .85rem; display: block; margin-bottom: .3rem; color: var(--color-primary); }
.pv-decisions div { font-size: .9rem; }
.pv-decisions div p { margin-bottom: .3rem; }

/* Quill editor */
.quill-editor { background: var(--color-surface); min-height: 120px; border-radius: 0 0 var(--radius) var(--radius); }
.ql-toolbar.ql-snow { border-radius: var(--radius) var(--radius) 0 0; border-color: var(--color-border); }
.ql-container.ql-snow { border-color: var(--color-border); font-size: .9rem; }

/*  Ce qu'il y a à faire passe en tête, sur toute la largeur ; les
    responsables, la date, l'état et les boutons suivent dessous. Avec
    « Modifier », « Clore » et « Supprimer » d'un côté et trois noms de
    l'autre, la description était écrasée à deux mots par ligne — la seule
    chose qu'on vient lire.
    Règle à garder : dans une rangée en flex, ce qui identifie la ligne ne
    partage pas la largeur avec ses commandes. */
.pv-action-item {
    display: flex; gap: .4rem .75rem; align-items: center; flex-wrap: wrap;
    padding: .5rem .75rem; margin-top: .5rem;
    border: 1px solid var(--color-border); border-radius: var(--radius);
    border-left: 3px solid var(--color-success); font-size: .85rem;
}
.pv-action-item.closed { opacity: .6; border-left-color: var(--color-muted); }
.pv-action-desc { flex: 1 0 100%; font-weight: 500; }

/*  Les boutons d'une action, groupés. Sur ordinateur ils se calent à
    droite de la ligne des informations ; sur téléphone ils forment une
    rangée à eux et se partagent la largeur à parts égales — sans ce
    groupe, ils se dispersaient une ligne sur deux au gré de la place
    restante. Même motif que .page-actions sur petit écran.
    Règle à garder : des commandes qui vont ensemble sont un groupe dans
    le HTML, sinon le retour à la ligne les sépare au hasard. */
.pv-action-btns, .action-btns {
    display: flex; gap: .35rem; flex-wrap: wrap; margin-left: auto;
}
.action-btns .d-inline { display: inline-flex; }

@media (max-width: 768px) {
    .pv-action-btns, .action-btns { flex: 1 0 100%; margin-left: 0; margin-top: .25rem; }
    .pv-action-btns > *, .action-btns > * { flex: 1 1 0; }
    .pv-action-btns .btn, .action-btns .btn { width: 100%; justify-content: center; }
}
.pv-add-action-wrap {
    display: flex; flex-wrap: wrap; gap: .4rem; align-items: center;
    margin-top: .75rem; padding: .6rem .75rem;
    background: var(--color-surface); border: 1px dashed var(--color-border);
    border-radius: var(--radius);
}
.pv-add-action-input { flex: 2; min-width: 140px; }
.pv-add-action-wrap select { flex: 1; min-width: 140px; }
.pv-add-action-wrap input[type="date"] { flex: 0 0 130px; width: 130px; }

.approve-bar {
    background: var(--color-warning-soft); border: 1px solid var(--color-warning-border);
    border-radius: var(--radius); padding: 1rem 1.25rem;
    display: flex; align-items: center; gap: 1rem;
    margin-bottom: 1.5rem; flex-wrap: wrap;
}
.approve-bar p { flex: 1; font-size: .9rem; color: var(--color-warning-text); margin: 0; }

/* Commentaires */
.comments-section { margin-top: 1.25rem; padding-top: 1rem; border-top: 1px dashed var(--color-border); }
.comments-title {
    font-size: .85rem; font-weight: 600; color: var(--color-muted);
    margin-bottom: .75rem; display: flex; align-items: center; gap: .4rem;
}
.comment-item {
    display: flex; gap: .75rem; padding: .75rem; margin-bottom: .5rem;
    border-radius: var(--radius); background: var(--color-subtle);
    border: 1px solid var(--color-border);
}
.comment-item.resolved { opacity: .6; background: var(--color-success-soft); border-color: var(--color-success-border); }
.comment-avatar {
    width: 32px; height: 32px; border-radius: 50%;
    background: var(--color-primary-fond); color: var(--color-on-fond);
    display: flex; align-items: center; justify-content: center;
    font-size: .7rem; font-weight: 700; flex-shrink: 0;
}
.comment-body { flex: 1; min-width: 0; }
.comment-header {
    display: flex; align-items: center; gap: .5rem;
    margin-bottom: .3rem; flex-wrap: wrap;
}
.comment-author { font-size: .8rem; font-weight: 600; }
.comment-role { padding: .1rem .35rem; border-radius: 999px; font-size: .65rem; font-weight: 500; }
.comment-date { font-size: .75rem; color: var(--color-muted); }
.comment-text { font-size: .85rem; line-height: 1.5; white-space: pre-wrap; }
.comment-actions { display: flex; gap: .4rem; margin-top: .4rem; }
.comment-actions form { display: inline; }
.comment-actions button {
    background: none; border: none; cursor: pointer;
    font-size: .75rem; color: var(--color-muted); padding: .1rem .3rem; border-radius: 4px;
}
.comment-actions button:hover { background: var(--color-border); color: var(--color-text); }
.resolved-badge { font-size: .7rem; color: var(--color-success); font-weight: 500; }
.comment-form { display: flex; gap: .5rem; margin-top: .75rem; align-items: flex-start; }
.comment-form textarea {
    flex: 1; padding: .5rem .75rem;
    border: 1px solid var(--color-border); border-radius: var(--radius);
    font-size: .85rem; font-family: inherit; line-height: 1.4;
    resize: vertical; min-height: 60px;
    color: var(--color-text); background: var(--color-surface);
}
.comment-form textarea:focus {
    outline: none; border-color: var(--color-primary);
    box-shadow: 0 0 0 3px var(--pal-bleu-600-a10);
}

/* Commentaires archivés */
.comments-archive { opacity: .75; border-top-style: dotted; }
.comments-archive summary {
    font-size: .85rem; font-weight: 600; color: var(--color-muted);
    margin-bottom: .75rem; display: flex; align-items: center; gap: .4rem;
    list-style: none; cursor: pointer; user-select: none;
}
.comments-archive summary::before { content: '▶'; font-size: .65rem; transition: transform .2s; }
.comments-archive details[open] summary::before { transform: rotate(90deg); }
.comments-archive summary small { font-weight: 400; color: var(--color-muted); margin-left: .5rem; }
.comments-archive .comment-item { opacity: .85; }

/* Utilitaires PV */
.pv-actions-bar { display: flex; gap: .75rem; align-items: center; margin-bottom: 1.5rem; flex-wrap: wrap; }
/* Le menu se cale à droite, même s'il passe à la ligne sur téléphone :
   son panneau s'ouvre vers la gauche (right: 0) et sortirait de l'écran
   depuis le bord gauche. */
.pv-actions-bar > .menu-plus { margin-left: auto; }
.pv-approved-meta { margin-top: .75rem; font-size: .85rem; color: var(--color-success); }
.pv-participant--invite { background: var(--color-neutral-soft); color: var(--color-neutral-text); }
[data-theme="dark"] .pv-participant--invite { background: var(--color-neutral-soft); color: var(--color-neutral-text); }
.pv-toggle-all-wrap { display: flex; justify-content: flex-end; margin-bottom: .75rem; }
.pv-actions-label { font-size: .85rem; }
.pv-action-meta   { color: var(--color-muted); font-size: .8rem; }
.pv-edit-btn-wrap { margin-top: .75rem; }

/* Édition inline point */
.pv-edit-block    { display: none; }
.pv-edit-block.is-active { display: block; }
.pv-edit-group    { margin-bottom: .75rem; }
.pv-edit-label    { font-size: .8rem; font-weight: 600; }
.pv-edit-input    {
    width: 100%; padding: .4rem .6rem;
    border: 1px solid var(--color-border); border-radius: var(--radius);
    font-size: .9rem; background: var(--color-surface); color: var(--color-text);
    font-family: var(--font);
}
.pv-edit-btns     { display: flex; gap: .5rem; }
.pv-save-status   { font-size: .8rem; color: var(--color-success); align-self: center; }
.pv-save-status.is-saving { color: var(--color-muted); }
.pv-save-status.is-error  { color: var(--color-danger); }
.pv-read-block { display: block; }
.pv-read-block.is-hidden { display: none; }

/* Documents attachés */
.pv-docs-wrap     { margin-top: 1.5rem; }
.pv-docs-title    { font-size: 1rem; font-weight: 600; margin-bottom: .75rem; }
.pv-docs-body     { padding: 0; }
.pv-doc-item {
    display: flex; align-items: center; gap: .75rem;
    padding: .65rem 1rem; border-bottom: 1px solid var(--color-border); font-size: .85rem;
}
.pv-doc-item:last-child { border-bottom: none; }
.pv-doc-icon      { font-size: 1.1rem; }
.pv-doc-body      { flex: 1; min-width: 0; }
.pv-doc-link      { color: var(--color-primary); text-decoration: none; font-weight: 500; }
.pv-doc-link:hover { text-decoration: underline; }
.pv-doc-meta      { font-size: .75rem; color: var(--color-muted); }

/* Édition réunion (edit.php) */
.edit-header { display: flex; align-items: center; gap: 1rem; margin-bottom: 1.5rem; flex-wrap: wrap; }
.edit-header h1 { flex: 1; font-size: 1.4rem; font-weight: 600; }
.status-bar { display: flex; gap: .75rem; align-items: center; flex-wrap: wrap; }

.quill-edit { background: var(--color-surface); min-height: 120px; border-radius: 0 0 var(--radius) var(--radius); }
/*  Les décisions sont courtes : 154 caractères en moyenne sur les 41
    points qui en portent, contre 447 pour la discussion — et un point sur
    deux n'en a aucune. Leur cadre partait pourtant à la même hauteur, ce
    qui faisait deux grandes boîtes identiques à l'écran. Il grandit à la
    saisie, comme l'autre. */
.quill-edit--court, .quill-editor--court { min-height: 64px; }

/*  Le repli des décisions, dans le corps d'un point : un simple titre
    cliquable, pas une carte — on est déjà dans celle du point. Le chevron
    est celui du motif commun ; le marqueur du navigateur est retiré des
    deux côtés, comme partout ailleurs. */
.pt-dec > summary {
    list-style: none; cursor: pointer;
    display: flex; align-items: center; gap: .4rem;
    font-size: .82rem; font-weight: 600; color: var(--color-text);
    margin-bottom: .35rem;
}
.pt-dec > summary::-webkit-details-marker { display: none; }
.pt-dec > summary::marker { content: ''; }
.pt-dec > summary:hover { color: var(--color-primary); }
.pt-dec:not([open]) > summary .pliable-chevron { transform: rotate(-90deg); }
.pt-dec[open] > summary .pliable-chevron { transform: rotate(0); }
.pt-dec-etat { font-weight: normal; font-size: .78rem; color: var(--color-muted); }
.pt-dec-etat:not(:empty)::before { content: "— "; }

.section { margin-bottom: 2rem; }
.section-title {
    font-size: 1.05rem; font-weight: 600; margin-bottom: 1rem;
    padding-bottom: .5rem; border-bottom: 2px solid var(--color-border);
}

/* Points éditables */
.point-card {
    background: var(--color-surface); border: 1px solid var(--color-border);
    border-radius: var(--radius); margin-bottom: 1rem; overflow: hidden;
    transition: box-shadow .15s, opacity .15s;
}
.point-card.dragging { opacity: .45; box-shadow: 0 4px 16px var(--pal-noir-a15); }
/* Fonds pris dans le thème : #eff6ff, #f8fafc et #f1f5f9 en dur restaient
   clairs en mode sombre. Le filet passe sur le corps ouvert — sous
   l'en-tête, il doublait le bord de la carte sur chaque point replié. */
.point-card.drag-over { border: 2px dashed var(--color-primary); background: var(--color-primary-lt); }
.point-header {
    display: flex; align-items: center; gap: .75rem;
    padding: .75rem 1rem; background: var(--color-surface-alt);
}
.point-header:hover { background: var(--color-primary-lt); }
.drag-handle {
    cursor: grab; font-size: 1.1rem; color: var(--color-muted);
    padding: 0 2px; flex-shrink: 0; user-select: none;
    opacity: .5; transition: opacity .15s;
}
.drag-handle:hover { opacity: 1; color: var(--color-primary); }
.drag-handle:active { cursor: grabbing; }
.point-move-btns { display: flex; flex-direction: column; gap: 1px; flex-shrink: 0; }
.point-move-btn {
    width: 22px; height: 15px; padding: 0; line-height: 1;
    border: 1px solid var(--color-border); background: var(--color-surface);
    color: var(--color-muted); border-radius: 3px; font-size: .6rem;
    cursor: pointer; display: flex; align-items: center; justify-content: center;
}
.point-move-btn:hover:not(:disabled) { color: var(--color-primary); border-color: var(--color-primary); }
.point-move-btn:disabled { opacity: .3; cursor: default; }
.point-numero {
    background: var(--color-primary-fond); color: var(--color-on-fond);
    width: 28px; height: 28px; border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    font-size: .8rem; font-weight: 700; flex-shrink: 0;
}
.point-titre { flex: 1; min-width: 0; font-weight: 500; font-size: .9rem; cursor: pointer; }
.point-titre:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; border-radius: 4px; }
.point-intitule { display: block; }
.point-toggle { font-size: .8rem; color: var(--color-muted); cursor: pointer; flex-shrink: 0; transition: transform .2s; }
.point-toggle.collapsed { transform: rotate(-90deg); }
/* « À rédiger » dans le résumé du point (classes partagées avec la lecture du PV). */
.pv-resume-vide { color: var(--color-warning); font-weight: 500; }
.point-body { padding: 1rem; display: none; }
.point-body.open { display: block; border-top: 1px solid var(--color-border); }
/* Section Documents : l'envoi suit la liste dans la même carte. */
.edit-docs-upload { border-top: 1px solid var(--color-border); }
@media (max-width: 768px) {
    /* Le glisser-déposer natif ne marche pas au doigt : la poignée n'y
       serait qu'un pictogramme de plus. Les flèches ▲▼ la remplacent. */
    .drag-handle { display: none; }
    .point-header { padding: .7rem .75rem; gap: .55rem; }
    /* Titre de page sur sa ligne, le statut et les boutons en dessous —
       même écueil que .page-actions. Après la règle de base .edit-header h1. */
    .edit-header h1 { flex: 1 1 100%; font-size: 1.2rem; }
}
.point-body textarea {
    width: 100%; padding: .5rem .75rem;
    border: 1px solid var(--color-border); border-radius: var(--radius);
    font-size: .9rem; font-family: inherit; line-height: 1.5;
    resize: vertical; min-height: 100px;
    color: var(--color-text); background: var(--color-surface);
}
.point-body textarea:focus {
    outline: none; border-color: var(--color-primary);
    box-shadow: 0 0 0 3px var(--pal-bleu-600-a10);
}

/* Actions inline */
.action-inline {
    display: flex; gap: .5rem; align-items: center;
    padding: .5rem; margin-top: .5rem;
    background: var(--color-success-lt); border: 1px solid var(--color-border); border-radius: var(--radius);
    font-size: .85rem; flex-wrap: wrap;
}
/*  Même raison que .pv-action-desc : la description prend sa ligne, les
    responsables, l'échéance et les boutons se rangent dessous. */
.action-inline .action-desc { flex: 1 0 100%; font-weight: 500; }
.action-inline .action-resp { color: var(--color-muted); }
.action-inline .action-ech  { color: var(--color-muted); font-size: .8rem; }
.actions-list-title { font-size: .85rem; font-weight: 600; }


/* Sauvegarder + Supprimer ce point côte à côte, en bas du point */
.point-save-delete-row {
    display: flex;
    align-items: center;
    gap: .75rem;
    margin-top: 1rem;
    padding-top: .75rem;
    border-top: 1px dashed var(--color-border);
    flex-wrap: wrap;
}
.point-save-delete-row form { margin: 0; display: inline; }
@media (max-width: 768px) {
    .point-save-delete-row { gap: .5rem; }
}

/* Formulaire ajout action */
.add-action-form {
    display: grid; grid-template-columns: 1fr auto auto auto;
    gap: .5rem; align-items: end; margin-top: .75rem;
    padding-top: .75rem; border-top: 1px dashed var(--color-border);
}
.add-action-form input, .add-action-form select {
    padding: .4rem .5rem; font-size: .85rem;
    border: 1px solid var(--color-border); border-radius: 4px;
}
.add-action-form input:focus, .add-action-form select:focus { outline: none; border-color: var(--color-primary); }

/* Ajout point */
/* La note posee au-dessus de la rangee, pas dedans : voir edit.php. */
.add-point-note { margin: 0 0 .75rem; font-size: .82rem; }
.add-point-form { display: flex; gap: .75rem; align-items: end; }
.add-point-form .form-group { flex: 1; margin-bottom: 0; }

/* Participants — carte repliable <details class="pliable"> (edit.php) */

.part-table { width: 100%; border-collapse: collapse; }
.part-table th {
    text-align: center; padding: .4rem .3rem;
    font-size: .8rem; font-weight: 600; color: var(--color-muted);
    border-bottom: 1px solid var(--color-border);
}
.part-table th:first-child { text-align: left; }
.part-table td { padding: .4rem .3rem; border-bottom: 1px solid var(--color-border); vertical-align: middle; text-align: center; }
.part-table td:first-child { text-align: left; }
.part-table tr:last-child td { border-bottom: none; }
.part-table .part-name { font-size: .85rem; font-weight: 500; }
.part-table .part-role { font-size: .7rem; }

.part-radio { display: none; }
.part-radio-label {
    display: inline-flex; align-items: center; justify-content: center;
    width: 30px; height: 30px; border-radius: 50%;
    border: 2px solid var(--color-border); cursor: pointer;
    font-size: .75rem; transition: all .15s;
}
.part-radio-label:hover { border-color: var(--color-primary); }
.part-radio:checked + .part-radio-label.lbl-present { background: var(--pal-vert-600); border-color: var(--pal-vert-600); color: var(--pal-blanc); }
.part-radio:checked + .part-radio-label.lbl-excuse  { background: var(--pal-ambre-600); border-color: var(--pal-ambre-600); color: var(--pal-blanc); }
.part-radio:checked + .part-radio-label.lbl-absent   { background: var(--pal-brique); border-color: var(--pal-brique); color: var(--pal-blanc); }

.invites-field { margin-top: 1rem; padding-top: .75rem; border-top: 1px dashed var(--color-border); }
.invites-field label { font-size: .82rem; font-weight: 600; margin-bottom: .4rem; display: block; }
.invites-field textarea {
    width: 100%; padding: .5rem .75rem; font-size: .85rem; font-family: inherit;
    border: 1px solid var(--color-border); border-radius: var(--radius);
    resize: vertical; min-height: 50px; color: var(--color-text); background: var(--color-surface);
}
.invites-hint { color: var(--color-muted); font-size: .75rem; }

/* Upload documents */
.upload-form { display: flex; gap: .75rem; align-items: flex-end; flex-wrap: wrap; }
.upload-form .form-group { flex: 1; margin-bottom: 0; min-width: 200px; }
.upload-form input[type="file"] {
    font-size: .85rem; padding: .3rem;
    border: 1px solid var(--color-border); border-radius: var(--radius); width: 100%;
}

/* Workflow */
.workflow-bar { display: flex; gap: 1rem; flex-wrap: wrap; align-items: center; }
.workflow-delete { margin-left: auto; }

/* Envois aux membres par email — convocation (reunions/edit.php) et
   diffusion du PV (reunions/view.php). Deux colonnes de membres dans la
   fenêtre : vingt noms empilés la rendaient plus haute que l'écran. Une
   seule colonne quand la place manque, sans media query. */
.pv-envoi-etat    { margin-bottom: .75rem; }
.pv-envoi-odj     { margin: 0 0 .75rem 1.25rem; font-size: .9rem; }
.pv-membres-titre { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; margin: .75rem 0 .4rem; }
/*  Ces rangées portent un libellé et une paire de boutons (« Tout cocher /
    Tout décocher », « Copier / Ouvrir WhatsApp », « Envoyée au groupe /
    à chacun »). Sur un téléphone, chacun passait à la ligne pour lui seul,
    aligné à gauche et de largeur inégale. Le libellé prend sa ligne, les
    deux boutons se partagent la suivante — comme les boutons d'en-tête.
    :has() limite la règle aux rangées qui en portent : un simple
    paragraphe (« Ordre du jour ») garde sa mise en page. */
@media (max-width: 768px) {
    .pv-membres-titre:has(.btn) > strong { flex: 1 0 100%; }
    .pv-membres-titre:has(.btn) > .btn   { flex: 1 1 calc(50% - .25rem); justify-content: center; }
    .pv-membres-titre:has(.btn) > .text-muted { flex: 1 0 100%; }
}
.pv-membres-liste { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: .5rem 1rem; margin-bottom: .5rem; }
.pv-membres-liste small { word-break: break-all; }
/* Liste d'adhérents (diffusion du rapport d'AG) : 170 lignes défilent
   dans leur cadre, le mot d'accompagnement et le bouton restent à portée. */
.pv-membres-liste--longue { max-height: 45vh; overflow-y: auto; padding-right: .25rem; }
/*  La fenêtre de reprise d'actions liste des PHRASES, pas des noms : la
    grille à deux colonnes de 220 px y découpait des descriptions entières
    en colonnes étroites, et le word-break ci-dessus — posé pour qu'une
    adresse email trop longue ne déborde pas — coupait les mots en plein
    milieu (« Réunio / n Comité »). Une colonne, et des mots entiers.
    Règle à garder : une liste à cocher se met en colonnes quand ses
    libellés tiennent sur une ligne, jamais quand ce sont des phrases. */
.pv-membres-liste--phrases { grid-template-columns: 1fr; gap: .75rem; }
.pv-membres-liste--phrases small { word-break: normal; overflow-wrap: anywhere; }

/*  Les deux façons d'envoyer, chacune dans son cadre et sous son nom.
    Elles se suivaient sans se distinguer : on croyait la fenêtre finie au
    milieu, en voyant le bouton d'envoi, et rien ne disait que ce qu'on
    venait de remplir partait par email. */
.pv-envoi-bloc {
    border: 1px solid var(--color-border); border-radius: var(--radius);
    padding: .85rem 1rem; margin-bottom: 1rem;
    background: var(--color-surface-alt);
}
.pv-envoi-bloc-titre {
    font-size: .9rem; font-weight: 700; margin: 0 0 .35rem;
    color: var(--color-text);
}
.pv-envoi-bloc-sous { font-size: .8rem; margin: 0 0 .75rem; }
/*  Le bouton d'envoi appartient à son bloc : calé à droite sur ordinateur,
    pleine largeur au doigt. */
.pv-envoi-action { display: flex; justify-content: flex-end; margin: .75rem 0 0; }
@media (max-width: 768px) {
    .pv-envoi-action .btn { flex: 1 1 100%; justify-content: center; white-space: normal; }
}
.pv-envoi-texte { width: 100%; font-size: .85rem; font-family: var(--font); margin-bottom: .5rem; }
.pv-diffusion      { margin-bottom: 1.5rem; }   /* comme .pv-header, juste au-dessus */

/* Aperçu du courrier dans la fenêtre d'envoi par email : un courrier peut
   faire deux pages, la fenêtre ne doit pas s'allonger d'autant. */
.cour-email-apercu {
    max-height: 240px; overflow-y: auto;
    border: 1px solid var(--color-border); border-radius: var(--radius);
    padding: .75rem 1rem; margin-bottom: .5rem;
    background: var(--color-surface-alt); font-size: .9rem;
}

/* Info bar (mandature + type) */
.info-bar { display: flex; gap: .5rem; align-items: center; }
.info-bar-text { font-size: .85rem; }
.info-bar .btn { margin-left: auto; }

@media (max-width: 768px) {
    .part-table th:not(:first-child) { font-size: .6rem; padding: .3rem .15rem; }
    .part-radio-label { width: 26px; height: 26px; font-size: .65rem; }
    .part-table .part-name { font-size: .8rem; }
    .add-action-form { grid-template-columns: 1fr; }
    /* En colonne, l'alignement « en bas » de la version ordinateur
       (align-items: end) devient « à droite » : le champ et le bouton se
       collaient au bord droit de la carte. Pleine largeur à la place. */
    /* Workflow : en ligne sur ordinateur, la suppression est poussée à
       droite (margin-left: auto). Passé à la ligne sur téléphone, cela
       donnait trois alignements dans la même carte. En colonne : le geste
       courant pleine largeur, son explication dessous, la suppression à
       part, sous un filet — loin du pouce qui vient soumettre. */
    .workflow-bar { flex-direction: column; align-items: stretch; gap: .6rem; }
    .workflow-bar form .btn { width: 100%; justify-content: center; }
    .workflow-delete { margin-left: 0; margin-top: .25rem; padding-top: .75rem; border-top: 1px dashed var(--color-border); }
    .add-point-form { flex-direction: column; align-items: stretch; }
    .add-point-form .form-group input { width: 100%; }
    .add-point-form .btn { justify-content: center; }
}

/* ═══════════════════════════════════════════════════
   ACTIONS — actions/index.php + mes_actions.php
   ═══════════════════════════════════════════════════ */

/* .action-resp : encore utilisée par reunions/edit.php. */
.action-resp { font-size: .85rem; }
.action-link-icon { color: var(--color-primary); font-size: .75rem; margin-left: 3px; }

.echeance-badge { padding: .2rem .5rem; border-radius: 999px; font-size: .75rem; font-weight: 500; white-space: nowrap; }
.ech-retard  { background: var(--color-danger-soft); color: var(--color-danger); }
.ech-soon    { background: var(--color-warning-soft); color: var(--color-warning-text); }
.ech-ok      { background: var(--color-success-soft); color: var(--color-success); }
.ech-none    { background: var(--color-neutral-soft); color: var(--color-muted); }
[data-theme="dark"] .ech-retard { background: var(--color-danger-soft); }
[data-theme="dark"] .ech-soon   { background: var(--color-warning-soft); }
[data-theme="dark"] .ech-ok     { background: var(--color-success-soft); }
[data-theme="dark"] .ech-none   { background: var(--color-surface-alt); }

.close-modal {
    display: none; position: fixed; top: 0; left: 0; right: 0; bottom: 0;
    background: var(--pal-noir-a40); z-index: 200; align-items: center; justify-content: center;
}
.close-modal.active { display: flex; }
.close-modal-content {
    background: var(--color-surface); border-radius: var(--radius);
    padding: 1.5rem; width: 100%; max-width: 450px; box-shadow: 0 10px 25px var(--pal-noir-a15);
}
.close-modal-title { font-size: 1.05rem; font-weight: 600; margin-bottom: 1rem; }
.close-modal-desc { font-size: .9rem; margin-bottom: 1rem; color: var(--color-muted); }

/* Tableau des actions (actions/index.php). Retard et clôture sur les
   variables du thème : l'ancienne ligne en retard avait un fond clair
   écrit en dur, blanc cassé sur fond sombre. */
.actions-desc { font-weight: 500; }
.actions-table tr.actions-tr--retard td { background: var(--color-danger-lt); }
.actions-table tr.actions-tr--close { opacity: .65; }
@media (max-width: 768px) {
    .actions-table tbody tr.actions-tr--retard { border-left: 3px solid var(--color-danger); }
    .actions-table tbody tr.actions-tr--retard td { background: transparent; }
}

.ma-filters { display: flex; gap: .75rem; margin-bottom: 1.5rem; align-items: center; }
.ma-filters .btn { padding: .35rem .75rem; font-size: .85rem; }
.ma-filters .btn.active { background: var(--color-primary-fond); color: var(--color-on-fond); }
.ma-card {
    background: var(--color-surface); border: 1px solid var(--color-border);
    border-radius: var(--radius); margin-bottom: 1rem; overflow: hidden;
}
.ma-card.late { border-left: 3px solid var(--color-danger); }
.ma-card.done { opacity: .65; }
.ma-card-header {
    padding: .75rem 1rem; display: flex; align-items: flex-start; gap: .75rem;
    background: var(--color-surface-alt); border-bottom: 1px solid var(--color-border);
}
.ma-card-icon { font-size: 1.1rem; }
.ma-card-body-wrap { flex: 1; }
.ma-card-body { padding: .75rem 1rem 1rem; }
.ma-desc { font-weight: 500; flex: 1; font-size: .9rem; }
.ma-meta { font-size: .78rem; color: var(--color-muted); display: flex; gap: .75rem; flex-wrap: wrap; margin-top: .3rem; }
.ma-comments { margin-top: .75rem; }
.ma-comments-title { font-size: .82rem; font-weight: 600; }
.ma-comment {
    padding: .5rem .75rem; background: var(--color-surface-alt);
    border-radius: var(--radius); margin-bottom: .5rem; font-size: .83rem;
}
.ma-comment-author { font-weight: 500; font-size: .78rem; color: var(--color-primary); }
.ma-comment-date { font-size: .72rem; color: var(--color-muted); }
.ma-comment-text { margin-top: .2rem; }
.ma-no-comment { font-size: .82rem; margin-top: .3rem; }
.ma-comment-form { display: flex; gap: .5rem; margin-top: .75rem; }
.ma-comment-form input[type="text"] {
    flex: 1; padding: .4rem .6rem; font-size: .85rem;
    border: 1px solid var(--color-border); border-radius: var(--radius);
    background: var(--color-surface); color: var(--color-text);
}
.ma-comment-form input[type="text"]:focus { outline: none; border-color: var(--color-primary); }
.ma-actions-btns { display: flex; gap: .5rem; margin-top: .75rem; }

/* Carte repliable (<details>). Repliée, l'en-tête perd son filet bas,
   qui soulignerait un corps absent. */
.ma-card > summary { list-style: none; cursor: pointer; }
.ma-card > summary::-webkit-details-marker { display: none; }
.ma-card > summary::marker { content: ''; }
.ma-card > summary:focus-visible { outline: 2px solid var(--color-primary); outline-offset: -2px; }
.ma-card:not([open]) .ma-card-header { border-bottom: none; }
.ma-card > summary:hover .ma-card-header { background: var(--color-primary-lt); }
.ma-card-chevron { font-size: .7rem; color: var(--color-muted); align-self: center; transform: rotate(-90deg); transition: transform .2s; }
.ma-card[open] .ma-card-chevron { transform: rotate(0); }
.ma-card-body-wrap { min-width: 0; }
@media (max-width: 768px) {
    /* L'échéance passe sous la description plutôt que de la comprimer :
       le bloc de texte réclame toute la ligne à côté de l'icône et du
       chevron, le badge retombe dessous, aligné sur le texte. */
    .ma-card-header { flex-wrap: wrap; gap: .4rem .6rem; }
    .ma-card-body-wrap { flex: 1 1 calc(100% - 3.2rem); }
    .ma-card-header .echeance-badge { order: 5; margin-left: 1.7rem; }
}

.done-modal-overlay {
    display: none; position: fixed; top: 0; left: 0; right: 0; bottom: 0;
    background: var(--pal-noir-a40); z-index: 200; align-items: center; justify-content: center;
}
.done-modal-overlay.active { display: flex; }
.done-modal {
    background: var(--color-surface); border-radius: var(--radius-lg);
    padding: 1.5rem; width: 100%; max-width: 480px; margin: 1rem;
    box-shadow: 0 10px 25px var(--pal-noir-a15); animation: modalIn .2s ease-out;
}
@keyframes modalIn { from { opacity: 0; transform: scale(.95) translateY(10px); } to { opacity: 1; transform: scale(1) translateY(0); } }
.done-modal-title { font-size: 1.05rem; font-weight: 600; margin-bottom: .5rem; }
.done-modal-desc { font-size: .85rem; color: var(--color-muted); margin-bottom: 1rem; }
.done-modal-label { font-size: .85rem; font-weight: 500; margin-bottom: .3rem; display: block; }
.done-modal-opt { color: var(--color-muted); font-weight: 400; }
.done-modal-hint { font-size: .72rem; color: var(--color-muted); margin-top: .75rem; }

/* ═══════════════════════════════════════════════════
   SECRÉTARIAT — secretariat/index.php
   ═══════════════════════════════════════════════════ */
/*  L'accueil suit le modèle commun des accueils (includes/accueil.php,
    bloc « ACCUEILS DES MODULES ») depuis la refonte B2·3 — étape 4. */

/* ═══════════════════════════════════════════════════
   PRÉSENCES — secretariat/presences.php
   ═══════════════════════════════════════════════════ */
.pres-td-bar   { min-width: 100px; }
.pres-bar {
    display: flex; height: 8px; border-radius: 4px; overflow: hidden;
    width: 100%; min-width: 80px; background: var(--color-border);
}
.pres-bar-seg { height: 100%; width: 0; transition: width .6s cubic-bezier(.22,.61,.36,1); }
.pres-bar-seg--present { background: var(--pal-vert-600); }
.pres-bar-seg--excuse  { background: var(--pal-ambre-600); }
.pres-bar-seg--absent  { background: var(--pal-rouge-600); }
.pres-bar-empty        { color: var(--color-muted); font-size: .75rem; }
@media (max-width: 768px) {.pres-td-bar { min-width: 0; } .pres-bar { min-width: 60px; } }

/* ═══════════════════════════════════════════════════
   MODÈLES — modeles/index.php
   ═══════════════════════════════════════════════════ */
.points-list { display: flex; flex-direction: column; gap: .5rem; }
.points-list .point-input { display: flex; gap: .5rem; align-items: center; }
.points-list .point-input input {
    flex: 1; padding: .4rem .6rem; font-size: .85rem;
    border: 1px solid var(--color-border); border-radius: var(--radius);
}
.points-list .point-input input:focus { outline: none; border-color: var(--color-primary); }
.points-list .point-num {
    width: 24px; height: 24px; border-radius: 50%;
    background: var(--color-primary-fond); color: var(--color-on-fond);
    display: flex; align-items: center; justify-content: center;
    font-size: .7rem; font-weight: 700; flex-shrink: 0;
}
.remove-point-btn { background: none; border: none; cursor: pointer; color: var(--color-danger); font-size: .85rem; padding: .2rem; }

/* ── Mes actions — lien compte rendu ── */
.ma-reunion-link {
    color: var(--color-primary);
    text-decoration: none;
    font-weight: 500;
}
.ma-reunion-link:hover {
    text-decoration: underline;
}

/* Tuiles des accueils (tuileAccueil()) qui mènent à leur liste. */
a.stat-card { text-decoration: none; color: inherit; cursor: pointer; }
a.stat-card:hover { transform: translateY(-2px); box-shadow: 0 4px 12px var(--pal-noir-a10); }

/* ── Récap actions réunion ── */
.pv-recap-card { margin-top: 1.5rem; }
.pv-recap-filters { display: flex; gap: .4rem; flex-wrap: wrap; margin-bottom: .75rem; }
/* Participants en carte repliable (reunions/view.php) : même écart sous
   la carte que l'ancien bloc, avant l'ordre du jour. */
.pv-participants-carte { margin-bottom: 1.5rem; }
/* Écrit sous .pv-recap-filters (un cran plus précis) : il doit l'emporter
   sur le bouton secondaire du mode sombre, écrit dans une autre section. */
.pv-recap-filters .pv-recap-filter.active { background: var(--color-primary-fond); color: var(--color-on-fond); border-color: var(--color-primary-fond); }

.pv-recap-stats {
    display: flex; gap: 1rem; flex-wrap: wrap;
    margin-bottom: .75rem; padding-bottom: .75rem;
    border-bottom: 1px solid var(--color-border);
}
.pv-recap-stat { font-size: .82rem; font-weight: 600; }
.pv-recap-stat--open   { color: var(--color-primary); }
.pv-recap-stat--closed { color: var(--color-success); }
.pv-recap-stat--total  { color: var(--color-muted); }

.pv-recap-list { display: flex; flex-direction: column; gap: .5rem; }
.pv-recap-item {
    display: flex; align-items: flex-start; gap: .75rem;
    padding: .6rem .75rem;
    border-radius: 8px;
    border: 1px solid var(--color-border);
    background: var(--color-surface);
}
.pv-recap-item--clos { opacity: .6; background: var(--color-surface-alt); }
.pv-recap-item--late { border-left: 3px solid var(--color-danger); }
.pv-recap-icon { font-size: 1rem; flex-shrink: 0; margin-top: .1rem; }
.pv-recap-body { flex: 1; min-width: 0; }
.pv-recap-desc { font-weight: 500; font-size: .88rem; margin-bottom: .2rem; }
.pv-recap-meta {
    display: flex; flex-wrap: wrap; gap: .5rem 1rem;
    font-size: .75rem; color: var(--color-muted);
}
.pv-recap-point { font-style: italic; }
.pv-recap-loading { color: var(--color-muted); font-size: .85rem; padding: .5rem 0; }
[data-theme="dark"] .pv-recap-item { background: var(--color-surface-alt); border-color: var(--pal-blanc-a08); }
[data-theme="dark"] .pv-recap-item--clos { background: var(--pal-blanc-a02); }

/* ── Courriers — Templates ── */
.cour-tpl-grid { display: flex; flex-direction: column; gap: .75rem; }
.cour-tpl-type-label {
    font-size: .9rem; font-weight: 700;
    color: var(--color-muted);
    padding: .5rem 0 .25rem;
    border-bottom: 1px solid var(--color-border);
    margin-top: .5rem;
}
.cour-tpl-card-head {
    display: flex; align-items: center; gap: .75rem;
    flex-wrap: wrap;
}
.cour-tpl-card-nom { font-weight: 600; flex: 1; font-size: .95rem; }
.cour-tpl-card-btns { display: flex; gap: .4rem; align-items: center; }
.cour-tpl-card-objet { margin-top: .3rem; }
.cour-tpl-card-auteur { margin-top: .15rem; }

/* Éditeur Quill template */
.cour-tpl-editor {
    min-height: 220px;
    border: 1px solid var(--color-border);
    border-top: none;
    border-radius: 0 0 6px 6px;
    background: var(--color-surface);
    font-size: .9rem;
}

/* Boutons variables */
.cour-tpl-variables {
    display: flex; flex-wrap: wrap; gap: .3rem;
    align-items: center;
    margin-bottom: 0;
    padding: .5rem .75rem;
    background: var(--color-surface-alt);
    border: 1px solid var(--color-border);
    border-bottom: none;
    border-radius: 6px 6px 0 0;
}
.cour-tpl-var-label {
    font-size: .72rem; color: var(--color-muted);
    margin-right: .25rem;
}
.cour-tpl-var-btn {
    font-size: .72rem; font-family: monospace;
    padding: 2px 7px;
    border-radius: 4px;
    border: 1px solid var(--color-border);
    background: var(--color-surface);
    cursor: pointer; color: var(--color-primary);
    transition: background .15s;
}
.cour-tpl-var-btn:hover {
    background: var(--color-primary-lt);
    border-color: var(--color-primary);
}

/* ── Courriers — Rédaction ── */
.cour-rediger-grid {
    display: grid;
    grid-template-columns: 280px 1fr;
    gap: 1.25rem;
    align-items: start;
}
.cour-rediger-sidebar { display: flex; flex-direction: column; gap: .75rem; }
/* Les trois champs de la colonne de rédaction d'un courrier : modèle,
   destinataire et date. Seule la largeur était posée ici ; les deux
   listes recevaient l'habillage général des select, le champ date rien
   du tout — il gardait l'apparence native du navigateur, cadre carré au
   milieu de champs arrondis (signalé par l'utilisateur). Le contexte
   pose donc son habillage complet, padding compris : c'est ce que la
   règle de base des select laisse volontairement à chaque contexte. */
.cour-sidebar-select {
    width: 100%;
    padding: .4rem .6rem;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius);
    background: var(--color-surface);
    color: var(--color-text);
    font-family: var(--font);
    font-size: .9rem;
}
/* Devenu un <button> (il ouvre la fenêtre d'ajout au lieu d'un autre
   onglet) : on lui rend l'allure de lien qu'il avait. */
.cour-sidebar-link { font-size: .8rem; color: var(--color-primary); display: block; margin-top: .4rem;
    background: none; border: 0; padding: 0; text-align: left; cursor: pointer; font-family: inherit; }
.cour-sidebar-link:hover { text-decoration: underline; }
.cour-sidebar-actions { display: flex; flex-direction: column; gap: .5rem; }
.cour-btn-full { width: 100%; justify-content: center; }

.cour-dest-preview {
    font-size: .8rem;
    color: var(--color-muted);
    margin-top: .5rem;
    padding: .4rem .6rem;
    background: var(--color-surface-alt);
    border-radius: 6px;
    border: 1px solid var(--color-border);
    display: none;
    line-height: 1.6;
}
.cour-dest-preview:not(:empty) { display: block; }

.cour-sig-label {
    display: flex; align-items: center; gap: .5rem;
    padding: .35rem 0;
    cursor: pointer;
    font-size: .88rem;
}
.cour-sig-label input { flex-shrink: 0; accent-color: var(--color-primary); }

.cour-rediger-editor {
    min-height: 350px;
    border: 1px solid var(--color-border);
    border-top: none;
    border-radius: 0 0 6px 6px;
    font-size: .9rem;
    background: var(--color-surface);
}

@media (max-width: 768px) {
    .cour-rediger-grid { grid-template-columns: 1fr; }
    /* Sur une colonne, « Sauvegarder / Aperçu / Générer le PDF »
       arrivaient avant l'objet et le corps, qu'on rédige d'abord. La
       colonne de réglages se dissout (display: contents) pour que ses
       cartes et ses boutons se rangent séparément : réglages en tête (le
       modèle pré-remplit le corps), rédaction, puis les boutons. */
    .cour-rediger-sidebar { display: contents; }
    .cour-rediger-sidebar > .card { order: 1; }
    /* Dissoute, la colonne perd son « gap » : sous l'écran d'un courrier
       la grille en fournit un, sous celui d'un email (bloc ordinaire) les
       cartes se collaient. L'écart commun des cartes revient ici. */
    .cour-rediger-layout .cour-rediger-sidebar > .card + .card { margin-top: .6rem; }
    .cour-rediger-main { order: 2; }
    .cour-sidebar-actions { order: 3; }
}

/* ── Courriers — Historique ── */

.cour-hist-ref {
    display: inline-block;
    font-family: 'Courier New', monospace;
    font-size: .72rem;
    color: var(--color-muted);
    background: var(--color-surface-alt);
    padding: 1px 6px;
    border-radius: 4px;
    margin-top: 3px;
    letter-spacing: .02em;
}
.cour-ref-banner {
    margin-bottom: 1rem;
    font-family: 'Courier New', monospace;
    letter-spacing: .02em;
}

/* ── Courrier — Modal Aperçu ── */
.cour-preview-modal {
    display: none;
    position: fixed; inset: 0;
    background: var(--pal-noir-a55);
    z-index: 9000;
    overflow-y: auto;
    padding: 20px 0;
}
.cour-preview-modal.is-open { display: block; }
.cour-preview-modal-box {
    background: var(--pal-blanc);
    max-width: 820px;
    margin: 20px auto;
    border-radius: 12px;
    box-shadow: 0 20px 50px var(--pal-noir-a25);
    display: flex;
    flex-direction: column;
    max-height: calc(100vh - 40px);
    overflow: hidden;
}
.cour-preview-modal-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 14px 20px;
    border-bottom: 1px solid var(--color-border);
    background: var(--color-surface-alt);
}
.cour-preview-modal-head h2 {
    font-size: 1.05rem; font-weight: 600; margin: 0;
}
.cour-preview-modal-close {
    background: transparent; border: none;
    font-size: 1.5rem; cursor: pointer;
    color: var(--color-muted);
    padding: 4px 10px; border-radius: 6px;
}
.cour-preview-modal-close:hover { background: var(--pal-noir-a05); color: var(--pal-noir); }
.cour-preview-modal-body {
    flex: 1;
    overflow-y: auto;
    padding: 30px 40px;
    background: var(--pal-gris-fond-froid);
}
.cour-preview-modal-foot {
    display: flex;
    justify-content: flex-end;
    flex-wrap: wrap;
    gap: 10px;
    padding: 12px 20px;
    border-top: 1px solid var(--color-border);
    background: var(--pal-blanc);
}
.cour-preview-loading {
    text-align: center;
    padding: 40px 20px;
    color: var(--color-muted);
    font-style: italic;
}

/* Page de courrier simulée dans la modal */
.cour-preview-page {
    background: var(--pal-blanc);
    padding: 25mm 20mm 20mm 20mm;
    box-shadow: 0 2px 10px var(--pal-noir-a08);
    border-radius: 4px;
    font-family: 'Times New Roman', Times, serif;
    font-size: 11pt;
    color: var(--pal-encre);
    line-height: 1.5;
    min-height: 500px;
}
.cour-preview-header {
    display: flex;
    justify-content: space-between;
    gap: 10mm;
    margin-bottom: 6mm;
}
.cour-preview-expediteur { flex: 1; }
.cour-preview-asso-nom { font-size: 13pt; font-weight: bold; margin-bottom: 2pt; }
.cour-preview-asso-president { font-size: 10pt; color: var(--pal-gris-fonce); margin-bottom: 4pt; }
.cour-preview-asso-coords { font-size: 9.5pt; color: var(--pal-gris-fonce); line-height: 1.6; }
.cour-preview-destinataire {
    text-align: right;
    min-width: 60mm;
    margin-top: 28mm;
}
.cour-preview-dest-nom { font-weight: bold; font-size: 11pt; }
.cour-preview-dest-service { font-size: 10pt; color: var(--pal-gris-fonce); }
.cour-preview-dest-adresse { font-size: 10pt; line-height: 1.6; margin-top: 3pt; }
.cour-preview-dest-manquant {
    color: var(--pal-rouge-600);
    font-style: italic;
    font-family: sans-serif;
    font-size: 10pt;
}
.cour-preview-date {
    text-align: right;
    font-size: 10.5pt;
    color: var(--pal-gris-fonce);
    margin-bottom: 8mm;
}
.cour-preview-objet { margin-bottom: 8mm; font-size: 11pt; }
.cour-preview-objet strong { font-weight: bold; }
.cour-preview-sep {
    border: none;
    border-top: 1px solid var(--pal-gris-trait);
    margin-bottom: 8mm;
}
.cour-preview-corps {
    font-size: 11pt;
    line-height: 1.7;
    text-align: justify;
    margin-bottom: 12mm;
}
.cour-preview-corps p { margin-bottom: 6pt; }
.cour-preview-corps ul, .cour-preview-corps ol { margin: 4pt 0 4pt 20pt; }
.cour-preview-corps .ql-indent-1 { padding-left: 30pt; }
.cour-preview-corps .ql-indent-2 { padding-left: 60pt; }
.cour-preview-corps .ql-indent-3 { padding-left: 90pt; }
.cour-preview-empty { color: var(--pal-rouge-600); font-style: italic; }
.cour-preview-signatures {
    display: flex;
    justify-content: space-around;
    flex-wrap: wrap;
    gap: 8mm;
    margin-top: 14mm;
    padding-top: 6mm;
    border-top: 1px solid var(--pal-gris-trait);
}
.cour-preview-sig-block {
    text-align: center;
    min-width: 50mm;
}
.cour-preview-sig-title { font-size: 10pt; font-weight: bold; margin-bottom: 2pt; }
.cour-preview-sig-name { font-size: 10pt; color: var(--pal-gris-fonce); margin-bottom: 12mm; }
.cour-preview-sig-line {
    border-top: 1px solid var(--pal-gris-trait);
    width: 50mm;
    margin: 0 auto;
}

@media (max-width: 768px) {
    .cour-preview-modal-box { margin: 0; max-height: 100vh; border-radius: 0; }
    .cour-preview-modal { padding: 0; }
    .cour-preview-modal-body { padding: 15px; }
    .cour-preview-page { padding: 15mm 10mm; }
    .cour-preview-header { flex-direction: column; gap: 10mm; }
    .cour-preview-destinataire { text-align: left; margin-top: 0; }
}

/* ── Écran de confirmation d'envoi d'un courrier ── */
.cour-envoye-box {
    text-align: center;
    padding: 2rem 1.5rem;
}
.cour-envoye-icon {
    font-size: 3rem;
    margin-bottom: .5rem;
}
.cour-envoye-title {
    font-size: 1.15rem;
    font-weight: 600;
    color: var(--color-success);
    margin-bottom: .5rem;
}
.cour-envoye-ref {
    display: inline-block;
    margin: .5rem 0 1rem;
    padding: .5rem 1rem;
    background: var(--color-success-soft);
    border-radius: 6px;
    font-size: .95rem;
}
.cour-envoye-ref strong {
    font-family: var(--font-mono, monospace);
    font-size: 1.1rem;
    color: var(--color-success);
}
.cour-envoye-desc {
    color: var(--color-muted);
    font-size: .9rem;
    margin: 1rem 0 1.5rem;
    line-height: 1.7;
}
.cour-envoye-actions {
    display: flex;
    gap: .6rem;
    justify-content: center;
    flex-wrap: wrap;
}
@media (max-width: 768px) {
    .cour-envoye-actions .btn {
        flex: 1 1 100%;
    }
}

/* ███████████████████████████████████████████████████████████████
   6. ÉCRANS — ADMINISTRATION
   ███████████████████████████████████████████████████████████████ */

/* ═══════════════════════════════════════════════════
   ADMIN — Composants spécifiques
   ═══════════════════════════════════════════════════ */

/* Boutons variantes (utilisés partout) */
.btn-warning { background: var(--color-warning-soft); color: var(--color-warning-text); border-color: var(--color-warning-border); }
.btn-warning:hover { background: var(--color-warning-border); }
.btn-success { background: var(--color-success-lt); color: var(--color-success); border-color: var(--color-success-border); }
.btn-success:hover { background: var(--color-success-border); }

/* Password form (change_password.php) */
.pwd-wrap { position: relative; }
.pwd-wrap input { padding-right: 40px; width: 100%; }
.pwd-eye {
    position: absolute; right: 8px; top: 50%; transform: translateY(-50%);
    background: none; border: none; cursor: pointer; font-size: 16px; padding: 2px;
}
/* Même largeur et même départ en haut que les autres pages (remarque de
   l'utilisateur, 07/10/2026) : bridée à 960 px et centrée, elle paraissait
   plus étroite que toutes les autres. */
.pwd-page { max-width: 420px; margin: 0 auto; }
/* Ordinateur : deux colonnes. À gauche ce qu'on lit (profil) et ce qu'on
   ouvre rarement (mot de passe, replié) ; à droite ce qu'on modifie (me
   joindre), la carte la plus haute. La seconde ligne est en 1fr : c'est
   elle qui absorbe la hauteur de « Me joindre », sinon un vide se
   creuserait entre le profil et le mot de passe. Un changement imposé
   met le mot de passe en tête de la colonne gauche. */
@media (min-width: 900px) {
    .pwd-page { max-width: none; }
    .pwd-grille {
        display: grid; grid-template-columns: 1fr 1fr;
        grid-template-rows: auto 1fr; gap: 1.5rem; align-items: start;
        grid-template-areas: "profil joindre" "mdp joindre";
    }
    .pwd-grille--impose { grid-template-areas: "mdp joindre" "profil joindre"; }
    .pwd-grille > .card { margin-bottom: 0; }
    .pwd-carte--profil { grid-area: profil; }
    .pwd-carte--joindre { grid-area: joindre; }
    .pwd-carte--mdp { grid-area: mdp; }
}
/* « L'application sur ce téléphone » : sous la grille, sur toute sa
   largeur (app.js ne la montre que s'il y a un geste à faire). */
/*  « Couleurs » (Mon compte) : une vignette par palette. Les couleurs de
    l'aperçu viennent de la page (--f fond, --b barre du haut, --m1..3
    les trois modules), écrites depuis le catalogue PALETTES. */
.pwd-carte--couleurs { margin-top: 1rem; }
@media (min-width: 900px) { .pwd-carte--couleurs { margin-top: 1.5rem; } }
.pal-choix { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: .75rem; }
.pal-option {
    position: relative; display: flex; flex-direction: column; gap: .5rem; cursor: pointer;
    padding: .6rem; border-radius: var(--radius-lg);
    border: 2px solid var(--color-border); background: var(--color-surface);
}
.pal-option:hover { border-color: var(--color-border-strong); }
.pal-option:has(input:checked) { border-color: var(--color-primary); background: var(--color-primary-lt); }
.pal-option:has(input:focus-visible) { outline: 3px solid var(--color-primary-ring); outline-offset: 2px; }
.pal-option input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.pal-apercu {
    display: flex; flex-direction: column; height: 64px; overflow: hidden;
    border-radius: 10px; background: var(--f); box-shadow: inset 0 0 0 1px var(--color-border);
}
.pal-apercu-barre { height: 16px; background: var(--b); box-shadow: inset 0 -1px 0 var(--color-border); }
.pal-apercu-points { display: flex; gap: 6px; padding: 12px 10px; }
.pal-apercu-points i { width: 18px; height: 18px; border-radius: 50%; background: var(--m1); }
.pal-apercu-points i:nth-child(2) { background: var(--m2); }
.pal-apercu-points i:nth-child(3) { background: var(--m3); }
.pal-nom { font-weight: 700; font-size: .9rem; line-height: 1.25; }
.pal-nom small { display: block; font-weight: 400; color: var(--color-muted); font-size: .8rem; }
@media (max-width: 768px) { .pal-choix { grid-template-columns: 1fr 1fr; } }
.pwd-carte--appli { margin-top: 1rem; }
@media (min-width: 900px) { .pwd-carte--appli { margin-top: 1.5rem; } }
.pwd-appli-texte { margin: 0 0 .75rem; font-size: .9rem; color: var(--color-muted); }
.pwd-appli-etapes { margin: 0; padding-left: 1.25rem; font-size: .9rem; line-height: 1.7; }
/* La page s'appelle « Mon compte » depuis qu'elle porte aussi le
   téléphone et la préférence d'emails : elle a donc un titre. */
.pwd-titre { font-size: 1.3rem; font-weight: 700; margin-bottom: 1rem; }
/* « Mes coordonnées » : ce que le site sait du compte, en deux
   colonnes — le libellé, la valeur. Une seule colonne sur téléphone,
   où « Dernière connexion » et sa date ne tiennent pas côte à côte. */
.pwd-identite { display: grid; grid-template-columns: auto 1fr; gap: .35rem .75rem; margin: 0 0 1rem; font-size: .88rem; }
.pwd-identite dt { color: var(--color-muted); }
.pwd-identite dd { margin: 0; font-weight: 600; word-break: break-word; }
@media (max-width: 768px) {
    .pwd-identite { grid-template-columns: 1fr; gap: .1rem; }
    .pwd-identite dd { margin-bottom: .4rem; }
}
.pwd-strength-bar {
    height: 4px; border-radius: 2px; margin-top: 6px;
    background: var(--color-border); overflow: hidden;
}
.pwd-strength-fill { height: 100%; width: 0; border-radius: 2px; transition: all .3s; }
.pwd-strength-text { font-size: .72rem; color: var(--color-muted); }
.pwd-match-text { font-size: .72rem; }
.pwd-submit { width: 100%; margin-top: .5rem; }

/*  Quatre badges de module, une seule mise en forme : seule la teinte
    change. Écrites une à une, trois d'entre elles avaient fini par
    diverger — le badge du secrétariat portait un texte vert sur un
    fond bleu, hérité d'un copier-coller. */
/*  Le rôle supplémentaire d'un compte, à côté de son rôle principal.
    Écrit plus discret : c'est un complément, pas une seconde identité,
    et deux badges de même poids se liraient comme deux comptes. */
.usr-role-second { opacity: .85; font-size: .68rem; }

/* Saisie ligne à ligne d'une remise de chèques. */

/* Permissions */
/* 280 px et non 240 : à 240, « EL MOURABITI Moustapha » était coupé alors
   que la colonne des droits avait de la place à revendre. */
.perms-layout { display: grid; grid-template-columns: 280px 1fr; gap: 1.25rem; align-items: start; }

/* Sur ordinateur, la colonne des comptes se lit d'un coup d'œil et le
   menu déroulant ne servirait à rien : il reste masqué, et un élément en
   display: none ne compte pas comme cellule de la grille. */
.perms-choix { display: none; }

@media (max-width: 768px) {
    .perms-layout { grid-template-columns: 1fr; }
    /* Deux barres de navigation sont déjà collées en haut d'un téléphone :
       une troisième mangerait le tiers de l'écran utile. */
    .perms-barre { position: static; }
    .perms-choix {
        display: flex; flex-wrap: wrap; align-items: center; gap: .6rem;
    }
    .perms-choix label { font-size: .85rem; color: var(--color-muted); margin: 0; }
    /* Le menu garde sa ligne pleine largeur — un nom de compte suivi de
       son rôle est long —, le bouton se met en dessous. */
    .perms-choix select {
        flex: 1 1 100%; width: 100%; min-width: 0;
        padding: .4rem .6rem; font-size: .9rem;
        border: 1px solid var(--color-border);
        border-radius: var(--radius);
        background: var(--color-surface); color: var(--color-text);
    }
    .perms-choix .btn { flex: 1 1 auto; justify-content: center; }
}

/* La colonne listait vingt-trois comptes et partait vers le haut avec le
   reste de la page : changer de personne obligeait à remonter tout ce
   qu'on venait de descendre. Elle se colle donc en haut et défile pour
   elle seule. (.perms-layout est déjà en align-items: start, sans quoi
   une cellule de grille s'étire sur toute la hauteur et rien ne colle.)

   `min-height: 0` sur la zone qui défile : sans lui, un enfant flex
   refuse de devenir plus court que son contenu et le débordement
   remonterait sur la colonne entière — même écueil que .sb-scroll dans
   la barre latérale. */
.perms-sidebar {
    padding: .5rem 0;
    position: sticky;
    top: 1rem;
    /* Plafonnée aussi en valeur absolue : sur un grand écran, la hauteur
       de la fenêtre laissait la liste descendre bien sous la colonne des
       droits, sections repliées. Au-delà, elle défile. */
    max-height: min(calc(100vh - 2rem), 40rem);
    display: flex;
    flex-direction: column;
}
.perms-sidebar-liste { overflow-y: auto; min-height: 0; }
.perms-filtre { padding: 0 12px 8px; flex-shrink: 0; }
.perms-filtre input {
    width: 100%; box-sizing: border-box;
    padding: .35rem .55rem; font-size: .8rem;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius);
    background: var(--color-surface); color: var(--color-text);
    font-family: var(--font);
}

/* Sur téléphone, la colonne disparaît au profit du menu « Compte »
   (.perms-choix) : empilée au-dessus du formulaire, elle obligeait à
   traverser tous les comptes avant d'atteindre la première case.
   ⚠ Cette règle doit rester APRÈS celle de .perms-sidebar : à force
   égale, la dernière écrite gagne. Posée plus haut, elle était écrasée
   par le display: flex de la colonne collante, et la liste revenait sur
   téléphone. */
@media (max-width: 768px) {
    .perms-sidebar { display: none; }
}
/* Groupes par rôle : l'intitulé remplace le badge répété sur chaque
   ligne. Le résumé est un vrai <summary>, donc atteignable au clavier. */
.perms-groupe + .perms-groupe { border-top: 1px solid var(--color-border); }
.perms-groupe-titre {
    display: flex; align-items: center; gap: 7px;
    padding: 7px 14px 5px;
    font-size: .8rem; font-weight: 700;
    color: var(--color-muted);
    cursor: pointer; list-style: none; user-select: none;
}
.perms-groupe-titre::-webkit-details-marker { display: none; }
.perms-groupe-titre::after {
    content: '▾'; margin-left: auto; font-size: .8rem;
    transition: transform .15s;
}
.perms-groupe:not([open]) > .perms-groupe-titre::after { transform: rotate(-90deg); }
.perms-groupe-titre:hover { color: var(--color-text); }
.perms-groupe-pastille { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
/*  Une teinte par rôle (pastille d'un groupe, pilule du compte affiché) :
    elles étaient un tableau PHP recopié dans des style="…". Un rôle
    ajouté demain prend sa ligne ici, sinon il reste gris. */
.perms-role.perms-role { background: var(--pal-gris-neutre); }
.perms-role.perms-role--admin         { background: var(--pal-violet-600); }
.perms-role.perms-role--secretaire    { background: var(--pal-vert-sapin); }
.perms-role.perms-role--tresorier     { background: var(--pal-or-brun); }
.perms-role.perms-role--bureau        { background: var(--pal-bleu-petrole); }
.perms-role.perms-role--cotisations   { background: var(--pal-cyan-700); }
.perms-role.perms-role--ecole         { background: var(--pal-indigo-600); }
.perms-role.perms-role--ecole_pedago  { background: var(--pal-indigo-500); }
.perms-role.perms-role--ecole_lecture { background: var(--pal-indigo-400); }
.perms-role.perms-role--prof          { background: var(--pal-indigo-800); }
.perms-role.perms-role--membre        { background: var(--pal-ardoise-bleue); }
.perms-groupe-nb {
    font-weight: 600; letter-spacing: 0;
    background: var(--color-surface-alt); border-radius: 999px; padding: 0 6px;
}

/* Une ligne par compte, sans avatar : ~32 px au lieu de 52. */
.perms-user-item {
    display: flex; align-items: center; gap: 6px;
    padding: 6px 14px 6px 29px; text-decoration: none; color: inherit;
    border-left: 3px solid transparent;
    transition: background .12s, border-color .12s;
}
.perms-user-item:hover  { background: var(--color-surface-alt); }
.perms-user-item.active { background: var(--color-accent-lt); border-left-color: var(--color-primary); }
.perms-user-item .perms-user-name { flex: 1; min-width: 0; display: block; }
.perms-user-ov { flex-shrink: 0; font-size: .8rem; }
.perms-avatar {
    width: 34px; height: 34px; border-radius: 50%;
    background: var(--color-surface-alt); border: 1px solid var(--color-border);
    display: flex; align-items: center; justify-content: center;
    font-size: 12px; font-weight: 700; color: var(--color-primary); flex-shrink: 0;
}
.perms-avatar--lg { width: 44px; height: 44px; font-size: 15px; }
.perms-user-name {
    font-size: .84rem; font-weight: 600;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    display: flex; align-items: center; gap: 5px;
}
.role-pill {
    display: inline-block; padding: 2px 8px; border-radius: 999px;
    font-size: .65rem; font-weight: 700; color: var(--pal-blanc);
}
.ov-badge {
    display: inline-block; font-size: .62rem; font-weight: 700;
    background: var(--color-warning-soft); color: var(--color-warning-text); border-radius: 3px; padding: 1px 5px;
}
.ov-badge--lg { font-size: .72rem; padding: 2px 7px; }

/* Le bandeau du compte choisi porte les deux commandes qui écrivent.
   Il reste visible pendant qu'on descend les sections : « Enregistrer »
   était sinon tout en bas, derrière cinquante-trois lignes de cases à
   cocher, alors qu'on vient ici pour en changer une. */
.perms-barre { position: sticky; top: 1rem; z-index: 40; }
.perms-barre-actions { display: flex; gap: .5rem; flex-wrap: wrap; flex-shrink: 0; }

/* Compteur d'une section : replié, c'est lui qui remplace la lecture des
   cases une par une. Le ⚡ est sa partie indispensable — une ligne
   personnalisée est surlignée, mais ce surlignage disparaît avec la
   section refermée, et un réglage sur mesure invisible est un réglage
   oublié. */
.perms-section-compte {
    font-size: .72rem; font-weight: 600; color: var(--color-muted);
    white-space: nowrap; flex-shrink: 0;
}
.perms-section-compte--surmesure {
    color: var(--color-warning-text); background: var(--color-warning-soft); border-radius: 3px; padding: 1px 6px;
}
[data-theme="dark"] .perms-section-compte--surmesure {
    color: var(--color-warning); background: var(--pal-ambre-400-a12);
}

/* Les .perm-row portent déjà leur propre rembourrage : le corps de carte
   ne doit pas en ajouter un second autour d'elles. */
.perms-section-corps { padding: 0; }

.perms-header-bar { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.perms-header-body { flex: 1; }
.perms-header-name { font-size: 1rem; font-weight: 600; }
.perms-header-meta { margin-top: 4px; display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.perms-header-caisse { font-size: .72rem; color: var(--color-muted); }
.perms-info-box {
    font-size: .8rem; color: var(--color-muted); background: var(--color-surface-alt);
    border-radius: var(--radius); padding: 10px 14px; margin-bottom: 1rem;
    border: 1px solid var(--color-border);
}
/* h3 depuis le regroupement par module : la règle .card-header h2 ne le
   couvre plus, graisse et marge sont reprises ici. */
.perms-section-title { font-size: .9rem; font-weight: 600; margin: 0; }

/* Bandeau de module : un titre et un compteur, pas une carte de plus.
   Il regroupe visuellement les sections d'un même module (six pour la
   trésorerie) et dit sans rien ouvrir où sont les droits d'une personne. */
.perms-module { margin-bottom: 1.5rem; }
.perms-module:not([open]) { margin-bottom: .6rem; }

/* Le module emprunte le repli mémorisé de details.pliable (app.js),
   pas son allure de carte : ces règles, écrites bien avant celles de
   l'école dans la feuille, l'emportent par leur précision (élément + deux
   classes) et non par leur place. Le <summary> reste en display: block,
   c'est le titre qui porte le flex (Safari iOS). */
details.perms-module.pliable > summary {
    padding: 0; border-bottom: none; background: none;
    list-style: none; cursor: pointer;
}
details.perms-module.pliable > summary::-webkit-details-marker { display: none; }
details.perms-module.pliable > summary:hover { background: none; }
details.perms-module.pliable > summary:hover .perms-module-titre { border-bottom-color: var(--color-primary); }

.perms-module-titre {
    display: flex; align-items: center; justify-content: space-between; gap: .5rem;
    margin: 0 0 .6rem; padding: 0 .15rem .4rem;
    font-size: .9rem; font-weight: 700;
    color: var(--color-text);
    border-bottom: 2px solid var(--color-border-strong);
    transition: border-color .15s;
}
.perms-module:not([open]) .perms-module-titre { margin-bottom: 0; }
.perms-module-titre .perms-section-compte { text-transform: none; letter-spacing: 0; }
.perms-module-nom { display: flex; align-items: center; gap: .45rem; }
.perms-module-chevron {
    display: inline-block; font-size: .75rem; color: var(--color-muted);
    transition: transform .2s;
}
.perms-module:not([open]) .perms-module-chevron { transform: rotate(-90deg); }
.perms-icon { font-size: 15px; }
.perms-hint-locked { color: var(--color-muted); }
.perms-save-bar { display: flex; justify-content: flex-end; gap: .75rem; margin-top: .5rem; }

.perm-row {
    display: flex; align-items: center; justify-content: space-between;
    padding: 11px 20px; border-bottom: 1px solid var(--color-border); transition: background .1s;
}
.perm-row:last-child { border-bottom: none; }
.perm-row--changed { background: var(--color-warning-lt); }
[data-theme="dark"] .perm-row--changed { background: var(--color-warning-soft); }

.perm-info { display: flex; align-items: center; gap: 10px; flex: 1; }
.perm-label { font-size: .85rem; font-weight: 500; display: block; }
.perm-default-hint { font-size: .72rem; margin-top: 2px; display: block; }
.hint--added   { color: var(--color-warning-text); font-weight: 600; }
.hint--removed { color: var(--color-danger); font-weight: 600; }

.toggle-wrap { cursor: pointer; flex-shrink: 0; }
.toggle-wrap input { display: none; }
.toggle-track {
    display: block; width: 42px; height: 24px; border-radius: 12px;
    background: var(--color-border); position: relative; transition: background .2s;
}
.toggle-track::before {
    content: ''; position: absolute; width: 18px; height: 18px; border-radius: 50%;
    background: var(--pal-blanc); top: 3px; left: 3px; transition: transform .2s;
    box-shadow: 0 1px 3px var(--pal-noir-a20);
}
.toggle-wrap input:checked + .toggle-track { background: var(--color-primary-fond); }
.toggle-wrap input:checked + .toggle-track::before { transform: translateX(18px); }
.toggle-wrap--disabled { opacity: .4; cursor: not-allowed; pointer-events: none; }
.toggle-wrap.is-changed .toggle-track { outline: 2px solid var(--color-warning); outline-offset: 2px; }

/* Users (users.php) */
.user-form {
    background: var(--color-surface); border: 1px solid var(--color-border);
    border-radius: var(--radius); padding: 1.5rem; margin-bottom: 1.5rem; max-width: 620px;
}
.user-form h2 {
    font-size: 1.05rem; font-weight: 600; margin-bottom: 1.25rem;
    padding-bottom: .75rem; border-bottom: 1px solid var(--color-border);
}
.form-actions { display: flex; gap: .75rem; margin-top: 1.5rem; flex-wrap: wrap; }
.role-option {
    display: flex; align-items: flex-start; gap: 10px; padding: 10px 12px;
    border: 1.5px solid var(--color-border); border-radius: var(--radius);
    cursor: pointer; transition: border-color .15s, background .15s; margin-bottom: 8px;
}
.role-option:hover { border-color: var(--color-primary); background: var(--color-surface-alt); }
.role-option input[type=radio] { margin-top: 3px; flex-shrink: 0; }
.role-option.selected { border-color: var(--color-primary); background: var(--color-accent-lt); }
.role-icon { font-size: 18px; flex-shrink: 0; }
.role-label { font-size: .875rem; font-weight: 600; }
.role-desc { font-size: .78rem; color: var(--color-muted); margin-top: 2px; }
.caisse-preview {
    font-size: .8rem; background: var(--color-surface-alt); border: 1px solid var(--color-border);
    border-radius: 6px; padding: 6px 12px; margin-top: 8px; display: none;
}
.caisse-preview.is-visible { display: block; }
.caisse-preview code { background: var(--pal-or-50); color: var(--pal-or-texte); padding: 1px 5px; border-radius: 3px; }
[data-theme="dark"] .caisse-preview code { background: var(--color-gold-soft); color: var(--color-warning-text); }
.usr-caisse-hint { display: block; margin-top: 4px; }

/* Ligne de suppression : elle est définitive et sans retour possible.
   Elle ne doit pas se lire comme les trois autres au moment où le doigt
   descend le menu. */
.usr-menu-danger { color: var(--color-danger); }

.status-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin-right: .4rem; }
.status-dot.active { background: var(--color-success); }
.status-dot.inactive { background: var(--color-danger); }

.usr-self-role    { font-size: .85rem; }
.usr-opt-badge    { font-size: .65rem; color: var(--color-warning-text); background: var(--color-warning-soft); border-radius: 3px; padding: 1px 4px; }
[data-theme="dark"] .usr-opt-badge { color: var(--color-warning); background: var(--pal-ambre-400-a12); }
.usr-locked       { color: var(--color-danger); }
.usr-count-wrap   { margin-top: .75rem; }

/* Utilisateurs groupés par rôle : une carte repliable par groupe. */
.usr-groupe { margin-bottom: .75rem; }
.usr-groupe-role { margin-top: .25rem; }
/* Un tableau par rôle : colonnes à largeur fixe, pour que « Dernière
   connexion » tombe au même endroit d'un groupe à l'autre. */
@media (min-width: 769px) {
    .usr-liste { table-layout: fixed; width: 100%; }
    .usr-liste .usr-th-role { width: 13rem; }
    .usr-liste .usr-th-connexion { width: 14rem; }
    .usr-liste .liste-th-actions { width: 18rem; }   /* « Modifier » + « Permissions » sur sa propre ligne */
}

.usr-check-label  { display: flex; align-items: center; gap: .5rem; cursor: pointer; }
.usr-actions-row  { display: flex; gap: .75rem; flex-wrap: wrap; }
/* Après un mot de passe temporaire : « Envoyer par WhatsApp » et
   « Copier le message » sous le mot de passe, dans le bandeau vert. */
.usr-acces-envoi  { display: flex; gap: .5rem; flex-wrap: wrap; margin: .6rem 0 .4rem; }
.usr-stats-row { display: flex; gap: 1.5rem; flex-wrap: wrap; align-items: center; margin-bottom: 1rem; }
.usr-stat-item    { text-align: center; }
.usr-stat-val     { font-size: 1.8rem; font-weight: 700; }
.usr-stat-label   { font-size: .75rem; color: var(--color-muted); }
.usr-stat--present { color: var(--color-success); }
.usr-stat--excuse  { color: var(--color-warning); }
.usr-stat--absent  { color: var(--color-danger); }
.usr-stat--muted   { color: var(--color-muted); }
.usr-stat-bar-wrap { flex: 1; min-width: 120px; }
.usr-stat-bar { display: flex; height: 10px; border-radius: 5px; overflow: hidden; background: var(--color-border); }
.usr-stat-bar-seg { height: 100%; width: 0; transition: width .6s cubic-bezier(.22,.61,.36,1); }
.usr-stat-bar-seg--present { background: var(--pal-vert-600); }
.usr-stat-bar-seg--excuse  { background: var(--pal-ambre-600); }
.usr-stat-bar-seg--absent  { background: var(--pal-rouge-600); }
.usr-stat-bar-note { font-size: .7rem; color: var(--color-muted); margin-top: 4px; }

/* Utilisateurs : chiffres de présence en mode sombre, puis sur téléphone. */
[data-theme="dark"] .usr-stat--present { color: var(--color-success); }
[data-theme="dark"] .usr-stat--excuse  { color: var(--color-warning); }
[data-theme="dark"] .usr-stat--absent  { color: var(--color-danger); }

@media (max-width: 768px) {

    /* Le passage carte de .users-table est désormais géré par le motif
       partagé .table-mobile / .table-mobile--repliable (voir plus haut) :
       même liste repliable que Élèves/Familles, pas de règles propres ici. */
    .usr-stats-row { gap: 1rem; }
    .usr-stat-val { font-size: 1.4rem; }
    .usr-stat-bar-wrap { flex-basis: 100%; }
}

/* ── Users — Edit layout ── */
.usr-edit-layout {
    display: flex !important;
    flex-direction: row !important;
    gap: 1.25rem;
    align-items: flex-start;
}
.usr-edit-main { flex: 1; min-width: 0; }
.usr-edit-main .user-form { max-width: 100%; }
.usr-edit-sidebar { width: 320px; flex-shrink: 0; }
.usr-edit-sidebar .user-form { max-width: 100%; }

/*  La fiche d'un compte en trois blocs titrés, deux champs par ligne :
    une dizaine de réglages tenaient sur plus d'un écran, chaque champ
    sur toute la largeur avec sa phrase d'explication dessous (passée
    dans une bulle ⓘ). Le bloc n'a pas de cadre — un filet et un titre
    suffisent à séparer, un cadre dans la carte en ferait trop. */
.usr-bloc { border: 0; margin: 0 0 .9rem; padding: 0; min-width: 0; }
.usr-bloc > legend {
    font-size: .9rem; font-weight: 700;
    color: var(--color-muted); padding: 0; margin-bottom: .6rem;
}
.usr-bloc + .usr-bloc { border-top: 1px solid var(--color-border); padding-top: .9rem; }
.usr-ligne { display: grid; grid-template-columns: 1fr 1fr; gap: 0 1rem; }
.usr-bloc .form-group { margin-bottom: .75rem; }
/*  Une case à cocher et sa bulle sur une ligne : la bulle hors du
    <label>, sinon toucher le ⓘ cocherait la case. */
.usr-case { display: flex; align-items: center; gap: .35rem; }
.form-group label.usr-check-label { margin-bottom: 0; }
/*  À côté d'un menu, la case se cale sur la hauteur du champ et non sur
    son libellé : sinon elle flotte au niveau du titre « Fonction ». */
.usr-ligne .usr-case--alignee { align-self: end; min-height: 2.4rem; }
@media (max-width: 768px) {
    .usr-ligne { grid-template-columns: 1fr; }
    .usr-ligne .usr-case--alignee { min-height: 0; }
    /*  Prénom et nom sont courts : côte à côte, ils tiennent encore. */
    .usr-ligne--toujours { grid-template-columns: 1fr 1fr; }
}

/*  Les trois actions tiennent dans une colonne de 320 px : à leur
    largeur naturelle, chacune passait à la ligne avec un bord droit
    différent — un escalier de trois boutons. Elles prennent la largeur
    de la carte, et gardent donc le même bord des deux côtés.
    Écrit sur .usr-edit-sidebar et non sur .usr-actions-row : la même
    rangée, posée un jour ailleurs qu'en colonne, doit continuer de se
    lire côte à côte. */
.usr-edit-sidebar .usr-actions-row { flex-direction: column; align-items: stretch; gap: .5rem; }
.usr-edit-sidebar .usr-actions-row > form { display: flex; }
.usr-edit-sidebar .usr-actions-row > form > .btn,
.usr-edit-sidebar .usr-actions-row > .btn { width: 100%; }
/*  La colonne fait 320 px : « Créer un mot de passe temporaire » ne tient
    pas sur une ligne, et le nowrap de .btn le faisait déborder de la carte
    (capture de l'utilisateur). Ici, le libellé passe à la ligne DANS le
    bouton. */
.usr-edit-sidebar .usr-actions-row > form { min-width: 0; }
.usr-edit-sidebar .usr-actions-row .btn { white-space: normal; min-width: 0; text-align: center; }

/*  Le bouton du bas de la carte de présence suit la même largeur : sans
    cela, les deux cartes de la colonne se terminent sur deux boutons de
    tailles différentes. */
.usr-edit-sidebar .user-form > .btn,
.usr-edit-sidebar .usr-danger-zone .btn { width: 100%; }

@media (max-width: 900px) {
    .usr-edit-layout { flex-direction: column !important; }
    .usr-edit-sidebar { width: 100%; }
    /*  Passée sous le formulaire, la colonne fait toute la largeur de la
        page : trois boutons étirés sur 900 px seraient pires que
        l'escalier. Ils reprennent leur largeur naturelle et tiennent sur
        une ligne. */
    .usr-edit-sidebar .usr-actions-row { flex-direction: row; align-items: center; gap: .75rem; }
    .usr-edit-sidebar .usr-actions-row > form > .btn,
    .usr-edit-sidebar .usr-actions-row > .btn,
    .usr-edit-sidebar .user-form > .btn,
    .usr-edit-sidebar .usr-danger-zone .btn { width: auto; }
}

/*  « form-hint » était posée sur les deux phrases d'explication du
    formulaire des comptes sans qu'aucune règle ne l'habille : elles
    s'affichaient à la taille du texte courant, plus grosses que les
    <small class="text-muted"> qui jouent le même rôle trois champs plus
    haut. */
.form-hint { display: block; margin-top: .4rem; font-size: .78rem; color: var(--color-muted); }

/*  L'état du compte, en tête de la carte d'actions : ce qui explique
    qu'une personne n'arrive pas à se connecter se lit là, et non plus
    seulement dans la liste. */
.usr-etat { list-style: none; margin: 0 0 1.25rem; padding: 0; font-size: .82rem; }
.usr-etat li { padding: .15rem 0; color: var(--color-muted); }
.usr-etat li:first-child { color: var(--color-text); font-weight: 500; }

/*  La suppression est définitive : elle se détache des actions
    courantes par un filet, comme ailleurs sur le site. Bouton neutre
    au texte rouge plutôt qu'un aplat — il ne doit pas attirer la main
    qui vient pour les trois autres. */
.usr-danger-zone { margin-top: 1.25rem; padding-top: 1rem; border-top: 1px solid var(--color-border); }
.usr-danger-zone small { display: block; margin-top: .5rem; font-size: .72rem; }
.usr-btn-danger { color: var(--color-danger); border-color: var(--color-danger); }
.usr-btn-danger:hover { background: var(--color-danger-lt); }

/*  Sur téléphone la ligne ne tient plus : on revient à la pile pleine
    largeur, comme .page-actions ailleurs sur le site. Écrit après la
    media query ci-dessus, sinon elle l'annulerait. */
@media (max-width: 768px) {
    .usr-edit-sidebar .usr-actions-row { flex-direction: column; align-items: stretch; gap: .5rem; }
    .usr-edit-sidebar .usr-actions-row > form > .btn,
    .usr-edit-sidebar .usr-actions-row > .btn,
    .usr-edit-sidebar .user-form > .btn,
    .usr-edit-sidebar .usr-danger-zone .btn { width: 100%; }
}

/* ── Sommaire sticky en haut des pages paramètres ── */
.params-toc {
    position: sticky;
    top: calc(var(--header-h, 56px) + 8px);
    z-index: 10;
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    padding: .6rem .9rem;
    margin-bottom: 1.25rem;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 8px;
    box-shadow: 0 2px 6px var(--pal-noir-a04);
}
.params-toc a {
    font-size: .82rem;
    padding: .35rem .7rem;
    border-radius: 5px;
    color: var(--color-text);
    text-decoration: none;
    transition: background .15s;
    white-space: nowrap;
}
.params-toc a:hover {
    background: var(--color-info-lt);
    color: var(--color-primary);
}
@media (max-width: 768px) {
    .params-toc {
        display: grid;
        grid-template-columns: repeat(2, 1fr);
        gap: .4rem;
    }
    .params-toc a {
        font-size: .78rem;
        padding: .4rem .5rem;
        text-align: center;
        white-space: normal;
    }
}

/* ── Page sauvegarde : statistiques d'export ── */
.backup-stats {
    margin: 1rem 0 1.25rem;
    padding: 1rem;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: 8px;
}
.backup-stats-title {
    font-weight: 600;
    margin-bottom: .6rem;
    font-size: .9rem;
}
.backup-stats-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: .5rem;
    margin-bottom: .6rem;
}
.backup-stat {
    display: flex;
    align-items: baseline;
    gap: .5rem;
    padding: .4rem .6rem;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 5px;
    font-size: .82rem;
}
.backup-stat-num {
    font-weight: 700;
    color: var(--color-primary);
    min-width: 2.5em;
    text-align: right;
}
.backup-stat-label {
    color: var(--color-muted);
    font-family: var(--font-mono, monospace);
    font-size: .76rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.backup-stats-total {
    font-size: .85rem;
    color: var(--color-muted);
    padding-top: .5rem;
    border-top: 1px dashed var(--color-border);
}

/* ── Page sauvegarde : résultat d'import ── */
.backup-import-result {
    margin-top: 1rem;
    padding: .9rem 1rem;
    background: var(--color-success-soft);
    border-left: 3px solid var(--color-success);
    border-radius: 5px;
    font-size: .85rem;
}
.backup-import-title {
    font-weight: 600;
    margin-bottom: .4rem;
}
.backup-import-result ul { margin: 0; padding-left: 1.2rem; }
.backup-import-result li { margin: .15rem 0; }

/* ══════════════════════════════════════════════════════════════
   EXERCICES COMPTABLES — admin/exercices.php
   Ces valeurs étaient écrites dans le HTML (style="…"), dont une
   couleur en dur qui ne suivait pas le thème sombre.
   ══════════════════════════════════════════════════════════════ */

/* ══════════════════════════════════════════════════════════════
   NETTOYAGE DES JUSTIFICATIFS — admin/nettoyage_justificatifs.php
   Ces règles vivaient dans un bloc <style> en bas de la page : le
   navigateur les relisait à chaque affichage, hors du cache.
   ══════════════════════════════════════════════════════════════ */
.nj-card-header  { display: flex; justify-content: space-between; align-items: center; }
.nj-tout         { font-size: .85rem; font-weight: 400; cursor: pointer; }
.nj-col-case     { width: 2.5rem; }
.nj-col-taille   { width: 6rem; text-align: right; white-space: nowrap; }
.nj-chemin       { font-size: .8rem; word-break: break-all; }
.nj-footer       { text-align: right; padding: 1rem; border-top: 1px solid var(--color-border); }
.nj-liste-manquants { margin: .5rem 0 0; padding-left: 1.2rem; font-size: .85rem; }
/* Un chemin de fichier n'a pas d'espace où se couper : sur téléphone il
   sortait de l'alerte. */
.nj-liste-manquants code { overflow-wrap: anywhere; }

/* ███████████████████████████████████████████████████████████████
   7. MODE SOMBRE DES ANCIENS ÉCRANS (avant la trésorerie et l'école, qui le retouchent)
   ███████████████████████████████████████████████████████████████ */

/* ═══════════════════════════════════════════════════
   DARK MODE — Inline style overrides
   ═══════════════════════════════════════════════════ */
[data-theme="dark"] input,
/* ══ Habillage de base d'une liste déroulante ══
   Le thème sombre habillait TOUS les select (règle ci-dessous), le thème
   clair aucun : il n'existait que des règles par contexte (.form-group,
   .filters, .ecole-filters…). Un select posé ailleurs — la colonne
   « Déplacer vers » d'une fenêtre de répartition, le jour d'un créneau —
   gardait donc l'apparence grise native du navigateur, au milieu de
   champs blancs et arrondis.

   Volontairement sans padding ni font-size : quatre contextes
   (.cour-sidebar-select, .ecole-appel-champ, .pv-add-action-wrap,
   .ops-pp-form) ne fixent pas les leurs et changeraient de taille. Cette
   règle habille, elle ne redimensionne pas — exactement ce que fait son
   équivalent sombre. Toute règle de classe l'emporte sur elle. */
select {
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius);
    background: var(--color-surface);
    color: var(--color-text);
    font-family: var(--font);
}

/* ══ Le bouton « Choisir un fichier » ══
   Même défaut que les listes déroulantes, au même endroit : le cadre d'un
   champ de fichier venait de .form-group input, mais le bouton QUI EST
   DEDANS est dessiné par le navigateur et aucune règle du site ne le
   touchait — un bouton gris carré au milieu d'un champ blanc arrondi.
   Il est rare (quatre champs visibles : sauvegarde, les deux logos et la
   photo de couverture, une pièce jointe de réunion), donc jamais habillé
   contexte par contexte.
   Le pseudo-élément ne s'atteint que comme ceci : ni .btn ni une classe
   ne peuvent être posées sur un bouton que le navigateur fabrique. */
input[type="file"]::file-selector-button {
    margin-right: .6rem;
    padding: .3rem .7rem;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius);
    background: var(--color-surface-alt);
    color: var(--color-text);
    font-family: var(--font);
    font-size: .78rem;
    font-weight: 500;
    cursor: pointer;
}
input[type="file"]::file-selector-button:hover { background: var(--color-surface); }

[data-theme="dark"] select,
[data-theme="dark"] textarea {
    background: var(--color-surface);
    color: var(--color-text);
    border-color: var(--color-border-strong);
}
[data-theme="dark"] input::placeholder,
[data-theme="dark"] textarea::placeholder { color: var(--color-muted); }

[data-theme="dark"] .btn-secondary {
    background: var(--color-surface-alt);
    border-color: var(--color-border-strong);
}
[data-theme="dark"] .btn-danger {
    background: var(--pal-rouge-900); color: var(--pal-rouge-300);
}

/* Modals */
[data-theme="dark"] .modal-overlay { background: var(--pal-noir-a60); }
[data-theme="dark"] .modal-coupures-box,
[data-theme="dark"] .modal-justif-box {
    background: var(--color-surface);
    box-shadow: var(--shadow-lg);
}

/* Justificatifs */
[data-theme="dark"] .justif-dropzone { border-color: var(--color-border); background: var(--color-surface); }
[data-theme="dark"] .justif-dropzone:hover { border-color: var(--color-primary); }

/* ███████████████████████████████████████████████████████████████
   8. ÉCRANS — TRÉSORERIE
   ███████████████████████████████████████████████████████████████ */

/* ═══════════════════════════════════════════════════
   DASHBOARD SPECIFIC
   ═══════════════════════════════════════════════════ */
.dashboard-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(380px, 1fr));
    gap: 1.25rem;
}
@media (max-width: 768px) {
    .dashboard-grid { grid-template-columns: 1fr; }
}

/* Action list */
.action-item {
    padding: .65rem .85rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    border-left: 3px solid var(--color-primary);
    transition: background var(--transition);
}
.action-desc { font-size: .85rem; font-weight: 500; margin-bottom: .2rem; }
.action-meta { display: flex; gap: .75rem; font-size: .78rem; color: var(--color-muted); flex-wrap: wrap; }

/* ═══════════════════════════════════════════════════
   DASHBOARD TRÉSORERIE — Composants spécifiques
   ═══════════════════════════════════════════════════ */

/* « À traiter » — remplace les bandeaux pleine couleur, qui occupaient
   tout l'écran du téléphone avant les actions rapides. Fond neutre et
   filet de couleur : l'alerte se voit sans crier, et suit le thème.
   Hauteur mini 44 px : la ligne entière est la cible du doigt. */
/*  « À traiter » — composant partagé, et non un bloc de trésorerie.
    Né sur l'accueil du trésorier sous le préfixe treso-, il sert
    depuis à l'accueil de l'école : garder le préfixe d'un module
    aurait fait croire, à chaque lecture, que l'un des deux écrans
    emprunte le style de l'autre. */
/* Accueil de l'école : une pile de cartes repliées à écart unique. Les
   marges propres à chaque carte (dont celle de .atraiter, pensée pour la
   trésorerie) sont neutralisées, sinon elles découpent la pile en faux
   groupes. */
.ecole-accueil-cartes { display: flex; flex-direction: column; gap: .6rem; margin-bottom: 1.25rem; }
.ecole-accueil-cartes > .card { margin: 0; }
.atraiter-liste { list-style: none; margin: 0; padding: 0; }
.atraiter-liste li + li { border-top: 1px solid var(--color-border); }
/*  Refonte B2·3 (étape 4) : un point de la couleur de la gravité devant,
    le chiffre de la même couleur, « › » au bout — plus de filet à gauche
    ni d’emoji (maquette du portail). */
.atraiter-ligne {
    display: flex; align-items: center; gap: .75rem;
    min-height: 48px; padding: .6rem 1.25rem;
    color: var(--color-text); text-decoration: none; font-size: .92rem;
}
.atraiter-point { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; background: var(--color-info); }
.atraiter-ligne--danger .atraiter-point { background: var(--color-danger); }
.atraiter-ligne--warn   .atraiter-point { background: var(--color-warning-vif); }
.atraiter-ligne:hover { background: var(--color-surface-alt); text-decoration: none; }
/* Une ligne sans lien (le compte n'a pas accès à l'écran visé) ne
   réagit pas au survol : elle informe, elle ne mène nulle part. */
div.atraiter-ligne:hover { background: none; }
.atraiter-lib { flex: 1; min-width: 0; }
.atraiter-val { font-weight: 700; white-space: nowrap; font-variant-numeric: tabular-nums; color: var(--color-info); }
.atraiter-ligne--danger .atraiter-val { color: var(--color-danger); }
.atraiter-ligne--warn .atraiter-val   { color: var(--color-warning); }
.atraiter-val--neutre { color: var(--color-muted); font-weight: 400; }
.atraiter-chevron { color: var(--color-muted); font-size: 1.1rem; flex-shrink: 0; }

@media (max-width: 768px) {
    .atraiter-ligne { padding-left: .9rem; padding-right: .9rem; }
}

/* ═══════════════════════════════════════════════════
   CATÉGORIES — tresorerie/categories.php
   ═══════════════════════════════════════════════════ */

.cat-layout { display: grid; grid-template-columns: 320px 1fr; gap: 1.5rem; align-items: start; }
.cat-form-sticky { position: sticky; top: 110px; }
.card-title-sm { font-size: .9rem; }
.cat-scope-badge {
    font-size: .78rem; font-weight: 700;
    border-radius: 999px; padding: 2px 10px;
}

/*  Sombre : la couleur du badge, posée dans la page (constante --pal-…),
    restait foncée sur fond foncé (contraste 2,7). Le texte prend la couleur
    du thème ; !important parce que la page l’écrit en ligne. */
[data-theme="dark"] .cat-scope-badge { color: var(--color-text) !important; }
.cat-scope-badge--bleu-petrole { background: var(--pal-bleu-petrole-a13); color: var(--pal-bleu-petrole); }
.cat-scope-badge--or-brun      { background: var(--pal-or-brun-a13);      color: var(--pal-or-brun); }
.cat-scope-badge--vert-sapin   { background: var(--pal-vert-sapin-a13);   color: var(--pal-vert-sapin); }

@media (max-width: 768px) {
    .cat-layout { grid-template-columns: 1fr; }
    .cat-form-sticky { position: static; }
}

/* ═══════════════════════════════════════════════════
   RÈGLES — tresorerie/regles.php
   ═══════════════════════════════════════════════════ */

.regles-motcle {
    background: var(--color-surface-alt); padding: 2px 8px;
    border-radius: 4px; font-weight: 700;
}
.regles-cat-badge {
    background: var(--color-info-soft); color: var(--color-info-text);
    padding: 2px 10px; border-radius: 10px; font-size: .78rem;
}
[data-theme="dark"] .regles-cat-badge { background: var(--pal-bleu-600-a15); color: var(--color-info-text); }

/* Modal overlay (used in regles, etc.) */
.modal-overlay {
    display: none; position: fixed; inset: 0;
    background: var(--pal-noir-a50); z-index: 1000;
}

/* ═══════════════════════════════════════════════════
   CERFA — tresorerie/cerfa.php
   ═══════════════════════════════════════════════════ */

#cerfa-wrapper {
    position: fixed; inset: 0; background: var(--pal-gris-fond);
    z-index: 9999; overflow-y: auto; padding: 1rem;
}
.cerfa-num { text-align: right; font-size: 10px; color: var(--pal-gris-fonce); margin-bottom: 8px; }
.cerfa-h1 { font-size: 13px; font-weight: 700; text-align: center; text-transform: uppercase; margin: 0 0 6px; }
.cerfa-sub { text-align: center; font-size: 9.5px; color: var(--pal-gris-sombre); margin-bottom: 16px; line-height: 1.5; }
.cb { border: 1.5px solid var(--pal-noir); border-radius: 4px; padding: 10px 12px; margin-bottom: 10px; }
.cbl { border: 1px solid var(--pal-gris-clair); border-radius: 4px; padding: 10px 12px; margin-bottom: 10px; }
.cts { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--pal-nuit); margin-bottom: 8px; border-bottom: 1px solid var(--pal-gris-pale); padding-bottom: 4px; }
.cg2 { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.cl { display: flex; gap: 4px; margin-bottom: 3px; font-size: 10.5px; }
.clb { color: var(--pal-gris-fonce); min-width: 110px; flex-shrink: 0; }
.cv { font-weight: 600; }
.cc { display: inline-block; border: 1px solid var(--pal-noir); padding: 0 3px; font-size: 10px; }
.cmb { font-size: 26px; font-weight: 700; text-align: center; color: var(--pal-nuit); margin: 8px 0 4px; }
.cft { margin-top: 14px; padding-top: 8px; border-top: 1px solid var(--pal-gris-trait); font-size: 8.5px; color: var(--pal-gris-moyen); text-align: center; }
.cerfa-nature-line { margin-top: 8px; font-size: 10px; }
.cerfa-montant-lettres { text-align: center; font-size: 11px; margin-bottom: 10px; font-style: italic; }
.cerfa-avantage { background: var(--pal-lavande-pale); }
.cerfa-avantage-text { font-size: 10px; line-height: 1.7; }
.cerfa-sign-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-top: 12px; }
.cerfa-sign-date { font-size: 10px; font-weight: 700; margin-bottom: 4px; }
.cerfa-sign-president { font-size: 10px; margin-bottom: 4px; }
.cerfa-sign-space { height: 40px; }
.cerfa-sign-label { border-top: 1px solid var(--pal-noir); padding-top: 4px; font-size: 9px; color: var(--pal-gris-moyen); }
.cerfa-warning { background: var(--pal-ambre-50); }
.cerfa-warn-title { font-size: 10px; font-weight: 700; margin-bottom: 4px; }
.cerfa-warn-text { font-size: 9px; line-height: 1.5; color: var(--pal-gris-fonce); }
/* La liste des reçus a quatre colonnes et ses boutons : elle prend la plus
   grande part, le formulaire (cinq champs l'un sous l'autre) la plus petite. */
.cerfa-main-grid { display: grid; grid-template-columns: minmax(18rem, 2fr) 3fr; gap: 1.5rem; align-items: start; }
.cerfa-gen-form { display: flex; flex-direction: column; gap: .85rem; }
.cerfa-readonly { padding: .5rem 0; font-size: .88rem; }

/* ═══════════════════════════════════════════════════
   RAPPORT AG — tresorerie/rapport_ag.php
   ═══════════════════════════════════════════════════ */

.ag-zone { margin: 0 auto; }
.ag-header-actions { display: flex; gap: .5rem; align-items: center; }
.ag-year-select {
    padding: .35rem .6rem; border: 1px solid var(--color-border);
    border-radius: var(--radius); font-size: .85rem; background: var(--color-surface);
}
.ag-header-block { text-align: center; margin-bottom: 2rem; padding-bottom: 1.5rem; border-bottom: 3px solid var(--color-primary); }
.ag-asso-name { font-size: 1.5rem; font-weight: 700; color: var(--color-primary); margin-bottom: .25rem; }
.ag-asso-sub { font-size: .85rem; color: var(--pal-or); margin-bottom: .6rem; }
.ag-report-title { font-size: 1.15rem; font-weight: 700; margin-bottom: .25rem; }
.ag-report-sub { font-size: .85rem; color: var(--color-muted); }

/* Résumé exécutif */
.ag-exec-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; margin-bottom: 1.75rem; }
.ag-exec-card { border-radius: var(--radius-lg); padding: 1.25rem; text-align: center; }
.ag-exec-card--recettes { background: var(--color-success-lt); border: 1px solid var(--color-success-border); }
.ag-exec-card--depenses { background: var(--color-danger-lt); border: 1px solid var(--color-danger-border); }
.ag-exec-card--resultat { border-radius: var(--radius-lg); padding: 1.25rem; text-align: center; }
.ag-exec-label { font-size: .8rem; margin-bottom: .5rem; font-weight: 600; }
.ag-exec-label--white { color: var(--pal-blanc-a70); }
.ag-exec-value { font-size: 1.5rem; font-weight: 800; }
.ag-exec-value--white { color: var(--pal-blanc); }
.ag-exec-n1 { font-size: .75rem; color: var(--color-muted); margin-top: .3rem; }
.ag-exec-n1--white { color: var(--pal-blanc-a80); }

[data-theme="dark"] .ag-exec-card--recettes { background: var(--pal-vert-500-a08); border-color: var(--pal-vert-500-a20); }
[data-theme="dark"] .ag-exec-card--depenses { background: var(--pal-rouge-500-a08); border-color: var(--pal-rouge-500-a20); }

/* Répartition banque / caisse */
.ag-split-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin-bottom: 1.75rem; }
.ag-split-card { border-radius: var(--radius-lg); overflow: hidden; }
.ag-split-card--banque { border: 1.5px solid var(--pal-bleu-200); }
.ag-split-card--caisse { border: 1.5px solid var(--color-warning-border); }
[data-theme="dark"] .ag-split-card--banque { border-color: var(--pal-bleu-500-a30); }
[data-theme="dark"] .ag-split-card--caisse { border-color: var(--pal-or-a30); }
.ag-split-body { padding: .9rem; display: grid; grid-template-columns: 1fr 1fr; gap: .5rem; text-align: center; }
.ag-split-label { font-size: .65rem; margin-bottom: .2rem; }
.ag-split-value { font-weight: 700; }

/* Section headers (colored bars) */
.ag-section-head {
    color: var(--pal-blanc); padding: .55rem 1rem;
    font-size: .85rem; font-weight: 700;
}
.ag-section-head--banque { background: var(--pal-bleu-800); }
.ag-section-head--caisse { background: var(--pal-or-brun); }
.ag-section-head--cotis { background: var(--pal-violet-800); }
.ag-section-head--recettes { background: var(--color-success); color: var(--color-on-accent); }
.ag-section-head--depenses { background: var(--color-danger); color: var(--color-on-accent); }
.ag-section-head--mensuel { background: var(--pal-bleu-marine); }
.ag-section-head--projets { background: var(--pal-gris-700); }

/* Section cards */
.ag-section-card {
    border: 1.5px solid var(--color-border);
    border-radius: var(--radius-lg); overflow: hidden;
    margin-bottom: 1.5rem;
}
.ag-section-card--mb-lg { margin-bottom: 1.75rem; }

/* Cotisations grid */
.ag-cotis-grid { padding: 1.25rem; display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; text-align: center; }
.ag-cotis-label { font-size: .8rem; color: var(--color-muted); margin-bottom: .3rem; }
.ag-cotis-value { font-size: 1.4rem; font-weight: 700; }
.ag-cotis-value--sm { font-size: 1.1rem; }

/* Detail tables (recettes/dépenses) */
.ag-detail-body { padding: .9rem 1rem; }
.ag-detail-thead {
    display: flex; padding: .25rem 0 .5rem;
    font-size: .8rem; color: var(--color-muted);
    border-bottom: 1px solid var(--color-border);
}
.ag-detail-row {
    display: flex; align-items: center; gap: .5rem;
    padding: .5rem 0; border-bottom: 1px solid var(--color-border);
}
.ag-col-cat { flex: 1; font-size: .83rem; }
.ag-col-montant { width: 100px; text-align: right; font-weight: 600; font-size: .83rem; }
.ag-col-n1 { width: 90px; text-align: right; font-size: .78rem; color: var(--color-muted); }
.ag-col-evol { width: 55px; text-align: right; }
.ag-detail-mixte { font-size: .7rem; color: var(--color-muted); }
.ag-mini-bar { width: 44px; height: 4px; background: var(--color-border); border-radius: 2px; overflow: hidden; flex-shrink: 0; }
.ag-mini-bar-spacer { width: 44px; }
.ag-detail-total { display: flex; padding-top: .6rem; font-weight: 700; font-size: .85rem; }
.ag-detail-total--success { border-top: 2px solid var(--color-success); }
.ag-detail-total--danger { border-top: 2px solid var(--color-danger); }

/* Évolution mensuelle */
.ag-mensuel-body { padding: 1.25rem 1rem 1rem; }
.ag-chart-grid { display: grid; grid-template-columns: repeat(12, 1fr); gap: 3px; align-items: end; height: 110px; margin-bottom: .4rem; }
.ag-chart-col { display: flex; flex-direction: column; align-items: center; gap: 0; height: 100%; justify-content: flex-end; }
.ag-chart-bars { display: flex; gap: 1px; align-items: flex-end; height: 100%; }
.ag-chart-labels { display: grid; grid-template-columns: repeat(12, 1fr); gap: 3px; text-align: center; }
.ag-chart-month { font-size: .62rem; color: var(--color-muted); font-weight: 600; }
.ag-chart-legend { display: flex; gap: 1rem; justify-content: center; margin-top: .75rem; font-size: .75rem; color: var(--color-muted); }
.ag-legend-dot {
    display: inline-block; width: 10px; height: 10px;
    border-radius: 2px; margin-right: 4px; vertical-align: middle; opacity: .8;
}
.ag-legend-dot--success { background: var(--color-success); }
.ag-legend-dot--danger { background: var(--color-danger); }

/* Projets */
.ag-projets-body { padding: .75rem 1rem; }
.ag-projet-row { padding: .6rem 0; border-bottom: 1px solid var(--color-border); display: flex; align-items: center; gap: .75rem; }
.ag-projet-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }
.ag-projet-name { flex: 1; font-size: .85rem; font-weight: 500; }
.ag-projet-entree { font-size: .8rem; color: var(--color-success); }
.ag-projet-sortie { font-size: .8rem; color: var(--color-danger); }
.ag-projet-solde { font-size: .8rem; font-weight: 600; width: 90px; text-align: right; }
.ag-projet-budget { width: 70px; }
.ag-projet-budget-label { font-size: .65rem; color: var(--color-muted); margin-bottom: 2px; }
.ag-projet-bar-bg { height: 4px; background: var(--color-border); border-radius: 2px; overflow: hidden; }
/*  Barres et teintes du rapport : seule la longueur (calculée) reste en
    style="…" dans la page. */
.ag-exec-card--resultat.ag-exec-card--positif { background: var(--pal-bleu-petrole); }
.ag-exec-card--resultat.ag-exec-card--negatif { background: var(--pal-brique-fonce); }
.ag-cotis-value.ag-cotis-value--bon    { color: var(--color-success); }
.ag-cotis-value.ag-cotis-value--moyen  { color: var(--pal-ambre-500); }
.ag-cotis-value.ag-cotis-value--faible { color: var(--color-danger); }
.ag-barre { height: 100%; border-radius: 2px; }
.ag-barre--ok        { background: var(--color-success); }
.ag-barre--attention { background: var(--pal-ambre-500); }
.ag-barre--danger    { background: var(--color-danger); }
.ag-chart-barre { width: 10px; min-height: 2px; border-radius: 2px 2px 0 0; opacity: .8; }
.ag-chart-barre--e { background: var(--color-success); }
.ag-chart-barre--s { background: var(--color-danger); }
.ag-chart-barre--nulle { min-height: 0; }

/* Footer */
.ag-footer {
    display: flex; justify-content: space-between;
    font-size: .72rem; color: var(--color-muted);
    border-top: 1.5px solid var(--color-border);
    padding-top: .75rem; flex-wrap: wrap; gap: .5rem;
}

@media (max-width: 768px) {
    .ag-exec-grid { grid-template-columns: 1fr; }
    .ag-cotis-grid { grid-template-columns: repeat(2, 1fr); }
    .ag-split-grid { grid-template-columns: 1fr; }
    .ag-zone { font-size: .85rem; }
}

/* ═══════════════════════════════════════════════════
   OPÉRATIONS — Composants spécifiques
   ═══════════════════════════════════════════════════ */

/* Bandeau opération bancaire */
.ops-bank-notice {
    padding: .6rem 1.25rem; background: var(--color-info-lt);
    border-bottom: 1px solid var(--color-border);
    font-size: .78rem; color: var(--color-info);
    display: flex; align-items: center; gap: 6px;
}

/* Boutons formulaire */
.ops-form-btns { display: flex; gap: .75rem; margin-top: 1rem; flex-wrap: wrap; }

/* Ligne formulaire */
.form-row {
    display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: .75rem; margin-bottom: .25rem;
}
@media (max-width: 768px) {
    .form-row { grid-template-columns: 1fr; }
}

/* Filtres */
.ops-filtres select, .ops-filtres input {
    font-family: var(--font);
}

@media (max-width: 768px) {
    .ops-filtres { flex-direction: column; align-items: stretch; }
}

/* Bouton coupures */

/* Justificatif dropzone */
.justif-dropzone {
    border: 2px dashed var(--color-border-strong);
    border-radius: var(--radius);
    padding: 1.25rem; text-align: center;
    transition: all .15s; cursor: pointer;
}
.justif-dropzone:hover { border-color: var(--color-primary); background: var(--color-primary-lt); }
.justif-drop-content { display: flex; flex-direction: column; align-items: center; gap: 6px; font-size: .85rem; color: var(--color-muted); }
.justif-spinner {
    width: 16px; height: 16px; border: 2px solid var(--color-border);
    border-top-color: var(--color-primary); border-radius: 50%;
    animation: spin .6s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* Badge transfert */
.badge-transfert { font-size: .75rem; color: var(--color-info); font-weight: 500; }

/* ═══════════════════════════════════════════════════
   COLLECTES — Composants spécifiques
   ═══════════════════════════════════════════════════ */

/* Sections formulaire (espèces, CB, compteurs) */
.col-form-section {
    background: var(--color-surface-alt); border-radius: var(--radius);
    padding: 1rem; margin-bottom: 1.25rem; border: 1px solid var(--color-border);
}
.col-form-section-title { font-weight: 600; font-size: .85rem; margin-bottom: .75rem; }
.col-form-section-header {
    display: flex; align-items: center; justify-content: space-between; margin-bottom: .75rem;
}

/* Total banner — bien visible */
.col-total-banner {
    background: var(--color-primary-fond); color: var(--color-on-fond); border-radius: var(--radius-lg);
    padding: 1.25rem; margin-bottom: 1.25rem; text-align: center;
    box-shadow: var(--shadow-md);
}
.col-total-label { font-size: .82rem; opacity: .85; margin-bottom: 6px; font-weight: 500; }
.col-total-value { font-size: 2rem; font-weight: 800; letter-spacing: -.02em; }

/* Submit grid */
.col-form-submit { display: grid; grid-template-columns: 1fr 1fr; gap: .75rem; margin-top: .5rem; }
.col-form-submit .btn { text-align: center; }

/* Tiers compact */
.col-tiers-check { margin-bottom: 1.25rem; }
.col-tiers-label-compact {
    display: flex; align-items: center; gap: 8px; cursor: pointer;
    font-size: .88rem; font-weight: 500; color: var(--color-text);
    padding: 8px 12px; border-radius: var(--radius);
    border: 1px solid var(--color-border); background: var(--color-surface-alt);
    transition: all .15s;
    -webkit-tap-highlight-color: transparent;
}
.col-tiers-label-compact:hover { border-color: var(--color-primary); }
.col-tiers-label-compact input[type="checkbox"] {
    width: 16px; height: 16px; accent-color: var(--color-primary); flex-shrink: 0;
}
.col-tiers-label-compact input:checked ~ span { color: var(--color-primary-dk); font-weight: 600; }

/* Espacement entre les form-group dans le formulaire collecte */
.col-form-section .form-group { margin-bottom: .85rem; }
.col-form-section .form-group:last-child { margin-bottom: 0; }

/* Label optionnel inline */
.form-group label small { display: inline; }

/* ═══════════════════════════════════════════════════════════════
   ADHÉRENTS — tresorerie/adherents.php
   ═══════════════════════════════════════════════════════════════ */
.adh-form-card    { max-width: 700px; margin-bottom: 1.5rem; }
.adh-input-cp     { max-width: 100px; }
.adh-checkbox-ecole { margin-top: .5rem; }
.adh-check-label  { display: flex; align-items: center; gap: 8px; cursor: pointer; font-weight: 500; }
.adh-form-actions { margin-top: 1.25rem; }
.adh-hr           { margin: 1.5rem 0; border: none; border-top: 1px solid var(--color-border); }

.adh-pagination-wrap { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: .5rem; }
.adh-pagination-top  { margin-bottom: .75rem; }
.pagination-info     { font-size: .75rem; color: var(--color-muted); }

.adh-row-inactive td { opacity: .55; }
/* soulignement : règle commune des noms */
.adh-contact-line   { font-size: .78rem; }

.badge-ecole { font-size: .65rem; background: var(--pal-ciel-100); color: var(--pal-ciel-700); border-radius: 3px; padding: 1px 4px; margin-left: 4px; vertical-align: middle; }
[data-theme="dark"] .badge-ecole { background: var(--color-info-soft); color: var(--color-info-text); }
.btn-success { background: var(--color-success-lt); color: var(--color-success); border-color: var(--color-success-border); }
.btn-success:hover { background: var(--color-success-border); }
[data-theme="dark"] .btn-success { background: var(--color-success-soft); color: var(--color-success-text); border-color: var(--color-success-border); }
[data-theme="dark"] .btn-success:hover { background: var(--color-success-border); }
.modal-overlay { display: none; position: fixed; inset: 0; background: var(--pal-noir-a45); z-index: 9999; align-items: center; justify-content: center; padding: 16px; }
.modal-overlay.open { display: flex; }
.modal-box { background: var(--color-surface); border-radius: var(--radius-xl); max-width: 580px; width: 100%; max-height: 90vh; overflow-y: auto; box-shadow: 0 24px 60px var(--pal-noir-a25); }
/* Tailles d'une fenêtre : --sm pour un formulaire court (une question,
   un montant). Les autres variantes portent un comportement à elles
   (plein écran sur téléphone : --prog, --repartition ; --fiche). */
.modal-box--sm { max-width: 500px; }
[data-theme="dark"] .modal-box { box-shadow: 0 20px 60px var(--pal-noir-a60); }
.modal-header { display: flex; justify-content: space-between; align-items: center; gap: 12px; padding: 18px 24px; border-bottom: 1px solid var(--color-border); }
.modal-header-title { font-family: var(--font-title); font-size: 1.15rem; font-weight: 600; }
.modal-close { background: none; border: none; font-size: 1.2rem; cursor: pointer; color: var(--color-muted); padding: 4px 8px; }
.modal-close:hover { color: var(--color-text); }
.modal-body { padding: 20px 24px; }
/*  Refonte B2·3 : sur téléphone une fenêtre monte du bas, comme les menus
    (coins du haut arrondis, toute la largeur). Les fenêtres déjà en plein
    écran gardent leur règle, écrite plus bas. */
@media (max-width: 768px) {
    html body .modal-overlay { align-items: flex-end; padding: 0; }   /* une copie de la règle de base est écrite plus bas */
    .modal-box, .modal-paiement-box { max-width: 100%; max-height: 92dvh; border-radius: var(--radius-xl) var(--radius-xl) 0 0; }
    .modal-header { padding: 16px 18px; }
    .modal-body { padding: 16px 18px max(16px, env(safe-area-inset-bottom, 0px)); }
}

.modal-box--fiche { max-width: 720px; }

/* ── Fiche résumée d'une famille (ecole/resume_famille.php), posée par-dessus
      la page : ce qu'on vient lire en touchant un nom, sans quitter l'écran. */
.modal-box--resume-famille { max-width: 560px; }
.resume-fam-annee { margin: 0 0 .6rem; font-size: .85rem; }
/* Une rubrique = titre à gauche, contenu à droite ; toutes pareilles. */
.resume-fam-rubriques { margin-bottom: .5rem; }
.resume-fam-rubrique { display: grid; grid-template-columns: 8.5rem minmax(0, 1fr); gap: .25rem .75rem;
                       align-items: baseline; padding: .7rem 0; border-bottom: 1px solid var(--color-border); }
.resume-fam-rubrique:first-child { padding-top: 0; } .resume-fam-rubrique:last-child { border-bottom: 0; }
.resume-fam-label { font-size: .8rem; font-weight: 600;
                    color: var(--color-muted); }
.resume-fam-ligne { display: flex; flex-wrap: wrap; align-items: center; gap: .25rem .6rem; }
.resume-fam-ligne + .resume-fam-ligne { margin-top: .4rem; }
.resume-fam-ligne--espace { justify-content: space-between; }
.resume-fam-nom { font-weight: 600; }
.resume-fam-actions { flex-wrap: wrap; }
@media (max-width: 768px) {
    .resume-fam-rubrique { grid-template-columns: 1fr; }
}
.adh-fiche-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0; margin-bottom: 1rem; font-size: .85rem; }
.adh-fiche-field { display: flex; flex-direction: column; padding: .5rem .75rem; border-bottom: 1px solid var(--color-border); }
.adh-fiche-field:nth-last-child(-n+2) { border-bottom: none; }
.adh-fiche-label { font-size: .8rem; font-weight: 600; color: var(--color-muted); margin-bottom: .15rem; }
.adh-fiche-cotis { border-top: 1px solid var(--color-border); padding-top: .75rem; margin-top: .5rem; }
.adh-fiche-cotis-title { font-weight: 600; font-size: .85rem; margin-bottom: .5rem; }
.adh-fiche-cotis-list  { max-height: 260px; overflow-y: auto; overflow-x: auto; }
.adh-fiche-cotis-table { width: 100%; border-collapse: collapse; font-size: .82rem; }
.adh-fiche-cotis-table th { font-size: .8rem; color: var(--color-muted); font-weight: 600; padding: .4rem .5rem; border-bottom: 2px solid var(--color-border); text-align: left; }
.adh-fiche-cotis-table td { padding: .55rem .5rem; border-bottom: 1px solid var(--color-border-strong); vertical-align: top; }
.adh-fiche-cotis-table tbody tr:last-child td { border-bottom: none; }
.adh-fiche-cotis-table tbody tr:hover { background: var(--color-surface-alt); }
.adh-fiche-cotis-table tfoot td { border-top: 2px solid var(--color-border); border-bottom: none; padding-top: .5rem; }
.adh-fiche-cotis-desc { font-size: .78rem; color: var(--color-muted); max-width: 320px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.adh-fiche-cotis-rejet { background: var(--color-danger-lt); }
.adh-fiche-nocotis { border-top: 1px solid var(--color-border); padding-top: .75rem; font-size: .82rem; color: var(--color-muted); }
.adh-fiche-actions { margin-top: 1rem; }
.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
@media (max-width: 768px) {
    .form-row         { grid-template-columns: 1fr; }
    .adh-fiche-grid   { grid-template-columns: 1fr; }
    .adh-fiche-field  { padding: .4rem .5rem; }
    .modal-box--fiche { max-width: 100%; margin: 8px; border-radius: 10px; }
    .adh-fiche-cotis-table th,
    .adh-fiche-cotis-table td { padding: .35rem .3rem; font-size: .75rem; }
    .adh-fiche-cotis-desc { max-width: 140px; font-size: .72rem; }
    .adh-fiche-cotis-list { max-height: 220px; }
}

/* ═══════════════════════════════════════════════════════════════
   BILAN — tresorerie/bilan.php
   ═══════════════════════════════════════════════════════════════ */

/* Sélecteur année */
.bil-years { display: flex; gap: .5rem; flex-wrap: wrap; align-items: center; }
.bil-sep   { width: 1px; height: 20px; background: var(--color-border); margin: 0 4px; }

/* Blocs de section dashboard */
.bil-block { margin-bottom: 1.5rem; }
.bil-block-label {
    font-size: .9rem; font-weight: 600;
    color: var(--color-muted); margin-bottom: .75rem;
}
.bil-note { font-size: .75rem; color: var(--color-muted); margin-top: .5rem; }

/* Couleurs sémantiques */
.bil-val--success { color: var(--color-success); }
.bil-val--danger  { color: var(--color-danger); }
.bil-val--muted   { color: var(--color-muted); }
.bil-val--primary { color: var(--color-primary); }

/* Card générique bilan */
.bil-card { margin-bottom: 1.5rem; }
.bil-card-body--flush { padding: 0; }
.bil-card-total { font-weight: 700; }

/* Cotisations */
.bil-cotis-grid {
    display: grid; grid-template-columns: repeat(3, 1fr);
    gap: 1rem; text-align: center;
}
.bil-cotis-item { min-width: 0; }
.bil-cotis-val   { font-size: 1.4rem; font-weight: 700; }
.bil-cotis-label { font-size: .75rem; color: var(--color-muted); }

/* Catégories (produits/charges) */
.bil-cat-table { margin: 0; }
.bil-cat-name  { font-size: .85rem; font-weight: 500; }
.bil-cat-name--italic { font-style: italic; }
.bil-cat-right { text-align: right; white-space: nowrap; }
.bil-cat-val   { font-weight: 600; font-size: .88rem; }
.bil-cat-pct   { display: block; }
.bil-cat-row--amort { background: var(--color-surface-alt); }

/* Barres de progression */
.bil-bar {
    height: 4px; background: var(--color-border);
    border-radius: 2px; margin-top: 4px; overflow: hidden;
}
.bil-bar-fill {
    height: 100%; border-radius: 2px; width: 0;
    transition: width .6s cubic-bezier(.22,.61,.36,1);
}
.bil-bar-fill--success { background: var(--color-success); }
.bil-bar-fill--danger  { background: var(--color-danger); }

/* Flux transitoires (collapsible) */
.bil-transit { margin-top: 1.5rem; }
.bil-transit-head { cursor: pointer; }
.bil-transit-title { font-size: .9rem; color: var(--color-muted); }
.bil-transit-title small { font-weight: 400; }
.bil-transit-arrow { font-size: .8rem; color: var(--color-muted); transition: transform .15s; }
.bil-transit-body  { display: none; padding: 0; }
.bil-transit-body--open { display: block; }
.bil-transit-table { margin: 0; font-size: .83rem; }
.bil-transit-note  { padding: .75rem 1rem; font-size: .75rem; color: var(--color-muted); margin: 0; }
.bil-ta-r { text-align: right; }

/* ─────────────────────────────────────────────────────────
   BILAN COMPTABLE — Document officiel
   ─────────────────────────────────────────────────────── */
.bcp-doc { margin: 0 auto; font-size: .85rem; }

/* En-tête */
.bcp-head {
    text-align: center; padding-bottom: 16px;
    border-bottom: 2px solid var(--color-border); margin-bottom: 20px;
}
.bcp-head-title    { font-size: 1.3rem; font-weight: 800; color: var(--color-primary); }
.bcp-head-mentions { font-size: .72rem; color: var(--color-muted); margin-top: 2px; }
.bcp-head-subtitle { margin-top: 12px; font-size: .95rem; font-weight: 600; }
.bcp-head-legal    { font-size: .72rem; color: var(--color-muted); margin-top: 4px; }

/* Sections */
.bcp-section { margin-bottom: 24px; }
.bcp-section-title {
    color: var(--pal-blanc); padding: 8px 16px;
    border-radius: 8px 8px 0 0;
    font-weight: 700; font-size: .88rem;
}
.bcp-section-title--primary { background: var(--color-primary-fond); color: var(--color-on-fond); }
.bcp-section-title--dark    { background: var(--pal-gris-700); }
.bcp-section-title--green   { background: var(--pal-emeraude-800); }

/* Grille 2 colonnes (produits/charges et actif/passif) */
.bcp-2col {
    display: grid; grid-template-columns: 1fr 1fr;
    border: 1.5px solid var(--color-border);
    border-top: none;
    border-radius: 0 0 8px 8px;
    overflow: hidden;
}
.bcp-col              { min-width: 0; }
.bcp-col--divider     { border-right: 1px solid var(--color-border); }
.bcp-col-head {
    background: var(--color-surface-alt);
    padding: 8px 14px;
    font-weight: 700; font-size: .78rem;
    border-bottom: 1px solid var(--color-border);
    display: flex; justify-content: space-between;
}
.bcp-col-head--4 {
    display: grid; grid-template-columns: 1fr 110px 110px 110px;
    gap: 0; padding: 6px 14px; font-size: .72rem;
}
.bcp-col-head--4 span:nth-child(2),
.bcp-col-head--4 span:nth-child(3),
.bcp-col-head--4 span:nth-child(4) {
    text-align: right;
    padding-left: 8px;
    border-left: 1px solid var(--color-border);
}

/* Libellé latéral Actif/Passif */
.bcp-side-label {
    color: var(--pal-blanc); padding: 6px 14px;
    font-weight: 700; font-size: .85rem;
}
.bcp-side-label--actif  { background: var(--pal-bleu-700); }
.bcp-side-label--passif { background: var(--pal-violet-600); }

/* Sous-en-têtes de groupe */
.bcp-subhead {
    padding: 6px 14px; font-weight: 600; font-size: .78rem;
    border-bottom: 1px solid var(--pal-noir-a04);
}
.bcp-subhead--primary { color: var(--color-primary); background: var(--pal-bleu-700-a03); }
.bcp-subhead--success { color: var(--color-success); background: var(--pal-vert-600-a03); }
.bcp-subhead--muted   { color: var(--color-muted);   background: var(--pal-noir-a02); }
[data-theme="dark"] .bcp-subhead--primary { background: var(--pal-bleu-400-a06); }
[data-theme="dark"] .bcp-subhead--success { background: var(--pal-vert-500-a06); }
[data-theme="dark"] .bcp-subhead--muted   { background: var(--pal-blanc-a02); }

/* Lignes */
.bcp-row {
    display: flex; justify-content: space-between;
    padding: 6px 14px;
    border-bottom: 1px solid var(--pal-noir-a04);
    font-size: .82rem;
}
.bcp-row--2 { display: grid; grid-template-columns: 1fr auto; gap: 8px; font-size: .78rem; }
.bcp-row--4 { display: grid; grid-template-columns: 1fr 110px 110px 110px; gap: 0; font-size: .78rem; }
.bcp-row--4 > span:nth-child(2),
.bcp-row--4 > span:nth-child(3),
.bcp-row--4 > span:nth-child(4) {
    text-align: right;
    padding-left: 8px;
    border-left: 1px solid var(--pal-noir-a06);
}
[data-theme="dark"] .bcp-row--4 > span:nth-child(2),
[data-theme="dark"] .bcp-row--4 > span:nth-child(3),
[data-theme="dark"] .bcp-row--4 > span:nth-child(4) {
    border-left-color: var(--pal-blanc-a08);
}
.bcp-row--indent { padding-left: 24px; padding-top: 5px; padding-bottom: 5px; }
.bcp-row--italic { font-style: italic; }
.bcp-row--total {
    background: var(--color-surface-alt);
    font-weight: 700; font-size: .85rem;
    padding: 8px 14px;
}
.bcp-row--subtotal {
    background: var(--color-surface-alt);
    font-weight: 600; font-size: .78rem;
    padding: 6px 14px;
    border-bottom: 1px solid var(--color-border);
}
.bcp-row--grandtotal {
    background: var(--color-surface-alt);
    font-weight: 800; font-size: .88rem;
    padding: 10px 14px;
}
.bcp-row-val { font-weight: 600; }
.bcp-ra      { text-align: right; }
[data-theme="dark"] .bcp-row     { border-bottom-color: var(--pal-blanc-a05); }
[data-theme="dark"] .bcp-subhead { border-bottom-color: var(--pal-blanc-a05); }

/* Résultat (grand encadré) */
.bcp-resultat {
    display: flex; align-items: center; justify-content: space-between;
    padding: 14px 20px; border-radius: 8px; margin-top: 8px;
    border: 2px solid;
}
.bcp-resultat--positif { background: var(--pal-vert-600-a06); border-color: var(--color-success); }
.bcp-resultat--negatif { background: var(--pal-rouge-600-a06); border-color: var(--color-danger); }
.bcp-resultat-label {
    font-size: .8rem;
    color: var(--color-muted); font-weight: 600;
}
.bcp-resultat-sub { font-size: .75rem; color: var(--color-muted); margin-top: 2px; }
.bcp-resultat-val { font-size: 1.4rem; font-weight: 800; }

/* Annexe */
.bcp-annex {
    border: 1.5px solid var(--color-border);
    border-top: none;
    border-radius: 0 0 8px 8px;
    padding: 20px;
}
.bcp-annex-block { margin-bottom: 16px; }
.bcp-annex-title { font-size: .85rem; font-weight: 700; margin-bottom: 6px; }
.bcp-annex-text  { font-size: .8rem; color: var(--color-muted); line-height: 1.7; margin: 0; }
.bcp-annex-box   { border-radius: 8px; padding: 14px 16px; margin-bottom: 16px; }
.bcp-annex-box--success { background: var(--pal-vert-600-a05); }
.bcp-annex-box--purple  { background: var(--pal-violet-600-a04); }
.bcp-val--purple { color: var(--pal-violet-600); }

.bcp-annex-table { width: 100%; font-size: .78rem; border-collapse: collapse; }
.bcp-annex-table thead tr { background: var(--color-surface-alt); }
.bcp-annex-table--purple thead tr { background: var(--pal-violet-600-a08); }
.bcp-annex-table--purple thead th { color: var(--pal-violet-600); }
.bcp-annex-table th, .bcp-annex-table td {
    padding: 8px 12px;
    border-bottom: 1px solid var(--pal-noir-a06);
}
[data-theme="dark"] .bcp-annex-table th,
[data-theme="dark"] .bcp-annex-table td { border-bottom-color: var(--pal-blanc-a06); }
.bcp-annex-table--purple td { border-bottom-color: var(--pal-violet-600-a08); }
.bcp-th-l { text-align: left; }
.bcp-th-r, .bcp-td-r { text-align: right; }

/* Pied de document */
.bcp-footer {
    border-top: 1.5px solid var(--color-border);
    padding-top: 16px;
    display: flex; justify-content: space-between; align-items: flex-end;
    flex-wrap: wrap; gap: 1rem;
}
.bcp-footer-info { font-size: .75rem; color: var(--color-muted); }
.bcp-footer-sign { text-align: right; }
.bcp-footer-sign-label { font-size: .75rem; color: var(--color-muted); margin-bottom: 40px; }
.bcp-footer-sign-box   {
    border-top: 1px solid var(--color-text);
    padding-top: 4px;
    font-size: .75rem; color: var(--color-muted);
    width: 180px;
}

/* ── Mobile ── */
@media (max-width: 768px) {
    .bil-cotis-grid  { gap: .5rem; }
    .bil-cotis-val   { font-size: 1.15rem; }
    .bil-cotis-label { font-size: .68rem; }

    .dashboard-grid  { grid-template-columns: 1fr; gap: 1rem; }

    .bil-cat-name    { font-size: .8rem; }
    .bil-cat-val     { font-size: .82rem; }
    .bil-cat-pct     { font-size: .7rem; }

    .bcp-doc          { font-size: .82rem; }
    .bcp-2col         { grid-template-columns: 1fr; }
    .bcp-col--divider { border-right: none; border-bottom: 1px solid var(--color-border); }
    .bcp-col-head--4  { grid-template-columns: 1fr 80px 80px; font-size: .68rem; }
    .bcp-row--4       { grid-template-columns: 1fr 80px 80px; font-size: .72rem; }
    .bcp-row--4 > :nth-child(3) { display: none; }
    .bcp-col-head--4 > :nth-child(3) { display: none; }

    .bcp-resultat     { flex-direction: column; align-items: flex-start; gap: 8px; }
    .bcp-resultat-val { font-size: 1.2rem; }

    .bcp-annex-table  { font-size: .7rem; }
    .bcp-annex-table th,
    .bcp-annex-table td  { padding: 6px 8px; }
    /* Cinq colonnes de montants ne tiennent pas en 375 px : le tableau
       défile au doigt dans son bloc plutôt que d'être rogné. */
    .bcp-annex-block, .bcp-annex-box { overflow-x: auto; }

    .bcp-footer       { flex-direction: column; align-items: flex-start; }
    .bcp-footer-sign  { text-align: left; }
}
@media (max-width: 768px) {
    .bil-cotis-grid { grid-template-columns: repeat(3, 1fr); }
    .bil-cotis-val  { font-size: 1rem; }
}

/* ═══════════════════════════════════════════════════════════════
   COTISATIONS — tresorerie/cotisations.php
   ═══════════════════════════════════════════════════════════════ */

/* Légende */
.cot-legende-nb { font-weight: 700; color: var(--color-text); }
.cot-legende {
    display: flex; gap: 1rem; font-size: .78rem;
    color: var(--color-muted); margin-bottom: .75rem;
    flex-wrap: wrap; align-items: center;
}

/* Tableau — wrapper dédié */
.cot-table-wrapper {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow);
    overflow-x: auto;
    overflow-y: visible;
}
.cot-table th   { font-size: .75rem; font-weight: 600; white-space: nowrap; padding: .5rem .4rem; }

.cot-th-membre  { min-width: 170px; position: sticky; left: 0; background: var(--color-surface); z-index: 2; }
.cot-th-euromois { text-align: center; width: 55px; }
.cot-th-total   { text-align: right; width: 80px; padding-right: .75rem; }
.cot-th-statut  { text-align: center; width: 50px; }
.cot-th-action  { text-align: center; width: 50px; }

.cot-td-membre  { position: sticky; left: 0; background: var(--color-surface); z-index: 1; }
.cot-membre-link { color: inherit; font-weight: 500; }   /* soulignement : règle commune des noms */
.cot-membre-sub  { font-size: .7rem; color: var(--color-muted); }
.cot-td-euromois { text-align: center; font-size: .8rem; color: var(--color-muted); }
.cot-cell        { text-align: center; padding: .2rem .1rem; }
/* La règle commune `.table td` (plus précise) posait 12 px de chaque côté :
   douze colonnes de 46 px pour une pastille de 22, et le tableau sortait
   de l'écran à 1280 px (« Payer » coupé). Sur ordinateur seulement : le
   téléphone a ses propres réglages plus bas. */
@media (min-width: 769px) {
    .cot-table td.cot-cell { padding: .35rem .15rem; }
    /*  La colonne Membre était la seule sans largeur : sur un grand écran
        elle prenait tout le blanc du tableau (capture de l'utilisateur).
        Elle se resserre sur le nom le plus long (width: 1% + nowrap), et
        ce sont les douze mois qui se partagent la place qui reste. */
    .cot-th-membre, .cot-td-membre { width: 1%; white-space: nowrap; }
    .cot-th-membre { min-width: 0; }
    .cot-th-euromois, .cot-th-total, .cot-th-statut, .cot-th-action { width: 1%; }
    .cot-mois-th { width: auto; }
    /*  Un nom très long ne rouvre pas la colonne : coupé par « … », entier
        au survol (title) et dans l'historique qu'il ouvre. */
    .cot-membre-link, .cot-membre-sub {
        display: block; max-width: 13rem;
        overflow: hidden; text-overflow: ellipsis;
    }
}
.cot-cell--futur { opacity: .3; }
.cot-cell--avant { opacity: .25; }
.cot-dot-futur   { color: var(--color-border); }
.cot-td-total    { text-align: right; font-size: .82rem; font-weight: 600; padding-right: .75rem; white-space: nowrap; }
.cot-td-total--ok   { color: var(--color-success); }
.cot-td-total--zero { color: var(--color-muted); }
/* Sous le total : l'argent qui passe d'une année à l'autre. */
/* Trop-perçu sous le total : orange tant qu'il attend une décision (le
   trésorier doit le voir sans ouvrir l'historique), gris une fois décidé. */
.cot-trop-percu-btn {
    display: inline-block; margin-left: .25rem; padding: 0 .4rem;
    font: inherit; font-size: .7rem; line-height: 1.5;
    color: var(--color-text); background: var(--color-surface);
    border: 1px solid var(--color-border); border-radius: 6px; cursor: pointer;
}
.cot-trop-percu-btn:hover { border-color: var(--color-primary); }
.cot-tp-intro { margin: 0 0 1rem; font-size: .9rem; }
/* Remise de chèques (Chèques) : la date en tête, les mois de chaque chèque
   lisibles dans la liste — c'est avec eux que la grille des cotisations
   se remplira. */
.chq-remise-tete { padding-bottom: 0; }
.chq-remise-aide { font-size: .85rem; margin: 0 0 .75rem; }
.chq-remise-date { max-width: 14rem; margin-bottom: .5rem; }
.chq-remise-sansmois { color: var(--color-warning); }
.cot-cheques-multi { font-size: .82rem; margin: .5rem 0 0; }
.chq-a-deposer { color: var(--color-warning); font-weight: 600; }

/* ── Fenêtre « Ajouter des chèques » ──
   Une ligne = un bloc à deux rangées (qui / combien / quoi, puis mois /
   quand / outils) : un tableau à neuf colonnes ne tiendrait ni dans une
   fenêtre ni sur un téléphone. Plein écran sur téléphone, comme la
   répartition des élèves. */
.chq-saisie-box { max-width: 860px; }
.chq-saisie-reception { max-width: 12rem; }
.chq-saisie-lignes { display: flex; flex-direction: column; gap: .6rem; }
.chq-saisie-ligne {
    border: 1px solid var(--color-border); border-left: 3px solid var(--color-primary);
    border-radius: 8px; padding: .6rem .75rem; background: var(--color-surface);
}
.chq-saisie-rangee { display: flex; flex-wrap: wrap; gap: .5rem .75rem; align-items: flex-end; }
.chq-saisie-rangee + .chq-saisie-rangee { margin-top: .5rem; }
.chq-saisie-champ { display: flex; flex-direction: column; gap: .15rem; margin: 0; font-weight: normal; }
.chq-saisie-lib { font-size: .72rem; font-weight: 600; color: var(--color-muted); }
.chq-saisie-champ input, .chq-saisie-champ select {
    font: inherit; font-size: .85rem; padding: .35rem .5rem; min-height: 2rem;
    border: 1px solid var(--color-border); border-radius: 6px;
    background: var(--color-surface); color: var(--color-text); width: 100%;
}
.chq-saisie-champ--adh { flex: 2 1 12rem; }
.chq-saisie-champ--em  { flex: 2 1 10rem; }
.chq-saisie-champ--mt  { flex: 0 1 7rem; }
.chq-saisie-champ--cat { flex: 1 1 8rem; }
.chq-saisie-champ--date { flex: 0 1 10rem; }
.chq-saisie-champ--note { flex: 3 1 12rem; }
.chq-saisie-champ--mt input { text-align: right; }
.chq-saisie-mois { display: flex; gap: .5rem; flex: 2 1 14rem; }
.chq-saisie-mois .chq-saisie-champ { flex: 1 1 0; min-width: 0; }
.chq-saisie-outils { display: flex; flex-wrap: wrap; gap: .35rem; align-items: center; margin-left: auto; }
.chq-saisie-rep { display: inline-flex; gap: .3rem; align-items: center; font-size: .8rem; }
.chq-saisie-rep input { width: 3.5rem; font: inherit; padding: .2rem .35rem; border: 1px solid var(--color-border); border-radius: 6px; }
.chq-saisie-plus { margin-top: .45rem; }
.chq-saisie-plus > summary { cursor: pointer; font-size: .78rem; color: var(--color-muted); }
.chq-saisie-plus[open] > summary { margin-bottom: .4rem; }
.chq-saisie-ajout { margin: .75rem 0 0; }
.chq-saisie-pied { align-items: center; }
.chq-saisie-total { margin-right: auto; font-weight: 600; font-size: .9rem; }
@media (max-width: 768px) {
    #modalSaisie { padding: 0; }
    #modalSaisie .chq-saisie-box { max-width: none; height: 100%; max-height: none; border-radius: 0; }
    .chq-saisie-champ--adh, .chq-saisie-champ--em { flex-basis: 100%; }
    .chq-saisie-outils { margin-left: 0; }
}
/* Import : une « REM CHQ » sans remise enregistrée. Écrite en clair sous le
   libellé (pas de bulle) : c'est ce qui explique pourquoi la ligne est
   décochée. */
/* Opérations : une remise de chèques sur une ligne, ses chèques dessous. */
/* Les chèques d'une remise dépliée se lisent comme ses lignes : fond
   teinté et libellé en retrait (la première cellule est la case à cocher). */
.ops-table tr.ops-remise-membre > td { background: var(--color-info-lt); }
.ops-table tr.ops-remise-membre .ops-ligne-haut,
.ops-table tr.ops-remise-membre .ops-ligne-meta { padding-left: 1rem; }
.ops-remise .ops-desc { font-weight: 600; }
.ops-remise-attente { font-size: .75rem; color: var(--color-warning); }
.rp-td-libelle-remise { min-width: 16rem; max-width: 24rem; color: var(--color-muted); }
.rp-remise-absente { margin-top: .3rem; font-size: .78rem; color: var(--color-warning); white-space: normal; line-height: 1.35; }
#modal-trop-percu .checkbox-label + .checkbox-label { margin-top: .6rem; }
#modal-trop-percu .checkbox-label input[type="radio"] { margin-top: .25rem; flex-shrink: 0; }
.cot-td-statut   { text-align: center; font-size: 1rem; }
.cot-statut { display: inline-flex; vertical-align: middle; }
.cot-statut--retard { color: var(--color-danger); }
.cot-statut--regler { color: var(--color-warning-vif); }
.cot-td-action   { text-align: center; }

/* Badges mois */
.badge-ecole-sm { font-size: .63rem; background: var(--color-info-soft); color: var(--color-info-text); padding: 1px 4px; border-radius: 3px; margin-left: 3px; }
.cot-membre-sub .badge-ecole-sm { margin-left: 0; }
[data-theme="dark"] .badge-ecole-sm { background: var(--color-info-soft); color: var(--color-info-text); }
.cot-mois-th    { background: var(--color-surface-alt); transition: background .15s; text-align: center; width: 36px; font-size: .72rem; cursor: pointer; user-select: none; }
.cot-mois-th:hover { background: var(--pal-or-a12); }
.cot-mois--courant { background: var(--pal-or-a20) !important; color: var(--color-gold-text); font-weight: 700; }
.cot-mois-th.filtre-impaye { background: var(--color-danger-soft) !important; color: var(--color-danger); }
.cot-mois-th.filtre-paye   { background: var(--color-success-soft) !important; color: var(--color-success); }
[data-theme="dark"] .cot-mois--courant     { color: var(--color-warning-text); }
[data-theme="dark"] .cot-mois-th.filtre-impaye { background: var(--color-danger-soft) !important; }
[data-theme="dark"] .cot-mois-th.filtre-paye   { background: var(--color-success-soft) !important; }

.cot-badge      { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; border-radius: 4px; font-size: .75rem; font-weight: 700; }
.cot-badge--ok  { background: var(--color-success-mid); color: var(--color-success-text); }
/* Un mois dû et impayé se VOIT (il était un point à 10 % d'opacité : l'école
   affichait « 2 mois », la trésorerie ne montrait rien). */
.cot-badge--non { background: var(--color-danger-lt); color: var(--color-danger); }
/* Chèque en main, pas encore encaissé : ni vert (pas payé), ni vide (on a
   de quoi le payer). Teinte « attente », comme les chèques en attente. */
.cot-badge--cheque { background: var(--color-warning-lt); font-size: .75rem; }
/* Le ⓘ du total vire à l'orange quand un trop-perçu attend une décision. */
.cot-aide--alerte .aide-btn,
.cot-aide--alerte .aide-btn:hover,
.cot-aide--alerte .aide-btn[aria-expanded="true"] { background: var(--color-warning); border-color: var(--color-warning); color: var(--color-on-accent); }
.cot-td-total .aide-txt { text-align: left; font-weight: normal; }
.cot-td-total .aide-btn { margin-left: 0; margin-right: .35rem; }   /* le ⓘ précède le montant */
[data-theme="dark"] .cot-badge--ok { background: var(--color-success-soft); color: var(--color-success-text); }

.cot-row--solde   > td:first-child { border-left: 3px solid var(--color-success); }
/* Les statuts réels de la page (impaye / partiel ci-dessus n'existent plus). */
.cot-row--regulariser > td:first-child { border-left: 3px solid var(--color-danger); }
.cot-row--a_regler    > td:first-child { border-left: 3px solid var(--color-warning); }
.cot-row.cot-hidden { visibility: collapse; }

/* Bouton payer */
.btn-payer {
    background: none; border: 1.5px solid var(--color-border); border-radius: 6px;
    padding: 2px 6px; cursor: pointer; font-size: .85rem; transition: all .15s;
    color: var(--color-text);   /* sans elle : noir du navigateur, illisible en sombre */
    /* Icône et mot côte à côte : dans la colonne serrée, le mot passait
       sous l'icône. */
    display: inline-flex; align-items: center; gap: 4px; white-space: nowrap;
}
.btn-payer:hover { border-color: var(--color-primary); background: var(--pal-bleu-700-a04); }

/* Modal paiement */
.modal-paiement-box { background: var(--color-surface); border-radius: 12px; max-width: 520px; width: 100%; max-height: 90vh; overflow-y: auto; box-shadow: var(--shadow-lg); }
[data-theme="dark"] .modal-paiement-box { box-shadow: 0 20px 60px var(--pal-noir-a60); }
.modal-paiement-header { display: flex; justify-content: space-between; align-items: center; padding: 14px 20px; border-bottom: 1px solid var(--color-border); }
.modal-paiement-title  { margin: 0; font-size: 1rem; font-weight: 600; }
.modal-paiement-close  { background: none; border: none; font-size: 1.2rem; cursor: pointer; color: var(--color-muted); padding: 4px 8px; }
.modal-paiement-close:hover { color: var(--color-text); }
.modal-paiement-body  { padding: 16px 20px 0; }
.modal-paiement-footer { padding: 14px 20px 20px; }
/*  Fenêtre « Historique » des cotisations : plus large, pied à boutons. */
.modal-paiement-box.modal-paiement-box--large { max-width: 600px; }
.modal-paiement-body.modal-paiement-body--plein { padding-bottom: 16px; }
.modal-paiement-footer.modal-paiement-footer--boutons {
    border-top: 1px solid var(--color-border); display: flex; flex-wrap: wrap; gap: .5rem;
}
/*  Saisie d'une opération : les mois de cotisation dans leur encadré. */
.op-suggestion .op-sugg-note { display: block; margin-top: .3rem; }
.op-suggestion .cot-periode-row { margin-top: .5rem; }
.op-suggestion .cot-periode-resume { margin-top: .4rem; }
/*  Import du relevé : ligne grise sous une valeur, teinte d'une ligne de
    l'aperçu selon son sens. */
.rp-sous { font-size: .78rem; }
.table tr.rp-ligne { border-left: 3px solid var(--color-success); }
.table tr.rp-ligne--entree    { background: var(--color-success-lt); }
.table tr.rp-ligne--sortie    { background: var(--color-danger-lt); }
.table tr.rp-ligne--transfert { background: var(--color-info-lt); border-left-color: var(--color-info); }

.cot-periode-wrap  { margin-bottom: 14px; }
.cot-periode-label { font-size: .8rem; font-weight: 700; color: var(--color-muted); display: block; margin-bottom: 6px; }
.cot-periode-row   { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-bottom: 8px; }
.cot-periode-sep   { font-size: .82rem; color: var(--color-muted); }
.cot-periode-select {
    padding: 6px 8px; border: 1.5px solid var(--color-border); border-radius: var(--radius);
    font-size: .82rem; background: var(--color-surface); color: var(--color-text);
    font-family: var(--font);
}
.cot-periode-resume   { font-size: .82rem; font-weight: 600; color: var(--color-primary); margin-top: 4px; }
.cot-periode-decoupe  { font-size: .75rem; color: var(--color-muted); margin-top: 4px; }
.p-form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: .75rem; margin-bottom: .5rem; }

/* Réassignation mois */
.reassign-op-form { padding: .75rem 0; border-bottom: 1px solid var(--color-border); }
.reassign-op-form:last-of-type { border-bottom: none; }
.reassign-op-header { font-size: .85rem; margin-bottom: .5rem; }
.reassign-mois-grid { display: grid; grid-template-columns: repeat(6, 1fr); gap: .35rem; }
.reassign-mois-label {
    font-size: .78rem; display: flex; align-items: center; gap: .25rem;
    padding: .25rem .35rem; border-radius: var(--radius); cursor: pointer;
    border: 1px solid var(--color-border); background: var(--color-surface);
    transition: all .1s;
}
.reassign-mois-label:hover { border-color: var(--color-primary); background: var(--color-accent-lt); }
.reassign-mois-label input[type="checkbox"] { margin: 0; }

/* Historique paiements */
.histo-info {
    display: flex; gap: 1.5rem; flex-wrap: wrap;
    padding: .6rem .75rem; background: var(--color-surface-alt);
    border-radius: var(--radius); font-size: .85rem;
    margin-bottom: .5rem;
}

@media (max-width: 768px) {.reassign-mois-grid { grid-template-columns: repeat(4, 1fr); } }
@media (max-width: 768px) {
    .p-form-grid    { grid-template-columns: 1fr; }
}

/* ── Mobile ── */
@media (max-width: 768px) {
    

    .cot-table-wrapper {
        margin-left:  -12px;
        margin-right: -12px;
        /* Largeur laissée au navigateur : « 100vw » compte la barre de
           défilement et dépassait de la page. */
        width: auto;
        max-width: none;
        box-sizing: border-box;
        border-radius: 0;
        border-left: none;
        border-right: none;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
    }
    .cot-table-wrapper::after {
        content: '← Faites défiler le tableau →';
        display: block;
        text-align: center;
        font-size: .68rem;
        color: var(--color-muted);
        padding: .35rem 0 .45rem;
        border-top: 1px solid var(--color-border);
        background: var(--color-surface-alt);
    }

    .cot-table { font-size: .72rem; min-width: 680px; }
    .cot-table th, .cot-table td { padding: .3rem .22rem; }
    .cot-th-membre   { min-width: 110px; font-size: .72rem; padding-left: 12px; }
    .cot-td-membre   { padding-left: 12px; }
    .cot-th-euromois { display: none; }
    .cot-td-euromois { display: none; }
    .cot-mois-th     { width: 26px; font-size: .63rem; padding: .3rem .1rem; }
    .cot-th-total    { width: 55px; font-size: .65rem; }
    .cot-th-statut   { width: 32px; }
    .cot-th-action   { width: 32px; }
    .cot-membre-link { font-size: .76rem; }
    .cot-membre-sub  { font-size: .61rem; }
    /*  Toujours deux lignes par adhérent : le nom, puis « 📚 Mensuelle ·
        Prélèvement », chacun sur UNE ligne coupée par « … ». Un nom qui
        passait à la ligne donnait à chaque adhérent sa hauteur. Le nom
        entier se lit en le touchant (historique). */
    .cot-membre-link, .cot-membre-sub {
        display: block; max-width: 9.5rem;
        white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    }
    .cot-td-total    { font-size: .7rem; padding-right: .35rem; }
    .cot-badge       { width: 17px; height: 17px; font-size: .62rem; border-radius: 3px; }
    .btn-payer       { font-size: .7rem; padding: 1px 3px; }

    .cot-th-membre, .cot-td-membre {
        position: sticky; left: 0;
        background: var(--color-surface);
        box-shadow: 2px 0 6px var(--pal-noir-a08);
        z-index: 2;
    }
    .cot-th-membre { z-index: 3; background: var(--color-surface-alt); }
    [data-theme="dark"] .cot-th-membre,
    [data-theme="dark"] .cot-td-membre {
        box-shadow: 2px 0 6px var(--pal-noir-a25);
    }

    .cot-row:hover .cot-td-membre { background: var(--color-surface-alt); }
}

/* ═══════════════════════════════════════════════════════════════
   VERSEMENT — tresorerie/versement.php
   ═══════════════════════════════════════════════════════════════ */

/* Layout */
.vers-raccourcis {
    display: flex; flex-wrap: wrap;
    gap: 8px; margin-bottom: 1rem;
}
.vers-layout {
    display: grid; grid-template-columns: 380px 1fr;
    gap: 1.5rem; align-items: start;
}
.vers-col-form { min-width: 0; }

/* Card soldes */
.vers-soldes-card { margin-bottom: 1rem; }
.vers-card-title  { font-size: .9rem; }
.vers-soldes-body { padding: .75rem; }
.vers-solde-row {
    display: flex; justify-content: space-between; align-items: center;
    padding: 6px 0; border-bottom: 1px solid var(--color-border);
    font-size: .85rem;
}
.vers-solde-row:last-child { border-bottom: none; }
.vers-solde-val { font-weight: 700; }
.vers-val--primary { color: var(--color-primary); }
.vers-val--danger  { color: var(--color-danger); }

/* Source read-only (trésorier) */
.vers-source-readonly {
    padding: .6rem .75rem;
    background: var(--color-surface-alt);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    font-size: .88rem; font-weight: 500;
}

/* Solde message */
.vers-solde-msg {
    color: var(--color-muted); font-size: .75rem;
}
.vers-solde-msg.is-danger  { color: var(--color-danger); }
.vers-solde-msg.is-success { color: var(--color-success); }

/* Récap */
.vers-recap {
    display: none;
    background: var(--color-surface-alt);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: .75rem 1rem;
    margin-bottom: 1rem;
    font-size: .85rem;
}
.vers-recap.is-visible { display: block; }
.vers-recap-txt { text-align: center; font-weight: 600; }

/* Raccourcis */
.btn-raccourci {
    padding: 8px 14px; border: 1.5px solid var(--color-border); border-radius: var(--radius);
    background: var(--color-surface); cursor: pointer; font-size: .78rem; font-weight: 600;
    color: var(--color-text); transition: all .15s; white-space: nowrap;
}
.btn-raccourci:hover {
    border-color: var(--color-primary); background: var(--pal-bleu-700-a04);
    transform: translateY(-1px);
}
.btn-raccourci.active {
    border-color: var(--color-primary); background: var(--pal-bleu-700-a08);
    color: var(--color-primary);
}

/* Historique */
.vers-hist-body  { padding: 0; }

.vers-verrou { font-size: .75rem; color: var(--color-muted); white-space: nowrap; }

/* ── Mobile ── */
@media (max-width: 768px) {
    .vers-layout      { grid-template-columns: 1fr; gap: 1rem; }
    .vers-raccourcis  { gap: 6px; }
    .btn-raccourci    { flex: 1 1 auto; font-size: .72rem; padding: 7px 10px; }

}

/* ═══════════════════════════════════════════════════════════════
   CHÈQUES — tresorerie/cheques.php
   ═══════════════════════════════════════════════════════════════ */
/* Les cases de tête utilisent .treso-soldes, qui gère déjà l'auto-fit et
   les 2 colonnes sur téléphone. Une surcharge à 3 colonnes fixes existait
   ici : elle s'appliquait aussi en mobile, où elle écrasait la règle
   responsive et serrait les cases sur toute la largeur. */

/* Filtres */

/* Desktop / Mobile switch */

/* Tableau desktop */
.chq-th-date     { width: 90px; }
.chq-emetteur   { font-weight: 500; font-size: .88rem; }
.chq-meta-line  { display: block; font-size: .72rem; }

/* Cartes mobile */

.chq-pagination { margin-top: 1rem; }

/* Boutons action (utilisés dans cheques) */
.btn-warning { background: var(--color-warning-soft); color: var(--color-warning-text); border-color: var(--color-warning-border); }
.btn-warning:hover { background: var(--color-warning-border); }
[data-theme="dark"] .btn-warning { background: var(--color-warning-soft); color: var(--color-warning-text); border-color: var(--color-warning-border); }
[data-theme="dark"] .btn-warning:hover { background: var(--pal-ambre-sombre-survol); }

/* Suggestion split */
.chq-suggestion {
    border: 1.5px solid var(--pal-cyan-300); border-radius: var(--radius);
    padding: 10px 12px; background: var(--pal-cyan-50); font-size: .82rem;
}
.chq-suggestion__title { font-weight: 600; color: var(--pal-cyan-700); margin-bottom: 8px; }
.chq-suggestion__select {
    padding: 2px 6px; border: 1px solid var(--color-border);
    border-radius: 4px; font-size: .78rem;
    background: var(--color-surface); color: var(--color-text);
}
[data-theme="dark"] .chq-suggestion { background: var(--color-info-soft); border-color: var(--pal-cyan-nuit); }
[data-theme="dark"] .chq-suggestion__title { color: var(--color-info-text); }

/* Modal chèques — variante 460 */

/* Checkbox carrée primary-accent */
.chq-grp-check {
    width: 18px; height: 18px; flex-shrink: 0;
    accent-color: var(--color-primary);
}

/* Modals — compléments utilisés dans cheques */
.chq-modal-list { overflow-y: auto; flex: 1; }
.chq-modal-row {
    display: flex; align-items: center; gap: .75rem;
    padding: .65rem 1.25rem; cursor: pointer;
    border-bottom: 1px solid var(--color-border);
    transition: background .1s;
}
.chq-modal-row:hover { background: var(--color-surface-alt); }
.chq-modal-row-info { flex: 1; min-width: 0; }
.chq-modal-row-nom  { font-weight: 500; font-size: .88rem; }
.chq-modal-row-montant { font-weight: 700; color: var(--color-success); white-space: nowrap; }
.chq-modal-footer { padding: .75rem 1.25rem; border-top: 1px solid var(--color-border); background: var(--color-surface-alt); flex-shrink: 0; }
.chq-modal-total { font-size: .88rem; color: var(--color-muted); margin-bottom: .75rem; }

.chq-enc-info      { margin-bottom: 1rem; }
.chq-enc-emetteur  { font-weight: 600; font-size: .9rem; }
.chq-enc-montant   { font-size: 1.1rem; font-weight: 700; color: var(--color-success); margin-top: 4px; }
.chq-enc-cat-badge { font-size: .72rem; margin-top: 4px; display: inline-block; }
.chq-enc-decoupage { display: none; margin-bottom: 1rem; }
/*  « ➕ Ajouter à la remise du … » : la case, sa phrase et son ⓘ sur une ligne. */
.chq-enc-joindre { display: flex; align-items: center; gap: .35rem; flex-wrap: wrap; }
.chq-enc-joindre .checkbox-label { margin: 0; }
.chq-enc-radio     { display: flex; align-items: center; gap: 8px; cursor: pointer; margin-bottom: 6px; font-size: .85rem; }
.chq-enc-mois-config { display: none; margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--pal-emeraude-200); }
.chq-enc-mois-row  { display: flex; gap: 8px; align-items: center; font-size: .8rem; flex-wrap: wrap; }
/* Sous les mois couverts : « 12 mois : Oct 2026 → Sep 2027 · 12 × 20 € ». */
.chq-enc-periode-resume { font-size: .78rem; font-weight: 600; color: var(--color-primary); margin: 6px 0 8px; }

/* Récap dépôt groupé — span total */

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

/* ═══════════════════════════════════════════════════════════════
   COLLECTES — tresorerie/collectes.php
   ═══════════════════════════════════════════════════════════════ */

/* ── Formulaire collecte ── */
.col-form-card { }
.col-input-nofix { min-width: 0; }

.form-row-collecte { grid-template-columns: 140px 1fr; }
@media (max-width: 768px) {
    .form-row-collecte { grid-template-columns: 1fr !important; }
}

.col-form-group-mb-sm { margin-bottom: .75rem; }
.col-form-group-mb-0  { margin-bottom: 0; }
.col-grid-coupures-wrap { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 12px; }
.col-section-title-lbl { font-size: .8rem; font-weight: 700; color: var(--color-text); }
.col-coupures-list { display: flex; flex-direction: column; gap: 5px; }

/* Zone compte / tiers (avec initial state PHP via d-none) */
.col-compte-dest-zone { margin-bottom: 1rem; }

.col-btn-add-compteur { padding: .2rem .6rem; font-size: .75rem; }
.col-compteurs-list   { display: flex; flex-direction: column; gap: .5rem; }
.col-form-hint        { display: block; margin-top: .5rem; font-size: .72rem; }
.col-btn-cancel       { text-align: center; }

/* ── Bandeau info mode tiers ── */
.col-tiers-banner {
    background: linear-gradient(135deg, var(--pal-or-50), var(--pal-or-100));
    border: 1px solid var(--pal-or-clair);
    border-radius: var(--radius);
    padding: .75rem 1rem;
    font-size: .85rem;
    color: var(--pal-or-texte);
    margin-bottom: 1.25rem;
    line-height: 1.4;
}
[data-theme="dark"] .col-tiers-banner {
    background: linear-gradient(135deg, var(--pal-or-nuit), var(--pal-or-nuit-2));
    color: var(--color-gold-text);
    border-color: var(--color-gold-border);
}

/*  Un bloc repliable par mois. Le bandeau prend la teinte des bandeaux
    de jour des Opérations ; replié, il dit le nombre de collectes et
    le total du mois. */
.col-mois > summary.col-mois-entete { background: var(--color-surface-alt); padding: .7rem 1.1rem; }
.col-mois-entete .pliable-titre { font-size: .95rem; }
.col-mois-resume { font-size: .85rem; color: var(--color-muted); white-space: nowrap; }
.col-mois-resume strong { color: var(--color-text); font-weight: 700; }
.col-mois-groupe > .col-mois + .col-mois { margin-top: .6rem; }
/*  Sur téléphone, les cartes d'un mois se posent dans le bloc, avec
    un peu d'air autour. */
@media (max-width: 768px) {
    /*  La règle commune masque, repliée sur téléphone, tout ce qui n'est
        pas le titre d'un bloc pliable (elle vise des boutons). Le résumé
        du mois est au contraire ce qu'on vient lire replié. Le « details »
        du sélecteur le rend plus précis : il l'emporte où qu'elle soit
        écrite. */
    details.col-mois:not([open]) .pliable-entete > .col-mois-resume { display: inline; }
}

.col-badge-tiers {
    font-size: .62rem; background: var(--color-gold-soft); color: var(--color-warning-text);
    border-radius: 3px; padding: 1px 6px; margin-left: 4px;
    font-weight: 700; letter-spacing: .3px; vertical-align: middle;
}
[data-theme="dark"] .col-badge-tiers { background: var(--color-gold-soft); color: var(--color-gold-text); }

/* ── Checkbox tiers ── */
.col-tiers-check { margin-bottom: 1.25rem; }

/* ── Fix date input mobile ── */
/* L'apparence neutralisée et le plafond de largeur valent partout : un
   champ date d'iOS déborde sinon de sa case. La pleine largeur, elle, ne
   vaut que sur téléphone — posée hors media query, elle étirait aussi sur
   ordinateur tout champ date hors d'un .form-group (trois écrans la
   contournaient chez eux). Mesuré sur 17 écrans à 1280 px : seule la
   séance de l'appel d'un cours sans créneau change, et prend sa largeur
   naturelle comme le menu voisin. */
input[type="date"], input[type="time"], input[type="datetime-local"], input[type="month"] {
    max-width: 100%; box-sizing: border-box;
    -webkit-appearance: none; appearance: none;
    /* Chrome écrit un champ date en police à chasse fixe (feuille du
       navigateur) : hors d'un .form-group, qui pose la police du site, la
       date de l'Appel s'affichait en « machine à écrire » à côté d'un menu
       en DM Sans. */
    font-family: var(--font);
    /* ⚠ Safari sur iPhone (signalé par l'utilisateur, capture « Nouvelle
       réunion » ; le mode téléphone de Chrome ne le montre PAS) :
       - un champ date VIDE n'y affiche rien et, l'apparence native retirée,
         n'a plus de hauteur : la case s'écrasait en un trait → hauteur
         minimale, celle des autres champs (ligne + rembourrage + bordure) ;
       - un champ date / heure y garde une largeur minimale qui passe outre
         width: 100% : l'heure débordait de sa colonne → min-width: 0. */
    min-width: 0;
    min-height: calc(1.3em + 1rem + 2px);
    line-height: 1.3;
}
/*  Safari centre la valeur, et c'est ce bloc qui donne sa hauteur à un
    champ vide : calé à gauche comme les autres champs, avec une hauteur. */
input::-webkit-date-and-time-value { text-align: left; min-height: 1.3em; }
@media (max-width: 768px) {
    input[type="date"], input[type="time"], input[type="datetime-local"], input[type="month"] { width: 100%; }
}

/* ── Compteurs ── */
.compteur-row { display: flex; align-items: center; gap: 8px; }
.compteur-num {
    width: 24px; height: 24px; border-radius: 50%;
    background: var(--color-primary-fond); color: var(--color-on-fond);
    font-size: .7rem; font-weight: 700;
    display: flex; align-items: center; justify-content: center;
    flex-shrink: 0;
}
.compteur-champs { flex: 1; min-width: 0; display: flex; align-items: center; gap: .35rem; }
.compteur-liste { flex-shrink: 0; white-space: nowrap; }
.compteur-row select,
.compteur-row input[type="text"] {
    flex: 1; padding: .45rem .7rem; border: 1px solid var(--color-border);
    border-radius: var(--radius); font-size: .88rem;
    background: var(--color-surface); color: var(--color-text);
    min-width: 0;
}
.compteur-row select:focus, .compteur-row input:focus { outline: none; border-color: var(--color-primary); box-shadow: 0 0 0 3px var(--pal-bleu-petrole-a12); }
.compteur-remove {
    width: 28px; height: 28px; border-radius: 6px; border: 1px solid var(--color-border);
    background: var(--color-surface); color: var(--color-danger);
    font-size: .85rem; cursor: pointer;
    display: flex; align-items: center; justify-content: center;
    flex-shrink: 0; transition: background .15s, border-color .15s;
    font-family: inherit; -webkit-tap-highlight-color: transparent;
}
.compteur-remove:hover { background: var(--color-danger-soft); border-color: var(--color-danger); }
[data-theme="dark"] .compteur-remove:hover { background: var(--color-danger-soft); }

/* ── Coupures collecte ── */
.col-section-toggle {
    display: flex; align-items: center; gap: 8px; cursor: pointer;
    padding: 8px 10px; border-radius: var(--radius); user-select: none;
    transition: background .15s;
}
.col-section-toggle:hover { background: var(--pal-noir-a03); }
.col-chevron {
    font-size: .65rem; transition: transform .2s; color: var(--color-muted);
}
.col-section-toggle.open .col-chevron { transform: rotate(90deg); }
.col-section-badge {
    margin-left: auto; font-size: .72rem; font-weight: 700;
    color: var(--color-muted); background: var(--color-surface);
    padding: 2px 8px; border-radius: 10px; border: 1px solid var(--color-border);
    min-width: 55px; text-align: center;
}
.col-section-badge.has-value {
    color: var(--color-success); border-color: var(--color-success);
    background: var(--pal-vert-600-a06);
}
.col-section-body { padding: 8px 0 4px 0; display: none; }
.col-section-body.is-open { display: block; }

.col-coupure {
    display: flex; align-items: center; gap: 4px; padding: 5px 8px;
    background: var(--color-surface); border: 1.5px solid var(--color-border);
    border-radius: 8px; transition: border-color .2s, box-shadow .2s;
}
.col-coupure:hover { border-color: var(--color-primary); }
.col-coupure.has-value {
    border-color: var(--color-primary);
    background: var(--pal-bleu-700-a03);
    box-shadow: 0 0 0 2px var(--pal-bleu-700-a06);
}
.col-coupure .col-val {
    font-size: .75rem; font-weight: 700; color: var(--color-text); min-width: 36px;
}
.col-coupure .col-btn {
    width: 28px; height: 28px; border: 1.5px solid var(--color-border);
    border-radius: 6px; background: var(--color-surface); cursor: pointer;
    font-size: 16px; display: flex; align-items: center; justify-content: center;
    color: var(--color-text); transition: background .15s, border-color .15s;
    user-select: none; -webkit-tap-highlight-color: transparent; flex-shrink: 0;
}
.col-coupure .col-btn:active {
    background: var(--pal-bleu-700-a08); border-color: var(--color-primary);
}
.col-coupure input[type="number"] {
    width: 40px; padding: 3px 2px; border: 1.5px solid var(--color-border);
    border-radius: 6px; font-size: .85rem; font-weight: 600; text-align: center;
    outline: none; background: var(--color-surface); color: var(--color-text);
    transition: border-color .2s; -moz-appearance: textfield;
}
.col-coupure input[type="number"]::-webkit-inner-spin-button,
.col-coupure input[type="number"]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.col-coupure input:focus { border-color: var(--color-primary); }
.col-coupure .col-sous {
    font-size: .68rem; color: var(--color-muted); margin-left: auto;
    min-width: 44px; text-align: right;
}
.col-coupure .col-sous b { transition: color .2s; }
.col-coupure.has-value .col-sous b { color: var(--color-success); font-size: .72rem; }

@media (max-width: 768px) {
    .col-grid-coupures { grid-template-columns: 1fr !important; gap: 8px !important; }
}

/* ═══════════════════════════════════════════════════════════════
   PARAMÈTRES — tresorerie/parametres.php
   ═══════════════════════════════════════════════════════════════ */

/* Card info (identité légale — redirige vers admin) */
.tps-info-card {
    display: flex;
    align-items: center;
    gap: 1rem;
    flex-wrap: wrap;
    padding: 1rem 1.25rem;
}
.tps-info-card .tps-info-icon { font-size: 1.5rem; }
.tps-info-card .tps-info-content { flex: 1; min-width: 200px; }
.tps-info-card .tps-info-title { font-weight: 600; margin-bottom: .2rem; }
.tps-info-card .tps-info-desc  { font-size: .82rem; color: var(--color-muted); line-height: 1.45; }

/* Logo */
.tps-logo-row {
    display: flex;
    align-items: center;
    gap: 1.25rem;
    flex-wrap: wrap;
    margin-bottom: 1rem;
}
.tps-logo-preview,
.tps-logo-placeholder {
    width: 80px; height: 80px;
    border-radius: var(--radius-lg);
    flex-shrink: 0;
}
.tps-logo-preview {
    border: 2px solid var(--color-border);
    object-fit: cover;
}
.tps-logo-placeholder {
    border: 2px dashed var(--color-border);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--color-muted);
    font-size: 1.5rem;
}
.tps-logo-form {
    flex: 1;
    min-width: 200px;
    max-width: 100%;
    display: flex;
    flex-direction: column;
    gap: .5rem;
    overflow: hidden;
}
.tps-logo-form input[type="file"] { font-size: .82rem; width: 100%; max-width: 100%; }
.tps-logo-hint {
    font-size: .75rem;
    color: var(--color-muted);
    margin: 0;
    line-height: 1.45;
}
.tps-logo-actions { display: flex; gap: .5rem; margin-top: .25rem; flex-wrap: wrap; }
.tps-logo-new-preview {
    display: none;
    width: 80px; height: 80px;
    border-radius: var(--radius-lg);
    border: 2px solid var(--color-success);
    object-fit: cover;
    margin-top: .5rem;
}

/* --- Paramètres trésorerie : bloc double logo --- */
.tps-logo-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1.5rem;
}

@media (max-width: 768px) {
    .tps-logo-grid { grid-template-columns: 1fr; }
}

@media (max-width: 768px) {
    /* Côte à côte, l'image et le formulaire se serrent trop pour laisser
       de la place au champ fichier natif (texte tronqué) : on les empile. */
    .tps-logo-row { flex-direction: column; align-items: stretch; }
    .tps-logo-form { min-width: 0; }
}

.tps-logo-block {
    padding: 1rem;
    background: var(--color-subtle);
    border-radius: 8px;
    border: 1px solid var(--color-border);
}

.tps-logo-title {
    margin: 0 0 .75rem;
    font-size: 1rem;
    font-weight: 600;
    display: flex;
    align-items: center;
    gap: .5rem;
}

.tps-logo-badge {
    font-size: .7rem;
    padding: .15rem .5rem;
    border-radius: 10px;
    background: var(--color-warning-soft);
    color: var(--color-warning-text);
    font-weight: 500;
}

/* Descriptions génériques */
.tps-desc {
    font-size: .82rem;
    color: var(--color-muted);
    margin-bottom: 1rem;
    line-height: 1.5;
}
.tps-hint {
    font-size: .78rem;
    color: var(--color-muted);
    margin-bottom: .75rem;
    line-height: 1.5;
}

/* Assistant de calcul (encadré bleu info) */
.tps-assist {
    background: var(--color-info-lt);
    border: 1.5px solid var(--pal-bleu-600-a25);
    border-radius: var(--radius);
    padding: 1rem;
    margin-bottom: 1.25rem;
}
[data-theme="dark"] .tps-assist {
    background: var(--pal-bleu-600-a08);
    border-color: var(--pal-bleu-600-a35);
}
.tps-assist-title {
    font-weight: 600;
    color: var(--color-info);
    margin-bottom: .5rem;
    font-size: .88rem;
}
[data-theme="dark"] .tps-assist-title { color: var(--color-info); }
.tps-assist-desc {
    font-size: .8rem;
    color: var(--color-muted);
    margin-bottom: .75rem;
    line-height: 1.5;
}
.tps-assist-row {
    display: flex;
    gap: .75rem;
    align-items: flex-end;
    flex-wrap: wrap;
}
.tps-assist-field label {
    font-size: .78rem;
    font-weight: 600;
    display: block;
    margin-bottom: .3rem;
}
.tps-assist-field input {
    padding: .5rem .75rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    font-size: .88rem;
    width: 180px;
    background: var(--color-surface);
    color: var(--color-text);
}
.tps-assist-field input:focus {
    outline: none;
    border-color: var(--color-info);
    box-shadow: 0 0 0 3px var(--pal-bleu-600-a10);
}
.tps-assist-result {
    font-size: .85rem;
    color: var(--color-muted);
    line-height: 1.5;
}
.tps-assist-result strong { color: var(--color-text); }

/* Grilles formulaires */
.tps-form-grid-2 {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1rem;
}
.tps-form-actions { margin-top: .75rem; display: flex; gap: .5rem; flex-wrap: wrap; }

/* Transitoires code */
.tps-code {
    font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
    font-size: .78rem;
    padding: .1rem .4rem;
    background: var(--color-surface-alt);
    border-radius: 4px;
    color: var(--color-text);
}

/* Immobilisations */
.tps-immo-form {
    display: none;
    background: var(--color-surface-alt);
    border-radius: var(--radius);
    padding: 1rem;
    margin-bottom: 1rem;
}
.tps-immo-form.is-open { display: block; }
.tps-immo-form-grid {
    display: grid;
    grid-template-columns: 2fr 1fr 1fr 1fr;
    gap: .75rem;
    align-items: end;
}
.tps-immo-form .form-group { margin: 0; }

/* Bouton icône (corbeille) */
/* Supprimer un bien : écrit, discret dans l'en-tête de sa carte,
   rouge au survol seulement — ce n'est pas le geste courant. */
.tps-btn-suppr {
    background: none; border: 1px solid transparent; border-radius: 6px;
    cursor: pointer; font: inherit; font-size: .75rem; white-space: nowrap;
    padding: .15rem .45rem; color: var(--color-muted);
}
.tps-btn-suppr:hover { color: var(--color-danger); border-color: var(--color-danger); }

@media (max-width: 768px) {
    .tps-form-grid-2       { grid-template-columns: 1fr; }
    .tps-immo-form-grid    { grid-template-columns: 1fr; }
    .tps-assist-field input { width: 100%; }
    .tps-assist-field       { flex: 1; min-width: 180px; }

    .tps-info-card { padding: .85rem 1rem; }
    .tps-info-card .tps-info-content { flex-basis: 100%; }
}

/* Utilitaires locaux */
.tps-mb { margin-bottom: 1.5rem; }
.tps-inline-form { display: inline; }

/* ═══════════════════════════════════════════════════════════════
   PROJETS — tresorerie/projets.php
   ═══════════════════════════════════════════════════════════════ */

/* Grille des cartes projets */
.proj-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: 1rem;
    margin-bottom: 1.5rem;
}

/* Carte projet */
.proj-card {
    display: block;
    background: var(--color-surface);
    border: 1.5px solid var(--color-border);
    border-left-width: 4px;
    border-radius: var(--radius);
    padding: 1rem 1rem .75rem;
    text-decoration: none;
    color: var(--color-text);
    transition: box-shadow .15s, transform .15s;
    cursor: pointer;
}
.proj-card:hover {
    box-shadow: var(--shadow-md);
    transform: translateY(-2px);
}
.proj-card.is-active { box-shadow: var(--shadow-md); }
.proj-card__head {
    display: flex;
    align-items: center;
    gap: .5rem;
    margin-bottom: .6rem;
    font-size: .88rem;
}
.proj-card__title { flex: 1; min-width: 0; }

.proj-dot {
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    flex-shrink: 0;
}

.proj-bar {
    height: 6px;
    background: var(--color-border);
    border-radius: 3px;
    overflow: hidden;
    margin-bottom: .3rem;
}
.proj-bar__fill {
    height: 100%;
    border-radius: 3px;
    transition: width .3s;
}
.proj-bar__fill.is-ok     { background: var(--color-success); }
.proj-bar__fill.is-warn   { background: var(--pal-ambre-500); }
.proj-bar__fill.is-danger { background: var(--color-danger); }
.proj-bar { margin: .5rem 0 .2rem; }

/* Le solde d'un projet en gros ; entrées et sorties, nommées, dessous. */
.proj-solde { font-family: var(--font-display, inherit); font-size: 1.25rem; font-weight: 700; line-height: 1.2; }
.proj-solde.is-positive { color: var(--color-success); }
.proj-solde.is-negative { color: var(--color-danger); }
.proj-card .liste-sous { margin-top: .15rem; }

/* En-tête du détail : le titre à gauche, les gestes à droite ; sur
   téléphone, les gestes passent dessous. */
.proj-detail-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .6rem; }
.proj-detail-actions { flex-wrap: nowrap; }
.proj-detail-desc { margin: 0; padding: .75rem 1.25rem 0; color: var(--color-muted); font-size: .88rem; }

/* Fenêtre « Rattacher » : une liste de cases, plus large que les fenêtres courtes. */
.modal-box.proj-rattacher-box { max-width: 720px; }
.proj-rattacher-outils { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem 1rem; margin-bottom: .6rem; }
.proj-rattacher-outils .form-group { flex: 1 1 14rem; min-width: 0; }
.proj-op-choix { display: flex; align-items: center; gap: .6rem; padding: .55rem .75rem;
                 border-bottom: 1px solid var(--color-border); cursor: pointer; }
.proj-op-choix:last-child { border-bottom: none; }
.proj-op-choix input { width: auto; flex: 0 0 auto; }
.proj-op-choix-texte { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.proj-op-choix-desc { overflow-wrap: anywhere; }
.proj-op-choix .liste-montant { white-space: nowrap; }
.proj-op-choix .liste-montant-nb { font-size: .95rem; }

/* Détail projet — card wrapper */
.proj-detail-card { margin-top: 1.5rem; }
.proj-detail-head { border-left: 4px solid var(--color-primary); }
.proj-detail-head h2 {
    display: flex;
    align-items: center;
    gap: .5rem;
    flex-wrap: wrap;
}
.proj-detail-head small {
    font-weight: 400;
    font-size: .8rem;
    color: var(--color-muted);
}

.proj-rattacher-list {
    max-height: 350px;
    overflow-y: auto;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
}

/* Modal projet — champ couleur */
.proj-color-input {
    width: 100%;
    height: 38px;
    padding: 2px;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    cursor: pointer;
    background: var(--color-surface);
}
.proj-form-grid-2 {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1rem;
}

@media (max-width: 768px) {
    .proj-rattacher-list { max-height: 250px; }
    .proj-form-grid-2    { grid-template-columns: 1fr; }
}

/* ═══════════════════════════════════════════════════════════════
   OPÉRATIONS — tresorerie/operations/*.php
   ═══════════════════════════════════════════════════════════════ */

/* Form-row & utilitaires de base */
.btn-xs { padding: .2rem .5rem; font-size: .72rem; border-radius: 4px; }
.badge-transfert {
    background: var(--color-info-soft); color: var(--pal-bleu-700);
    padding: 2px 8px; border-radius: 6px;
    font-size: .72rem; font-weight: 600;
}
[data-theme="dark"] .badge-transfert { background: var(--color-info-soft); color: var(--color-info-text); }
.btn-danger { background: var(--color-danger-lt); color: var(--color-danger); border-color: var(--color-danger-border); }
.btn-danger:hover { background: var(--color-danger-border); }
[data-theme="dark"] .btn-danger { background: var(--color-danger-soft); color: var(--color-danger); border-color: var(--color-danger-border); }
[data-theme="dark"] .btn-danger:hover { background: var(--pal-rouge-sombre-survol); }

/* ── Filtres opérations ── */
.ops-filtres {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    align-items: center;
}
.ops-filtres select,
.ops-filtres input {
    font-size: .88rem;
    padding: .45rem .9rem; min-height: 2.5rem;
    border: 1px solid var(--color-border-strong);
    border-radius: 999px;
    background: var(--color-surface);
    color: var(--color-text);
}

/* ── Tableau opérations ── */
.ops-table-wrap { overflow-x: auto; }
.ops-desc { font-size: .85rem; font-weight: 500; }
.ops-actions { display: flex; gap: 4px; justify-content: center; flex-wrap: wrap; }

/* En-têtes tableau */
.ops-th-montant  { width: 100px; text-align: right; }
.ops-th-justif   { width: 1%; white-space: nowrap; text-align: center; }
.ops-th-actions  { width: 80px; text-align: center; }

/* Cellules */
.ops-td-montant {
    text-align: right; font-weight: 700; white-space: nowrap;
}
.ops-td-justif    { text-align: center; }
.ops-td-actions   { text-align: center; }

/* Couleurs sens entrée/sortie/transfert */
td.ops-amount--entree,
span.ops-amount--entree    { color: var(--color-success) !important; }
td.ops-amount--sortie,
span.ops-amount--sortie    { color: var(--color-danger) !important; }
td.ops-amount--transfert,
span.ops-amount--transfert { color: var(--color-muted) !important; }

.ops-justif-btns {
    display: flex; flex-direction: column; gap: 3px;
    justify-content: center; align-items: center;
}
.ops-justif-ignored {
    display: block;
    font-size: .7rem; color: var(--color-muted); cursor: help; white-space: nowrap;
}
/* Les états de la colonne Justificatif, écrits en petites lettres
   plutôt qu'en pictogrammes seuls. Empilés, ils gardent la colonne
   étroite. */
.ops-justif-btn {
    display: inline-block; white-space: nowrap;
    font: inherit; font-size: .72rem; line-height: 1.3;
    padding: 1px 7px; border-radius: 10px; cursor: pointer;
    color: var(--color-text); background: var(--color-surface);
    border: 1px solid var(--color-border);
}
.ops-justif-btn:hover { border-color: var(--color-primary); color: var(--color-primary); }
.ops-justif-btn--attente { color: var(--color-warning-vif); border-style: dashed; }
.ops-justif-btn--discret { color: var(--color-muted); border-color: transparent; background: none; }
.ops-justif-btn--discret:hover { color: var(--color-text); border-color: var(--color-border); }
/* Téléphone : dans la ligne grise, un lien discret à côté de la catégorie. */
.ops-justif-lien {
    background: none; border: none; padding: 0; cursor: pointer;
    font: inherit; font-size: .72rem; color: var(--color-primary); white-space: nowrap;
}

/* Bouton notes — variantes selon contenu */
.ops-btn-note--has  { color: var(--color-primary); }

/* Éléments visibles uniquement sur mobile.
   .ops-mobile-meta sert encore aux courriers (secretariat/courriers.php,
   courrier_destinataires.php) : les listes d'opérations, elles, ont leur
   propre ligne .ops-ligne-meta, visible aux deux largeurs. */
.ops-mobile-montant { display: none; }

/* ── Page header opérations ── */
.ops-header-btns {
    display: flex;
    gap: .5rem;
    align-items: center;
    flex-wrap: wrap;
}

/* Inputs readonly (banque importée) */
.ops-input-readonly {
    opacity: .6;
    pointer-events: none;
}
.ops-input-readonly--alt {
    opacity: .6;
    background: var(--color-surface-alt);
}
.ops-input-disabled-soft { opacity: .6; }

/* Zones suggestion / cotisation */
.ops-form-mb-sm { margin-bottom: .75rem; }

/* Justificatif zone */
.ops-justif-existing {
    display: flex; align-items: center; gap: .75rem; flex-wrap: wrap;
    padding: .6rem .9rem;
    background: var(--color-surface-alt);
    border-radius: var(--radius);
    border: 1px solid var(--color-border);
}
.ops-justif-link {
    font-size: .85rem; color: var(--color-primary); font-weight: 500;
    background: none; border: none; cursor: pointer;
    text-decoration: underline; font-family: inherit;
}
.ops-justif-icon-lg { font-size: 1.5rem; }
.ops-justif-browse {
    color: var(--color-primary); cursor: pointer;
    font-weight: 600; text-decoration: underline;
}
.ops-justif-progress { font-size: .8rem; margin-top: 6px; }
.ops-justif-progress-row {
    display: flex; align-items: center; gap: 8px;
}
.ops-justif-progress-text { color: var(--color-muted); }
.ops-justif-progress-info {
    font-size: .75rem; color: var(--color-muted); margin-top: 4px;
}

/* Cards filtres / tableau */
.ops-table-body    { padding: 0; }

/* Pagination opérations */
.ops-pag-wrap {
    display: flex; align-items: center; justify-content: space-between;
    flex-wrap: wrap; gap: .5rem;
}
.ops-pag-info { margin: 0; font-size: .75rem; }
.ops-pag-mb   { margin-bottom: .75rem; }
.pagination-noflow { margin: 0; }

/* ══════════════════════════════════════════
   MOBILE — Opérations
   ══════════════════════════════════════════ */
@media (max-width: 768px) {
    .ops-filtres {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: .4rem;
    }
    .ops-filtres select,
    .ops-filtres input {
        width: 100%;
        font-size: .8rem;
    }

    .ops-table-wrap { overflow-x: visible; }
    .ops-table { min-width: 0 !important; }

    .ops-table thead { display: none; }
    .ops-table tbody { display: block; }

    .ops-table tbody tr.ops-row {
        display: block;
        background: var(--color-surface);
        border: 1px solid var(--color-border);
        border-radius: var(--radius);
        padding: .75rem;
        margin-bottom: .6rem;
        box-shadow: 0 1px 3px var(--pal-noir-a04);
    }
    .ops-table tbody tr.ops-row:hover td { background: transparent; }

    .ops-table tbody td {
        display: block;
        padding: .15rem 0;
        border-bottom: none;
        width: 100% !important;
    }
    .ops-table tbody td::before { display: none; }

    .ops-mobile-montant {
        display: inline;
        font-size: 1rem;
        font-weight: 700;
    }

    .ops-desc {
        font-size: .88rem;
        font-weight: 600;
        margin-bottom: .2rem;
    }

    .hide-mobile,
    .ops-desktop-montant {
        display: none !important;
    }

    td[data-label="Actions"] {
        padding-top: .4rem !important;
        margin-top: .3rem;
        border-top: 1px solid var(--color-border);
    }
    .ops-actions {
        justify-content: flex-start;
        gap: 6px;
    }
    .ops-actions .btn-xs {
        padding: .3rem .6rem;
        font-size: .78rem;
    }

    .page-header {
        flex-direction: column;
        align-items: flex-start !important;
        gap: .5rem !important;
    }
    .ops-header-btns {
        width: 100%;
    }
    .ops-header-btns .btn {
        flex: 1;
        text-align: center;
        justify-content: center;
        font-size: .75rem !important;
    }
}

@media (max-width: 400px) {
    .ops-filtres { grid-template-columns: 1fr; }
}

/* ═══════════════════════════════════════════════════
   OPÉRATIONS — haut de page rangé
   Placé après les deux blocs ops-* plus haut (hérités, en partie en
   double) : sélecteurs à deux classes pour l'emporter quel que soit
   l'ordre et le point de rupture.
   ═══════════════════════════════════════════════════ */

.ops-resume { display: flex; flex-direction: column; gap: .4rem; margin-bottom: .75rem; }
/* Carte : montants en colonnes à gauche, nombre et pages à droite. */
.ops-resume-page { color: var(--color-muted); white-space: nowrap; }
.ops-resume-pag { display: inline-flex; align-items: center; gap: .45rem; font-size: .78rem; color: var(--color-muted); }
.ops-resume-pag a, .ops-resume-pag .is-off {
    padding: .2rem .55rem; border: 1px solid var(--color-border); border-radius: var(--radius);
    color: var(--color-text); text-decoration: none; white-space: nowrap;
}
.ops-resume-pag a:hover { border-color: var(--color-primary); }
.ops-resume-pag .is-off { opacity: .4; }
.ops-resume-infos { display: flex; flex-wrap: wrap; gap: .15rem 1.1rem; font-size: .78rem; color: var(--color-muted); padding: 0 .25rem; }
.ops-resume-infos a { color: var(--color-primary); text-decoration: none; }
.ops-resume-infos a:hover { text-decoration: underline; }

/* Actions de ligne : « Modifier » + menu « ⋯ ». Le tableau défile
   horizontalement sur ordinateur (overflow-x: auto), ce qui rogne tout
   ce qui dépasse, y compris le panneau d'un menu ouvert sur les
   dernières lignes : le défilement est levé le temps qu'un menu est
   ouvert, comme pour les cartes. */
.ops-table-wrap:has(.menu-plus-list.open) { overflow: visible; }
.ops-table .ops-th-actions { width: auto; }
.ops-table .ops-td-actions .ops-actions { flex-wrap: nowrap; justify-content: flex-end; align-items: center; }
.ops-td-actions .menu-plus-list .ops-btn-note--has { color: var(--color-primary); }

@media (max-width: 768px) {
    .ops-resume-pag { gap: .3rem; }
    .ops-resume-infos { flex-direction: column; gap: .2rem; }
    .ops-table .ops-td-actions .ops-actions { justify-content: flex-start; }
}

/* Suggestions dynamiques (adhérent, règle auto, découpage) */
.op-suggestion {
    padding: 8px 12px; border-radius: 8px;
    display: flex; align-items: center; gap: 10px;
    flex-wrap: wrap; font-size: .82rem;
}
.op-suggestion--adherent { background: var(--color-success-soft); border: 1.5px solid var(--pal-vert-300); }
.op-suggestion--regle    { background: var(--color-info-lt); border: 1.5px solid var(--pal-bleu-300); }
.op-suggestion--info     { background: var(--pal-cyan-50); border: 1.5px solid var(--pal-cyan-300); color: var(--pal-cyan-700); }
.op-sugg-btn {
    padding: 3px 10px; border: none; border-radius: 6px;
    cursor: pointer; font-size: .78rem;
}
.op-sugg-btn--ok      { background: var(--pal-vert-600); color: var(--pal-blanc); }
.op-sugg-btn--ok-blue { background: var(--pal-bleu-700); color: var(--pal-blanc); }
.op-sugg-btn--close   { background: none; border: 1px solid var(--pal-gris-trait); color: var(--pal-gris-moyen); padding: 3px 8px; }
[data-theme="dark"] .op-suggestion--adherent { background: var(--color-success-soft); border-color: var(--color-success-border); }
[data-theme="dark"] .op-suggestion--regle    { background: var(--color-info-soft); border-color: var(--pal-ciel-nuit); }
[data-theme="dark"] .op-suggestion--info     { background: var(--color-info-soft); border-color: var(--pal-cyan-nuit); color: var(--color-info-text); }
[data-theme="dark"] .op-sugg-btn--close      { border-color: var(--color-border); color: var(--color-muted); }

/* Suggestion split — utilisé dans innerHTML */
.op-sugg-title { font-weight: 600; margin-bottom: 6px; }

/* Drag-drop zone justificatif */
.justif-dropzone {
    border: 2px dashed var(--color-border);
    border-radius: var(--radius);
    padding: 20px 16px;
    text-align: center;
    cursor: pointer;
    transition: all .2s;
    background: var(--color-surface);
}
.justif-dropzone:hover { border-color: var(--color-primary); background: var(--pal-bleu-700-a02); }
.justif-drop-active   { border-color: var(--color-primary) !important; background: var(--pal-bleu-700-a06) !important; }
.justif-drop-content {
    display: flex; flex-direction: column; align-items: center;
    gap: 4px; font-size: .85rem; color: var(--color-muted);
}

/* Spinner */
.justif-spinner {
    width: 16px; height: 16px;
    border: 2px solid var(--color-border);
    border-top-color: var(--color-primary);
    border-radius: 50%;
    animation: justif-spin .7s linear infinite;
}
@keyframes justif-spin { to { transform: rotate(360deg); } }

/* ── Modals communes opérations ── */
.modal-justif-box {
    background: var(--color-surface); border-radius: 12px;
    max-width: 680px; width: 100%; max-height: 92vh; overflow-y: auto;
    box-shadow: 0 20px 60px var(--pal-noir-a30);
}
.modal-justif-box--480 { max-width: 480px; }
.modal-justif-header {
    display: flex; justify-content: space-between; align-items: center;
    padding: 12px 20px; border-bottom: 1px solid var(--color-border);
}

/* Modal note */
.note-modal-title { font-size: .95rem; font-weight: 600; }
.note-modal-body  { padding: 16px 20px; }
.note-op-block    { margin-bottom: 12px; }
.note-op-desc {
    font-weight: 600; font-size: .88rem; color: var(--color-text);
}
.note-op-info {
    font-size: .78rem; color: var(--color-muted); margin-top: 2px;
}
.note-textarea {
    width: 100%; padding: 10px 14px;
    border: 1.5px solid var(--color-border); border-radius: 8px;
    font-size: .88rem; font-family: inherit; outline: none; resize: vertical;
    background: var(--color-surface); color: var(--color-text);
    transition: border-color .2s;
}
.note-textarea:focus { border-color: var(--color-primary); }
.note-actions {
    display: flex; gap: 8px; margin-top: 12px;
}
.note-btn-save { flex: 1; }

/* Modal justif preview */
.modal-justif-title {
    font-size: .9rem; font-weight: 600;
    min-width: 0; overflow: hidden;
    text-overflow: ellipsis; white-space: nowrap;
}
.modal-justif-body {
    padding: 16px 20px; text-align: center;
}
.modal-justif-actions {
    padding: 0 20px 16px;
    display: flex; gap: 8px; flex-wrap: wrap;
}
.modal-justif-iframe {
    width: 100%; height: 480px;
    border: 1.5px solid var(--color-border); border-radius: 8px;
}
.modal-justif-img {
    max-width: 100%; max-height: 480px;
    border-radius: 8px;
    border: 1.5px solid var(--color-border);
    cursor: zoom-in;
}

/* ── Modal coupures ── */

.modal-overlay {
    display: none; position: fixed; inset: 0;
    background: var(--pal-noir-a45); z-index: 9999;
    align-items: center; justify-content: center; padding: 16px;
}
.modal-overlay.open { display: flex; }

.modal-coupures-box {
    background: var(--color-surface); border-radius: 12px;
    max-width: 440px; width: 100%; max-height: 90vh; overflow-y: auto;
    box-shadow: 0 20px 60px var(--pal-noir-a25);
}
.modal-coupures-box--lg { max-width: 520px; }
.modal-coupures-header {
    display: flex; justify-content: space-between; align-items: center;
    padding: 14px 20px; border-bottom: 1px solid var(--color-border);
}
.modal-coupures-title { margin: 0; font-size: 1.05rem; }
.modal-coupures-close {
    background: none; border: none; font-size: 1.2rem;
    cursor: pointer; color: var(--color-muted); padding: 4px 8px;
}
.modal-coupures-close:hover { color: var(--color-text); }
.modal-coupures-body { padding: 16px 20px; }

/* ── Modal suppression en masse ── */
.masse-grid-2 {
    display: grid; grid-template-columns: 1fr 1fr;
    gap: 10px; margin-bottom: 12px;
}
.masse-form-group        { margin: 0; }
.masse-form-group-mb-sm  { margin-bottom: 10px; }
.masse-form-group-mb-md  { margin-bottom: 14px; }
.masse-label-sm          { font-size: .78rem; font-weight: 600; }
.masse-input-sm          { font-size: .82rem; }
.masse-btn-preview       { width: 100%; margin-bottom: 12px; font-size: .85rem; }

.masse-preview {
    display: none;
    background: var(--color-surface-alt);
    border-radius: 10px; padding: 14px 16px;
    margin-bottom: 14px; max-height: 220px;
    overflow-y: auto; font-size: .82rem;
}
.masse-preview.is-visible { display: block; }

.masse-confirm-zone { display: none; }
.masse-confirm-zone.is-visible { display: block; }

.masse-confirm-warn {
    background: var(--color-danger-soft);
    border: 1.5px solid var(--color-danger); border-radius: 10px;
    padding: 12px 16px; margin-bottom: 12px;
    font-size: .82rem; color: var(--color-danger);
}
.masse-confirm-actions {
    display: flex; gap: 10px;
}
.masse-confirm-btn-yes { flex: 1; font-size: .85rem; }
.masse-confirm-btn-no  { font-size: .85rem; }

.masse-purge-block {
    border-top: 1.5px solid var(--color-border);
    margin-top: 16px; padding-top: 16px;
}
.masse-purge-btn { width: 100%; font-size: .85rem; }
.masse-purge-hint {
    font-size: .7rem; color: var(--color-muted);
    text-align: center; margin-top: 6px;
}

/* Preview opérations innerHTML — utilisé par previsualiserMasse */
.masse-preview-empty {
    color: var(--color-muted); text-align: center; font-size: .82rem;
}
.masse-preview-head {
    display: flex; gap: 16px; margin-bottom: 10px;
    font-weight: 700; font-size: .85rem;
}
.masse-preview-head .pos { color: var(--color-success); }
.masse-preview-head .neg { color: var(--color-danger); }
.masse-preview-row {
    display: flex; gap: 10px; padding: 4px 0;
    border-bottom: 1px solid var(--color-border);
    font-size: .78rem; align-items: center;
}
.masse-preview-row .date {
    color: var(--color-muted); width: 75px; flex-shrink: 0;
}
.masse-preview-row .desc {
    flex: 1; overflow: hidden;
    text-overflow: ellipsis; white-space: nowrap;
}
.masse-preview-row .amt { font-weight: 700; flex-shrink: 0; }
.masse-preview-row .amt--pos { color: var(--color-success); }
.masse-preview-row .amt--neg { color: var(--color-danger); }
.masse-preview-more {
    text-align: center; color: var(--color-muted);
    font-size: .75rem; margin-top: 6px;
}

/* ============================================================
   SOUS-LOT 2D — Inventaire / Mots-clés / Rapports / Rapprochement
   ============================================================ */

/* ── Inventaire ── */
.inv-solde-card       { margin-bottom:1rem; }
.inv-solde-body       { text-align:center; padding:1.5rem; }
.inv-solde-label      { font-size:.82rem; color:var(--color-muted); margin-bottom:.5rem; }
.inv-solde-val        { font-size:2.5rem; font-weight:700; color:var(--color-primary); }
.inv-solde-divider    { margin-top:1rem; padding-top:.75rem; border-top:1px solid var(--color-border); }
.inv-solde-detail     { font-size:.78rem; color:var(--color-muted); }
.inv-solde-span       { font-size:.72rem; }
.inv-ecart-warn       { font-size:.78rem; font-weight:600; margin-top:4px; }
.inv-ecart-warn--over { color:var(--color-warning); }
.inv-ecart-warn--under{ color:var(--color-danger); }
.inv-grid             { display:grid; grid-template-columns:1fr 1fr; gap:1.5rem; align-items:start; }
.inv-total-box        { background:var(--color-primary-fond); color:var(--color-on-fond); border-radius:var(--radius);
                        padding:1rem; margin:1rem 0; text-align:center; }
.inv-total-label      { font-size:.78rem; opacity:.8; margin-bottom:4px; }
.inv-total-val        { font-size:2rem; font-weight:700; }
.inv-ecart-zone       { border-radius:var(--radius); padding:.75rem 1rem; margin-bottom:1rem; text-align:center;
                        border:1px solid var(--color-border); }
/* Couleurs du thème : les fonds en dur restaient clairs en mode sombre */
.inv-ecart-zone--ok    { background:var(--color-success-lt); }
.inv-ecart-zone--ok .inv-ecart-val    { color:var(--color-success); }
.inv-ecart-zone--over  { background:var(--color-warning-lt); }
.inv-ecart-zone--over .inv-ecart-val  { color:var(--color-warning); }
.inv-ecart-zone--under { background:var(--color-danger-lt); }
.inv-ecart-zone--under .inv-ecart-val { color:var(--color-danger); }
.inv-ecart-sublabel   { font-size:.78rem; margin-bottom:2px; }
.inv-ecart-val        { font-size:1.3rem; font-weight:700; }
.inv-card-sm          { margin-bottom:1rem; }
.inv-card-h2          { font-size:.9rem; }
.inv-card-pad0        { padding:0; }
.inv-arrete-filtre    { padding:.5rem 1rem; border-bottom:1px solid var(--color-border); }
.inv-arretes-plus     { padding:.6rem 1rem; text-align:center; border-top:1px solid var(--color-border); }
.inv-pli-ecart        { font-size:.75rem; font-weight:600; color:var(--color-danger); white-space:nowrap; }
.inv-arrete-form      { display:flex; gap:.4rem; align-items:center; margin:0; }
/* « par NOM Prénom » sur une ligne : sur ordinateur, la colonne de l'écart
   (motif d'acquittement) prenait toute la place et coupait le nom. */
@media (min-width: 769px) { .inv-table-arretes td:first-child { white-space: nowrap; } }
/* Écart du dernier comptage à résoudre : texte, puis les deux gestes */
.inv-resoudre         { display:flex; align-items:center; gap:.5rem; flex-wrap:wrap; justify-content:space-between;
                        padding:.6rem 1rem; background:var(--color-warning-lt);
                        border-bottom:1px solid var(--color-border); font-size:.82rem; }
.inv-resoudre-btns    { display:flex; gap:.4rem; }
.inv-recalage-tag     { color:var(--color-primary); font-size:.68rem; }
.inv-btn-full         { width:100%; }
.inv-flex-btns        { display:flex; gap:.5rem; flex-wrap:wrap; }

/* Modal partagé inventaire */
.modal-box-header       { display:flex; justify-content:space-between; align-items:center;
                          padding:14px 20px; border-bottom:1px solid var(--color-border); }
.modal-box-title        { font-size:.95rem; font-weight:600; }
.modal-box-close        { background:none; border:none; font-size:1.2rem; cursor:pointer; color:var(--color-muted); }
.modal-box-body         { padding:16px 20px; }
.modal-box-desc         { font-size:.85rem; margin-bottom:1rem; color:var(--color-text); }
.modal-box-desc--sm     { font-size:.8rem; margin-bottom:1rem; color:var(--color-muted); }
.modal-box-desc--half   { font-size:.85rem; margin-bottom:.5rem; color:var(--color-text); }
.modal-box-actions      { display:flex; gap:8px; margin-top:1rem; }
.modal-box-actions .btn { flex:1; }

/* Coupures : même motif que les Collectes (− / quantité / +, sections
   repliables). Les titres et les − / + y sont des <button> : il faut
   leur retirer l'habillage du navigateur. */
.inv-coupures-outils  { display:flex; align-items:center; justify-content:space-between; gap:.5rem;
                        flex-wrap:wrap; margin:.25rem 0 .5rem; }
.inv-coupures-depart  { font-size:.78rem; color:var(--color-muted); }
.inv-coupures         { display:flex; flex-direction:column; gap:4px; }
.inv-coupures .col-section-toggle {
    width:100%; border:1px solid var(--color-border); background:var(--color-surface);
    font:inherit; color:inherit; text-align:left;
}
.inv-coupures .col-coupure .col-btn { padding:0; font-family:inherit; line-height:1; }
.inv-coupures .col-coupure input[type="number"] { width:52px; }
.inv-caisse-vide      { margin:-.5rem 0 1rem; font-size:.85rem; }

@media (max-width: 768px) {
    .inv-grid { grid-template-columns:1fr !important; }
    .inv-resoudre-btns { width:100%; }
    .inv-resoudre-btns .btn { flex:1 1 0; }
    /* Téléphone : solde, total et écart resserrés — à pleine taille, ils
       occupaient un écran entier pour trois chiffres. */
    .inv-solde-body       { padding:.85rem 1rem; }
    .inv-solde-val        { font-size:1.9rem; }
    .inv-solde-label      { margin-bottom:.2rem; }
    .inv-solde-divider    { margin-top:.6rem; padding-top:.5rem; }
    .inv-total-box        { display:flex; align-items:center; justify-content:space-between;
                            gap:.5rem; padding:.6rem .9rem; margin:.75rem 0; text-align:left; }
    .inv-total-label      { font-size:.85rem; margin:0; }
    .inv-total-val        { font-size:1.45rem; }
    .inv-ecart-zone       { padding:.5rem .8rem; margin-bottom:.75rem; }
    .inv-ecart-val        { font-size:1rem; }
    .inv-ecart-sublabel   { font-size:.72rem; margin:2px 0 0; color:var(--color-muted); }
    /* Dernières opérations : trois colonnes courtes, lues en lignes plutôt qu'en cartes */
    .inv-table-ops td { padding:.45rem .6rem; }
}

.mk-alert-mb            { margin-bottom:1rem; }
.mk-td-libelle          { font-size:.78rem; color:var(--color-muted); max-width:200px; overflow:hidden;
                          text-overflow:ellipsis; white-space:nowrap; }
.mk-code-ambigu         { background:var(--color-gold-soft); padding:2px 8px; border-radius:4px; font-weight:700; }
[data-theme="dark"] .mk-code-ambigu { background:var(--color-gold-soft); }
.mk-table               { font-size:.84rem; }
.mk-pill                { display:inline-flex; align-items:center; gap:3px; padding:2px 8px;
                          border-radius:20px; font-size:.78rem; margin:2px; }
.mk-pill--normal        { background:var(--color-surface-alt); border:1px solid var(--color-border); }
.mk-pill--doublon       { background:var(--color-danger-soft); border:1px solid var(--color-danger-border); }
[data-theme="dark"] .mk-pill--doublon { background:var(--color-danger-soft); border-color:var(--color-danger-border); }
.mk-pill-warn           { color:var(--color-danger); font-size:.65rem; }
.mk-pill-del            { background:none; border:none; color:var(--color-muted); cursor:pointer;
                          font-size:.75rem; padding:0; line-height:1; }
/* Mots-clés : sous le titre d'un contrôle, sa phrase et son geste
   d'ensemble sur une ligne ; le tableau suit sans second cadre. */
.mk-controle-outils { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
                      gap: .5rem; padding: .25rem 1rem .6rem; }
.mk-controle-outils .liste-sous { margin: 0; }
.mk-filtres { margin-top: .75rem; }
/* Plusieurs mots-clés passent à la ligne entre eux, jamais au milieu. */
.mk-pill { margin: 1px 2px 1px 0; white-space: nowrap; }
.mk-overflow            { overflow-x:auto; }

/* ── Rapports ── */
.rpt-header-actions     { display:flex; gap:.5rem; }
.rpt-zone               { margin:0 auto; }
.rpt-entete             { text-align:center; margin-bottom:2rem; padding-bottom:1.25rem;
                          border-bottom:3px solid var(--color-primary); }
.rpt-asso-name          { font-size:1.4rem; font-weight:700; color:var(--color-primary); margin-bottom:.2rem; }
.rpt-mentions           { font-size: .85rem; color:var(--pal-or); margin-bottom:.5rem; }
.rpt-titre              { font-size:1.2rem; font-weight:700; margin-bottom:.2rem; }
.rpt-periode            { font-size:.85rem; color:var(--color-muted); }
.rpt-summary            { display:grid; grid-template-columns:repeat(3,1fr); gap:1rem; margin-bottom:1.75rem; }
.rpt-summary-card       { border-radius:var(--radius-lg); padding:1.25rem; text-align:center; }
.rpt-summary-card--e    { background:var(--color-success-lt); border:1px solid var(--pal-vert-200); }
[data-theme="dark"] .rpt-summary-card--e { background:var(--color-success-soft); border-color:var(--pal-vert-800); }
.rpt-summary-card--s    { background:var(--color-danger-soft); border:1px solid var(--pal-rouge-200); }
[data-theme="dark"] .rpt-summary-card--s { background:var(--color-danger-soft); border-color:var(--color-danger-border); }
.rpt-summary-card--r-pos{ background:var(--pal-bleu-petrole); }
.rpt-summary-card--r-neg{ background:var(--pal-brique-fonce); }
.rpt-summary-label      { font-size: .8rem; margin-bottom:.4rem; font-weight:600; }
.rpt-summary-label--e   { color:var(--color-success); }
.rpt-summary-label--s   { color:var(--color-danger); }
.rpt-summary-label--r   { color:var(--pal-blanc-a70); }
.rpt-summary-val        { font-size:1.5rem; font-weight:800; }
.rpt-summary-val--e     { color:var(--color-success); }
.rpt-summary-val--s     { color:var(--color-danger); }
.rpt-summary-val--r     { color:var(--pal-blanc); }
.rpt-compte-grid        { display:grid; grid-template-columns:1fr 1fr; gap:1rem; margin-bottom:1.75rem; }
.rpt-compte-card        { border-radius:var(--radius-lg); overflow:hidden; }
.rpt-compte-card--bank  { border:1.5px solid var(--pal-bleu-200); }
.rpt-compte-card--cash  { border:1.5px solid var(--color-warning-border); }
.rpt-compte-header      { color:var(--pal-blanc); padding:.6rem 1rem; font-size: .85rem; font-weight:700; }
.rpt-compte-header--bank{ background:var(--pal-bleu-800); }
.rpt-compte-header--cash{ background:var(--pal-or); }
.rpt-compte-body        { padding:1rem; display:grid; grid-template-columns:1fr 1fr; gap:.75rem; text-align:center; }
.rpt-compte-sublabel    { font-size: .8rem; margin-bottom:.25rem; }
.rpt-compte-sublabel--e { color:var(--color-success); }
.rpt-compte-sublabel--s { color:var(--color-danger); }
.rpt-compte-val         { font-size:1.05rem; font-weight:700; }
.rpt-compte-val--e      { color:var(--color-success); }
.rpt-compte-val--s      { color:var(--color-danger); }
.rpt-compte-solde       { text-align:center; padding:0 1rem .75rem; font-size:.85rem; font-weight:600; }
.rpt-cat-grid           { display:grid; grid-template-columns:1fr 1fr; gap:1rem; margin-bottom:1.5rem; }
.rpt-cat-card           { border:1.5px solid var(--color-border); border-radius:var(--radius-lg); overflow:hidden; }
.rpt-cat-header         { color:var(--pal-blanc); padding:.6rem 1rem; font-size: .85rem; font-weight:700; }
.rpt-cat-header--e      { background:var(--color-success); }
.rpt-cat-header--s      { background:var(--color-danger); }
.rpt-cat-body           { padding:.75rem 1rem; }
.rpt-cat-row            { display:flex; align-items:center; gap:.5rem; padding:.4rem 0;
                          border-bottom:1px solid var(--color-border); }
.rpt-cat-name           { flex:1; font-size:.82rem; }
.rpt-cat-detail         { font-size:.7rem; color:var(--color-muted); }
.rpt-cat-val            { font-size:.82rem; font-weight:600; white-space:nowrap; }
.rpt-cat-val--e         { color:var(--color-success); }
.rpt-cat-val--s         { color:var(--color-danger); }
.rpt-cat-bar            { width:48px; height:4px; background:var(--color-border); border-radius:2px;
                          overflow:hidden; flex-shrink:0; }
.rpt-cat-bar-fill       { height:100%; border-radius:2px; }
.rpt-cat-bar-fill--e    { background:var(--color-success); }
.rpt-cat-bar-fill--s    { background:var(--color-danger); }
.rpt-cat-total          { display:flex; justify-content:space-between; padding-top:.6rem; font-weight:700;
                          font-size:.85rem; margin-top:.25rem; }
.rpt-cat-total--e       { border-top:2px solid var(--color-success); }
.rpt-cat-total--s       { border-top:2px solid var(--color-danger); }
.rpt-transferts-info    { background:var(--pal-violet-100); border-radius:var(--radius); padding:.75rem 1rem;
                          margin-bottom:1.25rem; font-size:.85rem; color:var(--pal-violet-800); display:flex;
                          align-items:center; gap:.75rem; }
[data-theme="dark"] .rpt-transferts-info { background:var(--pal-nuit); color:var(--pal-violet-400); }
.rpt-exclusions         { font-size:.72rem; color:var(--color-muted); margin-bottom:1rem; font-style:italic; }
.rpt-footer             { display:flex; justify-content:space-between; align-items:center; font-size:.72rem;
                          color:var(--color-muted); border-top:1.5px solid var(--color-border);
                          padding-top:.75rem; margin-top:.5rem; flex-wrap:wrap; gap:.5rem; }
.rpt-select             { padding:.35rem .6rem; border:1px solid var(--color-border); border-radius:var(--radius);
                          font-size:.82rem; background:var(--color-surface); }
.rpt-form-col           { margin-top:1rem; display:flex; flex-direction:column; gap:.5rem; }
.rpt-form-row           { display:flex; gap:.5rem; justify-content:center; flex-wrap:wrap; }
.rpt-form-center        { align-self:center; }

@media (max-width: 768px) {
    .rpt-summary { grid-template-columns:1fr !important; }
    .rpt-compte-grid, .rpt-cat-grid { grid-template-columns:1fr !important; }
    .rpt-zone { font-size:.85rem !important; }
}

/* ── Rapprochement ── */
/*  Pleine largeur (comme la carte des opérations rapprochées) : la zone de
    dépôt sur une ligne, le bouton à sa droite ; empilés sur téléphone. */
.rp-upload-form         { display:flex; gap:1rem; align-items:stretch; }
.rp-upload-zone         { flex:1 1 auto; display:flex; flex-wrap:wrap; align-items:center; justify-content:center;
                          gap:.4rem 1rem; padding:1.25rem 1.5rem; border:2px dashed var(--color-border);
                          border-radius:var(--radius-lg); cursor:pointer; text-align:left;
                          transition:border-color .2s, background .2s; background:var(--color-surface-alt); }
.rp-upload-textes       { display:flex; flex-direction:column; gap:.15rem; }
.rp-upload-form .rp-upload-submit { margin:0; display:flex; align-items:center; }
@media (max-width: 768px) {
    .rp-upload-form     { flex-direction:column; }
    .rp-upload-zone     { flex-direction:column; text-align:center; }
    .rp-upload-form .rp-upload-submit .btn { width:100%; justify-content:center; }
}
.rp-upload-zone--drag   { border-color:var(--color-primary); background:var(--pal-or-a08); }
.rp-upload-icon         { font-size:2rem; }
.rp-upload-filename     { font-size:.8rem; color:var(--color-primary); font-weight:600; }
.rp-upload-submit       { margin-top:1.25rem; text-align:right; }
.rp-summary-bar         { padding:.75rem 1.25rem; }
.rp-summary-inner       { display:flex; flex-wrap:wrap; gap:1rem; align-items:center; font-size:.88rem; }
.rp-import-btns         { margin-bottom:1rem; display:flex; gap:.5rem; flex-wrap:wrap; align-items:center; }
.rp-nb-coches           { font-size:.8rem; color:var(--color-muted); }
.rp-section-success     { margin-bottom:1rem; border-color:var(--color-success); }
.rp-section-header--ok  { background:var(--color-success-pale); padding:.6rem 1rem; }
.rp-section-title--ok   { font-size:.9rem; color:var(--color-success); }
.rp-td-nowrap           { white-space:nowrap; }
.rp-td-libelle          { max-width:200px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; color:var(--color-muted); }
.rp-td-libelle--sm      { max-width:180px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; color:var(--color-muted); }
.rp-td-amount           { text-align:right; font-weight:600; white-space:nowrap; }
.rp-td-amount--entree   { color:var(--color-success); }
.rp-td-amount--sortie   { color:var(--color-danger); }
.rp-td-match-detail     { font-size:.75rem; color:var(--color-muted); margin-top:2px; }
.rp-td-match-info       { font-size:.72rem; color:var(--color-info); margin-top:1px; }
/* Remise de chèque à plusieurs réponses : le trésorier choisit. */
.rp-remise-choix-label  { display:block; font-weight:600; color:var(--color-warning); margin:2px 0; }
.rp-remise-choix        { max-width:100%; width:22rem; font-size:.75rem; padding:3px 6px; border:1px solid var(--color-border); border-radius:var(--radius); }
.rp-td-match-cat        { font-size:.82rem; font-weight:600; }
.rp-section-warning     { margin-bottom:1rem; border-color:var(--color-warning); }
.rp-td-select           { font-size:.8rem; padding:3px 6px; border:1px solid var(--color-border);
                          border-radius:var(--radius); background:var(--color-surface); min-width:130px; }
.rp-td-memo-label       { display:flex; align-items:center; gap:4px; font-size:.78rem; white-space:nowrap; }
/* Menus d'une ligne reconnue (catégorie puis adhérent) et mot-clé à
   mémoriser : empilés dans leur case, un léger écart entre eux. */
.rp-td-select--adh, .rp-td-motcle { display:block; margin-top:4px; }
/* Catégorie et adhérent d'une ligne reconnue : même largeur, l'une sous
   l'autre (à largeur libre, chaque menu suivait son texte et la colonne
   paraissait en escalier). */
.rp-td-match-cat        { min-width:15rem; }
.rp-td-match-cat .rp-td-select { display:block; width:100%; }
/* Même chose pour les menus des lignes à qualifier : pleine largeur de
   leur colonne, alignés d'une ligne à l'autre. */
.rp-section-warning select.rp-td-select { width:100%; }
.rp-td-motcle           { width:100%; min-width:130px; }
.rp-section-doublon     { margin-bottom:1rem; border-color:var(--color-danger); opacity:.7; }
.rp-doublon-title       { font-size:.85rem; color:var(--color-danger); }
.rp-doublon-status      { color:var(--color-danger); font-size:.78rem; font-weight:600; }
.rp-td-chk              { text-align:center; width:32px; }
/* Sur ordinateur, la case de l'en-tête du tableau suffit. Écrit avec
   label.…tout-cocher : la règle commune label.tout-cocher, plus précise
   qu'une classe seule et plus bas dans la feuille, l'affichait sinon,
   collée au bord de la carte. */
label.rp-tout-mobile.tout-cocher { display:none; }
.rp-th-right            { text-align:right; }

@media (max-width: 768px) {
    /* Aperçu de l'import en cartes (.table-mobile) : faire défiler de côté
       un tableau de six colonnes au doigt cachait le montant et les menus.
       En tête de carte : la case, la date, le montant ; dessous le libellé
       en entier, puis reconnaissance et menus sur toute la largeur. */
    .mk-overflow:has(> .rp-table-import) { overflow-x:visible; }
    label.rp-tout-mobile.tout-cocher { display:flex; margin:.6rem .85rem .3rem; }
    /* Resté en display: table, le tableau prenait la largeur de son plus
       long libellé et sortait de l'écran. */
    .rp-table-import, .rp-table-import tbody { display:block; width:100%; }
    .rp-table-import tbody tr {
        display:grid; grid-template-columns:auto 1fr auto;
        gap:.2rem .6rem; align-items:center;
    }
    .rp-table-import tbody td { width:auto !important; padding:0; }
    .rp-table-import tbody td:first-child {
        display:flex; margin:0; padding:0; border-bottom:none;
        grid-column:1; grid-row:1;
    }
    .rp-table-import tbody td:nth-child(2) { grid-column:2; grid-row:1; font-weight:600; }
    .rp-table-import tbody td:nth-child(4) { grid-column:3; grid-row:1; justify-content:flex-end; }
    .rp-table-import tbody td:nth-child(3) {
        grid-column:1 / -1; grid-row:2;
        max-width:none; white-space:normal; overflow:visible; text-overflow:clip;
        display:block; color:var(--color-text); font-size:.8rem;
    }
    .rp-table-import tbody td:nth-child(2)::before,
    .rp-table-import tbody td:nth-child(3)::before,
    .rp-table-import tbody td:nth-child(4)::before { display:none; }
    .rp-table-import tbody td.rp-td-plein {
        grid-column:1 / -1; padding-top:.35rem;
        border-top:1px dashed var(--color-border);
    }
    /* Libellé au-dessus, contenu dessous, calé à gauche : en flex
       « space-between », le badge partait au bord droit de la carte. */
    .rp-table-import tbody td.rp-td-plein { display:block; }
    .rp-table-import tbody td.rp-td-plein::before { display:block; margin:0 0 .2rem; }
    .rp-table-import tbody td.rp-td-plein > *,
    .rp-table-import tbody td.rp-td-plein > div { text-align:left; }
    /* « Déjà importé » redit le titre de la section Doublons. */
    .rp-table-import tbody td.table-mobile-secondary { display:none; }
    .rp-table-import .rp-td-match-cat { min-width:0; }
    .rp-table-import .rp-remise-choix { width:100%; }
    .rp-td-select { min-width:0 !important; width:100%; font-size:.75rem !important; }
    .rp-td-memo-label { white-space:normal !important; font-size:.7rem !important; }
}

/* ── Rapports: grille de choix (migré depuis <style> block) ──
   auto-fit et non auto-fill : quand une carte manque — l'export CSV ne
   s'affiche qu'à qui peut exporter — les trois restantes se partagent la
   ligne au lieu de laisser une colonne vide. min() sur le minimum : sur un
   écran plus étroit que la carte, la colonne rétrécit au lieu de déborder.
   180px plutôt que 220 : quatre cartes tiennent sur une ligne dès qu'il y
   a la place, au lieu de passer à deux lignes pour quelques pixels. */
.rapport-grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(min(100%,180px),1fr)); gap:1rem; margin-bottom:1.5rem; }
.rapport-card { background:var(--color-surface); border:1.5px solid var(--color-border); border-radius:var(--radius-lg);
                padding:1.5rem; text-align:center; transition:box-shadow .15s,transform .15s;
                /* Colonne : les cartes ont déjà la même hauteur (la grille les
                   étire), mais leur contenu était collé en haut — le bouton
                   d'une carte à deux menus tombait deux crans plus bas que
                   celui d'une carte à un seul lien. Le bloc d'action est
                   poussé en bas, les quatre boutons s'alignent. */
                display:flex; flex-direction:column; }
.rapport-card .rpt-form-col { margin-top:auto; padding-top:1rem; }
.rapport-card:hover { box-shadow:var(--shadow-md); transform:translateY(-2px); }
.rapport-icon { font-size:2.5rem; margin-bottom:.75rem; }
.rapport-card h3 { font-size:1rem; font-weight:600; margin-bottom:.3rem; color:var(--color-text); }
.rapport-card p { font-size:.82rem; color:var(--color-muted); }

/* En dessous d'un grand écran : deux colonnes carrées, toujours. Sans ce
   palier, quatre cartes tombaient en 3 + 1 — la dernière seule sur sa ligne —
   sur une fenêtre d'ordinateur pas très large comme sur une tablette. Moins
   de colonnes plutôt que des colonnes plus petites. */
@media (max-width: 1160px) {
    .rapport-grid { grid-template-columns: 1fr 1fr; }
}

/* Téléphone : deux cartes par ligne plutôt que quatre pavés empilés, qui
   demandaient trois écrans de défilement pour choisir un rapport. Cartes
   resserrées en conséquence, et les menus prennent toute la largeur de leur
   carte — écrite APRÈS la règle de base, sinon elle ne l'écraserait pas. */
@media (max-width: 768px) {
    .rapport-grid { gap:.6rem; }
    .rapport-card { padding:.9rem .6rem; }
    .rapport-card .rpt-form-col { padding-top:.6rem; gap:.4rem; }
    .rapport-icon { font-size:1.75rem; margin-bottom:.4rem; }
    .rapport-card h3 { font-size:.85rem; }
    .rapport-card p  { font-size:.72rem; }
    .rapport-card .rpt-form-row { flex-direction:column; gap:.4rem; }
    .rapport-card .rpt-select { width:100%; }
    .rapport-card .rpt-form-center { align-self:stretch; }
}

/* ── Rapprochement: badges (migré depuis <style> block) ── */
.rp-badge { padding:2px 8px; border-radius:6px; font-size:.78rem; font-weight:600; display:inline-block; }
.rp-badge--transfert { background:var(--color-info-soft); color:var(--color-info-text); }
.rp-badge--adherent  { background:var(--color-success-mid); color:var(--color-success-text); }
.rp-badge--cheque    { background:var(--pal-jaune-100); color:var(--pal-jaune-800); }
.rp-badge--regle     { background:var(--pal-ciel-100); color:var(--pal-ciel-800); }
[data-theme="dark"] .rp-badge--transfert { background:var(--color-info-soft); color:var(--color-info-text); }
[data-theme="dark"] .rp-badge--adherent  { background:var(--color-success-soft); color:var(--color-success-text); }
[data-theme="dark"] .rp-badge--cheque    { background:var(--color-warning-soft); color:var(--color-warning-text); }
[data-theme="dark"] .rp-badge--regle     { background:var(--color-info-soft); color:var(--color-info-text); }
.rp-header--warning  { background:var(--color-warning-lt); padding:.6rem 1rem; }
.rp-title--warning   { font-size:.9rem; color:var(--color-warning-text); }
.rp-header--danger   { background:var(--color-danger-soft); padding:.5rem 1rem; cursor:pointer; }
.rp-row--danger      { background:var(--color-danger-soft); }
[data-theme="dark"] .rp-header--warning { background:var(--color-warning-soft); }
[data-theme="dark"] .rp-title--warning  { color:var(--color-warning-text); }
[data-theme="dark"] .rp-header--danger  { background:var(--color-danger-soft); }
[data-theme="dark"] .rp-row--danger     { background:var(--color-danger-soft); }
.rp-upload-submit    { margin-top:1.25rem; text-align:right; }

/* ── Justificatifs échéancier ── */
.ops-justif-modele-row {
    margin-top: .6rem;
}
.ops-justif-modele-row--modal {
    margin-bottom: 1rem;
}
/* Formulaire de saisie : la case et sa bulle ⓘ sur une ligne. */
.ops-justif-modele-row--ligne { display: flex; align-items: center; gap: .35rem; }
/* Fichier choisi à la saisie : son nom et « Retirer » à la place de l'invite. */
.ops-justif-choisi {
    display: flex; align-items: center; justify-content: center;
    gap: .6rem; flex-wrap: wrap; font-size: .9rem; overflow-wrap: anywhere;
}
/* Formulaire de saisie d'une opération, sur ordinateur : chaque champ à
   la taille de ce qu'on y écrit. Étirés sur toute la largeur, Date et
   Montant faisaient 600 px pour « 03/10/2026 » et « 12,50 ». Le
   téléphone (une colonne) n'est pas touché. */
@media (min-width: 900px) {
    .ops-carte-saisie { max-width: 64rem; }
    .ops-carte-saisie .form-group { margin-bottom: .8rem; }
    /* Zone de fichier : une ligne, plus un grand cadre. */
    .ops-carte-saisie .justif-dropzone { padding: .6rem 1rem; }
    .ops-carte-saisie .form-group label.justif-drop-content { flex-direction: row; justify-content: center; gap: .6rem; }
    .ops-carte-saisie .ops-justif-icon-lg { font-size: 1.1rem; }
    .ops-carte-saisie .justif-drop-content > span { white-space: nowrap; }
    .ops-carte-saisie .ops-justif-browse { display: inline; }
}
/* Date · Sens · Montant · Compte sur une ligne, seulement si les quatre
   tiennent à côté de la barre latérale (minimum ≈ 560 px de contenu). */
@media (min-width: 1100px) {
    .ops-carte-saisie .ops-form-ligne1 {
        grid-template-columns: minmax(8.5rem, 1fr) minmax(7.5rem, 1fr) minmax(7rem, 1fr) minmax(9rem, 1.4fr);
    }
}
/* Mois de cotisation déjà enregistrés, lus en clair (le marqueur technique
   n'est plus dans Notes). */
.ops-mois-actuels { margin: 0 0 .8rem; font-size: .85rem; color: var(--color-muted); }
.ops-mois-actuels strong { color: var(--color-text); }
/* Saisie d'une opération — « + Projet, notes » replié (rarement remplis). */
.ops-form-plus { margin: 0 0 .8rem; }
.ops-form-plus > summary {
    cursor: pointer; font-size: .85rem; font-weight: 600;
    color: var(--color-primary); padding: .2rem 0; list-style: none;
}
.ops-form-plus > summary::-webkit-details-marker { display: none; }
.ops-form-plus[open] > summary { margin-bottom: .5rem; }
/* Sens en deux boutons : téléphone seulement (le menu reste sur ordinateur). */
.ops-sens-choix { display: none; }
.ops-sens-choix button {
    flex: 1 1 0; min-width: 0; padding: .5rem .25rem;
    border: 1px solid var(--color-border-strong); background: var(--color-surface);
    color: var(--color-text); font: inherit; font-size: .88rem; cursor: pointer;
    white-space: nowrap;
}
.ops-sens-choix button:first-child { border-radius: var(--radius) 0 0 var(--radius); }
.ops-sens-choix button:last-child  { border-radius: 0 var(--radius) var(--radius) 0; border-left: 0; }
.ops-sens-choix button[data-sens="entree"].is-on {
    background: var(--color-success-lt); border-color: var(--color-success); color: var(--color-success); font-weight: 600;
}
.ops-sens-choix button[data-sens="sortie"].is-on {
    background: var(--color-danger-lt); border-color: var(--color-danger); color: var(--color-danger); font-weight: 600;
}
.ops-sens-choix button[data-sens="sortie"].is-on { border-left: 1px solid var(--color-danger); }
/* Téléphone : Date · Sens puis Montant · Compte deux par ligne, et un
   même écart entre tous les champs (la grille ajoutait son écart à la
   marge de chaque champ : les lignes n'étaient pas espacées pareil). */
@media (max-width: 768px) {
    .ops-carte-saisie .form-row { gap: 0 .6rem; margin-bottom: 0; }
    .ops-carte-saisie .ops-form-ligne1 { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
    .ops-carte-saisie .form-group { margin-bottom: .85rem; }
    .ops-sens--boutons select { display: none; }
    .ops-sens--boutons .ops-sens-choix { display: flex; }
}
/* Zone de justificatif : le cadre entier est touchable. Sur un écran
   tactile (pas de souris), on ne peut pas glisser un fichier : le texte
   propose la photo, le cadre devient un bouton d'une ligne. */
/* Plus précis que « .form-group label » (bloc, gras, petit) : un libellé
   ici garde l'allure de la zone. */
.form-group label.justif-drop-content {
    display: flex; flex-direction: column; align-items: center; gap: 4px;
    margin: 0; cursor: pointer; font-weight: normal; font-size: .85rem;
    color: var(--color-muted);
}
.justif-dropzone .justif-txt-tactile { display: none; }
@media (hover: none) {
    .justif-dropzone .justif-txt-souris { display: none; }
    .justif-dropzone .justif-txt-tactile { display: inline; font-weight: 600; color: var(--color-primary); }
    .justif-dropzone { padding: .75rem 1rem; }
}
/* « Pas de justificatif » et son motif, sous la zone de fichier. */
.ops-sans-justif { margin-top: .6rem; }
.ops-sans-justif-motif { margin: .5rem 0 0; }
.ops-justif-modele-label {
    display: flex;
    align-items: flex-start;
    gap: .5rem;
    cursor: pointer;
    font-size: .9rem;
}
.ops-justif-modele-label input[type="checkbox"] {
    margin-top: .15rem;
    flex-shrink: 0;
    accent-color: var(--color-primary);
}
.ops-modele-badge {
    font-size: .85rem;
    opacity: .75;
    cursor: default;
}
.badge-modele-echeancier {
    display: inline-block;
    background: var(--color-primary-lt);
    color: var(--color-primary);
    border-radius: 6px;
    padding: 1px 7px;
    font-size: .75rem;
    font-weight: 600;
    margin-left: .4rem;
}
[data-theme="dark"] .badge-modele-echeancier {
    background: var(--pal-ambre-500-a15);
    color: var(--color-warning);
}

/* Justificatif hérité d'un modèle échéancier (🔗) : visuellement
   distinct du trombone d'une pièce propre, pour qu'un contrôle des
   comptes voie tout de suite d'où vient la justification. */
.ops-justif-herite {
    opacity: .8;
    filter: saturate(.7);
}
.ops-justif-herite:hover { opacity: 1; filter: none; }

/* Pointeur d'échéancier cassé : modèle supprimé ou fichier retiré */
.ops-justif-orphelin {
    color: var(--color-danger);
    font-size: .9rem;
    cursor: help;
}

.ops-justif-modele-warn {
    margin-top: .4rem;
    font-size: .78rem;
}

.modal-justif-note {
    font-size: .78rem;
    color: var(--color-muted);
    margin-right: auto;
    align-self: center;
}

/* ── Immobilisations — nouveau design ── */
.tps-immo-summary {
    display: flex;
    align-items: center;
    gap: 1rem;
    flex-wrap: wrap;
    background: var(--color-surface-alt);
    border-radius: 8px;
    padding: .85rem 1.1rem;
    margin-bottom: 1.25rem;
    border: 1px solid var(--color-border);
}
.tps-immo-summary-item { display: flex; flex-direction: column; gap: .15rem; }
.tps-immo-summary-label { font-size: .8rem; color: var(--color-muted); }
.tps-immo-summary-val { font-size: 1.05rem; font-weight: 700; }
.tps-immo-summary-val--primary { color: var(--color-primary); }
.tps-immo-summary-val--muted { color: var(--color-muted); font-size: .95rem; }
.tps-immo-summary-sep { color: var(--color-muted); font-size: 1.2rem; }
.tps-immo-summary-sep--right { margin-left: auto; }

.tps-immo-bien-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 1rem;
}
.tps-immo-bien-card {
    border: 1px solid var(--color-border);
    border-radius: 10px;
    padding: 1rem 1.1rem;
    background: var(--color-surface);
    transition: box-shadow .15s;
}
.tps-immo-bien-card:hover { box-shadow: 0 2px 10px var(--pal-noir-a08); }
.tps-immo-bien-card--amorti { opacity: .7; border-style: dashed; }

.tps-immo-bien-head {
    display: flex;
    align-items: center;
    gap: .5rem;
    margin-bottom: .3rem;
}
.tps-immo-bien-nom { font-weight: 600; flex: 1; font-size: .95rem; }
.tps-immo-badge-amorti {
    font-size: .7rem; font-weight: 600;
    background: var(--color-surface-alt);
    color: var(--color-muted);
    border-radius: 4px;
    padding: 1px 6px;
}
.tps-immo-bien-meta {
    font-size: .78rem;
    color: var(--color-muted);
    margin-bottom: .75rem;
}

.tps-immo-bar-wrap {
    display: flex;
    align-items: center;
    gap: .6rem;
    margin-bottom: .75rem;
}
.tps-immo-bar-track {
    flex: 1;
    height: 7px;
    background: var(--color-border);
    border-radius: 99px;
    overflow: hidden;
}
.tps-immo-bar-fill {
    height: 100%;
    border-radius: 99px;
    transition: width .4s ease;
}
.tps-immo-bar-fill--cours  { background: var(--color-primary); }
.tps-immo-bar-fill--avance { background: var(--color-warning); }
.tps-immo-bar-fill--amorti { background: var(--color-muted); }
.tps-immo-bar-pct {
    font-size: .75rem;
    color: var(--color-muted);
    white-space: nowrap;
    min-width: 70px;
    text-align: right;
}

.tps-immo-bien-kpis {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: .4rem .8rem;
}
.tps-immo-kpi { display: flex; flex-direction: column; gap: .1rem; }
.tps-immo-kpi-label { font-size: .8rem; color: var(--color-muted); }
.tps-immo-kpi-val { font-size: .88rem; font-weight: 600; }
.tps-immo-kpi-val--primary { color: var(--color-primary); }

/* Suggestions durée */
.tps-immo-presets {
    display: flex;
    flex-wrap: wrap;
    gap: .3rem;
    margin-top: .4rem;
    align-items: center;
}
.tps-immo-preset-label { font-size: .72rem; color: var(--color-muted); }
.tps-immo-preset {
    font-size: .72rem;
    padding: 2px 8px;
    border-radius: 99px;
    border: 1px solid var(--color-border);
    background: var(--color-surface-alt);
    cursor: pointer;
    color: var(--color-text);
    transition: border-color .15s, background .15s;
}
.tps-immo-preset:hover { border-color: var(--color-primary); background: var(--color-primary-lt); }

[data-theme="dark"] .tps-immo-bien-card { background: var(--color-surface-alt); }
[data-theme="dark"] .tps-immo-summary { background: var(--pal-blanc-a04); }

/* ============================================================
   REPORT D'EXERCICE — soldes d'ouverture / clôture
   Utilisé par tresorerie/rapports.php et tresorerie/rapport_ag.php.
   Grille 3 colonnes alignée sur .rpt-summary et .ag-exec-grid.
   ============================================================ */

.exo-solde-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 1rem;
    margin-bottom: 1.75rem;
}

.exo-solde-card {
    border-radius: var(--radius-lg);
    padding: 1.1rem 1.25rem;
    text-align: center;
    background: var(--color-surface-alt);
    border: 1px solid var(--color-border-strong);
}

/* Carte centrale : la variation, c'est le chiffre qu'on lit en premier */
.exo-solde-card--pivot {
    background: var(--color-primary-lt);
    border-color: var(--color-primary-mid);
}

.exo-solde-label {
    font-size: .8rem;
    font-weight: 600;
    color: var(--color-muted);
    margin-bottom: .35rem;
}

.exo-solde-val {
    font-size: 1.35rem;
    font-weight: 800;
    color: var(--color-text);
}

.exo-solde-val--pos { color: var(--color-success); }
.exo-solde-val--neg { color: var(--color-danger); }

.exo-solde-note {
    font-size: .7rem;
    color: var(--color-muted);
    margin-top: .3rem;
}

.exo-solde-warn {
    font-size: .72rem;
    font-weight: 600;
    color: var(--color-danger);
    margin-top: .3rem;
}

@media (max-width: 768px) {
    .exo-solde-grid { grid-template-columns: 1fr; }
}

/* ══════════════════════════════════════════════════════════════
   COTISATIONS — tuiles cliquables, année de la période, compte
   Écrit après les règles .cot-* existantes (vers 4400) : à force
   égale, la dernière règle écrite gagne.
   ══════════════════════════════════════════════════════════════ */

/* L'année de chaque bout de la période couverte (« de septembre 2026 à
   août 2027 ») : un menu court, à côté de son mois. */
.cot-periode-annee-select { width: auto; min-width: 5.2rem; }

/* Réassignation : une grille de mois par année, titrée. */
.reassign-annee {
    font-size: .72rem; font-weight: 700; color: var(--color-muted);
    margin: .5rem 0 .25rem;
}

/* Historique : ce qui passe d'une année à l'autre, sous le total. */
.cot-reports {
    margin-top: .5rem; padding: .5rem .75rem;
    background: var(--color-surface-alt); border-radius: var(--radius);
    font-size: .82rem; line-height: 1.6;
}

/* Phrase d'aide sous le compte (« un virement arrive sur le compte
   bancaire »). Elle n'apparaît que lorsqu'elle a quelque chose à dire. */
.cot-compte-aide {
    display: block; margin-top: 4px;
    font-size: .72rem; color: var(--color-muted);
}
.cot-compte-aide:empty { display: none; }

/* ══════════════════════════════════════════════════════════════
   OPÉRATIONS — retour sur la ligne modifiée
   Après un enregistrement, la page revient sur #op-<id>. La ligne est
   décalée sous les barres fixes du haut (sinon elle arriverait cachée
   dessous) et teintée un instant, pour qu'on voie tout de suite laquelle
   on vient de corriger au milieu d'une liste filtrée.
   ══════════════════════════════════════════════════════════════ */
.ops-table tr.ops-row { scroll-margin-top: 120px; }
.ops-table tr.ops-row:target,
.ops-table tr.ops-row:target > td { background: var(--color-primary-lt); }

/* ════════════════════════════════════════════════════════════
   OPÉRATIONS — une ligne par opération, groupées par jour

   Motif repris des relevés bancaires : un bandeau de jour, le libellé en
   tête de ligne, le compte et la catégorie en petit dessous, le montant
   à droite. La colonne Date disparaît — sur une page de cinquante
   opérations elle ne prenait que six valeurs différentes, et huit fois
   la même sur le tableau de bord — et Compte et Catégorie cessent d'être
   deux colonnes à lire de gauche à droite.

   Un seul motif pour les deux largeurs : le téléphone avait déjà cette
   présentation (libellé puis ligne grise), l'ordinateur en avait une
   autre. Sert au tableau de bord comme à la page Opérations.

   ⚠ Ce bloc est écrit APRÈS la media query des opérations plus haut :
     ses règles de base doivent pouvoir être écrasées par sa propre
     media query, placée en fin de bloc.
   ════════════════════════════════════════════════════════════ */

/* Le bandeau de jour n'est pas une opération : il ne se survole pas, ne
   se coche pas, et ne devient pas une carte sur téléphone. */
.ops-table tr.ops-jour td {
    background: var(--color-primary-lt);
    color: var(--color-primary-dk);
    font-size: .76rem;
    font-weight: 700;
    letter-spacing: .02em;
    padding: .4rem .75rem;
    border-bottom: 1px solid var(--color-primary-mid);
}
.ops-table tr.ops-jour:hover td { background: var(--color-primary-lt); }

/* Libellé, repère de détail, et le montant sur téléphone (sur
   ordinateur il garde sa colonne, alignée à droite). */
.ops-ligne-haut {
    display: flex;
    align-items: baseline;
    gap: .4rem;
    flex-wrap: wrap;
}
.ops-ligne-haut .ops-desc { flex: 0 1 auto; }

/* Compte · catégorie, sous le libellé : ce qui était deux colonnes. */
.ops-ligne-meta {
    display: flex;
    align-items: center;
    gap: .4rem;
    flex-wrap: wrap;
    margin-top: .15rem;
}
.ops-ligne-compte { font-size: .75rem; color: var(--color-muted); }
/* Catégorie, « ✓ rapprochée » et 📎 regroupés : sur téléphone ils doivent
   pouvoir se poser d'un bloc, le compte partant seul dans l'en-tête de la
   carte. Le même écart qu'entre les éléments de .ops-ligne-meta, pour que
   la ligne se lise d'un trait comme avant ce regroupement. */
.ops-ligne-suite {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    flex-wrap: wrap;
    min-width: 0;
}
.ops-ligne-cat    { font-size: .72rem; }
.ops-ligne-rapproche {
    font-size: .7rem; color: var(--color-success); white-space: nowrap;
}

/* Le repère qui dit qu'il y a un adhérent et/ou une note, et qui les
   ouvre. Le chevron pivote pour dire dans quel sens ça va. */
.ops-detail-btn {
    background: none; border: none; cursor: pointer;
    padding: 0 .15rem;
    font-size: .8rem; line-height: 1;
    color: var(--color-muted);
    white-space: nowrap;
}
.ops-detail-btn:hover { color: var(--color-text); }
.ops-chevron {
    display: inline-block;
    transition: transform var(--transition);
}
.ops-detail-btn[aria-expanded="true"] .ops-chevron { transform: rotate(180deg); }

.ops-detail {
    margin-top: .35rem;
    padding: .4rem .55rem;
    background: var(--color-surface-alt);
    border-radius: var(--radius);
    font-size: .76rem;
    color: var(--color-muted);
}
.ops-detail-adh  { font-weight: 600; color: var(--color-text); }
/* Le nom ouvre la fiche de l'adhérent : un bouton habillé en nom ;
   soulignement et survol viennent de la règle commune des noms. */
.ops-adh-lien {
    font: inherit; font-weight: 600; color: var(--color-text);
    background: none; border: 0; padding: 0; cursor: pointer; text-align: left;
}
.ops-detail-note { margin-top: .2rem; }

/* Le 📎 posé dans la ligne double celui de la colonne Justificatif,
   masquée sur téléphone : il ne se montre donc que là. */
.ops-meta-justif { display: none; }

/* ── Le filet de couleur ──

   Un trait au bord gauche de chaque ligne : vert pour une entrée, rouge
   pour une sortie, gris pour un transfert interne (filetOperation()). Il
   suivait le compte (bleu banque, ambre caisse) : une sortie de banque
   était bleue, ce qu'on ne lit pas comme une sortie. Le compte reste
   écrit sur chaque ligne.

   Posé sur la première cellule et non sur la ligne : en
   border-collapse, la bordure d'un <tr> est arbitrée avec celles des
   cellules qu'il contient. */
.ops-row--entree    { --ops-filet: var(--color-success); }
.ops-row--sortie    { --ops-filet: var(--color-danger); }
.ops-row--transfert { --ops-filet: var(--color-muted); }

.ops-table tbody tr.ops-row > td:first-child {
    border-left: 3px solid var(--ops-filet);
}

@media (max-width: 768px) {
    .ops-table tr.ops-jour {
        display: block;
        background: transparent;
        border: 0;
        box-shadow: none;
        border-radius: 0;
        padding: .5rem 0 .1rem;
        margin: 0;
    }
    .ops-table tr.ops-jour td {
        display: block;
        background: transparent;
        border: 0;
        padding: 0 .15rem;
        width: 100% !important;
    }
    .ops-table tr.ops-jour td::before { display: none; }

    /* La cellule de l'opération est le corps de la carte : ni étiquette
       « OPÉRATION » devant, ni mise en colonnes — elle empile déjà ses
       trois blocs. Pas de filet sous elle non plus : sur le tableau de
       bord c'est la seule cellule visible, il ne séparerait rien, et sur
       la page Opérations la cellule Actions porte déjà le sien. */
    .ops-table tbody td[data-label="Opération"] {
        display: block;
        border-bottom: none;
        margin-bottom: 0;
        padding-bottom: .1rem;
    }
    .ops-table tbody td[data-label="Opération"]::before { display: none; }

    .ops-ligne-haut {
        align-items: flex-start;
        gap: .3rem .5rem;
    }
    .ops-ligne-haut .ops-desc { flex: 1 1 auto; }
    /* Le montant se colle à droite du libellé, comme sur un relevé. */
    .ops-ligne-haut .ops-mobile-montant { margin-left: auto; }

    .ops-meta-justif { display: inline-flex; align-items: center; gap: .2rem; }
}

/* ══════════════════════════════════════════════════════════════
   OPÉRATIONS SUR TÉLÉPHONE — l'en-tête de carte porte les commandes

   Une carte d'opération gardait une ligne entière en haut pour une case
   à cocher seule et centrée, et une ligne entière en bas pour ses deux
   boutons. Les trois se rejoignent sur la première ligne — case à
   cocher à gauche, compte au milieu, boutons à droite — et la carte
   perd ses deux lignes creuses.

   Fait en grille sur le <tr>, la cellule de l'opération passant en
   display: contents : la case à cocher, le compte et les boutons
   vivent dans trois cellules différentes, et aucune propriété ne peut
   les rapprocher sans effacer ce niveau. Le HTML n'est pas touché,
   donc l'affichage sur ordinateur est inchangé par construction.

   ⚠ Réservé aux lignes qui ont des boutons (:has). Sans eux — compte en
     lecture seule, « Dernières opérations » du tableau de bord — le
     compte se retrouverait seul sur sa ligne et coûterait justement
     celle qu'on économise ici. Un navigateur sans :has() garde la
     présentation précédente, sans rien casser.
   ══════════════════════════════════════════════════════════════ */
@media (max-width: 768px) {
    .ops-table tbody tr.ops-row:has(.ops-td-actions) {
        display: grid;
        grid-template-columns: auto 1fr auto;
        grid-template-areas:
            "sel    compte  actions"
            "desc   desc    desc"
            "suite  suite   suite"
            "detail detail  detail";
        align-items: center;
        column-gap: .5rem;
        row-gap: .15rem;
    }

    /* Les deux cellules qui gardent une boîte : elles perdent les filets
       et les marges qui les séparaient du reste de la carte, puisqu'elles
       sont maintenant DANS son en-tête. */
    tr.ops-row:has(.ops-td-actions) > .ops-td-sel {
        grid-area: sel;
        display: flex;
        align-items: center;
        padding: 0;
        margin-bottom: 0;
        border-bottom: none;
    }
    tr.ops-row:has(.ops-td-actions) > td[data-label="Actions"] {
        grid-area: actions;
        padding: 0 !important;
        margin-top: 0;
        border-top: none;
    }
    /* nowrap : un bouton qui passerait à la ligne rendrait la ligne
       d'en-tête plus haute que les deux lignes qu'elle remplace. */
    tr.ops-row:has(.ops-td-actions) .ops-actions {
        justify-content: flex-end;
        flex-wrap: nowrap;
    }

    /* La cellule de l'opération s'efface : ses blocs deviennent des
       éléments de la grille de la carte, et peuvent donc se placer
       ailleurs que les uns sous les autres. */
    tr.ops-row:has(.ops-td-actions) > td[data-label="Opération"] { display: contents; }
    tr.ops-row:has(.ops-td-actions) .ops-ligne-meta { display: contents; }

    /* Le compte se coupe plutôt que de pousser les boutons hors de
       l'écran : à 375 px, « 🔄 Hassan → Khalid » et les deux boutons
       tiennent tout juste, et c'est le compte qui peut céder — il se
       relit en entier dans la liste, les boutons non. */
    tr.ops-row:has(.ops-td-actions) .ops-ligne-compte,
    tr.ops-row:has(.ops-td-actions) .badge-transfert {
        grid-area: compte;
        justify-self: start;
        max-width: 100%;
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    /* Le libellé reprend toute la largeur, et se lit à gauche : la règle
       commune de .table-mobile pousse à droite les sous-lignes d'une
       cellule qui n'est pas la première, ce qui convient à une valeur
       courte, pas au corps d'une carte. Son filet remplace celui que
       portait la case à cocher. */
    tr.ops-row:has(.ops-td-actions) .ops-ligne-haut {
        grid-area: desc;
        text-align: left;
        border-top: 1px solid var(--color-border);
        padding-top: .4rem;
        margin-top: .2rem;
    }

    /* Catégorie, « ✓ rapprochée » et 📎 forment UN élément de grille,
       posé sur toute la largeur. Placés séparément, ils tombaient dans
       les colonnes de l'en-tête : le badge « Maison - Travaux » élargissait
       la colonne de la case à cocher et le compte n'avait plus la place
       de s'écrire (« Ha… »). */
    tr.ops-row:has(.ops-td-actions) .ops-ligne-suite {
        grid-area: suite;
        display: flex;
        align-items: center;
        gap: .4rem;
        flex-wrap: wrap;
        min-width: 0;
    }
    tr.ops-row:has(.ops-td-actions) .ops-meta-justif { margin-left: auto; }
    tr.ops-row:has(.ops-td-actions) .ops-detail      { grid-area: detail; }

    /* .table-mobile pousse à droite les sous-lignes d'une cellule qui
       n'est pas la première — bon pour une valeur courte, faux pour le
       corps d'une carte, où tout se lit à gauche. text-align se transmet
       aux enfants, y compris à travers un display: contents. */
    tr.ops-row:has(.ops-td-actions) > td[data-label="Opération"] > div { text-align: left; }
}

/* Sur téléphone, le filet de compte passe du bord de la cellule au bord
   de la CARTE : c'est la carte entière qui représente l'opération, et un
   trait posé à l'intérieur se lirait comme une décoration. Même motif que
   les lignes « À traiter » de l'accueil trésorerie : fond neutre, filet de
   couleur à gauche. */
@media (max-width: 768px) {
    .ops-table tbody tr.ops-row {
        border-left: 3px solid var(--ops-filet);
    }
    .ops-table tbody tr.ops-row > td:first-child { border-left: none; }
}

/* ── Photo couverture PDF : aperçu ── */
.params-photo-preview {
    max-width: 200px;
    max-height: 120px;
    object-fit: cover;
    border-radius: 6px;
}
.params-photo-placeholder {
    width: 120px;
    height: 72px;
    font-size: .78rem;
    color: var(--color-muted);
}

/* ============================================================
   Graphiques (tresorerie/graphiques.php) — camemberts entrées /
   sorties de l'année et des mois, barres des douze mois.
   Vert = entrées, rouge = sorties : le sens de l'argent, comme le
   filet des listes d'opérations.
   ============================================================ */
.graph-annee-corps {
    display: flex; flex-direction: column; align-items: center; gap: .6rem;
}
.graph-camembert { width: 110px; aspect-ratio: 1; }
.graph-camembert--grand { width: 220px; }
.graph-camembert--touche { cursor: pointer; }
.graph-svg { display: block; width: 100%; height: 100%; }
/* Disque plein : deux parts séparées par un liseré de la couleur du
   fond de la carte. La part survolée s'éclaircit. */
.graph-fond { fill: var(--color-border); }
.graph-part { stroke: var(--color-surface); stroke-width: .7; stroke-linejoin: round; transition: opacity var(--transition); }
.graph-part--entree { fill: var(--color-success); }
.graph-part--sortie { fill: var(--color-danger); }
.graph-lien { cursor: pointer; outline: none; }
.graph-lien:hover .graph-part,
.graph-lien:focus-visible .graph-part { opacity: .8; }

/* Le résultat sous un camembert : le seul chiffre écrit en clair. */
.graph-solde {
    display: inline-flex; flex-direction: column; align-items: center;
    line-height: 1.2; text-decoration: none; color: var(--color-text);
}
.graph-solde-mt { font-family: var(--font-title); font-weight: 700; font-size: 1.05rem; white-space: nowrap; }
.graph-annee-corps .graph-solde-mt { font-size: 1.6rem; }
.graph-solde-mot { font-size: .75rem; color: var(--color-muted); }
.graph-solde--pos .graph-solde-mt { color: var(--color-success); }
.graph-solde--neg .graph-solde-mt { color: var(--color-danger); }
.graph-solde--nul .graph-solde-mt { color: var(--color-muted); }
a.graph-solde:hover .graph-solde-mot,
a.graph-solde:focus-visible .graph-solde-mot { text-decoration: underline; color: var(--color-text); }

.graph-legende {
    display: flex; flex-wrap: wrap; justify-content: center; gap: .3rem 1rem;
    font-size: .78rem; color: var(--color-muted); margin-top: .5rem;
}
.graph-legende > span { display: inline-flex; align-items: center; gap: .35rem; }
.graph-pastille {
    display: inline-block; flex: 0 0 auto;
    width: .65rem; height: .65rem; border-radius: 50%;
}
.graph-pastille--entree { background: var(--color-success); }
.graph-pastille--sortie { background: var(--color-danger); }

/* Les mois : une case par mois écoulé, six par ligne comme un
   calendrier (janvier → juin, juillet → décembre) : chaque mois garde sa
   place d'une année à l'autre, et l'année finie fait deux rangées pleines.
   Un nombre de colonnes réglé sur la largeur donnait 8 puis 2. */
.graph-mois-grille {
    display: grid; grid-template-columns: repeat(6, minmax(0, 1fr));
    gap: .9rem .75rem;
}
.graph-mois {
    position: relative;
    display: flex; flex-direction: column; align-items: center; gap: .45rem;
    min-width: 0; padding: .7rem .4rem;
    border: 1px solid var(--color-border); border-radius: var(--radius);
    scroll-margin-top: calc(80px + var(--env-h, 0px));
}
.graph-annee { scroll-margin-top: calc(80px + var(--env-h, 0px)); }
.graph-mois-nom { font-weight: 600; text-align: center; }
/* Le mois en cours : sa pastille à cheval sur le bord haut, comme un
   onglet — elle ne prend aucune hauteur dans la case. */
.graph-mois--en-cours { border-color: var(--color-info); }
.graph-mois-repere {
    position: absolute; top: 0; left: 50%; transform: translate(-50%, -50%);
    line-height: 1; white-space: nowrap;
}
@media (max-width: 1000px) {
    .graph-mois-grille { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* Les douze mois côte à côte, à la même échelle. */
.graph-barres {
    display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: 4px;
}
.graph-barres-mois { display: flex; flex-direction: column; gap: .3rem; min-width: 0; }
/* Toute la hauteur de la colonne d'une barre se survole ; elle se teinte
   légèrement pour dire laquelle est visée. */
.graph-barre-cible { fill: transparent; }
.graph-lien:hover .graph-barre-cible,
.graph-lien:focus-visible .graph-barre-cible { fill: var(--color-surface-alt); }
.graph-lien:hover .graph-barre,
.graph-lien:focus-visible .graph-barre { opacity: .8; }
.graph-barres-zone { display: block; height: 150px; border-bottom: 1px solid var(--color-border-strong); }
.graph-barres-svg { display: block; width: 100%; height: 100%; }
.graph-barre--entree { fill: var(--color-success); }
.graph-barre--sortie { fill: var(--color-danger); }
.graph-barres-nom { font-size: .7rem; color: var(--color-muted); text-align: center; text-decoration: none; }
a.graph-barres-nom:hover,
a.graph-barres-nom:focus-visible { color: var(--color-text); text-decoration: underline; }

/* Le détail d'un côté : dans la bulle qui suit la souris, ou dans la
   fenêtre ouverte au doigt (les deux côtés et leurs boutons). */
.graph-bulle {
    position: fixed; z-index: 1000; pointer-events: none;
    width: max-content; max-width: min(340px, calc(100vw - 16px));
    padding: .6rem .75rem; font-size: .8rem;
    background: var(--color-surface); color: var(--color-text);
    border: 1px solid var(--color-border); border-radius: var(--radius);
    box-shadow: var(--shadow-md);
}
.graph-apercu-tete { display: flex; align-items: center; gap: .4rem; font-weight: 700; }
.graph-apercu-total { margin-left: auto; padding-left: .9rem; white-space: nowrap; }
.graph-apercu-sous { margin: .15rem 0 .35rem; font-size: .72rem; color: var(--color-muted); }
.graph-apercu-liste { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .25rem; }
.graph-apercu-liste li { display: flex; align-items: baseline; gap: .5rem; min-width: 0; }
.graph-apercu-date { flex: 0 0 auto; font-size: .72rem; color: var(--color-muted); font-variant-numeric: tabular-nums; }
.graph-apercu-desc { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.graph-apercu-mt { flex: 0 0 auto; font-weight: 600; font-variant-numeric: tabular-nums; }
.graph-apercu-indice { margin: .45rem 0 0; font-size: .72rem; color: var(--color-muted); }
.graph-bulle .graph-apercu-btn { display: none; }
.graph-fenetre-corps .graph-apercu-indice { display: none; }
.graph-fenetre-corps .graph-apercu-btn { margin-top: .6rem; }
.graph-fenetre-corps .graph-apercu-cote + .graph-apercu-cote {
    margin-top: 1rem; padding-top: 1rem; border-top: 1px solid var(--color-border);
}
.graph-fenetre-corps .graph-apercu-tout { display: flex; justify-content: center; margin-top: 1.1rem; }

/* La liste complète (fenêtre ouverte par le serveur). */
.graph-liste-resume {
    display: flex; flex-wrap: wrap; align-items: baseline; gap: .3rem 1rem;
    margin-bottom: .6rem; font-weight: 600;
}
.graph-liste-resume .graph-solde { flex-direction: row; align-items: baseline; gap: .35rem; }
.graph-liste-resume .graph-solde-mt { font-size: 1rem; }
.graph-liste-tri { margin-bottom: .75rem; }

@media (max-width: 768px) {
    .graph-camembert--grand { width: 180px; }
    .graph-mois-grille { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .6rem; }
    .graph-mois .graph-camembert { width: 100px; }
    .graph-barres { gap: 2px; }
    .graph-barres-zone { height: 110px; }
    .graph-barres-nom { font-size: .6rem; }
}

/* ███████████████████████████████████████████████████████████████
   9. ÉCRANS — ÉCOLE ARABE
   ███████████████████████████████████████████████████████████████ */

/* ── Fenêtre Échéancier ──
   Deux sections, chacune avec son bouton dans son fil ; le pied de la
   fenêtre ne porte que « Fermer ». Champs habillés comme ceux de la
   fenêtre d'encaissement — ils avaient l'apparence brute du navigateur. */
.ecole-ech-section { margin-bottom: 1.25rem; }
.ecole-ech-section h3 { margin: 0 0 .35rem; }
.ecole-ech-auto { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 0 .75rem; }
.ecole-ech-auto .form-group { flex: 1 1 9rem; margin-bottom: .6rem; }
.ecole-ech-auto .ecole-ech-note { flex: 1 1 100%; margin: 0 0 .6rem; }
.ecole-ech-lignes { display: flex; flex-direction: column; gap: .4rem; margin-top: .5rem; }
.ecole-ech-ligne { display: flex; gap: .4rem; }
.ecole-ech-ligne input {
    padding: .4rem .5rem; font-size: .9rem; min-width: 0;
    border: 1px solid var(--color-border); border-radius: var(--radius);
    background: var(--color-surface); color: var(--color-text);
}
/* Plus précis que la règle globale des champs date (pleine largeur). */
.ecole-ech-ligne input[type="date"] { flex: 1 1 10rem; width: auto; }
.ecole-ech-ligne input[name="montant[]"] { flex: 0 0 8rem; text-align: right; font-variant-numeric: tabular-nums; }
.ecole-enc-bilan.ecole-ech-juste { background: var(--color-success-lt); color: var(--color-success); }
.ecole-ech-suppr { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; margin-bottom: .5rem; }

/* Sommaire d'ancres — fiche famille. */
.ecole-ancres {
    display: flex; flex-wrap: wrap; gap: .4rem;
    margin-bottom: 1rem;
}
.ecole-ancres a {
    font-size: .8rem; padding: .3rem .7rem; border-radius: 999px;
    background: var(--color-surface-alt); color: var(--color-muted);
    text-decoration: none; white-space: nowrap;
}
.ecole-ancres a:hover { background: var(--color-border); color: var(--color-text); }

/* Sur petit écran : le défilement au doigt laissait le dernier
   raccourci coupé net au bord de l'écran, comme une erreur d'affichage
   plutôt qu'une invitation à glisser. Une grille bien alignée tient
   les cinq raccourcis entiers, sans rien à découvrir. */
@media (max-width: 768px) {
    .ecole-ancres {
        display: grid;
        grid-template-columns: repeat(3, 1fr);
        gap: .4rem;
    }
    .ecole-ancres a {
        display: flex; align-items: center; justify-content: center;
        gap: .35rem;   /* en flex, l'espace entre l'icône et son mot disparaît */
        text-align: center; white-space: normal;
    }
    /* Un geste principal et son « ⋯ » sur la même ligne : empilé, le
       « ⋯ » prenait une ligne entière pour un bouton de trois points. */
    .card-header:has(.ecole-actions) .ecole-actions:has(> .menu-plus) { flex-direction: row; }
    .card-header:has(.ecole-actions) .ecole-actions:has(> .menu-plus) > * { flex: 1 1 auto; width: auto; }
    .card-header:has(.ecole-actions) .ecole-actions > .menu-plus { flex: 0 0 auto; }
}

/* ═══════════════════════════════════════════════════
   FICHE FAMILLE — refonte B2·3, étape 4 (maquette 3-fiche-famille)
   ═══════════════════════════════════════════════════
   Un bandeau d'identité, puis deux colonnes : les sections repliables à
   gauche, le Dossier et les derniers paiements à droite (340 px). Une
   colonne sous 1100 px, le Dossier en tête. Sur téléphone, « Encaisser »
   et « ⋯ Plus » sont fixés en bas de l'écran. */

/* ── Retour à la liste et année, sur une ligne au-dessus du bandeau ──
   Le menu d'année règle toute la page : il reste en haut, discret. */
.fiche-haut {
    display: flex; align-items: center; justify-content: space-between;
    gap: .75rem; margin-bottom: .55rem;
}
.fiche-haut .lien-retour { margin: 0; font-size: .9rem; font-weight: 600; color: var(--color-primary); }
.ecole-fiche-annee { display: flex; align-items: center; gap: .4rem; margin: 0; }
.ecole-fiche-annee select {
    min-height: 36px; padding: .25rem .9rem; font-size: .85rem;
    border: 1px solid var(--color-border-strong); border-radius: 999px;
    background-color: var(--color-surface); color: var(--color-text);
}
/* Sans cette marge, l'ancre atterrit sous la barre du haut. */
.card-header[id] { scroll-margin-top: 70px; }

/* ── Bandeau d'identité ──
   Pas une .card : rien ne doit y couper ce qui dépasse (menus), ni y
   poser de transformation — sur téléphone ses gestes sont en position
   fixe, calés sur l'écran. */
.fiche-identite {
    display: flex; align-items: center; flex-wrap: wrap; gap: .75rem 1rem;
    padding: 1.05rem 1.3rem; margin-bottom: .9rem;
    background: var(--color-surface); border-radius: var(--radius-lg); box-shadow: var(--shadow);
}
.fiche-id-rond {
    display: grid; place-items: center; flex: none;
    width: 56px; height: 56px; border-radius: 50%;
    background: var(--color-primary-mid); color: var(--color-primary);
    font-family: var(--font-title); font-weight: 700; font-size: 1.1rem;
}
.fiche-id-texte { flex: 1 1 14rem; min-width: 0; }
.fiche-id-texte h1 { margin: 0; font-size: 1.65rem; font-weight: 600; line-height: 1.15; overflow-wrap: anywhere; }
.fiche-id-sous { color: var(--color-muted); font-size: .95rem; font-variant-numeric: tabular-nums; }
.fiche-id-sous .lien-tel { color: inherit; }
.fiche-id-contact, .fiche-id-gestes { display: flex; align-items: center; gap: .5rem; }
/* Passés à la ligne (tablette), les gestes restent calés à droite. */
.fiche-id-gestes { margin-left: auto; }
.fiche-identite .btn .icone { flex: none; }
/* Le geste qu'on vient faire au guichet : plus grand que les autres. */
.fiche-id-encaisser.btn { min-height: 52px; padding: 0 1.6rem; font-size: 1rem; }

/* ── Deux colonnes ── */
.fiche-cols { display: flex; flex-direction: column; gap: .75rem; }
.fiche-sections { display: flex; flex-direction: column; gap: .6rem; min-width: 0; }
.fiche-cote { order: -1; display: flex; flex-direction: column; gap: .75rem; min-width: 0; }
/* Conteneurs en flex : leur « gap » fait l'écart, pas la marge commune
   des cartes empilées (.card + .card). */
:is(.fiche-sections, .fiche-cote) > .card + .card { margin-top: 0; }
/* Tablette : Dossier et derniers paiements côte à côte, plutôt que trois
   chiffres étirés sur toute la largeur. */
@media (min-width: 769px) and (max-width: 1099px) {
    .fiche-cote { flex-direction: row; align-items: flex-start; }
    .fiche-cote > .card { flex: 1 1 0; min-width: 0; }
}
@media (min-width: 1100px) {
    .fiche-cols { display: grid; grid-template-columns: minmax(0, 1fr) 340px; gap: 1rem; align-items: start; }
    .fiche-cote { order: 0; }
}

/* ── Sections repliables : titre · pilule de résumé · chevron à droite ── */
details.ecole-fiche-section { scroll-margin-top: calc(var(--nav-h) + var(--env-h) + 12px); }
details.ecole-fiche-section > summary { padding: 0 1.2rem; border-bottom: none; }
details.ecole-fiche-section > summary .pliable-entete { min-height: 58px; }
details.ecole-fiche-section > summary .pliable-titre {
    flex: 1 1 auto; min-width: 0; flex-wrap: nowrap; gap: .6rem;
    padding: .55rem 0; font-size: 1rem;
}
details.ecole-fiche-section > summary .pliable-libelle {
    display: inline-flex; align-items: center; gap: .5rem;
    flex: none; white-space: nowrap;
}
details.ecole-fiche-section > summary .pliable-libelle .icone { flex: none; color: var(--color-muted); }
/* Le résumé part à droite, contre le chevron ; une bulle ⓘ reste collée
   au titre qu'elle explique. */
details.ecole-fiche-section > summary .pliable-titre:not(:has(> .aide)) > .pliable-libelle,
details.ecole-fiche-section > summary .pliable-titre > .aide { margin-right: auto; }
details.ecole-fiche-section > summary .pliable-compte {
    flex: 0 1 auto; min-width: 0; text-align: right;
    padding: .2rem .75rem; border-radius: 14px;
    background: var(--color-neutral-soft); color: var(--color-text);
    font-family: var(--font); font-size: .8rem; font-weight: 700;
}
details.ecole-fiche-section > summary .badge { flex: 0 1 auto; font-family: var(--font); text-align: right; }
/* Le chevron : un « › » dessiné, qui pointe vers le bas une fois ouvert.
   Sélecteurs plus précis que ceux de .pliable, qu'ils remplacent. */
details.ecole-fiche-section:is([open], :not([open])) > summary .pliable-chevron {
    order: 9; flex: none; width: 9px; height: 9px; margin: 0 .35rem 0 .15rem;
    font-size: 0; border: solid var(--color-muted); border-width: 0 2px 2px 0;
    transform: rotate(-45deg);
}
details.ecole-fiche-section[open] > summary .pliable-chevron { transform: rotate(45deg) translate(-2px, -2px); }
details.ecole-fiche-section > .card-body { padding: .2rem 1.2rem 1.15rem; }
/* Les boutons d'une section ouvrent son corps, alignés à droite. Ils ne
   sont pas dans le titre : un bouton posé dans un <summary> replie la
   carte à chaque clic. */
.ecole-fiche-outils {
    display: flex; flex-wrap: wrap; justify-content: flex-end; align-items: center;
    gap: .4rem; margin: 0 0 .9rem;
}
/* Une section sans aucun bouton pour ce compte n'a pas à garder la marge. */
.ecole-fiche-outils:not(:has(*)) { display: none; }

/* ── Enfants : une carte par enfant ── */
.fiche-enfants { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: .75rem; }
.fiche-enfant {
    display: grid; grid-template-columns: minmax(0, 1fr) auto; align-content: start; gap: .5rem .6rem;
    padding: .8rem .9rem; border: 1px solid var(--color-border); border-radius: 14px;
    font-size: .9rem;
}
.fiche-enfant > * { grid-column: 1 / -1; min-width: 0; }
.fiche-enfant > .fiche-enfant-nom { grid-column: 1; }
.fiche-enfant > .fiche-enfant-statut { grid-column: 2; grid-row: 1; max-width: 10rem; text-align: right; }
.fiche-enfant-avant { font-size: .8rem; color: var(--color-muted); }
.fiche-enfant-gestes { padding-top: .55rem; border-top: 1px solid var(--color-border); }
.fiche-enfant-gestes:not(:has(.btn)) { display: none; }
/* Annulé ou archivé : en retrait, l'œil va d'abord à ceux qui suivent
   les cours. */
.fiche-enfant.ecole-enfant--retrait { background: var(--color-surface-alt); color: var(--color-muted); }

/* ── Colonne de droite : Dossier, derniers paiements ── */
.fiche-cote > .card { overflow: visible; }
.fiche-carte-titre { display: flex; align-items: center; gap: .5rem; }
.fiche-carte-titre h2 {
    display: inline-flex; align-items: center; gap: .5rem; flex: 1 1 auto; min-width: 0;
    margin: 0; font-size: 1rem; font-weight: 600;
}
.fiche-carte-titre h2 .icone { flex: none; color: var(--color-muted); }
.fiche-dossier { padding: 1rem 1.15rem 1.05rem; scroll-margin-top: calc(var(--nav-h) + var(--env-h) + 12px); }
.fiche-dossier-chiffres { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); align-items: end; gap: .5rem; margin-top: .75rem; }
.fiche-chiffre-lib { display: block; font-size: .78rem; font-weight: 600; color: var(--color-muted); }
.fiche-chiffre {
    display: block; font-family: var(--font-title); font-size: 1.2rem; font-weight: 600;
    font-variant-numeric: tabular-nums; white-space: nowrap;
}
.fiche-chiffre--ok    { color: var(--color-success); }
.fiche-chiffre--reste { color: var(--color-danger); }
.fiche-jauge { height: 10px; margin: .65rem 0 .55rem; border-radius: 5px; background: var(--color-neutral-soft); overflow: hidden; }
.fiche-jauge span { display: block; height: 100%; border-radius: 5px; background: var(--color-success); }
.fiche-dossier-ligne { margin: .25rem 0 0; font-size: .85rem; }
.fiche-dossier-retard { color: var(--color-danger); }
.fiche-ech { margin-top: .7rem; padding-top: .55rem; border-top: 1px solid var(--color-border); }
.fiche-ech > summary { cursor: pointer; font-size: .88rem; font-weight: 600; color: var(--color-primary); }
.fiche-ech ul { list-style: none; margin: .45rem 0 0; padding: 0; }
.fiche-ech li {
    display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: .6rem;
    padding: .4rem 0; border-top: 1px solid var(--color-border);
    font-size: .85rem; font-variant-numeric: tabular-nums;
}
.fiche-ech-montant { font-weight: 600; }
.fiche-ech-montant .ecole-sub { display: block; font-weight: 400; }

.fiche-derniers > .fiche-carte-titre { padding: .9rem 1.15rem .55rem; }
.fiche-dernier {
    display: flex; align-items: center; gap: .6rem;
    padding: .6rem 1.15rem; border-top: 1px solid var(--color-border);
}
.fiche-dernier-txt { flex: 1 1 auto; min-width: 0; font-size: .9rem; }
.fiche-dernier-txt > .text-muted { display: block; font-size: .8rem; }
.fiche-dernier-montant { flex: none; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--color-success); }
.fiche-dernier-montant--sortie { color: var(--color-danger); }
.fiche-derniers-tous {
    display: block; padding: .65rem 1.15rem; border-top: 1px solid var(--color-border);
    font-size: .9rem; font-weight: 600; color: var(--color-primary); text-decoration: none;
}
.fiche-derniers-tous:hover { text-decoration: underline; }

@media (max-width: 768px) {
    .fiche-identite { padding: .95rem; gap: .7rem .75rem; }
    .fiche-id-rond { width: 48px; height: 48px; font-size: 1rem; }
    .fiche-id-texte { flex-basis: 0; }
    .fiche-id-texte h1 { font-size: 1.3rem; }
    /* « Appeler » et « WhatsApp » se partagent la ligne à parts égales. */
    .fiche-id-contact { flex: 1 1 100%; }
    .fiche-id-contact > * { flex: 1 1 0; min-width: 0; }
    .fiche-id-contact > .menu-plus > .btn { width: 100%; }
    .fiche-id-contact > .menu-plus:first-child > .menu-plus-list { left: 0; right: auto; }
    /* Sans « Encaisser » (compte en consultation, année close) : « ⋯ Plus »
       reste dans le bandeau, sur toute la largeur. */
    .fiche-identite:not(.fiche-identite--barre) .fiche-id-gestes { flex: 1 1 100%; }
    .fiche-identite:not(.fiche-identite--barre) .fiche-id-gestes > .menu-plus,
    .fiche-identite:not(.fiche-identite--barre) .fiche-id-gestes > .menu-plus > .btn { width: 100%; }
    /* Avec « Encaisser » : les deux gestes sont fixés en bas de l'écran,
       à la place de la barre du module (includes/footer.php,
       $barreBasPage). Le menu s'ouvre vers le haut. */
    .fiche-identite--barre .fiche-id-gestes {
        position: fixed; left: 0; right: 0; bottom: 0; z-index: 900;
        gap: 8px; padding: 10px 14px max(10px, env(safe-area-inset-bottom, 0px));
        background: var(--color-surface); border-top: 1px solid var(--color-border);
    }
    .fiche-identite--barre .fiche-id-encaisser { order: -1; flex: 1 1 auto; }
    .fiche-identite--barre .fiche-id-gestes .btn { min-height: 52px; }
    .fiche-identite--barre .fiche-id-gestes .menu-plus-list { top: auto; bottom: calc(100% + 8px); }

    details.ecole-fiche-section > summary { padding: 0 .9rem; }
    details.ecole-fiche-section > summary .pliable-entete { min-height: 52px; }
    details.ecole-fiche-section > .card-body { padding: .2rem .9rem 1rem; }
    /* Un geste principal et son « ⋯ » sur une ligne : le bouton prend la
       place, le « ⋯ » garde la sienne. */
    .ecole-fiche-outils > .btn { flex: 1 1 auto; justify-content: center; }
    .ecole-fiche-outils > .menu-plus { flex: 0 0 auto; }
    .ecole-fiche-outils > .menu-plus:only-child,
    .ecole-fiche-outils > .menu-plus:first-child:not(:only-child) { flex: 1 1 auto; }
    .ecole-fiche-outils > .menu-plus:first-child > .btn { width: 100%; justify-content: center; }
    /* Un menu au libellé long (« Bilan de l'année ▾ ») ne tient pas à côté
       d'« Ajouter un enfant » : il prend la même largeur, dessous. */
    .ecole-fiche-outils > .menu-plus--large { flex: 1 1 100%; }
    .ecole-fiche-outils > .menu-plus--large > .btn { width: 100%; justify-content: center; }
    /* Menu posé à gauche : son panneau s'ouvre vers la droite, sinon il
       sortirait de l'écran par la gauche. */
    .ecole-fiche-outils > .menu-plus:first-child:not(:only-child) > .menu-plus-list { left: 0; right: auto; }
    .fiche-enfants { grid-template-columns: minmax(0, 1fr); }
}
@media print { .fiche-identite--barre .fiche-id-gestes { position: static; } }

/* Registre en mobilité.
   Neuf colonnes ne tiennent pas sur un téléphone, et le registre se
   consulte souvent debout, un parent en face : la date, la famille et
   le montant suffisent pour lui répondre. Le mode et le compte sont
   repliés sous le nom plutôt que supprimés — masquer une information
   sans la remplacer, c'est la perdre. */
/* Colonne de sélection dans la liste des opérations. */
.ops-th-sel, .ops-td-sel { width: 2.5rem; text-align: center; }
.ops-td-sel input:disabled { opacity: .35; cursor: not-allowed; }

/* Barre de sélection multiple — dé-rapprochement en lot. */
.rp-lot-barre {
    display: flex; align-items: center; justify-content: space-between;
    gap: 1rem; flex-wrap: wrap;
    margin-top: 1rem; padding-top: .85rem;
    border-top: 1px solid var(--color-border);
}
/* La barre du haut porte son trait en dessous, pas au-dessus. */
.rp-lot-barre--haut {
    margin-top: 0; margin-bottom: 1rem;
    padding-top: 0; padding-bottom: .85rem;
    border-top: none; border-bottom: 1px solid var(--color-border);
}

/* Sélecteur du nombre de lignes par page. */
.ops-pp-form { display: inline-flex; align-items: center; }
.ops-pp-form label { font-size: .82rem; color: var(--color-muted); }
.ops-pp-form select { margin: 0 .3rem; font-size: .82rem; }

/* Cartes repliables : l'ancien .card--pliable a rejoint le repli commun
   details.pliable (étape E de la remise en ordre). */
details.card.pliable { scroll-margin-top: 70px; }

/* Cases à cocher des options facturées. */
.ecole-option {
    display: flex; align-items: flex-start; gap: .5rem;
    padding: .35rem 0; font-size: .88rem;
}
.ecole-option input { margin-top: .2rem; flex-shrink: 0; }

/* Champs saisis DANS un tableau (barème, options de l'école) : hors
   .form-group, ils gardaient l'allure brute du navigateur — bordure fine,
   coins carrés, hauteur à part. Même habillage que les autres champs. */
.ecole-table-saisie td { vertical-align: middle; }
.ecole-table-saisie input[type="text"] {
    width: 100%; padding: .5rem .75rem;
    border: 1px solid var(--color-border-strong); border-radius: var(--radius);
    font-size: .9rem; font-family: var(--font);
    background: var(--color-surface); color: var(--color-text);
    transition: border-color var(--transition), box-shadow var(--transition);
}
.ecole-table-saisie input[type="text"]:focus {
    outline: none; border-color: var(--color-primary);
    box-shadow: 0 0 0 3px var(--color-primary-ring);
}
.ecole-table-saisie input[type="checkbox"] { width: 1.1rem; height: 1.1rem; }
/* Un montant : aligné à droite, chiffres de même largeur, « € » collé. */
.ecole-montant-champ { display: inline-flex; align-items: center; gap: .35rem; white-space: nowrap; }
.ecole-montant-champ input[type="text"] { width: 7rem; text-align: right; font-variant-numeric: tabular-nums; }
.ecole-table-saisie .ecole-num { text-align: right; font-variant-numeric: tabular-nums; }
.ecole-table-saisie .ecole-centre { text-align: center; }
@media (max-width: 768px) {
    /* En carte (.table-mobile), le libellé de la cellule est à gauche :
       le champ prend le reste de la ligne. */
    .ecole-table-saisie.table-mobile td > input[type="text"] { width: 60%; }
    /* La première cellule est le titre de la carte, sans libellé à côté :
       son champ prend toute la ligne. */
    .ecole-table-saisie.table-mobile td:first-child > input[type="text"] { width: 100%; }
    .ecole-table-saisie .ecole-centre { text-align: right; }
}

/* Gestes d'une ligne du registre et des paiements de la fiche : sur
   téléphone, « Modifier » vit en tête du menu « ⋯ » (voir
   actionsOperationEcole()), sur ordinateur en bouton à côté. Sélecteurs à
   deux classes : .menu-plus-list > button pose son propre display. */
@media (min-width: 769px) {
    .ecole-geste > .ecole-geste-mobile,
    .menu-plus-list > .ecole-geste-mobile { display: none; }
}
@media (max-width: 768px) {
    .ecole-geste > .ecole-geste-bureau { display: none; }
}

/* Blocs titrés d'une fenêtre de saisie (« Modifier la famille »,
   « Modifier la classe ») : un encadré par sujet, pour qu'on sache ce
   qu'on modifie — et chez qui. */
.ecole-famille-bloc,
.ecole-bloc-form {
    border: 1px solid var(--color-border); border-radius: var(--radius);
    padding: .5rem 1rem .25rem; margin: 0 0 1rem; min-width: 0;
}
.ecole-famille-bloc legend,
.ecole-bloc-form legend { font-weight: 600; font-size: .9rem; padding: 0 .35rem; }
.ecole-famille-bloc > .ecole-sub { margin: 0 0 .75rem; }
/* Code postal et ville se lisent ensemble : une ligne, la ville prend le
   reste. Tient aussi à 375 px — cinq chiffres n'ont pas besoin de plus. */
.ecole-famille-cpville { display: grid; grid-template-columns: 7rem minmax(0, 1fr); gap: 0 .75rem; }
@media (max-width: 768px) {
    .ecole-famille-bloc,
    .ecole-bloc-form { padding: .4rem .75rem .1rem; }
    .ecole-famille-cpville { grid-template-columns: 6rem minmax(0, 1fr); }
}

/* ── Fenêtre « Modifier la classe » ──
   Les champs courts partagent une ligne ; l'explication d'un champ est
   dans son ⓘ, posé à côté du libellé (.ecole-champ-tete). */
.ecole-champs-ligne { display: grid; gap: 0 .75rem; }
.ecole-champs-ligne--code { grid-template-columns: 7rem minmax(0, 1fr); }
.ecole-champs-ligne--egal { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
.ecole-champ-tete { display: flex; align-items: center; gap: .35rem; margin-bottom: .35rem; }
.form-group .ecole-champ-tete > label { margin: 0; }
.ecole-champ-court { max-width: 8rem; }
.ecole-bloc-form legend .aide { vertical-align: middle; }

/* Un créneau : le jour, puis « de … à … » et « Retirer ». Les menus
   gardent la largeur de « 10h45 », le jour prend le reste. */
.ecole-creneau-ligne {
    display: flex; flex-wrap: wrap; align-items: center; gap: .4rem .5rem;
    margin-bottom: .5rem;
}
.ecole-creneau-ligne > .ecole-creneau-jour { flex: 1 1 7rem; min-width: 0; }
.ecole-creneau-heures { display: flex; align-items: center; gap: .4rem; flex: 0 0 auto; }
.ecole-creneau-heures select { width: 5.5rem; min-width: 0; }
/* Hors .form-group : les menus d'un créneau reprennent l'habillage des
   autres champs de la fenêtre, sinon ils paraissent plus fins qu'eux. */
.ecole-creneau-ligne select {
    padding: .5rem .6rem; font-size: .9rem; font-family: var(--font);
    border: 1px solid var(--color-border-strong); border-radius: var(--radius);
    background: var(--color-surface); color: var(--color-text);
}

/* Annuler / Enregistrer collés en bas de la fenêtre, qui défile : sans
   cela il fallait descendre jusqu'au fond pour enregistrer. Les marges
   négatives reprennent le rembourrage de .modal-body. */
.ecole-modal-groupe .modal-actions {
    position: sticky; bottom: 0; z-index: 2;
    margin: 1rem -20px -16px; padding: .75rem 20px;
    background: var(--color-surface);
}

@media (max-width: 768px) {
    /* Plein écran, comme la fenêtre de répartition : à 375 px une fenêtre
       centrée avec ses marges ne laissait pas la place d'un formulaire. */
    .modal-overlay:has(.ecole-modal-groupe) { padding: 0; }
    .ecole-modal-groupe {
        max-width: none; width: 100%;
        max-height: 100vh; min-height: 100vh;
        border-radius: 0;
    }
    /* Type et enseignant, deux menus à libellés longs : l'un sous l'autre. */
    .ecole-champs-ligne--egal { grid-template-columns: minmax(0, 1fr); }
    .ecole-champs-ligne--code { grid-template-columns: 5.5rem minmax(0, 1fr); }
    /* Le jour sur sa ligne, « de … à … Retirer » sur la suivante. */
    .ecole-creneau-ligne > .ecole-creneau-jour { flex-basis: 100%; }
    .ecole-creneau-heures { flex: 1 1 100%; }
    .ecole-creneau-heures select { flex: 1 1 0; width: auto; }
    .ecole-creneau-ligne { padding-bottom: .5rem; border-bottom: 1px dashed var(--color-border); }
}

.col-repli { display: none; }
@media (max-width: 768px) {
    .col-secondaire { display: none; }
    .col-repli      { display: block; }
}
/* Registre sur téléphone : trois colonnes (famille, montant, actions)
   débordaient de quelques pixels et le tableau défilait de côté. Des
   cellules moins rembourrées suffisent. */
@media (max-width: 768px) {
    .ecole-registre-table th,
    .ecole-registre-table td { padding-left: .45rem; padding-right: .45rem; }
    .ecole-registre-table .ecole-geste { gap: .3rem; }
    /* La colonne des cases à cocher (sélection en lot) n'a besoin que de
       la largeur d'une case. */
    .ecole-registre-table .ecole-lot-col { padding-left: .35rem; padding-right: 0; width: 1.5rem; }
    .ecole-registre-table td.ecole-actions,
    .ecole-registre-table th:last-child { padding-right: .2rem; }
}

/* Un paiement en plusieurs règlements tient en une ligne ; « Détail »
   déplie ses règlements dessous, en retrait sur un fond à peine teinté,
   pour qu'on voie qu'ils appartiennent à la ligne du dessus. */
.ecole-versement-ligne > td { background: var(--color-surface-alt); }
.ecole-versement-ligne > td.ecole-reg-objet { padding-left: 1.5rem; }
/* Le nom de la famille est sur la ligne du paiement, juste au-dessus :
   le répéter sur chaque règlement ne dit rien de plus. */
.ecole-versement-ligne > td.ecole-reg-objet > strong:first-child { display: none; }
.ecole-versement--ouvert > td { border-bottom-color: transparent; }
.ecole-versement-fleche { display: inline-block; transition: transform .15s; }
.ecole-versement--ouvert .ecole-versement-fleche { transform: rotate(90deg); }
@media (max-width: 768px) {
    .ecole-versement-ligne > td.ecole-reg-objet { padding-left: 1rem; }
}
.ecole-soldes-ligne {
    display: flex; flex-wrap: wrap; gap: 1rem;
    align-items: center; justify-content: space-between;
}
/* Barre d'encaissement en lot : la date de passage en banque, collée au
   bouton qu'elle accompagne. */
.ecole-lot-date { display: flex; align-items: center; gap: .4rem; margin: 0 0 0 auto;
    font-size: .85rem; color: var(--color-muted); }
/* Hors .form-group, aucun habillage ne s'applique : le champ gardait le
   cadre brut du navigateur (remarque de l'utilisateur). Même allure que
   les champs de la fenêtre d'encaissement (.ecole-enc-ligne input). */
.ecole-lot-date input[type="date"] {
    width: auto; padding: .25rem .5rem; font-size: .85rem;
    font-family: var(--font);
    border: 1px solid var(--color-border); border-radius: var(--radius);
    background: var(--color-surface); color: var(--color-text);
}
/* Téléphone : « Tout sélectionner » prend sa ligne, la date et le bouton
   se rangent côte à côte dessous — calée à droite, la date laissait le
   bouton seul à gauche sur la ligne suivante. */
@media (max-width: 768px) {
    .ecole-lot-barre .ecole-soldes-ligne { gap: .6rem; }
    .ecole-lot-barre .ecole-soldes-ligne > div:first-child { flex: 1 1 100%; }
    .ecole-lot-date { margin-left: 0; }
}

/* Tableau de bord école — rangées de tuiles. */
/* La marge haute sépare deux rangées de tuiles qui ne parlent pas de la
   même chose (l'année scolaire en cours, puis l'argent en caisse toutes
   années confondues) : sans elle, le titre se colle au texte de la
   rangée précédente et la coupure ne se voit plus. */
.ecole-titre-rangee {
    font-size: .9rem; font-weight: 600;
    color: var(--color-text-tertiary);
    margin: 1.6rem 0 .5rem;
}
/*  Carte « En caisse » de l'accueil : les tuiles du Registre, sans la
    marge basse de .stats-grid — le bouton des caisses suit de près. */

/* Jauge de la part encaissée. */
.ecole-jauge {
    height: 4px; border-radius: 2px; margin-top: 8px;
    background: var(--color-border); overflow: hidden;
}
.ecole-jauge span {
    display: block; height: 100%; border-radius: 2px;
    background: var(--color-primary-fond);
}

/* Paramètres */
.params-cp-grid { display: grid; grid-template-columns: 90px 1fr; gap: .75rem; }
.params-separator { margin: 1rem 0; border-color: var(--color-border); }
.params-section-label {
    font-size: .9rem; font-weight: 600;
    color: var(--color-muted); margin-bottom: .75rem;
}
.params-section-small { font-weight: 400; }
@media (max-width: 768px) { .params-cp-grid { grid-template-columns: 1fr; } }

/* ── Fenêtre d'encaissement : les règlements « en plus » ──
   Une ligne par règlement ajouté au principal (mélange de modes). Le
   champ de date ne se montre que sur une ligne en chèque — mais reste
   dans le formulaire sur les autres : les listes r_*[] doivent garder le
   même nombre d'éléments pour que chaque montant retrouve son mode. */
.ecole-enc-lignes { display: flex; flex-direction: column; gap: .45rem; }
.ecole-enc-ligne {
    display: flex; flex-wrap: wrap; align-items: center; gap: .4rem;
    padding: .5rem; border-radius: 6px;
    background: var(--color-surface-alt);
    border-left: 3px solid var(--color-border-strong);
}
.ecole-enc-ligne--cheque { border-left-color: var(--color-ecole); }
.ecole-enc-ligne select,
.ecole-enc-ligne input {
    padding: .4rem .5rem; font-size: .9rem; min-width: 0;
    border: 1px solid var(--color-border); border-radius: var(--radius);
    background: var(--color-surface); color: var(--color-text);
}
.ecole-enc-ligne .enc-mode    { flex: 0 0 8rem; }
.ecole-enc-ligne .enc-montant { flex: 0 0 6rem; text-align: right; font-variant-numeric: tabular-nums; }
.ecole-enc-ligne .ecole-enc-quand {
    flex: 1 1 11rem; min-width: 0; display: flex; align-items: center; gap: .35rem;
    font-size: .8rem; color: var(--color-muted); margin: 0;
}
.ecole-enc-ligne .ecole-enc-quand input[type="date"] { width: auto; flex: 1; }
.ecole-enc-ligne .enc-retirer { margin-left: auto; }
.ecole-enc-ligne .enc-cheque { display: none; }
.ecole-enc-ligne--cheque .ecole-enc-quand { display: flex; }
.ecole-enc-boutons { display: flex; flex-wrap: wrap; gap: .4rem; margin: .5rem 0; }
.ecole-enc-bilan {
    padding: .55rem .75rem; margin: .25rem 0 1rem; border-radius: 6px;
    background: var(--color-ecole-lt); font-size: .9rem; font-variant-numeric: tabular-nums;
}
.ecole-enc-alerte { color: var(--color-danger); font-weight: 600; }
.ecole-enc-etaler { display: flex; flex-wrap: wrap; gap: 0 1rem; }
.ecole-enc-etaler .form-group { flex: 1 1 12rem; }
.ecole-enc-apres { display: flex; flex-wrap: wrap; gap: .4rem; margin-top: .5rem; }

/* ── Fenêtre « Encaisser », refonte B2·3 (maquette 4-fenetre-encaisser) ──
   Le montant en très gros, quatre tuiles de mode, la date et le compte
   côte à côte, les chèques, puis un pied gris collé en bas : « Annuler »
   et « Enregistrer 160,00 € » restent sous la main quelle que soit la
   longueur de la saisie. Les lignes « en plus » (.ecole-enc-ligne,
   ci-dessus) servent au mélange de modes. */
.modal-box.enc-box { max-width: 640px; }
.enc-tete.modal-header { align-items: flex-start; border-bottom: none; padding: 22px 28px 0; }
.enc-tete-texte { flex: 1 1 auto; min-width: 0; }
.enc-tete .modal-header-title { display: block; font-size: 1.4rem; }
.enc-pour { color: var(--color-muted); font-size: .95rem; font-variant-numeric: tabular-nums; }
.enc-pour strong { color: var(--color-text); }
.enc-corps.modal-body { display: flex; flex-direction: column; gap: 1.05rem; padding: 18px 28px 0; }
.enc-corps .form-group { margin: 0; }
.enc-lib { display: flex; align-items: center; gap: .4rem; margin-bottom: .45rem; font-size: .9rem; font-weight: 700; }
.enc-lib--centre { justify-content: center; margin-bottom: 0; color: var(--color-muted); }

/* Le montant reçu */
.enc-montant-bloc {
    padding: .9rem 1rem; text-align: center;
    background: var(--color-surface-alt); border: 1px solid var(--color-border); border-radius: var(--radius-lg);
}
.enc-total-ligne { display: flex; align-items: baseline; justify-content: center; gap: .35rem; }
/* #enc-total : plus précis que la règle des champs à 16 px des écrans
   tactiles (iOS ne zoome pas au-dessus de 16 px, ce chiffre peut rester
   grand). */
:root .enc-box input#enc-total {
    min-width: 1ch; max-width: 100%; padding: 0; border: 0; background: transparent;
    font-family: var(--font-title); font-size: 2.6rem !important; font-weight: 600; line-height: 1.2;
    font-variant-numeric: tabular-nums; text-align: right; color: var(--color-text);
}
:root .enc-box input#enc-total:focus { outline: none; }
.enc-total-ligne:focus-within { box-shadow: inset 0 -3px 0 var(--color-primary); }
.enc-total-euro { font-family: var(--font-title); font-size: 2rem; font-weight: 600; color: var(--color-muted); }
.enc-raccourcis { display: flex; flex-wrap: wrap; justify-content: center; gap: .5rem; margin-top: .45rem; }
.enc-raccourcis:empty { display: none; }
.enc-raccourci {
    min-height: 40px; padding: 0 .9rem; border-radius: 999px; cursor: pointer;
    border: 1px solid var(--color-border-strong); background: var(--color-surface); color: var(--color-text);
    font-family: var(--font); font-size: .9rem; font-weight: 600; font-variant-numeric: tabular-nums;
}
.enc-raccourci--actif { border-color: var(--color-primary); background: var(--color-primary-mid); color: var(--color-primary); }
.enc-bilan { margin-top: .55rem; font-size: .9rem; font-variant-numeric: tabular-nums; }

/* Les quatre modes : de grosses tuiles, une seule choisie. Le bouton
   radio est dans la tuile, invisible : le clavier et les lecteurs
   d'écran le trouvent, l'œil lit la tuile. */
.enc-modes { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: .6rem; }
.enc-tuile {
    position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: .35rem;
    min-height: 84px; margin: 0; border-radius: 14px; cursor: pointer;
    border: 2px solid var(--color-border); background: var(--color-surface); color: var(--color-text);
    font-size: .9rem; font-weight: 700;
}
.enc-tuile input { position: absolute; opacity: 0; width: 1px; height: 1px; margin: 0; }
.enc-tuile:has(input:checked) { border-color: var(--color-primary); background: var(--color-primary-mid); color: var(--color-primary); }
.enc-tuile:has(input:focus-visible) { box-shadow: 0 0 0 3px var(--color-primary-ring); }

.enc-grille { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .75rem; }
/* Un seul compte possible : rien à choisir, on dit seulement où va
   l'argent — même hauteur qu'un champ, sans en avoir l'air. */
.enc-fixe-lib { display: block; margin-bottom: .3rem; font-size: .85rem; font-weight: 600; }
.enc-fixe {
    display: flex; align-items: center; min-height: 2.6rem; padding: 0 .85rem;
    border-radius: var(--radius); background: var(--color-neutral-soft); font-size: .95rem;
}

/* Les chèques */
.enc-cheques { display: flex; flex-direction: column; gap: .5rem; }
.enc-cheque-ligne { display: grid; grid-template-columns: 5.2rem minmax(0, 7rem) minmax(0, 1fr) auto; align-items: center; gap: .6rem; }
.enc-cheque-num { font-size: .9rem; font-weight: 700; }
.enc-cheque-ligne input[type="text"], .enc-cheque-ligne input[type="date"] {
    width: 100%; min-width: 0; min-height: 2.6rem; padding: .45rem .7rem;
    border: 1px solid var(--color-border-strong); border-radius: var(--radius);
    background: var(--color-surface); color: var(--color-text); font-family: var(--font); font-size: .95rem;
}
.enc-ch-montant { text-align: right; font-variant-numeric: tabular-nums; }
.enc-ch-quand { display: flex; align-items: center; gap: .45rem; margin: 0; min-width: 0; font-size: .82rem; color: var(--color-muted); }
.enc-ch-quand > span { flex: none; }
.enc-boutons { display: flex; flex-wrap: wrap; gap: .25rem 1.1rem; margin: .45rem 0 0; }
.enc-lien {
    min-height: 36px; padding: 0 .15rem; border: 0; background: none; cursor: pointer;
    font-family: var(--font); font-size: .9rem; font-weight: 600; color: var(--color-primary);
}
.enc-lien:hover { text-decoration: underline; }
.enc-plus > summary { cursor: pointer; font-size: .9rem; font-weight: 600; color: var(--color-muted); }
.enc-plus[open] > summary { margin-bottom: .45rem; }

/* Le pied : gris, collé au bas de la fenêtre qui défile. */
.enc-pied.modal-actions {
    position: sticky; bottom: 0; z-index: 2;
    display: grid; grid-template-columns: 1fr 2fr; gap: .75rem;
    margin: .3rem -28px 0; padding: 16px 28px;
    background: var(--color-surface-alt); border-top: 1px solid var(--color-border);
}
.enc-pied .btn { min-height: 48px; font-variant-numeric: tabular-nums; }

@media (max-width: 768px) {
    /* Feuille presque plein écran, coins du haut arrondis. */
    .modal-box.enc-box { max-height: 96dvh; }
    .enc-tete.modal-header { padding: 14px 16px 0; align-items: center; }
    .enc-tete .modal-header-title { font-size: 1.25rem; }
    .enc-tete .btn { min-height: 44px; }
    .enc-corps.modal-body { padding: 12px 16px 0; gap: .9rem; }
    :root .enc-box input#enc-total { font-size: 2.1rem !important; }
    .enc-total-euro { font-size: 1.6rem; }
    .enc-modes { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .5rem; }
    .enc-grille { grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr)); gap: .6rem; }
    .enc-tuile { min-height: 60px; flex-direction: row; gap: .5rem; }
    /* Un chèque : son numéro et « Retirer » sur une ligne, le montant et
       la date dessous. */
    .enc-cheque-ligne { grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr); gap: .4rem .5rem; }
    .enc-cheque-num { grid-column: 1; }
    .enc-ch-retirer { grid-column: 2; grid-row: 1; justify-self: end; }
    .enc-ch-quand { flex-direction: column; align-items: stretch; gap: .1rem; }
    .enc-ch-montant { align-self: end; }
    .enc-pied.modal-actions {
        margin: .2rem -16px 0; padding: 12px 16px max(12px, env(safe-area-inset-bottom, 0px)); gap: .5rem;
    }
    .enc-pied .btn { min-height: 52px; min-width: 0; }
}

/* ── Gestes sur une opération (registre et fiche famille) ──
   « ✏️ Modifier » et « ⋯ » groupés : un retour à la ligne ne doit pas
   les séparer. Le tableau du registre défile horizontalement, ce qui
   rognerait le panneau du menu : le défilement est levé le temps où un
   menu est ouvert, comme pour les cartes. */
.ecole-geste { display: inline-flex; flex-wrap: wrap; align-items: center; gap: .3rem; }

/* Fiche famille : enfant annulé ou archivé, gardé pour la trace mais en
   retrait. Pas d'opacity : elle estomperait aussi le panneau du menu
   « ⋯ » ouvert, et le rendrait illisible par-dessus les lignes voisines. */
.table-responsive:has(.menu-plus-list.open) { overflow: visible; }
/* Une entrée qui explique pourquoi un geste manque, plutôt que de le taire. */
.menu-plus-list .menu-plus-note {
    display: block; padding: .5rem .75rem; font-size: .8rem;
    color: var(--color-muted); white-space: normal; max-width: 16rem;
}

/* Téléphone : le mode et le montant partagent la première ligne avec ✕,
   les champs du chèque passent dessous, chacun sur toute la largeur. */
@media (max-width: 768px) {
    .ecole-enc-ligne .enc-mode    { flex: 1 1 8rem; }
    .ecole-enc-ligne .enc-montant { flex: 0 0 6.5rem; }
    .ecole-enc-ligne .enc-retirer { order: 3; margin-left: 0; }
    .ecole-enc-ligne .ecole-enc-quand { order: 4; flex: 1 1 100%; }
}

/* ── Documents envoyés par email ──
   Une seule classe pour toute marque « ✔️ envoyé le … » : reçu fiscal,
   reçu de paiement, attestation, fiche de rentrée. Deux classes jumelles
   finiraient par diverger. */
.doc-envoye { font-size: .75rem; color: var(--color-success); white-space: nowrap; }
/* Montant d'un paiement sur la fiche famille : il se coupait en
   « 30,00 / € » dans une colonne étroite. Une sortie porte son signe
   et sa couleur, depuis qu'Entrée et Sortie ne font plus qu'une colonne. */
.ecole-montant { white-space: nowrap; }
.ecole-montant-sortie { color: var(--color-danger); }

@media (max-width: 768px) {
    .cerfa-main-grid { grid-template-columns: 1fr; }
}
@media print {
    #cerfa-wrapper { position: static; background: none; padding: 0; overflow: visible; }

    /*  ⚠ Cette règle s'écrivait « body > *:not(#cerfa-wrapper) ».
        Le seul enfant direct de <body> est .app-layout, sur TOUTES les
        pages du site : la règle le masquait donc partout, et tout aperçu
        d'impression sortait blanc — y compris celui du reçu CERFA, qui
        vit à l'intérieur de .app-layout et disparaissait avec lui.
        Ramenée à son intention : sur la page du reçu seulement, ne garder
        que le reçu en masquant ses voisins dans le contenu. Un navigateur
        sans :has() n'applique rien, plutôt que de tout cacher. */
    body:has(#cerfa-wrapper) .main-content > *:not(#cerfa-wrapper) { display: none !important; }
}

/* ══════════════════════════════════════════════════════════
   IMPORT DE LISTE (École arabe) — ecole/import_eleves.php
   Aperçu en tableau compact plutôt qu'une carte par famille (le
   même principe que le rapprochement bancaire de trésorerie,
   .mk-table) : sur un fichier de rentrée à 50-100 familles, une
   carte pleine hauteur par famille ne laissait voir que 2-3 lignes
   à l'écran.
   ══════════════════════════════════════════════════════════ */
.imp-table td { vertical-align: top; padding: .55rem .7rem; }
.imp-td-famille { min-width: 140px; }
.imp-famille-nom { font-weight: 600; font-size: .86rem; }
/*  Marges de l'écran d'import, sorties des style="…". */
.imp-liste-colonnes.imp-liste-colonnes { margin: .25rem 0 1rem 1.2rem; }
p.imp-p-bas.imp-p-bas   { margin-bottom: 1.25rem; }
p.imp-p-haut.imp-p-haut { margin-top: 1rem; }
.card-body.imp-pied { display: flex; justify-content: flex-end; gap: .6rem; }
td.ecole-titre-rangee.ecole-titre-rangee--espace { padding-top: 1rem; }
.imp-td-famille .badge { display: inline-block; margin-top: .25rem; font-size: .62rem; }
.imp-note-herite { font-size: .68rem; color: var(--color-muted); margin-top: .2rem; cursor: help; }

.imp-td-adherent { min-width: 280px; }
.imp-select { width: 100%; max-width: 440px; font-size: .8rem; padding: .28rem .4rem; }
.imp-actions { display: flex; gap: .3rem; flex-wrap: wrap; margin-top: .3rem; align-items: center; }
.imp-actions input[type="text"] { flex: 1; min-width: 140px; font-size: .76rem; padding: .22rem .4rem; }
.imp-actions .btn { font-size: .7rem; padding: .22rem .5rem; }
.imp-manuel-note { font-size: .7rem; color: var(--color-muted); margin-top: .25rem; }
.imp-diff { font-size: .72rem; margin-top: .3rem; }
.imp-diff label { display: block; margin-bottom: .1rem; font-weight: 400; }
.imp-p2 { font-size: .74rem; margin-top: .35rem; padding-top: .3rem; border-top: 1px dashed var(--color-border); }
.imp-p2-conflit { display: block; color: var(--color-warning); margin-bottom: .15rem; }

.imp-td-enfants { min-width: 170px; }
.imp-enfant { display: block; font-size: .78rem; line-height: 1.55; white-space: nowrap; }

.imp-row--warn td { background: var(--color-warning-lt); }

@media (max-width: 768px) {
    .imp-select { max-width: 100%; }
    .imp-td-famille, .imp-td-adherent, .imp-td-enfants { min-width: 0; }
}

/* Zone de dépôt du fichier — même motif que .rp-upload-zone
   (tresorerie/rapprochement.php), sous son propre préfixe de module. */
.imp-upload-zone {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: .75rem; padding: 2.5rem; border: 2px dashed var(--color-border);
    border-radius: var(--radius-lg); cursor: pointer; text-align: center;
    transition: border-color .2s, background .2s; background: var(--color-surface-alt);
}
.imp-upload-zone--drag { border-color: var(--color-primary); background: var(--pal-or-a08); }
.imp-upload-icon       { font-size: 2.5rem; }
.imp-upload-filename   { font-size: .8rem; color: var(--color-primary); font-weight: 600; }

/* ══════════════════════════════════════════════════════════
   APPEL (École arabe) — ecole/appel.php

   Le seul écran qu'un compte Enseignant peut ouvrir, et il s'utilise
   debout, téléphone en main, devant une classe. D'où trois partis
   pris qui ne se retrouvent nulle part ailleurs dans ce fichier :

   · les trois états sont des BOUTONS, pas une liste déroulante. Un
     menu demande deux gestes et cache le choix des autres élèves ;
   · ils sont COLORÉS (vert / ambre / rouge). On relit une colonne de
     pointage du coin de l'œil, pour trouver ce qui manque ;
   · rien n'est coché à l'ouverture, y compris visuellement — l'état
     « non renseigné » doit se voir, c'est ce qu'on vient compléter.

   Le style par défaut est celui de l'ordinateur ; l'empilement est
   dans la media query. Une classe de trente élèves sur un écran large
   doit rester une ligne par élève, pas trois.
   ══════════════════════════════════════════════════════════ */

/* Le choix de la séance : libellé et champ côte à côte. Le <span>
   remplace un <label for> — le champ est DANS le label, c'est lui qui
   porte l'association. */
.ecole-appel-champ { display: flex; align-items: center; gap: .45rem; }
.ecole-appel-champ > span {
    font-size: .85rem; color: var(--color-muted); white-space: nowrap;
}

/* Les créneaux, téléphone seulement (l'ordinateur garde
   .ecole-appel-creneaux-ordi, sous les champs) : à côté de la date, un
   par ligne, calés sur le champ ; avec « Déjà faites » (pas la place pour
   trois), ils passent dessous sur UNE ligne, séparés par « · ». */
.ecole-appel-creneaux { display: none; }
@media (max-width: 768px) {
    .ecole-appel-creneaux-ordi { display: none; }
    .ecole-appel-creneaux {
        display: flex; flex-direction: column; justify-content: center;
        flex: 1 1 8rem; align-self: flex-end; min-height: 2.5rem;
        font-size: .8rem; line-height: 1.35;
    }
    .ecole-filters:has(.ecole-appel-deja) .ecole-appel-creneaux {
        order: 10; flex: 1 0 100%; flex-direction: row; flex-wrap: wrap;
        align-self: auto; min-height: 0; column-gap: .35rem; justify-content: flex-start; text-align: left;
    }
    .ecole-filters:has(.ecole-appel-deja) .ecole-appel-creneaux span + span::before { content: '· '; }
}

.ecole-appel-entete { display: flex; align-items: center; justify-content: space-between; gap: .75rem; }

/* Le choix de la classe en boutons (boutonsClasses()) : toute la ligne,
   les champs voisins (date, mois…) passent dessous. Le bouton de la
   classe affichée est plein ; ✔ = appel déjà fait à la date choisie. */
.ecole-classes-choix { flex: 1 0 100%; grid-column: 1 / -1; display: flex; flex-direction: column; gap: .3rem; min-width: 0; }
.ecole-classes-choix-titre { font-size: .85rem; color: var(--color-muted); }
.ecole-classes-boutons { display: flex; flex-wrap: wrap; gap: .4rem; }
.ecole-classe-btn {
    flex: 1 1 0; min-width: 3.4rem; min-height: 2.5rem; padding: .35rem .5rem;
    font: inherit; font-size: .95rem; font-weight: 600;
    border: 1px solid var(--color-border-strong); border-radius: var(--radius);
    background: var(--color-surface); color: var(--color-text); cursor: pointer;
}
.ecole-classe-btn:hover { border-color: var(--color-ecole); }
.ecole-classe-btn.is-actif { background: var(--color-ecole); border-color: var(--color-ecole); color: var(--color-on-accent); }
.ecole-classe-fait { color: var(--color-success); font-size: .85em; }
.ecole-classe-btn.is-actif .ecole-classe-fait { color: inherit; }
.ecole-classe-btn:focus-visible { outline: 2px solid var(--color-ecole); outline-offset: 2px; }
/* Les boutons se partagent toute la largeur (demande de l'utilisateur).
   Sur téléphone, à 5 ou 6 ils ne tiennent plus sur une ligne : trois par
   ligne, ceux de la dernière s'étirent (5 = 3 + 2, 6 = 3 + 3). */
@media (max-width: 768px) {
    .ecole-classes-boutons--nombreux .ecole-classe-btn { flex: 1 1 calc(33.333% - .3rem); }
}
/* De 7 à 12 classes (le bureau) : deux lignes à parts égales sur
   téléphone (--par-ligne = moitié arrondie au-dessus, posée par
   boutonsClasses()). Les boutons y font ~52 px : marges resserrées, et le
   ✔ de l'Appel passe en pastille dans le coin (« CAS1 ✔ » ne tiendrait pas). */
@media (max-width: 768px) {
    .ecole-classes-boutons--deux-lignes { gap: .35rem; }
    .ecole-classes-boutons--deux-lignes .ecole-classe-btn {
        flex: 1 1 calc((100% - (var(--par-ligne) - 1) * .35rem) / var(--par-ligne) - .5px);
        min-width: 0; padding: .3rem .15rem; font-size: .9rem; position: relative;
    }
    .ecole-classes-boutons--deux-lignes .ecole-classe-fait {
        position: absolute; top: 1px; right: 3px; font-size: .65rem; line-height: 1;
    }
}
/* Très petit écran (320 px, ~38 px par bouton) : « CAS1 » débordait. */
@media (max-width: 360px) {
    .ecole-classes-boutons--deux-lignes .ecole-classe-btn { padding: .3rem 0; font-size: .78rem; }
}
/* Progression : sous les boutons de classe, « Validé le » restait seul dans
   la première colonne de la grille, la moitié droite vide (capture de
   l'utilisateur). Sur téléphone il prend la ligne, aligné sur les boutons. */
@media (max-width: 768px) {
    .prog-choix-ligne:has(> .ecole-classes-choix:not(.ecole-classes-choix--ordi)) > .prog-choix-champ { grid-column: 1 / -1; }
}
/* Et le libellé à côté du champ, sur la même ligne (demande de
   l'utilisateur) : sous des boutons, un libellé au-dessus coûtait une ligne. */
.prog-choix-ligne:has(> .ecole-classes-choix:not(.ecole-classes-choix--ordi)) > .prog-choix-champ { flex-direction: row; align-items: center; gap: .6rem; }
.prog-choix-ligne:has(> .ecole-classes-choix:not(.ecole-classes-choix--ordi)) > .prog-choix-champ > span { flex: 0 0 auto; white-space: nowrap; }
.prog-choix-ligne:has(> .ecole-classes-choix:not(.ecole-classes-choix--ordi)) > .prog-choix-champ > input { flex: 1 1 auto; width: auto; }
@media (min-width: 769px) {
    .prog-choix-ligne:has(> .ecole-classes-choix) > .prog-choix-champ { flex-direction: row; align-items: center; gap: .6rem; }
    .prog-choix-ligne:has(> .ecole-classes-choix) > .prog-choix-champ > span { flex: 0 0 auto; white-space: nowrap; }
    /* Largeur posée : en « auto », Chrome réduisait le champ date à son
       icône de calendrier, la date ne se lisait plus (capture de l'utilisateur). */
    .prog-choix-ligne:has(> .ecole-classes-choix) > .prog-choix-champ { grid-column: 1 / -1; }
    .prog-choix-ligne:has(> .ecole-classes-choix) > .prog-choix-champ > input[type="date"] { flex: 0 0 auto; width: 11rem; }
}
/* Au-delà de CLASSES_EN_BOUTONS (le bureau, 11 classes) : boutons sur
   ordinateur (demande de l'utilisateur, la place ne manque pas), menu sur
   téléphone, où trois rangées de boutons repousseraient l'écran. Les deux
   sont dans la page, le CSS choisit. */
@media (max-width: 768px) {
    .ecole-classes-choix--ordi { display: none; }
}
@media (min-width: 769px) {
    .ecole-classes-menu { display: none !important; }
}

.ecole-appel-liste { list-style: none; margin: 0; padding: 0; }

.ecole-appel-eleve {
    display: flex; align-items: center; gap: .75rem;
    padding: .45rem 0;
    border-bottom: 1px solid var(--color-border);
}
.ecole-appel-eleve:last-child { border-bottom: none; }

.ecole-appel-nom { flex: 1; min-width: 0; font-size: .92rem; font-weight: 500; }

/* Un élève parti reste pointable mais ne doit pas se confondre avec
   les autres : il ne vient plus, et le pointer absent chaque semaine
   n'apprendrait rien à personne. */
.ecole-appel-eleve--parti .ecole-appel-nom { color: var(--color-muted); font-weight: 400; }

/* ── Les trois états ──
   Les <input> sont retirés de l'affichage sans être retirés du
   document : ils gardent le clavier et les lecteurs d'écran, alors
   qu'un display:none les aurait rendus inatteignables autrement qu'à
   la souris. */
.ecole-appel-statut { display: flex; gap: .25rem; flex-shrink: 0; }
.ecole-appel-statut input[type="radio"] {
    position: absolute; width: 1px; height: 1px;
    opacity: 0; pointer-events: none;
}
.ecole-appel-opt {
    display: inline-flex; align-items: center; justify-content: center;
    min-height: 2.1rem; padding: .3rem .7rem;
    font-size: .82rem; font-weight: 500; line-height: 1;
    color: var(--color-muted);
    background: var(--color-surface-alt);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    cursor: pointer; user-select: none;
    transition: background var(--transition), color var(--transition), border-color var(--transition);
    margin: 0;
}
.ecole-appel-opt:hover { border-color: var(--color-border-strong); }
/* Libellé abrégé : seulement sur téléphone (bloc « Téléphone » plus bas). */
.ecole-appel-opt-court { display: none; }

/* Le « — » est un choix comme les autres : il efface une croix posée
   par erreur. Étroit, parce qu'on le cherche rarement. */
.ecole-appel-opt--vide { min-width: 2.4rem; padding: .3rem .4rem; }

.ecole-appel-statut input:checked + .ecole-appel-opt--present {
    background: var(--color-accent-lt); border-color: var(--color-accent);
    color: var(--color-accent-dk); font-weight: 600;
}
.ecole-appel-statut input:checked + .ecole-appel-opt--retard {
    background: var(--color-warning-lt); border-color: var(--color-warning);
    color: var(--color-warning); font-weight: 600;
}
.ecole-appel-statut input:checked + .ecole-appel-opt--absent {
    background: var(--color-danger-lt); border-color: var(--color-danger);
    color: var(--color-danger); font-weight: 600;
}
.ecole-appel-statut input:checked + .ecole-appel-opt--vide {
    background: var(--color-surface-alt); border-color: var(--color-border-strong);
    color: var(--color-text-tertiary);
}
/* Le contour de focus vit sur le libellé, l'input étant invisible :
   sans ça, parcourir la liste au clavier n'affiche plus rien. */
.ecole-appel-statut input:focus-visible + .ecole-appel-opt {
    outline: 2px solid var(--color-ecole); outline-offset: 2px;
}

/* ── « justifiée » ──
   Grisée plutôt que masquée quand elle n'a pas de sens (élève non
   absent) : la faire apparaître et disparaître changerait la hauteur de
   la ligne à chaque clic, et la liste sauterait sous le doigt.
   align-self : sur téléphone la ligne est en align-items: stretch (les
   boutons y prennent toute la hauteur) — la case, elle, reste centrée
   sur la hauteur des boutons (demande de l'utilisateur). */
.ecole-appel-justif {
    display: flex; align-items: center; gap: .3rem;
    align-self: center;
    flex-shrink: 0; width: 6rem;
    font-size: .78rem; color: var(--color-muted); margin: 0;
    cursor: pointer;
}
.ecole-appel-justif input { width: auto; margin: 0; }
.ecole-appel-justif.is-off { opacity: .3; cursor: default; }

/* La justification, obligatoire, passe sur sa propre ligne sous l'élève
   quand « justifiée » est cochée : à côté des boutons, elle n'aurait
   pas la place d'être lue. flex-wrap ne casse la ligne que pour elle :
   cachée ([hidden]), elle ne prend aucune place. */
.ecole-appel-eleve { flex-wrap: wrap; }
.ecole-appel-motif { flex: 1 0 100%; }
/* Ordinateur : sur toute la largeur, le champ traversait l'écran pour
   un mot (remarque de l'utilisateur, capture). Calé à droite sous les
   boutons, il se lit attaché à la case « justifiée » qui l'a ouvert.
   Il garde sa ligne à lui (base à 100 %), seul son champ rétrécit. */
@media (min-width: 769px) {
    .ecole-appel-motif { display: flex; justify-content: flex-end; }
    .ecole-appel-eleve .ecole-appel-motif input { width: 24rem; max-width: 100%; }
}
.ecole-appel-motif input {
    width: 100%; padding: .4rem .6rem; font-size: .85rem;
    border: 1px solid var(--color-border); border-radius: var(--radius);
    background: var(--color-surface); color: var(--color-text);
}
.ecole-abs-retirer { margin-top: .75rem; text-align: right; }

.ecole-appel-pied {
    display: flex; align-items: center; justify-content: space-between;
    gap: .75rem; flex-wrap: wrap;
}

/* ── Téléphone ──
   Le nom passe au-dessus, et les trois états se partagent la largeur :
   c'est la seule façon d'avoir des cibles qu'on touche sans viser.
   Rien de tout cela ne s'applique sur ordinateur, où la ligne unique
   permet d'embrasser la classe entière d'un regard. */
@media (max-width: 768px) {
    /* Une ligne par élève (demandes de l'utilisateur, captures) : le
       nom à gauche — NOM, le prénom dessous, comme la liste des Élèves —
       et les trois boutons abrégés à droite (« Prés. · Ret. · Abs. »,
       des mots, pas un code de lettres). Le « — » disparaît : retoucher
       le bouton choisi efface (appelRetouche()). « justifiée » n'apparaît
       que sous un ABSENT, avec son champ : la ligne grandit alors, mais
       seulement pour lui, sous le doigt qui vient de toucher « Abs. ».
       L'ordre du HTML ne change pas (`order`). */
    .ecole-appel-eleve {
        flex-wrap: wrap;
        align-items: center;
        gap: .35rem .5rem;
        padding: .45rem 0;
    }
    .ecole-appel-eleve > .ecole-appel-nom { flex: 1 1 0; order: 1; line-height: 1.25; }
    .ecole-appel-eleve > .ecole-appel-nom .nom-nom,
    .ecole-appel-eleve > .ecole-appel-nom .nom-prenom { display: block; overflow-wrap: anywhere; }
    .ecole-appel-eleve > .ecole-appel-nom .nom-prenom { font-weight: 400; font-size: .85rem; color: var(--color-muted); }
    .ecole-appel-eleve > .ecole-appel-statut { flex: 0 0 auto; order: 2; }
    .ecole-appel-eleve > .ecole-appel-justif { order: 3; flex: 1 0 100%; width: auto; }
    .ecole-appel-eleve > .ecole-appel-justif.is-off { display: none; }
    .ecole-appel-eleve > .ecole-appel-motif { order: 4; }
    .ecole-appel-opt { min-width: 3.1rem; min-height: 2.4rem; padding: .25rem .4rem; }
    .ecole-appel-opt-long { display: none; }
    .ecole-appel-opt-court { display: inline; }
    .ecole-appel-opt--vide { display: none; }
    /* Libellé au-dessus du champ : à côté, il prenait la place du texte
       et « S1 (Cours d'arabe supplémentaire) » était coupé. Les champs
       se partagent la ligne (Classe et Séance, Classe et Mois — demande de
       l'utilisateur, comme la Progression) et passent dessous faute de place. */
    .ecole-appel-champ { flex: 1 1 8rem; min-width: 0; flex-direction: column; align-items: stretch; gap: .2rem; }
    .ecole-appel-champ select,
    .ecole-appel-champ input[type="date"] { flex: 1; min-width: 0; width: 100%; }
    .ecole-appel-pied .btn { flex: 1 1 0; min-width: 5rem; }
    .ecole-appel-pied #appel-compteur { flex: 1 0 100%; }
}

/* ── Appel déjà fait : la lecture (demande de l'utilisateur) ──
   Une ligne par élève, sans bouton : on ne réécrit plus l'appel d'un
   enseignant d'un doigt qui glisse. Le bandeau dit qui, quand, combien. */
.ecole-appel-fait {
    background: var(--color-success-lt); border-left: 2px solid var(--color-success);
    border-radius: 6px; padding: .35rem .65rem; margin-bottom: .5rem;
    font-size: .8rem; line-height: 1.4;
}
.ecole-appel-fait-compte { color: var(--color-muted); }
.ecole-appel-modif {
    background: var(--color-warning-lt); border-left: 3px solid var(--color-warning);
    border-radius: 6px; padding: .5rem .75rem; margin-bottom: .4rem; font-size: .88rem;
}
.ecole-appel-lu {
    display: flex; flex-wrap: wrap; align-items: baseline; gap: .15rem .75rem;
    padding: .45rem 0; border-bottom: 1px solid var(--color-border);
}
.ecole-appel-lu:last-child { border-bottom: none; }
.ecole-appel-lu .ecole-appel-nom { flex: 1 1 10rem; margin-bottom: 0; }
.ecole-appel-etat { flex-shrink: 0; font-size: .85rem; font-weight: 600; }
.ecole-appel-etat--present { color: var(--color-success); }
.ecole-appel-etat--retard  { color: var(--color-warning); }
.ecole-appel-etat--absent  { color: var(--color-danger); }
.ecole-appel-etat--vide    { color: var(--color-muted); font-weight: 400; font-style: italic; }
.ecole-appel-lu-motif { flex: 1 0 100%; font-size: .8rem; color: var(--color-muted); text-align: right; }

/* ── Assiduité — fiche famille (ecole/fiche.php) ──
   Un bloc par enfant plutôt qu'un tableau : la liste des dates
   manquées a besoin de toute la largeur, et .table-mobile aurait
   découpé le bloc en deux cartes sur téléphone. */
.ecole-assid-bloc {
    padding: .8rem 0;
    border-bottom: 1px solid var(--color-border);
}
.ecole-assid-bloc:first-of-type { padding-top: 0; }
.ecole-assid-bloc:last-of-type  { padding-bottom: 0; border-bottom: none; }

.ecole-assid-nom { font-size: .95rem; margin-bottom: .4rem; }
.ecole-assid-nom .text-muted { font-size: .82rem; margin-left: .4rem; }

.ecole-assid-chiffres {
    display: flex; flex-wrap: wrap; gap: .4rem;
    font-size: .82rem; margin-bottom: .2rem;
}
.ecole-assid-chiffre {
    display: inline-flex; align-items: baseline; gap: .25rem;
    padding: .2rem .55rem; border-radius: var(--radius);
    background: var(--color-surface-alt); color: var(--color-muted);
}
.ecole-assid-chiffre--present { background: var(--color-accent-lt); color: var(--color-accent-dk); }
.ecole-assid-chiffre--absent  { background: var(--color-danger-lt);  color: var(--color-danger); }
.ecole-assid-chiffre--retard  { background: var(--color-warning-lt); color: var(--color-warning); }

/* Fiche famille : absences et retards groupés, chacun sa couleur pleine
   (un filet de 3 px ne se distinguait pas d'un coup d'œil). */
.ecole-assid-groupe { display: flex; flex-wrap: wrap; align-items: center; gap: .3rem; margin-top: .45rem; }
.ecole-assid-groupe-titre { font-size: .76rem; font-weight: 700; min-width: 4.8rem; }
.ecole-assid-groupe-titre--absent { color: var(--color-danger); }
.ecole-assid-groupe-titre--retard { color: var(--color-warning); }
.ecole-assid-date {
    font-size: .76rem; padding: .15rem .5rem; border-radius: 999px; font-weight: 500;
    white-space: nowrap;
}
.ecole-assid-date--absent { background: var(--color-danger-lt);  color: var(--color-danger); }
.ecole-assid-date--retard { background: var(--color-warning-lt); color: var(--color-warning); }
/* La frise d'assiduité (fiche famille) : une case par séance, groupée
   par mois. Petite et serrée : elle se lit d'un coup d'œil, comme une
   tendance ; le détail des dates est dans la liste dessous. */
.ecole-frise { display: flex; flex-wrap: wrap; gap: .35rem .75rem; margin: .5rem 0 .35rem; }
.ecole-frise-mois { display: flex; flex-direction: column; gap: .15rem; }
.ecole-frise-lib { font-size: .68rem; color: var(--color-text-tertiary); line-height: 1; }
.ecole-frise-cases { display: flex; gap: 2px; }
.ecole-frise-case { display: inline-block; width: 11px; height: 11px; border-radius: 2px;
                    background: var(--color-border); flex-shrink: 0; }
.ecole-frise-case--present { background: var(--color-accent); }
.ecole-frise-case--retard  { background: var(--color-warning); }
.ecole-frise-case--absent  { background: var(--color-danger); }
/* Séance pendant les vacances (déduit de la date) : un trait bleu sous
   la case, qui laisse lire sa couleur de présence. */
.ecole-frise-case--vac { box-shadow: 0 3px 0 -1px var(--color-info); }
/* Une absence justifiée reste rouge (c'est une absence), mais claire et
   cerclée : elle ne doit pas se lire comme une présence. */
.ecole-frise-case--absent.ecole-frise-case--justifiee {
    background: var(--color-danger-lt); box-shadow: inset 0 0 0 1.5px var(--color-danger); }
.ecole-frise-case--absent.ecole-frise-case--justifiee.ecole-frise-case--vac {
    box-shadow: inset 0 0 0 1.5px var(--color-danger), 0 3px 0 -1px var(--color-info); }
/* Une date d'absence qui s'ouvre (marquer justifiée) : un filet la
   distingue d'une pastille inerte, sans changer sa couleur d'absence. */
.ecole-assid-date--lien { text-decoration: none; box-shadow: inset 0 0 0 1px currentColor; }
.ecole-assid-date--lien:hover, .ecole-assid-date--lien:focus-visible { background: var(--color-danger); color: var(--color-on-accent); }
/* Même repère dans la grille d'Assiduité : « vac. » sous la date. */
.ecole-assid-vac {
    display: inline-block; font-size: .62rem; font-weight: 600; line-height: 1.2;
    padding: 0 .25rem; border-radius: 3px;
    background: var(--color-info-lt); color: var(--color-info);
}
.ecole-assid-seance .ecole-assid-vac { display: block; margin-top: .1rem; }
.ecole-assid-seance--vac { box-shadow: inset 0 -2px 0 var(--color-info); }
.ecole-frise-legende { display: flex; flex-wrap: wrap; gap: .25rem .9rem; font-size: .72rem;
                       color: var(--color-muted); margin-top: .75rem; }
.ecole-frise-legende span { display: inline-flex; align-items: center; gap: .3rem; }

/* ── Assiduité — tableau d'une classe (ecole/assiduite.php) ──
   Posture « assis, plusieurs lignes à comparer » : cet écran est
   pensé pour un ordinateur et reste consultable sur téléphone en
   défilant, plutôt que découpé en cartes — une carte par élève
   perdrait précisément ce qu'on vient y chercher, la comparaison
   d'une colonne de séance d'un élève à l'autre. */
.ecole-assid-grille { border-collapse: collapse; }
.ecole-assid-grille th, .ecole-assid-grille td { text-align: center; }
.ecole-assid-grille th:first-child,
.ecole-assid-grille td:first-child { text-align: left; white-space: nowrap; }
.ecole-assid-seance { font-size: .68rem; line-height: 1.25; font-weight: 600; }
.ecole-assid-seance span { display: block; font-weight: 400; color: var(--color-muted); }
.ecole-assid-case { width: 2.2rem; font-size: .8rem; font-weight: 600; padding: .3rem .15rem; }
.ecole-assid-case--present { color: var(--color-accent); }
.ecole-assid-case--retard  { color: var(--color-warning); }
.ecole-assid-case--absent  { color: var(--color-danger); }
.ecole-assid-case--vide    { color: var(--color-text-tertiary); font-weight: 400; }
/* Une absence justifiée reste une absence : elle se distingue par un
   soulignement, pas par une autre couleur — sinon on la lirait comme
   une troisième catégorie, et elle serait comptée à part. */
.ecole-assid-case--justifiee { text-decoration: underline; text-underline-offset: 2px; }
/* Le « A » d'une absence s'ouvre pour la marquer justifiée après coup :
   il prend toute la case, pour se toucher au doigt sans viser. */
.ecole-assid-lien { display: block; margin: -.3rem -.15rem; padding: .3rem .15rem;
                    color: inherit; text-decoration: inherit; border-radius: 4px; }
.ecole-assid-lien:hover, .ecole-assid-lien:focus-visible { background: var(--color-danger-lt); }
/* Le « A » est un lien : sans cette règle, `.table td a` (plus précis que
   la couleur de la case) le peignait en orange, la couleur du retard. */
.ecole-assid-grille td a.ecole-assid-lien { color: inherit; font-weight: inherit; }
.ecole-assid-total { white-space: nowrap; font-size: .82rem; }
/* La colonne des noms reste en place quand la grille défile en largeur
   (téléphone) : sans elle, on lit des ✓ et des A sans savoir de qui. */
.ecole-assid-grille th:first-child,
.ecole-assid-grille td:first-child { position: sticky; left: 0; z-index: 1; background: var(--color-surface); }
.ecole-assid-grille thead th:first-child { background: var(--color-surface-alt); }
.ecole-assid-bilan--abs { color: var(--color-danger); font-weight: 600; }
.ecole-assid-bilan--ret { color: var(--color-warning); font-weight: 600; }
/* Nom de l'élève : NOM puis prénom, sur une ligne à l'ordinateur. */
.ecole-assid-nom-fam { font-weight: 600; }
.ecole-assid-bilan-mobile { display: none; }
.modal-box--assid-eleve { max-width: 640px; }
.modal-box--assid-eleve .ecole-assid-bloc { padding-top: 0; border-bottom: none; }
/* Téléphone (retour d'un enseignant, iPhone) : un nom long occupait la
   largeur et poussait le bilan hors de l'écran. Le nom passe sur deux
   lignes dans une colonne bornée, le bilan descend sous le nom et sa
   colonne disparaît : les séances ont toute la place qui reste. */
@media (max-width: 768px) {
    .ecole-assid-grille th:first-child,
    .ecole-assid-grille td:first-child { white-space: normal; max-width: 40vw; min-width: 7.5rem;
                                         padding: .4rem .5rem; line-height: 1.25; }
    /* NOM et prénom restent sur une ligne tant qu'ils y tiennent (le
       navigateur coupe entre les deux sinon) : forcés sur deux lignes,
       chaque élève prenait trois lignes avec le bilan. */
    .ecole-assid-nom-fam, .ecole-assid-prenom { overflow-wrap: anywhere; }
    .ecole-assid-nom-fam { font-size: .82rem; }
    .ecole-assid-prenom  { font-size: .8rem; }  /* même couleur que le nom : un seul style de nom cliquable */
    .ecole-assid-bilan-mobile { display: block; font-size: .74rem; margin-top: .15rem; white-space: nowrap; }
    .ecole-assid-grille .ecole-assid-total { display: none; }
    .ecole-assid-grille th:not(:first-child),
    .ecole-assid-grille td:not(:first-child) { padding-left: .1rem; padding-right: .1rem; }
    .ecole-assid-case { width: 1.9rem; }
    .ecole-assid-legende { font-size: .72rem; gap: .35rem .7rem; }
}
/* Absences (vue d'ensemble) : un élève au-delà du seuil « d'affilée »
   se repère sans lire les chiffres. */
/* Absences : une phrase par élève plutôt que six colonnes de nombres.
   Sur ordinateur le nom à gauche, la phrase à droite ; sur téléphone
   la phrase passe sous le nom. */
.ecole-abs-liste { list-style: none; margin: 0; padding: 0; }
.ecole-abs-eleve { display: flex; flex-wrap: wrap; gap: .25rem 1rem; align-items: baseline;
                   padding: .6rem .5rem; border-bottom: 1px solid var(--color-border); }
.ecole-abs-eleve:last-child { border-bottom: none; }
.ecole-abs-eleve--alerte { box-shadow: inset 3px 0 0 var(--color-danger); padding-left: .75rem; }
.ecole-abs-qui { flex: 1 1 14rem; min-width: 0; }
.ecole-abs-classe { color: var(--color-muted); font-size: .82rem; }
.ecole-abs-quoi { flex: 1 1 16rem; font-size: .88rem; line-height: 1.45; }
.ecole-abs-signal { color: var(--color-danger); font-weight: 600; }
@media (max-width: 768px) {
    .ecole-abs-qui, .ecole-abs-quoi { flex-basis: 100%; }
}
.ecole-abs-table td:first-child .ecole-sub { display: block; }
/* Pied de grille : les absents de chaque séance, lus en colonne. */
.ecole-assid-pied td { font-size: .78rem; font-weight: 600; color: var(--color-muted);
                       border-top: 2px solid var(--color-border); }
.ecole-assid-pied td.ecole-assid-pied--abs { color: var(--color-danger); }

.ecole-assid-legende {
    display: flex; flex-wrap: wrap; gap: .75rem;
    font-size: .78rem; color: var(--color-muted); margin-top: .6rem;
}

/* ── École › fiche famille : les douze mois de cotisation ──
   Lecture seule, même calcul que Trésorerie › Cotisations. Les pastilles
   passent à la ligne d'elles-mêmes : six par ligne sur un téléphone.
   Refonte B2·3 : des pastilles rondes (maquette 3-fiche-famille), le
   mois dû cerclé de rouge, le mois pas encore dû en pointillés. */
.ecole-cotis-grille { display: flex; flex-wrap: wrap; align-items: center; gap: .45rem; }
.ecole-cotis-mois {
    display: inline-flex; flex-direction: column; align-items: center; justify-content: center;
    width: 2.75rem; height: 2.75rem; border-radius: 50%; line-height: 1.1;
    font-size: .72rem; font-weight: 700; border: 2px dashed var(--color-border-strong);
    background: var(--color-surface); color: var(--color-muted);
}
.ecole-cotis-mois-signe { font-size: .8rem; font-weight: 700; }
.ecole-cotis-mois-signe:empty { display: none; }
.ecole-cotis-mois--paye   { background: var(--color-success-lt); color: var(--color-success); border-color: transparent; }
.ecole-cotis-mois--impaye { background: var(--color-danger-lt);  color: var(--color-danger);  border-style: solid; border-color: var(--color-danger); }
.ecole-cotis-mois--hors,
.ecole-cotis-mois--exonere { opacity: .45; }
.ecole-cotis-mois--cheque { background: var(--color-warning-lt); color: var(--color-warning); border-style: dashed; border-color: var(--color-warning); }
/* « Adhésion 2026 » ne se coupe pas en deux sur téléphone ; sa largeur
   posée (flex: 0 0 auto), sinon le nowrap le ferait déborder. */
#adhesion .pliable-libelle { flex: 0 0 auto; white-space: nowrap; }
/* Badge « adhésion assoc. » des listes de l'école : sa ligne à lui, sous le
   nom, la bulle ⓘ toujours collée au badge. */
.ecole-badge-adhesion { display: flex; align-items: center; gap: .3rem; flex-wrap: nowrap; margin-top: .2rem; }
.ecole-badge-adhesion .badge { white-space: nowrap; }
/* Cotisations : la fiche de l'adhérent dans la fenêtre de l'historique,
   au-dessus des paiements (sans quitter la page). */
.cot-histo-fiche { padding: .75rem; margin-bottom: .75rem; border-radius: var(--radius);
                   background: var(--color-surface-alt); }
.cot-histo-fiche .adh-fiche-grid { margin-bottom: .6rem; }

/* ============================================================
   ÉCOLE — « PLUS DE FILTRES » (Élèves)
   ============================================================
   Même geste que Trésorerie › Opérations (.ops-filtres-plus) : les menus
   du quotidien restent dehors, les autres derrière un lien qui s'ouvre
   d'office quand l'un d'eux agit. Sur téléphone, les sept menus des
   Élèves faisaient quatre lignes avant le premier enfant. */
.ecole-filtres-plus > summary {
    display: inline-flex; align-items: center; gap: .35rem; cursor: pointer;
    font-size: .82rem; font-weight: 500; color: var(--color-ecole); list-style: none;
}
.ecole-filtres-plus > summary::-webkit-details-marker { display: none; }
.ecole-filtres-plus > summary::marker { content: ''; }
.ecole-filtres-plus > summary::before { content: '▸'; transition: transform .15s; }
.ecole-filtres-plus[open] > summary::before { transform: rotate(90deg); }
.ecole-filtres-plus-nb { color: var(--color-muted); font-weight: 400; }
.ecole-filtres-plus[open] > .ecole-filtres-etages-menus { margin-top: .5rem; }
.ecole-filtres-plus > .ecole-filtres-case { display: inline-flex; margin-top: .5rem; }
/*  Téléphone : les rangées de menus passent de la grille à deux colonnes
    à un flex qui revient à la ligne. En grille, un menu élargi par app.js
    (« Toutes les classes ») laissait son voisin seul sur la ligne, à
    demi-largeur, à côté d'un trou ; en flex, un menu seul s'étire. Vaut
    pour toutes les barres à étages (Élèves, Suivi, Registre). */
@media (max-width: 768px) {
    .ecole-filtres-etages .ecole-filtres-etages-menus { display: flex; flex-wrap: wrap; }
    .ecole-filtres-etages .ecole-filtres-etages-menus > select { flex: 1 1 40%; width: auto; }
    .ecole-filtres-etages .ecole-filtres-etages-menus > select:is(.filtre-menu-large, .filtre-menu-plein) { flex-basis: 100%; }
}

/* École › Classes : l'année à gauche, « 🖨 Imprimer ▾ » à droite, sur une
   seule rangée — sur téléphone l'en-tête passe en colonne et les deux se
   retrouvaient empilés, le bouton calé à gauche. */
.ecole-classes-outils { display: flex; align-items: center; gap: .6rem; }
@media (max-width: 768px) {
    .ecole-classes-outils { width: 100%; justify-content: space-between; }
    .ecole-classes-outils > .filters { margin: 0; }
}

/* L'écart entre deux cartes (.card + .card) sautait quand un <script>
   les séparait dans le HTML : Classes, entre « Semaine type » (suivie
   de son script) et « En attente » (capture de l'utilisateur). */
.card + script + .card { margin-top: .6rem; }
/* Même chose quand ce sont des fenêtres (masquées) qui les séparent :
   Paramètres de l'école, entre « Années scolaires » et « Comptes ». */
.card + .modal-overlay + .card,
.card + .modal-overlay + .modal-overlay + .card { margin-top: .6rem; }

/* Filet entre deux familles de gestes d'un menu « ⋯ » (Classes : imprimer
   et prévenir au-dessus, modifier et supprimer dessous). */
.menu-plus-list > .menu-plus-sep { border-top: 1px solid var(--color-border); margin: .25rem 0; }
/* Titre d'un bloc du menu (« Vacances de la Toussaint » dans Imprimer) :
   ce qui suit appartient à la période. */
.menu-plus-list > .menu-plus-titre {
    padding: .35rem .85rem .15rem; font-size: .8rem; font-weight: 600;
    color: var(--color-text-tertiary);
}
/* Un lien de menu « ⋯ » posé dans un tableau prenait l'orange des liens
   de cellule (.table td a, plus précis) : les lignes du même menu
   n'avaient pas la même couleur. */
.table td .menu-plus-list > a:not(.menu-plus-danger) { color: var(--color-text); }

/* ============================================================
   REGISTRE DE L'ÉCOLE — RANGÉ COMME LES OPÉRATIONS DE LA TRÉSORERIE
   ============================================================
   Demande de l'utilisateur : un bandeau par jour (plus de colonne Date),
   le mode, le compte et le reçu en ligne grise sous le nom, et un filet
   de couleur au bord gauche selon le SENS de l'argent — vert pour ce qui
   entre (paiement d'une famille, paiement d'une sortie scolaire), rouge
   pour ce qui sort (dépense, remboursement, annulation), gris pour un
   transfert. Le paiement d'une sortie scolaire était en indigo : une
   entrée d'argent en bleu, sous le mot « Sortie », se lisait comme une
   dépense (remarque de l'utilisateur). Le genre reste écrit en tête de
   la ligne grise. Filet en ombre intérieure et non en bordure : en
   border-collapse, la bordure d'une cellule est arbitrée avec ses
   voisines. */
.ecole-registre-table tr.ecole-reg-jour td {
    background: var(--color-ecole-lt); color: var(--color-ecole);
    font-size: .76rem; font-weight: 700; letter-spacing: .02em;
    padding: .4rem .75rem; border-bottom: 1px solid var(--color-border);
}
.ecole-registre-table tr.ecole-reg-jour:hover td { background: var(--color-ecole-lt); }
/*  La ligne « Solde de départ » : calculée, sans geste — un fond neutre
    et un filet gris la distinguent des vrais mouvements. */
.ecole-registre-table tr.ecole-reg-depart td { background: var(--color-bg); }
.ecole-registre-table tr.ecole-reg-depart td:first-child { box-shadow: inset 3px 0 0 var(--color-border-strong); }
.ecole-reg-meta { font-size: .78rem; color: var(--color-muted); margin-top: .1rem; }
.ecole-registre-table tr.ecole-reg--famille   > td:first-child { box-shadow: inset 3px 0 0 var(--color-success); }
.ecole-registre-table tr.ecole-reg--sortie    > td:first-child { box-shadow: inset 3px 0 0 var(--color-success); }
.ecole-registre-table tr.ecole-reg--depense   > td:first-child { box-shadow: inset 3px 0 0 var(--color-danger); }
.ecole-registre-table tr.ecole-reg--transfert > td:first-child { box-shadow: inset 3px 0 0 var(--color-border-strong); }

/* Registre de l'école : la carte Entrées / Sorties / Solde (reprise de
   Trésorerie › Opérations) sous la carte des filtres — le même écart
   qu'entre deux cartes (.card + .card). */
.card + .ops-resume { margin-top: .75rem; }

/* ── Registre de l'école : « À voir » (29/09/2026) ──
   Ce qu'un compte hors de l'équipe (trésorier, administrateur) a fait
   au registre, jusqu'au « ✔ Vu » du responsable. Filet ambre : une
   information à lire, pas une erreur. */
.ecole-a-voir { box-shadow: inset 3px 0 0 var(--color-warning); margin-bottom: .75rem; }
.ecole-a-voir .card-header { display: flex; align-items: center; justify-content: space-between; gap: .75rem; }
.ecole-a-voir .card-header h3 { margin: 0; }
.ecole-a-voir-outils { display: flex; gap: .4rem; flex: 0 0 auto; }
.ecole-a-voir-form { margin: 0; }
.ecole-a-voir-liste li.ecole-a-voir--vu { opacity: .7; }
.ecole-a-voir-nonvu { color: var(--color-warning); font-weight: 600; }
/* Tuile de la banque : date du dernier relevé par le trésorier (arrêté).
   En orange au-delà de RELEVE_BANQUE_JOURS — un signal, rien de bloqué. */
.ecole-releve { display: block; }
.liste-tuile .ecole-releve { font-size: .75rem; }
.liste-tuile .ecole-releve--vieux { color: var(--color-warning); font-weight: 600; }
.ecole-a-voir-liste { list-style: none; margin: 0; padding: .25rem 1rem .6rem; }
.ecole-a-voir-liste li { display: flex; gap: .6rem; padding: .5rem 0; border-top: 1px solid var(--color-border); }
.ecole-a-voir-liste li:first-child { border-top: 0; }
.ecole-a-voir-ico { flex: 0 0 auto; }
.ecole-a-voir-corps { display: flex; flex-direction: column; min-width: 0; }
.ecole-a-voir-msg { overflow-wrap: anywhere; }
.ecole-a-voir-meta { font-size: .8rem; color: var(--color-muted); }

/* ── Fenêtre « Sortie » du registre de l'école : deux champs courts par
   rangée (date · montant, mode · compte, catégorie · bénéficiaire) —
   la fenêtre tient sans défiler, même sur téléphone. ── */
.ecole-sortie-duo {
    display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    column-gap: .75rem;
}
.ecole-sortie-duo .form-group input,
.ecole-sortie-duo .form-group select { min-width: 0; width: 100%; }
.ecole-justif input[type="file"] {
    display: block; width: 100%; max-width: 100%; font-size: .85rem;
    padding: .35rem; border: 1px dashed var(--color-border); border-radius: 8px;
    background: var(--color-surface); color: var(--color-text);
}
/* Titre et case « Pas de justificatif » sur une ligne : la case décide
   si la zone de fichier s'affiche dessous. */
.ecole-justif-tete {
    display: flex; align-items: center; justify-content: space-between;
    flex-wrap: wrap; gap: .25rem .75rem;
}
.ecole-justif .ecole-justif-tete > label { margin-bottom: 0; }
.ecole-justif .ecole-justif-sans { font-size: .88rem; font-weight: 400; }
.ecole-justif input[type="file"] { margin-top: .4rem; }
/* La famille d'un remboursement : sa ligne entière dans la grille de
   la fenêtre « Dépense » (le menu porte des noms longs). */
.ecole-sortie-duo > .ecole-sortie-fam { grid-column: 1 / -1; }

/* ── École · Consultation : bandeau discret en tête des pages de l'école ── */
.ecole-consultation-bandeau {
    display: inline-flex; align-items: center; gap: .35rem;
    margin: 0 0 .6rem; padding: .15rem .6rem;
    border: 1px dashed var(--color-ecole); border-radius: 999px;
    background: var(--color-ecole-lt); color: var(--color-ecole-dk);
    font-size: .8rem; font-weight: 600;
}

/* ── École › Paramètres › Progression ──
   Le nombre de leçons tient en trois chiffres : un champ pleine largeur
   le ferait passer pour un texte à écrire. Les titres facultatifs se
   rangent en colonnes sur ordinateur, une par ligne sur téléphone. */
.ecole-prog-lecons { max-width: 8rem; }
.ecole-prog-titres { margin: .25rem 0 1rem; }
.ecole-prog-titres > summary { cursor: pointer; font-weight: 600; font-size: .9rem; }
.ecole-prog-titres-liste {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
    gap: 0 .75rem;
    margin-top: .6rem;
}
.ecole-prog-titres-liste .form-group { margin-bottom: .4rem; }
.ecole-prog-decoupage { border: 0; padding: 0; margin: 0 0 1rem; min-width: 0; }
.ecole-prog-decoupage legend { font-weight: 600; font-size: .9rem; margin-bottom: .4rem; padding: 0; }
.ecole-prog-decoupage .checkbox-label + .checkbox-label { margin-top: .4rem; }
/* Un bouton radio dans un libellé en flex : même alignement qu'une case. */
.checkbox-label input[type="radio"] { margin-top: .25rem; flex-shrink: 0; }

/* ══ Progression des élèves (docs/PROGRESSION-ELEVES.md) ══
   Écrite pour un enseignant debout, téléphone en main : un gros bouton
   pour l'étape suivante, des cases assez grandes pour le doigt, peu de
   choses à l'écran. Couleurs sur les variables du thème (mode sombre). */
.modal-box--prog { max-width: 720px; }
/*  En-tête de la fiche élève : le nom, puis sa classe et ses horaires en
    petit — une ligne, une seconde pour un cours d'option. La colonne peut
    rétrécir (min-width: 0) : un horaire long passe à la ligne au lieu de
    pousser la croix hors de l'écran. */
.prog-fen-tete { display: flex; flex-direction: column; gap: .1rem; min-width: 0; }
.prog-fen-classe { font-size: .85rem; color: var(--color-muted); line-height: 1.35; }
@media (max-width: 768px) {
    .modal-overlay:has(.modal-box--prog) { padding: 0; }
    .modal-box--prog { max-width: none; width: 100%; max-height: 100vh; min-height: 100vh; border-radius: 0; }
}

/* Deux faces d'une même fenêtre : Progression, Assiduité. */
.prog-onglets { display: flex; gap: .25rem; border-bottom: 1px solid var(--color-border); margin: 0 0 .75rem; }
.prog-onglet {
    flex: 1 1 0; text-align: center; padding: .55rem .5rem; font-weight: 600; font-size: .9rem;
    color: var(--color-muted); text-decoration: none; border-bottom: 3px solid transparent; margin-bottom: -1px;
}
.prog-onglet--on { color: var(--color-text); border-bottom-color: var(--color-ecole); }
a.prog-onglet:hover { color: var(--color-text); }
/* Trois onglets (Progression, Assiduité, Objectif) sur un téléphone :
   libellés un peu plus petits, ils tiennent sur une ligne. */
@media (max-width: 768px) {
    .prog-onglet { font-size: .8rem; padding: .5rem .2rem; white-space: nowrap; }
}

.prog-situation { margin: 0 0 .75rem; }

/* Ce qui vient d'être fait : se voit, et se défait sur place. */
/* Une ligne fine, « Annuler » en petit à droite (remarque de l'utilisateur :
   l'encart était « trop gros »). */
.prog-fait {
    display: flex; align-items: center; justify-content: space-between; gap: .5rem;
    padding: .3rem .3rem .3rem .65rem; margin-bottom: .6rem; border-radius: var(--radius);
    background: var(--color-success-lt); border: 1px solid var(--color-success);
    font-size: .85rem; font-weight: 500;
}
.prog-fait > span { min-width: 0; }
/* La question « déjà sue à son arrivée ? » après une première validation
   de l'année : une question, pas une confirmation — ton neutre. */
.prog-fait--question { background: var(--color-info-lt); border-color: var(--color-info); font-weight: 400; }
/* Objectif atteint : bien visible en tête de la progression, jusqu'à ce
   que le suivant soit fixé. */
.prog-objectif-atteint {
    display: flex; align-items: center; gap: .65rem; flex-wrap: wrap;
    padding: .7rem .8rem; margin-bottom: .75rem; border-radius: var(--radius);
    background: var(--color-success-lt); border: 2px solid var(--color-success);
}
.prog-objectif-atteint-ico { font-size: 1.6rem; line-height: 1; }
.prog-objectif-atteint-txt { flex: 1 1 12rem; min-width: 0; display: flex; flex-direction: column; gap: .1rem; font-size: .85rem; }
.prog-objectif-atteint-txt strong { font-size: 1rem; color: var(--color-success); }
.prog-objectif-atteint .btn { white-space: nowrap; }
.prog-fait .btn { padding: .2rem .5rem; font-size: .78rem; white-space: nowrap; flex-shrink: 0; }
.prog-geste { display: inline; margin: 0; }

/* Le geste de tous les jours. */
.prog-suivante, .prog-panneau {
    padding: .8rem; margin-bottom: 1rem; border-radius: var(--radius);
    border: 1px solid var(--color-border); background: var(--color-surface-alt);
}
.prog-suivante-label { font-size: .8rem; color: var(--color-muted); }
.prog-suivante-nom { font-size: 1.25rem; font-weight: 700; margin: .2rem 0 .6rem; }
.prog-suivante-gestes { display: flex; flex-wrap: wrap; gap: .5rem; }
.prog-suivante-gestes .prog-geste { display: block; flex: 1 1 12rem; }
.prog-suivante-gestes .btn { width: 100%; justify-content: center; }
.prog-lecture-seule { font-size: .85rem; margin: 0 0 .75rem; }

/* Une case par étape : n° de leçon ou de sourate, fraction du hizb. */
.prog-bloc { margin-bottom: 1rem; }
.prog-bloc-titre { font-size: 1rem; margin: 0 0 .5rem; }
.prog-compte { font-weight: 400; font-size: .85rem; color: var(--color-muted); }
.prog-cases { display: flex; flex-wrap: wrap; gap: .3rem; }
.prog-case {
    min-width: 2.6rem; height: 2.6rem; padding: 0 .3rem;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: 6px; font-size: .8rem; font-weight: 600; text-decoration: none;
    border: 1px solid var(--color-border-strong); background: var(--color-surface); color: var(--color-text);
}
.prog-case--memorise, .prog-case--acquis { background: var(--color-success); border-color: var(--color-success); color: var(--color-on-accent); }
/* Vu en lecture : à moitié rempli, comme le ◧ du projet. */
.prog-case--lecture {
    background: linear-gradient(135deg, var(--color-success-lt) 50%, var(--color-surface) 50%);
    border-color: var(--color-success);
}
.prog-case--a_revoir { border: 2px solid var(--color-warning); background: var(--color-warning-lt); }
.prog-case--suivante { outline: 3px solid var(--color-ecole); outline-offset: 1px; }
/* La case visée par l'objectif en cours : une petite 🎯 dans le coin. */
.prog-case--cible { position: relative; border: 2px dashed var(--color-primary); }
.prog-case-cible { position: absolute; top: .1rem; right: .15rem; font-size: .65rem; line-height: 1; pointer-events: none; }
.prog-hizb-cible { font-size: .78rem; font-weight: 600; color: var(--color-primary); margin-left: .3rem; }

/* Une rangée par hizb ; les suites terminées ou pas commencées se replient. */
/* Chaque hizb se replie, même allure que la Qaida (cadre fin, flèche du
   titre) ; « Récité en entier » dans le corps. */
.prog-hizb { margin-bottom: .6rem; border: 1px solid var(--color-border); border-radius: var(--radius); padding: .5rem .7rem; }
.prog-hizb > summary.prog-hizb-titre { cursor: pointer; }
.prog-hizb[open] > summary.prog-hizb-titre { margin-bottom: .5rem; }
.prog-hizb-recite { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem .6rem; margin-bottom: .5rem; }
.prog-recite { font-size: .8rem; color: var(--color-success); }
/* « Changer de hizb » sous le geste du jour : discret, replié — le geste
   rare ne passe pas devant celui de tous les jours. */
.prog-changer-hizb { margin-top: .5rem; font-size: .85rem; }
.prog-changer-hizb > summary { cursor: pointer; color: var(--color-muted); }
.prog-changer-hizb-form { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; margin-top: .4rem; }
.prog-changer-hizb-form select { flex: 1 1 9rem; min-width: 0; padding: .35rem .5rem; }
/* « Tout le Hizb N : Déjà su · Appris ici » (mode Corriger) : un hizb su
   seul, hors de l'ordre, validé d'un coup. Sur sa ligne, en tête du hizb. */
.prog-hizb-entier { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; flex: 1 1 100%; }
.prog-hizb-entier-titre { font-size: .85rem; color: var(--color-muted); }
@media (max-width: 768px) {
    .prog-hizb-entier-titre { flex: 1 1 100%; }
    .prog-hizb-entier .btn { flex: 1 1 0; min-width: 5rem; white-space: normal; justify-content: center; }
}
.prog-replie { margin-bottom: .6rem; border: 1px solid var(--color-border); border-radius: var(--radius); padding: .5rem .7rem; }
.prog-replie > summary { cursor: pointer; font-weight: 600; }
.prog-replie[open] > summary { margin-bottom: .6rem; }

/* Détail d'une étape : son état et son historique. */
.prog-panneau-etat { font-weight: 600; margin: 0 0 .6rem; }
.prog-panneau-etat--memorise, .prog-panneau-etat--acquis { color: var(--color-success); }
.prog-panneau-etat--a_revoir { color: var(--color-warning); }
.prog-hist-titre { font-size: .9rem; margin: 1rem 0 .4rem; }
.prog-hist { list-style: none; margin: 0; padding: 0; }
.prog-hist li {
    display: flex; justify-content: space-between; align-items: center; gap: .5rem;
    padding: .45rem 0; border-top: 1px solid var(--color-border); font-size: .88rem;
}
.prog-hist-gestes { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: .3rem; flex-shrink: 0; }
.prog-hist-gestes .btn { white-space: nowrap; }
.prog-hist--retiree > span:first-child { text-decoration: line-through; color: var(--color-muted); }
.prog-hist--retiree .text-muted { text-decoration: none; display: inline-block; }
/* Un objectif atteint se repère d'un coup d'œil dans l'historique. */
.prog-hist--atteint { border-left: 3px solid var(--color-success); padding-left: .5rem; }
.prog-obj-hist .prog-hist li:first-child { border-top: 0; }
.prog-retour { margin: 0 0 .5rem; }

/* La liste de la classe : un nom, et où il en est, en gris dessous. */
.prog-liste { list-style: none; margin: 0; padding: 0; }
.prog-liste li + li { border-top: 1px solid var(--color-border); }
/* La ligne entière ouvre la fiche : le lien (le nom) s'étend sur toute la
   ligne par son ::before ; la bulle ⓘ, hors du lien, passe au-dessus. */
.prog-liste li { position: relative; padding: .7rem 2.2rem .7rem 1rem; }
.prog-liste a { display: block; color: var(--color-text); text-decoration: none; }
.prog-liste a::before { content: ''; position: absolute; inset: 0; }
.prog-liste .aide { position: relative; z-index: 1; }
.prog-liste-colle { white-space: nowrap; }
/* « › » au bout de chaque élève : la ligne s'ouvre (le doigt ne survole
   pas — même repère que les lignes « À traiter » et les tuiles). */
.prog-liste a::after {
    content: '›'; position: absolute; right: 1rem; top: 50%; transform: translateY(-50%);
    font-size: 1.4rem; line-height: 1; color: var(--color-muted);
}
.prog-liste li:has(> a:hover) { background: var(--color-surface-alt); }
.prog-liste-nom { display: block; }
/* La leçon / sourate EN COURS en gras (demande de l’utilisateur). Dans la
   liste, la dernière validée est dans une bulle ⓘ ; la fiche famille garde
   sa ligne grise (.prog-liste-date). */
.prog-liste-ou { display: block; font-size: .85rem; font-weight: 600; color: var(--color-text); margin-top: .1rem; }
.prog-liste li.prog-liste--parti > * { opacity: .7; }

/* Commentaires de la progression : la zone de texte en pleine largeur
   (le micro du clavier du téléphone suffit à dicter), une carte par
   commentaire, le plus récent en haut. */
.prog-com { margin-bottom: 1rem; }
.prog-com-form textarea {
    width: 100%; padding: .5rem .7rem; font-size: .95rem; font-family: var(--font);
    border: 1px solid var(--color-border-strong); border-radius: var(--radius);
    background: var(--color-surface); color: var(--color-text); resize: vertical;
}
.prog-com-famille { margin: 0; display: inline-flex; }
.prog-com-bas { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: .5rem; margin-top: .5rem; }
.prog-com-ajout { margin-bottom: .75rem; }
.prog-com-sur { display: flex; align-items: center; gap: .4rem; margin: 0 0 .4rem; font-size: .85rem; }
.prog-com-sur select { flex: 1 1 auto; min-width: 0; padding: .3rem .5rem; font-size: .85rem; border-radius: 6px; }
.prog-com-famille-zone { display: inline-flex; align-items: center; gap: .3rem; }
.prog-com-form .aide { vertical-align: middle; }
.prog-com-actions { display: flex; flex-wrap: wrap; gap: .5rem; margin-left: auto; }
.prog-com-liste { list-style: none; margin: 0; padding: 0; }
.prog-com-liste > li {
    padding: .6rem .7rem; margin-bottom: .5rem; border-radius: var(--radius);
    border: 1px solid var(--color-border); background: var(--color-surface);
}
.prog-com-texte { white-space: normal; overflow-wrap: anywhere; }
.prog-com-meta { font-size: .8rem; color: var(--color-muted); margin-top: .3rem; }
.prog-com-gestes { display: flex; gap: .4rem; margin-top: .45rem; }
.prog-com-plus > summary { cursor: pointer; font-size: .88rem; color: var(--color-muted); margin-bottom: .5rem; }

/* La fenêtre de progression : situation, rappel du chemin. */
.prog-situation { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: .4rem .75rem; }
.prog-situation p { margin: 0; }
.prog-indice { margin: .6rem 0 0; font-size: .88rem; }
.prog-form-colonne { display: flex; flex-direction: column; gap: .5rem; }
.prog-form-colonne label { font-weight: 600; font-size: .9rem; }
.prog-form-colonne select {
    width: 100%; padding: .55rem .7rem; font-size: 1rem; font-family: var(--font);
    border: 1px solid var(--color-border-strong); border-radius: var(--radius);
    background: var(--color-surface); color: var(--color-text);
}
/* La légende des couleurs, une fois, sous la grille. */
.prog-legende { font-size: .8rem; color: var(--color-muted); display: flex; flex-wrap: wrap; align-items: center; gap: .3rem .5rem; }
.prog-case--mini { min-width: 0; width: .9rem; height: .9rem; padding: 0; border-radius: 3px; vertical-align: middle; }
/* Les huit tmen d'un hizb sur UNE rangée : un hizb, une ligne. */
.prog-cases--tmen { display: grid; grid-template-columns: repeat(8, minmax(0, 1fr)); }
.prog-cases--tmen .prog-case { min-width: 0; padding: 0; font-size: .75rem; }
.prog-legende-item { display: inline-flex; align-items: center; gap: .3rem; white-space: nowrap; }

/* Classe et date des validations côte à côte, un seul bloc ; l'un sous
   l'autre quand la place manque. */
.prog-choix-ligne { display: grid; grid-template-columns: repeat(auto-fit, minmax(7.5rem, 1fr)); gap: .5rem .75rem; align-items: end; }
.prog-choix-champ { display: flex; flex-direction: column; gap: .25rem; min-width: 0; }
.prog-choix-champ > span { font-size: .85rem; color: var(--color-muted); display: inline-flex; align-items: center; gap: .3rem; }
.prog-choix-champ > span label { font: inherit; color: inherit; margin: 0; }
.prog-choix-champ select, .prog-choix-champ input[type="date"] {
    width: 100%; min-width: 0; padding: .45rem .6rem; font-size: .95rem; font-family: var(--font);
    border: 1px solid var(--color-border-strong); border-radius: var(--radius);
    background: var(--color-surface); color: var(--color-text);
}
.prog-choix .prog-date-rappel { margin: .6rem 0 0; }
.prog-choix .prog-date-rappel a { margin-left: .4rem; }
.prog-date-choix--autre { border: 2px solid var(--color-warning); background: var(--color-warning-lt); }
.prog-date-rappel {
    margin: .6rem 0 .75rem; padding: .5rem .7rem; border-radius: var(--radius);
    background: var(--color-warning-lt); border: 1px solid var(--color-warning); font-size: 1rem;
}
.prog-liste-date { display: block; font-size: .78rem; color: var(--color-muted); margin-top: .05rem; }
/* « Connaît : … » — tout ce que l'élève connaît, d'une ligne (fiche élève,
   fiche famille). Libellé en gras, liste en gris : on la lit d'un coup. */
.prog-connait { display: block; font-size: .8rem; color: var(--color-muted); margin: .15rem 0 0; }
.prog-connait-lib { font-weight: 600; color: var(--color-text); }
/* Fiche famille : un enfant par ligne, le bouton à droite (dessous sur téléphone). */
.prog-fiche { list-style: none; margin: 0; padding: 0; }
.prog-fiche li { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .4rem .75rem; padding: .55rem 0; }
.prog-fiche li + li { border-top: 1px solid var(--color-border); }
.prog-fiche-resume { display: block; font-size: .9rem; }
/* Classes › Sans classe et En attente, sur téléphone : le tableau défilait
   déjà en largeur, et la colonne du nom s'écrasait à ~55 px (« parent : »
   sur trois lignes). Elle garde de quoi lire un nom sur une ligne. */
@media (max-width: 768px) {
    #pile td:has(> .ecole-sub), .ecole-attente td:has(> .ecole-sub) { min-width: 9.5rem; }
}

/* Objectifs : en cours (bleu), atteint (vert), échéance passée sans être
   atteint (orange) — un constat, pas une alerte (DA-9). */
.prog-objectif {
    display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .4rem .6rem;
    padding: .55rem .75rem; margin-bottom: 1rem; border-radius: var(--radius);
    background: var(--color-info-lt); border: 1px solid var(--color-info); font-weight: 600; font-size: .92rem;
}
.prog-objectif--atteint { background: var(--color-success-lt); border-color: var(--color-success); }
.prog-objectif--echu { background: var(--color-warning-lt); border-color: var(--color-warning); }
.prog-liste-objectif { display: block; font-size: .8rem; color: var(--color-info); margin-top: .1rem; }
.prog-classe-outils { padding-top: .6rem; padding-bottom: .6rem; border-bottom: 1px solid var(--color-border); }
.prog-form-colonne input[type="date"] {
    width: 100%; padding: .55rem .7rem; font-size: 1rem; font-family: var(--font);
    border: 1px solid var(--color-border-strong); border-radius: var(--radius);
    background: var(--color-surface); color: var(--color-text);
}

/* Bilan de la progression : un tableau sur ordinateur, des cartes sur
   téléphone (motif .table-mobile). */
.prog-classe-outils { display: flex; flex-wrap: wrap; gap: .5rem; }
@media (max-width: 768px) {
    /*  Les boutons de la classe se partagent la ligne : chacun à sa
        largeur, ils passaient l'un sous l'autre (capture de
        l'utilisateur). Un libellé long passe à la ligne DANS son bouton. */
    .prog-classe-outils > .btn { flex: 1 1 0; min-width: 0; justify-content: center; text-align: center; white-space: normal; }
}
.prog-bilan-intro { padding-bottom: 0; }
.prog-bilan td { vertical-align: top; }
/* « Appris cette année » : une ligne courte par élève, chaque chose dans
   son unité (leçons, sourates, tmen, hizb entiers). */
.prog-bilan td.prog-bilan-appris { font-size: .85rem; }
/* Le numéro d'une case validée prend la couleur du fond de page : blanc
   sur le vert foncé du thème clair, foncé sur le vert vif du thème sombre
   (en blanc, il y devenait illisible). */
.prog-case--memorise, .prog-case--acquis { color: var(--color-surface); }
/* Valider aussi les étapes d'avant : des pastilles à cocher, rangées par
   groupe (Qaida, Al-Fatiha, chaque hizb), cochées d'office sauf « à revoir ». */
.prog-rattrapage {
    padding: .7rem .8rem; margin-bottom: 1rem; border-radius: var(--radius);
    border: 1px solid var(--color-info); background: var(--color-info-lt);
}
.prog-rattrapage-titre { margin: 0 0 .5rem; }
.prog-rat-tout { margin-bottom: .4rem; }
.prog-rat-groupe { border: 0; padding: 0; margin: 0 0 .6rem; min-width: 0; }
.prog-rat-groupe legend { padding: 0; margin-bottom: .3rem; font-weight: 600; font-size: .9rem; }
.prog-rat-cases { display: flex; flex-wrap: wrap; gap: .3rem; }
.prog-rat-chip {
    display: inline-flex; align-items: center; gap: .25rem; padding: .3rem .45rem;
    border: 1px solid var(--color-border-strong); border-radius: 6px;
    background: var(--color-surface); font-size: .8rem; font-weight: 600; cursor: pointer;
}
.prog-rat-chip input { margin: 0; }
.prog-rat-chip--revoir { border: 2px solid var(--color-warning); }
/* Les trois boutons de la proposition à largeurs égales : côte à côte sur
   ordinateur, l'un sous l'autre en pleine largeur sur téléphone. */
/* « 📅 Dates » : la date (jour/mois) sous le numéro de chaque case notée,
   masquée tant que le bouton n'est pas activé. */
.prog-dates-lien { background: none; border: 0; padding: 0; font: inherit; color: var(--color-primary); cursor: pointer; text-decoration: underline dotted; text-underline-offset: 2px; white-space: nowrap; }
.prog-case-date { display: none; }
.prog-dates-on .prog-case:not(.prog-case--mini) { flex-direction: column; height: auto; min-height: 2.6rem; padding-top: .2rem; padding-bottom: .2rem; }
.prog-dates-on .prog-case-date { display: block; font-size: .58rem; font-weight: 500; line-height: 1; margin-top: .15rem; }
/* La face « Assiduité » de la fiche de progression : le même bloc que la
   fenêtre de l'écran Assiduité, sans filet ni marge du haut. */
.prog-assid .ecole-assid-bloc { padding-top: 0; border-bottom: none; }
.prog-assid-liens { margin: .75rem 0 0; display: flex; flex-wrap: wrap; gap: .4rem; align-items: stretch; }
/*  Le menu du relevé (menuDocumentPdf(), à gauche de la rangée) s'ouvre
    vers la droite : calé à droite, il sortait de l'écran par la gauche. */
.prog-assid-liens > .menu-plus[data-partager-zone] > .menu-plus-list { left: 0; right: auto; }
/*  Téléphone : les deux boutons (Relevé ▾ · Bilan ▾, ou Relevé · Partager)
    se partagent la ligne — avec la flèche ▾, « Bilan de l'année » passait
    seul à la ligne (capture de l'utilisateur, 04/10/2026). */
@media (max-width: 768px) {
    .prog-assid-liens > * { flex: 1 1 0; min-width: 0; }
    .prog-assid-liens > .btn,
    .prog-assid-liens > .menu-plus > .btn { width: 100%; height: 100%; white-space: normal; justify-content: center; }
}
.prog-rat-actions { display: grid; grid-template-columns: 1fr; gap: .5rem; }
@media (min-width: 769px) {
    /* Les deux choix côte à côte, « Non, seulement celle-ci » dessous, sur
       toute la largeur — pas un « 2 + 1 » bancal. */
    .prog-rat-actions { grid-template-columns: 1fr 1fr; }
    .prog-rat-actions > a { grid-column: 1 / -1; }
}
.prog-rat-actions .btn { width: 100%; justify-content: center; text-align: center; }
/* L'étape suivante : le nom à gauche, le bouton à droite sur la même ligne
   (taille normale) ; un nom long (sourate en arabe et en latin) fait passer
   le bouton dessous plutôt que de l'écraser. */
.prog-suivante-ligne { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .5rem .75rem; }
.prog-suivante-ligne .prog-suivante-nom { margin: .2rem 0; flex: 1 1 auto; min-width: 0; }
.prog-suivante-ligne .prog-suivante-gestes { flex: 0 0 auto; gap: .4rem; }
/* Deux boutons côte à côte (« Mémorisée », « Vue en lecture ») : même
   largeur, celle du plus long (remarque de l'utilisateur, « harmonise »). */
.prog-suivante-ligne .prog-suivante-gestes { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; }
.prog-suivante-ligne .prog-suivante-gestes .prog-geste { flex: 0 0 auto; }
.prog-suivante-ligne .prog-suivante-gestes .btn { width: 100%; }
/* « Lu, pas encore par cœur » : sous « Mémorisée », plus discret — côte à
   côte et de même taille, on se trompait de bouton (demande de
   l'utilisateur, 07/10/2026). Remplace l'« harmonise » d'avant. */
.prog-suivante-gestes:has(.prog-geste-lecture) { grid-auto-flow: row !important; }
.prog-suivante-gestes .btn.prog-geste-lecture { font-size: .8rem; font-weight: 500; padding: .25rem .5rem; color: var(--color-muted); }

/* « Que savait-il en arrivant ? » : en tête de la fiche tant que rien
   n'est validé ; un choix, puis la phrase à confirmer. */
.prog-arrivee {
    padding: .8rem; margin-bottom: 1rem; border-radius: var(--radius);
    border: 1px solid var(--color-info); background: var(--color-info-lt);
}
.prog-arrivee-titre { margin: 0 0 .6rem; }
.prog-arrivee-titre svg { vertical-align: -3px; }
.prog-arrivee-choix { display: flex; flex-direction: column; gap: .4rem; }
.prog-arrivee-ligne {
    display: flex; flex-wrap: wrap; align-items: center; gap: .35rem .5rem; margin: 0;
    padding: .45rem .6rem; border-radius: var(--radius); border: 1px solid var(--color-border);
    background: var(--color-surface); font-weight: 500; cursor: pointer;
}
.prog-arrivee-ligne:has(input:checked) { border-color: var(--color-primary); box-shadow: 0 0 0 1px var(--color-primary); }
.prog-arrivee-ligne input[type="radio"] { width: auto; margin: 0; flex: 0 0 auto; }
.prog-arrivee-ligne > span { flex: 0 1 auto; }
.prog-arrivee-ligne select, .prog-arrivee-duo select {
    flex: 1 1 10rem; min-width: 0; max-width: 100%; padding: .35rem .5rem; font-size: .9rem; font-family: var(--font);
    border: 1px solid var(--color-border-strong); border-radius: 6px;
    background: var(--color-surface); color: var(--color-text);
}
.prog-arrivee-duo { display: flex; gap: .35rem; flex: 1 1 12rem; min-width: 0; }
.prog-arrivee-duo select { flex: 1 1 5rem; }
.prog-arrivee-duo select[name="hizb"] { flex-grow: 2; min-width: 7rem; }
.prog-arrivee-gestes { display: flex; flex-wrap: wrap; gap: .5rem; margin: .7rem 0 0; }
.prog-arrivee-gestes .btn { flex: 1 1 10rem; justify-content: center; text-align: center; white-space: normal; }
.prog-arrivee-recap { margin: 0; display: grid; grid-template-columns: auto 1fr; gap: .3rem .75rem; }
.prog-arrivee-recap dt { font-size: .85rem; color: var(--color-muted); }
.prog-arrivee-recap dd { margin: 0; }

/* « Corriger une étape » : la grille ne s'écrit qu'en ce mode. */
.prog-corriger { margin: 0 0 .75rem; display: flex; align-items: center; flex-wrap: wrap; gap: .4rem; }
.prog-corriger--on {
    justify-content: space-between; padding: .5rem .7rem; border-radius: var(--radius);
    border: 1px solid var(--color-warning); background: var(--color-warning-lt);
}
span.prog-case { cursor: default; }

/* Hizb 60 et 59, Al-Fatiha : une ligne par sourate, son nom écrit. */
.prog-sourates { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr)); gap: .25rem .5rem; }
.prog-sourate {
    display: flex; align-items: center; gap: .45rem; padding: .35rem .5rem; min-height: 2.4rem;
    border-radius: 6px; border: 1px solid var(--color-border); background: var(--color-surface);
    color: var(--color-text); text-decoration: none; font-size: .88rem;
}
a.prog-sourate:hover { background: var(--color-surface-alt); }
.prog-sourate--memorise, .prog-sourate--acquis { background: var(--color-success-lt); border-color: var(--color-success); }
.prog-sourate--a_revoir { border: 2px solid var(--color-warning); }
.prog-sourate--en-cours { outline: 3px solid var(--color-ecole); outline-offset: 1px; font-weight: 700; }
.prog-sourate--cible { border-style: dashed; border-color: var(--color-primary); }
.prog-sourate .prog-case--mini { flex: 0 0 auto; }
.prog-sourate-num { flex: 0 0 1.8rem; font-size: .78rem; color: var(--color-muted); font-variant-numeric: tabular-nums; }
.prog-sourate-nom { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.prog-sourate-ar { flex: 0 0 auto; font-size: 1rem; }
.prog-sourate-etiquette { flex: 0 0 auto; font-size: .7rem; font-weight: 600; color: var(--color-ecole); }
.prog-sourate-etiquette--cible { color: var(--color-primary); }
.prog-dates-on .prog-sourate-date { display: inline; font-size: .7rem; color: var(--color-muted); }

/* Les documents de l'élève : un menu dans le pied de la fenêtre, à côté de
   « Fermer » (07/10/2026). Calé à gauche sur ordinateur (il porte sur la
   fiche, « Famille » et « Fermer » sont des sorties) ; le panneau s'ouvre
   VERS LE HAUT, le bouton étant tout en bas. */
.modal-actions--prog .prog-documents-pied { margin-right: auto; display: flex; }
.prog-documents .menu-plus-list { left: 0; right: auto; top: auto; bottom: calc(100% + 4px); }
.prog-documents .menu-plus-sep { display: block; }
/* Téléphone : les boutons du pied sur UNE ligne (trois à 50 % laissaient
   « Fermer » seul sur la seconde). « Documents » garde sa largeur, les
   autres se partagent le reste ; seul (pas de « Famille »), il s'étire
   comme « Fermer ». */
@media (max-width: 768px) {
    .modal-actions--prog { flex-wrap: nowrap; }
    .modal-actions--prog .btn { padding-left: .6rem; padding-right: .6rem; }
    .modal-actions--prog > .btn { flex: 1 1 0; min-width: 0; }
    .modal-actions--prog > .prog-documents-pied { flex: 0 0 auto; margin-right: 0; }
    .modal-actions--prog > .prog-documents-pied:nth-last-child(2) { flex: 1 1 0; }
    .modal-actions--prog .prog-documents,
    .modal-actions--prog .prog-documents > .btn { width: 100%; justify-content: center; }
}
/* Très petit écran (320 px) : « Documents » prend sa ligne, les deux
   autres la suivante, plutôt que des libellés qui débordent. */
@media (max-width: 359px) {
    .modal-actions--prog { flex-wrap: wrap; }
    .modal-actions--prog > .prog-documents-pied { flex: 1 1 100%; }
}
/* « ✔ Acquis » : un repli qui contient d'autres replis (Qaida,
   Al-Fatiha, hizb finis) ; dedans, ils perdent leur cadre pour ne pas
   empiler les bordures. */
.prog-acquis summary { color: var(--color-success); }
.prog-acquis > summary { display: flex; align-items: center; gap: .5rem; }
.prog-acquis > summary::before { content: '▸'; color: var(--color-success); }
.prog-acquis[open] > summary::before { content: '▾'; }
.prog-acquis > summary::-webkit-details-marker { display: none; }
.prog-acquis > summary { list-style: none; }
.prog-acquis-outils { margin-left: auto; display: inline-flex; align-items: center; gap: .3rem; font-weight: 400; }
.prog-titre-outils { display: inline-flex; align-items: center; gap: .3rem; font-weight: 400; font-size: 1rem; }
.prog-bloc-titre--outils { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; }
.prog-bloc-titre--outils .prog-titre-outils { margin-left: auto; }
.prog-hizb-titre--outils { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; list-style: none; }
.prog-hizb-titre--outils::-webkit-details-marker { display: none; }
.prog-hizb-titre--outils::before { content: '▸'; }
.prog-hizb[open] > .prog-hizb-titre--outils::before { content: '▾'; }
.prog-hizb-titre--outils .prog-titre-outils { margin-left: auto; }
.prog-corriger-lien { font-size: .85rem; color: var(--color-text); text-decoration: none; display: inline-flex; align-items: center; gap: .25rem;
    padding: .2rem .55rem; border: 1px solid var(--color-border-strong); border-radius: 999px; background: var(--color-surface); }
.prog-corriger-lien:hover { border-color: var(--color-primary); }
.prog-corriger-arrivee { flex: 1 0 100%; font-size: .88rem; }
.prog-arrivee-conv { display: flex; align-items: flex-start; gap: .45rem; margin: .6rem 0 0; font-size: .9rem; font-weight: 400; }
.prog-arrivee-conv input { width: auto; margin-top: .2rem; flex: 0 0 auto; }
.prog-sourates-sues { grid-column: 1 / -1; }
.prog-sourates-sues > details > summary { cursor: pointer; font-size: .85rem; font-weight: 600; color: var(--color-success); padding: .2rem 0; }
.prog-sourates-sues > details[open] > summary { margin-bottom: .35rem; }
.prog-acquis > summary .prog-compte { color: var(--color-muted); }
.prog-acquis .prog-replie, .prog-acquis .prog-hizb { border: 0; border-top: 1px solid var(--color-border); border-radius: 0; margin: 0; padding: .5rem 0; }
.prog-legende .prog-case--suivante.prog-case--mini { outline-width: 2px; margin-right: .15rem; }
/* Appel : l'effectif entre parenthèses à côté du nom du groupe, en
   retrait du titre (ce n'est qu'un repère pour compter les têtes). */
.ecole-appel-effectif { font-weight: 400; font-size: .85em; }
/* La date de la séance sous le nom du groupe : à la suite, elle se
   coupait au hasard à côté du bouton « Tout présent » (capture de
   l'utilisateur). */
.ecole-appel-date { display: block; }

/* Texte réservé aux lecteurs d'écran : présent dans la page, non affiché
   (ex. le titre des écrans Présences, que la barre du menu et l'onglet
   allumé disent déjà). */
.sr-only {
    position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}
/* Absences › « Par classe » : le bouton du bilan à côté du titre, qui
   passe dessous quand la place manque (téléphone) plutôt que d'écraser
   le titre sur trois lignes. */
.ecole-abs-classe-entete { flex-wrap: wrap; gap: .5rem; }
.ecole-abs-classe-entete h2 { flex: 1 1 14rem; min-width: 0; }

/* ── Progression : le bouton rapide de la liste ──
   Valider l'étape en cours sans ouvrir la fiche (demande de
   l'utilisateur). Le bouton est hors du lien de la ligne, posé à sa
   droite, avant le « › » ; la ligne lui réserve sa place. */
.prog-liste li.prog-liste--rapide { padding-right: 9.5rem; }
.prog-liste-geste { position: absolute; right: 2rem; top: 50%; transform: translateY(-50%); margin: 0; }
.prog-liste-geste .btn { white-space: nowrap; }
.prog-liste-fait { display: block; font-size: .85rem; font-weight: 600; color: var(--color-success); margin-top: .1rem; }
/* « Annuler » de la dernière validation rapide : un lien discret sur la
   ligne verte, au-dessus du lien qui couvre la ligne (le bouton de droite
   est déjà pris par l'étape suivante). */
.prog-liste-annuler { display: inline; margin: 0 0 0 .35rem; }
.prog-liste-annuler button {
    position: relative; z-index: 1; background: none; border: 0; padding: .15rem .2rem;
    font: inherit; font-size: .8rem; font-weight: 500; color: var(--color-muted);
    text-decoration: underline; cursor: pointer; white-space: nowrap;
}
.prog-liste-annuler button:hover { color: var(--color-text); }
.prog-liste-annule { display: block; font-size: .85rem; color: var(--color-muted); margin-top: .1rem; }

/* ── Historique d'une famille (fiche famille, section « 🕓 Historique ») ──
   Une liste, pas un tableau : chaque ligne se lit comme une phrase, et
   sur téléphone l'auteur passe simplement sous la phrase. Un bandeau
   par jour, au ton des opérations (même modèle que le relevé). */
.ecole-histo { list-style: none; margin: 0; padding: 0; }
.ecole-histo-jour {
    background: var(--color-primary-lt);
    color: var(--color-primary-dk);
    font-size: .76rem;
    font-weight: 700;
    letter-spacing: .02em;
    padding: .35rem .6rem;
    border-radius: var(--radius);
    margin-top: .6rem;
}
.ecole-histo-jour:first-child { margin-top: 0; }
.ecole-histo-ligne {
    display: grid;
    grid-template-columns: 2.9rem 1.5rem minmax(0, 1fr) auto;
    column-gap: .4rem;
    align-items: baseline;
    padding: .4rem .6rem;
    border-bottom: 1px solid var(--color-border);
    font-size: .88rem;
}
.ecole-histo-ligne:last-child { border-bottom: 0; }
.ecole-histo-heure { color: var(--color-muted); font-variant-numeric: tabular-nums; font-size: .8rem; }
.ecole-histo-ico   { text-align: center; }
.ecole-histo-txt   { overflow-wrap: anywhere; }
.ecole-histo-par   { color: var(--color-muted); font-size: .78rem; white-space: nowrap; text-align: right; }
.ecole-histo-plus  { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem; justify-content: center; margin: .8rem 0 0; }
@media (max-width: 768px) {
    .ecole-histo-ligne { grid-template-columns: 2.6rem 1.4rem minmax(0, 1fr); padding: .45rem .3rem; }
    /*  L'auteur sous la phrase : à côté, il lui prenait la moitié de la
        largeur et la coupait sur trois lignes. */
    .ecole-histo-par   { grid-column: 3; text-align: left; white-space: normal; }
}

/* ── Intervention dans la classe d'un autre (Appel, Progression) ──
   includes/ecole/intervention.php. Gris « vous consultez » : un état, pas
   une alerte ; jaune « vous intervenez » : on écrit à la place de
   l'enseignant, ça doit se voir tant que ça dure. */
.ecole-interv {
    display: flex; flex-wrap: wrap; align-items: center; gap: .4rem .75rem;
    background: var(--color-bg); border: 1px solid var(--color-border);
    border-left: 3px solid var(--color-border-strong);
    border-radius: 6px; padding: .5rem .75rem; margin-bottom: .6rem; font-size: .88rem;
}
.ecole-interv--active { background: var(--color-warning-lt); border-left-color: var(--color-warning); }
.ecole-interv-texte { flex: 1 1 14rem; min-width: 0; }
.ecole-interv-motif { display: block; color: var(--color-muted); font-size: .8rem; }
.ecole-interv-ouvrir > summary { list-style: none; cursor: pointer; }
.ecole-interv-ouvrir > summary::-webkit-details-marker { display: none; }
.ecole-interv-form { display: flex; gap: .4rem; align-items: center; flex-wrap: wrap; }
.ecole-interv-form input[type="text"] {
    flex: 1 1 14rem; min-width: 0; padding: .35rem .55rem; font-size: .88rem;
    border: 1px solid var(--color-border); border-radius: 6px;
    background: var(--color-surface); color: var(--color-text); font-family: var(--font);
}
.ecole-interv-ouvrir[open] { flex: 1 1 100%; }
/*  Dans la fiche d'un élève, le bandeau prend la place de « Lecture seule ». */
.modal-box .ecole-interv { margin: .5rem 0; }

/* ███████████████████████████████████████████████████████████████
   10. LE MOULE COMMUN — barres de filtres, replis, menus « ⋯ », bulle ⓘ, listes, glisser
   ███████████████████████████████████████████████████████████████ */

/* ══════════════════════════════════════════════════════════
   MODULE ÉCOLE ARABE — classes utilitaires
   ══════════════════════════════════════════════════════════ */

/* Barre de filtres : champs alignés horizontalement, qui passent
   à la ligne sur mobile. À ne pas confondre avec .form-group, qui
   empile libellé et champ dans les formulaires de saisie. */
.ecole-filters {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .6rem;
    margin-bottom: .9rem;
}
.ecole-filters label {
    font-size: .85rem;
    color: var(--color-muted);
    margin: 0;
    white-space: nowrap;
}
.ecole-filters input[type="text"],
.ecole-filters input[type="search"],
.ecole-filters input[type="date"],
.ecole-filters input[type="number"],
.ecole-filters select {
    width: auto;
    min-width: 8rem;
    padding: .45rem .9rem; min-height: 2.5rem;
    font-size: .9rem;
    border: 1px solid var(--color-border-strong);
    border-radius: 999px;
    background: var(--color-surface);
    color: var(--color-text);
}
/* La recherche (Suivi, Registre) : c'est le champ où l'on écrit le plus
   long, elle prend la place que les menus laissent. Le type « search »
   manquait à la règle ci-dessus : le champ gardait l'apparence brute du
   navigateur — un style de base manquant ne se voit qu'aux endroits
   qu'on n'avait pas encore écrits. */
.ecole-filters input[type="search"] {
    flex: 1 1 16rem;
    /* Safari (iPhone) dessine un champ de recherche à sa façon, arrondi,
       et ignore alors la bordure et le rembourrage posés ci-dessus. */
    -webkit-appearance: none;
    appearance: none;
}
.ecole-filters input[type="checkbox"] { width: auto; min-width: 0; margin-right: .3rem; }

/* Bouton « retirer les filtres », ajouté par footer.php quand un filtre
   est actif. Teinté : c'est la sortie de secours d'une liste devenue
   incompréhensible parce qu'on a oublié un filtre posé trois écrans
   plus tôt — elle doit se repérer sans être lue. */
.filtres-retirer {
    white-space: nowrap;
    color: var(--color-danger);
    border-color: var(--color-danger);
}
.filtres-retirer:hover { background: var(--color-danger-lt); color: var(--color-danger); }

/* Champs qui se lisent ensemble (un âge de … à …, deux boutons
   symétriques) : ils restent sur une même ligne même quand le reste de
   la barre s'empile.
   Sur ordinateur, le groupe n'est qu'un morceau de la barre parmi les
   autres : il se met à la suite du tri et ne prend que la largeur de
   son contenu. Deux cases de deux chiffres étalées sur un tiers d'écran
   chacune donnaient à l'âge l'importance visuelle d'un champ principal
   qu'il n'a pas. Le partage de la largeur est un comportement de
   téléphone, il est déplacé dans la media query plus bas. */
.ecole-filters-groupe {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: .5rem;
    /* Un <form> peut servir de groupe (le canal d'une relance et son
       bouton) : la marge que le navigateur lui donne d'office le
       désalignerait des commandes voisines. */
    margin: 0;
}
.ecole-filters-groupe > label { flex: 0 0 auto; }
/* Assez large pour deux chiffres et les flèches du navigateur : le
   min-width de 8rem commun à la barre de filtres est pensé pour des
   menus déroulants, pas pour un âge. */
.ecole-filters .ecole-filters-groupe > input:not([type="checkbox"]):not([type="radio"]) {
    flex: 0 0 auto; width: 5.5rem; min-width: 0;
}
.ecole-filters .ecole-filters-groupe > .btn  { flex: 0 0 auto; min-width: 0; }
/* Une zone d'aperçu encore vide ne doit pas compter pour un intervalle
   dans une colonne flex : elle laissait un blanc avant qu'on ait
   choisi quoi que ce soit. */
.ecole-filters > div:empty { display: none; }
/* Dernier élément d'une carte : sa marge basse double le rembourrage
   de la carte et creuse un vide entre deux blocs successifs. */
.ecole-filters:last-child { margin-bottom: 0; }

/* Sur petit écran, un select et une recherche à moitié larges, coincés
   côte à côte, lisaient mal : un champ de saisie garde donc sa ligne à
   lui, pleine largeur, plus facile à toucher du pouce.
   Les BOUTONS, eux, se partagent la ligne qui reste. La barre était
   auparavant en flex-direction: column, qui donnait une ligne entière
   au moindre « Filtrer » de sept lettres — et deux lignes depuis que
   « Retirer les filtres » vient s'y ajouter. Le passage au retour à la
   ligne automatique (flex-wrap) laisse ce qui est court se regrouper,
   sans rien changer sur ordinateur. */
@media (max-width: 768px) {
    .ecole-filters { align-items: center; }
    .ecole-filters label { width: 100%; }
    .ecole-filters select,
    .ecole-filters input[type="text"],
    .ecole-filters input[type="search"],
    .ecole-filters input[type="date"],
    .ecole-filters input[type="number"] {
        flex: 1 1 100%; width: 100%; min-width: 0;
    }
    .ecole-filters .btn { flex: 1 1 auto; width: auto; justify-content: center; }
    /* … sauf à l'intérieur d'un groupe, dont c'est justement la raison
       d'être : ses champs se partagent une ligne. */
    .ecole-filters .ecole-filters-groupe { flex: 1 1 100%; width: 100%; }
    .ecole-filters .ecole-filters-groupe > label { width: auto; }
    /* Largeurs de base plutôt que zéro : au-delà de trois ou quatre
       éléments (le bouton « Retirer les filtres » n'apparaît que filtre
       actif), la ligne se coupe en deux au lieu d'écraser les cases
       jusqu'à l'illisible. */
    .ecole-filters .ecole-filters-groupe > input { flex: 1 1 4rem; width: auto; min-width: 3.5rem; }
    .ecole-filters .ecole-filters-groupe > .btn  { flex: 1 1 7rem; width: auto; }
}

/* Barre de filtres à deux étages (Élèves, Suivi). La recherche en tête,
   sur toute la ligne — retrouver un enfant ou une famille est le geste
   le plus courant de ces écrans — puis les menus sur une grille à
   largeurs égales. Posés bout à bout, chacun prenait la largeur de sa
   plus longue option et la barre faisait un escalier. Commune aux deux
   écrans : une barre qui se range pareil se lit pareil.
   Sélecteurs à deux classes : ils doivent l'emporter sur les règles
   .ecole-filters ci-dessus, y compris celles de la media query. */
.ecole-filters.ecole-filtres-etages { flex-direction: column; align-items: stretch; }
.ecole-filtres-etages .ecole-filtres-etages-haut {
    display: flex; align-items: center; gap: .6rem 1rem; flex-wrap: wrap;
}
.ecole-filtres-etages .ecole-filtres-etages-haut input[type="search"] { flex: 1 1 16rem; width: auto; }
.ecole-filtres-etages .ecole-filtres-case { width: auto; flex: 0 0 auto; }
/* Une colonne par menu, quel que soit leur nombre (Classe et Options
   n'existent que s'il y a des classes ou des options). ⚠ Pas de
   repeat(auto-fit, minmax(…, 1fr)) : dans ce formulaire en colonne,
   Chrome y étirait les menus à 214 px de haut. */
.ecole-filtres-etages .ecole-filtres-etages-menus {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: minmax(0, 1fr);
    align-items: start;
    gap: .6rem;
}
.ecole-filtres-etages .ecole-filtres-etages-menus select { width: 100%; min-width: 0; }
/* Posée par app.js sur un menu dont la valeur choisie ne tiendrait pas
   dans sa case : il prend la place de deux, plutôt que d'afficher
   « Tous les chèques à enc ». */
.ecole-filtres-etages .ecole-filtres-etages-menus > select.filtre-menu-large { grid-column: span 2; }
/* « Retirer les filtres » est ajouté par app.js en fin de formulaire :
   dans une colonne il s'étirerait sur toute la largeur. */
.ecole-filtres-etages > .filtres-retirer { align-self: flex-start; }
/* (La variante « --nombreux » des Élèves, deux rangées de quatre, n'existe
   plus : ses menus secondaires sont passés dans « Plus de filtres ».) */
@media (min-width: 769px) {
    /* Une rangée où un menu ne tient pas (écran étroit, libellé long)
       passe à la même disposition : quatre par ligne, le menu élargi sur
       deux cases — plutôt que de tasser tous les autres. */
    .ecole-filtres-etages .ecole-filtres-etages-menus:has(> .filtre-menu-large) {
        grid-auto-flow: row dense;
        grid-template-columns: repeat(4, minmax(0, 1fr));
    }
    .ecole-filtres-etages .ecole-filtres-etages-menus > select.filtre-menu-plein { grid-column: 1 / -1; }
}

/* Élèves — le genre à compléter : une ligne sous les compteurs, et deux
   boutons sous le nom quand on filtre sur « non renseigné ». */
.eleves-genre-rapide { display: flex; gap: .4rem; margin-top: .4rem; }
.eleves-genre-fait { margin-top: .4rem; font-size: .85rem; color: var(--color-accent-dk); }

/* ── Sorties (ecole/sorties.php, ecole/sortie.php) ── */
.sortie-heures { display: grid; grid-template-columns: 1fr 1fr; gap: 0 .8rem; }
.sortie-paiement { display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; font-size: .88rem; }
.sortie-paiement-gestes { display: flex; gap: .35rem; flex-wrap: wrap; margin-top: .35rem; }
.table td .sortie-paiement-gestes a.btn-secondary { color: var(--color-text); }
.sortie-infos p { margin: 0 0 .45rem; }
.sortie-infos p:last-child { margin-bottom: 0; }
.sortie-infos-ico { display: inline-block; width: 1.6rem; }
.sortie-infos-texte {
    margin-top: .7rem !important; padding-top: .7rem;
    border-top: 1px solid var(--color-border); white-space: normal;
}
.sortie-resume { margin: 0 0 .3rem; font-size: .9rem; }
.sortie-resume--alerte { color: var(--color-danger); }
.sortie-resume + .ecole-barre-action,
.sortie-resume + .sortie-resume + .ecole-barre-action { margin-top: .8rem; }
.sortie-criteres, .sortie-un-eleve { align-items: center; }
.sortie-criteres .ecole-filters-groupe { display: inline-flex; align-items: center; gap: .35rem; }
.sortie-criteres .ecole-filters-groupe input[type="number"] { min-width: 0; width: 4.2rem; }
.sortie-un-eleve select { flex: 1 1 16rem; }
.sortie-table .sortie-col-case { width: 1%; }
/* Les boutons d'une section repliable vivent en tête de son corps, jamais
   dans son titre (un clic y replierait la section). */
.sortie-outils { margin-bottom: .9rem; }
/* Le titre d'une section tient sur une ligne ; c'est le résumé qui passe
   dessous quand la place manque (téléphone). */
.sortie-section > summary .pliable-titre { flex-wrap: wrap; row-gap: .15rem; }
/* ⚠ La règle commune donne au libellé une base nulle (flex: 1 1 0) : sans
   largeur propre, un libellé qui ne passe pas à la ligne débordait SOUS le
   résumé (« La sortie » écrit par-dessus la date). Il prend donc sa
   largeur naturelle, et c'est le résumé qui s'adapte ou passe dessous. */
.sortie-section > summary .pliable-libelle { flex: 0 0 auto; white-space: nowrap; }
.sortie-section > summary .pliable-compte { flex: 1 1 auto; min-width: 0; white-space: normal; }
.sortie-card-actions { display: flex; gap: .4rem; flex-wrap: wrap; }
@media (max-width: 768px) {
    /* Deux boutons par ligne plutôt qu'une ligne entière chacun. */
    .sortie-card-actions { width: 100%; }
    .sortie-card-actions > .btn { flex: 1 1 calc(50% - .2rem); justify-content: center; text-align: center; white-space: normal; }
}
/* Créneaux : une petite carte par plage horaire — l'heure d'abord, en
   gros (c'est ce qu'on cherche), le jour dessous, puis la salle et les
   groupes qui y passent. */
.sortie-creneaux { list-style: none; margin: 0 0 1rem; padding: 0; display: grid; gap: .5rem; }
.sortie-creneau-ajout { margin-top: .1rem; }
.sortie-creneau {
    display: flex; align-items: center; gap: 1rem;
    padding: .6rem .8rem; border: 1px solid var(--color-border-strong);
    border-left: 3px solid var(--color-ecole); border-radius: var(--radius);
    background: var(--color-surface);
}
.sortie-creneau-heure { flex: 0 0 auto; min-width: 8.5rem; display: flex; flex-direction: column; }
.sortie-creneau-heure strong { font-size: 1.05rem; }
.sortie-creneau-heure span { font-size: .8rem; color: var(--color-muted); }
.sortie-creneau-infos { flex: 1 1 auto; min-width: 0; font-size: .88rem; }
.sortie-creneau-lieu { margin-bottom: .2rem; }
.sortie-creneau-groupes { display: flex; flex-wrap: wrap; gap: .3rem; }
.sortie-puce {
    display: inline-block; padding: .1rem .5rem; border-radius: 999px; font-size: .8rem;
    background: var(--color-ecole-lt); color: var(--color-ecole-dk);
}
@media (max-width: 768px) {
    .sortie-creneau { flex-wrap: wrap; gap: .5rem .8rem; }
    .sortie-creneau-heure { min-width: 0; }
    .sortie-creneau > .btn { margin-left: auto; }
}
.sortie-groupes {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: .8rem; margin-top: .9rem;
    /* Chaque carte à SA hauteur : étirées (défaut d'une grille), les
       cartes repliées d'une rangée grandissaient à vide dès qu'une voisine
       s'ouvrait. */
    align-items: start;
}
.sortie-groupe {
    border: 1px solid var(--color-border-strong); border-left: 3px solid var(--color-ecole);
    border-radius: var(--radius); padding: .7rem .8rem; background: var(--color-surface);
}
.sortie-groupe-tete { display: flex; align-items: center; gap: .45rem; margin-bottom: .3rem; }
/* Un groupe repliable : la carte garde son allure, le titre (summary) ne
   prend ni le rembourrage ni le filet des sections de page. */
.sortie-groupe.pliable > summary { padding: 0; border-bottom: none; }
.sortie-groupe.pliable > summary:hover { background: none; }
.sortie-groupe.pliable > summary:hover strong { text-decoration: underline; }
.sortie-groupe-corps { margin-top: .5rem; }
.sortie-groupe-modifier { margin-bottom: .45rem; }
/* « Tout replier », posé par app.js juste au-dessus de la grille. */
.sortie-groupes.pliable-groupe { margin-top: .4rem; }
.sortie-groupe-ligne { font-size: .85rem; margin-bottom: .2rem; }
.sortie-groupe-ligne--manque { color: var(--color-primary-dk); }
.sortie-groupe-membres { margin: .5rem 0 0; padding: .5rem 0 0 1.1rem; border-top: 1px solid var(--color-border); font-size: .85rem; }
.sortie-groupe-membres li { margin: .1rem 0; }
.sortie-suppr { margin-top: 1rem; padding-top: .8rem; border-top: 1px solid var(--color-border); }
.sortie-coches-gestes { align-items: center; }
/* Le bloc du haut suit les zones d'ajout : pas de double rembourrage. */
.sortie-coches--haut { padding-top: 0; padding-bottom: .6rem; }
.sortie-groupe-choix { max-width: 12rem; }
.sortie-groupe-choix--fait { outline: 2px solid var(--color-accent); outline-offset: 1px; }
.sortie-filtre-familles { margin: 0 0 .5rem; font-size: .85rem; }
.sortie-filtre-familles a.actif { font-weight: 700; text-decoration: none; color: var(--color-text); }
.sortie-reponse { font-size: .85rem; margin: .1rem 0; }
.sortie-reponse--non { color: var(--color-danger); }
.sortie-reponse--attente { color: var(--color-warning-dk); }
.sortie-prevenir { display: flex; flex-wrap: wrap; gap: .35rem; align-items: center; }
/* Un bouton-lien dans un tableau prendrait la couleur des liens (.table td a). */
.table td .sortie-prevenir a.btn-secondary { color: var(--color-text); }
/* Familles d'une sortie sur téléphone : réponses, paiement et gestes sont
   trois blocs qu'on vient lire ensemble — chacun prend sa ligne sous le
   nom au lieu de se serrer à côté (le nom tombait à trois lettres). */
@media (max-width: 768px) {
    .table-mobile.table-liste.sortie-familles tbody td { flex: 1 1 100%; }
    .table-mobile.table-liste.sortie-familles tbody td:not(:first-child) { margin-top: 8px; }
    .table-mobile.table-liste.sortie-familles .sortie-prevenir > .btn { flex: 1 1 40%; }
}
.sortie-mail-case { font-size: .85rem; margin: 0 .3rem; }
.sortie-envoi-gestes { display: flex; gap: .5rem; flex-wrap: wrap; }
/* Prévenir toutes les familles : le message, modifiable, puis les gestes. */
.sortie-annonce { margin-bottom: 1rem; }
.sortie-annonce textarea {
    width: 100%; min-height: 9rem; padding: .6rem .7rem; font: inherit; font-size: .88rem; line-height: 1.45;
    border: 1px solid var(--color-border-strong); border-radius: var(--radius);
    background: var(--color-surface); color: var(--color-text); resize: vertical;
}
.sortie-annonce-gestes { display: flex; flex-wrap: wrap; gap: .45rem; align-items: center; margin-top: .6rem; }
.table td .sortie-annonce-gestes a.btn-secondary, .sortie-annonce-gestes a.btn-secondary { color: var(--color-text); }

/* Page publique de l'autorisation (sortie_autorisation.php) */
.autor-page { max-width: 540px; }
.autor-sortie { margin-bottom: 1rem; padding: .8rem 1rem; border-radius: var(--radius); background: var(--color-surface-alt); }
.autor-sortie h2 { margin: 0 0 .4rem; font-size: 1.15rem; }
.autor-sortie p { margin: .2rem 0; }
.autor-texte { margin-top: .5rem !important; white-space: normal; }
.autor-enfant { border: 1px solid var(--color-border-strong); border-radius: var(--radius); padding: .6rem .9rem .7rem; margin: 0 0 .8rem; }
.autor-enfant legend { font-weight: 700; padding: 0 .3rem; }
.autor-groupe { margin: 0 0 .4rem; font-size: .85rem; color: var(--color-muted); }
.autor-choix { display: flex; align-items: center; gap: .5rem; margin: .35rem 0; font-weight: 500; cursor: pointer; }
.autor-choix input[type="radio"] { width: auto; margin: 0; flex: 0 0 auto; }
.autor-reponse { margin: .4rem 0 0; font-size: .85rem; color: var(--color-muted); }
.sortie-meta-mobile { display: none; }
@media (max-width: 768px) {
    /* Une carte compacte par enfant : la case, le nom, et dessous une ligne
       grise « M2 · 9 ans · Fille ». Les trois colonnes sont masquées. */
    .sortie-table tbody tr { display: flex; align-items: flex-start; gap: .6rem; padding: .6rem .8rem; margin-bottom: .4rem; }
    .sortie-table tbody td.sortie-col-case,
    .sortie-table tbody td.sortie-td-enfant {
        display: block; width: auto !important; padding: 0; margin: 0; border: none;
    }
    .sortie-table tbody td.sortie-col-case::before,
    .sortie-table tbody td.sortie-td-enfant::before { content: none; display: none; }
    .sortie-table tbody td.sortie-td-enfant { flex: 1 1 auto; font-weight: 400; }
    .sortie-table tbody td.sortie-td-enfant > div { text-align: left; }
    .sortie-meta-mobile { display: block; margin-top: .15rem; font-size: .8rem; color: var(--color-muted); }
    /* Le menu « Groupe » reste sur la ligne de l'enfant, à droite. */
    .sortie-table tbody td.sortie-td-groupe { display: block; width: auto !important; padding: 0; margin: 0; border: none; flex: 0 0 auto; }
    .sortie-table tbody td.sortie-td-groupe::before { content: none; display: none; }
    .sortie-table .sortie-groupe-choix { max-width: 8.5rem; font-size: .8rem; padding: .3rem .4rem; }
    .sortie-groupes { grid-template-columns: 1fr; }
}

@media (max-width: 768px) {
    /* Deux menus par ligne : cinq menus pleine largeur l'un sous l'autre
       repoussaient la liste d'un écran entier. Le dernier, s'il est seul
       sur sa ligne, la prend en entier plutôt que d'en laisser la moitié
       vide. */
    .ecole-filtres-etages .ecole-filtres-etages-menus {
        grid-auto-flow: row dense;   /* un menu élargi ne laisse pas de trou */
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    }
    .ecole-filtres-etages .ecole-filtres-etages-menus > select:last-child:nth-child(odd) { grid-column: 1 / -1; }
    .ecole-filtres-etages .ecole-filtres-etages-menus > select.filtre-menu-large { grid-column: 1 / -1; }
    /* Barres en flex (trésorerie, réunions, journal…) : la ligne entière. */
    form select.filtre-menu-large { flex: 1 1 100% !important; max-width: none; }
    .ecole-filtres-etages .ecole-filtres-etages-haut input[type="search"] { flex: 1 1 100%; }
    .ecole-filtres-etages > .filtres-retirer { align-self: stretch; }
}

/* Zone d'action d'un écran de liste : cocher des élèves, choisir une
   classe, valider. Elle est posée juste sous la barre de filtres et lui
   ressemblait trait pour trait — mêmes champs, même gris — alors que
   l'une ne change que ce qu'on voit et que l'autre inscrit des dizaines
   d'élèves dans une classe. Fond teinté, filet de couleur à gauche et
   intitulé en toutes lettres : on ne valide plus une affectation en
   croyant filtrer. */
.ecole-barre-action {
    margin-top: .4rem;
    padding: .7rem .9rem;
    background: var(--color-primary-lt);
    border: 1px solid var(--color-primary-mid);
    border-left: 3px solid var(--color-primary);
    border-radius: var(--radius);
}
.ecole-barre-action-titre {
    margin: 0 0 .6rem;
    font-size: .85rem;
    font-weight: 600;
    color: var(--color-text);
}
/* Un avertissement placé dans l'encadré explique la commande qui suit :
   il ne doit pas y être collé, et .ecole-sub n'a pas de marge basse. */
.ecole-barre-action > p:not(.ecole-barre-action-titre) { margin: 0 0 .6rem; }
/* Deux commandes distinctes à la suite (recalculer, puis écraser le
   barème) : sans écart elles formeraient un seul bloc et l'intitulé de
   la seconde se lirait comme la fin de la première. */
.ecole-barre-action + .ecole-barre-action { margin-top: .9rem; }
/* Variante sur une ligne (Classes › Sans classe) : l'intitulé devient le
   début de la phrase « Affecter les élèves cochés à [classe] [Affecter] »
   — une ligne de moins ; sur téléphone la phrase passe à la ligne. */
.ecole-barre-action--ligne {
    display: flex; flex-wrap: wrap; align-items: center; gap: .5rem .75rem;
}
.ecole-barre-action--ligne > .ecole-barre-action-titre { margin: 0; }
.ecole-barre-action--ligne > .ecole-filters { flex: 1 1 auto; margin: 0; }

/* Case « Tout cocher » posée hors d'un en-tête de tableau (fenêtres
   d'envoi, Réinscription, barres d'action) — mécanisme data-tout-cocher
   d'app.js. Allure d'une étiquette, pas d'un bouton : on coche, on ne
   valide rien. La case garde sa taille : une largeur de champ héritée
   l'étirerait. */
label.tout-cocher {
    display: inline-flex; align-items: center; gap: .35rem;
    margin: 0; font-size: .85rem; font-weight: 500;
    white-space: nowrap; cursor: pointer; color: var(--color-text);
}
label.tout-cocher > input[type="checkbox"] { width: auto; margin: 0; flex: none; }

/* Question posée au retour d'un message de relance. Elle n'apparaît
   qu'après un clic sur un bouton de contact : une question affichée en
   permanence finit par ne plus être lue. Grisée et non colorée — c'est
   une question, pas une alerte. */
.ecole-trace {
    margin: .75rem 0 0;
    padding: .7rem .9rem;
    background: var(--color-surface-alt);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius);
}
.ecole-trace-q { margin: 0 0 .6rem; font-size: .9rem; }

/* « Prévenir une classe » : un parent déjà ouvert dans WhatsApp se
   repère au ✓ et à la teinte verte de son bouton — où j'en suis dans la
   liste, pas une preuve d'envoi. Le compte et « Effacer les ✓ » tiennent
   à droite du titre, et passent dessous quand la place manque. */
.btn.ecole-comm-ouvert { color: var(--color-success-text); border-color: var(--color-success-border); }
.ecole-comm-coche { font-weight: 700; }
.ecole-comm-entete { flex-wrap: wrap; gap: .4rem .75rem; }
.ecole-comm-gestes { margin-bottom: .6rem; }
@media (max-width: 768px) {
    /* « Ouvrir WhatsApp » est le geste du quotidien et le plus long des
       deux mots : à parts égales il débordait de son bouton à 375 px. */
    .page-actions-btns.ecole-comm-gestes > .btn-primary { flex-grow: 1.7; }
}
.ecole-comm-suivi { display: inline-flex; align-items: center; gap: .6rem; font-size: .85rem; }
/* Modèles de message (Paramètres) : le début du texte sous le nom, sur
   une ligne — assez pour reconnaître le modèle sans l'ouvrir. */
.ecole-modele-extrait {
    flex-basis: 100%; min-width: 0; font-size: .8rem; color: var(--color-muted);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Sous-ligne grise sous une valeur de tableau, et paragraphes
   explicatifs sous les titres. */
.ecole-sub {
    font-size: .8rem;
    line-height: 1.35;
    margin: .15rem 0 0;
}

/* Fiche famille, colonne Classe : la classe puis chaque cours d'option,
   chacun en bloc (nom, enseignant, horaires). L'écart dit où finit un
   cours et où commence le suivant — sans lui, l'enseignant de l'option
   se lisait comme un second enseignant de la classe. */
.fiche-cours + .fiche-cours { margin-top: .55rem; }
.fiche-cours-option-nom { font-weight: 500; font-size: .85rem; }
.fiche-cours-option-tag {
    display: inline-block; margin-left: .3rem; padding: 0 .35rem; border-radius: 4px;
    font-size: .68rem; line-height: 1.45; vertical-align: 1px;
    background: var(--color-surface-alt); color: var(--color-muted); border: 1px solid var(--color-border-strong);
}

/* Formulaire d'une seule action, glissé dans une cellule de tableau
   à côté d'un autre bouton. */
.ecole-inline { display: inline-block; margin: 0; }

/* Groupe de boutons d'action dans une cellule. */
.ecole-actions { white-space: nowrap; }
.ecole-actions > * { display: inline-block; vertical-align: middle; margin-right: .25rem; }

/* Sur petit écran, le titre de l'en-tête et ses boutons d'action ne
   tiennent plus sur une seule ligne : ils débordaient hors de l'écran
   plutôt que de passer à la ligne. On les empile à la place. */
@media (max-width: 768px) {
    .card-header:has(.ecole-actions) { flex-wrap: wrap; row-gap: .5rem; }
    /* Plusieurs boutons de couleurs différentes, entassés en vrac sur
       une ligne trop étroite, lisaient comme un fouillis. Une colonne
       nette, un bouton par ligne, est plus calme et plus facile à
       toucher du pouce. */
    .card-header:has(.ecole-actions) .ecole-actions {
        white-space: normal; width: 100%;
        display: flex; flex-direction: column; gap: .4rem;
    }
    /* display:flex explicite : sans lui, la règle .ecole-actions > *
       plus haut (display:inline-block, même niveau de priorité mais
       écrite après .btn) l'emportait. Un <button> reste centré par
       défaut même sans flexbox, un lien <a> non — d'où le lien
       "Relancer" qui partait à gauche alors que les vrais boutons
       restaient centrés. */
    .card-header:has(.ecole-actions) .ecole-actions > * {
        display: flex; justify-content: center;
        margin: 0; width: 100%;
    }
}

/* Bloc masqué au chargement, révélé par JavaScript. */
.ecole-form-cache { display: none; }

/* Boutons en pied de modale : alignés à droite, séparés du contenu.
   Sans cette règle ils se collent au dernier champ. */
.modal-actions {
    display: flex;
    justify-content: flex-end;
    gap: .6rem;
    margin-top: 1.4rem;
    padding-top: 1rem;
    border-top: 1px solid var(--color-border);
}
.modal-actions .btn { min-width: 6rem; }
/*  Sur téléphone, les deux boutons du bas se partagent la largeur au lieu
    de se serrer à droite : « 📧 Envoyer à 21 membre(s) » ne tient pas à
    côté d'« Annuler » à 375 px, et l'un des deux passait à la ligne, seul
    et aligné à droite. Vaut pour toutes les fenêtres du site. */
@media (max-width: 768px) {
    .modal-actions { flex-wrap: wrap; }
    .modal-actions > .btn { flex: 1 1 calc(50% - .3rem); min-width: 0; justify-content: center; }
}

/* ── Paramètres de l'école › Catégories de dépenses : une ligne par
   catégorie, les gestes derrière « ⋯ » (trois boutons par ligne
   faisaient un pavé sur téléphone). ── */
.ecole-cat-liste { list-style: none; margin: 0; padding: 0; }
.ecole-cat-liste li {
    display: grid; grid-template-columns: minmax(0, 1fr) auto auto;
    align-items: center; column-gap: .6rem;
    padding: .45rem 0; border-top: 1px solid var(--color-border);
}
.ecole-cat-titre { min-width: 0; display: flex; flex-wrap: wrap; align-items: center; gap: .25rem .5rem; }
.ecole-cat-liste li:first-child { border-top: 0; }
.ecole-cat-nom { font-weight: 500; }
.ecole-cat--inactive .ecole-cat-nom { color: var(--color-muted); }
.ecole-cat-n { font-size: .82rem; color: var(--color-muted); white-space: nowrap; }
.ecole-cat-ajout { display: flex; gap: .5rem; margin-top: .75rem; max-width: 30rem; }
.ecole-cat-ajout input[type="text"] {
    flex: 1 1 auto; min-width: 0; padding: .4rem .55rem; font: inherit;
    border: 1px solid var(--color-border); border-radius: 6px;
    background: var(--color-surface); color: var(--color-text);
}
.ecole-justif-resume { margin-bottom: .75rem; }
.ecole-reg-justif { white-space: nowrap; }
.ecole-cat-def { flex-basis: 100%; font-size: .8rem; color: var(--color-muted); }
.ecole-cat-defauts-titre { margin: .25rem 0 .5rem; font-weight: 600; font-size: .9rem; }

/* ═══════════════════════════════════════════════════
   ÉCOLE — CARTES PLIABLES ET ACTIONS DE LIGNE
   ═══════════════════════════════════════════════════ */

/* Une carte pliable est un <details>, pas un bloc piloté par du
   JavaScript : l'état ouvert/fermé est tenu par le navigateur, il
   survit au rechargement de la page sans code, et la carte reste
   lisible même si le script ne part pas. */
.pliable { display: block; }

/* Le <summary> reste en display:block et c'est un enfant qui porte le
   flex : Safari, sur iOS notamment, gère mal un summary passé en
   display:flex — le marqueur revient, et sur les versions anciennes le
   pli cesse de s'ouvrir. */
.pliable > summary {
    padding: .85rem 1.25rem;
    border-bottom: 1px solid var(--color-border);
    cursor: pointer;
    list-style: none;
    transition: background var(--transition);
}
.pliable-entete {
    display: flex; align-items: center; justify-content: space-between;
    gap: .75rem;
}
/* Le triangle par défaut du navigateur, retiré des deux côtés : on
   pose le nôtre, aligné avec le titre. */
.pliable > summary::-webkit-details-marker { display: none; }
.pliable > summary::marker { content: ''; }
.pliable > summary:hover { background: var(--color-surface-alt); }

/* Repliée, la carte n'a plus de contenu sous son en-tête : la bordure
   basse deviendrait un trait dans le vide. */
.pliable:not([open]) > summary { border-bottom: none; }

.pliable-titre {
    display: flex; align-items: center; gap: .5rem;
    font-size: .95rem; font-weight: 600; margin: 0;
    /* Le titre porte aussi ce qui doit rester lisible carte repliée —
       un décompte, un montant en retard, un badge de relance. Sur un
       téléphone, trois badges à la suite d'un nom de famille sortent
       de l'écran s'ils ne peuvent pas passer à la ligne. */
    flex-wrap: wrap;
}
/*  Le libellé, quand il est long.

    Un en-tête est une rangée en flex-wrap, et flexbox décide de passer
    un élément à la ligne d'après sa largeur de CONTENU, avant toute
    réduction. « 💰 En caisse, toutes années scolaires confondues » ne
    tenant pas à côté du chevron, il partait sur sa propre ligne, le
    montant sur une troisième : le chevron se retrouvait seul en haut.

    flex-basis à zéro règle exactement ça — l'élément ne pèse plus rien
    au moment du calcul de la ligne, donc rien ne casse, puis il grandit
    dans la place restante et se replie tout seul à l'intérieur.
    min-width: 0 parce qu'un élément flex refuse par défaut de descendre
    sous la largeur de son plus long mot.

    À poser sur tout en-tête dont le libellé peut s'allonger ; ceux qui
    tiennent en deux mots s'en passent, un texte nu s'y comporte bien. */
.pliable-libelle { flex: 1 1 0; min-width: 0; }
.pliable-chevron {
    font-size: .7rem; color: var(--color-muted);
    transition: transform .2s; transform: rotate(-90deg);
    display: inline-block;
}
.pliable[open] .pliable-chevron { transform: rotate(0); }
/* Replis imbriqués (un bloc d'option contient le repli de ses élèves
   déjà placés) : la règle ci-dessus atteint TOUS les chevrons contenus,
   y compris ceux des replis fermés, qui pointaient alors vers le bas en
   annonçant le contraire de leur état. Un chevron suit le repli le plus
   proche de lui. Plus spécifique et écrite après, donc elle l'emporte. */
.pliable:not([open]) > summary .pliable-chevron { transform: rotate(-90deg); }

/* Bouton « Tout déplier », ajouté par footer.php devant un groupe de
   cartes pliables. Contrairement à celui des tableaux repliables, il
   sert aussi sur ordinateur : une liste de vingt familles se parcourt
   mal repliée quel que soit l'écran. */
.pliable-toggle-all { display: inline-flex; margin: 0 0 .75rem; }

/* ══ Les élèves déjà placés d'une option, repliés ══
   Le même mécanisme que les cartes pliables, mais ce n'en est pas une :
   c'est une ligne discrète sous un tableau. Elle reprend donc le retrait
   du tableau au lieu du rembourrage d'un en-tête de carte, et son titre
   le poids du texte courant — ce qui compte ici est le décompte, pas le
   titre. Écrit APRÈS .pliable, dont il surcharge deux valeurs. */
.pliable.ecole-opt-places {
    margin: .25rem 0 1rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-surface-alt);
}
.pliable.ecole-opt-places > summary { padding: .5rem .75rem; }
.pliable.ecole-opt-places .pliable-titre {
    font-size: .85rem; font-weight: 500; color: var(--color-muted);
}
/* Ouverte, le tableau qu'elle contient ne colle pas à ses bords. */
.pliable.ecole-opt-places[open] > .table-responsive { padding: 0 .75rem .5rem; }

/* Le décompte reste visible carte repliée : sans lui, replier revient
   à cacher l'information au lieu de la ranger. */
.pliable-compte {
    font-weight: 400; color: var(--color-muted); font-size: .78rem;
}

/* Boutons d'action d'une ligne de tableau, sur UNE seule rangée.
   Empilés verticalement ils doublaient la hauteur de chaque ligne du
   tableau des groupes. */
.ecole-actions-row {
    display: flex; align-items: center; justify-content: flex-end;
    gap: .3rem; flex-wrap: nowrap; white-space: nowrap;
}
.ecole-actions-row form { display: inline-flex; margin: 0; }
.ecole-actions-row.ecole-actions-row--debut { justify-content: flex-start; }
.ecole-actions-row .btn { padding: .3rem .55rem; }

/* Sur une CELLULE de tableau, surtout pas display:flex.
   Un <td> passé en conteneur flex sort de la mise en page du tableau :
   il ne s'étire plus à la hauteur de la rangée, et sa bordure basse se
   dessine à sa propre hauteur — d'où un trait de séparation décalé sous
   la colonne des boutons, alors qu'il est aligné partout ailleurs.
   La cellule reste donc une vraie cellule ; ce sont ses enfants qui
   s'alignent, en inline-flex. */
td.ecole-actions-row {
    display: table-cell;
    vertical-align: middle;
    text-align: right;
    white-space: nowrap;
}
td.ecole-actions-row > * {
    display: inline-flex;
    vertical-align: middle;
    margin-left: .3rem;
}
td.ecole-actions-row > *:first-child { margin-left: 0; }

/* Menu « plus d'actions » d'une ligne (classe, cours...) : les actions
   secondaires restent accessibles sans multiplier les boutons visibles.
   Repris du motif .cour-pdf-dropdown des courriers. position: absolute
   sur le menu, position: relative sur son conteneur : sur iOS Safari,
   dans une table en overflow-x: auto, un menu mal positionné se fait
   rogner par le défilement horizontal. */
.menu-plus { position: relative; display: inline-block; }
.menu-plus-list {
    display: none;
    position: absolute;
    top: calc(100% + 4px);
    right: 0;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    /*  Refonte B2·3 : carte arrondie à ombre portée, comme les menus de
        la navigation ; lignes de 44 px séparées par l'espace, plus par
        des filets. */
    border-radius: 16px;
    box-shadow: var(--shadow-lg);
    padding: 6px;
    z-index: 200;
    min-width: 240px;
    overflow: hidden;
}
.menu-plus-list.open { display: block; }
/*  Pas la place sous le bouton (ligne en bas de l'écran) : le panneau
    s'ouvre au-dessus. Posée par app.js à l'ouverture — sans elle, il
    fallait faire défiler pour lire la fin du menu, et ce défilement le
    refermait. */
.menu-plus-list.menu-plus-list--haut { top: auto; bottom: calc(100% + 4px); }
/*  Pas la place à gauche du bouton (« ⋯ » posé côté gauche) : le panneau
    s'ouvre vers la droite. Posée par app.js à l'ouverture. La largeur reste
    bornée à l'écran, pour un bouton posé au milieu sur téléphone. */
.menu-plus-list.menu-plus-list--droite { left: 0; right: auto; }
.menu-plus-list { max-width: calc(100vw - 16px); }
/* Une carte coupe ce qui dépasse d'elle (overflow: hidden, pour que son
   contenu épouse ses coins arrondis). Le panneau d'un menu ouvert sur
   l'une des dernières lignes d'un tableau était donc tronqué au bord de
   la carte — les sections de la page Classes en sont toutes. On ne lève
   la coupure que le temps où un menu est ouvert : le reste du temps, la
   carte garde ses coins nets. Sans :has() (navigateur ancien), rien ne
   change par rapport à avant. */
.card:has(.menu-plus-list.open) { overflow: visible; }
/*  Même coupure, même remède, pour les deux cadres qui portent un point de
    l'ordre du jour : ils coupent ce qui dépasse d'eux pour garder leurs
    coins arrondis, et rognaient donc le panneau « Qui s'en occupe ? » à
    deux lignes. La coupure n'est levée que le temps où un panneau est
    ouvert. À refaire pour tout conteneur en overflow: hidden qui reçoit un
    jour un menu. */
.pv-point:has(.menu-plus-list.open),
.point-card:has(.menu-plus-list.open) { overflow: visible; }
.menu-plus-list > a,
.menu-plus-list > button,
.menu-plus-list form > button {
    display: flex; align-items: center; gap: .5rem; width: 100%;
    min-height: 2.6rem; padding: .5rem .85rem; background: none; border: none;
    color: var(--color-text); text-decoration: none; text-align: left;
    font-size: .92rem; font-family: inherit; cursor: pointer;
    border-radius: 10px;
}
.menu-plus-list form:last-child > button,
.menu-plus-list > a:last-child,
.menu-plus-list > button:last-child { border-bottom: none; }
.menu-plus-list > a:hover,
.menu-plus-list > button:hover,
.menu-plus-list form > button:hover { background: var(--color-surface-alt); }
/* Un <form> dans .ecole-actions-row est ailleurs mis en
   display: inline-flex (bouton compact sur la même ligne) — mais ici
   le formulaire est une ligne de menu, pas un bouton de rangée, il lui
   faut retrouver un display normal pour occuper toute la largeur. */
.menu-plus-list form { display: block; margin: 0; }
/* Ligne destructrice d'un menu. Deux classes dans le sélecteur : la
   règle « .menu-plus-list form > button » ci-dessus, plus précise
   qu'une classe seule, remettait sinon la couleur du texte — c'est ce
   qui laissait en noir le « Supprimer définitivement » d'Utilisateurs. */
.menu-plus-list .menu-plus-danger,
.menu-plus-list .usr-menu-danger { color: var(--color-danger); }

/* Sur petit écran la rangée passe à la ligne plutôt que de forcer un
   défilement horizontal sur toute la table. */
@media (max-width: 768px) {
    .ecole-actions-row { flex-wrap: wrap; justify-content: flex-start; }
    /* La cellule n'étant pas flex, c'est le retour à la ligne du texte
       qu'on réautorise ici. */
    td.ecole-actions-row { white-space: normal; }
    /* Dans l'en-tête d'une carte pliable, les boutons partagent sinon
       la ligne avec le titre : à l'étroit, ils tombent l'un sous
       l'autre au lieu de rester côte à côte. Toute la largeur de la
       carte, sur leur propre ligne, ils s'alignent normalement. */
    .pliable-entete { flex-wrap: wrap; }
    .pliable-entete > .ecole-actions-row { flex-basis: 100%; justify-content: flex-end; }
    /* Un seul bouton (« + Groupe ») tient à côté du titre : seul sur sa
       ligne, il coûtait une rangée pour rien. */
    .pliable-entete > .ecole-actions-row:has(> :only-child) { flex-basis: auto; margin-left: auto; }
    /* Repliée, une carte avec boutons se retrouvait plus haute qu'une
       carte sans bouton (ex. Enseignants vs Groupes) : la liste des
       cartes perdait son rythme. Les boutons ne servent qu'une fois
       la carte ouverte — ils n'ont pas à peser sur la vue repliée.
       Le sélecteur vise tout enfant qui n'est pas le titre : certains
       en-têtes n'ont qu'un bouton isolé, sans passer par
       .ecole-actions-row. */
    .pliable:not([open]) .pliable-entete > *:not(.pliable-titre):not(.perms-section-compte) { display: none; }
    /* Sauf le compteur d'une section de Permissions (« 3 / 11 », ⚡) : il
       dit, replié, où sont les droits et s'il y a un réglage sur mesure. */
}

/* Grille de la semaine type : une colonne par jour d'ouverture. Les
   colonnes se partagent la largeur à égalité, sinon un samedi chargé
   écrase un mercredi à un seul groupe. */
.ecole-semaine { table-layout: fixed; }
.ecole-semaine td { vertical-align: top; }
/* Une seule ligne porte toute la semaine : le survol commun des tableaux
   (.table tr:hover td) la colorait en entier, cartes comprises, au
   moindre passage de souris (remarque de l'utilisateur). */
.ecole-semaine tr:hover td { background: transparent; }
/* Sur mobile, une grille jour × créneaux ne se lit plus une fois les
   colonnes trop étroites pour leur contenu (essayé avec une largeur
   minimale : le contenu débordait d'une colonne sur l'autre). Une
   liste par jour, empilée, reste lisible à n'importe quelle largeur. */
.ecole-semaine-liste { display: none; }
/* Planning d'un enseignant : le menu et son total, au-dessus de la grille. */
.ecole-semaine-filtre { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem .75rem; margin-bottom: .9rem; }
/* Hors barre de filtres, rien ne l'habillait (nom collé au bord) : même
   allure que les menus des barres (.ecole-filters select). */
.ecole-semaine-filtre select {
    width: auto; max-width: 100%; min-width: 12rem;
    padding: .4rem .6rem; font-size: .9rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-surface); color: var(--color-text);
}
@media (max-width: 768px) {
    .table-responsive:has(.ecole-semaine) { display: none; }
    .ecole-semaine-liste { display: block; }
}
.ecole-semaine-jour { margin-bottom: 1.25rem; }
.ecole-semaine-jour:last-child { margin-bottom: 0; }
.ecole-semaine-jour-titre {
    font-size: .9rem; font-weight: 600;
    color: var(--color-text-tertiary);
    margin: 0 0 .5rem;
}
.ecole-semaine-case {
    border-left: 3px solid var(--color-primary);
    padding: .35rem .5rem;
    margin-bottom: .5rem;
    background: var(--color-surface-alt);
    border-radius: 0 var(--radius) var(--radius) 0;
}
.ecole-semaine-case:last-child { margin-bottom: 0; }

/* En-têtes de colonne cliquables. Ils doivent se distinguer d'un
   en-tête ordinaire — sinon personne ne devine qu'on peut cliquer —
   sans pour autant ressembler à un lien de navigation. */
.ecole-tri {
    color: inherit; text-decoration: none;
    border-bottom: 1px dotted var(--color-border);
}
.ecole-tri:hover { color: var(--color-primary); border-bottom-color: var(--color-primary); }
.ecole-tri-actif { color: var(--color-primary); font-weight: 600; border-bottom: none; }

/* ══ La fenêtre de répartition d'un groupe ══
   Elle a remplacé une carte qui s'insérait entre « Groupes » et
   « Cours en option » : la page entière se réorganisait pour montrer un
   seul groupe. Plus large que les autres fenêtres, parce qu'elle porte
   un tableau — élève, âge, famille, sa classe, et le menu de
   déplacement — et non un formulaire en colonne. */
.modal-box--repartition { max-width: 900px; }

/* Son ✕ est un lien et non un bouton : la fenêtre étant rendue par le
   serveur, elle doit aussi se refermer sans JavaScript. Il reprend donc
   l'allure du bouton qu'il remplace. */
a.modal-close { text-decoration: none; line-height: 1; }

/* Les actions qui suivent le groupe regardé (liste, feuille d'appel,
   prévenir), sur la même ligne que ses créneaux. */
.ecole-rep-infos {
    display: flex; flex-wrap: wrap; align-items: center; gap: .5rem;
    margin-bottom: .75rem;
}

/* Sur téléphone la fenêtre prend tout l'écran : à 375 px, une fenêtre
   centrée avec ses marges ne laisse pas la place d'un tableau, et
   répartir une classe est de toute façon un travail qu'on fait assis.
   Écrit APRÈS la règle de base, sans quoi elle l'écraserait. */
@media (max-width: 768px) {
    .modal-overlay:has(.modal-box--repartition) { padding: 0; }
    .modal-box--repartition {
        max-width: none; width: 100%;
        max-height: 100vh; min-height: 100vh;
        border-radius: 0;
    }
}

/* ══ Horaires des vacances (docs/HORAIRES-VACANCES.md) ══
   Le repère d'une ligne de groupe : discret, sous ses créneaux habituels,
   il disparaît seul le lendemain de la fin de la période. */
.ecole-vac-repere { font-size: .8rem; color: var(--color-info); margin-top: .15rem; }
/* Le choix de la période, hors .form-group : habillé comme les menus de
   la fenêtre (un champ posé hors des contextes habillés se regarde). */
.vac-choix-periode select {
    padding: .45rem .6rem; font-size: .9rem; font-family: var(--font); max-width: 100%;
    border: 1px solid var(--color-border-strong); border-radius: var(--radius);
    background: var(--color-surface); color: var(--color-text);
}
.vac-choix-periode { flex: 1 1 auto; min-width: 0; }
.vac-choix-periode select { width: 100%; }
@media (min-width: 769px) {
    .vac-choix-periode { flex: 0 1 auto; }
    .vac-choix-periode select { width: auto; }
}
.vac-habituel { margin: -.35rem 0 .75rem; }
/* La Semaine type en période : le choix de la période et ses boutons sur
   une ligne, puis les alertes, puis les jours en blocs. */
.ecole-vac-outils {
    display: flex; flex-wrap: wrap; align-items: center; gap: .5rem .75rem;
    margin-bottom: .75rem;
}
.ecole-vac-outils-btns { display: flex; flex-wrap: wrap; gap: .5rem; }
.vac-form-inline { display: contents; }
.vac-btn-danger { color: var(--color-danger); }
.ecole-vac-alerte { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .5rem; }
.ecole-vac-alerte form { margin: 0; }
.ecole-vac-voulu {
    display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .5rem;
    padding: .4rem .75rem; margin-bottom: .5rem;
    border: 1px solid var(--color-border); border-radius: var(--radius);
}
.ecole-vac-voulu form { margin: 0; }
/* Date par date, en blocs qui se rangent : deux semaines en colonnes
   feraient une grille de quinze colonnes. */
.ecole-vac-jours {
    display: grid; gap: .75rem;
    grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
    align-items: start;
}
.ecole-vac-jours .ecole-semaine-jour { margin: 0; }
/* Un cours d'option non aménagé : son horaire habituel, en retrait. */
.ecole-vac-habituel { opacity: .8; border-left-style: dashed; }
/* Fiche famille : les horaires de l'enfant pendant les prochaines
   vacances, sous sa classe. Orange quand sa classe n'en a pas. */
/* Fenêtre « Prévenir les familles » */
.vac-annonce {
    width: 100%; padding: .5rem .6rem; font-family: var(--font); font-size: .9rem;
    border: 1px solid var(--color-border-strong); border-radius: var(--radius);
    background: var(--color-surface); color: var(--color-text); resize: vertical;
}
.vac-prevenir-btns { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; margin-top: .5rem; }
.vac-familles .vac-prevenir-btns { margin-top: 0; }
.vac-email-form { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem .9rem; margin: .25rem 0 .5rem; }
.fiche-vac { margin-top: .35rem; padding-top: .3rem; border-top: 1px dashed var(--color-border); }
.fiche-vac-titre { font-size: .78rem; font-weight: 600; color: var(--color-info); }
.fiche-vac .ecole-sub { color: var(--color-muted); }
.fiche-vac .fiche-vac--aucun { color: var(--color-warning); }
@media (max-width: 768px) {
    .ecole-vac-outils-btns { margin-left: 0; width: 100%; }
    .ecole-vac-outils-btns .btn { flex: 1 1 40%; }
}
#vac-ajouter { margin-top: .1rem; }
.vac-nouvelle {
    margin-top: 1rem; padding: .6rem .75rem;
    border: 1px dashed var(--color-border-strong); border-radius: var(--radius);
}
.vac-nouvelle > summary { cursor: pointer; font-weight: 600; font-size: .9rem; }
.vac-nouvelle-form { margin-top: .75rem; }

/* Cours en option : mêmes créneaux, même feuille d'appel qu'une classe,
   mais ils ne comptent pas dans les places. Un liseré distinct dans la
   semaine type évite de les lire comme des classes. */
.ecole-semaine-option { border-left-color: var(--color-info); }

/* Une couleur par enseignant (08/10/2026, demande de l'utilisateur) :
   le filet de la case et le nom de l'enseignant prennent sa teinte, le
   planning se lit d'un coup d'œil. Écrit APRÈS .ecole-semaine-option :
   l'enseignant l'emporte sur le liseré d'option (le badge de l'option
   reste écrit dans la case). Le code de la classe garde sa couleur. */
.ecole-semaine-case[class*="ecole-prof-c"] { border-left-color: var(--prof-c); }
.ecole-semaine-prof { font-weight: 600; color: var(--prof-c, inherit); }
.ecole-prof-c1 { --prof-c: var(--prof-1); } .ecole-prof-c2 { --prof-c: var(--prof-2); }
.ecole-prof-c3 { --prof-c: var(--prof-3); } .ecole-prof-c4 { --prof-c: var(--prof-4); }
.ecole-prof-c5 { --prof-c: var(--prof-5); } .ecole-prof-c6 { --prof-c: var(--prof-6); }
.ecole-prof-c7 { --prof-c: var(--prof-7); } .ecole-prof-c8 { --prof-c: var(--prof-8); }

/* ══ Un bloc par option, encadré et repliable ══
   Les options se suivaient sans séparation : deux tableaux de cours et
   deux listes d'élèves d'affilée, sans savoir où l'une finissait. Le
   cadre et le filet de gauche délimitent, le repli isole.

   Le filet est de la même teinte pour toutes les options, et non une
   couleur par option : le nom est écrit juste à côté, la couleur n'a
   pas à l'identifier — elle dit seulement où le bloc commence et
   s'arrête. C'est la teinte déjà donnée aux cours d'option dans la
   semaine type (.ecole-semaine-option), pour qu'ils se reconnaissent
   d'un écran à l'autre.
   Écrit APRÈS .pliable, dont il surcharge le rembourrage. */
.pliable.ecole-option-bloc {
    margin: 0 0 1.25rem;
    border: 1px solid var(--color-border);
    border-left: 3px solid var(--color-info);
    border-radius: var(--radius);
    overflow: hidden;              /* le filet suit les coins arrondis */
}
.pliable.ecole-option-bloc > summary {
    padding: .7rem 1rem;
    background: var(--color-surface-alt);
}
.pliable.ecole-option-bloc:not([open]) > summary { border-bottom: none; }

/* Le contenu retraité sous son en-tête : c'est l'indentation qui dit
   « tout ceci appartient à cette option ». */
.ecole-option-corps { padding: .9rem 1rem 1rem; }

/* Sur téléphone, la place manque pour un retrait de chaque côté : le
   cadre et le filet suffisent à délimiter. */
@media (max-width: 768px) {
    .ecole-option-corps { padding: .75rem .5rem .75rem; }
    .pliable.ecole-option-bloc > summary { padding: .7rem .6rem; }
}

/* Tuiles adhérents : effectif au-dessus, retards en dessous. Deux
   liens dans une même carte — d'où le conteneur en <div>, un <a> dans
   un <a> étant invalide. */
.adh-stat-lien {
    display: block; text-decoration: none; color: inherit;
    border-radius: var(--radius); transition: opacity .15s;
}
.adh-stat-lien:hover { opacity: .75; text-decoration: none; }

.adh-stat-retard {
    display: block; margin-top: .5rem; padding-top: .45rem;
    border-top: 1px solid var(--color-border);
    font-size: .78rem; font-weight: 600;
    color: var(--color-warning); text-decoration: none;
}
a.adh-stat-retard:hover { text-decoration: underline; }

/* « Tous à jour » n'est pas cliquable : il n'y a rien à filtrer. */
.adh-stat-retard--ok { color: var(--color-muted); font-weight: 500; }

/* Le décompte de la carte « À traiter », repliée d'office sur l'accueil
   trésorerie, prend le ton de l'alerte la plus grave qu'elle contient.
   Sans ça, replier ferait perdre l'urgence : « À traiter (3) » en gris ne
   dit pas qu'un écart de caisse attend. Posé APRÈS .pliable-compte,
   qui donne la taille et le poids et qu'on ne fait que teinter. */
.atraiter-compte--danger { color: var(--color-danger);  font-weight: 700; }
.atraiter-compte--warn   { color: var(--color-warning); font-weight: 700; }
.atraiter-compte--info   { color: var(--color-muted); }

/* ══════════════════════════════════════════════════════════════
   AIDE « ⓘ » DES RAPPORTS — includes/aide_financiere.php
   Le texte est dans la page dès le départ, simplement caché : trois
   lignes déjà connues ne valent pas un aller-retour réseau chez
   l'hébergeur. Ouverture et placement mutualisés dans app.js.
   ══════════════════════════════════════════════════════════════ */

.aide { display: inline; }

/* Un rond discret, qui ne prend pas le pas sur le chiffre qu'il
   accompagne. Son ::after élargit la cible tactile sans l'agrandir. */
.aide-btn {
    position: relative;
    display: inline-flex; align-items: center; justify-content: center;
    width: 20px; height: 20px; margin-left: .35rem;
    border: 1px solid transparent; border-radius: 50%;
    background: var(--color-neutral-soft); color: var(--color-muted);
    font-family: Georgia, 'Times New Roman', serif; font-size: .78rem; font-weight: 700;
    font-style: italic; line-height: 1;
    text-transform: none; letter-spacing: normal;
    cursor: pointer; vertical-align: middle;
    transition: color .12s, border-color .12s;
}
.aide-btn::after {           /* cible tactile élargie, invisible */
    content: ""; position: absolute;
    top: -12px; right: -12px; bottom: -12px; left: -12px;
}
.aide-btn:hover,
.aide-btn[aria-expanded="true"] {
    color: var(--color-primary); border-color: var(--color-primary);
}

/* ── La bulle ──────────────────────────────────────────────────
   position: fixed, et non absolute : une bulle en absolu serait
   rognée par la première carte qui l'entoure — les cartes coupent ce
   qui dépasse d'elles pour garder leurs coins arrondis. En fixed elle
   échappe à tous ces découpages, et app.js la place sous le bouton
   en la ramenant dans l'écran si elle débordait.
   Elle flotte par-dessus la page : ouvrir une explication ne déplace
   plus rien autour, ce qui était insupportable au milieu d'un tableau.

   Un ⓘ peut désormais être posé n'importe où, y compris dans une carte qui
   porte un transform — toute carte animée à l'apparition (.stat-card) ou
   qui se soulève au survol. Un transform fait de la carte le repère de ce
   qui est en fixed à l'intérieur d'elle, et la bulle s'y plaçait de travers
   avant d'y être rognée ; app.js la sort donc dans <body> le temps de son
   affichage et la remet à sa place en refermant, pour qu'à l'impression
   elle sorte sous son propre chiffre.
   ⚠ Au-dessus de TOUT, fenêtres comprises (niveau 9999, et 10000 pour le
   voile du menu mobile) : à 400, une ⓘ ouverte dans une fenêtre — celle
   d'une classe — s'affichait derrière elle. Elle n'apparaît qu'à la
   demande et se referme au clic suivant : rien ne peut rester caché
   dessous. */
.aide-txt {
    position: fixed; left: 0; top: 0; z-index: 10050;
    display: block;
    width: min(21rem, calc(100vw - 24px));
    margin: 0;
    padding: .75rem 1rem;
    /*  Refonte B2·3 : bulle foncée à texte clair (claire en sombre) — les
        couleurs du texte et du fond inversées, elle se détache de la
        page dans les deux thèmes. */
    border: 1px solid transparent;
    border-radius: 14px;
    background: var(--color-text);
    color: var(--color-surface);
    box-shadow: var(--shadow-lg);
    font-size: .78rem; font-weight: 400; font-style: normal;
    line-height: 1.55; text-align: left;
    text-transform: none; letter-spacing: normal;
    hyphens: auto;
}

/* Une explication longue — celles du module école font deux paragraphes —
   dépasserait du bas de l'écran sur un téléphone, et la fin serait perdue
   sans que rien ne le dise. Plafonnée à la hauteur de la fenêtre, elle
   défile pour elle-même : on voit alors qu'il y a une suite. */
.aide-txt { max-height: min(24rem, calc(100vh - 24px)); overflow-y: auto; }

/* Les explications du module école sont écrites en paragraphes, celles des
   rapports financiers en texte simple : les deux se lisent dans la même bulle.
   Un <span> et non un <p>, parce que le rond se pose au bout d'un paragraphe
   et qu'un <p> dans un <p> est refermé d'office par le navigateur. */
.aide-txt .aide-p { display: block; }
.aide-txt .aide-p + .aide-p { margin-top: .55rem; }

/* ============================================================
   FLÈCHE « REVENIR EN HAUT » (commune : footer.php + app.js)
   ============================================================
   Remplace les deux boutons recopiés de la trésorerie (.btn-top,
   .btn-scroll-top), posés à 24 px du bas : sur téléphone ils tombaient
   SUR la barre fixe du bas. Ici, sur téléphone, la flèche se pose
   au-dessus de cette barre (hauteur de la barre + zone de sécurité de
   l'iPhone + un écart). */
.btn-remonter {
    position: fixed; right: 1.25rem; bottom: 1.5rem; z-index: 950;
    display: flex; align-items: center; justify-content: center;
    width: 42px; height: 42px; border-radius: 50%;
    border: none; cursor: pointer;
    background: var(--color-primary-fond); color: var(--color-on-fond); font-size: 1.2rem;
    box-shadow: 0 2px 8px var(--pal-noir-a20);
}
@media (max-width: 768px) {
    .btn-remonter {
        right: .9rem;
        bottom: calc(4.5rem + env(safe-area-inset-bottom, 0px));
    }
}
@media print { .btn-remonter { display: none !important; } }

/* Relances : les deux réglages (année, délai de repos) derrière
   « Filtres », sous le résumé. Dans le repli, ils gardent la mise en
   rangée des barres de filtres de l'école. */
.ecole-relances-filtres-corps {
    display: flex; flex-wrap: wrap; align-items: center; gap: .5rem;
    margin-top: .5rem;
}

/* ── Un nom qui ouvre sa fiche (élève, famille, adhérent) : UN seul style ──
   Tout nom de personne s'ouvre, partout (décision du 02/10/2026) : il n'y a
   plus à distinguer un nom cliquable d'un autre. Les pointillés, répétés
   sur toute une liste, faisaient « brouillon » (remarque de l'utilisateur,
   03/10/2026). Désormais :
   · ordinateur : rien au repos, souligné en orange au survol ;
   · téléphone (pas de survol, `hover: none`) : un trait fin et pâle reste
     visible — le seul repère avant de toucher —, orange au toucher.
   Mêmes règles pour tous les noms : école (`a.nom-lien`, `.prog-liste-nom`),
   Adhérents (liste et cartes), Opérations, Cotisations. `.main-content`
   devant : plus précis que `.table td a`, qui les peindrait en orange ;
   `.modal-overlay` : une fiche posée par-dessus la page est hors de
   `.main-content`. Un nom ajouté demain prend `.nom-lien`, rien d'autre. */
.main-content a.nom-lien, .modal-overlay a.nom-lien, .prog-liste-nom { font-weight: 600; }
.main-content :is(a.nom-lien, .prog-liste-nom, .ops-adh-lien, .cot-membre-link),
.modal-overlay a.nom-lien {
    color: var(--color-text);
    border-bottom: 0;
    text-decoration: none;
    text-underline-offset: 3px; text-decoration-thickness: 1px;
}
.main-content :is(a.nom-lien, .ops-adh-lien, .cot-membre-link):is(:hover, :focus-visible, :active),
.modal-overlay a.nom-lien:is(:hover, :focus-visible, :active),
.main-content .prog-liste a:is(:hover, :active) .prog-liste-nom {
    color: var(--color-primary);
    text-decoration: underline solid var(--color-primary);
}
@media (hover: none) {
    .main-content :is(a.nom-lien, .prog-liste-nom, .ops-adh-lien, .cot-membre-link),
    .modal-overlay a.nom-lien {
        text-decoration: underline solid var(--color-border-strong);
    }
    .main-content :is(a.nom-lien, .ops-adh-lien, .cot-membre-link):active,
    .modal-overlay a.nom-lien:active,
    .main-content .prog-liste a:active .prog-liste-nom {
        text-decoration-color: var(--color-primary);
    }
}

/* ═══════════════════════════════════════════════════
   LISTES — refonte B2·3 (maquettes 2, 6 et 7)
   ═══════════════════════════════════════════════════
   Le vocabulaire commun des grandes listes (Élèves, Familles, Registre,
   Opérations) : l'année en gris à côté du titre, des compteurs en
   segments, une barre de filtres en pilules sur une ligne, une seule
   carte dont chaque ligne porte son nom en gras, une ligne grise et des
   pilules. Sur téléphone, la ligne tient en une rangée (nom + pilules)
   et se déplie au toucher : le détail en phrases, puis deux boutons à
   largeurs égales. Une liste l'adopte en posant .table-liste sur son
   tableau .table-mobile--repliable et .liste-filtres sur sa barre. */
.liste-titre-annee { color: var(--color-muted); font-size: 1.1rem; font-weight: 500; white-space: nowrap; }

/* Compteurs en segments : chacun est un lien vers la liste qu'il compte. */
.liste-segments-rangee { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem .75rem; margin-bottom: 1rem; }
.liste-segments {
    display: inline-flex; flex-wrap: wrap; gap: 6px; padding: 4px;
    background: var(--color-neutral-soft); border-radius: 14px;
}
.liste-segment {
    display: flex; align-items: center; justify-content: center; gap: .5rem;
    min-height: 42px; padding: 0 1rem; border-radius: 11px;
    color: var(--color-neutral-text); font-size: .9rem; font-weight: 600; text-decoration: none; white-space: nowrap;
}
.liste-segment b { color: var(--color-text); font-variant-numeric: tabular-nums; }
.liste-segment:hover { color: var(--color-text); text-decoration: none; }
.liste-segment--actif, .liste-segment--actif:hover { background: var(--color-surface); color: var(--color-primary); box-shadow: var(--shadow); }
.liste-segment--actif b { color: var(--color-primary); }
/* Un compteur qui signale un retard garde la couleur de l'alerte (Actions). */
.liste-segment--alerte b { color: var(--color-danger); }
.liste-segments-note { color: var(--color-muted); font-size: .875rem; }
.liste-segments-note a { color: var(--color-primary); font-weight: 700; }

/* La barre de filtres en pilules, sur une ligne : la recherche prend la
   place, les menus leur largeur, « Plus de filtres » est une pilule qui
   déplie le reste dessous. Sélecteurs à trois classes : ils doivent
   l'emporter sur les règles des barres à étages. */
form.ecole-filtres-etages.liste-filtres { flex-direction: row; flex-wrap: wrap; align-items: center; gap: .6rem; margin-bottom: 1rem; }
.liste-filtres > .ecole-filtres-etages-haut { flex: 1 1 16rem; min-width: 0; position: relative; }
/* La loupe : dessinée par un masque, elle prend la couleur du thème. */
.liste-filtres > .ecole-filtres-etages-haut::before {
    content: ''; position: absolute; left: 16px; top: 50%; width: 18px; height: 18px; margin-top: -9px;
    background: var(--color-muted); pointer-events: none;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='M20 20l-3.5-3.5'/%3E%3C/svg%3E") center / contain no-repeat;
            mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='M20 20l-3.5-3.5'/%3E%3C/svg%3E") center / contain no-repeat;
}
.liste-filtres > .ecole-filtres-etages-haut input[type="search"] { width: 100%; min-height: 46px; padding-left: 44px; font-size: .95rem; }
.liste-filtres .ecole-filtres-etages-menus { display: flex; flex-wrap: wrap; gap: .6rem; }
.liste-filtres .ecole-filtres-etages-menus select {
    width: auto; max-width: 15rem; min-height: 44px; font-weight: 600; text-overflow: ellipsis;
}
.liste-filtres .ecole-filtres-etages-menus select.filtre-menu-large { max-width: none; }
/* Un filtre qui agit se voit : la pilule prend la teinte du module
   (classe posée par app.js, qui sait déjà quels filtres sont actifs). */
.liste-filtres select.filtre-actif {
    background-color: var(--color-primary-mid); border-color: var(--color-primary); color: var(--color-primary);
}
.liste-filtres > .ecole-filtres-plus > summary {
    min-height: 44px; padding: 0 1rem; border-radius: 999px; box-sizing: border-box;
    border: 1px solid var(--color-border-strong); background: var(--color-surface); color: var(--color-text);
    font-size: .9rem; font-weight: 600; white-space: nowrap;
}
.liste-filtres > .ecole-filtres-plus > summary::before { content: none; }
.liste-filtres > .ecole-filtres-plus > summary::after { content: '▾'; color: var(--color-muted); transition: transform .15s; }
.liste-filtres > .ecole-filtres-plus[open] > summary::after { transform: rotate(180deg); }
.liste-filtres > .ecole-filtres-plus:has(.ecole-filtres-plus-nb) > summary {
    background: var(--color-primary-mid); border-color: var(--color-primary); color: var(--color-primary);
}
.liste-filtres .ecole-filtres-plus-nb { color: inherit; font-weight: 600; }
.liste-filtres > .ecole-filtres-plus[open] { flex: 1 1 100%; order: 5; }
.liste-filtres > .ecole-filtres-plus[open] > .ecole-filtres-etages-menus { margin-top: .6rem; }
.liste-filtres .lf-court { display: none; }
.liste-filtres > .filtres-retirer { order: 6; align-self: center; min-height: 44px; border-radius: 999px; }

/* La liste : une seule carte, des lignes aérées. */
.table-liste { font-size: .95rem; }
.table-liste th { font-size: .85rem; }
@media (min-width: 769px) {
    .table-liste th { padding: 10px 20px; }
    .table-liste td { padding: 11px 20px; }
}
.table-liste td:first-child .nom-lien, .table-liste td:first-child > strong { font-weight: 700; }
.liste-sous { color: var(--color-muted); font-size: .85rem; }
.table td .liste-sous a, .table td.liste-td-tel a { color: inherit; font-weight: inherit; }
.liste-gris { color: var(--color-muted); }
/* Ce qu'une colonne dit sur ordinateur, repris sous le nom sur téléphone,
   quand la colonne ne tient pas à côté (sa cellule porte .hide-mobile). */
.liste-sous-mobile { display: none; }
@media (max-width: 768px) {
    .liste-sous-mobile { display: block; margin-top: .25rem; font-size: .85rem; color: var(--color-muted); }
    .liste-sous-mobile .liste-sous { display: inline; margin-left: .35rem; }
}
.table-liste td.liste-nowrap { white-space: nowrap; }
.table-liste .liste-th-actions, .table-liste .liste-actions { text-align: right; }
.liste-actions .ecole-geste { flex-wrap: nowrap; justify-content: flex-end; gap: .5rem; }
.table-liste .btn-sm { min-height: 2.5rem; padding: 0 .9rem; font-size: .88rem; }
/* Le détail en phrases de la ligne dépliée : téléphone seulement. */
.table-liste td.liste-td-tel { display: none; }
.liste-pilule {
    display: inline-flex; align-items: center; gap: .35rem; min-height: 28px; padding: 0 .75rem;
    border-radius: 14px; font-size: .85rem; font-weight: 700; white-space: nowrap; text-decoration: none;
}
.table td a.liste-pilule { font-weight: 700; }
.liste-pilule--classe { background: var(--color-primary-mid); color: var(--color-primary); }
.liste-pilule--warn   { background: var(--color-warning-soft); color: var(--color-warning-text); }
.liste-pilule--danger { background: var(--color-danger-lt); color: var(--color-danger); }
.liste-pilule--ok     { background: var(--color-success-soft); color: var(--color-success-text); }
.liste-pilule--neutre { background: var(--color-neutral-soft); color: var(--color-neutral-text); }
/* Sorties : deux cartes (à venir, passées), deux tableaux — les mêmes
   largeurs de colonnes pour que l'œil passe de l'un à l'autre. */
.sorties-liste th:nth-child(2) { width: 18%; }
.sorties-liste th:nth-child(3) { width: 26%; }

@media (max-width: 768px) {
    .liste-titre-annee { font-size: .95rem; }
    /* Segments : ils se partagent la largeur, trois par ligne au plus. */
    .liste-segments { display: flex; flex: 1 1 100%; }
    .liste-segment { flex: 1 1 28%; padding: 0 .5rem; font-size: .85rem; }

    /* Filtres : la recherche et la pilule « Filtres » sur une ligne ; les
       menus du quotidien se rangent derrière elle — sauf celui qui agit,
       qui reste affiché (un filtre posé ne se cache pas). */
    .liste-filtres > .ecole-filtres-etages-haut { order: 1; flex: 1 1 0; }
    .liste-filtres > .ecole-filtres-plus,
    .liste-filtres > .ecole-filtres-plus[open] { order: 2; }
    .liste-filtres > .ecole-filtres-etages-menus { order: 3; flex: 1 1 100%; }
    .liste-filtres .lf-long { display: none; }
    .liste-filtres .lf-court { display: inline; }
    /* Rangés derrière la pilule « Filtres »… seulement s'il y en a une : une
       barre sans « Plus de filtres » (Actions) garde ses menus à l'écran. */
    .liste-filtres:has(> .ecole-filtres-plus):not(:has(> .ecole-filtres-plus[open])) > .ecole-filtres-etages-menus > select:not(.filtre-actif) { display: none; }
    .liste-filtres:has(> .ecole-filtres-plus):not(:has(> .ecole-filtres-plus[open])) > .ecole-filtres-etages-menus:not(:has(.filtre-actif)) { display: none; }
    .liste-filtres .ecole-filtres-etages-menus select { flex: 1 1 40%; max-width: none; }
    .liste-filtres > .filtres-retirer { flex: 1 1 100%; }

    /* Lignes : plus de cartes séparées, une rangée par ligne dans la
       carte commune — le nom, puis les pilules marquées « coup d'œil ». */
    .table-mobile.table-liste tbody tr {
        display: flex; flex-wrap: wrap; align-items: center; gap: 0 8px;
        margin: 0; padding: 12px 14px; border: 0; border-bottom: 1px solid var(--color-border);
        border-radius: 0; box-shadow: none; background: transparent; cursor: pointer;
    }
    .table-mobile.table-liste tbody tr:last-child { border-bottom: 0; }
    /* Le tableau lui-même en bloc : resté en « table », il prenait la
       largeur du titre le plus long (une ligne en nowrap) et poussait la
       pilule et le « ⋯ » hors de la carte (Courriers, objet long). */
    .table-mobile.table-liste { display: block; width: 100%; }
    .table-mobile.table-liste tbody td {
        display: block; flex: 0 0 auto; width: auto !important; padding: 0; font-size: .95rem;
    }
    .table-mobile.table-liste tbody td.table-mobile-secondary { display: none; }
    .table-mobile.table-liste tbody td::before { content: none; }
    .table-mobile.table-liste tbody td:first-child {
        flex: 1 1 0; min-width: 0; margin: 0; padding: 0; border: 0; font-weight: 400;
    }
    .table-mobile.table-liste tbody td:first-child::after { content: none; }
    .table-mobile.table-liste tbody td:first-child > .nom-lien,
    .table-mobile.table-liste tbody td:first-child > strong {
        display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    }
    /* NOM, puis le prénom dessous en plus petit : coupé par « … » à côté
       des pilules, il ne se lisait plus (« DUPONT-LAMBERT Jea… »). Chaque
       ligne garde son « … » si elle reste trop longue. La rangée grandit
       à peine : interligne serré, rembourrage repris de 2 px. */
    .table-mobile.table-liste tbody tr:has(> td:first-child .nom-prenom) { padding-top: 10px; padding-bottom: 10px; }
    .table-mobile.table-liste tbody td:first-child > .nom-lien:has(.nom-prenom),
    .table-mobile.table-liste tbody td:first-child > strong:has(.nom-prenom) { white-space: normal; line-height: 1.25; }
    .table-mobile.table-liste tbody td:first-child .nom-nom,
    .table-mobile.table-liste tbody td:first-child .nom-prenom {
        display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    }
    .table-mobile.table-liste tbody td:first-child .nom-prenom {
        font-weight: 400; font-size: .88rem; color: var(--color-muted);
    }
    .table-mobile.table-liste tbody td:not(:first-child) > div { text-align: left; }
    /* Dépliée : le détail en phrases sous un filet en pointillés, puis les
       boutons à largeurs égales. */
    .table-mobile.table-liste tbody tr.tr--ouverte td.liste-td-tel {
        display: block; flex: 1 1 100%; margin-top: 8px; padding-top: 8px;
        border-top: 1px dashed var(--color-border); color: var(--color-muted); font-size: .9rem; line-height: 1.5;
    }
    .table-mobile.table-liste tbody td.liste-actions { flex: 1 1 100%; margin-top: 10px; text-align: left; white-space: normal; }
    .table-mobile.table-liste .liste-actions .ecole-geste {
        display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 8px;
    }
    .table-mobile.table-liste .liste-actions .ecole-geste > * { margin: 0; }
    .table-mobile.table-liste .liste-actions .btn { width: 100%; min-height: 44px; }
    .table-mobile.table-liste .liste-actions .menu-plus { display: block; }
    /* « Tout déplier » : un lien discret au-dessus de la liste. */
    .liste-carte > .table-mobile-toggle-all {
        margin: .35rem .6rem 0; min-height: 0; padding: .3rem .5rem; border: 0; background: none;
        color: var(--color-primary); font-size: .85rem;
    }
}

/* Libellés à deux longueurs : le long sur ordinateur, le court sur téléphone. */
.lf-court { display: none; }
@media (max-width: 768px) { .lf-long { display: none; } .lf-court { display: inline; } }
@media (min-width: 769px) { .liste-tel-seul { display: none !important; } }

/* Tuiles-liens au-dessus d'une liste : un trait de couleur, un libellé,
   un chiffre. Chacune filtre la liste qu'elle compte ; celle qui est
   posée est entourée. */
.liste-tuiles { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: .75rem; margin-bottom: 1rem; }
.liste-tuile {
    display: flex; align-items: center; gap: .75rem; padding: .75rem 1.1rem;
    background: var(--color-surface); border-radius: var(--radius-lg); box-shadow: var(--shadow);
    color: var(--color-text); text-decoration: none; --ton: var(--color-primary);
}
.liste-tuile:hover { text-decoration: none; color: var(--color-text); }
.liste-tuile--danger { --ton: var(--color-danger); }
.liste-tuile--warn   { --ton: var(--color-warning-text); }
.liste-tuile--ok     { --ton: var(--color-success); }
.liste-tuile--neutre { --ton: var(--color-neutral-text); }
.liste-tuile-trait { flex: none; width: 10px; height: 36px; border-radius: 5px; background: var(--ton); }
.liste-tuile-texte { flex: 1 1 auto; min-width: 0; }
.liste-tuile-lib { display: block; color: var(--color-muted); font-size: .85rem; font-weight: 600; }
.liste-tuile-nb { font-family: var(--font-title); font-size: 1.35rem; font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
/* Une précision sous le montant d'une tuile (« dont 6 690 € en retard », Suivi). */
.liste-tuile-texte > .liste-sous { display: block; }
.liste-tuile--danger .liste-tuile-nb, .liste-tuile--warn .liste-tuile-nb, .liste-tuile--ok .liste-tuile-nb { color: var(--ton); }
.liste-tuile-fleche { color: var(--color-muted); }
.liste-tuile--active { box-shadow: var(--shadow), inset 0 0 0 2px var(--color-primary); }
.liste-tuile--info { --ton: var(--color-info); }
.liste-tuile--or   { --ton: var(--color-gold-text); }
.liste-tuile--info .liste-tuile-nb, .liste-tuile--or .liste-tuile-nb { color: var(--ton); }
a.liste-tuile--lien:hover { box-shadow: var(--shadow-md); }
a.liste-tuile--lien.liste-tuile--active:hover { box-shadow: var(--shadow-md), inset 0 0 0 2px var(--color-primary); }
/* Une précision sous le chiffre (poids d'un dossier, date du relevé…). */
.liste-tuile-texte > .stat-sub { display: block; margin-top: 2px; font-size: .8rem; color: var(--color-muted); }
/* Nombre de colonnes : 3 par défaut ; 2, 4, ou « auto » quand le nombre
   de tuiles varie (caisses, bilan). Sur téléphone, 2 par ligne. */
.liste-tuiles--2    { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.liste-tuiles--4    { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.liste-tuiles--auto { grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); }
/* Trois chiffres courts : trois par ligne, téléphone compris — à deux par
   ligne, le troisième restait seul sous les deux autres. */
.liste-tuiles--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }

/* Lignes d'une famille */
.liste-adhesion { display: flex; align-items: center; gap: .3rem; margin-top: .25rem; }
.liste-adhesion .liste-pilule { min-height: 24px; font-size: .8rem; }
.table td a.liste-contact { display: inline-flex; align-items: center; gap: .4rem; color: var(--color-text); font-weight: 400; }
.table td a.liste-contact--wa, .table td a.liste-btn-wa { color: var(--color-success); font-weight: 700; font-size: .85rem; }
.table-liste .liste-th-montant, .table-liste td.liste-montant { text-align: right; white-space: nowrap; }
.liste-montant-nb { font-size: 1.05rem; font-weight: 700; font-variant-numeric: tabular-nums; }
.liste-montant--danger .liste-montant-nb { color: var(--color-danger); }
.liste-montant--warn   .liste-montant-nb { color: var(--color-warning-text); }
.liste-montant--ok     .liste-montant-nb { color: var(--color-success); }
.liste-compte { margin: .6rem .25rem 0; }

@media (max-width: 768px) {
    .liste-tuiles { gap: .4rem; }
    .liste-tuile { padding: .5rem .6rem; }
    .liste-tuile-trait, .liste-tuile-fleche { display: none; }
    .liste-tuile-lib { font-size: .78rem; }
    .liste-tuile-nb { font-family: var(--font); font-size: .9rem; font-weight: 700; }
    .liste-tuiles--4, .liste-tuiles--auto { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .liste-tuile--pleine { grid-column: 1 / -1; }
    /* Quatre gestes : deux par ligne, à largeurs égales. */
    .table-mobile.table-liste .liste-actions .liste-geste-famille { grid-auto-flow: row; grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .table-mobile.table-liste tbody td.liste-montant { text-align: right; }
    .table-mobile.table-liste tbody td:first-child > .liste-adhesion { margin-top: .3rem; }
}
.table-liste td a.btn-secondary { color: var(--color-text); }
@media (max-width: 768px) {
    /* « Autres actions » et le bouton principal côte à côte, à parts égales. */
    .page-header > .page-actions.liste-entete-actions { flex-wrap: nowrap; gap: .5rem; }
    .liste-entete-actions > * { flex: 1 1 0; min-width: 0; }
    .liste-entete-actions > .menu-plus > .btn { width: 100%; }
    .liste-entete-actions .btn { padding-left: .5rem; padding-right: .5rem; }
}
.table td .liste-sous .nom-lien { font-weight: 400; }
@media (max-width: 768px) {
    .liste-entete-actions > .menu-plus { flex: 0 0 auto; }
    /* Les gestes d'une famille : deux par ligne, un dernier seul s'étire. */
    .table-mobile.table-liste .liste-actions .liste-geste-famille { display: flex; flex-wrap: wrap; }
    .table-mobile.table-liste .liste-actions .liste-geste-famille > * { flex: 1 1 40%; width: auto; }
}

/* Entrées · Sorties · Solde de la liste filtrée, puis le nombre
   d'opérations et les pages (Registre, Opérations). */
.liste-totaux { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)) auto; gap: .75rem; align-items: stretch; margin-bottom: 1rem; }
.liste-totaux--4 { grid-template-columns: repeat(4, minmax(0, 1fr)) auto; }
.liste-totaux--2 { grid-template-columns: repeat(2, minmax(0, 1fr)) auto; }
.liste-totaux-pied {
    display: flex; flex-direction: column; justify-content: center; gap: .15rem;
    padding: 0 .4rem; color: var(--color-muted); font-size: .9rem; font-variant-numeric: tabular-nums;
}
.liste-totaux-pied .ops-resume-pag { margin: 0; }
.liste-tuile--neutre .liste-tuile-trait { background: var(--color-neutral-text); }

/* Le bandeau d'un jour et le filet du sens de l'argent (5 px). */
.ecole-registre-table.table-liste tr.ecole-reg-jour td,
.ecole-registre-table.table-liste tr.ecole-reg-jour:hover td {
    background: var(--color-neutral-soft); color: var(--color-neutral-text);
    font-size: .85rem; letter-spacing: 0; padding-top: .5rem; padding-bottom: .5rem;
}
.ecole-registre-table.table-liste tr.ecole-reg--famille   > td:first-child,
.ecole-registre-table.table-liste tr.ecole-reg--sortie    > td:first-child { box-shadow: inset 5px 0 0 var(--color-success); }
.ecole-registre-table.table-liste tr.ecole-reg--depense   > td:first-child { box-shadow: inset 5px 0 0 var(--color-danger); }
.ecole-registre-table.table-liste tr.ecole-reg--transfert > td:first-child,
.ecole-registre-table.table-liste tr.ecole-reg-depart     > td:first-child { box-shadow: inset 5px 0 0 var(--color-border-strong); }
.ecole-registre-table.table-liste .ecole-reg-meta { font-size: .85rem; }

@media (max-width: 768px) {
    .liste-totaux, .liste-totaux--4 { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: .4rem; }
    .liste-totaux--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .liste-totaux--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .liste-totaux .liste-tuile { justify-content: center; text-align: center; padding: .5rem .25rem; }
    /* À trois par ligne, un montant à cinq chiffres touchait les bords. */
    .liste-totaux:not(.liste-totaux--2):not(.liste-totaux--4) .liste-tuile-nb { font-size: .82rem; letter-spacing: -.01em; }
    .liste-totaux-pied { grid-column: 1 / -1; flex-direction: row; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .25rem .75rem; padding: 0 .25rem; }
    /* Dans le tableau serré du Registre, « ⋯ » garde sa place. */
    .ecole-registre-table .ecole-geste-plus { display: none; }
    .ecole-registre-table.table-liste { font-size: .9rem; }

    /* Registre sur téléphone : une rangée par ligne, comme les autres
       listes (capture de l'utilisateur : le tableau gardait une colonne
       Actions pour un gros « ⋯ », et le bandeau de jour, en colspan sur
       des colonnes masquées, laissait une colonne fantôme vide à droite).
       Les gestes passent par le glisser et le « ⋯ » discret d'app.js. */
    .table-mobile.ecole-registre-table tbody td.ecole-reg-objet { flex: 1 1 0; min-width: 0; }
    .table-mobile.ecole-registre-table tbody td.ecole-lot-col { flex: 0 0 auto; width: auto; padding: 0; }
    .table-mobile.ecole-registre-table tbody td.ecole-montant { white-space: nowrap; text-align: right; }
    .table-mobile.ecole-registre-table tbody tr.glisser-avec-points > td.ecole-actions { display: none; }
    .table-mobile.ecole-registre-table tbody td.col-secondaire { display: none; }
    .table-mobile.ecole-registre-table tbody tr.ecole-reg-jour { padding: 0; }
    .table-mobile.ecole-registre-table tbody tr.ecole-reg-jour > td { flex: 1 1 100%; padding: 6px 14px; }
    /* Le filet du sens de l'argent passe sur la rangée : posé sur la
       première cellule, sans rembourrage, il collerait au texte. */
    .table-mobile.ecole-registre-table tbody tr[class*="ecole-reg--"] > td:first-child,
    .table-mobile.ecole-registre-table tbody tr.ecole-reg-depart > td:first-child { box-shadow: none; }
    .table-mobile.ecole-registre-table tbody tr.ecole-reg--famille,
    .table-mobile.ecole-registre-table tbody tr.ecole-reg--sortie    { box-shadow: inset 5px 0 0 var(--color-success); }
    .table-mobile.ecole-registre-table tbody tr.ecole-reg--depense   { box-shadow: inset 5px 0 0 var(--color-danger); }
    .table-mobile.ecole-registre-table tbody tr.ecole-reg--transfert,
    .table-mobile.ecole-registre-table tbody tr.ecole-reg-depart     { box-shadow: inset 5px 0 0 var(--color-border-strong); }
}

/* ── Opérations de la trésorerie (.ops-table--liste) ──
   Mêmes lignes que la maquette : bandeau de jour gris, filet de 5 px
   selon le sens de l'argent, montant en gras, « Modifier » + « ⋯ Plus ». */
.ops-resume > .liste-totaux { margin-bottom: .5rem; }
.ops-table--liste { font-size: .95rem; }
.ops-table.ops-table--liste tr.ops-jour td,
.ops-table.ops-table--liste tr.ops-jour:hover td {
    background: var(--color-neutral-soft); color: var(--color-neutral-text);
    font-size: .85rem; letter-spacing: 0; border-bottom: 0;
}
.ops-table.ops-table--liste tbody tr.ops-row > td:first-child { border-left-width: 5px; }
.ops-table--liste .ops-desc { font-weight: 700; }
.ops-table--liste .ops-ligne-meta { font-size: .85rem; }
.ops-table--liste .ops-td-montant { font-size: 1.05rem; font-weight: 700; }
.ops-table--liste .ops-th-montant { width: 140px; }
.ops-table--liste td .ops-actions a.btn-secondary { color: var(--color-text); }
@media (min-width: 769px) {
    .ops-table--liste th { padding: 10px 18px; font-size: .85rem; }
    .ops-table--liste td { padding: 12px 18px; }
    .ops-table.ops-table--liste tr.ops-jour td { padding: 8px 18px; }
    .ops-table--liste .ops-actions .btn-sm { min-height: 2.5rem; padding: 0 .9rem; font-size: .88rem; }
}

@media (max-width: 768px) {
    /* Plus une carte par opération : une ligne dans la carte commune —
       le libellé et le montant, puis le compte et la catégorie en gris.
       Touchée, elle se déplie : justificatif, note, puis les deux boutons
       à largeurs égales (la case de sélection à leur gauche). */
    .liste-carte > .ops-table-body { padding: 0; }
    .ops-table.ops-table--liste tr.ops-jour { padding: 0; }
    .ops-table.ops-table--liste tr.ops-jour td { padding: 6px 14px; background: var(--color-neutral-soft); }
    .ops-table.ops-table--liste tbody tr.ops-row,
    .ops-table.ops-table--liste tbody tr.ops-row:has(.ops-td-actions) {
        margin: 0; padding: 10px 14px; border: 0; border-left: 5px solid var(--ops-filet);
        border-bottom: 1px solid var(--color-border); border-radius: 0; box-shadow: none;
        background: transparent; cursor: pointer;
    }
    .ops-table.ops-table--liste tbody tr.ops-row:has(.ops-td-actions) {
        grid-template-columns: auto minmax(0, 1fr);
        grid-template-areas: "desc desc" "compte suite" "detail detail" "sel actions";
        column-gap: .5rem; row-gap: .1rem;
    }
    .ops-table--liste tr.ops-row:has(.ops-td-actions) .ops-ligne-haut { border-top: 0; margin-top: 0; padding-top: 0; align-items: baseline; }
    .ops-table--liste .ops-ligne-haut .ops-desc { flex: 1 1 0; min-width: 0; font-size: .95rem; }
    .ops-table--liste .ops-mobile-montant { font-weight: 700; white-space: nowrap; }
    .ops-table--liste tr.ops-row .ops-ligne-compte,
    .ops-table--liste tr.ops-row .ops-ligne-suite { font-size: .85rem; color: var(--color-muted); }
    /* Repliée : ni case, ni boutons, ni repère de détail, ni justificatif. */
    .ops-table--liste tr.ops-row:not(.tr--ouverte) > .ops-td-sel,
    .ops-table--liste tr.ops-row:not(.tr--ouverte) > td[data-label="Actions"],
    .ops-table--liste tr.ops-row:not(.tr--ouverte) .ops-meta-justif,
    .ops-table--liste tr.ops-row .ops-detail-btn:not(.ops-remise-btn) { display: none; }
    .ops-table--liste tr.ops-row.tr--ouverte .ops-detail {
        margin-top: 6px; padding-top: 6px; border-top: 1px dashed var(--color-border);
        color: var(--color-muted); font-size: .9rem;
    }
    .ops-table--liste tr.ops-row.tr--ouverte > .ops-td-sel { grid-area: sel; margin-top: 8px; }
    .ops-table--liste tr.ops-row.tr--ouverte > td[data-label="Actions"] { grid-area: actions; margin-top: 8px; }
    .ops-table--liste tr.ops-row.tr--ouverte .ops-actions {
        display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px;
    }
    .ops-table--liste tr.ops-row.tr--ouverte .ops-actions .btn { width: 100%; min-height: 44px; font-size: .88rem; }
    .ops-table--liste tr.ops-row.tr--ouverte .ops-actions .menu-plus { display: block; }
}

/* Tablette et petits ordinateurs : le tableau reste en colonnes, mais
   resserré — la carte coupe ce qui dépasse (coins arrondis), une colonne
   d'actions trop large y perdait son dernier bouton. */
@media (min-width: 769px) and (max-width: 1100px) {
    .table-liste th, .table-liste td { padding-left: 12px; padding-right: 12px; }
    .table-liste .liste-actions { white-space: normal; }
    .table-liste .liste-actions .ecole-geste { flex-wrap: wrap; }
    .table-liste .btn-sm { padding: 0 .65rem; }
    .ops-table--liste th, .ops-table--liste td { padding-left: 12px; padding-right: 12px; }
}
.liste-contact { white-space: nowrap; }
@media (min-width: 769px) and (max-width: 1100px) {
    .table-liste td.liste-nowrap { white-space: normal; }
}
@media (min-width: 769px) and (max-width: 1100px) {
    /* Dernier recours : si une ligne ne tient toujours pas, la carte
       défile de côté plutôt que de couper un bouton. */
    .card.liste-carte:not(:has(.menu-plus-list.open)) { overflow-x: auto; }
}

/* ============================================================
   GLISSER UNE LIGNE — refonte B2·3 (section 8 de REFONTE-INTERFACE.md)

   Sur téléphone, glisser une ligne de liste vers la gauche montre ses
   actions ; le « ⋯ » au bout de la ligne ouvre les mêmes dans une
   feuille en bas d'écran (assets/js/app.js, « Glisser une ligne »).
   Sur ordinateur rien de tout cela n'existe : les boutons sont déjà à
   l'écran.
   ============================================================ */
.glisser-td { display: none; }

@media (max-width: 768px) {
    /* Le doigt qui part de côté nous revient ; le défilement vertical et
       le zoom à deux doigts restent au navigateur. Une vraie ligne de
       tableau ignore touch-action : ses cellules le portent. */
    tr[data-glisser], tr[data-glisser] > td { touch-action: pan-y pinch-zoom; }

    /* Le « ⋯ » : posé au bout de la ligne, hors de sa mise en page (la
       ligne est en flex ou en grille selon la liste).
       Discret (décision de l'utilisateur, une fois le geste vu sur un vrai
       téléphone) : le glisser est le chemin courant, le « ⋯ » reste pour
       qui ne le connaît pas — plus petit, plus pâle, centré sur la ligne
       au lieu d'être accroché en haut, et 10 px de largeur rendus au nom.
       La zone de toucher garde 44 px de haut. ⚠ Centré par une marge et
       non par transform : le geste pose son propre translateX sur chaque
       cellule d'une vraie ligne de tableau (Registre), il l'écraserait. */
    .table tbody tr.glisser-avec-points { position: relative; padding-right: 36px !important; }
    .table tbody tr.glisser-avec-points > td.glisser-td {
        display: block !important; position: absolute; top: 50%; right: 2px; margin: -22px 0 0;
        padding: 0; border: 0; width: auto !important; flex: none;
    }
    .glisser-points {
        display: grid; place-items: center; width: 32px; height: 44px; padding: 0; border: 0;
        border-radius: 10px; background: none; color: var(--color-muted); opacity: .55; cursor: pointer;
    }
    .glisser-points:active { background: var(--color-neutral-soft); opacity: 1; }
    .glisser-points .icone { fill: currentColor; width: 16px; height: 16px; }
    /* Ligne dépliée : le « ⋯ » remonte à hauteur du nom, il flotterait
       sinon au milieu du détail. */
    .table tbody tr.glisser-avec-points.tr--ouverte > td.glisser-td { top: 4px; margin-top: 0; }

    /* Dépliée, la ligne ne montre plus ses boutons (décision de
       l'utilisateur) : ils sont derrière le « ⋯ » et le geste. Ils restent
       dans la page — ce sont eux que la feuille clique —, et sans script
       (pas de « ⋯ ») ils restent affichés. */
    .table tbody tr.glisser-avec-points > td[data-glisser-actions],
    /* La case de la suppression en masse restait seule sur sa rangée :
       cocher des opérations une à une se fait assis, sur ordinateur. */
    .ops-table--liste tr.glisser-avec-points > td.ops-td-sel { display: none !important; }

    /* Pendant le geste, la carte coupe ce qui sort par la gauche. */
    .glisser-hote { overflow: hidden !important; }
    @supports (overflow: clip) { .glisser-hote { overflow: clip !important; } }
    tr.glisser-anime, tr.glisser-anime > td,
    .glisser-panneau.glisser-anime > .glisser-panneau-dedans { transition: transform .2s ease-out; }
}

/* Les boutons que la ligne découvre : posés sur la page, à la place que
   la ligne libère (le script donne position et hauteur). */
.glisser-panneau { position: absolute; z-index: 5; overflow: hidden; }
.glisser-panneau-dedans { display: flex; height: 100%; }
.glisser-btn {
    flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 3px; padding: 0 2px; border: 0; border-radius: 0; cursor: pointer;
    background: var(--color-primary-fond); color: var(--color-on-fond);
    font: inherit; font-size: .8rem; font-weight: 700; line-height: 1.1;
}
.glisser-btn > span { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.glisser-btn--fiche     { background: var(--color-primary-fond-dk); }
.glisser-btn--plus      { background: var(--color-muted); }
.glisser-btn--plus .icone { fill: currentColor; }
.glisser-btn--supprimer { background: var(--color-danger); }

/* La feuille en bas d'écran : le reste des actions en toutes lettres,
   ou la confirmation d'une suppression. Au-dessus de la barre du bas. */
.feuille-voile { position: fixed; inset: 0; z-index: 9990; background: var(--pal-noir-a45); touch-action: none; }
.feuille {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 9991;
    max-width: 34rem; max-height: 85vh; margin: 0 auto; overflow-y: auto;
    padding: 18px 16px calc(18px + env(safe-area-inset-bottom));
    border-radius: var(--radius-xl) var(--radius-xl) 0 0;
    background: var(--color-surface); color: var(--color-text); box-shadow: var(--shadow-lg);
    display: flex; flex-direction: column; gap: 4px; outline: none;
    animation: feuille-monte .2s ease-out;
}
@keyframes feuille-monte { from { transform: translateY(40px); opacity: 0; } to { transform: none; opacity: 1; } }
.feuille-rappel { margin-bottom: 6px; color: var(--color-muted); font-size: .88rem; overflow-wrap: anywhere; }
.feuille-titre { margin-bottom: 4px; font-family: var(--font-title); font-size: 1.1rem; font-weight: 700; }
.feuille-quoi { font-weight: 600; white-space: pre-line; overflow-wrap: anywhere; }
.feuille-note { margin-top: 4px; color: var(--color-muted); font-size: .88rem; line-height: 1.45; white-space: pre-line; }
.feuille-action {
    display: flex; align-items: center; gap: 12px; width: 100%; min-height: 48px; padding: 0 10px;
    border: 0; border-radius: var(--radius); background: none; color: var(--color-text);
    font: inherit; font-size: 1rem; font-weight: 600; text-align: left; cursor: pointer;
}
.feuille-action .icone { flex: none; color: var(--color-muted); }
.feuille-action:hover, .feuille-action:focus-visible { background: var(--color-neutral-soft); }
.feuille-action--danger, .feuille-action--danger .icone { color: var(--color-danger); }
.feuille-fermer { margin-top: 10px; min-height: 46px; width: 100%; justify-content: center; }
.feuille-choix { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 14px; }
.feuille-choix .btn { min-height: 48px; width: 100%; justify-content: center; gap: 8px; }
.feuille-oui--danger, .feuille-oui--danger:hover { background: var(--color-danger); border-color: var(--color-danger); color: var(--color-on-accent); }
/* La fenêtre de confirmation commune (app.js, data-confirmer) : la
   question en titre, l'explication dessous, comme la feuille du « ⋯ ». */
#fenetre-confirmer .modal-header-title { white-space: normal; overflow-wrap: anywhere; }
#fenetre-confirmer .modal-actions { border-top: 0; margin-top: 0; padding-top: 0; }
#fenetre-confirmer .confirmer-texte { margin-bottom: 1rem; }
.confirmer-note { margin: 0 0 .6rem; color: var(--color-muted); font-size: .9rem; line-height: 1.45; white-space: pre-line; }

@media (prefers-reduced-motion: reduce) {
    tr.glisser-anime, tr.glisser-anime > td,
    .glisser-panneau.glisser-anime > .glisser-panneau-dedans { transition: none; }
    .feuille { animation: none; }
}

/* « Recommencer la progression de l'année » : une confirmation qui se
   remarque (on retire tout), bouton rouge grisé tant que la case n'est
   pas cochée. */
.prog-recommencer {
    padding: .75rem .85rem; margin-bottom: .75rem; border-radius: var(--radius);
    background: var(--color-danger-soft); border: 1px solid var(--color-danger-border);
    font-size: .9rem;
}
.prog-recommencer p { margin: 0 0 .5rem; }
.prog-recommencer-titre { font-weight: 700; color: var(--color-danger); }
.prog-recommencer-note { color: var(--color-muted); font-size: .85rem; }
.prog-recommencer-case { margin: .25rem 0 .6rem; }
.prog-recommencer-case input { width: auto; }
.prog-recommencer-boutons { display: flex; gap: .5rem; justify-content: flex-end; flex-wrap: wrap; }
.prog-recommencer-ok:disabled { opacity: .45; cursor: not-allowed; }
.prog-fait--reset { background: var(--color-surface); border-color: var(--color-border-strong); }
.prog-corriger-reset { color: var(--color-danger); }

/* La sourate en cours : le bouton reste TOUJOURS à droite du nom
   (demande de l'utilisateur : avec un nom long, il passait dessous —
   deux mises en page selon la sourate). C'est le nom qui passe à la
   ligne, entre ses mots (nomInsecableProgression()), pas le bouton.
   Le bloc du jour seulement : le détail d'une case a deux boutons, qui
   passent sous le nom comme avant. */
.prog-suivante .prog-suivante-ligne { flex-wrap: nowrap; }
.prog-suivante .prog-suivante-ligne .prog-suivante-nom { flex: 1 1 0; min-width: min-content; }
.prog-insecable { white-space: nowrap; }
@media (max-width: 400px) {
    .prog-suivante .prog-suivante-ligne .prog-suivante-nom { font-size: 1.05rem; }
    .prog-suivante .prog-suivante-ligne .prog-suivante-gestes .btn { padding-left: .7rem; padding-right: .7rem; }
}
/* Une sourate en cours : le nom arabe, puis le nom latin dessous. */
.prog-suivante-nom--sourate { display: flex; flex-direction: column; gap: .05rem; line-height: 1.25; }
.prog-suivante-ar { font-size: 1.35rem; text-align: left; white-space: nowrap; }
.prog-suivante-lat { font-size: 1.05rem; white-space: nowrap; }
@media (max-width: 400px) {
    .prog-suivante .prog-suivante-ligne .prog-suivante-nom--sourate { font-size: inherit; }
}
/* La légende des couleurs, dans sa bulle : un carré par ligne. */
.aide-txt .prog-legende-item { display: flex; align-items: center; gap: .5rem; margin: .15rem 0; white-space: normal; }

/* Mode « ⚠ À revoir » : les cases apprises sont des boutons. Le bandeau
   du mode reste en haut pendant qu'on touche (son « Annuler » aussi). */
button.prog-case, button.prog-sourate { font: inherit; cursor: pointer; }
button.prog-case { font-size: .8rem; font-weight: 600; }
button.prog-sourate { width: 100%; text-align: left; font-size: .88rem; }
button.prog-sourate:hover, button.prog-case:hover { filter: brightness(.95); }
.prog-revoir--on { position: sticky; top: 0; z-index: 3; box-shadow: 0 2px 6px var(--pal-noir-a10); }
.prog-revoir-retour { flex: 1 0 100%; }
.prog-revoir-retour .prog-fait { margin: 0; }
#prog-vise { scroll-margin-top: 8rem; }
.prog-revoir-lien { color: var(--color-warning-dk); border-color: var(--color-warning); }
.prog-revoir-hizb { margin-left: auto; }
/* « ⚠ À revoir » en tête de la fiche : ce qui est à réviser, « ✔ Revu ». */
.prog-arevoir {
    margin: 0 0 .75rem; padding: .5rem .7rem; border-radius: var(--radius);
    border: 1px solid var(--color-warning); background: var(--color-warning-lt); font-size: .88rem;
}
.prog-arevoir-titre { font-weight: 700; margin-bottom: .3rem; }
.prog-arevoir ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .3rem; }
.prog-arevoir li { display: flex; align-items: center; justify-content: space-between; gap: .5rem; }
.prog-arevoir li > span { min-width: 0; }
.prog-arevoir .btn { white-space: nowrap; flex-shrink: 0; }

/* ══ Onglets d'un écran (ongletsPage(), helpers.php) ══
   Une seule forme pour tout le site : Présences (Appel · Assiduité ·
   Absences), Registre · Caisses, Suivi · Relances, Actions (Comité ·
   Commissions). Soulignés de la couleur du module, comme la barre du
   haut ; chaque onglet est un lien, celui de la page affichée n'en est
   pas un. Un nombre peut suivre le libellé, et un libellé plus court
   remplacer le long sur téléphone. */
.onglets-page {
    display: flex; gap: .25rem; margin: 0 0 1rem;
    border-bottom: 1px solid var(--color-border);
}
.onglet-page {
    flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; gap: .4rem;
    padding: .55rem .9rem; font-weight: 600; font-size: .9rem;
    color: var(--color-muted); text-decoration: none; white-space: nowrap;
    border-bottom: 3px solid transparent; margin-bottom: -1px;
}
.onglet-page--on { color: var(--color-text); border-bottom-color: var(--color-primary); }
a.onglet-page:hover { color: var(--color-text); text-decoration: none; }
.onglet-compte {
    min-width: 1.4rem; padding: .05rem .45rem; border-radius: 999px;
    font-size: .75rem; font-weight: 700; text-align: center;
    background: var(--color-surface-alt); color: var(--color-muted);
}
.onglet-page--on .onglet-compte { background: var(--color-primary-fond); color: var(--color-on-fond); }
.onglet-court { display: none; }
@media (max-width: 768px) {
    /*  Les onglets se partagent la largeur ; un libellé long passe à
        la ligne DANS son onglet plutôt que de pousser le voisin dehors. */
    .onglet-page { flex: 1 1 0; min-width: 0; text-align: center; white-space: normal; padding: .55rem .35rem; font-size: .85rem; }
    .onglet-long { display: none; }
    .onglet-court { display: inline; }
}

/* ███████████████████████████████████████████████████████████████
   11. TÉLÉPHONE ET ÉCRAN TACTILE (règles globales), ANIMATIONS, IMPRESSION
   ███████████████████████████████████████████████████████████████ */

/* ============================================================
   TÉLÉPHONE — les rangées de boutons se partagent la ligne
   ============================================================
   Demande de l'utilisateur (capture « Créer la réunion · Annuler »), puis
   inventaire à 375 px sur 64 écrans et leurs fenêtres : 17 rangées de
   boutons de largeurs inégales, calées à gauche sans remplir la ligne.
   Même motif que les boutons d'en-tête (.page-actions) : à parts égales.
   Un libellé trop long passe à la ligne DANS son bouton plutôt que de
   l'élargir. ⚠ Une rangée de boutons ajoutée demain prend l'une de ces
   classes (ou s'ajoute à la liste) pour en profiter. Ordinateur inchangé. */
@media (max-width: 768px) {
    :is(.form-buttons, .form-actions, .tps-form-actions, .btn-group, .perms-save-bar, .note-actions,
        .pv-actions-bar, .ma-filters,
        .pv-recap-filters, .ops-form-btns) {
        flex-wrap: wrap; justify-content: stretch;
        align-items: stretch;   /* même hauteur si un libellé passe sur deux lignes */
    }
    :is(.form-buttons, .form-actions, .tps-form-actions, .btn-group, .perms-save-bar, .note-actions,
        .pv-actions-bar, .ma-filters,
        .pv-recap-filters, .ops-form-btns) > .btn {
        flex: 1 1 0; min-width: 5rem;
        white-space: normal; text-align: center;
    }
    /*  Barre d'une réunion : Retour et Export PDF sur une ligne, le menu « ⋯ »
        dessous en pleine largeur — à trois, « Export PDF » se coupait en deux. */
    .pv-actions-bar > .btn { flex-basis: 40%; }
    /* En-tête de page : les boutons gardent leur libellé sur une ligne et
       se partagent la largeur selon leur texte (« + Nouvelle collecte »
       se coupait en deux à côté d'« Export CSV »). Trop longs, ils
       passent l'un sous l'autre. */
    /* ⛔ Symétrie (demande de l'utilisateur, 09/10/2026) : la rangée va d'un
       bord à l'autre. Deux boutons : à parts égales, libellé sur une ligne
       (trop longs, ils passent l'un sous l'autre, pleine largeur). Un
       bouton et un « ⋯ » : le bouton prend la place, le « ⋯ » garde la
       sienne. */
    .page-header > .btn-group { width: 100%; }
    .page-header > .btn-group > .btn { flex: 1 1 0; min-width: max-content; white-space: nowrap; justify-content: center; }
    .page-header > .btn-group > .menu-plus { flex: 0 0 auto; }
    .page-header > .btn-group > .menu-plus:only-child { flex: 1 1 auto; }
    .page-header > .btn-group > .menu-plus:only-child > .btn { width: 100%; justify-content: center; }
    /*  « ⋯ » se range à côté de « 📤 Partager » quand il y a la place
        (40 %, comme les boutons) ; seul sur sa ligne, il s'étire. */
    .pv-actions-bar > .menu-plus { flex: 1 1 40%; }
    .pv-actions-bar > .menu-plus > .btn { width: 100%; }
    /*  Saisie d'une opération : « Ajouter » suffit, le titre de la carte dit
        « Nouvelle opération » ; en entier, le libellé passait sur deux lignes. */
    .ops-btn-suite { display: none; }
    /*  Quatre onglets : deux lignes de deux, plutôt que trois et un seul. */
}

/* ============================================================
   ÉCRAN TACTILE — pas de zoom en touchant un champ
   ============================================================
   Safari (iPhone, iPad) agrandit la page quand on touche un champ dont
   le texte fait moins de 16 px, et ne la réduit pas en le quittant :
   il fallait dézoomer à la main après chaque saisie (constaté par
   l'utilisateur sur le montant d'une opération). Les champs du site
   sont en .9rem (14,4 px) ou moins. Sur un écran sans souris, tout
   champ de saisie passe à 16 px. ⛔ Ne pas « régler » ça en bloquant
   le zoom (maximum-scale=1 dans le viewport) : on ne pourrait plus
   agrandir la page à deux doigts, ce dont ont besoin ceux qui voient
   mal. !important : des dizaines de contextes posent leur propre
   taille (.form-group, barres de filtres, tableaux de saisie…). */
@media (hover: none) {
    /*  :root :is(…) : assez précis pour l'emporter sur une taille posée en
        !important par un écran (l'import du relevé mettait ses menus en
        .75rem !important sous 400 px — le zoom y revenait). La zone de
        texte des éditeurs (Quill : PV, courriers, emails) zoomait aussi. */
    :root :is(input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="file"]):not([type="hidden"]),
              select, textarea, .ql-editor) {
        font-size: 16px !important;
    }
}
/*  Double-toucher : sur ce qu'on touche (boutons, liens, champs), Safari
    n'agrandit plus la page quand on tape deux fois vite — taper « + »
    sur les billets d'un inventaire faisait zoomer. Le zoom à deux doigts
    reste permis partout. */
:is(a, button, input, select, textarea, label, summary, [role="button"], .btn) {
    touch-action: manipulation;
}

/* Collecte rapprochée : la zone des chiffres reste lisible mais inerte
   (les boutons − / + des coupures sont des <span>, que « disabled »
   n'atteint pas). */
.col-fige-zone { border: 0; padding: 0; margin: 0; min-width: 0; }
.col-fige-zone:disabled { opacity: .6; pointer-events: none; }
.col-fige-note { margin-bottom: 1rem; }
.col-input-nofix:disabled { opacity: .6; }

/* ── Tirer pour actualiser (application installée, assets/js/app.js) ──
   Pastille posée par-dessus la page, sous le bandeau test / local
   (--env-h). Elle ne prend aucune place : la page ne bouge pas. */
.tirer-actualiser {
    position: fixed; left: 50%; top: var(--env-h); z-index: 10040;
    display: none; align-items: center; gap: .5rem;
    padding: .35rem .8rem .35rem .4rem; border-radius: 999px;
    background: var(--color-surface); color: var(--color-text);
    border: 1px solid var(--color-border); box-shadow: var(--shadow-md);
    font-size: .85rem; font-weight: 600; white-space: nowrap;
    transform: translate(-50%, -50px); opacity: 0; pointer-events: none;
}
.tirer-actualiser--visible { display: flex; }
.tirer-anneau { position: relative; width: 28px; height: 28px; flex-shrink: 0; }
.tirer-anneau svg { width: 100%; height: 100%; transform: rotate(-90deg); }
.tirer-anneau circle { fill: none; stroke-width: 3; }
.tirer-fond { stroke: var(--color-border); }
.tirer-jauge { stroke: var(--color-primary); stroke-linecap: round; }
.tirer-fleche { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; font-size: .85rem; transition: transform .2s; }
.tirer-actualiser--pret .tirer-fleche { transform: rotate(180deg); }
.tirer-actualiser--pret .tirer-texte { color: var(--color-primary); }

/*  Accueil de l'Administration (admin/index.php) : les lignes du journal
    et des connexions reprennent celles du registre de l'école. */
.admin-accueil-liste { max-height: 30rem; }
/*  ⚠ min-width: 0 : sans lui, une ligne en nowrap élargit la carte et la
    pousse hors de l'écran du téléphone (même piège que l'accueil école). */
.accueil-colonnes > .admin-accueil-carte { min-width: 0; }
.admin-accueil-ico { flex-shrink: 0; display: inline-flex; color: var(--color-muted); }
/*  Le texte d'une ligne du journal est ce qu'on vient lire : il passe à
    la ligne plutôt que d'être coupé par « … ». */
.admin-accueil-texte { overflow-wrap: anywhere; }
.admin-accueil-quand { flex-shrink: 0; font-size: .82rem; color: var(--color-muted); white-space: nowrap; }

/* Un compte posé entre la barre de filtres et la liste (« 7 réunions
   prises en compte », « 412 entrées ») : une information d'état, pas une
   explication — elle reste en clair. */
.liste-total { margin: .1rem 0 .6rem; }
/* Le journal complet ne défile pas dans sa carte, contrairement aux
   aperçus des accueils : c'est la page qui défile, paginée. */
.accueil-registre-liste.journal-liste { max-height: none; overflow: visible; }
/* « heure · qui (rôle) · module » passe à la ligne plutôt que d'être
   coupé : sur téléphone, le module disparaissait derrière « … ». */
.journal-liste .accueil-registre-meta { white-space: normal; }

/* Utilisateurs : un compte jamais connecté se lit en pâle — c'est une
   information, pas une alerte ; un compte désactivé grise son nom (la
   pastille « Désactivé » dit pourquoi). */
.usr-jamais { color: var(--color-muted); font-style: italic; }
.table-liste tr.inactive .nom-lien { color: var(--color-muted); }

/* ═══════════════════════════════════════════════════
   ANIMATIONS
   ═══════════════════════════════════════════════════ */
@keyframes fadeUp {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: translateY(0); }
}
.stat-card { animation: fadeUp .25s ease both; }
.stat-card:nth-child(2) { animation-delay: .04s; }
.stat-card:nth-child(3) { animation-delay: .08s; }
.stat-card:nth-child(4) { animation-delay: .12s; }

/* ═══════════════════════════════════════════════════
   PRINT
   ═══════════════════════════════════════════════════ */
@media print {
    /*  Les documents destinés au papier ont leurs propres pages, qui ne
        chargent pas cette feuille : export/rapport_ag_pdf.php,
        export/rapport_bureau_pdf.php, export/bilan_pdf.php, export/pdf.php…
        et le rapport de collecte s'imprime dans une fenêtre à part. Ce bloc
        ne sert donc qu'au reçu CERFA, imprimé depuis son écran, et à un
        Ctrl+P fait sur n'importe quelle autre page : il retire l'habillage
        de l'application. Les masquages qui étaient éparpillés dans les
        anciens blocs d'impression des rapports, et qui valaient en réalité
        pour toutes les pages, sont regroupés ici. */
    .sidebar, .mobile-topbar, .subnav, .bottom-bar,
    .app-footer, .search-overlay,
    .btn,
    .topbar, .tn-bar, nav, .page-header, footer { display: none !important; }
    .main-area { margin-left: 0 !important; }
    .main-content { padding: 0 !important; margin: 0 !important; max-width: none !important; }
    body { background: var(--pal-blanc) !important; color: var(--pal-noir) !important; }
    /* Sans ça, un aplat de couleur ne s'imprime pas : un texte blanc sur
       fond coloré sort blanc sur blanc. */
    html, body { -webkit-print-color-adjust: exact !important; print-color-adjust: exact !important; }
    .card { box-shadow: none !important; border: 1px solid var(--pal-gris-trait) !important; }
    * { color-scheme: light; }

    /*  ⚠ Une feuille A4 moins ses marges fait moins de 768px : la règle des
        petits écrans s'y applique, et son overflow-x: hidden sur .main-area
        et .main-content force l'autre axe à « auto ». La zone de contenu
        devenait une boîte qui défile, avec un ascenseur dessiné en travers
        de la feuille et tout ce qui dépassait rogné au lieu de passer à la
        page suivante. Sur du papier, rien ne défile. */
    html, body, .app-layout, .main-area, .main-content {
        overflow: visible !important;
        height: auto !important;
        max-height: none !important;
    }
    /*  Même piège pour les cartes : overflow: hidden arrondit leurs coins
        à l'écran, mais coupe net sur le papier une carte à cheval sur deux
        feuilles, au lieu de la laisser se poursuivre. */
    .card { overflow: visible !important; }

    /*  La marge appartient à la PAGE, pas au document : un rembourrage ne
        s'applique qu'au début et à la fin d'un bloc, et les feuilles du
        milieu toucheraient le bord. Page par défaut sans marge — ce qui
        prive le navigateur de la place où il imprime l'adresse du site —
        et contenu posé sur une page nommée qui porte les marges réelles.
        Même motif que export/pdf.php. */
    @page         { size: A4; margin: 0; }
    @page feuille { size: A4; margin: 15mm; }
    .main-content { page: feuille; }
}
