/* Layout Tabler + charte revisee (voir docs/tabler-migration-roadmap.md) */

/* Checkbox du menu "Colonnes visibles" (initTabulatorColumnVisibilityButton) :
   .form-check-input non coche a une bordure a seulement 10% d'opacite (choix
   Tabler assume pour un simple champ de formulaire pose sur un fond neutre),
   quasi invisible sur le fond blanc d'un menu deroulant dense ou plusieurs
   cases doivent rester rapidement repérables. Un premier essai a 35%
   d'opacite restait insuffisant (case decochee toujours a peine visible) -
   bordure grise pleine (non transparente) + leger fond gris dans ce contexte
   precis uniquement, pour que le contour de la case reste visible quel que
   soit son etat coche/decoche. */
.dropdown-menu .form-check-input {
    border-color: #6c757d;
    background-color: #f1f3f5;
}

.dropdown-menu .form-check-input:checked {
    background-color: var(--tblr-primary);
}

/* Grilles calendrier Tabulator (une colonne par jour - Calendrier de suivi
   d'activites, suivi du temps des prestations) : le fond .tabulator-cell
   a un white-space:nowrap par defaut qui force la colonne a s'elargir des
   qu'un contenu depasse la largeur de l'en-tete (ex. "CP 2026 - 2027" bien
   plus long que "NS"/"week-end"). On autorise le retour a la ligne sur les
   espaces pour que la colonne reste calee sur la largeur de son en-tete
   (fixee par minWidth/maxWidth cote JS) plutot que de s'etirer. */
/* body en prefixe : tabulator_bootstrap5.min.css (.tabulator-row .tabulator-cell,
   meme specificite que la regle ci-dessous) charge apres leonis-theme.css via
   @RenderSection("styles"), et gagne donc a specificite egale sans ce point
   supplementaire. */
body .tabulator-cell.day,
body .tabulator-cell.ts,
body .tabulator-cell.tm {
    white-space: normal;
    word-break: break-word;
}

/* Colonnes de totaux du calendrier de suivi d'activites (TS = total semaine,
   TM/TMC = total mois) : fond colore repris de la reference dev.leonis-systemes.net
   (jaune pour TS, rouge-orange pour TM et TMC qui partagent la classe .tm). La
   regle historique ciblait td.ts/th.ts (DataTables) ; Tabulator rend des <div>
   .tabulator-cell / .tabulator-col, d'ou la perte du fond a la migration. Pose
   sur en-tetes ET cellules, en !important pour survivre au fond de survol des
   lignes (ces colonnes gardent leur couleur au survol, comme sur la reference -
   cf. l'exclusion :not(.ts):not(.tm) dans la regle de survol plus bas). */
body .tabulator-col.ts,
body .tabulator-cell.ts {
    background-color: #FFC300 !important;
    color: #212529;
    text-align: center;
}

body .tabulator-col.tm,
body .tabulator-cell.tm {
    background-color: #FF5733 !important;
    color: #212529;
    text-align: center;
}

/* Menu "Colonnes visibles" (initTabulatorColumnVisibilityButton) : au-dela de
   8/16 colonnes titrees, le JS active une grille CSS sur ce conteneur pour
   repartir les cases a cocher sur plusieurs colonnes plutot que de laisser la
   liste s'etirer verticalement (grid plutot que column-count : ce dernier
   fragmente ses enfants sur plusieurs boites internes, ce qui faisait perdre
   le fond blanc herite du .dropdown-menu parent sur la premiere "colonne"
   dans certains navigateurs - le tableau en arriere-plan redevenait visible
   par transparence). Fond explicite conserve en filet de securite. */
.tabulator-colvis-columns {
    gap: 0.125rem 0.5rem;
    /* Le fond blanc pose sur chaque case (juste en dessous) ne couvre pas
       l'espacement entre les cases (gap) : ce fin espace laissait donc
       passer la couleur d'arriere-plan du tableau par transparence, visible
       comme un mince filet colore entre deux lignes du menu. Fond pose ici
       aussi pour couvrir integralement la zone, gap compris. */
    background-color: var(--tblr-dropdown-bg, #fff);
    /* Persistant malgre un fond entierement opaque partout (verifie via
       elementsFromPoint - aucune transparence reelle) : le menu est en
       position:fixed (necessaire pour echapper au decoupage/recouvrement
       par les lignes du tableau, cf. plus bas) et compose donc dans son
       propre calque GPU, dont le bord tombe sur une frontiere de pixel
       physique fractionnaire sous un devicePixelRatio non entier (125% sous
       Windows) - l'anti-crenelage du bord de calque laisse alors passer un
       fin filet de la couleur juste derriere. box-shadow non flou, dans la
       meme couleur que le fond, deborde volontairement de 2px pour masquer
       ce filet plutot que de compter sur la seule limite de la boite. */
    box-shadow: 0 0 0 2px var(--tblr-dropdown-bg, #fff);
}

.tabulator-colvis-item {
    background-color: var(--tblr-dropdown-bg, #fff);
}

.tabulator-colvis-item .dropdown-item {
    background-color: var(--tblr-dropdown-bg, #fff);
    align-items: center;
    gap: 0.5rem;
}

/* Le label combine .dropdown-item et .form-check : Tabler applique alors le
   margin-left:-2rem de .form-check-input, tandis que le padding gauche de
   .form-check est remplace par celui de .dropdown-item. La case sortait donc
   de la boite du menu. Dans ce menu flex dedie, on remet la case dans le flux. */
.tabulator-colvis-item .form-check-input {
    float: none;
    flex-shrink: 0;
    margin-left: 0;
}

/* Espace juste sous la barre d'onglets/le titre d'une card (padding-top par
   defaut de Tabler, --tblr-card-spacer-y) reduit : trop de vide entre le
   haut de la card et son premier champ. Cible uniquement le haut - le reste
   du padding (bas/cotes) reste inchange. */
.card-body {
    padding-top: 0.5rem;
}

/* Labels de filtre (ex. "Tâches actives:", "Tâches en attente d'execution:")
   places devant un groupe de boutons radio dans un formulaire flex
   (form.d-flex, pas .row) : col-sm-4 leur donne 33% de la largeur du
   formulaire parent, suffisant pour les libelles courts mais pas pour les
   plus longs, qui passent sur 2 lignes - la hauteur de chaque rangee devient
   incoherente d'un filtre a l'autre et les groupes de boutons radio ne
   demarrent plus a la meme position visuelle. Largeur fixe, suffisante pour
   le plus long des libelles utilises, sur une seule ligne. Motif partage sur
   plusieurs vues (CoreCronTasks, ApplicationUsers, Prestations...), corrige
   ici globalement plutot que vue par vue. */
form.d-flex > label.col-sm-4 {
    flex: 0 0 230px;
    max-width: none;
    white-space: nowrap;
}

/* section.content-header (titre de page) n'a pas de conteneur, alors que
   section.content enveloppe systematiquement son contenu dans .container-fluid
   (gouttiere Bootstrap 5 de 2rem, soit ~13px de padding de chaque cote) - les
   cards se retrouvaient donc inserees de 13px par rapport au titre au-dessus,
   contrairement a dev.leonis-systemes.net ou les deux sont alignes (verifie :
   2px d'ecart la-bas contre 13px ici). Meme formule que le padding de
   .container-fluid pour rester synchronise si la gouttiere change. */
.content-header {
    padding-left: calc(var(--tblr-gutter-x, 2rem) * 0.5);
    padding-right: calc(var(--tblr-gutter-x, 2rem) * 0.5);
}

/* Tabler met .form-label/.form-control/.form-select/.form-check-label a
   0.875rem par defaut (soit ~11.4px avec notre racine a 13px), alors que le
   reste de l'interface (en-tetes de tableau, menu, corps de page) reste a
   1rem plein - contrairement a dev.leonis-systemes.net ou TOUT le texte
   (formulaires compris) partage la meme taille reduite (0.875rem appliquee
   uniformement sur le body). Plutot que de retoucher tout le corps de page
   au risque de re-casser des tailles deja calibrees ailleurs dans cette
   migration, on aligne les formulaires vers le haut (1rem) pour retrouver
   la coherence visuelle avec le reste de la page. */
.form-label,
.form-control,
.form-select,
.form-check-label {
    font-size: 1rem;
}

/* Nos vues ecrivent la case a cocher comme <label class="form-check"> englobant
   l'input et le libelle : le label etant un bloc, sa boite - donc sa zone de
   clic - occupe toute la largeur du conteneur et un clic tres loin du libelle
   basculait la case. On ramene la boite a la largeur de son contenu tout en
   restant un bloc (une case par ligne, comme aujourd'hui). Les cases des menus
   deroulants (colonnes Tabulator) doivent rester pleine largeur : c'est la
   ligne de menu entiere qui est cliquable par convention. */
label.form-check:not(.dropdown-item) {
    width: fit-content;
    max-width: 100%;
}

/* .form-group (Bootstrap 4) a ete retire de Bootstrap 5 sans remplacement -
   la classe reste presente sur ~150 vues (jamais nettoyee pendant la
   migration) mais n'a plus aucun effet visuel, alors qu'elle apportait
   margin-bottom:1rem par defaut en Bootstrap 4/AdminLTE. Plutot que de
   retirer la classe (ou la remplacer) sur des dizaines de fichiers, on lui
   redonne exactement son comportement d'origine ici : les champs qui en
   dependaient encore pour leur espacement retrouvent leur marge sans
   qu'aucune vue n'ait besoin d'etre modifiee. */
.form-group {
    margin-bottom: 1rem;
}

/* .form-inline (Bootstrap 4) a egalement ete retire sans remplacement (7 vues,
   barres de filtres "Label: [choix]") - le <form> repassait en display:block
   par defaut, empilant le label au-dessus du groupe de contrôles au lieu de
   les afficher cote a cote. Meme traitement que .form-group ci-dessus :
   on redonne son comportement flex d'origine plutot que de toucher aux vues. */
/* Bootstrap 4 donnait aussi a .form-group IMBRIQUE dans .form-inline un
   display:flex (regle `.form-inline .form-group`) - sans equivalent, un
   groupe de radios/checkbox cote a cote ("Actives / Inactives / Tous")
   empile dans un .form-group a l'interieur du form-inline retombe en
   display:block, empilant chaque .input-group (un par bouton radio) au lieu
   de les afficher en ligne. Cible precisement ce motif (.form-group avec
   plusieurs .input-group directs) plutot que tous les .form-group, pour ne
   pas affecter les cas a un seul champ. */
.form-group:has(> .input-group + .input-group) {
    display: flex;
    flex-flow: row wrap;
    align-items: center;
    gap: 0.25rem 1rem;
    /* .form-group a par ailleurs une regle globale margin-bottom:1rem (pour
       les cas empiles verticalement) - ici, en marge asymetrique (0 en haut,
       1rem en bas) sur un flex-item dont la ligne est partagee avec le label
       du champ, elle fausse le centrage vertical : align-items:center centre
       la boite de MARGE, pas juste le contenu, donc ce .form-group se
       retrouvait visuellement plus haut que le label a cote de lui. */
    margin-bottom: 0;
}

.form-group:has(> .input-group + .input-group) > .input-group {
    /* Chaque .input-group (un par bouton radio) doit garder sa largeur de
       contenu naturelle - sans ceci ils se partagent la largeur totale a
       parts egales (flex-grow herite) et retombent chacun sur sa propre
       ligne des que leur largeur ainsi gonflee ne tient plus 3 par ligne. */
    flex: 0 0 auto;
    width: auto;
}

.form-inline {
    display: flex;
    flex-flow: row wrap;
    align-items: center;
}

/* Motif "form-horizontal" (~200 vues) : une serie de <div class="input-group">
   consecutifs, un par champ, jamais enveloppes dans .form-group/.row - or
   .form-group (qui apportait margin-bottom:1rem en Bootstrap 4/AdminLTE) a
   ete retire de Bootstrap 5, et .input-group seul n'a aucune marge par
   defaut. Resultat : les champs se touchent (0px d'ecart), et la bordure du
   bas de chaque .form-control/.input-group-text vient se coller a la
   bordure du haut du champ suivant, donnant l'impression d'un cadre/filet
   horizontal indesirable entre chaque ligne. */
.form-horizontal > .input-group {
    margin-bottom: 0.75rem;
    /* .input-group est display:flex + align-items:stretch (defaut Bootstrap) :
       le label et le wrapper de controle etirent tous deux a la hauteur de la
       ligne, mais leur propre contenu (texte du label, champ) reste ancre en
       haut de leur boite etiree - visuellement le label "flotte" en haut du
       champ au lieu d'etre centre a cote de lui. Centre les deux au lieu de
       les etirer. */
    align-items: center;
}

/* Tabler applique box-shadow:var(--tblr-box-shadow-input) directement a
   .input-group (pas seulement aux champs qu'il contient), sur toute la
   largeur de la ligne - visible comme un trait fin sous chaque champ ou
   groupe de boutons radio empile (form-horizontal, mais aussi les groupes
   de radios "Actives/Inactives/Tous" dans un .form-group imbrique dans
   .form-inline - deux motifs de markup differents, meme classe .input-group
   en cause). Regle volontairement globale (pas de selecteur de contexte
   parent) pour couvrir tous les motifs plutot que de les traiter au cas par
   cas. Absent de dev.leonis-systemes.net. */
.input-group {
    box-shadow: none;
}

/* Message "Chargement..." affiche par Tabulator pendant une requete ajax
   (tabulator_bootstrap5.min.css : .tabulator-alert-msg.tabulator-alert-state-msg)
   n'a plus l'icone animee que l'ancien indicateur DataTables/AdminLTE
   affichait, uniquement le texte en noir. Remis une roue animee en CSS pur
   (pas de dependance a une image/police d'icone particuliere) et texte
   repris dans l'orange de la charte. Prefixe "body" + !important necessaires
   (tabulator_bootstrap5.min.css est injectee apres leonis-theme.css, cf.
   note sur l'ordre de @RenderSection("styles") plus haut dans ce fichier). */
body .tabulator-alert .tabulator-alert-msg.tabulator-alert-state-msg {
    color: #f6a523 !important;
    border-color: #f6a523 !important;
    display: flex !important;
    align-items: center;
    gap: 10px;
}

body .tabulator-alert .tabulator-alert-msg.tabulator-alert-state-msg::before {
    content: "";
    width: 20px;
    height: 20px;
    flex-shrink: 0;
    border: 3px solid #f6a523;
    border-right-color: transparent;
    border-radius: 50%;
    animation: leonis-tabulator-spin 0.75s linear infinite;
}

@media (prefers-reduced-motion: reduce) {
    body .tabulator-alert .tabulator-alert-msg.tabulator-alert-state-msg::before {
        animation: none;
    }
}

@keyframes leonis-tabulator-spin {
    to {
        transform: rotate(360deg);
    }
}

/* .control-label (Bootstrap 3/AdminLTE) etait mis en gras par defaut sur ces
   memes ~200 vues form-horizontal ; Bootstrap 5 ne definit pas cette classe
   du tout, le texte retombe donc en graisse normale sans cette regle. */
.control-label {
    font-weight: 700;
}

/* tabulator_bootstrap5.min.css fixe .tabulator en dur a font-size:16px (px,
   pas rem) - largement plus gros que le reste de l'interface. Un premier
   passage l'avait aligne sur 1rem (13px, la taille de base du corps de
   page) mais ca restait visiblement plus gros que le texte des formulaires
   (labels/checkbox a 1rem eux aussi, mais avec moins de padding/interlignage
   autour) - 0.875rem (~11.4px) donne un rendu plus proportionne, plus proche
   de la densite d'information de dev.leonis-systemes.net. Prefixe "body"
   necessaire : meme specificite que la regle .tabulator de
   tabulator_bootstrap5.min.css, mais cette derniere est injectee APRES
   leonis-theme.css (@RenderSection("styles") vient apres ce <link> dans
   _Layout.cshtml) - a specificite egale, le dernier declare l'emporte. */
body .tabulator {
    font-size: 0.875rem;
}

/* .btn-default : classe AdminLTE/Bootstrap 4, retiree de Bootstrap 5/Tabler.
   Utilisee telle quelle dans ~145 vues (barre d'outils Tabulator, boutons
   "Appliquer", navigation de periode...) - sans cette regle, ces boutons
   n'ont ni fond ni bordure et deviennent quasi invisibles. Valeurs reprises
   telles quelles de dev.leonis-systemes.net (adminlte.min.css). */
.btn-default {
    background-color: #f8f9fa;
    border-color: #ddd;
    color: #444;
}

.btn-default:hover {
    background-color: #e9ecef;
    color: #2b2b2b;
}

.btn-default:disabled {
    background-color: #f8f9fa;
    color: #444;
}

/* .btn-filter : classe dediee aux boutons d'action des zones de filtre
   (Appliquer, navigation de periode : precedent / periode courante / suivant).
   Remplace l'usage de .btn-default .btn-sm sur ces boutons pour leur donner une
   semantique propre (comme .tabulator-export-btn pour la barre d'export) et
   restaurer le rendu de l'ancienne version (dev.leonis-systemes.net) : base grise
   neutre, ICONES en orange accent, et hauteur un peu superieure au btn-sm tres
   compact de Tabler. */
.btn.btn-filter {
    background-color: #f8f9fa;
    border-color: #ddd;
    color: #444;
    font-size: 0.875rem;
    padding: 0.25rem 0.5rem;
    line-height: 1.5;
}

.btn.btn-filter:hover {
    background-color: #e9ecef;
    border-color: #ccc;
    color: #2b2b2b;
}

.btn.btn-filter:disabled {
    background-color: #f8f9fa;
    border-color: #ddd;
    color: #444;
}

.btn.btn-filter i {
    color: var(--leonis-accent);
}

/* .btn-sm : Tabler le definit beaucoup plus compact (padding-y 0.0625rem,
   soit moins de 1px) que le .btn-sm Bootstrap 4/AdminLTE d'origine, encore
   utilise tel quel dans ~145 vues (boutons "Appliquer", navigation de
   periode, barres d'outils...). Fond/bordure restent bien presents
   (verifie via getComputedStyle) mais la hauteur du bouton s'ecrase a
   13-17px au lieu d'environ 30px, ne laissant plus voir qu'un liseré de
   couleur autour du texte - illisible comme bouton. Restaure les valeurs
   Bootstrap 4/AdminLTE (dev.leonis-systemes.net), memes principe que
   .btn-default ci-dessus. */
.btn-sm {
    --tblr-btn-padding-y: 0.25rem;
    --tblr-btn-padding-x: 0.5rem;
    --tblr-btn-font-size: 0.875rem;
}

/* Barre d'export Tabulator (copier/Excel/CSV/PDF/imprimer, voir
   initTabulatorExportBar dans tabulator.js) : .btn-sm seul rendait ces
   boutons minuscules (padding ~1px 4px, icone 12px) - beaucoup trop petits
   pour rester confortablement cliquables/visibles. Agrandis via une classe
   dediee pour ne pas affecter les autres usages de .btn-sm (ex. boutons
   "Appliquer" des barres de filtres). Couleur orange de la charte (au lieu
   du gris neutre de dev.leonis-systemes.net) pour rester coherent avec le
   reste des actions de l'interface (boutons "Nouveau", pagination active,
   onglets actifs...), tous dans cette meme teinte. */
.tabulator-export-btn {
    padding: 0.375rem 0.625rem;
}

.tabulator-export-btn .ti {
    font-size: 1.1rem;
}

.tabulator-export-btn,
.tabulator-export-btn:disabled {
    background-color: #f6a523;
    border-color: #f6a523;
    color: #fff;
}

.tabulator-export-btn:hover {
    background-color: #dc9012;
    border-color: #dc9012;
    color: #fff;
}

.tabulator-export-btn {
    border-radius: 0;
    margin-left: -0.8px;
}

.tabulator-export-btn:first-child {
    border-radius: 4px 0 0 4px;
    margin-left: 0;
}

.tabulator-export-btn:last-child,
.tabulator-export-btn:last-of-type {
    /* :last-of-type en plus de :last-child : le bouton "Colonnes visibles"
       (initTabulatorColumnVisibilityButton) ajoute son menu <ul> comme frere
       APRES le dernier .tabulator-export-btn, qui n'est alors plus le dernier
       enfant du conteneur - mais reste le dernier <button>, que :last-of-type
       continue de cibler correctement. */
    border-radius: 0 4px 4px 0;
}

/* Pagination Tabulator, alignement visuel exact sur dev.leonis-systemes.net :
   le theme Bootstrap 5 fourni par tabulator_bootstrap5.min.css donne aux
   boutons de page un fond blanc a 20% d'opacite (pense pour une barre de
   navigation sombre) - sur notre fond de carte blanc, ca les rend quasi
   transparents et difficiles a distinguer d'un texte simple. Fond plein,
   couleurs reprises de la pagination Bootstrap de dev (page active en
   orange plein, texte blanc ; page inactive fond blanc, texte orange). */
.tabulator-page {
    background-color: #fff !important;
    color: #f6a523 !important;
    border-radius: 4px !important;
}

.tabulator-page:not(.disabled):hover {
    background-color: #fdf1de !important;
}

.tabulator-page.active {
    background-color: #f6a523 !important;
    color: #fff !important;
    border-color: #f6a523 !important;
}

.tabulator-page-size {
    background-color: #fff !important;
}

/* Footer/pagination Tabulator : meme fond creme que le corps des cartes de
   filtre (#fdf3e3) au lieu du gris #e6e6e6, pour la coherence graphique. */
.tabulator-footer {
    background-color: #fdf3e3 !important;
}

/* Menu d'actions de ligne ("...") rogne au ras du tableau.
   tabulator_bootstrap5.min.css pose sur .tabulator :
       overflow: hidden; transform: translateZ(0);
   translateZ(0) n'est qu'un indice de compositing GPU (transformation IDENTITE,
   invisible a l'oeil), mais un ancetre transforme devient le BLOC CONTENEUR des
   descendants en position:fixed - et son overflow:hidden les rogne alors comme
   n'importe quel descendant. Consequence : le strategy:"fixed" donne a Popper
   (cf. tabulator.js custom, menu d'actions par ligne) ne sortait plus de la
   boite du tableau, et le menu ouvert sur une ligne basse etait coupe net au
   bas de la table - il paraissait "passer sous le pied de pagination".
   On neutralise la seule transformation identite : le menu redevient positionne
   par rapport a la fenetre, donc entierement visible, tout en RESTANT dans le
   DOM du tableau (indispensable : les vues branchent leurs actions en
   delegation sur le conteneur de la table). Verifie par elementFromPoint sur le
   bas du menu : .leonis-content-wrapper avant, l'entree du menu apres. */
.tabulator {
    transform: none !important;
}

/* Lignes de tableau Tabulator, alignement visuel exact sur dev.leonis-systemes.net :
   la table DataTables de reference n'a aucun fond alterne (lignes blanches
   uniformes) - le theme Bootstrap 5 de Tabulator introduit un liseré gris sur
   une ligne sur deux, absent de la reference et genant en lecture rapide. */
body .tabulator-row.tabulator-row-even {
    background-color: transparent !important;
}

/* Survol : surligner TOUTES les lignes (paires comprises), pas une sur deux.
   L'annulation du fond alterne ci-dessus (transparent !important sur les lignes
   paires) a une specificite superieure au survol natif de Tabulator
   (.tabulator-row.tabulator-selectable:hover) et empechait donc une ligne sur
   deux de reagir au survol. On rehausse la specificite (:hover + prefixe body)
   et on applique la meme teinte a la ligne ; on neutralise le fond de cellule
   natif du survol pour que le surlignage de ligne soit uniforme sur toute la
   largeur (les cellules sont transparentes par defaut, y compris le calendrier
   ou la couleur est portee par le texte). */
/* Teinte orange (accent) au lieu d'un gris : le gris du survol (#dee2e6) etait
   quasi identique au gris des lignes verrouillees .table-secondary (#e2e3e5),
   on ne distinguait plus une ligne survolee d'une ligne verrouillee.
   Selecteur profond (+ body) pour depasser la specificite (0,5,0 !important) de
   `.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.table-secondary`
   de tabulator_bootstrap5.min.css : sans ca, le survol restait invisible sur les
   lignes verrouillees (frequentes sur les tableaux d'entites synchronisees). */
body .tabulator .tabulator-tableholder .tabulator-table .tabulator-row:hover {
    background-color: #f9e4bf !important;
}

body .tabulator-row:hover .tabulator-cell:not(.ts):not(.tm) {
    background-color: transparent !important;
}

/* Icones d'action dans les cellules Tabulator (voir get_method.js) : sans
   taille explicite elles heritent d'un corps de texte devenu plus petit
   (cf. reduction du font-size racine) et paraissent minuscules a cote des
   lignes du tableau. */
.tabulator-cell a > .ti {
    font-size: 1.25rem;
    vertical-align: middle;
}

/* Fleche de tri des en-tetes Tabulator : legerement agrandie pour rester
   lisible a cote du texte d'en-tete. */
.tabulator-col-sorter .tabulator-arrow {
    border-left-width: 7px !important;
    border-right-width: 7px !important;
    border-bottom-width: 7px !important;
    border-top-width: 7px !important;
}

:root {
    --leonis-dark: #523714;
    --leonis-accent: #f6a523;
    --leonis-accent-text: #a3660c;
    --leonis-content-bg: #f4f5f7;
    --leonis-sidebar-width: 230px;
    --leonis-sidebar-width-collapsed: 60px;
    --leonis-topbar-height: 56px;

    /* Recolore la couleur primaire de Tabler (bleu par defaut) vers le brun
       de la charte : couvre checkboxes/radios, focus, et composants natifs
       Tabler non deja surcharges individuellement (ex. .btn-primary). Les
       teintes derivees precompilees par Tabler (primary-lt, primary-darken,
       subtle...) restent bleutees - refonte complete hors scope. */
    --tblr-primary: var(--leonis-dark);
    --tblr-primary-rgb: 82, 55, 20;

    /* Palette semantique (succes/attention/danger/info) alignee sur les valeurs
       Bootstrap 4 encore en usage sur dev.leonis-systemes.net (ticket #724) -
       Tabler utilise par defaut une palette differente (vert/orange/rouge/bleu
       plus dessatures) qu'on remplace ici pour rester coherent avec l'existant. */
    --tblr-success: #28a745;
    --tblr-success-rgb: 40, 167, 69;
    --tblr-success-darken: #218838;
    --tblr-warning: #ffc107;
    --tblr-warning-rgb: 255, 193, 7;
    --tblr-warning-darken: #e0a800;
    /* Fond clair du bouton warning : le texte clair par defaut de Tabler
       (--tblr-warning-fg: var(--tblr-light)) n'est pas assez contraste. */
    --tblr-warning-fg: #1f2d3d;
    --tblr-danger: #dc3545;
    --tblr-danger-rgb: 220, 53, 69;
    --tblr-danger-darken: #c82333;
    --tblr-info: #17a2b8;
    --tblr-info-rgb: 23, 162, 184;
    --tblr-info-darken: #138496;

    /* Liens hypertextes : orange de la charte au lieu du bleu Bootstrap, pour
       s'intégrer à l'UI tout en restant lisibles sur fond clair (survol plus
       foncé pour le contraste). */
    --tblr-link-color: #dc9012;
    --tblr-link-color-rgb: 220, 144, 18;
    --tblr-link-hover-color: #a86a08;
    --tblr-link-hover-color-rgb: 168, 106, 8;
}

/* ==========================================================================
   Alertes (.alert Bootstrap) - bandeau d'information reutilisable dans toutes
   les vues. Le build Tabler laissait .alert quasi sans style ici (fond blanc,
   texte colore, aucune bordure) : trop discret pour attirer l'attention. On
   redonne un fond teinte + bordure + accent lateral epais, par variante
   semantique, a partir des variables de palette deja definies ci-dessus.

   Usage : classes Bootstrap standard - <div class="alert alert-warning">...</div>.
   Pour une icone en tete de message, ajouter les utilitaires flex Bootstrap :
   <div class="alert alert-info d-flex align-items-start gap-2">
       <i class="ti ti-lock"></i><span>...</span>
   </div>
   ========================================================================== */
.alert {
    padding: 0.75rem 1rem;
    margin-bottom: 1rem;
    border: 1px solid transparent;
    border-left-width: 4px;
    border-radius: 4px;
    font-size: 0.95rem;
    font-weight: 500;
    line-height: 1.4;
}

.alert:last-child {
    margin-bottom: 0;
}

/* Icone posee en tete via d-flex : ne pas la laisser retrecir, et l'aligner
   sur la hauteur de la premiere ligne de texte (meme line-height). */
.alert > .ti {
    flex: 0 0 auto;
    font-size: 1.2rem;
    line-height: 1.4;
}

.alert-info {
    color: #0b5563;
    background-color: rgba(var(--tblr-info-rgb), 0.10);
    border-color: var(--tblr-info);
}

.alert-warning {
    color: #6b5200;
    background-color: rgba(var(--tblr-warning-rgb), 0.16);
    border-color: var(--tblr-warning);
}

.alert-success {
    color: #14612a;
    background-color: rgba(var(--tblr-success-rgb), 0.10);
    border-color: var(--tblr-success);
}

.alert-danger {
    color: #86232e;
    background-color: rgba(var(--tblr-danger-rgb), 0.10);
    border-color: var(--tblr-danger);
}

/* Lien a l'interieur d'une alerte : reprend la teinte du message. */
.alert a {
    color: inherit;
    font-weight: 700;
    text-decoration: underline;
}

body.leonis-body {
    background: var(--leonis-content-bg);
}

/* Icone dans un addon d'input-group (ex. bouton "afficher le mot de passe") :
   la taille par defaut de .icon (1.25rem/20px, prevue pour boutons/nav) est
   plus haute que la ligne de texte de l'input (14px/20px de line-height),
   ce qui gonfle la hauteur de l'addon au-dela de celle du champ. */
.input-group-text .icon {
    font-size: 1rem;
    width: 1rem;
    height: 1rem;
}

/* .form-control definit un min-height explicite (formule Tabler) mais pas
   .input-group-text : les <input> (elements de formulaire) ne suivent pas
   toujours align-items:stretch de leur conteneur flex .input-group aussi
   fidelement qu'un <span>, ce qui laissait l'addon plus haut que le champ
   (ex. bouton oeil du mot de passe). Meme formule sur les deux. */
.input-group-text {
    height: calc(1.4285714286em + .875rem + calc(var(--tblr-border-width) * 2)) !important;
}

/* Markup legue de TempusDominus (icone calendrier a gauche des dateranges) :
   .input-group-prepend/.input-group-append n'existent plus dans Bootstrap 5
   et Tabler ne leur applique donc aucun style - en display:block par defaut,
   ce wrapper ne s'aligne pas correctement sur la hauteur du champ voisin.
   Le duo display:flex + align-items:stretch derive la hauteur du wrapper
   via le flex-stretch de .input-group (cross-size = max des hypothetical
   sizes des flex-items) : avec .input-group-text lui-meme force en height:
   100% (base indeterminee tant que le wrapper n'a pas de hauteur propre),
   le calcul reste circulaire et laisse quelques pixels d'ecart avec l'input
   voisin. On applique donc directement la meme formule absolue que
   .form-control/.input-group-text (calibree plus haut) au wrapper ET a
   l'icone qu'il contient, qui ne peut plus deriver. */
.input-group-prepend,
.input-group-append {
    display: flex;
    align-items: center;
    justify-content: center;
    height: calc(1.4285714286em + .875rem + calc(var(--tblr-border-width) * 2)) !important;
}

.input-group-prepend .input-group-text,
.input-group-append .input-group-text {
    height: 100% !important;
    display: flex;
    align-items: center;
}

/* Icone calendrier (ti-calendar) sans classe .icon : sa taille de police par
   defaut (plus grande que le texte du champ) gonflait la hauteur intrinseque
   de .input-group-prepend au-dela de celle de l'input voisin - desormais
   sans effet sur la hauteur du wrapper (fixee ci-dessus), garde par coherence
   visuelle avec l'icone du cote droit (bouton oeil du mot de passe). */
.input-group-prepend .input-group-text i,
.input-group-append .input-group-text i {
    font-size: 1rem;
}

/* Chevron de dropdown Tom Select : le CSS officiel tom-select.bootstrap5.css
   ne dessine ce chevron que si le wrapper n'a PAS la classe form-control/
   form-select (regle `.ts-wrapper:not(.form-control,.form-select)...`) - or
   tout le code applicatif initialise Tom Select avec class="form-control
   tomselect" (voir initTabulatorTable/DropDownListFor un peu partout), ce
   qui supprime silencieusement l'indicateur. On reapplique le meme SVG que
   celui deja fourni par tom-select, sans l'exclusion. */
body .ts-wrapper.form-control.single .ts-control,
body .ts-wrapper.form-control.multi .ts-control {
    /* !important + prefixe "body" necessaires : tom-select.bootstrap5.css
       force `background:transparent!important` sur un selecteur de meme
       specificite de classes (.ts-wrapper.form-control:not(.disabled)
       .ts-control), mais injecte sa feuille de style APRES leonis-theme.css
       (@RenderSection("styles") vient apres ce <link> dans _Layout.cshtml) -
       a specificite egale, le dernier declare l'emporte. Le prefixe element
       "body" ajoute un point de specificite supplementaire pour trancher. */
    background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3E%3C/svg%3E") !important;
    background-position: right .75rem center !important;
    background-repeat: no-repeat !important;
    background-size: 16px 12px !important;
    padding-right: 2.25rem !important;
}

/* Fond de la liste deroulante Tom Select (mono ET multi-select) : le CSS
   officiel tom-select.bootstrap5.css definit `.ts-dropdown { background:
   var(--bs-body-bg); ... }` - une variable Bootstrap 5 standard jamais
   definie ici (l'application utilise les variables Tabler --tblr-*, pas
   --bs-*). Une var() qui reference une variable inexistante et sans valeur
   de repli est invalide : la propriete retombe silencieusement sur sa valeur
   initiale, transparent pour background-color. Le contenu de la page
   (en-tetes de tableau, texte...) apparaissait donc par transparence sous
   la liste d'options, genant la lecture. Repli explicite en blanc. */
.ts-dropdown {
    background-color: #fff !important;
}

/* Checkbox brutes dans les colonnes booleennes Tabulator (formatters
   applicatifs qui generent un <input type="checkbox"> sans classe) : on
   reproduit le style .form-check-input de Tabler pour matcher visuellement
   les checkbox des formulaires, sans devoir modifier chaque formatter JS. */
.tabulator input[type="checkbox"] {
    display: block;
    flex-shrink: 0;
    width: 1.25rem;
    height: 1.25rem;
    margin: 0 auto;
    vertical-align: top;
    appearance: none;
    -webkit-appearance: none;
    background-color: var(--tblr-bg-forms, #fff);
    background-repeat: no-repeat;
    background-position: center;
    background-size: contain;
    border: var(--tblr-border-width, 1px) solid var(--tblr-border-color-translucent, rgba(0, 0, 0, .15));
    border-radius: var(--tblr-border-radius, 4px);
    cursor: default;
    pointer-events: none;
}

.tabulator input[type="checkbox"]:checked {
    background-color: var(--tblr-primary);
    border-color: transparent;
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' width='16' height='16'%3e%3cpath fill='none' stroke='%23ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8.5l2.5 2.5l5.5 -5.5'/%3e%3c/svg%3e");
}

.tabulator input[type="checkbox"]:disabled {
    opacity: .65;
}

/* Popup du menu utilisateur (_LoginPartial.cshtml) : l'ancien markup AdminLTE
   (.user-header/.user-footer/.bg-gradient-dark, retires de Bootstrap 5) ne
   beneficiait plus d'aucun style, d'ou un rendu tasse/non centre. Reproduit
   la mise en page de dev.leonis-systemes.net (avatar centre, nom/email
   centres, boutons cote a cote en pied de popup). */
.leonis-user-dropdown {
    min-width: 260px;
    padding-top: 1rem;
}

.leonis-user-dropdown-header {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    padding: 0 1rem 1rem;
    gap: .25rem;
}

.leonis-user-dropdown-header .avatar-lg {
    width: 4.5rem;
    height: 4.5rem;
    margin-bottom: .5rem;
}

.leonis-user-dropdown-footer {
    display: flex;
    justify-content: center;
    gap: .5rem;
    padding: .75rem 1rem 0;
}

.leonis-preloader {
    position: fixed;
    inset: 0;
    z-index: 2000;
    background: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: 1;
    transition: opacity 0.3s ease-out;
}

.leonis-preloader.leonis-preloader-hidden {
    opacity: 0;
    pointer-events: none;
}

.leonis-shell {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    /* Même raison que pour .leonis-sidebar : « vh » vaut le viewport barre d'URL masquée sur
       Chrome Android (751 mesuré contre 694 visibles), ce qui étirait la coque au-delà de
       l'écran. Repli conservé sur la ligne précédente. */
    min-height: 100dvh;
}

.leonis-body-row {
    display: flex;
    flex: 1;
}

/* Bandeau du haut */
/* ⚠️ L'élément porte AUSSI la classe Bootstrap/Tabler « .navbar », qui impose
   « flex-wrap: wrap ». Comme la barre a une hauteur FIXE, le moindre dépassement de largeur
   faisait basculer le groupe d'icônes sur une SECONDE ligne, qui sortait du bandeau et
   recouvrait le haut de la page — constaté sur mobile en ajoutant une 7e icône.
   On force donc le non-retour à la ligne, et on autorise le bloc de gauche à se comprimer
   (min-width: 0, sans quoi un enfant flex refuse de descendre sous sa taille de contenu). */
.leonis-topbar {
    background: var(--leonis-dark);
    height: var(--leonis-topbar-height);
    display: flex;
    flex-wrap: nowrap;
    align-items: center;
    justify-content: space-between;
    padding: 0 1rem;
    position: sticky;
    top: 0;
    z-index: 1030;
}

.leonis-topbar-left {
    display: flex;
    align-items: center;
    gap: 14px;
    min-width: 0;
}

.leonis-topbar-right {
    flex-wrap: nowrap;
}

/* Largeur confortable du champ de recherche sur écran large. Portée par la classe et non par
   un style inline, pour que l'état déplié sur mobile puisse passer outre. */
.leonis-search-form {
    min-width: 18rem;
}

/* Sur un écran étroit, la place se gagne sur ce qui n'y sert pas. */
@media (max-width: 767.98px) {
    /* --- Recherche dépliée par la loupe ---
       Le champ vient couvrir toute la barre : à cette largeur, le partager avec sept icônes
       le rendrait inutilisable. Les icônes et la marque sont donc masquées le temps de la
       saisie (visibility plutôt que display : la barre garde sa géométrie, rien ne saute). */
    body.leonis-search-open .leonis-search-form {
        display: flex !important;   /* prend le pas sur d-none */
        position: absolute;
        left: .5rem;
        right: .5rem;
        min-width: 0;
        margin: 0;
        z-index: 2;
    }

    body.leonis-search-open .leonis-search-form .input-icon {
        width: 100%;
    }

    body.leonis-search-open .leonis-topbar-left,
    body.leonis-search-open .leonis-topbar-right > li:not(.leonis-search-item) {
        visibility: hidden;
    }

    /* Le plein écran n'a aucun sens sur un téléphone : le navigateur y est déjà plein écran. */
    #leonisFullscreenToggle {
        display: none;
    }

    .leonis-topbar {
        padding: 0 .5rem;
    }

    .leonis-topbar-right {
        gap: 0;
    }

    .leonis-topbar-right .nav-link {
        padding: 0.25rem 0.3rem;
    }

    .leonis-brand-logo {
        max-height: 28px;
    }

    /* Le chevron du menu utilisateur (pseudo-élément ::after de .dropdown-toggle) est le
       dernier élément de la barre : il se retrouvait rogné au bord droit de l'écran, réduit à
       un fragment. Il n'apporte rien ici — l'avatar est cliquable et ouvre le même menu — et
       sa place profite aux icônes qui, elles, portent une action. */
    .leonis-topbar-right .dropdown-toggle::after {
        display: none;
    }
}

.leonis-sidebar-toggle {
    background: transparent;
    border: none;
    color: #e9dcc9;
    cursor: pointer;
    padding: 6px;
    border-radius: var(--radius, 4px);
    display: flex;
    font-size: 20px;
}

.leonis-sidebar-toggle:hover {
    background: rgba(255, 255, 255, 0.12);
}

.leonis-brand {
    display: flex;
    align-items: center;
}

/* ─── Images de la barre : jamais déformées ───────────────────────────────────────────────
   Sur téléphone la barre déborde (le bandeau du logo plus sept icônes). Or « .leonis-topbar-left »
   porte « min-width: 0 » — donc l'autorisation de passer sous la taille de son contenu — et le
   reboot Tabler applique « max-width: 100% » à toute image. Résultat mesuré le 2026-08-05 : le
   navigateur COMPRIMAIT la largeur du logo en gardant sa hauteur, d'où un « Régulus » écrasé, et
   l'avatar carré (1080 × 1080) rendu en ovale.

   Le correctif porte sur les images, pas sur la barre : une image ne se rétrécit plus
   (« flex-shrink: 0 »), n'est plus bornée par la largeur de son parent (« max-width: none ») et
   conserve son rapport de forme (« object-fit »). C'est la barre qui cède, ce qu'elle sait faire :
   la recherche dépliée masque déjà les autres entrées sous 992px.
   ⚠️ Le vrai levier de place reste le logo lui-même : « angle-haut.png » fait 7554 × 1820
   (rapport 4,15), soit ~91px de large pour 22px de haut. La vue lui substitue le logo carré
   « angle-haut-r.png » sous 576px via un <picture> — voir _Navbar.cshtml. */
.leonis-brand-logo {
    height: 22px;
    width: auto;
    flex-shrink: 0;
    max-width: none;
    object-fit: contain;
}

.leonis-topbar-right .avatar {
    flex-shrink: 0;
    max-width: none;
    /* « cover » et non « contain » : la source est carrée aujourd'hui, mais une photo de profil
       importée ne le sera pas, et un avatar se recadre plutôt qu'il ne se lettreboxe. */
    object-fit: cover;
}

.leonis-topbar-right {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 4px;
    margin: 0;
}

.leonis-topbar-right .nav-link {
    color: #e9dcc9;
}

.leonis-topbar-right .nav-link:hover {
    color: #fff;
    text-decoration: none;
}

/* Icones du topbar (cloche notifications, etoile page par defaut, user, ...) :
   elles heritaient de la petite taille de base (~11px). On les agrandit, on
   espace les entrees (cloche trop pres du nom) et on ancre le badge compteur
   sur le coin de l'icone pour eviter le chevauchement avec le texte. */
.leonis-topbar-right {
    gap: 8px;
}

.leonis-topbar-right .nav-link {
    position: relative;
    display: inline-flex;
    align-items: center;
    padding: 0.25rem 0.5rem;
    line-height: 1;
}

.leonis-topbar-right .nav-link > i.ti {
    font-size: 1.35rem;
    line-height: 1;
}

.leonis-topbar-right .navbar-badge {
    position: absolute;
    top: 0;
    right: 0;
    min-width: 1.1em;
    font-size: 0.62rem;
    line-height: 1;
    padding: 0.15em 0.3em;
    transform: translate(30%, -25%);
}

/* Sidebar */
.leonis-sidebar {
    width: var(--leonis-sidebar-width);
    background: var(--leonis-dark);
    flex-shrink: 0;
    transition: width .2s ease;
    overflow: hidden;
    position: sticky;
    top: var(--leonis-topbar-height);
    height: calc(100vh - var(--leonis-topbar-height));
    /* « dvh » suit le viewport VISIBLE, « vh » le viewport de mise en page — barre d'URL masquée
       sur Chrome Android. Mesuré sur l'appareil de l'utilisateur : 100vh = 751px pour un
       innerHeight de 694, d'où une barre latérale 57 px trop haute et autant d'espace perdu en
       bas du tiroir. La déclaration en « vh » est CONSERVÉE juste au-dessus : les navigateurs qui
       ignorent « dvh » gardent l'ancien comportement au lieu de perdre la hauteur. */
    height: calc(100dvh - var(--leonis-topbar-height));
    align-self: flex-start;
    /* Colonne flex : ses deux enfants en dépendent et ne fonctionnaient pas sans elle. Le champ de
       filtre est en « flex: 0 0 auto » (hauteur fixe, jamais comprimé) et « .leonis-sidebar-scroll »
       en « flex: 1 1 auto » + « min-height: 0 » pour occuper la hauteur restante ET pouvoir défiler.
       Dans un parent en display:block ces déclarations sont INERTES : le conteneur prenait la hauteur
       de ses 143 entrées, que le « overflow: hidden » ci-dessus rognait alors sans barre de
       défilement — le bas du menu était inatteignable. */
    display: flex;
    flex-direction: column;
}

/* ⚠️ RÈGLE GÉNÉRALE POUR TOUT CE FICHIER : « leonis-sidebar-collapsed » a DEUX sens opposés.
   Au-dessus de 992px elle veut dire « sidebar réduite en icônes » ; en dessous, elle veut dire
   « overlay ouvert » (cf. la media query en fin de fichier). Toute règle du mode ICÔNES doit
   donc être bornée à (min-width: 992px), sans quoi elle s'applique aussi au menu mobile — qui
   est alors large de 230px et n'a aucune raison d'être traité en icônes.
   Trois défauts sont nés de cet oubli : le menu qui ne se rétractait pas, le champ de filtre
   masqué, et le pied « Paramètres / Aide » empilé sur deux lignes au lieu d'être côte à côte.
   Les contre-règles qui « défaisaient » tout cela dans la media query mobile ont été retirées :
   il n'y a plus rien à défaire. */
@media (min-width: 992px) {
    body.leonis-sidebar-collapsed .leonis-sidebar {
        width: var(--leonis-sidebar-width-collapsed);
    }
}

/* La sidebar devient une colonne flex pour porter DEUX enfants : le champ de filtre, de
   hauteur fixe, et la zone de menu qui prend le reste. Auparavant elle n'avait qu'un enfant
   en height:100%, ce qui aurait fait déborder le menu de la hauteur du filtre. */
.leonis-sidebar {
    display: flex;
    flex-direction: column;
}

.leonis-sidebar-scroll {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
}

/* --- Filtre du menu ---
   143 entrées sur quatre niveaux : chercher est plus rapide que parcourir. */
.leonis-nav-filter {
    /* Le conteneur est forcé visible pour la même raison que le champ : c'est la fonction de recherche
       du menu qui disparaissait, et je n'ai pas identifié ce qui l'escamotait. */
    display: block !important;
    visibility: visible !important;
    position: relative;
    flex: 0 0 auto;
    padding: 10px 12px;
    /* Hauteur PLANCHER explicite. Le champ a été signalé « absent » sur téléphone alors qu'il est
       bien rendu (vérifié sur le HTML servi à une session authentifiée) et qu'aucune règle ne le
       masque sous 992px : je n'ai pas su reproduire l'escamotage. Faute de cause établie, on rend
       l'élément incompressible plutôt que de deviner — 44px est par ailleurs la taille minimale
       d'une cible tactile, donc la valeur se justifie seule. */
    min-height: 44px;
    box-sizing: border-box;
}

/* Étoile « page par défaut » de la barre du haut, à l'état actif.
   ⚠️ PAS l'orange d'accent : cet orange signifie « favori » dans le menu latéral, et le réutiliser ici
   confondait deux notions distinctes — page par défaut et favori n'ont rien à voir. L'état actif se
   dit donc dans la palette PROPRE à la barre : son encre est #e9dcc9, l'état actif est le blanc franc
   qu'elle emploie déjà au survol, appuyé par un halo.
   (Le remplissage ne peut pas servir de signal : « ti-star-filled » n'existe pas dans cette version de
   Tabler Icons — l'employer rendait l'étoile invisible.) */
.leonis-page-defaut-on {
    color: #fff;
    text-shadow: 0 0 .4rem rgba(255, 255, 255, .85);
}

/* ── Le champ de filtre, AUTONOME ─────────────────────────────────────────────────────────────────
   Signalé « absent sur mobile » à plusieurs reprises, alors qu'il est bien dans le HTML servi (vérifié
   sur une session authentifiée) et qu'aucune règle ne le masque sous 992px. Deux habillages ont échoué :
   un input nu, puis le composant « form-control » + « input-icon » de Tabler. Dans les deux cas, rien
   ne se peignait.

   On supprime donc toute dépendance et toute ambiguïté :
     • « display: block » et « appearance: none » — un input[type=search] a des habillages natifs
       (bouton d'effacement, décorations WebKit) qui peuvent le réduire ou l'aplatir ;
     • hauteur EXPLICITE, pas déduite d'une variable tierce ni du contenu ;
     • « !important » sur les trois propriétés qui décident de l'existence visuelle — display, hauteur,
       visibilité. Ce n'est pas élégant, et c'est assumé : quelque chose que je n'ai pas identifié le
       faisait disparaître, et un champ de recherche invisible n'est pas une imperfection, c'est une
       fonction perdue. Les couleurs, elles, restent surchargeables.
   La loupe est un fond décoratif en SVG intégré : rien à positionner, donc rien qui puisse se
   décrocher. */
.leonis-nav-filter-input {
    display: block !important;
    visibility: visible !important;
    box-sizing: border-box;
    width: 100%;
    height: 38px !important;
    padding: 6px 10px 6px 34px;
    margin: 0;
    font-size: 13px;
    line-height: 24px;
    color: #fff;
    background-color: rgba(255, 255, 255, .16);
    border: 1px solid rgba(255, 255, 255, .38);
    border-radius: 6px;
    outline: none;
    -webkit-appearance: none;
    appearance: none;

    /* Loupe : SVG intégré (donc aucune requête, aucun risque de police d'icônes absente), teintée en
       clair pour le fond sombre de la barre. */
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-opacity='0.75' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='10' cy='10' r='7'/%3E%3Cpath d='m21 21-6-6'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: 9px center;
    background-size: 16px 16px;
}

/* Le bouton d'effacement natif de WebKit se superpose à notre fond et peut masquer la saisie : on le
   retire, l'échappement au clavier vide déjà le champ (cf. custom.js). */
.leonis-nav-filter-input::-webkit-search-cancel-button,
.leonis-nav-filter-input::-webkit-search-decoration {
    -webkit-appearance: none;
    appearance: none;
}

.leonis-nav-filter-input::placeholder {
    color: rgba(255, 255, 255, .75);
    opacity: 1;   /* Firefox applique une opacité de .54 par défaut, qui annulerait le gain. */
}

/* Au focus, l'accent de la charte : le seul endroit où il a du sens ici — il marque la saisie active,
   et non un état « favori ». */
.leonis-nav-filter-input:focus {
    color: #fff;
    border-color: var(--leonis-accent, #f6a523);
    background-color: rgba(255, 255, 255, .22);
    box-shadow: none;
}

/* Entrée écartée par le filtre. */
.leonis-nav-hidden {
    display: none !important;
}

/* En mode icônes (poste de travail uniquement), il n'y a pas la place pour un champ de
   saisie. ⚠️ La règle est bornée à min-width:992px car en dessous la même classe
   « leonis-sidebar-collapsed » signifie l'INVERSE — overlay ouvert — et le filtre doit
   alors rester visible (cf. la media query en fin de fichier). */
@media (min-width: 992px) {
    body.leonis-sidebar-collapsed .leonis-nav-filter {
        display: none;
    }
}

.leonis-nav-block {
    display: block;
}

/* Bloc de navigation principal (hors pied de menu) : seul a defiler,
   le pied (Parametres/Aide) reste fixe en bas de la sidebar */
.leonis-nav-block:not(.leonis-nav-footer) {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
    padding: 12px 0;
}

.leonis-nav-block:not(.leonis-nav-footer)::-webkit-scrollbar {
    width: 6px;
}

.leonis-nav-block:not(.leonis-nav-footer)::-webkit-scrollbar-track {
    background: transparent;
}

.leonis-nav-block:not(.leonis-nav-footer)::-webkit-scrollbar-thumb {
    background: rgba(255, 255, 255, 0.25);
    border-radius: 3px;
}

.leonis-nav-footer {
    flex-shrink: 0;
    border-top: 1px solid rgba(255, 255, 255, 0.12);
    padding: 8px 0;
}

.leonis-nav-footer .leonis-nav {
    display: flex;
    flex-direction: row;
}

.leonis-nav-footer .leonis-nav-item {
    flex: 1;
}

.leonis-nav-footer .leonis-nav-link {
    flex-direction: column;
    justify-content: center;
    gap: 4px;
    padding: 8px 4px;
    text-align: center;
}

.leonis-nav-footer .leonis-nav-label {
    font-size: 11px;
    white-space: normal;
}

/* Mode icônes seulement : à 60px de large, « Paramètres » et « Aide » ne tiennent pas côte à
   côte. Sur mobile la sidebar fait 230px et le pied reste en ligne (règle de base), ce qui
   économise une ligne d'écran. */
@media (min-width: 992px) {
    body.leonis-sidebar-collapsed .leonis-nav-footer .leonis-nav {
        flex-direction: column;
    }
}

.leonis-nav {
    list-style: none;
    margin: 0;
    padding: 0;
}

/* Les trois règles « .leonis-nav-section » qui figuraient ici sont supprimées : plus aucun
   en-tête de section n'est produit. Les rubriques de premier niveau sont devenues des groupes
   REPLIABLES (.leonis-nav-root), justement pour que le menu ne déroule plus ses 79 entrées en
   permanence — c'est ce que ces en-têtes imposaient, n'ayant aucun mécanisme de repli.
   Deux d'entre elles masquaient le titre par text-indent:-9999px pour le mode icônes, ce qui
   fuyait sur mobile et n'y laissait que des traits de séparation muets. */

.leonis-nav-link {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 16px;
    font-size: 14px;
    color: #e9dcc9;
    text-decoration: none;
    white-space: nowrap;
}

.leonis-nav-link:hover {
    background: rgba(246, 165, 35, 0.15);
    color: #fff;
    text-decoration: none;
}

.leonis-nav-link.active {
    background: rgba(246, 165, 35, 0.22);
    color: #fff;
    border-left: 2px solid var(--leonis-accent);
    padding-left: 14px;
}

@media (min-width: 992px) {
    body.leonis-sidebar-collapsed .leonis-nav-link {
        padding: 8px 0;
        justify-content: center;
    }

    body.leonis-sidebar-collapsed .leonis-nav-link.active {
        border-left: none;
        padding-left: 0;
        border-top: 2px solid var(--leonis-accent);
    }
}

.leonis-nav-icon {
    font-size: 18px;
    width: 18px;
    text-align: center;
    color: var(--leonis-accent);
    flex-shrink: 0;
}

/* Icone du titre de page (content-header h1) en orange (accent), qu'elle soit INJECTEE
   par custom.js (.leonis-nav-icon, depuis l'icone du menu actif) ou posee EN DUR dans la
   vue (<i class="ti ...">). L'injection est sautee si un <i> existe deja (custom.js) : sans
   cette regle, les icones ecrites directement dans le h1 restaient noires (couleur de texte
   par defaut) au lieu d'orange. Cible uniquement l'icone du titre, pas celles des cartes. */
.content-header > h1 > i {
    color: var(--leonis-accent);
}

/* Badges à fond foncé : Bootstrap 5.3 ne force plus le texte blanc sur .badge, et le thème hérite
   de la couleur de texte sombre du corps -> texte gris/noir illisible sur fond rouge/bleu/gris/vert.
   On rétablit le blanc pour ces fonds foncés (les fonds clairs warning/info/light gardent un texte
   sombre, correct). Couvre aussi bien .bg-* que .text-bg-*. */
.badge.bg-danger, .badge.bg-primary, .badge.bg-secondary, .badge.bg-success, .badge.bg-dark {
    color: #fff !important;
}

/* Le h1 des content-header recoit une icone injectee (.leonis-nav-icon, 18px + me-2)
   qui decale le TEXTE du titre vers la droite. Les sous-titres places sous le titre
   (ex. <span id="lastSyncMessage"> "Derniere synchronisation ...") restaient alignes
   sous l'ICONE, pas sous le texte. On les indente de la largeur de l'icone + sa marge
   pour qu'ils s'alignent proprement sous le texte du titre. */
.content-header > h1 + span,
.content-header > span {
    display: block;
    padding-left: calc(18px + 0.5rem);
}

/* Icones dans les addons d'input-group (prepend/append : calendrier datepicker,
   oeil afficher/masquer mot de passe, etc.) : en orange (accent) sur le fond gris
   par defaut de la boite .input-group-text. */
.input-group .input-group-text .ti,
.input-group .input-group-text i,
.input-group .input-group-text > a {
    color: var(--leonis-accent);
}
/* Boite oeil (append sans wrapper .input-group-append) : sa hauteur retombe sur le
   calc() de Tabler (~29.6px) ~2px plus court que le champ (32px) -> bas desaligne.
   On force 32px, comme le prepend datepicker. (:has couvre ti-eye-off <-> ti-eye.) */
.input-group-text:has(.ti-eye-off),
.input-group-text:has(.ti-eye) {
    height: 32px !important;
    display: flex;
    align-items: center;
}

/* Liste "Complexite a respecter" (ChangePassword) : espace entre l'icone de
   validation OK/NOK (l'id peut porter sur le wrapper <div>/<span> ou sur le <i>)
   et le libelle de la regle qui suit. */
[id$="IconOK"],
[id$="IconNOK"] {
    margin-right: .5rem;
}

@media (min-width: 992px) {
    body.leonis-sidebar-collapsed .leonis-nav-label,
    body.leonis-sidebar-collapsed .leonis-nav-chevron,
    body.leonis-sidebar-collapsed .leonis-nav-sub {
        display: none;
    }
}

.leonis-nav-chevron {
    margin-left: auto;
    font-size: 14px;
    opacity: .7;
    transition: transform .2s ease;
}

.leonis-nav-item.leonis-menu-open > .leonis-nav-link .leonis-nav-chevron {
    transform: rotate(90deg);
}

.leonis-nav-sub {
    display: none;
    list-style: none;
    margin: 0;
    padding-left: 24px;
}

/* --- Rubriques de premier niveau ---
   Elles étaient de simples en-têtes (.leonis-nav-section) suivis de leurs enfants à plat :
   les 13 rubriques affichaient donc 79 entrées en permanence. Ce sont maintenant des groupes
   repliables ; au repos le menu tient en 13 lignes. On leur garde l'allure d'un intitulé de
   rubrique — majuscules, interlettrage, séparateur — pour que la hiérarchie reste lisible. */
.leonis-nav-root > .leonis-nav-link {
    font-size: 12px;
    letter-spacing: .04em;
    font-weight: 600;
    color: #f2e6d4;
}

.leonis-nav-root:not(:first-child) {
    border-top: 1px solid rgba(255, 255, 255, .10);
}

/* En mode icônes la sidebar ne fait que 60px : le retrait de 24px pousserait les icônes des
   sous-entrées hors du cadre. Le repli lui-même continue de fonctionner, jQuery posant un
   display inline qui l'emporte sur la règle de masquage du mode icônes. */
@media (min-width: 992px) {
    body.leonis-sidebar-collapsed .leonis-nav-sub {
        padding-left: 0;
    }
}

.leonis-nav-item.leonis-menu-open > .leonis-nav-sub {
    display: block;
}

.leonis-nav-sub .leonis-nav-link {
    padding: 6px 16px;
    font-size: 13px;
}

/* Contenu */
.leonis-content-wrapper {
    flex: 1;
    display: flex;
    flex-direction: column;
    background: var(--leonis-content-bg);
    min-width: 0;
}

/* margin-top:auto pousse le footer en bas du wrapper (qui occupe deja toute
   la hauteur disponible via flex:1 ci-dessus) quel que soit le nombre
   d'elements rendus par @RenderBody() - sans ca le footer suit simplement
   le contenu et se retrouve au milieu de la page des que celle-ci est plus
   courte que le viewport (page d'accueil, pages avec peu de donnees). */
.leonis-footer {
    margin-top: auto;
    padding: 12px 20px;
    font-size: 12px;
    color: #6c757d;
}

/* En dessous de 992px, .leonis-sidebar-collapsed change de sens : au lieu de
   reduire la sidebar en icones (desktop), elle la fait apparaitre en overlay
   (masquee par defaut sur mobile). */
@media (max-width: 991.98px) {
    /* ⚠️ PAS de « position: fixed » ici, et c'est tout l'objet du correctif du 2026-08-07.
       ────────────────────────────────────────────────────────────────────────────────────
       Sur Chrome Android, DEUX viewports coexistent : celui de mise en page (barre d'URL
       MASQUÉE) et le visible. Mesuré sur l'appareil de l'utilisateur : « 100vh = 751px »
       pour un « innerHeight » de 694 — le viewport de mise en page commence donc 57 px
       AU-DESSUS du haut visible.

       Or un élément « fixed » se place par rapport au viewport de MISE EN PAGE, tandis que
       la barre d'en-tête, en « position: sticky », se place dans le FLUX du document, aligné
       sur le haut visible. Les deux dérivent alors l'une de l'autre de la hauteur de la barre
       d'URL. Relevé sur l'appareil :

           en-tete : y=0->56  pos=sticky  z=1030
           aside   : y=0      pos=fixed   top=56px  z=1020   <- top calculé 56, peint à 0 !

       La barre latérale remontait donc de 57 px sous l'en-tête, qui la recouvre (1030 > 1020),
       et ses 58 premiers pixels — le bloc du champ de filtre — disparaissaient. Le champ était
       intact et correctement dimensionné (206x38, display:block, opacité 1) : simplement caché
       dessous. Quatre corrections précédentes ont échoué faute de mesurer cela, et aucune
       émulation ne reproduit la dérive (CDP ne simule pas la barre d'URL dynamique).

       La référence qui fonctionne est donc celle du FLUX. On garde le « position: sticky » de
       la règle de base — flux, mais épinglé sous l'en-tête — et on retire simplement la barre
       de l'encombrement horizontal par une marge négative, au lieu de la sortir du flux.
       Le tiroir recouvre alors le contenu par son z-index, sans jamais pouvoir dériver. */
    .leonis-sidebar {
        /* ⚠️ AUCUN « left » ici. Sur un élément « sticky », « left: 0 » l'épingle HORIZONTALEMENT
           et annule la marge négative ci-dessous : mesuré, le tiroir restait alors visible à x=0
           une fois fermé, et partait à x=230 une fois ouvert — l'inverse exact du comportement
           voulu. Le décalage horizontal est porté uniquement par la marge et le transform. */
        z-index: 1020;
        width: var(--leonis-sidebar-width);
        /* Retirée de l'encombrement de la rangée flex : sa boîte se place hors écran à gauche,
           le contenu principal démarre donc bien à x=0. */
        margin-left: calc(-1 * var(--leonis-sidebar-width));
    }

    /* Sous 992px, « leonis-sidebar-collapsed » signifie tiroir OUVERT (cf. l'en-tête de la
       règle des 992px). Le décalage vaut +100% et non 0 : la marge négative place la boîte à
       -230px, il faut donc la ramener de sa propre largeur pour l'amener à x=0. */
    body.leonis-sidebar-collapsed .leonis-sidebar {
        transform: translateX(100%);
    }

    /* Les trois contre-règles qui suivaient ici (réafficher le libellé et le chevron, rendre
       son padding au lien, redonner sa largeur à la sidebar) ne servaient qu'à DÉFAIRE des
       règles du mode icônes qui n'auraient jamais dû s'appliquer sur mobile. Ces règles sont
       désormais bornées à (min-width: 992px) : il n'y a plus rien à défaire. */
}

/* ─────────────────────────────────────────────────────────────────────────────────────────
   Tuile d'indicateur (#700) — un chiffre et son libellé, utilisée par les écrans de
   statistiques. Bâtie sur les variables Tabler (--tblr-*) et NON sur des couleurs en dur :
   elles suivent déjà le thème clair/sombre, donc aucun bloc « prefers-color-scheme » à
   maintenir en double.
   ───────────────────────────────────────────────────────────────────────────────────────── */
.leonis-kpi {
    height: 100%;
    padding: .75rem;
    border: 1px solid var(--tblr-border-color);
    border-radius: var(--tblr-border-radius, .25rem);
    background: var(--tblr-bg-surface);
    text-align: center;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: .15rem;
}

.leonis-kpi-value {
    font-size: 1.5rem;
    font-weight: 600;
    line-height: 1.1;
    /* Un chiffre porte l'identité par sa taille, pas par une couleur de série : il reste en
       encre primaire pour rester lisible dans les deux thèmes. */
    color: var(--tblr-body-color);
}

.leonis-kpi-label {
    font-size: .8125rem;
    color: var(--tblr-secondary);
    /* Les libellés sont longs (« Non clôturées en fin de période ») : on les laisse passer à
       la ligne plutôt que de les tronquer, sinon la tuile devient illisible sur mobile. */
    overflow-wrap: anywhere;
}

/* Sur mobile, deux tuiles par ligne suffisent : on réduit le chiffre pour qu'un nombre à
   cinq chiffres ne déborde pas de sa tuile. */
@media (max-width: 575.98px) {
    .leonis-kpi-value { font-size: 1.25rem; }
    .leonis-kpi-label { font-size: .75rem; }
}

/* ─── Favoris du menu latéral ─────────────────────────────────────────────────────────────
   Bloc « FAVORIS » en tête du menu + étoile de bascule sur chaque entrée terminale.
   L'étoile est un FRÈRE du lien, pas un enfant : imbriquée dans le <a>, un clic dessus
   suivrait aussi le lien. D'où le positionnement absolu dans un .leonis-nav-item relatif. */
.leonis-nav-item {
    position: relative;
}

.leonis-nav-fav {
    position: absolute;
    top: 50%;
    right: .35rem;
    transform: translateY(-50%);
    display: none;                 /* révélée au survol, ou si déjà active — voir plus bas */
    padding: .15rem .25rem;
    line-height: 1;
    background: none;
    border: 0;
    color: var(--leonis-sidebar-muted, #8a94a6);
    cursor: pointer;
    opacity: .75;
}

.leonis-nav-item:hover > .leonis-nav-fav,
.leonis-nav-fav.leonis-nav-fav-on {
    display: inline-block;
}

.leonis-nav-fav:hover {
    opacity: 1;
    color: #f0b429;
}

/* Favori actif : étoile pleine et colorée, lisible sans survol. */
.leonis-nav-fav.leonis-nav-fav-on {
    color: #f0b429;
    opacity: 1;
}

.leonis-nav-fav.leonis-nav-fav-on i {
    /* Tabler n'a pas de variante « pleine » pour ti-star dans cette version : le remplissage
       est simulé par l'ombre portée, ce qui suffit à distinguer actif et inactif. */
    text-shadow: 0 0 .35rem rgba(240, 180, 41, .8);
}

/* Séparation du bloc des favoris du reste du menu, sans en faire une rubrique repliable :
   les favoris doivent rester visibles en permanence, c'est leur seule utilité. */
.leonis-nav-favorites {
    border-bottom: 1px solid var(--leonis-sidebar-border, rgba(255, 255, 255, .08));
    padding-bottom: .35rem;
    margin-bottom: .35rem;

}

/* ⚠️ SANS CETTE RÈGLE le bloc des favoris mange la moitié de la hauteur du menu. Il porte la classe
   « leonis-nav-block », donc il héritait de la règle générique
   « .leonis-nav-block:not(.leonis-nav-footer) { flex: 1 1 auto; overflow-y: auto } », faite pour le
   bloc PRINCIPAL — celui qui doit occuper la place restante et défiler. Deux blocs extensibles se
   partageaient la hauteur, d'où un trou béant sous les favoris.

   ⚠️⚠️ Et le sélecteur doit porter LES DEUX classes : « :not(.leonis-nav-footer) » compte dans le
   calcul de spécificité, si bien que « .leonis-nav-block:not(.leonis-nav-footer) » (deux classes)
   l'emportait sur « .leonis-nav-favorites » seul (une classe) — première tentative de correctif sans
   effet, le trou restait. À spécificité égale, c'est l'ordre du fichier qui tranche, et cette règle
   vient après.

   Un bloc de favoris fait la taille de ses favoris, ni plus ni moins. */
.leonis-nav-block.leonis-nav-favorites {
    flex: 0 0 auto;
    overflow: visible;
}

/* Retrait des entrées en favori, à l'exclusion du titre : elles sont subordonnées à « FAVORIS »
   exactement comme les entrées d'un sous-menu le sont à leur rubrique. On reprend donc le même
   décalage — 24px, celui de « .leonis-nav-sub » — ajouté aux 16px du lien. */
.leonis-nav-favorites .leonis-nav-item:not(.leonis-nav-fav-title) > .leonis-nav-link {
    padding-left: 40px;
}

/* Le titre FAVORIS se présente comme une RUBRIQUE DE PREMIER NIVEAU, et pas comme une petite
   étiquette grise : mêmes dimensions, même graisse et même encre que « .leonis-nav-root >
   .leonis-nav-link » (12px, 600, #f2e6d4), l'icône à gauche du libellé grâce au même balisage.
   Il reste non cliquable — d'où le curseur par défaut : c'est un intitulé, pas une destination. */
.leonis-nav-fav-title > .leonis-nav-link {
    font-size: 12px;
    letter-spacing: .04em;
    font-weight: 600;
    color: #f2e6d4;
    text-transform: uppercase;
    cursor: default;
}

/* Pas de réaction au survol : rien à cliquer ici, le laisser s'éclaircir mentirait sur son rôle. */
.leonis-nav-fav-title > .leonis-nav-link:hover {
    background: transparent;
    color: #f2e6d4;
}

/* Sidebar réduite : le libellé est masqué, l'étoile n'a plus la place et n'aurait pas de sens
   (on ne gère pas ses favoris depuis un menu réduit à des icônes).
   ⚠️ BORNÉE À 992px, et c'est tout l'objet du correctif : en dessous, « leonis-sidebar-collapsed »
   signifie l'INVERSE — le tiroir est OUVERT (cf. l'avertissement en tête de fichier). Sans cette
   borne, la règle masquait l'étoile et le titre « FAVORIS » précisément quand l'utilisateur venait
   d'ouvrir le menu sur son téléphone : les favoris étaient donc inatteignables sur mobile
   (constaté 2026-08-05). */
@media (min-width: 992px) {
    .leonis-sidebar-collapsed .leonis-nav-fav,
    .leonis-sidebar-collapsed .leonis-nav-fav-title {
        display: none;
    }
}

/* ⚠️ L'étoile est en position absolue AU-DESSUS du lien : sans place réservée, un libellé long passe
   dessous et la rend inatteignable (constaté le 2026-08-05 sur « Réconciliation facturation »). On
   réserve donc sa largeur sur les liens qui en portent une, et le libellé s'abrège plutôt que de
   déborder. Le sélecteur cible le lien SUIVI d'une étoile, pour ne pas creuser un blanc à droite des
   rubriques, qui n'en ont pas. */
.leonis-nav-item > .leonis-nav-link:has(+ .leonis-nav-fav) {
    padding-right: 2.1rem;
}

.leonis-nav-item > .leonis-nav-link:has(+ .leonis-nav-fav) .leonis-nav-label {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Repli pour les navigateurs sans « :has() » : la place est alors réservée sur toutes les feuilles
   de sous-menu, qui sont précisément celles qui portent une étoile. Deux règles au lieu d'une, mais
   aucun libellé ne recouvre l'étoile, ce qui est le seul point qui compte. */
@supports not selector(:has(*)) {
    .leonis-nav-sub .leonis-nav-link {
        padding-right: 2.1rem;
    }

    .leonis-nav-sub .leonis-nav-label {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
}

/* L'étoile reste cliquable même si un libellé la chevauche malgré tout : elle est peinte après le
   lien dans le DOM, mais un z-index explicite évite de dépendre de cet ordre. */
.leonis-nav-fav {
    z-index: 2;
}

/* Écrans tactiles : il n'y a PAS de survol. Une affordance révélée au « :hover » n'y existe pas —
   l'étoile restait donc en display:none quoi que fasse l'utilisateur, d'où « je ne vois pas comment
   mettre une entrée en favoris ». On l'affiche en permanence, en la laissant discrète (opacité
   réduite tant qu'elle n'est pas active) pour ne pas alourdir chaque ligne du menu.
   « hover: none » cible le pointeur grossier sans se raccrocher à une largeur d'écran : une tablette
   large est tactile, un portable étroit ne l'est pas. */
@media (hover: none) {
    .leonis-nav-fav {
        display: inline-block;
        opacity: .45;
    }
}
