:root {
  --radius-lg: 20px;
  --radius-md: 14px;
  --radius-sm: 10px;
  --nav-height: 68px;
  --topbar-height: 56px;
  --sidebar-width: 248px;
  --license-columns: 1.7fr 0.9fr 1.6fr 1.3fr 0.8fr 1.4fr;
}


/* ==========================================================================
   Palette unique (fond noir-teal éditorial + accent terracotta/ambre, cf.
   identité visuelle Arbisa Informatique déjà en place côté Salbatu/Mytools
   Admin - mêmes teintes de marque, désormais partagées par le hub web) -
   plus de sélecteur de thème : une seule apparence dans toute l'app, y
   compris les modules qui avaient jusque-là leur propre palette figée en
   clair (diagnostics/parc/clients, cf. leurs portal.css).

   Les couleurs des onglets colorés/biseautés de la topbar (--app-tab-1,
   --palette-*, cf. plus bas) sont volontairement EXCLUES de cette refonte -
   identité propre à chaque module, à conserver telle quelle.
   ========================================================================== */
:root {
  --bg: #14251f;
  --surface: #1a2f28;
  --surface-raised: #20372f;
  --border: #33504a;
  --text: #f3efe6;
  --text-muted: #8fa39c;
  --topbar-bg: rgba(8, 12, 11, 0.94);
  --nav-bg: rgba(8, 12, 11, 0.94);
  --accent-1: #c87549;
  --accent-2: #e0a83c;
  --accent-gradient: linear-gradient(135deg, var(--accent-1), var(--accent-2));
  --success: #96d642;
  --success-bg: rgba(150, 214, 66, 0.14);
  --warning: #e0a83c;
  --warning-bg: rgba(224, 168, 60, 0.14);
  --danger: #c0392b;
  --danger-bg: rgba(192, 57, 43, 0.16);
  --shadow-soft: 0 8px 24px rgba(0, 0, 0, 0.4);
  --font-display: Georgia, "Iowan Old Style", "Palatino Linotype", "Book Antiqua", Palatino, serif;

  --tile-blue: linear-gradient(135deg, #3b82f6, #2563eb);
  --tile-green: linear-gradient(135deg, #22c55e, #15803d);
  --tile-orange: linear-gradient(135deg, #f59e0b, #ea580c);
  --tile-purple: linear-gradient(135deg, #a855f7, #7c3aed);
  --tile-red: linear-gradient(135deg, #f43f5e, #e11d48);
  --tile-ink: #ffffff;

  /* Couleur de repli d'un onglet topbar sans --tab-color défini (cf.
     .app-tab-shape plus bas) - les couleurs par défaut de chaque module
     viennent en réalité de --palette-* via les règles [data-module-id]
     ci-dessous ; ceci ne sert que de dernier filet. */
  --app-tab-1: #3b82f6;

  /* Palette des 10 teintes disponibles pour recolorer un onglet de la
     topbar (menu contextuel, clic droit - cf. static/js/app.js::initTopbarRecolor). */
  --palette-bleu: #3b82f6;
  --palette-jaune: #eab308;
  --palette-vert: #22c55e;
  --palette-rouge: #ef4444;
  --palette-violet: #8b5cf6;
  --palette-orange: #f97316;
  --palette-cyan: #06b6d4;
  --palette-anthracite: #3f4652;
  --palette-gris-brosse: #8a93a1;
  --palette-magenta: #d946ef;
}

* {
  box-sizing: border-box;
}

html, body {
  margin: 0;
  padding: 0;
}

/* Fond plat, sans texture (cf. identite visuelle de reference : rapport
   editorial noir-teal, entierement uni) - l'ancienne image decorative
   (static/images/fond.png, motif de circuits) est retiree du rendu : sa
   texture chargee entrait en contradiction directe avec l'ame minimaliste
   demandee. Fichier image conserve sur disque (non supprime) au cas ou. */
body {
  background-color: var(--bg);
  color: var(--text);
  font-family: "Segoe UI", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  padding-top: var(--topbar-height);
  min-height: 100vh;
  transition: background-color 0.2s ease, color 0.2s ease;
}

/* .bottom-nav n'existe plus dans le DOM sur les pages sans options propres
   (ex. l'accueil) : ne réserver l'espace en bas (mobile) / à gauche
   (desktop, cf. media query plus bas) que si elle est réellement présente. */
body:has(.bottom-nav) {
  padding-bottom: calc(var(--nav-height) + 16px);
}

a {
  color: inherit;
  text-decoration: none;
}

/* Topbar */
.topbar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: var(--topbar-height);
  background: var(--topbar-bg);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border);
  z-index: 20;
  display: flex;
  align-items: center;
}

.topbar-inner {
  width: 100%;
  padding: 0 20px;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.topbar-action {
  font-size: 18px;
  line-height: 1;
  padding: 6px;
  border-radius: 8px;
  -webkit-tap-highlight-color: transparent;
  transition: background-color 0.15s ease, transform 0.12s ease;
}

.topbar-action:hover {
  background: var(--surface-raised);
}

.topbar-action.active {
  background: var(--surface-raised);
}

.topbar-action:active {
  background: var(--surface-raised);
  transform: scale(0.92);
}

.topbar-action {
  border: none;
  background: transparent;
  color: var(--text);
  cursor: pointer;
}

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

.topbar-global-search {
  position: relative;
  min-width: 0;
  flex-shrink: 1;
}

.topbar-global-search-input {
  width: 220px;
  max-width: 40vw;
  padding: 8px 12px;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  background: var(--surface-raised);
  color: var(--text);
  font-size: 13px;
  font-family: inherit;
}

.topbar-global-search-input:focus {
  outline: none;
  border-color: var(--accent-1);
}

.topbar-global-search-results {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  width: 320px;
  max-width: 80vw;
  max-height: 60vh;
  overflow-y: auto;
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-soft);
  z-index: 60;
}

.topbar-global-search-results[hidden] {
  display: none;
}

.topbar-global-search-empty {
  padding: 14px 16px;
  font-size: 13px;
  color: var(--text-muted);
}

.topbar-global-search-section + .topbar-global-search-section {
  border-top: 1px solid var(--border);
}

.tgs-section-label {
  padding: 10px 16px 4px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.topbar-global-search-item {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 8px 16px;
  text-decoration: none;
  color: var(--text);
}

.topbar-global-search-item:hover,
.topbar-global-search-item.is-active {
  background: var(--surface);
}

/* Element survole au clavier (fleches haut/bas, cf. static/js/
   global_search.js) - un simple fond ne suffit pas a etre reperable sans
   la souris, l'anneau de focus habituel (--accent-1) le rend net meme pour
   un balayage rapide. */
.topbar-global-search-item.is-active {
  outline: 2px solid var(--accent-1);
  outline-offset: -2px;
}

.tgs-item-title {
  font-size: 14px;
  font-weight: 600;
}

.tgs-item-subtitle {
  font-size: 12px;
  color: var(--text-muted);
}

/* Mobile : le champ de recherche global vit dans .topbar-left avant
   .app-switcher/.brand sur des ecrans etroits, et cette derniere serait
   sinon comprimee a l'illisible - masque en dessous du seuil desktop, comme
   les autres elements exclusifs desktop de la topbar (cf. media query plus
   bas). */
.topbar-global-search {
  display: none;
}

.topbar-right {
  display: flex;
  align-items: center;
  gap: 4px;
}

/* Icône Accueil : deux instances dans le DOM (gauche desktop / droite
   mobile, cf. base.html) plutôt qu'une seule repositionnée, chacune n'étant
   affichée que sur son format cible - cf. media query desktop plus bas. */
.topbar-home-mobile {
  display: inline-flex;
  align-items: center;
}

.topbar-home-desktop {
  display: none;
}

/* Raccourci "Ajout client" mobile, entre le titre et l'icône Accueil - cf.
   base.html. Masqué sur desktop (media query plus bas), qui a son propre
   bouton sur la page d'accueil (.home-quick-add-btn). */
.topbar-quick-add-mobile {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: linear-gradient(135deg, #34d399, #10b981);
  color: #063a26;
  font-size: 16px;
  text-decoration: none;
  flex-shrink: 0;
}

/* Desktop uniquement (cf. media query plus bas) : sur mobile, Paramètres/
   Verrouiller vivent tous dans le menu ☰ (.app-switcher-dropdown). */
.topbar-settings-link,
.topbar-lock-form {
  display: none;
}

.app-switcher {
  position: relative;
}

.app-switcher-dropdown {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  min-width: 200px;
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-soft);
  overflow: hidden;
  z-index: 30;
}

.app-switcher-dropdown[hidden] {
  display: none;
}

.app-switcher-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 13px 16px;
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
  border: none;
  background: transparent;
  text-align: left;
  cursor: pointer;
  font-family: inherit;
}

.app-switcher-item:active {
  background: var(--surface);
}

.app-switcher-item.active {
  color: var(--accent-1);
}

.app-switcher-divider {
  height: 1px;
  background: var(--border);
  margin: 6px 0;
}

/* Onglets d'applications (desktop uniquement, cf. media query plus bas) :
   masqués par défaut, .app-switcher (menu déroulant mobile) prend leur place.

   Rail metallique anthracite MAT (pas de reflet sur le rail lui-meme, juste
   un grain tres discret), fin et etroit - une "fente" bordee de deux traits
   de 2-3px (plus sombre en haut, plus clair en bas, pour l'effet de rainure
   creusee) - qui abrite des boutons trapezoidaux INDEPENDANTS (espaces
   regulierement de 2-3px, le fond anthracite du rail restant visible entre
   eux - PAS de chevauchement, contrairement a une version precedente).

   Chaque bouton reste scinde en 3 elements imbriques - piege CSS connu :
   clip-path rogne un box-shadow porte par le MEME element, donc toute ombre
   portee doit vivre sur un conteneur NON decoupe :
     .app-tab-wrap  (non decoupe)   -> drag&drop, ombre legere
     .app-tab       (lien, non decoupe, plein cadre)
     .app-tab-shape (decoupe)       -> clip-path + fond + relief (bandes de
                                        biseau ~20% de la hauteur en haut et
                                        en bas) + reflet verre/brosse. */
.app-tabs {
  display: none;
  position: relative;
  height: 40px;
  align-items: stretch;
  gap: 3px;
  padding: 2px 4px;
  background: #14171a;
  border-top: 2px solid #05060a;
  border-bottom: 2px solid #363c47;
}

/* Grain tres discret du rail (mat, pas de brillance) - independant du reflet
   des boutons. */
.app-tabs::before {
  content: "";
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(
    100deg,
    rgba(255, 255, 255, 0.025) 0px,
    rgba(255, 255, 255, 0.025) 1px,
    transparent 1px,
    transparent 3px
  );
  pointer-events: none;
}

/* Embouts du rail : caisson gris neutre sans texte a gauche, caisson sombre
   avec pastille scintillante a droite (plus etroit en bas qu'en haut, pour
   epouser la fermeture du rail) - chacun environ 1/3 de la largeur d'un
   bouton standard ("Drive" ~ 95px de large -> ~32px). */
.app-tabs-cap {
  flex: none;
  align-self: stretch;
  display: flex;
  align-items: center;
  justify-content: center;
}

.app-tabs-cap-left {
  width: 32px;
  border-radius: 3px;
  background: linear-gradient(180deg, #6b7280, #565d69 45%, #4b5361);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.25),
    inset 0 -1px 2px rgba(0, 0, 0, 0.45);
}

.app-tabs-cap-right {
  width: 32px;
  clip-path: polygon(0 0, 100% 0, 88% 100%, 0 100%);
  background: linear-gradient(180deg, #262b33, #14171a);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.08),
    inset 0 -1px 2px rgba(0, 0, 0, 0.55);
  color: #cbd5e1;
  font-size: 13px;
  text-shadow: 0 0 4px rgba(148, 197, 255, 0.7);
}

.app-tab-wrap {
  position: relative;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.4));
  transition: opacity 0.15s ease;
}

.app-tab-wrap.dragging {
  opacity: 0.4;
}

.app-tab {
  display: flex;
  align-items: center;
  height: 100%;
  text-decoration: none;
}

.app-tab-shape {
  display: flex;
  align-items: center;
  position: relative;
  height: 100%;
  padding: 0 22px 0 28px;
  white-space: nowrap;
  clip-path: polygon(10px 0, 100% 0, calc(100% - 10px) 100%, 0 100%);
  background: var(--tab-color, var(--app-tab-1));
  transition: filter 0.15s ease;
}

/* Relief "biseau verre/metal brosse" : les 20% du haut et les 20% du bas
   forment le biseau (bande claire qui s'assombrit vers le bord, puis bande
   sombre qui s'eclaircit vers le bord), le milieu (60% de la hauteur) reste
   une surface plane et lisible pour le texte - proportions en %, donc
   toujours exactement 20/60/20 quelle que soit la hauteur reelle du rail. */
.app-tab-shape::after {
  content: "";
  position: absolute;
  inset: 0;
  clip-path: inherit;
  background: linear-gradient(
    180deg,
    rgba(255, 255, 255, 0.55) 0%,
    rgba(255, 255, 255, 0.12) 20%,
    rgba(255, 255, 255, 0.12) 20%,
    rgba(0, 0, 0, 0) 80%,
    rgba(0, 0, 0, 0.4) 100%
  );
  pointer-events: none;
}

/* Grain "metal brosse" superpose au reflet ci-dessus, tres discret,
   independant de la teinte (blanc/noir en simple superposition). */
.app-tab-shape::before {
  content: "";
  position: absolute;
  inset: 0;
  clip-path: inherit;
  background: repeating-linear-gradient(
    100deg,
    rgba(255, 255, 255, 0.05) 0px,
    rgba(255, 255, 255, 0.05) 1px,
    transparent 1px,
    transparent 3px
  );
  pointer-events: none;
}

.app-tab-label {
  position: relative;
  z-index: 1;
  color: #fff;
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  text-shadow:
    0 1px 2px rgba(0, 0, 0, 0.75),
    0 0 1px rgba(0, 0, 0, 0.9);
}

/* Couleurs par defaut par identite de module (remplace l'ancien
   positionnement purement nth-child) - reprend exactement les couleurs
   actuelles : Licences=Bleu, Diagnostics=Vert, Drive=Violet, Parc=Orange,
   Clients=Bleu (comportement de bouclage deja existant, conserve tel quel).
   Un choix personnalise (menu contextuel) ecrase --tab-color en inline sur
   .app-tab-wrap, qui l'emporte sur ces regles d'attribut. */
.app-tab-wrap[data-module-id="licenses"] { --tab-color: var(--palette-bleu); }
.app-tab-wrap[data-module-id="diagnostics"] { --tab-color: var(--palette-vert); }
.app-tab-wrap[data-module-id="drive"] { --tab-color: var(--palette-violet); }
.app-tab-wrap[data-module-id="parc"] { --tab-color: var(--palette-orange); }
.app-tab-wrap[data-module-id="clients"] { --tab-color: var(--palette-bleu); }

.app-tab.active .app-tab-shape {
  filter: brightness(1.1);
}

.app-tab:hover .app-tab-shape {
  filter: brightness(1.05);
}

.app-tab.active:hover .app-tab-shape {
  filter: brightness(1.1);
}

/* Menu contextuel de recoloration (clic droit sur un onglet) - meme
   convention que .context-menu de parc/css/portal.css (position fixe au
   curseur, borne a la fenetre en JS), mais classe globale distincte car
   base.html/style.css sont charges sur TOUTES les pages. */
.topbar-color-menu {
  position: fixed;
  z-index: 60;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  width: 132px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-soft);
  padding: 10px;
}

/* [hidden] et .topbar-color-menu ont la meme specificite (0,1,0) : sans
   cette regle explicite, l'ordre du cascade fait gagner le display:flex
   ci-dessus meme quand l'attribut hidden est present (cf. le meme motif
   deja utilise par .app-switcher-dropdown[hidden] plus haut). */
.topbar-color-menu[hidden] {
  display: none;
}

.color-swatch {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.25);
  background: var(--swatch-color, currentColor);
  cursor: pointer;
  padding: 0;
}

.color-swatch:hover {
  transform: scale(1.12);
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  font-weight: 700;
  font-size: 16px;
  letter-spacing: 0.2px;
}

.brand-mark {
  width: 22px;
  height: 22px;
  border-radius: 7px;
  background: var(--accent-gradient);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.08) inset;
}

/* Page */
.page {
  max-width: 560px;
  margin: 0 auto;
  padding: 20px 16px 8px;
}

.page-title {
  font-family: var(--font-display);
  font-size: 24px;
  font-weight: 700;
  margin: 4px 0 4px;
}

.page-subtitle {
  color: var(--text-muted);
  font-size: 14px;
  margin: 0 0 18px;
  line-height: 1.5;
}

/* Étiquette discrète au-dessus d'un titre ("RAPPORT D'AUDIT...", type
   éditorial) - réutilisable partout où un titre de page bénéficie d'un
   contexte d'une ligne avant lui. */
.eyebrow {
  display: block;
  color: var(--text-muted);
  font-size: 11.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 1px;
  margin: 0 0 6px;
}

.section-title {
  font-size: 16px;
  font-weight: 700;
  margin: 24px 0 10px;
}

/* Titre de section avec une action à droite (ex. "Voir plus" de la section
   Activité récente, cf. templates/hub/dashboard.html) - .section-title
   perd alors sa marge propre, portée par cette ligne à la place. */
.section-title-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 24px 0 10px;
}

.section-title-row .section-title {
  margin: 0;
}

.section-title-link {
  flex-shrink: 0;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--accent-1);
  text-decoration: none;
}

.section-title-link:hover {
  text-decoration: underline;
}

/* Flash messages */
.flash-stack {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 16px;
}

.flash {
  padding: 12px 14px;
  border-radius: var(--radius-sm);
  font-size: 14px;
  font-weight: 500;
  border: 1px solid transparent;
}

.flash-success {
  background: var(--success-bg);
  color: var(--success);
  border-color: rgba(34, 197, 94, 0.3);
}

.flash-warning {
  background: var(--warning-bg);
  color: var(--warning);
  border-color: rgba(245, 158, 11, 0.3);
}

.flash-error {
  background: var(--danger-bg);
  color: var(--danger);
  border-color: rgba(192, 57, 43, 0.3);
}

/* Low stock banner */
.banner {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px 16px;
  border-radius: var(--radius-md);
  font-size: 14px;
  font-weight: 600;
  margin-bottom: 18px;
  border: 1px solid rgba(245, 158, 11, 0.35);
}

/* Un `display` d'auteur (ci-dessus) prime toujours sur la feuille de style
   du navigateur, y compris sur sa règle par défaut [hidden] { display: none }
   — sans cette redéfinition explicite, l'attribut hidden serait ignoré et
   la bannière resterait affichée en permanence, quelle que soit sa valeur
   côté serveur. */
.banner[hidden] {
  display: none;
}

.banner-warning {
  background: var(--warning-bg);
  color: var(--warning);
}

.banner-icon {
  font-size: 18px;
}

.banner-link {
  cursor: pointer;
  transition: filter 0.12s ease;
}

.banner-link:hover {
  filter: brightness(1.1);
}

/* Carte générique (fond/bordure/ombre partagés par tous les modules -
   Parc/Clients/Diagnostics définissaient jusque-là chacun leur propre .card
   avec un padding légèrement différent : 22px/16px/24px). */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-soft);
  padding: 20px;
}

/* Stat cards */
.stat-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  margin-bottom: 36px;
}

.stat-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 20px 16px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  box-shadow: var(--shadow-soft);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: border-color 0.12s ease, transform 0.12s ease;
}

.stat-card:active {
  transform: scale(0.98);
}

.stat-card:hover {
  border-color: var(--accent-1);
}

.stat-value {
  font-size: 32px;
  font-weight: 800;
  background: var(--accent-gradient);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.stat-card-muted .stat-value {
  background: none;
  -webkit-text-fill-color: initial;
  color: var(--text);
}

.stat-label {
  color: var(--text-muted);
  font-size: 13px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.4px;
}

/* ==========================================================================
   Écran d'accueil (hub) : intro, tuiles de stats colorées, cartes des
   modules disponibles.
   ========================================================================== */
.home-shell {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.home-intro {
  margin-bottom: 8px;
}

.home-intro .page-title {
  margin-bottom: 2px;
}

.home-stat-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  margin-bottom: 8px;
}

.home-quick-add-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  padding: 14px;
  margin-bottom: 16px;
  font-size: 15px;
  font-weight: 800;
  letter-spacing: 0.02em;
  color: #063a26;
  background: linear-gradient(135deg, #34d399, #10b981);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-soft);
  text-decoration: none;
  transition: transform 0.15s ease;
}

.home-quick-add-btn:active {
  transform: scale(0.98);
}

.home-stat-tile {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 18px 16px;
  border-radius: var(--radius-lg);
  color: var(--tile-ink);
  box-shadow: var(--shadow-soft);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform 0.12s ease, filter 0.12s ease;
}

.home-stat-tile:hover {
  filter: brightness(1.05);
}

.home-stat-tile:active {
  transform: scale(0.98);
}

.home-stat-icon {
  font-size: 22px;
  line-height: 1;
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-sm);
  background: rgba(255, 255, 255, 0.22);
}

.home-stat-value {
  font-size: 28px;
  font-weight: 800;
  line-height: 1;
}

.home-stat-label {
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0.2px;
  opacity: 0.9;
}

.tile-blue {
  background: var(--tile-blue);
}

.tile-green {
  background: var(--tile-green);
}

.tile-orange {
  background: var(--tile-orange);
}

.tile-purple {
  background: var(--tile-purple);
}

.tile-red {
  background: var(--tile-red);
}

/* Liste "Activité récente" : fusion clients créés/mis à jour + factures
   envoyées (cf. backend/hub.py::_recent_activity), du plus récent au plus
   ancien. Chaque item est un bloc horizontal sur 2 lignes (cf.
   static/js/home_activity.js pour les interactions clic court/appui long). */
.home-activity-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.home-activity-item {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 12px 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-soft);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  /* Empêche la bulle "Copier/Partager" iOS et la sélection de texte lors de
     l'appui long (cf. static/js/home_activity.js), qui doit ouvrir NOTRE
     menu contextuel plutôt que celui du système. */
  -webkit-touch-callout: none;
  user-select: none;
  transition: transform 0.12s ease, border-color 0.12s ease;
}

.home-activity-item:hover {
  border-color: var(--accent-1);
}

.home-activity-item:active {
  transform: scale(0.99);
}

.home-activity-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.home-activity-row-date {
  justify-content: flex-end;
}

.home-activity-client {
  font-size: 14.5px;
  font-weight: 700;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Nom cliquable (client identifié, cf. templates/hub/_recent_activity_list.html)
   - toujours souligné, contrairement à .clients-cell-name-link (souligné au
   survol seulement) : ce lien pointe systématiquement vers la fiche client,
   même quand le reste de la ligne mène ailleurs (ex. un rapport ou une
   facture), donc il doit se distinguer visuellement en permanence. */
.home-activity-client-link {
  color: var(--accent-1);
  text-decoration: underline;
}

.home-activity-client-link:hover {
  color: var(--accent-2);
}

.home-activity-badge {
  flex-shrink: 0;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.3px;
  padding: 3px 9px;
  border-radius: 999px;
  color: #fff;
}

.home-activity-badge-creation {
  background: var(--tile-green, #10b981);
}

.home-activity-badge-update {
  background: var(--tile-blue, #3b82f6);
}

.home-activity-badge-invoice {
  background: var(--tile-purple, #8b5cf6);
}

.home-activity-badge-report {
  background: var(--tile-orange, #ea580c);
}

.home-activity-date {
  font-size: 12.5px;
  color: var(--text-muted);
}

/* Menu contextuel (appui long / clic droit) de la liste "Activité récente"
   ci-dessus - même convention que .context-menu de parc/diagnostics/clients
   (dupliqué ici plutôt que partagé, cf. commentaires plus haut dans ce
   fichier) : l'accueil ne charge aucune CSS de module. */
.context-menu {
  position: fixed;
  z-index: 50;
  min-width: 180px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-soft);
  padding: 6px;
}

.context-menu button {
  display: block;
  width: 100%;
  text-align: left;
  padding: 9px 12px;
  border: none;
  background: none;
  border-radius: 7px;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--text);
  cursor: pointer;
}

.context-menu[hidden] {
  display: none;
}

.context-menu button:hover {
  background: var(--surface-raised);
}

@media (min-width: 560px) {
  .home-stat-grid {
    /* auto-fit plutôt qu'un nombre de colonnes fixe : le nombre de tuiles
       varie (certaines ne s'affichent que si leur compteur est non nul). */
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  }
}

/* Tableau de bord : structure verticale permettant, sur mobile, de
   descendre les actions au centre de l'espace restant sous les cartes de
   statistiques (cf. règles dans la media query mobile plus bas). */
.dashboard-shell {
  display: flex;
  flex-direction: column;
  /* Réserve exactement la hauteur restante sous la topbar/nav pour pouvoir
     centrer verticalement les actions dans l'espace libre (mobile), sans
     dépasser (ce qui créerait un ascenseur vertical actif alors qu'il n'y a
     rien à faire défiler). Décompte : topbar (var(--topbar-height)) +
     barre du bas + son espacement (var(--nav-height) + 16px, réservés via
     le padding-bottom du body) + padding propre de .page (20px + 8px). */
  min-height: calc(100dvh - var(--topbar-height) - var(--nav-height) - 16px - 20px - 8px);
}

.dashboard-actions-wrap {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 24px 0;
}

.actions-grid {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  width: 100%;
  max-width: 300px;
  margin: 0 auto;
}

/* Boutons d'action du tableau de bord : sobres, contenu (icône + texte)
   centré comme un seul bloc, sans halo ni badge — même famille visuelle
   que les cartes de stats (fond .surface, coins arrondis, ombre douce). */
.action-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
  padding: 16px 20px;
  border-radius: var(--radius-lg);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.1px;
  text-align: center;
  cursor: pointer;
  box-shadow: var(--shadow-soft);
  -webkit-tap-highlight-color: transparent;
  transition: transform 0.12s ease, border-color 0.12s ease, background 0.12s ease, filter 0.12s ease;
}

.action-btn:active {
  transform: scale(0.97);
}

.action-btn-icon {
  font-size: 16px;
  line-height: 1;
}

.action-btn-primary {
  background: var(--accent-gradient);
  color: #ffffff;
  border-color: transparent;
  box-shadow: 0 10px 22px rgba(200, 117, 73, 0.28);
}

.action-btn-primary:hover {
  filter: brightness(1.06);
}

.action-btn-secondary:hover {
  border-color: var(--accent-1);
  background: var(--surface-raised);
}

.btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  border: none;
  border-radius: var(--radius-md);
  padding: 16px 20px;
  font-size: 16px;
  font-weight: 700;
  cursor: pointer;
  transition: transform 0.12s ease, filter 0.12s ease, opacity 0.12s ease;
  -webkit-tap-highlight-color: transparent;
}

.btn:active {
  transform: scale(0.97);
}

.btn:focus-visible,
.icon-btn:focus-visible,
.nav-item:focus-visible,
.topbar-action:focus-visible,
.app-tab:focus-visible,
a:focus-visible {
  outline: 2px solid var(--accent-1);
  outline-offset: 2px;
}

/* État "traitement en cours" (cf. static/js/app.js bindLoadingState) :
   retour visuel immédiat au clic, avant même la réponse du serveur. */
.btn.is-loading {
  opacity: 0.75;
  cursor: progress;
  pointer-events: none;
}

.btn-icon {
  font-size: 18px;
  line-height: 1;
}

.btn-big {
  width: 100%;
  padding: 18px 20px;
  border-radius: var(--radius-lg);
}

.btn-primary {
  background: var(--accent-gradient);
  color: #ffffff;
  box-shadow: 0 10px 24px rgba(200, 117, 73, 0.35);
}

.btn-primary:hover {
  filter: brightness(1.08);
}

.btn-primary:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.btn-secondary {
  background: var(--surface-raised);
  color: var(--text);
  border: 1px solid var(--border);
}

.btn-ghost {
  background: transparent;
  color: var(--text-muted);
  border: 1px solid var(--border);
}

/* Recherche */
.search-form {
  margin-bottom: 12px;
}

.search-form .text-input {
  font-size: 15px;
  padding-right: 40px;
}

.search-input-wrap {
  position: relative;
}

/* Masque la petite croix native des input[type=search] (rendu
   incohérent selon navigateurs) au profit du bouton personnalisé
   ci-dessous. */
.search-input-wrap input[type="search"]::-webkit-search-cancel-button {
  -webkit-appearance: none;
  appearance: none;
}

.search-clear {
  position: absolute;
  top: 50%;
  right: 6px;
  transform: translateY(-50%);
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: transparent;
  color: var(--text-muted);
  font-size: 20px;
  line-height: 1;
  border-radius: 50%;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.search-clear[hidden] {
  display: none;
}

.search-clear:hover,
.search-clear:active {
  background: var(--surface-raised);
  color: var(--text);
}

/* Onglets de filtre - toujours visibles (boutons, plus des liens : cf.
   static/js/licenses_grid.js pour le filtrage client-side AG Grid), défilent
   horizontalement si la largeur manque plutôt que de basculer vers un menu
   déroulant séparé. */
.filter-tabs {
  display: flex;
  gap: 8px;
  margin-bottom: 16px;
  overflow-x: auto;
}

.filter-tab {
  padding: 9px 16px;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 600;
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text-muted);
  white-space: nowrap;
  cursor: pointer;
}

.filter-tab.active {
  background: var(--accent-gradient);
  color: #fff;
  border-color: transparent;
}

/* Bouton compact (texte réduit) - même mesure que .btn-sm dupliqué dans
   static/parc/css/portal.css, static/diagnostics/css/portal.css et
   static/clients/css/portal.css : ce module n'a pas de feuille de style
   dédiée, donc la règle vit ici, dans le CSS partagé. */
.btn-sm {
  padding: 7px 12px;
  font-size: 12.5px;
  border-radius: 9px;
}

/* Ligne des onglets de filtre + actions du tableau (recherche sur sa
   propre ligne au-dessus, cf. templates/licenses.html) : onglets à gauche,
   "Colonnes"/"Exporter CSV"/"Activer une nouvelle licence"/"Commander des
   licences" à droite. */
.licenses-header-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}

.licenses-kebab-dropdown {
  position: relative;
}

.licenses-kebab-btn {
  font-size: 18px;
  line-height: 1;
  padding: 8px 14px;
}

.licenses-kebab-menu {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 20;
  display: flex;
  flex-direction: column;
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-soft);
  overflow: hidden;
  min-width: 220px;
}

/* [hidden] et .licenses-kebab-menu ont la même spécificité qu'un simple
   [hidden] : sans cette règle explicite le display:flex ci-dessus gagne
   même quand l'attribut hidden est présent (même piège déjà rencontré
   deux fois cette session pour .parc-kebab-menu/.topbar-color-menu). */
.licenses-kebab-menu[hidden] {
  display: none;
}

.licenses-kebab-menu button {
  display: block;
  width: 100%;
  text-align: left;
  border: none;
  background: none;
  padding: 13px 16px;
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
  cursor: pointer;
}

.licenses-kebab-menu button:hover {
  background: var(--surface);
}

.licenses-search-row {
  margin-bottom: 16px;
  max-width: 420px;
}

.licenses-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin-bottom: 14px;
}

.licenses-toolbar .filter-tabs {
  margin-bottom: 0;
}

.licenses-toolbar-spacer {
  flex: 1;
}

.licenses-columns-dropdown {
  position: relative;
}

.licenses-columns-menu {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 20;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-soft);
  padding: 8px;
  min-width: 200px;
}

.licenses-columns-menu[hidden] {
  display: none;
}

.licenses-columns-menu label {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  font-weight: 500;
  color: var(--text);
  padding: 6px 8px;
  margin: 0;
  border-radius: 7px;
  cursor: pointer;
}

.licenses-columns-menu label:hover {
  background: var(--surface-raised);
}

.licenses-columns-menu input[type="checkbox"] {
  accent-color: var(--accent-1);
}

/* Menu contextuel (clic droit sur une ligne du tableau) - nommé
   différemment de .context-menu (parc/diagnostics/clients) car
   static/css/style.css est chargé sur toutes les pages, cf. commentaire
   similaire sur .topbar-color-menu plus haut dans ce fichier. */
.licenses-context-menu {
  position: fixed;
  z-index: 50;
  min-width: 180px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-soft);
  padding: 6px;
}

.licenses-context-menu[hidden] {
  display: none;
}

.licenses-context-menu button {
  display: block;
  width: 100%;
  text-align: left;
  padding: 9px 12px;
  border: none;
  background: none;
  border-radius: 7px;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--text);
  cursor: pointer;
}

/* [hidden] et .licenses-context-menu button ont la même spécificité (0,1,1)
   qu'un sélecteur [hidden] seul (0,1,0) additionné du tag : sans cette
   règle explicite, le display:block ci-dessus gagne même quand l'attribut
   hidden est présent sur le bouton (même piège déjà rencontré pour
   .parc-kebab-menu/.topbar-color-menu). */
.licenses-context-menu button[hidden] {
  display: none;
}

.licenses-context-menu button:hover {
  background: var(--surface-raised);
}

.licenses-context-menu button.licenses-context-menu-danger {
  color: var(--danger);
}

.reconciliation-suggestion-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-height: 50vh;
  overflow-y: auto;
}

.reconciliation-suggestion-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}

.reconciliation-suggestion-info {
  font-size: 13.5px;
}

.reconciliation-suggestion-actions {
  display: flex;
  gap: 6px;
  flex-shrink: 0;
}

/* License list (réutilisé par templates/import.html pour l'aperçu des
   licences importées - pas seulement par le tableau AG Grid de /licences). */
.license-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.license-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 14px 16px;
}

.license-card-main {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.license-key {
  font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
  font-size: 13.5px;
  letter-spacing: 0.3px;
  word-break: break-all;
}

.badge {
  flex-shrink: 0;
  font-size: 11.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  padding: 5px 10px;
  border-radius: 999px;
}

.badge-available {
  background: var(--success-bg);
  color: var(--success);
}

.badge-sold {
  background: rgba(200, 117, 73, 0.16);
  color: var(--accent-1);
}

/* Composant "état vide" unique pour toute l'app (liste/tableau/grille sans
   résultat) - icône badge + texte, remplace les variantes divergentes qui
   coexistaient par module (icône+texte à un seul endroit, texte seul
   ailleurs, tailles/paddings différents). Les modules qui n'ont besoin que
   du texte peuvent omettre .empty-state-icon, la mise en page reste
   cohérente dans les deux cas. */
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: 48px 24px;
  color: var(--text-muted);
  font-size: 14px;
}

.empty-state-icon {
  width: 56px;
  height: 56px;
  margin-bottom: 14px;
  border-radius: 16px;
  background: var(--surface-raised);
  color: var(--text-muted);
  display: flex;
  align-items: center;
  justify-content: center;
}

.empty-state p {
  margin: 0;
  max-width: 360px;
}

/* Horodatage de build/deploiement (cf. backend/__init__.py::APP_STARTED_AT) -
   discret, juste assez visible pour verifier qu'un deploiement a pris effet. */
.app-build-footer {
  text-align: center;
  padding: 10px 10px 18px;
  font-size: 11px;
  color: var(--text-muted);
  opacity: 0.6;
}

/* Import form */
.import-form {
  display: flex;
  flex-direction: column;
  gap: 14px;
  margin-bottom: 8px;
}

.csv-import {
  margin-top: 32px;
  padding-top: 24px;
  border-top: 1px solid var(--border);
}

.textarea {
  width: 100%;
  min-height: 180px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  color: var(--text);
  padding: 14px;
  font-size: 14px;
  font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
  resize: vertical;
}

.textarea:focus {
  outline: none;
  border-color: var(--accent-1);
  box-shadow: 0 0 0 3px rgba(200, 117, 73, 0.2);
}

/* Bottom nav */
.bottom-nav {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  height: var(--nav-height);
  background: var(--nav-bg);
  backdrop-filter: blur(12px);
  border-top: 1px solid var(--border);
  display: flex;
  padding-bottom: env(safe-area-inset-bottom);
  z-index: 20;
}

.nav-item {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  color: var(--text-muted);
  font-size: 11px;
  font-weight: 600;
  transition: color 0.15s ease, background-color 0.15s ease;
}

.nav-item:hover {
  color: var(--text);
  background: var(--surface-raised);
}

.nav-icon {
  font-size: 20px;
}

.nav-label {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.nav-item.active {
  color: var(--accent-2);
}

/* Options propres à l'application courante (Importer/Paramètres/...) : le
   changement d'app lui-même vit désormais dans la topbar, donc ces options
   peuvent occuper toute la barre du bas mobile, pas seulement la sidebar
   desktop. Bouton réinitialisé (fond/bordure/police) pour "Verrouiller",
   qui est un <button> et non un <a> comme les autres. */
.nav-item-secondary {
  border: none;
  background: transparent;
  font-family: inherit;
  cursor: pointer;
}

.nav-item-secondary-form {
  display: contents;
}

.nav-divider {
  display: none;
}

/* Zone "Liens" (barre latérale Licences/Diagnostic, jamais Drive) : liens
   externes ajoutés par l'utilisateur, réordonnables par glisser-déposer
   (cf. static/js/app.js::initSidebarLinksReorder). Réordonnancement HTML5
   natif non tactile : réservé au desktop (sidebar verticale), où la barre
   du bas mobile (rangée d'icônes, flex:1) n'a de toute façon pas la place
   pour une liste de longueur variable - cf. media query desktop plus bas. */
.nav-links-section {
  display: none;
}

.nav-links-title {
  margin: 18px 0 4px;
  padding: 0 14px;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
}

.nav-links-list {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.nav-link-item {
  display: flex;
  align-items: center;
  gap: 4px;
  border-radius: var(--radius-sm);
}

.nav-link-item.dragging {
  opacity: 0.4;
}

.nav-link-drag-handle {
  flex-shrink: 0;
  padding: 0 0 0 6px;
  color: var(--text-muted);
  cursor: grab;
  font-size: 14px;
}

.nav-link-anchor {
  flex: 1;
  min-width: 0;
}

.nav-link-anchor .nav-label {
  overflow: hidden;
  text-overflow: ellipsis;
}

.nav-link-item:hover {
  background: var(--surface-raised);
}

.nav-link-delete-form {
  display: contents;
}

.nav-link-delete-btn {
  flex-shrink: 0;
  width: 26px;
  height: 26px;
  margin-right: 6px;
  border: none;
  border-radius: 8px;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.12s ease, background-color 0.12s ease, color 0.12s ease;
}

.nav-link-item:hover .nav-link-delete-btn {
  opacity: 1;
}

.nav-link-delete-btn:hover {
  background: var(--danger-bg);
  color: var(--danger);
}

/* Modal */
.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(4px);
  display: flex;
  align-items: flex-end;
  justify-content: center;
  z-index: 50;
}

.modal-backdrop[hidden] {
  display: none;
}

.modal {
  width: 100%;
  max-width: 480px;
  max-height: 88vh;
  overflow-y: auto;
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: 22px 22px 0 0;
  padding: 28px 22px calc(24px + env(safe-area-inset-bottom));
  box-shadow: var(--shadow-soft);
  animation: modal-in 0.2s ease;
}

.modal-section-divider {
  height: 1px;
  background: var(--border);
  margin: 18px 0;
}

.modal-expiry-info {
  color: var(--text-muted);
  font-size: 13px;
  margin: 0 0 16px;
}

#license-edit-form .text-input,
#sell-step-confirm .text-input {
  margin-bottom: 14px;
}

.modal-actions form {
  display: contents;
}

@keyframes modal-in {
  from {
    transform: translateY(24px);
    opacity: 0;
  }
  to {
    transform: translateY(0);
    opacity: 1;
  }
}

@media (min-width: 560px) {
  .modal-backdrop {
    align-items: center;
  }
  .modal {
    border-radius: var(--radius-lg);
  }
}

.modal-step h2 {
  margin: 0 0 12px;
  font-size: 19px;
}

.modal-license-key {
  font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
  font-size: 15px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 12px 14px;
  word-break: break-all;
  margin: 0 0 16px;
}

.license-key-big {
  font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 18px 12px;
  margin: 0 0 16px;
  text-align: center;
}

/* Modale de scan QR (partage de licence mobile -> PC, cf. static/js/
   license_share_scan.js) - vidéo en plein cadre 4:3, coins arrondis pour
   rester cohérent avec le reste des modales. */
.licenses-share-scan-video-wrap {
  width: 100%;
  aspect-ratio: 4 / 3;
  background: #000;
  border-radius: var(--radius-md);
  overflow: hidden;
  margin: 4px 0 14px;
}

.licenses-share-scan-video-wrap video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.license-key-big div {
  font-size: 26px;
  font-weight: 800;
  letter-spacing: 3px;
  line-height: 1.7;
  color: var(--text);
}

.field-label {
  display: block;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-muted);
  margin-bottom: 6px;
}

.field {
  margin-bottom: 16px;
}

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

.text-input {
  width: 100%;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  padding: 13px 14px;
  font-size: 15px;
}

.text-input:focus {
  outline: none;
  border-color: var(--accent-1);
  box-shadow: 0 0 0 3px rgba(200, 117, 73, 0.2);
}

.radio-group {
  display: flex;
  gap: 10px;
  margin: 6px 0 4px;
}

.radio-option {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 12px 10px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-size: 14px;
  font-weight: 600;
  color: var(--text-muted);
  cursor: pointer;
  transition: border-color 0.12s ease, color 0.12s ease, background 0.12s ease;
}

.radio-option input {
  accent-color: var(--accent-1);
}

.radio-option:has(input:checked) {
  border-color: var(--accent-1);
  color: var(--text);
  background: var(--surface-raised);
}

.checkbox-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 10px 0 4px;
  max-height: 240px;
  overflow-y: auto;
}

.checkbox-list-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 11px 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-size: 14px;
  font-weight: 600;
  color: var(--text-muted);
  cursor: pointer;
  transition: border-color 0.12s ease, color 0.12s ease, background 0.12s ease;
}

.checkbox-list-item input {
  accent-color: var(--accent-1);
  width: 16px;
  height: 16px;
  flex-shrink: 0;
}

.checkbox-list-item:has(input:checked) {
  border-color: var(--accent-1);
  color: var(--text);
  background: var(--surface-raised);
}

.field-error {
  color: var(--danger);
  font-size: 13px;
  margin: 8px 0 0;
}

.field-success {
  color: var(--success);
  font-size: 13px;
  margin: 8px 0 0;
  font-weight: 600;
}

.field-hint {
  color: var(--text-muted);
  font-size: 12px;
  margin: 6px 0 0;
}

.modal-actions {
  display: flex;
  gap: 10px;
  margin-top: 20px;
}

.modal-actions .btn {
  flex: 1;
  padding: 14px 16px;
}

.spinner {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: 3px solid var(--border);
  border-top-color: var(--accent-2);
  animation: spin 0.8s linear infinite;
  margin: 0 auto 16px;
}

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

#sell-step-picking {
  text-align: center;
  color: var(--text-muted);
  padding: 10px 0;
}

.check-mark {
  width: 52px;
  height: 52px;
  border-radius: 50%;
  background: var(--success-bg);
  color: var(--success);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 26px;
  font-weight: 800;
  margin: 0 auto 14px;
}

.check-mark-warn {
  background: var(--warning-bg);
  color: var(--warning);
}

.check-mark-primary {
  background: rgba(200, 117, 73, 0.14);
  color: var(--accent-1);
}

/* Expiration */
.expiry-warning {
  color: var(--warning);
  font-weight: 700;
}

.expiry-danger {
  color: var(--danger);
  font-weight: 700;
}

.licenses-client-unresolved {
  color: var(--danger);
  font-weight: 600;
}

.mute-toggle {
  display: inline-block;
  border: 1px solid var(--border);
  background: var(--surface-raised);
  color: var(--text-muted);
  font-size: 11px;
  font-weight: 600;
  padding: 4px 9px;
  border-radius: 999px;
  cursor: pointer;
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
}

.mute-toggle:hover {
  border-color: var(--accent-1);
  color: var(--text);
}

/* Paramètres */
.settings-section {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 18px 16px;
  margin-top: 8px;
  margin-bottom: 16px;
}

.settings-section .section-title {
  margin-top: 0;
}

.settings-section .page-subtitle {
  margin-bottom: 16px;
}

.settings-actions {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.settings-actions form {
  display: contents;
}

.email-list {
  list-style: none;
  margin: 0 0 14px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.email-list-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
  font-size: 13.5px;
}

.email-list-item form {
  display: contents;
}

.empty-state-inline {
  color: var(--text-muted);
  font-size: 13px;
  margin: 0 0 14px;
}

.passkey-meta {
  color: var(--text-muted);
  font-size: 12px;
}

.api-key-value {
  display: inline-block;
  font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
  font-size: 12.5px;
  word-break: break-all;
}

.api-key-copy-btn {
  margin-left: 6px;
}

.html-template-list-item-name {
  font-weight: 600;
}

.html-template-list-item-actions {
  display: flex;
  gap: 6px;
  flex-shrink: 0;
}

.html-template-list-item-actions form {
  display: contents;
}

.html-template-form .field:first-child .text-input {
  max-width: 420px;
}

.html-template-textarea {
  min-height: 420px;
  font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
  font-size: 13px;
  line-height: 1.5;
  resize: vertical;
  white-space: pre;
}

.email-type-list-item {
  align-items: center;
}

.email-type-list-item-name {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1;
  min-width: 0;
}

.email-type-native-badge {
  display: inline-block;
  background: var(--surface-raised);
  color: var(--text-muted);
  font-size: 11px;
  font-weight: 600;
  padding: 3px 8px;
  border-radius: 999px;
  border: 1px solid var(--border);
}

.email-type-rename-form {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1;
  min-width: 0;
}

.email-type-rename-form .text-input {
  flex: 1;
  min-width: 0;
  padding: 8px 10px;
  font-size: 13.5px;
}

.email-type-associate-form {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 14px;
}

.email-type-associate-form select.text-input {
  flex: 1 1 180px;
  min-width: 0;
}

.email-type-associate-form .btn {
  flex-shrink: 0;
}

.inline-form {
  display: flex;
  gap: 10px;
}

.inline-form .text-input {
  flex: 1;
  min-width: 0;
}

.inline-form .btn {
  flex-shrink: 0;
  width: auto;
  padding-left: 18px;
  padding-right: 18px;
}

/* Deux seuils numériques + bouton (Paramètres Licences, réconciliation) -
   .inline-form suppose un seul champ ; ici chaque seuil a son propre
   .field (label au-dessus, cf. convention des formulaires de fiche
   client/licence), alignés sur une ligne qui passe à la suivante si la
   largeur manque. */
.reconciliation-thresholds-form {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 12px;
}

.reconciliation-thresholds-form .field {
  width: 160px;
}

/* Zone de danger */
.danger-zone {
  background: var(--surface);
  border: 1px solid rgba(192, 57, 43, 0.35);
  border-radius: var(--radius-lg);
  padding: 18px 16px;
  margin-top: 8px;
  margin-bottom: 16px;
}

.danger-zone:last-child {
  margin-bottom: 0;
}

.danger-zone .section-title {
  margin-top: 0;
  color: var(--danger);
}

.danger-zone-text {
  color: var(--text-muted);
  font-size: 13.5px;
  line-height: 1.5;
  margin: 0 0 16px;
}

.btn-danger {
  background: var(--danger);
  color: #fff;
  box-shadow: 0 10px 24px rgba(192, 57, 43, 0.3);
}

/* ==========================================================================
   Desktop (>= 900px) : navigation latérale, mise en page élargie, tableau
   de licences véritable. Le HTML ne change pas selon le viewport — seule
   la disposition CSS est adaptée (display:contents sur les wrappers pour
   laisser leurs enfants rejoindre la grille de la carte/ligne).
   ========================================================================== */
@media (min-width: 900px) {
  body:has(.bottom-nav) {
    padding-left: var(--sidebar-width);
  }

  body {
    padding-bottom: 0;
  }

  .page {
    max-width: 1120px;
    padding: 36px 44px 48px;
  }

  /* Pages a tableau large (Parc Informatique, Clients) : le contenu
     habituel (formulaires, fiches) reste a une largeur de lecture
     confortable via .page ci-dessus, mais un tableau AG Grid avec de
     nombreuses colonnes a besoin de toute la largeur de l'ecran pour eviter
     le defilement horizontal (cf. templates/parc/dashboard.html,
     templates/clients/dashboard.html qui ajoutent cette classe via le bloc
     page_class de base.html). */
  .page.page-wide {
    max-width: 1900px;
  }

  /* Barre du bas -> sidebar fixe à gauche */
  .bottom-nav {
    top: var(--topbar-height);
    left: 0;
    right: auto;
    bottom: 0;
    width: var(--sidebar-width);
    height: auto;
    flex-direction: column;
    align-items: stretch;
    justify-content: flex-start;
    gap: 4px;
    padding: 20px 14px;
    border-top: none;
    border-right: 1px solid var(--border);
  }

  .nav-item {
    flex: none;
    flex-direction: row;
    justify-content: flex-start;
    gap: 12px;
    padding: 11px 14px;
    border-radius: var(--radius-sm);
    font-size: 14px;
    transition: background 0.12s ease, color 0.12s ease;
  }

  .nav-item .nav-icon {
    font-size: 18px;
  }

  .nav-item:hover {
    background: var(--surface-raised);
    color: var(--text);
  }

  .nav-item.active {
    background: var(--surface-raised);
    color: var(--text);
    box-shadow: inset 3px 0 0 var(--accent-2);
  }

  /* Bascule d'application : menu déroulant (.app-switcher) réservé au
     mobile, remplacé ici par des onglets directement visibles dans la
     topbar, CENTRÉS entre le logo et le groupe de droite (thème +
     verrouiller) - d'où la grille à 3 colonnes 1fr/auto/1fr : les deux
     colonnes latérales étant de largeur égale, la colonne centrale (les
     onglets) se retrouve exactement au milieu de la topbar, quelle que
     soit la largeur du contenu de chaque côté. Les rubans .app-tab
     doivent occuper toute la hauteur de la topbar (d'où le height:100%
     propagé depuis .topbar-inner, .topbar ayant lui déjà une hauteur fixe). */
  .topbar-inner {
    height: 100%;
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: stretch;
  }

  .topbar-left {
    justify-self: start;
    align-self: center;
  }

  .topbar-right {
    justify-self: end;
    align-self: center;
  }

  /* Icône Accueil : bascule desktop (gauche, avant le logo) / mobile
     (droite) - deux instances dans le DOM, cf. base.html. */
  .topbar-home-desktop {
    display: inline-flex;
    align-items: center;
  }

  .topbar-home-mobile {
    display: none;
  }

  .topbar-quick-add-mobile {
    display: none;
  }

  .app-switcher {
    display: none;
  }

  .topbar-global-search {
    display: block;
  }

  .app-tabs {
    display: flex;
    justify-self: center;
  }

  /* Paramètres et Verrouiller rejoignent la topbar (tout à droite) sur
     desktop ; sur mobile, ils restent dans le menu ☰. */
  .topbar-settings-link {
    display: inline-flex;
    align-items: center;
  }

  .topbar-lock-form {
    display: contents;
  }

  .nav-item-secondary {
    display: flex;
    width: 100%;
    text-align: left;
  }

  .nav-links-section {
    display: block;
    width: 100%;
  }

  /* Poussé tout en bas de la barre latérale (desktop uniquement, cf.
     templates/base.html) - le conteneur .bottom-nav a déjà top+bottom
     fixés (position:fixed), donc margin-top:auto sur son dernier enfant le
     colle bien au bas de l'écran, quel que soit le contenu au-dessus. */
  .nav-item-bottom {
    margin-top: auto;
    width: 100%;
  }

  .nav-divider {
    display: block;
    height: 1px;
    background: var(--border);
    margin: 8px 6px;
  }

  /* Boutons/liens : effet de survol pertinent avec une souris */
  .btn:hover {
    filter: brightness(1.06);
  }

  .btn-secondary:hover,
  .btn-ghost:hover {
    background: var(--surface);
    border-color: var(--accent-1);
  }

  .filter-tab:hover:not(.active) {
    border-color: var(--accent-1);
    color: var(--text);
  }

  .topbar-action:hover {
    background: var(--surface-raised);
  }

  /* Tableau de bord : plus de centrage vertical façon mobile, retour à un
     enchaînement classique haut en bas ; les actions restent un bloc
     centré, juste un peu plus large. */
  .dashboard-shell {
    min-height: 0;
  }

  .dashboard-actions-wrap {
    flex: none;
    padding: 0;
    margin-top: 28px;
  }

  .actions-grid {
    max-width: 340px;
  }

  .stat-grid {
    max-width: 480px;
  }

  /* Recherche + filtres alignés sur une seule ligne */
  .search-form {
    max-width: 420px;
  }

  /* Formulaires : ne pas les étirer sur toute la largeur de la page */
  .import-form,
  .csv-import {
    max-width: 680px;
  }

  /* Paramètres : deux colonnes pour que tout tienne sur l'écran */
  .settings-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    align-items: start;
    gap: 16px;
  }

  .settings-grid .settings-section,
  .settings-grid .danger-zone {
    margin-top: 0;
    margin-bottom: 0;
  }

  /* Liste de licences (templates/import.html) -> véritable tableau */
  .license-list {
    gap: 0;
    border: 1px solid var(--border);
    border-top: none;
    border-radius: 0 0 var(--radius-md) var(--radius-md);
    overflow: hidden;
  }

  .license-card {
    display: grid;
    grid-template-columns: var(--license-columns);
    gap: 14px;
    align-items: center;
    padding: 12px 20px;
    border: none;
    border-bottom: 1px solid var(--border);
    border-radius: 0;
  }

  .license-list > li:last-child {
    border-bottom: none;
  }

  .license-card:hover {
    background: var(--surface-raised);
  }

  .license-card-main {
    display: contents;
  }
}

/* ==========================================================================
   Page de connexion (code PIN)
   ========================================================================== */
.pin-body {
  padding-top: 0;
  padding-bottom: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}

.pin-screen {
  width: 100%;
  display: flex;
  justify-content: center;
}

.pin-card {
  width: 100%;
  max-width: 296px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 26px 20px;
  text-align: center;
  box-shadow: var(--shadow-soft);
}

.pin-card .brand-mark {
  display: inline-block;
  width: 30px;
  height: 30px;
  border-radius: 9px;
  margin-bottom: 12px;
}

.pin-title {
  font-size: 17px;
  font-weight: 700;
  margin: 0 0 4px;
}

.pin-subtitle {
  color: var(--text-muted);
  font-size: 12.5px;
  line-height: 1.5;
  margin: 0 0 18px;
}

.passkey-login-btn {
  width: 100%;
  margin-bottom: 16px;
}

.qr-login {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  margin-bottom: 14px;
}

.qr-login-code {
  display: inline-block;
  background: #ffffff;
  padding: 5px;
  border-radius: 8px;
  line-height: 0;
}

.qr-login-code svg {
  display: block;
  width: 68px;
  height: 68px;
}

.qr-login-caption {
  font-size: 10.5px;
  color: var(--text-muted);
}

.pin-divider {
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--text-muted);
  font-size: 12px;
  margin-bottom: 16px;
}

.pin-divider::before,
.pin-divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--border);
}

.pin-dots {
  display: flex;
  justify-content: center;
  gap: 9px;
  margin-bottom: 16px;
}

.pin-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  border: 1.5px solid var(--border);
  transition: background 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}

.pin-dot.filled {
  background: var(--accent-gradient);
  border-color: transparent;
  transform: scale(1.2);
}

.pin-error {
  color: var(--danger);
  font-size: 12.5px;
  font-weight: 600;
  min-height: 16px;
  margin: 0 0 14px;
  line-height: 1.5;
}

.pin-keypad {
  display: grid;
  grid-template-columns: repeat(3, 46px);
  justify-content: center;
  gap: 8px;
}

.pin-key {
  width: 46px;
  height: 46px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--surface-raised);
  color: var(--text);
  font-size: 16px;
  font-weight: 600;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.03) inset;
  transition: background 0.1s ease, border-color 0.1s ease, transform 0.1s ease;
}

.pin-key:hover {
  border-color: var(--accent-1);
}

.pin-key:active {
  transform: scale(0.92);
  background: var(--surface);
}

.pin-key-backspace {
  font-size: 15px;
  color: var(--text-muted);
}

.pin-card-wide {
  max-width: 320px;
}

/* Page /activation (partage de licence par QR, cf. backend/license_share.py,
   static/js/license_activation.js) - QR volontairement plus grand que
   .qr-login-code (scan depuis le téléphone, écran souvent à distance/angle,
   contrairement au QR de connexion consulté de très près). */
.activation-qr {
  padding: 14px;
  margin: 0 auto 6px;
}

.activation-qr svg {
  width: 200px;
  height: 200px;
}

/* Plus large que .pin-card-wide (partagée avec totp_setup.html) pour que la
   clé de licence tienne sur une seule ligne plutôt que de retourner à la
   ligne au milieu - cf. .activation-key ci-dessous. */
.activation-card {
  max-width: 480px;
}

.activation-result {
  margin: 4px 0 10px;
}

.activation-key {
  font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
  font-size: 19px;
  font-weight: 800;
  letter-spacing: 1px;
  white-space: nowrap;
  overflow-x: auto;
  background: var(--surface);
  border: 1px solid var(--accent-1, #f97316);
  border-radius: var(--radius-md);
  padding: 14px 16px;
  color: var(--text);
  margin: 0 0 12px;
}

.activation-copy-btn {
  width: 100%;
}

.activation-status {
  font-size: 13px;
  color: var(--text-muted);
  margin: 4px 0 0;
}

.activation-status.is-success {
  color: #34d399;
  font-weight: 700;
}

.qr-confirm-actions .btn + .btn {
  margin-top: 10px;
}

.qr-confirm-result {
  margin-top: 14px;
  margin-bottom: 0;
}

.totp-qr {
  display: inline-block;
  background: #ffffff;
  padding: 14px;
  border-radius: var(--radius-md);
  margin: 0 auto 14px;
}

.totp-qr svg {
  display: block;
  width: 190px;
  height: 190px;
}

.totp-manual {
  margin: 0 0 20px;
  font-size: 12.5px;
  color: var(--text-muted);
}

.totp-manual summary {
  cursor: pointer;
  font-weight: 600;
}

.totp-secret {
  display: block;
  margin-top: 10px;
  padding: 10px 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-size: 13px;
  letter-spacing: 1px;
  word-break: break-all;
  color: var(--text);
}

.totp-code-input {
  text-align: center;
  font-size: 26px;
  font-weight: 700;
  letter-spacing: 8px;
  font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
  padding: 14px 12px 14px 24px;
  margin-bottom: 14px;
}

.totp-code-input::placeholder {
  color: var(--border);
  letter-spacing: 8px;
}

/* ==========================================================================
   Vue "Cartes" responsive des tableaux (static/js/responsive_table.js)
   Classes partagées entre Parc/Clients/Diagnostics/Licences - contrairement
   à .context-menu (dupliqué par module), celles-ci doivent rendre
   identiquement partout, d'où leur centralisation ici avec un préfixe
   distinctif (même raisonnement que .topbar-color-menu plus haut dans ce
   fichier : cette feuille est chargée sur toutes les pages).
   ========================================================================== */

/* Mobile-first : cartes visibles, tableau masqué par défaut. */
.mtable-grid-host {
  display: none;
}

.mtable-cards {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-bottom: 16px;
}

.mtable-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 14px 16px;
}

.mtable-card-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
}

.mtable-card-title {
  font-size: 16px;
  font-weight: 700;
  color: var(--text);
}

.mtable-card-menu-btn {
  flex-shrink: 0;
  font-size: 18px;
  line-height: 1;
  padding: 4px 10px;
  background: none;
  border: none;
  color: var(--text-muted);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.mtable-card-badge {
  margin-top: 6px;
}

.mtable-card-facts {
  margin-top: 8px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 13px;
  color: var(--text-muted);
}

.mtable-filter-trigger {
  display: inline-flex;
}

@media (min-width: 768px) {
  .mtable-grid-host {
    display: block;
  }
  .mtable-cards,
  .mtable-empty,
  .mtable-filter-trigger {
    display: none;
  }
}

/* Panneau "Filtrer / Trier" (bottom sheet) - évite volontairement le motif
   [hidden] pour permettre une transition de glissement animée à
   l'ouverture/fermeture (piloté par la classe .open, ajoutée/retirée en JS). */
.mtable-sheet {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 40;
  transform: translateY(100%);
  visibility: hidden;
  pointer-events: none;
  transition: transform 0.25s ease;
  background: var(--surface-raised);
  border-top: 1px solid var(--border);
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  box-shadow: var(--shadow-soft);
  max-height: 80vh;
  overflow-y: auto;
  padding: 16px;
}

.mtable-sheet.open {
  transform: translateY(0);
  visibility: visible;
  pointer-events: auto;
}

.mtable-sheet-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 12px;
}

.mtable-sheet-header .modal-title {
  margin: 0;
}

.mtable-sheet-body {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.mtable-sheet-sort {
  margin-top: 16px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.mtable-sort-option {
  justify-content: flex-start;
  text-align: left;
}

@media (min-width: 768px) {
  .mtable-sheet {
    display: none;
  }
}

/* Contrôles qui n'ont aucun effet sur la vue "Cartes" (Colonnes, taille de
   page, Export CSV agissent uniquement sur le tableau AG Grid masqué sous
   768px) - masqués sur mobile plutôt que reparentés dans le panneau, pour
   ne pas laisser croire qu'ils affectent les cartes (cf. plan responsive_table). */
.mtable-desktop-only {
  display: none;
}

@media (min-width: 768px) {
  .mtable-desktop-only {
    /* revert plutôt qu'une valeur display fixe : cette classe s'applique à
       des éléments de nature différente selon le module (div de dropdown,
       bouton, select) - revert restaure le display naturel de chacun sans
       avoir à le deviner ici. */
    display: revert;
  }
}

/* Notification brève de succès (toast) - cf. window.MBToast dans
   static/js/app.js. Empilée en bas de l'écran, au-dessus des modales
   (z-index supérieur à .mtable-sheet) mais jamais bloquante (pointer-events
   none sur le conteneur, chaque toast disparaît seule). */
.mtoast-container {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 24px;
  z-index: 100;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  pointer-events: none;
}

.mtoast {
  background: var(--surface-raised);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-soft);
  border-radius: var(--radius-md);
  padding: 12px 20px;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--text);
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.2s ease, transform 0.2s ease;
  max-width: 90vw;
}

.mtoast.show {
  opacity: 1;
  transform: translateY(0);
}

.mtoast.mtoast-error {
  background: var(--danger-bg);
  border-color: var(--danger);
  color: var(--danger);
}

/* Auto-complétion "nom du client" mobile - cf. static/js/app.js::
   MBMobileClientAutocomplete. position:fixed + coordonnées calculées en JS
   (getBoundingClientRect) plutôt qu'un positionnement relatif/absolu
   classique : robuste quel que soit le contexte d'origine du champ (simple
   page, ou <dialog> - qui a sa propre couche d'empilement "top layer" au
   sein de laquelle cet élément est alors inséré, cf. getHost() en JS). */
.mobile-autocomplete-dropdown {
  position: fixed;
  max-height: 168px;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: var(--shadow-soft);
  z-index: 200;
}

.mobile-autocomplete-dropdown[hidden] {
  display: none;
}

.mobile-autocomplete-item {
  display: block;
  width: 100%;
  padding: 10px 14px;
  text-align: left;
  background: none;
  border: none;
  border-bottom: 1px solid var(--border);
  color: var(--text);
  font-size: 14px;
  font-family: inherit;
  cursor: pointer;
}

.mobile-autocomplete-item:last-child {
  border-bottom: none;
}

.mobile-autocomplete-item:active {
  background: var(--surface);
}

/* Garde-fou : ce menu ne doit jamais s'afficher sur desktop, même dans un
   cas limite (ex. resize après ouverture) - le <datalist> natif y reste la
   seule UI, jamais désactivé au-dessus de ce seuil (cf. syncNativeListAttr). */
@media (min-width: 768px) {
  .mobile-autocomplete-dropdown {
    display: none !important;
  }
}

/* Fenêtre superposée "fiche client" plein écran - cf.
   static/js/client_overlay.js (window.MBOpenClientOverlay). Au-dessus de
   tout le contenu normal (toasts, dropdowns) mais sous le "top layer"
   natif des <dialog> (#confirm-modal), qui doit pouvoir s'afficher
   par-dessus sans z-index particulier. */
.client-overlay {
  position: fixed;
  inset: 0;
  z-index: 250;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  /* Garde-fou largeur : quoi qu'il arrive dans le contenu injecté (fragment
     clients/_detail_content.html), rien ne doit jamais pouvoir élargir
     cette fenêtre plein écran au-delà du viewport. */
  overflow-x: hidden;
  max-width: 100vw;
}

.client-overlay[hidden] {
  display: none;
}

.client-overlay-header {
  flex-shrink: 0;
  padding: 12px 16px;
  border-bottom: 1px solid var(--border);
  background: var(--surface);
}

/* Sélecteur plus spécifique que ".client-detail-header" seul (0,1,0) pour
   annuler à coup sûr son "margin-bottom: 4px" (cf. static/clients/css/
   portal.css), quel que soit l'ordre de chargement des deux feuilles de
   style - cette dernière est chargée à la demande (cf. static/js/
   client_overlay.js::ensureFicheStylesLoaded), donc potentiellement APRÈS
   celle-ci, ce qui la ferait sinon gagner la cascade à spécificité égale. */
#client-overlay .client-overlay-header {
  margin-bottom: 0;
}

/* .client-detail-back est normalement un <a> (page complète) - repris ici
   sur un <button> pour l'overlay, qui ne navigue jamais : mêmes propriétés
   visuelles (cf. static/clients/css/portal.css), juste le curseur/la police
   d'un vrai bouton à rétablir (un <a> les a nativement, pas un <button>). */
button.client-detail-back {
  cursor: pointer;
  font: inherit;
}

.client-overlay-title {
  flex: 1;
  min-width: 0;
  margin: 0 12px;
  font-size: 15px;
  font-weight: 700;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Enregistrer (icône disquette) - dans le header plutôt qu'en pied de
   fenêtre : sur mobile, un bouton en bas d'un overlay plein écran peut se
   retrouver hors-écran (barre d'adresse, clavier virtuel pendant l'édition
   d'un champ...), alors que le header reste toujours dans le flux normal,
   en haut. Grisé/désactivé tant qu'aucune modification n'est en attente
   (cf. static/js/client_overlay.js). */
.client-overlay-save-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  flex-shrink: 0;
  margin-right: 8px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-size: 18px;
  color: var(--text-muted);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.client-overlay-save-btn:not(:disabled) {
  color: var(--accent-1);
  border-color: var(--accent-1);
}

.client-overlay-save-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.client-overlay-body {
  flex: 1;
  /* Sans ça, un enfant flex ne rétrécit jamais sous la hauteur de son
     contenu par défaut (min-height:auto implicite) : "overflow-y: auto"
     resterait sans effet dès que le contenu dépasse l'écran, le corps
     pousserait le header hors du viewport au lieu de défiler seul en
     dessous - c'est ce qui rendait le header "pas fixe" en pratique. */
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 16px;
}

/* Le fragment injecté (templates/clients/_detail_content.html) apporte son
   propre header et ses boutons "Enregistrer" par onglet, utiles pour la
   page complète mais redondants ici : l'overlay a le sien
   (.client-overlay-save-btn ci-dessus, dans .client-overlay-header). */
.client-overlay-body .client-detail-header,
.client-overlay-body .client-fiche-inline-save {
  display: none;
}

.client-overlay-loading {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 60px 0;
}

/* Aperçu des modifications en attente (machine à assigner, fichiers à
   envoyer) - injecté par static/js/client_overlay.js dans les conteneurs
   #pending-machine-preview/#pending-files-list (templates/clients/
   _detail_content.html), vides et [hidden] tant qu'aucune modification
   n'est en attente. */
.pending-change-preview {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin: 10px 0;
}

.pending-change-preview[hidden] {
  display: none;
}

.pending-change-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 12px;
  background: var(--surface);
  border: 1px dashed var(--accent-1);
  border-radius: var(--radius-sm);
  font-size: 13px;
  color: var(--text);
}

.pending-change-item button {
  background: none;
  border: none;
  color: var(--text-muted);
  cursor: pointer;
  font-size: 13px;
  text-decoration: underline;
  padding: 0;
}

.pending-change-item button:hover {
  color: var(--danger);
}

/* Document existant marqué "à supprimer" (pas encore appliqué tant que
   Enregistrer n'est pas cliqué) - cf. static/js/client_overlay.js. */
.doc-item.pending-delete {
  opacity: 0.5;
}

.doc-item.pending-delete .doc-name {
  text-decoration: line-through;
}
