: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; overflow-wrap: anywhere; }
/* Le logo de l'entreprise en vignette : fond blanc, il est fait pour le papier. */
.brand-mark.brand-logo { background: #fff; width: auto; min-width: 30px; max-width: 64px; height: 34px; padding: 3px 4px; }
.brand-mark.brand-logo img { max-width: 56px; max-height: 28px; display: block; }
.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; }
/* La copie destinée à la barre du téléphone : invisible au bureau, où le
   bandeau de la colonne est déjà sous les yeux. */
.nav-alertes.alertes-barre { display: none; }
.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. */
/* min-height: 0 — sans lui un enfant flex ne rétrécit jamais sous la hauteur
   de son contenu, et overflow-y: auto ne sert à rien : le menu, devenu plus
   haut qu'un écran de portable avec le groupe Bâtiment, dépassait du fond
   sombre de la barre (hauteur 100vh) et ses dernières entrées s'écrivaient en
   blanc sur blanc (« le menu est blanc après Remises en banque », 21/09/2026 —
   une page courte, donc rien ne masquait le débordement). Le menu défile
   maintenant dans la barre, le pied reste visible. */
/* Le panneau qui enveloppe recherche, alertes, menu et pied est lui-même un
   enfant flex de la barre : il doit pouvoir rétrécir (min-height: 0) pour que
   le menu à l'intérieur défile. Sur écran étroit la règle @media le remplace. */
.nav-panneau { display: flex; flex-direction: column; min-height: 0; flex: 1 1 auto; }
.nav { padding: 4px 6px 4px 12px; display: flex; flex-direction: column; gap: 1px; overflow-y: auto; min-height: 0; flex: 1 1 auto; scrollbar-width: thin; scrollbar-color: #3a4358 transparent; }
/* Les titres de groupe (Vendre, Encaisser…) se lisaient mal : 10,5 px gris
   sur fond sombre (« les menus comme Encaisser ne sont pas trop visibles »,
   29/09/2026). Plus grands, en gras, plus clairs, avec un filet de couleur
   qui sépare les blocs. Un séparateur sans titre reste un simple espace. */
.nav-sep {
  font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: .08em;
  color: #e2e8f0; padding: 9px 12px 5px; margin-top: 10px;
  border-top: 1px solid #334155; position: relative;
}
.nav-sep::before {
  content: ''; position: absolute; left: 12px; top: -1px; width: 28px; height: 2px;
  background: #60a5fa; border-radius: 2px;
}
.nav-sep:empty { border-top: 0; padding: 0; margin-top: 8px; }
.nav-sep:empty::before { display: none; }
.nav > .nav-sep:first-child { margin-top: 2px; }
.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; }
/* Favoris du menu (assets/menu.js) : l'étoile n'apparaît qu'au survol, sauf
   sur une entrée déjà favorite ; sur un écran tactile, elle reste visible. */
.nav-etoile { margin-left: 4px; background: none; border: 0; padding: 0 2px; font-size: 14px; line-height: 1;
  color: var(--sidebar-mute); cursor: pointer; opacity: 0; flex-shrink: 0; }
.nav-btn:hover .nav-etoile, .nav-etoile:focus-visible, .nav-etoile.actif { opacity: 1; }
.nav-etoile.actif { color: #f5b301; }
.nav-favoris .nav-etoile { opacity: 0; }
.nav-favoris .nav-btn:hover .nav-etoile { opacity: 1; }
@media (hover: none) { .nav-etoile { opacity: .55; } .nav-etoile.actif { opacity: 1; } }
.nav-recherche { position: relative; }
.nav-ecrans { position: absolute; left: 14px; right: 14px; top: 100%; z-index: 40; background: #fff; color: var(--text);
  border-radius: 6px; box-shadow: 0 6px 18px rgba(0,0,0,.25); overflow: hidden; margin-top: -8px; }
.nav-ecran { padding: 7px 10px; font-size: 13px; cursor: pointer; }
.nav-ecran.sel, .nav-ecran:hover { background: var(--primary); color: #fff; }
.nav-ecran.chercher { border-top: 1px solid var(--border); color: var(--muted); }
.nav-ecran.chercher.sel, .nav-ecran.chercher:hover { 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: min(440px, 60vh); overflow-y: auto;
}
.ref-pied { position: sticky; bottom: 0; background: var(--bg); font-size: 12px; padding: 6px 9px; color: var(--muted); border-top: 1px solid var(--border); }
.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; }

/* La police du PDF, servie à l'écran : la pagination du papier est calculée
   avec les métriques de DejaVu Sans (includes/document_mesure.php), et un
   écran composé en Arial s'enroulerait autrement — le pied ne tomberait plus
   où le PDF le met. Les fichiers viennent de dompdf (licence Bitstream Vera,
   libre), copiés dans assets/ parce que vendor/ est interdit par le .htaccess. */
@font-face {
  font-family: "DejaVu Sans";
  src: url("fonts/DejaVuSans.ttf") format("truetype");
  font-weight: normal; font-style: normal;
}
@font-face {
  font-family: "DejaVu Sans";
  src: url("fonts/DejaVuSans-Bold.ttf") format("truetype");
  font-weight: bold; font-style: normal;
}

/* 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. Chaque page du
   papier (.doc-page) est une feuille ; à l'écran elles sont séparées d'un
   pointillé, à l'impression le saut de page fait le travail. */
.doc-paper-wrap .doc-page { min-height: 277mm; }
.doc-paper-wrap .doc-page-suite {
  border-bottom: 2px dashed #cbd5e1;
  padding-bottom: 10mm;
  margin-bottom: 10mm;
}
.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; }
/* Encart « Facture électronique » sans plateforme raccordée (document_view.php). */
.chaine-grisee { opacity: .55; filter: grayscale(1); }
.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.creditee { background: #ede9fe; color: #5b21b6; }
.badge.converti { background: #ede9fe; color: #5b21b6; }
.badge.retard { background: #fef3c7; color: #92400e; }

.lines-table input { width: 100%; }
/* Le taux de TVA est une liste fermée (écran « Taux de TVA ») : même largeur que le champ qu’il remplace. */
.lines-table select.tva { width: 100%; min-width: 66px; }
/* Unité de la ligne (module bâtiment) : sous les boutons de quantité, étroite. */
.lines-table select.unite { display: block; width: 100%; margin-top: 3px; font-size: 12px; padding: 2px 4px; }
/* É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; }
.carte-interne { background: repeating-linear-gradient(135deg, #fafafa 0 10px, #f3f4f6 10px 20px); border-style: dashed; }
.carte-interne h2 { color: #6b7280; }
.carte-interne-avert { font-size: 13px; margin-top: 0; color: #92400e; background: #fffbeb; border-left: 3px solid #f59e0b; padding: 6px 10px; border-radius: 4px; }
.carte-interne .internal-totals span:last-child { color: #6b7280; }
.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; }

/* « screen and » : Chrome évalue la largeur d'une feuille A4 à ~730 px, et ces
   règles de téléphone s'appliquaient à l'IMPRESSION — la feuille recevait
   min-width: 210mm dans 194 mm utiles, et la colonne des totaux sortait du
   papier (DE0001030, 21/09/2026 : « à partir de Total HT on ne voit pas les
   sommes »). Le papier imprimé suit les règles de bureau, puis @media print. */
@media screen and (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. */
  /* LA COPIE DU BANDEAU D'ALERTES, dans la barre du haut. Au bureau elle
     n'existe pas (le bandeau de la colonne suffit) ; ici elle est la SEULE
     visible, le bandeau de la colonne étant dans le panneau caché. Elle
     s'efface quand le panneau s'ouvre, pour ne pas s'afficher en double. */
  .nav-alertes.alertes-barre { display: flex; flex-basis: 100%; padding: 0 14px 10px; }
  body.menu-ouvert .nav-alertes.alertes-barre { display: none; }
  .nav-panneau { display: none; flex-basis: 100%; }
  /* LE MENU OUVERT FIGE LA PAGE (24/09/2026). « overflow: hidden » sur body ne
     suffisait pas : Safari iOS l'ignore, le doigt faisait défiler le tableau de
     bord DERRIÈRE le menu, la barre partait avec lui et le menu restait figé —
     capture de l'utilisateur. La page est donc posée en position fixe pendant
     l'ouverture (le script retient sa position de défilement et la rend à la
     fermeture), la barre reste fixe en haut, le panneau se cale sous elle
     (--barre-haut, mesurée) et `overscroll-behavior: contain` empêche son
     défilement de se propager une fois en bout de liste. */
  body.menu-ouvert .nav-panneau {
    display: flex; flex-direction: column;
    position: fixed; left: 0; right: 0; top: var(--barre-haut, 52px); bottom: 0; z-index: 29;
    background: var(--sidebar); overflow-y: auto; -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain; touch-action: pan-y;
    padding-bottom: calc(24px + env(safe-area-inset-bottom, 0px));
  }
  body.menu-ouvert { overflow: hidden; position: fixed; left: 0; right: 0; width: 100%; }
  body.menu-ouvert .sidebar { position: fixed; left: 0; right: 0; }
  /* Le bas de la barre mesuré (--barre-haut) tient déjà compte du bandeau de démonstration. */
  /* Dans le panneau, le menu prend sa hauteur entière et c'est le panneau
     qui défile : le « min-height: 0 / flex: 1 » du bureau (menu qui défile
     dans une barre de 100vh) l'écrasait ici à zéro et ses entrées passaient
     par-dessus le pied — « des lignes se chevauchent » sur l'iPhone. */
  .nav { overflow: visible; padding: 4px 12px; min-height: auto; flex: 0 0 auto; }
  .nav-panneau { min-height: auto; flex: 0 0 auto; }
  .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 screen and (max-width: 700px) {
  /* TÉLÉPHONE : la page ne glisse jamais latéralement. Ce qui est plus large
     que l'écran (un tableau, la feuille A4) défile dans SON cadre ; le reste
     est ramené à la largeur. Sans cette règle, un seul pixel qui dépasse —
     et iOS en trouve toujours un — fait bouger toute la page sous le pouce. */
  /* Même raison qu'au-dessous : `overflow-x: hidden` fait du corps une zone de
     défilement — qui ne défile pas, puisque c'est la fenêtre qui défile — et
     tout `position: sticky` à l'intérieur cesse d'accrocher. C'est ce qui
     laissait le total de la caisse et la barre du menu s'échapper vers le
     haut. `clip` découpe pareil sans créer de zone ; `hidden` reste écrit
     avant, pour les navigateurs qui ignorent `clip` — c'est lui qui empêche
     Safari iOS de faire glisser la page entière. */
  html, body { overflow-x: hidden; overflow-x: clip; max-width: 100%; }
  /* SAFARI iOS n'obéit pas au overflow-x de la page : il laisse glisser dès
     qu'un élément dépasse d'un pixel. Ce qui tient sur iOS, c'est le clip posé
     sur le BLOC de contenu lui-même, et la barre du haut. Le panneau du menu
     est en position:fixed, un overflow d'ancêtre ne le coupe pas. */
  /* ⚠️ `overflow-x: hidden` CRÉE UNE ZONE DE DÉFILEMENT, et une zone de
     défilement qui ne défile pas neutralise tout `position: sticky` à
     l'intérieur : le total de la caisse, collé sous la barre, s'échappait
     quand même (mesuré à −276 px). `clip` découpe exactement pareil SANS créer
     de zone, donc sticky fonctionne. Les deux déclarations sont écrites à la
     suite : un navigateur qui ignore `clip` garde `hidden` et son découpage —
     c'est lui qui empêche Safari iOS de faire glisser toute la page. */
  .main { overflow-x: hidden; overflow-x: clip; max-width: 100vw; }
  .sidebar { overflow-x: hidden; max-width: 100vw; }
  .main > .container { max-width: 100%; }
  /* iOS gonfle le texte des tableaux et des blocs en paysage : non. */
  html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
  img, svg, video, iframe, input, select, textarea { max-width: 100%; }
  /* Les champs de date de Safari sont plus larges que ceux de Chrome. */
  input[type="date"], input[type="number"] { min-width: 0; width: auto; }
  input[type="search"], input[type="text"], input[type="email"] { min-width: 0; }
  /* 16 PX DANS TOUS LES CHAMPS, SUR TÉLÉPHONE (24/09/2026). Safari iOS ZOOME
     sur un champ dont le texte fait moins de 16 px dès qu'on le touche, et la
     page RESTE zoomée : « c'est coupé à droite, obligé de redimensionner » —
     capture de la liste des clients après un appui dans la recherche, barre du
     haut coupée comprise, ce qui trahissait un zoom et non un débordement.
     Les champs étaient à 14 px (et moins dans le tableau des lignes). Plutôt
     que d'interdire le zoom (maximum-scale), qui empêcherait aussi d'agrandir
     pour lire, on donne aux champs la taille qui ne le déclenche pas. Le
     sélecteur pèse assez lourd pour passer devant les tailles propres à un
     écran (unités, lignes de pièces). */
  input:not([type="checkbox"]):not([type="radio"]):not([type="submit"]):not([type="button"]):not([type="hidden"]),
  select, textarea, .lines-table select.unite, .lines-table td input, .lines-table td select, .lines-table td textarea { font-size: 16px; }
  .muted, p, li, td { overflow-wrap: anywhere; }
  .card td, .card th { overflow-wrap: normal; }
  /* Les chiffres du tableau de bord deux par ligne : une carte par ligne
     faisait défiler quatre écrans de blanc avant la première action. */
  .grid2, .grid3, .grid4, .grid5 { grid-template-columns: 1fr 1fr; gap: 8px; }
  .grid2 > .card, .grid3 > .card, .grid4 > .card, .grid5 > .card { padding: 12px; }
  /* Une case de grille ne descend pas sous la largeur de son contenu : un
     champ fichier ou nombre poussait sa colonne hors de l'écran (fiche
     article, notes de frais, présentation — relevés à 390 px le 25/09/2026). */
  .grid2 > *, .grid3 > *, .grid4 > *, .grid5 > *, .presentation > * { min-width: 0; }
  .grid2 .field input, .grid3 .field input, .grid4 .field input, .grid5 .field input,
  .grid2 .field select, .grid3 .field select, .grid4 .field select, .grid5 .field select { max-width: 100%; min-width: 0; }
  .grid2 > .card h2, .grid3 > .card h2, .grid4 > .card h2, .grid5 > .card h2 { font-size: 17px; margin: 4px 0 0; }
  .grid2 > .card .muted, .grid3 > .card .muted, .grid4 > .card .muted, .grid5 > .card .muted { font-size: 12px; }
  /* En-tête de page : le titre sur sa ligne, les boutons dessous, à la
     largeur du pouce. */
  .page-header { flex-direction: column; align-items: stretch; gap: 8px; }
  .page-header h1 { margin-bottom: 4px; }
  .actions-bar { gap: 6px; }
  .btn { padding: 9px 12px; }
  .container { padding: 10px; }
  .card { padding: 12px; margin-bottom: 10px; }
  table { font-size: 13px; }
}

@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; }
  /* Sur la fiche d'une pièce, SEULE la feuille s'imprime : les cartes qui
     l'entourent (chaîne, règlements, bandeau d'encaissement) sont masquées
     même sans noprint — un bloc ajouté sans y penser ne poussera plus la
     facture sur deux pages. */
  body.page-document .main > .container > :not(.doc-paper-wrap) { 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; }
  .doc-paper-wrap .doc-page { min-height: 0; }
  .doc-paper-wrap .doc-page-suite { border-bottom: none; padding-bottom: 0; margin-bottom: 0; }
  /* Mêmes marges que le PDF (document_pdf.php) : la pagination du papier est
     calculée pour 549,9 × 785,2 pt utiles ; avec les marges par défaut du
     navigateur (≈ 1 cm) le contenu déborderait d'une page. */
  @page { size: A4; margin: 10mm 8mm; }
}

/* 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, .lines-table select.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); }
/* La hauteur réservée est celle du bandeau MESURÉE (--bandeau-h, posée par
   includes/header.php) : fixée à 37 px, elle valait une ligne, et sur un écran
   étroit le texte de la démonstration en prenait deux ou trois — le bandeau
   recouvrait alors la barre du haut et le menu. 37 px reste le repli sans JS. */
body.mode-demo { padding-top: var(--bandeau-h, 37px); }
/* Installation gelée (déménagée ailleurs) : même bandeau, en rouge, et le
   texte porte l'adresse où l'on travaille désormais. */
.bandeau-gelee { background: #b91c1c; }
.bandeau-publique { background: #1d4ed8; }
.bandeau-publique a { color: #fff; text-decoration: underline; margin-left: 6px; }
/* Sur téléphone, le bandeau tient en une ligne : l'explication s'efface, le
   nom de la démonstration et la visite guidée restent. */
@media screen and (max-width: 700px) {
  .bandeau-demo { font-size: 12.5px; padding: 6px 10px; gap: 8px; }
  .bandeau-publique .bandeau-detail { display: none; }
}
.bandeau-gelee a { color: #fff; text-decoration: underline; }
body.mode-gelee { padding-top: var(--bandeau-h, 37px); }
body.mode-gelee .sidebar { top: var(--bandeau-h, 37px); height: calc(100vh - var(--bandeau-h, 37px)); }
@media screen and (max-width: 900px) { body.mode-gelee .sidebar { height: auto; } }
body.mode-demo .sidebar { top: var(--bandeau-h, 37px); height: calc(100vh - var(--bandeau-h, 37px)); }
@media screen and (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, .caisse-lignes select:hover { border-color: var(--border); }
.caisse-lignes input:focus, .caisse-lignes select:focus { outline: none; background: #fff; border-color: var(--primary); }
/* Le taux est une liste fermée : même allure que les champs, flèche comprise. */
.caisse-lignes select.t { padding: 5px 2px; text-align-last: center; cursor: pointer; }
.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 screen and (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; }
/* ------------------------------------------------------------------
   Adresses de livraison de la fiche client (14/10/2026) : une ligne par
   adresse, le formulaire déplié sous sa ligne au clic. <details name=…> :
   une seule ouverte à la fois là où le navigateur le sait, plusieurs
   ailleurs, sans conséquence. Sur téléphone la ligne devient une carte.
   ------------------------------------------------------------------ */
.liv-liste { border: 1px solid var(--border); border-radius: 8px; overflow: hidden; margin-bottom: 12px; }
.liv-liste:empty { display: none; }
.liv-item + .liv-item { border-top: 1px solid var(--border); }
.liv-ligne {
  list-style: none;
  display: grid;
  grid-template-columns: 18px minmax(140px, 1.2fr) minmax(160px, 2fr) minmax(90px, 1fr) auto;
  gap: 12px;
  align-items: center;
  padding: 10px 12px;
  cursor: pointer;
  font-size: 14px;
}
.liv-ligne::-webkit-details-marker { display: none; }
.liv-ligne:hover { background: #f8fafc; }
.liv-item[open] > .liv-ligne { background: #eef3ff; }
.liv-defaut { color: #d97706; font-size: 15px; }
.liv-libelle { font-weight: 600; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.liv-libelle .muted { font-weight: normal; }
.liv-adresse, .liv-contact { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.liv-fermer { display: none; }
.liv-item[open] .liv-ouvrir { display: none; }
.liv-item[open] .liv-fermer { display: inline; }
.liv-detail { margin: 0; border: 0; border-top: 1px solid var(--border); border-radius: 0; background: #f8fafc; box-shadow: none; }
.liv-inactives { margin-bottom: 12px; }
.liv-inactives > summary { cursor: pointer; color: var(--muted); font-size: 13px; padding: 4px 0 8px; }
.liv-ajout > summary { list-style: none; display: inline-block; margin-bottom: 10px; }
.liv-ajout > summary::-webkit-details-marker { display: none; }
.liv-ajout[open] > summary { display: none; }
@media (max-width: 700px) {
  .liv-ligne { grid-template-columns: 18px 1fr auto; grid-template-areas: "d l b" ". a a" ". c c"; row-gap: 2px; }
  .liv-defaut { grid-area: d; } .liv-libelle { grid-area: l; } .liv-modifier { grid-area: b; }
  .liv-adresse { grid-area: a; white-space: normal; } .liv-contact { grid-area: c; }
  .liv-contact:empty { display: none; }
}


/* 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; }
/* Une case à cocher garde SA taille. `.lines-table input { width: 100% }` vise
   les champs de saisie et attrapait aussi les cases : Chrome l'ignore pour une
   case, Safari iOS l'applique — la case s'étalait sur la largeur de la cellule
   et recouvrait le libellé voisin (« H☐s remise », capture de l'utilisateur,
   24/09/2026). */
.lines-table input[type="checkbox"] { width: 14px; height: 14px; min-width: 14px; flex: 0 0 auto; }
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 screen and (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; } }
/* Mode d'emploi : un chapitre à la fois, écran seulement (script de mode_emploi.php). */
@media screen { .me-un-chapitre .aide-contenu .aide-section:not(.active) { display: none; } }
.aide-sommaire a.actif { background: #fff; color: var(--primary); font-weight: 600; }
/* Le sommaire du guide est plus haut que l'écran : collé, il défile dans son
   propre cadre, et la recherche reste en tête, visible quelle que soit la
   section ouverte (« on ne voit plus Chercher »). */
@media screen and (min-width: 901px) {
  .aide-sommaire { max-height: calc(100vh - 32px); overflow-y: auto; scrollbar-width: thin; }
  .aide-sommaire .aide-recherche { position: sticky; top: 0; z-index: 1; background: var(--bg); padding-bottom: 6px; }
  .me-un-chapitre .aide-suite { display: flex; justify-content: space-between; gap: 8px; margin-top: 20px; flex-wrap: wrap; }
}
.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; }

/* === LA PIÈCE SUR UN TÉLÉPHONE (document_view.php) ========================
   La feuille A4 ne DÉBORDE plus depuis septembre, mais elle n'est pas lisible
   pour autant : un cadre à six colonnes réduit à 390 px se parcourt en
   balayant, et le montant qu'on vient chercher est hors de l'écran. Ce bloc
   décide donc ce qu'un téléphone MONTRE : le numéro, le client, les dates, les
   totaux, et les lignes repliées.

   Deux règles de portée, et elles comptent :
   · `screen and` : l'impression a sa propre largeur, et sans ce mot une
     impression depuis un téléphone remplacerait la feuille par cette fiche —
     c'est-à-dire imprimerait autre chose que ce que le client reçoit ;
   · rien de tout cela n'est dans assets/document.css, que Dompdf lit et qui ne
     connaît pas @media : le papier n'est pas touché, il est seulement caché. */
.piece-mobile { display: none; }

@media screen and (max-width: 900px) {
  .piece-mobile { display: block; margin-bottom: 14px; }
  /* La feuille reste là, à un bouton : on la montre pour vérifier ce qui
     partira, et elle disparaît de nouveau au clic suivant. */
  .doc-paper-wrap { display: none; }
  body.voir-feuille .doc-paper-wrap { display: block; }

  .pm-tete { display: flex; justify-content: space-between; align-items: flex-start;
             gap: 10px; padding: 12px 14px; background: var(--card, #fff);
             border: 1px solid var(--border); border-radius: 10px 10px 0 0; }
  .pm-numero { font-size: 20px; font-weight: 700; line-height: 1.2; }
  .pm-type { font-size: 12px; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }

  .pm-client, .pm-dates { padding: 10px 14px; background: var(--card, #fff);
                          border: 1px solid var(--border); border-top: 0; }
  .pm-client strong { font-size: 16px; }
  .pm-client .btn { margin-top: 8px; margin-right: 6px; }
  .pm-dates { display: flex; flex-wrap: wrap; gap: 4px 16px; font-size: 13px; color: var(--muted); }

  /* Les totaux en liste de définitions : une ligne par chiffre, le libellé à
     gauche et le montant à droite, alignés — ce qu'un tableau faisait, sans le
     défilement latéral. */
  .pm-totaux { margin: 0; padding: 10px 14px; background: var(--card, #fff);
               border: 1px solid var(--border); border-top: 0; }
  .pm-totaux > div { display: flex; justify-content: space-between; align-items: baseline;
                     gap: 12px; padding: 4px 0; }
  .pm-totaux dt { color: var(--muted); font-size: 13px; margin: 0; }
  .pm-totaux dd { margin: 0; font-variant-numeric: tabular-nums; white-space: nowrap; }
  .pm-totaux .fort { border-top: 1px solid var(--border); margin-top: 4px; padding-top: 8px; }
  .pm-totaux .fort dt, .pm-totaux .fort dd { font-weight: 700; font-size: 16px; color: inherit; }
  /* Le reste dû est le chiffre qu'on vient chercher : il est le plus gros. */
  .pm-du { border-top: 1px solid var(--border); margin-top: 4px; padding-top: 8px !important; }
  .pm-du dt { font-weight: 600; font-size: 14px !important; color: inherit !important; }
  .pm-du dd { font-size: 22px; font-weight: 700; }
  .pm-du.attente dt, .pm-du.attente dd { color: var(--danger); }
  .pm-du.solde dt, .pm-du.solde dd { color: #15803d; }

  .pm-lignes { background: var(--card, #fff); border: 1px solid var(--border); border-top: 0; }
  .pm-lignes > summary { padding: 12px 14px; cursor: pointer; font-weight: 600; }
  /* Une ligne est un BLOC, pas un rang de tableau : la désignation sur toute la
     largeur, les chiffres dessous. */
  .pm-ligne { padding: 10px 14px; border-top: 1px solid var(--border); }
  .pm-ligne.section { font-weight: 600; background: #f8fafc; }
  .pm-ref { font-size: 11.5px; color: var(--muted); font-variant-numeric: tabular-nums; }
  .pm-desi { margin: 2px 0 6px; }
  .pm-chiffres { display: flex; justify-content: space-between; gap: 12px;
                 font-size: 13px; color: var(--muted); font-variant-numeric: tabular-nums; }
  .pm-chiffres strong { color: inherit; font-size: 15px; }

  #pmFeuille { display: block; width: 100%; margin-top: 10px;
               border-radius: 0 0 10px 10px; }
}

/* === LE TABLEAU DE BORD SUR UN TÉLÉPHONE (index.php) ======================
   On sort le téléphone pour une question : où en est-on ? Au bureau, sept
   compteurs de documents en tête ne coûtent rien — tout tient dans l'écran.
   Sur 390 px ils occupent la première page entière, et le solde bancaire est
   sous le pli. Le HTML est le même ; seul l'ordre change. */
@media screen and (max-width: 900px) {
  .tb { display: flex; flex-direction: column; }
  /* 1. L'argent : solde, encaissé, reste dû. La réponse à la question. */
  .tb-argent { order: 1; }
  /* 2. Le rappel du soir, quand il y a lieu. */
  .tb-soir { order: 2; }
  /* 3. Ce qui vient de se passer. */
  .tb-recents { order: 3; }
  /* 4. Créer : utile, mais on crée rarement depuis un téléphone. */
  .tb-actions { order: 4; }
  /* 5. Les compteurs, en dernier et en petit : ils se consultent, ils
        n'appellent aucun geste. Deux par rangée plutôt que trois, sinon
        « Bons de livraison » se coupe en trois lignes. */
  .tb-compteurs { order: 5; grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .tb-compteurs .card { padding: 10px 12px; }
  .tb-compteurs h2 { font-size: 20px; margin: 2px 0 0; }
  .tb-compteurs .muted { font-size: 12px; }

  /* Les trois cartes d'argent l'une sous l'autre, le solde en premier et en
     grand : c'est le chiffre qu'on vient lire. */
  .tb-argent { grid-template-columns: 1fr; }
  .tb-argent h2 { font-size: 26px; }

  /* Les boutons de création : pleine largeur, empilés — une rangée de cinq
     boutons sur 390 px donne cinq demi-mots. */
  .tb-actions { flex-direction: column; align-items: stretch; }
  .tb-actions .btn { width: 100%; text-align: center; }

  /* Reste propre au tableau de bord : le montant en haut à droite de la carte,
     en face du numéro — c'est le couple qu'on lit. */
  .table-recents .rec-numero { padding-right: 110px; }
  .table-recents .rec-ttc { position: absolute; top: 10px; right: 12px;
                            display: block; font-weight: 700; font-size: 15px; }
  .table-recents .rec-ttc::before { content: none; }
  .table-recents tr { position: relative; }
}

/* Un numéro de téléphone et une adresse e-mail sont des liens partout, mais au
   bureau ils doivent se lire comme du texte : une liste de clients bleue et
   soulignée sur deux colonnes serait illisible. Le lien reste, l'habillage non. */
.lien-tel { color: inherit; text-decoration: none; }
.lien-tel:hover { text-decoration: underline; }

/* Le bloc « appeler / écrire / itinéraire » de la fiche client n'existe que
   sur un téléphone : au bureau on décroche son poste, et on ne part pas en
   camion depuis son écran. */
.fiche-contact { display: none; }

/* === LES CLIENTS SUR UN TÉLÉPHONE ========================================= */
@media screen and (max-width: 900px) {

  /* --- La fiche : les trois gestes en tête -------------------------------- */
  .fiche-contact {
    display: block; background: var(--card, #fff); border: 1px solid var(--border);
    border-radius: 10px; padding: 12px 14px; margin-bottom: 12px;
  }
  .fc-nom { font-size: 18px; font-weight: 700; }
  .fc-adresse { font-size: 13px; margin-top: 2px; }
  .fc-boutons { display: flex; flex-direction: column; gap: 6px; margin-top: 10px; }
  .fc-boutons .btn { width: 100%; text-align: center; }

  /* Reste propre aux clients : le téléphone plus gros que le reste (c'est ce
     qu'on vient chercher), et les identifiants professionnels laissés de côté
     — on ne lit pas un SIRET debout, et la fiche complète est à un doigt sur
     le nom. Ce n'est pas cacher une part d'un total, c'est résumer. */
  .table-clients .cli-tel { font-size: 15px; color: inherit; margin-top: 4px; }
  .table-clients .cli-identifiants { display: none; }
}

/* === SAISIR UNE PIÈCE SUR UN TÉLÉPHONE (document_form.php) ================
   C'est l'écran le plus difficile des quatre, et la décision est de NE PAS
   TOUCHER AU DOM. Deux raisons, qui ne se négocient pas :
   · l'ordre des lignes dans le DOM au moment de l'envoi devient l'ordre
     enregistré (`ordre`), et les champs partent en tableaux parallèles —
     déplacer une cellule, c'est décaler une pièce ;
   · recalc(), la lecture du code-barres, la ligne de synthèse, le
     glisser-déposer et les flèches ↑ ↓ interrogent tous les cellules PAR
     CLASSE. Un second balisage pour le téléphone aurait été un second écran de
     saisie à tenir en accord avec le premier, sur le formulaire le plus
     chargé de l'application.

   Donc : le même tableau, replié en cartes par le CSS. Chaque ligne devient une
   carte à quatre étages — référence et croix, désignation en pleine largeur,
   puis quantité × prix = montant, puis le reste en petit. `order` replace les
   cellules à l'écran sans les bouger dans le document. */
@media screen and (max-width: 900px) {
  .lines-table, .lines-table tbody, .lines-table tr, .lines-table td { display: block; }
  /* ⚠️ `.card > table { min-width: max-content }` — la règle de septembre qui
     fait DÉFILER un tableau dans sa carte — s'applique aussi à celui-ci et le
     forçait à 1719 px : les cartes étaient bien construites, et toutes hors de
     l'écran. Un tableau qu'on replie n'est plus un tableau qu'on fait défiler.
     Mesuré, pas deviné : la ligne faisait 1719 px dans une carte de 465. */
  .card > .lines-table { min-width: 0; }
  .lines-table { border: 0; }
  /* Plus de colonnes, donc plus d'en-têtes : la première rangée est celle des
     titres (ce tableau n'a pas de <thead>). */
  .lines-table > tbody > tr:first-child, .lines-table > tr:first-child { display: none; }

  .lines-table tr {
    display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
    border: 1px solid var(--border); border-radius: 10px;
    padding: 8px 10px; margin-bottom: 8px; background: var(--card, #fff);
  }
  .lines-table td { border: 0; padding: 0; }
  .lines-table td[data-libelle]::before {
    content: attr(data-libelle); display: block;
    color: var(--muted); font-size: 11px; line-height: 1.4;
  }

  /* --- Étage 1 : poignée, référence, croix ------------------------------- */
  .lines-table .drag-handle { order: 1; flex: 0 0 auto; cursor: grab; opacity: .55; }
  .lines-table .ref-cell    { order: 2; flex: 1 1 auto; min-width: 0; }
  .lines-table .del-cell    { order: 3; flex: 0 0 auto; }
  .lines-table .del-cell .remove-line { font-size: 20px; padding: 4px 8px; }

  /* --- Étage 2 : la désignation, sur toute la largeur -------------------- */
  .lines-table .desi-cell { order: 4; flex: 1 0 100%; }

  /* --- Étage 3 : ce qu'on tape et ce que ça fait ------------------------- */
  .lines-table .qty-cell   { order: 5; flex: 0 0 auto; display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }
  .lines-table .pu-cell    { order: 6; flex: 1 1 90px; min-width: 0; }
  .lines-table .line-total { order: 7; flex: 0 0 auto; margin-left: auto;
                             font-weight: 700; font-variant-numeric: tabular-nums; }
  .lines-table .line-total::before { content: none; }

  /* --- Étage 4 : le reste, en petit et replié --------------------------- */
  .lines-table .tva-cell,
  .lines-table .cell-remise,
  .lines-table .achat-col { order: 8; flex: 0 1 auto; font-size: 12px; }
  .lines-table .cell-remise { flex: 1 0 100%; display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
  .lines-table .achat-col { padding: 2px 4px; border-radius: 6px; }

  /* Les champs prennent la largeur qu'on leur donne, pas celle du tableau. */
  .lines-table input[type="number"], .lines-table input[type="text"],
  .lines-table select, .lines-table textarea { width: 100%; box-sizing: border-box; }
  .lines-table td .qty { width: 64px; text-align: center; }
  /* `td.cell-remise input.remise { width: 100% }` pèse (0,2,2) : il fallait
     au moins autant pour le ramener à sa taille. Mesuré à 417 px dans une
     carte de 439 — un « 5,00 » au milieu d'un champ vide. */
  /* Le taux est une liste (« 5,5 % », « 20 % ») : à 62 px Safari coupait
     « 20 % » derrière sa flèche. */
  .lines-table td .tva { width: 92px; }
  .lines-table td.cell-remise input.remise { width: 72px; }
  /* La case et son mot restent ensemble : séparés, on coche « prix masqué »
     en croyant cocher « hors remise ». */
  /* Le libellé de cette cellule est un `::before`, donc un ÉLÉMENT FLEX comme
     les autres : il se mettait en ligne avec le champ et les deux cases, et la
     cellule débordait de 35 px à la largeur d'un iPhone (345 dans 310). On lui
     donne sa ligne. Mesuré à 390 et 375 px, les deux largeurs qui existent. */
  .lines-table td.cell-remise::before { flex: 1 0 100%; }
  .lines-table td.cell-remise label.hors-remise {
    display: inline-flex; align-items: center; gap: 6px; white-space: nowrap;
    font-size: 13px; color: #374151; margin: 6px 16px 0 0; min-height: 32px;
  }
  /* Au doigt : une case de 20 px, et le libellé cliquable avec elle. */
  .lines-table td.cell-remise label.hors-remise input[type="checkbox"] {
    width: 20px; height: 20px; min-width: 20px;
  }
  .lines-table td .qte-achat, .lines-table td .achat,
  .lines-table td .ecotaxe, .lines-table td .copie-privee { width: 72px; }
  /* Une cible de doigt : 44 px est la règle, et un pas de quantité qu'on
     manque est une quantité fausse. */
  .lines-table .qty-pas { min-width: 40px; min-height: 40px; font-size: 18px; }
  /* La poignée de déplacement au doigt est illusoire ; les flèches ↑ ↓ du
     clavier restent, et l'ordre se corrige au bureau. On la laisse visible
     plutôt que de la retirer : la retirer supprimerait aussi l'accès clavier. */

  /* La barre de boutons sous le tableau (+ Ajouter, puce, tiret, coefficient)
     s'empile : une rangée de six boutons sur 390 px donne six demi-mots. */
  .lignes-actions { display: flex; flex-direction: column; align-items: stretch; gap: 6px; }
  .lignes-actions .btn { width: 100%; text-align: center; }

  /* Les totaux de la pièce prennent toute la largeur : à droite et étroits,
     ils coupaient « Total TTC » en deux lignes. */
  .totals { width: 100%; max-width: none; }
}

/* === TOUTE LISTE DEVIENT UNE CARTE SUR UN TÉLÉPHONE ========================
   Écrit une fois pour `.table-liste`, la classe que portent toutes les listes
   de l'application — devis, commandes, bons de livraison, factures, avoirs,
   clients, articles, relevé bancaire, relances, achats — et que les nouvelles
   reprendront. Le corriger écran par écran était la mauvaise altitude : sur un
   téléphone on voyait le numéro et le client, et la date, le statut et le
   total demandaient de faire défiler la ligne de gauche à droite.

   Les noms de colonnes sont posés sur les cellules par assets/listes-mobiles.js,
   la rangée d'en-têtes n'ayant plus de sens sans colonnes. Rien n'est déplacé
   dans le document : l'ordre des cellules reste l'ordre des colonnes. */
@media screen and (max-width: 900px) {
  /* ⚠️ `.card > table { min-width: max-content }` fait DÉFILER un tableau dans
     sa carte. C'est juste pour un tableau, et faux pour une liste qu'on replie :
     sans cette annulation les cartes se construisent hors de l'écran (mesuré
     une fois sur le tableau des lignes : 1719 px dans une carte de 465). */
  .card > .table-liste, .card .table-scroll > .table-liste,
  .table-scroll > .table-liste { min-width: 0; }
  .table-scroll { overflow-x: visible; }

  .table-liste, .table-liste tbody, .table-liste tr, .table-liste td { display: block; }
  .table-liste { border: 0; width: 100%; }
  .table-liste .liste-entete { display: none; }

  .table-liste tr {
    border: 1px solid var(--border); border-radius: 10px;
    padding: 10px 12px; margin-bottom: 8px; background: var(--card, #fff);
  }
  /* `th` COMPRIS : une rangée de totaux en pied de liste en porte, et sans
     cette ligne elle restait en colonnes pendant que les autres se repliaient
     — mesuré à 455 px dans une carte de 310 sur le relevé bancaire. */
  .table-liste tr:not(.liste-entete) th { display: block; text-align: left; border: 0; padding: 1px 0; }
  /* `:not(.liste-entete)` n'est pas une coquetterie : plusieurs écrans posent
     un `white-space: nowrap` à DEUX classes (`.table-banque .rappro-cell`),
     juste au bureau où la ligne ne doit pas doubler de hauteur, et faux ici où
     il n'y a plus de ligne. Il fallait donc deux classes pour l'emporter, et
     le `:not()` en apporte une — mesuré : la cellule de rapprochement faisait
     1039 px dans une carte de 310. */
  .table-liste tr:not(.liste-entete) > td, .table-liste tr:not(.liste-entete) > th {
    border: 0; padding: 1px 0; text-align: left;
    white-space: normal; max-width: none;
  }
  /* L'écrêtage à 320 px du bureau couperait un nom de client au tiers sur un
     écran qui, lui, a de la place en hauteur. */
  .table-liste td .cell-clip {
    max-width: none; white-space: normal; overflow: visible; text-overflow: clip;
  }

  /* La première cellule est le titre de la carte : un numéro de pièce ou un nom
     de client se lit sans qu'on lui dise ce que c'est. */
  .table-liste .liste-principale { font-size: 16px; font-weight: 600; margin-bottom: 2px; }

  /* Les autres portent leur nom de colonne devant la valeur. Le nom en gris et
     petit, la valeur dans la couleur du texte : on lit la valeur, le nom n'est
     là que pour lever le doute. */
  .table-liste td[data-libelle] { font-size: 13px; color: var(--muted); }
  .table-liste td[data-libelle]::before {
    content: attr(data-libelle) " "; color: var(--muted); font-size: 12px;
  }
  /* Une cellule vide n'affiche pas son étiquette toute seule : « Échéance »
     sans date ne dit rien et allonge la carte. */
  .table-liste td[data-libelle]:empty { display: none; }

  /* Les montants sont ce qu'on vient lire : en noir, un cran plus gros, et
     alignés à droite en face de leur nom. */
  .table-liste td.num[data-libelle] {
    display: flex; justify-content: space-between; gap: 12px;
    color: inherit; font-variant-numeric: tabular-nums;
  }
  .table-liste td.num[data-libelle]::before { flex: 0 0 auto; }

  /* La colonne d'actions n'est plus collée à droite — il n'y a plus de droite.
     Elle passe sous la carte, en rangée qui se replie. */
  .table-liste td.actions {
    position: static; margin-top: 8px;
    display: flex; flex-wrap: wrap; gap: 6px; align-items: center;
  }
  .table-liste td.actions form { display: inline-flex !important; margin: 0; }
  /* Un mini-formulaire dans une cellule (rapprocher une ligne de relevé,
     solder une facture) : ses contrôles se replient au lieu de partir en
     ligne droite — 558 px de sélecteurs et de boutons dans une carte de 310. */
  .table-liste tr:not(.liste-entete) td form { flex-wrap: wrap; max-width: 100%; }
  .table-liste tr:not(.liste-entete) td select,
  .table-liste tr:not(.liste-entete) td input[type="text"] { max-width: 100%; }
  /* Une rangée de message (« Aucun document… ») n'est pas une carte. */
  .table-liste .liste-message { border: 0; background: none; padding: 8px 0; }
}

/* === LA CAISSE SUR UN TÉLÉPHONE ===========================================
   Deux invariants, et ce sont ceux que la version de bureau a déjà posés pour
   les mêmes raisons :

   · LE TOTAL SE LIT CENT FOIS PAR JOUR. Il passait sous la barre du haut dès
     qu'on faisait défiler et se coupait en deux — le chiffre le plus regardé de
     l'écran, à moitié caché. Il se colle donc sous la barre, dont la hauteur
     est mesurée (voir --barre-haut dans includes/header.php) : elle change avec
     le bandeau d'alertes et celui de démonstration, et un nombre écrit en dur
     serait faux un jour sur deux.

   · ON NE DOIT JAMAIS AVOIR À FAIRE DÉFILER POUR ENCAISSER. Au bureau, les
     boutons de paiement ont été sortis du corps de l'écran parce que « plus le
     ticket était long, plus ils descendaient ». Sur un téléphone, la colonne
     unique reproduisait exactement ce défaut : mesurés à 450 px sous le pli sur
     un iPhone, avec un client qui attend. Le bloc « reste + modes » est donc
     fixé en bas. C'est aussi le bon geste : on tape une somme, on touche un
     mode — les deux sont au même endroit.

   Ce qui rétrécit est ce qu'on LIT ; ce qu'on VISE garde sa taille. */
@media screen and (max-width: 900px) {
  .caisse-total {
    position: sticky; top: var(--barre-haut, 52px); z-index: 12;
    margin-bottom: 8px;
  }
  /* Le total en entier, mais moins haut : sur un téléphone il doit laisser de
     la place au ticket. L'heure et la TVA détaillée passent à la trappe — on
     les lit au comptoir, pas dans la main. */
  .caisse-total-val { font-size: 34px; }
  .caisse-horloge { font-size: 12px; }

  /* La barre d'encaissement, fixée en bas. Elle porte ce qui sert à encaisser
     et rien d'autre : le reste dû, la somme remise, le rendu, les modes. */
  .caisse-encaissement {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 14;
    background: var(--card, #fff); border-top: 1px solid var(--border);
    padding: 8px 12px calc(8px + env(safe-area-inset-bottom, 0px));
    box-shadow: 0 -6px 18px rgba(0,0,0,.12);
  }
  .caisse-encaissement .caisse-reste { margin-top: 0; }
  /* L'aide et l'étiquette sortent de la barre : la place y vaut cher, et
     l'invite du champ dit déjà ce qu'on y tape. */
  .caisse-encaissement .caisse-reste-aide,
  .caisse-encaissement .caisse-reste label { display: none; }
  .caisse-encaissement .caisse-pied { margin-top: 8px; gap: 6px; }
  /* Les deux modes côte à côte et pleine largeur : c'est la cible que le doigt
     cherche en dernier, elle garde sa taille. */
  .caisse-encaissement .caisse-payer { flex: 1 1 0; min-width: 0; min-height: 52px; }
  /* « Vider le ticket » ne doit PAS être à côté d'« Espèces » : il est déjà à un
     doigt de trop, et il efface aussi les paiements déjà saisis. */
  .caisse-encaissement .caisse-annuler { flex: 1 1 100%; order: 9; min-height: 36px; font-size: 13px; }

  /* De quoi faire défiler jusqu'au bout sans que la barre fixe cache la fin du
     pavé : la barre est hors du flux, la place se reprend ici. */
  .caisse-corps { padding-bottom: 168px; }

  /* Les touches d'article gardent leur propre défilement, mais plus bas : sur
     un téléphone l'écran entier défile déjà. */
  .caisse-touches { max-height: none; }
}

/* ---------- Statistiques (statistiques.php) ----------
   Palette : les trois premières teintes d'une palette catégorielle vérifiée
   pour les daltoniens (validate_palette : écart CVD 9,2 et vision normale 24,0
   sur toutes les paires, fond blanc). L'ordre est fixe et suit la NATURE,
   jamais le rang : prestations en bleu, marchandises en orange, hors catalogue
   en vert d'eau, ouvrages en jaune quand le module bâtiment en produit. Le vert
   d'eau est sous 3:1 sur blanc : la légende et le tableau « Voir les chiffres »
   de chaque graphique portent l'information sans la couleur. */
.stats {
  --serie-1: #2a78d6; --serie-2: #eb6834; --serie-3: #1baf7a; --serie-4: #eda100;
  /* « Autres » et « sans commercial » : un gris neutre, jamais une 5e teinte. */
  --serie-autre: #a8a69e;
  --stats-grille: #e1e0d9; --stats-base: #c3c2b7; --stats-axe: #898781;
  --stats-encre: #0b0b0b; --stats-encre-2: #52514e;
}
.stats-tuiles { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 14px; margin-bottom: 14px; }
.stats-tuiles .card { margin: 0; }
.stats-tuile-lib { font-size: 13px; color: var(--stats-encre-2); }
.stats-tuile-val { font-size: 28px; font-weight: 700; color: var(--stats-encre); margin: 4px 0 2px; white-space: nowrap; }
.stats-tuile-pied { font-size: 12.5px; min-height: 1.4em; }
.stats-delta { font-weight: 600; }
.stats-hausse { color: #006300; }
.stats-baisse { color: #b91c1c; }
.stats-entete { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 8px 18px; }
.stats-entete h2 { margin-bottom: 6px; }
.stats-legende { display: flex; flex-wrap: wrap; gap: 6px 16px; font-size: 13px; color: var(--stats-encre-2); }
.stats-legende i { display: inline-block; width: 10px; height: 10px; border-radius: 2px; margin-right: 6px; vertical-align: -1px; }
.stats-legende strong { color: var(--stats-encre); font-weight: 600; margin-left: 2px; }
.stats-svg { width: 100%; height: auto; display: block; overflow: visible; }
.stats-svg .stats-grille { stroke: var(--stats-grille); stroke-width: 1; }
.stats-svg .stats-base { stroke: var(--stats-base); stroke-width: 1; }
.stats-svg .stats-axe { fill: var(--stats-axe); font-size: 11.5px; font-variant-numeric: tabular-nums; }
.stats-svg .stats-lib { fill: var(--stats-encre-2); font-size: 12.5px; }
.stats-svg .stats-val { fill: var(--stats-encre); font-size: 12px; font-variant-numeric: tabular-nums; }
.stats-svg .stats-courbe { fill: none; stroke: var(--serie-1); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.stats-svg .stats-point { fill: var(--serie-1); stroke: #fff; stroke-width: 2; }
.stats-svg .stats-barre-h { fill: var(--serie-1); }
.stats-svg .stats-cible { fill: transparent; cursor: default; outline: none; }
.stats-svg .stats-cible:hover, .stats-svg .stats-cible:focus { fill: rgba(11, 11, 11, .04); }
.stats-svg a .stats-cible { cursor: pointer; }
.stats-svg a:hover .stats-lib { fill: var(--primary); text-decoration: underline; }
.stats-tableau { margin-top: 10px; }
.stats-tableau summary { cursor: pointer; color: var(--primary); font-size: 13px; }
.stats-info {
  position: fixed; z-index: 300; pointer-events: none;
  background: #fff; color: var(--stats-encre, #0b0b0b); border: 1px solid rgba(11, 11, 11, .10);
  border-radius: 8px; box-shadow: 0 4px 16px rgba(0, 0, 0, .12);
  padding: 8px 10px; font-size: 12.5px; line-height: 1.5; font-variant-numeric: tabular-nums; max-width: 280px;
}
.stats-info .stats-info-titre { font-weight: 700; margin-bottom: 2px; }
/* Un SVG à viewBox impose sa largeur de dessin comme largeur minimale à une
   grille : sans ce min-width la page débordait sur téléphone. */
.stats .card, .stats .grid2 > *, .grid2.stats > * { min-width: 0; }
.stats-mobile { display: none; }
@media screen and (max-width: 900px) {
  .stats-bureau { display: none; }
  .stats-mobile { display: block; }
  .stats .grid2, .grid2.stats { grid-template-columns: 1fr; }
  .stats-tuiles { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  .stats-tuile-val { font-size: 21px; }
}
@media print { .stats-info { display: none; } }

/* ---------- Tableau de bord (index.php, 24/09/2026) ----------
   Des tuiles de couleur, parce qu'on les reconnaît avant de les lire : un
   liseré et une pastille d'icône de la couleur de la tuile, le chiffre en
   noir. Les teintes sont celles de la palette des Statistiques (vérifiée pour
   les daltoniens) ; le libellé est toujours écrit, la couleur ne dit rien seule.
   Le rouge ne sert qu'au retard de paiement. */
.tb-tuile, .tb-compteur { position: relative; color: inherit; text-decoration: none; display: block;
  border-top: 3px solid var(--accent, var(--primary)); transition: box-shadow .15s, transform .15s; }
.tb-tuile:hover, .tb-compteur:hover { text-decoration: none; box-shadow: 0 6px 18px rgba(15, 23, 42, .08); transform: translateY(-1px); }
.tb-icone { display: inline-flex; align-items: center; justify-content: center; width: 34px; height: 34px;
  border-radius: 9px; color: var(--accent, var(--primary)); background: #f1f5f9;
  background: color-mix(in srgb, var(--accent, var(--primary)) 13%, #fff); }
.tb-icone svg { width: 18px; height: 18px; }
.tb-tuile .tb-icone { position: absolute; top: 14px; right: 14px; }
.tb-tuile-lib { font-size: 13px; color: var(--muted); padding-right: 44px; }
.tb-tuile-val { font-size: 27px; font-weight: 700; margin: 6px 0 4px; white-space: nowrap; color: var(--text); }
.tb-tuile-pied { font-size: 12.5px; color: var(--muted); min-height: 1.4em; }
.tb-evol { font-weight: 700; }
.tb-evol.hausse { color: #006300; }
.tb-evol.baisse { color: #b91c1c; }
.tb-retard { color: #b91c1c; font-weight: 600; }
.tb-graphes { margin-bottom: 0; }
.tb-graphes .card h2 { margin-top: 0; }
.tb-compteurs { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 12px; margin-bottom: 16px; }
.tb-compteurs .tb-compteur { display: flex; align-items: center; gap: 12px; padding: 12px 14px; margin: 0; }
.tb-compteur strong { font-size: 20px; margin-right: 4px; color: var(--text); }
.tb-compteur .muted { font-size: 13px; }
@media screen and (max-width: 900px) {
  .tb-graphes { order: 3; }
  .tb .tb-recents { order: 4; }
  .tb .tb-actions { order: 5; }
  .tb .tb-compteurs { order: 6; grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .tb-tuile-val { font-size: 24px; }
}

/* ---------- Journal de chantier (chantier_journal.php, 24/09/2026) ----------
   Un écran de téléphone, sur un chantier, au pouce : boutons de 48 px au moins,
   un formulaire ouvert à la fois, l'appareil photo ouvert directement. */
.cj-chantiers { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 12px; }
.cj-chantier { display: flex; flex-direction: column; gap: 4px; color: inherit; text-decoration: none; margin: 0; }
.cj-chantier:hover { text-decoration: none; box-shadow: 0 6px 18px rgba(15, 23, 42, .08); }
.cj-chantier strong { font-size: 17px; }
.cj-avancement { display: block; height: 8px; border-radius: 4px; background: #e2e8f0; overflow: hidden; margin: 6px 0 2px; }
.cj-avancement span { display: block; height: 100%; background: #2a78d6; border-radius: 4px; }
.cj-boutons { display: grid; grid-template-columns: repeat(5, 1fr); gap: 8px; margin-bottom: 12px; }
.cj-bouton { min-height: 52px; border: 1px solid var(--border); border-radius: 10px; background: #fff;
  font: inherit; font-weight: 600; font-size: 15px; color: var(--text); cursor: pointer; }
.cj-bouton.actif { background: var(--primary); border-color: var(--primary); color: #fff; }
.cj-form label { display: block; margin-bottom: 10px; font-weight: 600; font-size: 14px; }
.cj-form input[type=text], .cj-form input[type=date], .cj-form select, .cj-form textarea {
  display: block; width: 100%; margin-top: 4px; font-size: 17px; padding: 10px; box-sizing: border-box; }
.cj-form input[type=range] { width: 100%; margin-top: 8px; }
.cj-form .btn { width: 100%; min-height: 48px; font-size: 16px; }
.cj-rapides { display: flex; flex-wrap: wrap; gap: 6px; margin: -4px 0 12px; }
.cj-rapides button { min-height: 40px; min-width: 56px; border: 1px solid var(--border); border-radius: 8px;
  background: #f8fafc; font: inherit; cursor: pointer; }
.cj-appareil { position: relative; display: block; border: 2px dashed #93c5fd; border-radius: 12px;
  background: #eff6ff; text-align: center; padding: 18px 10px; cursor: pointer; }
.cj-appareil input[type=file] { position: absolute; inset: 0; opacity: 0; width: 100%; height: 100%; cursor: pointer; }
.cj-appareil span { font-size: 16px; color: #1d4ed8; }
.cj-jour { font-size: 14px; color: var(--muted); margin: 18px 0 6px; text-transform: capitalize; }
.cj-entree { margin-bottom: 8px; padding: 12px 14px; border-left: 4px solid var(--border); }
.cj-entree.cj-heures { border-left-color: #2a78d6; }
.cj-entree.cj-photo { border-left-color: #1baf7a; }
.cj-entree.cj-depense { border-left-color: #eb6834; }
.cj-entree.cj-avancement { border-left-color: #4a3aa7; }
.cj-entree-tete { display: flex; justify-content: space-between; gap: 8px; font-size: 12.5px; margin-bottom: 4px; }
.cj-type { font-weight: 700; text-transform: uppercase; letter-spacing: .04em; }
.cj-vignette { display: block; max-width: 100%; max-height: 260px; border-radius: 8px; margin-top: 8px; }
.cj-retirer { margin-top: 8px; }
.sidebar-compagnon .nav-compagnon { display: flex; flex-direction: column; gap: 2px; padding: 8px; }
@media screen and (max-width: 900px) {
  .sidebar-compagnon .nav-compagnon { flex-direction: row; flex-wrap: wrap; padding: 0 10px 10px; }
  .sidebar-compagnon .nav-compagnon .nav-btn { flex: 1 1 auto; }
}
@media screen and (max-width: 520px) {
  .cj-boutons { grid-template-columns: repeat(3, 1fr); }
}

/* Factures en brouillon oubliées (index.php) : le seul bandeau rouge du tableau
   de bord avec le retard de paiement — un brouillon oublié est une facture qui
   n'existe pour personne. */
.tb-brouillons { border-left: 4px solid #b91c1c; background: #fef2f2; }
.tb-brouillons strong { color: #991b1b; }
.tb-brouillons-liste { display: flex; flex-wrap: wrap; gap: 6px 14px; align-items: baseline; margin-top: 8px; font-size: 13.5px; }
.tb-brouillons-liste .btn { margin-left: auto; }
@media screen and (max-width: 900px) { .tb .tb-brouillons { order: 2; } }

/* Carte « À faire » (index.php, lot 2 du 09/10/2026) : chaque ligne reste
   affichée à zéro. Rouge = à faire aujourd'hui, gris = de fond, vert = à jour. */
.tb-afaire h2 { margin: 0 0 8px; }
.tb-afaire-liste { list-style: none; margin: 0; padding: 0; display: grid;
  grid-template-columns: repeat(auto-fill, minmax(420px, 1fr)); gap: 2px 28px; }
/* Libellé et état en deux colonnes fixes : les états s'alignent d'une ligne
   à l'autre au lieu de suivre la longueur du libellé (09/10/2026). */
.tb-afaire-liste a { display: grid; grid-template-columns: minmax(0, 1fr) 200px; align-items: baseline; gap: 12px;
  padding: 6px 8px; border-radius: 6px; color: inherit; text-decoration: none; font-size: 13.5px;
  border-bottom: 1px solid var(--border); }
.tb-afaire-liste li.ok a { padding-top: 4px; padding-bottom: 4px; }
.tb-afaire-liste .tb-afaire-val { text-align: left; }
@media screen and (max-width: 700px) {
  .tb-afaire-liste { grid-template-columns: 1fr; }
  .tb-afaire-liste a { grid-template-columns: minmax(0, 1fr) auto; }
}
.tb-afaire-liste a:hover { background: var(--bg, #f5f6f8); text-decoration: none; }
.tb-afaire-lib { min-width: 0; }
.tb-afaire-val { white-space: nowrap; text-align: right; }
.tb-afaire-liste li.ok .tb-afaire-val { color: #006300; }
.tb-afaire-liste li.urgent .tb-afaire-val { color: #b91c1c; font-weight: 600; }
.tb-afaire-liste li.fond .tb-afaire-val { color: var(--muted); }
@media screen and (max-width: 900px) { .tb .tb-afaire { order: 2; } }

/* ---------- Prévu / réel et PV de réception (24/09/2026) ---------- */
.pr-table .pr-total td { font-weight: 700; border-top: 2px solid var(--border); }
.pr-depasse { color: #b91c1c; font-weight: 600; }
.pr-barre { display: inline-block; vertical-align: middle; width: 90px; height: 8px; border-radius: 4px; background: #e2e8f0; overflow: hidden; margin-right: 6px; }
.pr-barre span { display: block; height: 100%; background: #2a78d6; }
.pr-barre.alerte span { background: #b91c1c; }
.pv-form label { display: block; margin-bottom: 10px; font-weight: 600; font-size: 14px; }
.pv-form input[type=text], .pv-form input[type=date], .pv-form textarea { display: block; width: 100%; box-sizing: border-box; margin-top: 4px; font-size: 16px; padding: 9px; }
.pv-signature { border: 1px solid var(--border); border-radius: 10px; padding: 10px; margin: 6px 0 12px; background: #f8fafc; }
.pv-signature-tete { display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px; }
.pv-signature canvas { display: block; width: 100%; height: 190px; background: #fff; border: 1px dashed #94a3b8; border-radius: 8px; touch-action: none; }
.pv-declaration { display: flex !important; gap: 10px; align-items: flex-start; font-weight: 600; background: #eff6ff; border-radius: 8px; padding: 12px; }
.pv-declaration input { width: 22px; height: 22px; flex: 0 0 auto; margin-top: 1px; }
.pv-form .btn[type=submit] { width: 100%; min-height: 50px; font-size: 16px; }
.pv-reserves { margin: 6px 0 8px 18px; padding: 0; }
.pv-signature-image { display: block; max-width: 340px; width: 100%; border: 1px solid var(--border); border-radius: 8px; margin: 8px 0 12px; background: #fff; }
.pv-garanties { width: 100%; border-collapse: collapse; font-size: 14px; margin-bottom: 12px; }
.pv-garanties td { padding: 6px 8px; border-bottom: 1px solid var(--border); }

/* Bandeau « BL livrés à facturer » (documents.php, types bl et facture) : ce
   qui attend un geste se voit en tête de page, pas dans un bouton gris. */
.bandeau-bl {
  display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap;
  background: #fff7ed; border: 1px solid #fdba74; border-left: 5px solid #ea580c;
  border-radius: 8px; padding: 12px 16px; margin: 0 0 16px; color: #7c2d12; font-size: 15px;
}
.bandeau-bl .btn { background: #ea580c; border-color: #ea580c; }
.bandeau-bl .btn:hover { background: #c2410c; border-color: #c2410c; }

/* Commande livrée en partie : ni « confirmée » ni « livrée », elle attend encore. */
.badge.partielle { background: #fef3c7; color: #92400e; }

/* === LES PETITS TABLEAUX DE CHIFFRES SUR UN TÉLÉPHONE =====================
   Trois ou quatre colonnes — un libellé et un ou deux montants, comme la CA3
   du dossier TVA — tiennent dans la largeur d'un téléphone à condition que le
   libellé passe à la ligne. La règle générale `.card > table { min-width:
   max-content }` les faisait défiler de gauche à droite pour une phrase trop
   longue (« Ventes, prestations de services (base hors taxes taxable… »),
   alors que le montant, ce qu'on vient lire, était hors de l'écran. Ils ne se
   replient pas en cartes : ce sont des lignes de formulaire, qui se lisent
   dans l'ordre et en colonnes. Seuls les montants gardent leur ligne. */
@media screen and (max-width: 900px) {
  .card > table.table-etroite { min-width: 0; width: 100%; }
  .table-etroite th, .table-etroite td { white-space: normal; overflow-wrap: anywhere; padding-left: 6px; padding-right: 6px; }
  /* Les montants ne se coupent pas d'eux-mêmes — money() sépare les milliers
     et l'euro par des espaces insécables —, donc la cellule peut passer à la
     ligne sans casser un chiffre : « 178,67 € − déductible » tient en deux. */
  .table-etroite .num { overflow-wrap: normal; }
  .table-etroite th:first-child, .table-etroite td:first-child { padding-left: 0; }
}

/* Une grille à deux colonnes sert aux vignettes de chiffres ; une carte qui
   porte une LISTE n'y a pas sa place sur un téléphone — « Par article » et
   « Par client » côte à côte dans Marges faisaient des cartes de 150 px où
   chaque nom tenait sur trois lignes. Elle prend toute la largeur. */
@media screen and (max-width: 900px) {
  .grid2 > .card:has(.table-liste), .grid3 > .card:has(.table-liste),
  .grid4 > .card:has(.table-liste), .grid5 > .card:has(.table-liste) { grid-column: 1 / -1; }
}

/* === LA BARRE D'ACTIONS D'UNE PIÈCE SUR UN TÉLÉPHONE (document_view.php) ===
   Au bureau, treize boutons sur une ligne se lisent d'un coup d'œil. Sur un
   téléphone ils faisaient cinq rangées de tailles et de couleurs mêlées avant
   même la pièce — « ça fait brouillon ». On garde en vue ce qu'on fait debout,
   le téléphone à la main : revenir, modifier, envoyer (avec l'adresse, qu'on
   doit voir avant d'envoyer), valider, transformer. Le reste — dupliquer,
   imprimer, PDF, Factur-X, statut, supprimer… — se déplie sous « Plus
   d'actions ». Rien n'est déplacé dans le document : `order` range, la grille
   aligne. */
.act-toggle { display: none; }
@media screen and (max-width: 700px) {
  .actions-bar { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
  .actions-bar > * { margin: 0 !important; min-width: 0; }
  .actions-bar > form { display: block !important; }
  .actions-bar > .btn, .actions-bar > form > .btn { width: 100%; justify-content: center; text-align: center; }
  .actions-bar .act-retour   { order: 1; }
  .actions-bar .act-modifier { order: 2; }
  .actions-bar .act-envoi    { order: 3; grid-column: 1 / -1; }
  .actions-bar .act-mail     { order: 4; grid-column: 1 / -1; width: 100% !important; }
  .actions-bar > span.muted  { order: 5; grid-column: 1 / -1; }
  .actions-bar .act-valider  { order: 6; grid-column: 1 / -1; }
  .actions-bar > *           { order: 7; }
  .actions-bar .act-saut     { display: none; }
  .actions-bar .act-toggle   { order: 50; display: block; grid-column: 1 / -1; width: 100%; }
  .actions-bar .act-plus     { order: 60; display: none !important; }
  .actions-bar.tout .act-plus { display: block !important; }
  .actions-bar.tout .btn.act-plus { display: flex !important; align-items: center; justify-content: center; gap: 6px; }
  .actions-bar.tout > span.act-plus.badge { display: inline-block !important; }
  /* Le statut : la liste et « Appliquer » sur une ligne, dans toute la largeur. */
  .actions-bar.tout #formStatut { display: flex !important; gap: 8px; grid-column: 1 / -1; }
  .actions-bar #formStatut select { flex: 1 1 auto; min-width: 0; }
  .actions-bar #formStatut .btn { width: auto; }
}

/* === LE GUIDE SUR UN TÉLÉPHONE (guide.php) ================================
   Une section à la fois : le sommaire est la page d'accueil, une section
   s'ouvre seule (body.aide-lecture + .aide-section.active, posés par le
   script de guide.php d'après l'ancre), avec son retour, son mini-sommaire
   et « précédente / suivante ». Au bureau ces trois éléments n'existent pas :
   le sommaire collé à gauche fait déjà ce travail. */
.aide-retour, .aide-dans, .aide-suite { display: none; }
@media screen and (max-width: 900px) {
  .aide-sommaire { gap: 0; font-size: 16px; }
  .aide-sommaire a {
    display: flex; justify-content: space-between; align-items: center;
    padding: 12px 14px; background: var(--card, #fff); border: 1px solid var(--border);
    border-radius: 0; margin-top: -1px; color: var(--text);
  }
  .aide-sommaire a::after { content: "›"; color: var(--muted); font-size: 20px; line-height: 1; margin-left: 10px; }
  .aide-groupe { margin: 18px 2px 6px; font-size: 12px; }
  .aide-recherche { position: sticky; top: var(--barre-haut, 52px); z-index: 5; background: var(--bg); padding: 6px 0; }
  .aide-recherche input { font-size: 16px; }

  /* Sans section ouverte : le sommaire seul. Avec : la section seule. */
  .aide-contenu .aide-section { display: none; }
  body.aide-lecture .aide-sommaire { display: none; }
  body.aide-lecture .aide-contenu .aide-section.active { display: block; }
  body.aide-lecture .page-header { display: none; }

  .aide-retour { display: inline-block; font-size: 16px; padding: 4px 0 10px; }
  .aide-section h2 { font-size: 19px; }
  .aide-dans {
    display: flex; flex-direction: column; margin: 4px 0 16px;
    border: 1px solid var(--border); border-radius: 8px; overflow: hidden;
  }
  .aide-dans a { padding: 10px 12px; border-top: 1px solid var(--border); font-size: 15px; }
  .aide-dans a:first-child { border-top: 0; }
  .aide-section { scroll-margin-top: calc(var(--barre-haut, 52px) + 12px); }
  .aide-section h2[id] { scroll-margin-top: calc(var(--barre-haut, 52px) + 12px); }
  .aide-suite { display: flex; justify-content: space-between; gap: 8px; margin-top: 20px; flex-wrap: wrap; }
  .aide-suite .btn { flex: 1 1 45%; font-size: 14px; white-space: normal; text-align: center; }
  /* Une recherche : les résultats avant le sommaire. */
  .aide-layout { display: flex; flex-direction: column; }
  .aide-contenu { order: -1; }
  body:not(.aide-lecture) .aide-contenu:not(:has(.aide-resultat, .card:not(.aide-section))) { display: none; }
}

/* === PRÉSENTATION DES DOCUMENTS (presentation.php) =========================
   Les réglages à gauche, l'aperçu de la vraie pièce à droite, collé pendant
   qu'on fait défiler les réglages : on voit l'effet de chaque case sans
   remonter. Sur un téléphone l'aperçu passe dessous. */
.presentation { display: grid; grid-template-columns: minmax(320px, 440px) minmax(0, 1fr); gap: 20px; align-items: start; }
.presentation-reglages .card h2 { font-size: 16px; margin: 0 0 10px; }
.presentation-reglages label.check { display: flex; gap: 8px; align-items: flex-start; font-size: 14px; margin: 8px 0 0; font-weight: normal; }
.presentation-reglages label.check input { width: auto; margin-top: 3px; flex: 0 0 auto; }
.pres-modeles { display: grid; gap: 8px; }
.pres-modele { display: grid; grid-template-columns: auto 1fr; gap: 2px 10px; padding: 10px 12px; border: 1px solid var(--border); border-radius: 8px; cursor: pointer; font-weight: normal; }
.pres-modele input { grid-row: span 2; width: auto; margin-top: 3px; }
.pres-modele .muted { font-size: 12.5px; }
.pres-modele:has(input:checked) { border-color: var(--primary); box-shadow: 0 0 0 1px var(--primary) inset; }
.presentation-actions { display: flex; gap: 8px; flex-wrap: wrap; position: sticky; bottom: 0; background: var(--bg); padding: 10px 0; }
.presentation-apercu { position: sticky; top: 12px; }
.presentation-apercu-barre { display: flex; gap: 8px; align-items: center; margin-bottom: 8px; flex-wrap: wrap; }
.presentation-apercu-barre select { width: auto; max-width: 100%; }
.presentation-cadre { width: 100%; height: calc(100vh - 110px); border: 1px solid var(--border); border-radius: 8px; background: #e5e7eb; }
@media screen and (max-width: 900px) {
  .presentation { grid-template-columns: 1fr; }
  .presentation-apercu { position: static; }
  .presentation-cadre { height: 70vh; }
}

/* === MODULE SAV (sav.php, sav_dossier.php) =================================
   Repris de Repiko : le type en couleur (la même que dans Repiko), le statut en
   pastille, l'ancienneté neutre jusqu'à deux jours, orange au-delà, rouge passé
   une semaine — le plus ancien est celui qu'on va oublier. */
.sav-type { display: inline-block; font-size: 11px; font-weight: 600; border: 1px solid; border-radius: 999px; padding: 0 7px; margin-left: 6px; vertical-align: 1px; }
.sav-statut { display: inline-block; font-size: 12px; font-weight: 600; border-radius: 999px; padding: 1px 9px; background: #eef0f3; color: #374151; white-space: nowrap; }
.sav-statut.st-recu { background: #e0e7ff; color: #3730a3; }
.sav-statut.st-diagnostic { background: #ede9fe; color: #5b21b6; }
.sav-statut.st-attente_client { background: #fef3c7; color: #92400e; }
.sav-statut.st-attente_piece { background: #ffedd5; color: #9a3412; }
.sav-statut.st-reparation { background: #dbeafe; color: #1e40af; }
.sav-statut.st-pret { background: #dcfce7; color: #166534; }
.sav-statut.st-restitue { background: #f3f4f6; color: #6b7280; }
.sav-age { font-size: 12.5px; color: var(--muted); white-space: nowrap; }
.sav-age.orange { color: #b45309; font-weight: 600; }
.sav-age.rouge { color: #b91c1c; font-weight: 700; }
.sav-relance-due { color: #b91c1c; font-weight: 600; }
.sav-bloc-pret { border-left: 4px solid #16a34a; }
.sav-bloc-relance { border-left: 4px solid #dc2626; }
.sav-restitues > summary { cursor: pointer; font-weight: 600; padding: 10px 2px; color: var(--muted); }
.sav-types { display: flex; flex-wrap: wrap; gap: 8px; }
.sav-type-choix { display: inline-flex; align-items: center; gap: 6px; border: 1.5px solid var(--c); color: var(--c); border-radius: 999px; padding: 6px 14px; cursor: pointer; font-weight: 600; }
.sav-type-choix input { width: auto; margin: 0; accent-color: var(--c); }
.sav-type-choix:has(input:checked) { background: var(--c); color: #fff; }
.sav-appareil { border: 1px solid var(--border); border-radius: 8px; padding: 10px 12px; margin-bottom: 10px; }
.sav-appareil-tete { display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px; }
.sav-suggestions { position: absolute; z-index: 20; left: 0; right: 0; top: 100%; background: var(--card, #fff); border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 6px 18px rgba(0,0,0,.12); max-height: 280px; overflow-y: auto; }
.sav-suggestions button { display: block; width: 100%; text-align: left; background: none; border: 0; border-bottom: 1px solid var(--border); padding: 8px 10px; cursor: pointer; font: inherit; color: inherit; }
.sav-suggestions button:hover, .sav-suggestions button:focus { background: var(--bg); }
.sav-suggestions button .muted { display: block; font-size: 12px; }
.sav-evt { border-left: 3px solid var(--primary); padding: 4px 10px; margin-bottom: 8px; }
.sav-evt.auto { border-left-color: var(--border); }
.sav-evt .muted { font-size: 12px; }

/* Changement de statut dans la liste SAV : la liste et « Appliquer » côte à côte. */
.sav-statut-rapide { display: inline-flex !important; gap: 4px; align-items: center; margin-right: 4px; }
.sav-statut-rapide select { width: auto; font-size: 13px; padding: 3px 6px; }

/* Parcourir le catalogue fournisseur depuis une pièce (document_form.php). */
.modal.catalogue-modal { max-width: 980px; }
.catalogue-filtres { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-bottom: 8px; }
.catalogue-filtres input, .catalogue-filtres select { width: auto; flex: 1 1 150px; min-width: 0; }
.catalogue-filtres #catQ { flex: 2 1 260px; }
.catalogue-filtres #catPmin, .catalogue-filtres #catPmax { flex: 0 1 110px; }
.catalogue-dispo { display: inline-flex; gap: 5px; align-items: center; font-size: 13px; white-space: nowrap; }
.catalogue-dispo input { width: auto; flex: none; }
.catalogue-etat { font-size: 13px; margin: 4px 0 8px; }
.catalogue-liste { max-height: 60vh; overflow-y: auto; border-top: 1px solid var(--border); }
.catalogue-article { display: grid; grid-template-columns: 64px minmax(0, 1fr) auto; gap: 12px; align-items: center; padding: 8px 4px; border-bottom: 1px solid var(--border); font-size: 13px; }
.catalogue-image { width: 64px; height: 64px; display: flex; align-items: center; justify-content: center; }
.catalogue-image img { max-width: 64px; max-height: 64px; object-fit: contain; }
.catalogue-texte { min-width: 0; }
.catalogue-prix { display: flex; flex-direction: column; align-items: flex-end; gap: 2px; white-space: nowrap; }
.catalogue-pages { display: flex; gap: 10px; align-items: center; justify-content: center; margin-top: 10px; }
@media (max-width: 700px) {
  .catalogue-article { grid-template-columns: 48px minmax(0, 1fr); }
  .catalogue-image, .catalogue-image img { width: 48px; height: 48px; max-width: 48px; max-height: 48px; }
  .catalogue-prix { grid-column: 1 / -1; flex-direction: row; flex-wrap: wrap; justify-content: flex-end; align-items: center; gap: 8px; }
}

/* --- Le fil (compta_fil.php) --------------------------------------------- */
.fil-mois { display: flex; gap: 8px; align-items: center; }
.fil-tuiles { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; margin-bottom: 16px; }
.fil-tuile { background: #fff; border: 1px solid var(--border); border-radius: 10px; padding: 14px 16px; min-width: 0; }
.fil-tuile span { display: block; font-size: 12px; color: var(--muted); text-transform: uppercase; letter-spacing: .03em; }
.fil-tuile strong { display: block; font-size: 24px; margin: 4px 0; }
.fil-tuile small { color: var(--muted); font-size: 12px; }
.fil-barre { height: 8px; background: var(--bg); border-radius: 4px; overflow: hidden; margin: 6px 0; }
.fil-barre i { display: block; height: 100%; background: #16a34a; }
.fil-sort { color: #b91c1c; }
.fil-entre { color: #15803d; }
.fil-barre-outils { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; margin-bottom: 10px; }
.fil-info { background: #f0fdf4; border: 1px solid #bbf7d0; border-radius: 8px; padding: 8px 12px; font-size: 13px; }
.fil-carte { display: grid; grid-template-columns: 64px minmax(0, 1fr) auto auto; gap: 12px; align-items: start;
  padding: 10px 8px; border-bottom: 1px solid var(--border); border-left: 4px solid transparent; }
.fil-carte.fil-a_traiter { border-left-color: #f59e0b; }
.fil-carte.fil-a_verifier { border-left-color: #dc2626; }
.fil-carte.fil-affecte { border-left-color: #16a34a; }
.fil-carte.fil-vente, .fil-carte.fil-remise, .fil-carte.fil-fournisseur { border-left-color: #cbd5e1; opacity: .8; }
.fil-date { font-weight: 600; font-size: 13px; }
.fil-date span { display: block; font-weight: 400; font-size: 11px; color: var(--muted); }
.fil-titre { font-weight: 600; font-size: 13.5px; overflow-wrap: anywhere; }
.fil-sous { font-size: 13px; margin-top: 3px; }
.fil-montant { font-weight: 600; white-space: nowrap; text-align: right; }
.fil-actions { display: flex; gap: 4px; white-space: nowrap; }
.fil-ok { color: #16a34a; font-weight: 700; }
.fil-chip { display: inline-block; font-size: 11px; padding: 1px 7px; border-radius: 10px; background: #e2e8f0; color: #334155; }
.fil-chip.auto { background: #dcfce7; color: #166534; }
.fil-chip.appris, .fil-chip.reconnu { background: #dbeafe; color: #1e40af; }
.fil-chip.devine { background: #fef3c7; color: #92400e; }
.fil-chip.inconnu { background: #fee2e2; color: #991b1b; }
.fil-edit { display: flex; flex-wrap: wrap; gap: 8px; align-items: flex-end; margin-top: 8px; padding: 8px; background: var(--bg); border-radius: 8px; }
.fil-edit label { display: flex; flex-direction: column; font-size: 12px; gap: 2px; }
.fil-edit input[name=compte] { width: 300px; max-width: 100%; }
.fil-erreur { color: #b91c1c; font-size: 12.5px; }
/* Lot 3 (09/10/2026) : l'aide sous le choix du compte, le « qui » qui manque,
   et le mode d'emploi en tête du fil. */
.fil-aide-comptes { flex-basis: 100%; margin: 2px 0 0; font-size: 12px; color: var(--muted); line-height: 1.5; }
.fil-manque { font-size: 12px; color: #92400e; white-space: normal; max-width: 180px; }
.fil-mode summary { cursor: pointer; }
.fil-mode ol { margin: 8px 0 0; padding-left: 22px; font-size: 13.5px; line-height: 1.6; }
.fil-attente { opacity: .5; }
.fil-flash { animation: filFlash 1.2s; }
@keyframes filFlash { from { background: #dcfce7; } to { background: transparent; } }
.fil-vide { padding: 20px; text-align: center; color: var(--muted); }
@media (max-width: 900px) {
  .fil-tuiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .fil-carte { grid-template-columns: 52px minmax(0, 1fr) auto; }
  .fil-actions { grid-column: 2 / -1; }
}

.fil-onglets { display: flex; gap: 4px; margin-bottom: 12px; flex-wrap: wrap; }
.fil-onglets a { padding: 7px 14px; border-radius: 8px; background: #fff; border: 1px solid var(--border); color: inherit; text-decoration: none; font-size: 13.5px; }
.fil-onglets a.actif { background: var(--primary); color: #fff; border-color: var(--primary); }
.fil-clos { background: #f1f5f9; border: 1px solid #cbd5e1; border-radius: 10px; padding: 10px 14px; margin-bottom: 12px; font-size: 13.5px; }
.fil-cloture { background: #fffbeb; border: 1px solid #fde68a; border-radius: 10px; padding: 10px 14px; margin-bottom: 12px; font-size: 13.5px; }
.fil-cloture form { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.livres-classe td { background: var(--bg); font-weight: 600; }
.livres-lettre { font-family: monospace; color: #1e40af; }
.prev-courbe { width: 100%; height: auto; display: block; }

.fil-sep { width: 1px; align-self: stretch; background: var(--border); margin: 0 4px; }
.fil-filtre { padding: 4px 10px; border-radius: 14px; border: 1px solid var(--border); font-size: 12.5px; color: inherit; text-decoration: none; background: #fff; }
.fil-filtre b { font-weight: 600; color: var(--muted); margin-left: 2px; }
.fil-filtre.actif { background: #1e293b; color: #fff; border-color: #1e293b; }
.fil-filtre.actif b { color: #cbd5e1; }

.fil-activite { display: inline-block; font-size: 11.5px; padding: 0 7px; border-radius: 9px; background: #eef2ff; color: #3730a3; }
.ana-pastille { display: inline-block; width: 10px; height: 10px; border-radius: 3px; margin-right: 6px; vertical-align: -1px; }

.ana-seuil { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; }
.ana-seuil span, .ana-chiffres span { display: block; font-size: 12px; color: var(--muted); }
.ana-seuil strong { font-size: 20px; }
.ana-jauge { position: relative; height: 12px; background: var(--bg); border-radius: 6px; margin: 14px 0 6px; }
.ana-jauge i { display: block; height: 100%; border-radius: 6px; background: #15803d; }
.ana-jauge b { position: absolute; top: -4px; width: 2px; height: 20px; background: #1e293b; }
.ana-fiches { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 14px; }
.ana-fiche { border: 1px solid var(--border); border-top: 4px solid; border-radius: 10px; padding: 12px 14px; min-width: 0; }
.ana-fiche h3 { margin: 0 0 8px; font-size: 15px; }
.ana-fiche h4 { margin: 12px 0 4px; font-size: 12.5px; color: var(--muted); font-weight: 600; }
.ana-chiffres { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 12px; }
.ana-chiffres strong { font-size: 15px; }
.ana-chiffres small { display: block; font-size: 11.5px; }
.ana-top { margin: 0; padding-left: 18px; font-size: 13px; }
.ana-top li { display: flex; justify-content: space-between; gap: 8px; }
.ana-top li a { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.ana-top li span { white-space: nowrap; color: var(--muted); }
@media (max-width: 900px) { .ana-seuil { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* Clôture de l'exercice : les étapes numérotées, cochées une fois faites. */
.ex-etape { display: flex; align-items: center; gap: 10px; }
.ex-etape span { display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 26px; border-radius: 50%; background: var(--bg); border: 1px solid var(--border); font-size: 13px; }
.ex-etape.fait span { background: #15803d; border-color: #15803d; color: #fff; }
.ex-mois { display: flex; flex-wrap: wrap; gap: 6px; }
.ex-mois a { padding: 5px 10px; border-radius: 14px; border: 1px solid var(--border); text-decoration: none; color: inherit; font-size: 13px; }
.ex-mois a.clos { background: #f0fdf4; border-color: #bbf7d0; }

.tb-pilote { background: #f0fdf4; border-color: #bbf7d0; }

/* Le conseiller (conseiller.php) et sa carte du tableau de bord. */
.conseil-humeur { font-size: 16px; margin: 0; }
.conseil-groupe { margin: 22px 0 8px; font-size: 17px; }
.conseil-cartes { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 12px; }
.conseil-carte { border-left: 4px solid var(--border); margin: 0; }
.conseil-carte h3 { margin: 0 0 6px; font-size: 15px; }
.conseil-carte p { font-size: 13.5px; margin: 0 0 10px; }
.conseil-carte.conseil-bravo, .conseil-groupe.conseil-bravo { border-left-color: #15803d; }
.conseil-carte.conseil-attention { border-left-color: #d97706; }
.conseil-carte.conseil-conseil { border-left-color: #2563eb; }
.tb-conseiller { background: #faf5ff; border-color: #e9d5ff; }
.tb-conseiller-tete { display: flex; justify-content: space-between; align-items: center; gap: 8px; flex-wrap: wrap; }
.tb-conseil { font-size: 13.5px; padding: 3px 0; }

/* La fenêtre « Nouveau client » (includes/modal_client.php), en blocs comme la fiche. */
.modal .mc-bloc { padding: 14px 0; border-top: 1px solid var(--border); }
.modal-body > .flash + .mc-bloc, .modal-body > .mc-bloc:first-child { border-top: 0; padding-top: 0; }
.modal .mc-bloc .field { margin-bottom: 12px; }
.modal .mc-bloc h3 { margin: 0 0 10px; font-size: 16px; }
.modal .mc-bloc .field:last-child { margin-bottom: 0; }
.modal .mc-aide { font-size: 12.5px; margin: 8px 0 0; }
.modal .choix-type label { flex-basis: 220px; }
@media (max-width: 600px) {
  .modal-backdrop { padding: 0; }
  .modal { border-radius: 0; min-height: 100%; }
  .modal .grid2, .modal .grid3 { grid-template-columns: 1fr; gap: 0; }
  .modal .mc-ville { grid-template-columns: 1fr 2fr; gap: 0 8px; }
  .modal .mc-ville .field:last-child { grid-column: 1 / -1; }
  .modal-foot { position: sticky; bottom: 0; background: #fff; }
  .modal-foot .btn { flex: 1; }
}
/* Le bouton choisi se voit partout, sans script propre à chaque écran. */
.choix-type label:has(input:checked) { border-color: var(--primary); background: #eff6ff; }
/* Téléphone : un formulaire se lit sur UNE colonne. Les grilles de champs
   (.field) passent à une colonne ; les grilles de tuiles, elles, gardent leurs
   deux colonnes (27/09/2026 — le client et l'adresse de livraison du devis
   étaient coupés à mi-mot sur un iPhone). */
@media (max-width: 520px) {
  .grid2:has(> .field), .grid3:has(> .field), .grid4:has(> .field), .grid5:has(> .field) { grid-template-columns: 1fr; gap: 0; }
}
/* Téléphone : les dates libres d'une barre de période tiennent sur UNE ligne
   pleine largeur (« du » ▢ « au » ▢ Voir), au lieu d'une cellule de grille
   où « Tout » gonflait à côté d'elles. Vaut pour toutes les barres de période. */
@media (max-width: 900px) {
  .actions-bar > form:has(input[type=date]) { grid-column: 1 / -1; display: flex !important; flex-wrap: wrap; align-items: center; gap: 6px; margin-left: 0 !important; }
  .actions-bar > form:has(input[type=date]) input[type=date] { flex: 1 1 120px; min-width: 0; }
  .actions-bar > form:has(input[type=date]) .btn { width: auto !important; }
  .actions-bar > span.muted { grid-column: 1 / -1; }
}

/* N° de série d'une ligne : discret, montré quand la ligne est en main ou quand il est rempli. */
#linesTable input.serie { display: block; width: 100%; margin-top: 3px; font-size: 12px; padding: 3px 6px; border: 1px dashed var(--border, #cbd5e1); background: transparent; }
#linesTable tr:not(:focus-within) input.serie:placeholder-shown { display: none; }
#linesTable input.serie[hidden] { display: none; }

/* Dépôt de factures : ce qui attend le clic, et l'alerte de dossier (29/09/2026). */
.depot-pret { margin: 10px 0; padding: 10px 12px; border: 2px solid #22c55e; background: #f0fdf4; border-radius: 10px; font-size: 13.5px; font-weight: 600; }
.depot-alerte { color: #b91c1c; margin-top: 6px; }

/* BARRE D'ACTIONS D'UNE PIÈCE EN TUILES (05/10/2026) : au bureau, chaque bouton
   qui porte une icône la montre en grand, son nom en petit dessous — la barre
   tenait sur deux lignes de texte, elle tient sur une. Les libellés restent
   ceux du guide (« Envoyer par mail »…), sur deux lignes au besoin. Les boutons
   sans icône (Valider, Appliquer, → Avoir, Supprimer) gardent leur forme : ce
   sont des décisions, pas des outils. Le téléphone garde sa grille. */
@media screen and (min-width: 901px) {
  .actions-bar { gap: 6px; }
  .actions-bar .btn:has(> svg) {
    flex-direction: column; justify-content: center; gap: 5px;
    min-width: 76px; max-width: 104px; padding: 8px 8px 7px;
    font-size: 11.5px; line-height: 1.2; text-align: center; white-space: normal;
    border-radius: 9px; font-family: inherit;
  }
  .actions-bar .btn:has(> svg) svg { width: 20px; height: 20px; }
  /* Le menu des statuts prenait toute la largeur de son option la plus longue
     et poussait « Appliquer » dessous : « → Avoir » restait seul, décalé. Les
     formulaires de la barre s'alignent comme les boutons. */
  .actions-bar > form { display: inline-flex !important; align-items: center; gap: 6px; margin: 0; }
  .actions-bar #formStatut select { width: auto; max-width: 210px; margin: 0; }
  /* Deux rangées voulues : les outils, puis les décisions (destinataire,
     statut, Valider, transformations). Laissé au hasard du retour à la ligne,
     « → Avoir » tombait seul sous la barre. */
  .actions-bar .act-saut { flex-basis: 100%; height: 0; }
  .actions-bar .btn.secondary:has(> svg) { border-color: transparent; background: transparent; }
  .actions-bar .btn.secondary:has(> svg):hover { background: #eef3ff; color: var(--primary); }
}

/* Droits d'accès par zone (utilisateurs.php). */
.droits-compte { border-top: 1px solid var(--border); padding: 14px 0; }
.droits-tete { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 10px; }
.droits-profils { margin-left: auto; display: inline-flex; align-items: center; gap: 6px; font-size: 13px; color: var(--muted); }
.droits-zones { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 8px 16px; margin-bottom: 10px; }
.droits-zone { display: flex; gap: 8px; align-items: flex-start; font-size: 13.5px; line-height: 1.35; cursor: pointer; }
.droits-zone input { margin-top: 3px; }

/* Le message d'une action, recopié en bas de l'écran quand la page revient sur
   une ligne (includes/header.php) : sinon il restait hors de vue. */
.flash-bandeau { position: fixed; left: 50%; bottom: 16px; transform: translateX(-50%); z-index: 1200;
  width: min(640px, calc(100vw - 24px)); display: flex; flex-direction: column; gap: 8px; }
.flash-bandeau .flash { margin: 0; padding-right: 40px; position: relative; box-shadow: 0 8px 24px rgba(15, 23, 42, .18); }
.flash-fermer { position: absolute; top: 6px; right: 8px; border: 0; background: none; font-size: 20px; line-height: 1;
  cursor: pointer; color: inherit; padding: 2px 6px; }


/* ---------- Paramètres en onglets (lot 3, 09/10/2026) ----------
   Les blocs cachés le sont par l'attribut hidden ; « !important » parce que
   .card et la carte « Présentation » (style en ligne) fixent leur display. */
[data-onglet][hidden], .field[data-module-eteint][hidden] { display: none !important; }
.param-onglets { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin: 4px 0 16px;
  position: sticky; top: 0; z-index: 5; background: var(--bg, #f5f6f8); padding: 8px 0; }
.param-onglet { border: 1px solid var(--border); background: #fff; color: var(--text); border-radius: 18px;
  padding: 6px 14px; font-size: 13.5px; cursor: pointer; }
.param-onglet.actif { background: var(--primary); border-color: var(--primary); color: #fff; }
#paramRecherche { margin-left: auto; width: 240px; max-width: 100%; }
.param-enregistrer { position: sticky; bottom: 0; z-index: 5; display: flex; gap: 12px; align-items: center;
  padding: 10px 14px; margin: 0 -2px 16px; background: #fff; border: 1px solid var(--border);
  border-radius: 10px; box-shadow: 0 -4px 14px rgba(15, 23, 42, .06); }
@media screen and (max-width: 700px) { #paramRecherche { margin-left: 0; width: 100%; } }

/* Fenêtre de confirmation de DevFac (assets/fenetre.js, lot 4, 09/10/2026). */
.fenetre-devfac { z-index: 1000; }
.fenetre-devfac .modal-body p { margin: 0 0 10px; line-height: 1.5; }
.fenetre-champ { display: flex; flex-direction: column; gap: 4px; font-size: 13px; margin-top: 6px; }
.fenetre-erreur { color: #b91c1c; font-size: 13px; }

/* Fiche d'une pièce, au bureau (lot 5, 09/10/2026) : les gestes rares
   (Factur-X, XML, Duplicata, Reprendre en devis, Ticket) sous « Plus d'actions ». */
@media screen and (min-width: 901px) {
  .actions-bar .act-autre { display: none !important; }
  .actions-bar.tout .act-autre { display: inline-flex !important; }
  .actions-bar:has(.act-autre) .act-toggle { display: inline-flex; align-items: center; }
}

/* Formulaire de pièce : coûts d'achat masquables (lot 5, 09/10/2026). Cachées,
   les cellules restent dans le formulaire et sont postées. */
.cout-bascule { display: inline-flex; gap: 6px; align-items: center; font-size: 13px; margin: 0 0 6px; color: var(--muted); }
.lines-table.sans-couts .achat-col { display: none !important; }
.internal-totals.sans-couts { display: none !important; }

/* CIBLES AU DOIGT (lot 5, 09/10/2026) : « Suppr. » à côté de « Voir » faisait
   24 px de haut, l'étoile des favoris 14 px collée au lien. Sous 900 px, tout
   bouton fait au moins 40 px, l'étoile une zone de 36 px. */
@media screen and (max-width: 900px) {
  .btn, .btn.small, .table-liste .btn.small { min-height: 40px; }
  .echeance-raccourcis .btn { padding: 6px 10px; }
  .nav-etoile { min-width: 36px; min-height: 36px; font-size: 16px; display: inline-flex; align-items: center; justify-content: center; opacity: .6; }
}

/* Onglets d'un écran (assets/onglets.js, lot 5, 09/10/2026). */
.onglets-barre { display: flex; flex-wrap: wrap; gap: 6px; margin: 4px 0 16px; }
.onglets-barre .onglet { border: 1px solid var(--border); background: #fff; color: var(--text); border-radius: 18px;
  padding: 6px 14px; font-size: 13.5px; cursor: pointer; }
.onglets-barre .onglet b { display: inline-block; margin-left: 4px; padding: 0 6px; border-radius: 9px; background: var(--danger); color: #fff; font-size: 11.5px; }
.onglets-barre .onglet.actif { background: var(--primary); border-color: var(--primary); color: #fff; }
[data-onglet][hidden] { display: none !important; }

/* Carte « Connexions » du tableau de bord (09/10/2026). */
.tb-connexions h2 { margin: 0 0 6px; }
.tb-cx-ok { color: #006300; margin: 0; }
.tb-cx-alerte { margin: 0; color: #92400e; line-height: 1.6; }
.tb-cx-liste { list-style: none; margin: 0; padding: 0; font-size: 13px; line-height: 1.6; }
@media screen and (max-width: 900px) { .tb .tb-connexions { order: 7; } }

.tb-connexions.tb-cx-rouge { border-left: 4px solid #b91c1c; background: #fef2f2; }
.tb-cx-titre { margin: 0 0 6px; font-weight: 600; color: #991b1b; }

/* Statuts des commandes fournisseurs (cf_badge(), 09/10/2026). */
.badge.cf-brouillon { background: #f1f5f9; color: #475569; }
.badge.cf-envoyee   { background: #ffedd5; color: #9a3412; }
.badge.cf-confirmee { background: #dcfce7; color: #166534; }
.badge.cf-partielle { background: #dbeafe; color: #1e40af; }
.badge.cf-recue     { background: #e5e7eb; color: #374151; }
.badge.cf-annulee   { background: #fee2e2; color: #991b1b; text-decoration: line-through; }

/* Fiche d'une commande fournisseur : confirmation et livraison annoncée (09/10/2026). */
.cf-confirmation.attente { border-left: 4px solid #ea580c; background: #fff7ed; }
.cf-confirmation.ok { border-left: 4px solid #16a34a; background: #f0fdf4; }
.cf-conf-form { display: flex; flex-wrap: wrap; gap: 10px 16px; align-items: center; }
.cf-conf-form label { display: inline-flex; gap: 6px; align-items: center; font-size: 13px; }
.cf-conf-form input[type="date"] { width: auto; }

/* Un nombre illisible (assets/saisie_nombre.js) : signalé en rouge jusqu'à correction. */
input.nombre-invalide { border-color: #c0392b !important; background: #fdecea !important; }
