/* =========================================================================
   CLARIO UI — couche de tokens, mode sombre integral, tableau de bord
   =========================================================================

   POURQUOI CE FICHIER EXISTE, ET POURQUOI IL EST CHARGE EN DERNIER

   Deux problemes structurels que ce fichier corrige a la racine :

   1. CASCADE. `tagify.css`, `toastr.min.css` et `choices.css` etaient charges
      APRES `custom.css`. Leurs styles clairs gagnaient donc contre toute regle
      sombre ecrite en amont, quelle que soit sa qualite. Ce fichier passe en
      dernier : c'est la seule position d'ou l'on peut habiller ces widgets.

   2. PEINTURE MANUELLE. Les 268 regles sombres de `custom.css` repeignent
      chaque composant a la main. Un composant ajoute demain reste clair tant
      que personne n'ecrit sa regle — c'est exactement ce qui a produit les
      sections restees claires. Ici, les surfaces lisent des VARIABLES qui
      basculent avec le mode. Un composant qui utilise `var(--ui-surface)`
      suit le theme sans qu'on ait rien a ecrire pour lui.

   Ce fichier ne remplace pas `custom.css` : il le complete et le corrige aux
   endroits ou il ne pouvait pas gagner.
   ========================================================================= */


/* =========================================================================
   1. COUCHE DE TOKENS
   =========================================================================
   Les memes noms semantiques existent dans les deux modes. Ecrire
   `background: var(--ui-surface)` suffit : la valeur change, pas la regle.
   ========================================================================= */

:root {
    /* --- Marque, identique dans les deux modes --- */
    --ui-accent:            #10B981;   /* emeraude Clario */
    --ui-accent-soft:       rgba(16, 185, 129, 0.12);
    --ui-accent-2:          #FF6B00;   /* orange Clario */
    --ui-accent-2-soft:     rgba(255, 107, 0, 0.12);

    /* --- Rayons et rythme, communs --- */
    --ui-radius:            18px;
    --ui-radius-sm:         12px;
    --ui-radius-pill:       999px;
    --ui-gap:               14px;

    /* --- Surfaces, mode CLAIR (valeurs par defaut) --- */
    --ui-bg:                #F4F6F8;
    --ui-surface:           #FFFFFF;
    --ui-surface-2:         #F8FAFC;
    --ui-surface-3:         #EEF2F6;
    --ui-card:              #FFFFFF;
    --ui-card-glass:        #FFFFFF;
    --ui-border:            rgba(15, 23, 42, 0.08);
    --ui-border-strong:     rgba(15, 23, 42, 0.14);

    --ui-text:              #0F172A;
    --ui-text-body:         #334155;
    --ui-text-muted:        #64748B;
    --ui-text-dim:          #94A3B8;

    --ui-shadow:            0 4px 16px rgba(15, 23, 42, 0.06);
    --ui-shadow-lg:         0 12px 32px rgba(15, 23, 42, 0.10);
    --ui-blur:              blur(14px);

    /* Le voile de verre n'existe qu'en sombre : pose sur du blanc il produit
       un gris sale, jamais l'effet recherche. En clair il vaut donc `none`. */
    --ui-glass:             none;
}

body.dark-mode {
    --ui-bg:                #061812;
    --ui-surface:           #0B221A;
    --ui-surface-2:         #0E2A20;
    --ui-surface-3:         #123328;
    --ui-card:              #0B221A;
    --ui-card-glass:        rgba(11, 34, 26, 0.72);
    --ui-border:            rgba(16, 185, 129, 0.18);
    --ui-border-strong:     rgba(16, 185, 129, 0.34);

    --ui-text:              #FFFFFF;
    --ui-text-body:         #E2E8F0;
    --ui-text-muted:        #94A3B8;
    --ui-text-dim:          #64748B;

    --ui-shadow:            0 8px 32px rgba(0, 0, 0, 0.35);
    --ui-shadow-lg:         0 16px 48px rgba(0, 0, 0, 0.45);

    --ui-glass:             var(--ui-blur);
}


/* =========================================================================
   2. MODE SOMBRE INTEGRAL — les surfaces que personne n'avait couvertes
   =========================================================================
   Dix familles de composants restaient claires. Trois d'entre elles
   (toastr, tagify, choices) etaient IMPOSSIBLES a habiller depuis
   `custom.css` : leur feuille se chargeait apres. D'ou ce fichier.
   ========================================================================= */

/* --- Notifications toastr ------------------------------------------------
   Une notification claire sur une interface sombre est un flash blanc en
   plein ecran. C'est le defaut le plus visible des trois. */
body.dark-mode #toast-container > div {
    background-color: var(--ui-surface-2) !important;
    border: 1px solid var(--ui-border) !important;
    color: var(--ui-text-body) !important;
    box-shadow: var(--ui-shadow-lg) !important;
    opacity: 1 !important;
}

body.dark-mode #toast-container > .toast-success { border-left: 3px solid var(--ui-accent) !important; }
body.dark-mode #toast-container > .toast-error   { border-left: 3px solid #F0484B !important; }
body.dark-mode #toast-container > .toast-warning { border-left: 3px solid var(--ui-accent-2) !important; }
body.dark-mode #toast-container > .toast-info    { border-left: 3px solid #38BDF8 !important; }
body.dark-mode #toast-container .toast-title     { color: var(--ui-text) !important; }
body.dark-mode #toast-container .toast-message   { color: var(--ui-text-body) !important; }
body.dark-mode #toast-container .toast-close-button { color: var(--ui-text-muted) !important; text-shadow: none !important; }

/* --- Boites de dialogue jquery-confirm -----------------------------------
   Elles portent les confirmations de suppression : le moment ou l'on a le
   plus besoin de lire ce qui est ecrit. */
body.dark-mode .jconfirm .jconfirm-box {
    background: var(--ui-surface) !important;
    border: 1px solid var(--ui-border) !important;
    color: var(--ui-text-body) !important;
    box-shadow: var(--ui-shadow-lg) !important;
}
body.dark-mode .jconfirm .jconfirm-title,
body.dark-mode .jconfirm .jconfirm-content,
body.dark-mode .jconfirm .jconfirm-content-pane { color: var(--ui-text-body) !important; }
body.dark-mode .jconfirm .jconfirm-buttons button.btn-default {
    background: var(--ui-surface-3) !important;
    color: var(--ui-text-body) !important;
    border: 1px solid var(--ui-border) !important;
}
body.dark-mode .jconfirm-bg { background: rgba(0, 0, 0, 0.6) !important; }

/* --- SweetAlert ---------------------------------------------------------- */
body.dark-mode .swal2-popup {
    background: var(--ui-surface) !important;
    border: 1px solid var(--ui-border) !important;
    color: var(--ui-text-body) !important;
}
body.dark-mode .swal2-title,
body.dark-mode .swal2-html-container { color: var(--ui-text-body) !important; }
body.dark-mode .swal2-input,
body.dark-mode .swal2-textarea,
body.dark-mode .swal2-select {
    background: var(--ui-surface-2) !important;
    border: 1px solid var(--ui-border) !important;
    color: var(--ui-text-body) !important;
}

/* --- Selecteurs de date -------------------------------------------------- */
body.dark-mode .flatpickr-calendar,
body.dark-mode .daterangepicker {
    background: var(--ui-surface) !important;
    border: 1px solid var(--ui-border) !important;
    color: var(--ui-text-body) !important;
    box-shadow: var(--ui-shadow-lg) !important;
}
body.dark-mode .flatpickr-months .flatpickr-month,
body.dark-mode .flatpickr-current-month,
body.dark-mode .flatpickr-weekday,
body.dark-mode .daterangepicker .calendar-table,
body.dark-mode .daterangepicker th,
body.dark-mode .daterangepicker td {
    background: transparent !important;
    color: var(--ui-text-body) !important;
}
body.dark-mode .flatpickr-day { color: var(--ui-text-body) !important; }
body.dark-mode .flatpickr-day:hover,
body.dark-mode .daterangepicker td.available:hover {
    background: var(--ui-surface-3) !important;
    border-color: var(--ui-border) !important;
}
body.dark-mode .flatpickr-day.selected,
body.dark-mode .daterangepicker td.active {
    background: var(--ui-accent) !important;
    border-color: var(--ui-accent) !important;
    color: #04150F !important;
}
/* Un jour desactive doit rester LISIBLE tout en se distinguant : passer sous
   ~3:1 le rend invisible, et l'utilisateur croit a un trou dans le calendrier. */
body.dark-mode .flatpickr-day.flatpickr-disabled,
body.dark-mode .daterangepicker td.off { color: var(--ui-text-dim) !important; }
body.dark-mode .daterangepicker .drp-buttons { border-top-color: var(--ui-border) !important; }
body.dark-mode .daterangepicker:after { border-bottom-color: var(--ui-surface) !important; }
body.dark-mode .daterangepicker:before { border-bottom-color: var(--ui-border) !important; }

/* --- Listes, barres de progression, info-bulles -------------------------- */
body.dark-mode .list-group { background: transparent !important; }
body.dark-mode .list-group-item {
    background: var(--ui-surface) !important;
    border-color: var(--ui-border) !important;
    color: var(--ui-text-body) !important;
}
body.dark-mode .list-group-item-action:hover,
body.dark-mode .list-group-item-action:focus { background: var(--ui-surface-2) !important; }
body.dark-mode .list-group-item.active {
    background: var(--ui-accent-soft) !important;
    border-color: var(--ui-border-strong) !important;
    color: var(--ui-text) !important;
}

body.dark-mode .progress { background: var(--ui-surface-3) !important; }

body.dark-mode .tooltip-inner {
    background: var(--ui-surface-3) !important;
    color: var(--ui-text-body) !important;
    border: 1px solid var(--ui-border) !important;
}
body.dark-mode .tooltip .tooltip-arrow::before { border-top-color: var(--ui-surface-3) !important; }
body.dark-mode .popover {
    background: var(--ui-surface) !important;
    border: 1px solid var(--ui-border) !important;
}
body.dark-mode .popover-header {
    background: var(--ui-surface-2) !important;
    color: var(--ui-text) !important;
    border-bottom-color: var(--ui-border) !important;
}
body.dark-mode .popover-body { color: var(--ui-text-body) !important; }

body.dark-mode .navbar { background: transparent !important; }

/* --- Tagify (feuille chargee apres custom.css) --------------------------- */
body.dark-mode .tagify {
    background: var(--ui-surface-2) !important;
    border-color: var(--ui-border) !important;
    --tag-bg: var(--ui-surface-3);
    --tag-text-color: var(--ui-text-body);
}
body.dark-mode .tagify__input,
body.dark-mode .tagify__tag > div { color: var(--ui-text-body) !important; }
body.dark-mode .tagify__dropdown__wrapper {
    background: var(--ui-surface) !important;
    border-color: var(--ui-border) !important;
    color: var(--ui-text-body) !important;
}

/* --- Choices (feuille chargee apres custom.css) -------------------------- */
body.dark-mode .choices__inner,
body.dark-mode .choices__list--dropdown,
body.dark-mode .choices__list[aria-expanded] {
    background: var(--ui-surface-2) !important;
    border-color: var(--ui-border) !important;
    color: var(--ui-text-body) !important;
}
body.dark-mode .choices__list--dropdown .choices__item--selectable.is-highlighted,
body.dark-mode .choices__list[aria-expanded] .choices__item--selectable.is-highlighted {
    background: var(--ui-surface-3) !important;
}
body.dark-mode .choices__list--multiple .choices__item {
    background: var(--ui-accent-soft) !important;
    border-color: var(--ui-border-strong) !important;
    color: var(--ui-text-body) !important;
}
body.dark-mode .choices[data-type*=select-one] .choices__input {
    background: var(--ui-surface-3) !important;
    color: var(--ui-text-body) !important;
    border-bottom-color: var(--ui-border) !important;
}

/* --- Filet de securite --------------------------------------------------
   Les utilitaires Bootstrap poses en dur dans les vues. Ils sont peu
   nombreux (une trentaine de fichiers), mais chacun produit un bloc blanc
   franc au milieu d'une page sombre — le defaut le plus visible de tous. */
body.dark-mode .bg-white,
body.dark-mode .bg-light,
body.dark-mode .bg-body,
body.dark-mode .bg-body-tertiary {
    background-color: var(--ui-surface) !important;
    color: var(--ui-text-body) !important;
}
body.dark-mode .text-dark { color: var(--ui-text-body) !important; }
body.dark-mode .border { border-color: var(--ui-border) !important; }
body.dark-mode .border-top { border-top-color: var(--ui-border) !important; }
body.dark-mode .border-bottom { border-bottom-color: var(--ui-border) !important; }
body.dark-mode .border-start { border-left-color: var(--ui-border) !important; }
body.dark-mode .border-end { border-right-color: var(--ui-border) !important; }
body.dark-mode hr { border-color: var(--ui-border) !important; opacity: 1; }

/* Le remplissage automatique de Chrome repeint le champ en bleu clair et
   ignore `background-color`. Seule une ombre interne enorme le recouvre. */
body.dark-mode input:-webkit-autofill,
body.dark-mode input:-webkit-autofill:hover,
body.dark-mode input:-webkit-autofill:focus,
body.dark-mode textarea:-webkit-autofill,
body.dark-mode select:-webkit-autofill {
    -webkit-box-shadow: 0 0 0 1000px var(--ui-surface-2) inset !important;
    -webkit-text-fill-color: var(--ui-text-body) !important;
    caret-color: var(--ui-text-body);
    transition: background-color 9999s ease-in-out 0s;
}

/* Les barres de defilement internes restent claires sur WebKit tant qu'on ne
   declare pas `color-scheme` — le navigateur ne peut pas deviner. */
body.dark-mode { color-scheme: dark; }
body:not(.dark-mode) { color-scheme: light; }


/* =========================================================================
   3. TABLEAU DE BORD — cartes carrees, verre affine
   =========================================================================
   Les cartes d'indicateurs etaient etirees : une colonne de 380 px de large
   pour 140 px de contenu donne une bande horizontale, pas une carte. Le
   contenu flottait en haut et laissait un vide en bas.

   Correction : un rapport 1/1 plafonne en hauteur. Aux largeurs courantes
   (portable, 1440 px) la carte est carree ; sur un tres grand ecran le
   plafond l'empeche de devenir une tour de 380 px de haut et elle retombe
   sur la proportion des maquettes. Le contenu est reparti sur toute la
   hauteur plutot que tasse en haut.
   ========================================================================= */

#kpi-grid > [class*="col-"] > .futuristic-card,
.kpi-square {
    /* NI `aspect-ratio`, NI `max-height`. C'ETAIT LA LE DEFAUT.
       Les deux ensemble ne plafonnent pas la hauteur : ils retrecissent la
       LARGEUR. Sur une colonne de 459 px, le rapport 1/1 demande 459 px de
       haut, le plafond de 260 px les refuse, et le rapport rend alors une
       carte de 260 px de LARGE — 199 px de vide a sa droite, quatre fois de
       suite. C'est l'origine des ecarts signales.

       La carte occupe donc toute sa colonne, et sa hauteur vient de son
       contenu avec un plancher. `height: 100%` aligne les quatre sur la plus
       haute : sans lui, chacune s'arrete a son propre contenu et le bas de la
       rangee devient irregulier. */
    width: 100%;
    height: 100%;
    min-height: 188px;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    padding: 20px !important;
}

/* Le nombre est ce qu'on vient lire : il occupe le centre optique de la
   carte, pas une ligne parmi d'autres. */
#kpi-grid .bus-stat-count {
    font-size: clamp(24px, 2.1vw, 34px) !important;
    line-height: 1.1;
    letter-spacing: -0.02em;
    margin: auto 0 !important;
}

#kpi-grid .stat-icon-wrapper {
    width: 42px;
    height: 42px;
    border-radius: var(--ui-radius-sm);
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}

/* La courbe de fond descend au tiers bas : plus haut elle passe derriere le
   nombre et le rend illisible sur les cartes a fort contraste. */
#kpi-grid .card-sparkline-bg {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    width: 100%;
    height: 38%;
    opacity: 0.6;
    pointer-events: none;
    z-index: 1;
}

/* --- Le verre, affine ---------------------------------------------------
   Un `backdrop-filter` seul ne fait pas du verre : il floute ce qu'il y a
   derriere sans donner d'epaisseur. Ce qui lit comme du verre, c'est le
   liseré clair sur l'arete haute — la lumiere qui accroche le bord. */
.futuristic-card {
    background: var(--ui-card-glass) !important;
    backdrop-filter: var(--ui-glass);
    -webkit-backdrop-filter: var(--ui-glass);
    border: 1px solid var(--ui-border) !important;
    border-radius: var(--ui-radius) !important;
    box-shadow: var(--ui-shadow);
    position: relative;
}

body.dark-mode .futuristic-card::before {
    content: '';
    position: absolute;
    inset: 0 0 auto 0;
    height: 1px;
    background: linear-gradient(90deg,
        transparent,
        rgba(255, 255, 255, 0.14) 22%,
        rgba(255, 255, 255, 0.14) 78%,
        transparent);
    pointer-events: none;
    z-index: 3;
}

body.dark-mode .futuristic-card:hover {
    border-color: var(--ui-border-strong) !important;
    box-shadow: var(--ui-shadow-lg), 0 0 24px rgba(16, 185, 129, 0.10);
}

/* En clair, le verre n'a pas lieu d'etre : on garde la meme geometrie mais
   une surface franche. Un flou sur du blanc ne produit qu'un gris sale. */
body:not(.dark-mode) .futuristic-card {
    background: var(--ui-surface) !important;
    border: 1px solid var(--ui-border) !important;
    box-shadow: var(--ui-shadow) !important;
}
body:not(.dark-mode) .futuristic-card:hover {
    box-shadow: var(--ui-shadow-lg) !important;
    border-color: var(--ui-border-strong) !important;
}

/* Le survol souleve la carte. Repete sur douze cartes il donne le mal de
   mer ; deux pixels suffisent a signaler qu'elle est cliquable. */
.futuristic-card:hover { transform: translateY(-2px); }
#kpi-grid .futuristic-card:hover { transform: translateY(-3px); }

/* --- Titres de section --------------------------------------------------- */
.futuristic-card .card-title,
.futuristic-card h5,
.futuristic-card h6 { color: var(--ui-text) !important; }

/* --- Pastilles de periode ------------------------------------------------ */
.timeframe-pill {
    border-radius: var(--ui-radius-pill);
    padding: 5px 14px;
    font-size: 12px;
    font-weight: 600;
    border: 1px solid var(--ui-border);
    background: transparent;
    color: var(--ui-text-muted);
    transition: all 0.2s ease;
}
.timeframe-pill:hover { border-color: var(--ui-border-strong); color: var(--ui-text-body); }
.timeframe-pill.active {
    background: var(--ui-accent-2);
    border-color: var(--ui-accent-2);
    color: #FFFFFF;
}


/* =========================================================================
   4. RESPONSIVE
   =========================================================================
   Les corrections portent sur ce qui casse reellement : le rapport 1/1 sur
   un telephone, les tableaux larges, et les grilles qui gardent quatre
   colonnes sur une tablette.
   ========================================================================= */

/* Sous 576 px la carte occupe toute la largeur. Un rapport 1/1 en ferait un
   bloc de 340 px de haut par indicateur : quatre indicateurs deviendraient
   un mur a faire defiler. On rend la hauteur au contenu. */
@media (max-width: 575.98px) {
    #kpi-grid > [class*="col-"] > .futuristic-card,
    .kpi-square {
        min-height: 0;
        padding: 16px !important;
    }
    #kpi-grid .bus-stat-count { margin: 10px 0 !important; }
}

/* Entre 576 et 1200 px les cartes vont par deux. Le rapport 1/1 tiendrait
   mais donnerait des cartes de 350 px de haut sur une tablette. */
@media (min-width: 576px) and (max-width: 1199.98px) {
    #kpi-grid > [class*="col-"] > .futuristic-card,
    .kpi-square { min-height: 168px; }
}

/* Un tableau ne se comprime pas : sous une certaine largeur il faut le
   laisser defiler, sinon les colonnes se chevauchent et deviennent
   illisibles. */
@media (max-width: 991.98px) {
    .responsive-table,
    .table-responsive {
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
    }
    .responsive-table > table,
    .table-responsive > table { min-width: 680px; }
}

/* La page elle-meme ne doit jamais defiler horizontalement : c'est toujours
   un debordement accidentel, jamais une intention. */
html, body { overflow-x: hidden; }

/* Les graphiques ont besoin d'une hauteur declaree : un canvas sans hauteur
   s'effondre a zero des que son parent est en `flex`. */
@media (max-width: 767.98px) {
    #revenueChartCard canvas,
    .futuristic-card canvas { max-height: 240px !important; }
}


/* =========================================================================
   5. CORRECTIONS DE DEFAUTS CONSTATES
   ========================================================================= */

/* --- Les notifications n'apparaissaient JAMAIS -------------------------
   Bootstrap 5 declare `.toast:not(.show) { display: none }`. toastr pose la
   classe `toast` sur chaque notification mais n'y ajoute jamais `show`, et sa
   propre feuille ne redeclare pas `display`. Resultat : les 43 appels
   `toastr.success/error/warning` du projet — dont TOUS les messages de
   confirmation et d'erreur apres un enregistrement — etaient invisibles, en
   clair comme en sombre.

   Le selecteur d'origine (`.toast:not(.show)`, specificite 0-2-0) est battu
   par `#toast-container > div` (1-0-1), sans `!important`. */
#toast-container > div {
    display: block;
}

/* --- La couleur du montant portait l'information a l'envers -------------
   `body.dark-mode .bus-stat-count { color: #FF8800 }` peignait les quatre
   indicateurs en orange. Or les cartes portent deja une distinction : glow
   emeraude pour ce qui entre (ventes, revenus), glow orange pour ce qui sort
   (achats, depenses). Peindre les quatre montants de la meme couleur effaçait
   cette lecture — la seule qui compte d'un coup d'oeil.

   Le montant prend donc l'accent de sa carte : vert ce qui entre, orange ce
   qui sort. On lit le sens du flux avant meme d'avoir lu le chiffre. */
#kpi-grid .glow-emerald-card .bus-stat-count { color: var(--ui-accent) !important; }
#kpi-grid .glow-orange-card  .bus-stat-count { color: var(--ui-accent-2) !important; }

body.dark-mode #kpi-grid .glow-orange-card .bus-stat-count { color: #FF8800 !important; }

/* En clair, l'emeraude et l'orange de marque tombent autour de 3:1 sur du
   blanc. C'est la limite AA pour du grand texte, et le chiffre est en 30 px
   gras — il passe, mais sans marge. On fonce d'un cran plutot que de rester
   sur le fil. */
body:not(.dark-mode) #kpi-grid .glow-emerald-card .bus-stat-count { color: #047857 !important; }
body:not(.dark-mode) #kpi-grid .glow-orange-card  .bus-stat-count { color: #C2410C !important; }

/* --- La courbe de fond passait a travers la pastille -------------------
   A 60 % d'opacite sur 38 % de hauteur, le trace croisait la pastille de
   variation et la ligne « vs last month ». La pastille restait au-dessus
   (z-index), mais l'ensemble devenait illisible. La courbe est un decor :
   elle doit se deviner, pas se lire. */
#kpi-grid .card-sparkline-bg {
    height: 32%;
    opacity: 0.38;
}
.futuristic-card:hover .card-sparkline-bg { opacity: 0.55; }

/* La pastille et son libelle reposent sur la surface, pas sur la courbe. */
#kpi-grid .badge-neon-emerald,
#kpi-grid .badge-neon-orange {
    position: relative;
    z-index: 2;
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
}

/* L'animation de scintillement sur une pastille permanente attire l'oeil en
   continu vers une information secondaire, et gene la lecture du chiffre. */
#kpi-grid .badge-neon-emerald,
#kpi-grid .badge-neon-orange { animation: none !important; }


/* =========================================================================
   6. MODE CLAIR — les boites et leur ombre
   =========================================================================
   Quatre constats mesures sur le rendu, pas supposes :

   1. Le fond de page etait `radial-gradient(circle at top right, #FFF, #F4F6F8)`.
      Les cartes d'indicateurs sont EN HAUT A DROITE — exactement la ou le
      degrade vaut #FFFFFF. Des cartes blanches sur du blanc : rien ne se
      detachait, quelle que soit l'ombre.

   2. L'ombre valait `0 4px 16px rgba(15,23,42,0.06)`. A 6 % d'opacite sur un
      seul plan, elle ne porte pas : une carte ne flotte pas, elle est posee.

   3. Le rayon valait 14 px en clair (`body:not(.dark-mode) .card`, plus
      specifique) contre 18 px en sombre. Les deux modes n'avaient pas la meme
      geometrie.

   4. La courbe de fond teintait la carte a 38 % : les boites etaient vertes ou
      orangees, pas blanches.
   ========================================================================= */

/* 1. Un fond franc, uniforme. C'est lui qui fait exister les boites. */
body:not(.dark-mode) {
    background: var(--ui-bg) !important;
    background-attachment: fixed !important;
}

/* 2. Une ombre a deux plans.
      Le plan rapproche donne l'arete, le plan lointain donne la hauteur. Une
      ombre a un seul plan doit choisir entre les deux et n'obtient ni l'un ni
      l'autre. */
:root {
    --ui-shadow:    0 1px 3px rgba(16, 24, 40, 0.05), 0 6px 16px -4px rgba(16, 24, 40, 0.10);
    --ui-shadow-lg: 0 2px 6px rgba(16, 24, 40, 0.06), 0 16px 32px -8px rgba(16, 24, 40, 0.16);
}

/* 3 et 4. Geometrie identique dans les deux modes, surface blanche franche.
      La specificite monte a hauteur de `body:not(.dark-mode) .card`, qui
      imposait 14 px — a `!important` egal, c'est la specificite qui tranche. */
body:not(.dark-mode) .futuristic-card,
body:not(.dark-mode) .erp-table-section .futuristic-card {
    background: var(--ui-surface) !important;
    border-radius: var(--ui-radius) !important;
    /* Pas de bordure : dans la maquette, c'est l'ombre seule qui detache la
       boite. Une bordure ajoutee par-dessus durcit l'arete et fait perdre
       l'impression de relief. */
    border: 0 !important;
    box-shadow: var(--ui-shadow) !important;
}

body:not(.dark-mode) .futuristic-card:hover,
body:not(.dark-mode) .erp-table-section .futuristic-card:hover {
    box-shadow: var(--ui-shadow-lg) !important;
    border: 0 !important;
}

/* La courbe redevient un decor : la boite doit se lire blanche. */
body:not(.dark-mode) #kpi-grid .card-sparkline-bg { opacity: 0.20; }
body:not(.dark-mode) #kpi-grid .futuristic-card:hover .card-sparkline-bg { opacity: 0.32; }

/* La pastille d'icone est le seul aplat colore de la carte, comme dans la
   maquette : un carre arrondi teinte, discret. */
body:not(.dark-mode) #kpi-grid .stat-icon-wrapper.emerald {
    background: rgba(16, 185, 129, 0.10) !important;
    color: #047857 !important;
}
body:not(.dark-mode) #kpi-grid .stat-icon-wrapper.orange {
    background: rgba(255, 107, 0, 0.10) !important;
    color: #C2410C !important;
}

/* Les autres surfaces de page suivent la meme regle : une boite blanche,
   posee sur le gris, detachee par l'ombre — et non cernee d'un trait. */
body:not(.dark-mode) .erp-table-section > .container-fluid > .card,
body:not(.dark-mode) .erp-table-section .card.shadow-sm {
    background: var(--ui-surface) !important;
    border: 0 !important;
    border-radius: var(--ui-radius) !important;
    box-shadow: var(--ui-shadow) !important;
}

/* Le liseré de verre n'appartient qu'au mode sombre. Sur du blanc il
   dessinerait un trait gris en travers du haut de chaque carte. */
body:not(.dark-mode) .futuristic-card::before { content: none !important; }


/* =========================================================================
   7. GEOMETRIE IDENTIQUE DANS LES DEUX MODES
   =========================================================================
   `custom.css` porte :

       body.dark-mode .card,
       body.dark-mode .erp-table-section .card { border-radius: 14px !important; ... }

   Specificite 0-2-1, contre 0-1-0 pour `.futuristic-card`. A `!important`
   egal, c'est la specificite qui tranche : les cartes valaient 14 px en
   sombre et 18 px en clair. Deux modes, deux geometries.

   La regle ci-dessous monte a la meme specificite. A specificite ET
   importance egales, c'est l'ordre de chargement qui departage — et cette
   feuille est chargee en dernier, par construction.
   ========================================================================= */

body.dark-mode .futuristic-card,
body.dark-mode .erp-table-section .futuristic-card {
    border-radius: var(--ui-radius) !important;
    box-shadow: var(--ui-shadow) !important;
    border: 1px solid var(--ui-border) !important;
}

body.dark-mode .futuristic-card:hover,
body.dark-mode .erp-table-section .futuristic-card:hover {
    box-shadow: var(--ui-shadow-lg), 0 0 24px rgba(16, 185, 129, 0.10) !important;
    border-color: var(--ui-border-strong) !important;
}

/* L'ombre sombre est propre au mode : celle du mode clair, calee sur un gris
   bleute, disparait sur un fond sombre. On la redeclare ici plutot que dans
   `:root`, ou elle serait ecrasee par la section precedente. */
body.dark-mode {
    --ui-shadow:    0 8px 28px rgba(0, 0, 0, 0.38);
    --ui-shadow-lg: 0 16px 44px rgba(0, 0, 0, 0.48);
}

/* Les cartes a halo gardent leur teinte, mais elle s'ajoute a l'ombre au lieu
   de la remplacer : sans le plan sombre, la carte perd son relief et ne garde
   qu'une lueur verte flottante. */
body.dark-mode .glow-emerald-card {
    box-shadow: var(--ui-shadow), 0 0 25px rgba(16, 185, 129, 0.16) !important;
}
body.dark-mode .glow-orange-card {
    box-shadow: var(--ui-shadow), 0 0 25px rgba(255, 107, 0, 0.14) !important;
}


/* =========================================================================
   8. ORANGE EN MODE SOMBRE — PRIX ET BOUTONS D'ACTION
   =========================================================================
   Les montants reviennent a l'orange de marque. Cela retire la distinction
   entrant / sortant que portait la couleur du chiffre ; c'est un choix
   assume, demande explicitement. Les cartes gardent leur halo (emeraude a
   gauche, orange a droite), qui porte toujours ce sens.

   POUR LES BOUTONS, LA COULEUR DU TEXTE N'EST PAS LIBRE.

   Mesure sur l'orange de marque #FF6B00 :

       texte blanc  ->  2,86:1   sous le minimum, meme pour du grand texte
       texte sombre ->  6,61:1   confortable

   L'autre voie — foncer l'orange jusqu'a ce que le blanc passe — donne
   #C2410C, qui ne ressort plus qu'a 3,2:1 contre la page sombre : un bouton
   terne, et ce n'est plus l'orange de la marque. On garde donc l'orange vif
   et on encre le texte.
   ========================================================================= */

body.dark-mode {
    --ui-orange-ink: #1A0E02;
}

/* --- Les montants --- */
body.dark-mode .bus-stat-count,
body.dark-mode .money-text,
body.dark-mode #overall_purchase,
body.dark-mode #overall_sale,
body.dark-mode #overall_income,
body.dark-mode #overall_expense,
body.dark-mode .amount-container,
body.dark-mode .amount-info-container,
body.dark-mode #kpi-grid .glow-emerald-card .bus-stat-count,
body.dark-mode #kpi-grid .glow-orange-card .bus-stat-count {
    color: #FF8800 !important;
}

/* --- Les boutons d'action ---
   Seuls les boutons d'ACTION passent a l'orange : valider, enregistrer,
   ajouter. Les boutons de danger restent rouges et les boutons secondaires
   restent neutres — repeindre tout en orange ferait perdre la hierarchie qui
   dit lequel est le bouton principal. */
body.dark-mode .btn-primary,
body.dark-mode .btn-futuristic-emerald,
body.dark-mode .btn-futuristic-orange,
body.dark-mode .btn-clario-submit,
body.dark-mode .theme-btn,
body.dark-mode .submit-btn {
    background: var(--ui-accent-2) !important;
    background-image: none !important;
    border-color: var(--ui-accent-2) !important;
    color: var(--ui-orange-ink) !important;
    font-weight: 700;
}

body.dark-mode .btn-primary:hover,
body.dark-mode .btn-futuristic-emerald:hover,
body.dark-mode .btn-futuristic-orange:hover,
body.dark-mode .btn-clario-submit:hover,
body.dark-mode .theme-btn:hover,
body.dark-mode .submit-btn:hover {
    background: #FF8800 !important;
    border-color: #FF8800 !important;
    color: var(--ui-orange-ink) !important;
}

/* Une icone posee dans le bouton herite du texte : sans cette ligne elle
   resterait blanche sur l'orange, seule et illisible. */
body.dark-mode .btn-primary i,
body.dark-mode .btn-futuristic-emerald i,
body.dark-mode .btn-clario-submit i,
body.dark-mode .theme-btn i,
body.dark-mode .submit-btn i,
body.dark-mode .btn-primary svg,
body.dark-mode .btn-clario-submit svg {
    color: var(--ui-orange-ink) !important;
    fill: currentColor;
}

/* Un bouton desactive ne doit pas garder l'eclat d'un bouton actif : on le
   desature au lieu de baisser seulement son opacite, sinon il reste le point
   le plus lumineux d'un ecran ou il n'est plus cliquable. */
body.dark-mode .btn-primary:disabled,
body.dark-mode .btn-clario-submit:disabled,
body.dark-mode .theme-btn:disabled,
body.dark-mode .submit-btn:disabled {
    background: rgba(255, 107, 0, 0.28) !important;
    border-color: rgba(255, 107, 0, 0.28) !important;
    color: rgba(255, 255, 255, 0.55) !important;
}

/* La pastille de periode active du tableau de bord suit la meme regle. */
body.dark-mode .timeframe-pill.active {
    background: var(--ui-accent-2);
    border-color: var(--ui-accent-2);
    color: var(--ui-orange-ink);
    font-weight: 700;
}


/* =========================================================================
   9. BARRE DU HAUT — ESPACEMENT, LARGEUR, LISIBILITE
   =========================================================================
   Quatre defauts distincts, mesures sur le rendu.

   1. LA LANGUE ET LE THEME SE TOUCHAIENT. Deux causes qui s'ajoutaient :
      le groupe de droite n'avait AUCUN `gap` — les ecarts etaient poses a la
      main par des `me-2` sur certains elements et rien sur d'autres — et
      surtout `.language-change` portait `width: 55px`, une largeur fixe
      heritee de l'epoque ou le selecteur n'affichait qu'un drapeau. Il porte
      maintenant « French » : le bouton deborde de sa boite et vient mordre le
      bouton suivant. Elargir l'ecart seul n'aurait pas suffi.

   2. LA BARRE N'OCCUPAIT PAS LA LARGEUR. `.futuristic-search-bar` est fixe a
      280 px. Sur un grand ecran, le milieu reste vide.

   3. LE CHAMP DE RECHERCHE ETAIT ILLISIBLE EN MODE CLAIR :
      `body:not(.dark-mode) .futuristic-search-bar input { color: #FFFFFF }`
      sur un en-tete blanc — soit 1,00:1. Le texte tape n'apparaissait pas.

   4. Le marque-place tenait a 2,56:1, sous le minimum.
   ========================================================================= */

/* --- Structure ---------------------------------------------------------- */
/* `.gap-2` est pose sur ce conteneur dans le Blade et vaut `gap: .5rem
   !important`. Il faut donc le meme poids pour que les deux groupes ne se
   touchent pas — sinon l'ecart reste bloque a 8 px. */
.main-header-section > .d-flex {
    gap: 14px !important;
    column-gap: 18px !important;
}

/* Le groupe de gauche prend la place disponible, le groupe de droite garde la
   sienne. Sans `min-width: 0`, un enfant en `flex` refuse de retrecir sous sa
   largeur de contenu et pousse le reste hors de l'ecran. */
.main-header-section > .d-flex > .d-flex:first-child {
    flex: 1 1 auto;
    min-width: 0;
}

.main-header-section > .d-flex > .d-flex:last-child {
    /* L'ecart qui manquait. Il remplace les `me-2` disperses, qui laissaient
       les paires non couvertes collees.

       `!important` n'est pas une facilite ici : la classe Bootstrap `.gap-2`
       posee sur le conteneur declare `gap: .5rem !important`. Sans le meme
       poids, l'ecart retombait a 8 px des que cette regle pouvait s'appliquer
       — mesure a 500 px de large. */
    gap: 12px !important;
    flex: 0 0 auto;
    flex-wrap: wrap;
    row-gap: 8px !important;
}

/* Les marges posees a la main font double emploi avec le `gap` et decalent
   l'alignement d'un element sur deux. */
.main-header-section .theme-toggle-btn.me-2,
.main-header-section .btn-futuristic-orange.me-2 {
    margin-right: 0 !important;
}

/* --- Selecteur de langue ------------------------------------------------- */
.language-change {
    width: auto !important;
    flex: 0 0 auto;
}
.language-change .dropdown-toggle {
    white-space: nowrap;
}

/* --- La recherche occupe la place libre ---------------------------------- */
.futuristic-search-bar {
    flex: 1 1 240px;
    /* Un plafond : au-dela, un champ de recherche de 800 px de large n'aide
       personne et eloigne le bouton d'action du bord de l'ecran. */
    max-width: 420px;
    min-width: 0;
    width: auto;
}

/* --- Lisibilite du champ en mode clair ----------------------------------- */
body:not(.dark-mode) .futuristic-search-bar input {
    background: var(--ui-surface-2) !important;
    border-color: var(--ui-border) !important;
    color: var(--ui-text) !important;
}
body:not(.dark-mode) .futuristic-search-bar input::placeholder {
    color: #64748B !important;
}
body:not(.dark-mode) .futuristic-search-bar i {
    color: #64748B;
}

/* --- Visibilite du bouton clair/sombre en mode CLAIR ---------------------
   `custom.css:1406` peint ce bouton en #10B981 sur rgba(16,185,129,.15) sans
   variante claire. En sombre le disque est fonce, l'icone ressort. En clair
   le disque devient un blanc casse : l'icone tombe a 2,23:1, sous le seuil
   de 3:1 que la WCAG 1.4.11 demande pour un composant d'interface — d'ou un
   bouton qu'on devine plus qu'on ne le voit.

   On garde l'emeraude de marque mais a la valeur 700 (#047857), qui donne
   5,24:1 sur le disque : lisible meme si on le comptait comme du texte. */
body:not(.dark-mode) .theme-toggle-btn {
    background: rgba(16, 185, 129, 0.10);
    border-color: rgba(4, 120, 87, 0.40);
    color: #047857;
}
body:not(.dark-mode) .theme-toggle-btn:hover {
    background: #047857;
    color: #FFFFFF;
    box-shadow: 0 0 15px rgba(4, 120, 87, 0.35);
}

/* =========================================================================
   RESPONSIVE DE LA BARRE
   =========================================================================
   On retire par ordre d'utilite decroissante, plutot que de laisser les
   elements se tasser puis se chevaucher.
   ========================================================================= */

/* Sous 1400 px, le libelle de la langue s'efface — le drapeau suffit a dire
   laquelle est active, et c'est lui qu'on reconnait en premier. */
@media (max-width: 1399.98px) {
    .language-change .lang-name { display: none; }
    .language-change .flag-icon { margin-right: 0 !important; }
    .language-change .dropdown-toggle { padding-left: 10px; padding-right: 10px; }
}

/* Sous 1200 px, le nom de la boutique passe sur une seule ligne courte plutot
   que de pousser l'avatar hors du cadre. */
@media (max-width: 1199.98px) {
    .main-header-section .nav-name,
    .main-header-section .nav-greeting {
        max-width: 140px;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
}

/* Sous 992 px la recherche disparait deja (`d-none d-lg-block`) : le groupe de
   gauche n'a plus a s'etirer, sinon il laisse un trou au milieu. */
@media (max-width: 991.98px) {
    .main-header-section > .d-flex > .d-flex:first-child { flex: 0 1 auto; }
    .main-header-section > .d-flex { column-gap: 12px; }
}

/* Sur telephone, les deux groupes occupent chacun une ligne pleine et se
   repartissent dessus. C'est le comportement qui manquait : ils restaient
   tasses a gauche en laissant le cote droit vide. */
@media (max-width: 575.98px) {
    .main-header-section { padding: 10px 14px; }
    .main-header-section > .d-flex > .d-flex {
        flex: 1 1 100%;
        justify-content: space-between;
    }
    .main-header-section > .d-flex > .d-flex:last-child { gap: 8px; }
    .main-header-section .live-status-pill { display: none !important; }
}


/* =========================================================================
   10. LA BARRE RESTE SUR UNE LIGNE
   =========================================================================
   Mesure a 1100 px et a 820 px : les deux groupes passaient sur DEUX lignes,
   avec le second tasse a gauche et du vide a droite. C'est ce que montre la
   capture d'ecran.

   LA CAUSE EST STRUCTURELLE, PAS UNE AFFAIRE DE QUELQUES PIXELS.

   Le conteneur porte `flex-wrap: wrap`. En disposition flex, les elements sont
   places sur une ligne d'apres leur taille de BASE ; si la somme depasse le
   conteneur, ils passent a la ligne. Le retrecissement (`flex-shrink`)
   n'intervient qu'ENSUITE, a l'interieur d'une ligne — il n'a donc jamais sa
   chance. Elargir ou reduire un element ne change rien tant que
   l'enveloppement precede le retrecissement.

   On interdit donc l'enveloppement au-dessus du telephone, et on rend les
   groupes retrecissables. La recherche absorbe la compression : c'est le seul
   element dont la largeur n'a pas de signification propre.
   ========================================================================= */

@media (min-width: 768px) {
    .main-header-section > .d-flex {
        flex-wrap: nowrap !important;
    }

    /* `min-width: 0` est indispensable : sans lui, un enfant flex refuse de
       passer sous la largeur de son contenu, et la barre deborde au lieu de
       se comprimer. */
    .main-header-section > .d-flex > .d-flex:first-child {
        flex: 1 1 auto;
        min-width: 0;
        overflow: hidden;
    }

    .main-header-section > .d-flex > .d-flex:last-child {
        flex: 0 0 auto;
        flex-wrap: nowrap;
    }

    /* La recherche se comprime en premier et jusqu'au bout : un champ de
       recherche etroit reste utilisable, un bouton tronque ne l'est pas. */
    .futuristic-search-bar {
        flex: 1 1 0%;
        min-width: 0;
    }
}

/* Sous 1200 px, le lien « Voir le site web » cede sa place. Il double le
   contenu du menu lateral, alors que le selecteur de langue et le bouton de
   commande n'ont pas d'equivalent ailleurs dans la barre. */
@media (max-width: 1199.98px) {
    .main-header-section .view-website { display: none !important; }
}

/* Sur telephone, l'enveloppement redevient souhaitable : deux lignes pleines
   valent mieux qu'une ligne illisible. Chaque groupe occupe alors toute la
   largeur et repartit ses elements — c'est ce qui manquait, ils restaient
   tasses a gauche.

   POURQUOI 640 px ET NON LE PALIER `sm` DE BOOTSTRAP (576 px).

   Sous 768 px, `style.css:1110` efface le burger et le remplace par
   `.pos-logo`, large de 120 px. Mesure a 576 px : le groupe de gauche tombait
   a 70 px et `overflow: hidden` tranchait le logo en deux. Le logo n'est pas
   compressible — c'est une image de marque — et le groupe de droite ne cede
   rien puisqu'il est en `flex: 0 0 auto`. Le seuil d'enveloppement doit donc
   se placer la ou le logo cesse de tenir, pas sur un palier de grille pris
   par habitude. A 640 px le groupe de gauche mesure 134 px : le logo passe. */
@media (max-width: 767.98px) {
    .main-header-section > .d-flex { flex-wrap: wrap !important; }

    /* Enveloppement seul ne suffit pas, et c'est ce qui manquait : un groupe
       seul sur sa ligne reste a sa largeur de contenu, et `space-between` n'a
       alors rien a repartir — il se colle a gauche en laissant le reste vide.
       C'est exactement ce que montrait la capture.

       On force donc chaque groupe a prendre la ligne entiere, puis on demande
       au groupe de commandes de repartir ses elements d'un bord a l'autre.

       Les deux pseudo-classes sont reprises telles quelles : la section 9
       cible `:first-child` et `:last-child`, plus specifiques qu'un selecteur
       qui s'arreterait a `.d-flex`. Ecrit sans elles, ce bloc n'avait aucun
       effet malgre sa position plus bas dans le fichier — la specificite
       l'emporte sur l'ordre. */
    .main-header-section > .d-flex > .d-flex:first-child,
    .main-header-section > .d-flex > .d-flex:last-child {
        flex: 1 0 100%;
        min-width: 0;
    }

    .main-header-section > .d-flex > .d-flex:last-child {
        justify-content: space-between;
    }
}

/* Ceinture et bretelles : meme si la place venait a manquer, le logo garde sa
   taille plutot que de se laisser ecraser par ses voisins. */
.main-header-section .pos-logo {
    flex: 0 0 auto;
}


/* =========================================================================
   11. LIBELLES DE FORMULAIRE — LES BANDES BLANCHES EN MODE SOMBRE
   =========================================================================
   CE QUE L'ON VOYAIT : sous « Nom du produit », « Categorie », « Quantite »
   et une dizaine d'autres, un rectangle blanc franc sur le panneau sombre.

   LA CAUSE. `style.css:2492` habille ces libelles en encoche : le libelle
   chevauche la bordure haute du champ (`position: relative; top: 11px`) et la
   coupe grace a un fond opaque, `background: #fff`. Sur une carte blanche on
   ne voit que l'entaille ; sur un panneau sombre, on voit le rectangle.

   `custom.css:2283` et `custom.css:3309` reprenaient bien ces libelles en mode
   sombre — mais pour leur COULEUR DE TEXTE seulement. Le fond blanc n'a jamais
   ete repris, et aucune regle sombre ne le mentionnait.

   LA COULEUR. Ce n'est pas le verre depoli de la carte qui est derriere le
   libelle : `custom.css:2216` peint `.order-form-section` en
   `--clario-dark-surface` opaque, et cette couche masque le verre. Les modales
   (`custom.css:2297`) portent la meme valeur. Une seule couleur suffit donc, et
   c'est celle que `body.dark-mode .header-label` et
   `body.dark-mode .custom-from-to label` employaient deja — les deux seuls
   libelles de ce type qui avaient ete corriges.

   Le mode clair n'est pas touche : `.order-form-section` n'a pas de fond
   propre, elle herite de la carte blanche, et l'encoche blanche y est juste.
   ========================================================================= */

body.dark-mode .order-form-section label,
body.dark-mode .permission label,
body.dark-mode .role-input-label label,
body.dark-mode .modal-body label,
body.dark-mode label.upload-img-label,
body.dark-mode .custom-upload-label {
    background: var(--ui-card, #0B221A) !important;
}

/* Celui-ci n'est pas une encoche : `style.css:3030` en fait une zone de depot
   de 130 px de haut, dont le blanc est le remplissage. Il lui faut donc aussi
   une bordure sombre, sans quoi le gris clair `#d4d4d4` reste. */
body.dark-mode .upload-img-v2 label {
    background: var(--ui-card, #0B221A) !important;
    border-color: var(--ui-border, rgba(255, 255, 255, 0.12)) !important;
}


/* =========================================================================
   12. SITE PUBLIC — TEXTES ET PASTILLES ILLISIBLES
   =========================================================================

   12.1 LE TITRE DE LA VITRINE COD, MESURE A 1,16:1

   `custom.css` porte :

       body:not(.dark-mode) .futuristic-card .text-white { color: #0F172A }

   L'intention est juste : en mode clair une `futuristic-card` est blanche, et
   un texte blanc y serait invisible. Mais la page d'accueil publique n'a pas
   la classe `dark-mode`, et sa vitrine COD place un panneau `bg-dark` DANS une
   `futuristic-card`. La regle repeint alors en #0F172A un texte pose sur
   #212529 : 1,16:1, soit un titre qu'on ne lit plus du tout.

   On ne touche pas a la regle d'origine, qui reste bonne partout ailleurs. On
   rend simplement sa place au blanc la ou le fond est explicitement sombre.
   ========================================================================= */

body:not(.dark-mode) .futuristic-card .bg-dark .text-white,
body:not(.dark-mode) .futuristic-card .bg-dark.text-white,
body:not(.dark-mode) .futuristic-card .bg-black .text-white,
body:not(.dark-mode) .futuristic-card .bg-black.text-white {
    color: #FFFFFF !important;
}

/* Sur fond sombre, `text-muted` (#6C757D) tombe a 4,0:1 — sous le minimum
   pour du texte courant. On l'eclaircit, uniquement dans ce contexte. */
body:not(.dark-mode) .futuristic-card .bg-dark .text-muted,
body:not(.dark-mode) .futuristic-card .bg-black .text-muted {
    color: #C7CDD4 !important;
}

/* -------------------------------------------------------------------------
   12.2 LES PASTILLES JAUNE SUR JAUNE, MESUREES A 1,00:1

   Les gabarits emploient `bg-opacity-20`, `bg-opacity-15`, `bg-opacity-5`,
   `border-opacity-15` et `border-opacity-20`. AUCUNE DE CES CLASSES N'EXISTE :
   Bootstrap ne fournit que les paliers 10, 25, 50, 75 et 100. La classe est
   donc ignoree en silence, `--bs-bg-opacity` reste a 1, et
   `bg-warning + text-warning` donne du jaune sur du jaune.

   Deux corrections possibles : retoucher 21 endroits dans les gabarits, ou
   fournir les paliers manquants. La seconde tient en six lignes, couvre les
   emplois futurs, et laisse le balisage exprimer ce qu'il voulait dire.
   ------------------------------------------------------------------------- */

.bg-opacity-5   { --bs-bg-opacity: 0.05; }
.bg-opacity-15  { --bs-bg-opacity: 0.15; }
.bg-opacity-20  { --bs-bg-opacity: 0.20; }
.border-opacity-15 { --bs-border-opacity: 0.15; }
.border-opacity-20 { --bs-border-opacity: 0.20; }


/* =========================================================================
   13. BOUTONS BOOTSTRAP EN MODE SOMBRE
   =========================================================================
   MESURE AVANT CORRECTION : `btn-outline-primary`, `-secondary`, `-danger` et
   `-success` affichaient tous du NOIR PUR sur le panneau #0B221A, soit
   1,26:1. Le texte n'etait pas seulement difficile a lire : il etait absent a
   l'oeil. Seule la bordure coloree trahissait la presence du bouton.

   LA CAUSE, `style.css:136` :

       a, button, .btn, ol li a, ul li a { color: #000000; }

   Bootstrap fait porter la couleur d'un bouton par `--bs-btn-color`, lu par
   `.btn { color: var(--bs-btn-color) }`. La regle ci-dessus a la MEME
   specificite (0,1,0) et se charge APRES : elle gagne, et fixe tous les
   boutons au noir, quelle que soit leur variante et quel que soit le mode.
   En clair sur fond blanc cela passe inapercu ; en sombre, tout disparait.

   La section 8 avait deja traite `.btn-primary` et les boutons maison. Elle
   n'avait pas couvert les variantes Bootstrap, que le module COD emploie
   43 fois a lui seul.

   LE CHOIX DES COULEURS. `outline-primary` porte l'action principale : il
   passe a l'orange Clario, ce qui rejoint ce que l'on attend de ces boutons.
   Les autres gardent leur sens — neutre, rouge, emeraude — a une valeur
   remontee pour tenir sur fond sombre. La bordure reprend la couleur du
   texte, comme le veut un bouton en contour.
   ========================================================================= */

/* --- Boutons en contour --------------------------------------------------- */
body.dark-mode .btn-outline-primary {
    color: var(--ui-accent-2, #FF6B00) !important;   /* mesure 5,85:1 */
    border-color: var(--ui-accent-2, #FF6B00) !important;
    background-color: transparent !important;
}
body.dark-mode .btn-outline-primary:hover,
body.dark-mode .btn-outline-primary:focus,
body.dark-mode .btn-outline-primary:active {
    color: var(--ui-orange-ink, #1A0E02) !important;
    background-color: var(--ui-accent-2, #FF6B00) !important;
    border-color: var(--ui-accent-2, #FF6B00) !important;
}

body.dark-mode .btn-outline-secondary {
    color: #CBD5E1 !important;                        /* mesure 11,25:1 */
    border-color: rgba(203, 213, 225, 0.55) !important;
    background-color: transparent !important;
}
body.dark-mode .btn-outline-secondary:hover,
body.dark-mode .btn-outline-secondary:focus,
body.dark-mode .btn-outline-secondary:active {
    color: #0B221A !important;
    background-color: #CBD5E1 !important;
    border-color: #CBD5E1 !important;
}

body.dark-mode .btn-outline-danger {
    color: #F87171 !important;                        /* mesure 6,04:1 */
    border-color: #F87171 !important;
    background-color: transparent !important;
}
body.dark-mode .btn-outline-danger:hover,
body.dark-mode .btn-outline-danger:focus,
body.dark-mode .btn-outline-danger:active {
    color: #2A0B0B !important;
    background-color: #F87171 !important;
    border-color: #F87171 !important;
}

body.dark-mode .btn-outline-success {
    color: #34D399 !important;                        /* mesure 8,69:1 */
    border-color: #34D399 !important;
    background-color: transparent !important;
}
body.dark-mode .btn-outline-success:hover,
body.dark-mode .btn-outline-success:focus,
body.dark-mode .btn-outline-success:active {
    color: #04231A !important;
    background-color: #34D399 !important;
    border-color: #34D399 !important;
}

/* --- Boutons pleins -------------------------------------------------------
   Ceux-ci n'etaient pas invisibles, mais `btn-secondary` tombait a 4,48:1,
   juste sous le minimum. Le blanc, qui est ce que Bootstrap prevoit, les
   remonte tous au-dessus du seuil. */
body.dark-mode .btn-success,
body.dark-mode .btn-danger,
body.dark-mode .btn-secondary,
body.dark-mode .btn-info,
body.dark-mode .btn-dark {
    color: #FFFFFF !important;
}


/* =========================================================================
   14. LES CARTES ETIREES ET LES GRANDS VIDES VERTICAUX
   =========================================================================
   MESURE AVANT CORRECTION, sur le tableau de bord COD en 1280x800 : les cinq
   cartes faisaient 800 px de haut pour 28, 87, 87, 75 et 28 px de contenu.
   La page occupait 2542 px pour environ 300 px de matiere.

   LA CAUSE, `style.css:218` :

       .card { min-height: 100vh; }

   Toute carte, partout, fait au moins la hauteur de l'ecran. Une rangee de
   trois indicateurs devient trois colonnes d'un ecran de haut, et deux
   sections separees par un vide d'un ecran.

   LE THEME CROYAIT AVOIR RATTRAPE LE COUP. Deux regles annulent ce minimum :

       .erp-table-section.dashboard .card { min-height: 0 !important }   (l.1670)
       .card { min-height: 0 !important }  ... dans @media print          (l.7563)

   La premiere exige que la section porte AUSSI la classe `dashboard`. Or
   `erp-table-section dashboard` n'apparait dans AUCUNE des 198 vues du
   panneau : ce rattrapage ne s'est jamais applique une seule fois. La seconde
   ne vaut qu'a l'impression. Le minimum de 100vh etait donc actif partout,
   sur tout le panneau, depuis le debut.

   LA CORRECTION. On remet le comportement normal d'une carte : elle fait la
   hauteur de son contenu. `h-100` et les colonnes Bootstrap continuent
   d'egaliser les hauteurs d'une meme rangee, ce qui est le seul alignement
   dont ces grilles ont besoin.

   PORTEE. Ce changement touche tout le panneau, pas seulement le module COD.
   Les pages qui n'avaient qu'une seule carte paraissaient remplir l'ecran
   grace a ce minimum ; elles vont desormais s'arreter a leur contenu, le fond
   de page prenant le relais. C'est le comportement attendu, mais il vaut la
   peine d'y jeter un oeil apres mise en ligne.
   ========================================================================= */

.card {
    min-height: 0;
}

/* `.return-card` demandait explicitement 85vh avec `!important` : c'est un
   choix delibere, on ne le defait pas. */
/* Bootstrap fait de `.card` un conteneur flex en colonne. Un `span` y devient
   un element flex et s'etire sur toute la largeur : la pastille « 0 orders
   placed » traversait la carte au lieu d'epouser son texte. On lui rend sa
   largeur naturelle. */
.card > .badge,
.card > .badge-neon-orange,
.card > .badge-neon-emerald,
.card > span[class*="badge"] {
    align-self: flex-start;
}


/* =========================================================================
   15. L'ENTETE QUAND LA BARRE LATERALE EST OUVERTE
   =========================================================================
   MESURE AVANT CORRECTION, barre laterale ouverte : le lien « Voir le site
   web » mesurait 39 px de haut a 1600 px de fenetre, 64 px a 1440, et 89 px a
   1200 — soit deux, trois puis quatre lignes pour un libelle de quatre mots.

   DEUX CAUSES SE CUMULAIENT.

   1. LE LIEN SE COUPE A L'INTERIEUR. `.view-website` est un `inline-flex`
      contenant du texte et une icone. Le texte forme un element flex anonyme
      qui se replie des que la ligne est contrainte. Rien ne l'en empechait.

   2. MES SEUILS MESURAIENT LA MAUVAISE LARGEUR. `.side-bar` occupe 15 % et
      `.section-container` porte le `padding-left` correspondant : l'entete ne
      dispose que de 85 % de la fenetre. Une `@media (max-width: 1199.98px)`
      se declenche donc quand l'entete fait deja 1020 px, bien trop tard. A
      1440 px de fenetre l'entete ne mesure que 1171 px.

      S'y ajoute un element que le premier banc d'essai n'avait pas : le bouton
      de branche du module MultiBranchAddon, environ 150 px, present des qu'une
      boutique est active. C'est lui qui fait deborder la ligne.

   On corrige d'abord la coupure, qui est le defaut visible. Les seuils sont
   ensuite exprimes en tenant compte de la barre laterale : `.section-container`
   sans `.active` signifie barre deployee.
   ========================================================================= */

.main-header-section .view-website {
    white-space: nowrap;
    flex: 0 0 auto;
}

/* Le nom de la boutique pouvait prendre 162 px. On le borne, avec des points
   de suspension : l'identite reste lisible, la place rendue va a la recherche. */
.main-header-section .nav-name {
    max-width: 150px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* --- Ce qui cede, et dans quel ordre --------------------------------------
   Au-dessus de 1150 px la barre laterale occupe 15 % ; en dessous elle sort
   de l'ecran (`style.css:4829`) et l'entete retrouve toute la largeur. Les
   regles ci-dessous ne concernent donc que la bande ou la barre est deployee.

   Ordre de sacrifice, du moins utile au plus utile : le lien vers le site
   (que le menu lateral propose deja), puis la pastille de date (decorative),
   puis le libelle de langue (le drapeau suffit). La recherche se comprime en
   dernier — mesuree a 0 px avant ces regles, elle disparaissait purement et
   simplement alors qu'elle restait affichee. */
@media (min-width: 1151px) and (max-width: 1699.98px) {
    .section-container:not(.active) .main-header-section .view-website {
        display: none !important;
    }
}

@media (min-width: 1151px) and (max-width: 1399.98px) {
    .section-container:not(.active) .main-header-section .live-status-pill {
        display: none !important;
    }
}

@media (min-width: 1151px) and (max-width: 1299.98px) {
    .section-container:not(.active) .main-header-section .lang-name {
        display: none !important;
    }
}

/* Sous 1150 px la barre laterale sort de l'ecran et l'entete recupere toute
   la largeur — mais le contenu ne tient toujours pas : la recherche tombait a
   9 px a 1024 et a 0 px a 992, tout en restant affichee. La pastille de date
   cede ici aussi. */
@media (max-width: 1150px) {
    .main-header-section .live-status-pill { display: none !important; }
}


/* =========================================================================
   16. PAGE DE CONNEXION — LE VISUEL DE DROITE ETAIT ROGNE
   =========================================================================
   Le titre « De bons outils vous attendent chez Clario Cash » etait coupe net
   en haut du panneau.

   LA CAUSE. `custom.css:3816` pose :

       .auth-panel-img { width: 100%; height: 100%; object-fit: cover; }

   dans une boite `.auth-panel-column { height: 100vh }`. `cover` remplit la
   boite et ROGNE ce qui depasse, a parts egales en haut et en bas.

   Le visuel est un portrait 1086 x 1448, soit un rapport de 0,750. La boite,
   elle, vaut la moitie de la fenetre en largeur pour toute sa hauteur : 0,793
   a 1440x900, et jusqu'a 1,061 a 1354x640. Elle est donc toujours plus large
   que l'image, ce qui fait rogner en HAUTEUR — mesure a 1354x640 : 252 px
   perdus, 126 px en haut. Exactement la hauteur du titre.

   `cover` convient a une photo d'ambiance, dont on peut couper les bords sans
   rien perdre. Ce visuel-la porte du texte : il ne supporte aucun rognage.
   `contain` l'affiche en entier, quelle que soit la forme du cadre.

   Les marges laissees par `contain` prennent la teinte relevee sur les bords
   du fichier lui-meme (#023F1E en haut, #01371A en bas), ce qui les rend
   invisibles a la jonction.
   ========================================================================= */

/* `layouts/auth/app.blade.php:17` recharge `custom.css` APRES l'include qui
   amene ce fichier. Sur la page de connexion, clario-ui.css n'est donc plus le
   dernier servi : il faut le poids de `!important` pour que ces deux regles
   tiennent. */
.auth-panel-card {
    background-color: #023F1E !important;
}

.auth-panel-img {
    object-fit: contain !important;
    object-position: center;
}


/* =========================================================================
   17. LE GRAS ETAIT INVISIBLE EN MODE SOMBRE
   =========================================================================
   `style.css:2915` declare :

       b, strong { color: #191919 !important; }

   Avec `!important`, et sans contrepartie sombre. Tout mot mis en gras se
   peignait donc en gris tres fonce, quelle que soit la surface : mesure a
   1,05:1 sur un panneau #0B221A — invisible, pas seulement difficile a lire.

   La portee est totale : `<strong>` et `<b>` partout dans la plateforme. Le
   mode sombre ne le rattrapait qu'a deux endroits, tous deux dans les
   notifications (`custom.css:1490` et `2623`), ce qui montre que le defaut
   avait ete rencontre puis corrige au cas par cas plutot qu'a la racine.

   `inherit` plutot qu'une couleur fixe : le gras n'a pas de couleur propre,
   il prend celle de son contexte. Une valeur figee obligerait a la reprendre
   sur chaque fond particulier — pastille, bandeau, carte teintee — et
   reproduirait exactement le probleme qu'on corrige.
   ========================================================================= */

body.dark-mode b,
body.dark-mode strong {
    color: inherit !important;
}

/* --- Rouge d'alerte sur fond sombre --------------------------------------
   Le `#DC3545` de Bootstrap mesure 3,69:1 sur #0B221A, sous le minimum de
   4,5:1 pour du texte courant. La valeur 400 de la meme teinte donne 6,04:1
   — c'est celle deja retenue pour les boutons en contour de la section 13. */
body.dark-mode .text-danger {
    color: #F87171 !important;
}


/* =========================================================================
   18. FONCTIONNALITES HORS DU PLAN — VISIBLES, PAS CACHEES
   =========================================================================
   La grille tarifaire (§3) demande qu'une fonctionnalite non incluse reste
   « visible mais verrouillee avec un message expliquant le plan necessaire ».

   La cacher serait plus simple, et commercialement absurde : elle priverait
   le marchand de la seule chose qui pourrait le faire monter en gamme —
   savoir ce qu'il rate.

   L'entree reste donc en place, en retrait, avec un cadenas. Elle mene a la
   page des plans plutot qu'a une page interdite.

   L'opacite s'arrete a 0,55 : en dessous, le libelle passerait sous le seuil
   de contraste et le marchand ne lirait plus CE qu'il rate.
   ========================================================================= */

.side-bar-manu li.plan-locked > a,
li.plan-locked > a {
    opacity: 0.55;
}

li.plan-locked > a:hover {
    opacity: 0.8;
}

/* Les sous-entrees d'un menu verrouille n'ont plus lieu d'etre deroulees :
   elles menent toutes a des pages que le plan refuse. */
li.plan-locked > ul {
    display: none !important;
}

.plan-lock-icon {
    font-size: 0.78em;
    vertical-align: baseline;
}

/* Le cadenas ne doit pas se lire comme une alerte : il dit un etat, pas une
   erreur. On le laisse dans le gris de son contexte. */
body.dark-mode .plan-lock-icon { color: var(--ui-text-dim, #94A3B8); }
body:not(.dark-mode) .plan-lock-icon { color: var(--ui-text-muted, #64748B); }


/* =========================================================================
   19. LES BLOCS RESTES CLAIRS — INVENTAIRE, PAS RETOUCHE
   =========================================================================

   POURQUOI CETTE SECTION EXISTE APRES LES DIX-HUIT AUTRES.

   Chaque correction precedente repondait a une capture d'ecran : on voyait un
   bloc blanc, on ecrivait sa regle. La methode marche une fois et echoue
   toujours ensuite, parce qu'elle ne traite que ce qui a ete VU. C'est ce que
   l'entete de ce fichier appelle la peinture manuelle, et c'est exactement ce
   qui reproduisait le defaut ailleurs a chaque fois.

   On a donc procede autrement : relever dans `style.css` et `custom.css`
   CHAQUE regle qui pose un fond clair, la confronter a l'ensemble des
   selecteurs deja repeints sous `body.dark-mode`, et ne garder que la
   difference. Le releve donne 113 surfaces claires sans equivalent sombre.

   Sur ces 113 :
     -  57 appartiennent au theme d'origine et ne sont employees par AUCUNE
        vue — les repeindre aurait grossi le fichier sans rien changer a
        l'ecran ;
     -  12 simulent du PAPIER (apercu de facture A4) — voir plus bas, elles
        restent claires volontairement ;
     -  46 sont reellement a l'ecran. Elles sont ci-dessous, toutes.

   Les deux blocs blancs signales — la carte des reglages Super Admin
   (`.cards-header`) et le bandeau du resume des dus (`.loss-profit-container`)
   — sont dans ce lot. Ils n'ont rien de particulier : ils etaient simplement
   les deux qu'on avait sous les yeux.

   CE QUI RESTE CLAIR, ET POURQUOI.

   L'apercu de facture A4 represente une feuille de papier. Le passer en sombre
   afficherait a l'ecran autre chose que ce qui sortira de l'imprimante, ce qui
   est le contraire du but d'un apercu. `custom.css` force deja le blanc a
   l'impression ; l'apercu doit dire la meme chose. Sont donc ecartes
   `.invoice-content`, `.invoice-table thead/tfoot th`, `.invoice-footer`,
   `.erp-new-invice .invoice-text`, `.print-th`, `.in-print-btn`.

   En revanche la page du GENERATEUR de codes-barres est une interface, pas une
   etiquette : son menu deroulant et ses champs sont traites ici.
   ========================================================================= */


/* --- 19.1 Surfaces pleines ------------------------------------------------
   Les cartes, panneaux et conteneurs. `--ui-surface` pour ce qui repose sur le
   fond de page, `--ui-surface-2` pour ce qui repose sur une carte : sans cette
   distinction un menu deroulant ouvert au-dessus d'une carte disparaitrait
   dans elle, faute de difference de niveau. */
body.dark-mode .cards,
body.dark-mode .cards-header,
body.dark-mode .loss-profit-container,
body.dark-mode .bulk-upload-container,
body.dark-mode .empty-screen-container,
body.dark-mode .return-card,
body.dark-mode .tab-table-container,
body.dark-mode .transfer-amount-info,
body.dark-mode .incre-decre,
body.dark-mode .products .single-product,
body.dark-mode .mybazar-login-section .login-wrapper {
    background-color: var(--ui-surface) !important;
    border-color: var(--ui-border) !important;
    color: var(--ui-text-body) !important;
}

body.dark-mode .product-dropdown,
body.dark-mode .product-dropdown-options,
body.dark-mode .dropdown-options,
body.dark-mode .dropdown-selected,
body.dark-mode .barcode-dropdown,
body.dark-mode .x-btn,
body.dark-mode .multi-delete,
body.dark-mode .search-icon,
body.dark-mode .serial-item,
body.dark-mode .otp-select,
body.dark-mode .product-settings,
body.dark-mode .upload-product-img,
body.dark-mode .sidebar-free-plan a,
body.dark-mode .settings-image-upload .title,
body.dark-mode .input-select-wrapper select,
body.dark-mode .barcode-info h5,
body.dark-mode .barcode-table .input-date,
body.dark-mode .dashboard-table-content thead th,
body.dark-mode .in-table-row-bottom .total-amound,
body.dark-mode .mybazar-login-section .login-wrapper .input-group {
    background-color: var(--ui-surface-2) !important;
    border-color: var(--ui-border) !important;
    color: var(--ui-text-body) !important;
}

/* Un menu deroulant flotte : sans ombre il se confond avec ce qu'il recouvre,
   la difference de fond seule ne suffisant pas en sombre. */
body.dark-mode .product-dropdown,
body.dark-mode .product-dropdown-options,
body.dark-mode .dropdown-options,
body.dark-mode .barcode-dropdown {
    box-shadow: var(--ui-shadow-lg) !important;
}


/* --- 19.2 Survols ---------------------------------------------------------
   Le survol doit rester perceptible sans devenir un flash : un cran plus clair
   que la surface, jamais un blanc. */
body.dark-mode .x-btn:hover,
body.dark-mode .multi-items:hover,
body.dark-mode .product-option-item:hover,
body.dark-mode .dropdown-option:hover,
body.dark-mode .barcode-dropdown li:hover {
    background-color: var(--ui-surface-3) !important;
    color: var(--ui-text) !important;
}


/* --- 19.3 Barres de defilement internes ----------------------------------
   Un rail gris clair trace une ligne blanche verticale le long des listes de
   categories. */
body.dark-mode .category-brand-scroll::-webkit-scrollbar-track,
body.dark-mode .category-container::-webkit-scrollbar-track {
    background: var(--ui-surface-3) !important;
}


/* --- 19.4 Teintes porteuses de sens ---------------------------------------
   Ces fonds ne sont pas des surfaces : ce sont des signaux. Un rose pale dit
   « suppression », un vert pale dit « encaisse ». Les remplacer par la surface
   commune eteindrait l'information en meme temps que le blanc.

   On garde donc la teinte, en translucide sur le fond. Translucide et non
   opaque : ces blocs apparaissent tantot sur une carte, tantot sur le fond de
   page, et une valeur fixe serait juste sur l'un et fausse sur l'autre.

   Verifie : texte courant 11,3:1 sur la teinte rouge, le rouge lui-meme
   5,0:1 — au-dela des 4,5:1 exiges. */
body.dark-mode .alert-box,
body.dark-mode .delete-item .delete-item-show,
body.dark-mode .save-publish-btn,
body.dark-mode .trasfer-square-btn,
body.dark-mode .incre-decre:hover,
body.dark-mode .product-settings:hover,
body.dark-mode .plan-single-content:hover,
body.dark-mode .custom-modal .btn-no:hover {
    background-color: rgba(248, 113, 113, 0.14) !important;
    border-color: rgba(248, 113, 113, 0.30) !important;
    color: var(--ui-text-body) !important;
}

/* La carte des ventes accompagne `.profit-card` et `.loss-card`, deja
   sombres : laissee de cote, elle serait la seule des trois a rester claire. */
body.dark-mode .sales-card {
    background: linear-gradient(135deg, rgba(5, 56, 31, 0.8), rgba(16, 185, 129, 0.15)) !important;
    border: 1px solid rgba(16, 185, 129, 0.3) !important;
}


/* --- 19.5 Textes enfermes dans ces surfaces -------------------------------
   Repeindre un conteneur sans repeindre son texte ne corrige rien : le bloc
   passe du blanc au sombre et le texte noir devient illisible au lieu d'etre
   simplement laid.

   La liste est volontairement etroite. Elle ne contient que les regles de
   couleur DESCENDANT des conteneurs ci-dessus — pas toutes les regles de texte
   sombre de la plateforme, dont beaucoup sont posees sur des boutons colores
   ou le noir est correct. */
body.dark-mode .mybazar-login-section .login-wrapper h2 {
    color: var(--ui-text) !important;
}

body.dark-mode .in-table-row-bottom .total-amound,
body.dark-mode .delete-item .delete-item-show p,
body.dark-mode .mybazar-login-section .login-wrapper p {
    color: var(--ui-text-body) !important;
}

body.dark-mode .products .single-product .pro-category,
body.dark-mode .mybazar-login-section .login-wrapper h6,
body.dark-mode .mybazar-login-section .back-to-login a,
body.dark-mode .mybazar-login-section .forget-password a {
    color: var(--ui-text-muted) !important;
}

/* Rouges d'action : ils gardent leur sens, ils changent de valeur. Le rouge
   d'origine tombe a 2,2:1 sur fond sombre ; celui-ci tient 6,0:1. */
body.dark-mode .custom-modal .btn-no,
body.dark-mode .serial-item .remove-btn {
    color: #F87171 !important;
}


/* --- 19.6 Le resume chiffre des cartes ------------------------------------
   `.stat-title` et `.stat-value` portent `#121212` et `black` en dur. Sur les
   cartes claires d'origine c'etait juste. Ces cartes sont sombres depuis
   `custom.css` — mais la couleur du PARENT ne traverse pas une couleur posee
   sur l'ENFANT, et les montants y sont restes noirs sur vert fonce : les
   « Fournisseur du » et « Client du » du tableau des dus etaient illisibles.

   La portee est limitee aux trois cartes concernees, seuls endroits ou ces
   deux classes apparaissent dans les vues. */
body.dark-mode .profit-card .stat-title,
body.dark-mode .loss-card .stat-title,
body.dark-mode .sales-card .stat-title {
    color: var(--ui-text-body) !important;
    opacity: 1;
}

body.dark-mode .profit-card .stat-value,
body.dark-mode .loss-card .stat-value,
body.dark-mode .sales-card .stat-value {
    color: var(--ui-text) !important;
}


/* =========================================================================
   20. LE VERT DE MARQUE EN COULEUR DE TEXTE
   =========================================================================

   `--clr-primary` vaut `#05381F` — le vert profond de Clario. Pose sur du
   blanc il donne 13,2:1 : c'est un excellent texte de marque, et c'est pour
   cela qu'il sert de couleur de lien un peu partout.

   Sur une surface sombre il donne 1,27:1. Autrement dit : rien. Le menu des
   reglages Super Admin en donne l'exemple — « Pilotes » et « Parametres de
   stockage » n'etaient pas ternes, ils etaient ABSENTS de l'ecran.

   Le defaut ne se voyait pas tant que ces blocs restaient blancs : le vert
   sombre y etait juste. Les assombrir au §19 l'a mis a nu. C'est la meme
   erreur vue de l'autre cote — une couleur ecrite en dur pour un fond qu'on
   croyait immuable.

   POURQUOI PAS SIMPLEMENT REDEFINIR `--clr-primary` EN SOMBRE.

   Ce serait une ligne au lieu de trente, et ce serait faux. Le meme jeton sert
   aussi de FOND : la pastille active du menu est un aplat de ce vert avec du
   texte blanc dessus, et elle est parfaitement lisible. L'eclaircir rendrait
   le fond vif et le texte blanc illisible. Un jeton qui sert a la fois
   d'encre et de papier ne peut pas basculer d'un bloc.

   On ne reprend donc que les emplois en ENCRE, et `--ui-accent` (#10B981)
   leur rend leur lisibilite : 6,6:1 sur la surface, 6,0:1 sur la surface
   secondaire, 5,2:1 sur la pastille.
   ========================================================================= */

body.dark-mode .primary,
body.dark-mode .custom-primary,
body.dark-mode .text-custom-primary,
body.dark-mode .text-custom-primary:hover,
body.dark-mode .border-btn:hover,
body.dark-mode .cancel-btn,
body.dark-mode .role-reset-btn,
body.dark-mode .modal-close-btn,
body.dark-mode .request-domain-btn,
body.dark-mode .plan-buy-btn,
body.dark-mode .add-payment-button,
body.dark-mode .footer-acn,
body.dark-mode .custom-tabs .tab-item.active,
body.dark-mode .new-order .graph-header,
body.dark-mode .verify-modal-body .des .reset {
    color: var(--ui-accent) !important;
}

/* `.active` est exclue a dessein : elle porte du blanc sur la pastille verte,
   ou elle tient 12,6:1. L'inclure dans la reprise la repeindrait en emeraude
   sur ce meme vert — on corrigerait une entree lisible en la cassant. */
body.dark-mode .nav-link:not(.active),
body.dark-mode .nav-link:not(.active):hover,
body.dark-mode .nav-link:not(.active):focus {
    color: var(--ui-accent) !important;
}

/* Deux boutons portent a la fois ce vert et un fond pastel opaque : les
   traiter par la couleur seule laisserait leur pave clair en place. */
body.dark-mode .feature-btn {
    background: rgba(99, 102, 241, 0.16) !important;
    color: var(--ui-text-body) !important;
}

body.dark-mode .disc-btn:hover {
    background-color: rgba(248, 113, 113, 0.14) !important;
    border-color: rgba(248, 113, 113, 0.30) !important;
    color: var(--ui-accent) !important;
}


/* =========================================================================
   21. LA CALCULATRICE DE LA CAISSE — LE SURVOL DANS LES DEUX MODES
   =========================================================================

   Cette section est la seule du fichier qui ne soit PAS reservee au mode
   sombre. Elle est nee de la verification du reste, et le defaut trouve n'a
   rien a voir avec le theme.

   `custom.css` habille le survol des touches en emeraude sur un voile de la
   meme emeraude — 10 % en clair, 25 % en sombre. Une couleur posee sur une
   dilution d'elle-meme ne peut pas produire beaucoup de contraste :

     mode clair  : #10B981 sur #E7F8F2  ->  2,31:1
     mode sombre : #10B981 sur #0C4834  ->  4,16:1

   Les deux sont sous les 4,5:1 exiges, et le mode clair — celui qu'on
   n'aurait pas songe a verifier — est de loin le pire. La touche s'efface au
   moment precis ou le caissier la vise.

   Le voile est conserve : c'est lui qui signale le survol. Seule l'encre
   change, vers un ton qui tient sur son propre voile — 4,99:1 en clair,
   5,48:1 en sombre. */

body:not(.dark-mode) .calculator-btn:hover {
    color: #047857 !important;
}

body.dark-mode .calculator-btn:hover {
    color: #34D399 !important;
}


/* =========================================================================
   22. TABLEAU DE BORD — LE VIDE SOUS LE GRAPHIQUE
   =========================================================================

   La rangee d'analyse tient deux colonnes : le graphique a gauche, deux
   fiches empilees a droite. La hauteur de la rangee est celle de la plus
   haute des deux — la colonne de droite. La carte du graphique, elle,
   s'arretait a son propre contenu : 441 px dans une colonne de 523, soit
   82 px de vide sous elle.

   Le remede n'est pas de raccourcir la colonne de droite mais de rendre cette
   hauteur au graphique, qui en fait bien meilleur usage qu'un blanc.

   La hauteur du canevas etait ecrite en ligne dans le gabarit (`height:
   320px`). Une valeur en ligne ne se laisse pas depasser sans `!important` :
   elle a donc ete retiree du gabarit et remplacee par la classe ci-dessous,
   ou 320 px devient un PLANCHER et non un plafond. */

#revenueChartCard {
    height: 100%;
    display: flex;
    flex-direction: column;
}

.dash-chart-body {
    position: relative;
    flex: 1 1 auto;
    min-height: 320px;
}

/* Une carte de rangee doit remplir sa colonne, sinon la rangee se lit comme
   une case a moitie vide.

   Portee au SEUL tableau de bord d'accueil : sans le prefixe, la regle aurait
   etire les cartes de toutes les pages a colonnes du panneau, dont certaines
   sont volontairement basses a cote d'une colonne haute. Une correction de
   mise en page ne doit pas voyager au-dela de la page qui la demandait. */
.dash-accueil > .row > [class*="col-"] > .futuristic-card:only-child {
    height: 100%;
}


/* --- 22.1 Le bandeau « flux en direct » ----------------------------------
   Deux defauts au meme endroit.

   Sur grand ecran, `justify-content: space-between` avec deux enfants pousse
   l'etiquette a gauche et les messages a droite : un vide s'installe au milieu
   d'un bandeau qui devrait se lire comme une seule phrase.

   Sur telephone, `.ticker-content` n'avait aucune regle : la div se comprimait
   et les trois messages se repliaient sur cinq lignes, l'etiquette ecrasee sur
   deux mots dans une colonne de 40 px.

   Le bandeau devient donc une bande d'UNE seule ligne : l'etiquette ne se
   comprime pas, les messages suivent immediatement, et ce qui depasse se fait
   defiler du doigt. Pas d'animation : un texte qui glisse sans fin sur un
   tableau de bord professionnel derange plus qu'il n'informe, et ne se met pas
   en pause au clavier. */

.realtime-sales-ticker {
    justify-content: flex-start !important;
    gap: 16px;
    overflow: hidden;
}

.realtime-sales-ticker .ticker-label {
    flex: 0 0 auto;
    white-space: nowrap;
    font-weight: 600;
}

.realtime-sales-ticker .ticker-content {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 22px;
    white-space: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
}

.realtime-sales-ticker .ticker-content::-webkit-scrollbar { display: none; }
.realtime-sales-ticker .ticker-content > span { flex: 0 0 auto; }

/* =========================================================================
   INTERRUPTEURS ET CASES A COCHER — orange Clario, partout
   =========================================================================
   Trois feuilles se contredisaient (style.css, custom.css, Bootstrap). En
   sombre, le rail prenait presque la couleur de la page, et la pastille de
   Bootstrap — gris fonce par defaut — y disparaissait : on ne voyait plus si
   une fonction etait activee. Un seul langage desormais, pour les trois
   formes presentes dans l'application :
     - l'interrupteur Bootstrap (.form-switch .form-check-input) ;
     - l'ancien interrupteur maison (.switch > .slider) ;
     - la case a cocher (.form-check-input[type=checkbox]).
   ACTIVE = orange de marque, pastille blanche. DESACTIVE = rail neutre bien
   contraste, pastille visible. En clair, l'orange est assombri (#EA580C,
   3,6:1 sur blanc) : #FF6B00 n'y atteint pas les 3:1 exiges d'un controle.
   Le prefixe `html body` l'emporte sur les regles `body.dark-mode` en
   !important de custom.css, sans dependre de l'ordre de chargement.
   ========================================================================= */

:root {
    --ui-toggle-on:        #EA580C;
    --ui-toggle-on-ring:   rgba(234, 88, 12, 0.28);
    --ui-toggle-off:       #E4E7EC;
    --ui-toggle-off-edge:  #98A2B3;
    --ui-toggle-knob-off:  #475467;
}
body.dark-mode {
    --ui-toggle-on:        #FF8800;
    --ui-toggle-on-ring:   rgba(255, 136, 0, 0.30);
    --ui-toggle-off:       #1F2A37;
    --ui-toggle-off-edge:  #64748B;
    --ui-toggle-knob-off:  #CBD5E1;
}

/* ---- Interrupteur Bootstrap ------------------------------------------- */
html body .form-switch .form-check-input {
    width: 44px !important;
    height: 24px !important;
    border-radius: 999px !important;
    border: 1px solid var(--ui-toggle-off-edge) !important;
    background-color: var(--ui-toggle-off) !important;
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23475467'/%3e%3c/svg%3e") !important;
    background-position: left center !important;
    background-repeat: no-repeat !important;
    cursor: pointer;
    transition: background-position .15s ease, background-color .15s ease, border-color .15s ease;
}
html body.dark-mode .form-switch .form-check-input {
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23CBD5E1'/%3e%3c/svg%3e") !important;
}
html body .form-switch .form-check-input:checked,
html body.dark-mode .form-switch .form-check-input:checked {
    background-color: var(--ui-toggle-on) !important;
    border-color: var(--ui-toggle-on) !important;
    background-position: right center !important;
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e") !important;
}

/* L'interrupteur et son libelle sur la meme ligne. style.css retirait le
   retrait de Bootstrap et centrait la case : le libelle partait a la ligne,
   decale, comme detache de ce qu'il commande. */
html body .form-check.form-switch:has(.form-check-label) {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding-left: 0;
    min-height: 24px;
}
html body .form-check.form-switch:has(.form-check-label) .form-check-input {
    flex: 0 0 auto;
    float: none;
    margin: 0 !important;
}
html body .form-check.form-switch:has(.form-check-label) .form-check-label {
    flex: 1 1 auto;
    padding-top: 2px;
    cursor: pointer;
}

/* ---- Ancien interrupteur maison (.switch > .slider) --------------------- */
html body .switch .slider {
    background-color: var(--ui-toggle-off) !important;
    border: 1px solid var(--ui-toggle-off-edge);
}
html body .switch .slider:before {
    background-color: var(--ui-toggle-knob-off) !important;
    height: 18px;
    width: 18px;
    left: 2px;
    bottom: 2px;
}
html body .switch input:checked + .slider {
    background-color: var(--ui-toggle-on) !important;
    border-color: var(--ui-toggle-on);
}
html body .switch input:checked + .slider:before {
    background-color: #fff !important;
    transform: translateX(20px);
}
html body .switch input:focus-visible + .slider {
    box-shadow: 0 0 0 3px var(--ui-toggle-on-ring);
}

/* ---- Cases a cocher (hors interrupteurs) -------------------------------- */
html body .form-check-input[type="checkbox"]:not([role="switch"]):not(.form-switch *) {
    width: 1.15em;
    height: 1.15em;
    border: 1.5px solid var(--ui-toggle-off-edge) !important;
    background-color: transparent !important;
    cursor: pointer;
}
html body .form-check-input[type="checkbox"]:not([role="switch"]):not(.form-switch *):checked {
    background-color: var(--ui-toggle-on) !important;
    border-color: var(--ui-toggle-on) !important;
    /* La coche, que custom.css effacait en sombre : sans elle, une case cochee
       n'est qu'un carre orange qu'on ne distingue pas d'un bouton. */
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e") !important;
    background-size: 100% 100% !important;
    background-position: center !important;
    background-repeat: no-repeat !important;
}

/* Anneau de focus commun : un controle atteint au clavier doit se voir. */
html body .form-check-input:focus,
html body.dark-mode .form-check-input:focus {
    border-color: var(--ui-toggle-on) !important;
    box-shadow: 0 0 0 3px var(--ui-toggle-on-ring) !important;
}

/* Liste d'offres autorisees (Catalogue, COD) : des cases, pas un select
   multiple — le Ctrl+clic y decochait tout sans le dire. */
.plan-checklist {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
}
.plan-checklist .form-check {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0;
    padding: 8px 14px;
    border: 1px solid var(--ui-border-strong);
    border-radius: var(--ui-radius-sm);
    background: var(--ui-surface-2);
}
.plan-checklist .form-check:has(.form-check-input:checked) {
    border-color: var(--ui-toggle-on);
    background: var(--ui-accent-2-soft);
}
.plan-checklist .form-check-input { margin: 0 !important; float: none; }


/* =========================================================================
   Tableau de bord — reprise de la premiere configuration
   ========================================================================= */
.onboarding-resume {
    display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 16px; align-items: center;
    padding: 16px 20px; border-radius: 18px;
    background: linear-gradient(120deg, rgba(14, 140, 79, .12), rgba(255, 107, 0, .08));
    border: 1px solid rgba(14, 140, 79, .25);
}
.onboarding-resume-ico { width: 46px; height: 46px; border-radius: 14px; display: grid; place-items: center; background: #0E8C4F; color: #fff; font-size: 19px; }
.onboarding-resume-text { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.onboarding-resume-text strong { font-size: 15.5px; color: var(--ui-text, #0F172A); }
.onboarding-resume-text span { font-size: 13.5px; color: var(--ui-text-muted, #64748B); }
.onboarding-resume-bar { height: 6px; border-radius: 6px; background: rgba(14, 140, 79, .15); overflow: hidden; max-width: 360px; margin-top: 4px; }
.onboarding-resume-bar i { display: block; height: 100%; background: linear-gradient(90deg, #0E8C4F, #FF6B00); border-radius: inherit; }
.onboarding-resume-btn { display: inline-flex; align-items: center; gap: 8px; padding: 11px 18px; border-radius: 999px; background: #0E8C4F; color: #fff !important; font-weight: 800; font-size: 14px; text-decoration: none; white-space: nowrap; }
.onboarding-resume-btn:hover { background: #0B7A43; }
body.dark-mode .onboarding-resume-text strong { color: #E8F5EE !important; }
body.dark-mode .onboarding-resume-text span { color: #9DB3A7 !important; }
@media (max-width: 640px) {
    .onboarding-resume { grid-template-columns: auto minmax(0, 1fr); }
    .onboarding-resume-btn { grid-column: 1 / -1; justify-content: center; }
}
