/**
 * Admin modal — lateral tab layout.
 *
 * Mirrors the user-options features panel (.features-layout) for
 * visual consistency: a 200 px sidebar on the left listing the
 * categories, and the active panel on the right.
 *
 * All colors come from the --izi-* token set so the panel swaps
 * automatically under body.theme-dark / @media prefers-color-scheme.
 */

/* Make the admin modal body a flex column so .admin-layout can
   stretch to the available height instead of collapsing to its
   content. Matches the trick used by #viewSettings .modal-body in
   features-panel.css.
   `overflow: hidden` moves the scroll bar from the body to the
   right-hand .admin-tab-content so the sidebar stays full-height
   and the bottom-most tab remains visible regardless of panel
   content length. */
#viewAdmin .admin-modal-body {
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.admin-layout {
    display: flex;
    flex-direction: row;
    gap: var(--izi-space-md);
    align-items: stretch;
    flex: 1;
    min-height: 0;
}

/* La COLONNE et ses items n'ont plus de style ici : le balisage porte les
   classes du rail des Options (`features-tabs`, `features-cat-group*`,
   `features-cat-tab`) et l'apparence vient de styles/features-panel.css. Une
   seule source de vérité — redire ces valeurs ici les faisait dériver, et
   c'est ce qui donnait deux écrans de familles différentes.
   Les classes `admin-tabs` / `admin-tab` restent dans le balisage : elles
   servent au JS (switchAdminTab) et aux tests, pas à l'apparence. */

/* Un seul écart assumé avec le rail des Options, et il est FONCTIONNEL : leurs
   items portent un compteur à droite, d'où `justify-content: space-between`. Les
   onglets d'administration n'en ont pas — hérité tel quel, leur libellé était
   renvoyé au bord droit (mesuré), l'icône restant seule à gauche. */
.admin-tabs .admin-tab {
    justify-content: flex-start;
}

.admin-tab-content {
    flex: 1;
    min-width: 0;
    min-height: 0;
    display: flex;
    flex-direction: column;
    gap: var(--izi-space-md);
    overflow-y: auto;
    padding-right: var(--izi-space-sm);
}

/* ===== Vocabulaire des panneaux =====
   Les neuf panneaux portaient leur mise en page EN LIGNE : 56 attributs `style`
   dans le balisage, chacun redisant à sa manière la même intention (une rangée
   d'en-tête, une phrase de description, une liste défilante, un état de
   chargement). Deux de ces valeurs ne pouvaient même pas fonctionner :
   `var(--background)` et `var(--accent)` ne figuraient dans aucune feuille (la
   table d'alias de base.css les a depuis). D'où l'effet de bric-à-brac. Un
   vocabulaire, en tokens. */

/* Rangée d'en-tête d'un panneau : la phrase à gauche, l'action à droite. */
.admin-panel-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--izi-space-md);
    margin-bottom: var(--izi-space-md);
}

/* Phrase qui dit ce que fait le panneau. */
.admin-panel-desc {
    color: var(--izi-text-secondary);
    font-size: var(--izi-font-size-sm);
    margin: 0;
}

/* Sous-titre à l'intérieur d'un panneau (« Invitations en attente »). */
.admin-panel-subhead {
    margin: var(--izi-space-lg) 0 var(--izi-space-sm);
    font-size: var(--izi-font-size-base);
    font-weight: 600;
}

/* Une description posée directement dans le panneau annonce ce qui suit. */
.admin-panel > .admin-panel-desc {
    margin-bottom: var(--izi-space-md);
}

/* Bloc de formulaire séparé de ce qui suit. Le rythme interne vient du `gap` :
   les trois marges écrites en ligne (`margin-bottom` sur la description, sur la
   rangée, `margin-top` sur le sélecteur de groupes) disaient la même chose trois
   fois, avec trois valeurs différentes. */
.admin-panel-block {
    display: flex;
    flex-direction: column;
    gap: var(--izi-space-md);
    margin-bottom: var(--izi-space-xl);
}

/* Le sélecteur de groupes de l'invitation est vide tant qu'aucun groupe n'existe
   — sans ceci le `gap` réserve un intervalle pour rien. */
.admin-panel-block > *:empty {
    display: none;
}

/* Rangée de champ + bouton. */
.admin-form-row {
    display: flex;
    gap: var(--izi-space-sm);
    align-items: center;
}

.admin-form-row .form-input {
    flex: 1;
    min-width: 0;
}

/* Liste d'un panneau. AUCUNE hauteur maximale ici : le conteneur d'onglets
   défile déjà (`.admin-tab-content`), et les quatre plafonds écrits en ligne —
   400, 400, 350, 300 px — donnaient quatre barres de défilement imbriquées à des
   hauteurs décidées au cas par cas. */
.admin-panel-list {
    min-width: 0;
}

/* État de chargement / vide, écrit quatorze fois en ligne à l'identique ; l'état
   d'erreur l'était sept fois de plus, à la seule couleur près. */
.admin-loading,
.admin-empty,
.admin-error {
    text-align: center;
    padding: var(--izi-space-2xl, 2rem);
    margin: 0;
}

.admin-loading,
.admin-empty {
    color: var(--izi-text-secondary);
}

.admin-error {
    color: var(--izi-error);
}

/* ===== Rangées d'une liste =====
   Administrateurs, invitations, groupes, membres, sous-groupes : cinq listes qui
   dessinaient la même rangée, chacune avec ses propres valeurs en ligne (padding
   0,75rem ici, 0,75rem 1rem là, filet du bas d'un côté, fond arrondi de l'autre).
   Une seule rangée, un seul rythme. */
.admin-rows {
    display: flex;
    flex-direction: column;
    gap: var(--izi-space-sm);
}

.admin-row {
    display: flex;
    align-items: center;
    gap: var(--izi-space-md);
    padding: var(--izi-space-sm) var(--izi-space-md);
    background: var(--izi-bg-tertiary);
    border-radius: var(--izi-radius-md, 6px);
}

.admin-row-main {
    flex: 1;
    min-width: 0;
}

.admin-row-title {
    font-weight: 600;
    display: flex;
    align-items: center;
    gap: var(--izi-space-sm);
}

.admin-row-sub {
    color: var(--izi-text-secondary);
    font-size: var(--izi-font-size-xs);
}

.admin-row-actions {
    display: flex;
    gap: var(--izi-space-xs);
    flex: 0 0 auto;
}

/* Initiale d'un membre. Le fond venait d'un `var(--accent)` sans déclaration
   pour les membres, d'un orange en dur pour les responsables : la pastille de
   l'un était transparente, celle de l'autre hors palette. Même famille de
   teintes que les pastilles de rôle (`.badge-admin`) : fond teinté, encre
   saturée — lisible dans les deux thèmes. */
.admin-row-avatar {
    flex: 0 0 auto;
    width: 2rem;
    height: 2rem;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: var(--izi-font-size-xs);
    font-weight: 600;
    background: var(--izi-primary-bg);
    color: var(--izi-primary);
}

.admin-row-avatar--lead {
    background: color-mix(in srgb, var(--izi-warning) 18%, transparent);
    color: var(--izi-warning);
}

/* Étoile du responsable, hors pastille (légendes, listes de groupes). */
.admin-star {
    color: var(--izi-warning);
}

/* Légende d'une liste : ce que veulent dire l'étoile et le cercle. */
.admin-legend {
    display: flex;
    flex-wrap: wrap;
    gap: var(--izi-space-lg);
    align-items: center;
    padding: var(--izi-space-sm) var(--izi-space-md);
    margin-bottom: var(--izi-space-md);
    background: var(--izi-bg-tertiary);
    border-radius: var(--izi-radius-md, 6px);
    color: var(--izi-text-secondary);
    font-size: var(--izi-font-size-xs);
}

/* Bloc d'ajout en pied de liste, séparé par un filet. */
.admin-add-block {
    margin-top: var(--izi-space-lg);
    padding-top: var(--izi-space-lg);
    border-top: 1px solid var(--izi-border);
}

.admin-add-label {
    display: block;
    margin-bottom: var(--izi-space-sm);
    font-size: var(--izi-font-size-sm);
    font-weight: 500;
}

/* Case à cocher d'une liste de sélection (groupes d'un utilisateur). */
.admin-check-row {
    display: flex;
    align-items: center;
    gap: var(--izi-space-md);
    padding: var(--izi-space-sm) var(--izi-space-md);
    border-radius: var(--izi-radius-md, 6px);
    cursor: pointer;
}

.admin-check-row:hover {
    background: var(--izi-bg-hover);
}

.admin-check-row input[type="checkbox"] {
    flex: 0 0 auto;
    accent-color: var(--izi-primary);
}

/* Puces cochables posées en ligne (groupes proposés à l'invitation). */
.admin-chip-choices {
    display: flex;
    flex-wrap: wrap;
    gap: var(--izi-space-sm);
    margin-top: var(--izi-space-sm);
}

.admin-chip-choice {
    display: inline-flex;
    align-items: center;
    gap: var(--izi-space-xs);
    padding: var(--izi-space-xs) var(--izi-space-sm);
    border: 1px solid var(--izi-border);
    border-radius: var(--izi-radius-md, 6px);
    background: var(--izi-bg);
    font-size: var(--izi-font-size-sm);
    cursor: pointer;
}

.admin-chip-choice:hover {
    border-color: var(--izi-primary);
}

/* Choix exclusif présenté en carte (backend de stockage) : même dessin que les
   cartes de la démo de stockage, mais en tokens. */
.admin-choice {
    display: flex;
    gap: var(--izi-space-md);
    padding: var(--izi-space-md);
    border: 1px solid var(--izi-border);
    border-radius: var(--izi-radius-md, 6px);
    cursor: pointer;
}

.admin-choice:hover {
    border-color: var(--izi-primary);
}

.admin-choice input[type="radio"] {
    margin-top: 0.2rem;
    accent-color: var(--izi-primary);
    flex: 0 0 auto;
}

.admin-choice-desc {
    color: var(--izi-text-secondary);
    font-size: var(--izi-font-size-sm);
}

.admin-choices {
    display: flex;
    flex-direction: column;
    gap: var(--izi-space-md);
}

/* Le catalogue des moteurs : UNE LIGNE par moteur.
 *
 * Le nom à gauche, l'état et le chemin à droite, alignés sur la même ligne de
 * base — la place est là, et empiler les deux doublait la hauteur de chaque
 * entrée pour rien : seize moteurs, seize lignes de trop, et la liste ne tenait
 * plus dans le panneau sans défiler.
 *
 * Aucune des deux polices ne change : c'est l'alignement qui fait le travail,
 * pas une mise en avant.
 *
 * Portée à cette liste (`izi-db-liste`) : le panneau des pièces jointes emploie
 * les mêmes `.admin-choice` avec un bouton radio et une description sur
 * plusieurs lignes, où l'empilement est le bon choix. */
.izi-db-liste .admin-choice {
    align-items: baseline;
    justify-content: space-between;
    gap: var(--izi-space-lg);
}

/* Le chemin ne se coupe pas en deux ; c'est le nom qui cède s'il le faut. */
.izi-db-liste .admin-choice-desc {
    flex: 0 1 auto;
    text-align: right;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.izi-db-liste .admin-choice > strong {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Un moteur absent d'`izibuddy.ini` reste lisible mais ne se propose pas. */
.izi-db-liste .admin-choice.is-disabled {
    cursor: default;
    opacity: 0.55;
}

.izi-db-liste .admin-choice.is-disabled:hover {
    border-color: var(--izi-border);
}

.izi-db-liste .admin-choice.is-current {
    border-color: var(--izi-primary);
}

/* Avertissement d'un panneau (migration non automatique, admin seul…). */
.admin-note-warning {
    color: var(--izi-warning, #d97706);
    font-size: var(--izi-font-size-sm);
    margin-top: var(--izi-space-md);
}

/* ===== Chiffres du tableau de bord =====
   Quatre cartes qui répétaient chacune la même mise en page en ligne, avec une
   valeur en `var(--accent)` (jamais déclaré, donc couleur héritée) et trois
   couleurs en dur (#10B981, #8B5CF6, #F59E0B) hors palette. */
.admin-stats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
    gap: var(--izi-space-md);
    margin-bottom: var(--izi-space-lg);
}

.admin-stat {
    padding: var(--izi-space-md);
    background: var(--izi-bg-tertiary);
    border-radius: var(--izi-radius-md, 6px);
    text-align: center;
}

.admin-stat-value {
    font-size: var(--izi-font-size-xl);
    font-weight: 700;
    color: var(--izi-primary);
}

.admin-stat-value--success { color: var(--izi-success); }
.admin-stat-value--info { color: var(--izi-info); }
.admin-stat-value--warning { color: var(--izi-warning); }
.admin-stat-value--error { color: var(--izi-error); }
.admin-stat-value--muted { color: var(--izi-text-secondary); }

.admin-stat-label {
    color: var(--izi-text-secondary);
    font-size: var(--izi-font-size-xs);
    margin-top: var(--izi-space-xs);
}

/* Rangée d'actions secondaires (exports, statistiques). */
.admin-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--izi-space-sm);
}

.admin-toolbar-label {
    color: var(--izi-text-secondary);
    font-size: var(--izi-font-size-sm);
}

/* ===== Alertes =====
   Le filet de gauche portait la sévérité par une couleur calculée en JS
   (#DC2626 / #F59E0B / #3B82F6 / #6B7280) : hors palette, et invisible pour le
   thème. La sévérité est désormais une classe, la couleur un token. */
.admin-alert {
    display: flex;
    align-items: flex-start;
    gap: var(--izi-space-md);
    padding: var(--izi-space-md);
    background: var(--izi-bg-tertiary);
    border-radius: var(--izi-radius-md, 6px);
    border-left: 3px solid var(--izi-text-muted);
}

.admin-alert--critical { border-left-color: var(--izi-error); }
.admin-alert--warning { border-left-color: var(--izi-warning); }
.admin-alert--info { border-left-color: var(--izi-info); }

.admin-alert-icon {
    flex: 0 0 auto;
    font-size: var(--izi-font-size-lg);
}

/* ===== Table de l'administration =====
   Elle portait sa mise en page EN LIGNE, attribut par attribut (largeur,
   bordures, padding, alignements), et ses couleurs en dur. Résultat mesuré : un
   `var(--background)` absent de toute feuille — donc des puces de
   groupes sans fond — et une pastille de rôle crème sur fond sombre. La mise en
   page vit ici, en tokens, comme celle des autres tables de l'application. */
.admin-table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--izi-font-size-base);
}

.admin-table th {
    text-align: left;
    padding: var(--izi-space-sm) var(--izi-space-md);
    font-weight: 600;
    color: var(--izi-text-secondary);
    border-bottom: 1px solid var(--izi-border-strong);
    white-space: nowrap;
}

.admin-table td {
    padding: var(--izi-space-sm) var(--izi-space-md);
    border-bottom: 1px solid var(--izi-border);
    vertical-align: middle;
}

.admin-table tbody tr:last-child td {
    border-bottom: none;
}

.admin-table tbody tr:hover {
    background: var(--izi-bg-hover, rgba(255, 255, 255, 0.03));
}

/* Colonnes serrées : l'état et les actions ne se laissent pas replier. */
.admin-table .admin-col-tight {
    width: 1%;
    white-space: nowrap;
}

.admin-table .admin-col-actions {
    width: 1%;
    white-space: nowrap;
    text-align: right;
}

.admin-table .admin-col-actions .btn + .btn {
    margin-left: var(--izi-space-xs);
}

/* Nom de l'utilisateur courant : signalé par le poids, pas par une couleur. */
.admin-table .admin-cell-self {
    font-weight: 600;
}

.admin-table .admin-cell-note {
    color: var(--izi-text-secondary);
    font-size: var(--izi-font-size-xs);
}

/* ===== Rangée dépliante =====
   Chaque utilisateur occupait DEUX lignes, parce que la colonne des groupes
   empilait ses puces — 74 px de haut par rangée, mesuré, pour un nom, un statut
   et une action qui tiennent sur 37. Les groupes descendent dans un dépliant. */
.admin-disclose {
    display: flex;
    align-items: center;
    gap: var(--izi-space-sm);
    width: 100%;
    padding: 0;
    border: 0;
    background: none;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
}

/* Nom sans groupe : même alignement, mais rien à ouvrir. */
.admin-disclose--flat {
    cursor: default;
}

.admin-disclose-caret {
    flex: 0 0 auto;
    width: 1em;
    color: var(--izi-text-secondary);
    transition: transform var(--izi-transition-base, 0.15s);
}

.admin-disclose[aria-expanded="true"] .admin-disclose-caret {
    transform: rotate(90deg);
}

.admin-disclose:hover .admin-disclose-caret {
    color: var(--izi-primary);
}

/* Nombre de groupes : ce que la rangée repliée ne dirait pas sans lui. */
.admin-disclose-count {
    flex: 0 0 auto;
    min-width: 1.25em;
    padding: 0 var(--izi-space-xs);
    border-radius: 999px;
    background: var(--izi-bg-tertiary);
    color: var(--izi-text-secondary);
    font-size: var(--izi-font-size-xs);
    text-align: center;
}

/* Rangée d'un groupe : décalée sous son utilisateur, et sans filet — le paquet
   « utilisateur + ses groupes » se lit comme un bloc, pas comme des voisins. */
.admin-grow > td {
    border-bottom: none;
    padding-top: 2px;
    padding-bottom: 2px;
}

.admin-grow > td:first-child {
    padding-left: calc(var(--izi-space-md) + 1em + var(--izi-space-sm));
}

.admin-grow-name {
    display: inline-flex;
    align-items: baseline;
    gap: var(--izi-space-sm);
}

/* Le dépliant appartient à la rangée du dessus : pas de filet entre les deux. */
.admin-table .admin-urow:has(+ .admin-grow:not([hidden])) > td {
    border-bottom: none;
}

/* Le filet se referme sous la DERNIÈRE rangée de groupe du paquet. */
.admin-table .admin-grow:not([hidden]):not(:has(+ .admin-grow:not([hidden]))) > td {
    border-bottom: 1px solid var(--izi-border);
}

/* La pastille de statut EST la commande de rôle ; celle d'un groupe est une
   porte vers la gestion de ce groupe. Même dessin, deux intentions — seule la
   première porte un chevron, parce que seule elle ouvre un menu. */
.admin-role-btn,
.admin-group-btn {
    border: 1px solid transparent;
    cursor: pointer;
    font-family: inherit;
}

.admin-role-btn:hover,
.admin-group-btn:hover {
    border-color: currentColor;
}

.admin-role-caret {
    margin-left: 2px;
    opacity: 0.7;
}

/* Puce de groupe : le fond venait d'un `var(--background)` sans déclaration. */
.admin-chip {
    display: inline-block;
    padding: 2px var(--izi-space-sm);
    margin-right: var(--izi-space-xs);
    border-radius: 4px;
    background: var(--izi-bg-tertiary);
    color: var(--izi-text);
    font-size: var(--izi-font-size-xs);
    white-space: nowrap;
}

/* On narrow viewports collapse to the vertical-then-vertical
   stacking the old layout had, so a phone or split-pane still
   shows the full panel. */
@media (max-width: 720px) {
    .admin-layout {
        flex-direction: column;
    }
    .admin-tabs {
        flex: 0 0 auto;
        flex-direction: row;
        flex-wrap: wrap;
        align-self: stretch;
    }
    /* En bande, les groupes se posent côte à côte et perdent leur filet de
       séparation horizontal, qui ne sépare plus rien dans ce sens. */
    .admin-tabs .features-cat-group {
        flex: 1 1 160px;
    }
    .admin-tabs .features-cat-group + .features-cat-group {
        margin-top: 0;
        padding-top: 0;
        border-top: none;
    }
}
