/* ERP L'Épaulard, charte « salle des cartes » : ligne claire, encre marine
   sur papier, angles droits, aplats francs. Les quatre statuts d'une commande
   suivent son avancement, du chaud au froid : AMBRE tant qu'elle attend le
   message du client, VERT une fois confirmée, BLEU une fois partie, ENCRE une
   fois facturée. Le seul ton chaud de la grille est celui qui demande une
   action. */

/* Polices embarquées dans l'application : rien n'est appelé depuis un serveur
   extérieur, la saisie doit tenir hors ligne. Un seul fichier variable par
   famille couvre toutes les graisses. Le repli sur la pile du système est
   conservé au cas où un fichier manquerait. */
@font-face {
  font-family: "Geist"; src: url("fonts/Geist-Variable.woff2") format("woff2");
  font-weight: 100 900; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Geist Mono";
  src: url("fonts/GeistMono-Variable.woff2") format("woff2");
  font-weight: 100 900; font-style: normal; font-display: swap;
}

:root {
  --papier: #f6f4ee;
  --carte: #fffdf8;
  --encre: #14213d;
  --encre-2: #3d4a6b;
  --muet: #5f6880;            /* AA sur papier et carte */
  --trait: #14213d;
  --trait-fin: #cfd3de;
  --teal: #007479;
  --teal-clair: #e3f1f1;
  --jaune: #f7c948;
  --jaune-fond: #fdf3d7;
  --vert: #2e7d5b;
  --vert-texte: #256349;
  --vert-fond: #e2f0e9;
  --rouge: #c0392b;
  --rouge-fond: #f9e5e2;
  /* Statuts d'une commande. Séparation vérifiée au validateur de palette :
     la paire la plus proche tient un écart de 18,6 en deutéranopie et de
     19,5 en vision normale, pour un seuil de 8. Le teal reste la seule
     couleur d'interface, il ne désigne plus aucun statut. */
  --st-prev: #e9a400;  --st-prev-fond: #fdf1d5;  --st-prev-texte: #6d4c00;
  --st-val:  #2e7d5b;  --st-val-fond:  #e2f0e7;  --st-val-texte:  #1f5b41;
  --st-liv:  #3a7bd5;  --st-liv-fond:  #e4ecfa;  --st-liv-texte:  #1d4e97;
  --st-fac:  #2b3a5c;  --st-fac-fond:  #e5e8ef;  --st-fac-texte:  #2b3a5c;
  /* espacement (base 4) et échelle typographique */
  --e1: 4px; --e2: 8px; --e3: 12px; --e4: 16px; --e5: 24px; --e6: 32px;
  --t-micro: 12px; --t-petit: 14px; --t-base: 17px;
  --t-titre: 26px; --t-chiffre: 30px;
  --sans: "Geist", "Segoe UI", "Helvetica Neue", Arial, sans-serif;
  --mono: "Geist Mono", Consolas, "Cascadia Mono", monospace;
  /* largeur du menu latéral et affichage de ses libellés : les deux vont
     ensemble, un rail replié n'affiche que ses repères. */
  --rail: 216px; --lbl: block;
}

/* Sous 1500 px le menu se replie de lui-même : la matrice de la semaine a
   besoin de toute la largeur. Le choix fait sur le poste l'emporte ensuite. */
@media (max-width: 1500px) { :root { --rail: 64px; --lbl: none; } }
html[data-rail="ouvert"] { --rail: 216px; --lbl: block; }
html[data-rail="replie"] { --rail: 64px; --lbl: none; }

* { box-sizing: border-box; }

html { scroll-behavior: smooth; scroll-padding-top: 20px; }

body {
  margin: 0; min-height: 100vh;
  display: grid; grid-template-columns: var(--rail) 1fr;
  background: var(--papier);
  color: var(--encre);
  font-family: var(--sans);
  font-size: var(--t-base);
  line-height: 1.45;
}

/* Une colonne de grille prend par défaut la largeur de son contenu : sans
   min-width nul, un tableau large pousserait toute la page. */
.zone { min-width: 0; }

main { max-width: 1240px; margin: 0 auto; padding: 20px 24px 80px; }
main.large { max-width: 1900px; }

/* Les capitales sont réservées aux badges d'état. Un titre se lit en casse
   normale : la hiérarchie tient à la taille, à la graisse et au filet. */
h1 { font-size: var(--t-titre); margin: 18px 0 6px; letter-spacing: -.4px;
     font-weight: 650; }
h2 {
  font-size: 19px; letter-spacing: -.15px; color: var(--encre);
  margin: 30px 0 12px; font-weight: 600;
  border-bottom: 1px solid var(--trait-fin); padding-bottom: 7px;
}
h2:first-child { margin-top: 10px; }
h1, h2, h3 { text-wrap: balance; }
p { text-wrap: pretty; }
/* Un titre qui porte une date : majuscule au premier mot seulement, jamais à
   chaque mot. « Jeudi 6 août 2026 », pas « Jeudi 6 Août 2026 ». */
.titre-date::first-letter { text-transform: uppercase; }

.sous-titre { color: var(--muet); margin: 0 0 14px; }
.discret { color: var(--muet); }
.alerte-texte { color: var(--rouge); font-weight: 700; }
.vert-texte { color: var(--vert-texte); font-weight: 700; }

/* D7 : un écran de synthèse se lit en phrases avant de se lire en tableaux. */
.phrase { font-size: 19px; line-height: 1.5; margin: 0 0 8px; }

/* Focus : teal plein (5,47:1 sur papier), jamais supprimé, jamais délavé.
   Au clavier seulement (:focus-visible) pour ne pas encadrer chaque clic. */
:focus-visible { outline: 3px solid var(--teal); outline-offset: 2px; }
.rail :focus-visible { outline-color: var(--jaune); }
:target { outline: 3px solid var(--teal); outline-offset: -3px; }

/* ---------------- menu latéral ----------------
   Le menu tient toute la hauteur à gauche et suit le défilement. Replié, il
   ne montre plus que ses repères et rend 152 px à la zone de travail. */
.evitement {
  position: absolute; left: -9999px; top: 0; z-index: 20;
  background: var(--encre); color: #fff; padding: 10px 18px; font-weight: 600;
}
.evitement:focus { left: 0; }

/* Un élément marqué `hidden` reste caché même quand une classe lui impose un
   mode d'affichage : sans cette règle, une pastille masquée par le script
   continuerait de s'afficher (la classe l'emporte sur la feuille du
   navigateur). */
[hidden] { display: none !important; }

.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
/* Les propriétés de tracé sont posées sur l'élément qui appelle le repère :
   elles seules descendent dans le contenu cloné. */
.ic {
  width: 20px; height: 20px; flex: none; fill: none; stroke: currentColor;
  stroke-width: 1.7; stroke-linecap: square; stroke-linejoin: miter;
}

.rail {
  position: sticky; top: 0; align-self: start; z-index: 5;
  height: 100vh; width: var(--rail); overflow: hidden;
  display: flex; flex-direction: column;
  background: var(--encre); color: #c9cee0;
  border-right: 3px solid var(--teal);
}
.rail-marque {
  display: flex; align-items: center; gap: 11px; flex: none;
  padding: 16px 18px 15px; border-bottom: 1px solid rgba(255, 255, 255, .13);
}
.brand-mark { width: 24px; height: 24px; flex: none; color: #f2f0e9; }
.brand-texte { display: var(--lbl); white-space: nowrap; }
.brand-nom { display: block; font-weight: 700; letter-spacing: 2.5px;
             font-size: 16px; color: #f2f0e9; }
.brand-sub { display: block; font-size: 11px; color: #8f99b5; margin-top: 2px; }

.rail-nav { display: flex; flex-direction: column; padding: 10px 0;
            overflow-y: auto; }
.rail-nav a {
  display: flex; align-items: center; gap: 12px; white-space: nowrap;
  padding: 9px 18px; color: #c9cee0; text-decoration: none; font-size: 15px;
  border-left: 4px solid transparent;
  transition: background-color .14s, color .14s, border-color .14s;
}
.rail-nav a b { display: var(--lbl); font-weight: 500; }
.rail-nav a:hover { background: rgba(255, 255, 255, .07); color: #fff; }
.rail-nav a.actif {
  background: rgba(0, 116, 121, .32); border-left-color: var(--teal);
  color: #fff;
}
.rail-nav a.actif b { font-weight: 600; }

.rail-pied {
  margin-top: auto; flex: none; padding: 12px 14px 14px;
  border-top: 1px solid rgba(255, 255, 255, .13);
}
.rail-date {
  display: var(--lbl); font-size: 12.5px; color: #8f99b5; white-space: nowrap;
  margin-bottom: 8px;
}
.rail-date::first-letter { text-transform: uppercase; }
/* Compte connecté : il disparaît avec les libellés quand le rail se replie,
   comme la date au-dessus. */
.rail-compte {
  display: var(--lbl); font-size: 12.5px; color: #8f99b5; white-space: nowrap;
  margin-bottom: 8px;
}
.rail-compte b { display: block; color: #f2f0e9; font-weight: 600; }
.rail-compte a { color: #8f99b5; text-decoration: none; }
.rail-compte a:hover { color: #fff; text-decoration: underline; }
.rail-bascule {
  display: flex; align-items: center; gap: 12px; width: 100%;
  background: none; border: 1px solid transparent; color: #8f99b5;
  font: inherit; font-size: 13.5px; padding: 5px 3px; cursor: pointer;
  transition: color .14s, border-color .14s;
}
.rail-bascule b { display: var(--lbl); font-weight: 500; }
.rail-bascule:hover { color: #fff; border-color: rgba(255, 255, 255, .25); }
.rail-bascule .ic { width: 18px; height: 18px; margin: 0 1px; }
/* Le chevron pointe vers ce que le clic va faire : refermer, ou rouvrir. */
@media (max-width: 1500px) { .rail-bascule .ic { transform: rotate(180deg); } }
html[data-rail="replie"] .rail-bascule .ic { transform: rotate(180deg); }
html[data-rail="ouvert"] .rail-bascule .ic { transform: none; }

/* ---------------- mode consultation (atelier) ---------------- */
.bandeau-atelier {
  background: var(--jaune); color: #3a2c00; font-weight: 500;
  padding: 9px 24px; border-bottom: 2px solid #b9931f;
}
.bandeau-atelier b { text-transform: uppercase; letter-spacing: 1.5px;
                     font-size: 13px; font-weight: 700; }
.bandeau-atelier a { color: #3a2c00; margin-left: 10px; font-weight: 700; }
body.mode-atelier { background: #efeade; }
body.mode-atelier .rail { border-right-color: var(--jaune); }

/* ---------------- page d'erreur ---------------- */
.page-erreur { max-width: 640px; margin-top: 40px; }
.page-erreur h1 { margin-top: 0; }
.erreur-code {
  font-family: var(--mono); font-size: 52px;
  font-weight: 700; color: var(--teal); line-height: 1;
}
.erreur-aide { color: var(--encre-2); padding-left: 20px; }
.erreur-aide li { margin: 4px 0; }

.flashs { max-width: 1240px; margin: 14px auto 0; padding: 0 24px; }
.flash {
  border: 2px solid var(--teal); background: var(--teal-clair);
  color: var(--encre); padding: 10px 16px; margin-bottom: 6px; font-weight: 600;
}
.flash::before { font-weight: 700; margin-right: 8px; }
.flash-succes { background: var(--vert-fond); border-color: var(--vert); }
.flash-succes::before { content: "✓"; color: var(--vert-texte); }
.flash-erreur { background: var(--rouge-fond); border-color: var(--rouge); }
.flash-erreur::before { content: "✕"; color: var(--rouge); }
.flash a { color: var(--teal); font-weight: 700; }

/* ---------------- bandeau checklist ---------------- */
.checklist {
  border: 2px solid var(--jaune); background: var(--jaune-fond);
  padding: 10px 16px; margin: 12px 0 6px;
}
.checklist ul { margin: 4px 0 0; padding-left: 20px; }
.checklist b { font-size: 14.5px; font-weight: 700; }

/* Bandeau de veille de jour férié. */
.bandeau-ferie {
  border: 2px solid var(--rouge); background: var(--rouge-fond);
  padding: 10px 16px; margin: 12px 0 6px; line-height: 1.5;
}
.etiq-ferie {
  border: 2px solid var(--rouge); color: var(--rouge); background: var(--rouge-fond);
  font-weight: 700; font-size: 13px; padding: 3px 10px; white-space: nowrap;
}

/* Contrôle « livré jamais facturé », regroupé par client. */
.groupe-oublis { border-bottom: 1px solid var(--trait-fin); padding: 6px 0; }
.groupe-oublis:last-of-type { border-bottom: none; }
.groupe-oublis > summary { cursor: pointer; padding: 4px 2px; }
.groupe-oublis > summary:hover { color: var(--teal); }
.groupe-oublis table { margin-top: 6px; }

/* ---------------- cartes & tableaux ---------------- */
.carte {
  background: var(--carte); border: 2px solid var(--trait);
  padding: 16px 18px; margin-bottom: 20px;
}
.carte.legere { border-color: var(--trait-fin); }
.carte.rouge { border-color: var(--rouge); }
/* Largeurs de colonnes récurrentes : des classes, pas des styles posés ligne à
   ligne dans les gabarits. */
.col-barre { width: 32%; }
.col-barre-mince { width: 18%; }
.tab-large { max-width: 1100px; }
.tab-doc { max-width: 760px; }

/* Matrice des tarifs d'un client : la colonne qui facture aujourd'hui est
   encadrée, celles qui prendront effet plus tard restent en retrait et
   portent la croix qui les retire. Les anciennes ne se distinguent pas :
   c'est de l'historique, il ne demande rien. */
.tab-tarifs { width: auto; min-width: 420px; max-width: none; }
.tab-tarifs th, .tab-tarifs td { min-width: 96px; }
.tab-tarifs th.col-vigueur, .tab-tarifs td.col-vigueur {
  background: var(--teal-clair);
  box-shadow: inset 2px 0 0 var(--teal), inset -2px 0 0 var(--teal);
}
.tab-tarifs th.col-vigueur { box-shadow: inset 2px 2px 0 var(--teal),
                                         inset -2px 0 0 var(--teal); }
.tab-tarifs tr:last-child td.col-vigueur {
  box-shadow: inset 2px 0 0 var(--teal), inset -2px -2px 0 var(--teal);
}
.tab-tarifs th.col-futur, .tab-tarifs td.col-futur { color: var(--muet); }
.tab-tarifs th.col-futur b, .tab-tarifs td.col-futur b { font-weight: 600; }
.col-etat {
  display: block; font-size: 10.5px; font-weight: 700; letter-spacing: 1px;
  text-transform: uppercase; color: var(--teal);
}
.tab-tarifs th form { display: inline-block; margin-left: 4px; }
/* Saisie d'un barème complet : la table reste étroite, c'est une colonne de
   prix, pas un tableau de lecture. */
.tab-saisie { max-width: 420px; margin-bottom: 14px; }
.tab-saisie td { padding: 4px 10px; }
.tab-saisie .discret { margin-left: 4px; }

table { border-collapse: collapse; width: 100%; }
th {
  text-align: left; font-size: 13px; font-weight: 600; color: var(--muet);
  border-bottom: 2px solid var(--trait); padding: 8px 10px;
}
/* Tout est centré sur la hauteur de la ligne : un bouton et le texte d'à côté
   doivent se lire sur le même axe, même quand un nom passe sur deux lignes. */
td { padding: 8px 10px; border-bottom: 1px solid var(--trait-fin);
     vertical-align: middle; }
tbody tr:last-child td { border-bottom: none; }
/* Un nombre ne se coupe jamais en deux lignes : « 33 959,25 € » réparti sur
   trois rangs est illisible, et c'est la colonne qu'il faut élargir, pas le
   chiffre qu'il faut plier. La colonne s'ajuste d'elle-même au plus long. */
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums;
                 white-space: nowrap; }
td.num { font-family: var(--mono); font-size: 16px; }
/* Un chemin de dossier est un seul mot que le navigateur ne coupe nulle part :
   posé dans une cellule de chiffres, il pousse la carte au-delà de la page. */
td.chemin, .chemin { white-space: normal; overflow-wrap: anywhere;
                     word-break: break-all; }
/* Même règle pour les libellés courts qui font sens d'un bloc : une date, un
   numéro de pièce, un taux. */
td.insecable, th.insecable { white-space: nowrap; }
.total-row td {
  border-top: 2px solid var(--trait); font-weight: 700; background: #f1efe7;
}

/* ---------------- listes triables et filtrables ----------------
   L'en-tête d'une colonne triable se signale au survol et au clavier ; la
   place du repère est réservée en permanence pour que le tri ne fasse pas
   sauter la largeur des colonnes. */
.triable th.tri-actif { cursor: pointer; -webkit-user-select: none; user-select: none; }
.triable th.tri-actif:hover { color: var(--teal); }
.triable th.tri-actif::after {
  content: "▾"; margin-left: 6px; font-size: 11px; color: transparent;
}
.triable th.tri-actif:hover::after,
.triable th.tri-actif:focus::after { color: var(--trait-fin); }
/* Le repère de tri en cours passe avant le repère de survol : même poids de
   sélecteur, posé après. */
.triable th.tri-actif[aria-sort="ascending"]::after { content: "▲"; color: var(--teal); }
.triable th.tri-actif[aria-sort="descending"]::after { content: "▼"; color: var(--teal); }

/* Barre de filtres d'une liste de documents : les champs sur une ligne, le
   compte et le choix du nombre de lignes en pied. */
.filtres {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: 12px 16px;
  margin-bottom: 16px;
}
.filtres input[name="q"] { width: 220px; }
.filtres select { min-width: 130px; }
[data-liste].en-cours { opacity: .85; }

/* Menu de clients à cocher : une seule ligne fermée, un panneau qui se pose
   par-dessus le reste quand on l'ouvre. La recherche filtre la liste, les
   clients déjà cochés restent visibles pour pouvoir être décochés. */
.choix { position: relative; }
.choix > summary {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  width: 250px; padding: 7px 10px; cursor: pointer;
  border: 2px solid var(--trait); background: #fff; list-style: none;
  font-size: var(--t-base);
}
.choix > summary::-webkit-details-marker { display: none; }
.choix > summary:hover { border-color: var(--teal); }
.choix-resume { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.choix-fleche { width: 14px; height: 14px; flex: none; color: var(--muet);
                transform: rotate(-90deg); }
.choix[open] > summary { border-color: var(--teal); }
.choix[open] .choix-fleche { transform: rotate(90deg); }
.choix-panneau {
  position: absolute; z-index: 8; top: 100%; left: 0; width: 250px;
  background: var(--carte); border: 2px solid var(--teal); border-top: none;
  padding: 8px; box-shadow: 0 6px 14px rgba(20, 33, 61, .12);
}
.choix-filtre { width: 100%; padding: 5px 8px; font-size: 14.5px; }
.choix-liste { max-height: 236px; overflow-y: auto; margin: 6px 0 0; }
.choix-item {
  display: flex; align-items: center; gap: 8px; padding: 3px 4px;
  font-size: 14.5px; cursor: pointer;
}
.choix-item:hover { background: var(--teal-clair); }
.choix-item input { margin: 0; flex: none; }
.choix-item span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.choix-pied {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 8px; margin-top: 6px; padding-top: 6px; font-size: 13px;
  border-top: 1px solid var(--trait-fin);
}
.lien-bouton {
  background: none; border: none; padding: 0; font: inherit; font-size: 13px;
  color: var(--teal); cursor: pointer; text-decoration: underline;
}
.filtres-pied {
  flex: 1 0 100%; display: flex; flex-wrap: wrap; gap: 10px 20px;
  align-items: baseline; justify-content: space-between;
  border-top: 1px solid var(--trait-fin); padding-top: 10px; font-size: 14px;
}
.taille { color: var(--muet); }
.taille a {
  color: var(--teal); text-decoration: none; padding: 1px 6px;
  border: 1px solid transparent;
}
.taille a:hover { border-color: var(--teal); }
.taille a.actif {
  background: var(--encre); color: #fff; border-color: var(--encre);
  font-weight: 600;
}

.filtre-tab { display: flex; align-items: center; gap: 10px; margin: 0 0 10px; }
.filtre-champ { width: 240px; padding: 5px 9px; font-size: 15px; }
.filtre-compte { font-size: 13px; font-variant-numeric: tabular-nums; }

.vide {
  padding: 26px 20px; text-align: center; color: var(--encre-2);
  border: 2px dashed var(--trait-fin);
}
.vide b { color: var(--encre); }

/* ---------------- cellules éditables (façon tableur) ---------------- */
.cellule {
  border: 2px solid transparent; background: none; width: 76px;
  text-align: right; font: inherit; padding: 4px 6px;
  font-family: var(--mono); font-size: 16px;
}
.cellule.texte { text-align: left; width: 170px; font-family: inherit;
                 font-size: 15px; }
.cellule:hover { border-color: var(--trait-fin); background: #fff; }
.cellule:focus { border-color: var(--teal); background: #fff; }
.cellule:focus-visible { outline: 3px solid var(--teal); outline-offset: 1px; }
.btn-ok {
  background: none; border: 2px solid transparent; color: var(--teal);
  font-weight: 700; cursor: pointer; padding: 4px 8px; font-size: 15px;
}
.btn-ok:hover { border-color: var(--teal); }

/* ---------------- statuts ---------------- */
.chip {
  display: inline-block; padding: 4px 12px; font-size: 13px; font-weight: 700;
  letter-spacing: .8px; text-transform: uppercase; border: 2px solid;
  background: none; cursor: pointer; font-family: inherit; min-height: 28px;
}
.chip-previsionnel { background: var(--st-prev-fond); border-color: var(--st-prev); color: var(--st-prev-texte); }
.chip-valide { background: var(--st-val-fond); border-color: var(--st-val); color: var(--st-val-texte); }
.chip-livre { background: var(--st-liv-fond); border-color: var(--st-liv); color: var(--st-liv-texte); }
.chip-facture { background: var(--st-fac-fond); border-color: var(--st-fac); color: var(--st-fac-texte); }
button.chip:hover { filter: brightness(.95); }
.chip-fixe { cursor: default; }

/* Une légende dit ce que les repères signifient. Elle ne raconte pas comment
   se servir de l'écran : ça, ça s'apprend en s'en servant. */
.legende { font-size: 13.5px; color: var(--muet); margin: 8px 0 18px;
           display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.legende .chip { cursor: default; }
.legende b { color: var(--encre-2); font-weight: 600; }
.leg-sep { width: 1px; height: 15px; background: var(--trait-fin);
           margin: 0 6px; flex: none; }

/* ---------------- ce qui manque sur une fiche ----------------
   Une étiquette dit ce qui n'est pas renseigné, son infobulle dit ce que
   l'absence empêche. Le tarif est le seul manque qui bloque une facture
   aujourd'hui : il est le seul en rouge. */
.tag {
  display: inline-block; font-size: 12px; font-weight: 600; padding: 1px 8px;
  border: 1px solid var(--trait-fin); background: var(--papier);
  color: var(--encre-2); margin: 1px 4px 1px 0; white-space: nowrap;
  cursor: help;
}
.tag-tarif { border-color: var(--rouge); background: var(--rouge-fond);
             color: var(--rouge); font-weight: 700; }

.bandeau-manques {
  border: 2px solid var(--trait-fin); background: var(--carte);
  border-left: 8px solid var(--jaune); padding: 10px 16px; margin: 12px 0 18px;
}
.bandeau-manques.bloquant { border-left-color: var(--rouge); }
.bandeau-manques b { font-size: 15px; }
.bandeau-manques ul { margin: 6px 0 0; padding-left: 20px; font-size: 14.5px; }
.bandeau-manques li { margin: 3px 0; color: var(--encre-2); }

/* ---------------- pilotage : le fil rouge ----------------
   Un sommaire ancré, quatre sections numérotées, une phrase d'introduction
   par section. La page se parcourt du haut vers le bas, dans l'ordre. */
.sommaire {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--e3);
  margin: 16px 0 8px;
}
@media (max-width: 980px) { .sommaire { grid-template-columns: repeat(2, 1fr); } }
.somm-item {
  display: block; text-decoration: none; color: var(--encre);
  background: var(--carte); border: 2px solid var(--trait);
  border-left: 8px solid var(--teal); padding: 10px 14px;
}
.somm-item:hover { background: var(--teal-clair); }
.somm-item.somm-alerte { border-left-color: var(--rouge); }
.somm-titre {
  display: block; font-size: 13px; color: var(--muet); font-weight: 600;
}
.somm-chiffre {
  display: block; font-size: 19px; font-weight: 700; margin-top: 3px;
  font-variant-numeric: tabular-nums;
}

.section-fil { margin-top: var(--e6); }
h2.titre-section {
  display: flex; align-items: center; gap: 10px;
  font-size: 21px; text-transform: none; letter-spacing: .2px;
  color: var(--encre); border-bottom: 3px solid var(--teal);
  padding-bottom: 8px; margin: 0 0 10px;
}
.section-num {
  background: var(--teal); color: #fff; font-size: 13px; font-weight: 700;
  width: 26px; height: 26px; line-height: 26px; text-align: center;
  flex: none;
}
.intro-section { color: var(--encre-2); margin: 0 0 16px; max-width: 78ch; }
.titre-bloc {
  font-size: 16px; margin: 0 0 8px; font-weight: 600; color: var(--encre);
}

/* les trois chiffres de tête : même hauteur, méthode collée en bas */
.trio { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--e4); }
@media (max-width: 1080px) { .trio { grid-template-columns: 1fr; } }
.chiffre-bloc {
  background: var(--carte); border: 2px solid var(--trait);
  padding: 14px 18px 16px; display: flex; flex-direction: column;
}
.chiffre-libelle {
  font-size: 13px; color: var(--muet); font-weight: 600;
}
.chiffre-val {
  font-size: var(--t-chiffre); font-weight: 700; line-height: 1.15;
  font-family: var(--mono);
  font-variant-numeric: tabular-nums; margin: 6px 0 2px;
}
.chiffre-val small {
  font-size: 15px; font-weight: 600;
  font-family: var(--sans);
}
.chiffre-compl { font-size: 15px; margin: 0 0 8px; }
.chiffre-liste { margin: 0 0 10px; padding-left: 18px; font-size: 14.5px; }
.chiffre-liste li { margin: 3px 0; }
.chiffre-note {
  font-size: 13px; color: var(--muet); margin: auto 0 0; padding-top: 8px;
}

/* largeurs de tableaux et fin de carte : des classes, pas des styles posés
   ligne à ligne dans le gabarit. */
.tab-etroite { max-width: 680px; }
.tab-moyenne { max-width: 900px; }
.tab-mini { max-width: 520px; }
.btn-calcul { margin-top: 12px; }
/* Un bloc n'a pas besoin de marge contre son propre cadre : la règle vaut pour
   toutes les cartes, elle évite autant de styles posés à la main. */
.carte > *:last-child { margin-bottom: 0; }
.carte > p:first-child { margin-top: 0; }

/* clients en retrait : un seul tableau, deux motifs */
.motif {
  display: inline-block; font-size: 11.5px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .6px; padding: 2px 8px;
  border: 2px solid; white-space: nowrap;
}
.motif-baisse { border-color: var(--rouge); color: var(--rouge); background: var(--rouge-fond); }
.motif-saison { border-color: var(--jaune); color: #7a5e00; background: var(--jaune-fond); }
.pourquoi { display: block; font-size: 14px; color: var(--encre-2); margin-top: 4px; }
.tab-retrait td { vertical-align: top; }
.sous-cellule {
  display: block; font-size: 11.5px; letter-spacing: .2px;
  font-family: var(--sans); font-weight: 400;
}

/* section repliée : la surveillance ne s'ouvre que si on la demande */
.pli { border: 2px solid var(--trait-fin); background: var(--carte); padding: 0 18px; }
.pli > summary {
  cursor: pointer; font-weight: 700; padding: 12px 0; list-style-position: outside;
}
.pli > summary:hover { color: var(--teal); }
.pli[open] > summary { border-bottom: 1px solid var(--trait-fin); }
.pli > *:last-child { margin-bottom: 14px; }

/* ---------------- grands chiffres ---------------- */
.kpis { display: flex; gap: var(--e4); flex-wrap: wrap; margin: 14px 0 22px; }
.kpi {
  background: var(--carte); border: 2px solid var(--trait);
  padding: 12px 20px 14px; min-width: 175px;
}
.kpi.accent { background: var(--encre); color: #fff; border-color: var(--encre); }
.kpi.accent .kpi-libelle { color: #aeb6cd; }
.kpi.alerte { border-color: var(--rouge); }
.kpi-libelle {
  font-size: 13px; color: var(--muet); font-weight: 600; margin-bottom: 4px;
}
.kpi-valeur {
  font-size: var(--t-chiffre); font-weight: 700;
  font-variant-numeric: tabular-nums;
  font-family: var(--mono);
}
.kpi-valeur small { font-size: 15px; font-weight: 600; }
.kpi-note { font-size: 13px; color: var(--muet); margin-top: 2px; }
.kpi.accent .kpi-note { color: #aeb6cd; }

/* ---------------- formulaires ---------------- */
input, select, textarea {
  font: inherit; color: var(--encre); background: #fff;
  border: 2px solid var(--trait); padding: 7px 10px;
}
input:focus, select:focus, textarea:focus { border-color: var(--teal); }
input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: 3px solid var(--teal); outline-offset: 1px; border-color: var(--teal);
}
/* Trois gabarits de champ, et rien d'autre. Sans eux, chaque select prend la
   largeur de sa plus longue option et la ligne devient un escalier :
   « Offert / échantillon » impose 190 px là où « on / off » en réclame 60.
   .court porte un nombre et l'aligne à droite, .moyen un choix ou un mot,
   .champ-large un nom libre. */
input.court, select.court { width: 92px; }
/* Le champ de poids par défaut d'un contenant porte le repère « à peser » :
   coupé en « à pese », il ne dit plus rien. */
.tab-reglages .cellule[name="poids_defaut"] { width: 86px; }
input.court { text-align: right; }
input.moyen, select.moyen { width: 150px; }
.champ-large input, .champ-large select { width: 230px; }
label.champ, .champ { display: flex; flex-direction: column; gap: 4px; }
.champ > span, .champ > label {
  font-size: 13.5px; color: var(--encre-2); font-weight: 600;
}
.champ-ligne { flex-direction: row !important; align-items: center; gap: 10px; }

/* Une seule hauteur de boîte dans une ligne de formulaire. Un select tire sa
   hauteur de sa police, un input de son padding : sans hauteur imposée les
   deux se décalent de deux pixels sur Chrome et de quatre sur Safari. La
   hauteur est donc posée en border-box, la même pour l'input, le select, la
   valeur en lecture seule et la case à cocher, qui n'a pas de boîte à elle. */
.form-ligne input:not([type="checkbox"]), .form-ligne select {
  box-sizing: border-box; height: 38px; line-height: 20px;
}
/* Le `gap` remplace l'espace que la mise en flex supprime : le taux et son
   marqueur deviennent deux éléments de flex, et le blanc écrit entre eux dans
   le gabarit disparaît. Le taux de perte se lisait « −32,4 %à vérifier ». */
.form-ligne .champ > b {
  display: flex; align-items: center; min-height: 38px; padding: 7px 0;
  line-height: 20px; gap: 0 .4em;
}
.form-ligne .champ-ligne { min-height: 38px; }

.btn {
  display: inline-block; font: inherit; font-weight: 700; cursor: pointer;
  background: var(--encre); color: #fff; border: 2px solid var(--encre);
  padding: 9px 20px; text-decoration: none; letter-spacing: .5px;
  min-height: 32px;
}
.btn:hover { background: var(--teal); border-color: var(--teal); }
.btn-second { background: none; color: var(--encre); }
.btn-second:hover { background: var(--teal-clair); color: var(--encre); }
/* Le retour n'est pas une action sur le document : il ouvre la barre, à
   gauche, en retrait des boutons qui agissent. */
.btn-retour {
  background: none; color: var(--muet); border-color: var(--trait-fin);
  font-weight: 600; letter-spacing: 0;
}
.btn-retour:hover { background: none; color: var(--encre);
                    border-color: var(--encre); }
.btn-petit { padding: 4px 12px; font-size: 13.5px; min-height: 28px; }
.btn-danger { background: none; color: var(--rouge); border-color: var(--rouge); }
.btn-danger:hover { background: var(--rouge-fond); }
.btn[disabled] { opacity: .45; cursor: not-allowed; }

/* Réponse au geste : la couleur d'une surface bascule en 140 ms, le clic
   enfonce d'un pixel. Rien de plus sur un outil de saisie quotidienne. */
.btn, .btn-ok, .chip, .nav-fleche, .somm-item, .plus, .croix, .bande,
.cellule, input, select, textarea, .rail-nav a, .groupe-oublis > summary,
.pli > summary, .ajout-bloc > summary, .triable th.tri-actif {
  transition: background-color .14s, border-color .14s, color .14s;
}
.btn:active, .nav-fleche:active, button.chip:active, .btn-ok:active,
.rail-bascule:active { transform: translateY(1px); }

/* Un poste réglé sur « animations réduites » ne reçoit aucune transition. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { transition-duration: .01ms !important; }
}

.form-ligne { display: flex; gap: var(--e3); align-items: flex-end; flex-wrap: wrap; }
.rang { display: flex; gap: var(--e3); flex-wrap: wrap; align-items: center; }
/* Les boutons d'action d'une ligne de tableau restent côte à côte : empilés,
   ils triplent la hauteur de chaque ligne de la liste. */
/* Serrés de moitié : dans une cellule, deux boutons voisins se lisent comme
   un seul groupe d'actions, pas comme deux colonnes. */
/* La cellule reste une vraie cellule de tableau (bordures et largeur de
   colonne intactes) : c'est le bloc intérieur qui aligne les boutons, sur une
   seule ligne, calés à droite. */
td > .rang { gap: var(--e2); flex-wrap: nowrap; justify-content: flex-end; }
td > .rang .btn { white-space: nowrap; }
/* Aucune action ne se laisse comprimer : sans cette règle, la colonne
   annonçait au tableau une largeur minimale plus petite que ses boutons, et
   « Reporter » se lisait « Re » pendant que la croix sortait de la carte. */
td > .rang > * { flex: 0 0 auto; }
td.actions { white-space: nowrap; }
/* Livrer en un geste : la quantité qui part se saisit contre le bouton qui
   émet le bon, et se lit comme un champ, pas comme un nombre affiché. */
form[data-role="livrer"] { display: flex; align-items: center; gap: 4px; }
form[data-role="livrer"] .cellule {
  width: 58px; border-color: var(--trait-fin); background: #fff;
  height: 32px;
}
/* Livrer et Reporter portent le même geste, ils ont la même hauteur : un lien
   habillé en bouton se cale sur la hauteur du bouton voisin. */
.tab-jour td.actions .btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 30px; padding: 4px 10px;
}
/* La colonne d'actions de la grille du jour porte un champ, deux boutons et
   une croix : sa largeur est garantie ici, les cellules de saisie et la note
   se resserrent d'autant pour que la rangée tienne dans la carte. */
.tab-jour td.actions, .tab-jour th.c-actions { min-width: 286px; }
/* Le numéro de bon ne se coupe jamais en deux : « M769-02 » est ce que le
   chargeur lit pour retrouver le second conditionnement d'une expédition. */
.tab-jour td[data-ligne-bl] { white-space: nowrap; }
.tab-jour .cellule[name="qte"], .tab-jour .cellule[name="poids"] { width: 40px; }
/* Le choix du lot montre son numéro en entier, flèche comprise : « M1 » à
   la place de « M149 » ne dit plus quel lot part avec le camion. */
.tab-jour select.cellule[name="lot_servi"] { width: 100%; }

/* Budget de largeur de la grille du Jour, à l'écran seulement.
   La colonne d'actions avait sa largeur garantie, mais la table entière
   dépassait sa zone de défilement de 40 à 64 px : la croix d'annulation
   partait hors champ à 1 500 comme à 1 280 px, et il fallait faire défiler la
   grille pour l'atteindre sans que rien ne l'annonce.
   Les dix colonnes se partagent désormais la largeur exacte de la carte :
   280 px pour les actions, qui portent un champ, deux boutons et une croix et
   ne se compriment jamais, et le reste au prorata pour les neuf autres. La
   somme fait 100 %, donc `scrollWidth` vaut `clientWidth` et rien n'est
   coupé. Chaque part est calée sur ce que sa colonne ne peut pas plier,
   mesuré sur une semaine de journées réelles : « PRÉVISIONNEL » pour le
   statut, « 7 754,00 » pour les kilos, « M769-02 » pour le bon.
   Le plancher de 1 128 px de la table est la largeur en deçà de laquelle une
   de ces colonnes commencerait à couper son contenu : sous cette largeur, ce
   qui suppose d'avoir déployé le rail sur un écran étroit, la carte défile
   comme elle l'a toujours fait, plutôt que de laisser du texte sortir de sa
   cellule. Sur le papier, la colonne d'actions n'existe pas et ce budget non
   plus : les règles sont réservées à l'écran. */
@media screen {
  .tab-jour { table-layout: fixed; min-width: 1128px; }
  /* Quatre pixels de gouttière rendus par colonne, soit quarante
     sur la grille : la colonne Note les reprend. */
  .tab-jour th, .tab-jour td { padding-left: 6px; padding-right: 6px; }
  /* La pastille de statut est le second poste de la grille après
     les actions : resserrée, « PRÉVISIONNEL » tient dans sa
     colonne et rend une quinzaine de pixels à la note. */
  .tab-jour .chip { padding: 4px 8px; letter-spacing: .4px; }
  .tab-jour col.c-client { width: 11.52%; }
  .tab-jour col.c-qte    { width: 4.96%; }
  .tab-jour col.c-unite  { width: 7.45%; }
  .tab-jour col.c-total  { width: 6.74%; }
  .tab-jour col.c-cdt    { width: 6.7%; }
  .tab-jour col.c-noteb  { width: 9.8%; }
  .tab-jour col.c-lot    { width: 7.97%; }
  .tab-jour col.c-statut { width: 12.41%; }
  .tab-jour col.c-bl     { width: 7.45%; }
  .tab-jour col.c-act    { width: 25.0%; }
  /* Un nom de client va jusqu'à cinquante caractères dans le classeur
     repris (« Association calais voiles et traditions pour 10H30 ») :
     il se replie, et se coupe s'il le faut, plutôt que de pousser la
     grille hors de son cadre. */
  .tab-jour td:first-child { overflow-wrap: anywhere; }
}
/* La note se lit sans cliquer dedans : « reste de M806 · chauffeur STEF passe
   à 14 h » est une consigne de transport, elle s'imprime sur la feuille du
   jour et se relit dix fois par jour. Sa largeur n'est plus un plancher mais
   une part du budget ci-dessus : c'est la colonne qui reprend tout ce que les
   autres n'utilisent pas, 128 px à 1 280 et 132 px à 1 500. Au-delà, la
   consigne se lit en infobulle et sur le papier en entier. */
.tab-jour .c-note { min-width: 0; }
/* Doublure de la note, rendue seulement sur le papier : une case de saisie
   y coupe ce qui dépasse de sa largeur. */
.print-seul { display: none; }
.tab-jour .cellule[name="commentaire"] { width: 100%; min-width: 0; }

/* ---------------- navigation jour/semaine ---------------- */
.nav-periode { display: flex; align-items: center; gap: 14px; margin: 6px 0 4px;
               flex-wrap: wrap; }
.nav-periode h1 { margin: 0; }
.nav-fleche {
  font-size: 20px; font-weight: 700; text-decoration: none; color: var(--encre);
  border: 2px solid var(--trait); padding: 0 14px; background: var(--carte);
}
.nav-fleche:hover { background: var(--teal); color: #fff; border-color: var(--teal); }

/* Saut direct à une date ou à une semaine, à côté des flèches. */
.saut { display: flex; align-items: center; gap: 6px; }
.saut-etiq { display: flex; align-items: center; color: var(--encre-2);
             cursor: pointer; }
.saut input { padding: 4px 8px; font-size: 14.5px; }

/* Une seule hauteur dans la barre de période : la flèche, le champ de saut,
   le bouton Aller et les duplications se posent sur la même ligne de base.
   Trois hauteurs différentes sur la même barre donnaient un peigne. */
.nav-periode .nav-fleche, .nav-periode .btn, .nav-periode input {
  box-sizing: border-box; height: 32px; min-height: 32px;
}
.nav-periode .nav-fleche, .nav-periode .btn {
  display: inline-flex; align-items: center; justify-content: center;
  line-height: 1;
}
/* Texte réservé aux lecteurs d'écran : présent dans le document, hors de la
   page. Jamais display:none, qui le retirerait aussi de la lecture vocale. */
.sr {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}

/* ---------------- matrice semaine ----------------
   Une ligne par client ET par format, colonnes = jours. Un format, ce sont
   les trois choses qui changent ce qu'on prépare : le contenant, le poids de
   l'un, le type de purification. Une case ne porte donc qu'un seul nombre, le
   nombre de contenants, et toutes les lignes ont exactement la même hauteur.
   C'est le but : une hauteur qui saute d'une ligne à l'autre rend la grille
   illisible bien avant que les couleurs n'y soient pour quelque chose. */
.matrice-zone { background: var(--carte); border: 2px solid var(--trait);
                margin-bottom: 20px; }
table.matrice { table-layout: fixed; font-size: 14px; }
.matrice col.c-client { width: 148px; }
/* « Big 1020 kg · Non purifié » est le libellé le plus long que porte
   l'historique : la colonne est taillée dessus, pour qu'aucun format ne soit
   coupé. Les colonnes de jours n'ont besoin que d'une pastille et d'un
   nombre, elles ont la place de rendre ces pixels. */
.matrice col.c-format { width: 172px; }
.matrice col.c-total { width: 76px; }
/* Les six jours ont la même largeur, posée et non déduite du contenu : sinon
   un jour chargé se paie sur le voisin et la grille bouge d'une semaine à
   l'autre. 128 px est ce qui reste à 1 280 px, rail replié : 1 168 px de
   table moins les 396 px des colonnes client, format et total, divisés par
   six. Au-delà, les colonnes se partagent la largeur en trop. */
.matrice col.c-jour { width: 128px; }
.matrice th, .matrice td { padding: 3px 5px; vertical-align: middle; }
/* Filet vertical entre deux jours : sans lui, deux cases voisines se touchent
   et on ne sait plus à qui appartient quoi. */
.mat-fmt tbody td, .mat-fmt tfoot td { border-right: 1px solid var(--trait-fin); }
.mat-fmt tbody td:last-child, .mat-fmt tfoot td:last-child { border-right: none; }
/* Le bloc d'un client se détache de celui du dessus. */
.mat-fmt tbody tr.debut-client > * { border-top: 2px solid var(--trait-fin); }
/* L'écriture est partie, la grille attend la réponse : rien ne bouge, elle
   pâlit à peine. Le geste suivant reste possible. */
.mat-fmt.en-cours, .tab-jour.en-cours, .carte.en-cours { opacity: .85; }

/* En-tête : le jour est le lien vers l'écran Jour, ses kilos sont dessous.
   Il colle en haut quand la liste des clients défile. */
.matrice thead th {
  position: sticky; top: 0; z-index: 2; background: var(--carte);
  padding: 6px; border-bottom: 2px solid var(--trait);
}
.matrice thead th.c-jour { text-transform: none; letter-spacing: 0; }
.matrice thead a {
  display: block; color: var(--encre); font-size: 14px; font-weight: 700;
  text-transform: capitalize; letter-spacing: .2px; text-decoration: none;
}
.matrice thead a:hover { color: var(--teal); text-decoration: underline; }
.matrice .c-kg {
  display: block; font-size: 12.5px; color: var(--muet);
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
}
.matrice th.c-fer { box-shadow: inset 0 4px 0 var(--rouge); }

/* Colonne client : une seule cellule pour tous les formats d'un client, avec
   son total de la semaine dessous. Le nom entier reste en infobulle. */
.matrice .c-nom {
  font-size: 14px; font-weight: 600; text-transform: none; letter-spacing: 0;
  color: var(--encre); vertical-align: top; padding-top: 7px;
  border-right: 2px solid var(--trait);
}
.cn-nom { display: block; white-space: nowrap; overflow: hidden;
          text-overflow: ellipsis; }
.cn-kg {
  display: block; font-family: var(--mono); font-size: 12px; font-weight: 400;
  color: var(--muet); font-variant-numeric: tabular-nums; margin-top: 1px;
}
/* Le format : contenant, poids de l'un, type. Une ligne, jamais deux. */
.matrice td.c-format {
  font-family: var(--mono); font-size: 12.5px; color: var(--encre-2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  border-right: 2px solid var(--trait-fin);
}
/* Zébrure sur la couleur de fond, teintes de colonne en image : les deux se
   superposent au lieu de s'annuler, et l'en-tête collant reste opaque. */
.matrice tbody tr:nth-child(even) td,
.matrice tbody tr:nth-child(even) th { background-color: rgba(20, 33, 61, .035); }
.matrice .c-we {
  background-image: linear-gradient(rgba(20, 33, 61, .05), rgba(20, 33, 61, .05));
}
/* Le jour courant passe après le week-end : un samedi peut être aujourd'hui. */
.matrice .c-auj {
  background-image: linear-gradient(rgba(0, 116, 121, .10), rgba(0, 116, 121, .10));
}
.matrice tbody td { border-bottom: 1px solid var(--trait-fin); }
.matrice tbody th { border-bottom: 1px solid var(--trait-fin); }
.matrice td.c-total {
  font-weight: 700; font-family: var(--mono);
  font-size: 14px;
}
.matrice .ligne-vide td { padding: 0; }
.matrice .ligne-vide .vide { border: none; }

/* Une case : le bloc de commande porte la couleur du statut, comme la cellule
   colorée du classeur d'origine. La hauteur est fixée une fois pour toutes,
   elle ne dépend pas du contenu. Un jour qui porte deux commandes du même
   format empile deux blocs sans casser la colonne. */
.mat-fmt td.cel { height: 34px; text-align: right; padding: 2px 3px; }
.mv { position: relative; display: flex; align-items: center;
      justify-content: flex-end; gap: 2px; height: 28px; padding-left: 15px;
      border: 1px solid rgba(0, 0, 0, .10); }
.mv + .mv { margin-top: 2px; }
.mv-previsionnel { background: var(--st-prev-fond); }
.mv-valide { background: var(--st-val-fond); }
.mv-livre { background: var(--st-liv-fond); }
.mv-facture { background: var(--st-fac-fond); }
.mv form { display: flex; align-items: center; }
.mv form:empty { display: none; }
.mv-etat { flex: none; }
/* La bande de gauche est le bouton de bascule : pleine hauteur du bloc, sur
   une arête qu'on vise sans regarder, et jamais en conflit avec le champ de
   saisie qu'elle jouxte. */
.mv-etat { position: absolute; left: 0; top: 0; bottom: 0; }
.bande { display: block; width: 13px; height: 100%; padding: 0; border: none;
         border-right: 1px solid rgba(0, 0, 0, .12); cursor: pointer; }
.bande-fixe { cursor: default; }
.bande-previsionnel { background: var(--st-prev); }
.bande-valide { background: var(--st-val); }
.bande-livre { background: var(--st-liv); }
.bande-facture { background: var(--st-fac); }
button.bande:hover { filter: brightness(.88); }
button.bande:active { filter: brightness(.78); }
/* Deux largeurs de champ dans la grille, pas trois : 48 px pour un nombre de
   contenants ou un taux, 68 px pour un poids en kilos, qui porte un chiffre
   de plus. */
.matrice .cellule.mini {
  box-sizing: border-box; width: 48px; padding: 1px 3px; font-size: 15px;
  font-weight: 600; border-width: 1px; border-color: transparent;
  background: none;
}
/* Contenant pesé un par un : la case porte deux champs, le nombre et le poids
   de l'un. Les deux gardent la largeur des nombres : 68 px pour le poids
   demanderait une colonne de jour de 163 px, soit 978 px pour six jours quand
   la table n'en offre que 772 à 1 280 px. */
.mv-poids .cellule.mini { padding: 1px 2px; font-size: 14px; }
.mv-fois { font-family: var(--mono); font-size: 12px; color: var(--muet);
           flex: none; }
.matrice .cellule.mini:hover { border-color: rgba(0, 0, 0, .25); }
.matrice .cellule.mini:focus {
  border-color: var(--teal); background: #fff;
}
.mv-qte {
  font-family: var(--mono); font-size: 15px; font-weight: 600;
  font-variant-numeric: tabular-nums; min-width: 48px; text-align: right;
  padding-right: 4px; color: var(--encre-2);
}
.mv-note { color: var(--teal); font-size: 12px; }


/* Suppression : discrète, révélée au survol de la case ou au clavier. */
.croix {
  background: none; border: 1px solid transparent; color: var(--rouge);
  font: inherit; font-size: 10px; line-height: 1; padding: 0 1px;
  cursor: pointer; opacity: 0;
}
.matrice td:hover .croix, .matrice td:focus-within .croix { opacity: 1; }
.croix:hover { border-color: var(--rouge); background: var(--rouge-fond); }

/* « + » : ouvre le bloc d'ajout prérempli, sous la grille. */
.plus {
  color: var(--trait-fin); font-weight: 700; font-size: 14px; line-height: 1;
  text-decoration: none; padding: 0 3px; border: 1px solid transparent;
}
.cel-vide .plus { color: #b7bcca; }
.plus:hover, .plus:focus-visible { color: var(--teal); border-color: var(--teal);
                                   background: #fff; }
.cel-vide { text-align: center; }

/* Pieds de tableau : les kilos du jour, la pêche de la veille, puis les
   repères et les actions. Les deux premiers restent lisibles en consultation. */
.matrice tfoot th, .matrice tfoot td { border-top: 1px solid var(--trait-fin); }
.matrice tfoot .total-row td, .matrice tfoot .total-row th {
  border-top: 2px solid var(--trait); font-size: 15px;
}
.matrice tfoot .total-row td { font-family: var(--mono); }
.matrice tfoot th {
  font-size: 12.5px; font-weight: 600; color: var(--encre-2);
  text-align: left;
}
.pied-peche td { font-family: var(--mono);
                 font-size: 13.5px; }
.pied-peche small { display: block; font-size: 11px;
                    font-family: var(--sans); }
/* ---------------- les deux blocs de production ----------------
   La pêche se décide AVANT la journée : son bloc ouvre l'écran, au-dessus de
   la grille des clients. Le réalisé se lit APRÈS : son bloc la ferme. Entre
   les deux, la gestion du carnet. Les trois tableaux partagent le même
   gabarit de colonnes, les jours restent alignés d'un bloc à l'autre.
   Le calcul du classeur, posé ligne à ligne dans son ordre : commandes, stock
   repris, stock à garder, perte, taux, et le seul chiffre qu'il donne aux gars
   le matin. Fond distinct : ce n'est plus de la vente, c'est de la production. */
.bloc-peche, .bloc-realise { margin-bottom: 14px; }
.mat-peche thead th, .mat-realise thead th {
  background: #eae7dd; border-bottom: 2px solid var(--trait);
  font-size: 12.5px; color: var(--encre-2); text-align: left;
  padding: 5px 8px; font-weight: 600;
}
.mat-peche thead th.c-tete-client, .mat-realise thead th.c-tete-client {
  font-size: 13px; font-weight: 700; color: var(--encre);
}
.mat-peche thead th.c-auj, .mat-realise thead th.c-auj {
  box-shadow: inset 0 -3px 0 var(--teal);
}
/* Le réalisé n'est pas une consigne : il se lit plus bas en intensité que la
   pêche, qui commande la journée. */
.mat-realise tr.peche-l th, .mat-realise tr.peche-l td,
.mat-realise tr.peche-total th, .mat-realise tr.peche-total td {
  background: var(--carte);
}
.cellule.mini.pesee { width: 68px; text-align: right; }
.mat-realise td .cellule.mini.pesee { border-color: var(--trait-fin); }
/* « 20 sacs · 300 kg » n'est pas un nombre : la cellule le rend en une seule
   ligne serrée, et se replie plutôt que de déborder sur la colonne voisine. */
.matrice.mat-realise tr.peche-l td.sacs {
  font-size: 11px; letter-spacing: -.2px;
  white-space: normal; overflow-wrap: anywhere;
}
/* Un taux qu'on ne peut pas calculer se dit en toutes lettres : c'est une
   phrase, pas un pourcentage, et elle se lit sur le ton d'une absence. */
.mat-realise .taux-nc {
  font-family: var(--sans); font-size: 11.5px; font-weight: 400;
  color: var(--muet); letter-spacing: 0;
}
.matrice tr.peche-tete th {
  background: #eae7dd; border-top: 3px solid var(--trait);
  padding: 7px 8px; font-size: 13px; font-weight: 700; color: var(--encre);
}
.matrice tr.peche-tete .discret { font-weight: 400; font-size: 12.5px; }
.matrice tr.peche-l th, .matrice tr.peche-l td,
.matrice tr.peche-total th, .matrice tr.peche-total td {
  background: #f4f2ea; border-top: none;
  border-bottom: 1px solid var(--trait-fin);
}
.matrice tr.peche-l td { font-family: var(--mono); font-size: 13px; }
.matrice tr.peche-l th, .matrice tr.peche-total th {
  font-size: 12.5px; font-weight: 600; color: var(--encre-2);
}
.matrice tr.peche-l .discret { font-weight: 400; }
.matrice tr.peche-total th, .matrice tr.peche-total td {
  border-top: 2px solid var(--trait); border-bottom: none;
  font-weight: 700; font-size: 15px;
}
.matrice tr.peche-total td { font-family: var(--mono); }
.matrice tr.peche-total th { font-size: 13px; letter-spacing: .3px;
                             color: var(--encre); }
/* La note sous un chiffre de colonne se replie dans sa cellule : héritée de
   `td.num`, elle restait sur une ligne et débordait sur la colonne voisine
   dès que le rail se repliait, à 1280 px. */
.peche-jour { display: block; font-family: var(--sans); font-size: 11px;
              font-weight: 400; color: var(--muet);
              white-space: normal; overflow-wrap: anywhere; }
/* Taux de perte : le seul chiffre du bloc qui se corrige, et il se corrige
   à la semaine, pas jour par jour. */
.peche-taux form { display: flex; align-items: center; justify-content: flex-end;
                   gap: 2px; }
.matrice .cellule.mini.taux { font-size: 13.5px; }
.peche-taux .pct { font-family: var(--mono); font-size: 12.5px;
                   color: var(--muet); }

.pied-actions td { padding: 5px 6px; }
.pied-actions form { display: block; margin-top: 4px; }
.pied-actions .btn-petit { padding: 3px 8px; font-size: 12.5px; min-height: 24px; }
.marque-auj {
  display: inline-block; background: var(--teal); color: #fff; font-size: 10.5px;
  font-weight: 700; text-transform: uppercase; letter-spacing: 1px;
  padding: 1px 6px;
}
.pied-actions .etiq-ferie { display: inline-block; font-size: 11.5px;
                            padding: 1px 6px; }
/* Météo du jour de livraison, sous le nombre de kilos à pêcher : l'icône et
   la température, ce qui joue sur les ventes du magasin. Le vent de la
   fenêtre de départ du bateau, sans conséquence pour ces ventes, ne prend un
   badge coloré que passé le seuil ; en dessous, il reste en infobulle sur le
   bloc météo. */
.peche-cond td { font-size: 12.5px; line-height: 1.35; padding-top: 3px;
                 padding-bottom: 4px; }
.cond-vent, .cond-maree, .cond-meteo {
  display: flex; align-items: center; white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.cond-meteo { gap: 3px; color: var(--encre-2); font-weight: 600; }
.cond-meteo + .cond-vent { margin-top: 2px; }
.ic-meteo { width: 15px; height: 15px; flex: none; stroke-width: 1.6; }
.cond-soleil .ic-meteo { color: var(--st-prev-texte); }
.cond-voile .ic-meteo,
.cond-brouillard .ic-meteo { color: var(--muet); }
.cond-pluie .ic-meteo { color: var(--st-liv-texte); }
.cond-neige .ic-meteo { color: var(--teal); }
.cond-orage .ic-meteo { color: var(--rouge); }
/* Matin, midi, après-midi : trois vignettes dans la largeur d'une colonne de
   jour, deux lignes chacune (le moment, puis la température et l'icône). Le
   risque de pluie tient dans l'infobulle : à cette taille, un chiffre de plus
   ne se lirait pas. */
.meteo-creneaux { display: grid; grid-template-columns: repeat(3, 1fr);
                  gap: 1px; }
.meteo-creneau { min-width: 0; text-align: center; color: var(--encre-2);
                 font-variant-numeric: tabular-nums; }
.meteo-creneau i { display: block; font-style: normal; font-size: 10px;
                   line-height: 1.2; color: var(--muet); }
.meteo-val { display: flex; align-items: center; justify-content: center;
             gap: 1px; font-size: 12px; line-height: 1.25; white-space: nowrap; }
.meteo-val b { font-weight: 700; }
.meteo-creneaux .ic-meteo { width: 13px; height: 13px; stroke-width: 1.8; }
.meteo-creneaux + .cond-vent { margin-top: 3px; }
.cond-vent { font-weight: 600; color: var(--encre-2); }
.cond-vent b { font-weight: 700; }
.cond-vent.vent-orange { background: var(--st-prev-fond);
                         color: var(--st-prev-texte);
                         box-shadow: inset 3px 0 0 var(--st-prev);
                         padding-left: 6px; }
.cond-vent.vent-rouge { background: var(--rouge-fond); color: var(--rouge);
                        box-shadow: inset 3px 0 0 var(--rouge);
                        padding-left: 6px; }
.cond-maree { color: var(--muet); font-family: var(--mono); font-size: 11.5px; }
.legende .cond-vent { display: inline-flex; padding: 1px 6px;
                      border: 1px solid var(--trait-fin); }

.h1-sous { color: var(--muet); font-weight: 400; }
/* Repère posé dans la barre de période : une seule boîte pour tous, sinon
   deux cartes voisines n'ont ni la même hauteur ni le même corps de chiffre.
   Le groupe part à droite, le premier repère pousse les suivants. */
.kpi-compact { padding: 6px 16px 8px; min-width: 168px; }
/* Étirés à la hauteur de la barre plutôt que centrés dedans : l'un porte un
   rappel de l'an dernier, l'autre non, et centrés leurs deux chiffres ne se
   lisaient plus sur la même ligne. */
.kpi-compact { align-self: stretch; }
.kpi-compact:first-of-type { margin-left: auto; }
.kpi-compact .kpi-valeur { font-size: 22px; }
.kpi-compact .kpi-valeur small { color: var(--muet); font-weight: 500; }
/* Le liseré n'appartient qu'à ce qui attend une action : ambre tant qu'il
   reste des commandes à confirmer, vert quand la journée est bouclée. */
.kpi-compact.kpi-attente { border-left: 8px solid var(--st-prev); }
.kpi-compact.kpi-attente.kpi-fait { border-left-color: var(--st-val); }
.kpi-compact.kpi-fait .kpi-valeur { color: var(--st-val-texte); }

/* Bloc d'ajout : un seul formulaire pour toute la grille, prérempli par le
   « + » d'une case (client et jour passés dans l'adresse). */
.ajout-bloc {
  background: var(--carte); border: 2px solid var(--trait-fin);
  padding: 0 16px; margin-bottom: 20px;
}
.ajout-bloc > summary { cursor: pointer; font-weight: 700; padding: 12px 0;
                        color: var(--teal); }
.ajout-bloc > summary:hover { text-decoration: underline; }
.ajout-bloc[open] > summary { border-bottom: 1px solid var(--trait-fin);
                              margin-bottom: 14px; }
.ajout-bloc > *:last-child { margin-bottom: 14px; }

/* Ligne libre et mention d'une facture en préparation : deux gestes rares
   derrière un seul bouton, qui déplie le bloc sur place. Le marqueur natif du
   dépliant n'a rien à faire dans un bouton, il est retiré des deux côtés. */
.pli-ajout > summary { list-style: none; display: inline-block; }
.pli-ajout > summary::-webkit-details-marker { display: none; }
.pli-ajout > summary::marker { content: ""; }

/* ---------------- graphiques ----------------
   SVG produit par le serveur : aucune bibliothèque, aucun appel réseau, rien à
   installer. Une teinte appartient à un client (logic.PALETTE_SERIES, vérifiée
   sous protanopie et deutéranopie) ; la hachure dit l'année, les libellés
   posés au-dessus des piles donnent les totaux, le tableau croisé donne le
   détail chiffré. L'identité ne repose jamais sur la seule couleur. */
.graphe { margin: 0 0 6px; }
.graphe svg { display: block; width: 100%; height: auto; }
.g-grille { stroke: var(--trait-fin); stroke-width: 1; }
.g-base { stroke: var(--trait); stroke-width: 2; }
.g-axe { font-family: var(--mono); font-size: 11px; fill: var(--muet); }
.g-mois { font-family: var(--sans); font-size: 12px; fill: var(--encre-2); }
.g-valeur { font-family: var(--mono); font-size: 10.5px; fill: var(--encre-2); }
.g-unite { font-family: var(--sans); font-size: 10.5px; fill: var(--muet); }
.c-trace { fill: none; stroke-width: 2; stroke-linejoin: round; }
.c-trace.c-actuel { stroke: var(--teal); }
.c-trace.c-n1 { stroke: #a8adbe; stroke-dasharray: 5 4; }
.c-point.c-actuel { fill: var(--teal); stroke: var(--carte); stroke-width: 2; }
.c-point.c-n1 { fill: #a8adbe; stroke: var(--carte); stroke-width: 2; }
.c-fin { font-family: var(--sans); font-size: 12.5px; font-weight: 600;
         fill: var(--teal); }
.c-fin.c-n1-texte { fill: #6f7791; font-weight: 500; }

/* Registre technique : une mesure par jour, des points bien plus serrés que
   sur les courbes mensuelles. Le liseré blanc doit maigrir pour laisser voir
   la ligne. Un point hors échelle se dessine creux et cerclé de rouge, au
   plafond de l'axe : la valeur exacte reste dans l'infobulle. */
.c-point.c-jour { stroke-width: 1; }
.c-point.c-hors { fill: var(--carte); stroke: var(--rouge); stroke-width: 1.6; }
.c-trace.c-jour { stroke-width: 1.6; }

/* Restant de fin de journée : deux teintes fixes, pas une palette client. */
.surstock-sacs { fill: var(--teal); background: var(--teal); }
.surstock-vrac { fill: #a8adbe; background: #a8adbe; }

.legende-series {
  display: flex; flex-wrap: wrap; gap: 6px 18px; list-style: none;
  margin: 4px 0 12px; padding: 0; font-size: 14px;
}
.legende-series li { display: flex; align-items: center; gap: 7px; }
.pastille-serie {
  width: 13px; height: 13px; flex: none; display: inline-block;
  border: 1px solid rgba(20, 33, 61, .25);
}
.pastille-hachure {
  background: repeating-linear-gradient(45deg, var(--encre-2) 0 3px,
                                        var(--carte) 3px 6px);
}
.serie-annee { color: var(--muet); }

/* Un tableau plus large que sa carte défile seul, il ne pousse jamais la page
   ni ne comprime ses colonnes jusqu'à casser les nombres. */
.tab-defile { overflow-x: auto; }
.tab-croise { min-width: 1120px; font-size: 14px; }
.tab-croise th, .tab-croise td { padding: 6px 7px; }
.tab-croise td.num { font-size: 13.5px; }
.croise-nom { white-space: nowrap; }
.croise-nom .pastille-serie { vertical-align: -1px; margin-right: 6px; }

/* Croisé semaine x client : la colonne des semaines reste visible quand le
   tableau, large de nature, défile horizontalement. */
.tab-semaine th:first-child, .tab-semaine td:first-child {
  position: sticky; left: 0; z-index: 1; background: var(--carte);
}
.tab-semaine tfoot th:first-child, .tab-semaine tfoot td:first-child {
  background: #f1efe7;
}

/* Filtre « chiffre d'affaires au moins » : la saisie libre et les paliers
   sur la même ligne. */
.filtre-ca {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: 10px 16px;
  margin-bottom: 14px;
}
.filtre-ca input[type="number"] { width: 130px; }

/* ---------------- barres stats ---------------- */
.barre-fond { background: #e3ded2; height: 20px; position: relative; }
.barre { background: var(--teal); height: 100%; }
.barre.n1 { background: #7a8199; }
/* Deux volumes comparés dans la même cellule : l'année en cours au-dessus,
   l'an dernier en dessous, sur la même échelle. */
.barre-fond.barre-double { background: none; display: flex;
                           flex-direction: column; gap: 2px; }
.barre-double .barre { height: 9px; background: var(--teal); }
.barre-double .barre.n1 { background: #a8adbe; }

/* ---------------- heatmap calendrier ----------------
   UN seul conteneur défilant : les 3 bandes et leurs libellés de jours
   glissent ensemble, sinon la comparaison verticale ment. */
.heat-zone { overflow-x: auto; padding-bottom: 6px; }
.heat-inner { display: inline-block; min-width: max-content; }
.heat-bloc { margin-bottom: 12px; }
.heat-titre {
  font-size: 13px; font-weight: 600; color: var(--encre-2);
  margin: 0 0 4px 30px;
}
.heat-ligne { display: flex; align-items: flex-start; gap: 8px; }
.heat-jours { display: flex; flex-direction: column; gap: 2px; width: 22px; }
.heat-jours span {
  height: 16px; line-height: 16px; font-size: 10px; color: var(--muet);
  font-weight: 700; width: 22px; text-align: right;
}
.heat-grille { display: flex; gap: 2px; }
.heat-sem { display: flex; flex-direction: column; gap: 2px; }
/* repères de mois : une case par semaine, le nom déborde à droite */
.heat-axe { margin-bottom: 2px; }
.heat-mois { width: 16px; height: 16px; position: relative; }
.heat-mois.debut { border-left: 1px solid var(--trait-fin); }
.heat-mois span {
  position: absolute; left: 2px; bottom: 0; white-space: nowrap;
  font-size: 10px; font-weight: 700; color: var(--muet); letter-spacing: .5px;
}
/* Case de 16 px : sous cette taille, un liseré de repère mange la couleur
   d'intensité qu'il est censé encadrer. */
.heat {
  display: inline-block; width: 16px; height: 16px;
  border: 1px solid rgba(20, 33, 61, .12);
}
/* Case vide : trame pointillée transparente, distincte d'une petite
   journée (h0), qui reste un aplat plein. */
.heat.h-vide { background: none; border: 1px dotted rgba(20, 33, 61, .28); }
/* Palette d'intensité, reprise arrêt par arrêt dans logic.HEAT_PALETTE pour
   construire le dégradé de la légende. */
.heat.h0 { background: #cfe3e0; }
.heat.h1 { background: #b0d6d5; }
.heat.h2 { background: #8ac3c3; }
.heat.h3 { background: #58a9ab; }
.heat.h4 { background: #268b8f; }
.heat.h5 { background: #00666b; }
/* Projection : un style unique, sans palier d'intensité. */
.heat.proj { background: #eef7f7; border: 1px dashed var(--teal); }
/* Férié : liseré rouge de 2 px obtenu par la bordure d'origine doublée d'une
   ombre interne. La couleur d'intensité reste visible à l'intérieur, c'est
   elle qui porte l'information (l'Assomption 2025 vaut 5 157 kg). */
.heat.fer {
  border-color: var(--rouge);
  box-shadow: inset 0 0 0 1px var(--rouge);
}
.heat.auj { outline: 2px solid var(--encre); outline-offset: 1px; }
.heat-legende { display: flex; align-items: center; gap: 14px; margin-top: 8px;
                font-size: 12.5px; flex-wrap: wrap; }
.palier { display: flex; align-items: center; gap: 5px; }
.palier small { font-size: 11.5px; color: var(--muet); }

/* Échelle en dégradé : les arrêts de couleur sont posés aux bornes réelles,
   les graduations les nomment. La barre dit d'elle-même que l'échelle n'est
   pas régulière. */
.echelle { margin-top: 14px; max-width: 560px; }
.echelle-titre { font-size: 12.5px; font-weight: 600; margin-bottom: 4px; }
.echelle-barre { height: 14px; border: 1px solid rgba(20, 33, 61, .35); }
.echelle-ticks { position: relative; height: 22px; }
.tick { position: absolute; transform: translateX(-50%); text-align: center; }
.tick.tick-fin { transform: translateX(-100%); text-align: right; }
.tick i { display: block; width: 1px; height: 4px; background: var(--muet);
          margin: 0 auto; }
.tick.tick-fin i { margin: 0 0 0 auto; }
.tick small { display: block; font-size: 10.5px; color: var(--muet);
              font-variant-numeric: tabular-nums; white-space: nowrap; }

/* ---------------- projection 14 jours ---------------- */

/* ---------------- étiquettes ----------------
   Grille de planche adhésive : 70 mm × 37 mm, 3 × 8 par A4, gouttière nulle.
   Toute marge ici décale l'impression sur la planche. */
.planche {
  display: grid; grid-template-columns: repeat(3, 70mm); gap: 0;
  width: 210mm; margin: 0 auto; background: #fff;
}
.etiquette {
  width: 70mm; height: 37mm; overflow: hidden;
  border: 1px dashed var(--trait-fin); padding: 2.5mm 3mm; text-align: center;
  break-inside: avoid; background: #fff; color: #000;
  display: flex; flex-direction: column; justify-content: center; gap: .6mm;
  font-size: 9.5pt; line-height: 1.25;
}
.etiquette .cli { font-weight: 700; font-size: 12pt; letter-spacing: .3px; }
.etiquette .esp { font-size: 9pt; }
.etiquette .infos { font-size: 8pt; }
.etiquette .vivants { font-size: 7pt; font-weight: 700; text-transform: uppercase; }
.etiquette .lot { font-family: var(--mono); font-weight: 700; }
.etiquette .alerte-texte { color: var(--rouge); }

/* ---------------- impression BL / factures ---------------- */
.doc {
  background: #fff; border: 2px solid var(--trait);
  max-width: 900px; margin: 0 auto 20px; padding: 34px 40px;
}
.doc-entete { display: flex; justify-content: space-between; margin-bottom: 24px; }
.doc-societe { font-weight: 700; font-size: 19px; }
.doc-titre { font-size: 30px; font-weight: 700; letter-spacing: 4px; }
.doc-num { font-family: var(--mono); font-size: 20px; font-weight: 700; }
.doc-blocs { display: flex; gap: 24px; justify-content: space-between; margin-bottom: 22px; }
.doc-bloc { border: 2px solid var(--trait); padding: 12px 16px; flex: 1; font-size: 15px; }
.doc-bloc h3 {
  margin: 0 0 6px; font-size: 11.5px; text-transform: uppercase;
  letter-spacing: 1.5px; color: var(--teal);
}
.doc table { font-size: 15px; }
.doc-mentions { margin-top: 26px; font-size: 10.5px; color: var(--encre-2); line-height: 1.5; }
.doc-mentions p { margin: 3px 0; }
/* Mention légale qui conditionne la validité de la facture (exonération de
   TVA) : elle ne se lit pas en pied de page en corps 8. */
.mention-forte {
  margin: 14px 0 0; border: 2px solid var(--trait); padding: 8px 12px;
  font-weight: 700; background: #f1efe7;
}
.doc-pied {
  margin-top: 18px; border-top: 2px solid var(--trait); padding-top: 8px;
  font-size: 10.5px; color: var(--encre-2); text-align: center;
}
.barre-impression { max-width: 900px; margin: 16px auto; display: flex;
                    gap: 10px; flex-wrap: wrap; }
.barre-impression .btn-retour { margin-right: 12px; }
.saut-page { break-after: page; }

/* Marge de page nulle : c'est dans cette marge que le navigateur imprime son
   en-tête et son pied (date, titre de l'onglet, adresse du site, numéro de
   page). En la supprimant, ils n'ont plus où se poser. La marge de papier est
   alors portée par le document lui-même. Un poste peut aussi décocher
   « En-têtes et pieds de page » dans la fenêtre d'impression : le réglage y
   est retenu. */
@page { size: A4 portrait; margin: 0; }

@media print {
  .no-print, .rail, .flashs, .barre-impression, .checklist { display: none !important; }
  /* Le papier n'a pas de menu : la grille de l'écran redevient un flux. */
  body { display: block; background: #fff; font-size: 10pt; }
  main { padding: 0; max-width: none; }
  /* La marge de page vaut zéro pour chasser l'en-tête du navigateur : c'est
     donc le document qui porte la marge de papier. */
  .doc { border: none; max-width: none; margin: 0; padding: 14mm 13mm 12mm; }
  .doc-entete { margin-bottom: 5mm; }
  .doc-titre { font-size: 19pt; letter-spacing: 3px; }
  .doc-num { font-size: 14pt; }
  .doc-societe { font-size: 12pt; }
  .doc-blocs { gap: 5mm; margin-bottom: 5mm; }
  .doc-bloc { padding: 2.2mm 3mm; font-size: 8.5pt; line-height: 1.3; }
  .doc-bloc h3 { font-size: 8.5pt; margin-bottom: 1mm; }
  /* Le tableau du document se resserre au juste nécessaire : une semaine de
     livraisons doit tenir sur une page. Les colonnes de chiffres ne se
     coupent jamais en deux lignes, c'est ce qui faisait déborder la facture. */
  .doc table { font-size: 8.6pt; line-height: 1.25; }
  .doc th, .doc td { padding: 1.6mm 1.4mm; }
  .doc td.num, .doc th.num, .doc-tab td, .doc-tab th { white-space: nowrap; }
  .doc-tab td:nth-child(3) { white-space: normal; }
  .doc-mentions, .doc-pied { font-size: 7.5pt; }
  .doc-mentions { margin-top: 5mm; }
  .mention-forte { margin-top: 4mm; padding: 2mm 3mm; font-size: 8.5pt; }
  .carte { border-width: 1px; }
  /* Les statuts sont des aplats : sans cette exception le navigateur les
     retire à l'impression et la grille part en atelier sans ses couleurs. */
  .mv, .bande, .chip {
    -webkit-print-color-adjust: exact; print-color-adjust: exact;
  }
  thead { display: table-header-group; }
  /* Le total ne s'imprime qu'une fois, à la fin du tableau : avec
     table-footer-group, il se répéterait au bas de chaque page. */
  tfoot { display: table-row-group; }
  tr { page-break-inside: avoid; }
  .doc-blocs, .doc-entete { page-break-inside: avoid; }
  a[href]::after { content: none; }
  /* Planche d'étiquettes : elle se cale sur le bord de la feuille, c'est la
     planche adhésive qui porte ses propres marges. La marge de page nulle
     rend enfin ce calage exact. */
  .planche { width: 210mm; margin: 0; padding: 0; }

  /* --- Feuille du jour ---------------------------------------------------
     C'est le papier que l'atelier lit chaque matin, et le numéro de bon est
     ce que le chargeur y cherche : la grille doit tenir dans la largeur A4,
     colonne BL comprise, et la pastille de statut ne doit pas se couper. */
  .tab-defile { overflow: visible !important; }
  .tab-jour { width: 100%; font-size: 8.4pt; }
  .tab-jour th, .tab-jour td { padding: 1.2mm 1mm; }
  /* Le plancher de 240 px de la colonne Note est une règle d'écran : sur le
     papier il portait à lui seul la grille à 1 102 px pour 794 px utiles, et
     le navigateur réduisait toute la feuille à 72 %, corps 8,4 pt compris.
     La note se replie sur plusieurs lignes, la grille reprend sa taille. */
  .tab-jour .c-note { min-width: 0; white-space: normal; overflow-wrap: anywhere; }
  .tab-jour .chip {
    white-space: nowrap; font-size: 7.6pt; padding: 0.4mm 1.2mm;
    border-width: 1px;
  }
  /* Les cases de saisie redeviennent du texte : sur le papier, un cadre de
     formulaire ne sert à rien et vole la largeur des colonnes. */
  .tab-jour .cellule, .tab-jour select.cellule {
    border: none !important; background: none !important;
    padding: 0 !important; min-width: 0 !important;
    -webkit-appearance: none; appearance: none;
  }
  /* Une case de saisie sans largeur explicite reprend sa taille par défaut,
     celle d'une vingtaine de caractères : les colonnes Qté et Unité sortaient
     à 197 px chacune et poussaient la grille à 1 064 px, que le navigateur
     réduisait ensuite pour la faire tenir. Sur le papier, ces colonnes ne
     portent que trois ou quatre chiffres. */
  .tab-jour .cellule[name="qte"],
  .tab-jour .cellule[name="poids"] { width: 32px !important; }
  .tab-jour select.cellule[name="lot_servi"] { width: 48px !important; }
  /* La note quitte sa case de saisie et redevient du texte, qui se replie. */
  .tab-jour .c-note .cellule { display: none; }
  .tab-jour .c-note .print-seul { display: block; max-width: 200px; }
  /* Un texte d'invite n'est pas une donnée : il ne s'imprime pas. */
  input::placeholder { color: transparent !important; }
  /* Le cartouche « À pêcher » sortait en aplat bleu nuit pleine largeur. */
  .kpi.accent { background: #fff; color: var(--encre); }
  .kpi.accent .kpi-libelle, .kpi.accent .kpi-note { color: #444; }
  /* La feuille commence par sa date, comme le classeur qu'elle remplace. */
  .nav-periode { display: block; margin-bottom: 4mm; }
  .nav-fleche { display: none; }
  /* Les quatre cartouches tiennent sur un seul rang : le taux de perte seul
     sur une deuxième rangée coûtait un quart de page pour un chiffre. */
  .kpis { flex-wrap: nowrap; gap: 3mm; margin: 0 0 4mm; }
  .kpi { min-width: 0; flex: 1; padding: 2mm 3mm; }
  .kpi-valeur { font-size: 15pt; }
  /* Le registre s'imprime en valeurs relevées, pas en cases à remplir : les
     cadres de saisie et le bouton d'enregistrement ne servent qu'à l'écran. */
  .carte .form-ligne input, .carte .form-ligne select {
    border: none !important; background: none !important; padding: 0 !important;
    -webkit-appearance: none; appearance: none;
  }
  /* Sur le papier, un nombre calé à droite de sa case se lit sous le libellé
     de la colonne suivante : « 17 » arrivait à un centimètre de « UV » et à
     quatre de « T° eau ». Le cadre disparaissant à l'impression, l'alignement
     à droite n'a plus de bord à suivre : la valeur se range sous son libellé,
     à gauche, comme tout le reste du bloc. C'est la pièce remise à un contrôle
     sanitaire. */
  .carte .form-ligne input.court { text-align: left !important; }
  .carte .form-ligne .btn { display: none; }

  /* --- Écran Registre ----------------------------------------------------
     Le registre est la pièce remise à un contrôle sanitaire : dix colonnes
     dont les libellés portaient la table à 937 px pour 794 px de feuille,
     18 % coupés à droite. Les libellés se replient, la grille se resserre et
     la table reprend la largeur de la page. Le bloc « Jours à remplir », la
     barre de périodes et le pied de pagination sont des gestes d'écran :
     ils portent `no-print` dans le gabarit. */
  .tab-registre { max-width: none; width: 100%; table-layout: fixed;
                  font-size: 8.4pt; }
  .tab-registre th, .tab-registre td { padding: 1.2mm 1mm; }
  .tab-registre th { white-space: normal; overflow-wrap: anywhere; }
  .tab-registre td { overflow-wrap: anywhere; }
  .tab-registre td.num, .tab-registre th.num { white-space: normal; }
  /* Le repere de tri est un geste d ecran : il ne suit pas sur le papier. */
  .triable th.tri-actif::after { content: none; }
}
