:root {
  --primary: #2563eb;
  --primary-dark: #1d4ed8;
  --border: #e2e8f0;
  --bg: #f8fafc;
  --text: #1e293b;
  --muted: #64748b;
  --danger: #dc2626;
  --success: #16a34a;
  --sidebar: #151b26;
  /* Texte du menu : #9aa4b6 se lisait gris sur le fond sombre. Éclairci à
     #dfe4ec — assez clair pour se lire d'un coup d'œil, sans aller au blanc pur
     qui est réservé à l'entrée active et ne distinguerait plus rien. */
  --sidebar-soft: #dfe4ec;
  /* La nuance grise reste utile là où le texte est secondaire : le sous-titre de
     la marque, les pastilles de comptage, l'invite de recherche. */
  --sidebar-mute: #9aa4b6;
  --sidebar-line: #252d3b;
}
* { box-sizing: border-box; }
body {
  margin: 0;
  font-family: -apple-system, Segoe UI, Roboto, Arial, sans-serif;
  background: var(--bg);
  color: var(--text);
  font-size: 15px;
  display: flex;
  min-height: 100vh;
}
a { color: var(--primary); text-decoration: none; }
a:hover { text-decoration: underline; }

/* ---------- Menu latéral ---------- */
/* `body` est le conteneur flex, donc le bloc conteneur du position:sticky de la
   barre : pas de height:100% sur body, sinon il n'y a aucune distance sur
   laquelle coller et la barre défile avec la page. */
.sidebar {
  width: 236px;
  flex-shrink: 0;
  background: var(--sidebar);
  color: var(--sidebar-soft);
  display: flex;
  flex-direction: column;
  position: sticky;
  top: 0;
  height: 100vh;
}
.brand { display: flex; align-items: center; gap: 11px; padding: 20px 18px 16px; }
.brand:hover { text-decoration: none; }
.brand-mark {
  width: 30px; height: 30px; border-radius: 8px; flex-shrink: 0;
  background: linear-gradient(135deg, var(--primary), #7c3aed);
  display: grid; place-items: center;
  color: #fff; font-weight: 700; font-size: 15px;
}
.brand-name { display: block; font-weight: 600; font-size: 15.5px; color: #fff; line-height: 1.15; }
.brand-sub { display: block; font-size: 11px; color: var(--sidebar-mute); margin-top: 1px; }

/* Recherche globale, dans la barre latérale. Elle est volontairement au-dessus
   du menu : ce qu'on cherche, on le cherche avant de choisir un écran. */
.nav-recherche { padding: 0 14px 12px; }
.nav-recherche input {
  width: 100%; box-sizing: border-box; padding: 7px 10px; font-size: 13px;
  color: #fff; background: rgba(255,255,255,.08);
  border: 1px solid rgba(255,255,255,.14); border-radius: 6px;
}
.nav-recherche input::placeholder { color: var(--sidebar-mute); }
.nav-recherche input:focus {
  outline: none; background: rgba(255,255,255,.14); border-color: rgba(255,255,255,.34);
}

/* Alertes remontées en tête : ce qui réclame un geste ne doit pas dépendre de
   la longueur du menu. Des pastilles qui passent à la ligne plutôt que des
   lignes entières — deux par rangée, le bandeau coûte une trentaine de
   pixels au lieu d'une centaine. */
.nav-alertes { display: flex; flex-wrap: wrap; gap: 5px; padding: 0 14px 11px; }
.nav-alerte {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 9px; border-radius: 20px;
  font-size: 11.5px; font-weight: 500; color: #fecaca;
  background: rgba(220, 38, 38, .17); border: 1px solid rgba(220, 38, 38, .38);
}
.nav-alerte b { font-weight: 700; color: #fff; }
.nav-alerte:hover { background: var(--danger); color: #fff; text-decoration: none; }

/* Serré d'un cran : vingt entrées et cinq intertitres, chaque pixel gagné est
   une entrée de plus au-dessus de la ligne de flottaison. */
.nav { padding: 4px 12px; display: flex; flex-direction: column; gap: 1px; overflow-y: auto; }
.nav-sep {
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .07em;
  color: #8b95a7; padding: 11px 12px 4px;
}
.nav-btn, .foot-btn {
  display: flex; align-items: center; gap: 11px;
  padding: 7px 12px; border-radius: 9px;
  color: var(--sidebar-soft); font-size: 14px; font-weight: 450;
  transition: background .13s, color .13s;
}
.nav-btn svg, .foot-btn svg { width: 17px; height: 17px; flex-shrink: 0; stroke-width: 1.8; }
.nav-btn span:not(.nav-count) { flex: 1; min-width: 0; }
.nav-btn:hover, .foot-btn:hover { background: #1E2633; color: #fff; text-decoration: none; }
.nav-btn.active, .foot-btn.active { background: var(--primary); color: #fff; }
.nav-count {
  font-size: 11px; padding: 1px 7px; border-radius: 20px; min-width: 20px; text-align: center;
  background: #232C3A; color: var(--sidebar-mute);
}
.nav-btn.active .nav-count { background: rgba(255, 255, 255, .22); color: #fff; }

.sidebar-foot {
  margin-top: auto; padding: 12px; border-top: 1px solid var(--sidebar-line);
  display: flex; flex-direction: column; gap: 3px;
}
.foot-btn { font-size: 12.5px; padding: 7px 12px; }

/* ---------- Zone principale ---------- */
.main { flex: 1; min-width: 0; }
/* Largeur de travail : les écrans sont larges et les listes (clients,
   factures, relevé bancaire) portent beaucoup de colonnes — les brider à
   1100 px obligeait à faire défiler pour rien. Le document imprimé garde sa
   largeur A4 propre (.doc-paper-wrap), il n'est pas concerné. */
.container { max-width: 1600px; margin: 0 auto; padding: 24px; }

h1 { font-size: 24px; margin: 0 0 20px; }
h2 { font-size: 18px; }

.flash {
  background: #dcfce7;
  border: 1px solid #86efac;
  color: #166534;
  padding: 10px 14px;
  border-radius: 6px;
  margin-bottom: 16px;
}
/* Un refus n'est pas un succès : même bandeau, en rouge. */
.flash.erreur { background: #fee2e2; border-color: #fca5a5; color: #991b1b; }

.page-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
}

.card {
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 20px;
  margin-bottom: 20px;
}

table { width: 100%; border-collapse: collapse; }
th, td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--border); }
th { color: var(--muted); font-size: 13px; text-transform: uppercase; letter-spacing: 0.03em; }
tr:hover td { background: #f8fafc; }
td.num, th.num { text-align: right; }
/* --- Listes tenant sur une ligne par enregistrement ------------------------
   Sans « nowrap », un nom de client un peu long replie sa cellule sur trois
   hauteurs et les boutons d'action s'empilent les uns sous les autres : la
   liste devient impossible à parcourir à l'œil. Les colonnes longues sont donc
   écrêtées (nom complet en infobulle) et, si l'ensemble reste trop large, c'est
   le tableau qui défile horizontalement, pas la page. */
.table-scroll { overflow-x: auto; }
.table-liste th, .table-liste td { white-space: nowrap; padding: 8px 10px; }
.table-liste td.actions { text-align: right; }
/* Un badge de statut ne se coupe pas non plus : « Partiellement payée » se
   repliait sur deux lignes et doublait la hauteur de la ligne à lui seul. */
.table-liste .badge { white-space: nowrap; }
/* L'écrêtage porte sur un bloc interne : « text-overflow » posé directement sur
   une cellule de tableau à largeur automatique n'est pas fiable. */
.table-liste .cell-clip { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Un plafond PAR DÉFAUT, parce que sans max-width l'écrêtage ne coupe rien : la
   cellule prend la largeur de son texte, et le tableau avec. Constaté sur
   « Prix d'achat manquants » : une désignation de 229 caractères sur une seule
   ligne faisait un tableau de 3 500 px, et la colonne de saisie, tout à droite,
   était hors de l'écran — « je ne peux rien saisir ». Huit écrans posaient la
   classe sans plafond. Les plafonds par écran ci-dessous, plus spécifiques,
   gardent la main ; le texte complet reste dans l'infobulle. */
.table-liste .cell-clip { max-width: 320px; }
/* Boutons resserrés : à trois par ligne, ils décidaient à eux seuls de la
   largeur du tableau et repoussaient le reste hors de la carte. */
.table-liste .btn.small { padding: 4px 8px; font-size: 12px; }
.table-liste td.actions .btn { margin-left: 4px; }
/* La colonne des actions a été un temps collée à droite, pour rester atteignable
   sans faire défiler. Mauvaise idée : dès que le tableau dépasse la carte, une
   colonne collée ne libère pas de place, elle RECOUVRE sa voisine — la colonne
   « Documents » avait ainsi disparu sous les boutons. Le tableau défile donc
   normalement dans .table-scroll : rien n'est caché, tout est atteignable. */
.table-liste td.actions { border-left: 1px solid var(--border); }

/* En-tetes de colonne cliquables. L'en-tete garde son aspect de titre : c'est la
   fleche qui signale la colonne triee, pas une couleur de lien. */
th a.tri { color: inherit; text-decoration: none; white-space: nowrap; }
th a.tri:hover { color: var(--primary); }
th a.tri.actif { color: var(--text); }

/* --- Champs numeriques du tableau des lignes -------------------------------
   Les fleches natives avancent du pas declare (0,01) : sur un prix, une remise
   ou un taux de TVA elles ne servent a rien et le champ y perd de la place.
   Elles sont donc masquees partout, et la quantite recoit deux boutons a elle,
   qui avancent de 1. */
.lines-table input[type=number]::-webkit-outer-spin-button,
.lines-table input[type=number]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.lines-table input[type=number] { -moz-appearance: textfield; appearance: textfield; }

.qty-cell { white-space: nowrap; }
.qty-cell .qty { width: 62px; text-align: right; display: inline-block; }
.qty-pas {
  width: 24px; height: 30px; padding: 0; vertical-align: middle;
  border: 1px solid var(--border); background: #fff; border-radius: 6px;
  cursor: pointer; font-size: 15px; line-height: 1; color: var(--text);
}
.qty-pas:hover { border-color: var(--primary); color: var(--primary); }

/* --- Villes proposees d'apres le code postal -------------------------------- */
.communes-liste {
  position: absolute; z-index: 20; left: 0; right: 0; top: 100%;
  background: #fff; border: 1px solid var(--border); border-radius: 6px;
  box-shadow: 0 4px 12px rgba(0,0,0,.1); max-height: 240px; overflow-y: auto;
}
.commune-item {
  display: block; width: 100%; text-align: left; cursor: pointer;
  background: none; border: 0; border-bottom: 1px solid var(--border);
  padding: 7px 10px; font: inherit; color: inherit;
}
.commune-item:last-child { border-bottom: 0; }
.commune-item:hover, .commune-item:focus { background: var(--bg); color: var(--primary); }

/* --- Encaissement au comptoir ----------------------------------------------
   Le cas le plus frequent d'une facture reglee sur place : un bouton par mode,
   le solde entier, la date du jour. Mis en evidence parce que c'est l'action
   qu'on cherche en arrivant sur la facture qu'on vient d'editer. */
.comptoir {
  border: 1px solid #bfdbfe; background: #eff6ff; border-radius: 8px;
  padding: 12px 14px; margin-top: 16px;
}
.comptoir .titre { font-weight: bold; margin-bottom: 8px; }
.comptoir form { margin-right: 6px; }

/* Raccourcis de date d'echeance, sous le champ. */
.echeance-raccourcis { margin-top: 6px; display: flex; gap: 4px; flex-wrap: wrap; }
.echeance-raccourcis .btn { padding: 3px 7px; font-size: 12px; }

/* Liste deroulante de mode dans la liste des factures : compacte, elle ne doit
   pas doubler la largeur de la colonne d'actions. */
.mode-solder { width: auto; display: inline-block; padding: 3px 6px; font-size: 12px; }

/* --- Catalogue proposé dans la colonne Référence ---------------------------- */
.ref-liste {
  position: absolute; z-index: 30; left: 0; top: 100%; min-width: 380px;
  background: #fff; border: 1px solid var(--border); border-radius: 6px;
  box-shadow: 0 4px 12px rgba(0,0,0,.12); max-height: 260px; overflow-y: auto;
}
.ref-item {
  display: block; width: 100%; text-align: left; cursor: pointer;
  background: none; border: 0; border-bottom: 1px solid var(--border);
  padding: 6px 9px; font: inherit; font-size: 12.5px; color: inherit; white-space: nowrap;
}
.ref-item:last-child { border-bottom: 0; }
.ref-item:hover, .ref-item:focus { background: var(--bg); }
.ref-item strong { color: var(--primary); margin-right: 6px; }
/* Deux lignes par proposition : le nom, puis ce qui décide — coût, prix de
   vente, disponibilité. Un choix d'article se fait sur ces trois chiffres. */
.ref-item { white-space: normal; line-height: 1.35; }
.ref-l1 { display: block; }
.ref-l2 { display: block; font-size: 11.5px; color: var(--muted); }
.dispo-ok { color: #15803d; font-weight: 600; }
.dispo-non { color: #b45309; }

/* --- Graphiques SVG ---------------------------------------------------------
   Traces a la main, sans bibliotheque : ce projet a une seule dependance et il
   n'y a pas de raison d'en charger une de 300 Ko pour trois courbes. */
.graphe { width: 100%; height: auto; display: block; }
.graphe .grille { stroke: var(--border); stroke-width: 1; }
.graphe .axe { fill: var(--muted); font-size: 11px; font-family: inherit; }
.graphe .courbe { fill: none; stroke: var(--primary); stroke-width: 2; }
.graphe .aire { fill: var(--primary); opacity: .08; stroke: none; }
.graphe .barre-credit { fill: var(--success); }
.graphe .barre-debit { fill: var(--danger); }
.pastille { display: inline-block; width: 10px; height: 10px; border-radius: 2px; vertical-align: middle; }
.pastille.credit { background: var(--success); }
.pastille.debit { background: var(--danger); }

/* Largeurs calees pour que la liste tienne SANS defilement horizontal : la
   colonne d'actions est collee a droite, tout ce qui deborde passe dessous et
   devient invisible — c'est ce qui avait masque la colonne « Documents ». */
.table-clients .cell-nom { max-width: 200px; }
.table-clients .cell-ville { max-width: 110px; }
.table-clients .cell-email { max-width: 150px; }
.table-documents .cell-client { max-width: 380px; }
.table-banque .cell-libelle { max-width: 280px; }
/* Relevé bancaire : le formulaire de rapprochement était un bloc, il renvoyait
   donc « Écarter » à la ligne suivante et la mention « aucune correspondance »
   à celle d'avant — trois hauteurs par écriture. Tout est aligné sur une ligne.
   La colonne d'action n'est PAS collée à droite ici : la cellule porte un
   colspan, et une cellule fusionnée en position sticky se place de travers. */
.table-banque .rappro-cell { white-space: nowrap; }
.table-banque form.ecarter { display: inline-block; vertical-align: middle; margin-left: 6px; }
.table-banque .rappro-note { font-size: 12px; margin-left: 8px; }

.lines-view-table { table-layout: fixed; }
.lines-view-table td { word-wrap: break-word; overflow-wrap: break-word; }
.lines-view-table th, .lines-view-table td { padding: 8px 8px; }

/* inline-flex et non inline-block : un bouton peut porter une icône devant son
   libellé, et l'alignement vertical d'un SVG dans un inline-block est un
   nid à réglages. Sans icône, le rendu est celui d'avant. */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  background: var(--primary);
  color: #fff;
  border: none;
  padding: 9px 16px;
  border-radius: 6px;
  cursor: pointer;
  font-size: 14px;
  font-weight: 600;
}
.btn svg { width: 15px; height: 15px; flex-shrink: 0; stroke-width: 1.9; }
.btn.small svg { width: 13px; height: 13px; }
.btn:hover { background: var(--primary-dark); text-decoration: none; }
.btn.secondary { background: #fff; color: var(--text); border: 1px solid var(--border); }
.btn.secondary:hover { background: #f1f5f9; }
.btn.danger { background: var(--danger); }
.btn.danger:hover { background: #b91c1c; }
.btn.small { padding: 5px 10px; font-size: 13px; }

form label { display: block; font-weight: 600; margin-bottom: 4px; font-size: 13px; }
form .field { margin-bottom: 14px; }
input[type=text], input[type=email], input[type=tel], input[type=number], input[type=date], textarea, select {
  width: 100%;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 14px;
  font-family: inherit;
}
textarea { resize: vertical; }
.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.grid3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 16px; }
.grid4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; }
.grid5 { display: grid; grid-template-columns: repeat(5, 1fr); gap: 16px; }
/* Carte de solde bancaire : c'est le chiffre qu'on vient chercher en premier. */
.card.solde { border-color: #bfdbfe; background: #eff6ff; }
.card.solde h2 { color: #1d4ed8; }

/* --- Zone de depot d'un releve bancaire ------------------------------------ */
.depot {
  border: 2px dashed var(--border);
  border-radius: 8px;
  padding: 18px;
  text-align: center;
  transition: border-color .15s, background .15s;
}
.depot > * { display: block; margin: 4px auto; }
.depot input[type=file] { max-width: 420px; }
/* La page entiere est la cible : un fichier lache a cote ne doit pas etre
   ouvert par le navigateur a la place d'etre importe. */
body.depot-actif .depot { border-color: var(--primary); background: #eff6ff; }
.depot.depot-refus { border-color: var(--danger); background: #fef2f2; }

/* --- Pagination -------------------------------------------------------------
   Rendue au-dessus et au-dessous de la liste : sur cent lignes, remonter
   chercher le lien « suivant » est une gene inutile. */
.pagination { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin: 10px 0; }
.pagination .muted { margin-right: 8px; font-size: 13px; }

/* Aperçu "feuille A4" du document à l'écran : le contenu lui-même est stylé par
   assets/document.css, partagé avec l'impression et le PDF. */
.doc-paper-wrap {
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .06);
  padding: 10mm 8mm;
  margin: 0 auto 20px;
  max-width: 210mm;
  overflow-x: auto;
}
.chaine { padding: 12px 20px; display: flex; gap: 12px; flex-wrap: wrap; align-items: center; }
.verrou { padding: 14px 20px; background: #fffbeb; border-color: #fde68a; }

/* Fenêtre modale (ajout rapide d'un client depuis un document en cours). */
.modal-backdrop {
  position: fixed; inset: 0; z-index: 100;
  background: rgba(15, 23, 42, .45);
  display: flex; align-items: flex-start; justify-content: center;
  padding: 40px 16px; overflow-y: auto;
}
.modal-backdrop[hidden] { display: none; }
.modal {
  background: #fff; border-radius: 10px; width: 100%; max-width: 720px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, .25);
}
.modal-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 16px 20px; border-bottom: 1px solid var(--border);
}
.modal-head h2 { margin: 0; }
.modal-close {
  background: none; border: none; cursor: pointer;
  font-size: 26px; line-height: 1; color: var(--muted);
}
.modal-close:hover { color: var(--text); }
.modal-body { padding: 20px; }
.modal-foot {
  display: flex; gap: 10px;
  padding: 14px 20px; border-top: 1px solid var(--border);
}
.badge.mode-virement { background: #dbeafe; color: #1e40af; }
.badge.mode-cb { background: #ede9fe; color: #5b21b6; }
.badge.mode-cheque { background: #fef3c7; color: #92400e; }
.badge.mode-especes { background: #dcfce7; color: #166534; }
.badge.mode-autre { background: #e2e8f0; color: #475569; }
.badge.partiel { background: #fef3c7; color: #92400e; }
.badge.confirmee, .badge.livre, .badge.livree, .badge.emis { background: #dbeafe; color: #1e40af; }
.badge.facture, .badge.facturee, .badge.rembourse { background: #ede9fe; color: #5b21b6; }
.badge.annule { background: #fee2e2; color: #991b1b; }

.badge { display: inline-block; padding: 3px 10px; border-radius: 999px; font-size: 12px; font-weight: 600; }
.badge.brouillon { background: #e2e8f0; color: #475569; }
.badge.envoye, .badge.envoyee { background: #dbeafe; color: #1e40af; }
.badge.accepte, .badge.payee { background: #dcfce7; color: #166534; }
.badge.refuse, .badge.annulee { background: #fee2e2; color: #991b1b; }
.badge.converti { background: #ede9fe; color: #5b21b6; }
.badge.retard { background: #fef3c7; color: #92400e; }

.lines-table input { width: 100%; }
/* Écotaxe et copie privée partagent une cellule, l'une sous l'autre : deux
   colonnes de plus prendraient la place de la Désignation pour deux petits
   nombres, presque toujours vides. */
.lines-table .achat-col .ecotaxe, .lines-table .achat-col .copie-privee { display: block; margin: 0 0 2px; font-size: 12px; padding: 2px 4px; }
/* Désignation : une zone de texte alignée sur les inputs voisins (même padding,
   même taille), sans poignée ni ascenseur — c'est le script qui l'agrandit à la
   hauteur de son contenu. Les cellules s'alignent en haut pour qu'une
   désignation de quatre lignes garde ses quantité et prix sur la première. */
.lines-table textarea.designation {
  width: 100%; display: block; resize: none; overflow: hidden;
  min-height: 2.4em; line-height: 1.35; font-size: 14px; white-space: pre-wrap;
}
.lines-table td { padding: 6px; vertical-align: top; }
.lines-table th { padding: 6px; }
.remove-line { color: var(--danger); cursor: pointer; font-weight: 700; }
.drag-handle { cursor: grab; text-align: center; color: var(--muted); font-size: 16px; user-select: none; }
.drag-handle:active { cursor: grabbing; }
.lines-table tr.dragging { opacity: 0.4; }
.achat-col { background: #fffbeb; }
.internal-totals { background: #fffbeb; border: 1px solid #fde68a; border-radius: 6px; padding: 10px 14px; }
.internal-totals div span:first-child { color: #92400e; }

.totals { margin-left: auto; width: 280px; }
.totals div { display: flex; justify-content: space-between; padding: 6px 0; }
.totals .ttc { font-weight: 700; font-size: 17px; border-top: 2px solid var(--text); margin-top: 6px; padding-top: 10px; }

.doc-header { display: flex; justify-content: space-between; margin-bottom: 30px; }
.doc-header h1 { margin: 0; }
.muted { color: var(--muted); }
.actions-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-bottom: 20px; }
.text-right { text-align: right; }

/* Le bouton ☰ n'existe qu'à l'écran étroit. */
.nav-toggle { display: none; }

@media (max-width: 900px) {
  /* SUR UN TÉLÉPHONE : une barre en haut (marque + ☰), et le menu — le même
     qu'au bureau, libellés et groupes compris — en panneau plein écran quand
     body.menu-ouvert. La version précédente couchait la barre en bandeau
     horizontal et supprimait les libellés sous 700 px : une rangée d'icônes
     muettes, injouable au pouce. */
  body { display: block; }
  .sidebar {
    width: auto; height: auto; position: sticky; top: 0; z-index: 30;
    flex-direction: row; align-items: center; flex-wrap: wrap;
  }
  .brand { padding: 10px 14px; flex: 1; }
  .nav-toggle {
    display: inline-flex; align-items: center; gap: 8px;
    margin: 0 12px 0 0; padding: 8px 12px; border-radius: 8px;
    background: rgba(255,255,255,.08); color: #fff; border: 1px solid rgba(255,255,255,.18);
    font: inherit; font-size: 14px; cursor: pointer;
  }
  .nav-toggle-barres { display: inline-flex; flex-direction: column; gap: 3px; }
  .nav-toggle-barres i { display: block; width: 18px; height: 2px; background: currentColor; border-radius: 2px; }
  body.menu-ouvert .nav-toggle-barres i:nth-child(1) { transform: translateY(5px) rotate(45deg); }
  body.menu-ouvert .nav-toggle-barres i:nth-child(2) { opacity: 0; }
  body.menu-ouvert .nav-toggle-barres i:nth-child(3) { transform: translateY(-5px) rotate(-45deg); }
  /* Le panneau : caché, puis toute la hauteur sous la barre quand il est ouvert.
     Il défile lui-même, le fond ne bouge pas. */
  .nav-panneau { display: none; flex-basis: 100%; }
  body.menu-ouvert .nav-panneau {
    display: flex; flex-direction: column;
    position: fixed; left: 0; right: 0; top: 52px; bottom: 0; z-index: 29;
    background: var(--sidebar); overflow-y: auto; -webkit-overflow-scrolling: touch;
    padding-bottom: 24px;
  }
  body.menu-ouvert { overflow: hidden; }
  body.mode-demo.menu-ouvert .nav-panneau { top: 89px; }
  .nav { overflow: visible; padding: 4px 12px; }
  .nav-btn { padding: 11px 12px; font-size: 15px; }
  .sidebar-foot { margin-top: 12px; }
  /* Le contenu : marges réduites, les listes défilent horizontalement. */
  .container { padding: 12px; }
  h1 { font-size: 20px; }
  .card { padding: 14px; }
  /* Un tableau ne sait pas défiler seul : c'est sa carte qui défile, sinon
     c'est la page entière qui s'élargit (mesuré : 646 px pour 378 sur le
     tableau de bord) et le menu part avec elle. */
  .card, .table-scroll, .doc-paper-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .card > table, .card .table-scroll > table { min-width: max-content; }
  /* Les petits formulaires en ligne (période du/au, recherche) passent à la
     ligne au lieu de dépasser, et un champ de recherche prend la largeur. */
  form[style*="display:flex"] { flex-wrap: wrap; }
  form[style*="display:flex"] input[type="search"], form[style*="display:flex"] input[type="text"] { flex: 1 1 160px; min-width: 0; }
  /* La feuille du document garde sa largeur A4 et défile dans son cadre :
     réduite à 360 px elle devenait illisible. */
  .doc-paper { min-width: 210mm; }
  .actions-bar .btn { margin-bottom: 4px; }
}
@media (max-width: 700px) {
  .grid2, .grid3, .grid4, .grid5 { grid-template-columns: 1fr; }
}

@media print {
  /* L'impression navigateur doit rendre exactement la même feuille que le PDF :
     on neutralise toute la chrome de l'appli et on laisse assets/document.css
     piloter le contenu. */
  @page { size: A4; margin: 10mm 8mm; }
  .noprint { display: none !important; }
  /* body est en flex pour le menu latéral : à l'impression le menu disparaît,
     on repasse en flux normal pour que la feuille occupe toute la largeur. */
  body { background: #fff; font-size: 11px; display: block; min-height: 0; }
  .main { flex: none; }
  .container { max-width: 100%; padding: 0; margin: 0; }
  .card { border: none; padding: 0; margin-bottom: 8px; }
  h1 { font-size: 18px; margin: 0 0 8px; }
  .doc-paper-wrap {
    border: none;
    border-radius: 0;
    box-shadow: none;
    padding: 0;
    margin: 0;
    max-width: none;
    overflow: visible;
  }
  /* Les aplats gris des en-têtes de tableau doivent survivre à l'impression. */
  .doc-paper th, .doc-paper .doc-totaux td.lib {
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }
  .doc-lignes tr, .doc-paper table { page-break-inside: auto; }
  .doc-lignes tr { page-break-inside: avoid; }
}

/* Pastille d'alerte du menu (relances dues). */
.nav-count.hot { background: var(--danger); color: #fff; }

/* Taux de TVA verrouillé par un régime exonéré (UE, export). */
.lines-table input.exonere { background: #f1f5f9; color: var(--muted); }

/* Ligne de rapprochement bancaire : les champs restent sur une seule ligne. */
/* Rapprochement bancaire : tout sur une ligne. La règle précédente était un
   bloc en « flex-wrap: wrap » avec une marge basse : les contrôles passaient à
   la ligne, « Écarter » se retrouvait en dessous, et chaque écriture de relevé
   occupait trois hauteurs. Une seule déclaration ici — deux règles superposées
   laissaient « flex-wrap » de l'ancienne survivre à la nouvelle. */
form.rapprochement {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex-wrap: nowrap;
  vertical-align: middle;
  margin: 0;
}
/* La liste se contente de sa largeur utile : un <select> écrête son texte, il
   ne le replie pas, donc le limiter ne cache rien qu'on ne puisse dérouler. */
form.rapprochement select { width: auto; max-width: 300px; }

/* Note de reprise de numérotation : justifie un saut de série au contrôle. */
.note-reprise {
  background: #eff6ff; border: 1px solid #bfdbfe; border-radius: 8px;
  padding: 14px 18px; margin-bottom: 16px;
}
.note-reprise p { margin: 6px 0 0; font-size: 13.5px; }

/* ---------- Mode démonstration ----------
   Volontairement impossible à manquer : saisir un vrai devis dans la base de
   démonstration (ou l'inverse) est l'erreur que ce bandeau doit empêcher. */
.bandeau-demo {
  position: fixed; top: 0; left: 0; right: 0; z-index: 200;
  background: #b45309; color: #fff;
  padding: 8px 16px; font-size: 13.5px; font-weight: 600;
  display: flex; align-items: center; justify-content: center; gap: 14px;
}
.bandeau-demo button {
  background: rgba(255, 255, 255, .18); color: #fff;
  border: 1px solid rgba(255, 255, 255, .5); border-radius: 5px;
  padding: 3px 10px; font: inherit; font-size: 12.5px; cursor: pointer;
}
.bandeau-demo button:hover { background: rgba(255, 255, 255, .3); }
body.mode-demo { padding-top: 37px; }
body.mode-demo .sidebar { top: 37px; height: calc(100vh - 37px); }
@media (max-width: 900px) { body.mode-demo .sidebar { height: auto; } }
.demo-tag {
  display: block; margin: 0 12px 8px; padding: 4px 10px; border-radius: 6px;
  background: #b45309; color: #fff; font-size: 11px; font-weight: 700;
  letter-spacing: .06em; text-align: center;
}
.demo-tag:hover { background: #92400e; color: #fff; text-decoration: none; }


/* --- Recherche d'entreprise (annuaire Sirene) ------------------------------- */
.reche-bloc.encadre { border: 1px solid var(--border); border-radius: 6px; padding: 10px; margin-bottom: 14px; }
.reche-ligne { display: flex; gap: 8px; align-items: center; }
.reche-ligne input { flex: 1; }
.reche-resultats { margin-top: 10px; max-height: 320px; overflow-y: auto; }
/* Chaque résultat est un <button> : cliquable au clavier comme à la souris, et
   type="button" pour ne pas soumettre le formulaire qui l'entoure. */
.reche-item {
  display: block; width: 100%; text-align: left; cursor: pointer;
  background: #fff; border: 1px solid var(--border); border-radius: 6px;
  padding: 8px 10px; margin-bottom: 6px; font: inherit; color: inherit;
}
.reche-item:hover, .reche-item:focus { border-color: var(--primary); background: var(--bg); }
.reche-item strong { display: block; font-size: 14px; }
.reche-item span { display: block; font-size: 12px; color: var(--muted); margin-top: 2px; }
.reche-erreur { color: #991b1b; font-size: 13px; margin: 4px 0 0; }


/* --- Le gabarit papier n'hérite pas du thème de l'application ---------------
   assets/document.css apporte tous les filets du document imprimé. Les règles
   génériques de tableau ci-dessus (bordure basse, remplissage, en-têtes gris en
   majuscules, survol) s'y appliquaient aussi à l'écran et à l'impression
   navigateur, alors que le PDF, qui n'inline que document.css, en est exempt :
   d'où des traits parasites sous le bloc émetteur et dans le cadre du
   destinataire, et des libellés de colonnes qui ne ressemblaient pas au PDF.
   document.css étant chargé APRÈS, ses règles de même spécificité l'emportent
   sur cette remise à zéro — elle ne neutralise donc que ce qu'il ne définit pas. */
.doc-paper th, .doc-paper td { border-bottom: none; padding: 0; text-align: left; }
.doc-paper th { color: inherit; font-size: inherit; text-transform: none; letter-spacing: normal; }
.doc-paper tr:hover td { background: transparent; }

/* Le papier du TICKET a exactement le même besoin, et pour la même raison : il
   s'affiche maintenant à l'intérieur de l'application (l'aperçu de la caisse)
   alors qu'il s'imprime seul depuis ticket.php. Sans cette remise à zéro, le
   même ticket porterait des filets sous chaque ligne à l'écran et aucun sur le
   rouleau — deux tickets, ce qu'on cherche justement à éviter. */
.ticket-papier th, .ticket-papier td { border-bottom: none; text-align: left; }
.ticket-papier tr:hover td { background: transparent; }

/* --- Caisse tactile --------------------------------------------------------
   Présentation d'une caisse de magasin et non d'un formulaire : le total domine
   l'écran, le ticket est à gauche, le pavé et les articles à droite, les
   paiements en bas. Devant un client qui attend, on vise une case au doigt. */
.caisse { display: block; }
.caisse-total {
  background: #0f172a; color: #fff; border-radius: 10px;
  padding: 14px 22px; margin-bottom: 12px; text-align: right; position: relative;
  /* Dix pixels repris sur le retrait de la page. La caisse est le seul écran
     qui doit tenir en entier sans défiler, et elle n'a pas de titre au-dessus :
     le bandeau est le premier élément, rien ne peut le chevaucher. Le retrait
     de .container reste à 24 px pour tous les autres écrans, où il sert. */
  margin-top: -10px;
}
.caisse-total-lib {
  position: absolute; left: 22px; top: 40px;
  font-size: 13px; letter-spacing: 1.5px; color: #94a3b8;
}
.caisse-horloge {
  position: absolute; left: 22px; top: 16px;
  font-size: 13px; color: #cbd5e1; text-transform: capitalize;
}
.caisse-mail { margin-bottom: 10px; }
.caisse-mail input {
  width: 100%; box-sizing: border-box; padding: 8px 11px; font-size: 13px;
  border: 1px solid var(--border); border-radius: 8px;
}
.caisse-total-val { font-size: 58px; font-weight: 700; line-height: 1.05; font-variant-numeric: tabular-nums; }
.caisse-total-tva { font-size: 12.5px; color: #94a3b8; margin-top: 2px; }

.caisse-corps { display: flex; gap: 12px; align-items: flex-start; }
.caisse-ticket {
  flex: 1 1 0; min-width: 0; background: #fff;
  border: 1px solid var(--border); border-radius: 10px; padding: 12px;
}
.caisse-droite { flex: 0 0 430px; }

.caisse-scan { position: relative; }
.caisse-scan input {
  width: 100%; box-sizing: border-box; font-size: 17px; padding: 10px 12px;
  border: 2px solid var(--primary); border-radius: 8px;
}
/* Propositions sous la case de scan : même liste que la colonne Réf. du devis,
   à la largeur de la case. `.actif` est la ligne visée aux flèches. */
.caisse-scan .ref-liste { width: 100%; min-width: 0; max-height: 340px; font-size: 13px; }
.caisse-scan .ref-item.actif { background: var(--bg); }
.caisse-etat { font-size: 12px; color: var(--muted); margin: 6px 2px 10px; min-height: 16px; }

.caisse-lignes { width: 100%; border-collapse: collapse; }
.caisse-lignes td { border: 0; border-bottom: 1px solid var(--border); padding: 9px 6px; vertical-align: middle; }
.caisse-ligne { cursor: pointer; }
.caisse-ligne.active { background: #eff6ff; box-shadow: inset 3px 0 0 var(--primary); }
/* LE LIBELLÉ TOMBE SUR LE CHIFFRE, PAS SUR LE BORD DE LA CELLULE. La valeur
   n'est pas écrite dans le <td> : elle est dans un champ qui ajoute sa bordure
   et son propre padding. Le texte commence donc 14 px après le bord (6 de la
   cellule + 1 de bordure + 7 du champ), et un en-tête calé à 7 px paraissait
   décalé d'une demi-lettre sur toute la largeur du ticket. */
.caisse-lignes thead th {
  border: 0; border-bottom: 1px solid var(--border);
  font-size: 11px; letter-spacing: .6px; text-transform: uppercase;
  color: var(--muted); text-align: right; padding: 0 14px 6px;
}
.caisse-lignes thead th:first-child { text-align: left; }
/* Un en-tête s'aligne comme sa colonne : Qté et TVA sont centrés dans le
   champ, leur titre doit l'être aussi. */
.caisse-lignes thead th.l-qte,
.caisse-lignes thead th.l-tva { text-align: center; }
.caisse-lignes .l-qte { width: 70px; }
.caisse-lignes .l-pa  { width: 100px; }
.caisse-lignes .l-pu  { width: 100px; }
.caisse-lignes .l-tva { width: 62px; }
.caisse-lignes .d { display: block; width: 100%; box-sizing: border-box; font-weight: 600; font-size: 14.5px; }
.caisse-lignes .r { display: block; width: 100%; box-sizing: border-box; font-size: 11.5px; color: var(--muted); }
/* Quantité et prix restent des champs : au comptoir on corrige un prix au
   clavier aussi souvent qu'au pavé, et un chiffre qu'on ne peut pas cliquer se
   lit comme un chiffre figé. */
.caisse-lignes .d, .caisse-lignes .r,
.caisse-lignes .q, .caisse-lignes .p, .caisse-lignes .t, .caisse-lignes .pa {
  width: 100%; box-sizing: border-box; text-align: right;
  font-size: 16px; font-variant-numeric: tabular-nums;
  padding: 5px 7px; border: 1px solid transparent; border-radius: 6px;
  background: transparent; color: inherit;
}
.caisse-lignes .q, .caisse-lignes .t { text-align: center; }
.caisse-lignes .d, .caisse-lignes .r { text-align: left; }
.caisse-lignes input:hover { border-color: var(--border); }
.caisse-lignes input:focus { outline: none; background: #fff; border-color: var(--primary); }
.caisse-lignes .d::placeholder { color: #94a3b8; font-weight: 400; }
.caisse-lignes .l-tot { width: 110px; text-align: right; font-size: 17px; font-weight: 700; white-space: nowrap; }
.caisse-vide { color: var(--muted); text-align: center; padding: 26px 0; margin: 0; }

/* --- Caisse : onglets Saisie / Aperçu ----------------------------------------
   Le scan et l'e-mail restent au-dessus : on bascule la zone de saisie, pas
   l'écran. Deux onglets et pas une case à cocher, parce que les deux vues
   occupent la même place et qu'aucune n'est un réglage de l'autre. */
/* La saisie et le papier CÔTE À CÔTE. Ils ont d'abord été deux onglets à
   basculer ; regarder le ticket se construire pendant qu'on scanne suppose de
   voir les deux, sinon il faut choisir entre saisir et vérifier — et on ne
   vérifie plus.
   Le retour à la ligne est la sécurité : quand la largeur ne permet pas les
   deux, le papier passe SOUS le tableau au lieu de l'écraser. La saisie garde
   un plancher de 460 px, en dessous duquel ses six colonnes deviennent
   illisibles ; c'est ce plancher qui déclenche le passage à la ligne. */
.caisse-panneaux { display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-start; }
.caisse-pan-saisie { flex: 1 1 460px; min-width: 460px; }
.caisse-pan-apercu { flex: 0 1 auto; }
/* Le papier est posé sur un fond gris : sur du blanc on ne verrait pas où le
   ticket s'arrête, et c'est justement sa largeur qu'on veut juger. Le débord
   défile dans le cadre plutôt que d'allonger la page — les boutons de paiement
   doivent rester à leur place, un client attend devant. */
.caisse-apercu {
  background: #f1f5f9; border-radius: 8px; padding: 14px 0;
  max-height: 62vh; overflow-y: auto;
}
.caisse-apercu .ticket-papier {
  padding: 4mm 3mm; box-shadow: 0 1px 6px rgba(15, 23, 42, .18);
}

.caisse-saisie {
  display: flex; justify-content: space-between; align-items: baseline;
  background: #fff; border: 1px solid var(--border); border-radius: 8px;
  padding: 8px 14px; margin-bottom: 10px;
}
.caisse-saisie-lib { font-size: 12px; letter-spacing: 1px; color: var(--muted); text-transform: uppercase; }
.caisse-saisie-val { font-size: 28px; font-weight: 700; font-variant-numeric: tabular-nums; }

.caisse-pave { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
.tpad {
  font-size: 24px; font-weight: 600; padding: 16px 0; cursor: pointer;
  background: #fff; color: #0f172a;
  border: 1px solid var(--border); border-radius: 10px;
  box-shadow: 0 1px 0 rgba(15,23,42,.08);
}
.tpad:hover { background: var(--bg); }
.tpad:active { transform: translateY(1px); }
.tpad.act { font-size: 14px; background: #f1f5f9; }
.tpad.efface { font-size: 22px; color: #b91c1c; }
.tpad.sup { font-size: 13px; color: #b91c1c; }

/* Touches d'articles : LE CATALOGUE NE DOIT JAMAIS POUSSER LES BOUTONS DE
   PAIEMENT HORS DE L'ÉCRAN. Elles occupaient toute la hauteur qu'il leur fallait
   — quinze articles, cinq rangées — et « Carte bancaire » / « Espèces »
   tombaient sous la ligne de flottaison : il fallait faire défiler la page pour
   encaisser, avec un client devant soi.
   Deux réponses, et la seconde est la seule qui tienne dans le temps : les
   touches sont plus compactes, et surtout leur zone est PLAFONNÉE et défile
   toute seule. Réduire la police aurait gagné un écran et se serait recassé au
   vingt-cinquième article. */
.caisse-touches {
  display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px;
  max-height: 184px; overflow-y: auto;
}
.touche {
  flex: 1 1 112px; min-width: 112px; text-align: left; cursor: pointer;
  background: #fff; border: 1px solid var(--border); border-radius: 8px; padding: 6px 9px;
}
.touche:hover { background: var(--bg); }
/* Une seule ligne chacune : un nom qui passe à la ligne double la hauteur de
   toute la rangée, et c'est ce qui faisait déborder la colonne. */
.touche-ref { display: block; font-weight: 700; font-size: 12px; color: var(--primary); }
.touche-nom {
  display: block; font-size: 11.5px; color: var(--muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* Les boutons de paiement sont EMPILÉS, chacun sur toute la largeur de la
   colonne. Ils étaient côte à côte parce qu'ils occupaient toute la page ; dans
   une colonne de 430 px, « CARTE BANCAIRE » à trois par rangée ne tient pas et
   se casserait en deux lignes. Empilés, ce sont deux barres qu'on ne peut pas
   manquer du doigt — ce que doit être un bouton d'encaissement. */
.caisse-pied { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.caisse-payer {
  flex: 1 1 100%; font-size: 21px; font-weight: 700; letter-spacing: .5px;
  color: #fff; border: 0; border-radius: 10px; padding: 18px 10px; cursor: pointer;
}
.caisse-payer.cb { background: #1d4ed8; }
.caisse-payer.especes { background: #15803d; }
.caisse-payer:hover { filter: brightness(1.08); }
.caisse-annuler {
  flex: 1 1 100%; font-size: 14px; cursor: pointer; padding: 9px;
  background: #fff; color: #b91c1c;
  border: 1px solid #fecaca; border-radius: 10px;
}

/* Écran étroit : le pavé passe sous le ticket plutôt que de l'écraser. */
@media (max-width: 1100px) {
  .caisse-corps { flex-direction: column; }
  .caisse-droite { flex: 1 1 auto; width: 100%; }
  .caisse-total-val { font-size: 44px; }
}

/* ÉCRAN PEU HAUT : la caisse doit tenir SANS DÉFILER. C'est la seule règle du
   projet qui regarde la hauteur de la fenêtre, et c'est ici qu'elle se justifie :
   sur un portable 1366×768, la bannière du total, le pavé et les touches
   suffisaient à repousser les boutons de paiement sous le bord de l'écran. Ce
   qui rétrécit est ce qu'on LIT (le total, les chiffres du pavé) ; ce qu'on
   VISE reste grand — les deux boutons de paiement gardent leur taille, ils sont
   la cible que le doigt cherche en dernier et le client attend. */
@media (max-height: 900px) {
  .caisse-total { padding: 10px 18px; }
  .caisse-total-val { font-size: 40px; }
  /* L'heure et le libellé sont posés en absolu dans la bannière : ils doivent
     suivre son retrait, sinon ils flottent à côté de leur bord. */
  .caisse-horloge { top: 12px; left: 18px; }
  .caisse-total-lib { top: 34px; left: 18px; }
  .tpad { font-size: 20px; padding: 11px 0; }
  .caisse-touches { max-height: 132px; }
  .caisse-payer { padding: 16px 10px; font-size: 20px; }
  .caisse-apercu { max-height: 46vh; }
}
@media (max-height: 760px) {
  .caisse-total-val { font-size: 32px; }
  .tpad { font-size: 18px; padding: 8px 0; }
  .caisse-touches { max-height: 96px; }
  .caisse-payer { padding: 13px 10px; font-size: 18px; }
}

/* Barre de marge des graphiques : même famille que les barres bancaires. */
.barre-marge { fill: #7c3aed; }

/* Choix du type de client : deux cibles larges plutôt qu'une liste déroulante.
   Le geste est plus court, et surtout la réponse est visible sans dérouler. */
/* « modifications non enregistrées » : visible sans être alarmant — rien n'est
   perdu tant qu'on est sur la page, c'est en partant que ça le devient. */
.pastille-non-enregistre {
  display: inline-block; margin-left: 10px; padding: 3px 10px;
  font-size: 12.5px; border-radius: 20px;
  background: #fffbeb; border: 1px solid #fde68a; color: #92400e;
}

/* Marge négative sur un document en cours : signalé là où on regarde déjà les
   totaux, jamais sur le document imprimé — c'est une information interne. */
/* Quantité d'achat qui ne suit pas la quantité vendue : souligné, jamais
   refusé — vendre par lot ce qu'on achète à l'unité est courant. */
.qte-discordante { border-color: #f59e0b !important; background: #fffbeb; }

.alerte-marge {
  margin-top: 10px; padding: 10px 14px; border-radius: 8px; font-size: 13.5px;
  background: #fef2f2; border: 1px solid #fecaca; color: #7f1d1d;
}

.choix-type { display: flex; gap: 12px; flex-wrap: wrap; }
.choix-type label {
  flex: 1 1 260px; cursor: pointer; padding: 12px 16px;
  border: 2px solid var(--border); border-radius: 10px; background: #fff;
}
.choix-type label:hover { border-color: #94a3b8; }
.choix-type label.actif { border-color: var(--primary); background: #eff6ff; }
.choix-type label strong { display: block; font-size: 16px; margin-bottom: 2px; }
.choix-type label span { display: block; font-size: 12.5px; color: var(--muted); }
.choix-type input { margin-right: 8px; }

.prix-liste {
  width: 88px; text-align: right; font-variant-numeric: tabular-nums;
  padding: 4px 6px; border: 1px solid transparent; border-radius: 6px; background: transparent;
}
.prix-liste:hover { border-color: var(--border); }
.prix-liste:focus { outline: none; background: #fff; border-color: var(--primary); }

/* Avertissement de doublon client : visible sans être alarmant — c'est un
   signalement, pas une erreur, et la création reste toujours possible. */
.doublon-alerte {
  margin-top: 6px; padding: 8px 11px; font-size: 13px;
  background: #fffbeb; border: 1px solid #fde68a; border-radius: 7px;
}
.doublon-alerte ul { list-style: disc; }
.doublon-alerte a { font-weight: 600; }

/* Encaissement en plusieurs fois : ce qui a été pris, et ce qui reste. */
/* Le bandeau du reste vit dans la colonne de droite, au-dessus des boutons de
   paiement : le geste est « je tape un montant, je vois ce qui reste, j'appuie
   sur un mode », et il se lit de haut en bas sans traverser l'écran.
   TOUT SUR UNE LIGNE : le montant à saisir à gauche, le reste en face à droite.
   La première version renvoyait le reste à la ligne suivante — trois lignes de
   bandeau pour deux nombres, et c'est cette hauteur-là qui faisait défiler la
   page. La liste des encaissements pris ne prend sa propre ligne que lorsqu'il
   y en a : vide, elle ne pèse rien. */
.caisse-reste {
  display: flex; align-items: center; gap: 6px 10px; flex-wrap: wrap;
  background: #0f172a; color: #fff; border-radius: 10px; padding: 7px 12px; margin-top: 10px;
}
.caisse-reste label { font-size: 12.5px; color: #94a3b8; letter-spacing: .3px; }
.caisse-reste input {
  width: 104px; font-size: 19px; font-weight: 700; text-align: right;
  font-variant-numeric: tabular-nums; padding: 4px 8px; border-radius: 8px;
  border: 1px solid rgba(255,255,255,.25); background: rgba(255,255,255,.1); color: #fff;
}
.caisse-reste input:focus { outline: none; background: #fff; color: #0f172a; border-color: #fff; }
/* La liste des encaissements déjà pris passe à la ligne QUAND elle existe, et
   pas avant : une base de 100 % la ferait exister vide et couperait la ligne en
   deux pour rien. */
.caisse-reste-liste { display: flex; gap: 8px; flex-wrap: wrap; }
.caisse-reste-liste:not(:empty) { flex-basis: 100%; }
.caisse-reste .pmt {
  background: rgba(255,255,255,.12); border-radius: 999px; padding: 4px 10px; font-size: 13.5px;
}
.caisse-reste .pmt button {
  background: none; border: 0; color: #fca5a5; cursor: pointer; font-size: 15px; padding: 0 0 0 4px;
}
.caisse-reste-val { margin-left: auto; font-size: 13px; white-space: nowrap; }
.caisse-reste-val span { font-size: 21px; font-weight: 700; margin-left: 6px; }
/* Le rendu prend sa propre ligne, en ambre, dès que la somme tapée dépasse le
   reste : c'est le chiffre qu'on lit en ouvrant le tiroir, il ne se partage pas
   une ligne avec le reste dû. « sur 50,00 € reçus » rappelle d'où il vient. */
.caisse-rendu { flex-basis: 100%; text-align: right; color: #fbbf24; font-size: 13px; white-space: nowrap; }
.caisse-rendu span { font-size: 21px; font-weight: 700; margin-left: 6px; }
.caisse-rendu small { font-size: 12px; font-weight: 400; color: #fcd34d; margin-left: 4px; }
.caisse-reste-aide { flex-basis: 100%; font-size: 11px; color: #94a3b8; }

/* Compte connecté, en pied de barre latérale. Séparé d'un filet du reste des
   réglages : ce bloc parle de QUI est devant l'écran, pas de l'application. */
.sidebar-compte {
  margin-top: .6rem;
  padding-top: .6rem;
  border-top: 1px solid rgba(255,255,255,.12);
}

/* --- Choix du client par recherche -------------------------------------------
   Le conteneur doit être positionné : la liste des propositions est en absolute
   et se placerait sinon par rapport à la page entière. */
.client-choix { position: relative; }
.client-choix input { width: 100%; }
.client-choix .ref-liste { min-width: 100%; }
/* Message d'absence de résultat, ou liste tronquée : ce n'est pas un choix
   cliquable, donc ni bordure ni survol. */
.ref-vide { padding: 8px 9px; font-size: 12px; color: var(--muted); line-height: 1.35; }

/* --- Caisse : colonne des prix d'achat, révélée à la demande ------------------
   Visible par défaut (une colonne cachée ne se remplit jamais) ; la case la
   masque quand l'écran de caisse fait face à un client. */
.caisse-pa-bascule {
  display: flex; align-items: center; gap: .5rem;
  font-size: 12.5px; color: var(--muted); margin: 0 0 .4rem;
}
.caisse-pa-bascule input { width: auto; margin: 0; }
.caisse-marge { margin-left: auto; font-weight: 600; color: var(--ink); }
/* Le prix d'achat est un champ du ticket COMME LES AUTRES : il est décrit avec
   eux plus haut (.d .r .q .p .t .pa), et plus ici. Il en était absent, donc il
   gardait l'apparence native du navigateur — encadré, plus petit, large de
   5,5 rem dans une colonne sans largeur — et ne tombait sous son titre à
   aucune ligne. */

/* ------------------------------------------------------------------
   Carte repliable (<details class="card card-repliable">)

   Le <details> natif plutôt qu'un accordéon en JavaScript : la flèche,
   l'ouverture au clavier (Entrée/Espace) et l'annonce aux lecteurs
   d'écran sont déjà là, et une page de réglages n'a pas besoin d'un
   script pour se plier. On ne redessine que le marqueur, parce que
   celui du navigateur ne s'aligne pas avec un <h2>.
   ------------------------------------------------------------------ */
details.card-repliable { padding-top: 0; padding-bottom: 0; }
details.card-repliable > summary {
  list-style: none;            /* Firefox */
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 14px 0;
  user-select: none;
}
details.card-repliable > summary::-webkit-details-marker { display: none; }
details.card-repliable > summary::before {
  content: '';
  width: 0; height: 0;
  border-left: 6px solid currentColor;
  border-top: 5px solid transparent;
  border-bottom: 5px solid transparent;
  opacity: .55;
  transition: transform .15s ease;
  flex: none;
}
details.card-repliable[open] > summary::before { transform: rotate(90deg); }
details.card-repliable > summary:hover::before { opacity: 1; }
details.card-repliable > summary h2 { margin: 0; }
details.card-repliable > :last-child { margin-bottom: 16px; }

/* La ligne qu'on vient de traiter, sur les listes où l'action la fait sortir
   du filtre. Elle est ramenée à l'écran par une ancre ; encore faut-il la
   retrouver des yeux une fois arrivé. Le liseré s'efface tout seul : c'est un
   repère pour la seconde qui suit, pas un état. */
tr.ligne-agie > td { background: #ecfdf5; box-shadow: inset 3px 0 0 #10b981; }
@media (prefers-reduced-motion: no-preference) {
  tr.ligne-agie > td { animation: ligne-agie-fondu 2.5s ease-out 1s forwards; }
  @keyframes ligne-agie-fondu { to { background: transparent; box-shadow: none; } }
}

/* Case « hors remise » sous le champ de remise d'une ligne : discrète, car elle
   ne sert qu'à l'écotaxe et aux débours, mais lisible — c'est elle qui décide
   qu'un montant échappe à la remise globale. */
label.hors-remise {
  display: flex;
  align-items: center;
  gap: 3px;
  font-size: 10px;
  line-height: 1.1;
  color: #6b7280;
  margin-top: 3px;
  cursor: pointer;
}
/* Le texte s'enroule sur deux lignes courtes au lieu d'élargir la colonne :
   la table des lignes n'a que trois largeurs imposées, tout le reste se règle
   sur son contenu — un libellé insécable de 11 px suffisait à tout décaler. */
label.hors-remise > span { display: block; }
label.hors-remise input { margin: 0; flex: none; }
td.cell-remise { width: 86px; }
td.cell-remise input.remise { width: 100%; box-sizing: border-box; }
td.cell-remise input.remise[readonly] { background: #f3f4f6; color: #9ca3af; }

/* Prix d'une ligne masquée : grisé, jamais effacé. Le champ garde sa valeur —
   décocher la case la retrouve intacte — mais son aspect dit qu'elle ne compte
   pas dans les totaux pour l'instant. */
input.pu-masque {
  background: #f3f4f6;
  color: #9ca3af;
  text-decoration: line-through;
}

/* Quantité d'achat : la colonne la plus étroite de la table des lignes. Elle ne
   reçoit qu'un petit entier — presque toujours la même valeur que la quantité
   vendue — alors que la Désignation, elle, manque toujours de place. La largeur
   est imposée sur la cellule ET sur l'en-tête, sinon le titre la rouvre. */
.lines-table th.col-qte-achat,
.lines-table td.col-qte-achat { width: 58px; }
.lines-table td.col-qte-achat input { padding-left: 4px; padding-right: 4px; }

/* Pied du tableau du ticket : les totaux de colonne. Le trait au-dessus les
   sépare des lignes, et la graisse dit que ce ne sont plus des articles. */
.caisse-lignes tfoot td {
  border-top: 2px solid #d1d5db;
  font-weight: 600;
  padding-top: 6px;
  /* Même retrait que l'en-tête, et pour la même raison : le total doit tomber
     sous les chiffres de sa colonne, qui sont écrits dans un champ. */
  padding-left: 14px; padding-right: 14px;
}
.caisse-lignes tfoot td.num { text-align: right; }

/* Version du logiciel, tout en bas de la barre. Discrète par construction : on
   ne la lit que le jour où quelqu'un la demande. */
.sidebar-version {
  padding: 8px 12px 2px;
  font-size: 10.5px;
  color: #6b7488;
  letter-spacing: .02em;
}

/* Mise à jour disponible : dans le bandeau des alertes, mais en bleu. Elle
   demande un geste, pas dans la journée — le rouge reste à ce qui ne peut pas
   attendre. */
.nav-alerte.info {
  color: #bfdbfe;
  background: rgba(37, 99, 235, .18);
  border-color: rgba(37, 99, 235, .40);
}
.nav-alerte.info:hover { background: var(--primary); color: #fff; }

/* --- Guide d'utilisation (aide.php) -------------------------------------------
   Une seule page longue : sommaire collant à gauche, sections à droite. Le
   texte courant est borné à ~75 caractères, la largeur qui se lit. */
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.aide-layout { display: grid; grid-template-columns: 250px minmax(0, 1fr); gap: 24px; align-items: start; }
.aide-sommaire { position: sticky; top: 16px; display: flex; flex-direction: column; gap: 2px; font-size: 13.5px; }
.aide-sommaire a { color: var(--text); padding: 4px 8px; border-radius: 4px; }
.aide-sommaire a:hover { background: #fff; color: var(--primary); }
.aide-groupe { font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); margin: 12px 8px 4px; }
.aide-recherche { display: flex; gap: 6px; margin-bottom: 6px; }
.aide-recherche input { flex: 1; min-width: 0; }
.aide-section { scroll-margin-top: 16px; }
.aide-section h2 { font-size: 20px; margin: 0 0 4px; }
.aide-section h3 { font-size: 15px; margin: 22px 0 6px; }
.aide-fil { font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
.aide-resume { color: var(--muted); font-size: 15px; margin: 0 0 14px; max-width: 75ch; }
.aide-section p, .aide-section li { max-width: 75ch; line-height: 1.55; }
.aide-section ul, .aide-section ol { padding-left: 1.3em; margin: 6px 0 12px; }
.aide-section li { margin: 4px 0; }
.aide-section blockquote { margin: 10px 0 14px; padding: 8px 14px; border-left: 3px solid var(--primary); background: var(--bg); max-width: 75ch; }
.aide-section code { background: var(--bg); border: 1px solid var(--border); border-radius: 3px; padding: 0 4px; font-size: 13px; }
.aide-section hr { border: 0; border-top: 1px solid var(--border); margin: 18px 0; }
.aide-resultat { padding: 10px 0; border-bottom: 1px solid var(--border); }
.aide-resultat:last-child { border-bottom: 0; }
.aide-extrait { color: var(--muted); font-size: 14px; margin-top: 3px; max-width: 80ch; }
.aide-extrait mark { background: #fef08a; color: inherit; padding: 0 1px; }
@media (max-width: 900px) { .aide-layout { grid-template-columns: 1fr; } .aide-sommaire { position: static; } }
@media print { .aide-section { break-inside: avoid; border: 0; padding: 0 0 12px; } .aide-layout { display: block; } }
.aide-figure { margin: 14px 0 18px; max-width: 900px; }
.aide-figure img { display: block; width: 100%; height: auto; border: 1px solid var(--border); border-radius: 6px; background: #fff; }
.aide-figure figcaption { font-size: 13px; color: var(--muted); margin-top: 6px; max-width: 75ch; }
/* Factures fournisseurs : l'état d'une pièce chez le comptable, sur sa ligne. */
.etat-comptable.ok { color: var(--success); font-weight: 600; }
.etat-comptable.attente { color: #9a6200; font-weight: 600; }
.etat-comptable.muted { color: var(--muted); }
/* Caisse : le refus d'encaisser (ticket vide) se lit sous les boutons de paiement, là où on vient de cliquer. */
.caisse-payer-etat { margin-top: 8px; color: var(--danger); font-weight: 600; font-size: 14px; text-align: center; }

/* --- Clavier : un anneau de focus visible partout où l'on peut agir --------
   Le navigateur en dessine un par défaut, mais plusieurs champs le retiraient
   (outline: none) et les boutons du pavé, des touches d'article et de paiement
   n'en avaient aucun stylé. :focus-visible ne s'affiche qu'à la navigation au
   clavier, jamais au clic. */
a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible,
textarea:focus-visible, [tabindex]:focus-visible, summary:focus-visible {
  outline: 2px solid var(--primary); outline-offset: 2px;
}
.caisse-payer:focus-visible, .tpad:focus-visible, .touche:focus-visible { outline: 3px solid #fbbf24; outline-offset: 2px; }
/* La croix de suppression est un vrai bouton : atteignable au clavier, nommé
   pour un lecteur d'écran, sans l'habillage d'un bouton. */
button.remove-line { background: none; border: 0; padding: 2px 6px; font: inherit; font-weight: 700; color: var(--danger); cursor: pointer; }
.drag-handle:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
