/* public/css/design/components.css
 * Bibliotheque de composants neuve (Phase 4, 20/07/2026) — boutons, pastilles, tableaux,
 * modales, champs, menus deroulants. Classes ssm-* stylees ici pour de vrai (pas de
 * surcharge de styles AdminLTE existants) ; .modal-content/.form-control/table.dataTable
 * restent les noms de classe hérités (necessaires au JS Bootstrap/DataTables et presents
 * dans ~130 vues), mais leur CSS ci-dessous est ecrit de zero, pas une teinte d'AdminLTE.
 * S'applique partout ou <body data-design="..."> est present — desormais toujours vrai
 * (voir vendor/function.php::style()).
 */

/* --accent-soft n'existe pas dans tokens.css (uniquement bg/surface/accent/ok/warn/bad par
   direction) : calcule ici une seule fois a partir de --accent, pour tous les halos de focus/
   glow (filtres, icones de modale...). Corrige un bug ou var(--accent-soft, var(--warn-bg))
   retombait silencieusement sur le jaune d'avertissement faute de variable definie.
   20/07/2026 : retour utilisateur "j'ai pas aime le principe d'opacity" -> --accent-soft ne
   melange plus l'accent avec du transparent (color-mix(...,transparent), une vraie
   translucidite qui change de rendu selon ce qu'il y a derriere et peut produire des zones
   "sales"/imprevisibles, cf. le bug modal Irise). Il melange desormais l'accent avec --surface
   (couleur opaque, deterministe) : le resultat est une teinte pleine et stable, pas un calque
   transparent. Meme nom de variable (pour ne pas retoucher tous les usages), mecanisme different. */
body[data-design] { --accent-soft: color-mix(in srgb, var(--accent) 14%, var(--surface)); font-family: var(--font-ui); }
body[data-design] h1, body[data-design] h2, body[data-design] h3,
body[data-design] h4, body[data-design] h5, body[data-design] h6 { font-family: var(--font-display); color: var(--ink); }
body[data-design] a { color: var(--accent); }
body[data-design] a:hover { color: var(--accent-hover); }
body[data-design] .content-wrapper, body[data-design] .container-fluid { background: transparent; }

/* ================= Boutons ================= */
.ssm-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  font: 700 12.5px var(--font-ui); padding: 9px 16px; border-radius: var(--radius);
  border: 1px solid var(--line); background: var(--surface); color: var(--ink);
  cursor: pointer; line-height: 1.2; transition: background .12s, border-color .12s, color .12s;
}
.ssm-btn:hover { border-color: var(--accent); color: var(--accent); }
.ssm-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.ssm-btn:disabled { opacity: .45; cursor: not-allowed; }
.ssm-btn-primary, .ssm-btn.bg-gradient-success, .ssm-btn.bg-success {
  background: var(--accent); border-color: var(--accent); color: var(--accent-ink);
}
.ssm-btn-primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); color: var(--accent-ink); }
.ssm-btn-danger { background: var(--bad-bg); border-color: var(--bad); color: var(--bad); }
.ssm-btn-danger:hover { background: var(--bad); color: #fff; }
/* `<a class="ssm-btn-primary">` (ex. bouton Retour navigable en data-ssm-nav) : sans ceci, la regle
   generale `body[data-design] a { color: var(--accent) }` (specificite superieure a .ssm-btn-primary
   seule) rend le texte de la meme couleur que le fond accent -> bouton visuellement vide. */
body[data-design] a.ssm-btn-primary, body[data-design] a.ssm-btn-primary:hover { color: var(--accent-ink); }
body[data-design] a.ssm-btn-danger { color: var(--bad); }
body[data-design] a.ssm-btn-danger:hover { color: #fff; }
.ssm-btn-block { width: 100%; }
.ssm-btn-group { display: inline-flex; gap: 4px; align-items: center; }
.ssm-btn-icon { width: 32px; height: 32px; padding: 0; border-radius: var(--radius); }
.ssm-btn-icon i { font-size: 13px; }
/* Emplacement conventionnel des actions d'un panel (Ajouter/Imprimer/Exporter/...) : toujours a
   l'extreme droite de la barre de filtres, boutons icone+texte regroupes, jamais un bouton isole
   au milieu des filtres ni positionne via un decoupage col-md-x/col-md-y fragile (retour
   utilisateur : mal place). .ssm-panel-toolbar est un conteneur flex simple ; .ssm-panel-actions
   prend margin-left:auto pour etre pousse a l'extreme droite quel que soit ce qu'il y a a cote
   (filtre present ou pas, largeur variable) — meme principe que le ":has(> .float-right)" deja
   utilise ailleurs pour le meme besoin. */
.ssm-panel-toolbar { display: flex; align-items: center; flex-wrap: wrap; gap: 14px; }
/* Pas de flex-basis/max-width force ici : chaque .input-group doit garder la taille dictee par
   son propre contenu (le select2 nested a deja son propre min/max-width, cf. plus haut). Une
   largeur imposee au niveau du wrapper avait agrandi le filtre "Groupe" au-dela de ce que son
   select2 remplissait vraiment -> case trop large avec la fleche collee au texte au lieu d'etre
   a l'extremite (signale par l'utilisateur).
   21/07/2026 : Bootstrap donne a .input-group un width:100% en dur (bootstrap.css). Quand
   flex-basis vaut "auto" (ce que fait "flex: 0 0 auto"), la spec flexbox dit que le width
   explicite du champ devient le flex-basis effectif -> chaque filtre prenait 100% de la largeur
   de la rangee et passait donc a la ligne (Grand Livre : "chaque input dans une ligne", chaque
   image visible etait a 100%). Il faut neutraliser width en plus de flex pour que le
   dimensionnement au contenu fonctionne reellement. */
.ssm-panel-toolbar .input-group { flex: 0 0 auto; width: auto; }
/* Version portable : cote a cote au contenu au-dela de 768px, mais empiles en pleine largeur (et
   donc tous a la MEME largeur) en dessous - au lieu de rester chacun a sa largeur de contenu
   (donnait des filtres mal alignes / de largeurs differentes une fois empiles, signale sur Grand
   Livre). !important necessaire : body[data-design] .input-group.input-group-sm (plus bas dans ce
   fichier) est plus specifique (une classe + un attribut en plus) et fixe width:auto en dur, donc
   gagne sur cette regle malgre la media query et l'ordre des regles. */
@media (max-width: 768px) {
  .ssm-panel-toolbar .input-group { flex: 1 1 100% !important; width: 100% !important; }
  .ssm-panel-actions { width: 100% !important; margin-left: 0 !important; justify-content: flex-start !important; }
}

/* 21/07/2026 : la rangee dediee .ssm-panel-header-top (a l'interieur du card-header) prenait de
   la hauteur meme resserree, et n'etait pas "attachee au card" comme demande. Le bouton plein
   ecran est desormais en position absolute, attache directement a .ssm-panel/.card (qui doit donc
   etre position:relative), colle au coin haut-droit EXACT du card - aucun espace de mise en page
   consomme, plus jamais "trop de hauteur". Avec texte visible (plus un simple icone rond). */
/* Scope volontairement etroit (:has(> bouton)) plutot que tous les .card de l'appli : position:
   relative sur .card change potentiellement le contexte de positionnement d'enfants absolus
   ailleurs dans les ~100 vues non concernees par le plein ecran. */
body[data-design] .ssm-panel:has(> .ssm-panel-fullscreen-btn),
body[data-design] .card:has(> .ssm-panel-fullscreen-btn),
body[data-design] .ssm-panel:has(> .ssm-panel-toolbelt),
body[data-design] .card:has(> .ssm-panel-toolbelt) { position: relative; }
/* Le bouton absolu ne reserve pas d'espace tout seul : sans cette marge haute supplementaire, il
   se superposerait au contenu du card-header (ex. le bouton "Ajouter", qui vise le meme coin
   droit dans la rangee de filtres juste en dessous). */
body[data-design] .ssm-panel:has(> .ssm-panel-fullscreen-btn) > .ssm-panel-header,
body[data-design] .card:has(> .ssm-panel-fullscreen-btn) > .card-header,
body[data-design] .ssm-panel:has(> .ssm-panel-toolbelt) > .ssm-panel-header,
body[data-design] .card:has(> .ssm-panel-toolbelt) > .card-header { padding-top: 42px; }
.ssm-panel-fullscreen-btn {
  position: absolute; top: 10px; right: 14px; z-index: 5;
  font-size: 11px; padding: 5px 11px; gap: 6px;
}
.ssm-panel-fullscreen-btn i { font-size: 11px; }
/* Regroupe le bouton reglage + le bouton plein ecran (21/07/2026) : desormais le seul point
   d'ancrage absolu dans le coin haut-droit du panel - le plein ecran devient un enfant normal
   (position statique) de ce groupe, plus la peine de recalculer sa position independamment.
   Coexiste avec .ssm-panel-fullscreen-btn seul (sans toolbelt) pour les panels pas encore repris. */
.ssm-panel-toolbelt {
  position: absolute; top: 10px; right: 14px; z-index: 5;
  display: flex; align-items: center; gap: 6px;
}
.ssm-panel-toolbelt > .ssm-panel-fullscreen-btn { position: static; top: auto; right: auto; }
.ssm-panel-settings-btn {
  font-size: 11px; padding: 5px 9px;
}
.ssm-panel-settings-btn i { font-size: 12px; }
/* Repere "ou on est" affiche uniquement en plein ecran (sidebar/topbar recouvertes, donc plus de
   fil d'Ariane visible sans ca) - injecte/retire par ssm_panel_fullscreen() (ajax.js). */
body[data-design] .ssm-panel-fullscreen-crumb {
  position: absolute; top: 10px; left: 14px; z-index: 5;
  display: flex; align-items: center; gap: 7px;
  background: var(--surface-2); border: 1px solid var(--line-soft); border-radius: 999px;
  padding: 6px 14px 6px 12px; font: 700 11.5px var(--font-ui); color: var(--ink-2);
}
body[data-design] .ssm-panel-fullscreen-crumb i { color: var(--accent); font-size: 11px; }
.ssm-panel-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-left: auto; }
.ssm-panel-actions .ssm-btn i { font-size: 12px; }

/* ================= Plein ecran d'un panel (carte filtre + tableau) =================
   Le panel vise (.ssm-panel ou .card, selon la vue) est deplace comme enfant direct de <body> en
   JS (ssm_panel_fullscreen(), ajax.js) avant de recevoir cette classe : plus fiable qu'un simple
   position:fixed laisse a sa place (la sidebar/topbar restaient visibles par-dessus, un ancetre
   du panel plafonnant probablement son empilement). Une fois enfant de <body>, top/right/bottom/
   left explicites (plus robuste qu'inset pour la compatibilite) + z-index tres au-dessus de la
   sidebar (40) et du panneau de reglages (50) suffisent. Fond force en --bg (toujours opaque)
   plutot que d'heriter du fond normal de la carte : --surface est intentionnellement translucide
   sur la direction Irise (effet verre depoli pense pour une petite carte sur fond de page), ce qui
   devient genant en plein ecran ou toute la fenetre derriere transparaissait. */
body[data-design] .ssm-panel--fullscreen {
  /* !important necessaire sur position/inset : le panel garde sa classe .ssm-panel/.card en
     plein ecran (JS ne fait qu'ajouter .ssm-panel--fullscreen, pas de switch de classe), et la
     regle :has(> .ssm-panel-fullscreen-btn) qui met position:relative (plus haut) est PLUS
     specifique (attribut+classe+pseudo-classe) que .ssm-panel--fullscreen seule -> sans
     !important elle gagnait et le panel restait position:relative, donc rendu a sa place dans le
     <body> (tout en bas, apres appendTo) au lieu de recouvrir l'ecran : "disparaissait"
     litteralement de la vue au lieu de passer en plein ecran. */
  position: fixed !important; top: 0 !important; right: 0 !important; bottom: 0 !important; left: 0 !important;
  /* 100 (pas 2000/2147483647) : doit rester au-dessus de la sidebar/topbar/panneau reglages
     (40/20/50) mais EN DESSOUS des modales Bootstrap (~1040-1050 par defaut), sinon toute modale
     ouverte en plein ecran (ex. options d'impression/export) reste invisible derriere le panel. */
  z-index: 100; margin: 0 !important; border-radius: 0; border: none !important; box-shadow: none !important;
  display: flex; flex-direction: column; animation: none !important; overflow: auto;
  background: var(--bg) !important; backdrop-filter: none !important;
}
body[data-design] .ssm-panel--fullscreen > .ssm-panel-body,
body[data-design] .ssm-panel--fullscreen > .card-body { flex: 1 1 auto; overflow: auto; }
body[data-design].ssm-body-locked { overflow: hidden; }
.ssm-ic-primary { color: var(--accent); }
.ssm-ic-success { color: var(--ok); }
.ssm-ic-danger { color: var(--bad); }
.ssm-ic-warning { color: var(--warn); }
.ssm-ic-secondary, .ssm-ic-gray { color: var(--ink-2); }

/* ================= Menus deroulants (dropdown JS de Bootstrap conserve) ================= */
.ssm-dropdown { position: relative; display: inline-block; }
.ssm-menu {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 6px; min-width: 180px; font: 500 13px var(--font-ui);
}
.ssm-menu-pad { padding: 12px; }
.ssm-menu-item {
  display: block; padding: 8px 10px; border-radius: calc(var(--radius) - 2px);
  color: var(--ink); text-decoration: none; cursor: pointer;
}
.ssm-menu-item:hover { background: var(--surface-2); color: var(--accent); }
.dropdown-toggle::after { display: none; }

/* ================= Pastilles de statut ================= */
.ssm-pill {
  display: inline-flex; align-items: center; gap: 5px; font: 700 10.5px var(--font-ui);
  padding: 3px 10px; border-radius: 999px;
}
.ssm-pill::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.ssm-pill-success { background: var(--ok-bg); color: var(--ok); }
.ssm-pill-danger { background: var(--bad-bg); color: var(--bad); }
.ssm-pill-warning { background: var(--warn-bg); color: var(--warn); }
.ssm-pill-primary, .ssm-pill-info { background: var(--accent); color: var(--accent-ink); }
.ssm-pill-secondary, .ssm-pill-gray { background: var(--surface-2); color: var(--ink-2); }

/* ================= Cartes / panneaux =================
   V2 (20/07/2026) : la V1 (accent-bar sur l'en-tete + display:flex) a casse la position du
   bouton Ajouter (le display:flex sur .card-header perturbait la mise en page interne en
   .row/.col- existante) et n'a pas plu visuellement — abandonnee. On revient a un traitement
   minimal (uniquement couleurs/bordure/rayon/ombre, jamais de display sur un conteneur qui a
   deja des enfants en .row Bootstrap) + on regle le vrai probleme signale : les cartes
   imbriquees (carte dans une carte, ex. Clients.php) sont maintenant APLATIES — la carte
   interne perd son propre cadre/ombre/fond et devient une simple section de contenu. */
body[data-design] .card {
  background: var(--surface); border: 1px solid var(--line-soft); border-radius: var(--radius-card);
  box-shadow: var(--shadow); color: var(--ink);
}
body[data-design] .card-header, body[data-design] .card-footer {
  background: var(--surface-2); border-color: var(--line-soft); color: var(--ink);
}
body[data-design] .card-title, body[data-design] .card-header h1, body[data-design] .card-header h2,
body[data-design] .card-header h3, body[data-design] .card-header h4, body[data-design] .card-header h5,
body[data-design] .card-header h6 { font-family: var(--font-display); font-weight: 700; margin: 0; }
body[data-design] .card-body { padding: 18px; }
body[data-design] .card-tools .btn {
  width: 30px; height: 30px; padding: 0; display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--radius); background: transparent; border: none; color: var(--ink-2);
  transition: background .15s, color .15s;
}
body[data-design] .card-tools .btn:hover { background: var(--surface); color: var(--accent); }

/* Carte dans une carte : on aplatit l'interieure au lieu d'empiler deux cadres/ombres. */
body[data-design] .card .card {
  border: none; box-shadow: none; background: transparent; border-radius: 0;
}
body[data-design] .card .card > .card-header, body[data-design] .card .card > .card-body,
body[data-design] .card .card > .card-footer { background: transparent; padding-left: 0; padding-right: 0; }
body[data-design] .card .card > .card-header { border-bottom: 1px solid var(--line-soft); }

/* ================= .ssm-widget-card : petites cartes de tableau de bord (Compte Journalier,
   26/07/2026) — retour utilisateur : "les cards encaissement pompiste consommation citerne et
   vente, et sortie espece mal designe" (compte/portion/Principal.php). Cause : ces 5 cartes
   AdminLTE (`card collapsed-card border border-{primary,success,info,warning,danger}`) vivent
   DANS le `.card` panel de la page - la regle "carte dans une carte" ci-dessus (voulue pour
   Clients.php etc) les aplatit completement (plus de bordure/ombre/fond), donc les classes
   `border-*` Bootstrap n'ont plus aucun effet visuel : 5 blocs de texte empiles sans separation
   ni code couleur. Nouvelle classe DEDIEE (pas `.card`) pour echapper a cet aplatissement tout en
   gardant `data-card-widget="collapse"` (AdminLTE JS, comportement conserve). Code couleur repris
   de l'original via 5 modificateurs, mappe sur les tokens de palette existants (pas de nouvelle
   couleur inventee). */
/* !important partout ci-dessous : ces cartes gardent la classe `.card` (pour le JS AdminLTE
   `data-card-widget="collapse"` qui cherche `.closest('.card')`), donc la regle "carte dans une
   carte" juste au-dessus (`.card .card { border:none; box-shadow:none; background:transparent }`,
   3 classes = plus specifique que `.ssm-widget-card` seule, 2 classes) continuait a gagner et
   annulait silencieusement tout ce bloc - constat fait sur capture d'ecran fournie par
   l'utilisateur (aucune bordure/ombre visible, juste un filet de separation residuel). */
body[data-design] .ssm-widget-card {
  background: var(--surface) !important; border: 1px solid var(--line-soft) !important;
  border-left: 4px solid var(--accent) !important; border-radius: var(--radius-card) !important;
  box-shadow: var(--shadow) !important; margin-bottom: 18px; overflow: hidden;
  /* Cartes appairees (Pompiste/Citerne, Encaissement/Vente - meme hauteur demandee) : place dans
     une colonne `d-flex`, la carte doit elle-meme etre flex (width 100%, colonne verticale) pour
     s'etirer jusqu'en bas de la colonne (rendue egale a sa voisine par le comportement standard
     Bootstrap "colonnes egales" d'une `.row` flex) - sans ca, une simple div block ne s'etire
     jamais toute seule meme si son conteneur est plus haut. */
  display: flex; flex-direction: column; width: 100%;
}
body[data-design] .ssm-widget-card.collapsed-card { margin-bottom: 14px; }
body[data-design] .ssm-widget-card--success { border-left-color: var(--ok) !important; }
body[data-design] .ssm-widget-card--info { border-left-color: var(--accent-hover) !important; }
body[data-design] .ssm-widget-card--warning { border-left-color: var(--warn) !important; }
body[data-design] .ssm-widget-card--danger { border-left-color: var(--bad) !important; }
body[data-design] .ssm-widget-card > .card-header {
  background: var(--surface-2) !important; border-bottom: 1px solid var(--line-soft) !important;
  padding: 12px 16px !important; display: flex; align-items: center; justify-content: space-between;
  gap: 10px; flex-wrap: wrap;
}
body[data-design] .ssm-widget-card.collapsed-card > .card-header { border-bottom: none !important; }
body[data-design] .ssm-widget-card > .card-header .card-title {
  font: 700 14.5px var(--font-display); margin: 0; display: flex; align-items: center;
}
/* Boutons d'ouverture/ajout (card-tools) toujours colles a l'extreme droite de l'en-tete - retour
   utilisateur : ils flottaient au milieu. Cause : AdminLTE positionne `.card-tools` en `float:right`
   dans son propre CSS, ignore une fois le parent passe en `display:flex` (les floats n'ont aucun
   effet sur un enfant flex) - le bloc retombait a sa largeur naturelle sans etre pousse au bord.
   `margin-left:auto` force explicitement la butee a droite, independamment de tout float residuel. */
body[data-design] .ssm-widget-card > .card-header .card-tools {
  margin-left: auto !important; float: none !important; display: flex; align-items: center; gap: 4px;
}
/* Carte Archive (compte/Comptes.php, 28/07/2026, retour utilisateur : "bouton Agrandir/Reduire
   masque derriere le bouton Plein ecran") : le bouton collapse de .card-tools est pousse a
   l'extreme droite de l'en-tete (regle ci-dessus) - EXACTEMENT sous .ssm-panel-toolbelt
   (position:absolute, top:10px, right:14px, z-index:5). La compensation generique
   `.card:has(> .ssm-panel-toolbelt) > .card-header { padding-top:42px }` (plus haut dans ce
   fichier) est sans !important, donc ecrasee par le `padding:12px 16px !important` de
   `.ssm-widget-card > .card-header` ci-dessus : l'en-tete ne descend jamais, les deux boutons se
   superposent. Selecteur plus specifique (3 vs 2 classes/pseudo) + !important pour regagner la
   priorite, quel que soit l'ordre des regles dans ce fichier. */
body[data-design] .ssm-widget-card:has(> .ssm-panel-toolbelt) > .card-header,
body[data-design] .ssm-widget-card:has(> .ssm-panel-fullscreen-btn) > .card-header {
  padding-top: 42px !important;
}
body[data-design] .ssm-widget-card > .card-body { padding: 14px 16px !important; flex: 1 1 auto; }
body[data-design] .ssm-widget-card table { margin-bottom: 0; }
body[data-design] .ssm-widget-card .card-tools .btn {
  width: 28px; height: 28px; padding: 0; display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--radius); background: transparent; border: none; color: var(--ink-2);
  transition: background .15s, color .15s;
}
body[data-design] .ssm-widget-card .card-tools .btn:hover { background: var(--surface); color: var(--accent); }
/* Icone en pastille ronde devant le titre - meme principe que .ssm-modal-icon (modales), decline
   sur les 5 couleurs de carte ci-dessus. */
body[data-design] .ssm-widget-icon {
  width: 30px; height: 30px; border-radius: var(--radius); display: inline-flex; align-items: center;
  justify-content: center; background: var(--accent-soft, var(--surface-2)); color: var(--accent);
  font-size: 13px; flex: none; margin-right: 10px;
}
body[data-design] .ssm-widget-card--success .ssm-widget-icon { background: var(--ok-bg); color: var(--ok); }
body[data-design] .ssm-widget-card--info .ssm-widget-icon { background: var(--accent-soft, var(--surface-2)); color: var(--accent-hover); }
body[data-design] .ssm-widget-card--warning .ssm-widget-icon { background: var(--warn-bg); color: var(--warn); }
body[data-design] .ssm-widget-card--danger .ssm-widget-icon { background: var(--bad-bg); color: var(--bad); }

/* ================= .ssm-kpi-tile : tuile chiffre-cle (page d'accueil, 27/07/2026) — remplace les
   `small-box` AdminLTE (fond degrade plein, icone en filigrane) des cartes Achats/Ventes et
   Caisse/Banque du tableau de bord. Meme famille de couleurs que .ssm-widget-card (succes/danger/
   info/warning), mais forme "tuile" (icone a gauche, libelle+valeur a droite, lien pied de tuile)
   plutot que carte a en-tete. */
.ssm-kpi-tile {
  display: flex; align-items: center; gap: 12px; background: var(--surface);
  border: 1px solid var(--line-soft); border-left: 4px solid var(--accent); border-radius: var(--radius-card);
  box-shadow: var(--shadow); padding: 14px 16px; margin-bottom: 16px; transition: transform .15s ease, box-shadow .15s ease;
  text-decoration: none !important; color: inherit;
}
.ssm-kpi-tile:hover { transform: translateY(-2px); box-shadow: 0 6px 16px rgba(0,0,0,.08); color: inherit; }
.ssm-kpi-tile--success { border-left-color: var(--ok); }
.ssm-kpi-tile--danger { border-left-color: var(--bad); }
.ssm-kpi-tile--info { border-left-color: var(--accent-hover); }
.ssm-kpi-tile--warning { border-left-color: var(--warn); }
.ssm-kpi-tile-icon {
  width: 42px; height: 42px; border-radius: var(--radius); display: flex; align-items: center;
  justify-content: center; background: var(--accent-soft, var(--surface-2)); color: var(--accent);
  font-size: 17px; flex: none;
}
.ssm-kpi-tile--success .ssm-kpi-tile-icon { background: var(--ok-bg); color: var(--ok); }
.ssm-kpi-tile--danger .ssm-kpi-tile-icon { background: var(--bad-bg); color: var(--bad); }
.ssm-kpi-tile--info .ssm-kpi-tile-icon { background: var(--accent-soft, var(--surface-2)); color: var(--accent-hover); }
.ssm-kpi-tile--warning .ssm-kpi-tile-icon { background: var(--warn-bg); color: var(--warn); }
.ssm-kpi-tile-body { min-width: 0; flex: 1 1 auto; }
.ssm-kpi-tile-label { font: 600 12px var(--font-ui); color: var(--ink-2); margin: 0 0 2px; }
.ssm-kpi-tile-value { font: 700 17px var(--font-display); color: var(--ink); margin: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ssm-kpi-tile-arrow { flex: none; color: var(--ink-2); font-size: 13px; }
.ssm-kpi-tile:hover .ssm-kpi-tile-arrow { color: var(--accent); }

/* ================= .ssm-vente-tuile : tuile produit de l'ecran de vente Shop & Cafe (27/07/2026)
   ================= - grille visuelle avec photo, cliquable pour ajouter au ticket en cours. */
.ssm-vente-tuile {
  background: var(--surface); border: 1px solid var(--line-soft); border-radius: var(--radius-card);
  box-shadow: var(--shadow); padding: 10px; text-align: center; cursor: pointer;
  transition: transform .12s ease, box-shadow .12s ease; user-select: none;
}
.ssm-vente-tuile:hover { transform: translateY(-2px); box-shadow: 0 6px 16px rgba(0,0,0,.12); border-color: var(--accent); }
.ssm-vente-tuile:active { transform: translateY(0); }
.ssm-vente-tuile img { width: 100%; height: 84px; object-fit: cover; border-radius: var(--radius); margin-bottom: 8px; background: var(--surface-2); }
.ssm-vente-tuile-nom { font: 700 12.5px var(--font-ui); color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ssm-vente-tuile-prix { font: 700 13px var(--font-display); color: var(--accent); margin-top: 2px; }

.ssm-panier-ligne { display: flex; justify-content: space-between; align-items: center; padding: 8px 0; border-bottom: 1px dashed var(--line-soft); font-size: 13px; }
.ssm-panier-ligne:last-child { border-bottom: none; }
.ssm-panier-qte { display: inline-flex; align-items: center; gap: 6px; }
.ssm-panier-qte button { width: 22px; height: 22px; border-radius: 50%; border: 1px solid var(--line); background: var(--surface); cursor: pointer; line-height: 1; }
.ssm-panier-total { display: flex; justify-content: space-between; font: 700 16px var(--font-display); padding-top: 12px; margin-top: 8px; border-top: 2px solid var(--line); color: var(--accent); }

/* ================= .ssm-shop-compte-header : bandeau d'entete de la page Compte (resultat), avec
   ================= nom du point de vente + statut (ouvert/cloture) + acces direct a la caisse
   ================= (retour utilisateur 27/07/2026 : design a travailler, acces caisse/resultat peu
   ================= clairs). Meme famille visuelle que .ssm-widget-card (bordure gauche accent). */
.ssm-shop-compte-header {
  display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap;
  background: var(--surface); border: 1px solid var(--line-soft); border-left: 4px solid var(--accent);
  border-radius: var(--radius-card); box-shadow: var(--shadow); padding: 16px 20px; margin-bottom: 16px;
}
.ssm-shop-compte-header-info { display: flex; align-items: center; gap: 14px; }
.ssm-shop-compte-header-info .ssm-widget-icon { width: 48px; height: 48px; font-size: 19px; }
.ssm-shop-compte-header-info h2 { font: 700 19px var(--font-display); color: var(--ink); margin: 0 0 4px; }

.ssm-shop-resultat-detail { border-top: 1px solid var(--line-soft); padding-top: 10px; }
.ssm-shop-resultat-detail-line { display: flex; align-items: center; justify-content: space-between; padding: 6px 0; font: 600 13px var(--font-ui); color: var(--ink-2); }
.ssm-shop-resultat-detail-line strong { color: var(--ink); font-family: var(--font-display); }

/* ================= .ssm-ticket-recu : card "reçu imprimé" d'un ticket en attente (ecran de vente
   ================= Shop & Cafe, 27/07/2026) - meme principe que les tickets ouverts de compte_pv
   ================= (un ticket reste "en cours" tant qu'il n'est pas encaisse, voir
   ================= SKILL_MODULE_VENTE.md), affiche en page (vue "Tickets en attente") avec toutes
   ================= les informations, police monospace pour rappeler un ticket de caisse. */
.ssm-ticket-recu {
  background: var(--surface); border: 1px dashed var(--line); border-radius: var(--radius-card);
  box-shadow: var(--shadow); padding: 14px 16px; height: 100%; display: flex; flex-direction: column;
  font-family: ui-monospace, 'Courier New', monospace; font-size: 12.5px;
}
.ssm-ticket-recu-head { display: flex; justify-content: space-between; align-items: baseline; font: 700 13.5px var(--font-ui); color: var(--ink); padding-bottom: 8px; border-bottom: 1px dashed var(--line); margin-bottom: 8px; }
.ssm-ticket-recu-head span { font: 600 11.5px ui-monospace, monospace; color: var(--ink-2); }
.ssm-ticket-recu-employe { color: var(--ink-2); margin-bottom: 8px; }
.ssm-ticket-recu-lignes { flex: 1 1 auto; }
.ssm-ticket-recu-ligne { display: flex; justify-content: space-between; gap: 8px; padding: 2px 0; color: var(--ink); }
.ssm-ticket-recu-ligne span:first-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ssm-ticket-recu-total { display: flex; justify-content: space-between; font: 700 14px var(--font-display); color: var(--accent); border-top: 1px dashed var(--line); margin-top: 8px; padding-top: 8px; }
.ssm-ticket-recu-actions { display: flex; gap: 8px; margin-top: 12px; }
.ssm-ticket-recu-actions .ssm-btn { flex: 1 1 auto; font-family: var(--font-ui); }

/* ================= .ssm-icon-picker : grille d'icones cliquables (27/07/2026) - remplace un champ
   texte "classe FontAwesome" (retour utilisateur : un utilisateur ne connait pas le nom de la
   classe d'une icone), utilisee pour les categories du catalogue Shop & Cafe. */
.ssm-icon-picker { display: grid; grid-template-columns: repeat(auto-fill, minmax(46px, 1fr)); gap: 8px; max-height: 220px; overflow-y: auto; padding: 4px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface-2); }
.ssm-icon-picker-item { width: 100%; aspect-ratio: 1; display: flex; align-items: center; justify-content: center; border-radius: var(--radius); border: 1px solid var(--line-soft); background: var(--surface); color: var(--ink-2); cursor: pointer; font-size: 16px; transition: background .12s, color .12s, border-color .12s; }
.ssm-icon-picker-item:hover { border-color: var(--accent); color: var(--accent); }
.ssm-icon-picker-item.active { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }

/* ================= .ssm-panel : conteneur unique (filtre + tableau), sans carte imbriquee =====
   20/07/2026 : le motif "onglets (nav-tabs) dans une carte + une 2e carte a l'interieur pour le
   filtre/tableau" (Clients.php) a ete juge "pas une bonne idee". Nouveau motif de reference pour
   tout module a onglets : .ssm-tabs est une bande independante au-dessus (pas dans un card-header),
   et chaque panneau d'onglet contient UN SEUL conteneur .ssm-panel (filtre + tableau), jamais deux
   cadres empiles. Meme habillage visuel que .card (memes tokens) mais nom de classe distinct pour
   ne pas re-declencher le style "carte dans une carte" si un .card apparaissait par erreur autour. */
body[data-design] .ssm-panel {
  background: var(--surface); border: 1px solid var(--line-soft); border-radius: var(--radius-card);
  box-shadow: var(--shadow); color: var(--ink);
}
/* Pas d'overflow:hidden sur .ssm-panel (utilise avant pour clipper les coins carres du header/body
   contre le cadre arrondi) : ca cassait le header de table "sticky" (position:sticky ne peut
   "coller" que dans le scroll-port du plus proche ancetre a overflow != visible - .ssm-panel n'en
   a pas besoin, mais devenait ce scroll-port par accident et, comme il ne defile jamais lui-meme,
   annulait tout effet sticky). Le clipping des coins se fait desormais directement sur le
   header/body (rayon explicite), pas par overflow. */
body[data-design] .ssm-panel-header {
  padding: 16px 18px; background: var(--surface-2); border-bottom: 1px solid var(--line-soft);
  border-radius: var(--radius-card) var(--radius-card) 0 0;
}
body[data-design] .ssm-panel-body { padding: 18px; border-radius: 0 0 var(--radius-card) var(--radius-card); }
/* Barre Imprimer/Exporter statique, juste au-dessus du tableau (donc avant la recherche
   DataTables qui se rend juste en dessous) - rendue cote serveur, ne depend d'aucun DOM genere
   dynamiquement par DataTables (l'injection dans .dataTables_filter s'est averee peu fiable :
   boutons disparus). */
body[data-design] .ssm-table-toolbar { display: flex; justify-content: flex-end; gap: 6px; margin-bottom: 10px; }

/* ================= .ssm-filtres-toolbar : barre de filtres INDEPENDANTE du card-header (29/07/2026,
   retour utilisateur : "je souhaite qu'ils soient detaches du header de la carte et positionnes
   independamment"). Contrairement au placement filtres-dans-le-header (col-3/col-3... avec largeurs
   Bootstrap fixes qui se desalignent des que le contenu d'un label differe en longueur d'un filtre
   a l'autre), ce composant vit dans le .card-body, sous le titre, et utilise un flex-wrap ou chaque
   filtre garde une largeur minimale coherente (flex-basis) au lieu de largeurs de colonne rigides -
   alignement stable quel que soit le nombre/libelle des filtres. */
body[data-design] .ssm-filtres-toolbar {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: 10px 14px;
  padding-bottom: 14px; margin-bottom: 14px; border-bottom: 1px solid var(--line-soft);
}
body[data-design] .ssm-filtres-toolbar .ssm-filtre-item { flex: 1 1 200px; min-width: 180px; }
body[data-design] .ssm-filtres-toolbar .ssm-filtre-item .input-group { width: 100%; }

/* ================= Reglages d'affichage par tableau (21/07/2026, v2 alignement par colonne) =====
   Presets entete/bordure FERMES appliques par ssm_panel_settings() (ajax.js) via une classe sur
   le panel lui-meme (.ssm-panel OU .card selon la vue - jamais de couleur libre, voir
   app/models/parametre/AffichageTable.php pour la liste des valeurs possibles). L'alignement et
   la couleur de texte, eux, sont DESORMAIS par colonne : appliques via un <style> genere en JS
   (nth-child scope par id de panel), pas via ces classes - voir ssm_reglage_appliquer(). */
body[data-design] .ssm-panel.ssm-entete-accent table.dataTable thead th,
body[data-design] .card.ssm-entete-accent table.dataTable thead th { background: var(--accent) !important; color: var(--accent-ink) !important; }
body[data-design] .ssm-panel.ssm-entete-sombre table.dataTable thead th,
body[data-design] .card.ssm-entete-sombre table.dataTable thead th { background: var(--ink) !important; color: var(--surface) !important; }
body[data-design] .ssm-panel.ssm-entete-succes table.dataTable thead th,
body[data-design] .card.ssm-entete-succes table.dataTable thead th { background: var(--ok) !important; color: #fff !important; }
body[data-design] .ssm-panel.ssm-entete-attention table.dataTable thead th,
body[data-design] .card.ssm-entete-attention table.dataTable thead th { background: var(--warn) !important; color: #fff !important; }

/* Bordure de card : PAS de classe CSS ici (contrairement a l'entete ci-dessus) - ces panels
   portent aussi souvent les classes AdminLTE callout/card-outline (border-left-color/border-top
   en !important), qui gagnaient la course de specificite/ordre source face a une classe externe.
   Appliquee en style inline !important depuis ssm_reglage_appliquer() (ajax.js), qui gagne
   toujours face a n'importe quelle feuille de style externe. */

/* Bouton "reglage" (gear) : modale commune, presets ci-dessus (entete/bordure) + alignement et
   couleur par colonne. Meme famille visuelle que la modale d'export (ssm_ensure_export_modal). */
.ssm-reglage-section-titre {
  font: 700 11px var(--font-ui); text-transform: uppercase; letter-spacing: .05em;
  color: var(--ink-2); margin: 16px 0 8px;
}
.ssm-reglage-section-titre:first-child { margin-top: 0; }
.ssm-reglage-choix-row { display: flex; flex-wrap: wrap; gap: 8px; }
.ssm-reglage-choix {
  display: flex; align-items: center; gap: 7px; padding: 7px 12px; border-radius: var(--radius);
  border: 1px solid var(--line-soft); background: var(--bg); color: var(--ink-2);
  font: 600 12px var(--font-ui); cursor: pointer; transition: border-color .15s, color .15s;
}
.ssm-reglage-choix:hover { border-color: var(--accent); }
.ssm-reglage-choix--active { border-color: var(--accent); color: var(--ink); font-weight: 700; background: var(--surface-2); }

/* ================= Raccourcis clavier globaux (22/07/2026) =================
   Modal de choix quand un raccourci Ctrl+<lettre> correspond a plusieurs boutons, ou pour choisir
   une entree d'un menu deroulant declenche par raccourci - voir ssm_raccourci_ouvrir_modal()
   (ajax.js). Meme famille visuelle que .ssm-reglage-choix ci-dessus, mais en liste verticale
   (les libelles peuvent etre plus longs qu'un simple mot). */
.ssm-raccourci-liste { display: flex; flex-direction: column; gap: 6px; max-height: 55vh; overflow-y: auto; }
.ssm-raccourci-choix {
  display: flex; align-items: center; gap: 12px; padding: 10px 12px; border-radius: var(--radius);
  border: 1px solid var(--line-soft); background: var(--bg); color: var(--ink); cursor: pointer;
  font: 600 13px var(--font-ui); text-align: left; width: 100%; transition: border-color .15s, background .15s;
}
.ssm-raccourci-choix:hover { border-color: var(--accent); background: var(--surface-2); }
/* Selection courante (22/07/2026) : premier choix actif par defaut a l'ouverture, deplacee aux
   fleches haut/bas - voir ssm_raccourci_ouvrir_modal() (ajax.js). Memes tons que :hover pour une
   coherence visuelle (la selection clavier "ressemble" a un survol). */
.ssm-raccourci-choix--active { border-color: var(--accent); background: var(--surface-2); }
.ssm-raccourci-choix--active .ssm-raccourci-choix-touche { background: var(--accent); color: var(--accent-ink); }
.ssm-raccourci-choix-touche {
  width: 24px; height: 24px; border-radius: 50%; background: var(--surface-2); color: var(--ink-2);
  display: inline-flex; align-items: center; justify-content: center; font: 700 11px var(--font-ui); flex: none;
}
.ssm-raccourci-choix:hover .ssm-raccourci-choix-touche { background: var(--accent); color: var(--accent-ink); }
.ssm-raccourci-choix-label { flex: 1; }

/* ================= Reference complete des raccourcis clavier (22/07/2026) =================
   Modal purement informative (pas d'action au clic) ouverte depuis le panneau Reglages global -
   voir ssm_raccourcis_info_ouvrir() (ajax.js). Meme famille visuelle que .ssm-raccourci-choix
   ci-dessus (badge + texte) mais en 2 colonnes (touche a gauche, largeur fixe ; description a
   droite, qui peut faire plusieurs lignes) plutot qu'un bouton cliquable pleine largeur. */
.ssm-raccourcis-info-intro { color: var(--ink-2); font: 500 12.5px var(--font-ui); margin-bottom: 14px; }
.ssm-raccourcis-info-liste { display: flex; flex-direction: column; gap: 2px; max-height: 55vh; overflow-y: auto; }
.ssm-raccourcis-info-ligne {
  display: flex; align-items: flex-start; gap: 14px; padding: 10px 4px; border-bottom: 1px solid var(--line-soft);
}
.ssm-raccourcis-info-ligne:last-child { border-bottom: none; }
.ssm-raccourcis-info-touche {
  flex: none; width: 190px; font: 700 12px var(--font-num); color: var(--accent);
  background: var(--surface-2); border-radius: var(--radius); padding: 5px 10px; text-align: center;
  align-self: flex-start;
}
.ssm-raccourcis-info-desc { flex: 1; font: 500 12.5px var(--font-ui); color: var(--ink); line-height: 1.5; padding-top: 4px; }
@media (max-width: 560px) {
  .ssm-raccourcis-info-ligne { flex-direction: column; gap: 6px; }
  .ssm-raccourcis-info-touche { width: auto; align-self: flex-start; }
}

.ssm-reglage-dot { width: 15px; height: 15px; border-radius: 50%; flex: none; border: 1px solid rgba(0,0,0,.15); }
.ssm-reglage-colonnes { display: flex; flex-direction: column; gap: 10px; max-height: 50vh; overflow-y: auto; padding-right: 4px; }
.ssm-reglage-colonne-row {
  display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap;
  padding: 8px 10px; border-radius: var(--radius); background: var(--bg); border: 1px solid var(--line-soft);
}
.ssm-reglage-colonne-nom { font: 700 12.5px var(--font-ui); color: var(--ink); flex: 1 1 auto; min-width: 90px; }
.ssm-reglage-colonne-aligns { display: flex; gap: 3px; background: var(--surface-2); border-radius: var(--radius); padding: 2px; flex: none; }
.ssm-reglage-align-btn {
  width: 26px; height: 26px; display: inline-flex; align-items: center; justify-content: center;
  border: none; background: transparent; color: var(--ink-2); border-radius: calc(var(--radius) - 2px);
  cursor: pointer; font-size: 11px; transition: background .15s, color .15s;
}
.ssm-reglage-align-btn:hover { color: var(--ink); }
.ssm-reglage-align-btn--active { background: var(--accent); color: var(--accent-ink); }
/* Style de texte par colonne (22/07/2026, retour utilisateur : "gras normal italique") - meme
   groupe visuel que l'alignement ci-dessus, memes regles reprises via .ssm-reglage-align-btn
   (classe partagee) + une classe --active dediee pour ne pas entrer en conflit avec l'etat actif
   du groupe alignement voisin. */
.ssm-reglage-colonne-styles { margin-left: 2px; }
.ssm-reglage-style-btn {
  width: 26px; height: 26px; display: inline-flex; align-items: center; justify-content: center;
  border: none; background: transparent; color: var(--ink-2); border-radius: calc(var(--radius) - 2px);
  cursor: pointer; font-size: 11px; transition: background .15s, color .15s;
}
.ssm-reglage-style-btn:hover { color: var(--ink); }
.ssm-reglage-style-btn--active { background: var(--accent); color: var(--accent-ink); }
.ssm-reglage-colonne-dots { display: flex; gap: 6px; flex: none; }
.ssm-reglage-colonne-dots .ssm-reglage-dot { cursor: pointer; box-shadow: none; transition: box-shadow .15s, transform .15s; }
.ssm-reglage-colonne-dots .ssm-reglage-dot:hover { transform: scale(1.15); }
.ssm-reglage-colonne-dots .ssm-reglage-dot--active { box-shadow: 0 0 0 2px var(--surface), 0 0 0 4px var(--accent); }

/* ================= .ssm-tabs : onglets independants (hors card-header) =================
   Remplace .nav.nav-tabs place dans un .card-header (source du "carte dans une carte" : le
   .card-body qui suivait contenait lui-meme une carte complete). Meme langage visuel que les
   onglets .nav-tabs deja traites plus bas (couleur + trait anime, pas de fond) pour coherence. */
body[data-design] .ssm-tabs {
  display: flex; align-items: flex-end; gap: 4px; border-bottom: 1px solid var(--line);
  margin-bottom: 16px; flex-wrap: wrap;
}
body[data-design] .ssm-tabs-link {
  display: inline-flex; align-items: center; gap: 8px; padding: 10px 4px 10px; margin-right: 24px;
  font: 700 13px var(--font-ui); color: var(--ink-2) !important; text-decoration: none !important; cursor: pointer;
  border-bottom: 2px solid transparent; transition: color .15s ease, border-color .15s ease;
}
body[data-design] .ssm-tabs-link i { font-size: 13px; }
body[data-design] .ssm-tabs-link:hover { color: var(--accent) !important; border-bottom-color: var(--line); }
body[data-design] .ssm-tabs-link.active { color: var(--accent) !important; border-bottom-color: var(--accent); font-weight: 800; }

/* ================= .ssm-subtabs : sous-onglets "carte" (Statistique > Graphique, 25/07/2026) =====
   Restyle demande : formes/espacement/alignement uniquement, palette existante conservee
   (var(--accent)/var(--line-soft)/var(--ink)/var(--ink-2), aucune couleur nouvelle). Classe
   ADDITIONNELLE (en plus de .ssm-tabs/.ssm-tabs-link, gardees pour le JS Bootstrap pill) : ne
   touche pas le style des onglets .ssm-tabs de premier niveau ni des autres modules qui reutilisent
   .ssm-tabs-link ailleurs dans l'appli - override scope uniquement sous .ssm-subtabs. */
body[data-design] .ssm-subtabs {
  gap: 34px; border-bottom: 1px solid var(--line-soft); margin-bottom: 16px; align-items: center;
}
body[data-design] .ssm-subtabs .ssm-tabs-link {
  gap: 9px; padding: 0 2px 16px; margin-right: 0;
  font: 600 16px var(--font-ui); color: var(--ink-2) !important;
  border-bottom: none;
}
body[data-design] .ssm-subtabs .ssm-tabs-link i { font-size: 15px; }
body[data-design] .ssm-subtabs .ssm-tabs-link:hover { color: var(--ink) !important; border-bottom: none; }
body[data-design] .ssm-subtabs .ssm-tabs-link.active {
  font-weight: 700; color: var(--ink) !important; border-bottom: none;
  box-shadow: inset 0 -2.5px 0 var(--accent);
}

/* ---- Entree animee des cartes au chargement de page (pas dans les modales, deja animees) ---- */
@keyframes ssm-card-in {
  from { opacity: 0; transform: translateY(14px); }
  to { opacity: 1; transform: translateY(0); }
}
body[data-design] .ssm-container .card:not(.modal-content .card),
body[data-design] .ssm-container .small-box, body[data-design] .ssm-container .info-box,
body[data-design] .ssm-container .ssm-panel, body[data-design] .ssm-container .ssm-kpi {
  animation: ssm-card-in .55s cubic-bezier(.16, 1, .3, 1) both;
}
body[data-design] .ssm-container .card:nth-of-type(1), body[data-design] .ssm-container .small-box:nth-of-type(1),
body[data-design] .ssm-container .info-box:nth-of-type(1), body[data-design] .ssm-container .ssm-panel:nth-of-type(1),
body[data-design] .ssm-container .ssm-kpi:nth-of-type(1) { animation-delay: 0ms; }
body[data-design] .ssm-container .card:nth-of-type(2), body[data-design] .ssm-container .small-box:nth-of-type(2),
body[data-design] .ssm-container .info-box:nth-of-type(2), body[data-design] .ssm-container .ssm-panel:nth-of-type(2),
body[data-design] .ssm-container .ssm-kpi:nth-of-type(2) { animation-delay: 60ms; }
body[data-design] .ssm-container .card:nth-of-type(3), body[data-design] .ssm-container .small-box:nth-of-type(3),
body[data-design] .ssm-container .info-box:nth-of-type(3), body[data-design] .ssm-container .ssm-panel:nth-of-type(3),
body[data-design] .ssm-container .ssm-kpi:nth-of-type(3) { animation-delay: 120ms; }
body[data-design] .ssm-container .card:nth-of-type(4), body[data-design] .ssm-container .small-box:nth-of-type(4),
body[data-design] .ssm-container .info-box:nth-of-type(4), body[data-design] .ssm-container .ssm-panel:nth-of-type(4),
body[data-design] .ssm-container .ssm-kpi:nth-of-type(4) { animation-delay: 180ms; }
body[data-design] .ssm-container .card:nth-of-type(n+5), body[data-design] .ssm-container .small-box:nth-of-type(n+5),
body[data-design] .ssm-container .info-box:nth-of-type(n+5), body[data-design] .ssm-container .ssm-panel:nth-of-type(n+5),
body[data-design] .ssm-container .ssm-kpi:nth-of-type(n+5) { animation-delay: 220ms; }
@media (prefers-reduced-motion: reduce) {
  body[data-design] .ssm-container .card, body[data-design] .ssm-container .small-box,
  body[data-design] .ssm-container .info-box, body[data-design] .ssm-container .ssm-panel,
  body[data-design] .ssm-container .ssm-kpi { animation: none; }
  body[data-design] .card { transition: none; }
}

/* ================= .ssm-kpi : cartes de totaux/indicateurs (ex. soldes Grand Livre) =================
   21/07/2026 : remplace le motif "3 col-md-4 + 2 col-4 dont un vide pour aligner 'en cours' sous
   Solde Periode" (fragile - deux grilles Bootstrap differentes melangees pour un alignement
   visuel accidentel, signale par l'utilisateur : "j'ai utilise des colonnes vides"). "En cours"
   devient une sous-ligne DANS la carte "Solde de la Periode" (semantiquement rattache, comme
   demande), plus besoin de hack de colonnes. Classe deja anticipee dans l'animation d'entree des
   cartes ci-dessus mais jamais stylee (comme .ssm-panel avant le motif tabs/panel). */
.ssm-kpi-row { display: flex; gap: 14px; flex-wrap: wrap; margin-bottom: 4px; }
/* Pleine largeur par defaut (jusqu'aux ecrans de portable/desktop courants) ; au-dela d'un tres
   grand ecran, centrer le groupe plutot que de laisser les 3 cartes s'etaler bord a bord (demande
   utilisateur : "toute la ligne si affichage comme pc portable et centrer si grande ecran"). */
@media (min-width: 1400px) {
  .ssm-kpi-row { max-width: 1100px; margin-left: auto; margin-right: auto; }
}
/* Meme principe que les filtres : largeur de contenu uniforme forcee en pleine largeur sous
   768px, pour que les 3 cartes empilees fassent toutes la meme largeur. */
@media (max-width: 768px) {
  .ssm-kpi-row .ssm-kpi { flex: 1 1 100% !important; width: 100% !important; }
}
body[data-design] .ssm-kpi {
  flex: 1 1 220px; background: var(--surface); border: 1px solid var(--line-soft);
  border-radius: var(--radius-card); padding: 16px 20px; box-shadow: var(--shadow);
}
body[data-design] .ssm-kpi-label {
  display: flex; align-items: center; gap: 8px; font: 700 11px var(--font-ui); letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-2); margin-bottom: 10px;
}
body[data-design] .ssm-kpi-value {
  display: flex; align-items: center; gap: 9px; font: 800 25px var(--font-num); color: var(--ink);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
body[data-design] .ssm-kpi-value i { font-size: 16px; }
body[data-design] .ssm-kpi-value.ssm-kpi-positive { color: var(--ok); }
body[data-design] .ssm-kpi-value.ssm-kpi-negative { color: var(--bad); }
body[data-design] .ssm-kpi-sub {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  margin-top: 12px; padding-top: 12px; border-top: 1px dashed var(--line-soft);
  font: 700 12px var(--font-ui); color: var(--ink-2);
}
body[data-design] .ssm-kpi-sub strong { color: var(--ink); font: 800 13px var(--font-num); }

/* ================= .ssm-chart-card : conteneur graphique (Chart.js) =================
   Redesign Statistique/Credits (23/07/2026) : meme carte que .ssm-kpi (fond/bordure/ombre) pour un
   canvas Chart.js, avec un titre au-dessus - reutilisable pour toute future vue avec graphique. */
body[data-design] .ssm-chart-card {
  background: var(--surface); border: 1px solid var(--line-soft); border-radius: var(--radius-card);
  box-shadow: var(--shadow); padding: 16px 18px;
}
body[data-design] .ssm-chart-titre {
  font: 700 13px var(--font-ui); color: var(--ink-2); margin-bottom: 12px;
}
body[data-design] .ssm-chart-titre i { color: var(--accent); margin-right: 8px; }
body[data-design] .ssm-chart-zone { position: relative; height: 280px; }
body[data-design] .ssm-chart-zone canvas { max-height: 100%; }

/* ================= .ssm-chart-legende : legende HORS-CANVAS (25/07/2026) =================
   Statistique\Graphique : la legende native Chart.js est dessinee DANS le canvas - son detecteur
   de clic depend donc entierement de la geometrie du canvas au moment du clic (survol/legende
   decales signale par l'utilisateur sur les graphiques a plusieurs courbes/annees, meme apres le
   fix chart.resize() sur shown.bs.tab). Remplacee par une vraie legende DOM (boutons HTML, un par
   dataset, par INDEX explicite) pour les graphiques ou activer/desactiver une courbe est un
   vrai besoin (comparaison pluriannuelle, marge, general) - clic 100% fiable, independant de
   toute geometrie canvas. `plugins.legend.display:false` sur ces charts, legende native gardee
   ailleurs (encaissement, repartition par produit...) ou le besoin de toggle est secondaire. */
body[data-design] .ssm-chart-legende { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; justify-content: center; }
body[data-design] .ssm-chart-legende-item {
  display: inline-flex; align-items: center; gap: 6px; padding: 4px 10px; border-radius: 999px;
  border: 1px solid var(--line-soft); background: var(--surface); color: var(--ink);
  font: 600 11.5px var(--font-ui); cursor: pointer; user-select: none;
  transition: opacity .15s ease, background .15s ease;
}
body[data-design] .ssm-chart-legende-item:hover { background: var(--surface-2); }
body[data-design] .ssm-chart-legende-item__puce { width: 10px; height: 10px; border-radius: 50%; flex: none; }
body[data-design] .ssm-chart-legende-item--masque { opacity: .4; text-decoration: line-through; }
/* Boutons "global" (Tout Vente/Tout Achat, 25/07/2026, Comparaison uniquement) : meme pilule que
   les boutons individuels, juste distingue par un contour en tirets pour signaler que le clic
   agit sur plusieurs courbes a la fois (pas de nouvelle couleur, var(--accent) deja utilisee). */
body[data-design] .ssm-chart-legende-item--global { font-weight: 700; border-style: dashed; border-color: var(--accent); }

/* ================= .ssm-filtre-row : filtre "colonne" (Statistique > Graphique > Comparaison,
   25/07/2026) ================= Restyle demande : formes/espacement/alignement uniquement,
   palette existante conservee (var(--line-soft)/var(--ink)/var(--ink-2)/var(--bg)), pas de
   nouvelle couleur. Remplace le pattern .input-group-sm (label+control cote a cote dans une
   pilule) par un layout "colonne" (label au-dessus, control en dessous) pour CE filtre precis -
   .input-group.input-group-sm garde son style existant partout ailleurs dans l'appli. */
body[data-design] .ssm-filtre-row { display: flex; align-items: stretch; gap: 14px; flex-wrap: wrap; }
body[data-design] .ssm-filtre-col { display: flex; flex-direction: column; gap: 6px; flex: 1; min-width: 150px; }
body[data-design] .ssm-filtre-col--large { flex: 1.4; }
body[data-design] .ssm-filtre-col--action { flex: 0 0 auto; justify-content: flex-end; }
body[data-design] .ssm-filtre-label {
  font: 700 11px var(--font-ui); text-transform: uppercase; letter-spacing: .06em; color: var(--ink-2);
}
/* Select natif (Mois du/Au) : boite/rayon/hauteur uniformes, la fleche existante (regle globale
   select.custom-select plus haut) sert deja de chevron - rien a ajouter. */
body[data-design] .ssm-filtre-col select.custom-select {
  height: 44px; border-radius: 10px; padding: 0 30px 0 13px; border-color: var(--line-soft);
}
/* Select2 multiple (Annees) : meme boite que les selects voisins. Le template "multiple" de
   Select2 ne genere PAS d'element fleche (contrairement au mode single, deja gere plus haut) -
   chevron ajoute via ::after, positionne en flex (le conteneur est deja display:flex !important). */
body[data-design] .ssm-filtre-col .select2-container { width: 100% !important; }
body[data-design] .ssm-filtre-col .select2-selection--multiple {
  border-radius: 10px !important; min-height: 44px !important; padding: 5px 28px 5px 13px !important;
  position: relative;
}
body[data-design] .ssm-filtre-col .select2-selection--multiple::after {
  content: '▾'; position: absolute; right: 13px; top: 50%; transform: translateY(-50%);
  color: var(--ink-2); pointer-events: none; font-size: 11px;
}
body[data-design] .ssm-filtre-col--action .ssm-btn { height: 44px; border-radius: 10px; align-self: flex-end; }

/* ================= .ssm-seg-track : bascule segmentee "pilule" (meme page, 25/07/2026) =========
   Variante scopee de .ssm-seg-btn (deja globale, utilisee ailleurs - ex. Clair/Sombre du panneau
   reglages - non touchee) : piste avec espacement/rayon/ombre propres a ce toggle Montants/
   Quantites, palette existante (var(--accent)/var(--accent-ink)/var(--ink-2)/var(--line-soft)). */
body[data-design] .ssm-seg-track {
  display: flex; gap: 6px; padding: 5px; border-radius: 12px; border: 1px solid var(--line-soft);
  width: fit-content; position: relative;
}
body[data-design] .ssm-seg-track .ssm-seg-btn {
  flex: 1; text-align: center; padding: 12px; border-radius: 8px; border: none;
  background: transparent; color: var(--ink-2); box-shadow: none; white-space: nowrap;
  position: relative; z-index: 1; transition: color .2s ease;
}
body[data-design] .ssm-seg-track .ssm-seg-btn:hover { border-color: transparent; color: var(--ink); }
body[data-design] .ssm-seg-track .ssm-seg-btn.ssm-seg-btn--active {
  background: transparent; color: var(--accent-ink); box-shadow: none;
}
/* Curseur glissant anime (25/07/2026, "changement de tabs comme on/off avec animation") : un seul
   bloc colore en position absolue qui glisse d'un segment a l'autre (transition CSS sur transform),
   au lieu d'un fond qui saute instantanement d'un bouton a l'autre. Marche pour un track a
   EXACTEMENT 2 segments de largeur egale (flex:1 chacun, cas de Montants/Quantites et Chiffre
   d'Affaires/Quantite) : le curseur fait "calc(50% - 8px)" (moitie de la piste moins
   padding+la moitie du gap), et translateX(calc(100% + 6px)) le deplace exactement de sa propre
   largeur + le gap - independant de la largeur reelle de la piste, aucune mesure JS necessaire. */
body[data-design] .ssm-seg-track::before {
  content: ''; position: absolute; top: 5px; bottom: 5px; left: 5px;
  width: calc(50% - 8px); background: var(--accent); border-radius: 8px;
  box-shadow: 0 2px 6px var(--accent-soft); z-index: 0;
  transition: transform .25s ease;
}
body[data-design] .ssm-seg-track.ssm-seg-track--seg2::before { transform: translateX(calc(100% + 6px)); }

/* ================= .ssm-pct : badge % d'evolution vs l'annee precedente (25/07/2026) =========
   Statistique > Graphique > Comparaison - cartes de totaux Vente/Achat + cartes Encaissement.
   Palette existante (var(--ok)/var(--ok-bg) hausse, var(--bad)/var(--bad-bg) baisse) - simple
   convention "vert = en hausse / rouge = en baisse", sans jugement metier (une hausse d'Achat
   n'est pas forcement "positive", juste "en hausse"). */
body[data-design] .ssm-pct {
  display: inline-flex; align-items: center; gap: 3px; font: 700 11px var(--font-ui);
  padding: 1px 7px; border-radius: 999px; margin-left: 6px; vertical-align: middle;
}
body[data-design] .ssm-pct--hausse { background: var(--ok-bg); color: var(--ok); }
body[data-design] .ssm-pct--baisse { background: var(--bad-bg); color: var(--bad); }
body[data-design] .ssm-pct i { font-size: 9px; }

/* ================= .ssm-table--comparaison : colonnes annees alignees a droite (25/07/2026) ====
   Statistique > Graphique > Comparaison (tableaux totaux Vente/Achat + encaissement) - scope a
   cette classe uniquement, ne touche pas table.ssm-table generique utilisee ailleurs (DataTables
   avec d'autres structures de colonnes). 1ere colonne (le "Type"/libelle) reste alignee a gauche. */
body[data-design] table.ssm-table--comparaison th:not(:first-child),
body[data-design] table.ssm-table--comparaison td:not(:first-child) { text-align: right; }

/* ================= .ssm-stat-row : totaux "juste des chiffres", sans habillage carte =================
   21/07/2026 : retour utilisateur sur les totaux du Grand Livre - "ce sont juste des totaux",
   le traitement carte/ombre/bordure de .ssm-kpi etait trop lourd pour un simple recapitulatif de
   3 nombres dans l'en-tete d'un panel. Bande legere, sans fond ni bordure individuelle, separateurs
   fins entre chaque valeur. La structure HTML est rendue une seule fois (jamais remplacee) ; seul
   le texte des .ssm-stat-value change au changement de filtre (cf. Livre.php + ssm_stat_set() dans
   ajax.js), avec un etat .is-loading (fondu discret) le temps de la requete - jamais tout le bloc
   qui disparait derriere un loader generique. */
.ssm-stat-row { display: flex; align-items: stretch; gap: 24px; flex-wrap: wrap; margin-top: 14px; }
/* Variante "sous un tableau" (22/07/2026) : Total Page/Total Filtré d'une DataTable, place APRES
   le tableau plutot que dans l'en-tete du panel (contexte Grand Livre) - separateur net + centre,
   pour bien le distinguer visuellement du tableau juste au-dessus. Voir Encaissements.php,
   ssm_table_totaux() (ajax.js) - modele a reprendre pour toute autre table a montants. */
.ssm-stat-row--fin { justify-content: center; margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--line-soft); }
.ssm-stat { display: flex; flex-direction: column; gap: 4px; justify-content: center; }
.ssm-stat-sep { width: 1px; align-self: stretch; background: var(--line-soft); }
body[data-design] .ssm-stat-label {
  display: flex; align-items: center; gap: 6px; font: 700 10.5px var(--font-ui);
  text-transform: uppercase; letter-spacing: .05em; color: var(--ink-2);
}
body[data-design] .ssm-stat-label i { color: var(--accent); font-size: 11px; }
body[data-design] .ssm-stat-value {
  font: 800 20px var(--font-num); color: var(--ink); font-variant-numeric: tabular-nums;
  white-space: nowrap; transition: opacity .2s ease;
}
body[data-design] .ssm-stat-value.ssm-stat-positive { color: var(--ok); }
body[data-design] .ssm-stat-value.ssm-stat-negative { color: var(--bad); }
body[data-design] .ssm-stat-value.is-loading { opacity: .35; }
body[data-design] .ssm-stat-sub {
  display: flex; align-items: center; gap: 5px; font: 600 11px var(--font-ui); color: var(--ink-2);
}
/* Squelette (premier chargement uniquement, avant que le premier chiffre n'arrive) : un bandeau
   qui "respire" plutot qu'un 0 ou un blanc brut. */
.ssm-stat-skeleton {
  display: inline-block; width: 86px; height: 17px; border-radius: 4px;
  background: linear-gradient(90deg, var(--surface-2) 25%, var(--line-soft) 50%, var(--surface-2) 75%);
  background-size: 200% 100%; animation: ssm-skeleton-shimmer 1.2s ease-in-out infinite;
}
@keyframes ssm-skeleton-shimmer {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}
@media (prefers-reduced-motion: reduce) {
  .ssm-stat-skeleton { animation: none; }
}

/* ================= Tableaux / DataTables (neuf, remplace dataTables.bootstrap4) ================= */
table.ssm-table, body[data-design] table.dataTable {
  width: 100% !important; border-collapse: separate; border-spacing: 0;
  font: 13px var(--font-ui); color: var(--ink);
}
/* En-tete sticky : reste visible en haut du viewport pendant le defilement d'un tableau long.
   Fond obligatoirement opaque (var(--surface), pas transparent) sinon le contenu des lignes
   defilerait visuellement "a travers" l'en-tete colle. Necessite qu'aucun ancetre entre le
   thead et la zone de defilement n'ait overflow != visible (cf. correctif .ssm-panel plus haut). */
table.ssm-table thead th, body[data-design] table.dataTable thead th {
  text-align: left; padding: 10px 14px; font: 700 10.5px var(--font-ui);
  text-transform: uppercase; letter-spacing: .05em; color: var(--ink-2);
  border-bottom: 1px solid var(--line) !important; background: var(--surface) !important;
  box-shadow: none !important; position: sticky; top: 0; z-index: 2;
}
table.ssm-table tbody td, body[data-design] table.dataTable tbody td {
  padding: 10px 14px; border-bottom: 1px solid var(--line-soft) !important;
  font-variant-numeric: tabular-nums;
}
table.ssm-table tbody tr:hover, body[data-design] table.dataTable tbody tr:hover { background: var(--surface-2); }
table.ssm-table tbody tr:last-child td { border-bottom: none !important; }

.ssm-dt-toolbar { display: flex; justify-content: space-between; align-items: center; padding: 10px 14px; flex-wrap: wrap; gap: 10px; }
/* Recherche et "nombre de lignes" : meme famille visuelle, meme hauteur exacte (36px) - avant,
   le texte "Afficher"/"lignes" du label heritait du meme font-size que le champ (13px, trop
   voyant pour du texte d'accompagnement) et le <select> gardait l'apparence native du navigateur
   (bouton systeme, hauteur differente du champ de recherche a cote) au lieu d'etre stylise comme
   n'importe quel autre champ de l'appli. */
.ssm-dt-toolbar .dataTables_filter label {
  display: flex; align-items: center; gap: 8px; margin: 0; font: 600 11.5px var(--font-ui);
  text-transform: uppercase; letter-spacing: .03em; color: var(--ink-2);
}
.ssm-dt-toolbar .dataTables_filter input {
  background: var(--bg); border: 1px solid var(--line-soft); border-radius: var(--radius);
  height: 36px; padding: 0 12px; color: var(--ink); font: 500 13px var(--font-ui); min-width: 220px;
  box-sizing: border-box;
}
.ssm-dt-toolbar .dataTables_filter input:focus { outline: none; border-color: var(--accent); }
/* Selecteur "nombre de lignes" (10/20/50/100/Tout) : desactive globalement avant (lengthChange:
   false), reactive partout ou init_datatable() est utilise sans le desactiver localement (voir
   commentaire dans ajax.js). Meme famille visuelle que le champ de recherche a cote. */
.ssm-dt-toolbar .dataTables_length label {
  display: flex; align-items: center; gap: 8px; margin: 0; font: 600 11.5px var(--font-ui);
  text-transform: uppercase; letter-spacing: .03em; color: var(--ink-2); white-space: nowrap;
}
.ssm-dt-toolbar .dataTables_length select {
  -webkit-appearance: none; -moz-appearance: none; appearance: none;
  background: var(--bg) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none' stroke='%23888' stroke-width='2'%3E%3Cpath d='M6 8l4 4 4-4'/%3E%3C/svg%3E") no-repeat right 8px center / 11px;
  border: 1px solid var(--line-soft); border-radius: var(--radius);
  height: 36px; padding: 0 26px 0 10px; color: var(--ink); font: 700 12.5px var(--font-num);
  cursor: pointer; box-sizing: border-box;
}
.ssm-dt-toolbar .dataTables_length select:focus { outline: none; border-color: var(--accent); }
/* Groupe "recherche + actions" (Imprimer/Exporter) : injecte par ssm_table_toolbar() (ajax.js)
   juste avant le champ de recherche, dans le meme conteneur flex, plutot qu'au niveau du filtre
   du panel (retour utilisateur : integrer ca au niveau du tableau, pres de la recherche). */
.ssm-dt-search-group { display: flex; align-items: center; gap: 8px; }
.ssm-table-actions { display: flex; align-items: center; gap: 6px; }
.ssm-dt-foot { display: flex; align-items: center; justify-content: space-between; padding: 10px 14px; flex-wrap: wrap; gap: 8px; }
.ssm-dt-foot .dataTables_info { font: 12px var(--font-num); color: var(--ink-2); }
.dataTables_processing { background: var(--surface) !important; color: var(--ink) !important; border: 1px solid var(--line) !important; border-radius: var(--radius); z-index: 2; }
/* Effet "brouillard" pendant le chargement (24/07/2026) : donnees floutees, comme un feu
   d'automobile en face - en plus (pas a la place) de l'indicateur "Traitement en cours…"
   (z-index au-dessus, non flouté lui-meme puisque hors de table.ssm-table). */
table.ssm-table.ssm-table-brouillard {
  filter: blur(3px);
  opacity: .6;
  pointer-events: none;
  transition: filter .15s ease, opacity .15s ease;
}
table.ssm-table { transition: filter .15s ease, opacity .15s ease; }

/* ================= Pagination =================
   L'integration Bootstrap4 de DataTables rend chaque page comme
   <li class="paginate_button page-item"><a class="page-link">1</a></li> — l'element visible/
   cliquable est .page-link (dans le <li>), pas .paginate_button lui-meme (qui n'a pas de boite
   visible). Cible les deux pour couvrir toutes les tables, migrees vers init_datatable() ou non
   ("carre autour des numeros de page" signale par l'utilisateur = style Bootstrap .page-link
   jamais repris). */
body[data-design] .dataTables_wrapper .dataTables_paginate,
.ssm-dt-foot .dataTables_paginate { display: flex; gap: 4px; }
body[data-design] .dataTables_wrapper .dataTables_paginate .paginate_button { margin: 0; }
body[data-design] .dataTables_wrapper .dataTables_paginate .page-link,
body[data-design] .dataTables_wrapper .dataTables_paginate span.ellipsis {
  min-width: 28px; height: 28px; display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--radius) !important; border: 1px solid var(--line) !important; color: var(--ink-2) !important;
  font: 600 12px var(--font-num) !important; cursor: pointer; padding: 0 8px !important;
  background: var(--surface) !important; box-shadow: none !important; margin: 0;
}
body[data-design] .dataTables_wrapper .dataTables_paginate .page-link:hover {
  border-color: var(--accent) !important; color: var(--accent) !important; background: var(--surface-2) !important;
}
body[data-design] .dataTables_wrapper .dataTables_paginate .page-item.active .page-link {
  background: var(--accent) !important; border-color: var(--accent) !important; color: var(--accent-ink) !important;
}
body[data-design] .dataTables_wrapper .dataTables_paginate .page-item.disabled .page-link {
  opacity: .4; cursor: default; background: var(--surface) !important; color: var(--ink-2) !important;
}

/* Repli generique pour les tables pas encore migrees vers init_datatable() */
body[data-design] .dataTables_wrapper .dataTables_length select { background: var(--bg); border: 1px solid var(--line-soft); color: var(--ink); border-radius: var(--radius); }

/* ================= Champs de formulaire ================= */
.ssm-input, .ssm-field select,
body[data-design] .form-control, body[data-design] select.form-control {
  width: 100%; background: var(--bg); border: 1px solid var(--line-soft); color: var(--ink);
  border-radius: var(--radius); padding: 9px 11px; font: 500 13px var(--font-ui);
}
/* Correctif important : width:100% ci-dessus casse tout .input-group Bootstrap "classique"
   (pas -sm) — Bootstrap donne normalement flex:1 1 auto + width:1% a son .form-control interne
   pour qu'il partage la ligne avec les boutons ; notre width:100% ecrasait ca et forcait
   .input-group (qui a flex-wrap:wrap par defaut) a empiler input/boutons chacun sur sa ligne
   ("groupe nouveau/annuler tout desorganise" signale). On restaure le comportement Bootstrap
   dans ce contexte precis. */
body[data-design] .input-group > .form-control, body[data-design] .input-group > .ssm-input,
body[data-design] .input-group .ssm-btn-group { width: 1%; flex: 1 1 auto; }
body[data-design] .input-group { flex-wrap: nowrap; align-items: stretch; }
body[data-design] .input-group .ssm-btn-group { display: flex; }
body[data-design] .input-group .ssm-btn-icon { border-radius: 0; flex: none; height: auto; }
body[data-design] .input-group .ssm-btn-group .ssm-btn-icon:first-child { border-radius: var(--radius) 0 0 var(--radius); }
body[data-design] .input-group .ssm-btn-group .ssm-btn-icon:last-child { border-radius: 0 var(--radius) var(--radius) 0; }
body[data-design] .input-group > .form-control, body[data-design] .input-group > .ssm-input { border-radius: 0; }

body[data-design] .form-control:focus, .ssm-input:focus {
  outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft, var(--warn-bg));
}
.ssm-field-label, body[data-design] label { display: block; font: 700 10.5px var(--font-ui); text-transform: uppercase; letter-spacing: .05em; color: var(--ink-2); margin-bottom: 5px; }
/* ================= Select2 (widget JS qui remplace le <select> natif — largeur/liste non geree avant) =================
   select2-bootstrap4-theme pose deja background/border/border-radius sur .select2-selection ET
   .select2-selection--single (2 classes portees par le meme element) : on doit neutraliser les
   DEUX selecteurs explicitement, sinon un residu (coin carre, double bordure) reste visible —
   c'est le "carre autour du select" signale par l'utilisateur. */
body[data-design] .select2-container { min-width: 160px; }
body[data-design] .input-group.input-group-sm .select2-container { min-width: 150px; max-width: 260px; flex: 1; }
/* Correction (20/07/2026) : le "borderless partout" precedent partait d'un mauvais diagnostic —
   Select2 est utilise a la fois DANS des pilules de filtre (qui fournissent deja un contour :
   pas besoin d'une 2e bordure) et SEUL dans des formulaires de modale (qui ont besoin de leur
   propre boite, comme n'importe quel champ) ; le rendre borderless partout laissait les
   formulaires de modale sans aucune boite visible ("pas d'identite" signale). Par defaut : boite
   complete comme .form-control. Borderless UNIQUEMENT quand reellement imbrique dans une pilule. */
body[data-design] .select2-selection,
body[data-design] .select2-selection--single,
body[data-design] .select2-container--bootstrap4 .select2-selection,
body[data-design] .select2-container--bootstrap4 .select2-selection--single {
  background: var(--bg) !important; border: 1px solid var(--line-soft) !important; box-shadow: none !important; outline: none !important;
  border-radius: var(--radius) !important; color: var(--ink) !important; height: 40px !important;
  display: flex !important; align-items: center; font: 600 13px var(--font-ui);
  transition: border-color .15s ease, box-shadow .15s ease;
}
body[data-design] .ssm-filter .select2-selection, body[data-design] .ssm-filter .select2-selection--single,
body[data-design] .input-group.input-group-sm .select2-selection, body[data-design] .input-group.input-group-sm .select2-selection--single {
  background: transparent !important; border: none !important; border-radius: 0 !important;
}
body[data-design] .select2-container--bootstrap4 .select2-selection__rendered {
  color: var(--ink) !important; padding-left: 10px; line-height: normal !important;
}
body[data-design] .select2-container--bootstrap4 .select2-selection__placeholder { color: var(--ink-2) !important; }
body[data-design] .select2-container--bootstrap4 .select2-selection__arrow { height: 38px !important; }
body[data-design] .select2-container--bootstrap4.select2-container--focus .select2-selection,
body[data-design] .select2-container--bootstrap4.select2-container--open .select2-selection {
  border-color: var(--accent) !important; box-shadow: 0 0 0 3px var(--accent-soft) !important;
}
body[data-design] .select2-container--open .select2-dropdown {
  background: var(--surface) !important; border: 1px solid var(--line-soft) !important; border-radius: var(--radius);
  box-shadow: var(--shadow); min-width: 220px; overflow: hidden;
}
body[data-design] .select2-search--dropdown .select2-search__field {
  background: var(--bg) !important; border: 1px solid var(--line-soft) !important; color: var(--ink) !important;
  border-radius: var(--radius); padding: 6px 9px; font: 13px var(--font-ui);
}
body[data-design] .select2-results__option {
  color: var(--ink); font: 13px var(--font-ui); padding: 8px 12px; white-space: normal;
}
body[data-design] .select2-results__option--highlighted[aria-selected] {
  background: var(--accent) !important; color: var(--accent-ink) !important;
}
body[data-design] .select2-results__option[aria-selected="true"] { background: var(--surface-2); color: var(--ink); }

/* ================= Select2 multiple (`multiple` sur le <select>, ex. filtre "Annees" de
   Statistique\Graphique > Comparaison) =================
   25/07/2026 : les regles ci-dessus ne ciblent que `--single` - `--multiple` est une classe
   differente sur le meme conteneur, donc restait totalement hors theme (hauteur non fixee ->
   case plus basse que les selects voisins dans le meme .ssm-panel-toolbar = "mal aligne" signale,
   et les tags des annees choisies gardaient le bleu par defaut de Select2 = "background bleu hors
   du theme" signale). Meme traitement pilule que --single : boite complete par defaut, borderless
   quand imbrique dans .input-group-sm/.ssm-filter. */
body[data-design] .select2-selection--multiple,
body[data-design] .select2-container--bootstrap4 .select2-selection--multiple {
  background: var(--bg) !important; border: 1px solid var(--line-soft) !important; box-shadow: none !important; outline: none !important;
  border-radius: var(--radius) !important; min-height: 40px !important; display: flex !important; align-items: center;
  transition: border-color .15s ease, box-shadow .15s ease;
}
body[data-design] .ssm-filter .select2-selection--multiple,
body[data-design] .input-group.input-group-sm .select2-selection--multiple {
  background: transparent !important; border: none !important; border-radius: 0 !important;
}
body[data-design] .select2-selection--multiple .select2-selection__rendered {
  display: flex !important; flex-wrap: wrap; align-items: center; gap: 4px; width: 100%;
  padding: 3px 6px !important; margin: 0 !important; list-style: none;
}
body[data-design] .select2-selection--multiple .select2-search--inline .select2-search__field {
  background: transparent !important; color: var(--ink) !important; font: 600 13px var(--font-ui); margin-top: 0 !important;
}
/* Tag "annee choisie" : remplace le bleu/gris par defaut de Select2 par les couleurs de theme. */
body[data-design] .select2-selection__choice {
  background: var(--accent-soft) !important; border: 1px solid var(--accent) !important;
  color: var(--ink) !important; border-radius: var(--radius) !important; font: 700 12px var(--font-ui);
  padding: 2px 6px 2px 8px !important; margin: 2px 0 !important; display: inline-flex !important; align-items: center; gap: 6px;
}
body[data-design] .select2-selection__choice__remove {
  color: var(--accent) !important; border: none !important; background: transparent !important;
  order: -1; margin-right: 0 !important; font-weight: 700;
}
body[data-design] .select2-selection__choice__remove:hover { color: var(--bad) !important; }
body[data-design] .select2-container--bootstrap4.select2-container--focus .select2-selection--multiple,
body[data-design] .select2-container--bootstrap4.select2-container--open .select2-selection--multiple {
  border-color: var(--accent) !important; box-shadow: 0 0 0 3px var(--accent-soft) !important;
}
body[data-design] .icheck-primary > input:first-child:checked + input[type="hidden"] + label::before,
body[data-design] .icheck-primary > input:first-child:not(:checked) + input[type="hidden"] + label::before { border-color: var(--accent); }

/* ================= Modales (JS Bootstrap conserve, habillage neuf) =================
   Couleur contextuelle : data-mode="ajout" (creation, ok) vs "modification" (accent de
   la direction) sur .modal-content — barre superieure + icone d'en-tete. A ajouter au
   fil de l'eau sur les autres vues modal/*.php : <div class="modal-content" data-mode="ajout|modification">
   + <span class="ssm-modal-icon"><i class="fa ..."></i></span> juste apres le modal-header. */
body[data-design] .modal-content {
  background: var(--surface); color: var(--ink); border: 1px solid var(--line);
  border-radius: var(--radius-card); box-shadow: var(--shadow); border-top: 3px solid var(--line);
  overflow: hidden;
}
/* Sur Irise, --surface est volontairement translucide (effet verre) : sans flou sur la modale
   elle-meme (le flou du backdrop ne suffit pas), le contenu de la page transparaissait derriere
   les champs — effet "sale" signale. On transforme la transparence en vrai verre depoli. */
@supports (backdrop-filter: blur(1px)) {
  body[data-design] .modal-content { backdrop-filter: blur(20px); }
}
body[data-design] .modal-content[data-mode="ajout"] { border-top-color: var(--ok); }
body[data-design] .modal-content[data-mode="modification"] { border-top-color: var(--accent); }
/* 23/07/2026 : 3e mode pour les modales de confirmation d'une action destructive/irreversible sur
   un ENSEMBLE entier (cloturer/annuler la cloture/supprimer un etat - pas une simple ligne de
   tableau, qui garde dt_btn_dropdown_confirm()) - voir ssm_confirmer() (ajax.js). */
body[data-design] .modal-content[data-mode="suppression"] { border-top-color: var(--bad); }
body[data-design] .modal-header {
  background: var(--surface-2) !important; border-bottom: 1px solid var(--line); color: var(--ink) !important;
  border-top-left-radius: 0; border-top-right-radius: 0; display: flex; align-items: center; gap: 14px;
  padding: 18px 22px; position: relative; overflow: hidden;
}
/* halo discret derriere l'icone, meme esprit que le badge du sous-menu de module */
body[data-design] .modal-content[data-mode="ajout"] .modal-header::before,
body[data-design] .modal-content[data-mode="modification"] .modal-header::before,
body[data-design] .modal-content[data-mode="suppression"] .modal-header::before {
  content: ""; position: absolute; top: -40%; left: -60px; width: 160px; height: 220%;
  background: radial-gradient(circle, var(--accent-soft, var(--surface)) 0%, transparent 70%);
  opacity: .5; pointer-events: none;
}
body[data-design] .modal-content[data-mode="ajout"] .modal-header::before {
  background: radial-gradient(circle, var(--ok-bg) 0%, transparent 70%);
}
body[data-design] .modal-content[data-mode="suppression"] .modal-header::before {
  background: radial-gradient(circle, var(--bad-bg) 0%, transparent 70%);
}
body[data-design] .ssm-modal-icon {
  width: 38px; height: 38px; border-radius: var(--radius); display: inline-flex; align-items: center; justify-content: center;
  background: var(--surface); font-size: 15px; flex: none; position: relative; z-index: 1;
}
body[data-design] .modal-content[data-mode="ajout"] .ssm-modal-icon {
  background: var(--ok-bg); color: var(--ok); box-shadow: 0 0 0 4px var(--surface-2);
}
body[data-design] .modal-content[data-mode="suppression"] .ssm-modal-icon {
  background: var(--bad-bg); color: var(--bad); box-shadow: 0 0 0 4px var(--surface-2);
}
body[data-design] .modal-content[data-mode="modification"] .ssm-modal-icon {
  background: var(--accent-soft, var(--surface)); color: var(--accent); box-shadow: 0 0 0 4px var(--surface-2);
}
body[data-design] .modal-title { flex: 1; font: 700 17px var(--font-display); position: relative; z-index: 1; }
body[data-design] .modal-header .close {
  color: var(--ink); opacity: .55; text-shadow: none; margin: 0; position: relative; z-index: 1;
  transition: opacity .15s, transform .15s;
}
body[data-design] .modal-header .close:hover { opacity: 1; color: var(--bad); transform: rotate(90deg); }
body[data-design] .modal-footer { border-top: 1px solid var(--line); padding: 16px 22px; gap: 8px; }
body[data-design] .modal-footer .btn:not(.ssm-btn) {
  border-radius: var(--radius); font: 700 12.5px var(--font-ui); padding: 9px 18px;
}
body[data-design] .modal-footer .ssm-btn, body[data-design] .modal-footer .btn { transition: transform .12s ease, background .12s ease; }
body[data-design] .modal-footer .ssm-btn:hover:not(:disabled), body[data-design] .modal-footer .btn:hover:not(:disabled) { transform: translateY(-1px); }
body[data-design] .modal-content[data-mode="ajout"] .modal-footer .ssm-btn-primary { background: var(--ok); border-color: var(--ok); }
body[data-design] .modal-content[data-mode="ajout"] .modal-footer .ssm-btn-primary:hover { background: var(--ok); filter: brightness(1.08); }
body[data-design] .modal-backdrop.show { opacity: .6; background: var(--ink); }

/* ================= Barre de fermeture automatique d'une modale (21/07/2026) =================
   Injectee par ssm_modal_auto_close() (ajax.js) tout en haut de .modal-content (celui-ci a
   overflow:hidden, donc la barre epouse naturellement les coins arrondis). Se retire d'elle-meme
   des que l'utilisateur interagit avec la modale (voir la fonction JS) - jamais de fermeture
   surprise si l'utilisateur est en train de continuer a l'utiliser. */
.ssm-modal-timer { height: 3px; background: var(--bad-bg); flex: none; }
.ssm-modal-timer-bar { height: 100%; width: 100%; background: var(--bad); }

/* ================= Notifications (remplace toastr sur les flux modernises) =================
   Pile empilee en haut a droite, une carte par notification (memes tokens que le reste de
   l'appli - contrairement a toastr, qui garde son propre habillage generique non alignes sur les
   4 directions). Voir ssm_notify() (ajax.js). */
.ssm-toast-stack {
  position: fixed; top: 68px; right: 18px; z-index: 2000;
  display: flex; flex-direction: column; gap: 10px; pointer-events: none;
  max-width: min(340px, calc(100vw - 36px));
  width: min(340px, calc(100vw - 36px));
}
.ssm-toast {
  pointer-events: auto; display: flex; align-items: flex-start; gap: 10px;
  padding: 12px 14px; border-radius: var(--radius-card); background: var(--surface);
  border: 1px solid var(--line-soft); box-shadow: var(--shadow); color: var(--ink);
  font: 600 12.5px var(--font-ui);
  transform: translateX(120%); opacity: 0; transition: transform .3s ease, opacity .3s ease;
}
.ssm-toast--montre { transform: translateX(0); opacity: 1; }
.ssm-toast-icon {
  width: 30px; height: 30px; border-radius: 50%; flex: none; font-size: 13px; margin-top: 1px;
  display: inline-flex; align-items: center; justify-content: center;
}
.ssm-toast--success .ssm-toast-icon { background: var(--ok-bg); color: var(--ok); }
.ssm-toast--danger .ssm-toast-icon { background: var(--bad-bg); color: var(--bad); }
.ssm-toast--warning .ssm-toast-icon { background: var(--warn-bg); color: var(--warn); }
.ssm-toast--info .ssm-toast-icon { background: var(--surface-2); color: var(--accent); }
.ssm-toast-body { flex: 1; min-width: 0; }
.ssm-toast-text { display: block; padding-top: 4px; }
.ssm-toast-details {
  display: flex; flex-direction: column; gap: 3px; margin-top: 8px; padding-top: 8px;
  border-top: 1px solid var(--line-soft);
}
.ssm-toast-detail { display: flex; gap: 6px; font: 500 11.5px var(--font-ui); color: var(--ink-2); }
.ssm-toast-detail-label { flex: none; font-weight: 700; color: var(--ink-2); }
.ssm-toast-detail-valeur { color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ssm-toast-close { background: none; border: none; color: var(--ink-2); cursor: pointer; font-size: 11px; flex: none; padding: 2px; margin-top: 2px; }
.ssm-toast-close:hover { color: var(--ink); }
@media (prefers-reduced-motion: reduce) {
  .ssm-toast { transition: none; }
}
@supports (backdrop-filter: blur(2px)) {
  body[data-design] .modal-backdrop.show { backdrop-filter: blur(1.5px); }
}
@media (prefers-reduced-motion: reduce) {
  body[data-design] .modal-header .close, body[data-design] .modal-footer .ssm-btn, body[data-design] .modal-footer .btn { transition: none; }
}

/* ================= Cases a cocher / radios (custom-control Bootstrap) ================= */
body[data-design] .custom-control-label::before {
  background: var(--bg); border: 1px solid var(--line); box-shadow: none;
}
body[data-design] .custom-control-input:checked ~ .custom-control-label::before {
  background: var(--accent) !important; border-color: var(--accent) !important;
}
body[data-design] .custom-control-input:focus ~ .custom-control-label::before { box-shadow: 0 0 0 3px var(--accent-soft, var(--surface-2)); }
body[data-design] .custom-control-label { color: var(--ink); font: 500 13px var(--font-ui); }

/* ================= Rangee "Options" des modales (checkboxes de roles) =================
   Remplace le custom-checkbox Bootstrap brut (case + libelle nu sur fond gris injecte) par des
   pastilles cliquables homogenes avec le reste de l'identite formulaire (badge circulaire au
   rayon de la direction, meme famille que .ssm-field-icon/.ssm-modal-icon). Le <input> reste
   natif (accessibilite clavier/lecteur d'ecran, JS existant inchange) mais est visuellement
   masque ; le rendu vient des elements freres via :checked ~ / :disabled ~. */
body[data-design] .ssm-options-row {
  display: flex; align-items: center; flex-wrap: wrap; gap: 14px 18px;
  background: var(--surface-2); border: 1px solid var(--line-soft); border-radius: var(--radius-card);
  padding: 14px 18px; margin: 4px 0 18px;
}
body[data-design] .ssm-options-label {
  display: flex; align-items: center; gap: 8px; color: var(--ink-2);
  font: 800 11px var(--font-ui); letter-spacing: .08em; text-transform: uppercase; white-space: nowrap;
}
body[data-design] .ssm-options-label i { color: var(--accent); font-size: 13px; }
body[data-design] .ssm-options-group { display: flex; flex-wrap: wrap; gap: 10px; }
body[data-design] .ssm-option-toggle {
  display: flex; align-items: center; gap: 9px; cursor: pointer; user-select: none;
  background: var(--bg); border: 1.5px solid var(--line-soft); border-radius: var(--radius);
  padding: 7px 14px 7px 7px; margin: 0; transition: border-color .15s ease, background .15s ease, transform .1s ease;
}
body[data-design] .ssm-option-toggle:hover { border-color: var(--accent); transform: translateY(-1px); }
body[data-design] .ssm-option-toggle .custom-control-input {
  position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none;
}
body[data-design] .ssm-option-icon {
  display: flex; align-items: center; justify-content: center; width: 26px; height: 26px; flex: none;
  border-radius: var(--radius); background: var(--surface-2); color: var(--ink-2); font-size: 12px;
  transition: background .15s ease, color .15s ease;
}
body[data-design] .ssm-option-text { font: 700 12.5px var(--font-ui); color: var(--ink-2); transition: color .15s ease; }
body[data-design] .ssm-option-toggle:has(.custom-control-input:checked) {
  border-color: var(--accent); background: var(--accent-soft);
}
body[data-design] .ssm-option-toggle:has(.custom-control-input:checked) .ssm-option-icon { background: var(--accent); color: var(--accent-ink); }
body[data-design] .ssm-option-toggle:has(.custom-control-input:checked) .ssm-option-text { color: var(--ink); }
body[data-design] .ssm-option-toggle:has(.custom-control-input:focus) { border-color: var(--accent); }
body[data-design] .ssm-option-toggle:has(.custom-control-input:disabled) { opacity: .55; cursor: not-allowed; }
body[data-design] .ssm-option-toggle:has(.custom-control-input:disabled):hover { transform: none; border-color: var(--line-soft); }

/* ================= Colonnes a imprimer/exporter (modale ssm_export_modal) =================
   Liste generee dynamiquement (JS) a partir des <th> reelles de la table ouverte - checkbox
   native simple (pas le meme habillage que .ssm-option-toggle, ici potentiellement 6-10 items
   donc un rendu compact en grille prime sur le style "pilule"). */
body[data-design] .ssm-export-colonnes-label {
  display: block; font: 700 11px var(--font-ui); letter-spacing: .06em; text-transform: uppercase;
  color: var(--ink-2); margin: 4px 0 8px;
}
body[data-design] .ssm-export-colonnes {
  display: grid; grid-template-columns: repeat(2, 1fr); gap: 6px 14px;
  max-height: 180px; overflow-y: auto; padding-right: 4px;
}
body[data-design] .ssm-export-colonne {
  display: flex; align-items: center; gap: 8px; font: 600 12.5px var(--font-ui); color: var(--ink);
  cursor: pointer; margin: 0;
}
body[data-design] .ssm-export-colonne input { accent-color: var(--accent); width: 15px; height: 15px; flex: none; }

/* ================= Formulaires dans les modales : vrai traitement (100+ vues .modal/*) =================
   Motif d'origine : .form-group.text-center avec fond colore injecte par
   $GLOBALS['style']['bg_label_modal'] (bg-gradient-gray/lightblue/...), label + input
   colles au centre, pastille "Obligatoire" en bg-gradient-danger codee en dur. */
body[data-design] .modal-body { padding: 20px 24px; }
body[data-design] .modal-body .form-group { margin-bottom: 18px; text-align: left !important; }
body[data-design] .modal-body .form-group.bg-gradient-gray, body[data-design] .modal-body .form-group.bg-gradient-lightblue,
body[data-design] .modal-body .form-group.bg-lightblue, body[data-design] .modal-body .form-group.bg-gray,
body[data-design] .modal-body .form-group.bg-gradient-indigo, body[data-design] .modal-body .form-group.bg-indigo,
body[data-design] .modal-body .form-group.bg-gradient-teal, body[data-design] .modal-body .form-group.bg-teal,
body[data-design] .modal-body .form-group.bg-gradient-gray-dark,
body[data-design] .modal-body .row.bg-gradient-gray, body[data-design] .modal-body .row.bg-gradient-lightblue,
body[data-design] .modal-body .row.bg-lightblue, body[data-design] .modal-body .row.bg-gray,
body[data-design] .modal-body .row.bg-gradient-indigo, body[data-design] .modal-body .row.bg-gradient-teal {
  background: var(--surface-2) !important; padding: 12px 4px !important; border: none !important;
  border-radius: var(--radius); margin-left: 0 !important; margin-right: 0 !important;
}
body[data-design] .modal-body .form-group.bg-gradient-gray, body[data-design] .modal-body .form-group.bg-gradient-lightblue,
body[data-design] .modal-body .form-group.bg-lightblue, body[data-design] .modal-body .form-group.bg-gray,
body[data-design] .modal-body .form-group.bg-gradient-indigo, body[data-design] .modal-body .form-group.bg-indigo,
body[data-design] .modal-body .form-group.bg-gradient-teal, body[data-design] .modal-body .form-group.bg-teal,
body[data-design] .modal-body .form-group.bg-gradient-gray-dark {
  background: transparent !important; padding: 0 !important;
}
body[data-design] .modal-body .form-group > label {
  display: inline-flex; align-items: center; gap: 8px; margin-bottom: 7px;
  color: var(--ink-2); font: 700 11px var(--font-ui); text-transform: uppercase; letter-spacing: .04em;
}
/* Icone de champ : meme badge circulaire que les filtres/le sous-menu de module — identite
   coherente sur tout le formulaire, pas juste une icone volante devant le libelle. */
body[data-design] .modal-body .ssm-field-icon {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 22px; height: 22px; border-radius: var(--radius); background: var(--surface-2); color: var(--accent);
  font-size: 10px;
}
body[data-design] .modal-body .select2-error {
  display: inline-flex; align-items: center; gap: 4px; background: var(--bad-bg) !important;
  color: var(--bad) !important; font: 700 9.5px var(--font-ui); text-transform: uppercase; letter-spacing: .03em;
  padding: 2px 8px; border-radius: 999px; margin-left: 6px; vertical-align: middle;
}
body[data-design] .modal-body .form-control.is-invalid, body[data-design] .modal-body select.is-invalid {
  border-color: var(--bad) !important; box-shadow: 0 0 0 3px var(--bad-bg) !important;
}
/* Numero de carte (modale reglage_carte) : identite "carte" plutot qu'un <h3> Bootstrap nu. */
body[data-design] .ssm-carte-numero {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  background: var(--surface-2); border: 1px solid var(--line-soft); border-radius: var(--radius-card);
  padding: 14px; margin: 4px 0 18px; font: 800 20px var(--font-num); letter-spacing: .12em; color: var(--ink);
}
body[data-design] .ssm-carte-numero i { color: var(--accent); font-size: 17px; }

/* ================= Situation client (app/views/vente/portion/Situation.php) =================
   Remplace les <h3> Bootstrap nus + fonds hex en dur (#dc354590 etc.) par les tokens de la
   direction active. */
body[data-design] .ssm-situation-titre {
  margin: 0; font: 700 16px var(--font-display); color: var(--ink); display: flex; align-items: center;
}
body[data-design] .ssm-situation-titre i { color: var(--accent); }
body[data-design] .ssm-situation-detail {
  background: var(--surface-2); border: 1px solid var(--line-soft); border-radius: var(--radius-card);
  padding: 14px;
}
body[data-design] .ssm-situation-detail-titre {
  display: flex; align-items: center; gap: 8px; font: 700 13px var(--font-ui); color: var(--ink);
  text-transform: uppercase; letter-spacing: .03em; margin-bottom: 14px; padding-bottom: 10px;
  border-bottom: 2px solid var(--accent);
}

/* ================= Fiche Etat client (app/views/bons/portion/Header.php) =================
   23/07/2026, retour utilisateur explicite sur l'ordre d'affichage : ligne 1 = nom client + bouton
   modifier a gauche, badge de statut SEUL a l'extremite droite ; ligne 2 = reporter/cloturer/
   supprimer/annuler/imprimer, tous groupes dans .ssm-etat-titre-actions pousse a l'extremite droite
   (margin-left:auto direct sur le groupe, plus simple/robuste qu'un flex:1 sur le titre puisque
   chaque ligne n'a que 1-2 enfants). */
.ssm-etat-titre-actions { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }

/* Informations Bons en liste verticale plutot qu'en ligne de stats horizontales (retour utilisateur
   23/07/2026) : a cote, Informations Remplacements affiche en plus un tableau, donc plus haut -
   Bootstrap etire les deux colonnes .col-md-5/.col-md-7 a la meme hauteur (.row = display:flex),
   et une simple ligne de stats compactes laissait un grand vide sous elle. Une liste de lignes
   cle/valeur occupe naturellement plus de hauteur, pas de vide "gratuit". */
.ssm-etat-liste { display: flex; flex-direction: column; }
body[data-design] .ssm-etat-liste-item {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 10px 2px; border-bottom: 1px solid var(--line-soft);
}
.ssm-etat-liste-item:last-child { border-bottom: none; }
body[data-design] .ssm-etat-liste-label {
  display: flex; align-items: center; gap: 8px; font: 700 12px var(--font-ui); color: var(--ink-2);
}
body[data-design] .ssm-etat-liste-label i { color: var(--accent); font-size: 12px; width: 14px; text-align: center; }
body[data-design] .ssm-etat-liste-value {
  font: 800 16px var(--font-num); color: var(--ink); font-variant-numeric: tabular-nums; white-space: nowrap;
}

/* ================= Etat vide generique (ex. "Aucun bon trouve", modal d'attachement) =================
   23/07/2026, retour utilisateur : un <h3 class="text-warning"> nu "Aucun Bon trouve" ne convient
   plus au design system - meme traitement discret (icone + texte muted, pas d'alerte criarde) que
   partout ailleurs dans l'appli pour une liste/recherche sans resultat. */
body[data-design] .ssm-empty-state {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 10px; padding: 28px 16px; color: var(--ink-2); text-align: center;
}
body[data-design] .ssm-empty-state i { font-size: 26px; color: var(--line-soft); }
body[data-design] .ssm-empty-state p { margin: 0; font: 600 13px var(--font-ui); }

/* ================= Cards factures ouvertes (24/07/2026, Factures.php) =================
   Grille de cards pour les factures OUVERTES (encore des brouillons, montant pas fige) - remplace
   le tableau DataTable pour ce statut, qui n'apporte rien de plus sur des lignes en cours de
   construction. Meme esprit que .ssm-situation-detail (encadre net, sans l'ombre/le poids d'un
   .ssm-kpi) mais cliquable (mene a la facture, meme mecanisme data-ssm-nav que le reste de l'appli). */
.ssm-facture-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 14px; }
body[data-design] .ssm-facture-card {
  display: block; background: var(--surface-2); border: 1px solid var(--line-soft);
  border-radius: var(--radius-card); padding: 14px; color: var(--ink); text-decoration: none;
  transition: border-color .12s, transform .12s;
}
body[data-design] .ssm-facture-card:hover { border-color: var(--accent); transform: translateY(-2px); text-decoration: none; color: var(--ink); }
.ssm-facture-card-reference { display: flex; align-items: center; justify-content: space-between; gap: 8px; font: 700 13.5px var(--font-ui); margin-bottom: 8px; }
.ssm-facture-card-reference .badge { font: 600 10px var(--font-ui); }
.ssm-facture-card-client { display: flex; align-items: center; gap: 6px; font: 600 12.5px var(--font-ui); color: var(--ink-2); margin-bottom: 10px; }
.ssm-facture-card-montant { font: 800 19px var(--font-num); color: var(--accent); margin-bottom: 8px; }
.ssm-facture-card-pied { display: flex; align-items: center; justify-content: space-between; gap: 8px; font: 600 11px var(--font-ui); color: var(--ink-2); border-top: 1px solid var(--line-soft); padding-top: 8px; }

/* ================= En-tete de la page Facture (24/07/2026, portion/Header_facture.php) =================
   Ligne d'infos secondaires (N°/Date/Mode + bouton modifier) sous le titre - simple bande de texte,
   pas un composant lourd, coherent avec .ssm-etat-liste-* deja utilise ailleurs pour ce genre de
   petites valeurs cote a cote. */
body[data-design] .ssm-facture-sous-titre {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  font: 600 12.5px var(--font-ui); color: var(--ink-2); margin: 2px 0 0 34px;
}
.ssm-facture-sous-titre .ssm-btn-icon { width: 24px; height: 24px; }

/* ================= Alertes / toasts ================= */
body[data-design] .alert-success { background: var(--ok-bg); color: var(--ok); border-color: var(--ok); }
body[data-design] .alert-danger { background: var(--bad-bg); color: var(--bad); border-color: var(--bad); }
body[data-design] .alert-warning { background: var(--warn-bg); color: var(--warn); border-color: var(--warn); }
body[data-design] #toast-container > div { border-radius: var(--radius); font-family: var(--font-ui); box-shadow: var(--shadow); }

/* ================= Icones/textes utilitaires (encore emis par du HTML non converti) ================= */
body[data-design] .text-primary { color: var(--accent) !important; }
body[data-design] .text-success { color: var(--ok) !important; }
body[data-design] .text-danger { color: var(--bad) !important; }
body[data-design] .text-warning { color: var(--warn) !important; }
body[data-design] .text-gray, body[data-design] .text-muted, body[data-design] .text-secondary { color: var(--ink-2) !important; }
body[data-design] .text-dark { color: var(--ink) !important; }
body[data-design] .badge-success { background: var(--ok-bg) !important; color: var(--ok) !important; }
body[data-design] .badge-danger { background: var(--bad-bg) !important; color: var(--bad) !important; }
body[data-design] .badge-warning { background: var(--warn-bg) !important; color: var(--warn) !important; }

/* ================= Filtres (remplir_col(), 23 vues + input-group-sm partout) =================
   Meme ADN que le sous-menu de module : badge-icone circulaire (accent au repos ici, contrairement
   au menu, car un filtre n'a pas d'etat "actif" — juste un focus), halo anime au focus-within
   (pas de bordure rouge/bleue brute de navigateur), coins repris de --radius. */
.ssm-filter {
  display: inline-flex; align-items: center; gap: 9px; background: var(--surface);
  border: 1px solid var(--line-soft); border-radius: var(--radius); padding: 5px 14px 5px 5px; height: 44px;
  transition: border-color .15s ease, box-shadow .15s ease;
}
.ssm-filter:focus-within { border-color: var(--accent); box-shadow: 0 0 0 4px var(--accent-soft, var(--surface-2)); }
.ssm-filter-label { display: inline-flex; align-items: center; gap: 8px; font: 700 11px var(--font-ui); color: var(--ink-2); white-space: nowrap; text-transform: uppercase; letter-spacing: .04em; }
.ssm-filter-label i {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 26px; height: 26px; border-radius: var(--radius); background: var(--surface-2); color: var(--accent);
  font-size: 11px;
}
.ssm-filter-input.ssm-input, body[data-design] .ssm-filter input.form-control {
  border: none; background: transparent; height: 40px; width: auto; min-width: 120px;
  color: var(--ink); font-weight: 700; font-family: var(--font-num); padding: 0 4px;
}
.ssm-filter-input:focus { box-shadow: none; outline: none; }

/* ================= Selects natifs (custom-select / select simple) ================= */
body[data-design] select.custom-select, body[data-design] select.form-control, .ssm-select {
  appearance: none; -webkit-appearance: none;
  background: var(--bg) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none' stroke='%23888' stroke-width='2'%3E%3Cpath d='M6 8l4 4 4-4'/%3E%3C/svg%3E") no-repeat right 10px center / 14px;
  border: 1px solid var(--line-soft); color: var(--ink); border-radius: var(--radius);
  padding: 8px 30px 8px 11px; font: 500 13px var(--font-ui);
}
body[data-design] select.custom-select:focus, body[data-design] select.form-control:focus { border-color: var(--accent); outline: none; }

/* ================= Groupes input Bootstrap non convertis =================
   Meme ADN que .ssm-filter (badge-icone circulaire, halo au focus-within, coins --radius) —
   corrige au passage le desalignement signale entre filtres select (input-group) et date
   (ssm-filter) : hauteur et pilule desormais strictement identiques. */
body[data-design] .input-group.input-group-sm {
  display: inline-flex; align-items: center; background: var(--surface);
  border: 1px solid var(--line-soft); border-radius: var(--radius); height: 44px; overflow: visible;
  width: auto; flex-wrap: nowrap; padding: 0 4px 0 5px;
  transition: border-color .15s ease, box-shadow .15s ease;
}
body[data-design] .input-group.input-group-sm:focus-within { border-color: var(--accent); box-shadow: 0 0 0 4px var(--accent-soft, var(--surface-2)); }
body[data-design] .input-group-prepend, body[data-design] .input-group-append { display: flex; flex: none; }
body[data-design] .input-group.input-group-sm .input-group-text {
  background: transparent !important; border: none !important; color: var(--ink-2) !important;
  font: 700 11px var(--font-ui); text-transform: uppercase; letter-spacing: .04em;
  padding: 0 2px 0 4px; height: auto; white-space: nowrap;
  display: inline-flex; align-items: center; gap: 8px;
}
body[data-design] .input-group.input-group-sm .input-group-text i {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 26px; height: 26px; border-radius: var(--radius); background: var(--surface-2); color: var(--accent);
  font-size: 11px; margin: 0 !important;
}
body[data-design] .input-group.input-group-sm > .form-control {
  border: none !important; background: transparent !important; box-shadow: none !important;
  height: 40px; padding: 0 10px 0 4px; font: 600 13px var(--font-ui); color: var(--ink);
  border-radius: 0 !important; min-width: 90px; flex: 1;
}
body[data-design] .input-group.input-group-sm > select {
  border: none !important; box-shadow: none !important; height: 40px; padding: 0 26px 0 4px;
  font: 600 13px var(--font-ui); color: var(--ink); border-radius: 0 !important; flex: 1;
  min-width: 150px; max-width: 260px;
  background: transparent url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none' stroke='%23888' stroke-width='2'%3E%3Cpath d='M6 8l4 4 4-4'/%3E%3C/svg%3E") no-repeat right 6px center / 12px !important;
  text-overflow: ellipsis; white-space: nowrap; overflow: hidden;
}
/* Le chip garde une largeur naturelle mais ne s'ecrase plus dans les colonnes Bootstrap larges */
body[data-design] .input-group.input-group-sm { max-width: 100%; }
/* Repli generique (groupes hors .input-group-sm) : la regle plus specifique ci-dessus
   prend le dessus a l'interieur d'un .input-group-sm grace a la specificite CSS. */
body[data-design] .input-group-text {
  background: var(--surface-2) !important; border: 1px solid var(--line-soft) !important; color: var(--ink-2) !important;
  border-radius: var(--radius) 0 0 var(--radius); font: 700 11.5px var(--font-ui);
}

/* ================= Filtres : vraiment responsive =================
   Les colonnes Bootstrap (col-3/col-4...) qui contiennent un filtre gardent une
   largeur figee en %, donc les filtres s'ecrasaient au lieu de passer a la ligne.
   On rend ces colonnes precises "auto-largeur" : la .row (deja flex-wrap en
   Bootstrap 4) les fait alors refluer naturellement des que la place manque,
   sans toucher au balisage de chaque vue. */
body[data-design] .row > [class*="col-"]:has(> .ssm-filter),
body[data-design] .row > [class*="col-"]:has(> .input-group.input-group-sm),
body[data-design] .row > [class*="col-"]:has(> .select2-container) {
  flex: 0 0 auto; width: auto; max-width: 100%; margin-bottom: 8px;
}
body[data-design] .ssm-filter, body[data-design] .input-group.input-group-sm { flex-wrap: nowrap; }

/* Bouton(s) d'action ("Ajouter" et son dropdown) : toujours colle a l'extreme droite de sa
   ligne — que les filtres tiennent sur une seule ligne ou refluent sur plusieurs, grace a
   margin-left:auto dans le meme conteneur flex-wrap (repere via la classe float-right deja
   presente sur ces boutons dans le balisage existant).
   IMPORTANT : :has(> ...) ou :has(> .dropdown > ...) uniquement (enfant direct / petit-enfant
   via .dropdown) — jamais :has(.float-right) seul, qui remontait par erreur jusqu'a des
   conteneurs bien plus hauts (ex: la carte entiere) des qu'un .float-right existait n'importe
   ou en profondeur a l'interieur, cassant leur largeur (bug constate 20/07/2026). */
body[data-design] .row > [class*="col-"]:has(> .float-right),
body[data-design] .row > [class*="col-"]:has(> .dropdown > .float-right) {
  margin-left: auto; flex: 0 0 auto; width: auto; margin-bottom: 8px;
}

/* ================= Callout (bandeau de couleur AdminLTE -> version tokens) ================= */
body[data-design] .card.callout, body[data-design] .callout {
  border: 1px solid var(--line) !important; border-left: 4px solid var(--accent) !important;
  background: var(--surface) !important; border-radius: var(--radius-card);
}
/* 20/07/2026 : les 4 variantes callout-success/danger/warning/info pointaient chacune vers une
   couleur Bootstrap differente (vert/rouge/jaune/accent) -> deux cartes du meme type d'ecran
   (ex. Clients vs Groupes) rendues avec une bordure de couleur differente sans raison
   fonctionnelle, juste parce que le HTML herite d'une classe Bootstrap differente. Retour
   utilisateur : "on doit avoir le meme style et meme couleur partout". Les 4 variantes
   convergent desormais toutes vers --accent (couleur unique de la direction) ; on garde les
   4 selecteurs (au lieu d'un seul .callout) pour ne pas devoir toucher les ~100 vues qui
   utilisent encore ces classes Bootstrap au cas par cas. */
body[data-design] .card.callout-success, body[data-design] .callout-success,
body[data-design] .card.callout-danger, body[data-design] .callout-danger,
body[data-design] .card.callout-warning, body[data-design] .callout-warning,
body[data-design] .card.callout-info, body[data-design] .callout-info { border-left-color: var(--accent) !important; }
body[data-design] .card-outline.card-success, body[data-design] .card-outline.card-primary,
body[data-design] .card-outline.card-info, body[data-design] .card-outline.card-warning,
body[data-design] .card-outline.card-danger { border-top: 3px solid var(--accent) !important; }
body[data-design] .card-header.border-success, body[data-design] .card-header.border-primary,
body[data-design] .card-header.border-info { border-bottom: 1px solid var(--line) !important; }
body[data-design] hr.bg-success, body[data-design] hr.bg-primary, body[data-design] hr.bg-info { background: var(--line) !important; opacity: 1; height: 1px; border: none; }

/* ================= small-box / info-box (KPI AdminLTE -> version tokens) ================= */
body[data-design] .small-box {
  background: var(--surface) !important; color: var(--ink) !important; border: 1px solid var(--line);
  border-radius: var(--radius-card); box-shadow: var(--shadow);
}
body[data-design] .small-box .inner h3, body[data-design] .small-box .inner p { color: var(--ink) !important; }
body[data-design] .small-box .icon { color: var(--line-soft) !important; }
body[data-design] .small-box > .small-box-footer { background: var(--surface-2) !important; color: var(--ink-2) !important; border-top: 1px solid var(--line); }
body[data-design] .info-box {
  background: var(--surface) !important; border: 1px solid var(--line); border-radius: var(--radius-card);
  box-shadow: var(--shadow);
}
body[data-design] .info-box .info-box-icon { background: var(--accent-soft, var(--surface-2)) !important; color: var(--accent) !important; border-radius: var(--radius) 0 0 var(--radius); }
body[data-design] .info-box .info-box-text { color: var(--ink-2) !important; }
body[data-design] .info-box .info-box-number { color: var(--ink) !important; font-family: var(--font-num); }
/* Les couleurs contextuelles bg-success/bg-info/... sur small-box/info-box (fond plein) sont
   neutralisees au profit de l'accent unique de la direction — coherence visuelle par style. */
body[data-design] .small-box.bg-success, body[data-design] .small-box.bg-info,
body[data-design] .small-box.bg-warning, body[data-design] .small-box.bg-danger,
body[data-design] .small-box.bg-primary, body[data-design] .small-box.bg-gradient-success,
body[data-design] .small-box.bg-gradient-info, body[data-design] .small-box.bg-gradient-warning,
body[data-design] .small-box.bg-gradient-danger, body[data-design] .small-box.bg-gradient-primary {
  background: var(--surface) !important; color: var(--ink) !important;
}

/* ================= En-tetes de tableau : plus de bg-success/bg-gradient-* code en dur ================= */
body[data-design] table thead.bg-success, body[data-design] table thead.bg-info,
body[data-design] table thead.bg-primary, body[data-design] table thead.bg-warning,
body[data-design] table thead.bg-danger, body[data-design] table thead.bg-gradient-success,
body[data-design] table thead.bg-gradient-gray, body[data-design] table thead.bg-gradient-lightblue,
body[data-design] table td.bg-gradient-success, body[data-design] table td.bg-success {
  background: var(--surface-2) !important; color: var(--ink-2) !important;
}
body[data-design] table thead th { border-bottom: 1px solid var(--line) !important; }

/* ================= Boutons non convertis (classes Bootstrap/AdminLTE brutes, repli generique) ================= */
body[data-design] .btn:not(.ssm-btn) { border-radius: var(--radius); font-family: var(--font-ui); font-weight: 700; }
body[data-design] .btn.bg-gradient-success:not(.ssm-btn), body[data-design] .btn.bg-success:not(.ssm-btn),
body[data-design] .btn-success:not(.ssm-btn) { background: var(--ok) !important; border-color: var(--ok) !important; color: #fff !important; }
body[data-design] .btn.bg-gradient-danger:not(.ssm-btn), body[data-design] .btn.bg-danger:not(.ssm-btn),
body[data-design] .btn-danger:not(.ssm-btn) { background: var(--bad) !important; border-color: var(--bad) !important; color: #fff !important; }
body[data-design] .btn.bg-gradient-primary:not(.ssm-btn), body[data-design] .btn.bg-primary:not(.ssm-btn),
body[data-design] .btn-primary:not(.ssm-btn) { background: var(--accent) !important; border-color: var(--accent) !important; color: var(--accent-ink) !important; }
body[data-design] .btn.bg-gradient-warning:not(.ssm-btn), body[data-design] .btn.bg-warning:not(.ssm-btn),
body[data-design] .btn-warning:not(.ssm-btn) { background: var(--warn) !important; border-color: var(--warn) !important; color: #fff !important; }
body[data-design] .btn.bg-gradient-gray:not(.ssm-btn), body[data-design] .btn-outline-info:not(.ssm-btn),
body[data-design] .btn-outline-primary:not(.ssm-btn), body[data-design] .btn-outline-success:not(.ssm-btn),
body[data-design] .btn-outline-warning:not(.ssm-btn) { border-color: var(--accent) !important; color: var(--accent) !important; background: transparent !important; }
body[data-design] h3.text-gray { color: var(--ink) !important; }

/* ================= Dropdowns non convertis (repli generique) ================= */
body[data-design] .dropdown-menu:not(.ssm-menu) {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow); font: 500 13px var(--font-ui);
}
body[data-design] .dropdown-item:not(.ssm-menu-item) { color: var(--ink); }
body[data-design] .dropdown-item:not(.ssm-menu-item):hover { background: var(--surface-2); color: var(--accent); }
body[data-design] .btn.dropdown-toggle:not(.ssm-btn) {
  background: var(--surface); border: 1px solid var(--line); color: var(--ink); border-radius: var(--radius);
}
body[data-design] .btn.dropdown-toggle.btn-primary:not(.ssm-btn) { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }

/* ================= Sous-menu de module (ex: Clients/Cartes/Encaissements/Grand Livre) =================
   V2 (20/07/2026) : abandon du segmented-control plein-largeur (trop generique, "bouton de
   telecommande"). Chips compactes alignees a gauche, badge-icone circulaire.
   V3 (21/07/2026) : indicateur "thumb" unique qui glisse (translateX+width) au lieu d'un
   soulignement statique par onglet.
   V4 (21/07/2026) : sur retour utilisateur ("le menu avec background color complet et ombre,
   mieux"), reprise du principe segmented-control du brief original — piste avec fond/bordure
   propres (var(--surface-2), pas de couleur figee pour rester coherent avec les 4 directions +
   mode sombre), thumb plein (pas juste un trait) avec rayon et ombre teintee accent, texte qui
   passe au clair au-dessus du thumb rempli. Le JS (ssm_module_nav_positionner_thumb) n'a pas
   change, seule la geometrie visuelle differe. A garder seulement si valide a l'usage - sinon
   revenir a la V3 (thumb-trait sous les onglets). Modele : app/views/vente/portion/menu_client.php. */
:root, body[data-design] { --ssm-nav-duree: .6s; --ssm-nav-easing: cubic-bezier(.34, 1.4, .5, 1); }
.ssm-module-nav {
  display: inline-flex; flex-wrap: wrap; align-items: center; gap: 2px;
  background: var(--surface-2); border: 1px solid var(--line-soft); border-radius: var(--radius-card);
  margin-bottom: 22px; padding: 6px; position: relative; box-shadow: var(--shadow);
}
/* Thumb plein (pas un simple trait) qui glisse derriere l'onglet actif, a l'interieur de la
   piste (top/bottom cales sur le padding de .ssm-module-nav). */
.ssm-module-nav-thumb {
  /* Fix (22/07/2026, retour utilisateur "ca depasse l'element") : "left" etait a 6px ici EN PLUS
     du translateX() calcule en JS (ssm_module_nav_positionner_thumb(), ajax.js) a partir de
     $actif.position().left - qui renvoie DEJA la position complete de l'onglet relative a
     .ssm-module-nav (son offsetParent), padding inclus. Les deux s'additionnaient : le thumb
     finissait systematiquement decale de 6px vers la droite par rapport a l'onglet qu'il est
     cense recouvrir exactement. Peu visible sur "Plein" (le remplissage plein a de la marge
     interne), tres visible sur "Ligne"/"Contour" (trait/bordure precis, cense coller aux bords
     exacts de l'onglet) - constate sur Cartes/Grand Livre. "top"/"bottom" ne sont PAS concernes
     (jamais touches par le JS, qui ne calcule que translateX/width) - inchanges. */
  position: absolute; top: 6px; bottom: 6px; left: 0; width: 0; z-index: 0;
  background: var(--accent); border-radius: var(--radius); pointer-events: none;
  box-shadow: 0 2px 8px var(--accent-soft, rgba(0, 0, 0, .18));
  transition: transform var(--ssm-nav-duree) var(--ssm-nav-easing), width var(--ssm-nav-duree) var(--ssm-nav-easing);
}
body[data-design] .ssm-module-nav-item {
  display: flex; align-items: center; gap: 10px; border: none; background: transparent;
  color: var(--ink-2); cursor: pointer; padding: 9px 16px; text-decoration: none;
  font: 700 11.5px var(--font-ui); text-transform: uppercase; letter-spacing: .05em;
  border-radius: var(--radius); position: relative; z-index: 1;
  transition: color .3s ease;
}
body[data-design] .ssm-module-nav-item:hover { color: var(--ink); text-decoration: none; }
.ssm-module-nav-badge {
  width: 24px; height: 24px; border-radius: calc(var(--radius) - 2px); flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent; color: var(--ink-2); font-size: 11px;
  transition: background .18s ease, color .18s ease;
}
.ssm-module-nav-item:hover .ssm-module-nav-badge { color: var(--ink); }
body[data-design] .ssm-module-nav-item--active { color: var(--accent-ink); }
.ssm-module-nav-item--active .ssm-module-nav-badge { color: var(--accent-ink); }
@media (prefers-reduced-motion: reduce) {
  .ssm-module-nav-item, .ssm-module-nav-badge, .ssm-module-nav-thumb { transition: none; }
}

/* ---- Variantes de style + alignement du sous-menu (Phase 4, 22/07/2026, migration 014) ----
   Retour utilisateur : proposer un style alternatif "juste des lignes en bas + icone colore
   comme avant" (V3 historique, remplacee par le thumb plein V4 ci-dessus) + une 3e proposition,
   et un choix d'alignement (gauche/centre/droite). Reglable globalement (footer.php) ou par
   module (ssm_module_theme_menu_html(), vendor/function.php) - voir menu_client.php. Le MEME
   .ssm-module-nav-thumb (positionne en JS, ajax.js::ssm_module_nav_positionner_thumb) est reutilise
   tel quel pour les 3 styles - seule sa geometrie CSS change (plein/ligne/contour) - afin que les
   3 partagent exactement le meme mouvement glissant entre onglets (retour utilisateur : "contour
   ne fait pas le meme mouvement que plein et ligne"). Le texte/icone des onglets eux-memes
   (police, taille, padding) reste aussi IDENTIQUE entre les 3 styles - seule la piste/le thumb
   change d'apparence, jamais la boite de l'onglet - pour la meme raison ("il ne reste police,
   taille de texte"). */
.ssm-module-nav-align { display: flex; flex: 1 1 auto; min-width: 0; }
.ssm-module-nav-align[data-align="centre"] { justify-content: center; }
.ssm-module-nav-align[data-align="droite"] { justify-content: flex-end; }
.ssm-module-nav-align .ssm-module-nav { max-width: 100%; }

/* "Ligne" : piste transparente, trait fin glissant sous l'onglet actif + icone/texte colores
   (pas de pastille de fond) - reprend l'esprit de l'ancienne V3. */
.ssm-module-nav--ligne {
  background: transparent; border: none; box-shadow: none; border-radius: 0; padding: 0 0 8px;
  border-bottom: 1px solid var(--line-soft);
}
.ssm-module-nav--ligne .ssm-module-nav-thumb {
  top: auto; bottom: -1px; height: 3px; border-radius: 2px 2px 0 0; box-shadow: none;
}
body[data-design] .ssm-module-nav--ligne .ssm-module-nav-item--active { color: var(--accent) !important; }
.ssm-module-nav--ligne .ssm-module-nav-badge { background: transparent; }
.ssm-module-nav--ligne .ssm-module-nav-item--active .ssm-module-nav-badge { color: var(--accent); }

/* "Contour" (3e proposition) : pas de surface pleine - un cadre colore glisse d'onglet en onglet
   (le MEME .ssm-module-nav-thumb que "plein"/"ligne", juste transforme en simple contour
   transparent au lieu d'un pave plein) plutot qu'une bordure statique posee sur chaque onglet -
   c'est ce qui lui redonne le meme mouvement glissant que les 2 autres styles. Consequence
   directe : les onglets eux-memes n'ont plus besoin d'aucune bordure/padding particuliers, donc
   gardent exactement la meme boite (police, taille, padding) que "plein"/"ligne". */
.ssm-module-nav--contour {
  background: transparent; border: none; box-shadow: none; padding: 0; gap: 4px;
}
.ssm-module-nav--contour .ssm-module-nav-thumb {
  background: transparent; border: 1.5px solid var(--accent); box-shadow: none;
}
body[data-design] .ssm-module-nav--contour .ssm-module-nav-item--active { color: var(--accent) !important; background: transparent; }
.ssm-module-nav--contour .ssm-module-nav-item--active .ssm-module-nav-badge { color: var(--accent); }

/* ---- Rangee sous-menu de module + bouton theme (21/07/2026) ----
   Enveloppe .ssm-module-nav (largeur au contenu) et le bouton theme, pour que ce dernier soit
   pousse a l'extreme droite quelle que soit la largeur du sous-menu - voir menu_client.php. */
.ssm-module-nav-bar { display: flex; align-items: center; justify-content: space-between; gap: 14px; margin-bottom: 22px; flex-wrap: wrap; }
.ssm-module-nav-bar .ssm-module-nav { margin-bottom: 0; }
/* Separateur visuel ENTRE des onglets d'un meme .ssm-module-nav (24/07/2026, ex. Achat : Bon de
   Commande/Bon de Livraison/Comparaison groupes, separes de Depense) - simple trait, ne porte pas
   la classe .ssm-module-nav-item donc ignore par le positionnement du thumb/la navigation clavier
   (ssm_module_nav_positionner_thumb, ssm_module_nav_direction_par_url dans ajax.js, qui ciblent
   explicitement .ssm-module-nav-item). z-index aligne sur les onglets pour rester visible
   au-dessus du thumb glissant (qui a z-index:0). */
.ssm-module-nav-sep { width: 1px; align-self: stretch; margin: 6px 4px; background: var(--line-soft); position: relative; z-index: 1; }
.ssm-module-theme-btn { font-size: 12px; }
.ssm-module-theme .ssm-menu { min-width: 220px; }
.ssm-module-theme .ssm-swatch-btn { width: 100%; }

/* ---- Transition de contenu apres une navigation AJAX (meme duree/courbe "spring" que le thumb,
   cf. --ssm-nav-duree ci-dessus) ----
   Le nouveau contenu (#ssm_module_content) entre depuis le cote OPPOSE a celui vers lequel le
   thumb se deplace, pendant que l'ancien contenu (capture avant remplacement, cf.
   ssm_module_nav_transition() dans ajax.js) est superpose en position absolute et glisse dans le
   MEME sens que le thumb avant d'etre retire du DOM - demande explicite : "je veux que l'ancien
   card se deplace aussi... meme duree de deplacement". Repli neutre (fondu + leger glissement
   vertical, pas d'ancien contenu anime) si la direction ne peut pas etre determinee. */
@keyframes ssm-content-in {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: translateY(0); }
}
@keyframes ssm-content-in-droite {
  from { opacity: 0; transform: translateX(-26px); }
  to { opacity: 1; transform: translateX(0); }
}
@keyframes ssm-content-in-gauche {
  from { opacity: 0; transform: translateX(26px); }
  to { opacity: 1; transform: translateX(0); }
}
#ssm_module_content.ssm-content-in { animation: ssm-content-in var(--ssm-nav-duree) var(--ssm-nav-easing) both; }
#ssm_module_content.ssm-content-in-droite { animation: ssm-content-in-droite var(--ssm-nav-duree) var(--ssm-nav-easing) both; }
#ssm_module_content.ssm-content-in-gauche { animation: ssm-content-in-gauche var(--ssm-nav-duree) var(--ssm-nav-easing) both; }
/* Fix (24/07/2026, retour utilisateur : "en changeant d'onglet, la derniere ligne du tableau se
   retrouve en face de l'entete pendant 1s, puis redevient normal") : un `transform` sur un ANCETRE
   devient le "containing block" de tout descendant `position:sticky` (meme categorie de piege deja
   documentee plus haut pour `position:fixed` dans les modales) - le temps que la classe d'entree
   ci-dessus reste posee (transform actif via l'animation), le `<thead>` sticky (`table.ssm-table
   thead th { position:sticky }`, plus haut) se recalcule par rapport a CE conteneur transforme au
   lieu du scroll-port normal, d'ou le "saut" visuel juste pendant la transition. Les tableaux n'ont
   de toute facon pas besoin de coller pendant les ~350-600ms d'une transition de page - on neutralise
   simplement le sticky tant que la classe d'animation est posee. */
#ssm_module_content.ssm-content-in thead th,
#ssm_module_content.ssm-content-in-droite thead th,
#ssm_module_content.ssm-content-in-gauche thead th { position: static !important; }
/* Ancien contenu qui glisse hors champ (memes proportions/dimensions que le nouveau puisqu'il
   couvre exactement #ssm_module_content, position:relative cf. JS). z-index au-dessus du nouveau
   contenu pour bien voir l'un glisser par-dessus l'autre pendant la transition. */
.ssm-content-sortie {
  position: absolute; top: 0; left: 0; right: 0; z-index: 3; pointer-events: none;
  transition: transform var(--ssm-nav-duree) var(--ssm-nav-easing), opacity var(--ssm-nav-duree) var(--ssm-nav-easing);
}
.ssm-content-sortie-droite { transform: translateX(26px); opacity: 0; }
.ssm-content-sortie-gauche { transform: translateX(-26px); opacity: 0; }
/* La copie sortante recoit elle aussi un transform (ci-dessus) le temps de glisser hors champ -
   meme piege sticky que ci-dessus pour son propre <thead> (elle est de toute facon vouee a
   disparaitre, jamais besoin d'y coller). */
.ssm-content-sortie thead th { position: static !important; }
@media (prefers-reduced-motion: reduce) {
  #ssm_module_content.ssm-content-in, #ssm_module_content.ssm-content-in-droite, #ssm_module_content.ssm-content-in-gauche { animation: none; }
  .ssm-content-sortie { transition: none; display: none; }
}

/* ================= Onglets (nav-tabs Bootstrap, ex: Clients/Groupes) =================
   Bootstrap/AdminLTE posent leur propre fond + bordure grise au survol (#e9ecef, coins d'origine)
   qu'on n'ecrasait pas -> couleur incoherente et "carre" sans le bon rayon, signale. Le fond
   translucide (--accent-soft) au survol a ete abandonne (retour utilisateur : "j'ai pas aime
   le principe d'opacity") au profit du meme langage que le sous-menu de module : couleur
   d'accent + trait anime sous l'onglet, jamais de fond. On fixe aussi ici le bug "texte blanc
   sur fond blanc" de l'onglet actif : le blanc venait du fait que rien ne fixait explicitement
   la couleur du texte actif avec une specificite/priorite superieure a un eventuel style herite
   (AdminLTE/Bootstrap definissent .nav-tabs .nav-link.active en blanc sur fond colore dans
   certains contextes) ; on fixe desormais color en !important sur les 4 etats (defaut, hover,
   actif, actif+hover) pour ne plus jamais dependre d'un fond pour rester lisible. */
body[data-design] .nav-tabs { border-bottom: 1px solid var(--line); }
body[data-design] .nav-tabs .nav-link {
  border: none !important; color: var(--ink-2) !important; font: 700 12.5px var(--font-ui); padding: 12px 18px 10px;
  border-radius: 0 !important; border-bottom: 2px solid transparent !important;
  background: transparent !important; transition: color .15s ease, border-color .15s ease;
}
body[data-design] .nav-tabs .nav-link:hover {
  color: var(--accent) !important; border-bottom-color: var(--line) !important;
}
body[data-design] .nav-tabs .nav-link.active,
body[data-design] .nav-tabs .nav-link.active:hover {
  background: transparent !important; color: var(--accent) !important; font-weight: 800;
  border-bottom-color: var(--accent) !important;
}

/* ================= Totaux / pieds de tableau ================= */
body[data-design] table tfoot th, body[data-design] table tfoot td { border-top: 2px solid var(--line) !important; background: transparent !important; }
body[data-design] .h5.text-primary, body[data-design] table .text-primary.text-left { color: var(--accent) !important; font-family: var(--font-num); }

/* ================= 2 panels cote a cote, meme hauteur quel que soit le contenu =================
   24/07/2026 (retour utilisateur, vente/Reglement.php Factures/Paiements) : .row de Bootstrap 4 est
   deja display:flex/align-items:stretch par defaut - les 2 .col-6 s'etirent donc DEJA a la hauteur
   du plus grand des deux (+ .h-100 sur la carte interne, redondant mais explicite). Ce qui manquait
   reellement pour que ce soit VISIBLE (pas juste vrai en interne) : un cadre (bordure de carte) sur
   chaque colonne pour materialiser la boite, et un ecart plus marque que le gouttiere Bootstrap
   standard (15px de chaque cote, peu visible sans cadre). */
.ssm-parallele-col:first-child { padding-right: 22px; }
.ssm-parallele-col:last-child { padding-left: 22px; }
/* Les 2 boites ont deja la meme hauteur (ci-dessus), mais si l'une contient moins de lignes que
   l'autre, son bloc Total Page/Filtre remontait juste apres son tableau, plus court - au lieu de
   rester en face de celui de l'autre boite (capture d'ecran utilisateur, vente/Reglement.php
   Factures/Paiements). Fix : boite en colonne flex, totaux en dernier enfant avec margin-top:auto
   (absorbe tout l'espace restant au-dessus) - les 2 blocs de totaux restent alignes sur la meme
   ligne quel que soit le nombre de lignes de chaque tableau. */
#reglement_factures_panel, #reglement_paiements_panel { display: flex; flex-direction: column; }
#reglement_factures_panel .ssm-stat-row--fin, #reglement_paiements_panel .ssm-stat-row--fin { margin-top: auto; }

/* ================= Colonne "Pieces" groupee par remise (Envois banque, 25/07/2026) =================
   Chaque envoi peut contenir plusieurs remises + des pieces pas encore remises - regroupees comme
   un <optgroup> (titre de groupe puis pieces en retrait), voir EnvoiBanque::pieces_groupees(). */
.ssm-pieces-groupe { margin-bottom: 6px; }
.ssm-pieces-groupe:last-child { margin-bottom: 0; }
.ssm-pieces-groupe strong { font-size: 11.5px; text-transform: uppercase; letter-spacing: .03em; color: var(--ink-2, #6c757d); }
.ssm-pieces-ligne { padding-left: 14px; white-space: nowrap; }

/* ================= .ssm-wizard-* : assistant de configuration initiale (HomeController::
   ================= initialisation(), 27/07/2026) - ecran plein-page joue automatiquement tant
   ================= qu'aucun utilisateur n'existe en base (voir Controller::auth()), avant toute
   ================= connexion. Concu pour accueillir plusieurs etapes a venir (badge "Étape N"). */
.ssm-wizard-page { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 40px 16px; background: var(--bg); }
.ssm-wizard-card { width: 100%; max-width: 480px; background: var(--surface); border: 1px solid var(--line-soft); border-radius: var(--radius-card); box-shadow: var(--shadow); padding: 32px 34px; }
.ssm-wizard-logo { display: flex; justify-content: center; margin-bottom: 18px; }
.ssm-wizard-logo img { height: 56px; }
.ssm-wizard-title { text-align: center; font: 700 21px var(--font-display); color: var(--ink); margin: 10px 0 4px; }
.ssm-wizard-subtitle { text-align: center; font: 500 13px var(--font-ui); color: var(--ink-2); margin: 0 0 22px; }
.ssm-wizard-step-badge { display: inline-flex; align-items: center; gap: 6px; background: var(--accent-soft, var(--surface-2)); color: var(--accent); font: 700 11px var(--font-ui); letter-spacing: .04em; text-transform: uppercase; padding: 5px 12px; border-radius: 999px; }
.ssm-wizard-error { display: none; background: var(--bad-bg); color: var(--bad); border: 1px solid var(--bad); border-radius: var(--radius); padding: 10px 14px; font: 600 13px var(--font-ui); margin-bottom: 16px; }

/* ================= Note de test (29/07/2026, retour utilisateur) : zone de texte large pour que
   la description soit confortable a ecrire ET a relire ensuite (redimensionnable verticalement,
   jamais horizontalement pour ne pas casser la mise en page de la modale). */
body[data-design] .ssm-note-textarea { min-height: 150px; resize: vertical; }
/* Colonne Description de la DataTable d'administration : conserve les retours a la ligne
   (nl2br() cote serveur) et une largeur raisonnable plutot que de laisser le texte etirer toute
   la colonne sur une seule ligne interminable. */
body[data-design] #notes_test td:nth-child(4) { max-width: 340px; white-space: normal; word-break: break-word; }
