/* ==========================================================================
   MMAS — Refonte visuelle globale (admin desktop + mobile).
   Chargée EN DERNIER : couche de RECALIBRAGE, elle ne réécrit pas les
   feuilles existantes. Retirer le <link> dans _partials/head.html annule
   toute la refonte, sans autre effet de bord.

   Grammaire commune avec l'appli native (v1.3) :
   - le violet de marque redevient un ACCENT ; il ne recouvre plus les
     en-têtes, les bandeaux et les fonds pleins ;
   - base neutre encrée de violet (jamais de gris froid ni de noir pur) ;
   - une ombre = de l'encre diffuse, jamais un halo coloré ;
   - dégradés décoratifs supprimés (le « dégradé violet-bleu » est la
     signature visuelle qu'on veut quitter) ;
   - hiérarchie portée par la typographie et l'espace, pas par la couleur ;
   - Outfit pour les titres/chiffres, Inter conservé pour le texte dense
     (tableaux, formulaires) où il reste plus lisible en petit corps.

   Les couleurs de marque restent pilotées par la page Apparence
   (branding.js écrit --primary / --secondary) : ce fichier ne fige AUCUNE
   couleur de marque, il n'utilise que les variables.
   ========================================================================== */

:root {
    /* Encre & filets — teintés de la marque, jamais de gris froid pur */
    --ink: #1a1830;
    --ink-soft: #4a4763;
    --ink-faint: #6f6c88;          /* 4.8:1 sur blanc — sûr pour le texte secondaire */
    --hairline: rgba(26, 24, 48, 0.08);
    --hairline-strong: rgba(26, 24, 48, 0.14);
    --canvas: #f6f5fa;
    --wash: rgba(67, 56, 202, 0.07);

    /* Ombres : encre diffuse (aucune ombre colorée) */
    --shadow-1: 0 2px 8px rgba(26, 24, 48, 0.04);
    --shadow-2: 0 6px 18px rgba(26, 24, 48, 0.05);
    --shadow-3: 0 14px 34px rgba(26, 24, 48, 0.10);

    --r-sm: 10px;
    --r-md: 14px;
    --r-lg: 18px;

    --font-display: 'Outfit', 'Inter', system-ui, sans-serif;
}

/* ---------- Fond général ---------- */
body { background: var(--canvas); color: var(--ink); }

/* ---------- Typographie : Outfit sur les titres, chiffres tabulaires ------ */
h1, h2, h3, h4,
.page-title, .section-title, .card-header h2, .card-header h3,
.stat-value, .kpi-value {
    font-family: var(--font-display);
    letter-spacing: -0.3px;
    color: var(--ink);
}
.stat-value, .kpi-value, .amount, td.amount, .montant {
    font-variant-numeric: tabular-nums;
}

/* ==========================================================================
   SURFACES
   ========================================================================== */
.card,
.stat-card,
.panel,
.widget,
.content-card {
    background: var(--surface, #fff);
    border: 1px solid var(--hairline);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-2);
    transition: box-shadow 0.22s ease, transform 0.22s ease;
}
.card:hover, .stat-card:hover { box-shadow: var(--shadow-3); }

/* En-têtes de carte : plus de dégradé de marque en fond plein */
.card-header,
.panel-header,
.widget-header {
    background: #fff !important;
    color: var(--ink) !important;
    border-bottom: 1px solid var(--hairline);
}
.card-header h2, .card-header h3,
.card-header .card-title { color: var(--ink) !important; }
.card-header i { color: var(--primary-dark, #3730a3); }

/* Dégradés décoratifs neutralisés partout où ils servaient de fond plein */
.hero, .page-hero, .banner-brand, .header-gradient {
    background: #fff !important;
    color: var(--ink) !important;
    border: 1px solid var(--hairline);
    border-radius: var(--r-lg);
}

/* ==========================================================================
   STATISTIQUES (tableau de bord)
   ========================================================================== */
.stat-card {
    padding: 18px 20px;
}
.stat-card .stat-label,
.stat-card .stat-title {
    color: var(--ink-faint);
    font-size: 0.74rem;
    font-weight: 600;
    letter-spacing: 0.8px;
    text-transform: uppercase;
}
.stat-card .stat-value {
    color: var(--ink);
    font-weight: 700;
    letter-spacing: -1px;
}
/* L'icône devient une pastille lavée, pas un aplat de marque */
.stat-card .stat-icon,
.stat-card .icon-box {
    background: var(--wash) !important;
    color: var(--primary-dark, #3730a3) !important;
    border-radius: 12px;
    box-shadow: none !important;
}

/* ==========================================================================
   BOUTONS — même géométrie partout, retour tactile, aucun halo
   ========================================================================== */
.btn {
    border-radius: var(--r-md);
    font-family: var(--font-display);
    font-weight: 600;
    letter-spacing: -0.1px;
    box-shadow: none !important;
    transition: background 0.16s ease, color 0.16s ease, transform 0.12s ease,
                border-color 0.16s ease;
}
.btn:active { transform: scale(0.975); }
.btn-primary {
    background: var(--primary, #4338ca);
    border: 1px solid var(--primary, #4338ca);
    color: #fff;
}
.btn-primary:hover { background: var(--primary-dark, #3730a3); }
.btn-ghost, .btn-secondary, .btn-outline {
    background: #fff;
    border: 1px solid var(--hairline-strong);
    color: var(--ink-soft);
}
.btn-ghost:hover, .btn-secondary:hover, .btn-outline:hover {
    background: var(--wash);
    color: var(--primary-dark, #3730a3);
    border-color: transparent;
}
.btn-danger { background: #b4392c; border-color: #b4392c; }
.btn-success { background: #147a45; border-color: #147a45; }

/* ==========================================================================
   FORMULAIRES
   ========================================================================== */
.form-control, .form-select, input[type="text"], input[type="email"],
input[type="tel"], input[type="number"], input[type="date"], select, textarea {
    border: 1px solid var(--hairline-strong);
    border-radius: var(--r-md);
    background: #fff;
    color: var(--ink);
    transition: border-color 0.16s ease, box-shadow 0.16s ease;
}
.form-control:focus, .form-select:focus, input:focus, select:focus, textarea:focus {
    outline: none;
    border-color: var(--primary, #4338ca);
    box-shadow: 0 0 0 3px var(--wash);
}
label, .form-label {
    color: var(--ink-soft);
    font-weight: 600;
    font-size: 0.84rem;
}

/* ==========================================================================
   TABLEAUX — filets, pas de dégradé d'en-tête, chiffres alignés
   ========================================================================== */
.table {
    border-radius: var(--r-lg);
    border: 1px solid var(--hairline);
    overflow: hidden;
}
.table th {
    background: #fbfbfe !important;
    color: var(--ink-faint) !important;
    font-family: var(--font-display);
    font-size: 0.76rem;
    font-weight: 600;
    letter-spacing: 0.6px;
    text-transform: uppercase;
    border-bottom: 1px solid var(--hairline-strong) !important;
}
.table td {
    border-bottom: 1px solid var(--hairline);
    color: var(--ink-soft);
}
.table tbody tr:hover { background: #fafaff; }

/* ==========================================================================
   BADGES & PASTILLES — même géométrie, texte lisible (AA)
   ========================================================================== */
.badge, .chip, .pill, .status-badge, .summer-act-chip {
    border-radius: 999px;
    font-weight: 600;
    font-size: 0.74rem;
    letter-spacing: 0.1px;
    padding: 4px 11px;
    box-shadow: none;
}
.badge-success { background: #e7f6ec; color: var(--success-text, #047857); }
.badge-warning { background: #fbf0dc; color: var(--warning-text, #92400e); }
.badge-danger  { background: #fae9e6; color: var(--danger-text, #b91c1c); }
.badge-info    { background: var(--wash); color: var(--primary-dark, #3730a3); }
.badge-light   { background: #f1f0f7; color: var(--ink-soft); }

/* ==========================================================================
   NAVIGATION — barre latérale à plat (le dégradé était la signature à quitter)
   ========================================================================== */
.sidebar {
    background: var(--primary-dark, #3730a3) !important;
    border-right: none;
}
.sidebar .nav-item {
    border-radius: var(--r-md);
    transition: background 0.16s ease;
}
.sidebar .nav-item.active {
    background: rgba(255, 255, 255, 0.16) !important;
    font-weight: 600;
}
.sidebar .nav-section-title {
    color: rgba(255, 255, 255, 0.55);
    font-size: 0.68rem;
    letter-spacing: 1px;
    text-transform: uppercase;
}
.topbar, .app-header {
    background: rgba(255, 255, 255, 0.9);
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);
    border-bottom: 1px solid var(--hairline);
    box-shadow: none;
}

/* ==========================================================================
   MODALES
   ========================================================================== */
.modal-content, .swal2-popup {
    border-radius: var(--r-lg);
    border: 1px solid var(--hairline);
    box-shadow: var(--shadow-3);
}
.swal2-title { font-family: var(--font-display); color: var(--ink); }
.swal2-styled.swal2-confirm { border-radius: var(--r-md) !important; }

/* ==========================================================================
   CARTES FAMILLES (page Familles)
   ========================================================================== */
.family-card {
    border: 1px solid var(--hairline);
    border-top: 1px solid var(--hairline);   /* annule le liseré cyan de 4px */
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-2);
    overflow: hidden;
}
.family-card:hover, .family-card:focus-visible {
    box-shadow: var(--shadow-3);
    transform: translateY(-2px);
}
/* En-tête : le NOM porte la hiérarchie, plus le fond dégradé */
.family-card .family-card-header {
    background: #fff;
    color: var(--ink);
    padding: 16px 18px 12px;
    border-bottom: 1px solid var(--hairline);
}
.family-card .family-card-header .family-card-name,
.family-card .family-card-header .family-card-title {
    color: var(--ink);
    font-family: var(--font-display);
    font-size: 1.02rem;
    font-weight: 600;
}
.family-card .family-card-header .family-card-name i,
.family-card .family-card-header .family-card-title i { color: var(--ink-faint); }
.family-card .family-card-header .avatar,
.family-card .family-card-header .family-avatar {
    background: var(--wash) !important;
    color: var(--primary-dark, #3730a3) !important;
    font-weight: 700;
    box-shadow: none !important;
}
.family-card .family-card-body { padding: 16px 18px; }
.family-card .child-block {
    background: #f8f8fc;
    border: 1px solid var(--hairline);
    border-left: 3px solid var(--primary, #4338ca);
    border-radius: 12px;
    padding: 11px 13px;
}
.family-card .child-block:hover {
    background: var(--wash);
    transform: none;
    box-shadow: none;
}
/* « À valider » : liseré + bandeau, pas un encadré orange sur toute la carte */
.family-card-pending {
    border: 1px solid var(--hairline) !important;
    border-left: 4px solid var(--warning-dark, #d97706) !important;
    box-shadow: var(--shadow-2) !important;
}
.family-pending-banner {
    background: #fbf0dc;
    color: #8a5209;
    border-bottom: 1px solid rgba(180, 105, 14, 0.18);
    border-radius: 0;
    padding: 9px 14px;
    font-weight: 600;
}
/* Barre d'actions : une barre d'outils, pas sept pastilles arc-en-ciel.
   Les couleurs d'USAGE (vert WhatsApp, violet paiement, rouge suppression)
   restent reconnaissables ; les autres ne se teintent qu'au survol. */
.family-card-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 7px;
    padding: 12px 18px 16px;
    border-top: 1px solid var(--hairline);
    background: #fcfcfe;
}
.family-card-actions .action-btn {
    width: 38px; height: 38px; min-width: 38px;
    border-radius: 11px;
    border: 1px solid var(--hairline);
    background: #fff !important;
    color: var(--ink-soft) !important;
    box-shadow: none !important;
    display: inline-flex; align-items: center; justify-content: center;
    font-size: 0.92rem;
    transition: background 0.16s ease, color 0.16s ease, transform 0.12s ease;
}
.family-card-actions .action-btn:hover {
    background: var(--wash) !important;
    color: var(--primary-dark, #3730a3) !important;
}
.family-card-actions .action-btn:active { transform: scale(0.94); }
.family-card-actions .action-btn.whatsapp {
    background: #e7f6ec !important; color: #147a45 !important;
}
.family-card-actions .action-btn.whatsapp:hover {
    background: #147a45 !important; color: #fff !important;
}
.family-card-actions .action-btn.payment {
    background: var(--wash) !important; color: var(--primary-dark, #3730a3) !important;
}
.family-card-actions .action-btn.payment:hover {
    background: var(--primary, #4338ca) !important; color: #fff !important;
}
.family-card-actions .action-btn.delete,
.family-card-actions .action-btn.danger {
    background: #fff !important; color: #b4392c !important;
}
.family-card-actions .action-btn.delete:hover,
.family-card-actions .action-btn.danger:hover {
    background: #b4392c !important; color: #fff !important;
}
.family-card-actions .action-btn[style] {
    background: #fff !important; color: var(--ink-soft) !important;
}
.family-card-actions .action-btn[style]:hover {
    background: var(--wash) !important; color: var(--primary-dark, #3730a3) !important;
}
.family-card .family-card-footer { padding: 0 18px 12px; border-top: none; }

/* ==========================================================================
   MOBILE (≤ 768px) — doctrine du projet : listes, cibles 44px, pas de
   défilement horizontal, pas d'ombres lourdes.
   ========================================================================== */
@media (max-width: 768px) {
    body { background: var(--canvas); }

    .card, .stat-card, .family-card, .panel {
        border-radius: 16px;
        box-shadow: var(--shadow-1);
    }
    .card:hover, .stat-card:hover, .family-card:hover {
        box-shadow: var(--shadow-1);
        transform: none;                     /* pas d'effet de survol au doigt */
    }

    /* Cibles tactiles */
    .btn, .action-btn, .nav-item, .tabbar-item, .list-row {
        min-height: 44px;
    }
    .family-card-actions .action-btn {
        width: 42px; height: 42px; min-width: 42px;
    }

    /* Statistiques : 2 colonnes, chiffre lisible */
    .stat-card { padding: 14px 15px; }
    .stat-card .stat-value { font-size: 1.65rem; }

    /* Barre du bas : calme, encoche respectée */
    .bottom-nav {
        background: rgba(255, 255, 255, 0.96);
        -webkit-backdrop-filter: blur(12px);
        backdrop-filter: blur(12px);
        border-top: 1px solid var(--hairline);
        box-shadow: 0 -1px 14px rgba(26, 24, 48, 0.06);
        padding-bottom: env(safe-area-inset-bottom);
    }
    .bottom-nav .nav-item.active { color: var(--primary-dark, #3730a3); font-weight: 600; }

    /* Tableaux denses : défilement contenu, jamais la page */
    .table-wrapper, .table-responsive { overflow-x: auto; max-width: 100vw; }
}

/* ---------- Accessibilité : mouvement réduit ---------- */
@media (prefers-reduced-motion: reduce) {
    .card, .stat-card, .family-card, .btn, .action-btn { transition: none; }
    .btn:active, .action-btn:active, .family-card:hover { transform: none; }
}

/* ==========================================================================
   CORRECTIF LISIBILITÉ — en-tête des cartes familles.
   mobile-polish force `color: var(--white) !important` sur tout l'en-tête
   (héritage du bandeau dégradé). Une fois le fond passé en blanc, le nom de
   la famille devenait invisible. On rétablit l'encre avec la même arme, et
   on garantit le fond blanc quel que soit le viewport.
   ========================================================================== */
body.page-families .family-card-header,
body.page-families .family-card-header *,
body.page-families .family-card-title,
body.page-families .family-card-title span,
body.page-families .family-card-name,
body.page-families .family-card-name span,
.family-card .family-card-header,
.family-card .family-card-header * {
    color: var(--ink) !important;
}
body.page-families .family-card-header { background: #fff !important; }
body.page-families .family-card-header i,
.family-card .family-card-header i { color: var(--ink-faint) !important; }

/* Pastille d'initiales (pseudo-élément sur mobile) : marque lavée + encre */
body.page-families .family-card-header::before {
    background: var(--wash) !important;
    color: var(--primary-dark, #3730a3) !important;
}
/* Garantie de visibilité des filtres (statut / activité / pays / tri) :
   quelle qu'en soit la cause, un filtre ne doit jamais devenir invisible. */
.filters-grid .form-group select,
.filters-grid .form-group .form-select,
.filters-grid .form-group .form-input,
.filters-grid .form-group input {
    display: block !important;
    width: 100% !important;
    min-height: 44px;
    opacity: 1 !important;
    visibility: visible !important;
    color: var(--ink) !important;
    background-color: #fff !important;
}

/* Avatar de l'en-tête (image ou initiales) */
.family-card .family-card-header .avatar,
.family-card .family-card-header .family-avatar,
body.page-families .family-card-header .avatar {
    background: var(--wash) !important;
    color: var(--primary-dark, #3730a3) !important;
}

/* Table Animateurs fusionnée : identité + contact + paie du mois sur une
   seule ligne (le bloc « Heures & paie » ne relistait que les mêmes noms). */
.ic-hours { white-space: nowrap; font-variant-numeric: tabular-nums; }
.hours-total-row {
    background: #fbfbfe;
    font-weight: 700;
    border-top: 2px solid var(--hairline-strong);
}
.hours-total-row td { color: var(--ink); }
@media (max-width: 768px) {
    /* Sur mobile la table défile horizontalement dans son conteneur : on ne
       masque aucune colonne pour ne pas cacher la paie. */
    .table-scroll-wrapper { overflow-x: auto; max-width: 100vw; }
}

/* ==========================================================================
   MOBILE — LISIBILITÉ DES TABLES ET DES INDICATEURS
   Sur petit écran, chaque ligne de table devient une carte. Le rendu par
   défaut empilait ÉTIQUETTE au-dessus de VALEUR : une famille occupait un
   écran entier. On passe en « étiquette à gauche / valeur à droite », le
   premier champ servant de titre — deux fois plus compact, et on retrouve
   le balayage vertical d'une vraie liste.
   ========================================================================== */
@media (max-width: 768px) {

    /* ---- Indicateurs : compacts, alignés, sans vide au milieu ---- */
    .stats-grid { gap: 10px; }
    .stat-card {
        display: flex !important;
        align-items: center !important;
        justify-content: space-between !important;
        gap: 10px;
        padding: 14px !important;
        min-height: 84px;
    }
    .stat-card .stat-content { min-width: 0; }
    .stat-card .stat-value { font-size: 1.6rem !important; line-height: 1.1; }
    .stat-card .stat-label {
        font-size: 0.68rem !important;
        letter-spacing: 0.4px;
        line-height: 1.25;
        white-space: normal;
    }
    .stat-card .stat-icon {
        width: 38px !important;
        height: 38px !important;
        flex: 0 0 38px;
        font-size: 0.95rem !important;
    }

    /* ---- Bandeaux de carte : les actions passent à la ligne ---- */
    .card-header {
        flex-wrap: wrap !important;
        gap: 10px;
        align-items: flex-start !important;
    }
    .card-header-actions,
    .card-header .card-actions { width: 100%; }
    .card-header-actions .btn,
    .card-header .card-actions .btn { flex: 1 1 auto; justify-content: center; }

    /* ---- Note repliable : le mode d'emploi ne mange plus l'écran ---- */
    .info-note {
        border: 1px solid var(--hairline);
        border-radius: var(--r-md);
        padding: 10px 12px;
        margin-bottom: 12px;
        background: #fbfbfe;
    }
    .info-note > summary {
        cursor: pointer;
        font-size: 0.84rem;
        font-weight: 600;
        color: var(--primary-dark, #3730a3);
        list-style-position: inside;
    }

    /* ---- Lignes de table : étiquette à gauche, valeur à droite ---- */
    body.admin-app .card table.table tbody td {
        display: block !important;
        text-align: left;
        padding: 6px 0 !important;
        font-size: 0.88rem;
        overflow-wrap: anywhere;
    }
    /* Étiquette EN LIGNE devant la valeur : une ligne par champ au lieu de
       deux, sans jamais comprimer le texte (un affichage en flex écrasait
       les valeurs longues à une lettre par ligne). */
    body.admin-app .card table.table tbody td::before {
        display: inline !important;
        margin: 0 7px 0 0 !important;
        white-space: nowrap;
    }
    /* Premier champ = titre de la carte (nom de famille, d'animateur…) */
    body.admin-app .card table.table tbody td:first-child {
        display: block !important;
        text-align: left;
        font-size: 1rem;
        font-weight: 600;
        color: var(--ink);
        padding-bottom: 9px !important;
    }
    body.admin-app .card table.table tbody td:first-child::before { display: none !important; }
    body.admin-app .card table.table tbody td:first-child a { color: var(--primary-dark, #3730a3); }

    /* Dernier champ = actions : une rangée de boutons, pas une valeur */
    body.admin-app .card table.table tbody td:last-child {
        display: flex !important;
        flex-wrap: wrap;
        justify-content: flex-start;
        gap: 8px;
        padding-top: 10px !important;
        text-align: left;
    }
    body.admin-app .card table.table tbody td:last-child::before { display: none !important; }
    body.admin-app .card table.table tbody td:last-child .btn { min-height: 40px; }

    /* La ligne de total garde son alignement classique */
    body.admin-app .card table.table tbody tr.hours-total-row td {
        display: block !important;
    }
}

/* ==========================================================================
   SÉLECTEUR DE SAISON SUR MOBILE
   style.css le masquait sous 768px (`display:none !important`) : sur
   téléphone, impossible de changer de saison — bloquant en période de
   bascule (la saison active peut être vide tant que les familles ne sont
   pas réinscrites). On le rétablit en version compacte, avec un menu qui
   tient dans l'écran.
   ========================================================================== */
@media (max-width: 768px) {
    /* mobile-polish masque TOUT le conteneur d'actions de la barre
       (`.header-actions { display:none !important }`) — c'est lui qui cachait
       le sélecteur, pas seulement la pastille. On rouvre le conteneur et on
       n'y laisse que la saison (recherche globale et bouton d'action restent
       masqués par leurs propres règles). */
    body.admin-app .main-header .header-actions {
        display: flex !important;
        align-items: center;
        gap: 8px;
        margin-left: auto;
    }
    body.admin-app .main-header .header-actions > *:not(#seasonIndicatorWrap) {
        display: none !important;
    }
    body.admin-app .main-header #seasonIndicatorWrap {
        display: inline-flex !important;
    }

    .season-indicator {
        display: inline-flex !important;
        padding: 7px 10px;
        font-size: 0.74rem;
        min-height: 40px;          /* cible tactile confortable */
        background: var(--wash);
        border-color: transparent;
    }
    /* Sur très petit écran, l'icône calendrier suffit à identifier le contrôle :
       on garde le libellé de saison, on masque le chevron. */
    .season-indicator > i.fa-chevron-down { display: none; }

    #seasonIndicatorWrap { position: static !important; }

    /* Menu : feuille du bas (doctrine mobile du projet) — pas d'ancrage
       fragile sous un bouton, et le pouce l'atteint sans effort. */
    .season-picker-menu {
        position: fixed !important;
        top: auto !important;
        bottom: 0 !important;
        left: 0 !important;
        right: 0 !important;
        min-width: 0 !important;
        max-height: 70vh;
        overflow-y: auto;
        border-radius: var(--r-lg) var(--r-lg) 0 0;
        border: none;
        box-shadow: 0 -12px 34px rgba(26, 24, 48, 0.18);
        z-index: 2000;
        padding: 14px 12px calc(14px + env(safe-area-inset-bottom));
    }
    /* Poignée de préhension, comme les autres feuilles de l'app */
    .season-picker-menu::before {
        content: '';
        display: block;
        width: 38px;
        height: 4px;
        margin: 0 auto 12px;
        border-radius: 999px;
        background: var(--hairline-strong);
    }
    .season-picker-menu button,
    .season-picker-menu a,
    .season-picker-menu .season-option {
        display: block;
        width: 100%;
        text-align: left;
        min-height: 46px;          /* doigt */
        padding: 12px 14px;
        border-radius: var(--r-md);
        font-size: 0.92rem;
    }
}

/* ==========================================================================
   AUDIT — CORRECTIONS
   ========================================================================== */

/* Texte en dégradé : décoratif, jamais porteur de sens, et fragile (si le
   dégradé ne peint pas, le texte devient invisible). Couleur pleine partout ;
   l'emphase passe par la graisse et l'échelle. */
.sidebar-logo h1,
.page-title,
.total-amount,
.stat-value,
.kpi-value {
    background: none !important;
    -webkit-background-clip: border-box !important;
    background-clip: border-box !important;
    -webkit-text-fill-color: currentColor !important;
}
.sidebar-logo h1 { color: #fff !important; }
.page-title { color: var(--ink) !important; }
.total-amount { color: var(--primary-dark, #3730a3) !important; }

/* Le bandeau supérieur perd son dégradé horizontal (surface unie + filet). */
.main-header {
    background: rgba(255, 255, 255, 0.92) !important;
    box-shadow: none !important;
    border-bottom: 1px solid var(--hairline);
}

/* Glassmorphisme : réservé aux barres fixes (haut / bas). Ailleurs, une
   surface opaque — un flou décoratif coûte cher et vieillit mal. */
.card, .stat-card, .panel, .modal-content {
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
}

/* Largeurs fixes en style en ligne (24 dans les pages) : sur mobile elles
   provoquent un défilement horizontal. On les plafonne sans les réécrire
   page par page. */
@media (max-width: 768px) {
    [style*="width:"], [style*="width :"] { max-width: 100% !important; }
    .card, .card-body, .table-scroll-wrapper { max-width: 100%; }
}

/* ==========================================================================
   VÉRIFIÉ AU NAVIGATEUR (dev, 390px) — corrections constatées
   ========================================================================== */
@media (max-width: 768px) {

    /* Table Animateurs fusionnée : mobile-polish masquait les étiquettes de
       colonnes pour cette table (héritage d'avant la fusion, quand elle ne
       portait que Animateur/Contact/Actions). Les colonnes de paie
       affichaient donc des « — » orphelins, sans dire de quoi il s'agit. */
    body.page-instructors .card table.table tbody tr.instructor-row > td::before {
        display: inline !important;
    }
    /* Le nom reste le titre de la carte, les actions n'ont pas d'étiquette. */
    body.page-instructors .card table.table tbody tr.instructor-row > td:first-child::before,
    body.page-instructors .card table.table tbody tr.instructor-row > td:last-child::before {
        display: none !important;
    }

    /* Bandeaux de carte : le sélecteur de mois débordait de 85px (mesuré).
       Les contrôles non-boutons prennent la largeur et passent à la ligne. */
    .card-header input[type="month"],
    .card-header input[type="date"],
    .card-header .form-select,
    .card-header .form-input {
        flex: 1 1 100% !important;
        width: 100% !important;
        min-width: 0 !important;
    }
    .card-header { overflow: hidden; }
    /* Tout conteneur d'actions du bandeau passe à la ligne et prend la
       largeur, même sans classe dédiée (mesuré : 41px de débordement
       restants sur la page Animateurs, dont le bloc est en style en ligne). */
    .card-header > div {
        flex-wrap: wrap !important;
        width: 100%;
        margin-left: 0 !important;
        gap: 8px !important;
    }
    .card-header > div > .btn { flex: 1 1 auto; justify-content: center; }

    /* Tables larges : le contenu d'une cellule pleine largeur (états vides,
       « Chargement… ») ne doit pas forcer 568px dans un écran de 390px. */
    body.admin-app .card table.table { min-width: 0 !important; width: 100% !important; }
    body.admin-app .card table.table tbody td[colspan] {
        max-width: calc(100vw - 60px);
        white-space: normal !important;
        overflow-wrap: anywhere;
    }

    /* Indicateurs : contenu réellement centré (la grille égalise les hauteurs,
       le contenu restait collé en haut avec un vide sous lui). */
    body.admin-app .stat-card { align-items: center !important; }
    body.admin-app .stat-card .stat-content { flex: 1 1 auto; min-width: 0; }

    /* Le bouton flottant ne doit pas masquer le dernier élément de la liste. */
    body.admin-app .page-content { padding-bottom: 96px !important; }
}

/* ==========================================================================
   CONTRASTE — corrections mesurées à l'exécution (axe-core, WCAG AA)
   Le dépôt a déjà des jetons « -text » foncés prévus pour ça ; ils n'étaient
   pas utilisés partout. Les couleurs VIVES restent pour les fonds et les
   icônes, jamais pour du texte sur clair.
   ========================================================================== */

/* Barre latérale : le texte doit rester lisible quelle que soit la couleur de
   marque configurée (mesuré à 2,13:1 avec une marque claire). */
.sidebar .nav-item,
.sidebar .nav-item-text,
.sidebar .user-name { color: #fff !important; }
.sidebar .nav-section-title,
.sidebar .user-role { color: rgba(255, 255, 255, 0.85) !important; }
.sidebar .nav-item i { color: rgba(255, 255, 255, 0.92) !important; }

/* Sémantique en TEXTE : versions foncées (les vives échouent sur blanc) */
.text-danger, .text-danger *,
[style*="color:#ef4444"], [style*="color: #ef4444"] { color: var(--danger-text, #b91c1c) !important; }
.text-success, .text-success *,
.activity-stat-revenue,
[style*="color:#10b981"], [style*="color: #10b981"] { color: var(--success-text, #047857) !important; }
[style*="color:#0ea5e9"], [style*="color: #0ea5e9"],
.slot-time-range { color: var(--secondary-text, #0369a1) !important; }
[style*="color:var(--primary)"] .badge,
.badge[style*="color:var(--primary)"] { color: var(--primary-dark, #3730a3) !important; }

/* Gris de texte sur fonds gris clairs : --gray-500 tombe à 4,34:1 sur
   --gray-100. On passe au cran suivant sur ces surfaces. */
.cell-count,
.chip .count,
[style*="background:var(--gray-100)"],
[style*="background: var(--gray-100)"] { color: var(--gray-600, #475569) !important; }
.section-title, .section-title-plain { color: var(--ink) !important; }

/* Étiquette réservée aux lecteurs d'écran (le dépôt n'en avait pas). */
.sr-only {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* .text-muted utilisait --gray-400 (4,48:1 sur --gray-50 : 0,02 sous le
   seuil AA). On passe à l'encre pâle du système, sûre sur toutes les
   surfaces claires du produit. */
.text-muted, .text-muted * { color: var(--ink-faint, #6f6c88) !important; }

/* --- Contrastes mesurés sur mobile (production) ------------------------- */

/* Titre du planning : blanc sur fond lavande très clair (1,17:1) — invisible.
   Même famille de défaut que l'en-tête des cartes familles : un fond coloré
   passé au clair sans que le texte suive. */
.planning-title,
#calendarWeekTitle,
.planning-header h3 { color: var(--ink) !important; }

/* Boutons pleins : les fonds vifs ne portent pas de texte blanc
   (ambre 2,14:1, vert 2,53:1). Fonds foncés, texte blanc lisible. */
.btn-warning {
    /* --warning-dark (#d97706) ne donne que 3,18:1 avec du blanc : on descend
       à l'ambre du système (6,4:1). */
    background: #8a5209 !important;
    border-color: #8a5209 !important;
    color: #fff !important;
}
.btn-success {
    background: #147a45 !important;
    border-color: #147a45 !important;
    color: #fff !important;
}

/* Ambre en TEXTE sur clair → version foncée (note « Centre fermé »). */
[style*="color:#f59e0b"], [style*="color: #f59e0b"],
.text-warning { color: var(--warning-text, #92400e) !important; }

/* Gris de texte sur surfaces gris clair (capacité des salles). */
.room-capacity, .room-capacity * { color: var(--gray-600, #475569) !important; }

/* Pastilles de relance : rouge vif sur lavé rouge = 3,95:1. Version foncée. */
.reminder-badge-label,
.badge-danger .count,
.badge-danger * { color: #8f1d1d !important; }

/* Couleurs sémantiques VIVES employées comme couleur de TEXTE via un style en
   ligne : elles échouent toutes sur fond clair (ambre 2,14:1, vert 2,42:1,
   bleu 3,51:1). Le dépôt fournit des variantes « -text » foncées prévues pour
   ça — on les substitue automatiquement, partout, sans toucher au HTML.
   La parenthèse fermante empêche de matcher « var(--warning-text) ». */
[style*="color:var(--warning)"], [style*="color: var(--warning)"] {
    color: var(--warning-text, #92400e) !important;
}
[style*="color:var(--success)"], [style*="color: var(--success)"] {
    color: var(--success-text, #047857) !important;
}
[style*="color:var(--info)"], [style*="color: var(--info)"] {
    color: var(--info-text, #1d4ed8) !important;
}
[style*="color:var(--danger)"], [style*="color: var(--danger)"] {
    color: var(--danger-text, #b91c1c) !important;
}
[style*="color:var(--secondary)"], [style*="color: var(--secondary)"] {
    color: var(--secondary-text, #0369a1) !important;
}
[style*="color:var(--accent)"], [style*="color: var(--accent)"] {
    color: var(--accent-text, #6d28d9) !important;
}

/* Sélecteur de saison sur mobile : il vit dans le bandeau COLORÉ, où le
   violet foncé hérité du desktop et les badges gris (« HISTO ») ou bleus
   (« À VENIR ») deviennent illisibles. Pastille claire, texte blanc — même
   traitement que le bouton menu. */
@media (max-width: 768px) {
    .season-indicator {
        background: rgba(255, 255, 255, 0.18) !important;
        border: 1px solid rgba(255, 255, 255, 0.28) !important;
        color: #fff !important;
    }
    .season-indicator i,
    .season-indicator span,
    .season-indicator span[style] {
        color: #fff !important;
    }
    /* Le badge d'état (HISTO / À VENIR) reste lisible, en retrait. */
    .season-indicator span[style] span,
    #seasonIndicatorLabel span {
        color: rgba(255, 255, 255, 0.82) !important;
        font-weight: 700;
    }
}

/* =========================================================
   PLANNING — vue « Plan » sur mobile.

   La grille est une matrice salles × créneaux : sur 390 px elle devient une
   liste de créneaux. Chaque cours porte le nom de sa salle, l'en-tête de
   colonnes n'ayant plus de sens.

   Composition : un créneau = une carte blanche ; les cours y sont des
   LIGNES séparées d'un filet, jamais des boîtes grises dans une boîte
   blanche. Deux lignes par cours au lieu de cinq — l'intitulé et l'effectif
   sur la première, la salle, le professeur et les places sur la seconde.
   ========================================================= */
.cell-room,
.row-free-label,
.cell-seats { display: none; }

@media (max-width: 768px) {
    body.page-planning .planning-grid-header { display: none !important; }

    body.page-planning .planning-grid {
        display: block !important;
        background: transparent !important;
        box-shadow: none !important;
        overflow: visible !important;
    }

    /* Grille à deux colonnes plutôt qu'un flux libre : les pastilles de salles
       se dimensionnaient sur leur texte, d'où un bord droit en dents de scie. */
    body.page-planning .planning-row {
        display: grid !important;
        grid-template-columns: 1fr 1fr;
        align-items: start;
        gap: 0 8px;
        background: var(--white);
        border: 1px solid var(--hairline);
        border-radius: var(--r-lg, 18px);
        box-shadow: var(--shadow-1);
        padding: 4px 14px 12px !important;
        margin: 0 0 12px !important;
    }

    /* En-tête du créneau : plus de boîte dans la boîte. L'heure en Outfit
       tabulaire, seule ancre visuelle de la carte. */
    body.page-planning .planning-slot-header {
        order: 0;
        grid-column: 1 / -1;
        width: 100%;
        min-width: 0 !important;
        display: flex !important;
        flex-direction: row !important;
        align-items: center;
        justify-content: space-between;
        gap: 8px;
        background: transparent !important;
        border: none !important;
        padding: 0 !important;
        margin: 0 0 2px !important;
    }
    body.page-planning .slot-time-range {
        font-family: var(--font-display);
        font-size: 1.02rem;
        font-weight: 600;
        font-variant-numeric: tabular-nums;
        color: var(--ink) !important;
        letter-spacing: -0.02em;
    }
    body.page-planning .slot-name {
        font-size: 0.76rem;
        color: var(--ink-faint);
        margin-right: auto;
        margin-left: 8px;
    }
    body.page-planning .slot-name:empty { display: none; }
    body.page-planning .slot-delete-btn {
        position: static !important;
        opacity: 1 !important;
        width: 44px !important;
        height: 44px !important;
        margin: 0 -12px 0 0;
        color: var(--ink-faint) !important;
        font-size: 0.85rem !important;
        flex: 0 0 auto;
    }

    /* ---- Un cours : une ligne, pas une carte ---- */
    body.page-planning .planning-cell,
    body.page-planning .planning-cell.drop-zone {
        position: relative;
        display: grid !important;
        grid-template-columns: auto 1fr auto;
        align-items: center;
        column-gap: 6px;
        row-gap: 1px;
        order: 1;
        /* .planning-cell porte flex:1 pour la matrice du bureau : en liste, les
           cours se partageaient la ligne et le titre cassait en trois. */
        grid-column: 1 / -1;
        width: 100% !important;
        min-width: 0 !important;
        min-height: 0 !important;
        margin: 0 !important;
        padding: 9px 0 9px 14px !important;
        border: none !important;
        border-top: 1px solid var(--hairline) !important;
        border-radius: 0 !important;
        background: transparent !important;
    }
    body.page-planning .planning-slot-header + .planning-cell {
        border-top: none !important;
    }
    body.page-planning .planning-cell.draggable-session:active {
        background: var(--canvas) !important;
    }
    /* Le liseré de salle : un jonc arrondi plutôt qu'un bord carré, et la
       couleur de la salle — elle n'était posée que sur l'étiquette, si bien
       que tous les cours ressortaient du même violet. */
    body.page-planning .planning-cell.draggable-session::before {
        content: '';
        position: absolute;
        left: 0;
        top: 11px;
        bottom: 11px;
        width: 3px;
        border-radius: 999px;
        background: var(--room-color, var(--primary));
    }
    body.page-planning .planning-cell .drag-handle { display: none !important; }
    body.page-planning .planning-cell .over-capacity-badge,
    body.page-planning .planning-cell .cell-badge {
        position: absolute !important;
        top: 6px;
        right: 0;
        margin: 0 !important;
    }

    /* Ligne 1 — intitulé du cours et effectif. */
    body.page-planning .cell-header {
        grid-row: 1;
        grid-column: 1 / -1;
        display: flex !important;
        flex-direction: row !important;
        flex-wrap: nowrap;
        align-items: flex-start;
        justify-content: space-between;
        gap: 8px;
        background: transparent !important;
        border: none !important;
        border-radius: 0 !important;
        padding: 0 !important;
        margin: 0 !important;
        box-shadow: none !important;
    }
    body.page-planning .cell-activity {
        flex: 1 1 auto;
        min-width: 0;
        font-family: var(--font-display);
        font-size: 0.97rem;
        font-weight: 600;
        letter-spacing: -0.01em;
        color: var(--ink);
    }
    /* L'effectif en pastille pleine (rouge, ambre) posait un problème de
       contraste et alourdissait la ligne : chiffre nu, la couleur porte l'état. */
    body.page-planning .cell-count {
        font-variant-numeric: tabular-nums;
        font-weight: 700;
        font-size: 0.84rem !important;
        background: transparent !important;
        padding: 0 !important;
        color: var(--ink-soft) !important;
        flex: 0 0 auto;
    }
    body.page-planning .cell-almost-full .cell-count { color: var(--warning-dark, #8a5209) !important; }
    body.page-planning .cell-full .cell-count,
    body.page-planning .cell-over-capacity .cell-count { color: var(--danger-dark, #b4392c) !important; }

    /* Ligne 2 — salle, professeur, places. */
    body.page-planning .cell-room {
        display: block !important;
        grid-row: 2;
        grid-column: 1;
        font-size: 0.68rem;
        font-weight: 700;
        letter-spacing: 0.06em;
        text-transform: uppercase;
        /* !important : la substitution des couleurs sémantiques en texte
           (plus haut) matche « color:var(--warning) » DANS l'attribut style,
           donc aussi « --room-color:var(--warning) ». Le nom de salle sortait
           ambre pour les seules salles dont la couleur est un jeton
           sémantique. Le jonc et les pastilles portent la couleur. */
        color: var(--ink-faint) !important;
        margin: 0;
    }
    body.page-planning .cell-instructor {
        grid-row: 2;
        grid-column: 2;
        font-size: 0.79rem;
        color: var(--ink-soft);
        margin: 0;
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
    body.page-planning .cell-instructor i { display: none; }
    body.page-planning .cell-instructor::before {
        content: '·';
        margin-right: 5px;
        color: var(--hairline-strong);
    }
    /* La barre pleine largeur ne disait rien à 0 % et coûtait une ligne
       entière ; les pastilles se lisent d'un coup d'œil et tiennent au bout
       de la ligne du professeur. Le bureau garde sa barre. */
    body.page-planning .cell-progress { display: none !important; }
    body.page-planning .cell-seats {
        display: flex !important;
        grid-row: 2;
        grid-column: 3;
        align-items: center;
        gap: 3px;
    }
    body.page-planning .cell-seats .seat {
        width: 6px;
        height: 6px;
        border-radius: 999px;
        background: var(--hairline-strong);
    }
    body.page-planning .cell-seats .seat--on { background: var(--room-color, var(--primary)); }

    body.page-planning .cell-enrollments {
        grid-row: 3;
        grid-column: 1 / -1;
        margin-top: 4px !important;
    }

    /* ---- Salles encore libres ---- */
    /* Neuf grands cadres vides noyaient les cours : des pastilles compactes
       en fin de carte, posées sur un lavis plutôt que cernées de pointillés,
       qui donnaient à la carte un air de formulaire à remplir. */
    body.page-planning .row-free-label {
        display: block !important;
        order: 2;
        grid-column: 1 / -1;
        width: 100%;
        font-size: 0.68rem;
        font-weight: 700;
        letter-spacing: 0.06em;
        text-transform: uppercase;
        color: var(--ink-faint);
        margin: 12px 0 6px;
    }
    body.page-planning .planning-cell.cell-empty:not(.draggable-session) {
        display: inline-flex !important;
        /* .planning-cell est une colonne pour la matrice : sans cela le « + »
           se pose au-dessus du nom de salle au lieu de le précéder. */
        flex-direction: row !important;
        align-items: center;
        gap: 7px;
        order: 3;
        /* Les cours occupent les deux colonnes ; les pastilles, une seule. */
        grid-column: auto !important;
        justify-content: flex-start;
        width: auto !important;
        min-width: 0 !important;
        min-height: 44px !important;
        margin: 0 0 6px !important;
        white-space: nowrap;
        overflow: hidden;
        padding: 0 14px !important;
        border: none !important;
        border-top: none !important;
        border-radius: 999px !important;
        background: var(--canvas) !important;
    }
    body.page-planning .planning-cell.cell-empty:not(.draggable-session)::before { content: none; }
    body.page-planning .planning-cell.cell-empty:not(.draggable-session):active {
        background: var(--wash) !important;
    }
    body.page-planning .planning-cell.cell-empty:not(.draggable-session) .cell-empty-content {
        display: contents;
    }
    body.page-planning .planning-cell.cell-empty:not(.draggable-session) .cell-empty-content span { display: none; }
    body.page-planning .planning-cell.cell-empty:not(.draggable-session) .cell-room {
        display: inline !important;
        grid-row: auto;
        grid-column: auto;
        margin: 0 !important;
        font-size: 0.72rem;
        letter-spacing: 0.03em;
        color: var(--ink-soft) !important;
    }
    body.page-planning .planning-cell.cell-empty:not(.draggable-session) i {
        color: var(--room-color, var(--primary));
        font-size: 0.8rem;
    }
}

/* Effectif d'une cellule de planning : la pastille pleine portait « blanc sur
   ambre » (2,1:1) et, une fois la couleur de texte reprise par une couche
   amont, « ardoise sur ambre » (3,52:1). Fond lavé + texte sémantique foncé. */
.cell-almost-full .cell-count {
    background: var(--warning-wash, #fbf0dc) !important;
    color: var(--warning-text, #8a5209) !important;
}
.cell-full .cell-count,
.cell-over-capacity .cell-count {
    background: var(--danger-wash, #fae9e6) !important;
    color: var(--danger-text, #b4392c) !important;
}
.cell-over-capacity .cell-count {
    box-shadow: 0 0 0 2px rgba(180, 57, 44, 0.25) !important;
}

/* ==========================================================================
   AUDIT MOBILE PROFOND — 26/08/2026
   Corrections mesurées au navigateur sur les 33 pages de l'admin.
   ========================================================================== */

/* --- Jetons sémantiques « foncés » : ils servent de COULEUR DE TEXTE sur
   leur propre lavis clair, où ils ne passaient pas (2,6 à 2,9:1). Recalés sur
   la palette documentée dans DESIGN.md. Utilisés en fond, ils restent
   valides : plus foncé ne dégrade jamais un texte blanc. */
:root {
    --success-dark: #147a45;
    --warning-dark: #8a5209;
    --danger-dark: #b4392c;
    --info-dark: #1d4ed8;
}

/* --- Bouton primaire : dégradé décoratif et halo coloré, tous deux proscrits
   par la doctrine. mobile-polish les impose en !important. */
.btn-primary,
.btn-primary:hover:not(:disabled) {
    background-image: none !important;
    background-color: var(--primary, #4338ca) !important;
    box-shadow: none !important;
}
.btn-primary:hover:not(:disabled) { background-color: var(--primary-dark, #3730a3) !important; }

@media (max-width: 768px) {
    /* --- Pastilles de salles : 19 px de haut. Ma propre règle générale posait
       min-height:0 !important, qui battait le 42 px des pastilles. */
    body.page-planning .planning-cell.cell-empty:not(.draggable-session) {
        min-height: 44px !important;
        padding: 0 14px !important;
    }

    /* --- Bandeaux d'outils : 36 px, sous le seuil tactile. */
    body.admin-app .btn-sm,
    body.admin-app .comm-tab,
    body.admin-app .tab-btn,
    body.admin-app .summer-tab {
        min-height: 44px !important;
        display: inline-flex !important;
        align-items: center;
        justify-content: center;
    }

    /* --- Micro-typographie : les pastilles descendaient à 10,8 px. */
    body.admin-app .badge, body.admin-app .chip, body.admin-app .pill,
    body.admin-app .status-badge, body.admin-app .day-chip,
    body.admin-app .support-thread-count, body.admin-app .request-status-badge {
        font-size: 12px !important;
        line-height: 1.35;
    }

    /* --- Indications de formulaire trop pâles sur fond lavé. */
    .apz-hint { color: var(--ink-faint, #6f6c88) !important; }
}

@media (max-width: 768px) {
    /* ==========================================================================
       PLAN DES SALLES
       Les zones sont posées en pourcentage sur l'image du plan. Le faire
       défiler n'en montrait que la moitié — on croyait l'interface cassée —
       et remplacer les noms par une liste numérotée doublait la hauteur de
       la page pour répéter « Disponible » huit fois.
       Le plan tient donc ENTIER dans l'écran, et le nom qui n'entre pas en
       largeur bascule d'un quart de tour (cf. _ajusterEtiquettes).
       ========================================================================== */
    body.page-planning .fp-wrap { padding: var(--space-2) !important; }
    body.page-planning .fp-stage { min-width: 0; width: 100%; }

    /* Légende des états : quatre pastilles, une consigne, un bouton — quatre
       lignes auparavant. */
    body.page-planning .fp-legend {
        gap: var(--space-2) var(--space-3) !important;
        font-size: 12px !important;
        margin-bottom: var(--space-2) !important;
        padding-bottom: var(--space-2) !important;
    }
    body.page-planning .fp-legend .fp-dot {
        width: 11px;
        height: 11px;
        margin-right: var(--space-1);
    }
    body.page-planning .fp-legend-hint {
        margin-left: 0 !important;
        flex-basis: 100%;
        color: var(--ink-faint, #6f6c88) !important;
    }
    body.page-planning #fpEditBtn { margin-left: 0 !important; }

    /* Le nom occupe toute la pièce et s'y centre : dans 40 px de large, une
       bannière en haut ne laissait de place à rien. */
    body.page-planning .fp-room-name {
        position: absolute;
        inset: 0;
        display: flex !important;
        align-items: center;
        justify-content: center;
        margin: 0 !important;
        padding: 0 2px !important;
        font-size: 9.5px !important;
        line-height: 1.1;
        letter-spacing: 0.02em;
        white-space: nowrap !important;
        text-shadow: 0 0 3px var(--white), 0 0 3px var(--white);
        pointer-events: none;
    }
    body.page-planning .fp-room-name--pivot {
        writing-mode: vertical-rl;
        transform: rotate(180deg);
    }

    /* « Aucune session à venir » répété dans chaque pièce libre masquait le
       nom : la couleur de la zone dit déjà qu'elle est disponible. En
       revanche « Aucune salle assignée » signale une anomalie de
       configuration et reste affiché. */
    body.page-planning .fp-room:not(.fp-room--unassigned) .fp-room-body {
        display: none !important;
    }
    /* La pièce non assignée garde son liseré violet distinctif ; son libellé
       chevauchait le nom pivoté dans 44 px de large. Le nom prime. */
    body.page-planning .fp-room--unassigned .fp-room-body { display: none !important; }

    /* --- Micro-typographie. Plancher : 12 px pour le texte courant, 11,5 px
       pour les étiquettes capitales (la taille documentée dans DESIGN.md).
       Les valeurs relevées descendaient à 9,3 px.

       ATTENTION À LA SPÉCIFICITÉ : mobile-polish pose
       « body.page-dashboard .qa-label { font-size:.65rem !important } ».
       Entre deux !important, c'est la spécificité qui tranche, pas l'ordre
       de chargement — d'où le préfixe body.admin-app ici. */
    body.admin-app #seasonIndicatorLabel,
    body.admin-app small, body.admin-app .text-sm, body.admin-app .small {
        font-size: 12px !important;
    }
    body.admin-app .qa-label,
    body.admin-app .hero-rate-label,
    body.admin-app .cell-room,
    body.admin-app .row-free-label,
    body.admin-app .chip-specialty,
    body.admin-app .stat-label,
    body.admin-app [style*="font-size:0.72rem"],
    body.admin-app .it-table th {
        font-size: 11.5px !important;
    }

    /* --- Cases à cocher enveloppées d'une étiquette : c'est l'étiquette
       qu'on touche, elle doit donc porter la hauteur de cible. */
    label.day-check,
    label.switch,
    .form-check-label,
    label:not([class^="swal2"]):has(> input[type="checkbox"]),
    label:not([class^="swal2"]):has(> input[type="radio"]) {
        min-height: 44px;
        display: inline-flex;
        align-items: center;
        gap: 8px;
    }
}

@media (max-width: 768px) {
    /* --- Débordements mesurés à l'audit.
       Bandeau d'onglets Communications : il déborde lui-même (404 px) faute
       d'être borné ; les chaînes techniques des journaux (« POST /api/… »)
       n'ont aucun point de césure ; les <select> masqués de Tom Select
       gardent leur largeur d'origine. */
    body.admin-app .comm-tabs {
        max-width: 100% !important;
        overflow-x: auto;
        flex-wrap: nowrap;
        scrollbar-width: none;
    }
    body.admin-app .comm-tabs::-webkit-scrollbar { display: none; }

    body.admin-app .stat-content,
    body.admin-app .log-message,
    body.admin-app .stat-label {
        overflow-wrap: anywhere;
        min-width: 0;
    }

    body.admin-app select.tomselected,
    body.admin-app .ts-hidden-accessible {
        max-width: 100% !important;
    }
}

@media (max-width: 768px) {
    /* --- Derniers écarts de l'audit. Chacun était battu par un !important
       de spécificité supérieure : entre deux !important, c'est la spécificité
       qui tranche, jamais l'ordre de chargement. On s'aligne dessus. */

    /* body.page-planning .btn-group .btn { min-height:36px !important } */
    body.admin-app .btn-group .btn { min-height: 44px !important; }

    /* body.page-audit .stat-card .stat-label { font-size:.75rem !important } */
    body.admin-app .stat-card .stat-label,
    body.admin-app .stat-card .stat-delta { font-size: 11.5px !important; }

    /* Indications d'aide de la page Apparence (feuille en ligne, .76rem). */
    body.admin-app .apz-hint { font-size: 12px !important; }

    /* Journaux : la valeur (« POST /api/… ») débordait de sa carte de 113 px,
       un élément flex ne rétrécissant pas sous son contenu sans min-width:0. */
    body.page-logs .stat-content,
    body.page-logs .stat-value {
        min-width: 0 !important;
        overflow-wrap: anywhere !important;
    }

    /* Tom Select conserve le <select> d'origine pour la valeur : il doit être
       hors flux, sinon il déborde de 30 px sur la droite. */
    body.admin-app select.tomselected.ts-hidden-accessible {
        position: absolute !important;
        width: 1px !important;
        height: 1px !important;
        opacity: 0 !important;
        pointer-events: none;
    }
}

@media (max-width: 768px) {
    /* Étiquettes de statistique du tableau de bord (11,1 px) et boutons
       d'action de la page Audit posés à 11 px en style en ligne. */
    body.admin-app .stat-content .stat-label { font-size: 11.5px !important; }
    body.page-audit [style*="font-size:11px"] { font-size: 12px !important; }
}

/* Gris ardoise clair (#94a3b8) employé comme couleur de TEXTE dans des styles
   en ligne : 2,6:1 sur blanc. Même traitement que les couleurs sémantiques
   vives plus haut — la parenthèse fermante évite de matcher une variable. */
[style*="color:#94a3b8"], [style*="color: #94a3b8"],
[style*="color:#cbd5e1"], [style*="color: #cbd5e1"],
[style*="color:#a0aec0"], [style*="color: #a0aec0"] {
    color: var(--ink-faint, #6f6c88) !important;
}

@media (max-width: 768px) {
    /* Dernier lot de l'audit — chaque sélecteur est calé sur la spécificité
       du !important qu'il doit dépasser (relevée au navigateur). */

    /* body.admin-app .alerts-kpi-grid .stat-card .stat-label → .74rem ! */
    body.admin-app .alerts-kpi-grid .stat-card .stat-label,
    body.admin-app .stats-grid .stat-card .stat-label { font-size: 11.5px !important; }

    /* Étiquettes capitales des fiches et de l'assistant de décision. */
    body.admin-app .child-label,
    body.admin-app .wizard-detail-label,
    body.admin-app .wizard-hero-eyebrow,
    body.admin-app table th { font-size: 11.5px !important; }

    /* Croix de retrait d'une exception : 27 px de large. */
    body.admin-app .cfg-rex-del { min-width: 44px !important; }
}

@media (max-width: 768px) {
    /* Journaux : la carte fait 175 px et sa valeur refusait de rétrécir.
       flex-basis auto conserve la largeur du contenu ; il faut 0. */
    body.page-logs .stat-card { min-width: 0 !important; }
    body.page-logs .stat-content { flex: 1 1 0 !important; }
}

@media (max-width: 768px) {
    /* La carte fait 175 px : même tronqué, un chemin d'API à 1 rem n'y entre
       pas. On borne la largeur et on réduit le corps de ce seul indicateur. */
    body.page-logs .stat-content { max-width: 100% !important; overflow: hidden; }
    body.page-logs #logKpiTopAction {
        font-size: 0.8rem !important;
        overflow-wrap: anywhere;
        line-height: 1.3;
    }
}

@media (max-width: 768px) {
    body.page-planning .fp-room-empty { font-size: 10.5px !important; }
    /* Le nom occupe alors toute la zone : on le centre. */
    body.page-planning .fp-room:not(.fp-room--unassigned) .fp-room-body {
        flex: 0 0 auto;
    }
}


/* Page Analyses — barre de proportion du tableau « inscrits par activité ». */
.ana-barre {
    display: inline-block;
    width: 110px;
    max-width: 100%;
    height: 6px;
    border-radius: 999px;
    background: var(--hairline, rgba(26, 24, 48, 0.08));
    overflow: hidden;
    vertical-align: middle;
}
.ana-barre > span {
    display: block;
    height: 100%;
    border-radius: 999px;
    background: var(--primary, #4338ca);
}

@media (max-width: 768px) {
    /* Cartes familles : DEUX avatars s'affichaient. mobile-polish en dessine un
       en pseudo-élément (content: attr(data-initials)) — hérité d'une époque où
       la carte n'en avait pas — et le JS en rend désormais un vrai, qui sait
       afficher la photo de la famille. On garde le vrai. */
    body.page-families .family-card-header::before { display: none !important; }

    /* Le vrai avatar reprend la présence que l'autre occupait. */
    body.page-families .family-card-title > span:first-child,
    body.page-families .family-card-title > span:first-child img {
        width: 38px !important;
        height: 38px !important;
    }
    /* Libéré de l'avatar en double, le nom tient sur une ligne. */
    body.page-families .family-card-title { gap: 10px !important; }
}

@media (max-width: 768px) {
    /* Les lignes de contact gardent leurs 44 px de cible tactile (doctrine),
       mais l'espace AUTOUR se resserre : deux lignes de texte occupaient
       142 px, l'essentiel en vide. */
    body.page-families .family-contact-info {
        gap: 2px !important;
        padding: 2px 0 !important;
    }

}

/* Le montant dû portait une ombre colorée (halo cyan), proscrite par la
   charte : l'élévation est de l'encre diffuse, jamais une couleur. */
.child-row .badge,
.child-amount,
body.page-families .child-row [class*="amount"] {
    box-shadow: none !important;
}

/* Collision de noms de classe. theme-v2 écrit « .admin-app .fab { background:
   var(--v2-grad) } » pour le bouton d'action flottant. Or Font Awesome utilise
   « fab » pour ses icônes de MARQUE : chaque <i class="fab fa-whatsapp"> se
   retrouvait posé sur un carré violet en dégradé. Une icône n'est jamais un
   bouton flottant — on distingue les deux par la balise. */
.admin-app i.fab,
.admin-app span.fab {
    background: none !important;
    box-shadow: none !important;
    border-radius: 0 !important;
    width: auto !important;
    height: auto !important;
    padding: 0 !important;
    position: static !important;
}

@media (max-width: 768px) {
    /* Défauts invisibles jusqu'ici : la page Familles était vide, l'audit
       n'avait aucune carte à mesurer. Les cartes revenues, ils apparaissent. */

    /* « Aucun paiement enregistré » : #78839a à 11 px, soit 3,5:1. */
    body.page-families [style*="color:#78839a"],
    body.page-families [style*="color: #78839a"] {
        color: var(--ink-faint, #6f6c88) !important;
        font-size: 11.5px !important;
    }

    /* Libellés des cartes enfant, entre 10,5 et 11,25 px. */
    body.page-families .child-amount-badge,
    body.page-families .activity-badge-small,
    body.page-families .activity-freq-tag {
        font-size: 11.5px !important;
    }
}

/* « Hors période » : les mois où le centre est fermé. Ni alerte, ni succès —
   un simple constat, donc une pastille neutre. */
.status-badge.closed,
.family-card .status-badge.closed {
    background: var(--papier-2, #f1f5f9) !important;
    color: var(--ink-faint, #6f6c88) !important;
    border: 1px solid var(--hairline, rgba(26, 24, 48, 0.08)) !important;
}

/* Ligne « frais d'inscription » de la fenêtre de paiement : une case, un
   libellé, un montant — même géométrie que les lignes d'activité. */
.fee-line {
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: 44px;
    padding: 8px 12px;
    border: 1px solid var(--hairline-strong, rgba(26, 24, 48, 0.14));
    border-radius: var(--r-md, 14px);
    cursor: pointer;
}
.fee-line > span { flex: 1; min-width: 0; }
.fee-line b { font-variant-numeric: tabular-nums; white-space: nowrap; }
.fee-line input { width: 18px; height: 18px; flex: 0 0 auto; }

/* Actions de correction sur une matière demandée (changer / retirer). */
.wizard-activity-actions {
    display: flex;
    gap: 4px;
    margin-left: auto;
    flex: 0 0 auto;
}
.wizard-activity-actions .btn { padding: 4px 9px; font-size: 0.78rem; }
@media (max-width: 768px) {
    .wizard-activity-card { flex-wrap: wrap; }
    .wizard-activity-actions { margin-left: 0; width: 100%; }
    .wizard-activity-actions .btn { min-height: 40px; }
}

/* Quatrième occurrence du même piège : « .family-pending-banner small »
   porte opacity .85, qui délave #8a5209 en #9b6a29 et fait tomber le
   contraste de 5,4:1 à 4,14:1. La hiérarchie se marque par la taille et la
   graisse, pas en effaçant le texte. */
.family-pending-banner small {
    opacity: 1 !important;
    font-weight: 500;
}

/* Le menu « actions administratives » est en position absolue dans
   .card-header, lequel porte overflow:hidden (mobile-polish) : il était
   tranché à mi-hauteur. Un en-tête qui contient un menu ne peut pas rogner. */
body.page-families .card-header { overflow: visible !important; }
body.page-families #familyAdminMenu { z-index: 40; }

@media (max-width: 768px) {
    /* ==========================================================================
       CARTE FAMILLE — densité.
       Une carte occupait 500 px pour une famille et un enfant : sept familles
       demandaient 3 500 px de défilement. On resserre sans rien retirer.
       ========================================================================== */

    /* Les sept actions tenaient sur trois rangées de 44 px. Sur toute la
       largeur de la carte, à 42 px — le plancher admis pour les barres denses
       (DESIGN.md) — elles tiennent sur UNE ligne : 7 × 42 + 6 × 6 = 330 px
       dans les 336 disponibles. */
    body.page-families .family-card-actions {
        display: flex !important;
        flex-wrap: nowrap !important;
        justify-content: space-between !important;
        gap: 4px !important;
        padding: 8px 10px 10px !important;
    }
    body.page-families .family-card .family-card-actions .action-btn,
    body.page-families .family-card .family-card-actions > * {
        /* box-sizing hérité en content-box : sans cette ligne, 42 px de
           contenu plus deux bordures faisaient 44, et le septième bouton
           sortait de la carte. */
        box-sizing: border-box !important;
        width: 41px !important;
        height: 41px !important;
        min-width: 41px !important;
        min-height: 41px !important;
        flex: 0 0 auto !important;
        margin: 0 !important;
    }

    /* Le pied ne porte qu'une ou deux pastilles : il n'a pas besoin d'un bloc. */
    body.page-families .family-card-footer {
        padding: 6px 14px 0 !important;
        border: none !important;
    }

    /* En-tête : le nom tient sur une ligne, la qualité passe en suffixe. */
    body.page-families .family-card-header { padding: 10px 14px 8px !important; }
    body.page-families .family-card-title { font-size: 0.95rem !important; }

    /* Contact : deux lignes tactiles, sans le vide autour. */
    body.page-families .family-contact-info { gap: 0 !important; padding: 0 !important; }
    body.page-families .contact-row { padding: 2px 0 !important; }
    body.page-families .family-card-body { padding: 8px 14px 6px !important; }
}

/* Bandeau « demande à traiter » sur la carte famille — même géométrie que le
   bandeau « À valider », mais bleu : c'est une action à mener, pas une
   anomalie à corriger. */
.family-request-banner {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 14px;
    background: var(--wash, rgba(67, 56, 202, 0.07));
    color: var(--primary-dark, #3730a3);
    font-size: 12.5px;
    font-weight: 600;
    border-bottom: 1px solid var(--hairline, rgba(26, 24, 48, 0.08));
}
.family-request-banner > i { flex: 0 0 auto; }
/* Le libellé absorbe la place restante et se coupe proprement ; sans
   min-width:0 il pousse le bouton et s'enroule mot par mot. */
.family-request-banner .frb-label {
    flex: 1 1 auto;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* Qualifié par body.page-families : les règles mobiles de la page étirent
   sinon tout .btn sur toute la largeur, ce qui casse la ligne en deux. */
body.page-families .family-pending-banner .frb-action,
body.page-families .family-request-banner .frb-action,
.family-pending-banner .frb-action,
.family-request-banner .frb-action {
    flex: 0 0 auto !important;
    width: auto !important;
    max-width: none !important;
    min-width: 0 !important;
    height: 32px !important;
    min-height: 32px !important;
    padding: 0 14px !important;
    margin: 0 !important;
    font-size: 12.5px !important;
    line-height: 1 !important;
    white-space: nowrap !important;
    display: inline-flex !important;
    align-items: center !important;
}
body.page-families .family-request-banner,
body.page-families .family-pending-banner {
    flex-wrap: nowrap !important;
}
/* Le bandeau « À valider » partage désormais la même mécanique de ligne. */
.family-pending-banner { display: flex; align-items: center; gap: 8px; }
.family-pending-banner > i { flex: 0 0 auto; }
.family-pending-banner .frb-label {
    flex: 1 1 auto;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ------------------------------------------------------------------
   Fiche famille — historique des paiements en cartes compactes
   Même défaut que la page Paiements : le patron générique empile un
   bloc libellé par colonne. Cinq blocs pour une ligne de caisse.
   Colonnes : 1 Date+enfant · 2 Montant · 3 Mode · 4 Mois · 5 Reçu
   ------------------------------------------------------------------ */
@media (max-width: 768px) {
    body.page-family.admin-app .card table.table tbody tr {
        display: grid !important;
        grid-template-columns: minmax(0, 1fr) auto;
        grid-template-areas:
            "entete montant"
            "mode   recu";
        align-items: center;
        gap: 4px 10px;
        padding: 10px 12px !important;
    }
    body.page-family.admin-app .card table.table tbody td {
        padding: 0 !important;
        border-bottom: none !important;
        min-width: 0;
    }
    body.page-family.admin-app .card table.table tbody td::before {
        display: none !important;
    }
    body.page-family.admin-app .card table.table tbody td:nth-child(1) {
        grid-area: entete;
        font-weight: 600;
        font-size: 0.9rem;
    }
    body.page-family.admin-app .card table.table tbody td:nth-child(2) {
        grid-area: montant;
        text-align: right !important;
        font-size: 1.02rem;
        white-space: nowrap;
    }
    body.page-family.admin-app .card table.table tbody td:nth-child(3) {
        grid-area: mode;
        display: flex !important;
        flex-wrap: wrap;
        gap: 4px;
    }
    /* Le mois est déjà lisible dans la date. */
    body.page-family.admin-app .card table.table tbody td:nth-child(4) {
        display: none !important;
    }
    body.page-family.admin-app .card table.table tbody td:nth-child(5) {
        grid-area: recu;
        text-align: right !important;
    }
}

/* ------------------------------------------------------------------
   Paiements — carte mobile compacte
   Le patron générique (main.js pose un data-label par cellule) empile
   7 blocs libellés : une carte d'écran entier pour cinq informations.
   Ici on garde le tableau, mais chaque ligne devient une grille de
   trois rangées, sans libellés — l'info se lit d'elle-même.
   Colonnes : 1 Date · 2 Famille · 3 Enfant · 4 Nature · 5 Montant
              6 Mois · 7 Actions
   ------------------------------------------------------------------ */
@media (max-width: 768px) {
    body.page-payments.admin-app .card table.table tbody tr {
        display: grid !important;
        grid-template-columns: minmax(0, 1fr) auto;
        /* Quatre rangées serrées. Les pastilles gardent la PLEINE largeur :
           partagées avec la colonne d'actions, la plus longue (« Mathématique
           primaire ») se faisait rogner. La date descend avec les boutons —
           c'est la ligne de service, on la lit en dernier. */
        grid-template-areas:
            "qui     montant"
            "quoi    quoi"
            "pied    pied"
            "entete  actions";
        align-items: center;
        gap: 2px 10px;
        padding: 12px 14px !important;
    }
    body.page-payments.admin-app .card table.table tbody td {
        padding: 2px 0 !important;
        border-bottom: none !important;
        min-width: 0;
    }
    /* Les libellés posés automatiquement n'ont plus lieu d'être. */
    body.page-payments.admin-app .card table.table tbody td::before {
        display: none !important;
    }
    body.page-payments.admin-app .card table.table tbody td:nth-child(1) {
        grid-area: entete;
        font-size: 0.82rem;
        color: var(--gray-500);
    }
    body.page-payments.admin-app .card table.table tbody td:nth-child(2) {
        grid-area: qui;
        font-size: 0.95rem;
    }
    /* Enfant : collé sous la famille, en secondaire. */
    body.page-payments.admin-app .card table.table tbody td:nth-child(3) {
        grid-area: quoi;
        font-size: 0.85rem;
        color: var(--gray-600);
    }
    body.page-payments.admin-app .card table.table tbody td:nth-child(4) {
        grid-area: pied;
        display: flex !important;
        flex-wrap: wrap;
        gap: 4px;
        align-items: center;
    }
    /* Le conteneur des pastilles est un bloc : sans display:contents il
       occupe toute la largeur et renvoie chaque pastille à la ligne. */
    body.page-payments.admin-app .card table.table tbody td:nth-child(4) > div {
        display: contents;
    }
    body.page-payments.admin-app .card table.table tbody td:nth-child(4) .badge {
        margin: 0 !important;
    }
    body.page-payments.admin-app .card table.table tbody td:nth-child(5) {
        grid-area: montant;
        text-align: right !important;
        font-size: 1.05rem;
        font-weight: 700;
        white-space: nowrap;
    }
    /* Le mois est déjà porté par la date : redondant sur une carte étroite. */
    body.page-payments.admin-app .card table.table tbody td:nth-child(6) {
        display: none !important;
    }
    body.page-payments.admin-app .card table.table tbody td:nth-child(7) {
        grid-area: actions;
        text-align: right !important;
    }
    body.page-payments.admin-app .card table.table tbody td .dep-actions {
        display: flex;
        justify-content: flex-end;
        gap: 6px;
    }
    body.page-payments.admin-app .card table.table tbody td .dep-actions .btn {
        min-width: 40px;
        min-height: 40px;
    }
}

/* ------------------------------------------------------------------
   Carte famille — densité mobile
   486 px pour une famille d'un enfant : le rapport information/place
   était mauvais, signalé trois fois. On resserre SANS rien retirer :
   contacts moins hauts, pastilles d'activité sur une ligne, pied de
   carte unique (statut + dernier paiement côte à côte).
   ------------------------------------------------------------------ */
@media (max-width: 768px) {
    body.page-families .family-card-header {
        padding: 7px 12px 5px !important;
    }
    /* « SALAMA HANANE (Mère) » passait à la ligne, doublant la hauteur de
       l'en-tête pour un nom court. Une seule ligne, coupée si besoin. */
    body.page-families .family-card-title {
        flex-wrap: nowrap !important;
        min-width: 0;
    }
    body.page-families .family-card-title > span {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        min-width: 0;
    }
    /* Le bandeau de demande n'a pas besoin d'une rangée pleine. */
    body.page-families .family-request-banner,
    body.page-families .family-pending-banner {
        padding: 5px 12px !important;
    }
    body.page-families .family-request-banner .frb-action,
    body.page-families .family-pending-banner .frb-action {
        height: 28px !important;
        min-height: 28px !important;
        padding: 0 11px !important;
    }
    body.page-families .family-card-body {
        padding: 6px 12px 4px !important;
    }
    /* Contacts : le lien garde une cible tactile confortable, mais la
       rangée n'ajoute plus ses propres marges par-dessus. */
    body.page-families .family-card-body .contact-row {
        padding: 0 !important;
        margin: 0 0 2px !important;
        min-height: 0 !important;
        font-size: 13.5px;
    }
    body.page-families .family-card-body .contact-row a {
        padding: 5px 0 !important;
        min-height: 34px !important;
        display: flex !important;
        align-items: center;
    }
    body.page-families .children-list {
        margin-top: 6px !important;
        padding-top: 6px !important;
    }
    body.page-families .child-row {
        padding: 7px 10px !important;
    }
    body.page-families .child-row-header {
        margin-bottom: 4px !important;
    }
    /* Deux matières tenaient sur deux lignes faute de place : pastilles
       resserrées, elles rentrent sur une seule. */
    body.page-families .child-activities-row {
        display: flex !important;
        flex-wrap: wrap;
        gap: 4px !important;
    }
    body.page-families .child-activities-row > * {
        font-size: 11.5px !important;
        padding: 3px 8px !important;
        margin: 0 !important;
    }
    /* Pied : statut à gauche, dernier paiement à droite, une seule rangée. */
    body.page-families .family-card-footer {
        display: flex !important;
        flex-wrap: nowrap !important;
        align-items: center;
        gap: 8px;
        padding: 6px 12px !important;
        min-height: 0 !important;
    }
    body.page-families .family-card-footer .last-pay {
        margin-left: auto;
        font-size: 11.5px;
        white-space: nowrap;
        flex: 0 0 auto;
    }
    body.page-families .family-card-actions {
        padding: 6px 10px 8px !important;
    }
    body.page-families .family-card .family-card-actions .action-btn,
    body.page-families .family-card .family-card-actions > * {
        width: 38px !important;
        height: 38px !important;
    }
}

/* ==================================================================
   CARTE FAMILLE — refonte visuelle
   ------------------------------------------------------------------
   Trois reproches, tous fondés : trop de hauteur pour peu de contenu,
   une barre de défilement qui apparaît au survol, et un rendu daté.
   Parti pris : une fiche calme et dense. Hiérarchie par la typo et
   l'espace, un seul accent (l'indigo de la charte) réservé au montant,
   et des actions qui cessent de crier — six cercles contourés de même
   poids ne hiérarchisaient rien.
   ================================================================== */

/* La liste d'enfants ne défile JAMAIS horizontalement : le contenu
   passe à la ligne. C'est cet overflow:auto qui faisait surgir une
   barre grise au survol dès qu'une matière dépassait d'un pixel. */
body.page-families .family-card .children-list {
    overflow-x: visible !important;
    overflow-y: visible !important;
}

body.page-families .family-card {
    background: #fff;
    border: 1px solid var(--gray-100);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    overflow: hidden;
    /* transform + box-shadow uniquement : aucune propriété de layout. */
    transition: box-shadow .18s cubic-bezier(.16, 1, .3, 1),
                transform .18s cubic-bezier(.16, 1, .3, 1),
                border-color .18s ease-out;
}
body.page-families .family-card:hover {
    box-shadow: var(--shadow-md);
    transform: translateY(-2px);
    border-color: var(--gray-200);
}
body.page-families .family-card:active { transform: translateY(0); }
/* Le liseré ambré de 4 px n'existait que sur les cartes « à valider » —
   celles qui portent déjà le bandeau du même nom. Deux fois le même
   signal, et un bord épais qui décalait la carte par rapport aux
   autres : on garde le bandeau, qui lui est explicite. */
body.page-families .family-card.family-card-pending {
    border-left: 1px solid var(--gray-100) !important;
}
@media (prefers-reduced-motion: reduce) {
    body.page-families .family-card,
    body.page-families .family-card:hover { transition: none; transform: none; }
}

/* ---- Identité ---- */
body.page-families .family-card .family-card-header {
    padding: 12px 14px 8px !important;
    border-bottom: none !important;
}
body.page-families .family-card .family-card-title {
    gap: 10px !important;
    flex-wrap: nowrap !important;
    min-width: 0;
}
body.page-families .family-card .family-card-title > span:last-child {
    min-width: 0;
    overflow: hidden;
    font-size: 14.5px;
    font-weight: 700;
    letter-spacing: -0.01em;
    line-height: 1.25;
    color: var(--gray-900);
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* Le rôle (« Mère ») est une précision, pas un titre : il tient sur la
   même ligne en petit, au lieu d'occuper une deuxième rangée. */
body.page-families .family-card .family-card-title > span:last-child span {
    display: inline !important;
    margin-left: 6px;
    font-size: 11.5px;
    font-weight: 500;
    color: var(--gray-500);
    text-transform: none;
}

/* ---- Contacts : une seule rangée, discrète ---- */
body.page-families .family-card .family-card-body {
    padding: 0 14px 10px !important;
}
body.page-families .family-card .family-contact-info {
    display: flex !important;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 16px;
    padding: 0 0 8px !important;
    margin: 0 !important;
    border-bottom: 1px solid var(--gray-100);
}
body.page-families .family-card .contact-row {
    display: inline-flex !important;
    align-items: center;
    gap: 6px !important;
    padding: 0 !important;
    margin: 0 !important;
    min-width: 0;
    max-width: 100%;
    font-size: 12.5px !important;
}
body.page-families .family-card .contact-row > i.fas {
    width: auto !important;
    height: auto !important;
    font-size: 11px !important;
    line-height: 1 !important;
    color: var(--gray-400);
}
body.page-families .family-card .contact-row a {
    min-height: 30px !important;
    padding: 4px 0 !important;
    display: inline-flex !important;
    align-items: center;
    color: var(--gray-700) !important;
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
body.page-families .family-card .contact-row a:hover { color: var(--primary) !important; }
/* L'indicatif pays : une information de service, pas un drapeau. En
   rouge plein (c'était le cas sur desktop) il devenait l'élément le plus
   voyant de la carte, devant le montant et l'état. */
body.page-families .family-card .country-badge {
    font-size: 9.5px !important;
    font-weight: 700 !important;
    padding: 1px 5px !important;
    letter-spacing: .04em;
    background: var(--gray-100) !important;
    color: var(--gray-600) !important;
    border: none !important;
    border-radius: var(--radius-sm) !important;
}

/* ---- Enfants : plus de cadre ni de liseré, une simple rangée ---- */
body.page-families .family-card .children-list {
    display: block !important;
    margin: 0 !important;
    padding: 6px 0 0 !important;
    border-top: none !important;
}
body.page-families .family-card .child-row {
    background: transparent !important;
    border: none !important;
    border-left: none !important;
    box-shadow: none !important;
    border-radius: 0 !important;
    padding: 6px 0 !important;
    margin: 0 !important;
}
body.page-families .family-card .child-row + .child-row {
    border-top: 1px solid var(--gray-100) !important;
}
body.page-families .family-card .child-row-header {
    display: flex !important;
    align-items: center;
    gap: 8px;
    margin-bottom: 5px !important;
}
body.page-families .family-card .child-name-label {
    min-width: 0;
    overflow: hidden;
    font-size: 13px !important;
    font-weight: 600 !important;
    letter-spacing: 0;
    color: var(--gray-800) !important;
    text-overflow: ellipsis;
    white-space: nowrap;
    text-transform: none !important;
}
/* Le montant est le seul endroit où la couleur de marque intervient. */
body.page-families .family-card .child-amount-badge {
    flex: 0 0 auto;
    margin-left: auto;
    padding: 2px 9px !important;
    border-radius: var(--radius-full);
    background: rgba(67, 56, 202, .08) !important;
    color: var(--primary-dark) !important;
    font-size: 12px !important;
    font-weight: 700 !important;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
body.page-families .family-card .child-activities-row {
    display: flex !important;
    flex-wrap: wrap !important;
    gap: 4px !important;
    overflow: visible !important;
}
body.page-families .family-card .activity-badge-small {
    padding: 2px 8px !important;
    border: none !important;
    border-radius: var(--radius-full) !important;
    background: var(--gray-100) !important;
    color: var(--gray-600) !important;
    font-size: 11px !important;
    font-weight: 500 !important;
    white-space: nowrap;
}
body.page-families .family-card .activity-badge-small.suspended {
    background: rgba(245, 158, 11, .12) !important;
    color: #8a5209 !important;
    text-decoration: line-through;
}
body.page-families .family-card .activity-freq-tag {
    margin-left: 4px;
    font-weight: 700;
    color: var(--gray-500) !important;
}

/* ---- Pied : état à gauche, dernier règlement à droite ---- */
body.page-families .family-card .family-card-footer {
    display: flex !important;
    flex-wrap: nowrap !important;
    align-items: center;
    gap: 8px;
    padding: 8px 14px !important;
    border-top: 1px solid var(--gray-100) !important;
    min-height: 0 !important;
}
body.page-families .family-card .family-card-footer .status-badge {
    order: -1;                       /* l'état d'abord : c'est ce qu'on cherche */
    font-size: 11.5px !important;
    padding: 3px 10px !important;
}
body.page-families .family-card .family-card-footer .last-pay {
    margin-left: auto;
    flex: 0 0 auto;
    font-size: 11px;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* ---- Actions : plates, hiérarchisées par la couleur au survol ---- */
body.page-families .family-card .family-card-actions {
    display: flex !important;
    justify-content: space-between !important;
    gap: 4px !important;
    padding: 6px 10px 8px !important;
    background: transparent !important;
    border-top: none !important;
}
body.page-families .family-card .family-card-actions .action-btn {
    width: 40px !important;
    height: 40px !important;
    display: inline-flex !important;
    align-items: center !important;
    justify-content: center !important;
    border: none !important;
    border-radius: var(--radius-sm) !important;
    background: transparent !important;
    box-shadow: none !important;
    color: var(--gray-500) !important;
    font-size: 14px !important;
    transition: background-color .14s ease-out, color .14s ease-out;
}
body.page-families .family-card .family-card-actions .action-btn:hover {
    background: var(--gray-100) !important;
    color: var(--gray-800) !important;
}
body.page-families .family-card .family-card-actions .action-btn.whatsapp:hover {
    background: rgba(16, 185, 129, .12) !important; color: #0f7a53 !important;
}
body.page-families .family-card .family-card-actions .action-btn.payment:hover,
body.page-families .family-card .family-card-actions .action-btn.edit:hover {
    background: rgba(67, 56, 202, .10) !important; color: var(--primary-dark) !important;
}
body.page-families .family-card .family-card-actions .action-btn.delete:hover {
    background: rgba(239, 68, 68, .12) !important; color: #b4392c !important;
}
body.page-families .family-card .family-card-actions .action-btn:focus-visible {
    outline: 2px solid var(--primary);
    outline-offset: 2px;
}

@media (max-width: 768px) {
    /* Cibles tactiles : on ne descend pas les boutons sous 40 px. */
    body.page-families .family-card .family-card-actions .action-btn {
        width: 40px !important;
        height: 40px !important;
    }
    body.page-families .family-card .family-contact-info {
        gap: 2px 14px;
    }
}

/* ==================================================================
   FICHE FAMILLE 360° — mise en page et finition
   ------------------------------------------------------------------
   L'ancienne grille auto-fit alignait des cartes de hauteurs très
   inégales et laissait de grands vides à droite, tout en coinçant le
   tableau des paiements dans une colonne de 340 px — d'où son
   ascenseur horizontal. Deux colonnes assumées : à gauche ce qu'on
   consulte et où l'on agit, à droite les indicateurs courts.
   ================================================================== */
body.page-family .family360-grid {
    display: grid;
    gap: 16px;
    align-items: start;
    grid-template-columns: minmax(0, 1fr);
}
@media (min-width: 1100px) {
    body.page-family .family360-grid {
        grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr);
    }
}
body.page-family .f360-main,
body.page-family .f360-side {
    display: grid;
    gap: 16px;
    align-content: start;
    min-width: 0;
}

/* En-têtes de cartes homogènes : même hauteur, même filet, même poids. */
body.page-family .card {
    border: 1px solid var(--gray-100);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    overflow: hidden;
}
body.page-family .card > .card-header {
    padding: 12px 16px !important;
    border-bottom: 1px solid var(--gray-100) !important;
    background: transparent !important;
}
body.page-family .card > .card-header .card-title {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0;
    font-size: 14px;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--gray-900);
}
body.page-family .card > .card-body { padding: 14px 16px !important; }

/* Le tableau respire dans la colonne large ; il ne défile que si le
   contenu l'exige vraiment, et jamais la page avec lui. */
body.page-family .card .table { width: 100%; }
body.page-family .card > .card-body > div[style*="overflow-x"] {
    overflow-x: auto;
    scrollbar-width: thin;
}

/* Le drapeau d'intl-tel-input vient d'un sprite sur cdn.jsdelivr, que la
   CSP bloque : il ne rendait qu'un rectangle vide, pris pour une case à
   cocher cassée. L'indicatif (+212) porte déjà l'information. */
.iti__flag { display: none !important; }
.iti__country-container .iti__selected-country-primary { gap: 4px; }

/* ------------------------------------------------------------------
   Fiche famille — bandeau d'identité
   Ma réduction de padding avait trop mordu ici : le nom touchait la
   ligne de contacts, et les trois informations se lisaient comme un
   seul bloc. C'est le premier élément de la page, il a droit à de
   l'air ; la densité se joue dans les cartes en dessous.
   ------------------------------------------------------------------ */
body.page-family .card.f360-identite > .card-body {
    padding: 20px !important;
    gap: 18px !important;
}
body.page-family .f360-identite-texte {
    display: flex;
    flex-direction: column;
    gap: 8px;               /* respiration nom / contacts */
    min-width: 0;
}
body.page-family .f360-identite-texte h2 {
    margin: 0;
    font-size: 1.35rem;
    font-weight: 700;
    line-height: 1.25;      /* sans quoi les jambages frôlaient la ligne suivante */
    letter-spacing: -0.015em;
    color: var(--gray-900);
}
body.page-family .f360-contacts {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 22px;          /* large entre les informations, serré entre icône et texte */
    font-size: .9rem;
    line-height: 1.5;
}
body.page-family .f360-contacts > span {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    min-width: 0;
}
body.page-family .f360-contacts i {
    font-size: .82em;
    color: var(--gray-400);
}

@media (max-width: 768px) {
    /* Sur téléphone les trois informations s'empilent : on rapproche
       verticalement pour ne pas pousser le reste hors de l'écran. */
    body.page-family .card.f360-identite > .card-body { padding: 16px !important; }
    body.page-family .f360-contacts { gap: 6px 16px; }
}

/* ==================================================================
   DENSITÉ — règle d'or : jamais beaucoup de place pour peu d'infos
   ------------------------------------------------------------------
   Mesuré, pas estimé : tools/ui-check/densite.mjs calcule l'encre
   réelle (boîtes de lignes de texte via Range + contrôles visibles)
   rapportée à la hauteur de chaque conteneur. Sur 191 conteneurs à
   390 px, 52 000 px de vide, concentrés sur DEUX patrons partagés —
   d'où une correction unique plutôt que trente rustines.
   ================================================================== */

@media (max-width: 768px) {

/* ---- 1. Tableaux en cartes : l'étiquette passe À CÔTÉ de la valeur.
   Le patron générique empilait l'étiquette au-dessus, soit deux lignes
   et ~35 px par information. Une ligne de journal à six colonnes
   coûtait 210 px pour six mots. En colonne, la même information tient
   en ~24 px : le journal passe de 21 500 à moins de 15 000 px, et
   toutes les pages en tableau en profitent d'un coup. ---- */
body.admin-app .card table.table tbody tr {
    padding: 10px 12px !important;
    margin-bottom: 8px !important;
}
body.admin-app .card table.table tbody td {
    display: grid !important;
    grid-template-columns: 82px minmax(0, 1fr);
    align-items: start;
    column-gap: 10px;
    padding: 3px 0 !important;
    border-bottom: none !important;
    min-height: 0 !important;
    font-size: 0.87rem;
    line-height: 1.45;
}
body.admin-app .card table.table tbody td::before {
    margin: 0 !important;
    font-size: 0.64rem !important;
    line-height: 1.75 !important;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* Cellule sans étiquette (barre d'actions) : elle reprend toute la
   largeur, sinon la colonne d'étiquette vide décalerait les boutons. */
body.admin-app .card table.table tbody td:not([data-label]),
body.admin-app .card table.table tbody td[data-label=""] {
    display: block !important;
    padding-top: 6px !important;
}
/* Un filet ne sépare plus chaque champ — la colonne d'étiquettes
   structure déjà la lecture, et la carte isole déjà la ligne. */
body.admin-app .card table.table tbody td:last-child {
    border-bottom: none !important;
}

/* ---- 2. Cartes : marges internes calibrées.
   20 px en haut ET en bas autour d'un titre de trois mots, c'est
   40 px de vide par carte, multipliés par le nombre de cartes. ---- */
body.admin-app .card > .card-header {
    padding: 12px 14px !important;
}
body.admin-app .card > .card-body {
    padding: 12px 14px !important;
}
body.admin-app .card > .card-header + .card-body {
    padding-top: 10px !important;
}

/* ---- 3. Barre de filtres : c'est un outil, pas un contenu. ---- */
body.admin-app .filters-card > .card-body,
body.admin-app .card.filters-card > .card-body {
    padding: 10px 12px !important;
}
body.admin-app .filters-card .form-group {
    margin-bottom: 8px !important;
}
body.admin-app .filters-card .form-label {
    margin-bottom: 3px !important;
    font-size: 0.66rem !important;
}

/* ---- 4. Tuiles de statistiques : un nombre et son libellé. ---- */
body.admin-app .stat-card {
    padding: 12px 12px 11px !important;
    gap: 8px !important;
}
body.admin-app .stat-card .stat-label {
    line-height: 1.3;
}
body.admin-app .stat-card .stat-icon {
    width: 34px !important;
    height: 34px !important;
    flex: 0 0 34px !important;
}

/* ---- 5. États vides : informer sans occuper un écran. ---- */
body.admin-app .empty-state {
    padding: 18px 14px !important;
}
body.admin-app .empty-state i,
body.admin-app .empty-state .empty-icon {
    font-size: 1.6rem !important;
    margin-bottom: 6px !important;
}
body.admin-app .empty-state h3,
body.admin-app .empty-state .empty-title {
    font-size: 0.95rem !important;
    margin: 0 0 4px !important;
}

/* ---- 6. Fenêtres modales : mêmes marges que les cartes.
   Une modale plein écran qui n'affiche que quatre champs oblige à
   faire défiler pour atteindre le bouton de validation. ---- */
body.admin-app .modal .modal-body {
    padding: 14px !important;
}
body.admin-app .modal .modal-body .form-group {
    margin-bottom: 12px !important;
}
body.admin-app .modal .modal-body .form-label {
    margin-bottom: 4px !important;
}
body.admin-app .modal .modal-header {
    padding: 12px 14px !important;
}

}

/* ==================================================================
   FENÊTRES MODALES — densité des formulaires
   ------------------------------------------------------------------
   Mesuré : « Nouvel animateur » occupait 787 px pour 213 caractères,
   « Nouvelle activité » 684 px pour 87. Sur un écran de 844 px, il
   fallait faire défiler pour atteindre le bouton d'enregistrement
   d'un formulaire de six champs.
   Le coût vient du champ lui-même : étiquette + saisie + marge, soit
   ~85 px répétés. On réduit l'interstitiel, jamais la cible tactile —
   la zone de saisie reste à 44 px, le plancher confortable au doigt.
   ================================================================== */
@media (max-width: 768px) {

body.admin-app .modal .modal-body .form-group {
    margin-bottom: 10px !important;
}
body.admin-app .modal .modal-body .form-label,
body.admin-app .modal .modal-body label.form-label {
    margin-bottom: 3px !important;
    font-size: 0.76rem !important;
    line-height: 1.35 !important;
    font-weight: 600;
    color: var(--gray-600);
}
/* 44 px : le plancher tactile. On descend de 48 à 44, pas en dessous. */
body.admin-app .modal .modal-body .form-input,
body.admin-app .modal .modal-body .form-select,
body.admin-app .modal .modal-body input:not([type="checkbox"]):not([type="radio"]),
body.admin-app .modal .modal-body select {
    min-height: 44px !important;
    padding-top: 9px !important;
    padding-bottom: 9px !important;
}
body.admin-app .modal .modal-body textarea {
    min-height: 66px !important;
    padding-top: 9px !important;
    padding-bottom: 9px !important;
}

/* Les champs courts groupés par l'auteur dans une même rangée tiennent
   côte à côte : c'est précisément pourquoi il les a groupés. En dessous
   de 165 px la saisie devient inconfortable, donc auto-fit s'en charge
   et le champ surnuméraire passe à la ligne de lui-même. */
body.admin-app .modal .modal-body .form-row {
    display: grid !important;
    /* !important obligatoire : « .form-row { grid-template-columns: 1fr
       !important } » (mobile-polish:467) ne tient qu'à une classe, mais
       entre deux !important c'est la spécificité qui tranche — et sans le
       mot-clé, la déclaration la plus faible l'emporterait quand même. */
    grid-template-columns: repeat(auto-fit, minmax(165px, 1fr)) !important;
    gap: 0 10px !important;
    align-items: start;
}
body.admin-app .modal .modal-body .form-row > .form-group {
    min-width: 0;
}

/* Le message d'aide sous un champ ne mérite pas sa propre rangée. */
body.admin-app .modal .modal-body .form-group small,
body.admin-app .modal .modal-body .form-group .text-xs {
    display: block;
    margin-top: 2px;
    line-height: 1.35;
}
/* Un emplacement d'erreur vide ne doit rien occuper tant qu'il est vide. */
body.admin-app .modal .modal-body .field-error:empty {
    display: none !important;
}

/* Barre d'actions : collée en bas, elle reste atteignable sans défiler
   jusqu'au bout d'un formulaire long. */
body.admin-app .modal .modal-body .form-actions {
    margin-top: 12px !important;
    padding-top: 10px !important;
    border-top: 1px solid var(--gray-100);
    gap: 8px;
}

}

/* Le dégagement de 96 px sous le corps d'une modale existe pour que la
   dernière rangée n'affleure pas le pied COLLANT (mobile-polish:634).
   Il s'appliquait aussi aux modales qui n'ont pas de pied — leurs boutons
   vivent dans le corps — soit 80 px de vide pur en bas de chaque petite
   fenêtre. On le réserve à celles qui en ont réellement un.
   :has() non reconnu ⇒ la règle est ignorée et l'ancien comportement,
   sûr, reste en place. */
@media (max-width: 768px) {
    body.admin-app .modal-overlay .modal:not(:has(> .modal-footer)) .modal-body {
        padding-bottom: 14px !important;
    }
}

/* ------------------------------------------------------------------
   Modale famille — bloc « Enfant »
   Mesuré : 927 px POUR UN SEUL enfant, soit plus que tout le reste de
   la fenêtre, et répété à chaque frère ou sœur. La section d'état civil
   empilait cinq champs de 90 px sur une seule colonne avec 20 px de
   gouttière.
   Le nom garde toute la largeur (c'est le champ qu'on lit et corrige) ;
   les quatre suivants — date, système, niveau, fréquence — sont courts
   et tiennent deux par rangée.
   ------------------------------------------------------------------ */
@media (max-width: 768px) {
    body.admin-app .child-card-edit .child-card-header {
        padding: 10px 14px !important;
    }
    body.admin-app .child-card-edit .child-card-body {
        padding: 14px !important;
    }
    body.admin-app .child-card-edit .child-info-section {
        margin-bottom: 14px !important;
    }
    body.admin-app .child-card-edit .form-row-modern {
        grid-template-columns: repeat(auto-fit, minmax(148px, 1fr)) !important;
        gap: 0 10px !important;
    }
    body.admin-app .child-card-edit .form-row-modern > .form-field {
        margin-bottom: 8px !important;
        min-width: 0;
    }
    /* Le nom complet ne se coupe pas en deux colonnes. */
    body.admin-app .child-card-edit .form-row-modern > .form-field:first-child {
        grid-column: 1 / -1;
    }
    body.admin-app .child-card-edit .activities-section-modern {
        padding: 12px !important;
    }
}

/* ------------------------------------------------------------------
   Garde : les pages qui ont leur PROPRE mise en carte
   La couche de densité pose « td { display:grid; grid-template-columns:
   82px 1fr } » pour aligner étiquette et valeur. Deux pages n'en veulent
   pas — elles composent déjà leurs cellules en zones nommées (Paiements,
   fiche famille). Sans cette garde, chaque cellule y gagnait une colonne
   d'étiquette vide de 82 px : le nom passait à la ligne et la barre de
   boutons chevauchait les pastilles.
   Placé en fin de feuille pour passer après la couche générique.
   ------------------------------------------------------------------ */
@media (max-width: 768px) {
    body.page-payments.admin-app .card table.table tbody td,
    body.page-family.admin-app .card table.table tbody td {
        display: block !important;
        grid-template-columns: none !important;
        column-gap: 0 !important;
    }
    /* La cellule des pastilles reste en rangée souple. */
    body.page-payments.admin-app .card table.table tbody td:nth-child(4) {
        display: flex !important;
    }
    body.page-family.admin-app .card table.table tbody td:nth-child(3) {
        display: flex !important;
    }
}

/* ------------------------------------------------------------------
   Tableau de bord — « Derniers paiements » en trois rangées
   Le patron générique donnait une rangée par colonne : nom, mois,
   détail sur trois lignes, montant, date — sept lignes pour UN
   encaissement. Ce qu'on lit d'abord, c'est qui a payé et combien.
   ------------------------------------------------------------------ */
@media (max-width: 768px) {
    body.page-dashboard.admin-app #recentPaymentsList tr {
        display: grid !important;
        grid-template-columns: minmax(0, 1fr) auto;
        column-gap: 10px;
        align-items: baseline;
    }
    body.page-dashboard.admin-app #recentPaymentsList td {
        display: block !important;
        grid-template-columns: none !important;
        padding: 1px 0 !important;
        border-bottom: none !important;
    }
    body.page-dashboard.admin-app #recentPaymentsList td::before {
        display: none !important;
    }
    body.page-dashboard.admin-app #recentPaymentsList td:nth-child(1) {
        grid-row: 1; grid-column: 1;
        font-weight: 700; font-size: 0.95rem;
        overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    }
    body.page-dashboard.admin-app #recentPaymentsList td:nth-child(4) {
        grid-row: 1; grid-column: 2;
        text-align: right; white-space: nowrap;
    }
    body.page-dashboard.admin-app #recentPaymentsList td:nth-child(3) {
        grid-row: 2; grid-column: 1 / -1;
        font-size: 0.82rem; color: var(--gray-600); line-height: 1.4;
    }
    body.page-dashboard.admin-app #recentPaymentsList td:nth-child(2) {
        grid-row: 3; grid-column: 1;
        font-size: 0.75rem;
    }
    body.page-dashboard.admin-app #recentPaymentsList td:nth-child(5) {
        grid-row: 3; grid-column: 2;
        text-align: right; font-size: 0.75rem; white-space: nowrap;
    }

    /* En-tête de carte : le titre et son action de tête se lisent
       ensemble. « Tout voir » s'octroyait une rangée entière. */
    body.admin-app .card > .card-header {
        display: flex !important;
        flex-direction: row !important;
        align-items: center;
        justify-content: space-between;
        gap: 10px;
        flex-wrap: nowrap;
    }
    body.admin-app .card > .card-header > .card-title {
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
    body.admin-app .card > .card-header > .btn,
    body.admin-app .card > .card-header > a {
        flex: 0 0 auto;
        margin: 0 !important;
    }
}

/* ------------------------------------------------------------------
   Même composition pour TOUTES les listes en cartes
   Ce qui a été validé sur Paiements et le tableau de bord devient la
   règle générale : l'identité de la ligne en tête, ses actions en face
   sur la MÊME rangée, les champs étiquetés en dessous. La barre de
   boutons s'octroyait sinon une rangée pleine de 44 px sur chaque
   ligne de chaque liste.
   :has() réserve le déplacement aux cellules d'ACTION réelles — une
   dernière colonne de données garde sa pleine largeur. Les deux pages
   qui composent déjà leurs cellules (Paiements, fiche famille) sont
   exclues plus haut et ne sont pas concernées.
   ------------------------------------------------------------------ */
@media (max-width: 768px) {
    body.admin-app:not(.page-payments):not(.page-family) .card table.table tbody tr:has(> td:last-child .btn, > td:last-child button) {
        display: grid !important;
        grid-template-columns: minmax(0, 1fr) auto;
        column-gap: 8px;
        align-items: start;
    }
    body.admin-app:not(.page-payments):not(.page-family) .card table.table tbody tr:has(> td:last-child .btn, > td:last-child button) > td {
        grid-column: 1 / -1;
    }
    body.admin-app:not(.page-payments):not(.page-family) .card table.table tbody tr:has(> td:last-child .btn, > td:last-child button) > td:first-child {
        grid-column: 1;
        grid-row: 1;
        font-weight: 600;
    }
    body.admin-app:not(.page-payments):not(.page-family) .card table.table tbody tr > td:last-child:has(button, .btn, a.btn) {
        grid-column: 2;
        grid-row: 1;
        display: flex !important;
        justify-content: flex-end;
        align-items: center;
        gap: 4px;
        padding: 0 !important;
        white-space: nowrap;
    }
    /* Compacts, mais jamais sous le seuil confortable au doigt. */
    body.admin-app .card table.table tbody td:last-child .btn,
    body.admin-app .card table.table tbody td:last-child .action-btn {
        min-width: 38px;
        min-height: 38px;
    }
}

/* ------------------------------------------------------------------
   Tuiles de statistiques — hauteur alignée
   Certaines portaient « min-height: 110px » et une réserve de 48 px à
   droite, héritées d'une époque où l'icône était positionnée en absolu.
   Elle est aujourd'hui un frère en flex : la réserve rétrécit le libellé
   pour rien, ce qui le fait passer à la ligne, ce qui déclenche la
   hauteur forcée. D'où deux tuiles côte à côte dont l'une est à moitié
   vide. On rend la hauteur au contenu ; la grille égalise la rangée.
   ------------------------------------------------------------------ */
@media (max-width: 768px) {
    body.admin-app .stat-card {
        min-height: 0 !important;
    }
    /* La réserve à droite n'était PAS superflue : l'icône est positionnée
       en absolu, et sans elle les libellés passent dessous. On la garde,
       ajustée à la taille réelle de l'icône (34 px) au lieu de 48. */
    body.admin-app .stat-card .stat-content {
        padding-right: 44px !important;
        min-width: 0;
    }
    body.admin-app .stat-card .stat-label {
        font-size: 0.78rem;
        line-height: 1.25;
    }
}

/* ------------------------------------------------------------------
   Boutons des bandeaux « À traiter » / « À valider »
   Je les avais descendus à 28 px en resserrant la carte : sous le
   pouce, c'est trop petit. On remonte à 34 px — la carte ne gagne que
   6 px à les rétrécir, et ils se ratent.
   ------------------------------------------------------------------ */
body.page-families .family-request-banner .frb-action,
body.page-families .family-pending-banner .frb-action {
    height: 34px !important;
    min-height: 34px !important;
    padding: 0 13px !important;
}

/* ------------------------------------------------------------------
   Modale famille — champ « Montant » d'une activité
   Le suffixe « DH » est posé en absolu dans le champ ; l'original
   réservait 40 px à droite (style.css:7759). La règle mobile
   « input:not([type=checkbox]) { padding: 11px 14px !important } »
   écrase ce raccourci : le montant se réimprimait PAR-DESSUS « DH ».
   Même famille de bug que l'indicatif téléphonique.
   Et l'indice de tarif dégressif, ajouté en fin de conteneur flex,
   venait se placer À CÔTÉ du champ, sur le « DH ». Il prend sa ligne.
   ------------------------------------------------------------------ */
/* Spécificité : la règle concurrente est « input:not([type=checkbox])
   :not([type=radio]) », soit deux pseudo-classes — il faut au moins
   autant de poids, d'où body.admin-app en tête. */
body.admin-app .modal input.activity-amount-modern,
body.admin-app input.activity-amount-modern {
    padding-right: 40px !important;
    padding-left: 12px !important;
}
.modal .amount-input-wrapper {
    flex-wrap: wrap;
}
.modal .amount-input-wrapper .price-hint,
.amount-input-wrapper .price-hint {
    flex: 1 0 100%;
    margin-top: 4px;
    line-height: 1.3;
}

/* Frais d'inscription sur la ligne enfant : réglés (vert discret) ou dus
   (ambre). Volontairement une pastille et non un montant — les frais sont
   annuels, les additionner au total mensuel le fausserait dès octobre. */
body.page-families .family-card .activity-badge-small.frais-ok {
    background: rgba(16, 185, 129, .12) !important;
    color: #0f7a53 !important;
    font-weight: 600 !important;
}
body.page-families .family-card .activity-badge-small.frais-du {
    background: rgba(245, 158, 11, .14) !important;
    color: #8a5209 !important;
    font-weight: 600 !important;
}

/* ------------------------------------------------------------------
   Bouton « Envoyer » WhatsApp de la page Contrats
   L'action principale de cet écran n'est pas de copier un lien, c'est de
   l'envoyer : elle porte donc la couleur de WhatsApp et son libellé, au
   lieu d'un énième bouton gris. Quand le numéro manque, le bouton reste
   VISIBLE mais éteint — sinon l'absence passerait pour un bug d'affichage
   alors qu'il manque une donnée sur la fiche famille.
   ------------------------------------------------------------------ */
.btn.btn-wa {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: #25D366 !important;
    color: #fff !important;
    border: none !important;
    font-weight: 700;
    white-space: nowrap;
}
.btn.btn-wa:hover { background: #1da851 !important; }
.btn.btn-wa.is-off {
    background: var(--gray-100) !important;
    color: var(--gray-500) !important;
    cursor: not-allowed;
}

/* ==================================================================
   PLANNING — vue par animateur
   Une liste nominative se lit et s'imprime : l'animateur emporte sa
   feuille en salle. D'où une composition sobre, un niveau scolaire
   qui se détache de chaque nom, et une impression qui ne coupe pas
   un créneau en deux.
   ================================================================== */
.instr-bloc {
    background: #fff;
    border: 1px solid var(--gray-100);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    padding: 14px 16px;
    margin-bottom: 14px;
}
.instr-entete {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    flex-wrap: wrap;
    padding-bottom: 8px;
    border-bottom: 2px solid var(--primary);
    margin-bottom: 10px;
}
.instr-nom {
    margin: 0;
    font-size: 1.05rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--gray-900);
}
.instr-compte { font-size: .82rem; color: var(--gray-500); font-weight: 600; }

/* Chaque créneau est un bloc à part entière. Un simple filet ne suffisait
   pas : sur téléphone l'en-tête passe sur deux lignes et les créneaux se
   confondaient, au point qu'on ne savait plus quel élève appartenait à
   quelle séance. L'en-tête prend donc un fond, et la liste vit dessous. */
.instr-creneau {
    border: 1px solid var(--gray-200);
    border-radius: var(--radius-sm);
    overflow: hidden;
    margin-bottom: 10px;
    padding: 0;
}
.instr-creneau:last-child { margin-bottom: 0; }
.instr-quand {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 2px 10px;
    padding: 7px 10px;
    margin: 0;
    background: var(--gray-50, #f8fafc);
    border-bottom: 1px solid var(--gray-200);
    font-size: .88rem;
}
.instr-quand strong { color: var(--gray-900); }
.instr-quand span { color: var(--gray-600); }
.instr-ou { font-weight: 600; color: var(--primary-dark) !important; }
/* Salles masquables — la feuille sert d'abord à l'appel, l'animateur sait
   où il fait cours. Le choix est retenu d'une visite à l'autre. */
.instr-sans-salles .instr-salle { display: none; }
.instr-actions {
    display: flex;
    justify-content: flex-end;
    align-items: center;
    gap: var(--space-3);
    flex-wrap: wrap;
    margin-bottom: var(--space-3);
}
.instr-bascule {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    min-height: 44px;
    padding: 0 var(--space-2);
    cursor: pointer;
    color: var(--gray-600);
    font-size: .88rem;
}
.instr-bascule input { width: 18px; height: 18px; accent-color: var(--primary); cursor: pointer; }

/* Les élèves étaient rangés en deux colonnes de PAGE : chaque colonne
   faisait la moitié de la largeur, donc un créneau à deux élèves posait le
   second au milieu de l'écran, à plusieurs centimètres du premier. On les
   pose en pastilles qui s'enchaînent : la liste prend la place qu'il lui
   faut, pas la largeur disponible, et une classe de douze tient sur deux
   rangées serrées. */
.instr-eleves {
    margin: 0;
    padding: var(--space-2) var(--space-3);
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    counter-reset: instr-eleve;
}
.instr-eleves li {
    counter-increment: instr-eleve;
    display: inline-flex;
    align-items: baseline;
    gap: var(--space-1);
    padding: var(--space-1) var(--space-3);
    border: 1px solid var(--gray-200);
    border-radius: var(--radius-sm);
    background: var(--gray-50);
    break-inside: avoid;
    font-size: .88rem;
}
/* Le numéro reste : la feuille sert à l'appel, on compte les présents. */
.instr-eleves li::before {
    content: counter(instr-eleve) ".";
    color: var(--gray-500);
    font-size: .74rem;
    font-weight: 700;
}
.instr-eleve { color: var(--gray-800); }
.instr-niveau {
    /* L'écart vient du gap de la pastille, pas d'une marge propre. */
    margin-left: 0;
    padding: 1px 7px;
    border-radius: var(--radius-full);
    background: var(--gray-100);
    color: var(--gray-600);
    font-size: .72rem;
    font-weight: 700;
}
/* Un niveau manquant se voit : c'est une fiche enfant à compléter,
   pas une information qu'on peut deviner. */
.instr-niveau.vide {
    background: rgba(245, 158, 11, .14);
    color: #8a5209;
    font-weight: 600;
}
.instr-vide {
    margin: 0;
    padding: 8px 10px;
    font-size: .85rem;
    color: var(--gray-500);
    font-style: italic;
}

@media print {
    .no-print, .sidebar, .topbar, .planning-actions, .bottom-nav { display: none !important; }
    .instr-bloc {
        break-inside: avoid;
        page-break-inside: avoid;
        box-shadow: none;
        border: 1px solid #999;
    }
    .instr-creneau { break-inside: avoid; page-break-inside: avoid; }
}

/* ------------------------------------------------------------------
   Planning — sélecteur de vue sur téléphone
   Cinq vues ne tiennent pas sur 362 px. Les boutons ne débordaient pas :
   ils se COMPRIMAIENT, et chacun rognait son propre libellé — d'où un
   « Animateu » coupé que ni scrollWidth ni un test de débordement ne
   signalent. On les laisse passer à la ligne : deux rangées lisibles
   valent mieux qu'une rangée tronquée.
   ------------------------------------------------------------------ */
@media (max-width: 768px) {
    body.page-planning .planning-views {
        flex-wrap: wrap !important;
        gap: 6px;
        width: 100%;
    }
    body.page-planning .planning-views .btn {
        flex: 0 0 auto !important;
        min-width: 0;
        white-space: nowrap;
        overflow: visible;
    }
    /* Le compte de l'animateur se lit d'un bloc : « 2 créneaux » puis
       « · 11 élèves » sur deux lignes se lisait comme deux informations. */
    body.page-planning .instr-compte {
        white-space: nowrap;
    }
    body.page-planning .instr-entete {
        gap: 4px 10px;
    }
}

/* =========================================================
   MÊME GRAMMAIRE POUR LES CARTES SŒURS — 31/08/2026

   La vue « Plan » a été refaite en lignes : intitulé et chiffre sur la
   première, contexte et jauge sur la seconde, un jonc coloré pour
   l'identité, aucune boîte dans la boîte. Trois autres écrans montrent la
   même matière — une séance, une salle, un effectif — et la montraient
   chacun à leur façon. On les aligne :

     · planning, vue Jour     (.agenda-card)
     · présences, sessions    (.attendance-session-card)
     · planning, vue Semaine  (.week-day-card)

   Règles communes : pas de pastille pleine ni de dégradé décoratif, pas
   d'icône qui répète le mot qu'elle précède, les chiffres à droite, la
   couleur portée par un jonc et une jauge — jamais par un aplat.
   ========================================================= */

@media (max-width: 768px) {

    /* ---------- PLANNING · vue Jour ---------- */
    /* L'heure occupait une colonne grise pleine hauteur, la salle une
       pastille teintée, l'effectif une ligne à part sous une barre : quatre
       informations pour 200 px. */
    body.page-planning .day-agenda-list {
        background: var(--white);
        border: 1px solid var(--hairline);
        border-radius: var(--r-lg, 18px);
        box-shadow: var(--shadow-1);
        padding: 0 14px;
        overflow: hidden;
    }
    body.page-planning .agenda-card {
        position: relative;
        display: grid !important;
        grid-template-columns: auto 1fr;
        align-items: center;
        column-gap: 12px;
        margin: 0 !important;
        padding: 10px 0 10px 14px !important;
        background: transparent !important;
        border: none !important;
        border-left: none !important;
        border-radius: 0 !important;
        box-shadow: none !important;
    }
    body.page-planning .agenda-card + .agenda-card {
        border-top: 1px solid var(--hairline) !important;
    }
    body.page-planning .agenda-card:active { background: var(--canvas) !important; }
    body.page-planning .agenda-card::before {
        content: '';
        position: absolute;
        left: 0;
        top: 12px;
        bottom: 12px;
        width: 3px;
        border-radius: 999px;
        background: var(--room-color, var(--primary));
    }
    body.page-planning .agenda-time {
        display: flex !important;
        flex-direction: column;
        align-items: flex-end;
        gap: 0;
        min-width: 0 !important;
        width: auto !important;
        padding: 0 !important;
        background: transparent !important;
        border: none !important;
        font-variant-numeric: tabular-nums;
    }
    body.page-planning .agenda-time .start {
        font-family: var(--font-display);
        font-size: 0.92rem;
        font-weight: 600;
        color: var(--ink);
        letter-spacing: -0.02em;
    }
    body.page-planning .agenda-time .end {
        font-size: 0.74rem;
        color: var(--ink-faint);
    }
    /* display:contents dissout les deux sous-blocs : intitulé, salle,
       professeur et effectif deviennent les cases d'une seule grille, seule
       façon de mettre le chiffre en face du titre sans toucher au HTML. */
    body.page-planning .agenda-details {
        display: grid !important;
        grid-template-columns: auto 1fr auto;
        align-items: center;
        column-gap: 6px;
        row-gap: 1px;
        min-width: 0;
    }
    body.page-planning .agenda-header,
    body.page-planning .agenda-meta { display: contents !important; }
    body.page-planning .agenda-activity {
        grid-row: 1;
        grid-column: 1 / 3;
        font-family: var(--font-display);
        font-size: 0.95rem;
        font-weight: 600;
        letter-spacing: -0.01em;
        color: var(--ink);
        min-width: 0;
    }
    body.page-planning .agenda-counts {
        grid-row: 1;
        grid-column: 3;
        justify-self: end;
        font-variant-numeric: tabular-nums;
        font-weight: 700;
        font-size: 0.83rem;
        color: var(--ink-soft) !important;
        white-space: nowrap;
    }
    body.page-planning .agenda-counts i { display: none; }
    /* La pastille de salle teintée reprenait la couleur de la salle en TEXTE
       sur son propre lavis : contraste non garanti, la couleur venant de la
       base. Étiquette sobre, le jonc porte la couleur. */
    body.page-planning .agenda-room {
        grid-row: 2;
        grid-column: 1;
        padding: 0 !important;
        background: transparent !important;
        border: none !important;
        border-radius: 0 !important;
        font-size: 0.68rem !important;
        font-weight: 700;
        letter-spacing: 0.06em;
        text-transform: uppercase;
        color: var(--ink-faint) !important;
    }
    body.page-planning .agenda-instructor,
    body.page-planning .agenda-meta .text-muted {
        grid-row: 2;
        grid-column: 2;
        font-size: 0.79rem;
        color: var(--ink-soft);
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
    body.page-planning .agenda-instructor i { display: none; }
    body.page-planning .agenda-instructor::before,
    body.page-planning .agenda-meta .text-muted::before {
        content: '·';
        margin-right: 5px;
        color: var(--hairline-strong);
    }
    body.page-planning .agenda-details .progress-bar { display: none !important; }
    body.page-planning .agenda-details .cell-seats {
        display: flex !important;
        grid-row: 2;
        grid-column: 3;
        align-items: center;
        gap: 3px;
    }
    /* Le chevron consommait 30 px de largeur pour redire que la ligne
       s'ouvre — la ligne entière est déjà tactile. */
    body.page-planning .agenda-action { display: none !important; }


    /* ---------- PRÉSENCES · sessions du jour ---------- */
    /* En-tête dégradé, pastille d'état, trois compteurs, barre vide et
       bouton pleine largeur : 430 px par séance, dont l'essentiel répétait
       le même « rien de pointé ». */
    body.page-attendance .attendance-session-card {
        position: relative;
        margin: 0 !important;
        /* Le conteneur ne marge pas a droite : sans ce padding l'etiquette
           et le bouton affleuraient le bord de la carte. */
        padding: 12px 14px 12px 14px !important;
        background: transparent !important;
        border: none !important;
        border-left: none !important;
        border-radius: 0 !important;
        box-shadow: none !important;
    }
    body.page-attendance .attendance-session-card + .attendance-session-card {
        border-top: 1px solid var(--hairline) !important;
    }
    body.page-attendance .attendance-session-card::before {
        content: '';
        position: absolute;
        left: 0;
        top: 14px;
        bottom: 14px;
        width: 3px;
        border-radius: 999px;
        background: var(--etat, var(--primary));
    }
    body.page-attendance .attendance-session-card > .card-header {
        display: flex !important;
        /* .card-header autorise le retour a la ligne et ses deux enfants font
           100 % : l'etiquette « x/y pointes » tombait sous le titre. */
        flex-wrap: nowrap !important;
        align-items: flex-start;
        justify-content: space-between;
        gap: 10px;
        background: none !important;
        border: none !important;
        padding: 0 !important;
        margin: 0 0 6px !important;
    }
    body.page-attendance .attendance-session-card > .card-header strong {
        font-family: var(--font-display);
        font-size: 0.95rem;
        font-weight: 600;
        letter-spacing: -0.01em;
        color: var(--ink);
    }
    body.page-attendance .attendance-session-card > .card-header small {
        display: block;
        font-size: 0.79rem;
        color: var(--ink-soft) !important;
        margin-top: 1px;
    }
    body.page-attendance .attendance-session-card > .card-header > div:first-child {
        flex: 1 1 auto;
        min-width: 0;
        width: auto !important;
    }
    body.page-attendance .attendance-session-card > .card-header .text-right {
        flex: 0 0 auto;
        width: auto !important;
    }
    body.page-attendance .attendance-session-card > .card-body {
        display: flex !important;
        align-items: center;
        justify-content: space-between;
        gap: 10px;
        flex-wrap: wrap;
        padding: 0 !important;
    }
    body.page-attendance .attendance-stats {
        display: flex !important;
        align-items: center;
        gap: 12px;
        flex: 1 1 auto;
        min-width: 0;
        font-size: 0.79rem;
        font-variant-numeric: tabular-nums;
        flex-wrap: nowrap;
    }
    /* Chiffres seuls : l'icône et sa couleur disent déjà présent, absent ou
       retard. La phrase entière reste dans l'aria-label. */
    body.page-attendance .attendance-stats .att-lib,
    body.page-attendance .attendance-session-card .btn .att-lib { display: none; }
    /* La barre ne disait rien tant que rien n'était pointé, et redisait
       l'étiquette « x/y pointés » le reste du temps. */
    body.page-attendance .attendance-progress { display: none !important; }
    /* Bouton pleine largeur pour une action ponctuelle : il pesait autant
       que la séance elle-même. Au bout de la ligne, toujours 44 px. */
    body.page-attendance .attendance-session-card .btn.w-full {
        width: auto !important;
        min-height: 44px !important;
        margin: 0 !important;
        flex: 0 0 auto;
        white-space: nowrap;
    }


    /* ---------- PLANNING · vue Semaine ---------- */
    /* Un bandeau violet plein par jour — la refonte a justement rendu le
       violet à son rôle d'accent — surmontant un anneau à 4 %, donc gris à
       96 %, puis trois lignes précédées d'icônes redondantes. */
    body.page-planning .week-day-card {
        background: var(--white);
        border: 1px solid var(--hairline);
        border-radius: var(--r-md, 14px);
        box-shadow: var(--shadow-1);
        overflow: hidden;
    }
    body.page-planning .week-day-card-header {
        display: flex !important;
        align-items: baseline;
        justify-content: space-between;
        gap: 6px;
        background: none !important;
        background-color: transparent !important;
        color: var(--ink) !important;
        border: none !important;
        border-bottom: 1px solid var(--hairline) !important;
        padding: 10px 12px !important;
    }
    body.page-planning .week-day-card-header .day-name {
        font-family: var(--font-display);
        font-size: 0.86rem;
        font-weight: 600;
        color: var(--ink) !important;
    }
    body.page-planning .week-day-card-header .day-date {
        font-family: var(--font-display);
        font-size: 1.05rem;
        font-weight: 700;
        font-variant-numeric: tabular-nums;
        color: var(--ink-faint) !important;
    }
    body.page-planning .week-day-card-body {
        display: grid !important;
        grid-template-columns: auto 1fr;
        align-items: center;
        gap: 10px;
        padding: 10px 12px !important;
    }
    /* L'anneau tombe à la taille d'une pastille : à 4 % il ne se lit pas,
       c'est le chiffre qui informe. Il garde son rôle de repère coloré. */
    body.page-planning .week-day-card-body .fill-circle {
        width: 34px !important;
        height: 34px !important;
        flex: 0 0 auto;
        margin: 0 !important;
    }
    /* Le disque blanc central est fixe a 60 px : reduit a 34, l'anneau
       disparaissait entierement sous lui. */
    body.page-planning .week-day-card-body .fill-circle::before {
        width: 26px !important;
        height: 26px !important;
    }
    body.page-planning .week-day-card-body .fill-circle span {
        font-size: 0.62rem !important;
        font-weight: 700;
        font-variant-numeric: tabular-nums;
    }
    body.page-planning .day-stats {
        display: flex !important;
        flex-direction: column;
        gap: 1px;
        min-width: 0;
        text-align: left !important;
        font-size: 0.76rem;
        color: var(--ink-soft);
        font-variant-numeric: tabular-nums;
    }
    body.page-planning .day-stats i { display: none; }
}

/* ---------- TABLEAU DE BORD · statistiques par activité ---------- */
/* Une tuile de 64 px pour une icône qui, dans les données réelles, est
   l'étoile par défaut sur toutes les activités : elle ne portait que la
   couleur, déjà tenue par le jonc de gauche. Le nom cassait sur deux lignes
   parce que la tuile lui prenait le quart de la largeur. 130 px par
   activité pour trois informations. */
@media (max-width: 768px) {
    body.page-dashboard .activities-stats-grid {
        display: block !important;
    }
    body.page-dashboard .activity-stat-card {
        position: relative;
        display: grid !important;
        grid-template-columns: auto 1fr auto;
        align-items: center;
        column-gap: 10px;
        row-gap: 0;
        margin: 0 !important;
        padding: 10px 2px 10px 14px !important;
        background: transparent !important;
        border: none !important;
        border-left: none !important;
        border-radius: 0 !important;
        box-shadow: none !important;
        min-height: 44px;
    }
    body.page-dashboard .activity-stat-card + .activity-stat-card {
        border-top: 1px solid var(--hairline) !important;
    }
    body.page-dashboard .activity-stat-card:active { background: var(--canvas) !important; }
    /* Le bord carré pleine hauteur devient un jonc arrondi, comme partout
       ailleurs. La couleur passe par une variable posée en ligne : une
       couleur de bordure ne se relit pas depuis une autre propriété. */
    body.page-dashboard .activity-stat-card::before {
        content: '';
        position: absolute;
        left: 0;
        top: 10px;
        bottom: 10px;
        width: 3px;
        border-radius: 999px;
        background: var(--activite-color, var(--primary));
    }
    /* fa-star est l'icône par défaut des activités sans icône propre : ici,
       les neuf. Une tuile colorée pour une étoile identique partout, à côté
       d'un jonc qui porte déjà la même couleur, c'est deux fois la même
       information. Les activités dotées d'une vraie icône la gardent. */
    body.page-dashboard .activity-stat-icon:has(> i.fa-star) { display: none !important; }
    body.page-dashboard .activity-stat-card:has(.activity-stat-icon > i.fa-star) {
        grid-template-columns: 1fr auto;
    }
    body.page-dashboard .activity-stat-icon {
        grid-row: 1 / span 2;
        grid-column: 1;
        width: 30px !important;
        height: 30px !important;
        min-width: 0 !important;
        border-radius: var(--r-sm, 10px) !important;
        font-size: 0.72rem !important;
        flex: 0 0 auto;
    }
    body.page-dashboard .activity-stat-info {
        grid-row: 1;
        grid-column: 1;
        min-width: 0;
    }
    body.page-dashboard .activity-stat-card:has(.activity-stat-icon > i:not(.fa-star)) .activity-stat-info {
        grid-column: 2;
    }
    body.page-dashboard .activity-stat-name {
        font-family: var(--font-display);
        font-size: 0.95rem;
        font-weight: 600;
        letter-spacing: -0.01em;
        color: var(--ink);
        line-height: 1.25;
    }
    body.page-dashboard .activity-stat-details {
        display: flex !important;
        gap: 10px;
        margin-top: 1px !important;
        font-size: 0.78rem;
        color: var(--ink-soft);
        font-variant-numeric: tabular-nums;
    }
    /* Le bonhomme précédait « inscrits » : il ne disait rien de plus. */
    body.page-dashboard .activity-stat-details i { display: none; }
    body.page-dashboard .activity-stat-revenue {
        grid-row: 1;
        grid-column: -1;
        justify-self: end;
        align-self: center;
        font-size: 0.95rem !important;
        font-weight: 700;
        font-variant-numeric: tabular-nums;
        white-space: nowrap;
    }

    /* L'action d'en-tête (« Voir tout ») tombait sur sa propre ligne :
       .card-header autorise le retour à la ligne et le bloc de titre occupe
       toute la largeur. Une ligne entière pour un lien. */
    body.admin-app .card > .card-header {
        flex-wrap: nowrap !important;
    }
    body.admin-app .card > .card-header > .card-header-left {
        flex: 1 1 auto;
        min-width: 0;
    }
    body.admin-app .card > .card-header > .btn-ghost {
        flex: 0 0 auto;
        white-space: nowrap;
    }
}

/* ==========================================================================
   PROSPECTS — les inscriptions commencées sur le site
   Une fiche = quelqu'un à rappeler. On met donc en avant ce qui sert à
   décrocher le téléphone : le nom, depuis quand, comment le joindre — et,
   pour ceux qui n'ont pas terminé, où ils se sont arrêtés.
   ========================================================================== */
.prosp-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
    gap: var(--space-4);
}
.prosp-carte {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    padding: var(--space-4);
    border: 1px solid var(--gray-200);
    border-radius: var(--radius-md);
    background: #fff;
    box-shadow: var(--shadow-sm);
}
.prosp-entete {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-2);
    flex-wrap: wrap;
}
.prosp-identite { display: flex; flex-direction: column; min-width: 0; }
.prosp-identite strong { font-size: 1rem; color: var(--gray-900); }
.prosp-quand { font-size: 0.78rem; color: var(--gray-500); }

.prosp-contacts { display: flex; flex-direction: column; gap: var(--space-1); }
.prosp-contacts a {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    min-height: 32px;
    color: var(--gray-600);
    font-size: 0.88rem;
    text-decoration: none;
}
.prosp-contacts a:hover { color: var(--primary); text-decoration: underline; }
.prosp-contacts i { color: var(--gray-400); width: 14px; }

.prosp-puces { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.prosp-puce {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: var(--space-1) var(--space-3);
    border-radius: var(--radius-sm);
    background: var(--gray-50);
    border: 1px solid var(--gray-200);
    color: var(--gray-700);
    font-size: 0.78rem;
}
/* La formule commande tout le reste : elle se distingue des matières. */
.prosp-puce-forte {
    background: var(--wash, rgba(67, 56, 202, 0.07));
    border-color: transparent;
    color: var(--primary-dark);
    font-weight: 600;
}

.prosp-arret {
    margin: 0;
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius-sm);
    background: rgba(245, 158, 11, 0.12);
    color: #8a5209;
    font-size: 0.82rem;
}
.prosp-note {
    margin: 0;
    color: var(--gray-600);
    font-size: 0.85rem;
    font-style: italic;
}
.prosp-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: auto;
    padding-top: var(--space-2);
    border-top: 1px solid var(--gray-100);
}

/* L'entonnoir : une barre par étape, proportionnelle au plus gros abandon. */
.prosp-abandons { display: flex; flex-direction: column; gap: var(--space-2); }
.prosp-etape {
    display: grid;
    grid-template-columns: minmax(90px, 140px) 1fr auto;
    align-items: center;
    gap: var(--space-3);
    font-size: 0.85rem;
}
.prosp-etape-nom { color: var(--gray-700); }
.prosp-barre {
    display: block;
    height: 8px;
    border-radius: var(--radius-full);
    background: var(--gray-100);
    overflow: hidden;
}
.prosp-barre > span {
    display: block;
    height: 100%;
    border-radius: var(--radius-full);
    background: var(--warning);
}
.prosp-etape-nb {
    font-weight: 700;
    color: var(--gray-900);
    font-variant-numeric: tabular-nums;
}

/* Téléphone : une fiche par ligne, cibles tactiles confortables. */
@media (max-width: 768px) {
    body.page-prospects .prosp-grid { display: block; width: 100%; }
    body.page-prospects .prosp-carte { width: 100%; margin-bottom: var(--space-3); }
    body.page-prospects .prosp-contacts a { min-height: 44px; }
    body.page-prospects .prosp-actions .btn { min-height: 44px; }
}
