/* =========================================================================
   Kronos — feuille de style
   Charte : docs/MOTIF-VEINE-DOR.md. Interface neutre par obligation métier :
   la photographie de la montre est le seul élément saturé de l'écran, sans
   quoi on ne peut plus juger un cadran ni une patine. Séparation par bordures
   et contraste de fond, JAMAIS par ombre. L'ERP est carré. Deux graisses
   d'Inter seulement : 400 et 500.

   NOIR ET OR depuis le 25.08.2026 — le vert profond hérité du socle a été
   retiré partout, jusque dans le motif. Le noir et le doré sont des MOMENTS
   (connexion, états vides, passeport) et des aplats de marque, jamais le thème
   du quotidien, qui reste le blanc galerie. L'or a deux emplois de plus qu'à
   l'époque du vert, et c'est la conséquence directe du changement : il porte
   les LIENS — un lien noir serait indiscernable de l'encre — et il porte les
   fêlures du motif, qui étaient auparavant photographiées.
   ========================================================================= */

/* --- Polices embarquées localement (aucun appel CDN, CSP font-src 'self') - */
@font-face {
  font-family: "Inter";
  src: url("/static/fonts/inter-variable.woff2") format("woff2");
  font-weight: 100 900;
  font-display: swap;
}
@font-face {
  font-family: "Marcellus";
  src: url("/static/fonts/marcellus.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
}

/* --- Variables de référence (docs/DESIGN.md) — aucune couleur en dur ----- */
:root {
  /* Identité — le NOIR de la marque, présent partout dans le quotidien.
     Refonte du 25.08.2026 : le vert profond hérité du socle cède au noir.
     Un noir CHAUD, jamais #000 : le noir pur éteint l'or, qui y vire au jaune.
     C'est le noir des cadrans et des écrins, et c'est lui qui fait vibrer
     --or juste à côté. */
  --primaire:        #131110;
  /* Survol. Il ÉCLAIRCIT, il ne fonce pas : on ne peut pas assombrir un noir,
     et l'ancien couple (vert / vert plus sombre) n'a donc pas d'équivalent.
     Le nom le dit — appeler « foncé » une valeur plus claire aurait été une
     ligne fausse dans la feuille de style. */
  --primaire-survol: #3A342E;
  --primaire-tint:   #EFEBE3;

  /* Moments — aplats noirs, cadrés d'un filet doré. Jamais le quotidien.
     Plus profond que --primaire : un aplat plein doit s'enfoncer davantage
     qu'un bouton, sinon les deux se confondent sur le même écran. */
  --noir-profond:    #0B0A09;
  --or:              #C29A4B;
  --filet-or:        rgba(194, 154, 75, .55);
  --filet-or-faible: rgba(194, 154, 75, .22);
  --sur-noir:        #D8D1C4;

  /* Quotidien — le blanc galerie, ni crème ni gris. */
  /* Neutralisé le 25.08.2026 : #1A1D1B portait une pointe de vert (le vert
     était le canal dominant). Invisible à l'œil, mais c'était la dernière
     trace de l'ancienne identité dans le texte courant. Contraste inchangé. */
  --encre:           #1B1A17;   /* ~16:1 sur surface */
  --encre-douce:     #5B5852;   /*  7.1:1 */
  --encre-attenuee:  #6E6B64;   /*  5.3:1 — remonté de #8B948F (2.9:1, échouait AA) */

  --bordure:         #E6E3DC;
  --fond:            #FBFAF8;
  --surface:         #FFFFFF;

  /* Doré sur fond clair : rare, réservé aux valeurs et aux certifications.
     --accent est la valeur de la charte, pour les filets et les marques ;
     --accent-texte est sa version lisible, obligatoire dès qu'il porte du
     texte (#A8792B ne tient que 3.4:1 sur son propre fond teinté).
     --accent-survol est son état survolé, ajouté le 25.08.2026 : l'or PORTE
     désormais les liens (voir la règle `a`), et un lien sans état survolé
     distinct ne dit pas qu'il est cliquable. */
  --accent:          #A8792B;
  --accent-texte:    #8A6220;
  --accent-survol:   #6B4B18;
  --accent-tint:     #F7F1E4;

  /* Sémantique — la charte n'impose rien ici, elle encadre l'identité.
     Valeurs choisies pour tenir 4.5:1 sur leur fond teinté. */
  --succes:          #1D7A4F;
  --succes-tint:     #EAF5EF;
  --avert:           #9C4E0C;
  --avert-tint:      #FDF2E6;
  --danger:          #A3312B;
  --danger-tint:     #FBECEC;
  --info:            #2C5F82;
  --info-tint:       #EAF1F6;

  --police:          "Inter", -apple-system, "Segoe UI", sans-serif;
  --police-marque:   "Marcellus", "Playfair Display", Georgia, serif;

  --rayon:           4px;
  --ligne-tableau:   36px;
  --barre-laterale:  220px;
  --bandeau:         48px;
  /* La largeur utile de la zone de travail. 1680 px laisse passer les tableaux
     les plus larges du produit (le registre d'achat en compte onze colonnes)
     sans qu'un formulaire à deux champs s'étale sur un mètre d'écran. */
  --contenu-max:     1680px;

  /* Mouvement — strictement fonctionnel : il lève une ambiguïté, il ne
     décore pas. Toute animation est désactivée sous prefers-reduced-motion. */
  --duree-court:     120ms;
  --duree-moyen:     180ms;
  --duree-long:      260ms;
  --sortie:          cubic-bezier(.22, 1, .36, 1);
  --entree:          cubic-bezier(.4, 0, .2, 1);
}

/* Aucune ombre portée n'est définie : c'est volontaire (DESIGN.md).
   Le seul relief autorisé est le trait de base d'un cadre de moment fort. */

* { box-sizing: border-box; }

html, body {
  margin: 0; padding: 0;
  font-family: var(--police);
  font-size: 14px;
  font-weight: 400;
  color: var(--encre);
  background: var(--fond);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 { font-weight: 500; color: var(--encre); margin: 0 0 .5em; }
/* Le lien porte l'OR, pas le noir de la marque — et c'est la seule décision
   de la refonte du 25.08.2026 qui ne soit pas un simple remplacement de
   couleur. Le vert sortant se distinguait de l'encre ; un noir ne le peut
   pas : --primaire (#131110) et --encre (#1B1A17) sont le même gris à l'œil,
   et tous les liens du produit auraient disparu dans leur paragraphe.
   Dans un système noir et or, c'est l'or qui signale ce qui répond au clic.
   --accent-texte et non --accent : #A8792B ne tient pas 4.5:1 en petit corps. */
a { color: var(--accent-texte); text-decoration: none; }
a:hover { color: var(--accent-survol); text-decoration: underline; text-underline-offset: 2px; }
p { margin: 0 0 .8em; }

/* --- Surfaces que nous n'avons pas dessinées, mais qui portent la charte -- */
::selection { background: var(--primaire-tint); color: var(--primaire); }
input, textarea, select { caret-color: var(--primaire); }
* { scrollbar-width: thin; scrollbar-color: #CFCCC4 transparent; }
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-thumb { background: #CFCCC4; border: 3px solid transparent; background-clip: content-box; border-radius: 999px; }
*::-webkit-scrollbar-thumb:hover { background: #B4B0A6; background-clip: content-box; }
*::-webkit-scrollbar-track { background: transparent; }

/* --- Focus clavier : un opérateur passe six heures par jour ici ----------- */
:focus-visible {
  outline: 2px solid var(--primaire);
  outline-offset: 2px;
  border-radius: 2px;
}
.moment :focus-visible { outline-color: var(--or); }

/* Lien d'évitement : premier élément focalisable de chaque page d'app.
   Position fixe et translation, pour qu'il apparaisse au même endroit quel que
   soit le défilement de la page. */
.evitement {
  position: fixed; left: 8px; top: 8px; z-index: 100;
  background: var(--surface); border: 1px solid var(--primaire);
  color: var(--primaire); font-weight: 500;
  padding: 8px 14px; border-radius: var(--rayon);
  transform: translateY(calc(-100% - 16px));
  transition: transform var(--duree-court) var(--entree);
}
.evitement:focus { transform: none; text-decoration: none; }

/* Chiffres tabulaires : tout montant, poids, millimètre, DATE et numéro. Sans
   cela les colonnes ne s'alignent pas et l'outil a l'air amateur. */
.tabulaire, td.montant, td.poids, th.montant, th.poids {
  font-variant-numeric: tabular-nums;
  text-align: right;
}
td.date, .compteur-jours, .faits dd, .valeur, .total-bloc, kbd, .pagination {
  font-variant-numeric: tabular-nums;
}

/* --- Marque -------------------------------------------------------------- */
/* Marcellus est en réserve absolue, et la réserve est étroite : le wordmark,
   l'écran de connexion, la référence du passeport public. Rien d'autre.
   Les surfaces de travail — indicateurs, totaux, tableaux, formulaires —
   restent en Inter : un chiffre qu'on lit cent fois par jour se lit mieux en
   linéale, et l'outil doit rester fluide avant d'être signé.
   Jamais dans une liste, jamais en italique. */
.marque { font-family: var(--police-marque); font-weight: 400; }

/* Wordmark complet : picto à gauche, gap 12px, KRONOS en capitales espacées. */
.wordmark { display: inline-flex; align-items: center; gap: 12px; text-decoration: none; }
.wordmark .picto { width: 26px; height: 26px; flex: none; }
.wordmark .lettres {
  font-family: var(--police-marque); font-weight: 400;
  font-size: 1.2rem; letter-spacing: .16em; text-indent: .16em;
  color: var(--primaire); line-height: 1; text-transform: uppercase;
}
.wordmark:hover { text-decoration: none; }
.wordmark:hover .lettres { color: var(--primaire-survol); }

/* Légendes et labels techniques : Inter 500, 12px, capitales espacées. */
.legende {
  font-size: 12px; font-weight: 500; letter-spacing: .14em;
  text-transform: uppercase; color: var(--encre-douce);
}
/* Surtitre sur fond sombre : même dessin, plus espacé, doré. */
.moment .legende { letter-spacing: .2em; color: var(--or); }

/* ======================= Ossature ======================================== */
.app {
  display: grid;
  grid-template-columns: var(--barre-laterale) 1fr;
  grid-template-rows: var(--bandeau) 1fr;
  grid-template-areas: "laterale bandeau" "laterale contenu";
  min-height: 100vh;
}

/* --- Barre latérale ------------------------------------------------------ */
.laterale {
  grid-area: laterale;
  background: var(--surface);
  border-right: 1px solid var(--bordure);
  display: flex; flex-direction: column;
  /* Le défilement appartient au MENU, pas à la colonne entière.
     Auparavant la colonne entière défilait : sur une fenêtre d'environ 800 px
     de haut, le pied — Paramètres et Utilisateurs — passait sous le bord et
     n'était atteignable qu'en faisant défiler la barre elle-même. Rien ne le
     signalait, et « le module Utilisateurs a disparu » a été rapporté trois
     fois. Le pied reste désormais posé en bas de l'écran quelle que soit la
     hauteur ; seules les entrées du milieu défilent. */
  position: sticky; top: 0; height: 100vh; overflow: hidden;
}
.laterale-logo { display: block; padding: 13px 16px 12px; flex: none; }
.laterale-menu { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 4px 0 10px; }
.laterale-pied {
  flex: none;
  border-top: 1px solid var(--bordure); padding: 4px 0 10px;
}

/* Les douze entrées sont regroupées : un opérateur cherche « le flux
   commercial », pas la neuvième ligne d'une liste plate. */
.laterale-groupe { padding: 12px 16px 5px; }
.laterale-groupe:first-child { padding-top: 6px; }

.laterale a.entree {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 16px; color: var(--encre-douce);
  border-left: 3px solid transparent; text-decoration: none;
}
.laterale a.entree:hover { background: var(--fond); color: var(--encre); }
.laterale a.entree.active {
  background: var(--primaire-tint);
  border-left-color: var(--primaire);
  color: var(--primaire); font-weight: 500;
}
.laterale a.entree:focus-visible { outline-offset: -2px; }
.laterale .icone { width: 16px; height: 16px; flex: none; stroke-width: 1.5; }

/* --- Bandeau supérieur --------------------------------------------------- */
.bandeau {
  grid-area: bandeau;
  height: var(--bandeau);
  background: var(--surface);
  border-bottom: 1px solid var(--bordure);
  display: flex; align-items: center; gap: 16px;
  padding: 0 20px;
  position: sticky; top: 0; z-index: 40;
  /* Sans `min-width: 0`, la piste `1fr` de la grille prend la largeur
     MINIMALE du bandeau — nom, « Changer d'espace », « Déconnexion » en une
     rangée — et toute la page suit : mesuré à 505 px sur un écran de 390
     (Mydas, 08.09.2026). */
  min-width: 0;
}
.fil-ariane { display: flex; align-items: center; gap: 6px; color: var(--encre-attenuee); white-space: nowrap; }
.fil-ariane a { color: var(--encre-douce); }
.fil-ariane .courant { color: var(--encre); font-weight: 500; }
.recherche-globale { flex: 1; max-width: 420px; margin: 0 auto; position: relative; }
.recherche-globale input {
  width: 100%; height: 30px; padding: 0 62px 0 30px;
  border: 1px solid var(--bordure); border-radius: var(--rayon);
  background: var(--fond); font: inherit; color: var(--encre);
}
.recherche-globale input::placeholder { color: var(--encre-attenuee); }
.recherche-globale .icone {
  position: absolute; left: 8px; top: 7px; width: 16px; height: 16px;
  color: var(--encre-attenuee); pointer-events: none;
}
.recherche-globale kbd {
  position: absolute; right: 8px; top: 6px; pointer-events: none;
  font: 500 11px var(--police); color: var(--encre-attenuee);
  border: 1px solid var(--bordure); border-radius: 3px; padding: 0 4px;
  background: var(--surface);
}
.bandeau-compte { margin-left: auto; display: flex; align-items: center; gap: 10px; color: var(--encre-douce); }

/* --- Zone de contenu ----------------------------------------------------- */
/* La zone de travail, et sa BORNE HAUTE — ajoutée le 25.08.2026.

   Toutes les media queries de cette feuille étaient des `max-width` : rien
   n'avait jamais été dessiné au-dessus de 1280 px. Sur l'écran de 3836 px du
   client, la conséquence n'est pas cosmétique : un champ de saisie faisait
   1300 px, une zone de texte davantage, et les colonnes d'un tableau
   s'écartaient au point que l'œil ne rattachait plus une valeur à sa ligne.
   Un texte se lit mal au-delà d'une centaine de caractères par ligne ; un
   formulaire, plus mal encore.

   La borne est posée sur les ENFANTS et non sur `.contenu` lui-même : le
   pseudo-élément qui porte la fêlure d'angle est en `fixed` et appartient à la
   fenêtre entière, pas à la colonne de lecture. */
.contenu { grid-area: contenu; padding: 20px; min-width: 0; }

/* Le lien d'une rangée de tableau — ajouté le 25.08.2026.

   Les vingt-cinq tableaux du produit ne s'ouvraient QU'À LA SOURIS : la rangée
   portait `data-href` et un écouteur `click`, rien d'autre. Un horloger au
   clavier tabulait de « Nouvelle montre » jusqu'au pied de page sans jamais
   atteindre une seule ligne, et ne pouvait ouvrir aucune fiche — ni montre, ni
   tiers, ni vente, ni intervention. Au lecteur d'écran, le tableau était
   annoncé comme une grille inerte.

   Un VRAI lien dans la première cellule, et non un `tabindex` sur la rangée :
   lui seul donne d'un coup le focus, la touche Entrée, le clic du milieu, le
   menu contextuel et l'annonce « lien ». `data-href` reste pour le confort de
   la souris — cliquer n'importe où dans la ligne.

   Il ne se voit pas tant qu'on ne le vise pas : dans un tableau dense, vingt
   libellés soulignés en doré feraient un sapin de Noël. */
.lien-ligne { color: inherit; text-decoration: none; }
.lien-ligne:hover { color: var(--primaire); text-decoration: underline; }
.lien-ligne:focus-visible {
  outline: 2px solid var(--primaire); outline-offset: 2px;
  border-radius: 2px; color: var(--primaire);
}

/* ======================= Vue liste ======================================= */
.barre-actions {
  display: flex; align-items: center; gap: 10px; margin-bottom: 12px;
  flex-wrap: wrap;
}
.barre-actions .compteur { margin-left: auto; color: var(--encre-attenuee); }

.carte {
  background: var(--surface); border: 1px solid var(--bordure);
  border-radius: var(--rayon);
}
/* En-tête de carte : la légende technique, pas un titre de plus. */
.carte-entete {
  display: flex; align-items: center; gap: 12px;
  padding: 11px 16px; border-bottom: 1px solid var(--bordure);
}
.carte-entete h2 { margin: 0; font-size: 12px; font-weight: 500; letter-spacing: .14em; text-transform: uppercase; color: var(--encre-douce); }
.carte-entete .appoint { margin-left: auto; color: var(--encre-attenuee); font-size: 12.5px; }

table.liste { width: 100%; border-collapse: collapse; background: var(--surface); }
table.liste th, table.liste td {
  height: var(--ligne-tableau);
  padding: 8px 12px;
  border-bottom: 1px solid var(--bordure);
  text-align: left; vertical-align: middle;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
table.liste th {
  font-size: 12px; font-weight: 500; letter-spacing: .06em;
  text-transform: uppercase; color: var(--encre-attenuee);
  background: var(--surface);
}
/* Le collant ne vaut QUE pour la ligne de titres. Posé sur tous les `th`, il
   emportait aussi ceux d'un `tfoot` — la ligne « Total » d'une fiche de devis
   se décollait de son montant au défilement — et ceux d'un `th scope="row"`,
   qui flottaient au-dessus de leur propre rangée. Rétroporté de Mydas, où le
   même défaut avait été payé. */
table.liste thead th { position: sticky; top: var(--bandeau); z-index: 10; }
/* `.prose` : la cellule qui porte une PHRASE, et non une référence, une date
   ou un montant. Le `nowrap` ci-dessus vaut pour une liste — il devient faux
   dès qu'une cellule contient du texte suivi, et personne ne le voit avant
   d'ouvrir l'écran sur un jeu réel : « Patek Philippe · Nautilus · 5711/1A »
   tenait la colonne « Objet » à 499 px, et seize écrans faisaient défiler la
   page entière de côté, leurs boutons d'action hors champ. Nommer la cellule
   coûte un mot ; l'oublier fait sortir la colonne de droite de l'écran. */
table.liste th.prose, table.liste td.prose {
  /* `overflow-wrap` autant que `white-space` : une adresse électronique est
     UN mot pour le navigateur. Sans lui, la colonne « E-mail » revenait à la
     ligne nulle part et poussait encore la page de seize pixels. */
  white-space: normal; overflow-wrap: anywhere;
}

/* Le même filet ouvre la carte de chaque tableau, au-dessus de la ligne de
   titres — jamais derrière une vignette de montre ni une cellule de couleur,
   ce que la charte protège pour de bonnes raisons : une vignette de montre
   se juge sur fond neutre, sans filet qui la traverse.

   Il est porté par la CARTE et non par les cellules d'en-tête : celles-ci sont
   en `overflow: hidden` pour l'ellipse, ce qui rognait leur propre
   pseudo-élément — le filet existait dans le CSS et ne paraissait nulle part.
   Et un fond par cellule aurait redémarré le motif à chaque colonne.

   Cadrage vertical différent de celui du bandeau : deux traces identiques
   feraient une frise, et une frise est un décor. */
table.liste tbody tr:hover { background: var(--fond); cursor: pointer; }
/* Pendant que la PAGE défile, le survol est suspendu. Sans cela, la ligne
   sous le curseur change à chaque image du défilement, sa couleur de fond
   avec elle — et la liste entière repeint à chaque image, sur le fil
   principal. Mesuré le 03.09.2026 (Chromium, 3 s de molette sur une liste
   de 50 lignes) : ~500 peintures avec le curseur sur le tableau, zéro avec le
   curseur à côté. C'est ce que le client a décrit comme « le module stock
   lague » le jour où son stock a dépassé un écran. La classe est posée par
   kronos.js le temps du défilement ; sans JavaScript, rien ne change : le
   survol reste entier. Règle CSS-5 de l'auditeur. */
body.defile table.liste tbody { pointer-events: none; }
table.liste tbody tr:last-child td { border-bottom: none; }

/* Urgence : un filet à gauche et le chiffre en couleur. Le fond des rangées
   reste neutre — les listes portent des vignettes de montres, et un fond
   teinté fausse le jugement d'une couleur (DESIGN.md). */
table.liste tr.ligne-retard td:first-child { box-shadow: inset 2px 0 0 var(--danger); }
table.liste tr.ligne-urgence td:first-child { box-shadow: inset 2px 0 0 var(--avert); }
table.liste tr.ligne-urgence td.compteur-jours { color: var(--avert); font-weight: 500; }
table.liste tr.ligne-retard td.compteur-jours { color: var(--danger); font-weight: 500; }
table.liste .col-coche { width: 34px; }
table.liste .vignette {
  width: 28px; height: 28px; border-radius: 3px; object-fit: cover;
  display: block; background: var(--surface); border: 1px solid var(--bordure);
}

/* Filtres rapides en pastilles au-dessus du tableau. */
.filtres-rapides { display: flex; gap: 6px; flex-wrap: wrap; }
.filtre-pastille {
  border: 1px solid var(--bordure); border-radius: 999px;
  background: var(--surface); color: var(--encre-douce);
  padding: 3px 12px; font: inherit; cursor: pointer; text-decoration: none;
}
.filtre-pastille:hover { border-color: var(--encre-attenuee); text-decoration: none; }
.filtre-pastille.actif {
  background: var(--primaire-tint); border-color: var(--primaire);
  color: var(--primaire); font-weight: 500;
}

/* Pagination serveur. */
.pagination { display: flex; align-items: center; gap: 8px; padding: 10px 12px; color: var(--encre-attenuee); }
.pagination a { padding: 2px 8px; border: 1px solid var(--bordure); border-radius: var(--rayon); }

/* ======================= Pastilles de statut ============================= */
.pastille {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 1px 9px; border-radius: 999px; font-size: 12.5px; font-weight: 500;
  border: 1px solid transparent; white-space: nowrap;
}
.pastille::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.pastille-succes { color: var(--succes); background: var(--succes-tint); }
.pastille-avert  { color: var(--avert);  background: var(--avert-tint); }
.pastille-danger { color: var(--danger); background: var(--danger-tint); }
.pastille-info   { color: var(--info);   background: var(--info-tint); }
.pastille-neutre { color: var(--encre-douce); background: var(--fond); border-color: var(--bordure); }
.pastille-accent { color: var(--accent-texte); background: var(--accent-tint); }

/* Rôles de tiers. */
.pastille-role { font-size: 11.5px; padding: 0 8px; }

/* Badge repère (annotation numérotée) — pastille bordée, chiffre tabulaire. */
.repere {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 22px; padding: 1px 7px 2px;
  background: var(--fond); border: 1px solid var(--primaire); border-radius: var(--rayon);
  font-size: 12px; font-weight: 500; color: var(--primaire);
  font-variant-numeric: tabular-nums; line-height: 1.5;
}

/* ======================= Boutons ========================================= */
.btn {
  display: inline-flex; align-items: center; gap: 6px;
  height: 30px; padding: 0 14px;
  border: 1px solid var(--bordure); border-radius: var(--rayon);
  background: var(--surface); color: var(--encre);
  font: inherit; font-weight: 500; cursor: pointer; text-decoration: none;
  white-space: nowrap;
  transition: background var(--duree-court) var(--entree),
              border-color var(--duree-court) var(--entree);
}
.btn:hover { background: var(--fond); text-decoration: none; color: var(--encre); }
.btn-primaire { background: var(--primaire); border-color: var(--primaire); color: var(--surface); }
.btn-primaire:hover { background: var(--primaire-survol); border-color: var(--primaire-survol); color: var(--surface); }
.btn-danger { color: var(--danger); border-color: var(--danger); }
.btn-danger:hover { background: var(--danger-tint); color: var(--danger); }
.btn-secondaire { color: var(--primaire); border-color: var(--primaire); }
.btn-secondaire:hover { background: var(--primaire-tint); color: var(--primaire-survol); }
.btn-discret { border-color: transparent; background: transparent; color: var(--encre-douce); }
.btn-discret:hover { background: var(--fond); color: var(--encre); }
.btn-icone { width: 30px; min-width: 30px; padding: 0; justify-content: center; }
.btn:disabled { opacity: .45; cursor: not-allowed; }
.btn .icone { width: 16px; height: 16px; }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* ======================= Champs ========================================== */
.champ { margin-bottom: 14px; }
.champ label { display: block; margin-bottom: 4px; color: var(--encre-douce); font-weight: 500; }
.champ input, .champ select, .champ textarea {
  width: 100%; padding: 6px 10px; height: 32px;
  border: 1px solid var(--bordure); border-radius: var(--rayon);
  background: var(--surface); color: var(--encre); font: inherit;
  transition: border-color var(--duree-court) var(--entree);
}
.champ textarea { height: auto; min-height: 72px; resize: vertical; }
.champ input::placeholder, .champ textarea::placeholder { color: var(--encre-attenuee); }
.champ input:focus, .champ select:focus, .champ textarea:focus { border-color: var(--primaire); }

/* Une case à cocher n'est pas un champ de saisie, et la règle ci-dessus ne lui
   était pas destinée — elle l'atteignait quand même, par `input`. La case
   recevait donc 100 % de large, 32 px de haut, un filet et un rembourrage :
   sur WebKit elle s'étirait sur toute la colonne et repoussait son libellé à
   l'autre bout de la ligne ; sur Chrome elle devenait un rectangle de
   13 × 32 px, décalé de sept pixels sous le mot qu'elle étiquette.
   Rétroportage du 31.08.2026 — le défaut a été constaté sur Mydas, à l'écran
   « Nouveau fournisseur », et Kronos le portait au même endroit ainsi que sur
   « Rôles » du tiers et sur les SOIXANTE cases « rattacher » d'une fiche de
   lot. Six gabarits portaient déjà `style="width:auto;height:auto"` en ligne :
   c'est cette rustine recopiée qui rendait l'oubli invisible ailleurs. La
   règle vit ici une fois ; la rustine nulle part.
   `flex: none` couvre le libellé en flex, où la case se faisait sinon étirer à
   la hauteur de la ligne. */
.champ input[type="checkbox"], .champ input[type="radio"] {
  width: auto; height: auto; padding: 0; border: 0; background: none;
  flex: none;
}
/* Le sélecteur de fichier garde le filet et la largeur du champ, mais pas la
   hauteur fixe : son bouton natif mesure plus que les 20 px de contenu qui
   restaient sous les 32 px, et se faisait rogner en bas. */
.champ input[type="file"] { height: auto; min-height: 32px; padding: 5px 10px; }
.champ input[readonly] { background: var(--fond); color: var(--encre-douce); }
.champ .aide { font-size: 12px; color: var(--encre-attenuee); margin-top: 3px; }
/* Messages d'erreur : précis, à côté du champ concerné. Jamais de bandeau. */
.champ .erreur { font-size: 12.5px; color: var(--danger); margin-top: 3px; }
.champ.en-erreur input, .champ.en-erreur select, .champ.en-erreur textarea { border-color: var(--danger); }
/* Le plafond de piste n'est pas cosmétique : sans lui, `1fr` étire chaque
   champ à toute la largeur disponible, et sur un grand écran on saisit une
   date dans une case de 560 px. Même forme que Mydas. */
/* `grid-auto-columns: 0` : dans une carte étroite — la colonne de droite
   d'une fiche, 331 px — `auto-fill` ne pose qu'UNE piste, et un champ qui en
   réclame deux (l'idiome que la règle CSS-1 de la recette interdit, encore
   présent dans une vingtaine de gabarits) en faisait naître une seconde. Cette
   piste implicite naissait en `auto`, à la largeur de son contenu, et sortait
   de la carte puis de l'écran : la fiche d'une fourniture poussait la page de
   45 px. Bornée à zéro, la demande d'une piste de plus se ramène à celle qui
   existe. La règle est inerte partout où la carte en tient déjà deux. */
.grille-champs {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 360px));
  grid-auto-columns: 0; gap: 0 16px;
}

/* ======================= Vue fiche ======================================= */
.fiche-entete {
  display: flex; align-items: flex-start; gap: 16px; margin-bottom: 16px;
  flex-wrap: wrap;
}
.fiche-titre h1 { font-size: 1.35rem; margin: 0; }
.fiche-titre .sous-titre { color: var(--encre-douce); }
.fiche-actions { display: flex; gap: 8px; flex-wrap: wrap; }

/* Barre de statut : le cycle de vie de l'objet, en haut à droite. */
.barre-statut { display: flex; margin-left: auto; }
.barre-statut .etape {
  padding: 4px 14px; border: 1px solid var(--bordure);
  background: var(--surface); color: var(--encre-attenuee);
  border-left-width: 0; font-size: 12.5px; white-space: nowrap;
}
.barre-statut .etape:first-child { border-left-width: 1px; border-radius: var(--rayon) 0 0 var(--rayon); }
.barre-statut .etape:last-child { border-radius: 0 var(--rayon) var(--rayon) 0; }
.barre-statut .etape.courante {
  background: var(--primaire-tint); color: var(--primaire);
  border-color: var(--primaire); border-left-width: 1px; font-weight: 500;
}

.fiche-colonnes { display: grid; grid-template-columns: 2fr 1fr; gap: 16px; align-items: start; }
/* Sans cela, un tableau large (colonnes en nowrap) force sa colonne de grille
   et fait défiler la page entière à l'horizontale. */
.fiche-colonnes > * { min-width: 0; }
.fiche-colonnes--deux { grid-template-columns: 1fr 1fr; }
@media (max-width: 1100px) {
  .fiche-colonnes, .fiche-colonnes--deux { grid-template-columns: 1fr; }
}

/* Un tableau plus large que son cadre défile dans son propre cadre, jamais en
   emportant la page avec lui. */
.tableau-defilant { overflow-x: auto; }

/* Dans une carte composite (fiche voyage, tableau de bord), l'en-tête collant
   n'a pas de sens : il se fige au défilement de la page et flotte par-dessus
   le contenu de la carte — l'en-tête qui recouvrait « Aucun frais enregistré ».
   Le collant reste réservé aux pages-listes pleine hauteur. */
.tableau-defilant table.liste th { position: static; }

/* Cadre posé par kronos.js autour de CHAQUE table.liste qui n'en a pas. Il ne
   défile que lorsque le tableau déborde (classe `deborde`, mesurée par un
   ResizeObserver) : tant que le tableau tient, le cadre reste transparent et
   l'en-tête collant continue de coller — un `overflow-x: auto` permanent
   ferait du cadre le conteneur de défilement, et l'en-tête n'aurait plus rien
   à quoi coller. Sur un écran étroit, le tableau défile dans son cadre et la
   page garde sa largeur ; mesuré avant : /tiers à 1219 px sur une tablette de
   768. */
.tableau-defilant--auto { overflow: visible; }
.tableau-defilant--auto.deborde { overflow-x: auto; overscroll-behavior-x: contain; }
.tableau-defilant--auto:not(.deborde) table.liste thead th { position: sticky; }
.tableau-defilant--auto.deborde table.liste { min-width: max-content; }

/* Un état vide vit dans une cellule de tableau : sans ceci, le nowrap des
   cellules tronque son texte au milieu d'un mot et force un défilement
   horizontal absurde. */
table.liste td:has(> .etat-vide) { white-space: normal; }
.fiche-section { padding: 16px; }
.fiche-section + .fiche-section { border-top: 1px solid var(--bordure); }
.fiche-section h2 { font-size: .95rem; color: var(--encre-douce); }

/* Liste de faits (libellé/valeur) dans une fiche. */
.faits { display: grid; grid-template-columns: max-content 1fr; gap: 4px 18px; }
.faits dt { color: var(--encre-attenuee); }
.faits dd { margin: 0; }

/* Index typographique : rangées séparées par des filets, sans tableau.
   Pattern de la charte — pour les listes riches et les faits mis en scène. */
.index-liste { border-top: 1px solid var(--bordure); }
.index-liste .rangee {
  display: flex; align-items: baseline; gap: 16px;
  padding: 11px 2px; border-bottom: 1px solid var(--bordure);
  color: var(--encre-douce);
}
.index-liste .rangee .cle {
  flex: none; width: 130px; font-weight: 500; color: var(--encre);
}
.index-liste .rangee .valeur { font-size: inherit; font-weight: 400; color: var(--encre); }

/* ======================= Onglets ========================================= */
/* `flex-wrap` : les onglets des réglages sont neuf, et la dernière paire
   — « Éléments du full set », « Canaux de publication » — sortait de la
   fenêtre en poussant la page de 157 px de côté. Une barre d'onglets qui
   ne tient pas se replie ; elle ne déplace pas l'écran. */
.onglets { display: flex; flex-wrap: wrap; gap: 2px; border-bottom: 1px solid var(--bordure); margin-bottom: 0; }
.onglet {
  padding: 8px 14px; color: var(--encre-douce); cursor: pointer;
  border: none; background: none; font: inherit;
  border-bottom: 2px solid transparent; text-decoration: none;
}
.onglet:hover { color: var(--encre); text-decoration: none; }
.onglet.actif { color: var(--primaire); border-bottom-color: var(--primaire); font-weight: 500; }
.onglet-panneau { padding: 16px; }

/* ======================= Blocs pliables (calculateur) ==================== */
.bloc-pliable { border: 1px solid var(--bordure); border-radius: var(--rayon); background: var(--surface); margin-bottom: 12px; }
.bloc-pliable > .bloc-titre {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 10px 14px; font: inherit; font-weight: 500; color: var(--encre);
  background: none; border: none; cursor: pointer; text-align: left;
}
.bloc-pliable.vide > .bloc-titre { color: var(--encre-attenuee); font-weight: 400; }
.bloc-titre .total-bloc { margin-left: auto; font-variant-numeric: tabular-nums; color: var(--encre-douce); }
.bloc-corps {
  border-top: 1px solid var(--bordure); padding: 10px 14px;
  animation: bloc-ouvre var(--duree-moyen) var(--sortie);
}
.bloc-titre .chevron { transition: transform var(--duree-court) var(--entree); width: 16px; height: 16px; }
.bloc-titre .chevron.ouvert { transform: rotate(90deg); }
@keyframes bloc-ouvre {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: none; }
}

/* ======================= Panneau latéral ================================= */
.panneau-fond {
  position: fixed; inset: 0; background: rgba(26, 29, 27, .28); z-index: 90;
  animation: voile-entre var(--duree-moyen) var(--entree);
}
.panneau {
  position: fixed; top: 0; right: 0; bottom: 0; width: 420px; max-width: 92vw;
  background: var(--surface); border-left: 1px solid var(--bordure); z-index: 91;
  display: flex; flex-direction: column;
  animation: panneau-entre var(--duree-long) var(--sortie);
}
.panneau-entete {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 16px; border-bottom: 1px solid var(--bordure);
}
.panneau-corps { padding: 16px; overflow-y: auto; flex: 1; }
@keyframes panneau-entre { from { transform: translateX(24px); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes voile-entre { from { opacity: 0; } to { opacity: 1; } }

/* ======================= Dialogue ======================================== */
.dialogue-fond {
  position: fixed; inset: 0; background: rgba(26, 29, 27, .28); z-index: 95;
  display: flex; align-items: flex-start; justify-content: center; padding-top: 12vh;
  animation: voile-entre var(--duree-moyen) var(--entree);
}
.dialogue {
  width: 440px; max-width: 92vw;
  background: var(--surface); border: 1px solid var(--bordure); border-radius: var(--rayon);
  animation: dialogue-entre var(--duree-moyen) var(--sortie);
}
.dialogue-entete { padding: 14px 16px; border-bottom: 1px solid var(--bordure); font-weight: 500; }
.dialogue-corps { padding: 16px; }
.dialogue-pied { padding: 12px 16px; border-top: 1px solid var(--bordure); display: flex; justify-content: flex-end; gap: 8px; }
@keyframes dialogue-entre { from { transform: scale(.98) translateY(-6px); opacity: 0; } to { transform: none; opacity: 1; } }

/* ======================= Avis et alertes ================================= */
/* « Le système ne décide jamais à la place de l'utilisateur : alerter sans
   bloquer. » Un avis se lit, il ne ressemble pas à une erreur. */
.avis {
  display: flex; align-items: baseline; gap: 10px;
  padding: 11px 14px; border: 1px solid var(--bordure); border-radius: var(--rayon);
  background: var(--surface); color: var(--encre-douce);
}
.avis .titre { font-weight: 500; color: var(--encre); }
.avis .appoint { color: var(--encre-attenuee); }
.avis-avert { border-color: #E9CFA8; background: var(--avert-tint); }
.avis-avert .titre { color: var(--avert); }
/* La proposition du tutoriel au tableau de bord (24.09.2026, transposé de
   Mydas) : une carte, jamais une fenêtre modale qu'on ferme sans la lire. */
.avis-tutoriel { align-items: center; flex-wrap: wrap; }
.avis-tutoriel .appoint { flex: 1 1 300px; }
.avis-actions { display: flex; align-items: center; gap: 8px; margin-left: auto; }
.avis-actions form { margin: 0; }

/* L'en-tête de l'accueil d'un module : son nom, ce qu'il fait, et la flèche de
   son tutoriel. La description se lit d'un trait sans repousser le tableau
   hors de l'écran. */
.entete-module { margin: 0 0 12px; }
.entete-module h1 { font-size: 1.35rem; margin: 0 0 4px; }
.module-description { margin: 0; max-width: 72ch; color: var(--encre-attenuee); line-height: 1.5; }
.hv-titre .module-description { margin-top: 6px; }
/* La flèche du tutoriel, repère discret mais cible franche. Au doigt, 44 px de
   haut comme toute cible de terrain ; à la souris, 32 px suffisent et laissent
   le tableau remonter. */
.lien-discret-tutoriel {
  display: inline-flex; align-items: center; min-height: 32px;
  color: var(--accent-texte); font-size: 13px; text-decoration: none;
}
.lien-discret-tutoriel::before { content: "▸"; margin-right: 7px; }
.lien-discret-tutoriel:hover { text-decoration: underline; }
@media (pointer: coarse) { .lien-discret-tutoriel { min-height: 44px; } }
.liste-tutoriels { list-style: none; margin: 10px 0 0; padding: 0; display: grid; gap: 8px; }
.liste-tutoriels li { display: grid; }
.liste-tutoriels .texte-attenue { font-size: 13px; line-height: 1.45; }

/* ======================= États vides ===================================== */
/* Le seul endroit du quotidien où le picto a droit de cité : une liste vide
   n'est pas une erreur, c'est un moment de calme. */
.etat-vide {
  display: flex; flex-direction: column; align-items: center;
  gap: 14px; padding: 44px 24px; text-align: center;
}
.etat-vide .picto { width: 30px; height: 30px; opacity: .5; }
.etat-vide .propos { color: var(--encre-douce); max-width: 44ch; margin: 0; }
.etat-vide .propos strong { font-weight: 500; color: var(--encre); }
/* Variante en cellule de tableau, pour les listes existantes. */
td > .etat-vide { padding: 30px 16px; }

/* ======================= Moments forts =================================== */
/* Aplat NOIR cadré d'un double filet doré. Connexion et splash
   uniquement : jamais une surface de travail, jamais près d'une montre. */
.moment {
  background: var(--noir-profond);
  color: #FFFFFF;
  position: relative;
}
.moment .doux { color: var(--sur-noir); }
/* Les deux filets de cadre : 1px à 36px du bord, 1px à 42px. */
.cadre-or::before, .cadre-or::after {
  content: ""; position: absolute; pointer-events: none; border: 1px solid var(--filet-or);
}
.cadre-or::before { inset: 20px; }
.cadre-or::after { inset: 26px; border-color: var(--filet-or-faible); }

/* ======================= Divers ========================================== */
.flashes { position: fixed; top: calc(var(--bandeau) + 8px); right: 16px; z-index: 99; max-width: 380px; }
.flash {
  padding: 9px 14px; border-radius: var(--rayon); border: 1px solid var(--bordure);
  margin-bottom: 8px; background: var(--surface);
  animation: flash-entre var(--duree-long) var(--sortie);
}
.flash-success { background: var(--succes-tint); border-color: var(--succes); color: var(--succes); }
.flash-error   { background: var(--danger-tint); border-color: var(--danger); color: var(--danger); }
.flash-info    { background: var(--info-tint);   border-color: var(--info);   color: var(--info); }
@keyframes flash-entre { from { transform: translateY(-8px); opacity: 0; } to { transform: none; opacity: 1; } }

/* Indicateur de chargement HTMX : un tableau qui se recharge sans signal
   donne l'impression d'une application figée. */
.htmx-indicator { opacity: 0; transition: opacity .15s ease; }
.htmx-request .htmx-indicator, .htmx-request.htmx-indicator { opacity: 1; }
/* La roulette d'attente. Elle s'appelait `.indicateur` — un nom que les
   gabarits ont pris pour « le chiffre d'un indicateur », et vingt-six valeurs
   de KPI l'ont employé : le tableau de bord, les inventaires et tous les
   rapports affichaient leurs montants dans un cercle de 14 px, en rotation
   perpétuelle, le texte replié à un caractère par ligne par-dessus son propre
   libellé. Le nom est donc devenu impossible à confondre. Trouvé sur un
   enregistrement d'usage le 25.08.2026 ; un test tient désormais la règle. */
.roulette {
  display: inline-block; width: 14px; height: 14px;
  border: 2px solid var(--bordure); border-top-color: var(--primaire);
  border-radius: 50%; animation: rotation .7s linear infinite;
}
@keyframes rotation { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .roulette { animation: none; border-top-color: var(--encre-attenuee); }
}

/* --- Sélecteur cherchable (V1.1) --------------------------------------------
   On tape un code, on trouve. Remplace les listes déroulantes qu'il fallait
   faire défiler. Sobre : un champ, une liste, un filet — pas d'ombre portée. */
.selecteur { position: relative; }
.selecteur-saisie {
  width: 100%; height: 32px; padding: 0 10px;
  border: 1px solid var(--bordure); border-radius: var(--rayon);
  background: var(--surface); color: var(--encre); font: inherit;
}
/* La bordure seule ne suffit pas : elle passe de gris à doré, un écart de
   teinte que beaucoup d'yeux ne lisent pas. L'anneau, si. */
.selecteur-saisie:focus-visible {
  border-color: var(--primaire);
  outline: 2px solid var(--primaire); outline-offset: 1px;
}
.selecteur-saisie:focus { border-color: var(--primaire); }
.selecteur-saisie::placeholder { color: var(--encre-attenuee); }
.selecteur-attente { position: absolute; right: 26px; top: 8px; }
.selecteur-liste {
  position: absolute; z-index: 30; left: 0; right: 0; top: calc(100% + 3px);
  max-height: 292px; overflow-y: auto;
  background: var(--surface); border: 1px solid var(--primaire);
  border-radius: var(--rayon);
  display: flex; flex-direction: column;
}
/* Le display:flex ci-dessus l'emporte sur le style navigateur de [hidden] :
   sans cette règle, la liste ne se fermait JAMAIS — ni au clic à côté, ni
   après sélection (régression vue en démo le 17.08.2026). Le garde-fou est
   GLOBAL : hidden doit gagner sur n'importe quel display posé par une classe,
   pour ce composant et tous ceux qui viendront. */
[hidden] { display: none !important; }
.selecteur-option {
  display: flex; align-items: baseline; gap: 10px; width: 100%;
  padding: 7px 10px; text-align: left; font: inherit; color: var(--encre);
  background: none; border: 0; border-bottom: 1px solid var(--bordure);
  cursor: pointer;
}
.selecteur-option:last-child { border-bottom: 0; }
/* Survol et focus étaient rendus À L'IDENTIQUE, et l'anneau supprimé. Un
   vendeur qui parcourait vingt clients au clavier n'avait pour repère qu'un
   fond beige à 1,19:1 — indiscernable du blanc sur un écran de bureau bien
   éclairé. Il validait au jugé, et rattachait la vente au mauvais client.
   L'`outline-offset` est NÉGATIF : `.selecteur-liste` défile en `overflow-y`,
   et un anneau posé à l'extérieur y serait rogné. */
.selecteur-option:hover { background: var(--primaire-tint); }
.selecteur-option:focus-visible {
  background: var(--primaire-tint);
  outline: 2px solid var(--primaire); outline-offset: -2px;
}
.selecteur-principal { font-weight: 500; white-space: nowrap; }
.selecteur-appoint {
  color: var(--encre-douce); font-size: 12.5px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.selecteur-montant { margin-left: auto; color: var(--encre-douce); white-space: nowrap; }
.selecteur-note { padding: 10px; color: var(--encre-attenuee); font-size: 12.5px; }
/* Dans une rangée de tableau (calculateur, lignes de vente), la cellule est
   étroite : la liste garde son ancrage sur le champ mais s'élargit pour rester
   lisible. Un tableau ne rogne pas ce qui dépasse de ses cellules. */
td .selecteur-liste { min-width: 320px; }

/* --- Documents joints (V1.1) ------------------------------------------------
   Bloc partagé par la fiche prêt, la fiche montre et la fiche vente. Sobre :
   une liste, une zone de dépôt, rien de plus. Aucune ombre portée, un filet
   pour séparer — l'ERP est carré (DESIGN.md). */
.documents-liste { list-style: none; margin: 0; padding: 0; }
/* `flex-wrap` : la ligne porte un nom de fichier, un horodatage avec son
   auteur (`nowrap`, et c'est voulu) et un bouton. Sur une fiche de montre au
   nom long, les trois ne tenaient pas et la ligne poussait la page 97 px hors
   de la fenêtre. Elle se replie maintenant plutôt que de déplacer l'écran. */
.documents-liste li {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
  padding: 7px 16px; border-bottom: 1px solid var(--bordure);
  min-height: var(--ligne-tableau);
}
.documents-liste li:last-child { border-bottom: none; }
.documents-nom { font-weight: 500; overflow-wrap: anywhere; }
.documents-meta {
  margin-left: auto; color: var(--encre-attenuee); font-size: 12.5px;
  white-space: nowrap;
}
.documents-supprimer { display: flex; }
.documents-vide { padding: 14px 16px; margin: 0; }
.documents-erreur {
  margin: 0 16px 12px; padding: 8px 10px;
  background: var(--danger-tint); color: var(--danger);
  border: 1px solid var(--danger); border-radius: var(--rayon);
  font-size: 13px;
}
.documents-depot { padding: 14px 16px 16px; border-top: 1px solid var(--bordure); }
.documents-zone {
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  padding: 18px 14px; text-align: center; cursor: pointer;
  border: 1px dashed var(--bordure); border-radius: var(--rayon);
  background: var(--fond); color: var(--encre-douce);
  transition: border-color var(--duree-court) var(--entree),
              background var(--duree-court) var(--entree);
}
.documents-zone:hover { border-color: var(--primaire); }
.documents-zone:focus-within { border-color: var(--primaire); border-style: solid; }
.documents-zone-survol {
  border-color: var(--primaire); border-style: solid; background: var(--primaire-tint);
}
.documents-zone-remplie {
  border-style: solid; border-color: var(--primaire); background: var(--surface);
}
.documents-zone-remplie .documents-invite { color: var(--primaire); font-weight: 500; }
/* Le champ natif est masqué, jamais retiré du flux : il reste atteignable au
   clavier et le label porte le clic.
   Le sélecteur porte le type : sans lui, `.champ input` (une classe ET un
   type) l'emportait sur `.documents-fichier` (une classe) et rendait au champ
   ses 100 % de large. Masqué par `clip-path`, il restait invisible — mais sa
   boîte, posée en absolu, poussait la page au-delà de la fenêtre : une barre
   de défilement horizontale sans rien à voir au bout. */
input.documents-fichier {
  position: absolute; width: 1px; height: 1px; opacity: 0;
  overflow: hidden; clip-path: inset(50%);
}
.documents-invite { overflow-wrap: anywhere; }
.documents-formats { font-size: 12px; }
.documents-champs {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: 12px; margin-top: 12px;
}
.documents-champs .champ { margin-bottom: 0; flex: 1 1 160px; }
.documents-attente { display: block; margin-top: 8px; font-size: 12.5px; }

/* Une valeur recalculée par le serveur doit se voir changer, sinon
   l'opérateur ne sait pas si le montant qu'il lit est à jour. */
.valeur-fraiche { animation: valeur-change var(--duree-long) var(--sortie); }
@keyframes valeur-change {
  from { opacity: .35; filter: blur(3px); }
  to   { opacity: 1; filter: none; }
}

/* Erreur de validation : le champ se signale une fois, puis redevient neutre. */
.champ.en-erreur input, .champ.en-erreur select, .champ.en-erreur textarea {
  animation: secousse 320ms var(--entree);
}
@keyframes secousse {
  0%, 100% { transform: none; }
  20% { transform: translateX(-4px); }
  45% { transform: translateX(3px); }
  70% { transform: translateX(-2px); }
}

/* Indicateurs en cartes (tableau de bord, rapports, inventaires, fiche tiers).
   `minmax(170px, 280px)` et non `1fr` : sur un écran large, `1fr` étalait six
   cartes à 586 px chacune pour y loger un nombre de six caractères. Le regard
   traversait un demi-mètre entre deux chiffres qu'il faut comparer. */
.indicateurs {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 280px));
  gap: 12px; margin-bottom: 16px;
}
/* En COLONNE, et ce n'est pas cosmétique : le libellé et la valeur sont deux
   `<span>`, donc en ligne par défaut. Ils s'affichaient côte à côte, et le
   `margin-top` de la valeur — écrit pour un bloc — n'y pouvait rien. */
.indicateur-carte {
  padding: 14px 16px;
  display: flex; flex-direction: column; align-items: flex-start; gap: 3px;
}
.indicateur-carte .libelle {
  font-size: 12px; font-weight: 500; letter-spacing: .1em;
  text-transform: uppercase; color: var(--encre-attenuee);
}
.indicateur-carte .valeur {
  font-weight: 500;
  font-size: 1.35rem; line-height: 1.2; color: var(--encre);
  font-variant-numeric: tabular-nums;
}

/* Index chiffré : la bande qui ouvre le tableau de bord. Pas cinq boîtes de
   poids égal — un index typographique, séparé par des filets, dont le premier
   chiffre porte le noir de la marque. La hiérarchie vient de la taille, du
   filet et de la couleur, pas d'une police à empattements : c'est un écran
   qu'on ouvre chaque matin pour lire des montants. */
/* La piste est BORNÉE, et pas `1fr`. `auto-fit` sans plafond étale ce qu'on lui
   donne sur toute la largeur disponible : à 1680 px de zone utile, un compteur
   à deux chiffres se retrouvait au centre d'une case de 560 px — et de 1646 px
   quand la bande n'en portait qu'un seul. C'est le défaut déjà corrigé sur
   `.indicateurs`, et c'est le même correctif. `justify-content: start` garde
   les mesures groupées à gauche : elles se lisent de gauche à droite, pas
   comme une rangée d'icônes centrée. */
.index-chiffres {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 340px));
  justify-content: start;
  margin-bottom: 22px; background: var(--surface);
  border: 1px solid var(--bordure); border-radius: var(--rayon);
  overflow: hidden;
}
.index-chiffres .mesure { padding: 18px 20px 20px; border-right: 1px solid var(--bordure); }
.index-chiffres .mesure:last-child { border-right: none; }
.index-chiffres .libelle {
  font-size: 12px; font-weight: 500; letter-spacing: .1em;
  text-transform: uppercase; color: var(--encre-attenuee);
  display: block; min-height: 2.6em;
}
/* 1.35rem et pas davantage : à cinq colonnes, c'est la taille maximale où un
   montant à sept chiffres tient encore sur une ligne. Un montant qui passe à
   la ligne coûte plus en lisibilité qu'il ne rapporte en présence. */
.index-chiffres .valeur {
  display: block; margin-top: 6px;
  font-weight: 500; letter-spacing: -.01em;
  font-size: 1.35rem; line-height: 1.2; color: var(--encre);
  font-variant-numeric: tabular-nums;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.index-chiffres .mesure.majeur .valeur { color: var(--primaire); }
@media (max-width: 900px) {
  .index-chiffres .mesure { border-bottom: 1px solid var(--bordure); }
  .index-chiffres .libelle { min-height: 0; }
}

/* Cadre photo : fond blanc STRICT, jamais teinté — condition pour juger d'une
   couleur (DESIGN.md). */
.cadre-photo {
  background: #FFFFFF; border: 1px solid var(--bordure); border-radius: var(--rayon);
  display: flex; align-items: center; justify-content: center; overflow: hidden;
}
.cadre-photo img { max-width: 100%; max-height: 100%; display: block; }
.bande-miniatures { display: flex; gap: 6px; margin-top: 8px; flex-wrap: wrap; }
.bande-miniatures img {
  width: 52px; height: 52px; object-fit: cover; border-radius: 3px;
  border: 1px solid var(--bordure); cursor: pointer; background: #FFFFFF;
}
.bande-miniatures img.active { border-color: var(--primaire); }

/* ======================= Écrans publics ================================== */
body.public { display: flex; min-height: 100vh; background: var(--fond); }
.public-cadre { margin: auto; width: 100%; max-width: 400px; padding: 24px 16px; }
.public-carte {
  background: var(--surface); border: 1px solid var(--bordure);
  border-radius: var(--rayon); padding: 32px;
}

/* Connexion : le moment fort de l'app. Aplat NOIR, double filet doré,
   emblème au centre. C'est le seul écran de travail qui a le droit d'être
   sombre — aucune montre n'y est jugée. */
body.connexion { display: block; background: var(--noir-profond); }
.connexion-scene {
  min-height: 100vh; display: flex; align-items: center; justify-content: center;
  padding: 32px 16px; position: relative;
}
/* Filigrane : le picto en très grand, à 6 % — l'unique motif de la marque.
   Il ne compte pas comme un second picto : la charte le pose ainsi sur la
   couverture, emblème compris. */
.connexion-filigrane {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  width: min(720px, 88vw); color: var(--or); opacity: .06; pointer-events: none;
}
.connexion-filigrane svg { width: 100%; height: auto; display: block; }
.connexion-carte {
  position: relative; width: 100%; max-width: 372px;
  background: var(--surface); border: 1px solid var(--filet-or);
  border-radius: var(--rayon); padding: 36px 32px 32px;
}
.connexion-embleme { display: block; width: 56px; margin: 0 auto; color: var(--primaire); }
.connexion-embleme svg { display: block; }
.connexion-marque {
  margin-top: 20px; text-align: center;
  font-family: var(--police-marque); font-weight: 400; font-size: 1.9rem;
  letter-spacing: .18em; text-indent: .18em; text-transform: uppercase;
  color: var(--primaire); line-height: 1;
}
.connexion-org {
  margin-top: 10px; text-align: center;
  font-size: 12px; font-weight: 500; letter-spacing: .14em;
  text-transform: uppercase; color: var(--encre-attenuee);
}
.connexion-filet { width: 44px; height: 1px; background: var(--accent); margin: 22px auto 26px; }

/* Passeport public : la photo d'abord, l'interface s'efface.
   Surface client final — elle doit tenir dans un téléphone, en pleine rue. */
.passeport-public { max-width: 520px; margin: 24px auto 40px; padding: 0 16px; }

/* La montre en premier, sur blanc strict et sans cadre lourd : rien ne doit
   entrer en concurrence avec la couleur qu'on est venu regarder. */
.passeport-photo {
  background: #FFFFFF; border: 1px solid var(--bordure); border-radius: var(--rayon);
  padding: 10px; margin-bottom: 8px;
}
.passeport-photo img {
  display: block; width: 100%; height: auto;
  max-height: 62vh; object-fit: contain; margin: 0 auto;
}
/* Sur un téléphone, 32 px de marge de carte volent un tiers de la photo. */
@media (max-width: 480px) {
  .passeport-public { padding: 0 10px; }
  .public-carte { padding: 20px 16px 24px; }
}
.passeport-marque {
  font-family: var(--police-marque); font-weight: 400;
  font-size: 1.8rem; letter-spacing: .04em; text-transform: uppercase;
  color: var(--primaire); text-align: center; line-height: 1.15;
  font-variant-numeric: tabular-nums;
}
.passeport-reference { text-align: center; color: var(--encre-douce); margin: 6px 0 0; }
.passeport-org {
  text-align: center; font-size: 12px; font-weight: 500; letter-spacing: .14em;
  text-transform: uppercase; color: var(--encre-attenuee); margin-bottom: 18px;
}
.passeport-pied {
  display: flex; align-items: center; justify-content: center; gap: 9px;
  margin-top: 22px; font-size: 12px; font-weight: 500; letter-spacing: .14em;
  text-transform: uppercase; color: var(--encre-attenuee);
}
.passeport-pied .picto { width: 11px; height: 11px; }

/* ======================= Pages d'erreur ================================== */
.page-erreur {
  max-width: 480px; margin: 15vh auto 0; padding: 32px;
  background: var(--surface); border: 1px solid var(--bordure); border-radius: var(--rayon);
  text-align: center;
}
.page-erreur h1 { font-size: 1.3rem; }

/* ======================= Utilitaires ===================================== */
.texte-attenue { color: var(--encre-attenuee); }
.texte-doux { color: var(--encre-douce); }
.texte-succes { color: var(--succes); }
.texte-avert { color: var(--avert); }
.texte-danger { color: var(--danger); }
.mono-espace { font-variant-numeric: tabular-nums; }
/* Aucun bloc préformaté ne pousse la page : ce qui dépasse défile DANS le
   bloc. Le détail d'un chiffrage aligne ses montants sur des points de
   conduite — une seule « mot » pour le navigateur, que `pre-wrap` ne sait pas
   couper — et quatre fiches (montre, devis, intervention, fourniture)
   débordaient de 44 px chacune. Règle qui balaye : le bloc écrit demain entre
   dans le périmètre sans que personne y pense. */
pre { max-width: 100%; overflow-x: auto; overflow-wrap: anywhere; }

.separateur-v { width: 1px; align-self: stretch; background: var(--bordure); }
.mb-0 { margin-bottom: 0; }
[x-cloak] { display: none !important; }

/* ======================= Adaptation aux écrans =========================== */
/* L'ossature n'avait aucun point de rupture : sous 900 px la barre latérale
   mangeait l'écran. Elle passe en bandeau d'icônes, puis en rangée défilante. */
@media (max-width: 1200px) {
  :root { --barre-laterale: 188px; }
}
@media (max-width: 960px) {
  :root { --barre-laterale: 56px; }
  .laterale-logo { padding: 13px 0; display: flex; justify-content: center; }
  .wordmark .lettres, .laterale-groupe { display: none; }
  .laterale a.entree { justify-content: center; padding: 10px 0; gap: 0; }
  .laterale a.entree { font-size: 0; }
  .laterale .icone { width: 18px; height: 18px; }
  .recherche-globale { max-width: none; }
}
/* La navigation basse n'existe que sous 720 px : au-dessus, la barre
   latérale porte la navigation et la barre basse disparaît. */
.onglets-bas { display: none; }

@media (max-width: 720px) {
  .app {
    grid-template-columns: 1fr;
    grid-template-rows: var(--bandeau) 1fr;
    grid-template-areas: "bandeau" "contenu";
  }
  /* La barre latérale cède la place à la navigation basse : une rangée
     d'icônes défilante en haut mettait la navigation hors de portée du pouce
     et se faisait emporter par le défilement horizontal de la page. */
  .laterale { display: none; }
  .fil-ariane { display: none; }
  /* Le défilement horizontal n'emporte plus la page : chaque tableau trop
     large défile dans SON cadre (règle .liste ci-dessous). La zone de
     contenu réserve la hauteur de la barre basse. Contrepartie assumée : les
     en-têtes collants ne collent plus sous 720 px. */
  .contenu { padding: 14px; overflow-x: hidden; padding-bottom: 98px; }
  .contenu table.liste { display: block; overflow-x: auto; }
  /* Quand kronos.js a posé le cadre défilant, le tableau redevient un tableau :
     en `display: block` il ne remplirait plus sa carte. La règle du dessus
     reste le filet de sécurité sans JavaScript. */
  .tableau-defilant > table.liste { display: table; }
  /* Le compte (nom, espace, déconnexion) vit déjà dans le volet « Plus » : au
     bandeau il ne reste que la recherche, pleine largeur, sans le raccourci
     clavier qu'aucun téléphone ne tape. */
  .bandeau { padding: 0 12px; gap: 10px; }
  .bandeau-compte { display: none; }
  .recherche-globale { max-width: none; }
  .recherche-globale kbd { display: none; }
  .recherche-globale input { padding-right: 10px; height: 34px; }
  .fiche-entete { flex-direction: column; }
  .barre-statut { margin-left: 0; }
  .indicateurs { grid-template-columns: repeat(2, 1fr); }
  .indicateur-carte { border-bottom: 1px solid var(--bordure); }
  .flashes { left: 12px; right: 12px; max-width: none; }

  /* --- La barre d'onglets, sous le pouce --------------------------------- */
  .onglets-bas {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 30;
    display: flex; align-items: stretch;
    background: var(--surface); border-top: 1px solid var(--bordure);
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }
  .onglets-bas .onglet {
    flex: 1; min-height: 56px;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 3px; padding: 6px 2px 7px;
    color: var(--encre-attenuee); font-size: 10px; text-decoration: none;
    border-top: 2px solid transparent; margin-top: -1px;
    cursor: pointer; list-style: none;
  }
  .onglets-bas .onglet.actif { color: var(--primaire); font-weight: 500; border-top-color: var(--primaire); }
  .onglets-bas .onglet .icone { width: 21px; height: 21px; }
  .onglets-plus { flex: 1; display: flex; }
  .onglets-plus > summary { flex: 1; }
  .onglets-plus > summary::-webkit-details-marker { display: none; }
  .onglets-plus[open] > summary { color: var(--primaire); }
  /* Le voile derrière le volet — un clic dessus referme (kronos.js). */
  .onglets-plus[open]::before {
    content: ""; position: fixed; inset: 0; z-index: 39;
    background: rgba(26, 29, 27, .34);
  }
  .volet-plus {
    position: fixed; left: 0; right: 0; z-index: 40;
    bottom: calc(56px + env(safe-area-inset-bottom, 0px));
    background: var(--surface); border-top: 1px solid var(--bordure);
    max-height: calc(100vh - 140px); overflow-y: auto;
  }
  .volet-plus-grille { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .volet-plus-grille .entree {
    display: flex; align-items: center; gap: 10px; min-height: 48px; padding: 0 16px;
    color: var(--encre); font-size: 13.5px; text-decoration: none;
    border-bottom: 1px solid var(--bordure);
  }
  .volet-plus-grille .entree:nth-child(odd) { border-right: 1px solid var(--bordure); }
  .volet-plus-grille .entree.active { color: var(--primaire); font-weight: 500; }
  .volet-plus-grille .entree .icone { width: 18px; height: 18px; color: var(--encre-douce); flex: none; }
  .volet-plus-grille .entree.active .icone { color: var(--primaire); }
  .volet-plus-pied {
    display: flex; align-items: center; justify-content: space-between;
    padding: 10px 16px; font-size: 13px; color: var(--encre-douce);
  }

}

/* Téléphone couché sous 720 px de large (iPhone SE, petits Android) : 390 px
   de haut au plus. La barre basse passe en rangée icône + mot, 44 px au lieu
   de 56, et le contenu récupère ce qu'elle rend. */
@media (max-width: 720px) and (max-height: 520px) {
  .onglets-bas .onglet { min-height: 44px; flex-direction: row; gap: 6px; padding: 4px 2px; font-size: 11px; }
  .onglets-bas .onglet .icone { width: 18px; height: 18px; }
  .volet-plus { bottom: calc(44px + env(safe-area-inset-bottom, 0px)); max-height: calc(100vh - 100px); }
  .contenu { padding-bottom: 72px; }
  /* Trois colonnes de 40 px : les treize entrées tiennent sans défiler dans
     les 275 px qui restent, là où deux colonnes de 48 px en cachaient cinq. */
  .volet-plus-grille { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .volet-plus-grille .entree { min-height: 40px; }
  .volet-plus-grille .entree:nth-child(odd) { border-right: 1px solid var(--bordure); }
  .volet-plus-grille .entree:nth-child(3n) { border-right: 0; }
}

/* Le mouvement lève une ambiguïté ; il n'est jamais nécessaire à la
   compréhension. Qui n'en veut pas n'en a aucun. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ======================= Veine d'Or (identité, 25.08.2026) =============== */
/* Motif kintsugi NOIR ET OR — docs/MOTIF-VEINE-DOR.md fait autorité.
   Règles inchangées : un geste par écran ; jamais sur une surface où l'on juge
   une montre ; jamais de bord d'image visible ; matière statique ; rien de
   simulé en code.

   Ce qui change le 25.08.2026 : les masters sont RECOLORÉS, pas redessinés.

   Le motif d'origine est un marbre pâle veiné de feuille d'or, avec une tache
   turquoise — couleur d'une identité verte qui n'est plus la nôtre. Un premier
   essai avait remplacé les images par un tracé vectoriel : rejeté, et à raison.
   Une fêlure dessinée à la main ne ressemble pas à une fêlure ; la valeur du
   motif est dans la photographie de la feuille d'or, son modelé et ses
   accidents. On garde donc les masters et l'on change leurs COULEURS
   (`scripts/recolorer_motif.py`, deux opérations, aucune retouche du dessin).

   DEUX JEUX, et il faut les deux :

   - `or_*`   — le fond clair d'origine, turquoise recoloré en or. Pour tout ce
                qui reste sur blanc : zone de travail, états vides, barre
                latérale, hero de la vitrine.
   - `noir_*` — le marbre basculé au noir, la dorure allumée. Pour les écrans
                « moments » et les sections sombres.

   Choisir le mauvais jeu se voit immédiatement : le fond clair posé sur du noir
   donne un rectangle blanc, et l'inverse un rectangle noir. C'est le
   « bord d'image visible » que la charte interdit depuis le premier jour. */

/* Écrans publics « moments » (connexion, première connexion, changement de
   mot de passe, passeport introuvable) : le marbre NOIR, veiné d'or. La carte
   blanche se pose sur la zone calme du centre-haut. */
body.connexion {
  background: var(--noir-profond) url("/static/img/motif/noir_fond-1920.webp")
              center / cover no-repeat;
}
@media (max-width: 1280px) {
  body.connexion { background-image: url("/static/img/motif/noir_fond-1280.webp"); }
}
body.connexion .connexion-filigrane { display: none; }
body.connexion .cadre-or::before,
body.connexion .cadre-or::after { display: none; }
/* L'ombre est plus dense qu'à l'époque du fond clair : sur du blanc une carte
   blanche se détachait d'un rien ; sur du noir, sans ombre, elle paraît
   découpée au cutter. */
body.connexion .connexion-carte { box-shadow: 0 18px 50px rgba(0, 0, 0, .55); }

/* Coin fondu — l'angle doré qui entre par le bas-gauche d'une zone « moment ».
   Jamais derrière du texte : le contenu passe au-dessus. `multiply` fond le
   papier du master dans le fond clair — c'est ce qui évite le bord visible. */
.vd-coin {
  position: absolute; left: 0; bottom: 0; width: 46%; height: 80%;
  background: url("/static/img/motif/or_coin-900.webp") left bottom / cover no-repeat;
  opacity: .38; mix-blend-mode: multiply; pointer-events: none;
  -webkit-mask-image: radial-gradient(ellipse at left bottom, #000 30%, transparent 72%);
  mask-image: radial-gradient(ellipse at left bottom, #000 30%, transparent 72%);
}

/* Trait organique — la veine comme filet. Page À propos uniquement dans
   l'app : la seule page où Kronos parle de lui. */
.vd-veine {
  height: 18px; width: 150px;
  background: url("/static/img/motif/or_veine-1000.webp") center / cover no-repeat;
  mix-blend-mode: multiply;
  -webkit-mask-image: linear-gradient(90deg, #000 0%, #000 60%, transparent);
  mask-image: linear-gradient(90deg, #000 0%, #000 60%, transparent);
}

/* Variante « centrée » — pied du passeport public. Le fondu part des deux
   bords : la veine FERME la page au lieu de pointer vers la droite. */
.vd-veine--centree {
  width: 168px; height: 20px;
  background-size: 380px auto;
  background-position: 6px center;
  margin: 26px auto 14px;
  filter: saturate(1.6) contrast(1.15);
  -webkit-mask-image: radial-gradient(ellipse at center, #000 16%, transparent 72%);
  mask-image: radial-gradient(ellipse at center, #000 16%, transparent 72%);
}

/* Pas de variante « prefers-color-scheme » ici : Kronos est en thème clair,
   délibérément — un fond sombre fausse l'appréciation des couleurs de montre.
   Le noir de l'identité est celui des « moments » et des aplats de marque,
   jamais celui de la zone de travail. Une règle « dark » se déclencherait chez
   qui a son système en sombre et repeindrait une interface restée claire. */

/* ---------------------------------------------------------------------------
   Veine d'Or sur les écrans de travail — décision du 21.08.2026, conservée.

   Deux couches, dosées sur planches comparatives :

   1. UN VOILE. Le fond kintsugi passe derrière toute la zone de travail, tenu
      à 38 % par un voile blanc superposé. Le marbre plein « faisait trop » ;
      en transparence il donne une profondeur, pas un décor.

   2. DES PAILLETTES. Sur les surfaces blanches, un semis d'or repris de la
      zone vive du motif, sous un voile blanc à 86 %. On le devine de près, il
      disparaît quand on travaille.

   Les deux emploient le jeu `or_` : la zone de travail reste CLAIRE, et y
   poser le jeu noir reviendrait à peindre l'écran de travail en sombre — ce
   que l'argument métier interdit.

   Deux pièges rencontrés, tous deux évités ici :
   — `overflow: hidden` sur la carte casse l'en-tête collant du tableau ;
   — un pseudo-élément posé sur la carte passe DERRIÈRE le fond opaque des
     cellules et ne se voit jamais. D'où des fonds superposés, pas des calques.

   Le voile ne défile pas avec la liste ; en dessous de 720 px il repasse en
   `scroll`, un calque fixe étant erratique sur mobile.

   IL EST PORTÉ PAR UN CALQUE FIXE (`::before`), PAS PAR
   `background-attachment: fixed` — mesure du 03.09.2026 sur Mydas. Un fond
   attaché à la fenêtre n'a pas de calque à lui : à chaque cran de molette le
   navigateur repeint la zone de travail entière, image de 1920 px comprise,
   sur le fil principal. Sur le banc (Chromium, 3 s de molette sur une liste
   de 50 lignes) la rastérisation coûtait 2,6 fois plus qu'avec un calque, et
   c'est ce que le client a vu le jour où son stock a dépassé un écran :
   « la navigation saccade ». Un pseudo-élément en `position: fixed` reçoit
   son propre calque du compositeur, peint une fois, et le défilement ne le
   touche plus. Même image, même cadrage (le calque couvre la fenêtre entière
   comme le faisait `fixed`, puis se rogne à la zone de travail) : rien ne
   change à l'écran, seul le coût disparaît. Règle CSS-4 de l'auditeur.

   `isolation: isolate` ferme le groupe de fusion : le coin en `multiply`
   (plus bas) se compose contre ce calque et lui seul, pas contre la page
   entière. */
.contenu { isolation: isolate; }
.contenu::before {
  content: "";
  position: fixed; inset: 0;
  z-index: 0; pointer-events: none;
  background-image:
    linear-gradient(rgba(251, 250, 248, .82), rgba(251, 250, 248, .82)),
    url("/static/img/motif/or_fond-1920.webp");
  background-size: auto, cover;
  background-position: center, center top;
  background-repeat: no-repeat, no-repeat;
  clip-path: inset(var(--bandeau) 0 0 var(--barre-laterale));
}
/* Le voile est passé de 62 % à 82 % de blanc le 25.08.2026, et le motif de la
   décision du 21.08 tient toujours — c'est son DOSAGE qui était réglé pour un
   écran de bureau ordinaire. En `cover` sur 3836 px, l'image de 1920 px est
   agrandie deux fois : sa bande dorée, prévue comme un pied, occupait alors la
   moitié basse de la fenêtre, et le carré-repère du master traversait la zone
   de travail. À 82 % le motif redevient ce qu'il devait être — une profondeur
   qu'on devine dans les gouttières, jamais une image qu'on regarde. */

/* Les surfaces qui portent de la donnée restent opaques : rien ne se juge sur
   du doré. C'est la seule règle conservée de l'interdit d'origine, et elle
   protège l'argument que Kronos vend à un négociant. */
.contenu .carte,
.contenu .fiche-section,
.contenu .bloc-pliable {
  background-color: var(--surface);
}
.contenu .carte { box-shadow: 0 1px 3px rgba(19, 17, 16, .07); }

/* Les paillettes. Fond superposé plutôt que calque, pour les raisons dites
   plus haut. `td` redevient transparent afin de les laisser paraître. */
.contenu table.liste,
.contenu table.liste th {
  background-image:
    linear-gradient(rgba(255, 255, 255, .86), rgba(255, 255, 255, .86)),
    url("/static/img/motif/or_veine-1000.webp");
  background-size: auto, 1100px auto;
  background-position: center, right -80px top -6px;
  background-repeat: no-repeat, no-repeat;
  background-color: var(--surface);
}
.contenu table.liste td { background-color: transparent; }

@media (max-width: 720px) {
  /* Le calque redevient un fond qui défile avec la page : `.contenu` est en
     `position: relative` (plus bas), `inset: 0` le couvre en entier. */
  .contenu::before { position: absolute; clip-path: none; }
}

/* ---------------------------------------------------------------------------
   Le coin fondu et la barre marbrée — piste retenue le 22.08.2026.

   Ce qui rend le coin juste, et que les filets retirés n'avaient pas : il
   occupe le VIDE. Sur une liste courte il monte du bas et remplit ce que la
   page laisse nu ; sur une liste longue le tableau le recouvre et il
   disparaît. Le motif s'efface exactement quand la donnée arrive.

   Le coin est en `fixed` : il appartient à la fenêtre, pas au flux. S'il
   défilait avec le contenu, il traverserait le tableau au lieu de rester dans
   son angle.
--------------------------------------------------------------------------- */
.contenu { position: relative; }
.contenu::after {
  content: "";
  position: fixed; right: 0; bottom: 0;
  width: 520px; height: 380px;
  z-index: 0; pointer-events: none;
  background: url("/static/img/motif/or_coin-900.webp") right bottom / contain no-repeat;
  /* Le coin d'origine ouvre vers la droite : on le retourne pour qu'il entre
     par l'angle au lieu d'en sortir. */
  transform: scaleX(-1);
  transform-origin: right bottom;
  opacity: .30;
  mix-blend-mode: multiply;
  -webkit-mask-image: radial-gradient(ellipse at right bottom, #000 20%, transparent 75%);
  mask-image: radial-gradient(ellipse at right bottom, #000 20%, transparent 75%);
}
/* Le contenu passe au-dessus : sans cela le coin recouvrirait les dernières
   lignes d'un tableau, ce qui est précisément l'écueil de la « tranche en
   pied » écartée le 21.08.
   Et il est BORNÉ : voir le commentaire de `.contenu`. La marge automatique
   centre la colonne de lecture au lieu de la coller à gauche — sur un écran
   large, un contenu aligné à gauche laisse un désert à droite que l'œil lit
   comme une zone qui n'a pas fini de charger. */
.contenu > * {
  position: relative; z-index: 1;
  max-width: var(--contenu-max);
  margin-inline: auto;
}

/* La colonne de navigation reçoit le motif vertical. C'est la zone la plus
   sûre de l'écran : aucune montre n'y est jugée, aucun chiffre n'y est lu. */
.laterale { position: relative; }
.laterale::before {
  content: "";
  position: absolute; inset: 0;
  pointer-events: none;
  background: url("/static/img/motif/or_bordure-1100.webp") center / cover no-repeat;
  opacity: .20;
  mix-blend-mode: multiply;
}
.laterale > * { position: relative; }

/* Sous 720 px la barre latérale cesse d'être une colonne : elle devient un
   bandeau horizontal d'icônes. Le motif `bordure` est vertical — l'y étirer
   reviendrait à l'employer dans une forme qui n'est pas la sienne, l'erreur
   même des filets retirés. On le retire, et le coin rétrécit pour ne pas
   occuper le tiers d'un écran de téléphone. */
@media (max-width: 720px) {
  .laterale::before { display: none; }
  .contenu::after { width: 260px; height: 200px; opacity: .24; }
}

/* État vide — variante Veine d'Or (choix 3C « coin fondu »). Opt-in par la
   classe modificatrice : seuls les états vides de module la portent, jamais
   les panneaux du tableau de bord ni les sous-listes de fiche. */
.etat-vide--veine { position: relative; overflow: hidden; }
.etat-vide--veine::before {
  content: ""; position: absolute; left: 0; bottom: 0;
  width: 46%; height: 82%; max-width: 460px;
  background: url("/static/img/motif/or_coin-900.webp") left bottom / cover no-repeat;
  opacity: .38; mix-blend-mode: multiply; pointer-events: none;
  -webkit-mask-image: radial-gradient(ellipse at left bottom, #000 30%, transparent 72%);
  mask-image: radial-gradient(ellipse at left bottom, #000 30%, transparent 72%);
}
.etat-vide--veine > * { position: relative; z-index: 1; }
.etat-vide--veine .picto { opacity: .95; color: var(--accent); }

/* Pages d'erreur dans l'app (404, 403) — le coin console l'impasse. */
.page-erreur { position: relative; min-height: 55vh; padding-top: 10vh; text-align: center; }

/* Moment Kronos — la toute première montre / vente / passeport d'un compte.
   Rendu par partials/flashes.html (catégorie « premiere »), une seule fois :
   le flash est consommé au premier affichage. Sans JavaScript : le lien
   « Continuer » recharge la page, l'instant est passé. */
.moment-premiere {
  position: fixed; inset: 0; z-index: 200;
  background: rgba(26, 29, 27, .45);
  display: flex; align-items: center; justify-content: center; padding: 24px;
}
.moment-premiere-carte {
  position: relative; overflow: hidden;
  background: var(--surface); border: 1px solid var(--bordure);
  border-radius: var(--rayon); max-width: 400px; width: 100%;
  padding: 34px 36px 30px; text-align: center;
  box-shadow: 0 14px 40px rgba(26, 29, 27, .25);
}
.moment-premiere-contenu { position: relative; z-index: 1; }
.moment-premiere-titre {
  font-family: var(--police-marque); font-size: 1.15rem; color: var(--primaire);
  letter-spacing: .02em;
}
.moment-premiere-texte { color: var(--encre-douce); margin: 10px 0 20px; }

/* Entrée directe par rôle sur l'écran de connexion — hors production. */
.demo-comptes { margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--bordure); }
.demo-titre {
  margin: 0 0 8px; font-size: 11px; letter-spacing: .07em; text-transform: uppercase;
  color: var(--encre-attenuee);
}
.demo-forme { margin: 0; }
.demo-compte {
  display: flex; flex-direction: column; gap: 1px; width: 100%; text-align: left;
  padding: 7px 10px; margin-bottom: 6px; cursor: pointer;
  background: var(--surface); border: 1px solid var(--bordure); border-radius: 4px;
  font: inherit; color: var(--encre);
}
.demo-compte:hover { background: var(--primaire-tint); border-color: var(--primaire); }
.demo-compte:focus-visible { outline: 2px solid var(--primaire); outline-offset: 1px; }
/* L'administratrice porte la marque : c'est le compte qui montre tout. */
.demo-compte--admin { border-color: var(--primaire); }
.demo-nom { font-weight: 500; }
.demo-role { font-size: 12px; color: var(--encre-attenuee); }

/* Console de l'éditeur. Elle reste distincte de l'espace client et ne montre
   que le registre et ses métadonnées d'exploitation (ADR 0001). */
body.pilotage { background: var(--fond); }
.pilotage-page { max-width: 1420px; margin: 0 auto; padding: 0 24px 60px; }
.pilotage-entete {
  min-height: 64px; display: flex; justify-content: space-between; align-items: center;
  gap: 20px; border-bottom: 1px solid var(--bordure);
}
.pilotage-identite { display: flex; align-items: center; gap: 12px; min-width: 0; }
.pilotage-marque { display: flex; align-items: center; gap: 8px; font-weight: 500; color: var(--primaire); }
.pilotage-marque span { font-family: var(--police-marque); font-size: 1.05rem; }
.pilotage-produit { padding-left: 12px; border-left: 1px solid var(--bordure); color: var(--encre-douce); }
.pilotage-compte { display: flex; align-items: center; gap: 10px; color: var(--encre-douce); }
.pilotage-compte > span { display: flex; flex-direction: column; align-items: flex-end; line-height: 1.35; }
.pilotage-compte strong { color: var(--encre); font-weight: 500; }
.pilotage-compte small { color: var(--encre-attenuee); }
.pilotage-mention { margin: 0 0 14px; font-size: 12px; letter-spacing: 0;
  text-transform: uppercase; color: var(--encre-attenuee); text-align: center; }

.pilotage-garde {
  display: grid; grid-template-columns: 40px minmax(0, 1fr) auto; align-items: center;
  gap: 16px; padding: 20px 0; border-bottom: 1px solid var(--bordure);
}
.pilotage-garde-icone {
  width: 40px; height: 40px; display: grid; place-items: center;
  /* La bordure était #C9DDD0 — un vert pâle en dur, dernier survivant de
     l'ancienne identité dans la feuille. Elle suit désormais le jeu de
     variables, comme tout le reste. */
  color: var(--primaire); background: var(--primaire-tint); border: 1px solid var(--bordure);
  border-radius: var(--rayon);
}
.pilotage-garde-icone .icone { width: 21px; height: 21px; }
.pilotage-garde h1 { margin: 0 0 3px; font-size: 1.28rem; }
.pilotage-garde p { margin: 0; max-width: 760px; color: var(--encre-douce); }
.pilotage-registre { display: flex; flex-direction: column; align-items: flex-end; }
.pilotage-registre span { font-size: 12px; color: var(--encre-attenuee); }
.pilotage-registre code { font-size: 13px; color: var(--encre); }

.pilotage-indicateurs {
  display: grid; grid-template-columns: repeat(5, minmax(120px, 1fr));
  margin: 18px 0 0; background: var(--surface); border: 1px solid var(--bordure);
  border-radius: var(--rayon);
}
.pilotage-indicateur { min-height: 72px; padding: 13px 16px; border-left: 1px solid var(--bordure); }
.pilotage-indicateur:first-child { border-left: 0; }
.pilotage-indicateur span { display: block; color: var(--encre-douce); font-size: 12.5px; }
.pilotage-indicateur strong { display: block; margin-top: 3px; font-size: 1.35rem; font-weight: 500;
  font-variant-numeric: tabular-nums; }
.pilotage-indicateur--succes strong { color: var(--succes); }
.pilotage-indicateur--avert strong { color: var(--avert); }
.pilotage-indicateur--danger strong { color: var(--danger); }

.pilotage-etat-services {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  min-height: 42px; padding: 6px 0; color: var(--encre-douce); font-size: 12.5px;
}
.pilotage-etat-separateur { width: 1px; height: 18px; margin: 0 6px; background: var(--bordure); }
.pilotage-section { margin-top: 22px; }
.pilotage-section-entete {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 16px; margin-bottom: 9px;
}
.pilotage-section-entete h2 {
  display: flex; align-items: center; gap: 7px; margin: 0; font-size: 1rem;
}
.pilotage-section-entete h2 .icone { width: 17px; height: 17px; color: var(--encre-douce); }
.pilotage-section-entete p { margin: 2px 0 0; color: var(--encre-attenuee); font-size: 12.5px; }
.pilotage-filtres { display: flex; align-items: center; justify-content: flex-end; gap: 7px; flex-wrap: wrap; }
.pilotage-filtres input, .pilotage-filtres select {
  height: 30px; padding: 0 9px; border: 1px solid var(--bordure);
  border-radius: var(--rayon); background: var(--surface); color: var(--encre); font: inherit;
}
.pilotage-filtres input { width: 230px; }
.pilotage-filtres select { width: 150px; }
.pilotage-filtres input:focus, .pilotage-filtres select:focus { border-color: var(--primaire); }

.pilotage-tableau table { min-width: 1040px; table-layout: auto; }
.pilotage-tableau table.liste tbody tr:hover { cursor: default; }
.pilotage-tableau table.liste td { height: 58px; }
.pilotage-tableau table.liste th:nth-child(1) { width: 20%; }
.pilotage-tableau table.liste th:nth-child(2) { width: 19%; }
.pilotage-tableau table.liste th:nth-child(3) { width: 12%; }
.pilotage-tableau table.liste th:nth-child(4) { width: 15%; }
.pilotage-tableau table.liste th:nth-child(5) { width: 17%; }
.pilotage-tableau table.liste th:nth-child(6) { width: 17%; }
.pilotage-ligne-alerte td:first-child { box-shadow: inset 2px 0 0 var(--danger); }
.pilotage-client-nom, .pilotage-base-nom { display: block; overflow: hidden; text-overflow: ellipsis; }
.pilotage-client-nom { font-weight: 500; color: var(--encre); }
.pilotage-base-nom { max-width: 240px; color: var(--encre); }
.pilotage-meta { display: block; margin-top: 3px; color: var(--encre-attenuee); font-size: 11.5px; }
.pilotage-meta--seul { margin-top: 0; }
.pilotage-actions { display: flex; align-items: center; gap: 2px; flex-wrap: nowrap; }
.pilotage-actions form { margin: 0; }
.pilotage-actions .btn { height: 28px; padding: 0 8px; font-size: 12px; }

@media (max-width: 760px) {
  .pilotage-page { padding: 0 12px 40px; }
  .pilotage-entete { min-height: 58px; }
  .pilotage-produit, .pilotage-compte small { display: none; }
  .pilotage-garde { grid-template-columns: 40px minmax(0, 1fr); }
  .pilotage-registre { grid-column: 2; align-items: flex-start; }
  .pilotage-indicateurs { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .pilotage-indicateur { border-left: 0; border-top: 1px solid var(--bordure); }
  .pilotage-indicateur:nth-child(1), .pilotage-indicateur:nth-child(2) { border-top: 0; }
  .pilotage-indicateur:nth-child(even) { border-left: 1px solid var(--bordure); }
  .pilotage-indicateur:last-child { grid-column: 1 / -1; }
  .pilotage-section-entete { align-items: stretch; flex-direction: column; }
  .pilotage-filtres { justify-content: flex-start; }
  .pilotage-filtres input { width: 100%; }
  .pilotage-filtres select { flex: 1; min-width: 150px; }
}

/* Titres de section de la page de recherche : le compte suit le nom, pour
   qu on sache d un coup d oeil ou porte la reponse. */
.recherche-titre { display:flex; align-items:baseline; gap:8px; font-size:1.05rem; margin:18px 0 8px; }
.recherche-titre .texte-attenue { font-size:.85rem; }

/* ======================= Révision responsive du 08.09.2026 ===============
   Mesurée par scripts/banc_responsive.py à quatre formats : téléphone debout
   (390 × 844), téléphone couché (844 × 390), tablette (768 × 1024), bureau
   (1440 × 900). Ces règles vivent en fin de feuille : elles doivent battre
   les règles de composant écrites plus haut, à spécificité égale.
   ========================================================================= */

/* --- Entre 720 et 960 px (tablette debout, téléphone couché) ------------
   Fil d'Ariane, recherche et compte se partagent 700 px : le fil se coupe
   avec des points, la recherche garde un minimum, le nom se tronque. Sans
   cela, « Déconnexion » sortait du cadre à 768 px sur toute fiche au titre
   long. */
@media (max-width: 960px) {
  .fil-ariane { flex: 0 1 auto; min-width: 0; }
  .fil-ariane .courant { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
  .recherche-globale { min-width: 110px; flex: 1 1 110px; }
  .bandeau-compte { flex: none; gap: 6px; }
  .bandeau-compte > span { max-width: 120px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .bandeau-compte .btn { padding: 0 8px; }
}

/* --- Cibles tactiles (WCAG 2.5.8 : 24 px au moins) -----------------------
   Une case à cocher native fait 13 px ; 16 px partout, 24 px au doigt. Les
   liens posés en bloc (fil d'Ariane, faits d'une fiche, cellules) gagnent
   une boîte de 32 px par un remplissage compensé d'une marge négative : la
   mise en page ne bouge pas d'un pixel, seule la zone qui répond grandit. */
.contenu input[type="checkbox"], .contenu input[type="radio"] {
  width: 16px; height: 16px; margin: 0; vertical-align: middle; flex: none;
}
.contenu input[type="file"] { min-height: 32px; }
@media (pointer: coarse) {
  .contenu input[type="checkbox"], .contenu input[type="radio"] { width: 24px; height: 24px; }
  table.liste .col-coche { width: 44px; }
  .contenu select, .contenu textarea,
  .contenu input:not([type="checkbox"]):not([type="radio"]):not([type="hidden"]) { min-height: 32px; }
  .contenu .btn, .contenu button:not(.onglet) { min-height: 32px; }
  details > summary { padding-top: 4px; padding-bottom: 4px; }
  .fil-ariane a, .faits dd a, .contenu td a, .contenu dd a, .index-chiffres .libelle a {
    display: inline-block; padding: 6px 0; margin: -6px 0;
  }
}

/* --- Les rangées d'une nouvelle vente, sous 720 px --------------------------
   Même geste que le calculateur : type et objet sur la première ligne, la
   désignation sur la deuxième, coût · prix · croix sur la troisième. L'en-tête
   du tableau part : chaque champ porte son propre texte d'invite. */
@media (max-width: 720px) {
  .tableau-lignes, .tableau-lignes tbody { display: block; width: 100%; }
  .tableau-lignes thead { display: none; }
  .ligne-vente {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr) 34px;
    gap: 6px 8px; align-items: center;
    padding: 10px 0; border-bottom: 1px solid var(--bordure);
  }
  .ligne-vente:last-child { border-bottom: 0; }
  .ligne-vente > td { display: block; width: auto !important; padding: 0; height: auto; border: 0; }
  .ligne-vente > td:has(input[name="ligne_designation"]) { grid-column: 1 / -1; }
  .ligne-vente > td.montant { text-align: right; }
}

/* --- Liens posés dans une phrase de fiche, au doigt --------------------------
   Le nom du client sous le titre d'une vente, le numéro de la facture liée :
   des liens de 21 px de haut. Même compensation que plus haut : la boîte qui
   répond grandit, la ligne ne bouge pas. */
@media (pointer: coarse) {
  .contenu a:not(.btn):not(.onglet):not(.entree):not(.pagination a) {
    display: inline-block; padding: 6px 0; margin: -6px 0;
  }
}

/* --- Une grille sortie des styles en ligne (GABARIT-4) ------------------
   Le champ + bouton d'une proposition d'objet : en classe, la requête média
   peut la replier. */
.grille-champs--et-bouton { grid-template-columns: 1fr auto; align-items: end; }
@media (max-width: 480px) {
  .grille-champs--et-bouton { grid-template-columns: 1fr; }
}

/* Un champ sur toute la largeur de la grille. En classe et non en style en
   ligne : `grid-column: span 2` en ligne créait, sur une grille réduite à une
   colonne (téléphone), une seconde piste implicite de 0 px où les champs
   suivants se plaçaient — sélecteurs de 22 px (Kronos, 08.09.2026). */
.champ--large { grid-column: 1 / -1; }

/* Une colonne de prose (th.prose / td.prose) se laisse écraser lettre par
   lettre plutôt que de faire déborder le tableau : « Marque et cuvée » sur
   14 px de large et 246 de haut (Baccus, 08.09.2026). Avec un minimum, le
   tableau déborde franchement et son cadre défile. La barre de statut d'une
   fiche passe à la ligne au lieu de sortir du cadre (/vrac/1 à 768 px). */
table.liste th.prose, table.liste td.prose { min-width: 180px; }
.barre-statut { flex-wrap: wrap; min-width: 0; }

/* ======================= L'Hôtel des ventes (10.09.2026) ===================
   La salle en cartes, l'en-tête du module avec ses onglets, les formulaires.
   Tout en classes : aucune disposition en style en ligne (GABARIT-4). */
.hv-entete { display: flex; align-items: flex-start; gap: 16px; flex-wrap: wrap; margin-bottom: 8px; }
.hv-entete h1 { margin: 0 0 4px; }
.hv-titre { flex: 1 1 320px; min-width: 0; }
.hv-sous-titre { margin: 0; color: var(--encre-attenuee); }
.hv-cloche { flex: none; }
.hv-compte {
  display: inline-block; min-width: 18px; padding: 0 6px; border-radius: 9px;
  background: var(--surface); color: var(--primaire); font-size: 12px; text-align: center;
}
/* Les onglets de l'Hôtel défilent sur une ligne, comme chez Mydas (11.09.2026) :
   repliés sur trois lignes, ils prenaient 120 px au-dessus de la salle au
   téléphone. Le repli général des `.onglets` reste pour les réglages. */
.hv-onglets { margin-bottom: 16px; flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; -ms-overflow-style: none; }
.hv-onglets::-webkit-scrollbar { display: none; }
.hv-onglets .onglet { flex: none; white-space: nowrap; }
.hv-salles { margin-bottom: 12px; }
.hv-recherche { flex-wrap: wrap; }
.hv-recherche .champ-nu { height: 30px; padding: 0 10px; flex: 1 1 180px; min-width: 0; }
.hv-recherche .tabulaire { flex: 0 1 140px; }
.hv-inline { display: inline; }
.hv-expedition { display: inline-flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.hv-expedition input { max-width: 180px; }

.hv-grille {
  display: grid; gap: 14px;
  grid-template-columns: repeat(auto-fill, minmax(230px, 320px));
}
.hv-carte {
  display: flex; flex-direction: column; padding: 0; overflow: hidden; color: inherit; text-decoration: none;
  transition: border-color var(--duree-court) var(--entree);
}
.hv-carte:hover { text-decoration: none; border-color: var(--encre-attenuee); }
.hv-photo {
  display: flex; align-items: center; justify-content: center;
  aspect-ratio: 4 / 3; background: var(--fond); color: var(--encre-attenuee); overflow: hidden;
}
.hv-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.hv-photo .icone { width: 40px; height: 40px; }
.hv-photo--grande { aspect-ratio: 16 / 9; border-radius: var(--rayon); margin-bottom: 12px; }
.hv-corps { padding: 12px 14px 14px; display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.hv-corps h3 { margin: 0; font-size: 15px; font-weight: 500; overflow-wrap: anywhere; }
.hv-numero { font-size: 12px; color: var(--encre-attenuee); letter-spacing: .06em; }
.hv-faits { margin: 0; color: var(--encre-douce); font-size: 13px; overflow-wrap: anywhere; }
.hv-preuves { margin: 2px 0 0; display: flex; flex-wrap: wrap; gap: 4px; }
.hv-pied { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; margin-top: auto; padding-top: 8px; flex-wrap: wrap; }
.hv-prix { font-weight: 500; font-variant-numeric: tabular-nums; }
.hv-prix--grand { font-size: 1.6rem; margin-bottom: 4px; }
.hv-achat form { margin-top: 12px; }
.hv-description { white-space: normal; overflow-wrap: anywhere; }
.hv-liste-preuves { list-style: none; padding: 0; margin: 0 0 12px; display: grid; gap: 6px; }
.hv-liste-preuves .icone { vertical-align: -3px; color: var(--succes); }
.hv-prix-saisie { width: 120px; max-width: 100%; height: 30px; padding: 0 8px; border: 1px solid var(--bordure); border-radius: var(--rayon); font: inherit; text-align: right; }
.hv-formulaire { max-width: 760px; }
table.liste tr.hv-non-lue td { font-weight: 500; }

/* Téléphone : la salle passe à deux cartes, puis une ; les champs de
   recherche prennent toute la largeur — mesuré sur les sept formats. */
@media (max-width: 720px) {
  .hv-grille { grid-template-columns: repeat(auto-fill, minmax(150px, 220px)); gap: 10px; }
  .hv-recherche .tabulaire { flex: 1 1 120px; }
  .hv-cloche { width: 100%; justify-content: center; }
}
@media (max-width: 400px) {
  .hv-grille { grid-template-columns: 1fr; }
}

/* --- « Mettre en vente » au téléphone (11.09.2026) ---------------------------
   Le tableau défilait dans son cadre, règle de la maison, mais la colonne du
   prix — LE geste de l'écran — restait hors champ à droite : au portrait on
   voyait la case, la référence et l'objet, jamais le prix. Sous 720 px chaque
   ligne devient une carte : case · référence · preuve sur la première ligne,
   la description sur la deuxième, le champ du prix sur la troisième avec son
   étiquette (l'en-tête du tableau est parti avec lui). Le tableau reste un
   tableau au-delà de 1024 px : au téléphone couché (844 px), sur la
   tablette debout (768 px) et même couchée (1024 px, barre latérale
   ouverte), la même colonne était coupée au bord droit. Mesuré sur les
   sept formats. */
@media (max-width: 1024px) {
  .contenu table.liste.hv-publication, .hv-publication tbody { display: block; width: 100%; overflow: visible; }
  .hv-publication thead { display: none; }
  .hv-publication tr.hv-ligne {
    display: grid; grid-template-columns: auto minmax(0, 1fr) auto;
    gap: 4px 10px; align-items: center;
    padding: 10px 0; border-bottom: 1px solid var(--bordure);
  }
  .hv-publication tr.hv-ligne:last-child { border-bottom: 0; }
  .hv-publication tr.hv-ligne > td { display: block; width: auto; height: auto; padding: 0; border: 0; min-width: 0; }
  .hv-publication .hv-cell-coche { grid-row: 1; grid-column: 1; }
  .hv-publication .hv-cell-ref { grid-row: 1; grid-column: 2; font-weight: 500; overflow-wrap: anywhere; }
  .hv-publication .hv-cell-preuve { grid-row: 1; grid-column: 3; }
  .hv-publication .hv-cell-desc { grid-column: 2 / -1; color: var(--encre-douce); overflow-wrap: anywhere; }
  .hv-publication .hv-cell-prix {
    grid-column: 2 / -1; display: flex; justify-content: space-between; align-items: center; gap: 8px;
  }
  .hv-publication tr.hv-ligne > td.hv-cell-prix--vide { display: none; }
  .hv-publication .hv-cell-prix::before { content: attr(data-etiquette); color: var(--encre-douce); font-size: 13px; }
  .hv-publication .hv-cell-prix .hv-prix-saisie { width: 150px; height: 40px; font-size: 16px; }
}

/* Le fil d'Ariane ne pousse plus le compte hors du bandeau (09.09.2026) : un
   titre long — « Saphir padparadscha 2 à 3 ct, certifié » — faisait déborder
   « Déconnexion » de 142 px à 1024 px. Le fil s'écrase avec des points de
   suspension, le compte garde sa place. */
.fil-ariane { min-width: 0; overflow: hidden; }
.fil-ariane .courant { overflow: hidden; text-overflow: ellipsis; }
.bandeau-compte { flex: none; }

/* --- Le paiement retenu de l'Hôtel des ventes (13.09.2026, ADR 0014) --------
   Transposé de Mydas le jour même. Les cases et les boutons radio d'un geste
   qui engage de l'argent (confirmer la réception, désigner le responsable d'un
   remboursement) portent leur phrase à côté de la case, sur toute la largeur :
   la case seule, collée à un libellé qui passe à la ligne, se manquait au
   doigt. Les montants s'alignent à droite dans leur liste ; la page publique
   du lien de réception garde le texte centré de la vitrine, mais pas ses
   formulaires, illisibles centrés. */
.hv-choix { display: flex; gap: 10px; align-items: flex-start; margin: 8px 0 12px; cursor: pointer; line-height: 1.45; }
.hv-choix input { flex: none; margin-top: 2px; }
.hv-choix span { min-width: 0; overflow-wrap: anywhere; }
.hv-choix-groupe { border: 0; padding: 0; margin: 12px 0; min-width: 0; }
.hv-choix-groupe legend { font-weight: 500; margin-bottom: 4px; }
.hv-parcours { margin: 12px 0 0; padding-left: 20px; display: grid; gap: 4px; }
.hv-etat > p { overflow-wrap: anywhere; }
.hv-etat h3 { margin: 16px 0 8px; font-size: 15px; }
.hv-etat .fiche-colonnes { margin-top: 12px; }
.hv-rembourser { margin-top: 16px; border-top: 1px solid var(--bordure); padding-top: 12px; }
.hv-rembourser summary { cursor: pointer; color: var(--encre-douce); }
.hv-rembourser form { margin-top: 8px; max-width: 760px; }
.hv-montants dd.montant { text-align: right; font-variant-numeric: tabular-nums; }
.hv-reception .faits { text-align: left; max-width: 560px; margin: 20px auto; }
.hv-reception .hv-reponses { text-align: left; margin-top: 20px; }
.hv-reception .avis { text-align: left; }
/* Au téléphone, la liste de la page de réception s'empile. La colonne des
   libellés prend la largeur du plus long (« Payé, sans débit (démonstration) »)
   et ne laissait aux valeurs qu'une bande étroite : le titre de la montre sur
   trois lignes, le montant coupé entre « CHF » et le nombre. Empêcher seulement
   la coupure faisait déborder la page de 8 px à 360 de large (banc du
   13.09.2026, Kronos) : c'est la colonne qu'il fallait rendre. */
@media (max-width: 520px) {
  .hv-reception .faits { grid-template-columns: 1fr; gap: 0; }
  .hv-reception .faits dt { margin-top: 10px; }
  .hv-reception .faits dd.montant { text-align: left; white-space: nowrap; }
}
@media (max-width: 720px) {
  .hv-etat .barre-actions { flex-direction: column; align-items: stretch; }
  .hv-etat .barre-actions .btn, .hv-etat .barre-actions form { width: 100%; }
  .hv-etat .barre-actions form .btn { width: 100%; justify-content: center; }
}
/* Les icônes posées dans un texte de l'Hôtel gardent la taille du texte. Une
   icône SVG sans règle de taille prend les 300 × 150 px par défaut d'un
   élément remplacé : sur Mydas, la coche « Vérifiée » de l'adresse de contact
   s'affichait en coche géante par-dessus les champs. Le banc ne le voit pas —
   rien ne déborde, la coche tient dans son cadre — la planche pleine page, si. */
.aide .icone, .texte-attenue .icone, .hv-liste-preuves .icone {
  width: 1em; height: 1em; vertical-align: -0.125em; flex: none;
}

/* ======================= Les actions à portée du doigt (16.09.2026) ========
   Rétroporté de Mydas le jour même. Là-bas, au téléphone debout, « Terminer »
   vivait à 873 px du bord droit de la liste des tâches, et le banc rendait
   zéro constat : le tableau défilait dans son cadre, et « hors cadre »
   exempte tout ce qu'un ancêtre rogne. Ici, le banc équipé a compté
   54 constats sur 15 écrans — tâches, commissions, publications, cotes,
   demandes et ordres de l'Hôtel, dossiers douaniers, fiches d'une montre,
   d'une fourniture et d'un voyage (332 px même au bureau), pagination.
   Une donnée peut défiler dans son cadre ; une action, non.
   ========================================================================= */

/* --- La liste empilable -----------------------------------------------------
   Une `table.liste--empilable` reste un tableau tant qu'elle tient dans son
   cadre. Quand elle n'y tient plus (classe `empilee`, mesurée EN TABLEAU par
   kronos.js), chaque rangée devient une pile : le titre en tête (`cel-titre`),
   un fait par ligne derrière le libellé de sa colonne (`data-libelle`, repris
   du `th` par le script), les actions en pied (`cel-actions`), la principale
   à droite, sous le pouce (`action-principale`). Aucun seuil en pixels : la
   même liste reste un tableau au bureau et s'empile dans une colonne de
   tableau de bord. Les faits passent sur deux colonnes dès que la pile a la
   largeur d'une tablette. */
table.liste td.cel-actions { width: 1%; text-align: right; white-space: nowrap; }
/* En tableau, les formulaires d'une cellule d'actions restent côte à côte :
   un `<form>` est un bloc, et deux gestes s'empilaient dans la rangée
   (Baccus, publications : un `display: flex` posé en ligne sur la cellule). */
table.liste td.cel-actions > form { display: inline-block; vertical-align: middle; }
.tableau-defilant.empilee { overflow: visible; }
.empilee > table.liste--empilable,
.empilee > table.liste--empilable > tbody { display: block; width: 100%; min-width: 0; }
.empilee > table.liste--empilable > thead { display: none; }
.empilee > table.liste--empilable > tbody > tr:not([hidden]) {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr));
  gap: 6px 28px; align-items: start;
  padding: 14px 16px; border-bottom: 1px solid var(--bordure);
}
.empilee > table.liste--empilable > tbody > tr:nth-last-child(1 of :not([hidden])) { border-bottom: 0; }
/* `width` en `!important` : une largeur posée en ligne sur une cellule
   (`style="width:220px"`) fixerait la largeur de sa ligne dans la pile — un
   style en ligne ne se bat pas autrement. */
.empilee > table.liste--empilable > tbody > tr > td {
  display: flow-root; width: auto !important; height: auto; min-width: 0; padding: 0; border: 0;
  white-space: normal; overflow: visible; overflow-wrap: anywhere; text-align: left;
}
.empilee > table.liste--empilable > tbody > tr > td:empty { display: none; }
.empilee > table.liste--empilable > tbody > tr > td:first-child { box-shadow: none; }
.empilee > table.liste--empilable > tbody > tr.ligne-retard { box-shadow: inset 3px 0 0 var(--danger); }
.empilee > table.liste--empilable > tbody > tr.ligne-urgence { box-shadow: inset 3px 0 0 var(--avert); }
/* Le libellé flotte dans la marge gauche de la cellule : la valeur garde sa
   mise en forme (liens, pastilles, retours à la ligne), et un libellé sur deux
   lignes allonge la cellule au lieu de chevaucher la suivante. */
.empilee > table.liste--empilable > tbody > tr > td[data-libelle] { padding-left: 116px; }
.empilee > table.liste--empilable > tbody > tr > td[data-libelle]::before {
  content: attr(data-libelle); float: left; width: 104px; margin-left: -116px;
  font-size: 12px; font-weight: 500; line-height: 1.75; letter-spacing: .06em;
  text-transform: uppercase; color: var(--encre-attenuee); overflow-wrap: normal;
}
.empilee > table.liste--empilable > tbody > tr > td.cel-titre,
.empilee > table.liste--empilable > tbody > tr > td.cel-actions,
.empilee > table.liste--empilable > tbody > tr > td[colspan] { grid-column: 1 / -1; }
.empilee > table.liste--empilable > tbody > tr > td.cel-titre { order: -1; padding-left: 0; font-size: 15px; }
.empilee > table.liste--empilable > tbody > tr > td.cel-titre::before,
.empilee > table.liste--empilable > tbody > tr > td.cel-actions::before { content: none; }
.empilee > table.liste--empilable > tbody > tr > td.cel-actions {
  order: 1; display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end;
  gap: 8px; padding: 6px 0 0;
}
.empilee > table.liste--empilable > tbody > tr > td.cel-actions:not(:has(*)) { display: none; }
.empilee > table.liste--empilable .cel-actions .action-principale { order: 1; margin-left: auto; }
.empilee > table.liste--empilable .cel-actions > details { flex: 1 1 100%; text-align: right; }
.empilee > table.liste--empilable .cel-actions > details[open] > :not(summary) { margin-top: 10px; text-align: left; }
/* La case de sélection partage la première ligne avec le titre ; les faits
   s'alignent sur le titre. */
.empilee > table.liste--empilable > tbody > tr > td.col-coche {
  grid-row: 1; grid-column: 1 / -1; justify-self: start; width: auto;
  position: relative; z-index: 1;
}
.empilee > table.liste--empilable > tbody > tr:has(> td.col-coche) > td.cel-titre { grid-row: 1; }
.empilee > table.liste--empilable > tbody > tr:has(> td.col-coche) > td:not(.col-coche, .cel-actions) { margin-left: 40px; }
/* La case « tout cocher » vit dans l'en-tête : empilée, la liste garde cette
   rangée-là, et elle seule. */
.empilee > table.liste--empilable > thead:has(th.col-coche input) { display: block; }
.empilee > table.liste--empilable > thead:has(th.col-coche input) > tr {
  display: flex; padding: 8px 16px; border-bottom: 1px solid var(--bordure);
}
.empilee > table.liste--empilable > thead:has(th.col-coche input) th { position: static; width: auto; height: auto; padding: 0; border: 0; }
.empilee > table.liste--empilable > thead:has(th.col-coche input) th:not(.col-coche) { display: none; }
@media (pointer: coarse) {
  .empilee > table.liste--empilable .cel-actions :is(.btn, button) { min-width: 44px; min-height: 44px; justify-content: center; }
  .empilee > table.liste--empilable .cel-actions .action-principale .btn { min-width: 120px; }
  /* Un bouton posé en lien dans une cellule reste un bouton au doigt : la
     règle des liens de cellule (32 px par remplissage compensé, plus haut)
     lui retirait son remplissage latéral et son centrage — « Vendue » collé à
     ses bords sur la fiche d'un prêt de Mydas. */
  .contenu td a.btn { display: inline-flex; padding: 0 14px; margin: 0; }
}

/* --- Le formulaire de modification d'une tâche, en classes ------------------
   Ses largeurs vivaient en style en ligne (220, 120, 110, 160 px) : empilée
   au téléphone, la rangée d'édition ne pouvait pas se replier. */
.tache-edition { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 8px; padding: 6px 0; }
.tache-edition .champ { margin: 0; min-width: 0; }
.tache-edition .champ-long { flex: 2 1 220px; }
.tache-edition .champ-court { flex: 0 1 120px; }
.tache-edition .champ-moyen { flex: 0 1 160px; }
@media (max-width: 720px) {
  .tache-edition .champ { flex: 1 1 100%; }
}

/* --- La barre de filtre d'une liste -----------------------------------------
   Le filtre des dossiers douaniers (type, recherche, « Filtrer ») tenait en
   `inline-flex` posé en style en ligne, sans retour à la ligne : au téléphone
   debout, « Filtrer » était rogné de 81 px par la zone de contenu de Mydas — ni
   visible, ni atteignable en glissant. */
.barre-filtre { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 6px; min-width: 0; max-width: 100%; }
@media (max-width: 720px) {
  .barre-filtre { display: flex; flex: 1 1 100%; }
  .barre-filtre input[type="search"] { flex: 1 1 140px; min-width: 0; }
}

/* --- Le fil d'Ariane entre 720 et 1100 px -------------------------------------
   Sur Mydas, à 768 px, « L'Hôtel des ventes / Demandes / Demande 4 » ne tenait pas : le
   titre courant s'écrasait à zéro, puis « Demandes » était rogné de 55 px,
   inatteignable. Sur tablette, le fil garde le dernier parent et la page
   courante ; la racine du module reste dans la navigation. */
/* 27.09.2026 : à 1024 px (iPad couché), « L'Hôtel des ventes / Demandes /
   Demande HV-2026-… » rognait encore « Demandes » de 61 px sur trois fiches de
   Mydas — les langues de l'interface, ajoutées le 24.09 au bandeau, ont pris la
   place qui restait. La coupe monte à 1100 px, le seuil de la fiche en colonne. */
@media (max-width: 1100px) {
  .fil-ariane > :not(:nth-last-child(-n+3)) { display: none; }
}

/* --- Ce qui passe à la ligne au doigt ----------------------------------------
   Rogné par la zone de contenu, sans défilement pour le rejoindre (Kronos,
   16.09.2026) : les numéros de page d'une longue liste au téléphone, et
   « Compléter la fiche » dans une ligne de « Mettre en vente » à 360 px — la
   cellule empilée gardait le `nowrap` des cellules de liste. */
.pagination { flex-wrap: wrap; row-gap: 6px; }
@media (max-width: 1024px) {
  .hv-publication tr.hv-ligne > td { white-space: normal; overflow: visible; }
}

/* L'en-tête d'une carte passe à la ligne au téléphone (16.09.2026). Dans
   Paramètres, le titre et son explication tenaient sur UNE rangée flex : le
   titre rétréci tombait à un mot par ligne dans une colonne de 90 px
   (« RÔLES / DE / TIERS »), l'explication filait à côté. Le banc ne le
   comptait pas, rien ne sortant du cadre ; la planche, si. Seuls les en-têtes
   qui portent une explication sont touchés : un titre suivi d'un bouton garde
   sa rangée. */
@media (max-width: 720px) {
  .carte-entete:has(> h2 + .texte-attenue) { flex-wrap: wrap; }
  .carte-entete > h2 + .texte-attenue { flex: 1 1 100%; }
}

/* --- Les langues de l'interface (24.09.2026) ------------------------------------
   Deux boutons, les deux autres langues : chacun nomme la langue où il mène. Repris d'Oikos,
   où « DE » en petites capitales se lisait à peine au bureau. */
.bascule-langue { display: inline-flex; gap: 4px; margin: 0; }
.bascule-langue .btn { min-width: 44px; justify-content: center; font-weight: 600; letter-spacing: .04em; }

/* Entre 720 et 960 px (tablette debout, téléphone couché), les deux boutons de langue prennent la place du
   raccourci clavier, qu'aucun écran tactile ne tape : sans cela la recherche ne gardait que sa loupe, vu sur la
   planche allemande du 24.09.2026. Le champ rend alors la marge qu'il réservait au raccourci : sans elle,
   « Suchen… » s'y coupait en « Such » (planche du 25.09.2026). */
@media (max-width: 960px) {
  .recherche-globale kbd { display: none; }
  .recherche-globale input { padding-right: 10px; }
  .bascule-langue .btn { min-width: 36px; }
}

/* Une pastille de filtre reste une cible de doigt dans toutes les langues : « All » ne fait que trois lettres,
   et sans largeur minimale le téléphone la réduisait à 19 px (banc responsive, anglais, 26.09.2026). */
.filtre-pastille { min-width: 24px; text-align: center; box-sizing: border-box; }
/* Au doigt, une règle générique retire le retrait latéral des liens : le mot touchait la bordure de la pastille. */
a.filtre-pastille { padding-inline: 10px; }

/* === Suivi commercial, repris de Mydas le 26.09.2026 === */
/* Qualité du prospect et chronologie d'une affaire (25.09.2026) : les étoiles
   se lisent d'un coup d'œil, les échanges comme un fil daté. */
.qualite-prospect { display: grid; gap: 12px; margin-bottom: 18px; }
.etoiles { font-size: 22px; letter-spacing: 2px; color: var(--accent); margin-right: 10px; }
.chronologie { list-style: none; margin: 0; padding: 0; }
.chronologie > li { border-left: 2px solid var(--bordure); padding: 0 0 16px 14px; position: relative; }
.chronologie > li::before { content: ""; position: absolute; left: -6px; top: 4px; width: 10px; height: 10px; border-radius: 50%; background: var(--bordure); }
.chronologie > li.planifie::before { background: var(--accent); }
.chronologie > li.no_show::before { background: var(--danger); }
.chronologie .entete-echange { display: flex; flex-wrap: wrap; gap: 6px 10px; align-items: baseline; }

/* Suivi commercial : trois étapes côte à côte au bureau, empilées au
   téléphone. En classe, jamais en style en ligne (GABARIT-4). */

/* Voyage : frais puis acquisitions, chacun sur toute la largeur (25.09.2026). */

/* --- Suivi commercial en un tableau (retour du 25.09.2026) -------------------
   Une ligne par client, les cases à remplir dans la ligne même. Les champs
   restent compacts (30 px) pour tenir sept colonnes au bureau ; au téléphone,
   `liste--empilable` range chaque client en fiche, champs pleine largeur. */
.suivi-filtres { margin: 0 0 12px; }
.suivi-filtres input[type="search"] { min-width: 14em; }
.suivi-table td { vertical-align: top; }
.suivi-table .suivi-saisie { min-width: 11em; }
.suivi-table .suivi-saisie > * + * { margin-top: 6px; }
.suivi-table input, .suivi-table select {
  display: block; width: 100%; height: 30px; padding: 0 8px; font: inherit; font-size: 13px;
  border: 1px solid var(--bordure); border-radius: var(--rayon); background: var(--fond-carte);
}
.suivi-table input:focus-visible, .suivi-table select:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.suivi-rangee { display: flex; gap: 6px; }
.suivi-rangee > * { flex: 1 1 0; min-width: 0; }
.suivi-rangee .suivi-heure { flex: 0 0 4.6em; }
.suivi-client { font-weight: 600; }
.suivi-compteurs { font-size: 12px; margin-top: 2px; }
.suivi-extrait { font-size: 12px; margin-top: 4px; max-width: 22em; }
.suivi-message { font-size: 12px; margin: 6px 0 0; }
.suivi-message .icone { width: 14px; height: 14px; vertical-align: -2px; }
.suivi-ajout { display: flex; flex-wrap: wrap; gap: 8px; padding: 12px; border-top: 1px solid var(--bordure); }
.suivi-ajout input { height: 32px; padding: 0 10px; font: inherit; border: 1px solid var(--bordure); border-radius: var(--rayon); flex: 1 1 12em; }
.suivi-aide { margin-top: 10px; max-width: 70ch; }
.suivi-masques { margin: 0; padding: 10px 12px; font-size: 13px; }
.ligne-suivi.ligne-retard > td:first-child { box-shadow: inset 2px 0 0 var(--danger); }
/* Les étoiles : cinq boutons radio, cibles de 26 px au doigt. L'ordre est
   inversé dans le code pour que « ~ » allume les étoiles de gauche. */
.notation { display: inline-flex; flex-direction: row-reverse; justify-content: flex-end; border: 0; margin: 4px 0 0; padding: 0; }
.notation input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.notation label { display: inline-flex; width: 26px; height: 26px; align-items: center; justify-content: center; cursor: pointer; color: var(--encre-attenuee); transition: color var(--duree-court) var(--entree); }
.notation label .icone { width: 18px; height: 18px; }
.notation input:checked ~ label, .notation label:hover, .notation label:hover ~ label { color: var(--accent); }
.notation input:checked ~ label .icone, .notation label:hover .icone, .notation label:hover ~ label .icone { fill: currentColor; }
.notation input:focus-visible + label { outline: 2px solid var(--accent); border-radius: 4px; }
/* Mesuré au banc le 25.09.2026 : en mise en page automatique, la largeur
   naturelle des champs faisait déborder la table dès le bureau, et
   `liste--empilable` la rangeait en fiches — le tableau demandé n'existait
   plus. Largeurs fixes à partir de 1100 px ; en dessous, les fiches. */
@media (min-width: 1100px) {
  .suivi-table { table-layout: fixed; width: 100%; }
  /* 26.09.2026, mesuré à 1440 px : « Motif si perdu », « Responsable » et le
     nom du commercial étaient rognés à 11 %, le titre « Budget · responsable »
     coupé net. Le dernier contact, du texte qui passe à la ligne, cède 2 %. */
  .suivi-table th:nth-child(1) { width: 16%; }
  .suivi-table th:nth-child(2) { width: 13%; }
  .suivi-table th:nth-child(3) { width: 18%; }
  .suivi-table th:nth-child(4) { width: 17%; }
  .suivi-table th:nth-child(5) { width: 13%; }
  .suivi-table th:nth-child(6) { width: 14%; }
  .suivi-table th:nth-child(7) { width: 9%; }
  /* `table.liste th` coupe tout titre à la ligne : plus spécifique ici. */
  table.liste.suivi-table th { white-space: normal; overflow: visible; text-overflow: clip; }
  .suivi-table .suivi-saisie { min-width: 0; }
  .suivi-table .btn { width: 100%; justify-content: center; padding-inline: 6px; }
}
.suivi-table input, .suivi-table select { min-width: 0; }
.suivi-filtres input, .suivi-filtres select {
  height: 32px; padding: 0 10px; font: inherit; border: 1px solid var(--bordure);
  border-radius: var(--rayon); background: var(--fond-carte);
}
@media (max-width: 600px) {
  .suivi-rangee { flex-wrap: wrap; }
  .suivi-rangee > select { flex-basis: 100%; }
}
/* Second passage du banc (25.09.2026) : étoiles rognées à côté du nom,
   « Enregistrer » coupé au bord, canal réduit à « App ». */
.suivi-table .notation { display: flex; }
.suivi-table .suivi-client { display: block; white-space: normal; overflow-wrap: anywhere; }
.suivi-table .cel-titre { white-space: normal; }
.suivi-prevu { display: flex; flex-wrap: wrap; gap: 4px 6px; align-items: baseline; }
.suivi-rangee--prochain { flex-wrap: wrap; }
.suivi-rangee--prochain > select { flex-basis: 100%; }
@media (min-width: 1100px) {
  .suivi-table th:nth-child(3), .suivi-table th:nth-child(4) { width: 18%; }
  .suivi-table th:nth-child(7) { width: 10%; }
  .suivi-table .btn { font-size: 13px; }
}
.suivi-table th { white-space: normal; }
.notation label ~ label { transition: color var(--duree-court) var(--entree); }

/* === Console de l'éditeur : caisse, sièges, fiche client, incidents, import ===
   Reprises de Deimos (lot 4 du chantier « console superadmin dans toute la gamme »). */
.pilotage-lien-caisse { display: inline-block; min-height: 24px; line-height: 24px; color: var(--primaire); text-decoration: none; }
.pilotage-lien-caisse:hover { text-decoration: underline; }
.pilotage-anomalies { margin: 0; padding: 0; list-style: none; }
.pilotage-anomalie {
  padding: 2px 0 2px 9px; border-left: 2px solid var(--bordure);
  color: var(--encre-douce); font-size: 12px; line-height: 1.35;
}
.pilotage-anomalie + .pilotage-anomalie { margin-top: 5px; }
.pilotage-anomalie--danger { border-left-color: var(--danger); color: var(--danger); }
.pilotage-anomalie--avert { border-left-color: var(--avert); color: var(--encre); }
.pilotage-anomalie--info { border-left-color: var(--bordure); }
.pilotage-indicateurs--six { grid-template-columns: repeat(6, minmax(110px, 1fr)); }
@media (max-width: 1100px) {
  .pilotage-indicateurs--six { grid-template-columns: repeat(3, minmax(110px, 1fr)); }
  .pilotage-indicateurs--six .pilotage-indicateur:nth-child(3n+1) { border-left: 0; }
  .pilotage-indicateurs--six .pilotage-indicateur:nth-child(n+4) { border-top: 1px solid var(--bordure); }
}
.pilotage-caisse table { min-width: 1180px; }
.pilotage-echeance { display: block; font-weight: 500; font-variant-numeric: tabular-nums; }
.pilotage-personne { color: var(--danger); font-weight: 500; }
.pilotage-caisse table.liste th:nth-child(n) { width: auto; }
.pilotage-caisse table.liste td { height: auto; padding-top: 10px; padding-bottom: 10px; }
.pilotage-alerte {
  display: flex; align-items: flex-start; gap: 9px; margin-top: 18px; padding: 11px 14px;
  border-left: 3px solid var(--bordure); background: var(--surface);
}
.pilotage-alerte .icone { width: 18px; height: 18px; flex: 0 0 auto; margin-top: 1px; }
.pilotage-alerte--danger { border-left-color: var(--danger); color: var(--danger); }
.pilotage-alerte--avert { border-left-color: var(--avert); color: var(--encre); }
.pilotage-import-gabarits, .pilotage-import-actions {
  display: flex; align-items: center; justify-content: flex-end; gap: 8px; flex-wrap: wrap;
}
.pilotage-import-forme {
  display: grid; grid-template-columns: 190px minmax(260px, 680px); gap: 12px 18px;
  align-items: center; padding: 20px 0; border-top: 1px solid var(--bordure);
  border-bottom: 1px solid var(--bordure);
}
.pilotage-import-forme label { font-weight: 500; }
.pilotage-import-forme select, .pilotage-import-forme input[type="file"] {
  width: 100%; min-width: 0; padding: 9px 11px; border: 1px solid var(--bordure);
  border-radius: var(--rayon); background: var(--surface); color: var(--encre); font: inherit;
}
.pilotage-import-forme input[type="file"] { font-size: 12.5px; color: var(--encre-douce); }
.pilotage-import-forme select:focus, .pilotage-import-forme input[type="file"]:focus {
  border-color: var(--primaire);
}
.pilotage-import-forme .pilotage-import-actions { grid-column: 2; justify-content: flex-start; }
.pilotage-import-cible { margin: 12px 0 16px; border-top: 1px solid var(--bordure); }
.pilotage-import-cible dl { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); margin: 0; }
.pilotage-import-cible dl > div { min-width: 0; padding: 12px 14px; border-bottom: 1px solid var(--bordure); }
.pilotage-import-cible dt { margin-bottom: 3px; color: var(--encre-attenuee); font-size: 12px; }
.pilotage-import-cible dd { margin: 0; overflow-wrap: anywhere; font-weight: 500; }
.pilotage-import-tableau { margin: 14px 0; }
.pilotage-import-tableau table { min-width: 620px; }
.pilotage-import-tableau table.liste th:first-child { width: 90px; }
.pilotage-import-lecture table.liste th:first-child { width: 50%; }
.pilotage-import-actions form { margin: 0; }
.jauge-sieges { margin: -8px 0 16px; color: var(--encre-douce); font-size: 13px; }
.jauge-sieges--pleine { color: var(--avert); }
.pilotage-sieges { display: flex; align-items: center; gap: 6px; margin: 0; }
.pilotage-sieges input { width: 64px; padding: 4px 8px; border: 1px solid var(--bordure); border-radius: var(--rayon); font: inherit; font-variant-numeric: tabular-nums; }
.pilotage-sieges input:focus { border-color: var(--primaire); }
.pilotage-sieges .btn { height: 28px; padding: 0 8px; font-size: 12px; }
@media (max-width: 760px) {
  .pilotage-import-forme { grid-template-columns: 1fr; }
  .pilotage-import-forme .pilotage-import-actions { grid-column: 1; }
  .pilotage-import-cible dl { grid-template-columns: 1fr 1fr; }
  .pilotage-import-cible dl > div:last-child { grid-column: 1 / -1; }
  .pilotage-import-actions { justify-content: flex-start; }
}

/* Le nom mène à la fiche : 24 px au doigt, comme toute cible (WCAG 2.5.8). */
a.pilotage-client-nom { display: inline-block; min-height: 24px; line-height: 24px; text-decoration: none; }
a.pilotage-client-nom:hover { text-decoration: underline; }
/* Un libellé masqué (`sr-only`, en absolu) posé dans une cellule prend la PAGE
   pour bloc conteneur quand le cadre défilant n'est pas positionné : la page
   entière s'élargit au téléphone (mesuré sur Mydas le 27.09.2026). */
.pilotage-tableau .tableau-defilant { position: relative; }
